@gjermundgaraba-designs/pixel-paper 0.17.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/DESIGN.md +16 -8
- package/dist/src/glyph/glyph.d.ts +3 -1
- package/dist/src/glyph/glyph.d.ts.map +1 -1
- package/dist/src/glyph/glyph.js +2 -1
- package/dist/src/glyph/glyphs.d.ts +3 -0
- package/dist/src/glyph/glyphs.d.ts.map +1 -1
- package/dist/src/glyph/glyphs.js +4 -3
- package/dist/src/identity/identity.d.ts +2 -0
- package/dist/src/identity/identity.d.ts.map +1 -1
- package/dist/src/identity/identity.js +8 -2
- package/dist/src/meter/meter.d.ts +5 -1
- package/dist/src/meter/meter.d.ts.map +1 -1
- package/dist/src/meter/meter.js +15 -3
- package/dist/src/monogram/monogram.d.ts +7 -2
- package/dist/src/monogram/monogram.d.ts.map +1 -1
- package/dist/src/monogram/monogram.js +24 -6
- package/dist/src/panel/panel.d.ts +5 -1
- package/dist/src/panel/panel.d.ts.map +1 -1
- package/dist/src/panel/panel.js +7 -3
- package/package.json +1 -1
- package/src/glyph/glyph.ts +2 -1
- package/src/glyph/glyphs.ts +6 -4
- package/src/identity/identity.ts +10 -2
- package/src/meter/meter.ts +18 -2
- package/src/monogram/monogram.ts +46 -6
- package/src/panel/panel.ts +21 -3
- package/src/pixel-paper.css +21 -1
package/DESIGN.md
CHANGED
|
@@ -602,6 +602,14 @@ components:
|
|
|
602
602
|
backgroundColor: "{colors.muted}"
|
|
603
603
|
width: "10px"
|
|
604
604
|
height: "14px"
|
|
605
|
+
meter-cell-toned-high:
|
|
606
|
+
backgroundColor: "{colors.amber}"
|
|
607
|
+
width: "10px"
|
|
608
|
+
height: "14px"
|
|
609
|
+
meter-cell-toned-full:
|
|
610
|
+
backgroundColor: "{colors.red}"
|
|
611
|
+
width: "10px"
|
|
612
|
+
height: "14px"
|
|
605
613
|
strength-cell:
|
|
606
614
|
backgroundColor: "{colors.head}"
|
|
607
615
|
width: "24px"
|
|
@@ -802,9 +810,9 @@ Two neutral palettes over one set of tokens, with three meaning hues shared betw
|
|
|
802
810
|
|
|
803
811
|
### Primary
|
|
804
812
|
|
|
805
|
-
- **Marker Amber** (`{colors.amber}`, both palettes): the Mark (a viewfinder glyph on an amber square beside a marked item), the warn chip (an update waiting, a source behind), a meter reading at or above 80% of its limit, the glyph box of a warning notice, of a confirm dialog and of a reconnecting banner; a stat's change or a bar's reading that the product calls a warning. Always carries Printer Ink text (`{colors.on-status}`); an amber glyph on paper is never allowed because it fails contrast. Where every row is marked the Mark prints plain (muted, no fill): amber is for the one among many.
|
|
813
|
+
- **Marker Amber** (`{colors.amber}`, both palettes): the Mark (a viewfinder glyph on an amber square beside a marked item), the warn chip (an update waiting, a source behind), a meter reading at or above 80% of its limit and a toned meter's lit cells there, the glyph box of a warning notice, of a confirm dialog and of a reconnecting banner; a stat's change or a bar's reading that the product calls a warning. Always carries Printer Ink text (`{colors.on-status}`); an amber glyph on paper is never allowed because it fails contrast. Where every row is marked the Mark prints plain (muted, no fill): amber is for the one among many.
|
|
806
814
|
- **Active Green** (`{colors.green}`, both palettes): the go chip of something that is live or in sync. Also carries Printer Ink text. Nothing else is green.
|
|
807
|
-
- **Urgent Red** (`{colors.red}` paper / `{colors.red-plum}` plum): the danger button's text, border and shadow tint; the blocked and limit-reached chips; a field's error line; the error notice's and error toast's border and glyph box; the offline word and an offline banner's glyph box; a stat's change or a bar's reading at fault; a broken image, video or audio frame; a stale age, a late due day (on a cursor row or card, a red slip with `on-red` text), a failed check, a stale meter's foot; a failed field's rule and label, a failed radio or select box, a fieldset's legend over a failed control; a link to a page that does not exist; the minus sign of a deleted diff line. Red fills carry Paper White text on paper (`{colors.on-red}`) and Printer Ink on plum (`{colors.on-red-plum}`), because plum lightens red for text contrast.
|
|
815
|
+
- **Urgent Red** (`{colors.red}` paper / `{colors.red-plum}` plum): the danger button's text, border and shadow tint; the blocked and limit-reached chips; a toned meter's lit cells at its limit; a field's error line; the error notice's and error toast's border and glyph box; the offline word and an offline banner's glyph box; a stat's change or a bar's reading at fault; a broken image, video or audio frame; a stale age, a late due day (on a cursor row or card, a red slip with `on-red` text), a failed check, a stale meter's foot; a failed field's rule and label, a failed radio or select box, a fieldset's legend over a failed control; a link to a page that does not exist; the minus sign of a deleted diff line. Red fills carry Paper White text on paper (`{colors.on-red}`) and Printer Ink on plum (`{colors.on-red-plum}`), because plum lightens red for text contrast.
|
|
808
816
|
|
|
809
817
|
### Neutral
|
|
810
818
|
|
|
@@ -824,7 +832,7 @@ What a program prints (terminal output, highlighted code, a log) is content, not
|
|
|
824
832
|
|
|
825
833
|
**The Content Ink Rule.** The `--term-*` and `--code-*` tokens colour only what a program printed, inside a code surface, a terminal, a log or a library adapter. They never colour chrome, state, a border, a fill or a person: a busy build is a chip, not a cyan word, and presence is a Monogram, not a hue.
|
|
826
834
|
|
|
827
|
-
**The Meaning Colour Rule.** Amber means marked or warning, green means active or in sync, red means urgent, offline, error, missing or destructive. Every other colour on a surface is a neutral token. A new element that wants colour must be one of those three meanings, or it is ink (content inks aside; see the Content Ink Rule). A meter's cells stay ink at every level
|
|
835
|
+
**The Meaning Colour Rule.** Amber means marked or warning, green means active or in sync, red means urgent, offline, error, missing or destructive. Every other colour on a surface is a neutral token. A new element that wants colour must be one of those three meanings, or it is ink (content inks aside; see the Content Ink Rule). A meter's cells stay ink at every level and the reading beside them carries the colour, except in a toned meter (`isToned`): on a page whose readings are scanned for their level, a wall of limits, the lit cells take the reading's amber from 80% and its red at the limit, and the reading beside them still says so in a mark or a chip, so the level never rests on colour. A search hit is inverted ink and a list's cursor row a muted outline, never amber, because a hit is a selection, not a warning. Charts and stats keep the rule: bar cells and the line stay ink (a second series is muted ink with smaller cells, never a hue), and a stat's change prints in ink with a direction glyph, because up is not good and down is not bad until the product says so; only a reading the product calls a warning or a fault takes amber or red.
|
|
828
836
|
|
|
829
837
|
**The Red On Commit Rule.** Red never rests on a button. Row and form actions that destroy something (disable, delete, restore over, reset) are neutral buttons; the ConfirmDialog they open carries the one red button, the commit. Red at rest belongs to states only: a blocked chip, a failed check, a missing page, the offline word. A `ConfirmDialog` with `isDanger` is the only destructive confirm: there is no inline arm-then-confirm button ("delete" that turns into "sure?"), because the dialog gives the commit protected focus (cancel is the default) and an alert dialog's semantics, while an armed button is easy to double-click through and shifts the layout as its word changes.
|
|
830
838
|
|
|
@@ -1027,9 +1035,9 @@ The printed button: a paper rectangle in a 2px ink frame that casts a 3px shadow
|
|
|
1027
1035
|
|
|
1028
1036
|
### Monograms
|
|
1029
1037
|
|
|
1030
|
-
**Monogram** → `span.monogram[role="img"][aria-label]` (`.large`, `.current`): one or two letters (the label's initials, or `letters`) in the 11px pixel face, uppercase, centred in a 22px square closed by a 2px ink border on paper; large is 34px with 14px letters, for a card of readings or a wall. `isCurrent` inverts it: you, among others. `isDecorative` → `span.monogram[aria-hidden="true"]`, for a monogram beside the same name in words, which screen readers then hear once. The system draws no logos: a provider, a source, a harness or a person is a monogram beside its name, never a brand mark and
|
|
1038
|
+
**Monogram** → `span.monogram[role="img"][aria-label]` (`.large`, `.current`): one or two letters (the label's initials, or `letters`) in the 11px pixel face, uppercase, centred in a 22px square closed by a 2px ink border on paper; large is 34px with 14px letters, for a card of readings or a wall. `isCurrent` inverts it: you, among others. `isDecorative` → `span.monogram[aria-hidden="true"]`, for a monogram beside the same name in words, which screen readers then hear once. The system draws no logos of its own: a provider, a source, a harness or a person is a monogram beside its name, never a picture and never a brand colour. Where the product knows a provider's own mark, it may redraw it in cells (`drawing`: rows of `#` and `.`, as a glyph is drawn) → `span.monogram.drawn > svg.px-icon`: the mark prints bare in ink, without the border or the paper, in the square the letters would take, a pixel per cell (two in a large monogram, so a 16-cell drawing is 32px in the 34px square); `isCurrent` sets it in paper on an ink square.
|
|
1031
1039
|
|
|
1032
|
-
**Identity** → `div.identity (.large) > span.monogram[aria-hidden="true"] + span.identity-text > strong + span.meta`: that pairing as one piece, its name read once (the monogram is decorative beside it). The name in the sans at 600 (16px when large, beside the large monogram, as a card's subject), wrapping rather than clipping; under it a meta line of whatever says which one (an id in code, a kind in a Tag), 8px apart and wrapping. A consent card names the client asking with it; a list of sources, harnesses or people names each.
|
|
1040
|
+
**Identity** → `div.identity (.large) > span.monogram[aria-hidden="true"] + span.identity-text > strong + span.meta`: that pairing as one piece (its monogram letters or drawn), its name read once (the monogram is decorative beside it). The name in the sans at 600 (16px when large, beside the large monogram, as a card's subject), wrapping rather than clipping; under it a meta line of whatever says which one (an id in code, a kind in a Tag), 8px apart and wrapping. A consent card names the client asking with it; a list of sources, harnesses or people names each.
|
|
1033
1041
|
|
|
1034
1042
|
### Time
|
|
1035
1043
|
|
|
@@ -1037,7 +1045,7 @@ The printed button: a paper rectangle in a 2px ink frame that casts a 3px shadow
|
|
|
1037
1045
|
|
|
1038
1046
|
### Panels
|
|
1039
1047
|
|
|
1040
|
-
- **Panel** → `section.panel[aria-labelledby]
|
|
1048
|
+
- **Panel** → `section.panel[aria-labelledby]` (`[aria-label]` with `name`) `> header.panel-tb > span.panel-lead + h2 + span.meta`, then `div.panel-body` (or the body directly when `isFlush`), then `div.panel-foot`. The section is named by its title, or by `name` where the title repeats among its siblings (panels titled by a kind, one per account), so each landmark keeps a name of its own. It is keyed by its `id`, so a panel among siblings that come and go keeps its own element, and a panel under another id is another element: one that replaces another in the same place is built anew (a live region inside it is inserted, not kept), so keep one panel under one id across states that should share it. Square, 2px ink border, Paper White, panel shadow. The title bar is inverted Departure Mono 13px uppercase 0.08em (`--tracking-title`), `padding: 6px 12px`; its meta is 11px at 75% opacity. A control in a title bar (a panel's, a window's or a card's) rings in paper, 2px inside its own edge, because the ink ring would vanish on the ink bar. The body pads 16px with a 14px grid gap; the foot pads `10px 12px` over a 1px rule, with a `.push` slot that goes right. `actions` puts small Buttons and IconButtons in `span.panel-acts` (6px apart) at the title bar's right end, after the meta; the bar trims to `3px 3px 3px 12px` at 31px or more. `lead` puts a quiet IconButton in `span.panel-lead` before the title (a Sortable's grip), and the bar trims its left to 3px the same way; a quiet icon button there prints in paper, hovered too, and held at 60%. On the ink bar a button is a paper outline (a primary one fills paper), flat, nudged 1px when pressed, its ring 4px inside in its own colour; disabled, it prints at 60%.
|
|
1041
1049
|
- **Deck** → `main.deck#main`: the column of panels.
|
|
1042
1050
|
- **EmptyState** → `div.empty > h3.empty-title + p`: `headingLevel` is required and picks the title's element, which looks the same at every level. Where the empty state is a page's or a section's main content it is a heading, `3` inside a Panel (whose title is an `h2`), `1` for a gate or a missing page; `"Strong"` prints `strong.empty-title` where it is not (a chart with nothing to chart, a picture of the state). Centred, `26px 16px`, a 12px uppercase 0.08em (`--tracking-title`) headline, a muted 46ch sentence, an optional action 6px below.
|
|
1043
1051
|
- **Wall** → `main.wall`, `Wall.markView` → `div.wall-mark` (a 30px ink-bordered glyph box beside the 22px wordmark). `Wall.cornerView` → `aside.wall-corner[aria-label]`, rendered just before the Wall: a paper slip in a 2px ink box on the 3px shadow, `6px 8px`, holding what a top bar would (see Layout).
|
|
@@ -1139,7 +1147,7 @@ One keyboard for the page, Vim first, with the arrows beside the letters. The ke
|
|
|
1139
1147
|
|
|
1140
1148
|
### Meters and cells
|
|
1141
1149
|
|
|
1142
|
-
**Cells** (`Meter.cellsView`) → `span.cells[role="meter"] > span.cell (.on)` (`.short` for 24×8px cells). **Meter** (over `@foldkit/ui`'s Meter) → `li.meter-row (.stale)` in `Meter.listView` → `ul.meters`: a reading against a maximum in the vocabulary of `<meter>` (`value`, `max`): the label (name register) and an optional detail (meta) beside twenty cells lit in ink up to the reading; then the reading's state (the percentage in the 12px pixel face below 80% of max, the amber reading mark from 80%, a red chip at max holding `full` or the percentage; below max it never prints 100% or lights every cell, so 49,999 of 50,000 reads 99% with 19 cells); then the numbers (or `valueText`) in 11px muted tabular figures, formatted in English (`41,200`) so server and browser agree, left out with `hasNumbers: false` where they would repeat the percentage (`valueText: "62% used"` beside 62%; screen readers still hear it); then `div.meter-foot` (resets, last read; `.late` red). `ul.meters` is a size container (`container: meters`), so a row lays out by the column it is placed in, not the window: from 560px the name and detail sit in a left column (180px to 240px) beside the cells; narrower, the row stacks and the numbers take a line of their own; under 280px, 240px and 200px the cells step down to 8, 6 and 4px wide, whole pixels. A meter list fits any column from 160px; give it the column's width (a flush panel's body), since a size container takes no width from its content. A stale meter (`isStale`: the last reading failed, the numbers are the last known) prints its lit cells muted and its name ends in "(stale)" for screen readers (`span.sr-only`), so the state never rests on colour; the caller says why and when it was last read in the foot line.
|
|
1150
|
+
**Cells** (`Meter.cellsView`) → `span.cells[role="meter"] > span.cell (.on)` (`.short` for 24×8px cells). **Meter** (over `@foldkit/ui`'s Meter) → `li.meter-row (.stale, .toned (.high, .full))` in `Meter.listView` → `ul.meters`: a reading against a maximum in the vocabulary of `<meter>` (`value`, `max`): the label (name register) and an optional detail (meta) beside twenty cells lit in ink up to the reading; then the reading's state (the percentage in the 12px pixel face below 80% of max, the amber reading mark from 80%, a red chip at max holding `full` or the percentage; below max it never prints 100% or lights every cell, so 49,999 of 50,000 reads 99% with 19 cells); then the numbers (or `valueText`) in 11px muted tabular figures, formatted in English (`41,200`) so server and browser agree, left out with `hasNumbers: false` where they would repeat the percentage (`valueText: "62% used"` beside 62%; screen readers still hear it); then `div.meter-foot` (resets, last read; `.late` red). `ul.meters` is a size container (`container: meters`), so a row lays out by the column it is placed in, not the window: from 560px the name and detail sit in a left column (180px to 240px) beside the cells; narrower, the row stacks and the numbers take a line of their own; under 280px, 240px and 200px the cells step down to 8, 6 and 4px wide, whole pixels. A meter list fits any column from 160px; give it the column's width (a flush panel's body), since a size container takes no width from its content. A stale meter (`isStale`: the last reading failed, the numbers are the last known) prints its lit cells muted and its name ends in "(stale)" for screen readers (`span.sr-only`), so the state never rests on colour; the caller says why and when it was last read in the foot line. A toned meter (`isToned`) lights its cells amber from 80% (`.toned.high`) and red at max (`.toned.full`), beside the same mark or chip; for a page of readings scanned for their level, such as a wall of limits, where the cells are what the eye finds first. A stale reading's muted cells win over the tone.
|
|
1143
1151
|
|
|
1144
1152
|
### Stats
|
|
1145
1153
|
|
|
@@ -1251,7 +1259,7 @@ Each component is `src/<name>/<name>.ts` with an explicit `index.ts`, a colocate
|
|
|
1251
1259
|
- **Don't** round a corner, blur a shadow, or tint a shadow with anything other than Shadow (or Danger Shadow on a danger button).
|
|
1252
1260
|
- **Don't** use amber, green or red for decoration, and don't put an amber or green glyph on paper without its fill.
|
|
1253
1261
|
- **Don't** let a content ink (`--term-*`, `--code-*`) out of code, terminals and logs: not on a chip, a border, a state word or a person.
|
|
1254
|
-
- **Don't** colour a meter's cells by level, or highlight a search hit in amber; the warning lives in the reading and a hit is a selection.
|
|
1262
|
+
- **Don't** colour a meter's cells by level outside a toned meter, or highlight a search hit in amber; the warning lives in the reading and a hit is a selection.
|
|
1255
1263
|
- **Don't** chart in hues, curves, diagonals or filled areas, or colour a stat's change by its direction; cells and stepped lines stay ink and only a toned reading carries colour.
|
|
1256
1264
|
- **Don't** print figures as a row of raised cards each holding one big number; Stats are ruled cells in a flush panel that names what they measure.
|
|
1257
1265
|
- **Don't** build an inline arm-then-confirm button ("delete" that turns into "sure?"); the one destructive confirm is a ConfirmDialog with `isDanger`.
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import type { Html, HtmlBuilder } from "foldkit/html";
|
|
2
|
-
import { type GlyphName } from "./glyphs.ts";
|
|
2
|
+
import { type Cell, type GlyphName } from "./glyphs.ts";
|
|
3
3
|
/** Configuration for rendering a glyph with `view`. */
|
|
4
4
|
export type ViewConfig = Readonly<{
|
|
5
5
|
name: GlyphName;
|
|
6
6
|
/** Rendered size in px. The grid is always 12x12; 12 is the size it was drawn for. */
|
|
7
7
|
size?: number;
|
|
8
8
|
}>;
|
|
9
|
+
/** One inked rectangle of a drawing, in `currentColor`. */
|
|
10
|
+
export declare const cellView: <Message>(h: HtmlBuilder<Message>) => ([x, y, width, height]: Cell) => Html;
|
|
9
11
|
/** One glyph from the inventory, in `currentColor`. Decorative: label the control that holds
|
|
10
12
|
* it. */
|
|
11
13
|
export declare const view: <Message>(config: ViewConfig, h: HtmlBuilder<Message>) => Html;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"glyph.d.ts","sourceRoot":"","sources":["../../../src/glyph/glyph.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEtD,OAAO,
|
|
1
|
+
{"version":3,"file":"glyph.d.ts","sourceRoot":"","sources":["../../../src/glyph/glyph.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEtD,OAAO,EAAE,KAAK,IAAI,EAAE,KAAK,SAAS,EAAU,MAAM,aAAa,CAAC;AAMhE,uDAAuD;AACvD,MAAM,MAAM,UAAU,GAAG,QAAQ,CAAC;IAChC,IAAI,EAAE,SAAS,CAAC;IAChB,sFAAsF;IACtF,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC,CAAC;AAEH,2DAA2D;AAC3D,eAAO,MAAM,QAAQ,GAClB,OAAO,KAAK,WAAW,CAAC,OAAO,CAAC,6BACT,IAAI,KAAG,IAO3B,CAAC;AAEP;UACU;AACV,eAAO,MAAM,IAAI,GAAI,OAAO,UAAU,UAAU,KAAK,WAAW,CAAC,OAAO,CAAC,KAAG,IAa3E,CAAC"}
|
package/dist/src/glyph/glyph.js
CHANGED
|
@@ -3,7 +3,8 @@ import { Array } from "effect";
|
|
|
3
3
|
import { glyphs } from "./glyphs.js";
|
|
4
4
|
// VIEW
|
|
5
5
|
const DRAWN_SIZE = 12;
|
|
6
|
-
|
|
6
|
+
/** One inked rectangle of a drawing, in `currentColor`. */
|
|
7
|
+
export const cellView = (h) => __foldkitBrandViewResult((([x, y, width, height]) => __foldkitBrandViewResult((h.rect([
|
|
7
8
|
h.X(`${x}`),
|
|
8
9
|
h.Y(`${y}`),
|
|
9
10
|
h.Width(`${width}`),
|
|
@@ -374,6 +374,9 @@ export type GlyphName = {
|
|
|
374
374
|
}[keyof Families];
|
|
375
375
|
/** The rows of a drawing, trimmed: twelve strings of twelve `#` or `.` for a well-drawn glyph. */
|
|
376
376
|
export declare const artRows: (art: string) => ReadonlyArray<string>;
|
|
377
|
+
/** A drawing as rectangles one cell tall: one for each horizontal run of ink in each row,
|
|
378
|
+
* up to `width` cells into the row. */
|
|
379
|
+
export declare const toCells: (art: string, width: number) => ReadonlyArray<Cell>;
|
|
377
380
|
/** Every glyph as the rectangles `Glyph.view` draws. */
|
|
378
381
|
export declare const glyphs: Record.ReadonlyRecord<GlyphName, ReadonlyArray<Cell>>;
|
|
379
382
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"glyphs.d.ts","sourceRoot":"","sources":["../../../src/glyph/glyphs.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"glyphs.d.ts","sourceRoot":"","sources":["../../../src/glyph/glyphs.ts"],"names":[],"mappings":"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"}
|
package/dist/src/glyph/glyphs.js
CHANGED
|
@@ -2589,14 +2589,15 @@ const GRID_SIZE = 12;
|
|
|
2589
2589
|
/** The rows of a drawing, trimmed: twelve strings of twelve `#` or `.` for a well-drawn glyph. */
|
|
2590
2590
|
export const artRows = (art) => __foldkitBrandViewResult((pipe(art, String.trim, String.split("\n"), Array.map(String.trim))), "@gjermundgaraba-designs/pixel-paper/src/glyph/glyphs.js#artRows");
|
|
2591
2591
|
const INK_RUN = /#+/g;
|
|
2592
|
-
/** A drawing as rectangles one cell tall: one for each horizontal run of ink in each row
|
|
2593
|
-
|
|
2592
|
+
/** A drawing as rectangles one cell tall: one for each horizontal run of ink in each row,
|
|
2593
|
+
* up to `width` cells into the row. */
|
|
2594
|
+
export const toCells = (art, width) => __foldkitBrandViewResult((Array.flatMap(artRows(art), (row, y) => __foldkitBrandViewResult((Array.map(Array.fromIterable(row.slice(0, width).matchAll(INK_RUN)), (run) => __foldkitBrandViewResult(([
|
|
2594
2595
|
run.index,
|
|
2595
2596
|
y,
|
|
2596
2597
|
run[0].length,
|
|
2597
2598
|
1,
|
|
2598
2599
|
]), "@gjermundgaraba-designs/pixel-paper/src/glyph/glyphs.js#anonymous~2"))), "@gjermundgaraba-designs/pixel-paper/src/glyph/glyphs.js#anonymous"))), "@gjermundgaraba-designs/pixel-paper/src/glyph/glyphs.js#toCells");
|
|
2599
|
-
const drawFamily = (family) => __foldkitBrandViewResult((Record.map(family, toCells)), "@gjermundgaraba-designs/pixel-paper/src/glyph/glyphs.js#drawFamily");
|
|
2600
|
+
const drawFamily = (family) => __foldkitBrandViewResult((Record.map(family, (art) => __foldkitBrandViewResult((toCells(art, GRID_SIZE)), "@gjermundgaraba-designs/pixel-paper/src/glyph/glyphs.js#anonymous~3"))), "@gjermundgaraba-designs/pixel-paper/src/glyph/glyphs.js#drawFamily");
|
|
2600
2601
|
/** Every glyph as the rectangles `Glyph.view` draws. */
|
|
2601
2602
|
export const glyphs = {
|
|
2602
2603
|
...drawFamily(direction),
|
|
@@ -5,6 +5,8 @@ export type ViewConfig = Readonly<{
|
|
|
5
5
|
label: string;
|
|
6
6
|
/** The monogram's letters, when the name's initials are not the ones people know. */
|
|
7
7
|
letters?: string;
|
|
8
|
+
/** The monogram's mark drawn in cells, in place of its letters (see Monogram). */
|
|
9
|
+
drawing?: string;
|
|
8
10
|
/** A line under the name: an id, a kind, a scope. */
|
|
9
11
|
meta?: ReadonlyArray<Html | string>;
|
|
10
12
|
/** Beside a name set large, as a card's subject. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"identity.d.ts","sourceRoot":"","sources":["../../../src/identity/identity.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAOtD,2DAA2D;AAC3D,MAAM,MAAM,UAAU,GAAG,QAAQ,CAAC;IAChC,uDAAuD;IACvD,KAAK,EAAE,MAAM,CAAC;IACd,qFAAqF;IACrF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,qDAAqD;IACrD,IAAI,CAAC,EAAE,aAAa,CAAC,IAAI,GAAG,MAAM,CAAC,CAAC;IACpC,oDAAoD;IACpD,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC,CAAC;AAEH;qFACqF;AACrF,eAAO,MAAM,IAAI,GAAI,OAAO,UAAU,UAAU,KAAK,WAAW,CAAC,OAAO,CAAC,KAAG,
|
|
1
|
+
{"version":3,"file":"identity.d.ts","sourceRoot":"","sources":["../../../src/identity/identity.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAOtD,2DAA2D;AAC3D,MAAM,MAAM,UAAU,GAAG,QAAQ,CAAC;IAChC,uDAAuD;IACvD,KAAK,EAAE,MAAM,CAAC;IACd,qFAAqF;IACrF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,kFAAkF;IAClF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,qDAAqD;IACrD,IAAI,CAAC,EAAE,aAAa,CAAC,IAAI,GAAG,MAAM,CAAC,CAAC;IACpC,oDAAoD;IACpD,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC,CAAC;AAEH;qFACqF;AACrF,eAAO,MAAM,IAAI,GAAI,OAAO,UAAU,UAAU,KAAK,WAAW,CAAC,OAAO,CAAC,KAAG,IAsB3E,CAAC"}
|
|
@@ -4,9 +4,15 @@ import { slotView } from "../slot/slot.js";
|
|
|
4
4
|
/** Who or what something is: its monogram beside its name in the sans, and a meta line.
|
|
5
5
|
* Screen readers hear the name once: the monogram beside it is hidden from them. */
|
|
6
6
|
export const view = (config, h) => {
|
|
7
|
-
const { label, letters, meta = [], isLarge = false } = config;
|
|
7
|
+
const { label, letters, drawing, meta = [], isLarge = false } = config;
|
|
8
8
|
return __foldkitBrandViewResult((h.div([h.Class(isLarge ? "identity large" : "identity")], [
|
|
9
|
-
Monogram.view({
|
|
9
|
+
Monogram.view({
|
|
10
|
+
label,
|
|
11
|
+
...(letters !== undefined && { letters }),
|
|
12
|
+
...(drawing !== undefined && { drawing }),
|
|
13
|
+
isLarge,
|
|
14
|
+
isDecorative: true,
|
|
15
|
+
}, h),
|
|
10
16
|
h.span([h.Class("identity-text")], [h.strong([], [label]), ...slotView("span", "meta", meta, h)]),
|
|
11
17
|
])), "@gjermundgaraba-designs/pixel-paper/src/identity/identity.js#view");
|
|
12
18
|
};
|
|
@@ -37,6 +37,10 @@ export type MeterConfig = Readonly<{
|
|
|
37
37
|
hasNumbers?: boolean;
|
|
38
38
|
/** In a red chip once the value reaches `max`. The percentage by default. */
|
|
39
39
|
full?: string;
|
|
40
|
+
/** The lit cells take the reading's tone as well: amber from 80%, red at `max`. For a page
|
|
41
|
+
* of readings scanned for their level, such as a wall of limits; the reading beside the
|
|
42
|
+
* cells still says it in a mark or a chip. */
|
|
43
|
+
isToned?: boolean;
|
|
40
44
|
/** The last reading failed: the cells print muted, the numbers are the last known, and
|
|
41
45
|
* screen readers hear "(stale)" after the name. Say why, and when it was last read, in
|
|
42
46
|
* `foot`. */
|
|
@@ -52,7 +56,7 @@ export type ListViewConfig = Readonly<{
|
|
|
52
56
|
* A ruled list of meters, edge to edge in a flush panel. Each is a named reading against a
|
|
53
57
|
* maximum, in the vocabulary of `<meter>`, built on `@foldkit/ui`'s Meter: 20 cells, the
|
|
54
58
|
* percentage (amber from 80%, a red chip at `max`, and neither 100% nor every cell before it),
|
|
55
|
-
* the numbers in English, a foot line. The cells are the `meter`, named by the printed label,
|
|
59
|
+
* the numbers in English, a foot line. The cells print ink unless the meter `isToned`. The cells are the `meter`, named by the printed label,
|
|
56
60
|
* with the value, the maximum and the numbers in words for screen readers.
|
|
57
61
|
*/
|
|
58
62
|
export declare const listView: <Message>(config: ListViewConfig, h: HtmlBuilder<Message>) => Html;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"meter.d.ts","sourceRoot":"","sources":["../../../src/meter/meter.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAatD,0DAA0D;AAC1D,MAAM,MAAM,WAAW,GAAG,QAAQ,CAAC;IACjC,uDAAuD;IACvD,EAAE,EAAE,MAAM,CAAC;IACX,gEAAgE;IAChE,KAAK,EAAE,MAAM,CAAC;IACd,0BAA0B;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,4CAA4C;IAC5C,KAAK,EAAE,MAAM,CAAC;IACd,wEAAwE;IACxE,SAAS,EAAE,MAAM,CAAC;IAClB,qDAAqD;IACrD,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC,CAAC;AASH;0EAC0E;AAC1E,eAAO,MAAM,SAAS,GAAI,OAAO,UAAU,WAAW,KAAK,WAAW,CAAC,OAAO,CAAC,KAAG,IAmBjF,CAAC;AAIF,iCAAiC;AACjC,MAAM,MAAM,WAAW,GAAG,QAAQ,CAAC;IACjC,uDAAuD;IACvD,EAAE,EAAE,MAAM,CAAC;IACX,4CAA4C;IAC5C,KAAK,EAAE,MAAM,CAAC;IACd,2DAA2D;IAC3D,MAAM,CAAC,EAAE,aAAa,CAAC,IAAI,GAAG,MAAM,CAAC,CAAC;IACtC,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,+CAA+C;IAC/C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;yCACqC;IACrC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;uFACmF;IACnF,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,6EAA6E;IAC7E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;kBAEc;IACd,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,uDAAuD;IACvD,IAAI,CAAC,EAAE,aAAa,CAAC,IAAI,GAAG,MAAM,CAAC,CAAC;CACrC,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"meter.d.ts","sourceRoot":"","sources":["../../../src/meter/meter.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAatD,0DAA0D;AAC1D,MAAM,MAAM,WAAW,GAAG,QAAQ,CAAC;IACjC,uDAAuD;IACvD,EAAE,EAAE,MAAM,CAAC;IACX,gEAAgE;IAChE,KAAK,EAAE,MAAM,CAAC;IACd,0BAA0B;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,4CAA4C;IAC5C,KAAK,EAAE,MAAM,CAAC;IACd,wEAAwE;IACxE,SAAS,EAAE,MAAM,CAAC;IAClB,qDAAqD;IACrD,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC,CAAC;AASH;0EAC0E;AAC1E,eAAO,MAAM,SAAS,GAAI,OAAO,UAAU,WAAW,KAAK,WAAW,CAAC,OAAO,CAAC,KAAG,IAmBjF,CAAC;AAIF,iCAAiC;AACjC,MAAM,MAAM,WAAW,GAAG,QAAQ,CAAC;IACjC,uDAAuD;IACvD,EAAE,EAAE,MAAM,CAAC;IACX,4CAA4C;IAC5C,KAAK,EAAE,MAAM,CAAC;IACd,2DAA2D;IAC3D,MAAM,CAAC,EAAE,aAAa,CAAC,IAAI,GAAG,MAAM,CAAC,CAAC;IACtC,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,+CAA+C;IAC/C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;yCACqC;IACrC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;uFACmF;IACnF,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,6EAA6E;IAC7E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;mDAE+C;IAC/C,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;kBAEc;IACd,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,uDAAuD;IACvD,IAAI,CAAC,EAAE,aAAa,CAAC,IAAI,GAAG,MAAM,CAAC,CAAC;CACrC,CAAC,CAAC;AAoGH,oEAAoE;AACpE,MAAM,MAAM,cAAc,GAAG,QAAQ,CAAC;IACpC,MAAM,EAAE,aAAa,CAAC,WAAW,CAAC,CAAC;CACpC,CAAC,CAAC;AAEH;;;;;;GAMG;AACH,eAAO,MAAM,QAAQ,GAAI,OAAO,UAAU,cAAc,KAAK,WAAW,CAAC,OAAO,CAAC,KAAG,IAMjF,CAAC"}
|
package/dist/src/meter/meter.js
CHANGED
|
@@ -47,18 +47,30 @@ const percentView = (config, percent, isFull, h) => {
|
|
|
47
47
|
return __foldkitBrandViewResult((h.span([h.Class("pct")], [percentText])), "@gjermundgaraba-designs/pixel-paper/src/meter/meter.js#percentView");
|
|
48
48
|
}
|
|
49
49
|
};
|
|
50
|
+
const toneClass = (value, max, isFull) => {
|
|
51
|
+
if (isFull) {
|
|
52
|
+
return __foldkitBrandViewResult((" toned full"), "@gjermundgaraba-designs/pixel-paper/src/meter/meter.js#toneClass");
|
|
53
|
+
}
|
|
54
|
+
else if (value >= max * HIGH_SHARE) {
|
|
55
|
+
return __foldkitBrandViewResult((" toned high"), "@gjermundgaraba-designs/pixel-paper/src/meter/meter.js#toneClass");
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
return __foldkitBrandViewResult((" toned"), "@gjermundgaraba-designs/pixel-paper/src/meter/meter.js#toneClass");
|
|
59
|
+
}
|
|
60
|
+
};
|
|
50
61
|
const meterView = (config, h) => {
|
|
51
|
-
const { id, label, value, max, detail = [], foot = [], isStale = false, hasNumbers = true, } = config;
|
|
62
|
+
const { id, label, value, max, detail = [], foot = [], isStale = false, hasNumbers = true, isToned = false, } = config;
|
|
52
63
|
const share = max > 0 ? Math.min(1, Math.max(0, value / max)) : 0;
|
|
53
64
|
const isFull = value >= max;
|
|
54
65
|
const numbers = config.valueText ?? numbersText(value, max, config.unit);
|
|
66
|
+
const rowClass = `meter-row${isStale ? " stale" : ""}${isToned ? toneClass(value, max, isFull) : ""}`;
|
|
55
67
|
return __foldkitBrandViewResult((UiMeter.view({
|
|
56
68
|
id,
|
|
57
69
|
value,
|
|
58
70
|
min: 0,
|
|
59
71
|
max,
|
|
60
72
|
valueText: numbers,
|
|
61
|
-
toView: (groups) => __foldkitBrandViewResult((h.keyed("li")(id, [h.Class(
|
|
73
|
+
toView: (groups) => __foldkitBrandViewResult((h.keyed("li")(id, [h.Class(rowClass)], [
|
|
62
74
|
h.div([h.Class("meter-head")], [
|
|
63
75
|
h.span([...groups.label, h.Class("meter-name")], [label, ...(isStale ? [h.span([h.Class("sr-only")], [" (stale)"])] : [])]),
|
|
64
76
|
...slotView("span", "meter-detail", detail, h),
|
|
@@ -76,7 +88,7 @@ const meterView = (config, h) => {
|
|
|
76
88
|
* A ruled list of meters, edge to edge in a flush panel. Each is a named reading against a
|
|
77
89
|
* maximum, in the vocabulary of `<meter>`, built on `@foldkit/ui`'s Meter: 20 cells, the
|
|
78
90
|
* percentage (amber from 80%, a red chip at `max`, and neither 100% nor every cell before it),
|
|
79
|
-
* the numbers in English, a foot line. The cells are the `meter`, named by the printed label,
|
|
91
|
+
* the numbers in English, a foot line. The cells print ink unless the meter `isToned`. The cells are the `meter`, named by the printed label,
|
|
80
92
|
* with the value, the maximum and the numbers in words for screen readers.
|
|
81
93
|
*/
|
|
82
94
|
export const listView = (config, h) => __foldkitBrandViewResult((h.ul(
|
|
@@ -5,6 +5,11 @@ export type ViewConfig = Readonly<{
|
|
|
5
5
|
label: string;
|
|
6
6
|
/** One or two letters, when the name's initials are not the ones people know. */
|
|
7
7
|
letters?: string;
|
|
8
|
+
/** A mark the product draws in cells, in place of the letters: rows of `#` (ink) and `.`,
|
|
9
|
+
* as a glyph is drawn, on a grid of up to 16 for a large monogram. It prints bare, in ink,
|
|
10
|
+
* a pixel per cell (two when large): a provider's own mark redrawn in the system's
|
|
11
|
+
* cells, never a picture or a brand colour. */
|
|
12
|
+
drawing?: string;
|
|
8
13
|
/** 34px, beside a name set large (a card of readings, a wall). */
|
|
9
14
|
isLarge?: boolean;
|
|
10
15
|
/** You, among others: the monogram inverts. */
|
|
@@ -13,7 +18,7 @@ export type ViewConfig = Readonly<{
|
|
|
13
18
|
* the name once, from the words. */
|
|
14
19
|
isDecorative?: boolean;
|
|
15
20
|
}>;
|
|
16
|
-
/** Letters in an ink square
|
|
17
|
-
*
|
|
21
|
+
/** Letters in an ink square, or a mark the product draws in cells: the identity of a person,
|
|
22
|
+
* a provider or a source. An image named by `label`, or hidden when `isDecorative`. */
|
|
18
23
|
export declare const view: <Message>(config: ViewConfig, h: HtmlBuilder<Message>) => Html;
|
|
19
24
|
//# sourceMappingURL=monogram.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"monogram.d.ts","sourceRoot":"","sources":["../../../src/monogram/monogram.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"monogram.d.ts","sourceRoot":"","sources":["../../../src/monogram/monogram.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAsDtD,0DAA0D;AAC1D,MAAM,MAAM,UAAU,GAAG,QAAQ,CAAC;IAChC,0EAA0E;IAC1E,KAAK,EAAE,MAAM,CAAC;IACd,iFAAiF;IACjF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;oDAGgD;IAChD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,kEAAkE;IAClE,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,+CAA+C;IAC/C,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;yCACqC;IACrC,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB,CAAC,CAAC;AAEH;wFACwF;AACxF,eAAO,MAAM,IAAI,GAAI,OAAO,UAAU,UAAU,KAAK,WAAW,CAAC,OAAO,CAAC,KAAG,IAmB3E,CAAC"}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { brandViewResult as __foldkitBrandViewResult } from 'foldkit/brand'
|
|
2
|
-
import { Array, String, pipe } from "effect";
|
|
2
|
+
import { Array, Number, String, pipe } from "effect";
|
|
3
|
+
import { cellView } from "../glyph/glyph.js";
|
|
4
|
+
import { artRows, toCells } from "../glyph/glyphs.js";
|
|
3
5
|
// LETTERS
|
|
4
6
|
const WORD_BREAK = /[\s._-]+/;
|
|
5
7
|
const LETTER_COUNT = 2;
|
|
@@ -11,12 +13,28 @@ const initials = (name) => __foldkitBrandViewResult((pipe(name.split(WORD_BREAK)
|
|
|
11
13
|
? pipe(Array.take(words, LETTER_COUNT), Array.map((word) => __foldkitBrandViewResult((word.slice(0, 1)), "@gjermundgaraba-designs/pixel-paper/src/monogram/monogram.js#anonymous")), Array.join(""))
|
|
12
14
|
: Array.headNonEmpty(words).slice(0, LETTER_COUNT)), "@gjermundgaraba-designs/pixel-paper/src/monogram/monogram.js#onNonEmpty"),
|
|
13
15
|
}))), "@gjermundgaraba-designs/pixel-paper/src/monogram/monogram.js#initials");
|
|
14
|
-
|
|
15
|
-
|
|
16
|
+
// DRAWING
|
|
17
|
+
/** A drawing prints a pixel per cell, two in a large monogram, so its cells stay whole. */
|
|
18
|
+
const DRAWN_CELL = 1;
|
|
19
|
+
const LARGE_DRAWN_CELL = 2;
|
|
20
|
+
const drawingView = (art, isLarge, h) => {
|
|
21
|
+
const rows = artRows(art);
|
|
22
|
+
const columns = Array.reduce(rows, 0, (widest, row) => __foldkitBrandViewResult((Number.max(widest, row.length)), "@gjermundgaraba-designs/pixel-paper/src/monogram/monogram.js#anonymous~2"));
|
|
23
|
+
const cell = isLarge ? LARGE_DRAWN_CELL : DRAWN_CELL;
|
|
24
|
+
return __foldkitBrandViewResult((h.svg([
|
|
25
|
+
h.ViewBox(`0 0 ${columns} ${rows.length}`),
|
|
26
|
+
h.Width(`${columns * cell}`),
|
|
27
|
+
h.Height(`${rows.length * cell}`),
|
|
28
|
+
h.AriaHidden(true),
|
|
29
|
+
h.Class("px-icon"),
|
|
30
|
+
], Array.map(toCells(art, columns), cellView(h)))), "@gjermundgaraba-designs/pixel-paper/src/monogram/monogram.js#drawingView");
|
|
31
|
+
};
|
|
32
|
+
/** Letters in an ink square, or a mark the product draws in cells: the identity of a person,
|
|
33
|
+
* a provider or a source. An image named by `label`, or hidden when `isDecorative`. */
|
|
16
34
|
export const view = (config, h) => {
|
|
17
|
-
const { label, letters, isLarge = false, isCurrent = false, isDecorative = false } = config;
|
|
35
|
+
const { label, letters, drawing, isLarge = false, isCurrent = false, isDecorative = false, } = config;
|
|
18
36
|
return __foldkitBrandViewResult((h.span([
|
|
19
37
|
...(isDecorative ? [h.AriaHidden(true)] : [h.Role("img"), h.AriaLabel(label)]),
|
|
20
|
-
h.Class(`monogram${isLarge ? " large" : ""}${isCurrent ? " current" : ""}`),
|
|
21
|
-
], [letters ?? initials(label)])), "@gjermundgaraba-designs/pixel-paper/src/monogram/monogram.js#view");
|
|
38
|
+
h.Class(`monogram${drawing === undefined ? "" : " drawn"}${isLarge ? " large" : ""}${isCurrent ? " current" : ""}`),
|
|
39
|
+
], [drawing === undefined ? (letters ?? initials(label)) : drawingView(drawing, isLarge, h)])), "@gjermundgaraba-designs/pixel-paper/src/monogram/monogram.js#view");
|
|
22
40
|
};
|
|
@@ -9,6 +9,10 @@ export type ViewConfig = Readonly<{
|
|
|
9
9
|
id: string;
|
|
10
10
|
/** Pixel caps in the inverted title bar. */
|
|
11
11
|
title: string;
|
|
12
|
+
/** What screen readers call the panel where its title repeats among its siblings (panels
|
|
13
|
+
* titled by a kind, one per account): the title and what tells this one apart. The
|
|
14
|
+
* title names it otherwise. */
|
|
15
|
+
name?: string;
|
|
12
16
|
/** A quiet IconButton before the title, such as the grip a Sortable of panels hands each
|
|
13
17
|
* panel. On the ink bar it prints as `actions` do. */
|
|
14
18
|
lead?: ReadonlyArray<Html | string>;
|
|
@@ -26,6 +30,6 @@ export type ViewConfig = Readonly<{
|
|
|
26
30
|
/** The id of a panel's title, which names it. */
|
|
27
31
|
export declare const titleId: (id: string) => string;
|
|
28
32
|
/** The unit of the system: paper in a 2px ink box on a 5px print shadow, under a title bar. A
|
|
29
|
-
* region landmark (`<section>`) named by its `h2` title, keyed by its `id`. */
|
|
33
|
+
* region landmark (`<section>`) named by its `h2` title, or by `name`, keyed by its `id`. */
|
|
30
34
|
export declare const view: <Message>(config: ViewConfig, h: HtmlBuilder<Message>) => Html;
|
|
31
35
|
//# sourceMappingURL=panel.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"panel.d.ts","sourceRoot":"","sources":["../../../src/panel/panel.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAMtD,uDAAuD;AACvD,MAAM,MAAM,UAAU,GAAG,QAAQ,CAAC;IAChC;;;;kCAI8B;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,4CAA4C;IAC5C,KAAK,EAAE,MAAM,CAAC;IACd;2DACuD;IACvD,IAAI,CAAC,EAAE,aAAa,CAAC,IAAI,GAAG,MAAM,CAAC,CAAC;IACpC,iDAAiD;IACjD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;yFACqF;IACrF,OAAO,CAAC,EAAE,aAAa,CAAC,IAAI,GAAG,MAAM,CAAC,CAAC;IACvC,IAAI,EAAE,aAAa,CAAC,IAAI,GAAG,MAAM,CAAC,CAAC;IACnC,2EAA2E;IAC3E,IAAI,CAAC,EAAE,aAAa,CAAC,IAAI,GAAG,MAAM,CAAC,CAAC;IACpC,uFAAuF;IACvF,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC,CAAC;AAEH,iDAAiD;AACjD,eAAO,MAAM,OAAO,OAAQ,MAAM,KAAG,MAAuB,CAAC;AAE7D;
|
|
1
|
+
{"version":3,"file":"panel.d.ts","sourceRoot":"","sources":["../../../src/panel/panel.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAMtD,uDAAuD;AACvD,MAAM,MAAM,UAAU,GAAG,QAAQ,CAAC;IAChC;;;;kCAI8B;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,4CAA4C;IAC5C,KAAK,EAAE,MAAM,CAAC;IACd;;oCAEgC;IAChC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;2DACuD;IACvD,IAAI,CAAC,EAAE,aAAa,CAAC,IAAI,GAAG,MAAM,CAAC,CAAC;IACpC,iDAAiD;IACjD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;yFACqF;IACrF,OAAO,CAAC,EAAE,aAAa,CAAC,IAAI,GAAG,MAAM,CAAC,CAAC;IACvC,IAAI,EAAE,aAAa,CAAC,IAAI,GAAG,MAAM,CAAC,CAAC;IACnC,2EAA2E;IAC3E,IAAI,CAAC,EAAE,aAAa,CAAC,IAAI,GAAG,MAAM,CAAC,CAAC;IACpC,uFAAuF;IACvF,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC,CAAC;AAEH,iDAAiD;AACjD,eAAO,MAAM,OAAO,OAAQ,MAAM,KAAG,MAAuB,CAAC;AAE7D;8FAC8F;AAC9F,eAAO,MAAM,IAAI,GAAI,OAAO,UAAU,UAAU,KAAK,WAAW,CAAC,OAAO,CAAC,KAAG,IAkC3E,CAAC"}
|
package/dist/src/panel/panel.js
CHANGED
|
@@ -3,10 +3,14 @@ import { slotView } from "../slot/slot.js";
|
|
|
3
3
|
/** The id of a panel's title, which names it. */
|
|
4
4
|
export const titleId = (id) => __foldkitBrandViewResult((`${id}-title`), "@gjermundgaraba-designs/pixel-paper/src/panel/panel.js#titleId");
|
|
5
5
|
/** The unit of the system: paper in a 2px ink box on a 5px print shadow, under a title bar. A
|
|
6
|
-
* region landmark (`<section>`) named by its `h2` title, keyed by its `id`. */
|
|
6
|
+
* region landmark (`<section>`) named by its `h2` title, or by `name`, keyed by its `id`. */
|
|
7
7
|
export const view = (config, h) => {
|
|
8
|
-
const { id, title, lead = [], meta, actions = [], body, foot = [], isFlush = false } = config;
|
|
9
|
-
return __foldkitBrandViewResult((h.keyed("section")(id, [
|
|
8
|
+
const { id, title, name, lead = [], meta, actions = [], body, foot = [], isFlush = false, } = config;
|
|
9
|
+
return __foldkitBrandViewResult((h.keyed("section")(id, [
|
|
10
|
+
h.Id(id),
|
|
11
|
+
name === undefined ? h.AriaLabelledBy(titleId(id)) : h.AriaLabel(name),
|
|
12
|
+
h.Class("panel"),
|
|
13
|
+
], [
|
|
10
14
|
h.header([h.Class("panel-tb")], [
|
|
11
15
|
...slotView("span", "panel-lead", lead, h),
|
|
12
16
|
h.h2([h.Id(titleId(id))], [title]),
|
package/package.json
CHANGED
package/src/glyph/glyph.ts
CHANGED
|
@@ -14,7 +14,8 @@ export type ViewConfig = Readonly<{
|
|
|
14
14
|
size?: number;
|
|
15
15
|
}>;
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
/** One inked rectangle of a drawing, in `currentColor`. */
|
|
18
|
+
export const cellView =
|
|
18
19
|
<Message>(h: HtmlBuilder<Message>) =>
|
|
19
20
|
([x, y, width, height]: Cell): Html =>
|
|
20
21
|
h.rect([
|
package/src/glyph/glyphs.ts
CHANGED
|
@@ -2614,10 +2614,11 @@ export const artRows = (art: string): ReadonlyArray<string> =>
|
|
|
2614
2614
|
|
|
2615
2615
|
const INK_RUN = /#+/g;
|
|
2616
2616
|
|
|
2617
|
-
/** A drawing as rectangles one cell tall: one for each horizontal run of ink in each row
|
|
2618
|
-
|
|
2617
|
+
/** A drawing as rectangles one cell tall: one for each horizontal run of ink in each row,
|
|
2618
|
+
* up to `width` cells into the row. */
|
|
2619
|
+
export const toCells = (art: string, width: number): ReadonlyArray<Cell> =>
|
|
2619
2620
|
Array.flatMap(artRows(art), (row, y) =>
|
|
2620
|
-
Array.map(Array.fromIterable(row.slice(0,
|
|
2621
|
+
Array.map(Array.fromIterable(row.slice(0, width).matchAll(INK_RUN)), (run): Cell => [
|
|
2621
2622
|
run.index,
|
|
2622
2623
|
y,
|
|
2623
2624
|
run[0].length,
|
|
@@ -2627,7 +2628,8 @@ const toCells = (art: string): ReadonlyArray<Cell> =>
|
|
|
2627
2628
|
|
|
2628
2629
|
const drawFamily = <Name extends string>(
|
|
2629
2630
|
family: Record.ReadonlyRecord<Name, string>,
|
|
2630
|
-
): Record.ReadonlyRecord<Name, ReadonlyArray<Cell>> =>
|
|
2631
|
+
): Record.ReadonlyRecord<Name, ReadonlyArray<Cell>> =>
|
|
2632
|
+
Record.map(family, (art) => toCells(art, GRID_SIZE));
|
|
2631
2633
|
|
|
2632
2634
|
/** Every glyph as the rectangles `Glyph.view` draws. */
|
|
2633
2635
|
export const glyphs: Record.ReadonlyRecord<GlyphName, ReadonlyArray<Cell>> = {
|
package/src/identity/identity.ts
CHANGED
|
@@ -11,6 +11,8 @@ export type ViewConfig = Readonly<{
|
|
|
11
11
|
label: string;
|
|
12
12
|
/** The monogram's letters, when the name's initials are not the ones people know. */
|
|
13
13
|
letters?: string;
|
|
14
|
+
/** The monogram's mark drawn in cells, in place of its letters (see Monogram). */
|
|
15
|
+
drawing?: string;
|
|
14
16
|
/** A line under the name: an id, a kind, a scope. */
|
|
15
17
|
meta?: ReadonlyArray<Html | string>;
|
|
16
18
|
/** Beside a name set large, as a card's subject. */
|
|
@@ -20,13 +22,19 @@ export type ViewConfig = Readonly<{
|
|
|
20
22
|
/** Who or what something is: its monogram beside its name in the sans, and a meta line.
|
|
21
23
|
* Screen readers hear the name once: the monogram beside it is hidden from them. */
|
|
22
24
|
export const view = <Message>(config: ViewConfig, h: HtmlBuilder<Message>): Html => {
|
|
23
|
-
const { label, letters, meta = [], isLarge = false } = config;
|
|
25
|
+
const { label, letters, drawing, meta = [], isLarge = false } = config;
|
|
24
26
|
|
|
25
27
|
return h.div(
|
|
26
28
|
[h.Class(isLarge ? "identity large" : "identity")],
|
|
27
29
|
[
|
|
28
30
|
Monogram.view(
|
|
29
|
-
{
|
|
31
|
+
{
|
|
32
|
+
label,
|
|
33
|
+
...(letters !== undefined && { letters }),
|
|
34
|
+
...(drawing !== undefined && { drawing }),
|
|
35
|
+
isLarge,
|
|
36
|
+
isDecorative: true,
|
|
37
|
+
},
|
|
30
38
|
h,
|
|
31
39
|
),
|
|
32
40
|
h.span(
|
package/src/meter/meter.ts
CHANGED
|
@@ -81,6 +81,10 @@ export type MeterConfig = Readonly<{
|
|
|
81
81
|
hasNumbers?: boolean;
|
|
82
82
|
/** In a red chip once the value reaches `max`. The percentage by default. */
|
|
83
83
|
full?: string;
|
|
84
|
+
/** The lit cells take the reading's tone as well: amber from 80%, red at `max`. For a page
|
|
85
|
+
* of readings scanned for their level, such as a wall of limits; the reading beside the
|
|
86
|
+
* cells still says it in a mark or a chip. */
|
|
87
|
+
isToned?: boolean;
|
|
84
88
|
/** The last reading failed: the cells print muted, the numbers are the last known, and
|
|
85
89
|
* screen readers hear "(stale)" after the name. Say why, and when it was last read, in
|
|
86
90
|
* `foot`. */
|
|
@@ -119,6 +123,16 @@ const percentView = <Message>(
|
|
|
119
123
|
}
|
|
120
124
|
};
|
|
121
125
|
|
|
126
|
+
const toneClass = (value: number, max: number, isFull: boolean): string => {
|
|
127
|
+
if (isFull) {
|
|
128
|
+
return " toned full";
|
|
129
|
+
} else if (value >= max * HIGH_SHARE) {
|
|
130
|
+
return " toned high";
|
|
131
|
+
} else {
|
|
132
|
+
return " toned";
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
|
|
122
136
|
const meterView = <Message>(config: MeterConfig, h: HtmlBuilder<Message>): Html => {
|
|
123
137
|
const {
|
|
124
138
|
id,
|
|
@@ -129,10 +143,12 @@ const meterView = <Message>(config: MeterConfig, h: HtmlBuilder<Message>): Html
|
|
|
129
143
|
foot = [],
|
|
130
144
|
isStale = false,
|
|
131
145
|
hasNumbers = true,
|
|
146
|
+
isToned = false,
|
|
132
147
|
} = config;
|
|
133
148
|
const share = max > 0 ? Math.min(1, Math.max(0, value / max)) : 0;
|
|
134
149
|
const isFull = value >= max;
|
|
135
150
|
const numbers = config.valueText ?? numbersText(value, max, config.unit);
|
|
151
|
+
const rowClass = `meter-row${isStale ? " stale" : ""}${isToned ? toneClass(value, max, isFull) : ""}`;
|
|
136
152
|
|
|
137
153
|
return UiMeter.view(
|
|
138
154
|
{
|
|
@@ -144,7 +160,7 @@ const meterView = <Message>(config: MeterConfig, h: HtmlBuilder<Message>): Html
|
|
|
144
160
|
toView: (groups) =>
|
|
145
161
|
h.keyed("li")(
|
|
146
162
|
id,
|
|
147
|
-
[h.Class(
|
|
163
|
+
[h.Class(rowClass)],
|
|
148
164
|
[
|
|
149
165
|
h.div(
|
|
150
166
|
[h.Class("meter-head")],
|
|
@@ -184,7 +200,7 @@ export type ListViewConfig = Readonly<{
|
|
|
184
200
|
* A ruled list of meters, edge to edge in a flush panel. Each is a named reading against a
|
|
185
201
|
* maximum, in the vocabulary of `<meter>`, built on `@foldkit/ui`'s Meter: 20 cells, the
|
|
186
202
|
* percentage (amber from 80%, a red chip at `max`, and neither 100% nor every cell before it),
|
|
187
|
-
* the numbers in English, a foot line. The cells are the `meter`, named by the printed label,
|
|
203
|
+
* the numbers in English, a foot line. The cells print ink unless the meter `isToned`. The cells are the `meter`, named by the printed label,
|
|
188
204
|
* with the value, the maximum and the numbers in words for screen readers.
|
|
189
205
|
*/
|
|
190
206
|
export const listView = <Message>(config: ListViewConfig, h: HtmlBuilder<Message>): Html =>
|
package/src/monogram/monogram.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
|
-
import { Array, String, pipe } from "effect";
|
|
1
|
+
import { Array, Number, String, pipe } from "effect";
|
|
2
2
|
import type { Html, HtmlBuilder } from "foldkit/html";
|
|
3
3
|
|
|
4
|
+
import { cellView } from "../glyph/glyph.ts";
|
|
5
|
+
import { artRows, toCells } from "../glyph/glyphs.ts";
|
|
6
|
+
|
|
4
7
|
// LETTERS
|
|
5
8
|
|
|
6
9
|
const WORD_BREAK = /[\s._-]+/;
|
|
@@ -25,6 +28,29 @@ const initials = (name: string): string =>
|
|
|
25
28
|
}),
|
|
26
29
|
);
|
|
27
30
|
|
|
31
|
+
// DRAWING
|
|
32
|
+
|
|
33
|
+
/** A drawing prints a pixel per cell, two in a large monogram, so its cells stay whole. */
|
|
34
|
+
const DRAWN_CELL = 1;
|
|
35
|
+
const LARGE_DRAWN_CELL = 2;
|
|
36
|
+
|
|
37
|
+
const drawingView = <Message>(art: string, isLarge: boolean, h: HtmlBuilder<Message>): Html => {
|
|
38
|
+
const rows = artRows(art);
|
|
39
|
+
const columns = Array.reduce(rows, 0, (widest, row) => Number.max(widest, row.length));
|
|
40
|
+
const cell = isLarge ? LARGE_DRAWN_CELL : DRAWN_CELL;
|
|
41
|
+
|
|
42
|
+
return h.svg(
|
|
43
|
+
[
|
|
44
|
+
h.ViewBox(`0 0 ${columns} ${rows.length}`),
|
|
45
|
+
h.Width(`${columns * cell}`),
|
|
46
|
+
h.Height(`${rows.length * cell}`),
|
|
47
|
+
h.AriaHidden(true),
|
|
48
|
+
h.Class("px-icon"),
|
|
49
|
+
],
|
|
50
|
+
Array.map(toCells(art, columns), cellView(h)),
|
|
51
|
+
);
|
|
52
|
+
};
|
|
53
|
+
|
|
28
54
|
// VIEW
|
|
29
55
|
|
|
30
56
|
/** Configuration for rendering a monogram with `view`. */
|
|
@@ -33,6 +59,11 @@ export type ViewConfig = Readonly<{
|
|
|
33
59
|
label: string;
|
|
34
60
|
/** One or two letters, when the name's initials are not the ones people know. */
|
|
35
61
|
letters?: string;
|
|
62
|
+
/** A mark the product draws in cells, in place of the letters: rows of `#` (ink) and `.`,
|
|
63
|
+
* as a glyph is drawn, on a grid of up to 16 for a large monogram. It prints bare, in ink,
|
|
64
|
+
* a pixel per cell (two when large): a provider's own mark redrawn in the system's
|
|
65
|
+
* cells, never a picture or a brand colour. */
|
|
66
|
+
drawing?: string;
|
|
36
67
|
/** 34px, beside a name set large (a card of readings, a wall). */
|
|
37
68
|
isLarge?: boolean;
|
|
38
69
|
/** You, among others: the monogram inverts. */
|
|
@@ -42,16 +73,25 @@ export type ViewConfig = Readonly<{
|
|
|
42
73
|
isDecorative?: boolean;
|
|
43
74
|
}>;
|
|
44
75
|
|
|
45
|
-
/** Letters in an ink square
|
|
46
|
-
*
|
|
76
|
+
/** Letters in an ink square, or a mark the product draws in cells: the identity of a person,
|
|
77
|
+
* a provider or a source. An image named by `label`, or hidden when `isDecorative`. */
|
|
47
78
|
export const view = <Message>(config: ViewConfig, h: HtmlBuilder<Message>): Html => {
|
|
48
|
-
const {
|
|
79
|
+
const {
|
|
80
|
+
label,
|
|
81
|
+
letters,
|
|
82
|
+
drawing,
|
|
83
|
+
isLarge = false,
|
|
84
|
+
isCurrent = false,
|
|
85
|
+
isDecorative = false,
|
|
86
|
+
} = config;
|
|
49
87
|
|
|
50
88
|
return h.span(
|
|
51
89
|
[
|
|
52
90
|
...(isDecorative ? [h.AriaHidden(true)] : [h.Role("img"), h.AriaLabel(label)]),
|
|
53
|
-
h.Class(
|
|
91
|
+
h.Class(
|
|
92
|
+
`monogram${drawing === undefined ? "" : " drawn"}${isLarge ? " large" : ""}${isCurrent ? " current" : ""}`,
|
|
93
|
+
),
|
|
54
94
|
],
|
|
55
|
-
[letters ?? initials(label)],
|
|
95
|
+
[drawing === undefined ? (letters ?? initials(label)) : drawingView(drawing, isLarge, h)],
|
|
56
96
|
);
|
|
57
97
|
};
|
package/src/panel/panel.ts
CHANGED
|
@@ -14,6 +14,10 @@ export type ViewConfig = Readonly<{
|
|
|
14
14
|
id: string;
|
|
15
15
|
/** Pixel caps in the inverted title bar. */
|
|
16
16
|
title: string;
|
|
17
|
+
/** What screen readers call the panel where its title repeats among its siblings (panels
|
|
18
|
+
* titled by a kind, one per account): the title and what tells this one apart. The
|
|
19
|
+
* title names it otherwise. */
|
|
20
|
+
name?: string;
|
|
17
21
|
/** A quiet IconButton before the title, such as the grip a Sortable of panels hands each
|
|
18
22
|
* panel. On the ink bar it prints as `actions` do. */
|
|
19
23
|
lead?: ReadonlyArray<Html | string>;
|
|
@@ -33,13 +37,27 @@ export type ViewConfig = Readonly<{
|
|
|
33
37
|
export const titleId = (id: string): string => `${id}-title`;
|
|
34
38
|
|
|
35
39
|
/** The unit of the system: paper in a 2px ink box on a 5px print shadow, under a title bar. A
|
|
36
|
-
* region landmark (`<section>`) named by its `h2` title, keyed by its `id`. */
|
|
40
|
+
* region landmark (`<section>`) named by its `h2` title, or by `name`, keyed by its `id`. */
|
|
37
41
|
export const view = <Message>(config: ViewConfig, h: HtmlBuilder<Message>): Html => {
|
|
38
|
-
const {
|
|
42
|
+
const {
|
|
43
|
+
id,
|
|
44
|
+
title,
|
|
45
|
+
name,
|
|
46
|
+
lead = [],
|
|
47
|
+
meta,
|
|
48
|
+
actions = [],
|
|
49
|
+
body,
|
|
50
|
+
foot = [],
|
|
51
|
+
isFlush = false,
|
|
52
|
+
} = config;
|
|
39
53
|
|
|
40
54
|
return h.keyed("section")(
|
|
41
55
|
id,
|
|
42
|
-
[
|
|
56
|
+
[
|
|
57
|
+
h.Id(id),
|
|
58
|
+
name === undefined ? h.AriaLabelledBy(titleId(id)) : h.AriaLabel(name),
|
|
59
|
+
h.Class("panel"),
|
|
60
|
+
],
|
|
43
61
|
[
|
|
44
62
|
h.header(
|
|
45
63
|
[h.Class("panel-tb")],
|
package/src/pixel-paper.css
CHANGED
|
@@ -3655,6 +3655,16 @@ dialog.veil:focus {
|
|
|
3655
3655
|
flex-wrap: wrap;
|
|
3656
3656
|
}
|
|
3657
3657
|
|
|
3658
|
+
/* a toned meter's lit cells take its reading's tone, amber from 80% and red at the maximum,
|
|
3659
|
+
unless the reading is stale */
|
|
3660
|
+
.meter-row.toned.high:not(.stale) .cells .cell.on {
|
|
3661
|
+
background: var(--amber);
|
|
3662
|
+
}
|
|
3663
|
+
|
|
3664
|
+
.meter-row.toned.full:not(.stale) .cells .cell.on {
|
|
3665
|
+
background: var(--red);
|
|
3666
|
+
}
|
|
3667
|
+
|
|
3658
3668
|
/* a stale reading prints its cells muted: the number is last known, not current */
|
|
3659
3669
|
.meter-row.stale .cells .cell.on {
|
|
3660
3670
|
background: var(--muted);
|
|
@@ -4522,7 +4532,7 @@ dialog.veil:focus {
|
|
|
4522
4532
|
position: absolute;
|
|
4523
4533
|
}
|
|
4524
4534
|
|
|
4525
|
-
/* ---------- monograms: letters in an ink square,
|
|
4535
|
+
/* ---------- monograms: letters in an ink square, or a mark the product draws in cells ---------- */
|
|
4526
4536
|
|
|
4527
4537
|
.monogram {
|
|
4528
4538
|
display: inline-grid;
|
|
@@ -4551,6 +4561,16 @@ dialog.veil:focus {
|
|
|
4551
4561
|
color: var(--paper);
|
|
4552
4562
|
}
|
|
4553
4563
|
|
|
4564
|
+
/* a mark drawn in cells prints bare, in ink, in the square the letters would take */
|
|
4565
|
+
.monogram.drawn {
|
|
4566
|
+
border: 0;
|
|
4567
|
+
background: none;
|
|
4568
|
+
}
|
|
4569
|
+
|
|
4570
|
+
.monogram.drawn.current {
|
|
4571
|
+
background: var(--ink);
|
|
4572
|
+
}
|
|
4573
|
+
|
|
4554
4574
|
/* ---------- identity: who or what, as its monogram beside its name ---------- */
|
|
4555
4575
|
|
|
4556
4576
|
.identity {
|