synthos 0.8.0 → 0.9.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 (359) hide show
  1. package/README.md +1 -1
  2. package/default-pages/application/page.html +42 -0
  3. package/default-pages/application/page.json +10 -0
  4. package/default-pages/elevenlabs_effects_studio/page.html +1363 -0
  5. package/default-pages/elevenlabs_effects_studio/page.json +11 -0
  6. package/default-pages/elevenlabs_voice_studio/page.html +801 -0
  7. package/default-pages/elevenlabs_voice_studio/page.json +11 -0
  8. package/default-pages/{json_tools.html → json_tools/page.html} +13 -11
  9. package/default-pages/json_tools/page.json +10 -0
  10. package/default-pages/my_notes/notes/a1b2c3d4-e5f6-7890-abcd-ef1234567890.json +5 -0
  11. package/default-pages/my_notes/page.html +132 -0
  12. package/default-pages/{my_notes.json → my_notes/page.json} +2 -2
  13. package/default-pages/neon_asteroids/files/Ambient_Space.mp3 +0 -0
  14. package/default-pages/neon_asteroids/files/Ambient_Space2.mp3 +0 -0
  15. package/default-pages/neon_asteroids/files/Ambient_Space3.mp3 +0 -0
  16. package/default-pages/neon_asteroids/files/Asteroid_Explosion.mp3 +0 -0
  17. package/default-pages/neon_asteroids/files/Hyperspace_Jump.mp3 +0 -0
  18. package/default-pages/neon_asteroids/files/Laser_Fire.mp3 +0 -0
  19. package/default-pages/neon_asteroids/files/Menu_Navigate.mp3 +0 -0
  20. package/default-pages/neon_asteroids/files/Power_Up_Collect.mp3 +0 -0
  21. package/default-pages/neon_asteroids/files/Saucer_Alert.mp3 +0 -0
  22. package/default-pages/neon_asteroids/files/Ship_Thrust.mp3 +0 -0
  23. package/default-pages/neon_asteroids/files/effects.json +74 -0
  24. package/default-pages/neon_asteroids/page.html +1822 -0
  25. package/default-pages/{neon_asteroids.json → neon_asteroids/page.json} +3 -3
  26. package/default-pages/{oregon_trail.html → oregon_trail/page.html} +14 -12
  27. package/default-pages/{oregon_trail.json → oregon_trail/page.json} +2 -2
  28. package/default-pages/retro_game_starter/page.html +1308 -0
  29. package/default-pages/retro_game_starter/page.json +12 -0
  30. package/default-pages/{sidebar_page.html → sidebar_page/page.html} +12 -10
  31. package/default-pages/sidebar_page/page.json +10 -0
  32. package/default-pages/{solar_explorer.html → solar_explorer/page.html} +14 -11
  33. package/default-pages/{solar_explorer.json → solar_explorer/page.json} +2 -2
  34. package/default-pages/{solar_tutorial.html → solar_tutorial/page.html} +12 -10
  35. package/default-pages/solar_tutorial/page.json +10 -0
  36. package/default-pages/{two-panel_page.html → two-panel_page/page.html} +13 -11
  37. package/default-pages/two-panel_page/page.json +10 -0
  38. package/default-pages/{us_map.html → us_map/page.html} +193 -192
  39. package/default-pages/{us_map.json → us_map/page.json} +12 -12
  40. package/default-pages/{us_map_1850.html → us_map_1850/page.html} +326 -325
  41. package/default-pages/{us_map_1850.json → us_map_1850/page.json} +12 -12
  42. package/default-pages/{western_cities_1850.html → western_cities_1850/page.html} +527 -526
  43. package/default-pages/{western_cities_1850.json → western_cities_1850/page.json} +12 -12
  44. package/default-themes/aurora-dawn.json +19 -0
  45. package/default-themes/aurora-dawn.v3.css +198 -0
  46. package/default-themes/aurora-dusk.json +19 -0
  47. package/default-themes/aurora-dusk.v3.css +200 -0
  48. package/default-themes/cosmos-dawn.json +19 -0
  49. package/default-themes/cosmos-dawn.v3.css +198 -0
  50. package/default-themes/cosmos-dusk.json +19 -0
  51. package/default-themes/cosmos-dusk.v3.css +200 -0
  52. package/default-themes/high-contrast-dark.json +19 -0
  53. package/default-themes/high-contrast-dark.v3.css +200 -0
  54. package/default-themes/high-contrast-light.json +19 -0
  55. package/default-themes/high-contrast-light.v3.css +198 -0
  56. package/default-themes/nebula-dawn.v2.css +110 -0
  57. package/default-themes/nebula-dawn.v3.css +199 -0
  58. package/default-themes/nebula-dusk.v2.css +104 -0
  59. package/default-themes/nebula-dusk.v3.css +201 -0
  60. package/default-themes/solar-flare-dawn.json +19 -0
  61. package/default-themes/solar-flare-dawn.v3.css +198 -0
  62. package/default-themes/solar-flare-dusk.json +19 -0
  63. package/default-themes/solar-flare-dusk.v3.css +200 -0
  64. package/dist/agents/index.d.ts +1 -1
  65. package/dist/agents/index.d.ts.map +1 -1
  66. package/dist/agents/index.js +2 -1
  67. package/dist/agents/index.js.map +1 -1
  68. package/dist/agents/openclaw/gatewayManager.d.ts +4 -0
  69. package/dist/agents/openclaw/gatewayManager.d.ts.map +1 -1
  70. package/dist/agents/openclaw/gatewayManager.js +27 -11
  71. package/dist/agents/openclaw/gatewayManager.js.map +1 -1
  72. package/dist/agents/openclaw/openclawProvider.d.ts.map +1 -1
  73. package/dist/agents/openclaw/openclawProvider.js +2 -4
  74. package/dist/agents/openclaw/openclawProvider.js.map +1 -1
  75. package/dist/agents/openclaw/sshTunnelManager.d.ts +2 -0
  76. package/dist/agents/openclaw/sshTunnelManager.d.ts.map +1 -1
  77. package/dist/agents/openclaw/sshTunnelManager.js +31 -12
  78. package/dist/agents/openclaw/sshTunnelManager.js.map +1 -1
  79. package/dist/builders/anthropic.d.ts +31 -0
  80. package/dist/builders/anthropic.d.ts.map +1 -0
  81. package/dist/builders/anthropic.js +227 -0
  82. package/dist/builders/anthropic.js.map +1 -0
  83. package/dist/builders/fireworksai.d.ts +9 -0
  84. package/dist/builders/fireworksai.d.ts.map +1 -0
  85. package/dist/builders/fireworksai.js +57 -0
  86. package/dist/builders/fireworksai.js.map +1 -0
  87. package/dist/builders/index.d.ts +13 -0
  88. package/dist/builders/index.d.ts.map +1 -0
  89. package/dist/builders/index.js +31 -0
  90. package/dist/builders/index.js.map +1 -0
  91. package/dist/builders/openai.d.ts +8 -0
  92. package/dist/builders/openai.d.ts.map +1 -0
  93. package/dist/builders/openai.js +87 -0
  94. package/dist/builders/openai.js.map +1 -0
  95. package/dist/builders/types.d.ts +54 -0
  96. package/dist/builders/types.d.ts.map +1 -0
  97. package/dist/builders/types.js +211 -0
  98. package/dist/builders/types.js.map +1 -0
  99. package/dist/connectors/index.d.ts.map +1 -1
  100. package/dist/connectors/index.js +3 -2
  101. package/dist/connectors/index.js.map +1 -1
  102. package/dist/connectors/registry.d.ts +2 -1
  103. package/dist/connectors/registry.d.ts.map +1 -1
  104. package/dist/connectors/registry.js +31 -8
  105. package/dist/connectors/registry.js.map +1 -1
  106. package/dist/customizer/Customizer.d.ts +57 -0
  107. package/dist/customizer/Customizer.d.ts.map +1 -0
  108. package/dist/customizer/Customizer.js +124 -0
  109. package/dist/customizer/Customizer.js.map +1 -0
  110. package/dist/customizer/index.d.ts.map +1 -0
  111. package/dist/customizer/index.js +9 -0
  112. package/dist/customizer/index.js.map +1 -0
  113. package/dist/files.d.ts +16 -0
  114. package/dist/files.d.ts.map +1 -1
  115. package/dist/files.js +60 -1
  116. package/dist/files.js.map +1 -1
  117. package/dist/index.d.ts.map +1 -1
  118. package/dist/index.js +1 -0
  119. package/dist/index.js.map +1 -1
  120. package/dist/init.d.ts +10 -6
  121. package/dist/init.d.ts.map +1 -1
  122. package/dist/init.js +96 -113
  123. package/dist/init.js.map +1 -1
  124. package/dist/migrations.d.ts.map +1 -1
  125. package/dist/migrations.js +23 -10
  126. package/dist/migrations.js.map +1 -1
  127. package/dist/models/anthropic.d.ts +4 -2
  128. package/dist/models/anthropic.d.ts.map +1 -1
  129. package/dist/models/anthropic.js +33 -6
  130. package/dist/models/anthropic.js.map +1 -1
  131. package/dist/models/fireworksai.d.ts.map +1 -1
  132. package/dist/models/fireworksai.js +9 -1
  133. package/dist/models/fireworksai.js.map +1 -1
  134. package/dist/models/index.d.ts +1 -1
  135. package/dist/models/index.d.ts.map +1 -1
  136. package/dist/models/index.js +2 -1
  137. package/dist/models/index.js.map +1 -1
  138. package/dist/models/openai.d.ts +1 -1
  139. package/dist/models/openai.d.ts.map +1 -1
  140. package/dist/models/openai.js +24 -3
  141. package/dist/models/openai.js.map +1 -1
  142. package/dist/models/types.d.ts +20 -1
  143. package/dist/models/types.d.ts.map +1 -1
  144. package/dist/models/types.js +6 -1
  145. package/dist/models/types.js.map +1 -1
  146. package/dist/pages.d.ts +30 -7
  147. package/dist/pages.d.ts.map +1 -1
  148. package/dist/pages.js +177 -55
  149. package/dist/pages.js.map +1 -1
  150. package/dist/service/server.d.ts.map +1 -1
  151. package/dist/service/server.js +37 -8
  152. package/dist/service/server.js.map +1 -1
  153. package/dist/service/transformPage.d.ts +47 -20
  154. package/dist/service/transformPage.d.ts.map +1 -1
  155. package/dist/service/transformPage.js +514 -293
  156. package/dist/service/transformPage.js.map +1 -1
  157. package/dist/service/useAgentRoutes.d.ts +2 -1
  158. package/dist/service/useAgentRoutes.d.ts.map +1 -1
  159. package/dist/service/useAgentRoutes.js +5 -2
  160. package/dist/service/useAgentRoutes.js.map +1 -1
  161. package/dist/service/useApiRoutes.d.ts.map +1 -1
  162. package/dist/service/useApiRoutes.js +237 -136
  163. package/dist/service/useApiRoutes.js.map +1 -1
  164. package/dist/service/useConnectorRoutes.js +6 -6
  165. package/dist/service/useConnectorRoutes.js.map +1 -1
  166. package/dist/service/useFileRoutes.d.ts +4 -0
  167. package/dist/service/useFileRoutes.d.ts.map +1 -0
  168. package/dist/service/useFileRoutes.js +122 -0
  169. package/dist/service/useFileRoutes.js.map +1 -0
  170. package/dist/service/usePageRoutes.d.ts.map +1 -1
  171. package/dist/service/usePageRoutes.js +648 -67
  172. package/dist/service/usePageRoutes.js.map +1 -1
  173. package/dist/service/useSharedDataRoutes.d.ts +4 -0
  174. package/dist/service/useSharedDataRoutes.d.ts.map +1 -0
  175. package/dist/service/useSharedDataRoutes.js +104 -0
  176. package/dist/service/useSharedDataRoutes.js.map +1 -0
  177. package/dist/service/useSharedFileRoutes.d.ts +4 -0
  178. package/dist/service/useSharedFileRoutes.d.ts.map +1 -0
  179. package/dist/service/useSharedFileRoutes.js +121 -0
  180. package/dist/service/useSharedFileRoutes.js.map +1 -0
  181. package/dist/settings.d.ts +1 -0
  182. package/dist/settings.d.ts.map +1 -1
  183. package/dist/settings.js +1 -0
  184. package/dist/settings.js.map +1 -1
  185. package/dist/synthos-cli.d.ts.map +1 -1
  186. package/dist/synthos-cli.js +4 -3
  187. package/dist/synthos-cli.js.map +1 -1
  188. package/dist/themes.d.ts +1 -0
  189. package/dist/themes.d.ts.map +1 -1
  190. package/dist/themes.js +28 -15
  191. package/dist/themes.js.map +1 -1
  192. package/migration-rules/v1-to-v2.md +193 -0
  193. package/migration-rules/v2-to-v3.md +481 -0
  194. package/package.json +11 -10
  195. package/required-pages/builder/page.html +43 -0
  196. package/required-pages/builder/page.json +10 -0
  197. package/required-pages/{pages.html → pages/page.html} +238 -233
  198. package/required-pages/pages/page.json +10 -0
  199. package/required-pages/{settings.html → settings/page.html} +389 -275
  200. package/required-pages/settings/page.json +10 -0
  201. package/required-pages/synthos_apis/page.html +846 -0
  202. package/required-pages/synthos_apis/page.json +10 -0
  203. package/required-pages/{synthos_scripts.html → synthos_scripts/page.html} +13 -11
  204. package/required-pages/synthos_scripts/page.json +10 -0
  205. package/src/agents/index.ts +1 -1
  206. package/src/agents/openclaw/gatewayManager.ts +22 -11
  207. package/src/agents/openclaw/openclawProvider.ts +2 -4
  208. package/src/agents/openclaw/sshTunnelManager.ts +19 -11
  209. package/src/builders/anthropic.ts +283 -0
  210. package/src/builders/fireworksai.ts +59 -0
  211. package/src/builders/index.ts +33 -0
  212. package/src/builders/openai.ts +89 -0
  213. package/src/builders/types.ts +261 -0
  214. package/src/connectors/index.ts +1 -1
  215. package/src/connectors/registry.ts +28 -8
  216. package/src/customizer/Customizer.ts +151 -0
  217. package/src/customizer/index.ts +5 -0
  218. package/src/files.ts +57 -0
  219. package/src/index.ts +2 -1
  220. package/src/init.ts +137 -123
  221. package/src/migrations.ts +30 -10
  222. package/src/models/anthropic.ts +40 -10
  223. package/src/models/fireworksai.ts +9 -2
  224. package/src/models/index.ts +1 -1
  225. package/src/models/openai.ts +26 -6
  226. package/src/models/types.ts +31 -1
  227. package/src/pages.ts +176 -54
  228. package/src/service/server.ts +36 -9
  229. package/src/service/transformPage.ts +557 -326
  230. package/src/service/useAgentRoutes.ts +7 -2
  231. package/src/service/useApiRoutes.ts +150 -41
  232. package/src/service/useConnectorRoutes.ts +7 -7
  233. package/src/service/useFileRoutes.ts +127 -0
  234. package/src/service/usePageRoutes.ts +720 -73
  235. package/src/service/useSharedDataRoutes.ts +106 -0
  236. package/src/service/useSharedFileRoutes.ts +126 -0
  237. package/src/settings.ts +2 -0
  238. package/src/synthos-cli.ts +4 -3
  239. package/src/themes.ts +25 -14
  240. package/static-files/favicon.svg +12 -0
  241. package/static-files/fluentlm-instructions.llmd +868 -0
  242. package/static-files/fluentlm-instructions.md +1595 -0
  243. package/static-files/fluentlm.css +4844 -0
  244. package/static-files/fluentlm.js +3602 -0
  245. package/static-files/fluentlm.min.css +1 -0
  246. package/static-files/fluentlm.min.js +1 -0
  247. package/{page-scripts/helpers-v2.js → static-files/helpers.v3.js} +82 -0
  248. package/static-files/page.v3.js +1290 -0
  249. package/static-files/recommended-frameworks.llmd +81 -0
  250. package/static-files/recommended-frameworks.md +137 -0
  251. package/static-files/retro-game.js +877 -0
  252. package/static-files/shell.css +797 -0
  253. package/static-files/theme-dark.css +169 -0
  254. package/static-files/theme-light.css +169 -0
  255. package/tests/builders.spec.ts +139 -0
  256. package/tests/pages.spec.ts +8 -8
  257. package/tests/transformPage.spec.ts +299 -360
  258. package/default-pages/application.html +0 -40
  259. package/default-pages/application.json +0 -1
  260. package/default-pages/json_tools.json +0 -1
  261. package/default-pages/my_notes.html +0 -33
  262. package/default-pages/neon_asteroids.html +0 -77
  263. package/default-pages/sidebar_page.json +0 -1
  264. package/default-pages/solar_tutorial.json +0 -1
  265. package/default-pages/two-panel_page.json +0 -1
  266. package/dist/agents/a2a/a2aProvider.d.ts +0 -3
  267. package/dist/agents/discovery.d.ts +0 -30
  268. package/dist/agents/openclaw/openclawProvider.d.ts +0 -3
  269. package/dist/agents/types.d.ts +0 -64
  270. package/dist/connectors/index.d.ts +0 -3
  271. package/dist/connectors/types.d.ts +0 -84
  272. package/dist/index.d.ts +0 -7
  273. package/dist/migrations.d.ts +0 -12
  274. package/dist/models/chainOfThought.d.ts +0 -12
  275. package/dist/models/fireworksai.d.ts +0 -30
  276. package/dist/models/logCompletePrompt.d.ts +0 -3
  277. package/dist/models/providers.d.ts +0 -8
  278. package/dist/models/utils.d.ts +0 -6
  279. package/dist/scripts.d.ts +0 -15
  280. package/dist/service/createCompletePrompt.d.ts +0 -5
  281. package/dist/service/debugLog.d.ts +0 -11
  282. package/dist/service/generateImage.d.ts +0 -32
  283. package/dist/service/index.d.ts +0 -8
  284. package/dist/service/modelInstructions.d.ts +0 -7
  285. package/dist/service/requiresSettings.d.ts +0 -3
  286. package/dist/service/server.d.ts +0 -4
  287. package/dist/service/useApiRoutes.d.ts +0 -4
  288. package/dist/service/useConnectorRoutes.d.ts +0 -4
  289. package/dist/service/useDataRoutes.d.ts +0 -4
  290. package/dist/service/useGatewayRoutes.d.ts +0 -4
  291. package/dist/service/useGatewayRoutes.d.ts.map +0 -1
  292. package/dist/service/useGatewayRoutes.js +0 -168
  293. package/dist/service/useGatewayRoutes.js.map +0 -1
  294. package/dist/service/usePageRoutes.d.ts +0 -5
  295. package/dist/synthos-cli.d.ts +0 -2
  296. package/page-scripts/page-v2.js +0 -656
  297. package/required-pages/builder.html +0 -48
  298. package/required-pages/builder.json +0 -1
  299. package/required-pages/pages.json +0 -1
  300. package/required-pages/settings.json +0 -1
  301. package/required-pages/synthos_apis.html +0 -327
  302. package/required-pages/synthos_apis.json +0 -1
  303. package/required-pages/synthos_scripts.json +0 -1
  304. package/src/connectors/airtable/connector.json +0 -27
  305. package/src/connectors/alpha-vantage/connector.json +0 -26
  306. package/src/connectors/brave-search/connector.json +0 -26
  307. package/src/connectors/cloudinary/connector.json +0 -27
  308. package/src/connectors/deepl/connector.json +0 -28
  309. package/src/connectors/elevenlabs/connector.json +0 -30
  310. package/src/connectors/giphy/connector.json +0 -27
  311. package/src/connectors/github/connector.json +0 -29
  312. package/src/connectors/huggingface/connector.json +0 -27
  313. package/src/connectors/imgur/connector.json +0 -29
  314. package/src/connectors/instagram/connector.json +0 -43
  315. package/src/connectors/jira/connector.json +0 -28
  316. package/src/connectors/mapbox/connector.json +0 -26
  317. package/src/connectors/nasa/connector.json +0 -27
  318. package/src/connectors/newsapi/connector.json +0 -27
  319. package/src/connectors/notion/connector.json +0 -28
  320. package/src/connectors/open-exchange-rates/connector.json +0 -27
  321. package/src/connectors/openweathermap/connector.json +0 -26
  322. package/src/connectors/pexels/connector.json +0 -27
  323. package/src/connectors/resend/connector.json +0 -29
  324. package/src/connectors/rss2json/connector.json +0 -27
  325. package/src/connectors/sendgrid/connector.json +0 -27
  326. package/src/connectors/spoonacular/connector.json +0 -28
  327. package/src/connectors/stability-ai/connector.json +0 -27
  328. package/src/connectors/twilio/connector.json +0 -28
  329. package/src/connectors/unsplash/connector.json +0 -27
  330. package/src/connectors/wolfram-alpha/connector.json +0 -26
  331. package/src/connectors/youtube-data/connector.json +0 -30
  332. /package/{dist/connectors → service-connectors}/airtable/connector.json +0 -0
  333. /package/{dist/connectors → service-connectors}/alpha-vantage/connector.json +0 -0
  334. /package/{dist/connectors → service-connectors}/brave-search/connector.json +0 -0
  335. /package/{dist/connectors → service-connectors}/cloudinary/connector.json +0 -0
  336. /package/{dist/connectors → service-connectors}/deepl/connector.json +0 -0
  337. /package/{dist/connectors → service-connectors}/elevenlabs/connector.json +0 -0
  338. /package/{dist/connectors → service-connectors}/giphy/connector.json +0 -0
  339. /package/{dist/connectors → service-connectors}/github/connector.json +0 -0
  340. /package/{dist/connectors → service-connectors}/huggingface/connector.json +0 -0
  341. /package/{dist/connectors → service-connectors}/imgur/connector.json +0 -0
  342. /package/{dist/connectors → service-connectors}/instagram/connector.json +0 -0
  343. /package/{dist/connectors → service-connectors}/jira/connector.json +0 -0
  344. /package/{dist/connectors → service-connectors}/mapbox/connector.json +0 -0
  345. /package/{dist/connectors → service-connectors}/nasa/connector.json +0 -0
  346. /package/{dist/connectors → service-connectors}/newsapi/connector.json +0 -0
  347. /package/{dist/connectors → service-connectors}/notion/connector.json +0 -0
  348. /package/{dist/connectors → service-connectors}/open-exchange-rates/connector.json +0 -0
  349. /package/{dist/connectors → service-connectors}/openweathermap/connector.json +0 -0
  350. /package/{dist/connectors → service-connectors}/pexels/connector.json +0 -0
  351. /package/{dist/connectors → service-connectors}/resend/connector.json +0 -0
  352. /package/{dist/connectors → service-connectors}/rss2json/connector.json +0 -0
  353. /package/{dist/connectors → service-connectors}/sendgrid/connector.json +0 -0
  354. /package/{dist/connectors → service-connectors}/spoonacular/connector.json +0 -0
  355. /package/{dist/connectors → service-connectors}/stability-ai/connector.json +0 -0
  356. /package/{dist/connectors → service-connectors}/twilio/connector.json +0 -0
  357. /package/{dist/connectors → service-connectors}/unsplash/connector.json +0 -0
  358. /package/{dist/connectors → service-connectors}/wolfram-alpha/connector.json +0 -0
  359. /package/{dist/connectors → service-connectors}/youtube-data/connector.json +0 -0
