@volter/world-console 2.0.1 → 2.0.3
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/README.md +6 -4
- package/client/console.css +192 -106
- package/client/console.tsx +1239 -492
- package/client/kit/kit.css +279 -0
- package/client/kit/kit.tsx +259 -0
- package/client/vendor-logos.ts +42 -0
- package/dist/client/console.bundle.js +126 -113
- package/dist/client/console.css +192 -106
- package/dist/client/console.tsx +1239 -492
- package/dist/client/kit/kit.css +279 -0
- package/dist/client/kit/kit.tsx +259 -0
- package/dist/client/vendor-logos.ts +42 -0
- package/dist/src/console.d.ts +20 -11
- package/dist/src/console.js +36 -24
- package/package.json +7 -5
- package/src/console.ts +43 -30
package/README.md
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
# @volter/world-console
|
|
2
2
|
|
|
3
|
-
The
|
|
3
|
+
The dashboard of [Volter World](https://github.com/volter-ai/world): a World's pages — its vendors' screens,
|
|
4
|
+
overview, branches, changes, activity and keys. It is the same page on your machine (`volter world view`), on a
|
|
5
|
+
self-hosted host and on the hosted cloud, and it carries nothing of orgs, members or billing: those are the
|
|
6
|
+
platform's pages. Install it beside `@volter/world-host`; the host mounts it at `/-/console/` and prints its URL.
|
|
4
7
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
- **Managed**: the hosted platform serves the same console as its portal.
|
|
8
|
+
`@volter/world-console/kit` is the pieces the platform's pages share with it (the brand's mark, door reads,
|
|
9
|
+
instants, vendors' marks and the stylesheet).
|
|
8
10
|
|
|
9
11
|
It is a pure frontend — a React client bundled at serve time behind one shell — and reads nothing but
|
|
10
12
|
a world's own HTTP endpoints. It holds no data path a `curl` could not call.
|
package/client/console.css
CHANGED
|
@@ -1,113 +1,199 @@
|
|
|
1
|
-
/*
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
this sheet, and the names below are this sheet's aliases for those roles; the pre-commit hook
|
|
6
|
-
refuses a literal colour here. The roles carry both themes (light-dark()); `color-scheme` picks one.
|
|
7
|
-
The portal's pages link this sheet; the site reads the same roles (apps/www/src/site.css). */
|
|
8
|
-
:root {
|
|
9
|
-
color-scheme: light dark;
|
|
10
|
-
--ground: var(--volter-surface-page); --surface: var(--volter-surface-raised); --surface-2: var(--volter-surface-subtle);
|
|
11
|
-
--line: var(--volter-border-default); --line-strong: var(--volter-border-strong);
|
|
12
|
-
--ink: var(--volter-text-primary); --muted: var(--volter-text-muted); --faint: var(--volter-text-faint);
|
|
13
|
-
--accent: var(--volter-action-default); --accent-ink: var(--volter-text-on-strong); --accent-soft: var(--volter-action-soft);
|
|
14
|
-
--danger: var(--volter-status-danger-base); --danger-text: var(--volter-status-danger-text); --danger-soft: var(--volter-status-danger-soft);
|
|
15
|
-
--warn: var(--volter-status-attention-text); --warn-soft: var(--volter-status-attention-soft); --ok: var(--volter-status-healthy-text);
|
|
16
|
-
--mono: var(--volter-font-data);
|
|
17
|
-
--sans: var(--volter-font-ui);
|
|
18
|
-
--radius: 8px; --shadow: var(--volter-shadow-resting);
|
|
19
|
-
}
|
|
20
|
-
:root[data-theme="light"] { color-scheme: light; }
|
|
21
|
-
:root[data-theme="dark"] { color-scheme: dark; }
|
|
1
|
+
/* THE DASHBOARD: a World's pages over the kit (kit/kit.css, served first). Only what a World shows lives here. */
|
|
2
|
+
/* the World (a place to look around): its head with the clock, its tabs, and one panel per tab */
|
|
3
|
+
.badge.rooted { color: var(--ok); border-color: currentColor; }
|
|
4
|
+
h2 .badge.read-only { vertical-align: middle; color: var(--warn); border-color: currentColor; }
|
|
22
5
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
h1, h2, h3, h4, h5 { margin: 0; font-weight: 600; letter-spacing: -0.005em; text-wrap: balance; }
|
|
36
|
-
h1 { font-size: 17px; }
|
|
37
|
-
h2 { font-size: 18px; margin: 28px 0 10px; }
|
|
38
|
-
h3 { font-size: 15px; margin: 22px 0 8px; }
|
|
39
|
-
h4 { font-size: 13px; margin: 18px 0 6px; color: var(--muted); text-transform: uppercase; letter-spacing: 0.06em; font-weight: 600; }
|
|
40
|
-
h5 { font-size: 13px; margin: 10px 0 4px; color: var(--danger-text); }
|
|
41
|
-
p { margin: 6px 0; }
|
|
42
|
-
ul, ol { margin: 6px 0; padding-left: 20px; }
|
|
43
|
-
li { margin: 3px 0; }
|
|
6
|
+
/* the clock: a test clock's simulation banner, in the world's head */
|
|
7
|
+
.clock { flex: 1 1 360px; border: 1px solid var(--line); border-radius: var(--radius); padding: 8px 12px; background: var(--surface-2); }
|
|
8
|
+
.clock.frozen { border-color: color-mix(in srgb, var(--warn) 55%, var(--line)); background: var(--warn-soft); }
|
|
9
|
+
.clock.frozen .badge { color: var(--warn); border-color: currentColor; }
|
|
10
|
+
.clock-now { margin: 0; }
|
|
11
|
+
.clock-controls { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-top: 6px; }
|
|
12
|
+
.clock-controls > p { flex-basis: 100%; margin: 0; }
|
|
13
|
+
.advance { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
|
|
14
|
+
.advance button { padding: 4px 9px; }
|
|
15
|
+
.advance form.inline { margin: 0; align-items: center; }
|
|
16
|
+
.advance input { padding: 4px 8px; font-size: 13px; }
|
|
17
|
+
.as-of { flex: 0 0 auto; }
|
|
44
18
|
|
|
45
|
-
/* the
|
|
46
|
-
|
|
47
|
-
header h1 a { color: var(--ink); }
|
|
48
|
-
header nav a { color: var(--muted); }
|
|
49
|
-
header .mode { margin-left: auto; color: var(--muted); font-size: 12.5px; }
|
|
50
|
-
header > a { color: var(--muted); font-size: 13px; }
|
|
51
|
-
header button { padding: 5px 12px; }
|
|
19
|
+
/* a snapshot: the persistent "you are looking at the past" banner */
|
|
20
|
+
.snapshot { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 8px 14px; margin: -4px 0 14px; padding: 9px 12px; border: 1px solid color-mix(in srgb, var(--warn) 55%, var(--line)); background: var(--warn-soft); border-radius: var(--radius); color: var(--ink); }
|
|
52
21
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
section > h2:first-child, section > h3:first-child { margin-top: 0; }
|
|
56
|
-
.billing, .members { margin: 10px 0 0; padding: 14px 16px; background: var(--surface-2); }
|
|
57
|
-
.billing p:first-child { margin-top: 0; }
|
|
58
|
-
.usage { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 6px 16px; padding: 0; list-style: none; margin: 8px 0; }
|
|
59
|
-
.usage li { margin: 0; color: var(--muted); }
|
|
60
|
-
.plan-preview { margin: 10px 0; padding: 10px 12px; border: 1px dashed var(--line-strong); border-radius: var(--radius); }
|
|
61
|
-
.plan-preview p { margin: 0 0 4px; }
|
|
62
|
-
.onboarding { border-color: var(--accent); background: var(--accent-soft); }
|
|
63
|
-
.onboarding ol { margin: 8px 0 12px; }
|
|
64
|
-
.onboarding li[role="checkbox"] { list-style: none; margin-left: -20px; }
|
|
65
|
-
.onboarding li[aria-checked="true"] { color: var(--muted); }
|
|
66
|
-
details.org-settings { padding: 10px 16px; }
|
|
67
|
-
details.org-settings summary { cursor: pointer; color: var(--muted); font-weight: 600; }
|
|
68
|
-
details.org-settings[open] summary { margin-bottom: 8px; }
|
|
69
|
-
.danger { margin-top: 14px; padding: 12px 14px; border: 1px solid color-mix(in srgb, var(--danger) 45%, var(--line)); background: var(--danger-soft); border-radius: var(--radius); }
|
|
70
|
-
.danger button { border-color: var(--danger); color: var(--danger-text); }
|
|
71
|
-
.danger button:hover:not(:disabled) { background: var(--danger); color: var(--volter-text-on-strong); }
|
|
72
|
-
.admin { margin-top: 24px; padding-top: 12px; border-top: 1px dashed var(--line); }
|
|
22
|
+
.panel { padding-top: 6px; }
|
|
23
|
+
.empty { border: 1px dashed var(--line-strong); border-radius: var(--radius); padding: 14px 16px; margin: 10px 0; }
|
|
73
24
|
|
|
74
|
-
/*
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
25
|
+
/* overview: a card per twin */
|
|
26
|
+
.map { list-style: none; padding: 0; margin: 8px 0; display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 12px; }
|
|
27
|
+
.map .card { margin: 0; border: 1px solid var(--line); border-radius: var(--radius); padding: 12px 14px; background: var(--surface-2); display: grid; gap: 4px; align-content: start; }
|
|
28
|
+
.card-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
|
|
29
|
+
.map h4.vendor { margin: 0; font-size: 15px; text-transform: none; letter-spacing: 0; color: var(--ink); }
|
|
30
|
+
.resources { list-style: none; padding: 0; margin: 4px 0; display: grid; gap: 2px; }
|
|
31
|
+
.resources li { display: flex; justify-content: space-between; margin: 0; font-variant-numeric: tabular-nums; }
|
|
32
|
+
.card-actions { display: flex; align-items: center; gap: 12px; margin: 6px 0 0; }
|
|
80
33
|
|
|
81
|
-
/*
|
|
82
|
-
.
|
|
83
|
-
.
|
|
84
|
-
.
|
|
34
|
+
/* timeline: an activity feed, by day, same-instant entries together */
|
|
35
|
+
.chips { display: flex; flex-wrap: wrap; gap: 6px; margin: 10px 0; }
|
|
36
|
+
.chips button { border-radius: 999px; padding: 3px 12px; }
|
|
37
|
+
.chips button[aria-pressed="true"] { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); }
|
|
38
|
+
.pill-slot { position: sticky; top: 8px; z-index: 2; display: flex; justify-content: center; height: 0; overflow: visible; }
|
|
39
|
+
.pill { border-radius: 999px; background: var(--accent); border-color: var(--accent); color: var(--accent-ink); box-shadow: var(--shadow); padding: 5px 14px; }
|
|
40
|
+
.pill:hover:not(:disabled) { color: var(--accent-ink); filter: brightness(1.06); }
|
|
41
|
+
.feed { margin-top: 8px; }
|
|
42
|
+
.day-head { position: sticky; top: 0; z-index: 1; margin: 14px 0 0; padding: 6px 0; background: var(--surface); border-bottom: 1px solid var(--line); font-size: 13px; color: var(--muted); }
|
|
43
|
+
.instants { list-style: none; padding: 0; margin: 0; }
|
|
44
|
+
.instant { display: grid; grid-template-columns: minmax(96px, 150px) 1fr; gap: 10px; margin: 0; padding: 7px 0; border-bottom: 1px solid var(--line); }
|
|
45
|
+
.instant-time { color: var(--muted); font-size: 12.5px; font-variant-numeric: tabular-nums; }
|
|
46
|
+
.entries { list-style: none; padding: 0; margin: 0; display: grid; gap: 4px; }
|
|
47
|
+
.entry { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 10px; margin: 0; }
|
|
48
|
+
.twin-chip { font: 600 12px/1.6 var(--mono); padding: 0 7px; border-radius: 5px; background: var(--accent-soft); color: var(--ink); }
|
|
49
|
+
.entry .op { font-weight: 600; }
|
|
50
|
+
.entry .standing { color: var(--muted); font-size: 12.5px; }
|
|
51
|
+
.feed > button { margin-top: 12px; }
|
|
52
|
+
@media (max-width: 720px) { .instant { grid-template-columns: 1fr; gap: 2px; } }
|
|
85
53
|
|
|
86
|
-
/*
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
label:has(input[type="checkbox"]) { display: flex; align-items: center; gap: 8px; color: var(--ink); font-size: 13px; }
|
|
99
|
-
input, select { font: inherit; font-size: 14px; padding: 7px 10px; border: 1px solid var(--line-strong); border-radius: 6px; background: var(--surface); color: var(--ink); }
|
|
100
|
-
input::placeholder { color: var(--faint); }
|
|
101
|
-
select { padding-right: 28px; }
|
|
102
|
-
[role="alert"] { color: var(--danger-text); background: var(--danger-soft); border: 1px solid color-mix(in srgb, var(--danger) 35%, var(--line)); border-radius: 6px; padding: 8px 10px; }
|
|
103
|
-
[role="status"] { color: var(--muted); }
|
|
104
|
-
.mode { color: var(--muted); font-size: 12.5px; }
|
|
54
|
+
/* trace: a waterfall with a lane per twin */
|
|
55
|
+
.waterfall { display: grid; border: 1px solid var(--line); border-radius: var(--radius); overflow-x: auto; margin: 8px 0; }
|
|
56
|
+
.wf-row { display: contents; }
|
|
57
|
+
.wf-row > span { padding: 7px 10px; border-bottom: 1px solid var(--line); min-width: 0; }
|
|
58
|
+
.wf-head > span { color: var(--muted); font-weight: 600; font-size: 12px; text-transform: uppercase; letter-spacing: 0.05em; background: var(--surface-2); }
|
|
59
|
+
.wf-time { font-size: 12.5px; font-variant-numeric: tabular-nums; }
|
|
60
|
+
.wf-cell { border-left: 1px dashed var(--line); }
|
|
61
|
+
.wf-cell.on details { border-left: 3px solid var(--volter-data-base); padding-left: 8px; }
|
|
62
|
+
.wf-cell summary { cursor: pointer; }
|
|
63
|
+
.fields { display: grid; grid-template-columns: max-content 1fr; gap: 2px 12px; margin: 6px 0; }
|
|
64
|
+
.fields dt { color: var(--muted); font-size: 12.5px; }
|
|
65
|
+
.fields dd { margin: 0; min-width: 0; overflow-wrap: anywhere; }
|
|
105
66
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
67
|
+
|
|
68
|
+
/* changes: a compare view, by twin */
|
|
69
|
+
.compare { margin: 12px 0; border: 1px solid var(--line); border-radius: var(--radius); }
|
|
70
|
+
.compare h3 { margin: 0; padding: 8px 12px; background: var(--surface-2); border-bottom: 1px solid var(--line); }
|
|
71
|
+
.compare ul { list-style: none; padding: 0; margin: 0; }
|
|
72
|
+
.compare li { margin: 0; padding: 7px 12px; border-bottom: 1px solid var(--line); }
|
|
73
|
+
.compare li:last-child { border-bottom: 0; }
|
|
74
|
+
.compare summary { cursor: pointer; }
|
|
75
|
+
.compare .op { font-weight: 600; margin: 0 6px; }
|
|
76
|
+
|
|
77
|
+
/* A World is a repository page: a sentence says what it is; its vendors' own screens are the live preview. */
|
|
78
|
+
.lede { margin: 2px 0 6px; color: var(--ink); max-width: 62ch; }
|
|
79
|
+
.connect summary, .clock-more summary { cursor: pointer; color: var(--muted); font-size: 12.5px; }
|
|
80
|
+
.connect[open] summary, .clock-more[open] summary { color: var(--ink); }
|
|
81
|
+
.connect p { margin: 6px 0 0; }
|
|
82
|
+
.clock-more { margin-top: 4px; }
|
|
83
|
+
.clock-more > p { margin: 6px 0; }
|
|
84
|
+
.vendors { display: grid; grid-template-columns: 220px 1fr; gap: 14px; margin-top: 12px; align-items: start; }
|
|
85
|
+
.vendor-list ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 4px; }
|
|
86
|
+
.vendor-list a { display: grid; gap: 1px; padding: 8px 10px; border-radius: var(--radius); border: 1px solid transparent; color: var(--ink); text-decoration: none; }
|
|
87
|
+
.vendor-list a:hover { background: var(--surface-2); }
|
|
88
|
+
.vendor-list a[aria-current="page"] { background: var(--surface-2); border-color: var(--line); }
|
|
89
|
+
.vendor-list > button { margin-top: 10px; }
|
|
90
|
+
.stage { border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden; background: var(--surface-2); }
|
|
91
|
+
.stage-bar { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 12px; padding: 8px 12px; border-bottom: 1px solid var(--line); background: var(--surface); }
|
|
92
|
+
.stage-bar a { margin-left: auto; }
|
|
93
|
+
.stage-note { margin: 0; padding: 6px 12px; border-bottom: 1px solid var(--line); }
|
|
94
|
+
.stage iframe { display: block; width: 100%; height: max(560px, calc(100vh - 300px)); border: 0; background: var(--ground); }
|
|
95
|
+
.stage > p { padding: 12px; margin: 0; }
|
|
96
|
+
.entry .label { color: var(--ink); }
|
|
97
|
+
.entry.run details > summary { cursor: pointer; list-style: none; display: flex; flex-wrap: wrap; gap: 4px 10px; align-items: baseline; }
|
|
98
|
+
.entry.run details > ul { margin: 6px 0 0 14px; padding: 0; list-style: none; display: grid; gap: 4px; }
|
|
99
|
+
@media (max-width: 760px) { .vendors { grid-template-columns: 1fr; } }
|
|
100
|
+
|
|
101
|
+
.stats { list-style: none; margin: 0 0 18px; padding: 0; display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 12px; }
|
|
102
|
+
.stats li { margin: 0; padding: 12px 14px; background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); display: grid; gap: 2px; }
|
|
103
|
+
.stat-label { color: var(--muted); font-size: 12px; }
|
|
104
|
+
.stat-value { font-size: 24px; font-weight: 600; letter-spacing: -0.01em; font-variant-numeric: tabular-nums; }
|
|
105
|
+
.overview-grid { display: grid; grid-template-columns: minmax(0, 1.25fr) minmax(0, 1fr); gap: 16px; align-items: start; }
|
|
106
|
+
.mini-feed { list-style: none; margin: 0; padding: 0; }
|
|
107
|
+
.mini-feed li { display: flex; align-items: center; gap: 10px; margin: 0; padding: 8px 14px; border-top: 1px solid var(--line); }
|
|
108
|
+
.mini-feed li:first-child { border-top: 0; }
|
|
109
|
+
.mini-what { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
110
|
+
.empty-block { display: grid; gap: 6px; padding: 18px 14px; }
|
|
111
|
+
.empty-block pre { max-width: none; }
|
|
112
|
+
.content .vendors { display: block; margin: 0; }
|
|
113
|
+
.content .stage-bar { align-items: center; }
|
|
114
|
+
.stage-actions { margin-left: auto; display: flex; gap: 8px; align-items: center; }
|
|
115
|
+
.content .stage iframe { height: calc(100vh - 175px); min-height: 520px; }
|
|
116
|
+
.content .instant { display: grid; grid-template-columns: 92px minmax(0, 1fr); gap: 12px; }
|
|
117
|
+
.content .entry { display: grid; grid-template-columns: 104px minmax(120px, 190px) minmax(0, 1fr) auto auto; align-items: baseline; }
|
|
118
|
+
.content .entry.run { display: block; }
|
|
119
|
+
.content .entry .label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
120
|
+
.content .twin-chip { display: inline-flex; align-items: center; gap: 7px; background: none; padding: 0; font: 500 13px/1.4 var(--sans); }
|
|
121
|
+
.content .twin-chip .mark { width: 20px; height: 20px; }
|
|
122
|
+
/* the canvas (React Flow): frames on a dotted surface, as a canvas app is; React Flow's variables take the brand's roles */
|
|
123
|
+
.canvas { position: relative; height: calc(100vh - 140px); min-height: 480px; border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden;
|
|
124
|
+
--xy-background-color: var(--surface-2); --xy-background-pattern-color: var(--line-strong); --xy-minimap-background-color: var(--surface);
|
|
125
|
+
--xy-minimap-mask-background-color: color-mix(in srgb, var(--surface-2) 72%, transparent); --xy-minimap-node-background-color: var(--line-strong); --xy-controls-button-background-color: var(--surface);
|
|
126
|
+
--xy-controls-button-background-color-hover: var(--surface-2); --xy-controls-button-color: var(--ink); --xy-controls-button-border-color: var(--line); --xy-node-border-radius: 12px; }
|
|
127
|
+
.canvas .react-flow__node-screen { padding: 0; border: 0; background: none; }
|
|
128
|
+
.frame { display: grid; grid-template-rows: 48px 1fr; background: var(--surface); border: 1px solid var(--line-strong); border-radius: 12px; box-shadow: var(--shadow); overflow: hidden; }
|
|
129
|
+
.frame.on { outline: 4px solid var(--accent); outline-offset: 3px; }
|
|
130
|
+
.frame-bar { display: flex; align-items: center; gap: 12px; padding: 0 16px; border-bottom: 1px solid var(--line); background: var(--surface-2); cursor: grab; font-size: 17px; }
|
|
131
|
+
.frame-bar .mark { width: 26px; height: 26px; }
|
|
132
|
+
.frame-bar .mark.logo svg { width: 16px; height: 16px; }
|
|
133
|
+
.frame-url { flex: 1; min-width: 0; margin: 0 8px; padding: 5px 12px; border-radius: 999px; background: var(--surface); border: 1px solid var(--line); color: var(--muted); font: 14px var(--mono); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
134
|
+
.frame-body { position: relative; }
|
|
135
|
+
.frame-body iframe { display: block; width: 100%; height: 100%; border: 0; background: var(--ground); }
|
|
136
|
+
.frame-label { display: flex; align-items: center; gap: 7px; padding: 3px 8px; background: var(--surface); border: 1px solid var(--line); border-radius: 6px; box-shadow: var(--shadow); font-weight: 600; font-size: 12.5px; }
|
|
137
|
+
.canvas-hint { position: absolute; left: 50%; transform: translateX(-50%); top: 10px; font-size: 12px; margin: 0; padding: 4px 10px; background: var(--surface); border: 1px solid var(--line); border-radius: 999px; z-index: 5; pointer-events: none; }
|
|
138
|
+
/* THE WORLD, laid out as Neon's console (docs/concepts/the-model.md: Neon for every SaaS): the top bar's breadcrumb
|
|
139
|
+
and Connect; a sidebar of the World's pages, the branch picker, the branch's pages and its vendors as services */
|
|
140
|
+
/* ALL SCREENS: the canvas is the whole window, with its panels floating over it */
|
|
141
|
+
.canvas.full { position: fixed; inset: 0; z-index: 30; height: auto; min-height: 0; border: 0; border-radius: 0; }
|
|
142
|
+
.float { background: var(--surface); border: 1px solid var(--line); border-radius: 10px; box-shadow: var(--shadow); }
|
|
143
|
+
.float.layers { width: 232px; padding: 6px; max-height: calc(100vh - 32px); overflow-y: auto; }
|
|
144
|
+
.float-head { display: flex; align-items: center; gap: 8px; }
|
|
145
|
+
.float-title { display: grid; line-height: 1.2; flex: 1; min-width: 0; }
|
|
146
|
+
.float button.back, .float button.ghost { border: 0; background: transparent; padding: 4px 8px; }
|
|
147
|
+
.float button.back:hover, .float button.ghost:hover { background: var(--surface-2); }
|
|
148
|
+
.layer-list { list-style: none; margin: 6px 0 0; padding: 6px 0 0; border-top: 1px solid var(--line); display: grid; gap: 1px; }
|
|
149
|
+
.layer-list li { margin: 0; }
|
|
150
|
+
.layer-list button { width: 100%; display: flex; align-items: center; gap: 8px; border: 0; background: transparent; padding: 5px 8px; text-align: left; color: var(--ink); }
|
|
151
|
+
.layer-list button:hover { background: var(--surface-2); color: var(--ink); }
|
|
152
|
+
.layer-list button.on { background: var(--accent-soft); }
|
|
153
|
+
.float.hint { padding: 4px 12px; border-radius: 999px; font-size: 12px; pointer-events: none; }
|
|
154
|
+
|
|
155
|
+
/* THE DASHBOARD, as Vercel's and Neon's open a project: the live screens first, connect and branches beside, activity under */
|
|
156
|
+
.dash { display: grid; grid-template-columns: minmax(0, 2fr) minmax(260px, 1fr); gap: 16px; align-items: start; }
|
|
157
|
+
.dash-screens { grid-column: 1; }
|
|
158
|
+
.dash-side { grid-column: 2; display: grid; gap: 16px; }
|
|
159
|
+
.dash-activity { grid-column: 1 / -1; }
|
|
160
|
+
.dash .block-head { gap: 12px; }
|
|
161
|
+
.dash .block-head h3 { display: flex; align-items: center; gap: 8px; margin-right: auto; }
|
|
162
|
+
.badge.live { color: var(--ok); border-color: currentColor; }
|
|
163
|
+
.pad { padding: 10px 14px; margin: 0; }
|
|
164
|
+
.dash .pad pre { max-width: none; margin: 8px 0; }
|
|
165
|
+
.thumbs { list-style: none; margin: 0; padding: 14px; display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 14px; }
|
|
166
|
+
.thumbs li { margin: 0; }
|
|
167
|
+
.thumbs a { display: grid; gap: 6px; color: var(--ink); text-decoration: none; }
|
|
168
|
+
.thumb { position: relative; display: block; aspect-ratio: 1280 / 820; overflow: hidden; border: 1px solid var(--line); border-radius: 8px; background: var(--surface-2); }
|
|
169
|
+
.thumbs a:hover .thumb { border-color: var(--accent); }
|
|
170
|
+
.thumb iframe { position: absolute; top: 0; left: 0; border: 0; transform-origin: 0 0; pointer-events: none; background: var(--ground); }
|
|
171
|
+
.thumb-none { position: absolute; inset: 0; display: grid; place-items: center; color: var(--faint); font-size: 12px; }
|
|
172
|
+
.thumb-foot { display: flex; align-items: center; gap: 8px; min-width: 0; font-size: 13px; }
|
|
173
|
+
.thumb-foot .mode { margin-left: auto; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
174
|
+
@media (max-width: 980px) { .dash { grid-template-columns: 1fr; } .dash-side, .dash-screens { grid-column: 1; } }
|
|
175
|
+
.dash section.block { padding: 0; margin: 0; box-shadow: none; }
|
|
176
|
+
.dash .pad code { word-break: break-all; }
|
|
177
|
+
.dash .branch-glyph { display: inline-grid; place-items: center; width: 20px; color: var(--muted); }
|
|
178
|
+
section.pitch { background: none; border: 0; box-shadow: none; padding: 0; margin: 0; }
|
|
179
|
+
.thumb-status { position: absolute; top: 8px; right: 8px; background: var(--surface); }
|
|
180
|
+
/* Neon's sidebar opens on Connect; its branch Overview is a services table and a monitoring chart */
|
|
181
|
+
.connect-side { display: block; margin: 0 0 10px; }
|
|
182
|
+
.connect-side > .connect-button { display: block; width: 100%; text-align: center; border-color: var(--accent); color: var(--accent); font-weight: 600; }
|
|
183
|
+
.connect-side .popover { left: 0; right: auto; width: min(420px, 80vw); }
|
|
184
|
+
.connect-side .popover .agent-prompt-button { width: 100%; margin-top: 8px; }
|
|
185
|
+
.chart-block { margin-top: 16px; }
|
|
186
|
+
.chart { width: 100%; height: auto; display: block; }
|
|
187
|
+
.chart .grid { stroke: var(--line); stroke-dasharray: 3 4; }
|
|
188
|
+
.chart .axis { stroke: var(--line-strong); }
|
|
189
|
+
.chart .tick { font: 8px var(--mono); fill: var(--muted); text-anchor: middle; }
|
|
190
|
+
.legend { list-style: none; display: flex; flex-wrap: wrap; gap: 6px 16px; margin: 8px 0 0; padding: 0; font-size: 12.5px; }
|
|
191
|
+
.legend li { display: flex; align-items: center; gap: 6px; margin: 0; }
|
|
192
|
+
.legend .swatch { width: 10px; height: 10px; border-radius: 2px; display: inline-block; }
|
|
193
|
+
/* the World's keys: what they are beside the way to make one */
|
|
194
|
+
.keys-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; margin-bottom: 8px; }
|
|
195
|
+
.keys-head h3 { margin-top: 0; }
|
|
196
|
+
.keys-head p { margin: 2px 0 0; max-width: 620px; }
|
|
197
|
+
/* a phone: the top bar keeps the menu, the mark, where you are, the way back as an arrow and Sign out */
|
|
198
|
+
@media (max-width: 720px) { main.app > header .mode, main.app > header .back-link .back-text { display: none; } main.app > header .back-link { flex: none; } }
|
|
199
|
+
@media (max-width: 720px) { .head-actions .clock { flex-wrap: wrap; max-width: 100%; } }
|