Files
HomeDash/web/navi.css
HomeDash Bot a8ce6ad759 feat(theme): 导航页恢复自动深浅色(跟随系统),保留隐藏原生设置入口
用户反馈:现在没有自动深/浅色。实测原因有两层:
1. Dashy 原生的日/夜切换按钮在设置面板里,而该面板按要求被隐藏;
2. navi.css 没有任何 prefers-color-scheme 分支,且多处写死亮色。

本提交按"我们自己接管"实现(不去赌 Dashy 压缩后的主题存储键):
- navi.js:默认跟 prefers-color-scheme;手动切换过以 localStorage.navi-theme 为准;
  系统偏好变化实时跟随;给 <html> 设 data-theme 与 .navi-dark,并设 color-scheme。
  Dashy 挂载后可能覆写 data-theme,用短暂定时对齐 + 属性观察器收口
  (仅在"与期望不一致"时回写,避免自激循环)。
- navi.css:深色下覆盖页面底色与文字,以及我们自己注入的悬浮控件
  (搜索条/收边控件/页脚/工作空间工具条与弹窗/迷你视图标签条)。
  选择器带 body 以压过主题注入的 customCss。

需要人工目视确认观感(深色下的玻璃层次只能靠眼睛调)。
2026-09-11 23:18:54 +08:00

