101 lines
7.0 KiB
HTML
101 lines
7.0 KiB
HTML
{% extends "base.html" %}
|
||
{% block content %}
|
||
<div class="flex flex-col md:flex-row gap-6">
|
||
<!-- 左侧侧边栏 -->
|
||
<aside class="w-full md:w-64 shrink-0">
|
||
<nav class="bg-white/90 backdrop-blur-xl rounded-3xl shadow-sm border border-slate-100 p-4 flex flex-col gap-1 sticky top-[80px]">
|
||
<div class="px-3 pb-4 mb-2 border-b border-slate-100/60">
|
||
<div class="flex items-center gap-3">
|
||
<div class="w-10 h-10 rounded-xl bg-gradient-to-br from-indigo-500 to-purple-600 flex items-center justify-center text-white shadow-md shadow-indigo-200 transform -rotate-6">
|
||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z"/><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"/></svg>
|
||
</div>
|
||
<div>
|
||
<h2 class="text-lg font-extrabold text-slate-800 tracking-tight">管理后台</h2>
|
||
<p class="text-xs font-medium text-slate-400 mt-0.5">智联青云控制中心</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{% set nav_items = [
|
||
('/admin', '仪表盘', 'M4 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2V6zM14 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2V6zM4 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2v-2zM14 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2v-2z'),
|
||
('/admin/contests', '杯赛管理', 'M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 002-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10'),
|
||
('/admin/contest-applications', '杯赛申请', 'M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4'),
|
||
('/admin/teacher-applications', '教师申请', 'M21 13.255A23.931 23.931 0 0112 15c-3.183 0-6.22-.62-9-1.745M16 6V4a2 2 0 00-2-2h-4a2 2 0 00-2 2v2m4 6h.01M5 20h14a2 2 0 002-2V8a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z'),
|
||
('/admin/exams', '考试管理', 'M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z'),
|
||
('/admin/users', '用户管理', 'M12 4.354a4 4 0 110 5.292M15 21H3v-1a6 6 0 0112 0v1zm0 0h6v-1a6 6 0 00-9-5.197M13 7a4 4 0 11-8 0 4 4 0 018 0z'),
|
||
('/admin/posts', '帖子管理', 'M17 8h2a2 2 0 012 2v6a2 2 0 01-2 2h-2v4l-4-4H9a1.994 1.994 0 01-1.414-.586m0 0L11 14h4a2 2 0 002-2V6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2v4l.586-.586z'),
|
||
('/admin/notifications', '通知管理', 'M15 17h5l-1.405-1.405A2.032 2.032 0 0118 14.158V11a6.002 6.002 0 00-4-5.659V5a2 2 0 10-4 0v.341C7.67 6.165 6 8.388 6 11v3.159c0 .538-.214 1.055-.595 1.436L4 17h5m6 0v1a3 3 0 11-6 0v-1m6 0H9')
|
||
] %}
|
||
|
||
{% for path, name, icon in nav_items %}
|
||
{% set is_active = request.path == path %}
|
||
<a href="{{ path }}" class="flex items-center gap-3 px-4 py-3 rounded-xl text-sm font-bold transition-all duration-200 group relative overflow-hidden
|
||
{% if is_active %}
|
||
text-indigo-600 bg-indigo-50/80 shadow-[inset_0_2px_4px_rgba(0,0,0,0.02)]
|
||
{% else %}
|
||
text-slate-500 hover:text-slate-800 hover:bg-slate-50
|
||
{% endif %}
|
||
">
|
||
{% if is_active %}
|
||
<div class="absolute left-0 top-1/2 -translate-y-1/2 w-1.5 h-8 bg-indigo-500 rounded-r-full"></div>
|
||
{% endif %}
|
||
<svg class="w-5 h-5 flex-shrink-0 {% if is_active %}text-indigo-500{% else %}text-slate-400 group-hover:text-slate-500{% endif %} transition-colors" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="{{ icon }}"/></svg>
|
||
{{ name }}
|
||
{% if is_active %}
|
||
<div class="absolute right-4 w-1.5 h-1.5 rounded-full bg-indigo-400 animate-pulse"></div>
|
||
{% endif %}
|
||
</a>
|
||
{% endfor %}
|
||
</nav>
|
||
</aside>
|
||
|
||
<!-- 主体内容区 -->
|
||
<main class="flex-1 min-w-0">
|
||
<div class="bg-white/80 backdrop-blur-xl rounded-3xl shadow-sm border border-slate-100 p-6 sm:p-8 relative">
|
||
<div class="absolute top-0 right-0 w-64 h-64 bg-indigo-50/30 rounded-bl-full -z-10"></div>
|
||
{% block admin_content %}{% endblock %}
|
||
</div>
|
||
</main>
|
||
</div>
|
||
|
||
<script>
|
||
document.addEventListener('DOMContentLoaded', () => {
|
||
// 简单的路由活动状态高亮处理(以防jinja的request.path不够精确)
|
||
const currentPath = window.location.pathname;
|
||
const navLinks = document.querySelectorAll('aside nav a[href]');
|
||
|
||
// 如果没有被Jinja正确高亮,这里做前端补充高亮
|
||
let foundActive = false;
|
||
navLinks.forEach(link => {
|
||
if(link.classList.contains('text-indigo-600')) foundActive = true;
|
||
});
|
||
|
||
if(!foundActive) {
|
||
navLinks.forEach(link => {
|
||
const href = link.getAttribute('href');
|
||
if (currentPath === href || (href !== '/admin' && currentPath.startsWith(href))) {
|
||
// 移除默认样式
|
||
link.className = link.className.replace('text-slate-500 hover:text-slate-800 hover:bg-slate-50', '');
|
||
// 添加活动样式
|
||
link.classList.add('text-indigo-600', 'bg-indigo-50/80', 'shadow-[inset_0_2px_4px_rgba(0,0,0,0.02)]');
|
||
|
||
// 插入左侧高亮条和右侧小圆点
|
||
if(!link.querySelector('.absolute.left-0')) {
|
||
link.insertAdjacentHTML('afterbegin', '<div class="absolute left-0 top-1/2 -translate-y-1/2 w-1.5 h-8 bg-indigo-500 rounded-r-full"></div>');
|
||
}
|
||
if(!link.querySelector('.absolute.right-4')) {
|
||
link.insertAdjacentHTML('beforeend', '<div class="absolute right-4 w-1.5 h-1.5 rounded-full bg-indigo-400 animate-pulse"></div>');
|
||
}
|
||
|
||
const icon = link.querySelector('svg');
|
||
if(icon) {
|
||
icon.classList.remove('text-slate-400', 'group-hover:text-slate-500');
|
||
icon.classList.add('text-indigo-500');
|
||
}
|
||
}
|
||
});
|
||
}
|
||
});
|
||
</script>
|
||
{% endblock %}
|