@peaske7/readit 0.3.0-rc.0 → 0.3.0-rc.2

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 (374) hide show
  1. package/README.md +3 -3
  2. package/dist/.vite/manifest.json +1111 -0
  3. package/dist/assets/_basePickBy-BMMA4Tou.js +1 -0
  4. package/dist/assets/_baseUniq-D40qku1I.js +1 -0
  5. package/dist/assets/arc-Ckg65iy8.js +1 -0
  6. package/dist/assets/architecture-YZFGNWBL-Dv3EY0zV.js +1 -0
  7. package/dist/assets/architectureDiagram-Q4EWVU46-DQnkwSaB.js +36 -0
  8. package/dist/assets/array-Bjz-wYpJ.js +1 -0
  9. package/dist/assets/blockDiagram-DXYQGD6D-UB6_S1lm.js +132 -0
  10. package/dist/assets/c4Diagram-AHTNJAMY-sn3k2GND.js +10 -0
  11. package/dist/assets/channel-D9wPw2fQ.js +1 -0
  12. package/dist/assets/chunk-2KRD3SAO-DaFfaCGO.js +1 -0
  13. package/dist/assets/chunk-336JU56O-C8siO5Of.js +2 -0
  14. package/dist/assets/chunk-426QAEUC-BB478m3j.js +1 -0
  15. package/dist/assets/chunk-4BX2VUAB-DRuTD7x5.js +1 -0
  16. package/dist/assets/chunk-4TB4RGXK-_l6jvVAY.js +206 -0
  17. package/dist/assets/chunk-55IACEB6-BExiaAoD.js +1 -0
  18. package/dist/assets/chunk-5FUZZQ4R-HOSFTxuG.js +62 -0
  19. package/dist/assets/chunk-5PVQY5BW-BRVNNRAX.js +2 -0
  20. package/dist/assets/chunk-67CJDMHE-DMt8LNEX.js +1 -0
  21. package/dist/assets/chunk-7N4EOEYR-CzLGefVf.js +1 -0
  22. package/dist/assets/chunk-AA7GKIK3-B6GFAk4U.js +1 -0
  23. package/dist/assets/chunk-BSJP7CBP-BK29yehL.js +1 -0
  24. package/dist/assets/chunk-CIAEETIT-D7hBXImP.js +1 -0
  25. package/dist/assets/chunk-Dlc7tRH4.js +1 -0
  26. package/dist/assets/chunk-EDXVE4YY-CSvKh9DT.js +1 -0
  27. package/dist/assets/chunk-ENJZ2VHE-QApb5cYr.js +10 -0
  28. package/dist/assets/chunk-FMBD7UC4-2FWyCCAV.js +15 -0
  29. package/dist/assets/chunk-FOC6F5B3-DKFHrt4K.js +1 -0
  30. package/dist/assets/chunk-ICPOFSXX-agBjBxsW.js +122 -0
  31. package/dist/assets/chunk-K5T4RW27-D51O7IkG.js +94 -0
  32. package/dist/assets/chunk-KGLVRYIC-DMHSCH4T.js +1 -0
  33. package/dist/assets/chunk-LIHQZDEY-C2aANxt9.js +1 -0
  34. package/dist/assets/chunk-ORNJ4GCN-Db_37NRX.js +1 -0
  35. package/dist/assets/chunk-OYMX7WX6-HGUtT2Q9.js +231 -0
  36. package/dist/assets/chunk-QZHKN3VN-8Lcg9gti.js +1 -0
  37. package/dist/assets/chunk-U2HBQHQK-BFYYQeuC.js +70 -0
  38. package/dist/assets/chunk-X2U36JSP-p8ehTP6s.js +1 -0
  39. package/dist/assets/chunk-XPW4576I-Bqbompq4.js +32 -0
  40. package/dist/assets/chunk-YZCP3GAM-HIMez9pG.js +1 -0
  41. package/dist/assets/chunk-ZZ45TVLE-DRIE_0bu.js +1 -0
  42. package/dist/assets/classDiagram-6PBFFD2Q-BawhEeUl.js +1 -0
  43. package/dist/assets/classDiagram-v2-HSJHXN6E-CLNjgH9n.js +1 -0
  44. package/dist/assets/clone-BBjvuERA.js +1 -0
  45. package/dist/assets/cose-bilkent-S5V4N54A-q90QeGKv.js +1 -0
  46. package/dist/assets/cytoscape.esm-BfXff3fb.js +321 -0
  47. package/dist/assets/dagre-Dxbob2Lr.js +1 -0
  48. package/dist/assets/dagre-KV5264BT-BuvpNxMw.js +4 -0
  49. package/dist/assets/defaultLocale-BwmRmqJp.js +1 -0
  50. package/dist/assets/diagram-5BDNPKRD-DQLsxwwt.js +10 -0
  51. package/dist/assets/diagram-G4DWMVQ6-Jv9Eefw4.js +24 -0
  52. package/dist/assets/diagram-MMDJMWI5-D-0YgNhU.js +43 -0
  53. package/dist/assets/diagram-TYMM5635-BHwO7zQG.js +24 -0
  54. package/dist/assets/dist-BNz65Ibc.js +1 -0
  55. package/dist/assets/erDiagram-SMLLAGMA-BjZGGBJz.js +85 -0
  56. package/dist/assets/flowDiagram-DWJPFMVM-CFbFUm_m.js +162 -0
  57. package/dist/assets/ganttDiagram-T4ZO3ILL-CXk4TcBi.js +292 -0
  58. package/dist/assets/gitGraph-7Q5UKJZL-BGFRt2qs.js +1 -0
  59. package/dist/assets/gitGraphDiagram-UUTBAWPF-C8yZOxjo.js +106 -0
  60. package/dist/assets/graphlib-DGcD9J2L.js +1 -0
  61. package/dist/assets/index-D-m0LiFI.js +14 -0
  62. package/dist/assets/index-DANHO6J0.css +2 -0
  63. package/dist/assets/info-OMHHGYJF-DI6-Z9vh.js +1 -0
  64. package/dist/assets/infoDiagram-42DDH7IO-p-PXDra2.js +2 -0
  65. package/dist/assets/init-TPm5RB77.js +1 -0
  66. package/dist/assets/isArrayLikeObject-69BLnVNM.js +1 -0
  67. package/dist/assets/isEmpty-DUS28g5f.js +1 -0
  68. package/dist/assets/ishikawaDiagram-UXIWVN3A-BrIoEvtb.js +70 -0
  69. package/dist/assets/journeyDiagram-VCZTEJTY-aZpvKa9g.js +139 -0
  70. package/dist/assets/kanban-definition-6JOO6SKY-CoOAY9ji.js +89 -0
  71. package/dist/assets/katex-5SGEXwpi.js +261 -0
  72. package/dist/assets/line-4MF1lR4d.js +1 -0
  73. package/dist/assets/linear-CXMqTN8N.js +1 -0
  74. package/dist/assets/mermaid-config-C8a4L22x.js +1 -0
  75. package/dist/assets/mermaid-parser.core-DREsY2u4.js +4 -0
  76. package/dist/assets/mermaid.core-8ysLpTJi.js +11 -0
  77. package/dist/assets/mindmap-definition-QFDTVHPH-CsqUJCMn.js +96 -0
  78. package/dist/assets/ordinal-D7l-8DAO.js +1 -0
  79. package/dist/assets/packet-4T2RLAQJ-DidW3JFc.js +1 -0
  80. package/dist/assets/path-BVpCanzE.js +1 -0
  81. package/dist/assets/pie-ZZUOXDRM-Bff2e5hg.js +1 -0
  82. package/dist/assets/pieDiagram-DEJITSTG-k0Br4NDS.js +30 -0
  83. package/dist/assets/quadrantDiagram-34T5L4WZ-Be9oCSza.js +7 -0
  84. package/dist/assets/radar-PYXPWWZC-CsdZBH3M.js +1 -0
  85. package/dist/assets/requirementDiagram-MS252O5E-8ECT7dEs.js +84 -0
  86. package/dist/assets/rough.esm-BoTisKeL.js +1 -0
  87. package/dist/assets/sankeyDiagram-XADWPNL6-CoKpeJJ0.js +10 -0
  88. package/dist/assets/sequenceDiagram-FGHM5R23-BTT2fFxG.js +157 -0
  89. package/dist/assets/src-CrmkjRpa.js +1 -0
  90. package/dist/assets/stateDiagram-FHFEXIEX-CIF47NYe.js +1 -0
  91. package/dist/assets/stateDiagram-v2-QKLJ7IA2-Cy1rmPfG.js +1 -0
  92. package/dist/assets/timeline-definition-GMOUNBTQ-Bes4B58n.js +120 -0
  93. package/dist/assets/treeView-SZITEDCU-DPKseaET.js +1 -0
  94. package/dist/assets/treemap-W4RFUUIX-DH-7GZe_.js +1 -0
  95. package/dist/assets/vennDiagram-DHZGUBPP-3wx2huKk.js +34 -0
  96. package/dist/assets/wardley-RL74JXVD-AgyXyBN5.js +1 -0
  97. package/dist/assets/wardleyDiagram-NUSXRM2D-DzViT1Yx.js +20 -0
  98. package/dist/assets/xychartDiagram-5P7HB3ND-BO_dbU0r.js +7 -0
  99. package/{index.html → dist/index.html} +2 -1
  100. package/dist/index.js +2625 -0
  101. package/package.json +11 -1
  102. package/.agents/skills/remotion-best-practices/SKILL.md +0 -61
  103. package/.agents/skills/remotion-best-practices/rules/3d.md +0 -86
  104. package/.agents/skills/remotion-best-practices/rules/animations.md +0 -27
  105. package/.agents/skills/remotion-best-practices/rules/assets/charts-bar-chart.tsx +0 -178
  106. package/.agents/skills/remotion-best-practices/rules/assets/text-animations-typewriter.tsx +0 -100
  107. package/.agents/skills/remotion-best-practices/rules/assets/text-animations-word-highlight.tsx +0 -108
  108. package/.agents/skills/remotion-best-practices/rules/assets.md +0 -78
  109. package/.agents/skills/remotion-best-practices/rules/audio-visualization.md +0 -198
  110. package/.agents/skills/remotion-best-practices/rules/audio.md +0 -169
  111. package/.agents/skills/remotion-best-practices/rules/calculate-metadata.md +0 -134
  112. package/.agents/skills/remotion-best-practices/rules/can-decode.md +0 -75
  113. package/.agents/skills/remotion-best-practices/rules/charts.md +0 -120
  114. package/.agents/skills/remotion-best-practices/rules/compositions.md +0 -154
  115. package/.agents/skills/remotion-best-practices/rules/display-captions.md +0 -184
  116. package/.agents/skills/remotion-best-practices/rules/extract-frames.md +0 -229
  117. package/.agents/skills/remotion-best-practices/rules/ffmpeg.md +0 -38
  118. package/.agents/skills/remotion-best-practices/rules/fonts.md +0 -152
  119. package/.agents/skills/remotion-best-practices/rules/get-audio-duration.md +0 -58
  120. package/.agents/skills/remotion-best-practices/rules/get-video-dimensions.md +0 -68
  121. package/.agents/skills/remotion-best-practices/rules/get-video-duration.md +0 -60
  122. package/.agents/skills/remotion-best-practices/rules/gifs.md +0 -141
  123. package/.agents/skills/remotion-best-practices/rules/images.md +0 -134
  124. package/.agents/skills/remotion-best-practices/rules/import-srt-captions.md +0 -69
  125. package/.agents/skills/remotion-best-practices/rules/light-leaks.md +0 -73
  126. package/.agents/skills/remotion-best-practices/rules/lottie.md +0 -70
  127. package/.agents/skills/remotion-best-practices/rules/maps.md +0 -412
  128. package/.agents/skills/remotion-best-practices/rules/measuring-dom-nodes.md +0 -34
  129. package/.agents/skills/remotion-best-practices/rules/measuring-text.md +0 -140
  130. package/.agents/skills/remotion-best-practices/rules/parameters.md +0 -109
  131. package/.agents/skills/remotion-best-practices/rules/sequencing.md +0 -118
  132. package/.agents/skills/remotion-best-practices/rules/sfx.md +0 -26
  133. package/.agents/skills/remotion-best-practices/rules/subtitles.md +0 -36
  134. package/.agents/skills/remotion-best-practices/rules/tailwind.md +0 -11
  135. package/.agents/skills/remotion-best-practices/rules/text-animations.md +0 -20
  136. package/.agents/skills/remotion-best-practices/rules/timing.md +0 -179
  137. package/.agents/skills/remotion-best-practices/rules/transcribe-captions.md +0 -70
  138. package/.agents/skills/remotion-best-practices/rules/transitions.md +0 -197
  139. package/.agents/skills/remotion-best-practices/rules/transparent-videos.md +0 -106
  140. package/.agents/skills/remotion-best-practices/rules/trimming.md +0 -51
  141. package/.agents/skills/remotion-best-practices/rules/videos.md +0 -171
  142. package/.agents/skills/remotion-best-practices/rules/voiceover.md +0 -99
  143. package/.agents/skills/simple/SKILL.md +0 -52
  144. package/.agents/skills/vercel-react-best-practices/AGENTS.md +0 -3254
  145. package/.agents/skills/vercel-react-best-practices/README.md +0 -123
  146. package/.agents/skills/vercel-react-best-practices/SKILL.md +0 -141
  147. package/.agents/skills/vercel-react-best-practices/rules/advanced-event-handler-refs.md +0 -55
  148. package/.agents/skills/vercel-react-best-practices/rules/advanced-init-once.md +0 -42
  149. package/.agents/skills/vercel-react-best-practices/rules/advanced-use-latest.md +0 -39
  150. package/.agents/skills/vercel-react-best-practices/rules/async-api-routes.md +0 -38
  151. package/.agents/skills/vercel-react-best-practices/rules/async-defer-await.md +0 -80
  152. package/.agents/skills/vercel-react-best-practices/rules/async-dependencies.md +0 -51
  153. package/.agents/skills/vercel-react-best-practices/rules/async-parallel.md +0 -28
  154. package/.agents/skills/vercel-react-best-practices/rules/async-suspense-boundaries.md +0 -99
  155. package/.agents/skills/vercel-react-best-practices/rules/bundle-barrel-imports.md +0 -59
  156. package/.agents/skills/vercel-react-best-practices/rules/bundle-conditional.md +0 -31
  157. package/.agents/skills/vercel-react-best-practices/rules/bundle-defer-third-party.md +0 -49
  158. package/.agents/skills/vercel-react-best-practices/rules/bundle-dynamic-imports.md +0 -35
  159. package/.agents/skills/vercel-react-best-practices/rules/bundle-preload.md +0 -50
  160. package/.agents/skills/vercel-react-best-practices/rules/client-event-listeners.md +0 -74
  161. package/.agents/skills/vercel-react-best-practices/rules/client-localstorage-schema.md +0 -71
  162. package/.agents/skills/vercel-react-best-practices/rules/client-passive-event-listeners.md +0 -48
  163. package/.agents/skills/vercel-react-best-practices/rules/client-swr-dedup.md +0 -56
  164. package/.agents/skills/vercel-react-best-practices/rules/js-batch-dom-css.md +0 -107
  165. package/.agents/skills/vercel-react-best-practices/rules/js-cache-function-results.md +0 -80
  166. package/.agents/skills/vercel-react-best-practices/rules/js-cache-property-access.md +0 -28
  167. package/.agents/skills/vercel-react-best-practices/rules/js-cache-storage.md +0 -70
  168. package/.agents/skills/vercel-react-best-practices/rules/js-combine-iterations.md +0 -32
  169. package/.agents/skills/vercel-react-best-practices/rules/js-early-exit.md +0 -50
  170. package/.agents/skills/vercel-react-best-practices/rules/js-flatmap-filter.md +0 -60
  171. package/.agents/skills/vercel-react-best-practices/rules/js-hoist-regexp.md +0 -45
  172. package/.agents/skills/vercel-react-best-practices/rules/js-index-maps.md +0 -37
  173. package/.agents/skills/vercel-react-best-practices/rules/js-length-check-first.md +0 -49
  174. package/.agents/skills/vercel-react-best-practices/rules/js-min-max-loop.md +0 -82
  175. package/.agents/skills/vercel-react-best-practices/rules/js-set-map-lookups.md +0 -24
  176. package/.agents/skills/vercel-react-best-practices/rules/js-tosorted-immutable.md +0 -57
  177. package/.agents/skills/vercel-react-best-practices/rules/rendering-activity.md +0 -26
  178. package/.agents/skills/vercel-react-best-practices/rules/rendering-animate-svg-wrapper.md +0 -47
  179. package/.agents/skills/vercel-react-best-practices/rules/rendering-conditional-render.md +0 -40
  180. package/.agents/skills/vercel-react-best-practices/rules/rendering-content-visibility.md +0 -38
  181. package/.agents/skills/vercel-react-best-practices/rules/rendering-hoist-jsx.md +0 -46
  182. package/.agents/skills/vercel-react-best-practices/rules/rendering-hydration-no-flicker.md +0 -82
  183. package/.agents/skills/vercel-react-best-practices/rules/rendering-hydration-suppress-warning.md +0 -30
  184. package/.agents/skills/vercel-react-best-practices/rules/rendering-resource-hints.md +0 -85
  185. package/.agents/skills/vercel-react-best-practices/rules/rendering-script-defer-async.md +0 -68
  186. package/.agents/skills/vercel-react-best-practices/rules/rendering-svg-precision.md +0 -28
  187. package/.agents/skills/vercel-react-best-practices/rules/rendering-usetransition-loading.md +0 -75
  188. package/.agents/skills/vercel-react-best-practices/rules/rerender-defer-reads.md +0 -39
  189. package/.agents/skills/vercel-react-best-practices/rules/rerender-dependencies.md +0 -45
  190. package/.agents/skills/vercel-react-best-practices/rules/rerender-derived-state-no-effect.md +0 -40
  191. package/.agents/skills/vercel-react-best-practices/rules/rerender-derived-state.md +0 -29
  192. package/.agents/skills/vercel-react-best-practices/rules/rerender-functional-setstate.md +0 -74
  193. package/.agents/skills/vercel-react-best-practices/rules/rerender-lazy-state-init.md +0 -58
  194. package/.agents/skills/vercel-react-best-practices/rules/rerender-memo-with-default-value.md +0 -38
  195. package/.agents/skills/vercel-react-best-practices/rules/rerender-memo.md +0 -44
  196. package/.agents/skills/vercel-react-best-practices/rules/rerender-move-effect-to-event.md +0 -45
  197. package/.agents/skills/vercel-react-best-practices/rules/rerender-no-inline-components.md +0 -82
  198. package/.agents/skills/vercel-react-best-practices/rules/rerender-simple-expression-in-memo.md +0 -35
  199. package/.agents/skills/vercel-react-best-practices/rules/rerender-transitions.md +0 -40
  200. package/.agents/skills/vercel-react-best-practices/rules/rerender-use-ref-transient-values.md +0 -73
  201. package/.agents/skills/vercel-react-best-practices/rules/server-after-nonblocking.md +0 -73
  202. package/.agents/skills/vercel-react-best-practices/rules/server-auth-actions.md +0 -96
  203. package/.agents/skills/vercel-react-best-practices/rules/server-cache-lru.md +0 -41
  204. package/.agents/skills/vercel-react-best-practices/rules/server-cache-react.md +0 -76
  205. package/.agents/skills/vercel-react-best-practices/rules/server-dedup-props.md +0 -65
  206. package/.agents/skills/vercel-react-best-practices/rules/server-hoist-static-io.md +0 -142
  207. package/.agents/skills/vercel-react-best-practices/rules/server-parallel-fetching.md +0 -83
  208. package/.agents/skills/vercel-react-best-practices/rules/server-serialization.md +0 -38
  209. package/.claude/CLAUDE.md +0 -184
  210. package/.claude/commands/review.md +0 -120
  211. package/.claude/commands/sync-docs.md +0 -71
  212. package/.claude/roadmap.md +0 -121
  213. package/.claude/rules/style-guide.md +0 -830
  214. package/.claude/settings.json +0 -18
  215. package/.claude/user-stories.md +0 -333
  216. package/AGENTS.md +0 -68
  217. package/Makefile +0 -32
  218. package/biome.json +0 -79
  219. package/bun.lock +0 -854
  220. package/bunfig.toml +0 -2
  221. package/docs/design.md +0 -563
  222. package/docs/perf-baseline.md +0 -130
  223. package/docs/plans/2026-03-13-client-mode-design.md +0 -86
  224. package/docs/plans/2026-03-13-client-mode-plan.md +0 -605
  225. package/docs/plans/2026-03-13-keyboard-shortcuts-design.md +0 -129
  226. package/docs/plans/2026-03-13-keyboard-shortcuts-plan.md +0 -1471
  227. package/docs/plans/2026-03-13-multi-document-design.md +0 -183
  228. package/docs/plans/2026-03-13-performance-benchmarks-design.md +0 -121
  229. package/docs/superpowers/plans/2026-03-26-surgical-pruning.md +0 -1176
  230. package/docs/superpowers/specs/2026-03-27-go-server-rewrite-design.md +0 -284
  231. package/e2e/comments.spec.ts +0 -81
  232. package/e2e/document-load.spec.ts +0 -32
  233. package/e2e/export.spec.ts +0 -58
  234. package/e2e/fixtures/sample.md +0 -7
  235. package/e2e/perf/add-comment.spec.ts +0 -116
  236. package/e2e/perf/fixtures/generate.ts +0 -327
  237. package/e2e/perf/initial-load.spec.ts +0 -49
  238. package/e2e/perf/perf.setup.ts +0 -23
  239. package/e2e/perf/perf.teardown.ts +0 -9
  240. package/e2e/perf/screenshot-final.png +0 -0
  241. package/e2e/perf/scroll.spec.ts +0 -39
  242. package/e2e/perf/tab-switch.spec.ts +0 -69
  243. package/e2e/perf/text-selection.spec.ts +0 -119
  244. package/e2e/perf/utils/metrics.ts +0 -350
  245. package/e2e/perf/utils/perf-cli.ts +0 -86
  246. package/e2e/persistence-file.spec.ts +0 -357
  247. package/e2e/utils/cli.ts +0 -84
  248. package/e2e/utils/selection.ts +0 -79
  249. package/go/cmd/readit/main.go +0 -416
  250. package/go/go.mod +0 -20
  251. package/go/go.sum +0 -41
  252. package/go/internal/server/anchor.go +0 -302
  253. package/go/internal/server/anchor_test.go +0 -111
  254. package/go/internal/server/comments.go +0 -390
  255. package/go/internal/server/documents.go +0 -113
  256. package/go/internal/server/embed.go +0 -17
  257. package/go/internal/server/headings.go +0 -33
  258. package/go/internal/server/headings_test.go +0 -75
  259. package/go/internal/server/htmltext.go +0 -123
  260. package/go/internal/server/markdown.go +0 -157
  261. package/go/internal/server/markdown_bench_test.go +0 -42
  262. package/go/internal/server/markdown_test.go +0 -79
  263. package/go/internal/server/server.go +0 -453
  264. package/go/internal/server/server_bench_test.go +0 -122
  265. package/go/internal/server/settings.go +0 -110
  266. package/go/internal/server/sse.go +0 -140
  267. package/go/internal/server/storage.go +0 -275
  268. package/go/internal/server/storage_test.go +0 -152
  269. package/go/internal/server/template.go +0 -66
  270. package/go/internal/server/types.go +0 -101
  271. package/go/internal/server/watcher.go +0 -74
  272. package/lefthook.yml +0 -8
  273. package/nvim-readit/lua/readit/health.lua +0 -64
  274. package/nvim-readit/lua/readit/init.lua +0 -463
  275. package/nvim-readit/plugin/readit.lua +0 -19
  276. package/playwright.config.ts +0 -34
  277. package/skills-lock.json +0 -20
  278. package/src/App.svelte +0 -890
  279. package/src/cli.ts +0 -881
  280. package/src/components/ActionsMenu.svelte +0 -95
  281. package/src/components/CommentBadge.svelte +0 -67
  282. package/src/components/CommentErrorBanner.svelte +0 -33
  283. package/src/components/CommentInput.svelte +0 -75
  284. package/src/components/CommentListItem.svelte +0 -95
  285. package/src/components/CommentManager.svelte +0 -129
  286. package/src/components/CommentNav.svelte +0 -109
  287. package/src/components/DocumentViewer.svelte +0 -233
  288. package/src/components/FloatingComment.svelte +0 -107
  289. package/src/components/Header.svelte +0 -76
  290. package/src/components/InlineEditor.svelte +0 -72
  291. package/src/components/MarginNote.svelte +0 -167
  292. package/src/components/MarginNotesContainer.svelte +0 -33
  293. package/src/components/MermaidEnhancer.svelte +0 -218
  294. package/src/components/MermaidModal.svelte +0 -67
  295. package/src/components/RawModal.svelte +0 -126
  296. package/src/components/ReanchorConfirm.svelte +0 -30
  297. package/src/components/SettingsModal.svelte +0 -220
  298. package/src/components/ShortcutCapture.svelte +0 -82
  299. package/src/components/ShortcutList.svelte +0 -145
  300. package/src/components/TabBar.svelte +0 -52
  301. package/src/components/TableOfContents.svelte +0 -125
  302. package/src/components/ui/ActionLink.svelte +0 -40
  303. package/src/components/ui/Button.svelte +0 -53
  304. package/src/components/ui/Dialog.svelte +0 -97
  305. package/src/components/ui/DropdownMenu.svelte +0 -85
  306. package/src/components/ui/DropdownMenuItem.svelte +0 -38
  307. package/src/components/ui/DropdownMenuSeparator.svelte +0 -11
  308. package/src/components/ui/Text.svelte +0 -42
  309. package/src/env.d.ts +0 -6
  310. package/src/index.css +0 -859
  311. package/src/lib/__fixtures__/bench-data.ts +0 -114
  312. package/src/lib/anchor.bench.ts +0 -91
  313. package/src/lib/anchor.test.ts +0 -527
  314. package/src/lib/anchor.ts +0 -381
  315. package/src/lib/comment-storage.bench.ts +0 -49
  316. package/src/lib/comment-storage.test.ts +0 -694
  317. package/src/lib/comment-storage.ts +0 -226
  318. package/src/lib/export.bench.ts +0 -21
  319. package/src/lib/export.ts +0 -36
  320. package/src/lib/fetch-or-throw.test.ts +0 -59
  321. package/src/lib/fetch-or-throw.ts +0 -12
  322. package/src/lib/headings.test.ts +0 -103
  323. package/src/lib/headings.ts +0 -44
  324. package/src/lib/highlight/core.test.ts +0 -93
  325. package/src/lib/highlight/dom.ts +0 -187
  326. package/src/lib/highlight/highlight-registry.ts +0 -221
  327. package/src/lib/highlight/highlight.bench.ts +0 -92
  328. package/src/lib/highlight/highlighter.ts +0 -247
  329. package/src/lib/highlight/resolver.ts +0 -38
  330. package/src/lib/highlight/types.ts +0 -17
  331. package/src/lib/html-text.test.ts +0 -162
  332. package/src/lib/html-text.ts +0 -161
  333. package/src/lib/i18n/en.ts +0 -124
  334. package/src/lib/i18n/index.ts +0 -3
  335. package/src/lib/i18n/ja.ts +0 -126
  336. package/src/lib/i18n/translations.ts +0 -27
  337. package/src/lib/i18n/types.ts +0 -130
  338. package/src/lib/key-lock.test.ts +0 -104
  339. package/src/lib/key-lock.ts +0 -23
  340. package/src/lib/margin-layout.bench.ts +0 -61
  341. package/src/lib/margin-layout.ts +0 -71
  342. package/src/lib/markdown-renderer.test.ts +0 -154
  343. package/src/lib/markdown-renderer.ts +0 -178
  344. package/src/lib/mermaid-config.ts +0 -38
  345. package/src/lib/mermaid-renderer.ts +0 -162
  346. package/src/lib/mermaid-worker.ts +0 -60
  347. package/src/lib/positions.ts +0 -157
  348. package/src/lib/shortcut-registry.ts +0 -244
  349. package/src/lib/utils.ts +0 -15
  350. package/src/main.ts +0 -16
  351. package/src/schema.ts +0 -92
  352. package/src/server.ts +0 -1216
  353. package/src/stores/app.svelte.ts +0 -231
  354. package/src/stores/locale.svelte.ts +0 -46
  355. package/src/stores/settings.svelte.ts +0 -90
  356. package/src/stores/shortcuts.svelte.ts +0 -104
  357. package/src/stores/ui.svelte.ts +0 -12
  358. package/src/template.ts +0 -104
  359. package/src/test-setup.ts +0 -48
  360. package/svelte.config.js +0 -5
  361. package/test.md +0 -74
  362. package/tsconfig.cli.json +0 -12
  363. package/tsconfig.json +0 -20
  364. package/vite.config.ts +0 -47
  365. package/vitest.config.ts +0 -15
  366. package/vscode-readit/.mcp.json +0 -7
  367. package/vscode-readit/.vscodeignore +0 -7
  368. package/vscode-readit/bun.lock +0 -78
  369. package/vscode-readit/icon.svg +0 -10
  370. package/vscode-readit/package.json +0 -110
  371. package/vscode-readit/src/extension.ts +0 -117
  372. package/vscode-readit/src/server-manager.ts +0 -272
  373. package/vscode-readit/src/webview-provider.ts +0 -204
  374. package/vscode-readit/tsconfig.json +0 -20
