diff --git a/HANDOFF.md b/HANDOFF.md
index a772e7f..cc2b112 100644
--- a/HANDOFF.md
+++ b/HANDOFF.md
@@ -113,7 +113,6 @@ stash-ui/src/components/ SearchField / Input / EngineIcon 等
"header": { "enabled": true, "speed": 24, "gap": 26, "items": [...] },
"sidebar": { "show_profile": true, "show_service": false, "show_nav": true },
"background": { "light": "", "dark": "" }, // 空 = 内置背景
- "card": { "opacity": 100, "blur": false }, // 卡片不透明度 40–100 + 毛玻璃
"search": {
"default": "internal",
"engines": [
@@ -148,7 +147,6 @@ stash-ui/src/components/ SearchField / Input / EngineIcon 等
- 搜索框:默认搜索项、五个外部引擎的名称 / URL / 启停、恢复默认;
- 侧边栏:资料卡 / 本地服务 / 分组导航显隐;
- 内容卡片:卡片 + 勾选分组 + 预览条数 + 排序;
- - 卡片外观:前台所有卡片的不透明度(40–100)与毛玻璃开关;
- **资料管理**:头像、名称、角色、简介、位置;
- **系统管理**:改密码、下载备份。
diff --git a/README.md b/README.md
index 25a88ec..6526f5c 100644
--- a/README.md
+++ b/README.md
@@ -54,7 +54,7 @@ cargo run -- --root ./sites --host 0.0.0.0 --port 3000
- 登录后点「站点设置」进入 `/admin`,左侧导航 + 右侧内容:
- **分组管理**:树形表格,可建根 / 子分组、图标(字符或 iconfont 图标名)、排序权重、启停、删除;
- **数据管理**:选分组后列出条目(含子分组),每条可单独设格式,可新建 / 编辑 / 删除;
- - **首页管理**(子项):**页头**(站点信息 / 操作工具 / 滚动信息三个页签)、**侧边栏**(三块侧栏卡片显隐)、**内容卡片**(左侧可拖拽排序的卡片列表 + 右侧分组表格:状态、预览条数、顺序、展示)、**卡片外观**(所有卡片的不透明度 40–100 与毛玻璃开关);
+ - **首页管理**(子项):**页头**(站点信息 / 操作工具 / 滚动信息三个页签)、**侧边栏**(三块侧栏卡片显隐)、**内容卡片**(左侧可拖拽排序的卡片列表 + 右侧分组表格:状态、预览条数、顺序、展示);
- **资料管理**与**系统管理**(改密码、下载整库备份);
- 分组的「状态」是**唯一可见性来源**:停用的分组在侧栏和卡片里都不再出现,层层往下生效;
- 详情页的 `[编辑]` 只在登录后显示;保存后局部刷新,`updated_at` 乐观锁;
diff --git a/src/db/settings.rs b/src/db/settings.rs
index 9d90a33..b9b942c 100644
--- a/src/db/settings.rs
+++ b/src/db/settings.rs
@@ -13,8 +13,6 @@ pub const SETTINGS_KEY: &str = "site";
pub const MAX_HEADER_ITEMS: usize = 8;
pub const MIN_SPEED: u32 = 8;
pub const MAX_SPEED: u32 = 120;
-pub const MIN_CARD_OPACITY: u32 = 40;
-pub const MAX_CARD_OPACITY: u32 = 100;
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Default)]
#[serde(rename_all = "snake_case")]
@@ -121,25 +119,6 @@ pub struct BackgroundSettings {
pub dark: String,
}
-/// 卡片外观:透明度与毛玻璃。前台所有卡片共用一套(首页 / 分组页 / 详情页 / 侧栏)。
-#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
-#[serde(default)]
-pub struct CardSettings {
- /// 卡片底色的不透明度(百分比,40–100)
- pub opacity: u32,
- /// 毛玻璃:背景模糊 + 提饱和度
- pub blur: bool,
-}
-
-impl Default for CardSettings {
- fn default() -> Self {
- Self {
- opacity: 100,
- blur: false,
- }
- }
-}
-
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Default)]
#[serde(default)]
pub struct SearchEngineSettings {
@@ -309,7 +288,6 @@ pub struct Settings {
pub header: HeaderSettings,
pub sidebar: SidebarSettings,
pub background: BackgroundSettings,
- pub card: CardSettings,
pub search: SearchSettings,
pub profile: ProfileSettings,
pub site: SiteMetaSettings,
@@ -376,11 +354,6 @@ pub fn validate(settings: &Settings) -> Result<(), StashError> {
"暗色背景地址最多 500 个字符".into(),
));
}
- if !(MIN_CARD_OPACITY..=MAX_CARD_OPACITY).contains(&settings.card.opacity) {
- return Err(StashError::InvalidDirectory(format!(
- "卡片不透明度需在 {MIN_CARD_OPACITY}–{MAX_CARD_OPACITY} 之间"
- )));
- }
if settings.search.engines.len() > 10 {
return Err(StashError::InvalidDirectory("搜索引擎最多 10 个".into()));
}
@@ -578,14 +551,6 @@ mod tests {
let mut empty = Settings::default();
empty.header.items.clear();
assert!(save(&mut conn, empty, 0).is_err());
-
- let mut too_transparent = Settings::default();
- too_transparent.card.opacity = MIN_CARD_OPACITY - 1;
- assert!(save(&mut conn, too_transparent, 0).is_err());
-
- let mut clear = Settings::default();
- clear.card.opacity = MAX_CARD_OPACITY;
- assert!(save(&mut conn, clear, 0).is_ok());
}
#[test]
diff --git a/stash-web/src/App.css b/stash-web/src/App.css
index f0a5943..aff51bf 100644
--- a/stash-web/src/App.css
+++ b/stash-web/src/App.css
@@ -14,26 +14,6 @@
--su-card-border: var(--su-border-strong);
}
-/* 卡片外观(后台「卡片外观」可调):底色透明度 + 毛玻璃,前台所有卡片共用一套。
- 变量由 AppNext 按站点设置写到 上;没设置时就是实底、无毛玻璃。 */
-.app .section-card,
-.app .profile-card,
-.app .service-panel,
-.app .nav-card,
-.app .group-own-block,
-.app .group-child-block,
-.app .detail-nav,
-.app .item-card,
-.app .article-body-card,
-.app .related-card {
- background-color: color-mix(
- in srgb,
- var(--su-bg-card) var(--stash-card-alpha, 100%),
- transparent
- );
- backdrop-filter: var(--stash-card-blur, none);
-}
-
/* 卡片阴影默认会被滚动容器在左右边缘一刀切掉(卡片正好贴着容器边)。
负边距把容器撑宽 16px、再补同样的内边距,内容位置不变,阴影有地方画。 */
#page-scroll {
@@ -396,6 +376,16 @@
margin-top: var(--su-space-2);
}
+/* 分组页的内容直接压在背景图上(没有卡片底):靠文字自己的对比来保证可读,
+ 次级文字提一档,再加一层同主题的描边,落在图片亮部也不会糊成一片。 */
+.detail-view .group-own-block,
+.detail-view .group-child-block,
+.detail-hero {
+ --su-text-sub: var(--su-text-secondary);
+ --su-text-muted: var(--su-text-sub);
+ text-shadow: 0 1px 3px color-mix(in srgb, var(--su-bg-page) 70%, transparent);
+}
+
/* 明细页的分组标题:与首页卡片标题同一套「色条 + 标题」 */
.group-title {
display: flex;
diff --git a/stash-web/src/AppNext.tsx b/stash-web/src/AppNext.tsx
index 8e83135..b9e3d42 100644
--- a/stash-web/src/AppNext.tsx
+++ b/stash-web/src/AppNext.tsx
@@ -333,7 +333,6 @@ export default function AppNext() {
show_nav: true,
},
background: cachedBackground ?? { light: '', dark: '' },
- card: { opacity: 100, blur: false },
search: {
default: 'internal',
engines: DEFAULT_SEARCH_ENGINES.map((engine) => ({ ...engine })),
@@ -409,13 +408,6 @@ export default function AppNext() {
}
}, [scheme])
- // 卡片外观:透明度和毛玻璃写在 的 CSS 变量上,前台所有卡片共用一套
- useEffect(() => {
- const root = document.documentElement.style
- root.setProperty('--stash-card-alpha', `${site.card.opacity}%`)
- root.setProperty('--stash-card-blur', site.card.blur ? 'blur(14px) saturate(1.15)' : 'none')
- }, [site.card.opacity, site.card.blur])
-
/** 页头的明暗切换:只写本机偏好,不需要登录;站点默认值在后台改 */
const toggleTheme = () => {
const next: ThemeChoice = isDark ? 'light' : 'dark'
@@ -668,9 +660,7 @@ export default function AppNext() {
{group.entries.length > 0 ? (
-