@keyfunc/keybricks-ds 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (418) hide show
  1. package/DEPLOY.md +204 -0
  2. package/DESIGN.md +269 -0
  3. package/INTEGRATION.md +417 -0
  4. package/SKILL.md +32 -0
  5. package/_adherence.oxlintrc.json +1469 -0
  6. package/_scripts/build-index.mjs +80 -0
  7. package/_scripts/build-tokens.mjs +135 -0
  8. package/assets/icons/icon-index.js +1 -0
  9. package/assets/icons/icon-index.json +1 -0
  10. package/assets/icons/unicons-index.js +1 -0
  11. package/assets/icons/unicons-index.json +1 -0
  12. package/assets/keybricks-logo.png +0 -0
  13. package/components/_cards/accordion.card.html +32 -0
  14. package/components/_cards/action-chip.card.html +22 -0
  15. package/components/_cards/activity.card.html +34 -0
  16. package/components/_cards/alert.card.html +32 -0
  17. package/components/_cards/app-chrome.card.html +36 -0
  18. package/components/_cards/banner.card.html +21 -0
  19. package/components/_cards/brand-visual.card.html +43 -0
  20. package/components/_cards/breadcrumb.card.html +23 -0
  21. package/components/_cards/button-1-base.card.html +39 -0
  22. package/components/_cards/button-2-states.card.html +56 -0
  23. package/components/_cards/button-3-sizes-icons.card.html +32 -0
  24. package/components/_cards/button-4-group.card.html +47 -0
  25. package/components/_cards/canvas-zoom-controls.card.html +19 -0
  26. package/components/_cards/cards-indicators.card.html +59 -0
  27. package/components/_cards/charts-1-sparkline.card.html +55 -0
  28. package/components/_cards/charts-10-gauge.card.html +31 -0
  29. package/components/_cards/charts-11-funnel.card.html +28 -0
  30. package/components/_cards/charts-12-treemap.card.html +23 -0
  31. package/components/_cards/charts-14-radar.card.html +31 -0
  32. package/components/_cards/charts-15-distribution.card.html +32 -0
  33. package/components/_cards/charts-16-pareto.card.html +25 -0
  34. package/components/_cards/charts-17-candlestick.card.html +34 -0
  35. package/components/_cards/charts-18-sankey.card.html +29 -0
  36. package/components/_cards/charts-19-chord.card.html +31 -0
  37. package/components/_cards/charts-2-line.card.html +46 -0
  38. package/components/_cards/charts-20-sunburst.card.html +38 -0
  39. package/components/_cards/charts-21-worldmap.card.html +33 -0
  40. package/components/_cards/charts-22-gantt.card.html +37 -0
  41. package/components/_cards/charts-23-bar3d.card.html +26 -0
  42. package/components/_cards/charts-24-pie3d.card.html +32 -0
  43. package/components/_cards/charts-25-surface3d.card.html +24 -0
  44. package/components/_cards/charts-26-scatter3d.card.html +24 -0
  45. package/components/_cards/charts-27-ribbon3d.card.html +23 -0
  46. package/components/_cards/charts-3-bar.card.html +71 -0
  47. package/components/_cards/charts-4-barlist.card.html +30 -0
  48. package/components/_cards/charts-5-donut.card.html +35 -0
  49. package/components/_cards/charts-6-scatter.card.html +26 -0
  50. package/components/_cards/charts-7-heatmap.card.html +28 -0
  51. package/components/_cards/charts-8-waterfall.card.html +25 -0
  52. package/components/_cards/charts-9-bullet.card.html +31 -0
  53. package/components/_cards/charts-99-fullpage.card.html +194 -0
  54. package/components/_cards/checkbox.card.html +34 -0
  55. package/components/_cards/codeblock.card.html +19 -0
  56. package/components/_cards/combobox.card.html +25 -0
  57. package/components/_cards/context-menu.card.html +21 -0
  58. package/components/_cards/datatable.card.html +48 -0
  59. package/components/_cards/date-picker.card.html +31 -0
  60. package/components/_cards/diffvalue.card.html +21 -0
  61. package/components/_cards/divider.card.html +24 -0
  62. package/components/_cards/drawer.card.html +30 -0
  63. package/components/_cards/dropdown-menu.card.html +38 -0
  64. package/components/_cards/dropzone.card.html +22 -0
  65. package/components/_cards/empty-state.card.html +29 -0
  66. package/components/_cards/filter-bar.card.html +34 -0
  67. package/components/_cards/icon-button.card.html +27 -0
  68. package/components/_cards/icons-1-core.card.html +49 -0
  69. package/components/_cards/icons-2-feather.card.html +39 -0
  70. package/components/_cards/icons-3-unicons.card.html +44 -0
  71. package/components/_cards/input.card.html +25 -0
  72. package/components/_cards/kbd.card.html +20 -0
  73. package/components/_cards/keyvalue.card.html +23 -0
  74. package/components/_cards/listrow.card.html +30 -0
  75. package/components/_cards/loading.card.html +33 -0
  76. package/components/_cards/log-viewer.card.html +23 -0
  77. package/components/_cards/modal.card.html +35 -0
  78. package/components/_cards/multi-select.card.html +26 -0
  79. package/components/_cards/number-stepper.card.html +24 -0
  80. package/components/_cards/pagination.card.html +25 -0
  81. package/components/_cards/people.card.html +46 -0
  82. package/components/_cards/pipeline-node.card.html +76 -0
  83. package/components/_cards/pipeline-palette.card.html +54 -0
  84. package/components/_cards/search.card.html +23 -0
  85. package/components/_cards/select.card.html +23 -0
  86. package/components/_cards/slider.card.html +25 -0
  87. package/components/_cards/smart-table.card.html +37 -0
  88. package/components/_cards/spreadsheet.card.html +31 -0
  89. package/components/_cards/stepper.card.html +25 -0
  90. package/components/_cards/tabs.card.html +25 -0
  91. package/components/_cards/tag.card.html +26 -0
  92. package/components/_cards/textarea.card.html +27 -0
  93. package/components/_cards/timeline.card.html +32 -0
  94. package/components/_cards/toast.card.html +33 -0
  95. package/components/_cards/toggles.card.html +68 -0
  96. package/components/_cards/tooltip.card.html +22 -0
  97. package/components/_cards/tree.card.html +150 -0
  98. package/components/_shared/frame-theme.js +16 -0
  99. package/components/_shared/src-brand.js +1 -0
  100. package/components/_shared/src-buttons.js +1 -0
  101. package/components/_shared/src-charts.js +1 -0
  102. package/components/_shared/src-data.js +1 -0
  103. package/components/_shared/src-display.js +1 -0
  104. package/components/_shared/src-feedback.js +1 -0
  105. package/components/_shared/src-forms.js +1 -0
  106. package/components/_shared/src-icons.js +1 -0
  107. package/components/_shared/src-navigation.js +1 -0
  108. package/components/_shared/src-pipeline.js +1 -0
  109. package/components/_shared/src-tabs.js +1 -0
  110. package/components/_shared/svg-download.js +19 -0
  111. package/components/_shared/view-source.js +185 -0
  112. package/components/_vue/index.mjs +114 -0
  113. package/components/brand/BrandVisual.d.ts +17 -0
  114. package/components/brand/BrandVisual.jsx +29 -0
  115. package/components/brand/BrandVisual.vue +34 -0
  116. package/components/brand/_dir.card.html +13 -0
  117. package/components/brand/brandMotifs.js +210 -0
  118. package/components/buttons/ActionChip.d.ts +10 -0
  119. package/components/buttons/ActionChip.jsx +20 -0
  120. package/components/buttons/ActionChip.vue +18 -0
  121. package/components/buttons/Button.d.ts +40 -0
  122. package/components/buttons/Button.jsx +101 -0
  123. package/components/buttons/Button.vue +87 -0
  124. package/components/buttons/IconButton.d.ts +26 -0
  125. package/components/buttons/IconButton.jsx +28 -0
  126. package/components/buttons/IconButton.vue +21 -0
  127. package/components/buttons/_dir.card.html +13 -0
  128. package/components/buttons/buttons.prompt.md +19 -0
  129. package/components/charts/Bar3D.d.ts +15 -0
  130. package/components/charts/Bar3D.jsx +93 -0
  131. package/components/charts/Bar3D.vue +79 -0
  132. package/components/charts/BarChart.d.ts +23 -0
  133. package/components/charts/BarChart.jsx +135 -0
  134. package/components/charts/BarChart.vue +139 -0
  135. package/components/charts/BarList.d.ts +13 -0
  136. package/components/charts/BarList.jsx +31 -0
  137. package/components/charts/BarList.vue +25 -0
  138. package/components/charts/BoxPlot.d.ts +18 -0
  139. package/components/charts/BoxPlot.jsx +62 -0
  140. package/components/charts/BoxPlot.vue +58 -0
  141. package/components/charts/BulletChart.d.ts +12 -0
  142. package/components/charts/BulletChart.jsx +41 -0
  143. package/components/charts/BulletChart.vue +33 -0
  144. package/components/charts/CandlestickChart.d.ts +15 -0
  145. package/components/charts/CandlestickChart.jsx +63 -0
  146. package/components/charts/CandlestickChart.vue +62 -0
  147. package/components/charts/ChartKit.d.ts +8 -0
  148. package/components/charts/ChartKit.jsx +76 -0
  149. package/components/charts/ChartKit.vue +47 -0
  150. package/components/charts/ChordChart.d.ts +13 -0
  151. package/components/charts/ChordChart.jsx +55 -0
  152. package/components/charts/ChordChart.vue +54 -0
  153. package/components/charts/DonutChart.d.ts +15 -0
  154. package/components/charts/DonutChart.jsx +73 -0
  155. package/components/charts/DonutChart.vue +61 -0
  156. package/components/charts/FunnelChart.d.ts +11 -0
  157. package/components/charts/FunnelChart.jsx +37 -0
  158. package/components/charts/FunnelChart.vue +29 -0
  159. package/components/charts/GanttChart.d.ts +20 -0
  160. package/components/charts/GanttChart.jsx +80 -0
  161. package/components/charts/GanttChart.vue +60 -0
  162. package/components/charts/GaugeChart.d.ts +13 -0
  163. package/components/charts/GaugeChart.jsx +33 -0
  164. package/components/charts/GaugeChart.vue +29 -0
  165. package/components/charts/HeatmapChart.d.ts +13 -0
  166. package/components/charts/HeatmapChart.jsx +62 -0
  167. package/components/charts/HeatmapChart.vue +38 -0
  168. package/components/charts/Histogram.d.ts +16 -0
  169. package/components/charts/Histogram.jsx +56 -0
  170. package/components/charts/Histogram.vue +53 -0
  171. package/components/charts/LineChart.d.ts +17 -0
  172. package/components/charts/LineChart.jsx +84 -0
  173. package/components/charts/LineChart.vue +86 -0
  174. package/components/charts/ParetoChart.d.ts +13 -0
  175. package/components/charts/ParetoChart.jsx +54 -0
  176. package/components/charts/ParetoChart.vue +55 -0
  177. package/components/charts/Pie3D.d.ts +17 -0
  178. package/components/charts/Pie3D.jsx +145 -0
  179. package/components/charts/Pie3D.vue +115 -0
  180. package/components/charts/RadarChart.d.ts +14 -0
  181. package/components/charts/RadarChart.jsx +79 -0
  182. package/components/charts/RadarChart.vue +73 -0
  183. package/components/charts/Ribbon3D.d.ts +13 -0
  184. package/components/charts/Ribbon3D.jsx +89 -0
  185. package/components/charts/Ribbon3D.vue +79 -0
  186. package/components/charts/SankeyChart.d.ts +15 -0
  187. package/components/charts/SankeyChart.jsx +59 -0
  188. package/components/charts/SankeyChart.vue +53 -0
  189. package/components/charts/Scatter3D.d.ts +12 -0
  190. package/components/charts/Scatter3D.jsx +69 -0
  191. package/components/charts/Scatter3D.vue +59 -0
  192. package/components/charts/ScatterChart.d.ts +12 -0
  193. package/components/charts/ScatterChart.jsx +53 -0
  194. package/components/charts/ScatterChart.vue +57 -0
  195. package/components/charts/Sparkline.d.ts +19 -0
  196. package/components/charts/Sparkline.jsx +63 -0
  197. package/components/charts/Sparkline.vue +54 -0
  198. package/components/charts/SunburstChart.d.ts +12 -0
  199. package/components/charts/SunburstChart.jsx +61 -0
  200. package/components/charts/SunburstChart.vue +60 -0
  201. package/components/charts/Surface3D.d.ts +13 -0
  202. package/components/charts/Surface3D.jsx +70 -0
  203. package/components/charts/Surface3D.vue +63 -0
  204. package/components/charts/TreemapChart.d.ts +11 -0
  205. package/components/charts/TreemapChart.jsx +35 -0
  206. package/components/charts/TreemapChart.vue +27 -0
  207. package/components/charts/WaterfallChart.d.ts +11 -0
  208. package/components/charts/WaterfallChart.jsx +59 -0
  209. package/components/charts/WaterfallChart.vue +46 -0
  210. package/components/charts/WorldMap.d.ts +21 -0
  211. package/components/charts/WorldMap.jsx +107 -0
  212. package/components/charts/WorldMap.vue +73 -0
  213. package/components/charts/_dir.card.html +7 -0
  214. package/components/charts/chart-3d.js +84 -0
  215. package/components/charts/chart-geometry.js +223 -0
  216. package/components/charts/charts.prompt.md +24 -0
  217. package/components/data/CodeBlock.d.ts +9 -0
  218. package/components/data/CodeBlock.jsx +19 -0
  219. package/components/data/CodeBlock.vue +22 -0
  220. package/components/data/DataTable.d.ts +28 -0
  221. package/components/data/DataTable.jsx +32 -0
  222. package/components/data/DataTable.vue +25 -0
  223. package/components/data/DiffValue.d.ts +11 -0
  224. package/components/data/DiffValue.jsx +15 -0
  225. package/components/data/DiffValue.vue +13 -0
  226. package/components/data/FilterBar.d.ts +16 -0
  227. package/components/data/FilterBar.jsx +22 -0
  228. package/components/data/FilterBar.vue +23 -0
  229. package/components/data/KeyValue.d.ts +16 -0
  230. package/components/data/KeyValue.jsx +25 -0
  231. package/components/data/KeyValue.vue +26 -0
  232. package/components/data/ListRow.d.ts +14 -0
  233. package/components/data/ListRow.jsx +25 -0
  234. package/components/data/ListRow.vue +25 -0
  235. package/components/data/Pagination.d.ts +12 -0
  236. package/components/data/Pagination.jsx +27 -0
  237. package/components/data/Pagination.vue +24 -0
  238. package/components/data/SmartTable.d.ts +30 -0
  239. package/components/data/SmartTable.jsx +73 -0
  240. package/components/data/SmartTable.vue +74 -0
  241. package/components/data/Spreadsheet.d.ts +33 -0
  242. package/components/data/Spreadsheet.jsx +110 -0
  243. package/components/data/Spreadsheet.vue +95 -0
  244. package/components/data/_dir.card.html +13 -0
  245. package/components/data/data.prompt.md +33 -0
  246. package/components/display/Avatar.d.ts +21 -0
  247. package/components/display/Avatar.jsx +31 -0
  248. package/components/display/Avatar.vue +34 -0
  249. package/components/display/Badge.d.ts +27 -0
  250. package/components/display/Badge.jsx +40 -0
  251. package/components/display/Badge.vue +47 -0
  252. package/components/display/Card.d.ts +27 -0
  253. package/components/display/Card.jsx +27 -0
  254. package/components/display/Card.vue +28 -0
  255. package/components/display/Divider.d.ts +8 -0
  256. package/components/display/Divider.jsx +14 -0
  257. package/components/display/Divider.vue +13 -0
  258. package/components/display/Kbd.d.ts +7 -0
  259. package/components/display/Kbd.jsx +12 -0
  260. package/components/display/Kbd.vue +9 -0
  261. package/components/display/ProgressBar.d.ts +42 -0
  262. package/components/display/ProgressBar.jsx +70 -0
  263. package/components/display/ProgressBar.vue +69 -0
  264. package/components/display/Tag.d.ts +9 -0
  265. package/components/display/Tag.jsx +15 -0
  266. package/components/display/Tag.vue +15 -0
  267. package/components/display/_dir.card.html +13 -0
  268. package/components/display/display.prompt.md +30 -0
  269. package/components/feedback/Accordion.d.ts +13 -0
  270. package/components/feedback/Accordion.jsx +21 -0
  271. package/components/feedback/Accordion.vue +22 -0
  272. package/components/feedback/ActivityItem.d.ts +25 -0
  273. package/components/feedback/ActivityItem.jsx +39 -0
  274. package/components/feedback/ActivityItem.vue +46 -0
  275. package/components/feedback/Alert.d.ts +36 -0
  276. package/components/feedback/Alert.jsx +48 -0
  277. package/components/feedback/Alert.vue +59 -0
  278. package/components/feedback/Banner.d.ts +15 -0
  279. package/components/feedback/Banner.jsx +25 -0
  280. package/components/feedback/Banner.vue +25 -0
  281. package/components/feedback/ContextMenu.d.ts +8 -0
  282. package/components/feedback/ContextMenu.jsx +18 -0
  283. package/components/feedback/ContextMenu.vue +19 -0
  284. package/components/feedback/Drawer.d.ts +18 -0
  285. package/components/feedback/Drawer.jsx +26 -0
  286. package/components/feedback/Drawer.vue +24 -0
  287. package/components/feedback/Menu.d.ts +10 -0
  288. package/components/feedback/Menu.jsx +24 -0
  289. package/components/feedback/Menu.vue +21 -0
  290. package/components/feedback/Modal.d.ts +38 -0
  291. package/components/feedback/Modal.jsx +69 -0
  292. package/components/feedback/Modal.vue +65 -0
  293. package/components/feedback/Stepper.d.ts +9 -0
  294. package/components/feedback/Stepper.jsx +24 -0
  295. package/components/feedback/Stepper.vue +18 -0
  296. package/components/feedback/Timeline.d.ts +15 -0
  297. package/components/feedback/Timeline.jsx +27 -0
  298. package/components/feedback/Timeline.vue +21 -0
  299. package/components/feedback/_dir.card.html +13 -0
  300. package/components/feedback/feedback.prompt.md +35 -0
  301. package/components/forms/Checkbox.d.ts +13 -0
  302. package/components/forms/Checkbox.jsx +17 -0
  303. package/components/forms/Checkbox.vue +18 -0
  304. package/components/forms/Combobox.d.ts +13 -0
  305. package/components/forms/Combobox.jsx +34 -0
  306. package/components/forms/Combobox.vue +35 -0
  307. package/components/forms/DatePicker.d.ts +12 -0
  308. package/components/forms/DatePicker.jsx +48 -0
  309. package/components/forms/DatePicker.vue +46 -0
  310. package/components/forms/Dropzone.d.ts +20 -0
  311. package/components/forms/Dropzone.jsx +36 -0
  312. package/components/forms/Dropzone.vue +28 -0
  313. package/components/forms/Field.d.ts +13 -0
  314. package/components/forms/Field.jsx +13 -0
  315. package/components/forms/Field.vue +12 -0
  316. package/components/forms/Input.d.ts +18 -0
  317. package/components/forms/Input.jsx +35 -0
  318. package/components/forms/Input.vue +38 -0
  319. package/components/forms/MultiSelect.d.ts +14 -0
  320. package/components/forms/MultiSelect.jsx +33 -0
  321. package/components/forms/MultiSelect.vue +36 -0
  322. package/components/forms/NumberStepper.d.ts +13 -0
  323. package/components/forms/NumberStepper.jsx +15 -0
  324. package/components/forms/NumberStepper.vue +17 -0
  325. package/components/forms/Radio.vue +16 -0
  326. package/components/forms/RadioGroup.vue +11 -0
  327. package/components/forms/SearchInput.d.ts +12 -0
  328. package/components/forms/SearchInput.jsx +17 -0
  329. package/components/forms/SearchInput.vue +14 -0
  330. package/components/forms/Select.d.ts +14 -0
  331. package/components/forms/Select.jsx +17 -0
  332. package/components/forms/Select.vue +16 -0
  333. package/components/forms/Slider.d.ts +15 -0
  334. package/components/forms/Slider.jsx +21 -0
  335. package/components/forms/Slider.vue +23 -0
  336. package/components/forms/Switch.d.ts +31 -0
  337. package/components/forms/Switch.jsx +40 -0
  338. package/components/forms/Switch.vue +16 -0
  339. package/components/forms/_dir.card.html +13 -0
  340. package/components/forms/forms.prompt.md +23 -0
  341. package/components/icons/Icon.d.ts +19 -0
  342. package/components/icons/Icon.jsx +93 -0
  343. package/components/icons/Icon.prompt.md +8 -0
  344. package/components/icons/Icon.vue +12 -0
  345. package/components/icons/Unicon.d.ts +12 -0
  346. package/components/icons/Unicon.jsx +16 -0
  347. package/components/icons/Unicon.vue +15 -0
  348. package/components/icons/_dir.card.html +13 -0
  349. package/components/icons/feather-paths.js +2 -0
  350. package/components/icons/icon-paths.js +73 -0
  351. package/components/index.d.ts +87 -0
  352. package/components/index.js +110 -0
  353. package/components/navigation/Breadcrumb.d.ts +24 -0
  354. package/components/navigation/Breadcrumb.jsx +120 -0
  355. package/components/navigation/Breadcrumb.vue +94 -0
  356. package/components/navigation/DocTree.d.ts +18 -0
  357. package/components/navigation/DocTree.jsx +37 -0
  358. package/components/navigation/DocTree.vue +25 -0
  359. package/components/navigation/Sidebar.d.ts +29 -0
  360. package/components/navigation/Sidebar.jsx +75 -0
  361. package/components/navigation/Sidebar.vue +54 -0
  362. package/components/navigation/TopBar.d.ts +27 -0
  363. package/components/navigation/TopBar.jsx +44 -0
  364. package/components/navigation/TopBar.vue +51 -0
  365. package/components/navigation/Tree.d.ts +83 -0
  366. package/components/navigation/Tree.jsx +347 -0
  367. package/components/navigation/Tree.vue +258 -0
  368. package/components/navigation/_dir.card.html +13 -0
  369. package/components/navigation/navigation.prompt.md +22 -0
  370. package/components/pipeline/ConfigPanel.d.ts +18 -0
  371. package/components/pipeline/ConfigPanel.jsx +30 -0
  372. package/components/pipeline/ConfigPanel.vue +32 -0
  373. package/components/pipeline/DataPreview.d.ts +14 -0
  374. package/components/pipeline/DataPreview.jsx +24 -0
  375. package/components/pipeline/DataPreview.vue +21 -0
  376. package/components/pipeline/NodeCard.d.ts +47 -0
  377. package/components/pipeline/NodeCard.jsx +97 -0
  378. package/components/pipeline/NodeCard.vue +75 -0
  379. package/components/pipeline/PaletteItem.vue +15 -0
  380. package/components/pipeline/PaletteListItem.vue +15 -0
  381. package/components/pipeline/PalettePanel.d.ts +20 -0
  382. package/components/pipeline/PalettePanel.jsx +74 -0
  383. package/components/pipeline/PalettePanel.vue +45 -0
  384. package/components/pipeline/PipelineCanvas.d.ts +25 -0
  385. package/components/pipeline/PipelineCanvas.jsx +94 -0
  386. package/components/pipeline/PipelineCanvas.vue +73 -0
  387. package/components/pipeline/ZoomControls.d.ts +9 -0
  388. package/components/pipeline/ZoomControls.jsx +15 -0
  389. package/components/pipeline/ZoomControls.vue +15 -0
  390. package/components/pipeline/_dir.card.html +13 -0
  391. package/components/pipeline/pipeline.prompt.md +22 -0
  392. package/components/tabs/SegmentedControl.d.ts +11 -0
  393. package/components/tabs/SegmentedControl.jsx +21 -0
  394. package/components/tabs/SegmentedControl.vue +15 -0
  395. package/components/tabs/Tabs.d.ts +13 -0
  396. package/components/tabs/Tabs.jsx +52 -0
  397. package/components/tabs/Tabs.vue +39 -0
  398. package/components/tabs/ViewToggle.d.ts +8 -0
  399. package/components/tabs/ViewToggle.jsx +12 -0
  400. package/components/tabs/ViewToggle.vue +12 -0
  401. package/components/tabs/_dir.card.html +13 -0
  402. package/components/tabs/tabs.prompt.md +14 -0
  403. package/package.json +76 -0
  404. package/readme.md +150 -0
  405. package/styles.css +10 -0
  406. package/tokens/alpha.css +27 -0
  407. package/tokens/charts.css +55 -0
  408. package/tokens/colors-extended.css +40 -0
  409. package/tokens/colors.css +39 -0
  410. package/tokens/dark.css +96 -0
  411. package/tokens/fonts.css +4 -0
  412. package/tokens/interaction.css +48 -0
  413. package/tokens/layout.css +30 -0
  414. package/tokens/motion.css +22 -0
  415. package/tokens/tokens.d.ts +680 -0
  416. package/tokens/tokens.js +1018 -0
  417. package/tokens/tokens.json +2928 -0
  418. package/tokens/typography.css +22 -0
