@deskwork/studio 0.12.0 → 0.13.0

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.
Files changed (67) hide show
  1. package/dist/components/scrapbook-item.d.ts +9 -1
  2. package/dist/components/scrapbook-item.d.ts.map +1 -1
  3. package/dist/components/scrapbook-item.js +11 -2
  4. package/dist/components/scrapbook-item.js.map +1 -1
  5. package/dist/data/glossary.json +62 -0
  6. package/dist/lib/glossary-helper.d.ts +16 -0
  7. package/dist/lib/glossary-helper.d.ts.map +1 -0
  8. package/dist/lib/glossary-helper.js +26 -0
  9. package/dist/lib/glossary-helper.js.map +1 -0
  10. package/dist/lib/version.d.ts +10 -0
  11. package/dist/lib/version.d.ts.map +1 -0
  12. package/dist/lib/version.js +29 -0
  13. package/dist/lib/version.js.map +1 -0
  14. package/dist/pages/chrome.d.ts +24 -13
  15. package/dist/pages/chrome.d.ts.map +1 -1
  16. package/dist/pages/chrome.js +25 -24
  17. package/dist/pages/chrome.js.map +1 -1
  18. package/dist/pages/chrome.ts +38 -27
  19. package/dist/pages/content-detail.js +1 -1
  20. package/dist/pages/content-detail.js.map +1 -1
  21. package/dist/pages/content-detail.ts +1 -1
  22. package/dist/pages/content.d.ts.map +1 -1
  23. package/dist/pages/content.js +48 -0
  24. package/dist/pages/content.js.map +1 -1
  25. package/dist/pages/content.ts +51 -0
  26. package/dist/pages/dashboard/header.d.ts.map +1 -1
  27. package/dist/pages/dashboard/header.js +3 -0
  28. package/dist/pages/dashboard/header.js.map +1 -1
  29. package/dist/pages/dashboard/header.ts +3 -0
  30. package/dist/pages/dashboard/section.d.ts +6 -3
  31. package/dist/pages/dashboard/section.d.ts.map +1 -1
  32. package/dist/pages/dashboard/section.js +25 -12
  33. package/dist/pages/dashboard/section.js.map +1 -1
  34. package/dist/pages/dashboard/section.ts +26 -13
  35. package/dist/pages/entry-review.js +2 -2
  36. package/dist/pages/entry-review.js.map +1 -1
  37. package/dist/pages/entry-review.ts +2 -2
  38. package/dist/pages/html.d.ts +2 -0
  39. package/dist/pages/html.d.ts.map +1 -1
  40. package/dist/pages/html.js +2 -0
  41. package/dist/pages/html.js.map +1 -1
  42. package/dist/pages/html.ts +4 -0
  43. package/dist/pages/layout.d.ts.map +1 -1
  44. package/dist/pages/layout.js +6 -0
  45. package/dist/pages/layout.js.map +1 -1
  46. package/dist/pages/layout.ts +7 -0
  47. package/dist/pages/review-scrapbook-drawer.d.ts +7 -0
  48. package/dist/pages/review-scrapbook-drawer.d.ts.map +1 -1
  49. package/dist/pages/review-scrapbook-drawer.js +45 -6
  50. package/dist/pages/review-scrapbook-drawer.js.map +1 -1
  51. package/dist/pages/review-scrapbook-drawer.ts +50 -6
  52. package/dist/pages/review.d.ts.map +1 -1
  53. package/dist/pages/review.js +168 -41
  54. package/dist/pages/review.js.map +1 -1
  55. package/dist/pages/review.ts +192 -41
  56. package/dist/pages/scrapbook.d.ts +7 -14
  57. package/dist/pages/scrapbook.d.ts.map +1 -1
  58. package/dist/pages/scrapbook.js +352 -193
  59. package/dist/pages/scrapbook.js.map +1 -1
  60. package/dist/pages/scrapbook.ts +390 -222
  61. package/dist/pages/shortform.js +1 -1
  62. package/dist/pages/shortform.js.map +1 -1
  63. package/dist/pages/shortform.ts +1 -1
  64. package/dist/server.d.ts.map +1 -1
  65. package/dist/server.js +26 -13
  66. package/dist/server.js.map +1 -1
  67. package/package.json +4 -4
@@ -1,203 +1,352 @@
1
1
  /**
2
- * Scrapbook viewer — `/dev/scrapbook/:site/<path>` (path may include `/`).
2
+ * Scrapbook viewer — `/dev/scrapbook/:site/<path>`.
3
3
  *
4
- * Reads the scrapbook directory at the given path and lists every
5
- * file with type chips + relative timestamps, plus secret items
6
- * (inside `scrapbook/secret/`) in a quiet second section. Empty
7
- * scrapbooks render an empty state with quick-add affordances.
4
+ * Issue #161 redesign: aside-left folder card with numbered item list,
5
+ * vertical card grid with per-kind colored ribbons + always-visible foot
6
+ * toolbar + per-kind preview rendering, drop zone, secret section,
7
+ * single-expanded card invariant, aside cross-linking.
8
8
  *
9
- * The `path` argument is the hierarchical address of the scrapbook
10
- * any slash-separated kebab-case identifier under the site's
11
- * contentDir. It does not need to correspond to a calendar entry;
12
- * organizational nodes (e.g. `the-outbound/characters` with no
13
- * own README) can host their own scrapbooks too.
14
- *
15
- * Port of `pages/dev/scrapbook/[site]/[slug].astro`. Layout swap
16
- * (Astro `<Layout>` → studio shell) and CSS link added; structurally
17
- * similar otherwise.
9
+ * Mockup: docs/superpowers/frontend-design/2026-05-02-review-redesign/scrapbook-redesign.html
10
+ * Spec: docs/superpowers/specs/2026-05-02-scrapbook-redesign-impl-spec.md
18
11
  */
19
- import { formatRelativeTime, formatSize, listScrapbook, } from '@deskwork/core/scrapbook';
12
+ import { readFileSync } from 'node:fs';
13
+ import { formatRelativeTime, formatSize, listScrapbook, scrapbookFilePath, } from '@deskwork/core/scrapbook';
20
14
  import { html, unsafe } from "./html.js";
21
15
  import { layout } from "./layout.js";
22
16
  import { renderEditorialFolio } from "./chrome.js";
