unspaghettit 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (270) hide show
  1. package/build/client/_app/immutable/assets/0.DSctqr5I.css +1 -0
  2. package/build/client/_app/immutable/assets/0.DSctqr5I.css.br +0 -0
  3. package/build/client/_app/immutable/assets/0.DSctqr5I.css.gz +0 -0
  4. package/build/client/_app/immutable/assets/BehaviorGraph.Bk0xQRZk.css +1 -0
  5. package/build/client/_app/immutable/assets/BehaviorGraph.Bk0xQRZk.css.br +0 -0
  6. package/build/client/_app/immutable/assets/BehaviorGraph.Bk0xQRZk.css.gz +0 -0
  7. package/build/client/_app/immutable/chunks/9nXQ5qrY2.js +1 -0
  8. package/build/client/_app/immutable/chunks/9nXQ5qrY2.js.br +0 -0
  9. package/build/client/_app/immutable/chunks/9nXQ5qrY2.js.gz +0 -0
  10. package/build/client/_app/immutable/chunks/B439_FLv.js +1 -0
  11. package/build/client/_app/immutable/chunks/B439_FLv.js.br +0 -0
  12. package/build/client/_app/immutable/chunks/B439_FLv.js.gz +0 -0
  13. package/build/client/_app/immutable/chunks/BCEY79Dw.js +1 -0
  14. package/build/client/_app/immutable/chunks/BCEY79Dw.js.br +2 -0
  15. package/build/client/_app/immutable/chunks/BCEY79Dw.js.gz +0 -0
  16. package/build/client/_app/immutable/chunks/{DBJWcC6Y.js → BYIrIC5L.js} +1 -1
  17. package/build/client/_app/immutable/chunks/BYIrIC5L.js.br +0 -0
  18. package/build/client/_app/immutable/chunks/BYIrIC5L.js.gz +0 -0
  19. package/build/client/_app/immutable/chunks/B_9TWPrx2.js +1 -0
  20. package/build/client/_app/immutable/chunks/B_9TWPrx2.js.br +0 -0
  21. package/build/client/_app/immutable/chunks/B_9TWPrx2.js.gz +0 -0
  22. package/build/client/_app/immutable/chunks/BvOhVtZg.js +1 -0
  23. package/build/client/_app/immutable/chunks/BvOhVtZg.js.br +1 -0
  24. package/build/client/_app/immutable/chunks/BvOhVtZg.js.gz +0 -0
  25. package/build/client/_app/immutable/chunks/CY3em1ma2.js +1 -0
  26. package/build/client/_app/immutable/chunks/CY3em1ma2.js.br +0 -0
  27. package/build/client/_app/immutable/chunks/CY3em1ma2.js.gz +0 -0
  28. package/build/client/_app/immutable/chunks/CgdRZPgI.js +1 -0
  29. package/build/client/_app/immutable/chunks/CgdRZPgI.js.br +0 -0
  30. package/build/client/_app/immutable/chunks/CgdRZPgI.js.gz +0 -0
  31. package/build/client/_app/immutable/chunks/D5speDV82.js +908 -0
  32. package/build/client/_app/immutable/chunks/D5speDV82.js.br +0 -0
  33. package/build/client/_app/immutable/chunks/D5speDV82.js.gz +0 -0
  34. package/build/client/_app/immutable/chunks/DkxwAIfJ2.js +1 -0
  35. package/build/client/_app/immutable/chunks/DkxwAIfJ2.js.br +0 -0
  36. package/build/client/_app/immutable/chunks/DkxwAIfJ2.js.gz +0 -0
  37. package/build/client/_app/immutable/chunks/{DatGSObE.js → OJscNS3T.js} +1 -1
  38. package/build/client/_app/immutable/chunks/OJscNS3T.js.br +0 -0
  39. package/build/client/_app/immutable/chunks/OJscNS3T.js.gz +0 -0
  40. package/build/client/_app/immutable/chunks/U9p9CtKG2.js +2 -0
  41. package/build/client/_app/immutable/chunks/U9p9CtKG2.js.br +0 -0
  42. package/build/client/_app/immutable/chunks/U9p9CtKG2.js.gz +0 -0
  43. package/build/client/_app/immutable/entry/app.Cd4S3giu.js +2 -0
  44. package/build/client/_app/immutable/entry/app.Cd4S3giu.js.br +0 -0
  45. package/build/client/_app/immutable/entry/app.Cd4S3giu.js.gz +0 -0
  46. package/build/client/_app/immutable/entry/start.C3xXQVkq.js +1 -0
  47. package/build/client/_app/immutable/entry/start.C3xXQVkq.js.br +0 -0
  48. package/build/client/_app/immutable/entry/start.C3xXQVkq.js.gz +0 -0
  49. package/build/client/_app/immutable/nodes/0.dIOlQ-0y.js +4 -0
  50. package/build/client/_app/immutable/nodes/0.dIOlQ-0y.js.br +0 -0
  51. package/build/client/_app/immutable/nodes/0.dIOlQ-0y.js.gz +0 -0
  52. package/build/client/_app/immutable/nodes/{1.KYdA6ppX.js → 1.Dyte3Ggf.js} +1 -1
  53. package/build/client/_app/immutable/nodes/1.Dyte3Ggf.js.br +2 -0
  54. package/build/client/_app/immutable/nodes/1.Dyte3Ggf.js.gz +0 -0
  55. package/build/client/_app/immutable/nodes/10.ivxAosDg.js +2 -0
  56. package/build/client/_app/immutable/nodes/10.ivxAosDg.js.br +0 -0
  57. package/build/client/_app/immutable/nodes/10.ivxAosDg.js.gz +0 -0
  58. package/build/client/_app/immutable/nodes/{9.CMW6a2Lg.js → 11.wvMfJKC2.js} +1 -1
  59. package/build/client/_app/immutable/nodes/11.wvMfJKC2.js.br +0 -0
  60. package/build/client/_app/immutable/nodes/11.wvMfJKC2.js.gz +0 -0
  61. package/build/client/_app/immutable/nodes/{2.DBz20KgG.js → 2.CmPPom9Z.js} +1 -1
  62. package/build/client/_app/immutable/nodes/2.CmPPom9Z.js.br +0 -0
  63. package/build/client/_app/immutable/nodes/2.CmPPom9Z.js.gz +0 -0
  64. package/build/client/_app/immutable/nodes/3.D-iCGCEx.js +1 -0
  65. package/build/client/_app/immutable/nodes/3.D-iCGCEx.js.br +0 -0
  66. package/build/client/_app/immutable/nodes/3.D-iCGCEx.js.gz +0 -0
  67. package/build/client/_app/immutable/nodes/{4.BvMzqBJj.js → 4.DbfAvO8Z.js} +1 -1
  68. package/build/client/_app/immutable/nodes/4.DbfAvO8Z.js.br +0 -0
  69. package/build/client/_app/immutable/nodes/4.DbfAvO8Z.js.gz +0 -0
  70. package/build/client/_app/immutable/nodes/5.CC5Q7lVw.js +42 -0
  71. package/build/client/_app/immutable/nodes/5.CC5Q7lVw.js.br +0 -0
  72. package/build/client/_app/immutable/nodes/5.CC5Q7lVw.js.gz +0 -0
  73. package/build/client/_app/immutable/nodes/6.CHIjlzpO.js +1 -0
  74. package/build/client/_app/immutable/nodes/6.CHIjlzpO.js.br +0 -0
  75. package/build/client/_app/immutable/nodes/6.CHIjlzpO.js.gz +0 -0
  76. package/build/client/_app/immutable/nodes/{6.BOHISqs-.js → 7.Ejs18ZUc.js} +1 -1
  77. package/build/client/_app/immutable/nodes/7.Ejs18ZUc.js.br +0 -0
  78. package/build/client/_app/immutable/nodes/7.Ejs18ZUc.js.gz +0 -0
  79. package/build/client/_app/immutable/nodes/{7.CemgNJfw.js → 8.B-HweAc8.js} +1 -1
  80. package/build/client/_app/immutable/nodes/8.B-HweAc8.js.br +0 -0
  81. package/build/client/_app/immutable/nodes/8.B-HweAc8.js.gz +0 -0
  82. package/build/client/_app/immutable/nodes/9.CKPeM6tx.js +5 -0
  83. package/build/client/_app/immutable/nodes/9.CKPeM6tx.js.br +0 -0
  84. package/build/client/_app/immutable/nodes/9.CKPeM6tx.js.gz +0 -0
  85. package/build/client/_app/version.json +1 -1
  86. package/build/client/_app/version.json.br +0 -0
  87. package/build/client/_app/version.json.gz +0 -0
  88. package/build/client/lyriks_logo.svg +148 -0
  89. package/build/client/lyriks_logo.svg.br +0 -0
  90. package/build/client/lyriks_logo.svg.gz +0 -0
  91. package/build/server/chunks/{0-C_o0oz-N.js → 0-Co8kcANG.js} +4 -4
  92. package/build/server/chunks/{0-C_o0oz-N.js.map → 0-Co8kcANG.js.map} +1 -1
  93. package/build/server/chunks/1-BSUItTig.js +9 -0
  94. package/build/server/chunks/{1-DPpKAKXV.js.map → 1-BSUItTig.js.map} +1 -1
  95. package/build/server/chunks/10-BygvxrZp.js +9 -0
  96. package/build/server/chunks/10-BygvxrZp.js.map +1 -0
  97. package/build/server/chunks/11-DRx0tRx2.js +9 -0
  98. package/build/server/chunks/11-DRx0tRx2.js.map +1 -0
  99. package/build/server/chunks/{2-AlfFqtL1.js → 2-BQT3m1vc.js} +3 -3
  100. package/build/server/chunks/{2-AlfFqtL1.js.map → 2-BQT3m1vc.js.map} +1 -1
  101. package/build/server/chunks/{3-vbjUt_51.js → 3-DPZ9BquJ.js} +3 -3
  102. package/build/server/chunks/{3-vbjUt_51.js.map → 3-DPZ9BquJ.js.map} +1 -1
  103. package/build/server/chunks/{4-BNow4x6D.js → 4-DHo47YX6.js} +3 -3
  104. package/build/server/chunks/{4-BNow4x6D.js.map → 4-DHo47YX6.js.map} +1 -1
  105. package/build/server/chunks/5-Cp9evBAG.js +9 -0
  106. package/build/server/chunks/5-Cp9evBAG.js.map +1 -0
  107. package/build/server/chunks/6-DiBq3bOV.js +9 -0
  108. package/build/server/chunks/6-DiBq3bOV.js.map +1 -0
  109. package/build/server/chunks/{6-QQ7r8Rd5.js → 7-C4hmS0dG.js} +3 -3
  110. package/build/server/chunks/{6-QQ7r8Rd5.js.map → 7-C4hmS0dG.js.map} +1 -1
  111. package/build/server/chunks/{7-CbPLGaIG.js → 8-CFFuDzBC.js} +4 -4
  112. package/build/server/chunks/{7-CbPLGaIG.js.map → 8-CFFuDzBC.js.map} +1 -1
  113. package/build/server/chunks/9-nhhKZJrs.js +9 -0
  114. package/build/server/chunks/9-nhhKZJrs.js.map +1 -0
  115. package/build/server/chunks/BehaviorGraph-m5kYj5HH.js +757 -0
  116. package/build/server/chunks/BehaviorGraph-m5kYj5HH.js.map +1 -0
  117. package/build/server/chunks/{FeatureCard-BQOY6gJQ.js → FeatureCard-CfbXNYe8.js} +2 -2
  118. package/build/server/chunks/{FeatureCard-BQOY6gJQ.js.map → FeatureCard-CfbXNYe8.js.map} +1 -1
  119. package/build/server/chunks/{ProgressBar-CfhccQ83.js → ProgressBar-DDoQJ_C9.js} +2 -2
  120. package/build/server/chunks/ProgressBar-DDoQJ_C9.js.map +1 -0
  121. package/build/server/chunks/{ProjectsIndex-CoDrvRya.js → ProjectsIndex-DUVJ3hyL.js} +2 -2
  122. package/build/server/chunks/{ProjectsIndex-CoDrvRya.js.map → ProjectsIndex-DUVJ3hyL.js.map} +1 -1
  123. package/build/server/chunks/TransitionCatalog-B8zHs-2E.js +271 -0
  124. package/build/server/chunks/TransitionCatalog-B8zHs-2E.js.map +1 -0
  125. package/build/server/chunks/{_layout.svelte-BREws55o.js → _layout.svelte-CLTmk0xU.js} +66 -15
  126. package/build/server/chunks/_layout.svelte-CLTmk0xU.js.map +1 -0
  127. package/build/server/chunks/{_page.svelte-De508ek8.js → _page.svelte-B1nG3PKn.js} +4 -4
  128. package/build/server/chunks/{_page.svelte-De508ek8.js.map → _page.svelte-B1nG3PKn.js.map} +1 -1
  129. package/build/server/chunks/{_page.svelte-Zf9H4KOP.js → _page.svelte-BW_nbAAH.js} +11 -315
  130. package/build/server/chunks/_page.svelte-BW_nbAAH.js.map +1 -0
  131. package/build/server/chunks/{_page.svelte-BqSC-1vK.js → _page.svelte-Caq7J0jU.js} +91 -47
  132. package/build/server/chunks/_page.svelte-Caq7J0jU.js.map +1 -0
  133. package/build/server/chunks/{_page.svelte-B7hT3P8E.js → _page.svelte-Cham-dsM.js} +4 -4
  134. package/build/server/chunks/{_page.svelte-B7hT3P8E.js.map → _page.svelte-Cham-dsM.js.map} +1 -1
  135. package/build/server/chunks/_page.svelte-Dhwjwph_.js +41 -0
  136. package/build/server/chunks/_page.svelte-Dhwjwph_.js.map +1 -0
  137. package/build/server/chunks/{_page.svelte-BKKCa9H5.js → _page.svelte-DlFVT40-.js} +3 -3
  138. package/build/server/chunks/{_page.svelte-BKKCa9H5.js.map → _page.svelte-DlFVT40-.js.map} +1 -1
  139. package/build/server/chunks/{_page.svelte-BtI2zZ_Z.js → _page.svelte-NVT2dzpG.js} +176 -327
  140. package/build/server/chunks/_page.svelte-NVT2dzpG.js.map +1 -0
  141. package/build/server/chunks/{_page.svelte-BKTveFAj.js → _page.svelte-Oj-W7G5s.js} +5 -5
  142. package/build/server/chunks/{_page.svelte-BKTveFAj.js.map → _page.svelte-Oj-W7G5s.js.map} +1 -1
  143. package/build/server/chunks/_page.svelte-Z_kK2lHY.js +68 -0
  144. package/build/server/chunks/_page.svelte-Z_kK2lHY.js.map +1 -0
  145. package/build/server/chunks/{builderModeStore.svelte-ihupr-3p.js → builderModeStore.svelte-BpRIU_zP.js} +217 -6
  146. package/build/server/chunks/builderModeStore.svelte-BpRIU_zP.js.map +1 -0
  147. package/build/server/chunks/client-DeX3TC3s.js +51 -0
  148. package/build/server/chunks/{client-DfpLcAZ9.js.map → client-DeX3TC3s.js.map} +1 -1
  149. package/build/server/chunks/{error.svelte-C35KOpru.js → error.svelte-Cdjeq3L2.js} +4 -4
  150. package/build/server/chunks/{error.svelte-C35KOpru.js.map → error.svelte-Cdjeq3L2.js.map} +1 -1
  151. package/build/server/chunks/featureStore.svelte-DIYgPBVm.js +161 -0
  152. package/build/server/chunks/featureStore.svelte-DIYgPBVm.js.map +1 -0
  153. package/build/server/chunks/{hooks.server-Rv301GTB.js → hooks.server-y3jdg_sB.js} +6 -2
  154. package/build/server/chunks/hooks.server-y3jdg_sB.js.map +1 -0
  155. package/build/server/chunks/{internal-BPKrFkK1.js → internal-KYK0WpL7.js} +4 -4
  156. package/build/server/chunks/{internal-BPKrFkK1.js.map → internal-KYK0WpL7.js.map} +1 -1
  157. package/build/server/chunks/projectFeaturesStore.svelte-2o-72_vr.js +313 -0
  158. package/build/server/chunks/projectFeaturesStore.svelte-2o-72_vr.js.map +1 -0
  159. package/build/server/chunks/{reconcile-Dv7jS3C8.js → reconcile-B5xqb6-s.js} +3 -272
  160. package/build/server/chunks/reconcile-B5xqb6-s.js.map +1 -0
  161. package/build/server/chunks/registry-DqAn_hVE.js +21 -0
  162. package/build/server/chunks/registry-DqAn_hVE.js.map +1 -0
  163. package/build/server/chunks/{state-CpLVNZq7.js → state-DBjl9lhV.js} +2 -2
  164. package/build/server/chunks/{state-CpLVNZq7.js.map → state-DBjl9lhV.js.map} +1 -1
  165. package/build/server/index.js +1 -1
  166. package/build/server/index.js.map +1 -1
  167. package/build/server/manifest.js +33 -17
  168. package/build/server/manifest.js.map +1 -1
  169. package/cli/commands/dashboard.ts +14 -0
  170. package/cli/commands/init.ts +26 -0
  171. package/cli/commands/theme.ts +62 -0
  172. package/cli/unspa.ts +38 -2
  173. package/cli/util/context-files.ts +5 -0
  174. package/cli/util/theme.ts +34 -0
  175. package/mcp-server/sync-notifier.ts +88 -35
  176. package/package.json +2 -1
  177. package/src/app.css +187 -0
  178. package/src/app.html +15 -1
  179. package/src/features/behavior-model/domain/services/BehaviorGraphModel.ts +531 -0
  180. package/src/features/behavior-model/presentation/adapters/VisBehaviorGraphRenderer.ts +492 -0
  181. package/src/features/behavior-model/presentation/components/BehaviorGraph.svelte +370 -0
  182. package/src/features/behavior-model/presentation/components/FeatureHeader.svelte +13 -5
  183. package/src/features/behavior-model/presentation/view-models/BehaviorGraphTheme.ts +43 -0
  184. package/src/features/builder-mode/domain/BuilderModeDashboard.ts +7 -1
  185. package/src/features/builder-mode/presentation/components/BuilderModeDashboard.svelte +78 -16
  186. package/src/features/builder-mode/presentation/components/BuilderTagChips.svelte +25 -0
  187. package/src/features/builder-mode/presentation/stores/builderModeStore.svelte.ts +247 -3
  188. package/src/features/projects/presentation/components/ProjectEditor.svelte +7 -0
  189. package/src/features/simulator/application/use-cases/RunScenarios.ts +15 -1
  190. package/src/hooks.server.ts +11 -1
  191. package/src/lib/theme/registry.ts +77 -0
  192. package/src/lib/theme/themeStore.svelte.ts +64 -0
  193. package/src/routes/+layout.svelte +184 -30
  194. package/src/routes/features/[id]/graph/+page.svelte +34 -0
  195. package/src/routes/projects/[id]/graph/+page.svelte +79 -0
  196. package/src/shared/presentation/components/ProgressBar.svelte +1 -1
  197. package/src/shared/presentation/toast/SyncToast.svelte +14 -3
  198. package/src/shared/presentation/toast/viewLinkResolver.ts +32 -0
  199. package/static/lyriks_logo.svg +148 -0
  200. package/build/client/_app/immutable/assets/0.DFMDYAU9.css +0 -1
  201. package/build/client/_app/immutable/assets/0.DFMDYAU9.css.br +0 -0
  202. package/build/client/_app/immutable/assets/0.DFMDYAU9.css.gz +0 -0
  203. package/build/client/_app/immutable/chunks/BO66rBOa2.js +0 -1
  204. package/build/client/_app/immutable/chunks/BO66rBOa2.js.br +0 -0
  205. package/build/client/_app/immutable/chunks/BO66rBOa2.js.gz +0 -0
  206. package/build/client/_app/immutable/chunks/DBJWcC6Y.js.br +0 -0
  207. package/build/client/_app/immutable/chunks/DBJWcC6Y.js.gz +0 -0
  208. package/build/client/_app/immutable/chunks/DHoA038D.js +0 -1
  209. package/build/client/_app/immutable/chunks/DHoA038D.js.br +0 -2
  210. package/build/client/_app/immutable/chunks/DHoA038D.js.gz +0 -0
  211. package/build/client/_app/immutable/chunks/DatGSObE.js.br +0 -0
  212. package/build/client/_app/immutable/chunks/DatGSObE.js.gz +0 -0
  213. package/build/client/_app/immutable/chunks/DjWKKtqp.js +0 -1
  214. package/build/client/_app/immutable/chunks/DjWKKtqp.js.br +0 -1
  215. package/build/client/_app/immutable/chunks/DjWKKtqp.js.gz +0 -0
  216. package/build/client/_app/immutable/chunks/Dq0DUAz1.js +0 -1
  217. package/build/client/_app/immutable/chunks/Dq0DUAz1.js.br +0 -0
  218. package/build/client/_app/immutable/chunks/Dq0DUAz1.js.gz +0 -0
  219. package/build/client/_app/immutable/chunks/iQu0D9Ux.js +0 -1
  220. package/build/client/_app/immutable/chunks/iQu0D9Ux.js.br +0 -0
  221. package/build/client/_app/immutable/chunks/iQu0D9Ux.js.gz +0 -0
  222. package/build/client/_app/immutable/entry/app.CLgh6Mx_.js +0 -2
  223. package/build/client/_app/immutable/entry/app.CLgh6Mx_.js.br +0 -0
  224. package/build/client/_app/immutable/entry/app.CLgh6Mx_.js.gz +0 -0
  225. package/build/client/_app/immutable/entry/start.D5GPCQZD.js +0 -1
  226. package/build/client/_app/immutable/entry/start.D5GPCQZD.js.br +0 -0
  227. package/build/client/_app/immutable/entry/start.D5GPCQZD.js.gz +0 -0
  228. package/build/client/_app/immutable/nodes/0.BOoI-hsu.js +0 -4
  229. package/build/client/_app/immutable/nodes/0.BOoI-hsu.js.br +0 -0
  230. package/build/client/_app/immutable/nodes/0.BOoI-hsu.js.gz +0 -0
  231. package/build/client/_app/immutable/nodes/1.KYdA6ppX.js.br +0 -2
  232. package/build/client/_app/immutable/nodes/1.KYdA6ppX.js.gz +0 -0
  233. package/build/client/_app/immutable/nodes/2.DBz20KgG.js.br +0 -0
  234. package/build/client/_app/immutable/nodes/2.DBz20KgG.js.gz +0 -0
  235. package/build/client/_app/immutable/nodes/3.19DIoFtw.js +0 -1
  236. package/build/client/_app/immutable/nodes/3.19DIoFtw.js.br +0 -0
  237. package/build/client/_app/immutable/nodes/3.19DIoFtw.js.gz +0 -0
  238. package/build/client/_app/immutable/nodes/4.BvMzqBJj.js.br +0 -0
  239. package/build/client/_app/immutable/nodes/4.BvMzqBJj.js.gz +0 -0
  240. package/build/client/_app/immutable/nodes/5.Dq6obSGG.js +0 -42
  241. package/build/client/_app/immutable/nodes/5.Dq6obSGG.js.br +0 -0
  242. package/build/client/_app/immutable/nodes/5.Dq6obSGG.js.gz +0 -0
  243. package/build/client/_app/immutable/nodes/6.BOHISqs-.js.br +0 -0
  244. package/build/client/_app/immutable/nodes/6.BOHISqs-.js.gz +0 -0
  245. package/build/client/_app/immutable/nodes/7.CemgNJfw.js.br +0 -0
  246. package/build/client/_app/immutable/nodes/7.CemgNJfw.js.gz +0 -0
  247. package/build/client/_app/immutable/nodes/8.DejSfIYh.js +0 -5
  248. package/build/client/_app/immutable/nodes/8.DejSfIYh.js.br +0 -0
  249. package/build/client/_app/immutable/nodes/8.DejSfIYh.js.gz +0 -0
  250. package/build/client/_app/immutable/nodes/9.CMW6a2Lg.js.br +0 -0
  251. package/build/client/_app/immutable/nodes/9.CMW6a2Lg.js.gz +0 -0
  252. package/build/server/chunks/1-DPpKAKXV.js +0 -9
  253. package/build/server/chunks/5-D7OCJpxD.js +0 -9
  254. package/build/server/chunks/5-D7OCJpxD.js.map +0 -1
  255. package/build/server/chunks/8-CVO-E-sf.js +0 -9
  256. package/build/server/chunks/8-CVO-E-sf.js.map +0 -1
  257. package/build/server/chunks/9-DxT1baO5.js +0 -9
  258. package/build/server/chunks/9-DxT1baO5.js.map +0 -1
  259. package/build/server/chunks/ProgressBar-CfhccQ83.js.map +0 -1
  260. package/build/server/chunks/_layout.svelte-BREws55o.js.map +0 -1
  261. package/build/server/chunks/_page.svelte-BqSC-1vK.js.map +0 -1
  262. package/build/server/chunks/_page.svelte-BtI2zZ_Z.js.map +0 -1
  263. package/build/server/chunks/_page.svelte-Zf9H4KOP.js.map +0 -1
  264. package/build/server/chunks/builderModeStore.svelte-ihupr-3p.js.map +0 -1
  265. package/build/server/chunks/client-DfpLcAZ9.js +0 -24
  266. package/build/server/chunks/hooks.server-Rv301GTB.js.map +0 -1
  267. package/build/server/chunks/reconcile-Dv7jS3C8.js.map +0 -1
  268. /package/build/client/_app/immutable/assets/{9.nv0I59TU.css → 11.nv0I59TU.css} +0 -0
  269. /package/build/client/_app/immutable/assets/{9.nv0I59TU.css.br → 11.nv0I59TU.css.br} +0 -0
  270. /package/build/client/_app/immutable/assets/{9.nv0I59TU.css.gz → 11.nv0I59TU.css.gz} +0 -0
