efficient-shell 4.127.0 → 4.132.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +938 -5
- package/dist/{Browser-F5TKMP4K.js → Browser-XPVJ2K7B.js} +13 -10
- package/dist/Browser-XPVJ2K7B.js.map +1 -0
- package/dist/{Calculator-T3XG7S73.js → Calculator-ZXJPXG7F.js} +12 -9
- package/dist/Calculator-ZXJPXG7F.js.map +1 -0
- package/dist/ConfirmDialog-MTC7QMUJ.js +4 -0
- package/dist/{ConfirmDialog-LJXMB45A.js.map → ConfirmDialog-MTC7QMUJ.js.map} +1 -1
- package/dist/{CurrencyConverter-CASQMKLO.js → CurrencyConverter-WSJ2BBSX.js} +12 -9
- package/dist/CurrencyConverter-WSJ2BBSX.js.map +1 -0
- package/dist/{Documents-YX67YTZS.js → Documents-ONGSXUJI.js} +14 -11
- package/dist/Documents-ONGSXUJI.js.map +1 -0
- package/dist/{Files-QB63GO6J.js → Files-GQZMFWXQ.js} +17 -14
- package/dist/Files-GQZMFWXQ.js.map +1 -0
- package/dist/{Notepad-3SUD5XUE.js → Notepad-HM73XAM4.js} +15 -12
- package/dist/Notepad-HM73XAM4.js.map +1 -0
- package/dist/PdfViewer-M2YGZIYX.js +5 -0
- package/dist/{PdfViewer-LSP3YNFC.js.map → PdfViewer-M2YGZIYX.js.map} +1 -1
- package/dist/{PomodoroTimer-4EHD2QC4.js → PomodoroTimer-DG3LI5CX.js} +14 -11
- package/dist/PomodoroTimer-DG3LI5CX.js.map +1 -0
- package/dist/{Preview-4ZHR4SKP.js → Preview-TUSV4UMO.js} +16 -13
- package/dist/Preview-TUSV4UMO.js.map +1 -0
- package/dist/{Sidebar-J76PV4QF.js → Sidebar-BPU7RCZP.js} +5 -4
- package/dist/Sidebar-BPU7RCZP.js.map +1 -0
- package/dist/{Spreadsheet-G3SC7XJ5.js → Spreadsheet-3WTXCHYQ.js} +14 -11
- package/dist/Spreadsheet-3WTXCHYQ.js.map +1 -0
- package/dist/{Stock-TLT4VN2R.js → Stock-YMPOMUAW.js} +12 -9
- package/dist/Stock-YMPOMUAW.js.map +1 -0
- package/dist/{Weather-FRKX3DAK.js → Weather-NZO3CWLH.js} +12 -9
- package/dist/Weather-NZO3CWLH.js.map +1 -0
- package/dist/{WorldClock-GKCITO3M.js → WorldClock-HUC6D3AD.js} +12 -9
- package/dist/WorldClock-HUC6D3AD.js.map +1 -0
- package/dist/apps/index.js +26 -22
- package/dist/apps/index.js.map +1 -1
- package/dist/brand.css +1 -1
- package/dist/chunk-7IN7YZAL.js +547 -0
- package/dist/chunk-7IN7YZAL.js.map +1 -0
- package/dist/{chunk-YNGPTOL6.js → chunk-7MA5XBWD.js} +3 -3
- package/dist/{chunk-YNGPTOL6.js.map → chunk-7MA5XBWD.js.map} +1 -1
- package/dist/{chunk-WK7FV7VV.js → chunk-BJ34QOR3.js} +827 -625
- package/dist/chunk-BJ34QOR3.js.map +1 -0
- package/dist/{chunk-HNH7FOYB.js → chunk-CGXMWHQW.js} +7 -6
- package/dist/chunk-CGXMWHQW.js.map +1 -0
- package/dist/{chunk-XUCIYMN7.js → chunk-CJYO4RVV.js} +4 -4
- package/dist/{chunk-XUCIYMN7.js.map → chunk-CJYO4RVV.js.map} +1 -1
- package/dist/{chunk-N3CG5HG5.js → chunk-CLGNTGC5.js} +12 -11
- package/dist/chunk-CLGNTGC5.js.map +1 -0
- package/dist/chunk-D276EMXS.js +57 -0
- package/dist/chunk-D276EMXS.js.map +1 -0
- package/dist/{chunk-7KIOEKHS.js → chunk-E3TWIN7Z.js} +21 -135
- package/dist/chunk-E3TWIN7Z.js.map +1 -0
- package/dist/{chunk-2VM2FRZJ.js → chunk-EENVXIVU.js} +47 -67
- package/dist/chunk-EENVXIVU.js.map +1 -0
- package/dist/{chunk-YG45DAUT.js → chunk-FONEQRBH.js} +17 -11
- package/dist/chunk-FONEQRBH.js.map +1 -0
- package/dist/chunk-IPXN646P.js +14 -0
- package/dist/chunk-IPXN646P.js.map +1 -0
- package/dist/chunk-IRWSRJ4K.js +48 -0
- package/dist/chunk-IRWSRJ4K.js.map +1 -0
- package/dist/chunk-JMKYYPOF.js +7 -0
- package/dist/{chunk-CJZXR7MG.js.map → chunk-JMKYYPOF.js.map} +1 -1
- package/dist/{chunk-JFQGPY7W.js → chunk-KWEX4ZAF.js} +20 -17
- package/dist/chunk-KWEX4ZAF.js.map +1 -0
- package/dist/{chunk-OKEFO6TI.js → chunk-LQTVTOSY.js} +10 -10
- package/dist/chunk-LQTVTOSY.js.map +1 -0
- package/dist/{chunk-G4KA3SAX.js → chunk-MQPX6ERJ.js} +4 -4
- package/dist/{chunk-G4KA3SAX.js.map → chunk-MQPX6ERJ.js.map} +1 -1
- package/dist/{chunk-FQB24B42.js → chunk-SEWF4O3H.js} +3 -3
- package/dist/{chunk-FQB24B42.js.map → chunk-SEWF4O3H.js.map} +1 -1
- package/dist/{chunk-AXWC3332.js → chunk-TFXJRHJV.js} +3 -3
- package/dist/{chunk-AXWC3332.js.map → chunk-TFXJRHJV.js.map} +1 -1
- package/dist/{chunk-G3HQLQYZ.js → chunk-TQURTLK2.js} +59 -34
- package/dist/chunk-TQURTLK2.js.map +1 -0
- package/dist/{chunk-6XQHH7D2.js → chunk-TRCWINHF.js} +5 -5
- package/dist/{chunk-6XQHH7D2.js.map → chunk-TRCWINHF.js.map} +1 -1
- package/dist/{chunk-NPJCMM6V.js → chunk-VWZIGZFF.js} +4 -4
- package/dist/{chunk-NPJCMM6V.js.map → chunk-VWZIGZFF.js.map} +1 -1
- package/dist/{chunk-HYZ5QMVO.js → chunk-XH3ELPQZ.js} +22 -19
- package/dist/chunk-XH3ELPQZ.js.map +1 -0
- package/dist/{chunk-PPUZJFCI.js → chunk-ZKHD4J73.js} +8 -7
- package/dist/chunk-ZKHD4J73.js.map +1 -0
- package/dist/file-intake/index.js +3 -1
- package/dist/file-intake/index.js.map +1 -1
- package/dist/{index-dQia6NpB.d.ts → index-COwksV6G.d.ts} +699 -199
- package/dist/index.d.ts +2 -2
- package/dist/index.js +37 -32
- package/dist/index.js.map +1 -1
- package/dist/map/index.js +5 -3
- package/dist/map/index.js.map +1 -1
- package/dist/markdown/index.js +4 -3
- package/dist/markdown/index.js.map +1 -1
- package/dist/page-tabs/index.js +12 -8
- package/dist/page-tabs/index.js.map +1 -1
- package/dist/shell.css +17 -17
- package/dist/themes.css +15 -0
- package/dist/ui/index.d.ts +1 -1
- package/dist/ui/index.js +17 -13
- package/dist/ui/index.js.map +1 -1
- package/dist/ui.css +691 -283
- package/package.json +1 -1
- package/dist/Browser-F5TKMP4K.js.map +0 -1
- package/dist/Calculator-T3XG7S73.js.map +0 -1
- package/dist/ConfirmDialog-LJXMB45A.js +0 -3
- package/dist/CurrencyConverter-CASQMKLO.js.map +0 -1
- package/dist/Documents-YX67YTZS.js.map +0 -1
- package/dist/Files-QB63GO6J.js.map +0 -1
- package/dist/Notepad-3SUD5XUE.js.map +0 -1
- package/dist/PdfViewer-LSP3YNFC.js +0 -4
- package/dist/PomodoroTimer-4EHD2QC4.js.map +0 -1
- package/dist/Preview-4ZHR4SKP.js.map +0 -1
- package/dist/Sidebar-J76PV4QF.js.map +0 -1
- package/dist/Spreadsheet-G3SC7XJ5.js.map +0 -1
- package/dist/Stock-TLT4VN2R.js.map +0 -1
- package/dist/Weather-FRKX3DAK.js.map +0 -1
- package/dist/WorldClock-GKCITO3M.js.map +0 -1
- package/dist/chunk-2VM2FRZJ.js.map +0 -1
- package/dist/chunk-3CUSBZWG.js +0 -59
- package/dist/chunk-3CUSBZWG.js.map +0 -1
- package/dist/chunk-7KIOEKHS.js.map +0 -1
- package/dist/chunk-CJZXR7MG.js +0 -7
- package/dist/chunk-G3HQLQYZ.js.map +0 -1
- package/dist/chunk-HNH7FOYB.js.map +0 -1
- package/dist/chunk-HYZ5QMVO.js.map +0 -1
- package/dist/chunk-JFQGPY7W.js.map +0 -1
- package/dist/chunk-N3CG5HG5.js.map +0 -1
- package/dist/chunk-OKEFO6TI.js.map +0 -1
- package/dist/chunk-PPUZJFCI.js.map +0 -1
- package/dist/chunk-WK7FV7VV.js.map +0 -1
- package/dist/chunk-YG45DAUT.js.map +0 -1
package/README.md
CHANGED
|
@@ -373,7 +373,7 @@ All exports are named — `import { Modal, ... } from 'efficient-shell'`.
|
|
|
373
373
|
|---|---|
|
|
374
374
|
| `<ShellAuthProvider value={{ hasAnyPerm }}>` | Permission-filter nav items. |
|
|
375
375
|
| `<ShellPrefsProvider value={{ prefs, save }}>` | Where the shell reads/writes user prefs (theme, taskbar pos, sticky notes, …). Use `useLocalStoragePrefs(key)` for a backend-less default. Since 4.92.0 it is also how `<EntityList>` / `<ResizableTable>` column config and sort persist: with no provider mounted, `useShellPrefs()` reads empty and drops saves, so both silently degrade to localStorage-only and never reach the user's profile. Session restore reads `session_windows` once, at mount: hand the provider prefs that are already loaded by then (an adapter whose prefs arrive later misses that load's replay, though the saved set is kept). |
|
|
376
|
-
| `<ShellStringsProvider value={{ … }}
|
|
376
|
+
| `<ShellStringsProvider value={{ … }} locale?>` | Translates every word the shell and the kit draw on their own account — window controls, taskbar hints, dialogs, pickers, pagers, list footers, upload zones, charts, timelines. English works with NO provider; the override is a typed partial merged per section, so an incomplete catalog falls back rather than breaking. Prop-level text (`emptyText`, placeholders) always wins over the catalog. `locale` (a BCP 47 tag) writes dates and numbers that locale's way; without one nothing moves. See [Languages, dates and numbers](#languages-dates-and-numbers--shellstringsprovider) for the full catalog. |
|
|
377
377
|
| `<ShellEntityFetcherProvider value={(endpoint, id) => …}>` | How the modal stack fetches entity data. |
|
|
378
378
|
| `<BugReportConfigProvider value={{ submit, list?, resolve? }}>` | Wire the bug-report flow to your backend. |
|
|
379
379
|
| `<DesktopHostProvider value={{ stickyResolver?, saveShortcuts?, … }}>` | Sticky-note ref resolver + persistence callbacks. |
|
|
@@ -403,6 +403,7 @@ All exports are named — `import { Modal, ... } from 'efficient-shell'`.
|
|
|
403
403
|
| `useUndoCanEdit(canEdit)` | A form's own word on whether the record may be edited right now — `useUndoCanEdit(!isLocked)`. While false the stack records nothing, ⌘Z is left alone and the footer shows no controls. A nested `<UndoProvider canEdit={false}>` in the form's JSX says the same thing: it shadows the stack for its children AND forwards the read-only claim to the window's stack, which is where the form's own `useUndoableState` calls (made above it in the tree) register. Either form of the claim makes the whole window read-only. The positive claim, `useUndoCanEdit(true)`, is how a window that edits in place outside Edit mode — a detail with inline cells behind a permission — asks the footer for the pair. |
|
|
404
404
|
| `useMultiModal()` | Manages multi-window stacking + activate/blur. |
|
|
405
405
|
| `useShellAuth() / useShellPrefs() / useShellEntityFetcher() / useBugReport() / useDesktopHost()` | Context readers — the shell uses these internally; consumers may also call them. |
|
|
406
|
+
| `useShellStrings() / useShellLocale()` | The active catalog, and the provider's `locale` (`undefined` without one) — for a host cell that should write a date or a number the way the kit does. |
|
|
406
407
|
|
|
407
408
|
### Apps barrel — `efficient-shell/apps`
|
|
408
409
|
|
|
@@ -491,8 +492,20 @@ What you get: every form control, the display and layout primitives
|
|
|
491
492
|
`HelpCenter`, `EditableGrid`, `SearchableSelect`, `PopupMenu`), the charts, all
|
|
492
493
|
nine page templates, the pageless data primitives (`Pagination`, `Kanban`,
|
|
493
494
|
`ListFooter`, `ListLoadError`), `toast`, and the theming hooks (`useTheme`,
|
|
494
|
-
`resolveTheme`, `applyThemePrefs`) —
|
|
495
|
-
|
|
495
|
+
`resolveTheme`, `applyThemePrefs`) — the way to an accent theme, which works by
|
|
496
|
+
stamping `data-theme`. Dark mode answers to either `<html data-theme="dark">`
|
|
497
|
+
(what `useTheme` stamps) or `<html class="dark">` (next-themes, shadcn/ui,
|
|
498
|
+
Tailwind's class strategy), so an app whose own theme switcher already sets the
|
|
499
|
+
class gets the kit's dark mode with nothing more to wire.
|
|
500
|
+
|
|
501
|
+
**An app with its own design system** can keep the kit off its markup. Three
|
|
502
|
+
rules in `ui.css` style bare elements rather than the kit's components: dark
|
|
503
|
+
form controls (every `input`, `select` and `textarea`), the 16px font-size that
|
|
504
|
+
stops iOS zooming on focus (narrow or coarse-pointer screens), and dark
|
|
505
|
+
scrollbars. In a portal built on the kit that is what you want; in an app that
|
|
506
|
+
draws its own controls it restyles them. `<html class="rosh-host-elements">`
|
|
507
|
+
turns those three off. The kit's own controls stay dark through their
|
|
508
|
+
remapped utility classes.
|
|
496
509
|
|
|
497
510
|
What you do not get: `Modal` and the window manager, `Layout`, `Desktop`,
|
|
498
511
|
`StartMenu`, `GlobalSearch`, the settings panels, the bundled apps, and the
|
|
@@ -510,6 +523,926 @@ layers without preflight.
|
|
|
510
523
|
`efficient-shell` (the root entry) is unchanged and remains a superset: same
|
|
511
524
|
components, same bindings, plus the shell.
|
|
512
525
|
|
|
526
|
+
### Server rendering (Next.js App Router)
|
|
527
|
+
|
|
528
|
+
Every React entry — the root, `ui`, `apps`, `markdown`, `file-intake`,
|
|
529
|
+
`page-tabs`, `map` — starts with `"use client"`, so a **server component can
|
|
530
|
+
import and render kit components**: they are server-rendered as client
|
|
531
|
+
components and hydrated in the browser.
|
|
532
|
+
|
|
533
|
+
```tsx
|
|
534
|
+
// app/bookings/page.tsx — a server component
|
|
535
|
+
import { Card, PageHeader, DataTable } from 'efficient-shell/ui';
|
|
536
|
+
```
|
|
537
|
+
|
|
538
|
+
- **Kit functions and constants are client references.** `toast`, `confirm`,
|
|
539
|
+
`formatDate`, `inputClasses`, `resolveTheme`, `CMD_K`, `Z_LAYERS`… arrive in a
|
|
540
|
+
server component as references, not values: call them from client code (a
|
|
541
|
+
`'use client'` file, an event handler, an effect). From a server component,
|
|
542
|
+
render components and pass them serialisable props.
|
|
543
|
+
- **`markup` is server-safe.** It has no directive and imports no React, so its
|
|
544
|
+
functions are plain functions you can call from server code.
|
|
545
|
+
- **The first render is the server's.** What only a browser knows renders as
|
|
546
|
+
the server would, and switches one render after hydration: the ⌘ forms of the
|
|
547
|
+
shortcut constants (render them through `<Kbd keys={CMD_K} />`, which handles
|
|
548
|
+
the switch; `isMac` is `false` on a server), a `SidebarLayout`'s saved width,
|
|
549
|
+
`useLocalStoragePrefs`, the OS dark-mode setting in `useTheme`, reduced motion,
|
|
550
|
+
and *today* — `Calendar` marks it after hydration, and a `Calendar` with
|
|
551
|
+
nothing to open on (no `value`, `month` or `defaultMonth`) draws an empty frame
|
|
552
|
+
until then, so pass `defaultMonth` if the server knows the month. Popups and
|
|
553
|
+
portals open after hydration. A root that was never server-rendered sees none
|
|
554
|
+
of this: it reads the browser on its first render, as before.
|
|
555
|
+
- `formatDate` writes the default format on a server. A page that also lets
|
|
556
|
+
readers choose a format (`user_date_format`) should format those dates in the
|
|
557
|
+
browser after mount.
|
|
558
|
+
|
|
559
|
+
### Theming the kit from a host app
|
|
560
|
+
|
|
561
|
+
An app with its own design system — its own neutrals, its own primary, square
|
|
562
|
+
corners, one focus treatment for the whole app — can put the kit under its look
|
|
563
|
+
without forking a component. Every colour, radius, typeface and focus ring the
|
|
564
|
+
kit draws comes from a token, and the knobs below are all of them. (A colour
|
|
565
|
+
written as a literal in a kit module fails the build:
|
|
566
|
+
`tests/kitColourLiterals.test.ts`.)
|
|
567
|
+
|
|
568
|
+
Write light classes in your own markup and never `dark:` variants. The kit's
|
|
569
|
+
dark mode remaps utility classes under `<html data-theme="dark">` or
|
|
570
|
+
`<html class="dark">` — so a next-themes or shadcn/ui host already has it, and
|
|
571
|
+
points it at its own palette through the neutral roles below — and its accent
|
|
572
|
+
themes under `data-theme="pink" | "green" | "grey" | "blue"`, which only a host
|
|
573
|
+
that stamps one gets. `rosh-host-elements` on `<html>` keeps the three rules
|
|
574
|
+
that style bare `input`/`select`/`textarea` and scrollbars off your own markup.
|
|
575
|
+
|
|
576
|
+
Your `@theme` wins whichever side of the import it is on (the kit's is
|
|
577
|
+
`@theme default`). Your `:root` and dark overrides of the kit's TOKENS are plain
|
|
578
|
+
declarations, where source order decides, so import the kit first:
|
|
579
|
+
|
|
580
|
+
```css
|
|
581
|
+
@import "tailwindcss";
|
|
582
|
+
@import "efficient-shell/ui.css";
|
|
583
|
+
/* your @theme and :root blocks after this line */
|
|
584
|
+
```
|
|
585
|
+
|
|
586
|
+
**Palette.** Kit components paint with Tailwind palette utilities, which
|
|
587
|
+
compile to `var(--color-<family>-<step>)`, so `@theme` reaches them. The
|
|
588
|
+
families the kit uses: **gray** (nearly all chrome: surfaces, borders, text),
|
|
589
|
+
**blue** (the accent: primary buttons, links, selection, the chosen tab),
|
|
590
|
+
**red** (danger and invalid), **green** (success), **amber** and **yellow**
|
|
591
|
+
(warning), one **emerald** and one **neutral** (a template's sparkline,
|
|
592
|
+
BrandMark's dark plate), plus `white` and `black`. Status badges and charts read
|
|
593
|
+
their own tokens (`--status-*`, `--viz-*`, `--rosh-donut-*`) rather than the palette.
|
|
594
|
+
|
|
595
|
+
```css
|
|
596
|
+
@theme {
|
|
597
|
+
/* a neutral gray ramp, and a near-black primary */
|
|
598
|
+
--color-gray-50: oklch(98.5% 0 0); /* … through --color-gray-950 */
|
|
599
|
+
--color-blue-600: oklch(20.5% 0 0); /* the primary Button's fill */
|
|
600
|
+
--color-blue-700: oklch(14.5% 0 0); /* its hover */
|
|
601
|
+
}
|
|
602
|
+
```
|
|
603
|
+
|
|
604
|
+
**Accent, picked at runtime.** `applyThemePrefs({ accent_color })` (or
|
|
605
|
+
`useTheme`) stamps `data-custom-accent` on `<html>` and the `--accent-50` …
|
|
606
|
+
`--accent-700` scale inline; `themes.css` then remaps the blue accent utilities
|
|
607
|
+
to that scale, and the timeline, `SidebarLayout`'s resize handle and the accent
|
|
608
|
+
focus ring follow it. A host can stamp the same attribute and scale itself. For
|
|
609
|
+
a fixed brand colour, `@theme` above is simpler.
|
|
610
|
+
|
|
611
|
+
**The accent in dark.** Dark mode paints the blue utilities from four channel
|
|
612
|
+
tokens, not from the palette: `--rosh-dark-accent-rgb` (washes, borders,
|
|
613
|
+
selection), `--rosh-dark-accent-line-rgb`, `--rosh-dark-accent-ink-rgb` (accent
|
|
614
|
+
text) and `--rosh-dark-accent-ink-strong-rgb`. Each is three comma-separated
|
|
615
|
+
channels, defaulting to blue-500 / 400 / 300 / 200. A host that maps
|
|
616
|
+
`--color-blue-*` for light sets these too, or its accent turns blue at night:
|
|
617
|
+
|
|
618
|
+
```css
|
|
619
|
+
:root { --rosh-dark-accent-rgb: 230, 230, 230; --rosh-dark-accent-line-rgb: 230, 230, 230;
|
|
620
|
+
--rosh-dark-accent-ink-rgb: 230, 230, 230; --rosh-dark-accent-ink-strong-rgb: 230, 230, 230; }
|
|
621
|
+
```
|
|
622
|
+
|
|
623
|
+
**The neutral roles.** Twelve tokens, declared for light on `:root` and for dark
|
|
624
|
+
under `:is([data-theme="dark"], .dark)`: `--surface`, `--surface-sunken`, `--surface-raised`,
|
|
625
|
+
`--line-subtle`, `--line`, `--line-strong`, `--ink-faintest`, `--ink-faint`,
|
|
626
|
+
`--ink-muted`, `--ink`, `--ink-strong`, `--ink-strongest`. Dark mode's remaps,
|
|
627
|
+
the timeline card and the frosted glass read them.
|
|
628
|
+
|
|
629
|
+
```css
|
|
630
|
+
:root { --surface: #ffffff; --line: oklch(92.2% 0 0); --ink-strongest: oklch(14.5% 0 0); }
|
|
631
|
+
:is([data-theme="dark"], .dark) { --surface: oklch(14.5% 0 0); --line: oklch(26.9% 0 0); }
|
|
632
|
+
```
|
|
633
|
+
|
|
634
|
+
**Focus.** Kit controls ring on `:focus-visible`, so a button does not ring
|
|
635
|
+
when it is clicked and a text field does (it takes typing, so the browser shows
|
|
636
|
+
where the caret went). The ring colours are tokens; each default is the
|
|
637
|
+
Tailwind colour the kit always drew:
|
|
638
|
+
|
|
639
|
+
| Token | Default | Where |
|
|
640
|
+
|---|---|---|
|
|
641
|
+
| `--rosh-focus-ring` | blue-400 at 30% | fields, outlined and quiet buttons, Checkbox, Radio |
|
|
642
|
+
| `--rosh-focus-ring-strong` | blue-400 at 40% | primary Button, Switch, TileButton, a badge's close |
|
|
643
|
+
| `--rosh-focus-ring-solid` | blue-400 | edgeless controls: a dialog's close, calendar days, table rows, crumbs, steps |
|
|
644
|
+
| `--rosh-focus-ring-deep` | blue-500 | charts (plot, legend), a chip's remove, the date-range field |
|
|
645
|
+
| `--rosh-focus-ring-accent` | blue-500, follows the accent | HelpCenter's search, the prompt dialog's field |
|
|
646
|
+
| `--rosh-focus-ring-zone` | `rgba(59,130,246,.45)` | upload zones and thumbnails |
|
|
647
|
+
| `--rosh-focus-ring-invalid` | red-400 at 30% | an invalid field, `ghost-danger` |
|
|
648
|
+
| `--rosh-focus-ring-invalid-strong` | red-400 at 40% | the `danger` Button |
|
|
649
|
+
| `--rosh-focus-ring-invalid-solid` | red-400 | `FormErrorSummary` |
|
|
650
|
+
|
|
651
|
+
To give the whole app **one** focus treatment, hand focus to the host: put
|
|
652
|
+
`rosh-host-focus` on `<html>` (or on any ancestor of the kit). The kit then
|
|
653
|
+
draws no ring and no outline of its own and removes nothing, so your rule is
|
|
654
|
+
what every kit control shows — including one in `@layer base`, which the kit
|
|
655
|
+
outranks otherwise:
|
|
656
|
+
|
|
657
|
+
```html
|
|
658
|
+
<html class="rosh-host-focus">
|
|
659
|
+
```
|
|
660
|
+
|
|
661
|
+
```css
|
|
662
|
+
@layer base {
|
|
663
|
+
:where(a, button, input, select, textarea, summary, [role="button"], [role="tab"],
|
|
664
|
+
[tabindex]:not([tabindex="-1"])):focus-visible {
|
|
665
|
+
outline: 2px solid var(--ring);
|
|
666
|
+
outline-offset: 2px;
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
```
|
|
670
|
+
|
|
671
|
+
A class rather than a token, because no token value can give an outline back:
|
|
672
|
+
the kit takes the browser's outline off its controls while it draws a ring, and
|
|
673
|
+
only a selector that stops matching can stop that. A focused text field still
|
|
674
|
+
changes its border colour (`focus:border-blue-400`): that is the field's edge,
|
|
675
|
+
so the palette above governs it.
|
|
676
|
+
|
|
677
|
+
**Radius and type.** `ui.css` declares `--radius-sm` … `--radius-2xl`,
|
|
678
|
+
`--font-sans` and `--font-mono` as `@theme default`; declare your own anywhere. Bare
|
|
679
|
+
`rounded` and `rounded-full` (pills, switches, avatars, badges) compile to fixed
|
|
680
|
+
values unless you name `--radius` and `--radius-full` too. A few kit component
|
|
681
|
+
classes in `ui.css` (the timeline card's) carry pixel radii of their own.
|
|
682
|
+
|
|
683
|
+
```css
|
|
684
|
+
@theme {
|
|
685
|
+
--radius: 0; --radius-sm: 0; --radius-md: 0; --radius-lg: 0; --radius-xl: 0; --radius-2xl: 0;
|
|
686
|
+
--font-sans: "Inter", ui-sans-serif, system-ui, sans-serif;
|
|
687
|
+
}
|
|
688
|
+
```
|
|
689
|
+
|
|
690
|
+
**Glass.** Menus, popups, listboxes and tooltips are frosted glass
|
|
691
|
+
(`glassStyle()`). `--menu-opacity` (0–1, default `0.95`) sets how much shows
|
|
692
|
+
through. `rosh-reduce-transparency` on `<html>` makes every popup one solid
|
|
693
|
+
`--rosh-glass-surface` (default: `--surface`) with no blur — and strips
|
|
694
|
+
`backdrop-filter` from everything else on the page too, since it is the user's
|
|
695
|
+
"Reduce transparency" preference. The frosted look itself is
|
|
696
|
+
`--rosh-glass-surface`, `--rosh-glass-surface-mid`, `--rosh-glass-border` and
|
|
697
|
+
`--rosh-glass-shadow`; the solid one adds `--rosh-glass-solid-border` and
|
|
698
|
+
`--rosh-glass-solid-shadow`. All have light and dark values.
|
|
699
|
+
|
|
700
|
+
```css
|
|
701
|
+
:root { --rosh-glass-surface: var(--popover); --rosh-glass-solid-shadow: 0 4px 12px rgb(0 0 0 / 0.08); }
|
|
702
|
+
```
|
|
703
|
+
|
|
704
|
+
**Everything else** a kit component paints, each defaulting to the literal it
|
|
705
|
+
replaced: `--rosh-media-scrim` and `--rosh-media-scrim-button` (the dark wash
|
|
706
|
+
under text and buttons on an upload thumbnail), `--rosh-drop-ring` (the halo
|
|
707
|
+
while a file is dragged over a gallery), `--rosh-mark-plate-shadow` and
|
|
708
|
+
`--rosh-mark-plate-shadow-strong` (`BrandMark`'s plates), `--rosh-resize-handle`
|
|
709
|
+
(`SidebarLayout`'s handle without a custom accent), and `--rosh-donut-1` …
|
|
710
|
+
`--rosh-donut-8` with `--rosh-donut-track` (`DonutChart`'s default palette —
|
|
711
|
+
point them at `--viz-series-*` for one palette across every chart). The chart
|
|
712
|
+
palette (`--viz-*`), the status tiers (`--status-*`) and the timeline
|
|
713
|
+
(`--tl-*`) are documented where `ui.css` declares them.
|
|
714
|
+
|
|
715
|
+
### Languages, dates and numbers — `ShellStringsProvider`
|
|
716
|
+
|
|
717
|
+
Every word the kit draws on its own account — a dialog's "Close", a pager's
|
|
718
|
+
"Previous page", a chart's tooltip rows, a calendar's "Next month", an upload
|
|
719
|
+
zone's refusal — comes from one typed catalog. With no provider the catalog is
|
|
720
|
+
American English and the markup is exactly what it has always been. Mount the
|
|
721
|
+
provider once, near the top of the app, with whatever you translate:
|
|
722
|
+
|
|
723
|
+
```tsx
|
|
724
|
+
import { ShellStringsProvider, type ShellStringsOverride } from 'efficient-shell/ui';
|
|
725
|
+
|
|
726
|
+
// Your own catalog, your own plural rules — the kit asks for nothing else.
|
|
727
|
+
function kitStrings(t: (key: string, values?: object) => string): ShellStringsOverride {
|
|
728
|
+
return {
|
|
729
|
+
dialog: {
|
|
730
|
+
close: t('kit.close'), cancel: t('kit.cancel'), ok: t('kit.ok'),
|
|
731
|
+
// Word order is the translation's: the kit draws the <kbd> wherever
|
|
732
|
+
// the sentence puts the word.
|
|
733
|
+
typeToConfirm: word => t('kit.typeToConfirm', { word }),
|
|
734
|
+
},
|
|
735
|
+
pagination: { previous: t('kit.previousPage'), next: t('kit.nextPage') },
|
|
736
|
+
// A sentence with a value in it is a function. Counts arrive as numbers,
|
|
737
|
+
// so a plural rule can choose the words: "1 запись", "5 записей".
|
|
738
|
+
list: {
|
|
739
|
+
allLoaded: (total, label) => t('kit.allLoaded', { total, label }),
|
|
740
|
+
loadedOf: (loaded, total, label) => t('kit.loadedOf', { loaded, total, label }),
|
|
741
|
+
},
|
|
742
|
+
};
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
<ShellStringsProvider value={kitStrings(t)} locale="de-DE">
|
|
746
|
+
<App />
|
|
747
|
+
</ShellStringsProvider>
|
|
748
|
+
```
|
|
749
|
+
|
|
750
|
+
**How the catalog merges.** `value` is a partial: per section, keys you leave
|
|
751
|
+
out keep their English default, so a catalog that falls behind a release still
|
|
752
|
+
works. A prop on the component (`emptyText`, `placeholder`, `label`,
|
|
753
|
+
`emptyLabel`, a chart's `formatValue`) always wins over the catalog — the
|
|
754
|
+
catalog replaces the kit's defaults, never your words. A nested provider's
|
|
755
|
+
`value` merges onto the English defaults, not onto its parent's.
|
|
756
|
+
|
|
757
|
+
**Sentences are functions, deliberately not templates.** The catalog is not an
|
|
758
|
+
i18n library: no message syntax, no plural rules. An entry that carries a value
|
|
759
|
+
is a plain function, and you write it with whatever you already use. Two rules
|
|
760
|
+
make the arguments predictable:
|
|
761
|
+
|
|
762
|
+
- a **count** arrives as a `number`, unformatted, because the words depend on it
|
|
763
|
+
— format it yourself (the English defaults format it in the provider's
|
|
764
|
+
`locale`);
|
|
765
|
+
- a **value the kit has already written** — a date, a file size, the output of
|
|
766
|
+
your own `formatValue` — arrives as the `string` that will be printed.
|
|
767
|
+
|
|
768
|
+
Three older entries are halves the kit concatenates (`select.remove` before a
|
|
769
|
+
chip's label, `pageTabs.close` before a tab's title, a count before
|
|
770
|
+
`pageTabs.discardMany`). They still work; each now has an optional
|
|
771
|
+
whole-sentence function beside it (`select.removeItem`, `pageTabs.closeTab`,
|
|
772
|
+
`pageTabs.discardCount`) that wins when you supply it, for a language whose
|
|
773
|
+
word order a concatenation cannot express.
|
|
774
|
+
|
|
775
|
+
**`locale` — how dates and numbers are written.** A BCP 47 tag. With one:
|
|
776
|
+
|
|
777
|
+
- `Calendar`, `DatePicker` and `DateRangePicker` take month and weekday names —
|
|
778
|
+
and the full date each day is announced as — from `Intl.DateTimeFormat` in
|
|
779
|
+
that locale (`Oktober`, `Mo.`, `2026年10月2日`). The calendar is always
|
|
780
|
+
Gregorian, whatever the locale's default.
|
|
781
|
+
- `DatePicker native`, `DateTimePicker` and `TimePicker` are drawn by the
|
|
782
|
+
browser, so they get the locale the one way they can: a `lang` attribute.
|
|
783
|
+
- `formatDate`, and the timelines' dates, are written by `Intl` in the locale
|
|
784
|
+
(`dateStyle: 'medium'` by default). The stored `user_date_format` is not read
|
|
785
|
+
— a locale is the host saying how dates read for everyone it serves.
|
|
786
|
+
- Numbers the kit formats itself use `Intl.NumberFormat` in the locale: list
|
|
787
|
+
footers, page numbers, `Statistic`, `CountBadge`, chart axes, tooltips,
|
|
788
|
+
percentages and the meters (`1.234,5`, `37,5 %`).
|
|
789
|
+
|
|
790
|
+
With no `locale` — no provider, or a provider that only translates strings —
|
|
791
|
+
nothing changes: the same English month names, `DD/MM/YYYY` from the stored
|
|
792
|
+
setting, `toLocaleString()` with no argument, `String(v)`. Mounting the provider
|
|
793
|
+
for its strings alone moves no digit. A nested provider without a `locale`
|
|
794
|
+
keeps its parent's; a malformed tag (`en_US`) is reported once on the console
|
|
795
|
+
and ignored rather than thrown in render. Which day a week starts on is still
|
|
796
|
+
`weekStartsOn`, not the locale's to change. `InputNumber` keeps a `.` decimal in
|
|
797
|
+
the field, because what is typed there is parsed back.
|
|
798
|
+
|
|
799
|
+
`useShellLocale()` reads the tag for your own cells — pass it on as
|
|
800
|
+
`formatDate(value, { locale, style })` or `fmtSliderDate(ms, locale)`, or hand it
|
|
801
|
+
to `Intl` directly — so a host's dates and numbers read like the kit's.
|
|
802
|
+
|
|
803
|
+
**What is not in the catalog, on purpose:** month and weekday names (the
|
|
804
|
+
`locale` supplies them); file-format names in `BrandAssetEditor`'s default
|
|
805
|
+
`acceptHint` and the `20ft`/`40ft` container codes (notation, not language); the
|
|
806
|
+
`Kbd` shortcut constants (key symbols); `STAGES` labels (data a consumer's own
|
|
807
|
+
tables read); the sample content of the starter templates (`DashboardTemplate`,
|
|
808
|
+
`AuthScreen` and the rest are demos to copy, not components to configure); and
|
|
809
|
+
console warnings, which are for developers.
|
|
810
|
+
|
|
811
|
+
**The full catalog** — 39 sections, 359 keys. A function's default is shown
|
|
812
|
+
with sample arguments.
|
|
813
|
+
|
|
814
|
+
<details><summary><code>window</code> — 17 keys</summary>
|
|
815
|
+
|
|
816
|
+
| Key | Type | English default |
|
|
817
|
+
|---|---|---|
|
|
818
|
+
| `minimize` | `string` | `Minimize` |
|
|
819
|
+
| `restore` | `string` | `Restore` |
|
|
820
|
+
| `maximize` | `string` | `Maximize` |
|
|
821
|
+
| `windowed` | `string` | `Windowed` |
|
|
822
|
+
| `pinOnTop` | `string` | `Pin on top` |
|
|
823
|
+
| `unpin` | `string` | `Unpin from top` |
|
|
824
|
+
| `close` | `string` | `Close` |
|
|
825
|
+
| `windowSuffix` | `string` | `window` |
|
|
826
|
+
| `prev` | `string` | `Prev` |
|
|
827
|
+
| `next` | `string` | `Next` |
|
|
828
|
+
| `snapLayouts` | `string` | `Snap layouts` |
|
|
829
|
+
| `snapLeft` | `string` | `Snap left half` |
|
|
830
|
+
| `snapRight` | `string` | `Snap right half` |
|
|
831
|
+
| `snapTopLeft` | `string` | `Snap top-left quarter` |
|
|
832
|
+
| `snapTopRight` | `string` | `Snap top-right quarter` |
|
|
833
|
+
| `snapBottomLeft` | `string` | `Snap bottom-left quarter` |
|
|
834
|
+
| `snapBottomRight` | `string` | `Snap bottom-right quarter` |
|
|
835
|
+
|
|
836
|
+
</details>
|
|
837
|
+
|
|
838
|
+
<details><summary><code>taskbar</code> — 9 keys</summary>
|
|
839
|
+
|
|
840
|
+
| Key | Type | English default |
|
|
841
|
+
|---|---|---|
|
|
842
|
+
| `closeWindow` | `string` | `Close window` |
|
|
843
|
+
| `offscreenHint` | `string` | `This window is off screen — click to bring it back` |
|
|
844
|
+
| `offscreenDot` | `string` | `Off screen — click to bring this window back` |
|
|
845
|
+
| `expose` | `string` | `Exposé — show all open windows as thumbnails` |
|
|
846
|
+
| `addToDesktop` | `string` | `Add to desktop` |
|
|
847
|
+
| `removeFromDesktop` | `string` | `Remove from desktop` |
|
|
848
|
+
| `minimizeAllWindows` | `string` | `Minimize all` |
|
|
849
|
+
| `restoreAllWindows` | `string` | `Restore all` |
|
|
850
|
+
| `closeAllWindows` | `string` | `Close all` |
|
|
851
|
+
|
|
852
|
+
</details>
|
|
853
|
+
|
|
854
|
+
<details><summary><code>logout</code> — 2 keys</summary>
|
|
855
|
+
|
|
856
|
+
| Key | Type | English default |
|
|
857
|
+
|---|---|---|
|
|
858
|
+
| `goodbye` | `string` | `Goodbye` |
|
|
859
|
+
| `seeYou` | `string` | `See you next time` |
|
|
860
|
+
|
|
861
|
+
</details>
|
|
862
|
+
|
|
863
|
+
<details><summary><code>about</code> — 5 keys</summary>
|
|
864
|
+
|
|
865
|
+
| Key | Type | English default |
|
|
866
|
+
|---|---|---|
|
|
867
|
+
| `aboutPrefix` | `string` | `About` |
|
|
868
|
+
| `thisApp` | `string` | `this app` |
|
|
869
|
+
| `openSourceLicenses` | `string` | `Open Source Licenses` |
|
|
870
|
+
| `whatsNew` | `string` | `What's New` |
|
|
871
|
+
| `noChangelog` | `string` | `No changelog available.` |
|
|
872
|
+
|
|
873
|
+
</details>
|
|
874
|
+
|
|
875
|
+
<details><summary><code>table</code> — 4 keys</summary>
|
|
876
|
+
|
|
877
|
+
| Key | Type | English default |
|
|
878
|
+
|---|---|---|
|
|
879
|
+
| `empty` | `string` | `Nothing to show` |
|
|
880
|
+
| `loading` | `string` | `Loading` |
|
|
881
|
+
| `selectAll` | `string` | `Select all rows` |
|
|
882
|
+
| `selectRow` | `string` | `Select row` |
|
|
883
|
+
|
|
884
|
+
</details>
|
|
885
|
+
|
|
886
|
+
<details><summary><code>select</code> — 6 keys</summary>
|
|
887
|
+
|
|
888
|
+
| Key | Type | English default |
|
|
889
|
+
|---|---|---|
|
|
890
|
+
| `none` | `string` | `— None —` |
|
|
891
|
+
| `noMatches` | `string` | `No matches` |
|
|
892
|
+
| `allSelected` | `string` | `All options selected` |
|
|
893
|
+
| `clear` | `string` | `Clear selection` |
|
|
894
|
+
| `remove` | `string` | `Remove` |
|
|
895
|
+
| `removeItem?` | `(label: string) => string` | *(none — the older halves are concatenated)* |
|
|
896
|
+
|
|
897
|
+
</details>
|
|
898
|
+
|
|
899
|
+
<details><summary><code>notifications</code> — 9 keys</summary>
|
|
900
|
+
|
|
901
|
+
| Key | Type | English default |
|
|
902
|
+
|---|---|---|
|
|
903
|
+
| `title` | `string` | `Notifications` |
|
|
904
|
+
| `markAllRead` | `string` | `Mark all read` |
|
|
905
|
+
| `dnd` | `string` | `Do not disturb` |
|
|
906
|
+
| `dndOn` | `string` | `Do not disturb is on` |
|
|
907
|
+
| `caughtUp` | `string` | `All caught up` |
|
|
908
|
+
| `empty` | `string` | `No notifications yet` |
|
|
909
|
+
| `viewAll` | `string` | `View all notifications` |
|
|
910
|
+
| `cardLabel` | `string` | `Notification` |
|
|
911
|
+
| `dismiss` | `string` | `Dismiss notification` |
|
|
912
|
+
|
|
913
|
+
</details>
|
|
914
|
+
|
|
915
|
+
<details><summary><code>form</code> — 1 keys</summary>
|
|
916
|
+
|
|
917
|
+
| Key | Type | English default |
|
|
918
|
+
|---|---|---|
|
|
919
|
+
| `errorSummaryTitle` | `string` | `There is a problem` |
|
|
920
|
+
|
|
921
|
+
</details>
|
|
922
|
+
|
|
923
|
+
<details><summary><code>help</code> — 10 keys</summary>
|
|
924
|
+
|
|
925
|
+
| Key | Type | English default |
|
|
926
|
+
|---|---|---|
|
|
927
|
+
| `title` | `string` | `Help` |
|
|
928
|
+
| `searchPlaceholder` | `string` | `Search help…` |
|
|
929
|
+
| `empty` | `string` | `No help articles yet.` |
|
|
930
|
+
| `noResults` | `string` | `No articles match your search.` |
|
|
931
|
+
| `loading` | `string` | `Loading…` |
|
|
932
|
+
| `pickArticle` | `string` | `Pick a help article from the left.` |
|
|
933
|
+
| `noBody` | `string` | `This article has no body yet.` |
|
|
934
|
+
| `draft` | `string` | `Draft` |
|
|
935
|
+
| `newArticle` | `string` | `+ New` |
|
|
936
|
+
| `edit` | `string` | `Edit` |
|
|
937
|
+
|
|
938
|
+
</details>
|
|
939
|
+
|
|
940
|
+
<details><summary><code>update</code> — 2 keys</summary>
|
|
941
|
+
|
|
942
|
+
| Key | Type | English default |
|
|
943
|
+
|---|---|---|
|
|
944
|
+
| `available` | `string` | `A new version is available.` |
|
|
945
|
+
| `refreshNow` | `string` | `Refresh now` |
|
|
946
|
+
|
|
947
|
+
</details>
|
|
948
|
+
|
|
949
|
+
<details><summary><code>pageTabs</code> — 13 keys</summary>
|
|
950
|
+
|
|
951
|
+
| Key | Type | English default |
|
|
952
|
+
|---|---|---|
|
|
953
|
+
| `label` | `string` | `Open pages` |
|
|
954
|
+
| `close` | `string` | `Close` |
|
|
955
|
+
| `closeTab?` | `(title: string) => string` | *(none — the older halves are concatenated)* |
|
|
956
|
+
| `closeOthers` | `string` | `Close other tabs` |
|
|
957
|
+
| `closeRight` | `string` | `Close tabs to the right` |
|
|
958
|
+
| `closeAll` | `string` | `Close all tabs` |
|
|
959
|
+
| `unsaved` | `string` | `Unsaved changes` |
|
|
960
|
+
| `discardTitle` | `string` | `Discard unsaved changes?` |
|
|
961
|
+
| `discardOne` | `string` | `This page has changes that have not been saved. Close it anyway?` |
|
|
962
|
+
| `discardMany` | `string` | `pages have changes that have not been saved. Close them anyway?` |
|
|
963
|
+
| `discardCount?` | `(count: number) => string` | *(none — the older halves are concatenated)* |
|
|
964
|
+
| `discardConfirm` | `string` | `Discard and close` |
|
|
965
|
+
| `keepEditing` | `string` | `Keep editing` |
|
|
966
|
+
|
|
967
|
+
</details>
|
|
968
|
+
|
|
969
|
+
<details><summary><code>dialog</code> — 9 keys</summary>
|
|
970
|
+
|
|
971
|
+
| Key | Type | English default |
|
|
972
|
+
|---|---|---|
|
|
973
|
+
| `close` | `string` | `Close` |
|
|
974
|
+
| `cancel` | `string` | `Cancel` |
|
|
975
|
+
| `ok` | `string` | `OK` |
|
|
976
|
+
| `confirmTitle` | `string` | `Confirm` |
|
|
977
|
+
| `destructiveTitle` | `string` | `Confirm Action` |
|
|
978
|
+
| `destructiveCancel` | `string` | `Dismiss` |
|
|
979
|
+
| `destructiveConfirm` | `string` | `Delete` |
|
|
980
|
+
| `typeToConfirm` | `(word: string) => string` | `Type {word} to confirm:` |
|
|
981
|
+
| `promptTitle` | `string` | `Enter a value` |
|
|
982
|
+
|
|
983
|
+
</details>
|
|
984
|
+
|
|
985
|
+
<details><summary><code>calendar</code> — 10 keys</summary>
|
|
986
|
+
|
|
987
|
+
| Key | Type | English default |
|
|
988
|
+
|---|---|---|
|
|
989
|
+
| `previousMonth` | `string` | `Previous month` |
|
|
990
|
+
| `nextMonth` | `string` | `Next month` |
|
|
991
|
+
| `previousYear` | `string` | `Previous year` |
|
|
992
|
+
| `nextYear` | `string` | `Next year` |
|
|
993
|
+
| `previousYears` | `string` | `Previous years` |
|
|
994
|
+
| `nextYears` | `string` | `Next years` |
|
|
995
|
+
| `monthPanel` | `string` | `Choose a month` |
|
|
996
|
+
| `yearPanel` | `string` | `Choose a year` |
|
|
997
|
+
| `chooseMonth` | `(month: string) => string` | `Choose a month, currently {month}` |
|
|
998
|
+
| `chooseYear` | `(year: number) => string` | `Choose a year, currently 2026` |
|
|
999
|
+
|
|
1000
|
+
</details>
|
|
1001
|
+
|
|
1002
|
+
<details><summary><code>datePicker</code> — 4 keys</summary>
|
|
1003
|
+
|
|
1004
|
+
| Key | Type | English default |
|
|
1005
|
+
|---|---|---|
|
|
1006
|
+
| `placeholder` | `string` | `Select a date` |
|
|
1007
|
+
| `dialog` | `string` | `Choose a date` |
|
|
1008
|
+
| `clear` | `string` | `Clear` |
|
|
1009
|
+
| `today` | `string` | `Today` |
|
|
1010
|
+
|
|
1011
|
+
</details>
|
|
1012
|
+
|
|
1013
|
+
<details><summary><code>dateRange</code> — 18 keys</summary>
|
|
1014
|
+
|
|
1015
|
+
| Key | Type | English default |
|
|
1016
|
+
|---|---|---|
|
|
1017
|
+
| `placeholder` | `string` | `Date Range` |
|
|
1018
|
+
| `clearRange` | `string` | `Clear date range` |
|
|
1019
|
+
| `dialog` | `string` | `Date range` |
|
|
1020
|
+
| `from` | `string` | `From` |
|
|
1021
|
+
| `to` | `string` | `To` |
|
|
1022
|
+
| `start` | `string` | `Start` |
|
|
1023
|
+
| `end` | `string` | `End` |
|
|
1024
|
+
| `fromOnly` | `(date: string) => string` | `From {date}` |
|
|
1025
|
+
| `toOnly` | `(date: string) => string` | `To {date}` |
|
|
1026
|
+
| `last2Weeks` | `string` | `Last 2 Weeks` |
|
|
1027
|
+
| `lastMonth` | `string` | `Last Month` |
|
|
1028
|
+
| `last3Months` | `string` | `Last 3 Months` |
|
|
1029
|
+
| `last6Months` | `string` | `Last 6 Months` |
|
|
1030
|
+
| `last12Months` | `string` | `Last 12 Months` |
|
|
1031
|
+
| `custom` | `string` | `Custom` |
|
|
1032
|
+
| `clear` | `string` | `Clear` |
|
|
1033
|
+
| `cancel` | `string` | `Cancel` |
|
|
1034
|
+
| `apply` | `string` | `Apply` |
|
|
1035
|
+
|
|
1036
|
+
</details>
|
|
1037
|
+
|
|
1038
|
+
<details><summary><code>pagination</code> — 5 keys</summary>
|
|
1039
|
+
|
|
1040
|
+
| Key | Type | English default |
|
|
1041
|
+
|---|---|---|
|
|
1042
|
+
| `label` | `string` | `Pagination` |
|
|
1043
|
+
| `first` | `string` | `First page` |
|
|
1044
|
+
| `previous` | `string` | `Previous page` |
|
|
1045
|
+
| `next` | `string` | `Next page` |
|
|
1046
|
+
| `last` | `string` | `Last page` |
|
|
1047
|
+
|
|
1048
|
+
</details>
|
|
1049
|
+
|
|
1050
|
+
<details><summary><code>list</code> — 8 keys</summary>
|
|
1051
|
+
|
|
1052
|
+
| Key | Type | English default |
|
|
1053
|
+
|---|---|---|
|
|
1054
|
+
| `selected` | `(count: number) => string` | `3 selected` |
|
|
1055
|
+
| `allLoaded` | `(total: number, label: string) => string` | `All 3 {label} loaded` |
|
|
1056
|
+
| `count` | `(total: number, label: string) => string` | `3 {label}` |
|
|
1057
|
+
| `loadedOf` | `(loaded: number, total: number, label: string) => string` | `3 of 3 {label}` |
|
|
1058
|
+
| `loadingMore` | `string` | `Loading more...` |
|
|
1059
|
+
| `loadError` | `string` | `Couldn't load this list` |
|
|
1060
|
+
| `loadErrorMessage` | `string` | `Something went wrong fetching these records. Check your connection and try again.` |
|
|
1061
|
+
| `retry` | `string` | `Try again` |
|
|
1062
|
+
|
|
1063
|
+
</details>
|
|
1064
|
+
|
|
1065
|
+
<details><summary><code>kanban</code> — 4 keys</summary>
|
|
1066
|
+
|
|
1067
|
+
| Key | Type | English default |
|
|
1068
|
+
|---|---|---|
|
|
1069
|
+
| `loading` | `string` | `Loading…` |
|
|
1070
|
+
| `empty` | `string` | `No items.` |
|
|
1071
|
+
| `dropHere` | `string` | `Drop here` |
|
|
1072
|
+
| `addItem` | `string` | `Add item` |
|
|
1073
|
+
|
|
1074
|
+
</details>
|
|
1075
|
+
|
|
1076
|
+
<details><summary><code>files</code> — 13 keys</summary>
|
|
1077
|
+
|
|
1078
|
+
| Key | Type | English default |
|
|
1079
|
+
|---|---|---|
|
|
1080
|
+
| `attach` | `string` | `Attach files` |
|
|
1081
|
+
| `drop` | `string` | `Drop files to attach` |
|
|
1082
|
+
| `remove` | `(name: string) => string` | `Remove {name}` |
|
|
1083
|
+
| `chooseMany` | `string` | `Choose files` |
|
|
1084
|
+
| `chooseOne` | `string` | `Choose a file` |
|
|
1085
|
+
| `dragMany` | `string` | `or drag them here` |
|
|
1086
|
+
| `dragOne` | `string` | `or drag it here` |
|
|
1087
|
+
| `notAccepted` | `(name: string, hint: string) => string` | `{name} is not an accepted file type ({hint})` |
|
|
1088
|
+
| `tooLarge` | `(name: string, size: string, limit: string) => string` | `{name} is {size} — the limit is {limit}` |
|
|
1089
|
+
| `tooMany` | `(name: string, max: number) => string` | `{name} was not added — 3 files is the limit` |
|
|
1090
|
+
| `bytes` | `(value: number) => string` | `3 B` |
|
|
1091
|
+
| `kilobytes` | `(value: number) => string` | `3 KB` |
|
|
1092
|
+
| `megabytes` | `(value: number) => string` | `3.0 MB` |
|
|
1093
|
+
|
|
1094
|
+
</details>
|
|
1095
|
+
|
|
1096
|
+
<details><summary><code>media</code> — 14 keys</summary>
|
|
1097
|
+
|
|
1098
|
+
| Key | Type | English default |
|
|
1099
|
+
|---|---|---|
|
|
1100
|
+
| `uploadImage` | `string` | `Upload an image` |
|
|
1101
|
+
| `uploadVideo` | `string` | `Upload a video` |
|
|
1102
|
+
| `uploadFile` | `string` | `Upload a file` |
|
|
1103
|
+
| `upload` | `string` | `Upload media` |
|
|
1104
|
+
| `cta` | `string` | `Choose from library or upload` |
|
|
1105
|
+
| `replace` | `string` | `Replace` |
|
|
1106
|
+
| `remove` | `string` | `Remove` |
|
|
1107
|
+
| `uploading` | `string` | `Uploading…` |
|
|
1108
|
+
| `cover` | `string` | `Cover` |
|
|
1109
|
+
| `add` | `string` | `Add` |
|
|
1110
|
+
| `addMedia` | `string` | `Add media` |
|
|
1111
|
+
| `empty` | `string` | `No media.` |
|
|
1112
|
+
| `removeItem` | `(name: string) => string` | `Remove {name}` |
|
|
1113
|
+
| `reorder` | `(name: string, position: number, total: number) => string` | `{name}, item 2 of 3. Use arrow keys to reorder.` |
|
|
1114
|
+
|
|
1115
|
+
</details>
|
|
1116
|
+
|
|
1117
|
+
<details><summary><code>brandAsset</code> — 10 keys</summary>
|
|
1118
|
+
|
|
1119
|
+
| Key | Type | English default |
|
|
1120
|
+
|---|---|---|
|
|
1121
|
+
| `save` | `(noun: string, assetName: string) => string` | `Save {noun}` |
|
|
1122
|
+
| `remove` | `(noun: string, assetName: string) => string` | `Remove {noun}` |
|
|
1123
|
+
| `discard` | `string` | `Discard change` |
|
|
1124
|
+
| `saveFailed` | `(noun: string, assetName: string) => string` | `Could not save {noun}.` |
|
|
1125
|
+
| `removeFailed` | `(noun: string, assetName: string) => string` | `Could not remove {noun}.` |
|
|
1126
|
+
| `region` | `(assetName: string, subjectName: string) => string` | `{assetName} for {subjectName}` |
|
|
1127
|
+
| `usedFor` | `(subjectName: string) => string` | `Used for {subjectName}.` |
|
|
1128
|
+
| `previews` | `(assetName: string) => string` | `{assetName} previews` |
|
|
1129
|
+
| `preview` | `string` | `Preview` |
|
|
1130
|
+
| `alt` | `(subjectName: string, assetName: string) => string` | `{subjectName} {assetName}` |
|
|
1131
|
+
|
|
1132
|
+
</details>
|
|
1133
|
+
|
|
1134
|
+
<details><summary><code>copy</code> — 5 keys</summary>
|
|
1135
|
+
|
|
1136
|
+
| Key | Type | English default |
|
|
1137
|
+
|---|---|---|
|
|
1138
|
+
| `copy` | `string` | `Copy` |
|
|
1139
|
+
| `copyLabel` | `(label: string) => string` | `Copy {label}` |
|
|
1140
|
+
| `copied` | `string` | `Copied` |
|
|
1141
|
+
| `copiedLabel` | `(label: string) => string` | `{label} copied` |
|
|
1142
|
+
| `failed` | `string` | `Could not copy to the clipboard` |
|
|
1143
|
+
|
|
1144
|
+
</details>
|
|
1145
|
+
|
|
1146
|
+
<details><summary><code>keypad</code> — 2 keys</summary>
|
|
1147
|
+
|
|
1148
|
+
| Key | Type | English default |
|
|
1149
|
+
|---|---|---|
|
|
1150
|
+
| `backspace` | `string` | `Backspace` |
|
|
1151
|
+
| `enter` | `string` | `Enter` |
|
|
1152
|
+
|
|
1153
|
+
</details>
|
|
1154
|
+
|
|
1155
|
+
<details><summary><code>banner</code> — 1 keys</summary>
|
|
1156
|
+
|
|
1157
|
+
| Key | Type | English default |
|
|
1158
|
+
|---|---|---|
|
|
1159
|
+
| `dismiss` | `string` | `Dismiss` |
|
|
1160
|
+
|
|
1161
|
+
</details>
|
|
1162
|
+
|
|
1163
|
+
<details><summary><code>badge</code> — 2 keys</summary>
|
|
1164
|
+
|
|
1165
|
+
| Key | Type | English default |
|
|
1166
|
+
|---|---|---|
|
|
1167
|
+
| `remove` | `string` | `Remove` |
|
|
1168
|
+
| `removeItem` | `(label: string) => string` | `Remove {label}` |
|
|
1169
|
+
|
|
1170
|
+
</details>
|
|
1171
|
+
|
|
1172
|
+
<details><summary><code>breadcrumbs</code> — 2 keys</summary>
|
|
1173
|
+
|
|
1174
|
+
| Key | Type | English default |
|
|
1175
|
+
|---|---|---|
|
|
1176
|
+
| `label` | `string` | `Breadcrumb` |
|
|
1177
|
+
| `hidden` | `string` | `Hidden crumbs` |
|
|
1178
|
+
|
|
1179
|
+
</details>
|
|
1180
|
+
|
|
1181
|
+
<details><summary><code>emptyState</code> — 1 keys</summary>
|
|
1182
|
+
|
|
1183
|
+
| Key | Type | English default |
|
|
1184
|
+
|---|---|---|
|
|
1185
|
+
| `message` | `string` | `Nothing here yet.` |
|
|
1186
|
+
|
|
1187
|
+
</details>
|
|
1188
|
+
|
|
1189
|
+
<details><summary><code>errors</code> — 9 keys</summary>
|
|
1190
|
+
|
|
1191
|
+
| Key | Type | English default |
|
|
1192
|
+
|---|---|---|
|
|
1193
|
+
| `notFound` | `string` | `Page not found` |
|
|
1194
|
+
| `notFoundBody` | `string` | `The page you're looking for doesn't exist or was moved.` |
|
|
1195
|
+
| `forbidden` | `string` | `Access denied` |
|
|
1196
|
+
| `forbiddenBody` | `string` | `You don't have permission to view this page.` |
|
|
1197
|
+
| `noAccess` | `string` | `You don't have access to this` |
|
|
1198
|
+
| `serverError` | `string` | `Something went wrong` |
|
|
1199
|
+
| `serverErrorBody` | `string` | `An unexpected error occurred. Please try again.` |
|
|
1200
|
+
| `retry` | `string` | `Try again` |
|
|
1201
|
+
| `details` | `string` | `Error details` |
|
|
1202
|
+
|
|
1203
|
+
</details>
|
|
1204
|
+
|
|
1205
|
+
<details><summary><code>search</code> — 10 keys</summary>
|
|
1206
|
+
|
|
1207
|
+
| Key | Type | English default |
|
|
1208
|
+
|---|---|---|
|
|
1209
|
+
| `placeholder` | `string` | `Search...` |
|
|
1210
|
+
| `escBadge` | `string` | `ESC` |
|
|
1211
|
+
| `searching` | `string` | `Searching...` |
|
|
1212
|
+
| `noResults` | `string` | `No results found.` |
|
|
1213
|
+
| `minChars` | `(min: number) => string` | `Type at least 3 characters to search...` |
|
|
1214
|
+
| `navigate` | `string` | `navigate` |
|
|
1215
|
+
| `open` | `string` | `open` |
|
|
1216
|
+
| `close` | `string` | `close` |
|
|
1217
|
+
| `enterKey` | `string` | `Enter` |
|
|
1218
|
+
| `escKey` | `string` | `Esc` |
|
|
1219
|
+
|
|
1220
|
+
</details>
|
|
1221
|
+
|
|
1222
|
+
<details><summary><code>grid</code> — 9 keys</summary>
|
|
1223
|
+
|
|
1224
|
+
| Key | Type | English default |
|
|
1225
|
+
|---|---|---|
|
|
1226
|
+
| `selectAll` | `string` | `Select all` |
|
|
1227
|
+
| `insertRowAbove` | `string` | `Insert row above` |
|
|
1228
|
+
| `insertRowBelow` | `string` | `Insert row below` |
|
|
1229
|
+
| `deleteRow` | `(row: number) => string` | `Delete row 4` |
|
|
1230
|
+
| `insertColumnLeft` | `string` | `Insert column left` |
|
|
1231
|
+
| `insertColumnRight` | `string` | `Insert column right` |
|
|
1232
|
+
| `deleteColumn` | `(column: string) => string` | `Delete column {column}` |
|
|
1233
|
+
| `resize` | `string` | `Drag to resize · double-click to auto-fit` |
|
|
1234
|
+
| `fill` | `string` | `Drag to fill` |
|
|
1235
|
+
|
|
1236
|
+
</details>
|
|
1237
|
+
|
|
1238
|
+
<details><summary><code>sidebar</code> — 1 keys</summary>
|
|
1239
|
+
|
|
1240
|
+
| Key | Type | English default |
|
|
1241
|
+
|---|---|---|
|
|
1242
|
+
| `resize` | `string` | `Drag to resize · double-click to reset` |
|
|
1243
|
+
|
|
1244
|
+
</details>
|
|
1245
|
+
|
|
1246
|
+
<details><summary><code>markdown</code> — 1 keys</summary>
|
|
1247
|
+
|
|
1248
|
+
| Key | Type | English default |
|
|
1249
|
+
|---|---|---|
|
|
1250
|
+
| `screenshot` | `string` | `Screenshot` |
|
|
1251
|
+
|
|
1252
|
+
</details>
|
|
1253
|
+
|
|
1254
|
+
<details><summary><code>severity</code> — 4 keys</summary>
|
|
1255
|
+
|
|
1256
|
+
| Key | Type | English default |
|
|
1257
|
+
|---|---|---|
|
|
1258
|
+
| `success` | `string` | `ok` |
|
|
1259
|
+
| `warning` | `string` | `warning` |
|
|
1260
|
+
| `danger` | `string` | `critical` |
|
|
1261
|
+
| `unrecognised` | `(token: string) => string` | `unrecognised severity {token}` |
|
|
1262
|
+
|
|
1263
|
+
</details>
|
|
1264
|
+
|
|
1265
|
+
<details><summary><code>meter</code> — 10 keys</summary>
|
|
1266
|
+
|
|
1267
|
+
| Key | Type | English default |
|
|
1268
|
+
|---|---|---|
|
|
1269
|
+
| `noData` | `string` | `no data` |
|
|
1270
|
+
| `warningAt` | `(bound: number) => string` | `warning ≥ 3` |
|
|
1271
|
+
| `criticalAt` | `(bound: number) => string` | `critical ≥ 3` |
|
|
1272
|
+
| `noReading` | `string` | `no reading` |
|
|
1273
|
+
| `noBudget` | `string` | `no budget` |
|
|
1274
|
+
| `ofBudget` | `(value: string) => string` | `{value} of budget` |
|
|
1275
|
+
| `budget` | `string` | `budget` |
|
|
1276
|
+
| `hoursMinutes` | `(hours: number, minutes: number) => string` | `3h 3m` |
|
|
1277
|
+
| `minutesSeconds` | `(minutes: number, seconds: number) => string` | `3m 3s` |
|
|
1278
|
+
| `seconds` | `(seconds: number) => string` | `3s` |
|
|
1279
|
+
|
|
1280
|
+
</details>
|
|
1281
|
+
|
|
1282
|
+
<details><summary><code>charts</code> — 81 keys</summary>
|
|
1283
|
+
|
|
1284
|
+
| Key | Type | English default |
|
|
1285
|
+
|---|---|---|
|
|
1286
|
+
| `showTable` | `string` | `Show the data as a table` |
|
|
1287
|
+
| `loading` | `string` | `Loading chart data` |
|
|
1288
|
+
| `noData` | `string` | `No data in this window.` |
|
|
1289
|
+
| `windowStart` | `string` | `Window start` |
|
|
1290
|
+
| `windowEnd` | `string` | `Window end` |
|
|
1291
|
+
| `window` | `(from: string, to: string, count: number) => string` | `Time window — showing {from} to {to} of 3 intervals` |
|
|
1292
|
+
| `overIntervals` | `(series: string[], count: number) => string` | `{series1}, {series2} over 3 intervals` |
|
|
1293
|
+
| `acrossCategories` | `(series: string[], count: number) => string` | `{series1}, {series2} across 3 categories` |
|
|
1294
|
+
| `acrossMeasures` | `(series: string[], count: number) => string` | `{series1}, {series2} across 3 measures` |
|
|
1295
|
+
| `breakdown` | `(total: string, segments: number) => string` | `Breakdown of {total} across 3 segments` |
|
|
1296
|
+
| `funnel` | `(stages: number, first: string, last: string) => string` | `Funnel of 3 stages, {first} down to {last}` |
|
|
1297
|
+
| `radialTrack` | `(count: number) => string` | `3 categories, as concentric proportions` |
|
|
1298
|
+
| `radialCycle` | `(count: number) => string` | `3 categories, around a cycle` |
|
|
1299
|
+
| `tableFrom` | `string` | `From` |
|
|
1300
|
+
| `tableTo` | `string` | `To` |
|
|
1301
|
+
| `tableItem` | `string` | `Item` |
|
|
1302
|
+
| `tableLevel` | `string` | `Level` |
|
|
1303
|
+
| `tableSeries` | `string` | `Series` |
|
|
1304
|
+
| `inBucket` | `(total: string) => string` | `{total} in this bucket` |
|
|
1305
|
+
| `inCategory` | `(total: string) => string` | `{total} in this category` |
|
|
1306
|
+
| `value` | `string` | `Value` |
|
|
1307
|
+
| `share` | `string` | `Share` |
|
|
1308
|
+
| `count` | `string` | `Count` |
|
|
1309
|
+
| `flow` | `string` | `Flow` |
|
|
1310
|
+
| `totalFlow` | `string` | `Total flow` |
|
|
1311
|
+
| `throughput` | `string` | `Throughput` |
|
|
1312
|
+
| `open` | `string` | `Open` |
|
|
1313
|
+
| `high` | `string` | `High` |
|
|
1314
|
+
| `low` | `string` | `Low` |
|
|
1315
|
+
| `close` | `string` | `Close` |
|
|
1316
|
+
| `maximum` | `string` | `Maximum` |
|
|
1317
|
+
| `q3` | `string` | `Q3` |
|
|
1318
|
+
| `median` | `string` | `Median` |
|
|
1319
|
+
| `q1` | `string` | `Q1` |
|
|
1320
|
+
| `minimum` | `string` | `Minimum` |
|
|
1321
|
+
| `distribution` | `string` | `Distribution` |
|
|
1322
|
+
| `fiveNumber` | `(label: string, count: number) => string` | `{label}: five-number summary for 3 categories` |
|
|
1323
|
+
| `outliers` | `(count: number) => string` | `3 outliers beyond the whiskers` |
|
|
1324
|
+
| `price` | `string` | `Price` |
|
|
1325
|
+
| `ohlc` | `(label: string, count: number) => string` | `{label}: open, high, low and close across 3 periods` |
|
|
1326
|
+
| `closedAbove` | `string` | `Closed above its open` |
|
|
1327
|
+
| `closedBelow` | `string` | `Closed below its open` |
|
|
1328
|
+
| `noFlows` | `string` | `No flows to chart.` |
|
|
1329
|
+
| `chord` | `(count: number) => string` | `Flows between 3 participants` |
|
|
1330
|
+
| `noStages` | `string` | `No stages to chart.` |
|
|
1331
|
+
| `ofFirstStage` | `string` | `Of first stage` |
|
|
1332
|
+
| `droppedHere` | `string` | `Dropped here` |
|
|
1333
|
+
| `intensity` | `string` | `Intensity` |
|
|
1334
|
+
| `noActivity` | `string` | `No activity in this window.` |
|
|
1335
|
+
| `heatmap` | `(label: string, rows: number, columns: number) => string` | `{label} across 4 rows and 3 columns` |
|
|
1336
|
+
| `countAxis` | `string` | `count` |
|
|
1337
|
+
| `histogram` | `(label: string, bins: number, observations: number) => string` | `{label}: 3 bins over 3 observations` |
|
|
1338
|
+
| `observations` | `string` | `Observations` |
|
|
1339
|
+
| `notEnough` | `string` | `Not enough eligible requests to judge.` |
|
|
1340
|
+
| `objectiveMet` | `(objective: string) => string` | `objective {objective} met` |
|
|
1341
|
+
| `objectiveMissed` | `(objective: string) => string` | `objective {objective} missed` |
|
|
1342
|
+
| `nothingToPlot` | `string` | `Nothing to plot.` |
|
|
1343
|
+
| `nothingToCompare` | `string` | `Nothing to compare.` |
|
|
1344
|
+
| `other` | `string` | `Other` |
|
|
1345
|
+
| `nothingToBreakDown` | `string` | `Nothing to break down.` |
|
|
1346
|
+
| `range` | `string` | `Range` |
|
|
1347
|
+
| `rangeLabel` | `(label: string, count: number) => string` | `{label}: low and high across 3 categories` |
|
|
1348
|
+
| `nothingToRank` | `string` | `Nothing to rank in this window.` |
|
|
1349
|
+
| `emphasised` | `string` | `(emphasised)` |
|
|
1350
|
+
| `sankey` | `(nodes: number, links: number) => string` | `Flow between 3 nodes over 3 links` |
|
|
1351
|
+
| `noObservations` | `string` | `No observations in this window.` |
|
|
1352
|
+
| `xAxis` | `string` | `x` |
|
|
1353
|
+
| `yAxis` | `string` | `y` |
|
|
1354
|
+
| `size` | `string` | `Size` |
|
|
1355
|
+
| `scatter` | `(series: string[], yLabel: string, xLabel: string) => string` | `{series1}, {series2}: {yLabel} against {xLabel}` |
|
|
1356
|
+
| `outsideRange` | `(count: number) => string` | `3 points outside the shown range` |
|
|
1357
|
+
| `waterfall` | `(steps: number, from: string, to: string) => string` | `Waterfall of 3 steps from {from} to {to}` |
|
|
1358
|
+
| `balance` | `string` | `Balance` |
|
|
1359
|
+
| `increase` | `string` | `Increase` |
|
|
1360
|
+
| `decrease` | `string` | `Decrease` |
|
|
1361
|
+
| `runningTotal` | `string` | `Running total` |
|
|
1362
|
+
| `sunburst` | `(total: string, depth: number) => string` | `Hierarchy of {total} across 3 levels` |
|
|
1363
|
+
| `treemap` | `(count: number) => string` | `Treemap of 3 items` |
|
|
1364
|
+
| `trendUp` | `string` | `up` |
|
|
1365
|
+
| `trendDown` | `string` | `down` |
|
|
1366
|
+
| `trendFlat` | `string` | `flat` |
|
|
1367
|
+
|
|
1368
|
+
</details>
|
|
1369
|
+
|
|
1370
|
+
<details><summary><code>timeline</code> — 17 keys</summary>
|
|
1371
|
+
|
|
1372
|
+
| Key | Type | English default |
|
|
1373
|
+
|---|---|---|
|
|
1374
|
+
| `days` | `(count: number) => string` | `3 days` |
|
|
1375
|
+
| `daysToToday` | `(count: number) => string` | `3 days to today` |
|
|
1376
|
+
| `notReached` | `string` | `Not yet reached` |
|
|
1377
|
+
| `next` | `string` | `Next` |
|
|
1378
|
+
| `more` | `(count: number) => string` | `+3 more` |
|
|
1379
|
+
| `today` | `string` | `Today` |
|
|
1380
|
+
| `todayTitle` | `(date: string) => string` | `Today — {date}` |
|
|
1381
|
+
| `open` | `(name: string) => string` | `Open {name}` |
|
|
1382
|
+
| `openButton` | `string` | `Open` |
|
|
1383
|
+
| `scrub` | `string` | `Scrub the timeline` |
|
|
1384
|
+
| `alsoToCome` | `(names: string[]) => string` | `Also to come: {names1}, {names2}` |
|
|
1385
|
+
| `start` | `(date: string) => string` | `Start · {date}` |
|
|
1386
|
+
| `events` | `(count: number, names: string[]) => string` | `3 events · {names1}, {names2}` |
|
|
1387
|
+
| `started` | `(date: string) => string` | `started {date}` |
|
|
1388
|
+
| `duration` | `(days: number) => string` | `3 days` |
|
|
1389
|
+
| `reached` | `(dated: number, total: number) => string` | `3 of 3 milestones` |
|
|
1390
|
+
| `milestones` | `(title: string) => string` | `{title} milestones` |
|
|
1391
|
+
|
|
1392
|
+
</details>
|
|
1393
|
+
|
|
1394
|
+
<details><summary><code>production</code> — 20 keys</summary>
|
|
1395
|
+
|
|
1396
|
+
| Key | Type | English default |
|
|
1397
|
+
|---|---|---|
|
|
1398
|
+
| `heading` | `string` | `Production progress` |
|
|
1399
|
+
| `start` | `string` | `Start` |
|
|
1400
|
+
| `estimated` | `string` | `Estimated` |
|
|
1401
|
+
| `estimatedCompletion` | `string` | `Estimated completion` |
|
|
1402
|
+
| `estDone` | `string` | `Est. done` |
|
|
1403
|
+
| `play` | `string` | `Play` |
|
|
1404
|
+
| `pause` | `string` | `Pause` |
|
|
1405
|
+
| `playTitle` | `string` | `Play the timeline, report by report` |
|
|
1406
|
+
| `backTo` | `(report: string) => string` | `Back to {report}` |
|
|
1407
|
+
| `showing` | `(report: string) => string` | `Showing {report}` |
|
|
1408
|
+
| `overall` | `(percent: number) => string` | `3% overall` |
|
|
1409
|
+
| `inStock` | `(pieces: number) => string` | `3 pc in stock` |
|
|
1410
|
+
| `noReport` | `string` | `No production report filed yet` |
|
|
1411
|
+
| `leadTime` | `(days: number) => string` | `3 days lead time` |
|
|
1412
|
+
| `report` | `string` | `Production report` |
|
|
1413
|
+
| `shipment` | `string` | `Shipment` |
|
|
1414
|
+
| `inspection` | `string` | `Inspection` |
|
|
1415
|
+
| `invoice` | `string` | `Invoice` |
|
|
1416
|
+
| `scrub` | `string` | `Scrub the production timeline` |
|
|
1417
|
+
| `label` | `(from: string, to: string) => string` | `Production reports and events, {from} to {to}` |
|
|
1418
|
+
|
|
1419
|
+
</details>
|
|
1420
|
+
|
|
1421
|
+
<details><summary><code>containers</code> — 10 keys</summary>
|
|
1422
|
+
|
|
1423
|
+
| Key | Type | English default |
|
|
1424
|
+
|---|---|---|
|
|
1425
|
+
| `items` | `(count: number) => string` | `3 items` |
|
|
1426
|
+
| `pieces` | `(count: number) => string` | `3 pcs` |
|
|
1427
|
+
| `split` | `(instructed: number, loaded: number) => string` | `(3 instr / 3 loaded)` |
|
|
1428
|
+
| `added` | `(count: number, pieces: number) => string` | `3 new (3 pcs)` |
|
|
1429
|
+
| `fill` | `(volume: number, capacity: number) => string` | `3.0 / 3 m³` |
|
|
1430
|
+
| `total` | `string` | `Total:` |
|
|
1431
|
+
| `instructed` | `(volume: number) => string` | `3.00 m³ instruction` |
|
|
1432
|
+
| `loaded` | `(volume: number) => string` | `3.00 m³ loaded` |
|
|
1433
|
+
| `volume` | `(volume: number) => string` | `3.00 m³` |
|
|
1434
|
+
| `noVolume` | `string` | `Volume: N/A (no volume data for these part numbers)` |
|
|
1435
|
+
|
|
1436
|
+
</details>
|
|
1437
|
+
|
|
1438
|
+
<details><summary><code>toast</code> — 1 keys</summary>
|
|
1439
|
+
|
|
1440
|
+
| Key | Type | English default |
|
|
1441
|
+
|---|---|---|
|
|
1442
|
+
| `notification` | `string` | `Notification` |
|
|
1443
|
+
|
|
1444
|
+
</details>
|
|
1445
|
+
|
|
513
1446
|
### Brand surfaces — `efficient-shell/brand.css`
|
|
514
1447
|
|
|
515
1448
|
For output that is not a portal window — a report, a published artifact, a
|
|
@@ -753,7 +1686,7 @@ copying both from `node_modules/maplibre-gl/dist`). Tiles come from
|
|
|
753
1686
|
|
|
754
1687
|
| Export | Notes |
|
|
755
1688
|
|---|---|
|
|
756
|
-
| `EntityMap` | The map. `pins` (`MapPin`: glyph or `icon` paths, `badge`, `tone` classes, `approximate`, `faded`), `selectedKey` + `onSelect`, `focus` to fly to a pin, `routes` (`MapRoute`, dashed when an estimate), `fitTo`, `attribution`. Follows `data-theme="dark"` on `<html>`; resizes with its box (a shell window sends no window resize). Without WebGL it says so and its children still draw. |
|
|
1689
|
+
| `EntityMap` | The map. `pins` (`MapPin`: glyph or `icon` paths, `badge`, `tone` classes, `approximate`, `faded`), `selectedKey` + `onSelect`, `focus` to fly to a pin, `routes` (`MapRoute`, dashed when an estimate), `fitTo`, `attribution`. Follows `data-theme="dark"` or a `dark` class on `<html>`; resizes with its box (a shell window sends no window resize). Without WebGL it says so and its children still draw. |
|
|
757
1690
|
| `LocationsMap` | A record's compact map over an endpoint: legend, "Locating N addresses…", a note per record with no pin, the chosen pin's card. `palette` names the categories the portal's way; `numbers` gives each pin the number the page's own list shows. |
|
|
758
1691
|
| `MapLegend`, `SelectedCard` | The overlays, for a map that lays out its own list (the admin portal's list-wide Map view). |
|
|
759
1692
|
| `useMapPoints(queryKey, queryFn)` | react-query, re-asked every few seconds while `pending > 0`; `mapPointsRefetchInterval` is the same rule for a hand-written query. |
|
|
@@ -769,7 +1702,7 @@ copying both from `node_modules/maplibre-gl/dist`). Tiles come from
|
|
|
769
1702
|
| `isPageEntry`, `isEntityEntry` | Type guards for `WindowRegistryEntry`. |
|
|
770
1703
|
| `glassStyle()` | Returns the theme-aware frosted-glass `style` object. |
|
|
771
1704
|
| `reportBug(submit)` | Captures a screenshot via `getDisplayMedia`, opens the dialog, hands the payload to your `submit`. |
|
|
772
|
-
| `formatDate(iso)` |
|
|
1705
|
+
| `formatDate(iso, { locale?, style? })` | A `YYYY-MM-DD` (or the date part of a timestamp) in the user's stored date format — or, given a `locale`, written by `Intl` in it (`style` defaults to `{ dateStyle: 'medium' }`). Returns `—` for nothing. |
|
|
773
1706
|
| `installStaleChunkReload(options?)` | Call once before the app mounts. A deploy replaces every lazy chunk; a tab opened before it crashes on the first lazy window it opens ("Failed to fetch dynamically imported module", or a `ChunkLoadError`) and no remount can fix it. This reloads the page instead — once per 30 s cooldown, kept in `sessionStorage`, so a chunk still missing after the reload (a broken deploy) crashes visibly instead of looping. It hears Vite's `vite:preloadError` (whose throw it swallows) and, for Next.js (Turbopack) and webpack, a chunk under `chunkPathPrefix` (default `NEXT_CHUNK_PATH_PREFIX`, `/_next/static/`; a path from this origin or a full URL for a CDN `assetPrefix`; `null` for Vite only) that fails as a `<script>`, a stylesheet or a script/style/module preload — or that came back as HTML and threw a `SyntaxError`, which is how a missing chunk surfaces without `X-Content-Type-Options: nosniff`. Prefetches, fonts and images are ignored. Before a chunk reload it asks the server (`HEAD`, `no-store`) whether the file is really gone — a 404/410, or the SPA fallback's HTML — so a dropped connection is left to the loader's own retry and an offline tab is never reloaded onto the browser's error page. Both signals share one cooldown. Returns the uninstaller. |
|
|
774
1707
|
| `isStaleChunkError(error)` | True for the three engines' "module the server did not return" messages, Vite's CSS-preload line, and any Error named `ChunkLoadError` (Turbopack, webpack) — what `WindowCrashedFallback` uses to offer "Reload page" instead of "Reload window". |
|
|
775
1708
|
| `budgetState(elapsed, budget)` | `no-reading` \| `no-budget` \| `within` \| `over` — the verdict `BudgetBar` draws by, exported so a run list sorts and filters by the same rule rather than re-deriving "late" a second time. |
|