427 lines
13 KiB
CSS
427 lines
13 KiB
CSS
/* 设计 token 唯一 JS 来源在 src/theme/tokens.ts,两处取值保持同步 */
|
|
@import 'tailwindcss';
|
|
|
|
@theme {
|
|
--color-bg: #f5f4ed;
|
|
--color-card: #faf9f5;
|
|
--color-white: #ffffff; /* 语义:输入 / 嵌入面,暗色下为深灰而非纯白 */
|
|
--color-ink: #141413;
|
|
--color-ink-2: #5e5d59;
|
|
--color-ink-3: #87867f;
|
|
--color-line: #e8e6dc;
|
|
--color-line-soft: #f0eee6;
|
|
--color-row-hover: #f1efe8;
|
|
--color-wash: #efede4; /* 侧栏 / 图标按钮悬浮底 */
|
|
--color-wash-deep: #ece9df; /* 侧栏激活 / 头像底 */
|
|
--color-accent: #c96442;
|
|
--color-accent-hover: #ad4f2e;
|
|
--color-chart: #c15f3c;
|
|
--color-ok: #788c5d;
|
|
--color-err: #b53333;
|
|
--color-info: #6a9bcc;
|
|
--color-warn: #a87514;
|
|
|
|
--font-sans:
|
|
-apple-system, 'SF Pro Text', 'Helvetica Neue', 'PingFang SC', 'Noto Sans SC', sans-serif;
|
|
--font-serif: Georgia, 'Times New Roman', 'Songti SC', serif;
|
|
--font-mono: ui-monospace, 'SF Mono', Menlo, Consolas, monospace;
|
|
|
|
/* 浮层(下拉/整页提示卡)统一投影:比卡片的 1px 分层重一档,仍保持克制 */
|
|
--shadow-overlay: 0 8px 24px rgba(20, 20, 19, 0.1);
|
|
}
|
|
|
|
/* 暗色主题:html.dark 由 stores/app.ts 挂载,色值与 tokens.ts 的 darkTokens 同步 */
|
|
html.dark {
|
|
--color-bg: #191817;
|
|
--color-card: #201f1e;
|
|
--color-white: #262524;
|
|
--color-ink: #eceae4;
|
|
--color-ink-2: #a8a69e;
|
|
--color-ink-3: #807e76;
|
|
--color-line: #3a3835;
|
|
--color-line-soft: #2c2b29;
|
|
--color-row-hover: #292825;
|
|
--color-wash: #2b2a27;
|
|
--color-wash-deep: #33312d;
|
|
--color-accent: #d97757;
|
|
--color-accent-hover: #e08b6d;
|
|
--color-chart: #d97757;
|
|
--color-ok: #8fa574;
|
|
--color-err: #d06060;
|
|
--color-info: #7fabd6;
|
|
--color-warn: #c29135;
|
|
color-scheme: dark;
|
|
}
|
|
|
|
html,
|
|
body {
|
|
background: var(--color-bg);
|
|
color: var(--color-ink);
|
|
font-family: var(--font-sans);
|
|
font-size: 14px;
|
|
line-height: 1.5;
|
|
-webkit-font-smoothing: antialiased;
|
|
}
|
|
|
|
/* 全局滚动条瘦身:透明轨道 + 细圆角滑块,明暗主题跟随 ink 变量 */
|
|
* {
|
|
scrollbar-width: thin;
|
|
scrollbar-color: color-mix(in srgb, var(--color-ink) 22%, transparent) transparent;
|
|
}
|
|
::-webkit-scrollbar {
|
|
width: 7px;
|
|
height: 7px;
|
|
background: transparent;
|
|
}
|
|
::-webkit-scrollbar-track {
|
|
background: transparent;
|
|
}
|
|
::-webkit-scrollbar-thumb {
|
|
background: color-mix(in srgb, var(--color-ink) 22%, transparent);
|
|
border-radius: 4px;
|
|
}
|
|
::-webkit-scrollbar-thumb:hover {
|
|
background: color-mix(in srgb, var(--color-ink) 38%, transparent);
|
|
}
|
|
|
|
/* 表格滚动条常显:Naive 隐藏原生条(scrollbar-width:none)后全靠自绘 thumb,
|
|
而自绘条仅悬停时短暂出现且渲染链路脆弱,窄容器下用户无从得知表格可横滚。
|
|
现代 Chromium(121+)只认标准属性——computed 为 none 时 ::-webkit-* 规则
|
|
整体失效,故必须以更高特异性覆盖 scrollbar-width 本身(样式随全局瘦滚动条);
|
|
webkit 伪元素规则兜底老内核(Naive 把 scrollbar/thumb 清零,须逐项放开) */
|
|
.n-data-table .n-scrollbar > .n-scrollbar-container {
|
|
scrollbar-width: thin;
|
|
}
|
|
.n-data-table .n-scrollbar > .n-scrollbar-container::-webkit-scrollbar:horizontal {
|
|
display: block;
|
|
height: 7px;
|
|
background: transparent;
|
|
}
|
|
.n-data-table .n-scrollbar > .n-scrollbar-container::-webkit-scrollbar-thumb:horizontal {
|
|
display: block;
|
|
height: 7px;
|
|
border-radius: 4px;
|
|
background: color-mix(in srgb, var(--color-ink) 22%, transparent);
|
|
}
|
|
|
|
/* 租户选择器面板(移动端):popover follower 只会翻转不会平移,窄屏下
|
|
bottom-start / bottom-end 两个方向都放不下整块面板,必然被视口裁切;
|
|
改为覆盖 follower 定位,固定顶部整宽展示(follower 挂 body 下,无
|
|
transform 祖先,fixed 相对视口生效) */
|
|
@media (max-width: 767px) {
|
|
.v-binder-follower-content:has(.tenant-picker-panel) {
|
|
position: fixed !important;
|
|
inset: 60px 12px auto 12px !important;
|
|
transform: none !important;
|
|
}
|
|
.v-binder-follower-content:has(.tenant-picker-panel) .n-popover,
|
|
.tenant-picker-panel {
|
|
width: 100% !important;
|
|
}
|
|
}
|
|
|
|
/* 页面标题统一 serif */
|
|
.page-title {
|
|
font-family: var(--font-serif);
|
|
font-size: 24px;
|
|
font-weight: 600;
|
|
}
|
|
|
|
/* 卡片:圆角 8、细边框、whisper 阴影,无渐变;
|
|
overflow hidden 防止内部表格等方角内容溢出圆角 */
|
|
.panel {
|
|
background: var(--color-card);
|
|
border: 1px solid var(--color-line);
|
|
border-radius: 8px;
|
|
box-shadow: 0 1px 2px rgba(20, 20, 19, 0.04);
|
|
min-width: 0;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.mono {
|
|
font-family: var(--font-mono);
|
|
font-size: 12.5px;
|
|
letter-spacing: -0.2px;
|
|
}
|
|
|
|
/* NDataTable 分页器默认贴表格底边,补出与卡片底部的间隔 */
|
|
.n-data-table .n-data-table__pagination {
|
|
padding: 4px 18px 14px;
|
|
}
|
|
|
|
/* 租户下拉双行选项:菜单项上下留白拉开行距,避免相邻两租户挤在一起 */
|
|
.n-base-select-option .cfg-tenancy-sub {
|
|
margin-top: 1px;
|
|
}
|
|
.n-base-select-option__content:has(.cfg-tenancy-sub) {
|
|
padding: 6px 0;
|
|
}
|
|
/* NSelect 选中框(收起态)只显示别名单行,租户名辅行隐藏 */
|
|
.n-base-selection-label .cfg-tenancy-sub {
|
|
display: none;
|
|
}
|
|
|
|
/* AppInputNumber(方案 B 内嵌步进):上下箭头收进右侧独立竖栏——
|
|
竖栏占满框高、border-left 与框体结构化分隔,上下两格中缝分隔线,
|
|
悬停格底 wash;suffix 内 minus / add 恒为最后两个子元素(add 上 minus 下)。 */
|
|
.app-input-number .n-input .n-input-wrapper {
|
|
padding-right: 34px; /* 26px 竖栏 + 文本安全间距 */
|
|
}
|
|
.app-input-number .n-input__suffix {
|
|
position: absolute;
|
|
top: 0;
|
|
right: 0;
|
|
bottom: 0;
|
|
width: 26px;
|
|
margin: 0;
|
|
display: grid;
|
|
/* minmax(0,…) 允许行收缩:small 尺寸下按钮固有高度(18px)大于半行,
|
|
1fr 的隐式 min-height:auto 会把行撑爆,下箭头溢出框外 */
|
|
grid-template-rows: minmax(0, 1fr) minmax(0, 1fr);
|
|
border-left: 1px solid var(--color-line-soft);
|
|
}
|
|
.app-input-number .n-input__suffix > :last-child {
|
|
grid-row: 1; /* add 在上 */
|
|
border-bottom: 1px solid var(--color-line-soft);
|
|
border-top-right-radius: 5px;
|
|
}
|
|
.app-input-number .n-input__suffix > :nth-last-child(2) {
|
|
grid-row: 2; /* minus 在下 */
|
|
border-bottom-right-radius: 5px;
|
|
}
|
|
.app-input-number .n-input__suffix .n-button {
|
|
/* 箭头颜色跟随文本弱色而非按钮主题色:NButton 自带 --n-text-color
|
|
内联声明会盖过外层 color,必须直接覆盖变量 */
|
|
--n-icon-size: 9px;
|
|
--n-text-color: var(--color-ink-3);
|
|
--n-text-color-hover: var(--color-ink);
|
|
--n-text-color-pressed: var(--color-ink);
|
|
--n-text-color-focus: var(--color-ink);
|
|
width: 100%;
|
|
height: 100%;
|
|
min-height: 0;
|
|
border-radius: inherit;
|
|
color: var(--color-ink-3);
|
|
}
|
|
.app-input-number .n-input__suffix .n-button:not(.n-button--disabled):hover {
|
|
background: var(--color-wash);
|
|
color: var(--color-ink);
|
|
}
|
|
/* clearable 时 naive-ui 在 suffix 首位多渲染 .n-base-clear,会被上面的
|
|
2 行网格自动排进隐式第 2 列、把 26px 竖栏撑爆(箭头溢出框外)——
|
|
绝对定位使其脱离网格流,悬浮在竖栏左侧;文本区同步加宽避让清空图标 */
|
|
.app-input-number .n-input__suffix .n-base-clear {
|
|
position: absolute;
|
|
right: 100%;
|
|
top: 50%;
|
|
transform: translateY(-50%);
|
|
margin-right: 5px;
|
|
}
|
|
.app-input-number .n-input:has(.n-base-clear) .n-input-wrapper {
|
|
padding-right: 52px;
|
|
}
|
|
|
|
/* useToast 可展开详情:toast 内嵌代码块(标签 + 复制 + 内滚 pre)。
|
|
message 经 teleport 渲染于 body,组件 scoped 样式不可达,故置于全局。 */
|
|
.toast-body {
|
|
max-width: 420px;
|
|
}
|
|
.toast-line {
|
|
display: flex;
|
|
align-items: baseline;
|
|
gap: 10px;
|
|
}
|
|
.toast-toggle {
|
|
flex: none;
|
|
cursor: pointer;
|
|
font-size: 12px;
|
|
color: var(--color-accent);
|
|
user-select: none;
|
|
}
|
|
.toast-toggle:hover {
|
|
text-decoration: underline;
|
|
}
|
|
.toast-code {
|
|
margin-top: 8px;
|
|
overflow: hidden;
|
|
border: 1px solid var(--color-line);
|
|
border-radius: 8px;
|
|
background: var(--color-wash);
|
|
}
|
|
.toast-code-head {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
border-bottom: 1px solid var(--color-line-soft);
|
|
padding: 4px 8px 4px 10px;
|
|
}
|
|
.toast-tag {
|
|
font-family: var(--font-mono);
|
|
font-size: 10px;
|
|
font-weight: 700;
|
|
letter-spacing: 0.08em;
|
|
}
|
|
.toast-tag-error {
|
|
color: var(--color-err);
|
|
}
|
|
.toast-tag-warning {
|
|
color: var(--color-warn);
|
|
}
|
|
.toast-copy {
|
|
cursor: pointer;
|
|
border: none;
|
|
background: none;
|
|
padding: 2px 4px;
|
|
font-size: 11px;
|
|
color: var(--color-ink-3);
|
|
}
|
|
.toast-copy:hover {
|
|
color: var(--color-ink);
|
|
}
|
|
.toast-code-pre {
|
|
margin: 0;
|
|
max-height: 180px;
|
|
overflow: auto;
|
|
padding: 8px 10px;
|
|
font-family: var(--font-mono);
|
|
font-size: 11.5px;
|
|
line-height: 1.55;
|
|
white-space: pre-wrap;
|
|
word-break: break-all;
|
|
color: var(--color-ink-2);
|
|
}
|
|
|
|
/* 全屏页轨道环(FullPageBackdrop 与登录页品牌区共用):
|
|
spin 动画占用 transform,环定位只能用 left/top(calc 同心),不能用 translate。 */
|
|
.fpb-ring {
|
|
position: absolute;
|
|
border-radius: 50%;
|
|
border: 1.5px solid var(--color-line);
|
|
pointer-events: none;
|
|
}
|
|
.fpb-ring-dash {
|
|
border-style: dashed;
|
|
border-color: color-mix(in srgb, var(--color-line) 70%, var(--color-accent) 30%);
|
|
}
|
|
@media (prefers-reduced-motion: no-preference) {
|
|
.fpb-spin {
|
|
animation: fpb-spin 52s linear infinite;
|
|
}
|
|
@keyframes fpb-spin {
|
|
to {
|
|
transform: rotate(360deg);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* 明暗主题扩散切换(useThemeRipple):关掉 View Transitions 默认交叉淡入,
|
|
由 JS 在 ::view-transition-new(root) 上做以触发点为圆心的 clip-path 揭示;
|
|
旧快照垫底不动,blend 还原为普通覆盖,避免半透明混色。 */
|
|
::view-transition-old(root),
|
|
::view-transition-new(root) {
|
|
animation: none;
|
|
mix-blend-mode: normal;
|
|
}
|
|
::view-transition-old(root) {
|
|
z-index: 1;
|
|
}
|
|
::view-transition-new(root) {
|
|
z-index: 2;
|
|
}
|
|
/* 扩散进行中禁掉页面自身的过渡:new 快照是实时层,Naive 等组件的
|
|
0.3s 颜色渐变会在扩散圆内继续播放,叠加揭示动画表现为闪烁/渗色。 */
|
|
html.theme-switching *,
|
|
html.theme-switching *::before,
|
|
html.theme-switching *::after {
|
|
transition: none !important;
|
|
}
|
|
|
|
/* 区间树形选择器菜单(teleport 至 body,scoped 样式不可达):
|
|
容器留白,展开箭头与文本节奏对齐 Select 下拉 */
|
|
.n-tree-select-menu .n-tree {
|
|
padding: 5px 6px;
|
|
}
|
|
|
|
/* 代码高亮配色(highlight.js 输出):贴设计 token 的低饱和土色系,
|
|
预览弹窗与编辑器 overlay 共用;明暗两态随 token 自动切换 */
|
|
.code-hl .hljs-comment,
|
|
.code-hl .hljs-quote {
|
|
color: var(--color-ink-3);
|
|
font-style: italic;
|
|
}
|
|
.code-hl .hljs-keyword,
|
|
.code-hl .hljs-selector-tag,
|
|
.code-hl .hljs-meta {
|
|
color: var(--color-warn);
|
|
}
|
|
.code-hl .hljs-string,
|
|
.code-hl .hljs-regexp {
|
|
color: var(--color-ok);
|
|
}
|
|
.code-hl .hljs-number,
|
|
.code-hl .hljs-literal,
|
|
.code-hl .hljs-symbol {
|
|
color: var(--color-accent);
|
|
}
|
|
.code-hl .hljs-attr,
|
|
.code-hl .hljs-attribute,
|
|
.code-hl .hljs-property,
|
|
.code-hl .hljs-section,
|
|
.code-hl .hljs-selector-class,
|
|
.code-hl .hljs-selector-id {
|
|
color: var(--color-info);
|
|
}
|
|
.code-hl .hljs-title,
|
|
.code-hl .hljs-name,
|
|
.code-hl .hljs-built_in {
|
|
color: var(--color-ink);
|
|
font-weight: 600;
|
|
}
|
|
|
|
/* 移动端:Tab 条横向滑动;右缘渐隐暗示还有更多 Tab(Naive 无内建暗示),
|
|
滚动内容补尾部内边距,滚到底时末个 Tab 不被渐隐吃掉 */
|
|
@media (max-width: 767px) {
|
|
.n-tabs .n-tabs-nav-scroll-wrapper {
|
|
overflow-x: auto;
|
|
scrollbar-width: none;
|
|
-webkit-mask-image: linear-gradient(90deg, #000 0, #000 calc(100% - 28px), transparent);
|
|
mask-image: linear-gradient(90deg, #000 0, #000 calc(100% - 28px), transparent);
|
|
}
|
|
.n-tabs .n-tabs-nav-scroll-wrapper::-webkit-scrollbar {
|
|
display: none;
|
|
}
|
|
.n-tabs .n-tabs-nav-scroll-content {
|
|
padding-right: 28px;
|
|
}
|
|
}
|
|
|
|
/* 弹窗移动端全屏形态,FormModal 与各详情/表单弹窗共用(配 useMobileModal):
|
|
NModal teleport 到 body,组件 scoped 样式够不到,且按路由分包后单组件的
|
|
非 scoped 样式不保证已加载,故规则放全局。内容区吃满剩余高度限内滚动,
|
|
页脚实底常驻含手势区安全距。内容区类名此版本为 .n-card-content(footer
|
|
却是 .n-card__footer),两种拼写都盖住防升级回切 */
|
|
.form-modal-mobile {
|
|
display: flex;
|
|
flex-direction: column;
|
|
overflow: hidden;
|
|
}
|
|
.form-modal-mobile .form-modal-body {
|
|
max-height: none;
|
|
flex: 1;
|
|
min-height: 0;
|
|
}
|
|
.form-modal-mobile .n-card-content,
|
|
.form-modal-mobile .n-card__content {
|
|
flex: 1;
|
|
min-height: 0;
|
|
display: flex;
|
|
flex-direction: column;
|
|
/* 无内层滚动容器的弹窗(详情类)内容直接在此滚;FormModal 内层
|
|
.form-modal-body 自会收缩到容器内,不触发此层滚动 */
|
|
overflow-y: auto;
|
|
}
|
|
.form-modal-mobile .n-card__footer {
|
|
padding-bottom: calc(16px + env(safe-area-inset-bottom));
|
|
background: var(--color-card);
|
|
}
|