@@ -10,6 +10,8 @@
10
10
  import { projectsStore } from "$features/projects/presentation/stores/projectsStore.svelte";
11
11
  import { builderModeStore } from "$features/builder-mode/presentation/stores/builderModeStore.svelte";
12
12
  import { enabledViews, isEnabled } from "$lib/views/enabled";
13
+ import { themeStore } from "$lib/theme/themeStore.svelte";
14
+ import { ALL_THEMES } from "$lib/theme/registry";
13
15
  import { identityStore } from "$shared/identity/identityStore.svelte";
14
16
  import { authStore } from "$shared/security/authStore.svelte";
15
17
  import {
@@ -23,6 +25,10 @@
23
25
  // tries to read identityStore.author (notably the YDocClient
24
26
  // building its WebSocket URL). Idempotent on re-mount.
25
27
  identityStore.init();
28
+ // Mirror the active colour theme from the <html data-theme> attribute
29
+ // (server default + the inline head script's localStorage override) into
30
+ // reactive state so the header switcher and chrome track it live.
31
+ themeStore.init();
26
32
  // Hydrate the optional dashboard auth token the same way. When
27
33
  // unset, every API/SSE/WS request goes out unauthenticated; the
28
34
  // first 401 from the server triggers `apiFetch`'s prompt-and-retry
@@ -73,6 +79,8 @@
73
79
  let identityMenuRef = $state<HTMLDivElement | null>(null);
74
80
  let settingsMenuOpen = $state(false);
75
81
  let settingsMenuRef = $state<HTMLDivElement | null>(null);
82
+ let themeMenuOpen = $state(false);
83
+ let themeMenuRef = $state<HTMLDivElement | null>(null);
76
84
 
77
85
  function handleGlobalMouseDown(event: MouseEvent) {
78
86
  const target = event.target as Node;
@@ -90,6 +98,9 @@
90
98
  ) {
91
99
  settingsMenuOpen = false;
92
100
  }
101
+ if (themeMenuOpen && themeMenuRef && !themeMenuRef.contains(target)) {
102
+ themeMenuOpen = false;
103
+ }
93
104
  }
