snice 2.5.4 → 3.1.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 (323) hide show
  1. package/README.md +501 -882
  2. package/bin/templates/base/src/components/counter-button.ts +13 -26
  3. package/bin/templates/base/src/controllers/counter-controller.ts +3 -3
  4. package/dist/components/accordion/snice-accordion-item.d.ts +4 -5
  5. package/dist/components/accordion/snice-accordion-item.js +37 -39
  6. package/dist/components/accordion/snice-accordion-item.js.map +1 -1
  7. package/dist/components/accordion/snice-accordion.d.ts +5 -11
  8. package/dist/components/accordion/snice-accordion.js +51 -52
  9. package/dist/components/accordion/snice-accordion.js.map +1 -1
  10. package/dist/components/alert/snice-alert.d.ts +2 -6
  11. package/dist/components/alert/snice-alert.js +41 -56
  12. package/dist/components/alert/snice-alert.js.map +1 -1
  13. package/dist/components/avatar/snice-avatar.d.ts +2 -6
  14. package/dist/components/avatar/snice-avatar.js +64 -71
  15. package/dist/components/avatar/snice-avatar.js.map +1 -1
  16. package/dist/components/badge/snice-badge.d.ts +2 -3
  17. package/dist/components/badge/snice-badge.js +22 -23
  18. package/dist/components/badge/snice-badge.js.map +1 -1
  19. package/dist/components/breadcrumbs/snice-breadcrumbs.d.ts +5 -12
  20. package/dist/components/breadcrumbs/snice-breadcrumbs.js +88 -89
  21. package/dist/components/breadcrumbs/snice-breadcrumbs.js.map +1 -1
  22. package/dist/components/button/snice-button.d.ts +3 -7
  23. package/dist/components/button/snice-button.js +37 -58
  24. package/dist/components/button/snice-button.js.map +1 -1
  25. package/dist/components/card/snice-card.d.ts +5 -8
  26. package/dist/components/card/snice-card.js +71 -56
  27. package/dist/components/card/snice-card.js.map +1 -1
  28. package/dist/components/checkbox/snice-checkbox.d.ts +4 -13
  29. package/dist/components/checkbox/snice-checkbox.js +66 -137
  30. package/dist/components/checkbox/snice-checkbox.js.map +1 -1
  31. package/dist/components/chip/snice-chip.d.ts +5 -11
  32. package/dist/components/chip/snice-chip.js +44 -47
  33. package/dist/components/chip/snice-chip.js.map +1 -1
  34. package/dist/components/date-picker/snice-date-picker.d.ts +11 -11
  35. package/dist/components/date-picker/snice-date-picker.js +134 -133
  36. package/dist/components/date-picker/snice-date-picker.js.map +1 -1
  37. package/dist/components/divider/snice-divider.d.ts +2 -4
  38. package/dist/components/divider/snice-divider.js +14 -22
  39. package/dist/components/divider/snice-divider.js.map +1 -1
  40. package/dist/components/drawer/snice-drawer.d.ts +4 -4
  41. package/dist/components/drawer/snice-drawer.js +25 -19
  42. package/dist/components/drawer/snice-drawer.js.map +1 -1
  43. package/dist/components/input/snice-input.d.ts +8 -6
  44. package/dist/components/input/snice-input.js +122 -105
  45. package/dist/components/input/snice-input.js.map +1 -1
  46. package/dist/components/layout/snice-layout-blog.d.ts +4 -4
  47. package/dist/components/layout/snice-layout-blog.js +21 -19
  48. package/dist/components/layout/snice-layout-blog.js.map +1 -1
  49. package/dist/components/layout/snice-layout-card.d.ts +2 -2
  50. package/dist/components/layout/snice-layout-card.js +16 -9
  51. package/dist/components/layout/snice-layout-card.js.map +1 -1
  52. package/dist/components/layout/snice-layout-centered.d.ts +2 -2
  53. package/dist/components/layout/snice-layout-centered.js +14 -7
  54. package/dist/components/layout/snice-layout-centered.js.map +1 -1
  55. package/dist/components/layout/snice-layout-dashboard.d.ts +5 -5
  56. package/dist/components/layout/snice-layout-dashboard.js +38 -30
  57. package/dist/components/layout/snice-layout-dashboard.js.map +1 -1
  58. package/dist/components/layout/snice-layout-fullscreen.d.ts +2 -2
  59. package/dist/components/layout/snice-layout-fullscreen.js +17 -10
  60. package/dist/components/layout/snice-layout-fullscreen.js.map +1 -1
  61. package/dist/components/layout/snice-layout-landing.d.ts +4 -4
  62. package/dist/components/layout/snice-layout-landing.js +21 -19
  63. package/dist/components/layout/snice-layout-landing.js.map +1 -1
  64. package/dist/components/layout/snice-layout-minimal.d.ts +2 -2
  65. package/dist/components/layout/snice-layout-minimal.js +17 -6
  66. package/dist/components/layout/snice-layout-minimal.js.map +1 -1
  67. package/dist/components/layout/snice-layout-sidebar.d.ts +5 -4
  68. package/dist/components/layout/snice-layout-sidebar.js +42 -20
  69. package/dist/components/layout/snice-layout-sidebar.js.map +1 -1
  70. package/dist/components/layout/snice-layout-split.d.ts +2 -2
  71. package/dist/components/layout/snice-layout-split.js +14 -7
  72. package/dist/components/layout/snice-layout-split.js.map +1 -1
  73. package/dist/components/layout/snice-layout.d.ts +4 -4
  74. package/dist/components/layout/snice-layout.js +16 -10
  75. package/dist/components/layout/snice-layout.js.map +1 -1
  76. package/dist/components/login/snice-login.d.ts +6 -11
  77. package/dist/components/login/snice-login.js +97 -71
  78. package/dist/components/login/snice-login.js.map +1 -1
  79. package/dist/components/modal/snice-modal.d.ts +5 -9
  80. package/dist/components/modal/snice-modal.js +47 -78
  81. package/dist/components/modal/snice-modal.js.map +1 -1
  82. package/dist/components/nav/snice-nav.d.ts +13 -7
  83. package/dist/components/nav/snice-nav.js +191 -100
  84. package/dist/components/nav/snice-nav.js.map +1 -1
  85. package/dist/components/nav/snice-nav.types.d.ts +3 -3
  86. package/dist/components/pagination/snice-pagination.d.ts +6 -7
  87. package/dist/components/pagination/snice-pagination.js +94 -81
  88. package/dist/components/pagination/snice-pagination.js.map +1 -1
  89. package/dist/components/progress/snice-progress.d.ts +2 -7
  90. package/dist/components/progress/snice-progress.js +41 -98
  91. package/dist/components/progress/snice-progress.js.map +1 -1
  92. package/dist/components/radio/snice-radio.d.ts +4 -4
  93. package/dist/components/radio/snice-radio.js +52 -44
  94. package/dist/components/radio/snice-radio.js.map +1 -1
  95. package/dist/components/select/snice-option.d.ts +2 -1
  96. package/dist/components/select/snice-option.js +12 -5
  97. package/dist/components/select/snice-option.js.map +1 -1
  98. package/dist/components/select/snice-select.d.ts +9 -21
  99. package/dist/components/select/snice-select.js +98 -170
  100. package/dist/components/select/snice-select.js.map +1 -1
  101. package/dist/components/skeleton/snice-skeleton.d.ts +2 -6
  102. package/dist/components/skeleton/snice-skeleton.js +18 -49
  103. package/dist/components/skeleton/snice-skeleton.js.map +1 -1
  104. package/dist/components/snice-cell-BLFVdxPp.js +4 -0
  105. package/dist/components/snice-cell-BLFVdxPp.js.map +1 -0
  106. package/dist/components/switch/snice-switch.d.ts +2 -2
  107. package/dist/components/switch/snice-switch.js +38 -26
  108. package/dist/components/switch/snice-switch.js.map +1 -1
  109. package/dist/components/table/snice-cell-actions.d.ts +24 -0
  110. package/dist/components/table/snice-cell-actions.js +149 -0
  111. package/dist/components/table/snice-cell-actions.js.map +1 -0
  112. package/dist/components/table/snice-cell-boolean.d.ts +2 -2
  113. package/dist/components/table/snice-cell-boolean.js +13 -7
  114. package/dist/components/table/snice-cell-boolean.js.map +1 -1
  115. package/dist/components/table/snice-cell-color.d.ts +18 -0
  116. package/dist/components/table/snice-cell-color.js +149 -0
  117. package/dist/components/table/snice-cell-color.js.map +1 -0
  118. package/dist/components/table/snice-cell-currency.d.ts +24 -0
  119. package/dist/components/table/snice-cell-currency.js +235 -0
  120. package/dist/components/table/snice-cell-currency.js.map +1 -0
  121. package/dist/components/table/snice-cell-date.d.ts +2 -2
  122. package/dist/components/table/snice-cell-date.js +14 -8
  123. package/dist/components/table/snice-cell-date.js.map +1 -1
  124. package/dist/components/table/snice-cell-duration.d.ts +2 -2
  125. package/dist/components/table/snice-cell-duration.js +12 -6
  126. package/dist/components/table/snice-cell-duration.js.map +1 -1
  127. package/dist/components/table/snice-cell-email.d.ts +15 -0
  128. package/dist/components/table/snice-cell-email.js +125 -0
  129. package/dist/components/table/snice-cell-email.js.map +1 -0
  130. package/dist/components/table/snice-cell-filesize.d.ts +2 -2
  131. package/dist/components/table/snice-cell-filesize.js +12 -6
  132. package/dist/components/table/snice-cell-filesize.js.map +1 -1
  133. package/dist/components/table/snice-cell-image.d.ts +20 -0
  134. package/dist/components/table/snice-cell-image.js +162 -0
  135. package/dist/components/table/snice-cell-image.js.map +1 -0
  136. package/dist/components/table/snice-cell-json.d.ts +20 -0
  137. package/dist/components/table/snice-cell-json.js +186 -0
  138. package/dist/components/table/snice-cell-json.js.map +1 -0
  139. package/dist/components/table/snice-cell-link.d.ts +17 -0
  140. package/dist/components/table/snice-cell-link.js +142 -0
  141. package/dist/components/table/snice-cell-link.js.map +1 -0
  142. package/dist/components/table/snice-cell-location.d.ts +19 -0
  143. package/dist/components/table/snice-cell-location.js +185 -0
  144. package/dist/components/table/snice-cell-location.js.map +1 -0
  145. package/dist/components/table/snice-cell-number.d.ts +2 -2
  146. package/dist/components/table/snice-cell-number.js +12 -6
  147. package/dist/components/table/snice-cell-number.js.map +1 -1
  148. package/dist/components/table/snice-cell-percentage.d.ts +22 -0
  149. package/dist/components/table/snice-cell-percentage.js +208 -0
  150. package/dist/components/table/snice-cell-percentage.js.map +1 -0
  151. package/dist/components/table/snice-cell-phone.d.ts +18 -0
  152. package/dist/components/table/snice-cell-phone.js +153 -0
  153. package/dist/components/table/snice-cell-phone.js.map +1 -0
  154. package/dist/components/table/snice-cell-progress.d.ts +2 -2
  155. package/dist/components/table/snice-cell-progress.js +12 -6
  156. package/dist/components/table/snice-cell-progress.js.map +1 -1
  157. package/dist/components/table/snice-cell-rating.d.ts +2 -2
  158. package/dist/components/table/snice-cell-rating.js +12 -6
  159. package/dist/components/table/snice-cell-rating.js.map +1 -1
  160. package/dist/components/table/snice-cell-sparkline.d.ts +2 -2
  161. package/dist/components/table/snice-cell-sparkline.js +13 -7
  162. package/dist/components/table/snice-cell-sparkline.js.map +1 -1
  163. package/dist/components/table/snice-cell-status.d.ts +17 -0
  164. package/dist/components/table/snice-cell-status.js +144 -0
  165. package/dist/components/table/snice-cell-status.js.map +1 -0
  166. package/dist/components/table/snice-cell-tag.d.ts +16 -0
  167. package/dist/components/table/snice-cell-tag.js +131 -0
  168. package/dist/components/table/snice-cell-tag.js.map +1 -0
  169. package/dist/components/table/snice-cell-text.d.ts +2 -2
  170. package/dist/components/table/snice-cell-text.js +14 -8
  171. package/dist/components/table/snice-cell-text.js.map +1 -1
  172. package/dist/components/table/snice-cell.d.ts +2 -2
  173. package/dist/components/table/snice-cell.js +12 -6
  174. package/dist/components/table/snice-cell.js.map +1 -1
  175. package/dist/components/table/snice-column.d.ts +1 -1
  176. package/dist/components/table/snice-column.js +6 -3
  177. package/dist/components/table/snice-column.js.map +1 -1
  178. package/dist/components/table/snice-header.d.ts +5 -5
  179. package/dist/components/table/snice-header.js +60 -50
  180. package/dist/components/table/snice-header.js.map +1 -1
  181. package/dist/components/table/snice-progress.d.ts +2 -2
  182. package/dist/components/table/snice-progress.js +18 -11
  183. package/dist/components/table/snice-progress.js.map +1 -1
  184. package/dist/components/table/snice-rating.d.ts +2 -2
  185. package/dist/components/table/snice-rating.js +15 -8
  186. package/dist/components/table/snice-rating.js.map +1 -1
  187. package/dist/components/table/snice-row.d.ts +17 -6
  188. package/dist/components/table/snice-row.js +95 -44
  189. package/dist/components/table/snice-row.js.map +1 -1
  190. package/dist/components/table/snice-table.d.ts +18 -10
  191. package/dist/components/table/snice-table.js +355 -173
  192. package/dist/components/table/snice-table.js.map +1 -1
  193. package/dist/components/table/snice-table.types.d.ts +101 -2
  194. package/dist/components/tabs/snice-tab-panel.d.ts +2 -2
  195. package/dist/components/tabs/snice-tab-panel.js +12 -6
  196. package/dist/components/tabs/snice-tab-panel.js.map +1 -1
  197. package/dist/components/tabs/snice-tab.d.ts +6 -5
  198. package/dist/components/tabs/snice-tab.js +36 -19
  199. package/dist/components/tabs/snice-tab.js.map +1 -1
  200. package/dist/components/tabs/snice-tabs.d.ts +5 -5
  201. package/dist/components/tabs/snice-tabs.js +38 -28
  202. package/dist/components/tabs/snice-tabs.js.map +1 -1
  203. package/dist/components/toast/snice-toast-container.d.ts +7 -7
  204. package/dist/components/toast/snice-toast-container.js +19 -12
  205. package/dist/components/toast/snice-toast-container.js.map +1 -1
  206. package/dist/components/toast/snice-toast.d.ts +3 -15
  207. package/dist/components/toast/snice-toast.js +49 -108
  208. package/dist/components/toast/snice-toast.js.map +1 -1
  209. package/dist/components/tooltip/snice-tooltip.d.ts +2 -2
  210. package/dist/components/tooltip/snice-tooltip.js +14 -7
  211. package/dist/components/tooltip/snice-tooltip.js.map +1 -1
  212. package/dist/context.d.ts +44 -0
  213. package/dist/element-ready.d.ts +40 -0
  214. package/dist/{types/element.d.ts → element.d.ts} +2 -8
  215. package/dist/{types/events.d.ts → events.d.ts} +0 -4
  216. package/dist/index.cjs +2589 -605
  217. package/dist/index.cjs.map +1 -1
  218. package/dist/index.d.ts +21 -0
  219. package/dist/index.esm.js +2568 -604
  220. package/dist/index.esm.js.map +1 -1
  221. package/dist/index.iife.js +2589 -605
  222. package/dist/index.iife.js.map +1 -1
  223. package/dist/method-decorators.d.ts +121 -0
  224. package/dist/on.d.ts +59 -0
  225. package/dist/parts.d.ts +159 -0
  226. package/dist/render-debug.d.ts +27 -0
  227. package/dist/render-tracker.d.ts +14 -0
  228. package/dist/render.d.ts +96 -0
  229. package/dist/symbols.cjs +163 -0
  230. package/dist/symbols.cjs.map +1 -1
  231. package/dist/{types/symbols.d.ts → symbols.d.ts} +22 -0
  232. package/dist/symbols.esm.js +27 -3
  233. package/dist/symbols.esm.js.map +1 -1
  234. package/dist/template.d.ts +100 -0
  235. package/dist/transitions.cjs +219 -0
  236. package/dist/transitions.esm.js +2 -2
  237. package/dist/types/context.d.ts +48 -0
  238. package/dist/types/element-options.d.ts +26 -0
  239. package/dist/types/index.d.ts +25 -9
  240. package/dist/types/nav-context.d.ts +19 -0
  241. package/dist/types/{types/on-options.d.ts → on-options.d.ts} +2 -0
  242. package/dist/types/{types/placard.d.ts → placard.d.ts} +0 -1
  243. package/docs/ai/README.md +17 -0
  244. package/docs/ai/api.md +175 -0
  245. package/docs/ai/architecture.md +160 -0
  246. package/docs/ai/components/accordion.md +174 -0
  247. package/docs/ai/components/alert.md +77 -0
  248. package/docs/ai/components/avatar.md +61 -0
  249. package/docs/ai/components/badge.md +69 -0
  250. package/docs/ai/components/breadcrumbs.md +74 -0
  251. package/docs/ai/components/button.md +75 -0
  252. package/docs/ai/components/card.md +61 -0
  253. package/docs/ai/components/checkbox.md +74 -0
  254. package/docs/ai/components/chip.md +73 -0
  255. package/docs/ai/components/date-picker.md +75 -0
  256. package/docs/ai/components/divider.md +66 -0
  257. package/docs/ai/components/drawer.md +80 -0
  258. package/docs/ai/components/input.md +111 -0
  259. package/docs/ai/components/login.md +109 -0
  260. package/docs/ai/components/modal.md +67 -0
  261. package/docs/ai/components/nav.md +76 -0
  262. package/docs/ai/components/pagination.md +55 -0
  263. package/docs/ai/components/progress.md +72 -0
  264. package/docs/ai/components/radio.md +79 -0
  265. package/docs/ai/components/select.md +92 -0
  266. package/docs/ai/components/skeleton.md +57 -0
  267. package/docs/ai/components/switch.md +53 -0
  268. package/docs/ai/components/table.md +227 -0
  269. package/docs/ai/components/tabs.md +83 -0
  270. package/docs/ai/components/toast.md +140 -0
  271. package/docs/ai/components/tooltip.md +146 -0
  272. package/docs/ai/patterns.md +244 -0
  273. package/docs/components/accordion.md +558 -0
  274. package/docs/components/drawer.md +602 -0
  275. package/docs/components/modal.md +558 -0
  276. package/docs/components/nav.md +239 -0
  277. package/docs/components/pagination.md +289 -0
  278. package/docs/components/select.md +599 -0
  279. package/docs/components/switch.md +354 -0
  280. package/docs/components/tabs.md +546 -0
  281. package/docs/components/toast.md +506 -0
  282. package/docs/components/tooltip.md +523 -0
  283. package/docs/controllers.md +744 -0
  284. package/docs/elements.md +855 -0
  285. package/docs/events.md +807 -0
  286. package/docs/migration-v2-to-v3.md +569 -0
  287. package/docs/observe.md +588 -0
  288. package/docs/placards.md +401 -0
  289. package/docs/request-response.md +852 -0
  290. package/docs/routing.md +1186 -0
  291. package/package.json +10 -11
  292. package/dist/components/snice-cell-C9N6yGxQ.js +0 -4
  293. package/dist/components/snice-cell-C9N6yGxQ.js.map +0 -1
  294. package/dist/types/types/index.d.ts +0 -23
  295. /package/dist/{types/controller.d.ts → controller.d.ts} +0 -0
  296. /package/dist/{types/global.d.ts → global.d.ts} +0 -0
  297. /package/dist/{types/observe.d.ts → observe.d.ts} +0 -0
  298. /package/dist/{types/request-response.d.ts → request-response.d.ts} +0 -0
  299. /package/dist/{types/router.d.ts → router.d.ts} +0 -0
  300. /package/dist/{types/testing.d.ts → testing.d.ts} +0 -0
  301. /package/dist/{types/transitions.d.ts → transitions.d.ts} +0 -0
  302. /package/dist/types/{types/adopted-options.d.ts → adopted-options.d.ts} +0 -0
  303. /package/dist/types/{types/app-context.d.ts → app-context.d.ts} +0 -0
  304. /package/dist/types/{types/dispatch-options.d.ts → dispatch-options.d.ts} +0 -0
  305. /package/dist/types/{types/guard.d.ts → guard.d.ts} +0 -0
  306. /package/dist/types/{types/i-controller.d.ts → i-controller.d.ts} +0 -0
  307. /package/dist/types/{types/moved-options.d.ts → moved-options.d.ts} +0 -0
  308. /package/dist/types/{types/observe-options.d.ts → observe-options.d.ts} +0 -0
  309. /package/dist/types/{types/page-options.d.ts → page-options.d.ts} +0 -0
  310. /package/dist/types/{types/part-options.d.ts → part-options.d.ts} +0 -0
  311. /package/dist/types/{types/property-converter.d.ts → property-converter.d.ts} +0 -0
  312. /package/dist/types/{types/property-options.d.ts → property-options.d.ts} +0 -0
  313. /package/dist/types/{types/query-options.d.ts → query-options.d.ts} +0 -0
  314. /package/dist/types/{types/request-options.d.ts → request-options.d.ts} +0 -0
  315. /package/dist/types/{types/respond-options.d.ts → respond-options.d.ts} +0 -0
  316. /package/dist/types/{types/route-params.d.ts → route-params.d.ts} +0 -0
  317. /package/dist/types/{types/router-instance.d.ts → router-instance.d.ts} +0 -0
  318. /package/dist/types/{types/router-options.d.ts → router-options.d.ts} +0 -0
  319. /package/dist/types/{types/simple-array.d.ts → simple-array.d.ts} +0 -0
  320. /package/dist/types/{types/snice-element.d.ts → snice-element.d.ts} +0 -0
  321. /package/dist/types/{types/snice-global.d.ts → snice-global.d.ts} +0 -0
  322. /package/dist/types/{types/transition.d.ts → transition.d.ts} +0 -0
  323. /package/dist/{types/utils.d.ts → utils.d.ts} +0 -0
