@toolr/ui-design 0.1.5 → 0.1.6

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 (68) hide show
  1. package/agent-rules.json +91 -0
  2. package/ai-manifest.json +190 -0
  3. package/components/content/info-panel-primitives.tsx +14 -14
  4. package/components/lib/ai-tools.tsx +1 -1
  5. package/components/sections/ai-tools-paths/tools-paths-panel.tsx +7 -7
  6. package/components/sections/captured-issues/captured-issues-panel.tsx +11 -11
  7. package/components/sections/golden-snapshots/file-diff-viewer.tsx +13 -13
  8. package/components/sections/golden-snapshots/golden-sync-panel.tsx +5 -5
  9. package/components/sections/golden-snapshots/snapshot-manager.tsx +11 -11
  10. package/components/sections/golden-snapshots/status-overview.tsx +20 -20
  11. package/components/sections/golden-snapshots/version-manager.tsx +8 -8
  12. package/components/sections/prompt-editor/file-type-tabbed-prompt-editor.tsx +4 -4
  13. package/components/sections/prompt-editor/simulator-prompt-editor.tsx +5 -5
  14. package/components/sections/prompt-editor/tabbed-prompt-editor.tsx +7 -7
  15. package/components/sections/report-bug/report-bug-form.tsx +14 -14
  16. package/components/sections/report-bug/screenshot-uploader.tsx +6 -6
  17. package/components/sections/snapshot-browser/snapshot-browser-panel.tsx +3 -3
  18. package/components/sections/snapshot-browser/snapshot-tree.tsx +8 -8
  19. package/components/sections/snippets-editor/snippets-editor.tsx +81 -22
  20. package/components/settings/SettingsHeader.tsx +1 -1
  21. package/components/settings/SettingsTreeNav.tsx +22 -4
  22. package/components/ui/action-dialog.tsx +5 -5
  23. package/components/ui/badge.tsx +4 -4
  24. package/components/ui/bottom-panel-header.tsx +4 -4
  25. package/components/ui/breadcrumb.tsx +2 -2
  26. package/components/ui/collapsible-section.tsx +1 -1
  27. package/components/ui/cookie-consent.tsx +5 -5
  28. package/components/ui/detail-section.tsx +3 -3
  29. package/components/ui/editor-placeholder-card.tsx +7 -7
  30. package/components/ui/editor-toolbar.tsx +12 -0
  31. package/components/ui/execution-details-panel.tsx +6 -6
  32. package/components/ui/extension-list-card.tsx +3 -3
  33. package/components/ui/file-structure-section.tsx +17 -17
  34. package/components/ui/file-tree.tsx +3 -1
  35. package/components/ui/files-panel.tsx +27 -9
  36. package/components/ui/filter-dropdown.tsx +5 -5
  37. package/components/ui/form-actions.tsx +1 -1
  38. package/components/ui/frontmatter-form-header.tsx +4 -4
  39. package/components/ui/icon-button.tsx +1 -1
  40. package/components/ui/input.tsx +5 -5
  41. package/components/ui/label.tsx +4 -4
  42. package/components/ui/layout-tab-bar.tsx +4 -4
  43. package/components/ui/modal.tsx +2 -2
  44. package/components/ui/nav-card.tsx +3 -3
  45. package/components/ui/navigation-bar.tsx +5 -5
  46. package/components/ui/number-input.tsx +4 -4
  47. package/components/ui/registry-browser.tsx +4 -4
  48. package/components/ui/registry-card.tsx +13 -13
  49. package/components/ui/registry-detail.tsx +6 -6
  50. package/components/ui/segmented-toggle.tsx +4 -4
  51. package/components/ui/select.tsx +5 -5
  52. package/components/ui/selection-grid.tsx +4 -4
  53. package/components/ui/setting-row.tsx +1 -1
  54. package/components/ui/settings-card.tsx +3 -3
  55. package/components/ui/settings-info-box.tsx +1 -1
  56. package/components/ui/settings-section-title.tsx +1 -1
  57. package/components/ui/snapshot-card.tsx +7 -7
  58. package/components/ui/snippets-panel.tsx +10 -10
  59. package/components/ui/sort-dropdown.tsx +2 -2
  60. package/components/ui/status-card.tsx +4 -4
  61. package/components/ui/tab-bar.tsx +2 -2
  62. package/components/ui/tooltip.tsx +3 -3
  63. package/dist/content.js +14 -14
  64. package/dist/index.d.ts +11 -4
  65. package/dist/index.js +428 -336
  66. package/dist/tokens/primitives.css +9 -2
  67. package/package.json +13 -3
  68. package/tokens/primitives.css +9 -2
