From bf3ce934dd7faa3814ebe22e2bb4478d68bd1a35 Mon Sep 17 00:00:00 2001 From: Sakurasan <26715255+Sakurasan@users.noreply.github.com> Date: Thu, 1 Oct 2026 00:15:33 +0800 Subject: [PATCH] =?UTF-8?q?=E5=90=8E=E5=8F=B0=E7=AE=A1=E7=90=86=E6=89=8B?= =?UTF-8?q?=E6=9C=BA=E7=AB=AF=E9=80=82=E9=85=8D=EF=BC=9A=E4=BE=A7=E6=A0=8F?= =?UTF-8?q?=E6=94=B6=E6=88=90=20=E2=98=B0=20=E6=8A=BD=E5=B1=89=EF=BC=8C?= =?UTF-8?q?=E5=88=97=E8=A1=A8/=E6=80=BB=E8=A7=88=E5=93=8D=E5=BA=94?= =?UTF-8?q?=E5=BC=8F=E5=8D=95=E5=88=97=EF=BC=8C=E7=BC=96=E8=BE=91=E5=99=A8?= =?UTF-8?q?=E8=B4=B4=E8=BE=B9=E4=B8=8E=E5=B7=A5=E5=85=B7=E6=A0=8F=E6=94=B6?= =?UTF-8?q?=E7=B4=A7=EF=BC=8C=E4=BF=AE=20iOS=20=E8=81=9A=E7=84=A6=E7=BC=A9?= =?UTF-8?q?=E6=94=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/admin/AdminLayout.vue | 18 +++- frontend/src/admin/DashboardView.vue | 19 +++- frontend/src/admin/EditorView.vue | 6 +- frontend/src/styles.css | 146 ++++++++++++++++++++++++--- 4 files changed, 168 insertions(+), 21 deletions(-) diff --git a/frontend/src/admin/AdminLayout.vue b/frontend/src/admin/AdminLayout.vue index cdeb1e1..7031211 100644 --- a/frontend/src/admin/AdminLayout.vue +++ b/frontend/src/admin/AdminLayout.vue @@ -14,6 +14,7 @@ const route = useRoute() const ready = ref(false) const paletteOpen = ref(false) const shortcutsOpen = ref(false) +const sideOpen = ref(false) const counts = ref({ published: 0, draft: 0, tags: 0 }) async function loadCounts() { @@ -75,6 +76,8 @@ function onKeydown(e) { paletteOpen.value = true return } + // Esc 收起手机端抽屉 + if (e.key === 'Escape') sideOpen.value = false // ? if (e.key === '?' && !e.metaKey && !e.ctrlKey && !e.altKey) { const t = e.target @@ -91,14 +94,17 @@ function onKeydown(e) { onMounted(() => window.addEventListener('keydown', onKeydown)) onBeforeUnmount(() => window.removeEventListener('keydown', onKeydown)) -// refresh counts when route changes (posts / tags edited) -watch(() => route.path, () => loadCounts()) +// refresh counts when route changes (posts / tags edited); 顺手收起手机端抽屉 +watch(() => route.path, () => { + sideOpen.value = false + loadCounts() +}) \ No newline at end of file + + diff --git a/frontend/src/admin/EditorView.vue b/frontend/src/admin/EditorView.vue index 956e83e..3d85faa 100644 --- a/frontend/src/admin/EditorView.vue +++ b/frontend/src/admin/EditorView.vue @@ -910,13 +910,13 @@ const tbGroups = computed(() => [
-
+
- + {{ form.kind === 'short' ? '一两段话,时间线里不显示标题' : '有标题、有结构,适合讲完整一件事' }} - +
diff --git a/frontend/src/styles.css b/frontend/src/styles.css index 90b8f14..00fd3c4 100644 --- a/frontend/src/styles.css +++ b/frontend/src/styles.css @@ -502,15 +502,12 @@ html.topbar-hidden {--topbar-h: 0px;} width: 100%; margin: 0 auto;} @media (max-width: 860px) { - .admin-shell {grid-template-columns: 1fr;} - .admin-side {position: static; - height: auto; - border-right: 0; - border-bottom: 1px solid var(--admin-line);} - .admin-side .nav {flex-direction: row; - flex-wrap: wrap; - padding: 8px;} - .admin-side .group {display: none;} + /* minmax(0,1fr) 而非裸 1fr:裸 1fr 带 min-content 下限,内容宽的页面会把 + 整条轨道连页面一起撑出横向滚动。align-content:start:shell 的 + min-height:100dvh 会把 auto 行拉伸填满屏幕,行高回到内容高度。 + 侧栏本身在 ≤860px 变成抽屉(规则在文件末尾「后台 · 手机端适配」段)。 */ + .admin-shell {grid-template-columns: minmax(0, 1fr); + align-content: start;} .admin-content {padding: 20px 16px 60px;} } @media (max-width: 780px) { @@ -737,12 +734,21 @@ html.topbar-hidden {--topbar-h: 0px;} cursor: pointer;} .post-card.has-check {grid-template-columns: 24px 96px minmax(0, 1fr) 110px 90px;} @media (max-width: 760px) { + /* has-check 必须一起覆写:它(0,2,0)写在上面,单列 .post-card(0,1,0) 压不过它, + 5 列会被 390px 挤成一字一行。操作链接保留(藏掉就删不了文章), + 挪到正文下面一行;字数/时长列是次要信息,手机上藏掉。 */ .post-card {grid-template-columns: 64px minmax(0, 1fr);} + .post-card.has-check {grid-template-columns: 24px 64px minmax(0, 1fr);} .post-card .cover {width: 64px; height: 64px;} - .post-card .stats, .post-card .actions {display: none;} + .post-card .stats {display: none;} + .post-card .actions {grid-column: 2 / -1; + grid-row: 2; + flex-direction: row; + gap: 14px;} } .bulk-bar {display: flex; + flex-wrap: wrap; align-items: center; gap: 12px; padding: 10px 14px; @@ -891,8 +897,8 @@ html.topbar-hidden {--topbar-h: 0px;} .toolbar {display: flex; flex-wrap: wrap; align-items: center; - gap: 10px; - padding: 6px 8px; + gap: 0 10px; + padding: 4px 6px; border: 1px solid var(--admin-line); border-bottom: 0; border-radius: 3px 3px 0 0; @@ -1449,3 +1455,119 @@ body.lb-open .reading-bar {visibility: hidden;} z-index: 60; transition: width .1s linear; pointer-events: none;} + +/* ========================================================================== + 后台 · 手机端适配 + -------------------------------------------------------------------------- + 放在文件末尾:上面的 .editor-mode / .tb-btn / .tb-popover .input / .chip + 等基础定义同特指度、位置更靠后,手机端覆写写在前面会被反压(chrome.css + 同款老坑)。 + ========================================================================== */ +/* 顶栏退出按钮:桌面隐藏,退出走侧栏 footer;≤860px 侧栏进抽屉后 + 退出固定在顶栏(显示规则在下面的 ≤860px 块)。 */ +.admin-topbar .leave-m {display: none; + padding: 5px 12px; + font-size: 12.5px; + color: var(--admin-muted); + border: 1px solid var(--admin-line); + background: var(--admin-paper); + border-radius: 6px; + cursor: pointer;} +/* 顶栏 ☰:唤出侧栏抽屉,桌面隐藏。 */ +.admin-topbar .menu-btn {display: none; + width: 36px; + height: 36px; + align-items: center; + justify-content: center; + padding: 0; + border: 1px solid var(--admin-line); + border-radius: 6px; + background: var(--admin-paper); + color: var(--admin-ink); + font-size: 15px; + cursor: pointer;} +.admin-topbar .crumbs {display: flex; + align-items: center; + gap: 10px;} +/* ≤860px:侧栏整体收成抽屉。横铺一行要横向滚、换行三行吃掉 230px+ 才见 + 内容,竖排抽屉两头都不占——☰ 唤出、点遮罩或 Esc 或跳转后收回。 + 宽度 264px 比桌面 224px 略宽:手机上项的可点区域更足。 */ +@media (max-width: 860px) { + .admin-side {position: fixed; + top: 0; + bottom: 0; + left: 0; + width: 264px; + height: auto; + z-index: 120; + border-right: 1px solid var(--admin-line); + border-bottom: 0; + transform: translateX(-105%); + transition: transform 0.28s ease;} + .admin-side.open {transform: none; + box-shadow: var(--admin-shadow);} + .admin-side .group {display: block;} + .side-scrim {position: fixed; + inset: 0; + z-index: 110; + background: var(--admin-overlay); + opacity: 0; + pointer-events: none; + transition: opacity 0.25s ease;} + .side-scrim.on {opacity: 1; + pointer-events: auto;} + .admin-topbar {padding: 0 14px;} + .admin-topbar .menu-btn {display: inline-flex;} + .admin-topbar .leave-m {display: inline-block;} + .admin-content {padding: 16px 12px 60px;} +} +/* 手机端(≤720px)编辑器细节:⌘K 对触屏无意义藏掉 kbd;类型/模式切换条 + 收满一行,避免「转存外链图」被压成一字一行。 */ +@media (max-width: 720px) { + .admin-topbar .cmd-hint kbd {display: none;} + /* Crepe 主题给左侧 +/拖拽手柄留了 120px 槽位,手机上吃掉三分之一宽度; + 上下也各留 60px,第一行文字离头顶太远。触屏上把手柄藏掉(插块走 / + 斜杠菜单),四边收紧到 16px,正文贴边、第一行上移;特指度压过 crepe + frame 主题的 .milkdown .editor。手柄的 display:flex 是插件运行时写在 + 内联样式上的,必须 !important 才压得住。 */ + .admin-content .milkdown .ProseMirror {padding: 16px;} + .admin-content .milkdown-block-handle {display: none !important;} + .editor-top-row .kind-hint, + .editor-top-row .spacer {display: none;} + .editor-mode {display: flex; + width: 100%;} + .editor-mode button {flex: 1; + white-space: nowrap;} + /* 链接/图片输入条:一行塞不下两组输入框,改上下堆叠 */ + .tb-popover {flex-wrap: wrap;} + .tb-popover .input {flex: 1 1 100%;} + .tb-popover > .btn {flex: 1;} + /* 字数统计条放得下、不挤爆 */ + .editor-stats {flex-wrap: wrap; + row-gap: 4px;} +} +/* 触屏:iOS 聚焦时字号 <16px 的输入框会触发页面自动放大—— + CodeMirror 正文与链接/图片输入条都显式压过字号,这里抬回 16px。 + 顺带把工具栏按钮提到 40px,够得上指腹。 */ +@media (pointer: coarse) { + .tb-btn {width: 38px; + height: 36px;} + .tb-btn svg {width: 18px; + height: 18px;} + .tb-popover .input {font-size: 16px;} + .md-pane .cm-content {font-size: 16px;} + .chip {padding: 8px 14px;} +} +/* 编辑器顶部行:改用类而不是行内样式,手机端才有得调(上面的 ≤720px 规则) */ +.editor-top-row {display: flex; + gap: 6px; + align-items: center; + flex-wrap: wrap; + margin-bottom: 10px;} +.editor-top-row .kind-hint {font-size: 12px; + color: var(--admin-muted); + margin-left: 4px;} +.editor-top-row .spacer {flex: 1;} +/* 富文本空态只有 64px 高,跟 Markdown 页签(.md-pane min-height:460px)差一截; + 对齐到 460px,白底画在 .milkdown 上,min-height 就够撑起整块。 */ +.admin-content .milkdown {min-height: 460px;}