@krizaka/ui 3.37.0 → 3.39.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.
Files changed (63) hide show
  1. package/dist/blocks.css +36 -36
  2. package/dist/chip-link.js +1 -1
  3. package/dist/chip-row.js +1 -1
  4. package/dist/{chunk-IANSFIVC.js → chunk-7JFHTPI3.js} +13 -3
  5. package/dist/chunk-7JFHTPI3.js.map +1 -0
  6. package/dist/{chunk-RE5WJ4QP.js → chunk-ADRUEPYC.js} +4 -4
  7. package/dist/chunk-ADRUEPYC.js.map +1 -0
  8. package/dist/{chunk-BTTDIVVJ.js → chunk-F2UZ2WWL.js} +2 -2
  9. package/dist/chunk-F2UZ2WWL.js.map +1 -0
  10. package/dist/image-cropper.js +1 -1
  11. package/dist/kanban.js +1 -1
  12. package/dist/kanban.js.map +1 -1
  13. package/dist/landing-page.js +1 -6
  14. package/dist/landing-page.js.map +1 -1
  15. package/dist/map.js +2 -2
  16. package/dist/map.js.map +1 -1
  17. package/dist/motion.css +3 -3
  18. package/dist/native/vertical-video.js +1 -1
  19. package/dist/native/vertical-video.js.map +1 -1
  20. package/dist/native.d.ts +1 -1
  21. package/dist/native.js +11 -11
  22. package/dist/native.js.map +1 -1
  23. package/dist/nav-bar.d.ts +1 -1
  24. package/dist/nav-bar.js +1 -1
  25. package/dist/photo-grid.js +1 -1
  26. package/dist/photo-grid.js.map +1 -1
  27. package/dist/product-page.js +1 -6
  28. package/dist/product-page.js.map +1 -1
  29. package/dist/site-footer.d.ts +5 -17
  30. package/dist/site-footer.js +33 -29
  31. package/dist/site-footer.js.map +1 -1
  32. package/dist/{sites-B4sYlfPQ.d.ts → sites-inztN_Bv.d.ts} +8 -0
  33. package/dist/sites.d.ts +11 -1
  34. package/dist/sites.js +12 -2
  35. package/dist/sites.js.map +1 -1
  36. package/dist/slider.js +3 -3
  37. package/dist/slider.js.map +1 -1
  38. package/dist/step-showcase.js +1 -1
  39. package/dist/step-showcase.js.map +1 -1
  40. package/dist/story.css +3 -3
  41. package/dist/video-player.js +1 -1
  42. package/dist/video-trimmer.js +1 -1
  43. package/dist/video-trimmer.js.map +1 -1
  44. package/package.json +3 -3
  45. package/registry/chip-link.json +1 -1
  46. package/registry/examples/site-footer/company.js +0 -4
  47. package/registry/examples/site-footer/company.tsx +3 -7
  48. package/registry/index.json +7 -7
  49. package/registry/kanban.json +1 -1
  50. package/registry/landing-page.json +1 -1
  51. package/registry/map.json +2 -2
  52. package/registry/nav-bar.json +1 -1
  53. package/registry/photo-grid.json +1 -1
  54. package/registry/product-page.json +1 -1
  55. package/registry/rail-nav.json +1 -1
  56. package/registry/site-footer.json +10 -10
  57. package/registry/sites.json +2 -2
  58. package/registry/slider.json +1 -1
  59. package/registry/step-showcase.json +1 -1
  60. package/registry/video-trimmer.json +1 -1
  61. package/dist/chunk-BTTDIVVJ.js.map +0 -1
  62. package/dist/chunk-IANSFIVC.js.map +0 -1
  63. package/dist/chunk-RE5WJ4QP.js.map +0 -1
package/dist/nav-bar.d.ts CHANGED
@@ -2,7 +2,7 @@ import * as tailwind_variants from 'tailwind-variants';
2
2
  import { NavigationMenu } from 'radix-ui';
3
3
  import * as React from 'react';
4
4
  import { LanguageSwitchProps } from './language-switch.js';
5
- import { S as SiteId, F as FamilyLabels } from './sites-B4sYlfPQ.js';
5
+ import { S as SiteId, F as FamilyLabels } from './sites-inztN_Bv.js';
6
6
 
7
7
  declare const navBar: tailwind_variants.TVReturnType<{
8
8
  floating: {
package/dist/nav-bar.js CHANGED
@@ -4,7 +4,7 @@ import {
4
4
  GitHubGlyph,
5
5
  familyLabels,
6
6
  sitesByGroup
7
- } from "./chunk-IANSFIVC.js";
7
+ } from "./chunk-7JFHTPI3.js";
8
8
  import {
9
9
  LanguageSwitch
10
10
  } from "./chunk-VPO27AFS.js";
@@ -13,7 +13,7 @@ var photoGrid = tv({
13
13
  slot: "relative aspect-[3/4] overflow-hidden rounded-xl",
14
14
  photo: "group h-full w-full cursor-grab bg-surface-3 outline-hidden focus-visible:ring-2 focus-visible:ring-ring data-[over]:ring-2 data-[over]:ring-accent active:cursor-grabbing",
15
15
  image: "h-full w-full object-cover",
16
- main: "absolute bottom-2 left-2 rounded-full bg-accent px-2 py-0.5 text-[10px] font-extrabold text-on-accent",
16
+ main: "absolute bottom-2 left-2 rounded-sm bg-accent px-2 py-0.5 text-[10px] font-extrabold text-on-accent",
17
17
  tools: "absolute right-1.5 top-1.5 flex gap-1 opacity-0 transition-opacity group-hover:opacity-100 group-focus-within:opacity-100 focus-within:opacity-100 motion-reduce:transition-none",
18
18
  tool: "inline-flex h-7 w-7 items-center justify-center rounded-full bg-scrim text-fg-on-media hover:bg-scrim-strong focus-visible:opacity-100 focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring",
19
19
  empty: "flex h-full w-full flex-col items-center justify-center gap-2 rounded-xl border-[1.5px] border-dashed border-border-strong bg-surface-1 text-xs font-semibold text-fg-secondary hover:bg-surface-2 focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring disabled:opacity-50 data-[required]:border-accent",
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/photo-grid/photo-grid.tsx"],"sourcesContent":["// Client. A profile's photos in a grid of slots: the first is the main one; drag a photo onto another to reorder, or use\n// its menu (make main, earlier, later, remove) — the keyboard way, every move announced.\nimport * as React from \"react\";\nimport { tv } from \"tailwind-variants\";\n\nimport { PlusGlyph } from \"../glyphs\";\n\nexport const photoGrid = tv({\n slots: {\n root: \"grid gap-2\",\n slot: \"relative aspect-[3/4] overflow-hidden rounded-xl\",\n photo: \"group h-full w-full cursor-grab bg-surface-3 outline-hidden focus-visible:ring-2 focus-visible:ring-ring data-[over]:ring-2 data-[over]:ring-accent active:cursor-grabbing\",\n image: \"h-full w-full object-cover\",\n main: \"absolute bottom-2 left-2 rounded-full bg-accent px-2 py-0.5 text-[10px] font-extrabold text-on-accent\",\n tools: \"absolute right-1.5 top-1.5 flex gap-1 opacity-0 transition-opacity group-hover:opacity-100 group-focus-within:opacity-100 focus-within:opacity-100 motion-reduce:transition-none\",\n tool: \"inline-flex h-7 w-7 items-center justify-center rounded-full bg-scrim text-fg-on-media hover:bg-scrim-strong focus-visible:opacity-100 focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring\",\n empty:\n \"flex h-full w-full flex-col items-center justify-center gap-2 rounded-xl border-[1.5px] border-dashed border-border-strong bg-surface-1 text-xs font-semibold text-fg-secondary \" +\n \"hover:bg-surface-2 focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring disabled:opacity-50 data-[required]:border-accent\",\n plus: \"flex h-8 w-8 items-center justify-center rounded-full bg-surface-3 data-[next]:bg-accent data-[next]:text-on-accent [&>svg]:h-4 [&>svg]:w-4\",\n },\n});\n\nexport type GridPhoto = {\n /** A stable id. */\n id: string;\n /** Its URL. */\n src: string;\n /** What it shows — its text alternative. */\n alt?: string;\n};\n\nexport type PhotoGridLabels = {\n /** An empty slot (“Add a photo”). */\n add: string;\n /** The first photo's badge (“Main”). */\n main: string;\n /** A photo's name: `(n) => \"Photo \" + n`. */\n photo: (position: number) => string;\n /** Move earlier. */\n moveEarlier: string;\n /** Move later. */\n moveLater: string;\n /** Remove. */\n remove: string;\n /** Announced after a move: `(n) => \"Moved to place \" + n`. */\n moved: (position: number) => string;\n};\n\nexport type PhotoGridProps = {\n /** The photos, in order: the first is the main one. */\n value: readonly GridPhoto[];\n /** Called with the new order, or without a removed photo. */\n onValueChange: (photos: GridPhoto[]) => void;\n /** Called by an empty slot: open the file picker, the camera, the editor. */\n onAdd?: () => void;\n /** How many slots. Default 6. */\n slots?: number;\n /** Fewest photos required: the empty slots up to it are marked. Default 1. */\n required?: number;\n /** Columns. Default 3. */\n columns?: number;\n /** The words, passed translated. */\n labels: PhotoGridLabels;\n /** Classes merged on the root. */\n className?: string;\n};\n\n/** A profile's photos in slots: drag to reorder, or each photo's buttons (earlier, later, remove), every move announced. */\nexport function PhotoGrid({ value, onValueChange, onAdd, slots = 6, required = 1, columns = 3, labels, className }: PhotoGridProps) {\n const s = photoGrid();\n const [dragged, setDragged] = React.useState<number | null>(null);\n const [over, setOver] = React.useState<number | null>(null);\n const [message, setMessage] = React.useState(\"\");\n const move = (from: number, to: number) => {\n if (to < 0 || to >= value.length || from === to) return;\n const next = [...value];\n const [photo] = next.splice(from, 1);\n next.splice(to, 0, photo!);\n onValueChange(next);\n setMessage(labels.moved(to + 1));\n };\n return (\n <div className={s.root({ className })} style={{ gridTemplateColumns: `repeat(${columns}, minmax(0, 1fr))` }}>\n <p className=\"sr-only\" aria-live=\"polite\">\n {message}\n </p>\n {Array.from({ length: slots }, (_, i) => {\n const photo = value[i];\n if (!photo) {\n return (\n <div key={`empty-${i}`} className={s.slot()}>\n <button type=\"button\" disabled={!onAdd || i > value.length} onClick={onAdd} data-required={i < required || undefined} className={s.empty()}>\n <span className={s.plus()} data-next={i === value.length || undefined}>\n <PlusGlyph />\n </span>\n {i === value.length ? labels.add : <span className=\"sr-only\">{labels.add}</span>}\n </button>\n </div>\n );\n }\n const name = [labels.photo(i + 1), photo.alt, i === 0 ? labels.main : null].filter(Boolean).join(\", \");\n return (\n <div key={photo.id} className={s.slot()}>\n <div\n role=\"group\"\n aria-label={name}\n draggable\n tabIndex={0}\n data-over={over === i || undefined}\n className={s.photo()}\n onDragStart={(e) => {\n e.dataTransfer.effectAllowed = \"move\";\n setDragged(i);\n }}\n onDragOver={(e) => {\n if (dragged === null) return;\n e.preventDefault();\n setOver(i);\n }}\n onDragLeave={() => setOver(null)}\n onDrop={(e) => {\n e.preventDefault();\n if (dragged !== null) move(dragged, i);\n setDragged(null);\n setOver(null);\n }}\n onDragEnd={() => {\n setDragged(null);\n setOver(null);\n }}\n >\n <img src={photo.src} alt={photo.alt ?? \"\"} className={s.image()} draggable={false} />\n {i === 0 ? <span className={s.main()} aria-hidden>{labels.main}</span> : null}\n <div className={s.tools()}>\n {i > 0 ? (\n <button type=\"button\" aria-label={`${labels.moveEarlier} — ${labels.photo(i + 1)}`} className={s.tool()} onClick={() => move(i, i - 1)}>\n <svg viewBox=\"0 0 24 24\" className=\"h-4 w-4\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.4\" strokeLinecap=\"round\" aria-hidden><path d=\"M15 5l-7 7 7 7\" /></svg>\n </button>\n ) : null}\n {i < value.length - 1 ? (\n <button type=\"button\" aria-label={`${labels.moveLater} — ${labels.photo(i + 1)}`} className={s.tool()} onClick={() => move(i, i + 1)}>\n <svg viewBox=\"0 0 24 24\" className=\"h-4 w-4\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.4\" strokeLinecap=\"round\" aria-hidden><path d=\"M9 5l7 7-7 7\" /></svg>\n </button>\n ) : null}\n <button type=\"button\" aria-label={`${labels.remove} — ${labels.photo(i + 1)}`} className={s.tool()} onClick={() => onValueChange(value.filter((_, j) => j !== i))}>\n <svg viewBox=\"0 0 24 24\" className=\"h-4 w-4\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.4\" strokeLinecap=\"round\" aria-hidden><path d=\"M18 6 6 18M6 6l12 12\" /></svg>\n </button>\n </div>\n </div>\n </div>\n );\n })}\n </div>\n );\n}\n"],"mappings":"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","names":["_"]}
1
+ {"version":3,"sources":["../src/photo-grid/photo-grid.tsx"],"sourcesContent":["// Client. A profile's photos in a grid of slots: the first is the main one; drag a photo onto another to reorder, or use\n// its menu (make main, earlier, later, remove) — the keyboard way, every move announced.\nimport * as React from \"react\";\nimport { tv } from \"tailwind-variants\";\n\nimport { PlusGlyph } from \"../glyphs\";\n\nexport const photoGrid = tv({\n slots: {\n root: \"grid gap-2\",\n slot: \"relative aspect-[3/4] overflow-hidden rounded-xl\",\n photo: \"group h-full w-full cursor-grab bg-surface-3 outline-hidden focus-visible:ring-2 focus-visible:ring-ring data-[over]:ring-2 data-[over]:ring-accent active:cursor-grabbing\",\n image: \"h-full w-full object-cover\",\n main: \"absolute bottom-2 left-2 rounded-sm bg-accent px-2 py-0.5 text-[10px] font-extrabold text-on-accent\",\n tools: \"absolute right-1.5 top-1.5 flex gap-1 opacity-0 transition-opacity group-hover:opacity-100 group-focus-within:opacity-100 focus-within:opacity-100 motion-reduce:transition-none\",\n tool: \"inline-flex h-7 w-7 items-center justify-center rounded-full bg-scrim text-fg-on-media hover:bg-scrim-strong focus-visible:opacity-100 focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring\",\n empty:\n \"flex h-full w-full flex-col items-center justify-center gap-2 rounded-xl border-[1.5px] border-dashed border-border-strong bg-surface-1 text-xs font-semibold text-fg-secondary \" +\n \"hover:bg-surface-2 focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring disabled:opacity-50 data-[required]:border-accent\",\n plus: \"flex h-8 w-8 items-center justify-center rounded-full bg-surface-3 data-[next]:bg-accent data-[next]:text-on-accent [&>svg]:h-4 [&>svg]:w-4\",\n },\n});\n\nexport type GridPhoto = {\n /** A stable id. */\n id: string;\n /** Its URL. */\n src: string;\n /** What it shows — its text alternative. */\n alt?: string;\n};\n\nexport type PhotoGridLabels = {\n /** An empty slot (“Add a photo”). */\n add: string;\n /** The first photo's badge (“Main”). */\n main: string;\n /** A photo's name: `(n) => \"Photo \" + n`. */\n photo: (position: number) => string;\n /** Move earlier. */\n moveEarlier: string;\n /** Move later. */\n moveLater: string;\n /** Remove. */\n remove: string;\n /** Announced after a move: `(n) => \"Moved to place \" + n`. */\n moved: (position: number) => string;\n};\n\nexport type PhotoGridProps = {\n /** The photos, in order: the first is the main one. */\n value: readonly GridPhoto[];\n /** Called with the new order, or without a removed photo. */\n onValueChange: (photos: GridPhoto[]) => void;\n /** Called by an empty slot: open the file picker, the camera, the editor. */\n onAdd?: () => void;\n /** How many slots. Default 6. */\n slots?: number;\n /** Fewest photos required: the empty slots up to it are marked. Default 1. */\n required?: number;\n /** Columns. Default 3. */\n columns?: number;\n /** The words, passed translated. */\n labels: PhotoGridLabels;\n /** Classes merged on the root. */\n className?: string;\n};\n\n/** A profile's photos in slots: drag to reorder, or each photo's buttons (earlier, later, remove), every move announced. */\nexport function PhotoGrid({ value, onValueChange, onAdd, slots = 6, required = 1, columns = 3, labels, className }: PhotoGridProps) {\n const s = photoGrid();\n const [dragged, setDragged] = React.useState<number | null>(null);\n const [over, setOver] = React.useState<number | null>(null);\n const [message, setMessage] = React.useState(\"\");\n const move = (from: number, to: number) => {\n if (to < 0 || to >= value.length || from === to) return;\n const next = [...value];\n const [photo] = next.splice(from, 1);\n next.splice(to, 0, photo!);\n onValueChange(next);\n setMessage(labels.moved(to + 1));\n };\n return (\n <div className={s.root({ className })} style={{ gridTemplateColumns: `repeat(${columns}, minmax(0, 1fr))` }}>\n <p className=\"sr-only\" aria-live=\"polite\">\n {message}\n </p>\n {Array.from({ length: slots }, (_, i) => {\n const photo = value[i];\n if (!photo) {\n return (\n <div key={`empty-${i}`} className={s.slot()}>\n <button type=\"button\" disabled={!onAdd || i > value.length} onClick={onAdd} data-required={i < required || undefined} className={s.empty()}>\n <span className={s.plus()} data-next={i === value.length || undefined}>\n <PlusGlyph />\n </span>\n {i === value.length ? labels.add : <span className=\"sr-only\">{labels.add}</span>}\n </button>\n </div>\n );\n }\n const name = [labels.photo(i + 1), photo.alt, i === 0 ? labels.main : null].filter(Boolean).join(\", \");\n return (\n <div key={photo.id} className={s.slot()}>\n <div\n role=\"group\"\n aria-label={name}\n draggable\n tabIndex={0}\n data-over={over === i || undefined}\n className={s.photo()}\n onDragStart={(e) => {\n e.dataTransfer.effectAllowed = \"move\";\n setDragged(i);\n }}\n onDragOver={(e) => {\n if (dragged === null) return;\n e.preventDefault();\n setOver(i);\n }}\n onDragLeave={() => setOver(null)}\n onDrop={(e) => {\n e.preventDefault();\n if (dragged !== null) move(dragged, i);\n setDragged(null);\n setOver(null);\n }}\n onDragEnd={() => {\n setDragged(null);\n setOver(null);\n }}\n >\n <img src={photo.src} alt={photo.alt ?? \"\"} className={s.image()} draggable={false} />\n {i === 0 ? <span className={s.main()} aria-hidden>{labels.main}</span> : null}\n <div className={s.tools()}>\n {i > 0 ? (\n <button type=\"button\" aria-label={`${labels.moveEarlier} — ${labels.photo(i + 1)}`} className={s.tool()} onClick={() => move(i, i - 1)}>\n <svg viewBox=\"0 0 24 24\" className=\"h-4 w-4\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.4\" strokeLinecap=\"round\" aria-hidden><path d=\"M15 5l-7 7 7 7\" /></svg>\n </button>\n ) : null}\n {i < value.length - 1 ? (\n <button type=\"button\" aria-label={`${labels.moveLater} — ${labels.photo(i + 1)}`} className={s.tool()} onClick={() => move(i, i + 1)}>\n <svg viewBox=\"0 0 24 24\" className=\"h-4 w-4\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.4\" strokeLinecap=\"round\" aria-hidden><path d=\"M9 5l7 7-7 7\" /></svg>\n </button>\n ) : null}\n <button type=\"button\" aria-label={`${labels.remove} — ${labels.photo(i + 1)}`} className={s.tool()} onClick={() => onValueChange(value.filter((_, j) => j !== i))}>\n <svg viewBox=\"0 0 24 24\" className=\"h-4 w-4\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.4\" strokeLinecap=\"round\" aria-hidden><path d=\"M18 6 6 18M6 6l12 12\" /></svg>\n </button>\n </div>\n </div>\n </div>\n );\n })}\n </div>\n );\n}\n"],"mappings":"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","names":["_"]}
@@ -24,12 +24,7 @@ function ProductPage({ brand, mark, title, lead, facts, actions, visual, visualL
24
24
  ] })
25
25
  ] }),
