Files
stash/stash-web/src/App.css
T
CNWei 6e17169ac4 fix(mobile): 窄屏主内容被挤出视口,侧栏与页头适配手机/平板
- ≤1100 时滚动容器不换行、aside/main 不再锁 100% 高(之前 main 被排到视口右侧,完全看不见)
- 平板:资料卡 + 导航卡两列并排;手机:只留导航卡(资料/服务卡隐藏)
- 手机页头:隐藏跑马灯,改两列(品牌 + 操作图标),高度 56
- 删掉一直没生效的 .sidebar 网格规则(被更高优先级的 flex 规则盖住)
2026-11-05 19:50:21 +08:00

1660 lines
34 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.
/* 页面级样式:只保留「组件库没有」的部分(背景、外壳、封面兜底、正文版式)。
颜色 / 间距 / 字号全部取自 @stash/ui 的令牌。 */
/* 主题级覆盖:放 :root 而不是 .app,前后台两个壳才能拿到同一套描边/阴影。
卡片保留一层很浅的投影;浅色默认 gray-1 几乎看不见,描边提一档。 */
:root {
--su-card-border: var(--su-gray-3);
--su-shadow-card: 0 6px 16px rgba(27, 26, 49, 0.02);
--su-shadow-hover: 0 6px 16px rgba(27, 26, 49, 0.06);
}
/* 深色下描边要比卡片底(#202022)亮一档,才是一条实线 */
:root[data-scheme='dark'] {
--su-card-border: var(--su-border-strong);
}
/* 卡片阴影默认会被滚动容器在左右边缘一刀切掉(卡片正好贴着容器边)。
负边距把容器撑宽 16px、再补同样的内边距,内容位置不变,阴影有地方画。 */
#page-scroll {
margin: 0 -16px;
padding: 0 16px;
}
.app {
position: relative;
z-index: 1;
/* 透明:让固定背景图从下面透出来(Layout 默认有底色) */
background-color: transparent;
}
/* 顶部背景:固定 65vh,底部渐隐到页面底色;明暗两层交叉淡入 */
.site-background {
position: fixed;
inset: 0 0 auto;
z-index: 0;
height: 65vh;
background-position: center top;
background-repeat: no-repeat;
background-size: cover;
pointer-events: none;
opacity: 1;
transition: opacity 160ms var(--su-ease-in-out);
}
.site-background-light {
background-image: url('./assets/site-bg.jpg');
}
.site-background-dark {
background-image: url('./assets/site-bg-dark.jpg');
opacity: 0;
}
.site-background::after {
content: '';
position: absolute;
right: 0;
bottom: 0;
left: 0;
height: 80%;
background: linear-gradient(to bottom, transparent, var(--su-bg-page));
}
[data-scheme='dark'] .site-background-light {
opacity: 0;
}
[data-scheme='dark'] .site-background-dark {
opacity: 1;
}
/* ---------- 页头 ---------- */
.site-header-inner {
display: grid;
grid-template-columns: minmax(0, 1fr) minmax(0, 720px) minmax(0, 1fr);
align-items: center;
gap: var(--su-space-4);
width: 100%;
max-width: var(--su-layout-width);
height: calc(var(--su-header-height) - 1px);
margin: 0 auto;
padding: 0 var(--su-space-5);
}
/* 通配符说明:两列小表 */
.ticker-vars {
display: grid;
grid-template-columns: auto minmax(0, 1fr);
gap: var(--su-space-2) var(--su-space-4);
align-items: center;
padding: var(--su-space-3);
border: 1px solid var(--su-border);
border-radius: var(--su-radius-md);
background-color: var(--su-bg-subtle);
font-size: var(--su-font-size-sm);
}
.ticker-vars code {
padding: 0 var(--su-space-2);
border-radius: var(--su-radius-xs);
background-color: var(--su-bg-card);
color: var(--su-color-primary);
font-family: var(--su-font-mono);
justify-self: start;
}
/* 后台:左侧导航 + 右侧内容 */
.admin-shell {
display: grid;
grid-template-columns: 190px minmax(0, 1fr);
gap: var(--su-space-6);
align-items: start;
margin-top: var(--su-space-5);
}
.admin-nav {
position: sticky;
top: calc(var(--su-header-height) + var(--su-space-5));
padding-right: var(--su-space-4);
border-right: 1px solid var(--su-border);
}
.admin-panel {
min-width: 0;
}
@media (max-width: 860px) {
.admin-shell {
grid-template-columns: 1fr;
}
.admin-nav {
position: static;
padding-right: 0;
border-right: none;
border-bottom: 1px solid var(--su-border);
padding-bottom: var(--su-space-3);
}
}
/* 后台:一条已保存字体的编辑框 */
.font-link {
display: flex;
flex-direction: column;
gap: var(--su-space-3);
padding: var(--su-space-4);
border: 1px solid var(--su-border);
border-radius: var(--su-radius-sm);
}
/* 字体族名带 hint、名称不带,两个字段高度不同;顶部对齐才不会错位 */
.font-link .admin-row {
align-items: flex-start;
}
.font-link .admin-row > * {
flex: 1 1 0;
min-width: 0;
}
/* 后台「首页 Logo」的实时预览:外观交给库里的 Brand,这里只管外框 */
.brand-preview {
display: flex;
align-items: center;
gap: var(--su-space-2);
padding: var(--su-space-3) var(--su-space-4);
border: 1px dashed var(--su-border);
border-radius: var(--su-radius-md);
background-color: var(--su-bg-card);
}
/* ---------- 页头滚动信息 ---------- */
/* 跑马灯外壳在 @stash/ui 的 Ticker 里,这里只剩每条信息的排版 */
.header-ticker-item {
display: inline-flex;
align-items: center;
gap: var(--su-space-2);
font-size: var(--su-font-size-sm);
line-height: var(--su-line-height-sm);
color: var(--su-text-sub);
white-space: nowrap;
}
/* 滚动信息居中,左右列等宽 */
.header-ticker-slot {
justify-self: center;
width: 100%;
min-width: 0;
}
.header-ticker {
width: 100%;
max-width: none;
margin: 0;
}
.header-actions {
justify-self: end;
/* 靠右对齐到页头右边缘 */
flex: none;
}
/* ---------- 搜索:页头下的工具条(Layout 的 toolbar 插槽) ---------- */
.search-toolbar {
display: flex;
justify-content: center;
/* 整条带 120(32 + 44 + 44):搜索框比贴着页头时再往下挪 16 */
padding: var(--su-space-8) 0 calc(var(--su-space-10) + var(--su-space-1));
}
/* ---------- 两栏骨架 ---------- */
.content {
display: flex;
flex-direction: column;
gap: var(--su-space-5);
padding-right: 4px;
padding-bottom: var(--su-space-10);
}
.sidebar {
display: flex;
flex-direction: column;
gap: var(--su-space-4);
padding-top: 0;
}
/* ---------- 侧栏卡片 ---------- */
.profile-card {
display: flex;
flex-direction: column;
align-items: center;
gap: var(--su-space-2);
padding: var(--su-space-5) var(--su-space-4) var(--su-space-4);
text-align: center;
}
.profile-name {
line-height: 1.2;
}
.profile-role {
padding: 0 var(--su-space-2);
border: 1px solid var(--su-border);
border-radius: var(--su-radius-pill);
font-size: var(--su-font-size-xs);
line-height: var(--su-line-height-sm);
color: var(--su-text-sub);
}
.profile-bio {
margin-top: 2px;
line-height: 1.55;
}
.profile-location {
margin-top: 2px;
font-size: var(--su-font-size-xs);
line-height: var(--su-line-height-sm);
color: var(--su-text-muted);
}
/* 旧版头像下面留 4px,和名字之间更松 */
.profile-card > span:first-child {
margin-bottom: 4px;
}
.service-panel {
padding: var(--su-space-3) var(--su-space-4);
}
/* 旧版标题与统计值的行高比库默认更紧 */
.service-panel h2 {
line-height: var(--su-line-height-sm);
}
/* 旧版连接状态药丸:22 高、12px */
.service-status {
height: 22px;
padding: 0 var(--su-space-3);
font-size: var(--su-font-size-xs);
}
/* 旧版统计行是 12/18 */
.service-stats span {
line-height: var(--su-line-height-sm);
}
.service-stats {
display: flex;
flex-direction: column;
gap: var(--su-space-2);
margin-top: 10px;
}
.service-actions {
display: flex;
gap: var(--su-space-2);
margin-top: var(--su-space-3);
}
.service-actions > * {
flex: 1;
}
.service-host {
max-width: 140px;
}
.nav-card {
padding: var(--su-space-2);
}
/* ---------- 首页分区 ---------- */
.home-view {
display: flex;
flex-direction: column;
gap: var(--su-space-5);
}
.section-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: var(--su-space-4);
}
.section-title-wrapper {
display: flex;
align-items: center;
}
/* 角标是挂在标题右上角的绝对定位元素(旧版行为),不占行内宽度 */
.section-title-box {
position: relative;
display: inline-flex;
align-items: center;
}
.count-badge {
position: absolute;
top: -8px;
/* 以左边缘定位:不管角标是 1 位还是 2 位数,和标题的距离都一样 */
left: calc(100% + 8px);
right: auto;
height: 16px;
min-width: 16px;
padding: 0 var(--su-space-1);
border-radius: var(--su-radius-sm);
box-shadow: 0 1px 3px color-mix(in srgb, var(--su-color-danger) 30%, transparent);
font-size: var(--su-font-size-xs);
font-weight: var(--su-font-weight-strong);
line-height: 1;
}
/* 旧版分区标题是 16/1.2,更多按钮是 24px 小方按钮 */
.section-header h2 {
line-height: 1.2;
}
.section-more {
width: 24px;
height: 24px;
}
.section-bar {
width: 4px;
height: 16px;
margin-right: var(--su-space-2);
border-radius: var(--su-radius-xs);
background-color: var(--su-color-primary);
}
/* 新前台:卡片内的分组块 / 分组页层级 */
.card-group-block + .card-group-block {
margin-top: var(--su-space-4);
}
.card-group-title {
margin: 0 0 var(--su-space-2);
font-size: var(--su-font-size-md);
font-weight: 600;
color: var(--su-text-sub);
}
.mixed-format-block + .mixed-format-block {
margin-top: var(--su-space-4);
}
.group-child-block {
margin-top: var(--su-space-2);
}
/* 明细页的分组标题:与首页卡片标题同一套「色条 + 标题」 */
.group-title {
display: flex;
align-items: center;
}
.group-bar {
width: 4px;
height: 16px;
margin-right: var(--su-space-2);
border-radius: var(--su-radius-xs);
background-color: var(--su-color-primary);
}
/* ---------- 应用条目 / 图文白卡 ---------- */
/* 条目行的版式在 @stash/ui 的 EntryRow,图文卡在 EntryTile,这里不再有手写卡片外壳 */
/* ---------- 详情 ---------- */
.detail-view {
display: flex;
flex-direction: column;
gap: var(--su-space-5);
}
.detail-nav {
display: flex;
align-items: center;
padding: 12px var(--su-space-5);
}
/* 面包屑在左侧,12px(与旧版 breadcrumb 一致) */
.detail-breadcrumb {
font-size: var(--su-font-size-xs);
}
.detail-nav > * {
width: 100%;
}
.detail-hero {
display: flex;
flex-direction: column;
align-items: center;
padding: var(--su-space-3) 0 var(--su-space-1);
text-align: center;
}
.detail-hero-icon {
display: flex;
align-items: center;
justify-content: center;
width: 44px;
height: 44px;
margin-bottom: var(--su-space-2);
border-radius: 50%;
background-color: var(--su-color-primary-soft);
color: var(--su-color-primary);
font-size: var(--su-font-size-xl);
line-height: 1;
}
.detail-hero-title {
font-size: var(--su-font-size-xl);
font-weight: var(--su-font-weight-strong);
line-height: 1.5;
}
.detail-hero-count {
margin-top: var(--su-space-1);
font-size: var(--su-font-size-md);
color: var(--su-text-muted);
}
.item-card {
display: flex;
flex-direction: column;
align-items: center;
padding: var(--su-space-6);
}
.item-title {
display: flex;
align-items: center;
justify-content: center;
gap: var(--su-space-3);
font-size: var(--su-font-size-xl);
font-weight: var(--su-font-weight-semibold);
line-height: 1.5;
}
/* 旧版标签:2px 10px、12px、主色浅底 */
.item-tag {
height: 22px;
padding: 0 var(--su-space-3);
font-size: var(--su-font-size-xs);
}
.item-edit {
margin-left: var(--su-space-1);
font-size: var(--su-font-size-sm);
color: var(--su-color-primary);
vertical-align: middle;
cursor: pointer;
}
.item-edit:disabled {
cursor: not-allowed;
opacity: 0.6;
}
.item-cover {
display: grid;
place-items: center;
margin: var(--su-space-5) 0 var(--su-space-3);
overflow: hidden;
background-color: var(--su-color-primary-soft);
color: var(--su-color-primary);
}
.item-cover img {
width: 100%;
height: 100%;
object-fit: cover;
}
.item-cover-letter {
font-size: var(--su-font-size-2xl);
color: var(--su-text-sub);
}
.item-quote {
display: flex;
gap: var(--su-space-2);
width: 100%;
margin-top: 18px;
text-align: left;
}
.item-quote-mark {
flex-shrink: 0;
font-size: var(--su-font-size-2xl);
font-weight: var(--su-font-weight-strong);
line-height: 1;
color: color-mix(in srgb, var(--su-color-danger) 35%, transparent);
}
.item-quote-text {
font-size: var(--su-font-size-md);
line-height: 1.7;
color: var(--su-text-sub);
}
/* 旧版正文段落:占满卡片宽度、左对齐、14/1.7、次级色 */
.item-desc {
width: 100%;
margin-top: 10px;
line-height: 1.7;
text-align: left;
}
.item-actions {
display: flex;
align-items: center;
gap: var(--su-space-2);
width: 100%;
margin-top: 18px;
}
/* 统计小药丸:浏览 / 点赞的底 */
.item-stat {
min-width: 56px;
height: 36px;
padding: 0 var(--su-space-3);
border-radius: var(--su-radius-cover);
background-color: var(--su-bg-page);
}
/* 跳转按钮占满剩余宽度 */
.item-jump {
display: inline-flex;
flex: 1;
align-items: center;
justify-content: center;
gap: var(--su-space-2);
height: 36px;
border-radius: var(--su-radius-cover);
background-color: var(--su-color-primary);
color: var(--su-white);
font-size: var(--su-font-size-md);
transition: opacity var(--su-duration-fast) var(--su-ease-in-out);
}
.item-jump:hover:not(:disabled) {
background-color: var(--su-color-primary-hover);
}
.item-jump:disabled {
cursor: not-allowed;
opacity: 0.5;
}
.item-banner {
width: 100%;
margin-top: var(--su-space-4);
border-radius: var(--su-radius-md);
}
/* ---------- 文章 ---------- */
.article-head {
display: flex;
flex-direction: column;
align-items: center;
gap: var(--su-space-3);
padding: var(--su-space-1) 0;
text-align: center;
}
.article-heading {
max-width: 760px;
font-size: var(--su-font-size-xl);
font-weight: var(--su-font-weight-strong);
line-height: 1.4;
}
.article-meta {
display: flex;
align-items: center;
font-size: var(--su-font-size-xs);
color: var(--su-text-muted);
}
.article-meta-item {
display: inline-flex;
align-items: center;
}
.article-meta-dot {
width: 3px;
height: 3px;
margin: 0 var(--su-space-2);
border-radius: 50%;
background-color: var(--su-border);
}
.article-body-card {
overflow: hidden;
}
.article-body {
display: flex;
flex-direction: column;
gap: var(--su-space-3);
padding: var(--su-space-8) var(--su-space-10) var(--su-space-10);
}
.article-lead {
margin-bottom: var(--su-space-2);
}
.article-body-image {
width: 100%;
margin: var(--su-space-2) 0;
border-radius: var(--su-radius-md);
}
/* ---------- 推荐阅读 ---------- */
.related-grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: var(--su-space-4) var(--su-space-6);
margin-top: var(--su-space-4);
}
.related-title {
display: flex;
align-items: center;
gap: var(--su-space-2);
margin-bottom: var(--su-space-4);
}
.related-item {
display: flex;
align-items: center;
gap: var(--su-space-3);
width: 100%;
padding: var(--su-space-1);
border-radius: var(--su-radius-cover);
text-align: left;
transition: background-color var(--su-duration-fast) var(--su-ease-in-out);
}
.related-item:hover {
background-color: var(--su-bg-subtle);
}
.related-info {
min-width: 0;
}
/* ---------- 通用 ---------- */
/* 服务面板的两个操作按钮:旧版是 12px / 28 高 / 等分 / 描边 */
.service-action {
flex: 1;
height: 28px;
padding: 0 var(--su-space-2);
font-size: var(--su-font-size-xs);
border-radius: var(--su-radius-cover);
}
.service-action:hover:not(:disabled) {
border-color: var(--su-color-primary);
background-color: var(--su-color-primary-soft);
color: var(--su-color-primary);
}
/* 页头图标按钮:旧版 hover 是浅灰底 + 深色字 */
.site-header-inner button:hover {
background-color: var(--su-bg-light);
color: var(--su-text-main);
}
/* 分区卡右上角 •••:旧版 hover 只有浅灰底 */
.section-more:hover {
background-color: var(--su-bg-light);
color: var(--su-text-sub);
}
/* 详情 / 文章切换时的淡入上浮(旧版 view-in) */
@keyframes view-in {
from {
opacity: 0;
transform: translateY(6px);
}
to {
opacity: 1;
transform: none;
}
}
.detail-view {
animation: view-in 0.22s ease both;
}
@media (prefers-reduced-motion: reduce) {
.detail-view {
animation: none;
}
}
.link-button {
display: inline-flex;
align-items: center;
gap: var(--su-space-1);
height: 32px;
padding: 0 var(--su-space-3);
border: 1px solid var(--su-border);
border-radius: var(--su-radius-sm);
font-size: var(--su-font-size-sm);
color: var(--su-text-sub);
transition: background-color var(--su-duration-fast) var(--su-ease-in-out);
}
.link-button:hover {
background-color: var(--su-bg-subtle);
color: var(--su-text-main);
}
.sr-only {
position: absolute;
width: 1px;
height: 1px;
overflow: hidden;
clip-path: inset(50%);
white-space: nowrap;
}
/* ---------- 设置页 ---------- */
.admin-page {
min-height: 100vh;
min-height: 100dvh;
background-color: var(--su-bg-page);
}
/* 与前台页头同一套:整条吸顶,内部 .site-header-inner 负责 60 高与限宽 */
.admin-topbar {
position: sticky;
top: 0;
z-index: var(--su-z-header);
border-bottom: 1px solid var(--su-border);
background-color: var(--su-bg-card);
}
.admin-main {
/* 与页头内层同宽同左缘:页头 1380 减左右各 20 的内边距 = 内容从 50 起 */
width: min(var(--su-layout-width), 100%);
margin: 0 auto;
padding: var(--su-space-8) var(--su-space-5) var(--su-space-10);
}
.admin-locked {
display: flex;
align-items: center;
justify-content: space-between;
gap: var(--su-space-4);
margin-top: var(--su-space-5);
padding: var(--su-space-4);
border: 1px dashed var(--su-border-strong);
border-radius: var(--su-radius-md);
}
.admin-form {
margin-top: var(--su-space-5);
}
.admin-row {
display: flex;
align-items: center;
gap: var(--su-space-3);
}
.admin-item-row {
display: grid;
grid-template-columns: minmax(0, 1fr) 160px 120px auto;
align-items: center;
gap: var(--su-space-2);
}
.admin-item-row .su-switch {
justify-self: start;
}
/* ---------- 响应式 ---------- */
@media (max-width: 1100px) {
/* 单列堆叠:滚动容器不能换行,否则侧栏占满高度后主内容会被排到视口右侧(看不见) */
#page-scroll {
flex-wrap: nowrap;
}
.profile-card {
grid-row: auto;
}
.service-panel {
display: none;
}
.search-toolbar {
padding: var(--su-space-5) 0 var(--su-space-6);
}
.content {
padding-top: var(--su-space-2);
}
}
@media (max-width: 820px) {
/* 手机上只留分组导航:资料卡 / 本地服务卡太占地,导航还留着方便进分组 */
#page-scroll > aside .profile-card,
#page-scroll > aside .service-panel {
display: none;
}
/* 手机上页头只留品牌 + 操作图标:跑马灯放不下,会盖到下面的搜索条上 */
.header-ticker-slot {
display: none;
}
.site-header-inner {
grid-template-columns: minmax(0, 1fr) auto;
gap: var(--su-space-2);
height: 56px;
padding: 0 var(--su-space-3);
}
.header-actions {
gap: var(--su-space-1);
}
}
@media (prefers-reduced-motion: reduce) {
.related-item,
.link-button {
transition: none;
}
}
/* ---------- 条目操作条 / 设置页细节 ---------- */
.item-stat {
display: inline-flex;
align-items: center;
gap: var(--su-space-1);
padding: 0;
border: none;
background: none;
color: var(--su-text-sub);
font: inherit;
cursor: pointer;
}
.item-stat.is-liked,
.item-stat.is-liked svg {
color: var(--su-color-primary);
}
.item-title .item-edit {
margin-left: 0;
align-self: center;
line-height: 1;
}
.admin-actions {
margin-top: var(--su-space-6);
}
.admin-tabs {
overflow: visible;
margin-bottom: var(--su-space-5);
}
/* Select 自身有 160px 最小宽度,网格项必须允许收缩,否则会盖住「新增」按钮 */
/* 侧栏里的子分类(分组):缩进一层,弱化文字 */
/* 归类页:一行一个分区,标题 / 类型 / 图标 / 色条 / 条数 / 保存 / 删除 */
/* 新后台:分组树行 / 新建行 / 卡片头,用弹性布局避免网格列数对不上 */
.admin-node-title {
flex: 1;
min-width: 0;
}
/* 分组管理:参考后台的树形表格 */
.group-toolbar {
display: flex;
justify-content: flex-start;
}
.group-name-cell {
display: flex;
align-items: center;
gap: var(--su-space-2);
}
/* 接口一览页 */
.api-docs {
display: flex;
flex-direction: column;
gap: var(--su-space-5);
}
.api-path {
padding: 0 var(--su-space-2);
border-radius: var(--su-radius-xs);
background-color: var(--su-bg-subtle);
color: var(--su-text-sub);
font-family: var(--su-font-mono);
font-size: var(--su-font-size-sm);
}
/* 数据管理:分组下拉与「新建数据」紧挨着 */
.entry-toolbar {
display: flex;
align-items: center;
gap: var(--su-space-2);
}
.entry-toolbar-select {
width: 260px;
}
/* 折叠箭头:外观交给 @stash/ui 的 Caret,这里只管按钮盒与占位 */
.group-caret {
display: inline-flex;
flex: none;
align-items: center;
justify-content: center;
width: 20px;
height: 20px;
padding: 0;
border: none;
background: none;
color: var(--su-text-muted);
cursor: pointer;
}
.group-caret-empty {
cursor: default;
}
/* 分组图标选择:搜索 + 图标网格 */
.icon-picker {
display: flex;
flex-direction: column;
gap: var(--su-space-3);
margin-top: var(--su-space-3);
padding: var(--su-space-3);
border: 1px solid var(--su-border);
border-radius: var(--su-radius-md);
background-color: var(--su-bg-subtle);
}
.icon-picker-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(40px, 1fr));
gap: var(--su-space-2);
max-height: 220px;
overflow-y: auto;
}
.icon-picker-item {
display: grid;
place-items: center;
height: 36px;
border: 1px solid transparent;
border-radius: var(--su-radius-sm);
background-color: var(--su-bg-card);
color: var(--su-text-sub);
font-size: var(--su-font-size-lg);
cursor: pointer;
transition:
border-color var(--su-duration-fast) var(--su-ease-in-out),
color var(--su-duration-fast) var(--su-ease-in-out);
}
.icon-picker-item:hover {
border-color: var(--su-color-primary);
color: var(--su-color-primary);
}
.group-mark {
display: inline-flex;
flex: none;
align-items: center;
justify-content: center;
width: 20px;
color: var(--su-color-primary);
font-size: var(--su-font-size-lg);
}
.group-mark-empty {
width: 20px;
}
.group-mark-text {
font-size: var(--su-font-size-md);
}
.group-name {
color: var(--su-text-main);
font-weight: 500;
}
.group-icon-field {
display: flex;
align-items: center;
gap: var(--su-space-2);
}
.group-icon-preview {
display: inline-flex;
flex: none;
align-items: center;
justify-content: center;
width: 40px;
height: 40px;
border: 1px solid var(--su-border-strong);
border-radius: var(--su-radius-sm);
background-color: var(--su-bg-subtle);
}
.group-dialog-row {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: var(--su-space-3);
}
.entry-format {
display: inline-block;
padding: 0 var(--su-space-2);
border-radius: var(--su-radius-xs);
background-color: var(--su-bg-subtle);
color: var(--su-text-muted);
font-size: var(--su-font-size-sm);
}
.entry-title {
color: var(--su-text-main);
font-weight: 500;
}
.entry-href {
display: inline-block;
max-width: 100%;
overflow: hidden;
color: var(--su-color-primary);
font-size: var(--su-font-size-sm);
text-overflow: ellipsis;
text-decoration: none;
vertical-align: bottom;
white-space: nowrap;
}
a.entry-href:hover {
text-decoration: underline;
}
.entry-href-empty {
color: var(--su-text-placeholder);
}
.entry-group {
color: var(--su-text-sub);
font-size: var(--su-font-size-sm);
}
/* 首页:左右栏共用一个滚动区,左侧吸顶交给 CSS sticky */
#page-scroll {
scrollbar-width: none;
-ms-overflow-style: none;
}
#page-scroll::-webkit-scrollbar {
display: none;
}
/* 左栏吸顶:sticky 由滚动引擎处理,不会像 JS 改 transform 那样落后平滑滚动一帧。
高度锁在滚动区高度内,栏内只有「分组导航」可滚,资料卡与本地服务保持不动。 */
#page-scroll > aside {
position: sticky;
top: 0;
align-self: flex-start;
height: 100%;
max-height: 100%;
overflow: hidden;
}
/* 侧栏卡片也贴着 aside 的边缘,阴影同样会被裁掉。
撑宽 16px 再补等量内边距,卡片宽度和位置都不变,阴影有地方画(窄屏堆叠时不适用)。 */
@media (min-width: 1101px) {
#page-scroll > aside {
width: calc(var(--layout-sider) + 32px);
margin: 0 -16px;
padding: 0 16px;
}
}
#page-scroll > aside .sidebar-wrap,
#page-scroll > aside .sidebar-home {
display: flex;
flex-direction: column;
height: 100%;
min-height: 0;
}
#page-scroll > aside .profile-card,
#page-scroll > aside .service-panel {
flex-shrink: 0;
}
/* 只有导航卡参与滚动,滚动条隐藏 */
#page-scroll > aside .nav-card {
flex: 0 1 auto;
min-height: 0;
overflow-y: auto;
overflow-x: hidden;
scrollbar-width: none;
-ms-overflow-style: none;
}
#page-scroll > aside .nav-card::-webkit-scrollbar {
display: none;
width: 0;
height: 0;
}
.sidebar-home {
padding-top: 0;
padding-bottom: 24px;
will-change: transform;
}
.sidebar-wrap {
position: relative;
}
/* 侧栏到内容区共用一条滚动虚化遮罩,同一水平高度 */
/* 侧栏卡片保持实底:原来 64% 半透明 + 毛玻璃,同一张卡落在背景图不同亮度的位置
会显出深浅差,明暗两套主题也分不出来。现在和首页卡片同一种底,只有背景图透出卡片外面。 */
.sidebar-home .nav-card {
overflow: hidden;
border: 1px solid var(--su-card-border);
border-radius: var(--su-radius-md);
background-color: var(--su-bg-card);
box-shadow: var(--su-shadow-card);
}
/* 首页卡片:左侧卡片列表 + 右侧分组表格 */
.cards-manager {
display: grid;
grid-template-columns: 220px minmax(0, 1fr);
gap: var(--su-space-4);
align-items: start;
margin-top: var(--su-space-4);
}
.cards-side {
padding: var(--su-space-3);
border: 1px solid var(--su-card-border);
border-radius: var(--su-radius-md);
background-color: var(--su-bg-subtle);
}
.cards-side-new {
display: flex;
flex-direction: column;
align-items: stretch;
gap: var(--su-space-2);
margin: var(--su-space-2) 0 var(--su-space-3);
}
.cards-side-new > button {
width: 100%;
}
/* 拖动说明夹在「新建卡片」和卡片列表之间:上方靠按钮的外边距,下方留一点呼吸 */
.cards-drag-hint {
display: block;
margin: 0 0 var(--su-space-4);
}
.cards-main {
min-width: 0;
}
/* 首页 Tab:侧边栏设置 + 首页卡片上下两段 */
.admin-home {
display: flex;
flex-direction: column;
gap: var(--su-space-4);
}
.admin-home-section {
display: flex;
flex-direction: column;
gap: var(--su-space-3);
}
.card-order-cell {
display: flex;
align-items: center;
gap: var(--su-space-1);
}
/* 分组管理里状态为「关闭」的分组:卡片里只能看、不能勾选 */
/* 卡片表格的状态列:启用/已停用同一个胶囊,只换颜色 */
.card-state {
display: inline-block;
padding: 0 var(--su-space-2);
border-radius: var(--su-radius-pill);
font-size: var(--su-font-size-xs);
line-height: var(--su-line-height-sm);
white-space: nowrap;
}
.card-state-on {
background-color: var(--su-color-success-soft);
color: var(--su-color-success);
}
.card-state-off {
background-color: var(--su-color-danger-soft);
color: var(--su-color-danger);
}
.card-order-index {
display: grid;
place-items: center;
width: 20px;
height: 20px;
margin-right: var(--su-space-1);
border-radius: var(--su-radius-pill);
background-color: var(--su-color-primary-soft);
color: var(--su-color-primary);
font-size: var(--su-font-size-xs);
}
@media (max-width: 860px) {
.cards-manager {
grid-template-columns: 1fr;
}
}
/* 分区管理:一个分区一块,下面挂卡片预览与子分组 */
/* 内容页:新增条目表单与条目列表 */
.admin-content-form {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: var(--su-space-3);
}
.admin-content-form .admin-col-span {
grid-column: 1 / -1;
}
.admin-item-actions .admin-remove:disabled {
color: var(--su-text-muted);
cursor: not-allowed;
opacity: 0.45;
}
/* 后台表格里的操作列与卡片标题栏(其余表格样式已交给 @stash/ui 的 Table) */
.group-actions {
display: flex;
justify-content: flex-end;
gap: var(--su-space-3);
}
.cards-table-head {
display: flex;
align-items: center;
gap: var(--su-space-2);
margin-bottom: var(--su-space-2);
}
.cards-table-head .admin-remove {
color: var(--su-color-danger);
}
.cards-table-head .admin-remove:not(:disabled):hover {
color: var(--su-color-danger);
background-color: color-mix(in srgb, var(--su-color-danger) 10%, transparent);
}
/* ---------- 明暗切换:短暂给所有表面补颜色过渡 ---------- */
/* 只在切换的 180ms 内加 !important,避免覆盖组件平时的 hover/展开动画。 */
html.theme-transition,
html.theme-transition *,
html.theme-transition *::before,
html.theme-transition *::after {
transition:
background-color 160ms var(--su-ease-in-out),
border-color 160ms var(--su-ease-in-out),
color 160ms var(--su-ease-in-out),
fill 160ms var(--su-ease-in-out),
stroke 160ms var(--su-ease-in-out),
box-shadow 160ms var(--su-ease-in-out) !important;
}
@media (prefers-reduced-motion: reduce) {
html.theme-transition,
html.theme-transition *,
html.theme-transition *::before,
html.theme-transition *::after {
transition: none !important;
}
}
/* 背景图不跟着全局颜色过渡,单独做明暗交叉淡入 */
html.theme-transition .site-background {
transition: opacity 160ms var(--su-ease-in-out) !important;
}
@media (prefers-reduced-motion: reduce) {
html.theme-transition .site-background {
transition: none !important;
}
}
/* 后台:背景管理预览 */
.background-grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: var(--su-space-5);
}
.background-section {
display: flex;
flex-direction: column;
gap: var(--su-space-3);
min-width: 0;
}
.background-preview {
position: relative;
height: 180px;
border: 1px solid var(--su-border);
border-radius: var(--su-radius-md);
background-color: var(--su-bg-subtle);
background-position: center top;
background-repeat: no-repeat;
background-size: cover;
overflow: hidden;
}
.background-preview span {
position: absolute;
bottom: var(--su-space-3);
left: var(--su-space-3);
padding: 2px var(--su-space-2);
border-radius: var(--su-radius-pill);
background-color: rgb(0 0 0 / 55%);
color: #fff;
font-size: var(--su-font-size-xs);
}
@media (width <= 900px) {
.background-grid {
grid-template-columns: minmax(0, 1fr);
}
}
/* 明暗切换:支持的浏览器直接对整页做快照交叉淡入,避免背景图和底色各变各的 */
::view-transition-old(root),
::view-transition-new(root) {
animation-duration: 160ms;
animation-timing-function: var(--su-ease-in-out);
}
@media (prefers-reduced-motion: reduce) {
::view-transition-old(root),
::view-transition-new(root) {
animation: none;
}
}
/* ---------- 搜索框:顶部引擎标签 + 下拉选项 ---------- */
.search-shell {
position: relative;
width: min(100%, 480px);
}
.engine-badge {
position: absolute;
top: -12px;
left: 16px;
z-index: 2;
display: inline-flex;
align-items: center;
gap: 5px;
padding: 2px 8px;
border: 1px solid var(--su-border);
border-radius: 6px;
background-color: var(--su-bg-card);
box-shadow: var(--su-shadow-card);
color: var(--su-text-main);
font: inherit;
font-size: 11px;
line-height: 1.4;
cursor: pointer;
transition:
background-color var(--su-duration-fast) var(--su-ease-in-out),
border-color var(--su-duration-fast) var(--su-ease-in-out);
}
.engine-badge:hover,
.engine-badge[aria-expanded='true'] {
border-color: var(--su-border-strong);
background-color: var(--su-bg-subtle);
}
.engine-badge svg {
display: block;
flex-shrink: 0;
}
.engine-dropdown {
position: absolute;
top: calc(100% + 8px);
left: 10px;
z-index: var(--su-z-float);
display: flex;
flex-direction: column;
gap: 2px;
min-width: 170px;
padding: var(--su-space-1);
border: 1px solid var(--su-border);
border-radius: var(--su-radius-sm);
background-color: var(--su-bg-card);
box-shadow: var(--su-shadow-pop);
animation: engine-menu-in 160ms var(--su-ease-out);
}
@keyframes engine-menu-in {
from {
opacity: 0;
transform: translateY(-6px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.engine-divider {
height: 1px;
margin: 4px 8px;
background-color: var(--su-border);
}
.engine-option {
display: flex;
align-items: center;
gap: 10px;
width: 100%;
padding: 8px 12px;
border: 0;
border-radius: 6px;
background: transparent;
color: var(--su-text-main);
font: inherit;
font-size: 13px;
text-align: left;
white-space: nowrap;
cursor: pointer;
transition: background-color var(--su-duration-fast) var(--su-ease-in-out);
}
.engine-option:hover {
background-color: var(--su-bg-subtle);
}
.engine-option.is-active {
background-color: var(--su-color-primary-soft);
color: var(--su-color-primary);
}
/* 后台:搜索框引擎配置 */
.search-engine-list {
display: flex;
flex-direction: column;
gap: var(--su-space-3);
}
.search-engine-row {
padding: var(--su-space-4);
border: 1px solid var(--su-border);
border-radius: var(--su-radius-md);
}
.search-engine-row.is-disabled {
opacity: 0.55;
}
.search-engine-head {
display: flex;
align-items: center;
gap: var(--su-space-2);
margin-bottom: var(--su-space-3);
}
.search-engine-head > :last-child {
margin-left: auto;
}
.search-engine-fields {
display: grid;
grid-template-columns: minmax(0, 1fr) minmax(0, 2fr);
gap: var(--su-space-3);
}
@media (width <= 900px) {
.search-engine-fields {
grid-template-columns: minmax(0, 1fr);
}
}
/* ---------- 窄屏覆盖(放文件末尾:要盖过上面的侧栏基础规则) ---------- */
@media (max-width: 1100px) {
/* 侧栏 / 主内容在窄屏都不锁 100% 高、不吸顶;放在文件末尾才压得过上面的基础规则 */
#page-scroll > aside {
position: static;
align-self: stretch;
height: auto;
max-height: none;
overflow: visible;
}
#page-scroll > main {
height: auto;
max-height: none;
}
#page-scroll > aside .sidebar-wrap {
height: auto;
padding: 0 var(--su-space-4) var(--su-space-4);
}
/* 资料卡 + 导航卡并排,少占一屏 */
#page-scroll > aside .sidebar-home {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: var(--su-space-3);
height: auto;
}
}
@media (max-width: 820px) {
/* 手机上只留导航卡,单列铺开 */
#page-scroll > aside .sidebar-home {
display: block;
}
}