@jant/core 0.6.16 → 0.7.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 (508) hide show
  1. package/README.md +11 -11
  2. package/bin/commands/assets/upload.js +192 -15
  3. package/bin/commands/import-site.js +60 -4
  4. package/bin/commands/reset-password.js +21 -8
  5. package/bin/commands/site/snapshot/export.js +1 -1
  6. package/bin/commands/site/snapshot/import.js +1 -1
  7. package/bin/lib/d1-query.js +5 -16
  8. package/bin/lib/node-env.js +40 -4
  9. package/bin/lib/site-selection.js +85 -29
  10. package/bin/lib/wrangler-cli.js +28 -2
  11. package/bin/lib/wrangler-json.js +35 -0
  12. package/dist/{app-C7_4oab9.js → app-K_Aa1MMn.js} +52476 -13330
  13. package/dist/client/.vite/manifest.json +255 -90
  14. package/dist/client/_assets/chunks/confirm-D7GrwsCN.js +45 -0
  15. package/dist/client/_assets/chunks/create-editor-CD3FhrOB.js +257 -0
  16. package/dist/client/_assets/chunks/{native-DpcrFAPh.js → emoji-mart-C4RpRKcU.js} +716 -1
  17. package/dist/client/_assets/chunks/footnote-rail-CmeoVtnU.js +1 -0
  18. package/dist/client/_assets/chunks/heic-to-CuP2Qlsw.js +1 -0
  19. package/dist/client/_assets/chunks/jant-locale-picker-DL6mIOT5.js +69 -0
  20. package/dist/client/_assets/chunks/lit-DW8VmJAT.js +2 -0
  21. package/dist/client/_assets/chunks/mediabunny-DRaCQ1r-.js +31 -0
  22. package/dist/client/_assets/chunks/rolldown-runtime-hePW80VL.js +1 -0
  23. package/dist/client/_assets/chunks/settings-paths-BcdySNx6.js +84 -0
  24. package/dist/client/_assets/chunks/site-header-nav-DzXsFk05.js +1 -0
  25. package/dist/client/_assets/chunks/slug-format-CRXO1AL5.js +1 -0
  26. package/dist/client/_assets/chunks/slugify-373citbs.js +1 -0
  27. package/dist/client/_assets/chunks/sortable-list-CgaL2jCs.js +2 -0
  28. package/dist/client/_assets/chunks/types-D5iF3H1a.js +1 -0
  29. package/dist/client/_assets/chunks/unsafe-html-B5ZEXaxg.js +1 -0
  30. package/dist/client/_assets/chunks/unsafe-svg-0QCkP0vZ.js +2 -0
  31. package/dist/client/_assets/client-GiYENVw8.css +2 -0
  32. package/dist/client/_assets/client-VnFxJN7G.js +295 -0
  33. package/dist/client/_assets/client-auth-k8gJ6QJj.js +828 -0
  34. package/dist/client/_assets/client-author-DQ8R-8KR.css +2 -0
  35. package/dist/client/_assets/client-compose-B_kDtWkW.js +2004 -0
  36. package/dist/client/_assets/client-manage-M90aSTOk.js +2170 -0
  37. package/dist/client/_assets/client-settings-DfYs9n1F.js +1112 -0
  38. package/dist/{export-Dl5KCiEs.js → github-sync-BPAvT999.js} +2254 -107
  39. package/dist/index.js +2 -5
  40. package/dist/node.js +5 -7
  41. package/package.json +3 -3
  42. package/src/__tests__/auth-session-freshness.test.ts +57 -0
  43. package/src/__tests__/basecoat-variants.test.ts +121 -0
  44. package/src/__tests__/bin/assets-upload.test.ts +68 -0
  45. package/src/__tests__/export-hugo-build.test.ts +260 -0
  46. package/src/__tests__/export-service.test.ts +231 -0
  47. package/src/__tests__/helpers/component-css.ts +91 -0
  48. package/src/__tests__/helpers/db.ts +33 -0
  49. package/src/__tests__/helpers/export-fixtures.ts +3 -0
  50. package/src/__tests__/stylesheet-audience.test.ts +159 -0
  51. package/src/__tests__/stylesheet-breakpoints.test.ts +183 -0
  52. package/src/app.tsx +71 -16
  53. package/src/auth.ts +18 -1
  54. package/src/client/__tests__/collection-page-actions.test.ts +51 -2
  55. package/src/client/__tests__/compose-bridge-image-upload.test.ts +196 -0
  56. package/src/client/__tests__/compose-bridge-video-poster.test.ts +159 -0
  57. package/src/client/__tests__/compose-bridge.test.ts +272 -0
  58. package/src/client/__tests__/compose-launch.test.ts +62 -1
  59. package/src/client/__tests__/compose-shortcuts.test.ts +38 -9
  60. package/src/client/__tests__/compose-triggers.test.ts +90 -0
  61. package/src/client/__tests__/copy-field.test.ts +162 -0
  62. package/src/client/__tests__/custom-url-menu.test.ts +127 -6
  63. package/src/client/__tests__/image-processor.test.ts +324 -2
  64. package/src/client/__tests__/lazy-entries.test.ts +92 -0
  65. package/src/client/__tests__/media-scroll-hint.test.ts +155 -0
  66. package/src/client/__tests__/runtime-paths.test.ts +84 -0
  67. package/src/client/__tests__/smart-collection-page-actions.test.ts +158 -0
  68. package/src/client/__tests__/toast.test.ts +23 -0
  69. package/src/client/__tests__/video-processor-probe.test.ts +175 -0
  70. package/src/client/__tests__/video-processor.test.ts +181 -0
  71. package/src/client/audio-processor.ts +24 -15
  72. package/src/client/audio-waveform.ts +49 -0
  73. package/src/client/collection-dialog-host.ts +72 -0
  74. package/src/client/collection-navigation.ts +51 -16
  75. package/src/client/collection-page-actions.ts +26 -0
  76. package/src/client/components/__tests__/jant-collection-dialog.test.ts +329 -0
  77. package/src/client/components/__tests__/jant-collection-directory.test.ts +274 -10
  78. package/src/client/components/__tests__/jant-collection-form.test.ts +59 -178
  79. package/src/client/components/__tests__/jant-command-palette.test.ts +28 -0
  80. package/src/client/components/__tests__/jant-compose-dialog-draft-storage.test.ts +340 -0
  81. package/src/client/components/__tests__/jant-compose-dialog.test.ts +1250 -53
  82. package/src/client/components/__tests__/jant-compose-editor.test.ts +544 -40
  83. package/src/client/components/__tests__/jant-compose-fullscreen.test.ts +0 -1
  84. package/src/client/components/__tests__/jant-locale-picker.test.ts +207 -0
  85. package/src/client/components/__tests__/jant-nav-manager.test.ts +234 -15
  86. package/src/client/components/__tests__/jant-post-menu.test.ts +413 -2
  87. package/src/client/components/__tests__/jant-post-picker.test.ts +197 -0
  88. package/src/client/components/__tests__/jant-settings-avatar.test.ts +15 -12
  89. package/src/client/components/__tests__/jant-settings-general.test.ts +541 -172
  90. package/src/client/components/__tests__/jant-settings-language.test.ts +851 -0
  91. package/src/client/components/__tests__/jant-smart-collection-dialog.test.ts +665 -0
  92. package/src/client/components/collection-dialog-types.ts +49 -0
  93. package/src/client/components/collection-manager-types.ts +32 -1
  94. package/src/client/components/collection-types.ts +1 -15
  95. package/src/client/components/compose-types.ts +75 -1
  96. package/src/client/components/jant-collection-dialog.ts +722 -0
  97. package/src/client/components/jant-collection-directory.ts +567 -182
  98. package/src/client/components/jant-collection-form.ts +53 -232
  99. package/src/client/components/jant-command-palette.ts +100 -49
  100. package/src/client/components/jant-compose-dialog.ts +1486 -707
  101. package/src/client/components/jant-compose-editor.ts +673 -336
  102. package/src/client/components/jant-compose-fullscreen.ts +51 -43
  103. package/src/client/components/jant-config-editor.ts +65 -53
  104. package/src/client/components/jant-confirm-dialog.ts +13 -11
  105. package/src/client/components/jant-locale-picker.ts +418 -0
  106. package/src/client/components/jant-media-lightbox.ts +146 -136
  107. package/src/client/components/jant-nav-manager.ts +690 -366
  108. package/src/client/components/jant-post-menu.ts +1086 -282
  109. package/src/client/components/jant-post-picker.ts +324 -0
  110. package/src/client/components/jant-repo-picker.ts +138 -106
  111. package/src/client/components/jant-settings-avatar.ts +31 -27
  112. package/src/client/components/jant-settings-general.ts +617 -543
  113. package/src/client/components/jant-settings-language.ts +1087 -0
  114. package/src/client/components/jant-smart-collection-dialog.ts +1021 -0
  115. package/src/client/components/jant-text-preview.ts +94 -86
  116. package/src/client/components/nav-manager-types.ts +62 -1
  117. package/src/client/components/settings-types.ts +14 -29
  118. package/src/client/components/smart-collection-conditions.ts +285 -0
  119. package/src/client/components/smart-collection-dialog-types.ts +68 -0
  120. package/src/client/compose-bridge.ts +214 -141
  121. package/src/client/compose-launch.ts +76 -2
  122. package/src/client/compose-shortcuts.ts +6 -8
  123. package/src/client/compose-triggers.ts +50 -0
  124. package/src/client/copy-field.ts +108 -0
  125. package/src/client/custom-url-menu.ts +60 -4
  126. package/src/client/icons.ts +14 -0
  127. package/src/client/image-plan.ts +165 -0
  128. package/src/client/image-processor.ts +195 -117
  129. package/src/client/image-worker-client.ts +45 -0
  130. package/src/client/image-worker.ts +135 -0
  131. package/src/client/lazy-entries.ts +95 -0
  132. package/src/client/lazy-slugify.ts +2 -2
  133. package/src/client/media-scroll-hint.ts +43 -2
  134. package/src/client/mediabunny.ts +29 -0
  135. package/src/client/post-picker.ts +41 -0
  136. package/src/client/runtime-paths.ts +74 -1
  137. package/src/client/settings-bridge.ts +4 -10
  138. package/src/client/site-header-nav.js +18 -6
  139. package/src/client/smart-collection-dialog-host.ts +116 -0
  140. package/src/client/smart-collection-page-actions.ts +208 -0
  141. package/src/client/tiptap/__tests__/bubble-menu.test.ts +110 -0
  142. package/src/client/tiptap/__tests__/floating-position.test.ts +136 -1
  143. package/src/client/tiptap/__tests__/inline-image-upload.test.ts +37 -0
  144. package/src/client/tiptap/bubble-menu.ts +47 -16
  145. package/src/client/tiptap/floating-position.ts +216 -2
  146. package/src/client/tiptap/inline-image-upload.ts +7 -3
  147. package/src/client/tiptap/link-toolbar.ts +22 -9
  148. package/src/client/toast.ts +13 -0
  149. package/src/client/types/vite-worker.d.ts +12 -0
  150. package/src/client/upload-with-metadata.ts +3 -13
  151. package/src/client/video-processor.ts +351 -107
  152. package/src/client-auth.ts +14 -31
  153. package/src/client-compose.ts +19 -0
  154. package/src/client-manage.ts +13 -0
  155. package/src/client-settings.ts +14 -0
  156. package/src/client-site.ts +10 -3
  157. package/src/client.ts +4 -0
  158. package/src/db/__tests__/backfill-nav-label-mirrors.test.ts +149 -0
  159. package/src/db/__tests__/schema-enum-sources.test.ts +33 -0
  160. package/src/db/__tests__/smart-collection-placement.test.ts +402 -0
  161. package/src/db/backfills/0006_clear_mirrored_page_nav_labels.sql +31 -0
  162. package/src/db/migrations/0032_married_tomas.sql +3 -0
  163. package/src/db/migrations/0033_busy_johnny_storm.sql +198 -0
  164. package/src/db/migrations/0034_cheerful_rumiko_fujikawa.sql +35 -0
  165. package/src/db/migrations/meta/0032_snapshot.json +2582 -0
  166. package/src/db/migrations/meta/0033_snapshot.json +2816 -0
  167. package/src/db/migrations/meta/0034_snapshot.json +2816 -0
  168. package/src/db/migrations/meta/_journal.json +21 -0
  169. package/src/db/migrations/pg/0030_abandoned_nighthawk.sql +3 -0
  170. package/src/db/migrations/pg/0031_strong_ultimatum.sql +128 -0
  171. package/src/db/migrations/pg/0032_furry_multiple_man.sql +6 -0
  172. package/src/db/migrations/pg/meta/0030_snapshot.json +3329 -0
  173. package/src/db/migrations/pg/meta/0031_snapshot.json +3660 -0
  174. package/src/db/migrations/pg/meta/0032_snapshot.json +3660 -0
  175. package/src/db/migrations/pg/meta/_journal.json +21 -0
  176. package/src/db/pg/schema.ts +195 -27
  177. package/src/db/post-visibility.ts +117 -0
  178. package/src/db/schema.ts +222 -27
  179. package/src/i18n/__tests__/detect.test.ts +26 -81
  180. package/src/i18n/__tests__/supported-locales.test.ts +83 -0
  181. package/src/i18n/context.tsx +12 -2
  182. package/src/i18n/detect.ts +7 -66
  183. package/src/i18n/locales/glossary.zh-Hans.yml +44 -4
  184. package/src/i18n/locales/glossary.zh-Hant.yml +44 -4
  185. package/src/i18n/locales/public/en.po +490 -158
  186. package/src/i18n/locales/public/en.ts +1 -1
  187. package/src/i18n/locales/public/zh-Hans.po +487 -155
  188. package/src/i18n/locales/public/zh-Hans.ts +1 -1
  189. package/src/i18n/locales/public/zh-Hant.po +487 -155
  190. package/src/i18n/locales/public/zh-Hant.ts +1 -1
  191. package/src/i18n/locales/settings/en.po +551 -69
  192. package/src/i18n/locales/settings/en.ts +1 -1
  193. package/src/i18n/locales/settings/zh-Hans.po +597 -115
  194. package/src/i18n/locales/settings/zh-Hans.ts +1 -1
  195. package/src/i18n/locales/settings/zh-Hant.po +610 -128
  196. package/src/i18n/locales/settings/zh-Hant.ts +1 -1
  197. package/src/i18n/locales.ts +94 -0
  198. package/src/i18n/middleware.ts +12 -2
  199. package/src/i18n/supported-locales.ts +80 -0
  200. package/src/lib/__tests__/api-settings.test.ts +11 -2
  201. package/src/lib/__tests__/asset-path.test.ts +92 -0
  202. package/src/lib/__tests__/deferred.test.ts +90 -0
  203. package/src/lib/__tests__/discover-ping.test.ts +89 -0
  204. package/src/lib/__tests__/discover.test.ts +410 -0
  205. package/src/lib/__tests__/feed-policy.test.ts +26 -0
  206. package/src/lib/__tests__/feed.test.ts +1526 -15
  207. package/src/lib/__tests__/filter-dimensions.test.ts +341 -0
  208. package/src/lib/__tests__/hosted-signin.test.ts +1 -1
  209. package/src/lib/__tests__/http-cache.test.ts +162 -0
  210. package/src/lib/__tests__/jant-docs-dev.test.ts +21 -0
  211. package/src/lib/__tests__/jant-docs.test.ts +23 -0
  212. package/src/lib/__tests__/lang-detect.test.ts +231 -0
  213. package/src/lib/__tests__/media-helpers.test.ts +81 -0
  214. package/src/lib/__tests__/navigation.test.ts +135 -1
  215. package/src/lib/__tests__/resolve-config.test.ts +64 -3
  216. package/src/lib/__tests__/schemas.test.ts +42 -4
  217. package/src/lib/__tests__/site-unavailable-page.test.ts +25 -0
  218. package/src/lib/__tests__/slug.test.ts +70 -0
  219. package/src/lib/__tests__/slugify.test.ts +85 -0
  220. package/src/lib/__tests__/storage.test.ts +32 -0
  221. package/src/lib/__tests__/thread-fold.test.ts +113 -0
  222. package/src/lib/__tests__/upload-sideload.test.ts +14 -0
  223. package/src/lib/__tests__/url-fetch.test.ts +1 -2
  224. package/src/lib/__tests__/url.test.ts +78 -72
  225. package/src/lib/__tests__/view-language.test.ts +413 -0
  226. package/src/lib/__tests__/worker-response-cache.test.ts +90 -0
  227. package/src/lib/address.ts +57 -0
  228. package/src/lib/api-posts.ts +12 -0
  229. package/src/lib/asset-path.ts +98 -1
  230. package/src/lib/build-env.ts +16 -0
  231. package/src/lib/collection-groups.ts +5 -1
  232. package/src/lib/collection-paths.ts +3 -10
  233. package/src/lib/constants.ts +28 -3
  234. package/src/lib/copy-field.ts +36 -0
  235. package/src/lib/crypto.ts +40 -0
  236. package/src/lib/csp-builder.ts +2 -1
  237. package/src/lib/deferred.ts +79 -0
  238. package/src/lib/discover-ping.ts +141 -0
  239. package/src/lib/discover.ts +437 -0
  240. package/src/lib/env.ts +134 -0
  241. package/src/lib/errors.ts +33 -0
  242. package/src/lib/feed-policy.ts +236 -2
  243. package/src/lib/feed.ts +926 -73
  244. package/src/lib/filter-dimensions.ts +1349 -0
  245. package/src/lib/github-sync-site-config.ts +3 -0
  246. package/src/lib/hosted-signin.ts +1 -1
  247. package/src/lib/http-cache.ts +148 -0
  248. package/src/lib/hugo-markdown.ts +16 -0
  249. package/src/lib/icons.ts +9 -2
  250. package/src/lib/ids.ts +3 -0
  251. package/src/lib/jant-docs.ts +42 -0
  252. package/src/lib/lang-detect.ts +308 -0
  253. package/src/lib/media-helpers.ts +13 -1
  254. package/src/lib/navigation.ts +78 -11
  255. package/src/lib/pagination.ts +28 -24
  256. package/src/lib/per-language-surfaces.ts +67 -0
  257. package/src/lib/post-meta.ts +19 -0
  258. package/src/lib/render.tsx +55 -7
  259. package/src/lib/resolve-config.ts +53 -5
  260. package/src/lib/schemas.ts +201 -10
  261. package/src/lib/site-header-fragment.tsx +2 -1
  262. package/src/lib/site-unavailable-page.ts +47 -0
  263. package/src/lib/slug.ts +51 -7
  264. package/src/lib/slugify.ts +113 -0
  265. package/src/lib/startup-config.ts +4 -6
  266. package/src/lib/storage.ts +7 -0
  267. package/src/lib/summary.ts +50 -0
  268. package/src/lib/thread-fold.ts +161 -0
  269. package/src/lib/time.ts +32 -0
  270. package/src/lib/timeline.ts +42 -1
  271. package/src/lib/tiptap-render.ts +1 -2
  272. package/src/lib/upload.ts +16 -13
  273. package/src/lib/url.ts +139 -86
  274. package/src/lib/version.ts +10 -8
  275. package/src/lib/view-language.ts +436 -0
  276. package/src/lib/view.ts +51 -23
  277. package/src/lib/viewer-context.ts +62 -0
  278. package/src/middleware/__tests__/auth.test.ts +70 -2
  279. package/src/middleware/__tests__/cache-control.test.ts +71 -3
  280. package/src/middleware/__tests__/onboarding.test.ts +76 -5
  281. package/src/middleware/__tests__/secure-headers.test.ts +1 -1
  282. package/src/middleware/__tests__/session.test.ts +181 -33
  283. package/src/middleware/auth.ts +50 -31
  284. package/src/middleware/cache-control.ts +75 -10
  285. package/src/middleware/config.ts +6 -6
  286. package/src/middleware/error-handler.ts +12 -0
  287. package/src/middleware/onboarding.ts +32 -10
  288. package/src/middleware/secure-headers.ts +1 -1
  289. package/src/middleware/session.ts +96 -8
  290. package/src/node/__tests__/cli-migrate.test.ts +21 -19
  291. package/src/node/__tests__/cli-reset-password.test.ts +81 -8
  292. package/src/node/__tests__/cli-runtime-target.test.ts +48 -1
  293. package/src/node/__tests__/cli-site-selection.test.ts +128 -38
  294. package/src/node/__tests__/runtime.test.ts +37 -0
  295. package/src/node/index.ts +1 -0
  296. package/src/preset.css +76 -22
  297. package/src/routes/__tests__/feed-validator.test.ts +156 -0
  298. package/src/routes/api/__tests__/collections.test.ts +114 -0
  299. package/src/routes/api/__tests__/discover.test.ts +222 -0
  300. package/src/routes/api/__tests__/nav-items.test.ts +212 -2
  301. package/src/routes/api/__tests__/post-translations.test.ts +829 -0
  302. package/src/routes/api/__tests__/settings.test.ts +24 -3
  303. package/src/routes/api/__tests__/telegram.test.ts +6 -5
  304. package/src/routes/api/collections.ts +49 -6
  305. package/src/routes/api/custom-urls.ts +0 -1
  306. package/src/routes/api/discover.ts +95 -0
  307. package/src/routes/api/export.ts +3 -0
  308. package/src/routes/api/internal/__tests__/sites.test.ts +42 -2
  309. package/src/routes/api/nav-items.ts +55 -8
  310. package/src/routes/api/posts.ts +159 -0
  311. package/src/routes/api/public/__tests__/archive.test.ts +111 -0
  312. package/src/routes/api/public/archive.ts +77 -81
  313. package/src/routes/api/public/posts.ts +23 -6
  314. package/src/routes/api/smart-collections.ts +132 -0
  315. package/src/routes/api/telegram.ts +2 -40
  316. package/src/routes/api/uploads.ts +1 -2
  317. package/src/routes/auth/__tests__/setup-auth.test.ts +137 -0
  318. package/src/routes/auth/__tests__/setup-discover.test.ts +204 -0
  319. package/src/routes/auth/__tests__/setup-flow.test.ts +270 -0
  320. package/src/routes/auth/__tests__/setup-page.test.tsx +329 -0
  321. package/src/routes/auth/__tests__/setup-steps.test.ts +310 -0
  322. package/src/routes/auth/__tests__/setup.test.ts +278 -26
  323. package/src/routes/auth/__tests__/signin.test.ts +135 -0
  324. package/src/routes/auth/setup.tsx +934 -186
  325. package/src/routes/auth/signin.tsx +10 -8
  326. package/src/routes/compose.tsx +5 -0
  327. package/src/routes/dash/__tests__/custom-urls-archive.test.ts +44 -0
  328. package/src/routes/dash/__tests__/custom-urls-page.test.ts +49 -0
  329. package/src/routes/dash/__tests__/delete-account.test.ts +106 -0
  330. package/src/routes/dash/__tests__/settings-discover.test.ts +213 -0
  331. package/src/routes/dash/custom-urls.tsx +1 -37
  332. package/src/routes/dash/settings.tsx +502 -41
  333. package/src/routes/discover-announce.ts +96 -0
  334. package/src/routes/feed/__tests__/feed.test.ts +165 -2
  335. package/src/routes/feed/feed.ts +69 -40
  336. package/src/routes/feed/sitemap.ts +95 -11
  337. package/src/routes/pages/__tests__/archive-indexing.test.ts +200 -0
  338. package/src/routes/pages/__tests__/archive-params.test.ts +370 -6
  339. package/src/routes/pages/__tests__/collection-routing.test.ts +16 -0
  340. package/src/routes/pages/__tests__/collections-feed-links.test.ts +72 -0
  341. package/src/routes/pages/__tests__/collections.test.ts +9 -3
  342. package/src/routes/pages/__tests__/custom-archive-url.test.ts +119 -0
  343. package/src/routes/pages/__tests__/feed-autodiscovery.test.ts +148 -0
  344. package/src/routes/pages/__tests__/language-routing.test.ts +679 -0
  345. package/src/routes/pages/__tests__/post-preview-partial.test.ts +96 -0
  346. package/src/routes/pages/__tests__/smart-collection.test.ts +298 -0
  347. package/src/routes/pages/__tests__/subscribe.test.ts +248 -0
  348. package/src/routes/pages/archive.tsx +471 -369
  349. package/src/routes/pages/collection.tsx +94 -96
  350. package/src/routes/pages/collections.tsx +38 -50
  351. package/src/routes/pages/featured.tsx +32 -13
  352. package/src/routes/pages/home.tsx +25 -6
  353. package/src/routes/pages/language.tsx +113 -0
  354. package/src/routes/pages/latest.tsx +26 -16
  355. package/src/routes/pages/new.tsx +3 -0
  356. package/src/routes/pages/page.tsx +178 -17
  357. package/src/routes/pages/partials.tsx +41 -0
  358. package/src/routes/pages/search.tsx +18 -3
  359. package/src/routes/pages/smart-collection.tsx +340 -0
  360. package/src/routes/pages/subscribe.tsx +182 -0
  361. package/src/runtime/__tests__/index.test.ts +19 -0
  362. package/src/runtime/__tests__/node.test.ts +129 -4
  363. package/src/runtime/cloudflare.ts +21 -2
  364. package/src/runtime/index.ts +27 -1
  365. package/src/runtime/node.ts +18 -1
  366. package/src/runtime/site.ts +95 -24
  367. package/src/services/__tests__/auth.test.ts +116 -7
  368. package/src/services/__tests__/collection.test.ts +108 -4
  369. package/src/services/__tests__/language.test.ts +495 -0
  370. package/src/services/__tests__/navigation.test.ts +213 -10
  371. package/src/services/__tests__/path.test.ts +180 -0
  372. package/src/services/__tests__/post-language.test.ts +830 -0
  373. package/src/services/__tests__/post.test.ts +46 -9
  374. package/src/services/__tests__/settings.test.ts +228 -17
  375. package/src/services/__tests__/site-admin.test.ts +5 -5
  376. package/src/services/__tests__/smart-collection.test.ts +651 -0
  377. package/src/services/about-page.ts +22 -1
  378. package/src/services/auth.ts +51 -49
  379. package/src/services/bootstrap.ts +188 -38
  380. package/src/services/collection-directory-position.ts +76 -0
  381. package/src/services/collection.ts +331 -46
  382. package/src/services/custom-url.ts +27 -22
  383. package/src/services/export-theme/assets/client-site.css +1 -1
  384. package/src/services/export-theme/assets/client-site.js +123 -123
  385. package/src/services/export-theme/layouts/_default/rss.xml +77 -1
  386. package/src/services/export-theme/layouts/partials/feed-post-content.xml +105 -2
  387. package/src/services/export-theme/layouts/partials/media-gallery.html +35 -21
  388. package/src/services/export-theme/layouts/partials/pagination.html +14 -13
  389. package/src/services/export-theme/layouts/partials/post-card.html +8 -4
  390. package/src/services/export-theme/layouts/partials/reply.html +2 -1
  391. package/src/services/export-theme/layouts/partials/thread-preview.html +40 -30
  392. package/src/services/export-theme/styles/main.css +13 -1
  393. package/src/services/export.ts +278 -19
  394. package/src/services/index.ts +34 -3
  395. package/src/services/language.ts +412 -0
  396. package/src/services/mcp.ts +3 -1
  397. package/src/services/media.ts +14 -6
  398. package/src/services/navigation.ts +429 -67
  399. package/src/services/path.ts +221 -6
  400. package/src/services/post.ts +1021 -152
  401. package/src/services/search.ts +39 -2
  402. package/src/services/settings.ts +238 -43
  403. package/src/services/site-admin.ts +24 -7
  404. package/src/services/site.ts +77 -1
  405. package/src/services/smart-collection.ts +636 -0
  406. package/src/services/telegram.ts +20 -22
  407. package/src/services/upload-session.ts +1 -3
  408. package/src/style-author.css +27 -0
  409. package/src/styles/components-author.css +1622 -0
  410. package/src/styles/components.css +24 -1571
  411. package/src/styles/site-media.css +16 -2
  412. package/src/styles/tokens.css +82 -12
  413. package/src/styles/ui-author.css +7602 -0
  414. package/src/styles/ui.css +1087 -7219
  415. package/src/types/app-context.ts +7 -0
  416. package/src/types/bindings.ts +3 -0
  417. package/src/types/config.ts +94 -15
  418. package/src/types/constants.ts +188 -16
  419. package/src/types/entities.ts +87 -1
  420. package/src/types/operations.ts +64 -2
  421. package/src/types/props.ts +157 -31
  422. package/src/types/views.ts +55 -1
  423. package/src/ui/__tests__/font-themes.test.ts +52 -12
  424. package/src/ui/compose/ComposeDialog.tsx +201 -7
  425. package/src/ui/compose/ComposePrompt.tsx +1 -5
  426. package/src/ui/compose/__tests__/ComposeDialog.test.tsx +125 -0
  427. package/src/ui/dash/appearance/AdvancedContent.tsx +2 -2
  428. package/src/ui/dash/appearance/CodeInjectionContent.tsx +12 -16
  429. package/src/ui/dash/appearance/NavigationContent.tsx +117 -16
  430. package/src/ui/dash/appearance/__tests__/NavigationContent.test.tsx +33 -11
  431. package/src/ui/dash/appearance/__tests__/system-nav-descriptions.test.ts +44 -0
  432. package/src/ui/dash/appearance/system-nav-descriptions.ts +75 -0
  433. package/src/ui/dash/settings/AccountMenuContent.tsx +2 -2
  434. package/src/ui/dash/settings/ApiTokensContent.tsx +2 -1
  435. package/src/ui/dash/settings/ConfigEditorContent.tsx +35 -16
  436. package/src/ui/dash/settings/GeneralContent.tsx +275 -113
  437. package/src/ui/dash/settings/LanguageContent.tsx +409 -0
  438. package/src/ui/dash/settings/SettingsRootContent.tsx +19 -1
  439. package/src/ui/dash/settings/__tests__/GeneralContent.test.tsx +324 -4
  440. package/src/ui/dash/settings/__tests__/LanguageContent.test.tsx +144 -0
  441. package/src/ui/dash/settings/__tests__/discover-copy.test.ts +66 -0
  442. package/src/ui/dash/settings/discover-copy.ts +116 -0
  443. package/src/ui/feed/LinkCard.tsx +55 -45
  444. package/src/ui/feed/NoteCard.tsx +9 -4
  445. package/src/ui/feed/PostStatusBadges.tsx +90 -43
  446. package/src/ui/feed/QuoteCard.tsx +55 -30
  447. package/src/ui/feed/ThreadPreview.tsx +6 -2
  448. package/src/ui/feed/__tests__/thread-preview.test.ts +13 -16
  449. package/src/ui/feed/__tests__/timeline-cards.test.ts +314 -49
  450. package/src/ui/feed/thread-preview-state.ts +20 -6
  451. package/src/ui/font-themes.ts +39 -29
  452. package/src/ui/layouts/BaseLayout.tsx +155 -10
  453. package/src/ui/layouts/SiteLayout.tsx +192 -34
  454. package/src/ui/layouts/__tests__/BaseLayout.test.tsx +196 -17
  455. package/src/ui/layouts/__tests__/SiteLayout.test.tsx +109 -85
  456. package/src/ui/pages/ArchivePage.tsx +282 -289
  457. package/src/ui/pages/CollectionPage.tsx +86 -76
  458. package/src/ui/pages/CollectionsPage.tsx +5 -0
  459. package/src/ui/pages/ComposePage.tsx +8 -0
  460. package/src/ui/pages/PostPage.tsx +47 -0
  461. package/src/ui/pages/SearchPage.tsx +3 -3
  462. package/src/ui/pages/SmartCollectionPage.tsx +434 -0
  463. package/src/ui/pages/SubscribePage.tsx +236 -0
  464. package/src/ui/pages/__tests__/ArchivePage.test.tsx +65 -9
  465. package/src/ui/pages/__tests__/collections-directory-rows.test.tsx +92 -0
  466. package/src/ui/pages/__tests__/collections-view-links.test.tsx +81 -0
  467. package/src/ui/shared/CollectionDirectory.tsx +178 -3
  468. package/src/ui/shared/CollectionsManager.tsx +70 -17
  469. package/src/ui/shared/CopyField.tsx +127 -0
  470. package/src/ui/shared/EmptyPostContent.tsx +23 -0
  471. package/src/ui/shared/MediaGallery.tsx +125 -46
  472. package/src/ui/shared/Pagination.tsx +20 -5
  473. package/src/ui/shared/PostFooter.tsx +20 -11
  474. package/src/ui/shared/__tests__/archive-labels.test.ts +100 -0
  475. package/src/ui/shared/__tests__/media-gallery.test.ts +210 -2
  476. package/src/ui/shared/__tests__/navigation-labels.test.ts +16 -22
  477. package/src/ui/shared/__tests__/pagination.test.ts +38 -24
  478. package/src/ui/shared/__tests__/post-footer.test.ts +32 -0
  479. package/src/ui/shared/archive-labels.ts +98 -0
  480. package/src/ui/shared/collection-management-labels.ts +94 -16
  481. package/src/ui/shared/navigation-labels.ts +45 -71
  482. package/src/ui/shared/post-article-attributes.ts +2 -0
  483. package/src/ui/shared/smart-collection-labels.ts +343 -0
  484. package/dist/app-C75Zc8dD.js +0 -6
  485. package/dist/client/_assets/chunks/heic-to-DUUaO23q.js +0 -1
  486. package/dist/client/_assets/chunks/module-DcsAZQZ_.js +0 -716
  487. package/dist/client/_assets/chunks/url-CU9pEbk5.js +0 -1
  488. package/dist/client/_assets/client-Bq0vre8Y.js +0 -296
  489. package/dist/client/_assets/client-D3VZyG4L.css +0 -2
  490. package/dist/client/_assets/client-auth-F2rb9WfF.js +0 -5571
  491. package/dist/env-BPYViDJJ.js +0 -281
  492. package/dist/github-api-BNF35Lkx.js +0 -176
  493. package/dist/github-app-DdiD-bC4.js +0 -275
  494. package/dist/github-sync-Bqg62IvV.js +0 -4
  495. package/dist/github-sync-HdK2EgvJ.js +0 -431
  496. package/dist/url-CbLAtlZe.js +0 -900
  497. package/src/client/__tests__/collection-created-notice.test.ts +0 -36
  498. package/src/client/__tests__/collection-form-bridge.test.ts +0 -216
  499. package/src/client/__tests__/post-form-bridge.test.ts +0 -82
  500. package/src/client/collection-created-notice.ts +0 -66
  501. package/src/client/collection-form-bridge.ts +0 -191
  502. package/src/client/components/__tests__/jant-post-form.test.ts +0 -193
  503. package/src/client/components/jant-post-form.ts +0 -422
  504. package/src/client/components/post-form-template.ts +0 -352
  505. package/src/client/components/post-form-types.ts +0 -96
  506. package/src/client/media-metadata.ts +0 -247
  507. package/src/client/post-form-bridge.ts +0 -193
  508. package/src/ui/pages/CollectionEditorPage.tsx +0 -175