94
105
 
95
106
  async function pickRename() {
@@ -143,13 +154,25 @@
143
154
  // only when more than one view is active — a toggle between one thing is
144
155
  // meaningless. Builder is only "active" when it's both enabled and routed to.
145
156
  const views = $derived(enabledViews());
146
- const showViewSwitcher = $derived(views.length > 1);
157
+ // The Lyriks community edition presents a single, unswitched view, so hide
158
+ // the Expert/Builder switcher while that theme is active.
159
+ const showViewSwitcher = $derived(views.length > 1 && !themeStore.isLyriks);
147
160
  const builderActive = $derived(
148
161
  isEnabled("builder") && page.url.pathname.startsWith("/builder-mode"),
149
162
  );
150
163
  const mcpActive = $derived(page.url.pathname.startsWith("/mcp"));
151
- // Dark chrome while in Builder so the header matches the dark canvas.
152
- const dark = $derived(builderActive);
164
+ // The feature editor + graph use a wider 1600px content column than the rest
165
+ // of the app (max-w-7xl). Match the header container to whichever the current
166
+ // route uses, so the header always spans the same width as the content below.
167
+ const wideContent = $derived(page.url.pathname.startsWith("/features/"));
168
+ // The Lyriks theme paints the header with a saturated violet→fuchsia
169
+ // gradient (see below) and the shell with a cool canvas. Cosmetic only.
170
+ const lyriks = $derived(themeStore.isLyriks);
171
+ const themes = ALL_THEMES;
172
+ // Dark chrome while in Builder OR under the Lyriks gradient header, so the
173
+ // header's foreground (logo, icons, switcher) stays legible on a dark/vivid
174
+ // background. The dropdown panels keep their own white surface regardless.
175
+ const dark = $derived(builderActive || lyriks);
153
176
  const builderProject = $derived(
154
177
  builderActive ? builderModeStore.selectedProject : null,
155
178
  );
@@ -167,39 +190,65 @@
167
190
  if (e.key === "Escape") {
168
191
  identityMenuOpen = false;
169
192
  settingsMenuOpen = false;
193
+ themeMenuOpen = false;
170
194
  }
171
195
  }}
