@devalok/shilp-sutra 0.36.0 → 0.37.0-next.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 (530) hide show
  1. package/MIGRATION.md +346 -0
  2. package/README.md +26 -29
  3. package/dist/_chunks/badge-group.js +42 -42
  4. package/dist/_chunks/badge-group.js.map +1 -1
  5. package/dist/_chunks/chat.js +324 -327
  6. package/dist/_chunks/chat.js.map +1 -1
  7. package/dist/_chunks/date-picker.js +245 -245
  8. package/dist/_chunks/date-picker.js.map +1 -1
  9. package/dist/_chunks/document-preview.js +33 -33
  10. package/dist/_chunks/document-preview.js.map +1 -1
  11. package/dist/_chunks/file-preview.js +264 -264
  12. package/dist/_chunks/file-preview.js.map +1 -1
  13. package/dist/_chunks/image-preview.js +45 -45
  14. package/dist/_chunks/image-preview.js.map +1 -1
  15. package/dist/_chunks/mention-suggestion.js +85 -85
  16. package/dist/_chunks/mention-suggestion.js.map +1 -1
  17. package/dist/_chunks/motion-provider.js +13 -13
  18. package/dist/_chunks/motion-provider.js.map +1 -1
  19. package/dist/_chunks/popover.js +36 -36
  20. package/dist/_chunks/popover.js.map +1 -1
  21. package/dist/_chunks/primitives.js +489 -489
  22. package/dist/_chunks/primitives.js.map +1 -1
  23. package/dist/_chunks/rich-chat-input.js +1066 -1066
  24. package/dist/_chunks/rich-chat-input.js.map +1 -1
  25. package/dist/_chunks/shared.js +43 -43
  26. package/dist/_chunks/shared.js.map +1 -1
  27. package/dist/_chunks/text.js +432 -0
  28. package/dist/_chunks/text.js.map +1 -0
  29. package/dist/_chunks/tiptap.js +6053 -6187
  30. package/dist/_chunks/tiptap.js.map +1 -1
  31. package/dist/_chunks/tree-view.js +97 -97
  32. package/dist/_chunks/tree-view.js.map +1 -1
  33. package/dist/_chunks/use-calendar.js.map +1 -1
  34. package/dist/ai/ai-command-provider.d.ts.map +1 -1
  35. package/dist/ai/ai-command-provider.js.map +1 -1
  36. package/dist/ai/block-renderer.d.ts.map +1 -1
  37. package/dist/ai/block-renderer.js +43 -43
  38. package/dist/ai/block-renderer.js.map +1 -1
  39. package/dist/ai/blocks/block-table.d.ts.map +1 -1
  40. package/dist/ai/blocks/confirm.d.ts.map +1 -1
  41. package/dist/ai/blocks/divider.d.ts.map +1 -1
  42. package/dist/ai/blocks/error.d.ts.map +1 -1
  43. package/dist/ai/blocks/index.d.ts +5 -5
  44. package/dist/ai/blocks/index.d.ts.map +1 -1
  45. package/dist/ai/blocks/index.js +2 -2
  46. package/dist/ai/blocks/info.d.ts.map +1 -1
  47. package/dist/ai/blocks/loading.d.ts.map +1 -1
  48. package/dist/ai/blocks/stat-row.d.ts.map +1 -1
  49. package/dist/ai/blocks/success.d.ts.map +1 -1
  50. package/dist/ai/blocks/text.d.ts.map +1 -1
  51. package/dist/ai/command-bar.d.ts +0 -11
  52. package/dist/ai/command-bar.d.ts.map +1 -1
  53. package/dist/ai/command-bar.js +128 -128
  54. package/dist/ai/command-bar.js.map +1 -1
  55. package/dist/ai/conversation.d.ts +1 -1
  56. package/dist/ai/conversation.d.ts.map +1 -1
  57. package/dist/ai/conversation.js +76 -76
  58. package/dist/ai/conversation.js.map +1 -1
  59. package/dist/ai/devadoot-icon.d.ts +0 -12
  60. package/dist/ai/devadoot-icon.d.ts.map +1 -1
  61. package/dist/ai/index.d.ts +11 -11
  62. package/dist/ai/index.d.ts.map +1 -1
  63. package/dist/ai/index.js +44 -44
  64. package/dist/ai/index.js.map +1 -1
  65. package/dist/composed/activity-feed.d.ts.map +1 -1
  66. package/dist/composed/activity-feed.js +93 -93
  67. package/dist/composed/activity-feed.js.map +1 -1
  68. package/dist/composed/avatar-group.d.ts.map +1 -1
  69. package/dist/composed/avatar-group.js +50 -50
  70. package/dist/composed/avatar-group.js.map +1 -1
  71. package/dist/composed/bulk-action-bar.d.ts.map +1 -1
  72. package/dist/composed/bulk-action-bar.js +40 -40
  73. package/dist/composed/bulk-action-bar.js.map +1 -1
  74. package/dist/composed/command-palette.d.ts +0 -6
  75. package/dist/composed/command-palette.d.ts.map +1 -1
  76. package/dist/composed/command-palette.js +131 -131
  77. package/dist/composed/command-palette.js.map +1 -1
  78. package/dist/composed/confirm-dialog.d.ts.map +1 -1
  79. package/dist/composed/confirm-dialog.js.map +1 -1
  80. package/dist/composed/content-card.d.ts.map +1 -1
  81. package/dist/composed/content-card.js.map +1 -1
  82. package/dist/composed/date-picker/calendar-grid.d.ts.map +1 -1
  83. package/dist/composed/date-picker/date-picker.d.ts.map +1 -1
  84. package/dist/composed/date-picker/date-range-picker.d.ts.map +1 -1
  85. package/dist/composed/date-picker/date-time-picker.d.ts.map +1 -1
  86. package/dist/composed/date-picker/index.d.ts +11 -11
  87. package/dist/composed/date-picker/index.d.ts.map +1 -1
  88. package/dist/composed/date-picker/index.js +1 -1
  89. package/dist/composed/date-picker/month-picker.d.ts.map +1 -1
  90. package/dist/composed/date-picker/presets.d.ts.map +1 -1
  91. package/dist/composed/date-picker/time-picker.d.ts.map +1 -1
  92. package/dist/composed/date-picker/year-picker.d.ts.map +1 -1
  93. package/dist/composed/deadline-indicator.d.ts.map +1 -1
  94. package/dist/composed/deadline-indicator.js +25 -25
  95. package/dist/composed/deadline-indicator.js.map +1 -1
  96. package/dist/composed/emoji-picker.d.ts.map +1 -1
  97. package/dist/composed/emoji-picker.js +37 -37
  98. package/dist/composed/emoji-picker.js.map +1 -1
  99. package/dist/composed/empty-state.d.ts.map +1 -1
  100. package/dist/composed/empty-state.js +21 -21
  101. package/dist/composed/empty-state.js.map +1 -1
  102. package/dist/composed/error-boundary.d.ts +1 -1
  103. package/dist/composed/error-boundary.d.ts.map +1 -1
  104. package/dist/composed/error-boundary.js.map +1 -1
  105. package/dist/composed/extensions/emoji-node.d.ts.map +1 -1
  106. package/dist/composed/extensions/emoji-suggestion.d.ts.map +1 -1
  107. package/dist/composed/extensions/file-attachment.d.ts.map +1 -1
  108. package/dist/composed/extensions/mention-suggestion.d.ts +1 -1
  109. package/dist/composed/extensions/mention-suggestion.d.ts.map +1 -1
  110. package/dist/composed/extensions/slash-command.d.ts +1 -1
  111. package/dist/composed/extensions/slash-command.d.ts.map +1 -1
  112. package/dist/composed/file-preview/audio-preview.d.ts.map +1 -1
  113. package/dist/composed/file-preview/document-preview.d.ts.map +1 -1
  114. package/dist/composed/file-preview/embed-preview.d.ts.map +1 -1
  115. package/dist/composed/file-preview/image-preview.d.ts.map +1 -1
  116. package/dist/composed/file-preview/shared.d.ts.map +1 -1
  117. package/dist/composed/file-preview/video-preview.d.ts.map +1 -1
  118. package/dist/composed/file-preview.d.ts.map +1 -1
  119. package/dist/composed/filter-bar.d.ts +1 -1
  120. package/dist/composed/filter-bar.d.ts.map +1 -1
  121. package/dist/composed/filter-bar.js +54 -54
  122. package/dist/composed/filter-bar.js.map +1 -1
  123. package/dist/composed/form-section.d.ts.map +1 -1
  124. package/dist/composed/form-section.js +26 -26
  125. package/dist/composed/form-section.js.map +1 -1
  126. package/dist/composed/global-loading.d.ts.map +1 -1
  127. package/dist/composed/global-loading.js.map +1 -1
  128. package/dist/composed/index.d.ts +55 -55
  129. package/dist/composed/index.d.ts.map +1 -1
  130. package/dist/composed/index.js +17 -17
  131. package/dist/composed/inline-edit.d.ts.map +1 -1
  132. package/dist/composed/inline-edit.js.map +1 -1
  133. package/dist/composed/loading-skeleton.d.ts +1 -1
  134. package/dist/composed/loading-skeleton.d.ts.map +1 -1
  135. package/dist/composed/loading-skeleton.js.map +1 -1
  136. package/dist/composed/markdown-viewer.d.ts.map +1 -1
  137. package/dist/composed/markdown-viewer.js +3 -3
  138. package/dist/composed/markdown-viewer.js.map +1 -1
  139. package/dist/composed/master-detail.d.ts.map +1 -1
  140. package/dist/composed/master-detail.js +42 -42
  141. package/dist/composed/master-detail.js.map +1 -1
  142. package/dist/composed/member-picker.d.ts.map +1 -1
  143. package/dist/composed/member-picker.js.map +1 -1
  144. package/dist/composed/multi-select-popover.d.ts.map +1 -1
  145. package/dist/composed/multi-select-popover.js +55 -55
  146. package/dist/composed/multi-select-popover.js.map +1 -1
  147. package/dist/composed/page-header.d.ts.map +1 -1
  148. package/dist/composed/page-header.js.map +1 -1
  149. package/dist/composed/page-skeletons.d.ts.map +1 -1
  150. package/dist/composed/page-skeletons.js.map +1 -1
  151. package/dist/composed/priority-indicator.d.ts.map +1 -1
  152. package/dist/composed/priority-indicator.js +34 -34
  153. package/dist/composed/priority-indicator.js.map +1 -1
  154. package/dist/composed/responsive-overlay.d.ts.map +1 -1
  155. package/dist/composed/responsive-overlay.js.map +1 -1
  156. package/dist/composed/rich-chat-input/attachment-strip.d.ts.map +1 -1
  157. package/dist/composed/rich-chat-input/audio-player.d.ts.map +1 -1
  158. package/dist/composed/rich-chat-input/audio-waveform.d.ts.map +1 -1
  159. package/dist/composed/rich-chat-input/chat-toolbar.d.ts.map +1 -1
  160. package/dist/composed/rich-chat-input/recording-overlay.d.ts.map +1 -1
  161. package/dist/composed/rich-chat-input/reply-banner.d.ts.map +1 -1
  162. package/dist/composed/rich-chat-input/schedule-send.d.ts.map +1 -1
  163. package/dist/composed/rich-chat-input.d.ts +6 -6
  164. package/dist/composed/rich-chat-input.d.ts.map +1 -1
  165. package/dist/composed/rich-chat-input.js +1 -1
  166. package/dist/composed/rich-text-editor.d.ts.map +1 -1
  167. package/dist/composed/rich-text-editor.js +25 -25
  168. package/dist/composed/rich-text-editor.js.map +1 -1
  169. package/dist/composed/schedule-view.d.ts.map +1 -1
  170. package/dist/composed/schedule-view.js +53 -53
  171. package/dist/composed/schedule-view.js.map +1 -1
  172. package/dist/composed/simple-tooltip.d.ts.map +1 -1
  173. package/dist/composed/simple-tooltip.js.map +1 -1
  174. package/dist/composed/status-badge.d.ts +1 -1
  175. package/dist/composed/status-badge.d.ts.map +1 -1
  176. package/dist/composed/status-badge.js +30 -30
  177. package/dist/composed/status-badge.js.map +1 -1
  178. package/dist/hooks/index.d.ts +3 -3
  179. package/dist/hooks/index.d.ts.map +1 -1
  180. package/dist/hooks/index.js +1 -1
  181. package/dist/hooks/use-color-mode.js.map +1 -1
  182. package/dist/hooks/use-toast.d.ts +1 -1
  183. package/dist/hooks/use-toast.d.ts.map +1 -1
  184. package/dist/motion/index.d.ts +2 -2
  185. package/dist/motion/index.d.ts.map +1 -1
  186. package/dist/motion/index.js.map +1 -1
  187. package/dist/motion/motion-provider.d.ts +1 -1
  188. package/dist/motion/motion-provider.d.ts.map +1 -1
  189. package/dist/motion/primitives-index.d.ts +1 -1
  190. package/dist/motion/primitives-index.d.ts.map +1 -1
  191. package/dist/motion/primitives-index.js +40 -40
  192. package/dist/motion/primitives-index.js.map +1 -1
  193. package/dist/motion/primitives.d.ts +1 -1
  194. package/dist/motion/primitives.d.ts.map +1 -1
  195. package/dist/shell/app-command-palette.d.ts +0 -8
  196. package/dist/shell/app-command-palette.d.ts.map +1 -1
  197. package/dist/shell/app-command-palette.js.map +1 -1
  198. package/dist/shell/bottom-navbar.d.ts +0 -6
  199. package/dist/shell/bottom-navbar.d.ts.map +1 -1
  200. package/dist/shell/bottom-navbar.js +62 -62
  201. package/dist/shell/bottom-navbar.js.map +1 -1
  202. package/dist/shell/index.d.ts +8 -8
  203. package/dist/shell/index.d.ts.map +1 -1
  204. package/dist/shell/index.js +5 -5
  205. package/dist/shell/link-context.d.ts +1 -1
  206. package/dist/shell/link-context.d.ts.map +1 -1
  207. package/dist/shell/notification-center.d.ts +0 -6
  208. package/dist/shell/notification-center.d.ts.map +1 -1
  209. package/dist/shell/notification-center.js +54 -54
  210. package/dist/shell/notification-center.js.map +1 -1
  211. package/dist/shell/notification-preferences.d.ts +0 -6
  212. package/dist/shell/notification-preferences.d.ts.map +1 -1
  213. package/dist/shell/notification-preferences.js +22 -22
  214. package/dist/shell/notification-preferences.js.map +1 -1
  215. package/dist/shell/sidebar.d.ts.map +1 -1
  216. package/dist/shell/sidebar.js.map +1 -1
  217. package/dist/shell/top-bar.d.ts +0 -6
  218. package/dist/shell/top-bar.d.ts.map +1 -1
  219. package/dist/shell/top-bar.js.map +1 -1
  220. package/dist/tailwind/index.cjs +15 -499
  221. package/dist/tailwind/preset.d.ts +21 -0
  222. package/dist/tailwind/preset.d.ts.map +1 -1
  223. package/dist/tailwind/preset.js +14 -489
  224. package/dist/tailwind/preset.js.map +1 -1
  225. package/dist/tokens/animations.css +17 -0
  226. package/dist/tokens/base.css +26 -0
  227. package/dist/tokens/index.css +22 -0
  228. package/dist/tokens/semantic.css +436 -464
  229. package/dist/tokens/shilp-sutra.css +41 -0
  230. package/dist/tokens/typography-semantic.css +48 -41
  231. package/dist/tokens/utilities.css +276 -0
  232. package/dist/tokens/variants.css +14 -0
  233. package/dist/ui/accordion.d.ts +2 -2
  234. package/dist/ui/accordion.d.ts.map +1 -1
  235. package/dist/ui/accordion.js +23 -23
  236. package/dist/ui/accordion.js.map +1 -1
  237. package/dist/ui/alert-dialog.d.ts +2 -2
  238. package/dist/ui/alert-dialog.d.ts.map +1 -1
  239. package/dist/ui/alert-dialog.js +37 -37
  240. package/dist/ui/alert-dialog.js.map +1 -1
  241. package/dist/ui/alert.d.ts.map +1 -1
  242. package/dist/ui/alert.js +36 -36
  243. package/dist/ui/alert.js.map +1 -1
  244. package/dist/ui/aspect-ratio.d.ts +1 -1
  245. package/dist/ui/aspect-ratio.d.ts.map +1 -1
  246. package/dist/ui/aspect-ratio.js.map +1 -1
  247. package/dist/ui/autocomplete.d.ts +1 -1
  248. package/dist/ui/autocomplete.d.ts.map +1 -1
  249. package/dist/ui/autocomplete.js +27 -27
  250. package/dist/ui/autocomplete.js.map +1 -1
  251. package/dist/ui/avatar.d.ts +2 -2
  252. package/dist/ui/avatar.d.ts.map +1 -1
  253. package/dist/ui/avatar.js +41 -41
  254. package/dist/ui/avatar.js.map +1 -1
  255. package/dist/ui/badge-group.d.ts.map +1 -1
  256. package/dist/ui/badge-indicator.d.ts.map +1 -1
  257. package/dist/ui/badge-indicator.js +10 -10
  258. package/dist/ui/badge-indicator.js.map +1 -1
  259. package/dist/ui/badge.d.ts +2 -2
  260. package/dist/ui/badge.d.ts.map +1 -1
  261. package/dist/ui/banner.d.ts.map +1 -1
  262. package/dist/ui/banner.js +28 -28
  263. package/dist/ui/banner.js.map +1 -1
  264. package/dist/ui/breadcrumb.d.ts +1 -1
  265. package/dist/ui/breadcrumb.d.ts.map +1 -1
  266. package/dist/ui/breadcrumb.js.map +1 -1
  267. package/dist/ui/button-group.d.ts.map +1 -1
  268. package/dist/ui/button-group.js.map +1 -1
  269. package/dist/ui/button-processing.d.ts.map +1 -1
  270. package/dist/ui/button-processing.js +15 -15
  271. package/dist/ui/button-processing.js.map +1 -1
  272. package/dist/ui/button.d.ts.map +1 -1
  273. package/dist/ui/button.js +84 -84
  274. package/dist/ui/button.js.map +1 -1
  275. package/dist/ui/card.d.ts +1 -1
  276. package/dist/ui/card.d.ts.map +1 -1
  277. package/dist/ui/card.js +28 -28
  278. package/dist/ui/card.js.map +1 -1
  279. package/dist/ui/charts/_internal/axes.d.ts +1 -1
  280. package/dist/ui/charts/_internal/axes.d.ts.map +1 -1
  281. package/dist/ui/charts/_internal/grid-lines.d.ts.map +1 -1
  282. package/dist/ui/charts/_internal/legend.d.ts.map +1 -1
  283. package/dist/ui/charts/_internal/tooltip.d.ts +1 -1
  284. package/dist/ui/charts/_internal/tooltip.d.ts.map +1 -1
  285. package/dist/ui/charts/area-chart.d.ts.map +1 -1
  286. package/dist/ui/charts/bar-chart.d.ts +1 -1
  287. package/dist/ui/charts/bar-chart.d.ts.map +1 -1
  288. package/dist/ui/charts/chart-container.d.ts.map +1 -1
  289. package/dist/ui/charts/gauge-chart.d.ts.map +1 -1
  290. package/dist/ui/charts/index.d.ts +5 -5
  291. package/dist/ui/charts/index.d.ts.map +1 -1
  292. package/dist/ui/charts/index.js +618 -618
  293. package/dist/ui/charts/index.js.map +1 -1
  294. package/dist/ui/charts/line-chart.d.ts.map +1 -1
  295. package/dist/ui/charts/pie-chart.d.ts.map +1 -1
  296. package/dist/ui/charts/radar-chart.d.ts.map +1 -1
  297. package/dist/ui/charts/sparkline.d.ts.map +1 -1
  298. package/dist/ui/chat/date-separator.d.ts.map +1 -1
  299. package/dist/ui/chat/index.d.ts +4 -4
  300. package/dist/ui/chat/index.d.ts.map +1 -1
  301. package/dist/ui/chat/index.js +1 -1
  302. package/dist/ui/chat/message-input.d.ts.map +1 -1
  303. package/dist/ui/chat/message-list.d.ts.map +1 -1
  304. package/dist/ui/chat/message.d.ts +1 -1
  305. package/dist/ui/chat/message.d.ts.map +1 -1
  306. package/dist/ui/chat/system-message.d.ts.map +1 -1
  307. package/dist/ui/chat/typing-indicator.d.ts.map +1 -1
  308. package/dist/ui/chat/unread-separator.d.ts.map +1 -1
  309. package/dist/ui/checkbox.d.ts.map +1 -1
  310. package/dist/ui/checkbox.js +18 -18
  311. package/dist/ui/checkbox.js.map +1 -1
  312. package/dist/ui/code.d.ts.map +1 -1
  313. package/dist/ui/code.js.map +1 -1
  314. package/dist/ui/collapsible.d.ts +2 -2
  315. package/dist/ui/collapsible.d.ts.map +1 -1
  316. package/dist/ui/collapsible.js +10 -10
  317. package/dist/ui/collapsible.js.map +1 -1
  318. package/dist/ui/color-input.d.ts.map +1 -1
  319. package/dist/ui/color-input.js +85 -85
  320. package/dist/ui/color-input.js.map +1 -1
  321. package/dist/ui/color-swatch.d.ts.map +1 -1
  322. package/dist/ui/color-swatch.js.map +1 -1
  323. package/dist/ui/combobox.d.ts.map +1 -1
  324. package/dist/ui/combobox.js +58 -58
  325. package/dist/ui/combobox.js.map +1 -1
  326. package/dist/ui/container.d.ts.map +1 -1
  327. package/dist/ui/container.js.map +1 -1
  328. package/dist/ui/context-menu.d.ts +2 -2
  329. package/dist/ui/context-menu.d.ts.map +1 -1
  330. package/dist/ui/context-menu.js +47 -47
  331. package/dist/ui/context-menu.js.map +1 -1
  332. package/dist/ui/data-table-body.d.ts +1 -1
  333. package/dist/ui/data-table-body.d.ts.map +1 -1
  334. package/dist/ui/data-table-body.js +43 -43
  335. package/dist/ui/data-table-body.js.map +1 -1
  336. package/dist/ui/data-table-bulk-actions.js.map +1 -1
  337. package/dist/ui/data-table-card.d.ts.map +1 -1
  338. package/dist/ui/data-table-card.js +7 -7
  339. package/dist/ui/data-table-card.js.map +1 -1
  340. package/dist/ui/data-table-context.d.ts +1 -1
  341. package/dist/ui/data-table-context.d.ts.map +1 -1
  342. package/dist/ui/data-table-context.js.map +1 -1
  343. package/dist/ui/data-table-header.js +38 -38
  344. package/dist/ui/data-table-header.js.map +1 -1
  345. package/dist/ui/data-table-pagination.js.map +1 -1
  346. package/dist/ui/data-table-toolbar.d.ts.map +1 -1
  347. package/dist/ui/data-table-toolbar.js.map +1 -1
  348. package/dist/ui/data-table.d.ts +2 -2
  349. package/dist/ui/data-table.d.ts.map +1 -1
  350. package/dist/ui/data-table.js +5 -5
  351. package/dist/ui/data-table.js.map +1 -1
  352. package/dist/ui/devalok-grain.js +8 -8
  353. package/dist/ui/devalok-grain.js.map +1 -1
  354. package/dist/ui/dialog.d.ts +2 -2
  355. package/dist/ui/dialog.d.ts.map +1 -1
  356. package/dist/ui/dialog.js +41 -41
  357. package/dist/ui/dialog.js.map +1 -1
  358. package/dist/ui/dropdown-menu.d.ts +2 -2
  359. package/dist/ui/dropdown-menu.d.ts.map +1 -1
  360. package/dist/ui/dropdown-menu.js +46 -46
  361. package/dist/ui/dropdown-menu.js.map +1 -1
  362. package/dist/ui/file-upload.d.ts.map +1 -1
  363. package/dist/ui/file-upload.js +54 -54
  364. package/dist/ui/file-upload.js.map +1 -1
  365. package/dist/ui/form.d.ts.map +1 -1
  366. package/dist/ui/form.js +17 -17
  367. package/dist/ui/form.js.map +1 -1
  368. package/dist/ui/hover-card.d.ts +2 -2
  369. package/dist/ui/hover-card.d.ts.map +1 -1
  370. package/dist/ui/hover-card.js +19 -19
  371. package/dist/ui/hover-card.js.map +1 -1
  372. package/dist/ui/icon-button.d.ts.map +1 -1
  373. package/dist/ui/icon-button.js.map +1 -1
  374. package/dist/ui/icon-group.d.ts.map +1 -1
  375. package/dist/ui/icon-group.js +4 -4
  376. package/dist/ui/icon-group.js.map +1 -1
  377. package/dist/ui/icon.d.ts.map +1 -1
  378. package/dist/ui/icon.js +32 -32
  379. package/dist/ui/icon.js.map +1 -1
  380. package/dist/ui/index.d.ts +57 -57
  381. package/dist/ui/index.d.ts.map +1 -1
  382. package/dist/ui/index.js +27 -27
  383. package/dist/ui/index.js.map +1 -1
  384. package/dist/ui/input-otp.d.ts +1 -1
  385. package/dist/ui/input-otp.d.ts.map +1 -1
  386. package/dist/ui/input-otp.js.map +1 -1
  387. package/dist/ui/input.d.ts.map +1 -1
  388. package/dist/ui/input.js +14 -14
  389. package/dist/ui/input.js.map +1 -1
  390. package/dist/ui/label.d.ts +1 -1
  391. package/dist/ui/label.d.ts.map +1 -1
  392. package/dist/ui/label.js.map +1 -1
  393. package/dist/ui/lib/bottom-sheet.d.ts.map +1 -1
  394. package/dist/ui/lib/index.d.ts +4 -4
  395. package/dist/ui/lib/index.d.ts.map +1 -1
  396. package/dist/ui/lib/slot.d.ts +1 -1
  397. package/dist/ui/lib/slot.d.ts.map +1 -1
  398. package/dist/ui/lib/utils.d.ts.map +1 -1
  399. package/dist/ui/lib/utils.js.map +1 -1
  400. package/dist/ui/link.d.ts.map +1 -1
  401. package/dist/ui/link.js.map +1 -1
  402. package/dist/ui/menubar.d.ts +2 -2
  403. package/dist/ui/menubar.d.ts.map +1 -1
  404. package/dist/ui/menubar.js +64 -64
  405. package/dist/ui/menubar.js.map +1 -1
  406. package/dist/ui/navigation-menu.d.ts +2 -2
  407. package/dist/ui/navigation-menu.d.ts.map +1 -1
  408. package/dist/ui/navigation-menu.js +72 -72
  409. package/dist/ui/navigation-menu.js.map +1 -1
  410. package/dist/ui/number-input.d.ts.map +1 -1
  411. package/dist/ui/number-input.js.map +1 -1
  412. package/dist/ui/pagination.d.ts +1 -1
  413. package/dist/ui/pagination.d.ts.map +1 -1
  414. package/dist/ui/pagination.js.map +1 -1
  415. package/dist/ui/popover.d.ts +2 -2
  416. package/dist/ui/popover.d.ts.map +1 -1
  417. package/dist/ui/progress-ring.d.ts +1 -1
  418. package/dist/ui/progress-ring.d.ts.map +1 -1
  419. package/dist/ui/progress-ring.js +33 -33
  420. package/dist/ui/progress-ring.js.map +1 -1
  421. package/dist/ui/progress.d.ts +2 -2
  422. package/dist/ui/progress.d.ts.map +1 -1
  423. package/dist/ui/progress.js +23 -23
  424. package/dist/ui/progress.js.map +1 -1
  425. package/dist/ui/radio.d.ts.map +1 -1
  426. package/dist/ui/radio.js +19 -19
  427. package/dist/ui/radio.js.map +1 -1
  428. package/dist/ui/search-input.d.ts.map +1 -1
  429. package/dist/ui/search-input.js +17 -17
  430. package/dist/ui/search-input.js.map +1 -1
  431. package/dist/ui/segmented-control.d.ts.map +1 -1
  432. package/dist/ui/segmented-control.js +19 -19
  433. package/dist/ui/segmented-control.js.map +1 -1
  434. package/dist/ui/select.d.ts +2 -2
  435. package/dist/ui/select.d.ts.map +1 -1
  436. package/dist/ui/select.js +68 -68
  437. package/dist/ui/select.js.map +1 -1
  438. package/dist/ui/separator.d.ts +1 -1
  439. package/dist/ui/separator.d.ts.map +1 -1
  440. package/dist/ui/separator.js.map +1 -1
  441. package/dist/ui/sheet.d.ts +2 -2
  442. package/dist/ui/sheet.d.ts.map +1 -1
  443. package/dist/ui/sheet.js +44 -44
  444. package/dist/ui/sheet.js.map +1 -1
  445. package/dist/ui/sidebar.d.ts +1 -1
  446. package/dist/ui/sidebar.d.ts.map +1 -1
  447. package/dist/ui/sidebar.js +156 -156
  448. package/dist/ui/sidebar.js.map +1 -1
  449. package/dist/ui/skeleton.d.ts +1 -1
  450. package/dist/ui/skeleton.d.ts.map +1 -1
  451. package/dist/ui/skeleton.js +2 -2
  452. package/dist/ui/skeleton.js.map +1 -1
  453. package/dist/ui/slider.d.ts +2 -2
  454. package/dist/ui/slider.d.ts.map +1 -1
  455. package/dist/ui/slider.js +5 -5
  456. package/dist/ui/slider.js.map +1 -1
  457. package/dist/ui/spinner.d.ts.map +1 -1
  458. package/dist/ui/spinner.js +21 -21
  459. package/dist/ui/spinner.js.map +1 -1
  460. package/dist/ui/split-button.d.ts +1 -1
  461. package/dist/ui/split-button.d.ts.map +1 -1
  462. package/dist/ui/split-button.js +28 -28
  463. package/dist/ui/split-button.js.map +1 -1
  464. package/dist/ui/stack.d.ts +1 -1
  465. package/dist/ui/stack.d.ts.map +1 -1
  466. package/dist/ui/stack.js.map +1 -1
  467. package/dist/ui/stat-card.d.ts.map +1 -1
  468. package/dist/ui/stat-card.js +73 -73
  469. package/dist/ui/stat-card.js.map +1 -1
  470. package/dist/ui/status-dot.d.ts.map +1 -1
  471. package/dist/ui/status-dot.js.map +1 -1
  472. package/dist/ui/stepper.d.ts +1 -1
  473. package/dist/ui/stepper.d.ts.map +1 -1
  474. package/dist/ui/stepper.js +48 -48
  475. package/dist/ui/stepper.js.map +1 -1
  476. package/dist/ui/switch.d.ts +1 -1
  477. package/dist/ui/switch.d.ts.map +1 -1
  478. package/dist/ui/switch.js +15 -15
  479. package/dist/ui/switch.js.map +1 -1
  480. package/dist/ui/table.d.ts +1 -1
  481. package/dist/ui/table.d.ts.map +1 -1
  482. package/dist/ui/table.js.map +1 -1
  483. package/dist/ui/tabs.d.ts +2 -2
  484. package/dist/ui/tabs.d.ts.map +1 -1
  485. package/dist/ui/tabs.js +52 -52
  486. package/dist/ui/tabs.js.map +1 -1
  487. package/dist/ui/text.d.ts +1 -1
  488. package/dist/ui/text.d.ts.map +1 -1
  489. package/dist/ui/text.js.map +1 -1
  490. package/dist/ui/textarea.d.ts.map +1 -1
  491. package/dist/ui/textarea.js +13 -13
  492. package/dist/ui/textarea.js.map +1 -1
  493. package/dist/ui/toast-registry.js.map +1 -1
  494. package/dist/ui/toast.d.ts +3 -3
  495. package/dist/ui/toast.d.ts.map +1 -1
  496. package/dist/ui/toast.js +164 -164
  497. package/dist/ui/toast.js.map +1 -1
  498. package/dist/ui/toaster.d.ts.map +1 -1
  499. package/dist/ui/toaster.js +6 -6
  500. package/dist/ui/toaster.js.map +1 -1
  501. package/dist/ui/toggle-group.d.ts +1 -1
  502. package/dist/ui/toggle-group.d.ts.map +1 -1
  503. package/dist/ui/toggle-group.js.map +1 -1
  504. package/dist/ui/toggle.d.ts +1 -1
  505. package/dist/ui/toggle.d.ts.map +1 -1
  506. package/dist/ui/toggle.js +14 -14
  507. package/dist/ui/toggle.js.map +1 -1
  508. package/dist/ui/tooltip.d.ts +2 -2
  509. package/dist/ui/tooltip.d.ts.map +1 -1
  510. package/dist/ui/tooltip.js +26 -26
  511. package/dist/ui/tooltip.js.map +1 -1
  512. package/dist/ui/tree-view/index.d.ts +2 -2
  513. package/dist/ui/tree-view/index.d.ts.map +1 -1
  514. package/dist/ui/tree-view/index.js +1 -1
  515. package/dist/ui/tree-view/tree-view.d.ts +1 -1
  516. package/dist/ui/tree-view/tree-view.d.ts.map +1 -1
  517. package/dist/ui/visually-hidden.d.ts.map +1 -1
  518. package/dist/ui/visually-hidden.js.map +1 -1
  519. package/docs/components/_header.md +96 -0
  520. package/docs/rollback.md +179 -0
  521. package/llms-full.txt +97 -1
  522. package/llms.txt +24 -2
  523. package/package.json +296 -277
  524. package/dist/_chunks/framer.js +0 -5604
  525. package/dist/_chunks/framer.js.map +0 -1
  526. package/dist/_chunks/rolldown-runtime.js +0 -21
  527. package/dist/_chunks/sonner.js +0 -616
  528. package/dist/_chunks/sonner.js.map +0 -1
  529. package/dist/_chunks/stat-row.js +0 -432
  530. package/dist/_chunks/stat-row.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"notification-center.js","names":[],"sources":["../../src/shell/notification-center.tsx"],"sourcesContent":["'use client'\n\n/**\n * NotificationCenter -- Popover-based notification panel.\n *\n * Props-driven: accepts notifications array and callbacks instead of\n * reading from Zustand stores or using Remix useNavigate.\n */\nimport * as React from 'react'\nimport { useRef, useCallback } from 'react'\nimport { formatRelativeTime } from '../ui/lib/date-utils'\nimport {\n Popover,\n PopoverContent,\n PopoverTrigger,\n} from '../ui/popover'\nimport {\n Sheet,\n SheetContent,\n SheetTitle,\n SheetTrigger,\n} from '../ui/sheet'\nimport {\n Tooltip,\n TooltipContent,\n TooltipTrigger,\n} from '../ui/tooltip'\nimport { IconBell, IconChecks, IconInbox, IconX } from '@tabler/icons-react'\nimport { Icon } from '../ui/icon'\nimport { cn } from '../ui/lib/utils'\nimport { Spinner } from '../ui/spinner'\nimport { useIsMobile } from '../hooks/use-mobile'\nimport { motion, useReducedMotion } from 'framer-motion'\nimport { durations } from '../ui/lib/motion'\n\n// -----------------------------------------------------------------------\n// Types\n// -----------------------------------------------------------------------\n\nexport interface NotificationAction {\n /** Button label */\n label: string\n /** Visual style — 'primary' is filled, 'default' is ghost, 'danger' is red ghost */\n variant?: 'primary' | 'default' | 'danger'\n /** Called when the action button is clicked. Receives the notification id. */\n onClick: (id: string) => void\n}\n\nexport interface Notification {\n id: string\n title: string\n body?: string | null\n tier: 'INFO' | 'IMPORTANT' | 'CRITICAL'\n isRead: boolean\n createdAt: string\n entityType?: string | null\n entityId?: string | null\n projectId?: string | null\n project?: { title: string } | null\n /** Inline action buttons (e.g. Approve / Deny). Max 2–3 recommended. */\n actions?: NotificationAction[]\n}\n\nexport interface NotificationCenterProps\n extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n /** List of notifications to display */\n notifications?: Notification[]\n /** Count of unread notifications (derived from notifications if not provided) */\n unreadCount?: number\n /** Whether the popover is open (controlled mode) */\n open?: boolean\n /** Called when the popover open state changes */\n onOpenChange?: (open: boolean) => void\n /** Whether more notifications are loading */\n isLoading?: boolean\n /** Whether there are more notifications to fetch */\n hasMore?: boolean\n /** Called when the user scrolls near the bottom to load more */\n onFetchMore?: () => void\n /** Called to mark a single notification as read */\n onMarkRead?: (id: string) => void\n /** Called to mark all notifications as read */\n onMarkAllRead?: () => void\n /** Called when the user clicks a notification (e.g., navigate to entity) */\n onNavigate?: (path: string) => void\n /** Resolve a notification to a navigation path. Return null if no navigation. */\n getNotificationRoute?: (notification: Notification) => string | null\n /** Additional actions rendered in the header (e.g., settings button) */\n headerActions?: React.ReactNode\n /** Custom empty state to display when there are no notifications */\n emptyState?: React.ReactNode\n /** Content rendered below the notification list as a footer */\n footerSlot?: React.ReactNode\n /** Called when the user dismisses a notification. Renders an X button per row when provided. */\n onDismiss?: (id: string) => void\n /** Additional className for the popover content container */\n popoverClassName?: string\n /** Additional className */\n className?: string\n}\n\n// -----------------------------------------------------------------------\n// Helpers\n// -----------------------------------------------------------------------\n\n\nfunction isSameDay(a: Date, b: Date): boolean {\n return (\n a.getFullYear() === b.getFullYear() &&\n a.getMonth() === b.getMonth() &&\n a.getDate() === b.getDate()\n )\n}\n\nfunction getDateGroup(dateStr: string): string {\n const date = new Date(dateStr)\n const today = new Date()\n const yesterday = new Date()\n yesterday.setDate(today.getDate() - 1)\n\n if (isSameDay(date, today)) return 'Today'\n if (isSameDay(date, yesterday)) return 'Yesterday'\n return 'Earlier'\n}\n\nconst TIER_COLORS: Record<string, string> = {\n INFO: 'bg-info-9',\n IMPORTANT: 'bg-warning-9',\n CRITICAL: 'bg-error-9',\n}\n\n// -----------------------------------------------------------------------\n// NotificationItem (internal)\n// -----------------------------------------------------------------------\n\nfunction NotificationItem({\n notification,\n onRead,\n onNavigate,\n getRoute,\n onDismiss,\n}: {\n notification: Notification\n onRead: (id: string) => void\n onNavigate: (path: string) => void\n getRoute: (notification: Notification) => string | null\n onDismiss?: (id: string) => void\n}) {\n const route = getRoute(notification)\n\n const handleClick = () => {\n if (!notification.isRead) {\n onRead(notification.id)\n }\n if (route) {\n onNavigate(route)\n }\n }\n\n const handleKeyDown = (e: React.KeyboardEvent) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault()\n handleClick()\n }\n }\n\n return (\n <div\n role=\"button\"\n tabIndex={0}\n onClick={handleClick}\n onKeyDown={handleKeyDown}\n className={cn(\n 'group relative flex w-full cursor-pointer items-start gap-ds-04 px-ds-05 py-ds-04 text-left transition-colors duration-fast-02 ease-productive-standard',\n 'hover:bg-surface-raised',\n !notification.isRead && 'bg-accent-1',\n )}\n >\n {/* Tier dot — doubles as read/unread marker */}\n <div className=\"mt-ds-02b flex shrink-0\">\n <span\n className={cn(\n 'h-[8px] w-[8px] rounded-ds-full transition-opacity duration-fast-02 ease-productive-standard',\n TIER_COLORS[notification.tier] || TIER_COLORS.INFO,\n notification.isRead ? 'opacity-20' : 'opacity-100',\n )}\n />\n </div>\n\n {/* Content */}\n <div className=\"min-w-0 flex-1\">\n <p\n className={cn(\n 'truncate text-ds-md text-surface-fg',\n !notification.isRead && 'font-semibold',\n )}\n >\n {notification.title}\n </p>\n {notification.body && (\n <p className=\"mt-ds-01 line-clamp-2 text-ds-sm text-surface-fg-subtle\">\n {notification.body}\n </p>\n )}\n <div className=\"mt-ds-02 flex items-center gap-ds-03\">\n <span className=\"text-ds-sm text-surface-fg-subtle\">\n {formatRelativeTime(notification.createdAt)}\n </span>\n {notification.project && (\n <>\n <span className=\"text-surface-fg-subtle\">\n &middot;\n </span>\n <span className=\"truncate text-ds-sm text-surface-fg-subtle\">\n {notification.project.title}\n </span>\n </>\n )}\n </div>\n\n {/* Inline actions */}\n {notification.actions && notification.actions.length > 0 && (\n <div className=\"mt-ds-03 flex items-center gap-ds-02\">\n {notification.actions.map((action) => (\n <button\n key={action.label}\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation()\n action.onClick(notification.id)\n }}\n onKeyDown={(e) => e.stopPropagation()}\n className={cn(\n 'rounded-ds-md px-ds-03 py-ds-01 text-ds-sm font-medium transition-colors duration-fast-02 ease-productive-standard',\n action.variant === 'primary'\n ? 'bg-accent-9 text-accent-fg hover:bg-accent-10'\n : action.variant === 'danger'\n ? 'text-error-11 hover:bg-error-3'\n : 'text-surface-fg-muted hover:bg-surface-raised-hover',\n )}\n >\n {action.label}\n </button>\n ))}\n </div>\n )}\n </div>\n\n {/* Dismiss button */}\n {onDismiss && (\n <button\n type=\"button\"\n aria-label={`Dismiss notification: ${notification.title}`}\n onClick={(e) => {\n e.stopPropagation()\n onDismiss(notification.id)\n }}\n onKeyDown={(e) => e.stopPropagation()}\n className=\"absolute right-ds-03 top-ds-03 hidden rounded-ds-sm p-ds-01 text-surface-fg-subtle transition-[color,background-color,opacity] duration-fast-01 ease-productive-standard hover:bg-surface-raised-hover hover:text-surface-fg-muted group-hover:flex group-focus-within:flex\"\n >\n <Icon icon={IconX} size=\"sm\" />\n </button>\n )}\n </div>\n )\n}\n\n// -----------------------------------------------------------------------\n// NotificationCenter\n// -----------------------------------------------------------------------\n\nconst NotificationCenter = React.forwardRef<HTMLButtonElement, NotificationCenterProps>(\n (\n {\n notifications = [],\n unreadCount: unreadCountProp,\n open,\n onOpenChange,\n isLoading = false,\n hasMore = false,\n onFetchMore,\n onMarkRead,\n onMarkAllRead,\n onNavigate,\n getNotificationRoute,\n onDismiss,\n headerActions,\n emptyState,\n footerSlot,\n popoverClassName,\n className,\n ...props\n },\n ref,\n ) => {\n const scrollRef = useRef<HTMLDivElement>(null)\n const prefersReducedMotion = useReducedMotion()\n const isMobile = useIsMobile()\n\n const unreadCount =\n unreadCountProp ?? notifications.filter((n) => !n.isRead).length\n\n const getRoute = getNotificationRoute ?? (() => null)\n\n const handleNavigate = useCallback(\n (path: string) => {\n onOpenChange?.(false)\n onNavigate?.(path)\n },\n [onNavigate, onOpenChange],\n )\n\n const handleMarkRead = useCallback(\n (id: string) => {\n onMarkRead?.(id)\n },\n [onMarkRead],\n )\n\n const handleScroll = useCallback(() => {\n const el = scrollRef.current\n if (!el || isLoading || !hasMore) return\n if (el.scrollTop + el.clientHeight >= el.scrollHeight - 50) {\n onFetchMore?.()\n }\n }, [isLoading, hasMore, onFetchMore])\n\n // Group notifications by date\n const grouped = notifications.reduce<Record<string, Notification[]>>(\n (acc, n) => {\n const group = getDateGroup(n.createdAt)\n if (!acc[group]) acc[group] = []\n acc[group].push(n)\n return acc\n },\n {},\n )\n\n const groupOrder = ['Today', 'Yesterday', 'Earlier']\n\n // -- Shared panel content (used in both Popover and Sheet) --\n const panelContent = (\n <>\n {/* Header */}\n <div className=\"flex items-center justify-between border-b border-surface-border-strong px-ds-05 py-ds-04\">\n <div className=\"flex items-center gap-ds-03\">\n {/* On mobile the SheetTitle provides the accessible heading; on desktop use h3 */}\n {!isMobile && (\n <h3 className=\"text-ds-md font-semibold text-surface-fg\">\n Notifications\n </h3>\n )}\n {unreadCount > 0 && (\n <span className=\"flex h-5 min-w-5 items-center justify-center rounded-ds-full bg-accent-2 px-ds-02b text-ds-sm font-semibold text-accent-11\">\n {unreadCount}\n </span>\n )}\n </div>\n <div className=\"flex items-center gap-ds-03\">\n {unreadCount > 0 && onMarkAllRead && (\n <button\n type=\"button\"\n onClick={onMarkAllRead}\n className=\"flex items-center gap-ds-02 text-ds-sm text-surface-fg-subtle transition-colors hover:text-accent-11\"\n >\n <Icon icon={IconChecks} size=\"sm\" />\n Mark all read\n </button>\n )}\n {headerActions}\n </div>\n </div>\n\n {/* Notification list */}\n <div\n ref={scrollRef}\n onScroll={handleScroll}\n className={cn('overflow-y-auto', isMobile ? 'max-h-[60vh]' : 'max-h-[420px]')}\n >\n {notifications.length === 0 ? (\n emptyState || (\n <div className=\"flex flex-col items-center justify-center px-ds-05 py-ds-09\">\n <div className=\"flex h-ds-lg w-ds-lg items-center justify-center rounded-ds-full bg-surface-raised\">\n <Icon icon={IconInbox} size=\"lg\" className=\"text-surface-fg-subtle\" />\n </div>\n <p className=\"mt-ds-04 text-ds-md text-surface-fg-subtle\">\n No notifications yet\n </p>\n <p className=\"mt-ds-02 text-ds-sm text-surface-fg-subtle\">\n You&apos;re all caught up!\n </p>\n </div>\n )\n ) : (\n groupOrder.map((group) => {\n const items = grouped[group]\n if (!items || items.length === 0) return null\n return (\n <div key={group}>\n <div className=\"sticky top-0 z-raised bg-surface-overlay px-ds-05 py-ds-02b\">\n <span className=\"text-ds-sm font-medium text-surface-fg-subtle\">\n {group}\n </span>\n </div>\n {items.map((notification, index) => (\n <motion.div\n key={notification.id}\n initial={prefersReducedMotion ? undefined : { opacity: 0 }}\n animate={{ opacity: 1 }}\n transition={prefersReducedMotion ? { duration: 0 } : { delay: index * 0.03 }}\n >\n <NotificationItem\n notification={notification}\n onRead={handleMarkRead}\n onNavigate={handleNavigate}\n getRoute={getRoute}\n onDismiss={onDismiss}\n />\n </motion.div>\n ))}\n </div>\n )\n })\n )}\n\n {isLoading && (\n <div className=\"flex items-center justify-center py-ds-05\">\n <Spinner />\n </div>\n )}\n </div>\n {footerSlot && (\n <div className=\"border-t border-surface-border-strong px-ds-05 py-ds-03\">\n {footerSlot}\n </div>\n )}\n </>\n )\n\n // -- Trigger button (shared between both modes) --\n const triggerButton = (\n <button\n {...props}\n ref={ref}\n aria-label={unreadCount > 0 ? `Notifications, ${unreadCount} unread` : 'Notifications'}\n className={cn(\n 'relative flex h-ds-sm-plus w-ds-sm-plus items-center justify-center rounded-ds-full border border-surface-border-strong bg-surface-raised text-surface-fg-muted transition-colors ease-productive-standard hover:bg-surface-raised-hover',\n className,\n )}\n >\n <Icon icon={IconBell} size=\"sm\" />\n {unreadCount > 0 && (\n <motion.span\n initial={{ rotate: 0 }}\n animate={prefersReducedMotion ? undefined : { rotate: [0, -3, 3, -1, 1, 0] }}\n transition={prefersReducedMotion ? { duration: 0 } : { duration: durations.slow01, ease: 'easeInOut' }}\n className=\"absolute -right-ds-01 -top-ds-01 flex h-4 min-w-4 items-center justify-center rounded-ds-full bg-accent-9 px-ds-02 text-ds-xs font-semibold text-accent-fg\"\n >\n {unreadCount > 99 ? '99+' : unreadCount}\n </motion.span>\n )}\n </button>\n )\n\n // -- Mobile: render in a bottom Sheet --\n if (isMobile) {\n return (\n <Sheet open={open} onOpenChange={onOpenChange}>\n <Tooltip>\n <TooltipTrigger asChild>\n <SheetTrigger asChild>\n {triggerButton}\n </SheetTrigger>\n </TooltipTrigger>\n <TooltipContent side=\"bottom\" align=\"center\">\n Notifications\n </TooltipContent>\n </Tooltip>\n\n <SheetContent side=\"bottom\" className={cn('p-0', popoverClassName)} responsive={false}>\n <SheetTitle className=\"px-ds-05 pt-ds-04 text-ds-md font-semibold text-surface-fg\">\n Notifications\n </SheetTitle>\n {panelContent}\n </SheetContent>\n </Sheet>\n )\n }\n\n // -- Desktop: render in a Popover --\n return (\n <Popover open={open} onOpenChange={onOpenChange}>\n <Tooltip>\n <TooltipTrigger asChild>\n <PopoverTrigger asChild>\n {triggerButton}\n </PopoverTrigger>\n </TooltipTrigger>\n <TooltipContent side=\"bottom\" align=\"center\">\n Notifications\n </TooltipContent>\n </Tooltip>\n\n <PopoverContent\n className={cn(\n 'w-[380px] rounded-ds-xl border border-surface-border-strong bg-surface-overlay p-0 shadow-floating',\n popoverClassName,\n )}\n sideOffset={8}\n align=\"end\"\n >\n {panelContent}\n </PopoverContent>\n </Popover>\n )\n },\n)\nNotificationCenter.displayName = 'NotificationCenter'\n\nexport { NotificationCenter }\n"],"mappings":"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"}
