@lar-works/design-system 0.2.0 → 0.3.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 (433) hide show
  1. package/README.md +5 -1
  2. package/dist/actions/Button.d.ts +39 -1
  3. package/dist/actions/Button.js +39 -9
  4. package/dist/actions/Button.js.map +1 -1
  5. package/dist/actions/ButtonLink.d.ts +5 -1
  6. package/dist/actions/ButtonLink.js +28 -2
  7. package/dist/actions/ButtonLink.js.map +1 -1
  8. package/dist/actions/ButtonRecipes.js +7 -0
  9. package/dist/actions/ButtonRecipes.js.map +1 -0
  10. package/dist/actions/IconButton.d.ts +2 -2
  11. package/dist/actions/IconButton.js +1 -1
  12. package/dist/actions/IconButton.js.map +1 -1
  13. package/dist/actions/ThemeSwitch.js +1 -1
  14. package/dist/board/ActivityLine.d.ts +36 -0
  15. package/dist/board/ActivityLine.js +144 -0
  16. package/dist/board/ActivityLine.js.map +1 -0
  17. package/dist/board/ActivityTrack.d.ts +11 -0
  18. package/dist/board/ActivityTrack.js +25 -0
  19. package/dist/board/ActivityTrack.js.map +1 -0
  20. package/dist/board/AddItem.d.ts +82 -0
  21. package/dist/board/AddItem.js +185 -0
  22. package/dist/board/AddItem.js.map +1 -0
  23. package/dist/board/Archive.d.ts +21 -0
  24. package/dist/board/Archive.js +63 -0
  25. package/dist/board/Archive.js.map +1 -0
  26. package/dist/board/Attention.d.ts +66 -0
  27. package/dist/board/Attention.js +122 -0
  28. package/dist/board/Attention.js.map +1 -0
  29. package/dist/board/BoardShell.d.ts +16 -0
  30. package/dist/board/BoardShell.js +35 -0
  31. package/dist/board/BoardShell.js.map +1 -0
  32. package/dist/board/BoardTitleBar.d.ts +50 -0
  33. package/dist/board/BoardTitleBar.js +125 -0
  34. package/dist/board/BoardTitleBar.js.map +1 -0
  35. package/dist/board/ButtonKinds.d.ts +24 -0
  36. package/dist/board/ButtonKinds.js +19 -0
  37. package/dist/board/ButtonKinds.js.map +1 -0
  38. package/dist/board/Cleanup.d.ts +8 -0
  39. package/dist/board/Cleanup.js +15 -0
  40. package/dist/board/Cleanup.js.map +1 -0
  41. package/dist/board/Counters.d.ts +101 -0
  42. package/dist/board/Counters.js +202 -0
  43. package/dist/board/Counters.js.map +1 -0
  44. package/dist/board/DataAttributes.d.ts +6 -0
  45. package/dist/board/Dependencies.d.ts +17 -0
  46. package/dist/board/Dependencies.js +44 -0
  47. package/dist/board/Dependencies.js.map +1 -0
  48. package/dist/board/Desk.d.ts +52 -0
  49. package/dist/board/Desk.js +130 -0
  50. package/dist/board/Desk.js.map +1 -0
  51. package/dist/board/Dossier.d.ts +100 -0
  52. package/dist/board/Dossier.js +194 -0
  53. package/dist/board/Dossier.js.map +1 -0
  54. package/dist/board/Filters.d.ts +33 -0
  55. package/dist/board/Filters.js +64 -0
  56. package/dist/board/Filters.js.map +1 -0
  57. package/dist/board/ItemDetails.d.ts +167 -0
  58. package/dist/board/ItemDetails.js +339 -0
  59. package/dist/board/ItemDetails.js.map +1 -0
  60. package/dist/board/ItemDialog.d.ts +73 -0
  61. package/dist/board/ItemDialog.js +140 -0
  62. package/dist/board/ItemDialog.js.map +1 -0
  63. package/dist/board/ItemParts.d.ts +42 -0
  64. package/dist/board/ItemParts.js +82 -0
  65. package/dist/board/ItemParts.js.map +1 -0
  66. package/dist/board/ItemProgress.d.ts +56 -0
  67. package/dist/board/ItemProgress.js +138 -0
  68. package/dist/board/ItemProgress.js.map +1 -0
  69. package/dist/board/List.d.ts +65 -0
  70. package/dist/board/List.js +118 -0
  71. package/dist/board/List.js.map +1 -0
  72. package/dist/board/LoadingScreen.d.ts +38 -0
  73. package/dist/board/LoadingScreen.js +74 -0
  74. package/dist/board/LoadingScreen.js.map +1 -0
  75. package/dist/board/NeedsYou.d.ts +13 -0
  76. package/dist/board/NeedsYou.js +31 -0
  77. package/dist/board/NeedsYou.js.map +1 -0
  78. package/dist/board/Onboarding.d.ts +53 -0
  79. package/dist/board/Onboarding.js +122 -0
  80. package/dist/board/Onboarding.js.map +1 -0
  81. package/dist/board/PartsList.d.ts +60 -0
  82. package/dist/board/PartsList.js +115 -0
  83. package/dist/board/PartsList.js.map +1 -0
  84. package/dist/board/ProjectIcon.d.ts +51 -0
  85. package/dist/board/ProjectIcon.js +120 -0
  86. package/dist/board/ProjectIcon.js.map +1 -0
  87. package/dist/board/PullRequests.d.ts +43 -0
  88. package/dist/board/PullRequests.js +83 -0
  89. package/dist/board/PullRequests.js.map +1 -0
  90. package/dist/board/RowStyles.js +14 -0
  91. package/dist/board/RowStyles.js.map +1 -0
  92. package/dist/board/Settings.d.ts +54 -0
  93. package/dist/board/Settings.js +112 -0
  94. package/dist/board/Settings.js.map +1 -0
  95. package/dist/board/Slices.d.ts +32 -0
  96. package/dist/board/Slices.js +88 -0
  97. package/dist/board/Slices.js.map +1 -0
  98. package/dist/board/SourceIcon.d.ts +12 -0
  99. package/dist/board/SourceIcon.js +24 -0
  100. package/dist/board/SourceIcon.js.map +1 -0
  101. package/dist/board/StagePane.d.ts +43 -0
  102. package/dist/board/StagePane.js +97 -0
  103. package/dist/board/StagePane.js.map +1 -0
  104. package/dist/board/StageRow.d.ts +141 -0
  105. package/dist/board/StageRow.js +287 -0
  106. package/dist/board/StageRow.js.map +1 -0
  107. package/dist/board/StageTrack.d.ts +18 -0
  108. package/dist/board/StageTrack.js +38 -0
  109. package/dist/board/StageTrack.js.map +1 -0
  110. package/dist/board/StartControls.d.ts +30 -0
  111. package/dist/board/StartControls.js +51 -0
  112. package/dist/board/StartControls.js.map +1 -0
  113. package/dist/board/StatusColors.d.ts +5 -0
  114. package/dist/board/StatusColors.js +17 -0
  115. package/dist/board/StatusColors.js.map +1 -0
  116. package/dist/board/StatusGlyph.d.ts +18 -0
  117. package/dist/board/StatusGlyph.js +51 -0
  118. package/dist/board/StatusGlyph.js.map +1 -0
  119. package/dist/board/Threads.d.ts +13 -0
  120. package/dist/board/Threads.js +35 -0
  121. package/dist/board/Threads.js.map +1 -0
  122. package/dist/board/TrackerLabels.d.ts +27 -0
  123. package/dist/board/TrackerLabels.js +56 -0
  124. package/dist/board/TrackerLabels.js.map +1 -0
  125. package/dist/board/UpdatePill.d.ts +52 -0
  126. package/dist/board/UpdatePill.js +188 -0
  127. package/dist/board/UpdatePill.js.map +1 -0
  128. package/dist/board/Vocabulary.d.ts +56 -0
  129. package/dist/board/Vocabulary.js +104 -0
  130. package/dist/board/Vocabulary.js.map +1 -0
  131. package/dist/board/Warnings.d.ts +35 -0
  132. package/dist/board/Warnings.js +85 -0
  133. package/dist/board/Warnings.js.map +1 -0
  134. package/dist/board/WorkMap.d.ts +136 -0
  135. package/dist/board/WorkMap.js +274 -0
  136. package/dist/board/WorkMap.js.map +1 -0
  137. package/dist/board/index.d.ts +42 -0
  138. package/dist/collections/CollectionState.d.ts +10 -1
  139. package/dist/collections/CollectionState.js +12 -5
  140. package/dist/collections/CollectionState.js.map +1 -1
  141. package/dist/collections/ResultList.js +1 -1
  142. package/dist/collections/ScrollRow.js +1 -1
  143. package/dist/collections/VirtualList.js +1 -1
  144. package/dist/display/Avatar.d.ts +5 -2
  145. package/dist/display/Avatar.js +2 -2
  146. package/dist/display/Avatar.js.map +1 -1
  147. package/dist/display/Badge.d.ts +6 -1
  148. package/dist/display/Badge.js +9 -4
  149. package/dist/display/Badge.js.map +1 -1
  150. package/dist/display/CheckList.js +1 -1
  151. package/dist/display/Comment.d.ts +12 -0
  152. package/dist/display/Comment.js +39 -0
  153. package/dist/display/Comment.js.map +1 -0
  154. package/dist/display/CopyButton.d.ts +10 -2
  155. package/dist/display/CopyButton.js +29 -16
  156. package/dist/display/CopyButton.js.map +1 -1
  157. package/dist/display/Diagram.d.ts +17 -0
  158. package/dist/display/Diagram.js +49 -0
  159. package/dist/display/Diagram.js.map +1 -0
  160. package/dist/display/ImagePicker.js +1 -1
  161. package/dist/display/InfoBox.js +2 -2
  162. package/dist/display/InsetPanel.d.ts +3 -1
  163. package/dist/display/InsetPanel.js +7 -4
  164. package/dist/display/InsetPanel.js.map +1 -1
  165. package/dist/display/ItemAction.js +2 -2
  166. package/dist/display/LabelChip.d.ts +26 -0
  167. package/dist/display/LabelChip.js +41 -0
  168. package/dist/display/LabelChip.js.map +1 -0
  169. package/dist/display/LabelTint.js +60 -0
  170. package/dist/display/LabelTint.js.map +1 -0
  171. package/dist/display/Person.d.ts +5 -0
  172. package/dist/display/Person.js +19 -0
  173. package/dist/display/Person.js.map +1 -0
  174. package/dist/display/PropertySheet.js +1 -1
  175. package/dist/display/RadioChoice.d.ts +9 -2
  176. package/dist/display/RadioChoice.js +5 -1
  177. package/dist/display/RadioChoice.js.map +1 -1
  178. package/dist/display/RatingLink.js +1 -1
  179. package/dist/display/RichText.d.ts +12 -0
  180. package/dist/display/RichText.js +94 -0
  181. package/dist/display/RichText.js.map +1 -0
  182. package/dist/display/RowList.js +1 -1
  183. package/dist/display/index.d.ts +6 -1
  184. package/dist/feedback/Alert.js +1 -1
  185. package/dist/feedback/AsyncState.js +1 -1
  186. package/dist/feedback/DismissButton.d.ts +12 -0
  187. package/dist/feedback/DismissButton.js +20 -0
  188. package/dist/feedback/DismissButton.js.map +1 -0
  189. package/dist/feedback/ErrorNotification.js +2 -0
  190. package/dist/feedback/ErrorNotification.js.map +1 -1
  191. package/dist/feedback/FormResult.d.ts +16 -0
  192. package/dist/feedback/FormResult.js +30 -0
  193. package/dist/feedback/FormResult.js.map +1 -0
  194. package/dist/feedback/LiveRegion.d.ts +7 -0
  195. package/dist/feedback/LiveRegion.js +15 -0
  196. package/dist/feedback/LiveRegion.js.map +1 -0
  197. package/dist/feedback/Loading.d.ts +19 -0
  198. package/dist/feedback/Loading.js +63 -0
  199. package/dist/feedback/Loading.js.map +1 -0
  200. package/dist/feedback/Notifications.d.ts +35 -1
  201. package/dist/feedback/Notifications.js +196 -4
  202. package/dist/feedback/Notifications.js.map +1 -1
  203. package/dist/feedback/Progress.d.ts +15 -0
  204. package/dist/feedback/Progress.js +38 -0
  205. package/dist/feedback/Progress.js.map +1 -0
  206. package/dist/feedback/ProgressStatusRow.js +1 -1
  207. package/dist/feedback/StatusIndicator.d.ts +6 -1
  208. package/dist/feedback/StatusIndicator.js +19 -5
  209. package/dist/feedback/StatusIndicator.js.map +1 -1
  210. package/dist/feedback/index.d.ts +8 -4
  211. package/dist/forms/Checkbox.js +1 -1
  212. package/dist/forms/ColorSwatches.d.ts +21 -0
  213. package/dist/forms/ColorSwatches.js +26 -0
  214. package/dist/forms/ColorSwatches.js.map +1 -0
  215. package/dist/forms/FormSection.d.ts +68 -6
  216. package/dist/forms/FormSection.js +139 -8
  217. package/dist/forms/FormSection.js.map +1 -1
  218. package/dist/forms/HiddenField.d.ts +6 -0
  219. package/dist/forms/HiddenField.js +13 -0
  220. package/dist/forms/HiddenField.js.map +1 -0
  221. package/dist/forms/Input.d.ts +12 -2
  222. package/dist/forms/Input.js +10 -3
  223. package/dist/forms/Input.js.map +1 -1
  224. package/dist/forms/LabelPicker.d.ts +43 -0
  225. package/dist/forms/LabelPicker.js +107 -0
  226. package/dist/forms/LabelPicker.js.map +1 -0
  227. package/dist/forms/MarkdownEditor.d.ts +21 -0
  228. package/dist/forms/MarkdownEditor.js +175 -0
  229. package/dist/forms/MarkdownEditor.js.map +1 -0
  230. package/dist/forms/MarkdownToolbar.js +204 -0
  231. package/dist/forms/MarkdownToolbar.js.map +1 -0
  232. package/dist/forms/OptionSelect.d.ts +30 -9
  233. package/dist/forms/OptionSelect.js +53 -13
  234. package/dist/forms/OptionSelect.js.map +1 -1
  235. package/dist/forms/Select.d.ts +4 -1
  236. package/dist/forms/Select.js +3 -1
  237. package/dist/forms/Select.js.map +1 -1
  238. package/dist/forms/Switch.d.ts +4 -1
  239. package/dist/forms/Switch.js +5 -2
  240. package/dist/forms/Switch.js.map +1 -1
  241. package/dist/forms/TagInput.js +1 -1
  242. package/dist/forms/index.d.ts +7 -3
  243. package/dist/foundations/AmbientMotion.d.ts +2 -0
  244. package/dist/foundations/AmbientMotion.js +39 -0
  245. package/dist/foundations/AmbientMotion.js.map +1 -0
  246. package/dist/foundations/DesignSystemProvider.d.ts +34 -0
  247. package/dist/foundations/DesignSystemProvider.js +26 -1
  248. package/dist/foundations/DesignSystemProvider.js.map +1 -1
  249. package/dist/foundations/index.d.ts +2 -1
  250. package/dist/icons/BrandIcons.d.ts +8 -2
  251. package/dist/icons/BrandIcons.js +14 -3
  252. package/dist/icons/BrandIcons.js.map +1 -1
  253. package/dist/icons/dynamic.d.ts +2 -0
  254. package/dist/icons/dynamic.js +1 -0
  255. package/dist/icons/index.d.ts +2 -2
  256. package/dist/icons/index.js +1 -1
  257. package/dist/icons.d.ts +2 -2
  258. package/dist/icons.js +1 -1
  259. package/dist/index.d.ts +71 -10
  260. package/dist/index.js +78 -21
  261. package/dist/layout/Site.js +1 -1
  262. package/dist/layout/TitleBar.js +1 -1
  263. package/dist/layout/index.d.ts +2 -2
  264. package/dist/layout/index.js +3 -3
  265. package/dist/layout/toolbar/CommandPaletteTrigger.d.ts +17 -2
  266. package/dist/layout/toolbar/CommandPaletteTrigger.js +89 -6
  267. package/dist/layout/toolbar/CommandPaletteTrigger.js.map +1 -1
  268. package/dist/layout/toolbar/TriggerFit.js +56 -0
  269. package/dist/layout/toolbar/TriggerFit.js.map +1 -0
  270. package/dist/navigation/CollectionBrowseSelector.js +1 -1
  271. package/dist/navigation/CollectionViewToggle.d.ts +26 -0
  272. package/dist/navigation/CollectionViewToggle.js +54 -23
  273. package/dist/navigation/CollectionViewToggle.js.map +1 -1
  274. package/dist/navigation/DrilldownBrowseSelector.js +1 -1
  275. package/dist/navigation/FolderSelector.js +2 -2
  276. package/dist/navigation/SortMenu.d.ts +10 -0
  277. package/dist/navigation/SortMenu.js +33 -0
  278. package/dist/navigation/SortMenu.js.map +1 -0
  279. package/dist/navigation/index.d.ts +3 -2
  280. package/dist/overlays/CommandPalette.d.ts +38 -4
  281. package/dist/overlays/CommandPalette.js +140 -54
  282. package/dist/overlays/CommandPalette.js.map +1 -1
  283. package/dist/overlays/Drawer.js +1 -1
  284. package/dist/overlays/DropdownMenu.d.ts +7 -1
  285. package/dist/overlays/DropdownMenu.js +13 -2
  286. package/dist/overlays/DropdownMenu.js.map +1 -1
  287. package/dist/overlays/HelpTip.d.ts +8 -0
  288. package/dist/overlays/HelpTip.js +29 -0
  289. package/dist/overlays/HelpTip.js.map +1 -0
  290. package/dist/overlays/ImageViewer.js +2 -2
  291. package/dist/overlays/Modal.d.ts +5 -0
  292. package/dist/overlays/Modal.js +17 -2
  293. package/dist/overlays/Modal.js.map +1 -1
  294. package/dist/overlays/ModalExpandButton.d.ts +18 -0
  295. package/dist/overlays/ModalExpandButton.js +43 -0
  296. package/dist/overlays/ModalExpandButton.js.map +1 -0
  297. package/dist/overlays/Popover.d.ts +2 -1
  298. package/dist/overlays/Popover.js +1 -0
  299. package/dist/overlays/Popover.js.map +1 -1
  300. package/dist/overlays/index.d.ts +4 -2
  301. package/dist/showcase/Cards.js +1 -1
  302. package/dist/showcase/FeatureRow.js +1 -1
  303. package/dist/showcase/PhotoSearchConcept.js +1 -1
  304. package/dist/showcase/ProductBand.js +1 -1
  305. package/dist/showcase/Status.js +1 -1
  306. package/dist/typography/Code.d.ts +18 -0
  307. package/dist/typography/Code.js +24 -0
  308. package/dist/typography/Code.js.map +1 -0
  309. package/dist/typography/Link.d.ts +7 -2
  310. package/dist/typography/Link.js +15 -5
  311. package/dist/typography/Link.js.map +1 -1
  312. package/dist/typography/Typography.d.ts +19 -1
  313. package/dist/typography/Typography.js +11 -3
  314. package/dist/typography/Typography.js.map +1 -1
  315. package/dist/typography/index.d.ts +3 -3
  316. package/package.json +26 -3
  317. package/src/actions/Button.tsx +78 -11
  318. package/src/actions/ButtonLink.tsx +34 -0
  319. package/src/actions/ButtonRecipes.ts +10 -0
  320. package/src/actions/IconButton.tsx +7 -4
  321. package/src/board/ActivityLine.tsx +176 -0
  322. package/src/board/ActivityTrack.tsx +23 -0
  323. package/src/board/AddItem.tsx +259 -0
  324. package/src/board/Archive.tsx +75 -0
  325. package/src/board/Attention.tsx +135 -0
  326. package/src/board/BoardShell.tsx +30 -0
  327. package/src/board/BoardTitleBar.tsx +167 -0
  328. package/src/board/ButtonKinds.ts +32 -0
  329. package/src/board/Cleanup.tsx +19 -0
  330. package/src/board/Counters.tsx +224 -0
  331. package/src/board/DataAttributes.ts +3 -0
  332. package/src/board/Dependencies.tsx +49 -0
  333. package/src/board/Desk.tsx +155 -0
  334. package/src/board/Dossier.tsx +262 -0
  335. package/src/board/Filters.tsx +85 -0
  336. package/src/board/ItemDetails.tsx +435 -0
  337. package/src/board/ItemDialog.tsx +179 -0
  338. package/src/board/ItemParts.tsx +128 -0
  339. package/src/board/ItemProgress.tsx +164 -0
  340. package/src/board/List.tsx +154 -0
  341. package/src/board/LoadingScreen.tsx +78 -0
  342. package/src/board/NeedsYou.tsx +30 -0
  343. package/src/board/Onboarding.tsx +124 -0
  344. package/src/board/PartsList.tsx +160 -0
  345. package/src/board/ProjectIcon.tsx +172 -0
  346. package/src/board/PullRequests.tsx +106 -0
  347. package/src/board/RowStyles.ts +17 -0
  348. package/src/board/Settings.tsx +124 -0
  349. package/src/board/Slices.tsx +103 -0
  350. package/src/board/SourceIcon.tsx +33 -0
  351. package/src/board/StagePane.tsx +128 -0
  352. package/src/board/StageRow.tsx +320 -0
  353. package/src/board/StageTrack.tsx +61 -0
  354. package/src/board/StartControls.tsx +77 -0
  355. package/src/board/StatusColors.ts +28 -0
  356. package/src/board/StatusGlyph.tsx +70 -0
  357. package/src/board/Threads.tsx +38 -0
  358. package/src/board/TrackerLabels.tsx +75 -0
  359. package/src/board/UpdatePill.tsx +222 -0
  360. package/src/board/Vocabulary.tsx +155 -0
  361. package/src/board/Warnings.tsx +83 -0
  362. package/src/board/WorkMap.tsx +436 -0
  363. package/src/board/base.css +121 -0
  364. package/src/board/button-kinds.css +8 -0
  365. package/src/board/index.ts +224 -0
  366. package/src/board/items.css +75 -0
  367. package/src/board/loading-screen.css +171 -0
  368. package/src/board/rows.css +180 -0
  369. package/src/board/title-bar.css +56 -0
  370. package/src/board/tokens.css +52 -0
  371. package/src/board.css +19 -0
  372. package/src/collections/CollectionState.tsx +20 -7
  373. package/src/display/Avatar.tsx +6 -3
  374. package/src/display/Badge.tsx +25 -3
  375. package/src/display/Comment.tsx +26 -0
  376. package/src/display/CopyButton.tsx +48 -18
  377. package/src/display/Diagram.tsx +59 -0
  378. package/src/display/InsetPanel.tsx +4 -1
  379. package/src/display/LabelChip.tsx +73 -0
  380. package/src/display/LabelTint.ts +72 -0
  381. package/src/display/Person.tsx +11 -0
  382. package/src/display/RadioChoice.tsx +11 -2
  383. package/src/display/RichText.tsx +114 -0
  384. package/src/display/index.ts +5 -0
  385. package/src/feedback/DismissButton.tsx +28 -0
  386. package/src/feedback/ErrorNotification.ts +3 -0
  387. package/src/feedback/FormResult.tsx +50 -0
  388. package/src/feedback/LiveRegion.tsx +10 -0
  389. package/src/feedback/Loading.tsx +75 -0
  390. package/src/feedback/Notifications.tsx +267 -2
  391. package/src/feedback/Progress.tsx +44 -0
  392. package/src/feedback/StatusIndicator.tsx +34 -3
  393. package/src/feedback/index.ts +12 -2
  394. package/src/forms/ColorSwatches.tsx +50 -0
  395. package/src/forms/FormSection.tsx +245 -10
  396. package/src/forms/HiddenField.tsx +4 -0
  397. package/src/forms/Input.tsx +26 -4
  398. package/src/forms/LabelPicker.tsx +140 -0
  399. package/src/forms/MarkdownEditor.tsx +283 -0
  400. package/src/forms/MarkdownToolbar.tsx +267 -0
  401. package/src/forms/OptionSelect.tsx +110 -25
  402. package/src/forms/Select.tsx +20 -13
  403. package/src/forms/Switch.tsx +16 -2
  404. package/src/forms/index.ts +16 -2
  405. package/src/foundations/AmbientMotion.ts +51 -0
  406. package/src/foundations/DesignSystemProvider.tsx +19 -0
  407. package/src/foundations/index.ts +1 -0
  408. package/src/foundations/theme.css +64 -0
  409. package/src/icons/BrandIcons.tsx +12 -3
  410. package/src/icons/dynamic.ts +4 -0
  411. package/src/icons/index.ts +1 -1
  412. package/src/index.ts +2 -1
  413. package/src/layout/index.ts +1 -1
  414. package/src/layout/toolbar/CommandPaletteTrigger.tsx +187 -31
  415. package/src/layout/toolbar/TriggerFit.ts +84 -0
  416. package/src/navigation/CollectionViewToggle.tsx +94 -24
  417. package/src/navigation/SortMenu.tsx +41 -0
  418. package/src/navigation/index.ts +2 -1
  419. package/src/overlays/CommandPalette.tsx +190 -60
  420. package/src/overlays/DropdownMenu.tsx +12 -1
  421. package/src/overlays/HelpTip.tsx +29 -0
  422. package/src/overlays/Modal.tsx +23 -0
  423. package/src/overlays/ModalExpandButton.tsx +48 -0
  424. package/src/overlays/Popover.tsx +3 -1
  425. package/src/overlays/index.ts +9 -1
  426. package/src/showcase.css +6 -0
  427. package/src/styles.css +9 -1
  428. package/src/typography/Code.tsx +24 -0
  429. package/src/typography/Link.tsx +19 -10
  430. package/src/typography/Typography.tsx +25 -2
  431. package/src/typography/index.ts +1 -1
  432. package/dist/feedback/index.js +0 -11
  433. package/dist/typography/index.js +0 -4