172
196
  />
173
197
 
174
198
  <div
175
- class="flex min-h-full flex-col bg-[linear-gradient(180deg,#f0fdfa_0%,#f8fafc_220px,#f8fafc_100%)] text-ink"
199
+ class="flex min-h-full flex-col text-ink {lyriks
200
+ ? 'bg-[linear-gradient(180deg,#e6ddfa_0%,#eeeafb_220px,#eeeafb_100%)]'
201
+ : 'bg-[linear-gradient(180deg,#f0fdfa_0%,#f8fafc_220px,#f8fafc_100%)]'}"
176
202
  >
177
203
  <header
178
- class="sticky top-0 z-30 border-b backdrop-blur transition-colors {dark
179
- ? 'border-slate-800 bg-slate-950/90'
180
- : 'border-slate-200 bg-white/95'}"
204
+ class="sticky top-0 z-30 border-b backdrop-blur transition-colors {lyriks
205
+ ? 'border-transparent bg-[linear-gradient(90deg,#6d28d9_0%,#a21caf_55%,#db2777_100%)]'
206
+ : dark
207
+ ? 'border-slate-800 bg-slate-950/90'
208
+ : 'border-slate-200 bg-white/95'}"
181
209
  >
182
210
  <div
183
- class="mx-auto flex h-16 max-w-6xl items-center justify-between px-4 sm:px-6"
211
+ class="mx-auto flex h-16 items-center justify-between px-4 sm:px-6 {wideContent
212
+ ? 'max-w-400'
213
+ : 'max-w-7xl'}"
184
214
  >
