snice 4.10.0 → 4.12.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 (269) hide show
  1. package/adapters/react/carousel.d.ts +1 -0
  2. package/adapters/react/carousel.d.ts.map +1 -1
  3. package/adapters/react/carousel.js +1 -1
  4. package/adapters/react/carousel.js.map +1 -1
  5. package/adapters/react/carousel.tsx +2 -1
  6. package/bin/templates/CLAUDE.md +169 -113
  7. package/bin/templates/pwa/README.md +72 -94
  8. package/bin/templates/pwa/src/components/app-header.ts +218 -0
  9. package/bin/templates/pwa/src/components/notification-badge.ts +68 -0
  10. package/bin/templates/pwa/src/components/search-bar.ts +99 -0
  11. package/bin/templates/pwa/src/controllers/notification-controller.ts +42 -0
  12. package/bin/templates/pwa/src/guards/auth.ts +1 -1
  13. package/bin/templates/pwa/src/main.ts +19 -0
  14. package/bin/templates/pwa/src/pages/dashboard.ts +124 -23
  15. package/bin/templates/pwa/src/pages/data.ts +329 -0
  16. package/bin/templates/pwa/src/pages/notifications.ts +112 -30
  17. package/bin/templates/pwa/src/pages/profile.ts +86 -52
  18. package/bin/templates/pwa/src/pages/settings.ts +291 -0
  19. package/bin/templates/pwa/src/styles/global.css +12 -3
  20. package/dist/cdn/accordion/snice-accordion.js +1 -1
  21. package/dist/cdn/accordion/snice-accordion.min.js +1 -1
  22. package/dist/cdn/alert/snice-alert.js +1 -1
  23. package/dist/cdn/alert/snice-alert.min.js +1 -1
  24. package/dist/cdn/app-tiles/snice-app-tiles.js +1 -1
  25. package/dist/cdn/app-tiles/snice-app-tiles.min.js +1 -1
  26. package/dist/cdn/audio-recorder/snice-audio-recorder.js +1 -1
  27. package/dist/cdn/audio-recorder/snice-audio-recorder.min.js +1 -1
  28. package/dist/cdn/avatar/snice-avatar.js +1 -1
  29. package/dist/cdn/avatar/snice-avatar.min.js +1 -1
  30. package/dist/cdn/badge/snice-badge.js +1 -1
  31. package/dist/cdn/badge/snice-badge.min.js +1 -1
  32. package/dist/cdn/banner/snice-banner.js +1 -1
  33. package/dist/cdn/banner/snice-banner.min.js +1 -1
  34. package/dist/cdn/book/snice-book.js +1 -1
  35. package/dist/cdn/book/snice-book.min.js +1 -1
  36. package/dist/cdn/breadcrumbs/snice-breadcrumbs.js +1 -1
  37. package/dist/cdn/breadcrumbs/snice-breadcrumbs.min.js +1 -1
  38. package/dist/cdn/button/snice-button.js +1 -1
  39. package/dist/cdn/button/snice-button.min.js +1 -1
  40. package/dist/cdn/calendar/snice-calendar.js +1 -1
  41. package/dist/cdn/calendar/snice-calendar.min.js +1 -1
  42. package/dist/cdn/camera/README.md +1 -1
  43. package/dist/cdn/camera/snice-camera.js +1 -1
  44. package/dist/cdn/camera/snice-camera.min.js +1 -1
  45. package/dist/cdn/camera-annotate/snice-camera-annotate.js +1 -1
  46. package/dist/cdn/camera-annotate/snice-camera-annotate.min.js +1 -1
  47. package/dist/cdn/candlestick/snice-candlestick.js +1 -1
  48. package/dist/cdn/candlestick/snice-candlestick.min.js +1 -1
  49. package/dist/cdn/card/snice-card.js +1 -1
  50. package/dist/cdn/card/snice-card.min.js +1 -1
  51. package/dist/cdn/carousel/README.md +2 -2
  52. package/dist/cdn/carousel/snice-carousel.js +9 -3
  53. package/dist/cdn/carousel/snice-carousel.js.map +1 -1
  54. package/dist/cdn/carousel/snice-carousel.min.js +3 -3
  55. package/dist/cdn/carousel/snice-carousel.min.js.map +1 -1
  56. package/dist/cdn/chart/snice-chart.js +1 -1
  57. package/dist/cdn/chart/snice-chart.min.js +1 -1
  58. package/dist/cdn/chat/snice-chat.js +1 -1
  59. package/dist/cdn/chat/snice-chat.min.js +1 -1
  60. package/dist/cdn/checkbox/snice-checkbox.js +1 -1
  61. package/dist/cdn/checkbox/snice-checkbox.min.js +1 -1
  62. package/dist/cdn/chip/snice-chip.js +1 -1
  63. package/dist/cdn/chip/snice-chip.min.js +1 -1
  64. package/dist/cdn/code-block/snice-code-block.js +1 -1
  65. package/dist/cdn/code-block/snice-code-block.min.js +1 -1
  66. package/dist/cdn/color-display/snice-color-display.js +1 -1
  67. package/dist/cdn/color-display/snice-color-display.min.js +1 -1
  68. package/dist/cdn/color-picker/snice-color-picker.js +1 -1
  69. package/dist/cdn/color-picker/snice-color-picker.min.js +1 -1
  70. package/dist/cdn/command-palette/snice-command-palette.js +1 -1
  71. package/dist/cdn/command-palette/snice-command-palette.min.js +1 -1
  72. package/dist/cdn/comments/snice-comments.js +1 -1
  73. package/dist/cdn/comments/snice-comments.min.js +1 -1
  74. package/dist/cdn/countdown/snice-countdown.js +1 -1
  75. package/dist/cdn/countdown/snice-countdown.min.js +1 -1
  76. package/dist/cdn/cropper/snice-cropper.js +1 -1
  77. package/dist/cdn/cropper/snice-cropper.min.js +1 -1
  78. package/dist/cdn/date-picker/snice-date-picker.js +1 -1
  79. package/dist/cdn/date-picker/snice-date-picker.min.js +1 -1
  80. package/dist/cdn/diff/snice-diff.js +1 -1
  81. package/dist/cdn/diff/snice-diff.min.js +1 -1
  82. package/dist/cdn/divider/snice-divider.js +1 -1
  83. package/dist/cdn/divider/snice-divider.min.js +1 -1
  84. package/dist/cdn/doc/snice-doc.js +1 -1
  85. package/dist/cdn/doc/snice-doc.min.js +1 -1
  86. package/dist/cdn/draw/snice-draw.js +1 -1
  87. package/dist/cdn/draw/snice-draw.min.js +1 -1
  88. package/dist/cdn/drawer/snice-drawer.js +1 -1
  89. package/dist/cdn/drawer/snice-drawer.min.js +1 -1
  90. package/dist/cdn/empty-state/snice-empty-state.js +1 -1
  91. package/dist/cdn/empty-state/snice-empty-state.min.js +1 -1
  92. package/dist/cdn/file-gallery/snice-file-gallery.js +1 -1
  93. package/dist/cdn/file-gallery/snice-file-gallery.min.js +1 -1
  94. package/dist/cdn/file-upload/snice-file-upload.js +1 -1
  95. package/dist/cdn/file-upload/snice-file-upload.min.js +1 -1
  96. package/dist/cdn/flip-card/snice-flip-card.js +1 -1
  97. package/dist/cdn/flip-card/snice-flip-card.min.js +1 -1
  98. package/dist/cdn/flow/snice-flow.js +1 -1
  99. package/dist/cdn/flow/snice-flow.min.js +1 -1
  100. package/dist/cdn/funnel/snice-funnel.js +1 -1
  101. package/dist/cdn/funnel/snice-funnel.min.js +1 -1
  102. package/dist/cdn/gantt/README.md +1 -1
  103. package/dist/cdn/gantt/snice-gantt.js +1 -1
  104. package/dist/cdn/gantt/snice-gantt.min.js +1 -1
  105. package/dist/cdn/gauge/snice-gauge.js +1 -1
  106. package/dist/cdn/gauge/snice-gauge.min.js +1 -1
  107. package/dist/cdn/heatmap/snice-heatmap.js +1 -1
  108. package/dist/cdn/heatmap/snice-heatmap.min.js +1 -1
  109. package/dist/cdn/image/snice-image.js +1 -1
  110. package/dist/cdn/image/snice-image.min.js +1 -1
  111. package/dist/cdn/input/snice-input.js +1 -1
  112. package/dist/cdn/input/snice-input.min.js +1 -1
  113. package/dist/cdn/kanban/snice-kanban.js +1 -1
  114. package/dist/cdn/kanban/snice-kanban.min.js +1 -1
  115. package/dist/cdn/kpi/snice-kpi.js +1 -1
  116. package/dist/cdn/kpi/snice-kpi.min.js +1 -1
  117. package/dist/cdn/layout/snice-layout.js +1 -1
  118. package/dist/cdn/layout/snice-layout.min.js +1 -1
  119. package/dist/cdn/link/snice-link.js +1 -1
  120. package/dist/cdn/link/snice-link.min.js +1 -1
  121. package/dist/cdn/link-preview/snice-link-preview.js +1 -1
  122. package/dist/cdn/link-preview/snice-link-preview.min.js +1 -1
  123. package/dist/cdn/list/snice-list.js +1 -1
  124. package/dist/cdn/list/snice-list.min.js +1 -1
  125. package/dist/cdn/location/snice-location.js +1 -1
  126. package/dist/cdn/location/snice-location.min.js +1 -1
  127. package/dist/cdn/login/snice-login.js +1 -1
  128. package/dist/cdn/login/snice-login.min.js +1 -1
  129. package/dist/cdn/map/snice-map.js +1 -1
  130. package/dist/cdn/map/snice-map.min.js +1 -1
  131. package/dist/cdn/markdown/README.md +1 -1
  132. package/dist/cdn/markdown/snice-markdown.js +2 -2
  133. package/dist/cdn/markdown/snice-markdown.js.map +1 -1
  134. package/dist/cdn/markdown/snice-markdown.min.js +2 -2
  135. package/dist/cdn/markdown/snice-markdown.min.js.map +1 -1
  136. package/dist/cdn/masonry/snice-masonry.js +1 -1
  137. package/dist/cdn/masonry/snice-masonry.min.js +1 -1
  138. package/dist/cdn/menu/snice-menu.js +1 -1
  139. package/dist/cdn/menu/snice-menu.min.js +1 -1
  140. package/dist/cdn/modal/snice-modal.js +1 -1
  141. package/dist/cdn/modal/snice-modal.min.js +1 -1
  142. package/dist/cdn/music-player/snice-music-player.js +1 -1
  143. package/dist/cdn/music-player/snice-music-player.min.js +1 -1
  144. package/dist/cdn/nav/snice-nav.js +1 -1
  145. package/dist/cdn/nav/snice-nav.min.js +1 -1
  146. package/dist/cdn/network-graph/snice-network-graph.js +1 -1
  147. package/dist/cdn/network-graph/snice-network-graph.min.js +1 -1
  148. package/dist/cdn/notification-center/snice-notification-center.js +1 -1
  149. package/dist/cdn/notification-center/snice-notification-center.min.js +1 -1
  150. package/dist/cdn/org-chart/snice-org-chart.js +1 -1
  151. package/dist/cdn/org-chart/snice-org-chart.min.js +1 -1
  152. package/dist/cdn/pagination/snice-pagination.js +1 -1
  153. package/dist/cdn/pagination/snice-pagination.min.js +1 -1
  154. package/dist/cdn/paint/snice-paint.js +1 -1
  155. package/dist/cdn/paint/snice-paint.min.js +1 -1
  156. package/dist/cdn/pdf-viewer/README.md +2 -2
  157. package/dist/cdn/pdf-viewer/snice-pdf-viewer.js +72 -78
  158. package/dist/cdn/pdf-viewer/snice-pdf-viewer.js.map +1 -1
  159. package/dist/cdn/pdf-viewer/snice-pdf-viewer.min.js +3 -3
  160. package/dist/cdn/pdf-viewer/snice-pdf-viewer.min.js.map +1 -1
  161. package/dist/cdn/podcast-player/README.md +1 -1
  162. package/dist/cdn/podcast-player/snice-podcast-player.js +2 -2
  163. package/dist/cdn/podcast-player/snice-podcast-player.js.map +1 -1
  164. package/dist/cdn/podcast-player/snice-podcast-player.min.js +2 -2
  165. package/dist/cdn/podcast-player/snice-podcast-player.min.js.map +1 -1
  166. package/dist/cdn/pricing-table/snice-pricing-table.js +1 -1
  167. package/dist/cdn/pricing-table/snice-pricing-table.min.js +1 -1
  168. package/dist/cdn/progress/snice-progress.js +1 -1
  169. package/dist/cdn/progress/snice-progress.min.js +1 -1
  170. package/dist/cdn/qr-code/snice-qr-code.js +1 -1
  171. package/dist/cdn/qr-code/snice-qr-code.min.js +1 -1
  172. package/dist/cdn/qr-reader/snice-qr-reader.js +1 -1
  173. package/dist/cdn/qr-reader/snice-qr-reader.min.js +1 -1
  174. package/dist/cdn/radio/snice-radio.js +1 -1
  175. package/dist/cdn/radio/snice-radio.min.js +1 -1
  176. package/dist/cdn/rating/snice-rating.js +1 -1
  177. package/dist/cdn/rating/snice-rating.min.js +1 -1
  178. package/dist/cdn/recipe/snice-recipe.js +1 -1
  179. package/dist/cdn/recipe/snice-recipe.min.js +1 -1
  180. package/dist/cdn/runtime/README.md +1 -1
  181. package/dist/cdn/runtime/snice-runtime.esm.js +10 -3
  182. package/dist/cdn/runtime/snice-runtime.esm.js.map +1 -1
  183. package/dist/cdn/runtime/snice-runtime.esm.min.js +4 -4
  184. package/dist/cdn/runtime/snice-runtime.esm.min.js.map +1 -1
  185. package/dist/cdn/runtime/snice-runtime.js +10 -3
  186. package/dist/cdn/runtime/snice-runtime.js.map +1 -1
  187. package/dist/cdn/runtime/snice-runtime.min.js +4 -4
  188. package/dist/cdn/runtime/snice-runtime.min.js.map +1 -1
  189. package/dist/cdn/sankey/snice-sankey.js +1 -1
  190. package/dist/cdn/sankey/snice-sankey.min.js +1 -1
  191. package/dist/cdn/select/snice-select.js +1 -1
  192. package/dist/cdn/select/snice-select.min.js +1 -1
  193. package/dist/cdn/skeleton/snice-skeleton.js +1 -1
  194. package/dist/cdn/skeleton/snice-skeleton.min.js +1 -1
  195. package/dist/cdn/slider/snice-slider.js +1 -1
  196. package/dist/cdn/slider/snice-slider.min.js +1 -1
  197. package/dist/cdn/sortable/snice-sortable.js +1 -1
  198. package/dist/cdn/sortable/snice-sortable.min.js +1 -1
  199. package/dist/cdn/sparkline/snice-sparkline.js +1 -1
  200. package/dist/cdn/sparkline/snice-sparkline.min.js +1 -1
  201. package/dist/cdn/spinner/snice-spinner.js +1 -1
  202. package/dist/cdn/spinner/snice-spinner.min.js +1 -1
  203. package/dist/cdn/split-pane/snice-split-pane.js +1 -1
  204. package/dist/cdn/split-pane/snice-split-pane.min.js +1 -1
  205. package/dist/cdn/spotlight/snice-spotlight.js +1 -1
  206. package/dist/cdn/spotlight/snice-spotlight.min.js +1 -1
  207. package/dist/cdn/spreadsheet/snice-spreadsheet.js +1 -1
  208. package/dist/cdn/spreadsheet/snice-spreadsheet.min.js +1 -1
  209. package/dist/cdn/stepper/snice-stepper.js +1 -1
  210. package/dist/cdn/stepper/snice-stepper.min.js +1 -1
  211. package/dist/cdn/switch/snice-switch.js +1 -1
  212. package/dist/cdn/switch/snice-switch.min.js +1 -1
  213. package/dist/cdn/table/snice-table.js +1 -1
  214. package/dist/cdn/table/snice-table.min.js +1 -1
  215. package/dist/cdn/tabs/snice-tabs.js +1 -1
  216. package/dist/cdn/tabs/snice-tabs.min.js +1 -1
  217. package/dist/cdn/tag-input/snice-tag-input.js +1 -1
  218. package/dist/cdn/tag-input/snice-tag-input.min.js +1 -1
  219. package/dist/cdn/terminal/snice-terminal.js +1 -1
  220. package/dist/cdn/terminal/snice-terminal.min.js +1 -1
  221. package/dist/cdn/testimonial/snice-testimonial.js +1 -1
  222. package/dist/cdn/testimonial/snice-testimonial.min.js +1 -1
  223. package/dist/cdn/textarea/snice-textarea.js +1 -1
  224. package/dist/cdn/textarea/snice-textarea.min.js +1 -1
  225. package/dist/cdn/time-range-picker/snice-time-range-picker.js +1 -1
  226. package/dist/cdn/time-range-picker/snice-time-range-picker.min.js +1 -1
  227. package/dist/cdn/timeline/snice-timeline.js +1 -1
  228. package/dist/cdn/timeline/snice-timeline.min.js +1 -1
  229. package/dist/cdn/timer/snice-timer.js +1 -1
  230. package/dist/cdn/timer/snice-timer.min.js +1 -1
  231. package/dist/cdn/toast/snice-toast.js +1 -1
  232. package/dist/cdn/toast/snice-toast.min.js +1 -1
  233. package/dist/cdn/tooltip/snice-tooltip.js +1 -1
  234. package/dist/cdn/tooltip/snice-tooltip.min.js +1 -1
  235. package/dist/cdn/tree/snice-tree.js +1 -1
  236. package/dist/cdn/tree/snice-tree.min.js +1 -1
  237. package/dist/cdn/treemap/snice-treemap.js +1 -1
  238. package/dist/cdn/treemap/snice-treemap.min.js +1 -1
  239. package/dist/cdn/video-player/snice-video-player.js +1 -1
  240. package/dist/cdn/video-player/snice-video-player.min.js +1 -1
  241. package/dist/cdn/virtual-scroller/snice-virtual-scroller.js +1 -1
  242. package/dist/cdn/virtual-scroller/snice-virtual-scroller.min.js +1 -1
  243. package/dist/cdn/waterfall/snice-waterfall.js +1 -1
  244. package/dist/cdn/waterfall/snice-waterfall.min.js +1 -1
  245. package/dist/cdn/weather/snice-weather.js +1 -1
  246. package/dist/cdn/weather/snice-weather.min.js +1 -1
  247. package/dist/components/carousel/snice-carousel.js +8 -2
  248. package/dist/components/carousel/snice-carousel.js.map +1 -1
  249. package/dist/components/code-block/grammars/html.json +48 -0
  250. package/dist/components/markdown/snice-markdown.js +1 -1
  251. package/dist/components/markdown/snice-markdown.js.map +1 -1
  252. package/dist/components/pdf-viewer/snice-pdf-viewer.d.ts +9 -8
  253. package/dist/components/pdf-viewer/snice-pdf-viewer.js +71 -77
  254. package/dist/components/pdf-viewer/snice-pdf-viewer.js.map +1 -1
  255. package/dist/components/podcast-player/snice-podcast-player.js +1 -1
  256. package/dist/components/podcast-player/snice-podcast-player.js.map +1 -1
  257. package/dist/index.cjs +8 -1
  258. package/dist/index.cjs.map +1 -1
  259. package/dist/index.esm.js +8 -1
  260. package/dist/index.esm.js.map +1 -1
  261. package/dist/index.iife.js +8 -1
  262. package/dist/index.iife.js.map +1 -1
  263. package/dist/symbols.cjs +1 -1
  264. package/dist/symbols.esm.js +1 -1
  265. package/dist/transitions.cjs +1 -1
  266. package/dist/transitions.esm.js +1 -1
  267. package/docs/ai/patterns.md +1 -1
  268. package/docs/routing.md +2 -2
  269. package/package.json +4 -2
