diff --git a/design/prototype/atoms.css b/design/prototype/atoms.css new file mode 100644 index 0000000..cbc0307 --- /dev/null +++ b/design/prototype/atoms.css @@ -0,0 +1,272 @@ +/* ============================================================= + 穿山甲 VPN · Pangolin VPN — Prototype Atoms + design/prototype/atoms.css + ------------------------------------------------------------- + 本文件是「原型公用组件原子层」的唯一真相源(single source)。 + canonical CSS 原子类,沉淀自 design/preview/*.html 组件规格、 + web/usercenter/components/shared.tsx、web/website/src/styles/website.css + 与 client/lib/widgets/*.dart 的交互态语义。 + + 铁律(写/改本文件必守,对齐 design/CLAUDE.md §1): + 1. 颜色 / 圆角 / 间距 / 字号 / 阴影 / 字体 一律走 var(--token) + (token 定义在 tokens.css)。禁任何硬编码 hex / rgb / 魔法数。 + 2. 明暗双主题「自动」适配:原子类只引语义 token(--surface / --fg1 …), + 主题切换由 tokens.css 的 [data-theme="dark"] 负责—— + 本文件里不写任何 [data-theme] 分支。 + 3. 暖大地色 · 大圆角(按钮全胶囊 radius-full / 卡片 lg–xl / 输入 md)· + 柔和暖阴影 · 状态用「色点 + 文字胶囊」非 emoji。 + 4. 交互态语义:hover 主色加深一档 · press 缩放 .97 · focus clay 光环 + (shadow-focus)· disabled sand-200 底 + sand-400 字。 + 5. 每新增一个原子,须在 design/prototype/index.html 登记(登记簿单源)。 + + 使用前先在页面
引入:tokens.css(令牌)+ 本文件(原子)。 + ============================================================= */ + + +/* ============================================================= + BUTTONS · .btn + variants + 全胶囊圆角 · hover 加深 · press 收缩 .97 · focus clay 光环 + 变体:.btn-primary(实心 clay) · .btn-ghost(描边/幽灵) · + .btn-subtle(次要描边) · .btn-danger · 尺寸 .btn-lg · .btn-icon + ============================================================= */ +.btn { + display: inline-flex; + align-items: center; + justify-content: center; + gap: var(--space-2); + font-family: var(--font-sans); + font-weight: 600; + font-size: var(--text-sm); + line-height: 1; + border: none; + border-radius: var(--radius-full); + padding: var(--space-3) var(--space-5); + cursor: pointer; + white-space: nowrap; + transition: background-color var(--dur-fast) var(--ease-out), + color var(--dur-fast) var(--ease-out), + border-color var(--dur-fast) var(--ease-out), + transform var(--dur-fast) var(--ease-out), + box-shadow var(--dur-fast) var(--ease-out); +} +.btn > svg { width: 16px; height: 16px; flex-shrink: 0; } +.btn:focus-visible { + outline: none; + box-shadow: var(--shadow-focus); +} +.btn:active { transform: scale(0.97); } +.btn:disabled, +.btn.is-disabled { + background: var(--sand-200); + color: var(--sand-400); + cursor: not-allowed; + transform: none; + box-shadow: none; + border-color: transparent; +} + +/* Primary — 实心黏土铜 */ +.btn-primary { background: var(--accent); color: var(--fg-on-accent); } +.btn-primary:hover { background: var(--accent-hover); } +.btn-primary:active { background: var(--accent-press); } + +/* Ghost — 透明底、clay 字,hover 上 accent-subtle */ +.btn-ghost { background: transparent; color: var(--accent); } +.btn-ghost:hover { background: var(--accent-subtle); } + +/* Subtle — surface 底 + 强描边(次要动作) */ +.btn-subtle { + background: var(--surface); + color: var(--fg1); + border: 1.5px solid var(--border-strong); +} +.btn-subtle:hover { border-color: var(--accent); color: var(--accent); } + +/* Danger — 危险动作(断开 / 移除设备) */ +.btn-danger { background: var(--danger-subtle); color: var(--red-600); } +.btn-danger:hover { background: var(--danger); color: var(--fg-on-accent); } + +/* 尺寸 / 形态修饰 */ +.btn-lg { padding: var(--space-4) var(--space-6); font-size: var(--text-body); } +.btn-icon { padding: var(--space-3); } /* 正方形图标按钮(配 radius-full 成圆) */ +.btn-block { width: 100%; } + + +/* ============================================================= + CARD · .card + surface 底 + border + radius-xl + shadow-sm + ============================================================= */ +.card { + background: var(--surface); + border: 1px solid var(--border); + border-radius: var(--radius-xl); + box-shadow: var(--shadow-sm); + padding: var(--space-5); +} +.card-flush { padding: 0; } /* 列表容器(server-row 组)用,内容自带 padding */ + + +/* ============================================================= + INPUT · .input (+ .field / .flabel) + 强描边 + radius-md + focus clay 光环 + ============================================================= */ +.field { display: block; } +.flabel { + display: block; + font-family: var(--font-sans); + font-size: var(--text-caption); + font-weight: 600; + color: var(--fg2); + margin-bottom: var(--space-2); +} +.input { + width: 100%; + box-sizing: border-box; + font-family: var(--font-sans); + font-size: var(--text-sm); + color: var(--fg1); + background: var(--surface); + border: 1.5px solid var(--border-strong); + border-radius: var(--radius-md); + padding: var(--space-3) var(--space-4); + transition: border-color var(--dur-fast) var(--ease-out), + box-shadow var(--dur-fast) var(--ease-out); +} +.input::placeholder { color: var(--fg3); } +.input:focus, +.input.is-focused { + outline: none; + border-color: var(--accent); + box-shadow: var(--shadow-focus); +} +.input:disabled { + background: var(--bg-subtle); + color: var(--fg3); + cursor: not-allowed; +} +.input.is-error { border-color: var(--danger); } +.input.is-error:focus { box-shadow: 0 0 0 4px var(--danger-subtle); } + + +/* ============================================================= + BADGE / PILL · .pill (+ status modifiers) + 状态胶囊:色点 + 文字(非 emoji)。全胶囊圆角。 + 状态:.is-success / .is-warning / .is-danger / .is-neutral + 变体:.pill-accent(实心 clay,如 PRO) · .pill-outline(accent 描边,如节点属性) + ============================================================= */ +.pill { + display: inline-flex; + align-items: center; + gap: var(--space-2); + font-family: var(--font-sans); + font-size: var(--text-caption); + font-weight: 600; + line-height: 1; + padding: var(--space-2) var(--space-3); + border-radius: var(--radius-full); + background: var(--sand-100); + color: var(--fg2); +} +.pill .dot { + width: 7px; + height: 7px; + border-radius: var(--radius-full); + background: var(--sand-400); + flex-shrink: 0; +} +/* alias:.badge === .pill(语义等价,命名习惯不同) */ +.badge { } + +.pill.is-success { background: var(--success-subtle); color: var(--green-600); } +.pill.is-success .dot { background: var(--success); } +.pill.is-warning { background: var(--warning-subtle); color: var(--amber-600); } +.pill.is-warning .dot { background: var(--warning); } +.pill.is-danger { background: var(--danger-subtle); color: var(--red-600); } +.pill.is-danger .dot { background: var(--danger); } +.pill.is-neutral { background: var(--sand-100); color: var(--fg2); } +.pill.is-neutral .dot { background: var(--sand-400); } + +/* 实心 accent(PRO 会员等强调标签) */ +.pill-accent { background: var(--accent); color: var(--fg-on-accent); } +/* accent 描边(节点属性:流媒体 / P2P 等) */ +.pill-outline { + background: var(--accent-subtle); + color: var(--accent); + border: 1px solid var(--accent-border); +} + + +/* ============================================================= + LANGUAGE SELECT · .langsel (触发药丸) + .menu (绝对定位菜单) + 对齐 usercenter shared.tsx::LangSeg / website 的自定义下拉: + 不依赖原生