cicy-desktop 2.1.69 → 2.1.71
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/package.json +7 -7
- package/src/backends/homepage-react/assets/index-BpljolQs.js +365 -0
- package/src/backends/homepage-react/assets/{index-BniEbx_j.css → index-C9AZlTew.css} +1 -1
- package/src/backends/homepage-react/index.html +2 -2
- package/src/backends/local-teams.js +42 -4
- package/src/backends/sidecar-ipc.js +23 -1
- package/src/i18n/locales/en.json +9 -7
- package/src/i18n/locales/zh-CN.json +9 -7
- package/src/sidecar/cicy-code.js +54 -111
- package/src/sidecar/localbin.js +133 -0
- package/src/sidecar/native.js +4 -2
- package/src/sidecar/runtime.js +7 -3
- package/workers/render/src/App.css +156 -10
- package/workers/render/src/App.jsx +254 -39
- package/.env.dev +0 -7
- package/src/backends/homepage-react/assets/index-B8gGhz8B.js +0 -365
- package/workers/render.bak.20260528-2338/DESIGN_v2.md +0 -254
- package/workers/render.bak.20260528-2338/index.html +0 -12
- package/workers/render.bak.20260528-2338/package-lock.json +0 -827
- package/workers/render.bak.20260528-2338/package.json +0 -19
- package/workers/render.bak.20260528-2338/public/_headers +0 -5
- package/workers/render.bak.20260528-2338/public/manifest.json +0 -6
- package/workers/render.bak.20260528-2338/src/App.css +0 -224
- package/workers/render.bak.20260528-2338/src/App.jsx +0 -1028
- package/workers/render.bak.20260528-2338/src/api.js +0 -285
- package/workers/render.bak.20260528-2338/src/cicycode-ops.js +0 -222
- package/workers/render.bak.20260528-2338/src/components/BackendCard.css +0 -299
- package/workers/render.bak.20260528-2338/src/components/BackendCard.jsx +0 -133
- package/workers/render.bak.20260528-2338/src/components/BackendModal.css +0 -161
- package/workers/render.bak.20260528-2338/src/components/BackendModal.jsx +0 -199
- package/workers/render.bak.20260528-2338/src/components/Button.css +0 -72
- package/workers/render.bak.20260528-2338/src/components/Button.jsx +0 -37
- package/workers/render.bak.20260528-2338/src/components/Card.css +0 -42
- package/workers/render.bak.20260528-2338/src/components/Card.jsx +0 -21
- package/workers/render.bak.20260528-2338/src/components/Icon.jsx +0 -30
- package/workers/render.bak.20260528-2338/src/components/Menu.css +0 -55
- package/workers/render.bak.20260528-2338/src/components/Menu.jsx +0 -91
- package/workers/render.bak.20260528-2338/src/components/SidecarBanner.css +0 -79
- package/workers/render.bak.20260528-2338/src/components/SidecarBanner.jsx +0 -84
- package/workers/render.bak.20260528-2338/src/components/StatusChip.css +0 -19
- package/workers/render.bak.20260528-2338/src/components/StatusChip.jsx +0 -31
- package/workers/render.bak.20260528-2338/src/components/Toast.css +0 -31
- package/workers/render.bak.20260528-2338/src/components/Toast.jsx +0 -23
- package/workers/render.bak.20260528-2338/src/components/WslSetupBanner.css +0 -464
- package/workers/render.bak.20260528-2338/src/components/WslSetupBanner.jsx +0 -716
- package/workers/render.bak.20260528-2338/src/dockerInstaller.js +0 -0
- package/workers/render.bak.20260528-2338/src/i18n/en.json +0 -116
- package/workers/render.bak.20260528-2338/src/i18n/fr.json +0 -116
- package/workers/render.bak.20260528-2338/src/i18n/index.js +0 -69
- package/workers/render.bak.20260528-2338/src/i18n/ja.json +0 -116
- package/workers/render.bak.20260528-2338/src/i18n/zh-CN.json +0 -121
- package/workers/render.bak.20260528-2338/src/main.js +0 -475
- package/workers/render.bak.20260528-2338/src/main.jsx +0 -18
- package/workers/render.bak.20260528-2338/src/style.css +0 -275
- package/workers/render.bak.20260528-2338/src/styles/base.css +0 -98
- package/workers/render.bak.20260528-2338/src/styles/tokens.css +0 -90
- package/workers/render.bak.20260528-2338/src/tos.js +0 -72
- package/workers/render.bak.20260528-2338/src/worker.js +0 -40
- package/workers/render.bak.20260528-2338/src/wslInstaller.js +0 -1563
- package/workers/render.bak.20260528-2338/vite.config.js +0 -36
- package/workers/render.bak.20260528-2338/wrangler.toml +0 -17
|
@@ -1,299 +0,0 @@
|
|
|
1
|
-
/* ── Square BackendCard ─────────────────────────────────────────────────
|
|
2
|
-
Aspect 1:1, brand-accented top stripe, large name, prominent CTA.
|
|
3
|
-
*/
|
|
4
|
-
.bcard {
|
|
5
|
-
position: relative;
|
|
6
|
-
/* Fixed footprint — does not stretch with window width. The grid is
|
|
7
|
-
repeat(auto-fill, 200px) so columns are always exactly 200px wide. */
|
|
8
|
-
width: 200px;
|
|
9
|
-
height: 200px;
|
|
10
|
-
background: var(--bg-elev-1);
|
|
11
|
-
border: 1px solid var(--hairline);
|
|
12
|
-
border-radius: var(--r-lg);
|
|
13
|
-
padding: var(--sp-4);
|
|
14
|
-
display: flex;
|
|
15
|
-
flex-direction: column;
|
|
16
|
-
overflow: hidden;
|
|
17
|
-
cursor: default;
|
|
18
|
-
transition: transform var(--dur-base) var(--ease),
|
|
19
|
-
box-shadow var(--dur-base) var(--ease),
|
|
20
|
-
border-color var(--dur-base) var(--ease);
|
|
21
|
-
}
|
|
22
|
-
.bcard:hover {
|
|
23
|
-
transform: translateY(-2px);
|
|
24
|
-
border-color: var(--hairline-strong, var(--hairline));
|
|
25
|
-
box-shadow: 0 8px 24px -8px rgba(0,0,0,0.18), 0 1px 0 rgba(255,255,255,0.04) inset;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/* top accent stripe — colored bar that runs across the top edge */
|
|
29
|
-
.bcard__accent {
|
|
30
|
-
position: absolute;
|
|
31
|
-
top: 0; left: 0; right: 0;
|
|
32
|
-
height: 3px;
|
|
33
|
-
background: var(--brand);
|
|
34
|
-
opacity: 0.85;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/* Glowing background circle for online cards (subtle) */
|
|
38
|
-
.bcard--online::before {
|
|
39
|
-
content: "";
|
|
40
|
-
position: absolute;
|
|
41
|
-
bottom: -40%;
|
|
42
|
-
right: -20%;
|
|
43
|
-
width: 140%;
|
|
44
|
-
height: 100%;
|
|
45
|
-
background: radial-gradient(circle at center, var(--brand-soft) 0%, transparent 60%);
|
|
46
|
-
pointer-events: none;
|
|
47
|
-
opacity: 0.5;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/* ── top row: status pill + menu ── */
|
|
51
|
-
.bcard__top {
|
|
52
|
-
display: flex;
|
|
53
|
-
align-items: center;
|
|
54
|
-
justify-content: space-between;
|
|
55
|
-
position: relative;
|
|
56
|
-
z-index: 1;
|
|
57
|
-
}
|
|
58
|
-
.bcard__status-pill {
|
|
59
|
-
display: inline-flex;
|
|
60
|
-
align-items: center;
|
|
61
|
-
gap: 6px;
|
|
62
|
-
padding: 4px 8px;
|
|
63
|
-
background: var(--bg);
|
|
64
|
-
border: 1px solid var(--hairline);
|
|
65
|
-
border-radius: var(--r-pill);
|
|
66
|
-
color: var(--fg-2);
|
|
67
|
-
}
|
|
68
|
-
.bcard__status-pill svg { color: var(--fg-3); }
|
|
69
|
-
.bcard__dot {
|
|
70
|
-
width: 7px; height: 7px;
|
|
71
|
-
border-radius: 50%;
|
|
72
|
-
background: var(--fg-3);
|
|
73
|
-
flex-shrink: 0;
|
|
74
|
-
}
|
|
75
|
-
.bcard__dot--up { background: var(--ok); box-shadow: 0 0 0 2px color-mix(in srgb, var(--ok) 30%, transparent); }
|
|
76
|
-
.bcard__dot--warn { background: var(--warn); }
|
|
77
|
-
.bcard__dot--down { background: var(--err); }
|
|
78
|
-
.bcard__dot--unknown { background: var(--fg-3); }
|
|
79
|
-
|
|
80
|
-
.bcard__menu-trigger { color: var(--fg-3); }
|
|
81
|
-
.bcard__menu-trigger:hover { color: var(--fg); }
|
|
82
|
-
|
|
83
|
-
/* ── body: name + host + meta ── */
|
|
84
|
-
.bcard__body {
|
|
85
|
-
flex: 1;
|
|
86
|
-
display: flex;
|
|
87
|
-
flex-direction: column;
|
|
88
|
-
gap: var(--sp-1);
|
|
89
|
-
padding-top: var(--sp-3);
|
|
90
|
-
padding-bottom: var(--sp-3);
|
|
91
|
-
position: relative;
|
|
92
|
-
z-index: 1;
|
|
93
|
-
min-width: 0;
|
|
94
|
-
}
|
|
95
|
-
.bcard__name {
|
|
96
|
-
margin: 0;
|
|
97
|
-
font-size: 17px;
|
|
98
|
-
font-weight: 700;
|
|
99
|
-
color: var(--fg);
|
|
100
|
-
letter-spacing: -0.015em;
|
|
101
|
-
line-height: 1.25;
|
|
102
|
-
overflow: hidden;
|
|
103
|
-
text-overflow: ellipsis;
|
|
104
|
-
white-space: nowrap;
|
|
105
|
-
}
|
|
106
|
-
.bcard__host {
|
|
107
|
-
font-family: var(--font-mono);
|
|
108
|
-
font-size: 11px;
|
|
109
|
-
color: var(--fg-2);
|
|
110
|
-
overflow: hidden;
|
|
111
|
-
text-overflow: ellipsis;
|
|
112
|
-
white-space: nowrap;
|
|
113
|
-
}
|
|
114
|
-
.bcard__meta {
|
|
115
|
-
display: flex;
|
|
116
|
-
flex-wrap: wrap;
|
|
117
|
-
gap: 4px;
|
|
118
|
-
font-size: 11px;
|
|
119
|
-
color: var(--fg-3);
|
|
120
|
-
}
|
|
121
|
-
.bcard__ver {
|
|
122
|
-
font-family: var(--font-mono);
|
|
123
|
-
color: var(--fg-2);
|
|
124
|
-
background: var(--bg);
|
|
125
|
-
padding: 1px 6px;
|
|
126
|
-
border-radius: var(--r-sm);
|
|
127
|
-
border: 1px solid var(--hairline);
|
|
128
|
-
}
|
|
129
|
-
.bcard__sep { opacity: 0.4; }
|
|
130
|
-
.bcard__badge {
|
|
131
|
-
display: inline-flex; align-items: center;
|
|
132
|
-
align-self: flex-start;
|
|
133
|
-
padding: 2px 8px;
|
|
134
|
-
border-radius: var(--r-pill);
|
|
135
|
-
background: var(--brand-soft);
|
|
136
|
-
color: var(--brand);
|
|
137
|
-
font-size: 10px;
|
|
138
|
-
font-weight: 700;
|
|
139
|
-
text-transform: uppercase;
|
|
140
|
-
letter-spacing: 0.4px;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
/* ── primary CTA button ── */
|
|
144
|
-
.bcard__cta {
|
|
145
|
-
position: relative; z-index: 1;
|
|
146
|
-
display: inline-flex;
|
|
147
|
-
align-items: center;
|
|
148
|
-
justify-content: center;
|
|
149
|
-
gap: 8px;
|
|
150
|
-
width: 100%;
|
|
151
|
-
height: 38px;
|
|
152
|
-
border: none;
|
|
153
|
-
border-radius: var(--r-md);
|
|
154
|
-
background: var(--brand);
|
|
155
|
-
color: white;
|
|
156
|
-
font-size: var(--t-sm);
|
|
157
|
-
font-weight: 600;
|
|
158
|
-
letter-spacing: 0.1px;
|
|
159
|
-
cursor: pointer;
|
|
160
|
-
transition: transform 0.1s var(--ease), background var(--dur-base) var(--ease), box-shadow var(--dur-base) var(--ease);
|
|
161
|
-
box-shadow: 0 2px 6px -1px color-mix(in srgb, var(--brand) 35%, transparent);
|
|
162
|
-
}
|
|
163
|
-
.bcard__cta:hover {
|
|
164
|
-
background: color-mix(in srgb, var(--brand) 90%, white);
|
|
165
|
-
box-shadow: 0 4px 10px -2px color-mix(in srgb, var(--brand) 50%, transparent);
|
|
166
|
-
}
|
|
167
|
-
.bcard__cta:active { transform: translateY(1px); }
|
|
168
|
-
.bcard__cta:disabled {
|
|
169
|
-
background: var(--bg);
|
|
170
|
-
color: var(--fg-3);
|
|
171
|
-
cursor: not-allowed;
|
|
172
|
-
box-shadow: none;
|
|
173
|
-
border: 1px solid var(--hairline);
|
|
174
|
-
}
|
|
175
|
-
.bcard__cta--ghost {
|
|
176
|
-
background: var(--bg);
|
|
177
|
-
color: var(--fg);
|
|
178
|
-
border: 1px solid var(--hairline);
|
|
179
|
-
box-shadow: none;
|
|
180
|
-
}
|
|
181
|
-
.bcard__cta--ghost:hover {
|
|
182
|
-
background: var(--bg-elev-2, var(--bg));
|
|
183
|
-
border-color: var(--brand);
|
|
184
|
-
color: var(--brand);
|
|
185
|
-
}
|
|
186
|
-
.bcard__cta-spinner {
|
|
187
|
-
width: 14px; height: 14px;
|
|
188
|
-
border: 2px solid currentColor;
|
|
189
|
-
border-top-color: transparent;
|
|
190
|
-
border-radius: 50%;
|
|
191
|
-
animation: bcard-spin 0.8s linear infinite;
|
|
192
|
-
}
|
|
193
|
-
@keyframes bcard-spin { to { transform: rotate(360deg); } }
|
|
194
|
-
|
|
195
|
-
/* ── progress overlay — replaces CTA ── */
|
|
196
|
-
.bcard__progress {
|
|
197
|
-
position: relative; z-index: 1;
|
|
198
|
-
display: flex;
|
|
199
|
-
flex-direction: column;
|
|
200
|
-
gap: 6px;
|
|
201
|
-
}
|
|
202
|
-
.bcard__progress-text {
|
|
203
|
-
display: flex;
|
|
204
|
-
justify-content: space-between;
|
|
205
|
-
font-size: 12px;
|
|
206
|
-
font-weight: 500;
|
|
207
|
-
color: var(--fg);
|
|
208
|
-
}
|
|
209
|
-
.bcard__progress-pct { color: var(--brand); font-weight: 700; }
|
|
210
|
-
.bcard__progress-bar {
|
|
211
|
-
height: 5px;
|
|
212
|
-
background: var(--bg);
|
|
213
|
-
border-radius: var(--r-pill);
|
|
214
|
-
overflow: hidden;
|
|
215
|
-
border: 1px solid var(--hairline);
|
|
216
|
-
}
|
|
217
|
-
.bcard__progress-fill {
|
|
218
|
-
height: 100%;
|
|
219
|
-
background: linear-gradient(90deg, var(--brand), color-mix(in srgb, var(--brand) 60%, white));
|
|
220
|
-
transition: width 0.3s var(--ease);
|
|
221
|
-
border-radius: var(--r-pill);
|
|
222
|
-
}
|
|
223
|
-
.bcard__progress-bar.is-indeterminate .bcard__progress-fill {
|
|
224
|
-
animation: bcard-indeterminate 1.4s ease-in-out infinite;
|
|
225
|
-
}
|
|
226
|
-
@keyframes bcard-indeterminate {
|
|
227
|
-
0% { transform: translateX(-100%); }
|
|
228
|
-
100% { transform: translateX(400%); }
|
|
229
|
-
}
|
|
230
|
-
.bcard__progress-meta {
|
|
231
|
-
display: flex;
|
|
232
|
-
justify-content: space-between;
|
|
233
|
-
align-items: center;
|
|
234
|
-
font-size: 11px;
|
|
235
|
-
color: var(--fg-3);
|
|
236
|
-
font-family: var(--font-mono);
|
|
237
|
-
}
|
|
238
|
-
.bcard__cancel {
|
|
239
|
-
background: transparent;
|
|
240
|
-
border: none;
|
|
241
|
-
color: var(--fg-3);
|
|
242
|
-
font-size: 11px;
|
|
243
|
-
cursor: pointer;
|
|
244
|
-
padding: 0;
|
|
245
|
-
font-family: inherit;
|
|
246
|
-
}
|
|
247
|
-
.bcard__cancel:hover { color: var(--err); }
|
|
248
|
-
|
|
249
|
-
/* Scrollable log panel under the progress bar — surfaces every shell command
|
|
250
|
-
and its summarized output so the user knows the install is alive. */
|
|
251
|
-
/* When the install log is showing, let the card span the entire grid row
|
|
252
|
-
so the scrollable log has room (otherwise it's clamped to one card width). */
|
|
253
|
-
.bcard.bcard--has-log {
|
|
254
|
-
grid-column: 1 / -1;
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
/* Install-time scrolling shell log. Each entry is one shell command preview
|
|
258
|
-
and its summarized output so the user knows the install is alive. */
|
|
259
|
-
.bcard__progress-log {
|
|
260
|
-
margin-top: 10px;
|
|
261
|
-
max-height: 55vh;
|
|
262
|
-
min-height: 200px;
|
|
263
|
-
overflow-y: auto;
|
|
264
|
-
font-family: var(--font-mono);
|
|
265
|
-
font-size: 12px;
|
|
266
|
-
line-height: 1.5;
|
|
267
|
-
color: var(--fg-3);
|
|
268
|
-
background: color-mix(in srgb, var(--bg-1, #0d1117) 70%, transparent);
|
|
269
|
-
border: 1px solid var(--border, #30363d);
|
|
270
|
-
border-radius: 6px;
|
|
271
|
-
padding: 10px 12px;
|
|
272
|
-
white-space: pre-wrap;
|
|
273
|
-
word-break: break-word;
|
|
274
|
-
user-select: text;
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
/* ── kind variants ── */
|
|
278
|
-
.bcard--local .bcard__accent { background: var(--brand); }
|
|
279
|
-
.bcard--cloud .bcard__accent { background: var(--accent-cloud, #f59e0b); }
|
|
280
|
-
.bcard--cloud .bcard__cta { background: var(--accent-cloud, #f59e0b); box-shadow: 0 2px 6px -1px color-mix(in srgb, var(--accent-cloud, #f59e0b) 35%, transparent); }
|
|
281
|
-
.bcard--cloud .bcard__cta:hover { background: color-mix(in srgb, var(--accent-cloud, #f59e0b) 90%, white); }
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
/* Minimal in-progress state — used when the WSL banner above the grid
|
|
285
|
-
already shows the full step timeline. The card just says "安装中…"
|
|
286
|
-
to avoid duplicating that information. */
|
|
287
|
-
.bcard__progress--minimal {
|
|
288
|
-
display: flex;
|
|
289
|
-
flex-direction: row !important;
|
|
290
|
-
align-items: center;
|
|
291
|
-
justify-content: center;
|
|
292
|
-
gap: 8px;
|
|
293
|
-
flex: 1;
|
|
294
|
-
font-size: var(--t-sm);
|
|
295
|
-
color: var(--fg-2);
|
|
296
|
-
}
|
|
297
|
-
.bcard__progress--minimal .bcard__cta-spinner {
|
|
298
|
-
border-color: var(--fg-3) transparent transparent transparent;
|
|
299
|
-
}
|
|
@@ -1,133 +0,0 @@
|
|
|
1
|
-
import Card from "./Card.jsx";
|
|
2
|
-
import Button from "./Button.jsx";
|
|
3
|
-
import Menu from "./Menu.jsx";
|
|
4
|
-
import StatusChip, { dotKind } from "./StatusChip.jsx";
|
|
5
|
-
import Icon from "./Icon.jsx";
|
|
6
|
-
import { useT } from "../i18n";
|
|
7
|
-
import "./BackendCard.css";
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Square BackendCard — single tile in the grid. 1:1 aspect ratio.
|
|
11
|
-
*
|
|
12
|
-
* Visual layout (top-down):
|
|
13
|
-
* ┌──────────────────────┐
|
|
14
|
-
* │ ● ⋯ │ meta row: status dot, kind icon, menu
|
|
15
|
-
* │ │
|
|
16
|
-
* │ Local │ name (large, bold)
|
|
17
|
-
* │ 127.0.0.1:8008 │ host (mono, dim)
|
|
18
|
-
* │ v2.0.7 · 3h │ version + uptime
|
|
19
|
-
* │ │
|
|
20
|
-
* │ ┌──────────────────┐ │
|
|
21
|
-
* │ │ ↗ Open │ │ primary action (full-width)
|
|
22
|
-
* │ └──────────────────┘ │
|
|
23
|
-
* └──────────────────────┘
|
|
24
|
-
*/
|
|
25
|
-
export default function BackendCard({
|
|
26
|
-
backend, health, onOpen, menuItems = [],
|
|
27
|
-
badge, openLoading = false, openDisabled = false,
|
|
28
|
-
primaryButton, progress, progressLog, onCancel,
|
|
29
|
-
}) {
|
|
30
|
-
const t = useT();
|
|
31
|
-
const isLocal = backend.kind === "local";
|
|
32
|
-
const kind = dotKind(health);
|
|
33
|
-
|
|
34
|
-
const hasProgress = !!progress;
|
|
35
|
-
const pct = hasProgress && typeof progress.progress === "number"
|
|
36
|
-
? Math.round(progress.progress * 100) : null;
|
|
37
|
-
|
|
38
|
-
const accent = isLocal ? "var(--brand)" : "var(--accent-cloud)";
|
|
39
|
-
|
|
40
|
-
return (
|
|
41
|
-
<div className={`bcard ${isLocal ? "bcard--local" : "bcard--cloud"} ${kind === "up" ? "bcard--online" : ""} ${hasProgress && progressLog && progressLog.length > 0 ? "bcard--has-log" : ""}`}>
|
|
42
|
-
<div className="bcard__accent" style={{ background: accent }} />
|
|
43
|
-
|
|
44
|
-
<div className="bcard__top">
|
|
45
|
-
<div className="bcard__status-pill">
|
|
46
|
-
<span className={`bcard__dot bcard__dot--${kind}`} />
|
|
47
|
-
<Icon name={isLocal ? "laptop" : "globe"} size={12} />
|
|
48
|
-
</div>
|
|
49
|
-
{menuItems.length > 0 && !hasProgress && (
|
|
50
|
-
<Menu
|
|
51
|
-
trigger={<Button variant="ghost" size="sm" className="btn--icon bcard__menu-trigger" icon={<Icon name="more" />} />}
|
|
52
|
-
items={menuItems}
|
|
53
|
-
/>
|
|
54
|
-
)}
|
|
55
|
-
</div>
|
|
56
|
-
|
|
57
|
-
<div className="bcard__body">
|
|
58
|
-
<h3 className="bcard__name" title={isLocal ? t("team.local") : backend.name}>
|
|
59
|
-
{isLocal ? t("team.local") : backend.name}
|
|
60
|
-
</h3>
|
|
61
|
-
{badge && <span className="bcard__badge">{badge}</span>}
|
|
62
|
-
</div>
|
|
63
|
-
|
|
64
|
-
{hasProgress ? (
|
|
65
|
-
progress.minimal ? (
|
|
66
|
-
// Minimal state: just say "安装中…" with a small spinner. The
|
|
67
|
-
// detailed timeline + progress bar lives in the WSL banner
|
|
68
|
-
// above the grid; the card avoids duplicating it.
|
|
69
|
-
<div className="bcard__progress bcard__progress--minimal">
|
|
70
|
-
<span className="bcard__cta-spinner" />
|
|
71
|
-
<span>{t("card.installing")}</span>
|
|
72
|
-
</div>
|
|
73
|
-
) : (
|
|
74
|
-
<div className="bcard__progress">
|
|
75
|
-
<div className="bcard__progress-text">
|
|
76
|
-
<span>{progress.message || t("card.installing")}</span>
|
|
77
|
-
<span className="bcard__progress-pct">{pct == null ? "" : `${pct}%`}</span>
|
|
78
|
-
</div>
|
|
79
|
-
<div className={`bcard__progress-bar ${pct == null ? "is-indeterminate" : ""}`}>
|
|
80
|
-
<div className="bcard__progress-fill" style={{ width: pct == null ? "30%" : `${pct}%` }} />
|
|
81
|
-
</div>
|
|
82
|
-
<div className="bcard__progress-meta">
|
|
83
|
-
<span>
|
|
84
|
-
{progress.received != null && progress.total
|
|
85
|
-
? `${formatBytes(progress.received)} / ${formatBytes(progress.total)}`
|
|
86
|
-
: (progress.phase || "")}
|
|
87
|
-
</span>
|
|
88
|
-
{onCancel && (
|
|
89
|
-
<button type="button" className="bcard__cancel" onClick={onCancel}>{t("card.cancel")}</button>
|
|
90
|
-
)}
|
|
91
|
-
</div>
|
|
92
|
-
{progressLog && progressLog.length > 0 && (
|
|
93
|
-
<pre className="bcard__progress-log" ref={(el) => {
|
|
94
|
-
// Auto-scroll to the bottom whenever a new line lands. ref callback
|
|
95
|
-
// runs on every render — cheaper than a useEffect for a leaf div.
|
|
96
|
-
if (el) el.scrollTop = el.scrollHeight;
|
|
97
|
-
}}>
|
|
98
|
-
{progressLog.join("\n")}
|
|
99
|
-
</pre>
|
|
100
|
-
)}
|
|
101
|
-
</div>
|
|
102
|
-
)
|
|
103
|
-
) : (
|
|
104
|
-
<button
|
|
105
|
-
type="button"
|
|
106
|
-
className={`bcard__cta ${primaryButton?.variant === "ghost" ? "bcard__cta--ghost" : ""}`}
|
|
107
|
-
/* openDisabled is intended for the default Open button (which
|
|
108
|
-
would launch into a not-yet-running container). When the
|
|
109
|
-
caller supplies a primaryButton (Install / Start / Retry /
|
|
110
|
-
Update), it has its own onClick and shouldn't inherit that
|
|
111
|
-
gating — otherwise e.g. the Install button in `missing` state
|
|
112
|
-
is disabled by the very condition (no daemon) that requires
|
|
113
|
-
clicking Install. The primaryButton can still opt in
|
|
114
|
-
explicitly via its own `disabled: true`. */
|
|
115
|
-
disabled={primaryButton ? !!primaryButton.disabled : openDisabled}
|
|
116
|
-
onClick={primaryButton?.onClick || onOpen}
|
|
117
|
-
>
|
|
118
|
-
{(primaryButton?.loading ?? openLoading)
|
|
119
|
-
? <span className="bcard__cta-spinner" />
|
|
120
|
-
: <Icon name={primaryButton?.icon || "open"} size={14} />}
|
|
121
|
-
<span>{primaryButton?.label || t("card.open")}</span>
|
|
122
|
-
</button>
|
|
123
|
-
)}
|
|
124
|
-
</div>
|
|
125
|
-
);
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
function formatBytes(n) {
|
|
129
|
-
if (n == null) return "?";
|
|
130
|
-
if (n < 1024) return `${n} B`;
|
|
131
|
-
if (n < 1024 * 1024) return `${(n / 1024).toFixed(1)} KB`;
|
|
132
|
-
return `${(n / (1024 * 1024)).toFixed(1)} MB`;
|
|
133
|
-
}
|
|
@@ -1,161 +0,0 @@
|
|
|
1
|
-
.modal-backdrop {
|
|
2
|
-
position: fixed;
|
|
3
|
-
inset: 0;
|
|
4
|
-
background: rgba(5, 8, 12, 0.6);
|
|
5
|
-
backdrop-filter: blur(6px);
|
|
6
|
-
-webkit-backdrop-filter: blur(6px);
|
|
7
|
-
display: grid;
|
|
8
|
-
place-items: center;
|
|
9
|
-
z-index: 2000;
|
|
10
|
-
animation: modal-fade var(--dur-base) var(--ease);
|
|
11
|
-
padding: var(--sp-4);
|
|
12
|
-
}
|
|
13
|
-
@keyframes modal-fade {
|
|
14
|
-
from { opacity: 0; }
|
|
15
|
-
to { opacity: 1; }
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
.modal {
|
|
19
|
-
width: 100%;
|
|
20
|
-
max-width: 480px;
|
|
21
|
-
background: var(--bg-elev-1);
|
|
22
|
-
border: 1px solid var(--hairline-2);
|
|
23
|
-
border-radius: var(--r-lg);
|
|
24
|
-
box-shadow: 0 24px 48px -12px rgba(0,0,0,0.6), 0 4px 12px rgba(0,0,0,0.3);
|
|
25
|
-
display: flex;
|
|
26
|
-
flex-direction: column;
|
|
27
|
-
overflow: hidden;
|
|
28
|
-
animation: modal-rise var(--dur-base) var(--ease);
|
|
29
|
-
}
|
|
30
|
-
@keyframes modal-rise {
|
|
31
|
-
from { opacity: 0; transform: translateY(8px) scale(0.98); }
|
|
32
|
-
to { opacity: 1; transform: translateY(0) scale(1); }
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
.modal__head {
|
|
36
|
-
display: flex;
|
|
37
|
-
align-items: center;
|
|
38
|
-
justify-content: space-between;
|
|
39
|
-
padding: var(--sp-4) var(--sp-5);
|
|
40
|
-
border-bottom: 1px solid var(--hairline);
|
|
41
|
-
}
|
|
42
|
-
.modal__title {
|
|
43
|
-
margin: 0;
|
|
44
|
-
font-size: var(--t-md);
|
|
45
|
-
font-weight: 600;
|
|
46
|
-
color: var(--fg);
|
|
47
|
-
letter-spacing: -0.01em;
|
|
48
|
-
}
|
|
49
|
-
.modal__close {
|
|
50
|
-
display: grid; place-items: center;
|
|
51
|
-
width: 28px; height: 28px;
|
|
52
|
-
border-radius: var(--r-sm);
|
|
53
|
-
color: var(--fg-3);
|
|
54
|
-
transition: all var(--dur-fast) var(--ease);
|
|
55
|
-
}
|
|
56
|
-
.modal__close:hover { color: var(--fg); background: var(--bg-elev-2); }
|
|
57
|
-
|
|
58
|
-
.modal__body {
|
|
59
|
-
padding: var(--sp-5);
|
|
60
|
-
display: flex;
|
|
61
|
-
flex-direction: column;
|
|
62
|
-
gap: var(--sp-4);
|
|
63
|
-
}
|
|
64
|
-
.modal__field {
|
|
65
|
-
display: flex;
|
|
66
|
-
flex-direction: column;
|
|
67
|
-
gap: 6px;
|
|
68
|
-
}
|
|
69
|
-
.modal__label {
|
|
70
|
-
font-size: 11px;
|
|
71
|
-
font-weight: 600;
|
|
72
|
-
color: var(--fg-2);
|
|
73
|
-
text-transform: uppercase;
|
|
74
|
-
letter-spacing: 0.04em;
|
|
75
|
-
}
|
|
76
|
-
.modal__required { color: var(--brand); }
|
|
77
|
-
.modal__input {
|
|
78
|
-
background: var(--bg);
|
|
79
|
-
border: 1px solid var(--hairline-2);
|
|
80
|
-
border-radius: var(--r-sm);
|
|
81
|
-
padding: 10px 12px;
|
|
82
|
-
font-size: var(--t-sm);
|
|
83
|
-
color: var(--fg);
|
|
84
|
-
font-family: inherit;
|
|
85
|
-
transition: all var(--dur-fast) var(--ease);
|
|
86
|
-
user-select: text;
|
|
87
|
-
-webkit-user-select: text;
|
|
88
|
-
}
|
|
89
|
-
.modal__input:focus {
|
|
90
|
-
border-color: var(--brand);
|
|
91
|
-
box-shadow: 0 0 0 3px var(--brand-soft);
|
|
92
|
-
outline: none;
|
|
93
|
-
}
|
|
94
|
-
.modal__input::placeholder { color: var(--fg-3); }
|
|
95
|
-
|
|
96
|
-
.modal__status {
|
|
97
|
-
font-size: var(--t-xs);
|
|
98
|
-
padding: 8px 12px;
|
|
99
|
-
border-radius: var(--r-sm);
|
|
100
|
-
}
|
|
101
|
-
.modal__status--idle { display: none; }
|
|
102
|
-
.modal__status--probing { background: var(--brand-soft); color: var(--brand); }
|
|
103
|
-
.modal__status--ok { background: var(--success-soft); color: var(--success); }
|
|
104
|
-
.modal__status--err { background: var(--danger-soft); color: var(--danger); }
|
|
105
|
-
|
|
106
|
-
.modal__foot {
|
|
107
|
-
display: flex;
|
|
108
|
-
justify-content: flex-end;
|
|
109
|
-
gap: var(--sp-2);
|
|
110
|
-
padding: var(--sp-3) var(--sp-5) var(--sp-4);
|
|
111
|
-
border-top: 1px solid var(--hairline);
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
.modal__input[readonly] {
|
|
115
|
-
color: var(--fg-3);
|
|
116
|
-
cursor: not-allowed;
|
|
117
|
-
background: var(--bg-elev-2);
|
|
118
|
-
border-color: var(--hairline);
|
|
119
|
-
}
|
|
120
|
-
.modal__input[readonly]:focus {
|
|
121
|
-
border-color: var(--hairline);
|
|
122
|
-
box-shadow: none;
|
|
123
|
-
}
|
|
124
|
-
.modal__locked {
|
|
125
|
-
font-size: 10px;
|
|
126
|
-
color: var(--fg-3);
|
|
127
|
-
font-weight: 400;
|
|
128
|
-
text-transform: none;
|
|
129
|
-
letter-spacing: normal;
|
|
130
|
-
margin-left: 6px;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
.modal__token-wrap {
|
|
134
|
-
position: relative;
|
|
135
|
-
display: flex;
|
|
136
|
-
align-items: stretch;
|
|
137
|
-
}
|
|
138
|
-
.modal__token-input {
|
|
139
|
-
flex: 1;
|
|
140
|
-
padding-right: 40px; /* leave room for the eye button */
|
|
141
|
-
}
|
|
142
|
-
.modal__token-toggle {
|
|
143
|
-
position: absolute;
|
|
144
|
-
right: 4px;
|
|
145
|
-
top: 50%;
|
|
146
|
-
transform: translateY(-50%);
|
|
147
|
-
width: 32px;
|
|
148
|
-
height: 32px;
|
|
149
|
-
display: grid;
|
|
150
|
-
place-items: center;
|
|
151
|
-
border-radius: var(--r-sm);
|
|
152
|
-
color: var(--fg-3);
|
|
153
|
-
cursor: pointer;
|
|
154
|
-
background: transparent;
|
|
155
|
-
border: 0;
|
|
156
|
-
transition: all var(--dur-fast) var(--ease);
|
|
157
|
-
}
|
|
158
|
-
.modal__token-toggle:hover {
|
|
159
|
-
color: var(--fg);
|
|
160
|
-
background: var(--bg-elev-2);
|
|
161
|
-
}
|