26
26
  visual && /* @__PURE__ */ jsxs("figure", { className: "kz-tpl-stage", children: [
27
- /* @__PURE__ */ jsxs("div", { className: "kz-tpl-stage-bar", "aria-hidden": true, children: [
28
- /* @__PURE__ */ jsx("i", {}),
29
- /* @__PURE__ */ jsx("i", {}),
30
- /* @__PURE__ */ jsx("i", {}),
31
- visualLabel && /* @__PURE__ */ jsx("span", { children: visualLabel })
32
- ] }),
27
+ /* @__PURE__ */ jsx("div", { className: "kz-tpl-stage-bar", "aria-hidden": true, children: visualLabel && /* @__PURE__ */ jsx("span", { children: visualLabel }) }),
33
28
  visual
34
29
  ] })
35
30
  ] }) }) }),
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/product-page/product-page.tsx"],"sourcesContent":["// Server-safe. A product's overview: the hero with the product's mark, its promise, facts and main action beside a live\n// window of the product; the traps it removes as compact argument cards; its decisions with their cost; the promise a\n// bird keeps; the closing call. Under the product's brand (`brand` → `.brand-<id>`).\nimport { ArgumentCard } from \"@krizaka/ui/argument-card\";\nimport { CardGrid } from \"@krizaka/ui/card-grid\";\nimport { CtaPanel } from \"@krizaka/ui/cta-panel\";\nimport { type Decision, DecisionList } from \"@krizaka/ui/decision-list\";\nimport { MascotQuote } from \"@krizaka/ui/mascot-quote\";\nimport type { MascotBird } from \"@krizaka/ui/mascots\";\nimport { type Fact, Facts, Page, Section } from \"@krizaka/ui/page\";\nimport type { LinkComponent } from \"@krizaka/ui/page-hero\";\nimport { SectionBackdrop } from \"@krizaka/ui/section-backdrop\";\nimport type * as React from \"react\";\n\nimport { cn } from \"../cn\";\n\nexport interface ProductReason {\n /** A stable key (the card's anchor). */\n id: string;\n /** Its name. */\n title: React.ReactNode;\n /** The trap elsewhere, in one line. */\n trap: React.ReactNode;\n /** The signature icon. */\n icon?: React.ReactNode;\n /** The bird in the corner (whose rule it is). */\n mark?: React.ReactNode;\n /** Where the long version lives (a page) — or nothing, and the card stays its face. */\n href?: string;\n}\n\nexport type ProductPageProps = Omit<React.HTMLAttributes<HTMLElement>, \"title\"> & {\n /** The product's brand (`orazaka`, `orochia`…): the page wears `.brand-<id>`. */\n brand?: string;\n /** The product's mark and name, above the title. */\n mark?: React.ReactNode;\n /** The promise: the page's `h1`. */\n title: React.ReactNode;\n /** One or two sentences under it. */\n lead?: React.ReactNode;\n /** Facts under the lead (open source, a law it keeps). */\n facts?: readonly Fact[];\n /** The hero's actions. */\n actions?: React.ReactNode;\n /** The product alive, in a window beside the words. */\n visual?: React.ReactNode;\n /** The window's caption. */\n visualLabel?: React.ReactNode;\n /** The reasons' section heading. */\n reasonsHeading: { eyebrow?: React.ReactNode; title: React.ReactNode; lead?: React.ReactNode };\n /** The words of the cards: the trap's label (read, not shown) and the way in. */\n reasonLabels: { trap: string; more: React.ReactNode };\n /** The traps it removes. */\n reasons: readonly ProductReason[];\n /** The decisions' section: heading, decisions and their four labels. */\n decisions?: { eyebrow?: React.ReactNode; title: React.ReactNode; items: readonly Decision[]; labels: { chose: React.ReactNode; refused: React.ReactNode; because: React.ReactNode; cost: React.ReactNode } };\n /** The promise a bird keeps, under the decisions. */\n promise?: { bird: MascotBird; label: React.ReactNode; text: React.ReactNode };\n /** More sections between the decisions and the closing call (the tour, the platform, a comparison). */\n children?: React.ReactNode;\n /** The closing call. */\n closing?: { title: React.ReactNode; body?: React.ReactNode; actions: React.ReactNode };\n /** The app's link component (Next's `Link`). */\n linkAs?: LinkComponent;\n};\n\n/** A product's overview: split hero, traps as compact cards, decisions with their cost, the bird's promise, closing call. */\nexport function ProductPage({ brand, mark, title, lead, facts, actions, visual, visualLabel, reasonsHeading, reasonLabels, reasons, decisions, promise, closing, linkAs, className, children, ...props }: ProductPageProps) {\n return (\n <div className={cn(brand && \"brand-\" + brand, className)} {...props}>\n <SectionBackdrop as=\"header\" grid className=\"kz-hero\">\n <Page>\n <div className={visual ? \"kz-tpl-split\" : undefined}>\n <div className=\"kz-hero-text\">\n {mark && <p className=\"kz-eyebrow\">{mark}</p>}\n <h1 className=\"kz-hero-title\">{title}</h1>\n {lead && <p className=\"kz-hero-lead\">{lead}</p>}\n {(facts || actions) && (\n <div className=\"kz-hero-extra\">\n {facts && <Facts items={facts} />}\n {actions && <div className=\"kz-tpl-actions\">{actions}</div>}\n </div>\n )}\n </div>\n {visual && (\n <figure className=\"kz-tpl-stage\">\n <div className=\"kz-tpl-stage-bar\" aria-hidden>\n <i />\n <i />\n <i />\n {visualLabel && <span>{visualLabel}</span>}\n </div>\n {visual}\n </figure>\n )}\n </div>\n </Page>\n </SectionBackdrop>\n <Section id=\"why\" eyebrow={reasonsHeading.eyebrow} title={reasonsHeading.title} lead={reasonsHeading.lead} reveal>\n <CardGrid min={260} fit=\"fit\">\n {reasons.map((r) => (\n <ArgumentCard\n key={r.id}\n id={`why-${r.id}`}\n icon={r.icon}\n title={r.title}\n mark={r.mark}\n hook={{ label: reasonLabels.trap, text: r.trap }}\n more={r.href ? { href: r.href, label: reasonLabels.more } : undefined}\n linkAs={linkAs}\n />\n ))}\n </CardGrid>\n </Section>\n {decisions && (\n <Section id=\"decisions\" eyebrow={decisions.eyebrow} title={decisions.title} divider reveal>\n <DecisionList decisions={decisions.items} labels={decisions.labels} />\n {promise && (\n <div className=\"kz-tpl-promise\">\n <MascotQuote variant=\"callout\" bird={promise.bird} mood=\"welcome\" label={promise.label}>\n {promise.text}\n </MascotQuote>\n </div>\n )}\n </Section>\n )}\n {children}\n {closing && (\n <Section spacing=\"sm\" aria-labelledby=\"product-closing\">\n <CtaPanel id=\"product-closing\" title={closing.title} body={closing.body} reveal>\n {closing.actions}\n </CtaPanel>\n </Section>\n )}\n </div>\n );\n}\n"],"mappings":";;;;;AAGA,SAAS,oBAAoB;AAC7B,SAAS,gBAAgB;AACzB,SAAS,gBAAgB;AACzB,SAAwB,oBAAoB;AAC5C,SAAS,mBAAmB;AAE5B,SAAoB,OAAO,MAAM,eAAe;AAEhD,SAAS,uBAAuB;AA+DT,cAIP,YAJO;AAPhB,SAAS,YAAY,EAAE,OAAO,MAAM,OAAO,MAAM,OAAO,SAAS,QAAQ,aAAa,gBAAgB,cAAc,SAAS,WAAW,SAAS,SAAS,QAAQ,WAAW,UAAU,GAAG,MAAM,GAAqB;AAC1N,SACE,qBAAC,SAAI,WAAW,GAAG,SAAS,WAAW,OAAO,SAAS,GAAI,GAAG,OAC5D;AAAA,wBAAC,mBAAgB,IAAG,UAAS,MAAI,MAAC,WAAU,WAC1C,8BAAC,QACC,+BAAC,SAAI,WAAW,SAAS,iBAAiB,QACxC;AAAA,2BAAC,SAAI,WAAU,gBACZ;AAAA,gBAAQ,oBAAC,OAAE,WAAU,cAAc,gBAAK;AAAA,QACzC,oBAAC,QAAG,WAAU,iBAAiB,iBAAM;AAAA,QACpC,QAAQ,oBAAC,OAAE,WAAU,gBAAgB,gBAAK;AAAA,SACzC,SAAS,YACT,qBAAC,SAAI,WAAU,iBACZ;AAAA,mBAAS,oBAAC,SAAM,OAAO,OAAO;AAAA,UAC9B,WAAW,oBAAC,SAAI,WAAU,kBAAkB,mBAAQ;AAAA,WACvD;AAAA,SAEJ;AAAA,MACC,UACC,qBAAC,YAAO,WAAU,gBAChB;AAAA,6BAAC,SAAI,WAAU,oBAAmB,eAAW,MAC3C;AAAA,8BAAC,OAAE;AAAA,UACH,oBAAC,OAAE;AAAA,UACH,oBAAC,OAAE;AAAA,UACF,eAAe,oBAAC,UAAM,uBAAY;AAAA,WACrC;AAAA,QACC;AAAA,SACH;AAAA,OAEJ,GACF,GACF;AAAA,IACA,oBAAC,WAAQ,IAAG,OAAM,SAAS,eAAe,SAAS,OAAO,eAAe,OAAO,MAAM,eAAe,MAAM,QAAM,MAC/G,8BAAC,YAAS,KAAK,KAAK,KAAI,OACrB,kBAAQ,IAAI,CAAC,MACZ;AAAA,MAAC;AAAA;AAAA,QAEC,IAAI,OAAO,EAAE,EAAE;AAAA,QACf,MAAM,EAAE;AAAA,QACR,OAAO,EAAE;AAAA,QACT,MAAM,EAAE;AAAA,QACR,MAAM,EAAE,OAAO,aAAa,MAAM,MAAM,EAAE,KAAK;AAAA,QAC/C,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,OAAO,aAAa,KAAK,IAAI;AAAA,QAC5D;AAAA;AAAA,MAPK,EAAE;AAAA,IAQT,CACD,GACH,GACF;AAAA,IACC,aACC,qBAAC,WAAQ,IAAG,aAAY,SAAS,UAAU,SAAS,OAAO,UAAU,OAAO,SAAO,MAAC,QAAM,MACxF;AAAA,0BAAC,gBAAa,WAAW,UAAU,OAAO,QAAQ,UAAU,QAAQ;AAAA,MACnE,WACC,oBAAC,SAAI,WAAU,kBACb,8BAAC,eAAY,SAAQ,WAAU,MAAM,QAAQ,MAAM,MAAK,WAAU,OAAO,QAAQ,OAC9E,kBAAQ,MACX,GACF;AAAA,OAEJ;AAAA,IAED;AAAA,IACA,WACC,oBAAC,WAAQ,SAAQ,MAAK,mBAAgB,mBACpC,8BAAC,YAAS,IAAG,mBAAkB,OAAO,QAAQ,OAAO,MAAM,QAAQ,MAAM,QAAM,MAC5E,kBAAQ,SACX,GACF;AAAA,KAEJ;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../src/product-page/product-page.tsx"],"sourcesContent":["// Server-safe. A product's overview: the hero with the product's mark, its promise, facts and main action beside a live\n// window of the product; the traps it removes as compact argument cards; its decisions with their cost; the promise a\n// bird keeps; the closing call. Under the product's brand (`brand` → `.brand-<id>`).\nimport { ArgumentCard } from \"@krizaka/ui/argument-card\";\nimport { CardGrid } from \"@krizaka/ui/card-grid\";\nimport { CtaPanel } from \"@krizaka/ui/cta-panel\";\nimport { type Decision, DecisionList } from \"@krizaka/ui/decision-list\";\nimport { MascotQuote } from \"@krizaka/ui/mascot-quote\";\nimport type { MascotBird } from \"@krizaka/ui/mascots\";\nimport { type Fact, Facts, Page, Section } from \"@krizaka/ui/page\";\nimport type { LinkComponent } from \"@krizaka/ui/page-hero\";\nimport { SectionBackdrop } from \"@krizaka/ui/section-backdrop\";\nimport type * as React from \"react\";\n\nimport { cn } from \"../cn\";\n\nexport interface ProductReason {\n /** A stable key (the card's anchor). */\n id: string;\n /** Its name. */\n title: React.ReactNode;\n /** The trap elsewhere, in one line. */\n trap: React.ReactNode;\n /** The signature icon. */\n icon?: React.ReactNode;\n /** The bird in the corner (whose rule it is). */\n mark?: React.ReactNode;\n /** Where the long version lives (a page) — or nothing, and the card stays its face. */\n href?: string;\n}\n\nexport type ProductPageProps = Omit<React.HTMLAttributes<HTMLElement>, \"title\"> & {\n /** The product's brand (`orazaka`, `orochia`…): the page wears `.brand-<id>`. */\n brand?: string;\n /** The product's mark and name, above the title. */\n mark?: React.ReactNode;\n /** The promise: the page's `h1`. */\n title: React.ReactNode;\n /** One or two sentences under it. */\n lead?: React.ReactNode;\n /** Facts under the lead (open source, a law it keeps). */\n facts?: readonly Fact[];\n /** The hero's actions. */\n actions?: React.ReactNode;\n /** The product alive, in a window beside the words. */\n visual?: React.ReactNode;\n /** The window's caption. */\n visualLabel?: React.ReactNode;\n /** The reasons' section heading. */\n reasonsHeading: { eyebrow?: React.ReactNode; title: React.ReactNode; lead?: React.ReactNode };\n /** The words of the cards: the trap's label (read, not shown) and the way in. */\n reasonLabels: { trap: string; more: React.ReactNode };\n /** The traps it removes. */\n reasons: readonly ProductReason[];\n /** The decisions' section: heading, decisions and their four labels. */\n decisions?: { eyebrow?: React.ReactNode; title: React.ReactNode; items: readonly Decision[]; labels: { chose: React.ReactNode; refused: React.ReactNode; because: React.ReactNode; cost: React.ReactNode } };\n /** The promise a bird keeps, under the decisions. */\n promise?: { bird: MascotBird; label: React.ReactNode; text: React.ReactNode };\n /** More sections between the decisions and the closing call (the tour, the platform, a comparison). */\n children?: React.ReactNode;\n /** The closing call. */\n closing?: { title: React.ReactNode; body?: React.ReactNode; actions: React.ReactNode };\n /** The app's link component (Next's `Link`). */\n linkAs?: LinkComponent;\n};\n\n/** A product's overview: split hero, traps as compact cards, decisions with their cost, the bird's promise, closing call. */\nexport function ProductPage({ brand, mark, title, lead, facts, actions, visual, visualLabel, reasonsHeading, reasonLabels, reasons, decisions, promise, closing, linkAs, className, children, ...props }: ProductPageProps) {\n return (\n <div className={cn(brand && \"brand-\" + brand, className)} {...props}>\n <SectionBackdrop as=\"header\" grid className=\"kz-hero\">\n <Page>\n <div className={visual ? \"kz-tpl-split\" : undefined}>\n <div className=\"kz-hero-text\">\n {mark && <p className=\"kz-eyebrow\">{mark}</p>}\n <h1 className=\"kz-hero-title\">{title}</h1>\n {lead && <p className=\"kz-hero-lead\">{lead}</p>}\n {(facts || actions) && (\n <div className=\"kz-hero-extra\">\n {facts && <Facts items={facts} />}\n {actions && <div className=\"kz-tpl-actions\">{actions}</div>}\n </div>\n )}\n </div>\n {visual && (\n <figure className=\"kz-tpl-stage\">\n <div className=\"kz-tpl-stage-bar\" aria-hidden>\n {visualLabel && <span>{visualLabel}</span>}\n </div>\n {visual}\n </figure>\n )}\n </div>\n </Page>\n </SectionBackdrop>\n <Section id=\"why\" eyebrow={reasonsHeading.eyebrow} title={reasonsHeading.title} lead={reasonsHeading.lead} reveal>\n <CardGrid min={260} fit=\"fit\">\n {reasons.map((r) => (\n <ArgumentCard\n key={r.id}\n id={`why-${r.id}`}\n icon={r.icon}\n title={r.title}\n mark={r.mark}\n hook={{ label: reasonLabels.trap, text: r.trap }}\n more={r.href ? { href: r.href, label: reasonLabels.more } : undefined}\n linkAs={linkAs}\n />\n ))}\n </CardGrid>\n </Section>\n {decisions && (\n <Section id=\"decisions\" eyebrow={decisions.eyebrow} title={decisions.title} divider reveal>\n <DecisionList decisions={decisions.items} labels={decisions.labels} />\n {promise && (\n <div className=\"kz-tpl-promise\">\n <MascotQuote variant=\"callout\" bird={promise.bird} mood=\"welcome\" label={promise.label}>\n {promise.text}\n </MascotQuote>\n </div>\n )}\n </Section>\n )}\n {children}\n {closing && (\n <Section spacing=\"sm\" aria-labelledby=\"product-closing\">\n <CtaPanel id=\"product-closing\" title={closing.title} body={closing.body} reveal>\n {closing.actions}\n </CtaPanel>\n </Section>\n )}\n </div>\n );\n}\n"],"mappings":";;;;;AAGA,SAAS,oBAAoB;AAC7B,SAAS,gBAAgB;AACzB,SAAS,gBAAgB;AACzB,SAAwB,oBAAoB;AAC5C,SAAS,mBAAmB;AAE5B,SAAoB,OAAO,MAAM,eAAe;AAEhD,SAAS,uBAAuB;AA+DT,cAIP,YAJO;AAPhB,SAAS,YAAY,EAAE,OAAO,MAAM,OAAO,MAAM,OAAO,SAAS,QAAQ,aAAa,gBAAgB,cAAc,SAAS,WAAW,SAAS,SAAS,QAAQ,WAAW,UAAU,GAAG,MAAM,GAAqB;AAC1N,SACE,qBAAC,SAAI,WAAW,GAAG,SAAS,WAAW,OAAO,SAAS,GAAI,GAAG,OAC5D;AAAA,wBAAC,mBAAgB,IAAG,UAAS,MAAI,MAAC,WAAU,WAC1C,8BAAC,QACC,+BAAC,SAAI,WAAW,SAAS,iBAAiB,QACxC;AAAA,2BAAC,SAAI,WAAU,gBACZ;AAAA,gBAAQ,oBAAC,OAAE,WAAU,cAAc,gBAAK;AAAA,QACzC,oBAAC,QAAG,WAAU,iBAAiB,iBAAM;AAAA,QACpC,QAAQ,oBAAC,OAAE,WAAU,gBAAgB,gBAAK;AAAA,SACzC,SAAS,YACT,qBAAC,SAAI,WAAU,iBACZ;AAAA,mBAAS,oBAAC,SAAM,OAAO,OAAO;AAAA,UAC9B,WAAW,oBAAC,SAAI,WAAU,kBAAkB,mBAAQ;AAAA,WACvD;AAAA,SAEJ;AAAA,MACC,UACC,qBAAC,YAAO,WAAU,gBAChB;AAAA,4BAAC,SAAI,WAAU,oBAAmB,eAAW,MAC1C,yBAAe,oBAAC,UAAM,uBAAY,GACrC;AAAA,QACC;AAAA,SACH;AAAA,OAEJ,GACF,GACF;AAAA,IACA,oBAAC,WAAQ,IAAG,OAAM,SAAS,eAAe,SAAS,OAAO,eAAe,OAAO,MAAM,eAAe,MAAM,QAAM,MAC/G,8BAAC,YAAS,KAAK,KAAK,KAAI,OACrB,kBAAQ,IAAI,CAAC,MACZ;AAAA,MAAC;AAAA;AAAA,QAEC,IAAI,OAAO,EAAE,EAAE;AAAA,QACf,MAAM,EAAE;AAAA,QACR,OAAO,EAAE;AAAA,QACT,MAAM,EAAE;AAAA,QACR,MAAM,EAAE,OAAO,aAAa,MAAM,MAAM,EAAE,KAAK;AAAA,QAC/C,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,OAAO,aAAa,KAAK,IAAI;AAAA,QAC5D;AAAA;AAAA,MAPK,EAAE;AAAA,IAQT,CACD,GACH,GACF;AAAA,IACC,aACC,qBAAC,WAAQ,IAAG,aAAY,SAAS,UAAU,SAAS,OAAO,UAAU,OAAO,SAAO,MAAC,QAAM,MACxF;AAAA,0BAAC,gBAAa,WAAW,UAAU,OAAO,QAAQ,UAAU,QAAQ;AAAA,MACnE,WACC,oBAAC,SAAI,WAAU,kBACb,8BAAC,eAAY,SAAQ,WAAU,MAAM,QAAQ,MAAM,MAAK,WAAU,OAAO,QAAQ,OAC9E,kBAAQ,MACX,GACF;AAAA,OAEJ;AAAA,IAED;AAAA,IACA,WACC,oBAAC,WAAQ,SAAQ,MAAK,mBAAgB,mBACpC,8BAAC,YAAS,IAAG,mBAAkB,OAAO,QAAQ,OAAO,MAAM,QAAQ,MAAM,QAAM,MAC5E,kBAAQ,SACX,GACF;AAAA,KAEJ;AAEJ;","names":[]}
@@ -1,13 +1,12 @@
1
1
  import * as tailwind_variants from 'tailwind-variants';