@@ -1,218 +0,0 @@
1
- <script lang="ts">
2
- import { Code2, Image as ImageIcon, Maximize2 } from "lucide-svelte";
3
- import { mount, unmount } from "svelte";
4
- import { localeState, t } from "../stores/locale.svelte";
5
- import MermaidModal from "./MermaidModal.svelte";
6
-
7
- interface Props {
8
- /** The article element that contains all rendered mermaid containers. */
9
- root: HTMLElement | undefined;
10
- /** Bumped whenever document content is re-rendered (rescan triggers). */
11
- contentVersion: number;
12
- /** Called after an inline toggle so margin notes / positions can recache. */
13
- notifyContentChanged?: () => void;
14
- }
15
-
16
- let { root, contentVersion, notifyContentChanged }: Props = $props();
17
-
18
- let modalOpen = $state(false);
19
- let modalSvg = $state("");
20
- let modalSource = $state("");
21
-
22
- const ENHANCED_FLAG = "readitMermaidEnhanced";
23
-
24
- function decodeSource(container: HTMLElement): string {
25
- const encoded = container.dataset.mermaidSource ?? "";
26
- try {
27
- return decodeURIComponent(encoded);
28
- } catch {
29
- return encoded;
30
- }
31
- }
32
-
33
- function openModal(container: HTMLElement) {
34
- const svgEl = container.querySelector("svg");
35
- modalSvg = svgEl ? svgEl.outerHTML : "";
36
- modalSource = decodeSource(container);
37
- modalOpen = true;
38
- }
39
-
40
- function ensureSourceView(container: HTMLElement, source: string): HTMLElement {
41
- let pre = container.querySelector<HTMLElement>(".mermaid-source-view");
42
- if (pre) return pre;
43
- pre = document.createElement("pre");
44
- pre.className = "mermaid-source-view";
45
- const codeEl = document.createElement("code");
46
- codeEl.className = "language-mermaid";
47
- codeEl.textContent = source;
48
- pre.appendChild(codeEl);
49
- pre.style.display = "none";
50
- // Insert before the toolbar so the toolbar stays the last child.
51
- const toolbar = container.querySelector(".mermaid-toolbar");
52
- container.insertBefore(pre, toolbar);
53
- return pre;
54
- }
55
-
56
- function toggleInline(container: HTMLElement, source: string): void {
57
- const svg = container.querySelector<SVGElement>("svg");
58
- const pre = ensureSourceView(container, source);
59
- const showingCode = container.dataset.mermaidView === "code";
60
- const next = showingCode ? "graph" : "code";
61
-
62
- if (svg) svg.style.display = next === "code" ? "none" : "";
63
- pre.style.display = next === "code" ? "block" : "none";
64
- container.dataset.mermaidView = next;
65
-
66
- const toolbar = container.querySelector<HTMLElement>(".mermaid-toolbar");
67
- const toggleBtn = toolbar?.querySelector<HTMLButtonElement>(
68
- '[data-action="toggle"]',
69
- );
70
- toggleBtn?.setAttribute(
71
- "aria-label",
72
- next === "code" ? t("mermaid.showDiagram") : t("mermaid.showSource"),
73
- );
74
- toggleBtn?.setAttribute("aria-pressed", next === "code" ? "true" : "false");
75
-
76
- const handle = (
77
- toolbar as (HTMLElement & { _readitHandle?: ToolbarHandle }) | null
78
- )?._readitHandle;
79
- handle?.remountToggleIcon(next);
80
-
81
- notifyContentChanged?.();
82
- }
83
-
84
- interface ToolbarHandle {
85
- cleanup: () => void;
86
- remountToggleIcon: (view: "graph" | "code") => void;
87
- }
88
-
89
- function mountToggleIcon(target: HTMLElement, view: "graph" | "code") {
90
- // Show "code" icon when graph is visible (click to see code), and vice versa.
91
- const Icon = view === "graph" ? Code2 : ImageIcon;
92
- return mount(Icon, { target, props: { size: 14 } });
93
- }
94
-
95
- function buildToolbar(container: HTMLElement): HTMLElement {
96
- const toolbar = document.createElement("div");
97
- toolbar.className = "mermaid-toolbar";
98
- toolbar.setAttribute("contenteditable", "false");
99
-
100
- const toggleBtn = document.createElement("button");
101
- toggleBtn.type = "button";
102
- toggleBtn.dataset.action = "toggle";
103
- toggleBtn.setAttribute("aria-label", t("mermaid.showSource"));
104
- toggleBtn.setAttribute("aria-pressed", "false");
105
-
106
- const expandBtn = document.createElement("button");
107
- expandBtn.type = "button";
108
- expandBtn.dataset.action = "expand";
109
- expandBtn.setAttribute("aria-label", t("mermaid.expand"));
110
-
111
- toolbar.appendChild(toggleBtn);
112
- toolbar.appendChild(expandBtn);
113
-
114
- let toggleIcon = mountToggleIcon(toggleBtn, "graph");
115
- const expandIcon = mount(Maximize2, {
116
- target: expandBtn,
117
- props: { size: 14 },
118
- });
119
-
120
- toggleBtn.addEventListener("click", (e) => {
121
- e.preventDefault();
122
- e.stopPropagation();
123
- toggleInline(container, decodeSource(container));
124
- });
125
-
126
- expandBtn.addEventListener("click", (e) => {
127
- e.preventDefault();
128
- e.stopPropagation();
129
- openModal(container);
130
- });
131
-
132
- const handle: ToolbarHandle = {
133
- cleanup: () => {
134
- void unmount(toggleIcon);
135
- void unmount(expandIcon);
136
- },
137
- remountToggleIcon: (view) => {
138
- void unmount(toggleIcon);
139
- toggleIcon = mountToggleIcon(toggleBtn, view);
140
- },
141
- };
142
- (toolbar as HTMLElement & { _readitHandle?: ToolbarHandle })._readitHandle =
143
- handle;
144
-
145
- return toolbar;
146
- }
147
-
148
- function enhance(target: HTMLElement) {
149
- const containers = target.querySelectorAll<HTMLElement>(
150
- ".mermaid-container[data-mermaid-source]",
151
- );
152
-
153
- for (const container of containers) {
154
- if (container.dataset[ENHANCED_FLAG] === "true") continue;
155
- container.dataset[ENHANCED_FLAG] = "true";
156
-
157
- // Ensure the container can host the absolutely-positioned toolbar.
158
- container.style.position = "relative";
159
-
160
- const toolbar = buildToolbar(container);
161
- container.appendChild(toolbar);
162
- }
163
- }
164
-
165
- function cleanup(target: HTMLElement) {
166
- const toolbars = target.querySelectorAll<HTMLElement>(".mermaid-toolbar");
167
- for (const tb of toolbars) {
168
- (
169
- tb as HTMLElement & { _readitHandle?: ToolbarHandle }
170
- )._readitHandle?.cleanup();
171
- tb.remove();
172
- }
173
- const enhanced = target.querySelectorAll<HTMLElement>(
174
- ".mermaid-container[data-readit-mermaid-enhanced]",
175
- );
176
- for (const c of enhanced) {
177
- delete c.dataset[ENHANCED_FLAG];
178
- }
179
- }
180
-
181
- $effect(() => {
182
- if (!root) return;
183
- // Re-scan whenever contentVersion changes; declared so Svelte tracks it.
184
- void contentVersion;
185
- enhance(root);
186
- return () => {
187
- if (root) cleanup(root);
188
- };
189
- });
190
-
191
- // Refresh aria-labels on existing imperative toolbars when locale changes.
192
- $effect(() => {
193
- if (!root) return;
194
- void localeState.locale;
195
- const toolbars = root.querySelectorAll<HTMLElement>(".mermaid-toolbar");
196
- for (const tb of toolbars) {
197
- const container = tb.closest<HTMLElement>(".mermaid-container");
198
- const showingCode = container?.dataset.mermaidView === "code";
199
- tb.querySelector<HTMLButtonElement>('[data-action="toggle"]')?.setAttribute(
200
- "aria-label",
201
- showingCode ? t("mermaid.showDiagram") : t("mermaid.showSource"),
202
- );
203
- tb.querySelector<HTMLButtonElement>('[data-action="expand"]')?.setAttribute(
204
- "aria-label",
205
- t("mermaid.expand"),
206
- );
207
- }
208
- });
209
- </script>
210
-
211
- <MermaidModal
212
- bind:open={modalOpen}
213
- svg={modalSvg}
214
- source={modalSource}
215
- onclose={() => {
216
- modalOpen = false;
217
- }}
218
- />
@@ -1,67 +0,0 @@
1
- <script lang="ts">
2
- import { Code2, Image as ImageIcon } from "lucide-svelte";
3
- import { t } from "../stores/locale.svelte";
4
- import Dialog from "./ui/Dialog.svelte";
5
-
6
- interface Props {
7
- open: boolean;
8
- svg: string;
9
- source: string;
10
- onclose: () => void;
11
- }
12
-
13
- let { open = $bindable(false), svg, source, onclose }: Props = $props();
14
-
15
- type View = "graph" | "code";
16
- let view = $state<View>("graph");
17
-
18
- // Reset to graph view each time the modal opens so the user always
19
- // lands on the diagram first.
20
- $effect(() => {
21
- if (open) view = "graph";
22
- });
23
- </script>
24
-
25
- <Dialog
26
- bind:open
27
- {onclose}
28
- contentClass="w-[90vw] h-[90vh] max-w-[90vw]"
29
- >
30
- {#snippet header()}
31
- {t("mermaid.modalTitle")}
32
- {/snippet}
33
-
34
- {#snippet headerActions()}
35
- <div class="flex items-center gap-1 mr-8">
36
- <button
37
- type="button"
38
- onclick={() => (view = "graph")}
39
- aria-pressed={view === "graph"}
40
- class="inline-flex items-center gap-1.5 px-2.5 py-1 text-xs rounded-md text-zinc-600 dark:text-zinc-400 hover:bg-zinc-100 dark:hover:bg-zinc-800 aria-pressed:bg-zinc-100 dark:aria-pressed:bg-zinc-800 aria-pressed:text-zinc-900 dark:aria-pressed:text-zinc-100"
41
- >
42
- <ImageIcon class="w-3.5 h-3.5" />
43
- {t("mermaid.viewGraph")}
44
- </button>
45
- <button
46
- type="button"
47
- onclick={() => (view = "code")}
48
- aria-pressed={view === "code"}
49
- class="inline-flex items-center gap-1.5 px-2.5 py-1 text-xs rounded-md text-zinc-600 dark:text-zinc-400 hover:bg-zinc-100 dark:hover:bg-zinc-800 aria-pressed:bg-zinc-100 dark:aria-pressed:bg-zinc-800 aria-pressed:text-zinc-900 dark:aria-pressed:text-zinc-100"
50
- >
51
- <Code2 class="w-3.5 h-3.5" />
52
- {t("mermaid.viewCode")}
53
- </button>
54
- </div>
55
- {/snippet}
56
-
57
- <div class="w-full h-full overflow-auto flex items-center justify-center">
58
- {#if view === "graph"}
59
- <!-- eslint-disable-next-line -- trusted mermaid render output -->
60
- <div class="mermaid-container mermaid-modal-graph">{@html svg}</div>
61
- {:else}
62
- <pre
63
- class="w-full h-full m-0 p-4 text-xs leading-relaxed font-mono text-zinc-800 dark:text-zinc-200 bg-zinc-50 dark:bg-zinc-950 rounded-lg overflow-auto whitespace-pre"
64
- >{source}</pre>
65
- {/if}
66
- </div>
67
- </Dialog>
@@ -1,126 +0,0 @@
1
- <script lang="ts">
2
- import { Copy } from "lucide-svelte";
3
- import { app } from "../stores/app.svelte";
4
- import { t } from "../stores/locale.svelte";
5
- import Button from "./ui/Button.svelte";
6
- import Dialog from "./ui/Dialog.svelte";
7
- import Text from "./ui/Text.svelte";
8
-
9
- interface Props {
10
- open: boolean;
11
- onclose: () => void;
12
- }
13
-
14
- let { open = $bindable(false), onclose }: Props = $props();
15
-
16
- type ModalState =
17
- | { status: "idle" }
18
- | { status: "loading" }
19
- | { status: "error"; error: string }
20
- | { status: "empty"; path: string }
21
- | { status: "success"; content: string; path: string };
22
-
23
- let modalState = $state<ModalState>({ status: "idle" });
24
-
25
- $effect(() => {
26
- if (!open) {
27
- modalState = { status: "idle" };
28
- return;
29
- }
30
-
31
- modalState = { status: "loading" };
32
-
33
- const query = app.activeDocumentPath
34
- ? `?path=${encodeURIComponent(app.activeDocumentPath)}`
35
- : "";
36
-
37
- fetch(`/api/comments/raw${query}`)
38
- .then((response) => {
39
- if (!response.ok) {
40
- throw new Error("Failed to fetch raw comments");
41
- }
42
- return response.json();
43
- })
44
- .then((result) => {
45
- if (result.content === null) {
46
- modalState = { status: "empty", path: result.path };
47
- } else {
48
- modalState = {
49
- status: "success",
50
- content: result.content,
51
- path: result.path,
52
- };
53
- }
54
- })
55
- .catch((err) => {
56
- modalState = {
57
- status: "error",
58
- error: err instanceof Error ? err.message : "Unknown error",
59
- };
60
- });
61
- });
62
-
63
- async function handleCopy() {
64
- if (modalState.status !== "success") return;
65
-
66
- try {
67
- await navigator.clipboard.writeText(modalState.content);
68
- } catch {}
69
- }
70
- </script>
71
-
72
- <Dialog bind:open {onclose} contentClass="max-w-2xl max-h-[80vh]">
73
- {#snippet header()}
74
- {t("rawModal.title")}
75
- {/snippet}
76
-
77
- {#snippet headerActions()}
78
- {#if modalState.status === "success"}
79
- <Button
80
- variant="ghost"
81
- size="icon"
82
- class="size-7"
83
- onclick={handleCopy}
84
- title={t("rawModal.copyTitle")}
85
- >
86
- <Copy class="w-4 h-4" />
87
- </Button>
88
- {/if}
89
- {/snippet}
90
-
91
- {#if modalState.status === "success" || modalState.status === "empty"}
92
- <div
93
- class="px-4 py-2 border-b border-zinc-50 dark:border-zinc-800 text-xs text-zinc-400 dark:text-zinc-500 font-mono truncate -mt-4 -mx-4 mb-4"
94
- >
95
- {modalState.path}
96
- </div>
97
- {/if}
98
-
99
- {#if modalState.status === "loading"}
100
- <Text variant="caption" class="text-center py-8">
101
- {t("rawModal.loading")}
102
- </Text>
103
- {/if}
104
-
105
- {#if modalState.status === "error"}
106
- <Text variant="body" class="text-red-500 text-center py-8">
107
- {modalState.error}
108
- </Text>
109
- {/if}
110
-
111
- {#if modalState.status === "empty"}
112
- <Text variant="caption" class="text-center py-8">
113
- {t("rawModal.noComments")}
114
- </Text>
115
- {/if}
116
-
117
- {#if modalState.status === "success"}
118
- <Text
119
- variant="body"
120
- as="pre"
121
- class="text-xs font-mono whitespace-pre-wrap break-words leading-relaxed"
122
- >
123
- {modalState.content}
124
- </Text>
125
- {/if}
126
- </Dialog>
@@ -1,30 +0,0 @@
1
- <script lang="ts">
2
- import { t } from "../stores/locale.svelte";
3
- import Button from "./ui/Button.svelte";
4
- import Text from "./ui/Text.svelte";
5
-
6
- interface Props {
7
- selectionText: string;
8
- onconfirm: () => void;
9
- oncancel: () => void;
10
- }
11
-
12
- let { selectionText, onconfirm, oncancel }: Props = $props();
13
- </script>
14
-
15
- <div class="border-t border-zinc-200 dark:border-zinc-700 pt-2 pb-3 pl-6">
16
- <Text variant="body" class="mb-2">
17
- {t("reanchor.question")}
18
- </Text>
19
- <Text variant="caption" class="italic line-clamp-2 mb-2">
20
- "{selectionText}"
21
- </Text>
22
- <div class="flex gap-3 text-sm">
23
- <Button variant="link" size="sm" onclick={onconfirm}>
24
- {t("reanchor.confirm")}
25
- </Button>
26
- <Button variant="ghost" size="sm" onclick={oncancel}>
27
- {t("reanchor.cancel")}
28
- </Button>
29
- </div>
30
- </div>
@@ -1,220 +0,0 @@
1
- <script lang="ts">
2
- import { Check, ChevronDown } from "lucide-svelte";
3
- import { type Locale, Locales } from "../lib/i18n";
4
- import { cn } from "../lib/utils";
5
- import { FontFamilies, type FontFamily, ThemeModes } from "../schema";
6
- import { localeState, setLocale, t } from "../stores/locale.svelte";
7
- import {
8
- settings,
9
- updateFontFamily,
10
- updateThemeMode,
11
- } from "../stores/settings.svelte";
12
- import ShortcutList from "./ShortcutList.svelte";
13
- import Dialog from "./ui/Dialog.svelte";
14
- import DropdownMenu from "./ui/DropdownMenu.svelte";
15
- import DropdownMenuItem from "./ui/DropdownMenuItem.svelte";
16
- import Text from "./ui/Text.svelte";
17
-
18
- interface Props {
19
- open: boolean;
20
- onclose: () => void;
21
- }
22
-
23
- let { open = $bindable(false), onclose }: Props = $props();
24
-
25
- const LOCALE_OPTIONS = [
26
- { value: Locales.JA, label: "日本語" },
27
- { value: Locales.EN, label: "English" },
28
- ] as const;
29
-
30
- let themeOptions = $derived([
31
- { value: ThemeModes.SYSTEM, label: t("settings.theme.system") },
32
- { value: ThemeModes.LIGHT, label: t("settings.theme.light") },
33
- { value: ThemeModes.DARK, label: t("settings.theme.dark") },
34
- ]);
35
-
36
- let fontOptions = $derived([
37
- {
38
- value: FontFamilies.SERIF,
39
- label: t("settings.font.serif"),
40
- fontClass: "font-serif",
41
- },
42
- {
43
- value: FontFamilies.SANS_SERIF,
44
- label: t("settings.font.sansSerif"),
45
- fontClass: "font-sans",
46
- },
47
- ]);
48
-
49
- let activeTheme = $derived(
50
- themeOptions.find((o) => o.value === settings.themeMode) ?? themeOptions[0],
51
- );
52
- let activeFont = $derived(
53
- fontOptions.find((o) => o.value === settings.fontFamily) ?? fontOptions[0],
54
- );
55
- let activeLocale = $derived(
56
- LOCALE_OPTIONS.find((o) => o.value === localeState.locale) ??
57
- LOCALE_OPTIONS[0],
58
- );
59
-
60
- const triggerClassName = cn(
61
- "inline-flex items-center gap-2 px-2.5 py-1.5 rounded-lg text-sm",
62
- "border border-zinc-200 dark:border-zinc-700",
63
- "bg-white dark:bg-zinc-800",
64
- "text-zinc-700 dark:text-zinc-300",
65
- "hover:bg-zinc-50 dark:hover:bg-zinc-700/50",
66
- "transition-colors cursor-pointer",
67
- );
68
-
69
- let themeDropdownOpen = $state(false);
70
- let fontDropdownOpen = $state(false);
71
- let localeDropdownOpen = $state(false);
72
- </script>
73
-
74
- <Dialog bind:open {onclose} contentClass="max-w-md">
75
- {#snippet header()}
76
- {t("settings.title")}
77
- {/snippet}
78
-
79
- <div class="space-y-4">
80
- <div>
81
- <Text variant="overline" as="h3" class="mb-3">
82
- {t("settings.theme")}
83
- </Text>
84
- <DropdownMenu bind:open={themeDropdownOpen} align="start" contentClass="min-w-[160px]">
85
- {#snippet trigger()}
86
- <button type="button" class={triggerClassName}>
87
- {#if activeTheme.value === ThemeModes.SYSTEM}
88
- <span
89
- class="size-2.5 rounded-full bg-gradient-to-r from-amber-400 to-indigo-400"
90
- ></span>
91
- {:else}
92
- <span
93
- class={cn(
94
- "size-2.5 rounded-full",
95
- activeTheme.value === ThemeModes.LIGHT
96
- ? "bg-amber-400"
97
- : "bg-indigo-400",
98
- )}
99
- ></span>
100
- {/if}
101
- <span
102
- class="text-[10px] font-semibold leading-none text-zinc-500 dark:text-zinc-400 bg-zinc-100 dark:bg-zinc-800 rounded px-1 py-0.5"
103
- >Aa</span>
104
- <span>{activeTheme.label}</span>
105
- <ChevronDown class="size-3 text-zinc-400 dark:text-zinc-500" />
106
- </button>
107
- {/snippet}
108
-
109
- {#each themeOptions as option (option.value)}
110
- <DropdownMenuItem
111
- onselect={() => {
112
- updateThemeMode(option.value);
113
- themeDropdownOpen = false;
114
- }}
115
- class="flex items-center gap-2"
116
- >
117
- {#if option.value === ThemeModes.SYSTEM}
118
- <span
119
- class="size-2.5 rounded-full bg-gradient-to-r from-amber-400 to-indigo-400"
120
- ></span>
121
- {:else}
122
- <span
123
- class={cn(
124
- "size-2.5 rounded-full",
125
- option.value === ThemeModes.LIGHT
126
- ? "bg-amber-400"
127
- : "bg-indigo-400",
128
- )}
129
- ></span>
130
- {/if}
131
- <span
132
- class="text-[10px] font-semibold leading-none text-zinc-500 dark:text-zinc-400 bg-zinc-100 dark:bg-zinc-800 rounded px-1 py-0.5"
133
- >Aa</span>
134
- <span class="flex-1">{option.label}</span>
135
- {#if settings.themeMode === option.value}
136
- <Check class="size-3.5 text-zinc-500 dark:text-zinc-400" />
137
- {/if}
138
- </DropdownMenuItem>
139
- {/each}
140
- </DropdownMenu>
141
- </div>
142
-
143
- <div>
144
- <Text variant="overline" as="h3" class="mb-3">
145
- {t("settings.font")}
146
- </Text>
147
- <DropdownMenu bind:open={fontDropdownOpen} align="start" contentClass="min-w-[160px]">
148
- {#snippet trigger()}
149
- <button type="button" class={triggerClassName}>
150
- <span
151
- class={cn(
152
- "text-[10px] font-semibold leading-none text-zinc-500 dark:text-zinc-400 bg-zinc-100 dark:bg-zinc-800 rounded px-1 py-0.5",
153
- activeFont.fontClass,
154
- )}
155
- >Aa</span>
156
- <span>{activeFont.label}</span>
157
- <ChevronDown class="size-3 text-zinc-400 dark:text-zinc-500" />
158
- </button>
159
- {/snippet}
160
-
161
- {#each fontOptions as option (option.value)}
162
- <DropdownMenuItem
163
- onselect={() => {
164
- updateFontFamily(option.value as FontFamily);
165
- fontDropdownOpen = false;
166
- }}
167
- class="flex items-center gap-2"
168
- >
169
- <span
170
- class={cn(
171
- "text-[10px] font-semibold leading-none text-zinc-500 dark:text-zinc-400 bg-zinc-100 dark:bg-zinc-800 rounded px-1 py-0.5",
172
- option.fontClass,
173
- )}
174
- >Aa</span>
175
- <span class="flex-1">{option.label}</span>
176
- {#if settings.fontFamily === option.value}
177
- <Check class="size-3.5 text-zinc-500 dark:text-zinc-400" />
178
- {/if}
179
- </DropdownMenuItem>
180
- {/each}
181
- </DropdownMenu>
182
- </div>
183
-
184
- <div>
185
- <Text variant="overline" as="h3" class="mb-3">
186
- {t("settings.language")}
187
- </Text>
188
- <DropdownMenu bind:open={localeDropdownOpen} align="start" contentClass="min-w-[160px]">
189
- {#snippet trigger()}
190
- <button type="button" class={triggerClassName}>
191
- <span>{activeLocale.label}</span>
192
- <ChevronDown class="size-3 text-zinc-400 dark:text-zinc-500" />
193
- </button>
194
- {/snippet}
195
-
196
- {#each LOCALE_OPTIONS as option (option.value)}
197
- <DropdownMenuItem
198
- onselect={() => {
199
- setLocale(option.value as Locale);
200
- localeDropdownOpen = false;
201
- }}
202
- class="flex items-center gap-2"
203
- >
204
- <span class="flex-1">{option.label}</span>
205
- {#if localeState.locale === option.value}
206
- <Check class="size-3.5 text-zinc-500 dark:text-zinc-400" />
207
- {/if}
208
- </DropdownMenuItem>
209
- {/each}
210
- </DropdownMenu>
211
- </div>
212
-
213
- <div>
214
- <Text variant="overline" as="h3" class="mb-3">
215
- {t("shortcuts.title")}
216
- </Text>
217
- <ShortcutList />
218
- </div>
219
- </div>
220
- </Dialog>