@@ -5,229 +5,208 @@
5
5
  <script id="theme-info" src="/api/theme-info.js" data-locked="true"></script>
6
6
  <link id="theme-css" rel="stylesheet" href="/api/theme.css" data-locked="true">
7
7
  <style>
8
- /* Advanced options */
9
- .advanced-options { margin-top: 8px }
10
- .advanced-toggle { background: 0 0; border: none; color: var(--text-secondary); font-size: 13px; cursor: pointer; padding: 8px 0; display: flex; align-items: center; gap: 6px; transition: color .2s }
11
- .advanced-toggle:hover { color: var(--accent-primary) }
12
- .toggle-icon { font-size: 10px; transition: transform .2s }
13
- .toggle-icon.open { transform: rotate(90deg) }
14
- .advanced-content { padding-left: 16px; border-left: 2px solid var(--border-color); margin-left: 4px }
15
-
16
- /* Header */
17
- .saved-pages { font-size: 22px; font-weight: 700; min-height: var(--header-min-height); padding: var(--header-padding-vertical) var(--header-padding-horizontal); line-height: var(--header-line-height); display: flex; align-items: center; justify-content: center; box-sizing: border-box; background: linear-gradient(135deg, var(--accent-primary), var(--accent-secondary)); color: #fff; border-radius: 12px; width: 100%; box-shadow: 0 6px 25px var(--accent-glow); position: relative; z-index: 1; margin-bottom: 20px }
18
-
19
- /* Category sections */
20
- .page-category { width: 100%; margin-bottom: 20px; position: relative; z-index: 1 }
21
- .category-title { font-size: 16px; color: var(--text-secondary); margin-bottom: 12px; padding-left: 5px; border-left: 3px solid var(--accent-tertiary) }
22
- .page-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: 12px }
23
-
24
- /* Page links */
25
- .page-link { padding: 12px 16px; background: linear-gradient(135deg, rgba(102,126,234,.15) 0, rgba(118,75,162,.15) 100%); border: 1px solid var(--border-color); border-radius: 10px; color: var(--text-primary); text-decoration: none; text-align: center; font-size: 14px; transition: .3s; cursor: pointer; user-select: none; white-space: nowrap; overflow: hidden; position: relative }
26
- .page-link:hover { background: linear-gradient(135deg, rgba(102,126,234,.3) 0, rgba(118,75,162,.3) 100%); border-color: var(--text-secondary); box-shadow: 0 4px 15px var(--accent-glow); color: var(--accent-tertiary); transform: translateY(-2px) }
27
- .page-link .scroll-text { display: inline-block; white-space: nowrap; max-width: 100%; overflow: hidden; text-overflow: ellipsis }
28
- .page-link.scrolling .scroll-text { text-overflow: clip; overflow: visible; animation: scrollText var(--scroll-duration, 3s) linear infinite }
29
- @keyframes scrollText { 0%, 10% { transform: translateX(0) } 100%, 90% { transform: translateX(var(--scroll-distance, -50%)) } }
30
-
31
- /* Pinned pages */
32
- .page-link.pinned { background: linear-gradient(135deg, rgba(102,126,234,.35) 0, rgba(118,75,162,.35) 100%); border: 2px solid var(--accent-tertiary); box-shadow: 0 2px 12px var(--accent-glow) }
33
- .page-link.pinned:hover { background: linear-gradient(135deg, rgba(102,126,234,.5) 0, rgba(118,75,162,.5) 100%); box-shadow: 0 4px 20px var(--accent-glow) }
34
-
35
- /* Builder page */
36
- .page-link.builder-page { background: linear-gradient(135deg, var(--accent-primary), var(--accent-secondary)); color: #fff; border: none; box-shadow: 0 4px 20px var(--accent-glow); font-weight: 600 }
37
- .page-link.builder-page:hover { background: linear-gradient(135deg, var(--accent-primary), var(--accent-secondary)); filter: brightness(1.1); box-shadow: 0 6px 25px var(--accent-glow); color: #fff; transform: translateY(-2px) }
38
-
39
- /* Light mode pinned overrides */
40
- .light-mode .page-link.pinned { background: linear-gradient(135deg, rgba(102,126,234,.3) 0, rgba(192,84,212,.25) 100%); border-color: var(--accent-secondary) }
41
- .light-mode .page-link.pinned:hover { background: linear-gradient(135deg, rgba(102,126,234,.45) 0, rgba(192,84,212,.4) 100%) }
42
-
43
- /* Filter bar */
44
- .filter-bar { display: flex; align-items: center; gap: 8px; margin-bottom: 16px; flex-wrap: nowrap }
45
- .filter-buttons-container { display: flex; gap: 8px; flex-shrink: 1; min-width: 0; overflow: hidden }
46
- .filter-btn { padding: 6px 14px; border-radius: 20px; border: 1px solid var(--border-color); background: 0 0; color: var(--text-secondary); font-size: 13px; cursor: pointer; transition: .2s; white-space: nowrap; flex-shrink: 0 }
47
- .filter-btn:hover { border-color: var(--accent-primary); color: var(--accent-primary) }
48
- .filter-btn.active { background: linear-gradient(135deg, var(--accent-primary), var(--accent-secondary)); color: #fff; border-color: transparent }
49
-
50
- /* More dropdown */
51
- .more-dropdown { position: relative; flex-shrink: 0 }
52
- .more-btn { position: relative }
53
- .more-menu { position: absolute; top: 100%; left: 0; margin-top: 4px; min-width: 150px; max-height: 250px; overflow-y: auto; border-radius: 8px; padding: 4px 0; box-shadow: 0 8px 30px rgba(0,0,0,.4); display: none; border: 1px solid var(--border-color); background: rgba(30,30,50,.95); z-index: 100 }
54
- .more-menu.show { display: block }
55
- .more-menu-item { padding: 8px 16px; font-size: 13px; cursor: pointer; color: var(--text-primary); transition: background .15s; white-space: nowrap }
56
- .more-menu-item:hover { background: linear-gradient(135deg, rgba(102,126,234,.3) 0, rgba(118,75,162,.3) 100%) }
57
- .more-menu-item.active { background: linear-gradient(135deg, rgba(102,126,234,.2) 0, rgba(118,75,162,.2) 100%); color: var(--accent-tertiary) }
58
-
59
- /* Search */
60
- .search-input { margin-left: auto; padding: 6px 12px; border-radius: 20px; border: 1px solid var(--border-color); background: 0 0; color: var(--text-primary); font-size: 13px; outline: 0; width: 180px; min-width: 120px; flex-shrink: 0; transition: border-color .2s }
61
- .search-input:focus { border-color: var(--accent-primary) }
62
- .search-input::placeholder { color: var(--text-secondary) }
63
-
64
- /* Context menu */
65
- .context-menu { position: fixed; z-index: 1000; min-width: 180px; border-radius: 8px; padding: 4px 0; box-shadow: 0 8px 30px rgba(0,0,0,.4); display: none; border: 1px solid var(--border-color); background: rgba(30,30,50,.95) }
66
- .context-menu-item { padding: 8px 16px; font-size: 13px; cursor: pointer; color: var(--text-primary); transition: background .15s }
67
- .context-menu-item:hover { background: linear-gradient(135deg, rgba(102,126,234,.3) 0, rgba(118,75,162,.3) 100%) }
68
- .light-mode .context-menu, .light-mode .more-menu { background: rgba(255,255,255,.97); box-shadow: 0 8px 30px rgba(0,0,0,.15) }
69
-
70
- /* Upgrade badge & toast */
71
- .version-badge { display: block; font-size: 10px; color: var(--accent-tertiary); margin-top: 4px; opacity: .8 }
72
- .page-link.needs-upgrade { border: 1px dashed var(--accent-tertiary); background: linear-gradient(135deg, rgba(102,126,234,.08) 0, rgba(118,75,162,.08) 100%); animation: 3s ease-in-out infinite upgradeGlow; overflow: visible; z-index: 2 }
73
- .page-link.needs-upgrade:hover { background: linear-gradient(135deg, rgba(102,126,234,.2) 0, rgba(118,75,162,.2) 100%); border-color: var(--accent-primary) }
74
- @keyframes upgradeGlow { 0%, 100% { box-shadow: 0 0 0 transparent } 50% { box-shadow: 0 0 12px var(--accent-glow) } }
75
- .upgrade-badge { position: absolute; top: -6px; right: -6px; font-size: 9px; color: #fff; font-weight: 600; background: linear-gradient(135deg, var(--accent-primary), var(--accent-secondary)); padding: 2px 7px; border-radius: 10px; line-height: 1.3; box-shadow: 0 2px 8px var(--accent-glow); pointer-events: none; z-index: 10 }
76
- .light-mode .page-link.needs-upgrade { background: linear-gradient(135deg, rgba(102,126,234,.06) 0, rgba(192,84,212,.06) 100%) }
77
- .upgrade-toast { position: fixed; bottom: 20px; right: 20px; padding: 12px 20px; background: linear-gradient(135deg, var(--accent-primary), var(--accent-secondary)); color: #fff; border-radius: 8px; font-size: 13px; box-shadow: 0 4px 15px var(--accent-glow); z-index: 2000; opacity: 0; transform: translateY(10px); transition: opacity .3s, transform .3s }
78
- .upgrade-toast.show { opacity: 1; transform: translateY(0) }
8
+ /* Layout-specific rules only — all component styling via FluentLM */
9
+ #pagesBtn { opacity: 0.4; pointer-events: none; }
10
+ .page-grid { display: flex; flex-wrap: wrap; gap: 12px; }
11
+ .page-btn { display: flex; align-items: center; justify-content: center; min-width: 120px; height: 20px; padding: 10px 14px; border-radius: 12px; border: 1px solid var(--neutralLight); background: var(--defaultStateBackground); color: var(--bodyText); font-size: 14px; cursor: pointer; text-decoration: none; position: relative; transition: background .2s, border-color .2s, box-shadow .2s, transform .15s; overflow: hidden; box-sizing: content-box; }
12
+ .page-btn:hover { background: var(--defaultHoverBackground); border-color: var(--themePrimary); box-shadow: 0 4px 12px rgba(0,0,0,.1); transform: translateY(-1px); }
13
+ .page-btn .btn-label { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; text-align: center; }
14
+ .page-btn.scrolling .btn-label { text-overflow: clip; overflow: visible; }
15
+ .page-btn.scrolling .scroll-text { animation: scrollText var(--scroll-duration, 3s) linear infinite; display: inline-block; }
16
+ @keyframes scrollText { 0%, 10% { transform: translateX(0) } 90%, 100% { transform: translateX(var(--scroll-distance, -50%)) } }
17
+ .page-btn.builder-page { background: linear-gradient(135deg, var(--themePrimary), var(--themeDarkAlt)); color: #fff; border: none; font-weight: 600; box-shadow: 0 4px 16px var(--themeLighter); }
18
+ .page-btn.builder-page:hover { filter: brightness(1.1); box-shadow: 0 6px 20px var(--themeLighter); }
19
+ .page-btn.pinned { border: 2px solid var(--themePrimary); box-shadow: 0 2px 8px var(--themeLighter); }
20
+ .page-btn.needs-upgrade { border: 1px dashed var(--themePrimary); animation: 3s ease-in-out infinite upgradeGlow; overflow: visible; }
21
+ @keyframes upgradeGlow { 0%, 100% { box-shadow: none } 50% { box-shadow: 0 0 12px var(--themeLighter) } }
22
+ .upgrade-badge { position: absolute; top: -6px; right: -6px; font-size: 9px; color: #fff; font-weight: 600; background: linear-gradient(135deg, var(--themePrimary), var(--themeDarkAlt)); padding: 2px 7px; border-radius: 10px; line-height: 1.3; box-shadow: 0 2px 8px var(--themeLighter); pointer-events: none; z-index: 10; }
23
+ .toast-fixed { position: fixed; bottom: 20px; right: 20px; z-index: 2000; max-width: 360px; opacity: 0; transform: translateY(10px); transition: opacity .3s, transform .3s; pointer-events: none; }
24
+ .toast-fixed.show { opacity: 1; transform: translateY(0); pointer-events: auto; }
25
+ .advanced-options { margin-top: 8px; }
26
+ .advanced-toggle { background: none; border: none; color: var(--bodySubtext); font-size: 13px; cursor: pointer; padding: 8px 0; display: flex; align-items: center; gap: 6px; }
27
+ .advanced-toggle:hover { color: var(--themePrimary); }
28
+ .toggle-icon { font-size: 10px; transition: transform .2s; }
29
+ .toggle-icon.open { transform: rotate(90deg); }
30
+ .advanced-content { padding-left: 16px; border-left: 2px solid var(--neutralLight); margin-left: 4px; }
31
+ .filter-toolbar { display: flex; align-items: center; gap: var(--spacingS1); }
32
+ .filter-toolbar .flm-pivot { flex: 1; min-width: 0; overflow: hidden; }
33
+ .filter-toolbar .flm-pivot-tabs { flex-wrap: nowrap; overflow: hidden; }
34
+ .filter-toolbar .flm-searchbox { flex-shrink: 0; width: 200px; }
35
+ .more-dropdown { position: relative; flex-shrink: 0; }
36
+ .more-menu { position: absolute; top: 100%; left: 0; margin-top: 4px; min-width: 150px; max-height: 250px; overflow-y: auto; display: none; z-index: 100; }
37
+ .more-menu.show { display: block; }
79
38
  </style>
80
39
  <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/7.9.0/d3.min.js"></script>
81
40
  <script src="https://cdnjs.cloudflare.com/ajax/libs/marked/14.1.1/marked.min.js"></script>
82
41
  <script src="https://cdnjs.cloudflare.com/ajax/libs/mermaid/11.1.0/mermaid.min.js"></script>
42
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js"></script>
83
43
  <script id="page-info" src="/api/page-info.js?page=pages2"></script>
84
44
  </head>
85
45
 
86
46
  <body>
47
+ <div class="shell-toolbar" data-locked="true">
48
+ <button class="shell-toolbar-btn" id="builderToggle" aria-label="Page Builder" data-locked="true"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"><path d="M7 18.5H6.2c-1.77 0-3.2-1.43-3.2-3.2V7.7C3 5.93 4.43 4.5 6.2 4.5h11.6c1.77 0 3.2 1.43 3.2 3.2v7.6c0 1.77-1.43 3.2-3.2 3.2H12l-4.2 3.2c-.5.38-1.2.02-1.2-.6V18.5Z" stroke="currentColor" stroke-width="1.8" stroke-linejoin="round"/><circle cx="8.5" cy="11.5" r="1" fill="currentColor"/><circle cx="12" cy="11.5" r="1" fill="currentColor"/><circle cx="15.5" cy="11.5" r="1" fill="currentColor"/></svg></button>
49
+ <button class="shell-toolbar-btn" id="pagesBtn" aria-label="View All Pages" data-locked="true"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" fill="none"><rect x="3" y="3" width="11" height="12" rx="1.5" stroke="currentColor" stroke-width="1.8" stroke-linejoin="round"/><path d="M6 7.5h5M6 10h3" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/><rect x="18" y="3" width="11" height="12" rx="1.5" stroke="currentColor" stroke-width="1.8" stroke-linejoin="round"/><path d="M21 7.5h5M21 10h3" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/><rect x="3" y="18" width="11" height="12" rx="1.5" stroke="currentColor" stroke-width="1.8" stroke-linejoin="round"/><path d="M6 22.5h5M6 25h3" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/><rect x="18" y="18" width="11" height="12" rx="1.5" stroke="currentColor" stroke-width="1.8" stroke-linejoin="round"/><path d="M21 22.5h5M21 25h3" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg></button>
50
+ <button class="shell-toolbar-btn" id="saveBtn" aria-label="Save Page" data-locked="true"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"><path d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2Z" stroke="currentColor" stroke-width="1.8" stroke-linejoin="round"/><path d="M17 21v-8H7v8" stroke="currentColor" stroke-width="1.8" stroke-linejoin="round"/><path d="M7 3v5h8" stroke="currentColor" stroke-width="1.8" stroke-linejoin="round"/></svg></button>
51
+ <div class="shell-toolbar-spacer" data-locked="true"></div>
52
+ <button class="shell-toolbar-btn" id="settingsBtn" aria-label="Settings" data-locked="true"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"><path d="M12 15a3 3 0 1 0 0-6 3 3 0 0 0 0 6Z" stroke="currentColor" stroke-width="1.8"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 1 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 1 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 1 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 1 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1Z" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg></button>
53
+ </div>
87
54
  <div class="chat-panel" data-locked="true">
88
- <div class="chat-header" data-locked="true">SynthOS</div>
55
+ <div class="chat-header" data-locked="true"><span>Page Builder</span><button class="chat-header-close" id="builderClose" aria-label="Close builder" data-locked="true">&times;</button></div>
89
56
  <div class="chat-messages" id="chatMessages" data-locked="true">
90
57
  <div class="chat-message">
91
58
  <p><strong>SynthOS:</strong> Here are all of the created pages. Right-click any page to pin it to
92
59
  favorites, edit its definition, or copy it to a new page.</p>
93
60
  </div>
94
- </div>
95
- <div class="link-group" data-locked="true">
96
- <a href="#" id="saveLink" data-locked="true">Save</a>
97
- <a href="/pages" id="pagesLink" data-locked="true">Pages</a>
98
- <a href="#" id="resetLink" data-locked="true">Reset</a>
99
- </div>
61
+ </div>
100
62
  <form action="/" method="POST" id="chatForm" data-locked="true">
101
- <input type="text" class="chat-input" id="chatInput" name="message" placeholder="Type a message..." data-locked="true">
102
- <button type="submit" class="chat-submit" data-locked="true">Send</button>
63
+ <textarea class="chat-input" id="chatInput" name="message" rows="2" placeholder="Type a message..." data-locked="true"></textarea>
103
64
  </form>
104
65
  </div>
105
66
  <div class="viewer-panel" id="viewerPanel" style="justify-content: flex-start; align-items: stretch;">
106
- <div class="saved-pages">Pages<button id="importBtn" style="position: absolute; right: 16px; padding: 4px 14px; border-radius: 8px; border: 1px solid rgba(255,255,255,.3); background: rgba(255,255,255,.15); color: #fff; font-size: 13px; cursor: pointer; transition: background .2s; line-height: 1.4;" onmouseover="this.style.background='rgba(255,255,255,.3)'" onmouseout="this.style.background='rgba(255,255,255,.15)'">Import</button></div>
107
- <input type="file" id="importFileInput" accept=".zip" style="display:none">
108
-
109
- <!-- Favorites section (hidden when empty) -->
110
- <div id="favoritesSection" class="page-category" style="display: none;">
111
- <h2 class="category-title">Favorites</h2>
112
- <div id="favoritesGrid" class="page-grid"></div>
113
- </div>
67
+ <div class="flm-stack" style="gap: var(--spacingM); height: 100%; padding: var(--spacingM);">
68
+ <!-- Header row -->
69
+ <div class="flm-stack flm-stack--horizontal flm-stack--space-between" style="align-items: center;">
70
+ <span class="flm-text flm-text--xLarge flm-text--bold">Pages</span>
71
+ <div class="flm-stack flm-stack--horizontal" style="gap: var(--spacingS1);">
72
+ <button class="flm-button" data-icon="Upload" id="importBtn">Import</button>
73
+ </div>
74
+ </div>
75
+ <input type="file" id="importFileInput" accept=".zip" style="display:none">
114
76
 
115
- <!-- All Pages section with filter bar -->
116
- <div class="page-category">
117
- <h2 class="category-title">Pages</h2>
118
- <div id="filterBar" class="filter-bar">
119
- <div class="filter-buttons-container">
120
- <button class="filter-btn active" data-category="All">All</button>
77
+ <!-- Toolbar row: pivot tabs + search -->
78
+ <div class="filter-toolbar" id="filterBar">
79
+ <div class="flm-pivot flm-pivot--tabs" id="categoryPivot">
80
+ <div class="flm-pivot-tabs" role="tablist" id="categoryTabs">
81
+ <button class="flm-pivot-tab flm-pivot-tab--active" data-category="All" role="tab">All</button>
82
+ </div>
121
83
  </div>
122
84
  <div class="more-dropdown" id="moreDropdown" style="display: none;">
123
- <button class="filter-btn more-btn" id="moreBtn">More ▾</button>
124
- <div class="more-menu" id="moreMenu"></div>
85
+ <button class="flm-button flm-button--subtle" id="moreBtn">More <i class="flm-icon" data-icon="ChevronDown"></i></button>
86
+ <div class="flm-contextmenu more-menu" id="moreMenu"></div>
87
+ </div>
88
+ <div class="flm-searchbox" id="searchBox">
89
+ <input class="flm-searchbox-input" id="searchInput" type="text" placeholder="Search pages...">
125
90
  </div>
126
- <input type="text" class="search-input" id="searchInput" placeholder="Search pages...">
127
91
  </div>
128
- <div id="pagesGrid" class="page-grid"></div>
92
+
93
+ <!-- Favorites section (hidden when empty) -->
94
+ <div id="favoritesSection" class="flm-stack" style="display: none; gap: var(--spacingS1);">
95
+ <span class="flm-text flm-text--mediumPlus flm-text--semibold flm-text--secondary">Favorites</span>
96
+ <div id="favoritesGrid" class="page-grid"></div>
97
+ </div>
98
+
99
+ <!-- All Pages grid -->
100
+ <div class="flm-stack" style="gap: var(--spacingS1);">
101
+ <span class="flm-text flm-text--mediumPlus flm-text--semibold flm-text--secondary">Pages</span>
102
+ <div id="pagesGrid" class="page-grid"></div>
103
+ </div>
129
104
  </div>
130
105
 
131
- <!-- Edit Page Modal -->
132
- <div id="editPageModal" class="modal-overlay">
133
- <div class="modal-content">
134
- <div class="modal-header">Edit Page Definition</div>
135
- <div class="modal-body">
136
- <div class="form-group">
137
- <label class="form-label">Display Title</label>
138
- <input type="text" id="editPageTitle" class="form-input" placeholder="Enter display title...">
139
- <div style="font-size: 11px; color: var(--text-secondary); margin-top: 4px; opacity: 0.8;">Page
140
- name: <span id="editPageNameDisplay"></span></div>
141
- </div>
142
- <div class="form-group">
143
- <label class="form-label">Categories (comma-separated)</label>
144
- <input type="text" id="editPageCategories" class="form-input" placeholder="e.g. Tools, Games, Utilities">
145
- </div>
146
- <div class="form-group">
147
- <label class="form-label checkbox-label">
148
- <input type="checkbox" id="editPagePinned">
149
- <span>Pinned to Favorites</span>
150
- </label>
151
- </div>
152
- <div class="form-group">
153
- <label class="form-label checkbox-label">
154
- <input type="checkbox" id="editPageLocked">
155
- <span>Locked</span>
156
- </label>
157
- <div style="font-size: 11px; color: var(--text-secondary); margin-top: 4px; opacity: 0.8;">
158
- Locked pages are read-only and cannot be modified through chat.
106
+ <!-- Edit Page Dialog -->
107
+ <div id="editPageModal" class="flm-dialog-overlay" data-light-dismiss>
108
+ <div class="flm-dialog">
109
+ <div class="flm-dialog-header">
110
+ <h2 class="flm-dialog-title">Edit Page Definition</h2>
111
+ <button class="flm-dialog-close" data-icon="Cancel" aria-label="Close" id="editCloseBtn"></button>
112
+ </div>
113
+ <div class="flm-dialog-body">
114
+ <div class="flm-stack" style="gap: var(--spacingM);">
115
+ <div class="flm-textfield">
116
+ <label class="flm-label" for="editPageTitle">Display Title</label>
117
+ <input class="flm-textfield-input" id="editPageTitle" placeholder="Enter display title...">
118
+ <span class="flm-text flm-text--small flm-text--secondary">Page name: <span id="editPageNameDisplay"></span></span>
159
119
  </div>
160
- </div>
161
- <div class="form-group">
162
- <label class="form-label checkbox-label">
163
- <input type="checkbox" id="editPageShowInAll" checked>
164
- <span>Show in All</span>
120
+ <div class="flm-textfield">
121
+ <label class="flm-label" for="editPageCategories">Categories (comma-separated)</label>
122
+ <input class="flm-textfield-input" id="editPageCategories" placeholder="e.g. Tools, Games, Utilities">
123
+ </div>
124
+ <label class="flm-checkbox">
125
+ <input type="checkbox" class="flm-checkbox-input" id="editPagePinned">
126
+ <span class="flm-checkbox-mark"></span>
127
+ <span class="flm-checkbox-label">Pinned to Favorites</span>
165
128
  </label>
166
- <div style="font-size: 11px; color: var(--text-secondary); margin-top: 4px; opacity: 0.8;">
167
- When unchecked, this page is hidden from the "All" filter and only appears under its category.
129
+ <div>
130
+ <label class="flm-checkbox">
131
+ <input type="checkbox" class="flm-checkbox-input" id="editPageLocked">
132
+ <span class="flm-checkbox-mark"></span>
133
+ <span class="flm-checkbox-label">Locked</span>
134
+ </label>
135
+ <span class="flm-text flm-text--small flm-text--secondary flm-text--block" style="margin-top: 4px; padding-left: 26px;">Locked pages are read-only and cannot be modified through chat.</span>
136
+ </div>
137
+ <div>
138
+ <label class="flm-checkbox">
139
+ <input type="checkbox" class="flm-checkbox-input" id="editPageShowInAll" checked>
140
+ <span class="flm-checkbox-mark"></span>
141
+ <span class="flm-checkbox-label">Show in All</span>
142
+ </label>
143
+ <span class="flm-text flm-text--small flm-text--secondary flm-text--block" style="margin-top: 4px; padding-left: 26px;">When unchecked, this page is hidden from the "All" filter and only appears under its category.</span>
168
144
  </div>
169
145
  </div>
170
146
  </div>
171
- <div class="modal-footer">
172
- <button class="modal-btn modal-btn-danger" id="deletePageBtn">Delete Page</button>
173
- <div class="modal-footer-right">
174
- <button class="modal-btn modal-btn-secondary" id="editCancelBtn">Cancel</button>
175
- <button class="modal-btn modal-btn-primary" id="editSaveBtn">Save Changes</button>
176
- </div>
147
+ <div class="flm-dialog-footer">
148
+ <button class="flm-button" id="deletePageBtn" style="color: var(--errorText);">Delete Page</button>
149
+ <div style="flex: 1;"></div>
150
+ <button class="flm-button" id="editCancelBtn">Cancel</button>
151
+ <button class="flm-button flm-button--primary" id="editSaveBtn">Save Changes</button>
177
152
  </div>
178
153
  </div>
179
154
  </div>
180
155
 
181
- <!-- Copy Page Modal -->
182
- <div id="copyPageModal" class="modal-overlay">
183
- <div class="modal-content">
184
- <div class="modal-header">Copy to New Page</div>
185
- <div class="modal-body">
186
- <div class="form-group">
187
- <label class="form-label">Display Title</label>
188
- <input type="text" id="copyPageTitle" class="form-input" placeholder="Enter display title...">
189
- <div style="font-size: 11px; color: var(--text-secondary); margin-top: 4px; opacity: 0.8;">
190
- Source: <span id="copySourcePageDisplay"></span></div>
191
- </div>
192
- <div class="form-group">
193
- <label class="form-label">Categories (comma-separated)</label>
194
- <input type="text" id="copyPageCategories" class="form-input" placeholder="e.g. Tools, Games, Utilities">
195
- </div>
196
- <div class="advanced-options">
197
- <button type="button" class="advanced-toggle" id="advancedToggle">
198
- <span class="toggle-icon">▶</span> Advanced Options
199
- </button>
200
- <div class="advanced-content" id="advancedContent" style="display: none;">
201
- <div class="form-group" style="margin-top: 12px;">
202
- <label class="form-label">Custom Page ID</label>
203
- <input type="text" id="copyNewPageName" class="form-input" placeholder="Auto-generated from title...">
204
- <div style="font-size: 11px; color: var(--text-secondary); margin-top: 4px; opacity: 0.8;">
205
- Used in the URL. Leave blank to auto-generate from title.</div>
156
+ <!-- Copy Page Dialog -->
157
+ <div id="copyPageModal" class="flm-dialog-overlay" data-light-dismiss>
158
+ <div class="flm-dialog">
159
+ <div class="flm-dialog-header">
160
+ <h2 class="flm-dialog-title">Copy to New Page</h2>
161
+ <button class="flm-dialog-close" data-icon="Cancel" aria-label="Close" id="copyCloseBtn"></button>
162
+ </div>
163
+ <div class="flm-dialog-body">
164
+ <div class="flm-stack" style="gap: var(--spacingM);">
165
+ <div class="flm-textfield">
166
+ <label class="flm-label" for="copyPageTitle">Display Title</label>
167
+ <input class="flm-textfield-input" id="copyPageTitle" placeholder="Enter display title...">
168
+ <span class="flm-text flm-text--small flm-text--secondary">Source: <span id="copySourcePageDisplay"></span></span>
169
+ </div>
170
+ <div class="flm-textfield">
171
+ <label class="flm-label" for="copyPageCategories">Categories (comma-separated)</label>
172
+ <input class="flm-textfield-input" id="copyPageCategories" placeholder="e.g. Tools, Games, Utilities">
173
+ </div>
174
+ <div class="advanced-options">
175
+ <button type="button" class="advanced-toggle" id="advancedToggle">
176
+ <span class="toggle-icon">&#9654;</span> Advanced Options
177
+ </button>
178
+ <div class="advanced-content" id="advancedContent" style="display: none;">
179
+ <div class="flm-textfield" style="margin-top: 12px;">
180
+ <label class="flm-label" for="copyNewPageName">Custom Page ID</label>
181
+ <input class="flm-textfield-input" id="copyNewPageName" placeholder="Auto-generated from title...">
182
+ <span class="flm-text flm-text--small flm-text--secondary">Used in the URL. Leave blank to auto-generate from title.</span>
183
+ </div>
206
184
  </div>
207
185
  </div>
208
186
  </div>
209
187
  </div>
210
- <div class="modal-footer">
211
- <div class="modal-footer-right">
212
- <button class="modal-btn modal-btn-secondary" id="copyCancelBtn">Cancel</button>
213
- <button class="modal-btn modal-btn-primary" id="copyConfirmBtn">Create Copy</button>
214
- </div>
188
+ <div class="flm-dialog-footer">
189
+ <div style="flex: 1;"></div>
190
+ <button class="flm-button" id="copyCancelBtn">Cancel</button>
191
+ <button class="flm-button flm-button--primary" id="copyConfirmBtn">Create Copy</button>
215
192
  </div>
216
193
  </div>
217
194
  </div>
218
195
 
219
- <!-- Delete Confirmation Modal -->
220
- <div id="deleteConfirmModal" class="modal-overlay">
221
- <div class="modal-content">
222
- <div class="modal-header">Confirm Delete</div>
223
- <div class="modal-body">
224
- <p style="color: var(--text-primary); margin: 0;">Are you sure you want to delete "<span id="deletePageNameDisplay2"></span>"? This cannot be undone.</p>
196
+ <!-- Delete Confirmation Dialog -->
197
+ <div id="deleteConfirmModal" class="flm-dialog-overlay" data-light-dismiss>
198
+ <div class="flm-dialog">
199
+ <div class="flm-dialog-header">
200
+ <h2 class="flm-dialog-title">Confirm Delete</h2>
201
+ <button class="flm-dialog-close" data-icon="Cancel" aria-label="Close" id="deleteCloseBtn"></button>
225
202
  </div>
226
- <div class="modal-footer">
227
- <div class="modal-footer-right">
228
- <button class="modal-btn modal-btn-secondary" id="deleteCancelBtn">Cancel</button>
229
- <button class="modal-btn modal-btn-danger" id="deleteConfirmBtn">Delete</button>
230
- </div>
203
+ <div class="flm-dialog-body">
204
+ <p class="flm-text">Are you sure you want to delete "<span id="deletePageNameDisplay2"></span>"? This cannot be undone.</p>
205
+ </div>
206
+ <div class="flm-dialog-footer">
207
+ <div style="flex: 1;"></div>
208
+ <button class="flm-button" id="deleteCancelBtn">Cancel</button>
209
+ <button class="flm-button" id="deleteConfirmBtn" style="color: var(--errorText);">Delete</button>
231
210
  </div>
232
211
  </div>
233
212
  </div>
@@ -235,19 +214,19 @@
235
214
  </div>
236
215
 
237
216
  <!-- Context menu -->
238
- <div id="contextMenu" class="context-menu">
239
- <div id="pinMenuItem" class="context-menu-item"></div>
240
- <div id="editMenuItem" class="context-menu-item">Edit page definition</div>
241
- <div id="copyMenuItem" class="context-menu-item">Copy to new page</div>
242
- <div id="updateMenuItem" class="context-menu-item">Update page</div>
243
- <div style="height: 1px; background: var(--border-color); margin: 4px 0;"></div>
244
- <div id="shareMenuItem" class="context-menu-item">Download page</div>
217
+ <div id="contextMenu" class="flm-contextmenu" style="position: fixed;">
218
+ <button id="pinMenuItem" class="flm-contextmenu-item"><span class="flm-contextmenu-item-text"></span></button>
219
+ <button id="editMenuItem" class="flm-contextmenu-item"><span class="flm-contextmenu-item-text">Edit page definition</span></button>
220
+ <button id="copyMenuItem" class="flm-contextmenu-item"><span class="flm-contextmenu-item-text">Copy to new page</span></button>
221
+ <button id="updateMenuItem" class="flm-contextmenu-item"><span class="flm-contextmenu-item-text">Update page</span></button>
222
+ <div class="flm-contextmenu-divider"></div>
223
+ <button id="shareMenuItem" class="flm-contextmenu-item"><span class="flm-contextmenu-item-text">Download page</span></button>
245
224
  </div>
246
225
  <div id="instructions" style="display: none;" data-locked="true"></div>
247
226
  <div id="thoughts" style="display: none;" data-locked="true"></div>
248
227
 
249
- <!-- Toast container -->
250
- <div id="upgradeToast" class="upgrade-toast"></div>
228
+ <!-- Toast -->
229
+ <div id="upgradeToast" class="flm-messagebar flm-messagebar--success toast-fixed"></div>
251
230
 
252
231
  <script>
253
232
  (function() {
@@ -282,6 +261,7 @@
282
261
  var favoritesSection = document.getElementById('favoritesSection');
283
262
  var favoritesGrid = document.getElementById('favoritesGrid');
284
263
  var filterBar = document.getElementById('filterBar');
264
+ var categoryTabs = document.getElementById('categoryTabs');
285
265
  var pagesGrid = document.getElementById('pagesGrid');
286
266
  var searchInput = document.getElementById('searchInput');
287
267
  var moreDropdown = document.getElementById('moreDropdown');
@@ -302,6 +282,7 @@
302
282
  var editPageLocked = document.getElementById('editPageLocked');
303
283
  var editPageShowInAll = document.getElementById('editPageShowInAll');
304
284
  var editCancelBtn = document.getElementById('editCancelBtn');
285
+ var editCloseBtn = document.getElementById('editCloseBtn');
305
286
  var editSaveBtn = document.getElementById('editSaveBtn');
306
287
  var deletePageBtn = document.getElementById('deletePageBtn');
307
288
  var copySourcePageDisplay = document.getElementById('copySourcePageDisplay');
@@ -309,9 +290,11 @@
309
290
  var copyPageCategories = document.getElementById('copyPageCategories');
310
291
  var copyNewPageName = document.getElementById('copyNewPageName');
311
292
  var copyCancelBtn = document.getElementById('copyCancelBtn');
293
+ var copyCloseBtn = document.getElementById('copyCloseBtn');
312
294
  var copyConfirmBtn = document.getElementById('copyConfirmBtn');
313
295
  var deletePageNameDisplay2 = document.getElementById('deletePageNameDisplay2');
314
296
  var deleteCancelBtn = document.getElementById('deleteCancelBtn');
297
+ var deleteCloseBtn = document.getElementById('deleteCloseBtn');
315
298
  var deleteConfirmBtn = document.getElementById('deleteConfirmBtn');
316
299
  var loadingOverlay = document.getElementById('loadingOverlay');
317
300
  var shareMenuItem = document.getElementById('shareMenuItem');
@@ -324,7 +307,7 @@
324
307
  return page.title || page.name;
325
308
  }
326
309
 
327
- // ── Page link creation (final version: scroll-text + upgrade badge + context menu) ──
310
+ // ── Page button creation ──
328
311
 
329
312
  function createPageLink(page, isBuilder) {
330
313
  var latestVersion = window.pageInfo ? window.pageInfo.latestPageVersion : 0;
@@ -334,13 +317,19 @@
334
317
  a.href = '/' + page.name;
335
318
 
336
319
  var title = displayName(page);
337
- var span = document.createElement('span');
338
- span.className = 'scroll-text';
339
- span.textContent = title;
340
- a.appendChild(span);
320
+
321
+ // Label with scroll-text
322
+ var label = document.createElement('span');
323
+ label.className = 'btn-label';
324
+ var scrollSpan = document.createElement('span');
325
+ scrollSpan.className = 'scroll-text';
326
+ scrollSpan.textContent = title;
327
+ label.appendChild(scrollSpan);
328
+ a.appendChild(label);
329
+
341
330
  a.title = title;
342
331
 
343
- var classes = 'page-link';
332
+ var classes = 'page-btn';
344
333
  if (isBuilder) {
345
334
  classes += ' builder-page';
346
335
  } else if (needsUpgrade) {
@@ -370,8 +359,8 @@
370
359
  });
371
360
 
372
361
  a.addEventListener('mouseenter', function() {
373
- var textWidth = span.scrollWidth;
374
- var containerWidth = a.clientWidth - 32;
362
+ var textWidth = scrollSpan.scrollWidth;
363
+ var containerWidth = label.clientWidth - 8;
375
364
  if (textWidth > containerWidth) {
376
365
  var scrollDistance = textWidth - containerWidth + 20;
377
366
  var duration = Math.max(2, scrollDistance / 30);
@@ -388,7 +377,7 @@
388
377
  return a;
389
378
  }
390
379
 
391
- // ── Context menu (final version: hides builder items, shows update for outdated) ──
380
+ // ── Context menu ──
392
381
 
393
382
  function showContextMenu(e, page) {
394
383
  contextTarget = page;
@@ -397,7 +386,7 @@
397
386
  pinMenuItem.style.display = isBuilder ? 'none' : '';
398
387
  editMenuItem.style.display = isBuilder ? 'none' : '';
399
388
  if (!isBuilder) {
400
- pinMenuItem.textContent = page.pinned ? 'Unpin from Favorites' : 'Pin to Favorites';
389
+ pinMenuItem.querySelector('.flm-contextmenu-item-text').textContent = page.pinned ? 'Unpin from Favorites' : 'Pin to Favorites';
401
390
  }
402
391
 
403
392
  var latestVersion = window.pageInfo ? window.pageInfo.latestPageVersion : 0;
@@ -407,11 +396,11 @@
407
396
 
408
397
  contextMenu.style.left = e.clientX + 'px';
409
398
  contextMenu.style.top = e.clientY + 'px';
410
- contextMenu.style.display = 'block';
399
+ contextMenu.classList.add('flm-contextmenu--visible');
411
400
  }
412
401
 
413
402
  function hideContextMenu() {
414
- contextMenu.style.display = 'none';
403
+ contextMenu.classList.remove('flm-contextmenu--visible');
415
404
  contextTarget = null;
416
405
  }
417
406
 
@@ -443,33 +432,37 @@
443
432
  }
444
433
 
445
434
  function renderFilterBar() {
446
- var container = document.querySelector('.filter-buttons-container');
447
- container.innerHTML = '';
435
+ categoryTabs.innerHTML = '';
448
436
  moreMenu.innerHTML = '';
449
437
 
450
- var allBtn = document.createElement('button');
451
- allBtn.className = 'filter-btn' + (activeCategory === 'All' ? ' active' : '');
452
- allBtn.textContent = 'All';
453
- allBtn.dataset.category = 'All';
454
- allBtn.addEventListener('click', function() { setCategory('All'); });
455
- container.appendChild(allBtn);
438
+ var allTab = document.createElement('button');
439
+ allTab.className = 'flm-pivot-tab' + (activeCategory === 'All' ? ' flm-pivot-tab--active' : '');
440
+ allTab.textContent = 'All';
441
+ allTab.setAttribute('role', 'tab');
442
+ allTab.dataset.category = 'All';
443
+ allTab.addEventListener('click', function() { setCategory('All'); });
444
+ categoryTabs.appendChild(allTab);
456
445
 
457
446
  visibleCategories.forEach(function(cat) {
458
- var btn = document.createElement('button');
459
- btn.className = 'filter-btn' + (activeCategory === cat ? ' active' : '');
460
- btn.textContent = cat;
461
- btn.dataset.category = cat;
462
- btn.addEventListener('click', function() { setCategory(cat); });
463
- container.appendChild(btn);
447
+ var tab = document.createElement('button');
448
+ tab.className = 'flm-pivot-tab' + (activeCategory === cat ? ' flm-pivot-tab--active' : '');
449
+ tab.textContent = cat;
450
+ tab.setAttribute('role', 'tab');
451
+ tab.dataset.category = cat;
452
+ tab.addEventListener('click', function() { setCategory(cat); });
453
+ categoryTabs.appendChild(tab);
464
454
  });
465
455
 
466
456
  if (overflowCategories.length > 0) {
467
457
  moreDropdown.style.display = '';
468
- moreBtn.className = 'filter-btn more-btn' + (overflowCategories.includes(activeCategory) ? ' active' : '');
458
+ moreBtn.className = 'flm-button flm-button--subtle' + (overflowCategories.includes(activeCategory) ? ' flm-button--primary' : '');
469
459
  overflowCategories.forEach(function(cat) {
470
- var item = document.createElement('div');
471
- item.className = 'more-menu-item' + (activeCategory === cat ? ' active' : '');
472
- item.textContent = cat;
460
+ var item = document.createElement('button');
461
+ item.className = 'flm-contextmenu-item' + (activeCategory === cat ? ' flm-contextmenu-item--checked' : '');
462
+ var itemText = document.createElement('span');
463
+ itemText.className = 'flm-contextmenu-item-text';
464
+ itemText.textContent = cat;
465
+ item.appendChild(itemText);
473
466
  item.addEventListener('click', function() { setCategory(cat); hideMoreMenu(); });
474
467
  moreMenu.appendChild(item);
475
468
  });
@@ -482,21 +475,22 @@
482
475
  var allCats = getAllCategories();
483
476
  if (!filterBar) return;
484
477
 
485
- var availableWidth = filterBar.offsetWidth - (searchInput.offsetWidth + 8) - 50 - 16;
478
+ var searchBoxEl = document.getElementById('searchBox');
479
+ var availableWidth = filterBar.offsetWidth - (searchBoxEl ? searchBoxEl.offsetWidth + 8 : 0) - 50 - 16;
486
480
  visibleCategories = [];
487
481
  overflowCategories = [];
488
482
 
489
483
  var temp = document.createElement('button');
490
- temp.className = 'filter-btn';
484
+ temp.className = 'flm-pivot-tab';
491
485
  temp.style.visibility = 'hidden';
492
486
  temp.style.position = 'absolute';
493
487
  document.body.appendChild(temp);
494
488
 
495
489
  // Measure "More" button width
496
- temp.textContent = 'More \u25BE';
497
- var moreBtnWidth = temp.offsetWidth + 8;
490
+ temp.textContent = 'More';
491
+ var moreBtnWidth = temp.offsetWidth + 16;
498
492
 
499
- // Measure each category button
493
+ // Measure each category tab
500
494
  var catWidths = {};
501
495
  allCats.forEach(function(cat) {
502
496
  temp.textContent = cat;
@@ -595,20 +589,28 @@
595
589
  }
596
590
  }
597
591
 
598
- // ── Modal helpers ──
592
+ // ── Dialog helpers ──
593
+
594
+ function showDialog(overlay) {
595
+ overlay.classList.add('flm-dialog-overlay--open');
596
+ }
597
+
598
+ function hideDialog(overlay) {
599
+ overlay.classList.remove('flm-dialog-overlay--open');
600
+ }
599
601
 
600
602
  function closeEditModal() {
601
- editPageModal.classList.remove('show');
603
+ hideDialog(editPageModal);
602
604
  currentEditPage = null;
603
605
  }
604
606
 
605
607
  function closeCopyModal() {
606
- copyPageModal.classList.remove('show');
608
+ hideDialog(copyPageModal);
607
609
  currentCopySource = null;
608
610
  }
609
611
 
610
612
  function closeDeleteModal() {
611
- deleteConfirmModal.classList.remove('show');
613
+ hideDialog(deleteConfirmModal);
612
614
  currentDeletePage = null;
613
615
  }
614
616
 
@@ -671,10 +673,11 @@
671
673
  editPageLocked.checked = contextTarget.mode === 'locked';
672
674
  editPageShowInAll.checked = contextTarget.showInAll !== false;
673
675
  hideContextMenu();
674
- editPageModal.classList.add('show');
676
+ showDialog(editPageModal);
675
677
  });
676
678
 
677
679
  editCancelBtn.addEventListener('click', closeEditModal);
680
+ editCloseBtn.addEventListener('click', closeEditModal);
678
681
 
679
682
  editSaveBtn.addEventListener('click', async function() {
680
683
  if (!currentEditPage) return;
@@ -718,10 +721,11 @@
718
721
  currentDeletePage = currentEditPage;
719
722
  deletePageNameDisplay2.textContent = displayName(currentEditPage);
720
723
  closeEditModal();
721
- deleteConfirmModal.classList.add('show');
724
+ showDialog(deleteConfirmModal);
722
725
  });
723
726
 
724
727
  deleteCancelBtn.addEventListener('click', closeDeleteModal);
728
+ deleteCloseBtn.addEventListener('click', closeDeleteModal);
725
729
 
726
730
  deleteConfirmBtn.addEventListener('click', async function() {
727
731
  if (!currentDeletePage) return;
@@ -757,11 +761,12 @@
757
761
  copyPageCategories.value = (contextTarget.categories || []).join(', ');
758
762
  copyNewPageName.value = '';
759
763
  hideContextMenu();
760
- copyPageModal.classList.add('show');
764
+ showDialog(copyPageModal);
761
765
  copyPageTitle.focus();
762
766
  });
763
767
 
764
768
  copyCancelBtn.addEventListener('click', closeCopyModal);
769
+ copyCloseBtn.addEventListener('click', closeCopyModal);
765
770
 
766
771
  copyConfirmBtn.addEventListener('click', async function() {
767
772
  if (!currentCopySource) return;
@@ -914,6 +919,6 @@
914
919
  loadPages();
915
920
  })();
916
921
  </script>
917
- <script id="page-helpers" src="/api/page-helpers.js?v=2" data-locked="true"></script>
918
- <script id="page-script" src="/api/page-script.js?v=2" data-locked="true"></script>
922
+ <script id="page-helpers" src="/api/page-helpers.js?v=3" data-locked="true"></script>
923
+ <script id="page-script" src="/api/page-script.js?v=3" data-locked="true"></script>
919
924
  </body></html>