@glimstone/core 4.0.0 → 4.1.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 +13 -0
- package/dist/button.d.ts +5 -0
- package/dist/button.js +4 -3
- package/dist/clipboard.d.ts +4 -0
- package/dist/clipboard.js +30 -0
- package/dist/colorNames.d.ts +10 -0
- package/dist/colorNames.js +61 -0
- package/dist/colorPicker.d.ts +59 -3
- package/dist/colorPicker.js +181 -73
- package/dist/dialog.d.ts +5 -0
- package/dist/dialog.js +27 -22
- package/dist/field.d.ts +21 -0
- package/dist/field.js +26 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +9 -0
- package/dist/marks.d.ts +30 -0
- package/dist/marks.js +30 -0
- package/dist/media.d.ts +2 -0
- package/dist/media.js +4 -0
- package/dist/menu.d.ts +109 -0
- package/dist/menu.js +163 -0
- package/dist/meter.d.ts +32 -0
- package/dist/meter.js +44 -0
- package/dist/pill.d.ts +3 -0
- package/dist/pill.js +7 -0
- package/dist/selectModel.d.ts +17 -0
- package/dist/selectModel.js +23 -0
- package/dist/selector.d.ts +2 -2
- package/dist/sidebarRow.d.ts +4 -0
- package/dist/sidebarRow.js +6 -1
- package/dist/table.d.ts +12 -0
- package/dist/table.js +5 -0
- package/dist/toastEngine.d.ts +12 -0
- package/dist/toastEngine.js +8 -0
- package/dist/tree.d.ts +38 -0
- package/dist/tree.js +57 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/window.d.ts +29 -0
- package/dist/window.js +62 -0
- package/glyph-map.md +48 -0
- package/glyphs.json +247 -0
- package/glyphs.md +28 -2
- package/package.json +1 -1
- package/tokens.css +1093 -12
package/dist/selectModel.d.ts
CHANGED
|
@@ -38,6 +38,23 @@ export declare function selectRootClass(width: SelectWidth): string;
|
|
|
38
38
|
/** The trigger's classes. `wrap` lets a long value run onto a second line, for one whose end says as much as its start, such as a path. */
|
|
39
39
|
export declare function selectTriggerClass(size: SelectSize, wrap: boolean): string;
|
|
40
40
|
export declare function selectContentClass(glyphs: boolean): string;
|
|
41
|
+
/**
|
|
42
|
+
* Which rows an open list draws. `menu` takes a context menu's, so an app with
|
|
43
|
+
* both shows one kind of menu row.
|
|
44
|
+
*/
|
|
45
|
+
export type SelectRows = "list" | "menu";
|
|
46
|
+
export interface SelectRowParts {
|
|
47
|
+
content: string;
|
|
48
|
+
item: string;
|
|
49
|
+
/** The glyph's room, or null where no row of a list has one. A menu row keeps it always. */
|
|
50
|
+
glyph: string | null;
|
|
51
|
+
label: string;
|
|
52
|
+
check: string;
|
|
53
|
+
caret: string;
|
|
54
|
+
heading: string;
|
|
55
|
+
}
|
|
56
|
+
/** The classes of an open list and its rows. */
|
|
57
|
+
export declare function selectRowParts(rows: SelectRows, glyphs: boolean): SelectRowParts;
|
|
41
58
|
/** A field defaults to `fill`, the smaller sizes to `steady`. */
|
|
42
59
|
export declare function defaultWidth(size: SelectSize): SelectWidth;
|
|
43
60
|
export declare const SELECT_POSITIONING: {
|
package/dist/selectModel.js
CHANGED
|
@@ -24,6 +24,29 @@ export function selectTriggerClass(size, wrap) {
|
|
|
24
24
|
export function selectContentClass(glyphs) {
|
|
25
25
|
return `glim-select-content glim-fade${glyphs ? " glim-select-content--glyphs" : ""}`;
|
|
26
26
|
}
|
|
27
|
+
/** The classes of an open list and its rows. */
|
|
28
|
+
export function selectRowParts(rows, glyphs) {
|
|
29
|
+
const content = selectContentClass(glyphs);
|
|
30
|
+
return rows === "menu"
|
|
31
|
+
? {
|
|
32
|
+
content: `${content} glim-select-content--menu`,
|
|
33
|
+
item: "glim-menu-item",
|
|
34
|
+
glyph: "glim-menu-glyph",
|
|
35
|
+
label: "glim-menu-label",
|
|
36
|
+
check: "glim-menu-end glim-menu-tick",
|
|
37
|
+
caret: "glim-menu-end glim-menu-caret",
|
|
38
|
+
heading: "glim-menu-head",
|
|
39
|
+
}
|
|
40
|
+
: {
|
|
41
|
+
content,
|
|
42
|
+
item: "glim-select-item",
|
|
43
|
+
glyph: glyphs ? "glim-select-glyph" : null,
|
|
44
|
+
label: "glim-select-label",
|
|
45
|
+
check: "glim-select-check",
|
|
46
|
+
caret: "glim-select-caret",
|
|
47
|
+
heading: "glim-select-heading",
|
|
48
|
+
};
|
|
49
|
+
}
|
|
27
50
|
/** A field defaults to `fill`, the smaller sizes to `steady`. */
|
|
28
51
|
export function defaultWidth(size) {
|
|
29
52
|
return size === "field" ? "fill" : "steady";
|
package/dist/selector.d.ts
CHANGED
|
@@ -34,7 +34,7 @@ export declare const MAX_PINNED_WIDTH = 352;
|
|
|
34
34
|
*/
|
|
35
35
|
export declare function pinnedWidth(widest: number, count: number, room: number, gap: number): number;
|
|
36
36
|
/** The id of a tab in a strip that switches `panelId`; the panel names itself after it. */
|
|
37
|
-
export declare function selectorTabId(panelId: string, itemId: string): string;
|
|
37
|
+
export declare function selectorTabId(panelId: string, itemId: string | number): string;
|
|
38
38
|
/**
|
|
39
39
|
* The label axis a selector follows. The page-level strips are tabs, the
|
|
40
40
|
* smaller ones stand in form rows beside buttons, and the column of tiles
|
|
@@ -56,7 +56,7 @@ export declare function nextFocusIndex(key: SelectorNavKey, current: number, cou
|
|
|
56
56
|
*/
|
|
57
57
|
export declare function rovedIndex(disabled: boolean[], activeIndex: number): number;
|
|
58
58
|
/** The value of a "many" selector once `id` is toggled, in the items' order. */
|
|
59
|
-
export declare function toggleSelection(value: readonly
|
|
59
|
+
export declare function toggleSelection<V>(value: readonly V[], id: V, order: readonly V[]): V[];
|
|
60
60
|
/**
|
|
61
61
|
* Moves the focus for a key press inside `track` and returns the segment it
|
|
62
62
|
* landed on, or null when the key is not one the strip answers. Disabled
|
package/dist/sidebarRow.d.ts
CHANGED
|
@@ -9,6 +9,10 @@ export interface SidebarRowInput {
|
|
|
9
9
|
hueIndex?: number;
|
|
10
10
|
/** The figure on the row; nothing shows at zero. */
|
|
11
11
|
count?: number;
|
|
12
|
+
/** Something stands beside the link in the row, so it is never centred. */
|
|
13
|
+
framed?: boolean;
|
|
14
|
+
/** A tree's row: stepped in by its level, with a smaller glyph and gap. */
|
|
15
|
+
depth?: number;
|
|
12
16
|
}
|
|
13
17
|
export interface SidebarRowView {
|
|
14
18
|
className: string;
|
package/dist/sidebarRow.js
CHANGED
|
@@ -15,14 +15,19 @@ export function sidebarRowView(r) {
|
|
|
15
15
|
const showLabel = !hidesLabel(mode);
|
|
16
16
|
const reactive = mode === "reactive";
|
|
17
17
|
const hued = r.hueIndex !== undefined;
|
|
18
|
+
const tree = r.depth !== undefined;
|
|
19
|
+
// A tree's depth and a slot's control mean nothing in the middle of the row.
|
|
20
|
+
const centred = !showLabel && !r.framed && !tree;
|
|
18
21
|
const style = {
|
|
19
22
|
...(hued ? hueVars(r.hueIndex) : {}),
|
|
23
|
+
...(tree ? { "--nav-depth": String(r.depth) } : {}),
|
|
20
24
|
...(reactive ? { "--reactive-chars": String(labelWidth(r.label)) } : {}),
|
|
21
25
|
};
|
|
22
26
|
return {
|
|
23
27
|
className: [
|
|
24
28
|
"glim-nav-row",
|
|
25
|
-
|
|
29
|
+
centred && "glim-nav-row--centred",
|
|
30
|
+
tree && "glim-nav-row--tree",
|
|
26
31
|
reactive && "glim-reactive",
|
|
27
32
|
hued && "glim-hue glim-hue-icon",
|
|
28
33
|
r.active && "glim-active",
|
package/dist/table.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export interface TableColumn {
|
|
2
|
+
/** Which field of a row the column shows. */
|
|
3
|
+
key: string;
|
|
4
|
+
/** The column's heading. A table with no heading at all draws no header row. */
|
|
5
|
+
label?: string;
|
|
6
|
+
/** Sets the column at the end, in figures that line up (rule 7). */
|
|
7
|
+
end?: boolean;
|
|
8
|
+
/** `muted` for a quiet column, `accent` for what changes. */
|
|
9
|
+
tone?: "muted" | "accent";
|
|
10
|
+
}
|
|
11
|
+
/** The classes of a cell. */
|
|
12
|
+
export declare function tableCellClass(column: TableColumn): string;
|
package/dist/table.js
ADDED
package/dist/toastEngine.d.ts
CHANGED
|
@@ -5,10 +5,16 @@ export declare const TOAST_DURATION_MS = 4000;
|
|
|
5
5
|
* viewport. Without a cap, a held Enter key grows the stack off-screen, where
|
|
6
6
|
* its cards still block clicks on the page. */
|
|
7
7
|
export declare const MAX_VISIBLE_TOASTS = 4;
|
|
8
|
+
/** A button on a toast, such as Undo. A press runs it and dismisses the toast. */
|
|
9
|
+
export interface ToastAction {
|
|
10
|
+
label: string;
|
|
11
|
+
onClick: () => void;
|
|
12
|
+
}
|
|
8
13
|
export interface ToastEntry {
|
|
9
14
|
id: string;
|
|
10
15
|
message: string;
|
|
11
16
|
severity: ToastSeverity;
|
|
17
|
+
action?: ToastAction;
|
|
12
18
|
/** What is left of the duration, authoritative only while paused
|
|
13
19
|
* (expiresAt === null). */
|
|
14
20
|
remainingMs: number;
|
|
@@ -26,6 +32,7 @@ export declare function addToast(list: ToastEntry[], toast: {
|
|
|
26
32
|
id: string;
|
|
27
33
|
message: string;
|
|
28
34
|
severity: ToastSeverity;
|
|
35
|
+
action?: ToastAction;
|
|
29
36
|
}, now: number, durationMs?: number, maxVisible?: number): ToastEntry[];
|
|
30
37
|
/** Removes one toast and leaves the others alone. Unknown ids are ignored. */
|
|
31
38
|
export declare function removeToast(list: ToastEntry[], id: string): ToastEntry[];
|
|
@@ -54,6 +61,11 @@ export declare function applyEngagement(prev: Readonly<ToastEngagement>, kind: T
|
|
|
54
61
|
next: ToastEngagement;
|
|
55
62
|
engaged: boolean;
|
|
56
63
|
};
|
|
64
|
+
/**
|
|
65
|
+
* A message cut after each slash, for a <wbr> between the parts, so a path breaks
|
|
66
|
+
* at a folder rather than inside a name.
|
|
67
|
+
*/
|
|
68
|
+
export declare function softBreaks(message: string): string[];
|
|
57
69
|
/** Quiet mode filters by severity: it hides routine successes, never warnings
|
|
58
70
|
* or failures. */
|
|
59
71
|
export declare function shouldShowToast(severity: ToastSeverity, quiet: boolean): boolean;
|
package/dist/toastEngine.js
CHANGED
|
@@ -24,6 +24,7 @@ export function addToast(list, toast, now, durationMs = TOAST_DURATION_MS, maxVi
|
|
|
24
24
|
id: toast.id,
|
|
25
25
|
message: toast.message,
|
|
26
26
|
severity: toast.severity,
|
|
27
|
+
action: toast.action,
|
|
27
28
|
remainingMs: durationMs,
|
|
28
29
|
expiresAt: now + durationMs,
|
|
29
30
|
};
|
|
@@ -76,6 +77,13 @@ export function applyEngagement(prev, kind, active) {
|
|
|
76
77
|
const next = { ...prev, [kind]: active };
|
|
77
78
|
return { next, engaged: next.hover || next.focus };
|
|
78
79
|
}
|
|
80
|
+
/**
|
|
81
|
+
* A message cut after each slash, for a <wbr> between the parts, so a path breaks
|
|
82
|
+
* at a folder rather than inside a name.
|
|
83
|
+
*/
|
|
84
|
+
export function softBreaks(message) {
|
|
85
|
+
return message.split(/(?<=[/\\])/);
|
|
86
|
+
}
|
|
79
87
|
/** Quiet mode filters by severity: it hides routine successes, never warnings
|
|
80
88
|
* or failures. */
|
|
81
89
|
export function shouldShowToast(severity, quiet) {
|
package/dist/tree.d.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
export interface TreeNode<G = unknown> {
|
|
2
|
+
/** Unique in the tree, such as a path. */
|
|
3
|
+
id: string;
|
|
4
|
+
label: string;
|
|
5
|
+
/** Whether the row can open. Its children are asked for the first time it does. */
|
|
6
|
+
hasChildren?: boolean;
|
|
7
|
+
glyph?: G;
|
|
8
|
+
/** Takes the glyph's place while the row is open. */
|
|
9
|
+
openGlyph?: G;
|
|
10
|
+
/** Attributes for the row, such as a data hook. */
|
|
11
|
+
attrs?: Record<string, string>;
|
|
12
|
+
}
|
|
13
|
+
export interface TreeRow<G = unknown> {
|
|
14
|
+
node: TreeNode<G>;
|
|
15
|
+
/** From 1, as aria-level counts. */
|
|
16
|
+
level: number;
|
|
17
|
+
position: number;
|
|
18
|
+
siblings: number;
|
|
19
|
+
parent: string | null;
|
|
20
|
+
open: boolean;
|
|
21
|
+
}
|
|
22
|
+
/** The rows on show, top to bottom. The top level's children are filed under null. */
|
|
23
|
+
export declare function treeRows<G>(children: ReadonlyMap<string | null, readonly TreeNode<G>[]>, open: readonly string[]): TreeRow<G>[];
|
|
24
|
+
export type TreeStep = {
|
|
25
|
+
focus: string;
|
|
26
|
+
} | {
|
|
27
|
+
open: string;
|
|
28
|
+
} | {
|
|
29
|
+
close: string;
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* What a key does on the row at `at`, or null when the tree does not answer it.
|
|
33
|
+
* Right and left swap under a right-to-left page. A letter goes to the next row
|
|
34
|
+
* starting with it, wrapping at the end.
|
|
35
|
+
*/
|
|
36
|
+
export declare function treeStep<G>(rows: readonly TreeRow<G>[], at: number, key: string, rtl?: boolean): TreeStep | null;
|
|
37
|
+
/** Puts the focus on a row. */
|
|
38
|
+
export declare function focusTreeRow(tree: HTMLElement, id: string): void;
|
package/dist/tree.js
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
// The model behind Tree: which rows are on show and what a key does there. The
|
|
2
|
+
// frameworks hold the children and draw the rows; the glyph type is theirs.
|
|
3
|
+
/** The rows on show, top to bottom. The top level's children are filed under null. */
|
|
4
|
+
export function treeRows(children, open) {
|
|
5
|
+
const rows = [];
|
|
6
|
+
const walk = (parent, level) => {
|
|
7
|
+
const nodes = children.get(parent) ?? [];
|
|
8
|
+
nodes.forEach((node, i) => {
|
|
9
|
+
const isOpen = !!node.hasChildren && open.includes(node.id);
|
|
10
|
+
rows.push({ node, level, position: i + 1, siblings: nodes.length, parent, open: isOpen });
|
|
11
|
+
if (isOpen)
|
|
12
|
+
walk(node.id, level + 1);
|
|
13
|
+
});
|
|
14
|
+
};
|
|
15
|
+
walk(null, 1);
|
|
16
|
+
return rows;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* What a key does on the row at `at`, or null when the tree does not answer it.
|
|
20
|
+
* Right and left swap under a right-to-left page. A letter goes to the next row
|
|
21
|
+
* starting with it, wrapping at the end.
|
|
22
|
+
*/
|
|
23
|
+
export function treeStep(rows, at, key, rtl = false) {
|
|
24
|
+
const row = rows[at];
|
|
25
|
+
const focus = (target) => (target ? { focus: target.node.id } : null);
|
|
26
|
+
switch (key) {
|
|
27
|
+
case "ArrowDown":
|
|
28
|
+
return focus(rows[at + 1]);
|
|
29
|
+
case "ArrowUp":
|
|
30
|
+
return focus(rows[at - 1]);
|
|
31
|
+
case "Home":
|
|
32
|
+
return focus(rows[0]);
|
|
33
|
+
case "End":
|
|
34
|
+
return focus(rows[rows.length - 1]);
|
|
35
|
+
case "ArrowRight":
|
|
36
|
+
case "ArrowLeft": {
|
|
37
|
+
const inward = key === (rtl ? "ArrowLeft" : "ArrowRight");
|
|
38
|
+
if (inward) {
|
|
39
|
+
if (!row.node.hasChildren)
|
|
40
|
+
return null;
|
|
41
|
+
return row.open ? focus(rows[at + 1]?.parent === row.node.id ? rows[at + 1] : undefined) : { open: row.node.id };
|
|
42
|
+
}
|
|
43
|
+
if (row.open)
|
|
44
|
+
return { close: row.node.id };
|
|
45
|
+
return row.parent === null ? null : { focus: row.parent };
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
if (key.length !== 1 || key === " ")
|
|
49
|
+
return null;
|
|
50
|
+
const letter = key.toLowerCase();
|
|
51
|
+
const after = [...rows.slice(at + 1), ...rows.slice(0, at)];
|
|
52
|
+
return focus(after.find((r) => r.node.label.toLowerCase().startsWith(letter)));
|
|
53
|
+
}
|
|
54
|
+
/** Puts the focus on a row. */
|
|
55
|
+
export function focusTreeRow(tree, id) {
|
|
56
|
+
tree.querySelector(`[data-tree-id="${CSS.escape(id)}"]`)?.focus();
|
|
57
|
+
}
|
package/dist/version.d.ts
CHANGED
package/dist/version.js
CHANGED
package/dist/window.d.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export type WindowSize = "normal" | "wide" | "full";
|
|
2
|
+
export interface WindowActionBase {
|
|
3
|
+
/** The forward action, filled with the accent. Its presence makes the way out Cancel rather than Close. */
|
|
4
|
+
primary?: boolean;
|
|
5
|
+
/** This action already leaves the window, such as Done, so no Cancel or Close is added. */
|
|
6
|
+
wayOut?: boolean;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* The foot's buttons in order. A window whose foot has anything in it can be
|
|
10
|
+
* left from there: without a way out among its actions it gets Cancel when
|
|
11
|
+
* one of them goes forward and Close otherwise, before the others, so the
|
|
12
|
+
* forward action stays last.
|
|
13
|
+
*/
|
|
14
|
+
export declare function windowFoot<A extends WindowActionBase>(actions: readonly A[], hasStart: boolean, wayOut: {
|
|
15
|
+
cancel: A;
|
|
16
|
+
close: A;
|
|
17
|
+
}): A[];
|
|
18
|
+
/**
|
|
19
|
+
* Puts a window on the stack. Escape closes the one in front and Tab stays
|
|
20
|
+
* inside it. Returns the removal, to call however the window closes.
|
|
21
|
+
*/
|
|
22
|
+
export declare function stackWindow(card: () => HTMLElement | null, close: () => void): () => void;
|
|
23
|
+
/** Whether a window is open, for a key handler of the app's that should leave the page alone. */
|
|
24
|
+
export declare function windowIsOpen(): boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Where focus goes as a window opens: its first field, so typing can start at
|
|
27
|
+
* once, or else the last button of its foot, the forward action.
|
|
28
|
+
*/
|
|
29
|
+
export declare function windowFocusTarget(card: HTMLElement): HTMLElement | null;
|
package/dist/window.js
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
// What every Window shares, whatever it holds ("Windows" in the design
|
|
2
|
+
// language): a foot that always offers a way out, a stack in which Escape and
|
|
3
|
+
// Tab belong to the window in front, and where focus lands when one opens.
|
|
4
|
+
import { keepTabInside } from "./dialog.js";
|
|
5
|
+
import { menuIsOpen } from "./menu.js";
|
|
6
|
+
/**
|
|
7
|
+
* The foot's buttons in order. A window whose foot has anything in it can be
|
|
8
|
+
* left from there: without a way out among its actions it gets Cancel when
|
|
9
|
+
* one of them goes forward and Close otherwise, before the others, so the
|
|
10
|
+
* forward action stays last.
|
|
11
|
+
*/
|
|
12
|
+
export function windowFoot(actions, hasStart, wayOut) {
|
|
13
|
+
if ((actions.length === 0 && !hasStart) || actions.some((a) => a.wayOut))
|
|
14
|
+
return [...actions];
|
|
15
|
+
return [actions.some((a) => a.primary) ? wayOut.cancel : wayOut.close, ...actions];
|
|
16
|
+
}
|
|
17
|
+
const stack = [];
|
|
18
|
+
// A key that an open menu or a Select inside the window already handled is
|
|
19
|
+
// left alone, so Escape closes one thing at a time from the front.
|
|
20
|
+
function onKey(e) {
|
|
21
|
+
const top = stack[stack.length - 1];
|
|
22
|
+
if (!top || e.defaultPrevented)
|
|
23
|
+
return;
|
|
24
|
+
if (e.key === "Escape") {
|
|
25
|
+
if (menuIsOpen())
|
|
26
|
+
return;
|
|
27
|
+
e.preventDefault();
|
|
28
|
+
top.close();
|
|
29
|
+
}
|
|
30
|
+
else if (e.key === "Tab")
|
|
31
|
+
keepTabInside(top.card(), e);
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Puts a window on the stack. Escape closes the one in front and Tab stays
|
|
35
|
+
* inside it. Returns the removal, to call however the window closes.
|
|
36
|
+
*/
|
|
37
|
+
export function stackWindow(card, close) {
|
|
38
|
+
const entry = { card, close };
|
|
39
|
+
stack.push(entry);
|
|
40
|
+
if (stack.length === 1)
|
|
41
|
+
document.addEventListener("keydown", onKey);
|
|
42
|
+
return () => {
|
|
43
|
+
const at = stack.indexOf(entry);
|
|
44
|
+
if (at >= 0)
|
|
45
|
+
stack.splice(at, 1);
|
|
46
|
+
if (stack.length === 0)
|
|
47
|
+
document.removeEventListener("keydown", onKey);
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
/** Whether a window is open, for a key handler of the app's that should leave the page alone. */
|
|
51
|
+
export function windowIsOpen() {
|
|
52
|
+
return stack.length > 0;
|
|
53
|
+
}
|
|
54
|
+
const FIELD = 'input:not([type="file"]):not([type="hidden"]):not([disabled]), textarea:not([disabled])';
|
|
55
|
+
/**
|
|
56
|
+
* Where focus goes as a window opens: its first field, so typing can start at
|
|
57
|
+
* once, or else the last button of its foot, the forward action.
|
|
58
|
+
*/
|
|
59
|
+
export function windowFocusTarget(card) {
|
|
60
|
+
const foot = card.querySelectorAll(".glim-modal-foot button:not([disabled])");
|
|
61
|
+
return card.querySelector(FIELD) ?? foot[foot.length - 1] ?? null;
|
|
62
|
+
}
|
package/glyph-map.md
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
| Show, reveal | `IconEye` | `IconEye`, standard | `IconEye`, standard |
|
|
14
14
|
| Hide again | `IconEyeOff` | `IconEyeOff`, standard | `IconEyeOff`, standard |
|
|
15
15
|
| Reset to the default | `IconRefresh` | `IconClearSelection`, switch | `IconRefresh`, standard |
|
|
16
|
+
| Reset one row of a colour card to its defaults | `IconResetArrow` | `IconResetArrow` in `AccentCard.tsx`, switch | none |
|
|
16
17
|
| Retry, reload, refresh | `IconRetry` | `IconRefresh`, switch | `IconRetry`, standard |
|
|
17
18
|
| Upload | `IconUpload` | `IconUpload`, standard | `IconUpload`, standard |
|
|
18
19
|
| Import, read in | `IconImport` | `IconImport`, standard | `IconImport`, standard |
|
|
@@ -82,6 +83,8 @@
|
|
|
82
83
|
| Write to us | `IconMail` | `IconMail`, standard | `IconMail`, standard |
|
|
83
84
|
| Send a test | `IconSendTest` | `IconCheck`, switch | `IconSendTest`, standard |
|
|
84
85
|
| Buy the author a coffee | `IconCoffee` | `IconCoffee`, standard | none |
|
|
86
|
+
| Give through PayPal | `IconPayPal` | `IconPayPal` in `donateMarks.tsx`, switch | `IconPayPal` in `donateMarks.tsx`, switch |
|
|
87
|
+
| Give from a crypto wallet | `IconBitcoin` | `IconBitcoin` in `donateMarks.tsx`, switch | `IconBitcoin` in `donateMarks.tsx`, switch |
|
|
85
88
|
| A protection is on, turn it on | `IconShieldOn` | `IconShieldOn`, standard | `IconShieldOn`, standard |
|
|
86
89
|
| A protection is off, turn it off | `IconShieldOff` | `IconShieldOff`, standard | `IconShieldOff`, standard |
|
|
87
90
|
| Store uncompressed | `IconCompressOff` | `IconCompressOff`, standard | none |
|
|
@@ -125,6 +128,22 @@
|
|
|
125
128
|
| A subtitle file | `IconFileSubtitles` | none | `IconFileSubtitles` before a subtitle file, standard |
|
|
126
129
|
| A description or another text file | `IconFileText` | none | `IconFileText` before a description or a text file, standard |
|
|
127
130
|
| A file, an attachment | `IconFile` | none | `IconFile` before any other file, standard |
|
|
131
|
+
| A RAW photo straight from the camera | `IconFileRaw` | none | none |
|
|
132
|
+
| A design or vector graphic | `IconFileDesign` | none | none |
|
|
133
|
+
| A playlist | `IconFilePlaylist` | none | none |
|
|
134
|
+
| A PDF document | `IconFilePdf` | none | none |
|
|
135
|
+
| A text document from an office suite | `IconFileDoc` | none | none |
|
|
136
|
+
| A spreadsheet | `IconFileSheet` | none | none |
|
|
137
|
+
| A presentation | `IconFileSlides` | none | none |
|
|
138
|
+
| An e-book | `IconBook` | none | none |
|
|
139
|
+
| A disk image or virtual disk | `IconDisc` | none | none |
|
|
140
|
+
| A program or installable package | `IconFileProgram` | none | none |
|
|
141
|
+
| A font | `IconFont` | none | none |
|
|
142
|
+
| A checksum or signature | `IconHash` | none | none |
|
|
143
|
+
| A torrent or magnet link | `IconMagnet` | none | none |
|
|
144
|
+
| A 3D model or CAD drawing | `IconCube` | none | none |
|
|
145
|
+
| A calendar or contact card | `IconCalendar` | none | none |
|
|
146
|
+
| A backup, temporary or unfinished file | `IconHourglass` | none | none |
|
|
128
147
|
| Instances, other boxes | `IconFleet` | `IconFleet`, standard | `IconFleet`, standard |
|
|
129
148
|
| Collector, taking links in | `IconCollector` | none | `IconCollector`, standard |
|
|
130
149
|
| Accounts | `IconAccounts` | none | `IconAccounts`, standard |
|
|
@@ -365,10 +384,39 @@ FireSquire wears seven glyphs on the buttons of its pre-reboot check and on the
|
|
|
365
384
|
|
|
366
385
|
<br>
|
|
367
386
|
|
|
387
|
+
## CannonCommander
|
|
388
|
+
|
|
389
|
+
CannonCommander's new interface draws every glyph from the assortment. The rows below are the meanings that came into it with the file manager, and the others follow once its screens are built.
|
|
390
|
+
|
|
391
|
+
| Meaning | GlimStone | CannonCommander |
|
|
392
|
+
| --- | --- | --- |
|
|
393
|
+
| Reset one row of a colour card to its defaults | `IconResetArrow` | `IconResetArrow`, standard |
|
|
394
|
+
| Give through PayPal | `IconPayPal` | `IconPayPal`, standard |
|
|
395
|
+
| Give from a crypto wallet | `IconBitcoin` | `IconBitcoin`, standard |
|
|
396
|
+
| A RAW photo straight from the camera | `IconFileRaw` | `IconFileRaw`, standard |
|
|
397
|
+
| A design or vector graphic | `IconFileDesign` | `IconFileDesign`, standard |
|
|
398
|
+
| A playlist | `IconFilePlaylist` | `IconFilePlaylist`, standard |
|
|
399
|
+
| A PDF document | `IconFilePdf` | `IconFilePdf`, standard |
|
|
400
|
+
| A text document from an office suite | `IconFileDoc` | `IconFileDoc`, standard |
|
|
401
|
+
| A spreadsheet | `IconFileSheet` | `IconFileSheet`, standard |
|
|
402
|
+
| A presentation | `IconFileSlides` | `IconFileSlides`, standard |
|
|
403
|
+
| An e-book | `IconBook` | `IconBook`, standard |
|
|
404
|
+
| A disk image or virtual disk | `IconDisc` | `IconDisc`, standard |
|
|
405
|
+
| A program or installable package | `IconFileProgram` | `IconFileProgram`, standard |
|
|
406
|
+
| A font | `IconFont` | `IconFont`, standard |
|
|
407
|
+
| A checksum or signature | `IconHash` | `IconHash`, standard |
|
|
408
|
+
| A torrent or magnet link | `IconMagnet` | `IconMagnet`, standard |
|
|
409
|
+
| A 3D model or CAD drawing | `IconCube` | `IconCube`, standard |
|
|
410
|
+
| A calendar or contact card | `IconCalendar` | `IconCalendar`, standard |
|
|
411
|
+
| A backup, temporary or unfinished file | `IconHourglass` | `IconHourglass`, standard |
|
|
412
|
+
|
|
413
|
+
<br>
|
|
414
|
+
|
|
368
415
|
## Where each app keeps its glyphs
|
|
369
416
|
|
|
370
417
|
- **ArrowLoop:** `scripts/gen_glyphs.py` writes the app's glyphs, and the Look settings glyphs come from it, for the web and, through `scripts/gen_glyph_data.py`, for the phone. `web/src/lib/glyphName.ts` maps a translation key to a glyph name, and a key it does not know keeps its text.
|
|
371
418
|
- **BombVault:** `scripts/gen_glyphs.py` writes `web/src/components/glyphs.tsx` and `navGlyphs.tsx` from a copy of `glyphs.json` at 16px; the phone app shows the web launcher and uses the same files. `glyphFor.tsx` maps a translation key to a glyph when a button passes none; a button that passes one wins.
|
|
419
|
+
- **CannonCommander:** the frontend maps a file's kind to a glyph name through `prototype/src/formats.json` and draws the entry from `glyphs.json` through `@glimstone/vue`.
|
|
372
420
|
- **FireSquire:** `firesquire-glyphs.js` beside its scripts holds a copy of every entry it draws, the square viewBox and the drawing, and names the GlimStone release it came from. `plugin/test/glyphs.test.js` checks that every glyph a button asks for is in the copy.
|
|
373
421
|
- **KnightLoader:** `web/scripts/gen-glyphs.mjs` writes `web/src/lib/glyphs.tsx` at 22px with the ink at three quarters of the box; the Android app has no SVG and shows tinted bitmaps rendered from the same list into `mobile/assets/`. Every call site passes its glyph; Settings page glyphs are mapped in `pages/settings/pageIcons.tsx`. The browser extension copies the eye and a few others in `extension/src/`.
|
|
374
422
|
- **ShipLog:** `include/glyphs.php` holds a copy of every entry it draws. `shiplog.page` uses them on the settings page, and `shiplog.Docker.page` hands four of them to `scripts/docker.js` for the changelog window.
|