185
215
  <div class="flex min-w-0 items-center gap-3">
186
- <a href="/" class="flex shrink-0 items-center gap-2">
216
+ <a href="/" class="flex shrink-0 items-center gap-2.5">
187
217
  <img
188
- src="/unspaghettit_logo.png"
189
- alt="Unspaghettit"
190
- class="h-12 w-auto"
218
+ src={lyriks ? "/lyriks_logo.svg" : "/unspaghettit_logo.png"}
219
+ alt={lyriks ? "Lyriks" : "Unspaghettit"}
220
+ class={lyriks ? "h-9 w-9 shrink-0" : "h-12 w-auto"}
191
221
  />
192
- <span
193
- class="relative hidden font-brand text-3xl font-semibold leading-none sm:inline-block {dark
194
- ? 'text-white'
195
- : 'text-slate-950'}"
196
- >
197
- Unspaghettit
222
+ {#if lyriks}
223
+ <!-- Clean stacked lockup: wordmark with an aligned uppercase
224
+ edition label below (the old absolute subtitle overflowed
225
+ because "community edition" is wider than "Lyriks"). -->
226
+ <span class="hidden flex-col items-start leading-none sm:flex">
227
+ <span
228
+ class="font-brand text-2xl font-bold tracking-tight {dark
229
+ ? 'text-white'
230
+ : 'text-slate-950'}">Lyriks.io</span
231
+ >
232
+ <span
233
+ class="mt-1 pl-px text-[9px] font-semibold uppercase tracking-[0.18em] {dark
234
+ ? 'text-white/75'
235
+ : 'text-slate-500'}">Community Edition</span
236
+ >
237
+ </span>
238
+ {:else}
198
239
  <span
199
- class="font-grotesk absolute right-0 -bottom-2 text-[10px] font-medium tracking-wide text-slate-500"
200
- >by Lyriks.io</span
240
+ class="relative hidden font-brand text-3xl font-semibold leading-none sm:inline-block {dark
241
+ ? 'text-white'
242
+ : 'text-slate-950'}"
201
243
  >
202
- </span>
244
+ Unspaghettit
245
+ <span
246
+ class="font-grotesk absolute right-0 -bottom-2 text-[10px] font-medium tracking-wide {dark
247
+ ? 'text-white/70'
248
+ : 'text-slate-500'}">by Lyriks.io</span
249
+ >
250
+ </span>
251
+ {/if}
203
252
  </a>