1
+ {"version":3,"file":"notification-center.js","names":[],"sources":["../../src/shell/notification-center.tsx"],"sourcesContent":["'use client'\n\n/**\n * NotificationCenter -- Popover-based notification panel.\n *\n * Props-driven: accepts notifications array and callbacks instead of\n * reading from Zustand stores or using Remix useNavigate.\n */\nimport { IconBell, IconChecks, IconInbox, IconX } from '@tabler/icons-react'\nimport { motion, useReducedMotion } from 'framer-motion'\nimport * as React from 'react'\nimport { useCallback,useRef } from 'react'\n\nimport { useIsMobile } from '../hooks/use-mobile'\nimport { Icon } from '../ui/icon'\nimport { formatRelativeTime } from '../ui/lib/date-utils'\nimport { durations } from '../ui/lib/motion'\nimport { cn } from '../ui/lib/utils'\nimport {\n Popover,\n PopoverContent,\n PopoverTrigger,\n} from '../ui/popover'\nimport {\n Sheet,\n SheetContent,\n SheetTitle,\n SheetTrigger,\n} from '../ui/sheet'\nimport { Spinner } from '../ui/spinner'\nimport {\n Tooltip,\n TooltipContent,\n TooltipTrigger,\n} from '../ui/tooltip'\n\n// -----------------------------------------------------------------------\n// Types\n// -----------------------------------------------------------------------\n\nexport interface NotificationAction {\n /** Button label */\n label: string\n /** Visual style — 'primary' is filled, 'default' is ghost, 'danger' is red ghost */\n variant?: 'primary' | 'default' | 'danger'\n /** Called when the action button is clicked. Receives the notification id. */\n onClick: (id: string) => void\n}\n\nexport interface Notification {\n id: string\n title: string\n body?: string | null\n tier: 'INFO' | 'IMPORTANT' | 'CRITICAL'\n isRead: boolean\n createdAt: string\n entityType?: string | null\n entityId?: string | null\n projectId?: string | null\n project?: { title: string } | null\n /** Inline action buttons (e.g. Approve / Deny). Max 2–3 recommended. */\n actions?: NotificationAction[]\n}\n\nexport interface NotificationCenterProps\n extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n /** List of notifications to display */\n notifications?: Notification[]\n /** Count of unread notifications (derived from notifications if not provided) */\n unreadCount?: number\n /** Whether the popover is open (controlled mode) */\n open?: boolean\n /** Called when the popover open state changes */\n onOpenChange?: (open: boolean) => void\n /** Whether more notifications are loading */\n isLoading?: boolean\n /** Whether there are more notifications to fetch */\n hasMore?: boolean\n /** Called when the user scrolls near the bottom to load more */\n onFetchMore?: () => void\n /** Called to mark a single notification as read */\n onMarkRead?: (id: string) => void\n /** Called to mark all notifications as read */\n onMarkAllRead?: () => void\n /** Called when the user clicks a notification (e.g., navigate to entity) */\n onNavigate?: (path: string) => void\n /** Resolve a notification to a navigation path. Return null if no navigation. */\n getNotificationRoute?: (notification: Notification) => string | null\n /** Additional actions rendered in the header (e.g., settings button) */\n headerActions?: React.ReactNode\n /** Custom empty state to display when there are no notifications */\n emptyState?: React.ReactNode\n /** Content rendered below the notification list as a footer */\n footerSlot?: React.ReactNode\n /** Called when the user dismisses a notification. Renders an X button per row when provided. */\n onDismiss?: (id: string) => void\n /** Additional className for the popover content container */\n popoverClassName?: string\n /** Additional className */\n className?: string\n}\n\n// -----------------------------------------------------------------------\n// Helpers\n// -----------------------------------------------------------------------\n\n\nfunction isSameDay(a: Date, b: Date): boolean {\n return (\n a.getFullYear() === b.getFullYear() &&\n a.getMonth() === b.getMonth() &&\n a.getDate() === b.getDate()\n )\n}\n\nfunction getDateGroup(dateStr: string): string {\n const date = new Date(dateStr)\n const today = new Date()\n const yesterday = new Date()\n yesterday.setDate(today.getDate() - 1)\n\n if (isSameDay(date, today)) return 'Today'\n if (isSameDay(date, yesterday)) return 'Yesterday'\n return 'Earlier'\n}\n\nconst TIER_COLORS: Record<string, string> = {\n INFO: 'bg-info-9',\n IMPORTANT: 'bg-warning-9',\n CRITICAL: 'bg-error-9',\n}\n\n// -----------------------------------------------------------------------\n// NotificationItem (internal)\n// -----------------------------------------------------------------------\n\nfunction NotificationItem({\n notification,\n onRead,\n onNavigate,\n getRoute,\n onDismiss,\n}: {\n notification: Notification\n onRead: (id: string) => void\n onNavigate: (path: string) => void\n getRoute: (notification: Notification) => string | null\n onDismiss?: (id: string) => void\n}) {\n const route = getRoute(notification)\n\n const handleClick = () => {\n if (!notification.isRead) {\n onRead(notification.id)\n }\n if (route) {\n onNavigate(route)\n }\n }\n\n const handleKeyDown = (e: React.KeyboardEvent) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault()\n handleClick()\n }\n }\n\n return (\n <div\n role=\"button\"\n tabIndex={0}\n onClick={handleClick}\n onKeyDown={handleKeyDown}\n className={cn(\n 'group relative flex w-full cursor-pointer items-start gap-ds-04 px-ds-05 py-ds-04 text-left transition-colors duration-fast-02 ease-productive-standard',\n 'hover:bg-surface-raised',\n !notification.isRead && 'bg-accent-1',\n )}\n >\n {/* Tier dot — doubles as read/unread marker */}\n <div className=\"mt-ds-02b flex shrink-0\">\n <span\n className={cn(\n 'h-[8px] w-[8px] rounded-ds-full transition-opacity duration-fast-02 ease-productive-standard',\n TIER_COLORS[notification.tier] || TIER_COLORS.INFO,\n notification.isRead ? 'opacity-20' : 'opacity-100',\n )}\n />\n </div>\n\n {/* Content */}\n <div className=\"min-w-0 flex-1\">\n <p\n className={cn(\n 'truncate text-ds-md text-surface-fg',\n !notification.isRead && 'font-semibold',\n )}\n >\n {notification.title}\n </p>\n {notification.body && (\n <p className=\"mt-ds-01 line-clamp-2 text-ds-sm text-surface-fg-subtle\">\n {notification.body}\n </p>\n )}\n <div className=\"mt-ds-02 flex items-center gap-ds-03\">\n <span className=\"text-ds-sm text-surface-fg-subtle\">\n {formatRelativeTime(notification.createdAt)}\n </span>\n {notification.project && (\n <>\n <span className=\"text-surface-fg-subtle\">\n &middot;\n </span>\n <span className=\"truncate text-ds-sm text-surface-fg-subtle\">\n {notification.project.title}\n </span>\n </>\n )}\n </div>\n\n {/* Inline actions */}\n {notification.actions && notification.actions.length > 0 && (\n <div className=\"mt-ds-03 flex items-center gap-ds-02\">\n {notification.actions.map((action) => (\n <button\n key={action.label}\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation()\n action.onClick(notification.id)\n }}\n onKeyDown={(e) => e.stopPropagation()}\n className={cn(\n 'rounded-ds-md px-ds-03 py-ds-01 text-ds-sm font-medium transition-colors duration-fast-02 ease-productive-standard',\n action.variant === 'primary'\n ? 'bg-accent-9 text-accent-fg hover:bg-accent-10'\n : action.variant === 'danger'\n ? 'text-error-11 hover:bg-error-3'\n : 'text-surface-fg-muted hover:bg-surface-raised-hover',\n )}\n >\n {action.label}\n </button>\n ))}\n </div>\n )}\n </div>\n\n {/* Dismiss button */}\n {onDismiss && (\n <button\n type=\"button\"\n aria-label={`Dismiss notification: ${notification.title}`}\n onClick={(e) => {\n e.stopPropagation()\n onDismiss(notification.id)\n }}\n onKeyDown={(e) => e.stopPropagation()}\n className=\"absolute right-ds-03 top-ds-03 hidden rounded-ds-sm p-ds-01 text-surface-fg-subtle transition-[color,background-color,opacity] duration-fast-01 ease-productive-standard hover:bg-surface-raised-hover hover:text-surface-fg-muted group-hover:flex group-focus-within:flex\"\n >\n <Icon icon={IconX} size=\"sm\" />\n </button>\n )}\n </div>\n )\n}\n\n// -----------------------------------------------------------------------\n// NotificationCenter\n// -----------------------------------------------------------------------\n\nconst NotificationCenter = React.forwardRef<HTMLButtonElement, NotificationCenterProps>(\n (\n {\n notifications = [],\n unreadCount: unreadCountProp,\n open,\n onOpenChange,\n isLoading = false,\n hasMore = false,\n onFetchMore,\n onMarkRead,\n onMarkAllRead,\n onNavigate,\n getNotificationRoute,\n onDismiss,\n headerActions,\n emptyState,\n footerSlot,\n popoverClassName,\n className,\n ...props\n },\n ref,\n ) => {\n const scrollRef = useRef<HTMLDivElement>(null)\n const prefersReducedMotion = useReducedMotion()\n const isMobile = useIsMobile()\n\n const unreadCount =\n unreadCountProp ?? notifications.filter((n) => !n.isRead).length\n\n const getRoute = getNotificationRoute ?? (() => null)\n\n const handleNavigate = useCallback(\n (path: string) => {\n onOpenChange?.(false)\n onNavigate?.(path)\n },\n [onNavigate, onOpenChange],\n )\n\n const handleMarkRead = useCallback(\n (id: string) => {\n onMarkRead?.(id)\n },\n [onMarkRead],\n )\n\n const handleScroll = useCallback(() => {\n const el = scrollRef.current\n if (!el || isLoading || !hasMore) return\n if (el.scrollTop + el.clientHeight >= el.scrollHeight - 50) {\n onFetchMore?.()\n }\n }, [isLoading, hasMore, onFetchMore])\n\n // Group notifications by date\n const grouped = notifications.reduce<Record<string, Notification[]>>(\n (acc, n) => {\n const group = getDateGroup(n.createdAt)\n if (!acc[group]) acc[group] = []\n acc[group].push(n)\n return acc\n },\n {},\n )\n\n const groupOrder = ['Today', 'Yesterday', 'Earlier']\n\n // -- Shared panel content (used in both Popover and Sheet) --\n const panelContent = (\n <>\n {/* Header */}\n <div className=\"flex items-center justify-between border-b border-surface-border-strong px-ds-05 py-ds-04\">\n <div className=\"flex items-center gap-ds-03\">\n {/* On mobile the SheetTitle provides the accessible heading; on desktop use h3 */}\n {!isMobile && (\n <h3 className=\"text-ds-md font-semibold text-surface-fg\">\n Notifications\n </h3>\n )}\n {unreadCount > 0 && (\n <span className=\"flex h-5 min-w-5 items-center justify-center rounded-ds-full bg-accent-2 px-ds-02b text-ds-sm font-semibold text-accent-11\">\n {unreadCount}\n </span>\n )}\n </div>\n <div className=\"flex items-center gap-ds-03\">\n {unreadCount > 0 && onMarkAllRead && (\n <button\n type=\"button\"\n onClick={onMarkAllRead}\n className=\"flex items-center gap-ds-02 text-ds-sm text-surface-fg-subtle transition-colors hover:text-accent-11\"\n >\n <Icon icon={IconChecks} size=\"sm\" />\n Mark all read\n </button>\n )}\n {headerActions}\n </div>\n </div>\n\n {/* Notification list */}\n <div\n ref={scrollRef}\n onScroll={handleScroll}\n className={cn('overflow-y-auto', isMobile ? 'max-h-[60vh]' : 'max-h-[420px]')}\n >\n {notifications.length === 0 ? (\n emptyState || (\n <div className=\"flex flex-col items-center justify-center px-ds-05 py-ds-09\">\n <div className=\"flex h-ds-lg w-ds-lg items-center justify-center rounded-ds-full bg-surface-raised\">\n <Icon icon={IconInbox} size=\"lg\" className=\"text-surface-fg-subtle\" />\n </div>\n <p className=\"mt-ds-04 text-ds-md text-surface-fg-subtle\">\n No notifications yet\n </p>\n <p className=\"mt-ds-02 text-ds-sm text-surface-fg-subtle\">\n You&apos;re all caught up!\n </p>\n </div>\n )\n ) : (\n groupOrder.map((group) => {\n const items = grouped[group]\n if (!items || items.length === 0) return null\n return (\n <div key={group}>\n <div className=\"sticky top-0 z-raised bg-surface-overlay px-ds-05 py-ds-02b\">\n <span className=\"text-ds-sm font-medium text-surface-fg-subtle\">\n {group}\n </span>\n </div>\n {items.map((notification, index) => (\n <motion.div\n key={notification.id}\n initial={prefersReducedMotion ? undefined : { opacity: 0 }}\n animate={{ opacity: 1 }}\n transition={prefersReducedMotion ? { duration: 0 } : { delay: index * 0.03 }}\n >\n <NotificationItem\n notification={notification}\n onRead={handleMarkRead}\n onNavigate={handleNavigate}\n getRoute={getRoute}\n onDismiss={onDismiss}\n />\n </motion.div>\n ))}\n </div>\n )\n })\n )}\n\n {isLoading && (\n <div className=\"flex items-center justify-center py-ds-05\">\n <Spinner />\n </div>\n )}\n </div>\n {footerSlot && (\n <div className=\"border-t border-surface-border-strong px-ds-05 py-ds-03\">\n {footerSlot}\n </div>\n )}\n </>\n )\n\n // -- Trigger button (shared between both modes) --\n const triggerButton = (\n <button\n {...props}\n ref={ref}\n aria-label={unreadCount > 0 ? `Notifications, ${unreadCount} unread` : 'Notifications'}\n className={cn(\n 'relative flex h-ds-sm-plus w-ds-sm-plus items-center justify-center rounded-ds-full border border-surface-border-strong bg-surface-raised text-surface-fg-muted transition-colors ease-productive-standard hover:bg-surface-raised-hover',\n className,\n )}\n >\n <Icon icon={IconBell} size=\"sm\" />\n {unreadCount > 0 && (\n <motion.span\n initial={{ rotate: 0 }}\n animate={prefersReducedMotion ? undefined : { rotate: [0, -3, 3, -1, 1, 0] }}\n transition={prefersReducedMotion ? { duration: 0 } : { duration: durations.slow01, ease: 'easeInOut' }}\n className=\"absolute -right-ds-01 -top-ds-01 flex h-4 min-w-4 items-center justify-center rounded-ds-full bg-accent-9 px-ds-02 text-ds-xs font-semibold text-accent-fg\"\n >\n {unreadCount > 99 ? '99+' : unreadCount}\n </motion.span>\n )}\n </button>\n )\n\n // -- Mobile: render in a bottom Sheet --\n if (isMobile) {\n return (\n <Sheet open={open} onOpenChange={onOpenChange}>\n <Tooltip>\n <TooltipTrigger asChild>\n <SheetTrigger asChild>\n {triggerButton}\n </SheetTrigger>\n </TooltipTrigger>\n <TooltipContent side=\"bottom\" align=\"center\">\n Notifications\n </TooltipContent>\n </Tooltip>\n\n <SheetContent side=\"bottom\" className={cn('p-0', popoverClassName)} responsive={false}>\n <SheetTitle className=\"px-ds-05 pt-ds-04 text-ds-md font-semibold text-surface-fg\">\n Notifications\n </SheetTitle>\n {panelContent}\n </SheetContent>\n </Sheet>\n )\n }\n\n // -- Desktop: render in a Popover --\n return (\n <Popover open={open} onOpenChange={onOpenChange}>\n <Tooltip>\n <TooltipTrigger asChild>\n <PopoverTrigger asChild>\n {triggerButton}\n </PopoverTrigger>\n </TooltipTrigger>\n <TooltipContent side=\"bottom\" align=\"center\">\n Notifications\n </TooltipContent>\n </Tooltip>\n\n <PopoverContent\n className={cn(\n 'w-[380px] rounded-ds-xl border border-surface-border-strong bg-surface-overlay p-0 shadow-floating',\n popoverClassName,\n )}\n sideOffset={8}\n align=\"end\"\n >\n {panelContent}\n </PopoverContent>\n </Popover>\n )\n },\n)\nNotificationCenter.displayName = 'NotificationCenter'\n\nexport { NotificationCenter }\n"],"mappings":"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"}
@@ -1,10 +1,4 @@
1
1
  "use client";
