@bakapiano/ccsm 0.9.0 → 0.10.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/CLAUDE.md +222 -195
- package/README.md +77 -79
- package/lib/cliSessionWatcher.js +249 -0
- package/lib/config.js +101 -24
- package/lib/folders.js +96 -0
- package/lib/localCliSessions.js +177 -0
- package/lib/persistedSessions.js +134 -0
- package/lib/webTerminal.js +31 -18
- package/lib/workspace.js +26 -4
- package/package.json +1 -1
- package/public/assets/claude-color.svg +1 -0
- package/public/assets/codex-color.svg +1 -0
- package/public/assets/copilot-color.svg +1 -0
- package/public/css/base.css +22 -5
- package/public/css/cards.css +37 -3
- package/public/css/feedback.css +127 -43
- package/public/css/forms.css +97 -25
- package/public/css/layout.css +74 -26
- package/public/css/modal.css +40 -26
- package/public/css/responsive.css +2 -2
- package/public/css/sidebar.css +424 -25
- package/public/css/terminals.css +138 -0
- package/public/css/tokens.css +28 -12
- package/public/css/wco.css +38 -39
- package/public/css/widgets.css +1177 -6
- package/public/index.html +35 -2
- package/public/js/api.js +194 -37
- package/public/js/components/AdoptModal.js +171 -0
- package/public/js/components/App.js +1 -11
- package/public/js/components/DirectoryPicker.js +203 -0
- package/public/js/components/EntityFormModal.js +105 -0
- package/public/js/components/Modal.js +51 -0
- package/public/js/components/OfflineBanner.js +29 -23
- package/public/js/components/PageTitleBar.js +13 -0
- package/public/js/components/Picker.js +179 -0
- package/public/js/components/Popover.js +55 -0
- package/public/js/components/Sidebar.js +219 -32
- package/public/js/components/TerminalView.js +27 -3
- package/public/js/components/useDragSort.js +67 -0
- package/public/js/dialog.js +10 -2
- package/public/js/icons.js +66 -3
- package/public/js/main.js +54 -3
- package/public/js/pages/AboutPage.js +80 -0
- package/public/js/pages/ConfigurePage.js +429 -207
- package/public/js/pages/LaunchPage.js +326 -86
- package/public/js/pages/SessionsPage.js +91 -41
- package/public/js/state.js +102 -73
- package/public/manifest.webmanifest +2 -2
- package/scripts/install.js +7 -2
- package/server.js +755 -441
- package/lib/favorites.js +0 -51
- package/lib/focus.js +0 -369
- package/lib/labels.js +0 -29
- package/lib/launcher.js +0 -219
- package/lib/sessions.js +0 -272
- package/lib/snapshot.js +0 -141
- package/public/js/actions.js +0 -107
- package/public/js/components/Fab.js +0 -11
- package/public/js/components/FavoritesTable.js +0 -81
- package/public/js/components/Footer.js +0 -12
- package/public/js/components/NewSessionModal.js +0 -153
- package/public/js/components/PageHead.js +0 -33
- package/public/js/components/Pagination.js +0 -27
- package/public/js/components/RecentTable.js +0 -68
- package/public/js/components/SessionsTable.js +0 -71
- package/public/js/components/SnapshotPanel.js +0 -77
- package/public/js/components/TitleCell.js +0 -40
- package/public/js/components/WorkspacesGrid.js +0 -41
- package/public/js/pages/TerminalsPage.js +0 -74
package/public/css/cards.css
CHANGED
|
@@ -2,10 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
.card {
|
|
4
4
|
background: var(--bg-elev);
|
|
5
|
-
border: 1px solid var(--border);
|
|
6
|
-
border-radius:
|
|
5
|
+
border: 1px solid var(--border-soft);
|
|
6
|
+
border-radius: 6px;
|
|
7
7
|
overflow: hidden;
|
|
8
8
|
box-shadow: var(--shadow);
|
|
9
|
+
transition: box-shadow .2s ease, border-color .2s ease, transform .2s ease;
|
|
10
|
+
}
|
|
11
|
+
.card:hover {
|
|
12
|
+
box-shadow: var(--shadow-md);
|
|
13
|
+
border-color: var(--border);
|
|
9
14
|
}
|
|
10
15
|
|
|
11
16
|
.card-head {
|
|
@@ -56,6 +61,7 @@
|
|
|
56
61
|
font-weight: 600;
|
|
57
62
|
letter-spacing: -0.012em;
|
|
58
63
|
color: var(--ink);
|
|
64
|
+
line-height: 1.2;
|
|
59
65
|
}
|
|
60
66
|
.card-title .title-icon {
|
|
61
67
|
color: var(--ink-mid);
|
|
@@ -92,10 +98,11 @@
|
|
|
92
98
|
.about-mark { display: inline-flex; }
|
|
93
99
|
.about-mark svg { width: 48px; height: 48px; }
|
|
94
100
|
.about-name {
|
|
95
|
-
font-size:
|
|
101
|
+
font-size: 22px;
|
|
96
102
|
font-weight: 600;
|
|
97
103
|
letter-spacing: -0.02em;
|
|
98
104
|
color: var(--ink);
|
|
105
|
+
line-height: 1.1;
|
|
99
106
|
}
|
|
100
107
|
.about-version {
|
|
101
108
|
font-family: var(--mono);
|
|
@@ -104,6 +111,33 @@
|
|
|
104
111
|
margin-left: 6px;
|
|
105
112
|
font-weight: 400;
|
|
106
113
|
}
|
|
114
|
+
.about-version-row {
|
|
115
|
+
display: flex;
|
|
116
|
+
align-items: center;
|
|
117
|
+
justify-content: space-between;
|
|
118
|
+
gap: 16px;
|
|
119
|
+
flex-wrap: wrap;
|
|
120
|
+
}
|
|
121
|
+
.about-version-line {
|
|
122
|
+
font-size: 13px;
|
|
123
|
+
color: var(--ink);
|
|
124
|
+
}
|
|
125
|
+
.about-update-line {
|
|
126
|
+
margin-top: 4px;
|
|
127
|
+
font-size: 12.5px;
|
|
128
|
+
color: var(--ink-mid);
|
|
129
|
+
font-weight: 500;
|
|
130
|
+
}
|
|
131
|
+
.about-version-actions {
|
|
132
|
+
display: inline-flex;
|
|
133
|
+
align-items: center;
|
|
134
|
+
gap: 6px;
|
|
135
|
+
}
|
|
136
|
+
.muted-text {
|
|
137
|
+
font-size: 11.5px;
|
|
138
|
+
color: var(--ink-muted);
|
|
139
|
+
line-height: 1.5;
|
|
140
|
+
}
|
|
107
141
|
.about-tagline {
|
|
108
142
|
margin-top: 2px;
|
|
109
143
|
font-size: 13px;
|
package/public/css/feedback.css
CHANGED
|
@@ -111,70 +111,154 @@
|
|
|
111
111
|
/* Offline banner · shown when /api/health is unreachable. Sticks to the
|
|
112
112
|
top of the main column above all cards. Contains a ccsm:// link that
|
|
113
113
|
asks Windows to spawn the backend. */
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
box-shadow: 0 3px 10px -8px rgba(26, 24, 21, 0.15);
|
|
123
|
-
}
|
|
124
|
-
.offline-banner-inner {
|
|
114
|
+
/* Offline overlay — full-screen modal that blocks all interaction
|
|
115
|
+
until the backend comes back. Z-index above dialogs / toasts. */
|
|
116
|
+
.offline-overlay {
|
|
117
|
+
position: fixed;
|
|
118
|
+
inset: 0;
|
|
119
|
+
z-index: 200;
|
|
120
|
+
background: rgba(26, 24, 21, 0.55);
|
|
121
|
+
backdrop-filter: blur(6px);
|
|
125
122
|
display: flex;
|
|
126
123
|
align-items: center;
|
|
127
|
-
|
|
124
|
+
justify-content: center;
|
|
125
|
+
padding: var(--s-6);
|
|
126
|
+
animation: panel-in .2s ease-out;
|
|
128
127
|
}
|
|
129
|
-
.offline-
|
|
130
|
-
|
|
128
|
+
.offline-card {
|
|
129
|
+
background: var(--bg-elev);
|
|
130
|
+
border: 1px solid var(--ui-border);
|
|
131
|
+
border-radius: var(--r-lg);
|
|
132
|
+
box-shadow: 0 24px 60px -20px rgba(0,0,0,0.4);
|
|
133
|
+
padding: var(--s-8) var(--s-8) var(--s-6);
|
|
134
|
+
max-width: 480px;
|
|
135
|
+
width: 100%;
|
|
136
|
+
text-align: center;
|
|
131
137
|
display: flex;
|
|
132
138
|
flex-direction: column;
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
139
|
+
align-items: center;
|
|
140
|
+
gap: var(--s-3);
|
|
141
|
+
}
|
|
142
|
+
.offline-brand {
|
|
143
|
+
width: 56px;
|
|
144
|
+
height: 56px;
|
|
145
|
+
display: inline-flex;
|
|
146
|
+
align-items: center;
|
|
147
|
+
justify-content: center;
|
|
148
|
+
}
|
|
149
|
+
.offline-brand svg { width: 100%; height: 100%; }
|
|
150
|
+
.offline-title {
|
|
151
|
+
margin: 0;
|
|
152
|
+
font-size: 22px;
|
|
153
|
+
font-weight: 600;
|
|
136
154
|
}
|
|
137
|
-
.offline-
|
|
138
|
-
|
|
155
|
+
.offline-copy {
|
|
156
|
+
margin: 0;
|
|
139
157
|
color: var(--ink-mid);
|
|
158
|
+
font-size: 13.5px;
|
|
159
|
+
line-height: 1.55;
|
|
160
|
+
max-width: 380px;
|
|
140
161
|
}
|
|
141
|
-
.offline-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
162
|
+
.offline-actions {
|
|
163
|
+
margin-top: var(--s-2);
|
|
164
|
+
}
|
|
165
|
+
.offline-actions .action.big {
|
|
166
|
+
padding: 10px 22px;
|
|
167
|
+
font-size: 14px;
|
|
168
|
+
font-weight: 500;
|
|
169
|
+
}
|
|
170
|
+
.offline-fallback {
|
|
171
|
+
margin-top: var(--s-3);
|
|
172
|
+
width: 100%;
|
|
173
|
+
text-align: left;
|
|
174
|
+
font-size: 12px;
|
|
175
|
+
color: var(--ink-mid);
|
|
149
176
|
}
|
|
177
|
+
.offline-fallback summary {
|
|
178
|
+
cursor: pointer;
|
|
179
|
+
text-align: center;
|
|
180
|
+
color: var(--ink-muted);
|
|
181
|
+
}
|
|
182
|
+
.offline-fallback-body {
|
|
183
|
+
margin-top: var(--s-3);
|
|
184
|
+
padding: var(--s-3);
|
|
185
|
+
background: var(--bg);
|
|
186
|
+
border-radius: var(--r-sm);
|
|
187
|
+
}
|
|
188
|
+
.offline-fallback-body pre {
|
|
189
|
+
margin: var(--s-2) 0;
|
|
190
|
+
padding: 8px 10px;
|
|
191
|
+
background: var(--ink);
|
|
192
|
+
color: var(--bg-elev);
|
|
193
|
+
border-radius: 4px;
|
|
194
|
+
font-family: var(--mono);
|
|
195
|
+
font-size: 12px;
|
|
196
|
+
overflow-x: auto;
|
|
197
|
+
}
|
|
198
|
+
.offline-fallback-body p { margin: 0; }
|
|
199
|
+
|
|
200
|
+
/* Legacy banner styles (unused after v1.0 redesign but kept tiny in
|
|
201
|
+
case external CSS references them). */
|
|
202
|
+
.offline-banner { display: none; }
|
|
150
203
|
|
|
151
204
|
/* Toast bottom-right — auto-hides via JS */
|
|
152
205
|
.toast {
|
|
153
206
|
position: fixed;
|
|
154
|
-
bottom: var(--s-
|
|
155
|
-
right: var(--s-
|
|
207
|
+
bottom: var(--s-5);
|
|
208
|
+
right: var(--s-5);
|
|
156
209
|
z-index: 100;
|
|
157
|
-
max-width:
|
|
158
|
-
padding:
|
|
159
|
-
background: var(--
|
|
160
|
-
|
|
161
|
-
border
|
|
162
|
-
border-radius:
|
|
163
|
-
font-size:
|
|
164
|
-
|
|
210
|
+
max-width: 380px;
|
|
211
|
+
padding: 11px 16px 11px 14px;
|
|
212
|
+
background: var(--ink);
|
|
213
|
+
color: var(--bg);
|
|
214
|
+
border: 0;
|
|
215
|
+
border-radius: 6px;
|
|
216
|
+
font-size: 12.5px;
|
|
217
|
+
font-weight: 400;
|
|
165
218
|
letter-spacing: -0.005em;
|
|
219
|
+
line-height: 1.45;
|
|
220
|
+
display: flex;
|
|
221
|
+
align-items: center;
|
|
222
|
+
gap: 12px;
|
|
166
223
|
opacity: 0;
|
|
167
|
-
transform: translateY(
|
|
168
|
-
|
|
224
|
+
transform: translateY(10px) scale(0.98);
|
|
225
|
+
transform-origin: bottom right;
|
|
226
|
+
transition:
|
|
227
|
+
opacity .22s cubic-bezier(.4, 0, .2, 1),
|
|
228
|
+
transform .28s cubic-bezier(.34, 1.4, .64, 1);
|
|
169
229
|
pointer-events: none;
|
|
170
|
-
box-shadow:
|
|
230
|
+
box-shadow:
|
|
231
|
+
0 10px 32px -8px rgba(26, 24, 21, 0.30),
|
|
232
|
+
0 2px 6px rgba(26, 24, 21, 0.12),
|
|
233
|
+
inset 0 0 0 1px rgba(255, 255, 255, 0.06);
|
|
234
|
+
}
|
|
235
|
+
.toast::before {
|
|
236
|
+
content: "OK";
|
|
237
|
+
font-family: var(--mono);
|
|
238
|
+
font-size: 9px;
|
|
239
|
+
letter-spacing: 0.14em;
|
|
240
|
+
font-weight: 500;
|
|
241
|
+
padding: 3px 6px;
|
|
242
|
+
border-radius: 4px;
|
|
243
|
+
background: rgba(255, 255, 255, 0.10);
|
|
244
|
+
color: rgba(255, 255, 255, 0.75);
|
|
245
|
+
flex-shrink: 0;
|
|
246
|
+
line-height: 1;
|
|
171
247
|
}
|
|
172
248
|
.toast.show {
|
|
173
249
|
opacity: 1;
|
|
174
|
-
transform: translateY(0);
|
|
250
|
+
transform: translateY(0) scale(1);
|
|
251
|
+
}
|
|
252
|
+
.toast.error::before {
|
|
253
|
+
content: "ERR";
|
|
254
|
+
background: rgba(183, 63, 63, 0.85);
|
|
255
|
+
color: #fff;
|
|
256
|
+
}
|
|
257
|
+
.toast.ok::before {
|
|
258
|
+
content: "OK";
|
|
259
|
+
background: rgba(74, 138, 74, 0.85);
|
|
260
|
+
color: #fff;
|
|
175
261
|
}
|
|
176
|
-
.toast.error { border-left-color: var(--red); }
|
|
177
|
-
.toast.ok { border-left-color: var(--green); }
|
|
178
262
|
|
|
179
263
|
/* Sticky "you have unsaved changes" banner above the Configure card */
|
|
180
264
|
.dirty-banner {
|
package/public/css/forms.css
CHANGED
|
@@ -11,25 +11,35 @@
|
|
|
11
11
|
font-size: 13px;
|
|
12
12
|
font-weight: 500;
|
|
13
13
|
letter-spacing: -0.005em;
|
|
14
|
-
border-radius:
|
|
14
|
+
border-radius: 6px;
|
|
15
15
|
cursor: pointer;
|
|
16
|
-
transition:
|
|
16
|
+
transition:
|
|
17
|
+
background .14s ease,
|
|
18
|
+
border-color .14s ease,
|
|
19
|
+
color .14s ease,
|
|
20
|
+
box-shadow .14s ease,
|
|
21
|
+
transform .14s cubic-bezier(.4, 0, .2, 1);
|
|
17
22
|
white-space: nowrap;
|
|
18
23
|
box-shadow: var(--shadow-sm);
|
|
19
|
-
/* Buttons always lay out as icon-left + text-right, gap between them,
|
|
20
|
-
and the cluster is centered inside the button's box. Anchor links
|
|
21
|
-
using .action (e.g. About page) inherit the same layout. */
|
|
22
24
|
display: inline-flex;
|
|
23
25
|
align-items: center;
|
|
24
26
|
justify-content: center;
|
|
25
27
|
gap: 6px;
|
|
26
28
|
text-decoration: none;
|
|
29
|
+
position: relative;
|
|
27
30
|
}
|
|
28
31
|
.action:hover {
|
|
29
32
|
background: var(--bg);
|
|
30
33
|
border-color: var(--ink-faint);
|
|
34
|
+
box-shadow: 0 2px 4px -2px rgba(26, 24, 21, 0.10);
|
|
35
|
+
transform: translateY(-0.5px);
|
|
36
|
+
}
|
|
37
|
+
.action:active { transform: translateY(0.5px); box-shadow: var(--shadow-sm); }
|
|
38
|
+
.action:focus-visible {
|
|
39
|
+
outline: none;
|
|
40
|
+
box-shadow: 0 0 0 3px rgba(26, 24, 21, 0.10);
|
|
41
|
+
border-color: var(--ink);
|
|
31
42
|
}
|
|
32
|
-
.action:active { transform: translateY(0.5px); }
|
|
33
43
|
.action:disabled { opacity: .5; cursor: not-allowed; pointer-events: none; }
|
|
34
44
|
.action.primary {
|
|
35
45
|
background: var(--ink);
|
|
@@ -39,6 +49,7 @@
|
|
|
39
49
|
.action.primary:hover {
|
|
40
50
|
background: #000;
|
|
41
51
|
border-color: #000;
|
|
52
|
+
box-shadow: 0 4px 12px -4px rgba(26, 24, 21, 0.35);
|
|
42
53
|
}
|
|
43
54
|
.action.small { font-size: 12px; padding: 4px 10px; }
|
|
44
55
|
.action.tiny { font-size: 11px; padding: 3px 8px; }
|
|
@@ -64,11 +75,11 @@
|
|
|
64
75
|
background: var(--bg-elev);
|
|
65
76
|
border: 1px solid var(--border-strong);
|
|
66
77
|
color: var(--ink);
|
|
67
|
-
padding:
|
|
78
|
+
padding: 8px 12px;
|
|
68
79
|
font-family: var(--body);
|
|
69
80
|
font-size: 13px;
|
|
70
|
-
border-radius:
|
|
71
|
-
transition: border-color .
|
|
81
|
+
border-radius: 6px;
|
|
82
|
+
transition: border-color .14s ease, box-shadow .14s ease, background .14s ease;
|
|
72
83
|
width: 100%;
|
|
73
84
|
max-width: 480px;
|
|
74
85
|
}
|
|
@@ -203,6 +214,7 @@ input[type="checkbox"]:checked::after {
|
|
|
203
214
|
font-weight: 500;
|
|
204
215
|
cursor: pointer;
|
|
205
216
|
user-select: none;
|
|
217
|
+
appearance: none;
|
|
206
218
|
transition: all .12s ease;
|
|
207
219
|
border-radius: 999px;
|
|
208
220
|
}
|
|
@@ -233,7 +245,7 @@ input[type="checkbox"]:checked::after {
|
|
|
233
245
|
/* Two-column field grid used inside the Configure card */
|
|
234
246
|
.config-grid {
|
|
235
247
|
display: grid;
|
|
236
|
-
grid-template-columns: 1fr
|
|
248
|
+
grid-template-columns: 1fr;
|
|
237
249
|
gap: var(--s-5) var(--s-6);
|
|
238
250
|
align-items: start;
|
|
239
251
|
}
|
|
@@ -281,40 +293,88 @@ input[type="checkbox"]:checked::after {
|
|
|
281
293
|
.repos-table tbody td:last-child { padding-right: var(--s-2); }
|
|
282
294
|
.repos-table tbody td input { font-size: 12px; max-width: none; }
|
|
283
295
|
|
|
284
|
-
/* Theme accent picker (Configure tab).
|
|
285
|
-
|
|
286
|
-
|
|
296
|
+
/* Theme accent picker (Configure tab). Pill chips with color dot + name;
|
|
297
|
+
active chip fills with its accent color. A "Custom" chip toggles an
|
|
298
|
+
inline color picker + hex input + reset. */
|
|
287
299
|
.accent-picker {
|
|
288
300
|
display: flex;
|
|
289
301
|
flex-direction: column;
|
|
290
302
|
gap: var(--s-3);
|
|
291
303
|
}
|
|
292
|
-
.accent-
|
|
304
|
+
.accent-chips {
|
|
293
305
|
display: flex;
|
|
294
306
|
flex-wrap: wrap;
|
|
295
|
-
gap:
|
|
307
|
+
gap: 6px;
|
|
296
308
|
}
|
|
297
|
-
.accent-
|
|
309
|
+
.accent-chip {
|
|
298
310
|
appearance: none;
|
|
299
|
-
|
|
300
|
-
|
|
311
|
+
display: inline-flex;
|
|
312
|
+
align-items: center;
|
|
313
|
+
gap: 6px;
|
|
314
|
+
padding: 5px 11px 5px 9px;
|
|
315
|
+
border: 1px solid var(--border);
|
|
301
316
|
border-radius: 999px;
|
|
302
|
-
|
|
317
|
+
background: var(--bg-elev);
|
|
318
|
+
color: var(--ink-mid);
|
|
319
|
+
font-size: 12px;
|
|
320
|
+
font-weight: 500;
|
|
321
|
+
letter-spacing: -0.005em;
|
|
322
|
+
line-height: 1;
|
|
303
323
|
cursor: pointer;
|
|
304
|
-
|
|
305
|
-
|
|
324
|
+
transition: background .12s ease, color .12s ease,
|
|
325
|
+
border-color .12s ease, transform .12s ease,
|
|
326
|
+
box-shadow .12s ease;
|
|
306
327
|
}
|
|
307
|
-
.accent-
|
|
308
|
-
|
|
309
|
-
|
|
328
|
+
.accent-chip:hover {
|
|
329
|
+
color: var(--ink);
|
|
330
|
+
border-color: var(--ink-faint);
|
|
331
|
+
transform: translateY(-1px);
|
|
310
332
|
}
|
|
333
|
+
.accent-chip-dot {
|
|
334
|
+
width: 10px;
|
|
335
|
+
height: 10px;
|
|
336
|
+
border-radius: 999px;
|
|
337
|
+
background: var(--c, var(--ink-faint));
|
|
338
|
+
box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.08);
|
|
339
|
+
flex: none;
|
|
340
|
+
}
|
|
341
|
+
.accent-chip-plus {
|
|
342
|
+
display: inline-flex;
|
|
343
|
+
align-items: center;
|
|
344
|
+
justify-content: center;
|
|
345
|
+
width: 10px;
|
|
346
|
+
height: 10px;
|
|
347
|
+
color: var(--ink-mid);
|
|
348
|
+
font-size: 14px;
|
|
349
|
+
line-height: 1;
|
|
350
|
+
}
|
|
351
|
+
.accent-chip.is-active {
|
|
352
|
+
background: var(--c);
|
|
353
|
+
border-color: var(--c);
|
|
354
|
+
color: #fff;
|
|
355
|
+
box-shadow: 0 1px 0 rgba(0, 0, 0, 0.05);
|
|
356
|
+
}
|
|
357
|
+
.accent-chip.is-active .accent-chip-dot {
|
|
358
|
+
background: rgba(255, 255, 255, 0.85);
|
|
359
|
+
box-shadow: none;
|
|
360
|
+
}
|
|
361
|
+
.accent-chip-custom {
|
|
362
|
+
border-style: dashed;
|
|
363
|
+
}
|
|
364
|
+
.accent-chip-custom.is-open:not(.is-active) {
|
|
365
|
+
border-style: solid;
|
|
366
|
+
color: var(--ink);
|
|
367
|
+
border-color: var(--ink-faint);
|
|
368
|
+
}
|
|
369
|
+
|
|
311
370
|
.accent-custom {
|
|
312
371
|
display: flex;
|
|
313
372
|
align-items: center;
|
|
314
373
|
gap: var(--s-2);
|
|
374
|
+
padding-top: 2px;
|
|
315
375
|
}
|
|
316
376
|
.accent-custom input[type="color"] {
|
|
317
|
-
width:
|
|
377
|
+
width: 32px;
|
|
318
378
|
height: 28px;
|
|
319
379
|
padding: 0;
|
|
320
380
|
border: 1px solid var(--border);
|
|
@@ -331,3 +391,15 @@ input[type="checkbox"]:checked::after {
|
|
|
331
391
|
border-radius: var(--r-sm);
|
|
332
392
|
background: var(--bg-elev);
|
|
333
393
|
}
|
|
394
|
+
.accent-reset {
|
|
395
|
+
appearance: none;
|
|
396
|
+
background: transparent;
|
|
397
|
+
border: 0;
|
|
398
|
+
padding: 4px 6px;
|
|
399
|
+
font-size: 12px;
|
|
400
|
+
color: var(--ink-faint);
|
|
401
|
+
cursor: pointer;
|
|
402
|
+
border-radius: 6px;
|
|
403
|
+
transition: color .12s ease, background .12s ease;
|
|
404
|
+
}
|
|
405
|
+
.accent-reset:hover { color: var(--ink-mid); background: var(--bg); }
|
package/public/css/layout.css
CHANGED
|
@@ -3,7 +3,13 @@
|
|
|
3
3
|
.app {
|
|
4
4
|
display: grid;
|
|
5
5
|
grid-template-columns: var(--sidebar-w) 1fr;
|
|
6
|
-
|
|
6
|
+
height: 100vh;
|
|
7
|
+
/* Pin to viewport height (not min-height) — child flex columns set
|
|
8
|
+
min-height:0 and rely on a bounded parent height to compute their own
|
|
9
|
+
space. With min-height:100vh, a transient xterm resize that briefly
|
|
10
|
+
reports a too-large cell count makes the WebGL canvas grow, .session-pane
|
|
11
|
+
grows to fit, .main grows, .app grows... cascading into a multi-hundred-
|
|
12
|
+
thousand-pixel tall page. height:100vh caps the cascade. */
|
|
7
13
|
transition: grid-template-columns .25s cubic-bezier(.4, 0, .2, 1);
|
|
8
14
|
}
|
|
9
15
|
.app:has(.sidebar[data-collapsed="true"]) {
|
|
@@ -19,8 +25,13 @@ body.is-resizing-sidebar .app {
|
|
|
19
25
|
display: flex;
|
|
20
26
|
flex-direction: column;
|
|
21
27
|
min-width: 0;
|
|
22
|
-
|
|
23
|
-
|
|
28
|
+
/* grid items default to min-height:auto which lets internal content
|
|
29
|
+
(eg a misbehaving xterm canvas that briefly reports an absurd height)
|
|
30
|
+
overflow the grid track and balloon the whole page. min-height:0
|
|
31
|
+
restores the expected "fit my grid cell" behaviour. */
|
|
32
|
+
min-height: 0;
|
|
33
|
+
padding: 0 var(--s-4);
|
|
34
|
+
gap: var(--s-2);
|
|
24
35
|
}
|
|
25
36
|
|
|
26
37
|
.page-head {
|
|
@@ -34,6 +45,7 @@ body.is-resizing-sidebar .app {
|
|
|
34
45
|
.page-head-inner { min-width: 0; }
|
|
35
46
|
|
|
36
47
|
.page-title {
|
|
48
|
+
font-family: var(--display);
|
|
37
49
|
font-size: 26px;
|
|
38
50
|
font-weight: 600;
|
|
39
51
|
letter-spacing: -0.024em;
|
|
@@ -71,42 +83,78 @@ body.is-resizing-sidebar .app {
|
|
|
71
83
|
flex: 1;
|
|
72
84
|
display: flex;
|
|
73
85
|
flex-direction: column;
|
|
86
|
+
min-height: 0;
|
|
74
87
|
}
|
|
75
88
|
|
|
76
89
|
.tab-panel {
|
|
77
90
|
display: none;
|
|
78
91
|
flex-direction: column;
|
|
79
|
-
gap: var(--s-
|
|
92
|
+
gap: var(--s-4);
|
|
93
|
+
min-height: 0;
|
|
80
94
|
}
|
|
81
95
|
.tab-panel[data-active] {
|
|
82
96
|
display: flex;
|
|
83
|
-
|
|
84
|
-
}
|
|
85
|
-
@keyframes panel-in {
|
|
86
|
-
from { opacity: 0; transform: translateY(6px); }
|
|
87
|
-
to { opacity: 1; transform: translateY(0); }
|
|
97
|
+
flex: 1;
|
|
88
98
|
}
|
|
89
99
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
border-top: 1px solid var(--border-soft);
|
|
100
|
+
/* Per-page title strip — height matches the sidebar collapse-toggle
|
|
101
|
+
(28px) so the topmost row of the window reads as one unified band. */
|
|
102
|
+
.page-title-bar {
|
|
94
103
|
display: flex;
|
|
95
|
-
flex-
|
|
96
|
-
align-items:
|
|
104
|
+
flex-direction: row-reverse;
|
|
105
|
+
align-items: center;
|
|
106
|
+
justify-content: flex-start;
|
|
107
|
+
gap: var(--s-3);
|
|
108
|
+
height: 40px;
|
|
109
|
+
margin: 0 calc(-1 * var(--s-4)) 0;
|
|
110
|
+
padding: 0 var(--s-5);
|
|
111
|
+
/* Replace the hard inset shadow rule with a soft gradient fade — gives
|
|
112
|
+
the top band a printed-paper masthead feeling rather than a CSS
|
|
113
|
+
divider. */
|
|
114
|
+
background:
|
|
115
|
+
linear-gradient(to bottom, rgba(216, 212, 198, 0.0) 0%, rgba(216, 212, 198, 0.0) calc(100% - 1px), var(--ui-border-soft) 100%);
|
|
116
|
+
color: var(--ink);
|
|
117
|
+
font-size: 13px;
|
|
118
|
+
font-weight: 400;
|
|
119
|
+
line-height: 1.4;
|
|
120
|
+
}
|
|
121
|
+
.page-title-bar-title {
|
|
122
|
+
margin: 0;
|
|
123
|
+
font-size: 13px;
|
|
124
|
+
font-weight: 400;
|
|
125
|
+
display: flex;
|
|
126
|
+
align-items: center;
|
|
97
127
|
gap: var(--s-2);
|
|
98
|
-
|
|
99
|
-
|
|
128
|
+
min-width: 0;
|
|
129
|
+
flex: 1;
|
|
130
|
+
overflow: hidden;
|
|
131
|
+
line-height: 1.4;
|
|
100
132
|
}
|
|
101
|
-
.
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
133
|
+
.page-title-bar-actions {
|
|
134
|
+
display: flex;
|
|
135
|
+
align-items: center;
|
|
136
|
+
gap: var(--s-2);
|
|
137
|
+
flex-shrink: 0;
|
|
138
|
+
}
|
|
139
|
+
.session-title-text {
|
|
140
|
+
font-weight: 500;
|
|
141
|
+
font-size: 13px;
|
|
142
|
+
letter-spacing: -0.005em;
|
|
143
|
+
color: var(--ink);
|
|
144
|
+
flex-shrink: 0;
|
|
106
145
|
}
|
|
107
|
-
.
|
|
146
|
+
.session-title-meta {
|
|
147
|
+
display: flex;
|
|
148
|
+
align-items: center;
|
|
149
|
+
gap: 6px;
|
|
150
|
+
color: var(--ink-muted);
|
|
151
|
+
font-size: 11.5px;
|
|
152
|
+
overflow: hidden;
|
|
153
|
+
white-space: nowrap;
|
|
154
|
+
}
|
|
155
|
+
.session-title-meta .mono {
|
|
108
156
|
font-family: var(--mono);
|
|
109
|
-
|
|
110
|
-
|
|
157
|
+
overflow: hidden;
|
|
158
|
+
text-overflow: ellipsis;
|
|
159
|
+
max-width: 40vw;
|
|
111
160
|
}
|
|
112
|
-
.footer-status .fs-divider { color: var(--ink-faint); margin: 0 var(--s-1); }
|