Browse Source

fix(ux): improve comment spacing, merge admin titlebar into global header, fix dark mode editor

- CommentSection: add padding-top 8px to comment-item for spacing between author/time and top
- AdminLayout: remove sticky topbar (now merged into global App.vue header), clean up unused code
- App.vue: show page title for all routes with × separator after brand name, remove admin-route filter
- QuillEditor: use --ac-border-strong for toolbar/container borders, add toolbar button colors for dark mode
- ArticleEditorView: use --ac-border-strong for all borders, btn-cancel now light red with danger colors
main
Mohan 1 month ago
parent
commit
2379d220ce
  1. 8
      src/App.vue
  2. 1
      src/components/CommentSection.vue
  3. 21
      src/components/QuillEditor.vue
  4. 36
      src/views/admin/AdminLayout.vue
  5. 24
      src/views/admin/ArticleEditorView.vue

8
src/App.vue

@ -30,7 +30,7 @@ async function handleLogout() {
<div>
<header class="app-header">
<router-link to="/" class="brand">Mach-CMS</router-link>
<span v-if="pageTitle && !isAdminRoute" class="header-page-title">{{ pageTitle }}</span>
<span v-if="pageTitle" class="header-page-title"><span class="header-title-sep">×</span>{{ pageTitle }}</span>
<nav class="nav-links">
<router-link to="/">首页</router-link>
<router-link to="/search">搜索</router-link>
@ -89,6 +89,12 @@ async function handleLogout() {
color: var(--ac-header-text);
}
.header-title-sep {
margin: 0 8px;
color: var(--ac-header-muted);
font-weight: 400;
}
.app-header .brand {
display: flex;
align-items: center;

1
src/components/CommentSection.vue

@ -205,6 +205,7 @@ onMounted(() => {
.comment-item {
display: flex;
gap: 16px;
padding-top: 8px;
}
.comment-item:not(:last-child) .comment-card {

21
src/components/QuillEditor.vue

@ -87,13 +87,30 @@ watch(() => props.modelValue, (val) => {
line-height: 1.8;
}
.quill-editor :deep(.ql-toolbar) {
border-color: var(--ac-border, #d4c4b0);
border-color: var(--ac-border-strong, #d4c4b0);
background: var(--ac-surface, #faf8f5);
}
.quill-editor :deep(.ql-container) {
border-color: var(--ac-border, #d4c4b0);
border-color: var(--ac-border-strong, #d4c4b0);
}
.quill-editor :deep(.ql-editor.ql-blank::before) {
color: var(--ac-text-disabled);
}
.quill-editor :deep(.ql-toolbar button) {
color: var(--ac-text-secondary);
}
.quill-editor :deep(.ql-toolbar button:hover) {
color: var(--ac-text);
}
.quill-editor :deep(.ql-toolbar .ql-active) {
color: var(--ac-primary-ink);
}
.quill-editor :deep(.ql-toolbar .ql-picker-label),
.quill-editor :deep(.ql-toolbar .ql-picker-item) {
color: var(--ac-text-secondary);
}
.quill-editor :deep(.ql-toolbar .ql-picker-label:hover),
.quill-editor :deep(.ql-toolbar .ql-picker-item:hover) {
color: var(--ac-text);
}
</style>

36
src/views/admin/AdminLayout.vue

@ -1,12 +1,7 @@
<script setup lang="ts">
import { computed } from 'vue'
import { useRoute } from 'vue-router'
import { useAuthStore } from '@/stores/auth'
const auth = useAuthStore()
const route = useRoute()
const pageTitle = computed(() => (route.meta.title as string) || '')
</script>
<template>
@ -19,10 +14,6 @@ const pageTitle = computed(() => (route.meta.title as string) || '')
<router-link v-if="auth.isAdmin" to="/admin/comments">评论审核</router-link>
</nav>
</aside>
<div class="content-wrap">
<header class="topbar">
<span class="topbar-title">{{ pageTitle }}</span>
</header>
<main class="content">
<router-view v-slot="{ Component }">
<transition name="page" mode="out-in">
@ -31,7 +22,6 @@ const pageTitle = computed(() => (route.meta.title as string) || '')
</router-view>
</main>
</div>
</div>
</template>
<style scoped>
@ -70,33 +60,9 @@ const pageTitle = computed(() => (route.meta.title as string) || '')
color: var(--ac-header-text);
}
.content-wrap {
.content {
flex: 1;
display: flex;
flex-direction: column;
min-width: 0;
}
.topbar {
position: sticky;
top: 0;
z-index: 1000;
display: flex;
align-items: center;
padding: 0 20px;
height: 52px;
background: var(--ac-bg-card);
border-bottom: 1px solid var(--ac-border);
}
.topbar-title {
font-family: var(--song-font-serif);
font-size: 16px;
font-weight: 600;
color: var(--ac-text);
}
.content {
padding: 20px;
}
</style>

24
src/views/admin/ArticleEditorView.vue

@ -234,7 +234,7 @@ onMounted(() => {
.title-input {
width: 100%;
padding: 12px 16px;
border: 1px solid var(--ac-border);
border: 1px solid var(--ac-border-strong);
border-radius: var(--song-radius-l);
font-family: 'Noto Serif SC', 'SimSun', 'STSong', serif;
font-size: 22px;
@ -263,7 +263,7 @@ onMounted(() => {
.side-section {
background: var(--ac-bg-card);
border: 1px solid var(--ac-border);
border: 1px solid var(--ac-border-strong);
border-radius: var(--song-radius-l);
padding: 16px;
}
@ -299,7 +299,7 @@ onMounted(() => {
.summary-input {
width: 100%;
padding: 8px 12px;
border: 1px solid var(--ac-input-border);
border: 1px solid var(--ac-border-strong);
border-radius: var(--song-radius-l);
font-size: 13px;
line-height: 1.5;
@ -323,7 +323,7 @@ onMounted(() => {
max-height: 120px;
object-fit: cover;
border-radius: var(--song-radius-m);
border: 1px solid var(--ac-border);
border: 1px solid var(--ac-border-strong);
margin-bottom: 6px;
}
@ -344,15 +344,17 @@ onMounted(() => {
display: inline-block;
padding: 8px 14px;
background: var(--ac-primary-bg);
border: 1px solid var(--ac-border-strong);
color: var(--ac-primary-ink);
border-radius: var(--song-radius-m);
cursor: pointer;
font-size: 13px;
transition: background var(--song-dur-1) var(--song-ease);
transition: background var(--song-dur-1) var(--song-ease), border-color var(--song-dur-1) var(--song-ease);
}
.upload-btn:hover {
background: var(--ac-active);
border-color: var(--ac-primary-ink);
}
.upload-input {
@ -371,22 +373,24 @@ onMounted(() => {
gap: 6px;
font-size: 13px;
cursor: pointer;
color: var(--ac-text);
}
.btn-cancel {
display: block;
text-align: center;
padding: 8px;
border: 1px solid var(--ac-input-border);
border: 1px solid var(--ac-danger-bg);
border-radius: var(--song-radius-l);
color: var(--ac-text-secondary);
color: var(--ac-danger-ink);
background: var(--ac-danger-bg);
text-decoration: none;
font-size: 13px;
transition: border-color var(--song-dur-1) var(--song-ease), color var(--song-dur-1) var(--song-ease);
transition: background var(--song-dur-1) var(--song-ease), color var(--song-dur-1) var(--song-ease), border-color var(--song-dur-1) var(--song-ease);
}
.btn-cancel:hover {
border-color: var(--ac-primary);
color: var(--ac-primary-ink);
border-color: var(--ac-danger-ink);
color: var(--ac-danger-ink);
}
</style>
Loading…
Cancel
Save