@krizaka/sovkora-design-system 0.0.0-stage → 4.0.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 (56) hide show
  1. package/CHANGELOG.md +234 -0
  2. package/LICENSE +202 -0
  3. package/README.md +82 -2
  4. package/package.json +112 -3
  5. package/registry/badge.json +97 -0
  6. package/registry/button.json +140 -0
  7. package/registry/chat-showcase.json +113 -0
  8. package/registry/clip-player.json +120 -0
  9. package/registry/command-palette.json +116 -0
  10. package/registry/examples/badge/model-state.tsx +16 -0
  11. package/registry/examples/button/send.tsx +18 -0
  12. package/registry/examples/chat-showcase/french.tsx +20 -0
  13. package/registry/examples/chat-showcase/sovereign-answer.tsx +20 -0
  14. package/registry/examples/clip-player/tea-pour.tsx +27 -0
  15. package/registry/examples/command-palette/workspace.tsx +30 -0
  16. package/registry/examples/icon/engine.tsx +26 -0
  17. package/registry/examples/icon/in-a-button.tsx +12 -0
  18. package/registry/examples/run-facts/clip-run.tsx +15 -0
  19. package/registry/examples/sentinel-mini/sidebar.tsx +11 -0
  20. package/registry/examples/skeleton/answer-loading.tsx +11 -0
  21. package/registry/examples/video-result/assistant.tsx +36 -0
  22. package/registry/examples/video-result/tea-pour.tsx +40 -0
  23. package/registry/foundations.json +2067 -0
  24. package/registry/icon.json +109 -0
  25. package/registry/index.json +242 -0
  26. package/registry/run-facts.json +75 -0
  27. package/registry/sentinel-mini.json +81 -0
  28. package/registry/skeleton.json +116 -0
  29. package/registry/video-result.json +167 -0
  30. package/src/components/Badge.tsx +36 -0
  31. package/src/components/Button.tsx +26 -0
  32. package/src/components/ChatShowcase.tsx +248 -0
  33. package/src/components/ClipPlayer.tsx +223 -0
  34. package/src/components/CommandPalette.tsx +104 -0
  35. package/src/components/CommandPalette.types.ts +33 -0
  36. package/src/components/Input.tsx +14 -0
  37. package/src/components/RunFacts.tsx +36 -0
  38. package/src/components/SentinelMini.tsx +61 -0
  39. package/src/components/Skeleton.tsx +50 -0
  40. package/src/components/VideoResult.tsx +123 -0
  41. package/src/components/badge.meta.ts +34 -0
  42. package/src/components/button.meta.ts +35 -0
  43. package/src/components/chat-showcase.css.ts +19 -0
  44. package/src/components/chat-showcase.meta.ts +50 -0
  45. package/src/components/clip-player.meta.ts +48 -0
  46. package/src/components/command-palette.meta.ts +47 -0
  47. package/src/components/icon.meta.ts +45 -0
  48. package/src/components/run-facts.meta.ts +32 -0
  49. package/src/components/sentinel-mini.meta.ts +39 -0
  50. package/src/components/skeleton.meta.ts +42 -0
  51. package/src/components/video-result.meta.ts +53 -0
  52. package/src/icon.registry.tsx +737 -0
  53. package/src/icon.tsx +74 -0
  54. package/src/index.ts +43 -0
  55. package/src/meta.ts +76 -0
  56. package/src/theme.css +859 -0
