@toolr/ui-design 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +63 -0
- package/components/content/info-panel-primitives.tsx +297 -0
- package/components/diagrams/diagram-utils.tsx +908 -0
- package/components/hooks/use-click-outside.ts +27 -0
- package/components/hooks/use-dropdown-max-height.ts +20 -0
- package/components/hooks/use-navigation-history.ts +94 -0
- package/components/lib/ai-tools.tsx +44 -0
- package/components/lib/cn.ts +6 -0
- package/components/lib/form-colors.ts +32 -0
- package/components/lib/theme-engine.ts +97 -0
- package/components/lib/toolr-brand.tsx +31 -0
- package/components/sections/ai-tools-paths/index.ts +37 -0
- package/components/sections/ai-tools-paths/tools-paths-panel.tsx +212 -0
- package/components/sections/ai-tools-paths/types.ts +111 -0
- package/components/sections/ai-tools-paths/use-tools-paths.ts +159 -0
- package/components/sections/captured-issues/captured-issues-panel.tsx +214 -0
- package/components/sections/captured-issues/index.ts +38 -0
- package/components/sections/captured-issues/types.ts +113 -0
- package/components/sections/captured-issues/use-captured-issues.ts +111 -0
- package/components/sections/golden-snapshots/file-diff-viewer.tsx +420 -0
- package/components/sections/golden-snapshots/golden-sync-panel.tsx +223 -0
- package/components/sections/golden-snapshots/index.ts +145 -0
- package/components/sections/golden-snapshots/snapshot-manager.tsx +200 -0
- package/components/sections/golden-snapshots/status-overview.tsx +305 -0
- package/components/sections/golden-snapshots/types.ts +288 -0
- package/components/sections/golden-snapshots/use-golden-sync.ts +477 -0
- package/components/sections/golden-snapshots/version-manager.tsx +186 -0
- package/components/sections/prompt-editor/file-type-tabbed-prompt-editor.tsx +210 -0
- package/components/sections/prompt-editor/index.ts +121 -0
- package/components/sections/prompt-editor/simulator-prompt-editor.tsx +276 -0
- package/components/sections/prompt-editor/tabbed-prompt-editor.tsx +514 -0
- package/components/sections/prompt-editor/types.ts +101 -0
- package/components/sections/prompt-editor/use-prompt-editor.ts +131 -0
- package/components/sections/report-bug/error-logger.ts +392 -0
- package/components/sections/report-bug/index.ts +59 -0
- package/components/sections/report-bug/issue-reporter-api.ts +83 -0
- package/components/sections/report-bug/report-bug-form.tsx +282 -0
- package/components/sections/report-bug/screenshot-uploader.tsx +228 -0
- package/components/sections/report-bug/use-report-bug.ts +170 -0
- package/components/sections/snapshot-browser/index.ts +53 -0
- package/components/sections/snapshot-browser/snapshot-browser-panel.tsx +147 -0
- package/components/sections/snapshot-browser/snapshot-tree.tsx +451 -0
- package/components/sections/snapshot-browser/types.ts +106 -0
- package/components/sections/snapshot-browser/use-snapshot-browser.ts +125 -0
- package/components/sections/snippets-editor/index.ts +31 -0
- package/components/sections/snippets-editor/snippets-editor.tsx +381 -0
- package/components/sections/snippets-editor/types.ts +48 -0
- package/components/sections/snippets-editor/use-snippets-editor.ts +217 -0
- package/components/ui/action-dialog.tsx +309 -0
- package/components/ui/ai-action-button.tsx +137 -0
- package/components/ui/ai-execution-action-buttons.tsx +106 -0
- package/components/ui/badge.tsx +67 -0
- package/components/ui/bottom-panel-header.tsx +240 -0
- package/components/ui/breadcrumb.tsx +168 -0
- package/components/ui/checkbox.tsx +102 -0
- package/components/ui/collapsible-section.tsx +100 -0
- package/components/ui/confirm-badge.tsx +71 -0
- package/components/ui/detail-section.tsx +67 -0
- package/components/ui/detail-view-wrapper.tsx +55 -0
- package/components/ui/editor-placeholder-card.tsx +197 -0
- package/components/ui/editor-toolbar.tsx +123 -0
- package/components/ui/execution-details-panel.tsx +93 -0
- package/components/ui/extension-list-card.tsx +105 -0
- package/components/ui/file-structure-section.tsx +373 -0
- package/components/ui/file-tree.tsx +171 -0
- package/components/ui/files-panel.tsx +251 -0
- package/components/ui/filter-dropdown.tsx +173 -0
- package/components/ui/form-actions.tsx +127 -0
- package/components/ui/frontmatter-form-header.tsx +80 -0
- package/components/ui/icon-button.tsx +388 -0
- package/components/ui/input.tsx +211 -0
- package/components/ui/label.tsx +159 -0
- package/components/ui/layout-tab-bar.tsx +289 -0
- package/components/ui/modal.tsx +194 -0
- package/components/ui/nav-card.tsx +81 -0
- package/components/ui/navigation-bar.tsx +285 -0
- package/components/ui/number-input.tsx +165 -0
- package/components/ui/registry-browser.tsx +261 -0
- package/components/ui/registry-card.tsx +710 -0
- package/components/ui/registry-detail.tsx +224 -0
- package/components/ui/resizable-textarea.tsx +290 -0
- package/components/ui/scope-badge.tsx +67 -0
- package/components/ui/segmented-toggle.tsx +133 -0
- package/components/ui/select.tsx +172 -0
- package/components/ui/selection-grid.tsx +313 -0
- package/components/ui/setting-row.tsx +97 -0
- package/components/ui/snapshot-card.tsx +107 -0
- package/components/ui/snippets-panel.tsx +161 -0
- package/components/ui/sort-dropdown.tsx +109 -0
- package/components/ui/status-card.tsx +96 -0
- package/components/ui/tab-bar.tsx +340 -0
- package/components/ui/toggle.tsx +142 -0
- package/components/ui/tooltip.tsx +326 -0
- package/dist/content.d.ts +110 -0
- package/dist/content.js +195 -0
- package/dist/diagrams.d.ts +371 -0
- package/dist/diagrams.js +702 -0
- package/dist/index.d.ts +2714 -0
- package/dist/index.js +11220 -0
- package/dist/preset.d.ts +24 -0
- package/dist/preset.js +17 -0
- package/dist/tokens/tokens/primitives.css +45 -0
- package/dist/tokens/tokens/semantic.css +46 -0
- package/dist/tokens/tokens/theme.css +11 -0
- package/dist/tokens/tokens/tokens.json +65 -0
- package/index.ts +123 -0
- package/package.json +63 -0
- package/tailwind-preset.ts +22 -0
- package/tokens/primitives.css +45 -0
- package/tokens/semantic.css +46 -0
- package/tokens/theme.css +11 -0
- package/tokens/tokens.json +65 -0
package/README.md
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# @toolr/ui-design
|
|
2
|
+
|
|
3
|
+
Shared UI design system for toolr applications. Provides components, design tokens, and a Tailwind preset.
|
|
4
|
+
|
|
5
|
+
## Setup
|
|
6
|
+
|
|
7
|
+
```jsonc
|
|
8
|
+
// package.json — path is relative to your app
|
|
9
|
+
{ "@toolr/ui-design": "file:../../shared/ui-design" }
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
```css
|
|
13
|
+
/* app CSS entry point */
|
|
14
|
+
@import "@toolr/ui-design/tokens";
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
// tailwind.config.ts
|
|
19
|
+
import { toolrPreset } from '@toolr/ui-design/preset'
|
|
20
|
+
export default { presets: [toolrPreset] }
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Exports
|
|
24
|
+
|
|
25
|
+
| Path | Content |
|
|
26
|
+
|------|---------|
|
|
27
|
+
| `@toolr/ui-design` | All components, hooks, types, utilities |
|
|
28
|
+
| `@toolr/ui-design/tokens` | CSS design tokens (semantic + primitives + keyframes) |
|
|
29
|
+
| `@toolr/ui-design/preset` | Tailwind preset (Inter font, extended breakpoints) |
|
|
30
|
+
| `@toolr/ui-design/content` | Info panel primitives |
|
|
31
|
+
| `@toolr/ui-design/diagrams` | Diagram utilities |
|
|
32
|
+
|
|
33
|
+
Always import components from the barrel export (`@toolr/ui-design`), not from deep paths.
|
|
34
|
+
|
|
35
|
+
## Claude Code Skills
|
|
36
|
+
|
|
37
|
+
Two skills ship with this package for Claude Code agents:
|
|
38
|
+
|
|
39
|
+
### `ui-playground` — Building the design system
|
|
40
|
+
|
|
41
|
+
For working on components and playground pages inside this repo. Triggers when editing files in `components/ui/`, `playground/src/pages/`, or `index.ts`.
|
|
42
|
+
|
|
43
|
+
### `ui-consumer` — Using the design system in apps
|
|
44
|
+
|
|
45
|
+
For consuming apps that import `@toolr/ui-design`. Covers setup, import patterns, FormColor, cn(), icons, tooltips, modals, sections, tokens, and common mistakes.
|
|
46
|
+
|
|
47
|
+
To make `ui-consumer` available in a consuming app, symlink it into the app's `.shared/.claude/skills/` directory:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
# From the monorepo root (adjust relative path as needed)
|
|
51
|
+
ln -s ../../../../shared/ui-design/.claude/skills/ui-consumer <app>/.shared/.claude/skills/ui-consumer
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Currently symlinked in: **configr** (`configr/.shared/.claude/skills/ui-consumer`).
|
|
55
|
+
|
|
56
|
+
## Playground
|
|
57
|
+
|
|
58
|
+
Interactive component playground with live preview, prop controls, and code generation.
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
# Start (requires tmux session toolr-shared-uidesign)
|
|
62
|
+
cd playground && npm run dev -- --port 6100
|
|
63
|
+
```
|
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* InfoPanelPrimitives — Shared building blocks for info panel content.
|
|
3
|
+
*
|
|
4
|
+
* Grid variant: 14px body text, CSS Grid definition lists, border-left callouts,
|
|
5
|
+
* no gray boxes, generous spacing. Designed for scannability.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { ReactNode } from 'react'
|
|
9
|
+
|
|
10
|
+
// ─── Paragraph ──────────────────────────────────────────────────────
|
|
11
|
+
|
|
12
|
+
export function P({ children }: { children: ReactNode }) {
|
|
13
|
+
return <p className="text-sm text-neutral-400 leading-relaxed mb-5">{children}</p>
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// ─── Section Header ─────────────────────────────────────────────────
|
|
17
|
+
|
|
18
|
+
export function SectionHeader({ color, children }: { color?: string; children: ReactNode }) {
|
|
19
|
+
const textColor = color ? `text-${color}-500/70` : 'text-neutral-500'
|
|
20
|
+
return (
|
|
21
|
+
<p className={`${textColor} text-xs uppercase font-semibold pb-0.5 border-b border-neutral-700/50 mb-2.5`} style={{ letterSpacing: '0.8px' }}>
|
|
22
|
+
{children}
|
|
23
|
+
</p>
|
|
24
|
+
)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// ─── Definition List (CSS Grid two-column) ──────────────────────────
|
|
28
|
+
|
|
29
|
+
export function DL({ children }: { children: ReactNode }) {
|
|
30
|
+
return (
|
|
31
|
+
<div className="mb-5">
|
|
32
|
+
<div className="grid grid-cols-[auto_1fr] gap-x-4">{children}</div>
|
|
33
|
+
</div>
|
|
34
|
+
)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function DLRow({ term, children, even }: { term: ReactNode; children: ReactNode; even?: boolean }) {
|
|
38
|
+
const bg = even ? 'bg-white/[0.015]' : ''
|
|
39
|
+
return (
|
|
40
|
+
<>
|
|
41
|
+
<div className={`py-2 border-b border-neutral-800/60 ${bg} font-semibold text-sm whitespace-nowrap`}>
|
|
42
|
+
{term}
|
|
43
|
+
</div>
|
|
44
|
+
<div className={`py-2 border-b border-neutral-800/60 ${bg} text-sm text-neutral-400`}>{children}</div>
|
|
45
|
+
</>
|
|
46
|
+
)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// ─── Unordered List ─────────────────────────────────────────────────
|
|
50
|
+
|
|
51
|
+
export function UL({ children }: { children: ReactNode }) {
|
|
52
|
+
return <ul className="text-sm text-neutral-400 space-y-2 mb-5">{children}</ul>
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function LI({ color, children }: { color: string; children: ReactNode }) {
|
|
56
|
+
return (
|
|
57
|
+
<li className="flex items-start gap-2">
|
|
58
|
+
<span className={`text-${color}-400 shrink-0`} style={{ marginTop: '3px', fontSize: '18px', lineHeight: '14px' }}>•</span>
|
|
59
|
+
<span>{children}</span>
|
|
60
|
+
</li>
|
|
61
|
+
)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// ─── Ordered List ───────────────────────────────────────────────────
|
|
65
|
+
|
|
66
|
+
export function OL({ children }: { children: ReactNode }) {
|
|
67
|
+
return <div className="space-y-2 mb-5">{children}</div>
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function OLI({ n, color, children }: { n: number; color: string; children: ReactNode }) {
|
|
71
|
+
return (
|
|
72
|
+
<div className="flex items-start gap-2.5 text-sm">
|
|
73
|
+
<span className={`text-${color}-400 shrink-0 w-4 text-right font-bold`}>{n}.</span>
|
|
74
|
+
<span className="text-neutral-400">{children}</span>
|
|
75
|
+
</div>
|
|
76
|
+
)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// ─── Callout ────────────────────────────────────────────────────────
|
|
80
|
+
|
|
81
|
+
/** Literal class strings so Tailwind's scanner can detect them. */
|
|
82
|
+
const CALLOUT_COLORS: Record<string, { borderL: string; borderY: string; bg: string; text: string; codeText: string; dimText: string }> = {
|
|
83
|
+
amber: { borderL: 'border-amber-500/40', borderY: 'border-y-amber-500/15', bg: 'bg-amber-500/5', text: 'text-amber-400', codeText: 'text-amber-300/80', dimText: 'text-amber-400/60' },
|
|
84
|
+
blue: { borderL: 'border-blue-500/40', borderY: 'border-y-blue-500/15', bg: 'bg-blue-500/5', text: 'text-blue-400', codeText: 'text-blue-300/80', dimText: 'text-blue-400/60' },
|
|
85
|
+
cyan: { borderL: 'border-cyan-500/40', borderY: 'border-y-cyan-500/15', bg: 'bg-cyan-500/5', text: 'text-cyan-400', codeText: 'text-cyan-300/80', dimText: 'text-cyan-400/60' },
|
|
86
|
+
emerald: { borderL: 'border-emerald-500/40', borderY: 'border-y-emerald-500/15', bg: 'bg-emerald-500/5', text: 'text-emerald-400', codeText: 'text-emerald-300/80', dimText: 'text-emerald-400/60' },
|
|
87
|
+
fuchsia: { borderL: 'border-fuchsia-500/40', borderY: 'border-y-fuchsia-500/15', bg: 'bg-fuchsia-500/5', text: 'text-fuchsia-400', codeText: 'text-fuchsia-300/80', dimText: 'text-fuchsia-400/60' },
|
|
88
|
+
green: { borderL: 'border-green-500/40', borderY: 'border-y-green-500/15', bg: 'bg-green-500/5', text: 'text-green-400', codeText: 'text-green-300/80', dimText: 'text-green-400/60' },
|
|
89
|
+
indigo: { borderL: 'border-indigo-500/40', borderY: 'border-y-indigo-500/15', bg: 'bg-indigo-500/5', text: 'text-indigo-400', codeText: 'text-indigo-300/80', dimText: 'text-indigo-400/60' },
|
|
90
|
+
lime: { borderL: 'border-lime-500/40', borderY: 'border-y-lime-500/15', bg: 'bg-lime-500/5', text: 'text-lime-400', codeText: 'text-lime-300/80', dimText: 'text-lime-400/60' },
|
|
91
|
+
orange: { borderL: 'border-orange-500/40', borderY: 'border-y-orange-500/15', bg: 'bg-orange-500/5', text: 'text-orange-400', codeText: 'text-orange-300/80', dimText: 'text-orange-400/60' },
|
|
92
|
+
pink: { borderL: 'border-pink-500/40', borderY: 'border-y-pink-500/15', bg: 'bg-pink-500/5', text: 'text-pink-400', codeText: 'text-pink-300/80', dimText: 'text-pink-400/60' },
|
|
93
|
+
purple: { borderL: 'border-purple-500/40', borderY: 'border-y-purple-500/15', bg: 'bg-purple-500/5', text: 'text-purple-400', codeText: 'text-purple-300/80', dimText: 'text-purple-400/60' },
|
|
94
|
+
red: { borderL: 'border-red-500/40', borderY: 'border-y-red-500/15', bg: 'bg-red-500/5', text: 'text-red-400', codeText: 'text-red-300/80', dimText: 'text-red-400/60' },
|
|
95
|
+
rose: { borderL: 'border-rose-500/40', borderY: 'border-y-rose-500/15', bg: 'bg-rose-500/5', text: 'text-rose-400', codeText: 'text-rose-300/80', dimText: 'text-rose-400/60' },
|
|
96
|
+
sky: { borderL: 'border-sky-500/40', borderY: 'border-y-sky-500/15', bg: 'bg-sky-500/5', text: 'text-sky-400', codeText: 'text-sky-300/80', dimText: 'text-sky-400/60' },
|
|
97
|
+
teal: { borderL: 'border-teal-500/40', borderY: 'border-y-teal-500/15', bg: 'bg-teal-500/5', text: 'text-teal-400', codeText: 'text-teal-300/80', dimText: 'text-teal-400/60' },
|
|
98
|
+
violet: { borderL: 'border-violet-500/40', borderY: 'border-y-violet-500/15', bg: 'bg-violet-500/5', text: 'text-violet-400', codeText: 'text-violet-300/80', dimText: 'text-violet-400/60' },
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export function getCalloutColors(color: string) {
|
|
102
|
+
return CALLOUT_COLORS[color] ?? CALLOUT_COLORS.blue
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export function Callout({ color, children }: { color: string; children: ReactNode }) {
|
|
106
|
+
const c = CALLOUT_COLORS[color] ?? CALLOUT_COLORS.blue
|
|
107
|
+
return (
|
|
108
|
+
<div className={`border-l-4 ${c.borderL} border-y ${c.borderY} ${c.bg} px-3 py-2.5 rounded-r mb-5 text-sm text-neutral-400`}>
|
|
109
|
+
{children}
|
|
110
|
+
</div>
|
|
111
|
+
)
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export function CalloutCode({ color, children }: { color: string; children: ReactNode }) {
|
|
115
|
+
const c = CALLOUT_COLORS[color] ?? CALLOUT_COLORS.blue
|
|
116
|
+
return (
|
|
117
|
+
<code className={`block bg-neutral-800/80 px-2 py-1 rounded mt-1.5 text-[13px] ${c.codeText}`}>
|
|
118
|
+
{children}
|
|
119
|
+
</code>
|
|
120
|
+
)
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export function CalloutDim({ children }: { children: ReactNode }) {
|
|
124
|
+
return <p className="text-neutral-500 mt-1.5">{children}</p>
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// ─── Code Block ─────────────────────────────────────────────────────
|
|
128
|
+
|
|
129
|
+
export function CodeBlock({ children }: { children: ReactNode }) {
|
|
130
|
+
return (
|
|
131
|
+
<div className="bg-neutral-900/60 rounded-md p-3 font-mono text-xs text-neutral-400 mb-5 whitespace-pre overflow-x-auto leading-normal">{children}</div>
|
|
132
|
+
)
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// ─── Inline Code ────────────────────────────────────────────────────
|
|
136
|
+
|
|
137
|
+
export function CK({ color, children }: { color?: string; children: ReactNode }) {
|
|
138
|
+
const textColor = color ? `text-${color}-400` : ''
|
|
139
|
+
return (
|
|
140
|
+
<code className={`bg-neutral-800/80 px-1.5 py-px rounded text-[0.9em] ${textColor}`}>{children}</code>
|
|
141
|
+
)
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// ─── External Link ──────────────────────────────────────────────────
|
|
145
|
+
|
|
146
|
+
export function ExternalLink({ href, children }: { href: string; children: ReactNode }) {
|
|
147
|
+
return (
|
|
148
|
+
<a href={href} target="_blank" rel="noopener noreferrer" className="underline cursor-pointer">
|
|
149
|
+
{children}
|
|
150
|
+
</a>
|
|
151
|
+
)
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// ─── Location List (colored-dot items in CSS Grid) ──────────────────
|
|
155
|
+
|
|
156
|
+
export function LocationList({ children }: { children: ReactNode }) {
|
|
157
|
+
return (
|
|
158
|
+
<div className="mb-5">
|
|
159
|
+
<div className="grid grid-cols-[auto_1fr] gap-x-4">{children}</div>
|
|
160
|
+
</div>
|
|
161
|
+
)
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
export function LocationItem({
|
|
165
|
+
color,
|
|
166
|
+
label,
|
|
167
|
+
children,
|
|
168
|
+
even,
|
|
169
|
+
}: {
|
|
170
|
+
color: string
|
|
171
|
+
label: string
|
|
172
|
+
children: ReactNode
|
|
173
|
+
even?: boolean
|
|
174
|
+
}) {
|
|
175
|
+
const bg = even ? 'bg-white/[0.015]' : ''
|
|
176
|
+
return (
|
|
177
|
+
<>
|
|
178
|
+
<div className={`py-2 border-b border-neutral-800/60 ${bg} flex items-center gap-1.5`}>
|
|
179
|
+
<span
|
|
180
|
+
className={`w-2 h-2 rounded-full bg-${color}-500/50 border border-${color}-500 shrink-0`}
|
|
181
|
+
/>
|
|
182
|
+
<span className={`text-${color}-400 text-sm font-semibold`}>{label}</span>
|
|
183
|
+
</div>
|
|
184
|
+
<div className={`py-2 border-b border-neutral-800/60 ${bg} text-sm text-neutral-400`}>{children}</div>
|
|
185
|
+
</>
|
|
186
|
+
)
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// ─── TitledLI — Bullet item with colored title + description ────────
|
|
190
|
+
|
|
191
|
+
export function TitledLI({ color, title, children }: { color: string; title: string; children: ReactNode }) {
|
|
192
|
+
return (
|
|
193
|
+
<li className="flex items-start gap-2 text-sm text-neutral-400">
|
|
194
|
+
<span className={`text-${color}-400 shrink-0`} style={{ marginTop: '3px', fontSize: '18px', lineHeight: '14px' }}>•</span>
|
|
195
|
+
<span>
|
|
196
|
+
<span className={`text-${color}-300 font-semibold`}>{title}</span>
|
|
197
|
+
{' '}— {children}
|
|
198
|
+
</span>
|
|
199
|
+
</li>
|
|
200
|
+
)
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// ─── CalloutDialog — Conversation exchange inside a Callout ─────────
|
|
204
|
+
|
|
205
|
+
export function CalloutDialog({ color, lines }: { color: string; lines: { speaker: string; text: string }[] }) {
|
|
206
|
+
return (
|
|
207
|
+
<div className="bg-neutral-800/80 rounded px-2 py-1 mt-1.5 flex flex-col gap-0.5 text-[13px]">
|
|
208
|
+
{lines.map((line, idx) => (
|
|
209
|
+
<div key={idx}>
|
|
210
|
+
<span className={`text-${color}-300 font-semibold mr-1`}>{line.speaker}:</span>
|
|
211
|
+
<span className="text-neutral-400">{line.text}</span>
|
|
212
|
+
</div>
|
|
213
|
+
))}
|
|
214
|
+
</div>
|
|
215
|
+
)
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// ─── TagGrid — Flex-wrapped CK pills ────────────────────────────────
|
|
219
|
+
|
|
220
|
+
export function TagGrid({ color, tags }: { color: string; tags: string[] }) {
|
|
221
|
+
return (
|
|
222
|
+
<div className="flex flex-wrap gap-1.5 mb-5">
|
|
223
|
+
{tags.map((tag) => <CK key={tag} color={color}>{tag}</CK>)}
|
|
224
|
+
</div>
|
|
225
|
+
)
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// ─── StatusBadge — Colored circle indicator row (use inside DL) ─────
|
|
229
|
+
|
|
230
|
+
export function StatusBadge({ value, badgeColor, label, children, even }: {
|
|
231
|
+
value: string
|
|
232
|
+
badgeColor: string
|
|
233
|
+
label: string
|
|
234
|
+
children: ReactNode
|
|
235
|
+
even?: boolean
|
|
236
|
+
}) {
|
|
237
|
+
return (
|
|
238
|
+
<DLRow
|
|
239
|
+
term={
|
|
240
|
+
<span className="flex items-center gap-1.5">
|
|
241
|
+
<span className={`inline-flex items-center justify-center w-5 h-5 rounded-full bg-${badgeColor}-500/20 text-${badgeColor}-400 text-[11px] font-bold shrink-0`}>{value}</span>
|
|
242
|
+
<span className={`text-${badgeColor}-400 font-semibold`}>{label}</span>
|
|
243
|
+
</span>
|
|
244
|
+
}
|
|
245
|
+
even={even}
|
|
246
|
+
>
|
|
247
|
+
{children}
|
|
248
|
+
</DLRow>
|
|
249
|
+
)
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// ─── BulletGridRow — Bullet item in grid layout (use inside DL) ─────
|
|
253
|
+
|
|
254
|
+
export function BulletGridRow({ color, term, children, even }: {
|
|
255
|
+
color: string
|
|
256
|
+
term: string
|
|
257
|
+
children: ReactNode
|
|
258
|
+
even?: boolean
|
|
259
|
+
}) {
|
|
260
|
+
return (
|
|
261
|
+
<DLRow
|
|
262
|
+
term={
|
|
263
|
+
<span className="flex items-center gap-1.5">
|
|
264
|
+
<span className={`text-${color}-400`} style={{ fontSize: '18px', lineHeight: '14px' }}>•</span>
|
|
265
|
+
<span className={`text-${color}-400 font-semibold`}>{term}</span>
|
|
266
|
+
</span>
|
|
267
|
+
}
|
|
268
|
+
even={even}
|
|
269
|
+
>
|
|
270
|
+
{children}
|
|
271
|
+
</DLRow>
|
|
272
|
+
)
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// ─── NumberGridRow — Numbered item in grid layout (use inside DL) ───
|
|
276
|
+
|
|
277
|
+
export function NumberGridRow({ color, n, term, children, even }: {
|
|
278
|
+
color: string
|
|
279
|
+
n: number
|
|
280
|
+
term: string
|
|
281
|
+
children: ReactNode
|
|
282
|
+
even?: boolean
|
|
283
|
+
}) {
|
|
284
|
+
return (
|
|
285
|
+
<DLRow
|
|
286
|
+
term={
|
|
287
|
+
<span className="flex items-center gap-1.5">
|
|
288
|
+
<span className={`text-${color}-400 font-bold w-4 text-right shrink-0`}>{n}.</span>
|
|
289
|
+
<span className={`text-${color}-400 font-semibold`}>{term}</span>
|
|
290
|
+
</span>
|
|
291
|
+
}
|
|
292
|
+
even={even}
|
|
293
|
+
>
|
|
294
|
+
{children}
|
|
295
|
+
</DLRow>
|
|
296
|
+
)
|
|
297
|
+
}
|