@selimssevgi/cube-design-angular 0.2.0 → 0.2.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/CHANGELOG.md CHANGED
@@ -1,5 +1,10 @@
1
1
  # changelog
2
2
 
3
+ ## 0.2.1
4
+
5
+ - `<cube-context>`'s words take their size from `--cube-context-title-size` (17px) and `--cube-context-line-size` (13px, the line and the in-use word), set in both token files; the other steps keep their ratio to them. before, the sizes were fixed, so an app could not reach them through variables. found taking 0.2.0 into anlat, whose text is never under 19px. nothing changes for an app that does not set them.
6
+ - how many lines a tile's title and line show are `--cube-context-title-lines` and `--cube-context-line-lines` (2 each, as before), so an app with bigger words lets the title take a third line instead of cutting it (anlat's "adını değiştirmek istiyorum" at 19px).
7
+
3
8
  ## 0.2.0
4
9
 
5
10
  - `cubeHold` (`CubeHold`, `CubeHeld`, `CUBE_HOLD_MS`, `CUBE_HOLD_SLOP`): pressing and holding a piece, the gesture cubes (tiles and the cube on top) and anlat (level tiles) each wrote by hand. a long press, a right click or the menu key raise one `cubeHeld`; a pinch or a drag never do; the click after a hold is swallowed. its hold time is 520 ms (cubes'), and each app may set its own (`cubeHoldMs`, anlat's is 480). what a hold opens stays in each app.
package/README.md CHANGED
@@ -11,7 +11,7 @@ it and its cube design decision is kept; then it moves in here.
11
11
  ## install
12
12
 
13
13
  ```shell
14
- npm install @selimssevgi/cube-design-angular@0.2.0 --save-exact
14
+ npm install @selimssevgi/cube-design-angular@0.2.1 --save-exact
15
15
  ```
16
16
 
17
17
  pin the exact version: a new version changes nothing in an app until that app takes it in its own
@@ -269,7 +269,12 @@ the tile's icon is its `icon` when `cube-icon` draws it (`contextIcon`); `hide`
269
269
  tile that adds draws the plus, and an icon of the app's own draws a face. its look is the
270
270
  `--cube-context-*` variables, set in both token files: `-tile`, `-line`, `-ink`, `-quiet`,
271
271
  `-in-use`, `-adds`, `-adds-bg`, `-adds-ink`, `-focus` and `-radius`, with the `--cube-icon-*` ones
272
- for the icons. its square is `<cube-square>` (below), so it lays out, measures and zooms like every
272
+ for the icons. the words' sizes are `--cube-context-title-size` (17px) and
273
+ `--cube-context-line-size` (13px, also the in-use word), the sizes on a tile of the second step
274
+ (`cc-l1`); the other steps keep their ratio to them, so an app that needs bigger letters (anlat:
275
+ nothing under 19px) sets the two and every step follows. a title and a line each show at most
276
+ `--cube-context-title-lines` and `--cube-context-line-lines` lines (2), so bigger words can take a
277
+ third line instead of being cut. its square is `<cube-square>` (below), so it lays out, measures and zooms like every
273
278
  other face; its open places take the context cube's line and radius. `contextSquare(count, room)`
274
279
  and `contextLevelFor(cell)` are kept as plain functions.
275
280
 
@@ -1961,7 +1961,7 @@ var CubeContext = class CubeContext {
1961
1961
  </cube-square>
1962
1962
  `,
1963
1963
  isInline: true,
1964
- styles: [":host{display:block;font:inherit;color:var(--cube-context-ink, #1f2a26);--cube-square-place: color-mix(in srgb, var(--cube-context-line, #dae0d9) 55%, transparent);--cube-square-place-dashed: var(--cube-context-line, #dae0d9);--cube-square-radius: var(--cube-context-radius, 20px)}.cc-tile{all:unset;cursor:pointer;box-sizing:border-box;min-width:0;min-height:0;height:100%;overflow:hidden;display:grid;justify-items:center;align-content:center;gap:6px;padding:14px 10px 12px;text-align:center;background:var(--cube-context-tile, #ffffff);border:1px solid var(--cube-context-line, #dae0d9);border-radius:var(--cube-context-radius, 20px);user-select:none;-webkit-user-select:none;-webkit-touch-callout:none;transition:transform .16s}.cc-tile:active:not(:disabled){transform:scale(.97)}.cc-tile:focus-visible{outline:3px solid var(--cube-context-focus, #5f9a80);outline-offset:2px}.cc-tile.cc-in-use{border:2px solid var(--cube-context-in-use, #3b5a4c)}.cc-tile.cc-pale{background:transparent;border:2px dashed var(--cube-context-line, #dae0d9);color:var(--cube-context-quiet, #5d6a64)}.cc-tile.cc-adds{border:2px solid var(--cube-context-adds, #c8693f)}.cc-tile.cc-busy{opacity:.6;cursor:progress}.cc-tile:disabled:not(.cc-busy){cursor:default}.cc-icon{display:grid;place-items:center;line-height:0}.cc-tile.cc-adds .cc-icon{width:52px;height:52px;border-radius:50%;background:var(--cube-context-adds-bg, #f3e3d6);--cube-icon-stroke: var(--cube-context-adds-ink, #7a4a2b);--cube-icon-size: 26px}.cc-t,.cc-m{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;line-clamp:2;overflow:hidden;overflow-wrap:anywhere}.cc-t{font-size:17px;font-weight:700;line-height:1.2}.cc-m{font-size:13px;line-height:1.3;color:var(--cube-context-quiet, #5d6a64)}.cc-tick{font-size:13px;font-weight:800;color:var(--cube-context-in-use, #3b5a4c)}.cc-tile.cc-l0{border-radius:28px;padding:24px;gap:10px}.cc-l0 .cc-t{font-size:26px}.cc-l0 .cc-m{font-size:16px}.cc-l0 .cc-icon{--cube-icon-size: 64px}.cc-tile.cc-l0.cc-adds .cc-icon{width:96px;height:96px;--cube-icon-size: 40px}.cc-tile.cc-l2{border-radius:16px;padding:10px 6px;gap:5px}.cc-l2 .cc-t{font-size:14px}.cc-l2 .cc-m{font-size:12px}.cc-tile.cc-l3{border-radius:12px;padding:6px 4px;gap:3px}.cc-l3 .cc-t{font-size:12px}.cc-tile.cc-l4{border-radius:9px;padding:2px;gap:0}.cc-l3 .cc-icon,.cc-l4 .cc-icon{--cube-icon-size: 24px}.cc-tile.cc-l3.cc-adds .cc-icon,.cc-tile.cc-l4.cc-adds .cc-icon{width:30px;height:30px;--cube-icon-size: 18px}\n"],
1964
+ styles: [":host{display:block;font:inherit;color:var(--cube-context-ink, #1f2a26);--cube-square-place: color-mix(in srgb, var(--cube-context-line, #dae0d9) 55%, transparent);--cube-square-place-dashed: var(--cube-context-line, #dae0d9);--cube-square-radius: var(--cube-context-radius, 20px)}.cc-tile{all:unset;cursor:pointer;box-sizing:border-box;min-width:0;min-height:0;height:100%;overflow:hidden;display:grid;justify-items:center;align-content:center;gap:6px;padding:14px 10px 12px;text-align:center;background:var(--cube-context-tile, #ffffff);border:1px solid var(--cube-context-line, #dae0d9);border-radius:var(--cube-context-radius, 20px);user-select:none;-webkit-user-select:none;-webkit-touch-callout:none;transition:transform .16s}.cc-tile:active:not(:disabled){transform:scale(.97)}.cc-tile:focus-visible{outline:3px solid var(--cube-context-focus, #5f9a80);outline-offset:2px}.cc-tile.cc-in-use{border:2px solid var(--cube-context-in-use, #3b5a4c)}.cc-tile.cc-pale{background:transparent;border:2px dashed var(--cube-context-line, #dae0d9);color:var(--cube-context-quiet, #5d6a64)}.cc-tile.cc-adds{border:2px solid var(--cube-context-adds, #c8693f)}.cc-tile.cc-busy{opacity:.6;cursor:progress}.cc-tile:disabled:not(.cc-busy){cursor:default}.cc-icon{display:grid;place-items:center;line-height:0}.cc-tile.cc-adds .cc-icon{width:52px;height:52px;border-radius:50%;background:var(--cube-context-adds-bg, #f3e3d6);--cube-icon-stroke: var(--cube-context-adds-ink, #7a4a2b);--cube-icon-size: 26px}.cc-t,.cc-m{display:-webkit-box;-webkit-box-orient:vertical;overflow:hidden;overflow-wrap:anywhere}.cc-t{-webkit-line-clamp:var(--cube-context-title-lines, 2);line-clamp:var(--cube-context-title-lines, 2)}.cc-m{-webkit-line-clamp:var(--cube-context-line-lines, 2);line-clamp:var(--cube-context-line-lines, 2)}.cc-t{font-size:var(--cube-context-title-size, 17px);font-weight:700;line-height:1.2}.cc-m{font-size:var(--cube-context-line-size, 13px);line-height:1.3;color:var(--cube-context-quiet, #5d6a64)}.cc-tick{font-size:var(--cube-context-line-size, 13px);font-weight:800;color:var(--cube-context-in-use, #3b5a4c)}.cc-tile.cc-l0{border-radius:28px;padding:24px;gap:10px}.cc-l0 .cc-t{font-size:calc(var(--cube-context-title-size, 17px) * 26 / 17)}.cc-l0 .cc-m{font-size:calc(var(--cube-context-line-size, 13px) * 16 / 13)}.cc-l0 .cc-icon{--cube-icon-size: 64px}.cc-tile.cc-l0.cc-adds .cc-icon{width:96px;height:96px;--cube-icon-size: 40px}.cc-tile.cc-l2{border-radius:16px;padding:10px 6px;gap:5px}.cc-l2 .cc-t{font-size:calc(var(--cube-context-title-size, 17px) * 14 / 17)}.cc-l2 .cc-m{font-size:calc(var(--cube-context-line-size, 13px) * 12 / 13)}.cc-tile.cc-l3{border-radius:12px;padding:6px 4px;gap:3px}.cc-l3 .cc-t{font-size:calc(var(--cube-context-title-size, 17px) * 12 / 17)}.cc-tile.cc-l4{border-radius:9px;padding:2px;gap:0}.cc-l3 .cc-icon,.cc-l4 .cc-icon{--cube-icon-size: 24px}.cc-tile.cc-l3.cc-adds .cc-icon,.cc-tile.cc-l4.cc-adds .cc-icon{width:30px;height:30px;--cube-icon-size: 18px}\n"],
1965
1965
  dependencies: [
1966
1966
  {
1967
1967
  kind: "component",
@@ -2048,7 +2048,7 @@ i0.ɵɵngDeclareClassMetadata({
2048
2048
  </cube-square>
2049
2049
  `,
2050
2050
  changeDetection: ChangeDetectionStrategy.OnPush,
2051
- styles: [":host{display:block;font:inherit;color:var(--cube-context-ink, #1f2a26);--cube-square-place: color-mix(in srgb, var(--cube-context-line, #dae0d9) 55%, transparent);--cube-square-place-dashed: var(--cube-context-line, #dae0d9);--cube-square-radius: var(--cube-context-radius, 20px)}.cc-tile{all:unset;cursor:pointer;box-sizing:border-box;min-width:0;min-height:0;height:100%;overflow:hidden;display:grid;justify-items:center;align-content:center;gap:6px;padding:14px 10px 12px;text-align:center;background:var(--cube-context-tile, #ffffff);border:1px solid var(--cube-context-line, #dae0d9);border-radius:var(--cube-context-radius, 20px);user-select:none;-webkit-user-select:none;-webkit-touch-callout:none;transition:transform .16s}.cc-tile:active:not(:disabled){transform:scale(.97)}.cc-tile:focus-visible{outline:3px solid var(--cube-context-focus, #5f9a80);outline-offset:2px}.cc-tile.cc-in-use{border:2px solid var(--cube-context-in-use, #3b5a4c)}.cc-tile.cc-pale{background:transparent;border:2px dashed var(--cube-context-line, #dae0d9);color:var(--cube-context-quiet, #5d6a64)}.cc-tile.cc-adds{border:2px solid var(--cube-context-adds, #c8693f)}.cc-tile.cc-busy{opacity:.6;cursor:progress}.cc-tile:disabled:not(.cc-busy){cursor:default}.cc-icon{display:grid;place-items:center;line-height:0}.cc-tile.cc-adds .cc-icon{width:52px;height:52px;border-radius:50%;background:var(--cube-context-adds-bg, #f3e3d6);--cube-icon-stroke: var(--cube-context-adds-ink, #7a4a2b);--cube-icon-size: 26px}.cc-t,.cc-m{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;line-clamp:2;overflow:hidden;overflow-wrap:anywhere}.cc-t{font-size:17px;font-weight:700;line-height:1.2}.cc-m{font-size:13px;line-height:1.3;color:var(--cube-context-quiet, #5d6a64)}.cc-tick{font-size:13px;font-weight:800;color:var(--cube-context-in-use, #3b5a4c)}.cc-tile.cc-l0{border-radius:28px;padding:24px;gap:10px}.cc-l0 .cc-t{font-size:26px}.cc-l0 .cc-m{font-size:16px}.cc-l0 .cc-icon{--cube-icon-size: 64px}.cc-tile.cc-l0.cc-adds .cc-icon{width:96px;height:96px;--cube-icon-size: 40px}.cc-tile.cc-l2{border-radius:16px;padding:10px 6px;gap:5px}.cc-l2 .cc-t{font-size:14px}.cc-l2 .cc-m{font-size:12px}.cc-tile.cc-l3{border-radius:12px;padding:6px 4px;gap:3px}.cc-l3 .cc-t{font-size:12px}.cc-tile.cc-l4{border-radius:9px;padding:2px;gap:0}.cc-l3 .cc-icon,.cc-l4 .cc-icon{--cube-icon-size: 24px}.cc-tile.cc-l3.cc-adds .cc-icon,.cc-tile.cc-l4.cc-adds .cc-icon{width:30px;height:30px;--cube-icon-size: 18px}\n"]
2051
+ styles: [":host{display:block;font:inherit;color:var(--cube-context-ink, #1f2a26);--cube-square-place: color-mix(in srgb, var(--cube-context-line, #dae0d9) 55%, transparent);--cube-square-place-dashed: var(--cube-context-line, #dae0d9);--cube-square-radius: var(--cube-context-radius, 20px)}.cc-tile{all:unset;cursor:pointer;box-sizing:border-box;min-width:0;min-height:0;height:100%;overflow:hidden;display:grid;justify-items:center;align-content:center;gap:6px;padding:14px 10px 12px;text-align:center;background:var(--cube-context-tile, #ffffff);border:1px solid var(--cube-context-line, #dae0d9);border-radius:var(--cube-context-radius, 20px);user-select:none;-webkit-user-select:none;-webkit-touch-callout:none;transition:transform .16s}.cc-tile:active:not(:disabled){transform:scale(.97)}.cc-tile:focus-visible{outline:3px solid var(--cube-context-focus, #5f9a80);outline-offset:2px}.cc-tile.cc-in-use{border:2px solid var(--cube-context-in-use, #3b5a4c)}.cc-tile.cc-pale{background:transparent;border:2px dashed var(--cube-context-line, #dae0d9);color:var(--cube-context-quiet, #5d6a64)}.cc-tile.cc-adds{border:2px solid var(--cube-context-adds, #c8693f)}.cc-tile.cc-busy{opacity:.6;cursor:progress}.cc-tile:disabled:not(.cc-busy){cursor:default}.cc-icon{display:grid;place-items:center;line-height:0}.cc-tile.cc-adds .cc-icon{width:52px;height:52px;border-radius:50%;background:var(--cube-context-adds-bg, #f3e3d6);--cube-icon-stroke: var(--cube-context-adds-ink, #7a4a2b);--cube-icon-size: 26px}.cc-t,.cc-m{display:-webkit-box;-webkit-box-orient:vertical;overflow:hidden;overflow-wrap:anywhere}.cc-t{-webkit-line-clamp:var(--cube-context-title-lines, 2);line-clamp:var(--cube-context-title-lines, 2)}.cc-m{-webkit-line-clamp:var(--cube-context-line-lines, 2);line-clamp:var(--cube-context-line-lines, 2)}.cc-t{font-size:var(--cube-context-title-size, 17px);font-weight:700;line-height:1.2}.cc-m{font-size:var(--cube-context-line-size, 13px);line-height:1.3;color:var(--cube-context-quiet, #5d6a64)}.cc-tick{font-size:var(--cube-context-line-size, 13px);font-weight:800;color:var(--cube-context-in-use, #3b5a4c)}.cc-tile.cc-l0{border-radius:28px;padding:24px;gap:10px}.cc-l0 .cc-t{font-size:calc(var(--cube-context-title-size, 17px) * 26 / 17)}.cc-l0 .cc-m{font-size:calc(var(--cube-context-line-size, 13px) * 16 / 13)}.cc-l0 .cc-icon{--cube-icon-size: 64px}.cc-tile.cc-l0.cc-adds .cc-icon{width:96px;height:96px;--cube-icon-size: 40px}.cc-tile.cc-l2{border-radius:16px;padding:10px 6px;gap:5px}.cc-l2 .cc-t{font-size:calc(var(--cube-context-title-size, 17px) * 14 / 17)}.cc-l2 .cc-m{font-size:calc(var(--cube-context-line-size, 13px) * 12 / 13)}.cc-tile.cc-l3{border-radius:12px;padding:6px 4px;gap:3px}.cc-l3 .cc-t{font-size:calc(var(--cube-context-title-size, 17px) * 12 / 17)}.cc-tile.cc-l4{border-radius:9px;padding:2px;gap:0}.cc-l3 .cc-icon,.cc-l4 .cc-icon{--cube-icon-size: 24px}.cc-tile.cc-l3.cc-adds .cc-icon,.cc-tile.cc-l4.cc-adds .cc-icon{width:30px;height:30px;--cube-icon-size: 18px}\n"]
2052
2052
  }]
2053
2053
  }],
2054
2054
  ctorParameters: () => [],
