privateboard 0.1.6 → 0.1.7
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/dist/cli.js +7 -2
- package/dist/cli.js.map +1 -1
- package/package.json +4 -2
- package/public/agent-profile.js +14 -0
- package/public/app.js +465 -704
- package/public/index.html +193 -151
- package/public/report.html +356 -59
- package/public/typing-sfx.js +158 -0
- package/public/user-settings.css +90 -0
- package/public/user-settings.js +71 -0
package/public/user-settings.css
CHANGED
|
@@ -162,6 +162,43 @@
|
|
|
162
162
|
.us-nav-item.danger { color: var(--text-faint, #3A382F); }
|
|
163
163
|
.us-nav-item.danger:hover { color: var(--red, #B5706A); }
|
|
164
164
|
|
|
165
|
+
/* ─── Sidebar foot · app version stamp ───
|
|
166
|
+
Pinned to the bottom of the column flex via `margin-top: auto` so
|
|
167
|
+
it sits below every nav item even when the section list is short.
|
|
168
|
+
Tiny mono kicker · matches the section-tag typography elsewhere in
|
|
169
|
+
the overlay so it reads as quiet metadata, not a sixth nav item. */
|
|
170
|
+
.us-nav-foot {
|
|
171
|
+
margin-top: auto;
|
|
172
|
+
padding: 12px 12px 4px;
|
|
173
|
+
display: flex;
|
|
174
|
+
flex-direction: column;
|
|
175
|
+
gap: 2px;
|
|
176
|
+
align-items: flex-start;
|
|
177
|
+
border-top: 0.5px solid var(--line-bright, #2A2A26);
|
|
178
|
+
font-family: var(--mono);
|
|
179
|
+
}
|
|
180
|
+
.us-nav-foot-label {
|
|
181
|
+
font-size: 8.5px;
|
|
182
|
+
letter-spacing: 0.22em;
|
|
183
|
+
text-transform: uppercase;
|
|
184
|
+
color: var(--text-faint, #3A382F);
|
|
185
|
+
font-weight: 600;
|
|
186
|
+
}
|
|
187
|
+
.us-nav-foot-value {
|
|
188
|
+
font-size: 11px;
|
|
189
|
+
letter-spacing: 0.04em;
|
|
190
|
+
color: var(--text-soft, #8E8B83);
|
|
191
|
+
font-weight: 700;
|
|
192
|
+
font-variant-numeric: tabular-nums;
|
|
193
|
+
}
|
|
194
|
+
@media (max-width: 600px) {
|
|
195
|
+
/* On the horizontal-row mobile nav layout, the foot would steal a
|
|
196
|
+
slot in the scrollable tab strip — hide it there. The version
|
|
197
|
+
still surfaces via the running server's /api/version endpoint
|
|
198
|
+
for anyone who needs it. */
|
|
199
|
+
.us-nav-foot { display: none; }
|
|
200
|
+
}
|
|
201
|
+
|
|
165
202
|
/* Right pane (scrollable section content) */
|
|
166
203
|
.us-pane {
|
|
167
204
|
padding: 18px 22px 18px;
|
|
@@ -224,6 +261,59 @@
|
|
|
224
261
|
margin-top: 5px;
|
|
225
262
|
}
|
|
226
263
|
|
|
264
|
+
/* ─── Toggle row · pill button + supporting deck text ───
|
|
265
|
+
Matches the visual vocabulary of the day-picker pills (mono
|
|
266
|
+
uppercase, hairline border, lime accent when on) so the User pane
|
|
267
|
+
doesn't introduce a third button style for one toggle. */
|
|
268
|
+
.us-toggle-row {
|
|
269
|
+
display: flex;
|
|
270
|
+
align-items: center;
|
|
271
|
+
gap: 12px;
|
|
272
|
+
flex-wrap: wrap;
|
|
273
|
+
}
|
|
274
|
+
.us-toggle-pill {
|
|
275
|
+
appearance: none;
|
|
276
|
+
background: transparent;
|
|
277
|
+
border: 0.5px solid var(--line-bright, #2A2A26);
|
|
278
|
+
color: var(--text-soft, #8E8B83);
|
|
279
|
+
font-family: var(--mono);
|
|
280
|
+
font-size: 10.5px;
|
|
281
|
+
letter-spacing: 0.18em;
|
|
282
|
+
text-transform: uppercase;
|
|
283
|
+
font-weight: 700;
|
|
284
|
+
padding: 6px 14px;
|
|
285
|
+
display: inline-flex;
|
|
286
|
+
align-items: center;
|
|
287
|
+
gap: 8px;
|
|
288
|
+
cursor: pointer;
|
|
289
|
+
transition: color 0.12s, border-color 0.12s, background 0.12s;
|
|
290
|
+
}
|
|
291
|
+
.us-toggle-pill:hover {
|
|
292
|
+
color: var(--text, #C8C5BE);
|
|
293
|
+
border-color: var(--text-faint, #3A382F);
|
|
294
|
+
}
|
|
295
|
+
.us-toggle-pill.on {
|
|
296
|
+
color: var(--lime, #6FB572);
|
|
297
|
+
border-color: var(--lime, #6FB572);
|
|
298
|
+
background: var(--panel-2, #1A1A18);
|
|
299
|
+
}
|
|
300
|
+
.us-toggle-dot {
|
|
301
|
+
width: 6px;
|
|
302
|
+
height: 6px;
|
|
303
|
+
border-radius: 50%;
|
|
304
|
+
background: var(--text-faint, #3A382F);
|
|
305
|
+
transition: background 0.12s;
|
|
306
|
+
}
|
|
307
|
+
.us-toggle-pill.on .us-toggle-dot { background: var(--lime, #6FB572); }
|
|
308
|
+
.us-toggle-deck {
|
|
309
|
+
font-size: 11px;
|
|
310
|
+
color: var(--text-faint, #3A382F);
|
|
311
|
+
letter-spacing: 0.02em;
|
|
312
|
+
line-height: 1.5;
|
|
313
|
+
flex: 1 1 220px;
|
|
314
|
+
min-width: 0;
|
|
315
|
+
}
|
|
316
|
+
|
|
227
317
|
/* User avatar block */
|
|
228
318
|
.us-avatar-row {
|
|
229
319
|
display: flex;
|
package/public/user-settings.js
CHANGED
|
@@ -225,6 +225,19 @@
|
|
|
225
225
|
<div class="us-row-meta"><span data-us-intro-count>0</span> / 320 chars</div>
|
|
226
226
|
</div>
|
|
227
227
|
</div>
|
|
228
|
+
|
|
229
|
+
<div class="us-row">
|
|
230
|
+
<div class="us-row-label">Typing sound</div>
|
|
231
|
+
<div class="us-row-field">
|
|
232
|
+
<div class="us-toggle-row">
|
|
233
|
+
<button type="button" class="us-toggle-pill" data-us-sfx-typing aria-pressed="false">
|
|
234
|
+
<span class="us-toggle-dot"></span>
|
|
235
|
+
<span class="us-toggle-label" data-us-sfx-typing-label>off</span>
|
|
236
|
+
</button>
|
|
237
|
+
<span class="us-toggle-deck">a soft keyboard click as directors stream their replies. Persists locally.</span>
|
|
238
|
+
</div>
|
|
239
|
+
</div>
|
|
240
|
+
</div>
|
|
228
241
|
</div>
|
|
229
242
|
`;
|
|
230
243
|
}
|
|
@@ -930,6 +943,10 @@
|
|
|
930
943
|
<a href="#" class="us-nav-item" data-section="usage" role="tab" aria-selected="false">Usage</a>
|
|
931
944
|
<a href="#" class="us-nav-item" data-section="keys" role="tab" aria-selected="false">API Key</a>
|
|
932
945
|
<a href="#" class="us-nav-item" data-section="default" role="tab" aria-selected="false">Default Model</a>
|
|
946
|
+
<div class="us-nav-foot" data-us-version aria-label="App version">
|
|
947
|
+
<span class="us-nav-foot-label">version</span>
|
|
948
|
+
<span class="us-nav-foot-value" data-us-version-value>·</span>
|
|
949
|
+
</div>
|
|
933
950
|
</nav>
|
|
934
951
|
|
|
935
952
|
<div class="us-pane" data-us-pane></div>
|
|
@@ -1018,6 +1035,32 @@
|
|
|
1018
1035
|
});
|
|
1019
1036
|
introCount.textContent = introInput.value.length;
|
|
1020
1037
|
|
|
1038
|
+
// Typing-sound toggle · the persistence + audio context lives in
|
|
1039
|
+
// window.boardroomTypingSfx (typing-sfx.js), so this row only
|
|
1040
|
+
// mirrors the current state and proxies clicks. Reading inside the
|
|
1041
|
+
// wire-up call (not at HTML build time) means the pill always
|
|
1042
|
+
// reflects the LATEST stored state when the User pane re-mounts.
|
|
1043
|
+
const sfxBtn = paneEl.querySelector("[data-us-sfx-typing]");
|
|
1044
|
+
const sfxLabel = paneEl.querySelector("[data-us-sfx-typing-label]");
|
|
1045
|
+
if (sfxBtn && sfxLabel && window.boardroomTypingSfx) {
|
|
1046
|
+
const paint = () => {
|
|
1047
|
+
const on = window.boardroomTypingSfx.isEnabled();
|
|
1048
|
+
sfxBtn.classList.toggle("on", on);
|
|
1049
|
+
sfxBtn.setAttribute("aria-pressed", on ? "true" : "false");
|
|
1050
|
+
sfxLabel.textContent = on ? "on" : "off";
|
|
1051
|
+
};
|
|
1052
|
+
paint();
|
|
1053
|
+
sfxBtn.addEventListener("click", () => {
|
|
1054
|
+
const next = !window.boardroomTypingSfx.isEnabled();
|
|
1055
|
+
window.boardroomTypingSfx.setEnabled(next);
|
|
1056
|
+
paint();
|
|
1057
|
+
// Audible confirmation when turning ON · the click that just
|
|
1058
|
+
// toggled also serves as the gesture the AudioContext needs,
|
|
1059
|
+
// so this tick will actually be heard.
|
|
1060
|
+
if (next) window.boardroomTypingSfx.tick();
|
|
1061
|
+
});
|
|
1062
|
+
}
|
|
1063
|
+
|
|
1021
1064
|
// Regenerate avatar · same pattern as agent-profile's
|
|
1022
1065
|
// regenerateProfileAvatar: pull a fresh randomSeed, persist it to
|
|
1023
1066
|
// the user prefs, repaint. No counter, no name/intro composition —
|
|
@@ -1219,6 +1262,34 @@
|
|
|
1219
1262
|
overlay.classList.add("open");
|
|
1220
1263
|
overlay.setAttribute("aria-hidden", "false");
|
|
1221
1264
|
document.body.style.overflow = "hidden";
|
|
1265
|
+
// Lazy-fetch the version string on each open. Cheap (one tiny
|
|
1266
|
+
// request, no DB hit) and the user expects the foot to reflect
|
|
1267
|
+
// the running server, not a baked-in client constant — if they
|
|
1268
|
+
// upgrade the npm package and a tab is still open, the next
|
|
1269
|
+
// overlay open shows the new version.
|
|
1270
|
+
fetchAppVersion();
|
|
1271
|
+
}
|
|
1272
|
+
|
|
1273
|
+
let _versionCache = null;
|
|
1274
|
+
async function fetchAppVersion() {
|
|
1275
|
+
const slot = overlay && overlay.querySelector("[data-us-version-value]");
|
|
1276
|
+
if (!slot) return;
|
|
1277
|
+
// Use cache if we already have it · the version doesn't change
|
|
1278
|
+
// mid-process. First open does the network round-trip; subsequent
|
|
1279
|
+
// opens repaint from cache instantly.
|
|
1280
|
+
if (_versionCache) {
|
|
1281
|
+
slot.textContent = _versionCache;
|
|
1282
|
+
return;
|
|
1283
|
+
}
|
|
1284
|
+
try {
|
|
1285
|
+
const r = await fetch("/api/version");
|
|
1286
|
+
if (!r.ok) return;
|
|
1287
|
+
const j = await r.json();
|
|
1288
|
+
if (j && typeof j.version === "string") {
|
|
1289
|
+
_versionCache = `v${j.version}`;
|
|
1290
|
+
slot.textContent = _versionCache;
|
|
1291
|
+
}
|
|
1292
|
+
} catch { /* swallow · the foot just stays at "·" if offline */ }
|
|
1222
1293
|
}
|
|
1223
1294
|
function close() {
|
|
1224
1295
|
if (!overlay) return;
|