@wildwinter/app-shell 0.45.0 → 0.46.1
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/README.md +6 -8
- package/dist/{chunk-OHVWMLRM.js → chunk-CUFREPJ5.js} +4 -4
- package/dist/{chunk-OHVWMLRM.js.map → chunk-CUFREPJ5.js.map} +1 -1
- package/dist/{chunk-MS3BSTQB.js → chunk-J6RSONXM.js} +12 -19
- package/dist/chunk-J6RSONXM.js.map +1 -0
- package/dist/index.cjs +11 -18
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +2 -2
- package/dist/kit-gallery.cjs +10 -17
- package/dist/kit-gallery.cjs.map +1 -1
- package/dist/kit-gallery.css +14 -18
- package/dist/kit-gallery.css.map +1 -1
- package/dist/kit-gallery.d.cts +6 -8
- package/dist/kit-gallery.d.ts +6 -8
- package/dist/kit-gallery.js +1 -1
- package/dist/welcome.cjs +6 -12
- package/dist/welcome.cjs.map +1 -1
- package/dist/welcome.d.cts +2 -2
- package/dist/welcome.d.ts +2 -2
- package/dist/welcome.js +2 -2
- package/package.json +1 -1
- package/dist/chunk-MS3BSTQB.js.map +0 -1
package/README.md
CHANGED
|
@@ -163,7 +163,8 @@ openKitGallery({
|
|
|
163
163
|
sections: [
|
|
164
164
|
{ caption: "Start from a kit", items: [
|
|
165
165
|
{ id: "starter", name: "Starter project", blurb: "Two cards that already work together.",
|
|
166
|
-
play: "Press Play: one card opens the next.",
|
|
166
|
+
play: "Press Play: one card opens the next.", features: ["One box", "Playable at once"],
|
|
167
|
+
lands: ["One box", "Two cards"] },
|
|
167
168
|
] },
|
|
168
169
|
{ caption: "Learn from a finished project", action: "Open a Copy", usesDetails: false,
|
|
169
170
|
items: [{ id: "hamlet", name: "The Hamlet", blurb: "Small.", badge: "Start here" }] },
|
|
@@ -174,10 +175,6 @@ openKitGallery({
|
|
|
174
175
|
|
|
175
176
|
- **What a kit is made of stays in the app.** The shell knows names, words and
|
|
176
177
|
pictures, never boxes or scenes.
|
|
177
|
-
- **Pictures are masks.** `image` is a transparent file whose opaque pixels are
|
|
178
|
-
the ink, drawn in `--kit-art-ink` on `--kit-art-plate`. A dark theme sets a
|
|
179
|
-
paper-toned plate and a dark ink rather than inverting, which turns an
|
|
180
|
-
engraving into a photographic negative.
|
|
181
178
|
- Single click chooses, double-click chooses and goes, Enter in the name field
|
|
182
179
|
creates; the name is required when asked for.
|
|
183
180
|
- **v0.42: on the welcome too.** A welcome group with `tiles: true` draws its
|
|
@@ -191,9 +188,10 @@ openKitGallery({
|
|
|
191
188
|
- **v0.44:** `onChoose` runs whenever an item is chosen, so an app can show or
|
|
192
189
|
hide its own fields per kit; `validate` holds the pick until the app's own
|
|
193
190
|
field is filled, marking and focusing it the way an empty name is.
|
|
194
|
-
- **v0.
|
|
195
|
-
|
|
196
|
-
|
|
191
|
+
- **v0.46:** `features`, a kit's features as pills on its tile (the welcome's
|
|
192
|
+
too) and in the panel, replace both `shows` and pictures. Pictures were tried
|
|
193
|
+
in 0.41 to 0.45 and ruled out by the author; `image` and the `--kit-art-*`
|
|
194
|
+
tokens are gone.
|
|
197
195
|
|
|
198
196
|
## Roadmap
|
|
199
197
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { kitTile } from './chunk-
|
|
1
|
+
import { kitTile } from './chunk-J6RSONXM.js';
|
|
2
2
|
import { el } from './chunk-UG2P777F.js';
|
|
3
3
|
|
|
4
4
|
// src/welcome.ts
|
|
@@ -18,7 +18,7 @@ function mountWelcome(host, opts) {
|
|
|
18
18
|
name: item.name,
|
|
19
19
|
blurb: item.hint ?? "",
|
|
20
20
|
...item.badge !== void 0 ? { badge: item.badge } : {},
|
|
21
|
-
...item.
|
|
21
|
+
...item.features !== void 0 ? { features: item.features } : {}
|
|
22
22
|
}, item.onOpen))) : el("div", "welcome-list", ...g.items.map((item) => {
|
|
23
23
|
const b = el(
|
|
24
24
|
"button",
|
|
@@ -72,5 +72,5 @@ function mountWelcome(host, opts) {
|
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
export { mountWelcome };
|
|
75
|
-
//# sourceMappingURL=chunk-
|
|
76
|
-
//# sourceMappingURL=chunk-
|
|
75
|
+
//# sourceMappingURL=chunk-CUFREPJ5.js.map
|
|
76
|
+
//# sourceMappingURL=chunk-CUFREPJ5.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/welcome.ts"],"names":[],"mappings":";;;;AAmFO,SAAS,YAAA,CAAa,MAAmB,IAAA,EAA+B;AAC7E,EAAA,MAAM,UAAU,CAAC,IAAA,KAA8B,EAAA,CAAG,IAAA,EAAM,mBAAmB,IAAI,CAAA;AAC/E,EAAA,MAAM,KAAA,GAAQ,CAAC,KAAA,EAAA,GAAkB,IAAA,KAC/B,EAAA,CAAG,SAAA,EAAW,eAAA,EAAiB,OAAA,CAAQ,KAAK,CAAA,EAAG,GAAG,IAAI,CAAA;AAExD,EAAA,MAAM,OAAA,GAAU,EAAA,CAAG,KAAA,EAAO,iBAAiB,CAAA;AAC3C,EAAA,KAAA,MAAW,CAAA,IAAK,KAAK,OAAA,EAAS;AAC5B,IAAA,MAAM,IAAI,EAAA,CAAG,QAAA,EAAU,EAAE,SAAA,EAAW,MAAM,CAAA,CAAE,OAAA,GAAU,UAAA,GAAa,EAAE,IAAI,IAAA,EAAM,CAAA,CAAE,OAAO,OAAA,EAAS,CAAA,CAAE,SAAS,CAAA;AAC5G,IAAA,CAAA,CAAE,IAAA,GAAO,QAAA;AACT,IAAA,OAAA,CAAQ,OAAO,CAAC,CAAA;AAAA,EAClB;AAEA,EAAA,MAAM,UAAU,IAAA,CAAK,MAAA,IAAU,EAAC,EAAG,GAAA,CAAI,CAAC,CAAA,KAAM,KAAA;AAAA,IAAM,CAAA,CAAE,OAAA;AAAA,IACpD,CAAA,CAAE,SAAS,MAAA,GAAY,EAAA,CAAG,KAAK,cAAA,EAAgB,CAAA,CAAE,IAAI,CAAA,GAAI,IAAA;AAAA,IACzD,CAAA,CAAE,KAAA,GACE,EAAA,CAAG,KAAA,EAAO,gCAAA,EAAkC,GAAG,CAAA,CAAE,KAAA,CAAM,GAAA,CAAI,CAAC,IAAA,KAAS,OAAA,CAAQ;AAAA,MAC7E,MAAM,IAAA,CAAK,IAAA;AAAA,MAAM,KAAA,EAAO,KAAK,IAAA,IAAQ,EAAA;AAAA,MACrC,GAAI,KAAK,KAAA,KAAU,MAAA,GAAY,EAAE,KAAA,EAAO,IAAA,CAAK,KAAA,EAAM,GAAI,EAAC;AAAA,MACxD,GAAI,KAAK,
|
|
1
|
+
{"version":3,"sources":["../src/welcome.ts"],"names":[],"mappings":"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","file":"chunk-CUFREPJ5.js","sourcesContent":["// ---------------------------------------------------------------------------\n// The welcome screen: what an app shows with no project open. Title, one line\n// under it, the actions (Open, New), an optional teaching line, optional\n// captioned groups (Storyletter's shipped examples), and the recents.\n//\n// Both apps drew this with the same twelve CSS rules under two class prefixes\n// (`.recent-name` / `.wel-recent-name`), four of them byte-identical. The CSS\n// here is Patterpad's; the captioned groups are Storyletter's, as an optional\n// slot, drawn as a plain list of rows (name + hint) rather than cards.\n//\n// The whole screen is a drag region (the window has no title bar to grab\n// here) and every control opts out. Styles ship as welcome.css.\n// ---------------------------------------------------------------------------\n\nimport { el } from \"./dom.js\";\nimport { kitTile } from \"./kit-gallery.js\";\n\nexport interface WelcomeAction {\n label: string;\n onClick: () => void;\n /** The one accent button (Open a project…). */\n primary?: boolean;\n}\n\nexport interface WelcomeRecent {\n /** What the project calls itself, with the folder stem as the fallback. */\n name: string;\n /** Beside the name, because two projects may share a name and the folder\n * is how you tell them apart. */\n path: string;\n onOpen: () => void;\n}\n\nexport interface WelcomeGroupItem {\n name: string;\n /** What choosing it gets you, said before the click. */\n hint?: string;\n /** Tiled groups only: a word or two beside the name (\"Start here\"). */\n badge?: string;\n /** Tiled groups only: the kit's feature pills, as the gallery draws them. */\n features?: string[];\n onOpen: () => void;\n}\n\nexport interface WelcomeGroup {\n /** Sentence-case label text (\"Learn from a finished project\"); never an overline. */\n caption: string;\n /** The consequence of a click, said before the click (\"Each opens as your\n * own copy, in a folder you choose.\"). */\n note?: string;\n items: WelcomeGroupItem[];\n /** Draw the items as the kit gallery's tiles rather than rows (the kit\n * gallery brief, section 6: the welcome shows the kits and the examples as\n * the gallery shows them). Needs kit-gallery.css beside welcome.css. */\n tiles?: boolean;\n}\n\nexport interface WelcomeOptions {\n title: string;\n sub: string;\n actions: WelcomeAction[];\n recents: WelcomeRecent[];\n groups?: WelcomeGroup[];\n /** The teaching door: a line under the actions, quieter than a button\n * (\"New to Patter? Take the interactive tour\"). The app builds and styles\n * it; a text action in it is a link, not bare muted text. */\n tourLine?: HTMLElement;\n /** The recents caption. Default \"Recent\". */\n recentsCaption?: string;\n /** How many recents to show. Default 5. */\n maxRecents?: number;\n /** A sentence about why the last open failed, under everything. */\n error?: string;\n}\n\nexport interface Welcome {\n el: HTMLElement;\n /** Redraw the recents (the list changes as projects open and close). */\n setRecents(recents: WelcomeRecent[]): void;\n setError(error: string | undefined): void;\n}\n\n/** Mount the welcome into `host` (replacing its children). */\nexport function mountWelcome(host: HTMLElement, opts: WelcomeOptions): Welcome {\n const caption = (text: string): HTMLElement => el(\"h2\", \"welcome-caption\", text);\n const group = (label: string, ...body: (Node | null)[]): HTMLElement =>\n el(\"section\", \"welcome-group\", caption(label), ...body);\n\n const actions = el(\"div\", \"welcome-actions\");\n for (const a of opts.actions) {\n const b = el(\"button\", { className: `btn${a.primary ? \" primary\" : \"\"}`, text: a.label, onClick: a.onClick });\n b.type = \"button\";\n actions.append(b);\n }\n\n const groups = (opts.groups ?? []).map((g) => group(g.caption,\n g.note !== undefined ? el(\"p\", \"welcome-note\", g.note) : null,\n g.tiles\n ? el(\"div\", \"kit-gallery-grid welcome-tiles\", ...g.items.map((item) => kitTile({\n name: item.name, blurb: item.hint ?? \"\",\n ...(item.badge !== undefined ? { badge: item.badge } : {}),\n ...(item.features !== undefined ? { features: item.features } : {}),\n }, item.onOpen)))\n : el(\"div\", \"welcome-list\", ...g.items.map((item) => {\n const b = el(\"button\", { className: \"welcome-item\", onClick: item.onOpen },\n el(\"span\", \"welcome-item-name\", item.name),\n item.hint !== undefined ? el(\"span\", \"welcome-item-hint\", item.hint) : null);\n b.type = \"button\";\n return b;\n })),\n ));\n\n const recentsHost = el(\"div\", \"welcome-recents-slot\");\n const drawRecents = (recents: WelcomeRecent[]): void => {\n const shown = recents.slice(0, opts.maxRecents ?? 5);\n recentsHost.replaceChildren();\n if (shown.length === 0) return;\n recentsHost.append(group(opts.recentsCaption ?? \"Recent\",\n el(\"div\", \"welcome-recents\", ...shown.map((r) => {\n const b = el(\"button\", { className: \"welcome-recent\", onClick: r.onOpen },\n el(\"span\", \"welcome-recent-name\", r.name),\n el(\"span\", \"welcome-recent-path\", r.path));\n b.type = \"button\";\n return b;\n })),\n ));\n };\n drawRecents(opts.recents);\n\n const error = el(\"p\", \"welcome-error\");\n const setError = (text: string | undefined): void => {\n error.textContent = text ?? \"\";\n error.hidden = text === undefined || text === \"\";\n };\n setError(opts.error);\n\n const root = el(\"div\", \"welcome\", el(\"div\", \"welcome-card\",\n el(\"h1\", \"welcome-title\", opts.title),\n el(\"p\", \"welcome-sub\", opts.sub),\n actions,\n opts.tourLine ? el(\"div\", \"welcome-line\", opts.tourLine) : null,\n ...groups,\n recentsHost,\n error,\n ));\n host.replaceChildren(root);\n return { el: root, setRecents: drawRecents, setError };\n}\n"]}
|
|
@@ -2,28 +2,22 @@ import { dialogFrame } from './chunk-YRFJLJUH.js';
|
|
|
2
2
|
import { el } from './chunk-UG2P777F.js';
|
|
3
3
|
|
|
4
4
|
// src/kit-gallery.ts
|
|
5
|
-
function
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
if (image === void 0) return;
|
|
9
|
-
const ink = el("span", "kit-gallery-ink");
|
|
10
|
-
ink.style.setProperty("--kit-art", `url("${image.replace(/"/g, "%22")}")`);
|
|
11
|
-
host.append(ink);
|
|
5
|
+
function featurePills(features) {
|
|
6
|
+
if (!features || features.length === 0) return null;
|
|
7
|
+
return el("span", "kit-gallery-features", ...features.map((f) => el("span", "kit-gallery-feature", f)));
|
|
12
8
|
}
|
|
13
9
|
function kitTile(item, onClick) {
|
|
14
|
-
const art = el("div", "kit-gallery-art");
|
|
15
|
-
setArt(art, item.image);
|
|
16
10
|
const tile = el(
|
|
17
11
|
"button",
|
|
18
12
|
{ className: "kit-gallery-tile", onClick },
|
|
19
|
-
art,
|
|
20
13
|
el(
|
|
21
14
|
"span",
|
|
22
15
|
"kit-gallery-tile-head",
|
|
23
16
|
el("span", "kit-gallery-tile-name", item.name),
|
|
24
17
|
item.badge !== void 0 ? el("span", "kit-gallery-badge", item.badge) : null
|
|
25
18
|
),
|
|
26
|
-
el("span", "kit-gallery-tile-blurb", item.blurb)
|
|
19
|
+
el("span", "kit-gallery-tile-blurb", item.blurb),
|
|
20
|
+
featurePills(item.features)
|
|
27
21
|
);
|
|
28
22
|
tile.type = "button";
|
|
29
23
|
return tile;
|
|
@@ -45,24 +39,22 @@ function openKitGallery(opts) {
|
|
|
45
39
|
...nameInput ? [el("label", "kit-gallery-label", opts.nameLabel ?? "Name"), nameInput] : [],
|
|
46
40
|
...opts.details ? [opts.details] : []
|
|
47
41
|
);
|
|
48
|
-
const panelArt = el("div", "kit-gallery-art kit-gallery-panel-art");
|
|
49
42
|
const panelName = el("h3", "kit-gallery-panel-name");
|
|
50
43
|
const panelBlurb = el("p", "kit-gallery-panel-blurb");
|
|
51
44
|
const panelDetail = el("p", "kit-gallery-panel-detail");
|
|
52
45
|
const panelPlay = el("p", "kit-gallery-play");
|
|
53
|
-
const
|
|
46
|
+
const panelFeatures = el("div", "kit-gallery-panel-features");
|
|
54
47
|
const panelLands = el("ul", "kit-gallery-lands");
|
|
55
48
|
const panelLandsCaption = el("p", "kit-gallery-lands-caption", "What you get");
|
|
56
49
|
const panelNote = el("p", "kit-gallery-note");
|
|
57
50
|
const panel = el(
|
|
58
51
|
"div",
|
|
59
52
|
"kit-gallery-panel",
|
|
60
|
-
panelArt,
|
|
61
53
|
panelName,
|
|
54
|
+
panelFeatures,
|
|
62
55
|
panelBlurb,
|
|
63
56
|
panelDetail,
|
|
64
57
|
panelPlay,
|
|
65
|
-
panelShows,
|
|
66
58
|
panelLandsCaption,
|
|
67
59
|
panelLands,
|
|
68
60
|
panelNote,
|
|
@@ -102,12 +94,13 @@ function openKitGallery(opts) {
|
|
|
102
94
|
chosen = next;
|
|
103
95
|
for (const [tid, tile] of tiles) tile.setAttribute("aria-pressed", String(tid === id));
|
|
104
96
|
const { item, section } = chosen;
|
|
105
|
-
setArt(panelArt, item.image);
|
|
106
97
|
panelName.textContent = item.name;
|
|
107
98
|
setText(panelBlurb, item.blurb);
|
|
108
99
|
setText(panelDetail, item.detail);
|
|
109
100
|
setText(panelPlay, item.play);
|
|
110
|
-
|
|
101
|
+
const pills = featurePills(item.features);
|
|
102
|
+
panelFeatures.replaceChildren(...pills ? [pills] : []);
|
|
103
|
+
panelFeatures.hidden = pills === null;
|
|
111
104
|
panelLands.replaceChildren(...(item.lands ?? []).map((l) => el("li", void 0, l)));
|
|
112
105
|
panelLands.hidden = (item.lands ?? []).length === 0;
|
|
113
106
|
panelLandsCaption.hidden = panelLands.hidden;
|
|
@@ -165,5 +158,5 @@ function openKitGallery(opts) {
|
|
|
165
158
|
}
|
|
166
159
|
|
|
167
160
|
export { kitTile, openKitGallery };
|
|
168
|
-
//# sourceMappingURL=chunk-
|
|
169
|
-
//# sourceMappingURL=chunk-
|
|
161
|
+
//# sourceMappingURL=chunk-J6RSONXM.js.map
|
|
162
|
+
//# sourceMappingURL=chunk-J6RSONXM.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/kit-gallery.ts"],"names":[],"mappings":"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","file":"chunk-J6RSONXM.js","sourcesContent":["// ---------------------------------------------------------------------------\n// The kit gallery: pick a starting point by what you want to make.\n//\n// The new-thing moment for the family (New Project, New Box, New Scene), drawn\n// once. Adobe's New Document is the shape: tiles on the left, a details panel\n// on the right, one screen. Not a wizard: a wizard asks for settings before\n// anything has been chosen, and the choice is the part that teaches.\n//\n// Storyletter grew this as `kit-picker.ts` (one component at two scales on\n// <dialog>, \"a shell candidate, held back until it had been used in earnest\")\n// and the kit gallery brief moved it here, 2026-09-27\n// (storylet-studio/design/kit-gallery.md). What a kit IS made of stays in\n// each app: this file knows names, words and pictures, never boxes or scenes.\n//\n// Sections are shelves (\"Start from a kit\", \"Learn from a finished project\"),\n// and each says what its button does, because opening a copy of an example\n// and creating from a kit are different acts behind the same kind of tile.\n// The app's own fields (a project name, version control, a build path) sit in\n// the details panel, shown only for the sections that use them.\n// ---------------------------------------------------------------------------\n\nimport { el } from \"./dom.js\";\nimport { dialogFrame } from \"./dialog.js\";\n\nexport interface KitGalleryItem<T extends string> {\n id: T;\n /** What you are making, in the author's terms, not the model's. */\n name: string;\n /** What it is FOR: the panel's first line, and the tile's unless `tile` says otherwise. */\n blurb: string;\n /** The tile's line, when the blurb is longer than a tile holds (three\n * lines). A whole short sentence reads better than a long one cut off. */\n tile?: string;\n /** More, for the panel only. */\n detail?: string;\n /** What pressing Play (or Run) shows, said as a promise. */\n play?: string;\n /** What it has, in a word or two each (\"Drawn map\", \"Copies\"): pills on the tile and in the\n * panel, so kits compare at a glance before any is chosen. The author's ask, 2026-09-27, in\n * place of pictures, which were ruled out the same day. */\n features?: string[];\n /** What lands, in the concrete, as a short list in the panel. */\n lands?: string[];\n /** A word or two on the tile (\"Start here\"). */\n badge?: string;\n}\n\nexport interface KitGallerySection<T extends string> {\n /** Sentence-case label text (\"Start from a kit\"). Absent: no caption. */\n caption?: string;\n /** The consequence of a click, said before the click. */\n note?: string;\n items: KitGalleryItem<T>[];\n /** The primary button's label while an item here is chosen. Default \"Create\". */\n action?: string;\n /** Show the app's detail fields (and ask for the name) for this section.\n * Default true. An example is opened, not named, so its shelf says false. */\n usesDetails?: boolean;\n}\n\nexport interface KitGalleryChoice {\n /** Present when a name was asked for and the chosen section uses details. */\n name?: string;\n}\n\nexport interface KitGalleryOptions<T extends string> {\n /** The dialog's heading: \"New project\", \"New box\", \"New scene\". */\n title: string;\n /** What the thing being made IS, in concrete terms. */\n what?: string;\n sections: KitGallerySection<T>[];\n /** Ask for a name in the details panel, with this placeholder. Required\n * when asked: making a thing without one would have to invent a folder. */\n namePlaceholder?: string;\n /** The name field's label. Default \"Name\". */\n nameLabel?: string;\n /** The app's own fields, below the name (version control, a build path). */\n details?: HTMLElement;\n /** Runs whenever an item is chosen, the opening one included, so the app can show or hide its\n * own fields for it (New Scene's Speaker, for a kit with lines). */\n onChoose?: (id: T) => void;\n /** Checked before `onPick`, after the name: return the app's field that still needs filling (it\n * is focused and marked, and nothing is made), or null when all is well. */\n validate?: (id: T) => HTMLElement | null;\n /** Runs as the name is typed (and once on open, with \"\"), so the app's own\n * fields can follow it: Patterpad's folder preview and default publish path. */\n onNameInput?: (name: string) => void;\n /** The item chosen when the gallery opens. Default: the first. */\n initial?: T;\n onPick: (id: T, choice: KitGalleryChoice) => void;\n /** Runs once the gallery has closed, whichever way. */\n onClose?: () => void;\n}\n\nexport interface KitGallery {\n readonly dialog: HTMLDialogElement;\n close(): void;\n}\n\n/** A kit's features as pills, or null when it lists none. */\nfunction featurePills(features: string[] | undefined): HTMLElement | null {\n if (!features || features.length === 0) return null;\n return el(\"span\", \"kit-gallery-features\", ...features.map((f) => el(\"span\", \"kit-gallery-feature\", f)));\n}\n\n/** One tile: the name with its badge, the blurb, the feature pills. The gallery's\n * own, and the welcome screen's, so a kit looks the same wherever it is met\n * (welcome.ts draws a tiled group with it; import kit-gallery.css there too). */\nexport function kitTile(item: { name: string; blurb: string; badge?: string; features?: string[] }, onClick: () => void): HTMLButtonElement {\n const tile = el(\"button\", { className: \"kit-gallery-tile\", onClick },\n el(\"span\", \"kit-gallery-tile-head\",\n el(\"span\", \"kit-gallery-tile-name\", item.name),\n item.badge !== undefined ? el(\"span\", \"kit-gallery-badge\", item.badge) : null),\n el(\"span\", \"kit-gallery-tile-blurb\", item.blurb),\n featurePills(item.features)) as HTMLButtonElement;\n tile.type = \"button\";\n return tile;\n}\n\n/** Open the gallery as a modal dialog on the family's frame. */\nexport function openKitGallery<T extends string>(opts: KitGalleryOptions<T>): KitGallery {\n const frame = dialogFrame({ title: opts.title, ...(opts.what !== undefined ? { sub: opts.what } : {}), className: \"kit-gallery\", ...(opts.onClose ? { onClose: opts.onClose } : {}) });\n const { dialog } = frame;\n\n const entries = opts.sections.flatMap((section, s) => section.items.map((item) => ({ item, section, s })));\n if (entries.length === 0) throw new Error(\"openKitGallery: no items to choose from\");\n let chosen = entries.find((e) => e.item.id === opts.initial) ?? entries[0]!;\n\n // --- the details panel ----------------------------------------------------\n const nameInput = opts.namePlaceholder === undefined ? undefined : el(\"input\", { className: \"field kit-gallery-name\" }) as HTMLInputElement;\n if (nameInput) {\n nameInput.placeholder = opts.namePlaceholder!;\n nameInput.setAttribute(\"aria-label\", opts.nameLabel ?? \"Name\");\n }\n const fields = el(\"div\", \"kit-gallery-fields\",\n ...(nameInput ? [el(\"label\", \"kit-gallery-label\", opts.nameLabel ?? \"Name\"), nameInput] : []),\n ...(opts.details ? [opts.details] : []));\n\n const panelName = el(\"h3\", \"kit-gallery-panel-name\");\n const panelBlurb = el(\"p\", \"kit-gallery-panel-blurb\");\n const panelDetail = el(\"p\", \"kit-gallery-panel-detail\");\n const panelPlay = el(\"p\", \"kit-gallery-play\");\n const panelFeatures = el(\"div\", \"kit-gallery-panel-features\");\n const panelLands = el(\"ul\", \"kit-gallery-lands\");\n const panelLandsCaption = el(\"p\", \"kit-gallery-lands-caption\", \"What you get\");\n const panelNote = el(\"p\", \"kit-gallery-note\");\n const panel = el(\"div\", \"kit-gallery-panel\",\n panelName, panelFeatures, panelBlurb, panelDetail, panelPlay, panelLandsCaption, panelLands, panelNote, fields);\n\n const primary = el(\"button\", { className: \"btn primary\", onClick: () => commit() }) as HTMLButtonElement;\n primary.type = \"button\";\n const cancel = el(\"button\", { className: \"btn\", text: \"Cancel\", onClick: () => frame.close() }) as HTMLButtonElement;\n cancel.type = \"button\";\n\n const setText = (node: HTMLElement, text: string | undefined): void => {\n node.textContent = text ?? \"\";\n node.hidden = text === undefined || text === \"\";\n };\n\n // --- the tiles --------------------------------------------------------------\n const tiles = new Map<T, HTMLButtonElement>();\n const shelves = opts.sections.map((section) => {\n const grid = el(\"div\", \"kit-gallery-grid\", ...section.items.map((item) => {\n const tile = kitTile({ ...item, blurb: item.tile ?? item.blurb }, () => choose(item.id));\n tile.dataset.kit = item.id;\n // Double-click is the desktop's \"choose and go\"; a single click only chooses,\n // so a tile can be read in the panel before anything is made.\n tile.addEventListener(\"dblclick\", () => { choose(item.id); commit(); });\n tiles.set(item.id, tile);\n return tile;\n }));\n return el(\"section\", \"kit-gallery-shelf\",\n section.caption !== undefined ? el(\"h3\", \"kit-gallery-caption\", section.caption) : null,\n section.note !== undefined ? el(\"p\", \"kit-gallery-shelf-note\", section.note) : null,\n grid);\n });\n\n const choose = (id: T): void => {\n const next = entries.find((e) => e.item.id === id);\n if (!next) return;\n chosen = next;\n for (const [tid, tile] of tiles) tile.setAttribute(\"aria-pressed\", String(tid === id));\n const { item, section } = chosen;\n panelName.textContent = item.name;\n setText(panelBlurb, item.blurb);\n setText(panelDetail, item.detail);\n setText(panelPlay, item.play);\n const pills = featurePills(item.features);\n panelFeatures.replaceChildren(...(pills ? [pills] : []));\n panelFeatures.hidden = pills === null;\n panelLands.replaceChildren(...(item.lands ?? []).map((l) => el(\"li\", undefined, l)));\n panelLands.hidden = (item.lands ?? []).length === 0;\n panelLandsCaption.hidden = panelLands.hidden;\n const details = section.usesDetails !== false;\n fields.hidden = !details || (nameInput === undefined && opts.details === undefined);\n // Without the fields, the shelf's note is what the click will do next\n // (\"a folder you choose\"), so the panel repeats it beside the button.\n setText(panelNote, details ? undefined : section.note);\n primary.textContent = section.action ?? \"Create\";\n opts.onChoose?.(item.id);\n };\n\n const commit = (): void => {\n const { item, section } = chosen;\n const details = section.usesDetails !== false;\n let name: string | undefined;\n if (details && nameInput) {\n name = nameInput.value.trim();\n if (name === \"\") { nameInput.focus(); nameInput.classList.add(\"kit-gallery-missing\"); return; }\n }\n const missing = opts.validate?.(item.id) ?? null;\n if (missing) {\n missing.classList.add(\"kit-gallery-missing\");\n missing.addEventListener(\"input\", () => missing.classList.remove(\"kit-gallery-missing\"), { once: true });\n missing.focus();\n return;\n }\n frame.close();\n opts.onPick(item.id, name !== undefined ? { name } : {});\n };\n\n if (nameInput) {\n nameInput.addEventListener(\"input\", () => {\n nameInput.classList.remove(\"kit-gallery-missing\");\n opts.onNameInput?.(nameInput.value);\n });\n opts.onNameInput?.(\"\");\n // Enter creates with what is chosen: the author has said what it should be\n // called, and the tile they are looking at is the one they meant.\n nameInput.addEventListener(\"keydown\", (e) => {\n e.stopPropagation();\n if (e.key !== \"Enter\") return;\n e.preventDefault();\n commit();\n });\n }\n\n frame.body.append(el(\"div\", \"kit-gallery-layout\", el(\"div\", \"kit-gallery-shelves\", ...shelves), panel));\n frame.actions.append(cancel, primary);\n dialog.addEventListener(\"click\", (e) => { if (e.target === dialog) frame.close(); });\n\n choose(chosen.item.id);\n frame.open();\n // Focus where the next keystroke is wanted: the name when one is asked for\n // and the opening shelf uses it, otherwise the chosen tile.\n if (nameInput && chosen.section.usesDetails !== false) nameInput.focus();\n else tiles.get(chosen.item.id)?.focus();\n\n return { dialog, close: () => frame.close() };\n}\n"]}
|
package/dist/index.cjs
CHANGED
|
@@ -2699,28 +2699,22 @@ function showUpdaterDialog(opts) {
|
|
|
2699
2699
|
}
|
|
2700
2700
|
|
|
2701
2701
|
// src/kit-gallery.ts
|
|
2702
|
-
function
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
if (image === void 0) return;
|
|
2706
|
-
const ink = el("span", "kit-gallery-ink");
|
|
2707
|
-
ink.style.setProperty("--kit-art", `url("${image.replace(/"/g, "%22")}")`);
|
|
2708
|
-
host.append(ink);
|
|
2702
|
+
function featurePills(features) {
|
|
2703
|
+
if (!features || features.length === 0) return null;
|
|
2704
|
+
return el("span", "kit-gallery-features", ...features.map((f) => el("span", "kit-gallery-feature", f)));
|
|
2709
2705
|
}
|
|
2710
2706
|
function kitTile(item, onClick) {
|
|
2711
|
-
const art = el("div", "kit-gallery-art");
|
|
2712
|
-
setArt(art, item.image);
|
|
2713
2707
|
const tile = el(
|
|
2714
2708
|
"button",
|
|
2715
2709
|
{ className: "kit-gallery-tile", onClick },
|
|
2716
|
-
art,
|
|
2717
2710
|
el(
|
|
2718
2711
|
"span",
|
|
2719
2712
|
"kit-gallery-tile-head",
|
|
2720
2713
|
el("span", "kit-gallery-tile-name", item.name),
|
|
2721
2714
|
item.badge !== void 0 ? el("span", "kit-gallery-badge", item.badge) : null
|
|
2722
2715
|
),
|
|
2723
|
-
el("span", "kit-gallery-tile-blurb", item.blurb)
|
|
2716
|
+
el("span", "kit-gallery-tile-blurb", item.blurb),
|
|
2717
|
+
featurePills(item.features)
|
|
2724
2718
|
);
|
|
2725
2719
|
tile.type = "button";
|
|
2726
2720
|
return tile;
|
|
@@ -2742,24 +2736,22 @@ function openKitGallery(opts) {
|
|
|
2742
2736
|
...nameInput ? [el("label", "kit-gallery-label", opts.nameLabel ?? "Name"), nameInput] : [],
|
|
2743
2737
|
...opts.details ? [opts.details] : []
|
|
2744
2738
|
);
|
|
2745
|
-
const panelArt = el("div", "kit-gallery-art kit-gallery-panel-art");
|
|
2746
2739
|
const panelName = el("h3", "kit-gallery-panel-name");
|
|
2747
2740
|
const panelBlurb = el("p", "kit-gallery-panel-blurb");
|
|
2748
2741
|
const panelDetail = el("p", "kit-gallery-panel-detail");
|
|
2749
2742
|
const panelPlay = el("p", "kit-gallery-play");
|
|
2750
|
-
const
|
|
2743
|
+
const panelFeatures = el("div", "kit-gallery-panel-features");
|
|
2751
2744
|
const panelLands = el("ul", "kit-gallery-lands");
|
|
2752
2745
|
const panelLandsCaption = el("p", "kit-gallery-lands-caption", "What you get");
|
|
2753
2746
|
const panelNote = el("p", "kit-gallery-note");
|
|
2754
2747
|
const panel = el(
|
|
2755
2748
|
"div",
|
|
2756
2749
|
"kit-gallery-panel",
|
|
2757
|
-
panelArt,
|
|
2758
2750
|
panelName,
|
|
2751
|
+
panelFeatures,
|
|
2759
2752
|
panelBlurb,
|
|
2760
2753
|
panelDetail,
|
|
2761
2754
|
panelPlay,
|
|
2762
|
-
panelShows,
|
|
2763
2755
|
panelLandsCaption,
|
|
2764
2756
|
panelLands,
|
|
2765
2757
|
panelNote,
|
|
@@ -2799,12 +2791,13 @@ function openKitGallery(opts) {
|
|
|
2799
2791
|
chosen = next;
|
|
2800
2792
|
for (const [tid, tile] of tiles) tile.setAttribute("aria-pressed", String(tid === id));
|
|
2801
2793
|
const { item, section } = chosen;
|
|
2802
|
-
setArt(panelArt, item.image);
|
|
2803
2794
|
panelName.textContent = item.name;
|
|
2804
2795
|
setText(panelBlurb, item.blurb);
|
|
2805
2796
|
setText(panelDetail, item.detail);
|
|
2806
2797
|
setText(panelPlay, item.play);
|
|
2807
|
-
|
|
2798
|
+
const pills = featurePills(item.features);
|
|
2799
|
+
panelFeatures.replaceChildren(...pills ? [pills] : []);
|
|
2800
|
+
panelFeatures.hidden = pills === null;
|
|
2808
2801
|
panelLands.replaceChildren(...(item.lands ?? []).map((l) => el("li", void 0, l)));
|
|
2809
2802
|
panelLands.hidden = (item.lands ?? []).length === 0;
|
|
2810
2803
|
panelLandsCaption.hidden = panelLands.hidden;
|
|
@@ -2878,7 +2871,7 @@ function mountWelcome(host, opts) {
|
|
|
2878
2871
|
name: item.name,
|
|
2879
2872
|
blurb: item.hint ?? "",
|
|
2880
2873
|
...item.badge !== void 0 ? { badge: item.badge } : {},
|
|
2881
|
-
...item.
|
|
2874
|
+
...item.features !== void 0 ? { features: item.features } : {}
|
|
2882
2875
|
}, item.onOpen))) : el("div", "welcome-list", ...g.items.map((item) => {
|
|
2883
2876
|
const b = el(
|
|
2884
2877
|
"button",
|