@@ -1 +1 @@
1
- {"version":3,"file":"selimssevgi-cube-design-angular.mjs","names":[],"sources":["../../../projects/cube-design-angular/src/lib/drawing/cube-drawing.ts","../../../projects/cube-design-angular/src/lib/cube-picture/cube-picture.ts","../../../projects/cube-design-angular/src/lib/hold/cube-hold.ts","../../../projects/cube-design-angular/src/lib/icon/cube-icon.ts","../../../projects/cube-design-angular/src/lib/context-cube/context-cube.ts","../../../projects/cube-design-angular/src/lib/context-cube/arrange.ts","../../../projects/cube-design-angular/src/lib/context-cube/levels.ts","../../../projects/cube-design-angular/src/lib/square/turning-rows.ts","../../../projects/cube-design-angular/src/lib/square/cube-square.ts","../../../projects/cube-design-angular/src/lib/context-cube/cube-context.ts"],"sourcesContent":["/**\n * drawing a cube of small cubes in isometric view: the left, right and top faces, each split into\n * n × n stickers. a sticker is coloured by a piece, or pale while nothing is known for it.\n *\n * the same projection anlat, mosaic and cubes drew by hand before this package (cube design,\n * `07-visual.md`). pure functions, no angular: they can be used anywhere.\n */\n\n/** The side of the smallest cube that holds this many pieces, up to 7 × 7 × 7. */\nexport function sizeFor(count: number): number {\n let s = 1;\n while (s * s * s < count && s < 7) s++;\n return s;\n}\n\nexport type Face = 'top' | 'left' | 'right';\n\nexport interface Sticker {\n face: Face;\n /** The sticker's square, as SVG points. */\n outer: string;\n /** The coloured inset inside it. */\n inner: string;\n colour: string | null;\n}\n\nexport interface Drawing {\n width: number;\n height: number;\n viewBox: string;\n /** The faint bigger cube it can grow into, as dashed outlines. */\n hint: string[];\n stickers: Sticker[];\n}\n\nexport interface DrawOptions {\n /** Show the next size as a faint cube behind (only while it is small). */\n hint?: boolean;\n /** A value: one colour on every sticker. */\n whole?: boolean;\n /** How many times it has been turned: shifts the colours round the stickers. */\n rot?: number;\n}\n\nconst C30 = Math.cos(Math.PI / 6);\ntype Point = [number, number];\n\nfunction poly(pts: Point[], k: number): string {\n const cx = pts.reduce((a, q) => a + q[0], 0) / pts.length;\n const cy = pts.reduce((a, q) => a + q[1], 0) / pts.length;\n return pts\n .map(([x, y]) => `${(cx + (x - cx) * k).toFixed(1)},${(cy + (y - cy) * k).toFixed(1)}`)\n .join(' ');\n}\n\nfunction squares(n: number, s: number, shift: Point): { face: Face; pts: Point[] }[] {\n const ox = n * s * C30;\n const oy = n * s;\n const p = (x: number, y: number, z: number): Point => [\n shift[0] + ox + (x - y) * C30 * s,\n shift[1] + oy + (x + y) * 0.5 * s - z * s,\n ];\n const out: { face: Face; pts: Point[] }[] = [];\n for (let a = 0; a < n; a++)\n for (let b = n - 1; b >= 0; b--)\n out.push({\n face: 'left',\n pts: [p(a, n, b + 1), p(a + 1, n, b + 1), p(a + 1, n, b), p(a, n, b)],\n });\n for (let a = 0; a < n; a++)\n for (let b = n - 1; b >= 0; b--)\n out.push({\n face: 'right',\n pts: [p(n, a, b + 1), p(n, a + 1, b + 1), p(n, a + 1, b), p(n, a, b)],\n });\n for (let a = 0; a < n; a++)\n for (let b = 0; b < n; b++)\n out.push({\n face: 'top',\n pts: [p(a, b, n), p(a + 1, b, n), p(a + 1, b + 1, n), p(a, b + 1, n)],\n });\n return out;\n}\n\n/** A cube for `count` pieces, `width` wide, coloured by `colours` in sticker order. */\nexport function drawCube(\n count: number,\n colours: (string | null)[],\n width: number,\n options: DrawOptions = {},\n): Drawing {\n const n = sizeFor(Math.max(1, count));\n const hinted = !!options.hint && count < 9;\n const big = hinted ? n + 1 : n;\n const s = width / (2 * big * C30);\n const hint = hinted ? squares(big, s, [0, 0]).map((q) => poly(q.pts, 0.86)) : [];\n const shift: Point = hinted ? [(big - n) * s * C30, (big - n) * s * 2] : [0, 0];\n const k = colours.length ? (options.rot ?? 0) % colours.length : 0;\n const turned = colours.slice(k).concat(colours.slice(0, k));\n const stickers = squares(n, s, shift).map((q, i) => ({\n face: q.face,\n outer: poly(q.pts, 1),\n inner: poly(q.pts, 0.86),\n colour: options.whole ? (colours[0] ?? null) : (turned[i] ?? null),\n }));\n const height = 2 * big * s;\n return {\n width,\n height: Math.round(height),\n viewBox: `-2 -2 ${(width + 4).toFixed(1)} ${(height + 4).toFixed(1)}`,\n hint,\n stickers,\n };\n}\n","import { ChangeDetectionStrategy, Component, computed, input } from '@angular/core';\nimport { drawCube } from '../drawing/cube-drawing';\n\n/**\n * a cube of small cubes, one per piece: coloured where something is known, pale where not.\n *\n * its look comes from css variables, so each app keeps its own dialect (the light one of cubes and\n * anlat, the dark one of mosaic). every variable has a light fallback, so it draws without any;\n * `tokens/light.css` and `tokens/dark.css` set them all.\n */\n@Component({\n selector: 'cube-picture',\n template: `\n @let d = drawing();\n <svg\n [attr.viewBox]=\"d.viewBox\"\n [attr.width]=\"d.width\"\n [attr.height]=\"d.height\"\n aria-hidden=\"true\"\n >\n @for (q of d.hint; track $index) {\n <polygon class=\"hint\" [attr.points]=\"q\" />\n }\n @for (q of d.stickers; track $index) {\n <polygon [attr.points]=\"q.outer\" [attr.class]=\"'side ' + q.face\" />\n }\n @for (q of d.stickers; track $index) {\n <polygon\n [attr.points]=\"q.inner\"\n [attr.class]=\"q.colour ? 'sticker' : 'sticker unknown'\"\n [attr.fill]=\"q.colour\"\n />\n }\n </svg>\n `,\n styles: `\n :host {\n display: inline-block;\n line-height: 0;\n }\n svg {\n overflow: visible;\n }\n .hint {\n fill: none;\n stroke: var(--cube-hint, #87938c);\n stroke-width: 1;\n stroke-dasharray: 3 3;\n opacity: var(--cube-hint-opacity, 0.5);\n }\n .side {\n stroke: var(--cube-edge, #cdd8d0);\n stroke-width: var(--cube-edge-width, 0.6);\n }\n .top {\n fill: var(--cube-top, #f9fbf8);\n }\n .left {\n fill: var(--cube-left, #e9eee9);\n }\n .right {\n fill: var(--cube-right, #dfe6e0);\n }\n .sticker {\n stroke: var(--cube-sticker-edge, rgba(31, 45, 39, 0.28));\n stroke-width: 1;\n }\n .unknown {\n fill: var(--cube-unknown, #e3e7e1);\n stroke: var(--cube-unknown-edge, none);\n }\n `,\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class CubePicture {\n /** how many pieces: the cube is the smallest n × n × n that holds them. */\n readonly count = input(1);\n /** the stickers' colours in order; null is a sticker not known yet. */\n readonly colours = input<(string | null)[]>([]);\n /** the width in pixels. */\n readonly width = input(64);\n /** show the bigger cube it can grow into, faintly, while it is small. */\n readonly hint = input(false);\n /** one colour on every sticker (a value). */\n readonly whole = input(false);\n /** how many times it was turned: shifts the colours round the stickers. */\n readonly rot = input(0);\n\n protected readonly drawing = computed(() =>\n drawCube(this.count(), this.colours(), this.width(), {\n hint: this.hint(),\n whole: this.whole(),\n rot: this.rot(),\n }),\n );\n}\n","import { DestroyRef, Directive, ElementRef, inject, input, output } from '@angular/core';\n\n/** what a hold reports: how it came, on which element, and the event that ended it. */\nexport interface CubeHeld {\n /** `press`: a finger, pen or the main mouse button stayed put; `menu`: a contextmenu event. */\n via: 'press' | 'menu';\n /** the element holding the directive. */\n element: HTMLElement;\n /** the pointerdown that was held, or the contextmenu. */\n event: Event;\n}\n\n/** how long a press is held before it is a hold (cubes' value; each app may set its own). */\nexport const CUBE_HOLD_MS = 520;\n/** how far a finger may move while pressing before it is a drag, in pixels. */\nexport const CUBE_HOLD_SLOP = 10;\n\n/**\n * pressing and holding a piece (principle 31): a long press, a right click or the menu key raise\n * one `cubeHeld`. a second finger (a pinch) or a drag never does, and the click that follows a hold\n * is swallowed so the piece does not also open. what a hold opens is the app's.\n *\n * it only reports: it never stops or prevents the pointer events, so a swipe or a pinch on the same\n * element keeps working.\n */\n@Directive({\n selector: '[cubeHold]',\n host: {\n '[style.user-select]': 'cubeHoldDisabled() ? null : \"none\"',\n '[style.-webkit-user-select]': 'cubeHoldDisabled() ? null : \"none\"',\n '[style.-webkit-touch-callout]': 'cubeHoldDisabled() ? null : \"none\"',\n '(pointerdown)': 'press($event)',\n '(pointermove)': 'moved($event)',\n '(pointerup)': 'lift($event)',\n '(pointercancel)': 'lift($event)',\n '(pointerleave)': 'lift($event)',\n '(contextmenu)': 'menu($event)',\n '(keydown)': 'pressFired = false; swallow = false',\n },\n})\nexport class CubeHold {\n /** no hold at all: the listeners do nothing and the browser's own menu stays. */\n readonly cubeHoldDisabled = input(false);\n /** how long a press is held before it is a hold, in milliseconds. */\n readonly cubeHoldMs = input(CUBE_HOLD_MS);\n /** how far the press may move before it is a drag instead, in pixels. */\n readonly cubeHoldSlop = input(CUBE_HOLD_SLOP);\n /** a short buzz (`navigator.vibrate(12)`) when it holds, where the device can. */\n readonly cubeHoldBuzz = input(true);\n\n /** the piece was held. */\n readonly cubeHeld = output<CubeHeld>();\n\n private readonly element = inject<ElementRef<HTMLElement>>(ElementRef).nativeElement;\n private timer: ReturnType<typeof setTimeout> | undefined;\n /** where the press started; null while nothing may become a hold. */\n private start: { x: number; y: number } | null = null;\n /** the pointers down on the element: two or more are a pinch. */\n private readonly pointers = new Set<number>();\n /** this press already held, so the phone's own contextmenu after it is not a second hold. */\n protected pressFired = false;\n /** a hold swallows the one click that follows it. */\n protected swallow = false;\n\n constructor() {\n // caught first, before the element's own (click), so a hold never also opens the piece.\n const swallow = (e: Event) => {\n if (!this.swallow) return;\n this.swallow = false;\n e.preventDefault();\n e.stopImmediatePropagation();\n };\n this.element.addEventListener('click', swallow, true);\n inject(DestroyRef).onDestroy(() => {\n clearTimeout(this.timer);\n this.element.removeEventListener('click', swallow, true);\n });\n }\n\n protected press(e: PointerEvent): void {\n this.pointers.add(e.pointerId);\n this.cancel();\n this.pressFired = false;\n this.swallow = false;\n // a second finger is a pinch, and only the main button holds.\n if (this.cubeHoldDisabled() || this.pointers.size > 1 || e.button > 0) return;\n this.start = { x: e.clientX, y: e.clientY };\n this.timer = setTimeout(() => this.fire('press', e), this.cubeHoldMs());\n }\n\n protected moved(e: PointerEvent): void {\n if (!this.start) return;\n if (Math.hypot(e.clientX - this.start.x, e.clientY - this.start.y) > this.cubeHoldSlop()) {\n this.cancel();\n }\n }\n\n protected lift(e: PointerEvent): void {\n this.pointers.delete(e.pointerId);\n this.cancel();\n }\n\n /** a right click, a phone's own long press, the menu key or shift+f10. */\n protected menu(e: Event): void {\n if (this.cubeHoldDisabled()) return;\n e.preventDefault();\n if (this.pressFired) return;\n this.fire('menu', e);\n }\n\n private fire(via: CubeHeld['via'], event: Event): void {\n this.cancel();\n if (this.cubeHoldDisabled()) return;\n this.pressFired = via === 'press';\n this.swallow = true;\n if (this.cubeHoldBuzz()) globalThis.navigator?.vibrate?.(12);\n this.cubeHeld.emit({ via, element: this.element, event });\n }\n\n private cancel(): void {\n clearTimeout(this.timer);\n this.timer = undefined;\n this.start = null;\n }\n}\n","import { ChangeDetectionStrategy, Component, computed, input } from '@angular/core';\n\n/** the views a cube can be shown in, each drawn as its own shape. */\nexport type CubeIconView = 'square' | 'one' | 'two' | 'three' | 'four' | 'grid-4x5' | 'grid-3x6';\n\n/** what a tile of a cube the app keeps is about (a context cube's parts and their choices). */\nexport type CubeIconName =\n | 'names'\n | 'name'\n | 'change'\n | 'move'\n | 'place'\n | 'whose'\n | 'library'\n | 'mine'\n | 'shown'\n | 'hidden'\n | 'view'\n | 'sort'\n | 'kept'\n | 'face'\n | 'added'\n | 'up'\n | 'down'\n | 'plus'\n | CubeIconView;\n\n/** every icon, in the order above. */\nexport const CUBE_ICON_NAMES: readonly CubeIconName[] = [\n 'names',\n 'name',\n 'change',\n 'move',\n 'place',\n 'whose',\n 'library',\n 'mine',\n 'shown',\n 'hidden',\n 'view',\n 'sort',\n 'kept',\n 'face',\n 'added',\n 'up',\n 'down',\n 'plus',\n 'square',\n 'one',\n 'two',\n 'three',\n 'four',\n 'grid-4x5',\n 'grid-3x6',\n];\n\n/** a view's icon is its own shape: the cells of one, two… across, a fixed grid, the square. */\nconst SHAPES: Record<CubeIconView, { cols: number; rows: number }> = {\n square: { cols: 3, rows: 3 },\n one: { cols: 1, rows: 3 },\n two: { cols: 2, rows: 3 },\n three: { cols: 3, rows: 3 },\n four: { cols: 4, rows: 3 },\n 'grid-4x5': { cols: 4, rows: 5 },\n 'grid-3x6': { cols: 3, rows: 6 },\n};\n\nexport interface CubeIconCell {\n x: number;\n y: number;\n w: number;\n h: number;\n}\n\n/**\n * the cells a view's icon draws in its 24 × 24 box, or null when the icon is not a view. one across\n * is a list, so its cells are rows.\n */\nexport function cubeIconCells(icon: CubeIconName): CubeIconCell[] | null {\n const shape = SHAPES[icon as CubeIconView];\n if (!shape) return null;\n const { cols, rows } = shape;\n const gap = 1.6;\n const size = Math.min((17 - gap * (cols - 1)) / cols, (17 - gap * (rows - 1)) / rows);\n const w = cols * size + gap * (cols - 1);\n const h = rows * size + gap * (rows - 1);\n const out: CubeIconCell[] = [];\n for (let r = 0; r < rows; r++)\n for (let c = 0; c < cols; c++)\n out.push({\n x: cols === 1 ? 3.5 : 12 - w / 2 + c * (size + gap),\n y: 12 - h / 2 + r * (size + gap),\n w: cols === 1 ? 17 : size,\n h: size,\n });\n return out;\n}\n\n/**\n * an icon on a tile of a cube the app keeps (a context cube and its parts), in place of a small\n * cube: such cubes hold no pieces, so their tiles show what they are about.\n *\n * its look comes from css variables (`--cube-icon-*`), each with a light fallback; `tokens/light.css`\n * and `tokens/dark.css` set them all. it says nothing: the tile's words come from the app.\n */\n@Component({\n selector: 'cube-icon',\n template: `\n <svg viewBox=\"0 0 24 24\" aria-hidden=\"true\">\n @if (cells(); as cs) {\n @for (c of cs; track $index) {\n <rect\n class=\"cell\"\n [attr.x]=\"c.x\"\n [attr.y]=\"c.y\"\n [attr.width]=\"c.w\"\n [attr.height]=\"c.h\"\n rx=\"0.8\"\n />\n }\n }\n @switch (icon()) {\n @case ('view') {\n <rect x=\"4\" y=\"4\" width=\"7\" height=\"7\" rx=\"1.5\" />\n <rect x=\"13\" y=\"4\" width=\"7\" height=\"7\" rx=\"1.5\" />\n <rect x=\"4\" y=\"13\" width=\"7\" height=\"7\" rx=\"1.5\" />\n <rect x=\"13\" y=\"13\" width=\"7\" height=\"7\" rx=\"1.5\" />\n }\n @case ('sort') {\n <path d=\"M8 19V5M4.5 8.5 8 5l3.5 3.5M16 5v14M12.5 15.5 16 19l3.5-3.5\" />\n }\n @case ('kept') {\n <path d=\"M5 7h14M5 12h14M5 17h9\" />\n }\n @case ('face') {\n <path d=\"M12 3.5 20 8v8l-8 4.5L4 16V8Z\" />\n <path d=\"M4 8l8 4.5L20 8M12 12.5v8\" />\n }\n @case ('added') {\n <circle cx=\"12\" cy=\"12\" r=\"8\" />\n <path d=\"M12 7.5V12l3 2\" />\n }\n @case ('up') {\n <path d=\"M12 19V5M6.5 10.5 12 5l5.5 5.5\" />\n }\n @case ('plus') {\n <path d=\"M12 5v14M5 12h14\" />\n }\n @case ('down') {\n <path d=\"M12 5v14M6.5 13.5 12 19l5.5-5.5\" />\n }\n @case ('names') {\n <path d=\"M3.5 12.5 11 5h8v8l-7.5 7.5a1.5 1.5 0 0 1-2.1 0L3.5 14.6a1.5 1.5 0 0 1 0-2.1Z\" />\n <circle cx=\"15.2\" cy=\"8.8\" r=\"1.4\" />\n }\n @case ('name') {\n <path d=\"M5 18 9.5 6h1L15 18M6.6 14h6.8\" />\n <path\n d=\"M17 11.5c1.6-1.2 3.5-.5 3.5 1.4V18M20.5 14.6c-2.6-.3-4 .4-4 1.8 0 1.9 2.7 2 4 .3\"\n />\n }\n @case ('change') {\n <path d=\"M4 20h4L19 9a2.8 2.8 0 0 0-4-4L4 16v4Z\" />\n <path d=\"M13.5 6.5l4 4\" />\n }\n @case ('move') {\n <path\n d=\"M4 8V6a2 2 0 0 1 2-2h4l2 2h6a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2v-1\"\n />\n <path d=\"M2.5 13H12M9 10l3 3-3 3\" />\n }\n @case ('place') {\n <path\n d=\"M4 8V6a2 2 0 0 1 2-2h4l2 2h6a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V8Z\"\n />\n }\n @case ('whose') {\n <circle cx=\"9\" cy=\"8\" r=\"3.2\" />\n <path d=\"M3 19c.6-3.4 3-5.2 6-5.2s5.4 1.8 6 5.2\" />\n <path d=\"M16 5.5a3 3 0 0 1 0 5.6M18.5 14.4c1.4.8 2.3 2.4 2.5 4.6\" />\n }\n @case ('library') {\n <path d=\"M4 5h4v15H4zM10 5h4v15h-4z\" />\n <path d=\"m16 6 3.6-1 3 14.4-3.6 1z\" />\n }\n @case ('mine') {\n <circle cx=\"12\" cy=\"8\" r=\"3.4\" />\n <path d=\"M5 20c.7-4 3.5-6 7-6s6.3 2 7 6\" />\n }\n @case ('shown') {\n <path d=\"M3 12s3.2-6 9-6 9 6 9 6-3.2 6-9 6-9-6-9-6Z\" />\n <circle cx=\"12\" cy=\"12\" r=\"2.6\" />\n }\n @case ('hidden') {\n <path d=\"M3 12s3.2-6 9-6c1.6 0 3 .45 4.2 1.1M21 12s-3.2 6-9 6c-1.6 0-3-.45-4.2-1.1\" />\n <path d=\"M4.5 19.5 19.5 4.5\" />\n }\n }\n </svg>\n `,\n styles: `\n :host {\n display: inline-block;\n width: var(--cube-icon-size, 34px);\n height: var(--cube-icon-size, 34px);\n line-height: 0;\n }\n svg {\n width: 100%;\n height: 100%;\n fill: none;\n stroke: var(--cube-icon-stroke, #1f2a26);\n stroke-width: var(--cube-icon-stroke-width, 1.7);\n stroke-linecap: round;\n stroke-linejoin: round;\n }\n .cell {\n fill: var(--cube-icon-stroke, #1f2a26);\n stroke: none;\n opacity: var(--cube-icon-cell-opacity, 0.8);\n }\n :host(.in-use) svg {\n stroke: var(--cube-icon-in-use, #3b5a4c);\n }\n :host(.in-use) .cell {\n fill: var(--cube-icon-in-use, #3b5a4c);\n }\n `,\n host: { '[class.in-use]': 'inUse()' },\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class CubeIcon {\n /** what the tile is about. */\n readonly icon = input.required<CubeIconName>();\n /** the one in use among its siblings: drawn in the in-use colour. */\n readonly inUse = input(false);\n\n protected readonly cells = computed(() => cubeIconCells(this.icon()));\n}\n","import { InjectionToken } from '@angular/core';\nimport { Direction, ViewKey } from './arrange';\n\n/*\n * the context cube: behind every piece sits a second cube, the app's, where it keeps how the piece\n * is named, shown and kept. pressing and holding a piece walks into it (principle 31; cubes calls it\n * the own cube, decisions 39 and 40). this is its shape only: each app fills it from its own data\n * through a `ContextCubeSource`, and gives every word through `ContextWords`.\n */\n\n/**\n * the parts a context cube can have. the seven are the ones cubes found; an app may add its own,\n * any string, and they come after the known ones.\n */\nexport type ContextPartKey =\n 'names' | 'change' | 'view' | 'sort' | 'move' | 'whose' | 'hide' | (string & {});\n\n/** cubes' rows: how it is called (names, change), how it is shown (view, sort), what i do with it. */\nexport const CONTEXT_PART_ORDER: readonly ContextPartKey[] = [\n 'names',\n 'change',\n 'view',\n 'sort',\n 'move',\n 'whose',\n 'hide',\n];\n\n/** the parts in their rows; parts an app added come last, in the order it gave them. twice is once. */\nexport function orderParts(parts: readonly ContextPartKey[]): ContextPartKey[] {\n const unique = [...new Set(parts)];\n const known = CONTEXT_PART_ORDER.filter((p) => unique.includes(p));\n return [...known, ...unique.filter((p) => !CONTEXT_PART_ORDER.includes(p))];\n}\n\n/** one tile of a level. its title and line always come from the app. */\nexport interface ContextTile<D = unknown> {\n /** unique among its level. */\n key: string;\n title: string;\n line?: string | null;\n /** the icon's name: a part, a view key, a direction, or one of the app's. */\n icon: string;\n /** the one in use among its siblings (the name in use, shown or hidden, the view). */\n inUse?: boolean;\n /** drawn quietly: something that can be read but not used. */\n pale?: boolean;\n /** the plus: keeps something new beside the others, always last. */\n adds?: boolean;\n /** what the tile stands for, for the app's own `pick`. */\n data?: D;\n}\n\n/** where in the context cube one is: [] is its top (its parts), ['names'] a part, ['sort', by] deeper. */\nexport type ContextPath = readonly string[];\n\n/** what a pick does: walk into a deeper level, end the journey, step one level out, or nothing. */\nexport type ContextPick =\n { kind: 'enter'; path: string[] } | { kind: 'done' } | { kind: 'out' } | { kind: 'stay' };\n\n/** what an app gives for its own held type `T`: a piece, a cube, a to-do, a level. */\nexport interface ContextCubeSource<T = unknown> {\n /** the parts this held thing has, in any order (`orderParts` puts them in rows). */\n parts(held: T): ContextPartKey[];\n /** the tiles of one level, or null when that path does not exist for it. */\n level(held: T, path: ContextPath): ContextTile[] | null;\n /** a tile was tapped at that path. */\n pick(held: T, path: ContextPath, tile: ContextTile): ContextPick | Promise<ContextPick>;\n}\n\n/** a title and its line, in the app's language. */\nexport interface ContextWord {\n title: string;\n line?: string | null;\n}\n\n/** a name a piece has had, as the names level lists it. */\nexport interface ContextName {\n name: string;\n /** the one in use. */\n current: boolean;\n /** the day it was given, as the app keeps it. */\n on?: string | null;\n /** whose hands gave it. */\n by?: string | null;\n /** whether it was ever in use, or only kept beside. */\n used?: boolean;\n}\n\n/** every word the context cube shows. the package ships none. */\nexport interface ContextWords {\n /** each part's title and line; a part with no word has an empty title. */\n parts: Partial<Record<ContextPartKey, ContextWord>>;\n /** each view's name. */\n views: Partial<Record<ViewKey, ContextWord>>;\n /** the two directions of a sort, when a sort option has none of its own. */\n directions: Record<Direction, ContextWord>;\n /** the two pieces of hide. */\n hide: { shown: ContextWord; hidden: ContextWord };\n /** the plus among the names, and the line under each name (its day and hands). */\n names: { another: ContextWord; line?: (name: ContextName) => string | null };\n /** said on the one in use, when the app wants it said. */\n inUse?: string;\n}\n\n/** the app's source of context cubes. */\nexport const CONTEXT_CUBE_SOURCE = new InjectionToken<ContextCubeSource<any>>(\n 'CONTEXT_CUBE_SOURCE',\n);\n\n/** the app's words for the context cube. */\nexport const CONTEXT_CUBE_WORDS = new InjectionToken<ContextWords>('CONTEXT_CUBE_WORDS');\n\n/** what the top level shows of a part now: the view in use, the name, shown or hidden. */\nexport interface PartNow {\n line?: string | null;\n icon?: string;\n}\n\n/**\n * the icon a part's tile shows when the app gives none of what it holds now. most parts are drawn\n * by their own name; hide has no icon of its own and shows shown (the eye), since a piece is in\n * sight until it is hidden. an app passes `now.hide.icon` (`shown` or `hidden`) to say which.\n */\nexport const PART_ICONS: Partial<Record<ContextPartKey, string>> = { hide: 'shown' };\n\n/** the top of a context cube: its parts in rows, each with its word and, when given, what it holds now. */\nexport function partsLevel(\n parts: readonly ContextPartKey[],\n words: ContextWords,\n now: Partial<Record<ContextPartKey, PartNow>> = {},\n): ContextTile<ContextPartKey>[] {\n return orderParts(parts).map((p) => ({\n key: p,\n title: words.parts[p]?.title ?? '',\n line: now[p]?.line !== undefined ? now[p]?.line : (words.parts[p]?.line ?? null),\n icon: now[p]?.icon ?? PART_ICONS[p] ?? p,\n data: p,\n }));\n}\n","/*\n * how a cube's pieces are laid out and in what order they come, moved from cubes\n * (`core/world/arrange.ts`, design decision 40). both change the view only, never the cube. the\n * words for each view and each direction come from the app (`ContextWords`).\n */\n\n/** the ways a cube's square can be laid out: the square first (cubes decision 23), then the rest. */\nexport type ViewKey = 'square' | 'one' | 'two' | 'three' | 'four' | 'grid-4x5' | 'grid-3x6';\n\n/** every view, in the order they are offered. */\nexport const VIEW_KEYS: readonly ViewKey[] = [\n 'square',\n 'one',\n 'two',\n 'three',\n 'four',\n 'grid-4x5',\n 'grid-3x6',\n];\n\nexport const isView = (v: unknown): v is ViewKey => VIEW_KEYS.includes(v as ViewKey);\n\n/** columns and rows of a layout holding this many; every row is full, open places outlined. */\nexport interface Grid {\n cols: number;\n rows: number;\n}\n\nexport function gridFor(view: ViewKey, count: number): Grid {\n const n = Math.max(1, count);\n switch (view) {\n case 'square': {\n const side = Math.max(1, Math.ceil(Math.sqrt(n)));\n return { cols: side, rows: side };\n }\n case 'one':\n case 'two':\n case 'three':\n case 'four': {\n const cols = { one: 1, two: 2, three: 3, four: 4 }[view];\n return { cols, rows: Math.ceil(n / cols) };\n }\n case 'grid-4x5':\n case 'grid-3x6': {\n const [cols, rows] = view === 'grid-4x5' ? [4, 5] : [3, 6];\n return { cols, rows: rows * Math.ceil(n / (cols * rows)) };\n }\n }\n}\n\n/** up is the face's own order (a to z, oldest first, its first colour first); down the other way. */\nexport type Direction = 'up' | 'down';\n\n/** what an item is sorted by: text, a number, or nothing found (not known yet). */\nexport type SortValue = string | number | null | undefined;\n\n/**\n * items in the order a sort asks for. `by` reads what each item is sorted by; text is compared as\n * a person reads it, numbers as numbers. an item with nothing found is not known yet and comes last\n * in both directions (empty is the point, never hidden). ties keep the items' own order.\n */\nexport function sortItems<T>(items: readonly T[], by: (item: T) => SortValue, dir: Direction): T[] {\n const sign = dir === 'down' ? -1 : 1;\n const known = (v: SortValue): v is string | number => v !== null && v !== undefined && v !== '';\n return items\n .map((item, at) => ({ item, at, value: by(item) }))\n .sort((a, b) => {\n const ka = known(a.value);\n const kb = known(b.value);\n if (!ka || !kb) return Number(!ka) - Number(!kb) || a.at - b.at;\n return sign * compare(a.value as string | number, b.value as string | number) || a.at - b.at;\n })\n .map((x) => x.item);\n}\n\nfunction compare(a: string | number, b: string | number): number {\n if (typeof a === 'number' && typeof b === 'number') return a - b;\n return String(a).localeCompare(String(b));\n}\n","import { Direction, VIEW_KEYS, ViewKey } from './arrange';\nimport { ContextName, ContextTile, ContextWord, ContextWords } from './context-cube';\n\n/*\n * the levels every app's context cube shares, as pure functions: names, hide, view and sort. each\n * returns the tiles of one level; what a tap does stays with the app (its `pick`), read from the\n * tile's `data`.\n */\n\n/** what a names tile holds: a name, or the plus. */\nexport type NamesData = { name: ContextName } | { another: true };\n\n/**\n * every name it has had: the one in use first, then the rest newest first (the names come oldest\n * first, as they were given). when the app allows it, a plus keeps a new one beside it without\n * using it.\n */\nexport function namesLevel(\n names: readonly ContextName[],\n words: ContextWords,\n opts: { canAdd?: boolean } = {},\n): ContextTile<NamesData>[] {\n const listed = [...names.filter((n) => n.current), ...names.filter((n) => !n.current).reverse()];\n const tiles: ContextTile<NamesData>[] = listed.map((n, i) => ({\n key: `name:${i}:${n.name}`,\n title: n.name,\n line: words.names.line?.(n) ?? null,\n icon: 'name',\n inUse: n.current,\n data: { name: n },\n }));\n if (opts.canAdd)\n tiles.push({\n key: 'name:+',\n title: words.names.another.title,\n line: words.names.another.line ?? null,\n icon: 'plus',\n adds: true,\n data: { another: true },\n });\n return tiles;\n}\n\n/** hide: a cube of two pieces, shown and hidden, one in use; `data` is whether it hides. */\nexport function hideLevel(hidden: boolean, words: ContextWords): ContextTile<boolean>[] {\n return [\n {\n key: 'hide:shown',\n title: words.hide.shown.title,\n line: words.hide.shown.line ?? null,\n icon: 'shown',\n inUse: !hidden,\n data: false,\n },\n {\n key: 'hide:hidden',\n title: words.hide.hidden.title,\n line: words.hide.hidden.line ?? null,\n icon: 'hidden',\n inUse: hidden,\n data: true,\n },\n ];\n}\n\n/**\n * view: every way to lay the cube out, its icon its own shape. the one in use says so in place of\n * its line, so both fit a small tile.\n */\nexport function viewLevel(\n now: ViewKey,\n words: ContextWords,\n views: readonly ViewKey[] = VIEW_KEYS,\n): ContextTile<ViewKey>[] {\n return views.map((v) => ({\n key: 'view:' + v,\n title: words.views[v]?.title ?? '',\n line: v === now ? null : (words.views[v]?.line ?? null),\n icon: v,\n inUse: v === now,\n data: v,\n }));\n}\n\n/** what a cube can be sorted by, given by the app: as kept, names, when added, each face. */\nexport interface SortOption {\n /** the app's own key: `kept`, `names`, `added`, a face's id. */\n by: string;\n title: string;\n line?: string | null;\n icon: string;\n /** false for an order with no two ways (as kept): picking it uses it at once. */\n directed?: boolean;\n /** this option's two directions in its own words (a to z, oldest first, small first). */\n up?: ContextWord;\n down?: ContextWord;\n}\n\n/** a sort in use. */\nexport interface SortNow {\n by: string;\n dir: Direction;\n}\n\n/** the two directions of an option, in its own words or else the app's general ones. */\nexport function directionWords(\n option: SortOption,\n words: ContextWords,\n): Record<Direction, ContextWord> {\n return {\n up: option.up ?? words.directions.up,\n down: option.down ?? words.directions.down,\n };\n}\n\n/**\n * sort: the options, the one in use marked; a directed option in use says its direction in place\n * of its line. picking a directed option walks into its two directions (`sortDirectionsLevel`).\n */\nexport function sortLevel(\n options: readonly SortOption[],\n now: SortNow,\n words: ContextWords,\n): ContextTile<SortOption>[] {\n return options.map((o) => {\n const inUse = now.by === o.by;\n const directed = o.directed !== false;\n return {\n key: 'sort:' + o.by,\n title: o.title,\n line: inUse && directed ? directionWords(o, words)[now.dir].title : (o.line ?? null),\n icon: o.icon,\n inUse,\n data: o,\n };\n });\n}\n\n/**\n * inside one sort option: its two directions, up first. whatever direction, an item with nothing\n * found is not known yet and comes last (`sortItems`); the words say so in their lines.\n */\nexport function sortDirectionsLevel(\n option: SortOption,\n now: SortNow,\n words: ContextWords,\n): ContextTile<Direction>[] {\n const w = directionWords(option, words);\n return (['up', 'down'] as const).map((dir) => ({\n key: 'dir:' + dir,\n title: w[dir].title,\n line: w[dir].line ?? null,\n icon: dir,\n inUse: now.by === option.by && now.dir === dir,\n data: dir,\n }));\n}\n","/**\n * turning rows (selim: row rotation), first tried in mosaic's todarch cube: a square of more\n * pieces than its front holds keeps its front full and turns its rows like the layers of a puzzle\n * cube. each row is a band of four sides; the pieces past the front fill the first row's other\n * sides, then the second row's, and so on, so the open places gather at the very end and a row\n * with nothing behind its front does not turn.\n *\n * this is only the layout, pure and without angular: which piece sits on which side of which row.\n * the front is cols × rows (3 × 3 as mosaic draws it, 4 × 5 and 3 × 6 for cubes' fixed grids).\n * when four sides a row are still not enough, rows are added below, as mosaic does.\n */\nexport interface TurningRows<T> {\n /** rows × 4 sides × cols places; null is an open place. side 0 is the front. */\n rows: (T | null)[][][];\n /** how many sides of each row hold something (1: only its front, it does not turn). */\n sides: number[];\n}\n\n/** the sides of one row: its front and the three behind it. */\nexport const TURNING_SIDES = 4;\n\nexport function turningRows<T>(\n pieces: readonly T[],\n own: T | null,\n cols = 3,\n rows = cols,\n): TurningRows<T> {\n const across = Math.max(1, Math.floor(cols));\n const down = Math.max(1, Math.floor(rows));\n const count = pieces.length + (own !== null ? 1 : 0);\n const perRow = across * TURNING_SIDES;\n const rowCount = Math.max(down, Math.ceil(count / perRow));\n const grid: (T | null)[][][] = Array.from({ length: rowCount }, () =>\n Array.from({ length: TURNING_SIDES }, () =>\n Array.from<T | null>({ length: across }).fill(null),\n ),\n );\n const front: [number, number][] = [];\n for (let r = 0; r < rowCount; r++) for (let c = 0; c < across; c++) front.push([r, c]);\n // the own box keeps the front's last place, so it is always seen\n const frontForPieces = own !== null ? front.slice(0, -1) : front;\n if (own !== null) grid[rowCount - 1][0][across - 1] = own;\n let next = 0;\n for (const [r, c] of frontForPieces) {\n if (next >= pieces.length) break;\n grid[r][0][c] = pieces[next++];\n }\n for (let r = 0; r < rowCount && next < pieces.length; r++)\n for (let s = 1; s < TURNING_SIDES && next < pieces.length; s++)\n for (let c = 0; c < across && next < pieces.length; c++) grid[r][s][c] = pieces[next++];\n const sides = grid.map(\n (row) => 1 + row.slice(1).filter((side) => side.some((t) => t !== null)).length,\n );\n return { rows: grid, sides };\n}\n","import {\n ChangeDetectionStrategy,\n Component,\n DestroyRef,\n Directive,\n ElementRef,\n TemplateRef,\n afterNextRender,\n computed,\n contentChild,\n effect,\n inject,\n input,\n signal,\n untracked,\n viewChild,\n} from '@angular/core';\nimport { NgTemplateOutlet } from '@angular/common';\nimport { ViewKey, gridFor } from '../context-cube/arrange';\nimport { TURNING_SIDES, turningRows } from './turning-rows';\n\n/*\n * the square: the complete grid of tiles every face of a cube is drawn with (cube design decision\n * 23, cubes decision 40). mosaic (`app-square-tiles`), cubes (`app-tiles`) and the context cube each\n * wrote it; this is the one they share. it only places the tiles an app gives: each app keeps\n * drawing its own tile through a template. turning rows ride on it (`turning`, off by default).\n */\n\n/** how close a square's places are: from one big tile (0) to only its icon or small cube (4). */\nexport type SquareLevel = 0 | 1 | 2 | 3 | 4;\n\n/** cubes' steps (`levelFor`), by a cell's side in px: a tile says less as the square fills. */\nexport function squareLevelFor(cell: number): SquareLevel {\n return cell >= 280 ? 0 : cell >= 150 ? 1 : cell >= 100 ? 2 : cell >= 70 ? 3 : 4;\n}\n\n/** places still open keep their outline; the fuller the square, the closer its places. */\nexport function squareGap(n: number): number {\n return n <= 2 ? 12 : n === 3 ? 10 : n === 4 ? 8 : 5;\n}\n\n/** the room a square may take: the width it is given, and the window's height for the square. */\nexport interface SquareRoom {\n width: number;\n /** the window's height less a head (48 px); only the square view is held to it, so it is seen whole. */\n tall: number;\n}\n\n/** one square laid out: its columns and rows, its size, and how much each tile says. */\nexport interface SquareLayout {\n cols: number;\n rows: number;\n /** the square's width and height, in px. */\n width: number;\n height: number;\n gap: number;\n /** a cell's width, in px. */\n cell: number;\n /** a row's height: the cell, or a list row's own height in one across. */\n rowHeight: number;\n level: SquareLevel;\n /** one across is a list: each row as tall as a tile with its name and line, not a square. */\n list: boolean;\n /** places not filled, outlined; they only ever finish the last row. */\n open: number;\n}\n\n/** the largest side a square takes on a wide screen, in px (cubes', mosaic's). */\nexport const SQUARE_MAX_SIDE = 880;\n/** a row's height in one across, the list (cubes'). */\nexport const SQUARE_LIST_ROW = 76;\n\n/**\n * how this many tiles are laid out in a view, in this much room. the square view is the smallest\n * n × n that holds them, as wide as the room and the window's height allow; the other views are as\n * long as they need and scroll. open places only finish the last row, so a view never draws a whole\n * empty row (decision of 2026-11-01): three pieces in 4 × 5 are one row of four. the square keeps\n * its own rule, its size coming from the pieces.\n */\nexport function squareLayout(\n view: ViewKey,\n count: number,\n room: SquareRoom,\n opts: { maxSide?: number; listRow?: number } = {},\n): SquareLayout {\n const n = Math.max(0, count);\n const grid = gridFor(view, n);\n const cols = grid.cols;\n const rows = view === 'square' ? grid.rows : Math.max(1, Math.ceil(n / cols));\n const width = Math.max(\n 0,\n Math.min(\n view === 'square' ? Math.min(room.width, room.tall) : room.width,\n opts.maxSide ?? SQUARE_MAX_SIDE,\n ),\n );\n const list = view === 'one';\n const gap = list ? 8 : squareGap(Math.max(cols, Math.min(rows, 5)));\n const cell = Math.max(0, (width - gap * (cols - 1)) / cols);\n const rowHeight = list ? (opts.listRow ?? SQUARE_LIST_ROW) : cell;\n return {\n cols,\n rows,\n width,\n height: rows * rowHeight + gap * (rows - 1),\n gap,\n cell,\n rowHeight,\n level: list ? 1 : squareLevelFor(cell),\n list,\n open: cols * rows - n,\n };\n}\n\n/** what a tile's template is given. */\nexport interface CubeSquareTileContext<T> {\n /** the tile, as the app gave it. */\n $implicit: T;\n index: number;\n /** how much it says (0 everything … 4 only its icon or small cube). */\n level: SquareLevel;\n /** its cell's width and height, in px, for a picture sized to it. */\n cell: number;\n rowHeight: number;\n /** one across: a list row, not a square cell. */\n list: boolean;\n}\n\n/**\n * `<ng-template cubeSquareTile let-tile let-level=\"level\">`: how the app draws one tile inside a\n * `<cube-square>`. the square only places it; the template fills its cell.\n */\n@Directive({ selector: 'ng-template[cubeSquareTile]' })\nexport class CubeSquareTile<T> {\n readonly template = inject<TemplateRef<CubeSquareTileContext<T>>>(TemplateRef);\n /** the tiles' type, for the template's checks: `[cubeSquareTile]=\"tiles()\"`. */\n readonly cubeSquareTile = input<readonly T[] | '' | undefined>();\n\n static ngTemplateContextGuard<T>(\n _dir: CubeSquareTile<T>,\n ctx: unknown,\n ): ctx is CubeSquareTileContext<T> {\n return true;\n }\n}\n\n/** the front a view keeps when its rows turn: the square's `across` × `across`, a fixed grid's page. */\nexport function turningFront(view: ViewKey, across = 3): { cols: number; rows: number } | null {\n if (view === 'square') return { cols: across, rows: across };\n if (view === 'grid-4x5') return { cols: 4, rows: 5 };\n if (view === 'grid-3x6') return { cols: 3, rows: 6 };\n return null;\n}\n\n/** narrower than this (a phone), a full square turns its rows, when `turning` is on. */\nexport const TURNING_BELOW = 640;\n/** turns after which a row with more stops nudging when the square opens. */\nexport const TURNING_NUDGE_UNTIL = 3;\n\n/** turns counted on this page when the app gives no key to keep them on the phone. */\nlet turnedHere = 0;\nconst readTurned = (key: string | null): number => {\n if (!key) return turnedHere;\n try {\n return Number(localStorage.getItem(key)) || 0;\n } catch {\n return turnedHere;\n }\n};\nconst noteTurned = (key: string | null): void => {\n turnedHere++;\n if (!key) return;\n try {\n localStorage.setItem(key, String(readTurned(key) + 1));\n } catch {\n // a phone that keeps nothing keeps nudging, which is fine\n }\n};\n\nconst reducedMotion = () =>\n typeof matchMedia === 'function' && matchMedia('(prefers-reduced-motion: reduce)').matches;\n\n/**\n * `<cube-square [tiles] [view]>`: the tiles an app gives, laid out as a complete square or another\n * view, each drawn by the app's `cubeSquareTile` template and told its level. it measures its own\n * width (up to the window's height for the square, at most `maxSide`), outlines its open places and\n * zooms a step when it has to hold more. it says no word and draws no tile. its look is css\n * variables (`--cube-square-*`), set in both token files.\n */\n@Component({\n selector: 'cube-square',\n imports: [NgTemplateOutlet],\n template: `\n @let sq = layout();\n @if (rings(); as r) {\n <div\n class=\"cs-turning\"\n [class]=\"'cs-turning cs-l' + sq.level\"\n [class.cs-dashed]=\"dashed()\"\n [attr.data-level]=\"sq.level\"\n [style.width.px]=\"sq.width\"\n [style.--cs-gap.px]=\"sq.gap\"\n >\n @for (row of r.rows; track ri; let ri = $index) {\n <div\n class=\"cs-row\"\n [class.cs-turns]=\"r.sides[ri] > 1\"\n [attr.data-row]=\"ri\"\n [style.height.px]=\"sq.rowHeight\"\n (pointerdown)=\"down(ri, $event)\"\n (pointermove)=\"move(ri, $event)\"\n (pointerup)=\"up(ri, $event)\"\n (pointercancel)=\"up(ri, $event)\"\n (keydown)=\"key(ri, $event)\"\n >\n @if (r.sides[ri] > 1) {\n <span class=\"cs-edge\" aria-hidden=\"true\"></span>\n }\n <div\n class=\"cs-band\"\n [class.cs-still]=\"dragging() === ri || still()\"\n [class.cs-nudging]=\"nudging()\"\n [style.transform]=\"\n 'translateZ(' + -sq.width / 2 + 'px) rotateY(' + angle(ri) + 'deg)'\n \"\n >\n @for (side of row; track si; let si = $index) {\n <div\n class=\"cs-side\"\n [attr.data-side]=\"si\"\n [style.grid-template-columns]=\"'repeat(' + sq.cols + ', minmax(0, 1fr))'\"\n [style.transform]=\"\n 'rotateY(' + si * 90 + 'deg) translateZ(' + sq.width / 2 + 'px)'\n \"\n [attr.aria-hidden]=\"sideOf(ri) === si ? null : 'true'\"\n [attr.inert]=\"sideOf(ri) === si ? null : ''\"\n >\n @for (t of side; track ci; let ci = $index) {\n @if (t !== null) {\n <div class=\"cs-cell\">\n @if (tile(); as tpl) {\n <ng-container\n [ngTemplateOutlet]=\"tpl.template\"\n [ngTemplateOutletContext]=\"{\n $implicit: t,\n index: indexOf(t),\n level: sq.level,\n cell: sq.cell,\n rowHeight: sq.rowHeight,\n list: false,\n }\"\n />\n }\n </div>\n } @else if (si < r.sides[ri]) {\n <div class=\"cs-place\" aria-hidden=\"true\"></div>\n }\n }\n </div>\n }\n </div>\n </div>\n }\n </div>\n } @else {\n <div\n #grid\n [class]=\"'cs-square cs-l' + sq.level\"\n [class.cs-list]=\"sq.list\"\n [class.cs-dashed]=\"dashed()\"\n [attr.data-level]=\"sq.level\"\n [style.width.px]=\"sq.width\"\n [style.height.px]=\"sq.height\"\n [style.--cs-gap.px]=\"sq.gap\"\n [style.grid-template-columns]=\"'repeat(' + sq.cols + ', minmax(0, 1fr))'\"\n [style.grid-template-rows]=\"'repeat(' + sq.rows + ', minmax(0, 1fr))'\"\n >\n @for (t of tiles(); track keyOf()(t, $index); let i = $index) {\n <div class=\"cs-cell\">\n @if (tile(); as tpl) {\n <ng-container\n [ngTemplateOutlet]=\"tpl.template\"\n [ngTemplateOutletContext]=\"{\n $implicit: t,\n index: i,\n level: sq.level,\n cell: sq.cell,\n rowHeight: sq.rowHeight,\n list: sq.list,\n }\"\n />\n }\n </div>\n }\n @for (i of openPlaces(); track i) {\n <div class=\"cs-place\" aria-hidden=\"true\"></div>\n }\n </div>\n }\n `,\n // every class is cs-prefixed: an app's global .tile, .square or .place rules would reach inside,\n // since emulated encapsulation only keeps the component's rules in.\n styles: `\n :host {\n display: block;\n }\n .cs-square {\n display: grid;\n gap: calc(var(--cs-gap) * var(--cube-square-gap-scale, 1));\n --cs-radius: var(--cube-square-radius, 20px);\n }\n .cs-cell {\n display: grid;\n min-width: 0;\n min-height: 0;\n }\n .cs-place {\n box-sizing: border-box;\n border: var(--cube-square-place-width, 1.5px) solid\n var(--cube-square-place, color-mix(in srgb, #dae0d9 55%, transparent));\n border-radius: var(--cs-radius);\n }\n /* something could come here (a cube of mine, a level with a plus): its open places are dashed. */\n .cs-dashed .cs-place {\n border-style: dashed;\n border-color: var(--cube-square-place-dashed, #dae0d9);\n }\n .cs-l0 {\n --cs-radius: 28px;\n }\n .cs-l2 {\n --cs-radius: 16px;\n }\n .cs-l3 {\n --cs-radius: 12px;\n }\n .cs-l4 {\n --cs-radius: 9px;\n }\n .cs-l4 .cs-place {\n border-width: 1px;\n }\n /* turning rows: each row a band of four sides, turned like a puzzle cube's layer. */\n .cs-turning {\n display: flex;\n flex-direction: column;\n gap: calc(var(--cs-gap) * var(--cube-square-gap-scale, 1));\n --cs-radius: var(--cube-square-radius, 20px);\n }\n .cs-row {\n position: relative;\n perspective: 1400px;\n touch-action: pan-y;\n user-select: none;\n -webkit-user-select: none;\n outline: none;\n }\n .cs-row:focus-visible {\n outline: 2px solid var(--cube-square-focus, #5f9a80);\n outline-offset: 3px;\n border-radius: var(--cs-radius);\n }\n .cs-band {\n position: absolute;\n inset: 0;\n transform-style: preserve-3d;\n transition: transform 380ms cubic-bezier(0.2, 0.8, 0.2, 1);\n }\n .cs-band.cs-nudging {\n transition: transform 520ms cubic-bezier(0.4, 0, 0.2, 1);\n }\n .cs-band.cs-still {\n transition: none;\n }\n .cs-side {\n position: absolute;\n inset: 0;\n display: grid;\n gap: calc(var(--cs-gap) * var(--cube-square-gap-scale, 1));\n backface-visibility: hidden;\n }\n /* the hint: the edge of the next side, on a row that has more. */\n .cs-edge {\n pointer-events: none;\n position: absolute;\n top: 18%;\n bottom: 18%;\n right: calc(-1 * max(4px, var(--cs-gap) - 2px));\n z-index: 1;\n width: 3px;\n border-radius: 999px;\n background: var(--cube-square-edge, color-mix(in srgb, #5f9a80 45%, transparent));\n }\n `,\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class CubeSquare<T> {\n /** the tiles, in the order they are placed. */\n readonly tiles = input.required<readonly T[]>();\n /** how they are laid out: the square (the default), one to four across, 4 × 5, 3 × 6. */\n readonly view = input<ViewKey>('square');\n /** the largest side the square takes on a wide screen, in px. */\n readonly maxSide = input(SQUARE_MAX_SIDE);\n /** a row's height in one across, in px. */\n readonly listRow = input(SQUARE_LIST_ROW);\n /** open places dashed, where something could come (a cube of mine, a level with a plus). */\n readonly dashed = input(false);\n /** what keeps a tile the same tile across changes, so it is not drawn anew; its place by default. */\n readonly keyOf = input<(tile: T, index: number) => unknown>((_, i) => i);\n /**\n * turning rows (selim: row rotation, first in mosaic's todarch cube), off unless the app turns\n * them on: on a phone, a square or fixed grid holding more than its front keeps its size, and each\n * row becomes a band of four sides that a finger (or the arrow keys on a focused row) turns, bringing\n * in the pieces past the front (`turningRows`).\n */\n readonly turning = input(false);\n /** rows turn only on a screen narrower than this, in px; a wide screen shows the whole square. */\n readonly turnBelow = input(TURNING_BELOW);\n /** the square's front when its rows turn: `across` × `across` (3 × 3). */\n readonly across = input(3);\n /** which tile is my own box: it keeps the front's last place while the rows turn. */\n readonly isOwn = input<((tile: T) => boolean) | null>(null);\n /** where the turns are counted on this phone (localStorage), so the nudge stops after a few. */\n readonly nudgeKey = input<string | null>(null);\n\n protected readonly tile = contentChild<CubeSquareTile<T>>(CubeSquareTile);\n private readonly grid = viewChild<ElementRef<HTMLElement>>('grid');\n /** the host's width and the window's height, followed as either changes. */\n private readonly room = signal<SquareRoom>({ width: 0, tall: 0 });\n\n /** the layout now: columns, rows, size, gap, level and open places. */\n /** the front kept while the rows turn, or null when they do not (off, a wide screen, all fit). */\n readonly front = computed(() => {\n if (!this.turning()) return null;\n if ((this.room().width || 354) >= this.turnBelow()) return null;\n const front = turningFront(this.view(), Math.max(1, Math.floor(this.across())));\n return front && this.tiles().length > front.cols * front.rows ? front : null;\n });\n\n /** the layout now: columns, rows, size, gap, level and open places. */\n readonly layout = computed(() => {\n const r = this.room();\n const width = r.width || 354;\n const room = { width, tall: r.tall || width };\n const opts = { maxSide: this.maxSide(), listRow: this.listRow() };\n const front = this.front();\n if (!front) return squareLayout(this.view(), this.tiles().length, room, opts);\n // turning: laid out as its full front, then as many rows as the turning rows need\n const view = this.view();\n const full = squareLayout(view, front.cols * front.rows, room, opts);\n const rows = this.rings()?.rows.length ?? front.rows;\n return {\n ...full,\n rows,\n height: rows * full.rowHeight + full.gap * (rows - 1),\n open: 0,\n };\n });\n\n /** the turning rows: rows × four sides × cols, and how many sides of each hold something. */\n protected readonly rings = computed(() => {\n const front = this.front();\n if (!front) return null;\n const isOwn = this.isOwn();\n const tiles = this.tiles();\n const own = isOwn ? (tiles.find((t) => isOwn(t)) ?? null) : null;\n const pieces = own === null ? tiles : tiles.filter((t) => t !== own);\n return turningRows(pieces, own, front.cols, front.rows);\n });\n\n private readonly indexes = computed(() => new Map(this.tiles().map((t, i) => [t, i])));\n protected indexOf(t: T): number {\n return this.indexes().get(t) ?? 0;\n }\n protected readonly openPlaces = computed(() =>\n Array.from({ length: this.layout().open }, (_, i) => i),\n );\n\n /** each row's turn in degrees, and the row a finger is turning now. */\n private readonly angles = signal<Record<number, number>>({});\n protected readonly dragging = signal<number | null>(null);\n /** turns that should not animate (reduced motion). */\n protected readonly still = signal(reducedMotion());\n protected readonly nudging = signal(false);\n private drag: {\n row: number;\n id: number;\n x: number;\n y: number;\n base: number;\n moved: boolean;\n } | null = null;\n /** fingers on the square now: a second one is a pinch, never a turn. */\n private readonly fingers = new Set<number>();\n private suppressClick = false;\n private nudged = false;\n private readonly timers: ReturnType<typeof setTimeout>[] = [];\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef).nativeElement;\n\n protected angle(row: number): number {\n return this.angles()[row] ?? 0;\n }\n\n /** the side of a row facing me (0 to 3). */\n protected sideOf(row: number): number {\n const sides = TURNING_SIDES;\n return ((Math.round(-this.angle(row) / 90) % sides) + sides) % sides;\n }\n\n private filled(row: number): number {\n return this.rings()?.sides[row] ?? 1;\n }\n\n protected down(row: number, e: PointerEvent): void {\n this.fingers.add(e.pointerId);\n if (this.fingers.size > 1) {\n // a pinch: let the turn go, the row settles where it was\n this.cancelDrag();\n return;\n }\n if (this.filled(row) <= 1) return;\n this.drag = {\n row,\n id: e.pointerId,\n x: e.clientX,\n y: e.clientY,\n base: this.angle(row),\n moved: false,\n };\n }\n\n protected move(row: number, e: PointerEvent): void {\n const drag = this.drag;\n if (!drag || drag.row !== row || drag.id !== e.pointerId) return;\n const dx = e.clientX - drag.x;\n const dy = e.clientY - drag.y;\n if (!drag.moved) {\n // only a sideways drag turns; up and down is the page scrolling\n if (Math.abs(dx) < 8 || Math.abs(dx) < Math.abs(dy)) return;\n drag.moved = true;\n this.dragging.set(row);\n (e.currentTarget as HTMLElement | null)?.setPointerCapture?.(e.pointerId);\n }\n const width = this.layout().width || 354;\n this.angles.update((a) => ({ ...a, [row]: drag.base + (dx / width) * 90 }));\n }\n\n protected up(row: number, e: PointerEvent): void {\n this.fingers.delete(e.pointerId);\n const drag = this.drag;\n if (!drag || drag.row !== row || drag.id !== e.pointerId) return;\n this.drag = null;\n if (!drag.moved) return;\n this.dragging.set(null);\n this.suppressClick = true;\n setTimeout(() => (this.suppressClick = false));\n // a short swipe is enough to turn one side; it settles on a side, never between two\n const moved = this.angle(row) - drag.base;\n const steps =\n Math.abs(moved) > 12 ? Math.sign(moved) * Math.max(1, Math.round(Math.abs(moved) / 90)) : 0;\n this.settle(row, drag.base, steps);\n }\n\n private cancelDrag(): void {\n const drag = this.drag;\n this.drag = null;\n if (!drag?.moved) return;\n this.dragging.set(null);\n this.angles.update((a) => ({ ...a, [drag.row]: drag.base }));\n }\n\n /** turns a row `steps` sides from `base`, passing the sides with nothing on them. */\n private settle(row: number, base: number, steps: number): void {\n const filled = this.filled(row);\n const sideAt = (s: number) =>\n ((Math.round(-(base + s * 90) / 90) % TURNING_SIDES) + TURNING_SIDES) % TURNING_SIDES;\n let n = steps;\n while (n !== 0 && sideAt(n) >= filled) n += Math.sign(n);\n this.angles.update((a) => ({ ...a, [row]: base + n * 90 }));\n if (n !== 0) noteTurned(this.nudgeKey());\n }\n\n /** the arrow keys on a focused row turn it, so a keyboard reaches every piece too. */\n protected key(row: number, e: KeyboardEvent): void {\n if (e.key !== 'ArrowRight' && e.key !== 'ArrowLeft') return;\n if (this.filled(row) <= 1) return;\n e.preventDefault();\n const col = this.focusedColumn(e.target as HTMLElement | null);\n // the next side comes in from the right, as a swipe to the left brings it\n this.settle(row, this.angle(row), e.key === 'ArrowRight' ? -1 : 1);\n setTimeout(() => this.focusSide(row, col));\n }\n\n private focusedColumn(target: HTMLElement | null): number {\n const cell = target?.closest('.cs-cell, .cs-place');\n const side = cell?.parentElement;\n return cell && side ? Array.from(side.children).indexOf(cell) : 0;\n }\n\n /** after a turn by the keys, focus goes to the same place on the side now facing me. */\n private focusSide(row: number, col: number): void {\n const side = this.host.querySelector<HTMLElement>(\n `.cs-row[data-row=\"${row}\"] .cs-side[data-side=\"${this.sideOf(row)}\"]`,\n );\n if (!side) return;\n const cells = Array.from(side.children) as HTMLElement[];\n const order = [cells[col], ...cells].filter(Boolean);\n const focusable = 'button, a[href], input, select, textarea, [tabindex]:not([tabindex=\"-1\"])';\n for (const cell of order) {\n const el = cell.matches(focusable) ? cell : cell.querySelector<HTMLElement>(focusable);\n if (el) {\n el.focus();\n return;\n }\n }\n side.closest<HTMLElement>('.cs-row')?.focus();\n }\n\n /** the nudge: rows with more turn a little and back, one after another, until i turned a few. */\n private nudge(): void {\n const rings = this.rings();\n if (this.nudged || !rings || reducedMotion()) return;\n if (readTurned(this.nudgeKey()) >= TURNING_NUDGE_UNTIL) return;\n const rows = rings.sides.flatMap((s, i) => (s > 1 ? [i] : []));\n if (!rows.length) return;\n this.nudged = true;\n this.nudging.set(true);\n const set = (row: number, angle: number) => {\n if (this.drag || this.dragging() !== null) return;\n this.angles.update((a) => ({ ...a, [row]: angle }));\n };\n rows.forEach((row, i) => {\n this.timers.push(\n setTimeout(() => set(row, -22), 500 + i * 180),\n setTimeout(() => set(row, 0), 1020 + i * 180),\n );\n });\n this.timers.push(setTimeout(() => this.nudging.set(false), 1600 + rows.length * 180));\n }\n\n constructor() {\n const host = this.host;\n const destroy = inject(DestroyRef);\n // the tap that ends a turn is not a tap on a tile\n const swallow = (e: Event) => {\n if (!this.suppressClick) return;\n e.stopPropagation();\n e.preventDefault();\n };\n host.addEventListener('click', swallow, true);\n destroy.onDestroy(() => {\n host.removeEventListener('click', swallow, true);\n this.timers.forEach(clearTimeout);\n });\n effect(() => {\n if (this.rings()) untracked(() => this.timers.push(setTimeout(() => this.nudge())));\n });\n afterNextRender(() => {\n const measure = () =>\n this.room.set({ width: host.clientWidth, tall: Math.max(320, window.innerHeight - 48) });\n measure();\n const watch = typeof ResizeObserver === 'function' ? new ResizeObserver(measure) : null;\n watch?.observe(host);\n window.addEventListener('resize', measure);\n destroy.onDestroy(() => {\n watch?.disconnect();\n window.removeEventListener('resize', measure);\n });\n });\n // a square that has to hold more zooms out a step (and in when it holds fewer); the other views\n // only grow longer.\n let before = 0;\n let beforeView: ViewKey | null = null;\n effect(() => {\n const { cols, list } = this.layout();\n const view = this.view();\n const el = this.grid()?.nativeElement;\n if (\n el &&\n before &&\n cols !== before &&\n view === beforeView &&\n !list &&\n !reducedMotion() &&\n typeof el.animate === 'function'\n ) {\n el.animate([{ transform: `scale(${cols / before})` }, { transform: 'none' }], {\n duration: 420,\n easing: 'cubic-bezier(.2,.7,.2,1)',\n });\n }\n before = cols;\n beforeView = view;\n });\n }\n}\n","import {\n ChangeDetectionStrategy,\n Component,\n computed,\n effect,\n inject,\n input,\n output,\n signal,\n untracked,\n} from '@angular/core';\nimport { CUBE_ICON_NAMES, CubeIcon, CubeIconName } from '../icon/cube-icon';\nimport {\n CubeSquare,\n CubeSquareTile,\n SquareLevel,\n squareGap,\n squareLevelFor,\n} from '../square/cube-square';\nimport { gridFor } from './arrange';\nimport {\n CONTEXT_CUBE_SOURCE,\n CONTEXT_CUBE_WORDS,\n ContextCubeSource,\n ContextPath,\n ContextTile,\n ContextWords,\n} from './context-cube';\n\n/*\n * the square that draws one level of a context cube: the tiles an app's `ContextCubeSource` gives\n * for the held thing at a path, as a complete square (cube design decision 23, cubes decisions 39\n * and 40). it never routes, zooms, draws a head or says a word of its own: each app hosts it in its\n * own route under its own head, and walks the path it reports.\n */\n\n/** how close a square's places are: from one big tile (0) to only its icon (4). */\nexport type ContextLevel = SquareLevel;\n\n/** cubes' steps, now the square's (`squareLevelFor`); kept under its first name. */\nexport const contextLevelFor: (cell: number) => ContextLevel = squareLevelFor;\n\n/** a level's square: n × n places, how far apart, and how much each tile says. */\nexport interface ContextSquare {\n /** places on a side. */\n n: number;\n /** the square's side, in px. */\n side: number;\n gap: number;\n level: ContextLevel;\n /** the places not filled, outlined so the square stays whole. */\n open: number;\n}\n\n/**\n * the square for this many tiles in this much room: the smallest n × n that holds them all\n * (`gridFor('square', count)`), as wide as the room, at most `maxSide`.\n */\nexport function contextSquare(count: number, room: number, maxSide = 880): ContextSquare {\n const { cols: n, rows } = gridFor('square', count);\n const side = Math.max(0, Math.min(room, maxSide));\n const gap = squareGap(n);\n const cell = (side - gap * (n - 1)) / n;\n return { n, side, gap, level: contextLevelFor(cell), open: n * rows - Math.max(0, count) };\n}\n\n/**\n * the icon a tile is drawn with: its own when `cube-icon` draws it, shown for `hide` (it has no icon\n * of its own), the plus for a tile that adds, and else a face (an app's own part with an icon the\n * package does not have).\n */\nexport function contextIcon(tile: Pick<ContextTile, 'icon' | 'adds'>): CubeIconName {\n if ((CUBE_ICON_NAMES as readonly string[]).includes(tile.icon)) return tile.icon as CubeIconName;\n if (tile.adds) return 'plus';\n if (tile.icon === 'hide') return 'shown';\n return 'face';\n}\n\n/** a tapped tile and the element it is drawn in. */\nexport interface ContextTapped {\n tile: ContextTile;\n element: HTMLElement;\n}\n\n/**\n * `<cube-context [held] [path]>`: one level of the held thing's context cube, as a complete square\n * of icon tiles. a tap asks the source's `pick`, and the answer comes out as `enter` (a deeper\n * path), `done` (the journey ends: a name, a view, shown or hidden was used) or `out` (one level\n * up); `stay` redraws the level where it is. a level the source does not have (null) is `out` too.\n *\n * the source and the words come from `CONTEXT_CUBE_SOURCE` and `CONTEXT_CUBE_WORDS`, or from the\n * `source` and `words` inputs when one screen holds a different one. its look is css variables\n * (`--cube-context-*`, `--cube-icon-*`), set in both token files.\n */\n@Component({\n selector: 'cube-context',\n imports: [CubeIcon, CubeSquare, CubeSquareTile],\n template: `\n <cube-square\n [tiles]=\"tiles()\"\n [dashed]=\"adds()\"\n [maxSide]=\"maxSide()\"\n [keyOf]=\"keyOf\"\n [class.cc-adds]=\"adds()\"\n >\n <ng-template [cubeSquareTile]=\"tiles()\" let-t let-level=\"level\">\n <button\n type=\"button\"\n [class]=\"'cc-tile cc-l' + level\"\n [class.cc-in-use]=\"!!t.inUse\"\n [class.cc-pale]=\"!!t.pale\"\n [class.cc-adds]=\"!!t.adds\"\n [class.cc-busy]=\"busy() === t.key\"\n [disabled]=\"busy() !== null\"\n [attr.aria-label]=\"level >= 4 ? t.title : null\"\n [attr.aria-current]=\"t.inUse ? 'true' : null\"\n [attr.title]=\"level >= 3 ? t.title : null\"\n (click)=\"tap(t, $any($event.currentTarget))\"\n >\n <span class=\"cc-icon\"><cube-icon [icon]=\"iconOf(t)\" [inUse]=\"!!t.inUse\" /></span>\n @if (level < 4) {\n <span class=\"cc-t\">{{ t.title }}</span>\n }\n @if (t.line && level < 3) {\n <span class=\"cc-m\">{{ t.line }}</span>\n }\n @if (t.inUse && inUseWord() && level < 3) {\n <span class=\"cc-tick\">{{ inUseWord() }}</span>\n }\n </button>\n </ng-template>\n </cube-square>\n `,\n // every class is cc-prefixed: an app's own .tile, .square or .place rules (cubes has them) are\n // global and would reach inside, since emulated encapsulation only keeps the component's rules in.\n styles: `\n :host {\n display: block;\n font: inherit;\n color: var(--cube-context-ink, #1f2a26);\n /* the square's open places in the context cube's own look */\n --cube-square-place: color-mix(in srgb, var(--cube-context-line, #dae0d9) 55%, transparent);\n --cube-square-place-dashed: var(--cube-context-line, #dae0d9);\n --cube-square-radius: var(--cube-context-radius, 20px);\n }\n .cc-tile {\n all: unset;\n cursor: pointer;\n box-sizing: border-box;\n min-width: 0;\n min-height: 0;\n height: 100%;\n overflow: hidden;\n display: grid;\n justify-items: center;\n align-content: center;\n gap: 6px;\n padding: 14px 10px 12px;\n text-align: center;\n background: var(--cube-context-tile, #ffffff);\n border: 1px solid var(--cube-context-line, #dae0d9);\n border-radius: var(--cube-context-radius, 20px);\n user-select: none;\n -webkit-user-select: none;\n -webkit-touch-callout: none;\n transition: transform 160ms;\n }\n .cc-tile:active:not(:disabled) {\n transform: scale(0.97);\n }\n .cc-tile:focus-visible {\n outline: 3px solid var(--cube-context-focus, #5f9a80);\n outline-offset: 2px;\n }\n .cc-tile.cc-in-use {\n border: 2px solid var(--cube-context-in-use, #3b5a4c);\n }\n .cc-tile.cc-pale {\n background: transparent;\n border: 2px dashed var(--cube-context-line, #dae0d9);\n color: var(--cube-context-quiet, #5d6a64);\n }\n .cc-tile.cc-adds {\n border: 2px solid var(--cube-context-adds, #c8693f);\n }\n .cc-tile.cc-busy {\n opacity: 0.6;\n cursor: progress;\n }\n .cc-tile:disabled:not(.cc-busy) {\n cursor: default;\n }\n .cc-icon {\n display: grid;\n place-items: center;\n line-height: 0;\n }\n .cc-tile.cc-adds .cc-icon {\n width: 52px;\n height: 52px;\n border-radius: 50%;\n background: var(--cube-context-adds-bg, #f3e3d6);\n --cube-icon-stroke: var(--cube-context-adds-ink, #7a4a2b);\n --cube-icon-size: 26px;\n }\n .cc-t,\n .cc-m {\n display: -webkit-box;\n -webkit-box-orient: vertical;\n -webkit-line-clamp: 2;\n line-clamp: 2;\n overflow: hidden;\n overflow-wrap: anywhere;\n }\n .cc-t {\n font-size: 17px;\n font-weight: 700;\n line-height: 1.2;\n }\n .cc-m {\n font-size: 13px;\n line-height: 1.3;\n color: var(--cube-context-quiet, #5d6a64);\n }\n .cc-tick {\n font-size: 13px;\n font-weight: 800;\n color: var(--cube-context-in-use, #3b5a4c);\n }\n .cc-tile.cc-l0 {\n border-radius: 28px;\n padding: 24px;\n gap: 10px;\n }\n .cc-l0 .cc-t {\n font-size: 26px;\n }\n .cc-l0 .cc-m {\n font-size: 16px;\n }\n .cc-l0 .cc-icon {\n --cube-icon-size: 64px;\n }\n .cc-tile.cc-l0.cc-adds .cc-icon {\n width: 96px;\n height: 96px;\n --cube-icon-size: 40px;\n }\n .cc-tile.cc-l2 {\n border-radius: 16px;\n padding: 10px 6px;\n gap: 5px;\n }\n .cc-l2 .cc-t {\n font-size: 14px;\n }\n .cc-l2 .cc-m {\n font-size: 12px;\n }\n .cc-tile.cc-l3 {\n border-radius: 12px;\n padding: 6px 4px;\n gap: 3px;\n }\n .cc-l3 .cc-t {\n font-size: 12px;\n }\n .cc-tile.cc-l4 {\n border-radius: 9px;\n padding: 2px;\n gap: 0;\n }\n .cc-l3 .cc-icon,\n .cc-l4 .cc-icon {\n --cube-icon-size: 24px;\n }\n .cc-tile.cc-l3.cc-adds .cc-icon,\n .cc-tile.cc-l4.cc-adds .cc-icon {\n width: 30px;\n height: 30px;\n --cube-icon-size: 18px;\n }\n `,\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class CubeContext {\n /** what was held: a piece, a cube, a to-do, a level, as the app's source knows it. */\n readonly held = input.required<unknown>();\n /** where in its context cube: [] is its top (the parts), ['names'] a part, ['sort', by] deeper. */\n readonly path = input<ContextPath>([]);\n /** a source for this screen alone; else `CONTEXT_CUBE_SOURCE`. */\n readonly source = input<ContextCubeSource<any> | null>(null);\n /** words for this screen alone; else `CONTEXT_CUBE_WORDS`. */\n readonly words = input<ContextWords | null>(null);\n /** the largest side the square takes on a wide screen, in px. */\n readonly maxSide = input(880);\n\n /** walk into a deeper level: the app puts this path in its own route. */\n readonly enter = output<string[]>();\n /** step one level out (or out of the context cube, from its top). */\n readonly out = output<void>();\n /** the journey ends: the tile that was used. */\n readonly done = output<ContextTile>();\n /**\n * a tile was tapped, before the source answers: the tile and its element, so the app can grow the\n * next level (or whatever the pick opens) out of the tile, as it zooms into any other piece.\n */\n readonly tapped = output<ContextTapped>();\n\n private readonly given = inject(CONTEXT_CUBE_SOURCE, { optional: true });\n private readonly givenWords = inject(CONTEXT_CUBE_WORDS, { optional: true });\n\n /** the tile whose pick is still being answered; every tile waits meanwhile. */\n protected readonly busy = signal<string | null>(null);\n /** bumped after a pick, so a source that keeps its data outside signals is read again. */\n private readonly again = signal(0);\n\n private readonly from = computed(() => {\n const s = this.source() ?? this.given;\n if (!s) throw new Error('cube-context: provide CONTEXT_CUBE_SOURCE or pass [source]');\n return s;\n });\n /** the path as one key, so the same path given anew is the same level. */\n private readonly where = computed(() => this.path().join('\\u0000'));\n private readonly level = computed(() => {\n this.again();\n return this.from().level(this.held(), this.path());\n });\n protected readonly tiles = computed(() => this.level() ?? []);\n protected readonly adds = computed(() => this.tiles().some((t) => !!t.adds));\n /** a tile stays the same tile across levels by its key. */\n protected readonly keyOf = (t: ContextTile) => t.key;\n protected readonly inUseWord = computed(() => (this.words() ?? this.givenWords)?.inUse ?? null);\n protected readonly iconOf = contextIcon;\n\n constructor() {\n // a path the source does not have (a part that went away) steps out.\n effect(() => {\n if (this.level() === null) untracked(() => this.out.emit());\n });\n // a new path is a new level: nothing is waiting any more.\n effect(() => {\n this.where();\n this.held();\n untracked(() => this.busy.set(null));\n });\n }\n\n protected async tap(tile: ContextTile, element?: HTMLElement): Promise<void> {\n if (this.busy() !== null) return;\n if (element) this.tapped.emit({ tile, element });\n const held = this.held();\n const path = this.path();\n const where = this.where();\n const here = () => this.held() === held && this.where() === where;\n this.busy.set(tile.key);\n try {\n const picked = await this.from().pick(held, path, tile);\n // the person walked elsewhere while it was answered: the answer is for a level gone.\n if (!here()) return;\n switch (picked.kind) {\n case 'enter':\n this.enter.emit(picked.path);\n break;\n case 'done':\n this.done.emit(tile);\n break;\n case 'out':\n this.out.emit();\n break;\n case 'stay':\n break;\n }\n } finally {\n if (here()) this.busy.set(null);\n this.again.update((n) => n + 1);\n }\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"selimssevgi-cube-design-angular.mjs","names":[],"sources":["../../../projects/cube-design-angular/src/lib/drawing/cube-drawing.ts","../../../projects/cube-design-angular/src/lib/cube-picture/cube-picture.ts","../../../projects/cube-design-angular/src/lib/hold/cube-hold.ts","../../../projects/cube-design-angular/src/lib/icon/cube-icon.ts","../../../projects/cube-design-angular/src/lib/context-cube/context-cube.ts","../../../projects/cube-design-angular/src/lib/context-cube/arrange.ts","../../../projects/cube-design-angular/src/lib/context-cube/levels.ts","../../../projects/cube-design-angular/src/lib/square/turning-rows.ts","../../../projects/cube-design-angular/src/lib/square/cube-square.ts","../../../projects/cube-design-angular/src/lib/context-cube/cube-context.ts"],"sourcesContent":["/**\n * drawing a cube of small cubes in isometric view: the left, right and top faces, each split into\n * n × n stickers. a sticker is coloured by a piece, or pale while nothing is known for it.\n *\n * the same projection anlat, mosaic and cubes drew by hand before this package (cube design,\n * `07-visual.md`). pure functions, no angular: they can be used anywhere.\n */\n\n/** The side of the smallest cube that holds this many pieces, up to 7 × 7 × 7. */\nexport function sizeFor(count: number): number {\n let s = 1;\n while (s * s * s < count && s < 7) s++;\n return s;\n}\n\nexport type Face = 'top' | 'left' | 'right';\n\nexport interface Sticker {\n face: Face;\n /** The sticker's square, as SVG points. */\n outer: string;\n /** The coloured inset inside it. */\n inner: string;\n colour: string | null;\n}\n\nexport interface Drawing {\n width: number;\n height: number;\n viewBox: string;\n /** The faint bigger cube it can grow into, as dashed outlines. */\n hint: string[];\n stickers: Sticker[];\n}\n\nexport interface DrawOptions {\n /** Show the next size as a faint cube behind (only while it is small). */\n hint?: boolean;\n /** A value: one colour on every sticker. */\n whole?: boolean;\n /** How many times it has been turned: shifts the colours round the stickers. */\n rot?: number;\n}\n\nconst C30 = Math.cos(Math.PI / 6);\ntype Point = [number, number];\n\nfunction poly(pts: Point[], k: number): string {\n const cx = pts.reduce((a, q) => a + q[0], 0) / pts.length;\n const cy = pts.reduce((a, q) => a + q[1], 0) / pts.length;\n return pts\n .map(([x, y]) => `${(cx + (x - cx) * k).toFixed(1)},${(cy + (y - cy) * k).toFixed(1)}`)\n .join(' ');\n}\n\nfunction squares(n: number, s: number, shift: Point): { face: Face; pts: Point[] }[] {\n const ox = n * s * C30;\n const oy = n * s;\n const p = (x: number, y: number, z: number): Point => [\n shift[0] + ox + (x - y) * C30 * s,\n shift[1] + oy + (x + y) * 0.5 * s - z * s,\n ];\n const out: { face: Face; pts: Point[] }[] = [];\n for (let a = 0; a < n; a++)\n for (let b = n - 1; b >= 0; b--)\n out.push({\n face: 'left',\n pts: [p(a, n, b + 1), p(a + 1, n, b + 1), p(a + 1, n, b), p(a, n, b)],\n });\n for (let a = 0; a < n; a++)\n for (let b = n - 1; b >= 0; b--)\n out.push({\n face: 'right',\n pts: [p(n, a, b + 1), p(n, a + 1, b + 1), p(n, a + 1, b), p(n, a, b)],\n });\n for (let a = 0; a < n; a++)\n for (let b = 0; b < n; b++)\n out.push({\n face: 'top',\n pts: [p(a, b, n), p(a + 1, b, n), p(a + 1, b + 1, n), p(a, b + 1, n)],\n });\n return out;\n}\n\n/** A cube for `count` pieces, `width` wide, coloured by `colours` in sticker order. */\nexport function drawCube(\n count: number,\n colours: (string | null)[],\n width: number,\n options: DrawOptions = {},\n): Drawing {\n const n = sizeFor(Math.max(1, count));\n const hinted = !!options.hint && count < 9;\n const big = hinted ? n + 1 : n;\n const s = width / (2 * big * C30);\n const hint = hinted ? squares(big, s, [0, 0]).map((q) => poly(q.pts, 0.86)) : [];\n const shift: Point = hinted ? [(big - n) * s * C30, (big - n) * s * 2] : [0, 0];\n const k = colours.length ? (options.rot ?? 0) % colours.length : 0;\n const turned = colours.slice(k).concat(colours.slice(0, k));\n const stickers = squares(n, s, shift).map((q, i) => ({\n face: q.face,\n outer: poly(q.pts, 1),\n inner: poly(q.pts, 0.86),\n colour: options.whole ? (colours[0] ?? null) : (turned[i] ?? null),\n }));\n const height = 2 * big * s;\n return {\n width,\n height: Math.round(height),\n viewBox: `-2 -2 ${(width + 4).toFixed(1)} ${(height + 4).toFixed(1)}`,\n hint,\n stickers,\n };\n}\n","import { ChangeDetectionStrategy, Component, computed, input } from '@angular/core';\nimport { drawCube } from '../drawing/cube-drawing';\n\n/**\n * a cube of small cubes, one per piece: coloured where something is known, pale where not.\n *\n * its look comes from css variables, so each app keeps its own dialect (the light one of cubes and\n * anlat, the dark one of mosaic). every variable has a light fallback, so it draws without any;\n * `tokens/light.css` and `tokens/dark.css` set them all.\n */\n@Component({\n selector: 'cube-picture',\n template: `\n @let d = drawing();\n <svg\n [attr.viewBox]=\"d.viewBox\"\n [attr.width]=\"d.width\"\n [attr.height]=\"d.height\"\n aria-hidden=\"true\"\n >\n @for (q of d.hint; track $index) {\n <polygon class=\"hint\" [attr.points]=\"q\" />\n }\n @for (q of d.stickers; track $index) {\n <polygon [attr.points]=\"q.outer\" [attr.class]=\"'side ' + q.face\" />\n }\n @for (q of d.stickers; track $index) {\n <polygon\n [attr.points]=\"q.inner\"\n [attr.class]=\"q.colour ? 'sticker' : 'sticker unknown'\"\n [attr.fill]=\"q.colour\"\n />\n }\n </svg>\n `,\n styles: `\n :host {\n display: inline-block;\n line-height: 0;\n }\n svg {\n overflow: visible;\n }\n .hint {\n fill: none;\n stroke: var(--cube-hint, #87938c);\n stroke-width: 1;\n stroke-dasharray: 3 3;\n opacity: var(--cube-hint-opacity, 0.5);\n }\n .side {\n stroke: var(--cube-edge, #cdd8d0);\n stroke-width: var(--cube-edge-width, 0.6);\n }\n .top {\n fill: var(--cube-top, #f9fbf8);\n }\n .left {\n fill: var(--cube-left, #e9eee9);\n }\n .right {\n fill: var(--cube-right, #dfe6e0);\n }\n .sticker {\n stroke: var(--cube-sticker-edge, rgba(31, 45, 39, 0.28));\n stroke-width: 1;\n }\n .unknown {\n fill: var(--cube-unknown, #e3e7e1);\n stroke: var(--cube-unknown-edge, none);\n }\n `,\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class CubePicture {\n /** how many pieces: the cube is the smallest n × n × n that holds them. */\n readonly count = input(1);\n /** the stickers' colours in order; null is a sticker not known yet. */\n readonly colours = input<(string | null)[]>([]);\n /** the width in pixels. */\n readonly width = input(64);\n /** show the bigger cube it can grow into, faintly, while it is small. */\n readonly hint = input(false);\n /** one colour on every sticker (a value). */\n readonly whole = input(false);\n /** how many times it was turned: shifts the colours round the stickers. */\n readonly rot = input(0);\n\n protected readonly drawing = computed(() =>\n drawCube(this.count(), this.colours(), this.width(), {\n hint: this.hint(),\n whole: this.whole(),\n rot: this.rot(),\n }),\n );\n}\n","import { DestroyRef, Directive, ElementRef, inject, input, output } from '@angular/core';\n\n/** what a hold reports: how it came, on which element, and the event that ended it. */\nexport interface CubeHeld {\n /** `press`: a finger, pen or the main mouse button stayed put; `menu`: a contextmenu event. */\n via: 'press' | 'menu';\n /** the element holding the directive. */\n element: HTMLElement;\n /** the pointerdown that was held, or the contextmenu. */\n event: Event;\n}\n\n/** how long a press is held before it is a hold (cubes' value; each app may set its own). */\nexport const CUBE_HOLD_MS = 520;\n/** how far a finger may move while pressing before it is a drag, in pixels. */\nexport const CUBE_HOLD_SLOP = 10;\n\n/**\n * pressing and holding a piece (principle 31): a long press, a right click or the menu key raise\n * one `cubeHeld`. a second finger (a pinch) or a drag never does, and the click that follows a hold\n * is swallowed so the piece does not also open. what a hold opens is the app's.\n *\n * it only reports: it never stops or prevents the pointer events, so a swipe or a pinch on the same\n * element keeps working.\n */\n@Directive({\n selector: '[cubeHold]',\n host: {\n '[style.user-select]': 'cubeHoldDisabled() ? null : \"none\"',\n '[style.-webkit-user-select]': 'cubeHoldDisabled() ? null : \"none\"',\n '[style.-webkit-touch-callout]': 'cubeHoldDisabled() ? null : \"none\"',\n '(pointerdown)': 'press($event)',\n '(pointermove)': 'moved($event)',\n '(pointerup)': 'lift($event)',\n '(pointercancel)': 'lift($event)',\n '(pointerleave)': 'lift($event)',\n '(contextmenu)': 'menu($event)',\n '(keydown)': 'pressFired = false; swallow = false',\n },\n})\nexport class CubeHold {\n /** no hold at all: the listeners do nothing and the browser's own menu stays. */\n readonly cubeHoldDisabled = input(false);\n /** how long a press is held before it is a hold, in milliseconds. */\n readonly cubeHoldMs = input(CUBE_HOLD_MS);\n /** how far the press may move before it is a drag instead, in pixels. */\n readonly cubeHoldSlop = input(CUBE_HOLD_SLOP);\n /** a short buzz (`navigator.vibrate(12)`) when it holds, where the device can. */\n readonly cubeHoldBuzz = input(true);\n\n /** the piece was held. */\n readonly cubeHeld = output<CubeHeld>();\n\n private readonly element = inject<ElementRef<HTMLElement>>(ElementRef).nativeElement;\n private timer: ReturnType<typeof setTimeout> | undefined;\n /** where the press started; null while nothing may become a hold. */\n private start: { x: number; y: number } | null = null;\n /** the pointers down on the element: two or more are a pinch. */\n private readonly pointers = new Set<number>();\n /** this press already held, so the phone's own contextmenu after it is not a second hold. */\n protected pressFired = false;\n /** a hold swallows the one click that follows it. */\n protected swallow = false;\n\n constructor() {\n // caught first, before the element's own (click), so a hold never also opens the piece.\n const swallow = (e: Event) => {\n if (!this.swallow) return;\n this.swallow = false;\n e.preventDefault();\n e.stopImmediatePropagation();\n };\n this.element.addEventListener('click', swallow, true);\n inject(DestroyRef).onDestroy(() => {\n clearTimeout(this.timer);\n this.element.removeEventListener('click', swallow, true);\n });\n }\n\n protected press(e: PointerEvent): void {\n this.pointers.add(e.pointerId);\n this.cancel();\n this.pressFired = false;\n this.swallow = false;\n // a second finger is a pinch, and only the main button holds.\n if (this.cubeHoldDisabled() || this.pointers.size > 1 || e.button > 0) return;\n this.start = { x: e.clientX, y: e.clientY };\n this.timer = setTimeout(() => this.fire('press', e), this.cubeHoldMs());\n }\n\n protected moved(e: PointerEvent): void {\n if (!this.start) return;\n if (Math.hypot(e.clientX - this.start.x, e.clientY - this.start.y) > this.cubeHoldSlop()) {\n this.cancel();\n }\n }\n\n protected lift(e: PointerEvent): void {\n this.pointers.delete(e.pointerId);\n this.cancel();\n }\n\n /** a right click, a phone's own long press, the menu key or shift+f10. */\n protected menu(e: Event): void {\n if (this.cubeHoldDisabled()) return;\n e.preventDefault();\n if (this.pressFired) return;\n this.fire('menu', e);\n }\n\n private fire(via: CubeHeld['via'], event: Event): void {\n this.cancel();\n if (this.cubeHoldDisabled()) return;\n this.pressFired = via === 'press';\n this.swallow = true;\n if (this.cubeHoldBuzz()) globalThis.navigator?.vibrate?.(12);\n this.cubeHeld.emit({ via, element: this.element, event });\n }\n\n private cancel(): void {\n clearTimeout(this.timer);\n this.timer = undefined;\n this.start = null;\n }\n}\n","import { ChangeDetectionStrategy, Component, computed, input } from '@angular/core';\n\n/** the views a cube can be shown in, each drawn as its own shape. */\nexport type CubeIconView = 'square' | 'one' | 'two' | 'three' | 'four' | 'grid-4x5' | 'grid-3x6';\n\n/** what a tile of a cube the app keeps is about (a context cube's parts and their choices). */\nexport type CubeIconName =\n | 'names'\n | 'name'\n | 'change'\n | 'move'\n | 'place'\n | 'whose'\n | 'library'\n | 'mine'\n | 'shown'\n | 'hidden'\n | 'view'\n | 'sort'\n | 'kept'\n | 'face'\n | 'added'\n | 'up'\n | 'down'\n | 'plus'\n | CubeIconView;\n\n/** every icon, in the order above. */\nexport const CUBE_ICON_NAMES: readonly CubeIconName[] = [\n 'names',\n 'name',\n 'change',\n 'move',\n 'place',\n 'whose',\n 'library',\n 'mine',\n 'shown',\n 'hidden',\n 'view',\n 'sort',\n 'kept',\n 'face',\n 'added',\n 'up',\n 'down',\n 'plus',\n 'square',\n 'one',\n 'two',\n 'three',\n 'four',\n 'grid-4x5',\n 'grid-3x6',\n];\n\n/** a view's icon is its own shape: the cells of one, two… across, a fixed grid, the square. */\nconst SHAPES: Record<CubeIconView, { cols: number; rows: number }> = {\n square: { cols: 3, rows: 3 },\n one: { cols: 1, rows: 3 },\n two: { cols: 2, rows: 3 },\n three: { cols: 3, rows: 3 },\n four: { cols: 4, rows: 3 },\n 'grid-4x5': { cols: 4, rows: 5 },\n 'grid-3x6': { cols: 3, rows: 6 },\n};\n\nexport interface CubeIconCell {\n x: number;\n y: number;\n w: number;\n h: number;\n}\n\n/**\n * the cells a view's icon draws in its 24 × 24 box, or null when the icon is not a view. one across\n * is a list, so its cells are rows.\n */\nexport function cubeIconCells(icon: CubeIconName): CubeIconCell[] | null {\n const shape = SHAPES[icon as CubeIconView];\n if (!shape) return null;\n const { cols, rows } = shape;\n const gap = 1.6;\n const size = Math.min((17 - gap * (cols - 1)) / cols, (17 - gap * (rows - 1)) / rows);\n const w = cols * size + gap * (cols - 1);\n const h = rows * size + gap * (rows - 1);\n const out: CubeIconCell[] = [];\n for (let r = 0; r < rows; r++)\n for (let c = 0; c < cols; c++)\n out.push({\n x: cols === 1 ? 3.5 : 12 - w / 2 + c * (size + gap),\n y: 12 - h / 2 + r * (size + gap),\n w: cols === 1 ? 17 : size,\n h: size,\n });\n return out;\n}\n\n/**\n * an icon on a tile of a cube the app keeps (a context cube and its parts), in place of a small\n * cube: such cubes hold no pieces, so their tiles show what they are about.\n *\n * its look comes from css variables (`--cube-icon-*`), each with a light fallback; `tokens/light.css`\n * and `tokens/dark.css` set them all. it says nothing: the tile's words come from the app.\n */\n@Component({\n selector: 'cube-icon',\n template: `\n <svg viewBox=\"0 0 24 24\" aria-hidden=\"true\">\n @if (cells(); as cs) {\n @for (c of cs; track $index) {\n <rect\n class=\"cell\"\n [attr.x]=\"c.x\"\n [attr.y]=\"c.y\"\n [attr.width]=\"c.w\"\n [attr.height]=\"c.h\"\n rx=\"0.8\"\n />\n }\n }\n @switch (icon()) {\n @case ('view') {\n <rect x=\"4\" y=\"4\" width=\"7\" height=\"7\" rx=\"1.5\" />\n <rect x=\"13\" y=\"4\" width=\"7\" height=\"7\" rx=\"1.5\" />\n <rect x=\"4\" y=\"13\" width=\"7\" height=\"7\" rx=\"1.5\" />\n <rect x=\"13\" y=\"13\" width=\"7\" height=\"7\" rx=\"1.5\" />\n }\n @case ('sort') {\n <path d=\"M8 19V5M4.5 8.5 8 5l3.5 3.5M16 5v14M12.5 15.5 16 19l3.5-3.5\" />\n }\n @case ('kept') {\n <path d=\"M5 7h14M5 12h14M5 17h9\" />\n }\n @case ('face') {\n <path d=\"M12 3.5 20 8v8l-8 4.5L4 16V8Z\" />\n <path d=\"M4 8l8 4.5L20 8M12 12.5v8\" />\n }\n @case ('added') {\n <circle cx=\"12\" cy=\"12\" r=\"8\" />\n <path d=\"M12 7.5V12l3 2\" />\n }\n @case ('up') {\n <path d=\"M12 19V5M6.5 10.5 12 5l5.5 5.5\" />\n }\n @case ('plus') {\n <path d=\"M12 5v14M5 12h14\" />\n }\n @case ('down') {\n <path d=\"M12 5v14M6.5 13.5 12 19l5.5-5.5\" />\n }\n @case ('names') {\n <path d=\"M3.5 12.5 11 5h8v8l-7.5 7.5a1.5 1.5 0 0 1-2.1 0L3.5 14.6a1.5 1.5 0 0 1 0-2.1Z\" />\n <circle cx=\"15.2\" cy=\"8.8\" r=\"1.4\" />\n }\n @case ('name') {\n <path d=\"M5 18 9.5 6h1L15 18M6.6 14h6.8\" />\n <path\n d=\"M17 11.5c1.6-1.2 3.5-.5 3.5 1.4V18M20.5 14.6c-2.6-.3-4 .4-4 1.8 0 1.9 2.7 2 4 .3\"\n />\n }\n @case ('change') {\n <path d=\"M4 20h4L19 9a2.8 2.8 0 0 0-4-4L4 16v4Z\" />\n <path d=\"M13.5 6.5l4 4\" />\n }\n @case ('move') {\n <path\n d=\"M4 8V6a2 2 0 0 1 2-2h4l2 2h6a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2v-1\"\n />\n <path d=\"M2.5 13H12M9 10l3 3-3 3\" />\n }\n @case ('place') {\n <path\n d=\"M4 8V6a2 2 0 0 1 2-2h4l2 2h6a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V8Z\"\n />\n }\n @case ('whose') {\n <circle cx=\"9\" cy=\"8\" r=\"3.2\" />\n <path d=\"M3 19c.6-3.4 3-5.2 6-5.2s5.4 1.8 6 5.2\" />\n <path d=\"M16 5.5a3 3 0 0 1 0 5.6M18.5 14.4c1.4.8 2.3 2.4 2.5 4.6\" />\n }\n @case ('library') {\n <path d=\"M4 5h4v15H4zM10 5h4v15h-4z\" />\n <path d=\"m16 6 3.6-1 3 14.4-3.6 1z\" />\n }\n @case ('mine') {\n <circle cx=\"12\" cy=\"8\" r=\"3.4\" />\n <path d=\"M5 20c.7-4 3.5-6 7-6s6.3 2 7 6\" />\n }\n @case ('shown') {\n <path d=\"M3 12s3.2-6 9-6 9 6 9 6-3.2 6-9 6-9-6-9-6Z\" />\n <circle cx=\"12\" cy=\"12\" r=\"2.6\" />\n }\n @case ('hidden') {\n <path d=\"M3 12s3.2-6 9-6c1.6 0 3 .45 4.2 1.1M21 12s-3.2 6-9 6c-1.6 0-3-.45-4.2-1.1\" />\n <path d=\"M4.5 19.5 19.5 4.5\" />\n }\n }\n </svg>\n `,\n styles: `\n :host {\n display: inline-block;\n width: var(--cube-icon-size, 34px);\n height: var(--cube-icon-size, 34px);\n line-height: 0;\n }\n svg {\n width: 100%;\n height: 100%;\n fill: none;\n stroke: var(--cube-icon-stroke, #1f2a26);\n stroke-width: var(--cube-icon-stroke-width, 1.7);\n stroke-linecap: round;\n stroke-linejoin: round;\n }\n .cell {\n fill: var(--cube-icon-stroke, #1f2a26);\n stroke: none;\n opacity: var(--cube-icon-cell-opacity, 0.8);\n }\n :host(.in-use) svg {\n stroke: var(--cube-icon-in-use, #3b5a4c);\n }\n :host(.in-use) .cell {\n fill: var(--cube-icon-in-use, #3b5a4c);\n }\n `,\n host: { '[class.in-use]': 'inUse()' },\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class CubeIcon {\n /** what the tile is about. */\n readonly icon = input.required<CubeIconName>();\n /** the one in use among its siblings: drawn in the in-use colour. */\n readonly inUse = input(false);\n\n protected readonly cells = computed(() => cubeIconCells(this.icon()));\n}\n","import { InjectionToken } from '@angular/core';\nimport { Direction, ViewKey } from './arrange';\n\n/*\n * the context cube: behind every piece sits a second cube, the app's, where it keeps how the piece\n * is named, shown and kept. pressing and holding a piece walks into it (principle 31; cubes calls it\n * the own cube, decisions 39 and 40). this is its shape only: each app fills it from its own data\n * through a `ContextCubeSource`, and gives every word through `ContextWords`.\n */\n\n/**\n * the parts a context cube can have. the seven are the ones cubes found; an app may add its own,\n * any string, and they come after the known ones.\n */\nexport type ContextPartKey =\n 'names' | 'change' | 'view' | 'sort' | 'move' | 'whose' | 'hide' | (string & {});\n\n/** cubes' rows: how it is called (names, change), how it is shown (view, sort), what i do with it. */\nexport const CONTEXT_PART_ORDER: readonly ContextPartKey[] = [\n 'names',\n 'change',\n 'view',\n 'sort',\n 'move',\n 'whose',\n 'hide',\n];\n\n/** the parts in their rows; parts an app added come last, in the order it gave them. twice is once. */\nexport function orderParts(parts: readonly ContextPartKey[]): ContextPartKey[] {\n const unique = [...new Set(parts)];\n const known = CONTEXT_PART_ORDER.filter((p) => unique.includes(p));\n return [...known, ...unique.filter((p) => !CONTEXT_PART_ORDER.includes(p))];\n}\n\n/** one tile of a level. its title and line always come from the app. */\nexport interface ContextTile<D = unknown> {\n /** unique among its level. */\n key: string;\n title: string;\n line?: string | null;\n /** the icon's name: a part, a view key, a direction, or one of the app's. */\n icon: string;\n /** the one in use among its siblings (the name in use, shown or hidden, the view). */\n inUse?: boolean;\n /** drawn quietly: something that can be read but not used. */\n pale?: boolean;\n /** the plus: keeps something new beside the others, always last. */\n adds?: boolean;\n /** what the tile stands for, for the app's own `pick`. */\n data?: D;\n}\n\n/** where in the context cube one is: [] is its top (its parts), ['names'] a part, ['sort', by] deeper. */\nexport type ContextPath = readonly string[];\n\n/** what a pick does: walk into a deeper level, end the journey, step one level out, or nothing. */\nexport type ContextPick =\n { kind: 'enter'; path: string[] } | { kind: 'done' } | { kind: 'out' } | { kind: 'stay' };\n\n/** what an app gives for its own held type `T`: a piece, a cube, a to-do, a level. */\nexport interface ContextCubeSource<T = unknown> {\n /** the parts this held thing has, in any order (`orderParts` puts them in rows). */\n parts(held: T): ContextPartKey[];\n /** the tiles of one level, or null when that path does not exist for it. */\n level(held: T, path: ContextPath): ContextTile[] | null;\n /** a tile was tapped at that path. */\n pick(held: T, path: ContextPath, tile: ContextTile): ContextPick | Promise<ContextPick>;\n}\n\n/** a title and its line, in the app's language. */\nexport interface ContextWord {\n title: string;\n line?: string | null;\n}\n\n/** a name a piece has had, as the names level lists it. */\nexport interface ContextName {\n name: string;\n /** the one in use. */\n current: boolean;\n /** the day it was given, as the app keeps it. */\n on?: string | null;\n /** whose hands gave it. */\n by?: string | null;\n /** whether it was ever in use, or only kept beside. */\n used?: boolean;\n}\n\n/** every word the context cube shows. the package ships none. */\nexport interface ContextWords {\n /** each part's title and line; a part with no word has an empty title. */\n parts: Partial<Record<ContextPartKey, ContextWord>>;\n /** each view's name. */\n views: Partial<Record<ViewKey, ContextWord>>;\n /** the two directions of a sort, when a sort option has none of its own. */\n directions: Record<Direction, ContextWord>;\n /** the two pieces of hide. */\n hide: { shown: ContextWord; hidden: ContextWord };\n /** the plus among the names, and the line under each name (its day and hands). */\n names: { another: ContextWord; line?: (name: ContextName) => string | null };\n /** said on the one in use, when the app wants it said. */\n inUse?: string;\n}\n\n/** the app's source of context cubes. */\nexport const CONTEXT_CUBE_SOURCE = new InjectionToken<ContextCubeSource<any>>(\n 'CONTEXT_CUBE_SOURCE',\n);\n\n/** the app's words for the context cube. */\nexport const CONTEXT_CUBE_WORDS = new InjectionToken<ContextWords>('CONTEXT_CUBE_WORDS');\n\n/** what the top level shows of a part now: the view in use, the name, shown or hidden. */\nexport interface PartNow {\n line?: string | null;\n icon?: string;\n}\n\n/**\n * the icon a part's tile shows when the app gives none of what it holds now. most parts are drawn\n * by their own name; hide has no icon of its own and shows shown (the eye), since a piece is in\n * sight until it is hidden. an app passes `now.hide.icon` (`shown` or `hidden`) to say which.\n */\nexport const PART_ICONS: Partial<Record<ContextPartKey, string>> = { hide: 'shown' };\n\n/** the top of a context cube: its parts in rows, each with its word and, when given, what it holds now. */\nexport function partsLevel(\n parts: readonly ContextPartKey[],\n words: ContextWords,\n now: Partial<Record<ContextPartKey, PartNow>> = {},\n): ContextTile<ContextPartKey>[] {\n return orderParts(parts).map((p) => ({\n key: p,\n title: words.parts[p]?.title ?? '',\n line: now[p]?.line !== undefined ? now[p]?.line : (words.parts[p]?.line ?? null),\n icon: now[p]?.icon ?? PART_ICONS[p] ?? p,\n data: p,\n }));\n}\n","/*\n * how a cube's pieces are laid out and in what order they come, moved from cubes\n * (`core/world/arrange.ts`, design decision 40). both change the view only, never the cube. the\n * words for each view and each direction come from the app (`ContextWords`).\n */\n\n/** the ways a cube's square can be laid out: the square first (cubes decision 23), then the rest. */\nexport type ViewKey = 'square' | 'one' | 'two' | 'three' | 'four' | 'grid-4x5' | 'grid-3x6';\n\n/** every view, in the order they are offered. */\nexport const VIEW_KEYS: readonly ViewKey[] = [\n 'square',\n 'one',\n 'two',\n 'three',\n 'four',\n 'grid-4x5',\n 'grid-3x6',\n];\n\nexport const isView = (v: unknown): v is ViewKey => VIEW_KEYS.includes(v as ViewKey);\n\n/** columns and rows of a layout holding this many; every row is full, open places outlined. */\nexport interface Grid {\n cols: number;\n rows: number;\n}\n\nexport function gridFor(view: ViewKey, count: number): Grid {\n const n = Math.max(1, count);\n switch (view) {\n case 'square': {\n const side = Math.max(1, Math.ceil(Math.sqrt(n)));\n return { cols: side, rows: side };\n }\n case 'one':\n case 'two':\n case 'three':\n case 'four': {\n const cols = { one: 1, two: 2, three: 3, four: 4 }[view];\n return { cols, rows: Math.ceil(n / cols) };\n }\n case 'grid-4x5':\n case 'grid-3x6': {\n const [cols, rows] = view === 'grid-4x5' ? [4, 5] : [3, 6];\n return { cols, rows: rows * Math.ceil(n / (cols * rows)) };\n }\n }\n}\n\n/** up is the face's own order (a to z, oldest first, its first colour first); down the other way. */\nexport type Direction = 'up' | 'down';\n\n/** what an item is sorted by: text, a number, or nothing found (not known yet). */\nexport type SortValue = string | number | null | undefined;\n\n/**\n * items in the order a sort asks for. `by` reads what each item is sorted by; text is compared as\n * a person reads it, numbers as numbers. an item with nothing found is not known yet and comes last\n * in both directions (empty is the point, never hidden). ties keep the items' own order.\n */\nexport function sortItems<T>(items: readonly T[], by: (item: T) => SortValue, dir: Direction): T[] {\n const sign = dir === 'down' ? -1 : 1;\n const known = (v: SortValue): v is string | number => v !== null && v !== undefined && v !== '';\n return items\n .map((item, at) => ({ item, at, value: by(item) }))\n .sort((a, b) => {\n const ka = known(a.value);\n const kb = known(b.value);\n if (!ka || !kb) return Number(!ka) - Number(!kb) || a.at - b.at;\n return sign * compare(a.value as string | number, b.value as string | number) || a.at - b.at;\n })\n .map((x) => x.item);\n}\n\nfunction compare(a: string | number, b: string | number): number {\n if (typeof a === 'number' && typeof b === 'number') return a - b;\n return String(a).localeCompare(String(b));\n}\n","import { Direction, VIEW_KEYS, ViewKey } from './arrange';\nimport { ContextName, ContextTile, ContextWord, ContextWords } from './context-cube';\n\n/*\n * the levels every app's context cube shares, as pure functions: names, hide, view and sort. each\n * returns the tiles of one level; what a tap does stays with the app (its `pick`), read from the\n * tile's `data`.\n */\n\n/** what a names tile holds: a name, or the plus. */\nexport type NamesData = { name: ContextName } | { another: true };\n\n/**\n * every name it has had: the one in use first, then the rest newest first (the names come oldest\n * first, as they were given). when the app allows it, a plus keeps a new one beside it without\n * using it.\n */\nexport function namesLevel(\n names: readonly ContextName[],\n words: ContextWords,\n opts: { canAdd?: boolean } = {},\n): ContextTile<NamesData>[] {\n const listed = [...names.filter((n) => n.current), ...names.filter((n) => !n.current).reverse()];\n const tiles: ContextTile<NamesData>[] = listed.map((n, i) => ({\n key: `name:${i}:${n.name}`,\n title: n.name,\n line: words.names.line?.(n) ?? null,\n icon: 'name',\n inUse: n.current,\n data: { name: n },\n }));\n if (opts.canAdd)\n tiles.push({\n key: 'name:+',\n title: words.names.another.title,\n line: words.names.another.line ?? null,\n icon: 'plus',\n adds: true,\n data: { another: true },\n });\n return tiles;\n}\n\n/** hide: a cube of two pieces, shown and hidden, one in use; `data` is whether it hides. */\nexport function hideLevel(hidden: boolean, words: ContextWords): ContextTile<boolean>[] {\n return [\n {\n key: 'hide:shown',\n title: words.hide.shown.title,\n line: words.hide.shown.line ?? null,\n icon: 'shown',\n inUse: !hidden,\n data: false,\n },\n {\n key: 'hide:hidden',\n title: words.hide.hidden.title,\n line: words.hide.hidden.line ?? null,\n icon: 'hidden',\n inUse: hidden,\n data: true,\n },\n ];\n}\n\n/**\n * view: every way to lay the cube out, its icon its own shape. the one in use says so in place of\n * its line, so both fit a small tile.\n */\nexport function viewLevel(\n now: ViewKey,\n words: ContextWords,\n views: readonly ViewKey[] = VIEW_KEYS,\n): ContextTile<ViewKey>[] {\n return views.map((v) => ({\n key: 'view:' + v,\n title: words.views[v]?.title ?? '',\n line: v === now ? null : (words.views[v]?.line ?? null),\n icon: v,\n inUse: v === now,\n data: v,\n }));\n}\n\n/** what a cube can be sorted by, given by the app: as kept, names, when added, each face. */\nexport interface SortOption {\n /** the app's own key: `kept`, `names`, `added`, a face's id. */\n by: string;\n title: string;\n line?: string | null;\n icon: string;\n /** false for an order with no two ways (as kept): picking it uses it at once. */\n directed?: boolean;\n /** this option's two directions in its own words (a to z, oldest first, small first). */\n up?: ContextWord;\n down?: ContextWord;\n}\n\n/** a sort in use. */\nexport interface SortNow {\n by: string;\n dir: Direction;\n}\n\n/** the two directions of an option, in its own words or else the app's general ones. */\nexport function directionWords(\n option: SortOption,\n words: ContextWords,\n): Record<Direction, ContextWord> {\n return {\n up: option.up ?? words.directions.up,\n down: option.down ?? words.directions.down,\n };\n}\n\n/**\n * sort: the options, the one in use marked; a directed option in use says its direction in place\n * of its line. picking a directed option walks into its two directions (`sortDirectionsLevel`).\n */\nexport function sortLevel(\n options: readonly SortOption[],\n now: SortNow,\n words: ContextWords,\n): ContextTile<SortOption>[] {\n return options.map((o) => {\n const inUse = now.by === o.by;\n const directed = o.directed !== false;\n return {\n key: 'sort:' + o.by,\n title: o.title,\n line: inUse && directed ? directionWords(o, words)[now.dir].title : (o.line ?? null),\n icon: o.icon,\n inUse,\n data: o,\n };\n });\n}\n\n/**\n * inside one sort option: its two directions, up first. whatever direction, an item with nothing\n * found is not known yet and comes last (`sortItems`); the words say so in their lines.\n */\nexport function sortDirectionsLevel(\n option: SortOption,\n now: SortNow,\n words: ContextWords,\n): ContextTile<Direction>[] {\n const w = directionWords(option, words);\n return (['up', 'down'] as const).map((dir) => ({\n key: 'dir:' + dir,\n title: w[dir].title,\n line: w[dir].line ?? null,\n icon: dir,\n inUse: now.by === option.by && now.dir === dir,\n data: dir,\n }));\n}\n","/**\n * turning rows (selim: row rotation), first tried in mosaic's todarch cube: a square of more\n * pieces than its front holds keeps its front full and turns its rows like the layers of a puzzle\n * cube. each row is a band of four sides; the pieces past the front fill the first row's other\n * sides, then the second row's, and so on, so the open places gather at the very end and a row\n * with nothing behind its front does not turn.\n *\n * this is only the layout, pure and without angular: which piece sits on which side of which row.\n * the front is cols × rows (3 × 3 as mosaic draws it, 4 × 5 and 3 × 6 for cubes' fixed grids).\n * when four sides a row are still not enough, rows are added below, as mosaic does.\n */\nexport interface TurningRows<T> {\n /** rows × 4 sides × cols places; null is an open place. side 0 is the front. */\n rows: (T | null)[][][];\n /** how many sides of each row hold something (1: only its front, it does not turn). */\n sides: number[];\n}\n\n/** the sides of one row: its front and the three behind it. */\nexport const TURNING_SIDES = 4;\n\nexport function turningRows<T>(\n pieces: readonly T[],\n own: T | null,\n cols = 3,\n rows = cols,\n): TurningRows<T> {\n const across = Math.max(1, Math.floor(cols));\n const down = Math.max(1, Math.floor(rows));\n const count = pieces.length + (own !== null ? 1 : 0);\n const perRow = across * TURNING_SIDES;\n const rowCount = Math.max(down, Math.ceil(count / perRow));\n const grid: (T | null)[][][] = Array.from({ length: rowCount }, () =>\n Array.from({ length: TURNING_SIDES }, () =>\n Array.from<T | null>({ length: across }).fill(null),\n ),\n );\n const front: [number, number][] = [];\n for (let r = 0; r < rowCount; r++) for (let c = 0; c < across; c++) front.push([r, c]);\n // the own box keeps the front's last place, so it is always seen\n const frontForPieces = own !== null ? front.slice(0, -1) : front;\n if (own !== null) grid[rowCount - 1][0][across - 1] = own;\n let next = 0;\n for (const [r, c] of frontForPieces) {\n if (next >= pieces.length) break;\n grid[r][0][c] = pieces[next++];\n }\n for (let r = 0; r < rowCount && next < pieces.length; r++)\n for (let s = 1; s < TURNING_SIDES && next < pieces.length; s++)\n for (let c = 0; c < across && next < pieces.length; c++) grid[r][s][c] = pieces[next++];\n const sides = grid.map(\n (row) => 1 + row.slice(1).filter((side) => side.some((t) => t !== null)).length,\n );\n return { rows: grid, sides };\n}\n","import {\n ChangeDetectionStrategy,\n Component,\n DestroyRef,\n Directive,\n ElementRef,\n TemplateRef,\n afterNextRender,\n computed,\n contentChild,\n effect,\n inject,\n input,\n signal,\n untracked,\n viewChild,\n} from '@angular/core';\nimport { NgTemplateOutlet } from '@angular/common';\nimport { ViewKey, gridFor } from '../context-cube/arrange';\nimport { TURNING_SIDES, turningRows } from './turning-rows';\n\n/*\n * the square: the complete grid of tiles every face of a cube is drawn with (cube design decision\n * 23, cubes decision 40). mosaic (`app-square-tiles`), cubes (`app-tiles`) and the context cube each\n * wrote it; this is the one they share. it only places the tiles an app gives: each app keeps\n * drawing its own tile through a template. turning rows ride on it (`turning`, off by default).\n */\n\n/** how close a square's places are: from one big tile (0) to only its icon or small cube (4). */\nexport type SquareLevel = 0 | 1 | 2 | 3 | 4;\n\n/** cubes' steps (`levelFor`), by a cell's side in px: a tile says less as the square fills. */\nexport function squareLevelFor(cell: number): SquareLevel {\n return cell >= 280 ? 0 : cell >= 150 ? 1 : cell >= 100 ? 2 : cell >= 70 ? 3 : 4;\n}\n\n/** places still open keep their outline; the fuller the square, the closer its places. */\nexport function squareGap(n: number): number {\n return n <= 2 ? 12 : n === 3 ? 10 : n === 4 ? 8 : 5;\n}\n\n/** the room a square may take: the width it is given, and the window's height for the square. */\nexport interface SquareRoom {\n width: number;\n /** the window's height less a head (48 px); only the square view is held to it, so it is seen whole. */\n tall: number;\n}\n\n/** one square laid out: its columns and rows, its size, and how much each tile says. */\nexport interface SquareLayout {\n cols: number;\n rows: number;\n /** the square's width and height, in px. */\n width: number;\n height: number;\n gap: number;\n /** a cell's width, in px. */\n cell: number;\n /** a row's height: the cell, or a list row's own height in one across. */\n rowHeight: number;\n level: SquareLevel;\n /** one across is a list: each row as tall as a tile with its name and line, not a square. */\n list: boolean;\n /** places not filled, outlined; they only ever finish the last row. */\n open: number;\n}\n\n/** the largest side a square takes on a wide screen, in px (cubes', mosaic's). */\nexport const SQUARE_MAX_SIDE = 880;\n/** a row's height in one across, the list (cubes'). */\nexport const SQUARE_LIST_ROW = 76;\n\n/**\n * how this many tiles are laid out in a view, in this much room. the square view is the smallest\n * n × n that holds them, as wide as the room and the window's height allow; the other views are as\n * long as they need and scroll. open places only finish the last row, so a view never draws a whole\n * empty row (decision of 2026-11-01): three pieces in 4 × 5 are one row of four. the square keeps\n * its own rule, its size coming from the pieces.\n */\nexport function squareLayout(\n view: ViewKey,\n count: number,\n room: SquareRoom,\n opts: { maxSide?: number; listRow?: number } = {},\n): SquareLayout {\n const n = Math.max(0, count);\n const grid = gridFor(view, n);\n const cols = grid.cols;\n const rows = view === 'square' ? grid.rows : Math.max(1, Math.ceil(n / cols));\n const width = Math.max(\n 0,\n Math.min(\n view === 'square' ? Math.min(room.width, room.tall) : room.width,\n opts.maxSide ?? SQUARE_MAX_SIDE,\n ),\n );\n const list = view === 'one';\n const gap = list ? 8 : squareGap(Math.max(cols, Math.min(rows, 5)));\n const cell = Math.max(0, (width - gap * (cols - 1)) / cols);\n const rowHeight = list ? (opts.listRow ?? SQUARE_LIST_ROW) : cell;\n return {\n cols,\n rows,\n width,\n height: rows * rowHeight + gap * (rows - 1),\n gap,\n cell,\n rowHeight,\n level: list ? 1 : squareLevelFor(cell),\n list,\n open: cols * rows - n,\n };\n}\n\n/** what a tile's template is given. */\nexport interface CubeSquareTileContext<T> {\n /** the tile, as the app gave it. */\n $implicit: T;\n index: number;\n /** how much it says (0 everything … 4 only its icon or small cube). */\n level: SquareLevel;\n /** its cell's width and height, in px, for a picture sized to it. */\n cell: number;\n rowHeight: number;\n /** one across: a list row, not a square cell. */\n list: boolean;\n}\n\n/**\n * `<ng-template cubeSquareTile let-tile let-level=\"level\">`: how the app draws one tile inside a\n * `<cube-square>`. the square only places it; the template fills its cell.\n */\n@Directive({ selector: 'ng-template[cubeSquareTile]' })\nexport class CubeSquareTile<T> {\n readonly template = inject<TemplateRef<CubeSquareTileContext<T>>>(TemplateRef);\n /** the tiles' type, for the template's checks: `[cubeSquareTile]=\"tiles()\"`. */\n readonly cubeSquareTile = input<readonly T[] | '' | undefined>();\n\n static ngTemplateContextGuard<T>(\n _dir: CubeSquareTile<T>,\n ctx: unknown,\n ): ctx is CubeSquareTileContext<T> {\n return true;\n }\n}\n\n/** the front a view keeps when its rows turn: the square's `across` × `across`, a fixed grid's page. */\nexport function turningFront(view: ViewKey, across = 3): { cols: number; rows: number } | null {\n if (view === 'square') return { cols: across, rows: across };\n if (view === 'grid-4x5') return { cols: 4, rows: 5 };\n if (view === 'grid-3x6') return { cols: 3, rows: 6 };\n return null;\n}\n\n/** narrower than this (a phone), a full square turns its rows, when `turning` is on. */\nexport const TURNING_BELOW = 640;\n/** turns after which a row with more stops nudging when the square opens. */\nexport const TURNING_NUDGE_UNTIL = 3;\n\n/** turns counted on this page when the app gives no key to keep them on the phone. */\nlet turnedHere = 0;\nconst readTurned = (key: string | null): number => {\n if (!key) return turnedHere;\n try {\n return Number(localStorage.getItem(key)) || 0;\n } catch {\n return turnedHere;\n }\n};\nconst noteTurned = (key: string | null): void => {\n turnedHere++;\n if (!key) return;\n try {\n localStorage.setItem(key, String(readTurned(key) + 1));\n } catch {\n // a phone that keeps nothing keeps nudging, which is fine\n }\n};\n\nconst reducedMotion = () =>\n typeof matchMedia === 'function' && matchMedia('(prefers-reduced-motion: reduce)').matches;\n\n/**\n * `<cube-square [tiles] [view]>`: the tiles an app gives, laid out as a complete square or another\n * view, each drawn by the app's `cubeSquareTile` template and told its level. it measures its own\n * width (up to the window's height for the square, at most `maxSide`), outlines its open places and\n * zooms a step when it has to hold more. it says no word and draws no tile. its look is css\n * variables (`--cube-square-*`), set in both token files.\n */\n@Component({\n selector: 'cube-square',\n imports: [NgTemplateOutlet],\n template: `\n @let sq = layout();\n @if (rings(); as r) {\n <div\n class=\"cs-turning\"\n [class]=\"'cs-turning cs-l' + sq.level\"\n [class.cs-dashed]=\"dashed()\"\n [attr.data-level]=\"sq.level\"\n [style.width.px]=\"sq.width\"\n [style.--cs-gap.px]=\"sq.gap\"\n >\n @for (row of r.rows; track ri; let ri = $index) {\n <div\n class=\"cs-row\"\n [class.cs-turns]=\"r.sides[ri] > 1\"\n [attr.data-row]=\"ri\"\n [style.height.px]=\"sq.rowHeight\"\n (pointerdown)=\"down(ri, $event)\"\n (pointermove)=\"move(ri, $event)\"\n (pointerup)=\"up(ri, $event)\"\n (pointercancel)=\"up(ri, $event)\"\n (keydown)=\"key(ri, $event)\"\n >\n @if (r.sides[ri] > 1) {\n <span class=\"cs-edge\" aria-hidden=\"true\"></span>\n }\n <div\n class=\"cs-band\"\n [class.cs-still]=\"dragging() === ri || still()\"\n [class.cs-nudging]=\"nudging()\"\n [style.transform]=\"\n 'translateZ(' + -sq.width / 2 + 'px) rotateY(' + angle(ri) + 'deg)'\n \"\n >\n @for (side of row; track si; let si = $index) {\n <div\n class=\"cs-side\"\n [attr.data-side]=\"si\"\n [style.grid-template-columns]=\"'repeat(' + sq.cols + ', minmax(0, 1fr))'\"\n [style.transform]=\"\n 'rotateY(' + si * 90 + 'deg) translateZ(' + sq.width / 2 + 'px)'\n \"\n [attr.aria-hidden]=\"sideOf(ri) === si ? null : 'true'\"\n [attr.inert]=\"sideOf(ri) === si ? null : ''\"\n >\n @for (t of side; track ci; let ci = $index) {\n @if (t !== null) {\n <div class=\"cs-cell\">\n @if (tile(); as tpl) {\n <ng-container\n [ngTemplateOutlet]=\"tpl.template\"\n [ngTemplateOutletContext]=\"{\n $implicit: t,\n index: indexOf(t),\n level: sq.level,\n cell: sq.cell,\n rowHeight: sq.rowHeight,\n list: false,\n }\"\n />\n }\n </div>\n } @else if (si < r.sides[ri]) {\n <div class=\"cs-place\" aria-hidden=\"true\"></div>\n }\n }\n </div>\n }\n </div>\n </div>\n }\n </div>\n } @else {\n <div\n #grid\n [class]=\"'cs-square cs-l' + sq.level\"\n [class.cs-list]=\"sq.list\"\n [class.cs-dashed]=\"dashed()\"\n [attr.data-level]=\"sq.level\"\n [style.width.px]=\"sq.width\"\n [style.height.px]=\"sq.height\"\n [style.--cs-gap.px]=\"sq.gap\"\n [style.grid-template-columns]=\"'repeat(' + sq.cols + ', minmax(0, 1fr))'\"\n [style.grid-template-rows]=\"'repeat(' + sq.rows + ', minmax(0, 1fr))'\"\n >\n @for (t of tiles(); track keyOf()(t, $index); let i = $index) {\n <div class=\"cs-cell\">\n @if (tile(); as tpl) {\n <ng-container\n [ngTemplateOutlet]=\"tpl.template\"\n [ngTemplateOutletContext]=\"{\n $implicit: t,\n index: i,\n level: sq.level,\n cell: sq.cell,\n rowHeight: sq.rowHeight,\n list: sq.list,\n }\"\n />\n }\n </div>\n }\n @for (i of openPlaces(); track i) {\n <div class=\"cs-place\" aria-hidden=\"true\"></div>\n }\n </div>\n }\n `,\n // every class is cs-prefixed: an app's global .tile, .square or .place rules would reach inside,\n // since emulated encapsulation only keeps the component's rules in.\n styles: `\n :host {\n display: block;\n }\n .cs-square {\n display: grid;\n gap: calc(var(--cs-gap) * var(--cube-square-gap-scale, 1));\n --cs-radius: var(--cube-square-radius, 20px);\n }\n .cs-cell {\n display: grid;\n min-width: 0;\n min-height: 0;\n }\n .cs-place {\n box-sizing: border-box;\n border: var(--cube-square-place-width, 1.5px) solid\n var(--cube-square-place, color-mix(in srgb, #dae0d9 55%, transparent));\n border-radius: var(--cs-radius);\n }\n /* something could come here (a cube of mine, a level with a plus): its open places are dashed. */\n .cs-dashed .cs-place {\n border-style: dashed;\n border-color: var(--cube-square-place-dashed, #dae0d9);\n }\n .cs-l0 {\n --cs-radius: 28px;\n }\n .cs-l2 {\n --cs-radius: 16px;\n }\n .cs-l3 {\n --cs-radius: 12px;\n }\n .cs-l4 {\n --cs-radius: 9px;\n }\n .cs-l4 .cs-place {\n border-width: 1px;\n }\n /* turning rows: each row a band of four sides, turned like a puzzle cube's layer. */\n .cs-turning {\n display: flex;\n flex-direction: column;\n gap: calc(var(--cs-gap) * var(--cube-square-gap-scale, 1));\n --cs-radius: var(--cube-square-radius, 20px);\n }\n .cs-row {\n position: relative;\n perspective: 1400px;\n touch-action: pan-y;\n user-select: none;\n -webkit-user-select: none;\n outline: none;\n }\n .cs-row:focus-visible {\n outline: 2px solid var(--cube-square-focus, #5f9a80);\n outline-offset: 3px;\n border-radius: var(--cs-radius);\n }\n .cs-band {\n position: absolute;\n inset: 0;\n transform-style: preserve-3d;\n transition: transform 380ms cubic-bezier(0.2, 0.8, 0.2, 1);\n }\n .cs-band.cs-nudging {\n transition: transform 520ms cubic-bezier(0.4, 0, 0.2, 1);\n }\n .cs-band.cs-still {\n transition: none;\n }\n .cs-side {\n position: absolute;\n inset: 0;\n display: grid;\n gap: calc(var(--cs-gap) * var(--cube-square-gap-scale, 1));\n backface-visibility: hidden;\n }\n /* the hint: the edge of the next side, on a row that has more. */\n .cs-edge {\n pointer-events: none;\n position: absolute;\n top: 18%;\n bottom: 18%;\n right: calc(-1 * max(4px, var(--cs-gap) - 2px));\n z-index: 1;\n width: 3px;\n border-radius: 999px;\n background: var(--cube-square-edge, color-mix(in srgb, #5f9a80 45%, transparent));\n }\n `,\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class CubeSquare<T> {\n /** the tiles, in the order they are placed. */\n readonly tiles = input.required<readonly T[]>();\n /** how they are laid out: the square (the default), one to four across, 4 × 5, 3 × 6. */\n readonly view = input<ViewKey>('square');\n /** the largest side the square takes on a wide screen, in px. */\n readonly maxSide = input(SQUARE_MAX_SIDE);\n /** a row's height in one across, in px. */\n readonly listRow = input(SQUARE_LIST_ROW);\n /** open places dashed, where something could come (a cube of mine, a level with a plus). */\n readonly dashed = input(false);\n /** what keeps a tile the same tile across changes, so it is not drawn anew; its place by default. */\n readonly keyOf = input<(tile: T, index: number) => unknown>((_, i) => i);\n /**\n * turning rows (selim: row rotation, first in mosaic's todarch cube), off unless the app turns\n * them on: on a phone, a square or fixed grid holding more than its front keeps its size, and each\n * row becomes a band of four sides that a finger (or the arrow keys on a focused row) turns, bringing\n * in the pieces past the front (`turningRows`).\n */\n readonly turning = input(false);\n /** rows turn only on a screen narrower than this, in px; a wide screen shows the whole square. */\n readonly turnBelow = input(TURNING_BELOW);\n /** the square's front when its rows turn: `across` × `across` (3 × 3). */\n readonly across = input(3);\n /** which tile is my own box: it keeps the front's last place while the rows turn. */\n readonly isOwn = input<((tile: T) => boolean) | null>(null);\n /** where the turns are counted on this phone (localStorage), so the nudge stops after a few. */\n readonly nudgeKey = input<string | null>(null);\n\n protected readonly tile = contentChild<CubeSquareTile<T>>(CubeSquareTile);\n private readonly grid = viewChild<ElementRef<HTMLElement>>('grid');\n /** the host's width and the window's height, followed as either changes. */\n private readonly room = signal<SquareRoom>({ width: 0, tall: 0 });\n\n /** the layout now: columns, rows, size, gap, level and open places. */\n /** the front kept while the rows turn, or null when they do not (off, a wide screen, all fit). */\n readonly front = computed(() => {\n if (!this.turning()) return null;\n if ((this.room().width || 354) >= this.turnBelow()) return null;\n const front = turningFront(this.view(), Math.max(1, Math.floor(this.across())));\n return front && this.tiles().length > front.cols * front.rows ? front : null;\n });\n\n /** the layout now: columns, rows, size, gap, level and open places. */\n readonly layout = computed(() => {\n const r = this.room();\n const width = r.width || 354;\n const room = { width, tall: r.tall || width };\n const opts = { maxSide: this.maxSide(), listRow: this.listRow() };\n const front = this.front();\n if (!front) return squareLayout(this.view(), this.tiles().length, room, opts);\n // turning: laid out as its full front, then as many rows as the turning rows need\n const view = this.view();\n const full = squareLayout(view, front.cols * front.rows, room, opts);\n const rows = this.rings()?.rows.length ?? front.rows;\n return {\n ...full,\n rows,\n height: rows * full.rowHeight + full.gap * (rows - 1),\n open: 0,\n };\n });\n\n /** the turning rows: rows × four sides × cols, and how many sides of each hold something. */\n protected readonly rings = computed(() => {\n const front = this.front();\n if (!front) return null;\n const isOwn = this.isOwn();\n const tiles = this.tiles();\n const own = isOwn ? (tiles.find((t) => isOwn(t)) ?? null) : null;\n const pieces = own === null ? tiles : tiles.filter((t) => t !== own);\n return turningRows(pieces, own, front.cols, front.rows);\n });\n\n private readonly indexes = computed(() => new Map(this.tiles().map((t, i) => [t, i])));\n protected indexOf(t: T): number {\n return this.indexes().get(t) ?? 0;\n }\n protected readonly openPlaces = computed(() =>\n Array.from({ length: this.layout().open }, (_, i) => i),\n );\n\n /** each row's turn in degrees, and the row a finger is turning now. */\n private readonly angles = signal<Record<number, number>>({});\n protected readonly dragging = signal<number | null>(null);\n /** turns that should not animate (reduced motion). */\n protected readonly still = signal(reducedMotion());\n protected readonly nudging = signal(false);\n private drag: {\n row: number;\n id: number;\n x: number;\n y: number;\n base: number;\n moved: boolean;\n } | null = null;\n /** fingers on the square now: a second one is a pinch, never a turn. */\n private readonly fingers = new Set<number>();\n private suppressClick = false;\n private nudged = false;\n private readonly timers: ReturnType<typeof setTimeout>[] = [];\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef).nativeElement;\n\n protected angle(row: number): number {\n return this.angles()[row] ?? 0;\n }\n\n /** the side of a row facing me (0 to 3). */\n protected sideOf(row: number): number {\n const sides = TURNING_SIDES;\n return ((Math.round(-this.angle(row) / 90) % sides) + sides) % sides;\n }\n\n private filled(row: number): number {\n return this.rings()?.sides[row] ?? 1;\n }\n\n protected down(row: number, e: PointerEvent): void {\n this.fingers.add(e.pointerId);\n if (this.fingers.size > 1) {\n // a pinch: let the turn go, the row settles where it was\n this.cancelDrag();\n return;\n }\n if (this.filled(row) <= 1) return;\n this.drag = {\n row,\n id: e.pointerId,\n x: e.clientX,\n y: e.clientY,\n base: this.angle(row),\n moved: false,\n };\n }\n\n protected move(row: number, e: PointerEvent): void {\n const drag = this.drag;\n if (!drag || drag.row !== row || drag.id !== e.pointerId) return;\n const dx = e.clientX - drag.x;\n const dy = e.clientY - drag.y;\n if (!drag.moved) {\n // only a sideways drag turns; up and down is the page scrolling\n if (Math.abs(dx) < 8 || Math.abs(dx) < Math.abs(dy)) return;\n drag.moved = true;\n this.dragging.set(row);\n (e.currentTarget as HTMLElement | null)?.setPointerCapture?.(e.pointerId);\n }\n const width = this.layout().width || 354;\n this.angles.update((a) => ({ ...a, [row]: drag.base + (dx / width) * 90 }));\n }\n\n protected up(row: number, e: PointerEvent): void {\n this.fingers.delete(e.pointerId);\n const drag = this.drag;\n if (!drag || drag.row !== row || drag.id !== e.pointerId) return;\n this.drag = null;\n if (!drag.moved) return;\n this.dragging.set(null);\n this.suppressClick = true;\n setTimeout(() => (this.suppressClick = false));\n // a short swipe is enough to turn one side; it settles on a side, never between two\n const moved = this.angle(row) - drag.base;\n const steps =\n Math.abs(moved) > 12 ? Math.sign(moved) * Math.max(1, Math.round(Math.abs(moved) / 90)) : 0;\n this.settle(row, drag.base, steps);\n }\n\n private cancelDrag(): void {\n const drag = this.drag;\n this.drag = null;\n if (!drag?.moved) return;\n this.dragging.set(null);\n this.angles.update((a) => ({ ...a, [drag.row]: drag.base }));\n }\n\n /** turns a row `steps` sides from `base`, passing the sides with nothing on them. */\n private settle(row: number, base: number, steps: number): void {\n const filled = this.filled(row);\n const sideAt = (s: number) =>\n ((Math.round(-(base + s * 90) / 90) % TURNING_SIDES) + TURNING_SIDES) % TURNING_SIDES;\n let n = steps;\n while (n !== 0 && sideAt(n) >= filled) n += Math.sign(n);\n this.angles.update((a) => ({ ...a, [row]: base + n * 90 }));\n if (n !== 0) noteTurned(this.nudgeKey());\n }\n\n /** the arrow keys on a focused row turn it, so a keyboard reaches every piece too. */\n protected key(row: number, e: KeyboardEvent): void {\n if (e.key !== 'ArrowRight' && e.key !== 'ArrowLeft') return;\n if (this.filled(row) <= 1) return;\n e.preventDefault();\n const col = this.focusedColumn(e.target as HTMLElement | null);\n // the next side comes in from the right, as a swipe to the left brings it\n this.settle(row, this.angle(row), e.key === 'ArrowRight' ? -1 : 1);\n setTimeout(() => this.focusSide(row, col));\n }\n\n private focusedColumn(target: HTMLElement | null): number {\n const cell = target?.closest('.cs-cell, .cs-place');\n const side = cell?.parentElement;\n return cell && side ? Array.from(side.children).indexOf(cell) : 0;\n }\n\n /** after a turn by the keys, focus goes to the same place on the side now facing me. */\n private focusSide(row: number, col: number): void {\n const side = this.host.querySelector<HTMLElement>(\n `.cs-row[data-row=\"${row}\"] .cs-side[data-side=\"${this.sideOf(row)}\"]`,\n );\n if (!side) return;\n const cells = Array.from(side.children) as HTMLElement[];\n const order = [cells[col], ...cells].filter(Boolean);\n const focusable = 'button, a[href], input, select, textarea, [tabindex]:not([tabindex=\"-1\"])';\n for (const cell of order) {\n const el = cell.matches(focusable) ? cell : cell.querySelector<HTMLElement>(focusable);\n if (el) {\n el.focus();\n return;\n }\n }\n side.closest<HTMLElement>('.cs-row')?.focus();\n }\n\n /** the nudge: rows with more turn a little and back, one after another, until i turned a few. */\n private nudge(): void {\n const rings = this.rings();\n if (this.nudged || !rings || reducedMotion()) return;\n if (readTurned(this.nudgeKey()) >= TURNING_NUDGE_UNTIL) return;\n const rows = rings.sides.flatMap((s, i) => (s > 1 ? [i] : []));\n if (!rows.length) return;\n this.nudged = true;\n this.nudging.set(true);\n const set = (row: number, angle: number) => {\n if (this.drag || this.dragging() !== null) return;\n this.angles.update((a) => ({ ...a, [row]: angle }));\n };\n rows.forEach((row, i) => {\n this.timers.push(\n setTimeout(() => set(row, -22), 500 + i * 180),\n setTimeout(() => set(row, 0), 1020 + i * 180),\n );\n });\n this.timers.push(setTimeout(() => this.nudging.set(false), 1600 + rows.length * 180));\n }\n\n constructor() {\n const host = this.host;\n const destroy = inject(DestroyRef);\n // the tap that ends a turn is not a tap on a tile\n const swallow = (e: Event) => {\n if (!this.suppressClick) return;\n e.stopPropagation();\n e.preventDefault();\n };\n host.addEventListener('click', swallow, true);\n destroy.onDestroy(() => {\n host.removeEventListener('click', swallow, true);\n this.timers.forEach(clearTimeout);\n });\n effect(() => {\n if (this.rings()) untracked(() => this.timers.push(setTimeout(() => this.nudge())));\n });\n afterNextRender(() => {\n const measure = () =>\n this.room.set({ width: host.clientWidth, tall: Math.max(320, window.innerHeight - 48) });\n measure();\n const watch = typeof ResizeObserver === 'function' ? new ResizeObserver(measure) : null;\n watch?.observe(host);\n window.addEventListener('resize', measure);\n destroy.onDestroy(() => {\n watch?.disconnect();\n window.removeEventListener('resize', measure);\n });\n });\n // a square that has to hold more zooms out a step (and in when it holds fewer); the other views\n // only grow longer.\n let before = 0;\n let beforeView: ViewKey | null = null;\n effect(() => {\n const { cols, list } = this.layout();\n const view = this.view();\n const el = this.grid()?.nativeElement;\n if (\n el &&\n before &&\n cols !== before &&\n view === beforeView &&\n !list &&\n !reducedMotion() &&\n typeof el.animate === 'function'\n ) {\n el.animate([{ transform: `scale(${cols / before})` }, { transform: 'none' }], {\n duration: 420,\n easing: 'cubic-bezier(.2,.7,.2,1)',\n });\n }\n before = cols;\n beforeView = view;\n });\n }\n}\n","import {\n ChangeDetectionStrategy,\n Component,\n computed,\n effect,\n inject,\n input,\n output,\n signal,\n untracked,\n} from '@angular/core';\nimport { CUBE_ICON_NAMES, CubeIcon, CubeIconName } from '../icon/cube-icon';\nimport {\n CubeSquare,\n CubeSquareTile,\n SquareLevel,\n squareGap,\n squareLevelFor,\n} from '../square/cube-square';\nimport { gridFor } from './arrange';\nimport {\n CONTEXT_CUBE_SOURCE,\n CONTEXT_CUBE_WORDS,\n ContextCubeSource,\n ContextPath,\n ContextTile,\n ContextWords,\n} from './context-cube';\n\n/*\n * the square that draws one level of a context cube: the tiles an app's `ContextCubeSource` gives\n * for the held thing at a path, as a complete square (cube design decision 23, cubes decisions 39\n * and 40). it never routes, zooms, draws a head or says a word of its own: each app hosts it in its\n * own route under its own head, and walks the path it reports.\n */\n\n/** how close a square's places are: from one big tile (0) to only its icon (4). */\nexport type ContextLevel = SquareLevel;\n\n/** cubes' steps, now the square's (`squareLevelFor`); kept under its first name. */\nexport const contextLevelFor: (cell: number) => ContextLevel = squareLevelFor;\n\n/** a level's square: n × n places, how far apart, and how much each tile says. */\nexport interface ContextSquare {\n /** places on a side. */\n n: number;\n /** the square's side, in px. */\n side: number;\n gap: number;\n level: ContextLevel;\n /** the places not filled, outlined so the square stays whole. */\n open: number;\n}\n\n/**\n * the square for this many tiles in this much room: the smallest n × n that holds them all\n * (`gridFor('square', count)`), as wide as the room, at most `maxSide`.\n */\nexport function contextSquare(count: number, room: number, maxSide = 880): ContextSquare {\n const { cols: n, rows } = gridFor('square', count);\n const side = Math.max(0, Math.min(room, maxSide));\n const gap = squareGap(n);\n const cell = (side - gap * (n - 1)) / n;\n return { n, side, gap, level: contextLevelFor(cell), open: n * rows - Math.max(0, count) };\n}\n\n/**\n * the icon a tile is drawn with: its own when `cube-icon` draws it, shown for `hide` (it has no icon\n * of its own), the plus for a tile that adds, and else a face (an app's own part with an icon the\n * package does not have).\n */\nexport function contextIcon(tile: Pick<ContextTile, 'icon' | 'adds'>): CubeIconName {\n if ((CUBE_ICON_NAMES as readonly string[]).includes(tile.icon)) return tile.icon as CubeIconName;\n if (tile.adds) return 'plus';\n if (tile.icon === 'hide') return 'shown';\n return 'face';\n}\n\n/** a tapped tile and the element it is drawn in. */\nexport interface ContextTapped {\n tile: ContextTile;\n element: HTMLElement;\n}\n\n/**\n * `<cube-context [held] [path]>`: one level of the held thing's context cube, as a complete square\n * of icon tiles. a tap asks the source's `pick`, and the answer comes out as `enter` (a deeper\n * path), `done` (the journey ends: a name, a view, shown or hidden was used) or `out` (one level\n * up); `stay` redraws the level where it is. a level the source does not have (null) is `out` too.\n *\n * the source and the words come from `CONTEXT_CUBE_SOURCE` and `CONTEXT_CUBE_WORDS`, or from the\n * `source` and `words` inputs when one screen holds a different one. its look is css variables\n * (`--cube-context-*`, `--cube-icon-*`), set in both token files.\n */\n@Component({\n selector: 'cube-context',\n imports: [CubeIcon, CubeSquare, CubeSquareTile],\n template: `\n <cube-square\n [tiles]=\"tiles()\"\n [dashed]=\"adds()\"\n [maxSide]=\"maxSide()\"\n [keyOf]=\"keyOf\"\n [class.cc-adds]=\"adds()\"\n >\n <ng-template [cubeSquareTile]=\"tiles()\" let-t let-level=\"level\">\n <button\n type=\"button\"\n [class]=\"'cc-tile cc-l' + level\"\n [class.cc-in-use]=\"!!t.inUse\"\n [class.cc-pale]=\"!!t.pale\"\n [class.cc-adds]=\"!!t.adds\"\n [class.cc-busy]=\"busy() === t.key\"\n [disabled]=\"busy() !== null\"\n [attr.aria-label]=\"level >= 4 ? t.title : null\"\n [attr.aria-current]=\"t.inUse ? 'true' : null\"\n [attr.title]=\"level >= 3 ? t.title : null\"\n (click)=\"tap(t, $any($event.currentTarget))\"\n >\n <span class=\"cc-icon\"><cube-icon [icon]=\"iconOf(t)\" [inUse]=\"!!t.inUse\" /></span>\n @if (level < 4) {\n <span class=\"cc-t\">{{ t.title }}</span>\n }\n @if (t.line && level < 3) {\n <span class=\"cc-m\">{{ t.line }}</span>\n }\n @if (t.inUse && inUseWord() && level < 3) {\n <span class=\"cc-tick\">{{ inUseWord() }}</span>\n }\n </button>\n </ng-template>\n </cube-square>\n `,\n // every class is cc-prefixed: an app's own .tile, .square or .place rules (cubes has them) are\n // global and would reach inside, since emulated encapsulation only keeps the component's rules in.\n styles: `\n :host {\n display: block;\n font: inherit;\n color: var(--cube-context-ink, #1f2a26);\n /* the square's open places in the context cube's own look */\n --cube-square-place: color-mix(in srgb, var(--cube-context-line, #dae0d9) 55%, transparent);\n --cube-square-place-dashed: var(--cube-context-line, #dae0d9);\n --cube-square-radius: var(--cube-context-radius, 20px);\n }\n .cc-tile {\n all: unset;\n cursor: pointer;\n box-sizing: border-box;\n min-width: 0;\n min-height: 0;\n height: 100%;\n overflow: hidden;\n display: grid;\n justify-items: center;\n align-content: center;\n gap: 6px;\n padding: 14px 10px 12px;\n text-align: center;\n background: var(--cube-context-tile, #ffffff);\n border: 1px solid var(--cube-context-line, #dae0d9);\n border-radius: var(--cube-context-radius, 20px);\n user-select: none;\n -webkit-user-select: none;\n -webkit-touch-callout: none;\n transition: transform 160ms;\n }\n .cc-tile:active:not(:disabled) {\n transform: scale(0.97);\n }\n .cc-tile:focus-visible {\n outline: 3px solid var(--cube-context-focus, #5f9a80);\n outline-offset: 2px;\n }\n .cc-tile.cc-in-use {\n border: 2px solid var(--cube-context-in-use, #3b5a4c);\n }\n .cc-tile.cc-pale {\n background: transparent;\n border: 2px dashed var(--cube-context-line, #dae0d9);\n color: var(--cube-context-quiet, #5d6a64);\n }\n .cc-tile.cc-adds {\n border: 2px solid var(--cube-context-adds, #c8693f);\n }\n .cc-tile.cc-busy {\n opacity: 0.6;\n cursor: progress;\n }\n .cc-tile:disabled:not(.cc-busy) {\n cursor: default;\n }\n .cc-icon {\n display: grid;\n place-items: center;\n line-height: 0;\n }\n .cc-tile.cc-adds .cc-icon {\n width: 52px;\n height: 52px;\n border-radius: 50%;\n background: var(--cube-context-adds-bg, #f3e3d6);\n --cube-icon-stroke: var(--cube-context-adds-ink, #7a4a2b);\n --cube-icon-size: 26px;\n }\n .cc-t,\n .cc-m {\n display: -webkit-box;\n -webkit-box-orient: vertical;\n overflow: hidden;\n overflow-wrap: anywhere;\n }\n .cc-t {\n -webkit-line-clamp: var(--cube-context-title-lines, 2);\n line-clamp: var(--cube-context-title-lines, 2);\n }\n .cc-m {\n -webkit-line-clamp: var(--cube-context-line-lines, 2);\n line-clamp: var(--cube-context-line-lines, 2);\n }\n .cc-t {\n font-size: var(--cube-context-title-size, 17px);\n font-weight: 700;\n line-height: 1.2;\n }\n .cc-m {\n font-size: var(--cube-context-line-size, 13px);\n line-height: 1.3;\n color: var(--cube-context-quiet, #5d6a64);\n }\n .cc-tick {\n font-size: var(--cube-context-line-size, 13px);\n font-weight: 800;\n color: var(--cube-context-in-use, #3b5a4c);\n }\n .cc-tile.cc-l0 {\n border-radius: 28px;\n padding: 24px;\n gap: 10px;\n }\n .cc-l0 .cc-t {\n font-size: calc(var(--cube-context-title-size, 17px) * 26 / 17);\n }\n .cc-l0 .cc-m {\n font-size: calc(var(--cube-context-line-size, 13px) * 16 / 13);\n }\n .cc-l0 .cc-icon {\n --cube-icon-size: 64px;\n }\n .cc-tile.cc-l0.cc-adds .cc-icon {\n width: 96px;\n height: 96px;\n --cube-icon-size: 40px;\n }\n .cc-tile.cc-l2 {\n border-radius: 16px;\n padding: 10px 6px;\n gap: 5px;\n }\n .cc-l2 .cc-t {\n font-size: calc(var(--cube-context-title-size, 17px) * 14 / 17);\n }\n .cc-l2 .cc-m {\n font-size: calc(var(--cube-context-line-size, 13px) * 12 / 13);\n }\n .cc-tile.cc-l3 {\n border-radius: 12px;\n padding: 6px 4px;\n gap: 3px;\n }\n .cc-l3 .cc-t {\n font-size: calc(var(--cube-context-title-size, 17px) * 12 / 17);\n }\n .cc-tile.cc-l4 {\n border-radius: 9px;\n padding: 2px;\n gap: 0;\n }\n .cc-l3 .cc-icon,\n .cc-l4 .cc-icon {\n --cube-icon-size: 24px;\n }\n .cc-tile.cc-l3.cc-adds .cc-icon,\n .cc-tile.cc-l4.cc-adds .cc-icon {\n width: 30px;\n height: 30px;\n --cube-icon-size: 18px;\n }\n `,\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class CubeContext {\n /** what was held: a piece, a cube, a to-do, a level, as the app's source knows it. */\n readonly held = input.required<unknown>();\n /** where in its context cube: [] is its top (the parts), ['names'] a part, ['sort', by] deeper. */\n readonly path = input<ContextPath>([]);\n /** a source for this screen alone; else `CONTEXT_CUBE_SOURCE`. */\n readonly source = input<ContextCubeSource<any> | null>(null);\n /** words for this screen alone; else `CONTEXT_CUBE_WORDS`. */\n readonly words = input<ContextWords | null>(null);\n /** the largest side the square takes on a wide screen, in px. */\n readonly maxSide = input(880);\n\n /** walk into a deeper level: the app puts this path in its own route. */\n readonly enter = output<string[]>();\n /** step one level out (or out of the context cube, from its top). */\n readonly out = output<void>();\n /** the journey ends: the tile that was used. */\n readonly done = output<ContextTile>();\n /**\n * a tile was tapped, before the source answers: the tile and its element, so the app can grow the\n * next level (or whatever the pick opens) out of the tile, as it zooms into any other piece.\n */\n readonly tapped = output<ContextTapped>();\n\n private readonly given = inject(CONTEXT_CUBE_SOURCE, { optional: true });\n private readonly givenWords = inject(CONTEXT_CUBE_WORDS, { optional: true });\n\n /** the tile whose pick is still being answered; every tile waits meanwhile. */\n protected readonly busy = signal<string | null>(null);\n /** bumped after a pick, so a source that keeps its data outside signals is read again. */\n private readonly again = signal(0);\n\n private readonly from = computed(() => {\n const s = this.source() ?? this.given;\n if (!s) throw new Error('cube-context: provide CONTEXT_CUBE_SOURCE or pass [source]');\n return s;\n });\n /** the path as one key, so the same path given anew is the same level. */\n private readonly where = computed(() => this.path().join('\\u0000'));\n private readonly level = computed(() => {\n this.again();\n return this.from().level(this.held(), this.path());\n });\n protected readonly tiles = computed(() => this.level() ?? []);\n protected readonly adds = computed(() => this.tiles().some((t) => !!t.adds));\n /** a tile stays the same tile across levels by its key. */\n protected readonly keyOf = (t: ContextTile) => t.key;\n protected readonly inUseWord = computed(() => (this.words() ?? this.givenWords)?.inUse ?? null);\n protected readonly iconOf = contextIcon;\n\n constructor() {\n // a path the source does not have (a part that went away) steps out.\n effect(() => {\n if (this.level() === null) untracked(() => this.out.emit());\n });\n // a new path is a new level: nothing is waiting any more.\n effect(() => {\n this.where();\n this.held();\n untracked(() => this.busy.set(null));\n });\n }\n\n protected async tap(tile: ContextTile, element?: HTMLElement): Promise<void> {\n if (this.busy() !== null) return;\n if (element) this.tapped.emit({ tile, element });\n const held = this.held();\n const path = this.path();\n const where = this.where();\n const here = () => this.held() === held && this.where() === where;\n this.busy.set(tile.key);\n try {\n const picked = await this.from().pick(held, path, tile);\n // the person walked elsewhere while it was answered: the answer is for a level gone.\n if (!here()) return;\n switch (picked.kind) {\n case 'enter':\n this.enter.emit(picked.path);\n break;\n case 'done':\n this.done.emit(tile);\n break;\n case 'out':\n this.out.emit();\n break;\n case 'stay':\n break;\n }\n } finally {\n if (here()) this.busy.set(null);\n this.again.update((n) => n + 1);\n }\n }\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@selimssevgi/cube-design-angular",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "cube design in angular: the pieces anlat, mosaic and cubes share, starting with the isometric cube picture.",
5
5
  "keywords": [
6
6
  "angular",
package/tokens/dark.css CHANGED
@@ -28,6 +28,10 @@
28
28
  --cube-context-adds-ink: #f3e3d6;
29
29
  --cube-context-focus: #9cc5b0;
30
30
  --cube-context-radius: 20px;
31
+ --cube-context-title-size: 17px;
32
+ --cube-context-line-size: 13px;
33
+ --cube-context-title-lines: 2;
34
+ --cube-context-line-lines: 2;
31
35
  --cube-square-place: color-mix(in srgb, #4b5563 55%, transparent);
32
36
  --cube-square-place-dashed: #4b5563;
33
37
  --cube-square-place-width: 1.5px;
package/tokens/light.css CHANGED
@@ -28,6 +28,10 @@
28
28
  --cube-context-adds-ink: #7a4a2b;
29
29
  --cube-context-focus: #5f9a80;
30
30
  --cube-context-radius: 20px;
31
+ --cube-context-title-size: 17px;
32
+ --cube-context-line-size: 13px;
33
+ --cube-context-title-lines: 2;
34
+ --cube-context-line-lines: 2;
31
35
  --cube-square-place: color-mix(in srgb, #dae0d9 55%, transparent);
32
36
  --cube-square-place-dashed: #dae0d9;
33
37
  --cube-square-place-width: 1.5px;