@@ -0,0 +1,91 @@
1
+ {
2
+ "meta": {
3
+ "description": "Critical rules for AI agents building apps with @toolr/ui-design. These are the things agents commonly get wrong.",
4
+ "lastUpdated": "2026-03-05"
5
+ },
6
+ "categories": [
7
+ {
8
+ "name": "Setup",
9
+ "color": "#2dd4bf",
10
+ "rules": [
11
+ { "type": "do", "text": "body { background-color: var(--background); } — portals render at document.body with semi-transparent backgrounds; without this, white bleeds through" },
12
+ { "type": "do", "text": "@import \"@toolr/ui-design/tokens\" in app CSS — without it, all semantic tokens are undefined" },
13
+ { "type": "do", "text": "Add @utility text-xs { font-size: 11px; } in app CSS — Tailwind v4 @theme blocks in consuming apps don't inherit --font-size-xss from ui-design tokens" },
14
+ { "type": "do", "text": "Import from @toolr/ui-design barrel only, never deep paths like @toolr/ui-design/components/ui/input" }
15
+ ]
16
+ },
17
+ {
18
+ "name": "Typography",
19
+ "color": "#fbbf24",
20
+ "rules": [
21
+ { "type": "dont", "text": "Minimum font size is 11px (text-xs) — never go below" },
22
+ { "type": "do", "text": "text-neutral-300 is primary text, not white — white is for emphasis only" },
23
+ { "type": "do", "text": "font-medium (500) is the default weight — not semibold, not normal" }
24
+ ]
25
+ },
26
+ {
27
+ "name": "Components",
28
+ "color": "#60a5fa",
29
+ "rules": [
30
+ { "type": "do", "text": "Every IconButton must have a tooltip prop — tooltip={{ description: \"...\" }}, not a plain string" },
31
+ { "type": "do", "text": "onChange delivers the value directly, never a React event — onChange={setName} not onChange={(e) => setName(e.target.value))" },
32
+ { "type": "do", "text": "Icons are string names — icon=\"search\", not icon={<Search />} from lucide-react" },
33
+ { "type": "do", "text": "Use FilterDropdown for filtering (value \"all\" for unfiltered), SortDropdown for sorting — they are separate components" },
34
+ { "type": "dont", "text": "Never use Select with an \"All\" option for filtering — use FilterDropdown" },
35
+ { "type": "dont", "text": "Never use raw HTML <select>, <input type=\"checkbox\">, <button>, or inline dropdown implementations" },
36
+ { "type": "do", "text": "ConfirmModal for actions (confirm/cancel), AlertModal for info (dismiss only) — don't mix them" },
37
+ { "type": "do", "text": "Use cn() for class composition, never string concatenation — cn() resolves Tailwind conflicts" }
38
+ ]
39
+ },
40
+ {
41
+ "name": "Styling",
42
+ "color": "#c084fc",
43
+ "rules": [
44
+ { "type": "do", "text": "Use semantic tokens (--background, --surface, --border) for structure, Tailwind utilities for accent colors" },
45
+ { "type": "dont", "text": "Never hardcode hex values for accents — use Tailwind {color}-{shade} classes" },
46
+ { "type": "dont", "text": "Never use transition-all — specify the property (transition-colors, transition-transform)" },
47
+ { "type": "dont", "text": "Never use shadow-sm/shadow-md — use shadow-xl for dropdowns/tooltips, shadow-2xl for modals only" },
48
+ { "type": "dont", "text": "Never use rounded-full except for toggle knobs, checkmarks, and avatars — badges use rounded-lg" },
49
+ { "type": "dont", "text": "Never use CSS group-hover for tooltips — always use the portal-based Tooltip component" }
50
+ ]
51
+ },
52
+ {
53
+ "name": "Portals",
54
+ "color": "#fb923c",
55
+ "rules": [
56
+ { "type": "do", "text": "Select, Tooltip, Modal all render via createPortal to document.body — parent overflow:hidden and z-index don't affect them" },
57
+ { "type": "do", "text": "Popover background is rgba(0,0,0,0.8) — semi-transparent by design, which is why body background matters" },
58
+ { "type": "dont", "text": "Never wrap portal components in overflow:hidden expecting to clip them — they escape to document.body" }
59
+ ]
60
+ },
61
+ {
62
+ "name": "State & Data",
63
+ "color": "#4ade80",
64
+ "rules": [
65
+ { "type": "do", "text": "Zustand empty array selectors: use a module-level constant — const EMPTY: T[] = [], never inline []" },
66
+ { "type": "do", "text": "Immutable store updates: always spread nested state — { ...state.settings, key: value }" },
67
+ { "type": "dont", "text": "Never prop drill data available in stores — components should read from stores directly" },
68
+ { "type": "dont", "text": "Never call invoke() directly — use the central useTauri.ts wrapper (handles snake_case mapping)" }
69
+ ]
70
+ },
71
+ {
72
+ "name": "Code Hygiene",
73
+ "color": "#fb7185",
74
+ "rules": [
75
+ { "type": "dont", "text": "Never comment out code — delete it entirely. No // removed, no _unused renames" },
76
+ { "type": "dont", "text": "Never create abstractions for one-time operations — only when 3+ identical implementations exist" },
77
+ { "type": "do", "text": "Features only import from core, never from other features — cross-feature data flows through core stores" },
78
+ { "type": "do", "text": "Delete unused exports, types, and variables — no speculative interfaces or \"just in case\" code" }
79
+ ]
80
+ },
81
+ {
82
+ "name": "Sync Validation",
83
+ "color": "#22d3ee",
84
+ "rules": [
85
+ { "type": "dont", "text": "Never use --no-verify or --no-hooks to bypass the pre-commit sync check" },
86
+ { "type": "do", "text": "Run npm run sync-check before committing component or playground changes" },
87
+ { "type": "do", "text": "Keep playground page, App.tsx route, component-graph entry, and ai-manifest.json in sync within the same commit" }
88
+ ]
89
+ }
90
+ ]
91
+ }
@@ -0,0 +1,190 @@
1
+ {
2
+ "meta": {
3
+ "package": "@toolr/ui-design",
4
+ "description": "Shared dark-theme design system for toolr apps. React + Tailwind CSS.",
5
+ "imports": {
6
+ "components": "@toolr/ui-design",
7
+ "tokens": "@toolr/ui-design/tokens",
8
+ "content": "@toolr/ui-design/content",
9
+ "diagrams": "@toolr/ui-design/diagrams",
10
+ "preset": "@toolr/ui-design/preset",
11
+ "manifest": "@toolr/ui-design/manifest"
12
+ },
13
+ "docs": {
14
+ "rules": "docs/rules/",
15
+ "files": [
16
+ "docs/rules/foundations.md",
17
+ "docs/rules/color-system.md",
18
+ "docs/rules/token-conventions.md",
19
+ "docs/rules/component-usage.md",
20
+ "docs/rules/icon-conventions.md",
21
+ "docs/rules/layout-patterns.md",
22
+ "docs/rules/content-conventions.md",
23
+ "docs/rules/diagram-conventions.md"
24
+ ]
25
+ },
26
+ "howToUse": "Import components from '@toolr/ui-design'. Import CSS tokens via @import '@toolr/ui-design/tokens' in your app CSS. Read the relevant docs/rules/ file for conventions. For full component interfaces, read the source file listed in each component entry."
27
+ },
28
+
29
+ "conventions": {
30
+ "onChange": "Receives the new value directly, never a React event",
31
+ "className": "Use cn() from @toolr/ui-design for conditional class composition (clsx + tailwind-merge)",
32
+ "icons": "Use IconButton with icon='name' string prop (lucide icon names). Do NOT import lucide-react directly",
33
+ "tooltips": "Always an object { description: string, title?: string, extra?: string }, never a plain string",
34
+ "colors": "Use Tailwind utilities for accents (text-blue-400, bg-green-500/20). Use CSS vars for structural colors (var(--surface)). Never raw hex",
35
+ "spacing": "4px grid: 0, 0.5, 1, 1.5, 2, 3, 4, 6 (= 0-24px). Never arbitrary values like mt-7 or px-9",
36
+ "typography": "text-xs (12px captions), text-sm (14px body), text-base (16px headings). text-xss (11px) for fine print",
37
+ "modals": "Use ConfirmModal/AlertModal/ActionDialog. Never window.alert/confirm/prompt"
38
+ },
39
+
40
+ "types": {
41
+ "FormColor": "blue | green | red | orange | cyan | yellow | purple | indigo | emerald | amber | violet | gray | sky",
42
+ "AccentColor": "blue | purple | orange | green | pink | amber | emerald | teal | sky",
43
+ "IconName": "string — any lucide icon name (e.g. 'save', 'trash', 'search', 'plus')",
44
+ "TooltipContent": "{ title?: string, description: string | ReactNode, extra?: string }",
45
+ "SelectOption<T>": "{ value: T, label: string, icon?: ReactNode }",
46
+ "ModalKind": "info | warning | error | success",
47
+ "ModalSize": "sm | md | lg | xl"
48
+ },
49
+
50
+ "components": {
51
+ "form": [
52
+ { "name": "Input", "description": "Text input with search mode, action slot, error state", "replaces": "input", "keyProps": "value, onChange, type?: text|search, variant?: filled|ghost, size?: sm|md, error?, mono?, actionSlot?", "file": "components/ui/input.tsx" },
53
+ { "name": "NumberInput", "description": "Numeric input with increment/decrement buttons", "replaces": "input[type=number]", "keyProps": "value, onChange, min?, max?, step?, size?: sm|md", "file": "components/ui/number-input.tsx" },
54
+ { "name": "Select", "description": "Portal dropdown with keyboard nav and check indicators", "replaces": "select", "keyProps": "value, onChange, options: SelectOption[], color?: FormColor, size?: sm|md, variant?: filled|ghost", "file": "components/ui/select.tsx" },
55
+ { "name": "FilterDropdown", "description": "Clearable single-select filter with 'All' default and optional search", "keyProps": "value, onChange, options, allLabel?, searchable?", "file": "components/ui/filter-dropdown.tsx" },
56
+ { "name": "SortDropdown", "description": "Field picker with direction toggle arrow", "keyProps": "field, ascending, fields: SortField[], onFieldChange, onToggleDirection", "file": "components/ui/sort-dropdown.tsx" },
57
+ { "name": "Toggle", "description": "iOS-style boolean switch", "replaces": "input[type=checkbox] (for on/off settings)", "keyProps": "checked, onChange, color?: FormColor, size?: sm|md|lg", "file": "components/ui/toggle.tsx" },
58
+ { "name": "Checkbox", "description": "Check-icon boolean for multi-select lists", "replaces": "input[type=checkbox] (for checklists)", "keyProps": "checked, onChange, color?: FormColor, size?: sm|md|lg", "file": "components/ui/checkbox.tsx" },
59
+ { "name": "SegmentedToggle", "description": "Horizontal icon-based mutually-exclusive toggle group", "keyProps": "options: SegmentedToggleOption[], value, onChange, color?: FormColor", "file": "components/ui/segmented-toggle.tsx" },
60
+ { "name": "ResizableTextarea", "description": "Textarea with drag-to-resize handle", "replaces": "textarea", "keyProps": "value, onChange, variant?: filled|ghost, minHeight?, maxHeight?", "file": "components/ui/resizable-textarea.tsx" },
61
+ { "name": "FormActions", "description": "Flex row for form buttons with optional nav slot", "keyProps": "padding?: compact|normal|modal, children", "file": "components/ui/form-actions.tsx" },
62
+ { "name": "SelectionGrid", "description": "Grid of selectable cards with icons and descriptions", "keyProps": "items: SelectionCardItem[], selected, onSelect", "file": "components/ui/selection-grid.tsx" }
63
+ ],
64
+
65
+ "action": [
66
+ { "name": "IconButton", "description": "Icon-only button with tooltip, badge, status indicator, href mode", "replaces": "button", "keyProps": "icon: IconName|ReactNode, tooltip: TooltipContent, color?: FormColor, size?: xss|xs|sm|lg, status?, badge?, href?, strikethrough?, disabled?", "file": "components/ui/icon-button.tsx" },
67
+ { "name": "CollapseButton", "description": "Animated chevron toggle button for expand/collapse", "keyProps": "isOpen, onToggle, tooltip: TooltipContent", "file": "components/ui/icon-button.tsx" },
68
+ { "name": "AiActionButton", "description": "Button with AI loading/success/error states for async AI operations", "keyProps": "icon, tooltip, status: AiActionStatus, onClick, completionResult?", "file": "components/ui/ai-action-button.tsx" },
69
+ { "name": "AiExecutionActionButtons", "description": "Run/stop/retry button group for AI execution workflows", "keyProps": "status: ExecutionStatus, onRun, onStop, onRetry", "file": "components/ui/ai-execution-action-buttons.tsx" },
70
+ { "name": "ConfirmBadge", "description": "Badge that requires click-confirmation before triggering action", "keyProps": "label, onConfirm, color?: ConfirmBadgeColor", "file": "components/ui/confirm-badge.tsx" }
71
+ ],
72
+
73
+ "display": [
74
+ { "name": "Label", "description": "Border-focused colored badge/tag with icon and tooltip", "keyProps": "text, color: LabelColor, icon?, tooltip?: TooltipContent, size?: xs|sm|md", "file": "components/ui/label.tsx" },
75
+ { "name": "Badge", "description": "Minimal inline badge for counts or short labels", "keyProps": "text, color?: BadgeColor", "file": "components/ui/badge.tsx" },
76
+ { "name": "ScopeBadge", "description": "Pre-configured Label for user/project/local/read-only scopes", "keyProps": "scope: ScopeType", "file": "components/ui/scope-badge.tsx" },
77
+ { "name": "Tooltip", "description": "Portal-based tooltip with auto-positioning and arrow", "keyProps": "content: TooltipContent, position?: top|bottom|left|right|auto, children", "file": "components/ui/tooltip.tsx" },
78
+ { "name": "TooltipButton", "description": "Icon button that toggles a persistent tooltip on click", "keyProps": "content: TooltipContent, icon?: IconName", "file": "components/ui/tooltip.tsx" },
79
+ { "name": "StatusCard", "description": "Card showing a list of status items with icons and values", "keyProps": "title, items: StatusItem[]", "file": "components/ui/status-card.tsx" },
80
+ { "name": "SnapshotCard", "description": "Card displaying snapshot metadata with timestamp and actions", "keyProps": "snapshot, onRestore?, onDelete?", "file": "components/ui/snapshot-card.tsx" }
81
+ ],
82
+
83
+ "layout": [
84
+ { "name": "CollapsibleSection", "description": "Section with animated expand/collapse and header actions", "keyProps": "title, defaultOpen?, children, actions?", "file": "components/ui/collapsible-section.tsx" },
85
+ { "name": "DetailSection", "description": "Key-value detail rows in a bordered section", "keyProps": "title, rows: DetailRow[]", "file": "components/ui/detail-section.tsx" },
86
+ { "name": "DetailViewWrapper", "description": "Standard wrapper for detail/edit views with header and back navigation", "keyProps": "title, onBack?, children, actions?", "file": "components/ui/detail-view-wrapper.tsx" },
87
+ { "name": "BottomPanelHeader", "description": "Tab bar header for bottom panels with status banner", "keyProps": "tabs: PanelTab[], activeTab, onTabChange, banner?: StatusBanner", "file": "components/ui/bottom-panel-header.tsx" },
88
+ { "name": "EditorToolbar", "description": "Toolbar row for editor panels with title, actions, and status", "keyProps": "title?, children, actions?", "file": "components/ui/editor-toolbar.tsx" },
89
+ { "name": "EditorPlaceholderCard", "description": "Centered placeholder card shown when no editor content is active", "keyProps": "icon, title, description", "file": "components/ui/editor-placeholder-card.tsx" },
90
+ { "name": "FrontmatterFormHeader", "description": "Form header for YAML frontmatter editing with field labels", "keyProps": "fields, onChange", "file": "components/ui/frontmatter-form-header.tsx" },
91
+ { "name": "FilesPanel", "description": "File list panel with add/remove actions", "keyProps": "files: FileEntry[], onAdd?, onRemove?", "file": "components/ui/files-panel.tsx" },
92
+ { "name": "SnippetsPanel", "description": "Panel displaying a list of text snippets with copy action", "keyProps": "snippets: Snippet[], onCopy?", "file": "components/ui/snippets-panel.tsx" }
93
+ ],
94
+
95
+ "navigation": [
96
+ { "name": "Breadcrumb", "description": "Breadcrumb trail with clickable segments", "keyProps": "segments: BreadcrumbSegment[], onNavigate", "file": "components/ui/breadcrumb.tsx" },
97
+ { "name": "NavigationBar", "description": "Top navigation bar with title, back button, and actions", "keyProps": "title, onBack?, children", "file": "components/ui/navigation-bar.tsx" },
98
+ { "name": "TabBar", "description": "Horizontal tab strip with optional badge counts", "keyProps": "tabs: Tab[], activeTab, onTabChange", "file": "components/ui/tab-bar.tsx" },
99
+ { "name": "LayoutTabBar", "description": "Tab bar for switching layout views (e.g. split/full)", "keyProps": "tabs: LayoutTab[], activeTab, onTabChange", "file": "components/ui/layout-tab-bar.tsx" },
100
+ { "name": "NavCard", "description": "Navigation card with icon, title, and description for app selection", "keyProps": "title, description, icon, onClick, color?", "file": "components/ui/nav-card.tsx" },
101
+ { "name": "ExtensionListCard", "description": "Card showing extension info with type indicator and actions", "keyProps": "title, type, description, actions?", "file": "components/ui/extension-list-card.tsx" }
102
+ ],
103
+
104
+ "modal": [
105
+ { "name": "ConfirmModal", "description": "Action confirmation dialog with confirm/cancel buttons", "replaces": "window.confirm", "keyProps": "isOpen, onClose, onConfirm, title, kind?: ModalKind, confirmLabel?, loading?, children", "file": "components/ui/modal.tsx" },
106
+ { "name": "AlertModal", "description": "Dismiss-only alert dialog", "replaces": "window.alert", "keyProps": "isOpen, onClose, title, kind?: ModalKind, children", "file": "components/ui/modal.tsx" },
107
+ { "name": "ActionDialog", "description": "Full-featured dialog with custom content and action buttons", "keyProps": "isOpen, onClose, title, size?: ModalSize, children, actions?", "file": "components/ui/action-dialog.tsx" }
108
+ ],
109
+
110
+ "section": [
111
+ { "name": "TabbedPromptEditor", "description": "Multi-tab prompt editor with variable insertion and dirty detection. Use with usePromptEditor() hook", "keyProps": "...usePromptEditor(), standalone?, className?", "hook": "usePromptEditor", "file": "components/sections/prompt-editor/index.ts" },
112
+ { "name": "FileTypeTabbedPromptEditor", "description": "Prompt editor variant with file type tabs", "keyProps": "...usePromptEditor(), fileTypes: FileTypeOption[]", "hook": "usePromptEditor", "file": "components/sections/prompt-editor/index.ts" },
113
+ { "name": "SimulatorPromptEditor", "description": "Prompt editor with scenario selector for testing prompts", "keyProps": "...usePromptEditor(), scenarios: ScenarioOption[]", "file": "components/sections/prompt-editor/index.ts" },
114
+ { "name": "RegistryBrowser", "description": "Browsable grid of registry items with search, filter, sort", "keyProps": "items, onSelect, selectedId?", "file": "components/ui/registry-browser.tsx" },
115
+ { "name": "RegistryDetail", "description": "Detail view for a single registry item with file structure", "keyProps": "item, onBack, onInstall?", "file": "components/ui/registry-detail.tsx" },
116
+ { "name": "RegistryCard", "description": "Card displaying a registry item with type badge and metadata", "keyProps": "item, onClick?, selected?", "file": "components/ui/registry-card.tsx" },
117
+ { "name": "GoldenSyncPanel", "description": "Golden snapshot sync panel with diff viewer. Use with useGoldenSync() hook", "keyProps": "...useGoldenSync()", "hook": "useGoldenSync", "file": "components/sections/golden-snapshots/index.ts" },
118
+ { "name": "SnapshotBrowserPanel", "description": "Browse and manage snapshots. Use with useSnapshotBrowser() hook", "keyProps": "...useSnapshotBrowser()", "hook": "useSnapshotBrowser", "file": "components/sections/snapshot-browser/index.ts" },
119
+ { "name": "SnippetsEditor", "description": "Create and edit text snippets. Use with useSnippetsEditor() hook", "keyProps": "...useSnippetsEditor()", "hook": "useSnippetsEditor", "file": "components/sections/snippets-editor/index.ts" },
120
+ { "name": "ReportBugForm", "description": "Bug report form with screenshot capture. Use with useReportBug() hook", "keyProps": "...useReportBug()", "hook": "useReportBug", "file": "components/sections/report-bug/index.ts" },
121
+ { "name": "ScreenshotUploader", "description": "Drag & drop multi-image upload with base64 encoding and preview thumbnails", "keyProps": "screenshots: Screenshot[], onChange, maxTotalSize?, disabled?", "file": "components/sections/report-bug/index.ts" },
122
+ { "name": "ToolsPathsPanel", "description": "AI tool path configuration panel. Use with useToolsPaths() hook", "keyProps": "...useToolsPaths()", "hook": "useToolsPaths", "file": "components/sections/ai-tools-paths/index.ts" },
123
+ { "name": "CapturedIssuesPanel", "description": "View and manage captured error issues. Use with useCapturedIssues() hook", "keyProps": "...useCapturedIssues()", "hook": "useCapturedIssues", "file": "components/sections/captured-issues/index.ts" },
124
+ { "name": "FileStructureSection", "description": "File tree with code preview, syntax highlighting, and copy", "keyProps": "files: FileTreeNode[], accentColor?: AccentColor", "file": "components/ui/file-structure-section.tsx" },
125
+ { "name": "FileTree", "description": "Expandable file/folder tree with selection", "keyProps": "nodes: FileTreeNode[], selectedPath?, onSelect", "file": "components/ui/file-tree.tsx" },
126
+ { "name": "ExecutionDetailsPanel", "description": "Panel showing execution result rows with expandable details", "keyProps": "rows: ExecutionDetailRow[]", "file": "components/ui/execution-details-panel.tsx" }
127
+ ],
128
+
129
+ "settings": [
130
+ { "name": "SettingsPanel", "description": "Full settings page with tree navigation and content area", "keyProps": "tree: SettingsTreeNode[], activePath, onNavigate, children", "file": "components/settings/index.ts" },
131
+ { "name": "SettingsTreeNav", "description": "Tree navigation sidebar for settings", "keyProps": "tree: SettingsTreeNode[], activePath, onNavigate", "file": "components/settings/index.ts" },
132
+ { "name": "SettingsHeader", "description": "Header for settings pages with breadcrumb", "keyProps": "path: string[], tree: SettingsTreeNode[]", "file": "components/settings/index.ts" },
133
+ { "name": "SettingRow", "description": "Single settings row with label, description, and control slot", "keyProps": "label, description?, children (control element)", "file": "components/ui/setting-row.tsx" },
134
+ { "name": "SettingsCard", "description": "Bordered card container for grouping settings", "keyProps": "title?, children", "file": "components/ui/settings-card.tsx" },
135
+ { "name": "SettingsInfoBox", "description": "Informational callout box within settings", "keyProps": "title?, children, color?: SettingsInfoBoxColor", "file": "components/ui/settings-info-box.tsx" },
136
+ { "name": "SettingsSectionTitle", "description": "Section heading for settings groups", "keyProps": "title, description?", "file": "components/ui/settings-section-title.tsx" }
137
+ ],
138
+
139
+ "brand": [
140
+ { "name": "ToolrAppLogo", "description": "App logo with icon and name for toolr suite apps", "keyProps": "appId: ToolrAppId, size?: sm|md|lg", "file": "components/lib/toolr-brand.tsx" },
141
+ { "name": "AiToolIcon", "description": "Logo icon for AI tools (Claude, GPT, Gemini, etc.)", "keyProps": "tool: AiToolKey, size?: number", "file": "components/lib/ai-tools.tsx" },
142
+ { "name": "CookieConsent", "description": "Cookie consent banner with accept/reject", "keyProps": "onConsent: (choice: ConsentChoice) => void", "file": "components/ui/cookie-consent.tsx" }
143
+ ]
144
+ },
145
+
146
+ "hooks": [
147
+ { "name": "usePromptEditor", "description": "State manager for TabbedPromptEditor — tabs, dirty detection, save, variables", "file": "components/sections/prompt-editor/index.ts" },
148
+ { "name": "useGoldenSync", "description": "State manager for GoldenSyncPanel — diff tree, sync status, file comparison", "file": "components/sections/golden-snapshots/index.ts" },
149
+ { "name": "useSnapshotBrowser", "description": "State manager for SnapshotBrowserPanel — snapshot list, categories, actions", "file": "components/sections/snapshot-browser/index.ts" },
150
+ { "name": "useSnippetsEditor", "description": "State manager for SnippetsEditor — CRUD operations on snippets", "file": "components/sections/snippets-editor/index.ts" },
151
+ { "name": "useReportBug", "description": "State manager for ReportBugForm — issue types, screenshots, submission", "file": "components/sections/report-bug/index.ts" },
152
+ { "name": "useToolsPaths", "description": "State manager for ToolsPathsPanel — AI tool detection, path configuration", "file": "components/sections/ai-tools-paths/index.ts" },
153
+ { "name": "useCapturedIssues", "description": "State manager for CapturedIssuesPanel — error list, submission, dismissal", "file": "components/sections/captured-issues/index.ts" },
154
+ { "name": "useClickOutside", "description": "Close menus/dropdowns when clicking outside the ref element", "file": "components/hooks/use-click-outside.ts" },
155
+ { "name": "useDropdownMaxHeight", "description": "Calculate max height for dropdowns to stay within viewport", "file": "components/hooks/use-dropdown-max-height.ts" },
156
+ { "name": "useNavigationHistory", "description": "Browser-like back/forward navigation state", "file": "components/hooks/use-navigation-history.ts" }
157
+ ],
158
+
159
+ "utilities": [
160
+ { "name": "cn", "description": "clsx + tailwind-merge for conditional class composition", "usage": "cn('base-class', condition && 'conditional-class', className)", "file": "components/lib/cn.ts" },
161
+ { "name": "FORM_COLORS", "description": "Color config map — FORM_COLORS[color].border/.hover/.focus/.selectedBg/.accent", "file": "components/lib/form-colors.ts" },
162
+ { "name": "applyTheme", "description": "Apply theme to document — applyTheme(themeId, accentHue)", "file": "components/lib/theme-engine.ts" },
163
+ { "name": "ACCENT_DEFS", "description": "Array of { id, label, hue } for all available accent colors", "file": "components/lib/theme-engine.ts" },
164
+ { "name": "iconMap", "description": "Map of icon name strings to lucide-react components", "file": "components/ui/icon-button.tsx" }
165
+ ],
166
+
167
+ "enforcement": {
168
+ "htmlReplacements": {
169
+ "button": "IconButton",
170
+ "input": "Input",
171
+ "select": "Select",
172
+ "textarea": "ResizableTextarea"
173
+ },
174
+ "allowedImportPaths": [
175
+ "@toolr/ui-design",
176
+ "@toolr/ui-design/tokens",
177
+ "@toolr/ui-design/content",
178
+ "@toolr/ui-design/diagrams",
179
+ "@toolr/ui-design/preset",
180
+ "@toolr/ui-design/manifest"
181
+ ],
182
+ "bannedImports": ["lucide-react"],
183
+ "bannedGlobals": ["alert", "confirm", "prompt"],
184
+ "bannedGlobalReplacements": {
185
+ "alert": "AlertModal",
186
+ "confirm": "ConfirmModal",
187
+ "prompt": "ConfirmModal with an Input"
188
+ }
189
+ }
190
+ }
@@ -10,7 +10,7 @@ import type { ReactNode } from 'react'
10
10
  // ─── Paragraph ──────────────────────────────────────────────────────