23
- function renderItemRow(item, index, opts = {}) {
24
- const { secret = false, withTools = true } = opts;
25
- const editBtn = withTools && item.kind === 'md'
26
- ? unsafe(html `<button type="button" class="scrapbook-tool" data-action="edit">edit</button>`)
27
- : '';
28
- const seq = String(index + 1).padStart(2, '0');
29
- const kindLabel = item.kind === 'other' ? '·' : item.kind.toUpperCase();
30
- const idPrefix = secret ? 'secret-' : '';
31
- const dataSecret = secret ? ' data-secret="true"' : '';
32
- // The "mark secret/public" toggle is the cross-section rename
33
- // affordance. The button label flips with the source section.
34
- const sectionToggleLabel = secret ? 'mark public' : 'mark secret';
35
- const toolbar = withTools
36
- ? unsafe(html `<div class="scrapbook-toolbar" data-toolbar>
37
- ${editBtn}
38
- <button type="button" class="scrapbook-tool" data-action="rename">rename</button>
39
- <button type="button" class="scrapbook-tool" data-action="toggle-secret">${sectionToggleLabel}</button>
40
- <button type="button" class="scrapbook-tool scrapbook-tool--delete" data-action="delete">delete</button>
41
- </div>`)
42
- : '';
43
- return unsafe(html `
44
- <li class="scrapbook-item${secret ? ' scrapbook-item--secret' : ''}" data-state="closed" data-open="false"
45
- data-filename="${item.name}" data-kind="${item.kind}"
46
- data-size="${item.size}" data-mtime="${item.mtime}"${unsafe(dataSecret)}
47
- id="${idPrefix}item-${encodeURIComponent(item.name)}">
48
- <button type="button" class="scrapbook-item-header" aria-expanded="false">
49
- <span class="scrapbook-seq" aria-hidden="true">§ ${seq}</span>
50
- <span class="scrapbook-kind scrapbook-kind--${item.kind}" aria-hidden="true">${kindLabel}</span>
51
- <span class="scrapbook-filename" data-filename-cell>${item.name}</span>
52
- <time class="scrapbook-mtime" datetime="${item.mtime}">${formatRelativeTime(item.mtime)}</time>
53
- <span class="scrapbook-disclosure" aria-hidden="true">▸</span>
54
- </button>
55
- ${toolbar}
56
- <div class="scrapbook-perforation" aria-hidden="true"></div>
57
- <div class="scrapbook-item-body" data-body>
58
- <div data-body-content></div>
59
- </div>
60
- </li>`);
17
+ const KIND_LABEL = {
18
+ md: 'MD',
19
+ img: 'IMG',
20
+ json: 'JSON',
21
+ js: 'JS',
22
+ txt: 'TXT',
23
+ other: '·',
24
+ };
25
+ function escapeHtml(s) {
26
+ return s
27
+ .replace(/&/g, '&amp;')
28
+ .replace(/</g, '&lt;')
29
+ .replace(/>/g, '&gt;')
30
+ .replace(/"/g, '&quot;')
31
+ .replace(/'/g, '&#39;');
61
32
  }
62
33
  /**
63
- * Build a hierarchical breadcrumb from the path. Each segment links to
64
- * the scrapbook view for its prefix. The root segment (site) just
65
- * goes back to the editorial dashboard.
34
+ * Strip a YAML frontmatter block from the top of an md file. Only strips
35
+ * the leading `---\n...\n---\n` block; body-level `---` separators (Setext
36
+ * H2 underline, thematic break) are preserved because the function only
37
+ * looks at the first 4 chars for the opener.
66
38
  */
67
- function renderBreadcrumb(site, path) {
68
- const segments = path.split('/');
69
- const links = [];
70
- for (let i = 0; i < segments.length; i++) {
71
- const prefix = segments.slice(0, i + 1).join('/');
72
- const isLast = i === segments.length - 1;
73
- if (isLast) {
74
- links.push(html `<span class="scrapbook-breadcrumb-current">${segments[i]}</span>`);
39
+ function stripFrontmatter(text) {
40
+ if (!text.startsWith('---\n'))
41
+ return text;
42
+ const closeIdx = text.indexOf('\n---\n', 4);
43
+ if (closeIdx < 0)
44
+ return text;
45
+ return text.slice(closeIdx + 5).replace(/^\n+/, '');
46
+ }
47
+ /**
48
+ * Build the closed-state preview excerpt for md/json/txt. Returns null
49
+ * when there's nothing useful to render — empty file, frontmatter-only
50
+ * file, or binary masquerading as text — so the caller can omit the
51
+ * preview block entirely (matches "other" kind treatment, avoids the
52
+ * 6rem min-height void).
53
+ *
54
+ * For json: pretty-print via JSON.parse + JSON.stringify(_, null, 2) so
55
+ * minified single-line files still render multi-line. Falls back to raw
56
+ * content on parse error (bad JSON is still readable as text).
57
+ *
58
+ * Binary detection: NUL byte presence after UTF-8 decode. Real text
59
+ * almost never has NUL; binary files have it within the first KB.
60
+ */
61
+ function previewExcerpt(buf, kind) {
62
+ let text = buf.subarray(0, Math.min(buf.byteLength, 2400)).toString('utf-8');
63
+ if (text.indexOf('\0') >= 0)
64
+ return null;
65
+ if (kind === 'md')
66
+ text = stripFrontmatter(text);
67
+ if (kind === 'json') {
68
+ try {
69
+ const fullText = buf.toString('utf-8');
70
+ text = JSON.stringify(JSON.parse(fullText), null, 2);
71
+ }
72
+ catch {
73
+ // Invalid JSON — fall through to the raw-text excerpt below.
74
+ }
75
+ }
76
+ const excerpt = text.split('\n').slice(0, 8).join('\n').slice(0, 600);
77
+ if (excerpt.trim() === '')
78
+ return null;
79
+ return excerpt;
80
+ }
81
+ /**
82
+ * Count lines in a text file: number of `\n` bytes plus 1 if the last
83
+ * byte isn't `\n` (so a 3-line file whether or not it has a trailing
84
+ * newline reports 3).
85
+ */
86
+ function countLines(buf) {
87
+ let count = 0;
88
+ for (const b of buf)
89
+ if (b === 0x0a)
90
+ count++;
91
+ if (buf.length > 0 && buf[buf.length - 1] !== 0x0a)
92
+ count++;
93
+ return count;
94
+ }
95
+ /**
96
+ * Count top-level keys in a JSON object. Returns null if the file is not
97
+ * valid JSON or its root is not a plain object (arrays, primitives →
98
+ * null; caller renders no extra meta).
99
+ */
100
+ function countJsonKeys(buf) {
101
+ try {
102
+ const obj = JSON.parse(buf.toString('utf-8'));
103
+ if (obj !== null && typeof obj === 'object' && !Array.isArray(obj)) {
104
+ return Object.keys(obj).length;
105
+ }
106
+ return null;
107
+ }
108
+ catch {
109
+ return null;
110
+ }
111
+ }
112
+ /**
113
+ * Read PNG dimensions from the IHDR chunk. Returns null for non-PNG or
114
+ * truncated files. JPEG/WebP/GIF support deferred — most deskwork
115
+ * scrapbook images are screenshots / icons (PNG) and the meta is purely
116
+ * informational, so the empty-string fallback is acceptable for other
117
+ * formats.
118
+ */
119
+ function readImageDimensions(buf) {
120
+ if (buf.length < 24)
121
+ return null;
122
+ if (buf[0] !== 0x89 || buf[1] !== 0x50 || buf[2] !== 0x4e || buf[3] !== 0x47)
123
+ return null;
124
+ return { width: buf.readUInt32BE(16), height: buf.readUInt32BE(20) };
125
+ }
126
+ /**
127
+ * Compute the per-kind extra meta string shown after the kind chip + size:
128
+ * md / txt → "{N} lines"
129
+ * json → "{N} keys" (root must be a plain object; otherwise empty)
130
+ * img → "{W} × {H}" (PNG only; other formats → empty)
131
+ * other → empty
132
+ *
133
+ * ENOENT (race-window with delete) returns empty so the card still
134
+ * renders; other errors propagate to the page renderer.
135
+ */
136
+ function computeKindMeta(ctx, site, path, item) {
137
+ if (item.kind !== 'md' && item.kind !== 'txt' && item.kind !== 'json' && item.kind !== 'img') {
138
+ return '';
139
+ }
140
+ let buf;
141
+ try {
142
+ const fullPath = scrapbookFilePath(ctx.projectRoot, ctx.config, site, path, item.name);
143
+ buf = readFileSync(fullPath);
144
+ }
145
+ catch (e) {
146
+ if (e instanceof Error && 'code' in e && e.code === 'ENOENT')
147
+ return '';
148
+ throw e;
149
+ }
150
+ if (item.kind === 'md' || item.kind === 'txt')
151
+ return `${countLines(buf)} lines`;
152
+ if (item.kind === 'json') {
153
+ const keys = countJsonKeys(buf);
154
+ return keys !== null ? `${keys} keys` : '';
155
+ }
156
+ // img
157
+ const dims = readImageDimensions(buf);
158
+ return dims ? `${dims.width} × ${dims.height}` : '';
159
+ }
160
+ /**
161
+ * Server-side preview for the closed-state card. Img → bg-frame URL;
162
+ * md → italic Newsreader excerpt with frontmatter stripped; json → mono
163
+ * pre with parse-then-stringify pretty-print; txt → mono pre raw excerpt.
164
+ * Other / empty / binary-as-text → no preview block.
165
+ */
166
+ function renderPreview(ctx, site, path, item, opts = {}) {
167
+ const { secret = false } = opts;
168
+ if (item.kind === 'img') {
169
+ const params = new URLSearchParams({ site, path, name: item.name });
170
+ if (secret)
171
+ params.set('secret', '1');
172
+ const url = `/api/dev/scrapbook-file?${params.toString()}`;
173
+ return unsafe(html `
174
+ <div class="scrap-preview scrap-preview--img" aria-hidden="true">
175
+ <div class="scrap-preview--img-frame" style="background-image: url(&quot;${url}&quot;);"></div>
176
+ </div>`);
177
+ }
178
+ if (item.kind !== 'md' && item.kind !== 'txt' && item.kind !== 'json') {
179
+ return unsafe('');
180
+ }
181
+ try {
182
+ const fullPath = scrapbookFilePath(ctx.projectRoot, ctx.config, site, path, item.name, secret ? { secret: true } : {});
183
+ const buf = readFileSync(fullPath);
184
+ const excerpt = previewExcerpt(buf, item.kind);
185
+ if (excerpt === null)
186
+ return unsafe('');
187
+ const safe = escapeHtml(excerpt);
188
+ if (item.kind === 'json' || item.kind === 'txt') {
189
+ return unsafe(html `
190
+ <pre class="scrap-preview scrap-preview--mono" aria-hidden="true">${unsafe(safe)}</pre>`);
75
191
  }
76
- else {
77
- links.push(html `<a class="scrapbook-breadcrumb-link" href="/dev/scrapbook/${site}/${prefix}">${segments[i]}</a>`);
192
+ return unsafe(html `
193
+ <div class="scrap-preview scrap-preview-md" aria-hidden="true"><p>${unsafe(safe)}</p></div>`);
194
+ }
195
+ catch (e) {
196
+ // ENOENT = file disappeared between listScrapbook and this read (race
197
+ // window with delete); rendering an empty preview is the right call.
198
+ // Anything else (EACCES, EISDIR, encoding bugs) propagates so the
199
+ // operator sees a real error instead of a silently-broken page.
200
+ if (e instanceof Error && 'code' in e && e.code === 'ENOENT') {
201
+ return unsafe('');
78
202
  }
203
+ throw e;
79
204
  }
80
- const sep = '<span class="scrapbook-breadcrumb-sep" aria-hidden="true">›</span>';
81
- const joined = links.join(`\n${sep}\n`);
205
+ }
206
+ function countByKind(items) {
207
+ const counts = {
208
+ all: items.length,
209
+ md: 0,
210
+ img: 0,
211
+ json: 0,
212
+ js: 0,
213
+ txt: 0,
214
+ other: 0,
215
+ };
216
+ for (const i of items)
217
+ counts[i.kind]++;
218
+ return counts;
219
+ }
220
+ function renderFilterChips(counts) {
221
+ const chip = (kind, label, isAll = false) => unsafe(html `
222
+ <button class="scrap-filter" type="button" data-filter="${kind}"
223
+ aria-pressed="${isAll ? 'true' : 'false'}">${label} · ${counts[kind]}</button>`);
224
+ return unsafe(html `
225
+ <div class="scrap-filters" role="toolbar" aria-label="filter by kind">
226
+ ${chip('all', 'all', true)}
227
+ ${chip('md', 'md')}
228
+ ${chip('img', 'img')}
229
+ ${chip('json', 'json')}
230
+ ${chip('txt', 'txt')}
231
+ ${chip('other', 'other')}
232
+ </div>`);
233
+ }
234
+ function renderSearch() {
82
235
  return unsafe(html `
83
- <nav class="scrapbook-breadcrumb" aria-label="scrapbook hierarchy">
84
- <a class="scrapbook-breadcrumb-link" href="/dev/editorial-studio">${site}</a>
85
- <span class="scrapbook-breadcrumb-sep" aria-hidden="true">›</span>
86
- ${unsafe(joined)}
236
+ <div class="scrap-search">
237
+ <input type="search" placeholder="filter by name or content" aria-label="filter scrapbook" data-scrap-search />
238
+ <span class="scrap-search-kbd">/</span>
239
+ </div>`);
240
+ }
241
+ function renderBreadcrumb(site, path) {
242
+ const segments = path.split('/').filter(Boolean);
243
+ const last = segments[segments.length - 1] ?? path;
244
+ return unsafe(html `
245
+ <nav class="scrap-breadcrumb" aria-label="hierarchy">
246
+ <a href="/dev/content/${site}">${site}</a><span class="sep">›</span>
247
+ <b>${last}</b>
87
248
  </nav>`);
88
249
  }
89
- function renderIndexSidebar(items, site, path) {
90
- const totalBytes = items.reduce((acc, item) => acc + item.size, 0);
91
- const lastModified = items.length > 0
92
- ? items.reduce((a, b) => (a.mtime > b.mtime ? a : b)).mtime
93
- : null;
250
+ function renderAside(site, path, items, totalSize, lastModified, secretCount) {
251
+ const lastModifiedLabel = lastModified ? formatRelativeTime(lastModified) : '—';
252
+ const publicCount = items.length;
253
+ const sizeLabel = formatSize(totalSize);
254
+ const folderLabel = path.split('/').filter(Boolean).pop() ?? path;
255
+ const fullPath = `${site}/${path}/scrapbook/`;
94
256
  return unsafe(html `
95
- <aside class="scrapbook-index">
96
- <p class="scrapbook-index-kicker">
97
- <span aria-hidden="true">§</span> The folder
257
+ <aside class="scrap-aside">
258
+ <p class="scrap-aside-kicker"><em>§</em> The folder</p>
259
+ <h1 class="scrap-aside-title">${folderLabel}</h1>
260
+ <p class="scrap-aside-meta">${site}</p>
261
+ <hr />
262
+ <p class="scrap-aside-totals">
263
+ <strong>${publicCount}</strong> public ·
264
+ <strong>${secretCount}</strong> secret ·
265
+ <em>${sizeLabel}</em>
98
266
  </p>
99
- <p class="scrapbook-index-meta">${path}</p>
100
- <p class="scrapbook-index-meta">${site}</p>
267
+ <p class="scrap-aside-meta">last modified ${lastModifiedLabel}</p>
101
268
  <hr />
102
- <ol class="scrapbook-index-list" data-scrapbook-index>
103
- ${items.map((item, i) => unsafe(html `<li data-index-for="${item.name}">
104
- <span class="scrapbook-index-num">No. ${String(i + 1).padStart(2, '0')}</span>
105
- <a href="#item-${encodeURIComponent(item.name)}">${item.name}</a>
106
- </li>`))}
269
+ <ol class="scrap-aside-list" data-scrap-aside-list>
270
+ ${items.map((item, i) => {
271
+ const seq = String(i + 1).padStart(2, '0');
272
+ return unsafe(html `<li><span class="num">${seq}</span><a href="#item-${i + 1}" data-scrap-aside-link>${item.name}</a></li>`);
273
+ })}
107
274
  </ol>
108
275
  <hr />
109
- <p class="scrapbook-index-totals">${items.length} ${items.length === 1 ? 'item' : 'items'} · ${formatSize(totalBytes)}</p>
110
- ${lastModified
111
- ? unsafe(html `<p class="scrapbook-index-subtotal">last modified ${formatRelativeTime(lastModified)}</p>`)
112
- : ''}
113
- <hr />
114
- <div class="scrapbook-index-actions">
115
- <button type="button" class="scrapbook-index-btn" data-action="new-note">+ new note</button>
116
- <button type="button" class="scrapbook-index-btn" data-action="upload">+ upload file</button>
276
+ <div class="scrap-aside-actions">
277
+ <button class="scrap-aside-btn scrap-aside-btn--primary" type="button" data-action="new-note">+ new note</button>
278
+ <button class="scrap-aside-btn" type="button" data-action="upload">+ upload file</button>
117
279
  </div>
118
280
  <hr />
119
- <p class="scrapbook-index-path">${site}/${path}/scrapbook/</p>
281
+ <p class="scrap-aside-path">${fullPath}</p>
120
282
  </aside>`);
121
283
  }
122
- function renderEmpty() {
284
+ function renderCard(ctx, site, path, item, index, opts = {}) {
285
+ const { secret = false } = opts;
286
+ const seq = String(index + 1).padStart(2, '0');
287
+ const kindLabel = KIND_LABEL[item.kind];
288
+ const kindClass = item.kind === 'other' ? '' : `scrap-kind--${item.kind}`;
289
+ const time = item.mtime
290
+ ? html `<time class="scrap-time" datetime="${item.mtime}">${formatRelativeTime(item.mtime)}</time>`
291
+ : '';
292
+ const preview = renderPreview(ctx, site, path, item, { secret });
293
+ const kindMeta = computeKindMeta(ctx, site, path, item);
294
+ const kindMetaHtml = kindMeta
295
+ ? unsafe(html `<span>·</span><span>${kindMeta}</span>`)
296
+ : unsafe('');
297
+ const editBtn = item.kind === 'img'
298
+ ? unsafe('')
299
+ : unsafe(html `<button class="scrap-tool" type="button" data-action="edit">edit</button>`);
300
+ // Secret cards get id="secret-item-N" to disambiguate from public ids in
301
+ // restoreFromHash + aside cross-link lookups (F4 contract); the
302
+ // mark-secret action toggle reads "mark public" since clicking it moves
303
+ // the card OUT of the secret section.
304
+ const id = secret ? `secret-item-${index + 1}` : `item-${index + 1}`;
305
+ const markSecretLabel = secret ? 'mark public' : 'mark secret';
306
+ const dataSecretAttr = secret ? ' data-secret="true"' : '';
123
307
  return unsafe(html `
124
- <section class="scrapbook-empty">
125
- <p>
126
- This scrapbook is empty. Write the first note, or drop a file
127
- anywhere on this page.
128
- </p>
129
- <div class="scrapbook-empty-actions">
130
- <button type="button" class="scrapbook-index-btn" data-action="new-note">+ new note</button>
131
- <button type="button" class="scrapbook-index-btn" data-action="upload">+ upload file</button>
308
+ <li class="scrap-card" data-kind="${item.kind}" data-state="closed" id="${id}"${unsafe(dataSecretAttr)}>
309
+ <div class="scrap-card-head">
310
+ <span class="scrap-seq">N° ${seq}</span>
311
+ <span class="scrap-name" data-action="open">${item.name}</span>
312
+ ${unsafe(time)}
132
313
  </div>
133
- </section>`);
314
+ <div class="scrap-card-meta">
315
+ <span class="scrap-kind ${kindClass}">${kindLabel}</span>
316
+ <span class="scrap-size">${formatSize(item.size)}</span>
317
+ ${kindMetaHtml}
318
+ </div>
319
+ ${preview}
320
+ <div class="scrap-card-foot">
321
+ <button class="scrap-tool scrap-tool--primary" type="button" data-action="open">open</button>
322
+ ${editBtn}
323
+ <button class="scrap-tool" type="button" data-action="rename">rename</button>
324
+ <button class="scrap-tool" type="button" data-action="mark-secret">${markSecretLabel}</button>
325
+ <span class="spacer"></span>
326
+ <button class="scrap-tool scrap-tool--delete" type="button" data-action="delete">delete</button>
327
+ </div>
328
+ </li>`);
134
329
  }
135
- function renderReadingPanel(items) {
330
+ function renderDropZone() {
136
331
  return unsafe(html `
137
- <section class="scrapbook-reading">
138
- <form class="scrapbook-composer" data-scrapbook-composer hidden>
139
- <div class="scrapbook-composer-header">
140
- <span class="scrapbook-composer-seq" aria-hidden="true">✎</span>
141
- <span class="scrapbook-composer-kind">NEW</span>
142
- <input type="text" class="scrapbook-composer-filename" data-composer-filename
143
- placeholder="note-name.md" aria-label="new note filename" />
144
- <div class="scrapbook-editor-footer scrapbook-composer-actions">
145
- <label class="scrapbook-secret-toggle" title="save under scrapbook/secret/ — never published">
146
- <input type="checkbox" data-composer-secret />
147
- <span>secret</span>
148
- </label>
149
- <button type="button" class="scrapbook-tool" data-action="composer-cancel">cancel</button>
150
- <button type="submit" class="scrapbook-tool scrapbook-tool--primary" data-action="composer-save">save →</button>
151
- </div>
152
- </div>
153
- <div class="scrapbook-composer-body">
154
- <textarea data-composer-body
155
- placeholder="Write the note in markdown. Cmd/Ctrl+S saves."
156
- aria-label="new note body"></textarea>
157
- </div>
158
- </form>
159
- <ol class="scrapbook-items" data-scrapbook-items>
160
- ${items.map((item, i) => renderItemRow(item, i))}
161
- </ol>
162
- <div class="scrapbook-drop" data-scrapbook-drop role="button" tabindex="0"
163
- aria-label="upload a file to the scrapbook">
164
- <span class="scrapbook-drop-label">── drop a file here, or pick one ──</span>
165
- <input type="file" data-scrapbook-file-input
166
- accept="image/*,application/json,text/plain,text/markdown,.md,.json,.txt" />
167
- <label class="scrapbook-secret-toggle scrapbook-secret-toggle--upload"
168
- title="save the upload under scrapbook/secret/ — never published">
169
- <input type="checkbox" data-upload-secret />
170
- <span>upload as secret</span>
171
- </label>
172
- </div>
173
- </section>`);
332
+ <div class="scrap-drop" role="button" tabindex="0" data-action="upload"
333
+ aria-label="Drop a file here, or press Enter to pick one">
334
+ ── drop a file here, or pick one ──
335
+ </div>`);
174
336
  }
175
- /**
176
- * Quiet second section listing items inside `scrapbook/secret/`. Read-
177
- * only in v1 — operators populate the directory by hand or via the
178
- * core API; the studio surface just shows what's there. The "private"
179
- * badge gives unmistakable visual differentiation from the public
180
- * items above.
181
- */
182
- function renderSecretSection(items) {
337
+ function renderSecretSection(ctx, site, path, secretItems) {
338
+ if (secretItems.length === 0)
339
+ return unsafe('');
340
+ const cards = secretItems.map((item, i) => renderCard(ctx, site, path, item, i, { secret: true }));
183
341
  return unsafe(html `
184
- <section class="scrapbook-secret" data-scrapbook-secret>
185
- <header class="scrapbook-secret-header">
186
- <span class="scrapbook-secret-mark" aria-hidden="true">⚿</span>
187
- <h2 class="scrapbook-secret-title">Secret</h2>
188
- <span class="scrapbook-secret-badge" aria-label="private — never published">
189
- private
190
- </span>
191
- <span class="scrapbook-secret-count">
192
- ${items.length} ${items.length === 1 ? 'item' : 'items'}
193
- </span>
342
+ <section class="scrap-secret" aria-label="secret items">
343
+ <header class="scrap-secret-head">
344
+ <span class="scrap-secret-mark" aria-hidden="true">⚿</span>
345
+ <h2 class="scrap-secret-title">Secret</h2>
346
+ <span class="scrap-secret-badge">private — never published</span>
194
347
  </header>
195
- <p class="scrapbook-secret-help">
196
- Items inside <code>scrapbook/secret/</code>. Excluded from the
197
- public site by the host's content-collection patterns.
198
- </p>
199
- <ol class="scrapbook-items scrapbook-items--secret">
200
- ${items.map((item, i) => renderItemRow(item, i, { secret: true, withTools: true }))}
348
+ <ol class="scrap-cards">
349
+ ${cards}
201
350
  </ol>
202
351
  </section>`);
203
352
  }
@@ -208,41 +357,51 @@ export function renderScrapbookPage(ctx, site, path) {
208
357
  if (!(site in ctx.config.sites)) {
209
358
  throw new Error(`unknown site: ${site}`);
210
359
  }
211
- const summary = listScrapbook(ctx.projectRoot, ctx.config, site, path);
212
- const items = summary.items;
213
- const secretItems = summary.secretItems;
214
- const publicBlock = items.length === 0
215
- ? renderEmpty().__raw
216
- : renderReadingPanel(items).__raw + renderIndexSidebar(items, site, path).__raw;
217
- const secretBlock = secretItems.length > 0 ? renderSecretSection(secretItems).__raw : '';
360
+ // listScrapbook returns { exists: false, items: [] } for missing dirs
361
+ // (packages/core/src/scrapbook.ts:337-339), so an empty scrapbook is not
362
+ // an error path. Real errors (slug validation, scrapbookDir resolution
363
+ // failures, FS permission issues) propagate to the studio's error handler.
364
+ const result = listScrapbook(ctx.projectRoot, ctx.config, site, path);
365
+ const items = result.items;
366
+ const secretItems = result.secretItems;
367
+ const totalSize = items.reduce((s, i) => s + i.size, 0);
368
+ const lastModified = items.reduce((acc, i) => {
369
+ if (!i.mtime)
370
+ return acc;
371
+ if (!acc || i.mtime > acc)
372
+ return i.mtime;
373
+ return acc;
374
+ }, null);
375
+ const counts = countByKind(items);
376
+ const folderLabel = path.split('/').filter(Boolean).pop() ?? path;
377
+ const cards = items.map((item, i) => renderCard(ctx, site, path, item, i));
378
+ const cardsHtml = cards.map((c) => c.__raw).join('');
218
379
  const body = html `
219
380
  ${renderEditorialFolio('content', `scrapbook · ${site}/${path}`)}
220
- <main class="scrapbook-page" data-site="${site}" data-slug="${path}" data-scrapbook-root>
221
- <header class="er-pagehead er-pagehead--compact scrapbook-header">
222
- ${renderBreadcrumb(site, path)}
223
- <p class="er-pagehead__kicker scrapbook-kicker">
224
- <span class="scrapbook-kicker-mark" aria-hidden="true">§</span>
225
- Scrapbook
226
- </p>
227
- <h1 class="er-pagehead__title scrapbook-title">${path}</h1>
228
- <a class="scrapbook-back" href="/dev/editorial-studio">← back to the desk</a>
229
- </header>
230
- <div class="scrapbook-status" data-scrapbook-status hidden></div>
231
- ${unsafe(publicBlock)}
232
- ${unsafe(secretBlock)}
233
- <div class="scrapbook-drop-overlay" data-scrapbook-overlay aria-hidden="true">
234
- <span class="scrapbook-drop-overlay-text">drop to add to the scrapbook ◇</span>
235
- </div>
381
+ <main class="scrap-page" data-site="${site}" data-path="${path}">
382
+ ${renderAside(site, path, items, totalSize, lastModified, secretItems.length)}
383
+ <section class="scrap-main">
384
+ <header class="scrap-main-header">
385
+ ${renderBreadcrumb(site, path)}
386
+ ${renderSearch()}
387
+ </header>
388
+ ${renderFilterChips(counts)}
389
+ <ol class="scrap-cards" id="cards" data-scrap-cards>
390
+ ${unsafe(cardsHtml)}
391
+ </ol>
392
+ ${renderDropZone()}
393
+ ${renderSecretSection(ctx, site, path, secretItems)}
394
+ </section>
236
395
  </main>`;
237
396
  return layout({
238
- title: `scrapbook · ${path} — dev`,
397
+ title: `scrapbook · ${folderLabel} — dev`,
239
398
  cssHrefs: [
240
399
  '/static/css/editorial-review.css',
241
400
  '/static/css/editorial-nav.css',
242
401
  '/static/css/scrapbook.css',
243
402
  '/static/css/blog-figure.css',
244
403
  ],
245
- bodyAttrs: 'data-review-ui="studio"',
404
+ bodyAttrs: 'data-review-ui="scrapbook"',
246
405
  bodyHtml: body,
247
406
  scriptModules: ['scrapbook-client'],
248
407
  });
@@ -1 +1 @@
1
- {"version":3,"file":"scrapbook.js","sourceRoot":"","sources":["../../src/pages/scrapbook.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"scrapbook.js","sourceRoot":"","sources":["../../src/pages/scrapbook.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EACL,kBAAkB,EAClB,UAAU,EACV,aAAa,EACb,iBAAiB,GAGlB,MAAM,0BAA0B,CAAC;AAElC,OAAO,EAAE,IAAI,EAAE,MAAM,EAAgB,MAAM,WAAW,CAAC;AACvD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAEnD,MAAM,UAAU,GAAsC;IACpD,EAAE,EAAE,IAAI;IACR,GAAG,EAAE,KAAK;IACV,IAAI,EAAE,MAAM;IACZ,EAAE,EAAE,IAAI;IACR,GAAG,EAAE,KAAK;IACV,KAAK,EAAE,GAAG;CACX,CAAC;AAEF,SAAS,UAAU,CAAC,CAAS;IAC3B,OAAO,CAAC;SACL,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC;SACtB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC;SACvB,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;AAC5B,CAAC;AAED;;;;;GAKG;AACH,SAAS,gBAAgB,CAAC,IAAY;IACpC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC;QAAE,OAAO,IAAI,CAAC;IAC3C,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;IAC5C,IAAI,QAAQ,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IAC9B,OAAO,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;AACtD,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,SAAS,cAAc,CAAC,GAAW,EAAE,IAA2B;IAC9D,IAAI,IAAI,GAAG,GAAG,CAAC,QAAQ,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IAC7E,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IACzC,IAAI,IAAI,KAAK,IAAI;QAAE,IAAI,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;IACjD,IAAI,IAAI,KAAK,MAAM,EAAE,CAAC;QACpB,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;YACvC,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;QACvD,CAAC;QAAC,MAAM,CAAC;YACP,6DAA6D;QAC/D,CAAC;IACH,CAAC;IACD,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IACtE,IAAI,OAAO,CAAC,IAAI,EAAE,KAAK,EAAE;QAAE,OAAO,IAAI,CAAC;IACvC,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;GAIG;AACH,SAAS,UAAU,CAAC,GAAW;IAC7B,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,KAAK,MAAM,CAAC,IAAI,GAAG;QAAE,IAAI,CAAC,KAAK,IAAI;YAAE,KAAK,EAAE,CAAC;IAC7C,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,KAAK,IAAI;QAAE,KAAK,EAAE,CAAC;IAC5D,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;GAIG;AACH,SAAS,aAAa,CAAC,GAAW;IAChC,IAAI,CAAC;QACH,MAAM,GAAG,GAAY,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;QACvD,IAAI,GAAG,KAAK,IAAI,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;YACnE,OAAO,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC;QACjC,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAID;;;;;;GAMG;AACH,SAAS,mBAAmB,CAAC,GAAW;IACtC,IAAI,GAAG,CAAC,MAAM,GAAG,EAAE;QAAE,OAAO,IAAI,CAAC;IACjC,IAAI,GAAG,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,GAAG,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,GAAG,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,GAAG,CAAC,CAAC,CAAC,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAC1F,OAAO,EAAE,KAAK,EAAE,GAAG,CAAC,YAAY,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,YAAY,CAAC,EAAE,CAAC,EAAE,CAAC;AACvE,CAAC;AAED;;;;;;;;;GASG;AACH,SAAS,eAAe,CACtB,GAAkB,EAClB,IAAY,EACZ,IAAY,EACZ,IAAmB;IAEnB,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI,IAAI,IAAI,CAAC,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM,IAAI,IAAI,CAAC,IAAI,KAAK,KAAK,EAAE,CAAC;QAC7F,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,IAAI,GAAW,CAAC;IAChB,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,iBAAiB,CAAC,GAAG,CAAC,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;QACvF,GAAG,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC;IAC/B,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,IAAI,CAAC,YAAY,KAAK,IAAI,MAAM,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,KAAK,QAAQ;YAAE,OAAO,EAAE,CAAC;QACxE,MAAM,CAAC,CAAC;IACV,CAAC;IACD,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI,IAAI,IAAI,CAAC,IAAI,KAAK,KAAK;QAAE,OAAO,GAAG,UAAU,CAAC,GAAG,CAAC,QAAQ,CAAC;IACjF,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;QACzB,MAAM,IAAI,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC;QAChC,OAAO,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;IAC7C,CAAC;IACD,MAAM;IACN,MAAM,IAAI,GAAG,mBAAmB,CAAC,GAAG,CAAC,CAAC;IACtC,OAAO,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,MAAM,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;AACtD,CAAC;AAED;;;;;GAKG;AACH,SAAS,aAAa,CACpB,GAAkB,EAClB,IAAY,EACZ,IAAY,EACZ,IAAmB,EACnB,OAA6B,EAAE;IAE/B,MAAM,EAAE,MAAM,GAAG,KAAK,EAAE,GAAG,IAAI,CAAC;IAChC,IAAI,IAAI,CAAC,IAAI,KAAK,KAAK,EAAE,CAAC;QACxB,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;QACpE,IAAI,MAAM;YAAE,MAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;QACtC,MAAM,GAAG,GAAG,2BAA2B,MAAM,CAAC,QAAQ,EAAE,EAAE,CAAC;QAC3D,OAAO,MAAM,CAAC,IAAI,CAAA;;mFAE6D,GAAG;aACzE,CAAC,CAAC;IACb,CAAC;IACD,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI,IAAI,IAAI,CAAC,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;QACtE,OAAO,MAAM,CAAC,EAAE,CAAC,CAAC;IACpB,CAAC;IACD,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,iBAAiB,CAChC,GAAG,CAAC,WAAW,EACf,GAAG,CAAC,MAAM,EACV,IAAI,EACJ,IAAI,EACJ,IAAI,CAAC,IAAI,EACT,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAC/B,CAAC;QACF,MAAM,GAAG,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC;QACnC,MAAM,OAAO,GAAG,cAAc,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/C,IAAI,OAAO,KAAK,IAAI;YAAE,OAAO,MAAM,CAAC,EAAE,CAAC,CAAC;QACxC,MAAM,IAAI,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC;QACjC,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM,IAAI,IAAI,CAAC,IAAI,KAAK,KAAK,EAAE,CAAC;YAChD,OAAO,MAAM,CAAC,IAAI,CAAA;4EACoD,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC9F,CAAC;QACD,OAAO,MAAM,CAAC,IAAI,CAAA;0EACoD,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IAClG,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,sEAAsE;QACtE,qEAAqE;QACrE,kEAAkE;QAClE,gEAAgE;QAChE,IAAI,CAAC,YAAY,KAAK,IAAI,MAAM,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YAC7D,OAAO,MAAM,CAAC,EAAE,CAAC,CAAC;QACpB,CAAC;QACD,MAAM,CAAC,CAAC;IACV,CAAC;AACH,CAAC;AAYD,SAAS,WAAW,CAAC,KAA+B;IAClD,MAAM,MAAM,GAAe;QACzB,GAAG,EAAE,KAAK,CAAC,MAAM;QACjB,EAAE,EAAE,CAAC;QACL,GAAG,EAAE,CAAC;QACN,IAAI,EAAE,CAAC;QACP,EAAE,EAAE,CAAC;QACL,GAAG,EAAE,CAAC;QACN,KAAK,EAAE,CAAC;KACT,CAAC;IACF,KAAK,MAAM,CAAC,IAAI,KAAK;QAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;IACxC,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,iBAAiB,CAAC,MAAkB;IAC3C,MAAM,IAAI,GAAG,CAAC,IAAsB,EAAE,KAAa,EAAE,KAAK,GAAG,KAAK,EAAW,EAAE,CAC7E,MAAM,CAAC,IAAI,CAAA;8DAC+C,IAAI;sBAC5C,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,KAAK,KAAK,MAAM,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IACrF,OAAO,MAAM,CAAC,IAAI,CAAA;;QAEZ,IAAI,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,CAAC;QACxB,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC;QAChB,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC;QAClB,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC;QACpB,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC;QAClB,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC;WACnB,CAAC,CAAC;AACb,CAAC;AAED,SAAS,YAAY;IACnB,OAAO,MAAM,CAAC,IAAI,CAAA;;;;WAIT,CAAC,CAAC;AACb,CAAC;AAED,SAAS,gBAAgB,CAAC,IAAY,EAAE,IAAY;IAClD,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IACjD,MAAM,IAAI,GAAG,QAAQ,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,IAAI,CAAC;IACnD,OAAO,MAAM,CAAC,IAAI,CAAA;;8BAEU,IAAI,KAAK,IAAI;WAChC,IAAI;WACJ,CAAC,CAAC;AACb,CAAC;AAED,SAAS,WAAW,CAClB,IAAY,EACZ,IAAY,EACZ,KAA+B,EAC/B,SAAiB,EACjB,YAA2B,EAC3B,WAAmB;IAEnB,MAAM,iBAAiB,GAAG,YAAY,CAAC,CAAC,CAAC,kBAAkB,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;IAChF,MAAM,WAAW,GAAG,KAAK,CAAC,MAAM,CAAC;IACjC,MAAM,SAAS,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC;IACxC,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,IAAI,IAAI,CAAC;IAClE,MAAM,QAAQ,GAAG,GAAG,IAAI,IAAI,IAAI,aAAa,CAAC;IAC9C,OAAO,MAAM,CAAC,IAAI,CAAA;;;sCAGkB,WAAW;oCACb,IAAI;;;kBAGtB,WAAW;kBACX,WAAW;cACf,SAAS;;kDAE2B,iBAAiB;;;UAGzD,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE;QACtB,MAAM,GAAG,GAAG,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;QAC3C,OAAO,MAAM,CAAC,IAAI,CAAA,yBAAyB,GAAG,yBAAyB,CAAC,GAAG,CAAC,2BAA2B,IAAI,CAAC,IAAI,WAAW,CAAC,CAAC;IAC/H,CAAC,CAAC;;;;;;;;oCAQ0B,QAAQ;aAC/B,CAAC,CAAC;AACf,CAAC;AAED,SAAS,UAAU,CACjB,GAAkB,EAClB,IAAY,EACZ,IAAY,EACZ,IAAmB,EACnB,KAAa,EACb,OAA6B,EAAE;IAE/B,MAAM,EAAE,MAAM,GAAG,KAAK,EAAE,GAAG,IAAI,CAAC;IAChC,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IAC/C,MAAM,SAAS,GAAG,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACxC,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,eAAe,IAAI,CAAC,IAAI,EAAE,CAAC;IAC1E,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK;QACrB,CAAC,CAAC,IAAI,CAAA,sCAAsC,IAAI,CAAC,KAAK,KAAK,kBAAkB,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS;QAClG,CAAC,CAAC,EAAE,CAAC;IACP,MAAM,OAAO,GAAG,aAAa,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;IACjE,MAAM,QAAQ,GAAG,eAAe,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;IACxD,MAAM,YAAY,GAAY,QAAQ;QACpC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAA,uBAAuB,QAAQ,SAAS,CAAC;QACtD,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IACf,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,KAAK,KAAK;QACjC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC;QACZ,CAAC,CAAC,MAAM,CAAC,IAAI,CAAA,2EAA2E,CAAC,CAAC;IAC5F,yEAAyE;IACzE,gEAAgE;IAChE,wEAAwE;IACxE,sCAAsC;IACtC,MAAM,EAAE,GAAG,MAAM,CAAC,CAAC,CAAC,eAAe,KAAK,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,GAAG,CAAC,EAAE,CAAC;IACrE,MAAM,eAAe,GAAG,MAAM,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,aAAa,CAAC;IAC/D,MAAM,cAAc,GAAG,MAAM,CAAC,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,EAAE,CAAC;IAC3D,OAAO,MAAM,CAAC,IAAI,CAAA;wCACoB,IAAI,CAAC,IAAI,6BAA6B,EAAE,IAAI,MAAM,CAAC,cAAc,CAAC;;qCAErE,GAAG;sDACc,IAAI,CAAC,IAAI;UACrD,MAAM,CAAC,IAAI,CAAC;;;kCAGY,SAAS,KAAK,SAAS;mCACtB,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC;UAC9C,YAAY;;QAEd,OAAO;;;UAGL,OAAO;;6EAE4D,eAAe;;;;UAIlF,CAAC,CAAC;AACZ,CAAC;AAED,SAAS,cAAc;IACrB,OAAO,MAAM,CAAC,IAAI,CAAA;;;;WAIT,CAAC,CAAC;AACb,CAAC;AAED,SAAS,mBAAmB,CAC1B,GAAkB,EAClB,IAAY,EACZ,IAAY,EACZ,WAAqC;IAErC,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,MAAM,CAAC,EAAE,CAAC,CAAC;IAChD,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IACnG,OAAO,MAAM,CAAC,IAAI,CAAA;;;;;;;;UAQV,KAAK;;eAEA,CAAC,CAAC;AACjB,CAAC;AAED,MAAM,UAAU,mBAAmB,CACjC,GAAkB,EAClB,IAAY,EACZ,IAAY;IAEZ,oEAAoE;IACpE,gEAAgE;IAChE,8DAA8D;IAC9D,IAAI,CAAC,CAAC,IAAI,IAAI,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;QAChC,MAAM,IAAI,KAAK,CAAC,iBAAiB,IAAI,EAAE,CAAC,CAAC;IAC3C,CAAC;IACD,sEAAsE;IACtE,yEAAyE;IACzE,uEAAuE;IACvE,2EAA2E;IAC3E,MAAM,MAAM,GAAG,aAAa,CAAC,GAAG,CAAC,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;IACtE,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC;IAC3B,MAAM,WAAW,GAAG,MAAM,CAAC,WAAW,CAAC;IACvC,MAAM,SAAS,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;IACxD,MAAM,YAAY,GAAG,KAAK,CAAC,MAAM,CAAgB,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE;QAC1D,IAAI,CAAC,CAAC,CAAC,KAAK;YAAE,OAAO,GAAG,CAAC;QACzB,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC,KAAK,GAAG,GAAG;YAAE,OAAO,CAAC,CAAC,KAAK,CAAC;QAC1C,OAAO,GAAG,CAAC;IACb,CAAC,EAAE,IAAI,CAAC,CAAC;IACT,MAAM,MAAM,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC;IAClC,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,IAAI,IAAI,CAAC;IAClE,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IAC3E,MAAM,SAAS,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACrD,MAAM,IAAI,GAAG,IAAI,CAAA;MACb,oBAAoB,CAAC,SAAS,EAAE,eAAe,IAAI,IAAI,IAAI,EAAE,CAAC;0CAC1B,IAAI,gBAAgB,IAAI;QAC1D,WAAW,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,WAAW,CAAC,MAAM,CAAC;;;YAGvE,gBAAgB,CAAC,IAAI,EAAE,IAAI,CAAC;YAC5B,YAAY,EAAE;;UAEhB,iBAAiB,CAAC,MAAM,CAAC;;YAEvB,MAAM,CAAC,SAAS,CAAC;;UAEnB,cAAc,EAAE;UAChB,mBAAmB,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,WAAW,CAAC;;YAE/C,CAAC;IACX,OAAO,MAAM,CAAC;QACZ,KAAK,EAAE,eAAe,WAAW,QAAQ;QACzC,QAAQ,EAAE;YACR,kCAAkC;YAClC,+BAA+B;YAC/B,2BAA2B;YAC3B,6BAA6B;SAC9B;QACD,SAAS,EAAE,4BAA4B;QACvC,QAAQ,EAAE,IAAI;QACd,aAAa,EAAE,CAAC,kBAAkB,CAAC;KACpC,CAAC,CAAC;AACL,CAAC"}