@@ -0,0 +1,97 @@
1
+ {
2
+ "name": "badge",
3
+ "type": "composite",
4
+ "title": "Badge",
5
+ "summary": "The @krizaka/ui badge with the 1.x `variant` kept as a deprecated alias of `tone`.",
6
+ "description": "The @krizaka/ui badge with the 1.x `variant` kept as a deprecated alias of `tone`.",
7
+ "why": "Sovkora 1.x badges took `variant` (`default`, `success`…); the platform says `tone`. This adapter maps one onto the other so the apps keep working while they migrate.",
8
+ "status": "stable",
9
+ "deprecated": null,
10
+ "category": "data-display",
11
+ "platforms": "web",
12
+ "builtOn": [
13
+ "ui/badge"
14
+ ],
15
+ "whenToUse": [
16
+ "In code already importing `Badge` from `@krizaka/sovkora-design-system`: a model's state, a job's status."
17
+ ],
18
+ "whenNotToUse": [
19
+ {
20
+ "when": "In new code: import `Badge` from `@krizaka/ui/badge` and write `tone`.",
21
+ "use": "ui/badge"
22
+ }
23
+ ],
24
+ "bestPractices": [
25
+ "Write `tone`, not `variant` (deprecated since 2.0; `default` → `neutral`).",
26
+ "One or two words: `Local`, `Running`, `Failed`."
27
+ ],
28
+ "accessibility": {
29
+ "keyboard": [],
30
+ "notes": [
31
+ "The primitive's: a `<span>` read with its content; the colour is never the only signal."
32
+ ]
33
+ },
34
+ "related": [
35
+ "ui/badge"
36
+ ],
37
+ "web": {
38
+ "entry": "@krizaka/sovkora-design-system",
39
+ "import": "import { Badge } from \"@krizaka/sovkora-design-system\";",
40
+ "props": [
41
+ {
42
+ "component": "Badge",
43
+ "description": "The",
44
+ "props": [
45
+ {
46
+ "name": "dot",
47
+ "type": "boolean",
48
+ "default": null,
49
+ "description": "A small dot before the text, in the tone's colour (pulsing with `pulse`).",
50
+ "required": false
51
+ },
52
+ {
53
+ "name": "pulse",
54
+ "type": "boolean",
55
+ "default": null,
56
+ "description": "Makes the `dot` pulse (stopped under reduced motion).",
57
+ "required": false
58
+ },
59
+ {
60
+ "name": "size",
61
+ "type": "\"sm\" | \"md\"",
62
+ "default": "sm",
63
+ "description": "sm · md.",
64
+ "required": false
65
+ },
66
+ {
67
+ "name": "tone",
68
+ "type": "\"neutral\" | \"accent\" | \"success\" | \"warning\" | \"danger\" | \"scrim\"",
69
+ "default": "neutral",
70
+ "description": "neutral · accent · success · warning · danger (soft tints, the text stays a text role) · scrim (on a media).",
71
+ "required": false
72
+ },
73
+ {
74
+ "name": "variant",
75
+ "type": "BadgeVariant",
76
+ "default": null,
77
+ "description": "@deprecated Since 2.0 — use `tone` (`default` → `neutral`, the other names are the same).",
78
+ "required": false
79
+ }
80
+ ]
81
+ }
82
+ ],
83
+ "examples": [
84
+ {
85
+ "name": "model-state",
86
+ "title": "A model's state",
87
+ "description": "Local, loading, failed — the tones of the primitive.",
88
+ "path": "examples/badge/model-state.tsx",
89
+ "module": "@krizaka/sovkora-design-system/registry/examples/badge/model-state",
90
+ "code": "import { Badge } from \"@krizaka/sovkora-design-system\";\n\n// A model's state in the console: `tone`, never the deprecated `variant`.\nexport default function ModelState() {\n return (\n <div className=\"flex flex-wrap gap-2\">\n <Badge tone=\"success\" dot>\n Local · ready\n </Badge>\n <Badge tone=\"accent\" dot pulse>\n Loading\n </Badge>\n <Badge tone=\"danger\">Failed</Badge>\n </div>\n );\n}\n"
91
+ }
92
+ ]
93
+ },
94
+ "native": null,
95
+ "dependencies": [],
96
+ "registryDependencies": []
97
+ }
@@ -0,0 +1,140 @@
1
+ {
2
+ "name": "button",
3
+ "type": "composite",
4
+ "title": "Button",
5
+ "summary": "The @krizaka/ui button with the Sovkora 1.x default kept: without a `variant`, it is the primary (orange) button.",
6
+ "description": "The @krizaka/ui button with the Sovkora 1.x default kept: without a `variant`, it is the primary (orange) button.",
7
+ "why": "Sovkora 1.x buttons were primary by default; the platform's default is `secondary`. This adapter keeps the 1.x default so the apps written against it look the same — everything else is the primitive's.",
8
+ "status": "stable",
9
+ "deprecated": null,
10
+ "category": "actions",
11
+ "platforms": "web",
12
+ "builtOn": [
13
+ "ui/button"
14
+ ],
15
+ "whenToUse": [
16
+ "In code already importing `Button` from `@krizaka/sovkora-design-system`."
17
+ ],
18
+ "whenNotToUse": [
19
+ {
20
+ "when": "In new code: import `Button` from `@krizaka/ui/button` and say the variant.",
21
+ "use": "ui/button"
22
+ }
23
+ ],
24
+ "bestPractices": [
25
+ "One primary action per view: pass `variant=\"secondary\"` or `\"ghost\"` to the others.",
26
+ "Lock it while sending (`disabled` + `loading`): the input-blocking rule (ERR-126)."
27
+ ],
28
+ "accessibility": {
29
+ "keyboard": [],
30
+ "notes": [
31
+ "The primitive's: a native `<button>`, its focus ring, `loading` sets `aria-busy`."
32
+ ]
33
+ },
34
+ "related": [
35
+ "ui/button",
36
+ "icon"
37
+ ],
38
+ "web": {
39
+ "entry": "@krizaka/sovkora-design-system",
40
+ "import": "import { Button } from \"@krizaka/sovkora-design-system\";",
41
+ "props": [
42
+ {
43
+ "component": "Button",
44
+ "description": "The",
45
+ "props": [
46
+ {
47
+ "name": "announce",
48
+ "type": "string",
49
+ "default": null,
50
+ "description": "A message announced politely by assistive technology when it changes (“Saved”, “Upload failed”) — passed translated.",
51
+ "required": false
52
+ },
53
+ {
54
+ "name": "asChild",
55
+ "type": "boolean",
56
+ "default": null,
57
+ "description": "Renders the child (e.g. a <Link>) instead of the <button>, with props, classes and ref merged.",
58
+ "required": false
59
+ },
60
+ {
61
+ "name": "indicator",
62
+ "type": "boolean",
63
+ "default": "true",
64
+ "description": "Shows the glyph while `loading` / with a `status`. `false`: you draw your own.",
65
+ "required": false
66
+ },
67
+ {
68
+ "name": "loading",
69
+ "type": "boolean",
70
+ "default": null,
71
+ "description": "Disables and signals the wait (aria-busy, data-loading) and shows the Krizaka loader glyph before the label; the\nbutton keeps its colour.",
72
+ "required": false
73
+ },
74
+ {
75
+ "name": "magnetic",
76
+ "type": "boolean",
77
+ "default": null,
78
+ "description": "@deprecated Since 3.31 (krizaka-ui#393): does nothing — a button never moves under the pointer. Removed in 4.0.",
79
+ "required": false
80
+ },
81
+ {
82
+ "name": "progress",
83
+ "type": "number | null",
84
+ "default": null,
85
+ "description": "Between 0 and 1, while `loading`: the glyph's trace and a light fill across the button grow to the value (an\nupload, an export).",
86
+ "required": false
87
+ },
88
+ {
89
+ "name": "shape",
90
+ "type": "\"rounded\" | \"pill\" | \"cut\"",
91
+ "default": "rounded",
92
+ "description": "`rounded` (an 8 px radius, the radius of a field) · `pill`. `cut` is deprecated (krizaka-ui#393: the chamfer is\nretired) — it draws `rounded` and warns in development; it will be removed in 4.0.",
93
+ "required": false
94
+ },
95
+ {
96
+ "name": "shimmer",
97
+ "type": "boolean",
98
+ "default": null,
99
+ "description": "@deprecated Since 3.31 (krizaka-ui#393): does nothing — the hover is quiet. Removed in 4.0.",
100
+ "required": false
101
+ },
102
+ {
103
+ "name": "size",
104
+ "type": "\"sm\" | \"md\" | \"lg\" | \"icon\"",
105
+ "default": "md",
106
+ "description": "sm · md · lg, or `icon` (a square).",
107
+ "required": false
108
+ },
109
+ {
110
+ "name": "status",
111
+ "type": "\"success\" | \"error\" | null",
112
+ "default": null,
113
+ "description": "How the action ended: `success` draws a check, `error` a cross (and the button shakes its head once); a ring of\nthe status colour opens around it. Clear it to return to rest.",
114
+ "required": false
115
+ },
116
+ {
117
+ "name": "variant",
118
+ "type": "\"danger\" | \"primary\" | \"gradient\" | \"secondary\" | \"outline\" | \"ghost\"",
119
+ "default": "primary",
120
+ "description": "The look: `primary` (the accent), `gradient` (accent → accent-2), `secondary` (a raised surface), `outline`,\n`ghost`, `danger`.",
121
+ "required": false
122
+ }
123
+ ]
124
+ }
125
+ ],
126
+ "examples": [
127
+ {
128
+ "name": "send",
129
+ "title": "Send a prompt",
130
+ "description": "The primary by default; locked while the answer is generated.",
131
+ "path": "examples/button/send.tsx",
132
+ "module": "@krizaka/sovkora-design-system/registry/examples/button/send",
133
+ "code": "\"use client\";\n\nimport { Button } from \"@krizaka/sovkora-design-system\";\nimport { useState } from \"react\";\n\n// Primary by default (the 1.x default); locked while the answer is generated (ERR-126).\nexport default function Send() {\n const [generating, setGenerating] = useState(false);\n const send = () => {\n setGenerating(true);\n setTimeout(() => setGenerating(false), 1500);\n };\n return (\n <Button loading={generating} disabled={generating} onClick={send}>\n Send\n </Button>\n );\n}\n"
134
+ }
135
+ ]
136
+ },
137
+ "native": null,
138
+ "dependencies": [],
139
+ "registryDependencies": []
140
+ }
@@ -0,0 +1,113 @@
1
+ {
2
+ "name": "chat-showcase",
3
+ "type": "composite",
4
+ "title": "Chat showcase",
5
+ "summary": "A self-playing sovereign AI chat: a question, the answer typed out, the interceptor pipeline it went through, and the promise that nothing left the premises.",
6
+ "description": "A self-playing sovereign AI chat: a question, the answer typed out, the interceptor pipeline it went through, and the promise that nothing left the premises.",
7
+ "why": "Sovkora sells one idea — your AI answers on your own machines, through a deterministic pipeline, with zero data egress. A chat bubble from @krizaka/ui cannot tell that story; this composite stages it the same way on the website, the client app and the console: the persona asks, the engine answers locally, the pipeline chips land, the privacy line closes.",
8
+ "status": "stable",
9
+ "deprecated": null,
10
+ "category": "data-display",
11
+ "platforms": "web",
12
+ "builtOn": [],
13
+ "whenToUse": [
14
+ "On a home or a product page, to show what Sovkora does in one glance.",
15
+ "In an empty state of the chat (first visit), as a demonstration before the first question."
16
+ ],
17
+ "whenNotToUse": [
18
+ {
19
+ "when": "For a real conversation: this is a scripted mockup, not a chat."
20
+ },
21
+ {
22
+ "when": "For a short status of the engine (online, model).",
23
+ "use": "ui/badge"
24
+ }
25
+ ],
26
+ "bestPractices": [
27
+ "Speak as a named persona with a real need (\"Eric, finance lead\"), never an admin or a test account.",
28
+ "The pipeline names steps the reader understands (`PII masked`, `Routed locally`), not class names.",
29
+ "Every word is a prop (`labels`, `question`, `answer`, `pipeline`): the app translates them.",
30
+ "One per page: it moves, and two moving mockups compete."
31
+ ],
32
+ "accessibility": {
33
+ "keyboard": [],
34
+ "notes": [
35
+ "`role=\"img\"` with the question and the answer as its name: a screen reader hears the exchange once, not the typing.",
36
+ "Under `prefers-reduced-motion` the final state shows at once: no typing, no pulse, no caret.",
37
+ "The composer is the kit's `MessageComposer` (pill), `inert` and `aria-hidden`: it is the same component as the app's chat, not a field here."
38
+ ]
39
+ },
40
+ "related": [
41
+ "icon",
42
+ "sentinel-mini",
43
+ "ui/card"
44
+ ],
45
+ "web": {
46
+ "entry": "@krizaka/sovkora-design-system",
47
+ "import": "import { ChatShowcase } from \"@krizaka/sovkora-design-system\";",
48
+ "props": [
49
+ {
50
+ "component": "ChatShowcase",
51
+ "description": "Renders the animated sovereign-chat card.",
52
+ "props": [
53
+ {
54
+ "name": "answer",
55
+ "type": "string",
56
+ "default": null,
57
+ "description": "The assistant's scripted answer (typed out char-by-char).",
58
+ "required": true
59
+ },
60
+ {
61
+ "name": "labels",
62
+ "type": "ChatShowcaseLabels",
63
+ "default": null,
64
+ "description": "The chrome's words, translated: the agent's name, its status, the model, the \"answered locally\" tag, the privacy line, the composer's placeholder.",
65
+ "required": true
66
+ },
67
+ {
68
+ "name": "pipeline",
69
+ "type": "string[]",
70
+ "default": null,
71
+ "description": "Interceptor pipeline steps rendered as chips once the answer lands.",
72
+ "required": true
73
+ },
74
+ {
75
+ "name": "question",
76
+ "type": "string",
77
+ "default": null,
78
+ "description": "The user's scripted question.",
79
+ "required": true
80
+ },
81
+ {
82
+ "name": "className",
83
+ "type": "string",
84
+ "default": null,
85
+ "description": "Extra classes on the wrapper (width, placement), merged last.",
86
+ "required": false
87
+ }
88
+ ]
89
+ }
90
+ ],
91
+ "examples": [
92
+ {
93
+ "name": "sovereign-answer",
94
+ "title": "A sovereign answer",
95
+ "description": "Eric asks about a contract; the answer is computed on premises and the pipeline shows the steps.",
96
+ "path": "examples/chat-showcase/sovereign-answer.tsx",
97
+ "module": "@krizaka/sovkora-design-system/registry/examples/chat-showcase/sovereign-answer",
98
+ "code": "import { ChatShowcase } from \"@krizaka/sovkora-design-system\";\n\n// Eric, finance lead, asks about a contract: the engine answers on premises, nothing leaves.\nexport default function SovereignAnswer() {\n return (\n <ChatShowcase\n labels={{\n agent: \"Sovkora · Finance desk\",\n status: \"On premises · online\",\n model: \"llama-3.1-70b\",\n routed: \"Answered locally\",\n privacy: \"0 bytes left your network\",\n placeholder: \"Ask about your documents…\",\n }}\n question=\"Eric here — which supplier contracts renew before March, and at what notice?\"\n answer=\"Three renew before March: Northwind (90 days' notice, by Dec 2), Calder Logistics (60 days, by Jan 4) and Ivo Print (30 days, by Feb 1). Northwind's clause also caps the increase at 3 %.\"\n pipeline={[\"PII masked\", \"Policy checked\", \"Routed locally\", \"Cited 3 contracts\"]}\n />\n );\n}\n"
99
+ },
100
+ {
101
+ "name": "french",
102
+ "title": "In the reader's language",
103
+ "description": "The same mockup with the words of another locale — every word is a prop.",
104
+ "path": "examples/chat-showcase/french.tsx",
105
+ "module": "@krizaka/sovkora-design-system/registry/examples/chat-showcase/french",
106
+ "code": "import { ChatShowcase } from \"@krizaka/sovkora-design-system\";\n\n// The same mockup in French: every word is a prop, translated by the app.\nexport default function French() {\n return (\n <ChatShowcase\n labels={{\n agent: \"Sovkora · Service juridique\",\n status: \"Sur site · en ligne\",\n model: \"mistral-small\",\n routed: \"Répondu en local\",\n privacy: \"0 octet n'a quitté votre réseau\",\n placeholder: \"Posez une question sur vos documents…\",\n }}\n question=\"Camille ici — quels contrats contiennent une clause de non-concurrence ?\"\n answer=\"Deux contrats : celui de Hélène Morel (12 mois, Île-de-France) et celui de Bastien Roy (6 mois, sans zone). Aucun autre n'en contient.\"\n pipeline={[\"Données masquées\", \"Politique vérifiée\", \"Routé en local\"]}\n />\n );\n}\n"
107
+ }
108
+ ]
109
+ },
110
+ "native": null,
111
+ "dependencies": [],
112
+ "registryDependencies": []
113
+ }
@@ -0,0 +1,120 @@
1
+ {
2
+ "name": "clip-player",
3
+ "type": "composite",
4
+ "title": "Clip player",
5
+ "summary": "A short clip that is plainly a clip: a muted loop that plays in view, a badge with its length, play/pause and sound buttons, and a click that opens it larger.",
6
+ "description": "A short clip that is plainly a clip: a muted loop that plays in view, a badge with its length, play/pause and sound buttons, and a click that opens it larger.",
7
+ "why": "A 5-second generated clip is shown as a loop, not as a video page: it must read as a video at a glance (badge), play by itself only while it is on screen, stay quiet, give the visitor the controls on hover and focus, and open large with the native controls. @krizaka/ui's player is built for long videos; this one is the product's way to show a result.",
8
+ "status": "beta",
9
+ "deprecated": null,
10
+ "category": "data-display",
11
+ "platforms": "web",
12
+ "builtOn": [
13
+ "ui/button",
14
+ "ui/dialog"
15
+ ],
16
+ "whenToUse": [
17
+ "A generated clip of a few seconds in a gallery, a result page or a card.",
18
+ "Anywhere a loop must start and stop with the viewport and respect reduced motion."
19
+ ],
20
+ "whenNotToUse": [
21
+ {
22
+ "when": "A long video, subtitles, chapters or streaming.",
23
+ "use": "ui/video-player"
24
+ },
25
+ {
26
+ "when": "A decorative background loop with no controls: a muted `<video>` is enough."
27
+ }
28
+ ],
29
+ "bestPractices": [
30
+ "Give both files: `webm` is tried first, `mp4` is the fallback every browser reads.",
31
+ "Give the poster: it is what reduced motion and the first paint show.",
32
+ "Name the clip in a sentence (`title`): it is the video's accessible name and the dialog's title."
33
+ ],
34
+ "accessibility": {
35
+ "keyboard": [
36
+ {
37
+ "keys": "Tab",
38
+ "action": "Reaches the frame (open larger), play/pause and sound."
39
+ },
40
+ {
41
+ "keys": "Enter / Space",
42
+ "action": "Activates the focused button."
43
+ },
44
+ {
45
+ "keys": "Escape",
46
+ "action": "Closes the large view."
47
+ }
48
+ ],
49
+ "notes": [
50
+ "Nothing plays by itself under `prefers-reduced-motion`: the poster and a play button.",
51
+ "The clip is muted and `playsInline`; the sound button is a toggle (`aria-pressed`).",
52
+ "A pause by hand sticks: scrolling away and back does not restart it."
53
+ ]
54
+ },
55
+ "related": [
56
+ "video-result",
57
+ "run-facts",
58
+ "ui/video-player"
59
+ ],
60
+ "web": {
61
+ "entry": "@krizaka/sovkora-design-system",
62
+ "import": "import { ClipPlayer } from \"@krizaka/sovkora-design-system\";",
63
+ "props": [
64
+ {
65
+ "component": "ClipPlayer",
66
+ "description": "A clip that is plainly a clip: muted loop that plays only while on screen (and pauses off screen and in a hidden\ntab), a badge, play/pause and sound buttons on hover and focus (always shown where the pointer cannot hover), and a\nclick anywhere on the frame opens it larger in a dialog with the native controls. Under `prefers-reduced-motion` it\nnever plays by itself: the poster and a play button. Plain files, `playsInline`, `preload=\"none\"`.",
67
+ "props": [
68
+ {
69
+ "name": "labels",
70
+ "type": "ClipPlayerLabels",
71
+ "default": null,
72
+ "description": "The words.",
73
+ "required": true
74
+ },
75
+ {
76
+ "name": "sources",
77
+ "type": "ClipSources",
78
+ "default": null,
79
+ "description": "The files.",
80
+ "required": true
81
+ },
82
+ {
83
+ "name": "title",
84
+ "type": "string",
85
+ "default": null,
86
+ "description": "The accessible name of the video: what it shows, in a sentence.",
87
+ "required": true
88
+ },
89
+ {
90
+ "name": "className",
91
+ "type": "string",
92
+ "default": null,
93
+ "description": "Extra classes on the video, merged last.",
94
+ "required": false
95
+ },
96
+ {
97
+ "name": "orientation",
98
+ "type": "\"landscape\" | \"portrait\"",
99
+ "default": "landscape",
100
+ "description": "The shape of the frame: a 16:9 one by default, a portrait one as tall as a phone allows.",
101
+ "required": false
102
+ }
103
+ ]
104
+ }
105
+ ],
106
+ "examples": [
107
+ {
108
+ "name": "tea-pour",
109
+ "title": "A loop in a card",
110
+ "description": "Eric's tea-pour shot: badge, controls on hover, opens larger on click.",
111
+ "path": "examples/clip-player/tea-pour.tsx",
112
+ "module": "@krizaka/sovkora-design-system/registry/examples/clip-player/tea-pour",
113
+ "code": "import { ClipPlayer } from \"@krizaka/sovkora-design-system\";\n\n// Eric's tea-pour shot as a loop: it plays in view, the controls show on hover, a click opens it larger.\nexport default function TeaPour() {\n return (\n <div className=\"max-w-xl overflow-hidden rounded-2xl border border-border-default\">\n <ClipPlayer\n title=\"Mint tea pouring into an engraved glass in a Berber tent\"\n sources={{\n mp4: \"https://krizaka-assets.b-cdn.net/site/products/orazaka/gallery-video/tea-pour.c4138c8ce9.mp4\",\n webm: \"https://krizaka-assets.b-cdn.net/site/products/orazaka/gallery-video/tea-pour.b33e468733.webm\",\n poster:\n \"https://krizaka-assets.b-cdn.net/site/products/orazaka/gallery-video/tea-pour-poster.8a062e63c2.webp\",\n }}\n labels={{\n badge: \"Video · 5 s\",\n play: \"Play\",\n pause: \"Pause\",\n mute: \"Mute\",\n unmute: \"Sound on\",\n enlarge: \"Open larger\",\n close: \"Close\",\n }}\n />\n </div>\n );\n}\n"
114
+ }
115
+ ]
116
+ },
117
+ "native": null,
118
+ "dependencies": [],
119
+ "registryDependencies": []
120
+ }
@@ -0,0 +1,116 @@
1
+ {
2
+ "name": "command-palette",
3
+ "type": "composite",
4
+ "title": "Command palette",
5
+ "summary": "The Sovkora ⌘K palette: jump to a studio, a chat, a setting — sections, registry icons and a footer of hints, on the platform's command dialog.",
6
+ "description": "The Sovkora ⌘K palette: jump to a studio, a chat, a setting — sections, registry icons and a footer of hints, on the platform's command dialog.",
7
+ "why": "`CommandDialog` from @krizaka/ui gives the combobox, the filtering, the focus trap and Escape. Sovkora adds what is its own: the ⌘K / Ctrl+K shortcut, entries grouped by section with the Sovkora icon registry, and the footer of keyboard hints its consoles share.",
8
+ "status": "stable",
9
+ "deprecated": null,
10
+ "category": "navigation",
11
+ "platforms": "web",
12
+ "builtOn": [
13
+ "ui/command",
14
+ "ui/kbd",
15
+ "ui/dialog"
16
+ ],
17
+ "whenToUse": [
18
+ "Once per app shell: the client app and the console, for power users who navigate by keyboard.",
19
+ "To reach an action that has no place in the navigation (new chat, switch theme)."
20
+ ],
21
+ "whenNotToUse": [
22
+ {
23
+ "when": "As the only way to reach a page: everything stays reachable from the navigation."
24
+ },
25
+ {
26
+ "when": "For a search over content (documents, conversations) with results to read.",
27
+ "use": "ui/command"
28
+ }
29
+ ],
30
+ "bestPractices": [
31
+ "Pass `commands` and `labels` translated (both required since 3.0).",
32
+ "Give `onNavigate` outside Next.js (or in tests); inside, it uses the router.",
33
+ "Short labels, verbs for actions (`New chat`), nouns for places (`Studios`)."
34
+ ],
35
+ "accessibility": {
36
+ "keyboard": [
37
+ {
38
+ "keys": "⌘ K / Ctrl K",
39
+ "action": "Opens and closes the palette."
40
+ },
41
+ {
42
+ "keys": "↑ ↓",
43
+ "action": "Moves through the results."
44
+ },
45
+ {
46
+ "keys": "Enter",
47
+ "action": "Runs the highlighted entry."
48
+ },
49
+ {
50
+ "keys": "Esc",
51
+ "action": "Closes it and returns the focus."
52
+ }
53
+ ],
54
+ "notes": [
55
+ "A dialog with a combobox and a listbox (cmdk on Radix): named by `labels.label`, results by `labels.results`."
56
+ ]
57
+ },
58
+ "related": [
59
+ "icon",
60
+ "ui/command",
61
+ "ui/kbd"
62
+ ],
63
+ "web": {
64
+ "entry": "@krizaka/sovkora-design-system",
65
+ "import": "import { CommandPalette } from \"@krizaka/sovkora-design-system\";",
66
+ "props": [
67
+ {
68
+ "component": "CommandPalette",
69
+ "description": "The Sovkora ⌘K palette: a product composite on `CommandDialog` from `@krizaka/ui/command` (cmdk + the platform's\ndialog: the combobox and listbox roles, the arrows, Enter, the filtering, the focus trap, Escape). It adds what is\nSovkora's: the shortcut, the registry icons, the sections and the footer of hints. Words and entries arrive as\nprops (since 3.0 they are required: the 1.x English defaults are gone).",
70
+ "props": [
71
+ {
72
+ "name": "commands",
73
+ "type": "CommandPaletteItem[]",
74
+ "default": null,
75
+ "description": "The entries, grouped by `section` in their order.",
76
+ "required": true
77
+ },
78
+ {
79
+ "name": "labels",
80
+ "type": "CommandPaletteLabels",
81
+ "default": null,
82
+ "description": "The words, translated.",
83
+ "required": true
84
+ },
85
+ {
86
+ "name": "onNavigate",
87
+ "type": "((href: string) => void)",
88
+ "default": null,
89
+ "description": "Where an entry's `href` goes. Default: the Next.js router (`router.push`).",
90
+ "required": false
91
+ },
92
+ {
93
+ "name": "shortcut",
94
+ "type": "string",
95
+ "default": "k",
96
+ "description": "The letter that opens it with ⌘ / Ctrl. Default `k`.",
97
+ "required": false
98
+ }
99
+ ]
100
+ }
101
+ ],
102
+ "examples": [
103
+ {
104
+ "name": "workspace",
105
+ "title": "Eric's workspace",
106
+ "description": "Studios, chats and settings, opened with ⌘K or the button.",
107
+ "path": "examples/command-palette/workspace.tsx",
108
+ "module": "@krizaka/sovkora-design-system/registry/examples/command-palette/workspace",
109
+ "code": "\"use client\";\n\nimport { CommandPalette } from \"@krizaka/sovkora-design-system\";\n\n// Eric's workspace: ⌘K / Ctrl+K opens it; entries and words are props.\nexport default function Workspace() {\n return (\n <div className=\"flex flex-col items-start gap-2 text-sm text-fg-secondary\">\n <p>Press ⌘K (Ctrl+K) to open the palette.</p>\n <CommandPalette\n onNavigate={() => {}}\n labels={{\n label: \"Command palette\",\n placeholder: \"Go to…\",\n results: \"Results\",\n empty: \"Nothing matches.\",\n navigate: \"move\",\n open: \"open\",\n close: \"close\",\n }}\n commands={[\n { id: \"studios\", label: \"Studios\", icon: \"studio\", href: \"/studios\", section: \"Go to\" },\n { id: \"chat\", label: \"Contracts assistant\", icon: \"chat\", href: \"/chat/contracts\", section: \"Go to\" },\n { id: \"new-chat\", label: \"New chat\", icon: \"newChat\", href: \"/chat/new\", section: \"Actions\" },\n { id: \"models\", label: \"Local models\", icon: \"model\", href: \"/settings/models\", section: \"Settings\" },\n ]}\n />\n </div>\n );\n}\n"
110
+ }
111
+ ]
112
+ },
113
+ "native": null,
114
+ "dependencies": [],
115
+ "registryDependencies": []
116
+ }
@@ -0,0 +1,16 @@
1
+ import { Badge } from "@krizaka/sovkora-design-system";
2
+
3
+ // A model's state in the console: `tone`, never the deprecated `variant`.
4
+ export default function ModelState() {
5
+ return (
6
+ <div className="flex flex-wrap gap-2">
7
+ <Badge tone="success" dot>
8
+ Local · ready
9
+ </Badge>
10
+ <Badge tone="accent" dot pulse>
11
+ Loading
12
+ </Badge>
13
+ <Badge tone="danger">Failed</Badge>
14
+ </div>
15
+ );
16
+ }
@@ -0,0 +1,18 @@
1
+ "use client";
2
+
3
+ import { Button } from "@krizaka/sovkora-design-system";
4
+ import { useState } from "react";
5
+
6
+ // Primary by default (the 1.x default); locked while the answer is generated (ERR-126).
7
+ export default function Send() {
8
+ const [generating, setGenerating] = useState(false);
9
+ const send = () => {
10
+ setGenerating(true);
11
+ setTimeout(() => setGenerating(false), 1500);
12
+ };
13
+ return (
14
+ <Button loading={generating} disabled={generating} onClick={send}>
15
+ Send
16
+ </Button>
17
+ );
18
+ }
@@ -0,0 +1,20 @@
1
+ import { ChatShowcase } from "@krizaka/sovkora-design-system";
2
+
3
+ // The same mockup in French: every word is a prop, translated by the app.
4
+ export default function French() {
5
+ return (
6
+ <ChatShowcase
7
+ labels={{
8
+ agent: "Sovkora · Service juridique",
9
+ status: "Sur site · en ligne",
10
+ model: "mistral-small",
11
+ routed: "Répondu en local",
12
+ privacy: "0 octet n'a quitté votre réseau",
13
+ placeholder: "Posez une question sur vos documents…",
14
+ }}
15
+ question="Camille ici — quels contrats contiennent une clause de non-concurrence ?"
16
+ answer="Deux contrats : celui de Hélène Morel (12 mois, Île-de-France) et celui de Bastien Roy (6 mois, sans zone). Aucun autre n'en contient."
17
+ pipeline={["Données masquées", "Politique vérifiée", "Routé en local"]}
18
+ />
19
+ );
20
+ }