11
11
 
12
12
  export function P({ children }: { children: ReactNode }) {
13
- return <p className="text-sm text-neutral-400 leading-relaxed mb-5">{children}</p>
13
+ return <p className="text-md text-neutral-400 leading-relaxed mb-5">{children}</p>
14
14
  }
15
15
 
16
16
  // ─── Section Header ─────────────────────────────────────────────────
@@ -18,7 +18,7 @@ export function P({ children }: { children: ReactNode }) {
18
18
  export function SectionHeader({ color, children }: { color?: string; children: ReactNode }) {
19
19
  const textColor = color ? `text-${color}-500/70` : 'text-neutral-500'
20
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' }}>
21
+ <p className={`${textColor} text-sm uppercase font-semibold pb-0.5 border-b border-neutral-700/50 mb-2.5`} style={{ letterSpacing: '0.8px' }}>
22
22
  {children}
23
23
  </p>
24
24
  )
@@ -38,10 +38,10 @@ export function DLRow({ term, children, even }: { term: ReactNode; children: Rea
38
38
  const bg = even ? 'bg-white/[0.015]' : ''
39
39
  return (
40
40
  <>
41
- <div className={`py-2 border-b border-neutral-800/60 ${bg} font-semibold text-sm whitespace-nowrap`}>
41
+ <div className={`py-2 border-b border-neutral-800/60 ${bg} font-semibold text-md whitespace-nowrap`}>
42
42
  {term}
43
43
  </div>
44
- <div className={`py-2 border-b border-neutral-800/60 ${bg} text-sm text-neutral-400`}>{children}</div>
44
+ <div className={`py-2 border-b border-neutral-800/60 ${bg} text-md text-neutral-400`}>{children}</div>
45
45
  </>
46
46
  )
47
47
  }
@@ -49,7 +49,7 @@ export function DLRow({ term, children, even }: { term: ReactNode; children: Rea
49
49
  // ─── Unordered List ─────────────────────────────────────────────────
50
50
 
51
51
  export function UL({ children }: { children: ReactNode }) {
52
- return <ul className="text-sm text-neutral-400 space-y-2 mb-5">{children}</ul>
52
+ return <ul className="text-md text-neutral-400 space-y-2 mb-5">{children}</ul>
53
53
  }
54
54
 
55
55
  export function LI({ color, children }: { color: string; children: ReactNode }) {
@@ -69,7 +69,7 @@ export function OL({ children }: { children: ReactNode }) {
69
69
 
70
70
  export function OLI({ n, color, children }: { n: number; color: string; children: ReactNode }) {
71
71
  return (
72
- <div className="flex items-start gap-2.5 text-sm">
72
+ <div className="flex items-start gap-2.5 text-md">
73
73
  <span className={`text-${color}-400 shrink-0 w-4 text-right font-bold`}>{n}.</span>
74
74
  <span className="text-neutral-400">{children}</span>
75
75
  </div>
@@ -105,7 +105,7 @@ export function getCalloutColors(color: string) {
105
105
  export function Callout({ color, children }: { color: string; children: ReactNode }) {
106
106
  const c = CALLOUT_COLORS[color] ?? CALLOUT_COLORS.blue
107
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`}>
108
+ <div className={`border-l-4 ${c.borderL} border-y ${c.borderY} ${c.bg} px-3 py-2.5 rounded-r mb-5 text-md text-neutral-400`}>
109
109
  {children}
110
110
  </div>
111
111
  )
@@ -114,7 +114,7 @@ export function Callout({ color, children }: { color: string; children: ReactNod
114
114
  export function CalloutCode({ color, children }: { color: string; children: ReactNode }) {
115
115
  const c = CALLOUT_COLORS[color] ?? CALLOUT_COLORS.blue
116
116
  return (
117
- <code className={`block bg-neutral-800/80 px-2 py-1 rounded mt-1.5 text-sm ${c.codeText}`}>
117
+ <code className={`block bg-neutral-800/80 px-2 py-1 rounded mt-1.5 text-md ${c.codeText}`}>
118
118
  {children}
119
119
  </code>
120
120
  )
@@ -128,7 +128,7 @@ export function CalloutDim({ children }: { children: ReactNode }) {
128
128
 
129
129
  export function CodeBlock({ children }: { children: ReactNode }) {
130
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>
131
+ <div className="bg-neutral-900/60 rounded-md p-3 font-mono text-sm text-neutral-400 mb-5 whitespace-pre overflow-x-auto leading-normal">{children}</div>
132
132
  )
133
133
  }
134
134
 
@@ -179,9 +179,9 @@ export function LocationItem({
179
179
  <span
180
180
  className={`w-2 h-2 rounded-full bg-${color}-500/50 border border-${color}-500 shrink-0`}
181
181
  />
182
- <span className={`text-${color}-400 text-sm font-semibold`}>{label}</span>
182
+ <span className={`text-${color}-400 text-md font-semibold`}>{label}</span>
183
183
  </div>
184
- <div className={`py-2 border-b border-neutral-800/60 ${bg} text-sm text-neutral-400`}>{children}</div>
184
+ <div className={`py-2 border-b border-neutral-800/60 ${bg} text-md text-neutral-400`}>{children}</div>
185
185
  </>
186
186
  )
187
187
  }
@@ -190,7 +190,7 @@ export function LocationItem({
190
190
 
191
191
  export function TitledLI({ color, title, children }: { color: string; title: string; children: ReactNode }) {
192
192
  return (
193
- <li className="flex items-start gap-2 text-sm text-neutral-400">
193
+ <li className="flex items-start gap-2 text-md text-neutral-400">
194
194
  <span className={`text-${color}-400 shrink-0`} style={{ marginTop: '3px', fontSize: '18px', lineHeight: '14px' }}>&#x2022;</span>
195
195
  <span>
196
196
  <span className={`text-${color}-300 font-semibold`}>{title}</span>
@@ -204,7 +204,7 @@ export function TitledLI({ color, title, children }: { color: string; title: str
204
204
 
205
205
  export function CalloutDialog({ color, lines }: { color: string; lines: { speaker: string; text: string }[] }) {
206
206
  return (
207
- <div className="bg-neutral-800/80 rounded px-2 py-1 mt-1.5 flex flex-col gap-0.5 text-sm">
207
+ <div className="bg-neutral-800/80 rounded px-2 py-1 mt-1.5 flex flex-col gap-0.5 text-md">
208
208
  {lines.map((line, idx) => (
209
209
  <div key={idx}>
210
210
  <span className={`text-${color}-300 font-semibold mr-1`}>{line.speaker}:</span>
@@ -238,7 +238,7 @@ export function StatusBadge({ value, badgeColor, label, children, even }: {
238
238
  <DLRow
239
239
  term={
240
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-xss font-bold shrink-0`}>{value}</span>
241
+ <span className={`inline-flex items-center justify-center w-5 h-5 rounded-full bg-${badgeColor}-500/20 text-${badgeColor}-400 text-xs font-bold shrink-0`}>{value}</span>
242
242
  <span className={`text-${badgeColor}-400 font-semibold`}>{label}</span>
243
243
  </span>
244
244
  }
@@ -38,7 +38,7 @@ export function AiToolIcon({ tool, size, showName, className, style }: {
38
38
  return (
39
39
  <span style={{ display: 'inline-flex', flexDirection: 'column', alignItems: 'center', gap: 4 }}>
40
40
  {img}
41
- <span className="text-xss text-neutral-400">{AI_TOOL_NAMES[tool as AiToolKey] ?? tool}</span>
41
+ <span className="text-xs text-neutral-400">{AI_TOOL_NAMES[tool as AiToolKey] ?? tool}</span>
42
42
  </span>
43
43
  )
44
44
  }
@@ -66,7 +66,7 @@ export function ToolsPathsPanel({
66
66
  <div className={cn('w-full', className)}>
67
67
  {/* Header */}
68
68
  <div className="flex items-center justify-between mb-4">
69
- <p className="text-xs text-neutral-500 leading-relaxed max-w-xl">
69
+ <p className="text-sm text-neutral-500 leading-relaxed max-w-xl">
70
70
  Configure CLI paths for AI coding assistants. Specify executable locations
71
71
  to enable integration with your development workflow.
72
72
  </p>
@@ -127,12 +127,12 @@ export function ToolsPathsPanel({
127
127
  </div>
128
128
  <div className="flex items-center gap-3">
129
129
  {tool.detected ? (
130
- <span className="flex items-center gap-1 text-xs text-green-400">
130
+ <span className="flex items-center gap-1 text-sm text-green-400">
131
131
  <Check className="w-3.5 h-3.5" />
132
132
  Installed
133
133
  </span>
134
134
  ) : (
135
- <span className="flex items-center gap-1 text-xs text-neutral-500">
135
+ <span className="flex items-center gap-1 text-sm text-neutral-500">
136
136
  <X className="w-3.5 h-3.5" />
137
137
  Not Found
138
138
  </span>
@@ -183,15 +183,15 @@ export function ToolsPathsPanel({
183
183
 
184
184
  {/* Helper text */}
185
185
  {isEnabled && !displayPath?.includes('/') && !tool.detected && (
186
- <p className="text-xs text-red-400 pl-5">
186
+ <p className="text-sm text-red-400 pl-5">
187
187
  Path required when enabled. Enter full path to binary.
188
188
  </p>
189
189
  )}
190
190
  {tool.detected && !tool.binaryPath && (
191
- <p className="text-xs text-neutral-500 pl-5">Using auto-detected path</p>
191
+ <p className="text-sm text-neutral-500 pl-5">Using auto-detected path</p>
192
192
  )}
193
193
  {!isEnabled && !displayPath?.includes('/') && !tool.detected && (
194
- <p className="text-xs text-neutral-500 pl-5">
194
+ <p className="text-sm text-neutral-500 pl-5">
195
195
  Tool disabled. Enter path to enable.
196
196
  </p>
197
197
  )}
@@ -199,7 +199,7 @@ export function ToolsPathsPanel({
199
199
 
200
200
  {/* Disabled warning */}
201
201
  {tool.detected && !isEnabled && (
202
- <p className="text-xs text-yellow-500">
202
+ <p className="text-sm text-yellow-500">
203
203
  Tool disabled — enable to use in your workflow
204
204
  </p>
205
205
  )}
@@ -75,7 +75,7 @@ export function CapturedIssuesPanel({
75
75
  <div className="flex items-center justify-between">
76
76
  <div className="flex items-center gap-2">
77
77
  <AlertTriangle className="w-4 h-4 text-red-400" />
78
- <span className="text-sm text-neutral-300">
78
+ <span className="text-md text-neutral-300">
79
79
  {errorCount > 0 && (
80
80
  <span className="text-red-400">
81
81
  {errorCount} error{errorCount !== 1 ? 's' : ''}
@@ -93,10 +93,10 @@ export function CapturedIssuesPanel({
93
93
 
94
94
  {/* Error List */}
95
95
  <div className="space-y-2">
96
- <p className="text-sm text-neutral-400">Captured Errors</p>
96
+ <p className="text-md text-neutral-400">Captured Errors</p>
97
97
  <div className="max-h-48 overflow-y-auto bg-neutral-950 border border-neutral-700 rounded-lg p-3 space-y-1">
98
98
  {errors.map((error) => (
99
- <div key={error.fingerprint} className="text-xs font-mono break-words">
99
+ <div key={error.fingerprint} className="text-sm font-mono break-words">
100
100
  <span className={cn('mr-2 shrink-0', error.level === 'warning' ? 'text-yellow-400' : 'text-red-400')}>
101
101
  {error.count > 1 ? `\u00d7${error.count}` : '\u2022'}
102
102
  </span>
@@ -108,7 +108,7 @@ export function CapturedIssuesPanel({
108
108
 
109
109
  {/* Optional Details */}
110
110
  <div className="space-y-3">
111
- <p className="text-sm text-neutral-400">Add context (optional)</p>
111
+ <p className="text-md text-neutral-400">Add context (optional)</p>
112
112
  <Input
113
113
  value={title}
114
114
  onChange={setTitle}
@@ -119,7 +119,7 @@ export function CapturedIssuesPanel({
119
119
  onChange={(e) => setDescription(e.target.value)}
120
120
  placeholder="What were you doing when this happened?"
121
121
  rows={3}
122
- className="w-full px-3 py-1.5 bg-neutral-750 border border-neutral-600 rounded-lg text-neutral-300 placeholder-neutral-500 focus:outline-none focus:border-blue-500 transition-colors resize-none text-sm"
122
+ className="w-full px-3 py-1.5 bg-neutral-750 border border-neutral-600 rounded-lg text-neutral-300 placeholder-neutral-500 focus:outline-none focus:border-blue-500 transition-colors resize-none text-md"
123
123
  />
124
124
  <Input
125
125
  type="text"
@@ -163,8 +163,8 @@ export function CapturedIssuesPanel({
163
163
  <Check className="w-5 h-5 text-green-400" />
164
164
  </div>
165
165
  <div>
166
- <h3 className="text-sm text-neutral-300 font-medium">No Issues Captured</h3>
167
- <p className="text-sm text-neutral-500">Everything is running smoothly.</p>
166
+ <h3 className="text-md text-neutral-300 font-medium">No Issues Captured</h3>
167
+ <p className="text-md text-neutral-500">Everything is running smoothly.</p>
168
168
  </div>
169
169
  </div>
170
170
  </div>
@@ -177,8 +177,8 @@ export function CapturedIssuesPanel({
177
177
  <summary className="flex items-center justify-between p-4 cursor-pointer hover:bg-neutral-850 transition-colors">
178
178
  <div className="flex items-center gap-2">
179
179
  <Check className="w-4 h-4 text-green-400" />
180
- <span className="text-sm text-neutral-300">Previously Reported</span>
181
- <span className="text-xs text-neutral-500">({submittedErrors.length})</span>
180
+ <span className="text-md text-neutral-300">Previously Reported</span>
181
+ <span className="text-sm text-neutral-500">({submittedErrors.length})</span>
182
182
  </div>
183
183
  <ChevronDown className="w-4 h-4 text-neutral-500 transition-transform group-open:rotate-180" />
184
184
  </summary>
@@ -191,12 +191,12 @@ export function CapturedIssuesPanel({
191
191
  <Check className="w-4 h-4 text-green-400 mt-0.5 shrink-0" />
192
192
  <div className="flex-1 min-w-0">
193
193
  <p
194
- className="text-sm text-neutral-300 font-mono truncate"
194
+ className="text-md text-neutral-300 font-mono truncate"
195
195
  title={error.message}
196
196
  >
197
197
  {error.message}
198
198
  </p>
199
- <div className="flex items-center gap-3 mt-1 text-xs text-neutral-500">
199
+ <div className="flex items-center gap-3 mt-1 text-sm text-neutral-500">
200
200
  {error.count > 0 && (
201
201
  <span className="text-yellow-400/80">+{error.count} since</span>
202
202
  )}