2
- /**
3
- * NotificationPreferences -- Manage notification rules per channel/project.
4
- *
5
- * Props-driven: accepts preferences array, projects, and callbacks.
6
- * No internal fetching -- the consumer is responsible for data loading.
7
- */
8
2
  import * as React from 'react';
9
3
  export interface NotificationPreference {
10
4
  id: string;
@@ -1 +1 @@
1
- {"version":3,"file":"notification-preferences.d.ts","sourceRoot":"","sources":["../../src/shell/notification-preferences.tsx"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AA4B9B,MAAM,WAAW,sBAAsB;IACrC,EAAE,EAAE,MAAM,CAAA;IACV,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,EAAE,OAAO,CAAA;CACf;AAED,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;CACd;AAED,MAAM,WAAW,4BACf,SAAQ,IAAI,CAAC,KAAK,CAAC,qBAAqB,CAAC,KAAK,CAAC,EAAE,QAAQ,CAAC;IAC1D,+BAA+B;IAC/B,WAAW,CAAC,EAAE,sBAAsB,EAAE,CAAA;IACtC,2CAA2C;IAC3C,QAAQ,CAAC,EAAE,mBAAmB,EAAE,CAAA;IAChC,8BAA8B;IAC9B,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,2CAA2C;IAC3C,MAAM,CAAC,EAAE,CAAC,UAAU,EAAE;QACpB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;QACxB,OAAO,EAAE,MAAM,CAAA;QACf,OAAO,EAAE,MAAM,CAAA;QACf,KAAK,EAAE,OAAO,CAAA;KACf,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC1B,4CAA4C;IAC5C,YAAY,CAAC,EAAE,CAAC,UAAU,EAAE,sBAAsB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC3E,gDAAgD;IAChD,YAAY,CAAC,EAAE,CACb,UAAU,EAAE,sBAAsB,EAClC,OAAO,EAAE,MAAM,KACZ,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACzB,oCAAoC;IACpC,QAAQ,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACzD,2BAA2B;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAqBD,QAAA,MAAM,uBAAuB,kHA0P5B,CAAA;AAID,OAAO,EAAE,uBAAuB,EAAE,CAAA"}
1
+ {"version":3,"file":"notification-preferences.d.ts","sourceRoot":"","sources":["../../src/shell/notification-preferences.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AA4B9B,MAAM,WAAW,sBAAsB;IACrC,EAAE,EAAE,MAAM,CAAA;IACV,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,EAAE,OAAO,CAAA;CACf;AAED,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;CACd;AAED,MAAM,WAAW,4BACf,SAAQ,IAAI,CAAC,KAAK,CAAC,qBAAqB,CAAC,KAAK,CAAC,EAAE,QAAQ,CAAC;IAC1D,+BAA+B;IAC/B,WAAW,CAAC,EAAE,sBAAsB,EAAE,CAAA;IACtC,2CAA2C;IAC3C,QAAQ,CAAC,EAAE,mBAAmB,EAAE,CAAA;IAChC,8BAA8B;IAC9B,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,2CAA2C;IAC3C,MAAM,CAAC,EAAE,CAAC,UAAU,EAAE;QACpB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;QACxB,OAAO,EAAE,MAAM,CAAA;QACf,OAAO,EAAE,MAAM,CAAA;QACf,KAAK,EAAE,OAAO,CAAA;KACf,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC1B,4CAA4C;IAC5C,YAAY,CAAC,EAAE,CAAC,UAAU,EAAE,sBAAsB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC3E,gDAAgD;IAChD,YAAY,CAAC,EAAE,CACb,UAAU,EAAE,sBAAsB,EAClC,OAAO,EAAE,MAAM,KACZ,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACzB,oCAAoC;IACpC,QAAQ,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACzD,2BAA2B;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAqBD,QAAA,MAAM,uBAAuB,kHA0P5B,CAAA;AAID,OAAO,EAAE,uBAAuB,EAAE,CAAA"}
@@ -5,8 +5,8 @@ import { Icon as n } from "../ui/icon.js";
5
5
  import { Button as r } from "../ui/button.js";
6
6
  import { Card as i, CardContent as a, CardHeader as o, CardTitle as s } from "../ui/card.js";
7
7
  import { Dialog as c, DialogContent as l, DialogDescription as u, DialogHeader as d, DialogTitle as f } from "../ui/dialog.js";
8
- import { Switch as p } from "../ui/switch.js";
9
- import { Select as m, SelectContent as h, SelectItem as g, SelectTrigger as _, SelectValue as v } from "../ui/select.js";
8
+ import { Select as p, SelectContent as m, SelectItem as h, SelectTrigger as g, SelectValue as _ } from "../ui/select.js";
9
+ import { Switch as v } from "../ui/switch.js";
10
10
  import * as y from "react";
11
11
  import { useState as b } from "react";
12
12
  import { Fragment as x, jsx as S, jsxs as C } from "react/jsx-runtime";
@@ -104,13 +104,13 @@ var O = {
104
104
  children: Z(t.projectId)
105
105
  })]
106
106
  }),