@@ -0,0 +1,120 @@
1
+ import React from "react";
2
+ import { Icon } from "../icons/Icon.jsx";
3
+
4
+ function Crumb({ label, last, hovered, onSelect }) {
5
+ const [hover, setHover] = React.useState(false);
6
+ const on = (hover || hovered) && !last;
7
+ return (
8
+ <span role={last ? undefined : "button"} tabIndex={last ? undefined : 0}
9
+ onClick={() => !last && onSelect && onSelect(label)}
10
+ onKeyDown={(e) => { if (!last && (e.key === "Enter" || e.key === " ")) { e.preventDefault(); onSelect && onSelect(label); } }}
11
+ onMouseEnter={() => setHover(true)} onMouseLeave={() => setHover(false)}
12
+ style={{ fontFamily: "var(--font-sans)", fontSize: "var(--text-sm)", lineHeight: "var(--leading-sm)", color: last || on ? "var(--text-heading)" : "var(--text-secondary)", fontWeight: last ? "var(--weight-medium)" : "var(--weight-regular)", cursor: last ? "default" : "pointer", borderRadius: "var(--radius-sm)", transition: "var(--t-hover)" }}>{label}</span>
13
+ );
14
+ }
15
+
16
+ function Sep() {
17
+ return <span style={{ color: "var(--text-muted)", display: "inline-flex" }}><Icon name="chevron-right" size={13} /></span>;
18
+ }
19
+
20
+ /** Overflow crumb: an ellipsis button that drops down the levels hidden by collapsing. */
21
+ function Overflow({ items, onSelect }) {
22
+ const [open, setOpen] = React.useState(false);
23
+ const [hover, setHover] = React.useState(false);
24
+ const root = React.useRef(null);
25
+ React.useEffect(() => {
26
+ if (!open) return;
27
+ const h = (e) => { if (root.current && !root.current.contains(e.target)) setOpen(false); };
28
+ document.addEventListener("mousedown", h);
29
+ return () => document.removeEventListener("mousedown", h);
30
+ }, [open]);
31
+ return (
32
+ <span ref={root} style={{ position: "relative", display: "inline-flex" }}>
33
+ <span role="button" tabIndex={0} aria-label={`Show ${items.length} hidden levels`} aria-expanded={open}
34
+ onClick={() => setOpen(!open)}
35
+ onKeyDown={(e) => { if (e.key === "Enter" || e.key === " ") { e.preventDefault(); setOpen(!open); } if (e.key === "Escape") setOpen(false); }}
36
+ onMouseEnter={() => setHover(true)} onMouseLeave={() => setHover(false)}
37
+ style={{ display: "inline-flex", alignItems: "center", justifyContent: "center", width: 20, height: 18, borderRadius: "var(--radius-sm)", cursor: "pointer", color: open || hover ? "var(--text-heading)" : "var(--text-muted)", background: open ? "var(--bg-active)" : hover ? "var(--bg-hover)" : "transparent", transition: "var(--t-hover)" }}>
38
+ <Icon name="ellipsis" size={14} />
39
+ </span>
40
+ {open ? (
41
+ <span style={{ position: "absolute", top: "calc(100% + 5px)", left: 0, zIndex: "var(--z-menu)", minWidth: 168, maxWidth: 260, background: "var(--bg-surface)", border: "1px solid var(--border-card)", borderRadius: "var(--radius-md)", boxShadow: "var(--shadow-menu)", padding: 4, display: "flex", flexDirection: "column" }}>
42
+ {items.map((it, i) => <OverflowItem key={it} label={it} depth={i} onSelect={(l) => { setOpen(false); onSelect && onSelect(l); }} />)}
43
+ </span>
44
+ ) : null}
45
+ </span>
46
+ );
47
+ }
48
+
49
+ function OverflowItem({ label, depth, onSelect }) {
50
+ const [hover, setHover] = React.useState(false);
51
+ return (
52
+ <span role="menuitem" tabIndex={0} onClick={() => onSelect(label)}
53
+ onKeyDown={(e) => { if (e.key === "Enter" || e.key === " ") { e.preventDefault(); onSelect(label); } }}
54
+ onMouseEnter={() => setHover(true)} onMouseLeave={() => setHover(false)}
55
+ style={{ display: "flex", alignItems: "center", gap: 6, padding: "6px 9px", paddingLeft: 9 + depth * 12, borderRadius: "var(--radius-sm)", cursor: "pointer", background: hover ? "var(--bg-hover)" : "transparent", fontFamily: "var(--font-sans)", fontSize: "var(--text-sm)", lineHeight: "var(--leading-sm)", color: "var(--text-heading)", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis", transition: "var(--t-hover)" }}>
56
+ {depth > 0 ? <span style={{ color: "var(--text-muted)", display: "inline-flex", flexShrink: 0 }}><Icon name="chevron-right" size={11} /></span> : null}
57
+ {label}
58
+ </span>
59
+ );
60
+ }
61
+
62
+ /** Breadcrumb trail — 12px, chevron separators, last crumb in heading color. Clickable crumbs darken on hover and carry press + keyboard focus from the global interaction layer. Trails longer than `maxItems` collapse to first · … · last two, with the hidden levels in a dropdown on the ellipsis. */
63
+ export function Breadcrumb({ items = [], onSelect, maxItems = 4, hoveredIndex, style }) {
64
+ const collapse = items.length > maxItems && maxItems >= 3;
65
+ const tailCount = maxItems - 2;
66
+ const head = collapse ? items.slice(0, 1) : items;
67
+ const hidden = collapse ? items.slice(1, items.length - tailCount) : [];
68
+ const tail = collapse ? items.slice(items.length - tailCount) : [];
69
+ const lastLabel = items[items.length - 1];
70
+ return (
71
+ <nav style={{ display: "flex", alignItems: "center", gap: 4, ...style }}>
72
+ {head.map((it, i) => (
73
+ <React.Fragment key={it}>
74
+ {i > 0 ? <Sep /> : null}
75
+ <Crumb label={it} last={it === lastLabel} hovered={hoveredIndex === i} onSelect={onSelect} />
76
+ </React.Fragment>
77
+ ))}
78
+ {collapse ? (
79
+ <React.Fragment>
80
+ <Sep />
81
+ <Overflow items={hidden} onSelect={onSelect} />
82
+ {tail.map((it) => (
83
+ <React.Fragment key={it}>
84
+ <Sep />
85
+ <Crumb label={it} last={it === lastLabel} onSelect={onSelect} />
86
+ </React.Fragment>
87
+ ))}
88
+ </React.Fragment>
89
+ ) : null}
90
+ </nav>
91
+ );
92
+ }
93
+
94
+ /** Theme toggle — flips <html data-theme> and persists to localStorage("kb-theme"). Pass `dark`+`onToggle` to control it externally. */
95
+ export function ThemeToggle({ size = 34, dark: darkProp, onToggle, style }) {
96
+ const controlled = darkProp != null;
97
+ const [darkState, setDark] = React.useState(() => (typeof document !== "undefined" && document.documentElement.dataset.theme === "dark"));
98
+ const dark = controlled ? darkProp : darkState;
99
+ React.useEffect(() => {
100
+ if (controlled || typeof document === "undefined") return;
101
+ document.documentElement.dataset.theme = dark ? "dark" : "light";
102
+ try { localStorage.setItem("kb-theme", dark ? "dark" : "light"); } catch (e) {}
103
+ }, [dark, controlled]);
104
+ const [hover, setHover] = React.useState(false);
105
+ return (
106
+ <button type="button" aria-label={dark ? "Switch to light mode" : "Switch to dark mode"} onClick={() => (controlled ? onToggle && onToggle(!dark) : setDark(!dark))}
107
+ onMouseEnter={() => setHover(true)} onMouseLeave={() => setHover(false)}
108
+ style={{ width: size, height: size, borderRadius: "var(--radius-md)", border: "none", cursor: "pointer", display: "inline-flex", alignItems: "center", justifyContent: "center", background: hover ? "var(--bg-hover)" : "transparent", color: "var(--text-body)", padding: 0, transition: "var(--t-hover)", ...style }}>
109
+ <Icon name={dark ? "sparkles" : "moon"} size={18} />
110
+ </button>
111
+ );
112
+ }
113
+
114
+ /** Reads the persisted theme and applies it before first paint. Call once at app start. */
115
+ export function applyStoredTheme() {
116
+ if (typeof document === "undefined") return;
117
+ let t = "light";
118
+ try { t = localStorage.getItem("kb-theme") || "light"; } catch (e) {}
119
+ document.documentElement.dataset.theme = t;
120
+ }
@@ -0,0 +1,94 @@
1
+ <script setup>
2
+ import { ref, computed, watch, onUnmounted } from 'vue'
3
+ import Icon from '../icons/Icon.vue'
4
+ // Breadcrumb trail — 12px, chevron separators, last crumb in heading color.
5
+ // Clickable crumbs darken on hover (no underline) and carry press + keyboard focus from the global interaction layer.
6
+ // Trails longer than maxItems collapse to first · … · last two, with the hidden levels in a dropdown on the ellipsis.
7
+ const props = defineProps({ items: { type: Array, default: () => [] }, maxItems: { type: Number, default: 4 }, hoveredIndex: { type: Number, default: null }, style: Object })
8
+ const emit = defineEmits(['select'])
9
+ const hover = ref(-1)
10
+ const ovHover = ref(false)
11
+ const menuHover = ref(-1)
12
+ const open = ref(false)
13
+ const root = ref(null)
14
+ const collapse = computed(() => props.items.length > props.maxItems && props.maxItems >= 3)
15
+ const tailCount = computed(() => props.maxItems - 2)
16
+ const head = computed(() => collapse.value ? props.items.slice(0, 1) : props.items)
17
+ const hidden = computed(() => collapse.value ? props.items.slice(1, props.items.length - tailCount.value) : [])
18
+ const tail = computed(() => collapse.value ? props.items.slice(props.items.length - tailCount.value) : [])
19
+ const lastLabel = computed(() => props.items[props.items.length - 1])
20
+ const isLast = (it) => it === lastLabel.value
21
+ const on = (i, it) => (hover.value === i || props.hoveredIndex === i) && !isLast(it)
22
+ function pick(it) { if (!isLast(it)) emit('select', it) }
23
+ function pickHidden(it) { open.value = false; emit('select', it) }
24
+ function onDoc(e) { if (root.value && !root.value.contains(e.target)) open.value = false }
25
+ watch(open, (v) => { if (v) document.addEventListener('mousedown', onDoc); else document.removeEventListener('mousedown', onDoc) })
26
+ onUnmounted(() => document.removeEventListener('mousedown', onDoc))
27
+ const crumbStyle = (i, it) => ({ fontFamily: 'var(--font-sans)', fontSize: 'var(--text-sm)', lineHeight: 'var(--leading-sm)', color: isLast(it) || on(i, it) ? 'var(--text-heading)' : 'var(--text-secondary)', fontWeight: isLast(it) ? 'var(--weight-medium)' : 'var(--weight-regular)', cursor: isLast(it) ? 'default' : 'pointer', borderRadius: 'var(--radius-sm)', transition: 'var(--t-hover)' })
28
+ </script>
29
+ <template>
30
+ <nav :style="{ display: 'flex', alignItems: 'center', gap: 4, ...style }">
31
+ <template v-for="(it, i) in head" :key="it">
32
+ <span v-if="i > 0" style="color:var(--text-muted);display:inline-flex"><Icon name="chevron-right" :size="13" /></span>
33
+ <span :role="isLast(it) ? undefined : 'button'" :tabindex="isLast(it) ? undefined : 0"
34
+ @click="pick(it)" @keydown.enter.prevent="pick(it)" @keydown.space.prevent="pick(it)"
35
+ @mouseenter="hover = i" @mouseleave="hover = -1" :style="crumbStyle(i, it)">{{ it }}</span>
36
+ </template>
37
+ <template v-if="collapse">
38
+ <span style="color:var(--text-muted);display:inline-flex"><Icon name="chevron-right" :size="13" /></span>
39
+ <span ref="root" style="position:relative;display:inline-flex">
40
+ <span role="button" tabindex="0" :aria-label="`Show ${hidden.length} hidden levels`" :aria-expanded="open"
41
+ @click="open = !open" @keydown.enter.prevent="open = !open" @keydown.space.prevent="open = !open" @keydown.esc="open = false"
42
+ @mouseenter="ovHover = true" @mouseleave="ovHover = false"
43
+ :style="{ display: 'inline-flex', alignItems: 'center', justifyContent: 'center', width: '20px', height: '18px', borderRadius: 'var(--radius-sm)', cursor: 'pointer', color: open || ovHover ? 'var(--text-heading)' : 'var(--text-muted)', background: open ? 'var(--bg-active)' : ovHover ? 'var(--bg-hover)' : 'transparent', transition: 'var(--t-hover)' }">
44
+ <Icon name="ellipsis" :size="14" />
45
+ </span>
46
+ <span v-if="open" style="position:absolute;top:calc(100% + 5px);left:0;z-index:var(--z-menu);min-width:168px;max-width:260px;background:var(--bg-surface);border:1px solid var(--border-card);border-radius:var(--radius-md);box-shadow:var(--shadow-menu);padding:4px;display:flex;flex-direction:column">
47
+ <span v-for="(h, hi) in hidden" :key="h" role="menuitem" tabindex="0"
48
+ @click="pickHidden(h)" @keydown.enter.prevent="pickHidden(h)" @keydown.space.prevent="pickHidden(h)"
49
+ @mouseenter="menuHover = hi" @mouseleave="menuHover = -1"
50
+ :style="{ display: 'flex', alignItems: 'center', gap: '6px', padding: '6px 9px', paddingLeft: (9 + hi * 12) + 'px', borderRadius: 'var(--radius-sm)', cursor: 'pointer', background: menuHover === hi ? 'var(--bg-hover)' : 'transparent', fontFamily: 'var(--font-sans)', fontSize: 'var(--text-sm)', lineHeight: 'var(--leading-sm)', color: 'var(--text-heading)', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis', transition: 'var(--t-hover)' }">
51
+ <span v-if="hi > 0" style="color:var(--text-muted);display:inline-flex;flex-shrink:0"><Icon name="chevron-right" :size="11" /></span>{{ h }}
52
+ </span>
53
+ </span>
54
+ </span>
55
+ <template v-for="it in tail" :key="it">
56
+ <span style="color:var(--text-muted);display:inline-flex"><Icon name="chevron-right" :size="13" /></span>
57
+ <span :role="isLast(it) ? undefined : 'button'" :tabindex="isLast(it) ? undefined : 0"
58
+ @click="pick(it)" @keydown.enter.prevent="pick(it)" @keydown.space.prevent="pick(it)"
59
+ :style="crumbStyle(-1, it)">{{ it }}</span>
60
+ </template>
61
+ </template>
62
+ </nav>
63
+ </template>
64
+
65
+ <!-- ThemeToggle — flips <html data-theme> and persists to localStorage("kb-theme"). Pass `dark` (v-model) to control it externally. -->
66
+ <!--
67
+ <script setup name="ThemeToggle">
68
+ import { ref, computed, watch, onMounted } from 'vue'
69
+ import Icon from '../icons/Icon.vue'
70
+ const props = defineProps({ size: { type: Number, default: 34 }, dark: { type: Boolean, default: null }, style: Object })
71
+ const emit = defineEmits(['update:dark'])
72
+ const darkState = ref(false)
73
+ const dark = computed(() => props.dark != null ? props.dark : darkState.value)
74
+ const hover = ref(false)
75
+ onMounted(() => { darkState.value = document.documentElement.dataset.theme === 'dark' })
76
+ watch(dark, (v) => { if (props.dark != null) return; document.documentElement.dataset.theme = v ? 'dark' : 'light'; try { localStorage.setItem('kb-theme', v ? 'dark' : 'light') } catch (e) {} })
77
+ function toggle() { if (props.dark != null) emit('update:dark', !dark.value); else darkState.value = !darkState.value }
78
+ </script>
79
+ <template>
80
+ <button type="button" :aria-label="dark ? 'Switch to light mode' : 'Switch to dark mode'" @click="toggle" @mouseenter="hover = true" @mouseleave="hover = false"
81
+ :style="{ width: size, height: size, borderRadius: 'var(--radius-md)', border: 'none', cursor: 'pointer', display: 'inline-flex', alignItems: 'center', justifyContent: 'center', background: hover ? 'var(--bg-hover)' : 'transparent', color: 'var(--text-body)', padding: 0, transition: 'var(--t-hover)', ...style }">
82
+ <Icon :name="dark ? 'sparkles' : 'moon'" :size="18" />
83
+ </button>
84
+ </template>
85
+ -->
86
+
87
+ <!-- applyStoredTheme() — reads the persisted theme and applies it before first paint. Call once at app start (main.js): -->
88
+ <!--
89
+ export function applyStoredTheme() {
90
+ let t = 'light'
91
+ try { t = localStorage.getItem('kb-theme') || 'light' } catch (e) {}
92
+ document.documentElement.dataset.theme = t
93
+ }
94
+ -->
@@ -0,0 +1,18 @@
1
+ import * as React from "react";
2
+ /** Secondary 240px documents panel: header, search, 30px tree rows with hued doc icons. */
3
+ export interface DocTreeItem {
4
+ label: string;
5
+ kind?: "folder" | "doc";
6
+ /** Doc icon hue: orange | green | purple | blue | teal | gray */
7
+ hue?: string;
8
+ /** Override glyph */
9
+ icon?: string;
10
+ }
11
+ export interface DocTreeProps {
12
+ title?: string;
13
+ items?: DocTreeItem[];
14
+ active?: string;
15
+ onSelect?: (label: string) => void;
16
+ style?: React.CSSProperties;
17
+ }
18
+ export declare function DocTree(props: DocTreeProps): JSX.Element;
@@ -0,0 +1,37 @@
1
+ import React from "react";
2
+ import { Icon } from "../icons/Icon.jsx";
3
+ import { IconButton } from "../buttons/IconButton.jsx";
4
+ import { SearchInput } from "../forms/SearchInput.jsx";
5
+
6
+ const docHues = { orange: "var(--cat-transform)", green: "var(--cat-source)", purple: "var(--cat-merge)", blue: "var(--info-fg)", teal: "var(--cat-output)", gray: "var(--text-muted)" };
7
+
8
+ /** Secondary documents panel — 240px: title header, search row, 30px tree items. items: [{label, kind:"folder"|"doc", hue, icon}]. */
9
+ export function DocTree({ title = "Documents", items = [], active, onSelect, style }) {
10
+ return (
11
+ <div style={{ width: "var(--sidebar-w)", background: "var(--bg-surface)", borderRight: "1px solid var(--border-card)", display: "flex", flexDirection: "column", boxSizing: "border-box", flexShrink: 0, ...style }}>
12
+ <div style={{ height: "var(--topbar-h)", borderBottom: "1px solid var(--border-card)", display: "flex", alignItems: "center", justifyContent: "space-between", padding: "0 12px 0 16px", boxSizing: "border-box", flexShrink: 0 }}>
13
+ <span style={{ fontFamily: "var(--font-sans)", fontWeight: "var(--weight-medium)", fontSize: "var(--text-md)", lineHeight: "var(--leading-md)", letterSpacing: "var(--tracking-md)", color: "var(--text-heading)" }}>{title}</span>
14
+ <IconButton icon="chevron-right" size="md" muted />
15
+ </div>
16
+ <div style={{ padding: "12px 16px 8px", borderBottom: "1px solid var(--border-subtle)" }}>
17
+ <SearchInput bare placeholder="Search..." style={{ gap: 8 }} />
18
+ </div>
19
+ <div style={{ padding: 8, display: "flex", flexDirection: "column", gap: 2, overflowY: "auto" }}>
20
+ {items.map((it) => {
21
+ const is = active === it.label;
22
+ return (
23
+ <div key={it.label} role="treeitem" tabIndex={0} onClick={() => onSelect && onSelect(it.label)}
24
+ style={{ height: "var(--h-tree-item)", borderRadius: "var(--radius-md)", display: "flex", alignItems: "center", gap: 8, padding: "6px 8px", boxSizing: "border-box", cursor: "pointer", background: is ? "var(--bg-active)" : "transparent" }}
25
+ onMouseEnter={(e) => { if (!is) e.currentTarget.style.background = "var(--bg-hover)"; }}
26
+ onMouseLeave={(e) => { if (!is) e.currentTarget.style.background = "transparent"; }}>
27
+ <span style={{ color: it.kind === "folder" ? "var(--text-muted)" : docHues[it.hue || "gray"], display: "inline-flex" }}>
28
+ <Icon name={it.icon || (it.kind === "folder" ? "folder" : "file-text")} size={16} />
29
+ </span>
30
+ <span style={{ fontFamily: "var(--font-sans)", fontSize: "var(--text-sm)", lineHeight: "var(--leading-sm)", color: "var(--text-heading)", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{it.label}</span>
31
+ </div>
32
+ );
33
+ })}
34
+ </div>
35
+ </div>
36
+ );
37
+ }
@@ -0,0 +1,25 @@
1
+ <script setup>
2
+ import Icon from '../icons/Icon.vue'
3
+ import IconButton from '../buttons/IconButton.vue'
4
+ import SearchInput from '../forms/SearchInput.vue'
5
+ const docHues = { orange: 'var(--cat-transform)', green: 'var(--cat-source)', purple: 'var(--cat-merge)', blue: 'var(--info-fg)', teal: 'var(--cat-output)', gray: 'var(--text-muted)' }
6
+ // Secondary documents panel — 240px: title header, search row, 30px tree items. items: [{label, kind:"folder"|"doc", hue, icon}].
7
+ defineProps({ title: { type: String, default: 'Documents' }, items: { type: Array, default: () => [] }, active: String, style: Object })
8
+ const emit = defineEmits(['select'])
9
+ </script>
10
+ <template>
11
+ <div :style="{ width: 'var(--sidebar-w)', background: 'var(--bg-surface)', borderRight: '1px solid var(--border-card)', display: 'flex', flexDirection: 'column', boxSizing: 'border-box', flexShrink: 0, ...style }">
12
+ <div style="height:var(--topbar-h);border-bottom:1px solid var(--border-card);display:flex;align-items:center;justify-content:space-between;padding:0 12px 0 16px;box-sizing:border-box;flex-shrink:0">
13
+ <span style="font-family:var(--font-sans);font-weight:var(--weight-medium);font-size:var(--text-md);line-height:var(--leading-md);letter-spacing:var(--tracking-md);color:var(--text-heading)">{{ title }}</span>
14
+ <IconButton icon="chevron-right" size="md" muted />
15
+ </div>
16
+ <div style="padding:12px 16px 8px;border-bottom:1px solid var(--border-subtle)"><SearchInput bare placeholder="Search..." style="gap:8px" /></div>
17
+ <div style="padding:8px;display:flex;flex-direction:column;gap:2px;overflow-y:auto">
18
+ <div v-for="it in items" :key="it.label" @click="emit('select', it.label)"
19
+ :style="{ height: 'var(--h-tree-item)', borderRadius: 'var(--radius-md)', display: 'flex', alignItems: 'center', gap: 8, padding: '6px 8px', boxSizing: 'border-box', cursor: 'pointer', background: active === it.label ? 'var(--bg-active)' : 'transparent' }">
20
+ <span :style="{ color: it.kind === 'folder' ? 'var(--text-muted)' : docHues[it.hue || 'gray'], display: 'inline-flex' }"><Icon :name="it.icon || (it.kind === 'folder' ? 'folder' : 'file-text')" :size="16" /></span>
21
+ <span style="font-family:var(--font-sans);font-size:var(--text-sm);line-height:var(--leading-sm);color:var(--text-heading);white-space:nowrap;overflow:hidden;text-overflow:ellipsis">{{ it.label }}</span>
22
+ </div>
23
+ </div>
24
+ </div>
25
+ </template>
@@ -0,0 +1,29 @@
1
+ import * as React from "react";
2
+ /**
3
+ * App sidebar — 240px expanded / 64px icon rail. Logo header, nav, expandable sections, pinned footer.
4
+ * @startingPoint section="Chrome" subtitle="240px app sidebar with icon-rail collapse" viewport="240x600"
5
+ */
6
+ export interface SidebarItem {
7
+ icon: string;
8
+ label: string;
9
+ children?: SidebarItem[];
10
+ /** Expand this section initially */
11
+ open?: boolean;
12
+ }
13
+ export interface SidebarProps {
14
+ items?: SidebarItem[];
15
+ footerItems?: SidebarItem[];
16
+ /** Active item label */
17
+ active?: string;
18
+ onSelect?: (label: string) => void;
19
+ collapsed?: boolean;
20
+ /** Renders the "Collapse" item */
21
+ onToggleCollapse?: () => void;
22
+ logo?: string;
23
+ brand?: string;
24
+ height?: number | string;
25
+ style?: React.CSSProperties;
26
+ }
27
+ export declare function Sidebar(props: SidebarProps): JSX.Element;
28
+ /** The product's real nav model. */
29
+ export declare const KEYBRICKS_NAV: SidebarItem[];
@@ -0,0 +1,75 @@
1
+ import React from "react";
2
+ import { Icon } from "../icons/Icon.jsx";
3
+
4
+ function NavItem({ icon, label, active, indent, collapsed, badge, onClick }) {
5
+ const [hover, setHover] = React.useState(false);
6
+ return (
7
+ <div role="button" tabIndex={0} onClick={onClick} onMouseEnter={() => setHover(true)} onMouseLeave={() => setHover(false)}
8
+ style={{ height: indent ? "var(--h-subnav-item)" : "var(--h-nav-item)", borderRadius: "var(--radius-md)", display: "flex", alignItems: "center", justifyContent: collapsed ? "center" : "flex-start", gap: 10, padding: collapsed ? "8px 10px" : indent ? "6px 10px" : "8px 10px", boxSizing: "border-box", cursor: "pointer", background: active ? "var(--bg-active)" : hover ? "var(--bg-hover)" : "transparent", color: active ? "var(--text-heading)" : "var(--text-body)", transition: "var(--t-hover)" }}>
9
+ <Icon name={icon} size={indent ? 14 : 16} />
10
+ {!collapsed ? <span style={{ fontFamily: "var(--font-sans)", fontWeight: "var(--weight-medium)", fontSize: "var(--text-base)", lineHeight: "var(--leading-base)", letterSpacing: "var(--tracking-base)", whiteSpace: "nowrap", flex: 1 }}>{label}</span> : null}
11
+ {!collapsed && badge ? badge : null}
12
+ </div>
13
+ );
14
+ }
15
+
16
+ /**
17
+ * Keybricks app sidebar — 240px (collapsed: 64px icon rail). White, hairline right border.
18
+ * items: [{icon,label,children:[{icon,label}]}]; active by label; footer items pinned.
19
+ */
20
+ export function Sidebar({ items = [], footerItems = [{ icon: "circle-help", label: "Help" }, { icon: "settings", label: "Settings" }, { icon: "moon", label: "Dark Mode" }], active, onSelect, collapsed = false, onToggleCollapse, logo = "assets/keybricks-logo.png", brand = "Keybricks", height = "100%", style }) {
21
+ const [openSections, setOpen] = React.useState(() => items.filter((i) => i.children && (i.open || (i.children.some((c) => c.label === active)))).map((i) => i.label));
22
+ const toggleSection = (l) => setOpen(openSections.includes(l) ? openSections.filter((x) => x !== l) : [...openSections, l]);
23
+ return (
24
+ <aside style={{ width: collapsed ? "var(--rail-w)" : "var(--sidebar-w)", height, background: "var(--bg-surface)", borderRight: "1px solid var(--border-card)", display: "flex", flexDirection: "column", boxSizing: "border-box", flexShrink: 0, transition: "width .15s ease", ...style }}>
25
+ <div style={{ height: "var(--topbar-h)", borderBottom: "1px solid var(--border-card)", display: "flex", alignItems: "center", gap: 10, padding: "0 16px", boxSizing: "border-box", justifyContent: collapsed ? "center" : "flex-start", flexShrink: 0 }}>
26
+ <img src={logo} alt="" style={{ width: 24, height: 24, objectFit: "contain" }} />
27
+ {!collapsed ? <span style={{ fontFamily: "var(--font-sans)", fontWeight: "var(--weight-semibold)", fontSize: "var(--text-lg)", lineHeight: "var(--leading-lg)", letterSpacing: "-.609px", color: "var(--text-primary)" }}>{brand}</span> : null}
28
+ </div>
29
+ <nav style={{ flex: 1, overflowY: "auto", padding: 8, display: "flex", flexDirection: "column", gap: 0 }}>
30
+ {onToggleCollapse ? <NavItem icon="panel-left" label="Collapse" collapsed={collapsed} onClick={onToggleCollapse} /> : null}
31
+ {items.map((it) => it.children ? (
32
+ <div key={it.label}>
33
+ <div onClick={() => toggleSection(it.label)} style={{ height: "var(--h-subnav-item)", display: "flex", alignItems: "center", gap: 10, padding: collapsed ? "6px 10px" : "6px 10px", justifyContent: collapsed ? "center" : "flex-start", cursor: "pointer", color: "var(--text-body)", borderRadius: "var(--radius-md)", boxSizing: "border-box" }}>
34
+ <Icon name={it.icon} size={16} />
35
+ {!collapsed ? <><span style={{ fontFamily: "var(--font-sans)", fontWeight: "var(--weight-medium)", fontSize: "var(--text-base)", letterSpacing: "var(--tracking-base)", flex: 1 }}>{it.label}</span><Icon name={openSections.includes(it.label) ? "chevron-up" : "chevron-down"} size={14} /></> : null}
36
+ </div>
37
+ {!collapsed && openSections.includes(it.label) ? (
38
+ <div style={{ marginLeft: 24, display: "flex", flexDirection: "column", gap: 2, paddingTop: 2 }}>
39
+ {it.children.map((c) => <NavItem key={c.label} icon={c.icon} label={c.label} indent active={active === c.label} onClick={() => onSelect && onSelect(c.label)} />)}
40
+ </div>
41
+ ) : null}
42
+ </div>
43
+ ) : (
44
+ <NavItem key={it.label} icon={it.icon} label={it.label} collapsed={collapsed} active={active === it.label} onClick={() => onSelect && onSelect(it.label)} />
45
+ ))}
46
+ </nav>
47
+ <div style={{ borderTop: "1px solid var(--border-card)", padding: 8, display: "flex", flexDirection: "column", flexShrink: 0 }}>
48
+ {footerItems.map((f) => <NavItem key={f.label} icon={f.icon} label={f.label} collapsed={collapsed} onClick={() => onSelect && onSelect(f.label)} />)}
49
+ </div>
50
+ </aside>
51
+ );
52
+ }
53
+
54
+ /** Default Keybricks nav model (Home dashboard). */
55
+ export const KEYBRICKS_NAV = [
56
+ { icon: "house", label: "Home" },
57
+ { icon: "file-text", label: "Documents" },
58
+ { icon: "layout-grid", label: "Business Intelligence" },
59
+ { icon: "database", label: "Data Integration" },
60
+ { icon: "scale", label: "Reconciliation" },
61
+ { icon: "network", label: "Consolidation" },
62
+ {
63
+ icon: "folder-cog", label: "Management", children: [
64
+ { icon: "box", label: "Modeling" },
65
+ { icon: "workflow", label: "Workflow" },
66
+ { icon: "shield", label: "Security Management" },
67
+ { icon: "refresh-cw", label: "System Migration" },
68
+ { icon: "chart-column", label: "Business Logic" },
69
+ { icon: "list-todo", label: "Tasks Management" },
70
+ { icon: "circle-check", label: "Validation Rules" },
71
+ { icon: "settings-2", label: "Control Center" },
72
+ { icon: "network", label: "Reconciliation" },
73
+ ],
74
+ },
75
+ ];
@@ -0,0 +1,54 @@
1
+ <script setup>
2
+ import { ref } from 'vue'
3
+ import Icon from '../icons/Icon.vue'
4
+
5
+ /**
6
+ * Keybricks app sidebar — 240px (collapsed: 64px icon rail). White, hairline right border.
7
+ * items: [{icon,label,children:[{icon,label}]}]; active by label; footer items pinned.
8
+ */
9
+ const props = defineProps({
10
+ items: { type: Array, default: () => [] },
11
+ footerItems: { type: Array, default: () => [{ icon: 'circle-help', label: 'Help' }, { icon: 'settings', label: 'Settings' }, { icon: 'moon', label: 'Dark Mode' }] },
12
+ active: String, collapsed: { type: Boolean, default: false },
13
+ logo: { type: String, default: 'assets/keybricks-logo.png' }, brand: { type: String, default: 'Keybricks' },
14
+ height: { type: [String, Number], default: '100%' }, style: Object, canCollapse: Boolean,
15
+ })
16
+ const emit = defineEmits(['select', 'toggleCollapse'])
17
+ const openSections = ref(props.items.filter(i => i.children && (i.open || i.children.some(c => c.label === props.active))).map(i => i.label))
18
+ function toggleSection(l) { openSections.value = openSections.value.includes(l) ? openSections.value.filter(x => x !== l) : [...openSections.value, l] }
19
+ function itemStyle(active, indent) { return { height: indent ? 'var(--h-subnav-item)' : 'var(--h-nav-item)', borderRadius: 'var(--radius-md)', display: 'flex', alignItems: 'center', gap: 10, padding: indent ? '6px 10px' : '8px 10px', boxSizing: 'border-box', cursor: 'pointer', background: active ? 'var(--bg-active)' : 'transparent', color: active ? 'var(--text-heading)' : 'var(--text-body)', transition: 'var(--t-hover)' } }
20
+ </script>
21
+ <template>
22
+ <aside :style="{ width: collapsed ? 'var(--rail-w)' : 'var(--sidebar-w)', height, background: 'var(--bg-surface)', borderRight: '1px solid var(--border-card)', display: 'flex', flexDirection: 'column', boxSizing: 'border-box', flexShrink: 0, transition: 'width .15s ease', ...style }">
23
+ <div :style="{ height: 'var(--topbar-h)', borderBottom: '1px solid var(--border-card)', display: 'flex', alignItems: 'center', gap: 10, padding: '0 16px', boxSizing: 'border-box', justifyContent: collapsed ? 'center' : 'flex-start', flexShrink: 0 }">
24
+ <img :src="logo" alt="" style="width:24px;height:24px;object-fit:contain" />
25
+ <span v-if="!collapsed" style="font-family:var(--font-sans);font-weight:var(--weight-semibold);font-size:var(--text-lg);line-height:var(--leading-lg);letter-spacing:-.609px;color:var(--text-primary)">{{ brand }}</span>
26
+ </div>
27
+ <nav style="flex:1;overflow-y:auto;padding:8px;display:flex;flex-direction:column;gap:0">
28
+ <div v-if="canCollapse" role="button" tabindex="0" @click="emit('toggleCollapse')" :style="itemStyle(false, false)"><Icon name="panel-left" :size="16" /><span v-if="!collapsed" style="font-family:var(--font-sans);font-weight:var(--weight-medium);font-size:var(--text-base);line-height:var(--leading-base);letter-spacing:var(--tracking-base);white-space:nowrap;flex:1">Collapse</span></div>
29
+ <template v-for="it in items" :key="it.label">
30
+ <div v-if="it.children">
31
+ <div role="button" tabindex="0" @click="toggleSection(it.label)" :style="{ height: 'var(--h-subnav-item)', display: 'flex', alignItems: 'center', gap: 10, padding: '6px 10px', justifyContent: collapsed ? 'center' : 'flex-start', cursor: 'pointer', color: 'var(--text-body)', borderRadius: 'var(--radius-md)', boxSizing: 'border-box' }">
32
+ <Icon :name="it.icon" :size="16" />
33
+ <template v-if="!collapsed"><span style="font-family:var(--font-sans);font-weight:var(--weight-medium);font-size:var(--text-base);letter-spacing:var(--tracking-base);flex:1">{{ it.label }}</span><Icon :name="openSections.includes(it.label) ? 'chevron-up' : 'chevron-down'" :size="14" /></template>
34
+ </div>
35
+ <div v-if="!collapsed && openSections.includes(it.label)" style="margin-left:24px;display:flex;flex-direction:column;gap:2px;padding-top:2px">
36
+ <div v-for="c in it.children" :key="c.label" role="button" tabindex="0" @click="emit('select', c.label)" :style="itemStyle(active === c.label, true)"><Icon :name="c.icon" :size="14" /><span style="font-family:var(--font-sans);font-weight:var(--weight-medium);font-size:var(--text-base);line-height:var(--leading-base);letter-spacing:var(--tracking-base);white-space:nowrap;flex:1">{{ c.label }}</span></div>
37
+ </div>
38
+ </div>
39
+ <div v-else role="button" tabindex="0" @click="emit('select', it.label)" :style="itemStyle(active === it.label, false)"><Icon :name="it.icon" :size="16" /><span v-if="!collapsed" style="font-family:var(--font-sans);font-weight:var(--weight-medium);font-size:var(--text-base);line-height:var(--leading-base);letter-spacing:var(--tracking-base);white-space:nowrap;flex:1">{{ it.label }}</span></div>
40
+ </template>
41
+ </nav>
42
+ <div style="border-top:1px solid var(--border-card);padding:8px;display:flex;flex-direction:column;flex-shrink:0">
43
+ <div v-for="f in footerItems" :key="f.label" role="button" tabindex="0" @click="emit('select', f.label)" :style="itemStyle(false, false)"><Icon :name="f.icon" :size="16" /><span v-if="!collapsed" style="font-family:var(--font-sans);font-weight:var(--weight-medium);font-size:var(--text-base);line-height:var(--leading-base);letter-spacing:var(--tracking-base);white-space:nowrap;flex:1">{{ f.label }}</span></div>
44
+ </div>
45
+ </aside>
46
+ </template>
47
+
48
+ <!-- KEYBRICKS_NAV — default Keybricks nav model (Home dashboard), same shape as Sidebar.jsx's export, for reference:
49
+ export const KEYBRICKS_NAV = [
50
+ { icon: 'house', label: 'Home' }, { icon: 'file-text', label: 'Documents' },
51
+ { icon: 'layout-grid', label: 'Business Intelligence' }, { icon: 'database', label: 'Data Integration' },
52
+ { icon: 'scale', label: 'Reconciliation' }, { icon: 'network', label: 'Consolidation' },
53
+ { icon: 'folder-cog', label: 'Management', children: [ ... ] },
54
+ ] -->
@@ -0,0 +1,27 @@
1
+ import * as React from "react";
2
+ /** 56px top bar with bare search + bell + dark AI Assistant button. */
3
+ export interface TopBarProps {
4
+ placeholder?: string;
5
+ /** Replaces the default bell + AI Assistant pair */
6
+ actions?: React.ReactNode;
7
+ /** Receives the new search string */
8
+ onSearch?: (value: string) => void;
9
+ style?: React.CSSProperties;
10
+ }
11
+ export declare function TopBar(props: TopBarProps): JSX.Element;
12
+ /** Editor toolbar: back, 14px/600 title, "• Editing", right actions. */
13
+ export interface PageToolbarProps {
14
+ title?: string;
15
+ status?: string;
16
+ actions?: React.ReactNode;
17
+ onBack?: () => void;
18
+ style?: React.CSSProperties;
19
+ }
20
+ export declare function PageToolbar(props: PageToolbarProps): JSX.Element;
21
+ /** 15px/500 page title + muted subtitle. */
22
+ export interface PageHeadingProps {
23
+ title?: string;
24
+ subtitle?: string;
25
+ style?: React.CSSProperties;
26
+ }
27
+ export declare function PageHeading(props: PageHeadingProps): JSX.Element;
@@ -0,0 +1,44 @@
1
+ import React from "react";
2
+ import { Icon } from "../icons/Icon.jsx";
3
+ import { IconButton } from "../buttons/IconButton.jsx";
4
+ import { Button } from "../buttons/Button.jsx";
5
+ import { SearchInput } from "../forms/SearchInput.jsx";
6
+
7
+ /** 56px top bar: bare search left, bell + dark AI Assistant button right. */
8
+ export function TopBar({ placeholder = "Search documents, workflows, data...", actions, onSearch, style }) {
9
+ return (
10
+ <header style={{ height: "var(--topbar-h)", background: "var(--bg-surface)", borderBottom: "1px solid var(--border-card)", display: "flex", alignItems: "center", justifyContent: "space-between", padding: "0 24px", boxSizing: "border-box", flexShrink: 0, ...style }}>
11
+ <SearchInput bare placeholder={placeholder} onChange={onSearch} style={{ width: 576, maxWidth: "48%" }} />
12
+ <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
13
+ {actions || (<>
14
+ <IconButton icon="bell" size="lg" />
15
+ <Button variant="dark" icon="sparkles">AI Assistant</Button>
16
+ </>)}
17
+ </div>
18
+ </header>
19
+ );
20
+ }
21
+
22
+ /** Editor toolbar: back chevron, 14px/600 title, "• Editing" status, right action slot. */
23
+ export function PageToolbar({ title, status = "• Editing", actions, onBack, style }) {
24
+ return (
25
+ <div style={{ height: "var(--topbar-h)", background: "var(--bg-surface)", borderBottom: "1px solid var(--border-card)", display: "flex", alignItems: "center", justifyContent: "space-between", padding: "0 16px", boxSizing: "border-box", flexShrink: 0, ...style }}>
26
+ <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
27
+ {onBack ? <IconButton icon="chevron-left" size="md" onClick={onBack} /> : null}
28
+ <span style={{ fontFamily: "var(--font-sans)", fontWeight: "var(--weight-semibold)", fontSize: "var(--text-md)", lineHeight: "var(--leading-md)", letterSpacing: "var(--tracking-md)", color: "var(--text-heading)" }}>{title}</span>
29
+ {status ? <span style={{ fontFamily: "var(--font-sans)", fontSize: "var(--text-sm)", lineHeight: "var(--leading-sm)", color: "var(--text-muted)", marginLeft: 6 }}>{status}</span> : null}
30
+ </div>
31
+ <div style={{ display: "flex", alignItems: "center", gap: 8 }}>{actions}</div>
32
+ </div>
33
+ );
34
+ }
35
+
36
+ /** Page heading block: 15px/500 title + 13px muted subtitle (System Migration pages). */
37
+ export function PageHeading({ title, subtitle, style }) {
38
+ return (
39
+ <div style={{ display: "flex", flexDirection: "column", gap: 4, ...style }}>
40
+ <span style={{ fontFamily: "var(--font-sans)", fontWeight: "var(--weight-medium)", fontSize: "var(--text-lg)", lineHeight: "var(--leading-lg)", letterSpacing: "var(--tracking-lg)", color: "var(--text-primary)" }}>{title}</span>
41
+ {subtitle ? <span style={{ fontFamily: "var(--font-sans)", fontSize: "var(--text-base)", lineHeight: "var(--leading-base)", letterSpacing: "var(--tracking-base)", color: "var(--text-secondary)" }}>{subtitle}</span> : null}
42
+ </div>
43
+ );
44
+ }
@@ -0,0 +1,51 @@
1
+ <script setup>
2
+ import IconButton from '../buttons/IconButton.vue'
3
+ import Button from '../buttons/Button.vue'
4
+ import SearchInput from '../forms/SearchInput.vue'
5
+ // 56px top bar: bare search left, bell + dark AI Assistant button right.
6
+ defineProps({ placeholder: { type: String, default: 'Search documents, workflows, data...' }, style: Object })
7
+ const emit = defineEmits(['search'])
8
+ </script>
9
+ <template>
10
+ <header :style="{ height: 'var(--topbar-h)', background: 'var(--bg-surface)', borderBottom: '1px solid var(--border-card)', display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '0 24px', boxSizing: 'border-box', flexShrink: 0, ...style }">
11
+ <SearchInput bare :placeholder="placeholder" @update:modelValue="v => emit('search', v)" style="width:576px;max-width:48%" />
12
+ <div style="display:flex;align-items:center;gap:8px">
13
+ <slot name="actions">
14
+ <IconButton icon="bell" size="lg" />
15
+ <Button variant="dark" icon="sparkles">AI Assistant</Button>
16
+ </slot>
17
+ </div>
18
+ </header>
19
+ </template>
20
+
21
+ <!-- PageToolbar — editor toolbar: back chevron, 14px/600 title, "• Editing" status, right action slot. -->
22
+ <!--
23
+ <script setup name="PageToolbar">
24
+ import IconButton from '../buttons/IconButton.vue'
25
+ defineProps({ title: String, status: { type: String, default: '• Editing' }, showBack: Boolean, style: Object })
26
+ const emit = defineEmits(['back'])
27
+ </script>
28
+ <template>
29
+ <div :style="{ height: 'var(--topbar-h)', background: 'var(--bg-surface)', borderBottom: '1px solid var(--border-card)', display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '0 16px', boxSizing: 'border-box', flexShrink: 0, ...style }">
30
+ <div style="display:flex;align-items:center;gap:8px">
31
+ <IconButton v-if="showBack" icon="chevron-left" size="md" @click="emit('back')" />
32
+ <span style="font-family:var(--font-sans);font-weight:var(--weight-semibold);font-size:var(--text-md);line-height:var(--leading-md);letter-spacing:var(--tracking-md);color:var(--text-heading)">{{ title }}</span>
33
+ <span v-if="status" style="font-family:var(--font-sans);font-size:var(--text-sm);line-height:var(--leading-sm);color:var(--text-muted);margin-left:6px">{{ status }}</span>
34
+ </div>
35
+ <div style="display:flex;align-items:center;gap:8px"><slot name="actions" /></div>
36
+ </div>
37
+ </template>
38
+ -->
39
+
40
+ <!-- PageHeading — page heading block: 15px/500 title + 13px muted subtitle. -->
41
+ <!--
42
+ <script setup name="PageHeading">
43
+ defineProps({ title: String, subtitle: String, style: Object })
44
+ </script>
45
+ <template>
46
+ <div :style="{ display: 'flex', flexDirection: 'column', gap: 4, ...style }">
47
+ <span style="font-family:var(--font-sans);font-weight:var(--weight-medium);font-size:var(--text-lg);line-height:var(--leading-lg);letter-spacing:var(--tracking-lg);color:var(--text-primary)">{{ title }}</span>
48
+ <span v-if="subtitle" style="font-family:var(--font-sans);font-size:var(--text-base);line-height:var(--leading-base);letter-spacing:var(--tracking-base);color:var(--text-secondary)">{{ subtitle }}</span>
49
+ </div>
50
+ </template>
51
+ -->