@silicaclaw/cli 1.0.0-beta.9 → 2026.3.18-2
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/CHANGELOG.md +93 -0
- package/INSTALL.md +24 -13
- package/README.md +62 -18
- package/VERSION +1 -1
- package/apps/local-console/package.json +1 -0
- package/apps/local-console/public/index.html +2113 -473
- package/apps/local-console/src/server.ts +108 -31
- package/apps/public-explorer/public/index.html +283 -61
- package/docs/CLOUDFLARE_RELAY.md +61 -0
- package/docs/NEW_USER_INSTALL.md +166 -0
- package/docs/NEW_USER_OPERATIONS.md +265 -0
- package/package.json +2 -2
- package/packages/core/dist/socialConfig.d.ts +1 -1
- package/packages/core/dist/socialConfig.js +7 -6
- package/packages/core/dist/socialResolver.js +15 -5
- package/packages/core/src/socialConfig.ts +8 -7
- package/packages/core/src/socialResolver.ts +17 -5
- package/packages/network/dist/index.d.ts +1 -0
- package/packages/network/dist/index.js +1 -0
- package/packages/network/dist/relayPreview.d.ts +166 -0
- package/packages/network/dist/relayPreview.js +430 -0
- package/packages/network/src/index.ts +1 -0
- package/packages/network/src/relayPreview.ts +552 -0
- package/packages/storage/dist/socialRuntimeRepo.js +4 -4
- package/packages/storage/src/socialRuntimeRepo.ts +4 -4
- package/scripts/quickstart.sh +241 -38
- package/scripts/silicaclaw-cli.mjs +418 -56
- package/scripts/silicaclaw-gateway.mjs +197 -46
- package/scripts/webrtc-signaling-server.mjs +89 -5
|
@@ -4,65 +4,117 @@
|
|
|
4
4
|
<meta charset="UTF-8" />
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
6
|
<title>SilicaClaw Control UI</title>
|
|
7
|
-
<meta name="description" content="SilicaClaw local-first agent control console." />
|
|
7
|
+
<meta id="metaDescription" name="description" content="SilicaClaw local-first agent control console." />
|
|
8
8
|
<meta property="og:type" content="website" />
|
|
9
|
-
<meta property="og:title" content="SilicaClaw Local Console" />
|
|
10
|
-
<meta property="og:description" content="Local-first control surface for SilicaClaw agents." />
|
|
9
|
+
<meta id="ogTitle" property="og:title" content="SilicaClaw Local Console" />
|
|
10
|
+
<meta id="ogDescription" property="og:description" content="Local-first control surface for SilicaClaw agents." />
|
|
11
11
|
<meta property="og:image" content="/assets/silicaclaw-logo.png" />
|
|
12
12
|
<meta name="twitter:card" content="summary_large_image" />
|
|
13
|
-
<meta name="twitter:title" content="SilicaClaw Local Console" />
|
|
14
|
-
<meta name="twitter:description" content="Local-first control surface for SilicaClaw agents." />
|
|
13
|
+
<meta id="twitterTitle" name="twitter:title" content="SilicaClaw Local Console" />
|
|
14
|
+
<meta id="twitterDescription" name="twitter:description" content="Local-first control surface for SilicaClaw agents." />
|
|
15
15
|
<meta name="twitter:image" content="/assets/silicaclaw-logo.png" />
|
|
16
16
|
<link rel="icon" type="image/png" href="/assets/silicaclaw-logo.png" />
|
|
17
17
|
<link rel="apple-touch-icon" href="/assets/silicaclaw-logo.png" />
|
|
18
18
|
<style>
|
|
19
19
|
:root {
|
|
20
20
|
--bg: #0e1015;
|
|
21
|
+
--bg-accent: #13151b;
|
|
21
22
|
--bg-elevated: #191c24;
|
|
22
23
|
--bg-hover: #1f2330;
|
|
24
|
+
--bg-muted: #1f2330;
|
|
23
25
|
--panel: #0e1015;
|
|
26
|
+
--panel-strong: #191c24;
|
|
27
|
+
--panel-hover: #1f2330;
|
|
24
28
|
--card: #161920;
|
|
25
|
-
--
|
|
26
|
-
--
|
|
29
|
+
--card-foreground: #f0f0f2;
|
|
30
|
+
--card-highlight: rgba(255, 255, 255, 0.04);
|
|
31
|
+
--card-soft: rgba(22, 25, 32, 0.86);
|
|
32
|
+
--card-strong: rgba(25, 28, 36, 0.96);
|
|
33
|
+
--chrome: rgba(14, 16, 21, 0.96);
|
|
34
|
+
--chrome-strong: rgba(14, 16, 21, 0.98);
|
|
27
35
|
--text: #d4d4d8;
|
|
28
36
|
--text-strong: #f4f4f5;
|
|
29
|
-
--muted: #
|
|
30
|
-
--
|
|
31
|
-
--
|
|
32
|
-
--
|
|
37
|
+
--muted: #838387;
|
|
38
|
+
--muted-strong: #62626a;
|
|
39
|
+
--border: #1e2028;
|
|
40
|
+
--border-strong: #2e3040;
|
|
41
|
+
--border-hover: #3e4050;
|
|
42
|
+
--accent: #ff5c5c;
|
|
43
|
+
--accent-hover: #ff7070;
|
|
44
|
+
--accent-subtle: rgba(255, 92, 92, 0.1);
|
|
45
|
+
--accent-glow: rgba(255, 92, 92, 0.2);
|
|
33
46
|
--ok: #22c55e;
|
|
34
47
|
--warn: #f59e0b;
|
|
35
|
-
--
|
|
36
|
-
--
|
|
48
|
+
--danger: #ef4444;
|
|
49
|
+
--info: #3b82f6;
|
|
50
|
+
--focus-ring: 0 0 0 2px var(--bg), 0 0 0 3px color-mix(in srgb, var(--accent) 60%, transparent);
|
|
51
|
+
--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.25);
|
|
52
|
+
--shadow-md: 0 4px 16px rgba(0, 0, 0, 0.3);
|
|
53
|
+
--shadow-lg: 0 12px 32px rgba(0, 0, 0, 0.4);
|
|
54
|
+
--radius-sm: 6px;
|
|
55
|
+
--radius-md: 10px;
|
|
56
|
+
--radius-lg: 14px;
|
|
57
|
+
--radius-xl: 20px;
|
|
58
|
+
--radius-full: 9999px;
|
|
59
|
+
--ease-out: cubic-bezier(0.16, 1, 0.3, 1);
|
|
60
|
+
--duration-fast: 100ms;
|
|
61
|
+
--font-body: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
|
62
|
+
--mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
|
|
63
|
+
|
|
37
64
|
}
|
|
38
65
|
:root[data-theme-mode="light"] {
|
|
39
66
|
--bg: #f8f9fa;
|
|
40
|
-
--bg-
|
|
67
|
+
--bg-accent: #f1f3f5;
|
|
68
|
+
--bg-elevated: #ffffff;
|
|
41
69
|
--bg-hover: #eceef0;
|
|
70
|
+
--bg-muted: #eceef0;
|
|
42
71
|
--panel: #f8f9fa;
|
|
72
|
+
--panel-strong: #f1f3f5;
|
|
73
|
+
--panel-hover: #e6e8eb;
|
|
43
74
|
--card: #ffffff;
|
|
44
|
-
--
|
|
45
|
-
--
|
|
75
|
+
--card-foreground: #1a1a1e;
|
|
76
|
+
--card-highlight: rgba(0, 0, 0, 0.02);
|
|
77
|
+
--card-soft: rgba(255, 255, 255, 0.9);
|
|
78
|
+
--card-strong: rgba(255, 255, 255, 0.98);
|
|
79
|
+
--chrome: rgba(248, 249, 250, 0.96);
|
|
80
|
+
--chrome-strong: rgba(248, 249, 250, 0.98);
|
|
46
81
|
--text: #3c3c43;
|
|
47
82
|
--text-strong: #1a1a1e;
|
|
48
|
-
--muted: #
|
|
49
|
-
--
|
|
50
|
-
--
|
|
51
|
-
--
|
|
52
|
-
--
|
|
53
|
-
--
|
|
54
|
-
--
|
|
55
|
-
--
|
|
83
|
+
--muted: #6e6e73;
|
|
84
|
+
--muted-strong: #545458;
|
|
85
|
+
--border: #e5e5ea;
|
|
86
|
+
--border-strong: #d1d1d6;
|
|
87
|
+
--border-hover: #aeaeb2;
|
|
88
|
+
--accent: #dc2626;
|
|
89
|
+
--accent-hover: #ef4444;
|
|
90
|
+
--accent-subtle: rgba(220, 38, 38, 0.08);
|
|
91
|
+
--accent-glow: rgba(220, 38, 38, 0.1);
|
|
92
|
+
--ok: #15803d;
|
|
93
|
+
--warn: #b45309;
|
|
94
|
+
--danger: #dc2626;
|
|
95
|
+
--info: #2563eb;
|
|
96
|
+
--focus-ring: 0 0 0 2px var(--bg), 0 0 0 3px color-mix(in srgb, var(--accent) 50%, transparent);
|
|
97
|
+
--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.04);
|
|
98
|
+
--shadow-md: 0 4px 12px rgba(0, 0, 0, 0.06);
|
|
99
|
+
--shadow-lg: 0 12px 28px rgba(0, 0, 0, 0.08);
|
|
100
|
+
|
|
56
101
|
}
|
|
57
102
|
* { box-sizing: border-box; }
|
|
58
|
-
html, body {
|
|
103
|
+
html, body {
|
|
104
|
+
margin: 0;
|
|
105
|
+
height: 100%;
|
|
106
|
+
overflow: hidden;
|
|
107
|
+
}
|
|
59
108
|
body {
|
|
60
|
-
font
|
|
109
|
+
font: 400 13.5px/1.55 var(--font-body);
|
|
110
|
+
letter-spacing: -0.01em;
|
|
61
111
|
color: var(--text);
|
|
62
112
|
background:
|
|
63
113
|
radial-gradient(900px 420px at 8% -12%, rgba(255, 92, 92, 0.18), transparent 60%),
|
|
64
114
|
linear-gradient(180deg, #0e1015 0%, #0e1015 62%, #0f1219 100%);
|
|
65
115
|
transition: background .2s ease, color .2s ease;
|
|
116
|
+
-webkit-font-smoothing: antialiased;
|
|
117
|
+
-moz-osx-font-smoothing: grayscale;
|
|
66
118
|
}
|
|
67
119
|
:root[data-theme-mode="light"] body {
|
|
68
120
|
background:
|
|
@@ -72,35 +124,121 @@
|
|
|
72
124
|
|
|
73
125
|
.app {
|
|
74
126
|
display: grid;
|
|
75
|
-
grid-template-columns:
|
|
76
|
-
|
|
127
|
+
grid-template-columns: 258px 1fr;
|
|
128
|
+
height: 100vh;
|
|
129
|
+
overflow: hidden;
|
|
130
|
+
transition: grid-template-columns .2s ease;
|
|
131
|
+
}
|
|
132
|
+
.app.nav-collapsed {
|
|
133
|
+
grid-template-columns: 78px 1fr;
|
|
134
|
+
}
|
|
135
|
+
.app.focus-mode {
|
|
136
|
+
grid-template-columns: 1fr;
|
|
77
137
|
}
|
|
78
138
|
|
|
79
139
|
.sidebar {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
140
|
+
display: flex;
|
|
141
|
+
flex-direction: column;
|
|
142
|
+
min-height: 0;
|
|
143
|
+
border-right: 1px solid color-mix(in srgb, var(--border) 74%, transparent);
|
|
144
|
+
background: var(--bg);
|
|
145
|
+
padding: 14px 10px 12px;
|
|
146
|
+
position: relative;
|
|
147
|
+
overflow: hidden;
|
|
148
|
+
transition: padding .2s ease;
|
|
149
|
+
}
|
|
150
|
+
:root[data-theme-mode="light"] .sidebar {
|
|
151
|
+
background: var(--panel);
|
|
152
|
+
}
|
|
153
|
+
.app.nav-collapsed .sidebar {
|
|
154
|
+
padding: 12px 8px 10px;
|
|
155
|
+
}
|
|
156
|
+
.sidebar-shell {
|
|
157
|
+
display: flex;
|
|
158
|
+
flex: 1 1 auto;
|
|
159
|
+
min-height: 0;
|
|
160
|
+
flex-direction: column;
|
|
161
|
+
}
|
|
162
|
+
.sidebar-shell__header {
|
|
163
|
+
flex: 0 0 auto;
|
|
164
|
+
display: flex;
|
|
165
|
+
align-items: center;
|
|
166
|
+
justify-content: space-between;
|
|
167
|
+
gap: 12px;
|
|
168
|
+
min-height: 0;
|
|
169
|
+
padding: 0 8px 18px;
|
|
170
|
+
}
|
|
171
|
+
.nav-collapse-toggle {
|
|
172
|
+
width: 36px;
|
|
173
|
+
height: 36px;
|
|
174
|
+
display: flex;
|
|
175
|
+
align-items: center;
|
|
176
|
+
justify-content: center;
|
|
177
|
+
background: var(--bg-elevated);
|
|
178
|
+
border: 1px solid color-mix(in srgb, var(--border-strong) 68%, transparent);
|
|
179
|
+
border-radius: 999px;
|
|
180
|
+
cursor: pointer;
|
|
181
|
+
color: var(--muted);
|
|
182
|
+
flex: 0 0 auto;
|
|
183
|
+
transition:
|
|
184
|
+
background .16s ease,
|
|
185
|
+
border-color .16s ease,
|
|
186
|
+
color .16s ease,
|
|
187
|
+
transform .16s ease;
|
|
188
|
+
}
|
|
189
|
+
.nav-collapse-toggle:hover {
|
|
190
|
+
background: color-mix(in srgb, var(--bg-hover) 90%, transparent);
|
|
191
|
+
border-color: color-mix(in srgb, var(--border-strong) 88%, transparent);
|
|
192
|
+
color: var(--text);
|
|
193
|
+
transform: translateY(-1px);
|
|
194
|
+
}
|
|
195
|
+
.nav-collapse-toggle__icon {
|
|
196
|
+
display: flex;
|
|
197
|
+
align-items: center;
|
|
198
|
+
justify-content: center;
|
|
199
|
+
width: 16px;
|
|
200
|
+
height: 16px;
|
|
201
|
+
color: inherit;
|
|
202
|
+
}
|
|
203
|
+
.nav-collapse-toggle__icon svg {
|
|
204
|
+
width: 16px;
|
|
205
|
+
height: 16px;
|
|
206
|
+
stroke: currentColor;
|
|
207
|
+
fill: none;
|
|
208
|
+
stroke-width: 1.5px;
|
|
209
|
+
stroke-linecap: round;
|
|
210
|
+
stroke-linejoin: round;
|
|
211
|
+
}
|
|
212
|
+
.sidebar-shell__body {
|
|
213
|
+
flex: 1 1 auto;
|
|
214
|
+
min-height: 0;
|
|
215
|
+
display: flex;
|
|
216
|
+
flex-direction: column;
|
|
217
|
+
}
|
|
218
|
+
.sidebar-shell__footer {
|
|
219
|
+
flex: 0 0 auto;
|
|
220
|
+
padding: 12px 8px 0;
|
|
83
221
|
}
|
|
84
222
|
.brand {
|
|
85
223
|
display: flex;
|
|
86
224
|
align-items: center;
|
|
87
225
|
gap: 10px;
|
|
88
|
-
margin-bottom:
|
|
226
|
+
margin-bottom: 0;
|
|
89
227
|
}
|
|
90
228
|
.brand-logo {
|
|
91
|
-
width:
|
|
92
|
-
height:
|
|
229
|
+
width: 32px;
|
|
230
|
+
height: 32px;
|
|
93
231
|
border-radius: 10px;
|
|
94
232
|
object-fit: cover;
|
|
95
233
|
display: block;
|
|
96
|
-
box-shadow: 0
|
|
97
|
-
border: 1px solid color-mix(in srgb, var(--
|
|
234
|
+
box-shadow: 0 8px 18px rgba(0, 0, 0, 0.18);
|
|
235
|
+
border: 1px solid color-mix(in srgb, var(--border) 75%, transparent);
|
|
98
236
|
}
|
|
99
237
|
.brand-badge {
|
|
100
|
-
width:
|
|
101
|
-
height:
|
|
238
|
+
width: 32px;
|
|
239
|
+
height: 32px;
|
|
102
240
|
border-radius: 10px;
|
|
103
|
-
background: linear-gradient(135deg, var(--
|
|
241
|
+
background: linear-gradient(135deg, var(--accent), var(--accent-hover));
|
|
104
242
|
color: #fff;
|
|
105
243
|
font-weight: 900;
|
|
106
244
|
display: grid;
|
|
@@ -109,98 +247,451 @@
|
|
|
109
247
|
.brand-badge.hidden { display: none; }
|
|
110
248
|
.brand h1 {
|
|
111
249
|
margin: 0;
|
|
112
|
-
font-size:
|
|
250
|
+
font-size: 15px;
|
|
251
|
+
line-height: 1.1;
|
|
252
|
+
letter-spacing: -0.03em;
|
|
113
253
|
}
|
|
114
254
|
.brand p {
|
|
115
255
|
margin: 2px 0 0;
|
|
116
256
|
color: var(--muted);
|
|
117
|
-
font-size:
|
|
257
|
+
font-size: 10px;
|
|
258
|
+
line-height: 1.15;
|
|
259
|
+
font-weight: 600;
|
|
260
|
+
letter-spacing: 0.08em;
|
|
261
|
+
text-transform: uppercase;
|
|
262
|
+
}
|
|
263
|
+
.version-dot {
|
|
264
|
+
width: 5px;
|
|
265
|
+
height: 5px;
|
|
266
|
+
border-radius: 999px;
|
|
267
|
+
background: var(--accent);
|
|
268
|
+
opacity: .85;
|
|
269
|
+
}
|
|
270
|
+
.app.nav-collapsed .brand h1,
|
|
271
|
+
.app.nav-collapsed .brand p,
|
|
272
|
+
.app.nav-collapsed .sidebar-foot,
|
|
273
|
+
.app.nav-collapsed .sidebar-version__label,
|
|
274
|
+
.app.nav-collapsed .sidebar-nav__label {
|
|
275
|
+
display: none;
|
|
276
|
+
}
|
|
277
|
+
.app.focus-mode .sidebar {
|
|
278
|
+
display: none;
|
|
279
|
+
}
|
|
280
|
+
.app.focus-mode .integration-strip,
|
|
281
|
+
.app.focus-mode .page-hero,
|
|
282
|
+
.app.focus-mode .notice,
|
|
283
|
+
.app.focus-mode #publicDiscoveryHint {
|
|
284
|
+
display: none !important;
|
|
285
|
+
}
|
|
286
|
+
.app.nav-collapsed .brand {
|
|
287
|
+
display: none;
|
|
288
|
+
}
|
|
289
|
+
.app.nav-collapsed .sidebar-shell__header {
|
|
290
|
+
justify-content: center;
|
|
291
|
+
align-items: center;
|
|
292
|
+
gap: 0;
|
|
293
|
+
padding: 0 2px 16px;
|
|
294
|
+
}
|
|
295
|
+
.app.nav-collapsed .nav button {
|
|
296
|
+
justify-content: center;
|
|
297
|
+
width: 44px;
|
|
298
|
+
min-height: 44px;
|
|
299
|
+
padding: 0;
|
|
300
|
+
margin: 0 auto;
|
|
301
|
+
border-radius: 16px;
|
|
302
|
+
border-color: transparent;
|
|
303
|
+
box-shadow: none;
|
|
304
|
+
background: transparent;
|
|
305
|
+
}
|
|
306
|
+
.app.nav-collapsed .nav button .tab-labels {
|
|
307
|
+
display: none;
|
|
308
|
+
}
|
|
309
|
+
.app.nav-collapsed .nav button .tab-icon {
|
|
310
|
+
width: 18px;
|
|
311
|
+
height: 18px;
|
|
312
|
+
}
|
|
313
|
+
.app.nav-collapsed .nav button .tab-icon svg {
|
|
314
|
+
width: 18px;
|
|
315
|
+
height: 18px;
|
|
316
|
+
}
|
|
317
|
+
.app.nav-collapsed .nav button.active::before {
|
|
318
|
+
left: 8px;
|
|
319
|
+
top: 10px;
|
|
320
|
+
bottom: 10px;
|
|
321
|
+
}
|
|
322
|
+
.app.nav-collapsed .sidebar-shell__footer {
|
|
323
|
+
padding: 8px 0 2px;
|
|
324
|
+
}
|
|
325
|
+
.app.nav-collapsed .sidebar-utility {
|
|
326
|
+
display: none;
|
|
327
|
+
}
|
|
328
|
+
.app.nav-collapsed .sidebar-version {
|
|
329
|
+
width: 44px;
|
|
330
|
+
min-height: 44px;
|
|
331
|
+
padding: 0;
|
|
332
|
+
justify-content: center;
|
|
333
|
+
border-radius: 16px;
|
|
334
|
+
}
|
|
335
|
+
.app.nav-collapsed .sidebar-version__text {
|
|
336
|
+
display: none;
|
|
118
337
|
}
|
|
119
338
|
|
|
120
339
|
.nav {
|
|
121
340
|
display: grid;
|
|
122
|
-
gap:
|
|
341
|
+
gap: 4px;
|
|
342
|
+
min-height: 0;
|
|
343
|
+
overflow: auto;
|
|
344
|
+
padding: 0;
|
|
345
|
+
scrollbar-width: none;
|
|
346
|
+
}
|
|
347
|
+
.nav::-webkit-scrollbar { display: none; }
|
|
348
|
+
.sidebar-nav__label {
|
|
349
|
+
padding: 0 10px 8px;
|
|
350
|
+
color: var(--muted);
|
|
351
|
+
font-size: 12px;
|
|
352
|
+
font-weight: 700;
|
|
353
|
+
letter-spacing: 0.06em;
|
|
354
|
+
text-transform: uppercase;
|
|
123
355
|
}
|
|
124
356
|
.nav button {
|
|
357
|
+
position: relative;
|
|
358
|
+
display: flex;
|
|
359
|
+
align-items: center;
|
|
360
|
+
justify-content: flex-start;
|
|
361
|
+
gap: 8px;
|
|
362
|
+
min-height: 40px;
|
|
125
363
|
text-align: left;
|
|
126
364
|
border: 1px solid transparent;
|
|
127
365
|
background: transparent;
|
|
128
366
|
color: var(--muted);
|
|
129
|
-
padding:
|
|
130
|
-
border-radius:
|
|
367
|
+
padding: 0 9px;
|
|
368
|
+
border-radius: 12px;
|
|
131
369
|
cursor: pointer;
|
|
132
370
|
font: inherit;
|
|
371
|
+
transition:
|
|
372
|
+
border-color .16s ease,
|
|
373
|
+
background .16s ease,
|
|
374
|
+
color .16s ease,
|
|
375
|
+
transform .16s ease;
|
|
376
|
+
}
|
|
377
|
+
.nav button .tab-icon {
|
|
378
|
+
width: 16px;
|
|
379
|
+
height: 16px;
|
|
380
|
+
display: inline-flex;
|
|
381
|
+
align-items: center;
|
|
382
|
+
justify-content: center;
|
|
383
|
+
flex-shrink: 0;
|
|
384
|
+
opacity: .72;
|
|
385
|
+
}
|
|
386
|
+
.nav button .tab-icon svg {
|
|
387
|
+
width: 16px;
|
|
388
|
+
height: 16px;
|
|
389
|
+
stroke: currentColor;
|
|
390
|
+
fill: none;
|
|
391
|
+
stroke-width: 1.5px;
|
|
392
|
+
stroke-linecap: round;
|
|
393
|
+
stroke-linejoin: round;
|
|
394
|
+
}
|
|
395
|
+
.nav button .tab-labels {
|
|
396
|
+
min-width: 0;
|
|
397
|
+
}
|
|
398
|
+
.nav button .tab-title {
|
|
399
|
+
display: block;
|
|
400
|
+
font-size: 14px;
|
|
401
|
+
font-weight: 600;
|
|
402
|
+
color: inherit;
|
|
403
|
+
white-space: nowrap;
|
|
404
|
+
}
|
|
405
|
+
.nav button .tab-copy {
|
|
406
|
+
display: none;
|
|
133
407
|
}
|
|
134
408
|
.nav button.active {
|
|
135
|
-
color:
|
|
136
|
-
border-color: color-mix(in srgb, var(--
|
|
137
|
-
background: var(--
|
|
409
|
+
color: var(--text-strong);
|
|
410
|
+
border-color: color-mix(in srgb, var(--accent) 18%, transparent);
|
|
411
|
+
background: color-mix(in srgb, var(--accent-subtle) 88%, var(--bg-elevated) 12%);
|
|
412
|
+
box-shadow: inset 0 1px 0 color-mix(in srgb, white 10%, transparent);
|
|
413
|
+
}
|
|
414
|
+
.nav button.active .tab-icon {
|
|
415
|
+
opacity: 1;
|
|
416
|
+
color: var(--accent);
|
|
417
|
+
}
|
|
418
|
+
.nav button:hover {
|
|
419
|
+
color: var(--text);
|
|
420
|
+
background: color-mix(in srgb, var(--bg-hover) 68%, transparent);
|
|
421
|
+
border-color: color-mix(in srgb, var(--border) 60%, transparent);
|
|
422
|
+
}
|
|
423
|
+
.nav button:hover .tab-icon {
|
|
424
|
+
opacity: 1;
|
|
138
425
|
}
|
|
139
|
-
.nav button:hover { color: #d2e7ff; }
|
|
140
426
|
|
|
141
427
|
.sidebar-foot {
|
|
142
|
-
margin-top:
|
|
143
|
-
|
|
144
|
-
|
|
428
|
+
margin-top: 12px;
|
|
429
|
+
flex: 0 0 auto;
|
|
430
|
+
border-top: 1px solid color-mix(in srgb, var(--border) 80%, transparent);
|
|
431
|
+
padding-top: 12px;
|
|
432
|
+
color: var(--muted);
|
|
433
|
+
font-size: 12px;
|
|
434
|
+
}
|
|
435
|
+
.sidebar-utility {
|
|
436
|
+
display: grid;
|
|
437
|
+
gap: 8px;
|
|
438
|
+
padding: 12px;
|
|
439
|
+
border-radius: 16px;
|
|
440
|
+
border: 1px solid color-mix(in srgb, var(--border) 72%, transparent);
|
|
441
|
+
background: var(--bg-elevated);
|
|
442
|
+
box-shadow: none;
|
|
443
|
+
}
|
|
444
|
+
.sidebar-utility-row {
|
|
445
|
+
display: flex;
|
|
446
|
+
align-items: center;
|
|
447
|
+
justify-content: space-between;
|
|
448
|
+
gap: 10px;
|
|
449
|
+
}
|
|
450
|
+
.sidebar-utility__label {
|
|
451
|
+
font-size: 11px;
|
|
452
|
+
font-weight: 700;
|
|
453
|
+
color: var(--muted);
|
|
454
|
+
text-transform: uppercase;
|
|
455
|
+
letter-spacing: 0.06em;
|
|
456
|
+
}
|
|
457
|
+
.sidebar-utility__value {
|
|
458
|
+
color: var(--text);
|
|
459
|
+
font-size: 12px;
|
|
460
|
+
font-weight: 600;
|
|
461
|
+
}
|
|
462
|
+
.sidebar-version {
|
|
463
|
+
margin-top: 10px;
|
|
464
|
+
display: flex;
|
|
465
|
+
align-items: center;
|
|
466
|
+
justify-content: space-between;
|
|
467
|
+
gap: 10px;
|
|
468
|
+
min-height: 40px;
|
|
469
|
+
padding: 0 12px;
|
|
470
|
+
border-radius: 14px;
|
|
471
|
+
background: var(--bg-elevated);
|
|
472
|
+
border: 1px solid color-mix(in srgb, var(--border) 72%, transparent);
|
|
473
|
+
box-shadow: none;
|
|
474
|
+
}
|
|
475
|
+
.sidebar-version__label {
|
|
476
|
+
display: inline-flex;
|
|
477
|
+
align-items: center;
|
|
478
|
+
gap: 6px;
|
|
479
|
+
font-size: 11px;
|
|
480
|
+
font-weight: 600;
|
|
145
481
|
color: var(--muted);
|
|
482
|
+
text-transform: uppercase;
|
|
483
|
+
letter-spacing: 0.06em;
|
|
484
|
+
}
|
|
485
|
+
.sidebar-version__text {
|
|
146
486
|
font-size: 12px;
|
|
487
|
+
color: var(--text);
|
|
488
|
+
font-weight: 600;
|
|
489
|
+
}
|
|
490
|
+
.sidebar-version__status {
|
|
491
|
+
width: 8px;
|
|
492
|
+
height: 8px;
|
|
493
|
+
border-radius: 999px;
|
|
494
|
+
flex-shrink: 0;
|
|
495
|
+
margin-left: auto;
|
|
496
|
+
background: var(--danger);
|
|
497
|
+
box-shadow: 0 0 0 4px color-mix(in srgb, var(--danger) 14%, transparent);
|
|
498
|
+
}
|
|
499
|
+
.sidebar-version__status.online {
|
|
500
|
+
background: var(--ok);
|
|
501
|
+
box-shadow: 0 0 0 4px color-mix(in srgb, var(--ok) 14%, transparent);
|
|
502
|
+
}
|
|
503
|
+
.app.nav-collapsed .sidebar-version {
|
|
504
|
+
justify-content: center;
|
|
505
|
+
padding: 0;
|
|
506
|
+
}
|
|
507
|
+
.app.nav-collapsed .sidebar-version__status {
|
|
508
|
+
margin-left: 0;
|
|
147
509
|
}
|
|
148
510
|
|
|
149
511
|
.main {
|
|
150
|
-
|
|
512
|
+
display: flex;
|
|
513
|
+
flex-direction: column;
|
|
514
|
+
min-width: 0;
|
|
515
|
+
min-height: 0;
|
|
516
|
+
height: 100vh;
|
|
517
|
+
overflow: hidden;
|
|
518
|
+
padding: 0;
|
|
151
519
|
}
|
|
152
520
|
.topbar {
|
|
521
|
+
flex: 0 0 auto;
|
|
153
522
|
display: flex;
|
|
154
523
|
justify-content: space-between;
|
|
155
|
-
gap:
|
|
524
|
+
gap: 12px;
|
|
156
525
|
align-items: center;
|
|
157
|
-
|
|
526
|
+
min-height: 52px;
|
|
527
|
+
padding: 0 24px;
|
|
528
|
+
border-bottom: 1px solid color-mix(in srgb, var(--border) 74%, transparent);
|
|
529
|
+
background: var(--chrome);
|
|
530
|
+
backdrop-filter: blur(12px) saturate(1.6);
|
|
531
|
+
-webkit-backdrop-filter: blur(12px) saturate(1.6);
|
|
158
532
|
}
|
|
159
533
|
.topbar h2 {
|
|
534
|
+
display: none;
|
|
160
535
|
margin: 0;
|
|
161
|
-
font-size: 22px;
|
|
162
536
|
}
|
|
163
537
|
.topbar p {
|
|
164
|
-
|
|
538
|
+
display: none;
|
|
539
|
+
margin: 0;
|
|
165
540
|
color: var(--muted);
|
|
166
|
-
font-size:
|
|
541
|
+
font-size: 12px;
|
|
542
|
+
white-space: nowrap;
|
|
543
|
+
overflow: hidden;
|
|
544
|
+
text-overflow: ellipsis;
|
|
545
|
+
}
|
|
546
|
+
.dashboard-header__breadcrumb {
|
|
547
|
+
display: flex;
|
|
548
|
+
align-items: center;
|
|
549
|
+
gap: 8px;
|
|
550
|
+
min-width: 0;
|
|
551
|
+
overflow: hidden;
|
|
552
|
+
font-size: 12px;
|
|
553
|
+
margin-bottom: 2px;
|
|
554
|
+
letter-spacing: 0.01em;
|
|
555
|
+
}
|
|
556
|
+
.dashboard-header__breadcrumb-link,
|
|
557
|
+
.dashboard-header__breadcrumb-sep {
|
|
558
|
+
color: var(--muted);
|
|
559
|
+
}
|
|
560
|
+
.dashboard-header__breadcrumb-current {
|
|
561
|
+
color: var(--text-strong);
|
|
562
|
+
font-weight: 650;
|
|
563
|
+
white-space: nowrap;
|
|
564
|
+
overflow: hidden;
|
|
565
|
+
text-overflow: ellipsis;
|
|
167
566
|
}
|
|
168
567
|
|
|
568
|
+
.topnav-shell__content {
|
|
569
|
+
min-width: 0;
|
|
570
|
+
flex: 1;
|
|
571
|
+
overflow: hidden;
|
|
572
|
+
}
|
|
573
|
+
.main-scroll {
|
|
574
|
+
flex: 1 1 auto;
|
|
575
|
+
min-height: 0;
|
|
576
|
+
overflow: auto;
|
|
577
|
+
padding: 12px 18px 18px;
|
|
578
|
+
}
|
|
169
579
|
.status-row {
|
|
170
580
|
display: flex;
|
|
171
581
|
gap: 8px;
|
|
172
|
-
flex-wrap:
|
|
582
|
+
flex-wrap: nowrap;
|
|
173
583
|
align-items: center;
|
|
584
|
+
flex-shrink: 0;
|
|
585
|
+
min-width: max-content;
|
|
174
586
|
}
|
|
175
|
-
.
|
|
587
|
+
.topbar-actions {
|
|
176
588
|
display: inline-flex;
|
|
177
|
-
|
|
178
|
-
|
|
589
|
+
align-items: center;
|
|
590
|
+
gap: 8px;
|
|
591
|
+
}
|
|
592
|
+
.icon-btn {
|
|
593
|
+
width: 30px;
|
|
594
|
+
height: 30px;
|
|
595
|
+
display: inline-flex;
|
|
596
|
+
align-items: center;
|
|
597
|
+
justify-content: center;
|
|
179
598
|
border-radius: 999px;
|
|
180
|
-
border: 1px solid var(--
|
|
599
|
+
border: 1px solid color-mix(in srgb, var(--border) 86%, transparent);
|
|
181
600
|
background: var(--bg-elevated);
|
|
601
|
+
color: var(--muted);
|
|
602
|
+
padding: 0;
|
|
603
|
+
}
|
|
604
|
+
.icon-btn:hover {
|
|
605
|
+
color: var(--text-strong);
|
|
606
|
+
border-color: color-mix(in srgb, var(--accent) 28%, transparent);
|
|
607
|
+
background: color-mix(in srgb, var(--accent-subtle) 65%, var(--bg-elevated));
|
|
182
608
|
}
|
|
183
|
-
.
|
|
609
|
+
.icon-btn.active {
|
|
610
|
+
color: var(--text-strong);
|
|
611
|
+
border-color: color-mix(in srgb, var(--accent) 34%, transparent);
|
|
612
|
+
background: var(--accent-subtle);
|
|
613
|
+
}
|
|
614
|
+
.icon-btn svg {
|
|
615
|
+
width: 15px;
|
|
616
|
+
height: 15px;
|
|
617
|
+
stroke: currentColor;
|
|
618
|
+
}
|
|
619
|
+
.topbar-theme-mode {
|
|
620
|
+
display: inline-flex;
|
|
621
|
+
align-items: center;
|
|
622
|
+
gap: 2px;
|
|
623
|
+
padding: 3px;
|
|
624
|
+
border: 1px solid color-mix(in srgb, var(--border) 84%, transparent);
|
|
625
|
+
border-radius: 999px;
|
|
626
|
+
background: color-mix(in srgb, var(--bg-elevated) 78%, transparent);
|
|
627
|
+
}
|
|
628
|
+
.topbar-theme-mode__btn {
|
|
629
|
+
width: 30px;
|
|
630
|
+
height: 30px;
|
|
631
|
+
display: inline-flex;
|
|
632
|
+
align-items: center;
|
|
633
|
+
justify-content: center;
|
|
634
|
+
padding: 0;
|
|
184
635
|
border: 1px solid transparent;
|
|
636
|
+
border-radius: 999px;
|
|
185
637
|
background: transparent;
|
|
186
638
|
color: var(--muted);
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
639
|
+
cursor: pointer;
|
|
640
|
+
transition:
|
|
641
|
+
color var(--duration-fast) ease,
|
|
642
|
+
background var(--duration-fast) ease,
|
|
643
|
+
border-color var(--duration-fast) ease;
|
|
191
644
|
}
|
|
192
|
-
.theme-
|
|
193
|
-
color: var(--text
|
|
194
|
-
background: var(--
|
|
195
|
-
|
|
645
|
+
.topbar-theme-mode__btn:hover {
|
|
646
|
+
color: var(--text);
|
|
647
|
+
background: var(--bg-hover);
|
|
648
|
+
}
|
|
649
|
+
.topbar-theme-mode__btn:focus-visible {
|
|
650
|
+
outline: none;
|
|
651
|
+
box-shadow: var(--focus-ring);
|
|
652
|
+
}
|
|
653
|
+
.topbar-theme-mode__btn--active {
|
|
654
|
+
color: var(--accent);
|
|
655
|
+
background: var(--accent-subtle);
|
|
656
|
+
border-color: color-mix(in srgb, var(--accent) 25%, transparent);
|
|
657
|
+
}
|
|
658
|
+
.topbar-theme-mode__btn svg {
|
|
659
|
+
width: 14px;
|
|
660
|
+
height: 14px;
|
|
661
|
+
stroke: currentColor;
|
|
662
|
+
fill: none;
|
|
663
|
+
stroke-width: 1.75px;
|
|
664
|
+
stroke-linecap: round;
|
|
665
|
+
stroke-linejoin: round;
|
|
666
|
+
}
|
|
667
|
+
.theme-icon {
|
|
668
|
+
width: 14px;
|
|
669
|
+
height: 14px;
|
|
670
|
+
display: inline-flex;
|
|
671
|
+
align-items: center;
|
|
672
|
+
justify-content: center;
|
|
673
|
+
}
|
|
674
|
+
.theme-icon svg {
|
|
675
|
+
width: 14px;
|
|
676
|
+
height: 14px;
|
|
677
|
+
stroke: currentColor;
|
|
678
|
+
fill: none;
|
|
679
|
+
stroke-width: 1.75px;
|
|
680
|
+
stroke-linecap: round;
|
|
681
|
+
stroke-linejoin: round;
|
|
196
682
|
}
|
|
197
683
|
.pill {
|
|
198
684
|
border-radius: 999px;
|
|
199
|
-
border: 1px solid var(--
|
|
200
|
-
background: var(--bg-elevated);
|
|
685
|
+
border: 1px solid color-mix(in srgb, var(--border) 86%, transparent);
|
|
686
|
+
background: color-mix(in srgb, var(--bg-elevated) 96%, transparent);
|
|
201
687
|
color: var(--muted);
|
|
202
|
-
padding:
|
|
688
|
+
padding: 6px 10px;
|
|
203
689
|
font-size: 12px;
|
|
690
|
+
font-weight: 500;
|
|
691
|
+
min-height: 32px;
|
|
692
|
+
display: inline-flex;
|
|
693
|
+
align-items: center;
|
|
694
|
+
box-shadow: inset 0 1px 0 color-mix(in srgb, white 4%, transparent);
|
|
204
695
|
}
|
|
205
696
|
.pill.ok { color: var(--ok); border-color: rgba(34, 197, 94, 0.45); background: rgba(34, 197, 94, 0.08); }
|
|
206
697
|
.pill.warn { color: var(--warn); border-color: rgba(245, 158, 11, 0.45); background: rgba(245, 158, 11, 0.08); }
|
|
@@ -208,8 +699,8 @@
|
|
|
208
699
|
.notice {
|
|
209
700
|
display: none;
|
|
210
701
|
margin-bottom: 12px;
|
|
211
|
-
border: 1px solid color-mix(in srgb, var(--
|
|
212
|
-
background: var(--
|
|
702
|
+
border: 1px solid color-mix(in srgb, var(--accent) 28%, transparent);
|
|
703
|
+
background: var(--accent-subtle);
|
|
213
704
|
border-radius: 10px;
|
|
214
705
|
padding: 10px 12px;
|
|
215
706
|
font-size: 13px;
|
|
@@ -219,13 +710,16 @@
|
|
|
219
710
|
position: sticky;
|
|
220
711
|
top: 0;
|
|
221
712
|
z-index: 9;
|
|
222
|
-
margin-bottom:
|
|
223
|
-
border: 1px solid var(--
|
|
224
|
-
border-radius:
|
|
225
|
-
background:
|
|
226
|
-
|
|
227
|
-
|
|
713
|
+
margin-bottom: 8px;
|
|
714
|
+
border: 1px solid color-mix(in srgb, var(--border) 82%, transparent);
|
|
715
|
+
border-radius: 14px;
|
|
716
|
+
background:
|
|
717
|
+
linear-gradient(180deg, color-mix(in srgb, var(--card-soft) 98%, transparent), color-mix(in srgb, var(--bg-elevated) 94%, transparent));
|
|
718
|
+
padding: 8px 12px;
|
|
719
|
+
font-size: 12px;
|
|
720
|
+
line-height: 1.45;
|
|
228
721
|
color: var(--text);
|
|
722
|
+
box-shadow: inset 0 1px 0 color-mix(in srgb, white 4%, transparent);
|
|
229
723
|
}
|
|
230
724
|
.integration-strip.ok {
|
|
231
725
|
border-color: rgba(34, 197, 94, 0.35);
|
|
@@ -233,40 +727,157 @@
|
|
|
233
727
|
.integration-strip.warn {
|
|
234
728
|
border-color: rgba(245, 158, 11, 0.35);
|
|
235
729
|
}
|
|
730
|
+
.page-hero {
|
|
731
|
+
display: grid;
|
|
732
|
+
grid-template-columns: 1.2fr .8fr;
|
|
733
|
+
gap: 10px;
|
|
734
|
+
margin-bottom: 8px;
|
|
735
|
+
}
|
|
736
|
+
.hero-copy {
|
|
737
|
+
border: 1px solid color-mix(in srgb, var(--border) 84%, transparent);
|
|
738
|
+
border-radius: 16px;
|
|
739
|
+
background:
|
|
740
|
+
linear-gradient(180deg, color-mix(in srgb, var(--card-strong) 98%, transparent), color-mix(in srgb, var(--card-soft) 96%, transparent));
|
|
741
|
+
padding: 11px 14px;
|
|
742
|
+
box-shadow:
|
|
743
|
+
inset 0 1px 0 color-mix(in srgb, white 4%, transparent),
|
|
744
|
+
0 10px 24px color-mix(in srgb, black 9%, transparent);
|
|
745
|
+
}
|
|
746
|
+
.hero-copy h3 {
|
|
747
|
+
margin: 0;
|
|
748
|
+
font-size: 17px;
|
|
749
|
+
color: var(--text-strong);
|
|
750
|
+
letter-spacing: -0.02em;
|
|
751
|
+
}
|
|
752
|
+
.hero-copy p {
|
|
753
|
+
margin: 5px 0 0;
|
|
754
|
+
color: var(--muted);
|
|
755
|
+
font-size: 12px;
|
|
756
|
+
line-height: 1.42;
|
|
757
|
+
}
|
|
758
|
+
.hero-meta {
|
|
759
|
+
border: 1px solid color-mix(in srgb, var(--border) 84%, transparent);
|
|
760
|
+
border-radius: 16px;
|
|
761
|
+
background:
|
|
762
|
+
linear-gradient(180deg, color-mix(in srgb, var(--bg-elevated) 97%, transparent), color-mix(in srgb, var(--panel) 98%, transparent));
|
|
763
|
+
padding: 11px;
|
|
764
|
+
box-shadow: inset 0 1px 0 color-mix(in srgb, white 4%, transparent);
|
|
765
|
+
}
|
|
766
|
+
.hero-meta-grid {
|
|
767
|
+
display: grid;
|
|
768
|
+
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
769
|
+
gap: 6px;
|
|
770
|
+
}
|
|
771
|
+
.hero-meta-item {
|
|
772
|
+
border: 1px solid color-mix(in srgb, var(--border) 76%, transparent);
|
|
773
|
+
border-radius: 12px;
|
|
774
|
+
background: color-mix(in srgb, var(--panel) 90%, transparent);
|
|
775
|
+
padding: 7px 9px;
|
|
776
|
+
}
|
|
236
777
|
|
|
237
778
|
.view { display: none; }
|
|
238
|
-
.view.active {
|
|
779
|
+
.view.active {
|
|
780
|
+
display: grid;
|
|
781
|
+
gap: 8px;
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
.section-header {
|
|
785
|
+
display: flex;
|
|
786
|
+
align-items: center;
|
|
787
|
+
justify-content: space-between;
|
|
788
|
+
gap: 12px;
|
|
789
|
+
min-width: 0;
|
|
790
|
+
}
|
|
791
|
+
.section-header__copy {
|
|
792
|
+
min-width: 0;
|
|
793
|
+
}
|
|
794
|
+
.section-header__eyebrow {
|
|
795
|
+
margin: 0 0 3px;
|
|
796
|
+
color: var(--muted);
|
|
797
|
+
font-size: 11px;
|
|
798
|
+
font-weight: 700;
|
|
799
|
+
letter-spacing: 0.08em;
|
|
800
|
+
text-transform: uppercase;
|
|
801
|
+
}
|
|
802
|
+
.section-header__title {
|
|
803
|
+
margin: 0;
|
|
804
|
+
color: var(--text-strong);
|
|
805
|
+
font-size: 16px;
|
|
806
|
+
letter-spacing: -0.02em;
|
|
807
|
+
}
|
|
808
|
+
.section-header__body {
|
|
809
|
+
margin: 4px 0 0;
|
|
810
|
+
color: var(--muted);
|
|
811
|
+
font-size: 12px;
|
|
812
|
+
line-height: 1.45;
|
|
813
|
+
}
|
|
814
|
+
.section-surface {
|
|
815
|
+
border: 1px solid color-mix(in srgb, var(--border) 84%, transparent);
|
|
816
|
+
border-radius: 16px;
|
|
817
|
+
background:
|
|
818
|
+
linear-gradient(180deg, color-mix(in srgb, var(--card-strong) 98%, transparent), color-mix(in srgb, var(--card-soft) 96%, transparent));
|
|
819
|
+
padding: 12px;
|
|
820
|
+
box-shadow:
|
|
821
|
+
inset 0 1px 0 color-mix(in srgb, white 4%, transparent),
|
|
822
|
+
0 14px 30px color-mix(in srgb, black 10%, transparent);
|
|
823
|
+
}
|
|
824
|
+
.section-surface.compact {
|
|
825
|
+
padding: 10px 12px;
|
|
826
|
+
}
|
|
239
827
|
|
|
240
828
|
.grid {
|
|
241
829
|
display: grid;
|
|
242
|
-
gap:
|
|
830
|
+
gap: 8px;
|
|
243
831
|
grid-template-columns: repeat(4, minmax(0, 1fr));
|
|
244
832
|
}
|
|
833
|
+
#networkCards,
|
|
834
|
+
#socialPrimaryCards,
|
|
835
|
+
#socialIntegrationCards,
|
|
836
|
+
#socialAdvancedCards {
|
|
837
|
+
grid-template-columns: repeat(3, minmax(0, 1fr));
|
|
838
|
+
}
|
|
245
839
|
.card {
|
|
246
|
-
border: 1px solid var(--
|
|
247
|
-
border-radius:
|
|
248
|
-
background:
|
|
840
|
+
border: 1px solid color-mix(in srgb, var(--border) 84%, transparent);
|
|
841
|
+
border-radius: 16px;
|
|
842
|
+
background:
|
|
843
|
+
linear-gradient(180deg, color-mix(in srgb, var(--card-strong) 98%, transparent), color-mix(in srgb, var(--card-soft) 96%, transparent));
|
|
249
844
|
padding: 12px;
|
|
250
|
-
box-shadow:
|
|
845
|
+
box-shadow:
|
|
846
|
+
inset 0 1px 0 color-mix(in srgb, white 4%, transparent),
|
|
847
|
+
0 14px 30px color-mix(in srgb, black 10%, transparent);
|
|
848
|
+
transition: border-color .16s ease, transform .16s ease, box-shadow .16s ease;
|
|
849
|
+
}
|
|
850
|
+
.card:hover {
|
|
851
|
+
border-color: color-mix(in srgb, var(--accent) 14%, var(--border));
|
|
852
|
+
box-shadow:
|
|
853
|
+
inset 0 1px 0 color-mix(in srgb, white 4%, transparent),
|
|
854
|
+
0 18px 36px color-mix(in srgb, black 14%, transparent);
|
|
251
855
|
}
|
|
252
856
|
.label { font-size: 12px; color: var(--muted); }
|
|
253
|
-
.value { margin-top: 4px; font-size:
|
|
857
|
+
.value { margin-top: 4px; font-size: 22px; font-weight: 800; letter-spacing: -0.03em; }
|
|
254
858
|
|
|
255
859
|
.split {
|
|
256
|
-
margin-top:
|
|
860
|
+
margin-top: 8px;
|
|
257
861
|
display: grid;
|
|
258
|
-
gap:
|
|
862
|
+
gap: 8px;
|
|
259
863
|
grid-template-columns: 1.2fr 1fr;
|
|
260
864
|
}
|
|
261
|
-
.title-sm { margin: 0 0 10px; font-size:
|
|
865
|
+
.title-sm { margin: 0 0 10px; font-size: 16px; letter-spacing: -0.02em; }
|
|
262
866
|
.mono { font-family: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12px; }
|
|
263
867
|
|
|
264
868
|
.table {
|
|
265
869
|
width: 100%;
|
|
266
870
|
border-collapse: collapse;
|
|
267
871
|
}
|
|
872
|
+
.table thead th {
|
|
873
|
+
color: var(--muted);
|
|
874
|
+
font-size: 11px;
|
|
875
|
+
font-weight: 700;
|
|
876
|
+
text-transform: uppercase;
|
|
877
|
+
letter-spacing: 0.07em;
|
|
878
|
+
}
|
|
268
879
|
.table th, .table td {
|
|
269
|
-
border-bottom: 1px solid var(--
|
|
880
|
+
border-bottom: 1px solid var(--border);
|
|
270
881
|
text-align: left;
|
|
271
882
|
padding: 8px 6px;
|
|
272
883
|
font-size: 13px;
|
|
@@ -281,22 +892,33 @@
|
|
|
281
892
|
input, textarea {
|
|
282
893
|
margin-top: 5px;
|
|
283
894
|
width: 100%;
|
|
284
|
-
border-radius:
|
|
285
|
-
border: 1px solid var(--
|
|
286
|
-
background: var(--bg-elevated);
|
|
287
|
-
color:
|
|
895
|
+
border-radius: 12px;
|
|
896
|
+
border: 1px solid color-mix(in srgb, var(--border) 84%, transparent);
|
|
897
|
+
background: linear-gradient(180deg, color-mix(in srgb, var(--bg-elevated) 98%, transparent), color-mix(in srgb, var(--panel) 96%, transparent));
|
|
898
|
+
color: var(--text);
|
|
288
899
|
font: inherit;
|
|
289
900
|
padding: 10px;
|
|
901
|
+
box-shadow: inset 0 1px 0 color-mix(in srgb, white 3%, transparent);
|
|
290
902
|
}
|
|
291
903
|
select {
|
|
292
904
|
margin-top: 5px;
|
|
293
905
|
width: 100%;
|
|
294
|
-
border-radius:
|
|
295
|
-
border: 1px solid var(--
|
|
296
|
-
background: var(--bg-elevated);
|
|
906
|
+
border-radius: 12px;
|
|
907
|
+
border: 1px solid color-mix(in srgb, var(--border) 84%, transparent);
|
|
908
|
+
background: linear-gradient(180deg, color-mix(in srgb, var(--bg-elevated) 98%, transparent), color-mix(in srgb, var(--panel) 96%, transparent));
|
|
297
909
|
color: var(--text);
|
|
298
910
|
font: inherit;
|
|
299
911
|
padding: 10px;
|
|
912
|
+
box-shadow: inset 0 1px 0 color-mix(in srgb, white 3%, transparent);
|
|
913
|
+
}
|
|
914
|
+
input:focus,
|
|
915
|
+
textarea:focus,
|
|
916
|
+
select:focus {
|
|
917
|
+
outline: none;
|
|
918
|
+
border-color: color-mix(in srgb, var(--accent) 34%, transparent);
|
|
919
|
+
box-shadow:
|
|
920
|
+
inset 0 1px 0 color-mix(in srgb, white 3%, transparent),
|
|
921
|
+
0 0 0 3px color-mix(in srgb, var(--accent) 14%, transparent);
|
|
300
922
|
}
|
|
301
923
|
textarea { min-height: 90px; resize: vertical; }
|
|
302
924
|
|
|
@@ -305,28 +927,87 @@
|
|
|
305
927
|
gap: 8px;
|
|
306
928
|
flex-wrap: wrap;
|
|
307
929
|
}
|
|
930
|
+
.actions button,
|
|
931
|
+
.action-bar button,
|
|
932
|
+
.toolbar button {
|
|
933
|
+
min-height: 38px;
|
|
934
|
+
}
|
|
935
|
+
.action-bar {
|
|
936
|
+
display: flex;
|
|
937
|
+
gap: 8px;
|
|
938
|
+
flex-wrap: wrap;
|
|
939
|
+
margin-bottom: 8px;
|
|
940
|
+
padding: 2px 0 0;
|
|
941
|
+
}
|
|
942
|
+
.summary-list {
|
|
943
|
+
display: grid;
|
|
944
|
+
gap: 8px;
|
|
945
|
+
}
|
|
946
|
+
.summary-item {
|
|
947
|
+
display: grid;
|
|
948
|
+
gap: 3px;
|
|
949
|
+
padding: 10px;
|
|
950
|
+
border-radius: 12px;
|
|
951
|
+
border: 1px solid color-mix(in srgb, var(--border) 82%, transparent);
|
|
952
|
+
background: linear-gradient(180deg, color-mix(in srgb, var(--bg-elevated) 98%, transparent), color-mix(in srgb, var(--panel) 94%, transparent));
|
|
953
|
+
box-shadow: inset 0 1px 0 color-mix(in srgb, white 4%, transparent);
|
|
954
|
+
}
|
|
955
|
+
.empty-state {
|
|
956
|
+
border: 1px dashed color-mix(in srgb, var(--border-strong) 88%, transparent);
|
|
957
|
+
border-radius: 14px;
|
|
958
|
+
padding: 18px;
|
|
959
|
+
color: var(--muted);
|
|
960
|
+
background: linear-gradient(180deg, color-mix(in srgb, var(--panel) 94%, transparent), color-mix(in srgb, var(--bg-elevated) 88%, transparent));
|
|
961
|
+
line-height: 1.55;
|
|
962
|
+
}
|
|
308
963
|
button {
|
|
309
964
|
border: 1px solid transparent;
|
|
310
|
-
border-radius:
|
|
311
|
-
background: var(--
|
|
965
|
+
border-radius: 12px;
|
|
966
|
+
background: var(--accent);
|
|
312
967
|
color: #ffffff;
|
|
313
968
|
font-weight: 700;
|
|
314
969
|
padding: 9px 13px;
|
|
315
970
|
cursor: pointer;
|
|
971
|
+
box-shadow: 0 10px 20px color-mix(in srgb, var(--accent) 16%, transparent);
|
|
972
|
+
}
|
|
973
|
+
button:hover {
|
|
974
|
+
transform: translateY(-1px);
|
|
975
|
+
filter: saturate(1.04);
|
|
976
|
+
}
|
|
977
|
+
.nav button,
|
|
978
|
+
.nav-collapse-toggle,
|
|
979
|
+
.icon-btn,
|
|
980
|
+
.topbar-theme-mode__btn {
|
|
981
|
+
box-shadow: none;
|
|
982
|
+
filter: none;
|
|
983
|
+
}
|
|
984
|
+
.nav button,
|
|
985
|
+
.nav-collapse-toggle,
|
|
986
|
+
.icon-btn {
|
|
987
|
+
background: transparent;
|
|
988
|
+
color: var(--muted);
|
|
989
|
+
}
|
|
990
|
+
.nav button:hover,
|
|
991
|
+
.nav-collapse-toggle:hover,
|
|
992
|
+
.icon-btn:hover,
|
|
993
|
+
.topbar-theme-mode__btn:hover {
|
|
994
|
+
filter: none;
|
|
316
995
|
}
|
|
317
996
|
button.secondary {
|
|
318
|
-
border-color: var(--
|
|
319
|
-
background: var(--bg-elevated);
|
|
997
|
+
border-color: var(--border-strong);
|
|
998
|
+
background: color-mix(in srgb, var(--bg-elevated) 96%, transparent);
|
|
320
999
|
color: var(--text);
|
|
1000
|
+
box-shadow: none;
|
|
321
1001
|
}
|
|
322
1002
|
|
|
323
1003
|
.feedback {
|
|
324
|
-
border: 1px solid var(--
|
|
325
|
-
border-radius:
|
|
326
|
-
background: var(--bg-elevated);
|
|
327
|
-
padding:
|
|
1004
|
+
border: 1px solid color-mix(in srgb, var(--border) 84%, transparent);
|
|
1005
|
+
border-radius: 12px;
|
|
1006
|
+
background: linear-gradient(180deg, color-mix(in srgb, var(--bg-elevated) 98%, transparent), color-mix(in srgb, var(--panel) 96%, transparent));
|
|
1007
|
+
padding: 10px 11px;
|
|
328
1008
|
font-size: 13px;
|
|
329
1009
|
color: var(--muted);
|
|
1010
|
+
box-shadow: inset 0 1px 0 color-mix(in srgb, white 4%, transparent);
|
|
330
1011
|
}
|
|
331
1012
|
.profile-layout {
|
|
332
1013
|
display: grid;
|
|
@@ -334,10 +1015,11 @@
|
|
|
334
1015
|
grid-template-columns: 1.1fr .9fr;
|
|
335
1016
|
}
|
|
336
1017
|
.profile-meta {
|
|
337
|
-
border: 1px solid var(--
|
|
338
|
-
border-radius:
|
|
1018
|
+
border: 1px solid color-mix(in srgb, var(--border) 82%, transparent);
|
|
1019
|
+
border-radius: 12px;
|
|
339
1020
|
padding: 10px;
|
|
340
|
-
background: color-mix(in srgb, var(--card)
|
|
1021
|
+
background: linear-gradient(180deg, color-mix(in srgb, var(--card-soft) 98%, transparent), color-mix(in srgb, var(--bg-elevated) 90%, transparent));
|
|
1022
|
+
box-shadow: inset 0 1px 0 color-mix(in srgb, white 4%, transparent);
|
|
341
1023
|
}
|
|
342
1024
|
.profile-meta h4 {
|
|
343
1025
|
margin: 0 0 8px;
|
|
@@ -362,9 +1044,9 @@
|
|
|
362
1044
|
flex-wrap: wrap;
|
|
363
1045
|
}
|
|
364
1046
|
.tag-chip {
|
|
365
|
-
border: 1px solid var(--
|
|
1047
|
+
border: 1px solid var(--border-strong);
|
|
366
1048
|
border-radius: 999px;
|
|
367
|
-
background: var(--
|
|
1049
|
+
background: var(--bg-hover);
|
|
368
1050
|
color: var(--text);
|
|
369
1051
|
padding: 3px 9px;
|
|
370
1052
|
font-size: 12px;
|
|
@@ -377,14 +1059,15 @@
|
|
|
377
1059
|
margin-top: 4px;
|
|
378
1060
|
color: var(--muted);
|
|
379
1061
|
font-size: 12px;
|
|
1062
|
+
line-height: 1.45;
|
|
380
1063
|
}
|
|
381
1064
|
.field-error {
|
|
382
1065
|
margin-top: 4px;
|
|
383
|
-
color: var(--
|
|
1066
|
+
color: var(--danger);
|
|
384
1067
|
font-size: 12px;
|
|
385
1068
|
}
|
|
386
1069
|
.input-invalid {
|
|
387
|
-
border-color: color-mix(in srgb, var(--
|
|
1070
|
+
border-color: color-mix(in srgb, var(--danger) 55%, transparent);
|
|
388
1071
|
}
|
|
389
1072
|
.save-busy {
|
|
390
1073
|
opacity: 0.7;
|
|
@@ -394,46 +1077,71 @@
|
|
|
394
1077
|
.logs {
|
|
395
1078
|
max-height: 420px;
|
|
396
1079
|
overflow: auto;
|
|
397
|
-
border: 1px solid var(--
|
|
398
|
-
border-radius:
|
|
399
|
-
background: var(--panel);
|
|
1080
|
+
border: 1px solid color-mix(in srgb, var(--border) 82%, transparent);
|
|
1081
|
+
border-radius: 14px;
|
|
1082
|
+
background: linear-gradient(180deg, color-mix(in srgb, var(--panel) 96%, transparent), color-mix(in srgb, var(--bg-elevated) 90%, transparent));
|
|
400
1083
|
padding: 10px;
|
|
1084
|
+
box-shadow: inset 0 1px 0 color-mix(in srgb, white 3%, transparent);
|
|
401
1085
|
}
|
|
402
1086
|
.log-item {
|
|
403
|
-
border-bottom: 1px dashed var(--
|
|
1087
|
+
border-bottom: 1px dashed var(--border);
|
|
404
1088
|
padding: 7px 0;
|
|
405
1089
|
}
|
|
406
1090
|
.log-item:last-child { border-bottom: 0; }
|
|
407
1091
|
.log-info { color: #8dc6ff; }
|
|
408
1092
|
.log-warn { color: var(--warn); }
|
|
409
|
-
.log-error { color: var(--
|
|
1093
|
+
.log-error { color: var(--danger); }
|
|
410
1094
|
.toolbar {
|
|
411
1095
|
display: flex;
|
|
412
1096
|
gap: 10px;
|
|
413
1097
|
flex-wrap: wrap;
|
|
414
1098
|
align-items: end;
|
|
415
1099
|
margin-bottom: 10px;
|
|
1100
|
+
padding-bottom: 2px;
|
|
416
1101
|
}
|
|
417
1102
|
.toolbar .field {
|
|
418
1103
|
min-width: 180px;
|
|
419
1104
|
}
|
|
420
1105
|
.mono-block {
|
|
421
|
-
border: 1px solid var(--
|
|
422
|
-
border-radius:
|
|
423
|
-
background: color-mix(in srgb, var(--bg-elevated)
|
|
1106
|
+
border: 1px solid color-mix(in srgb, var(--border) 82%, transparent);
|
|
1107
|
+
border-radius: 12px;
|
|
1108
|
+
background: linear-gradient(180deg, color-mix(in srgb, var(--bg-elevated) 96%, transparent), color-mix(in srgb, var(--panel) 92%, transparent));
|
|
424
1109
|
padding: 10px;
|
|
425
1110
|
max-height: 240px;
|
|
426
1111
|
overflow: auto;
|
|
427
1112
|
white-space: pre-wrap;
|
|
428
1113
|
word-break: break-word;
|
|
1114
|
+
box-shadow: inset 0 1px 0 color-mix(in srgb, white 3%, transparent);
|
|
1115
|
+
}
|
|
1116
|
+
.advanced-panel {
|
|
1117
|
+
margin-top: 8px;
|
|
1118
|
+
}
|
|
1119
|
+
.advanced-panel.card > summary,
|
|
1120
|
+
details.card > summary {
|
|
1121
|
+
display: flex;
|
|
1122
|
+
align-items: center;
|
|
1123
|
+
justify-content: space-between;
|
|
1124
|
+
}
|
|
1125
|
+
.advanced-panel summary {
|
|
1126
|
+
cursor: pointer;
|
|
1127
|
+
list-style: none;
|
|
1128
|
+
user-select: none;
|
|
1129
|
+
}
|
|
1130
|
+
.advanced-panel summary::-webkit-details-marker { display: none; }
|
|
1131
|
+
.advanced-panel summary::after {
|
|
1132
|
+
content: attr(data-i18n-closed-label);
|
|
1133
|
+
float: right;
|
|
1134
|
+
color: var(--muted);
|
|
1135
|
+
font-size: 12px;
|
|
429
1136
|
}
|
|
1137
|
+
.advanced-panel[open] summary::after { content: attr(data-i18n-open-label); }
|
|
430
1138
|
|
|
431
1139
|
.toast {
|
|
432
1140
|
position: fixed;
|
|
433
1141
|
right: 16px;
|
|
434
1142
|
bottom: 16px;
|
|
435
1143
|
background: var(--bg-elevated);
|
|
436
|
-
border: 1px solid color-mix(in srgb, var(--
|
|
1144
|
+
border: 1px solid color-mix(in srgb, var(--accent) 32%, transparent);
|
|
437
1145
|
color: var(--text);
|
|
438
1146
|
border-radius: 10px;
|
|
439
1147
|
padding: 10px 12px;
|
|
@@ -449,69 +1157,222 @@
|
|
|
449
1157
|
transform: translateY(0);
|
|
450
1158
|
}
|
|
451
1159
|
|
|
1160
|
+
#view-overview .action-bar {
|
|
1161
|
+
margin-bottom: 0;
|
|
1162
|
+
}
|
|
1163
|
+
#view-overview .grid {
|
|
1164
|
+
grid-template-columns: repeat(4, minmax(0, 1fr));
|
|
1165
|
+
}
|
|
1166
|
+
#view-overview .card .field-hint {
|
|
1167
|
+
font-size: 12px;
|
|
1168
|
+
}
|
|
1169
|
+
#view-overview #snapshot {
|
|
1170
|
+
line-height: 1.55;
|
|
1171
|
+
}
|
|
1172
|
+
|
|
452
1173
|
@media (max-width: 980px) {
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
1174
|
+
html, body {
|
|
1175
|
+
height: auto;
|
|
1176
|
+
overflow: auto;
|
|
1177
|
+
}
|
|
1178
|
+
.app {
|
|
1179
|
+
grid-template-columns: 1fr;
|
|
1180
|
+
height: auto;
|
|
1181
|
+
overflow: visible;
|
|
1182
|
+
}
|
|
1183
|
+
.sidebar {
|
|
1184
|
+
border-right: 0;
|
|
1185
|
+
border-bottom: 1px solid var(--border);
|
|
1186
|
+
height: auto;
|
|
1187
|
+
overflow: visible;
|
|
1188
|
+
}
|
|
1189
|
+
.sidebar-shell {
|
|
1190
|
+
display: block;
|
|
1191
|
+
}
|
|
1192
|
+
.nav { grid-template-columns: repeat(2, minmax(0,1fr)); }
|
|
456
1193
|
.grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
|
457
|
-
.split, .row, .profile-layout { grid-template-columns: 1fr; }
|
|
1194
|
+
.split, .row, .profile-layout, .page-hero { grid-template-columns: 1fr; }
|
|
1195
|
+
.main {
|
|
1196
|
+
height: auto;
|
|
1197
|
+
overflow: visible;
|
|
1198
|
+
padding-bottom: 18px;
|
|
1199
|
+
}
|
|
1200
|
+
.main-scroll {
|
|
1201
|
+
overflow: visible;
|
|
1202
|
+
padding-right: 0;
|
|
1203
|
+
}
|
|
458
1204
|
}
|
|
459
1205
|
</style>
|
|
460
1206
|
</head>
|
|
461
1207
|
<body>
|
|
462
|
-
<div class="app">
|
|
1208
|
+
<div class="app" id="appShell">
|
|
463
1209
|
<aside class="sidebar">
|
|
464
|
-
<div class="
|
|
465
|
-
<
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
1210
|
+
<div class="sidebar-shell">
|
|
1211
|
+
<div class="sidebar-shell__header">
|
|
1212
|
+
<div class="brand">
|
|
1213
|
+
<img id="brandLogo" class="brand-logo" src="/assets/silicaclaw-logo.png" alt="SilicaClaw logo" />
|
|
1214
|
+
<div id="brandFallback" class="brand-badge hidden">SC</div>
|
|
1215
|
+
<div>
|
|
1216
|
+
<h1>SilicaClaw</h1>
|
|
1217
|
+
<p>Control UI</p>
|
|
1218
|
+
</div>
|
|
1219
|
+
</div>
|
|
1220
|
+
<button class="nav-collapse-toggle" id="sidebarToggleBtn" type="button" title="Collapse sidebar" aria-label="Collapse sidebar">
|
|
1221
|
+
<span class="nav-collapse-toggle__icon" aria-hidden="true">
|
|
1222
|
+
<svg viewBox="0 0 24 24">
|
|
1223
|
+
<rect x="3" y="3" width="18" height="18" rx="2"></rect>
|
|
1224
|
+
<path d="M9 3v18"></path>
|
|
1225
|
+
<path d="M16 10l-3 2 3 2"></path>
|
|
1226
|
+
</svg>
|
|
1227
|
+
</span>
|
|
1228
|
+
</button>
|
|
1229
|
+
</div>
|
|
1230
|
+
<div class="sidebar-shell__body">
|
|
1231
|
+
<div class="sidebar-nav__label">Control</div>
|
|
1232
|
+
<nav class="nav">
|
|
1233
|
+
<button class="tab active" data-tab="overview">
|
|
1234
|
+
<span class="tab-icon" aria-hidden="true">
|
|
1235
|
+
<svg viewBox="0 0 24 24">
|
|
1236
|
+
<line x1="12" x2="12" y1="20" y2="10"></line>
|
|
1237
|
+
<line x1="18" x2="18" y1="20" y2="4"></line>
|
|
1238
|
+
<line x1="6" x2="6" y1="20" y2="16"></line>
|
|
1239
|
+
</svg>
|
|
1240
|
+
</span>
|
|
1241
|
+
<span class="tab-labels"><span class="tab-title">Overview</span><span class="tab-copy">Agent summary and discovered peers</span></span>
|
|
1242
|
+
</button>
|
|
1243
|
+
<button class="tab" data-tab="profile">
|
|
1244
|
+
<span class="tab-icon" aria-hidden="true">
|
|
1245
|
+
<svg viewBox="0 0 24 24">
|
|
1246
|
+
<path d="M14.5 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7.5L14.5 2z"></path>
|
|
1247
|
+
<polyline points="14 2 14 8 20 8"></polyline>
|
|
1248
|
+
<line x1="16" x2="8" y1="13" y2="13"></line>
|
|
1249
|
+
<line x1="16" x2="8" y1="17" y2="17"></line>
|
|
1250
|
+
<line x1="10" x2="8" y1="9" y2="9"></line>
|
|
1251
|
+
</svg>
|
|
1252
|
+
</span>
|
|
1253
|
+
<span class="tab-labels"><span class="tab-title">Profile</span><span class="tab-copy">Public identity and saved profile</span></span>
|
|
1254
|
+
</button>
|
|
1255
|
+
<button class="tab" data-tab="network">
|
|
1256
|
+
<span class="tab-icon" aria-hidden="true">
|
|
1257
|
+
<svg viewBox="0 0 24 24">
|
|
1258
|
+
<circle cx="12" cy="12" r="2"></circle>
|
|
1259
|
+
<path d="M16.24 7.76a6 6 0 0 1 0 8.49m-8.48-.01a6 6 0 0 1 0-8.49m11.31-2.82a10 10 0 0 1 0 14.14m-14.14 0a10 10 0 0 1 0-14.14"></path>
|
|
1260
|
+
</svg>
|
|
1261
|
+
</span>
|
|
1262
|
+
<span class="tab-labels"><span class="tab-title">Network</span><span class="tab-copy">Relay health, broadcast, diagnostics</span></span>
|
|
1263
|
+
</button>
|
|
1264
|
+
<button class="tab" data-tab="social">
|
|
1265
|
+
<span class="tab-icon" aria-hidden="true">
|
|
1266
|
+
<svg viewBox="0 0 24 24">
|
|
1267
|
+
<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"></path>
|
|
1268
|
+
</svg>
|
|
1269
|
+
</span>
|
|
1270
|
+
<span class="tab-labels"><span class="tab-title">Social</span><span class="tab-copy">social.md config and runtime state</span></span>
|
|
1271
|
+
</button>
|
|
1272
|
+
</nav>
|
|
1273
|
+
</div>
|
|
1274
|
+
<div class="sidebar-shell__footer">
|
|
1275
|
+
<div class="sidebar-version" title="Current version">
|
|
1276
|
+
<span class="sidebar-version__label"><span class="version-dot"></span>Version</span>
|
|
1277
|
+
<span class="sidebar-version__text" id="brandVersion">-</span>
|
|
1278
|
+
<span class="sidebar-version__status" id="brandStatusDot" aria-hidden="true"></span>
|
|
1279
|
+
</div>
|
|
470
1280
|
</div>
|
|
471
1281
|
</div>
|
|
472
|
-
|
|
473
|
-
<nav class="nav">
|
|
474
|
-
<button class="tab active" data-tab="overview">Overview</button>
|
|
475
|
-
<button class="tab" data-tab="profile">Profile</button>
|
|
476
|
-
<button class="tab" data-tab="network">Network</button>
|
|
477
|
-
<button class="tab" data-tab="peers">Peers</button>
|
|
478
|
-
<button class="tab" data-tab="discovery">Discovery Events</button>
|
|
479
|
-
<button class="tab" data-tab="social">Social Config</button>
|
|
480
|
-
<button class="tab" data-tab="logs">Logs</button>
|
|
481
|
-
</nav>
|
|
482
|
-
|
|
483
|
-
<div class="sidebar-foot" id="sideMeta">adapter: -<br/>namespace: -</div>
|
|
484
1282
|
</aside>
|
|
485
1283
|
|
|
486
1284
|
<main class="main">
|
|
487
1285
|
<div class="topbar">
|
|
488
|
-
<div>
|
|
489
|
-
<
|
|
490
|
-
|
|
1286
|
+
<div class="topnav-shell__content">
|
|
1287
|
+
<div class="dashboard-header__breadcrumb">
|
|
1288
|
+
<span class="dashboard-header__breadcrumb-link">SilicaClaw</span>
|
|
1289
|
+
<span class="dashboard-header__breadcrumb-sep">/</span>
|
|
1290
|
+
<span class="dashboard-header__breadcrumb-current" id="pageBreadcrumb">Overview</span>
|
|
1291
|
+
</div>
|
|
1292
|
+
<h2 id="topbarTitle">Local Console</h2>
|
|
1293
|
+
<p id="topbarSubtitle">OpenClaw-inspired local-first agent control surface</p>
|
|
491
1294
|
</div>
|
|
492
1295
|
<div class="status-row">
|
|
493
1296
|
<div class="pill" id="pillAdapter">adapter: -</div>
|
|
494
1297
|
<div class="pill" id="pillBroadcast">broadcast: -</div>
|
|
495
|
-
<div class="
|
|
496
|
-
<button id="
|
|
497
|
-
|
|
1298
|
+
<div class="topbar-actions">
|
|
1299
|
+
<button class="icon-btn" id="focusModeBtn" type="button" title="Toggle focus mode" aria-label="Toggle focus mode">
|
|
1300
|
+
<svg viewBox="0 0 24 24" fill="none" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
|
1301
|
+
<path d="M4 7V4h3"></path>
|
|
1302
|
+
<path d="M20 7V4h-3"></path>
|
|
1303
|
+
<path d="M4 17v3h3"></path>
|
|
1304
|
+
<path d="M20 17v3h-3"></path>
|
|
1305
|
+
<circle cx="12" cy="12" r="3"></circle>
|
|
1306
|
+
</svg>
|
|
1307
|
+
</button>
|
|
1308
|
+
<div class="topbar-theme-mode" id="themeModeGroup" role="group" aria-label="Color mode">
|
|
1309
|
+
<button class="topbar-theme-mode__btn" data-theme-choice="dark" type="button" title="Dark" aria-label="Color mode: Dark">
|
|
1310
|
+
<span class="theme-icon" aria-hidden="true">
|
|
1311
|
+
<svg viewBox="0 0 24 24">
|
|
1312
|
+
<path d="M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9z"></path>
|
|
1313
|
+
</svg>
|
|
1314
|
+
</span>
|
|
1315
|
+
</button>
|
|
1316
|
+
<button class="topbar-theme-mode__btn" data-theme-choice="light" type="button" title="Light" aria-label="Color mode: Light">
|
|
1317
|
+
<span class="theme-icon" aria-hidden="true">
|
|
1318
|
+
<svg viewBox="0 0 24 24">
|
|
1319
|
+
<circle cx="12" cy="12" r="4"></circle>
|
|
1320
|
+
<path d="M12 2v2"></path>
|
|
1321
|
+
<path d="M12 20v2"></path>
|
|
1322
|
+
<path d="M4.93 4.93l1.41 1.41"></path>
|
|
1323
|
+
<path d="M17.66 17.66l1.41 1.41"></path>
|
|
1324
|
+
<path d="M2 12h2"></path>
|
|
1325
|
+
<path d="M20 12h2"></path>
|
|
1326
|
+
<path d="M4.93 19.07l1.41-1.41"></path>
|
|
1327
|
+
<path d="M17.66 6.34l1.41-1.41"></path>
|
|
1328
|
+
</svg>
|
|
1329
|
+
</span>
|
|
1330
|
+
</button>
|
|
1331
|
+
<button class="topbar-theme-mode__btn" data-theme-choice="system" type="button" title="System" aria-label="Color mode: System">
|
|
1332
|
+
<span class="theme-icon" aria-hidden="true">
|
|
1333
|
+
<svg viewBox="0 0 24 24">
|
|
1334
|
+
<rect x="3" y="4" width="18" height="12" rx="2"></rect>
|
|
1335
|
+
<path d="M8 20h8"></path>
|
|
1336
|
+
<path d="M12 16v4"></path>
|
|
1337
|
+
</svg>
|
|
1338
|
+
</span>
|
|
1339
|
+
</button>
|
|
1340
|
+
</div>
|
|
498
1341
|
</div>
|
|
499
1342
|
</div>
|
|
500
1343
|
</div>
|
|
501
|
-
<div class="
|
|
502
|
-
|
|
503
|
-
|
|
1344
|
+
<div class="main-scroll">
|
|
1345
|
+
<div class="integration-strip warn" id="integrationStatusBar">
|
|
1346
|
+
Connected to SilicaClaw: - · Network mode: - · Public discovery: -
|
|
1347
|
+
</div>
|
|
1348
|
+
<section class="page-hero">
|
|
1349
|
+
<div class="hero-copy">
|
|
1350
|
+
<h3 id="pageHeroTitle">Overview</h3>
|
|
1351
|
+
<p id="pageHeroBody">See whether this node is online and who else is visible.</p>
|
|
1352
|
+
</div>
|
|
1353
|
+
<div class="hero-meta">
|
|
1354
|
+
<div class="hero-meta-grid">
|
|
1355
|
+
<div class="hero-meta-item"><div class="label">Mode</div><div class="mono" id="heroMode">-</div></div>
|
|
1356
|
+
<div class="hero-meta-item"><div class="label">Adapter</div><div class="mono" id="heroAdapter">-</div></div>
|
|
1357
|
+
<div class="hero-meta-item"><div class="label">Relay</div><div class="mono" id="heroRelay">-</div></div>
|
|
1358
|
+
<div class="hero-meta-item"><div class="label">Room</div><div class="mono" id="heroRoom">-</div></div>
|
|
1359
|
+
</div>
|
|
1360
|
+
</div>
|
|
1361
|
+
</section>
|
|
504
1362
|
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
</div>
|
|
510
|
-
<div class="field-hint" id="publicDiscoveryHint" style="margin-bottom:12px; display:none;">
|
|
511
|
-
Public discovery only shares signed profile/presence records. It does not share private files and does not enable chat or remote control.
|
|
512
|
-
</div>
|
|
1363
|
+
<div class="notice" id="initNotice"></div>
|
|
1364
|
+
<div class="field-hint" id="publicDiscoveryHint" style="margin-bottom:12px; display:none;">
|
|
1365
|
+
Use <strong>Profile → Public Enabled</strong> as the single public visibility switch.
|
|
1366
|
+
</div>
|
|
513
1367
|
|
|
514
|
-
|
|
1368
|
+
<section id="view-overview" class="view active">
|
|
1369
|
+
<div class="section-surface compact">
|
|
1370
|
+
<div class="action-bar">
|
|
1371
|
+
<button id="overviewBroadcastNowBtn" type="button">Broadcast Now</button>
|
|
1372
|
+
<button class="secondary" id="overviewGoProfileBtn" type="button">Edit Profile</button>
|
|
1373
|
+
<button class="secondary" id="overviewGoNetworkBtn" type="button">Open Network</button>
|
|
1374
|
+
</div>
|
|
1375
|
+
</div>
|
|
515
1376
|
<div class="grid" id="overviewCards"></div>
|
|
516
1377
|
<div class="split">
|
|
517
1378
|
<div class="card">
|
|
@@ -528,9 +1389,16 @@
|
|
|
528
1389
|
<div class="mono" id="snapshot"></div>
|
|
529
1390
|
</div>
|
|
530
1391
|
</div>
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
1392
|
+
</section>
|
|
1393
|
+
|
|
1394
|
+
<section id="view-profile" class="view">
|
|
1395
|
+
<div class="section-header">
|
|
1396
|
+
<div class="section-header__copy">
|
|
1397
|
+
<div class="section-header__eyebrow">Profile</div>
|
|
1398
|
+
<h3 class="section-header__title">Public profile</h3>
|
|
1399
|
+
<p class="section-header__body">Edit the public card other nodes can see.</p>
|
|
1400
|
+
</div>
|
|
1401
|
+
</div>
|
|
534
1402
|
<div class="profile-layout">
|
|
535
1403
|
<div class="card stack">
|
|
536
1404
|
<h3 class="title-sm">Public Profile Editor</h3>
|
|
@@ -561,6 +1429,7 @@
|
|
|
561
1429
|
<div class="field-error" id="errTags"></div>
|
|
562
1430
|
</div>
|
|
563
1431
|
<label><input type="checkbox" name="public_enabled" /> Public Enabled</label>
|
|
1432
|
+
<div class="field-hint">This is the main public visibility switch used for discovery and relay broadcast.</div>
|
|
564
1433
|
<div class="actions">
|
|
565
1434
|
<button type="submit" id="saveProfileBtn">Save Profile</button>
|
|
566
1435
|
<button type="button" class="secondary" id="refreshProfileBtn">Reload</button>
|
|
@@ -592,96 +1461,144 @@
|
|
|
592
1461
|
</div>
|
|
593
1462
|
</div>
|
|
594
1463
|
</div>
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
1464
|
+
</section>
|
|
1465
|
+
|
|
1466
|
+
<section id="view-network" class="view">
|
|
1467
|
+
<div class="section-header">
|
|
1468
|
+
<div class="section-header__copy">
|
|
1469
|
+
<div class="section-header__eyebrow">Network</div>
|
|
1470
|
+
<h3 class="section-header__title">Network</h3>
|
|
1471
|
+
<p class="section-header__body">Check relay status, peers, and broadcast health.</p>
|
|
1472
|
+
</div>
|
|
1473
|
+
</div>
|
|
598
1474
|
<div class="grid" id="networkCards"></div>
|
|
599
1475
|
<div class="split">
|
|
600
1476
|
<div class="card">
|
|
601
|
-
<h3 class="title-sm">
|
|
602
|
-
<div class="
|
|
1477
|
+
<h3 class="title-sm">Connection Summary</h3>
|
|
1478
|
+
<div class="summary-list" id="networkSummaryList"></div>
|
|
603
1479
|
</div>
|
|
604
1480
|
<div class="card">
|
|
605
|
-
<h3 class="title-sm">Actions</h3>
|
|
1481
|
+
<h3 class="title-sm">Quick Actions</h3>
|
|
1482
|
+
<div class="field-hint" style="margin-bottom:10px;">Use these first.</div>
|
|
606
1483
|
<div class="actions">
|
|
607
1484
|
<button id="startBroadcastBtn">Start Broadcast</button>
|
|
608
1485
|
<button class="secondary" id="stopBroadcastBtn">Stop Broadcast</button>
|
|
609
1486
|
<button class="secondary" id="broadcastNowBtn">Broadcast Now</button>
|
|
610
|
-
<button class="secondary" id="refreshCacheBtn">Refresh Cache</button>
|
|
611
|
-
<button class="secondary" id="clearCacheBtn">Clear Discovered Cache</button>
|
|
612
|
-
<button class="secondary" id="quickGlobalPreviewBtn">Enable Cross-network Preview</button>
|
|
613
1487
|
</div>
|
|
1488
|
+
<details class="advanced-panel">
|
|
1489
|
+
<summary class="title-sm">Advanced Actions</summary>
|
|
1490
|
+
<div class="actions" style="margin-top:10px;">
|
|
1491
|
+
<button class="secondary" id="quickGlobalPreviewBtn">Enable Cross-network Preview</button>
|
|
1492
|
+
</div>
|
|
1493
|
+
</details>
|
|
614
1494
|
<div id="networkFeedback" class="feedback" style="margin-top:10px;">Ready.</div>
|
|
615
1495
|
</div>
|
|
616
1496
|
</div>
|
|
617
|
-
<
|
|
1497
|
+
<details class="advanced-panel card">
|
|
1498
|
+
<summary class="title-sm">Diagnostics</summary>
|
|
618
1499
|
<div class="card" style="margin-top:10px;">
|
|
619
|
-
<h3 class="title-sm">
|
|
620
|
-
<div class="mono
|
|
1500
|
+
<h3 class="title-sm">Runtime Components</h3>
|
|
1501
|
+
<div class="mono" id="networkComponents"></div>
|
|
621
1502
|
</div>
|
|
1503
|
+
<div class="grid" id="peerCards" style="margin-top:10px;"></div>
|
|
622
1504
|
<div class="card" style="margin-top:10px;">
|
|
623
|
-
<h3 class="title-sm">
|
|
624
|
-
<div
|
|
1505
|
+
<h3 class="title-sm">Peer Inventory</h3>
|
|
1506
|
+
<div id="peerTableWrap"></div>
|
|
625
1507
|
</div>
|
|
626
|
-
</div>
|
|
627
|
-
</section>
|
|
628
|
-
|
|
629
|
-
<section id="view-peers" class="view">
|
|
630
|
-
<div class="grid" id="peerCards"></div>
|
|
631
|
-
<div class="card" style="margin-top:10px;">
|
|
632
|
-
<h3 class="title-sm">Peer Inventory</h3>
|
|
633
|
-
<div id="peerTableWrap"></div>
|
|
634
|
-
</div>
|
|
635
|
-
<div class="card" style="margin-top:10px;">
|
|
636
|
-
<h3 class="title-sm">Peer Discovery Stats</h3>
|
|
637
|
-
<div class="mono mono-block" id="peerStatsWrap">-</div>
|
|
638
|
-
</div>
|
|
639
|
-
</section>
|
|
640
|
-
|
|
641
|
-
<section id="view-discovery" class="view">
|
|
642
|
-
<div class="grid" id="discoveryCards"></div>
|
|
643
|
-
<div class="split">
|
|
644
1508
|
<div class="card" style="margin-top:10px;">
|
|
645
|
-
<h3 class="title-sm">
|
|
646
|
-
<div class="
|
|
1509
|
+
<h3 class="title-sm">Peer Discovery Stats</h3>
|
|
1510
|
+
<div class="mono mono-block" id="peerStatsWrap">-</div>
|
|
1511
|
+
</div>
|
|
1512
|
+
<div class="grid" id="discoveryCards" style="margin-top:10px;"></div>
|
|
1513
|
+
<div class="split">
|
|
1514
|
+
<div class="card" style="margin-top:10px;">
|
|
1515
|
+
<h3 class="title-sm">Recent Discovery Events</h3>
|
|
1516
|
+
<div class="logs" id="discoveryEventList"></div>
|
|
1517
|
+
</div>
|
|
1518
|
+
<div class="card" style="margin-top:10px;">
|
|
1519
|
+
<h3 class="title-sm">Discovery Snapshot</h3>
|
|
1520
|
+
<div class="mono mono-block" id="discoverySnapshot">-</div>
|
|
1521
|
+
</div>
|
|
647
1522
|
</div>
|
|
648
1523
|
<div class="card" style="margin-top:10px;">
|
|
649
|
-
<h3 class="title-sm">
|
|
650
|
-
<div class="
|
|
1524
|
+
<h3 class="title-sm">Logs</h3>
|
|
1525
|
+
<div class="toolbar">
|
|
1526
|
+
<div class="field">
|
|
1527
|
+
<label for="logLevelFilter">Category</label>
|
|
1528
|
+
<select id="logLevelFilter">
|
|
1529
|
+
<option value="all">all</option>
|
|
1530
|
+
<option value="info">info</option>
|
|
1531
|
+
<option value="warn">warn</option>
|
|
1532
|
+
<option value="error">error</option>
|
|
1533
|
+
</select>
|
|
1534
|
+
</div>
|
|
1535
|
+
<div>
|
|
1536
|
+
<button type="button" class="secondary" id="refreshLogsBtn">Refresh Logs</button>
|
|
1537
|
+
</div>
|
|
1538
|
+
</div>
|
|
1539
|
+
<div class="logs" id="logList"></div>
|
|
1540
|
+
</div>
|
|
1541
|
+
<div class="split">
|
|
1542
|
+
<div class="card" style="margin-top:10px;">
|
|
1543
|
+
<h3 class="title-sm">Config Snapshot</h3>
|
|
1544
|
+
<div class="mono mono-block" id="networkConfigSnapshot">-</div>
|
|
1545
|
+
</div>
|
|
1546
|
+
<div class="card" style="margin-top:10px;">
|
|
1547
|
+
<h3 class="title-sm">Stats Snapshot</h3>
|
|
1548
|
+
<div class="mono mono-block" id="networkStatsSnapshot">-</div>
|
|
1549
|
+
</div>
|
|
1550
|
+
</div>
|
|
1551
|
+
</details>
|
|
1552
|
+
</section>
|
|
1553
|
+
|
|
1554
|
+
<section id="view-social" class="view">
|
|
1555
|
+
<div class="section-header">
|
|
1556
|
+
<div class="section-header__copy">
|
|
1557
|
+
<div class="section-header__eyebrow">Social</div>
|
|
1558
|
+
<h3 class="section-header__title">Social</h3>
|
|
1559
|
+
<p class="section-header__body">Switch mode and export a clean social.md template.</p>
|
|
651
1560
|
</div>
|
|
652
1561
|
</div>
|
|
653
|
-
</section>
|
|
654
|
-
|
|
655
|
-
<section id="view-social" class="view">
|
|
656
1562
|
<div class="card">
|
|
657
1563
|
<h3 class="title-sm">Integration Status</h3>
|
|
658
1564
|
<div class="feedback" id="socialStatusLine">Checking integration status...</div>
|
|
659
1565
|
<div class="field-hint" id="socialStatusSubline">-</div>
|
|
660
1566
|
<div class="field-hint" id="socialStateHint">-</div>
|
|
661
1567
|
</div>
|
|
662
|
-
<div class="
|
|
663
|
-
|
|
1568
|
+
<div class="split" style="margin-top:10px;">
|
|
1569
|
+
<div class="card">
|
|
1570
|
+
<h3 class="title-sm">What Is Active</h3>
|
|
1571
|
+
<div class="grid" id="socialPrimaryCards"></div>
|
|
1572
|
+
</div>
|
|
1573
|
+
<div class="card">
|
|
1574
|
+
<h3 class="title-sm">Identity Binding</h3>
|
|
1575
|
+
<div class="grid" id="socialIntegrationCards"></div>
|
|
1576
|
+
</div>
|
|
1577
|
+
</div>
|
|
664
1578
|
<details class="card" style="margin-top:10px;">
|
|
665
1579
|
<summary class="title-sm" style="cursor:pointer;">Advanced Network Details</summary>
|
|
666
1580
|
<div class="grid" id="socialAdvancedCards" style="margin-top:10px;"></div>
|
|
667
1581
|
<div class="mono mono-block" id="socialAdvancedWrap" style="margin-top:10px;">-</div>
|
|
668
1582
|
</details>
|
|
669
|
-
<
|
|
670
|
-
<
|
|
671
|
-
|
|
672
|
-
<div class="
|
|
673
|
-
|
|
674
|
-
|
|
1583
|
+
<details class="advanced-panel card">
|
|
1584
|
+
<summary class="title-sm">Source / Runtime / Template</summary>
|
|
1585
|
+
<div class="split">
|
|
1586
|
+
<div class="card" style="margin-top:10px;">
|
|
1587
|
+
<h3 class="title-sm">Source & Parsed Frontmatter</h3>
|
|
1588
|
+
<div class="mono mono-block" id="socialSourceWrap">-</div>
|
|
1589
|
+
<div style="height:10px;"></div>
|
|
1590
|
+
<div class="mono mono-block" id="socialRawWrap">-</div>
|
|
1591
|
+
</div>
|
|
1592
|
+
<div class="card" style="margin-top:10px;">
|
|
1593
|
+
<h3 class="title-sm">Runtime Summary</h3>
|
|
1594
|
+
<div class="mono mono-block" id="socialRuntimeWrap">-</div>
|
|
1595
|
+
</div>
|
|
675
1596
|
</div>
|
|
676
1597
|
<div class="card" style="margin-top:10px;">
|
|
677
|
-
<h3 class="title-sm">
|
|
678
|
-
<div class="mono mono-block" id="
|
|
1598
|
+
<h3 class="title-sm">Export Template Preview</h3>
|
|
1599
|
+
<div class="mono mono-block" id="socialTemplateWrap">-</div>
|
|
679
1600
|
</div>
|
|
680
|
-
</
|
|
681
|
-
<div class="card" style="margin-top:10px;">
|
|
682
|
-
<h3 class="title-sm">Export Template Preview</h3>
|
|
683
|
-
<div class="mono mono-block" id="socialTemplateWrap">-</div>
|
|
684
|
-
</div>
|
|
1601
|
+
</details>
|
|
685
1602
|
<div class="card" style="margin-top:10px;">
|
|
686
1603
|
<h3 class="title-sm">Actions</h3>
|
|
687
1604
|
<div class="toolbar">
|
|
@@ -694,46 +1611,733 @@
|
|
|
694
1611
|
</select>
|
|
695
1612
|
</div>
|
|
696
1613
|
<div>
|
|
697
|
-
<button
|
|
1614
|
+
<button id="socialModeApplyBtn">Apply Runtime Mode</button>
|
|
698
1615
|
</div>
|
|
699
1616
|
</div>
|
|
1617
|
+
<div class="field-hint" style="margin-top:10px;">Profile visibility is managed in the Profile page.</div>
|
|
700
1618
|
<div class="actions">
|
|
701
|
-
<button id="socialReloadBtn">Reload Config</button>
|
|
702
|
-
<button class="secondary" id="socialGenerateBtn">Generate Default social.md</button>
|
|
703
1619
|
<button class="secondary" id="socialExportBtn">Export social.md template</button>
|
|
704
1620
|
<button class="secondary" id="socialCopyBtn">Copy Template</button>
|
|
705
1621
|
<button class="secondary" id="socialDownloadBtn">Download Template</button>
|
|
706
1622
|
</div>
|
|
707
1623
|
<div id="socialFeedback" class="feedback" style="margin-top:10px;">Ready.</div>
|
|
708
1624
|
</div>
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
<section id="view-logs" class="view">
|
|
712
|
-
<div class="card">
|
|
713
|
-
<h3 class="title-sm">Recent Logs</h3>
|
|
714
|
-
<div class="toolbar">
|
|
715
|
-
<div class="field">
|
|
716
|
-
<label for="logLevelFilter">Category</label>
|
|
717
|
-
<select id="logLevelFilter">
|
|
718
|
-
<option value="all">all</option>
|
|
719
|
-
<option value="info">info</option>
|
|
720
|
-
<option value="warn">warn</option>
|
|
721
|
-
<option value="error">error</option>
|
|
722
|
-
</select>
|
|
723
|
-
</div>
|
|
724
|
-
<div>
|
|
725
|
-
<button type="button" class="secondary" id="refreshLogsBtn">Refresh Logs</button>
|
|
726
|
-
</div>
|
|
727
|
-
</div>
|
|
728
|
-
<div class="logs" id="logList"></div>
|
|
729
|
-
</div>
|
|
730
|
-
</section>
|
|
1625
|
+
</section>
|
|
1626
|
+
</div>
|
|
731
1627
|
</main>
|
|
732
1628
|
</div>
|
|
733
1629
|
|
|
734
1630
|
<div id="toast" class="toast"></div>
|
|
735
1631
|
|
|
736
1632
|
<script>
|
|
1633
|
+
const LOCALE_STORAGE_KEY = 'silicaclaw.i18n.locale';
|
|
1634
|
+
const DEFAULT_LOCALE = 'en';
|
|
1635
|
+
const SUPPORTED_LOCALES = ['en', 'zh-CN'];
|
|
1636
|
+
const TRANSLATIONS = {
|
|
1637
|
+
en: {
|
|
1638
|
+
meta: {
|
|
1639
|
+
title: 'SilicaClaw Control UI',
|
|
1640
|
+
description: 'SilicaClaw local-first agent control console.',
|
|
1641
|
+
socialTitle: 'SilicaClaw Local Console',
|
|
1642
|
+
socialDescription: 'Local-first control surface for SilicaClaw agents.',
|
|
1643
|
+
},
|
|
1644
|
+
common: {
|
|
1645
|
+
control: 'Control',
|
|
1646
|
+
version: 'Version',
|
|
1647
|
+
localConsole: 'Local Console',
|
|
1648
|
+
subtitle: 'OpenClaw-inspired local-first agent control surface',
|
|
1649
|
+
copied: 'Copied',
|
|
1650
|
+
done: 'Done',
|
|
1651
|
+
saving: 'Saving...',
|
|
1652
|
+
saved: 'Saved.',
|
|
1653
|
+
ready: 'Ready.',
|
|
1654
|
+
reload: 'Reload',
|
|
1655
|
+
yes: 'yes',
|
|
1656
|
+
no: 'no',
|
|
1657
|
+
on: 'enabled',
|
|
1658
|
+
off: 'disabled',
|
|
1659
|
+
unknownError: 'Unknown error',
|
|
1660
|
+
requestFailed: 'Request failed ({status})',
|
|
1661
|
+
},
|
|
1662
|
+
pageMeta: {
|
|
1663
|
+
overview: {
|
|
1664
|
+
title: 'Overview',
|
|
1665
|
+
body: 'See whether this node is online and who else is visible.',
|
|
1666
|
+
},
|
|
1667
|
+
profile: {
|
|
1668
|
+
title: 'Profile',
|
|
1669
|
+
body: 'Edit the public card other nodes can see.',
|
|
1670
|
+
},
|
|
1671
|
+
network: {
|
|
1672
|
+
title: 'Network',
|
|
1673
|
+
body: 'Check relay status, peers, and broadcast health.',
|
|
1674
|
+
},
|
|
1675
|
+
social: {
|
|
1676
|
+
title: 'Social',
|
|
1677
|
+
body: 'Switch mode and export a clean social.md template.',
|
|
1678
|
+
},
|
|
1679
|
+
},
|
|
1680
|
+
actions: {
|
|
1681
|
+
broadcastNow: 'Broadcast Now',
|
|
1682
|
+
editProfile: 'Edit Profile',
|
|
1683
|
+
openNetwork: 'Open Network',
|
|
1684
|
+
startBroadcast: 'Start Broadcast',
|
|
1685
|
+
stopBroadcast: 'Stop Broadcast',
|
|
1686
|
+
enablePreview: 'Enable Cross-network Preview',
|
|
1687
|
+
refreshLogs: 'Refresh Logs',
|
|
1688
|
+
exportTemplate: 'Export social.md template',
|
|
1689
|
+
copyTemplate: 'Copy Template',
|
|
1690
|
+
downloadTemplate: 'Download Template',
|
|
1691
|
+
applyRuntimeMode: 'Apply Runtime Mode',
|
|
1692
|
+
saveProfile: 'Save Profile',
|
|
1693
|
+
copyPublicProfilePreview: 'Copy public profile preview summary',
|
|
1694
|
+
},
|
|
1695
|
+
labels: {
|
|
1696
|
+
overviewTabCopy: 'Agent summary and discovered peers',
|
|
1697
|
+
profileTabCopy: 'Public identity and saved profile',
|
|
1698
|
+
networkTabCopy: 'Relay health, broadcast, diagnostics',
|
|
1699
|
+
socialTabCopy: 'social.md config and runtime state',
|
|
1700
|
+
collapseSidebar: 'Collapse sidebar',
|
|
1701
|
+
expandSidebar: 'Expand sidebar',
|
|
1702
|
+
toggleFocusMode: 'Toggle focus mode',
|
|
1703
|
+
exitFocusMode: 'Exit focus mode',
|
|
1704
|
+
colorMode: 'Color mode',
|
|
1705
|
+
dark: 'Dark',
|
|
1706
|
+
light: 'Light',
|
|
1707
|
+
system: 'System',
|
|
1708
|
+
mode: 'Mode',
|
|
1709
|
+
adapter: 'Adapter',
|
|
1710
|
+
relay: 'Relay',
|
|
1711
|
+
room: 'Room',
|
|
1712
|
+
namespace: 'Namespace',
|
|
1713
|
+
port: 'Port',
|
|
1714
|
+
show: 'Show',
|
|
1715
|
+
hide: 'Hide',
|
|
1716
|
+
discoveredAgents: 'Discovered Agents',
|
|
1717
|
+
onlyShowOnline: 'Only show online',
|
|
1718
|
+
nodeSnapshot: 'Node Snapshot',
|
|
1719
|
+
profileEyebrow: 'Profile',
|
|
1720
|
+
publicProfile: 'Public profile',
|
|
1721
|
+
publicProfileEditor: 'Public Profile Editor',
|
|
1722
|
+
displayName: 'Display Name',
|
|
1723
|
+
avatarUrl: 'Avatar URL',
|
|
1724
|
+
bio: 'Bio',
|
|
1725
|
+
tagsCommaSeparated: 'Tags (comma separated)',
|
|
1726
|
+
publicEnabled: 'Public Enabled',
|
|
1727
|
+
livePreview: 'Live Preview',
|
|
1728
|
+
publicCard: 'Public Card',
|
|
1729
|
+
publishStatus: 'Publish Status',
|
|
1730
|
+
publicProfilePreview: 'Public Profile Preview',
|
|
1731
|
+
networkEyebrow: 'Network',
|
|
1732
|
+
connectionSummary: 'Connection Summary',
|
|
1733
|
+
quickActions: 'Quick Actions',
|
|
1734
|
+
advancedActions: 'Advanced Actions',
|
|
1735
|
+
diagnostics: 'Diagnostics',
|
|
1736
|
+
runtimeComponents: 'Runtime Components',
|
|
1737
|
+
peerInventory: 'Peer Inventory',
|
|
1738
|
+
peerDiscoveryStats: 'Peer Discovery Stats',
|
|
1739
|
+
recentDiscoveryEvents: 'Recent Discovery Events',
|
|
1740
|
+
discoverySnapshot: 'Discovery Snapshot',
|
|
1741
|
+
logs: 'Logs',
|
|
1742
|
+
category: 'Category',
|
|
1743
|
+
configSnapshot: 'Config Snapshot',
|
|
1744
|
+
statsSnapshot: 'Stats Snapshot',
|
|
1745
|
+
socialEyebrow: 'Social',
|
|
1746
|
+
integrationStatus: 'Integration Status',
|
|
1747
|
+
whatIsActive: 'What Is Active',
|
|
1748
|
+
identityBinding: 'Identity Binding',
|
|
1749
|
+
advancedNetworkDetails: 'Advanced Network Details',
|
|
1750
|
+
sourceRuntimeTemplate: 'Source / Runtime / Template',
|
|
1751
|
+
sourceParsedFrontmatter: 'Source & Parsed Frontmatter',
|
|
1752
|
+
runtimeSummary: 'Runtime Summary',
|
|
1753
|
+
exportTemplatePreview: 'Export Template Preview',
|
|
1754
|
+
actionsTitle: 'Actions',
|
|
1755
|
+
networkModeRuntime: 'Network Mode (runtime)',
|
|
1756
|
+
},
|
|
1757
|
+
hints: {
|
|
1758
|
+
publicDiscoverySwitch: 'Use Profile -> Public Enabled as the single public visibility switch.',
|
|
1759
|
+
discoverabilityRecommendation: 'Recommended 2-32 chars for better discoverability.',
|
|
1760
|
+
avatarOptional: 'Optional. Must be http(s) URL if provided.',
|
|
1761
|
+
tagsLimit: 'Up to 8 tags, each <= 20 chars.',
|
|
1762
|
+
publicEnabledHint: 'This is the main public visibility switch used for discovery and relay broadcast.',
|
|
1763
|
+
signedPublicProfileHint: 'This is the signed public profile view other nodes/explorer can see.',
|
|
1764
|
+
useTheseFirst: 'Use these first.',
|
|
1765
|
+
profileVisibilityManaged: 'Profile visibility is managed in the Profile page.',
|
|
1766
|
+
checkingIntegration: 'Checking integration status...',
|
|
1767
|
+
allIntegrationChecksPassed: 'All integration checks passed.',
|
|
1768
|
+
},
|
|
1769
|
+
placeholders: {
|
|
1770
|
+
agentName: 'Agent name',
|
|
1771
|
+
bioSummary: 'Public summary',
|
|
1772
|
+
tags: 'ai,browser,local-first',
|
|
1773
|
+
},
|
|
1774
|
+
overview: {
|
|
1775
|
+
discovered: 'Discovered',
|
|
1776
|
+
online: 'Online',
|
|
1777
|
+
offline: 'Offline',
|
|
1778
|
+
presenceTtl: 'Presence TTL',
|
|
1779
|
+
agentsZero: '0 agents',
|
|
1780
|
+
noDiscoveredAgents: 'No discovered agents yet.',
|
|
1781
|
+
agentsOnlineFilter: '{shown}/{total} agents (online filter)',
|
|
1782
|
+
agentsDiscovered: '{count} agents discovered',
|
|
1783
|
+
tableName: 'Name',
|
|
1784
|
+
tableAgentId: 'Agent ID',
|
|
1785
|
+
tableStatus: 'Status',
|
|
1786
|
+
tableUpdated: 'Updated',
|
|
1787
|
+
unnamed: '(unnamed)',
|
|
1788
|
+
onboardingNotice: 'Connected · mode={mode} · discoverable={discoverable} · next: update your profile, turn on Public Enabled, and export social.md',
|
|
1789
|
+
pillRunning: 'broadcast: running',
|
|
1790
|
+
pillPaused: 'broadcast: paused',
|
|
1791
|
+
},
|
|
1792
|
+
preview: {
|
|
1793
|
+
unnamedAgent: '(unnamed agent)',
|
|
1794
|
+
noBioYet: 'No bio yet.',
|
|
1795
|
+
noTags: 'No tags',
|
|
1796
|
+
visibleFields: 'Visible fields: {visible} | Hidden fields: {hidden}',
|
|
1797
|
+
visible: '[visible] {field}',
|
|
1798
|
+
hidden: '[hidden] {field}',
|
|
1799
|
+
},
|
|
1800
|
+
network: {
|
|
1801
|
+
started: 'Started',
|
|
1802
|
+
transportState: 'Transport State',
|
|
1803
|
+
signalingUrl: 'Signaling URL',
|
|
1804
|
+
signalingEndpoints: 'Signaling Endpoints',
|
|
1805
|
+
webrtcRoom: 'WebRTC Room',
|
|
1806
|
+
bootstrapSources: 'Bootstrap Sources',
|
|
1807
|
+
seedPeers: 'Seed Peers',
|
|
1808
|
+
discoveryEvents: 'Discovery Events',
|
|
1809
|
+
recv: 'Recv',
|
|
1810
|
+
sent: 'Sent',
|
|
1811
|
+
peers: 'Peers',
|
|
1812
|
+
onlinePeers: 'Online Peers',
|
|
1813
|
+
activeWebrtcPeers: 'Active WebRTC Peers',
|
|
1814
|
+
reconnectAttempts: 'Reconnect Attempts',
|
|
1815
|
+
lastInbound: 'Last Inbound',
|
|
1816
|
+
lastOutbound: 'Last Outbound',
|
|
1817
|
+
relayHealth: 'Relay health',
|
|
1818
|
+
currentRelay: 'Current relay',
|
|
1819
|
+
currentRoom: 'Current room',
|
|
1820
|
+
lastJoin: 'Last join',
|
|
1821
|
+
lastPoll: 'Last poll',
|
|
1822
|
+
lastPublish: 'Last publish',
|
|
1823
|
+
lastError: 'Last error',
|
|
1824
|
+
degraded: 'degraded',
|
|
1825
|
+
connected: 'connected',
|
|
1826
|
+
none: 'none',
|
|
1827
|
+
total: 'Total',
|
|
1828
|
+
stale: 'Stale',
|
|
1829
|
+
observeCalls: 'Observe Calls',
|
|
1830
|
+
heartbeats: 'Heartbeats',
|
|
1831
|
+
peersAdded: 'Peers Added',
|
|
1832
|
+
peersRemoved: 'Peers Removed',
|
|
1833
|
+
noPeersDiscovered: 'No peers discovered yet. Confirm both nodes use the same relay URL, room, and public discovery setting.',
|
|
1834
|
+
peer: 'Peer',
|
|
1835
|
+
status: 'Status',
|
|
1836
|
+
lastSeen: 'Last Seen',
|
|
1837
|
+
staleSince: 'Stale Since',
|
|
1838
|
+
messages: 'Messages',
|
|
1839
|
+
firstSeen: 'First Seen',
|
|
1840
|
+
meta: 'Meta',
|
|
1841
|
+
eventsTotal: 'Events Total',
|
|
1842
|
+
lastEvent: 'Last Event',
|
|
1843
|
+
noDiscoveryEvents: 'No discovery events yet. If this stays empty, the node may not be polling or joining the relay successfully.',
|
|
1844
|
+
noLogsYet: 'No logs yet.',
|
|
1845
|
+
noLogsForLevel: 'No {level} logs.',
|
|
1846
|
+
},
|
|
1847
|
+
social: {
|
|
1848
|
+
connectedToSilicaClaw: 'Connected to SilicaClaw',
|
|
1849
|
+
notConnectedToSilicaClaw: 'Not connected to SilicaClaw',
|
|
1850
|
+
discoverableInCurrentMode: 'Discoverable in current mode',
|
|
1851
|
+
notDiscoverableInCurrentMode: 'Not discoverable in current mode',
|
|
1852
|
+
usingMode: 'Using {mode}',
|
|
1853
|
+
publicDiscoveryEnabled: 'Public discovery enabled',
|
|
1854
|
+
publicDiscoveryDisabled: 'Public discovery disabled',
|
|
1855
|
+
notConnected: 'Not connected',
|
|
1856
|
+
barStatus: 'Connected to SilicaClaw: {connected} · Network mode: {mode} · Public discovery: {public}',
|
|
1857
|
+
configured: 'Configured',
|
|
1858
|
+
running: 'Running',
|
|
1859
|
+
discoverable: 'Discoverable',
|
|
1860
|
+
publicDiscovery: 'Public discovery',
|
|
1861
|
+
networkMode: 'network mode',
|
|
1862
|
+
connected: 'connected',
|
|
1863
|
+
discoverableReason: 'discoverable reason',
|
|
1864
|
+
displayName: 'display name',
|
|
1865
|
+
agentId: 'agent id',
|
|
1866
|
+
socialFound: 'social.md found',
|
|
1867
|
+
socialSource: 'social.md source',
|
|
1868
|
+
runtimeGenerated: 'runtime generated',
|
|
1869
|
+
reuseOpenClawIdentity: 'reuse OpenClaw identity',
|
|
1870
|
+
mode: 'mode',
|
|
1871
|
+
broadcastStatus: 'broadcast status',
|
|
1872
|
+
namespace: 'namespace',
|
|
1873
|
+
bootstrapHints: 'bootstrap hints',
|
|
1874
|
+
restartRequired: 'restart required',
|
|
1875
|
+
configuredReason: 'Configured: {reason}',
|
|
1876
|
+
runningReason: 'Running: {reason}',
|
|
1877
|
+
discoverableReasonFull: 'Discoverable: {reason}',
|
|
1878
|
+
},
|
|
1879
|
+
feedback: {
|
|
1880
|
+
unsavedChanges: 'You have unsaved changes.',
|
|
1881
|
+
allChangesSaved: 'All changes saved.',
|
|
1882
|
+
fixValidation: 'Please fix validation errors before saving.',
|
|
1883
|
+
savingProfile: 'Saving profile...',
|
|
1884
|
+
profileSaved: 'Profile saved',
|
|
1885
|
+
profileReloaded: 'Profile form reloaded',
|
|
1886
|
+
exportingTemplate: 'Exporting template...',
|
|
1887
|
+
templateExported: 'Template exported from current runtime.',
|
|
1888
|
+
templateCopied: 'Template copied to clipboard.',
|
|
1889
|
+
preparingDownload: 'Preparing download...',
|
|
1890
|
+
runtimeUpdated: 'Runtime mode updated.',
|
|
1891
|
+
copyPreviewFailed: 'Copy preview failed',
|
|
1892
|
+
logsRefreshed: 'Logs refreshed',
|
|
1893
|
+
crossPreviewEnabled: 'Cross-network preview enabled',
|
|
1894
|
+
enableCrossPreviewFailed: 'Enable cross-network preview failed',
|
|
1895
|
+
downloadFailed: 'Download failed',
|
|
1896
|
+
exportFailed: 'Export failed',
|
|
1897
|
+
copyFailed: 'Copy failed',
|
|
1898
|
+
failed: 'Failed',
|
|
1899
|
+
runtimeMode: 'Runtime mode: {mode}',
|
|
1900
|
+
downloaded: 'Downloaded {filename}.',
|
|
1901
|
+
runtimeModeApplying: 'Applying runtime mode: {mode}...',
|
|
1902
|
+
copyingTemplate: 'Copying template...',
|
|
1903
|
+
crossPreviewEnabling: 'Enabling cross-network preview...',
|
|
1904
|
+
promptSignalingUrl: 'Signaling URL (publicly reachable):',
|
|
1905
|
+
promptRoom: 'Room:',
|
|
1906
|
+
},
|
|
1907
|
+
validation: {
|
|
1908
|
+
displayNameShort: 'Display name should be at least 2 chars.',
|
|
1909
|
+
displayNameLong: 'Display name too long.',
|
|
1910
|
+
avatarProtocol: 'Avatar URL must start with http:// or https://',
|
|
1911
|
+
tooManyTags: 'Too many tags (max 8).',
|
|
1912
|
+
tagTooLong: 'Each tag must be <= 20 chars.',
|
|
1913
|
+
leaveConfirm: 'You have unsaved profile changes. Leave anyway?',
|
|
1914
|
+
},
|
|
1915
|
+
},
|
|
1916
|
+
'zh-CN': {
|
|
1917
|
+
meta: {
|
|
1918
|
+
title: 'SilicaClaw 控制台',
|
|
1919
|
+
description: 'SilicaClaw 本地优先代理控制台。',
|
|
1920
|
+
socialTitle: 'SilicaClaw 本地控制台',
|
|
1921
|
+
socialDescription: '面向 SilicaClaw 代理的本地优先控制界面。',
|
|
1922
|
+
},
|
|
1923
|
+
common: {
|
|
1924
|
+
control: '控制',
|
|
1925
|
+
version: '版本',
|
|
1926
|
+
localConsole: '本地控制台',
|
|
1927
|
+
subtitle: '受 OpenClaw 启发的本地优先代理控制界面',
|
|
1928
|
+
copied: '已复制',
|
|
1929
|
+
done: '完成',
|
|
1930
|
+
saving: '保存中...',
|
|
1931
|
+
saved: '已保存。',
|
|
1932
|
+
ready: '就绪。',
|
|
1933
|
+
reload: '重新加载',
|
|
1934
|
+
yes: '是',
|
|
1935
|
+
no: '否',
|
|
1936
|
+
on: '已启用',
|
|
1937
|
+
off: '已禁用',
|
|
1938
|
+
unknownError: '未知错误',
|
|
1939
|
+
requestFailed: '请求失败 ({status})',
|
|
1940
|
+
},
|
|
1941
|
+
pageMeta: {
|
|
1942
|
+
overview: {
|
|
1943
|
+
title: '概览',
|
|
1944
|
+
body: '查看当前节点是否在线,以及还能看到哪些节点。',
|
|
1945
|
+
},
|
|
1946
|
+
profile: {
|
|
1947
|
+
title: 'Profile',
|
|
1948
|
+
body: '编辑其他节点可见的公开名片。',
|
|
1949
|
+
},
|
|
1950
|
+
network: {
|
|
1951
|
+
title: '网络',
|
|
1952
|
+
body: '检查 relay 状态、对等节点和广播健康度。',
|
|
1953
|
+
},
|
|
1954
|
+
social: {
|
|
1955
|
+
title: '社交',
|
|
1956
|
+
body: '切换模式并导出干净的 social.md 模板。',
|
|
1957
|
+
},
|
|
1958
|
+
},
|
|
1959
|
+
actions: {
|
|
1960
|
+
broadcastNow: '立即广播',
|
|
1961
|
+
editProfile: '编辑 Profile',
|
|
1962
|
+
openNetwork: '打开网络页',
|
|
1963
|
+
startBroadcast: '启动广播',
|
|
1964
|
+
stopBroadcast: '停止广播',
|
|
1965
|
+
enablePreview: '启用跨网络预览',
|
|
1966
|
+
refreshLogs: '刷新日志',
|
|
1967
|
+
exportTemplate: '导出 social.md 模板',
|
|
1968
|
+
copyTemplate: '复制模板',
|
|
1969
|
+
downloadTemplate: '下载模板',
|
|
1970
|
+
applyRuntimeMode: '应用运行时模式',
|
|
1971
|
+
saveProfile: '保存 Profile',
|
|
1972
|
+
copyPublicProfilePreview: '复制公开 Profile 预览摘要',
|
|
1973
|
+
},
|
|
1974
|
+
labels: {
|
|
1975
|
+
overviewTabCopy: '代理摘要与已发现节点',
|
|
1976
|
+
profileTabCopy: '公开身份与已保存的 Profile',
|
|
1977
|
+
networkTabCopy: 'Relay 健康度、广播与诊断',
|
|
1978
|
+
socialTabCopy: 'social.md 配置与运行时状态',
|
|
1979
|
+
collapseSidebar: '折叠侧边栏',
|
|
1980
|
+
expandSidebar: '展开侧边栏',
|
|
1981
|
+
toggleFocusMode: '切换专注模式',
|
|
1982
|
+
exitFocusMode: '退出专注模式',
|
|
1983
|
+
colorMode: '颜色模式',
|
|
1984
|
+
dark: '深色',
|
|
1985
|
+
light: '浅色',
|
|
1986
|
+
system: '跟随系统',
|
|
1987
|
+
mode: '模式',
|
|
1988
|
+
adapter: '适配器',
|
|
1989
|
+
relay: 'Relay',
|
|
1990
|
+
room: '房间',
|
|
1991
|
+
namespace: '命名空间',
|
|
1992
|
+
port: '端口',
|
|
1993
|
+
show: '显示',
|
|
1994
|
+
hide: '隐藏',
|
|
1995
|
+
discoveredAgents: '已发现代理',
|
|
1996
|
+
onlyShowOnline: '只显示在线',
|
|
1997
|
+
nodeSnapshot: '节点快照',
|
|
1998
|
+
profileEyebrow: 'Profile',
|
|
1999
|
+
publicProfile: '公开 Profile',
|
|
2000
|
+
publicProfileEditor: '公开 Profile 编辑器',
|
|
2001
|
+
displayName: '显示名称',
|
|
2002
|
+
avatarUrl: '头像 URL',
|
|
2003
|
+
bio: '简介',
|
|
2004
|
+
tagsCommaSeparated: '标签(逗号分隔)',
|
|
2005
|
+
publicEnabled: '公开启用',
|
|
2006
|
+
livePreview: '实时预览',
|
|
2007
|
+
publicCard: '公开卡片',
|
|
2008
|
+
publishStatus: '发布状态',
|
|
2009
|
+
publicProfilePreview: '公开 Profile 预览',
|
|
2010
|
+
networkEyebrow: '网络',
|
|
2011
|
+
connectionSummary: '连接摘要',
|
|
2012
|
+
quickActions: '快捷操作',
|
|
2013
|
+
advancedActions: '高级操作',
|
|
2014
|
+
diagnostics: '诊断',
|
|
2015
|
+
runtimeComponents: '运行时组件',
|
|
2016
|
+
peerInventory: '节点清单',
|
|
2017
|
+
peerDiscoveryStats: '节点发现统计',
|
|
2018
|
+
recentDiscoveryEvents: '最近发现事件',
|
|
2019
|
+
discoverySnapshot: '发现快照',
|
|
2020
|
+
logs: '日志',
|
|
2021
|
+
category: '类别',
|
|
2022
|
+
configSnapshot: '配置快照',
|
|
2023
|
+
statsSnapshot: '统计快照',
|
|
2024
|
+
socialEyebrow: '社交',
|
|
2025
|
+
integrationStatus: '集成状态',
|
|
2026
|
+
whatIsActive: '当前激活项',
|
|
2027
|
+
identityBinding: '身份绑定',
|
|
2028
|
+
advancedNetworkDetails: '高级网络详情',
|
|
2029
|
+
sourceRuntimeTemplate: '来源 / 运行时 / 模板',
|
|
2030
|
+
sourceParsedFrontmatter: '源文件与解析后的 Frontmatter',
|
|
2031
|
+
runtimeSummary: '运行时摘要',
|
|
2032
|
+
exportTemplatePreview: '导出模板预览',
|
|
2033
|
+
actionsTitle: '操作',
|
|
2034
|
+
networkModeRuntime: '网络模式(运行时)',
|
|
2035
|
+
},
|
|
2036
|
+
hints: {
|
|
2037
|
+
publicDiscoverySwitch: '使用 Profile -> Public Enabled 作为唯一的公开可见性开关。',
|
|
2038
|
+
discoverabilityRecommendation: '建议 2-32 个字符,以提升可发现性。',
|
|
2039
|
+
avatarOptional: '可选。如提供,必须是 http(s) URL。',
|
|
2040
|
+
tagsLimit: '最多 8 个标签,每个不超过 20 个字符。',
|
|
2041
|
+
publicEnabledHint: '这是发现与 relay 广播使用的主公开可见性开关。',
|
|
2042
|
+
signedPublicProfileHint: '这是其他节点或 explorer 可以看到的已签名公开 Profile 视图。',
|
|
2043
|
+
useTheseFirst: '优先使用这些操作。',
|
|
2044
|
+
profileVisibilityManaged: 'Profile 可见性在 Profile 页面管理。',
|
|
2045
|
+
checkingIntegration: '正在检查集成状态...',
|
|
2046
|
+
allIntegrationChecksPassed: '所有集成检查均已通过。',
|
|
2047
|
+
},
|
|
2048
|
+
placeholders: {
|
|
2049
|
+
agentName: '代理名称',
|
|
2050
|
+
bioSummary: '公开摘要',
|
|
2051
|
+
tags: 'ai,browser,local-first',
|
|
2052
|
+
},
|
|
2053
|
+
overview: {
|
|
2054
|
+
discovered: '已发现',
|
|
2055
|
+
online: '在线',
|
|
2056
|
+
offline: '离线',
|
|
2057
|
+
presenceTtl: 'Presence TTL',
|
|
2058
|
+
agentsZero: '0 个代理',
|
|
2059
|
+
noDiscoveredAgents: '还没有发现代理。',
|
|
2060
|
+
agentsOnlineFilter: '{shown}/{total} 个代理(在线筛选)',
|
|
2061
|
+
agentsDiscovered: '已发现 {count} 个代理',
|
|
2062
|
+
tableName: '名称',
|
|
2063
|
+
tableAgentId: '代理 ID',
|
|
2064
|
+
tableStatus: '状态',
|
|
2065
|
+
tableUpdated: '更新时间',
|
|
2066
|
+
unnamed: '(未命名)',
|
|
2067
|
+
onboardingNotice: '已连接 · mode={mode} · discoverable={discoverable} · 下一步:更新 Profile、开启 Public Enabled,并导出 social.md',
|
|
2068
|
+
pillRunning: 'broadcast: 运行中',
|
|
2069
|
+
pillPaused: 'broadcast: 已暂停',
|
|
2070
|
+
},
|
|
2071
|
+
preview: {
|
|
2072
|
+
unnamedAgent: '(未命名代理)',
|
|
2073
|
+
noBioYet: '还没有简介。',
|
|
2074
|
+
noTags: '没有标签',
|
|
2075
|
+
visibleFields: '显示字段: {visible} | 隐藏字段: {hidden}',
|
|
2076
|
+
visible: '[显示] {field}',
|
|
2077
|
+
hidden: '[隐藏] {field}',
|
|
2078
|
+
},
|
|
2079
|
+
network: {
|
|
2080
|
+
started: '已启动',
|
|
2081
|
+
transportState: '传输状态',
|
|
2082
|
+
signalingUrl: 'Signaling URL',
|
|
2083
|
+
signalingEndpoints: 'Signaling 端点',
|
|
2084
|
+
webrtcRoom: 'WebRTC 房间',
|
|
2085
|
+
bootstrapSources: 'Bootstrap 来源',
|
|
2086
|
+
seedPeers: '种子节点',
|
|
2087
|
+
discoveryEvents: '发现事件',
|
|
2088
|
+
recv: '接收',
|
|
2089
|
+
sent: '发送',
|
|
2090
|
+
peers: '节点',
|
|
2091
|
+
onlinePeers: '在线节点',
|
|
2092
|
+
activeWebrtcPeers: '活跃 WebRTC 节点',
|
|
2093
|
+
reconnectAttempts: '重连尝试次数',
|
|
2094
|
+
lastInbound: '最近入站',
|
|
2095
|
+
lastOutbound: '最近出站',
|
|
2096
|
+
relayHealth: 'Relay 健康度',
|
|
2097
|
+
currentRelay: '当前 Relay',
|
|
2098
|
+
currentRoom: '当前房间',
|
|
2099
|
+
lastJoin: '最近加入',
|
|
2100
|
+
lastPoll: '最近轮询',
|
|
2101
|
+
lastPublish: '最近发布',
|
|
2102
|
+
lastError: '最近错误',
|
|
2103
|
+
degraded: '降级',
|
|
2104
|
+
connected: '已连接',
|
|
2105
|
+
none: '无',
|
|
2106
|
+
total: '总数',
|
|
2107
|
+
stale: '陈旧',
|
|
2108
|
+
observeCalls: '观察调用',
|
|
2109
|
+
heartbeats: '心跳',
|
|
2110
|
+
peersAdded: '新增节点',
|
|
2111
|
+
peersRemoved: '移除节点',
|
|
2112
|
+
noPeersDiscovered: '尚未发现节点。请确认两端使用相同的 relay URL、room 与公开发现设置。',
|
|
2113
|
+
peer: '节点',
|
|
2114
|
+
status: '状态',
|
|
2115
|
+
lastSeen: '最近出现',
|
|
2116
|
+
staleSince: '陈旧开始于',
|
|
2117
|
+
messages: '消息数',
|
|
2118
|
+
firstSeen: '首次出现',
|
|
2119
|
+
meta: '元数据',
|
|
2120
|
+
eventsTotal: '事件总数',
|
|
2121
|
+
lastEvent: '最近事件',
|
|
2122
|
+
noDiscoveryEvents: '还没有发现事件。如果这里持续为空,节点可能没有成功轮询或加入 relay。',
|
|
2123
|
+
noLogsYet: '还没有日志。',
|
|
2124
|
+
noLogsForLevel: '没有 {level} 级别日志。',
|
|
2125
|
+
},
|
|
2126
|
+
social: {
|
|
2127
|
+
connectedToSilicaClaw: '已连接到 SilicaClaw',
|
|
2128
|
+
notConnectedToSilicaClaw: '未连接到 SilicaClaw',
|
|
2129
|
+
discoverableInCurrentMode: '当前模式下可发现',
|
|
2130
|
+
notDiscoverableInCurrentMode: '当前模式下不可发现',
|
|
2131
|
+
usingMode: '使用 {mode}',
|
|
2132
|
+
publicDiscoveryEnabled: '公开发现已启用',
|
|
2133
|
+
publicDiscoveryDisabled: '公开发现已禁用',
|
|
2134
|
+
notConnected: '未连接',
|
|
2135
|
+
barStatus: 'Connected to SilicaClaw: {connected} · Network mode: {mode} · Public discovery: {public}',
|
|
2136
|
+
configured: '已配置',
|
|
2137
|
+
running: '运行中',
|
|
2138
|
+
discoverable: '可发现',
|
|
2139
|
+
publicDiscovery: '公开发现',
|
|
2140
|
+
networkMode: '网络模式',
|
|
2141
|
+
connected: '已连接',
|
|
2142
|
+
discoverableReason: '可发现原因',
|
|
2143
|
+
displayName: '显示名称',
|
|
2144
|
+
agentId: '代理 ID',
|
|
2145
|
+
socialFound: '已找到 social.md',
|
|
2146
|
+
socialSource: 'social.md 来源',
|
|
2147
|
+
runtimeGenerated: '运行时生成',
|
|
2148
|
+
reuseOpenClawIdentity: '复用 OpenClaw 身份',
|
|
2149
|
+
mode: '模式',
|
|
2150
|
+
broadcastStatus: '广播状态',
|
|
2151
|
+
namespace: '命名空间',
|
|
2152
|
+
bootstrapHints: 'Bootstrap 提示',
|
|
2153
|
+
restartRequired: '需要重启',
|
|
2154
|
+
configuredReason: 'Configured: {reason}',
|
|
2155
|
+
runningReason: 'Running: {reason}',
|
|
2156
|
+
discoverableReasonFull: 'Discoverable: {reason}',
|
|
2157
|
+
},
|
|
2158
|
+
feedback: {
|
|
2159
|
+
unsavedChanges: '你有尚未保存的更改。',
|
|
2160
|
+
allChangesSaved: '所有更改都已保存。',
|
|
2161
|
+
fixValidation: '请先修复校验错误再保存。',
|
|
2162
|
+
savingProfile: '正在保存 Profile...',
|
|
2163
|
+
profileSaved: 'Profile 已保存',
|
|
2164
|
+
profileReloaded: 'Profile 表单已重新加载',
|
|
2165
|
+
exportingTemplate: '正在导出模板...',
|
|
2166
|
+
templateExported: '已按当前运行时导出模板。',
|
|
2167
|
+
templateCopied: '模板已复制到剪贴板。',
|
|
2168
|
+
preparingDownload: '正在准备下载...',
|
|
2169
|
+
runtimeUpdated: '运行时模式已更新。',
|
|
2170
|
+
copyPreviewFailed: '复制预览失败',
|
|
2171
|
+
logsRefreshed: '日志已刷新',
|
|
2172
|
+
crossPreviewEnabled: '跨网络预览已启用',
|
|
2173
|
+
enableCrossPreviewFailed: '启用跨网络预览失败',
|
|
2174
|
+
downloadFailed: '下载失败',
|
|
2175
|
+
exportFailed: '导出失败',
|
|
2176
|
+
copyFailed: '复制失败',
|
|
2177
|
+
failed: '失败',
|
|
2178
|
+
runtimeMode: '运行时模式: {mode}',
|
|
2179
|
+
downloaded: '已下载 {filename}。',
|
|
2180
|
+
runtimeModeApplying: '正在应用运行时模式: {mode}...',
|
|
2181
|
+
copyingTemplate: '正在复制模板...',
|
|
2182
|
+
crossPreviewEnabling: '正在启用跨网络预览...',
|
|
2183
|
+
promptSignalingUrl: 'Signaling URL(需公网可达):',
|
|
2184
|
+
promptRoom: '房间:',
|
|
2185
|
+
},
|
|
2186
|
+
validation: {
|
|
2187
|
+
displayNameShort: '显示名称至少需要 2 个字符。',
|
|
2188
|
+
displayNameLong: '显示名称过长。',
|
|
2189
|
+
avatarProtocol: '头像 URL 必须以 http:// 或 https:// 开头',
|
|
2190
|
+
tooManyTags: '标签过多(最多 8 个)。',
|
|
2191
|
+
tagTooLong: '每个标签必须不超过 20 个字符。',
|
|
2192
|
+
leaveConfirm: '你有未保存的 Profile 更改,仍要离开吗?',
|
|
2193
|
+
},
|
|
2194
|
+
},
|
|
2195
|
+
};
|
|
2196
|
+
function isSupportedLocale(value) {
|
|
2197
|
+
return SUPPORTED_LOCALES.includes(value);
|
|
2198
|
+
}
|
|
2199
|
+
function resolveNavigatorLocale(language) {
|
|
2200
|
+
return String(language || '').toLowerCase().startsWith('zh') ? 'zh-CN' : DEFAULT_LOCALE;
|
|
2201
|
+
}
|
|
2202
|
+
function resolveInitialLocale() {
|
|
2203
|
+
const saved = localStorage.getItem(LOCALE_STORAGE_KEY);
|
|
2204
|
+
if (isSupportedLocale(saved)) return saved;
|
|
2205
|
+
return resolveNavigatorLocale(globalThis.navigator?.language || '');
|
|
2206
|
+
}
|
|
2207
|
+
let currentLocale = resolveInitialLocale();
|
|
2208
|
+
function t(key, params = {}) {
|
|
2209
|
+
const parts = key.split('.');
|
|
2210
|
+
const resolve = (bundle) => parts.reduce((acc, part) => (acc && typeof acc === 'object' ? acc[part] : undefined), bundle);
|
|
2211
|
+
let value = resolve(TRANSLATIONS[currentLocale]);
|
|
2212
|
+
if (typeof value !== 'string') value = resolve(TRANSLATIONS[DEFAULT_LOCALE]);
|
|
2213
|
+
if (typeof value !== 'string') return key;
|
|
2214
|
+
return value.replace(/\{(\w+)\}/g, (_, name) => params[name] ?? `{${name}}`);
|
|
2215
|
+
}
|
|
2216
|
+
function setLocale(locale) {
|
|
2217
|
+
currentLocale = isSupportedLocale(locale) ? locale : DEFAULT_LOCALE;
|
|
2218
|
+
document.documentElement.lang = currentLocale;
|
|
2219
|
+
}
|
|
2220
|
+
function applyStaticTranslations() {
|
|
2221
|
+
const setText = (selector, text, index = 0) => {
|
|
2222
|
+
const nodes = document.querySelectorAll(selector);
|
|
2223
|
+
if (nodes[index]) nodes[index].textContent = text;
|
|
2224
|
+
};
|
|
2225
|
+
document.title = t('meta.title');
|
|
2226
|
+
document.getElementById('metaDescription').setAttribute('content', t('meta.description'));
|
|
2227
|
+
document.getElementById('ogTitle').setAttribute('content', t('meta.socialTitle'));
|
|
2228
|
+
document.getElementById('ogDescription').setAttribute('content', t('meta.socialDescription'));
|
|
2229
|
+
document.getElementById('twitterTitle').setAttribute('content', t('meta.socialTitle'));
|
|
2230
|
+
document.getElementById('twitterDescription').setAttribute('content', t('meta.socialDescription'));
|
|
2231
|
+
setText('.brand p', 'Control UI');
|
|
2232
|
+
document.querySelectorAll('.advanced-panel summary').forEach((summary) => {
|
|
2233
|
+
summary.setAttribute('data-i18n-closed-label', t('labels.show'));
|
|
2234
|
+
summary.setAttribute('data-i18n-open-label', t('labels.hide'));
|
|
2235
|
+
});
|
|
2236
|
+
setText('.sidebar-nav__label', t('common.control'));
|
|
2237
|
+
setText('[data-tab="overview"] .tab-title', t('pageMeta.overview.title'));
|
|
2238
|
+
setText('[data-tab="overview"] .tab-copy', t('labels.overviewTabCopy'));
|
|
2239
|
+
setText('[data-tab="profile"] .tab-title', t('pageMeta.profile.title'));
|
|
2240
|
+
setText('[data-tab="profile"] .tab-copy', t('labels.profileTabCopy'));
|
|
2241
|
+
setText('[data-tab="network"] .tab-title', t('pageMeta.network.title'));
|
|
2242
|
+
setText('[data-tab="network"] .tab-copy', t('labels.networkTabCopy'));
|
|
2243
|
+
setText('[data-tab="social"] .tab-title', t('pageMeta.social.title'));
|
|
2244
|
+
setText('[data-tab="social"] .tab-copy', t('labels.socialTabCopy'));
|
|
2245
|
+
document.getElementById('sidebarToggleBtn').title = t('labels.collapseSidebar');
|
|
2246
|
+
document.getElementById('sidebarToggleBtn').setAttribute('aria-label', t('labels.collapseSidebar'));
|
|
2247
|
+
document.querySelector('.sidebar-version').title = t('common.version');
|
|
2248
|
+
setText('.sidebar-version__label', t('common.version'));
|
|
2249
|
+
setText('.dashboard-header__breadcrumb-current', t('pageMeta.overview.title'));
|
|
2250
|
+
document.getElementById('topbarTitle').textContent = t('common.localConsole');
|
|
2251
|
+
document.getElementById('topbarSubtitle').textContent = t('common.subtitle');
|
|
2252
|
+
document.getElementById('focusModeBtn').title = t('labels.toggleFocusMode');
|
|
2253
|
+
document.getElementById('focusModeBtn').setAttribute('aria-label', t('labels.toggleFocusMode'));
|
|
2254
|
+
document.getElementById('themeModeGroup').setAttribute('aria-label', t('labels.colorMode'));
|
|
2255
|
+
document.querySelector('[data-theme-choice="dark"]').title = t('labels.dark');
|
|
2256
|
+
document.querySelector('[data-theme-choice="dark"]').setAttribute('aria-label', `${t('labels.colorMode')}: ${t('labels.dark')}`);
|
|
2257
|
+
document.querySelector('[data-theme-choice="light"]').title = t('labels.light');
|
|
2258
|
+
document.querySelector('[data-theme-choice="light"]').setAttribute('aria-label', `${t('labels.colorMode')}: ${t('labels.light')}`);
|
|
2259
|
+
document.querySelector('[data-theme-choice="system"]').title = t('labels.system');
|
|
2260
|
+
document.querySelector('[data-theme-choice="system"]').setAttribute('aria-label', `${t('labels.colorMode')}: ${t('labels.system')}`);
|
|
2261
|
+
setText('#view-overview .title-sm', t('labels.discoveredAgents'), 0);
|
|
2262
|
+
document.getElementById('agentsCountHint').textContent = t('overview.agentsZero');
|
|
2263
|
+
setText('#view-overview label.field-hint', t('labels.onlyShowOnline'));
|
|
2264
|
+
setText('#view-overview .title-sm', t('labels.nodeSnapshot'), 1);
|
|
2265
|
+
setText('#view-profile .section-header__eyebrow', t('labels.profileEyebrow'));
|
|
2266
|
+
setText('#view-profile .section-header__title', t('labels.publicProfile'));
|
|
2267
|
+
setText('#view-profile .title-sm', t('labels.publicProfileEditor'), 0);
|
|
2268
|
+
setText('#view-profile label', t('labels.displayName'), 0);
|
|
2269
|
+
setText('#view-profile .row > div:nth-child(2) label', t('labels.avatarUrl'));
|
|
2270
|
+
setText('#view-profile div > label + textarea', t('labels.bio'));
|
|
2271
|
+
setText('#view-profile div > label + input[name="tags"]', t('labels.tagsCommaSeparated'));
|
|
2272
|
+
document.querySelector('#view-profile input[name="display_name"]').setAttribute('placeholder', t('placeholders.agentName'));
|
|
2273
|
+
document.querySelector('#view-profile input[name="avatar_url"]').setAttribute('placeholder', 'https://...');
|
|
2274
|
+
document.querySelector('#view-profile textarea[name="bio"]').setAttribute('placeholder', t('placeholders.bioSummary'));
|
|
2275
|
+
document.querySelector('#view-profile input[name="tags"]').setAttribute('placeholder', t('placeholders.tags'));
|
|
2276
|
+
document.querySelector('#view-profile input[name="display_name"]').nextElementSibling.textContent = t('hints.discoverabilityRecommendation');
|
|
2277
|
+
document.querySelector('#view-profile input[name="avatar_url"]').nextElementSibling.textContent = t('hints.avatarOptional');
|
|
2278
|
+
document.querySelector('#view-profile input[name="tags"]').nextElementSibling.textContent = t('hints.tagsLimit');
|
|
2279
|
+
document.querySelector('#view-profile input[name="public_enabled"]').parentElement.childNodes[1].textContent = ` ${t('labels.publicEnabled')}`;
|
|
2280
|
+
setText('#view-profile .field-hint', t('hints.publicEnabledHint'), 3);
|
|
2281
|
+
setText('#view-profile .title-sm', t('labels.livePreview'), 1);
|
|
2282
|
+
setText('#view-profile .profile-meta h4', t('labels.publicCard'), 0);
|
|
2283
|
+
setText('#view-profile .profile-meta h4', t('labels.publishStatus'), 1);
|
|
2284
|
+
setText('#view-profile .profile-meta h4', t('labels.publicProfilePreview'), 2);
|
|
2285
|
+
setText('#view-profile .profile-meta .field-hint', t('hints.signedPublicProfileHint'));
|
|
2286
|
+
setText('#view-network .section-header__eyebrow', t('labels.networkEyebrow'));
|
|
2287
|
+
setText('#view-network .section-header__title', t('pageMeta.network.title'));
|
|
2288
|
+
setText('#view-network .split .card .title-sm', t('labels.connectionSummary'), 0);
|
|
2289
|
+
setText('#view-network .split .card .title-sm', t('labels.quickActions'), 1);
|
|
2290
|
+
setText('#view-network .split .card .field-hint', t('hints.useTheseFirst'));
|
|
2291
|
+
setText('#view-network details.advanced-panel summary', t('labels.advancedActions'), 0);
|
|
2292
|
+
setText('#view-network > details.advanced-panel.card > summary', t('labels.diagnostics'));
|
|
2293
|
+
setText('#view-network .card .title-sm', t('labels.runtimeComponents'), 3);
|
|
2294
|
+
setText('#view-network .card .title-sm', t('labels.peerInventory'), 4);
|
|
2295
|
+
setText('#view-network .card .title-sm', t('labels.peerDiscoveryStats'), 5);
|
|
2296
|
+
setText('#view-network .card .title-sm', t('labels.recentDiscoveryEvents'), 6);
|
|
2297
|
+
setText('#view-network .card .title-sm', t('labels.discoverySnapshot'), 7);
|
|
2298
|
+
setText('#view-network label[for="logLevelFilter"]', t('labels.category'));
|
|
2299
|
+
setText('#view-network .card .title-sm', t('labels.configSnapshot'), 9);
|
|
2300
|
+
setText('#view-network .card .title-sm', t('labels.statsSnapshot'), 10);
|
|
2301
|
+
setText('#view-social .section-header__eyebrow', t('labels.socialEyebrow'));
|
|
2302
|
+
setText('#view-social .section-header__title', t('pageMeta.social.title'));
|
|
2303
|
+
setText('#view-social .card .title-sm', t('labels.integrationStatus'), 0);
|
|
2304
|
+
document.querySelector('#socialStatusLine').textContent = t('hints.checkingIntegration');
|
|
2305
|
+
setText('#view-social .split .card .title-sm', t('labels.whatIsActive'), 0);
|
|
2306
|
+
setText('#view-social .split .card .title-sm', t('labels.identityBinding'), 1);
|
|
2307
|
+
setText('#view-social details.card summary', t('labels.advancedNetworkDetails'));
|
|
2308
|
+
setText('#view-social details.advanced-panel summary', t('labels.sourceRuntimeTemplate'));
|
|
2309
|
+
setText('#view-social .card .title-sm', t('labels.sourceParsedFrontmatter'), 3);
|
|
2310
|
+
setText('#view-social .card .title-sm', t('labels.runtimeSummary'), 4);
|
|
2311
|
+
setText('#view-social .card .title-sm', t('labels.exportTemplatePreview'), 5);
|
|
2312
|
+
setText('#view-social .card .title-sm', t('labels.actionsTitle'), 6);
|
|
2313
|
+
setText('label[for="socialModeSelect"]', t('labels.networkModeRuntime'));
|
|
2314
|
+
setText('#view-social > .card:last-of-type .field-hint', t('hints.profileVisibilityManaged'));
|
|
2315
|
+
setText('.hero-meta-item .label', t('labels.mode'), 0);
|
|
2316
|
+
setText('.hero-meta-item .label', t('labels.adapter'), 1);
|
|
2317
|
+
setText('.hero-meta-item .label', t('labels.relay'), 2);
|
|
2318
|
+
setText('.hero-meta-item .label', t('labels.room'), 3);
|
|
2319
|
+
document.getElementById('publicDiscoveryHint').innerHTML = t('hints.publicDiscoverySwitch');
|
|
2320
|
+
document.getElementById('overviewBroadcastNowBtn').textContent = t('actions.broadcastNow');
|
|
2321
|
+
document.getElementById('overviewGoProfileBtn').textContent = t('actions.editProfile');
|
|
2322
|
+
document.getElementById('overviewGoNetworkBtn').textContent = t('actions.openNetwork');
|
|
2323
|
+
document.getElementById('startBroadcastBtn').textContent = t('actions.startBroadcast');
|
|
2324
|
+
document.getElementById('stopBroadcastBtn').textContent = t('actions.stopBroadcast');
|
|
2325
|
+
document.getElementById('quickGlobalPreviewBtn').textContent = t('actions.enablePreview');
|
|
2326
|
+
document.getElementById('refreshLogsBtn').textContent = t('actions.refreshLogs');
|
|
2327
|
+
document.getElementById('socialExportBtn').textContent = t('actions.exportTemplate');
|
|
2328
|
+
document.getElementById('socialCopyBtn').textContent = t('actions.copyTemplate');
|
|
2329
|
+
document.getElementById('socialDownloadBtn').textContent = t('actions.downloadTemplate');
|
|
2330
|
+
document.getElementById('socialModeApplyBtn').textContent = t('actions.applyRuntimeMode');
|
|
2331
|
+
document.getElementById('copyPublicProfilePreviewBtn').textContent = t('actions.copyPublicProfilePreview');
|
|
2332
|
+
document.getElementById('saveProfileBtn').textContent = t('actions.saveProfile');
|
|
2333
|
+
document.getElementById('refreshProfileBtn').textContent = t('common.reload');
|
|
2334
|
+
document.getElementById('profileFeedback').textContent = t('common.ready');
|
|
2335
|
+
document.getElementById('networkFeedback').textContent = t('common.ready');
|
|
2336
|
+
document.getElementById('socialFeedback').textContent = t('common.ready');
|
|
2337
|
+
}
|
|
2338
|
+
setLocale(currentLocale);
|
|
2339
|
+
applyStaticTranslations();
|
|
2340
|
+
|
|
737
2341
|
let activeTab = 'overview';
|
|
738
2342
|
let profileBaseline = '';
|
|
739
2343
|
let profileDirty = false;
|
|
@@ -742,6 +2346,7 @@
|
|
|
742
2346
|
let logLevelFilter = 'all';
|
|
743
2347
|
let socialTemplate = '';
|
|
744
2348
|
let onlyShowOnline = false;
|
|
2349
|
+
const pageMeta = TRANSLATIONS[currentLocale].pageMeta || TRANSLATIONS[DEFAULT_LOCALE].pageMeta;
|
|
745
2350
|
|
|
746
2351
|
function ago(ts) {
|
|
747
2352
|
if (!ts) return '-';
|
|
@@ -767,6 +2372,12 @@
|
|
|
767
2372
|
t.classList.add('show');
|
|
768
2373
|
setTimeout(() => t.classList.remove('show'), 2000);
|
|
769
2374
|
}
|
|
2375
|
+
function resolveThemeMode(mode) {
|
|
2376
|
+
if (mode === 'system') {
|
|
2377
|
+
return window.matchMedia && window.matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark';
|
|
2378
|
+
}
|
|
2379
|
+
return mode === 'light' ? 'light' : 'dark';
|
|
2380
|
+
}
|
|
770
2381
|
function flashButton(btn, doneText = 'Done') {
|
|
771
2382
|
if (!btn) return;
|
|
772
2383
|
const oldText = btn.textContent || '';
|
|
@@ -783,11 +2394,16 @@
|
|
|
783
2394
|
el.style.color = level === 'error' ? '#ff6b81' : level === 'warn' ? '#ffb454' : '#9aa7c3';
|
|
784
2395
|
}
|
|
785
2396
|
function applyTheme(mode) {
|
|
786
|
-
const
|
|
2397
|
+
const raw = mode === 'system' ? 'system' : (mode === 'light' ? 'light' : 'dark');
|
|
2398
|
+
const next = resolveThemeMode(raw);
|
|
787
2399
|
document.documentElement.setAttribute('data-theme-mode', next);
|
|
788
|
-
localStorage.setItem('silicaclaw_theme_mode',
|
|
789
|
-
document.
|
|
790
|
-
|
|
2400
|
+
localStorage.setItem('silicaclaw_theme_mode', raw);
|
|
2401
|
+
document.querySelectorAll('[data-theme-choice]').forEach((btn) => {
|
|
2402
|
+
btn.classList.toggle('active', btn.dataset.themeChoice === raw);
|
|
2403
|
+
btn.classList.toggle('topbar-theme-mode__btn--active', btn.dataset.themeChoice === raw);
|
|
2404
|
+
btn.setAttribute('aria-checked', btn.dataset.themeChoice === raw ? 'true' : 'false');
|
|
2405
|
+
btn.setAttribute('aria-pressed', btn.dataset.themeChoice === raw ? 'true' : 'false');
|
|
2406
|
+
});
|
|
791
2407
|
}
|
|
792
2408
|
function parseTags(raw) {
|
|
793
2409
|
return String(raw || '')
|
|
@@ -822,7 +2438,7 @@
|
|
|
822
2438
|
if (fromUserInput && !profileSaving) {
|
|
823
2439
|
setFeedback(
|
|
824
2440
|
'profileFeedback',
|
|
825
|
-
profileDirty ? '
|
|
2441
|
+
profileDirty ? t('feedback.unsavedChanges') : t('feedback.allChangesSaved'),
|
|
826
2442
|
profileDirty ? 'warn' : 'info'
|
|
827
2443
|
);
|
|
828
2444
|
}
|
|
@@ -849,27 +2465,27 @@
|
|
|
849
2465
|
let ok = true;
|
|
850
2466
|
let err = '';
|
|
851
2467
|
if (displayName.length > 0 && displayName.length < 2) {
|
|
852
|
-
err = '
|
|
2468
|
+
err = t('validation.displayNameShort');
|
|
853
2469
|
ok = false;
|
|
854
2470
|
} else if (displayName.length > 48) {
|
|
855
|
-
err = '
|
|
2471
|
+
err = t('validation.displayNameLong');
|
|
856
2472
|
ok = false;
|
|
857
2473
|
}
|
|
858
2474
|
setInputError(displayNameEl, 'errDisplayName', err);
|
|
859
2475
|
|
|
860
2476
|
err = '';
|
|
861
2477
|
if (avatarUrl && !/^https?:\/\//i.test(avatarUrl)) {
|
|
862
|
-
err = '
|
|
2478
|
+
err = t('validation.avatarProtocol');
|
|
863
2479
|
ok = false;
|
|
864
2480
|
}
|
|
865
2481
|
setInputError(avatarEl, 'errAvatarUrl', err);
|
|
866
2482
|
|
|
867
2483
|
err = '';
|
|
868
2484
|
if (tags.length > 8) {
|
|
869
|
-
err = '
|
|
2485
|
+
err = t('validation.tooManyTags');
|
|
870
2486
|
ok = false;
|
|
871
2487
|
} else if (tags.some((t) => t.length > 20)) {
|
|
872
|
-
err = '
|
|
2488
|
+
err = t('validation.tagTooLong');
|
|
873
2489
|
ok = false;
|
|
874
2490
|
}
|
|
875
2491
|
setInputError(tagsEl, 'errTags', err);
|
|
@@ -881,14 +2497,14 @@
|
|
|
881
2497
|
const tags = parseTags(field(form, 'tags')?.value || '');
|
|
882
2498
|
const enabled = !!field(form, 'public_enabled')?.checked;
|
|
883
2499
|
|
|
884
|
-
document.getElementById('previewName').textContent = displayName || '
|
|
885
|
-
document.getElementById('previewBio').textContent = bio || '
|
|
2500
|
+
document.getElementById('previewName').textContent = displayName || t('preview.unnamedAgent');
|
|
2501
|
+
document.getElementById('previewBio').textContent = bio || t('preview.noBioYet');
|
|
886
2502
|
document.getElementById('previewPublish').textContent = `public_enabled: ${enabled}`;
|
|
887
2503
|
document.getElementById('bioCount').textContent = String(bio.length);
|
|
888
2504
|
|
|
889
2505
|
const tagBox = document.getElementById('previewTags');
|
|
890
2506
|
if (!tags.length) {
|
|
891
|
-
tagBox.innerHTML =
|
|
2507
|
+
tagBox.innerHTML = `<span class="tag-chip muted">${t('preview.noTags')}</span>`;
|
|
892
2508
|
return;
|
|
893
2509
|
}
|
|
894
2510
|
tagBox.innerHTML = tags.map((tag) => `<span class=\"tag-chip\">${tag}</span>`).join('');
|
|
@@ -898,30 +2514,34 @@
|
|
|
898
2514
|
const btn = document.getElementById('saveProfileBtn');
|
|
899
2515
|
btn.disabled = busy;
|
|
900
2516
|
btn.classList.toggle('save-busy', busy);
|
|
901
|
-
btn.textContent = busy ? '
|
|
2517
|
+
btn.textContent = busy ? t('common.saving') : t('actions.saveProfile');
|
|
902
2518
|
}
|
|
903
2519
|
|
|
904
2520
|
async function api(path, options = {}) {
|
|
905
2521
|
const res = await fetch(path, { headers: { 'Content-Type': 'application/json' }, ...options });
|
|
906
2522
|
const json = await res.json().catch(() => null);
|
|
907
2523
|
if (!res.ok || !json || !json.ok) {
|
|
908
|
-
throw new Error(json?.error?.message ||
|
|
2524
|
+
throw new Error(json?.error?.message || t('common.requestFailed', { status: String(res.status) }));
|
|
909
2525
|
}
|
|
910
2526
|
return json;
|
|
911
2527
|
}
|
|
912
2528
|
|
|
913
2529
|
function switchTab(tab) {
|
|
914
2530
|
if (activeTab === 'profile' && tab !== 'profile' && profileDirty && !profileSaving) {
|
|
915
|
-
const ok = window.confirm('
|
|
2531
|
+
const ok = window.confirm(t('validation.leaveConfirm'));
|
|
916
2532
|
if (!ok) {
|
|
917
2533
|
return;
|
|
918
2534
|
}
|
|
919
2535
|
}
|
|
920
2536
|
activeTab = tab;
|
|
921
2537
|
document.querySelectorAll('.tab').forEach((b) => b.classList.toggle('active', b.dataset.tab === tab));
|
|
922
|
-
['overview', 'profile', 'network', '
|
|
2538
|
+
['overview', 'profile', 'network', 'social'].forEach((k) => {
|
|
923
2539
|
document.getElementById(`view-${k}`).classList.toggle('active', k === tab);
|
|
924
2540
|
});
|
|
2541
|
+
const meta = pageMeta[tab] || pageMeta.overview;
|
|
2542
|
+
document.getElementById('pageBreadcrumb').textContent = meta.title;
|
|
2543
|
+
document.getElementById('pageHeroTitle').textContent = meta.title;
|
|
2544
|
+
document.getElementById('pageHeroBody').textContent = meta.body;
|
|
925
2545
|
if (tab === 'profile' && !profileDirty && !profileSaving) {
|
|
926
2546
|
refreshProfile().catch(() => {});
|
|
927
2547
|
}
|
|
@@ -934,67 +2554,62 @@
|
|
|
934
2554
|
const d = onlyShowOnline ? all.filter((agent) => agent.online) : all;
|
|
935
2555
|
|
|
936
2556
|
document.getElementById('overviewCards').innerHTML = [
|
|
937
|
-
['
|
|
938
|
-
['
|
|
939
|
-
['
|
|
940
|
-
['
|
|
2557
|
+
[t('overview.discovered'), o.discovered_count],
|
|
2558
|
+
[t('overview.online'), o.online_count],
|
|
2559
|
+
[t('overview.offline'), o.offline_count],
|
|
2560
|
+
[t('overview.presenceTtl'), `${Math.floor(o.presence_ttl_ms / 1000)}s`],
|
|
941
2561
|
].map(([k,v]) => `<div class="card"><div class="label">${k}</div><div class="value">${v}</div></div>`).join('');
|
|
942
2562
|
|
|
2563
|
+
document.getElementById('brandVersion').textContent = o.app_version ? `v${o.app_version}` : '-';
|
|
2564
|
+
|
|
943
2565
|
document.getElementById('snapshot').textContent = [
|
|
2566
|
+
`app_version: ${o.app_version || '-'}`,
|
|
944
2567
|
`agent_id: ${o.agent_id || '-'}`,
|
|
945
2568
|
`public_enabled: ${o.public_enabled}`,
|
|
946
2569
|
`broadcast_enabled: ${o.broadcast_enabled}`,
|
|
947
2570
|
`last_broadcast: ${ago(o.last_broadcast_at)}`,
|
|
948
2571
|
].join('\n');
|
|
2572
|
+
document.getElementById('heroMode').textContent = o.social?.network_mode || '-';
|
|
949
2573
|
|
|
950
|
-
document.getElementById('pillBroadcast').textContent = o.broadcast_enabled ? '
|
|
2574
|
+
document.getElementById('pillBroadcast').textContent = o.broadcast_enabled ? t('overview.pillRunning') : t('overview.pillPaused');
|
|
951
2575
|
document.getElementById('pillBroadcast').className = `pill ${o.broadcast_enabled ? 'ok' : 'warn'}`;
|
|
952
2576
|
|
|
953
2577
|
const init = o.init_state || {};
|
|
954
2578
|
const onboarding = o.onboarding || {};
|
|
955
2579
|
const notice = document.getElementById('initNotice');
|
|
956
|
-
const onboardingActions = document.getElementById('onboardingActions');
|
|
957
|
-
const enableBtn = document.getElementById('enablePublicDiscoveryBtn');
|
|
958
|
-
const disableBtn = document.getElementById('disablePublicDiscoveryBtn');
|
|
959
2580
|
const discoveryHint = document.getElementById('publicDiscoveryHint');
|
|
960
2581
|
const showOnboarding = onboarding.first_run || init.identity_auto_created || init.profile_auto_created || init.social_auto_created;
|
|
961
2582
|
if (onboarding.first_run || init.identity_auto_created || init.profile_auto_created || init.social_auto_created) {
|
|
962
2583
|
notice.classList.add('show');
|
|
963
|
-
notice.textContent =
|
|
2584
|
+
notice.textContent = t('overview.onboardingNotice', {
|
|
2585
|
+
mode: onboarding.mode || '-',
|
|
2586
|
+
discoverable: onboarding.discoverable ? t('common.yes') : t('common.no'),
|
|
2587
|
+
});
|
|
964
2588
|
} else {
|
|
965
2589
|
notice.classList.remove('show');
|
|
966
2590
|
}
|
|
967
2591
|
if (onboarding.can_enable_public_discovery || onboarding.public_enabled) {
|
|
968
|
-
onboardingActions.style.display = 'flex';
|
|
969
2592
|
discoveryHint.style.display = 'block';
|
|
970
|
-
if (onboarding.public_enabled) {
|
|
971
|
-
enableBtn.style.display = 'none';
|
|
972
|
-
disableBtn.style.display = 'inline-block';
|
|
973
|
-
} else {
|
|
974
|
-
enableBtn.style.display = 'inline-block';
|
|
975
|
-
disableBtn.style.display = 'none';
|
|
976
|
-
}
|
|
977
2593
|
} else {
|
|
978
|
-
onboardingActions.style.display = 'none';
|
|
979
2594
|
discoveryHint.style.display = 'none';
|
|
980
2595
|
}
|
|
981
2596
|
|
|
982
2597
|
if (!d.length) {
|
|
983
|
-
document.getElementById('agentsCountHint').textContent = '
|
|
984
|
-
document.getElementById('agentsWrap').innerHTML =
|
|
2598
|
+
document.getElementById('agentsCountHint').textContent = t('overview.agentsZero');
|
|
2599
|
+
document.getElementById('agentsWrap').innerHTML = `<div class="label">${t('overview.noDiscoveredAgents')}</div>`;
|
|
985
2600
|
} else {
|
|
986
2601
|
document.getElementById('agentsCountHint').textContent = onlyShowOnline
|
|
987
|
-
?
|
|
988
|
-
:
|
|
2602
|
+
? t('overview.agentsOnlineFilter', { shown: String(d.length), total: String(all.length) })
|
|
2603
|
+
: t('overview.agentsDiscovered', { count: String(d.length) });
|
|
989
2604
|
document.getElementById('agentsWrap').innerHTML = `
|
|
990
2605
|
<table class="table">
|
|
991
|
-
<thead><tr><th
|
|
2606
|
+
<thead><tr><th>${t('overview.tableName')}</th><th>${t('overview.tableAgentId')}</th><th>${t('overview.tableStatus')}</th><th>${t('overview.tableUpdated')}</th></tr></thead>
|
|
992
2607
|
<tbody>
|
|
993
2608
|
${d.map((a) => `
|
|
994
2609
|
<tr>
|
|
995
|
-
<td>${a.display_name || '
|
|
2610
|
+
<td>${a.display_name || t('overview.unnamed')}</td>
|
|
996
2611
|
<td class="mono">${shortId(a.agent_id)}</td>
|
|
997
|
-
<td class="${a.online ? 'online' : 'offline'}">${a.online ? 'online' : 'offline'}</td>
|
|
2612
|
+
<td class="${a.online ? 'online' : 'offline'}">${a.online ? t('overview.online') : t('overview.offline')}</td>
|
|
998
2613
|
<td>${ago(a.updated_at)}</td>
|
|
999
2614
|
</tr>
|
|
1000
2615
|
`).join('')}
|
|
@@ -1025,10 +2640,10 @@
|
|
|
1025
2640
|
const hiddenFields = summary?.public_visibility?.hidden_fields || [];
|
|
1026
2641
|
const visible = visibleFields.join(', ') || '-';
|
|
1027
2642
|
const hidden = hiddenFields.join(', ') || '-';
|
|
1028
|
-
document.getElementById('publicVisibilityHint').textContent =
|
|
2643
|
+
document.getElementById('publicVisibilityHint').textContent = t('preview.visibleFields', { visible, hidden });
|
|
1029
2644
|
const rows = [
|
|
1030
|
-
...visibleFields.map((field) =>
|
|
1031
|
-
...hiddenFields.map((field) =>
|
|
2645
|
+
...visibleFields.map((field) => t('preview.visible', { field })),
|
|
2646
|
+
...hiddenFields.map((field) => t('preview.hidden', { field })),
|
|
1032
2647
|
];
|
|
1033
2648
|
document.getElementById('publicVisibilityList').textContent = rows.length ? rows.join('\n') : '-';
|
|
1034
2649
|
}
|
|
@@ -1045,31 +2660,41 @@
|
|
|
1045
2660
|
const d = s.adapter_discovery_stats || {};
|
|
1046
2661
|
const dx = s.adapter_diagnostics_summary || {};
|
|
1047
2662
|
const ac = s.adapter_config || c.adapter_config || {};
|
|
2663
|
+
document.getElementById('heroAdapter').textContent = c.adapter || '-';
|
|
2664
|
+
document.getElementById('heroRelay').textContent = dx.signaling_url || '-';
|
|
2665
|
+
document.getElementById('heroRoom').textContent = dx.room || '-';
|
|
1048
2666
|
|
|
1049
2667
|
document.getElementById('pillAdapter').textContent = `adapter: ${c.adapter}`;
|
|
1050
|
-
document.getElementById('sideMeta').innerHTML = `adapter: ${c.adapter}<br/>namespace: ${c.namespace || '-'}<br/>port: ${c.port ?? '-'}`;
|
|
1051
|
-
|
|
1052
2668
|
document.getElementById('networkCards').innerHTML = [
|
|
1053
|
-
['
|
|
1054
|
-
['
|
|
1055
|
-
['
|
|
1056
|
-
['
|
|
1057
|
-
['
|
|
1058
|
-
['
|
|
1059
|
-
['
|
|
1060
|
-
['
|
|
1061
|
-
['
|
|
1062
|
-
['
|
|
1063
|
-
['
|
|
1064
|
-
['
|
|
1065
|
-
['
|
|
1066
|
-
['
|
|
1067
|
-
['
|
|
1068
|
-
['
|
|
1069
|
-
['
|
|
1070
|
-
['
|
|
1071
|
-
['
|
|
2669
|
+
[t('labels.adapter'), c.adapter],
|
|
2670
|
+
[t('labels.namespace'), c.namespace || '-'],
|
|
2671
|
+
[t('labels.port'), c.port ?? '-'],
|
|
2672
|
+
[t('network.started'), ac.started === true ? t('common.yes') : ac.started === false ? t('common.no') : '-'],
|
|
2673
|
+
[t('network.transportState'), ac.transport?.state || '-'],
|
|
2674
|
+
[t('network.signalingUrl'), dx.signaling_url || '-'],
|
|
2675
|
+
[t('network.signalingEndpoints'), (dx.signaling_endpoints || []).length || 0],
|
|
2676
|
+
[t('network.webrtcRoom'), dx.room || '-'],
|
|
2677
|
+
[t('network.bootstrapSources'), (dx.bootstrap_sources || []).length || 0],
|
|
2678
|
+
[t('network.seedPeers'), dx.seed_peers_count ?? 0],
|
|
2679
|
+
[t('network.discoveryEvents'), dx.discovery_events_total ?? 0],
|
|
2680
|
+
[t('network.recv'), msg.received_total ?? 0],
|
|
2681
|
+
[t('network.sent'), msg.broadcast_total ?? 0],
|
|
2682
|
+
[t('network.peers'), p.total ?? 0],
|
|
2683
|
+
[t('network.onlinePeers'), p.online ?? 0],
|
|
2684
|
+
[t('network.activeWebrtcPeers'), dx.active_webrtc_peers ?? '-'],
|
|
2685
|
+
[t('network.reconnectAttempts'), dx.reconnect_attempts_total ?? '-'],
|
|
2686
|
+
[t('network.lastInbound'), ago(msg.last_message_at)],
|
|
2687
|
+
[t('network.lastOutbound'), ago(msg.last_broadcast_at)],
|
|
1072
2688
|
].map(([k,v]) => `<div class="card"><div class="label">${k}</div><div class="value" style="font-size:17px;">${v}</div></div>`).join('');
|
|
2689
|
+
document.getElementById('networkSummaryList').innerHTML = [
|
|
2690
|
+
[t('network.relayHealth'), dx.last_error ? t('network.degraded') : t('network.connected')],
|
|
2691
|
+
[t('network.currentRelay'), dx.signaling_url || '-'],
|
|
2692
|
+
[t('network.currentRoom'), dx.room || '-'],
|
|
2693
|
+
[t('network.lastJoin'), ago(dx.last_join_at)],
|
|
2694
|
+
[t('network.lastPoll'), ago(dx.last_poll_at)],
|
|
2695
|
+
[t('network.lastPublish'), ago(dx.last_publish_at)],
|
|
2696
|
+
[t('network.lastError'), dx.last_error || t('network.none')],
|
|
2697
|
+
].map(([k, v]) => `<div class="summary-item"><div class="label">${k}</div><div class="mono">${v}</div></div>`).join('');
|
|
1073
2698
|
|
|
1074
2699
|
const comp = c.components || {};
|
|
1075
2700
|
const lim = c.limits || {};
|
|
@@ -1097,6 +2722,12 @@
|
|
|
1097
2722
|
`discovery_heartbeat_send_errors: ${d.heartbeat_send_errors ?? '-'}`,
|
|
1098
2723
|
`signaling_messages_sent_total: ${dx.signaling_messages_sent_total ?? '-'}`,
|
|
1099
2724
|
`signaling_messages_received_total: ${dx.signaling_messages_received_total ?? '-'}`,
|
|
2725
|
+
`last_join_at: ${dx.last_join_at ? new Date(dx.last_join_at).toISOString() : '-'}`,
|
|
2726
|
+
`last_poll_at: ${dx.last_poll_at ? new Date(dx.last_poll_at).toISOString() : '-'}`,
|
|
2727
|
+
`last_publish_at: ${dx.last_publish_at ? new Date(dx.last_publish_at).toISOString() : '-'}`,
|
|
2728
|
+
`last_peer_refresh_at: ${dx.last_peer_refresh_at ? new Date(dx.last_peer_refresh_at).toISOString() : '-'}`,
|
|
2729
|
+
`last_error_at: ${dx.last_error_at ? new Date(dx.last_error_at).toISOString() : '-'}`,
|
|
2730
|
+
`last_error: ${dx.last_error || '-'}`,
|
|
1100
2731
|
`signaling_endpoints: ${Array.isArray(dx.signaling_endpoints) ? dx.signaling_endpoints.join(', ') : '-'}`,
|
|
1101
2732
|
`bootstrap_sources: ${Array.isArray(dx.bootstrap_sources) ? dx.bootstrap_sources.join(', ') : '-'}`,
|
|
1102
2733
|
`seed_peers_count: ${dx.seed_peers_count ?? '-'}`,
|
|
@@ -1121,25 +2752,28 @@
|
|
|
1121
2752
|
const summary = peers.diagnostics_summary || {};
|
|
1122
2753
|
|
|
1123
2754
|
document.getElementById('peerCards').innerHTML = [
|
|
1124
|
-
['
|
|
1125
|
-
['
|
|
1126
|
-
['
|
|
1127
|
-
['
|
|
1128
|
-
['
|
|
1129
|
-
['
|
|
1130
|
-
['
|
|
1131
|
-
['
|
|
1132
|
-
['
|
|
1133
|
-
['
|
|
1134
|
-
['
|
|
1135
|
-
['
|
|
1136
|
-
['
|
|
1137
|
-
['
|
|
1138
|
-
['
|
|
2755
|
+
[t('network.total'), peers.total || 0],
|
|
2756
|
+
[t('overview.online'), peers.online || 0],
|
|
2757
|
+
[t('network.stale'), peers.stale || 0],
|
|
2758
|
+
[t('labels.namespace'), peers.namespace || '-'],
|
|
2759
|
+
[t('network.signalingUrl'), summary.signaling_url || '-'],
|
|
2760
|
+
[t('network.signalingEndpoints'), (summary.signaling_endpoints || []).length || 0],
|
|
2761
|
+
[t('labels.room'), summary.room || '-'],
|
|
2762
|
+
[t('network.lastJoin'), ago(summary.last_join_at)],
|
|
2763
|
+
[t('network.lastPoll'), ago(summary.last_poll_at)],
|
|
2764
|
+
[t('network.lastPublish'), ago(summary.last_publish_at)],
|
|
2765
|
+
[t('network.bootstrapSources'), (summary.bootstrap_sources || []).length || 0],
|
|
2766
|
+
[t('network.seedPeers'), summary.seed_peers_count ?? 0],
|
|
2767
|
+
[t('network.discoveryEvents'), summary.discovery_events_total ?? 0],
|
|
2768
|
+
[t('network.activeWebrtcPeers'), summary.active_webrtc_peers ?? '-'],
|
|
2769
|
+
[t('network.observeCalls'), ds.observe_calls || 0],
|
|
2770
|
+
[t('network.heartbeats'), ds.heartbeat_sent || 0],
|
|
2771
|
+
[t('network.peersAdded'), ds.peers_added || 0],
|
|
2772
|
+
[t('network.peersRemoved'), ds.peers_removed || 0],
|
|
1139
2773
|
].map(([k,v]) => `<div class="card"><div class="label">${k}</div><div class="value" style="font-size:17px;">${v}</div></div>`).join('');
|
|
1140
2774
|
|
|
1141
2775
|
if (!peers.items || !peers.items.length) {
|
|
1142
|
-
document.getElementById('peerTableWrap').innerHTML =
|
|
2776
|
+
document.getElementById('peerTableWrap').innerHTML = `<div class="empty-state">${t('network.noPeersDiscovered')}</div>`;
|
|
1143
2777
|
document.getElementById('peerStatsWrap').textContent = toPrettyJson({
|
|
1144
2778
|
discovery_stats: ds,
|
|
1145
2779
|
diagnostics_summary: summary,
|
|
@@ -1149,7 +2783,7 @@
|
|
|
1149
2783
|
|
|
1150
2784
|
document.getElementById('peerTableWrap').innerHTML = `
|
|
1151
2785
|
<table class="table">
|
|
1152
|
-
<thead><tr><th
|
|
2786
|
+
<thead><tr><th>${t('network.peer')}</th><th>${t('network.status')}</th><th>${t('network.lastSeen')}</th><th>${t('network.staleSince')}</th><th>${t('network.messages')}</th><th>${t('network.firstSeen')}</th><th>${t('network.meta')}</th></tr></thead>
|
|
1153
2787
|
<tbody>
|
|
1154
2788
|
${peers.items.map((peer) => `
|
|
1155
2789
|
<tr>
|
|
@@ -1178,16 +2812,16 @@
|
|
|
1178
2812
|
const items = Array.isArray(payload.items) ? payload.items : [];
|
|
1179
2813
|
|
|
1180
2814
|
document.getElementById('discoveryCards').innerHTML = [
|
|
1181
|
-
['
|
|
1182
|
-
['
|
|
1183
|
-
['
|
|
1184
|
-
['
|
|
1185
|
-
['
|
|
1186
|
-
['
|
|
2815
|
+
[t('labels.adapter'), payload.adapter || '-'],
|
|
2816
|
+
[t('labels.namespace'), payload.namespace || '-'],
|
|
2817
|
+
[t('network.eventsTotal'), payload.total ?? 0],
|
|
2818
|
+
[t('network.lastEvent'), ago(payload.last_event_at)],
|
|
2819
|
+
[t('network.signalingEndpoints'), (payload.signaling_endpoints || []).length || 0],
|
|
2820
|
+
[t('network.seedPeers'), payload.seed_peers_count ?? 0],
|
|
1187
2821
|
].map(([k,v]) => `<div class="card"><div class="label">${k}</div><div class="value" style="font-size:17px;">${v}</div></div>`).join('');
|
|
1188
2822
|
|
|
1189
2823
|
if (!items.length) {
|
|
1190
|
-
document.getElementById('discoveryEventList').innerHTML =
|
|
2824
|
+
document.getElementById('discoveryEventList').innerHTML = `<div class="empty-state">${t('network.noDiscoveryEvents')}</div>`;
|
|
1191
2825
|
} else {
|
|
1192
2826
|
document.getElementById('discoveryEventList').innerHTML = items
|
|
1193
2827
|
.slice()
|
|
@@ -1220,55 +2854,60 @@
|
|
|
1220
2854
|
const runtimeNetwork = runtime.resolved_network || {};
|
|
1221
2855
|
const discoverable = status.discoverable === true;
|
|
1222
2856
|
const mode = status.network_mode || summary.current_network_mode || network.mode || runtimeNetwork.mode || '-';
|
|
1223
|
-
const summaryLine = status.status_line || summary.summary_line || `${summary.connected ? '
|
|
1224
|
-
const publicDiscoveryText = status.public_enabled ? '
|
|
2857
|
+
const summaryLine = status.status_line || summary.summary_line || `${summary.connected ? t('social.connectedToSilicaClaw') : t('social.notConnectedToSilicaClaw')} · ${discoverable ? t('social.discoverableInCurrentMode') : t('social.notDiscoverableInCurrentMode')} · ${t('social.usingMode', { mode })}`;
|
|
2858
|
+
const publicDiscoveryText = status.public_enabled ? t('social.publicDiscoveryEnabled') : t('social.publicDiscoveryDisabled');
|
|
1225
2859
|
|
|
1226
|
-
const namespaceText = `${status.connected_to_silicaclaw ? '
|
|
2860
|
+
const namespaceText = `${status.connected_to_silicaclaw ? t('social.connectedToSilicaClaw') : t('social.notConnected')} · ${publicDiscoveryText} · ${t('social.mode')} ${mode}`;
|
|
1227
2861
|
document.getElementById('socialStatusLine').textContent = summaryLine;
|
|
1228
2862
|
document.getElementById('socialStatusSubline').textContent = namespaceText;
|
|
1229
2863
|
const bar = document.getElementById('integrationStatusBar');
|
|
1230
2864
|
bar.className = `integration-strip ${status.connected_to_silicaclaw && status.public_enabled ? 'ok' : 'warn'}`;
|
|
1231
|
-
bar.textContent =
|
|
2865
|
+
bar.textContent = t('social.barStatus', {
|
|
2866
|
+
connected: status.connected_to_silicaclaw ? t('common.yes') : t('common.no'),
|
|
2867
|
+
mode,
|
|
2868
|
+
public: status.public_enabled ? t('common.on') : t('common.off'),
|
|
2869
|
+
});
|
|
2870
|
+
document.getElementById('brandStatusDot').classList.toggle('online', !!status.connected_to_silicaclaw);
|
|
1232
2871
|
const reasons = [];
|
|
1233
|
-
if (!status.configured && status.configured_reason) reasons.push(
|
|
1234
|
-
if (!status.running && status.running_reason) reasons.push(
|
|
1235
|
-
if (!status.discoverable && status.discoverable_reason) reasons.push(
|
|
1236
|
-
document.getElementById('socialStateHint').textContent = reasons.length ? reasons.join(' · ') : '
|
|
2872
|
+
if (!status.configured && status.configured_reason) reasons.push(t('social.configuredReason', { reason: status.configured_reason }));
|
|
2873
|
+
if (!status.running && status.running_reason) reasons.push(t('social.runningReason', { reason: status.running_reason }));
|
|
2874
|
+
if (!status.discoverable && status.discoverable_reason) reasons.push(t('social.discoverableReasonFull', { reason: status.discoverable_reason }));
|
|
2875
|
+
document.getElementById('socialStateHint').textContent = reasons.length ? reasons.join(' · ') : t('hints.allIntegrationChecksPassed');
|
|
1237
2876
|
const modeSelect = document.getElementById('socialModeSelect');
|
|
1238
2877
|
if (modeSelect && mode !== '-') {
|
|
1239
2878
|
modeSelect.value = mode;
|
|
1240
2879
|
}
|
|
1241
2880
|
|
|
1242
2881
|
document.getElementById('socialPrimaryCards').innerHTML = [
|
|
1243
|
-
['
|
|
1244
|
-
['
|
|
1245
|
-
['
|
|
1246
|
-
['
|
|
1247
|
-
['
|
|
1248
|
-
['connected', status.connected_to_silicaclaw ? 'yes' : 'no'],
|
|
1249
|
-
['
|
|
2882
|
+
[t('social.configured'), status.configured ? t('common.yes') : t('common.no')],
|
|
2883
|
+
[t('social.running'), status.running ? t('common.yes') : t('common.no')],
|
|
2884
|
+
[t('social.discoverable'), discoverable ? t('common.yes') : t('common.no')],
|
|
2885
|
+
[t('social.publicDiscovery'), status.public_enabled ? t('common.on') : t('common.off')],
|
|
2886
|
+
[t('social.networkMode'), mode],
|
|
2887
|
+
[t('social.connected'), status.connected_to_silicaclaw ? t('common.yes') : t('common.no')],
|
|
2888
|
+
[t('social.discoverableReason'), status.discoverable_reason || '-'],
|
|
1250
2889
|
].map(([k,v]) => `<div class="card"><div class="label">${k}</div><div class="value" style="font-size:17px;">${v}</div></div>`).join('');
|
|
1251
2890
|
|
|
1252
2891
|
document.getElementById('socialIntegrationCards').innerHTML = [
|
|
1253
|
-
['
|
|
1254
|
-
['
|
|
1255
|
-
['social.
|
|
1256
|
-
['social.
|
|
1257
|
-
['
|
|
1258
|
-
['
|
|
1259
|
-
['mode', mode],
|
|
1260
|
-
['
|
|
2892
|
+
[t('social.displayName'), status.display_name || t('overview.unnamed')],
|
|
2893
|
+
[t('social.agentId'), shortId(status.agent_id || '')],
|
|
2894
|
+
[t('social.socialFound'), summary.social_md_found ? t('common.yes') : t('common.no')],
|
|
2895
|
+
[t('social.socialSource'), summary.social_md_source_path || '-'],
|
|
2896
|
+
[t('social.runtimeGenerated'), summary.runtime_generated ? t('common.yes') : t('common.no')],
|
|
2897
|
+
[t('social.reuseOpenClawIdentity'), summary.reused_openclaw_identity ? t('common.yes') : t('common.no')],
|
|
2898
|
+
[t('social.mode'), mode],
|
|
2899
|
+
[t('social.broadcastStatus'), summary.current_broadcast_status || '-'],
|
|
1261
2900
|
].map(([k,v]) => `<div class="card"><div class="label">${k}</div><div class="value" style="font-size:17px;">${v}</div></div>`).join('');
|
|
1262
2901
|
|
|
1263
2902
|
document.getElementById('socialAdvancedCards').innerHTML = [
|
|
1264
|
-
['adapter', runtimeNetwork.adapter || summary.current_adapter || '-'],
|
|
1265
|
-
['namespace', runtimeNetwork.namespace || summary.current_namespace || '-'],
|
|
1266
|
-
['room', runtimeNetwork.room || network.room || '-'],
|
|
1267
|
-
['
|
|
1268
|
-
['
|
|
1269
|
-
['
|
|
1270
|
-
['
|
|
1271
|
-
['
|
|
2903
|
+
[t('labels.adapter'), runtimeNetwork.adapter || summary.current_adapter || '-'],
|
|
2904
|
+
[t('social.namespace'), runtimeNetwork.namespace || summary.current_namespace || '-'],
|
|
2905
|
+
[t('labels.room'), runtimeNetwork.room || network.room || '-'],
|
|
2906
|
+
[t('network.signalingEndpoints'), (runtimeNetwork.signaling_urls || []).length || 0],
|
|
2907
|
+
[t('network.bootstrapSources'), (runtimeNetwork.bootstrap_sources || []).length || 0],
|
|
2908
|
+
[t('network.seedPeers'), (runtimeNetwork.seed_peers || []).length || 0],
|
|
2909
|
+
[t('social.bootstrapHints'), (runtimeNetwork.bootstrap_hints || []).length || 0],
|
|
2910
|
+
[t('social.restartRequired'), social.network_requires_restart ? t('common.yes') : t('common.no')],
|
|
1272
2911
|
].map(([k,v]) => `<div class="card"><div class="label">${k}</div><div class="value" style="font-size:17px;">${v}</div></div>`).join('');
|
|
1273
2912
|
document.getElementById('socialAdvancedWrap').textContent = toPrettyJson({
|
|
1274
2913
|
runtime_network: runtimeNetwork,
|
|
@@ -1295,14 +2934,14 @@
|
|
|
1295
2934
|
function renderLogs() {
|
|
1296
2935
|
const el = document.getElementById('logList');
|
|
1297
2936
|
if (!logsCache.length) {
|
|
1298
|
-
el.innerHTML =
|
|
2937
|
+
el.innerHTML = `<div class="empty-state">${t('network.noLogsYet')}</div>`;
|
|
1299
2938
|
return;
|
|
1300
2939
|
}
|
|
1301
2940
|
const filtered = logLevelFilter === 'all'
|
|
1302
2941
|
? logsCache
|
|
1303
2942
|
: logsCache.filter((l) => String(l.level || '').toLowerCase() === logLevelFilter);
|
|
1304
2943
|
if (!filtered.length) {
|
|
1305
|
-
el.innerHTML = `<div class="
|
|
2944
|
+
el.innerHTML = `<div class="empty-state">${t('network.noLogsForLevel', { level: logLevelFilter })}</div>`;
|
|
1306
2945
|
return;
|
|
1307
2946
|
}
|
|
1308
2947
|
el.innerHTML = filtered.map((l) => `
|
|
@@ -1320,34 +2959,81 @@
|
|
|
1320
2959
|
|
|
1321
2960
|
async function refreshAll() {
|
|
1322
2961
|
try {
|
|
1323
|
-
const tasks = [refreshOverview(), refreshNetwork(),
|
|
2962
|
+
const tasks = [refreshOverview(), refreshNetwork(), refreshSocial(), refreshPublicProfilePreview()];
|
|
2963
|
+
if (activeTab === 'network') {
|
|
2964
|
+
tasks.push(refreshPeers(), refreshDiscovery(), refreshLogs());
|
|
2965
|
+
}
|
|
1324
2966
|
const shouldRefreshProfile = !(activeTab === 'profile' && profileDirty);
|
|
1325
2967
|
if (shouldRefreshProfile) {
|
|
1326
2968
|
tasks.push(refreshProfile());
|
|
1327
2969
|
}
|
|
1328
2970
|
await Promise.all(tasks);
|
|
1329
2971
|
} catch (e) {
|
|
1330
|
-
setFeedback('networkFeedback', e instanceof Error ? e.message : '
|
|
2972
|
+
setFeedback('networkFeedback', e instanceof Error ? e.message : t('common.unknownError'), 'error');
|
|
1331
2973
|
}
|
|
1332
2974
|
}
|
|
1333
2975
|
|
|
1334
2976
|
document.querySelectorAll('.tab').forEach((btn) => {
|
|
1335
2977
|
btn.addEventListener('click', () => switchTab(btn.dataset.tab));
|
|
1336
2978
|
});
|
|
1337
|
-
document.getElementById('
|
|
1338
|
-
|
|
2979
|
+
document.getElementById('sidebarToggleBtn').addEventListener('click', () => {
|
|
2980
|
+
const shell = document.getElementById('appShell');
|
|
2981
|
+
const next = !shell.classList.contains('nav-collapsed');
|
|
2982
|
+
shell.classList.toggle('nav-collapsed', next);
|
|
2983
|
+
const btn = document.getElementById('sidebarToggleBtn');
|
|
2984
|
+
const icon = btn.querySelector('.nav-collapse-toggle__icon');
|
|
2985
|
+
btn.classList.toggle('active', next);
|
|
2986
|
+
btn.title = next ? t('labels.expandSidebar') : t('labels.collapseSidebar');
|
|
2987
|
+
btn.setAttribute('aria-label', btn.title);
|
|
2988
|
+
if (icon) {
|
|
2989
|
+
icon.innerHTML = next
|
|
2990
|
+
? `
|
|
2991
|
+
<svg viewBox="0 0 24 24">
|
|
2992
|
+
<rect x="3" y="3" width="18" height="18" rx="2"></rect>
|
|
2993
|
+
<path d="M9 3v18"></path>
|
|
2994
|
+
<path d="M14 10l3 2-3 2"></path>
|
|
2995
|
+
</svg>
|
|
2996
|
+
`
|
|
2997
|
+
: `
|
|
2998
|
+
<svg viewBox="0 0 24 24">
|
|
2999
|
+
<rect x="3" y="3" width="18" height="18" rx="2"></rect>
|
|
3000
|
+
<path d="M9 3v18"></path>
|
|
3001
|
+
<path d="M16 10l-3 2 3 2"></path>
|
|
3002
|
+
</svg>
|
|
3003
|
+
`;
|
|
3004
|
+
}
|
|
3005
|
+
});
|
|
3006
|
+
document.getElementById('focusModeBtn').addEventListener('click', () => {
|
|
3007
|
+
const shell = document.getElementById('appShell');
|
|
3008
|
+
const next = !shell.classList.contains('focus-mode');
|
|
3009
|
+
shell.classList.toggle('focus-mode', next);
|
|
3010
|
+
const btn = document.getElementById('focusModeBtn');
|
|
3011
|
+
btn.classList.toggle('active', next);
|
|
3012
|
+
btn.title = next ? t('labels.exitFocusMode') : t('labels.toggleFocusMode');
|
|
3013
|
+
btn.setAttribute('aria-label', btn.title);
|
|
3014
|
+
});
|
|
3015
|
+
document.querySelectorAll('[data-theme-choice]').forEach((btn) => {
|
|
3016
|
+
btn.addEventListener('click', () => {
|
|
3017
|
+
applyTheme(btn.dataset.themeChoice || 'dark');
|
|
3018
|
+
});
|
|
3019
|
+
});
|
|
3020
|
+
document.getElementById('overviewBroadcastNowBtn').addEventListener('click', () => {
|
|
3021
|
+
document.getElementById('broadcastNowBtn').click();
|
|
3022
|
+
});
|
|
3023
|
+
document.getElementById('overviewGoProfileBtn').addEventListener('click', () => switchTab('profile'));
|
|
3024
|
+
document.getElementById('overviewGoNetworkBtn').addEventListener('click', () => switchTab('network'));
|
|
1339
3025
|
|
|
1340
3026
|
document.getElementById('profileForm').addEventListener('submit', async (event) => {
|
|
1341
3027
|
event.preventDefault();
|
|
1342
3028
|
const f = event.currentTarget;
|
|
1343
3029
|
const result = validateProfileForm(f);
|
|
1344
3030
|
if (!result.ok) {
|
|
1345
|
-
setFeedback('profileFeedback', '
|
|
3031
|
+
setFeedback('profileFeedback', t('feedback.fixValidation'), 'warn');
|
|
1346
3032
|
return;
|
|
1347
3033
|
}
|
|
1348
3034
|
|
|
1349
3035
|
const tags = result.tags;
|
|
1350
|
-
setFeedback('profileFeedback', '
|
|
3036
|
+
setFeedback('profileFeedback', t('feedback.savingProfile'));
|
|
1351
3037
|
setSaveBusy(true);
|
|
1352
3038
|
try {
|
|
1353
3039
|
const r = await api('/api/profile', { method: 'PUT', body: JSON.stringify({
|
|
@@ -1357,12 +3043,12 @@
|
|
|
1357
3043
|
avatar_url: field(f, 'avatar_url').value,
|
|
1358
3044
|
public_enabled: !!field(f, 'public_enabled').checked,
|
|
1359
3045
|
})});
|
|
1360
|
-
setFeedback('profileFeedback', r.meta?.message || '
|
|
1361
|
-
toast('
|
|
3046
|
+
setFeedback('profileFeedback', r.meta?.message || t('common.saved'));
|
|
3047
|
+
toast(t('feedback.profileSaved'));
|
|
1362
3048
|
field(f, 'tags').value = normalizeTagsInput(field(f, 'tags').value);
|
|
1363
3049
|
await refreshAll();
|
|
1364
3050
|
} catch (e) {
|
|
1365
|
-
setFeedback('profileFeedback', e instanceof Error ? e.message : '
|
|
3051
|
+
setFeedback('profileFeedback', e instanceof Error ? e.message : t('feedback.failed'), 'error');
|
|
1366
3052
|
} finally {
|
|
1367
3053
|
setSaveBusy(false);
|
|
1368
3054
|
}
|
|
@@ -1370,7 +3056,7 @@
|
|
|
1370
3056
|
|
|
1371
3057
|
document.getElementById('refreshProfileBtn').addEventListener('click', async () => {
|
|
1372
3058
|
await refreshProfile();
|
|
1373
|
-
toast('
|
|
3059
|
+
toast(t('feedback.profileReloaded'));
|
|
1374
3060
|
});
|
|
1375
3061
|
const profileFormEl = document.getElementById('profileForm');
|
|
1376
3062
|
['input', 'change'].forEach((evt) => {
|
|
@@ -1405,27 +3091,21 @@
|
|
|
1405
3091
|
setFeedback('networkFeedback', text);
|
|
1406
3092
|
try {
|
|
1407
3093
|
const r = await api(path, { method: 'POST' });
|
|
1408
|
-
setFeedback('networkFeedback', r.meta?.message || '
|
|
1409
|
-
toast(r.meta?.message || '
|
|
3094
|
+
setFeedback('networkFeedback', r.meta?.message || t('common.done'), level);
|
|
3095
|
+
toast(r.meta?.message || t('common.done'));
|
|
1410
3096
|
await refreshAll();
|
|
1411
3097
|
} catch (e) {
|
|
1412
|
-
setFeedback('networkFeedback', e instanceof Error ? e.message : '
|
|
3098
|
+
setFeedback('networkFeedback', e instanceof Error ? e.message : t('feedback.failed'), 'error');
|
|
1413
3099
|
}
|
|
1414
3100
|
}
|
|
1415
|
-
document.getElementById('startBroadcastBtn').addEventListener('click', () => runAction('/api/broadcast/start', '
|
|
1416
|
-
document.getElementById('stopBroadcastBtn').addEventListener('click', () => runAction('/api/broadcast/stop', '
|
|
1417
|
-
document.getElementById('broadcastNowBtn').addEventListener('click', () => runAction('/api/broadcast/now', '
|
|
1418
|
-
document.getElementById('refreshCacheBtn').addEventListener('click', () => runAction('/api/cache/refresh', 'Refreshing cache...'));
|
|
1419
|
-
document.getElementById('clearCacheBtn').addEventListener('click', async () => {
|
|
1420
|
-
const ok = window.confirm('Clear discovered cache now?\n\nThis removes discovered peer profiles/presence/index references and keeps your self profile.');
|
|
1421
|
-
if (!ok) return;
|
|
1422
|
-
await runAction('/api/cache/clear', 'Clearing discovered cache...', 'warn');
|
|
1423
|
-
});
|
|
3101
|
+
document.getElementById('startBroadcastBtn').addEventListener('click', () => runAction('/api/broadcast/start', t('actions.startBroadcast')));
|
|
3102
|
+
document.getElementById('stopBroadcastBtn').addEventListener('click', () => runAction('/api/broadcast/stop', t('actions.stopBroadcast'), 'warn'));
|
|
3103
|
+
document.getElementById('broadcastNowBtn').addEventListener('click', () => runAction('/api/broadcast/now', t('actions.broadcastNow')));
|
|
1424
3104
|
document.getElementById('quickGlobalPreviewBtn').addEventListener('click', async () => {
|
|
1425
|
-
const currentSignaling = window.prompt('
|
|
3105
|
+
const currentSignaling = window.prompt(t('feedback.promptSignalingUrl'), 'http://localhost:4510');
|
|
1426
3106
|
if (!currentSignaling) return;
|
|
1427
|
-
const room = window.prompt('
|
|
1428
|
-
setFeedback('networkFeedback', '
|
|
3107
|
+
const room = window.prompt(t('feedback.promptRoom'), 'silicaclaw-global-preview') || 'silicaclaw-global-preview';
|
|
3108
|
+
setFeedback('networkFeedback', t('feedback.crossPreviewEnabling'));
|
|
1429
3109
|
try {
|
|
1430
3110
|
const result = await api('/api/network/quick-connect-global-preview', {
|
|
1431
3111
|
method: 'POST',
|
|
@@ -1434,11 +3114,11 @@
|
|
|
1434
3114
|
room: room.trim(),
|
|
1435
3115
|
}),
|
|
1436
3116
|
});
|
|
1437
|
-
setFeedback('networkFeedback', result.meta?.message || '
|
|
1438
|
-
toast('
|
|
3117
|
+
setFeedback('networkFeedback', result.meta?.message || t('feedback.crossPreviewEnabled'));
|
|
3118
|
+
toast(t('feedback.crossPreviewEnabled'));
|
|
1439
3119
|
await refreshAll();
|
|
1440
3120
|
} catch (e) {
|
|
1441
|
-
setFeedback('networkFeedback', e instanceof Error ? e.message : '
|
|
3121
|
+
setFeedback('networkFeedback', e instanceof Error ? e.message : t('feedback.enableCrossPreviewFailed'), 'error');
|
|
1442
3122
|
}
|
|
1443
3123
|
});
|
|
1444
3124
|
document.getElementById('onlyOnlineToggle').addEventListener('change', async (event) => {
|
|
@@ -1447,104 +3127,50 @@
|
|
|
1447
3127
|
});
|
|
1448
3128
|
document.getElementById('refreshLogsBtn').addEventListener('click', async () => {
|
|
1449
3129
|
await refreshLogs();
|
|
1450
|
-
toast('
|
|
1451
|
-
});
|
|
1452
|
-
document.getElementById('enablePublicDiscoveryBtn').addEventListener('click', async () => {
|
|
1453
|
-
const ok = window.confirm(
|
|
1454
|
-
'Enable public discovery now?\n\n' +
|
|
1455
|
-
'- Only profile/presence are shared.\n' +
|
|
1456
|
-
'- Private files are not shared.\n' +
|
|
1457
|
-
'- Chat and remote control are not enabled.\n\n' +
|
|
1458
|
-
'This updates runtime state and does not overwrite social.md.'
|
|
1459
|
-
);
|
|
1460
|
-
if (!ok) return;
|
|
1461
|
-
setFeedback('networkFeedback', 'Enabling public discovery...');
|
|
1462
|
-
try {
|
|
1463
|
-
const res = await api('/api/public-discovery/enable', { method: 'POST' });
|
|
1464
|
-
setFeedback('networkFeedback', res.meta?.message || 'Public discovery enabled.');
|
|
1465
|
-
toast('Public discovery enabled');
|
|
1466
|
-
await refreshAll();
|
|
1467
|
-
} catch (e) {
|
|
1468
|
-
setFeedback('networkFeedback', e instanceof Error ? e.message : 'Enable public discovery failed', 'error');
|
|
1469
|
-
}
|
|
1470
|
-
});
|
|
1471
|
-
document.getElementById('disablePublicDiscoveryBtn').addEventListener('click', async () => {
|
|
1472
|
-
const ok = window.confirm('Disable public discovery now? This updates runtime state and does not overwrite social.md.');
|
|
1473
|
-
if (!ok) return;
|
|
1474
|
-
setFeedback('networkFeedback', 'Disabling public discovery...');
|
|
1475
|
-
try {
|
|
1476
|
-
const res = await api('/api/public-discovery/disable', { method: 'POST' });
|
|
1477
|
-
setFeedback('networkFeedback', res.meta?.message || 'Public discovery disabled.');
|
|
1478
|
-
toast('Public discovery disabled');
|
|
1479
|
-
await refreshAll();
|
|
1480
|
-
} catch (e) {
|
|
1481
|
-
setFeedback('networkFeedback', e instanceof Error ? e.message : 'Disable public discovery failed', 'error');
|
|
1482
|
-
}
|
|
1483
|
-
});
|
|
1484
|
-
document.getElementById('socialReloadBtn').addEventListener('click', async () => {
|
|
1485
|
-
setFeedback('socialFeedback', 'Reloading social config...');
|
|
1486
|
-
try {
|
|
1487
|
-
const res = await api('/api/social/reload', { method: 'POST' });
|
|
1488
|
-
setFeedback('socialFeedback', res.meta?.message || 'Reloaded');
|
|
1489
|
-
toast('Social config reloaded');
|
|
1490
|
-
await refreshAll();
|
|
1491
|
-
} catch (e) {
|
|
1492
|
-
setFeedback('socialFeedback', e instanceof Error ? e.message : 'Reload failed', 'error');
|
|
1493
|
-
}
|
|
1494
|
-
});
|
|
1495
|
-
document.getElementById('socialGenerateBtn').addEventListener('click', async () => {
|
|
1496
|
-
setFeedback('socialFeedback', 'Generating default social.md...');
|
|
1497
|
-
try {
|
|
1498
|
-
const res = await api('/api/social/generate-default', { method: 'POST' });
|
|
1499
|
-
setFeedback('socialFeedback', res.meta?.message || 'Done');
|
|
1500
|
-
toast(res.meta?.message || 'Default social.md ready');
|
|
1501
|
-
await refreshAll();
|
|
1502
|
-
} catch (e) {
|
|
1503
|
-
setFeedback('socialFeedback', e instanceof Error ? e.message : 'Generate failed', 'error');
|
|
1504
|
-
}
|
|
3130
|
+
toast(t('feedback.logsRefreshed'));
|
|
1505
3131
|
});
|
|
1506
3132
|
document.getElementById('socialExportBtn').addEventListener('click', async () => {
|
|
1507
|
-
setFeedback('socialFeedback', '
|
|
3133
|
+
setFeedback('socialFeedback', t('feedback.exportingTemplate'));
|
|
1508
3134
|
try {
|
|
1509
3135
|
await exportSocialTemplate();
|
|
1510
|
-
setFeedback('socialFeedback', '
|
|
1511
|
-
toast('
|
|
3136
|
+
setFeedback('socialFeedback', t('feedback.templateExported'));
|
|
3137
|
+
toast(t('feedback.templateExported'));
|
|
1512
3138
|
} catch (e) {
|
|
1513
|
-
setFeedback('socialFeedback', e instanceof Error ? e.message : '
|
|
3139
|
+
setFeedback('socialFeedback', e instanceof Error ? e.message : t('feedback.exportFailed'), 'error');
|
|
1514
3140
|
}
|
|
1515
3141
|
});
|
|
1516
3142
|
document.getElementById('socialModeApplyBtn').addEventListener('click', async () => {
|
|
1517
3143
|
const mode = document.getElementById('socialModeSelect').value;
|
|
1518
|
-
setFeedback('socialFeedback',
|
|
3144
|
+
setFeedback('socialFeedback', t('feedback.runtimeModeApplying', { mode }));
|
|
1519
3145
|
try {
|
|
1520
3146
|
const res = await api('/api/social/runtime-mode', {
|
|
1521
3147
|
method: 'POST',
|
|
1522
3148
|
body: JSON.stringify({ mode }),
|
|
1523
3149
|
});
|
|
1524
|
-
setFeedback('socialFeedback', res.meta?.message || '
|
|
1525
|
-
toast(
|
|
3150
|
+
setFeedback('socialFeedback', res.meta?.message || t('feedback.runtimeUpdated'));
|
|
3151
|
+
toast(t('feedback.runtimeMode', { mode }));
|
|
1526
3152
|
await refreshAll();
|
|
1527
3153
|
} catch (e) {
|
|
1528
|
-
setFeedback('socialFeedback', e instanceof Error ? e.message : '
|
|
3154
|
+
setFeedback('socialFeedback', e instanceof Error ? e.message : t('feedback.failed'), 'error');
|
|
1529
3155
|
}
|
|
1530
3156
|
});
|
|
1531
3157
|
document.getElementById('socialCopyBtn').addEventListener('click', async () => {
|
|
1532
|
-
setFeedback('socialFeedback', '
|
|
3158
|
+
setFeedback('socialFeedback', t('feedback.copyingTemplate'));
|
|
1533
3159
|
const btn = document.getElementById('socialCopyBtn');
|
|
1534
3160
|
try {
|
|
1535
3161
|
if (!socialTemplate) {
|
|
1536
3162
|
await exportSocialTemplate();
|
|
1537
3163
|
}
|
|
1538
3164
|
await navigator.clipboard.writeText(socialTemplate);
|
|
1539
|
-
setFeedback('socialFeedback', '
|
|
1540
|
-
toast('
|
|
1541
|
-
flashButton(btn, '
|
|
3165
|
+
setFeedback('socialFeedback', t('feedback.templateCopied'));
|
|
3166
|
+
toast(t('common.copied'));
|
|
3167
|
+
flashButton(btn, t('common.copied'));
|
|
1542
3168
|
} catch (e) {
|
|
1543
|
-
setFeedback('socialFeedback', e instanceof Error ? e.message : '
|
|
3169
|
+
setFeedback('socialFeedback', e instanceof Error ? e.message : t('feedback.copyFailed'), 'error');
|
|
1544
3170
|
}
|
|
1545
3171
|
});
|
|
1546
3172
|
document.getElementById('socialDownloadBtn').addEventListener('click', async () => {
|
|
1547
|
-
setFeedback('socialFeedback', '
|
|
3173
|
+
setFeedback('socialFeedback', t('feedback.preparingDownload'));
|
|
1548
3174
|
try {
|
|
1549
3175
|
const payload = await exportSocialTemplate();
|
|
1550
3176
|
const filename = String(payload.filename || 'social.md');
|
|
@@ -1557,10 +3183,10 @@
|
|
|
1557
3183
|
anchor.click();
|
|
1558
3184
|
anchor.remove();
|
|
1559
3185
|
URL.revokeObjectURL(url);
|
|
1560
|
-
setFeedback('socialFeedback',
|
|
1561
|
-
toast('
|
|
3186
|
+
setFeedback('socialFeedback', t('feedback.downloaded', { filename }));
|
|
3187
|
+
toast(t('feedback.downloaded', { filename }));
|
|
1562
3188
|
} catch (e) {
|
|
1563
|
-
setFeedback('socialFeedback', e instanceof Error ? e.message : '
|
|
3189
|
+
setFeedback('socialFeedback', e instanceof Error ? e.message : t('feedback.downloadFailed'), 'error');
|
|
1564
3190
|
}
|
|
1565
3191
|
});
|
|
1566
3192
|
document.getElementById('copyPublicProfilePreviewBtn').addEventListener('click', async () => {
|
|
@@ -1568,10 +3194,10 @@
|
|
|
1568
3194
|
try {
|
|
1569
3195
|
const summary = (await api('/api/public-profile/preview')).data || null;
|
|
1570
3196
|
await navigator.clipboard.writeText(toPrettyJson(summary));
|
|
1571
|
-
toast('
|
|
1572
|
-
flashButton(btn, '
|
|
3197
|
+
toast(t('actions.copyPublicProfilePreview'));
|
|
3198
|
+
flashButton(btn, t('common.copied'));
|
|
1573
3199
|
} catch (e) {
|
|
1574
|
-
setFeedback('profileFeedback', e instanceof Error ? e.message : '
|
|
3200
|
+
setFeedback('profileFeedback', e instanceof Error ? e.message : t('feedback.copyPreviewFailed'), 'error');
|
|
1575
3201
|
}
|
|
1576
3202
|
});
|
|
1577
3203
|
document.getElementById('logLevelFilter').addEventListener('change', (event) => {
|
|
@@ -1593,6 +3219,20 @@
|
|
|
1593
3219
|
});
|
|
1594
3220
|
})();
|
|
1595
3221
|
|
|
3222
|
+
if (window.matchMedia) {
|
|
3223
|
+
const media = window.matchMedia('(prefers-color-scheme: light)');
|
|
3224
|
+
const handleThemeMedia = () => {
|
|
3225
|
+
if ((localStorage.getItem('silicaclaw_theme_mode') || 'dark') === 'system') {
|
|
3226
|
+
applyTheme('system');
|
|
3227
|
+
}
|
|
3228
|
+
};
|
|
3229
|
+
if (typeof media.addEventListener === 'function') {
|
|
3230
|
+
media.addEventListener('change', handleThemeMedia);
|
|
3231
|
+
} else if (typeof media.addListener === 'function') {
|
|
3232
|
+
media.addListener(handleThemeMedia);
|
|
3233
|
+
}
|
|
3234
|
+
}
|
|
3235
|
+
|
|
1596
3236
|
applyTheme(localStorage.getItem('silicaclaw_theme_mode') || 'dark');
|
|
1597
3237
|
refreshAll();
|
|
1598
3238
|
exportSocialTemplate().catch(() => {});
|