1397 lines
45 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* HomeDash responsive presentation layer.
Loaded after Dashy's bundled styles; persistent wallpaper rules stay in conf.yml. */
html {
-webkit-text-size-adjust: 100%;
text-size-adjust: 100%;
}
/* 禁用移动端/Chromium 对可点击元素注入的蓝色点击闪烁。 */
html[data-theme] *,
html[data-theme] *::before,
html[data-theme] *::after {
-webkit-tap-highlight-color: transparent !important;
}
html[data-theme] body {
/* border-box 让 padding 计入 min-height:否则 min-height:100vh 与
padding-bottom 相加,短页面(极简/工作空间)必然多出一屏滚动。 */
box-sizing: border-box !important;
min-width: 0;
overflow-x: hidden;
/* 列向 flex + 页脚 margin-top:auto,把备案号顶到页面底部而非浮在中间。 */
display: flex !important;
flex-direction: column !important;
min-height: 100vh !important;
/* 备案号占据真正的页面最底部;悬浮控件在它上方,不再用底部 padding
把页脚整体抬高。 */
padding-bottom: 0 !important;
}
html[data-theme] #app {
width: 100% !important;
}
/* Dashy 的 #dashy 默认 min-height:100vh,短页面叠加页脚后必出滚动;
交回内容自然撑高,视口高度由 body 兜住。 */
html[data-theme] #dashy {
min-height: auto !important;
}
/* Dashy's native filter/settings strip duplicates the portal search and breaks on phones.
原生设置入口(齿轮/铅笔/调色板)与我们的 /admin/ 重复,统一隐藏。 */
html[data-theme] .home > .settings-outer,
html[data-theme] .config-launcher,
html[data-theme] .options-trigger,
html[data-theme] .settings-outer,
html[data-theme] .minimal-home .title-and-search > form {
display: none !important;
}
html[data-theme] body:has(.modal-overlay) > .navi-search-bar,
html[data-theme] body:has(.modal-overlay) > .navi-footer-host {
visibility: hidden !important;
pointer-events: none !important;
}
/* Keep configuration dialogs above section tabs and cards without changing dialog layout. */
html[data-theme] .modal-overlay {
z-index: 10000 !important;
}
html[data-theme] dialog.dashy-modal {
z-index: 10001 !important;
}
/* Stable icon geometry: raster/SVG and font icons occupy the same visual box. */
html[data-theme] a.item .item-icon {
flex: 0 0 56px !important;
width: 56px !important;
min-width: 56px !important;
height: 56px !important;
min-height: 56px !important;
display: inline-flex !important;
align-items: center !important;
justify-content: center !important;
overflow: hidden !important;
transform: none !important;
}
html[data-theme] a.item .item-icon .tile-icon,
html[data-theme] a.item .item-icon img,
html[data-theme] a.item .item-icon object {
box-sizing: border-box !important;
width: 48px !important;
min-width: 48px !important;
max-width: 48px !important;
height: 48px !important;
min-height: 48px !important;
max-height: 48px !important;
padding: 2px !important;
object-fit: contain !important;
object-position: center !important;
transform: none !important;
}
html[data-theme] a.item .item-icon i,
html[data-theme] a.item .item-icon svg:not(.tile-icon) {
width: 32px !important;
height: 32px !important;
font-size: 30px !important;
line-height: 32px !important;
}
html[data-theme] a.item .tile-title {
min-width: 0 !important;
overflow: hidden;
}
html[data-theme] a.item .tile-title .text,
html[data-theme] a.item .description,
html[data-theme] a.item .item-url {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
/* ── 渲染开销:把 backdrop-filter 从「重复的卡片层」撤掉 ──
实测首页 37 个元素带模糊(24 张卡片 + 6 个分组容器 + 顶栏 + 悬浮件)。
模糊要对背景逐帧重新采样,而卡片又参与逐张淡入/悬停位移,
两者叠加就是肉眼可见的卡顿。这里保留分组容器的玻璃感与悬浮件,
卡片只留半透明底 + 边框 + 投影(视觉差异很小,开销差很多)。 */
html[data-theme] body a.item,
html[data-theme] body .minimal-section-inner,
html[data-theme] body div.item-wrapper {
backdrop-filter: none !important;
-webkit-backdrop-filter: none !important;
}
/* 搜索栏是最常动的元素(宽/圆角/内边距都在变),它的模糊每帧都要重算 */
html[data-theme] body .navi-search-bar {
backdrop-filter: none !important;
-webkit-backdrop-filter: none !important;
}
/* ── 底部搜索:左下角放大镜悬浮球 ──
收起态只显示一个放大镜图标;点它展开成输入框;
展开后输入框内左侧仍是同一个放大镜按钮,点它收起。 */
html[data-theme] .navi-search-bar {
box-sizing: border-box !important;
position: fixed !important;
left: calc(16px + env(safe-area-inset-left, 0px)) !important;
bottom: calc(76px + env(safe-area-inset-bottom, 0px)) !important;
margin: 0 !important;
display: flex !important;
align-items: center !important;
gap: 8px !important;
z-index: 900 !important;
color: #475569 !important;
background: rgba(255, 255, 255, .72) !important;
border: 1px solid rgba(255, 255, 255, .9) !important;
box-shadow: 0 14px 38px rgba(15, 23, 42, .16), inset 0 1px 0 rgba(255, 255, 255, .95) !important;
backdrop-filter: blur(22px) saturate(180%) !important;
-webkit-backdrop-filter: blur(22px) saturate(180%) !important;
overflow: hidden !important;
}
html[data-theme] .navi-search-bar[data-state="collapsed"] {
width: 56px !important;
height: 56px !important;
padding: 0 !important;
border-radius: 50% !important;
}
html[data-theme] .navi-search-bar[data-state="open"] {
/* 必须给右下按钮组留位:按钮组 right:16px、宽 52+10+52=114px,
其左边缘在 innerW-130;搜索栏 left:16 → 上限 innerW-130-12-16 = 100%-158px。
否则展开后发送按钮会压在视图切换/管理入口上(窄屏尤其明显)。 */
width: min(560px, calc(100% - 158px)) !important;
min-height: 58px !important;
padding: 7px 8px !important;
border-radius: 20px !important;
}
html[data-theme] .navi-search-bar[data-state="collapsed"] input,
html[data-theme] .navi-search-bar[data-state="collapsed"] .navi-search-submit {
display: none !important;
}
html[data-theme] .navi-search-toggle {
flex: 0 0 42px !important;
width: 42px !important;
height: 42px !important;
display: grid !important;
place-items: center !important;
padding: 0 !important;
color: #0f172a !important;
background: transparent !important;
border: 0 !important;
border-radius: 50% !important;
cursor: pointer;
appearance: none !important;
-webkit-appearance: none !important;
-webkit-tap-highlight-color: transparent;
transition: transform .28s cubic-bezier(.22, 1, .36, 1) !important;
}
/* 点击与聚焦都不变蓝,只保留轻微缩放反馈。 */
html[data-theme] .navi-search-toggle:hover,
html[data-theme] .navi-search-toggle:focus,
html[data-theme] .navi-search-toggle:active {
color: #0f172a !important;
background: transparent !important;
outline: none !important;
}
@media (hover: hover) {
html[data-theme] .navi-search-toggle:hover {
transform: scale(1.05);
}
}
html[data-theme] .navi-search-toggle:active {
transform: scale(.96);
}
/* ── 右下角按钮组(视图切换 + 管理入口)────
两者放进同一个 fixed 容器,便于在工作空间作为一组收边,
避免各自位移后互相重叠。 */
html[data-theme] .navi-dock {
transition: opacity .2s ease, transform .2s cubic-bezier(.22, 1, .36, 1),
visibility 0s linear 0s !important;
position: fixed !important;
right: calc(16px + env(safe-area-inset-right, 0px)) !important;
bottom: calc(76px + env(safe-area-inset-bottom, 0px)) !important;
display: flex !important;
align-items: center !important;
gap: 10px !important;
z-index: 900 !important;
}
html[data-theme] .navi-dock > .navi-admin-entry {
position: static !important;
left: auto !important;
right: auto !important;
top: auto !important;
bottom: auto !important;
}
html[data-theme] .navi-dock > .navi-view-switch {
position: relative !important;
left: auto !important;
right: auto !important;
top: auto !important;
bottom: auto !important;
}
/* 右侧管理入口:Dashy 页面本身没有去 /admin/ 的链接 */
html[data-theme] .navi-admin-entry {
box-sizing: border-box !important;
width: 52px !important;
height: 52px !important;
display: grid !important;
place-items: center !important;
z-index: 900 !important;
color: #334155 !important;
background: rgba(255, 255, 255, .72) !important;
border: 1px solid rgba(255, 255, 255, .9) !important;
border-radius: 50% !important;
box-shadow: 0 14px 38px rgba(15, 23, 42, .16), inset 0 1px 0 rgba(255, 255, 255, .95) !important;
backdrop-filter: blur(22px) saturate(180%) !important;
-webkit-backdrop-filter: blur(22px) saturate(180%) !important;
-webkit-tap-highlight-color: transparent !important;
transition: transform .22s cubic-bezier(.22, 1, .36, 1), background .2s ease !important;
}
html[data-theme] .navi-admin-entry:hover,
html[data-theme] .navi-admin-entry:focus,
html[data-theme] .navi-admin-entry:active {
color: #334155 !important;
background: rgba(255, 255, 255, .94) !important;
outline: none !important;
}
@media (hover: hover) {
html[data-theme] .navi-admin-entry:hover {
transform: translateY(-1px) scale(1.05);
}
}
html[data-theme] .navi-admin-entry:active {
transform: scale(.96);
}
html[data-theme] .navi-admin-entry svg {
width: 22px !important;
height: 22px !important;
}
html[data-theme] body:has(.modal-overlay) > .navi-dock,
html[data-theme] body:has(.modal-overlay) .navi-admin-entry {
visibility: hidden !important;
pointer-events: none !important;
}
/* ── 视图切换:圆形悬浮按钮,紧贴管理入口左侧 ──
原生 .switch-view-buttons 是侧栏底部的方形图标,这里一并隐藏。 */
html[data-theme] nav.side-bar .switch-view-buttons {
display: none !important;
}
html[data-theme] .navi-view-switch {
display: block !important;
}
html[data-theme] .navi-view-toggle {
box-sizing: border-box !important;
width: 52px !important;
height: 52px !important;
display: grid !important;
place-items: center !important;
padding: 0 !important;
color: #334155 !important;
background: rgba(255, 255, 255, .72) !important;
border: 1px solid rgba(255, 255, 255, .9) !important;
border-radius: 50% !important;
box-shadow: 0 14px 38px rgba(15, 23, 42, .16), inset 0 1px 0 rgba(255, 255, 255, .95) !important;
backdrop-filter: blur(22px) saturate(180%) !important;
-webkit-backdrop-filter: blur(22px) saturate(180%) !important;
-webkit-tap-highlight-color: transparent !important;
appearance: none !important;
-webkit-appearance: none !important;
outline: none !important;
cursor: pointer;
transition: transform .22s cubic-bezier(.22, 1, .36, 1), background .2s ease !important;
}
html[data-theme] .navi-view-toggle:hover,
html[data-theme] .navi-view-toggle:focus,
html[data-theme] .navi-view-toggle:active {
color: #334155 !important;
background: rgba(255, 255, 255, .94) !important;
}
@media (hover: hover) {
html[data-theme] .navi-view-toggle:hover {
transform: translateY(-1px) scale(1.05);
}
}
html[data-theme] .navi-view-toggle:active {
transform: scale(.96);
}
html[data-theme] .navi-view-toggle svg {
width: 22px !important;
height: 22px !important;
}
html[data-theme] .navi-view-menu {
position: absolute !important;
right: 0 !important;
bottom: 62px !important;
min-width: 134px !important;
display: flex !important;
flex-direction: column !important;
gap: 2px !important;
padding: 7px !important;
background: rgba(255, 255, 255, .92) !important;
border: 1px solid rgba(255, 255, 255, .95) !important;
border-radius: 16px !important;
box-shadow: 0 18px 40px rgba(15, 23, 42, .18), inset 0 1px 0 rgba(255, 255, 255, .95) !important;
backdrop-filter: blur(20px) saturate(180%) !important;
-webkit-backdrop-filter: blur(20px) saturate(180%) !important;
animation: navi-fade-up .22s cubic-bezier(.22, 1, .36, 1) both;
}
html[data-theme] .navi-view-menu[hidden] {
display: none !important;
}
html[data-theme] .navi-view-option {
padding: 9px 12px !important;
color: #334155 !important;
font-size: 13.5px !important;
text-decoration: none !important;
border-radius: 10px !important;
white-space: nowrap !important;
-webkit-tap-highlight-color: transparent !important;
}
html[data-theme] .navi-view-option:hover,
html[data-theme] .navi-view-option:focus,
html[data-theme] .navi-view-option:active {
color: #0f172a !important;
background: rgba(226, 232, 240, .7) !important;
outline: none !important;
}
html[data-theme] .navi-view-option.is-active {
color: #0f172a !important;
background: rgba(186, 230, 253, .55) !important;
font-weight: 600 !important;
}
html[data-theme] body:has(.modal-overlay) .navi-view-switch {
visibility: hidden !important;
pointer-events: none !important;
}
html[data-theme] .navi-search-bar input {
min-width: 0 !important;
height: 42px !important;
flex: 1 1 auto !important;
padding: 0 4px !important;
color: #0f172a !important;
background: transparent !important;
border: 0 !important;
outline: 0 !important;
box-shadow: none !important;
font: inherit !important;
font-size: 16px !important;
}
html[data-theme] .navi-search-bar input::placeholder {
color: #64748b !important;
opacity: 1;
}
html[data-theme] .navi-search-submit {
flex: 0 0 44px !important;
width: 44px !important;
height: 44px !important;
display: grid !important;
place-items: center !important;
padding: 0 !important;
color: #fff !important;
background: linear-gradient(135deg, #0ea5e9, #2563eb) !important;
border: 0 !important;
border-radius: 14px !important;
box-shadow: 0 8px 20px rgba(37, 99, 235, .28) !important;
cursor: pointer;
-webkit-tap-highlight-color: transparent !important;
outline: none !important;
}
html[data-theme] .navi-search-toggle svg,
html[data-theme] .navi-search-submit svg {
width: 20px;
height: 20px;
}
/* 放大镜与搜索框同步形变:圆环、手柄退场,向左收起箭头进入。 */
html[data-theme] .navi-search-toggle svg {
overflow: visible;
}
html[data-theme] .navi-magnifier-ring,
html[data-theme] .navi-magnifier-handle,
html[data-theme] .navi-collapse-arrow {
transform-box: fill-box;
transform-origin: center;
transition: opacity .22s ease, transform .28s cubic-bezier(.22, 1, .36, 1) !important;
}
html[data-theme] .navi-collapse-arrow {
opacity: 0;
transform: translateX(5px) scale(.62);
}
html[data-theme] .navi-search-bar[data-state="open"] .navi-magnifier-ring {
opacity: 0;
transform: translateX(-4px) scale(.28);
}
html[data-theme] .navi-search-bar[data-state="open"] .navi-magnifier-handle {
opacity: 0;
transform: translate(-4px, -4px) rotate(-35deg) scale(.45);
}
html[data-theme] .navi-search-bar[data-state="open"] .navi-collapse-arrow {
opacity: 1;
transform: translateX(0) scale(1);
}
/* Minimal view is the phone/tablet layout used by Dashy. */
html[data-theme] .minimal-home {
box-sizing: border-box !important;
width: min(100% - 24px, 920px) !important;
max-width: 920px !important;
min-height: auto !important;
margin: 0 auto !important;
padding: 28px 0 16px !important;
background: transparent !important;
}
html[data-theme] .minimal-home .title-and-search {
padding: 0 8px !important;
}
/* ── 顶部标题:三个视图统一(同字号/字重/字距/居中)──
此前 /minimal 是 48px 居中,而 / 与 /workspace 是顶栏里 40px 左对齐,
同一个站点的三个视图两套标题样式,很割裂。 */
html[data-theme] #dashy > header {
display: flex !important;
align-items: center !important;
justify-content: center !important;
padding: 10px 12px !important;
}
html[data-theme] #dashy > header .page-titles {
display: block !important;
width: auto !important;
max-width: 100% !important;
margin: 0 auto !important;
text-align: center !important;
}
html[data-theme] #dashy > header .page-titles .text {
display: block !important;
text-align: center !important;
}
html[data-theme] #dashy > header .page-titles .subtitle {
display: block !important;
margin: 6px 0 0 !important;
color: #64748b !important;
font-size: 13.5px !important;
font-weight: 400 !important;
letter-spacing: 0 !important;
text-align: center !important;
}
html[data-theme] #dashy > header .page-titles h1,
html[data-theme] .minimal-home .title-and-search h1 {
max-width: 100%;
margin: 0 !important;
color: #0f172a !important;
font-size: clamp(1.75rem, 4vw, 2.75rem) !important;
font-weight: 700 !important;
line-height: 1.08 !important;
letter-spacing: -.035em !important;
text-align: center !important;
overflow-wrap: anywhere;
}
html[data-theme] .minimal-home > .item-group-container {
box-sizing: border-box !important;
width: 100% !important;
margin: 32px auto 0 !important;
padding: 0 6px !important;
}
html[data-theme] .minimal-headings-wrap {
position: relative;
z-index: 2;
gap: 6px !important;
margin-bottom: 8px !important;
}
html[data-theme] .minimal-headings-row {
gap: 6px !important;
scroll-snap-type: x proximity;
}
/* 滚动行两端用 mask 渐变淡出:此前卡片在滚动行边缘(紧贴两侧 ‹ › 按钮)
被硬切,看起来像"被按钮截断"。用 :has() 关联翻页按钮的 disabled 状态,
已经在尽头的一侧就不淡出,避免"尽头还在渐隐"的错觉。 */
html[data-theme] .minimal-headings-row {
-webkit-mask-image: linear-gradient(to right, transparent 0, #000 24px, #000 calc(100% - 24px), transparent 100%);
mask-image: linear-gradient(to right, transparent 0, #000 24px, #000 calc(100% - 24px), transparent 100%);
}
/* 已到最左:左侧不淡出 */
html[data-theme] .minimal-headings-wrap:has(> .tab-scroll-btn:first-child[disabled]) .minimal-headings-row {
-webkit-mask-image: linear-gradient(to right, #000 0, #000 calc(100% - 24px), transparent 100%);
mask-image: linear-gradient(to right, #000 0, #000 calc(100% - 24px), transparent 100%);
}
/* 已到最右:右侧不淡出 */
html[data-theme] .minimal-headings-wrap:has(> .tab-scroll-btn:last-child[disabled]) .minimal-headings-row {
-webkit-mask-image: linear-gradient(to right, transparent 0, #000 24px, #000 100%);
mask-image: linear-gradient(to right, transparent 0, #000 24px, #000 100%);
}
/* 两端都到尽头:完全不淡出 */
html[data-theme] .minimal-headings-wrap:has(> .tab-scroll-btn:first-child[disabled]):has(> .tab-scroll-btn:last-child[disabled]) .minimal-headings-row {
-webkit-mask-image: none;
mask-image: none;
}
html[data-theme] .minimal-headings-row .headings {
flex-basis: 132px !important;
min-height: 44px !important;
padding: 8px 12px !important;
border-radius: 14px !important;
scroll-snap-align: start;
}
html[data-theme] .minimal-headings-row .headings .section-title {
font-size: 15px !important;
line-height: 1.2 !important;
}
html[data-theme] .minimal-headings-wrap .tab-scroll-btn {
min-width: 34px !important;
padding: 0 8px !important;
border-radius: 12px !important;
}
html[data-theme] .minimal-section-inner {
padding: 8px !important;
background: rgba(255, 255, 255, .34) !important;
border: 1px solid rgba(255, 255, 255, .72) !important;
border-radius: 20px !important;
box-shadow: 0 16px 38px rgba(15, 23, 42, .10), inset 0 1px 0 rgba(255, 255, 255, .88) !important;
backdrop-filter: blur(20px) saturate(170%) !important;
-webkit-backdrop-filter: blur(20px) saturate(170%) !important;
}
/* 空分组(非选中分组 / 无条目)不能被渲染成空玻璃条。
Dashy 会把其余分组渲染成 16px 的空 .minimal-section-inner,
一旦给它加了边框和底色就会变成一排“莫名其妙的框”。 */
html[data-theme] .minimal-section-inner:not(:has(a.item)),
html[data-theme] .minimal-section-inner:empty {
display: none !important;
}
html[data-theme] .minimal-widget-wrap:empty {
display: none !important;
}
html[data-theme] .minimal-section-inner .section-items {
gap: 10px !important;
}
html[data-theme] .minimal-section-inner a.item {
box-sizing: border-box !important;
min-height: 82px !important;
margin: 0 !important;
padding: 12px 16px !important;
}
@media (max-width: 599px) {
html[data-theme] .minimal-home {
width: min(100% - 16px, 430px) !important;
padding-top: 22px !important;
}
html[data-theme] #dashy > header .page-titles h1,
html[data-theme] .minimal-home .title-and-search h1 {
font-size: clamp(1.6rem, 8vw, 2.2rem) !important;
}
html[data-theme] .minimal-home > .item-group-container {
margin-top: 26px !important;
padding: 0 !important;
}
html[data-theme] .minimal-headings-row .headings {
flex-basis: 116px !important;
padding: 8px 10px !important;
}
html[data-theme] .minimal-section-inner {
padding: 7px !important;
}
html[data-theme] .minimal-section-inner a.item {
min-height: 78px !important;
padding: 10px 12px !important;
border-radius: 16px !important;
}
html[data-theme] a.item .item-icon {
flex-basis: 52px !important;
width: 52px !important;
min-width: 52px !important;
height: 52px !important;
min-height: 52px !important;
}
html[data-theme] a.item .item-icon .tile-icon,
html[data-theme] a.item .item-icon img,
html[data-theme] a.item .item-icon object {
width: 44px !important;
min-width: 44px !important;
max-width: 44px !important;
height: 44px !important;
min-height: 44px !important;
max-height: 44px !important;
}
/* Keep the screen-level warning inside the phone viewport. */
html[data-theme] .modal-overlay .modal-body {
min-width: 0 !important;
max-width: 100vw !important;
overflow-x: hidden !important;
}
html[data-theme] .modal-overlay .config-tabs {
overflow-x: auto !important;
overscroll-behavior-x: contain;
scrollbar-width: none;
}
html[data-theme] .modal-overlay .config-tabs::-webkit-scrollbar {
display: none;
}
html[data-theme] .modal-overlay .config-tabs > * {
flex: 0 0 auto !important;
}
html[data-theme] .modal-overlay .config-buttons,
html[data-theme] .modal-overlay .config-buttons > * {
min-width: 0 !important;
max-width: 100% !important;
}
html[data-theme] .modal-overlay .config-buttons > p,
html[data-theme] .modal-overlay .config-buttons .warning,
html[data-theme] .modal-overlay .config-buttons .info {
white-space: normal !important;
overflow-wrap: anywhere !important;
}
html[data-theme] .navi-search-bar {
left: calc(10px + env(safe-area-inset-left, 0px)) !important;
bottom: calc(76px + env(safe-area-inset-bottom, 0px)) !important;
}
html[data-theme] .navi-search-bar[data-state="collapsed"] {
width: 52px !important;
height: 52px !important;
}
html[data-theme] .navi-search-bar[data-state="open"] {
/* 移动端按钮组 right:10px、宽 48+8+48=104px → 左边缘 innerW-114,
搜索栏 left:10 → 上限 100%-132px */
width: calc(100% - 132px) !important;
min-height: 56px !important;
border-radius: 18px !important;
}
html[data-theme] .navi-admin-entry {
width: 48px !important;
height: 48px !important;
}
html[data-theme] .navi-dock {
right: calc(10px + env(safe-area-inset-right, 0px)) !important;
bottom: calc(76px + env(safe-area-inset-bottom, 0px)) !important;
gap: 8px !important;
}
/* 移动端基准 right:10px,露出 14px → 位移 = 自身宽度 - 4px */
html[data-theme][data-navi-view="workspace"] .navi-dock {
transform: translateX(calc(100% - 4px)) !important;
}
html[data-theme] .navi-view-toggle {
width: 48px !important;
height: 48px !important;
}
html[data-theme] .navi-view-toggle svg {
width: 20px !important;
height: 20px !important;
}
html[data-theme] body {
padding-bottom: 0 !important;
}
}
/* 极窄屏(≤380px):输入框展开时右下按钮组整组让位。
预留式收窄在 320px 下只剩 68px 可输入,不可用;搜索是聚焦动作,
此时把两个按钮藏起来(visibility 不受 prefers-reduced-motion 影响,
比 transform 更可靠),搜索栏即可用满宽度。 */
@media (max-width: 380px) {
/* 备案号在这里会换行成两行(实测 390px 高 39px、320px 高 66px),
而按钮固定在 bottom:76px → 实测两者只剩 1px。把按钮上移并收紧凑页脚,
保证仍有 ~20px 间隙。 */
html[data-theme] .navi-search-bar {
bottom: calc(88px + env(safe-area-inset-bottom, 0px)) !important;
}
html[data-theme] .navi-dock {
bottom: calc(88px + env(safe-area-inset-bottom, 0px)) !important;
}
html[data-theme] .navi-footer {
gap: 6px !important;
padding: 8px 16px !important;
}
html[data-theme] .navi-search-bar[data-state="open"] {
width: calc(100% - 40px) !important;
}
html[data-theme] .navi-search-bar[data-state="open"] ~ .navi-dock {
/* visibility 延迟到淡出结束再切,否则瞬间消失、看不到过渡 */
visibility: hidden !important;
pointer-events: none !important;
opacity: 0 !important;
transform: translateY(10px) !important;
transition: opacity .2s ease, transform .2s cubic-bezier(.22, 1, .36, 1),
visibility 0s linear .2s !important;
}
}
/* ── 页脚:备案号胶囊 ──
备案号在 /admin/ 里编辑,这里只负责呈现;同时清掉历史上塞在
内联样式里的 margin-bottom:80px(那是给旧的流式搜索栏让位的)。 */
html[data-theme] footer {
margin: 0 !important;
padding: 0 0 8px !important;
background: transparent !important;
}
html[data-theme] footer > div {
margin-bottom: 0 !important;
padding: 0 !important;
}
/* 极简/工作空间视图补的备案号页脚:留在文档流里,靠 body 的 flex
把它顶到页面底部(贴着悬浮搜索栏上方),而不是 fixed 浮在内容中间。 */
html[data-theme] .navi-footer-host {
margin-top: auto !important;
display: flex !important;
justify-content: center !important;
padding: 8px !important;
}
html[data-theme] .navi-footer {
display: flex !important;
flex-wrap: wrap !important;
align-items: center !important;
justify-content: center !important;
gap: 9px !important;
width: fit-content !important;
max-width: min(680px, calc(100% - 24px)) !important;
margin: 14px auto 0 !important;
padding: 9px 18px !important;
color: #64748b !important;
font-size: 12.5px !important;
line-height: 1.4 !important;
background: rgba(255, 255, 255, .55) !important;
border: 1px solid rgba(255, 255, 255, .78) !important;
border-radius: 999px !important;
box-shadow: 0 6px 18px rgba(15, 23, 42, .06), inset 0 1px 0 rgba(255, 255, 255, .92) !important;
backdrop-filter: blur(14px) saturate(170%) !important;
-webkit-backdrop-filter: blur(14px) saturate(170%) !important;
}
html[data-theme] .navi-footer a {
color: #64748b !important;
text-decoration: none !important;
border-bottom: 1px dashed rgba(100, 116, 139, .45) !important;
-webkit-tap-highlight-color: transparent !important;
}
html[data-theme] .navi-footer a:hover,
html[data-theme] .navi-footer a:focus,
html[data-theme] .navi-footer a:active {
color: #64748b !important;
border-bottom-color: rgba(100, 116, 139, .45) !important;
outline: none !important;
}
html[data-theme] .navi-footer-sep {
color: rgba(100, 116, 139, .45) !important;
}
/* ── 工作空间:悬浮控件与备案号收起到屏幕边缘 ──
工作空间中间嵌的是别人的应用,这些常驻控件会遮挡内容。
搜索球收左边缘、右下角按钮组整组收右边缘、备案号收下边缘,
各留 14px 露出;鼠标移入或点击、聚焦时滑出展开。 */
html[data-theme][data-navi-view="workspace"] .navi-search-bar,
html[data-theme][data-navi-view="workspace"] .navi-dock,
html[data-theme][data-navi-view="workspace"] .navi-footer-host {
opacity: .55 !important;
transition: transform .26s cubic-bezier(.22, 1, .36, 1), opacity .26s ease !important;
animation: none !important;
}
/* 基础 left 为 16px、宽 56px → 位移 58px 后恰好露出 14px */
html[data-theme][data-navi-view="workspace"] .navi-search-bar {
transform: translateX(-58px) !important;
}
/* 按钮组整组右移自身宽度减 14px,恰好露出 14px */
html[data-theme][data-navi-view="workspace"] .navi-dock {
/* 基准 right:16px,露出 14px → 位移 = 自身宽度 + 16px - 14px */
transform: translateX(calc(100% + 2px)) !important;
}
html[data-theme][data-navi-view="workspace"] .navi-footer-host {
position: fixed !important;
left: 0 !important;
right: 0 !important;
bottom: 0 !important;
z-index: 880 !important;
padding: 0 !important;
transform: translateY(calc(100% - 13px)) !important;
}
/* 展开:悬停 / 聚焦 / 按下 / 搜索已展开 */
html[data-theme][data-navi-view="workspace"] .navi-search-bar:hover,
html[data-theme][data-navi-view="workspace"] .navi-search-bar:focus-within,
html[data-theme][data-navi-view="workspace"] .navi-search-bar[data-state="open"],
html[data-theme][data-navi-view="workspace"] .navi-dock:hover,
html[data-theme][data-navi-view="workspace"] .navi-dock:focus-within,
html[data-theme][data-navi-view="workspace"] .navi-footer-host:hover,
html[data-theme][data-navi-view="workspace"] .navi-footer-host:focus-within,
/* 触摸/点击展开:第一次交互只滑出,第二次才触发(见 navi.js 的 peek guard) */
html[data-navi-view="workspace"].navi-peek-open .navi-search-bar,
html[data-navi-view="workspace"].navi-peek-open .navi-dock,
html[data-navi-view="workspace"].navi-peek-open .navi-footer-host {
opacity: 1 !important;
transform: translateX(0) translateY(0) !important;
}
/* ── 工作空间:点侧栏应用 → 在中间内嵌打开网页 ──
Dashy 的面板就是 iframe,我们只是让它在文档流里正常显示、并且只在
「可内嵌」时显示;被拒绝时改为明确提示,而不是一片空白。
用正常文档流(而不是 fixed 钉在视口中间),否则会把页面切成
「顶栏 / 大方块 / 底部」三段,看起来上下都被截断。 */
html[data-theme] .work-space {
height: auto !important;
min-height: 0 !important;
}
html[data-theme] .work-space .multi-taking-view,
html[data-theme] .work-space .workspace-widget-view {
display: none !important;
}
/* iframe 面板与提示卡共用同一块位置,切换状态时布局不跳动 */
html[data-theme] .work-space .web-content,
html[data-theme] .work-space .navi-ws-notice {
box-sizing: border-box !important;
position: static !important;
display: none !important;
width: auto !important;
height: min(72vh, 720px) !important;
min-height: 300px !important;
margin: 18px 18px 14px 72px !important;
border: 1px solid rgba(255, 255, 255, .85) !important;
border-radius: 20px !important;
box-shadow: 0 18px 44px rgba(15, 23, 42, .14), inset 0 1px 0 rgba(255, 255, 255, .92) !important;
overflow: hidden !important;
z-index: 1 !important;
}
html[data-theme] .work-space .web-content {
padding: 0 !important;
background: #fff !important;
}
html[data-theme] .work-space[data-navi-ws="frame"] .web-content {
display: block !important;
margin-top: 8px !important;
}
/* 面板工具条:常驻退路(刷新 / 在新标签页打开),只在内嵌态出现 */
html[data-theme] .navi-ws-bar {
display: none !important;
}
html[data-theme] .work-space[data-navi-ws="frame"] .navi-ws-bar {
box-sizing: border-box !important;
position: static !important;
display: flex !important;
align-items: center !important;
gap: 10px !important;
min-height: 40px !important;
margin: 18px 18px 0 72px !important;
padding: 5px 6px 5px 16px !important;
background: rgba(255, 255, 255, .55) !important;
border: 1px solid rgba(255, 255, 255, .82) !important;
border-radius: 999px !important;
box-shadow: 0 10px 26px rgba(15, 23, 42, .1), inset 0 1px 0 rgba(255, 255, 255, .92) !important;
backdrop-filter: blur(16px) saturate(180%) !important;
-webkit-backdrop-filter: blur(16px) saturate(180%) !important;
}
html[data-theme] .navi-ws-bar-host {
color: #0f172a !important;
font-size: 13.5px !important;
font-weight: 600 !important;
overflow: hidden !important;
text-overflow: ellipsis !important;
white-space: nowrap !important;
}
html[data-theme] .navi-ws-bar-note {
color: #94a3b8 !important;
font-size: 12.5px !important;
overflow: hidden !important;
text-overflow: ellipsis !important;
white-space: nowrap !important;
}
html[data-theme] .navi-ws-bar-spacer {
flex: 1 1 auto !important;
}
html[data-theme] .navi-ws-bar-btn {
flex: 0 0 auto !important;
padding: 6px 13px !important;
color: #334155 !important;
font-family: inherit !important;
font-size: 12.5px !important;
background: rgba(255, 255, 255, .72) !important;
border: 1px solid rgba(255, 255, 255, .9) !important;
border-radius: 999px !important;
cursor: pointer;
-webkit-tap-highlight-color: transparent !important;
outline: none !important;
}
html[data-theme] .navi-ws-bar-btn:hover,
html[data-theme] .navi-ws-bar-btn:focus,
html[data-theme] .navi-ws-bar-btn:active {
color: #0f172a !important;
background: rgba(255, 255, 255, .95) !important;
}
html[data-theme] .work-space .web-content iframe {
/* 必须是 static:Dashy 默认 absolute,包含块是 #dashy 而不是 .web-content,
于是 .web-content 的 overflow:hidden 拦不住它,iframe 会按 #dashy 的高度
撑高整页(实测多出 77px 纵向滚动)。 */
position: static !important;
display: block !important;
width: 100% !important;
height: 100% !important;
border: 0 !important;
background: #fff !important;
}
html[data-theme] .work-space[data-navi-ws="hint"] .navi-ws-notice,
html[data-theme] .work-space[data-navi-ws="loading"] .navi-ws-notice,
html[data-theme] .work-space[data-navi-ws="blocked"] .navi-ws-notice {
display: flex !important;
flex-direction: column !important;
align-items: center !important;
justify-content: center !important;
gap: 10px !important;
padding: 24px !important;
text-align: center !important;
background: rgba(255, 255, 255, .55) !important;
backdrop-filter: blur(18px) saturate(180%) !important;
-webkit-backdrop-filter: blur(18px) saturate(180%) !important;
}
html[data-theme] .navi-ws-notice-title {
color: #0f172a !important;
font-size: 16px !important;
font-weight: 650 !important;
}
html[data-theme] .navi-ws-notice-text {
color: #64748b !important;
font-size: 13.5px !important;
}
html[data-theme] .navi-ws-notice-url {
max-width: 80% !important;
color: #94a3b8 !important;
font-size: 12.5px !important;
word-break: break-all !important;
}
/* ── 「不支持在工作区显示」弹层 ──
被拒内嵌时不能只是面板里一行字:用户点了必须有明确反馈。
z-index 低于 Dashy 自己的配置弹层(10000),避免挡住它。 */
html[data-theme] .navi-ws-modal {
position: fixed !important;
inset: 0 !important;
z-index: 9990 !important;
display: flex !important;
align-items: center !important;
justify-content: center !important;
padding: 18px !important;
background: rgba(15, 23, 42, .28) !important;
backdrop-filter: blur(4px) !important;
-webkit-backdrop-filter: blur(4px) !important;
animation: navi-fade-in .18s ease both;
}
html[data-theme] .navi-ws-modal.closing {
opacity: 0 !important;
transition: opacity .16s ease !important;
}
html[data-theme] .navi-ws-modal.closing .navi-ws-modal-card {
transform: translateY(8px) scale(.98) !important;
transition: transform .16s ease !important;
}
html[data-theme] .navi-ws-modal-card {
box-sizing: border-box !important;
width: min(420px, 100%) !important;
display: flex !important;
flex-direction: column !important;
align-items: center !important;
gap: 8px !important;
padding: 24px 22px 20px !important;
text-align: center !important;
background: rgba(255, 255, 255, .96) !important;
border: 1px solid rgba(255, 255, 255, .9) !important;
border-radius: 20px !important;
box-shadow: 0 26px 60px rgba(15, 23, 42, .28), inset 0 1px 0 rgba(255, 255, 255, .95) !important;
animation: navi-fade-up .22s cubic-bezier(.22, 1, .36, 1) both;
}
html[data-theme] .navi-ws-modal-title {
color: #0f172a !important;
font-size: 17px !important;
font-weight: 650 !important;
}
html[data-theme] .navi-ws-modal-host {
color: #0284c7 !important;
font-size: 13px !important;
word-break: break-all !important;
}
html[data-theme] .navi-ws-modal-text {
color: #64748b !important;
font-size: 13.5px !important;
line-height: 1.5 !important;
}
html[data-theme] .navi-ws-modal-actions {
display: flex !important;
flex-wrap: wrap !important;
gap: 10px !important;
justify-content: center !important;
margin-top: 10px !important;
}
html[data-theme] .navi-ws-modal-ok {
padding: 9px 18px !important;
color: #334155 !important;
font-family: inherit !important;
font-size: 13.5px !important;
background: rgba(241, 245, 249, .95) !important;
border: 1px solid rgba(203, 213, 225, .9) !important;
border-radius: 999px !important;
cursor: pointer;
-webkit-tap-highlight-color: transparent !important;
outline: none !important;
}
html[data-theme] .navi-ws-modal-ok:hover,
html[data-theme] .navi-ws-modal-ok:focus {
color: #0f172a !important;
background: rgba(255, 255, 255, .98) !important;
}
html[data-theme] .navi-ws-open {
margin-top: 6px !important;
padding: 9px 18px !important;
color: #fff !important;
font-family: inherit !important;
font-size: 13.5px !important;
background: linear-gradient(135deg, #0ea5e9, #2563eb) !important;
border: 0 !important;
border-radius: 999px !important;
box-shadow: 0 10px 24px rgba(37, 99, 235, .28) !important;
-webkit-tap-highlight-color: transparent !important;
outline: none !important;
cursor: pointer;
}
/* ── 工作空间:侧栏与内容区同样走玻璃圆角 ── */
html[data-theme] nav.side-bar {
background: rgba(255, 255, 255, .62) !important;
border-right: 1px solid rgba(255, 255, 255, .6) !important;
backdrop-filter: blur(18px) saturate(180%) !important;
-webkit-backdrop-filter: blur(18px) saturate(180%) !important;
}
html[data-theme] nav.side-bar .side-bar-section {
padding: 2px !important;
}
html[data-theme] nav.side-bar .side-bar-item {
border-radius: 12px !important;
transition: background .2s ease !important;
}
html[data-theme] nav.side-bar .side-bar-item:hover {
background: rgba(255, 255, 255, .92) !important;
}
/* ── 动效 ──
只动 transform / opacity,不触发布局;时长 180–380ms,
缓动统一 cubic-bezier(.22,1,.36,1)(快速起步、平稳收尾)。 */
@keyframes navi-fade-in {
from { opacity: 0; }
to { opacity: 1; }
}
@keyframes navi-fade-up {
from { opacity: 0; transform: translateY(10px); }
to { opacity: 1; transform: translateY(0); }
}
@keyframes navi-bar-in {
from { opacity: 0; transform: translateY(16px); }
to { opacity: 1; transform: translateY(0); }
}
html[data-theme] html,
html[data-theme] body {
scroll-behavior: smooth;
}
/* 视图切换:主内容与选中分组淡入 */
html[data-theme] #dashy > *,
html[data-theme] .minimal-section-inner.selected,
html[data-theme] .work-space {
animation: navi-fade-in .3s cubic-bezier(.22, 1, .36, 1) both;
}
/* 悬浮搜索栏:从下侧滑入 */
html[data-theme] .navi-search-bar {
animation: navi-bar-in .36s cubic-bezier(.22, 1, .36, 1) both;
transition: box-shadow .24s ease, border-color .24s ease, background .24s ease,
width .28s cubic-bezier(.22, 1, .36, 1), border-radius .28s ease !important;
}
html[data-theme] .navi-admin-entry {
animation: navi-fade-in .42s ease both;
}
html[data-theme] .navi-search-submit {
transition: transform .2s cubic-bezier(.22, 1, .36, 1), box-shadow .2s ease, filter .2s ease !important;
}
html[data-theme] .navi-search-submit:hover {
filter: brightness(1.06);
transform: translateY(-1px) scale(1.04);
box-shadow: 0 12px 26px rgba(37, 99, 235, .34) !important;
}
html[data-theme] .navi-search-submit:focus,
html[data-theme] .navi-search-submit:active {
outline: none !important;
}
html[data-theme] .navi-search-submit:active {
transform: translateY(0) scale(.96);
}
html[data-theme] .navi-footer-host {
animation: navi-fade-in .42s ease both;
}
/* 卡片逐个淡入:只作用在内容层,避免和 masonry 布局的位移冲突 */
html[data-theme] div.collapsible-content .item-wrapper,
html[data-theme] .minimal-section-inner .item-wrapper {
animation: navi-fade-up .34s cubic-bezier(.22, 1, .36, 1) both;
}
html[data-theme] .item-wrapper:nth-child(1) { animation-delay: 0ms; }
html[data-theme] .item-wrapper:nth-child(2) { animation-delay: 30ms; }
html[data-theme] .item-wrapper:nth-child(3) { animation-delay: 60ms; }
html[data-theme] .item-wrapper:nth-child(4) { animation-delay: 90ms; }
html[data-theme] .item-wrapper:nth-child(5) { animation-delay: 120ms; }
html[data-theme] .item-wrapper:nth-child(6) { animation-delay: 150ms; }
html[data-theme] .item-wrapper:nth-child(n+7) { animation-delay: 180ms; }
/* 分组容器:悬停轻微上浮 */
html[data-theme] div.collapsable {
transition: box-shadow .26s ease, border-color .26s ease, transform .26s cubic-bezier(.22, 1, .36, 1) !important;
}
html[data-theme] div.collapsable:hover {
transform: translateY(-2px);
border-color: rgba(147, 197, 253, .6) !important;
box-shadow: 0 18px 40px rgba(15, 23, 42, .12), inset 0 1px 0 rgba(255, 255, 255, .9) !important;
}
html[data-theme] div.collapsable h2,
html[data-theme] .minimal-headings-row .headings {
transition: background .22s ease, color .22s ease, transform .22s cubic-bezier(.22, 1, .36, 1), border-color .22s ease !important;
}
html[data-theme] .minimal-headings-row .headings:hover {
transform: translateY(-1px);
border-color: rgba(147, 197, 253, .75) !important;
}
html[data-theme] .minimal-headings-row .headings:active {
transform: scale(.975);
}
html[data-theme] .minimal-headings-wrap .tab-scroll-btn {
transition: background .2s ease, color .2s ease, transform .2s cubic-bezier(.22, 1, .36, 1) !important;
}
html[data-theme] .minimal-headings-wrap .tab-scroll-btn:hover:not([disabled]) {
transform: scale(1.06);
}
html[data-theme] a.item:active {
transform: translateY(-1px) scale(.99) !important;
}
html[data-theme] a.item .item-icon img,
html[data-theme] a.item .item-icon svg {
transition: transform .26s cubic-bezier(.22, 1, .36, 1) !important;
}
html[data-theme] nav.side-bar .side-bar-item {
transition: background .2s ease, transform .2s cubic-bezier(.22, 1, .36, 1) !important;
}
html[data-theme] nav.side-bar .side-bar-item:hover {
transform: scale(1.06);
}
html[data-theme] .navi-footer a {
transition: color .2s ease, border-color .2s ease !important;
}
@media (prefers-reduced-motion: reduce) {
html[data-theme] html,
html[data-theme] body {
scroll-behavior: auto !important;
}
html[data-theme] #dashy > *,
html[data-theme] .minimal-section-inner.selected,
html[data-theme] .work-space,
html[data-theme] .navi-search-bar,
html[data-theme] .navi-admin-entry,
html[data-theme] .navi-footer-host,
html[data-theme] div.collapsible-content .item-wrapper,
html[data-theme] .minimal-section-inner .item-wrapper {
animation: none !important;
opacity: 1 !important;
transform: none !important;
}
html[data-theme] a.item,
html[data-theme] a.item .tile-icon {
transition: none !important;
}
html[data-theme] a.item:hover,
html[data-theme] div.collapsable:hover,
html[data-theme] nav.side-bar .side-bar-item:hover,
html[data-theme] .minimal-headings-row .headings:hover {
transform: none !important;
}
}
/* ── 深色模式 ──
触发条件:<html data-theme="dark">(由 navi.js 按系统偏好设置)。
这里只覆盖两类东西:① 页面底色/文字;② 我们自己注入的悬浮控件
(原生 Dashy 卡片的观感由主题提供,不在这里重复定义)。
选择器都带 body 以压过主题注入的 customCss(同优先级时后者更具体)。 */
html[data-theme="dark"] body {
background-color: #0b1120 !important;
color: #e8eefc !important;
}
html[data-theme="dark"] body .navi-search-bar,
html[data-theme="dark"] body .navi-dock,
html[data-theme="dark"] body .navi-footer-host,
html[data-theme="dark"] body .navi-ws-toolbar,
html[data-theme="dark"] body .navi-ws-modal {
background: rgba(17, 25, 40, 0.78) !important;
border-color: rgba(148, 163, 184, 0.22) !important;
color: #e8eefc !important;
box-shadow: 0 8px 28px rgba(0, 0, 0, 0.45) !important;
}
html[data-theme="dark"] body .navi-search-bar input,
html[data-theme="dark"] body .navi-search-bar .navi-search-input {
background: rgba(15, 23, 42, 0.6) !important;
color: #e8eefc !important;
border-color: rgba(148, 163, 184, 0.25) !important;
}
html[data-theme="dark"] body .navi-search-bar input::placeholder { color: #94a3b8 !important; }
html[data-theme="dark"] body .navi-footer,
html[data-theme="dark"] body .navi-footer a,
html[data-theme="dark"] body .navi-footer .navi-footer-sep { color: #94a3b8 !important; }
html[data-theme="dark"] body .navi-footer a:hover { color: #60a5fa !important; }
html[data-theme="dark"] body .navi-dock button,
html[data-theme="dark"] body .navi-dock a {
background: rgba(30, 41, 59, 0.72) !important;
color: #cbd5e1 !important;
border-color: rgba(148, 163, 184, 0.22) !important;
}
html[data-theme="dark"] body .navi-dock button:hover,
html[data-theme="dark"] body .navi-dock a:hover { color: #93bbfd !important; }
html[data-theme="dark"] body .minimal-section-inner,
html[data-theme="dark"] body div.item-wrapper {
background: rgba(17, 25, 40, 0.6) !important;
border-color: rgba(148, 163, 184, 0.18) !important;
}
html[data-theme="dark"] body .navi-mini-tabs { background: rgba(11, 17, 32, 0.85) !important; }