@bakapiano/ccsm 0.22.3 → 0.22.5
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/CLAUDE.md +538 -538
- package/README.md +189 -189
- package/bin/ccsm.js +235 -235
- package/lib/cliActivity.js +139 -139
- package/lib/codexSeed.js +183 -183
- package/lib/config.js +274 -274
- package/lib/devices.js +229 -229
- package/lib/folders.js +124 -124
- package/lib/localCliSessions.js +519 -519
- package/lib/persistedSessions.js +129 -129
- package/lib/tunnel.js +621 -621
- package/lib/webTerminal.js +225 -225
- package/lib/workspace.js +233 -233
- package/package.json +57 -57
- package/public/css/base.css +99 -99
- package/public/css/cards.css +183 -183
- package/public/css/feedback.css +504 -504
- package/public/css/forms.css +453 -453
- package/public/css/layout.css +176 -176
- package/public/css/modal.css +190 -190
- package/public/css/responsive.css +176 -176
- package/public/css/sidebar.css +707 -707
- package/public/css/terminals.css +645 -543
- package/public/css/tokens.css +81 -81
- package/public/css/wco.css +196 -196
- package/public/css/widgets.css +2725 -2725
- package/public/index.html +152 -152
- package/public/js/api.js +371 -371
- package/public/js/backend.js +149 -149
- package/public/js/components/App.js +73 -73
- package/public/js/components/DirectoryPicker.js +203 -203
- package/public/js/components/EntityFormModal.js +153 -153
- package/public/js/components/Modal.js +57 -57
- package/public/js/components/OfflineBanner.js +67 -67
- package/public/js/components/PageTitleBar.js +13 -13
- package/public/js/components/PendingApprovalOverlay.js +128 -128
- package/public/js/components/Picker.js +179 -179
- package/public/js/components/Popover.js +55 -55
- package/public/js/components/RestartOverlay.js +36 -36
- package/public/js/components/Sidebar.js +380 -380
- package/public/js/components/TerminalInstance.js +159 -22
- package/public/js/components/TerminalResizeDebouncer.js +126 -0
- package/public/js/components/TerminalView.js +15 -2
- package/public/js/components/XtermTerminal.js +74 -15
- package/public/js/components/useDragSort.js +67 -67
- package/public/js/dialog.js +67 -67
- package/public/js/icons.js +212 -212
- package/public/js/main.js +296 -296
- package/public/js/pages/AboutPage.js +90 -90
- package/public/js/pages/ConfigurePage.js +713 -713
- package/public/js/pages/LaunchPage.js +421 -421
- package/public/js/pages/RemotePage.js +743 -743
- package/public/js/pages/SessionsPage.js +199 -80
- package/public/js/state.js +335 -335
- package/public/manifest.webmanifest +25 -0
- package/public/setup/index.html +567 -0
- package/scripts/dev.js +149 -149
- package/scripts/install.js +153 -153
- package/scripts/restart-helper.js +96 -96
- package/scripts/upgrade-helper.js +687 -687
- package/server.js +1807 -1807
package/public/css/tokens.css
CHANGED
|
@@ -1,81 +1,81 @@
|
|
|
1
|
-
/* ccsm · design tokens · v0.6 */
|
|
2
|
-
|
|
3
|
-
:root {
|
|
4
|
-
/* Surfaces — pale near-white tinted with the default Ocean accent.
|
|
5
|
-
These match what state.js · applyAccentCssVars computes for the
|
|
6
|
-
#2f6fa3 default, so the first paint (before the inline accent
|
|
7
|
-
script in index.html runs) never flashes the old warm-cream bg. */
|
|
8
|
-
--bg: #f6f8fa;
|
|
9
|
-
--bg-elev: #ffffff;
|
|
10
|
-
--sidebar-bg: #f6f8fa;
|
|
11
|
-
--sidebar-hover: #e2ebf3;
|
|
12
|
-
--sidebar-active: #d3e1ed;
|
|
13
|
-
|
|
14
|
-
/* Neutral UI chrome — borders, footer strip, etc. These are NEVER
|
|
15
|
-
re-derived from the accent so dividers stay calm regardless of
|
|
16
|
-
theme choice. */
|
|
17
|
-
--ui-border: #d8d4c6;
|
|
18
|
-
--ui-border-soft: #e6e2d4;
|
|
19
|
-
--ui-bg: #e2ebf3;
|
|
20
|
-
|
|
21
|
-
/* Borders & rules — tinted with the default Ocean accent to match
|
|
22
|
-
what state.js writes at boot. */
|
|
23
|
-
--border: #d3e1ed;
|
|
24
|
-
--border-soft: #d8e4ee;
|
|
25
|
-
--border-strong: #c0d5e5;
|
|
26
|
-
|
|
27
|
-
/* Ink */
|
|
28
|
-
--ink: #1a1815;
|
|
29
|
-
--ink-mid: #534e44;
|
|
30
|
-
--ink-muted: #8a8475;
|
|
31
|
-
--ink-faint: #b5af9d;
|
|
32
|
-
|
|
33
|
-
/* Accent — Ocean blue. Calm and content-first. Users can override via
|
|
34
|
-
the Theme accent picker in Settings; that flow rewrites these vars
|
|
35
|
-
at runtime (state.js · applyAccentCssVars). */
|
|
36
|
-
--accent: #2f6fa3;
|
|
37
|
-
--accent-deep: #25577f;
|
|
38
|
-
--accent-soft: rgba(47, 111, 163, 0.10);
|
|
39
|
-
--accent-softer: rgba(47, 111, 163, 0.04);
|
|
40
|
-
|
|
41
|
-
/* Status */
|
|
42
|
-
--green: #4a8a4a;
|
|
43
|
-
--yellow: #c4892b;
|
|
44
|
-
--red: #b73f3f;
|
|
45
|
-
--blue: #4a73a5;
|
|
46
|
-
|
|
47
|
-
/* Type */
|
|
48
|
-
--body: "Geist", ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
|
49
|
-
--display: "Geist", ui-sans-serif, system-ui, sans-serif;
|
|
50
|
-
--mono: "JetBrains Mono", "Cascadia Mono", "Consolas", monospace;
|
|
51
|
-
|
|
52
|
-
/* Scale */
|
|
53
|
-
--s-1: 4px; --s-2: 8px; --s-3: 12px; --s-4: 16px;
|
|
54
|
-
--s-5: 20px; --s-6: 24px; --s-8: 32px; --s-10: 40px;
|
|
55
|
-
--s-12: 48px; --s-16: 64px;
|
|
56
|
-
|
|
57
|
-
/* Radius — tightened in v1.0 for a more codex-like crisp feel.
|
|
58
|
-
999px stays in code where pills are intentional (status dots etc). */
|
|
59
|
-
--r-sm: 3px;
|
|
60
|
-
--r: 4px;
|
|
61
|
-
--r-md: 5px;
|
|
62
|
-
--r-lg: 6px;
|
|
63
|
-
|
|
64
|
-
/* Shadow — soft, like print on cream */
|
|
65
|
-
--shadow-sm: 0 1px 0 rgba(26, 24, 21, 0.04);
|
|
66
|
-
--shadow: 0 1px 2px rgba(26, 24, 21, 0.04),
|
|
67
|
-
0 1px 0 rgba(26, 24, 21, 0.03);
|
|
68
|
-
--shadow-md: 0 4px 12px -2px rgba(26, 24, 21, 0.08),
|
|
69
|
-
0 1px 0 rgba(26, 24, 21, 0.04);
|
|
70
|
-
--shadow-lg: 0 18px 40px -16px rgba(26, 24, 21, 0.18),
|
|
71
|
-
0 4px 12px -4px rgba(26, 24, 21, 0.10);
|
|
72
|
-
|
|
73
|
-
/* Subtle paper grain — applied as a layered background on .app to give
|
|
74
|
-
surfaces the texture of laid paper rather than flat color. SVG noise
|
|
75
|
-
keeps it crisp at any zoom level. */
|
|
76
|
-
--paper-noise: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='160' height='160'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 0.10 0 0 0 0 0.09 0 0 0 0 0.07 0 0 0 0.035 0'/></filter><rect width='100%25' height='100%25' filter='url(%23n)'/></svg>");
|
|
77
|
-
|
|
78
|
-
/* Sidebar geometry */
|
|
79
|
-
--sidebar-w: 232px;
|
|
80
|
-
--sidebar-w-collapsed: 44px;
|
|
81
|
-
}
|
|
1
|
+
/* ccsm · design tokens · v0.6 */
|
|
2
|
+
|
|
3
|
+
:root {
|
|
4
|
+
/* Surfaces — pale near-white tinted with the default Ocean accent.
|
|
5
|
+
These match what state.js · applyAccentCssVars computes for the
|
|
6
|
+
#2f6fa3 default, so the first paint (before the inline accent
|
|
7
|
+
script in index.html runs) never flashes the old warm-cream bg. */
|
|
8
|
+
--bg: #f6f8fa;
|
|
9
|
+
--bg-elev: #ffffff;
|
|
10
|
+
--sidebar-bg: #f6f8fa;
|
|
11
|
+
--sidebar-hover: #e2ebf3;
|
|
12
|
+
--sidebar-active: #d3e1ed;
|
|
13
|
+
|
|
14
|
+
/* Neutral UI chrome — borders, footer strip, etc. These are NEVER
|
|
15
|
+
re-derived from the accent so dividers stay calm regardless of
|
|
16
|
+
theme choice. */
|
|
17
|
+
--ui-border: #d8d4c6;
|
|
18
|
+
--ui-border-soft: #e6e2d4;
|
|
19
|
+
--ui-bg: #e2ebf3;
|
|
20
|
+
|
|
21
|
+
/* Borders & rules — tinted with the default Ocean accent to match
|
|
22
|
+
what state.js writes at boot. */
|
|
23
|
+
--border: #d3e1ed;
|
|
24
|
+
--border-soft: #d8e4ee;
|
|
25
|
+
--border-strong: #c0d5e5;
|
|
26
|
+
|
|
27
|
+
/* Ink */
|
|
28
|
+
--ink: #1a1815;
|
|
29
|
+
--ink-mid: #534e44;
|
|
30
|
+
--ink-muted: #8a8475;
|
|
31
|
+
--ink-faint: #b5af9d;
|
|
32
|
+
|
|
33
|
+
/* Accent — Ocean blue. Calm and content-first. Users can override via
|
|
34
|
+
the Theme accent picker in Settings; that flow rewrites these vars
|
|
35
|
+
at runtime (state.js · applyAccentCssVars). */
|
|
36
|
+
--accent: #2f6fa3;
|
|
37
|
+
--accent-deep: #25577f;
|
|
38
|
+
--accent-soft: rgba(47, 111, 163, 0.10);
|
|
39
|
+
--accent-softer: rgba(47, 111, 163, 0.04);
|
|
40
|
+
|
|
41
|
+
/* Status */
|
|
42
|
+
--green: #4a8a4a;
|
|
43
|
+
--yellow: #c4892b;
|
|
44
|
+
--red: #b73f3f;
|
|
45
|
+
--blue: #4a73a5;
|
|
46
|
+
|
|
47
|
+
/* Type */
|
|
48
|
+
--body: "Geist", ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
|
49
|
+
--display: "Geist", ui-sans-serif, system-ui, sans-serif;
|
|
50
|
+
--mono: "JetBrains Mono", "Cascadia Mono", "Consolas", monospace;
|
|
51
|
+
|
|
52
|
+
/* Scale */
|
|
53
|
+
--s-1: 4px; --s-2: 8px; --s-3: 12px; --s-4: 16px;
|
|
54
|
+
--s-5: 20px; --s-6: 24px; --s-8: 32px; --s-10: 40px;
|
|
55
|
+
--s-12: 48px; --s-16: 64px;
|
|
56
|
+
|
|
57
|
+
/* Radius — tightened in v1.0 for a more codex-like crisp feel.
|
|
58
|
+
999px stays in code where pills are intentional (status dots etc). */
|
|
59
|
+
--r-sm: 3px;
|
|
60
|
+
--r: 4px;
|
|
61
|
+
--r-md: 5px;
|
|
62
|
+
--r-lg: 6px;
|
|
63
|
+
|
|
64
|
+
/* Shadow — soft, like print on cream */
|
|
65
|
+
--shadow-sm: 0 1px 0 rgba(26, 24, 21, 0.04);
|
|
66
|
+
--shadow: 0 1px 2px rgba(26, 24, 21, 0.04),
|
|
67
|
+
0 1px 0 rgba(26, 24, 21, 0.03);
|
|
68
|
+
--shadow-md: 0 4px 12px -2px rgba(26, 24, 21, 0.08),
|
|
69
|
+
0 1px 0 rgba(26, 24, 21, 0.04);
|
|
70
|
+
--shadow-lg: 0 18px 40px -16px rgba(26, 24, 21, 0.18),
|
|
71
|
+
0 4px 12px -4px rgba(26, 24, 21, 0.10);
|
|
72
|
+
|
|
73
|
+
/* Subtle paper grain — applied as a layered background on .app to give
|
|
74
|
+
surfaces the texture of laid paper rather than flat color. SVG noise
|
|
75
|
+
keeps it crisp at any zoom level. */
|
|
76
|
+
--paper-noise: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='160' height='160'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 0.10 0 0 0 0 0.09 0 0 0 0 0.07 0 0 0 0.035 0'/></filter><rect width='100%25' height='100%25' filter='url(%23n)'/></svg>");
|
|
77
|
+
|
|
78
|
+
/* Sidebar geometry */
|
|
79
|
+
--sidebar-w: 232px;
|
|
80
|
+
--sidebar-w-collapsed: 44px;
|
|
81
|
+
}
|
package/public/css/wco.css
CHANGED
|
@@ -1,196 +1,196 @@
|
|
|
1
|
-
/* PWA / --app= window drag regions.
|
|
2
|
-
*
|
|
3
|
-
* `-webkit-app-region: drag` is a Chromium-only property; it has effect in
|
|
4
|
-
* Electron, installed PWA windows, AND in `--app=` chromeless mode where
|
|
5
|
-
* the manifest's display_override unlocks WCO-ish behaviour. In a plain
|
|
6
|
-
* browser tab it's silently ignored. We therefore apply it *unconditionally*
|
|
7
|
-
* (no `@media (display-mode: …)` gate) so any surface that does honour it
|
|
8
|
-
* gets the drag handles — particularly the case where Edge `--app=` reads
|
|
9
|
-
* our manifest, hides its own OS title bar, but still reports
|
|
10
|
-
* display-mode: browser. Without unconditional rules, that window has
|
|
11
|
-
* neither a native title bar to grab NOR app-region drag → undraggable.
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
.sidebar-brand,
|
|
15
|
-
.sidebar-top,
|
|
16
|
-
.page-title-bar,
|
|
17
|
-
.page-head,
|
|
18
|
-
.page-head-inner,
|
|
19
|
-
.page-title,
|
|
20
|
-
.page-subtitle {
|
|
21
|
-
-webkit-app-region: drag;
|
|
22
|
-
app-region: drag;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/* Any interactive element opts out of drag so click / focus / scroll
|
|
26
|
-
still reach the page. */
|
|
27
|
-
button, a, input, select, textarea, label,
|
|
28
|
-
.nav-item, .util-item, .collapse-toggle,
|
|
29
|
-
.action, .server-status,
|
|
30
|
-
.star-btn, .rename-btn, .card-fold, .modal-close,
|
|
31
|
-
.chip, .radio, .fab,
|
|
32
|
-
.ph-stat, .ph-divider,
|
|
33
|
-
.page-title-bar-actions,
|
|
34
|
-
.session-title-action {
|
|
35
|
-
-webkit-app-region: no-drag;
|
|
36
|
-
app-region: no-drag;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
body.is-app .sidebar-brand,
|
|
40
|
-
body.is-app .sidebar-top,
|
|
41
|
-
body.is-app .page-title-bar,
|
|
42
|
-
body.is-app .page-head,
|
|
43
|
-
body.is-app .page-head-inner,
|
|
44
|
-
body.is-app .page-title,
|
|
45
|
-
body.is-app .page-subtitle {
|
|
46
|
-
user-select: none;
|
|
47
|
-
-webkit-user-select: none;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/* In an app/PWA window, the OS title bar is hidden and only floating
|
|
51
|
-
close/max/min controls remain in the top-right. The 40px top band of
|
|
52
|
-
ccsm (sidebar-top + page-title-bar) IS that title bar — it's already
|
|
53
|
-
tall enough, sits at y=0 with no extra padding, and gets a drag region
|
|
54
|
-
so the user can grab anywhere along it to move the window. */
|
|
55
|
-
body.is-app .sidebar { padding-top: 0; }
|
|
56
|
-
body.is-app .main { padding-top: 0; }
|
|
57
|
-
|
|
58
|
-
body.is-app .page-title,
|
|
59
|
-
body.is-app .page-subtitle {
|
|
60
|
-
display: none;
|
|
61
|
-
}
|
|
62
|
-
body.is-app .page-head {
|
|
63
|
-
padding-bottom: 0;
|
|
64
|
-
border-bottom: 0;
|
|
65
|
-
align-items: center;
|
|
66
|
-
min-height: 28px;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
/* Standalone PWA (browser still paints its own title bar above our
|
|
70
|
-
document): suppress our duplicate chrome — the brand mark + collapse
|
|
71
|
-
row at top-left of the sidebar AND the page-title-bar header — since
|
|
72
|
-
the OS title bar already shows the app name and serves as the visual
|
|
73
|
-
header. With sidebar-top hidden, the nav tabs (Sessions/Launch/…)
|
|
74
|
-
float up to start at the very top of the sidebar column. A 1px
|
|
75
|
-
border-top across the whole app grid gives the OS title bar something
|
|
76
|
-
to rest against instead of bleeding straight into our content. */
|
|
77
|
-
body.is-app:not(.is-wco) .sidebar-top {
|
|
78
|
-
display: none;
|
|
79
|
-
}
|
|
80
|
-
body.is-app:not(.is-wco) .page-title-bar {
|
|
81
|
-
display: none;
|
|
82
|
-
}
|
|
83
|
-
/* terminals.css uses `.page-title-bar + .session-tabs { margin-top: -s-4 }`
|
|
84
|
-
to flush the tab strip against the in-page title-bar. Adjacent-sibling
|
|
85
|
-
selectors match by DOM order regardless of display, so the rule still
|
|
86
|
-
pulls session-tabs up by 16px even when the title-bar is hidden — the
|
|
87
|
-
top half of the tabs ends up clipped above the viewport / under the OS
|
|
88
|
-
title bar. Reset to 0 in standalone PWA. */
|
|
89
|
-
body.is-app:not(.is-wco) .page-title-bar + .session-tabs {
|
|
90
|
-
margin-top: 0;
|
|
91
|
-
}
|
|
92
|
-
body.is-app:not(.is-wco) .app {
|
|
93
|
-
/* Hairline separator under the OS title bar. Has to sit ABOVE the
|
|
94
|
-
sidebar's own background — an inset box-shadow on .app gets covered
|
|
95
|
-
by .sidebar (which paints var(--ui-bg) across its full area inside
|
|
96
|
-
.app), so the line was invisible. An absolutely-positioned ::before
|
|
97
|
-
paints over both columns; it's outside the grid track so it doesn't
|
|
98
|
-
reintroduce the 1px overflow that a real `border-top: 1px` did. */
|
|
99
|
-
position: relative;
|
|
100
|
-
}
|
|
101
|
-
body.is-app:not(.is-wco) .app::before {
|
|
102
|
-
content: "";
|
|
103
|
-
position: absolute;
|
|
104
|
-
top: 0;
|
|
105
|
-
left: 0;
|
|
106
|
-
right: 0;
|
|
107
|
-
height: 1px;
|
|
108
|
-
background: var(--border);
|
|
109
|
-
z-index: 10;
|
|
110
|
-
pointer-events: none;
|
|
111
|
-
}
|
|
112
|
-
/* With page-title-bar hidden, session-pane's `margin-top: calc(-1 *
|
|
113
|
-
var(--s-4))` — designed to flush it against the (now invisible)
|
|
114
|
-
title-bar — would otherwise yank the terminal up into the OS title-bar
|
|
115
|
-
border. Zero the margin AND drop session-pane's `height: 100%` so flex
|
|
116
|
-
does all the height math; otherwise the height: 100% double-counts and
|
|
117
|
-
creates dead space at the bottom. */
|
|
118
|
-
body.is-app:not(.is-wco) .session-pane {
|
|
119
|
-
margin-top: 0;
|
|
120
|
-
height: auto;
|
|
121
|
-
}
|
|
122
|
-
/* Settings + Launch · with the in-page title-bar hidden in standalone
|
|
123
|
-
mode, their content would otherwise butt straight against the OS
|
|
124
|
-
title-bar border. Give a little breathing room. Sessions has its
|
|
125
|
-
own full-bleed terminal pane; About has its own hero header. */
|
|
126
|
-
body.is-app:not(.is-wco) [data-panel="configure"],
|
|
127
|
-
body.is-app:not(.is-wco) [data-panel="launch"],
|
|
128
|
-
body.is-app:not(.is-wco) [data-panel="remote"] {
|
|
129
|
-
padding-top: var(--s-4);
|
|
130
|
-
}
|
|
131
|
-
/* Sidebar nav rows (New Session / Settings) also need a top gap in
|
|
132
|
-
standalone — body.is-app zeros .sidebar's padding-top so the in-page
|
|
133
|
-
title-bar can sit flush, but with that title-bar gone in standalone
|
|
134
|
-
mode the nav buttons end up jammed against the OS title-bar border.
|
|
135
|
-
Restore a small inset so they read as a real nav, not as overflow. */
|
|
136
|
-
body.is-app:not(.is-wco) .sidebar { padding-top: var(--s-3); }
|
|
137
|
-
|
|
138
|
-
/* WCO mode only: the browser has hidden its own title bar and floats OS
|
|
139
|
-
controls (min/max/close) over our content top-right. Our 34px top band
|
|
140
|
-
IS the title bar in that case — it gets shrunk to match the OS control
|
|
141
|
-
strip height, and reserves a right-side padding so action buttons don't
|
|
142
|
-
slide under those floating controls. 150px covers Windows controls
|
|
143
|
-
(~46px × 3) with breathing room; the env() override below uses the
|
|
144
|
-
precise titlebar-area-width when the browser exposes it.
|
|
145
|
-
In plain standalone PWA (browser still paints its own title bar above
|
|
146
|
-
our document), none of this applies — our page-title-bar behaves like
|
|
147
|
-
a normal 40px page header from layout.css. */
|
|
148
|
-
body.is-wco .page-title-bar {
|
|
149
|
-
padding-right: calc(var(--s-4) + 150px);
|
|
150
|
-
}
|
|
151
|
-
body.is-wco .page-title-bar,
|
|
152
|
-
body.is-wco .sidebar-top {
|
|
153
|
-
/* --titlebar-h is set from JS reading
|
|
154
|
-
navigator.windowControlsOverlay.getTitlebarAreaRect().height — the
|
|
155
|
-
OS-reported strip the overlay reserves for us. CSS env() and a 32px
|
|
156
|
-
baseline are layered fallbacks when the JS API is unavailable. No
|
|
157
|
-
min-floor on the JS path: the OS knows its own caption height best,
|
|
158
|
-
and over-padding (the previous max(40px, …)) made the chrome look
|
|
159
|
-
visibly chunkier than the rest of the window. */
|
|
160
|
-
/* `max(36px, …)` floors the anti-zoom shrink — at heavy page zoom the
|
|
161
|
-
counter-scale would otherwise collapse the WCO strip past the OS
|
|
162
|
-
control row height, jamming the brand mark / collapse toggle into
|
|
163
|
-
the title text. 36px matches the standalone page-title-bar floor
|
|
164
|
-
in layout.css so both modes degrade to the same minimum. */
|
|
165
|
-
height: max(36px, calc(var(--titlebar-h, env(titlebar-area-height, 32px)) * var(--anti-zoom, 1)));
|
|
166
|
-
min-height: max(36px, calc(var(--titlebar-h, env(titlebar-area-height, 32px)) * var(--anti-zoom, 1)));
|
|
167
|
-
max-height: max(36px, calc(var(--titlebar-h, env(titlebar-area-height, 32px)) * var(--anti-zoom, 1)));
|
|
168
|
-
}
|
|
169
|
-
body.is-wco .sidebar-brand,
|
|
170
|
-
body.is-wco .sidebar-brand-button,
|
|
171
|
-
body.is-wco .collapse-toggle {
|
|
172
|
-
height: var(--titlebar-h, env(titlebar-area-height, 32px));
|
|
173
|
-
min-height: var(--titlebar-h, env(titlebar-area-height, 32px));
|
|
174
|
-
}
|
|
175
|
-
/* terminals.css uses the .tab-panel's gap (s-4) plus a -s-4 margin-top on
|
|
176
|
-
.session-tabs to close that gap, so the tab strip visually flushes
|
|
177
|
-
against the page-title-bar above. In WCO the negative margin pulls the
|
|
178
|
-
tabs row UP by 16px — i.e. its top edge lands ABOVE the OS overlay's
|
|
179
|
-
bottom edge, and the kebab inside gets clipped by the floating window
|
|
180
|
-
controls. Cancel both the gap and the negative margin here so the tabs
|
|
181
|
-
row sits at exactly y=titlebar-area-height (flush below the overlay)
|
|
182
|
-
without losing flushness against the title-bar. */
|
|
183
|
-
body.is-wco .tab-panel { gap: 0; }
|
|
184
|
-
body.is-wco .page-title-bar + .session-tabs { margin-top: 0; }
|
|
185
|
-
/* terminals.css also gives .session-tabs `margin-bottom: -s-4` to close
|
|
186
|
-
the gap to session-pane below — but with tab-panel gap now 0 in WCO
|
|
187
|
-
that negative margin pulls session-pane UP 16px instead, overlapping
|
|
188
|
-
the bottom of the tab labels (kebab + tab text get clipped from
|
|
189
|
-
below). Zero it out too. */
|
|
190
|
-
body.is-wco .session-tabs { margin-bottom: 0; }
|
|
191
|
-
|
|
192
|
-
@media (display-mode: window-controls-overlay) {
|
|
193
|
-
body.is-wco .page-title-bar {
|
|
194
|
-
padding-right: calc(var(--s-4) + 100vw - env(titlebar-area-width, 100vw));
|
|
195
|
-
}
|
|
196
|
-
}
|
|
1
|
+
/* PWA / --app= window drag regions.
|
|
2
|
+
*
|
|
3
|
+
* `-webkit-app-region: drag` is a Chromium-only property; it has effect in
|
|
4
|
+
* Electron, installed PWA windows, AND in `--app=` chromeless mode where
|
|
5
|
+
* the manifest's display_override unlocks WCO-ish behaviour. In a plain
|
|
6
|
+
* browser tab it's silently ignored. We therefore apply it *unconditionally*
|
|
7
|
+
* (no `@media (display-mode: …)` gate) so any surface that does honour it
|
|
8
|
+
* gets the drag handles — particularly the case where Edge `--app=` reads
|
|
9
|
+
* our manifest, hides its own OS title bar, but still reports
|
|
10
|
+
* display-mode: browser. Without unconditional rules, that window has
|
|
11
|
+
* neither a native title bar to grab NOR app-region drag → undraggable.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
.sidebar-brand,
|
|
15
|
+
.sidebar-top,
|
|
16
|
+
.page-title-bar,
|
|
17
|
+
.page-head,
|
|
18
|
+
.page-head-inner,
|
|
19
|
+
.page-title,
|
|
20
|
+
.page-subtitle {
|
|
21
|
+
-webkit-app-region: drag;
|
|
22
|
+
app-region: drag;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/* Any interactive element opts out of drag so click / focus / scroll
|
|
26
|
+
still reach the page. */
|
|
27
|
+
button, a, input, select, textarea, label,
|
|
28
|
+
.nav-item, .util-item, .collapse-toggle,
|
|
29
|
+
.action, .server-status,
|
|
30
|
+
.star-btn, .rename-btn, .card-fold, .modal-close,
|
|
31
|
+
.chip, .radio, .fab,
|
|
32
|
+
.ph-stat, .ph-divider,
|
|
33
|
+
.page-title-bar-actions,
|
|
34
|
+
.session-title-action {
|
|
35
|
+
-webkit-app-region: no-drag;
|
|
36
|
+
app-region: no-drag;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
body.is-app .sidebar-brand,
|
|
40
|
+
body.is-app .sidebar-top,
|
|
41
|
+
body.is-app .page-title-bar,
|
|
42
|
+
body.is-app .page-head,
|
|
43
|
+
body.is-app .page-head-inner,
|
|
44
|
+
body.is-app .page-title,
|
|
45
|
+
body.is-app .page-subtitle {
|
|
46
|
+
user-select: none;
|
|
47
|
+
-webkit-user-select: none;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/* In an app/PWA window, the OS title bar is hidden and only floating
|
|
51
|
+
close/max/min controls remain in the top-right. The 40px top band of
|
|
52
|
+
ccsm (sidebar-top + page-title-bar) IS that title bar — it's already
|
|
53
|
+
tall enough, sits at y=0 with no extra padding, and gets a drag region
|
|
54
|
+
so the user can grab anywhere along it to move the window. */
|
|
55
|
+
body.is-app .sidebar { padding-top: 0; }
|
|
56
|
+
body.is-app .main { padding-top: 0; }
|
|
57
|
+
|
|
58
|
+
body.is-app .page-title,
|
|
59
|
+
body.is-app .page-subtitle {
|
|
60
|
+
display: none;
|
|
61
|
+
}
|
|
62
|
+
body.is-app .page-head {
|
|
63
|
+
padding-bottom: 0;
|
|
64
|
+
border-bottom: 0;
|
|
65
|
+
align-items: center;
|
|
66
|
+
min-height: 28px;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/* Standalone PWA (browser still paints its own title bar above our
|
|
70
|
+
document): suppress our duplicate chrome — the brand mark + collapse
|
|
71
|
+
row at top-left of the sidebar AND the page-title-bar header — since
|
|
72
|
+
the OS title bar already shows the app name and serves as the visual
|
|
73
|
+
header. With sidebar-top hidden, the nav tabs (Sessions/Launch/…)
|
|
74
|
+
float up to start at the very top of the sidebar column. A 1px
|
|
75
|
+
border-top across the whole app grid gives the OS title bar something
|
|
76
|
+
to rest against instead of bleeding straight into our content. */
|
|
77
|
+
body.is-app:not(.is-wco) .sidebar-top {
|
|
78
|
+
display: none;
|
|
79
|
+
}
|
|
80
|
+
body.is-app:not(.is-wco) .page-title-bar {
|
|
81
|
+
display: none;
|
|
82
|
+
}
|
|
83
|
+
/* terminals.css uses `.page-title-bar + .session-tabs { margin-top: -s-4 }`
|
|
84
|
+
to flush the tab strip against the in-page title-bar. Adjacent-sibling
|
|
85
|
+
selectors match by DOM order regardless of display, so the rule still
|
|
86
|
+
pulls session-tabs up by 16px even when the title-bar is hidden — the
|
|
87
|
+
top half of the tabs ends up clipped above the viewport / under the OS
|
|
88
|
+
title bar. Reset to 0 in standalone PWA. */
|
|
89
|
+
body.is-app:not(.is-wco) .page-title-bar + .session-tabs {
|
|
90
|
+
margin-top: 0;
|
|
91
|
+
}
|
|
92
|
+
body.is-app:not(.is-wco) .app {
|
|
93
|
+
/* Hairline separator under the OS title bar. Has to sit ABOVE the
|
|
94
|
+
sidebar's own background — an inset box-shadow on .app gets covered
|
|
95
|
+
by .sidebar (which paints var(--ui-bg) across its full area inside
|
|
96
|
+
.app), so the line was invisible. An absolutely-positioned ::before
|
|
97
|
+
paints over both columns; it's outside the grid track so it doesn't
|
|
98
|
+
reintroduce the 1px overflow that a real `border-top: 1px` did. */
|
|
99
|
+
position: relative;
|
|
100
|
+
}
|
|
101
|
+
body.is-app:not(.is-wco) .app::before {
|
|
102
|
+
content: "";
|
|
103
|
+
position: absolute;
|
|
104
|
+
top: 0;
|
|
105
|
+
left: 0;
|
|
106
|
+
right: 0;
|
|
107
|
+
height: 1px;
|
|
108
|
+
background: var(--border);
|
|
109
|
+
z-index: 10;
|
|
110
|
+
pointer-events: none;
|
|
111
|
+
}
|
|
112
|
+
/* With page-title-bar hidden, session-pane's `margin-top: calc(-1 *
|
|
113
|
+
var(--s-4))` — designed to flush it against the (now invisible)
|
|
114
|
+
title-bar — would otherwise yank the terminal up into the OS title-bar
|
|
115
|
+
border. Zero the margin AND drop session-pane's `height: 100%` so flex
|
|
116
|
+
does all the height math; otherwise the height: 100% double-counts and
|
|
117
|
+
creates dead space at the bottom. */
|
|
118
|
+
body.is-app:not(.is-wco) .session-pane {
|
|
119
|
+
margin-top: 0;
|
|
120
|
+
height: auto;
|
|
121
|
+
}
|
|
122
|
+
/* Settings + Launch · with the in-page title-bar hidden in standalone
|
|
123
|
+
mode, their content would otherwise butt straight against the OS
|
|
124
|
+
title-bar border. Give a little breathing room. Sessions has its
|
|
125
|
+
own full-bleed terminal pane; About has its own hero header. */
|
|
126
|
+
body.is-app:not(.is-wco) [data-panel="configure"],
|
|
127
|
+
body.is-app:not(.is-wco) [data-panel="launch"],
|
|
128
|
+
body.is-app:not(.is-wco) [data-panel="remote"] {
|
|
129
|
+
padding-top: var(--s-4);
|
|
130
|
+
}
|
|
131
|
+
/* Sidebar nav rows (New Session / Settings) also need a top gap in
|
|
132
|
+
standalone — body.is-app zeros .sidebar's padding-top so the in-page
|
|
133
|
+
title-bar can sit flush, but with that title-bar gone in standalone
|
|
134
|
+
mode the nav buttons end up jammed against the OS title-bar border.
|
|
135
|
+
Restore a small inset so they read as a real nav, not as overflow. */
|
|
136
|
+
body.is-app:not(.is-wco) .sidebar { padding-top: var(--s-3); }
|
|
137
|
+
|
|
138
|
+
/* WCO mode only: the browser has hidden its own title bar and floats OS
|
|
139
|
+
controls (min/max/close) over our content top-right. Our 34px top band
|
|
140
|
+
IS the title bar in that case — it gets shrunk to match the OS control
|
|
141
|
+
strip height, and reserves a right-side padding so action buttons don't
|
|
142
|
+
slide under those floating controls. 150px covers Windows controls
|
|
143
|
+
(~46px × 3) with breathing room; the env() override below uses the
|
|
144
|
+
precise titlebar-area-width when the browser exposes it.
|
|
145
|
+
In plain standalone PWA (browser still paints its own title bar above
|
|
146
|
+
our document), none of this applies — our page-title-bar behaves like
|
|
147
|
+
a normal 40px page header from layout.css. */
|
|
148
|
+
body.is-wco .page-title-bar {
|
|
149
|
+
padding-right: calc(var(--s-4) + 150px);
|
|
150
|
+
}
|
|
151
|
+
body.is-wco .page-title-bar,
|
|
152
|
+
body.is-wco .sidebar-top {
|
|
153
|
+
/* --titlebar-h is set from JS reading
|
|
154
|
+
navigator.windowControlsOverlay.getTitlebarAreaRect().height — the
|
|
155
|
+
OS-reported strip the overlay reserves for us. CSS env() and a 32px
|
|
156
|
+
baseline are layered fallbacks when the JS API is unavailable. No
|
|
157
|
+
min-floor on the JS path: the OS knows its own caption height best,
|
|
158
|
+
and over-padding (the previous max(40px, …)) made the chrome look
|
|
159
|
+
visibly chunkier than the rest of the window. */
|
|
160
|
+
/* `max(36px, …)` floors the anti-zoom shrink — at heavy page zoom the
|
|
161
|
+
counter-scale would otherwise collapse the WCO strip past the OS
|
|
162
|
+
control row height, jamming the brand mark / collapse toggle into
|
|
163
|
+
the title text. 36px matches the standalone page-title-bar floor
|
|
164
|
+
in layout.css so both modes degrade to the same minimum. */
|
|
165
|
+
height: max(36px, calc(var(--titlebar-h, env(titlebar-area-height, 32px)) * var(--anti-zoom, 1)));
|
|
166
|
+
min-height: max(36px, calc(var(--titlebar-h, env(titlebar-area-height, 32px)) * var(--anti-zoom, 1)));
|
|
167
|
+
max-height: max(36px, calc(var(--titlebar-h, env(titlebar-area-height, 32px)) * var(--anti-zoom, 1)));
|
|
168
|
+
}
|
|
169
|
+
body.is-wco .sidebar-brand,
|
|
170
|
+
body.is-wco .sidebar-brand-button,
|
|
171
|
+
body.is-wco .collapse-toggle {
|
|
172
|
+
height: var(--titlebar-h, env(titlebar-area-height, 32px));
|
|
173
|
+
min-height: var(--titlebar-h, env(titlebar-area-height, 32px));
|
|
174
|
+
}
|
|
175
|
+
/* terminals.css uses the .tab-panel's gap (s-4) plus a -s-4 margin-top on
|
|
176
|
+
.session-tabs to close that gap, so the tab strip visually flushes
|
|
177
|
+
against the page-title-bar above. In WCO the negative margin pulls the
|
|
178
|
+
tabs row UP by 16px — i.e. its top edge lands ABOVE the OS overlay's
|
|
179
|
+
bottom edge, and the kebab inside gets clipped by the floating window
|
|
180
|
+
controls. Cancel both the gap and the negative margin here so the tabs
|
|
181
|
+
row sits at exactly y=titlebar-area-height (flush below the overlay)
|
|
182
|
+
without losing flushness against the title-bar. */
|
|
183
|
+
body.is-wco .tab-panel { gap: 0; }
|
|
184
|
+
body.is-wco .page-title-bar + .session-tabs { margin-top: 0; }
|
|
185
|
+
/* terminals.css also gives .session-tabs `margin-bottom: -s-4` to close
|
|
186
|
+
the gap to session-pane below — but with tab-panel gap now 0 in WCO
|
|
187
|
+
that negative margin pulls session-pane UP 16px instead, overlapping
|
|
188
|
+
the bottom of the tab labels (kebab + tab text get clipped from
|
|
189
|
+
below). Zero it out too. */
|
|
190
|
+
body.is-wco .session-tabs { margin-bottom: 0; }
|
|
191
|
+
|
|
192
|
+
@media (display-mode: window-controls-overlay) {
|
|
193
|
+
body.is-wco .page-title-bar {
|
|
194
|
+
padding-right: calc(var(--s-4) + 100vw - env(titlebar-area-width, 100vw));
|
|
195
|
+
}
|
|
196
|
+
}
|