snice 4.29.0 → 4.30.1

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 (516) hide show
  1. package/README.md +3 -10
  2. package/adapters/react/SniceProvider.d.ts +71 -0
  3. package/adapters/react/SniceProvider.js +49 -0
  4. package/adapters/react/SniceProvider.js.map +1 -0
  5. package/adapters/react/SniceRouter.d.ts +44 -0
  6. package/adapters/react/SniceRouter.js +190 -0
  7. package/adapters/react/SniceRouter.js.map +1 -0
  8. package/adapters/react/components.d.ts +2 -0
  9. package/adapters/react/components.d.ts.map +1 -1
  10. package/adapters/react/components.js +1 -0
  11. package/adapters/react/components.js.map +1 -1
  12. package/adapters/react/components.ts +2 -0
  13. package/adapters/react/grid.d.ts +36 -0
  14. package/adapters/react/grid.d.ts.map +1 -0
  15. package/adapters/react/grid.js +24 -0
  16. package/adapters/react/grid.js.map +1 -0
  17. package/adapters/react/grid.tsx +44 -0
  18. package/adapters/react/index.d.ts +5 -0
  19. package/adapters/react/index.d.ts.map +1 -1
  20. package/adapters/react/index.js +3 -2
  21. package/adapters/react/index.js.map +1 -1
  22. package/adapters/react/index.ts +6 -3
  23. package/adapters/react/matchRoute.d.ts +16 -0
  24. package/adapters/react/matchRoute.js +32 -0
  25. package/adapters/react/matchRoute.js.map +1 -0
  26. package/adapters/react/types.d.ts +1 -15
  27. package/adapters/react/types.d.ts.map +1 -1
  28. package/adapters/react/types.ts +1 -15
  29. package/adapters/react/useRequestHandler.js +1 -1
  30. package/adapters/react/useRequestHandler.js.map +1 -1
  31. package/bin/snice.js +8 -13
  32. package/bin/templates/{pwa → default}/index.html +1 -1
  33. package/bin/templates/{pwa → default}/src/components/app-header.ts +36 -18
  34. package/bin/templates/{pwa → default}/src/components/notification-badge.ts +2 -21
  35. package/bin/templates/{pwa → default}/src/components/search-bar.ts +12 -12
  36. package/bin/templates/default/src/context.ts +17 -0
  37. package/bin/templates/{pwa → default}/src/controllers/notification-controller.ts +10 -15
  38. package/bin/templates/{pwa → default}/src/daemons/notifications.ts +0 -12
  39. package/bin/templates/{pwa → default}/src/main.ts +1 -7
  40. package/bin/templates/{pwa → default}/src/middleware/error.ts +1 -8
  41. package/bin/templates/{pwa → default}/src/pages/dashboard.ts +17 -18
  42. package/bin/templates/{pwa → default}/src/pages/data.ts +24 -24
  43. package/bin/templates/{pwa → default}/src/pages/login.ts +3 -6
  44. package/bin/templates/{pwa → default}/src/pages/notifications.ts +21 -19
  45. package/bin/templates/{pwa → default}/src/pages/profile.ts +10 -12
  46. package/bin/templates/{pwa → default}/src/pages/settings.ts +22 -22
  47. package/bin/templates/default/src/router.ts +13 -0
  48. package/bin/templates/default/src/styles/global.css +16 -0
  49. package/bin/templates/{pwa → default}/tsconfig.json +2 -1
  50. package/bin/templates/react/README.md +124 -0
  51. package/bin/templates/react/global.d.ts +10 -0
  52. package/bin/templates/react/index.html +15 -0
  53. package/bin/templates/react/package.json +31 -0
  54. package/bin/templates/react/src/App.tsx +112 -0
  55. package/bin/templates/react/src/components/AppHeader.tsx +85 -0
  56. package/bin/templates/react/src/components/AppLayout.tsx +11 -0
  57. package/bin/templates/react/src/components/NotificationBadge.tsx +13 -0
  58. package/bin/templates/react/src/components/SearchBar.tsx +63 -0
  59. package/bin/templates/react/src/daemons/notifications.ts +136 -0
  60. package/bin/templates/react/src/fetcher.ts +15 -0
  61. package/bin/templates/react/src/guards/auth.ts +6 -0
  62. package/bin/templates/react/src/main.tsx +27 -0
  63. package/bin/templates/react/src/middleware/auth.ts +16 -0
  64. package/bin/templates/react/src/middleware/error.ts +29 -0
  65. package/bin/templates/react/src/middleware/retry.ts +31 -0
  66. package/bin/templates/react/src/pages/DashboardPage.tsx +111 -0
  67. package/bin/templates/react/src/pages/DataPage.tsx +119 -0
  68. package/bin/templates/react/src/pages/LoginPage.tsx +46 -0
  69. package/bin/templates/react/src/pages/NotificationsPage.tsx +119 -0
  70. package/bin/templates/react/src/pages/ProfilePage.tsx +92 -0
  71. package/bin/templates/react/src/pages/SettingsPage.tsx +165 -0
  72. package/bin/templates/react/src/services/auth.ts +48 -0
  73. package/bin/templates/react/src/services/jwt.ts +35 -0
  74. package/bin/templates/react/src/services/storage.ts +24 -0
  75. package/bin/templates/react/src/styles/global.css +382 -0
  76. package/bin/templates/react/src/types/auth.ts +21 -0
  77. package/bin/templates/react/src/types/notifications.ts +9 -0
  78. package/bin/templates/react/tests/helpers/test-utils.ts +79 -0
  79. package/bin/templates/react/tests/middleware/auth.test.ts +67 -0
  80. package/bin/templates/react/tests/middleware/error.test.ts +105 -0
  81. package/bin/templates/react/tests/middleware/retry.test.ts +103 -0
  82. package/bin/templates/react/tests/services/auth.test.ts +89 -0
  83. package/bin/templates/react/tests/services/jwt.test.ts +76 -0
  84. package/bin/templates/react/tests/services/storage.test.ts +69 -0
  85. package/bin/templates/{base → react}/tsconfig.json +4 -6
  86. package/bin/templates/react/vite.config.ts +18 -0
  87. package/bin/templates/react/vitest.config.ts +18 -0
  88. package/dist/cdn/accordion/snice-accordion.js +1 -1
  89. package/dist/cdn/accordion/snice-accordion.min.js +1 -1
  90. package/dist/cdn/action-bar/snice-action-bar.js +1 -1
  91. package/dist/cdn/action-bar/snice-action-bar.min.js +1 -1
  92. package/dist/cdn/activity-feed/snice-activity-feed.js +1 -1
  93. package/dist/cdn/activity-feed/snice-activity-feed.min.js +1 -1
  94. package/dist/cdn/alert/snice-alert.js +1 -1
  95. package/dist/cdn/alert/snice-alert.min.js +1 -1
  96. package/dist/cdn/app-tiles/snice-app-tiles.js +1 -1
  97. package/dist/cdn/app-tiles/snice-app-tiles.min.js +1 -1
  98. package/dist/cdn/approval-flow/snice-approval-flow.js +1 -1
  99. package/dist/cdn/approval-flow/snice-approval-flow.min.js +1 -1
  100. package/dist/cdn/audio-recorder/snice-audio-recorder.js +1 -1
  101. package/dist/cdn/audio-recorder/snice-audio-recorder.min.js +1 -1
  102. package/dist/cdn/availability/snice-availability.js +1 -1
  103. package/dist/cdn/availability/snice-availability.min.js +1 -1
  104. package/dist/cdn/avatar/snice-avatar.js +1 -1
  105. package/dist/cdn/avatar/snice-avatar.min.js +1 -1
  106. package/dist/cdn/avatar-group/snice-avatar-group.js +1 -1
  107. package/dist/cdn/avatar-group/snice-avatar-group.min.js +1 -1
  108. package/dist/cdn/badge/snice-badge.js +1 -1
  109. package/dist/cdn/badge/snice-badge.min.js +1 -1
  110. package/dist/cdn/banner/snice-banner.js +1 -1
  111. package/dist/cdn/banner/snice-banner.min.js +1 -1
  112. package/dist/cdn/binpack/snice-binpack.js +1 -1
  113. package/dist/cdn/binpack/snice-binpack.min.js +1 -1
  114. package/dist/cdn/book/snice-book.js +1 -1
  115. package/dist/cdn/book/snice-book.min.js +1 -1
  116. package/dist/cdn/booking/snice-booking.js +1 -1
  117. package/dist/cdn/booking/snice-booking.min.js +1 -1
  118. package/dist/cdn/breadcrumbs/snice-breadcrumbs.js +1 -1
  119. package/dist/cdn/breadcrumbs/snice-breadcrumbs.min.js +1 -1
  120. package/dist/cdn/button/snice-button.js +1 -1
  121. package/dist/cdn/button/snice-button.min.js +1 -1
  122. package/dist/cdn/calendar/snice-calendar.js +1 -1
  123. package/dist/cdn/calendar/snice-calendar.min.js +1 -1
  124. package/dist/cdn/camera/snice-camera.js +1 -1
  125. package/dist/cdn/camera/snice-camera.min.js +1 -1
  126. package/dist/cdn/camera-annotate/snice-camera-annotate.js +1 -1
  127. package/dist/cdn/camera-annotate/snice-camera-annotate.min.js +1 -1
  128. package/dist/cdn/candlestick/snice-candlestick.js +1 -1
  129. package/dist/cdn/candlestick/snice-candlestick.min.js +1 -1
  130. package/dist/cdn/card/snice-card.js +1 -1
  131. package/dist/cdn/card/snice-card.min.js +1 -1
  132. package/dist/cdn/carousel/snice-carousel.js +1 -1
  133. package/dist/cdn/carousel/snice-carousel.min.js +1 -1
  134. package/dist/cdn/cart/snice-cart.js +1 -1
  135. package/dist/cdn/cart/snice-cart.min.js +1 -1
  136. package/dist/cdn/chart/snice-chart.js +1 -1
  137. package/dist/cdn/chart/snice-chart.min.js +1 -1
  138. package/dist/cdn/chat/snice-chat.js +1 -1
  139. package/dist/cdn/chat/snice-chat.min.js +1 -1
  140. package/dist/cdn/checkbox/snice-checkbox.js +1 -1
  141. package/dist/cdn/checkbox/snice-checkbox.min.js +1 -1
  142. package/dist/cdn/chip/README.md +2 -2
  143. package/dist/cdn/chip/snice-chip.js +2 -2
  144. package/dist/cdn/chip/snice-chip.js.map +1 -1
  145. package/dist/cdn/chip/snice-chip.min.js +3 -3
  146. package/dist/cdn/chip/snice-chip.min.js.map +1 -1
  147. package/dist/cdn/code-block/snice-code-block.js +1 -1
  148. package/dist/cdn/code-block/snice-code-block.min.js +1 -1
  149. package/dist/cdn/color-display/snice-color-display.js +1 -1
  150. package/dist/cdn/color-display/snice-color-display.min.js +1 -1
  151. package/dist/cdn/color-picker/snice-color-picker.js +1 -1
  152. package/dist/cdn/color-picker/snice-color-picker.min.js +1 -1
  153. package/dist/cdn/command-palette/snice-command-palette.js +1 -1
  154. package/dist/cdn/command-palette/snice-command-palette.min.js +1 -1
  155. package/dist/cdn/comments/snice-comments.js +1 -1
  156. package/dist/cdn/comments/snice-comments.min.js +1 -1
  157. package/dist/cdn/countdown/snice-countdown.js +1 -1
  158. package/dist/cdn/countdown/snice-countdown.min.js +1 -1
  159. package/dist/cdn/cropper/snice-cropper.js +1 -1
  160. package/dist/cdn/cropper/snice-cropper.min.js +1 -1
  161. package/dist/cdn/data-card/snice-data-card.js +1 -1
  162. package/dist/cdn/data-card/snice-data-card.min.js +1 -1
  163. package/dist/cdn/date-picker/README.md +1 -1
  164. package/dist/cdn/date-picker/snice-date-picker.js +2 -2
  165. package/dist/cdn/date-picker/snice-date-picker.js.map +1 -1
  166. package/dist/cdn/date-picker/snice-date-picker.min.js +2 -2
  167. package/dist/cdn/date-picker/snice-date-picker.min.js.map +1 -1
  168. package/dist/cdn/date-range-picker/README.md +1 -1
  169. package/dist/cdn/date-range-picker/snice-date-range-picker.js +2 -2
  170. package/dist/cdn/date-range-picker/snice-date-range-picker.js.map +1 -1
  171. package/dist/cdn/date-range-picker/snice-date-range-picker.min.js +11 -11
  172. package/dist/cdn/date-range-picker/snice-date-range-picker.min.js.map +1 -1
  173. package/dist/cdn/date-time-picker/README.md +1 -1
  174. package/dist/cdn/date-time-picker/snice-date-time-picker.js +2 -2
  175. package/dist/cdn/date-time-picker/snice-date-time-picker.js.map +1 -1
  176. package/dist/cdn/date-time-picker/snice-date-time-picker.min.js +2 -2
  177. package/dist/cdn/date-time-picker/snice-date-time-picker.min.js.map +1 -1
  178. package/dist/cdn/diff/snice-diff.js +1 -1
  179. package/dist/cdn/diff/snice-diff.min.js +1 -1
  180. package/dist/cdn/divider/snice-divider.js +1 -1
  181. package/dist/cdn/divider/snice-divider.min.js +1 -1
  182. package/dist/cdn/doc/snice-doc.js +1 -1
  183. package/dist/cdn/doc/snice-doc.min.js +1 -1
  184. package/dist/cdn/draw/README.md +2 -2
  185. package/dist/cdn/draw/snice-draw.js +26 -4
  186. package/dist/cdn/draw/snice-draw.js.map +1 -1
  187. package/dist/cdn/draw/snice-draw.min.js +3 -3
  188. package/dist/cdn/draw/snice-draw.min.js.map +1 -1
  189. package/dist/cdn/drawer/snice-drawer.js +1 -1
  190. package/dist/cdn/drawer/snice-drawer.min.js +1 -1
  191. package/dist/cdn/empty-state/snice-empty-state.js +1 -1
  192. package/dist/cdn/empty-state/snice-empty-state.min.js +1 -1
  193. package/dist/cdn/estimate/snice-estimate.js +1 -1
  194. package/dist/cdn/estimate/snice-estimate.min.js +1 -1
  195. package/dist/cdn/file-gallery/snice-file-gallery.js +1 -1
  196. package/dist/cdn/file-gallery/snice-file-gallery.min.js +1 -1
  197. package/dist/cdn/file-upload/snice-file-upload.js +1 -1
  198. package/dist/cdn/file-upload/snice-file-upload.min.js +1 -1
  199. package/dist/cdn/flip-card/snice-flip-card.js +1 -1
  200. package/dist/cdn/flip-card/snice-flip-card.min.js +1 -1
  201. package/dist/cdn/flow/snice-flow.js +1 -1
  202. package/dist/cdn/flow/snice-flow.min.js +1 -1
  203. package/dist/cdn/form-layout/snice-form-layout.js +1 -1
  204. package/dist/cdn/form-layout/snice-form-layout.min.js +1 -1
  205. package/dist/cdn/funnel/snice-funnel.js +1 -1
  206. package/dist/cdn/funnel/snice-funnel.min.js +1 -1
  207. package/dist/cdn/gantt/snice-gantt.js +1 -1
  208. package/dist/cdn/gantt/snice-gantt.min.js +1 -1
  209. package/dist/cdn/gauge/snice-gauge.js +1 -1
  210. package/dist/cdn/gauge/snice-gauge.min.js +1 -1
  211. package/dist/cdn/grid/README.md +27 -0
  212. package/dist/cdn/grid/snice-grid.js +862 -0
  213. package/dist/cdn/grid/snice-grid.js.map +1 -0
  214. package/dist/cdn/grid/snice-grid.min.js +13 -0
  215. package/dist/cdn/grid/snice-grid.min.js.map +1 -0
  216. package/dist/cdn/heatmap/snice-heatmap.js +1 -1
  217. package/dist/cdn/heatmap/snice-heatmap.min.js +1 -1
  218. package/dist/cdn/image/snice-image.js +1 -1
  219. package/dist/cdn/image/snice-image.min.js +1 -1
  220. package/dist/cdn/input/snice-input.js +1 -1
  221. package/dist/cdn/input/snice-input.min.js +1 -1
  222. package/dist/cdn/invoice/snice-invoice.js +1 -1
  223. package/dist/cdn/invoice/snice-invoice.min.js +1 -1
  224. package/dist/cdn/kanban/snice-kanban.js +1 -1
  225. package/dist/cdn/kanban/snice-kanban.min.js +1 -1
  226. package/dist/cdn/key-value/snice-key-value.js +1 -1
  227. package/dist/cdn/key-value/snice-key-value.min.js +1 -1
  228. package/dist/cdn/kpi/snice-kpi.js +1 -1
  229. package/dist/cdn/kpi/snice-kpi.min.js +1 -1
  230. package/dist/cdn/layout/snice-layout.js +1 -1
  231. package/dist/cdn/layout/snice-layout.min.js +1 -1
  232. package/dist/cdn/leaderboard/snice-leaderboard.js +1 -1
  233. package/dist/cdn/leaderboard/snice-leaderboard.min.js +1 -1
  234. package/dist/cdn/link/snice-link.js +1 -1
  235. package/dist/cdn/link/snice-link.min.js +1 -1
  236. package/dist/cdn/link-preview/snice-link-preview.js +1 -1
  237. package/dist/cdn/link-preview/snice-link-preview.min.js +1 -1
  238. package/dist/cdn/list/snice-list.js +1 -1
  239. package/dist/cdn/list/snice-list.min.js +1 -1
  240. package/dist/cdn/location/snice-location.js +1 -1
  241. package/dist/cdn/location/snice-location.min.js +1 -1
  242. package/dist/cdn/login/snice-login.js +1 -1
  243. package/dist/cdn/login/snice-login.min.js +1 -1
  244. package/dist/cdn/map/snice-map.js +1 -1
  245. package/dist/cdn/map/snice-map.min.js +1 -1
  246. package/dist/cdn/markdown/snice-markdown.js +1 -1
  247. package/dist/cdn/markdown/snice-markdown.min.js +1 -1
  248. package/dist/cdn/masonry/snice-masonry.js +1 -1
  249. package/dist/cdn/masonry/snice-masonry.min.js +1 -1
  250. package/dist/cdn/menu/snice-menu.js +1 -1
  251. package/dist/cdn/menu/snice-menu.min.js +1 -1
  252. package/dist/cdn/message-strip/README.md +2 -2
  253. package/dist/cdn/message-strip/snice-message-strip.js +2 -2
  254. package/dist/cdn/message-strip/snice-message-strip.js.map +1 -1
  255. package/dist/cdn/message-strip/snice-message-strip.min.js +6 -6
  256. package/dist/cdn/message-strip/snice-message-strip.min.js.map +1 -1
  257. package/dist/cdn/metric-table/snice-metric-table.js +1 -1
  258. package/dist/cdn/metric-table/snice-metric-table.min.js +1 -1
  259. package/dist/cdn/modal/snice-modal.js +1 -1
  260. package/dist/cdn/modal/snice-modal.min.js +1 -1
  261. package/dist/cdn/music-player/snice-music-player.js +1 -1
  262. package/dist/cdn/music-player/snice-music-player.min.js +1 -1
  263. package/dist/cdn/nav/snice-nav.js +1 -1
  264. package/dist/cdn/nav/snice-nav.min.js +1 -1
  265. package/dist/cdn/network-graph/snice-network-graph.js +1 -1
  266. package/dist/cdn/network-graph/snice-network-graph.min.js +1 -1
  267. package/dist/cdn/notification-center/snice-notification-center.js +1 -1
  268. package/dist/cdn/notification-center/snice-notification-center.min.js +1 -1
  269. package/dist/cdn/order-tracker/snice-order-tracker.js +1 -1
  270. package/dist/cdn/order-tracker/snice-order-tracker.min.js +1 -1
  271. package/dist/cdn/org-chart/snice-org-chart.js +1 -1
  272. package/dist/cdn/org-chart/snice-org-chart.min.js +1 -1
  273. package/dist/cdn/pagination/snice-pagination.js +1 -1
  274. package/dist/cdn/pagination/snice-pagination.min.js +1 -1
  275. package/dist/cdn/paint/README.md +2 -2
  276. package/dist/cdn/paint/snice-paint.js +26 -3
  277. package/dist/cdn/paint/snice-paint.js.map +1 -1
  278. package/dist/cdn/paint/snice-paint.min.js +3 -3
  279. package/dist/cdn/paint/snice-paint.min.js.map +1 -1
  280. package/dist/cdn/pdf-viewer/snice-pdf-viewer.js +1 -1
  281. package/dist/cdn/pdf-viewer/snice-pdf-viewer.min.js +1 -1
  282. package/dist/cdn/permission-matrix/snice-permission-matrix.js +1 -1
  283. package/dist/cdn/permission-matrix/snice-permission-matrix.min.js +1 -1
  284. package/dist/cdn/podcast-player/snice-podcast-player.js +1 -1
  285. package/dist/cdn/podcast-player/snice-podcast-player.min.js +1 -1
  286. package/dist/cdn/pricing-table/snice-pricing-table.js +1 -1
  287. package/dist/cdn/pricing-table/snice-pricing-table.min.js +1 -1
  288. package/dist/cdn/product-card/README.md +1 -1
  289. package/dist/cdn/product-card/snice-product-card.js +1 -1
  290. package/dist/cdn/product-card/snice-product-card.min.js +1 -1
  291. package/dist/cdn/progress/snice-progress.js +1 -1
  292. package/dist/cdn/progress/snice-progress.min.js +1 -1
  293. package/dist/cdn/progress-ring/snice-progress-ring.js +1 -1
  294. package/dist/cdn/progress-ring/snice-progress-ring.min.js +1 -1
  295. package/dist/cdn/qr-code/snice-qr-code.js +1 -1
  296. package/dist/cdn/qr-code/snice-qr-code.min.js +1 -1
  297. package/dist/cdn/qr-reader/snice-qr-reader.js +1 -1
  298. package/dist/cdn/qr-reader/snice-qr-reader.min.js +1 -1
  299. package/dist/cdn/radio/snice-radio.js +1 -1
  300. package/dist/cdn/radio/snice-radio.min.js +1 -1
  301. package/dist/cdn/range-slider/snice-range-slider.js +1 -1
  302. package/dist/cdn/range-slider/snice-range-slider.min.js +1 -1
  303. package/dist/cdn/rating/snice-rating.js +1 -1
  304. package/dist/cdn/rating/snice-rating.min.js +1 -1
  305. package/dist/cdn/receipt/snice-receipt.js +1 -1
  306. package/dist/cdn/receipt/snice-receipt.min.js +1 -1
  307. package/dist/cdn/recipe/snice-recipe.js +1 -1
  308. package/dist/cdn/recipe/snice-recipe.min.js +1 -1
  309. package/dist/cdn/runtime/README.md +2 -2
  310. package/dist/cdn/runtime/snice-runtime.esm.js +40 -15
  311. package/dist/cdn/runtime/snice-runtime.esm.js.map +1 -1
  312. package/dist/cdn/runtime/snice-runtime.esm.min.js +7 -7
  313. package/dist/cdn/runtime/snice-runtime.esm.min.js.map +1 -1
  314. package/dist/cdn/runtime/snice-runtime.js +40 -15
  315. package/dist/cdn/runtime/snice-runtime.js.map +1 -1
  316. package/dist/cdn/runtime/snice-runtime.min.js +6 -6
  317. package/dist/cdn/runtime/snice-runtime.min.js.map +1 -1
  318. package/dist/cdn/sankey/snice-sankey.js +1 -1
  319. package/dist/cdn/sankey/snice-sankey.min.js +1 -1
  320. package/dist/cdn/segmented-control/snice-segmented-control.js +1 -1
  321. package/dist/cdn/segmented-control/snice-segmented-control.min.js +1 -1
  322. package/dist/cdn/select/snice-select.js +1 -1
  323. package/dist/cdn/select/snice-select.min.js +1 -1
  324. package/dist/cdn/skeleton/snice-skeleton.js +1 -1
  325. package/dist/cdn/skeleton/snice-skeleton.min.js +1 -1
  326. package/dist/cdn/slider/snice-slider.js +1 -1
  327. package/dist/cdn/slider/snice-slider.min.js +1 -1
  328. package/dist/cdn/sortable/snice-sortable.js +1 -1
  329. package/dist/cdn/sortable/snice-sortable.min.js +1 -1
  330. package/dist/cdn/sparkline/snice-sparkline.js +1 -1
  331. package/dist/cdn/sparkline/snice-sparkline.min.js +1 -1
  332. package/dist/cdn/spinner/snice-spinner.js +1 -1
  333. package/dist/cdn/spinner/snice-spinner.min.js +1 -1
  334. package/dist/cdn/split-button/snice-split-button.js +1 -1
  335. package/dist/cdn/split-button/snice-split-button.min.js +1 -1
  336. package/dist/cdn/split-pane/snice-split-pane.js +1 -1
  337. package/dist/cdn/split-pane/snice-split-pane.min.js +1 -1
  338. package/dist/cdn/spotlight/snice-spotlight.js +1 -1
  339. package/dist/cdn/spotlight/snice-spotlight.min.js +1 -1
  340. package/dist/cdn/spreadsheet/snice-spreadsheet.js +1 -1
  341. package/dist/cdn/spreadsheet/snice-spreadsheet.min.js +1 -1
  342. package/dist/cdn/stat-group/snice-stat-group.js +1 -1
  343. package/dist/cdn/stat-group/snice-stat-group.min.js +1 -1
  344. package/dist/cdn/step-input/snice-step-input.js +1 -1
  345. package/dist/cdn/step-input/snice-step-input.min.js +1 -1
  346. package/dist/cdn/stepper/snice-stepper.js +1 -1
  347. package/dist/cdn/stepper/snice-stepper.min.js +1 -1
  348. package/dist/cdn/switch/snice-switch.js +1 -1
  349. package/dist/cdn/switch/snice-switch.min.js +1 -1
  350. package/dist/cdn/table/snice-table.js +1 -1
  351. package/dist/cdn/table/snice-table.min.js +1 -1
  352. package/dist/cdn/tabs/snice-tabs.js +1 -1
  353. package/dist/cdn/tabs/snice-tabs.min.js +1 -1
  354. package/dist/cdn/tag/README.md +1 -1
  355. package/dist/cdn/tag/snice-tag.js +2 -2
  356. package/dist/cdn/tag/snice-tag.js.map +1 -1
  357. package/dist/cdn/tag/snice-tag.min.js +3 -3
  358. package/dist/cdn/tag/snice-tag.min.js.map +1 -1
  359. package/dist/cdn/tag-input/README.md +2 -2
  360. package/dist/cdn/tag-input/snice-tag-input.js +2 -2
  361. package/dist/cdn/tag-input/snice-tag-input.js.map +1 -1
  362. package/dist/cdn/tag-input/snice-tag-input.min.js +2 -2
  363. package/dist/cdn/tag-input/snice-tag-input.min.js.map +1 -1
  364. package/dist/cdn/terminal/snice-terminal.js +1 -1
  365. package/dist/cdn/terminal/snice-terminal.min.js +1 -1
  366. package/dist/cdn/testimonial/snice-testimonial.js +1 -1
  367. package/dist/cdn/testimonial/snice-testimonial.min.js +1 -1
  368. package/dist/cdn/textarea/snice-textarea.js +1 -1
  369. package/dist/cdn/textarea/snice-textarea.min.js +1 -1
  370. package/dist/cdn/time-picker/README.md +1 -1
  371. package/dist/cdn/time-picker/snice-time-picker.js +2 -2
  372. package/dist/cdn/time-picker/snice-time-picker.js.map +1 -1
  373. package/dist/cdn/time-picker/snice-time-picker.min.js +2 -2
  374. package/dist/cdn/time-picker/snice-time-picker.min.js.map +1 -1
  375. package/dist/cdn/time-range-picker/snice-time-range-picker.js +1 -1
  376. package/dist/cdn/time-range-picker/snice-time-range-picker.min.js +1 -1
  377. package/dist/cdn/timeline/snice-timeline.js +1 -1
  378. package/dist/cdn/timeline/snice-timeline.min.js +1 -1
  379. package/dist/cdn/timer/snice-timer.js +1 -1
  380. package/dist/cdn/timer/snice-timer.min.js +1 -1
  381. package/dist/cdn/toast/README.md +1 -1
  382. package/dist/cdn/toast/snice-toast.js +7 -3
  383. package/dist/cdn/toast/snice-toast.js.map +1 -1
  384. package/dist/cdn/toast/snice-toast.min.js +6 -6
  385. package/dist/cdn/toast/snice-toast.min.js.map +1 -1
  386. package/dist/cdn/tooltip/snice-tooltip.js +1 -1
  387. package/dist/cdn/tooltip/snice-tooltip.min.js +1 -1
  388. package/dist/cdn/tree/snice-tree.js +1 -1
  389. package/dist/cdn/tree/snice-tree.min.js +1 -1
  390. package/dist/cdn/treemap/snice-treemap.js +1 -1
  391. package/dist/cdn/treemap/snice-treemap.min.js +1 -1
  392. package/dist/cdn/user-card/snice-user-card.js +1 -1
  393. package/dist/cdn/user-card/snice-user-card.min.js +1 -1
  394. package/dist/cdn/video-player/snice-video-player.js +1 -1
  395. package/dist/cdn/video-player/snice-video-player.min.js +1 -1
  396. package/dist/cdn/virtual-scroller/snice-virtual-scroller.js +1 -1
  397. package/dist/cdn/virtual-scroller/snice-virtual-scroller.min.js +1 -1
  398. package/dist/cdn/waterfall/README.md +1 -1
  399. package/dist/cdn/waterfall/snice-waterfall.js +1 -1
  400. package/dist/cdn/waterfall/snice-waterfall.min.js +1 -1
  401. package/dist/cdn/weather/snice-weather.js +1 -1
  402. package/dist/cdn/weather/snice-weather.min.js +1 -1
  403. package/dist/cdn/work-order/snice-work-order.js +1 -1
  404. package/dist/cdn/work-order/snice-work-order.min.js +1 -1
  405. package/dist/components/chip/snice-chip.js +1 -1
  406. package/dist/components/chip/snice-chip.js.map +1 -1
  407. package/dist/components/date-picker/snice-date-picker.js +1 -1
  408. package/dist/components/date-picker/snice-date-picker.js.map +1 -1
  409. package/dist/components/date-range-picker/snice-date-range-picker.js +1 -1
  410. package/dist/components/date-range-picker/snice-date-range-picker.js.map +1 -1
  411. package/dist/components/date-time-picker/snice-date-time-picker.js +1 -1
  412. package/dist/components/date-time-picker/snice-date-time-picker.js.map +1 -1
  413. package/dist/components/draw/snice-draw.d.ts +2 -0
  414. package/dist/components/draw/snice-draw.js +25 -3
  415. package/dist/components/draw/snice-draw.js.map +1 -1
  416. package/dist/components/grid/snice-grid.d.ts +73 -0
  417. package/dist/components/grid/snice-grid.js +795 -0
  418. package/dist/components/grid/snice-grid.js.map +1 -0
  419. package/dist/components/grid/snice-grid.types.d.ts +41 -0
  420. package/dist/components/message-strip/snice-message-strip.js +1 -1
  421. package/dist/components/message-strip/snice-message-strip.js.map +1 -1
  422. package/dist/components/paint/snice-paint.d.ts +2 -0
  423. package/dist/components/paint/snice-paint.js +25 -2
  424. package/dist/components/paint/snice-paint.js.map +1 -1
  425. package/dist/components/tag/snice-tag.js +1 -1
  426. package/dist/components/tag/snice-tag.js.map +1 -1
  427. package/dist/components/tag-input/snice-tag-input.js +1 -1
  428. package/dist/components/tag-input/snice-tag-input.js.map +1 -1
  429. package/dist/components/theme/theme.css +15 -0
  430. package/dist/components/time-picker/snice-time-picker.js +1 -1
  431. package/dist/components/time-picker/snice-time-picker.js.map +1 -1
  432. package/dist/components/toast/snice-toast-container.js +4 -0
  433. package/dist/components/toast/snice-toast-container.js.map +1 -1
  434. package/dist/components/toast/snice-toast.js +2 -2
  435. package/dist/index.cjs +37 -12
  436. package/dist/index.cjs.map +1 -1
  437. package/dist/index.esm.js +37 -12
  438. package/dist/index.esm.js.map +1 -1
  439. package/dist/index.iife.js +37 -12
  440. package/dist/index.iife.js.map +1 -1
  441. package/dist/react/SniceProvider.d.ts +71 -0
  442. package/dist/react/SniceProvider.js +49 -0
  443. package/dist/react/SniceProvider.js.map +1 -0
  444. package/dist/react/SniceRouter.d.ts +44 -0
  445. package/dist/react/SniceRouter.js +190 -0
  446. package/dist/react/SniceRouter.js.map +1 -0
  447. package/dist/react/index.d.ts +3 -0
  448. package/dist/react/index.js +14 -0
  449. package/dist/react/index.js.map +1 -0
  450. package/dist/react/matchRoute.d.ts +16 -0
  451. package/dist/react/matchRoute.js +32 -0
  452. package/dist/react/matchRoute.js.map +1 -0
  453. package/dist/react/useRequestHandler.js +1 -1
  454. package/dist/react/useRequestHandler.js.map +1 -1
  455. package/dist/symbols.cjs +1 -1
  456. package/dist/symbols.esm.js +1 -1
  457. package/dist/transitions.cjs +1 -1
  458. package/dist/transitions.esm.js +1 -1
  459. package/dist/types/guard.d.ts +4 -11
  460. package/docs/ai/README.md +7 -7
  461. package/docs/ai/components/grid.md +116 -0
  462. package/docs/ai/patterns.md +24 -0
  463. package/docs/ai/react-integration.md +97 -0
  464. package/docs/components/grid.md +249 -0
  465. package/docs/plans/2026-03-10-grid-component-design.md +138 -0
  466. package/docs/plans/2026-03-10-grid-component-plan.md +716 -0
  467. package/docs/plans/2026-03-10-react-integration-plan.md +1178 -0
  468. package/docs/react-integration.md +508 -0
  469. package/docs/request-response.md +7 -21
  470. package/package.json +1 -1
  471. package/bin/templates/base/README.md +0 -33
  472. package/bin/templates/base/global.d.ts +0 -14
  473. package/bin/templates/base/index.html +0 -13
  474. package/bin/templates/base/package.json +0 -21
  475. package/bin/templates/base/src/components/counter-button.ts +0 -88
  476. package/bin/templates/base/src/components/counter-button.types.ts +0 -7
  477. package/bin/templates/base/src/components/feature-card.ts +0 -59
  478. package/bin/templates/base/src/components/feature-card.types.ts +0 -5
  479. package/bin/templates/base/src/controllers/counter-controller.ts +0 -24
  480. package/bin/templates/base/src/main.ts +0 -24
  481. package/bin/templates/base/src/pages/about-page.ts +0 -68
  482. package/bin/templates/base/src/pages/home-page.ts +0 -105
  483. package/bin/templates/base/src/pages/not-found-page.ts +0 -55
  484. package/bin/templates/base/src/router.ts +0 -9
  485. package/bin/templates/base/src/styles/global.css +0 -27
  486. package/bin/templates/base/src/types/api-response.ts +0 -5
  487. package/bin/templates/base/src/types/status.ts +0 -1
  488. package/bin/templates/base/src/types/theme.ts +0 -1
  489. package/bin/templates/base/src/types/user.ts +0 -5
  490. package/bin/templates/base/vite.config.ts +0 -38
  491. package/bin/templates/pwa/public/vite.svg +0 -1
  492. package/bin/templates/pwa/src/router.ts +0 -20
  493. package/bin/templates/pwa/src/styles/global.css +0 -64
  494. /package/bin/templates/{pwa → default}/README.md +0 -0
  495. /package/bin/templates/{pwa → default}/global.d.ts +0 -0
  496. /package/bin/templates/{pwa → default}/package.json +0 -0
  497. /package/bin/templates/{pwa → default}/public/icons/.gitkeep +0 -0
  498. /package/bin/templates/{base → default}/public/vite.svg +0 -0
  499. /package/bin/templates/{pwa → default}/src/fetcher.ts +0 -0
  500. /package/bin/templates/{pwa → default}/src/guards/auth.ts +0 -0
  501. /package/bin/templates/{pwa → default}/src/middleware/auth.ts +0 -0
  502. /package/bin/templates/{pwa → default}/src/middleware/retry.ts +0 -0
  503. /package/bin/templates/{pwa → default}/src/services/auth.ts +0 -0
  504. /package/bin/templates/{pwa → default}/src/services/jwt.ts +0 -0
  505. /package/bin/templates/{pwa → default}/src/services/storage.ts +0 -0
  506. /package/bin/templates/{pwa → default}/src/types/auth.ts +0 -0
  507. /package/bin/templates/{pwa → default}/src/types/notifications.ts +0 -0
  508. /package/bin/templates/{pwa → default}/tests/helpers/test-utils.ts +0 -0
  509. /package/bin/templates/{pwa → default}/tests/middleware/auth.test.ts +0 -0
  510. /package/bin/templates/{pwa → default}/tests/middleware/error.test.ts +0 -0
  511. /package/bin/templates/{pwa → default}/tests/middleware/retry.test.ts +0 -0
  512. /package/bin/templates/{pwa → default}/tests/services/auth.test.ts +0 -0
  513. /package/bin/templates/{pwa → default}/tests/services/jwt.test.ts +0 -0
  514. /package/bin/templates/{pwa → default}/tests/services/storage.test.ts +0 -0
  515. /package/bin/templates/{pwa → default}/vite.config.ts +0 -0
  516. /package/bin/templates/{pwa → default}/vitest.config.ts +0 -0
