@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
@@ -0,0 +1,1112 @@
1
+ import{h as e,i as t,n,s as r,t as i,u as a}from"./chunks/lit-DW8VmJAT.js";import{a as o,i as s,r as c,s as l,t as u}from"./chunks/jant-locale-picker-DL6mIOT5.js";import{n as d}from"./chunks/confirm-D7GrwsCN.js";import{_ as f,d as p,h as m,l as h,m as g,p as _,u as v}from"./chunks/types-D5iF3H1a.js";import{r as y,t as b}from"./chunks/create-editor-CD3FhrOB.js";var x={ICO_16:16,ICO_32:32,APPLE_TOUCH:512};function S(e){let t=e.length*16,n=6+t,r=new ArrayBuffer(6+t),i=new DataView(r);i.setUint16(0,0,!0),i.setUint16(2,1,!0),i.setUint16(4,e.length,!0);let a=[];for(let t=0;t<e.length;t++){let r=e[t],o=6+t*16;i.setUint8(o+0,r.size<256?r.size:0),i.setUint8(o+1,r.size<256?r.size:0),i.setUint8(o+2,0),i.setUint8(o+3,0),i.setUint16(o+4,1,!0),i.setUint16(o+6,32,!0),i.setUint32(o+8,r.png.byteLength,!0),i.setUint32(o+12,n,!0),n+=r.png.byteLength,a.push(r.png)}return new Blob([r,...a],{type:`image/x-icon`})}var C=180;function w(e){return new Promise((t,n)=>{let r=new Image;r.onload=()=>{URL.revokeObjectURL(r.src),t(r)},r.onerror=()=>n(Error(`Failed to load image`)),r.src=URL.createObjectURL(e)})}function T(e,t){let n=document.createElement(`canvas`);n.width=t,n.height=t;let r=n.getContext(`2d`);if(!r)throw Error(`Failed to get canvas context`);r.imageSmoothingEnabled=!0,r.imageSmoothingQuality=`high`;let i=Math.max(t/e.width,t/e.height),a=t/i,o=t/i,s=(e.width-a)/2,c=(e.height-o)/2;return r.drawImage(e,s,c,a,o,0,0,t,t),new Promise((e,t)=>{n.toBlob(n=>{n?e(n):t(Error(`Failed to create PNG blob`))},`image/png`)})}function E(e,t){return e.type===`image/png`&&t.width===t.height&&t.width>=C&&t.height>=C}async function D(t,n){let r=t.closest(`form`)?.querySelector(`label`),i=r?.textContent??``;try{r&&(r.textContent=t.dataset.textProcessing||`Processing...`);let i=await w(n),a=n,o=n.name;if(n.type!==`image/svg+xml`){let e=await T(i,512);a=new File([e],n.name.replace(/\.[^.]+$/,`.png`),{type:`image/png`}),o=a.name}let s=E(n,i)?Promise.resolve(n):T(i,x.APPLE_TOUCH),[c,l,u]=await Promise.all([T(i,16),T(i,32),s]),[d,p]=await Promise.all([c.arrayBuffer(),l.arrayBuffer()]),m=S([{size:16,png:d},{size:32,png:p}]);r&&(r.textContent=t.dataset.textUploading||`Uploading...`);let h=new FormData;h.append(`file`,a,o),h.append(`favicon`,m,`favicon.ico`),h.append(`appleTouch`,u,`apple-touch-icon.png`);let g=await fetch(e(`/settings/avatar`),{method:`POST`,headers:{Accept:`application/json`},body:h});if(!g.ok){let e=t.dataset.textError||`Upload failed. Please try again.`;try{let t=await f(g);e=_(t,`error`)??_(t,`message`)??e}catch{}throw Error(e)}let v=await f(g),y=_(v,`status`),b=_(v,`url`);if(y===`redirect`&&b){window.location.href=b;return}window.location.href=e(`/settings/avatar?saved`)}catch(e){r&&(r.textContent=i),a(e instanceof Error&&e.message?e.message:t.dataset.textError||`Upload failed. Please try again.`,`error`)}t.value=``}function O(){document.addEventListener(`change`,e=>{let t=e.target.closest(`[data-avatar-upload]`);t?.files?.[0]&&(e.stopPropagation(),D(t,t.files[0]))})}O();var k=[`latest`,`featured`,`off`];function A(e){let t=e?.trim();return t&&k.includes(t)?t:null}function ee(e){if(e.demoMode||!e.rssFeedsEnabled)return`none`;let t=A(e.storedValue);if(t)return t===`off`?`none`:t;if(e.noindex)return`none`;let n=A(e.defaultValue);return n?n===`off`?`none`:n:`none`}var j={links:`Links`,quotes:`Quotes`};function M(e,t){let n=[],r=t.filter(e=>e.term&&e.href).sort((e,t)=>t.term.length-e.term.length);for(let{term:t,href:i}of r)for(let r=e.indexOf(t);r!==-1;r=e.indexOf(t,r+1)){let e=r+t.length;if(!n.some(t=>r<t.end&&t.start<e)){n.push({start:r,end:e,href:i});break}}n.sort((e,t)=>e.start-t.start);let i=[],a=0;for(let{start:t,end:r,href:o}of n)t>a&&i.push({text:e.slice(a,t)}),i.push({text:e.slice(t,r),href:o}),a=r;return a<e.length&&i.push({text:e.slice(a)}),i}function N(e,t,n){return n?M(e,[{term:t.name,href:n.home},{term:j.links,href:n.links},{term:j.quotes,href:n.quotes},{term:t.rules,href:n.rules}]):[{text:e}]}var P=`flex flex-col py-8 first:pt-0 last:pb-0`,F=class extends i{static properties={labels:{type:Object},timezones:{type:Array},siteNameFallback:{type:String,attribute:`sitename-fallback`},siteDescriptionFallback:{type:String,attribute:`sitedescription-fallback`},demoMode:{type:Boolean,attribute:`demo-mode`},discoverDefault:{type:String,attribute:`discover-default`},discoverPages:{type:Object,attribute:`discover-pages`},discoverStatus:{type:String,attribute:`discover-status`},feedsEnabled:{type:Boolean,attribute:`feeds-enabled`},mainFeedUrl:{type:String,attribute:`main-feed-url`},latestFeedUrl:{type:String,attribute:`latest-feed-url`},featuredFeedUrl:{type:String,attribute:`featured-feed-url`},archiveFeedUrl:{type:String,attribute:`archive-feed-url`},feedsDocsUrl:{type:String,attribute:`feeds-docs-url`},aboutPage:{type:Object,attribute:`about-page`},aboutEditUrl:{type:String,attribute:`about-edit-url`},aboutCreateUrl:{type:String,attribute:`about-create-url`},_siteName:{state:!0},_siteDescription:{state:!0},_siteFooter:{state:!0},_origSite:{state:!0},_siteDirty:{state:!0},_siteLoading:{state:!0},_timeZone:{state:!0},_origLocale:{state:!0},_localeDirty:{state:!0},_localeLoading:{state:!0},_mainRssFeed:{state:!0},_origMainRssFeed:{state:!0},_feedLoading:{state:!0},_showJantBrandingOnHome:{state:!0},_origShowJantBrandingOnHome:{state:!0},_homeLoading:{state:!0},_noindex:{state:!0},_origNoindex:{state:!0},_searchLoading:{state:!0},_discover:{state:!0},_origDiscover:{state:!0},_discoverLoading:{state:!0}};_descEditor=null;_footerEditor=null;createRenderRoot(){return this.innerHTML=``,this}constructor(){super(),this.labels={},this.timezones=[],this.siteNameFallback=``,this.siteDescriptionFallback=``,this.demoMode=!1,this.mainFeedUrl=`/feed`,this.latestFeedUrl=`/latest/feed`,this.featuredFeedUrl=`/featured/feed`,this.archiveFeedUrl=`/archive/feed`,this.feedsDocsUrl=``,this.aboutPage={state:`missing`,path:`/about`},this.aboutEditUrl=`/about?edit=1`,this.aboutCreateUrl=`/settings/general/about-page`,this._siteName=``,this._siteDescription=``,this._siteFooter=``,this._origSite={siteName:``,siteDescription:``,siteFooter:``},this._siteDirty=!1,this._siteLoading=!1,this._timeZone=`UTC`,this._origLocale={timeZone:`UTC`},this._localeDirty=!1,this._localeLoading=!1,this._mainRssFeed=`featured`,this._origMainRssFeed=`featured`,this._feedLoading=!1,this._noindex=!1,this._origNoindex=!1,this._showJantBrandingOnHome=!1,this._origShowJantBrandingOnHome=!1,this._homeLoading=!1,this._searchLoading=!1,this.discoverDefault=``,this.discoverPages=null,this.discoverStatus=``,this.feedsEnabled=!1,this._discover=``,this._origDiscover=``,this._discoverLoading=!1}connectedCallback(){super.connectedCallback()}disconnectedCallback(){super.disconnectedCallback(),this._descEditor?.destroy(),this._descEditor=null,this._footerEditor?.destroy(),this._footerEditor=null}initData(e){this._siteName=e.siteName,this._siteDescription=e.siteDescription,this._siteFooter=e.siteFooter,this._timeZone=e.timeZone,this._origLocale={timeZone:e.timeZone},this._mainRssFeed=e.mainRssFeed,this._origMainRssFeed=e.mainRssFeed,this._showJantBrandingOnHome=e.showJantBrandingOnHome,this._origShowJantBrandingOnHome=e.showJantBrandingOnHome,this._noindex=e.noindex,this._origNoindex=e.noindex,this._discover=e.discover,this._origDiscover=e.discover,this.updateComplete.then(()=>{this._initEditors(),this._origSite={siteName:e.siteName,siteDescription:this._siteDescription,siteFooter:this._siteFooter}})}sectionSaved(e){e===`site`?(this._origSite={siteName:this._siteName,siteDescription:this._siteDescription,siteFooter:this._siteFooter},this._siteDirty=!1,this._siteLoading=!1):e===`time`?(this._origLocale={timeZone:this._timeZone},this._localeDirty=!1,this._localeLoading=!1):e===`feeds`?(this._origMainRssFeed=this._mainRssFeed,this._feedLoading=!1):e===`home`?(this._origShowJantBrandingOnHome=this._showJantBrandingOnHome,this._homeLoading=!1):e===`search`?(this._origNoindex=this._noindex,this._searchLoading=!1):e===`discover`&&(this._origDiscover=this._discover,this._discoverLoading=!1)}sectionError(e){e===`site`?this._siteLoading=!1:e===`time`?this._localeLoading=!1:e===`feeds`?(this._mainRssFeed=this._origMainRssFeed,this._feedLoading=!1):e===`home`?(this._showJantBrandingOnHome=this._origShowJantBrandingOnHome,this._homeLoading=!1):e===`search`?(this._noindex=this._origNoindex,this._searchLoading=!1):e===`discover`&&(this._discover=this._origDiscover,this._discoverLoading=!1)}_initEditors(){this._initDescEditor(),this._initFooterEditor()}_initDescEditor(){let e=this.querySelector(`[data-settings-desc-editor]`);if(!e||this._descEditor)return;this._descEditor=b({element:e,placeholder:this.siteDescriptionFallback,content:this._siteDescription||void 0,onUpdate:e=>{this._siteDescription=e,this._syncSiteDirty()}}),this._siteDescription=y(this._descEditor.getJSON());let t=e.querySelector(`.ProseMirror`);t&&(t.style.outline=`none`,t.style.minHeight=`3rem`)}_initFooterEditor(){let e=this.querySelector(`[data-settings-footer-editor]`);if(!e||this._footerEditor)return;this._footerEditor=b({element:e,content:this._siteFooter||void 0,onUpdate:e=>{this._siteFooter=e,this._syncSiteDirty()}}),this._siteFooter=y(this._footerEditor.getJSON());let t=e.querySelector(`.ProseMirror`);t&&(t.style.outline=`none`,t.style.minHeight=`6rem`)}_syncSiteDirty(){this._siteDirty=this._siteName!==this._origSite.siteName||this._siteDescription!==this._origSite.siteDescription||this._siteFooter!==this._origSite.siteFooter}_saveSite(){!this._siteLoading&&this._siteDirty&&(this._siteLoading=!0,this.dispatchEvent(new CustomEvent(`jant:settings-save`,{bubbles:!0,detail:{endpoint:`/settings/general`,data:{siteName:this._siteName,siteDescription:this._siteDescription,siteFooter:this._siteFooter},section:`site`}})))}_syncLocaleDirty(){this._localeDirty=this._timeZone!==this._origLocale.timeZone}_saveLocale(){!this._localeLoading&&this._localeDirty&&(this._localeLoading=!0,this.dispatchEvent(new CustomEvent(`jant:settings-save`,{bubbles:!0,detail:{endpoint:`/settings/general/time`,data:{timeZone:this._timeZone},section:`time`}})))}_saveMainRssFeed(e){this._feedLoading||e===this._mainRssFeed||(this._mainRssFeed=e,this._feedLoading=!0,this.dispatchEvent(new CustomEvent(`jant:settings-save`,{bubbles:!0,detail:{endpoint:`/settings/general/feeds`,data:{mainRssFeed:e},section:`feeds`}})))}_saveHomeToggle(e){this._homeLoading||(this._showJantBrandingOnHome=e,this._homeLoading=!0,this.dispatchEvent(new CustomEvent(`jant:settings-save`,{bubbles:!0,detail:{endpoint:`/settings/general/home`,data:{showJantBrandingOnHome:e},section:`home`}})))}_saveSearchToggle(e){this.demoMode||this._searchLoading||(this._noindex=!e,this._searchLoading=!0,this.dispatchEvent(new CustomEvent(`jant:settings-save`,{bubbles:!0,detail:{endpoint:`/settings/general/search`,data:{allowIndexing:e},section:`search`}})))}_effectiveDiscoverMode(e={}){return ee({storedValue:this._discover||null,defaultValue:this.discoverDefault||null,demoMode:this.demoMode,noindex:e.noindex??this._noindex,rssFeedsEnabled:this.feedsEnabled})}_onDiscoverToggle(e){this._saveDiscover(e?`latest`:`off`)}_saveDiscover(e){this._discoverLoading||(this._discover=e,this._discoverLoading=!0,this.dispatchEvent(new CustomEvent(`jant:settings-save`,{bubbles:!0,detail:{endpoint:`/settings/general/discover`,data:{discover:e},section:`discover`}})))}_onKeydown(e,t,n,r){e.isComposing||e.keyCode===229||e.key===`Enter`&&!r&&n&&!(e.target instanceof HTMLTextAreaElement)&&(e.preventDefault(),t())}_renderSaveAction(e,r,i){return t`
2
+ <div class="flex mt-4">
3
+ <button
4
+ type="button"
5
+ class="btn"
6
+ ?disabled=${e||!r}
7
+ @click=${i}
8
+ >
9
+ ${e?t`<svg
10
+ class="animate-spin size-4"
11
+ xmlns="http://www.w3.org/2000/svg"
12
+ viewBox="0 0 24 24"
13
+ fill="none"
14
+ stroke="currentColor"
15
+ stroke-width="2"
16
+ stroke-linecap="round"
17
+ stroke-linejoin="round"
18
+ role="status"
19
+ >
20
+ <path d="M21 12a9 9 0 1 1-6.219-8.56" />
21
+ </svg>`:n}
22
+ ${this.labels.save}
23
+ </button>
24
+ </div>
25
+ `}_renderSectionTitle(e){return t`<h3 class="text-sm font-semibold tracking-[0.01em]">
26
+ ${e}
27
+ </h3>`}_renderMainRssFeedOption(e,n,r){let i=this._mainRssFeed===e;return t`
28
+ <label
29
+ class=${`flex items-start gap-3 rounded-xl border p-3 cursor-pointer transition-colors ${i?`border-primary`:`border-border`}`}
30
+ >
31
+ <input
32
+ type="radio"
33
+ name="main-rss-feed"
34
+ value=${e}
35
+ class="mt-1"
36
+ .checked=${i}
37
+ ?disabled=${this._feedLoading}
38
+ @change=${()=>this._saveMainRssFeed(e)}
39
+ />
40
+ <div>
41
+ <div class="font-medium">${n}</div>
42
+ <div class="text-sm text-muted-foreground">${r}</div>
43
+ </div>
44
+ </label>
45
+ `}_renderFeedUrl(e,n,r){return t`
46
+ <div class=${s} data-copy-field-root>
47
+ <p class="text-sm font-medium">${e}</p>
48
+ ${r?t`<p class="text-sm text-muted-foreground">${r}</p>`:``}
49
+ <div class=${o}>
50
+ <input
51
+ type="text"
52
+ class=${l}
53
+ .value=${n}
54
+ readonly
55
+ aria-label=${e}
56
+ data-copy-field-value
57
+ />
58
+ <button
59
+ type="button"
60
+ class=${c}
61
+ data-copy-field=${this.labels.feedUrlCopied}
62
+ data-copy-field-failed=${this.labels.copyFailed}
63
+ >
64
+ ${this.labels.copy}
65
+ </button>
66
+ </div>
67
+ </div>
68
+ `}_renderAboutPageRow(){let e=this.aboutPage;return t`
69
+ <div class="mt-2 text-sm text-muted-foreground" data-about-page-row>
70
+ ${this.labels.aboutPagePrompt}
71
+ ${e.state===`ready`?t`
72
+ <a
73
+ class="font-medium text-foreground underline-offset-4 hover:underline"
74
+ href=${this.aboutEditUrl}
75
+ >
76
+ ${this.labels.editAboutPage}
77
+ </a>
78
+ `:e.state===`missing`?t`
79
+ <form
80
+ class="inline"
81
+ method="post"
82
+ action=${this.aboutCreateUrl}
83
+ >
84
+ <button
85
+ type="submit"
86
+ class="inline cursor-pointer border-0 bg-transparent p-0 font-medium text-foreground underline-offset-4 hover:underline"
87
+ >
88
+ ${this.labels.createAboutPage}
89
+ </button>
90
+ </form>
91
+ `:t`
92
+ <span class="text-destructive"
93
+ >${this.labels.aboutPageConflict}</span
94
+ >
95
+ `}
96
+ </div>
97
+ `}_renderSiteSection(){return t`
98
+ <section
99
+ class="${P} gap-4"
100
+ @keydown=${e=>this._onKeydown(e,()=>this._saveSite(),this._siteDirty,this._siteLoading)}
101
+ >
102
+ ${this._renderSectionTitle(this.labels.site)}
103
+ <div class="field">
104
+ <label class="label">${this.labels.siteName}</label>
105
+ <input
106
+ type="text"
107
+ class="input"
108
+ maxlength=${120}
109
+ .value=${this._siteName}
110
+ placeholder=${this.siteNameFallback}
111
+ @input=${e=>{this._siteName=e.target.value,this._syncSiteDirty()}}
112
+ />
113
+ </div>
114
+
115
+ <div class="field">
116
+ <label class="label">${this.labels.aboutBlog}</label>
117
+ <div class="settings-tiptap-editor" data-settings-desc-editor></div>
118
+ <p class="text-sm text-muted-foreground mt-1">
119
+ ${this.labels.aboutBlogHelp}
120
+ </p>
121
+ ${this._renderAboutPageRow()}
122
+ </div>
123
+
124
+ <div class="field">
125
+ <label class="label">${this.labels.siteFooter}</label>
126
+ <div class="settings-tiptap-editor" data-settings-footer-editor></div>
127
+ <p class="text-sm text-muted-foreground mt-1">
128
+ ${this.labels.footerHelp}
129
+ </p>
130
+ </div>
131
+
132
+ ${this._renderSaveAction(this._siteLoading,this._siteDirty,()=>this._saveSite())}
133
+ </section>
134
+ `}_renderVisibilitySection(){return t`
135
+ <section class="${P} gap-6">
136
+ ${this._renderSectionTitle(this.labels.siteVisibility)}
137
+ <div class="flex flex-col gap-2">
138
+ <label class="flex items-center gap-2 cursor-pointer">
139
+ <input
140
+ type="checkbox"
141
+ class="checkbox"
142
+ .checked=${!this._noindex}
143
+ ?disabled=${this.demoMode||this._searchLoading}
144
+ @change=${e=>this._saveSearchToggle(e.target.checked)}
145
+ />
146
+ <span>${this.labels.allowIndexing}</span>
147
+ </label>
148
+ ${this.demoMode?t`<p class="text-sm text-muted-foreground">
149
+ ${this.labels.demoSeoLocked}
150
+ </p>`:n}
151
+ </div>
152
+ ${this._renderDiscoverForm()}
153
+ </section>
154
+ `}_renderFeedsSection(){return t`
155
+ <section class="${P} gap-4">
156
+ ${this._renderSectionTitle(this.labels.feeds)}
157
+ <div class="field">
158
+ <p class="label">${this.labels.mainRssFeed}</p>
159
+ <p class="text-sm text-muted-foreground mt-1">
160
+ ${this.labels.mainRssFeedHelp}
161
+ </p>
162
+ <div class="mt-3 flex flex-col gap-2">
163
+ ${this._renderMainRssFeedOption(`featured`,this.labels.featuredFeedOption,this.labels.featuredFeedOptionDescription)}
164
+ ${this._renderMainRssFeedOption(`latest`,this.labels.latestFeedOption,this.labels.latestFeedOptionDescription)}
165
+ </div>
166
+ <p class="text-sm text-muted-foreground mt-2">
167
+ ${this.labels.mainRssFeedWarning}
168
+ </p>
169
+ </div>
170
+
171
+ <div class="rounded-xl border border-border/70 bg-muted/30 p-4">
172
+ <div class="flex flex-col gap-4">
173
+ <div class="flex flex-col gap-1">
174
+ <p class="text-sm font-medium">
175
+ ${this.labels.availableFeedUrls}
176
+ </p>
177
+ <p class="text-sm text-muted-foreground">
178
+ ${this.labels.availableFeedUrlsHelp}
179
+ ${this.feedsDocsUrl?t`
180
+ <a
181
+ href=${this.feedsDocsUrl}
182
+ target="_blank"
183
+ rel="noopener noreferrer"
184
+ class="underline hover:text-foreground transition-colors"
185
+ >${this.labels.feedsDocs}</a
186
+ >
187
+ `:``}
188
+ </p>
189
+ </div>
190
+
191
+ ${this._renderFeedUrl(this.labels.mainFeedUrl,this.mainFeedUrl)}
192
+ ${this._renderFeedUrl(this.labels.latestFeedUrl,this.latestFeedUrl)}
193
+ ${this._renderFeedUrl(this.labels.featuredFeedUrl,this.featuredFeedUrl)}
194
+ ${this._renderFeedUrl(this.labels.archiveFeedUrl,this.archiveFeedUrl,this.labels.archiveFeedUrlHelp)}
195
+ </div>
196
+ </div>
197
+ </section>
198
+ `}_renderTimeSection(){return t`
199
+ <section
200
+ class="${P} gap-4"
201
+ @keydown=${e=>this._onKeydown(e,()=>this._saveLocale(),this._localeDirty,this._localeLoading)}
202
+ >
203
+ ${this._renderSectionTitle(this.labels.timeSection)}
204
+ <div class="field">
205
+ <label class="label">${this.labels.timeZone}</label>
206
+ <select
207
+ class="select"
208
+ @change=${e=>{this._timeZone=e.target.value,this._syncLocaleDirty()}}
209
+ >
210
+ ${this.timezones.map(e=>t`
211
+ <option
212
+ value=${e.value}
213
+ ?selected=${this._timeZone===e.value}
214
+ >
215
+ ${e.label}
216
+ </option>
217
+ `)}
218
+ </select>
219
+ </div>
220
+
221
+ ${this._renderSaveAction(this._localeLoading,this._localeDirty,()=>this._saveLocale())}
222
+ </section>
223
+ `}_renderHomeSection(){return t`
224
+ <section class="${P} gap-4">
225
+ ${this._renderSectionTitle(this.labels.home)}
226
+ <label class="flex items-center gap-2 cursor-pointer">
227
+ <input
228
+ type="checkbox"
229
+ class="checkbox"
230
+ .checked=${this._showJantBrandingOnHome}
231
+ ?disabled=${this._homeLoading}
232
+ @change=${e=>this._saveHomeToggle(e.target.checked)}
233
+ />
234
+ <span>${this.labels.showJantBrandingOnHome}</span>
235
+ </label>
236
+ </section>
237
+ `}_renderDiscoverForm(){let e=this._effectiveDiscoverMode()!==`none`,r=this.demoMode||!this.feedsEnabled,i=!r&&!e&&this._effectiveDiscoverMode({noindex:!1})!==`none`;return t`
238
+ <div class="flex flex-col gap-3">
239
+ <div class="flex flex-col gap-2">
240
+ <label class="flex items-center gap-2 cursor-pointer">
241
+ <input
242
+ type="checkbox"
243
+ class="checkbox"
244
+ .checked=${e}
245
+ ?disabled=${r||this._discoverLoading}
246
+ @change=${e=>this._onDiscoverToggle(e.target.checked)}
247
+ />
248
+ <span>${this.labels.discoverEnabled}</span>
249
+ </label>
250
+ <p class="text-sm text-muted-foreground">
251
+ ${r?this.demoMode?this.labels.discoverDemoLocked:this.labels.discoverFeedsOffLocked:this._renderDiscoverIntro()}
252
+ </p>
253
+ ${i?t`<p class="text-sm text-muted-foreground">
254
+ ${this.labels.discoverSearchOff}
255
+ </p>`:n}
256
+ </div>
257
+ ${r?n:this._renderDiscoverStatus()}
258
+ </div>
259
+ `}_renderDiscoverIntro(){return N(this.labels.discoverIntro??``,{name:this.labels.discoverName??``,rules:this.labels.discoverRules??``},this.discoverPages).map(e=>e.href?t`<a
260
+ href=${e.href}
261
+ target="_blank"
262
+ rel="noopener noreferrer"
263
+ class="underline hover:text-foreground transition-colors"
264
+ >${e.text}</a
265
+ >`:e.text)}_renderDiscoverStatus(){let e=this._parsedDiscoverStatus();return!e||this._effectiveDiscoverMode()===`none`||e.lines.length===0&&!e.showAnnounce?n:t`
266
+ <div class="flex flex-col gap-1 border-t pt-3">
267
+ ${e.lines.map(e=>t`<p class="text-sm text-muted-foreground">${e}</p>`)}
268
+ ${e.showAnnounce?t`
269
+ <div class="flex flex-wrap items-center gap-3 mt-1">
270
+ <button
271
+ type="button"
272
+ class="btn-outline"
273
+ ?disabled=${this._discoverLoading}
274
+ @click=${()=>this._announce()}
275
+ >
276
+ ${this.labels.discoverAnnounce}
277
+ </button>
278
+ ${e.submitUrl?t`<a
279
+ class="text-sm underline hover:text-foreground transition-colors"
280
+ href=${e.submitUrl}
281
+ target="_blank"
282
+ rel="noopener noreferrer"
283
+ >${this.labels.discoverAnnounceManual}</a
284
+ >`:n}
285
+ </div>
286
+ `:n}
287
+ </div>
288
+ `}_parsedDiscoverStatus(){if(!this.discoverStatus)return null;try{let e=JSON.parse(this.discoverStatus);if(typeof e!=`object`||!e)return null;let t=e;return{lines:Array.isArray(t.lines)?t.lines.filter(e=>typeof e==`string`):[],showAnnounce:t.showAnnounce===!0,submitUrl:typeof t.submitUrl==`string`?t.submitUrl:null}}catch{return null}}_announce(){this._discoverLoading||(this._discoverLoading=!0,this.dispatchEvent(new CustomEvent(`jant:settings-save`,{bubbles:!0,detail:{endpoint:`/settings/general/discover/announce`,data:{},section:`discover`}})))}render(){return t`
289
+ <div class="flex flex-col gap-8">
290
+ <h2 class="text-lg font-semibold">${this.labels.general}</h2>
291
+ <div class="flex flex-col divide-y">
292
+ ${this._renderSiteSection()} ${this._renderVisibilitySection()}
293
+ ${this._renderFeedsSection()} ${this._renderTimeSection()}
294
+ ${this._renderHomeSection()}
295
+ </div>
296
+ </div>
297
+ `}};customElements.define(`jant-settings-general`,F);var I=`${typeof __JANT_DEV__<`u`&&__JANT_DEV__===!0?`https://jant-cloud.localtest.me`:`https://jant.me`}/docs`;function L(e=``){return e?`${I}/${e}`:I}var R=[``,`en`,`zh-Hans`,`zh-Hant`],z=L(`multilingual`);function B(e,t){return e.replace(/\{(\w+)\}/g,(e,n)=>t[n]??e)}var V=class extends i{static properties={labels:{type:Object},locales:{type:Array},_contentLanguage:{state:!0},_dashboardLanguage:{state:!0},_multilingualEnabled:{state:!0},_additional:{state:!0},_unmarkedPostCount:{state:!0},_sitePathPrefix:{state:!0},_savingSite:{state:!0},_savingDashboard:{state:!0},_removeError:{state:!0},_rowMenuOpen:{state:!0},_enableError:{state:!0},_enableOpen:{state:!0},_enableAdditional:{state:!0},_enablePrimary:{state:!0},_enableBusy:{state:!0}};#e=z;createRenderRoot(){return this.innerHTML=``,this}constructor(){super(),this.labels={},this.locales=[],this._contentLanguage=`en`,this._dashboardLanguage=``,this._multilingualEnabled=!1,this._additional=[],this._unmarkedPostCount=0,this._sitePathPrefix=``,this._savingSite=!1,this._savingDashboard=!1,this._removeError=null,this._rowMenuOpen=null,this._enableError=null,this._enableOpen=!1,this._enableAdditional=[],this._enablePrimary=`en`,this._enableBusy=!1}connectedCallback(){super.connectedCallback(),this.#t(),document.addEventListener(`click`,this.#s),document.addEventListener(`keydown`,this.#c)}disconnectedCallback(){super.disconnectedCallback(),document.removeEventListener(`click`,this.#s),document.removeEventListener(`keydown`,this.#c)}#t(){let e=document.getElementById(`language-settings-initial-data`);if(!e?.textContent)return;let t;try{t=JSON.parse(e.textContent)}catch{return}let n=t;this._contentLanguage=n.contentLanguage??`en`,this._dashboardLanguage=n.dashboardLanguage??``,this._multilingualEnabled=n.multilingualEnabled??!1,this._additional=Array.isArray(n.additionalLanguages)?[...n.additionalLanguages]:[],this._unmarkedPostCount=n.unmarkedPostCount??0,this._sitePathPrefix=n.sitePathPrefix??``,this.#e=n.multilingualDocsUrl||z}#n(e){return this.locales.find(t=>t.tag===e)??{tag:e,native:e,english:e,coverage:0}}#r(e){let t=this.#n(e);return t.native||t.tag}#i(e){return`${this._sitePathPrefix}/${e.toLowerCase()}`}#a(e){return`${this._sitePathPrefix}/settings/language${e}`}#o(){return this.querySelector(`jant-locale-picker[open]`)!==null}#s=e=>{if(!this._rowMenuOpen)return;let t=e.target;t&&this.contains(t)&&t.closest?.(`[data-row-menu]`)||(this._rowMenuOpen=null)};#c=e=>{if(e.key===`Escape`){if(this._rowMenuOpen){e.stopPropagation(),this._rowMenuOpen=null;return}this._enableOpen&&(e.stopPropagation(),this.#_())}};#l(e){this._rowMenuOpen=this._rowMenuOpen===e?null:e}async#u(e,t){try{let n=await fetch(this.#a(e),{method:`POST`,headers:{"Content-Type":`application/json`,Accept:`application/json`},body:JSON.stringify(t)}),r=await f(n);return n.ok?{ok:!0,message:_(r,`toast`)}:{ok:!1,message:_(r,`error`)??`HTTP ${n.status}`,language:_(r,`language`)}}catch{return{ok:!1,message:`Couldn't reach the server. Try again.`}}}async#d(e){if(this._removeError=null,e===this._contentLanguage)return;if(this._multilingualEnabled){let t=this._contentLanguage;if(!await d({title:this.labels.changePrimaryTitle,message:B(this.labels.changePrimaryBody,{next:this.#r(e),previous:this.#r(t),prefix:this.#i(t)}),confirmLabel:this.labels.changePrimaryConfirm,cancelLabel:this.labels.cancel}))return;this._savingSite=!0;let n=await this.#u(`/primary`,{language:e});if(this._savingSite=!1,!n.ok){a(n.message??``,`error`);return}this._additional=[...this._additional.filter(t=>t!==e),t],this._contentLanguage=e,n.message&&a(n.message);return}this._savingSite=!0;let t=this._contentLanguage;this._contentLanguage=e;let n=await this.#u(``,{contentLanguage:e});if(this._savingSite=!1,!n.ok){this._contentLanguage=t,a(n.message??``,`error`);return}n.message&&a(n.message)}async#f(e){let t=this._dashboardLanguage;this._dashboardLanguage=e,this._savingDashboard=!0;let n=await this.#u(``,{dashboardLanguage:e});if(this._savingDashboard=!1,!n.ok){this._dashboardLanguage=t,a(n.message??``,`error`);return}window.location.reload()}async#p(e){this._removeError=null;let t=await this.#u(`/add`,{language:e});if(!t.ok){a(t.message??``,`error`);return}this._additional=[...this._additional,e],t.message&&a(t.message)}async#m(e){this._removeError=null;let t=this._multilingualEnabled&&this._additional.length===1&&this._additional[0]===e;if(t&&!await d({title:this.labels.removeLastTitle,message:B(this.labels.removeLastBody,{language:this.#r(e),prefix:this.#i(e)}),confirmLabel:this.labels.removeLastConfirm,cancelLabel:this.labels.cancel}))return;let n=await this.#u(`/remove`,{language:e});if(!n.ok){this._removeError={tag:e,message:n.message??``};return}if(this._additional=this._additional.filter(t=>t!==e),t){this._multilingualEnabled=!1,n.message&&r(n.message),window.location.reload();return}n.message&&a(n.message)}async#h(){if(this._removeError=null,!await d({title:this.labels.disableTitle,message:B(this.labels.disableBody,{prefix:this.#i(this._additional[0]??`en`)}),confirmLabel:this.labels.disableConfirm,cancelLabel:this.labels.cancel}))return;let e=await this.#u(`/disable`,{});if(!e.ok){a(e.message??``,`error`);return}this._multilingualEnabled=!1,e.message&&r(e.message),window.location.reload()}#g(){this._removeError=null,this._enableError=null,this._enablePrimary=this._contentLanguage,this._enableAdditional=[...this._additional],this._enableOpen=!0,this.updateComplete.then(()=>{let e=this.querySelector(`[data-enable-dialog]`);e&&!e.open&&e.showModal(),e?.querySelector(`[data-enable-panel]`)?.focus()})}#_(){let e=this.querySelector(`[data-enable-dialog]`);e?.open&&e.close(),this._enableOpen=!1}async#v(){if(this._enableAdditional.length===0||this._enableBusy)return;this._enableBusy=!0,this._enableError=null;let e=await this.#u(`/enable`,{primary:this._enablePrimary,additional:this._enableAdditional});if(this._enableBusy=!1,!e.ok){this._enableError={message:e.message??``,...e.language?{language:e.language}:{}};return}this._contentLanguage=this._enablePrimary,this._additional=[...this._enableAdditional],this._multilingualEnabled=!0,this._unmarkedPostCount=0,this.#_(),e.message&&r(e.message),window.location.reload()}get#y(){return this.#b??={search:this.labels.searchPlaceholder,empty:this.labels.noMatches},this.#b}#b=null;#x(e){return t`
298
+ <jant-locale-picker
299
+ .locales=${this.locales}
300
+ .labels=${this.#y}
301
+ .value=${e.current??``}
302
+ .exclude=${[...e.exclude]}
303
+ .triggerLabel=${e.triggerLabel??``}
304
+ .triggerClass=${e.triggerClass}
305
+ .labelledby=${e.labelId}
306
+ @locale-select=${t=>e.onSelect(t.detail.tag)}
307
+ ></jant-locale-picker>
308
+ `}#S(e){return t`
309
+ <div class="flex flex-wrap items-center gap-2" role="alert">
310
+ <p class="text-sm text-destructive">${e.message}</p>
311
+ ${e.language?t`
312
+ <button
313
+ type="button"
314
+ class="btn-sm-outline"
315
+ data-enable-add-back
316
+ @click=${()=>this.#C(e.language??``)}
317
+ >
318
+ ${B(this.labels.addMissingLanguage,{language:this.#r(e.language)})}
319
+ </button>
320
+ `:n}
321
+ </div>
322
+ `}#C(e){e&&(this._enableError=null,!(e===this._enablePrimary||this._enableAdditional.includes(e))&&(this._enableAdditional=[...this._enableAdditional,e]))}#w(){if(!this._enableOpen)return n;let e=this._unmarkedPostCount>0?B(this.labels.enableMarkWarning,{language:this.#r(this._enablePrimary)}):null;return t`
323
+ <dialog
324
+ class="dialog confirm-dialog"
325
+ data-enable-dialog
326
+ @cancel=${e=>{e.preventDefault(),this.#_()}}
327
+ @click=${e=>{e.target===e.currentTarget&&this.#_()}}
328
+ @keydown=${e=>{e.key===`Enter`&&!e.shiftKey&&!this.#o()&&(e.preventDefault(),this.#v())}}
329
+ >
330
+ <div
331
+ class="confirm-dialog-panel"
332
+ data-enable-panel
333
+ tabindex="-1"
334
+ role="document"
335
+ aria-labelledby="language-enable-title"
336
+ >
337
+ <header class="confirm-dialog-header">
338
+ <h2 id="language-enable-title" class="confirm-dialog-title">
339
+ ${this.labels.enableTitle}
340
+ </h2>
341
+ </header>
342
+
343
+ <div class="flex flex-col gap-4 py-2">
344
+ <div class="field">
345
+ <span id="language-enable-primary-label" class="label"
346
+ >${this.labels.primaryLanguage}</span
347
+ >
348
+ ${this.#x({labelId:`language-enable-primary-label`,current:this._enablePrimary,exclude:this._enableAdditional,triggerLabel:this.#r(this._enablePrimary),triggerClass:u,onSelect:e=>{this._enablePrimary=e,this._enableAdditional=this._enableAdditional.filter(t=>t!==e)}})}
349
+ <p class="text-sm text-muted-foreground mt-1">
350
+ ${this.labels.primaryLanguageHelp}
351
+ </p>
352
+ </div>
353
+
354
+ <div class="field">
355
+ <span id="language-enable-add-label" class="label"
356
+ >${this.labels.otherLanguages}</span
357
+ >
358
+ <div class="flex flex-wrap items-center gap-2">
359
+ ${this._enableAdditional.map(e=>t`
360
+ <span class="badge-secondary gap-1">
361
+ ${this.#r(e)}
362
+ <button
363
+ type="button"
364
+ class="cursor-pointer opacity-70 hover:opacity-100"
365
+ aria-label=${B(this.labels.removeLanguage,{language:this.#r(e)})}
366
+ @click=${()=>{this._enableAdditional=this._enableAdditional.filter(t=>t!==e)}}
367
+ >
368
+ ×
369
+ </button>
370
+ </span>
371
+ `)}
372
+ ${this.#x({labelId:`language-enable-add-label`,exclude:[this._enablePrimary,...this._enableAdditional],triggerLabel:`+ ${this.labels.addLanguage}`,triggerClass:`btn-sm-outline`,onSelect:e=>{this._enableAdditional=[...this._enableAdditional,e]}})}
373
+ </div>
374
+ </div>
375
+
376
+ ${e?t`
377
+ <div class="alert">
378
+ <svg
379
+ xmlns="http://www.w3.org/2000/svg"
380
+ viewBox="0 0 24 24"
381
+ fill="none"
382
+ stroke="currentColor"
383
+ stroke-width="2"
384
+ stroke-linecap="round"
385
+ stroke-linejoin="round"
386
+ aria-hidden="true"
387
+ >
388
+ <path
389
+ d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3"
390
+ />
391
+ <path d="M12 9v4" />
392
+ <path d="M12 17h.01" />
393
+ </svg>
394
+ <strong>${this.labels.enableMarkTitle}</strong>
395
+ <section>
396
+ <p>${e}</p>
397
+ <p>${this.labels.enableFixHint}</p>
398
+ </section>
399
+ </div>
400
+ `:n}
401
+
402
+ <p class="text-sm text-muted-foreground">
403
+ ${this.labels.enableReassurance}
404
+ </p>
405
+
406
+ ${this._enableAdditional.length===0?t`<p class="text-sm text-muted-foreground">
407
+ ${this.labels.enableNeedsLanguage}
408
+ </p>`:n}
409
+ ${this._enableError?this.#S(this._enableError):n}
410
+ </div>
411
+
412
+ <footer class="confirm-dialog-actions">
413
+ <button
414
+ type="button"
415
+ class="btn-outline"
416
+ @click=${()=>this.#_()}
417
+ >
418
+ ${this.labels.cancel}
419
+ </button>
420
+ <button
421
+ type="button"
422
+ class="btn"
423
+ data-enable-confirm
424
+ ?disabled=${this._enableAdditional.length===0||this._enableBusy}
425
+ @click=${()=>void this.#v()}
426
+ >
427
+ ${this._enableBusy?this.labels.saving:this.labels.save}
428
+ </button>
429
+ </footer>
430
+ </div>
431
+ </dialog>
432
+ `}#T(e){let r=this._rowMenuOpen===e,i=this.#r(e);return t`
433
+ <span class="relative ml-auto flex items-center" data-row-menu>
434
+ <button
435
+ type="button"
436
+ class="btn-sm-ghost text-muted-foreground"
437
+ aria-haspopup="menu"
438
+ aria-expanded=${r?`true`:`false`}
439
+ aria-label=${B(this.labels.languageMenu,{language:i})}
440
+ data-language-menu
441
+ @click=${()=>this.#l(e)}
442
+ >
443
+ ⋯
444
+ </button>
445
+ ${r?t`
446
+ <div
447
+ role="menu"
448
+ class="absolute right-0 top-full z-20 mt-1 min-w-40 rounded-md border bg-popover py-1 text-popover-foreground shadow-md"
449
+ >
450
+ <button
451
+ type="button"
452
+ role="menuitem"
453
+ class="block w-full cursor-pointer px-3 py-2 text-left text-sm hover:bg-accent"
454
+ ?disabled=${this._savingSite}
455
+ @click=${()=>{this._rowMenuOpen=null,this.#d(e)}}
456
+ >
457
+ ${this.labels.makePrimary}
458
+ </button>
459
+ <button
460
+ type="button"
461
+ role="menuitem"
462
+ class="block w-full cursor-pointer px-3 py-2 text-left text-sm text-destructive hover:bg-accent"
463
+ @click=${()=>{this._rowMenuOpen=null,this.#m(e)}}
464
+ >
465
+ ${B(this.labels.removeLanguage,{language:i})}
466
+ </button>
467
+ </div>
468
+ `:n}
469
+ </span>
470
+ `}#E(){let e=[this._contentLanguage,...this._additional];return t`
471
+ <div class="field">
472
+ <span id="language-list-label" class="label"
473
+ >${this.labels.languagesLabel}${this._savingSite?` ${this.labels.saving}`:``}</span
474
+ >
475
+ <ul
476
+ class="flex flex-col rounded-md border divide-y"
477
+ aria-labelledby="language-list-label"
478
+ >
479
+ ${e.map(e=>{let r=e===this._contentLanguage,i=r?`${this._sitePathPrefix}/`:this.#i(e);return t`
480
+ <li class="flex flex-col px-3 py-1.5 text-sm">
481
+ <div class="flex min-h-8 items-center gap-3">
482
+ <span class="min-w-0 truncate" lang=${e}
483
+ >${this.#r(e)}</span
484
+ >
485
+ <a
486
+ href=${i}
487
+ target="_blank"
488
+ rel="noopener noreferrer"
489
+ class="shrink-0"
490
+ >
491
+ <code
492
+ class="rounded bg-muted px-1.5 py-0.5 text-xs text-muted-foreground underline-offset-2 hover:text-foreground hover:underline"
493
+ >${i}</code
494
+ >
495
+ </a>
496
+ ${r?t`<span class="badge-secondary ml-auto"
497
+ >${this.labels.primaryBadge}</span
498
+ >`:this.#T(e)}
499
+ </div>
500
+ ${this._removeError?.tag===e?t`
501
+ <p class="pb-1 text-sm text-destructive" role="alert">
502
+ ${this._removeError.message}${this._multilingualEnabled?t`
503
+ <a
504
+ class="underline underline-offset-2"
505
+ href=${`${this.#i(e)}/archive`}
506
+ target="_blank"
507
+ rel="noopener noreferrer"
508
+ >${this.labels.viewPosts}</a
509
+ >
510
+ `:n}
511
+ </p>
512
+ `:n}
513
+ </li>
514
+ `})}
515
+ </ul>
516
+ <div class="mt-2">
517
+ ${this.#x({labelId:`language-list-label`,exclude:[this._contentLanguage,...this._additional],triggerLabel:`+ ${this.labels.addLanguage}`,triggerClass:`btn-sm-outline`,onSelect:e=>void this.#p(e)})}
518
+ </div>
519
+ </div>
520
+ `}render(){return this.labels.contentLanguage?t`
521
+ <div class="flex flex-col gap-8">
522
+ <section class="flex flex-col gap-4">
523
+ <h2 class="text-lg font-medium">${this.labels.siteSection}</h2>
524
+
525
+ ${this._multilingualEnabled?this.#E():t`
526
+ <div class="field">
527
+ <span id="language-primary-label" class="label"
528
+ >${this.labels.contentLanguage}</span
529
+ >
530
+ ${this.#x({labelId:`language-primary-label`,current:this._contentLanguage,exclude:[],triggerLabel:this.#r(this._contentLanguage),triggerClass:u,onSelect:e=>void this.#d(e)})}
531
+ <p class="text-sm text-muted-foreground mt-1">
532
+ ${this.labels.contentLanguageHelp}${this._savingSite?` ${this.labels.saving}`:``}
533
+ </p>
534
+ </div>
535
+ `}
536
+ </section>
537
+
538
+ <section class="flex flex-col gap-3 border-t pt-8">
539
+ <h2 class="text-lg font-medium">${this.labels.multilingual}</h2>
540
+ <p class="text-sm text-muted-foreground">
541
+ ${this.labels.multilingualHelp}
542
+ </p>
543
+ <p class="text-sm text-muted-foreground">
544
+ <a
545
+ href=${this.#e}
546
+ target="_blank"
547
+ rel="noopener noreferrer"
548
+ class="underline hover:text-foreground transition-colors"
549
+ >${this.labels.multilingualDocs}</a
550
+ >
551
+ — ${this.labels.multilingualDocsHelp}
552
+ </p>
553
+ <div class="flex items-center gap-3">
554
+ ${this._multilingualEnabled?t`
555
+ <span class="badge-secondary">${this.labels.statusOn}</span>
556
+ <button
557
+ type="button"
558
+ class="btn-link h-auto p-0 text-sm text-muted-foreground"
559
+ data-multilingual-off
560
+ @click=${()=>void this.#h()}
561
+ >
562
+ ${this.labels.disableConfirm}
563
+ </button>
564
+ `:t`
565
+ <button
566
+ type="button"
567
+ class="btn-sm-outline"
568
+ data-multilingual-setup
569
+ @click=${()=>this.#g()}
570
+ >
571
+ ${this.labels.turnOn}
572
+ </button>
573
+ `}
574
+ </div>
575
+ </section>
576
+
577
+ <section class="flex flex-col gap-4 border-t pt-8">
578
+ <h2 class="text-lg font-medium">${this.labels.dashboardSection}</h2>
579
+
580
+ <div class="field">
581
+ <label id="dashboard-language-label" class="label"
582
+ >${this.labels.dashboardLanguage}</label
583
+ >
584
+ <select
585
+ class="select"
586
+ aria-labelledby="dashboard-language-label"
587
+ ?disabled=${this._savingDashboard}
588
+ @change=${e=>void this.#f(e.target.value)}
589
+ >
590
+ ${R.map(e=>t`
591
+ <option
592
+ value=${e}
593
+ ?selected=${this._dashboardLanguage===e}
594
+ >
595
+ ${e===``?this.labels.followContent:this.#r(e)}
596
+ </option>
597
+ `)}
598
+ </select>
599
+ <p class="text-sm text-muted-foreground mt-1">
600
+ ${this.labels.dashboardLanguageHelp}
601
+ </p>
602
+ </div>
603
+ </section>
604
+ </div>
605
+
606
+ ${this.#w()}
607
+ `:n}};customElements.define(`jant-settings-language`,V);var H=class extends i{static properties={avatarUrl:{type:String,attribute:`avatar-url`},showInHeader:{type:Boolean,attribute:`show-in-header`},labels:{type:Object},_showInHeader:{state:!0},_origShowInHeader:{state:!0},_dirty:{state:!0},_loading:{state:!0},_removeLoading:{state:!0}};createRenderRoot(){return this.innerHTML=``,this}constructor(){super(),this.avatarUrl=``,this.showInHeader=!1,this.labels={},this._showInHeader=!1,this._origShowInHeader=!1,this._dirty=!1,this._loading=!1,this._removeLoading=!1}connectedCallback(){super.connectedCallback(),this._showInHeader=this.showInHeader,this._origShowInHeader=this.showInHeader}saved(){this._origShowInHeader=this._showInHeader,this._dirty=!1,this._loading=!1}saveError(){this._loading=!1}removeError(){this._removeLoading=!1}_toggleDisplay(){this._showInHeader=!this._showInHeader,this._dirty=this._showInHeader!==this._origShowInHeader}_cancelDisplay(){this._showInHeader=this._origShowInHeader,this._dirty=!1}_saveDisplay(){!this._loading&&this._dirty&&(this._loading=!0,this.dispatchEvent(new CustomEvent(`jant:settings-save`,{bubbles:!0,detail:{endpoint:`/settings/avatar/display`,data:{showHeaderAvatar:this._showInHeader?`true`:``},section:`avatar-display`}})))}async _removeAvatar(){await d({message:this.labels.confirmRemoveAvatar,confirmLabel:this.labels.remove,cancelLabel:this.labels.cancel,tone:`danger`})&&(this._removeLoading||(this._removeLoading=!0,this.dispatchEvent(new CustomEvent(`jant:avatar-remove`,{bubbles:!0,detail:{endpoint:`/settings/avatar/remove`}}))))}_renderPreview(){let e=`rounded-full size-16 overflow-hidden border border-border/70 bg-muted/40 flex items-center justify-center shrink-0`;return this.avatarUrl?t`
608
+ <div class=${e}>
609
+ <img
610
+ src=${this.avatarUrl}
611
+ alt=""
612
+ class="w-full h-full object-cover"
613
+ />
614
+ </div>
615
+ `:t`
616
+ <div class="${e} text-muted-foreground">
617
+ <svg
618
+ xmlns="http://www.w3.org/2000/svg"
619
+ width="24"
620
+ height="24"
621
+ viewBox="0 0 24 24"
622
+ fill="none"
623
+ stroke="currentColor"
624
+ stroke-width="2"
625
+ stroke-linecap="round"
626
+ stroke-linejoin="round"
627
+ >
628
+ <rect width="18" height="18" x="3" y="3" rx="2" ry="2" />
629
+ <circle cx="9" cy="9" r="2" />
630
+ <path d="m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21" />
631
+ </svg>
632
+ </div>
633
+ `}render(){return t`
634
+ <div>
635
+ <h2 class="text-lg font-semibold mb-4">${this.labels.blogAvatar}</h2>
636
+ <div class="flex flex-col gap-4">
637
+ <div class="flex items-center gap-4">
638
+ ${this._renderPreview()}
639
+ <div class="flex flex-col gap-2">
640
+ <form
641
+ action=${e(`/settings/avatar`)}
642
+ method="post"
643
+ enctype="multipart/form-data"
644
+ class="inline"
645
+ >
646
+ <label class="btn text-sm cursor-pointer">
647
+ ${this.labels.uploadAvatar}
648
+ <input
649
+ type="file"
650
+ name="file"
651
+ accept="image/jpeg,image/png,image/gif,image/webp,image/svg+xml"
652
+ class="hidden"
653
+ data-avatar-upload
654
+ data-text-processing=${this.labels.processing}
655
+ data-text-uploading=${this.labels.uploading}
656
+ data-text-error=${this.labels.uploadError}
657
+ />
658
+ </label>
659
+ </form>
660
+ ${this.avatarUrl?t`
661
+ <button
662
+ type="button"
663
+ class="btn-outline text-sm"
664
+ ?disabled=${this._removeLoading}
665
+ @click=${()=>void this._removeAvatar()}
666
+ >
667
+ ${this.labels.remove}
668
+ </button>
669
+ `:n}
670
+ </div>
671
+ </div>
672
+ <p class="text-sm text-muted-foreground">${this.labels.avatarHelp}</p>
673
+ <label class="flex items-center gap-2 cursor-pointer">
674
+ <input
675
+ type="checkbox"
676
+ class="checkbox"
677
+ .checked=${this._showInHeader}
678
+ @change=${this._toggleDisplay}
679
+ />
680
+ <span>${this.labels.displayInHeader}</span>
681
+ </label>
682
+ <div class="flex gap-2 mt-4">
683
+ <button
684
+ type="button"
685
+ class="btn"
686
+ ?disabled=${this._loading||!this._dirty}
687
+ @click=${this._saveDisplay}
688
+ >
689
+ ${this._loading?t`<svg
690
+ class="animate-spin size-4"
691
+ xmlns="http://www.w3.org/2000/svg"
692
+ viewBox="0 0 24 24"
693
+ fill="none"
694
+ stroke="currentColor"
695
+ stroke-width="2"
696
+ stroke-linecap="round"
697
+ stroke-linejoin="round"
698
+ role="status"
699
+ >
700
+ <path d="M21 12a9 9 0 1 1-6.219-8.56" />
701
+ </svg>`:n}
702
+ ${this.labels.save}
703
+ </button>
704
+ <button
705
+ type="button"
706
+ class="btn-outline"
707
+ ?disabled=${this._loading||!this._dirty}
708
+ @click=${this._cancelDisplay}
709
+ >
710
+ ${this.labels.cancel}
711
+ </button>
712
+ </div>
713
+ </div>
714
+ </div>
715
+ `}};customElements.define(`jant-settings-avatar`,H);var U={search:`Search settings`,modifiedOnly:`Show only modified`,modified:`Modified`,locked:`Locked`,reset:`Reset to default`,saving:`Saving…`,saved:`Saved`,saveError:`This setting wasn't saved. Check the value and try again.`,noMatches:`Nothing matches this search. Try a different name or description.`,countTemplate:`{count} settings shown`,openSetting:`Open setting`,configured:`Configured`,notConfigured:`Not configured`};function W(e){if(!g(e))return;let t={};for(let[n,r]of Object.entries(e)){if(typeof r!=`string`)return;t[n]=r}return t}function G(e){if(!g(e))return null;let t=_(e,`key`),n=_(e,`mode`),r=_(e,`type`),i=_(e,`value`),a=_(e,`fallbackValue`),o=_(e,`description`),s=_(e,`settingsPath`),c=_(e,`display`),l=_(e,`fallbackKey`);if(!t||n!==`edit`&&n!==`link`||r!==`boolean`&&r!==`string`&&r!==`number`&&r!==`enum`||i===void 0||a===void 0||o===void 0||typeof e.modified!=`boolean`||typeof e.locked!=`boolean`||n===`link`&&(!s||c!==`value`&&c!==`configured`))return null;let u=Array.isArray(e.options)?e.options.filter(e=>typeof e==`string`):void 0;if(n===`edit`&&r===`enum`&&(!u||u.length===0))return null;let d=W(e.optionLabels);return{key:t,mode:n,type:r,value:i,fallbackValue:a,modified:e.modified,locked:e.locked,description:o,...typeof e.maxLength==`number`&&{maxLength:e.maxLength},...typeof e.min==`number`&&{min:e.min},...typeof e.max==`number`&&{max:e.max},...typeof e.step==`number`&&{step:e.step},...u&&{options:u},...d&&{optionLabels:d},...s&&{settingsPath:s},...c===`value`||c===`configured`?{display:c}:{},...e.resettable===!0&&{resettable:!0},...l&&{fallbackKey:l}}}function K(e){try{let t=JSON.parse(e);return!g(t)||!Array.isArray(t.fields)?[]:t.fields.map(G).filter(e=>e!==null)}catch{return[]}}function q(e){try{let t=JSON.parse(e);if(!g(t))return U;let n={...U};for(let e of Object.keys(n)){let r=t[e];typeof r==`string`&&r&&(n[e]=r)}return n}catch{return U}}var J=class extends i{static properties={endpoint:{type:String},initialData:{type:String,attribute:`initial-data`},labelsJson:{type:String,attribute:`labels`},_items:{state:!0},_labels:{state:!0},_query:{state:!0},_modifiedOnly:{state:!0},_drafts:{state:!0},_pending:{state:!0},_statuses:{state:!0}};_statusTimeouts=new Map;createRenderRoot(){return this}constructor(){super(),this.endpoint=`/api/settings`,this.initialData=``,this.labelsJson=``,this._items=[],this._labels=U,this._query=``,this._modifiedOnly=!1,this._drafts={},this._pending={},this._statuses={}}connectedCallback(){super.connectedCallback(),this.querySelector(`:scope > .config-editor-fallback`)?.remove();let e=this.getAttribute(`initial-data`)??this.initialData,t=this.getAttribute(`labels`)??this.labelsJson;this._items=K(e),this._labels=q(t),this._drafts=Object.fromEntries(this._items.map(e=>[e.key,e.value]))}disconnectedCallback(){for(let e of this._statusTimeouts.values())window.clearTimeout(e);this._statusTimeouts.clear(),super.disconnectedCallback()}_filteredItems(){let e=v(this._query);return this._items.map((t,n)=>({item:t,index:n,rank:e?h([t.key,t.description,t.type,t.value],e):0})).filter(e=>e.rank!==null&&(!this._modifiedOnly||e.item.modified)).sort((e,t)=>(e.rank??0)-(t.rank??0)||e.index-t.index).map(({item:e})=>e)}_setDraft(e,t){this._drafts={...this._drafts,[e]:t},this._statuses[e]&&this._setStatus(e,void 0)}_setPending(e,t){this._pending={...this._pending,[e]:t}}_setStatus(e,t){let n=this._statusTimeouts.get(e);if(n!==void 0&&(window.clearTimeout(n),this._statusTimeouts.delete(e)),this._statuses={...this._statuses,[e]:t},t?.state===`saved`){let t=window.setTimeout(()=>{this._statuses[e]?.state===`saved`&&(this._statuses={...this._statuses,[e]:void 0}),this._statusTimeouts.delete(e)},2e3);this._statusTimeouts.set(e,t)}}_replaceItem(e,t){this._items=this._items.map(n=>n.key===e?t(n):n)}_commitValue(e,t,n){let r={...this._drafts,[e]:t};this._items=this._items.map(i=>i.key===e?{...i,value:t,modified:n}:i.fallbackKey===e?i.modified?{...i,fallbackValue:t}:(r[i.key]=t,{...i,value:t,fallbackValue:t}):i),this._drafts=r}async _save(e,t){if(e.locked||this._pending[e.key])return;let n=e.type===`boolean`||e.type===`enum`,r=e.value;n&&this._replaceItem(e.key,e=>({...e,value:t})),this._setPending(e.key,!0),this._setStatus(e.key,{state:`saving`});try{let n=await fetch(this.endpoint,{method:`PUT`,headers:{"Content-Type":`application/json`,Accept:`application/json`},body:JSON.stringify({[e.key]:t})});if(!n.ok)throw Error(await m(n,this._labels.saveError));let r=(await f(n)).settings,i=_(r,e.key)??t;this._commitValue(e.key,i,!0),this._setStatus(e.key,{state:`saved`})}catch(t){n&&this._replaceItem(e.key,e=>({...e,value:r})),this._setStatus(e.key,{state:`error`,message:t instanceof Error?t.message:this._labels.saveError})}finally{this._setPending(e.key,!1)}}async _reset(e){if(!(!e.modified||e.locked||e.mode===`link`&&!e.resettable||this._pending[e.key])){this._setPending(e.key,!0),this._setStatus(e.key,{state:`saving`});try{let t=await fetch(`${this.endpoint}/${encodeURIComponent(e.key)}`,{method:`DELETE`,headers:{Accept:`application/json`}});if(!t.ok)throw Error(await m(t,this._labels.saveError));let n=await f(t),r=g(n.setting)?n.setting:void 0,i=_(r,`value`)??_(n.settings,e.key)??e.fallbackValue;this._commitValue(e.key,i,!1),this._setStatus(e.key,{state:`saved`})}catch(t){this._setStatus(e.key,{state:`error`,message:t instanceof Error?t.message:this._labels.saveError})}finally{this._setPending(e.key,!1)}}}_renderStatus(e){let r=this._statuses[e.key];return r?r.state===`saving`?t`<span class="config-editor-status" role="status"
716
+ >${this._labels.saving}</span
717
+ >`:r.state===`saved`?t`<span
718
+ class="config-editor-status config-editor-status-saved"
719
+ role="status"
720
+ >${this._labels.saved}</span
721
+ >`:t`<span
722
+ class="config-editor-status config-editor-status-error"
723
+ role="alert"
724
+ >${r.message}</span
725
+ >`:n}_renderControl(e){let r=`config-editor-${e.key.toLowerCase().replaceAll(`_`,`-`)}`,i=!!this._pending[e.key]||e.locked;if(e.type===`boolean`)return t`<input
726
+ id=${r}
727
+ name=${e.key}
728
+ type="checkbox"
729
+ role="switch"
730
+ class="input"
731
+ aria-describedby=${`${r}-description`}
732
+ .checked=${e.value===`true`}
733
+ ?disabled=${i}
734
+ @change=${t=>void this._save(e,String(t.target.checked))}
735
+ />`;if(e.type===`enum`)return t`<select
736
+ id=${r}
737
+ name=${e.key}
738
+ class="select config-editor-select"
739
+ aria-describedby=${`${r}-description`}
740
+ .value=${e.value}
741
+ ?disabled=${i}
742
+ @change=${t=>void this._save(e,t.target.value)}
743
+ >
744
+ ${(e.options??[]).map(n=>t`<option value=${n} ?selected=${n===e.value}>
745
+ ${e.optionLabels?.[n]??n}
746
+ </option>`)}
747
+ </select>`;let a=this._drafts[e.key]??e.value,o=a!==e.value;return t`<input
748
+ id=${r}
749
+ name=${e.key}
750
+ class="input config-editor-value-input"
751
+ type=${e.type===`number`?`number`:`text`}
752
+ autocomplete="off"
753
+ spellcheck="false"
754
+ aria-describedby=${`${r}-description`}
755
+ .value=${a}
756
+ maxlength=${e.maxLength??n}
757
+ min=${e.min??n}
758
+ max=${e.max??n}
759
+ step=${e.step??n}
760
+ ?disabled=${i}
761
+ @input=${t=>this._setDraft(e.key,t.target.value)}
762
+ @blur=${t=>{let n=t.target.value;n!==e.value&&this._save(e,n)}}
763
+ @keydown=${t=>{t.key===`Escape`?(t.preventDefault(),this._setDraft(e.key,e.value)):t.key===`Enter`&&!t.isComposing&&o&&(t.preventDefault(),this._save(e,a))}}
764
+ />`}_renderLinkedSetting(e){let n=e.display===`configured`?e.value===`true`?this._labels.configured:this._labels.notConfigured:e.value;return t`
765
+ <a
766
+ class="config-editor-open-control"
767
+ href=${e.settingsPath??`/settings`}
768
+ aria-describedby=${`config-editor-${e.key.toLowerCase().replaceAll(`_`,`-`)}-description`}
769
+ >
770
+ <span class="config-editor-linked-value" translate="no">${n}</span>
771
+ <span class="config-editor-open-action">
772
+ ${this._labels.openSetting}
773
+ <svg
774
+ xmlns="http://www.w3.org/2000/svg"
775
+ width="15"
776
+ height="15"
777
+ viewBox="0 0 24 24"
778
+ fill="none"
779
+ stroke="currentColor"
780
+ stroke-width="2"
781
+ stroke-linecap="round"
782
+ stroke-linejoin="round"
783
+ aria-hidden="true"
784
+ >
785
+ <path d="M5 12h14" />
786
+ <path d="m13 6 6 6-6 6" />
787
+ </svg>
788
+ </span>
789
+ </a>
790
+ `}_canReset(e){return e.modified&&!e.locked&&(e.mode===`edit`||e.resettable===!0)}_renderRow(e){let r=`config-editor-${e.key.toLowerCase().replaceAll(`_`,`-`)}`,i=[`config-editor-control-row`,e.mode===`edit`&&e.type===`enum`?`config-editor-control-row-select`:``,e.mode===`edit`&&e.type===`number`?`config-editor-control-row-number`:``].filter(Boolean).join(` `);return t`
791
+ <li
792
+ class="config-editor-row"
793
+ data-modified=${String(e.modified)}
794
+ aria-busy=${String(!!this._pending[e.key])}
795
+ >
796
+ <div class="config-editor-copy">
797
+ <div class="config-editor-heading">
798
+ ${e.mode===`edit`?t`<label for=${r}
799
+ ><code class="config-editor-key" translate="no"
800
+ >${e.key}</code
801
+ ></label
802
+ >`:t`<code class="config-editor-key" translate="no"
803
+ >${e.key}</code
804
+ >`}
805
+ ${e.modified?t`<span class="config-editor-state config-editor-modified"
806
+ >${this._labels.modified}</span
807
+ >`:n}
808
+ ${e.locked?t`<span class="config-editor-state config-editor-locked"
809
+ >${this._labels.locked}</span
810
+ >`:n}
811
+ </div>
812
+ <p class="config-editor-description" id=${`${r}-description`}>
813
+ ${e.description}
814
+ </p>
815
+ </div>
816
+ <div class="config-editor-value-column">
817
+ <div class=${i}>
818
+ ${e.mode===`link`?this._renderLinkedSetting(e):this._renderControl(e)}
819
+ ${this._canReset(e)?t`<button
820
+ type="button"
821
+ class="config-editor-reset"
822
+ aria-label=${this._labels.reset}
823
+ title=${this._labels.reset}
824
+ ?disabled=${!!this._pending[e.key]}
825
+ @click=${()=>void this._reset(e)}
826
+ >
827
+ <svg
828
+ xmlns="http://www.w3.org/2000/svg"
829
+ width="15"
830
+ height="15"
831
+ viewBox="0 0 24 24"
832
+ fill="none"
833
+ stroke="currentColor"
834
+ stroke-width="2"
835
+ stroke-linecap="round"
836
+ stroke-linejoin="round"
837
+ aria-hidden="true"
838
+ >
839
+ <path d="M3 12a9 9 0 1 0 3-6.7L3 8" />
840
+ <path d="M3 3v5h5" />
841
+ </svg>
842
+ </button>`:n}
843
+ </div>
844
+ ${this._renderStatus(e)}
845
+ </div>
846
+ </li>
847
+ `}render(){let e=this._filteredItems(),n=this._labels.countTemplate.replace(`{count}`,String(e.length));return t`
848
+ <div class="config-editor-toolbar">
849
+ <div class="config-editor-search">
850
+ <svg
851
+ xmlns="http://www.w3.org/2000/svg"
852
+ width="17"
853
+ height="17"
854
+ viewBox="0 0 24 24"
855
+ fill="none"
856
+ stroke="currentColor"
857
+ stroke-width="2"
858
+ stroke-linecap="round"
859
+ stroke-linejoin="round"
860
+ aria-hidden="true"
861
+ >
862
+ <circle cx="11" cy="11" r="8"></circle>
863
+ <path d="m21 21-4.3-4.3"></path>
864
+ </svg>
865
+ <input
866
+ type="search"
867
+ name="config-search"
868
+ class="input config-editor-search-input"
869
+ autocomplete="off"
870
+ spellcheck="false"
871
+ placeholder=${this._labels.search}
872
+ aria-label=${this._labels.search}
873
+ .value=${this._query}
874
+ @input=${e=>{this._query=e.target.value}}
875
+ @keydown=${e=>{e.key===`Escape`&&this._query&&(e.preventDefault(),this._query=``)}}
876
+ />
877
+ </div>
878
+ </div>
879
+ <div class="config-editor-toolbar-meta">
880
+ <p class="config-editor-count" aria-live="polite">${n}</p>
881
+ <label class="config-editor-modified-filter">
882
+ <input
883
+ type="checkbox"
884
+ name="modified-only"
885
+ class="input"
886
+ .checked=${this._modifiedOnly}
887
+ @change=${e=>{this._modifiedOnly=e.target.checked}}
888
+ />
889
+ <span>${this._labels.modifiedOnly}</span>
890
+ </label>
891
+ </div>
892
+ ${e.length>0?t`<ul class="config-editor-list">
893
+ ${e.map(e=>this._renderRow(e))}
894
+ </ul>`:t`<div class="config-editor-empty" role="status">
895
+ <p>${this._labels.noMatches}</p>
896
+ </div>`}
897
+ `}};customElements.get(`jant-config-editor`)||customElements.define(`jant-config-editor`,J);var Y=300,X=1,Z=class extends i{static properties={labels:{type:Object},apiBase:{type:String,attribute:`api-base`},connectUrl:{type:String,attribute:`connect-url`},installUrl:{type:String,attribute:`install-url`},cancelUrl:{type:String,attribute:`cancel-url`},createRepoNameHint:{type:String,attribute:`create-repo-name-hint`},_installations:{state:!0},_selectedOwner:{state:!0},_ownerOpen:{state:!0},_repos:{state:!0},_totalCount:{state:!0},_hasMore:{state:!0},_nextPage:{state:!0},_reposMode:{state:!0},_repoOpen:{state:!0},_repoSearch:{state:!0},_loadingRepos:{state:!0},_selectedRepo:{state:!0},_classification:{state:!0},_classifying:{state:!0},_confirmText:{state:!0},_connecting:{state:!0},_error:{state:!0}};#e=null;#t=0;#n=!1;#r=null;createRenderRoot(){return this.innerHTML=``,this}constructor(){super(),this.labels={},this.apiBase=``,this.connectUrl=``,this.installUrl=``,this.cancelUrl=``,this.createRepoNameHint=``,this._installations=[],this._selectedOwner=null,this._ownerOpen=!1,this._repos=[],this._totalCount=0,this._hasMore=!1,this._nextPage=null,this._reposMode=`list`,this._repoOpen=!1,this._repoSearch=``,this._loadingRepos=!1,this._selectedRepo=null,this._classification=null,this._classifying=!1,this._confirmText=``,this._connecting=!1,this._error=null}connectedCallback(){super.connectedCallback(),document.addEventListener(`click`,this.#m),document.addEventListener(`keydown`,this.#h),window.addEventListener(`focus`,this.#g),this.#i()}disconnectedCallback(){super.disconnectedCallback(),document.removeEventListener(`click`,this.#m),document.removeEventListener(`keydown`,this.#h),window.removeEventListener(`focus`,this.#g),this.#e&&clearTimeout(this.#e)}async#i(){try{let e=await fetch(`${this.apiBase}/installations`,{headers:{Accept:`application/json`},credentials:`same-origin`});if(!e.ok)throw Error(`HTTP ${e.status}`);let t=await e.json();this._installations=t.installations;let n=t.installations.length===1?t.installations[0]:null;n&&this.#u(n)}catch(e){this._error=e instanceof Error?e.message:String(e)}}async#a(e,t={}){let n=++this.#t;this._loadingRepos=!0;try{let r=new URLSearchParams({installationId:e});t.q&&r.set(`q`,t.q);let i=await fetch(`${this.apiBase}/repos?${r.toString()}`,{headers:{Accept:`application/json`},credentials:`same-origin`});if(n!==this.#t)return;if(i.status===410){this._installations=this._installations.filter(t=>t.installationId!==e),this._selectedOwner=null,this._repos=[];return}if(!i.ok){let e=await i.json().catch(()=>({}));throw Error(e.error??`HTTP ${i.status}`)}let a=await i.json();this._repos=a.repos,this._totalCount=a.totalCount,this._hasMore=a.hasMore,this._nextPage=a.nextPage,this._reposMode=a.mode}catch(e){n===this.#t&&(this._error=e instanceof Error?e.message:String(e))}finally{n===this.#t&&(this._loadingRepos=!1)}}async#o(e,t){this._classifying=!0,this._classification=null,this._confirmText=``;try{let n=await fetch(`${this.apiBase}/classify`,{method:`POST`,headers:{"Content-Type":`application/json`,Accept:`application/json`},credentials:`same-origin`,body:JSON.stringify({installationId:e,repo:t})}),r=await n.json();if(!n.ok||!r.classification)throw Error(r.error??`HTTP ${n.status}`);this._classification=r.classification}catch(e){this._error=e instanceof Error?e.message:String(e)}finally{this._classifying=!1}}async#s(){if(this._selectedOwner&&this._selectedRepo&&this._classification){this._connecting=!0,this._error=null;try{let e=this._classification.kind===`foreign`||this._classification.kind===`owned-by-other-site`,t=await fetch(this.connectUrl,{method:`POST`,headers:{"Content-Type":`application/json`,Accept:`application/json`},credentials:`same-origin`,body:JSON.stringify({installationId:this._selectedOwner.installationId,repo:this._selectedRepo.fullName,confirmForeign:e})}),n=await t.json().catch(()=>({}));if(!t.ok||!n.ok)throw Error(n.error??`HTTP ${t.status}`);window.location.href=n.redirect??this.cancelUrl}catch(e){this._error=e instanceof Error?e.message:String(e),this._connecting=!1}}}#c(){let e=this._selectedOwner;if(!e)return;let t=this.createRepoNameHint||``,n=new URL(`https://github.com/new`);t&&n.searchParams.set(`name`,t),n.searchParams.set(`owner`,e.account.login),n.searchParams.set(`visibility`,`private`),this.#n=!0,this.#r=t||null,window.open(n.toString(),`_blank`,`noopener,noreferrer`),this._repoOpen=!1}#l(){if(!this._selectedOwner)return;let e=this._repoSearch.trim();this.#a(this._selectedOwner.installationId,e?{q:e}:{})}#u(e){if(this._selectedOwner?.installationId===e.installationId){this._ownerOpen=!1;return}this._selectedOwner=e,this._ownerOpen=!1,this._selectedRepo=null,this._classification=null,this._confirmText=``,this._repoSearch=``,this.#a(e.installationId)}#d(e){this._selectedRepo=e,this._repoOpen=!1,this._repoSearch=``,this._selectedOwner&&this.#o(this._selectedOwner.installationId,e.fullName)}#f(e){let t=e.target.value;if(this._repoSearch=t,this.#e&&clearTimeout(this.#e),!this._selectedOwner)return;let n=t.trim();if(n.length<X){this._reposMode===`search`&&this.#a(this._selectedOwner.installationId);return}this.#e=setTimeout(()=>{this._selectedOwner&&this.#a(this._selectedOwner.installationId,{q:n})},Y)}#p(){let e=this._repoSearch.trim().toLowerCase();return!e||this._reposMode===`search`?this._repos:this._repos.filter(t=>t.name.toLowerCase().includes(e)||t.fullName.toLowerCase().includes(e))}#m=e=>{if(!this._ownerOpen&&!this._repoOpen)return;let t=e.target,n=this.querySelector(`.repo-picker-owner`),r=this.querySelector(`.repo-picker-repo`);n&&!n.contains(t)&&(this._ownerOpen=!1),r&&!r.contains(t)&&(this._repoOpen=!1)};#h=e=>{e.key===`Escape`&&(e.isComposing||e.keyCode===229||(this._ownerOpen||this._repoOpen)&&(this._ownerOpen=!1,this._repoOpen=!1))};#g=()=>{if(!this.#n)return;let e=this._selectedOwner;if(!e){this.#n=!1;return}let t=this.#r;this.#n=!1,this.#r=null,(async()=>{if(this._repoSearch=``,await this.#a(e.installationId),t){let e=this._repos.find(e=>e.name===t);e&&this.#d(e)}})()};#_(){this._ownerOpen=!this._ownerOpen,this._repoOpen=!1}#v(){this._selectedOwner&&(this._repoOpen=!this._repoOpen,this._ownerOpen=!1,this._repoOpen&&queueMicrotask(()=>{this.querySelector(`.repo-picker-repo-search`)?.focus()}))}render(){return t`
898
+ <div class="flex flex-col gap-6 max-w-lg">
899
+ <div>
900
+ <h2 class="text-lg font-medium mb-1">${this.labels.pageTitle}</h2>
901
+ <p class="text-sm text-muted-foreground">
902
+ ${this.labels.pageSubtitle}
903
+ </p>
904
+ </div>
905
+
906
+ ${this.#y()} ${this.#x()}
907
+ ${this.#C()} ${this.#T()}
908
+ ${this._error?t`<div class="alert-destructive text-sm" role="alert">
909
+ <section><p>${this._error}</p></section>
910
+ </div>`:n}
911
+ </div>
912
+ `}#y(){let e=this._selectedOwner;return t`
913
+ <div class="field repo-picker-owner relative">
914
+ <label class="label">${this.labels.ownerLabel}</label>
915
+ <button
916
+ type="button"
917
+ class="btn-outline w-full justify-between font-normal"
918
+ @click=${()=>this.#_()}
919
+ aria-haspopup="listbox"
920
+ aria-expanded=${this._ownerOpen}
921
+ >
922
+ <span class="flex items-center gap-2 truncate">
923
+ ${e?t`
924
+ ${e.account.avatarUrl?t`<img
925
+ src=${e.account.avatarUrl}
926
+ alt=""
927
+ class="w-5 h-5 rounded-full"
928
+ loading="lazy"
929
+ />`:n}
930
+ <span class="truncate">${e.account.login}</span>
931
+ `:t`<span class="text-muted-foreground"
932
+ >${this._installations.length===0?this.labels.ownerEmpty:this.labels.ownerPlaceholder}</span
933
+ >`}
934
+ </span>
935
+ <span class="text-muted-foreground">▾</span>
936
+ </button>
937
+ ${this._ownerOpen?this.#b():n}
938
+ </div>
939
+ `}#b(){return t`
940
+ <div
941
+ class="absolute z-10 mt-1 w-full rounded-md border bg-background shadow-lg"
942
+ role="listbox"
943
+ >
944
+ <ul class="max-h-64 overflow-y-auto py-1">
945
+ ${this._installations.map(e=>t`
946
+ <li>
947
+ <button
948
+ type="button"
949
+ class="flex w-full items-center gap-2 px-3 py-2 text-left text-sm hover:bg-muted"
950
+ @click=${()=>this.#u(e)}
951
+ role="option"
952
+ aria-selected=${this._selectedOwner?.installationId===e.installationId}
953
+ >
954
+ ${e.account.avatarUrl?t`<img
955
+ src=${e.account.avatarUrl}
956
+ alt=""
957
+ class="w-5 h-5 rounded-full"
958
+ loading="lazy"
959
+ />`:n}
960
+ <span class="truncate">${e.account.login}</span>
961
+ <span class="ml-auto text-xs text-muted-foreground">
962
+ ${e.account.type===`Organization`?`Org`:``}
963
+ </span>
964
+ </button>
965
+ </li>
966
+ `)}
967
+ ${this.installUrl?t`
968
+ <li class="border-t mt-1 pt-1">
969
+ <a
970
+ href=${this.installUrl}
971
+ class="block px-3 py-2 text-sm text-primary hover:bg-muted"
972
+ >
973
+ ${this.labels.installAnother}
974
+ </a>
975
+ </li>
976
+ `:n}
977
+ </ul>
978
+ </div>
979
+ `}#x(){let e=this._selectedRepo,r=!this._selectedOwner;return t`
980
+ <div class="field repo-picker-repo relative">
981
+ <label class="label">${this.labels.repositoryLabel}</label>
982
+ <button
983
+ type="button"
984
+ class="btn-outline w-full justify-between font-normal"
985
+ @click=${()=>this.#v()}
986
+ aria-haspopup="listbox"
987
+ aria-expanded=${this._repoOpen}
988
+ ?disabled=${r}
989
+ >
990
+ <span class="truncate">
991
+ ${e?t`<span>${e.name}</span> ${e.private?t`<span class="text-xs text-muted-foreground ml-1"
992
+ >${this.labels.privateBadge}</span
993
+ >`:n}`:t`<span class="text-muted-foreground"
994
+ >${r?this.labels.repoPlaceholderNoOwner:this.labels.repoPlaceholder}</span
995
+ >`}
996
+ </span>
997
+ <span class="text-muted-foreground">▾</span>
998
+ </button>
999
+ ${this._repoOpen?this.#S():n}
1000
+ </div>
1001
+ `}#S(){let e=this.#p();return t`
1002
+ <div
1003
+ class="absolute z-10 mt-1 w-full rounded-md border bg-background shadow-lg"
1004
+ >
1005
+ <div class="p-2 border-b flex items-center gap-2">
1006
+ <input
1007
+ type="text"
1008
+ class="input repo-picker-repo-search flex-1"
1009
+ placeholder=${this.labels.repoSearchPlaceholder}
1010
+ .value=${this._repoSearch}
1011
+ @input=${e=>this.#f(e)}
1012
+ />
1013
+ <button
1014
+ type="button"
1015
+ class="btn-icon-ghost"
1016
+ title=${this.labels.refreshRepos}
1017
+ aria-label=${this.labels.refreshRepos}
1018
+ @click=${()=>this.#l()}
1019
+ ?disabled=${this._loadingRepos}
1020
+ >
1021
+ <!-- Simple refresh glyph; matches BaseCoat icon button sizing -->
1022
+ <span aria-hidden="true">⟳</span>
1023
+ </button>
1024
+ </div>
1025
+ ${this._hasMore&&this._reposMode===`list`?t`<p class="px-3 pt-2 text-xs text-muted-foreground">
1026
+ ${this.labels.repoShowingOf.replace(`{shown}`,String(this._repos.length)).replace(`{total}`,String(this._totalCount))}
1027
+ — ${this.labels.repoSearchHint}
1028
+ </p>`:n}
1029
+ <ul class="max-h-64 overflow-y-auto py-1" role="listbox">
1030
+ ${this._loadingRepos?t`<li class="px-3 py-2 text-sm text-muted-foreground">
1031
+ ${this.labels.repoLoading}
1032
+ </li>`:e.length===0?t`<li class="px-3 py-2 text-sm text-muted-foreground">
1033
+ ${this.labels.repoEmpty}
1034
+ </li>`:e.map(e=>t`
1035
+ <li>
1036
+ <button
1037
+ type="button"
1038
+ class="flex w-full items-center gap-2 px-3 py-2 text-left text-sm hover:bg-muted"
1039
+ @click=${()=>this.#d(e)}
1040
+ role="option"
1041
+ aria-selected=${this._selectedRepo?.fullName===e.fullName}
1042
+ >
1043
+ <span class="truncate">${e.name}</span>
1044
+ ${e.private?t`<span
1045
+ class="ml-auto text-xs text-muted-foreground"
1046
+ >${this.labels.privateBadge}</span
1047
+ >`:n}
1048
+ </button>
1049
+ </li>
1050
+ `)}
1051
+ </ul>
1052
+ <div class="border-t p-2">
1053
+ <button
1054
+ type="button"
1055
+ class="flex w-full items-start gap-2 px-2 py-2 text-left text-sm text-primary hover:bg-muted rounded-md"
1056
+ @click=${()=>this.#c()}
1057
+ >
1058
+ <span class="flex flex-col">
1059
+ <span class="font-medium">${this.labels.createOnGitHub} →</span>
1060
+ ${this.createRepoNameHint?t`<span class="text-xs text-muted-foreground">
1061
+ ${this.labels.createOnGitHubHint.replace(`{name}`,this.createRepoNameHint)}
1062
+ </span>`:n}
1063
+ </span>
1064
+ </button>
1065
+ </div>
1066
+ </div>
1067
+ `}#C(){if(this._classifying)return t`<p class="text-sm text-muted-foreground">
1068
+ ${this.labels.classifyLoading}
1069
+ </p>`;if(!this._classification||!this._selectedRepo)return n;let e=this._classification;if(e.kind===`empty`)return t`<p class="text-sm text-muted-foreground">
1070
+ ${this.labels.classificationEmpty}
1071
+ </p>`;if(e.kind===`owned`)return t`<p class="text-sm text-muted-foreground">
1072
+ ${this.labels.classificationOwned}
1073
+ </p>`;if(e.kind===`owned-by-other-site`)return t`<div class="alert-destructive text-sm" role="alert">
1074
+ <section>
1075
+ <p>
1076
+ ${this.labels.classificationOwnedByOther.replace(`{host}`,e.marker.site_host)}
1077
+ </p>
1078
+ </section>
1079
+ </div>`;let r=this._selectedRepo.fullName;return t`
1080
+ <div class="alert flex flex-col gap-3 text-sm">
1081
+ <div>
1082
+ <strong class="block mb-1">${this.labels.confirmHeading}</strong>
1083
+ <span>${this.labels.confirmBody.replace(`{repo}`,r)}</span>
1084
+ </div>
1085
+ <div class="field">
1086
+ <label class="label text-xs">
1087
+ ${this.labels.confirmInputLabel.replace(`{repo}`,r)}
1088
+ </label>
1089
+ <input
1090
+ type="text"
1091
+ class="input w-full"
1092
+ placeholder=${this.labels.confirmInputPlaceholder}
1093
+ .value=${this._confirmText}
1094
+ @input=${e=>{this._confirmText=e.target.value}}
1095
+ autocomplete="off"
1096
+ spellcheck="false"
1097
+ />
1098
+ </div>
1099
+ </div>
1100
+ `}#w(){if(!this._selectedRepo||!this._classification||this._classifying||this._connecting)return!1;let e=this._classification;return e.kind===`owned-by-other-site`?!1:e.kind!==`foreign`||this._confirmText.trim()===this._selectedRepo.fullName}#T(){return t`
1101
+ <div class="flex items-center gap-2">
1102
+ <button
1103
+ type="button"
1104
+ class="btn"
1105
+ ?disabled=${!this.#w()}
1106
+ @click=${()=>this.#s()}
1107
+ >
1108
+ ${this._connecting?this.labels.connecting:this.labels.connect}
1109
+ </button>
1110
+ <a href=${this.cancelUrl} class="btn-ghost">${this.labels.cancel}</a>
1111
+ </div>
1112
+ `}};customElements.define(`jant-repo-picker`,Z);function Q(e){let t=_(e,`siteName`),n=_(e,`siteDescription`),r=_(e,`mainRssFeed`),i=_(e,`timeZone`),a=_(e,`siteFooter`),o=p(e,`showJantBrandingOnHome`),s=p(e,`noindex`),c=_(e,`discover`);return t===void 0||n===void 0||r===void 0||i===void 0||a===void 0||o===void 0||s===void 0||c===void 0?null:{siteName:t,siteDescription:n,mainRssFeed:r,timeZone:i,siteFooter:a,showJantBrandingOnHome:o,noindex:s,discover:c}}document.addEventListener(`jant:settings-save`,async e=>{let{endpoint:t,data:n,section:r}=e.detail,i=document.querySelector(`jant-settings-general`),o=document.querySelector(`jant-settings-avatar`);try{let e=await fetch(t,{method:`POST`,headers:{"Content-Type":`application/json`,Accept:`application/json`},body:JSON.stringify(n)});if(!e.ok)throw Error(`HTTP ${e.status}`);let s=await f(e),c=_(s,`status`),l=_(s,`url`),u=_(s,`toast`);if(c===`redirect`&&l){window.location.href=l;return}u&&a(u),r===`avatar-display`?o?.saved():i?.sectionSaved(r)}catch{a(`Failed to save. Please try again.`,`error`),r===`avatar-display`?o?.saveError():i?.sectionError(r)}}),document.addEventListener(`jant:avatar-remove`,async e=>{let{endpoint:t}=e.detail,n=document.querySelector(`jant-settings-avatar`);try{let e=await fetch(t,{method:`POST`,headers:{"Content-Type":`application/json`,Accept:`application/json`}});if(!e.ok)throw Error(`HTTP ${e.status}`);let n=await f(e),r=_(n,`status`),i=_(n,`url`);if(r===`redirect`&&i){window.location.href=i;return}}catch{a(`Failed to remove avatar. Please try again.`,`error`),n?.removeError()}});function $(){let e=document.querySelector(`jant-settings-general`);if(!e)return;let t=document.getElementById(`settings-initial-data`);if(t?.textContent)try{let n=Q(JSON.parse(t.textContent));n&&e.initData(n)}catch{}}document.readyState===`loading`?document.addEventListener(`DOMContentLoaded`,$):queueMicrotask($);