204
253
  {#if showViewSwitcher}
205
254
  <div
@@ -287,6 +336,105 @@
287
336
  </div>
288
337
  {/if}
289
338
  <div class="flex shrink-0 items-center gap-1.5">
339
+ <div bind:this={themeMenuRef} class="relative">
340
+ <button
341
+ type="button"
342
+ onclick={() => {
343
+ themeMenuOpen = !themeMenuOpen;
344
+ settingsMenuOpen = false;
345
+ identityMenuOpen = false;
346
+ }}
347
+ aria-haspopup="menu"
348
+ aria-expanded={themeMenuOpen}
349
+ aria-label="Switch dashboard theme"
350
+ title="Switch theme"
351
+ class="grid h-9 w-9 place-items-center rounded-md transition {themeMenuOpen
352
+ ? lyriks
353
+ ? 'bg-white/30 text-white'
354
+ : dark
355
+ ? 'bg-slate-800 text-white'
356
+ : 'bg-slate-900 text-white'
357
+ : lyriks
358
+ ? 'bg-white/15 text-white hover:bg-white/25'
359
+ : dark
360
+ ? 'text-slate-300 hover:bg-white/10 hover:text-white'
361
+ : 'text-slate-600 hover:bg-slate-100 hover:text-slate-950'}"
362
+ >
363
+ <!-- Swatch / palette glyph: overlapping colour discs. -->
364
+ <svg
365
+ xmlns="http://www.w3.org/2000/svg"
366
+ viewBox="0 0 24 24"
367
+ fill="none"
368
+ stroke="currentColor"
369
+ stroke-width="1.6"
370
+ stroke-linecap="round"
371
+ stroke-linejoin="round"
372
+ class="h-5 w-5"
373
+ aria-hidden="true"
374
+ >
375
+ <circle cx="13.5" cy="6.5" r="2.5" />
376
+ <circle cx="17.5" cy="10.5" r="2.5" />
377
+ <circle cx="8.5" cy="7.5" r="2.5" />
378
+ <path
379
+ d="M12 21a9 9 0 1 1 0-18c4.97 0 9 3.58 9 8 0 2.5-2 3.5-3.5 3.5H15a2 2 0 0 0-1.4 3.42A1.5 1.5 0 0 1 12 21z"
380
+ />
381
+ </svg>
382
+ </button>
383
+ {#if themeMenuOpen}
384
+ <div
385
+ role="menu"
386
+ class="absolute right-0 top-12 z-40 w-64 overflow-hidden rounded-lg border border-slate-200 bg-white p-1 shadow-lg shadow-slate-950/10"
387
+ >
388
+ <p
389
+ class="px-3 pt-2 pb-1 text-[10px] font-semibold uppercase tracking-wide text-slate-400"
390
+ >
391
+ Theme
392
+ </p>
393
+ {#each themes as theme (theme.id)}
394
+ {@const active = themeStore.current === theme.id}
395
+ <button
396
+ type="button"
397
+ role="menuitemradio"
398
+ aria-checked={active}
399
+ onclick={() => {
400
+ themeStore.setTheme(theme.id);
401
+ themeMenuOpen = false;
402
+ }}
403
+ class="flex w-full items-center gap-3 rounded-md px-3 py-2 text-left text-sm {active
404
+ ? 'bg-slate-100 text-slate-950'
405
+ : 'text-slate-700 hover:bg-slate-50'}"
406
+ >
407
+ <span
408
+ class="h-5 w-5 shrink-0 rounded-full ring-1 ring-slate-950/10"
409
+ style="background: {theme.swatch}"
410
+ aria-hidden="true"
411
+ ></span>
412
+ <span class="min-w-0 flex-1">
413
+ <span class="block font-medium">{theme.label}</span>
414
+ <span class="block text-[11px] text-slate-500"
415
+ >{theme.description}</span
416
+ >
417
+ </span>
418
+ {#if active}
419
+ <svg
420
+ xmlns="http://www.w3.org/2000/svg"
421
+ viewBox="0 0 24 24"
422
+ fill="none"
423
+ stroke="currentColor"
424
+ stroke-width="2"
425
+ stroke-linecap="round"
426
+ stroke-linejoin="round"
427
+ class="h-4 w-4 shrink-0 text-brand-600"
428
+ aria-hidden="true"
429
+ >
430
+ <path d="M20 6 9 17l-5-5" />
431
+ </svg>
432
+ {/if}
433
+ </button>
434
+ {/each}
435
+ </div>
436
+ {/if}
437
+ </div>
290
438
  <div bind:this={settingsMenuRef} class="relative">
291
439
  <button
292
440
  type="button"
@@ -300,12 +448,16 @@
300
448
  title="App menu"
301
449
  class="grid h-9 w-9 place-items-center rounded-md transition {settingsMenuOpen ||
302
450
  mcpActive
303
- ? dark
304
- ? 'bg-slate-800 text-white'
305
- : 'bg-slate-900 text-white'
306
- : dark
307
- ? 'text-slate-400 hover:bg-slate-800 hover:text-white'
308
- : 'text-slate-600 hover:bg-slate-100 hover:text-slate-950'}"
451
+ ? lyriks
452
+ ? 'bg-white/30 text-white'
453
+ : dark
454
+ ? 'bg-slate-800 text-white'
455
+ : 'bg-slate-900 text-white'
456
+ : lyriks
457
+ ? 'bg-white/15 text-white hover:bg-white/25'
458
+ : dark
459
+ ? 'text-slate-400 hover:bg-slate-800 hover:text-white'
460
+ : 'text-slate-600 hover:bg-slate-100 hover:text-slate-950'}"
309
461
  >
310
462
  <svg
311
463
  xmlns="http://www.w3.org/2000/svg"
@@ -399,9 +551,11 @@
399
551
  href="/tutorial"
400
552
  aria-label="Help & tutorial"
401
553
  title="Help & tutorial"
402
- class="grid h-9 w-9 place-items-center rounded-md transition {dark
403
- ? 'text-slate-400 hover:bg-slate-800 hover:text-white'
404
- : 'text-slate-600 hover:bg-slate-100 hover:text-slate-950'}"
554
+ class="grid h-9 w-9 place-items-center rounded-md transition {lyriks
555
+ ? 'bg-white/15 text-white hover:bg-white/25'
556
+ : dark
557
+ ? 'text-slate-400 hover:bg-slate-800 hover:text-white'
558
+ : 'text-slate-600 hover:bg-slate-100 hover:text-slate-950'}"
405
559
  >
406
560
  <svg
407
561
  xmlns="http://www.w3.org/2000/svg"
