@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.
- package/CHANGELOG.md +234 -0
- package/LICENSE +202 -0
- package/README.md +82 -2
- package/package.json +112 -3
- package/registry/badge.json +97 -0
- package/registry/button.json +140 -0
- package/registry/chat-showcase.json +113 -0
- package/registry/clip-player.json +120 -0
- package/registry/command-palette.json +116 -0
- package/registry/examples/badge/model-state.tsx +16 -0
- package/registry/examples/button/send.tsx +18 -0
- package/registry/examples/chat-showcase/french.tsx +20 -0
- package/registry/examples/chat-showcase/sovereign-answer.tsx +20 -0
- package/registry/examples/clip-player/tea-pour.tsx +27 -0
- package/registry/examples/command-palette/workspace.tsx +30 -0
- package/registry/examples/icon/engine.tsx +26 -0
- package/registry/examples/icon/in-a-button.tsx +12 -0
- package/registry/examples/run-facts/clip-run.tsx +15 -0
- package/registry/examples/sentinel-mini/sidebar.tsx +11 -0
- package/registry/examples/skeleton/answer-loading.tsx +11 -0
- package/registry/examples/video-result/assistant.tsx +36 -0
- package/registry/examples/video-result/tea-pour.tsx +40 -0
- package/registry/foundations.json +2067 -0
- package/registry/icon.json +109 -0
- package/registry/index.json +242 -0
- package/registry/run-facts.json +75 -0
- package/registry/sentinel-mini.json +81 -0
- package/registry/skeleton.json +116 -0
- package/registry/video-result.json +167 -0
- package/src/components/Badge.tsx +36 -0
- package/src/components/Button.tsx +26 -0
- package/src/components/ChatShowcase.tsx +248 -0
- package/src/components/ClipPlayer.tsx +223 -0
- package/src/components/CommandPalette.tsx +104 -0
- package/src/components/CommandPalette.types.ts +33 -0
- package/src/components/Input.tsx +14 -0
- package/src/components/RunFacts.tsx +36 -0
- package/src/components/SentinelMini.tsx +61 -0
- package/src/components/Skeleton.tsx +50 -0
- package/src/components/VideoResult.tsx +123 -0
- package/src/components/badge.meta.ts +34 -0
- package/src/components/button.meta.ts +35 -0
- package/src/components/chat-showcase.css.ts +19 -0
- package/src/components/chat-showcase.meta.ts +50 -0
- package/src/components/clip-player.meta.ts +48 -0
- package/src/components/command-palette.meta.ts +47 -0
- package/src/components/icon.meta.ts +45 -0
- package/src/components/run-facts.meta.ts +32 -0
- package/src/components/sentinel-mini.meta.ts +39 -0
- package/src/components/skeleton.meta.ts +42 -0
- package/src/components/video-result.meta.ts +53 -0
- package/src/icon.registry.tsx +737 -0
- package/src/icon.tsx +74 -0
- package/src/index.ts +43 -0
- package/src/meta.ts +76 -0
- 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
|
+
}
|