@deskwork/studio 0.15.0 → 0.17.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.
- package/dist/components/scrapbook-item.d.ts +20 -0
- package/dist/components/scrapbook-item.d.ts.map +1 -1
- package/dist/components/scrapbook-item.js +21 -2
- package/dist/components/scrapbook-item.js.map +1 -1
- package/dist/lib/entry-resolver.d.ts +19 -6
- package/dist/lib/entry-resolver.d.ts.map +1 -1
- package/dist/lib/entry-resolver.js +40 -33
- package/dist/lib/entry-resolver.js.map +1 -1
- package/dist/pages/dashboard/affordances.d.ts.map +1 -1
- package/dist/pages/dashboard/affordances.js +13 -1
- package/dist/pages/dashboard/affordances.js.map +1 -1
- package/dist/pages/dashboard/affordances.ts +13 -1
- package/dist/pages/review-scrapbook-drawer.d.ts.map +1 -1
- package/dist/pages/review-scrapbook-drawer.js +10 -1
- package/dist/pages/review-scrapbook-drawer.js.map +1 -1
- package/dist/pages/review-scrapbook-drawer.ts +11 -1
- package/dist/pages/scrapbook/dispatch.d.ts +50 -0
- package/dist/pages/scrapbook/dispatch.d.ts.map +1 -0
- package/dist/pages/scrapbook/dispatch.js +104 -0
- package/dist/pages/scrapbook/dispatch.js.map +1 -0
- package/dist/pages/scrapbook/image-readers.d.ts +24 -0
- package/dist/pages/scrapbook/image-readers.d.ts.map +1 -0
- package/dist/pages/scrapbook/image-readers.js +135 -0
- package/dist/pages/scrapbook/image-readers.js.map +1 -0
- package/dist/pages/scrapbook/index.d.ts +21 -0
- package/dist/pages/scrapbook/index.d.ts.map +1 -0
- package/dist/pages/scrapbook/index.js +96 -0
- package/dist/pages/scrapbook/index.js.map +1 -0
- package/dist/pages/scrapbook/render.d.ts +68 -0
- package/dist/pages/scrapbook/render.d.ts.map +1 -0
- package/dist/pages/scrapbook/render.js +315 -0
- package/dist/pages/scrapbook/render.js.map +1 -0
- package/dist/pages/scrapbook/text-helpers.d.ts +40 -0
- package/dist/pages/scrapbook/text-helpers.d.ts.map +1 -0
- package/dist/pages/scrapbook/text-helpers.js +92 -0
- package/dist/pages/scrapbook/text-helpers.js.map +1 -0
- package/dist/pages/scrapbook/types.d.ts +26 -0
- package/dist/pages/scrapbook/types.d.ts.map +1 -0
- package/dist/pages/scrapbook/types.js +12 -0
- package/dist/pages/scrapbook/types.js.map +1 -0
- package/dist/pages/scrapbook.d.ts +8 -8
- package/dist/pages/scrapbook.d.ts.map +1 -1
- package/dist/pages/scrapbook.js +8 -600
- package/dist/pages/scrapbook.js.map +1 -1
- package/dist/pages/scrapbook.ts +11 -660
- package/dist/routes/api.d.ts.map +1 -1
- package/dist/routes/api.js +111 -2
- package/dist/routes/api.js.map +1 -1
- package/dist/routes/entry-annotation-body.d.ts +29 -0
- package/dist/routes/entry-annotation-body.d.ts.map +1 -1
- package/dist/routes/entry-annotation-body.js +80 -0
- package/dist/routes/entry-annotation-body.js.map +1 -1
- package/dist/routes/scrapbook-file.d.ts +1 -1
- package/dist/routes/scrapbook-file.js +1 -1
- package/dist/routes/scrapbook-mutation-dispatch.d.ts +29 -0
- package/dist/routes/scrapbook-mutation-dispatch.d.ts.map +1 -0
- package/dist/routes/scrapbook-mutation-dispatch.js +63 -0
- package/dist/routes/scrapbook-mutation-dispatch.js.map +1 -0
- package/dist/routes/scrapbook-mutation-envelope.d.ts +93 -0
- package/dist/routes/scrapbook-mutation-envelope.d.ts.map +1 -0
- package/dist/routes/scrapbook-mutation-envelope.js +147 -0
- package/dist/routes/scrapbook-mutation-envelope.js.map +1 -0
- package/dist/routes/scrapbook-mutations.d.ts +25 -7
- package/dist/routes/scrapbook-mutations.d.ts.map +1 -1
- package/dist/routes/scrapbook-mutations.js +67 -92
- package/dist/routes/scrapbook-mutations.js.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +16 -2
- package/dist/server.js.map +1 -1
- package/package.json +2 -2
- package/dist/pages/review.d.ts +0 -68
- package/dist/pages/review.d.ts.map +0 -1
- package/dist/pages/review.js +0 -561
- package/dist/pages/review.js.map +0 -1
- package/dist/pages/review.ts +0 -710
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scrapbook image-format readers — pure functions on Buffer headers.
|
|
3
|
+
*
|
|
4
|
+
* Recognizes PNG, JPEG, WebP, and GIF; returns null for unrecognized
|
|
5
|
+
* signatures or truncated/malformed buffers. Used by the scrapbook
|
|
6
|
+
* card meta to render `{W} × {H}` next to the image kind chip.
|
|
7
|
+
*
|
|
8
|
+
* Each format is parsed from its file-header structure (no external
|
|
9
|
+
* dependency); each branch returns null on any unexpected byte rather
|
|
10
|
+
* than throwing, so a corrupt image still renders with empty meta.
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Read width × height from a buffer. Recognizes PNG, JPEG, WebP, and
|
|
14
|
+
* GIF; returns null for unrecognized signatures or truncated/malformed
|
|
15
|
+
* buffers.
|
|
16
|
+
*/
|
|
17
|
+
export function readImageDimensions(buf) {
|
|
18
|
+
if (buf.length < 12)
|
|
19
|
+
return null;
|
|
20
|
+
// PNG: 89 50 4E 47 0D 0A 1A 0A then IHDR (chunk-length 4, "IHDR" 4,
|
|
21
|
+
// width 4, height 4 — width@16, height@20).
|
|
22
|
+
if (buf[0] === 0x89 && buf[1] === 0x50 && buf[2] === 0x4e && buf[3] === 0x47) {
|
|
23
|
+
if (buf.length < 24)
|
|
24
|
+
return null;
|
|
25
|
+
return { width: buf.readUInt32BE(16), height: buf.readUInt32BE(20) };
|
|
26
|
+
}
|
|
27
|
+
// GIF: "GIF87a" or "GIF89a" + logical screen descriptor (width LE @6,
|
|
28
|
+
// height LE @8).
|
|
29
|
+
if (buf[0] === 0x47 && buf[1] === 0x49 && buf[2] === 0x46 &&
|
|
30
|
+
buf[3] === 0x38 && (buf[4] === 0x37 || buf[4] === 0x39) && buf[5] === 0x61) {
|
|
31
|
+
if (buf.length < 10)
|
|
32
|
+
return null;
|
|
33
|
+
return { width: buf.readUInt16LE(6), height: buf.readUInt16LE(8) };
|
|
34
|
+
}
|
|
35
|
+
// JPEG: starts FF D8. Width/height live in a Start-Of-Frame marker
|
|
36
|
+
// (FF C0–CF, excluding DHT C4 / JPG C8 / DAC CC). Walk markers
|
|
37
|
+
// skipping their payloads until the SOF is found.
|
|
38
|
+
if (buf[0] === 0xff && buf[1] === 0xd8) {
|
|
39
|
+
return readJpegDimensions(buf);
|
|
40
|
+
}
|
|
41
|
+
// WebP: "RIFF" {size} "WEBP" then a chunk (VP8 / VP8L / VP8X).
|
|
42
|
+
if (buf[0] === 0x52 && buf[1] === 0x49 && buf[2] === 0x46 && buf[3] === 0x46 &&
|
|
43
|
+
buf[8] === 0x57 && buf[9] === 0x45 && buf[10] === 0x42 && buf[11] === 0x50) {
|
|
44
|
+
return readWebpDimensions(buf);
|
|
45
|
+
}
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
export function readJpegDimensions(buf) {
|
|
49
|
+
// Marker walk: skip FF D8 (SOI), then each marker is FF Xn followed
|
|
50
|
+
// by a 2-byte big-endian segment length (which includes its own 2
|
|
51
|
+
// bytes). The SOF segment's payload is: 1 byte precision, 2 bytes
|
|
52
|
+
// height, 2 bytes width (the rest is component info).
|
|
53
|
+
let i = 2;
|
|
54
|
+
while (i + 4 <= buf.length) {
|
|
55
|
+
if (buf[i] !== 0xff)
|
|
56
|
+
return null;
|
|
57
|
+
let marker = buf[i + 1] ?? 0;
|
|
58
|
+
// Skip fill bytes (0xff padding before the actual marker byte).
|
|
59
|
+
while (marker === 0xff && i + 2 < buf.length) {
|
|
60
|
+
i++;
|
|
61
|
+
marker = buf[i + 1] ?? 0;
|
|
62
|
+
}
|
|
63
|
+
i += 2;
|
|
64
|
+
// Standalone markers (no length): RST0–7 (D0–D7) and SOI/EOI/TEM.
|
|
65
|
+
if (marker === 0xd9 || marker === 0xd8 || marker === 0x01)
|
|
66
|
+
return null;
|
|
67
|
+
if (marker >= 0xd0 && marker <= 0xd7)
|
|
68
|
+
continue;
|
|
69
|
+
if (i + 2 > buf.length)
|
|
70
|
+
return null;
|
|
71
|
+
const segLen = buf.readUInt16BE(i);
|
|
72
|
+
// SOF markers carry the dimensions. Exclusions per JPEG spec:
|
|
73
|
+
// C4 (DHT — Huffman tables), C8 (JPG reserved), CC (DAC — arithmetic
|
|
74
|
+
// coding conditioning).
|
|
75
|
+
const isSof = marker >= 0xc0 && marker <= 0xcf &&
|
|
76
|
+
marker !== 0xc4 && marker !== 0xc8 && marker !== 0xcc;
|
|
77
|
+
if (isSof) {
|
|
78
|
+
if (i + 7 > buf.length)
|
|
79
|
+
return null;
|
|
80
|
+
return {
|
|
81
|
+
width: buf.readUInt16BE(i + 5),
|
|
82
|
+
height: buf.readUInt16BE(i + 3),
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
i += segLen;
|
|
86
|
+
}
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
export function readWebpDimensions(buf) {
|
|
90
|
+
// Three sub-formats (per RFC 6386 / VP8L spec / WebP container spec):
|
|
91
|
+
// - "VP8 " (lossy): header @20-22: signature 9D 01 2A, then
|
|
92
|
+
// 14-bit width LE @23, 14-bit height LE @25
|
|
93
|
+
// (each masked to 14 bits — top 2 bits are
|
|
94
|
+
// horizontal/vertical scale).
|
|
95
|
+
// - "VP8L" (lossless): header @20: signature 0x2F, then 32 bits
|
|
96
|
+
// packed: width-1 (14 bits) + height-1 (14
|
|
97
|
+
// bits) + alpha-flag + version (4 bits).
|
|
98
|
+
// - "VP8X" (extended): flags @20, reserved @21-23, width-1 (24
|
|
99
|
+
// bits LE) @24, height-1 (24 bits LE) @27.
|
|
100
|
+
// Need at least the RIFF header + chunk fourcc; per-variant length
|
|
101
|
+
// checks below cover the variant-specific payload sizes.
|
|
102
|
+
if (buf.length < 16)
|
|
103
|
+
return null;
|
|
104
|
+
const fourcc = buf.subarray(12, 16).toString('ascii');
|
|
105
|
+
if (fourcc === 'VP8 ') {
|
|
106
|
+
if (buf.length < 30)
|
|
107
|
+
return null;
|
|
108
|
+
if (buf[23] !== 0x9d || buf[24] !== 0x01 || buf[25] !== 0x2a)
|
|
109
|
+
return null;
|
|
110
|
+
const w = buf.readUInt16LE(26) & 0x3fff;
|
|
111
|
+
const h = buf.readUInt16LE(28) & 0x3fff;
|
|
112
|
+
return { width: w, height: h };
|
|
113
|
+
}
|
|
114
|
+
if (fourcc === 'VP8L') {
|
|
115
|
+
if (buf.length < 25)
|
|
116
|
+
return null;
|
|
117
|
+
if (buf[20] !== 0x2f)
|
|
118
|
+
return null;
|
|
119
|
+
// Read 4 bytes LE at offset 21, then unpack.
|
|
120
|
+
const packed = buf.readUInt32LE(21);
|
|
121
|
+
const widthMinus1 = packed & 0x3fff;
|
|
122
|
+
const heightMinus1 = (packed >>> 14) & 0x3fff;
|
|
123
|
+
return { width: widthMinus1 + 1, height: heightMinus1 + 1 };
|
|
124
|
+
}
|
|
125
|
+
if (fourcc === 'VP8X') {
|
|
126
|
+
if (buf.length < 30)
|
|
127
|
+
return null;
|
|
128
|
+
// 24-bit little-endian: low byte + (mid << 8) + (high << 16).
|
|
129
|
+
const w = ((buf[24] ?? 0) | ((buf[25] ?? 0) << 8) | ((buf[26] ?? 0) << 16)) + 1;
|
|
130
|
+
const h = ((buf[27] ?? 0) | ((buf[28] ?? 0) << 8) | ((buf[29] ?? 0) << 16)) + 1;
|
|
131
|
+
return { width: w, height: h };
|
|
132
|
+
}
|
|
133
|
+
return null;
|
|
134
|
+
}
|
|
135
|
+
//# sourceMappingURL=image-readers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"image-readers.js","sourceRoot":"","sources":["../../../src/pages/scrapbook/image-readers.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scrapbook viewer — `/dev/scrapbook/:site/<path>`.
|
|
3
|
+
*
|
|
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
|
+
*
|
|
9
|
+
* The implementation is split across this directory (one module per
|
|
10
|
+
* concern, each under the 500-line cap). This file is the orchestrator:
|
|
11
|
+
* dispatch listing, build the render context, compose the chrome.
|
|
12
|
+
*
|
|
13
|
+
* Mockup: docs/superpowers/frontend-design/2026-05-02-review-redesign/scrapbook-redesign.html
|
|
14
|
+
* Spec: docs/superpowers/specs/2026-05-02-scrapbook-redesign-impl-spec.md
|
|
15
|
+
*/
|
|
16
|
+
import type { StudioContext } from '../../routes/api.ts';
|
|
17
|
+
export { ScrapbookPageError } from './dispatch.ts';
|
|
18
|
+
export declare function renderScrapbookPage(ctx: StudioContext, site: string, path: string, opts?: {
|
|
19
|
+
entryId?: string;
|
|
20
|
+
}): Promise<string>;
|
|
21
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/pages/scrapbook/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAkBzD,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAEnD,wBAAsB,mBAAmB,CACvC,GAAG,EAAE,aAAa,EAClB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,IAAI,GAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAA;CAAO,GAC9B,OAAO,CAAC,MAAM,CAAC,CA+EjB"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scrapbook viewer — `/dev/scrapbook/:site/<path>`.
|
|
3
|
+
*
|
|
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
|
+
*
|
|
9
|
+
* The implementation is split across this directory (one module per
|
|
10
|
+
* concern, each under the 500-line cap). This file is the orchestrator:
|
|
11
|
+
* dispatch listing, build the render context, compose the chrome.
|
|
12
|
+
*
|
|
13
|
+
* Mockup: docs/superpowers/frontend-design/2026-05-02-review-redesign/scrapbook-redesign.html
|
|
14
|
+
* Spec: docs/superpowers/specs/2026-05-02-scrapbook-redesign-impl-spec.md
|
|
15
|
+
*/
|
|
16
|
+
import { html, unsafe } from "../html.js";
|
|
17
|
+
import { layout } from "../layout.js";
|
|
18
|
+
import { renderEditorialFolio } from "../chrome.js";
|
|
19
|
+
import { ScrapbookPageError, resolveListing } from "./dispatch.js";
|
|
20
|
+
import { countByKind, renderAside, renderBreadcrumb, renderCard, renderComposer, renderDropZone, renderFilterChips, renderSearch, renderSecretSection, } from "./render.js";
|
|
21
|
+
export { ScrapbookPageError } from "./dispatch.js";
|
|
22
|
+
export async function renderScrapbookPage(ctx, site, path, opts = {}) {
|
|
23
|
+
// Validate site against the project's configured site list. Without
|
|
24
|
+
// this check, an unknown site key reaches the path resolver and
|
|
25
|
+
// produces either an opaque error or a path traversal vector.
|
|
26
|
+
if (!(site in ctx.config.sites)) {
|
|
27
|
+
throw new ScrapbookPageError(`unknown site: ${site}`, 404);
|
|
28
|
+
}
|
|
29
|
+
const requestedEntryId = opts.entryId !== undefined && opts.entryId.length > 0 ? opts.entryId : null;
|
|
30
|
+
const { scrapbookDir, result, resolvedEntryId } = await resolveListing(ctx, site, path, requestedEntryId);
|
|
31
|
+
const items = result.items;
|
|
32
|
+
const secretItems = result.secretItems;
|
|
33
|
+
const totalSize = items.reduce((s, i) => s + i.size, 0);
|
|
34
|
+
const lastModified = items.reduce((acc, i) => {
|
|
35
|
+
if (!i.mtime)
|
|
36
|
+
return acc;
|
|
37
|
+
if (!acc || i.mtime > acc)
|
|
38
|
+
return i.mtime;
|
|
39
|
+
return acc;
|
|
40
|
+
}, null);
|
|
41
|
+
const counts = countByKind(items);
|
|
42
|
+
const folderLabel = path.split('/').filter(Boolean).pop() ?? path;
|
|
43
|
+
// Effective entryId for URL emission: prefer the request-supplied id
|
|
44
|
+
// (so the client's mutation requests round-trip through the same
|
|
45
|
+
// addressing mode) and fall back to the slug-mode lookup result.
|
|
46
|
+
const effectiveEntryId = requestedEntryId ?? resolvedEntryId;
|
|
47
|
+
const rctx = effectiveEntryId !== null
|
|
48
|
+
? { studio: ctx, site, path, entryId: effectiveEntryId, scrapbookDir }
|
|
49
|
+
: { studio: ctx, site, path, scrapbookDir };
|
|
50
|
+
const cards = items.map((item, i) => renderCard(rctx, item, i));
|
|
51
|
+
const cardsHtml = cards.map((c) => c.__raw).join('');
|
|
52
|
+
const reviewLink = effectiveEntryId !== null
|
|
53
|
+
? `/dev/editorial-review/entry/${effectiveEntryId}`
|
|
54
|
+
: null;
|
|
55
|
+
// The data-entry-id attribute is consumed by scrapbook-client.ts —
|
|
56
|
+
// when present, the client sends `entryId` on mutation requests so
|
|
57
|
+
// writes resolve via `scrapbookDirForEntry` (#191). Falls back to
|
|
58
|
+
// `data-path` slug-template addressing when absent.
|
|
59
|
+
// entryId comes from a UUID lookup — already validated against the
|
|
60
|
+
// calendar's CalendarEntry.id, so no escaping concern beyond the
|
|
61
|
+
// belt-and-braces unsafe wrapping for the conditional attribute.
|
|
62
|
+
const entryIdAttr = effectiveEntryId !== null
|
|
63
|
+
? unsafe(` data-entry-id="${effectiveEntryId}"`)
|
|
64
|
+
: unsafe('');
|
|
65
|
+
const body = html `
|
|
66
|
+
${renderEditorialFolio('content', `scrapbook · ${site}/${path}`)}
|
|
67
|
+
<main class="scrap-page" data-site="${site}" data-path="${path}"${entryIdAttr}>
|
|
68
|
+
${renderAside(site, path, items, totalSize, lastModified, secretItems.length, reviewLink)}
|
|
69
|
+
<section class="scrap-main">
|
|
70
|
+
<header class="scrap-main-header">
|
|
71
|
+
${renderBreadcrumb(site, path)}
|
|
72
|
+
${renderSearch()}
|
|
73
|
+
</header>
|
|
74
|
+
${renderFilterChips(counts)}
|
|
75
|
+
${renderComposer()}
|
|
76
|
+
<ol class="scrap-cards" id="cards" data-scrap-cards>
|
|
77
|
+
${unsafe(cardsHtml)}
|
|
78
|
+
</ol>
|
|
79
|
+
${renderDropZone()}
|
|
80
|
+
${renderSecretSection(rctx, secretItems)}
|
|
81
|
+
</section>
|
|
82
|
+
</main>`;
|
|
83
|
+
return layout({
|
|
84
|
+
title: `scrapbook · ${folderLabel} — dev`,
|
|
85
|
+
cssHrefs: [
|
|
86
|
+
'/static/css/editorial-review.css',
|
|
87
|
+
'/static/css/editorial-nav.css',
|
|
88
|
+
'/static/css/scrapbook.css',
|
|
89
|
+
'/static/css/blog-figure.css',
|
|
90
|
+
],
|
|
91
|
+
bodyAttrs: 'data-review-ui="scrapbook"',
|
|
92
|
+
bodyHtml: body,
|
|
93
|
+
scriptModules: ['scrapbook-client'],
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/pages/scrapbook/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scrapbook page render helpers — RawHtml emitters for cards, previews,
|
|
3
|
+
* the aside, the new-note composer, the drop zone, the secret section,
|
|
4
|
+
* and the breadcrumb / search / filter chrome.
|
|
5
|
+
*
|
|
6
|
+
* Reads filesystem only via `computeKindMeta` and `renderPreview`; both
|
|
7
|
+
* resolve through the pre-resolved `RenderCtx.scrapbookDir` (set by the
|
|
8
|
+
* dispatch step) so render stays free of path-resolution logic.
|
|
9
|
+
*/
|
|
10
|
+
import { type ScrapbookItem } from '@deskwork/core/scrapbook';
|
|
11
|
+
import { type RawHtml } from '../html.ts';
|
|
12
|
+
import type { RenderCtx } from './types.ts';
|
|
13
|
+
export interface KindCounts {
|
|
14
|
+
all: number;
|
|
15
|
+
md: number;
|
|
16
|
+
img: number;
|
|
17
|
+
json: number;
|
|
18
|
+
js: number;
|
|
19
|
+
txt: number;
|
|
20
|
+
other: number;
|
|
21
|
+
}
|
|
22
|
+
export declare function countByKind(items: readonly ScrapbookItem[]): KindCounts;
|
|
23
|
+
/**
|
|
24
|
+
* Compute the per-kind extra meta string shown after the kind chip + size:
|
|
25
|
+
* md / txt → "{N} lines"
|
|
26
|
+
* json → "{N} keys" (root must be a plain object; otherwise empty)
|
|
27
|
+
* img → "{W} × {H}" (PNG only; other formats → empty)
|
|
28
|
+
* other → empty
|
|
29
|
+
*
|
|
30
|
+
* ENOENT (race-window with delete) returns empty so the card still
|
|
31
|
+
* renders; other errors propagate to the page renderer.
|
|
32
|
+
*/
|
|
33
|
+
export declare function computeKindMeta(rctx: RenderCtx, item: ScrapbookItem, opts?: {
|
|
34
|
+
secret?: boolean;
|
|
35
|
+
}): string;
|
|
36
|
+
/**
|
|
37
|
+
* Server-side preview for the closed-state card. Img → bg-frame URL;
|
|
38
|
+
* md → italic Newsreader excerpt with frontmatter stripped; json → mono
|
|
39
|
+
* pre with parse-then-stringify pretty-print; txt → mono pre raw excerpt.
|
|
40
|
+
* Other / empty / binary-as-text → no preview block.
|
|
41
|
+
*/
|
|
42
|
+
export declare function renderPreview(rctx: RenderCtx, item: ScrapbookItem, opts?: {
|
|
43
|
+
secret?: boolean;
|
|
44
|
+
}): RawHtml;
|
|
45
|
+
export declare function renderFilterChips(counts: KindCounts): RawHtml;
|
|
46
|
+
export declare function renderSearch(): RawHtml;
|
|
47
|
+
export declare function renderBreadcrumb(site: string, path: string): RawHtml;
|
|
48
|
+
export declare function renderAside(site: string, path: string, items: readonly ScrapbookItem[], totalSize: number, lastModified: string | null, secretCount: number, reviewLink: string | null): RawHtml;
|
|
49
|
+
export declare function renderCard(rctx: RenderCtx, item: ScrapbookItem, index: number, opts?: {
|
|
50
|
+
secret?: boolean;
|
|
51
|
+
}): RawHtml;
|
|
52
|
+
/**
|
|
53
|
+
* Inline new-note composer (Phase 34b — #166).
|
|
54
|
+
*
|
|
55
|
+
* Mirrors the pre-F1 inline composer (`44094ee^:scrapbook.ts:274-294`),
|
|
56
|
+
* adapted to the F1 `.scrap-*` design vocabulary. Hidden by default;
|
|
57
|
+
* the aside's `+ new note` button reveals it via the client wire-up.
|
|
58
|
+
*
|
|
59
|
+
* Per `.claude/rules/affordance-placement.md`: component-attached to
|
|
60
|
+
* the page (not a generic toolbar), placed where the resulting note
|
|
61
|
+
* will appear in sorted position. Direct manipulation: in-page form,
|
|
62
|
+
* filename + body + secret toggle visible inline, Cmd/Ctrl+S saves,
|
|
63
|
+
* Esc cancels. Replaces the F1 `window.prompt()` regression (#166).
|
|
64
|
+
*/
|
|
65
|
+
export declare function renderComposer(): RawHtml;
|
|
66
|
+
export declare function renderDropZone(): RawHtml;
|
|
67
|
+
export declare function renderSecretSection(rctx: RenderCtx, secretItems: readonly ScrapbookItem[]): RawHtml;
|
|
68
|
+
//# sourceMappingURL=render.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../../../src/pages/scrapbook/render.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAIL,KAAK,aAAa,EAEnB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAgB,KAAK,OAAO,EAAE,MAAM,YAAY,CAAC;AAQxD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAW5C,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;CACf;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,SAAS,aAAa,EAAE,GAAG,UAAU,CAYvE;AAED;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,SAAS,EACf,IAAI,EAAE,aAAa,EACnB,IAAI,GAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAO,GAC9B,MAAM,CAwBR;AAsBD;;;;;GAKG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,SAAS,EACf,IAAI,EAAE,aAAa,EACnB,IAAI,GAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAO,GAC9B,OAAO,CAsCT;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAc7D;AAED,wBAAgB,YAAY,IAAI,OAAO,CAMtC;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAQpE;AAED,wBAAgB,WAAW,CACzB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,SAAS,aAAa,EAAE,EAC/B,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,GAAG,IAAI,EAC3B,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,GAAG,IAAI,GACxB,OAAO,CA2CT;AAED,wBAAgB,UAAU,CACxB,IAAI,EAAE,SAAS,EACf,IAAI,EAAE,aAAa,EACnB,KAAK,EAAE,MAAM,EACb,IAAI,GAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAO,GAC9B,OAAO,CAqDT;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,cAAc,IAAI,OAAO,CAmBxC;AAED,wBAAgB,cAAc,IAAI,OAAO,CAMxC;AAED,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,SAAS,EACf,WAAW,EAAE,SAAS,aAAa,EAAE,GACpC,OAAO,CAcT"}
|