@@ -0,0 +1,111 @@
1
+ import { useState, useEffect } from 'react';
2
+ import { useSniceContext, Card, Button } from 'snice/react';
3
+ import type { NotificationsDaemon } from '../daemons/notifications';
4
+
5
+ export function DashboardPage() {
6
+ const ctx = useSniceContext();
7
+ const principal = ctx.application.principal;
8
+ const userName = principal?.user?.name || 'User';
9
+ const [notificationCount, setNotificationCount] = useState(0);
10
+
11
+ useEffect(() => {
12
+ const daemon = ctx.application.notifications as NotificationsDaemon | undefined;
13
+ if (!daemon) return;
14
+
15
+ const unsubscribe = daemon.subscribe(() => {
16
+ setNotificationCount(prev => prev + 1);
17
+ });
18
+
19
+ return unsubscribe;
20
+ }, [ctx.application.notifications]);
21
+
22
+ return (
23
+ <div className="page-container">
24
+ <div style={{ marginBottom: '2rem' }}>
25
+ <h1 style={{ color: 'var(--snice-color-primary)', margin: '0 0 0.5rem 0' }}>
26
+ Welcome, {userName}!
27
+ </h1>
28
+ <p style={{ color: 'var(--snice-color-text-secondary)', margin: 0 }}>
29
+ This is your dashboard
30
+ </p>
31
+ </div>
32
+
33
+ <div className="stats-grid" style={{
34
+ display: 'grid',
35
+ gridTemplateColumns: 'repeat(3, 1fr)',
36
+ gap: '1rem',
37
+ marginBottom: '2rem'
38
+ }}>
39
+ <Card style={{ padding: '1.25rem', textAlign: 'center' }}>
40
+ <span style={{ display: 'block', fontSize: '2rem', fontWeight: 700, color: 'var(--snice-color-primary)' }}>4</span>
41
+ <span style={{ display: 'block', fontSize: '0.8125rem', color: 'var(--snice-color-text-secondary)', marginTop: '0.25rem' }}>Active Pages</span>
42
+ </Card>
43
+ <Card style={{ padding: '1.25rem', textAlign: 'center' }}>
44
+ <span style={{ display: 'block', fontSize: '2rem', fontWeight: 700, color: 'var(--snice-color-primary)' }}>{notificationCount}</span>
45
+ <span style={{ display: 'block', fontSize: '0.8125rem', color: 'var(--snice-color-text-secondary)', marginTop: '0.25rem' }}>Notifications</span>
46
+ </Card>
47
+ <Card style={{ padding: '1.25rem', textAlign: 'center' }}>
48
+ <span style={{ display: 'block', fontSize: '2rem', fontWeight: 700, color: 'var(--snice-color-primary)' }}>3</span>
49
+ <span style={{ display: 'block', fontSize: '0.8125rem', color: 'var(--snice-color-text-secondary)', marginTop: '0.25rem' }}>Middleware</span>
50
+ </Card>
51
+ </div>
52
+
53
+ <div style={{
54
+ display: 'grid',
55
+ gridTemplateColumns: 'repeat(auto-fit, minmax(280px, 1fr))',
56
+ gap: '1.5rem'
57
+ }}>
58
+ <Card style={{ padding: '1.5rem' }}>
59
+ <h3 style={{ margin: '0 0 1rem 0', color: 'var(--snice-color-primary)' }}>Features</h3>
60
+ <ul style={{ margin: 0, paddingLeft: '1.5rem' }}>
61
+ <li style={{ margin: '0.5rem 0' }}>JWT Authentication</li>
62
+ <li style={{ margin: '0.5rem 0' }}>Protected Routes with Guards</li>
63
+ <li style={{ margin: '0.5rem 0' }}>Middleware Pattern</li>
64
+ <li style={{ margin: '0.5rem 0' }}>Live Notifications</li>
65
+ <li style={{ margin: '0.5rem 0' }}>Theme Switching</li>
66
+ <li style={{ margin: '0.5rem 0' }}>Debounced Search</li>
67
+ <li style={{ margin: '0.5rem 0' }}>React + Snice Integration</li>
68
+ </ul>
69
+ </Card>
70
+
71
+ <Card style={{ padding: '1.5rem' }}>
72
+ <h3 style={{ margin: '0 0 1rem 0', color: 'var(--snice-color-primary)' }}>Architecture</h3>
73
+ <ul style={{ margin: 0, paddingLeft: '1.5rem' }}>
74
+ <li style={{ margin: '0.5rem 0' }}><strong>Pages:</strong> React components</li>
75
+ <li style={{ margin: '0.5rem 0' }}><strong>Components:</strong> Snice adapters + React</li>
76
+ <li style={{ margin: '0.5rem 0' }}><strong>Services:</strong> Business logic</li>
77
+ <li style={{ margin: '0.5rem 0' }}><strong>Middleware:</strong> Fetch interceptors</li>
78
+ <li style={{ margin: '0.5rem 0' }}><strong>Daemons:</strong> Lifecycle classes</li>
79
+ <li style={{ margin: '0.5rem 0' }}><strong>Guards:</strong> Route protection</li>
80
+ </ul>
81
+ </Card>
82
+
83
+ <Card style={{ padding: '1.5rem' }}>
84
+ <h3 style={{ margin: '0 0 1rem 0', color: 'var(--snice-color-primary)' }}>React Hooks</h3>
85
+ <ul style={{ margin: 0, paddingLeft: '1.5rem' }}>
86
+ <li style={{ margin: '0.5rem 0' }}><code>useSniceContext()</code> - App state</li>
87
+ <li style={{ margin: '0.5rem 0' }}><code>useNavigate()</code> - Navigation</li>
88
+ <li style={{ margin: '0.5rem 0' }}><code>useParams()</code> - Route params</li>
89
+ <li style={{ margin: '0.5rem 0' }}><code>useRoute()</code> - Current route</li>
90
+ </ul>
91
+ </Card>
92
+
93
+ <Card style={{ padding: '1.5rem' }}>
94
+ <h3 style={{ margin: '0 0 1rem 0', color: 'var(--snice-color-primary)' }}>Explore</h3>
95
+ <p style={{ color: 'var(--snice-color-text-secondary)', margin: '0 0 0.5rem 0' }}>Check out the other pages:</p>
96
+ <div style={{ display: 'flex', flexDirection: 'column', gap: '0.75rem', marginTop: '1rem' }}>
97
+ <a href="#/data" style={{ textDecoration: 'none' }}>
98
+ <Button variant="secondary" style={{ width: '100%' }}>Browse Data</Button>
99
+ </a>
100
+ <a href="#/settings" style={{ textDecoration: 'none' }}>
101
+ <Button variant="secondary" style={{ width: '100%' }}>Settings</Button>
102
+ </a>
103
+ <a href="#/notifications" style={{ textDecoration: 'none' }}>
104
+ <Button variant="secondary" style={{ width: '100%' }}>Notifications</Button>
105
+ </a>
106
+ </div>
107
+ </Card>
108
+ </div>
109
+ </div>
110
+ );
111
+ }
@@ -0,0 +1,119 @@
1
+ import { useState, useEffect, useCallback } from 'react';
2
+ import { Spinner, EmptyState } from 'snice/react';
3
+ import { SearchBar } from '../components/SearchBar';
4
+
5
+ interface DataItem {
6
+ id: string;
7
+ title: string;
8
+ description: string;
9
+ status: 'active' | 'pending' | 'archived';
10
+ createdAt: string;
11
+ }
12
+
13
+ const MOCK_ITEMS: DataItem[] = [
14
+ { id: '1', title: 'API Integration', description: 'Connect external payment gateway', status: 'active', createdAt: '2025-01-15' },
15
+ { id: '2', title: 'User Analytics', description: 'Implement tracking dashboard', status: 'pending', createdAt: '2025-01-20' },
16
+ { id: '3', title: 'Email Templates', description: 'Design transactional email set', status: 'active', createdAt: '2025-02-01' },
17
+ { id: '4', title: 'Legacy Migration', description: 'Migrate v1 database schema', status: 'archived', createdAt: '2024-12-10' },
18
+ { id: '5', title: 'Mobile App', description: 'React Native companion app', status: 'pending', createdAt: '2025-02-15' },
19
+ { id: '6', title: 'CI/CD Pipeline', description: 'GitHub Actions deployment workflow', status: 'active', createdAt: '2025-01-05' },
20
+ { id: '7', title: 'Documentation', description: 'API reference and developer guides', status: 'active', createdAt: '2025-02-10' },
21
+ { id: '8', title: 'Performance Audit', description: 'Lighthouse and Core Web Vitals', status: 'archived', createdAt: '2024-11-20' },
22
+ ];
23
+
24
+ function getStatusColor(status: string): string {
25
+ const colors: Record<string, string> = {
26
+ active: 'var(--snice-color-success)',
27
+ pending: 'var(--snice-color-warning)',
28
+ archived: 'var(--snice-color-text-secondary)'
29
+ };
30
+ return colors[status] || 'var(--snice-color-text-secondary)';
31
+ }
32
+
33
+ export function DataPage() {
34
+ const [loading, setLoading] = useState(true);
35
+ const [allItems, setAllItems] = useState<DataItem[]>([]);
36
+ const [searchQuery, setSearchQuery] = useState('');
37
+ const [statusFilter, setStatusFilter] = useState<'all' | 'active' | 'pending' | 'archived'>('all');
38
+
39
+ useEffect(() => {
40
+ const timer = setTimeout(() => {
41
+ setAllItems([...MOCK_ITEMS]);
42
+ setLoading(false);
43
+ }, 500);
44
+ return () => clearTimeout(timer);
45
+ }, []);
46
+
47
+ const filteredItems = allItems.filter(item => {
48
+ if (statusFilter !== 'all' && item.status !== statusFilter) return false;
49
+ if (searchQuery) {
50
+ const q = searchQuery.toLowerCase();
51
+ return item.title.toLowerCase().includes(q) || item.description.toLowerCase().includes(q);
52
+ }
53
+ return true;
54
+ });
55
+
56
+ const handleSearch = useCallback((query: string) => {
57
+ setSearchQuery(query);
58
+ }, []);
59
+
60
+ return (
61
+ <div className="page-container-medium">
62
+ <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', marginBottom: '1.5rem' }}>
63
+ <h1 style={{ margin: 0, color: 'var(--snice-color-primary)' }}>Data</h1>
64
+ <span style={{ fontSize: '0.875rem', color: 'var(--snice-color-text-secondary)' }}>
65
+ {filteredItems.length} items
66
+ </span>
67
+ </div>
68
+
69
+ <div style={{ display: 'flex', flexDirection: 'column', gap: '1rem', marginBottom: '1.5rem' }}>
70
+ <SearchBar placeholder="Search items..." onSearch={handleSearch} />
71
+
72
+ <div className="filters" style={{ display: 'flex', gap: '0.5rem' }}>
73
+ {(['all', 'active', 'pending', 'archived'] as const).map(status => (
74
+ <button
75
+ key={status}
76
+ className={`filter-btn ${statusFilter === status ? 'active' : ''}`}
77
+ onClick={() => setStatusFilter(status)}
78
+ >
79
+ {status.charAt(0).toUpperCase() + status.slice(1)}
80
+ </button>
81
+ ))}
82
+ </div>
83
+ </div>
84
+
85
+ {loading ? (
86
+ <div style={{ display: 'flex', justifyContent: 'center', padding: '3rem' }}>
87
+ <Spinner />
88
+ </div>
89
+ ) : filteredItems.length === 0 ? (
90
+ <EmptyState
91
+ icon="&#128269;"
92
+ title="No results"
93
+ description="Try adjusting your search or filters"
94
+ />
95
+ ) : (
96
+ <div className="data-table">
97
+ <div className="table-header">
98
+ <span className="col-title">Title</span>
99
+ <span className="col-status">Status</span>
100
+ <span className="col-date">Created</span>
101
+ </div>
102
+ {filteredItems.map(item => (
103
+ <div className="table-row" key={item.id}>
104
+ <div className="col-title">
105
+ <strong>{item.title}</strong>
106
+ <span className="description">{item.description}</span>
107
+ </div>
108
+ <div className="col-status">
109
+ <span className="status-dot" style={{ background: getStatusColor(item.status) }} />
110
+ {item.status}
111
+ </div>
112
+ <div className="col-date">{item.createdAt}</div>
113
+ </div>
114
+ ))}
115
+ </div>
116
+ )}
117
+ </div>
118
+ );
119
+ }
@@ -0,0 +1,46 @@
1
+ import { useRef, useState } from 'react';
2
+ import { useSniceContext, useNavigate, Login, useRequestHandler } from 'snice/react';
3
+ import 'snice/components/login/snice-login';
4
+
5
+ export function LoginPage() {
6
+ const ctx = useSniceContext();
7
+ const navigate = useNavigate();
8
+ const containerRef = useRef<HTMLDivElement>(null);
9
+ const [error, setError] = useState('');
10
+
11
+ useRequestHandler(containerRef, {
12
+ 'login-user': async (credentials: { username: string; password: string }) => {
13
+ setError('');
14
+ try {
15
+ await ctx.application.login(credentials.username, credentials.password);
16
+ navigate('/dashboard');
17
+ return { success: true };
18
+ } catch (err) {
19
+ const message = err instanceof Error ? err.message : 'Login failed';
20
+ setError(message);
21
+ return { success: false, error: message };
22
+ }
23
+ }
24
+ });
25
+
26
+ return (
27
+ <div className="login-page" ref={containerRef}>
28
+ <Login
29
+ variant="card"
30
+ size="medium"
31
+ title={'{{projectName}}'}
32
+ actionText="Sign In"
33
+ showForgotPassword={false}
34
+ alertMessage={error}
35
+ alertVariant={error ? 'error' : undefined}
36
+ >
37
+ <p slot="subtitle">Sign in to your account</p>
38
+ <div slot="footer">
39
+ <p className="hint">Demo credentials:</p>
40
+ <p className="hint"><strong>Email:</strong> demo@example.com</p>
41
+ <p className="hint"><strong>Password:</strong> demo</p>
42
+ </div>
43
+ </Login>
44
+ </div>
45
+ );
46
+ }
@@ -0,0 +1,119 @@
1
+ import { useState, useEffect, useCallback } from 'react';
2
+ import { useSniceContext, Alert, Button, EmptyState } from 'snice/react';
3
+ import type { NotificationsDaemon } from '../daemons/notifications';
4
+ import type { Notification, NotificationType } from '../types/notifications';
5
+
6
+ function getVariant(type: string): string {
7
+ const variants: Record<string, string> = {
8
+ info: 'info',
9
+ success: 'success',
10
+ warning: 'warning',
11
+ error: 'danger'
12
+ };
13
+ return variants[type] || 'info';
14
+ }
15
+
16
+ export function NotificationsPage() {
17
+ const ctx = useSniceContext();
18
+ const [notifications, setNotifications] = useState<Notification[]>([]);
19
+ const [filter, setFilter] = useState<NotificationType | 'all'>('all');
20
+
21
+ useEffect(() => {
22
+ const daemon = ctx.application.notifications as NotificationsDaemon | undefined;
23
+ if (!daemon) return;
24
+
25
+ const unsubscribe = daemon.subscribe((notification) => {
26
+ setNotifications(prev => [notification, ...prev]);
27
+ });
28
+
29
+ return unsubscribe;
30
+ }, [ctx.application.notifications]);
31
+
32
+ const clearAll = useCallback(() => {
33
+ setNotifications([]);
34
+ }, []);
35
+
36
+ const removeNotification = useCallback((id: string) => {
37
+ setNotifications(prev => prev.filter(n => n.id !== id));
38
+ }, []);
39
+
40
+ // Keyboard shortcut: Ctrl+Backspace to clear all
41
+ useEffect(() => {
42
+ const handleKeyDown = (e: KeyboardEvent) => {
43
+ if (e.ctrlKey && e.key === 'Backspace') {
44
+ clearAll();
45
+ }
46
+ };
47
+ document.addEventListener('keydown', handleKeyDown);
48
+ return () => document.removeEventListener('keydown', handleKeyDown);
49
+ }, [clearAll]);
50
+
51
+ const filteredNotifications = filter === 'all'
52
+ ? notifications
53
+ : notifications.filter(n => n.type === filter);
54
+
55
+ return (
56
+ <div className="page-container-narrow">
57
+ <div style={{
58
+ display: 'flex',
59
+ justifyContent: 'space-between',
60
+ alignItems: 'flex-start',
61
+ marginBottom: '1.5rem'
62
+ }}>
63
+ <div>
64
+ <h1 style={{ margin: 0, color: 'var(--snice-color-primary)' }}>Notifications</h1>
65
+ <span style={{ fontSize: '0.8125rem', color: 'var(--snice-color-text-secondary)' }}>
66
+ {notifications.length} total
67
+ </span>
68
+ </div>
69
+ {notifications.length > 0 && (
70
+ <Button variant="secondary" size="small" onClick={clearAll}>
71
+ Clear All (Ctrl+Backspace)
72
+ </Button>
73
+ )}
74
+ </div>
75
+
76
+ {notifications.length > 0 && (
77
+ <div className="filters" style={{ display: 'flex', gap: '0.5rem', marginBottom: '1.5rem' }}>
78
+ {(['all', 'info', 'success', 'warning', 'error'] as const).map(f => (
79
+ <button
80
+ key={f}
81
+ className={`filter-btn ${filter === f ? 'active' : ''}`}
82
+ onClick={() => setFilter(f)}
83
+ >
84
+ {f.charAt(0).toUpperCase() + f.slice(1)}
85
+ </button>
86
+ ))}
87
+ </div>
88
+ )}
89
+
90
+ {filteredNotifications.length === 0 ? (
91
+ <EmptyState
92
+ icon="&#128276;"
93
+ title="No notifications"
94
+ description="You'll see live notifications here as they arrive"
95
+ />
96
+ ) : (
97
+ <div style={{ display: 'flex', flexDirection: 'column', gap: '1rem' }}>
98
+ {filteredNotifications.map(notification => (
99
+ <Alert
100
+ key={notification.id}
101
+ variant={getVariant(notification.type)}
102
+ dismissible
103
+ className="notification-slide-in"
104
+ onAlertDismiss={() => removeNotification(notification.id)}
105
+ >
106
+ <strong style={{ display: 'block', marginBottom: '0.5rem' }}>
107
+ {notification.title}
108
+ </strong>
109
+ <p style={{ margin: '0 0 0.5rem 0' }}>{notification.message}</p>
110
+ <small style={{ opacity: 0.7 }}>
111
+ {new Date(notification.timestamp).toLocaleTimeString()}
112
+ </small>
113
+ </Alert>
114
+ ))}
115
+ </div>
116
+ )}
117
+ </div>
118
+ );
119
+ }
@@ -0,0 +1,92 @@
1
+ import { useSniceContext, Card, Avatar, Button, Divider, Spinner } from 'snice/react';
2
+
3
+ export function ProfilePage() {
4
+ const ctx = useSniceContext();
5
+ const principal = ctx.application.principal;
6
+ const user = principal?.user;
7
+
8
+ const handleLogout = async () => {
9
+ await ctx.application.logout();
10
+ window.location.hash = '#/login';
11
+ };
12
+
13
+ if (!user) {
14
+ return (
15
+ <div className="page-container-narrow">
16
+ <div style={{ display: 'flex', justifyContent: 'center', padding: '3rem' }}>
17
+ <Spinner />
18
+ </div>
19
+ </div>
20
+ );
21
+ }
22
+
23
+ return (
24
+ <div className="page-container-narrow">
25
+ <Card style={{ padding: '2rem' }}>
26
+ <div style={{ textAlign: 'center', paddingBottom: '1.5rem' }}>
27
+ <Avatar
28
+ src={user.avatar || ''}
29
+ name={user.name}
30
+ size="large"
31
+ style={{ marginBottom: '1rem' }}
32
+ />
33
+ <h1 style={{ margin: '0 0 0.5rem 0', color: 'var(--snice-color-primary)' }}>{user.name}</h1>
34
+ <p style={{ margin: '0 0 1rem 0', color: 'var(--snice-color-text-secondary)' }}>{user.email}</p>
35
+ <a href="#/settings" style={{ textDecoration: 'none' }}>
36
+ <Button variant="secondary" size="small">Edit Profile</Button>
37
+ </a>
38
+ </div>
39
+
40
+ <Divider style={{ margin: '0.5rem 0' }} />
41
+
42
+ <div style={{ paddingTop: '1.5rem' }}>
43
+ <h3 style={{ margin: '0 0 1rem 0', color: 'var(--snice-color-primary)' }}>Account Information</h3>
44
+ <div style={{ display: 'flex', flexDirection: 'column', gap: '0.75rem' }}>
45
+ <div style={{
46
+ display: 'flex',
47
+ justifyContent: 'space-between',
48
+ padding: '0.75rem',
49
+ background: 'var(--snice-color-background-secondary)',
50
+ borderRadius: 'var(--snice-border-radius-md)'
51
+ }}>
52
+ <span style={{ fontWeight: 600, color: 'var(--snice-color-text)' }}>User ID</span>
53
+ <span style={{ color: 'var(--snice-color-text-secondary)' }}>{user.id}</span>
54
+ </div>
55
+ <div style={{
56
+ display: 'flex',
57
+ justifyContent: 'space-between',
58
+ padding: '0.75rem',
59
+ background: 'var(--snice-color-background-secondary)',
60
+ borderRadius: 'var(--snice-border-radius-md)'
61
+ }}>
62
+ <span style={{ fontWeight: 600, color: 'var(--snice-color-text)' }}>Email</span>
63
+ <span style={{ color: 'var(--snice-color-text-secondary)' }}>{user.email}</span>
64
+ </div>
65
+ <div style={{
66
+ display: 'flex',
67
+ justifyContent: 'space-between',
68
+ padding: '0.75rem',
69
+ background: 'var(--snice-color-background-secondary)',
70
+ borderRadius: 'var(--snice-border-radius-md)'
71
+ }}>
72
+ <span style={{ fontWeight: 600, color: 'var(--snice-color-text)' }}>Name</span>
73
+ <span style={{ color: 'var(--snice-color-text-secondary)' }}>{user.name}</span>
74
+ </div>
75
+ </div>
76
+ </div>
77
+
78
+ <Divider style={{ margin: '0.5rem 0' }} />
79
+
80
+ <div style={{ paddingTop: '1.5rem' }}>
81
+ <h3 style={{ margin: '0 0 1rem 0', color: 'var(--snice-color-primary)' }}>Session</h3>
82
+ <p style={{ margin: '0 0 1rem 0', color: 'var(--snice-color-text-secondary)' }}>
83
+ You are currently logged in with JWT authentication.
84
+ </p>
85
+ <Button variant="danger" onClick={handleLogout}>
86
+ Sign Out
87
+ </Button>
88
+ </div>
89
+ </Card>
90
+ </div>
91
+ );
92
+ }
@@ -0,0 +1,165 @@
1
+ import { useState, useEffect, useCallback } from 'react';
2
+ import { useSniceContext, Card, Input, Button, Switch, Alert } from 'snice/react';
3
+
4
+ export function SettingsPage() {
5
+ const ctx = useSniceContext();
6
+ const principal = ctx.application.principal;
7
+ const user = principal?.user;
8
+
9
+ const [displayName, setDisplayName] = useState(user?.name || '');
10
+ const [email, setEmail] = useState(user?.email || '');
11
+ const [theme, setThemeState] = useState<'light' | 'dark' | 'system'>(() => {
12
+ return (localStorage.getItem('app-theme') as 'light' | 'dark' | 'system') || 'system';
13
+ });
14
+ const [notificationsEnabled, setNotificationsEnabled] = useState(() => {
15
+ return localStorage.getItem('notifications-enabled') !== 'false';
16
+ });
17
+ const [saved, setSaved] = useState(false);
18
+
19
+ useEffect(() => {
20
+ if (user) {
21
+ setDisplayName(user.name || '');
22
+ setEmail(user.email || '');
23
+ }
24
+ }, [user]);
25
+
26
+ const setTheme = useCallback((newTheme: 'light' | 'dark' | 'system') => {
27
+ setThemeState(newTheme);
28
+ localStorage.setItem('app-theme', newTheme);
29
+ if (newTheme === 'system') {
30
+ document.documentElement.removeAttribute('data-theme');
31
+ } else {
32
+ document.documentElement.setAttribute('data-theme', newTheme);
33
+ }
34
+ }, []);
35
+
36
+ const toggleNotifications = useCallback(() => {
37
+ setNotificationsEnabled(prev => {
38
+ const next = !prev;
39
+ localStorage.setItem('notifications-enabled', String(next));
40
+ return next;
41
+ });
42
+ }, []);
43
+
44
+ const saveSettings = useCallback(() => {
45
+ ctx.application.refreshAuth();
46
+ setSaved(true);
47
+ setTimeout(() => setSaved(false), 2000);
48
+ }, [ctx.application]);
49
+
50
+ // Keyboard shortcut: Ctrl+S to save
51
+ useEffect(() => {
52
+ const handleKeyDown = (e: KeyboardEvent) => {
53
+ if (e.ctrlKey && e.key === 's') {
54
+ e.preventDefault();
55
+ saveSettings();
56
+ }
57
+ };
58
+ document.addEventListener('keydown', handleKeyDown);
59
+ return () => document.removeEventListener('keydown', handleKeyDown);
60
+ }, [saveSettings]);
61
+
62
+ return (
63
+ <div className="page-container-narrow">
64
+ <h1 style={{ margin: '0 0 0.25rem 0', color: 'var(--snice-color-primary)' }}>Settings</h1>
65
+ <p style={{ margin: '0 0 2rem 0', fontSize: '0.8125rem', color: 'var(--snice-color-text-secondary)' }}>
66
+ Press Ctrl+S to save
67
+ </p>
68
+
69
+ {saved && (
70
+ <Alert variant="success" dismissible style={{ marginBottom: '1.5rem' }}>
71
+ Settings saved successfully!
72
+ </Alert>
73
+ )}
74
+
75
+ <Card style={{ padding: '1.5rem', marginBottom: '1.5rem' }}>
76
+ <h3 style={{ margin: '0 0 1.25rem 0', color: 'var(--snice-color-primary)' }}>Profile</h3>
77
+ <div style={{ marginBottom: '1rem' }}>
78
+ <label style={{
79
+ display: 'block',
80
+ marginBottom: '0.375rem',
81
+ fontSize: '0.875rem',
82
+ fontWeight: 500,
83
+ color: 'var(--snice-color-text)'
84
+ }}>Display Name</label>
85
+ <Input
86
+ value={displayName}
87
+ onInput={(e: any) => setDisplayName(e.target.value)}
88
+ placeholder="Your name"
89
+ style={{ width: '100%' }}
90
+ />
91
+ </div>
92
+ <div>
93
+ <label style={{
94
+ display: 'block',
95
+ marginBottom: '0.375rem',
96
+ fontSize: '0.875rem',
97
+ fontWeight: 500,
98
+ color: 'var(--snice-color-text)'
99
+ }}>Email</label>
100
+ <Input
101
+ value={email}
102
+ onInput={(e: any) => setEmail(e.target.value)}
103
+ placeholder="your@email.com"
104
+ style={{ width: '100%' }}
105
+ />
106
+ </div>
107
+ </Card>
108
+
109
+ <Card style={{ padding: '1.5rem', marginBottom: '1.5rem' }}>
110
+ <h3 style={{ margin: '0 0 1.25rem 0', color: 'var(--snice-color-primary)' }}>Appearance</h3>
111
+ <div className="theme-options" style={{ display: 'flex', gap: '0.75rem' }}>
112
+ <button
113
+ className={`theme-btn ${theme === 'light' ? 'active' : ''}`}
114
+ onClick={() => setTheme('light')}
115
+ >
116
+ <span className="theme-icon">&#9728;&#65039;</span>
117
+ Light
118
+ </button>
119
+ <button
120
+ className={`theme-btn ${theme === 'dark' ? 'active' : ''}`}
121
+ onClick={() => setTheme('dark')}
122
+ >
123
+ <span className="theme-icon">&#127769;</span>
124
+ Dark
125
+ </button>
126
+ <button
127
+ className={`theme-btn ${theme === 'system' ? 'active' : ''}`}
128
+ onClick={() => setTheme('system')}
129
+ >
130
+ <span className="theme-icon">&#128187;</span>
131
+ System
132
+ </button>
133
+ </div>
134
+ </Card>
135
+
136
+ <Card style={{ padding: '1.5rem', marginBottom: '1.5rem' }}>
137
+ <h3 style={{ margin: '0 0 1.25rem 0', color: 'var(--snice-color-primary)' }}>Notifications</h3>
138
+ <div style={{
139
+ display: 'flex',
140
+ alignItems: 'center',
141
+ justifyContent: 'space-between'
142
+ }}>
143
+ <div>
144
+ <p style={{ margin: 0, fontWeight: 500, color: 'var(--snice-color-text)' }}>
145
+ Push Notifications
146
+ </p>
147
+ <p style={{ margin: '0.25rem 0 0 0', fontSize: '0.8125rem', color: 'var(--snice-color-text-secondary)' }}>
148
+ Receive real-time notification alerts
149
+ </p>
150
+ </div>
151
+ <Switch
152
+ checked={notificationsEnabled}
153
+ onChange={toggleNotifications}
154
+ />
155
+ </div>
156
+ </Card>
157
+
158
+ <div style={{ display: 'flex', justifyContent: 'flex-end' }}>
159
+ <Button variant="primary" onClick={saveSettings}>
160
+ Save Settings
161
+ </Button>
162
+ </div>
163
+ </div>
164
+ );
165
+ }