@boost33/ui 0.5.1 → 0.7.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/CHANGELOG.md +2973 -0
- package/dist/components/AccountMenu/AccountMenu.js +66 -0
- package/dist/components/AccountMenu/AccountMenu.js.map +1 -0
- package/dist/components/AccountMenu/AccountMenu.module.css.js +42 -0
- package/dist/components/AccountMenu/AccountMenu.module.css.js.map +1 -0
- package/dist/components/AccountMenu/icons.js +32 -0
- package/dist/components/AccountMenu/icons.js.map +1 -0
- package/dist/components/AccountMenu/labels.js +14 -0
- package/dist/components/AccountMenu/labels.js.map +1 -0
- package/dist/components/CommandPalette/CommandPalette.js +65 -0
- package/dist/components/CommandPalette/CommandPalette.js.map +1 -0
- package/dist/components/CommandPalette/CommandPalette.module.css.js +34 -0
- package/dist/components/CommandPalette/CommandPalette.module.css.js.map +1 -0
- package/dist/components/CommandPalette/icons.js +23 -0
- package/dist/components/CommandPalette/icons.js.map +1 -0
- package/dist/components/CommandPalette/labels.js +19 -0
- package/dist/components/CommandPalette/labels.js.map +1 -0
- package/dist/components/NotificationCenter/NotificationCenter.js +67 -0
- package/dist/components/NotificationCenter/NotificationCenter.js.map +1 -0
- package/dist/components/NotificationCenter/NotificationCenter.module.css.js +54 -0
- package/dist/components/NotificationCenter/NotificationCenter.module.css.js.map +1 -0
- package/dist/components/NotificationCenter/icons.js +45 -0
- package/dist/components/NotificationCenter/icons.js.map +1 -0
- package/dist/components/NotificationCenter/labels.js +26 -0
- package/dist/components/NotificationCenter/labels.js.map +1 -0
- package/dist/components/ProductMark/ProductMark.d.ts +66 -76
- package/dist/components/ProductMark/ProductMark.js +218 -64
- package/dist/components/ProductMark/ProductMark.js.map +1 -1
- package/dist/components/SettingsFrame/SettingsFrame.d.ts +91 -0
- package/dist/components/SettingsFrame/SettingsFrame.js +109 -0
- package/dist/components/SettingsFrame/SettingsFrame.js.map +1 -0
- package/dist/components/SettingsFrame/SettingsFrame.module.css.js +74 -0
- package/dist/components/SettingsFrame/SettingsFrame.module.css.js.map +1 -0
- package/dist/components/SettingsFrame/icons.d.ts +10 -0
- package/dist/components/SettingsFrame/icons.js +37 -0
- package/dist/components/SettingsFrame/icons.js.map +1 -0
- package/dist/components/SettingsFrame/labels.d.ts +36 -0
- package/dist/components/SettingsFrame/labels.js +18 -0
- package/dist/components/SettingsFrame/labels.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.js +45 -29
- package/dist/index.js.map +1 -1
- package/dist/style.css +1 -1
- package/package.json +3 -2
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { jsxs as e, jsx as r } from "react/jsx-runtime";
|
|
2
|
+
import t from "./NotificationCenter.module.css.js";
|
|
3
|
+
function i() {
|
|
4
|
+
return /* @__PURE__ */ e(
|
|
5
|
+
"svg",
|
|
6
|
+
{
|
|
7
|
+
className: t.emptyGlyph,
|
|
8
|
+
viewBox: "0 0 16 16",
|
|
9
|
+
fill: "none",
|
|
10
|
+
stroke: "currentColor",
|
|
11
|
+
strokeWidth: "1.2",
|
|
12
|
+
strokeLinejoin: "round",
|
|
13
|
+
"aria-hidden": "true",
|
|
14
|
+
children: [
|
|
15
|
+
/* @__PURE__ */ r("path", { d: "M8 2.5C6 2.5 4.6 4 4.6 6V8.3C4.6 8.9 4.4 9.4 4 9.8L3.3 10.6C3 10.9 3.2 11.5 3.7 11.5H12.3C12.8 11.5 13 10.9 12.7 10.6L12 9.8C11.6 9.4 11.4 8.9 11.4 8.3V6C11.4 4 10 2.5 8 2.5Z" }),
|
|
16
|
+
/* @__PURE__ */ r("path", { d: "M6.5 13C6.8 13.5 7.4 13.8 8 13.8C8.6 13.8 9.2 13.5 9.5 13", strokeLinecap: "round" })
|
|
17
|
+
]
|
|
18
|
+
}
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
function a({ size: o }) {
|
|
22
|
+
return /* @__PURE__ */ e(
|
|
23
|
+
"svg",
|
|
24
|
+
{
|
|
25
|
+
className: t.sourceMark,
|
|
26
|
+
width: o,
|
|
27
|
+
height: o,
|
|
28
|
+
viewBox: "0 0 40 40",
|
|
29
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
30
|
+
"aria-hidden": "true",
|
|
31
|
+
children: [
|
|
32
|
+
/* @__PURE__ */ r("rect", { className: t.sourceMarkGround, width: "40", height: "40" }),
|
|
33
|
+
/* @__PURE__ */ e("g", { transform: "translate(10 10) scale(1.25)", fill: "none", stroke: "currentColor", strokeWidth: "1.3", strokeLinejoin: "round", children: [
|
|
34
|
+
/* @__PURE__ */ r("path", { d: "M8 2.5C6 2.5 4.6 4 4.6 6V8.3C4.6 8.9 4.4 9.4 4 9.8L3.3 10.6C3 10.9 3.2 11.5 3.7 11.5H12.3C12.8 11.5 13 10.9 12.7 10.6L12 9.8C11.6 9.4 11.4 8.9 11.4 8.3V6C11.4 4 10 2.5 8 2.5Z" }),
|
|
35
|
+
/* @__PURE__ */ r("path", { d: "M6.5 13C6.8 13.5 7.4 13.8 8 13.8C8.6 13.8 9.2 13.5 9.5 13", strokeLinecap: "round" })
|
|
36
|
+
] })
|
|
37
|
+
]
|
|
38
|
+
}
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
export {
|
|
42
|
+
i as EmptyBell,
|
|
43
|
+
a as SourceBellMark
|
|
44
|
+
};
|
|
45
|
+
//# sourceMappingURL=icons.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"icons.js","sources":["../../../src/components/NotificationCenter/icons.tsx"],"sourcesContent":["// The notification centre's own glyphs. Both are bells, and they are two\n// drawings rather than one because they are drawn at two sizes on two grounds:\n// one is white ink inside a 22px dark tile, the other is a 28px outline standing\n// alone on the panel's surface. Everything else the panel draws is either\n// ProductMark's or plain text.\n\nimport styles from './NotificationCenter.module.css'\n\n/**\n * The bell on the empty state, standing alone above \"You're all caught up\".\n *\n * Decorative: the two lines beneath it say the same thing in words, so a screen\n * reader that announced it as well would say the state twice. It is sized in CSS\n * (`--spacing-7`) rather than by width/height attributes, which is why it takes\n * no size prop.\n */\nexport function EmptyBell() {\n return (\n <svg\n className={styles.emptyGlyph}\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.2\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M8 2.5C6 2.5 4.6 4 4.6 6V8.3C4.6 8.9 4.4 9.4 4 9.8L3.3 10.6C3 10.9 3.2 11.5 3.7 11.5H12.3C12.8 11.5 13 10.9 12.7 10.6L12 9.8C11.6 9.4 11.4 8.9 11.4 8.3V6C11.4 4 10 2.5 8 2.5Z\" />\n <path d=\"M6.5 13C6.8 13.5 7.4 13.8 8 13.8C8.6 13.8 9.2 13.5 9.5 13\" strokeLinecap=\"round\" />\n </svg>\n )\n}\n\n/**\n * The tile a row draws when its notification names no product -- an account or\n * security event, which is what the drawing's fifth row is.\n *\n * **Why this is not a `ProductMark` with an unknown slug.** It would draw the\n * right thing by accident: ADR-0003's safe degrade gives an unrecognised slug\n * the bare tile with no glyph, which is a product whose artwork has not landed.\n * A notification with no product is not that. It is a row that correctly has no\n * product, and drawing it as a gap says the mark failed to load. So the fallback\n * is a bell -- the panel's own symbol, which is what the drawing puts there.\n *\n * It is still drawn ProductMark's way rather than as a styled `div`: a `rect` on\n * a 40-unit grid, its corner taken from `--radius-product-tile`, so the two\n * kinds of tile in the same column share one corner at every size instead of\n * agreeing to a px value that only matches at 22px. The glyph is on the same\n * 16-unit grid as `EmptyBell` above and the group transform insets it into the\n * middle 20 of the 40, which is the inset ProductMark gives its four -- so the\n * bell's ink lands at the weight the product glyphs do (1.3 on the 16 grid,\n * scaled 1.25, is 0.89px of stroke at 22px, which is what Paper draws).\n *\n * Decorative like ProductMark is here: the row's text names the source.\n */\nexport function SourceBellMark({ size }: { size: number }) {\n return (\n <svg\n className={styles.sourceMark}\n width={size}\n height={size}\n viewBox=\"0 0 40 40\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <rect className={styles.sourceMarkGround} width=\"40\" height=\"40\" />\n <g transform=\"translate(10 10) scale(1.25)\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.3\" strokeLinejoin=\"round\">\n <path d=\"M8 2.5C6 2.5 4.6 4 4.6 6V8.3C4.6 8.9 4.4 9.4 4 9.8L3.3 10.6C3 10.9 3.2 11.5 3.7 11.5H12.3C12.8 11.5 13 10.9 12.7 10.6L12 9.8C11.6 9.4 11.4 8.9 11.4 8.3V6C11.4 4 10 2.5 8 2.5Z\" />\n <path d=\"M6.5 13C6.8 13.5 7.4 13.8 8 13.8C8.6 13.8 9.2 13.5 9.5 13\" strokeLinecap=\"round\" />\n </g>\n </svg>\n )\n}\n"],"names":["EmptyBell","jsxs","styles","jsx","SourceBellMark","size"],"mappings":";;AAgBO,SAASA,IAAY;AAC1B,SACE,gBAAAC;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,WAAWC,EAAO;AAAA,MAClB,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,QAAO;AAAA,MACP,aAAY;AAAA,MACZ,gBAAe;AAAA,MACf,eAAY;AAAA,MAEZ,UAAA;AAAA,QAAA,gBAAAC,EAAC,QAAA,EAAK,GAAE,iLAAA,CAAiL;AAAA,QACzL,gBAAAA,EAAC,QAAA,EAAK,GAAE,6DAA4D,eAAc,QAAA,CAAQ;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAGhG;AAwBO,SAASC,EAAe,EAAE,MAAAC,KAA0B;AACzD,SACE,gBAAAJ;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,WAAWC,EAAO;AAAA,MAClB,OAAOG;AAAA,MACP,QAAQA;AAAA,MACR,SAAQ;AAAA,MACR,OAAM;AAAA,MACN,eAAY;AAAA,MAEZ,UAAA;AAAA,QAAA,gBAAAF,EAAC,UAAK,WAAWD,EAAO,kBAAkB,OAAM,MAAK,QAAO,MAAK;AAAA,QACjE,gBAAAD,EAAC,KAAA,EAAE,WAAU,gCAA+B,MAAK,QAAO,QAAO,gBAAe,aAAY,OAAM,gBAAe,SAC7G,UAAA;AAAA,UAAA,gBAAAE,EAAC,QAAA,EAAK,GAAE,iLAAA,CAAiL;AAAA,UACzL,gBAAAA,EAAC,QAAA,EAAK,GAAE,6DAA4D,eAAc,QAAA,CAAQ;AAAA,QAAA,EAAA,CAC5F;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAGN;"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { fillTemplate as r } from "../../fill-template.js";
|
|
2
|
+
const l = Object.freeze({
|
|
3
|
+
title: "Notifications",
|
|
4
|
+
markAllAsRead: "Mark all as read",
|
|
5
|
+
all: "All",
|
|
6
|
+
unread: "Unread",
|
|
7
|
+
unreadItem: "Unread",
|
|
8
|
+
meta: "%source% · %time%",
|
|
9
|
+
viewAll: "View all notifications",
|
|
10
|
+
emptyTitle: "You're all caught up",
|
|
11
|
+
emptyBody: "Nothing from any product needs your attention."
|
|
12
|
+
});
|
|
13
|
+
function s(a) {
|
|
14
|
+
const i = Object.fromEntries(
|
|
15
|
+
Object.entries(a ?? {}).filter(([, e]) => e !== void 0)
|
|
16
|
+
), t = { ...l, ...i };
|
|
17
|
+
return {
|
|
18
|
+
...t,
|
|
19
|
+
meta: (e, o) => r(t.meta, { source: e, time: o })
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
export {
|
|
23
|
+
l as defaultNotificationCenterLabels,
|
|
24
|
+
s as resolveNotificationCenterLabels
|
|
25
|
+
};
|
|
26
|
+
//# sourceMappingURL=labels.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"labels.js","sources":["../../../src/components/NotificationCenter/labels.ts"],"sourcesContent":["// The notification centre's own user-facing words, each a field with an English\n// default. Every string a person can read or a screen reader can announce that\n// is not row data lives here, so the first two consumers -- both French-default\n// -- translate the panel without this package taking an i18n dependency\n// (CLAUDE.md; B33-849). The notifications themselves are not here: their title,\n// their source and their time are the host's data, supplied per row on `items`,\n// because the host is the only side that knows what happened (B33-494's data\n// decision, 2026-10-06).\n//\n// ── Which label contract this follows, and why it is not a fourth one ────────\n//\n// This is `WalletChipLabels`'s contract, in all four of its parts, and the\n// choice is deliberate. B33-1007 found `AppSwitcherLabels` claiming parity with\n// the chip while diverging from it three ways; two were closed by B33-919 and\n// the third -- the freeze -- is still open. Picking the chip means the third\n// labels module in this package lands on the shape the other two are converging\n// *to*, so B33-1007 closes by making the switcher match this file rather than by\n// this file becoming a fourth thing to reconcile. The four parts:\n//\n// 1. `labels` is a `Partial`, so a consumer translates the strings it wants\n// and inherits the rest -- and so adding a field here later is not a\n// compile error in four apps on a patch bump.\n// 2. A `resolve*` step filters explicitly-`undefined` fields before merging,\n// because a next-intl `t('...')` returns `undefined` on a missed key and a\n// plain spread copies that `undefined` across (B33-873).\n// 3. The defaults are `Object.freeze({ … } satisfies …)` with NO type\n// annotation. That is the spelling B33-916 settled for the chip: the\n// annotation widens `Readonly<T>` straight back to the mutable interface,\n// so a consumer writing to the frozen export gets no compile error and an\n// uncaught TypeError in production instead.\n// 4. The one string that carries values is a `%placeholder%` template -- never\n// fragments concatenated in the render, because word order is not a property\n// of English. The delimiter is `%name%` and not `{name}` because a brace is\n// ICU argument syntax and a consumer keeps these strings in an ICU catalogue\n// (B33-1277); the reasoning is in `src/fill-template.ts`.\n//\n// A template, and *only* a template. `meta` took a function of the same values\n// until B33-1278, which is the shape B33-880 had already recorded as unpassable:\n// React's Flight serializer throws on any function it finds in a Client\n// Component's props, so a labels object holding one cannot be passed from a\n// Server Component page -- which is what a host page is by default. The union was\n// type-legal and fatal in production, and nothing in the type said so. A meta line\n// needing logic a template cannot express is computed in the host's own catalogue\n// and passed here finished.\n\nimport { fillTemplate } from '../../fill-template'\n\n/** Every user-facing string the notification centre renders that is not row data. */\nexport interface NotificationCenterLabels {\n /**\n * The panel's heading, and through it the panel's accessible name. Default\n * \"Notifications\".\n *\n * It is drawn as a real heading and the panel is pointed at it with\n * `aria-labelledby`, rather than carrying a second copy of the same word in an\n * `aria-label`. ADR-0010 says a disclosure panel carries no widget role and\n * takes a name without one; it does not say the name has to be invisible, and\n * a name that is already on the screen is one fewer string to translate and\n * one fewer place for the two to disagree.\n */\n title: string\n /**\n * The header's action, which clears every unread marker. Default\n * \"Mark all as read\".\n *\n * Stage A renders the control and wires nothing to it -- the handler is Stage\n * B's, with the rest of the interaction (CLAUDE.md, \"Presentational-first\").\n */\n markAllAsRead: string\n /** The first filter tab, showing every notification. Default \"All\". */\n all: string\n /**\n * The second filter tab, showing only the unread ones. Default \"Unread\".\n *\n * The count beside it is not a label: it is `items` counted, so it needs no\n * translation and cannot disagree with the list under it.\n */\n unread: string\n /**\n * The marker on an unread row, announced rather than drawn. Default \"Unread\".\n *\n * The drawing carries unread as a 6px orange dot and nothing else, which is a\n * colour-only distinction and reaches nobody using a screen reader. This is\n * the same state in words, in the row, visually hidden (CLAUDE.md,\n * \"Accessibility is part of done\"). It repeats `unread` by default because it\n * is the same English word, and it is a separate field because a locale is\n * entitled to tag a row differently from how it names a filter.\n */\n unreadItem: string\n /**\n * The second line of a row, around the host's source and time. Supplied whole\n * so the consumer owns word order and the separator.\n *\n * Placeholders: `%source%`, `%time%`. Default (en) `%source% · %time%`.\n *\n * Both values are the host's, preformatted -- see `NotificationCenterItem`\n * for why the time arrives as a string this package never computes.\n */\n meta: string\n /** The footer link out to the full list. Default \"View all notifications\". */\n viewAll: string\n /** The empty state's headline. Default \"You're all caught up\". */\n emptyTitle: string\n /**\n * The line under the empty state's headline. Default\n * \"Nothing from any product needs your attention.\"\n *\n * **The empty state is not an edge case.** A host that has not wired a feed\n * yet renders it, which makes it the state most consumers see first (B33-494's\n * data decision). A locale that leaves it untranslated is a blank panel.\n */\n emptyBody: string\n}\n\n/**\n * The English defaults. A consumer that passes nothing renders the panel in\n * English, which is what the specimen route shows and what a human will be\n * looking at when they approve this component at its fidelity gate.\n *\n * Frozen, and frozen without a type annotation. It is a public export reaching\n * four products on a version bump: `const` protects the binding and not the\n * contents, so a consumer aliasing it -- `const mine = defaultNotificationCenterLabels;\n * mine.title = 'Notifications'` -- would silently rename every panel in the\n * process (B33-877), and an annotation here would widen the `Readonly` back off\n * the emitted `.d.ts` and turn that into a runtime TypeError rather than a\n * compile error (B33-916).\n *\n * The freeze is shallow. No field here is an object and none should become one\n * without re-reading B33-916's note: a nested label defeats the guard silently.\n */\nexport const defaultNotificationCenterLabels = Object.freeze({\n title: 'Notifications',\n markAllAsRead: 'Mark all as read',\n all: 'All',\n unread: 'Unread',\n unreadItem: 'Unread',\n meta: '%source% · %time%',\n viewAll: 'View all notifications',\n emptyTitle: \"You're all caught up\",\n emptyBody: 'Nothing from any product needs your attention.',\n} satisfies NotificationCenterLabels)\n\n/**\n * The labels as the render consumes them: `meta` presented as a function of its\n * two values, so the component writes `t.meta(…)` and never handles a template\n * itself. Internal, and the interpolation has to happen somewhere.\n */\nexport interface ResolvedNotificationCenterLabels extends Omit<NotificationCenterLabels, 'meta'> {\n meta: (source: string, time: string) => string\n}\n\n/**\n * Merge a consumer's partial `labels` onto the English defaults, treating an\n * explicitly-`undefined` field as unsupplied, and present `meta` as a function of\n * its two values.\n *\n * `{ title: undefined }` is what one missing next-intl key looks like at the\n * call site. It must fall back to English rather than blank the heading -- which\n * here would also unname the panel, since the heading is what names it\n * (B33-873).\n */\nexport function resolveNotificationCenterLabels(\n labels?: Partial<NotificationCenterLabels>,\n): ResolvedNotificationCenterLabels {\n const supplied = Object.fromEntries(\n Object.entries(labels ?? {}).filter(([, value]) => value !== undefined),\n ) as Partial<NotificationCenterLabels>\n const merged = { ...defaultNotificationCenterLabels, ...supplied }\n return {\n ...merged,\n meta: (source, time) => fillTemplate(merged.meta, { source, time }),\n }\n}\n"],"names":["defaultNotificationCenterLabels","resolveNotificationCenterLabels","labels","supplied","value","merged","source","time","fillTemplate"],"mappings":";AAkIO,MAAMA,IAAkC,OAAO,OAAO;AAAA,EAC3D,OAAO;AAAA,EACP,eAAe;AAAA,EACf,KAAK;AAAA,EACL,QAAQ;AAAA,EACR,YAAY;AAAA,EACZ,MAAM;AAAA,EACN,SAAS;AAAA,EACT,YAAY;AAAA,EACZ,WAAW;AACb,CAAoC;AAqB7B,SAASC,EACdC,GACkC;AAClC,QAAMC,IAAW,OAAO;AAAA,IACtB,OAAO,QAAQD,KAAU,EAAE,EAAE,OAAO,CAAC,CAAA,EAAGE,CAAK,MAAMA,MAAU,MAAS;AAAA,EAAA,GAElEC,IAAS,EAAE,GAAGL,GAAiC,GAAGG,EAAA;AACxD,SAAO;AAAA,IACL,GAAGE;AAAA,IACH,MAAM,CAACC,GAAQC,MAASC,EAAaH,EAAO,MAAM,EAAE,QAAAC,GAAQ,MAAAC,EAAA,CAAM;AAAA,EAAA;AAEtE;"}
|
|
@@ -6,95 +6,76 @@
|
|
|
6
6
|
*
|
|
7
7
|
* **Module-internal since B33-1269, and it has to stay that way.** `src/index.ts`
|
|
8
8
|
* publishes `hasProductMark` below and neither this list nor `ProductSlug`. A
|
|
9
|
-
* `const` assertion over
|
|
9
|
+
* `const` assertion over these strings made an artwork inventory part of the
|
|
10
10
|
* published type contract: a consumer could write `Record<ProductSlug, ...>` or
|
|
11
|
-
* switch exhaustively over it, and then artwork landing for
|
|
11
|
+
* switch exhaustively over it, and then artwork landing for another product --
|
|
12
12
|
* the thing this package exists to ship -- would be a breaking change for them.
|
|
13
13
|
* Nothing published is typed `ProductSlug` anyway; every slug prop is `string` on
|
|
14
14
|
* purpose, so Identity's registry may run ahead of a mark release (ADR-0003, and
|
|
15
15
|
* `slug` below). So the union's only real job was answering "which slugs have
|
|
16
16
|
* artwork", and `hasProductMark` answers that without freezing the list.
|
|
17
|
+
* B33-1670 widening this from four slugs to ten is the proof: it adds drawings
|
|
18
|
+
* and flips six `hasProductMark` answers to true, and breaks nothing a consumer
|
|
19
|
+
* could have typed.
|
|
17
20
|
*
|
|
18
21
|
* The tests and the specimen read both names by deep import, which is how
|
|
19
22
|
* everything in this repo reaches into `src/`. A consumer cannot: `package.json`
|
|
20
23
|
* exports `.`, `./style.css` and `./theme.css`, and nothing else.
|
|
21
24
|
*
|
|
22
|
-
* **It is
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
* `
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
* straight from `GET /api/v1/products` drew the bare tile (see `slug` below) and
|
|
34
|
-
* nothing anywhere failed.
|
|
25
|
+
* **It is the whole of Identity's registry: all ten slugs, every one with a
|
|
26
|
+
* mark.** Transcribed from `boost33-identity/src/lib/productRegistry.ts` -- its
|
|
27
|
+
* `REGISTRY_SLUGS`, which is `PRODUCTS` from `src/config/products.ts`
|
|
28
|
+
* (boostscore, boostvoice, boostoutbound, brokers, boosttrade, boostfunding)
|
|
29
|
+
* plus `RESULTS_SLUG`, `PASSPORT_SLUG`, `PIPE_SLUG` and `WALLET_SLUG`. That file
|
|
30
|
+
* is the source of truth and this is a copy of it in another repository, which
|
|
31
|
+
* is a thing that drifts. It already did: until B33-1043 this list read
|
|
32
|
+
* `wallet | score | voice | outbound` while its comment asserted it was
|
|
33
|
+
* Identity's, so three of the four rows of a switcher fed straight from
|
|
34
|
+
* `GET /api/v1/products` drew the bare tile (see `slug` below) and nothing
|
|
35
|
+
* anywhere failed.
|
|
35
36
|
*
|
|
36
37
|
* Identity is not the side that renames. ADR-0003 records the shorter slugs as
|
|
37
38
|
* considered and rejected: these match the `?app=` keys live campaign URLs
|
|
38
39
|
* already carry, so renaming them means those links grant nothing on sign-up.
|
|
40
|
+
* The same holds for `boostvoice`, whose mark is already the Content pencil:
|
|
41
|
+
* the product is being renamed Boost Content, and the display name moves on
|
|
42
|
+
* Identity's side (B33-1672) while the slug stays.
|
|
39
43
|
*
|
|
40
44
|
* `tests/product-mark.test.tsx` pins this list against a second transcription of
|
|
41
45
|
* the same source, so the two repositories cannot part company in silence again.
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
+
* The pin also keeps a list of served slugs this package deliberately draws
|
|
47
|
+
* nothing for. That list is empty since B33-1670, and it stays in the test so an
|
|
48
|
+
* eleventh product Identity serves before its mark lands is a recorded decision
|
|
49
|
+
* rather than a quiet pass.
|
|
46
50
|
*
|
|
47
51
|
* The *order* is this package's own and not Identity's -- `REGISTRY_SLUGS` ends
|
|
48
|
-
* with `wallet` where this begins with it
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
* ProductMark specimen
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
* all.
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
* all
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
* referent, and it looks equally settled either way afterwards (CLAUDE.md, "an
|
|
70
|
-
* agent that picks one and builds it has invented a referent").
|
|
71
|
-
*
|
|
72
|
-
* The degrade is also the mildest it will ever be. Identity serves `brokers` as
|
|
73
|
-
* `live: false` -- the space is still being built -- so the switcher row carries
|
|
74
|
-
* the "Soon" tag beside the bare tile, which reads as a product that has not
|
|
75
|
-
* arrived rather than as a drawing that failed to load. That stops being true
|
|
76
|
-
* the day Brokers ships.
|
|
77
|
-
*
|
|
78
|
-
* **To close it:** get the mark drawn where the other four live
|
|
79
|
-
* (`boostledger/src/ui/primitives/icons.tsx`), lift it here verbatim, add
|
|
80
|
-
* `brokers` to this list, and let a human approve `productmark-brokers.png` at a
|
|
81
|
-
* gate. Not in that order optional: this list is what GLYPHS is typed against,
|
|
82
|
-
* so adding the slug without the artwork stops the build, which is the one part
|
|
83
|
-
* of this that cannot go wrong quietly.
|
|
84
|
-
*
|
|
85
|
-
* **And since B33-1269 that is an ordinary addition rather than a breaking
|
|
86
|
-
* change.** This list is not published, so widening it widens nothing a consumer
|
|
87
|
-
* has typed against: a fifth entry adds a drawing where there was a bare tile and
|
|
88
|
-
* flips `hasProductMark('brokers')` from false to true. Until then it was a
|
|
89
|
-
* major-bump-shaped change to ship a picture, which is the wrong price for the
|
|
90
|
-
* thing this package is for.
|
|
52
|
+
* with `wallet` where this begins with it, then follows Identity's order for the
|
|
53
|
+
* other nine. Nothing reads a render order off this list: a switcher draws the
|
|
54
|
+
* order its consumer was served (`AppSwitcher`), and the only thing this order
|
|
55
|
+
* sets is the left-to-right run of frames in the ProductMark specimen, where the
|
|
56
|
+
* four slugs that have carried a mark since 0.1 keep the first four places.
|
|
57
|
+
*
|
|
58
|
+
* ── Brokers, and the six that arrived with it ────────────────────────────────
|
|
59
|
+
*
|
|
60
|
+
* From 0.4.0 to 0.6.0 Identity served `brokers` and this package drew it as the
|
|
61
|
+
* bare tile, deliberately: no Brokers artwork existed in any repository to lift,
|
|
62
|
+
* and drawing one here would have been inventing a referent rather than
|
|
63
|
+
* transcribing a mark (PR #4 redrew the first four from a written description
|
|
64
|
+
* and got all four wrong). Identity then grew `boosttrade`, `boostfunding`,
|
|
65
|
+
* `boostresults`, `passport` and `pipe`, all served with no mark here either.
|
|
66
|
+
*
|
|
67
|
+
* B33-1669 closed it the way the old comment said it had to be closed: the
|
|
68
|
+
* marks were drawn where the others live (`boostledger/src/ui/primitives/icons.tsx`),
|
|
69
|
+
* for all ten products at once, and B33-1670 lifted them here verbatim. The
|
|
70
|
+
* part a commit cannot do is still outstanding when this lands -- a human
|
|
71
|
+
* approves `productmark-<slug>.png` for each of the ten at the fidelity gate
|
|
72
|
+
* (tests/baselines/README.md).
|
|
91
73
|
*/
|
|
92
|
-
export declare const PRODUCT_SLUGS: readonly ["wallet", "boostscore", "boostvoice", "boostoutbound"];
|
|
74
|
+
export declare const PRODUCT_SLUGS: readonly ["wallet", "boostscore", "boostvoice", "boostoutbound", "brokers", "boosttrade", "boostfunding", "boostresults", "passport", "pipe"];
|
|
93
75
|
/**
|
|
94
|
-
* One of the slugs this package draws a mark for. Not
|
|
95
|
-
*
|
|
96
|
-
*
|
|
97
|
-
* company.
|
|
76
|
+
* One of the slugs this package draws a mark for. Not published, for the reason
|
|
77
|
+
* recorded above. What this type is for is typing GLYPHS, so the list and the
|
|
78
|
+
* artwork cannot part company.
|
|
98
79
|
*/
|
|
99
80
|
export type ProductSlug = (typeof PRODUCT_SLUGS)[number];
|
|
100
81
|
/**
|
|
@@ -104,9 +85,9 @@ export type ProductSlug = (typeof PRODUCT_SLUGS)[number];
|
|
|
104
85
|
* **Ask this rather than matching a slug against a union of known slugs.** The
|
|
105
86
|
* set of slugs with artwork is this package's inventory, not a vocabulary:
|
|
106
87
|
* Identity owns which products exist (ADR-0003) and this list grows whenever a
|
|
107
|
-
* drawing lands.
|
|
108
|
-
*
|
|
109
|
-
* union is pinned to whichever inventory it compiled against; a caller that asks
|
|
88
|
+
* drawing lands. Since B33-1670 every slug Identity serves has a mark, and the
|
|
89
|
+
* next product Identity adds will be served before its mark ships here. A
|
|
90
|
+
* caller that pattern-matches a union is pinned to whichever inventory it compiled against; a caller that asks
|
|
110
91
|
* this gets the installed version's answer, and keeps working when the next mark
|
|
111
92
|
* ships.
|
|
112
93
|
*
|
|
@@ -135,9 +116,15 @@ export interface ProductMarkProps {
|
|
|
135
116
|
size?: number;
|
|
136
117
|
/**
|
|
137
118
|
* Dims the tile for a product the account is not entitled to -- the switcher's
|
|
138
|
-
* unowned rows need it.
|
|
139
|
-
*
|
|
140
|
-
*
|
|
119
|
+
* unowned and unbuilt rows need it. The tile ground greys to
|
|
120
|
+
* --color-neutral-300, and the cut-outs painted in the tile colour grey with
|
|
121
|
+
* it. The glyph stays white, and **the orange accent turns white too** (Jamal,
|
|
122
|
+
* 29 Oct 2026, B33-1669): a product the account does not own spends no
|
|
123
|
+
* orange. Two marks take the drawing from Paper's "Option: no orange" row to
|
|
124
|
+
* stay legible without the accent -- Outbound gains a fold line in the tile
|
|
125
|
+
* colour between its two wings, and Passport's globe flips to the tile colour
|
|
126
|
+
* with white lines. Fading the glyph instead would cost the shape the one
|
|
127
|
+
* thing telling the marks apart, and it is a prop rather than a wrapper
|
|
141
128
|
* `opacity-40 grayscale` filter because that lands on a mid-grey visibly
|
|
142
129
|
* darker than the grey Paper draws.
|
|
143
130
|
*
|
|
@@ -151,6 +138,8 @@ export interface ProductMarkProps {
|
|
|
151
138
|
* of those and makes the ratio bite. That combination is out of contract; no
|
|
152
139
|
* call site in this package uses it. See ADR-0012, which also records why the
|
|
153
140
|
* ground is not darkened and what to reach for if this is ever revisited.
|
|
141
|
+
* Since the accent turned white on a muted tile, every ink on that tile is the
|
|
142
|
+
* same white ADR-0012 measured, so its 1.41:1 is still the only ratio there is.
|
|
154
143
|
*/
|
|
155
144
|
muted?: boolean;
|
|
156
145
|
/**
|
|
@@ -170,8 +159,9 @@ export interface ProductMarkProps {
|
|
|
170
159
|
}
|
|
171
160
|
/**
|
|
172
161
|
* The tile-and-glyph mark for one Boost33 product -- a rounded --color-neutral-950
|
|
173
|
-
* square with the product's glyph in --color-primary-foreground
|
|
174
|
-
* share one palette and are told apart by
|
|
175
|
-
* orange in
|
|
162
|
+
* square with the product's glyph in --color-primary-foreground and one accent
|
|
163
|
+
* in --color-primary. The ten marks share one palette and are told apart by
|
|
164
|
+
* shape; the accent is the same orange in every one of them, so it identifies
|
|
165
|
+
* nothing.
|
|
176
166
|
*/
|
|
177
167
|
export declare function ProductMark({ slug, size, muted, title, className }: ProductMarkProps): import("react").JSX.Element;
|
|
@@ -1,77 +1,231 @@
|
|
|
1
|
-
import { jsxs as
|
|
2
|
-
import { useId as
|
|
3
|
-
import
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
1
|
+
import { jsxs as l, jsx as r, Fragment as e } from "react/jsx-runtime";
|
|
2
|
+
import { useId as L } from "react";
|
|
3
|
+
import a from "./ProductMark.module.css.js";
|
|
4
|
+
const w = 20, g = [
|
|
5
|
+
"wallet",
|
|
6
|
+
"boostscore",
|
|
7
|
+
"boostvoice",
|
|
8
|
+
"boostoutbound",
|
|
9
|
+
"brokers",
|
|
10
|
+
"boosttrade",
|
|
11
|
+
"boostfunding",
|
|
12
|
+
"boostresults",
|
|
13
|
+
"passport",
|
|
14
|
+
"pipe"
|
|
15
|
+
], o = "var(--color-primary-foreground)", b = "var(--color-primary)", M = "var(--color-neutral-950)", m = "var(--color-neutral-300)", d = 40, v = 0.62, W = 24, E = {
|
|
16
|
+
// wallet (upstream "Wallet"). A wallet with a card tucked behind its flap and
|
|
17
|
+
// an orange clasp.
|
|
18
|
+
wallet: {
|
|
19
|
+
optical: 0.94,
|
|
20
|
+
draw: ({ tile: t, accent: i }) => /* @__PURE__ */ l(e, { children: [
|
|
21
|
+
/* @__PURE__ */ r(
|
|
22
|
+
"path",
|
|
23
|
+
{
|
|
24
|
+
d: "M5 7 L15.4 3.1 A1.2 1.2 0 0 1 17 4 L17.6 7 Z",
|
|
25
|
+
fill: o,
|
|
26
|
+
stroke: o,
|
|
27
|
+
strokeWidth: "1",
|
|
28
|
+
strokeLinejoin: "round"
|
|
29
|
+
}
|
|
30
|
+
),
|
|
31
|
+
/* @__PURE__ */ r("rect", { x: "2.5", y: "6.5", width: "19", height: "15", rx: "3", fill: o }),
|
|
32
|
+
/* @__PURE__ */ r("rect", { x: "14.5", y: "10.75", width: "9", height: "6.5", rx: "2.5", fill: t }),
|
|
33
|
+
/* @__PURE__ */ r("circle", { cx: "17.75", cy: "14", r: "1.5", fill: i })
|
|
34
|
+
] })
|
|
35
|
+
},
|
|
36
|
+
// boostscore (upstream "Boost Score"). A target: a white ring around an orange
|
|
37
|
+
// bull's-eye.
|
|
38
|
+
boostscore: {
|
|
39
|
+
optical: 1,
|
|
40
|
+
draw: ({ tile: t, accent: i }) => /* @__PURE__ */ l(e, { children: [
|
|
41
|
+
/* @__PURE__ */ r("circle", { cx: "12", cy: "12", r: "10", fill: o }),
|
|
42
|
+
/* @__PURE__ */ r("circle", { cx: "12", cy: "12", r: "7", fill: t }),
|
|
43
|
+
/* @__PURE__ */ r("circle", { cx: "12", cy: "12", r: "4", fill: i })
|
|
44
|
+
] })
|
|
45
|
+
},
|
|
46
|
+
// boostvoice (upstream "Boost Voice"). The CONTENT pencil: the product is being
|
|
47
|
+
// renamed Boost Content and the mark is already drawn for the new name. The
|
|
48
|
+
// slug stays `boostvoice`; the display rename is Identity's (B33-1672).
|
|
49
|
+
boostvoice: {
|
|
50
|
+
optical: 1,
|
|
51
|
+
draw: ({ tile: t, accent: i }) => /* @__PURE__ */ l(e, { children: [
|
|
52
|
+
/* @__PURE__ */ r(
|
|
53
|
+
"path",
|
|
54
|
+
{
|
|
55
|
+
d: "M15.8 3.6 A2 2 0 0 1 18.6 3.6 L20.4 5.4 A2 2 0 0 1 20.4 8.2 L9 19.6 L4 20.5 L4.4 15 Z",
|
|
56
|
+
fill: o,
|
|
57
|
+
stroke: o,
|
|
58
|
+
strokeWidth: "1",
|
|
59
|
+
strokeLinejoin: "round"
|
|
60
|
+
}
|
|
61
|
+
),
|
|
62
|
+
/* @__PURE__ */ r("path", { d: "M13.4 6 L18 10.6", stroke: t, strokeWidth: "1.6", strokeLinecap: "round" }),
|
|
63
|
+
/* @__PURE__ */ r("rect", { x: "13", y: "18.25", width: "8.5", height: "2.75", rx: "1.375", fill: i })
|
|
64
|
+
] })
|
|
65
|
+
},
|
|
66
|
+
// boostoutbound (upstream "Boost Outbound"). A paper plane, its near wing orange.
|
|
67
|
+
boostoutbound: {
|
|
68
|
+
optical: 1,
|
|
69
|
+
draw: ({ tile: t, accent: i }) => /* @__PURE__ */ l(e, { children: [
|
|
70
|
+
/* @__PURE__ */ r(
|
|
71
|
+
"path",
|
|
72
|
+
{
|
|
73
|
+
d: "M21 3 L3 10.4 L10.2 13.8 Z",
|
|
74
|
+
fill: o,
|
|
75
|
+
stroke: o,
|
|
76
|
+
strokeWidth: "1.5",
|
|
77
|
+
strokeLinejoin: "round"
|
|
78
|
+
}
|
|
79
|
+
),
|
|
80
|
+
/* @__PURE__ */ r(
|
|
81
|
+
"path",
|
|
82
|
+
{
|
|
83
|
+
d: "M21 3 L10.2 13.8 L13.6 21 Z",
|
|
84
|
+
fill: i,
|
|
85
|
+
stroke: i,
|
|
86
|
+
strokeWidth: "1.5",
|
|
87
|
+
strokeLinejoin: "round"
|
|
88
|
+
}
|
|
89
|
+
),
|
|
90
|
+
i === o && /* @__PURE__ */ r("path", { d: "M20 4 L10.2 13.8", stroke: t, strokeWidth: "1.4", strokeLinecap: "round" })
|
|
91
|
+
] })
|
|
92
|
+
},
|
|
93
|
+
// brokers (upstream "Boost Brokers"). Two people, the one behind in orange; a
|
|
94
|
+
// tile-coloured outline separates the white figure in front from it.
|
|
95
|
+
brokers: {
|
|
96
|
+
optical: 1,
|
|
97
|
+
draw: ({ tile: t, accent: i }) => /* @__PURE__ */ l(e, { children: [
|
|
98
|
+
/* @__PURE__ */ r("circle", { cx: "16.5", cy: "7.5", r: "3.25", fill: i }),
|
|
99
|
+
/* @__PURE__ */ r("path", { d: "M11 20 A5.5 5.5 0 0 1 22 20 Z", fill: i }),
|
|
100
|
+
/* @__PURE__ */ r("circle", { cx: "9", cy: "7.5", r: "3.75", fill: o, stroke: t, strokeWidth: "1.5" }),
|
|
101
|
+
/* @__PURE__ */ r(
|
|
102
|
+
"path",
|
|
103
|
+
{
|
|
104
|
+
d: "M2 20.5 A7 7 0 0 1 16 20.5 Z",
|
|
105
|
+
fill: o,
|
|
106
|
+
stroke: t,
|
|
107
|
+
strokeWidth: "1.5",
|
|
108
|
+
strokeLinejoin: "round"
|
|
109
|
+
}
|
|
110
|
+
)
|
|
111
|
+
] })
|
|
112
|
+
},
|
|
113
|
+
// boosttrade (upstream "Boost Off Market"). A key -- something not on the open
|
|
114
|
+
// market -- with an orange bow.
|
|
115
|
+
boosttrade: {
|
|
116
|
+
optical: 1,
|
|
117
|
+
draw: ({ tile: t, accent: i }) => /* @__PURE__ */ l(e, { children: [
|
|
118
|
+
/* @__PURE__ */ r("rect", { x: "11", y: "10.6", width: "11", height: "2.8", rx: "1.4", fill: o }),
|
|
119
|
+
/* @__PURE__ */ r("rect", { x: "15.6", y: "11", width: "2.8", height: "5", rx: "1.2", fill: o }),
|
|
120
|
+
/* @__PURE__ */ r("rect", { x: "19.2", y: "11", width: "2.8", height: "3.8", rx: "1.2", fill: o }),
|
|
121
|
+
/* @__PURE__ */ r("circle", { cx: "7.5", cy: "12", r: "5.5", fill: o }),
|
|
122
|
+
/* @__PURE__ */ r("circle", { cx: "7.5", cy: "12", r: "2.6", fill: t }),
|
|
123
|
+
/* @__PURE__ */ r("circle", { cx: "7.5", cy: "12", r: "1.6", fill: i })
|
|
124
|
+
] })
|
|
125
|
+
},
|
|
126
|
+
// boostfunding (upstream "Boost Financing"). A banknote with its coin, an
|
|
127
|
+
// orange note stacked behind it.
|
|
128
|
+
boostfunding: {
|
|
129
|
+
optical: 1,
|
|
130
|
+
draw: ({ tile: t, accent: i }) => /* @__PURE__ */ l(e, { children: [
|
|
131
|
+
/* @__PURE__ */ r("rect", { x: "4.75", y: "4.5", width: "17", height: "11", rx: "2.5", fill: i }),
|
|
132
|
+
/* @__PURE__ */ r("rect", { x: "1", y: "8.25", width: "18.75", height: "12.5", rx: "3.25", fill: t }),
|
|
133
|
+
/* @__PURE__ */ r("rect", { x: "2.25", y: "9.5", width: "16.25", height: "10", rx: "2", fill: o }),
|
|
134
|
+
/* @__PURE__ */ r("circle", { cx: "10.375", cy: "14.5", r: "2.75", fill: t })
|
|
135
|
+
] })
|
|
136
|
+
},
|
|
137
|
+
// boostresults (upstream "Boost Activity"). A pulse line running into an
|
|
138
|
+
// orange dot -- activity, now.
|
|
139
|
+
boostresults: {
|
|
140
|
+
optical: 1,
|
|
141
|
+
draw: ({ accent: t }) => /* @__PURE__ */ l(e, { children: [
|
|
142
|
+
/* @__PURE__ */ r(
|
|
143
|
+
"path",
|
|
144
|
+
{
|
|
145
|
+
d: "M2.5 12.5 H6 L9 5 L14 19 L16.6 12.5 H17",
|
|
146
|
+
fill: "none",
|
|
147
|
+
stroke: o,
|
|
148
|
+
strokeWidth: "2.5",
|
|
149
|
+
strokeLinecap: "round",
|
|
150
|
+
strokeLinejoin: "round"
|
|
151
|
+
}
|
|
152
|
+
),
|
|
153
|
+
/* @__PURE__ */ r("circle", { cx: "20", cy: "12.5", r: "2.5", fill: t })
|
|
154
|
+
] })
|
|
155
|
+
},
|
|
156
|
+
// passport (upstream "Boost Passport"). A passport booklet with an orange globe
|
|
157
|
+
// and a name bar. The globe's meridian and equator are dropped below 24px (see
|
|
158
|
+
// the constant above).
|
|
159
|
+
passport: {
|
|
160
|
+
optical: 0.94,
|
|
161
|
+
draw: ({ tile: t, accent: i, size: c }) => /* @__PURE__ */ l(e, { children: [
|
|
162
|
+
/* @__PURE__ */ r("rect", { x: "4.5", y: "2", width: "15", height: "20", rx: "2.5", fill: o }),
|
|
163
|
+
/* @__PURE__ */ r("circle", { cx: "12", cy: "10", r: "5.75", fill: i === o ? t : i }),
|
|
164
|
+
c >= W && /* @__PURE__ */ l(e, { children: [
|
|
165
|
+
/* @__PURE__ */ r(
|
|
166
|
+
"ellipse",
|
|
167
|
+
{
|
|
168
|
+
cx: "12",
|
|
169
|
+
cy: "10",
|
|
170
|
+
rx: "2.5",
|
|
171
|
+
ry: "5.1",
|
|
172
|
+
fill: "none",
|
|
173
|
+
stroke: i === o ? o : t,
|
|
174
|
+
strokeWidth: "1.3"
|
|
175
|
+
}
|
|
176
|
+
),
|
|
177
|
+
/* @__PURE__ */ r("path", { d: "M6.25 10 H17.75", stroke: i === o ? o : t, strokeWidth: "1.3" })
|
|
178
|
+
] }),
|
|
179
|
+
/* @__PURE__ */ r("rect", { x: "8.5", y: "17.75", width: "7", height: "1.8", rx: "0.9", fill: t })
|
|
180
|
+
] })
|
|
181
|
+
},
|
|
182
|
+
// pipe (upstream "Boost Pipe"). A pipeline narrowing in three stages, the last
|
|
183
|
+
// -- the deal -- orange.
|
|
184
|
+
pipe: {
|
|
185
|
+
optical: 0.96,
|
|
186
|
+
draw: ({ accent: t }) => /* @__PURE__ */ l(e, { children: [
|
|
187
|
+
/* @__PURE__ */ r("rect", { x: "2.5", y: "4", width: "19", height: "4", rx: "2", fill: o }),
|
|
188
|
+
/* @__PURE__ */ r("rect", { x: "6", y: "10", width: "12", height: "4", rx: "2", fill: o }),
|
|
189
|
+
/* @__PURE__ */ r("rect", { x: "9.5", y: "16", width: "5", height: "4", rx: "2", fill: t })
|
|
190
|
+
] })
|
|
191
|
+
}
|
|
30
192
|
};
|
|
31
|
-
function
|
|
32
|
-
return
|
|
193
|
+
function k(t) {
|
|
194
|
+
return g.includes(t);
|
|
33
195
|
}
|
|
34
|
-
function
|
|
35
|
-
return
|
|
196
|
+
function _(t) {
|
|
197
|
+
return k(t);
|
|
36
198
|
}
|
|
37
|
-
function
|
|
38
|
-
const
|
|
39
|
-
return /* @__PURE__ */
|
|
199
|
+
function j({ slug: t, size: i = w, muted: c, title: n, className: f }) {
|
|
200
|
+
const x = L(), s = n == null, h = k(t) ? E[t] : null, p = c ? m : M, y = c ? o : b;
|
|
201
|
+
return /* @__PURE__ */ l(
|
|
40
202
|
"svg",
|
|
41
203
|
{
|
|
42
|
-
className:
|
|
43
|
-
width:
|
|
44
|
-
height:
|
|
45
|
-
viewBox:
|
|
46
|
-
role:
|
|
47
|
-
"aria-hidden":
|
|
48
|
-
"aria-labelledby":
|
|
204
|
+
className: f != null ? `${a.mark} ${f}` : a.mark,
|
|
205
|
+
width: i,
|
|
206
|
+
height: i,
|
|
207
|
+
viewBox: `0 0 ${d} ${d}`,
|
|
208
|
+
role: s ? void 0 : "img",
|
|
209
|
+
"aria-hidden": s ? "true" : void 0,
|
|
210
|
+
"aria-labelledby": s ? void 0 : x,
|
|
49
211
|
children: [
|
|
50
|
-
!
|
|
51
|
-
/* @__PURE__ */ r(
|
|
52
|
-
|
|
53
|
-
{
|
|
54
|
-
className: i.ground,
|
|
55
|
-
width: "40",
|
|
56
|
-
height: "40",
|
|
57
|
-
style: { fill: a ? "var(--color-neutral-300)" : "var(--color-neutral-950)" }
|
|
58
|
-
}
|
|
59
|
-
),
|
|
60
|
-
u && /* @__PURE__ */ r(
|
|
61
|
-
"g",
|
|
62
|
-
{
|
|
63
|
-
transform: "translate(10 10) scale(0.5)",
|
|
64
|
-
style: { color: "var(--color-primary-foreground)" },
|
|
65
|
-
children: u
|
|
66
|
-
}
|
|
67
|
-
)
|
|
212
|
+
!s && /* @__PURE__ */ r("title", { id: x, children: n }),
|
|
213
|
+
/* @__PURE__ */ r("rect", { className: a.ground, width: d, height: d, style: { fill: p } }),
|
|
214
|
+
h && /* @__PURE__ */ r("g", { transform: I(h.optical), children: h.draw({ tile: p, accent: y, size: i }) })
|
|
68
215
|
]
|
|
69
216
|
}
|
|
70
217
|
);
|
|
71
218
|
}
|
|
219
|
+
function I(t) {
|
|
220
|
+
const i = d * v * t, c = u((d - i) / 2), n = u(i / 24);
|
|
221
|
+
return `translate(${c} ${c}) scale(${n})`;
|
|
222
|
+
}
|
|
223
|
+
function u(t) {
|
|
224
|
+
return Math.round(t * 1e4) / 1e4;
|
|
225
|
+
}
|
|
72
226
|
export {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
227
|
+
g as PRODUCT_SLUGS,
|
|
228
|
+
j as ProductMark,
|
|
229
|
+
_ as hasProductMark
|
|
76
230
|
};
|
|
77
231
|
//# sourceMappingURL=ProductMark.js.map
|