/* ============================================================ * TDesign 主题控制层(UI 库主题) * ------------------------------------------------------------ * 本文件负责「控制 UI 库组件本身的色彩与风格」,分四件事: * ① 色阶:品牌蓝 / 中性蓝灰 / 语义色的 10 级色板(我们的色,喂给 TDesign) * ② 语义角色:把 tokens.scss 的 --tk-* 映射到 TDesign 的 --td-* * ③ 组件尺度:控件高度 / 内边距 / 字号 / 行高(本版为解决「控件太小」新增) * ④ 组件级微调:卡片、输入框、按钮、弹层的外形修正 * * 为什么这样做:60+ 个工具页面里已有大量 t-card / t-button / t-input / * t-select / t-tag,全部改一遍既不现实也容易漏。TDesign 的组件样式 * 完全建立在 --td-* 变量之上(例如 .t-input.t-size-l 的高度取自 * var(--td-comp-size-xl)),所以改变量 = 全站组件改版,属最小风险改造。 * * ⚠️ 三条必须遵守的约束(踩过坑): * 1. 只覆盖 TDesign 真实存在的变量名。写错名字不会报错,只是静默不生效。 * 新增前请在 node_modules/tdesign-vue-next 的样式产物里确认。 * 2. --td-font-body-* 是复合变量(size/line-height 简写), * 所以放大字号时必须同步改 --td-font-size-* 与 --td-line-height-*, * 只改前者会出现「大字号被小行高挤住」的破版。 * 3. 尺度变量不要动 --td-size-N 阶梯本身(那是 TDesign 的原子刻度, * 图标、徽标、间距都在用);只覆盖 --td-comp-size-* 一层。 * * 命名桥接对应关系(速查): * --tk-accent → --td-brand-color (按钮/主色底) * --tk-accent-text → --td-text-color-brand (链接/图标色) * --tk-bg → --td-bg-color-page * --tk-surface → --td-bg-color-container * --tk-border → --td-border-level-1-color * ============================================================ */ /* ============================================================ * 浅色主题 * ============================================================ */ :root, :root[theme-mode='light'] { /* ---------- 品牌色阶(宝石蓝,1 最浅 → 10 最深) ---------- */ --td-brand-color-1: #eff4ff; --td-brand-color-2: #dbe6fe; --td-brand-color-3: #c0d4fe; --td-brand-color-4: #96b6fd; --td-brand-color-5: #6294fb; --td-brand-color-6: #3b76f6; --td-brand-color-7: #2563eb; --td-brand-color-8: #1d4ed8; --td-brand-color-9: #1e3fb0; --td-brand-color-10: #1b3690; /* ---------- 语义色阶 ---------- */ --td-success-color-1: #e6f7ee; --td-success-color-2: #c9efdb; --td-success-color-3: #98ddb9; --td-success-color-4: #5ec592; --td-success-color-5: #26a86d; --td-success-color-6: #178a56; --td-success-color-7: #0e6d43; --td-success-color-8: #0a5233; --td-success-color-9: #073a24; --td-success-color-10: #042514; --td-warning-color-1: #fdf3e3; --td-warning-color-2: #f8e3c1; --td-warning-color-3: #efcd96; --td-warning-color-4: #e3b264; --td-warning-color-5: #cf9433; --td-warning-color-6: #b07a1f; --td-warning-color-7: #8d5f14; --td-warning-color-8: #6d480d; --td-warning-color-9: #4f3308; --td-warning-color-10: #342104; --td-error-color-1: #fdeceb; --td-error-color-2: #f9d3d1; --td-error-color-3: #f0b0ac; --td-error-color-4: #e2857f; --td-error-color-5: #cc5a53; --td-error-color-6: #ab403a; --td-error-color-7: #8a2f2a; --td-error-color-8: #6a211d; --td-error-color-9: #4c1613; --td-error-color-10: #320d0b; /* ---------- 中性色阶(蓝灰,1 最浅 → 14 最深) * 深浅两套主题共用同一条色阶:浅色主题取低号,深色主题取高号 ---------- */ --td-gray-color-1: #f4f6fb; --td-gray-color-2: #eef2f9; --td-gray-color-3: #e2e8f3; --td-gray-color-4: #ccd7e8; --td-gray-color-5: #b1bdd3; --td-gray-color-6: #8f9cb4; --td-gray-color-7: #6e7994; --td-gray-color-8: #55617a; --td-gray-color-9: #3d4759; --td-gray-color-10: #2e3747; --td-gray-color-11: #263147; --td-gray-color-12: #1b2333; --td-gray-color-13: #131926; --td-gray-color-14: #0b0f18; /* ---------- 语义角色 ---------- */ --td-brand-color: var(--tk-accent); --td-brand-color-hover: var(--tk-accent-hover); --td-brand-color-active: var(--tk-accent-active); --td-brand-color-focus: var(--tk-accent-surface-strong); --td-brand-color-disabled: #96b6fd; --td-brand-color-light: var(--tk-accent-surface); --td-brand-color-light-hover: var(--tk-accent-surface-strong); --td-success-color: var(--td-success-color-5); --td-success-color-hover: var(--td-success-color-4); --td-success-color-active: var(--td-success-color-6); --td-success-color-focus: var(--td-success-color-2); --td-success-color-disabled: var(--td-success-color-3); --td-success-color-light: var(--td-success-color-1); --td-success-color-light-hover: var(--td-success-color-2); --td-warning-color: var(--td-warning-color-5); --td-warning-color-hover: var(--td-warning-color-4); --td-warning-color-active: var(--td-warning-color-6); --td-warning-color-focus: var(--td-warning-color-2); --td-warning-color-disabled: var(--td-warning-color-3); --td-warning-color-light: var(--td-warning-color-1); --td-warning-color-light-hover: var(--td-warning-color-2); --td-error-color: var(--td-error-color-5); --td-error-color-hover: var(--td-error-color-4); --td-error-color-active: var(--td-error-color-6); --td-error-color-focus: var(--td-error-color-2); --td-error-color-disabled: var(--td-error-color-3); --td-error-color-light: var(--td-error-color-1); --td-error-color-light-hover: var(--td-error-color-2); /* ---------- 背景 ---------- */ --td-bg-color-page: var(--tk-bg); --td-bg-color-container: var(--tk-surface); --td-bg-color-container-hover: var(--tk-surface-hover); --td-bg-color-container-active: var(--tk-surface-active); --td-bg-color-container-select: var(--tk-surface-raised); --td-bg-color-secondarycontainer: var(--tk-surface-sunken); --td-bg-color-secondarycontainer-hover: var(--tk-surface-hover); --td-bg-color-secondarycontainer-active: var(--tk-surface-active); --td-bg-color-component: var(--tk-surface-sunken); --td-bg-color-component-hover: var(--tk-surface-hover); --td-bg-color-component-active: var(--tk-border-strong); --td-bg-color-component-disabled: var(--tk-surface-sunken); --td-bg-color-secondarycomponent: var(--tk-surface-hover); --td-bg-color-secondarycomponent-hover: var(--tk-surface-active); --td-bg-color-secondarycomponent-active: var(--tk-border-strong); --td-bg-color-specialcomponent: var(--tk-surface-raised); /* 遮罩:用带色相的深色,避免死黑 */ --td-mask-active: rgba(9, 15, 32, 0.55); --td-mask-disabled: rgba(255, 255, 255, 0.6); --td-mask-background: var(--tk-surface); /* ---------- 文字 ---------- */ --td-text-color-primary: var(--tk-text); --td-text-color-secondary: var(--tk-text-secondary); --td-text-color-placeholder: var(--tk-text-placeholder); --td-text-color-disabled: #b1bdd3; --td-text-color-anti: var(--tk-text-on-accent); --td-text-color-brand: var(--tk-accent-text); --td-text-color-link: var(--tk-accent-text); --td-text-color-watermark: rgba(15, 23, 41, 0.08); /* ---------- 描边 ---------- */ --td-border-level-1-color: var(--tk-border); --td-component-stroke: var(--tk-border); --td-border-level-2-color: var(--tk-border-strong); --td-component-border: var(--tk-border-strong); /* ---------- 圆角:统一收口为 --tk-radius-* ---------- */ --td-radius-small: var(--tk-radius-sm); --td-radius-default: var(--tk-radius-md); --td-radius-medium: var(--tk-radius-lg); --td-radius-large: var(--tk-radius-xl); --td-radius-extraLarge: var(--tk-radius-2xl); --td-radius-round: var(--tk-radius-pill); --td-radius-circle: 50%; /* ---------- 阴影:带背景色相的冷调投影 ---------- */ --td-shadow-1: var(--tk-shadow-1); --td-shadow-2: var(--tk-shadow-2); --td-shadow-3: var(--tk-shadow-3); --td-shadow-inset-top: inset 0 0.5px 0 var(--tk-border); --td-shadow-inset-right: inset 0.5px 0 0 var(--tk-border); --td-shadow-inset-bottom: inset 0 -0.5px 0 var(--tk-border); --td-shadow-inset-left: inset -0.5px 0 0 var(--tk-border); --td-table-shadow-color: rgba(15, 23, 41, 0.08); /* ---------- 滚动条 ---------- */ --td-scrollbar-color: rgba(15, 23, 41, 0.18); --td-scrollbar-hover-color: rgba(15, 23, 41, 0.34); --td-scroll-track-color: transparent; /* ---------- 字体 ---------- */ --td-font-family: var(--tk-font-sans); --td-font-family-medium: var(--tk-font-sans); } /* ============================================================ * 深色主题 * ============================================================ */ :root[theme-mode='dark'] { /* ---------- 品牌色阶(深色下 1 最深 → 10 最浅) ---------- */ --td-brand-color-1: #16244d; --td-brand-color-2: #1a2d63; --td-brand-color-3: #1e377c; --td-brand-color-4: #234298; --td-brand-color-5: #2a4fb5; --td-brand-color-6: #3059d6; --td-brand-color-7: #2563eb; --td-brand-color-8: #4a80f5; --td-brand-color-9: #7aa8ff; --td-brand-color-10: #b3ccff; /* ---------- 语义色阶 ---------- */ --td-success-color-1: #06291a; --td-success-color-2: #07341f; --td-success-color-3: #0a4429; --td-success-color-4: #0c5533; --td-success-color-5: #0e6a3f; --td-success-color-6: #11804c; --td-success-color-7: #199a5d; --td-success-color-8: #2cb673; --td-success-color-9: #52cf94; --td-success-color-10: #86e0b6; --td-warning-color-1: #342104; --td-warning-color-2: #452c07; --td-warning-color-3: #59380b; --td-warning-color-4: #6f4610; --td-warning-color-5: #8a5717; --td-warning-color-6: #a76b1f; --td-warning-color-7: #c48529; --td-warning-color-8: #dda044; --td-warning-color-9: #eebb6f; --td-warning-color-10: #f6d79c; --td-error-color-1: #320d0b; --td-error-color-2: #43120f; --td-error-color-3: #571713; --td-error-color-4: #6c1e18; --td-error-color-5: #83261f; --td-error-color-6: #9d342b; --td-error-color-7: #ba473c; --td-error-color-8: #d26155; --td-error-color-9: #e58377; --td-error-color-10: #f2aca4; /* ---------- 语义角色 ---------- * 注意:深色下按钮底保持 #2563eb(与白字 5.17:1), * 而链接/图标另用更亮的 --tk-accent-text 保证在深底上可读。 */ --td-brand-color: var(--tk-accent); --td-brand-color-hover: var(--tk-accent-hover); --td-brand-color-active: var(--tk-accent-active); --td-brand-color-focus: var(--tk-accent-surface-strong); --td-brand-color-disabled: #1e377c; --td-brand-color-light: var(--tk-accent-surface); --td-brand-color-light-hover: var(--tk-accent-surface-strong); --td-success-color: var(--td-success-color-8); --td-success-color-hover: var(--td-success-color-9); --td-success-color-active: var(--td-success-color-7); --td-success-color-focus: var(--td-success-color-2); --td-success-color-disabled: var(--td-success-color-3); --td-success-color-light: var(--td-success-color-1); --td-success-color-light-hover: var(--td-success-color-2); --td-warning-color: var(--td-warning-color-8); --td-warning-color-hover: var(--td-warning-color-7); --td-warning-color-active: var(--td-warning-color-6); --td-warning-color-focus: var(--td-warning-color-2); --td-warning-color-disabled: var(--td-warning-color-3); --td-warning-color-light: var(--td-warning-color-1); --td-warning-color-light-hover: var(--td-warning-color-2); --td-error-color: var(--td-error-color-8); --td-error-color-hover: var(--td-error-color-7); --td-error-color-active: var(--td-error-color-6); --td-error-color-focus: var(--td-error-color-2); --td-error-color-disabled: var(--td-error-color-3); --td-error-color-light: var(--td-error-color-1); --td-error-color-light-hover: var(--td-error-color-2); /* ---------- 背景 ---------- */ --td-bg-color-page: var(--tk-bg); --td-bg-color-container: var(--tk-surface); --td-bg-color-container-hover: var(--tk-surface-hover); --td-bg-color-container-active: var(--tk-surface-active); --td-bg-color-container-select: var(--tk-surface-raised); --td-bg-color-secondarycontainer: var(--tk-surface-sunken); --td-bg-color-secondarycontainer-hover: var(--tk-surface-hover); --td-bg-color-secondarycontainer-active: var(--tk-surface-active); --td-bg-color-component: var(--tk-surface-sunken); --td-bg-color-component-hover: var(--tk-surface-hover); --td-bg-color-component-active: var(--tk-surface-active); --td-bg-color-component-disabled: var(--tk-surface-sunken); --td-bg-color-secondarycomponent: var(--tk-surface-hover); --td-bg-color-secondarycomponent-hover: var(--tk-surface-active); --td-bg-color-secondarycomponent-active: var(--tk-border-strong); --td-bg-color-specialcomponent: var(--tk-surface-raised); --td-mask-active: rgba(0, 0, 0, 0.72); --td-mask-disabled: rgba(19, 25, 38, 0.6); --td-mask-background: var(--tk-surface); /* ---------- 文字 ---------- */ --td-text-color-primary: var(--tk-text); --td-text-color-secondary: var(--tk-text-secondary); --td-text-color-placeholder: var(--tk-text-placeholder); --td-text-color-disabled: #55617a; --td-text-color-anti: var(--tk-text-on-accent); --td-text-color-brand: var(--tk-accent-text); --td-text-color-link: var(--tk-accent-text); --td-text-color-watermark: rgba(233, 238, 248, 0.1); /* ---------- 描边 ---------- */ --td-border-level-1-color: var(--tk-border); --td-component-stroke: var(--tk-border); --td-border-level-2-color: var(--tk-border-strong); --td-component-border: var(--tk-border-strong); /* ---------- 圆角 / 阴影 / 滚动条 / 字体 ---------- */ --td-radius-small: var(--tk-radius-sm); --td-radius-default: var(--tk-radius-md); --td-radius-medium: var(--tk-radius-lg); --td-radius-large: var(--tk-radius-xl); --td-radius-extraLarge: var(--tk-radius-2xl); --td-radius-round: var(--tk-radius-pill); --td-radius-circle: 50%; --td-shadow-1: var(--tk-shadow-1); --td-shadow-2: var(--tk-shadow-2); --td-shadow-3: var(--tk-shadow-3); --td-shadow-inset-top: inset 0 0.5px 0 var(--tk-border); --td-shadow-inset-right: inset 0.5px 0 0 var(--tk-border); --td-shadow-inset-bottom: inset 0 -0.5px 0 var(--tk-border); --td-shadow-inset-left: inset -0.5px 0 0 var(--tk-border); --td-table-shadow-color: rgba(0, 0, 0, 0.3); --td-scrollbar-color: rgba(233, 238, 248, 0.18); --td-scrollbar-hover-color: rgba(233, 238, 248, 0.34); --td-scroll-track-color: transparent; --td-font-family: var(--tk-font-sans); --td-font-family-medium: var(--tk-font-sans); } /* ============================================================ * ③ UI 库组件尺度控制(本版新增,解决「控件太小」) * ------------------------------------------------------------ * 与主题无关,因此三个选择器都要写(且必须用 :root[theme-mode=...] 这一 * 与 TDesign 同级权重的写法,否则会被 UI 库自身的深色变量盖掉): * 直接改 --td-size-* 会连带影响图标/徽标,所以只覆盖 --td-comp-* 一层。 * * 放大前后对照(TDesign 默认 → 本版): * 默认输入框/按钮/下拉 32px → 40px * 大号控件 40px → 48px * 小号控件 24px → 28px * 控件文字 14px → 16px(与正文同号,读起来不再「小一号」) * ============================================================ */ /* ============================================================ * 深色主题的中性色阶(补在主题块之外,便于与尺度控制放在一起) * ------------------------------------------------------------ * TDesign 在深色下使用「反向灰阶」(1 最深 → 14 最浅), * 不覆盖的话组件会退回 UI 库自带的冷灰,与本主题的蓝灰体系脱节。 * ============================================================ */ :root[theme-mode='dark'] { --td-gray-color-1: #0b0f18; --td-gray-color-2: #131926; --td-gray-color-3: #1b2333; --td-gray-color-4: #222c3f; --td-gray-color-5: #263147; --td-gray-color-6: #35415c; --td-gray-color-7: #4a5670; --td-gray-color-8: #6e7994; --td-gray-color-9: #8f9cb4; --td-gray-color-10: #b1bdd3; --td-gray-color-11: #ccd7e8; --td-gray-color-12: #e2e8f3; --td-gray-color-13: #eef2f9; --td-gray-color-14: #f4f6fb; } :root, :root[theme-mode='light'], :root[theme-mode='dark'] { /* ---------- 控件高度阶梯 ---------- */ --td-comp-size-xxxs: 18px; /* 复选框、小圆点 */ --td-comp-size-xxs: 24px; /* 小号控件(t-tag / 紧凑按钮) */ --td-comp-size-xs: 28px; --td-comp-size-s: 32px; --td-comp-size-m: 40px; /* ★ 默认控件:输入框 / 按钮 / 下拉 / 日期选择 */ --td-comp-size-l: 44px; --td-comp-size-xl: 48px; /* large 尺寸输入框、下拉触发框 */ --td-comp-size-xxl: 52px; --td-comp-size-xxxl: 60px; /* ---------- 控件内边距:随高度同步放宽,否则大控件里的文字会贴边 ---------- */ --td-comp-paddingTB-xxs: 4px; --td-comp-paddingTB-xs: 6px; --td-comp-paddingTB-s: 8px; --td-comp-paddingTB-m: 12px; --td-comp-paddingTB-l: 14px; --td-comp-paddingTB-xl: 20px; --td-comp-paddingLR-xxs: 6px; --td-comp-paddingLR-xs: 8px; --td-comp-paddingLR-s: 12px; --td-comp-paddingLR-m: 16px; --td-comp-paddingLR-l: 20px; --td-comp-paddingLR-xl: 28px; /* ---------- 字号:控件文字提到 16px,与正文同号 ---------- */ --td-font-size-body-small: 13px; --td-font-size-body-medium: 16px; --td-font-size-body-large: 17px; --td-font-size-title-small: 16px; --td-font-size-title-medium: 18px; --td-font-size-title-large: 20px; --td-font-size-link-small: 13px; --td-font-size-link-medium: 15px; --td-font-size-link-large: 17px; --td-font-size-mark-small: 13px; --td-font-size-mark-medium: 15px; /* ---------- 行高:必须与上面成对修改,否则大字号会被小行高挤住 ---------- */ --td-line-height-body-small: 22px; --td-line-height-body-medium: 24px; --td-line-height-body-large: 26px; --td-line-height-title-small: 24px; --td-line-height-title-medium: 28px; --td-line-height-title-large: 30px; --td-line-height-link-small: 22px; --td-line-height-link-medium: 24px; --td-line-height-link-large: 26px; --td-line-height-mark-small: 22px; --td-line-height-mark-medium: 24px; } /* ============================================================ * ④ 组件级微调(清晰蓝 · 卡片工作台) * ------------------------------------------------------------ * 一条贯穿全站的原则: * 内容容器(卡片/面板)→ 白底 + 细描边 + 轻投影,与页面底拉开层次 * 功能控件(输入框/按钮/下拉)→ 更实的描边 + 明确的聚焦反馈 * 本版与上一版最大的区别就在这里:卡片重新「有形」,不再是无框纸面。 * ============================================================ */ /* 卡片:轻投影 + 细描边;hover 时抬到第二档阴影 */ .t-card { border-radius: var(--tk-radius-xl); box-shadow: var(--tk-shadow-1); } .t-card--bordered { border-color: var(--tk-border); box-shadow: none; } .t-card--shadow { box-shadow: var(--tk-shadow-2); } .t-card__header { font-weight: 620; font-size: var(--tk-text-lg); letter-spacing: var(--tk-track-title); } .t-card__title { letter-spacing: var(--tk-track-title); } /* 卡片内边距放大一档;窄屏收回默认值,否则手机上内容可用宽度会不够 */ .t-card .t-card__body { padding: var(--tk-space-5) var(--tk-space-6); } /* 输入框 / 文本域:聚焦时用主色描边 + 柔和外发光 */ .t-input__wrap, .t-textarea__inner { transition: border-color var(--tk-dur-fast) var(--tk-ease-out), box-shadow var(--tk-dur-fast) var(--tk-ease-out); } .t-is-focused .t-input__wrap, .t-is-focused .t-textarea__inner { box-shadow: 0 0 0 3px var(--tk-accent-ring); } /* 按钮:按压时轻微下沉,补足 TDesign 缺失的触感反馈 */ .t-button:not(.t-is-disabled):active { transform: translateY(1px); } /* 下拉/选择器的选项行:默认行高偏挤,放大后一屏可见项变少但扫读更快 */ .t-select-option, .t-dropdown__item { font-size: var(--td-font-size-body-medium); } /* 弹层:统一使用较大的圆角与柔和阴影 */ .t-popup__content, .t-dialog, .t-drawer { border-radius: var(--tk-radius-xl); } .t-dialog__header { font-weight: 620; letter-spacing: var(--tk-track-title); } /* 窄屏:大内边距在手机上会挤掉内容宽度,这里整体收回到常规密度 */ @media (max-width: 767px) { .t-card .t-card__body { padding: var(--tk-space-4); } }