style(ui): 组件圆角类对齐三档梯度(32/16/8)
配合 input.css 的 token 化,把散落在 RSX 组件里的孤悬圆角档位 统一到内容档 16px (rounded-2xl): 消除 24px (rounded-3xl, 4处无规范依据的中间档): - ADMIN_CARD_CLASS / ADMIN_TABLE_CLASS (ui.rs) - write.rs 编辑器容器 / write_skeleton.rs 编辑器骨架 消除 12px (rounded-xl, 10处): - INPUT_CLASS (forms.rs) 与 write 页输入框统一到 16px - write 页 3 处输入框 + 4 处错误提示框 - admin_layout 退出按钮 - system/admin_skeleton/posts_trash 卡片容器 - write_skeleton 骨架条(模拟输入框形状,跟随真实圆角) 改造后全站只剩 4 种圆角语义: 32px容器 / 16px内容 / 8px微元素 / 胶囊按钮,孤悬档位彻底清除。
This commit is contained in:
parent
248dcb761c
commit
ee9d2ecd6e
@ -111,7 +111,7 @@ pub fn AdminLayout() -> Element {
|
|||||||
div { class: "mt-auto pt-6 border-t border-[var(--color-paper-border)] flex items-center justify-between px-4",
|
div { class: "mt-auto pt-6 border-t border-[var(--color-paper-border)] flex items-center justify-between px-4",
|
||||||
ThemeToggle {}
|
ThemeToggle {}
|
||||||
button {
|
button {
|
||||||
class: "text-sm font-medium px-4 py-2 rounded-xl bg-[var(--color-paper-theme)] border border-[var(--color-paper-border)] shadow-sm hover:shadow-md transition-all text-[var(--color-paper-secondary)] hover:text-red-500 cursor-pointer",
|
class: "text-sm font-medium px-4 py-2 rounded-2xl bg-[var(--color-paper-theme)] border border-[var(--color-paper-border)] shadow-sm hover:shadow-md transition-all text-[var(--color-paper-secondary)] hover:text-red-500 cursor-pointer",
|
||||||
onclick: move |_| {
|
onclick: move |_| {
|
||||||
spawn(async move {
|
spawn(async move {
|
||||||
let _ = logout().await;
|
let _ = logout().await;
|
||||||
|
|||||||
@ -17,7 +17,7 @@ pub fn AdminDashboardSkeleton() -> Element {
|
|||||||
// 统计卡片骨架
|
// 统计卡片骨架
|
||||||
div { class: "grid grid-cols-1 md:grid-cols-3 gap-6",
|
div { class: "grid grid-cols-1 md:grid-cols-3 gap-6",
|
||||||
for _ in 0..3 {
|
for _ in 0..3 {
|
||||||
div { class: "rounded-xl bg-paper-entry border border-paper-border p-6 text-center space-y-3",
|
div { class: "rounded-2xl bg-paper-entry border border-paper-border p-6 text-center space-y-3",
|
||||||
SkeletonBox { class: "h-9 w-16 mx-auto rounded" }
|
SkeletonBox { class: "h-9 w-16 mx-auto rounded" }
|
||||||
SkeletonBox { class: "h-4 w-20 mx-auto rounded" }
|
SkeletonBox { class: "h-4 w-20 mx-auto rounded" }
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
use dioxus::prelude::*;
|
use dioxus::prelude::*;
|
||||||
|
|
||||||
/// 输入框基础 CSS 类,统一文本框、邮箱框、URL 框等样式。
|
/// 输入框基础 CSS 类,统一文本框、邮箱框、URL 框等样式。
|
||||||
pub const INPUT_CLASS: &str = "w-full px-4 py-2 border border-paper-border rounded-lg bg-paper-entry text-paper-primary placeholder:text-paper-tertiary focus:outline-none focus:border-paper-accent focus:ring-1 focus:ring-paper-accent/30 transition-colors duration-200";
|
pub const INPUT_CLASS: &str = "w-full px-4 py-2 border border-paper-border rounded-2xl bg-paper-entry text-paper-primary placeholder:text-paper-tertiary focus:outline-none focus:border-paper-accent focus:ring-1 focus:ring-paper-accent/30 transition-colors duration-200";
|
||||||
|
|
||||||
/// 主按钮 CSS 类,用于表单提交等主操作按钮。
|
/// 主按钮 CSS 类,用于表单提交等主操作按钮。
|
||||||
pub const BUTTON_PRIMARY_CLASS: &str = "w-full py-2.5 px-4 bg-paper-accent text-white font-medium rounded-full hover:brightness-110 active:scale-[0.98] transition-all duration-200 cursor-pointer";
|
pub const BUTTON_PRIMARY_CLASS: &str = "w-full py-2.5 px-4 bg-paper-accent text-white font-medium rounded-full hover:brightness-110 active:scale-[0.98] transition-all duration-200 cursor-pointer";
|
||||||
|
|||||||
@ -15,11 +15,11 @@ use crate::router::Route;
|
|||||||
// 样式常量
|
// 样式常量
|
||||||
// ===========================================================================
|
// ===========================================================================
|
||||||
|
|
||||||
/// Admin 卡片容器:大圆角,极简风,现代简约。
|
/// Admin 卡片容器:内容档圆角(16px),作为主面板内的内容卡片,与外壳 32px 形成层次。
|
||||||
pub const ADMIN_CARD_CLASS: &str = "bg-[var(--color-paper-entry)] rounded-3xl shadow-sm border border-transparent hover:border-[var(--color-paper-border)] transition-colors";
|
pub const ADMIN_CARD_CLASS: &str = "bg-[var(--color-paper-entry)] rounded-2xl shadow-sm border border-transparent hover:border-[var(--color-paper-border)] transition-colors";
|
||||||
|
|
||||||
/// Admin 表格容器:大圆角,现代简约,与卡片一致。
|
/// Admin 表格容器:内容档圆角(16px),与卡片一致。
|
||||||
pub const ADMIN_TABLE_CLASS: &str = "bg-[var(--color-paper-entry)] rounded-3xl shadow-sm border border-transparent hover:border-[var(--color-paper-border)] transition-colors overflow-hidden";
|
pub const ADMIN_TABLE_CLASS: &str = "bg-[var(--color-paper-entry)] rounded-2xl shadow-sm border border-transparent hover:border-[var(--color-paper-border)] transition-colors overflow-hidden";
|
||||||
|
|
||||||
/// Admin 表格行 hover 态:底部分割线 + 悬停背景。
|
/// Admin 表格行 hover 态:底部分割线 + 悬停背景。
|
||||||
pub const ADMIN_ROW_HOVER: &str =
|
pub const ADMIN_ROW_HOVER: &str =
|
||||||
|
|||||||
@ -25,7 +25,7 @@ pub fn WriteSkeleton() -> Element {
|
|||||||
|
|
||||||
// 编辑器区域:flex-1 撑满左栏剩余高度
|
// 编辑器区域:flex-1 撑满左栏剩余高度
|
||||||
div { class: "flex-1 min-h-[400px] flex flex-col my-4",
|
div { class: "flex-1 min-h-[400px] flex flex-col my-4",
|
||||||
div { class: "flex-1 min-h-0 w-full border border-[var(--color-paper-border)] rounded-3xl overflow-hidden bg-[var(--color-paper-entry)] shadow-sm p-4",
|
div { class: "flex-1 min-h-0 w-full border border-[var(--color-paper-border)] rounded-2xl overflow-hidden bg-[var(--color-paper-entry)] shadow-sm p-4",
|
||||||
// 工具栏
|
// 工具栏
|
||||||
div { class: "flex gap-2 pb-3 border-b border-[var(--color-paper-border)]",
|
div { class: "flex gap-2 pb-3 border-b border-[var(--color-paper-border)]",
|
||||||
for _ in 0..8 {
|
for _ in 0..8 {
|
||||||
@ -51,17 +51,17 @@ pub fn WriteSkeleton() -> Element {
|
|||||||
// 链接节
|
// 链接节
|
||||||
div { class: "p-6 border-b border-[var(--color-paper-border)]",
|
div { class: "p-6 border-b border-[var(--color-paper-border)]",
|
||||||
SkeletonBox { class: "h-3 w-10 rounded mb-3" }
|
SkeletonBox { class: "h-3 w-10 rounded mb-3" }
|
||||||
SkeletonBox { class: "h-8 w-full rounded-xl" }
|
SkeletonBox { class: "h-8 w-full rounded-2xl" }
|
||||||
}
|
}
|
||||||
// 标签节
|
// 标签节
|
||||||
div { class: "p-6 border-b border-[var(--color-paper-border)]",
|
div { class: "p-6 border-b border-[var(--color-paper-border)]",
|
||||||
SkeletonBox { class: "h-3 w-10 rounded mb-3" }
|
SkeletonBox { class: "h-3 w-10 rounded mb-3" }
|
||||||
SkeletonBox { class: "h-8 w-full rounded-xl" }
|
SkeletonBox { class: "h-8 w-full rounded-2xl" }
|
||||||
}
|
}
|
||||||
// 摘要节
|
// 摘要节
|
||||||
div { class: "p-6 border-b border-[var(--color-paper-border)]",
|
div { class: "p-6 border-b border-[var(--color-paper-border)]",
|
||||||
SkeletonBox { class: "h-3 w-10 rounded mb-3" }
|
SkeletonBox { class: "h-3 w-10 rounded mb-3" }
|
||||||
SkeletonBox { class: "h-16 w-full rounded-xl" }
|
SkeletonBox { class: "h-16 w-full rounded-2xl" }
|
||||||
}
|
}
|
||||||
// 封面图节
|
// 封面图节
|
||||||
div { class: "p-6",
|
div { class: "p-6",
|
||||||
|
|||||||
@ -367,7 +367,7 @@ fn AutoPurgeSettings(settings: Signal<TrashSettings>) -> Element {
|
|||||||
};
|
};
|
||||||
|
|
||||||
rsx! {
|
rsx! {
|
||||||
div { class: "rounded-xl border border-paper-border overflow-hidden bg-paper-entry",
|
div { class: "rounded-2xl border border-paper-border overflow-hidden bg-paper-entry",
|
||||||
// 顶部可点击摘要条:状态指示灯 + 标题 + 展开箭头
|
// 顶部可点击摘要条:状态指示灯 + 标题 + 展开箭头
|
||||||
button {
|
button {
|
||||||
class: "w-full flex items-center gap-3 px-5 py-4 text-left cursor-pointer hover:bg-paper-theme focus:outline-none focus-visible:ring-2 focus-visible:ring-paper-accent/40",
|
class: "w-full flex items-center gap-3 px-5 py-4 text-left cursor-pointer hover:bg-paper-theme focus:outline-none focus-visible:ring-2 focus-visible:ring-paper-accent/40",
|
||||||
|
|||||||
@ -421,14 +421,14 @@ fn DbStatusTab() -> Element {
|
|||||||
// 概览卡片骨架
|
// 概览卡片骨架
|
||||||
div { class: "grid grid-cols-2 md:grid-cols-4 gap-4",
|
div { class: "grid grid-cols-2 md:grid-cols-4 gap-4",
|
||||||
for _ in 0..4 {
|
for _ in 0..4 {
|
||||||
div { class: "rounded-xl bg-paper-entry border border-paper-border p-4 space-y-2",
|
div { class: "rounded-2xl bg-paper-entry border border-paper-border p-4 space-y-2",
|
||||||
SkeletonBox { class: "h-3 w-16 rounded" }
|
SkeletonBox { class: "h-3 w-16 rounded" }
|
||||||
SkeletonBox { class: "h-6 w-24 rounded" }
|
SkeletonBox { class: "h-6 w-24 rounded" }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 表清单骨架
|
// 表清单骨架
|
||||||
div { class: "rounded-xl bg-paper-entry border border-paper-border overflow-hidden",
|
div { class: "rounded-2xl bg-paper-entry border border-paper-border overflow-hidden",
|
||||||
div { class: "px-4 py-3 border-b border-paper-border",
|
div { class: "px-4 py-3 border-b border-paper-border",
|
||||||
SkeletonBox { class: "h-4 w-40 rounded" }
|
SkeletonBox { class: "h-4 w-40 rounded" }
|
||||||
}
|
}
|
||||||
@ -704,7 +704,7 @@ fn ServerStatusTab() -> Element {
|
|||||||
// 应用内指标卡片骨架
|
// 应用内指标卡片骨架
|
||||||
div { class: "grid grid-cols-2 md:grid-cols-4 gap-4",
|
div { class: "grid grid-cols-2 md:grid-cols-4 gap-4",
|
||||||
for _ in 0..4 {
|
for _ in 0..4 {
|
||||||
div { class: "rounded-xl bg-paper-entry border border-paper-border p-4 space-y-2",
|
div { class: "rounded-2xl bg-paper-entry border border-paper-border p-4 space-y-2",
|
||||||
SkeletonBox { class: "h-3 w-16 rounded" }
|
SkeletonBox { class: "h-3 w-16 rounded" }
|
||||||
SkeletonBox { class: "h-6 w-24 rounded" }
|
SkeletonBox { class: "h-6 w-24 rounded" }
|
||||||
}
|
}
|
||||||
@ -713,14 +713,14 @@ fn ServerStatusTab() -> Element {
|
|||||||
// 主机层指标卡片骨架
|
// 主机层指标卡片骨架
|
||||||
div { class: "grid grid-cols-2 md:grid-cols-4 gap-4",
|
div { class: "grid grid-cols-2 md:grid-cols-4 gap-4",
|
||||||
for _ in 0..4 {
|
for _ in 0..4 {
|
||||||
div { class: "rounded-xl bg-paper-entry border border-paper-border p-4 space-y-2",
|
div { class: "rounded-2xl bg-paper-entry border border-paper-border p-4 space-y-2",
|
||||||
SkeletonBox { class: "h-3 w-16 rounded" }
|
SkeletonBox { class: "h-3 w-16 rounded" }
|
||||||
SkeletonBox { class: "h-6 w-24 rounded" }
|
SkeletonBox { class: "h-6 w-24 rounded" }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 缓存命中率表骨架
|
// 缓存命中率表骨架
|
||||||
div { class: "rounded-xl bg-paper-entry border border-paper-border overflow-hidden",
|
div { class: "rounded-2xl bg-paper-entry border border-paper-border overflow-hidden",
|
||||||
div { class: "px-4 py-3 border-b border-paper-border",
|
div { class: "px-4 py-3 border-b border-paper-border",
|
||||||
SkeletonBox { class: "h-4 w-24 rounded" }
|
SkeletonBox { class: "h-4 w-24 rounded" }
|
||||||
}
|
}
|
||||||
|
|||||||
@ -432,13 +432,13 @@ fn write_editor(post_id: Option<i32>) -> Element {
|
|||||||
|
|
||||||
// 错误和成功提示
|
// 错误和成功提示
|
||||||
if let Some(err) = load_error() {
|
if let Some(err) = load_error() {
|
||||||
div { class: "flex-shrink-0 px-4 py-2 bg-red-50 dark:bg-red-900/20 text-red-600 dark:text-red-400 rounded-xl text-sm border border-red-100 dark:border-red-900/30 mb-2",
|
div { class: "flex-shrink-0 px-4 py-2 bg-red-50 dark:bg-red-900/20 text-red-600 dark:text-red-400 rounded-2xl text-sm border border-red-100 dark:border-red-900/30 mb-2",
|
||||||
"{err}"
|
"{err}"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(err) = error() {
|
if let Some(err) = error() {
|
||||||
div { class: "flex-shrink-0 px-4 py-2 bg-red-50 dark:bg-red-900/20 text-red-600 dark:text-red-400 rounded-xl text-sm border border-red-100 dark:border-red-900/30 mb-2",
|
div { class: "flex-shrink-0 px-4 py-2 bg-red-50 dark:bg-red-900/20 text-red-600 dark:text-red-400 rounded-2xl text-sm border border-red-100 dark:border-red-900/30 mb-2",
|
||||||
"{err}"
|
"{err}"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -447,7 +447,7 @@ fn write_editor(post_id: Option<i32>) -> Element {
|
|||||||
for err in upload_errors().clone() {
|
for err in upload_errors().clone() {
|
||||||
div {
|
div {
|
||||||
key: "{err.id}",
|
key: "{err.id}",
|
||||||
class: "flex-shrink-0 flex items-center justify-between gap-3 px-4 py-2 bg-red-50 dark:bg-red-900/20 text-red-600 dark:text-red-400 rounded-xl text-sm border border-red-100 dark:border-red-900/30 mb-2",
|
class: "flex-shrink-0 flex items-center justify-between gap-3 px-4 py-2 bg-red-50 dark:bg-red-900/20 text-red-600 dark:text-red-400 rounded-2xl text-sm border border-red-100 dark:border-red-900/30 mb-2",
|
||||||
span { "图片上传失败: {err.file_name} — {err.message}" }
|
span { "图片上传失败: {err.file_name} — {err.message}" }
|
||||||
button {
|
button {
|
||||||
class: "{BTN_CLOSE_ICON}",
|
class: "{BTN_CLOSE_ICON}",
|
||||||
@ -475,7 +475,7 @@ fn write_editor(post_id: Option<i32>) -> Element {
|
|||||||
// 容器变高编辑器自动跟着变高。min-h-[400px] 保证窗口过矮时仍可用。
|
// 容器变高编辑器自动跟着变高。min-h-[400px] 保证窗口过矮时仍可用。
|
||||||
div { class: "flex-1 min-h-[400px] flex flex-col my-4",
|
div { class: "flex-1 min-h-[400px] flex flex-col my-4",
|
||||||
div {
|
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",
|
class: "relative group flex-1 min-h-0 w-full border border-[var(--color-paper-border)] rounded-2xl overflow-hidden bg-[var(--color-paper-entry)] shadow-sm",
|
||||||
id: "tiptap-editor",
|
id: "tiptap-editor",
|
||||||
img {
|
img {
|
||||||
src: "/images/xiantiaoxiaogou_input_bg.webp",
|
src: "/images/xiantiaoxiaogou_input_bg.webp",
|
||||||
@ -493,7 +493,7 @@ fn write_editor(post_id: Option<i32>) -> Element {
|
|||||||
div { class: "p-6 border-b border-[var(--color-paper-border)]",
|
div { class: "p-6 border-b border-[var(--color-paper-border)]",
|
||||||
label { class: "block text-xs font-semibold uppercase tracking-wide text-[var(--color-paper-tertiary)] mb-3", "链接" }
|
label { class: "block text-xs font-semibold uppercase tracking-wide text-[var(--color-paper-tertiary)] mb-3", "链接" }
|
||||||
input {
|
input {
|
||||||
class: "w-full text-sm bg-[var(--color-paper-entry)] text-[var(--color-paper-primary)] placeholder-[var(--color-paper-tertiary)] focus:outline-none border border-[var(--color-paper-border)] focus:border-[var(--color-paper-primary)] rounded-xl px-3 py-2 transition-all",
|
class: "w-full text-sm bg-[var(--color-paper-entry)] text-[var(--color-paper-primary)] placeholder-[var(--color-paper-tertiary)] focus:outline-none border border-[var(--color-paper-border)] focus:border-[var(--color-paper-primary)] rounded-2xl px-3 py-2 transition-all",
|
||||||
placeholder: "自动生成",
|
placeholder: "自动生成",
|
||||||
value: "{slug}",
|
value: "{slug}",
|
||||||
oninput: move |evt| slug.set(evt.value()),
|
oninput: move |evt| slug.set(evt.value()),
|
||||||
@ -503,7 +503,7 @@ fn write_editor(post_id: Option<i32>) -> Element {
|
|||||||
div { class: "p-6 border-b border-[var(--color-paper-border)]",
|
div { class: "p-6 border-b border-[var(--color-paper-border)]",
|
||||||
label { class: "block text-xs font-semibold uppercase tracking-wide text-[var(--color-paper-tertiary)] mb-3", "标签" }
|
label { class: "block text-xs font-semibold uppercase tracking-wide text-[var(--color-paper-tertiary)] mb-3", "标签" }
|
||||||
input {
|
input {
|
||||||
class: "w-full text-sm bg-[var(--color-paper-entry)] text-[var(--color-paper-primary)] placeholder-[var(--color-paper-tertiary)] focus:outline-none border border-[var(--color-paper-border)] focus:border-[var(--color-paper-primary)] rounded-xl px-3 py-2 transition-all",
|
class: "w-full text-sm bg-[var(--color-paper-entry)] text-[var(--color-paper-primary)] placeholder-[var(--color-paper-tertiary)] focus:outline-none border border-[var(--color-paper-border)] focus:border-[var(--color-paper-primary)] rounded-2xl px-3 py-2 transition-all",
|
||||||
placeholder: "逗号分隔...",
|
placeholder: "逗号分隔...",
|
||||||
value: "{tags}",
|
value: "{tags}",
|
||||||
oninput: move |evt| tags.set(evt.value()),
|
oninput: move |evt| tags.set(evt.value()),
|
||||||
@ -513,7 +513,7 @@ fn write_editor(post_id: Option<i32>) -> Element {
|
|||||||
div { class: "p-6 border-b border-[var(--color-paper-border)]",
|
div { class: "p-6 border-b border-[var(--color-paper-border)]",
|
||||||
label { class: "block text-xs font-semibold uppercase tracking-wide text-[var(--color-paper-tertiary)] mb-3", "摘要" }
|
label { class: "block text-xs font-semibold uppercase tracking-wide text-[var(--color-paper-tertiary)] mb-3", "摘要" }
|
||||||
textarea {
|
textarea {
|
||||||
class: "w-full text-sm bg-[var(--color-paper-entry)] text-[var(--color-paper-primary)] placeholder-[var(--color-paper-tertiary)] focus:outline-none border border-[var(--color-paper-border)] focus:border-[var(--color-paper-primary)] rounded-xl px-3 py-2 transition-all resize-none leading-relaxed",
|
class: "w-full text-sm bg-[var(--color-paper-entry)] text-[var(--color-paper-primary)] placeholder-[var(--color-paper-tertiary)] focus:outline-none border border-[var(--color-paper-border)] focus:border-[var(--color-paper-primary)] rounded-2xl px-3 py-2 transition-all resize-none leading-relaxed",
|
||||||
placeholder: "选填...",
|
placeholder: "选填...",
|
||||||
rows: "3",
|
rows: "3",
|
||||||
value: "{summary}",
|
value: "{summary}",
|
||||||
@ -842,7 +842,7 @@ fn CoverUploader(cover_image: Signal<String>, cover_uploading: Signal<bool>) ->
|
|||||||
|
|
||||||
// 封面上传失败提示:复用页面红色条风格。
|
// 封面上传失败提示:复用页面红色条风格。
|
||||||
if let Some(err) = cover_error() {
|
if let Some(err) = cover_error() {
|
||||||
div { class: "flex items-center justify-between gap-3 px-4 py-2 bg-red-50 dark:bg-red-900/20 text-red-600 dark:text-red-400 rounded-xl text-sm border border-red-100 dark:border-red-900/30 mt-2",
|
div { class: "flex items-center justify-between gap-3 px-4 py-2 bg-red-50 dark:bg-red-900/20 text-red-600 dark:text-red-400 rounded-2xl text-sm border border-red-100 dark:border-red-900/30 mt-2",
|
||||||
span { "封面图: {err}" }
|
span { "封面图: {err}" }
|
||||||
button {
|
button {
|
||||||
class: "{BTN_CLOSE_ICON}",
|
class: "{BTN_CLOSE_ICON}",
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user