@@ -0,0 +1,401 @@
1
+ # Placards API
2
+
3
+ Placards provide rich metadata about pages that layouts can consume to dynamically build navigation, breadcrumbs, help systems, and other UI elements. This enables layouts to be populated with data instead of having hardcoded content.
4
+
5
+ ## Overview
6
+
7
+ The Placard system allows pages to declare metadata that describes their purpose, structure, and behavior. Layouts can then query this metadata to automatically build:
8
+
9
+ - Dynamic navigation menus
10
+ - Hierarchical breadcrumbs
11
+ - Context-sensitive help
12
+ - Search functionality
13
+ - Keyboard shortcuts
14
+
15
+ ## Basic Usage
16
+
17
+ Define a placard for your page using the `placard` option in the `@page` decorator:
18
+
19
+ ```typescript
20
+ import { page, Placard, render, html } from 'snice';
21
+
22
+ const placard: Placard<AppContext> = {
23
+ name: 'dashboard',
24
+ title: 'Dashboard',
25
+ description: 'Main analytics and overview dashboard',
26
+ icon: '📊',
27
+ show: true,
28
+ order: 1
29
+ };
30
+
31
+ @page({
32
+ tag: 'dashboard-page',
33
+ routes: ['/dashboard'],
34
+ placard: placard
35
+ })
36
+ class DashboardPage extends HTMLElement {
37
+ @render()
38
+ renderContent() {
39
+ return html`<h1>Dashboard</h1>`;
40
+ }
41
+ }
42
+ ```
43
+
44
+ ## Placard Interface
45
+
46
+ ```typescript
47
+ interface Placard<T = any> {
48
+ // Identification
49
+ name: string;
50
+
51
+ // Core display
52
+ title: string;
53
+ description?: string;
54
+ icon?: string;
55
+
56
+ // Help & discovery
57
+ tooltip?: string;
58
+ searchTerms?: string[];
59
+ hotkeys?: string[];
60
+ helpUrl?: string;
61
+
62
+ // Navigation structure
63
+ breadcrumbs?: string[];
64
+ group?: string;
65
+ parent?: string;
66
+ order?: number;
67
+ show?: boolean;
68
+
69
+ // Dynamic visibility
70
+ visibleOn?: Guard<T> | Guard<T>[];
71
+
72
+ // Extensibility
73
+ attributes?: Record<string, any>;
74
+ }
75
+ ```
76
+
77
+ ## Field Reference
78
+
79
+ ### Identification
80
+
81
+ **`name`** (required)
82
+ - Unique identifier for this placard
83
+ - Used for referencing in breadcrumbs and parent-child relationships
84
+ - Should be kebab-case, e.g., 'user-settings', 'admin-dashboard'
85
+
86
+ ### Core Display
87
+
88
+ **`title`** (required)
89
+ - Display name shown in navigation and breadcrumbs
90
+ - Should be concise and descriptive
91
+
92
+ **`description`** (optional)
93
+ - Longer description of the page's purpose
94
+ - Used in tooltips, search results, or help text
95
+
96
+ **`icon`** (optional)
97
+ - Visual icon representing the page
98
+ - Can be emoji, icon font class, or SVG path
99
+
100
+ ### Help & Discovery
101
+
102
+ **`tooltip`** (optional)
103
+ - Brief help text shown on hover
104
+ - Explains what the page does or when to use it
105
+
106
+ **`searchTerms`** (optional)
107
+ - Additional keywords for search functionality
108
+ - Helps users discover pages through alternate terms
109
+
110
+ ```typescript
111
+ searchTerms: ['settings', 'preferences', 'config', 'options']
112
+ ```
113
+
114
+ **`hotkeys`** (optional)
115
+ - Keyboard shortcuts to navigate to this page
116
+ - Uses standard key notation
117
+
118
+ ```typescript
119
+ hotkeys: ['ctrl+d', 'cmd+d', 'alt+shift+d']
120
+ ```
121
+
122
+ **`helpUrl`** (optional)
123
+ - Link to detailed documentation or help for this page
124
+
125
+ ### Navigation Structure
126
+
127
+ **`group`** (optional)
128
+ - Logical grouping for navigation organization
129
+ - Pages with the same group are displayed together
130
+
131
+ ```typescript
132
+ group: 'admin' // Groups with other admin pages
133
+ ```
134
+
135
+ **`parent`** (optional)
136
+ - References another placard's `name` to create hierarchy
137
+ - Used for nested navigation and breadcrumb construction
138
+
139
+ ```typescript
140
+ parent: 'users' // Child of the 'users' page
141
+ ```
142
+
143
+ **`order`** (optional)
144
+ - Numeric sort order within the group or parent
145
+ - Lower numbers appear first
146
+
147
+ **`show`** (optional)
148
+ - Whether to display this page in navigation menus
149
+ - Defaults to `true` if not specified
150
+
151
+ ### Dynamic Visibility
152
+
153
+ **`visibleOn`** (optional)
154
+ - Guard functions that determine if the page should appear in navigation
155
+ - Reuses the same guard system as route protection
156
+
157
+ ```typescript
158
+ visibleOn: [isAuthenticated, hasAdminRole]
159
+ ```
160
+
161
+ ### Extensibility
162
+
163
+ **`attributes`** (optional)
164
+ - Arbitrary metadata for custom layout needs
165
+ - Domain-specific or framework-specific data
166
+
167
+ ```typescript
168
+ attributes: {
169
+ category: 'reporting',
170
+ experimental: true,
171
+ requiredFeatures: ['analytics', 'charts']
172
+ }
173
+ ```
174
+
175
+ ## Hierarchical Navigation Example
176
+
177
+ ```typescript
178
+ // Parent page
179
+ const usersPlacard: Placard<AppContext> = {
180
+ name: 'users',
181
+ title: 'Users',
182
+ icon: '👥',
183
+ show: true,
184
+ order: 1,
185
+ group: 'admin'
186
+ };
187
+
188
+ // Child pages
189
+ const userListPlacard: Placard<AppContext> = {
190
+ name: 'user-list',
191
+ title: 'All Users',
192
+ parent: 'users',
193
+ order: 1,
194
+ show: true
195
+ };
196
+
197
+ const userCreatePlacard: Placard<AppContext> = {
198
+ name: 'user-create',
199
+ title: 'Create User',
200
+ parent: 'users',
201
+ order: 2,
202
+ show: true,
203
+ visibleOn: [canCreateUsers]
204
+ };
205
+
206
+ // Grandchild page
207
+ const userEditPlacard: Placard<AppContext> = {
208
+ name: 'user-edit',
209
+ title: 'Edit User',
210
+ parent: 'user-list',
211
+ show: false, // Hidden from nav, accessible via direct link
212
+ breadcrumbs: ['users', 'user-list', 'user-edit']
213
+ };
214
+ ```
215
+
216
+ ## Breadcrumb Resolution
217
+
218
+ Breadcrumbs can be automatically resolved using the `parent` hierarchy or explicitly defined:
219
+
220
+ ```typescript
221
+ // Automatic breadcrumbs using parent chain
222
+ const settingsPlacard: Placard<AppContext> = {
223
+ name: 'user-settings',
224
+ title: 'Settings',
225
+ parent: 'user-profile'
226
+ // Breadcrumbs will be auto-resolved: Users > Profile > Settings
227
+ };
228
+
229
+ // Explicit breadcrumbs
230
+ const advancedPlacard: Placard<AppContext> = {
231
+ name: 'advanced-settings',
232
+ title: 'Advanced',
233
+ breadcrumbs: ['dashboard', 'settings', 'advanced-settings']
234
+ // Explicitly defined breadcrumb path
235
+ };
236
+ ```
237
+
238
+ ## Layout Integration
239
+
240
+ Layouts can access placard data to build dynamic UI. The exact mechanism depends on your router implementation, but typically involves:
241
+
242
+ 1. **Router Context** - Placards available through router context
243
+ 2. **Navigation Builder** - Helper functions to build nav from placards
244
+ 3. **Event System** - Layouts listen for route changes and update UI
245
+
246
+ ```typescript
247
+ import { layout, render, html, Layout } from 'snice';
248
+
249
+ @layout('app-shell')
250
+ class AppShell extends HTMLElement implements Layout {
251
+ private placards: Placard[] = [];
252
+ private currentRoute = '';
253
+
254
+ @render()
255
+ renderContent() {
256
+ return html`
257
+ <header>
258
+ <nav>
259
+ ${this.placards
260
+ .filter(p => p.show !== false && !p.parent)
261
+ .map(p => html`
262
+ <a
263
+ href="#/${p.name}"
264
+ class="${this.currentRoute === p.name ? 'active' : ''}"
265
+ >
266
+ ${p.icon} ${p.title}
267
+ </a>
268
+ `)}
269
+ </nav>
270
+ </header>
271
+ <main>
272
+ <slot name="page"></slot>
273
+ </main>
274
+ `;
275
+ }
276
+
277
+ // Called by router when route changes
278
+ update(appContext: any, placards: Placard[], currentRoute: string, routeParams: any) {
279
+ this.placards = placards;
280
+ this.currentRoute = currentRoute;
281
+ // Property changes trigger re-render
282
+ }
283
+ }
284
+ ```
285
+
286
+ ### Building Navigation from Placards
287
+
288
+ ```typescript
289
+ @layout('sidebar-layout')
290
+ class SidebarLayout extends HTMLElement implements Layout {
291
+ private placards: Placard[] = [];
292
+ private grouped: Record<string, Placard[]> = {};
293
+
294
+ @render()
295
+ renderContent() {
296
+ return html`
297
+ <aside class="sidebar">
298
+ ${Object.entries(this.grouped).map(([group, items]) => html`
299
+ <div class="nav-group">
300
+ <h3>${group}</h3>
301
+ <ul>
302
+ ${items
303
+ .sort((a, b) => (a.order || 0) - (b.order || 0))
304
+ .map(p => html`
305
+ <li>
306
+ <a href="#/${p.name}" title="${p.tooltip || ''}">
307
+ ${p.icon} ${p.title}
308
+ </a>
309
+ </li>
310
+ `)}
311
+ </ul>
312
+ </div>
313
+ `)}
314
+ </aside>
315
+ <main>
316
+ <slot name="page"></slot>
317
+ </main>
318
+ `;
319
+ }
320
+
321
+ update(appContext: any, placards: Placard[], currentRoute: string, routeParams: any) {
322
+ this.placards = placards.filter(p => p.show !== false);
323
+
324
+ // Group placards
325
+ this.grouped = this.placards.reduce((acc, p) => {
326
+ const group = p.group || 'main';
327
+ if (!acc[group]) acc[group] = [];
328
+ acc[group].push(p);
329
+ return acc;
330
+ }, {} as Record<string, Placard[]>);
331
+ }
332
+ }
333
+ ```
334
+
335
+ ### Building Breadcrumbs
336
+
337
+ ```typescript
338
+ @layout('breadcrumb-layout')
339
+ class BreadcrumbLayout extends HTMLElement implements Layout {
340
+ private breadcrumbs: Placard[] = [];
341
+
342
+ @render()
343
+ renderContent() {
344
+ return html`
345
+ <nav class="breadcrumbs">
346
+ ${this.breadcrumbs.map((p, i) => html`
347
+ ${i > 0 ? html`<span class="separator">/</span>` : ''}
348
+ <a href="#/${p.name}">${p.title}</a>
349
+ `)}
350
+ </nav>
351
+ <main>
352
+ <slot name="page"></slot>
353
+ </main>
354
+ `;
355
+ }
356
+
357
+ update(appContext: any, placards: Placard[], currentRoute: string, routeParams: any) {
358
+ // Find current page placard
359
+ const current = placards.find(p => p.name === currentRoute);
360
+ if (!current) return;
361
+
362
+ // Build breadcrumb trail
363
+ this.breadcrumbs = this.buildBreadcrumbs(current, placards);
364
+ }
365
+
366
+ buildBreadcrumbs(placard: Placard, all: Placard[]): Placard[] {
367
+ const trail: Placard[] = [placard];
368
+
369
+ // Use explicit breadcrumbs if defined
370
+ if (placard.breadcrumbs) {
371
+ return placard.breadcrumbs
372
+ .map(name => all.find(p => p.name === name))
373
+ .filter(Boolean) as Placard[];
374
+ }
375
+
376
+ // Otherwise follow parent chain
377
+ let current = placard;
378
+ while (current.parent) {
379
+ const parent = all.find(p => p.name === current.parent);
380
+ if (!parent) break;
381
+ trail.unshift(parent);
382
+ current = parent;
383
+ }
384
+
385
+ return trail;
386
+ }
387
+ }
388
+ ```
389
+
390
+ ## Best Practices
391
+
392
+ 1. **Use consistent naming**: Use kebab-case for placard names
393
+ 2. **Provide helpful icons**: Visual indicators improve navigation UX
394
+ 3. **Set meaningful order**: Lower numbers appear first in navigation
395
+ 4. **Use groups wisely**: Group related pages for better organization
396
+ 5. **Define search terms**: Help users discover features through search
397
+ 6. **Leverage guards**: Use visibleOn to show/hide navigation based on permissions
398
+ 7. **Explicit when needed**: Use explicit breadcrumbs for complex hierarchies
399
+ 8. **Keep titles short**: Navigation labels should be concise
400
+ 9. **Provide tooltips**: Add helpful context for ambiguous page names
401
+ 10. **Use parent relationships**: Build hierarchical navigation automatically