107
- /* @__PURE__ */ C(m, {
107
+ /* @__PURE__ */ C(p, {
108
108
  value: t.minTier,
109
109
  onValueChange: (e) => M?.(t, e),
110
- children: [/* @__PURE__ */ S(_, {
110
+ children: [/* @__PURE__ */ S(g, {
111
111
  className: "h-ds-xs-plus w-[130px] text-ds-sm",
112
- children: /* @__PURE__ */ S(v, {})
113
- }), /* @__PURE__ */ S(h, { children: Object.entries(k).map(([e, t]) => /* @__PURE__ */ S(g, {
112
+ children: /* @__PURE__ */ S(_, {})
113
+ }), /* @__PURE__ */ S(m, { children: Object.entries(k).map(([e, t]) => /* @__PURE__ */ S(h, {
114
114
  value: e,
115
115
  children: t
116
116
  }, e)) })]
@@ -120,7 +120,7 @@ var O = {
120
120
  children: [/* @__PURE__ */ S("span", {
121
121
  className: "text-ds-sm text-surface-fg-subtle",
122
122
  children: t.muted ? "Muted" : "Active"
123
- }), /* @__PURE__ */ S(p, {
123
+ }), /* @__PURE__ */ S(v, {
124
124
  checked: !t.muted,
125
125
  onCheckedChange: () => j?.(t)
126
126
  })]
@@ -152,16 +152,16 @@ var O = {
152
152
  htmlFor: "pref-scope",
153
153
  className: "text-ds-sm font-medium text-surface-fg-muted",
154
154
  children: "Scope"
155
- }), /* @__PURE__ */ C(m, {
155
+ }), /* @__PURE__ */ C(p, {
156
156
  value: z,
157
157
  onValueChange: B,
158
- children: [/* @__PURE__ */ S(_, {
158
+ children: [/* @__PURE__ */ S(g, {
159
159
  id: "pref-scope",
160
- children: /* @__PURE__ */ S(v, { placeholder: "Select scope" })
161
- }), /* @__PURE__ */ C(h, { children: [/* @__PURE__ */ S(g, {
160
+ children: /* @__PURE__ */ S(_, { placeholder: "Select scope" })
161
+ }), /* @__PURE__ */ C(m, { children: [/* @__PURE__ */ S(h, {
162
162
  value: "global",
163
163
  children: "Global (all projects)"
164
- }), w.map((e) => /* @__PURE__ */ S(g, {
164
+ }), w.map((e) => /* @__PURE__ */ S(h, {
165
165
  value: e.id,
166
166
  children: e.title
167
167
  }, e.id))] })]
@@ -173,16 +173,16 @@ var O = {
173
173
  htmlFor: "pref-channel",
174
174
  className: "text-ds-sm font-medium text-surface-fg-muted",
175
175
  children: "Channel"
176
- }), /* @__PURE__ */ C(m, {
176
+ }), /* @__PURE__ */ C(p, {
177
177
  value: V,
178
178
  onValueChange: H,
179
- children: [/* @__PURE__ */ S(_, {
179
+ children: [/* @__PURE__ */ S(g, {
180
180
  id: "pref-channel",
181
- children: /* @__PURE__ */ S(v, {})
182
- }), /* @__PURE__ */ C(h, { children: [/* @__PURE__ */ S(g, {
181
+ children: /* @__PURE__ */ S(_, {})
182
+ }), /* @__PURE__ */ C(m, { children: [/* @__PURE__ */ S(h, {
183
183
  value: "IN_APP",
184
184
  children: "In-App"
185
- }), /* @__PURE__ */ S(g, {
185
+ }), /* @__PURE__ */ S(h, {
186
186
  value: "GOOGLE_CHAT",
187
187
  children: "Google Chat"
188
188
  })] })]
@@ -194,13 +194,13 @@ var O = {
194
194
  htmlFor: "pref-min-tier",
195
195
  className: "text-ds-sm font-medium text-surface-fg-muted",
196
196
  children: "Minimum Tier"
197
- }), /* @__PURE__ */ C(m, {
197
+ }), /* @__PURE__ */ C(p, {
198
198
  value: U,
199
199
  onValueChange: W,
200
- children: [/* @__PURE__ */ S(_, {
200
+ children: [/* @__PURE__ */ S(g, {
201
201
  id: "pref-min-tier",
202
- children: /* @__PURE__ */ S(v, {})
203
- }), /* @__PURE__ */ S(h, { children: Object.entries(k).map(([e, t]) => /* @__PURE__ */ S(g, {
202
+ children: /* @__PURE__ */ S(_, {})
203
+ }), /* @__PURE__ */ S(m, { children: Object.entries(k).map(([e, t]) => /* @__PURE__ */ S(h, {
204
204
  value: e,
205
205
  children: t
206
206
  }, e)) })]
@@ -212,7 +212,7 @@ var O = {
212
212
  htmlFor: "pref-muted",
213
213
  className: "text-ds-md text-surface-fg",
214
214
  children: "Mute this channel"
215
- }), /* @__PURE__ */ S(p, {
215
+ }), /* @__PURE__ */ S(v, {
216
216
  id: "pref-muted",
217
217
  checked: G,
218
218
  onCheckedChange: K
@@ -1 +1 @@
1
- {"version":3,"file":"notification-preferences.js","names":[],"sources":["../../src/shell/notification-preferences.tsx"],"sourcesContent":["'use client'\n\n/**\n * NotificationPreferences -- Manage notification rules per channel/project.\n *\n * Props-driven: accepts preferences array, projects, and callbacks.\n * No internal fetching -- the consumer is responsible for data loading.\n */\nimport * as React from 'react'\nimport { useState } from 'react'\nimport { Button } from '../ui/button'\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '../ui/select'\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogHeader,\n DialogTitle,\n} from '../ui/dialog'\nimport { Switch } from '../ui/switch'\nimport { Card, CardHeader, CardTitle, CardContent } from '../ui/card'\nimport { IconPlus, IconTrash, IconBell, IconMessage } from '@tabler/icons-react'\nimport { Icon } from '../ui/icon'\nimport { cn } from '../ui/lib/utils'\nimport { Spinner } from '../ui/spinner'\n\n// -----------------------------------------------------------------------\n// Types\n// -----------------------------------------------------------------------\n\nexport interface NotificationPreference {\n id: string\n userId?: string\n projectId: string | null\n channel: string\n minTier: string\n muted: boolean\n}\n\nexport interface NotificationProject {\n id: string\n title: string\n}\n\nexport interface NotificationPreferencesProps\n extends Omit<React.ComponentPropsWithRef<'div'>, 'onSave'> {\n /** Current preference rules */\n preferences?: NotificationPreference[]\n /** Available projects for scoping rules */\n projects?: NotificationProject[]\n /** Whether data is loading */\n isLoading?: boolean\n /** Called to add or update a preference */\n onSave?: (preference: {\n projectId: string | null\n channel: string\n minTier: string\n muted: boolean\n }) => void | Promise<void>\n /** Called to toggle mute on a preference */\n onToggleMute?: (preference: NotificationPreference) => void | Promise<void>\n /** Called to update the tier on a preference */\n onUpdateTier?: (\n preference: NotificationPreference,\n newTier: string,\n ) => void | Promise<void>\n /** Called to delete a preference */\n onDelete?: (preferenceId: string) => void | Promise<void>\n /** Additional className */\n className?: string\n}\n\n// -----------------------------------------------------------------------\n// Constants\n// -----------------------------------------------------------------------\n\nconst CHANNEL_LABELS: Record<string, { label: string; icon: React.ReactNode }> = {\n IN_APP: { label: 'In-App', icon: <Icon icon={IconBell} size=\"sm\" /> },\n GOOGLE_CHAT: { label: 'Google Chat', icon: <Icon icon={IconMessage} size=\"sm\" /> },\n}\n\nconst TIER_LABELS: Record<string, string> = {\n INFO: 'All (Info+)',\n IMPORTANT: 'Important+',\n CRITICAL: 'Critical only',\n}\n\n// -----------------------------------------------------------------------\n// NotificationPreferences\n// -----------------------------------------------------------------------\n\nconst NotificationPreferences = React.forwardRef<HTMLDivElement, NotificationPreferencesProps>(\n function NotificationPreferences(\n {\n preferences = [],\n projects = [],\n isLoading = false,\n onSave,\n onToggleMute,\n onUpdateTier,\n onDelete,\n className,\n ...props\n },\n ref,\n ) {\n const [showAddDialog, setShowAddDialog] = useState(false)\n const [newProjectId, setNewProjectId] = useState<string>('global')\n const [newChannel, setNewChannel] = useState<string>('IN_APP')\n const [newMinTier, setNewMinTier] = useState<string>('INFO')\n const [newMuted, setNewMuted] = useState(false)\n const [isSaving, setIsSaving] = useState(false)\n\n const handleAdd = async () => {\n if (!onSave) return\n setIsSaving(true)\n try {\n await onSave({\n projectId: newProjectId === 'global' ? null : newProjectId,\n channel: newChannel,\n minTier: newMinTier,\n muted: newMuted,\n })\n setShowAddDialog(false)\n resetForm()\n } catch (error) {\n console.error('[Preferences] Failed to save:', error)\n } finally {\n setIsSaving(false)\n }\n }\n\n const resetForm = () => {\n setNewProjectId('global')\n setNewChannel('IN_APP')\n setNewMinTier('INFO')\n setNewMuted(false)\n }\n\n const getProjectName = (projectId: string | null) => {\n if (!projectId) return 'Global (all projects)'\n const project = projects.find((p) => p.id === projectId)\n return project?.title || 'Unknown project'\n }\n\n return (\n <>\n <Card ref={ref} className={className} {...(props as Omit<typeof props, 'color'>)}>\n <CardHeader className=\"flex flex-row items-center justify-between space-y-0 pb-ds-04\">\n <CardTitle className=\"text-ds-md font-semibold\">\n Notification Preferences\n </CardTitle>\n <Button\n size=\"sm\"\n variant=\"outline\"\n onClick={() => setShowAddDialog(true)}\n >\n <Icon icon={IconPlus} size=\"sm\" className=\"mr-ds-02b\" />\n Add Rule\n </Button>\n </CardHeader>\n <CardContent>\n {isLoading ? (\n <div className=\"flex items-center justify-center py-ds-07\">\n <Spinner />\n </div>\n ) : preferences.length === 0 ? (\n <div className=\"py-ds-07 text-center\">\n <p className=\"text-ds-md text-surface-fg-subtle\">\n No custom preferences set. All notifications are delivered by\n default.\n </p>\n </div>\n ) : (\n <div className=\"flex flex-col\">\n {preferences.map((pref, i) => {\n const channelInfo =\n CHANNEL_LABELS[pref.channel] || CHANNEL_LABELS.IN_APP\n return (\n <div\n key={pref.id}\n className={cn(\n 'flex items-center gap-ds-05 py-ds-04',\n i < preferences.length - 1 &&\n 'border-b border-surface-border-strong',\n )}\n >\n {/* Channel icon */}\n <div className=\"flex h-ds-sm w-ds-sm shrink-0 items-center justify-center rounded-ds-lg bg-surface-raised\">\n <span className=\"[&>svg]:h-ico-sm [&>svg]:w-ico-sm text-surface-fg-muted\" aria-hidden=\"true\">{channelInfo.icon}</span>\n </div>\n\n {/* Info */}\n <div className=\"min-w-0 flex-1\">\n <p className=\"text-ds-md font-medium text-surface-fg\">\n {channelInfo.label}\n </p>\n <p className=\"text-ds-sm text-surface-fg-subtle\">\n {getProjectName(pref.projectId)}\n </p>\n </div>\n\n {/* Min tier */}\n <Select\n value={pref.minTier}\n onValueChange={(v) => onUpdateTier?.(pref, v)}\n >\n <SelectTrigger className=\"h-ds-xs-plus w-[130px] text-ds-sm\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {Object.entries(TIER_LABELS).map(([key, label]) => (\n <SelectItem key={key} value={key}>\n {label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n\n {/* Muted toggle */}\n <div className=\"flex items-center gap-ds-02b\">\n <span className=\"text-ds-sm text-surface-fg-subtle\">\n {pref.muted ? 'Muted' : 'Active'}\n </span>\n <Switch\n checked={!pref.muted}\n onCheckedChange={() => onToggleMute?.(pref)}\n />\n </div>\n\n {/* Delete */}\n <button\n type=\"button\"\n onClick={() => onDelete?.(pref.id)}\n className=\"shrink-0 rounded p-ds-02b text-surface-fg-subtle transition-colors hover:bg-surface-raised hover:text-error-11\"\n >\n <Icon icon={IconTrash} size=\"sm\" />\n </button>\n </div>\n )\n })}\n </div>\n )}\n </CardContent>\n </Card>\n\n {/* Add Preference Dialog */}\n <Dialog open={showAddDialog} onOpenChange={setShowAddDialog}>\n <DialogContent className=\"sm:max-w-md\">\n <DialogHeader>\n <DialogTitle>Add Notification Rule</DialogTitle>\n <DialogDescription>\n Customize how you receive notifications for a specific channel\n and project.\n </DialogDescription>\n </DialogHeader>\n <div className=\"flex flex-col gap-ds-05 pt-ds-03\">\n <div className=\"flex flex-col gap-ds-02b\">\n <label htmlFor=\"pref-scope\" className=\"text-ds-sm font-medium text-surface-fg-muted\">\n Scope\n </label>\n <Select value={newProjectId} onValueChange={setNewProjectId}>\n <SelectTrigger id=\"pref-scope\">\n <SelectValue placeholder=\"Select scope\" />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"global\">\n Global (all projects)\n </SelectItem>\n {projects.map((p) => (\n <SelectItem key={p.id} value={p.id}>\n {p.title}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n\n <div className=\"flex flex-col gap-ds-02b\">\n <label htmlFor=\"pref-channel\" className=\"text-ds-sm font-medium text-surface-fg-muted\">\n Channel\n </label>\n <Select value={newChannel} onValueChange={setNewChannel}>\n <SelectTrigger id=\"pref-channel\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"IN_APP\">In-App</SelectItem>\n <SelectItem value=\"GOOGLE_CHAT\">Google Chat</SelectItem>\n </SelectContent>\n </Select>\n </div>\n\n <div className=\"flex flex-col gap-ds-02b\">\n <label htmlFor=\"pref-min-tier\" className=\"text-ds-sm font-medium text-surface-fg-muted\">\n Minimum Tier\n </label>\n <Select value={newMinTier} onValueChange={setNewMinTier}>\n <SelectTrigger id=\"pref-min-tier\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {Object.entries(TIER_LABELS).map(([key, label]) => (\n <SelectItem key={key} value={key}>\n {label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n\n <div className=\"flex items-center justify-between\">\n <label htmlFor=\"pref-muted\" className=\"text-ds-md text-surface-fg\">\n Mute this channel\n </label>\n <Switch id=\"pref-muted\" checked={newMuted} onCheckedChange={setNewMuted} />\n </div>\n\n <div className=\"flex justify-end gap-ds-03 pt-ds-03\">\n <Button\n variant=\"ghost\"\n onClick={() => {\n setShowAddDialog(false)\n resetForm()\n }}\n >\n Cancel\n </Button>\n <Button\n onClick={handleAdd}\n disabled={isSaving}\n >\n {isSaving ? 'Saving...' : 'Save Rule'}\n </Button>\n </div>\n </div>\n </DialogContent>\n </Dialog>\n </>\n )\n },\n)\n\nNotificationPreferences.displayName = 'NotificationPreferences'\n\nexport { NotificationPreferences }\n"],"mappings":"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"}
1
+ {"version":3,"file":"notification-preferences.js","names":[],"sources":["../../src/shell/notification-preferences.tsx"],"sourcesContent":["'use client'\n\n/**\n * NotificationPreferences -- Manage notification rules per channel/project.\n *\n * Props-driven: accepts preferences array, projects, and callbacks.\n * No internal fetching -- the consumer is responsible for data loading.\n */\nimport { IconBell, IconMessage,IconPlus, IconTrash } from '@tabler/icons-react'\nimport * as React from 'react'\nimport { useState } from 'react'\n\nimport { Button } from '../ui/button'\nimport { Card, CardContent,CardHeader, CardTitle } from '../ui/card'\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogHeader,\n DialogTitle,\n} from '../ui/dialog'\nimport { Icon } from '../ui/icon'\nimport { cn } from '../ui/lib/utils'\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '../ui/select'\nimport { Spinner } from '../ui/spinner'\nimport { Switch } from '../ui/switch'\n\n// -----------------------------------------------------------------------\n// Types\n// -----------------------------------------------------------------------\n\nexport interface NotificationPreference {\n id: string\n userId?: string\n projectId: string | null\n channel: string\n minTier: string\n muted: boolean\n}\n\nexport interface NotificationProject {\n id: string\n title: string\n}\n\nexport interface NotificationPreferencesProps\n extends Omit<React.ComponentPropsWithRef<'div'>, 'onSave'> {\n /** Current preference rules */\n preferences?: NotificationPreference[]\n /** Available projects for scoping rules */\n projects?: NotificationProject[]\n /** Whether data is loading */\n isLoading?: boolean\n /** Called to add or update a preference */\n onSave?: (preference: {\n projectId: string | null\n channel: string\n minTier: string\n muted: boolean\n }) => void | Promise<void>\n /** Called to toggle mute on a preference */\n onToggleMute?: (preference: NotificationPreference) => void | Promise<void>\n /** Called to update the tier on a preference */\n onUpdateTier?: (\n preference: NotificationPreference,\n newTier: string,\n ) => void | Promise<void>\n /** Called to delete a preference */\n onDelete?: (preferenceId: string) => void | Promise<void>\n /** Additional className */\n className?: string\n}\n\n// -----------------------------------------------------------------------\n// Constants\n// -----------------------------------------------------------------------\n\nconst CHANNEL_LABELS: Record<string, { label: string; icon: React.ReactNode }> = {\n IN_APP: { label: 'In-App', icon: <Icon icon={IconBell} size=\"sm\" /> },\n GOOGLE_CHAT: { label: 'Google Chat', icon: <Icon icon={IconMessage} size=\"sm\" /> },\n}\n\nconst TIER_LABELS: Record<string, string> = {\n INFO: 'All (Info+)',\n IMPORTANT: 'Important+',\n CRITICAL: 'Critical only',\n}\n\n// -----------------------------------------------------------------------\n// NotificationPreferences\n// -----------------------------------------------------------------------\n\nconst NotificationPreferences = React.forwardRef<HTMLDivElement, NotificationPreferencesProps>(\n function NotificationPreferences(\n {\n preferences = [],\n projects = [],\n isLoading = false,\n onSave,\n onToggleMute,\n onUpdateTier,\n onDelete,\n className,\n ...props\n },\n ref,\n ) {\n const [showAddDialog, setShowAddDialog] = useState(false)\n const [newProjectId, setNewProjectId] = useState<string>('global')\n const [newChannel, setNewChannel] = useState<string>('IN_APP')\n const [newMinTier, setNewMinTier] = useState<string>('INFO')\n const [newMuted, setNewMuted] = useState(false)\n const [isSaving, setIsSaving] = useState(false)\n\n const handleAdd = async () => {\n if (!onSave) return\n setIsSaving(true)\n try {\n await onSave({\n projectId: newProjectId === 'global' ? null : newProjectId,\n channel: newChannel,\n minTier: newMinTier,\n muted: newMuted,\n })\n setShowAddDialog(false)\n resetForm()\n } catch (error) {\n console.error('[Preferences] Failed to save:', error)\n } finally {\n setIsSaving(false)\n }\n }\n\n const resetForm = () => {\n setNewProjectId('global')\n setNewChannel('IN_APP')\n setNewMinTier('INFO')\n setNewMuted(false)\n }\n\n const getProjectName = (projectId: string | null) => {\n if (!projectId) return 'Global (all projects)'\n const project = projects.find((p) => p.id === projectId)\n return project?.title || 'Unknown project'\n }\n\n return (\n <>\n <Card ref={ref} className={className} {...(props as Omit<typeof props, 'color'>)}>\n <CardHeader className=\"flex flex-row items-center justify-between space-y-0 pb-ds-04\">\n <CardTitle className=\"text-ds-md font-semibold\">\n Notification Preferences\n </CardTitle>\n <Button\n size=\"sm\"\n variant=\"outline\"\n onClick={() => setShowAddDialog(true)}\n >\n <Icon icon={IconPlus} size=\"sm\" className=\"mr-ds-02b\" />\n Add Rule\n </Button>\n </CardHeader>\n <CardContent>\n {isLoading ? (\n <div className=\"flex items-center justify-center py-ds-07\">\n <Spinner />\n </div>\n ) : preferences.length === 0 ? (\n <div className=\"py-ds-07 text-center\">\n <p className=\"text-ds-md text-surface-fg-subtle\">\n No custom preferences set. All notifications are delivered by\n default.\n </p>\n </div>\n ) : (\n <div className=\"flex flex-col\">\n {preferences.map((pref, i) => {\n const channelInfo =\n CHANNEL_LABELS[pref.channel] || CHANNEL_LABELS.IN_APP\n return (\n <div\n key={pref.id}\n className={cn(\n 'flex items-center gap-ds-05 py-ds-04',\n i < preferences.length - 1 &&\n 'border-b border-surface-border-strong',\n )}\n >\n {/* Channel icon */}\n <div className=\"flex h-ds-sm w-ds-sm shrink-0 items-center justify-center rounded-ds-lg bg-surface-raised\">\n <span className=\"[&>svg]:h-ico-sm [&>svg]:w-ico-sm text-surface-fg-muted\" aria-hidden=\"true\">{channelInfo.icon}</span>\n </div>\n\n {/* Info */}\n <div className=\"min-w-0 flex-1\">\n <p className=\"text-ds-md font-medium text-surface-fg\">\n {channelInfo.label}\n </p>\n <p className=\"text-ds-sm text-surface-fg-subtle\">\n {getProjectName(pref.projectId)}\n </p>\n </div>\n\n {/* Min tier */}\n <Select\n value={pref.minTier}\n onValueChange={(v) => onUpdateTier?.(pref, v)}\n >\n <SelectTrigger className=\"h-ds-xs-plus w-[130px] text-ds-sm\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {Object.entries(TIER_LABELS).map(([key, label]) => (\n <SelectItem key={key} value={key}>\n {label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n\n {/* Muted toggle */}\n <div className=\"flex items-center gap-ds-02b\">\n <span className=\"text-ds-sm text-surface-fg-subtle\">\n {pref.muted ? 'Muted' : 'Active'}\n </span>\n <Switch\n checked={!pref.muted}\n onCheckedChange={() => onToggleMute?.(pref)}\n />\n </div>\n\n {/* Delete */}\n <button\n type=\"button\"\n onClick={() => onDelete?.(pref.id)}\n className=\"shrink-0 rounded p-ds-02b text-surface-fg-subtle transition-colors hover:bg-surface-raised hover:text-error-11\"\n >\n <Icon icon={IconTrash} size=\"sm\" />\n </button>\n </div>\n )\n })}\n </div>\n )}\n </CardContent>\n </Card>\n\n {/* Add Preference Dialog */}\n <Dialog open={showAddDialog} onOpenChange={setShowAddDialog}>\n <DialogContent className=\"sm:max-w-md\">\n <DialogHeader>\n <DialogTitle>Add Notification Rule</DialogTitle>\n <DialogDescription>\n Customize how you receive notifications for a specific channel\n and project.\n </DialogDescription>\n </DialogHeader>\n <div className=\"flex flex-col gap-ds-05 pt-ds-03\">\n <div className=\"flex flex-col gap-ds-02b\">\n <label htmlFor=\"pref-scope\" className=\"text-ds-sm font-medium text-surface-fg-muted\">\n Scope\n </label>\n <Select value={newProjectId} onValueChange={setNewProjectId}>\n <SelectTrigger id=\"pref-scope\">\n <SelectValue placeholder=\"Select scope\" />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"global\">\n Global (all projects)\n </SelectItem>\n {projects.map((p) => (\n <SelectItem key={p.id} value={p.id}>\n {p.title}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n\n <div className=\"flex flex-col gap-ds-02b\">\n <label htmlFor=\"pref-channel\" className=\"text-ds-sm font-medium text-surface-fg-muted\">\n Channel\n </label>\n <Select value={newChannel} onValueChange={setNewChannel}>\n <SelectTrigger id=\"pref-channel\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"IN_APP\">In-App</SelectItem>\n <SelectItem value=\"GOOGLE_CHAT\">Google Chat</SelectItem>\n </SelectContent>\n </Select>\n </div>\n\n <div className=\"flex flex-col gap-ds-02b\">\n <label htmlFor=\"pref-min-tier\" className=\"text-ds-sm font-medium text-surface-fg-muted\">\n Minimum Tier\n </label>\n <Select value={newMinTier} onValueChange={setNewMinTier}>\n <SelectTrigger id=\"pref-min-tier\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {Object.entries(TIER_LABELS).map(([key, label]) => (\n <SelectItem key={key} value={key}>\n {label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n\n <div className=\"flex items-center justify-between\">\n <label htmlFor=\"pref-muted\" className=\"text-ds-md text-surface-fg\">\n Mute this channel\n </label>\n <Switch id=\"pref-muted\" checked={newMuted} onCheckedChange={setNewMuted} />\n </div>\n\n <div className=\"flex justify-end gap-ds-03 pt-ds-03\">\n <Button\n variant=\"ghost\"\n onClick={() => {\n setShowAddDialog(false)\n resetForm()\n }}\n >\n Cancel\n </Button>\n <Button\n onClick={handleAdd}\n disabled={isSaving}\n >\n {isSaving ? 'Saving...' : 'Save Rule'}\n </Button>\n </div>\n </div>\n </DialogContent>\n </Dialog>\n </>\n )\n },\n)\n\nNotificationPreferences.displayName = 'NotificationPreferences'\n\nexport { NotificationPreferences }\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"sidebar.d.ts","sourceRoot":"","sources":["../../src/shell/sidebar.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"sidebar.d.ts","sourceRoot":"","sources":["../../src/shell/sidebar.tsx"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"sidebar.js","names":[],"sources":["../../src/shell/sidebar.tsx"],"sourcesContent":["'use client'\n\n/**\n * AppSidebar -- Application-layer sidebar built on the Sidebar primitive.\n *\n * Design-system token migration (2026-02-28):\n * All V1 colour tokens have been replaced with semantic design-system tokens.\n * Typography classes replaced with Tailwind equivalents.\n *\n * Props-driven: accepts user info, currentPath, and navItems instead of\n * reading from Remix hooks or Zustand stores.\n */\nimport * as React from 'react'\nimport { useLink } from './link-context'\nimport {\n Sidebar as ShadcnSidebar,\n SidebarContent,\n SidebarFooter,\n SidebarGroup,\n SidebarGroupAction,\n SidebarGroupContent,\n SidebarGroupLabel,\n SidebarHeader,\n SidebarMenu,\n SidebarMenuBadge,\n SidebarMenuButton,\n SidebarMenuItem,\n SidebarMenuSub,\n SidebarMenuSubButton,\n SidebarMenuSubItem,\n SidebarSeparator,\n} from '../ui/sidebar'\nimport {\n Collapsible,\n CollapsibleContent,\n CollapsibleTrigger,\n} from '../ui/collapsible'\nimport { Avatar, AvatarFallback, AvatarImage } from '../ui/avatar'\nimport { cn } from '../ui/lib/utils'\n\n// -----------------------------------------------------------------------\n// Types\n// -----------------------------------------------------------------------\n\nexport interface NavSubItem {\n title: string\n href: string\n icon?: React.ReactNode\n exact?: boolean\n}\n\nexport interface NavItem {\n title: string\n href: string\n icon: React.ReactNode\n /** When true, the route matches only when the path is exactly equal */\n exact?: boolean\n /** Badge rendered on the right side of the nav item */\n badge?: string | number\n /** Optional child items — renders as collapsible sub-list with chevron */\n children?: NavSubItem[]\n /** Whether the collapsible is open by default. Auto-opens when a child is active. */\n defaultOpen?: boolean\n}\n\nexport interface NavGroup {\n label: string\n items: NavItem[]\n /** Action rendered next to the group label (e.g., a \"+\" button) */\n action?: React.ReactNode\n}\n\nexport interface SidebarUser {\n name: string\n email?: string\n image?: string | null\n designation?: string\n role?: string\n}\n\nexport interface SidebarPromo {\n /** Promo message text */\n text: string\n /** Optional icon rendered before the text */\n icon?: React.ReactNode\n /** Action button rendered in the promo banner */\n action?: { label: string; href?: string; onClick?: () => void }\n /** When provided, renders a dismiss (X) button that calls this handler */\n onDismiss?: () => void\n}\n\nexport interface SidebarFooterConfig {\n /** Legal/utility links rendered as a row separated by dividers */\n links?: Array<{ label: string; href: string }>\n /** Version or build info text (or link) rendered inline after links */\n version?: string | { label: string; href: string }\n /** Custom content rendered above the links row */\n slot?: React.ReactNode\n /** Promo/upsell banner rendered above the links row */\n promo?: SidebarPromo\n}\n\nexport interface AppSidebarProps\n extends React.HTMLAttributes<HTMLDivElement> {\n /** Currently active pathname -- used to highlight the active nav item */\n currentPath?: string\n /** User information displayed in the sidebar header */\n user?: SidebarUser | null\n /** Primary navigation groups rendered in the main content area */\n navGroups?: NavGroup[]\n /** Optional logo element. Falls back to a text placeholder. */\n logo?: React.ReactNode\n /** Footer links rendered at the bottom of the sidebar */\n footerLinks?: Array<{ label: string; href: string }>\n /** Structured footer config (takes precedence over footerLinks) */\n footer?: SidebarFooterConfig\n /** Content rendered between user header and navigation */\n headerSlot?: React.ReactNode\n /** Content rendered between navigation and footer */\n preFooterSlot?: React.ReactNode\n /** className applied to the wrapper div around preFooterSlot */\n preFooterClassName?: string\n /** Override rendering for specific nav items. Return null to use default rendering. */\n renderItem?: (item: NavItem, defaultRender: () => React.ReactNode) => React.ReactNode | null\n /** Additional className for the root sidebar element */\n className?: string\n}\n\n// -----------------------------------------------------------------------\n// ChevronRight (inline SVG icon for collapsible toggle)\n// -----------------------------------------------------------------------\n\nfunction ChevronRight({ className }: { className?: string }) {\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className={className}\n >\n <path d=\"m9 18 6-6-6-6\" />\n </svg>\n )\n}\n\nfunction CloseIcon({ className }: { className?: string }) {\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className={className}\n >\n <path d=\"M18 6 6 18\" />\n <path d=\"m6 6 12 12\" />\n </svg>\n )\n}\n\n// -----------------------------------------------------------------------\n// Shared styles\n// -----------------------------------------------------------------------\n\nconst navItemBase = 'relative gap-ds-04 rounded-ds-lg px-ds-04 py-ds-03 transition-colors duration-fast-02'\nconst navItemActive =\n \"bg-accent-2 text-accent-11 after:absolute after:right-0 after:top-0 after:h-full after:w-ds-01 after:rounded-l-ds-full after:bg-accent-9 after:content-['']\"\nconst navItemInactive = 'text-surface-fg-subtle hover:bg-surface-raised-hover hover:text-surface-fg'\n\n// -----------------------------------------------------------------------\n// NavLink (internal)\n// -----------------------------------------------------------------------\n\nfunction NavLink({\n item,\n isActive,\n isPathActive,\n}: {\n item: NavItem\n isActive: boolean\n isPathActive: (path: string, exact?: boolean) => boolean\n}) {\n const Link = useLink()\n const badgeContent =\n item.badge != null\n ? typeof item.badge === 'number' && item.badge > 99\n ? '99+'\n : String(item.badge)\n : null\n\n // S9: Collapsible children\n if (item.children && item.children.length > 0) {\n const hasActiveChild = item.children.some((child) =>\n isPathActive(child.href, child.exact),\n )\n const shouldOpen = hasActiveChild || isActive || (item.defaultOpen ?? false)\n\n return (\n <Collapsible defaultOpen={shouldOpen} className=\"group/collapsible\">\n <SidebarMenuItem>\n {/* Button row — chevron is anchored here, not on the full <li> */}\n <div className=\"relative\">\n <SidebarMenuButton\n asChild\n isActive={isActive || hasActiveChild}\n tooltip={item.title}\n className={cn(\n navItemBase,\n isActive || hasActiveChild ? navItemActive : navItemInactive,\n )}\n >\n <Link\n href={item.href}\n aria-label={item.title}\n aria-current={isActive ? 'page' : undefined}\n >\n <span className=\"[&>svg]:h-ico-md [&>svg]:w-ico-md shrink-0\" aria-hidden=\"true\">\n {item.icon}\n </span>\n <span className=\"text-ds-base\">{item.title}</span>\n </Link>\n </SidebarMenuButton>\n {badgeContent && <SidebarMenuBadge>{badgeContent}</SidebarMenuBadge>}\n <CollapsibleTrigger asChild>\n <button\n className=\"absolute right-ds-02 top-1/2 flex h-5 w-5 -translate-y-1/2 items-center justify-center rounded-ds-md text-surface-fg-subtle transition-colors hover:bg-surface-raised-hover hover:text-surface-fg group-data-[collapsible=icon]:hidden\"\n aria-label={`Toggle ${item.title}`}\n >\n <ChevronRight className=\"h-4 w-4 transition-transform duration-fast-02 ease-productive-standard group-data-[state=open]/collapsible:rotate-90\" />\n </button>\n </CollapsibleTrigger>\n </div>\n <CollapsibleContent>\n <SidebarMenuSub>\n {item.children.map((child) => {\n const childActive = isPathActive(child.href, child.exact)\n return (\n <SidebarMenuSubItem key={child.href}>\n <SidebarMenuSubButton\n asChild\n isActive={childActive}\n >\n <Link\n href={child.href}\n aria-current={childActive ? 'page' : undefined}\n >\n {child.icon && (\n <span className=\"[&>svg]:h-ico-sm [&>svg]:w-ico-sm shrink-0\" aria-hidden=\"true\">\n {child.icon}\n </span>\n )}\n <span>{child.title}</span>\n </Link>\n </SidebarMenuSubButton>\n </SidebarMenuSubItem>\n )\n })}\n </SidebarMenuSub>\n </CollapsibleContent>\n </SidebarMenuItem>\n </Collapsible>\n )\n }\n\n // Default: flat nav item\n return (\n <SidebarMenuItem>\n <SidebarMenuButton\n asChild\n isActive={isActive}\n tooltip={item.title}\n className={cn(\n navItemBase,\n isActive ? navItemActive : navItemInactive,\n )}\n >\n <Link\n href={item.href}\n aria-label={item.title}\n aria-current={isActive ? 'page' : undefined}\n >\n <span className=\"[&>svg]:h-ico-md [&>svg]:w-ico-md shrink-0\" aria-hidden=\"true\">{item.icon}</span>\n <span className=\"text-ds-base\">{item.title}</span>\n </Link>\n </SidebarMenuButton>\n {badgeContent && <SidebarMenuBadge>{badgeContent}</SidebarMenuBadge>}\n </SidebarMenuItem>\n )\n}\n\n// -----------------------------------------------------------------------\n// AppSidebar\n// -----------------------------------------------------------------------\n\nconst AppSidebar = React.forwardRef<HTMLDivElement, AppSidebarProps>(\n (\n {\n currentPath = '/',\n user,\n navGroups = [],\n logo,\n headerSlot,\n preFooterSlot,\n preFooterClassName,\n footerLinks = [],\n footer,\n renderItem,\n className,\n ...props\n },\n ref,\n ) => {\n const Link = useLink()\n const isActive = (path: string, exact = false) => {\n if (exact || path === '/') {\n return currentPath === path\n }\n return currentPath.startsWith(path)\n }\n\n return (\n <ShadcnSidebar\n {...props}\n ref={ref}\n aria-label=\"Main navigation\"\n className={cn(\n 'z-raised hidden h-full flex-col border-r border-surface-border-strong bg-surface-raised md:flex',\n className,\n )}\n >\n {/* Logo Header */}\n <SidebarHeader className=\"px-ds-06 py-ds-06\">\n {logo ?? (\n <span className=\"text-ds-lg font-semibold text-surface-fg\">\n Logo\n </span>\n )}\n </SidebarHeader>\n\n {/* User Info */}\n {user && (\n <div className=\"flex items-center gap-ds-04 px-ds-06 pb-ds-05\">\n <Avatar className=\"h-ds-sm-plus w-ds-sm-plus\">\n {user.image ? (\n <AvatarImage src={user.image} alt={user.name} />\n ) : null}\n <AvatarFallback className=\"bg-surface-raised-hover text-surface-fg\">\n {user.name?.charAt(0).toUpperCase()}\n </AvatarFallback>\n </Avatar>\n <div className=\"flex min-w-0 flex-col\">\n <span className=\"truncate text-ds-md text-surface-fg\">\n {user.name}\n </span>\n <span className=\"truncate text-ds-sm text-surface-fg-subtle\">\n {user.designation || user.role}\n </span>\n </div>\n </div>\n )}\n\n <SidebarSeparator />\n\n {/* Header Slot (S13) */}\n {headerSlot && (\n <>\n {headerSlot}\n <SidebarSeparator />\n </>\n )}\n\n {/* Navigation Groups */}\n <SidebarContent className=\"no-scrollbar px-ds-04\">\n {navGroups.map((group, idx) => (\n <div key={group.label}>\n {idx > 0 && <SidebarSeparator />}\n <SidebarGroup>\n <SidebarGroupLabel className=\"px-ds-04 text-ds-sm text-surface-fg-subtle\">\n {group.label}\n </SidebarGroupLabel>\n {group.action && (\n <SidebarGroupAction asChild>{group.action}</SidebarGroupAction>\n )}\n <SidebarGroupContent>\n <SidebarMenu>\n {group.items.map((item) => {\n const defaultRender = () => (\n <NavLink\n item={item}\n isActive={isActive(item.href, item.exact)}\n isPathActive={isActive}\n />\n )\n\n if (renderItem) {\n const custom = renderItem(item, defaultRender)\n if (custom !== null) {\n return <React.Fragment key={item.href}>{custom}</React.Fragment>\n }\n }\n\n return <React.Fragment key={item.href}>{defaultRender()}</React.Fragment>\n })}\n </SidebarMenu>\n </SidebarGroupContent>\n </SidebarGroup>\n </div>\n ))}\n </SidebarContent>\n\n {/* Pre-Footer Slot (S13) */}\n {preFooterSlot && (\n <>\n <SidebarSeparator />\n <div className={preFooterClassName}>\n {preFooterSlot}\n </div>\n </>\n )}\n\n {/* Footer */}\n {footer ? (\n <SidebarFooter className=\"gap-ds-03 px-ds-06 py-ds-05\">\n {footer.slot && <div>{footer.slot}</div>}\n\n {/* Promo banner */}\n {footer.promo && (\n <div className=\"relative rounded-ds-lg border border-surface-border bg-surface-raised p-ds-04 shadow-raised\">\n {footer.promo.onDismiss && (\n <button\n onClick={footer.promo.onDismiss}\n aria-label=\"Dismiss\"\n className=\"absolute right-ds-02 top-ds-02 flex h-5 w-5 items-center justify-center rounded-ds-md text-surface-fg-subtle transition-colors hover:bg-surface-raised-hover hover:text-surface-fg\"\n >\n <CloseIcon className=\"h-3.5 w-3.5\" />\n </button>\n )}\n <div className=\"flex flex-col gap-ds-03\">\n {footer.promo.icon && (\n <span className=\"text-accent-11 [&>svg]:h-ico-md [&>svg]:w-ico-md\" aria-hidden=\"true\">\n {footer.promo.icon}\n </span>\n )}\n <div className=\"flex min-w-0 flex-col gap-ds-03\">\n <p className=\"text-ds-sm text-surface-fg\">{footer.promo.text}</p>\n {footer.promo.action && (\n footer.promo.action.href ? (\n <Link\n href={footer.promo.action.href}\n onClick={footer.promo.action.onClick}\n className=\"inline-flex self-start rounded-ds-md bg-accent-9 px-ds-04 py-ds-02 text-ds-sm font-medium text-accent-fg transition-colors hover:bg-accent-10\"\n >\n {footer.promo.action.label}\n </Link>\n ) : (\n <button\n onClick={footer.promo.action.onClick}\n className=\"inline-flex self-start rounded-ds-md bg-accent-9 px-ds-04 py-ds-02 text-ds-sm font-medium text-accent-fg transition-colors hover:bg-accent-10\"\n >\n {footer.promo.action.label}\n </button>\n )\n )}\n </div>\n </div>\n </div>\n )}\n\n {/* Links + version on same line */}\n {(footer.links?.length || footer.version) && (\n <div className=\"flex items-center gap-ds-03 text-ds-sm text-surface-fg-subtle\">\n {footer.links?.map((link, i) => (\n <React.Fragment key={link.href}>\n {i > 0 && <span>·</span>}\n <Link\n className=\"transition-colors hover:text-accent-11\"\n href={link.href}\n >\n {link.label}\n </Link>\n </React.Fragment>\n ))}\n {footer.links?.length && footer.version && <span>·</span>}\n {footer.version && (\n typeof footer.version === 'string'\n ? <span>{footer.version}</span>\n : <Link className=\"transition-colors hover:text-accent-11\" href={footer.version.href}>{footer.version.label}</Link>\n )}\n </div>\n )}\n </SidebarFooter>\n ) : footerLinks.length > 0 ? (\n <SidebarFooter className=\"px-ds-06 py-ds-05\">\n <div className=\"flex items-center gap-ds-03 text-ds-sm text-surface-fg-subtle\">\n {footerLinks.map((link, i) => (\n <React.Fragment key={link.href}>\n {i > 0 && <span>·</span>}\n <Link\n className=\"transition-colors hover:text-accent-11\"\n href={link.href}\n >\n {link.label}\n </Link>\n </React.Fragment>\n ))}\n </div>\n </SidebarFooter>\n ) : null}\n </ShadcnSidebar>\n )\n },\n)\nAppSidebar.displayName = 'AppSidebar'\n\nexport { AppSidebar }\n"],"mappings":"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"}
1
+ {"version":3,"file":"sidebar.js","names":[],"sources":["../../src/shell/sidebar.tsx"],"sourcesContent":["'use client'\n\n/**\n * AppSidebar -- Application-layer sidebar built on the Sidebar primitive.\n *\n * Design-system token migration (2026-02-28):\n * All V1 colour tokens have been replaced with semantic design-system tokens.\n * Typography classes replaced with Tailwind equivalents.\n *\n * Props-driven: accepts user info, currentPath, and navItems instead of\n * reading from Remix hooks or Zustand stores.\n */\nimport * as React from 'react'\n\nimport { Avatar, AvatarFallback, AvatarImage } from '../ui/avatar'\nimport {\n Collapsible,\n CollapsibleContent,\n CollapsibleTrigger,\n} from '../ui/collapsible'\nimport { cn } from '../ui/lib/utils'\nimport {\n Sidebar as ShadcnSidebar,\n SidebarContent,\n SidebarFooter,\n SidebarGroup,\n SidebarGroupAction,\n SidebarGroupContent,\n SidebarGroupLabel,\n SidebarHeader,\n SidebarMenu,\n SidebarMenuBadge,\n SidebarMenuButton,\n SidebarMenuItem,\n SidebarMenuSub,\n SidebarMenuSubButton,\n SidebarMenuSubItem,\n SidebarSeparator,\n} from '../ui/sidebar'\nimport { useLink } from './link-context'\n\n// -----------------------------------------------------------------------\n// Types\n// -----------------------------------------------------------------------\n\nexport interface NavSubItem {\n title: string\n href: string\n icon?: React.ReactNode\n exact?: boolean\n}\n\nexport interface NavItem {\n title: string\n href: string\n icon: React.ReactNode\n /** When true, the route matches only when the path is exactly equal */\n exact?: boolean\n /** Badge rendered on the right side of the nav item */\n badge?: string | number\n /** Optional child items — renders as collapsible sub-list with chevron */\n children?: NavSubItem[]\n /** Whether the collapsible is open by default. Auto-opens when a child is active. */\n defaultOpen?: boolean\n}\n\nexport interface NavGroup {\n label: string\n items: NavItem[]\n /** Action rendered next to the group label (e.g., a \"+\" button) */\n action?: React.ReactNode\n}\n\nexport interface SidebarUser {\n name: string\n email?: string\n image?: string | null\n designation?: string\n role?: string\n}\n\nexport interface SidebarPromo {\n /** Promo message text */\n text: string\n /** Optional icon rendered before the text */\n icon?: React.ReactNode\n /** Action button rendered in the promo banner */\n action?: { label: string; href?: string; onClick?: () => void }\n /** When provided, renders a dismiss (X) button that calls this handler */\n onDismiss?: () => void\n}\n\nexport interface SidebarFooterConfig {\n /** Legal/utility links rendered as a row separated by dividers */\n links?: Array<{ label: string; href: string }>\n /** Version or build info text (or link) rendered inline after links */\n version?: string | { label: string; href: string }\n /** Custom content rendered above the links row */\n slot?: React.ReactNode\n /** Promo/upsell banner rendered above the links row */\n promo?: SidebarPromo\n}\n\nexport interface AppSidebarProps\n extends React.HTMLAttributes<HTMLDivElement> {\n /** Currently active pathname -- used to highlight the active nav item */\n currentPath?: string\n /** User information displayed in the sidebar header */\n user?: SidebarUser | null\n /** Primary navigation groups rendered in the main content area */\n navGroups?: NavGroup[]\n /** Optional logo element. Falls back to a text placeholder. */\n logo?: React.ReactNode\n /** Footer links rendered at the bottom of the sidebar */\n footerLinks?: Array<{ label: string; href: string }>\n /** Structured footer config (takes precedence over footerLinks) */\n footer?: SidebarFooterConfig\n /** Content rendered between user header and navigation */\n headerSlot?: React.ReactNode\n /** Content rendered between navigation and footer */\n preFooterSlot?: React.ReactNode\n /** className applied to the wrapper div around preFooterSlot */\n preFooterClassName?: string\n /** Override rendering for specific nav items. Return null to use default rendering. */\n renderItem?: (item: NavItem, defaultRender: () => React.ReactNode) => React.ReactNode | null\n /** Additional className for the root sidebar element */\n className?: string\n}\n\n// -----------------------------------------------------------------------\n// ChevronRight (inline SVG icon for collapsible toggle)\n// -----------------------------------------------------------------------\n\nfunction ChevronRight({ className }: { className?: string }) {\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className={className}\n >\n <path d=\"m9 18 6-6-6-6\" />\n </svg>\n )\n}\n\nfunction CloseIcon({ className }: { className?: string }) {\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className={className}\n >\n <path d=\"M18 6 6 18\" />\n <path d=\"m6 6 12 12\" />\n </svg>\n )\n}\n\n// -----------------------------------------------------------------------\n// Shared styles\n// -----------------------------------------------------------------------\n\nconst navItemBase = 'relative gap-ds-04 rounded-ds-lg px-ds-04 py-ds-03 transition-colors duration-fast-02'\nconst navItemActive =\n \"bg-accent-2 text-accent-11 after:absolute after:right-0 after:top-0 after:h-full after:w-ds-01 after:rounded-l-ds-full after:bg-accent-9 after:content-['']\"\nconst navItemInactive = 'text-surface-fg-subtle hover:bg-surface-raised-hover hover:text-surface-fg'\n\n// -----------------------------------------------------------------------\n// NavLink (internal)\n// -----------------------------------------------------------------------\n\nfunction NavLink({\n item,\n isActive,\n isPathActive,\n}: {\n item: NavItem\n isActive: boolean\n isPathActive: (path: string, exact?: boolean) => boolean\n}) {\n const Link = useLink()\n const badgeContent =\n item.badge != null\n ? typeof item.badge === 'number' && item.badge > 99\n ? '99+'\n : String(item.badge)\n : null\n\n // S9: Collapsible children\n if (item.children && item.children.length > 0) {\n const hasActiveChild = item.children.some((child) =>\n isPathActive(child.href, child.exact),\n )\n const shouldOpen = hasActiveChild || isActive || (item.defaultOpen ?? false)\n\n return (\n <Collapsible defaultOpen={shouldOpen} className=\"group/collapsible\">\n <SidebarMenuItem>\n {/* Button row — chevron is anchored here, not on the full <li> */}\n <div className=\"relative\">\n <SidebarMenuButton\n asChild\n isActive={isActive || hasActiveChild}\n tooltip={item.title}\n className={cn(\n navItemBase,\n isActive || hasActiveChild ? navItemActive : navItemInactive,\n )}\n >\n <Link\n href={item.href}\n aria-label={item.title}\n aria-current={isActive ? 'page' : undefined}\n >\n <span className=\"[&>svg]:h-ico-md [&>svg]:w-ico-md shrink-0\" aria-hidden=\"true\">\n {item.icon}\n </span>\n <span className=\"text-ds-base\">{item.title}</span>\n </Link>\n </SidebarMenuButton>\n {badgeContent && <SidebarMenuBadge>{badgeContent}</SidebarMenuBadge>}\n <CollapsibleTrigger asChild>\n <button\n className=\"absolute right-ds-02 top-1/2 flex h-5 w-5 -translate-y-1/2 items-center justify-center rounded-ds-md text-surface-fg-subtle transition-colors hover:bg-surface-raised-hover hover:text-surface-fg group-data-[collapsible=icon]:hidden\"\n aria-label={`Toggle ${item.title}`}\n >\n <ChevronRight className=\"h-4 w-4 transition-transform duration-fast-02 ease-productive-standard group-data-[state=open]/collapsible:rotate-90\" />\n </button>\n </CollapsibleTrigger>\n </div>\n <CollapsibleContent>\n <SidebarMenuSub>\n {item.children.map((child) => {\n const childActive = isPathActive(child.href, child.exact)\n return (\n <SidebarMenuSubItem key={child.href}>\n <SidebarMenuSubButton\n asChild\n isActive={childActive}\n >\n <Link\n href={child.href}\n aria-current={childActive ? 'page' : undefined}\n >\n {child.icon && (\n <span className=\"[&>svg]:h-ico-sm [&>svg]:w-ico-sm shrink-0\" aria-hidden=\"true\">\n {child.icon}\n </span>\n )}\n <span>{child.title}</span>\n </Link>\n </SidebarMenuSubButton>\n </SidebarMenuSubItem>\n )\n })}\n </SidebarMenuSub>\n </CollapsibleContent>\n </SidebarMenuItem>\n </Collapsible>\n )\n }\n\n // Default: flat nav item\n return (\n <SidebarMenuItem>\n <SidebarMenuButton\n asChild\n isActive={isActive}\n tooltip={item.title}\n className={cn(\n navItemBase,\n isActive ? navItemActive : navItemInactive,\n )}\n >\n <Link\n href={item.href}\n aria-label={item.title}\n aria-current={isActive ? 'page' : undefined}\n >\n <span className=\"[&>svg]:h-ico-md [&>svg]:w-ico-md shrink-0\" aria-hidden=\"true\">{item.icon}</span>\n <span className=\"text-ds-base\">{item.title}</span>\n </Link>\n </SidebarMenuButton>\n {badgeContent && <SidebarMenuBadge>{badgeContent}</SidebarMenuBadge>}\n </SidebarMenuItem>\n )\n}\n\n// -----------------------------------------------------------------------\n// AppSidebar\n// -----------------------------------------------------------------------\n\nconst AppSidebar = React.forwardRef<HTMLDivElement, AppSidebarProps>(\n (\n {\n currentPath = '/',\n user,\n navGroups = [],\n logo,\n headerSlot,\n preFooterSlot,\n preFooterClassName,\n footerLinks = [],\n footer,\n renderItem,\n className,\n ...props\n },\n ref,\n ) => {\n const Link = useLink()\n const isActive = (path: string, exact = false) => {\n if (exact || path === '/') {\n return currentPath === path\n }\n return currentPath.startsWith(path)\n }\n\n return (\n <ShadcnSidebar\n {...props}\n ref={ref}\n aria-label=\"Main navigation\"\n className={cn(\n 'z-raised hidden h-full flex-col border-r border-surface-border-strong bg-surface-raised md:flex',\n className,\n )}\n >\n {/* Logo Header */}\n <SidebarHeader className=\"px-ds-06 py-ds-06\">\n {logo ?? (\n <span className=\"text-ds-lg font-semibold text-surface-fg\">\n Logo\n </span>\n )}\n </SidebarHeader>\n\n {/* User Info */}\n {user && (\n <div className=\"flex items-center gap-ds-04 px-ds-06 pb-ds-05\">\n <Avatar className=\"h-ds-sm-plus w-ds-sm-plus\">\n {user.image ? (\n <AvatarImage src={user.image} alt={user.name} />\n ) : null}\n <AvatarFallback className=\"bg-surface-raised-hover text-surface-fg\">\n {user.name?.charAt(0).toUpperCase()}\n </AvatarFallback>\n </Avatar>\n <div className=\"flex min-w-0 flex-col\">\n <span className=\"truncate text-ds-md text-surface-fg\">\n {user.name}\n </span>\n <span className=\"truncate text-ds-sm text-surface-fg-subtle\">\n {user.designation || user.role}\n </span>\n </div>\n </div>\n )}\n\n <SidebarSeparator />\n\n {/* Header Slot (S13) */}\n {headerSlot && (\n <>\n {headerSlot}\n <SidebarSeparator />\n </>\n )}\n\n {/* Navigation Groups */}\n <SidebarContent className=\"no-scrollbar px-ds-04\">\n {navGroups.map((group, idx) => (\n <div key={group.label}>\n {idx > 0 && <SidebarSeparator />}\n <SidebarGroup>\n <SidebarGroupLabel className=\"px-ds-04 text-ds-sm text-surface-fg-subtle\">\n {group.label}\n </SidebarGroupLabel>\n {group.action && (\n <SidebarGroupAction asChild>{group.action}</SidebarGroupAction>\n )}\n <SidebarGroupContent>\n <SidebarMenu>\n {group.items.map((item) => {\n const defaultRender = () => (\n <NavLink\n item={item}\n isActive={isActive(item.href, item.exact)}\n isPathActive={isActive}\n />\n )\n\n if (renderItem) {\n const custom = renderItem(item, defaultRender)\n if (custom !== null) {\n return <React.Fragment key={item.href}>{custom}</React.Fragment>\n }\n }\n\n return <React.Fragment key={item.href}>{defaultRender()}</React.Fragment>\n })}\n </SidebarMenu>\n </SidebarGroupContent>\n </SidebarGroup>\n </div>\n ))}\n </SidebarContent>\n\n {/* Pre-Footer Slot (S13) */}\n {preFooterSlot && (\n <>\n <SidebarSeparator />\n <div className={preFooterClassName}>\n {preFooterSlot}\n </div>\n </>\n )}\n\n {/* Footer */}\n {footer ? (\n <SidebarFooter className=\"gap-ds-03 px-ds-06 py-ds-05\">\n {footer.slot && <div>{footer.slot}</div>}\n\n {/* Promo banner */}\n {footer.promo && (\n <div className=\"relative rounded-ds-lg border border-surface-border bg-surface-raised p-ds-04 shadow-raised\">\n {footer.promo.onDismiss && (\n <button\n onClick={footer.promo.onDismiss}\n aria-label=\"Dismiss\"\n className=\"absolute right-ds-02 top-ds-02 flex h-5 w-5 items-center justify-center rounded-ds-md text-surface-fg-subtle transition-colors hover:bg-surface-raised-hover hover:text-surface-fg\"\n >\n <CloseIcon className=\"h-3.5 w-3.5\" />\n </button>\n )}\n <div className=\"flex flex-col gap-ds-03\">\n {footer.promo.icon && (\n <span className=\"text-accent-11 [&>svg]:h-ico-md [&>svg]:w-ico-md\" aria-hidden=\"true\">\n {footer.promo.icon}\n </span>\n )}\n <div className=\"flex min-w-0 flex-col gap-ds-03\">\n <p className=\"text-ds-sm text-surface-fg\">{footer.promo.text}</p>\n {footer.promo.action && (\n footer.promo.action.href ? (\n <Link\n href={footer.promo.action.href}\n onClick={footer.promo.action.onClick}\n className=\"inline-flex self-start rounded-ds-md bg-accent-9 px-ds-04 py-ds-02 text-ds-sm font-medium text-accent-fg transition-colors hover:bg-accent-10\"\n >\n {footer.promo.action.label}\n </Link>\n ) : (\n <button\n onClick={footer.promo.action.onClick}\n className=\"inline-flex self-start rounded-ds-md bg-accent-9 px-ds-04 py-ds-02 text-ds-sm font-medium text-accent-fg transition-colors hover:bg-accent-10\"\n >\n {footer.promo.action.label}\n </button>\n )\n )}\n </div>\n </div>\n </div>\n )}\n\n {/* Links + version on same line */}\n {(footer.links?.length || footer.version) && (\n <div className=\"flex items-center gap-ds-03 text-ds-sm text-surface-fg-subtle\">\n {footer.links?.map((link, i) => (\n <React.Fragment key={link.href}>\n {i > 0 && <span>·</span>}\n <Link\n className=\"transition-colors hover:text-accent-11\"\n href={link.href}\n >\n {link.label}\n </Link>\n </React.Fragment>\n ))}\n {footer.links?.length && footer.version && <span>·</span>}\n {footer.version && (\n typeof footer.version === 'string'\n ? <span>{footer.version}</span>\n : <Link className=\"transition-colors hover:text-accent-11\" href={footer.version.href}>{footer.version.label}</Link>\n )}\n </div>\n )}\n </SidebarFooter>\n ) : footerLinks.length > 0 ? (\n <SidebarFooter className=\"px-ds-06 py-ds-05\">\n <div className=\"flex items-center gap-ds-03 text-ds-sm text-surface-fg-subtle\">\n {footerLinks.map((link, i) => (\n <React.Fragment key={link.href}>\n {i > 0 && <span>·</span>}\n <Link\n className=\"transition-colors hover:text-accent-11\"\n href={link.href}\n >\n {link.label}\n </Link>\n </React.Fragment>\n ))}\n </div>\n </SidebarFooter>\n ) : null}\n </ShadcnSidebar>\n )\n },\n)\nAppSidebar.displayName = 'AppSidebar'\n\nexport { AppSidebar }\n"],"mappings":"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"}
@@ -1,10 +1,4 @@
1
1
  "use client";
2
- /**
3
- * TopBar v2 — Composition-based application top bar.
4
- *
5
- * Subcomponents: TopBar.Left, TopBar.Center, TopBar.Right,
6
- * TopBar.Section, TopBar.IconButton, TopBar.Title, TopBar.UserMenu.
7
- */
8
2
  import * as React from 'react';
9
3
  export interface TopBarUser {
10
4
  name: string;
@@ -1 +1 @@
1
- {"version":3,"file":"top-bar.d.ts","sourceRoot":"","sources":["../../src/shell/top-bar.tsx"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAuB9B,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CACtB;AAED,MAAM,WAAW,YAAY;IAC3B,oBAAoB;IACpB,KAAK,EAAE,MAAM,CAAA;IACb,gCAAgC;IAChC,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACtB,2CAA2C;IAC3C,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,2BAA2B;IAC3B,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;IACpB,0CAA0C;IAC1C,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,sEAAsE;IACtE,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,+DAA+D;IAC/D,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;IACxB,mCAAmC;IACnC,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB;AAMD,UAAU,eAAgB,SAAQ,KAAK,CAAC,cAAc,CAAC,WAAW,CAAC;IACjE,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;IACzB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAgCD,UAAU,eAAgB,SAAQ,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC;IACpE,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;CAC1B;AAmBD,UAAU,iBAAkB,SAAQ,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC;IACtE,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;CAC1B;AAmBD,UAAU,gBAAiB,SAAQ,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC;IACrE,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;CAC1B;AAmBD,QAAA,MAAM,MAAM;;;;CAIF,CAAA;AAEV,UAAU,kBAAmB,SAAQ,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC;IACvE,GAAG,CAAC,EAAE,MAAM,OAAO,MAAM,CAAA;IACzB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;CAC1B;AAmBD,UAAU,qBACR,SAAQ,KAAK,CAAC,oBAAoB,CAAC,iBAAiB,CAAC;IACrD,IAAI,EAAE,KAAK,CAAC,SAAS,CAAA;IACrB,OAAO,EAAE,MAAM,CAAA;CAChB;AAkCD,UAAU,gBAAiB,SAAQ,KAAK,CAAC,cAAc,CAAC,kBAAkB,CAAC;IACzE,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;CAC1B;AAsBD,UAAU,mBAAmB;IAC3B,IAAI,EAAE,UAAU,CAAA;IAChB,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IACnC,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAA;IACrB,aAAa,CAAC,EAAE,YAAY,EAAE,CAAA;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAiJD,MAAM,MAAM,WAAW,GAAG,eAAe,CAAA;AAEzC,QAAA,MAAM,MAAM;;;;;;;;CAQV,CAAA;AAEF,OAAO,EAAE,MAAM,EAAE,CAAA"}
1
+ {"version":3,"file":"top-bar.d.ts","sourceRoot":"","sources":["../../src/shell/top-bar.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAuB9B,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CACtB;AAED,MAAM,WAAW,YAAY;IAC3B,oBAAoB;IACpB,KAAK,EAAE,MAAM,CAAA;IACb,gCAAgC;IAChC,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACtB,2CAA2C;IAC3C,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,2BAA2B;IAC3B,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;IACpB,0CAA0C;IAC1C,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,sEAAsE;IACtE,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,+DAA+D;IAC/D,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;IACxB,mCAAmC;IACnC,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB;AAMD,UAAU,eAAgB,SAAQ,KAAK,CAAC,cAAc,CAAC,WAAW,CAAC;IACjE,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;IACzB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAgCD,UAAU,eAAgB,SAAQ,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC;IACpE,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;CAC1B;AAmBD,UAAU,iBAAkB,SAAQ,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC;IACtE,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;CAC1B;AAmBD,UAAU,gBAAiB,SAAQ,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC;IACrE,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;CAC1B;AAmBD,QAAA,MAAM,MAAM;;;;CAIF,CAAA;AAEV,UAAU,kBAAmB,SAAQ,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC;IACvE,GAAG,CAAC,EAAE,MAAM,OAAO,MAAM,CAAA;IACzB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;CAC1B;AAmBD,UAAU,qBACR,SAAQ,KAAK,CAAC,oBAAoB,CAAC,iBAAiB,CAAC;IACrD,IAAI,EAAE,KAAK,CAAC,SAAS,CAAA;IACrB,OAAO,EAAE,MAAM,CAAA;CAChB;AAkCD,UAAU,gBAAiB,SAAQ,KAAK,CAAC,cAAc,CAAC,kBAAkB,CAAC;IACzE,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;CAC1B;AAsBD,UAAU,mBAAmB;IAC3B,IAAI,EAAE,UAAU,CAAA;IAChB,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IACnC,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAA;IACrB,aAAa,CAAC,EAAE,YAAY,EAAE,CAAA;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAiJD,MAAM,MAAM,WAAW,GAAG,eAAe,CAAA;AAEzC,QAAA,MAAM,MAAM;;;;;;;;CAQV,CAAA;AAEF,OAAO,EAAE,MAAM,EAAE,CAAA"}