Browse Source

refactor(theme): tokenize admin layout and list pages

main
Mohan 1 month ago
parent
commit
3c74ccfb1d
  1. 70
      src/views/admin/AdminLayout.vue
  2. 52
      src/views/admin/ArticleListView.vue
  3. 42
      src/views/admin/CommentReviewView.vue

70
src/views/admin/AdminLayout.vue

@ -1,9 +1,11 @@
<script setup lang="ts"> <script setup lang="ts">
import { useAuthStore } from '@/stores/auth' import { useAuthStore } from '@/stores/auth'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import { useTheme } from '@/composables/useTheme'
const auth = useAuthStore() const auth = useAuthStore()
const router = useRouter() const router = useRouter()
const theme = useTheme()
async function handleLogout() { async function handleLogout() {
try { try {
@ -25,6 +27,14 @@ async function handleLogout() {
<router-link v-if="auth.isAdmin" to="/admin/users">用户管理</router-link> <router-link v-if="auth.isAdmin" to="/admin/users">用户管理</router-link>
<router-link v-if="auth.isAdmin" to="/admin/comments">评论审核</router-link> <router-link v-if="auth.isAdmin" to="/admin/comments">评论审核</router-link>
</nav> </nav>
<div class="sidebar-foot">
<button
class="theme-toggle"
type="button"
:title="theme.isDark ? '切至天青昼' : '切至黛墨夜'"
@click="theme.toggle()"
>{{ theme.isDark ? '昼' : '夜' }}</button>
</div>
</aside> </aside>
<div class="content-wrap"> <div class="content-wrap">
<header class="topbar"> <header class="topbar">
@ -32,7 +42,11 @@ async function handleLogout() {
<a href="#" class="logout-link" @click.prevent="handleLogout">退出</a> <a href="#" class="logout-link" @click.prevent="handleLogout">退出</a>
</header> </header>
<main class="content"> <main class="content">
<router-view />
<router-view v-slot="{ Component }">
<transition name="page" mode="out-in">
<component :is="Component" />
</transition>
</router-view>
</main> </main>
</div> </div>
</div> </div>
@ -41,18 +55,23 @@ async function handleLogout() {
<style scoped> <style scoped>
.admin-layout { .admin-layout {
display: flex; display: flex;
min-height: calc(100vh - 56px);
min-height: calc(100vh - 60px);
} }
.sidebar { .sidebar {
width: 200px; width: 200px;
background: #1f2430;
flex-shrink: 0;
background: var(--ac-header-bg);
padding: 20px 12px; padding: 20px 12px;
display: flex;
flex-direction: column;
transition: background-color var(--song-dur-2) var(--song-ease);
} }
.sidebar-title { .sidebar-title {
color: #fff;
color: var(--ac-header-text);
font-size: 15px; font-size: 15px;
font-weight: 400;
margin: 0 0 16px; margin: 0 0 16px;
padding-left: 8px; padding-left: 8px;
} }
@ -66,22 +85,49 @@ async function handleLogout() {
.sidebar-nav a { .sidebar-nav a {
display: block; display: block;
padding: 10px 14px; padding: 10px 14px;
border-radius: 6px;
color: #cfd3dc;
border-radius: var(--song-radius-l);
color: var(--ac-header-muted);
text-decoration: none; text-decoration: none;
font-size: 14px; font-size: 14px;
transition: background var(--song-dur-1) var(--song-ease), color var(--song-dur-1) var(--song-ease);
} }
.sidebar-nav a.router-link-active, .sidebar-nav a.router-link-active,
.sidebar-nav a:hover { .sidebar-nav a:hover {
background: #2c3340;
color: #fff;
background: var(--ac-header-active-bg);
color: var(--ac-header-text);
}
.sidebar-foot {
margin-top: auto;
padding: 12px 8px 0;
}
.theme-toggle {
width: 100%;
height: 34px;
border: 1px solid var(--ac-border);
border-radius: var(--song-radius-m);
background: transparent;
color: var(--ac-header-muted);
font-family: var(--song-font-serif);
font-size: 15px;
letter-spacing: 0.1em;
cursor: pointer;
transition: color var(--song-dur-1) var(--song-ease), border-color var(--song-dur-1) var(--song-ease), background var(--song-dur-1) var(--song-ease);
}
.theme-toggle:hover {
color: var(--ac-header-text);
border-color: var(--ac-header-muted);
background: var(--ac-header-active-bg);
} }
.content-wrap { .content-wrap {
flex: 1; flex: 1;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
min-width: 0;
} }
.topbar { .topbar {
@ -91,17 +137,17 @@ async function handleLogout() {
gap: 16px; gap: 16px;
height: 52px; height: 52px;
padding: 0 20px; padding: 0 20px;
background: #fff;
border-bottom: 1px solid #e5e5ea;
background: var(--ac-bg-card);
border-bottom: 1px solid var(--ac-border);
} }
.current-user { .current-user {
color: #5c6470;
color: var(--ac-text-secondary);
font-size: 14px; font-size: 14px;
} }
.logout-link { .logout-link {
color: #d33c3c;
color: var(--ac-danger);
text-decoration: none; text-decoration: none;
font-size: 14px; font-size: 14px;
} }

52
src/views/admin/ArticleListView.vue

@ -183,26 +183,34 @@ onMounted(load)
.filter-select { .filter-select {
padding: 8px 12px; padding: 8px 12px;
border: 1px solid #d3d8e0;
border-radius: 6px;
border: 1px solid var(--ac-input-border);
border-radius: var(--song-radius-l);
background: var(--ac-bg-card);
color: var(--ac-text);
font-size: 14px;
} }
.btn-primary { .btn-primary {
display: inline-block; display: inline-block;
padding: 9px 16px; padding: 9px 16px;
background: #3b82f6;
color: #fff;
border-radius: 6px;
background: var(--ac-primary-strong);
color: var(--ac-primary-text);
border-radius: var(--song-radius-l);
text-decoration: none; text-decoration: none;
font-size: 14px; font-size: 14px;
transition: opacity var(--song-dur-1) var(--song-ease);
}
.btn-primary:hover {
opacity: 0.9;
} }
.article-table { .article-table {
width: 100%; width: 100%;
border-collapse: collapse; border-collapse: collapse;
background: #fff;
border: 1px solid #e5e5ea;
border-radius: 8px;
background: var(--ac-bg-card);
border: 1px solid var(--ac-border);
border-radius: var(--song-radius-l);
overflow: hidden; overflow: hidden;
} }
@ -210,34 +218,34 @@ onMounted(load)
.article-table td { .article-table td {
padding: 10px 14px; padding: 10px 14px;
text-align: left; text-align: left;
border-bottom: 1px solid #eee;
border-bottom: 1px solid var(--ac-border);
font-size: 14px; font-size: 14px;
} }
.article-table th { .article-table th {
background: #f7f8fa;
color: #5c6470;
background: var(--ac-surface);
color: var(--ac-text-secondary);
} }
.status-badge { .status-badge {
padding: 2px 10px; padding: 2px 10px;
border-radius: 12px;
border-radius: var(--song-radius-m);
font-size: 12px; font-size: 12px;
} }
.status-badge.draft { .status-badge.draft {
background: #e9ecef;
color: #6c757d;
background: var(--ac-surface);
color: var(--ac-text-secondary);
} }
.status-badge.published { .status-badge.published {
background: #d4edda;
color: #1e7e34;
background: var(--ac-success-bg);
color: var(--ac-success);
} }
.status-badge.archived { .status-badge.archived {
background: #fff3cd;
color: #b26a00;
background: var(--ac-warning-bg);
color: var(--ac-warning);
} }
.actions { .actions {
@ -248,21 +256,21 @@ onMounted(load)
.btn-link { .btn-link {
border: none; border: none;
background: none; background: none;
color: #3b82f6;
color: var(--ac-primary);
cursor: pointer; cursor: pointer;
font-size: 13px; font-size: 13px;
padding: 0; padding: 0;
} }
.btn-link.danger { .btn-link.danger {
color: #d33c3c;
color: var(--ac-danger);
} }
.error-text { .error-text {
color: #d33c3c;
color: var(--ac-danger);
} }
.hint-text { .hint-text {
color: #8a93a3;
color: var(--ac-text-disabled);
} }
</style> </style>

42
src/views/admin/CommentReviewView.vue

@ -171,16 +171,18 @@ onMounted(load)
<style scoped> <style scoped>
.page-title { .page-title {
font-family: var(--song-font-display);
font-weight: 400;
margin: 0 0 16px; margin: 0 0 16px;
font-size: 20px;
font-size: 22px;
} }
.comment-table { .comment-table {
width: 100%; width: 100%;
border-collapse: collapse; border-collapse: collapse;
background: #fff;
border: 1px solid #e5e5ea;
border-radius: 8px;
background: var(--ac-bg-card);
border: 1px solid var(--ac-border);
border-radius: var(--song-radius-l);
overflow: hidden; overflow: hidden;
} }
@ -188,13 +190,13 @@ onMounted(load)
.comment-table td { .comment-table td {
padding: 10px 14px; padding: 10px 14px;
text-align: left; text-align: left;
border-bottom: 1px solid #eee;
border-bottom: 1px solid var(--ac-border);
font-size: 14px; font-size: 14px;
} }
.comment-table th { .comment-table th {
background: #f7f8fa;
color: #5c6470;
background: var(--ac-surface);
color: var(--ac-text-secondary);
} }
.content-cell { .content-cell {
@ -203,29 +205,29 @@ onMounted(load)
} }
.sub-text { .sub-text {
color: #8a93a3;
color: var(--ac-text-disabled);
font-size: 12px; font-size: 12px;
} }
.status-badge { .status-badge {
padding: 2px 10px; padding: 2px 10px;
border-radius: 12px;
border-radius: var(--song-radius-m);
font-size: 12px; font-size: 12px;
} }
.status-badge.pending { .status-badge.pending {
background: #fff3cd;
color: #b26a00;
background: var(--ac-warning-bg);
color: var(--ac-warning);
} }
.status-badge.approved { .status-badge.approved {
background: #d4edda;
color: #1e7e34;
background: var(--ac-success-bg);
color: var(--ac-success);
} }
.status-badge.rejected { .status-badge.rejected {
background: #f8d7da;
color: #8f1f2b;
background: var(--ac-danger-bg);
color: var(--ac-danger);
} }
.actions { .actions {
@ -237,26 +239,26 @@ onMounted(load)
.btn-link { .btn-link {
border: none; border: none;
background: none; background: none;
color: #3b82f6;
color: var(--ac-primary);
cursor: pointer; cursor: pointer;
font-size: 13px; font-size: 13px;
padding: 0; padding: 0;
} }
.btn-link.danger { .btn-link.danger {
color: #d33c3c;
color: var(--ac-danger);
} }
.total-hint { .total-hint {
color: #8a93a3;
color: var(--ac-text-disabled);
font-size: 13px; font-size: 13px;
} }
.error-text { .error-text {
color: #d33c3c;
color: var(--ac-danger);
} }
.hint-text { .hint-text {
color: #8a93a3;
color: var(--ac-text-disabled);
} }
</style> </style>
Loading…
Cancel
Save