privateboard 0.1.6 → 0.1.8
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 +700 -17
- package/dist/cli.js.map +1 -1
- package/package.json +4 -2
- package/public/adjourn-overlay.css +194 -0
- package/public/agent-profile.js +14 -0
- package/public/app.js +862 -741
- package/public/bento.html +1396 -0
- package/public/home.html +389 -17
- package/public/index.html +211 -152
- package/public/magazine.html +1266 -0
- package/public/newspaper.html +1770 -0
- package/public/report.html +666 -55
- package/public/typing-sfx.js +158 -0
- package/public/user-settings.css +156 -19
- package/public/user-settings.js +109 -4
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "privateboard",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.8",
|
|
4
4
|
"description": "PrivateBoard · your private board meeting, on call. Local-first, multi-agent thinking amplifier.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -18,7 +18,9 @@
|
|
|
18
18
|
"start": "node dist/cli.js",
|
|
19
19
|
"test": "vitest run",
|
|
20
20
|
"test:watch": "vitest",
|
|
21
|
-
"
|
|
21
|
+
"sync-version": "node scripts/sync-version.mjs",
|
|
22
|
+
"regen-avatars": "node scripts/regen-avatars.mjs",
|
|
23
|
+
"prepublishOnly": "npm run sync-version && npm run build"
|
|
22
24
|
},
|
|
23
25
|
"repository": {
|
|
24
26
|
"type": "git",
|
|
@@ -168,6 +168,45 @@
|
|
|
168
168
|
line-height: 1.4;
|
|
169
169
|
word-break: break-word;
|
|
170
170
|
}
|
|
171
|
+
|
|
172
|
+
/* Subject row · the subject text can run several lines on long room
|
|
173
|
+
titles. We clamp to 3 lines by default and reveal a Show more /
|
|
174
|
+
less toggle only when the text actually overflows (the toggle is
|
|
175
|
+
`hidden` at render time and unhidden by openAdjournOverlay's post-
|
|
176
|
+
mount measurement). */
|
|
177
|
+
.adjourn-subject-wrap {
|
|
178
|
+
display: flex;
|
|
179
|
+
flex-direction: column;
|
|
180
|
+
gap: 6px;
|
|
181
|
+
min-width: 0;
|
|
182
|
+
}
|
|
183
|
+
.adjourn-subject-text {
|
|
184
|
+
display: block;
|
|
185
|
+
white-space: pre-wrap;
|
|
186
|
+
}
|
|
187
|
+
.adjourn-subject-text.is-clamped {
|
|
188
|
+
display: -webkit-box;
|
|
189
|
+
-webkit-line-clamp: 3;
|
|
190
|
+
-webkit-box-orient: vertical;
|
|
191
|
+
overflow: hidden;
|
|
192
|
+
}
|
|
193
|
+
.adjourn-subject-toggle {
|
|
194
|
+
align-self: flex-start;
|
|
195
|
+
appearance: none;
|
|
196
|
+
background: transparent;
|
|
197
|
+
border: none;
|
|
198
|
+
font-family: var(--mono);
|
|
199
|
+
font-size: 9.5px;
|
|
200
|
+
letter-spacing: 0.14em;
|
|
201
|
+
text-transform: uppercase;
|
|
202
|
+
color: var(--text-soft);
|
|
203
|
+
cursor: pointer;
|
|
204
|
+
padding: 0;
|
|
205
|
+
transition: color 0.12s;
|
|
206
|
+
}
|
|
207
|
+
.adjourn-subject-toggle:hover { color: var(--lime); }
|
|
208
|
+
.adjourn-subject-toggle::before { content: "[ "; color: var(--text-faint); }
|
|
209
|
+
.adjourn-subject-toggle::after { content: " ]"; color: var(--text-faint); }
|
|
171
210
|
.adjourn-summary-note {
|
|
172
211
|
margin: 0;
|
|
173
212
|
font-family: var(--font-human);
|
|
@@ -177,6 +216,161 @@
|
|
|
177
216
|
letter-spacing: -0.003em;
|
|
178
217
|
}
|
|
179
218
|
|
|
219
|
+
/* ─── Report-mode picker · two cards radio-style. Sits between the
|
|
220
|
+
summary note and the foot actions. Selected option gets a left
|
|
221
|
+
accent stripe + tinted bg; unselected stays quiet. The radio inputs
|
|
222
|
+
are visually hidden (the label IS the click target) but stay in the
|
|
223
|
+
DOM for accessibility / keyboard nav. ─────────────────────────── */
|
|
224
|
+
.adjourn-mode-picker {
|
|
225
|
+
margin-top: 16px;
|
|
226
|
+
padding-top: 14px;
|
|
227
|
+
border-top: 0.5px solid var(--line);
|
|
228
|
+
}
|
|
229
|
+
.adjourn-mode-label {
|
|
230
|
+
font-family: var(--mono);
|
|
231
|
+
font-size: 9.5px;
|
|
232
|
+
letter-spacing: 0.14em;
|
|
233
|
+
color: var(--text-faint);
|
|
234
|
+
margin-bottom: 8px;
|
|
235
|
+
text-transform: uppercase;
|
|
236
|
+
}
|
|
237
|
+
.adjourn-mode-options {
|
|
238
|
+
display: grid;
|
|
239
|
+
grid-template-columns: 1fr 1fr;
|
|
240
|
+
gap: 10px;
|
|
241
|
+
}
|
|
242
|
+
.adjourn-mode-options-3 {
|
|
243
|
+
grid-template-columns: 1fr 1fr 1fr;
|
|
244
|
+
}
|
|
245
|
+
.adjourn-mode-options-4 {
|
|
246
|
+
grid-template-columns: 1fr 1fr;
|
|
247
|
+
}
|
|
248
|
+
/* At desktop width the primary tile (Report · the long-form
|
|
249
|
+
markdown mode) takes 1.5× the width of the other three so it
|
|
250
|
+
reads as the default / recommended choice. The implementation
|
|
251
|
+
piggybacks on grid auto-placement: the primary is always the
|
|
252
|
+
first child, so giving column 1 a 1.5fr track is enough. */
|
|
253
|
+
@media (min-width: 800px) {
|
|
254
|
+
.adjourn-mode-options-4 { grid-template-columns: 1.5fr 1fr 1fr 1fr; }
|
|
255
|
+
}
|
|
256
|
+
@media (max-width: 720px) {
|
|
257
|
+
.adjourn-mode-options-3 { grid-template-columns: 1fr 1fr; }
|
|
258
|
+
}
|
|
259
|
+
@media (max-width: 540px) {
|
|
260
|
+
.adjourn-mode-options { grid-template-columns: 1fr; }
|
|
261
|
+
.adjourn-mode-options-3 { grid-template-columns: 1fr; }
|
|
262
|
+
.adjourn-mode-options-4 { grid-template-columns: 1fr; }
|
|
263
|
+
}
|
|
264
|
+
.adjourn-mode-option {
|
|
265
|
+
position: relative;
|
|
266
|
+
display: flex;
|
|
267
|
+
flex-direction: column;
|
|
268
|
+
align-items: stretch;
|
|
269
|
+
text-align: center;
|
|
270
|
+
gap: 8px;
|
|
271
|
+
padding: 14px 10px 12px;
|
|
272
|
+
background: var(--panel-2);
|
|
273
|
+
border: 1px solid var(--line);
|
|
274
|
+
cursor: pointer;
|
|
275
|
+
transition: border-color 0.12s, color 0.12s;
|
|
276
|
+
min-height: 130px;
|
|
277
|
+
}
|
|
278
|
+
.adjourn-mode-option:hover {
|
|
279
|
+
border-color: var(--line-bright);
|
|
280
|
+
}
|
|
281
|
+
/* Selected state · just the border + icon shift to lime. No
|
|
282
|
+
background tint, no transform · the visual delta against
|
|
283
|
+
neighbour tiles is enough on its own. */
|
|
284
|
+
.adjourn-mode-option.on {
|
|
285
|
+
border-color: var(--lime);
|
|
286
|
+
}
|
|
287
|
+
/* The native radio is the source of truth for `:checked` state and
|
|
288
|
+
keyboard navigation, but visually it's hidden — the whole tile IS
|
|
289
|
+
the click target. Keeping it in the DOM (at 1×1 absolutely-
|
|
290
|
+
positioned) preserves a11y without occupying layout space. */
|
|
291
|
+
.adjourn-mode-option input[type="radio"] {
|
|
292
|
+
position: absolute;
|
|
293
|
+
width: 1px;
|
|
294
|
+
height: 1px;
|
|
295
|
+
margin: 0;
|
|
296
|
+
padding: 0;
|
|
297
|
+
border: 0;
|
|
298
|
+
opacity: 0;
|
|
299
|
+
pointer-events: none;
|
|
300
|
+
}
|
|
301
|
+
/* Keyboard focus only · `:has(input:focus-visible)` skips the ring
|
|
302
|
+
on plain mouse clicks (which already get the lime border + icon
|
|
303
|
+
feedback) so a clicked tile doesn't show a doubled outline. */
|
|
304
|
+
.adjourn-mode-option:has(input:focus-visible) {
|
|
305
|
+
outline: 1px solid var(--lime);
|
|
306
|
+
outline-offset: 1px;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/* Icon block · 40px high, centered. Color inherits from the parent
|
|
310
|
+
so hover / selected states cascade through `currentColor` in the
|
|
311
|
+
SVG without per-mode overrides. */
|
|
312
|
+
.adjourn-mode-icon {
|
|
313
|
+
display: flex;
|
|
314
|
+
align-items: center;
|
|
315
|
+
justify-content: center;
|
|
316
|
+
height: 44px;
|
|
317
|
+
margin-bottom: 2px;
|
|
318
|
+
color: var(--text-soft);
|
|
319
|
+
transition: color 0.12s;
|
|
320
|
+
}
|
|
321
|
+
.adjourn-mode-icon svg {
|
|
322
|
+
width: 36px;
|
|
323
|
+
height: 36px;
|
|
324
|
+
display: block;
|
|
325
|
+
}
|
|
326
|
+
.adjourn-mode-option:hover .adjourn-mode-icon {
|
|
327
|
+
color: var(--text);
|
|
328
|
+
}
|
|
329
|
+
.adjourn-mode-option.on .adjourn-mode-icon {
|
|
330
|
+
color: var(--lime);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
/* Primary tile · the Report mode is the recommended default, so it
|
|
334
|
+
gets a slightly larger icon + a touch more padding to read as the
|
|
335
|
+
"main" choice without changing its visual register. */
|
|
336
|
+
.adjourn-mode-option-primary {
|
|
337
|
+
padding: 16px 14px 14px;
|
|
338
|
+
}
|
|
339
|
+
.adjourn-mode-option-primary .adjourn-mode-icon {
|
|
340
|
+
height: 50px;
|
|
341
|
+
}
|
|
342
|
+
.adjourn-mode-option-primary .adjourn-mode-icon svg {
|
|
343
|
+
width: 42px;
|
|
344
|
+
height: 42px;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
.adjourn-mode-body {
|
|
348
|
+
display: flex;
|
|
349
|
+
flex-direction: column;
|
|
350
|
+
gap: 3px;
|
|
351
|
+
min-width: 0;
|
|
352
|
+
}
|
|
353
|
+
.adjourn-mode-title {
|
|
354
|
+
font-family: var(--font-human);
|
|
355
|
+
font-size: 13px;
|
|
356
|
+
font-weight: 600;
|
|
357
|
+
color: var(--text);
|
|
358
|
+
letter-spacing: -0.005em;
|
|
359
|
+
line-height: 1.2;
|
|
360
|
+
}
|
|
361
|
+
.adjourn-mode-deck {
|
|
362
|
+
font-family: var(--font-human);
|
|
363
|
+
font-size: 11px;
|
|
364
|
+
line-height: 1.4;
|
|
365
|
+
color: var(--text-faint);
|
|
366
|
+
/* Clamp to 2 lines so 4 tiles align to the same height regardless
|
|
367
|
+
of deck length; longer decks ellipsis cleanly. */
|
|
368
|
+
display: -webkit-box;
|
|
369
|
+
-webkit-line-clamp: 2;
|
|
370
|
+
-webkit-box-orient: vertical;
|
|
371
|
+
overflow: hidden;
|
|
372
|
+
}
|
|
373
|
+
|
|
180
374
|
/* ─── Footer ─── skip-button on the left, primary actions on the right.
|
|
181
375
|
The skip moves out of the gallery-body and into a real button slot
|
|
182
376
|
so the visual weight matches Cancel / Adjourn (peers in size and
|
package/public/agent-profile.js
CHANGED
|
@@ -2389,6 +2389,14 @@
|
|
|
2389
2389
|
document.querySelectorAll("[data-notes-trigger].active").forEach((el) => el.classList.remove("active"));
|
|
2390
2390
|
document.querySelectorAll("[data-reports-trigger].active").forEach((el) => el.classList.remove("active"));
|
|
2391
2391
|
currentlyOpenSlug = null;
|
|
2392
|
+
// Clear the no-room flag IFF there's an actual room loaded · the
|
|
2393
|
+
// floating sidebar-expand button shouldn't show on top of a real
|
|
2394
|
+
// room view (the in-header expand button takes over there). When
|
|
2395
|
+
// showRoom fires without an active room (e.g. bouncing back to
|
|
2396
|
+
// the empty-state composer), keep no-room set so the expand
|
|
2397
|
+
// control stays reachable.
|
|
2398
|
+
const hasRoom = window.app && window.app.currentRoomId;
|
|
2399
|
+
if (hasRoom) document.documentElement.classList.remove("no-room");
|
|
2392
2400
|
}
|
|
2393
2401
|
|
|
2394
2402
|
/** Build a minimal profile object from a live /api/agents record so
|
|
@@ -2474,6 +2482,12 @@
|
|
|
2474
2482
|
// notes empty-state through the agent view.
|
|
2475
2483
|
if (v.reports) v.reports.setAttribute("hidden", "");
|
|
2476
2484
|
if (v.notes) v.notes.setAttribute("hidden", "");
|
|
2485
|
+
// The floating sidebar-expand button is gated on `html.no-room`
|
|
2486
|
+
// — without setting it here, a user who collapses the sidebar
|
|
2487
|
+
// while on an agent profile loses the expand control and has to
|
|
2488
|
+
// navigate back to a room view to recover it. Same logic that
|
|
2489
|
+
// app.js applies in openAllReports / openAllNotes.
|
|
2490
|
+
document.documentElement.classList.add("no-room");
|
|
2477
2491
|
document.querySelectorAll("[data-notes-trigger].active").forEach((el) => el.classList.remove("active"));
|
|
2478
2492
|
document.querySelectorAll("[data-reports-trigger].active").forEach((el) => el.classList.remove("active"));
|
|
2479
2493
|
v.agent.removeAttribute("hidden");
|