@wildwinter/app-shell 0.16.0 → 0.18.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/README.md +52 -4
- package/dist/index.cjs +105 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +87 -1
- package/dist/index.d.ts +87 -1
- package/dist/index.js +103 -1
- package/dist/index.js.map +1 -1
- package/dist/notes-editor.css +1 -1
- package/dist/notes-editor.css.map +1 -1
- package/dist/save.css +37 -0
- package/dist/save.css.map +1 -0
- package/dist/stale.css +30 -0
- package/dist/stale.css.map +1 -0
- package/dist/stepper.css +98 -0
- package/dist/stepper.css.map +1 -0
- package/dist/tokens.css +2 -1
- package/dist/tokens.css.map +1 -1
- package/package.json +13 -1
package/README.md
CHANGED
|
@@ -64,13 +64,61 @@ event loop (16ms), so a fast inner loop neither floods IPC nor stutters.
|
|
|
64
64
|
**A strip, not a modal.** The window that started the job shows it; the rest of
|
|
65
65
|
the app stays usable.
|
|
66
66
|
|
|
67
|
+
## v0.18 (the bars, and the third semantic colour)
|
|
68
|
+
|
|
69
|
+
Three drawings each app had grown its own copy of, and the token the family kept
|
|
70
|
+
needing and never had.
|
|
71
|
+
|
|
72
|
+
- **`renderStepperBar`** - a bottom bar that walks a list of things to attend to,
|
|
73
|
+
one at a time: count, previous, position, next, the entry as a button, an
|
|
74
|
+
action slot. Four bars across the two apps are this shape (problems, review
|
|
75
|
+
walks). It knows about a list and an index; it knows nothing about what a
|
|
76
|
+
problem or a comment is.
|
|
77
|
+
|
|
78
|
+
```ts
|
|
79
|
+
import { renderStepperBar } from "@wildwinter/app-shell";
|
|
80
|
+
import "@wildwinter/app-shell/stepper.css";
|
|
81
|
+
renderStepperBar(host, {
|
|
82
|
+
items: problems.map((p) => ({ kind: p.severity, kindClass: `sev-${p.severity}`, where: p.path, text: p.message })),
|
|
83
|
+
at, tone: "danger", onStep: (i) => { at = i; paint(); }, onGo: (i) => jumpTo(problems[i]),
|
|
84
|
+
});
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Whether stepping NAVIGATES is the caller's decision, and the bar takes no view:
|
|
88
|
+
an ambient surface moves the view and never the focus; a mode you entered may
|
|
89
|
+
take you somewhere.
|
|
90
|
+
|
|
91
|
+
- **`saveIndicator`** - the six lines that draw what `createSaveController`
|
|
92
|
+
already computes. Three states, always present: a dot that only ever appears
|
|
93
|
+
to worry you leaves "did that get written?" unanswered.
|
|
94
|
+
|
|
95
|
+
```ts
|
|
96
|
+
const ind = saveIndicator();
|
|
97
|
+
topbar.append(ind.el);
|
|
98
|
+
const saver = createSaveController({ write, onStatus: ind.set });
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
- **`staleBar`** - a running session that has fallen behind its source. The app
|
|
102
|
+
supplies the noun and the callback; the sentence is shared, because both apps
|
|
103
|
+
had written it independently and landed a word apart.
|
|
104
|
+
|
|
105
|
+
```ts
|
|
106
|
+
staleBar({ subject: "The project", onRestart: () => void rebuild() });
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
- **`--ok`** joins `--danger` and `--warn` in `tokens.css`, with a `light-dark()`
|
|
110
|
+
default every palette should override in its own `theme.css`. It is the only
|
|
111
|
+
colour in the grammar layer, and it is there because it kept not being
|
|
112
|
+
anywhere: "all is well" was being met with raw green literals that could not
|
|
113
|
+
theme-shift.
|
|
114
|
+
|
|
67
115
|
## Roadmap
|
|
68
116
|
|
|
69
117
|
Later slices lift the rest of the common shell from Patterpad (canonical),
|
|
70
|
-
reconciling Storylet Studio's variants: the pane grid + toggles, the
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
118
|
+
reconciling Storylet Studio's variants: the pane grid + toggles, the command
|
|
119
|
+
palette, and version control's renderer half. Storylet Studio migrates each
|
|
120
|
+
first (proving app-agnosticism); Patterpad follows - see
|
|
121
|
+
`patterkit/design/from-storylets/patterpad-onto-the-shell.md` for that order.
|
|
74
122
|
|
|
75
123
|
## Release
|
|
76
124
|
|
package/dist/index.cjs
CHANGED
|
@@ -136,6 +136,15 @@ var icon = {
|
|
|
136
136
|
dot: "\u25CF",
|
|
137
137
|
/** Play, in the sense of "run this". */
|
|
138
138
|
play: "\u25B6",
|
|
139
|
+
/** Start the thing again from the top: a play session, a sweep. Named for the
|
|
140
|
+
* act, not the arrow, which is the table's rule. */
|
|
141
|
+
restart: "\u27F2",
|
|
142
|
+
/** The three ways a collection can be shown. Named by what you get rather than
|
|
143
|
+
* by the glyph, so a second app can pick the same three without copying
|
|
144
|
+
* somebody's taste in symbols. */
|
|
145
|
+
viewCards: "\u25A6",
|
|
146
|
+
viewTable: "\u2630",
|
|
147
|
+
viewNode: "\u25C8",
|
|
139
148
|
// --- handling -------------------------------------------------------------
|
|
140
149
|
/** The drag grip on a reorderable row. */
|
|
141
150
|
grip: "\u283F",
|
|
@@ -1379,6 +1388,99 @@ function createSaveController(opts) {
|
|
|
1379
1388
|
};
|
|
1380
1389
|
}
|
|
1381
1390
|
|
|
1391
|
+
// src/save-view.ts
|
|
1392
|
+
var WORDS = {
|
|
1393
|
+
saved: "Saved",
|
|
1394
|
+
saving: "Saving\u2026",
|
|
1395
|
+
unsaved: "Unsaved"
|
|
1396
|
+
};
|
|
1397
|
+
function saveIndicator(initial = "saved") {
|
|
1398
|
+
const node = el("span");
|
|
1399
|
+
const set = (status) => {
|
|
1400
|
+
node.className = `savestat ${status}`;
|
|
1401
|
+
node.textContent = WORDS[status];
|
|
1402
|
+
};
|
|
1403
|
+
set(initial);
|
|
1404
|
+
return { el: node, set };
|
|
1405
|
+
}
|
|
1406
|
+
|
|
1407
|
+
// src/stale.ts
|
|
1408
|
+
function staleBar(opts) {
|
|
1409
|
+
const label2 = opts.restartLabel ?? "Restart";
|
|
1410
|
+
return el(
|
|
1411
|
+
"div",
|
|
1412
|
+
{ className: "stale-bar" },
|
|
1413
|
+
el("span", {
|
|
1414
|
+
className: "stale-bar-msg",
|
|
1415
|
+
text: `${opts.subject} changed in the editor. ${opts.advice ?? "Restart to play the new version."}`
|
|
1416
|
+
}),
|
|
1417
|
+
el("button", {
|
|
1418
|
+
className: "stale-bar-go",
|
|
1419
|
+
text: `${icon.restart} ${label2}`,
|
|
1420
|
+
onClick: () => opts.onRestart()
|
|
1421
|
+
})
|
|
1422
|
+
);
|
|
1423
|
+
}
|
|
1424
|
+
|
|
1425
|
+
// src/stepper.ts
|
|
1426
|
+
function renderStepperBar(host, opts) {
|
|
1427
|
+
const { items } = opts;
|
|
1428
|
+
const close = opts.onClose === void 0 ? null : el("button", {
|
|
1429
|
+
className: "stepbar-nav stepbar-close",
|
|
1430
|
+
text: icon.close,
|
|
1431
|
+
tip: opts.closeTip ?? "Close",
|
|
1432
|
+
onClick: opts.onClose
|
|
1433
|
+
});
|
|
1434
|
+
const actions = (opts.actions ?? []).filter((a) => a !== null && a !== void 0);
|
|
1435
|
+
if (items.length === 0) {
|
|
1436
|
+
if (opts.empty === void 0) {
|
|
1437
|
+
host.hidden = true;
|
|
1438
|
+
host.replaceChildren();
|
|
1439
|
+
return;
|
|
1440
|
+
}
|
|
1441
|
+
host.hidden = false;
|
|
1442
|
+
host.replaceChildren(
|
|
1443
|
+
el("span", { className: "stepbar-count muted", text: "0" }),
|
|
1444
|
+
el("span", { className: "stepbar-empty", text: opts.empty }),
|
|
1445
|
+
...actions,
|
|
1446
|
+
...close ? [close] : []
|
|
1447
|
+
);
|
|
1448
|
+
return;
|
|
1449
|
+
}
|
|
1450
|
+
host.hidden = false;
|
|
1451
|
+
const index = Math.min(Math.max(opts.at, 0), items.length - 1);
|
|
1452
|
+
const item = items[index];
|
|
1453
|
+
const step = (delta) => opts.onStep((index + delta + items.length) % items.length);
|
|
1454
|
+
const nav = items.length > 1 ? [
|
|
1455
|
+
el("button", {
|
|
1456
|
+
className: "stepbar-nav",
|
|
1457
|
+
text: icon.back,
|
|
1458
|
+
tip: opts.tips?.prev ?? "Previous",
|
|
1459
|
+
onClick: () => step(-1)
|
|
1460
|
+
}),
|
|
1461
|
+
el("span", { className: "stepbar-of", text: `${index + 1}/${items.length}` }),
|
|
1462
|
+
el("button", {
|
|
1463
|
+
className: "stepbar-nav",
|
|
1464
|
+
text: icon.forward,
|
|
1465
|
+
tip: opts.tips?.next ?? "Next",
|
|
1466
|
+
onClick: () => step(1)
|
|
1467
|
+
})
|
|
1468
|
+
] : [];
|
|
1469
|
+
host.replaceChildren(
|
|
1470
|
+
el("span", { className: `stepbar-count ${opts.tone ?? "muted"}`, text: String(items.length) }),
|
|
1471
|
+
...nav,
|
|
1472
|
+
el(
|
|
1473
|
+
"button",
|
|
1474
|
+
{ className: "stepbar-cur", tip: opts.tips?.go ?? "Go to this", onClick: () => opts.onGo(index) },
|
|
1475
|
+
item.kind === void 0 ? null : el("span", { className: `stepbar-cat${item.kindClass ? ` ${item.kindClass}` : ""}`, text: item.kind }),
|
|
1476
|
+
item.where === void 0 ? null : el("span", { className: "stepbar-where", text: item.where }),
|
|
1477
|
+
el("span", { className: "stepbar-msg", text: item.text })
|
|
1478
|
+
),
|
|
1479
|
+
...actions,
|
|
1480
|
+
...close ? [close] : []
|
|
1481
|
+
);
|
|
1482
|
+
}
|
|
1483
|
+
|
|
1382
1484
|
exports.EDIT_MENU = EDIT_MENU;
|
|
1383
1485
|
exports.JOB_PROGRESS = JOB_PROGRESS;
|
|
1384
1486
|
exports.PALETTE = PALETTE;
|
|
@@ -1416,7 +1518,10 @@ exports.openNotesEditor = openNotesEditor;
|
|
|
1416
1518
|
exports.paintVcBadges = paintVcBadges;
|
|
1417
1519
|
exports.pinButton = pinButton;
|
|
1418
1520
|
exports.placeAnchored = placeAnchored;
|
|
1521
|
+
exports.renderStepperBar = renderStepperBar;
|
|
1522
|
+
exports.saveIndicator = saveIndicator;
|
|
1419
1523
|
exports.showAbout = showAbout;
|
|
1524
|
+
exports.staleBar = staleBar;
|
|
1420
1525
|
exports.tagChips = tagChips;
|
|
1421
1526
|
exports.tipAt = tipAt;
|
|
1422
1527
|
exports.tipBold = tipBold;
|