refactor(write): 滚动条从内容区内部移到窗口边缘

将 /admin/write 从「锁一屏 + 内容区内部滚动」改为「整页自然滚动」,
滚动条出现在浏览器窗口右侧而非中间内容区边缘。

admin_layout: write 路由 root 由 h-dvh overflow-hidden 改为 min-h-dvh
自然文档流,main 去掉 overflow-hidden。

write.rs: 根 div 与内容区去掉 flex-1/min-h-0/overflow-y-auto 等滚动
约束;编辑器高度由 flex-1 改为 h-[60vh](min-h-[400px] 兜底);底部
操作栏去掉 flex-shrink-0,改为跟随页面滚动。

整页滚动时 Header 仍 sticky 吸顶(带毛玻璃),保存栏随内容滚走。
This commit is contained in:
xfy 2026-06-25 16:24:26 +08:00
parent 7611c60e6c
commit d41eb4b3cd
2 changed files with 13 additions and 16 deletions

View File

@ -96,14 +96,14 @@ pub fn AdminLayout() -> Element {
let is_write_route = let is_write_route =
matches!(route, Route::Write {}) || matches!(route, Route::WriteEdit { .. }); matches!(route, Route::Write {}) || matches!(route, Route::WriteEdit { .. });
let main_class = if is_write_route { let main_class = if is_write_route {
"flex-1 w-full max-w-5xl mx-auto px-6 flex flex-col overflow-hidden" "flex-1 w-full max-w-5xl mx-auto px-6 flex flex-col"
} else { } else {
"flex-1 w-full max-w-5xl mx-auto px-6 py-8" "flex-1 w-full max-w-5xl mx-auto px-6 py-8"
}; };
// Write 路由:页面固定高度,不滚动,由编辑器内部处理滚动 // 所有路由统一自然文档流:浏览器右侧滚动条,整页滚动。
let root_class = if is_write_route { let root_class = if is_write_route {
"h-dvh flex flex-col overflow-hidden bg-paper-theme" "min-h-dvh flex flex-col bg-paper-theme"
} else { } else {
"min-h-screen flex flex-col bg-paper-theme" "min-h-screen flex flex-col bg-paper-theme"
}; };

View File

@ -421,19 +421,16 @@ fn write_editor(post_id: Option<i32>) -> Element {
"w-full text-sm bg-transparent text-[var(--color-paper-primary)] placeholder-[var(--color-paper-tertiary)] focus:outline-none border-b border-[var(--color-paper-tertiary)] focus:border-[var(--color-paper-primary)] transition-colors pb-1.5"; "w-full text-sm bg-transparent text-[var(--color-paper-primary)] placeholder-[var(--color-paper-tertiary)] focus:outline-none border-b border-[var(--color-paper-tertiary)] focus:border-[var(--color-paper-primary)] transition-colors pb-1.5";
rsx! { rsx! {
div { class: "relative flex flex-col flex-1 min-h-0 overflow-hidden", div { class: "relative flex flex-col",
if loading() { if loading() {
div { class: "absolute inset-0 z-10 bg-paper-theme", div { class: "absolute inset-0 z-10 bg-paper-theme",
WriteSkeleton {} WriteSkeleton {}
} }
} }
// 可滚动主体:元信息 + 编辑器 + 内联错误提示。 // 整页自然滚动:元信息 + 编辑器 + 错误提示 + 底部操作栏一起随浏览器滚动。
// 底部操作栏留在此容器外(固定吸底),保证保存/状态按钮始终可见。 div { class: "flex flex-col",
// flex flex-col让内部 flex-1 编辑器能撑满剩余高度; // 顶部元信息区域
// overflow-y-auto内容超出时滚动min-h-0 允许 flex 子项收缩触发滚动)。
div { class: "flex-1 min-h-0 overflow-y-auto flex flex-col",
// 顶部元信息区域 - 固定高度,不滚动
div { class: "flex-shrink-0 space-y-5 pt-8", div { class: "flex-shrink-0 space-y-5 pt-8",
// 标题区域 - 大字号无框输入 // 标题区域 - 大字号无框输入
div { div {
@ -723,9 +720,9 @@ fn write_editor(post_id: Option<i32>) -> Element {
} }
} }
// 编辑器区域 - 沾满剩余高度,但保证最小编辑空间。 // 编辑器区域 - 整页滚动下用视口高度,保证充裕的编辑空间。
// min-h-[400px]窗口过矮时不被元信息挤压到不可用flex-1窗口充裕时填充 // h-[60vh]随窗口高度自适应min-h-[400px]:窗口过矮时仍可用
div { class: "flex-1 min-h-[400px] flex flex-col my-4", div { class: "h-[60vh] min-h-[400px] flex flex-col my-4",
div { div {
class: "flex-1 min-h-0 w-full border border-[var(--color-paper-border)] rounded-xl overflow-hidden bg-[var(--color-paper-entry)] shadow-[0_2px_8px_rgba(0,0,0,0.04)] dark:shadow-none", class: "flex-1 min-h-0 w-full border border-[var(--color-paper-border)] rounded-xl overflow-hidden bg-[var(--color-paper-entry)] shadow-[0_2px_8px_rgba(0,0,0,0.04)] dark:shadow-none",
id: "tiptap-editor", id: "tiptap-editor",
@ -769,10 +766,10 @@ fn write_editor(post_id: Option<i32>) -> Element {
} }
} }
} }
} // 滚动主体容器闭合 } // 内容区闭合
// 底部操作栏 - 固定吸底,不在滚动区域内 // 底部操作栏 - 跟随页面滚动
div { class: "flex-shrink-0 flex items-center gap-2 pt-2 pb-4 border-t border-[var(--color-paper-border)]", div { class: "flex items-center gap-2 pt-2 pb-4 border-t border-[var(--color-paper-border)]",
button { button {
class: "px-4 py-1.5 text-sm text-[var(--color-paper-secondary)] hover:text-[var(--color-paper-primary)] transition-colors cursor-pointer", class: "px-4 py-1.5 text-sm text-[var(--color-paper-secondary)] hover:text-[var(--color-paper-primary)] transition-colors cursor-pointer",
onclick: move |_| { onclick: move |_| {