@@ -0,0 +1,34 @@
1
+ <script lang="ts">
2
+ import { onMount } from 'svelte';
3
+ import { page } from '$app/stores';
4
+ import { asFeatureId } from '$features/behavior-model/domain/value-objects/ids';
5
+ import { featureStore } from '$features/behavior-model/presentation/stores/featureStore.svelte';
6
+ import { implementationStatusStore } from '$features/implementation-status/presentation/stores/implementationStatusStore.svelte';
7
+ import { projectContextStore } from '$features/projects/presentation/stores/projectContextStore.svelte';
8
+ import BehaviorGraph from '$features/behavior-model/presentation/components/BehaviorGraph.svelte';
9
+
10
+ onMount(() => {
11
+ const id = asFeatureId($page.params.id ?? '');
12
+ featureStore.load(id);
13
+ projectContextStore.load(id);
14
+ return () => {
15
+ featureStore.reset();
16
+ implementationStatusStore.reset();
17
+ projectContextStore.reset();
18
+ };
19
+ });
20
+ </script>
21
+
22
+ {#if featureStore.loading}
23
+ <div class="mx-auto max-w-7xl px-4 py-10 text-sm text-neutral-500">Loading...</div>
24
+ {:else if featureStore.error}
25
+ <div class="mx-auto max-w-7xl px-4 py-10 text-sm text-red-600">{featureStore.error}</div>
26
+ {:else if !featureStore.feature}
27
+ <div class="mx-auto max-w-7xl px-4 py-10 text-sm text-neutral-500">
28
+ Feature not found. <a href="/features" class="text-brand-700 underline">Back to list</a>.
29
+ </div>
30
+ {:else}
31
+ <main class="mx-auto max-w-[1600px] px-4 py-6">
32
+ <BehaviorGraph feature={featureStore.feature} />
33
+ </main>
34
+ {/if}
@@ -0,0 +1,79 @@
1
+ <script lang="ts">
2
+ import { onDestroy, onMount } from 'svelte';
3
+ import { page } from '$app/stores';
4
+ import { asFeatureId } from '$features/behavior-model/domain/value-objects/ids';
5
+ import BehaviorGraph from '$features/behavior-model/presentation/components/BehaviorGraph.svelte';
6
+ import { asProjectId } from '$features/projects/domain/value-objects/ids';
7
+ import { projectFeaturesStore } from '$features/projects/presentation/stores/projectFeaturesStore.svelte';
8
+ import { projectStore } from '$features/projects/presentation/stores/projectStore.svelte';
9
+ import { subscribeSyncEvents } from '$lib/client/sync/syncEvents';
10
+
11
+ let unsubscribeSync: (() => void) | null = null;
12
+ let graphDataReady = $state(false);
13
+
14
+ onMount(async () => {
15
+ const raw = $page.params.id;
16
+ if (!raw) return;
17
+ graphDataReady = false;
18
+ const id = asProjectId(raw);
19
+ await projectStore.load(id);
20
+ await projectFeaturesStore.loadAllSummaries();
21
+ if (projectStore.project) {
22
+ await projectFeaturesStore.load(projectStore.project.featureIds);
23
+ }
24
+ graphDataReady = true;
25
+ unsubscribeSync = subscribeSyncEvents(async (evt) => {
26
+ if (!projectStore.project) return;
27
+ if (evt.kind === 'project' && evt.id === String(id)) {
28
+ graphDataReady = false;
29
+ await projectFeaturesStore.syncWith(projectStore.project.featureIds);
30
+ graphDataReady = true;
31
+ } else if (evt.kind === 'feature') {
32
+ const ours = projectStore.project.featureIds.some((fid) => String(fid) === evt.id);
33
+ if (ours) {
34
+ await projectFeaturesStore.refetchOne(asFeatureId(evt.id));
35
+ } else {
36
+ await projectFeaturesStore.loadAllSummaries();
37
+ }
38
+ }
39
+ });
40
+ });
41
+
42
+ onDestroy(() => {
43
+ unsubscribeSync?.();
44
+ unsubscribeSync = null;
45
+ graphDataReady = false;
46
+ projectStore.reset();
47
+ projectFeaturesStore.reset();
48
+ });
49
+ </script>
50
+
51
+ <svelte:head>
52
+ <title>Project Graph / Unspaghettit</title>
53
+ </svelte:head>
54
+
55
+ {#if projectStore.loading}
56
+ <p class="mx-auto max-w-7xl px-4 py-10 text-sm text-neutral-500">Loading project...</p>
57
+ {:else if projectStore.error}
58
+ <p class="mx-auto max-w-7xl px-4 py-10 text-sm text-red-600">{projectStore.error}</p>
59
+ {:else if !projectStore.project}
60
+ <p class="mx-auto max-w-7xl px-4 py-10 text-sm text-neutral-500">
61
+ Project not found. <a href="/projects" class="text-brand-700 hover:underline">Back to projects</a>
62
+ </p>
63
+ {:else if projectFeaturesStore.loading || !graphDataReady}
64
+ <p class="mx-auto max-w-7xl px-4 py-10 text-sm text-neutral-500">Loading project features...</p>
65
+ {:else if projectFeaturesStore.error}
66
+ <p class="mx-auto max-w-7xl px-4 py-10 text-sm text-red-600">{projectFeaturesStore.error}</p>
67
+ {:else if projectStore.project.featureIds.length > 0 && projectFeaturesStore.features.length === 0}
68
+ <div class="mx-auto max-w-7xl px-4 py-10">
69
+ <p class="text-sm font-medium text-slate-900">No feature snapshots loaded for this project.</p>
70
+ <p class="mt-2 text-sm text-slate-600">
71
+ The project lists {projectStore.project.featureIds.length} feature{projectStore.project.featureIds.length === 1 ? '' : 's'},
72
+ but the graph could not load their behavior models from the shared hub.
73
+ </p>
74
+ </div>
75
+ {:else}
76
+ <main class="mx-auto max-w-[1800px] px-4 py-6">
77
+ <BehaviorGraph project={projectStore.project} features={projectFeaturesStore.features} />
78
+ </main>
79
+ {/if}
@@ -5,7 +5,7 @@
5
5
  * Designed to replace the "single flat colored fill" pattern that was
6
6
  * scattered across FeatureCard / MaturityPanel / FeatureHealthStrip.
7
7
  * Adds:
8
- * - tier-based color (red < 50%, amber < 80%, emerald ≥ 80%) when no
8
+ * - tier-based color (red < 50%, amber < 80%, emerald >= 80%) when no
9
9
  * explicit `color` is passed. The tier breakpoints match the
10
10
  * existing scorer thresholds so the visual identity stays in step
11
11
  * with the textual "critical / recommended" semantics.
@@ -3,6 +3,7 @@
3
3
  import { fly, fade } from 'svelte/transition';
4
4
  import { cubicOut } from 'svelte/easing';
5
5
  import { syncToastStore, type SyncToast } from './syncToastStore.svelte';
6
+ import { resolveViewLink } from './viewLinkResolver';
6
7
 
7
8
  onMount(() => {
8
9
  // Idempotent — starts the SSE subscription on first mount, no-ops on
@@ -89,6 +90,15 @@
89
90
  if (cleaned.length === 0) cleaned.push(toast.entityId);
90
91
  return cleaned;
91
92
  }
93
+
94
+ // The "View" target. Prefer the active view's own deep-link (e.g. the
95
+ // Builder, while it's open) so the user stays where they are; fall back to
96
+ // the default Expert route the toast was created with. Deletes carry no
97
+ // viewable target (the entity is gone).
98
+ function viewHref(toast: SyncToast): string | undefined {
99
+ if (toast.op === 'delete') return undefined;
100
+ return resolveViewLink(toast.kind, toast.entityId) ?? toast.href;
101
+ }
92
102
  </script>
93
103
 
94
104
  {#if syncToastStore.toasts.length > 0}
@@ -99,6 +109,7 @@
99
109
  >
100
110
  {#each syncToastStore.toasts as toast (toast.id)}
101
111
  {@const crumbs = breadcrumb(toast)}
112
+ {@const target = viewHref(toast)}
102
113
  <div
103
114
  class="pointer-events-auto flex items-start gap-3 rounded-lg border px-3 py-2 shadow-md shadow-slate-950/10 {kindAccent(toast.kind)}"
104
115
  in:fly={{ x: 24, duration: 180, easing: cubicOut }}
@@ -137,9 +148,9 @@
137
148
  {/if}
138
149
  </div>
139
150
  <div class="flex shrink-0 items-center gap-1">
140
- {#if toast.href}
151
+ {#if target}
141
152
  <a
142
- href={toast.href}
153
+ href={target}
143
154
  class="rounded-md bg-white/70 px-2 py-1 text-xs font-medium text-slate-700 hover:bg-white hover:text-brand-800"
144
155
  onclick={() => syncToastStore.dismiss(toast.id)}
145
156
  >
@@ -152,7 +163,7 @@
152
163
  onclick={() => syncToastStore.dismiss(toast.id)}
153
164
  aria-label="Dismiss"
154
165
  >
155
- ✕
166
+ &times;
156
167
  </button>
157
168
  </div>
158
169
  </div>
@@ -0,0 +1,32 @@
1
+ import type { SyncEvent } from '$lib/client/sync/syncEvents';
2
+
3
+ /**
4
+ * Lets the active view teach the activity-toast where its "View" button should
5
+ * point WITHOUT the shared toast layer importing any feature. A view (today the
6
+ * Builder) registers a resolver while it is mounted; the toast asks it for an
7
+ * in-view link to the changed entity first, and falls back to the default
8
+ * (Expert) route when the resolver returns null (entity not shown in that view)
9
+ * or no view is registered.
10
+ *
11
+ * Dependency inversion: the shared toast depends on this abstraction; the
12
+ * feature supplies the implementation — the same shape as the BuilderHost ports.
13
+ */
14
+ export type ViewLinkResolver = (kind: SyncEvent['kind'], id: string) => string | null;
15
+
16
+ let resolver: ViewLinkResolver | null = null;
17
+
18
+ /**
19
+ * Register the active view's resolver. Returns an unregister fn; calling it
20
+ * only clears the slot when it still holds THIS resolver, so a remount that
21
+ * registers a new one before the old view's cleanup runs isn't torn down.
22
+ */
23
+ export const registerViewLinkResolver = (next: ViewLinkResolver): (() => void) => {
24
+ resolver = next;
25
+ return () => {
26
+ if (resolver === next) resolver = null;
27
+ };
28
+ };
29
+
30
+ /** In-view link for the changed entity, or null to use the default route. */
31
+ export const resolveViewLink = (kind: SyncEvent['kind'], id: string): string | null =>
32
+ resolver ? resolver(kind, id) : null;
@@ -0,0 +1,148 @@
1
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
2
+ <!-- Created with Inkscape (http://www.inkscape.org/) -->
3
+
4
+ <svg
5
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
6
+ xmlns:cc="http://creativecommons.org/ns#"
7
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
8
+ xmlns:svg="http://www.w3.org/2000/svg"
9
+ xmlns="http://www.w3.org/2000/svg"
10
+ xmlns:xlink="http://www.w3.org/1999/xlink"
11
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
12
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
13
+ width="48"
14
+ height="48"
15
+ viewBox="0 0 12.7 12.7"
16
+ version="1.1"
17
+ id="svg8"
18
+ inkscape:version="0.92.3 (2405546, 2018-03-11)"
19
+ sodipodi:docname="lyriks-1.svg">
20
+ <defs
21
+ id="defs2">
22
+ <linearGradient
23
+ inkscape:collect="always"
24
+ id="linearGradient4618">
25
+ <stop
26
+ style="stop-color:#ffa101;stop-opacity:1;"
27
+ offset="0"
28
+ id="stop4614" />
29
+ <stop
30
+ style="stop-color:#ffa101;stop-opacity:0;"
31
+ offset="1"
32
+ id="stop4616" />
33
+ </linearGradient>
34
+ <linearGradient
35
+ inkscape:collect="always"
36
+ id="linearGradient4610">
37
+ <stop
38
+ style="stop-color:#bb46f5;stop-opacity:1;"
39
+ offset="0"
40
+ id="stop4606" />
41
+ <stop
42
+ style="stop-color:#bb46f5;stop-opacity:0;"
43
+ offset="1"
44
+ id="stop4608" />
45
+ </linearGradient>
46
+ <linearGradient
47
+ inkscape:collect="always"
48
+ id="linearGradient4602">
49
+ <stop
50
+ style="stop-color:#0066ff;stop-opacity:1;"
51
+ offset="0"
52
+ id="stop4598" />
53
+ <stop
54
+ style="stop-color:#0066ff;stop-opacity:0;"
55
+ offset="1"
56
+ id="stop4600" />
57
+ </linearGradient>
58
+ <linearGradient
59
+ inkscape:collect="always"
60
+ xlink:href="#linearGradient4602"
61
+ id="linearGradient4604"
62
+ x1="433.33047"
63
+ y1="223.41049"
64
+ x2="432.65369"
65
+ y2="484.82812"
66
+ gradientUnits="userSpaceOnUse"
67
+ gradientTransform="matrix(0.26458333,0,0,0.26458333,-82.110177,-99.957753)" />
68
+ <linearGradient
69
+ inkscape:collect="always"
70
+ xlink:href="#linearGradient4610"
71
+ id="linearGradient4612"
72
+ x1="432.83047"
73
+ y1="323.48856"
74
+ x2="433.53754"
75
+ y2="146.35829"
76
+ gradientUnits="userSpaceOnUse"
77
+ gradientTransform="matrix(0.26458333,0,0,0.26458333,-82.110177,-99.957753)" />
78
+ <linearGradient
79
+ inkscape:collect="always"
80
+ xlink:href="#linearGradient4618"
81
+ id="linearGradient4620"
82
+ x1="22.477682"
83
+ y1="34.598564"
84
+ x2="21.553013"
85
+ y2="86.671013"
86
+ gradientUnits="userSpaceOnUse"
87
+ gradientTransform="translate(12.832291,-41.407291)" />
88
+ </defs>
89
+ <sodipodi:namedview
90
+ id="base"
91
+ pagecolor="#ffffff"
92
+ bordercolor="#666666"
93
+ borderopacity="1.0"
94
+ inkscape:pageopacity="0.0"
95
+ inkscape:pageshadow="2"
96
+ inkscape:zoom="11.313708"
97
+ inkscape:cx="31.592839"
98
+ inkscape:cy="4.7086138"
99
+ inkscape:document-units="mm"
100
+ inkscape:current-layer="layer1"
101
+ showgrid="false"
102
+ inkscape:window-width="2560"
103
+ inkscape:window-height="1369"
104
+ inkscape:window-x="-8"
105
+ inkscape:window-y="-8"
106
+ inkscape:window-maximized="1"
107
+ inkscape:pagecheckerboard="false"
108
+ units="px" />
109
+ <metadata
110
+ id="metadata5">
111
+ <rdf:RDF>
112
+ <cc:Work
113
+ rdf:about="">
114
+ <dc:format>image/svg+xml</dc:format>
115
+ <dc:type
116
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
117
+ <dc:title></dc:title>
118
+ </cc:Work>
119
+ </rdf:RDF>
120
+ </metadata>
121
+ <g
122
+ inkscape:label="Calque 1"
123
+ inkscape:groupmode="layer"
124
+ id="layer1"
125
+ transform="translate(0,-284.3)">
126
+ <g
127
+ transform="matrix(0.43489873,0,0,0.40888801,-9.9205419,298.38648)"
128
+ id="g3740">
129
+ <rect
130
+ id="rect3742-2-8"
131
+ width="29.185829"
132
+ height="7.0625973"
133
+ x="22.823183"
134
+ y="-10.439077"
135
+ style="fill:url(#linearGradient4620);fill-opacity:1;stroke-width:0.29681981" />
136
+ <path
137
+ style="fill:url(#linearGradient4604);fill-opacity:1;stroke-width:0.09354433"
138
+ d="m 22.821255,-30.364151 v -4.069178 h 9.494747 9.494751 v 4.069178 4.069178 h -9.494751 -9.494747 z"
139
+ id="path3785"
140
+ inkscape:connector-curvature="0" />
141
+ <path
142
+ style="fill:url(#linearGradient4612);fill-opacity:1;stroke-width:0.09354433"
143
+ d="m 22.821255,-18.343704 v -4.022408 h 9.494747 9.494751 v 4.022408 4.022404 h -9.494751 -9.494747 z"
144
+ id="path3787"
145
+ inkscape:connector-curvature="0" />
146
+ </g>
147
+ </g>
148
+ </svg>