refactor(write): 写文章页改为左右两栏布局,编辑器自适应高度
原单列布局把编辑器挤到折叠线以下、又被元信息卡片压缩(h-[60vh]), 显得太矮。改为左右两栏: - 左栏(主写作区): 标题 + 摘要 + 编辑器,编辑器改为 flex-1 撑满 剩余高度(内部 .tiptap-editor/.ProseMirror 已是 height:100%)。 - 右栏(侧边栏, w-80): Slug + 标签 + 封面卡片纵向堆叠,独立滚动。 - 页头条提到两栏之上,底栏(取消/状态/发布)不变,仍横跨两列贴底。 #tiptap-editor 容器 id 保持不变,tiptap_bridge 按 id 挂载不受影响。 所有信号/server function/状态逻辑零改动,纯结构样式调整。
This commit is contained in:
parent
e8fc255b19
commit
7b678481c6
@ -419,24 +419,20 @@ fn write_editor(post_id: Option<i32>) -> Element {
|
||||
div { class: "absolute inset-0 z-10 bg-paper-theme", WriteSkeleton {} }
|
||||
}
|
||||
|
||||
// 内容区:单独滚动。layout 的 main 不再带 padding/滚动职责,
|
||||
// px-10 py-12 下放到这里,与其它 admin 页面的 main 视觉等价。
|
||||
// min-h-0 是 flex 子元素允许收缩到内容以下、让 overflow 生效的关键。
|
||||
div { class: "flex-1 min-h-0 overflow-y-auto px-10 py-12 flex flex-col",
|
||||
// 顶部元信息区域
|
||||
div { class: "flex-shrink-0 flex flex-col gap-6",
|
||||
// 页面标题与状态
|
||||
div { class: "flex flex-col md:flex-row md:items-end justify-between gap-6 pb-6 border-b border-[var(--color-paper-border)]",
|
||||
div {
|
||||
// 页头条:整宽,提到两栏之上,与内容区水平对齐(px-10 pt-10)。
|
||||
// flex-shrink-0 保证它不参与垂直伸缩。
|
||||
div { class: "flex-shrink-0 px-10 pt-10 pb-6 border-b border-[var(--color-paper-border)]",
|
||||
h1 { class: "text-4xl font-extrabold tracking-tight text-[var(--color-paper-primary)]",
|
||||
if is_edit { "编辑文章" } else { "撰写新文章" }
|
||||
}
|
||||
p { class: "text-base text-[var(--color-paper-secondary)] mt-2", "内容编辑器" }
|
||||
}
|
||||
}
|
||||
|
||||
// 核心文本域
|
||||
div { class: "flex flex-col gap-6",
|
||||
// 两栏容器:flex-1 分配空间,自身不滚动(min-h-0),滚动职责下放给左右两栏。
|
||||
div { class: "flex-1 min-h-0 flex",
|
||||
// 左栏(主写作区):flex-1 撑满宽度,min-w-0 防止长标题/代码块撑破 flex,
|
||||
// overflow-y-auto 独立滚动。
|
||||
div { class: "flex-1 min-w-0 min-h-0 overflow-y-auto px-10 py-8 flex flex-col",
|
||||
// 标题输入
|
||||
input {
|
||||
class: "w-full text-4xl md:text-5xl font-extrabold bg-transparent text-[var(--color-paper-primary)] placeholder-[var(--color-paper-tertiary)] focus:outline-none tracking-tight leading-tight",
|
||||
@ -447,57 +443,12 @@ fn write_editor(post_id: Option<i32>) -> Element {
|
||||
|
||||
// 摘要
|
||||
textarea {
|
||||
class: "w-full text-base font-normal bg-transparent text-[var(--color-paper-secondary)] placeholder-[var(--color-paper-tertiary)] focus:outline-none resize-none leading-relaxed mb-4 border-b-2 border-transparent focus:border-[var(--color-paper-border)] pb-2 transition-all",
|
||||
class: "w-full text-base font-normal bg-transparent text-[var(--color-paper-secondary)] placeholder-[var(--color-paper-tertiary)] focus:outline-none resize-none leading-relaxed mb-4 border-b-2 border-transparent focus:border-[var(--color-paper-border)] pb-2 transition-all mt-6",
|
||||
placeholder: "摘要(选填)...",
|
||||
rows: "2",
|
||||
value: "{summary}",
|
||||
oninput: move |evt| summary.set(evt.value()),
|
||||
}
|
||||
}
|
||||
|
||||
// 元信息放在控制面板网格
|
||||
div { class: "grid grid-cols-1 md:grid-cols-2 gap-6 mt-4",
|
||||
div { class: "flex flex-col gap-6 p-8 rounded-3xl border border-transparent bg-[var(--color-paper-entry)] hover:border-[var(--color-paper-border)] transition-colors shadow-sm",
|
||||
div {
|
||||
label { class: "{META_LABEL_CLASS}", "自定义链接 (Slug)" }
|
||||
input {
|
||||
class: "{META_INPUT_CLASS}",
|
||||
placeholder: "自动生成",
|
||||
value: "{slug}",
|
||||
oninput: move |evt| slug.set(evt.value()),
|
||||
}
|
||||
}
|
||||
div {
|
||||
label { class: "{META_LABEL_CLASS}", "标签系统" }
|
||||
input {
|
||||
class: "{META_INPUT_CLASS}",
|
||||
placeholder: "输入标签,以逗号分隔...",
|
||||
value: "{tags}",
|
||||
oninput: move |evt| tags.set(evt.value()),
|
||||
}
|
||||
}
|
||||
}
|
||||
// 封面图放右边
|
||||
div { class: "flex flex-col p-8 rounded-3xl border border-transparent bg-[var(--color-paper-entry)] hover:border-[var(--color-paper-border)] transition-colors shadow-sm",
|
||||
label { class: "{META_LABEL_CLASS}", "封面图" }
|
||||
CoverUploader { cover_image, cover_uploading }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 编辑器区域 - 整页滚动下用视口高度,保证充裕的编辑空间。
|
||||
// h-[60vh]:随窗口高度自适应;min-h-[400px]:窗口过矮时仍可用。
|
||||
div { class: "h-[60vh] min-h-[400px] flex flex-col my-4",
|
||||
div {
|
||||
class: "relative group flex-1 min-h-0 w-full border border-[var(--color-paper-border)] rounded-3xl overflow-hidden bg-[var(--color-paper-entry)] shadow-sm",
|
||||
id: "tiptap-editor",
|
||||
img {
|
||||
src: "/images/xiantiaoxiaogou_input_bg.webp",
|
||||
alt: "",
|
||||
class: "absolute bottom-2 right-2 w-24 opacity-10 pointer-events-none z-0",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 错误和成功提示
|
||||
if let Some(err) = load_error() {
|
||||
@ -538,7 +489,54 @@ fn write_editor(post_id: Option<i32>) -> Element {
|
||||
}
|
||||
}
|
||||
}
|
||||
} // 内容区闭合
|
||||
|
||||
// 编辑器区域:flex-1 撑满左栏剩余高度,不再硬编码 60vh。
|
||||
// 编辑器内部 .tiptap-editor/.ProseMirror 均为 height:100% + overflow-y:auto,
|
||||
// 容器变高编辑器自动跟着变高。min-h-[400px] 保证窗口过矮时仍可用。
|
||||
div { class: "flex-1 min-h-[400px] flex flex-col my-4",
|
||||
div {
|
||||
class: "relative group flex-1 min-h-0 w-full border border-[var(--color-paper-border)] rounded-3xl overflow-hidden bg-[var(--color-paper-entry)] shadow-sm",
|
||||
id: "tiptap-editor",
|
||||
img {
|
||||
src: "/images/xiantiaoxiaogou_input_bg.webp",
|
||||
alt: "",
|
||||
class: "absolute bottom-2 right-2 w-24 opacity-10 pointer-events-none z-0",
|
||||
}
|
||||
}
|
||||
}
|
||||
} // 左栏闭合
|
||||
|
||||
// 右栏(侧边栏):固定宽 w-80,flex-shrink-0 不被压缩,独立滚动。
|
||||
// border-l 与页头分割线视觉一致。
|
||||
div { class: "w-80 flex-shrink-0 min-h-0 overflow-y-auto border-l border-[var(--color-paper-border)] px-6 py-8 flex flex-col gap-6",
|
||||
// Slug + 标签卡片(沿用原元信息卡样式)
|
||||
div { class: "flex flex-col gap-6 p-8 rounded-3xl border border-transparent bg-[var(--color-paper-entry)] hover:border-[var(--color-paper-border)] transition-colors shadow-sm",
|
||||
div {
|
||||
label { class: "{META_LABEL_CLASS}", "自定义链接 (Slug)" }
|
||||
input {
|
||||
class: "{META_INPUT_CLASS}",
|
||||
placeholder: "自动生成",
|
||||
value: "{slug}",
|
||||
oninput: move |evt| slug.set(evt.value()),
|
||||
}
|
||||
}
|
||||
div {
|
||||
label { class: "{META_LABEL_CLASS}", "标签系统" }
|
||||
input {
|
||||
class: "{META_INPUT_CLASS}",
|
||||
placeholder: "输入标签,以逗号分隔...",
|
||||
value: "{tags}",
|
||||
oninput: move |evt| tags.set(evt.value()),
|
||||
}
|
||||
}
|
||||
}
|
||||
// 封面图卡片
|
||||
div { class: "flex flex-col p-8 rounded-3xl border border-transparent bg-[var(--color-paper-entry)] hover:border-[var(--color-paper-border)] transition-colors shadow-sm",
|
||||
label { class: "{META_LABEL_CLASS}", "封面图" }
|
||||
CoverUploader { cover_image, cover_uploading }
|
||||
}
|
||||
} // 右栏闭合
|
||||
} // 两栏容器闭合
|
||||
|
||||
// 底部操作栏 - flex 分区布局的贴底块:作为 main 直接子元素(flex-shrink-0),
|
||||
// 永远贴卡片底沿,不随内容区滚动。无需 sticky,不会跳动。
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user