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

52
src/views/admin/ArticleListView.vue

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

42
src/views/admin/CommentReviewView.vue

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