@@ -3,6 +3,11 @@
3
3
  *
4
4
  * These use Tailwind's @layer and @apply, so they must be imported
5
5
  * AFTER Tailwind is initialized in the user's CSS entry.
6
+ *
7
+ * Reader half only. The settings pages, the config editor, the navigation
8
+ * manager, the custom URL manager, the dash chrome and the form skeletons
9
+ * live in `components-author.css`, which loads only on authenticated pages —
10
+ * see the note in `style-author.css`.
6
11
  */
7
12
 
8
13
  /* Search result highlight */
@@ -15,377 +20,10 @@ mark {
15
20
 
16
21
  /* Config Editor — a quiet utility list, not a stack of nested cards. */
17
22
  @layer components {
18
- .config-editor-page {
19
- display: flex;
20
- flex-direction: column;
21
- width: min(54rem, 100%);
22
- gap: clamp(1rem, 2vw, 1.25rem);
23
- padding-bottom: 1rem;
24
- }
25
-
26
23
  jant-config-editor {
27
24
  display: block;
28
25
  min-width: 0;
29
26
  }
30
-
31
- .config-editor-toolbar,
32
- .config-editor-search {
33
- min-width: 0;
34
- }
35
-
36
- .config-editor-search {
37
- position: relative;
38
- }
39
-
40
- .config-editor-search > svg {
41
- position: absolute;
42
- z-index: 1;
43
- top: 50%;
44
- left: 0.78rem;
45
- transform: translateY(-50%);
46
- color: var(--color-muted-foreground);
47
- pointer-events: none;
48
- }
49
-
50
- .config-editor-search .config-editor-search-input {
51
- width: 100%;
52
- min-height: 2.65rem;
53
- padding-left: 2.35rem;
54
- border-radius: var(--radius);
55
- font-family: var(--font-ui);
56
- }
57
-
58
- .config-editor-fallback .config-editor-search-input {
59
- padding-left: 0.8rem;
60
- }
61
-
62
- .config-editor-toolbar-meta {
63
- display: flex;
64
- min-height: 1.85rem;
65
- align-items: center;
66
- justify-content: space-between;
67
- gap: 1rem;
68
- margin: 0.35rem 0.1rem 0.25rem;
69
- }
70
-
71
- .config-editor-count {
72
- margin: 0;
73
- color: var(--color-muted-foreground);
74
- font-family: var(--font-ui);
75
- font-size: var(--type-2xs);
76
- line-height: 1.35;
77
- }
78
-
79
- .config-editor-modified-filter {
80
- display: inline-flex;
81
- min-height: 1.85rem;
82
- align-items: center;
83
- gap: 0.42rem;
84
- color: var(--color-muted-foreground);
85
- font-family: var(--font-ui);
86
- font-size: var(--type-2xs);
87
- cursor: pointer;
88
- touch-action: manipulation;
89
- white-space: nowrap;
90
- }
91
-
92
- .config-editor-modified-filter:hover,
93
- .config-editor-modified-filter:focus-within {
94
- color: var(--color-foreground);
95
- }
96
-
97
- .config-editor-modified-filter:focus-within {
98
- outline: 2px solid color-mix(in srgb, var(--site-accent) 26%, transparent);
99
- outline-offset: 2px;
100
- }
101
-
102
- .config-editor-list {
103
- margin: 0;
104
- padding: 0;
105
- border-top: 1px solid var(--color-border);
106
- border-bottom: 1px solid var(--color-border);
107
- list-style: none;
108
- }
109
-
110
- .config-editor-row {
111
- display: grid;
112
- grid-template-columns: minmax(0, 1fr) minmax(16rem, 18rem);
113
- align-items: center;
114
- gap: clamp(1.25rem, 3vw, 2.25rem);
115
- min-width: 0;
116
- padding: 0.88rem 0.1rem;
117
- border-bottom: 1px solid
118
- color-mix(in srgb, var(--color-border) 78%, transparent);
119
- }
120
-
121
- .config-editor-row:last-child {
122
- border-bottom: 0;
123
- }
124
-
125
- .config-editor-row[aria-busy="true"] {
126
- background: color-mix(in srgb, var(--site-accent) 2.5%, transparent);
127
- }
128
-
129
- .config-editor-copy,
130
- .config-editor-value-column,
131
- .config-editor-control-row {
132
- min-width: 0;
133
- }
134
-
135
- .config-editor-heading {
136
- display: flex;
137
- flex-wrap: wrap;
138
- align-items: center;
139
- gap: 0.45rem;
140
- }
141
-
142
- .config-editor-heading > label {
143
- cursor: pointer;
144
- }
145
-
146
- .config-editor-key {
147
- overflow-wrap: anywhere;
148
- color: var(--color-foreground);
149
- font-family: var(--font-mono);
150
- font-size: var(--type-xs);
151
- font-weight: var(--fw-medium);
152
- line-height: 1.35;
153
- }
154
-
155
- .config-editor-state {
156
- display: inline-flex;
157
- align-items: center;
158
- gap: 0.3rem;
159
- color: var(--color-muted-foreground);
160
- font-family: var(--font-ui);
161
- font-size: var(--type-2xs);
162
- line-height: 1.3;
163
- }
164
-
165
- .config-editor-state::before {
166
- width: 0.28rem;
167
- height: 0.28rem;
168
- flex: none;
169
- border-radius: 999px;
170
- background: currentColor;
171
- content: "";
172
- }
173
-
174
- .config-editor-modified {
175
- color: color-mix(in srgb, var(--site-accent) 72%, var(--color-foreground));
176
- }
177
-
178
- .config-editor-locked::before {
179
- border-radius: 0.05rem;
180
- }
181
-
182
- .config-editor-description {
183
- margin: 0.28rem 0 0;
184
- color: var(--color-muted-foreground);
185
- font-family: var(--font-ui);
186
- font-size: var(--type-xs);
187
- line-height: 1.42;
188
- text-wrap: pretty;
189
- }
190
-
191
- .config-editor-value-column {
192
- display: flex;
193
- flex-direction: column;
194
- align-items: stretch;
195
- gap: 0.28rem;
196
- }
197
-
198
- .config-editor-control-row {
199
- display: grid;
200
- grid-template-columns: minmax(0, 1fr) 2rem;
201
- align-items: center;
202
- gap: 0.7rem;
203
- }
204
-
205
- .config-editor-control-row-select {
206
- grid-template-columns: minmax(0, 1fr) 2rem;
207
- }
208
-
209
- .config-editor-control-row-number {
210
- grid-template-columns: minmax(0, 8rem) 2rem;
211
- justify-content: start;
212
- }
213
-
214
- .config-editor-control-row > input[role="switch"] {
215
- justify-self: end;
216
- }
217
-
218
- .config-editor-control-row .config-editor-select,
219
- .config-editor-value-input {
220
- width: 100%;
221
- max-width: 100%;
222
- min-width: 0;
223
- font-family: var(--font-mono);
224
- font-size: var(--type-xs);
225
- }
226
-
227
- .config-editor-control-row .config-editor-select {
228
- overflow: hidden;
229
- text-overflow: ellipsis;
230
- white-space: nowrap;
231
- }
232
-
233
- .config-editor-status {
234
- align-self: flex-end;
235
- color: var(--color-muted-foreground);
236
- font-family: var(--font-ui);
237
- font-size: var(--type-2xs);
238
- line-height: 1.35;
239
- }
240
-
241
- .config-editor-status-saved {
242
- color: color-mix(in srgb, var(--site-accent) 68%, var(--color-foreground));
243
- }
244
-
245
- .config-editor-status-error {
246
- max-width: 100%;
247
- color: var(--color-destructive);
248
- text-align: right;
249
- text-wrap: pretty;
250
- }
251
-
252
- .config-editor-reset {
253
- display: grid;
254
- width: 2rem;
255
- height: 2rem;
256
- place-items: center;
257
- padding: 0;
258
- border: 0;
259
- border-radius: var(--radius);
260
- background: transparent;
261
- color: var(--color-muted-foreground);
262
- cursor: pointer;
263
- touch-action: manipulation;
264
- }
265
-
266
- .config-editor-reset:hover,
267
- .config-editor-reset:focus-visible {
268
- background: var(--color-muted);
269
- color: var(--color-foreground);
270
- }
271
-
272
- .config-editor-reset:focus-visible,
273
- .config-editor-open-control:focus-visible {
274
- outline: 2px solid color-mix(in srgb, var(--site-accent) 28%, transparent);
275
- outline-offset: 3px;
276
- }
277
-
278
- .config-editor-reset:disabled {
279
- opacity: 0.45;
280
- cursor: not-allowed;
281
- }
282
-
283
- .config-editor-open-control {
284
- display: flex;
285
- min-width: 0;
286
- min-height: 2.35rem;
287
- align-items: center;
288
- justify-content: space-between;
289
- gap: 0.8rem;
290
- padding: 0.35rem 0.1rem;
291
- color: inherit;
292
- text-decoration: none;
293
- cursor: pointer;
294
- touch-action: manipulation;
295
- }
296
-
297
- .config-editor-linked-value {
298
- min-width: 0;
299
- overflow: hidden;
300
- color: var(--site-text-secondary);
301
- font-family: var(--font-mono);
302
- font-size: var(--type-xs);
303
- line-height: 1.4;
304
- text-overflow: ellipsis;
305
- white-space: nowrap;
306
- }
307
-
308
- .config-editor-open-action {
309
- display: inline-flex;
310
- flex: none;
311
- align-items: center;
312
- gap: 0.3rem;
313
- color: var(--color-muted-foreground);
314
- font-family: var(--font-ui);
315
- font-size: var(--type-2xs);
316
- line-height: 1.35;
317
- white-space: nowrap;
318
- }
319
-
320
- .config-editor-open-control:hover .config-editor-linked-value,
321
- .config-editor-open-control:hover .config-editor-open-action,
322
- .config-editor-open-control:focus-visible .config-editor-linked-value,
323
- .config-editor-open-control:focus-visible .config-editor-open-action {
324
- color: var(--color-foreground);
325
- }
326
-
327
- .config-editor-fallback-value {
328
- width: 100%;
329
- min-width: 0;
330
- overflow: hidden;
331
- padding-block: 0.35rem;
332
- color: var(--site-text-secondary);
333
- font-family: var(--font-mono);
334
- font-size: var(--type-xs);
335
- line-height: 1.4;
336
- text-align: right;
337
- text-overflow: ellipsis;
338
- white-space: nowrap;
339
- }
340
-
341
- .config-editor-empty {
342
- display: grid;
343
- min-height: 9rem;
344
- place-items: center;
345
- padding: 2rem;
346
- border-top: 1px solid var(--color-border);
347
- border-bottom: 1px solid var(--color-border);
348
- color: var(--color-muted-foreground);
349
- font-family: var(--font-ui);
350
- font-size: var(--type-sm);
351
- line-height: 1.45;
352
- text-align: center;
353
- }
354
-
355
- .config-editor-empty p {
356
- max-width: 28rem;
357
- margin: 0;
358
- }
359
-
360
- @media (hover: hover) and (pointer: fine) {
361
- .config-editor-row .config-editor-reset {
362
- opacity: 0;
363
- pointer-events: none;
364
- }
365
-
366
- .config-editor-row:hover .config-editor-reset,
367
- .config-editor-row:focus-within .config-editor-reset {
368
- opacity: 1;
369
- pointer-events: auto;
370
- }
371
- }
372
-
373
- @media (max-width: 760px) {
374
- .config-editor-row {
375
- grid-template-columns: minmax(0, 1fr);
376
- align-items: stretch;
377
- gap: 0.62rem;
378
- padding-block: 0.85rem;
379
- }
380
-
381
- .config-editor-control-row > input[role="switch"] {
382
- justify-self: start;
383
- }
384
-
385
- .config-editor-fallback-value {
386
- text-align: left;
387
- }
388
- }
389
27
  }
390
28
 
391
29
  .search-snippet {
@@ -508,159 +146,10 @@ svg[stroke-width].icon-fine {
508
146
 
509
147
  /* Admin header */
510
148
  @layer components {
511
- .dash-header {
512
- padding: 20px 0 0;
513
- }
514
-
515
- @media (min-width: 700px) {
516
- .dash-header {
517
- padding: 24px 0 0;
518
- }
519
- }
520
-
521
- .dash-header-inner {
522
- display: flex;
523
- align-items: center;
524
- gap: 16px;
525
- padding-bottom: 12px;
526
- }
527
-
528
- .dash-header-avatar-link {
529
- flex-shrink: 0;
530
- line-height: 0;
531
- }
532
-
533
- .dash-header-avatar {
534
- width: 22px;
535
- height: 22px;
536
- border-radius: 5px;
537
- }
538
-
539
- .dash-header-avatar:is(img) {
540
- object-fit: cover;
541
- }
542
-
543
- .dash-header-avatar-fallback {
544
- display: flex;
545
- align-items: center;
546
- justify-content: center;
547
- color: white;
548
- font-size: var(--type-2xs);
549
- font-weight: var(--fw-semibold);
550
- line-height: 1;
551
- }
552
-
553
- .dash-header-nav {
554
- display: flex;
555
- align-items: center;
556
- gap: 16px;
557
- }
558
-
559
- .dash-header-nav-sep {
560
- display: none;
561
- }
562
-
563
- .dash-header-right {
564
- display: flex;
565
- align-items: center;
566
- gap: 8px;
567
- margin-left: auto;
568
- }
569
-
570
- .dash-header-link {
571
- font-size: var(--type-xs);
572
- color: var(--color-muted-foreground);
573
- transition: color 0.15s;
574
-
575
- &:hover {
576
- color: var(--color-foreground);
577
- }
578
- }
579
-
580
- .dash-header-link-active {
581
- color: var(--color-foreground);
582
- font-weight: var(--fw-medium);
583
- }
584
-
585
- .dash-header-visit {
586
- @apply flex items-center gap-3;
587
- font-size: var(--type-sm);
588
- color: var(--color-muted-foreground);
589
- transition: color 0.15s;
590
-
591
- &:hover {
592
- color: var(--color-foreground);
593
- }
594
- }
595
-
596
- .dash-header-visit-text {
597
- display: none;
598
- }
599
-
600
- @media (min-width: 700px) {
601
- .dash-header-visit-text {
602
- display: inline;
603
- }
604
-
605
- .dash-header-visit-icon {
606
- display: none;
607
- }
608
- }
609
-
610
- .dash-header-menu-btn {
611
- @apply flex items-center justify-center;
612
- width: 32px;
613
- height: 32px;
614
- border-radius: var(--radius);
615
- border: none;
616
- background: transparent;
617
- color: var(--color-muted-foreground);
618
- cursor: pointer;
619
- transition:
620
- color 0.15s,
621
- background-color 0.15s;
622
-
623
- &:hover {
624
- color: var(--color-foreground);
625
- background-color: var(--color-accent);
626
- }
627
- }
628
-
629
- .dash-header-menu-btn + [data-popover] {
630
- min-width: 170px;
631
- }
632
149
  }
633
150
 
634
151
  /* Breadcrumb — second row below header on settings sub-pages */
635
152
  @layer components {
636
- .dash-breadcrumb {
637
- display: flex;
638
- align-items: center;
639
- flex-wrap: wrap;
640
- gap: 8px;
641
- padding: 8px 0;
642
- font-size: var(--type-base);
643
- line-height: 1.35;
644
- }
645
-
646
- .dash-breadcrumb-parent {
647
- color: var(--color-muted-foreground);
648
- transition: color 0.15s;
649
-
650
- &:hover {
651
- color: var(--color-foreground);
652
- }
653
- }
654
-
655
- .dash-breadcrumb-sep {
656
- color: var(--color-muted-foreground);
657
- opacity: 0.5;
658
- }
659
-
660
- .dash-breadcrumb-current {
661
- color: var(--color-foreground);
662
- font-weight: var(--fw-medium);
663
- }
664
153
  }
665
154
 
666
155
  /* Page intro — shared title block for top-level pages */
@@ -716,1064 +205,28 @@ svg[stroke-width].icon-fine {
716
205
 
717
206
  /* Settings root — iOS-style grouped list */
718
207
  @layer components {
719
- .settings-root {
720
- @apply flex flex-col;
721
- width: var(--layout-content-width);
722
- gap: clamp(1.15rem, 2.8vw, 1.65rem);
723
- padding-bottom: 0.15rem;
724
- }
725
-
726
- @media (max-width: 760px) {
727
- .settings-root {
728
- width: 100%;
729
- }
730
- }
731
-
732
- .settings-directory-section {
733
- @apply flex flex-col;
734
- gap: 0.22rem;
735
- }
736
-
737
- .settings-directory-section + .settings-directory-section {
738
- padding-top: 0.34rem;
739
- }
740
-
741
- .settings-directory-section-title {
742
- margin: 0;
743
- font-family: var(--font-ui);
744
- color: var(--site-text-secondary);
745
- font-size: var(--type-xs);
746
- font-weight: var(--fw-medium);
747
- line-height: 1.3;
748
- letter-spacing: 0.02em;
749
- }
750
-
751
- .settings-directory-section-title[data-tone="danger"] {
752
- color: color-mix(
753
- in srgb,
754
- var(--color-destructive) 72%,
755
- var(--site-text-secondary)
756
- );
757
- }
758
-
759
- .settings-directory-list {
760
- @apply flex flex-col;
761
- gap: 0.35rem;
762
- }
763
-
764
- .settings-directory-item {
765
- @apply flex items-center w-full text-left;
766
- gap: 0.68rem;
767
- padding: 0.85rem 0.6rem 0.85rem 0;
768
- border: none;
769
- border-radius: 0.85rem;
770
- background: transparent;
771
- box-shadow: none;
772
- color: inherit;
773
- text-decoration: none;
774
- transition:
775
- background-color 0.18s ease,
776
- color 0.18s ease;
777
- }
778
-
779
- button.settings-directory-item {
780
- appearance: none;
781
- cursor: pointer;
782
- font: inherit;
783
- }
784
-
785
- .settings-directory-item:hover {
786
- background: color-mix(
787
- in srgb,
788
- var(--color-foreground) 4%,
789
- var(--color-background)
790
- );
791
- }
792
-
793
- .settings-directory-item:focus-visible {
794
- outline: 2px solid color-mix(in srgb, var(--site-accent) 28%, transparent);
795
- outline-offset: 3px;
796
- background: color-mix(in srgb, var(--site-accent) 6%, var(--color-card));
797
- }
208
+ }
798
209
 
799
- .settings-directory-item[data-tone="subtle"] {
800
- color: inherit;
801
- }
210
+ /* Admin scoped font rules */
211
+ @layer components {
212
+ }
802
213
 
803
- .settings-directory-item[data-tone="danger"] {
804
- color: inherit;
805
- }
214
+ /* Navigation preview — browser-chrome frame for nav preview */
215
+ @layer components {
216
+ }
806
217
 
807
- .settings-directory-item[data-tone="danger"]:hover,
808
- .settings-directory-item[data-tone="danger"]:focus-visible {
809
- background: color-mix(
810
- in srgb,
811
- var(--color-destructive) 7%,
812
- var(--color-background)
813
- );
814
- }
218
+ /* Navigation items list — card-style draggable nav items */
219
+ @layer components {
220
+ }
815
221
 
816
- .settings-directory-item-icon {
817
- @apply flex items-center justify-center shrink-0;
818
- width: 2.55rem;
819
- height: 2.55rem;
820
- border: 1px solid color-mix(in srgb, var(--color-border) 76%, white 24%);
821
- border-radius: 999px;
822
- background: transparent;
823
- color: var(--color-foreground);
824
- }
222
+ /* Skeleton screen sizing — used in SSR fallbacks while Lit hydrates */
223
+ @layer components {
224
+ }
825
225
 
826
- .settings-directory-item[data-tone="subtle"] .settings-directory-item-icon {
827
- color: color-mix(
828
- in srgb,
829
- var(--color-foreground) 86%,
830
- var(--color-muted-foreground)
831
- );
832
- }
833
-
834
- .settings-directory-item[data-tone="danger"] .settings-directory-item-icon {
835
- border-color: color-mix(
836
- in srgb,
837
- var(--color-destructive) 16%,
838
- var(--color-border)
839
- );
840
- color: color-mix(
841
- in srgb,
842
- var(--color-destructive) 86%,
843
- var(--color-foreground)
844
- );
845
- }
846
-
847
- .settings-directory-item-icon svg {
848
- width: 1.08rem;
849
- height: 1.08rem;
850
- stroke-width: 1.9;
851
- }
852
-
853
- .settings-directory-item-copy {
854
- @apply flex flex-col flex-1 min-w-0;
855
- gap: 0.3rem;
856
- }
857
-
858
- .settings-directory-item-name {
859
- font-family: var(--font-ui);
860
- font-size: var(--type-secondary);
861
- font-weight: var(--fw-regular);
862
- line-height: 1.3;
863
- color: var(--color-foreground);
864
- text-wrap: pretty;
865
- }
866
-
867
- .settings-directory-item-desc {
868
- font-family: var(--font-ui);
869
- font-size: var(--type-sm);
870
- line-height: 1.4;
871
- color: var(--muted-foreground);
872
- text-wrap: pretty;
873
- }
874
-
875
- .settings-directory-item-chevron {
876
- @apply shrink-0;
877
- color: color-mix(
878
- in srgb,
879
- var(--color-muted-foreground) 82%,
880
- var(--color-foreground)
881
- );
882
- opacity: 0.72;
883
- transition:
884
- transform 0.18s ease,
885
- opacity 0.18s ease,
886
- color 0.18s ease;
887
- }
888
-
889
- .settings-directory-item:hover .settings-directory-item-chevron,
890
- .settings-directory-item:focus-visible .settings-directory-item-chevron {
891
- transform: translateX(1px);
892
- opacity: 1;
893
- color: color-mix(
894
- in srgb,
895
- var(--color-foreground) 62%,
896
- var(--color-muted-foreground)
897
- );
898
- }
899
-
900
- .settings-root-version {
901
- text-align: center;
902
- font-size: var(--type-2xs);
903
- font-family: var(--font-mono, monospace);
904
- color: var(--color-muted-foreground);
905
- opacity: 0.45;
906
- margin: 0 0 0.6rem;
907
- user-select: all;
908
- }
909
-
910
- .settings-root-version-link {
911
- color: inherit;
912
- text-decoration: underline;
913
- text-decoration-style: dotted;
914
- text-underline-offset: 2px;
915
- }
916
-
917
- .settings-root-version-link:hover {
918
- opacity: 0.75;
919
- }
920
-
921
- .settings-root-signout {
922
- @apply flex justify-center;
923
- padding-top: 0.1rem;
924
- }
925
-
926
- .settings-root-signout-btn {
927
- @apply inline-flex items-center justify-center cursor-pointer;
928
- min-height: 1.8rem;
929
- padding: 0;
930
- border: none;
931
- background: transparent;
932
- color: var(--color-destructive);
933
- font-size: var(--type-xs);
934
- font-weight: var(--fw-medium);
935
- letter-spacing: -0.01em;
936
- transition:
937
- opacity 0.18s ease,
938
- color 0.18s ease;
939
- }
940
-
941
- .settings-root-signout-btn:hover,
942
- .settings-root-signout-btn:focus-visible {
943
- opacity: 0.78;
944
- }
945
-
946
- .settings-root-signout-btn:focus-visible {
947
- outline: 2px solid
948
- color-mix(in srgb, var(--color-destructive) 28%, transparent);
949
- outline-offset: 3px;
950
- }
951
-
952
- .settings-group-label {
953
- margin: 0 0 0.55rem;
954
- padding-inline: 0.15rem;
955
- font-size: var(--type-xs);
956
- font-weight: var(--fw-medium);
957
- line-height: 1.3;
958
- letter-spacing: 0.04em;
959
- color: color-mix(
960
- in srgb,
961
- var(--color-foreground) 72%,
962
- var(--color-muted-foreground)
963
- );
964
- }
965
-
966
- .settings-group {
967
- overflow: hidden;
968
- border: 1px solid
969
- color-mix(in srgb, var(--color-border) 84%, var(--site-accent) 8%);
970
- border-radius: 0.95rem;
971
- background-color: color-mix(
972
- in srgb,
973
- var(--color-card) 97%,
974
- var(--site-accent) 3%
975
- );
976
- box-shadow: 0 10px 24px -22px
977
- color-mix(in srgb, var(--color-foreground) 18%, transparent);
978
- }
979
-
980
- .settings-item {
981
- @apply flex items-center;
982
- gap: 0.75rem;
983
- padding: 0.82rem 0.9rem;
984
- --settings-item-icon-accent: var(--site-accent);
985
- --settings-item-icon-bg-strength: 13%;
986
- --settings-item-icon-border-strength: 22%;
987
- --settings-item-icon-fg-strength: 70%;
988
- transition:
989
- background-color 0.18s ease,
990
- border-color 0.18s ease;
991
- border-bottom: 1px solid
992
- color-mix(in srgb, var(--color-border) 78%, transparent);
993
-
994
- &:last-child {
995
- border-bottom: none;
996
- }
997
-
998
- &:hover {
999
- background-color: color-mix(
1000
- in srgb,
1001
- var(--settings-item-icon-accent) 5%,
1002
- var(--color-card)
1003
- );
1004
- }
1005
-
1006
- &:focus-visible {
1007
- outline: 2px solid
1008
- color-mix(in srgb, var(--settings-item-icon-accent) 24%, transparent);
1009
- outline-offset: -2px;
1010
- background-color: color-mix(
1011
- in srgb,
1012
- var(--settings-item-icon-accent) 6%,
1013
- var(--color-card)
1014
- );
1015
- }
1016
- }
1017
-
1018
- .settings-item[data-tone="subtle"] {
1019
- --settings-item-icon-bg-strength: 8%;
1020
- --settings-item-icon-border-strength: 16%;
1021
- --settings-item-icon-fg-strength: 56%;
1022
- }
1023
-
1024
- .settings-item[data-tone="danger"] {
1025
- --settings-item-icon-accent: var(--color-destructive);
1026
- --settings-item-icon-bg-strength: 10%;
1027
- --settings-item-icon-border-strength: 20%;
1028
- --settings-item-icon-fg-strength: 76%;
1029
- }
1030
-
1031
- .settings-item-icon {
1032
- @apply flex items-center justify-center shrink-0;
1033
- width: 28px;
1034
- height: 28px;
1035
- border-radius: 8px;
1036
- border: 1px solid
1037
- color-mix(
1038
- in srgb,
1039
- var(--settings-item-icon-accent)
1040
- var(--settings-item-icon-border-strength),
1041
- var(--color-border)
1042
- );
1043
- background-color: color-mix(
1044
- in srgb,
1045
- var(--settings-item-icon-accent) var(--settings-item-icon-bg-strength),
1046
- var(--color-card)
1047
- );
1048
- color: color-mix(
1049
- in srgb,
1050
- var(--settings-item-icon-accent) var(--settings-item-icon-fg-strength),
1051
- var(--color-foreground)
1052
- );
1053
- transition:
1054
- background-color 0.18s ease,
1055
- border-color 0.18s ease,
1056
- color 0.18s ease;
1057
- }
1058
-
1059
- .settings-item-text {
1060
- @apply flex flex-col flex-1 min-w-0;
1061
- gap: 0.08rem;
1062
- }
1063
-
1064
- .settings-item-name {
1065
- font-size: var(--type-base);
1066
- font-weight: var(--fw-medium);
1067
- line-height: 1.3;
1068
- color: var(--color-foreground);
1069
- }
1070
-
1071
- .settings-item-desc {
1072
- font-family: var(--font-ui);
1073
- font-size: var(--type-xs);
1074
- line-height: 1.4;
1075
- color: var(--color-muted-foreground);
1076
- }
1077
-
1078
- .settings-item-chevron {
1079
- @apply shrink-0;
1080
- color: var(--color-muted-foreground);
1081
- opacity: 0.38;
1082
- transition:
1083
- opacity 0.18s ease,
1084
- color 0.18s ease;
1085
- }
1086
-
1087
- .settings-item:hover .settings-item-chevron,
1088
- .settings-item:focus-visible .settings-item-chevron {
1089
- opacity: 0.62;
1090
- color: color-mix(
1091
- in srgb,
1092
- var(--color-foreground) 46%,
1093
- var(--color-muted-foreground)
1094
- );
1095
- }
1096
-
1097
- .settings-export-form {
1098
- display: block;
1099
- }
1100
-
1101
- @media (max-width: 699px) {
1102
- .settings-directory-item {
1103
- gap: 0.62rem;
1104
- padding: 0.78rem 0.52rem 0.78rem 0;
1105
- border-radius: 0.8rem;
1106
- }
1107
-
1108
- .settings-directory-item-icon {
1109
- width: 2.38rem;
1110
- height: 2.38rem;
1111
- }
1112
-
1113
- .settings-root-version {
1114
- text-align: left;
1115
- }
1116
-
1117
- .settings-root-signout {
1118
- justify-content: flex-start;
1119
- }
1120
- }
1121
-
1122
- button.settings-item {
1123
- @apply w-full text-left cursor-pointer;
1124
- background: none;
1125
- border: none;
1126
- font: inherit;
1127
- border-bottom: 1px solid
1128
- color-mix(in srgb, var(--color-border) 78%, transparent);
1129
-
1130
- &:last-child {
1131
- border-bottom: none;
1132
- }
1133
- }
1134
-
1135
- .custom-url-row {
1136
- position: relative;
1137
- display: flex;
1138
- align-items: stretch;
1139
- padding: 0.8rem 0.9rem 0.78rem;
1140
- transition: background-color 0.18s ease;
1141
- border-bottom: 1px solid
1142
- color-mix(in srgb, var(--color-border) 78%, transparent);
1143
-
1144
- &:last-child {
1145
- border-bottom: none;
1146
- }
1147
-
1148
- &:hover {
1149
- background-color: color-mix(
1150
- in srgb,
1151
- var(--site-accent) 4%,
1152
- var(--color-card)
1153
- );
1154
- }
1155
-
1156
- &:focus-within {
1157
- background-color: color-mix(
1158
- in srgb,
1159
- var(--site-accent) 5%,
1160
- var(--color-card)
1161
- );
1162
- }
1163
- }
1164
-
1165
- .custom-url-row-main {
1166
- display: flex;
1167
- flex: 1;
1168
- min-width: 0;
1169
- flex-direction: column;
1170
- gap: 0.28rem;
1171
- padding-right: 2.1rem;
1172
- }
1173
-
1174
- .custom-url-row-header {
1175
- position: relative;
1176
- min-width: 0;
1177
- }
1178
-
1179
- .custom-url-row-flow {
1180
- display: flex;
1181
- flex-direction: column;
1182
- align-items: flex-start;
1183
- gap: 0.16rem;
1184
- min-width: 0;
1185
- padding-top: 0.04rem;
1186
- }
1187
-
1188
- .custom-url-row-target {
1189
- display: flex;
1190
- flex-wrap: wrap;
1191
- align-items: flex-start;
1192
- gap: 0.24rem 0.56rem;
1193
- min-width: 0;
1194
- }
1195
-
1196
- .custom-url-row-menu {
1197
- position: absolute;
1198
- top: -0.18rem;
1199
- right: -0.24rem;
1200
- z-index: 2;
1201
- }
1202
-
1203
- .custom-url-path {
1204
- display: block;
1205
- min-width: 0;
1206
- overflow-wrap: anywhere;
1207
- font-size: var(--type-base);
1208
- line-height: 1.3;
1209
- letter-spacing: -0.018em;
1210
- color: color-mix(
1211
- in srgb,
1212
- var(--color-foreground) 94%,
1213
- var(--site-accent) 6%
1214
- );
1215
- }
1216
-
1217
- .custom-url-target-path {
1218
- display: inline;
1219
- max-width: 100%;
1220
- overflow-wrap: anywhere;
1221
- font-size: var(--type-xs);
1222
- line-height: 1.4;
1223
- letter-spacing: -0.01em;
1224
- color: color-mix(
1225
- in srgb,
1226
- var(--color-foreground) 74%,
1227
- var(--color-muted-foreground)
1228
- );
1229
- }
1230
-
1231
- .custom-url-menu-trigger {
1232
- @apply flex items-center justify-center cursor-pointer;
1233
- width: 1.75rem;
1234
- height: 1.75rem;
1235
- border: 1px solid transparent;
1236
- border-radius: 999px;
1237
- background: transparent;
1238
- color: color-mix(
1239
- in srgb,
1240
- var(--color-muted-foreground) 88%,
1241
- var(--color-foreground)
1242
- );
1243
- transition:
1244
- background-color 0.18s ease,
1245
- border-color 0.18s ease,
1246
- color 0.18s ease;
1247
-
1248
- &:hover {
1249
- background-color: color-mix(
1250
- in srgb,
1251
- var(--site-accent) 5%,
1252
- var(--color-card)
1253
- );
1254
- border-color: color-mix(
1255
- in srgb,
1256
- var(--color-border) 72%,
1257
- var(--site-accent) 12%
1258
- );
1259
- color: var(--color-foreground);
1260
- }
1261
-
1262
- &:focus-visible {
1263
- outline: 2px solid color-mix(in srgb, var(--site-accent) 20%, transparent);
1264
- outline-offset: 2px;
1265
- background-color: color-mix(
1266
- in srgb,
1267
- var(--site-accent) 6%,
1268
- var(--color-card)
1269
- );
1270
- border-color: color-mix(
1271
- in srgb,
1272
- var(--color-border) 72%,
1273
- var(--site-accent) 14%
1274
- );
1275
- color: var(--color-foreground);
1276
- }
1277
- }
1278
-
1279
- .custom-url-flow-arrow {
1280
- @apply flex items-center justify-center;
1281
- width: 0.9rem;
1282
- height: 0.9rem;
1283
- color: color-mix(
1284
- in srgb,
1285
- var(--color-muted-foreground) 82%,
1286
- var(--site-accent) 18%
1287
- );
1288
- opacity: 0.7;
1289
- }
1290
-
1291
- .custom-url-menu {
1292
- position: absolute;
1293
- right: 0;
1294
- top: calc(100% + 0.35rem);
1295
- z-index: 30;
1296
- min-width: 8.5rem;
1297
- padding: 0.35rem;
1298
- border: 1px solid
1299
- color-mix(in srgb, var(--color-border) 84%, var(--site-accent) 8%);
1300
- border-radius: 0.85rem;
1301
- background-color: color-mix(
1302
- in srgb,
1303
- var(--color-card) 98%,
1304
- var(--site-accent) 2%
1305
- );
1306
- box-shadow: 0 20px 38px -28px
1307
- color-mix(in srgb, var(--color-foreground) 26%, transparent);
1308
- }
1309
-
1310
- .custom-url-menu-item {
1311
- @apply w-full text-left cursor-pointer;
1312
- border: none;
1313
- background: transparent;
1314
- border-radius: 0.6rem;
1315
- padding: 0.58rem 0.72rem;
1316
- font-size: var(--type-sm);
1317
- line-height: 1.35;
1318
- color: var(--color-foreground);
1319
- transition:
1320
- background-color 0.18s ease,
1321
- color 0.18s ease;
1322
-
1323
- &:hover,
1324
- &:focus-visible {
1325
- background-color: color-mix(
1326
- in srgb,
1327
- var(--site-accent) 7%,
1328
- var(--color-card)
1329
- );
1330
- color: var(--color-foreground);
1331
- outline: none;
1332
- }
1333
- }
1334
-
1335
- .custom-url-menu-item-danger {
1336
- color: var(--color-destructive);
1337
-
1338
- &:hover,
1339
- &:focus-visible {
1340
- background-color: color-mix(
1341
- in srgb,
1342
- var(--color-destructive) 8%,
1343
- var(--color-card)
1344
- );
1345
- color: var(--color-destructive);
1346
- }
1347
- }
1348
-
1349
- .custom-url-target-meta {
1350
- display: inline-flex;
1351
- flex-wrap: wrap;
1352
- align-items: center;
1353
- gap: 0.38rem;
1354
- min-width: 0;
1355
- }
1356
-
1357
- .custom-url-type-mark {
1358
- display: inline-flex;
1359
- align-items: center;
1360
- gap: 0.26rem;
1361
- font-size: var(--type-2xs);
1362
- line-height: 1.32;
1363
- letter-spacing: 0.02em;
1364
- color: var(--color-muted-foreground);
1365
- }
1366
-
1367
- .custom-url-type-icon {
1368
- flex-shrink: 0;
1369
- color: color-mix(
1370
- in srgb,
1371
- var(--site-accent) 28%,
1372
- var(--color-muted-foreground)
1373
- );
1374
- opacity: 0.9;
1375
- }
1376
-
1377
- .custom-url-redirect-code {
1378
- font-size: var(--type-2xs);
1379
- line-height: 1.3;
1380
- letter-spacing: 0.05em;
1381
- color: var(--color-muted-foreground);
1382
- }
1383
-
1384
- @media (max-width: 640px) {
1385
- .custom-url-row {
1386
- padding-inline: 0.8rem;
1387
- }
1388
-
1389
- .custom-url-row-main {
1390
- padding-right: 1.95rem;
1391
- }
1392
-
1393
- .custom-url-menu {
1394
- min-width: 7.75rem;
1395
- }
1396
- }
1397
- }
1398
-
1399
- /* Admin scoped font rules */
1400
- @layer components {
1401
- .dash-heading {
1402
- font-family: var(--font-ui);
1403
- }
1404
- }
1405
-
1406
- /* Navigation preview — browser-chrome frame for nav preview */
1407
- @layer components {
1408
- .nav-preview {
1409
- @apply border rounded-lg overflow-hidden;
1410
- background-color: var(--color-card);
1411
- }
1412
-
1413
- .nav-preview-chrome {
1414
- @apply flex items-center gap-3 px-4 py-2.5 border-b;
1415
- background-color: var(--color-muted);
1416
- }
1417
-
1418
- .nav-preview-dots {
1419
- @apply flex gap-1.5;
1420
-
1421
- > span {
1422
- @apply block size-2.5 rounded-full;
1423
- background-color: var(--color-muted-foreground);
1424
- opacity: 0.3;
1425
- }
1426
- }
1427
-
1428
- .nav-preview-label {
1429
- @apply text-xs;
1430
- color: var(--color-muted-foreground);
1431
- }
1432
-
1433
- .nav-preview-content {
1434
- @apply px-5 py-3;
1435
- }
1436
-
1437
- .nav-preview-content .site-header-top {
1438
- justify-content: flex-start;
1439
- }
1440
- }
1441
-
1442
- /* Navigation items list — card-style draggable nav items */
1443
- @layer components {
1444
- .nav-items-list {
1445
- @apply flex flex-col gap-2;
1446
- }
1447
-
1448
- .nav-items-list-drop {
1449
- min-height: 3rem;
1450
- border: 1.5px dashed
1451
- color-mix(in srgb, var(--color-border) 60%, transparent);
1452
- border-radius: 0.75rem;
1453
- padding: 0.5rem;
1454
- transition: border-color 0.15s;
1455
- }
1456
-
1457
- .nav-items-list-drop:has(.nav-item) {
1458
- border-color: transparent;
1459
- padding: 0;
1460
- }
1461
-
1462
- .nav-items-empty-hint {
1463
- display: flex;
1464
- align-items: center;
1465
- justify-content: center;
1466
- height: 100%;
1467
- min-height: 2rem;
1468
- font-size: var(--type-xs);
1469
- color: var(--muted-foreground);
1470
- opacity: 0.6;
1471
- text-align: center;
1472
- margin: 0;
1473
- }
1474
-
1475
- .nav-item {
1476
- @apply border rounded-lg;
1477
- }
1478
-
1479
- .nav-item-editing {
1480
- @apply ring-1 ring-ring;
1481
- }
1482
-
1483
- .nav-item-row {
1484
- @apply flex items-center gap-1 px-1 py-1;
1485
- }
1486
-
1487
- .nav-item-handle {
1488
- @apply flex items-center justify-center w-8 h-8 shrink-0 cursor-grab rounded;
1489
- transition: background-color 0.15s;
1490
-
1491
- &:hover {
1492
- background-color: var(--color-accent);
1493
- }
1494
-
1495
- &:active {
1496
- cursor: grabbing;
1497
- }
1498
- }
1499
-
1500
- .nav-item-info {
1501
- @apply flex flex-col flex-1 min-w-0 py-1.5 px-1.5 rounded cursor-pointer;
1502
- transition: background-color 0.15s;
1503
-
1504
- &:hover {
1505
- background-color: var(--color-accent);
1506
- }
1507
- }
1508
-
1509
- .nav-item-toggle {
1510
- @apply flex items-center justify-center w-8 h-8 shrink-0 rounded border-0 bg-transparent cursor-pointer;
1511
- color: var(--color-muted-foreground);
1512
- transition:
1513
- color 0.15s,
1514
- background-color 0.15s;
1515
-
1516
- &:hover {
1517
- color: var(--color-foreground);
1518
- background-color: var(--color-accent);
1519
- }
1520
- }
1521
-
1522
- .nav-item-edit {
1523
- @apply flex flex-col gap-3 px-4 pb-3 pt-3 border-t mx-1 mb-1;
1524
- border-color: var(--color-border);
1525
- }
1526
-
1527
- .nav-suggestions-list {
1528
- @apply flex flex-col gap-2;
1529
- }
1530
-
1531
- .nav-suggestion-item {
1532
- @apply flex items-center justify-between gap-3 rounded-lg border px-3 py-2;
1533
- }
1534
-
1535
- .nav-suggestion-info {
1536
- @apply flex min-w-0 flex-col;
1537
- }
1538
-
1539
- .nav-suggestion-title {
1540
- @apply truncate text-sm font-medium;
1541
- }
1542
-
1543
- .nav-suggestion-meta {
1544
- @apply truncate text-xs text-muted-foreground;
1545
- }
1546
-
1547
- /* Collection picker dropdown menu */
1548
- .collection-picker {
1549
- @apply absolute left-0 z-10 mt-1.5 w-64 overflow-y-auto rounded-lg border py-1.5;
1550
- max-height: 20rem;
1551
- background-color: var(--color-popover);
1552
- box-shadow: var(--shadow-md);
1553
- }
1554
-
1555
- .collection-picker-group {
1556
- @apply px-3 pb-1 pt-3 text-xs font-medium;
1557
- color: var(--color-muted-foreground);
1558
-
1559
- &:first-child {
1560
- padding-top: 0.5rem;
1561
- }
1562
- }
1563
-
1564
- .collection-picker-item {
1565
- @apply flex items-center gap-2 rounded-md text-left border-0 bg-transparent cursor-pointer;
1566
- font-size: 0.9375rem;
1567
- line-height: 1.35;
1568
- padding: 0.5rem 0.625rem;
1569
- margin: 0 0.25rem;
1570
- width: calc(100% - 0.5rem);
1571
- color: var(--color-foreground);
1572
- transition: background-color 0.1s;
1573
-
1574
- &:hover:not(:disabled) {
1575
- background-color: var(--color-accent);
1576
- }
1577
-
1578
- &:disabled {
1579
- opacity: 0.5;
1580
- cursor: not-allowed;
1581
- }
1582
- }
1583
-
1584
- .collection-picker-title {
1585
- @apply truncate flex-1;
1586
- }
1587
-
1588
- .collection-picker-footer {
1589
- @apply sticky mt-1 border-t px-1 pb-1 pt-1;
1590
- bottom: -0.375rem;
1591
- background-color: var(--color-popover);
1592
- }
1593
-
1594
- .collection-picker-create {
1595
- @apply flex w-full cursor-pointer items-center gap-1 rounded-md border-0 bg-transparent px-2 py-1.5 text-left text-sm font-normal;
1596
- color: var(--color-muted-foreground);
1597
- transition:
1598
- background-color 0.1s,
1599
- color 0.1s;
1600
-
1601
- &:hover,
1602
- &:focus-visible {
1603
- background-color: var(--color-accent);
1604
- color: var(--color-foreground);
1605
- outline: none;
1606
- }
1607
- }
1608
-
1609
- /* Page picker — a focused search/create flow inside Navigation settings */
1610
- .nav-page-dialog > .nav-page-dialog-panel {
1611
- width: min(34rem, calc(100% - 2rem));
1612
- gap: 1.25rem;
1613
- }
1614
-
1615
- .nav-page-picker-section {
1616
- min-height: 16rem;
1617
- }
1618
-
1619
- .nav-page-search-wrap {
1620
- @apply relative;
1621
-
1622
- > svg {
1623
- @apply pointer-events-none absolute left-3 top-1/2 -translate-y-1/2;
1624
- color: var(--color-muted-foreground);
1625
- }
1626
- }
1627
-
1628
- .nav-page-search-wrap .nav-page-search-input.nav-page-search-input {
1629
- padding-inline-start: 2.5rem;
1630
- }
1631
-
1632
- .nav-page-results-label {
1633
- @apply mb-1.5 mt-4 text-xs font-medium;
1634
- color: var(--color-muted-foreground);
1635
- }
1636
-
1637
- .nav-page-results {
1638
- @apply -mx-2 flex flex-col gap-1 overflow-y-auto px-2;
1639
- max-height: min(18rem, 42vh);
1640
- }
1641
-
1642
- .nav-page-result {
1643
- @apply flex w-full cursor-pointer items-center justify-between gap-3 rounded-lg border-0 bg-transparent px-3 py-2.5 text-left;
1644
- color: var(--color-foreground);
1645
- transition:
1646
- background-color 0.12s,
1647
- color 0.12s;
1648
-
1649
- &:hover:not(:disabled),
1650
- &:focus-visible,
1651
- &.nav-page-result-selected {
1652
- background-color: var(--color-accent);
1653
- outline: none;
1654
- }
1655
-
1656
- &:disabled {
1657
- cursor: not-allowed;
1658
- opacity: 0.55;
1659
- }
1660
-
1661
- > svg {
1662
- @apply shrink-0;
1663
- color: var(--color-muted-foreground);
1664
- }
1665
- }
1666
-
1667
- .nav-page-result-copy {
1668
- @apply flex min-w-0 flex-col gap-0.5;
1669
- }
1670
-
1671
- .nav-page-result-title {
1672
- @apply truncate text-sm font-medium;
1673
- }
1674
-
1675
- .nav-page-result-path {
1676
- @apply truncate text-xs;
1677
- color: var(--color-muted-foreground);
1678
- }
1679
-
1680
- .nav-page-status {
1681
- @apply flex min-h-44 items-center justify-center px-6 text-center text-sm;
1682
- color: var(--color-muted-foreground);
1683
- }
1684
-
1685
- .nav-page-dialog-footer.nav-page-dialog-footer {
1686
- @apply sm:justify-between;
1687
- }
1688
-
1689
- .nav-page-create-link {
1690
- @apply gap-2;
1691
- }
1692
-
1693
- .nav-page-spinner {
1694
- @apply size-4 shrink-0 animate-spin rounded-full border-2;
1695
- border-color: var(--color-border);
1696
- border-top-color: var(--color-foreground);
1697
- }
1698
-
1699
- .nav-page-slug-field {
1700
- @apply flex items-center overflow-hidden rounded-md border;
1701
- background-color: var(--color-background);
1702
- border-color: var(--color-input);
1703
-
1704
- &:focus-within {
1705
- border-color: var(--color-ring);
1706
- box-shadow: 0 0 0 1px var(--color-ring);
1707
- }
1708
- }
1709
-
1710
- .nav-page-slug-prefix {
1711
- @apply shrink-0 pl-3 text-sm;
1712
- color: var(--color-muted-foreground);
1713
- }
1714
-
1715
- .nav-page-slug-input.nav-page-slug-input {
1716
- @apply min-w-0 flex-1 border-0 pl-0 shadow-none outline-none;
1717
-
1718
- &:focus {
1719
- box-shadow: none;
1720
- }
1721
- }
1722
-
1723
- .nav-page-visibility-note {
1724
- @apply flex items-start gap-2 rounded-lg px-3 py-2.5 text-sm;
1725
- color: var(--color-muted-foreground);
1726
- background-color: var(--color-muted);
1727
-
1728
- > svg {
1729
- @apply mt-0.5 shrink-0;
1730
- }
1731
- }
1732
-
1733
- .nav-collection-dialog > .nav-collection-dialog-panel {
1734
- width: min(32rem, calc(100% - 2rem));
1735
- gap: 1.25rem;
1736
- }
1737
-
1738
- .nav-create-success-header {
1739
- @apply items-center text-center;
1740
- }
1741
-
1742
- .nav-create-success-icon {
1743
- @apply mb-1 flex size-10 items-center justify-center rounded-full;
1744
- color: var(--color-primary);
1745
- background-color: color-mix(in srgb, var(--color-primary) 12%, transparent);
1746
- }
1747
-
1748
- .nav-create-success-card {
1749
- @apply flex flex-col gap-1 rounded-lg border px-4 py-3;
1750
- background-color: var(--color-muted);
1751
- }
1752
- }
1753
-
1754
- /* Skeleton screen sizing — used in SSR fallbacks while Lit hydrates */
1755
- @layer components {
1756
- .skel-label {
1757
- min-height: 1.5rem;
1758
- }
1759
-
1760
- .skel-input {
1761
- height: 2.75rem;
1762
- }
1763
-
1764
- .skel-textarea {
1765
- height: 6rem;
1766
- }
1767
-
1768
- .skel-section-sm {
1769
- min-height: 180px;
1770
- }
1771
-
1772
- .skel-section-md {
1773
- min-height: 200px;
1774
- }
1775
-
1776
- .skel-section-lg {
1777
- min-height: 300px;
1778
- }
226
+ /* Progressive enhancement for the locale picker: the plain <select> beside it
227
+ is the real field until the element upgrades, at which point the element
228
+ hides it and takes over. Keeping the picker out of the layout until then
229
+ avoids showing two controls for one choice. */
230
+ jant-locale-picker:not(:defined) {
231
+ display: none;
1779
232
  }