@@ -1,20 +1,24 @@
1
1
  import { page } from '../router';
2
- import { render, styles, html, css, context } from 'snice';
2
+ import { render, styles, html, css, context, observe, ready, dispose } from 'snice';
3
3
  import type { Placard, Context } from 'snice';
4
4
  import type { Principal } from '../types/auth';
5
- import { authGuard } from '../guards/auth';
5
+ import { isAuthenticated } from '../guards/auth';
6
+ import { getNotificationsDaemon } from '../daemons/notifications';
6
7
 
7
8
  const placard: Placard = {
8
9
  name: 'dashboard',
9
10
  title: 'Dashboard',
10
- icon: '📊',
11
+ icon: '\ud83d\udcca',
11
12
  show: true,
12
13
  order: 1
13
14
  };
14
15
 
15
- @page({ tag: 'dashboard-page', routes: ['/', '/dashboard'], guards: [authGuard], placard })
16
+ @page({ tag: 'dashboard-page', routes: ['/', '/dashboard'], guards: [isAuthenticated], placard })
16
17
  export class DashboardPage extends HTMLElement {
17
18
  userName = '';
19
+ notificationCount = 0;
20
+ isCompact = false;
21
+ private unsubscribe: (() => void) | null = null;
18
22
 
19
23
  @context()
20
24
  handleContext(ctx: Context) {
@@ -22,29 +26,72 @@ export class DashboardPage extends HTMLElement {
22
26
  this.userName = principal?.user?.name || 'User';
23
27
  }
24
28
 
29
+ @ready()
30
+ initialize() {
31
+ const daemon = getNotificationsDaemon();
32
+ this.unsubscribe = daemon.subscribe(() => {
33
+ this.notificationCount++;
34
+ });
35
+ }
36
+
37
+ @dispose()
38
+ cleanup() {
39
+ if (this.unsubscribe) {
40
+ this.unsubscribe();
41
+ this.unsubscribe = null;
42
+ }
43
+ }
44
+
45
+ @observe('media:(max-width: 768px)')
46
+ handleMediaChange(matches: boolean) {
47
+ this.isCompact = matches;
48
+ }
49
+
25
50
  @render()
26
51
  renderContent() {
27
52
  return html`
28
53
  <div class="container">
29
- <h1>Welcome, ${this.userName}!</h1>
30
- <p class="subtitle">This is your dashboard</p>
54
+ <div class="welcome">
55
+ <h1>Welcome, ${this.userName}!</h1>
56
+ <p class="subtitle">This is your dashboard</p>
57
+ </div>
58
+
59
+ <div class="stats">
60
+ <snice-card class="stat-card">
61
+ <span class="stat-value">4</span>
62
+ <span class="stat-label">Active Pages</span>
63
+ </snice-card>
64
+ <snice-card class="stat-card">
65
+ <span class="stat-value">${this.notificationCount}</span>
66
+ <span class="stat-label">Notifications</span>
67
+ </snice-card>
68
+ <snice-card class="stat-card">
69
+ <span class="stat-value">3</span>
70
+ <span class="stat-label">Middleware</span>
71
+ </snice-card>
72
+ </div>
31
73
 
32
74
  <div class="grid">
33
75
  <snice-card>
34
- <h3>⚡ Features</h3>
76
+ <h3>Features</h3>
35
77
  <ul>
36
78
  <li>JWT Authentication</li>
37
- <li>Protected Routes</li>
79
+ <li>Protected Routes with Guards</li>
38
80
  <li>Middleware Pattern</li>
39
- <li>Service Worker</li>
81
+ <li>Service Worker (PWA)</li>
40
82
  <li>Live Notifications</li>
83
+ <li>Controllers + Request/Response</li>
84
+ <li>Theme Switching</li>
85
+ <li>Debounced Search</li>
41
86
  </ul>
42
87
  </snice-card>
43
88
 
44
89
  <snice-card>
45
- <h3>🛠️ Architecture</h3>
90
+ <h3>Architecture</h3>
46
91
  <ul>
47
- <li><strong>Utils:</strong> Pure functions</li>
92
+ <li><strong>Pages:</strong> Route orchestrators</li>
93
+ <li><strong>Components:</strong> Reusable UI</li>
94
+ <li><strong>Controllers:</strong> Behavior modules</li>
48
95
  <li><strong>Services:</strong> Business logic</li>
49
96
  <li><strong>Middleware:</strong> Fetch interceptors</li>
50
97
  <li><strong>Daemons:</strong> Lifecycle classes</li>
@@ -53,22 +100,28 @@ export class DashboardPage extends HTMLElement {
53
100
  </snice-card>
54
101
 
55
102
  <snice-card>
56
- <h3>📦 What's Included</h3>
103
+ <h3>Decorators Used</h3>
57
104
  <ul>
58
- <li>TypeScript configuration</li>
59
- <li>Vite + SWC setup</li>
60
- <li>PWA manifest</li>
61
- <li>Mock authentication</li>
62
- <li>WebSocket daemon example</li>
105
+ <li><code>@page</code> - Route pages</li>
106
+ <li><code>@element</code> - Custom elements</li>
107
+ <li><code>@controller</code> - Behavior modules</li>
108
+ <li><code>@context</code> - Global state</li>
109
+ <li><code>@observe</code> - DOM observers</li>
110
+ <li><code>@watch</code> - Property watchers</li>
111
+ <li><code>@on</code> / <code>@dispatch</code> - Events</li>
112
+ <li><code>@request</code> / <code>@respond</code> - Communication</li>
63
113
  </ul>
64
114
  </snice-card>
65
115
 
66
116
  <snice-card>
67
- <h3>🚀 Get Started</h3>
117
+ <h3>Explore</h3>
68
118
  <p>Check out the other pages:</p>
69
119
  <div class="links">
70
- <a href="#/profile">
71
- <snice-button variant="secondary">View Profile</snice-button>
120
+ <a href="#/data">
121
+ <snice-button variant="secondary">Browse Data</snice-button>
122
+ </a>
123
+ <a href="#/settings">
124
+ <snice-button variant="secondary">Settings</snice-button>
72
125
  </a>
73
126
  <a href="#/notifications">
74
127
  <snice-button variant="secondary">Notifications</snice-button>
@@ -89,6 +142,10 @@ export class DashboardPage extends HTMLElement {
89
142
  margin: 0 auto;
90
143
  }
91
144
 
145
+ .welcome {
146
+ margin-bottom: 2rem;
147
+ }
148
+
92
149
  h1 {
93
150
  color: var(--primary-color);
94
151
  margin: 0 0 0.5rem 0;
@@ -96,12 +153,38 @@ export class DashboardPage extends HTMLElement {
96
153
 
97
154
  .subtitle {
98
155
  color: var(--text-light);
99
- margin: 0 0 2rem 0;
156
+ margin: 0;
157
+ }
158
+
159
+ .stats {
160
+ display: grid;
161
+ grid-template-columns: repeat(3, 1fr);
162
+ gap: 1rem;
163
+ margin-bottom: 2rem;
164
+ }
165
+
166
+ .stat-card {
167
+ padding: 1.25rem;
168
+ text-align: center;
169
+ }
170
+
171
+ .stat-value {
172
+ display: block;
173
+ font-size: 2rem;
174
+ font-weight: 700;
175
+ color: var(--primary-color);
176
+ }
177
+
178
+ .stat-label {
179
+ display: block;
180
+ font-size: 0.8125rem;
181
+ color: var(--text-light);
182
+ margin-top: 0.25rem;
100
183
  }
101
184
 
102
185
  .grid {
103
186
  display: grid;
104
- grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
187
+ grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
105
188
  gap: 1.5rem;
106
189
  }
107
190
 
@@ -124,6 +207,18 @@ export class DashboardPage extends HTMLElement {
124
207
  color: var(--text-color);
125
208
  }
126
209
 
210
+ code {
211
+ background: var(--bg-secondary);
212
+ padding: 0.125rem 0.375rem;
213
+ border-radius: var(--radius-sm);
214
+ font-size: 0.8125rem;
215
+ }
216
+
217
+ p {
218
+ color: var(--text-light);
219
+ margin: 0 0 0.5rem 0;
220
+ }
221
+
127
222
  .links {
128
223
  display: flex;
129
224
  flex-direction: column;
@@ -135,9 +230,15 @@ export class DashboardPage extends HTMLElement {
135
230
  text-decoration: none;
136
231
  }
137
232
 
138
- snice-button {
233
+ .links snice-button {
139
234
  width: 100%;
140
235
  }
236
+
237
+ @media (max-width: 640px) {
238
+ .stats {
239
+ grid-template-columns: 1fr;
240
+ }
241
+ }
141
242
  `;
142
243
  }
143
244
  }
@@ -0,0 +1,329 @@
1
+ import { page } from '../router';
2
+ import { render, styles, context, observe, property, html, css } from 'snice';
3
+ import type { Placard, Context } from 'snice';
4
+ import { isAuthenticated } from '../guards/auth';
5
+
6
+ interface DataItem {
7
+ id: string;
8
+ title: string;
9
+ description: string;
10
+ status: 'active' | 'pending' | 'archived';
11
+ createdAt: string;
12
+ }
13
+
14
+ const placard: Placard = {
15
+ name: 'data',
16
+ title: 'Data',
17
+ icon: '\ud83d\udcca',
18
+ show: true,
19
+ order: 5
20
+ };
21
+
22
+ // Mock data
23
+ const MOCK_ITEMS: DataItem[] = [
24
+ { id: '1', title: 'API Integration', description: 'Connect external payment gateway', status: 'active', createdAt: '2025-01-15' },
25
+ { id: '2', title: 'User Analytics', description: 'Implement tracking dashboard', status: 'pending', createdAt: '2025-01-20' },
26
+ { id: '3', title: 'Email Templates', description: 'Design transactional email set', status: 'active', createdAt: '2025-02-01' },
27
+ { id: '4', title: 'Legacy Migration', description: 'Migrate v1 database schema', status: 'archived', createdAt: '2024-12-10' },
28
+ { id: '5', title: 'Mobile App', description: 'React Native companion app', status: 'pending', createdAt: '2025-02-15' },
29
+ { id: '6', title: 'CI/CD Pipeline', description: 'GitHub Actions deployment workflow', status: 'active', createdAt: '2025-01-05' },
30
+ { id: '7', title: 'Documentation', description: 'API reference and developer guides', status: 'active', createdAt: '2025-02-10' },
31
+ { id: '8', title: 'Performance Audit', description: 'Lighthouse and Core Web Vitals', status: 'archived', createdAt: '2024-11-20' },
32
+ ];
33
+
34
+ @page({ tag: 'data-page', routes: ['/data'], guards: [isAuthenticated], placard })
35
+ export class DataPage extends HTMLElement {
36
+ private ctx?: Context;
37
+ allItems: DataItem[] = [];
38
+ filteredItems: DataItem[] = [];
39
+ searchQuery = '';
40
+ statusFilter: 'all' | 'active' | 'pending' | 'archived' = 'all';
41
+ @property({ type: Boolean }) loading = true;
42
+
43
+ @context()
44
+ handleContext(ctx: Context) {
45
+ this.ctx = ctx;
46
+ }
47
+
48
+ @observe('resize')
49
+ handleResize(entries: ResizeObserverEntry[]) {
50
+ const width = entries[0].contentRect.width;
51
+ const table = this.shadowRoot?.querySelector('.data-table');
52
+ if (table) {
53
+ table.classList.toggle('compact', width < 600);
54
+ }
55
+ }
56
+
57
+ connectedCallback() {
58
+ // Simulate loading data
59
+ setTimeout(() => {
60
+ this.allItems = [...MOCK_ITEMS];
61
+ this.filteredItems = this.allItems;
62
+ this.loading = false;
63
+ }, 500);
64
+ }
65
+
66
+ handleSearch(e: CustomEvent) {
67
+ this.searchQuery = e.detail.query || '';
68
+ this.applyFilters();
69
+ }
70
+
71
+ setStatusFilter(status: 'all' | 'active' | 'pending' | 'archived') {
72
+ this.statusFilter = status;
73
+ this.applyFilters();
74
+ }
75
+
76
+ private applyFilters() {
77
+ let items = this.allItems;
78
+
79
+ if (this.statusFilter !== 'all') {
80
+ items = items.filter(i => i.status === this.statusFilter);
81
+ }
82
+
83
+ if (this.searchQuery) {
84
+ const q = this.searchQuery.toLowerCase();
85
+ items = items.filter(i =>
86
+ i.title.toLowerCase().includes(q) ||
87
+ i.description.toLowerCase().includes(q)
88
+ );
89
+ }
90
+
91
+ this.filteredItems = items;
92
+ }
93
+
94
+ getStatusColor(status: string): string {
95
+ const colors: Record<string, string> = {
96
+ active: 'var(--success-color)',
97
+ pending: 'var(--warning-color)',
98
+ archived: 'var(--text-light)'
99
+ };
100
+ return colors[status] || 'var(--text-light)';
101
+ }
102
+
103
+ @render()
104
+ renderContent() {
105
+ return html`
106
+ <div class="container">
107
+ <div class="header">
108
+ <h1>Data</h1>
109
+ <span class="count">${this.filteredItems.length} items</span>
110
+ </div>
111
+
112
+ <div class="toolbar">
113
+ <search-bar
114
+ placeholder="Search items..."
115
+ @search=${this.handleSearch}
116
+ ></search-bar>
117
+
118
+ <div class="filters">
119
+ <button
120
+ class="filter-btn ${this.statusFilter === 'all' ? 'active' : ''}"
121
+ @click=${() => this.setStatusFilter('all')}
122
+ >All</button>
123
+ <button
124
+ class="filter-btn ${this.statusFilter === 'active' ? 'active' : ''}"
125
+ @click=${() => this.setStatusFilter('active')}
126
+ >Active</button>
127
+ <button
128
+ class="filter-btn ${this.statusFilter === 'pending' ? 'active' : ''}"
129
+ @click=${() => this.setStatusFilter('pending')}
130
+ >Pending</button>
131
+ <button
132
+ class="filter-btn ${this.statusFilter === 'archived' ? 'active' : ''}"
133
+ @click=${() => this.setStatusFilter('archived')}
134
+ >Archived</button>
135
+ </div>
136
+ </div>
137
+
138
+ <case ${this.loading ? 'loading' : this.filteredItems.length === 0 ? 'empty' : 'data'}>
139
+ <when value="loading">
140
+ <div class="center">
141
+ <snice-spinner></snice-spinner>
142
+ </div>
143
+ </when>
144
+ <when value="empty">
145
+ <snice-empty-state
146
+ icon="\ud83d\udd0d"
147
+ title="No results"
148
+ description="Try adjusting your search or filters"
149
+ ></snice-empty-state>
150
+ </when>
151
+ <default>
152
+ <div class="data-table">
153
+ <div class="table-header">
154
+ <span class="col-title">Title</span>
155
+ <span class="col-status">Status</span>
156
+ <span class="col-date">Created</span>
157
+ </div>
158
+ ${this.filteredItems.map(item => html`
159
+ <div class="table-row" key=${item.id}>
160
+ <div class="col-title">
161
+ <strong>${item.title}</strong>
162
+ <span class="description">${item.description}</span>
163
+ </div>
164
+ <div class="col-status">
165
+ <span class="status-dot" style="background: ${this.getStatusColor(item.status)}"></span>
166
+ ${item.status}
167
+ </div>
168
+ <div class="col-date">${item.createdAt}</div>
169
+ </div>
170
+ `)}
171
+ </div>
172
+ </default>
173
+ </case>
174
+ </div>
175
+ `;
176
+ }
177
+
178
+ @styles()
179
+ componentStyles() {
180
+ return css`
181
+ .container {
182
+ padding: 2rem;
183
+ max-width: 1000px;
184
+ margin: 0 auto;
185
+ }
186
+
187
+ .header {
188
+ display: flex;
189
+ justify-content: space-between;
190
+ align-items: baseline;
191
+ margin-bottom: 1.5rem;
192
+ }
193
+
194
+ h1 {
195
+ margin: 0;
196
+ color: var(--primary-color);
197
+ }
198
+
199
+ .count {
200
+ font-size: 0.875rem;
201
+ color: var(--text-light);
202
+ }
203
+
204
+ .toolbar {
205
+ display: flex;
206
+ flex-direction: column;
207
+ gap: 1rem;
208
+ margin-bottom: 1.5rem;
209
+ }
210
+
211
+ search-bar {
212
+ width: 100%;
213
+ }
214
+
215
+ .filters {
216
+ display: flex;
217
+ gap: 0.5rem;
218
+ }
219
+
220
+ .filter-btn {
221
+ padding: 0.375rem 0.75rem;
222
+ border: 1px solid var(--border-color);
223
+ border-radius: var(--radius-sm);
224
+ background: var(--bg-primary);
225
+ color: var(--text-light);
226
+ font-size: 0.8125rem;
227
+ cursor: pointer;
228
+ transition: all 0.15s;
229
+ }
230
+
231
+ .filter-btn:hover {
232
+ border-color: var(--primary-color);
233
+ color: var(--primary-color);
234
+ }
235
+
236
+ .filter-btn.active {
237
+ background: var(--primary-color);
238
+ border-color: var(--primary-color);
239
+ color: white;
240
+ }
241
+
242
+ .center {
243
+ display: flex;
244
+ justify-content: center;
245
+ padding: 3rem;
246
+ }
247
+
248
+ .data-table {
249
+ border: 1px solid var(--border-color);
250
+ border-radius: var(--radius-md);
251
+ overflow: hidden;
252
+ }
253
+
254
+ .table-header {
255
+ display: grid;
256
+ grid-template-columns: 1fr 120px 100px;
257
+ padding: 0.75rem 1rem;
258
+ background: var(--bg-secondary);
259
+ font-size: 0.75rem;
260
+ font-weight: 600;
261
+ text-transform: uppercase;
262
+ letter-spacing: 0.05em;
263
+ color: var(--text-light);
264
+ }
265
+
266
+ .table-row {
267
+ display: grid;
268
+ grid-template-columns: 1fr 120px 100px;
269
+ padding: 1rem;
270
+ border-top: 1px solid var(--border-color);
271
+ align-items: center;
272
+ transition: background 0.15s;
273
+ }
274
+
275
+ .table-row:hover {
276
+ background: var(--bg-secondary);
277
+ }
278
+
279
+ .col-title strong {
280
+ display: block;
281
+ color: var(--text-color);
282
+ font-size: 0.9375rem;
283
+ }
284
+
285
+ .description {
286
+ display: block;
287
+ font-size: 0.8125rem;
288
+ color: var(--text-light);
289
+ margin-top: 0.125rem;
290
+ }
291
+
292
+ .col-status {
293
+ display: flex;
294
+ align-items: center;
295
+ gap: 0.375rem;
296
+ font-size: 0.8125rem;
297
+ color: var(--text-color);
298
+ text-transform: capitalize;
299
+ }
300
+
301
+ .status-dot {
302
+ width: 8px;
303
+ height: 8px;
304
+ border-radius: 50%;
305
+ flex-shrink: 0;
306
+ }
307
+
308
+ .col-date {
309
+ font-size: 0.8125rem;
310
+ color: var(--text-light);
311
+ }
312
+
313
+ .data-table.compact .table-header {
314
+ display: none;
315
+ }
316
+
317
+ .data-table.compact .table-row {
318
+ grid-template-columns: 1fr;
319
+ gap: 0.5rem;
320
+ }
321
+
322
+ @media (max-width: 640px) {
323
+ .filters {
324
+ flex-wrap: wrap;
325
+ }
326
+ }
327
+ `;
328
+ }
329
+ }