sideby 0.0.0-stage → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +111 -2
- package/README.zh-CN.md +112 -0
- package/dist/build.json +1 -0
- package/dist/src/cli/args.d.ts +13 -0
- package/dist/src/cli/args.js +38 -0
- package/dist/src/cli/commands.d.ts +50 -0
- package/dist/src/cli/commands.js +566 -0
- package/dist/src/cli/format.d.ts +16 -0
- package/dist/src/cli/format.js +80 -0
- package/dist/src/cli/json-schemas.d.ts +2 -0
- package/dist/src/cli/json-schemas.js +259 -0
- package/dist/src/cli/main.d.ts +2 -0
- package/dist/src/cli/main.js +276 -0
- package/dist/src/cli/schemas.d.ts +1 -0
- package/dist/src/cli/schemas.js +16 -0
- package/dist/src/core/account-name.d.ts +2 -0
- package/dist/src/core/account-name.js +2 -0
- package/dist/src/core/accounts.d.ts +20 -0
- package/dist/src/core/accounts.js +131 -0
- package/dist/src/core/config.d.ts +61 -0
- package/dist/src/core/config.js +184 -0
- package/dist/src/core/create.d.ts +30 -0
- package/dist/src/core/create.js +126 -0
- package/dist/src/core/doctor.d.ts +41 -0
- package/dist/src/core/doctor.js +171 -0
- package/dist/src/core/errors.d.ts +12 -0
- package/dist/src/core/errors.js +14 -0
- package/dist/src/core/file-memo.d.ts +24 -0
- package/dist/src/core/file-memo.js +41 -0
- package/dist/src/core/fs-safe.d.ts +38 -0
- package/dist/src/core/fs-safe.js +205 -0
- package/dist/src/core/handoff.d.ts +41 -0
- package/dist/src/core/handoff.js +54 -0
- package/dist/src/core/identity.d.ts +23 -0
- package/dist/src/core/identity.js +79 -0
- package/dist/src/core/last-doctor.d.ts +36 -0
- package/dist/src/core/last-doctor.js +69 -0
- package/dist/src/core/launch.d.ts +37 -0
- package/dist/src/core/launch.js +108 -0
- package/dist/src/core/login-path.d.ts +23 -0
- package/dist/src/core/login-path.js +96 -0
- package/dist/src/core/paths.d.ts +13 -0
- package/dist/src/core/paths.js +32 -0
- package/dist/src/core/quota-levels.d.ts +19 -0
- package/dist/src/core/quota-levels.js +34 -0
- package/dist/src/core/resume.d.ts +9 -0
- package/dist/src/core/resume.js +15 -0
- package/dist/src/core/secret-file.d.ts +30 -0
- package/dist/src/core/secret-file.js +116 -0
- package/dist/src/core/share-meaning.d.ts +6 -0
- package/dist/src/core/share-meaning.js +32 -0
- package/dist/src/core/share-mode-names.d.ts +1 -0
- package/dist/src/core/share-mode-names.js +10 -0
- package/dist/src/core/share-modes.d.ts +24 -0
- package/dist/src/core/share-modes.js +405 -0
- package/dist/src/core/shell-init.d.ts +31 -0
- package/dist/src/core/shell-init.js +84 -0
- package/dist/src/core/skill-check.d.ts +11 -0
- package/dist/src/core/skill-check.js +57 -0
- package/dist/src/core/usage-days.d.ts +15 -0
- package/dist/src/core/usage-days.js +33 -0
- package/dist/src/core/version.d.ts +9 -0
- package/dist/src/core/version.js +46 -0
- package/dist/src/desktop/app.d.ts +60 -0
- package/dist/src/desktop/app.js +316 -0
- package/dist/src/desktop/icon.d.ts +16 -0
- package/dist/src/desktop/icon.js +174 -0
- package/dist/src/families/claude/index.d.ts +10 -0
- package/dist/src/families/claude/index.js +127 -0
- package/dist/src/families/claude/layout.d.ts +6 -0
- package/dist/src/families/claude/layout.js +5 -0
- package/dist/src/families/claude/quota-cache.d.ts +31 -0
- package/dist/src/families/claude/quota-cache.js +111 -0
- package/dist/src/families/claude/quota.d.ts +3 -0
- package/dist/src/families/claude/quota.js +53 -0
- package/dist/src/families/claude/usage.d.ts +22 -0
- package/dist/src/families/claude/usage.js +146 -0
- package/dist/src/families/codex/index.d.ts +5 -0
- package/dist/src/families/codex/index.js +70 -0
- package/dist/src/families/codex/rollout.d.ts +67 -0
- package/dist/src/families/codex/rollout.js +298 -0
- package/dist/src/families/grok/index.d.ts +8 -0
- package/dist/src/families/grok/index.js +82 -0
- package/dist/src/families/index.d.ts +3 -0
- package/dist/src/families/index.js +40 -0
- package/dist/src/families/logos.d.ts +21 -0
- package/dist/src/families/logos.js +26 -0
- package/dist/src/families/pi/index.d.ts +3 -0
- package/dist/src/families/pi/index.js +54 -0
- package/dist/src/families/shared/sessions.d.ts +9 -0
- package/dist/src/families/shared/sessions.js +70 -0
- package/dist/src/families/shared/toml.d.ts +5 -0
- package/dist/src/families/shared/toml.js +16 -0
- package/dist/src/index.d.ts +5 -0
- package/dist/src/index.js +4 -0
- package/dist/src/panel/background.d.ts +62 -0
- package/dist/src/panel/background.js +274 -0
- package/dist/src/panel/handler.d.ts +91 -0
- package/dist/src/panel/handler.js +396 -0
- package/dist/src/panel/i18n.d.ts +287 -0
- package/dist/src/panel/i18n.js +570 -0
- package/dist/src/panel/page-logic.d.ts +154 -0
- package/dist/src/panel/page-logic.js +326 -0
- package/dist/src/panel/page-script.d.ts +2 -0
- package/dist/src/panel/page-script.js +1633 -0
- package/dist/src/panel/page-styles.d.ts +7 -0
- package/dist/src/panel/page-styles.js +514 -0
- package/dist/src/panel/page.d.ts +20 -0
- package/dist/src/panel/page.js +96 -0
- package/dist/src/panel/server.d.ts +32 -0
- package/dist/src/panel/server.js +133 -0
- package/dist/src/panel/theme.d.ts +116 -0
- package/dist/src/panel/theme.js +132 -0
- package/dist/src/plugins/account-script.d.ts +4 -0
- package/dist/src/plugins/account-script.js +66 -0
- package/dist/src/plugins/bus.d.ts +33 -0
- package/dist/src/plugins/bus.js +84 -0
- package/dist/src/plugins/loader.d.ts +58 -0
- package/dist/src/plugins/loader.js +250 -0
- package/dist/src/quota/claude-statusline.d.ts +28 -0
- package/dist/src/quota/claude-statusline.js +301 -0
- package/dist/src/quota/statusline-tap.d.ts +11 -0
- package/dist/src/quota/statusline-tap.js +104 -0
- package/dist/src/runtime.d.ts +195 -0
- package/dist/src/runtime.js +424 -0
- package/dist/src/types.d.ts +285 -0
- package/dist/src/types.js +3 -0
- package/dist/testing/demo.d.ts +8 -0
- package/dist/testing/demo.js +50 -0
- package/dist/testing/index.d.ts +36 -0
- package/dist/testing/index.js +118 -0
- package/package.json +66 -4
- package/schemas/alias.json +102 -0
- package/schemas/app-install.json +74 -0
- package/schemas/app-uninstall.json +54 -0
- package/schemas/config.json +170 -0
- package/schemas/doctor.json +229 -0
- package/schemas/error.json +25 -0
- package/schemas/families.json +205 -0
- package/schemas/list.json +177 -0
- package/schemas/new.json +199 -0
- package/schemas/next.json +127 -0
- package/schemas/plugins.json +74 -0
- package/schemas/quota-setup.json +60 -0
- package/schemas/quota-teardown.json +30 -0
- package/schemas/quota.json +203 -0
- package/skills/sideby/SKILL.md +61 -0
- package/skills/sideby/references/accounts.md +31 -0
- package/skills/sideby/references/diagnose.md +47 -0
- package/skills/sideby/references/handoff.md +41 -0
- package/skills/sideby/references/quota.md +14 -0
- package/skills/sideby/references/setup.md +31 -0
- package/skills/sideby/references/sharing.md +17 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type ResolvedTheme } from './theme.ts';
|
|
2
|
+
/**
|
|
3
|
+
* The page's style block: default tokens, the host's tokens over them, then the rules that read them. With
|
|
4
|
+
* `colorScheme: 'auto'` the page follows the system unless the viewer picked light or dark in the Panel, which sets
|
|
5
|
+
* `data-theme` on the root element.
|
|
6
|
+
*/
|
|
7
|
+
export declare function pageStyles(theme?: ResolvedTheme): string;
|
|
@@ -0,0 +1,514 @@
|
|
|
1
|
+
// The Panel page's styles: design tokens (a host theme layers its values over them, see theme.ts) and the rules
|
|
2
|
+
// that read them. Every color, radius and size below comes from a token, so a host theme reaches every component.
|
|
3
|
+
import { resolveTheme } from './theme.js';
|
|
4
|
+
// Colors defined from other tokens; repeated in both schemes so they follow that scheme's base colors.
|
|
5
|
+
const DERIVED_COLORS = `
|
|
6
|
+
--primary-border: var(--primary); --primary-hover-border: var(--primary-hover); --btn-text: var(--text);
|
|
7
|
+
--btn-hover-border: var(--border-strong); --btn-hover-text: var(--text); --check: var(--primary);
|
|
8
|
+
--logo-bg: var(--text); --logo-fg: var(--bg); --logo-line: transparent;
|
|
9
|
+
--focus-outline: 2px solid var(--focus); --focus-ring: none;`;
|
|
10
|
+
// Design tokens. A host theme (theme.ts) layers its values over these: light values after LIGHT_TOKENS, dark values after
|
|
11
|
+
// DARK_TOKENS. DARK_TOKENS sets every color token again, so a host's light colors never leak into dark mode, while
|
|
12
|
+
// type, shape and layout tokens are shared by both schemes.
|
|
13
|
+
const LIGHT_TOKENS = `
|
|
14
|
+
--font: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif; --mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
|
15
|
+
--font-size: 14px; --small: 12.5px; --control-size: 13.5px; --heading-size: 15px; --large: 16px; --title-size: 22px;
|
|
16
|
+
--title-weight: 750; --heading-weight: 650; --strong-weight: 600; --button-weight: 600; --primary-weight: var(--button-weight);
|
|
17
|
+
--radius: 14px; --ctl-radius: 8px; --chip-radius: 999px; --ctl-h: 34px; --ctl-h-sm: 28px; --field-h: 36px;
|
|
18
|
+
--content-width: 1180px; --gutter: 24px;
|
|
19
|
+
--bg: #f5f6f8; --surface: #ffffff; --surface-2: #f0f2f5; --border: #e2e5ea; --border-strong: #cfd4dc;
|
|
20
|
+
--text: #15171c; --muted: #5b6372; --faint: #8b93a1; --accent: #4f46e5; --accent-soft: #eef0ff;
|
|
21
|
+
--primary: #4f46e5; --primary-hover: #4338ca; --primary-active: #3730a3; --on-primary: #ffffff;
|
|
22
|
+
--hover: #eceef2; --active: #e2e5ea; --focus: #6366f1;
|
|
23
|
+
--ok: #15803d; --ok-bar: #22c55e; --ok-soft: #e8f7ee; --warn: #b45309; --warn-bar: #f59e0b; --warn-soft: #fdf3e2;
|
|
24
|
+
--fail: #c81e1e; --fail-bar: #ef4444; --fail-soft: #fdecec; --track: #e9ecf1;
|
|
25
|
+
--spark: oklch(from var(--accent) clamp(0.55, l, 0.62) max(c, 0.14) h); --spark-soft: oklch(from var(--accent) 0.83 calc(max(c, 0.14) * 0.6) h);
|
|
26
|
+
--shadow: 0 1px 2px rgba(16,24,40,.04), 0 2px 8px rgba(16,24,40,.05);
|
|
27
|
+
--float-shadow: 0 10px 30px rgba(16,24,40,.14), 0 2px 6px rgba(16,24,40,.06);${DERIVED_COLORS}`;
|
|
28
|
+
const DARK_TOKENS = `
|
|
29
|
+
--bg: #0d0f12; --surface: #15181d; --surface-2: #1c2026; --border: #262b33; --border-strong: #353c47;
|
|
30
|
+
--text: #e7e9ee; --muted: #a0a8b5; --faint: #6c7480; --accent: #8b87ff; --accent-soft: #23224a;
|
|
31
|
+
--primary: #5b54e8; --primary-hover: #6a64ef; --primary-active: #4f46e5; --on-primary: #ffffff;
|
|
32
|
+
--hover: #22272e; --active: #2a3038; --focus: #8b87ff;
|
|
33
|
+
--ok: #4ade80; --ok-bar: #22c55e; --ok-soft: #13291c; --warn: #fbbf24; --warn-bar: #f59e0b; --warn-soft: #2d2410;
|
|
34
|
+
--fail: #f87171; --fail-bar: #ef4444; --fail-soft: #331717; --track: #252a32;
|
|
35
|
+
--spark: oklch(from var(--accent) clamp(0.7, l, 0.78) max(c, 0.14) h); --spark-soft: oklch(from var(--accent) 0.45 calc(max(c, 0.14) * 0.6) h);
|
|
36
|
+
--shadow: 0 1px 2px rgba(0,0,0,.3); --float-shadow: 0 12px 32px rgba(0,0,0,.5), 0 2px 6px rgba(0,0,0,.3);${DERIVED_COLORS}`;
|
|
37
|
+
/**
|
|
38
|
+
* The page's style block: default tokens, the host's tokens over them, then the rules that read them. With
|
|
39
|
+
* `colorScheme: 'auto'` the page follows the system unless the viewer picked light or dark in the Panel, which sets
|
|
40
|
+
* `data-theme` on the root element.
|
|
41
|
+
*/
|
|
42
|
+
export function pageStyles(theme = resolveTheme(undefined)) {
|
|
43
|
+
const rule = (decls, sel = ':root') => (decls.length ? `${sel} { ${decls.join('; ')}; }\n` : '');
|
|
44
|
+
const scheme = theme.colorScheme === 'auto' ? 'light dark' : theme.colorScheme;
|
|
45
|
+
let css = `:root {${LIGHT_TOKENS}\n color-scheme: ${scheme};\n}\n${rule(theme.light)}`;
|
|
46
|
+
if (theme.colorScheme === 'auto') {
|
|
47
|
+
const sel = ':root:not([data-theme=light])';
|
|
48
|
+
css += `@media (prefers-color-scheme: dark) {\n${sel} {${DARK_TOKENS}\n}\n${rule(theme.dark, sel)}}\n`;
|
|
49
|
+
css += `:root[data-theme=dark] {${DARK_TOKENS}\n color-scheme: dark;\n}\n${rule(theme.dark, ':root[data-theme=dark]')}`;
|
|
50
|
+
css += ':root[data-theme=light] { color-scheme: light; }\n';
|
|
51
|
+
}
|
|
52
|
+
else if (theme.colorScheme === 'dark')
|
|
53
|
+
css += `:root {${DARK_TOKENS}\n}\n${rule(theme.dark)}`;
|
|
54
|
+
return css + CSS;
|
|
55
|
+
}
|
|
56
|
+
const CSS = `
|
|
57
|
+
* { box-sizing: border-box; }
|
|
58
|
+
html { -webkit-text-size-adjust: 100%; }
|
|
59
|
+
body { margin: 0; background: var(--bg); color: var(--text); font: var(--font-size)/1.5 var(--font); font-variant-numeric: tabular-nums; }
|
|
60
|
+
[hidden] { display: none !important; }
|
|
61
|
+
.top-in, .wrap { max-width: var(--content-width); margin: 0 auto; }
|
|
62
|
+
.top-in { display: flex; align-items: center; justify-content: space-between; gap: 16px; padding: 28px var(--gutter) 0; }
|
|
63
|
+
.wrap { padding: 20px var(--gutter) 40px; }
|
|
64
|
+
.header-bar .top { background: var(--surface); border-bottom: 1px solid var(--border); }
|
|
65
|
+
.header-bar .top-in { min-height: 84px; padding: 14px var(--gutter); }
|
|
66
|
+
.header-bar .wrap { padding-top: 20px; }
|
|
67
|
+
h1, h2, h3 { margin: 0; letter-spacing: -0.01em; }
|
|
68
|
+
h2 { font-size: var(--heading-size); font-weight: var(--heading-weight); }
|
|
69
|
+
b, strong { font-weight: var(--strong-weight); }
|
|
70
|
+
p { margin: 0; }
|
|
71
|
+
a { color: var(--accent); text-decoration: none; }
|
|
72
|
+
a:hover { text-decoration: underline; }
|
|
73
|
+
code, .mono { font-family: var(--mono); font-size: 0.92em; }
|
|
74
|
+
.muted { color: var(--muted); }
|
|
75
|
+
.faint { color: var(--faint); }
|
|
76
|
+
.small { font-size: var(--small); }
|
|
77
|
+
.sr-only { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
|
|
78
|
+
.sep { color: var(--faint); margin: 0 6px; }
|
|
79
|
+
.brand { display: flex; align-items: center; gap: 12px; min-width: 0; }
|
|
80
|
+
.brand h1 { font-size: var(--title-size); font-weight: var(--title-weight); line-height: 1.3; letter-spacing: -0.02em; }
|
|
81
|
+
.tagline { color: var(--muted); font-size: 13px; }
|
|
82
|
+
.logo { display: inline-flex; flex: none; width: 40px; height: 40px; border-radius: 10px; background: var(--logo-bg); box-shadow: inset 0 0 0 1px var(--logo-line); }
|
|
83
|
+
/* desktop/icon.ts draws the same two half discs for the app icon. */
|
|
84
|
+
.logo svg { display: block; width: 100%; height: 100%; fill: var(--logo-fg); }
|
|
85
|
+
.top-actions { display: flex; align-items: center; gap: 8px; }
|
|
86
|
+
.section-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 12px; flex-wrap: wrap; }
|
|
87
|
+
.section-head > div:first-child { min-width: 0; }
|
|
88
|
+
.block { margin-bottom: 22px; }
|
|
89
|
+
.ic { width: 15px; height: 15px; flex: none; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
|
|
90
|
+
|
|
91
|
+
/* Summary: four quiet numbers in one surface. */
|
|
92
|
+
.summary { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); box-shadow: var(--shadow); margin-bottom: 18px; overflow: hidden; }
|
|
93
|
+
.stat { display: flex; align-items: flex-end; justify-content: space-between; gap: 10px; min-width: 0; padding: 14px 18px; border-left: 1px solid var(--border); text-align: left; }
|
|
94
|
+
.stat:first-child { border-left: 0; }
|
|
95
|
+
.stat-text { min-width: 0; }
|
|
96
|
+
.stat-label { color: var(--muted); font-size: var(--small); display: flex; align-items: center; gap: 6px; }
|
|
97
|
+
.stat-value { font-size: 22px; font-weight: var(--heading-weight); letter-spacing: -0.02em; line-height: 1.35; white-space: nowrap; }
|
|
98
|
+
.stat-sub { color: var(--faint); font-size: 12px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
|
99
|
+
.stat-btn { font: inherit; color: inherit; background: none; border: 0; border-left: 1px solid var(--border); cursor: pointer; transition: background-color .12s; }
|
|
100
|
+
.stat-btn:hover { background: var(--hover); }
|
|
101
|
+
.stat-btn[aria-pressed=true] { background: var(--warn-soft); }
|
|
102
|
+
.stat-warn .stat-value { color: var(--warn); }
|
|
103
|
+
.stat-ok .stat-value { color: var(--ok); }
|
|
104
|
+
.label-tip { display: inline-flex; align-items: center; gap: 6px; }
|
|
105
|
+
|
|
106
|
+
/* Toolbar */
|
|
107
|
+
.toolbar { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-bottom: 12px; }
|
|
108
|
+
.search { position: relative; flex: 1 1 240px; min-width: 0; display: block; }
|
|
109
|
+
.search-ic { position: absolute; left: 11px; top: 50%; transform: translateY(-50%); color: var(--faint); pointer-events: none; }
|
|
110
|
+
.search .search-input { padding-left: 34px; padding-right: 34px; height: var(--ctl-h); }
|
|
111
|
+
.kbd { position: absolute; right: 9px; top: 50%; transform: translateY(-50%); font: 11px/16px var(--mono); color: var(--faint); border: 1px solid var(--border); border-radius: 4px; padding: 0 5px; pointer-events: none; }
|
|
112
|
+
.search:focus-within .kbd, .search input:not(:placeholder-shown) ~ .kbd { display: none; }
|
|
113
|
+
.tools { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
|
|
114
|
+
.tb-select { width: auto; height: var(--ctl-h); font-size: var(--control-size); }
|
|
115
|
+
.seg { display: inline-flex; align-items: center; gap: 2px; height: var(--ctl-h); padding: 2px; border: 1px solid var(--border-strong); border-radius: var(--ctl-radius); background: var(--surface); }
|
|
116
|
+
.seg-btn { display: inline-flex; align-items: center; gap: 5px; height: 100%; padding: 0 10px; border: 0; border-radius: calc(var(--ctl-radius) - 2px); background: transparent; color: var(--muted); font: inherit; font-size: var(--control-size); cursor: pointer; }
|
|
117
|
+
.seg-btn:hover { color: var(--text); }
|
|
118
|
+
.seg-btn[aria-pressed=true] { background: var(--active); color: var(--text); font-weight: var(--strong-weight); }
|
|
119
|
+
.seg-btn:focus-visible { outline: var(--focus-outline); outline-offset: 1px; box-shadow: var(--focus-ring); }
|
|
120
|
+
.acct-head { margin-bottom: 10px; }
|
|
121
|
+
.acct-head h2 { display: flex; align-items: baseline; gap: 10px; }
|
|
122
|
+
#acct-count { font-weight: 400; }
|
|
123
|
+
|
|
124
|
+
/* Family groups */
|
|
125
|
+
.group { margin-bottom: 14px; min-width: 0; }
|
|
126
|
+
.group-list { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); box-shadow: var(--shadow); }
|
|
127
|
+
.group-head { display: flex; align-items: center; gap: 10px; padding: 8px 12px 8px 8px; min-height: 48px; flex-wrap: wrap; }
|
|
128
|
+
.group-cards .group-head { padding: 0 0 8px; min-height: 0; }
|
|
129
|
+
.group-toggle { display: inline-flex; align-items: center; gap: 9px; min-width: 0; padding: 5px 8px 5px 4px; border: 0; border-radius: var(--ctl-radius); background: none; color: var(--text); font: inherit; cursor: pointer; }
|
|
130
|
+
.group-toggle:hover { background: var(--hover); }
|
|
131
|
+
.group-toggle:focus-visible { outline: var(--focus-outline); outline-offset: 1px; box-shadow: var(--focus-ring); }
|
|
132
|
+
.chev { color: var(--faint); transition: transform .15s; }
|
|
133
|
+
.group-toggle[aria-expanded=true] .chev { transform: rotate(90deg); }
|
|
134
|
+
.group-title { font-weight: var(--heading-weight); font-size: var(--heading-size); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
|
135
|
+
.group-count { color: var(--muted); font-size: 12px; background: var(--surface-2); border-radius: var(--chip-radius); padding: 0 8px; line-height: 20px; }
|
|
136
|
+
.group-meta { margin-left: auto; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
|
|
137
|
+
.group-quota { display: inline-flex; align-items: center; gap: 8px; flex-wrap: wrap; justify-content: flex-end; }
|
|
138
|
+
|
|
139
|
+
/* List rows: identity, one column per quota window, usage, last used, health, menu. Every column but the first has a
|
|
140
|
+
fixed width, so the rows of all groups line up under the same column titles. --qn is the number of quota
|
|
141
|
+
columns; the page sets it on #accounts. */
|
|
142
|
+
#accounts { --qn: 2; --q-w: 148px; --u-w: 168px; --l-w: 82px; --h-w: 112px; --m-w: 28px; --col-gap: 20px; }
|
|
143
|
+
.row, .col-head { display: grid; grid-template-columns: minmax(0, 1fr) calc(var(--qn) * var(--q-w) + (var(--qn) - 1) * var(--col-gap)) var(--u-w) var(--l-w) var(--h-w) var(--m-w); column-gap: var(--col-gap); align-items: center; min-width: 0; }
|
|
144
|
+
.row { grid-template-areas: "id quota usage last health more" "notes notes notes notes notes notes"; padding: 11px 10px 11px 16px; border-top: 1px solid var(--border); transition: background-color .12s; }
|
|
145
|
+
.rows .row:hover { background: color-mix(in srgb, var(--hover) 55%, transparent); }
|
|
146
|
+
.row:first-child { border-top: 0; }
|
|
147
|
+
.row:last-child { border-radius: 0 0 var(--radius) var(--radius); }
|
|
148
|
+
.row-error .ident-name .name { color: var(--fail); }
|
|
149
|
+
.col-head { position: sticky; top: 0; z-index: 2; padding: 7px 10px 7px 16px; border-top: 1px solid var(--border); background: var(--surface); color: var(--faint); font-size: 11.5px; font-weight: var(--strong-weight); line-height: 1.3; white-space: nowrap; }
|
|
150
|
+
.col-head > span { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
|
|
151
|
+
.col-head .quota > span { overflow: hidden; text-overflow: ellipsis; }
|
|
152
|
+
.ident { grid-area: id; display: flex; align-items: center; gap: 10px; min-width: 0; }
|
|
153
|
+
.ident-text { min-width: 0; flex: 1; }
|
|
154
|
+
.ident-name { display: flex; align-items: center; gap: 6px; min-width: 0; flex-wrap: wrap; row-gap: 3px; }
|
|
155
|
+
.ident-name .name { font-weight: var(--strong-weight); font-size: var(--font-size); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 100%; }
|
|
156
|
+
.ident-email { color: var(--muted); font-size: 12px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; margin-top: 1px; }
|
|
157
|
+
.ident-email + .ident-sub { color: var(--faint); margin-top: 0; }
|
|
158
|
+
.tools .tb-icon { width: var(--ctl-h); height: var(--ctl-h); border-color: var(--border-strong); background: var(--surface); }
|
|
159
|
+
.tools .tb-icon:hover { background: var(--hover); }
|
|
160
|
+
.tools .tb-icon[aria-pressed=true] { background: var(--active); color: var(--text); }
|
|
161
|
+
.ident-sub { color: var(--muted); font-size: 12px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; margin-top: 1px; }
|
|
162
|
+
.plan { text-transform: capitalize; }
|
|
163
|
+
.row > .quota { grid-area: quota; }
|
|
164
|
+
.row > .usage { grid-area: usage; }
|
|
165
|
+
.row > .last { grid-area: last; }
|
|
166
|
+
.cell-health { grid-area: health; min-width: 0; }
|
|
167
|
+
.row > .more { grid-area: more; }
|
|
168
|
+
.row-notes { grid-area: notes; display: flex; flex-direction: column; gap: 6px; margin-top: 8px; }
|
|
169
|
+
|
|
170
|
+
/* Quota meters: percent and countdown over a bar colored by level (ok, warn at 60%, fail at 85% used). */
|
|
171
|
+
.quota { display: grid; grid-template-columns: repeat(var(--qn), minmax(0, 1fr)); column-gap: var(--col-gap); row-gap: 4px; min-width: 0; }
|
|
172
|
+
.row > .quota { grid-template-columns: repeat(var(--qn), var(--q-w)); }
|
|
173
|
+
.meter { min-width: 0; }
|
|
174
|
+
.m-top { display: flex; align-items: baseline; gap: 6px; font-size: 12px; line-height: 1.35; white-space: nowrap; min-width: 0; }
|
|
175
|
+
.m-label { color: var(--muted); font-weight: var(--strong-weight); }
|
|
176
|
+
.m-pct { font-weight: var(--strong-weight); font-size: 13px; font-variant-numeric: tabular-nums; }
|
|
177
|
+
.m-unit { color: var(--faint); font-weight: 400; font-size: 11.5px; }
|
|
178
|
+
.m-reset { margin-left: auto; color: var(--faint); font-size: 11.5px; font-variant-numeric: tabular-nums; overflow: hidden; text-overflow: ellipsis; }
|
|
179
|
+
.m-passed { font-style: italic; }
|
|
180
|
+
.m-none { color: var(--faint); }
|
|
181
|
+
.bar { height: 6px; border-radius: 999px; background: var(--track); overflow: hidden; margin-top: 5px; }
|
|
182
|
+
.bar > span { display: block; height: 100%; min-width: 0; border-radius: inherit; background: var(--ok-bar); transition: width .4s ease; }
|
|
183
|
+
.lvl-warn .bar > span { background: var(--warn-bar); } .lvl-warn .m-pct { color: var(--warn); }
|
|
184
|
+
.lvl-fail .bar > span { background: var(--fail-bar); } .lvl-fail .m-pct { color: var(--fail); }
|
|
185
|
+
.lvl-reset .m-pct { color: var(--muted); }
|
|
186
|
+
.lvl-stale.lvl-ok .m-pct { color: var(--muted); }
|
|
187
|
+
.is-stale .bar > span, .lvl-stale .bar > span { background: var(--faint); opacity: .5; }
|
|
188
|
+
.q-asof { grid-column: 1 / -1; display: flex; align-items: center; gap: 4px; color: var(--faint); font-size: 11.5px; line-height: 1.3; }
|
|
189
|
+
.q-asof .ic { width: 12px; height: 12px; }
|
|
190
|
+
.q-note { grid-column: 1 / -1; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; color: var(--muted); font-size: var(--small); }
|
|
191
|
+
.link-btn { padding: 0; border: 0; background: none; color: var(--accent); font: inherit; font-weight: var(--strong-weight); cursor: pointer; }
|
|
192
|
+
.link-btn:hover:not(:disabled) { text-decoration: underline; }
|
|
193
|
+
.link-btn:disabled { color: var(--faint); cursor: not-allowed; }
|
|
194
|
+
.link-btn:focus-visible { outline: var(--focus-outline); outline-offset: 2px; border-radius: 3px; }
|
|
195
|
+
|
|
196
|
+
/* Usage: total over cache hits, with the 7 day bars beside both lines. In the wide list the bars sit at the column's
|
|
197
|
+
right edge, so they line up down the column whatever the totals. */
|
|
198
|
+
.usage { display: flex; align-items: center; gap: 12px; min-width: 0; }
|
|
199
|
+
.rows .usage { justify-content: space-between; }
|
|
200
|
+
.u-text { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
|
|
201
|
+
.u-num { font-weight: var(--strong-weight); font-size: 13.5px; line-height: 1.3; white-space: nowrap; font-variant-numeric: tabular-nums; }
|
|
202
|
+
.u-unit { color: var(--faint); font-weight: 400; font-size: 12px; }
|
|
203
|
+
.rows .u-unit { display: none; }
|
|
204
|
+
.u-sub, .u-note { color: var(--faint); font-size: 11.5px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
|
205
|
+
.u-note { font-size: var(--small); color: var(--muted); white-space: normal; }
|
|
206
|
+
/* One slot per day, bars grow from a shared baseline; past days are a tint of the accent, today is the accent. */
|
|
207
|
+
.spark { display: inline-flex; align-items: flex-end; gap: 3px; height: 26px; flex: none; }
|
|
208
|
+
.spark i { display: flex; align-items: flex-end; width: 5px; height: 100%; }
|
|
209
|
+
.spark b { display: block; width: 100%; min-height: 4px; border-radius: 1.5px; background: color-mix(in srgb, var(--accent) 32%, var(--surface)); transition: background-color .12s; }
|
|
210
|
+
.spark i.zero b { height: 2px; min-height: 0; background: color-mix(in srgb, var(--faint) 30%, transparent); }
|
|
211
|
+
.spark i.today b { background: var(--accent); }
|
|
212
|
+
.spark i:not(.zero):hover b { background: color-mix(in srgb, var(--accent) 70%, var(--surface)); }
|
|
213
|
+
.spark i.today:hover b { background: var(--accent); }
|
|
214
|
+
/* Where relative colors work, both shades keep the accent's hue at a set lightness and a floor on chroma, so a dark or
|
|
215
|
+
muted accent still gives a clear light tint for past days and a vivid bar for today. */
|
|
216
|
+
@supports (color: oklch(from red l c h)) {
|
|
217
|
+
.spark b { background: var(--spark-soft); }
|
|
218
|
+
.spark i.today:not(.zero) b, .spark i:not(.zero):hover b { background: var(--spark); }
|
|
219
|
+
}
|
|
220
|
+
.spark-lg { height: 36px; gap: 4px; }
|
|
221
|
+
.spark-lg i { width: 7px; }
|
|
222
|
+
.spark-lg b { border-radius: 2px; }
|
|
223
|
+
.last { color: var(--muted); font-size: 12px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
|
224
|
+
.health { font-size: 11.5px; line-height: 20px; padding: 0 8px 0 7px; gap: 5px; max-width: 100%; }
|
|
225
|
+
.health .dot { width: 6px; height: 6px; }
|
|
226
|
+
|
|
227
|
+
/* In the wide list the column titles name the windows; elsewhere each meter carries its label. */
|
|
228
|
+
.rows .m-label, .rows .m-unit { display: none; }
|
|
229
|
+
|
|
230
|
+
/* Chips and badges */
|
|
231
|
+
.badge { flex: none; display: inline-grid; place-items: center; width: 34px; height: 34px; border-radius: 10px; color: #fff; font-weight: 700; font-size: 12.5px; letter-spacing: .02em; }
|
|
232
|
+
.badge-logo { background: var(--surface-2); border: 1px solid var(--border); color: var(--text); }
|
|
233
|
+
.badge svg { display: block; width: 20px; height: 20px; fill: currentColor; }
|
|
234
|
+
.badge-sm { width: 26px; height: 26px; border-radius: 7px; font-size: 10.5px; }
|
|
235
|
+
.badge-sm svg { width: 16px; height: 16px; }
|
|
236
|
+
.badge-xs { width: 16px; height: 16px; border-radius: 4px; border: 0; background: none; }
|
|
237
|
+
.badge-xs svg { width: 13px; height: 13px; }
|
|
238
|
+
.chip { display: inline-flex; align-items: center; gap: 5px; padding: 1px 8px; border-radius: var(--chip-radius); background: var(--surface-2); border: 1px solid var(--border); color: var(--muted); font: inherit; font-size: 12px; line-height: 20px; white-space: nowrap; max-width: 100%; overflow: hidden; text-overflow: ellipsis; }
|
|
239
|
+
.chip-sm { font-size: 11px; line-height: 16px; padding: 0 6px; }
|
|
240
|
+
.chip-btn { cursor: pointer; transition: filter .12s, border-color .12s; }
|
|
241
|
+
.chip-btn:hover { border-color: var(--border-strong); filter: brightness(.97); }
|
|
242
|
+
.chip-btn:focus-visible { outline: var(--focus-outline); outline-offset: 2px; box-shadow: var(--focus-ring); }
|
|
243
|
+
.chip-accent { background: var(--accent-soft); border-color: transparent; color: var(--accent); }
|
|
244
|
+
.chip-ok { background: var(--ok-soft); border-color: transparent; color: var(--ok); }
|
|
245
|
+
.chip-warn { background: var(--warn-soft); border-color: transparent; color: var(--warn); }
|
|
246
|
+
.chip-fail { background: var(--fail-soft); border-color: transparent; color: var(--fail); }
|
|
247
|
+
.chip .badge-xs { margin-left: -3px; }
|
|
248
|
+
/* Tags next to a name: short command, API, signed out, host missing; one size for all. */
|
|
249
|
+
.tag { display: inline-flex; align-items: center; gap: 4px; height: 18px; padding: 0 6px; border: 0; border-radius: 5px; background: var(--surface-2); color: var(--muted); font: inherit; font-size: 11px; font-weight: var(--strong-weight); line-height: 1; white-space: nowrap; }
|
|
250
|
+
.tag-alias { font-family: var(--mono); font-weight: 400; }
|
|
251
|
+
.tag-warn { background: var(--warn-soft); color: var(--warn); }
|
|
252
|
+
.tag-fail { background: var(--fail-soft); color: var(--fail); }
|
|
253
|
+
.tag-ok { background: var(--ok-soft); color: var(--ok); }
|
|
254
|
+
.tag .dot { width: 6px; height: 6px; }
|
|
255
|
+
.tag-btn { cursor: pointer; transition: filter .12s; }
|
|
256
|
+
.tag-btn:hover { filter: brightness(.96); }
|
|
257
|
+
.tag-btn:focus-visible { outline: var(--focus-outline); outline-offset: 2px; }
|
|
258
|
+
.group-wait { display: inline-flex; align-items: center; gap: 7px; color: var(--muted); font-size: var(--small); }
|
|
259
|
+
.pulse { width: 7px; height: 7px; border-radius: 50%; background: var(--accent); flex: none; animation: pulse 1.4s ease-in-out infinite; }
|
|
260
|
+
@keyframes pulse { 50% { opacity: .3; } }
|
|
261
|
+
.dot { width: 7px; height: 7px; border-radius: 50%; background: var(--faint); flex: none; }
|
|
262
|
+
.dot-ok { background: var(--ok-bar); } .dot-fail { background: var(--fail-bar); } .dot-warn { background: var(--warn-bar); }
|
|
263
|
+
.title-logo { display: flex; align-items: center; gap: 9px; min-width: 0; }
|
|
264
|
+
|
|
265
|
+
/* Cards view */
|
|
266
|
+
.grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 12px; }
|
|
267
|
+
.panel, .card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); box-shadow: var(--shadow); }
|
|
268
|
+
.panel { padding: 18px; }
|
|
269
|
+
.card { padding: 14px; display: flex; flex-direction: column; gap: 12px; min-width: 0; }
|
|
270
|
+
.card-error { border-color: var(--fail); }
|
|
271
|
+
.card-head { display: flex; align-items: flex-start; gap: 10px; min-width: 0; }
|
|
272
|
+
.card-head .badge { margin-top: 1px; }
|
|
273
|
+
.card .quota { gap: 10px 16px; }
|
|
274
|
+
.card .bar { height: 6px; }
|
|
275
|
+
.card-foot { display: flex; align-items: center; justify-content: space-between; gap: 10px; border-top: 1px solid var(--border); padding-top: 10px; margin-top: auto; min-width: 0; }
|
|
276
|
+
.card-side { display: flex; flex-direction: column; align-items: flex-end; gap: 4px; flex: none; }
|
|
277
|
+
.card .row-notes { margin: 0; }
|
|
278
|
+
|
|
279
|
+
/* Buttons: .btn is the secondary (outlined) variant; .btn-primary is the one main action of a block; .btn-ghost is a
|
|
280
|
+
quiet action such as Close. Two sizes: default (--ctl-h) for block actions, .btn-sm (--ctl-h-sm) inside cards, notes
|
|
281
|
+
and banners. .icon-btn is a square ghost button for icons. */
|
|
282
|
+
.btn { display: inline-flex; align-items: center; justify-content: center; gap: 6px; height: var(--ctl-h); padding: 0 14px; border-radius: var(--ctl-radius); border: 1px solid var(--border-strong); background: var(--surface); color: var(--btn-text); font: inherit; font-size: var(--control-size); font-weight: var(--button-weight); line-height: 1; cursor: pointer; white-space: nowrap; text-decoration: none; user-select: none; transition: background-color .12s, border-color .12s, color .12s; }
|
|
283
|
+
a.btn:hover { text-decoration: none; }
|
|
284
|
+
.btn:hover:not(:disabled) { background: var(--hover); border-color: var(--btn-hover-border); color: var(--btn-hover-text); }
|
|
285
|
+
.btn:active:not(:disabled) { background: var(--active); }
|
|
286
|
+
.btn-primary { background: var(--primary); border-color: var(--primary-border); color: var(--on-primary); font-weight: var(--primary-weight); }
|
|
287
|
+
.btn-primary:hover:not(:disabled) { background: var(--primary-hover); border-color: var(--primary-hover-border); color: var(--on-primary); }
|
|
288
|
+
.btn-primary:active:not(:disabled) { background: var(--primary-active); border-color: var(--primary-hover-border); }
|
|
289
|
+
.btn-ghost { border-color: transparent; background: transparent; color: var(--muted); }
|
|
290
|
+
.btn-ghost:hover:not(:disabled) { border-color: transparent; color: var(--text); }
|
|
291
|
+
.btn-sm { height: var(--ctl-h-sm); padding: 0 10px; font-size: var(--small); }
|
|
292
|
+
.btn svg { width: 15px; height: 15px; flex: none; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
|
|
293
|
+
.btn:disabled { background: var(--surface-2); border-color: var(--border); color: var(--faint); cursor: not-allowed; }
|
|
294
|
+
.btn-ghost:disabled { background: transparent; border-color: transparent; }
|
|
295
|
+
/* A busy button is disabled but keeps its variant, so a running action does not look unavailable. */
|
|
296
|
+
.btn[aria-busy=true]:disabled { cursor: progress; color: var(--muted); }
|
|
297
|
+
.btn-primary[aria-busy=true]:disabled { background: var(--primary); border-color: var(--primary-border); color: var(--on-primary); opacity: .85; }
|
|
298
|
+
.is-spinning svg { animation: spin .8s linear infinite; }
|
|
299
|
+
.icon-btn { display: inline-grid; place-items: center; width: var(--ctl-h-sm); height: var(--ctl-h-sm); padding: 0; border: 1px solid transparent; border-radius: var(--ctl-radius); background: transparent; color: var(--muted); cursor: pointer; font: inherit; }
|
|
300
|
+
.icon-btn:hover:not(:disabled), .icon-btn[aria-expanded=true] { background: var(--hover); color: var(--text); }
|
|
301
|
+
.more .ic { stroke-width: 3.2; width: 17px; height: 17px; }
|
|
302
|
+
.icon-btn:disabled { color: var(--faint); cursor: not-allowed; }
|
|
303
|
+
.top-actions .icon-btn { width: var(--ctl-h); height: var(--ctl-h); border-color: var(--border-strong); background: var(--surface); }
|
|
304
|
+
.top-actions .icon-btn:hover { background: var(--hover); }
|
|
305
|
+
.lang-btn { font-size: 12.5px; font-weight: var(--button-weight); color: var(--btn-text); width: auto !important; padding: 0 10px; }
|
|
306
|
+
.btn:focus-visible, .icon-btn:focus-visible, input:focus-visible, select:focus-visible, a:focus-visible, .stat-btn:focus-visible { outline: var(--focus-outline); outline-offset: 2px; box-shadow: var(--focus-ring); }
|
|
307
|
+
.btn:focus-visible { border-color: var(--focus); }
|
|
308
|
+
.note a, .banner a { color: inherit; text-decoration: underline; text-underline-offset: 2px; font-weight: var(--strong-weight); }
|
|
309
|
+
|
|
310
|
+
/* Notes and banners */
|
|
311
|
+
.note { background: var(--surface-2); border-radius: calc(var(--radius) - 6px); padding: 8px 11px; font-size: 13px; color: var(--muted); display: flex; flex-wrap: wrap; gap: 4px 8px; align-items: center; }
|
|
312
|
+
.note b { color: inherit; }
|
|
313
|
+
.note-fail { background: var(--fail-soft); color: var(--fail); }
|
|
314
|
+
.note-warn { background: var(--warn-soft); color: var(--warn); }
|
|
315
|
+
.error-note { justify-content: space-between; gap: 12px; }
|
|
316
|
+
.error-note > span { min-width: 0; overflow-wrap: anywhere; }
|
|
317
|
+
.error-note > .note-sub { flex-basis: 100%; color: var(--text); }
|
|
318
|
+
.banner { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; padding: 11px 14px; border-radius: calc(var(--radius) - 2px); margin-bottom: 12px; border: 1px solid var(--border); background: var(--surface); }
|
|
319
|
+
.banner > div { min-width: 0; }
|
|
320
|
+
.banner-quiet { padding: 8px 14px; background: transparent; border-style: dashed; }
|
|
321
|
+
.banner-fail { background: var(--fail-soft); border-color: transparent; color: var(--fail); }
|
|
322
|
+
.banner-warn { background: var(--warn-soft); border-color: transparent; color: var(--warn); }
|
|
323
|
+
.banner ul { margin: 6px 0 0; padding-left: 18px; }
|
|
324
|
+
.disabled-why { color: var(--muted); font-size: var(--small); margin-top: 10px; }
|
|
325
|
+
.actions { display: flex; gap: 8px; flex-wrap: wrap; }
|
|
326
|
+
.spin { display: inline-block; width: 13px; height: 13px; border-radius: 50%; border: 2px solid currentColor; border-right-color: transparent; animation: spin .8s linear infinite; vertical-align: -2px; flex: none; }
|
|
327
|
+
@keyframes spin { to { transform: rotate(360deg); } }
|
|
328
|
+
.copy { display: flex; align-items: center; gap: 6px; max-width: 100%; min-width: 0; }
|
|
329
|
+
.copy code { background: var(--surface-2); border: 1px solid var(--border); border-radius: 7px; padding: 3px 8px; overflow-x: auto; white-space: nowrap; color: var(--text); min-width: 0; }
|
|
330
|
+
|
|
331
|
+
/* Health check */
|
|
332
|
+
.diff { margin: 0; max-height: 260px; overflow: auto; background: var(--surface); border: 1px solid var(--border); border-radius: calc(var(--radius) - 4px); padding: 10px 0; font: 12px/1.55 var(--mono); }
|
|
333
|
+
.diff span { display: block; padding: 0 12px; white-space: pre; }
|
|
334
|
+
.diff .add { background: var(--ok-soft); color: var(--ok); } .diff .del { background: var(--fail-soft); color: var(--fail); } .diff .hunk { color: var(--faint); }
|
|
335
|
+
.filter-bar { display: flex; align-items: center; flex-wrap: wrap; gap: 8px 12px; padding: 8px 10px; margin-bottom: 4px; border-radius: var(--ctl-radius); background: var(--surface-2); }
|
|
336
|
+
.findings { list-style: none; margin: 12px 0 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
|
|
337
|
+
.more-findings { margin-top: 10px; }
|
|
338
|
+
.finding { display: flex; gap: 10px; padding: 10px 12px; border: 1px solid var(--border); border-radius: calc(var(--radius) - 4px); }
|
|
339
|
+
.finding .dot { margin-top: 7px; }
|
|
340
|
+
.finding.lvl-fail .dot { background: var(--fail-bar); } .finding.lvl-warn .dot { background: var(--warn-bar); }
|
|
341
|
+
.finding-body { min-width: 0; display: flex; flex-direction: column; gap: 3px; }
|
|
342
|
+
.finding-top { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
|
|
343
|
+
.hint { color: var(--muted); font-size: var(--small); overflow-wrap: anywhere; }
|
|
344
|
+
.all-good { display: flex; align-items: center; gap: 12px; margin-top: 12px; padding: 12px 14px; border-radius: calc(var(--radius) - 4px); background: var(--ok-soft); }
|
|
345
|
+
.check-icon { display: inline-grid; place-items: center; width: 26px; height: 26px; border-radius: 50%; background: var(--ok); color: var(--surface); font-weight: 700; flex: none; }
|
|
346
|
+
.warn-icon { display: inline-grid; place-items: center; width: 26px; height: 26px; border-radius: 50%; background: var(--warn); color: var(--surface); font-weight: 700; flex: none; }
|
|
347
|
+
.fix-result { margin-top: 12px; padding: 10px 12px; border-radius: calc(var(--radius) - 4px); font-size: 13px; }
|
|
348
|
+
.fix-result.is-ok { background: var(--ok-soft); color: var(--ok); } .fix-result.is-warn { background: var(--warn-soft); color: var(--warn); }
|
|
349
|
+
.fix-result ul { margin: 6px 0 0; padding-left: 18px; }
|
|
350
|
+
|
|
351
|
+
/* Forms */
|
|
352
|
+
.form { display: flex; flex-direction: column; gap: 14px; }
|
|
353
|
+
.field { display: flex; flex-direction: column; gap: 6px; border: 0; padding: 0; margin: 0; min-width: 0; }
|
|
354
|
+
.field > span, .field > legend { font-weight: var(--strong-weight); font-size: var(--small); padding: 0; margin-bottom: 6px; }
|
|
355
|
+
.field > span { margin-bottom: 0; }
|
|
356
|
+
input[type=text], input[type=search], select { height: var(--field-h); border-radius: var(--ctl-radius); border: 1px solid var(--border-strong); background-color: var(--surface); color: var(--text); font: inherit; padding: 0 12px; width: 100%; transition: border-color .12s, box-shadow .12s; }
|
|
357
|
+
input[type=search] { -webkit-appearance: none; appearance: none; }
|
|
358
|
+
input[type=search]::-webkit-search-cancel-button { -webkit-appearance: none; }
|
|
359
|
+
input::placeholder { color: var(--faint); }
|
|
360
|
+
input[type=text]:hover:not(:disabled), input[type=search]:hover, select:hover:not(:disabled) { border-color: var(--btn-hover-border); }
|
|
361
|
+
input[type=text]:focus, input[type=search]:focus, select:focus { border-color: var(--focus); }
|
|
362
|
+
input[type=text]:disabled, select:disabled { background-color: var(--surface-2); color: var(--faint); cursor: not-allowed; }
|
|
363
|
+
input.invalid { border-color: var(--fail); }
|
|
364
|
+
/* The select draws its own chevron with two gradient strokes (the CSP allows no external images), so it follows the
|
|
365
|
+
text color in both schemes and on hover. */
|
|
366
|
+
select { --chevron: var(--muted); appearance: none; padding-right: 32px; cursor: pointer; text-overflow: ellipsis;
|
|
367
|
+
background-image: linear-gradient(45deg, transparent calc(50% - .8px), var(--chevron) calc(50% - .8px) calc(50% + .8px), transparent calc(50% + .8px)), linear-gradient(-45deg, transparent calc(50% - .8px), var(--chevron) calc(50% - .8px) calc(50% + .8px), transparent calc(50% + .8px));
|
|
368
|
+
background-position: right 16px center, right 11px center; background-size: 5px 5px; background-repeat: no-repeat; }
|
|
369
|
+
select:is(:hover, :focus) { --chevron: var(--text); }
|
|
370
|
+
.check-row { display: flex; align-items: flex-start; gap: 8px; }
|
|
371
|
+
.check-row .check { flex: 1; }
|
|
372
|
+
.check-row .tip { margin-top: 12px; }
|
|
373
|
+
.check { display: flex; gap: 10px; align-items: flex-start; cursor: pointer; padding: 10px 12px; border: 1px solid var(--border); border-radius: var(--ctl-radius); transition: border-color .12s, background-color .12s; }
|
|
374
|
+
.check:hover { border-color: var(--btn-hover-border); }
|
|
375
|
+
.check:has(input:checked) { background: var(--accent-soft); border-color: transparent; }
|
|
376
|
+
.check input { width: 16px; height: 16px; margin: 2px 0 0; flex: none; accent-color: var(--check); cursor: pointer; }
|
|
377
|
+
.check span { display: flex; flex-direction: column; gap: 2px; }
|
|
378
|
+
.check b { font-size: var(--small); }
|
|
379
|
+
.field-error { color: var(--fail); font-size: var(--small); }
|
|
380
|
+
.field-hint { color: var(--muted); font-size: var(--small); }
|
|
381
|
+
.field-hint:empty { display: none; }
|
|
382
|
+
.field-error:empty { display: none; }
|
|
383
|
+
.fam-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 8px; }
|
|
384
|
+
.fam-card { position: relative; display: flex; align-items: center; gap: 10px; padding: 9px 10px; border: 1px solid var(--border); border-radius: var(--ctl-radius); cursor: pointer; min-width: 0; transition: border-color .12s, background-color .12s; }
|
|
385
|
+
.fam-card:hover { border-color: var(--btn-hover-border); }
|
|
386
|
+
.fam-card:has(input:checked) { border-color: var(--accent); background: var(--accent-soft); box-shadow: inset 0 0 0 1px var(--accent); }
|
|
387
|
+
.fam-card:has(input:focus-visible) { outline: var(--focus-outline); outline-offset: 2px; }
|
|
388
|
+
.fam-card.is-off { cursor: not-allowed; opacity: .6; }
|
|
389
|
+
.fam-card.is-off:hover { border-color: var(--border); }
|
|
390
|
+
.fam-text { display: flex; flex-direction: column; min-width: 0; }
|
|
391
|
+
.fam-title { font-weight: var(--strong-weight); font-size: var(--small); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
|
392
|
+
.fam-sub { color: var(--muted); font-size: 11.5px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
|
393
|
+
.preview { display: grid; grid-template-columns: max-content minmax(0, 1fr); gap: 4px 14px; margin: 0; padding: 10px 12px; border-radius: var(--ctl-radius); background: var(--surface-2); font-size: var(--small); }
|
|
394
|
+
.preview dt { color: var(--muted); }
|
|
395
|
+
.preview dd { margin: 0; overflow-wrap: anywhere; color: var(--text); }
|
|
396
|
+
.preview.is-draft dd { color: var(--faint); }
|
|
397
|
+
.created { display: flex; flex-direction: column; gap: 10px; }
|
|
398
|
+
.created-head { display: flex; align-items: center; gap: 10px; }
|
|
399
|
+
.steps { margin: 0; padding-left: 20px; display: flex; flex-direction: column; gap: 8px; }
|
|
400
|
+
.steps li::marker { color: var(--faint); }
|
|
401
|
+
.steps li { min-width: 0; }
|
|
402
|
+
.steps li > span:not(.copy) { display: block; margin-bottom: 4px; }
|
|
403
|
+
|
|
404
|
+
/* Dialog */
|
|
405
|
+
.dialog { padding: 0; border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface); color: var(--text); width: min(560px, calc(100vw - 24px)); max-height: calc(100vh - 48px); box-shadow: var(--float-shadow); }
|
|
406
|
+
.dialog[open] { display: flex; flex-direction: column; }
|
|
407
|
+
.dialog::backdrop { background: rgba(10, 12, 16, .4); }
|
|
408
|
+
.dlg-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 16px 18px 4px; }
|
|
409
|
+
.dlg-head h2 { font-size: var(--large); }
|
|
410
|
+
.dlg-body { padding: 10px 18px 16px; overflow: auto; display: flex; flex-direction: column; gap: 12px; }
|
|
411
|
+
.dlg-foot { display: flex; justify-content: flex-end; gap: 8px; padding: 12px 18px; border-top: 1px solid var(--border); background: var(--surface-2); border-radius: 0 0 var(--radius) var(--radius); }
|
|
412
|
+
|
|
413
|
+
/* Menu, tooltips, toasts */
|
|
414
|
+
.menu { position: fixed; z-index: 40; min-width: 230px; max-width: min(380px, calc(100vw - 16px)); padding: 4px; background: var(--surface); border: 1px solid var(--border); border-radius: calc(var(--ctl-radius) + 2px); box-shadow: var(--float-shadow); }
|
|
415
|
+
.menu-item { display: flex; align-items: center; gap: 10px; width: 100%; height: 32px; padding: 0 10px; border: 0; border-radius: calc(var(--ctl-radius) - 2px); background: none; color: var(--text); font: inherit; font-size: var(--control-size); text-align: left; cursor: pointer; }
|
|
416
|
+
.menu-item .ic { flex: none; color: var(--muted); }
|
|
417
|
+
.menu-item:hover:not(:disabled), .menu-item:focus-visible { background: var(--hover); outline: none; }
|
|
418
|
+
.menu-item:disabled { color: var(--faint); cursor: not-allowed; }
|
|
419
|
+
.menu-label { flex: none; white-space: nowrap; }
|
|
420
|
+
/* The hint gives way first: it shrinks to an ellipsis so a long label never pushes it past the menu's edge. */
|
|
421
|
+
.menu-hint { min-width: 0; margin-left: auto; padding-left: 12px; color: var(--faint); font-size: 11px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
|
422
|
+
.menu-sep { height: 1px; margin: 4px 6px; background: var(--border); }
|
|
423
|
+
.tip { display: inline-flex; position: relative; vertical-align: middle; }
|
|
424
|
+
.tip-btn { display: inline-grid; place-items: center; width: 16px; height: 16px; padding: 0; border: 1px solid var(--border-strong); border-radius: 50%; background: var(--surface); color: var(--muted); font: 700 10px/1 var(--font); cursor: help; }
|
|
425
|
+
.tip-btn:hover, .tip.is-open .tip-btn { color: var(--text); border-color: var(--muted); }
|
|
426
|
+
.tip-btn:focus-visible { outline: var(--focus-outline); outline-offset: 2px; }
|
|
427
|
+
.tip-body { display: none; position: fixed; z-index: 60; width: max-content; max-width: min(280px, calc(100vw - 16px)); padding: 7px 10px; border-radius: 7px; background: var(--text); color: var(--bg); font-size: 12px; font-weight: 400; line-height: 1.45; letter-spacing: 0; box-shadow: var(--float-shadow); pointer-events: none; text-align: left; white-space: normal; }
|
|
428
|
+
.tip.is-open .tip-body { display: block; }
|
|
429
|
+
.toasts { position: fixed; inset: auto auto 20px 50%; margin: 0; padding: 0; border: 0; background: none; color: inherit; overflow: visible; transform: translateX(-50%); z-index: 50; display: flex; flex-direction: column; align-items: center; gap: 8px; width: max-content; max-width: calc(100vw - 24px); pointer-events: none; }
|
|
430
|
+
.toast { pointer-events: auto; display: flex; align-items: center; gap: 10px; max-width: min(460px, calc(100vw - 24px)); min-height: 40px; padding: 6px 6px 6px 14px; border-radius: calc(var(--ctl-radius) + 2px); background: var(--surface); color: var(--text); border: 1px solid var(--border); box-shadow: var(--float-shadow); font-size: 13px; animation: toast-in .18s ease-out; }
|
|
431
|
+
.toast-dot { width: 8px; height: 8px; border-radius: 50%; flex: none; background: var(--ok); }
|
|
432
|
+
.toast-fail .toast-dot { background: var(--fail); } .toast-plain .toast-dot { background: var(--faint); } .toast-info .toast-dot { background: var(--warn); }
|
|
433
|
+
.toast-text { min-width: 0; overflow-wrap: anywhere; }
|
|
434
|
+
.toast-action { flex: none; height: 28px; padding: 0 10px; border: 1px solid var(--border-strong); border-radius: var(--ctl-radius); background: var(--surface); color: var(--text); font: inherit; font-weight: var(--button-weight); cursor: pointer; }
|
|
435
|
+
.toast-action:hover { background: var(--hover); }
|
|
436
|
+
.toast-x { flex: none; display: inline-grid; place-items: center; width: 26px; height: 26px; padding: 0; border: 0; border-radius: 6px; background: none; color: var(--faint); cursor: pointer; }
|
|
437
|
+
.toast-x:hover { color: var(--text); background: var(--hover); }
|
|
438
|
+
.toast-x .ic { width: 13px; height: 13px; }
|
|
439
|
+
.toast.bump { animation: toast-bump .25s ease-out; }
|
|
440
|
+
@keyframes toast-in { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }
|
|
441
|
+
@keyframes toast-bump { 50% { transform: scale(1.03); } }
|
|
442
|
+
.conn { position: fixed; top: 14px; left: 50%; transform: translateX(-50%); z-index: 55; display: flex; align-items: center; gap: 8px; max-width: calc(100vw - 24px); padding: 8px 14px; border-radius: var(--chip-radius); background: var(--warn-soft); color: var(--warn); border: 1px solid var(--border); box-shadow: var(--float-shadow); font-size: 13px; font-weight: var(--strong-weight); }
|
|
443
|
+
|
|
444
|
+
/* Empty, loading and filtered states */
|
|
445
|
+
.empty { text-align: center; padding: 36px 20px; background: var(--surface); border: 1px dashed var(--border-strong); border-radius: var(--radius); display: flex; flex-direction: column; align-items: center; gap: 12px; }
|
|
446
|
+
.empty-sm { padding: 28px 20px; }
|
|
447
|
+
.empty-fail { border-color: var(--fail); border-style: solid; background: var(--fail-soft); color: var(--fail); }
|
|
448
|
+
.empty h3 { font-size: 17px; font-weight: var(--heading-weight); }
|
|
449
|
+
.empty p { max-width: 520px; overflow-wrap: anywhere; }
|
|
450
|
+
.host-list { list-style: none; padding: 0; margin: 4px 0; display: flex; flex-direction: column; gap: 8px; min-width: min(360px, 100%); text-align: left; }
|
|
451
|
+
.host-list li { display: flex; align-items: center; gap: 10px; padding: 8px 10px; border: 1px solid var(--border); border-radius: calc(var(--radius) - 4px); }
|
|
452
|
+
.host-list li > span:nth-child(2) { flex: 1; font-weight: var(--strong-weight); }
|
|
453
|
+
.sk { display: block; border-radius: 6px; background: linear-gradient(90deg, var(--surface-2) 25%, var(--track) 50%, var(--surface-2) 75%); background-size: 200% 100%; animation: shimmer 1.3s ease-in-out infinite; }
|
|
454
|
+
.sk-row { display: flex; align-items: center; gap: 12px; padding: 14px 16px; border-top: 1px solid var(--border); }
|
|
455
|
+
.sk-row:first-child { border-top: 0; }
|
|
456
|
+
.sk-badge { width: 26px; height: 26px; border-radius: 7px; flex: none; }
|
|
457
|
+
.sk-title { height: 12px; width: 22%; }
|
|
458
|
+
.sk-bar { height: 8px; flex: 1; max-width: 160px; margin-left: auto; }
|
|
459
|
+
.sk-line { height: 12px; margin: 8px 0; }
|
|
460
|
+
.sk-stat { height: 40px; margin: 14px 18px; }
|
|
461
|
+
.w50 { width: 50%; } .w70 { width: 70%; }
|
|
462
|
+
@keyframes shimmer { from { background-position: 100% 0; } to { background-position: -100% 0; } }
|
|
463
|
+
.view-in > * { animation: view-in .22s ease-out both; }
|
|
464
|
+
@keyframes view-in { from { opacity: 0; transform: translateY(3px); } to { opacity: 1; transform: none; } }
|
|
465
|
+
.row.flash { animation: flash-row 2.4s ease-out; }
|
|
466
|
+
.card.flash { animation: flash-card 2.4s ease-out; }
|
|
467
|
+
@keyframes flash-row { from { background: var(--accent-soft); } to { background: transparent; } }
|
|
468
|
+
@keyframes flash-card { from { box-shadow: 0 0 0 2px var(--accent), var(--shadow); } to { box-shadow: 0 0 0 2px transparent, var(--shadow); } }
|
|
469
|
+
.checkup { margin-top: 8px; }
|
|
470
|
+
.foot { margin-top: 28px; text-align: center; }
|
|
471
|
+
|
|
472
|
+
@media (max-width: 1100px) {
|
|
473
|
+
.col-head { display: none; }
|
|
474
|
+
.row { grid-template-columns: minmax(0, 1fr) auto var(--m-w); grid-template-areas: "id health more" "quota quota quota" "usage usage last" "notes notes notes"; row-gap: 10px; }
|
|
475
|
+
.row > .quota { grid-template-columns: repeat(var(--qn), minmax(0, 1fr)); max-width: 560px; }
|
|
476
|
+
.rows .m-label, .rows .m-unit, .rows .u-unit { display: inline; }
|
|
477
|
+
.rows .usage { justify-content: flex-start; }
|
|
478
|
+
.row > .last { justify-self: end; }
|
|
479
|
+
}
|
|
480
|
+
@media (max-width: 760px) {
|
|
481
|
+
.summary { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
|
482
|
+
.stat:nth-child(3) { border-left: 0; }
|
|
483
|
+
.stat:nth-child(n+3) { border-top: 1px solid var(--border); }
|
|
484
|
+
}
|
|
485
|
+
@media (max-width: 560px) {
|
|
486
|
+
:root { --gutter: 14px; }
|
|
487
|
+
.top-in { padding: 16px var(--gutter) 0; }
|
|
488
|
+
.header-bar .top-in { min-height: 0; padding: 12px var(--gutter); }
|
|
489
|
+
.wrap { padding: 14px var(--gutter) 32px; }
|
|
490
|
+
.hide-sm { display: none; }
|
|
491
|
+
.tagline { display: none; }
|
|
492
|
+
.brand .logo { width: 34px; height: 34px; }
|
|
493
|
+
.brand h1 { font-size: 19px; }
|
|
494
|
+
#updated { display: none; }
|
|
495
|
+
.banner { flex-direction: column; }
|
|
496
|
+
.stat { padding: 11px 13px; align-items: flex-start; flex-direction: column; gap: 6px; }
|
|
497
|
+
.stat-value { font-size: 19px; }
|
|
498
|
+
.stat-sub { white-space: normal; }
|
|
499
|
+
.spark-lg { display: none; }
|
|
500
|
+
.search { flex-basis: 100%; }
|
|
501
|
+
.tools { width: 100%; }
|
|
502
|
+
.tools .tb-select { flex: 1 1 140px; min-width: 0; }
|
|
503
|
+
.toolbar > .btn-primary { flex: 1; }
|
|
504
|
+
.row { padding: 10px 12px; }
|
|
505
|
+
#accounts { --col-gap: 14px; }
|
|
506
|
+
.grid { grid-template-columns: 1fr; }
|
|
507
|
+
.panel { padding: 14px; }
|
|
508
|
+
.dlg-head { padding: 14px 14px 2px; } .dlg-body { padding: 10px 14px 14px; } .dlg-foot { padding: 10px 14px; }
|
|
509
|
+
}
|
|
510
|
+
@media (prefers-reduced-motion: reduce) {
|
|
511
|
+
.sk, .spin, .is-spinning svg, .toast, .toast.bump, .view-in > *, .row.flash, .card.flash, .pulse { animation: none; }
|
|
512
|
+
.bar > span, .chev, .row { transition: none; }
|
|
513
|
+
}
|
|
514
|
+
`;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { pageStyles } from './page-styles.ts';
|
|
2
|
+
import { type ResolvedTheme } from './theme.ts';
|
|
3
|
+
export { pageStyles };
|
|
4
|
+
export interface PageOptions {
|
|
5
|
+
basePath: string;
|
|
6
|
+
token: string;
|
|
7
|
+
/** CSP nonce for the inline style and script. */
|
|
8
|
+
nonce?: string;
|
|
9
|
+
version?: string;
|
|
10
|
+
/** buildId() of the serving process; the page reloads when /api/state reports another one. */
|
|
11
|
+
build?: string;
|
|
12
|
+
readOnly?: boolean;
|
|
13
|
+
/** Host theme from resolveTheme(); the default look when absent. */
|
|
14
|
+
theme?: ResolvedTheme;
|
|
15
|
+
/** Host language from createPanelHandler's `lang`; `auto` (the default) lets the viewer choose. */
|
|
16
|
+
lang?: 'auto' | 'en' | 'zh';
|
|
17
|
+
}
|
|
18
|
+
/** JSON that is safe inside a `<script>` element: no `</script>`, `<!--` or line separators survive. */
|
|
19
|
+
export declare function jsonForScript(value: unknown): string;
|
|
20
|
+
export declare function renderPage(opts: PageOptions): string;
|