2
2
  import * as React from 'react';
3
- import { S as SiteId, F as FamilyLabels } from './sites-B4sYlfPQ.js';
3
+ import { S as SiteId, F as FamilyLabels } from './sites-inztN_Bv.js';
4
4
 
5
5
  declare const siteFooter: tailwind_variants.TVReturnType<{
6
6
  variant: {
7
7
  site: {};
8
8
  docs: {
9
9
  inner: string;
10
- top: string;
11
10
  own: string;
12
11
  };
13
12
  app: {
@@ -19,10 +18,7 @@ declare const siteFooter: tailwind_variants.TVReturnType<{
19
18
  }, {
20
19
  root: string;
21
20
  inner: string;
22
- top: string;
23
- site: string;
24
- siteName: string;
25
- siteText: string;
21
+ band: string;
26
22
  own: string;
27
23
  family: string;
28
24
  column: string;
@@ -40,7 +36,6 @@ declare const siteFooter: tailwind_variants.TVReturnType<{
40
36
  site: {};
41
37
  docs: {
42
38
  inner: string;
43
- top: string;
44
39
  own: string;
45
40
  };
46
41
  app: {
@@ -52,10 +47,7 @@ declare const siteFooter: tailwind_variants.TVReturnType<{
52
47
  }, {
53
48
  root: string;
54
49
  inner: string;
55
- top: string;
56
- site: string;
57
- siteName: string;
58
- siteText: string;
50
+ band: string;
59
51
  own: string;
60
52
  family: string;
61
53
  column: string;
@@ -73,7 +65,6 @@ declare const siteFooter: tailwind_variants.TVReturnType<{
73
65
  site: {};
74
66
  docs: {
75
67
  inner: string;
76
- top: string;
77
68
  own: string;
78
69
  };
79
70
  app: {
@@ -85,10 +76,7 @@ declare const siteFooter: tailwind_variants.TVReturnType<{
85
76
  }, {
86
77
  root: string;
87
78
  inner: string;
88
- top: string;
89
- site: string;
90
- siteName: string;
91
- siteText: string;
79
+ band: string;
92
80
  own: string;
93
81
  family: string;
94
82
  column: string;
@@ -134,7 +122,7 @@ type SiteFooterProps = Omit<React.ComponentProps<"footer">, "children"> & {
134
122
  */
135
123
  variant?: "site" | "docs" | "app";
136
124
  };
137
- /** The footer of a Krizaka site: its own columns, the family in columns, the signature, the version, Montréal. */
125
+ /** The footer of a Krizaka site, one band: its own columns and the family's, then one line — signature, version, Montréal, legal. */
138
126
  declare function SiteFooter({ current, labels, children, version, env, legal, family: familyProp, variant, className, ...props }: SiteFooterProps): React.JSX.Element;
139
127
  declare namespace SiteFooter {
140
128
  var Column: typeof SiteFooterColumn;
@@ -1,10 +1,11 @@
1
1
  "use client";
2
2
  import {
3
3
  FamilyMark,
4
+ companyLinks,
4
5
  familyLabels,
5
6
  siteById,
6
7
  sitesByGroup
7
- } from "./chunk-IANSFIVC.js";
8
+ } from "./chunk-7JFHTPI3.js";
8
9
  import {
9
10
  KrizakaLogo
10
11
  } from "./chunk-4E5IUZHR.js";
@@ -18,12 +19,9 @@ var siteFooter = tv({
18
19
  slots: {
19
20
  root: "w-full border-t border-border-subtle bg-surface-0 text-fg",
20
21
  inner: "mx-auto grid w-full max-w-[calc(var(--kz-page-max,72rem)_+_2*var(--kz-page-gutter,clamp(16px,3.2vw,32px)))] grid-cols-[minmax(0,1fr)] gap-10 px-[var(--kz-page-gutter,clamp(16px,3.2vw,32px))] py-12",
21
- top: "grid grid-cols-[minmax(0,1fr)] gap-8 lg:grid-cols-[minmax(0,1fr)_minmax(0,2fr)]",
22
- site: "grid content-start gap-3",
23
- siteName: "inline-flex items-center gap-2 font-display text-[15px] font-bold tracking-tight text-fg",
24
- siteText: "max-w-xs text-sm leading-relaxed text-fg-secondary",
22
+ band: "grid grid-cols-[minmax(0,1fr)] gap-8 lg:grid-flow-col lg:auto-cols-[minmax(0,1fr)]",
25
23
  own: "grid grid-cols-[repeat(auto-fit,minmax(9rem,1fr))] gap-8",
26
- family: "grid grid-cols-2 gap-8 border-t border-border-subtle pt-8 md:grid-cols-4",
24
+ family: "grid grid-cols-2 gap-8 sm:grid-cols-3",
27
25
  column: "grid min-w-0 content-start gap-3",
28
26
  title: "text-[11px] font-semibold text-fg-secondary",
29
27
  list: "grid min-w-0 gap-2",
@@ -42,7 +40,6 @@ var siteFooter = tv({
42
40
  site: {},
43
41
  docs: {
44
42
  inner: "max-w-[calc(var(--kz-page-max-docs,88rem)_+_2*var(--kz-page-gutter,clamp(16px,3.2vw,32px)))] gap-6 py-8",
45
- top: "lg:grid-cols-[minmax(0,1fr)]",
46
43
  own: "sm:grid-cols-4"
47
44
  },
48
45
  app: {
@@ -73,30 +70,37 @@ function SiteFooter({
73
70
  const site = siteById(current);
74
71
  const krizaka = siteById("krizaka");
75
72
  const tag = [env, version && `v${version.replace(/^v/, "")}`].filter(Boolean).join(" \xB7 ");
73
+ const own = React.Children.toArray(children).length > 0;
74
+ const lang = labels.lang ?? "en";
75
+ const company = labels.company ?? familyLabels.en.company;
76
+ const groups = sitesByGroup();
77
+ const columns = [
78
+ ...groups.filter((g) => g.group === "products"),
79
+ { group: "open-source", sites: groups.filter((g) => g.group === "open-source" || g.group === "github").flatMap((g) => g.sites) }
80
+ ];
76
81
  return /* @__PURE__ */ jsx("footer", { className: s.root({ className }), ...props, children: /* @__PURE__ */ jsxs("div", { className: s.inner(), children: [
77
- !slim && /* @__PURE__ */ jsxs("div", { className: s.top(), children: [
78
- variant === "site" && /* @__PURE__ */ jsxs("div", { className: s.site(), children: [
79
- /* @__PURE__ */ jsxs("a", { href: site.url, className: s.siteName(), children: [
80
- /* @__PURE__ */ jsx(FamilyMark, { mark: site.mark, size: 24 }),
81
- site.name
82
- ] }),
83
- /* @__PURE__ */ jsx("p", { className: s.siteText(), children: labels.descriptions[site.id] })
84
- ] }),
85
- React.Children.toArray(children).length > 0 && /* @__PURE__ */ jsx("div", { className: s.own(), children })
86
- ] }),
87
- family && /* @__PURE__ */ jsx("nav", { "aria-label": labels.family, className: s.family(), children: sitesByGroup().map(({ group, sites }) => /* @__PURE__ */ jsxs("div", { className: s.column(), children: [
88
- /* @__PURE__ */ jsx("p", { id: `${id}-${group}`, className: s.title(), children: labels.groups[group] }),
89
- /* @__PURE__ */ jsx("ul", { "aria-labelledby": `${id}-${group}`, className: s.list(), children: sites.map((item) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs("a", { href: item.url, "aria-current": item.id === current ? "true" : void 0, className: s.link(), children: [
90
- /* @__PURE__ */ jsx("span", { className: s.mark(), children: /* @__PURE__ */ jsx(FamilyMark, { mark: item.mark, size: 16 }) }),
91
- item.name,
92
- item.status !== "released" && /* @__PURE__ */ jsx("span", { className: s.tag(), children: labels.status[item.status] }),
93
- item.id === current && /* @__PURE__ */ jsxs("span", { className: "sr-only", children: [
94
- "(",
95
- labels.current,
96
- ")"
82
+ !slim && (own || family) && /* @__PURE__ */ jsxs("div", { className: s.band(), children: [
83
+ own && /* @__PURE__ */ jsx("div", { className: s.own(), children }),
84
+ family && /* @__PURE__ */ jsxs("nav", { "aria-label": labels.family, className: s.family(), children: [
85
+ columns.map(({ group, sites }) => /* @__PURE__ */ jsxs("div", { className: s.column(), children: [
86
+ /* @__PURE__ */ jsx("p", { id: `${id}-${group}`, className: s.title(), children: labels.groups[group] }),
87
+ /* @__PURE__ */ jsx("ul", { "aria-labelledby": `${id}-${group}`, className: s.list(), children: sites.map((item) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs("a", { href: item.url, "aria-current": item.id === current ? "true" : void 0, className: s.link(), children: [
88
+ /* @__PURE__ */ jsx("span", { className: s.mark(), children: /* @__PURE__ */ jsx(FamilyMark, { mark: item.mark, size: 16 }) }),
89
+ item.name,
90
+ item.status !== "released" && /* @__PURE__ */ jsx("span", { className: s.tag(), children: labels.status[item.status] }),
91
+ item.id === current && /* @__PURE__ */ jsxs("span", { className: "sr-only", children: [
92
+ "(",
93
+ labels.current,
94
+ ")"
95
+ ] })
96
+ ] }) }, item.id)) })
97
+ ] }, group)),
98
+ /* @__PURE__ */ jsxs("div", { className: s.column(), children: [
99
+ /* @__PURE__ */ jsx("p", { id: `${id}-krizaka`, className: s.title(), children: labels.groups.krizaka }),
100
+ /* @__PURE__ */ jsx("ul", { "aria-labelledby": `${id}-krizaka`, className: s.list(), children: companyLinks.map((l) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx("a", { href: l.url[lang], className: s.link(), children: company[l.id] }) }, l.id)) })
97
101
  ] })
98
- ] }) }, item.id)) })
99
- ] }, group)) }),
102
+ ] })
103
+ ] }),
100
104
  /* @__PURE__ */ jsxs("div", { className: s.bottom(), children: [
101
105
  /* @__PURE__ */ jsxs("a", { href: krizaka.url, className: s.signature(), children: [
102
106
  /* @__PURE__ */ jsx(KrizakaLogo, { size: 18, animated: false }),
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/site-footer/site-footer.tsx"],"sourcesContent":["// Client (the marks hold an id). The footer shared by every site of the Krizaka family: the site's own columns, then the\n// family in columns from `@krizaka/ui/sites` (the same groups as the bar's switcher), then the signature line — “A\n// Krizaka product” by the kind of the current site — the version and the place.\nimport { Slot } from \"radix-ui\";\nimport * as React from \"react\";\nimport { tv } from \"tailwind-variants\";\n\nimport { FamilyMark } from \"../family-mark\";\nimport { KrizakaLogo } from \"../marks/KrizakaLogo\";\nimport { type FamilyLabels, familyLabels, siteById, type SiteId, sitesByGroup } from \"../sites/sites\";\n\nexport const siteFooter = tv({\n slots: {\n root: \"w-full border-t border-border-subtle bg-surface-0 text-fg\",\n inner:\n \"mx-auto grid w-full max-w-[calc(var(--kz-page-max,72rem)_+_2*var(--kz-page-gutter,clamp(16px,3.2vw,32px)))] grid-cols-[minmax(0,1fr)] gap-10 px-[var(--kz-page-gutter,clamp(16px,3.2vw,32px))] py-12\",\n top: \"grid grid-cols-[minmax(0,1fr)] gap-8 lg:grid-cols-[minmax(0,1fr)_minmax(0,2fr)]\",\n site: \"grid content-start gap-3\",\n siteName: \"inline-flex items-center gap-2 font-display text-[15px] font-bold tracking-tight text-fg\",\n siteText: \"max-w-xs text-sm leading-relaxed text-fg-secondary\",\n own: \"grid grid-cols-[repeat(auto-fit,minmax(9rem,1fr))] gap-8\",\n family: \"grid grid-cols-2 gap-8 border-t border-border-subtle pt-8 md:grid-cols-4\",\n column: \"grid min-w-0 content-start gap-3\",\n title: \"text-[11px] font-semibold text-fg-secondary\",\n list: \"grid min-w-0 gap-2\",\n link:\n \"inline-flex min-h-6 min-w-0 flex-wrap items-center gap-x-2 gap-y-0.5 rounded-md text-sm [overflow-wrap:anywhere] text-fg-secondary no-underline transition-colors hover:text-fg \" +\n \"focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring aria-[current=page]:text-fg aria-[current=true]:text-fg aria-[current=true]:font-semibold\",\n mark: \"flex h-4 w-4 shrink-0 items-center justify-center text-fg\",\n tag: \"rounded-sm bg-surface-3 px-1.5 py-px text-[10px] font-semibold text-fg-secondary\",\n bottom: \"flex flex-wrap items-center gap-x-5 gap-y-3 border-t border-border-subtle pt-6 text-xs text-fg-secondary\",\n signature:\n \"inline-flex items-center gap-2 rounded-md font-medium text-fg no-underline hover:text-fg-accent focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring\",\n version:\n \"rounded-sm border border-border-subtle bg-surface-2 px-2 py-0.5 font-mono text-[11px] text-fg-secondary\",\n legal: \"flex flex-wrap items-center gap-x-4 gap-y-2 sm:ml-auto\",\n },\n variants: {\n // `site`: the full footer. `docs`: no site block, the columns in one row, on the documentation's width. `app`: one\n // slim line inside a signed-in product — signature, version, legal links.\n variant: {\n site: {},\n docs: {\n inner: \"max-w-[calc(var(--kz-page-max-docs,88rem)_+_2*var(--kz-page-gutter,clamp(16px,3.2vw,32px)))] gap-6 py-8\",\n top: \"lg:grid-cols-[minmax(0,1fr)]\",\n own: \"sm:grid-cols-4\",\n },\n app: {\n root: \"bg-transparent\",\n inner: \"gap-0 py-3\",\n bottom: \"border-t-0 pt-0\",\n },\n },\n },\n defaultVariants: { variant: \"site\" },\n});\n\nexport type SiteFooterProps = Omit<React.ComponentProps<\"footer\">, \"children\"> & {\n /** The site this footer belongs to (`@krizaka/ui/sites`): its mark and line, its signature, marked in the family. */\n current: SiteId;\n /**\n * The family's words, passed translated: `familyLabels.fr` from `@krizaka/ui/sites`, or your own of the same shape.\n * @default familyLabels.en\n */\n labels?: FamilyLabels;\n /** The site's own columns (`SiteFooter.Column`), before the family. */\n children?: React.ReactNode;\n /** The version the site runs (`1.2.3`, shown `v1.2.3`). */\n version?: string;\n /** The environment, when it is not production (`DEV`). */\n env?: string;\n /**\n * Shows the family in columns (the Krizaka sites: www, ui., java.). A product is independent once deployed: pass\n * `family={false}` and the footer holds only its own columns, the legal links, the version and one publisher line —\n * “A Krizaka product”, linking to www.krizaka.com.\n * @default true\n */\n family?: boolean;\n /** The end of the signature line: legal links, a language switch (`SiteFooter.Link`s or any inline content). */\n legal?: React.ReactNode;\n /**\n * `site` — the full footer of a marketing or company site. `docs` — a compact one for documentation pages (no site\n * block, the columns in a row, the documentation's width; never the family). `app` — one slim line inside a signed-in\n * product: the publisher line, the version and the legal links (no columns, no family); render it once, in the\n * layout, and not at all where the app shell has a sidebar that holds them.\n * @default \"site\"\n */\n variant?: \"site\" | \"docs\" | \"app\";\n};\n\n/** The footer of a Krizaka site: its own columns, the family in columns, the signature, the version, Montréal. */\nexport function SiteFooter({\n current,\n labels = familyLabels.en,\n children,\n version,\n env,\n legal,\n family: familyProp = true,\n variant = \"site\",\n className,\n ...props\n}: SiteFooterProps) {\n const id = React.useId();\n const s = siteFooter({ variant });\n const family = variant === \"site\" && familyProp;\n const slim = variant === \"app\";\n const site = siteById(current);\n const krizaka = siteById(\"krizaka\");\n const tag = [env, version && `v${version.replace(/^v/, \"\")}`].filter(Boolean).join(\" · \");\n return (\n <footer className={s.root({ className })} {...props}>\n <div className={s.inner()}>\n {!slim && (\n <div className={s.top()}>\n {variant === \"site\" && (\n <div className={s.site()}>\n <a href={site.url} className={s.siteName()}>\n <FamilyMark mark={site.mark} size={24} />\n {site.name}\n </a>\n <p className={s.siteText()}>{labels.descriptions[site.id]}</p>\n </div>\n )}\n {React.Children.toArray(children).length > 0 && <div className={s.own()}>{children}</div>}\n </div>\n )}\n {family && (\n <nav aria-label={labels.family} className={s.family()}>\n {sitesByGroup().map(({ group, sites }) => (\n <div key={group} className={s.column()}>\n <p id={`${id}-${group}`} className={s.title()}>\n {labels.groups[group]}\n </p>\n <ul aria-labelledby={`${id}-${group}`} className={s.list()}>\n {sites.map((item) => (\n <li key={item.id}>\n <a href={item.url} aria-current={item.id === current ? \"true\" : undefined} className={s.link()}>\n <span className={s.mark()}>\n <FamilyMark mark={item.mark} size={16} />\n </span>\n {item.name}\n {item.status !== \"released\" && <span className={s.tag()}>{labels.status[item.status]}</span>}\n {item.id === current && <span className=\"sr-only\">({labels.current})</span>}\n </a>\n </li>\n ))}\n </ul>\n </div>\n ))}\n </nav>\n )}\n <div className={s.bottom()}>\n <a href={krizaka.url} className={s.signature()}>\n <KrizakaLogo size={18} animated={false} />\n {labels.signature[site.kind]}\n </a>\n {tag && (\n <span className={s.version()}>\n <span className=\"sr-only\">{labels.version} </span>\n {tag}\n </span>\n )}\n {!slim && <span>{labels.place}</span>}\n {legal && <div className={s.legal()}>{legal}</div>}\n </div>\n </div>\n </footer>\n );\n}\n\nexport type SiteFooterColumnProps = Omit<React.ComponentProps<\"div\">, \"title\"> & {\n /** The column's heading (“Docs”) — passed translated. */\n title: string;\n /** Its links (`SiteFooter.Link`). */\n children: React.ReactNode;\n};\n\n/** One of the site's own columns: a heading and its links. */\nexport function SiteFooterColumn({ title, children, className, ...props }: SiteFooterColumnProps) {\n const id = React.useId();\n // A group with no link is not a column: only a heading over nothing.\n if (React.Children.toArray(children).length === 0) return null;\n const s = siteFooter();\n return (\n <div className={s.column({ className })} {...props}>\n <p id={id} className={s.title()}>\n {title}\n </p>\n <ul aria-labelledby={id} className={s.list()}>\n {React.Children.toArray(children).map((child, i) => <li key={i}>{child}</li>)}\n </ul>\n </div>\n );\n}\n\nexport type SiteFooterLinkProps = React.ComponentProps<\"a\"> & {\n /** The current page: `aria-current=\"page\"`. */\n active?: boolean;\n /** Renders your router's `<Link>`. */\n asChild?: boolean;\n};\n\n/** A link of the footer. */\nexport function SiteFooterLink({ active, asChild, className, ...props }: SiteFooterLinkProps) {\n const s = siteFooter();\n const Comp = asChild ? Slot.Root : \"a\";\n return <Comp aria-current={active ? \"page\" : undefined} className={s.link({ className })} {...props} />;\n}\n\nSiteFooter.Column = SiteFooterColumn;\nSiteFooter.Link = SiteFooterLink;\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/site-footer/site-footer.tsx"],"sourcesContent":["// Client (the marks hold an id). The footer shared by every site of the Krizaka family — one calm band (Cahier, ADR-004;\n// peer review krizaka-ui#434: « too much, a double footer »): the site's own columns and the family's columns side by\n// side — Products · Open source (GitHub with them) · Krizaka (our story, the blog, contact) — then one line: the\n// signature (“A Krizaka product”, by the kind of the current site, to www), the version, the place, the legal links.\n// No site block (the bar already names the site), no column that lists only Krizaka, no link twice.\nimport { Slot } from \"radix-ui\";\nimport * as React from \"react\";\nimport { tv } from \"tailwind-variants\";\n\nimport { FamilyMark } from \"../family-mark\";\nimport { KrizakaLogo } from \"../marks/KrizakaLogo\";\nimport { companyLinks, type FamilyLabels, familyLabels, siteById, type SiteId, sitesByGroup } from \"../sites/sites\";\n\nexport const siteFooter = tv({\n slots: {\n root: \"w-full border-t border-border-subtle bg-surface-0 text-fg\",\n inner:\n \"mx-auto grid w-full max-w-[calc(var(--kz-page-max,72rem)_+_2*var(--kz-page-gutter,clamp(16px,3.2vw,32px)))] grid-cols-[minmax(0,1fr)] gap-10 px-[var(--kz-page-gutter,clamp(16px,3.2vw,32px))] py-12\",\n band: \"grid grid-cols-[minmax(0,1fr)] gap-8 lg:grid-flow-col lg:auto-cols-[minmax(0,1fr)]\",\n own: \"grid grid-cols-[repeat(auto-fit,minmax(9rem,1fr))] gap-8\",\n family: \"grid grid-cols-2 gap-8 sm:grid-cols-3\",\n column: \"grid min-w-0 content-start gap-3\",\n title: \"text-[11px] font-semibold text-fg-secondary\",\n list: \"grid min-w-0 gap-2\",\n link:\n \"inline-flex min-h-6 min-w-0 flex-wrap items-center gap-x-2 gap-y-0.5 rounded-md text-sm [overflow-wrap:anywhere] text-fg-secondary no-underline transition-colors hover:text-fg \" +\n \"focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring aria-[current=page]:text-fg aria-[current=true]:text-fg aria-[current=true]:font-semibold\",\n mark: \"flex h-4 w-4 shrink-0 items-center justify-center text-fg\",\n tag: \"rounded-sm bg-surface-3 px-1.5 py-px text-[10px] font-semibold text-fg-secondary\",\n bottom: \"flex flex-wrap items-center gap-x-5 gap-y-3 border-t border-border-subtle pt-6 text-xs text-fg-secondary\",\n signature:\n \"inline-flex items-center gap-2 rounded-md font-medium text-fg no-underline hover:text-fg-accent focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring\",\n version:\n \"rounded-sm border border-border-subtle bg-surface-2 px-2 py-0.5 font-mono text-[11px] text-fg-secondary\",\n legal: \"flex flex-wrap items-center gap-x-4 gap-y-2 sm:ml-auto\",\n },\n variants: {\n // `site`: the full footer. `docs`: no site block, the columns in one row, on the documentation's width. `app`: one\n // slim line inside a signed-in product — signature, version, legal links.\n variant: {\n site: {},\n docs: {\n inner: \"max-w-[calc(var(--kz-page-max-docs,88rem)_+_2*var(--kz-page-gutter,clamp(16px,3.2vw,32px)))] gap-6 py-8\",\n own: \"sm:grid-cols-4\",\n },\n app: {\n root: \"bg-transparent\",\n inner: \"gap-0 py-3\",\n bottom: \"border-t-0 pt-0\",\n },\n },\n },\n defaultVariants: { variant: \"site\" },\n});\n\nexport type SiteFooterProps = Omit<React.ComponentProps<\"footer\">, \"children\"> & {\n /** The site this footer belongs to (`@krizaka/ui/sites`): its mark and line, its signature, marked in the family. */\n current: SiteId;\n /**\n * The family's words, passed translated: `familyLabels.fr` from `@krizaka/ui/sites`, or your own of the same shape.\n * @default familyLabels.en\n */\n labels?: FamilyLabels;\n /** The site's own columns (`SiteFooter.Column`), before the family. */\n children?: React.ReactNode;\n /** The version the site runs (`1.2.3`, shown `v1.2.3`). */\n version?: string;\n /** The environment, when it is not production (`DEV`). */\n env?: string;\n /**\n * Shows the family in columns (the Krizaka sites: www, ui., java.). A product is independent once deployed: pass\n * `family={false}` and the footer holds only its own columns, the legal links, the version and one publisher line —\n * “A Krizaka product”, linking to www.krizaka.com.\n * @default true\n */\n family?: boolean;\n /** The end of the signature line: legal links, a language switch (`SiteFooter.Link`s or any inline content). */\n legal?: React.ReactNode;\n /**\n * `site` — the full footer of a marketing or company site. `docs` — a compact one for documentation pages (no site\n * block, the columns in a row, the documentation's width; never the family). `app` — one slim line inside a signed-in\n * product: the publisher line, the version and the legal links (no columns, no family); render it once, in the\n * layout, and not at all where the app shell has a sidebar that holds them.\n * @default \"site\"\n */\n variant?: \"site\" | \"docs\" | \"app\";\n};\n\n/** The footer of a Krizaka site, one band: its own columns and the family's, then one line — signature, version, Montréal, legal. */\nexport function SiteFooter({\n current,\n labels = familyLabels.en,\n children,\n version,\n env,\n legal,\n family: familyProp = true,\n variant = \"site\",\n className,\n ...props\n}: SiteFooterProps) {\n const id = React.useId();\n const s = siteFooter({ variant });\n const family = variant === \"site\" && familyProp;\n const slim = variant === \"app\";\n const site = siteById(current);\n const krizaka = siteById(\"krizaka\");\n const tag = [env, version && `v${version.replace(/^v/, \"\")}`].filter(Boolean).join(\" · \");\n const own = React.Children.toArray(children).length > 0;\n const lang = labels.lang ?? \"en\";\n const company = labels.company ?? familyLabels.en.company!;\n // Products · Open source (GitHub, every repository, closes it) · Krizaka (the company's pages): three columns, no\n // column that lists only Krizaka.\n const groups = sitesByGroup();\n const columns = [\n ...groups.filter((g) => g.group === \"products\"),\n { group: \"open-source\" as const, sites: groups.filter((g) => g.group === \"open-source\" || g.group === \"github\").flatMap((g) => g.sites) },\n ];\n return (\n <footer className={s.root({ className })} {...props}>\n <div className={s.inner()}>\n {!slim && (own || family) && (\n <div className={s.band()}>\n {own && <div className={s.own()}>{children}</div>}\n {family && (\n <nav aria-label={labels.family} className={s.family()}>\n {columns.map(({ group, sites }) => (\n <div key={group} className={s.column()}>\n <p id={`${id}-${group}`} className={s.title()}>\n {labels.groups[group]}\n </p>\n <ul aria-labelledby={`${id}-${group}`} className={s.list()}>\n {sites.map((item) => (\n <li key={item.id}>\n <a href={item.url} aria-current={item.id === current ? \"true\" : undefined} className={s.link()}>\n <span className={s.mark()}>\n <FamilyMark mark={item.mark} size={16} />\n </span>\n {item.name}\n {item.status !== \"released\" && <span className={s.tag()}>{labels.status[item.status]}</span>}\n {item.id === current && <span className=\"sr-only\">({labels.current})</span>}\n </a>\n </li>\n ))}\n </ul>\n </div>\n ))}\n <div className={s.column()}>\n <p id={`${id}-krizaka`} className={s.title()}>\n {labels.groups.krizaka}\n </p>\n <ul aria-labelledby={`${id}-krizaka`} className={s.list()}>\n {companyLinks.map((l) => (\n <li key={l.id}>\n <a href={l.url[lang]} className={s.link()}>\n {company[l.id]}\n </a>\n </li>\n ))}\n </ul>\n </div>\n </nav>\n )}\n </div>\n )}\n <div className={s.bottom()}>\n <a href={krizaka.url} className={s.signature()}>\n <KrizakaLogo size={18} animated={false} />\n {labels.signature[site.kind]}\n </a>\n {tag && (\n <span className={s.version()}>\n <span className=\"sr-only\">{labels.version} </span>\n {tag}\n </span>\n )}\n {!slim && <span>{labels.place}</span>}\n {legal && <div className={s.legal()}>{legal}</div>}\n </div>\n </div>\n </footer>\n );\n}\n\nexport type SiteFooterColumnProps = Omit<React.ComponentProps<\"div\">, \"title\"> & {\n /** The column's heading (“Docs”) — passed translated. */\n title: string;\n /** Its links (`SiteFooter.Link`). */\n children: React.ReactNode;\n};\n\n/** One of the site's own columns: a heading and its links. */\nexport function SiteFooterColumn({ title, children, className, ...props }: SiteFooterColumnProps) {\n const id = React.useId();\n // A group with no link is not a column: only a heading over nothing.\n if (React.Children.toArray(children).length === 0) return null;\n const s = siteFooter();\n return (\n <div className={s.column({ className })} {...props}>\n <p id={id} className={s.title()}>\n {title}\n </p>\n <ul aria-labelledby={id} className={s.list()}>\n {React.Children.toArray(children).map((child, i) => <li key={i}>{child}</li>)}\n </ul>\n </div>\n );\n}\n\nexport type SiteFooterLinkProps = React.ComponentProps<\"a\"> & {\n /** The current page: `aria-current=\"page\"`. */\n active?: boolean;\n /** Renders your router's `<Link>`. */\n asChild?: boolean;\n};\n\n/** A link of the footer. */\nexport function SiteFooterLink({ active, asChild, className, ...props }: SiteFooterLinkProps) {\n const s = siteFooter();\n const Comp = asChild ? Slot.Root : \"a\";\n return <Comp aria-current={active ? \"page\" : undefined} className={s.link({ className })} {...props} />;\n}\n\nSiteFooter.Column = SiteFooterColumn;\nSiteFooter.Link = SiteFooterLink;\n"],"mappings":"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","names":[]}
@@ -10,6 +10,10 @@ type SiteKind = "company" | "product" | "open-source";
10
10
  type SiteStatus = "released" | "upcoming" | "construction" | "development";
11
11
  /** The groups of the family, in reading order: Krizaka · Products · Open source · GitHub. */
12
12
  type SiteGroup = "krizaka" | "products" | "open-source" | "github";
13
+ /** The languages the family's words are written in. */
14
+ type SiteLocale = "en" | "fr";
15
+ /** The company's own pages, the footer's « Krizaka » column (the brand's home is the signature line's link). */
16
+ type CompanyLinkId = "story" | "blog" | "contact";
13
17
  /** The words of the family: the switcher, the footer, each site's one line. */
14
18
  interface FamilyLabels {
15
19
  /** The family's name: the switcher's navigation and its button, the footer's navigation (“Krizaka family”). */
@@ -28,6 +32,10 @@ interface FamilyLabels {
28
32
  place: string;
29
33
  /** The accessible name of the version (“Version”). */
30
34
  version: string;
35
+ /** The language of these words: the company links open in it. @default "en" */
36
+ lang?: SiteLocale;
37
+ /** The company's pages in the footer's « Krizaka » column. @default the English words */
38
+ company?: Record<CompanyLinkId, string>;
31
39
  }
32
40
 
33
41
  export type { FamilyLabels as F, SiteId as S };
package/dist/sites.d.ts CHANGED
@@ -40,6 +40,12 @@ declare function sitesByGroup(): {
40
40
  }[];
41
41
  /** The languages the family's words are written in. */
42
42
  type SiteLocale = "en" | "fr";
43
+ /** The company's own pages, the footer's « Krizaka » column (the brand's home is the signature line's link). */
44
+ type CompanyLinkId = "story" | "blog" | "contact";
45
+ declare const companyLinks: readonly {
46
+ id: CompanyLinkId;
47
+ url: Record<SiteLocale, string>;
48
+ }[];
43
49
  /** The words of the family: the switcher, the footer, each site's one line. */
44
50
  interface FamilyLabels {
45
51
  /** The family's name: the switcher's navigation and its button, the footer's navigation (“Krizaka family”). */
@@ -58,8 +64,12 @@ interface FamilyLabels {
58
64
  place: string;
59
65
  /** The accessible name of the version (“Version”). */
60
66
  version: string;
67
+ /** The language of these words: the company links open in it. @default "en" */
68
+ lang?: SiteLocale;
69
+ /** The company's pages in the footer's « Krizaka » column. @default the English words */
70
+ company?: Record<CompanyLinkId, string>;
61
71
  }
62
72
  /** The family's words in English and French. Pass `familyLabels[locale]`, or your own translation of the same shape. */
63
73
  declare const familyLabels: Record<SiteLocale, FamilyLabels>;
64
74
 
65
- export { type FamilyLabels, type Site, type SiteGroup, type SiteId, type SiteKind, type SiteLocale, type SiteMark, type SiteStatus, familyLabels, siteById, siteGroups, sites, sitesByGroup };
75
+ export { type CompanyLinkId, type FamilyLabels, type Site, type SiteGroup, type SiteId, type SiteKind, type SiteLocale, type SiteMark, type SiteStatus, companyLinks, familyLabels, siteById, siteGroups, sites, sitesByGroup };
package/dist/sites.js CHANGED
@@ -24,6 +24,11 @@ function siteById(id) {
24
24
  function sitesByGroup() {
25
25
  return siteGroups.map((group) => ({ group, sites: sites.filter((s) => s.group === group) })).filter((g) => g.sites.length > 0);
26
26
  }
27
+ var companyLinks = [
28
+ { id: "story", url: { en: "https://www.krizaka.com/story", fr: "https://www.krizaka.com/fr/story" } },
29
+ { id: "blog", url: { en: "https://blog.krizaka.com", fr: "https://blog.krizaka.com" } },
30
+ { id: "contact", url: { en: "https://www.krizaka.com/contact", fr: "https://www.krizaka.com/fr/contact" } }
31
+ ];
27
32
  var familyLabels = {
28
33
  en: {
29
34
  family: "Krizaka family",
@@ -46,7 +51,9 @@ var familyLabels = {
46
51
  },
47
52
  signature: { company: "A Krizaka company", product: "A Krizaka product", "open-source": "A Krizaka open-source project" },
48
53
  place: "Made in Montr\xE9al",
49
- version: "Version"
54
+ version: "Version",
55
+ lang: "en",
56
+ company: { story: "Our story", blog: "Blog", contact: "Contact us" }
50
57
  },
51
58
  fr: {
52
59
  family: "Famille Krizaka",
@@ -69,10 +76,13 @@ var familyLabels = {
69
76
  },
70
77
  signature: { company: "Une compagnie Krizaka", product: "Un produit Krizaka", "open-source": "Un projet open source de Krizaka" },
71
78
  place: "Fait \xE0 Montr\xE9al",
72
- version: "Version"
79
+ version: "Version",
80
+ lang: "fr",
81
+ company: { story: "Notre histoire", blog: "Blogue", contact: "Nous \xE9crire" }
73
82
  }
74
83
  };
75
84
  export {
85
+ companyLinks,
76
86
  familyLabels,
77
87
  siteById,
78
88
  siteGroups,
package/dist/sites.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/sites/sites.ts"],"sourcesContent":["// Server-safe: plain data. The Krizaka family — every site Krizaka runs, once. The family switcher of the bar\n// (`NavBar.Family`) and the common footer (`SiteFooter`) both read it, so adding a site is one release of this package:\n// every bar and every footer of the family follow.\n//\n// The words of the family (a site's one line, the groups, the statuses, the footer's signature) are brand data, written\n// here in English and French (`familyLabels`) — a site passes the set of its locale, or its own translation.\n\n/** A site of the family. */\nexport type SiteId = \"krizaka\" | \"orazaka\" | \"orochia\" | \"yasakia\" | \"yororis\" | \"yomizaka\" | \"kachizaka\" | \"akinaza\" | \"ui\" | \"java\" | \"motion\" | \"github\";\n\n/** What a site is: the company, a product, or an open-source project. It chooses the footer's signature line. */\nexport type SiteKind = \"company\" | \"product\" | \"open-source\";\n\n/**\n * `released`: open to visit. `upcoming`: announced, not released yet (said \"Coming soon\"). `construction`: under\n * construction — nothing offered (a QA-only app may run; the public page says so). `development`: being built in the\n * open, with a dev site (said \"In development\"). A site with none yet would use its repository as its address.\n */\nexport type SiteStatus = \"released\" | \"upcoming\" | \"construction\" | \"development\";\n\n/** The groups of the family, in reading order: Krizaka · Products · Open source · GitHub. */\nexport type SiteGroup = \"krizaka\" | \"products\" | \"open-source\" | \"github\";\n\n/** The mark a site wears: a brand of `ProductLogo` (Krizaka UI and Krizaka Java wear Krizaka's), or GitHub's. */\nexport type SiteMark = \"krizaka\" | \"orazaka\" | \"orochia\" | \"yasakia\" | \"yororis\" | \"yomizaka\" | \"kachizaka\" | \"akinaza\" | \"github\";\n\nexport interface Site {\n readonly id: SiteId;\n /** The name, never translated. */\n readonly name: string;\n /** The address of the site (its home). */\n readonly url: string;\n /** The address without the scheme, as people say it (`ui.krizaka.com`). */\n readonly host: string;\n readonly kind: SiteKind;\n readonly group: SiteGroup;\n readonly status: SiteStatus;\n readonly mark: SiteMark;\n /** The repository the site is built from. */\n readonly repo: string;\n}\n\nconst site = (s: Omit<Site, \"host\">): Site => ({ ...s, host: s.url.replace(/^https?:\\/\\//, \"\").replace(/\\/$/, \"\") });\n\n/** Every site of the family, in reading order (the group order, then the order inside each group). */\nexport const sites: readonly Site[] = [\n site({ id: \"krizaka\", name: \"Krizaka\", url: \"https://www.krizaka.com\", kind: \"company\", group: \"krizaka\", status: \"released\", mark: \"krizaka\", repo: \"https://github.com/krizaka/krizaka-com\" }),\n site({ id: \"orazaka\", name: \"Orazaka\", url: \"https://dev.orazaka.com\", kind: \"product\", group: \"products\", status: \"released\", mark: \"orazaka\", repo: \"https://github.com/krizaka/orazaka\" }),\n site({ id: \"orochia\", name: \"Orochia\", url: \"https://dev.orochia.com\", kind: \"product\", group: \"products\", status: \"released\", mark: \"orochia\", repo: \"https://github.com/krizaka/orochia\" }),\n site({ id: \"yasakia\", name: \"Yasakia\", url: \"https://dev.yasakia.com\", kind: \"product\", group: \"products\", status: \"development\", mark: \"yasakia\", repo: \"https://github.com/krizaka/yasakia\" }),\n site({ id: \"yororis\", name: \"Yororis\", url: \"https://dev.yororis.com\", kind: \"product\", group: \"products\", status: \"construction\", mark: \"yororis\", repo: \"https://github.com/krizaka/yororis\" }),\n site({ id: \"yomizaka\", name: \"Yomizaka\", url: \"https://dev.yomizaka.com\", kind: \"product\", group: \"products\", status: \"development\", mark: \"yomizaka\", repo: \"https://github.com/krizaka/yomizaka\" }),\n site({ id: \"kachizaka\", name: \"Kachizaka\", url: \"https://dev.kachizaka.com\", kind: \"product\", group: \"products\", status: \"development\", mark: \"kachizaka\", repo: \"https://github.com/krizaka/kachizaka\" }),\n site({ id: \"akinaza\", name: \"Akinaza\", url: \"https://dev.akinaza.com\", kind: \"product\", group: \"products\", status: \"development\", mark: \"akinaza\", repo: \"https://github.com/krizaka/akinaza\" }),\n site({ id: \"ui\", name: \"Krizaka UI\", url: \"https://ui.krizaka.com\", kind: \"open-source\", group: \"open-source\", status: \"released\", mark: \"krizaka\", repo: \"https://github.com/krizaka/krizaka-ui\" }),\n site({ id: \"java\", name: \"Krizaka Java\", url: \"https://java.krizaka.com\", kind: \"open-source\", group: \"open-source\", status: \"released\", mark: \"krizaka\", repo: \"https://github.com/krizaka/krizaka-build\" }),\n // The motion lab: built in the open on GitHub Pages; what proves itself there moves into Krizaka UI.\n site({ id: \"motion\", name: \"Krizaka Motion\", url: \"https://krizaka.github.io/krizaka-motion\", kind: \"open-source\", group: \"open-source\", status: \"development\", mark: \"krizaka\", repo: \"https://github.com/krizaka/krizaka-motion\" }),\n site({ id: \"github\", name: \"GitHub\", url: \"https://github.com/krizaka\", kind: \"open-source\", group: \"github\", status: \"released\", mark: \"github\", repo: \"https://github.com/krizaka\" }),\n];\n\n/** The groups, in reading order. */\nexport const siteGroups: readonly SiteGroup[] = [\"krizaka\", \"products\", \"open-source\", \"github\"];\n\n/** A site by id. */\nexport function siteById(id: SiteId): Site {\n const found = sites.find((s) => s.id === id);\n if (!found) throw new Error(`Unknown Krizaka site \"${id}\".`);\n return found;\n}\n\n/** The family grouped, in reading order: `[{ group, sites }]`, empty groups left out. */\nexport function sitesByGroup(): { group: SiteGroup; sites: Site[] }[] {\n return siteGroups.map((group) => ({ group, sites: sites.filter((s) => s.group === group) })).filter((g) => g.sites.length > 0);\n}\n\n/** The languages the family's words are written in. */\nexport type SiteLocale = \"en\" | \"fr\";\n\n/** The words of the family: the switcher, the footer, each site's one line. */\nexport interface FamilyLabels {\n /** The family's name: the switcher's navigation and its button, the footer's navigation (“Krizaka family”). */\n family: string;\n /** The heading of each group. */\n groups: Record<SiteGroup, string>;\n /** The badge of a site that is not released. */\n status: Record<Exclude<SiteStatus, \"released\">, string>;\n /** Says which site is the current one (“You are here”). */\n current: string;\n /** One line per site: what it is. */\n descriptions: Record<SiteId, string>;\n /** The footer's signature, by the kind of the current site (“A Krizaka product”). */\n signature: Record<SiteKind, string>;\n /** The footer's place line (“Made in Montréal”). */\n place: string;\n /** The accessible name of the version (“Version”). */\n version: string;\n}\n\n/** The family's words in English and French. Pass `familyLabels[locale]`, or your own translation of the same shape. */\nexport const familyLabels: Record<SiteLocale, FamilyLabels> = {\n en: {\n family: \"Krizaka family\",\n groups: { krizaka: \"Krizaka\", products: \"Products\", \"open-source\": \"Open source\", github: \"GitHub\" },\n status: { upcoming: \"Coming soon\", construction: \"Under construction\", development: \"In development\" },\n current: \"You are here\",\n descriptions: {\n krizaka: \"The company: our products, our open source, our story.\",\n orazaka: \"Sovereign AI on your own servers: chat, documents, images and video — and the engine under the other products.\",\n orochia: \"A video platform for creators.\",\n yasakia: \"Meet real people: introductions, and photos checked before you see them.\",\n yororis: \"A listening space with a face and a voice.\",\n yomizaka: \"Yomizaka reads your leases, contracts and invoices.\",\n kachizaka: \"Predictions among friends — live data, in real time.\",\n akinaza: \"Running a shop in Québec, for less — Loi 25 by design.\",\n ui: \"Components, tokens, icons and charts — web and React Native.\",\n java: \"Spring Boot building blocks on Maven Central.\",\n motion: \"The motion lab: the kit's motion, played live with its knobs.\",\n github: \"Every repository, in the open.\",\n },\n signature: { company: \"A Krizaka company\", product: \"A Krizaka product\", \"open-source\": \"A Krizaka open-source project\" },\n place: \"Made in Montréal\",\n version: \"Version\",\n },\n fr: {\n family: \"Famille Krizaka\",\n groups: { krizaka: \"Krizaka\", products: \"Produits\", \"open-source\": \"Open source\", github: \"GitHub\" },\n status: { upcoming: \"Bientôt\", construction: \"En construction\", development: \"En développement\" },\n current: \"Vous êtes ici\",\n descriptions: {\n krizaka: \"La compagnie : nos produits, notre open source, notre histoire.\",\n orazaka: \"L’IA souveraine sur vos propres serveurs : conversation, documents, images et vidéo — et le moteur des autres produits.\",\n orochia: \"Une plateforme vidéo pour les créateurs.\",\n yasakia: \"Rencontrez de vraies personnes : des présentations, et des photos vérifiées avant que vous les voyiez.\",\n yororis: \"Un espace d’écoute avec un visage et une voix.\",\n yomizaka: \"Yomizaka lit vos baux, contrats et factures.\",\n kachizaka: \"Les pronostics entre amis — des données en direct.\",\n akinaza: \"Tenir une boutique au Québec, pour moins cher — Loi 25 dès la conception.\",\n ui: \"Composants, jetons, icônes et graphiques — web et React Native.\",\n java: \"Des briques Spring Boot sur Maven Central.\",\n motion: \"Le labo du mouvement : le mouvement du kit, joué en direct, avec ses réglages.\",\n github: \"Tous les dépôts, au grand jour.\",\n },\n signature: { company: \"Une compagnie Krizaka\", product: \"Un produit Krizaka\", \"open-source\": \"Un projet open source de Krizaka\" },\n place: \"Fait à Montréal\",\n version: \"Version\",\n },\n};\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/sites/sites.ts"],"sourcesContent":["// Server-safe: plain data. The Krizaka family — every site Krizaka runs, once. The family switcher of the bar\n// (`NavBar.Family`) and the common footer (`SiteFooter`) both read it, so adding a site is one release of this package:\n// every bar and every footer of the family follow.\n//\n// The words of the family (a site's one line, the groups, the statuses, the footer's signature) are brand data, written\n// here in English and French (`familyLabels`) — a site passes the set of its locale, or its own translation.\n\n/** A site of the family. */\nexport type SiteId = \"krizaka\" | \"orazaka\" | \"orochia\" | \"yasakia\" | \"yororis\" | \"yomizaka\" | \"kachizaka\" | \"akinaza\" | \"ui\" | \"java\" | \"motion\" | \"github\";\n\n/** What a site is: the company, a product, or an open-source project. It chooses the footer's signature line. */\nexport type SiteKind = \"company\" | \"product\" | \"open-source\";\n\n/**\n * `released`: open to visit. `upcoming`: announced, not released yet (said \"Coming soon\"). `construction`: under\n * construction — nothing offered (a QA-only app may run; the public page says so). `development`: being built in the\n * open, with a dev site (said \"In development\"). A site with none yet would use its repository as its address.\n */\nexport type SiteStatus = \"released\" | \"upcoming\" | \"construction\" | \"development\";\n\n/** The groups of the family, in reading order: Krizaka · Products · Open source · GitHub. */\nexport type SiteGroup = \"krizaka\" | \"products\" | \"open-source\" | \"github\";\n\n/** The mark a site wears: a brand of `ProductLogo` (Krizaka UI and Krizaka Java wear Krizaka's), or GitHub's. */\nexport type SiteMark = \"krizaka\" | \"orazaka\" | \"orochia\" | \"yasakia\" | \"yororis\" | \"yomizaka\" | \"kachizaka\" | \"akinaza\" | \"github\";\n\nexport interface Site {\n readonly id: SiteId;\n /** The name, never translated. */\n readonly name: string;\n /** The address of the site (its home). */\n readonly url: string;\n /** The address without the scheme, as people say it (`ui.krizaka.com`). */\n readonly host: string;\n readonly kind: SiteKind;\n readonly group: SiteGroup;\n readonly status: SiteStatus;\n readonly mark: SiteMark;\n /** The repository the site is built from. */\n readonly repo: string;\n}\n\nconst site = (s: Omit<Site, \"host\">): Site => ({ ...s, host: s.url.replace(/^https?:\\/\\//, \"\").replace(/\\/$/, \"\") });\n\n/** Every site of the family, in reading order (the group order, then the order inside each group). */\nexport const sites: readonly Site[] = [\n site({ id: \"krizaka\", name: \"Krizaka\", url: \"https://www.krizaka.com\", kind: \"company\", group: \"krizaka\", status: \"released\", mark: \"krizaka\", repo: \"https://github.com/krizaka/krizaka-com\" }),\n site({ id: \"orazaka\", name: \"Orazaka\", url: \"https://dev.orazaka.com\", kind: \"product\", group: \"products\", status: \"released\", mark: \"orazaka\", repo: \"https://github.com/krizaka/orazaka\" }),\n site({ id: \"orochia\", name: \"Orochia\", url: \"https://dev.orochia.com\", kind: \"product\", group: \"products\", status: \"released\", mark: \"orochia\", repo: \"https://github.com/krizaka/orochia\" }),\n site({ id: \"yasakia\", name: \"Yasakia\", url: \"https://dev.yasakia.com\", kind: \"product\", group: \"products\", status: \"development\", mark: \"yasakia\", repo: \"https://github.com/krizaka/yasakia\" }),\n site({ id: \"yororis\", name: \"Yororis\", url: \"https://dev.yororis.com\", kind: \"product\", group: \"products\", status: \"construction\", mark: \"yororis\", repo: \"https://github.com/krizaka/yororis\" }),\n site({ id: \"yomizaka\", name: \"Yomizaka\", url: \"https://dev.yomizaka.com\", kind: \"product\", group: \"products\", status: \"development\", mark: \"yomizaka\", repo: \"https://github.com/krizaka/yomizaka\" }),\n site({ id: \"kachizaka\", name: \"Kachizaka\", url: \"https://dev.kachizaka.com\", kind: \"product\", group: \"products\", status: \"development\", mark: \"kachizaka\", repo: \"https://github.com/krizaka/kachizaka\" }),\n site({ id: \"akinaza\", name: \"Akinaza\", url: \"https://dev.akinaza.com\", kind: \"product\", group: \"products\", status: \"development\", mark: \"akinaza\", repo: \"https://github.com/krizaka/akinaza\" }),\n site({ id: \"ui\", name: \"Krizaka UI\", url: \"https://ui.krizaka.com\", kind: \"open-source\", group: \"open-source\", status: \"released\", mark: \"krizaka\", repo: \"https://github.com/krizaka/krizaka-ui\" }),\n site({ id: \"java\", name: \"Krizaka Java\", url: \"https://java.krizaka.com\", kind: \"open-source\", group: \"open-source\", status: \"released\", mark: \"krizaka\", repo: \"https://github.com/krizaka/krizaka-build\" }),\n // The motion lab: built in the open on GitHub Pages; what proves itself there moves into Krizaka UI.\n site({ id: \"motion\", name: \"Krizaka Motion\", url: \"https://krizaka.github.io/krizaka-motion\", kind: \"open-source\", group: \"open-source\", status: \"development\", mark: \"krizaka\", repo: \"https://github.com/krizaka/krizaka-motion\" }),\n site({ id: \"github\", name: \"GitHub\", url: \"https://github.com/krizaka\", kind: \"open-source\", group: \"github\", status: \"released\", mark: \"github\", repo: \"https://github.com/krizaka\" }),\n];\n\n/** The groups, in reading order. */\nexport const siteGroups: readonly SiteGroup[] = [\"krizaka\", \"products\", \"open-source\", \"github\"];\n\n/** A site by id. */\nexport function siteById(id: SiteId): Site {\n const found = sites.find((s) => s.id === id);\n if (!found) throw new Error(`Unknown Krizaka site \"${id}\".`);\n return found;\n}\n\n/** The family grouped, in reading order: `[{ group, sites }]`, empty groups left out. */\nexport function sitesByGroup(): { group: SiteGroup; sites: Site[] }[] {\n return siteGroups.map((group) => ({ group, sites: sites.filter((s) => s.group === group) })).filter((g) => g.sites.length > 0);\n}\n\n/** The languages the family's words are written in. */\nexport type SiteLocale = \"en\" | \"fr\";\n\n/** The company's own pages, the footer's « Krizaka » column (the brand's home is the signature line's link). */\nexport type CompanyLinkId = \"story\" | \"blog\" | \"contact\";\nexport const companyLinks: readonly { id: CompanyLinkId; url: Record<SiteLocale, string> }[] = [\n { id: \"story\", url: { en: \"https://www.krizaka.com/story\", fr: \"https://www.krizaka.com/fr/story\" } },\n { id: \"blog\", url: { en: \"https://blog.krizaka.com\", fr: \"https://blog.krizaka.com\" } },\n { id: \"contact\", url: { en: \"https://www.krizaka.com/contact\", fr: \"https://www.krizaka.com/fr/contact\" } },\n];\n\n/** The words of the family: the switcher, the footer, each site's one line. */\nexport interface FamilyLabels {\n /** The family's name: the switcher's navigation and its button, the footer's navigation (“Krizaka family”). */\n family: string;\n /** The heading of each group. */\n groups: Record<SiteGroup, string>;\n /** The badge of a site that is not released. */\n status: Record<Exclude<SiteStatus, \"released\">, string>;\n /** Says which site is the current one (“You are here”). */\n current: string;\n /** One line per site: what it is. */\n descriptions: Record<SiteId, string>;\n /** The footer's signature, by the kind of the current site (“A Krizaka product”). */\n signature: Record<SiteKind, string>;\n /** The footer's place line (“Made in Montréal”). */\n place: string;\n /** The accessible name of the version (“Version”). */\n version: string;\n /** The language of these words: the company links open in it. @default \"en\" */\n lang?: SiteLocale;\n /** The company's pages in the footer's « Krizaka » column. @default the English words */\n company?: Record<CompanyLinkId, string>;\n}\n\n/** The family's words in English and French. Pass `familyLabels[locale]`, or your own translation of the same shape. */\nexport const familyLabels: Record<SiteLocale, FamilyLabels> = {\n en: {\n family: \"Krizaka family\",\n groups: { krizaka: \"Krizaka\", products: \"Products\", \"open-source\": \"Open source\", github: \"GitHub\" },\n status: { upcoming: \"Coming soon\", construction: \"Under construction\", development: \"In development\" },\n current: \"You are here\",\n descriptions: {\n krizaka: \"The company: our products, our open source, our story.\",\n orazaka: \"Sovereign AI on your own servers: chat, documents, images and video — and the engine under the other products.\",\n orochia: \"A video platform for creators.\",\n yasakia: \"Meet real people: introductions, and photos checked before you see them.\",\n yororis: \"A listening space with a face and a voice.\",\n yomizaka: \"Yomizaka reads your leases, contracts and invoices.\",\n kachizaka: \"Predictions among friends — live data, in real time.\",\n akinaza: \"Running a shop in Québec, for less — Loi 25 by design.\",\n ui: \"Components, tokens, icons and charts — web and React Native.\",\n java: \"Spring Boot building blocks on Maven Central.\",\n motion: \"The motion lab: the kit's motion, played live with its knobs.\",\n github: \"Every repository, in the open.\",\n },\n signature: { company: \"A Krizaka company\", product: \"A Krizaka product\", \"open-source\": \"A Krizaka open-source project\" },\n place: \"Made in Montréal\",\n version: \"Version\",\n lang: \"en\",\n company: { story: \"Our story\", blog: \"Blog\", contact: \"Contact us\" },\n },\n fr: {\n family: \"Famille Krizaka\",\n groups: { krizaka: \"Krizaka\", products: \"Produits\", \"open-source\": \"Open source\", github: \"GitHub\" },\n status: { upcoming: \"Bientôt\", construction: \"En construction\", development: \"En développement\" },\n current: \"Vous êtes ici\",\n descriptions: {\n krizaka: \"La compagnie : nos produits, notre open source, notre histoire.\",\n orazaka: \"L’IA souveraine sur vos propres serveurs : conversation, documents, images et vidéo — et le moteur des autres produits.\",\n orochia: \"Une plateforme vidéo pour les créateurs.\",\n yasakia: \"Rencontrez de vraies personnes : des présentations, et des photos vérifiées avant que vous les voyiez.\",\n yororis: \"Un espace d’écoute avec un visage et une voix.\",\n yomizaka: \"Yomizaka lit vos baux, contrats et factures.\",\n kachizaka: \"Les pronostics entre amis — des données en direct.\",\n akinaza: \"Tenir une boutique au Québec, pour moins cher — Loi 25 dès la conception.\",\n ui: \"Composants, jetons, icônes et graphiques — web et React Native.\",\n java: \"Des briques Spring Boot sur Maven Central.\",\n motion: \"Le labo du mouvement : le mouvement du kit, joué en direct, avec ses réglages.\",\n github: \"Tous les dépôts, au grand jour.\",\n },\n signature: { company: \"Une compagnie Krizaka\", product: \"Un produit Krizaka\", \"open-source\": \"Un projet open source de Krizaka\" },\n place: \"Fait à Montréal\",\n version: \"Version\",\n lang: \"fr\",\n company: { story: \"Notre histoire\", blog: \"Blogue\", contact: \"Nous écrire\" },\n },\n};\n"],"mappings":"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","names":[]}
package/dist/slider.js CHANGED
@@ -14,14 +14,14 @@ var slider = tv({
14
14
  header: "flex items-baseline justify-between gap-3 text-xs font-semibold text-fg-secondary",
15
15
  value: "font-mono text-[11px] tabular-nums text-fg-secondary",
16
16
  control: "relative flex touch-none select-none items-center data-disabled:cursor-not-allowed data-disabled:opacity-40 data-[orientation=horizontal]:h-6 data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:min-h-40 data-[orientation=vertical]:w-6 data-[orientation=vertical]:flex-col",
17
- track: "relative grow overflow-hidden rounded-full bg-surface-3 inset-shadow-well data-[orientation=horizontal]:h-1.5 data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-1.5",
18
- range: "absolute rounded-full data-[orientation=horizontal]:h-full data-[orientation=vertical]:w-full",
17
+ track: "relative grow overflow-hidden rounded-sm bg-surface-3 inset-shadow-well data-[orientation=horizontal]:h-1.5 data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-1.5",
18
+ range: "absolute rounded-sm data-[orientation=horizontal]:h-full data-[orientation=vertical]:w-full",
19
19
  thumb: "group/thumb relative block h-5 w-5 cursor-grab rounded-full border-2 border-accent bg-fg-on-media shadow-raised transition-[box-shadow,scale] duration-150 hover:ring-4 hover:ring-accent/15 focus-visible:outline-hidden focus-visible:focus-ring active:scale-110 active:cursor-grabbing motion-reduce:transition-none motion-reduce:active:scale-100",
20
20
  // The value over the thumb: shown while the thumb is hovered, focused or held.
21
21
  bubble: "pointer-events-none absolute bottom-full left-1/2 mb-2.5 -translate-x-1/2 whitespace-nowrap rounded-lg bg-fg px-2 py-1 font-mono text-[11px] font-semibold tabular-nums text-surface-0 opacity-0 shadow-floating transition-opacity duration-150 after:absolute after:left-1/2 after:top-full after:-translate-x-1/2 after:border-4 after:border-transparent after:border-t-fg group-hover/thumb:opacity-100 group-focus-visible/thumb:opacity-100 group-active/thumb:opacity-100 data-[always]:opacity-100 motion-reduce:transition-none",
22
22
  bubbleVertical: "bottom-auto left-full top-1/2 mb-0 ml-3 -translate-x-0 -translate-y-1/2 after:hidden",
23
23
  ticks: "pointer-events-none absolute inset-0",
24
- tick: "absolute rounded-full bg-border-strong data-[on]:bg-on-accent/70 data-[orientation=horizontal]:top-1/2 data-[orientation=horizontal]:h-1 data-[orientation=horizontal]:w-px data-[orientation=horizontal]:-translate-x-1/2 data-[orientation=horizontal]:-translate-y-1/2 data-[orientation=vertical]:left-1/2 data-[orientation=vertical]:h-px data-[orientation=vertical]:w-1 data-[orientation=vertical]:-translate-x-1/2 data-[orientation=vertical]:translate-y-1/2",
24
+ tick: "absolute rounded-sm bg-border-strong data-[on]:bg-on-accent/70 data-[orientation=horizontal]:top-1/2 data-[orientation=horizontal]:h-1 data-[orientation=horizontal]:w-px data-[orientation=horizontal]:-translate-x-1/2 data-[orientation=horizontal]:-translate-y-1/2 data-[orientation=vertical]:left-1/2 data-[orientation=vertical]:h-px data-[orientation=vertical]:w-1 data-[orientation=vertical]:-translate-x-1/2 data-[orientation=vertical]:translate-y-1/2",
25
25
  marks: "relative h-4 w-full text-[11px] font-medium tabular-nums text-fg-secondary",
26
26
  mark: "absolute top-0 -translate-x-1/2 whitespace-nowrap first:translate-x-0 last:-translate-x-full"
27
27
  },