@@ -0,0 +1,160 @@
1
+ // An expanded dossier's parts list: each part with what it asks next, its stage track, figures, thread and slices, the
2
+ // done parts folded away; and a part's kind as every surface of the dossier names it.
3
+
4
+ import { BookOpenIcon, HammerIcon, ListChecksIcon, MessagesSquareIcon, ShapesIcon } from 'lucide-react';
5
+ import type { ReactNode } from 'react';
6
+
7
+ import { pickedRow, ROW_OPENS } from './RowStyles';
8
+
9
+ const KIND_ICON = {
10
+ grill: MessagesSquareIcon,
11
+ prototype: ShapesIcon,
12
+ research: BookOpenIcon,
13
+ task: ListChecksIcon,
14
+ decision: MessagesSquareIcon,
15
+ build: HammerIcon,
16
+ } as const;
17
+
18
+ /** What a dossier's part is: a decision's method, or a build. */
19
+ export type PartKind = keyof typeof KIND_ICON;
20
+
21
+ /** A part's method or kind with its icon, in the one place and style every dossier surface shows it. */
22
+ export function PartKindLabel({ kind, children }: { kind: PartKind; children: ReactNode }) {
23
+ const Icon = KIND_ICON[kind];
24
+
25
+ return (
26
+ <span
27
+ className="inline-flex shrink-0 items-center gap-1.5 text-[11px] text-(--muted-foreground)"
28
+ data-part-kind
29
+ >
30
+ <Icon className="size-3.5 shrink-0" />
31
+ {children}
32
+ </span>
33
+ );
34
+ }
35
+
36
+ /** The parts, in two columns where there's room, then `showDone`, the button that unfolds the done ones. */
37
+ export function PartsList({ showDone, children }: { showDone?: ReactNode; children: ReactNode }) {
38
+ return (
39
+ <div className="grid gap-1">
40
+ <ol className="m-0 grid list-none gap-x-4 gap-y-1 p-0 @4xl:grid-cols-2" data-parts-list>
41
+ {children}
42
+ </ol>
43
+ {showDone}
44
+ </div>
45
+ );
46
+ }
47
+
48
+ /** The button under the parts that shows or hides the done ones. */
49
+ export function ShowDoneToggle({
50
+ open,
51
+ onToggle,
52
+ children,
53
+ }: {
54
+ open: boolean;
55
+ onToggle: () => void;
56
+ children: string;
57
+ }) {
58
+ return (
59
+ <button
60
+ type="button"
61
+ aria-expanded={open}
62
+ onClick={onToggle}
63
+ className="justify-self-start rounded px-2 py-1 text-[11px] text-(--muted-foreground) hover:bg-(--accent)"
64
+ >
65
+ {children}
66
+ </button>
67
+ );
68
+ }
69
+
70
+ /**
71
+ * A part: one button opens its item from its `name` and `meta` (kind, repository, track, status), what it asks next
72
+ * (`action`) sits beside that button, then its `second` line (a RowSecondLine) and any `foot`, its start's message or
73
+ * error, under that.
74
+ */
75
+ export function PartRow({
76
+ id,
77
+ picked,
78
+ title,
79
+ onOpen,
80
+ name,
81
+ meta,
82
+ action,
83
+ second,
84
+ foot,
85
+ }: {
86
+ id: string;
87
+ picked: boolean;
88
+ title: string;
89
+ onOpen: () => void;
90
+ name: ReactNode;
91
+ meta: ReactNode;
92
+ action: ReactNode;
93
+ second?: ReactNode;
94
+ foot?: ReactNode;
95
+ }) {
96
+ return (
97
+ <li data-part={id} className={`@container rounded-md px-3 py-2 hover:bg-(--accent) ${pickedRow(picked)}`}>
98
+ <div className="flex items-start gap-x-3">
99
+ <button
100
+ type="button"
101
+ data-row-open
102
+ onClick={onOpen}
103
+ title={title}
104
+ className={`grid min-w-0 flex-1 gap-y-1 rounded text-left ${ROW_OPENS}`}
105
+ >
106
+ {name}
107
+ <span
108
+ className="flex min-w-0 flex-wrap items-center gap-x-2 gap-y-1 pl-5 text-xs text-(--muted-foreground)"
109
+ data-part-meta
110
+ >
111
+ {meta}
112
+ </span>
113
+ </button>
114
+ <span
115
+ data-part-action
116
+ className="flex min-h-7 shrink-0 items-center justify-end gap-2 text-xs text-(--muted-foreground)"
117
+ >
118
+ {action}
119
+ </span>
120
+ </div>
121
+ {second}
122
+ {foot && <span className="block pt-1 pl-5 empty:hidden">{foot}</span>}
123
+ </li>
124
+ );
125
+ }
126
+
127
+ /** A part's stage track in its meta line, at a fixed width so the tracks line up. */
128
+ export function PartTrack({ children }: { children: ReactNode }) {
129
+ return <span className="w-28 shrink-0">{children}</span>;
130
+ }
131
+
132
+ /** What a part waits on, beside its action, truncating. */
133
+ export function PartWaits({ children }: { children: string }) {
134
+ return (
135
+ <span className="max-w-48 truncate" title={children}>
136
+ {children}
137
+ </span>
138
+ );
139
+ }
140
+
141
+ /** A part's thread in its second line: its glyph, `name` and `state`; `title` names it in full. */
142
+ export function ThreadLine({
143
+ glyph,
144
+ name,
145
+ state,
146
+ title,
147
+ }: {
148
+ glyph: ReactNode;
149
+ name: string;
150
+ state: string;
151
+ title?: string | undefined;
152
+ }) {
153
+ return (
154
+ <span className="flex min-w-0 items-center gap-1.5" title={title}>
155
+ {glyph}
156
+ <span className="truncate">{name}</span>
157
+ <span className="shrink-0">· {state}</span>
158
+ </span>
159
+ );
160
+ }
@@ -0,0 +1,172 @@
1
+ // A project's icon, in a fixed square. An emoji or monogram chosen in T3 takes the square. Otherwise it holds the
2
+ // toned initial, with the favicon or lucide icon laid over it once that has loaded, so the square keeps its size either
3
+ // way and a missing or broken one leaves the initial. Decorative, as a name sits beside it. An SVG favicon only ever
4
+ // renders through this <img>, which runs none of its scripts.
5
+
6
+ import { lazy, Suspense, useState, type ComponentProps, type ComponentType } from 'react';
7
+
8
+ import type { DynamicIcon } from '../icons/dynamic';
9
+ import type { DataAttributes } from './DataAttributes';
10
+
11
+ /** T3's project icon colours, which tint a lucide icon or a monogram. */
12
+ export type ProjectIconColor =
13
+ | 'gray'
14
+ | 'red'
15
+ | 'orange'
16
+ | 'amber'
17
+ | 'yellow'
18
+ | 'lime'
19
+ | 'green'
20
+ | 'emerald'
21
+ | 'teal'
22
+ | 'cyan'
23
+ | 'sky'
24
+ | 'blue'
25
+ | 'indigo'
26
+ | 'violet'
27
+ | 'purple'
28
+ | 'fuchsia'
29
+ | 'pink'
30
+ | 'rose';
31
+
32
+ /** What a project's square shows over its initial: a lucide icon by name, an emoji, up to two characters of a
33
+ * monogram, or a favicon at `src`. */
34
+ export type ProjectIconSource =
35
+ | { kind: 'lucide'; name: string; color: ProjectIconColor }
36
+ | { kind: 'emoji'; emoji: string }
37
+ | { kind: 'monogram'; text: string; color: ProjectIconColor }
38
+ | { kind: 'favicon'; src: string };
39
+
40
+ /** The board's palette of repository colours, which the repositories take in their list order. */
41
+ const REPO_TONES = 8;
42
+
43
+ const SIZES = {
44
+ small: { square: 'size-3.5 text-[8px]', emoji: 'text-[10px]', monogram: 'text-[7px]' },
45
+ row: { square: 'size-4 text-[9px]', emoji: 'text-xs', monogram: 'text-[8px]' },
46
+ medium: { square: 'size-5 text-[10px]', emoji: 'text-sm', monogram: 'text-[10px]' },
47
+ };
48
+
49
+ export type ProjectIconSize = keyof typeof SIZES;
50
+
51
+ /** Whole class names, as Tailwind only finds those. */
52
+ const COLORS: Record<ProjectIconColor, string> = {
53
+ gray: 'text-gray-500',
54
+ red: 'text-red-500',
55
+ orange: 'text-orange-500',
56
+ amber: 'text-amber-500',
57
+ yellow: 'text-yellow-500',
58
+ lime: 'text-lime-500',
59
+ green: 'text-green-500',
60
+ emerald: 'text-emerald-500',
61
+ teal: 'text-teal-500',
62
+ cyan: 'text-cyan-500',
63
+ sky: 'text-sky-500',
64
+ blue: 'text-blue-500',
65
+ indigo: 'text-indigo-500',
66
+ violet: 'text-violet-500',
67
+ purple: 'text-purple-500',
68
+ fuchsia: 'text-fuchsia-500',
69
+ pink: 'text-pink-500',
70
+ rose: 'text-rose-500',
71
+ };
72
+
73
+ const OVERLAY = 'absolute inset-0 size-full bg-base-100';
74
+
75
+ /** lucide's name map and its icons are lazy chunks, loaded when first shown. DynamicIcon draws nothing for a name
76
+ * lucide lacks or an icon that won't load, and a name map that won't load draws nothing here. */
77
+ const LucideIcon = lazy<ComponentType<ComponentProps<typeof DynamicIcon>>>(() =>
78
+ import('../icons/dynamic').then(
79
+ (lucide) => ({ default: lucide.DynamicIcon }),
80
+ () => ({ default: () => null }),
81
+ ),
82
+ );
83
+
84
+ function Favicon({ src }: { src: string }) {
85
+ const [loaded, setLoaded] = useState(false);
86
+ const [failed, setFailed] = useState(false);
87
+
88
+ if (failed) return null;
89
+
90
+ return (
91
+ <img
92
+ src={src}
93
+ alt=""
94
+ hidden={!loaded}
95
+ onLoad={() => setLoaded(true)}
96
+ onError={() => setFailed(true)}
97
+ className={`${OVERLAY} object-contain`}
98
+ />
99
+ );
100
+ }
101
+
102
+ const graphemes = new Intl.Segmenter();
103
+ const firstGraphemes = (text: string, count: number) => {
104
+ let shown = '';
105
+ let length = 0;
106
+
107
+ for (const { segment } of graphemes.segment(text)) {
108
+ shown += segment;
109
+
110
+ if (++length === count) break;
111
+ }
112
+
113
+ return shown;
114
+ };
115
+
116
+ /**
117
+ * A project's icon in a square of its `size`: `icon`, or its `name`'s initial on the colour of its `place` among the
118
+ * board's repositories (muted for a project the board doesn't list), with a favicon or lucide icon laid over the
119
+ * initial once it has loaded.
120
+ */
121
+ export function ProjectIcon({
122
+ icon,
123
+ name,
124
+ place,
125
+ size,
126
+ ...data
127
+ }: {
128
+ icon?: ProjectIconSource | null | undefined;
129
+ name: string;
130
+ place?: number | undefined;
131
+ size: ProjectIconSize;
132
+ } & DataAttributes) {
133
+ const { square, emoji, monogram } = SIZES[size];
134
+ const shared = `${square} relative grid shrink-0 place-items-center overflow-hidden rounded-md font-bold`;
135
+
136
+ if (icon?.kind === 'emoji')
137
+ return (
138
+ <span {...data} data-project-icon className={shared} aria-hidden="true">
139
+ <span className={emoji}>{icon.emoji}</span>
140
+ </span>
141
+ );
142
+
143
+ if (icon?.kind === 'monogram')
144
+ return (
145
+ <span {...data} data-project-icon className={`${shared} ${COLORS[icon.color]}`} aria-hidden="true">
146
+ <span className={`${monogram} leading-none whitespace-nowrap`}>{firstGraphemes(icon.text, 2)}</span>
147
+ </span>
148
+ );
149
+
150
+ const tone = place === undefined ? 'repo-tone-none' : `repo-tone-${place % REPO_TONES}`;
151
+
152
+ return (
153
+ <span
154
+ {...data}
155
+ data-project-icon
156
+ className={`${tone} ${shared} bg-[var(--k,var(--color-base-600))] text-white`}
157
+ aria-hidden="true"
158
+ >
159
+ {firstGraphemes(name, 1).toUpperCase()}
160
+ {icon?.kind === 'favicon' && <Favicon key={icon.src} src={icon.src} />}
161
+ {icon?.kind === 'lucide' && (
162
+ <Suspense fallback={null}>
163
+ <LucideIcon
164
+ key={icon.name}
165
+ name={icon.name as ComponentProps<typeof DynamicIcon>['name']}
166
+ className={`${OVERLAY} ${COLORS[icon.color]}`}
167
+ />
168
+ </Suspense>
169
+ )}
170
+ </span>
171
+ );
172
+ }
@@ -0,0 +1,106 @@
1
+ // A piece of work's pull requests: a list with each one's checks and readiness, and the short reference rows show.
2
+
3
+ import { GitPullRequestIcon } from 'lucide-react';
4
+ import type { ReactNode } from 'react';
5
+
6
+ /** The pull requests in a list, one PullRequestRow each. */
7
+ export function PullRequestList({ children }: { children: ReactNode }) {
8
+ return <ul className="m-0 grid list-none grid-cols-[minmax(0,1fr)] gap-1 p-0">{children}</ul>;
9
+ }
10
+
11
+ /** A pull request: its icon and label linking to it in a new tab, then its `checks` and `readiness`. */
12
+ export function PullRequestRow({
13
+ href,
14
+ label,
15
+ checks,
16
+ readiness,
17
+ }: {
18
+ href: string;
19
+ label: string;
20
+ checks?: ReactNode;
21
+ readiness?: ReactNode;
22
+ }) {
23
+ return (
24
+ <li className="flex flex-wrap items-center gap-x-2 gap-y-1 rounded-lg border border-(--border) bg-(--card) px-3 py-2">
25
+ <GitPullRequestIcon className="size-4 shrink-0 text-(--st-done)" />
26
+ <a
27
+ href={href}
28
+ target="_blank"
29
+ rel="noopener"
30
+ className="min-w-0 flex-1 basis-24 font-medium wrap-anywhere hover:underline"
31
+ >
32
+ {label}
33
+ </a>
34
+ {checks}
35
+ {readiness}
36
+ </li>
37
+ );
38
+ }
39
+
40
+ const CHECKS_COLOR = { failed: 'var(--error)', running: 'var(--warning)', passed: 'var(--st-done)' } as const;
41
+
42
+ /** A pull request's checks as a coloured dot and their state, then any `counts`. */
43
+ export function ChecksState({ state, counts }: { state: keyof typeof CHECKS_COLOR; counts?: string }) {
44
+ return (
45
+ <span className="inline-flex shrink-0 items-center gap-1.5 text-xs text-(--muted-foreground)">
46
+ <span className="size-2 rounded-full" style={{ background: CHECKS_COLOR[state] }} />
47
+ checks {state}
48
+ {counts && <span className="tabular-nums">· {counts}</span>}
49
+ </span>
50
+ );
51
+ }
52
+
53
+ /** A pull request as a row names it: its icon and short label, `title` naming it in full. */
54
+ export function PullRequestRef({ label, title }: { label: string; title?: string }) {
55
+ return (
56
+ <span title={title} className="inline-flex shrink-0 items-center gap-1">
57
+ <GitPullRequestIcon className="size-3 shrink-0 text-(--st-done)" />
58
+ {label}
59
+ </span>
60
+ );
61
+ }
62
+
63
+ /** A pull request's readiness under its row: the `toggle` that shows it, then the `details` while shown. */
64
+ export function PullRequestReadiness({ toggle, details }: { toggle: ReactNode; details?: ReactNode }) {
65
+ return (
66
+ <div className="basis-full text-xs text-(--muted-foreground)">
67
+ {toggle}
68
+ {details}
69
+ </div>
70
+ );
71
+ }
72
+
73
+ /** What a readiness read says: its `status`, when it was `observed` and what blocks it, a `note`, and `refresh`. */
74
+ export function ReadinessDetails({
75
+ id,
76
+ status,
77
+ observed,
78
+ blockers = [],
79
+ note,
80
+ refresh,
81
+ }: {
82
+ id: string;
83
+ status: ReactNode;
84
+ observed?: ReactNode;
85
+ blockers?: string[];
86
+ note: ReactNode;
87
+ refresh: ReactNode;
88
+ }) {
89
+ return (
90
+ <div id={id} role="status" aria-live="polite">
91
+ <p>{status}</p>
92
+ {observed && (
93
+ <>
94
+ <p>{observed}</p>
95
+ <ul>
96
+ {blockers.map((b) => (
97
+ <li key={b}>{b}</li>
98
+ ))}
99
+ </ul>
100
+ </>
101
+ )}
102
+ <p>{note}</p>
103
+ {refresh}
104
+ </div>
105
+ );
106
+ }
@@ -0,0 +1,17 @@
1
+ // What the board's rows share: the rule under a row, the focus ring of a row's own buttons, the action slot, and how
2
+ // the row the item dialog shows is marked; and the warning panel its notes share.
3
+
4
+ /** The rule under a row, which takes no height, so every row of a type measures the same. */
5
+ export const ROW_RULE = 'shadow-[inset_0_-1px_var(--border)] last:shadow-none';
6
+ /** A row's own buttons draw their focus ring inside the pane that clips them. */
7
+ export const ROW_OPENS = 'focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-(--primary)';
8
+ /** What a row's action slot holds, centred and against its right edge. */
9
+ export const ROW_ACTION =
10
+ 'flex min-w-0 flex-wrap items-center justify-end gap-x-2 gap-y-1 text-right text-xs text-(--muted-foreground)';
11
+
12
+ /** A row the item dialog shows now: tinted and ringed. */
13
+ export const pickedRow = (picked: boolean) => (picked ? 'bg-(--accent) ring-2 ring-inset ring-(--primary)' : '');
14
+
15
+ /** The panel a warning about a piece of work sits in, such as why it needs you or is paused. */
16
+ export const WARNING_PANEL =
17
+ 'rounded-xl border border-[color-mix(in_srgb,var(--warning)_35%,transparent)] bg-(--warning-surface) px-3 py-2.5';
@@ -0,0 +1,124 @@
1
+ // Lar Factory's settings: the title bar's button that opens them, the sections' sidebar, the column of a page's groups,
2
+ // the short reason a setting can't be changed, and the parts its rows show under and beside their controls.
3
+
4
+ import { SettingsIcon } from 'lucide-react';
5
+ import type { ReactNode } from 'react';
6
+
7
+ import { Button } from '../actions/Button';
8
+ import { SidebarPane } from '../layout/sidebar/SidebarPane';
9
+ import { HelpTip } from '../overlays/HelpTip';
10
+ import { buttonKind } from './ButtonKinds';
11
+ import type { DataAttributes } from './DataAttributes';
12
+
13
+ /** The title bar's last button, which opens Settings: an icon-only App control named by its `label`, its 20px icon in
14
+ * the text colour rather than the muted one, so it holds its own beside the labelled controls. */
15
+ export function OpenSettingsButton({ label, onOpen }: { label: string; onOpen: () => void }) {
16
+ return (
17
+ <Button
18
+ {...buttonKind('control')}
19
+ iconOnly
20
+ className="open-settings text-base-content [&_svg]:size-5"
21
+ aria-label={label}
22
+ title={label}
23
+ onClick={onOpen}
24
+ >
25
+ <SettingsIcon />
26
+ </Button>
27
+ );
28
+ }
29
+
30
+ /**
31
+ * Settings' sidebar: the `search` field over the sections' groups (SidebarNavigationGroup), and `empty`, announced,
32
+ * when a search leaves none. `label` names the navigation.
33
+ */
34
+ export function SettingsNav({
35
+ label,
36
+ search,
37
+ empty,
38
+ children,
39
+ ...data
40
+ }: {
41
+ label: string;
42
+ search: ReactNode;
43
+ empty?: string | undefined;
44
+ children: ReactNode;
45
+ } & DataAttributes) {
46
+ return (
47
+ <div {...data} className="contents">
48
+ <SidebarPane label={label}>
49
+ <div className="w-44 shrink-0 md:mb-3 md:w-auto">{search}</div>
50
+ {empty && (
51
+ <p role="status" data-no-match className="text-base-700 m-0 px-2 py-1 text-xs">
52
+ {empty}
53
+ </p>
54
+ )}
55
+ {children}
56
+ </SidebarPane>
57
+ </div>
58
+ );
59
+ }
60
+
61
+ /**
62
+ * Why a setting can't be changed, in a short muted line that wraps: the `reason`, a help popover with the whole
63
+ * `explanation` (`helpLabel` names its button), then the `action` that checks again, such as an InlineLink with `onClick`.
64
+ */
65
+ export function ReasonNote({
66
+ reason,
67
+ explanation,
68
+ helpLabel,
69
+ action,
70
+ }: {
71
+ reason: string;
72
+ explanation: ReactNode;
73
+ helpLabel: string;
74
+ action?: ReactNode;
75
+ }) {
76
+ return (
77
+ <span className="inline-flex min-w-0 flex-wrap items-center gap-1 text-xs text-(--muted-foreground)">
78
+ <span>{reason}</span>
79
+ <HelpTip label={helpLabel}>{explanation}</HelpTip>
80
+ {action}
81
+ </span>
82
+ );
83
+ }
84
+
85
+ /** A settings group's note under its panel, such as what the group's last call did: small lines, stacked. `busy` marks
86
+ * it as still loading for assistive technology. */
87
+ export function SettingsNote({ busy, children, ...data }: { busy?: boolean; children: ReactNode } & DataAttributes) {
88
+ return (
89
+ <div {...data} className="grid gap-2 px-1" aria-busy={busy}>
90
+ {children}
91
+ </div>
92
+ );
93
+ }
94
+
95
+ /** What a setting row shows under its control, such as an install's progress, in small stacked lines; `breaks` lets a
96
+ * long path break anywhere. */
97
+ export function SettingDetails({ breaks = false, children }: { breaks?: boolean; children: ReactNode }) {
98
+ return <div className={`grid gap-2 text-xs${breaks ? ' [overflow-wrap:anywhere]' : ''}`}>{children}</div>;
99
+ }
100
+
101
+ /** A setting's control with its error under it, at most 20rem wide. */
102
+ export function SettingControl({ children }: { children: ReactNode }) {
103
+ return <div className="grid max-w-80 gap-2">{children}</div>;
104
+ }
105
+
106
+ /** A small list of each Project's value for a setting, the Project left and its value muted right, wrapping. */
107
+ export function ProjectValueList({
108
+ label,
109
+ rows,
110
+ }: {
111
+ label: string;
112
+ rows: readonly { key: string; name: string; value: string }[];
113
+ }) {
114
+ return (
115
+ <ul className="m-0 grid list-none gap-1 p-0 text-xs" aria-label={label}>
116
+ {rows.map(({ key, name, value }) => (
117
+ <li key={key} className="flex flex-wrap justify-between gap-x-3">
118
+ <span className="[overflow-wrap:anywhere]">{name}</span>{' '}
119
+ <span className="[overflow-wrap:anywhere] text-(--muted-foreground)">{value}</span>
120
+ </li>
121
+ ))}
122
+ </ul>
123
+ );
124
+ }
@@ -0,0 +1,103 @@
1
+ // A piece of work's slices: the bar every view of the board draws, and a list with each slice's mark.
2
+
3
+ import { CheckIcon } from 'lucide-react';
4
+ import type { ReactNode } from 'react';
5
+
6
+ import { ambientMotion } from '../foundations/AmbientMotion';
7
+
8
+ /** Where a slice stands. */
9
+ export type SliceProgress = 'done' | 'active' | 'blocked' | 'unknown' | 'waiting';
10
+
11
+ const SLICE_COLOR: Record<SliceProgress, string> = {
12
+ done: 'var(--st-done)',
13
+ active: 'var(--st-now)',
14
+ blocked: 'var(--st-review)',
15
+ unknown: 'var(--muted-foreground)',
16
+ waiting: 'var(--input)',
17
+ };
18
+
19
+ /** A 6px segment for each slice, named by its tooltip; waiting segments are faint, and an active one pulses unless
20
+ * `still`. */
21
+ export function SliceBar({
22
+ slices,
23
+ still = false,
24
+ }: {
25
+ slices: { name: string; progress: SliceProgress }[];
26
+ still?: boolean;
27
+ }) {
28
+ if (!slices.length) return null;
29
+
30
+ return (
31
+ <ol className="m-0 flex list-none gap-[2px] p-0">
32
+ {slices.map((s, i) => (
33
+ <li
34
+ key={i}
35
+ ref={s.progress === 'active' && !still ? ambientMotion : undefined}
36
+ title={s.name}
37
+ className={`h-1.5 flex-1 rounded-full ${s.progress === 'active' && !still ? 'status-pulse' : ''}`}
38
+ style={{ background: s.progress === 'waiting' ? 'var(--soft)' : SLICE_COLOR[s.progress] }}
39
+ />
40
+ ))}
41
+ </ol>
42
+ );
43
+ }
44
+
45
+ /** A slice's state as a ring: ticked when done, a question mark when unknown, a dot pulsing unless `still` while
46
+ * active. */
47
+ export function SliceMark({ progress, still = false }: { progress: SliceProgress; still?: boolean }) {
48
+ return (
49
+ <span
50
+ className="grid size-4 shrink-0 place-items-center rounded-full border-[1.5px]"
51
+ style={{
52
+ borderColor: SLICE_COLOR[progress],
53
+ background: progress === 'done' ? 'var(--st-done)' : 'transparent',
54
+ }}
55
+ >
56
+ {progress === 'unknown' && <span className="text-[9px] leading-none">?</span>}
57
+ {progress === 'done' && <CheckIcon className="size-2.5 text-white" strokeWidth={3} />}
58
+ {progress === 'active' && (
59
+ <span
60
+ ref={still ? undefined : ambientMotion}
61
+ className={`${still ? '' : 'status-pulse '}size-1.5 rounded-full bg-(--st-now)`}
62
+ />
63
+ )}
64
+ </span>
65
+ );
66
+ }
67
+
68
+ /** The slices of a piece of work, one SliceRow each. */
69
+ export function SliceList({ children }: { children: ReactNode }) {
70
+ return <ul className="m-0 grid list-none grid-cols-[minmax(0,1fr)] gap-0.5 p-0">{children}</ul>;
71
+ }
72
+
73
+ /** A slice in SliceList: where its ticket is saved, its mark, number, title (struck through when done) and state. */
74
+ export function SliceRow({
75
+ source,
76
+ progress,
77
+ still = false,
78
+ number,
79
+ title,
80
+ }: {
81
+ source: ReactNode;
82
+ progress: SliceProgress;
83
+ still?: boolean;
84
+ /** The slice's ticket number; a slice with none shows none. */
85
+ number?: number | undefined;
86
+ title: string;
87
+ }) {
88
+ return (
89
+ <li className="flex items-start gap-2 rounded-md px-2 py-1 text-[13px] hover:bg-(--soft)">
90
+ {source}
91
+ <span className="mt-0.5">
92
+ <SliceMark progress={progress} still={still} />
93
+ </span>
94
+ {!!number && <span className="shrink-0 text-(--muted-foreground) tabular-nums">#{number}</span>}
95
+ <span
96
+ className={`min-w-0 flex-1 wrap-anywhere ${progress === 'done' ? 'text-(--muted-foreground) line-through' : progress === 'active' ? 'font-medium' : ''}`}
97
+ >
98
+ {title}
99
+ </span>
100
+ <span className="mt-px shrink-0 text-[11px] text-(--muted-foreground)">{progress}</span>
101
+ </li>
102
+ );
103
+ }