@peaske7/readit 0.2.1 → 0.3.0-rc.1
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.
- package/dist/.vite/manifest.json +1111 -0
- package/dist/assets/_basePickBy-BMMA4Tou.js +1 -0
- package/dist/assets/_baseUniq-D40qku1I.js +1 -0
- package/dist/assets/arc-Ckg65iy8.js +1 -0
- package/dist/assets/architecture-YZFGNWBL-Dv3EY0zV.js +1 -0
- package/dist/assets/architectureDiagram-Q4EWVU46-ClRss4cm.js +36 -0
- package/dist/assets/array-Bjz-wYpJ.js +1 -0
- package/dist/assets/blockDiagram-DXYQGD6D-CBcFvoK1.js +132 -0
- package/dist/assets/c4Diagram-AHTNJAMY-D4d3ZLam.js +10 -0
- package/dist/assets/channel-D9EJxDy_.js +1 -0
- package/dist/assets/chunk-2KRD3SAO-DaFfaCGO.js +1 -0
- package/dist/assets/chunk-336JU56O-yLEQoF0v.js +2 -0
- package/dist/assets/chunk-426QAEUC-Uyzd4wAA.js +1 -0
- package/dist/assets/chunk-4BX2VUAB-DRuTD7x5.js +1 -0
- package/dist/assets/chunk-4TB4RGXK-3xbpIi_o.js +206 -0
- package/dist/assets/chunk-55IACEB6-BExiaAoD.js +1 -0
- package/dist/assets/chunk-5FUZZQ4R-DatVvHnF.js +62 -0
- package/dist/assets/chunk-5PVQY5BW-BKgvrGh8.js +2 -0
- package/dist/assets/chunk-67CJDMHE-DMt8LNEX.js +1 -0
- package/dist/assets/chunk-7N4EOEYR-CzLGefVf.js +1 -0
- package/dist/assets/chunk-AA7GKIK3-B6GFAk4U.js +1 -0
- package/dist/assets/chunk-BSJP7CBP-BK29yehL.js +1 -0
- package/dist/assets/chunk-CIAEETIT-D7hBXImP.js +1 -0
- package/dist/assets/chunk-Dlc7tRH4.js +1 -0
- package/dist/assets/chunk-EDXVE4YY-PYJdlmyH.js +1 -0
- package/dist/assets/chunk-ENJZ2VHE-DUHKBv6x.js +10 -0
- package/dist/assets/chunk-FMBD7UC4-2FWyCCAV.js +15 -0
- package/dist/assets/chunk-FOC6F5B3-DKFHrt4K.js +1 -0
- package/dist/assets/chunk-ICPOFSXX-Bh__D0ec.js +122 -0
- package/dist/assets/chunk-K5T4RW27-D51O7IkG.js +94 -0
- package/dist/assets/chunk-KGLVRYIC-DMHSCH4T.js +1 -0
- package/dist/assets/chunk-LIHQZDEY-C2aANxt9.js +1 -0
- package/dist/assets/chunk-ORNJ4GCN-Db_37NRX.js +1 -0
- package/dist/assets/chunk-OYMX7WX6-BltXOJLJ.js +231 -0
- package/dist/assets/chunk-QZHKN3VN-8Lcg9gti.js +1 -0
- package/dist/assets/chunk-U2HBQHQK-ByS6tilY.js +70 -0
- package/dist/assets/chunk-X2U36JSP-Bm-4Gqg_.js +1 -0
- package/dist/assets/chunk-XPW4576I-Bqbompq4.js +32 -0
- package/dist/assets/chunk-YZCP3GAM-CsC0imPb.js +1 -0
- package/dist/assets/chunk-ZZ45TVLE-CG-CqfPC.js +1 -0
- package/dist/assets/classDiagram-6PBFFD2Q-Jy1uFUk4.js +1 -0
- package/dist/assets/classDiagram-v2-HSJHXN6E-ChiLl3rR.js +1 -0
- package/dist/assets/clone-BBjvuERA.js +1 -0
- package/dist/assets/cose-bilkent-S5V4N54A-q90QeGKv.js +1 -0
- package/dist/assets/cytoscape.esm-BfXff3fb.js +321 -0
- package/dist/assets/dagre-KV5264BT-BQWiLFJB.js +4 -0
- package/dist/assets/dagre-nn_aIZ2E.js +1 -0
- package/dist/assets/defaultLocale-BwmRmqJp.js +1 -0
- package/dist/assets/diagram-5BDNPKRD-CJa7Y97H.js +10 -0
- package/dist/assets/diagram-G4DWMVQ6-tVQGBWfY.js +24 -0
- package/dist/assets/diagram-MMDJMWI5-CpimFldm.js +43 -0
- package/dist/assets/diagram-TYMM5635-D11WQVgy.js +24 -0
- package/dist/assets/dist-BNz65Ibc.js +1 -0
- package/dist/assets/erDiagram-SMLLAGMA-C2bLd0jS.js +85 -0
- package/dist/assets/flowDiagram-DWJPFMVM-Kw3fOOLT.js +162 -0
- package/dist/assets/ganttDiagram-T4ZO3ILL-fyMhyE2X.js +292 -0
- package/dist/assets/gitGraph-7Q5UKJZL-BGFRt2qs.js +1 -0
- package/dist/assets/gitGraphDiagram-UUTBAWPF-D4JoiOvg.js +106 -0
- package/dist/assets/graphlib-DGcD9J2L.js +1 -0
- package/dist/assets/index-Cow3qpoq.css +2 -0
- package/dist/assets/index-DUf7okYi.js +14 -0
- package/dist/assets/info-OMHHGYJF-DI6-Z9vh.js +1 -0
- package/dist/assets/infoDiagram-42DDH7IO-D1ZkeMBy.js +2 -0
- package/dist/assets/init-TPm5RB77.js +1 -0
- package/dist/assets/isArrayLikeObject-69BLnVNM.js +1 -0
- package/dist/assets/isEmpty-DUS28g5f.js +1 -0
- package/dist/assets/ishikawaDiagram-UXIWVN3A-Dv8hzjZB.js +70 -0
- package/dist/assets/journeyDiagram-VCZTEJTY-COeB7F5r.js +139 -0
- package/dist/assets/kanban-definition-6JOO6SKY-BbYmxCYU.js +89 -0
- package/dist/assets/katex-5SGEXwpi.js +261 -0
- package/dist/assets/line-_v2NGEdn.js +1 -0
- package/dist/assets/linear-CXMqTN8N.js +1 -0
- package/dist/assets/mermaid-config-C8a4L22x.js +1 -0
- package/dist/assets/mermaid-parser.core-CFmphzPP.js +4 -0
- package/dist/assets/mermaid.core-DnHAupTp.js +11 -0
- package/dist/assets/mindmap-definition-QFDTVHPH-D7_lIep7.js +96 -0
- package/dist/assets/ordinal-D7l-8DAO.js +1 -0
- package/dist/assets/packet-4T2RLAQJ-DidW3JFc.js +1 -0
- package/dist/assets/path-BVpCanzE.js +1 -0
- package/dist/assets/pie-ZZUOXDRM-Bff2e5hg.js +1 -0
- package/dist/assets/pieDiagram-DEJITSTG-DDvYHCT_.js +30 -0
- package/dist/assets/quadrantDiagram-34T5L4WZ-DcLcIrdi.js +7 -0
- package/dist/assets/radar-PYXPWWZC-CsdZBH3M.js +1 -0
- package/dist/assets/requirementDiagram-MS252O5E-DLX6ld7D.js +84 -0
- package/dist/assets/rough.esm-BoTisKeL.js +1 -0
- package/dist/assets/sankeyDiagram-XADWPNL6-D-1GtsHM.js +10 -0
- package/dist/assets/sequenceDiagram-FGHM5R23-Bwxs0YQg.js +157 -0
- package/dist/assets/src-CrmkjRpa.js +1 -0
- package/dist/assets/stateDiagram-FHFEXIEX-DW7rOcnQ.js +1 -0
- package/dist/assets/stateDiagram-v2-QKLJ7IA2-Jm-24vQ2.js +1 -0
- package/dist/assets/timeline-definition-GMOUNBTQ-DVdHyzxS.js +120 -0
- package/dist/assets/treeView-SZITEDCU-DPKseaET.js +1 -0
- package/dist/assets/treemap-W4RFUUIX-DH-7GZe_.js +1 -0
- package/dist/assets/vennDiagram-DHZGUBPP-DJaC6xmI.js +34 -0
- package/dist/assets/wardley-RL74JXVD-AgyXyBN5.js +1 -0
- package/dist/assets/wardleyDiagram-NUSXRM2D-CTKERPKv.js +20 -0
- package/dist/assets/xychartDiagram-5P7HB3ND-BuExiLXc.js +7 -0
- package/{index.html → dist/index.html} +2 -1
- package/dist/index.js +2539 -0
- package/package.json +11 -1
- package/.agents/skills/remotion-best-practices/SKILL.md +0 -61
- package/.agents/skills/remotion-best-practices/rules/3d.md +0 -86
- package/.agents/skills/remotion-best-practices/rules/animations.md +0 -27
- package/.agents/skills/remotion-best-practices/rules/assets/charts-bar-chart.tsx +0 -178
- package/.agents/skills/remotion-best-practices/rules/assets/text-animations-typewriter.tsx +0 -100
- package/.agents/skills/remotion-best-practices/rules/assets/text-animations-word-highlight.tsx +0 -108
- package/.agents/skills/remotion-best-practices/rules/assets.md +0 -78
- package/.agents/skills/remotion-best-practices/rules/audio-visualization.md +0 -198
- package/.agents/skills/remotion-best-practices/rules/audio.md +0 -169
- package/.agents/skills/remotion-best-practices/rules/calculate-metadata.md +0 -134
- package/.agents/skills/remotion-best-practices/rules/can-decode.md +0 -75
- package/.agents/skills/remotion-best-practices/rules/charts.md +0 -120
- package/.agents/skills/remotion-best-practices/rules/compositions.md +0 -154
- package/.agents/skills/remotion-best-practices/rules/display-captions.md +0 -184
- package/.agents/skills/remotion-best-practices/rules/extract-frames.md +0 -229
- package/.agents/skills/remotion-best-practices/rules/ffmpeg.md +0 -38
- package/.agents/skills/remotion-best-practices/rules/fonts.md +0 -152
- package/.agents/skills/remotion-best-practices/rules/get-audio-duration.md +0 -58
- package/.agents/skills/remotion-best-practices/rules/get-video-dimensions.md +0 -68
- package/.agents/skills/remotion-best-practices/rules/get-video-duration.md +0 -60
- package/.agents/skills/remotion-best-practices/rules/gifs.md +0 -141
- package/.agents/skills/remotion-best-practices/rules/images.md +0 -134
- package/.agents/skills/remotion-best-practices/rules/import-srt-captions.md +0 -69
- package/.agents/skills/remotion-best-practices/rules/light-leaks.md +0 -73
- package/.agents/skills/remotion-best-practices/rules/lottie.md +0 -70
- package/.agents/skills/remotion-best-practices/rules/maps.md +0 -412
- package/.agents/skills/remotion-best-practices/rules/measuring-dom-nodes.md +0 -34
- package/.agents/skills/remotion-best-practices/rules/measuring-text.md +0 -140
- package/.agents/skills/remotion-best-practices/rules/parameters.md +0 -109
- package/.agents/skills/remotion-best-practices/rules/sequencing.md +0 -118
- package/.agents/skills/remotion-best-practices/rules/sfx.md +0 -26
- package/.agents/skills/remotion-best-practices/rules/subtitles.md +0 -36
- package/.agents/skills/remotion-best-practices/rules/tailwind.md +0 -11
- package/.agents/skills/remotion-best-practices/rules/text-animations.md +0 -20
- package/.agents/skills/remotion-best-practices/rules/timing.md +0 -179
- package/.agents/skills/remotion-best-practices/rules/transcribe-captions.md +0 -70
- package/.agents/skills/remotion-best-practices/rules/transitions.md +0 -197
- package/.agents/skills/remotion-best-practices/rules/transparent-videos.md +0 -106
- package/.agents/skills/remotion-best-practices/rules/trimming.md +0 -51
- package/.agents/skills/remotion-best-practices/rules/videos.md +0 -171
- package/.agents/skills/remotion-best-practices/rules/voiceover.md +0 -99
- package/.agents/skills/simple/SKILL.md +0 -52
- package/.agents/skills/vercel-react-best-practices/AGENTS.md +0 -3254
- package/.agents/skills/vercel-react-best-practices/README.md +0 -123
- package/.agents/skills/vercel-react-best-practices/SKILL.md +0 -141
- package/.agents/skills/vercel-react-best-practices/rules/advanced-event-handler-refs.md +0 -55
- package/.agents/skills/vercel-react-best-practices/rules/advanced-init-once.md +0 -42
- package/.agents/skills/vercel-react-best-practices/rules/advanced-use-latest.md +0 -39
- package/.agents/skills/vercel-react-best-practices/rules/async-api-routes.md +0 -38
- package/.agents/skills/vercel-react-best-practices/rules/async-defer-await.md +0 -80
- package/.agents/skills/vercel-react-best-practices/rules/async-dependencies.md +0 -51
- package/.agents/skills/vercel-react-best-practices/rules/async-parallel.md +0 -28
- package/.agents/skills/vercel-react-best-practices/rules/async-suspense-boundaries.md +0 -99
- package/.agents/skills/vercel-react-best-practices/rules/bundle-barrel-imports.md +0 -59
- package/.agents/skills/vercel-react-best-practices/rules/bundle-conditional.md +0 -31
- package/.agents/skills/vercel-react-best-practices/rules/bundle-defer-third-party.md +0 -49
- package/.agents/skills/vercel-react-best-practices/rules/bundle-dynamic-imports.md +0 -35
- package/.agents/skills/vercel-react-best-practices/rules/bundle-preload.md +0 -50
- package/.agents/skills/vercel-react-best-practices/rules/client-event-listeners.md +0 -74
- package/.agents/skills/vercel-react-best-practices/rules/client-localstorage-schema.md +0 -71
- package/.agents/skills/vercel-react-best-practices/rules/client-passive-event-listeners.md +0 -48
- package/.agents/skills/vercel-react-best-practices/rules/client-swr-dedup.md +0 -56
- package/.agents/skills/vercel-react-best-practices/rules/js-batch-dom-css.md +0 -107
- package/.agents/skills/vercel-react-best-practices/rules/js-cache-function-results.md +0 -80
- package/.agents/skills/vercel-react-best-practices/rules/js-cache-property-access.md +0 -28
- package/.agents/skills/vercel-react-best-practices/rules/js-cache-storage.md +0 -70
- package/.agents/skills/vercel-react-best-practices/rules/js-combine-iterations.md +0 -32
- package/.agents/skills/vercel-react-best-practices/rules/js-early-exit.md +0 -50
- package/.agents/skills/vercel-react-best-practices/rules/js-flatmap-filter.md +0 -60
- package/.agents/skills/vercel-react-best-practices/rules/js-hoist-regexp.md +0 -45
- package/.agents/skills/vercel-react-best-practices/rules/js-index-maps.md +0 -37
- package/.agents/skills/vercel-react-best-practices/rules/js-length-check-first.md +0 -49
- package/.agents/skills/vercel-react-best-practices/rules/js-min-max-loop.md +0 -82
- package/.agents/skills/vercel-react-best-practices/rules/js-set-map-lookups.md +0 -24
- package/.agents/skills/vercel-react-best-practices/rules/js-tosorted-immutable.md +0 -57
- package/.agents/skills/vercel-react-best-practices/rules/rendering-activity.md +0 -26
- package/.agents/skills/vercel-react-best-practices/rules/rendering-animate-svg-wrapper.md +0 -47
- package/.agents/skills/vercel-react-best-practices/rules/rendering-conditional-render.md +0 -40
- package/.agents/skills/vercel-react-best-practices/rules/rendering-content-visibility.md +0 -38
- package/.agents/skills/vercel-react-best-practices/rules/rendering-hoist-jsx.md +0 -46
- package/.agents/skills/vercel-react-best-practices/rules/rendering-hydration-no-flicker.md +0 -82
- package/.agents/skills/vercel-react-best-practices/rules/rendering-hydration-suppress-warning.md +0 -30
- package/.agents/skills/vercel-react-best-practices/rules/rendering-resource-hints.md +0 -85
- package/.agents/skills/vercel-react-best-practices/rules/rendering-script-defer-async.md +0 -68
- package/.agents/skills/vercel-react-best-practices/rules/rendering-svg-precision.md +0 -28
- package/.agents/skills/vercel-react-best-practices/rules/rendering-usetransition-loading.md +0 -75
- package/.agents/skills/vercel-react-best-practices/rules/rerender-defer-reads.md +0 -39
- package/.agents/skills/vercel-react-best-practices/rules/rerender-dependencies.md +0 -45
- package/.agents/skills/vercel-react-best-practices/rules/rerender-derived-state-no-effect.md +0 -40
- package/.agents/skills/vercel-react-best-practices/rules/rerender-derived-state.md +0 -29
- package/.agents/skills/vercel-react-best-practices/rules/rerender-functional-setstate.md +0 -74
- package/.agents/skills/vercel-react-best-practices/rules/rerender-lazy-state-init.md +0 -58
- package/.agents/skills/vercel-react-best-practices/rules/rerender-memo-with-default-value.md +0 -38
- package/.agents/skills/vercel-react-best-practices/rules/rerender-memo.md +0 -44
- package/.agents/skills/vercel-react-best-practices/rules/rerender-move-effect-to-event.md +0 -45
- package/.agents/skills/vercel-react-best-practices/rules/rerender-no-inline-components.md +0 -82
- package/.agents/skills/vercel-react-best-practices/rules/rerender-simple-expression-in-memo.md +0 -35
- package/.agents/skills/vercel-react-best-practices/rules/rerender-transitions.md +0 -40
- package/.agents/skills/vercel-react-best-practices/rules/rerender-use-ref-transient-values.md +0 -73
- package/.agents/skills/vercel-react-best-practices/rules/server-after-nonblocking.md +0 -73
- package/.agents/skills/vercel-react-best-practices/rules/server-auth-actions.md +0 -96
- package/.agents/skills/vercel-react-best-practices/rules/server-cache-lru.md +0 -41
- package/.agents/skills/vercel-react-best-practices/rules/server-cache-react.md +0 -76
- package/.agents/skills/vercel-react-best-practices/rules/server-dedup-props.md +0 -65
- package/.agents/skills/vercel-react-best-practices/rules/server-hoist-static-io.md +0 -142
- package/.agents/skills/vercel-react-best-practices/rules/server-parallel-fetching.md +0 -83
- package/.agents/skills/vercel-react-best-practices/rules/server-serialization.md +0 -38
- package/.claude/CLAUDE.md +0 -184
- package/.claude/commands/review.md +0 -120
- package/.claude/commands/sync-docs.md +0 -71
- package/.claude/roadmap.md +0 -121
- package/.claude/rules/style-guide.md +0 -830
- package/.claude/settings.json +0 -18
- package/.claude/user-stories.md +0 -333
- package/AGENTS.md +0 -68
- package/Makefile +0 -32
- package/biome.json +0 -79
- package/bun.lock +0 -854
- package/bunfig.toml +0 -2
- package/docs/design.md +0 -563
- package/docs/perf-baseline.md +0 -130
- package/docs/plans/2026-03-13-client-mode-design.md +0 -86
- package/docs/plans/2026-03-13-client-mode-plan.md +0 -605
- package/docs/plans/2026-03-13-keyboard-shortcuts-design.md +0 -129
- package/docs/plans/2026-03-13-keyboard-shortcuts-plan.md +0 -1471
- package/docs/plans/2026-03-13-multi-document-design.md +0 -183
- package/docs/plans/2026-03-13-performance-benchmarks-design.md +0 -121
- package/docs/superpowers/plans/2026-03-26-surgical-pruning.md +0 -1176
- package/docs/superpowers/specs/2026-03-27-go-server-rewrite-design.md +0 -284
- package/e2e/comments.spec.ts +0 -81
- package/e2e/document-load.spec.ts +0 -32
- package/e2e/export.spec.ts +0 -58
- package/e2e/fixtures/sample.md +0 -7
- package/e2e/perf/add-comment.spec.ts +0 -116
- package/e2e/perf/fixtures/generate.ts +0 -327
- package/e2e/perf/initial-load.spec.ts +0 -49
- package/e2e/perf/perf.setup.ts +0 -23
- package/e2e/perf/perf.teardown.ts +0 -9
- package/e2e/perf/screenshot-final.png +0 -0
- package/e2e/perf/scroll.spec.ts +0 -39
- package/e2e/perf/tab-switch.spec.ts +0 -69
- package/e2e/perf/text-selection.spec.ts +0 -119
- package/e2e/perf/utils/metrics.ts +0 -350
- package/e2e/perf/utils/perf-cli.ts +0 -86
- package/e2e/persistence-file.spec.ts +0 -357
- package/e2e/utils/cli.ts +0 -84
- package/e2e/utils/selection.ts +0 -79
- package/go/cmd/readit/main.go +0 -416
- package/go/go.mod +0 -20
- package/go/go.sum +0 -41
- package/go/internal/server/anchor.go +0 -302
- package/go/internal/server/anchor_test.go +0 -111
- package/go/internal/server/comments.go +0 -390
- package/go/internal/server/documents.go +0 -113
- package/go/internal/server/embed.go +0 -17
- package/go/internal/server/headings.go +0 -33
- package/go/internal/server/headings_test.go +0 -75
- package/go/internal/server/htmltext.go +0 -123
- package/go/internal/server/markdown.go +0 -157
- package/go/internal/server/markdown_bench_test.go +0 -42
- package/go/internal/server/markdown_test.go +0 -79
- package/go/internal/server/server.go +0 -453
- package/go/internal/server/server_bench_test.go +0 -122
- package/go/internal/server/settings.go +0 -110
- package/go/internal/server/sse.go +0 -140
- package/go/internal/server/storage.go +0 -275
- package/go/internal/server/storage_test.go +0 -118
- package/go/internal/server/template.go +0 -66
- package/go/internal/server/types.go +0 -101
- package/go/internal/server/watcher.go +0 -74
- package/lefthook.yml +0 -8
- package/nvim-readit/lua/readit/health.lua +0 -64
- package/nvim-readit/lua/readit/init.lua +0 -463
- package/nvim-readit/plugin/readit.lua +0 -19
- package/playwright.config.ts +0 -34
- package/skills-lock.json +0 -20
- package/src/App.svelte +0 -881
- package/src/cli.ts +0 -881
- package/src/components/ActionsMenu.svelte +0 -95
- package/src/components/CommentBadge.svelte +0 -67
- package/src/components/CommentErrorBanner.svelte +0 -33
- package/src/components/CommentInput.svelte +0 -75
- package/src/components/CommentListItem.svelte +0 -95
- package/src/components/CommentManager.svelte +0 -129
- package/src/components/CommentNav.svelte +0 -109
- package/src/components/DocumentViewer.svelte +0 -218
- package/src/components/FloatingComment.svelte +0 -107
- package/src/components/Header.svelte +0 -76
- package/src/components/InlineEditor.svelte +0 -72
- package/src/components/MarginNote.svelte +0 -167
- package/src/components/MarginNotesContainer.svelte +0 -33
- package/src/components/RawModal.svelte +0 -126
- package/src/components/ReanchorConfirm.svelte +0 -30
- package/src/components/SettingsModal.svelte +0 -220
- package/src/components/ShortcutCapture.svelte +0 -82
- package/src/components/ShortcutList.svelte +0 -145
- package/src/components/TabBar.svelte +0 -52
- package/src/components/TableOfContents.svelte +0 -125
- package/src/components/ui/ActionLink.svelte +0 -40
- package/src/components/ui/Button.svelte +0 -53
- package/src/components/ui/Dialog.svelte +0 -97
- package/src/components/ui/DropdownMenu.svelte +0 -85
- package/src/components/ui/DropdownMenuItem.svelte +0 -38
- package/src/components/ui/DropdownMenuSeparator.svelte +0 -11
- package/src/components/ui/Text.svelte +0 -42
- package/src/env.d.ts +0 -6
- package/src/index.css +0 -754
- package/src/lib/__fixtures__/bench-data.ts +0 -114
- package/src/lib/anchor.bench.ts +0 -91
- package/src/lib/anchor.test.ts +0 -527
- package/src/lib/anchor.ts +0 -381
- package/src/lib/comment-storage.bench.ts +0 -49
- package/src/lib/comment-storage.test.ts +0 -632
- package/src/lib/comment-storage.ts +0 -222
- package/src/lib/export.bench.ts +0 -21
- package/src/lib/export.ts +0 -36
- package/src/lib/headings.test.ts +0 -103
- package/src/lib/headings.ts +0 -44
- package/src/lib/highlight/core.test.ts +0 -93
- package/src/lib/highlight/dom.ts +0 -187
- package/src/lib/highlight/highlight-registry.ts +0 -221
- package/src/lib/highlight/highlight.bench.ts +0 -92
- package/src/lib/highlight/highlighter.ts +0 -247
- package/src/lib/highlight/resolver.ts +0 -38
- package/src/lib/highlight/types.ts +0 -17
- package/src/lib/html-text.test.ts +0 -162
- package/src/lib/html-text.ts +0 -161
- package/src/lib/i18n/en.ts +0 -116
- package/src/lib/i18n/index.ts +0 -3
- package/src/lib/i18n/ja.ts +0 -118
- package/src/lib/i18n/translations.ts +0 -27
- package/src/lib/i18n/types.ts +0 -122
- package/src/lib/margin-layout.bench.ts +0 -61
- package/src/lib/margin-layout.ts +0 -71
- package/src/lib/markdown-renderer.test.ts +0 -154
- package/src/lib/markdown-renderer.ts +0 -177
- package/src/lib/mermaid-config.ts +0 -38
- package/src/lib/mermaid-renderer.ts +0 -162
- package/src/lib/mermaid-worker.ts +0 -60
- package/src/lib/positions.ts +0 -157
- package/src/lib/shortcut-registry.ts +0 -244
- package/src/lib/utils.ts +0 -15
- package/src/main.ts +0 -16
- package/src/schema.ts +0 -92
- package/src/server.ts +0 -1220
- package/src/stores/app.svelte.ts +0 -231
- package/src/stores/locale.svelte.ts +0 -46
- package/src/stores/settings.svelte.ts +0 -90
- package/src/stores/shortcuts.svelte.ts +0 -104
- package/src/stores/ui.svelte.ts +0 -12
- package/src/template.ts +0 -104
- package/src/test-setup.ts +0 -48
- package/svelte.config.js +0 -5
- package/test.md +0 -74
- package/tsconfig.cli.json +0 -12
- package/tsconfig.json +0 -20
- package/vite.config.ts +0 -47
- package/vitest.config.ts +0 -15
- package/vscode-readit/.mcp.json +0 -7
- package/vscode-readit/.vscodeignore +0 -7
- package/vscode-readit/bun.lock +0 -78
- package/vscode-readit/icon.svg +0 -10
- package/vscode-readit/package.json +0 -110
- package/vscode-readit/src/extension.ts +0 -117
- package/vscode-readit/src/server-manager.ts +0 -272
- package/vscode-readit/src/webview-provider.ts +0 -204
- package/vscode-readit/tsconfig.json +0 -20
|
@@ -1,1176 +0,0 @@
|
|
|
1
|
-
# Surgical Pruning Implementation Plan
|
|
2
|
-
|
|
3
|
-
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
|
4
|
-
|
|
5
|
-
**Goal:** Aggressively prune readit's frontend to remove ~4,000+ lines of unnecessary code, flatten state management layers, and eliminate heavy unused features — making the tool feel absurdly fast.
|
|
6
|
-
|
|
7
|
-
**Architecture:** Delete-first approach. Remove entire feature systems (minimap, layout modes, keyboard shortcut customization, editor scheme), flatten the triple-layered state management (Zustand store + 4 Contexts + 18 hooks) into a simpler structure, and cut heavyweight dependencies. The server and core libs (anchor, comment-storage, export) remain untouched — they're solid.
|
|
8
|
-
|
|
9
|
-
**Tech Stack:** React 19, TypeScript, Vite, Tailwind CSS v4, Zustand, Bun
|
|
10
|
-
|
|
11
|
-
---
|
|
12
|
-
|
|
13
|
-
## File Map
|
|
14
|
-
|
|
15
|
-
### Files to DELETE entirely
|
|
16
|
-
|
|
17
|
-
| File | Lines | Reason |
|
|
18
|
-
|------|-------|--------|
|
|
19
|
-
| `src/hooks/useLayoutMode.ts` | 44 | Fullscreen/centered toggle — removing layout modes |
|
|
20
|
-
| `src/hooks/useKeybindings.ts` | 108 | Shortcut customization system |
|
|
21
|
-
| `src/hooks/useKeyboardShortcuts.ts` | 63 | Shortcut listener |
|
|
22
|
-
| `src/hooks/useEditorScheme.ts` | 51 | "Open in VSCode" feature |
|
|
23
|
-
| `src/hooks/useScrollMetrics.ts` | 50 | Only used by minimap |
|
|
24
|
-
| `src/components/FloatingTOC.tsx` | 61 | Only used in fullscreen mode |
|
|
25
|
-
| `src/components/ShortcutCapture.tsx` | ~100 | Shortcut rebinding UI |
|
|
26
|
-
| `src/components/ShortcutList.tsx` | ~100 | Shortcut list UI |
|
|
27
|
-
| `src/components/comments/CommentMinimap.tsx` | 71 | Minimap |
|
|
28
|
-
| `src/contexts/LayoutContext.tsx` | 89 | Replaced by simpler SettingsContext |
|
|
29
|
-
| `src/lib/shortcut-registry.ts` | 210 | Entire shortcut system |
|
|
30
|
-
| `src/lib/shortcut-registry.test.ts` | ~100 | Tests for deleted code |
|
|
31
|
-
| `src/lib/editor-links.ts` | 60 | Editor URI builder |
|
|
32
|
-
|
|
33
|
-
**Estimated deletion: ~1,100+ lines from files alone**
|
|
34
|
-
|
|
35
|
-
### Files to MODIFY (simplify)
|
|
36
|
-
|
|
37
|
-
| File | Change |
|
|
38
|
-
|------|--------|
|
|
39
|
-
| `src/types/index.ts` | Remove `LayoutMode`, `ShortcutBinding`, `KeybindingOverride`, `EditorScheme` types |
|
|
40
|
-
| `src/App.tsx` | Remove minimap, FloatingTOC, isFullscreen branching, keyboard shortcuts |
|
|
41
|
-
| `src/components/ActionsMenu.tsx` | Remove fullscreen toggle, remove editor scheme, simplify |
|
|
42
|
-
| `src/components/Header.tsx` | Remove isFullscreen conditional styling |
|
|
43
|
-
| `src/components/SettingsModal.tsx` | Remove shortcut list, remove editor scheme dropdown |
|
|
44
|
-
| `src/components/comments/CommentInput.tsx` | Remove LayoutContext import, get font simpler way |
|
|
45
|
-
| `src/components/DocumentViewer/DocumentViewer.tsx` | Remove editor scheme references |
|
|
46
|
-
| `src/server/index.ts` | Remove keybindings/editorScheme from settings handling |
|
|
47
|
-
| `src/store/index.ts` | Minor cleanup if any store fields become orphaned |
|
|
48
|
-
|
|
49
|
-
### Files to CREATE
|
|
50
|
-
|
|
51
|
-
| File | Purpose |
|
|
52
|
-
|------|---------|
|
|
53
|
-
| `src/contexts/SettingsContext.tsx` | Lightweight replacement for LayoutContext — only font + theme |
|
|
54
|
-
|
|
55
|
-
---
|
|
56
|
-
|
|
57
|
-
## Prerequisites
|
|
58
|
-
|
|
59
|
-
**IMPORTANT:** The working tree has unstaged modifications. Before starting, create a new branch from current state:
|
|
60
|
-
|
|
61
|
-
```bash
|
|
62
|
-
git checkout -b refactor/surgical-pruning
|
|
63
|
-
git add -A && git commit -m "checkpoint: save WIP before pruning"
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
---
|
|
67
|
-
|
|
68
|
-
### Task 1: Delete standalone feature files
|
|
69
|
-
|
|
70
|
-
These files have no downstream dependents other than the files we'll modify in later tasks. Safe to delete first.
|
|
71
|
-
|
|
72
|
-
**Files:**
|
|
73
|
-
- Delete: `src/hooks/useLayoutMode.ts`
|
|
74
|
-
- Delete: `src/hooks/useKeybindings.ts`
|
|
75
|
-
- Delete: `src/hooks/useKeyboardShortcuts.ts`
|
|
76
|
-
- Delete: `src/hooks/useEditorScheme.ts`
|
|
77
|
-
- Delete: `src/hooks/useScrollMetrics.ts`
|
|
78
|
-
- Delete: `src/components/FloatingTOC.tsx`
|
|
79
|
-
- Delete: `src/components/ShortcutCapture.tsx`
|
|
80
|
-
- Delete: `src/components/ShortcutList.tsx`
|
|
81
|
-
- Delete: `src/components/comments/CommentMinimap.tsx`
|
|
82
|
-
- Delete: `src/lib/shortcut-registry.ts`
|
|
83
|
-
- Delete: `src/lib/shortcut-registry.test.ts`
|
|
84
|
-
- Delete: `src/lib/editor-links.ts`
|
|
85
|
-
|
|
86
|
-
- [ ] **Step 1: Delete all standalone files**
|
|
87
|
-
|
|
88
|
-
```bash
|
|
89
|
-
rm src/hooks/useLayoutMode.ts \
|
|
90
|
-
src/hooks/useKeybindings.ts \
|
|
91
|
-
src/hooks/useKeyboardShortcuts.ts \
|
|
92
|
-
src/hooks/useEditorScheme.ts \
|
|
93
|
-
src/hooks/useScrollMetrics.ts \
|
|
94
|
-
src/components/FloatingTOC.tsx \
|
|
95
|
-
src/components/ShortcutCapture.tsx \
|
|
96
|
-
src/components/ShortcutList.tsx \
|
|
97
|
-
src/components/comments/CommentMinimap.tsx \
|
|
98
|
-
src/lib/shortcut-registry.ts \
|
|
99
|
-
src/lib/shortcut-registry.test.ts \
|
|
100
|
-
src/lib/editor-links.ts
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
- [ ] **Step 2: Verify deletion didn't break anything unexpected**
|
|
104
|
-
|
|
105
|
-
```bash
|
|
106
|
-
# This WILL fail with import errors — that's expected. We just want to see which files reference deleted code.
|
|
107
|
-
bun run typecheck 2>&1 | grep "Cannot find module" | sort -u
|
|
108
|
-
```
|
|
109
|
-
|
|
110
|
-
Expected: errors from `App.tsx`, `LayoutContext.tsx`, `SettingsModal.tsx`, `ActionsMenu.tsx`, `CommentInput.tsx`, `DocumentViewer.tsx` referencing deleted modules. These are fixed in subsequent tasks.
|
|
111
|
-
|
|
112
|
-
- [ ] **Step 3: Commit deletions**
|
|
113
|
-
|
|
114
|
-
```bash
|
|
115
|
-
git add -A
|
|
116
|
-
git commit -m "chore: delete minimap, layout modes, shortcuts, editor scheme files"
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
---
|
|
120
|
-
|
|
121
|
-
### Task 2: Strip types and delete LayoutContext
|
|
122
|
-
|
|
123
|
-
**Files:**
|
|
124
|
-
- Modify: `src/types/index.ts`
|
|
125
|
-
- Delete: `src/contexts/LayoutContext.tsx`
|
|
126
|
-
|
|
127
|
-
- [ ] **Step 1: Simplify types/index.ts**
|
|
128
|
-
|
|
129
|
-
Remove these blocks from `src/types/index.ts`:
|
|
130
|
-
|
|
131
|
-
- `EditorSchemes` const + `EditorScheme` type (lines 71-78)
|
|
132
|
-
- `LayoutModes` const + `LayoutMode` type (lines 97-103)
|
|
133
|
-
- `ShortcutBinding` interface (lines 106-111)
|
|
134
|
-
- `KeybindingOverride` interface (lines 114-118)
|
|
135
|
-
- Remove `editorScheme` and `keybindings` fields from `DocumentSettings` interface (lines 124-125)
|
|
136
|
-
|
|
137
|
-
The resulting `DocumentSettings` should be:
|
|
138
|
-
|
|
139
|
-
```typescript
|
|
140
|
-
export interface DocumentSettings {
|
|
141
|
-
version: number;
|
|
142
|
-
fontFamily: FontFamily;
|
|
143
|
-
onboarded?: boolean;
|
|
144
|
-
}
|
|
145
|
-
```
|
|
146
|
-
|
|
147
|
-
- [ ] **Step 2: Delete LayoutContext**
|
|
148
|
-
|
|
149
|
-
```bash
|
|
150
|
-
rm src/contexts/LayoutContext.tsx
|
|
151
|
-
```
|
|
152
|
-
|
|
153
|
-
- [ ] **Step 3: Commit**
|
|
154
|
-
|
|
155
|
-
```bash
|
|
156
|
-
git add -A
|
|
157
|
-
git commit -m "chore: remove LayoutMode, EditorScheme, ShortcutBinding types and LayoutContext"
|
|
158
|
-
```
|
|
159
|
-
|
|
160
|
-
---
|
|
161
|
-
|
|
162
|
-
### Task 3: Create lightweight SettingsContext
|
|
163
|
-
|
|
164
|
-
Replaces LayoutContext with only what's needed: font preference + theme preference.
|
|
165
|
-
|
|
166
|
-
**Files:**
|
|
167
|
-
- Create: `src/contexts/SettingsContext.tsx`
|
|
168
|
-
|
|
169
|
-
- [ ] **Step 1: Create SettingsContext**
|
|
170
|
-
|
|
171
|
-
```tsx
|
|
172
|
-
// src/contexts/SettingsContext.tsx
|
|
173
|
-
import { createContext, type ReactNode, use, useMemo } from "react";
|
|
174
|
-
import { useFontPreference } from "../hooks/useFontPreference";
|
|
175
|
-
import { useThemePreference } from "../hooks/useThemePreference";
|
|
176
|
-
import type { FontFamily, ThemeMode } from "../types";
|
|
177
|
-
|
|
178
|
-
interface SettingsContextValue {
|
|
179
|
-
fontFamily: FontFamily;
|
|
180
|
-
setFontFamily: (font: FontFamily) => Promise<void>;
|
|
181
|
-
themeMode: ThemeMode;
|
|
182
|
-
setThemeMode: (mode: ThemeMode) => void;
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
export const SettingsContext = createContext<SettingsContextValue | null>(null);
|
|
186
|
-
|
|
187
|
-
export function useSettings(): SettingsContextValue {
|
|
188
|
-
const value = use(SettingsContext);
|
|
189
|
-
if (!value) {
|
|
190
|
-
throw new Error("useSettings must be used within a SettingsProvider");
|
|
191
|
-
}
|
|
192
|
-
return value;
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
export function SettingsProvider({ children }: { children: ReactNode }) {
|
|
196
|
-
const { fontFamily, setFontFamily } = useFontPreference();
|
|
197
|
-
const { themeMode, setThemeMode } = useThemePreference();
|
|
198
|
-
|
|
199
|
-
const value = useMemo<SettingsContextValue>(
|
|
200
|
-
() => ({ fontFamily, setFontFamily, themeMode, setThemeMode }),
|
|
201
|
-
[fontFamily, setFontFamily, themeMode, setThemeMode],
|
|
202
|
-
);
|
|
203
|
-
|
|
204
|
-
return <SettingsContext value={value}>{children}</SettingsContext>;
|
|
205
|
-
}
|
|
206
|
-
```
|
|
207
|
-
|
|
208
|
-
- [ ] **Step 2: Commit**
|
|
209
|
-
|
|
210
|
-
```bash
|
|
211
|
-
git add src/contexts/SettingsContext.tsx
|
|
212
|
-
git commit -m "feat: add lightweight SettingsContext replacing LayoutContext"
|
|
213
|
-
```
|
|
214
|
-
|
|
215
|
-
---
|
|
216
|
-
|
|
217
|
-
### Task 4: Rewire App.tsx
|
|
218
|
-
|
|
219
|
-
The biggest consumer of deleted features. Remove minimap, FloatingTOC, keyboard shortcuts, isFullscreen branching.
|
|
220
|
-
|
|
221
|
-
**Files:**
|
|
222
|
-
- Modify: `src/App.tsx`
|
|
223
|
-
|
|
224
|
-
- [ ] **Step 1: Update imports**
|
|
225
|
-
|
|
226
|
-
Remove these imports:
|
|
227
|
-
- `CommentMinimap`
|
|
228
|
-
- `FloatingTOC`
|
|
229
|
-
- `useKeyboardShortcuts`
|
|
230
|
-
- `useScrollMetrics`
|
|
231
|
-
- `ShortcutActions`
|
|
232
|
-
- `LayoutContext`, `LayoutProvider` from contexts
|
|
233
|
-
|
|
234
|
-
Add:
|
|
235
|
-
- `SettingsProvider` from `./contexts/SettingsContext`
|
|
236
|
-
|
|
237
|
-
- [ ] **Step 2: Simplify AppContent**
|
|
238
|
-
|
|
239
|
-
Remove from `AppContent`:
|
|
240
|
-
- `const { shortcuts, isFullscreen } = use(LayoutContext)!;` — delete entirely
|
|
241
|
-
- `useKeyboardShortcuts(...)` call — delete entirely
|
|
242
|
-
- `const scrollMetrics = useScrollMetrics();` — delete entirely
|
|
243
|
-
- The `{isFullscreen && <FloatingTOC ... />}` block — delete
|
|
244
|
-
- The `<CommentMinimap ... />` component — delete
|
|
245
|
-
- The `!isFullscreen` conditional on `max-w-7xl mx-auto` — always apply max-width (centered layout)
|
|
246
|
-
- The `!isFullscreen &&` guard on the TOC sidebar — always show TOC sidebar
|
|
247
|
-
|
|
248
|
-
The main layout div should become:
|
|
249
|
-
|
|
250
|
-
```tsx
|
|
251
|
-
<div className="flex-1 flex gap-4 w-full max-w-7xl mx-auto">
|
|
252
|
-
{headings.length > 0 && (
|
|
253
|
-
<aside className="w-48 flex-shrink-0 py-6 pl-6 hidden xl:block">
|
|
254
|
-
<div className="sticky top-64 max-h-[calc(100vh-17rem)] overflow-y-auto">
|
|
255
|
-
<TableOfContents
|
|
256
|
-
headings={headings}
|
|
257
|
-
activeId={activeHeadingId}
|
|
258
|
-
onHeadingClick={scrollToHeading}
|
|
259
|
-
/>
|
|
260
|
-
</div>
|
|
261
|
-
</aside>
|
|
262
|
-
)}
|
|
263
|
-
{/* ... document + margin notes unchanged ... */}
|
|
264
|
-
</div>
|
|
265
|
-
```
|
|
266
|
-
|
|
267
|
-
- [ ] **Step 3: Replace LayoutProvider with SettingsProvider in App**
|
|
268
|
-
|
|
269
|
-
In the `App` component's return, change:
|
|
270
|
-
|
|
271
|
-
```tsx
|
|
272
|
-
// Before
|
|
273
|
-
<LayoutProvider>
|
|
274
|
-
<PositionEngineProvider>
|
|
275
|
-
<CommentProvider ...>
|
|
276
|
-
<AppContent ... />
|
|
277
|
-
</CommentProvider>
|
|
278
|
-
</PositionEngineProvider>
|
|
279
|
-
</LayoutProvider>
|
|
280
|
-
|
|
281
|
-
// After
|
|
282
|
-
<SettingsProvider>
|
|
283
|
-
<PositionEngineProvider>
|
|
284
|
-
<CommentProvider ...>
|
|
285
|
-
<AppContent ... />
|
|
286
|
-
</CommentProvider>
|
|
287
|
-
</PositionEngineProvider>
|
|
288
|
-
</SettingsProvider>
|
|
289
|
-
```
|
|
290
|
-
|
|
291
|
-
- [ ] **Step 4: Verify typecheck compiles (may still have errors in other files)**
|
|
292
|
-
|
|
293
|
-
```bash
|
|
294
|
-
bun run typecheck 2>&1 | head -30
|
|
295
|
-
```
|
|
296
|
-
|
|
297
|
-
- [ ] **Step 5: Commit**
|
|
298
|
-
|
|
299
|
-
```bash
|
|
300
|
-
git add src/App.tsx
|
|
301
|
-
git commit -m "refactor: remove minimap, FloatingTOC, shortcuts from App"
|
|
302
|
-
```
|
|
303
|
-
|
|
304
|
-
---
|
|
305
|
-
|
|
306
|
-
### Task 5: Simplify ActionsMenu
|
|
307
|
-
|
|
308
|
-
Remove fullscreen toggle and editor scheme. Keep: reload, copy all, copy raw, export JSON, view raw, settings.
|
|
309
|
-
|
|
310
|
-
**Files:**
|
|
311
|
-
- Modify: `src/components/ActionsMenu.tsx`
|
|
312
|
-
|
|
313
|
-
- [ ] **Step 1: Update ActionsMenu**
|
|
314
|
-
|
|
315
|
-
Remove:
|
|
316
|
-
- `useLayoutContext` import → replace with `useSettings` from `../contexts/SettingsContext` (only if needed — check if anything from it is still used)
|
|
317
|
-
- `Maximize2`, `Minimize2` icon imports
|
|
318
|
-
- `const { isFullscreen, toggleLayoutMode } = useLayoutContext();` line
|
|
319
|
-
- The fullscreen toggle `<DropdownMenuItem>` (the one with Maximize2/Minimize2)
|
|
320
|
-
|
|
321
|
-
If ActionsMenu no longer needs `useSettings` at all (it likely doesn't — settings modal handles its own context), remove the context import entirely.
|
|
322
|
-
|
|
323
|
-
- [ ] **Step 2: Commit**
|
|
324
|
-
|
|
325
|
-
```bash
|
|
326
|
-
git add src/components/ActionsMenu.tsx
|
|
327
|
-
git commit -m "refactor: remove fullscreen toggle from ActionsMenu"
|
|
328
|
-
```
|
|
329
|
-
|
|
330
|
-
---
|
|
331
|
-
|
|
332
|
-
### Task 6: Simplify Header
|
|
333
|
-
|
|
334
|
-
**Files:**
|
|
335
|
-
- Modify: `src/components/Header.tsx`
|
|
336
|
-
|
|
337
|
-
- [ ] **Step 1: Update Header**
|
|
338
|
-
|
|
339
|
-
Remove:
|
|
340
|
-
- `useLayoutContext` import
|
|
341
|
-
- `const { isFullscreen } = useLayoutContext();` line
|
|
342
|
-
- The `!isFullscreen &&` conditional on `max-w-7xl mx-auto` — always apply it
|
|
343
|
-
|
|
344
|
-
The header div className becomes:
|
|
345
|
-
|
|
346
|
-
```tsx
|
|
347
|
-
<div className="px-6 py-3 flex items-center justify-between max-w-7xl mx-auto">
|
|
348
|
-
```
|
|
349
|
-
|
|
350
|
-
- [ ] **Step 2: Commit**
|
|
351
|
-
|
|
352
|
-
```bash
|
|
353
|
-
git add src/components/Header.tsx
|
|
354
|
-
git commit -m "refactor: remove fullscreen conditional from Header"
|
|
355
|
-
```
|
|
356
|
-
|
|
357
|
-
---
|
|
358
|
-
|
|
359
|
-
### Task 7: Simplify SettingsModal
|
|
360
|
-
|
|
361
|
-
Remove shortcut list and editor scheme sections. Keep: theme, font, language.
|
|
362
|
-
|
|
363
|
-
**Files:**
|
|
364
|
-
- Modify: `src/components/SettingsModal.tsx`
|
|
365
|
-
|
|
366
|
-
- [ ] **Step 1: Update imports**
|
|
367
|
-
|
|
368
|
-
Remove:
|
|
369
|
-
- `ExternalLink` from lucide-react
|
|
370
|
-
- `useLayoutContext` import → replace with `useSettings` from `../contexts/SettingsContext`
|
|
371
|
-
- `ShortcutList` import
|
|
372
|
-
- `EditorScheme`, `EditorSchemes` from types
|
|
373
|
-
|
|
374
|
-
- [ ] **Step 2: Simplify the component body**
|
|
375
|
-
|
|
376
|
-
Change the destructuring from:
|
|
377
|
-
|
|
378
|
-
```tsx
|
|
379
|
-
const {
|
|
380
|
-
fontFamily, setFontFamily,
|
|
381
|
-
editorScheme, setEditorScheme,
|
|
382
|
-
themeMode, setThemeMode,
|
|
383
|
-
shortcuts, updateBinding, toggleShortcutEnabled, resetShortcutsToDefaults,
|
|
384
|
-
} = useLayoutContext();
|
|
385
|
-
```
|
|
386
|
-
|
|
387
|
-
To:
|
|
388
|
-
|
|
389
|
-
```tsx
|
|
390
|
-
const { fontFamily, setFontFamily, themeMode, setThemeMode } = useSettings();
|
|
391
|
-
```
|
|
392
|
-
|
|
393
|
-
Remove:
|
|
394
|
-
- `editorOptions` array
|
|
395
|
-
- `activeEditor` variable
|
|
396
|
-
- The entire "Editor" `<div>` section (lines ~261-290)
|
|
397
|
-
- The entire "Keyboard Shortcuts" `<div>` section (lines ~292-305)
|
|
398
|
-
|
|
399
|
-
- [ ] **Step 3: Commit**
|
|
400
|
-
|
|
401
|
-
```bash
|
|
402
|
-
git add src/components/SettingsModal.tsx
|
|
403
|
-
git commit -m "refactor: strip editor scheme and shortcuts from SettingsModal"
|
|
404
|
-
```
|
|
405
|
-
|
|
406
|
-
---
|
|
407
|
-
|
|
408
|
-
### Task 8: Simplify CommentInput
|
|
409
|
-
|
|
410
|
-
Remove LayoutContext dependency for font class.
|
|
411
|
-
|
|
412
|
-
**Files:**
|
|
413
|
-
- Modify: `src/components/comments/CommentInput.tsx`
|
|
414
|
-
|
|
415
|
-
- [ ] **Step 1: Update CommentInput**
|
|
416
|
-
|
|
417
|
-
Replace:
|
|
418
|
-
|
|
419
|
-
```tsx
|
|
420
|
-
import { LayoutContext } from "../../contexts/LayoutContext";
|
|
421
|
-
// ...
|
|
422
|
-
const layout = use(LayoutContext);
|
|
423
|
-
const fontClass = layout
|
|
424
|
-
? layout.fontFamily === FontFamilies.SANS_SERIF
|
|
425
|
-
? "font-sans"
|
|
426
|
-
: "font-serif"
|
|
427
|
-
: undefined;
|
|
428
|
-
```
|
|
429
|
-
|
|
430
|
-
With:
|
|
431
|
-
|
|
432
|
-
```tsx
|
|
433
|
-
import { SettingsContext } from "../../contexts/SettingsContext";
|
|
434
|
-
// ...
|
|
435
|
-
const settings = use(SettingsContext);
|
|
436
|
-
const fontClass = settings
|
|
437
|
-
? settings.fontFamily === FontFamilies.SANS_SERIF
|
|
438
|
-
? "font-sans"
|
|
439
|
-
: "font-serif"
|
|
440
|
-
: undefined;
|
|
441
|
-
```
|
|
442
|
-
|
|
443
|
-
- [ ] **Step 2: Commit**
|
|
444
|
-
|
|
445
|
-
```bash
|
|
446
|
-
git add src/components/comments/CommentInput.tsx
|
|
447
|
-
git commit -m "refactor: switch CommentInput from LayoutContext to SettingsContext"
|
|
448
|
-
```
|
|
449
|
-
|
|
450
|
-
---
|
|
451
|
-
|
|
452
|
-
### Task 9: Clean up DocumentViewer editor scheme references
|
|
453
|
-
|
|
454
|
-
**Files:**
|
|
455
|
-
- Modify: `src/components/DocumentViewer/DocumentViewer.tsx`
|
|
456
|
-
- Check: `src/components/DocumentViewer/InlineCode.tsx`
|
|
457
|
-
|
|
458
|
-
- [ ] **Step 1: Find and remove editor scheme usage**
|
|
459
|
-
|
|
460
|
-
These files import `editorScheme` or `editor-links`. Remove:
|
|
461
|
-
- Any import of `useLayoutContext` or `LayoutContext` for `editorScheme`
|
|
462
|
-
- Any import from `../lib/editor-links`
|
|
463
|
-
- Any `buildEditorUri` / `parseFilePath` calls
|
|
464
|
-
- Replace editor-linked code elements with plain `<code>` elements (no click-to-open behavior)
|
|
465
|
-
|
|
466
|
-
If `DocumentViewer.tsx` uses `useLayoutContext` only for `editorScheme`, remove the import entirely. If it also uses `fontFamily`, switch to `useSettings`.
|
|
467
|
-
|
|
468
|
-
- [ ] **Step 2: Commit**
|
|
469
|
-
|
|
470
|
-
```bash
|
|
471
|
-
git add src/components/DocumentViewer/
|
|
472
|
-
git commit -m "refactor: remove editor scheme links from DocumentViewer"
|
|
473
|
-
```
|
|
474
|
-
|
|
475
|
-
---
|
|
476
|
-
|
|
477
|
-
### Task 10: Simplify server settings
|
|
478
|
-
|
|
479
|
-
**Files:**
|
|
480
|
-
- Modify: `src/server/index.ts`
|
|
481
|
-
|
|
482
|
-
- [ ] **Step 1: Clean up settings handling**
|
|
483
|
-
|
|
484
|
-
In `src/server/index.ts`:
|
|
485
|
-
|
|
486
|
-
Remove from imports:
|
|
487
|
-
- `EditorSchemes`, `type EditorScheme` from types
|
|
488
|
-
|
|
489
|
-
Remove:
|
|
490
|
-
- `isValidEditorScheme` function
|
|
491
|
-
- `editorScheme` handling in `updateSettingsRoute` (the `if (editorScheme !== undefined ...)` block and the spread)
|
|
492
|
-
- `keybindings` handling in `updateSettingsRoute` (the spread)
|
|
493
|
-
|
|
494
|
-
The `updateSettingsRoute` should simplify to only handling `fontFamily`:
|
|
495
|
-
|
|
496
|
-
```typescript
|
|
497
|
-
async function updateSettingsRoute(req: Request): Promise<Response> {
|
|
498
|
-
try {
|
|
499
|
-
const body = await req.json();
|
|
500
|
-
const { fontFamily } = body;
|
|
501
|
-
|
|
502
|
-
if (fontFamily !== undefined && !isValidFontFamily(fontFamily)) {
|
|
503
|
-
return errorResponse("Invalid font family", 400);
|
|
504
|
-
}
|
|
505
|
-
|
|
506
|
-
const current = await readSettings();
|
|
507
|
-
const settings: DocumentSettings = {
|
|
508
|
-
...current,
|
|
509
|
-
...(fontFamily !== undefined && { fontFamily }),
|
|
510
|
-
};
|
|
511
|
-
|
|
512
|
-
await writeSettings(settings);
|
|
513
|
-
return json(settings);
|
|
514
|
-
} catch (err) {
|
|
515
|
-
console.error("Failed to save settings:", err);
|
|
516
|
-
return errorResponse("Failed to save settings", 500);
|
|
517
|
-
}
|
|
518
|
-
}
|
|
519
|
-
```
|
|
520
|
-
|
|
521
|
-
- [ ] **Step 2: Commit**
|
|
522
|
-
|
|
523
|
-
```bash
|
|
524
|
-
git add src/server/index.ts
|
|
525
|
-
git commit -m "refactor: simplify server settings to font only"
|
|
526
|
-
```
|
|
527
|
-
|
|
528
|
-
---
|
|
529
|
-
|
|
530
|
-
### Task 11: Clean up barrel exports and unused hook re-exports
|
|
531
|
-
|
|
532
|
-
**Files:**
|
|
533
|
-
- Check/Modify: `src/hooks/index.ts` (if it exists and re-exports deleted hooks)
|
|
534
|
-
- Check/Modify: `src/components/index.ts` (if it exists and re-exports deleted components)
|
|
535
|
-
|
|
536
|
-
- [ ] **Step 1: Find and fix barrel exports**
|
|
537
|
-
|
|
538
|
-
```bash
|
|
539
|
-
# Check for re-exports of deleted modules
|
|
540
|
-
grep -r "useLayoutMode\|useKeybindings\|useKeyboardShortcuts\|useEditorScheme\|useScrollMetrics\|ShortcutCapture\|ShortcutList\|FloatingTOC\|CommentMinimap\|shortcut-registry\|editor-links\|LayoutContext\|useLayoutContext" src/ --include="*.ts" --include="*.tsx" -l
|
|
541
|
-
```
|
|
542
|
-
|
|
543
|
-
Remove any re-exports of deleted modules from barrel files.
|
|
544
|
-
|
|
545
|
-
- [ ] **Step 2: Commit**
|
|
546
|
-
|
|
547
|
-
```bash
|
|
548
|
-
git add -A
|
|
549
|
-
git commit -m "chore: clean up barrel exports for deleted modules"
|
|
550
|
-
```
|
|
551
|
-
|
|
552
|
-
---
|
|
553
|
-
|
|
554
|
-
### Task 12: Full verification
|
|
555
|
-
|
|
556
|
-
- [ ] **Step 1: Run typecheck**
|
|
557
|
-
|
|
558
|
-
```bash
|
|
559
|
-
bun run typecheck
|
|
560
|
-
```
|
|
561
|
-
|
|
562
|
-
Expected: PASS with zero errors.
|
|
563
|
-
|
|
564
|
-
- [ ] **Step 2: Run tests**
|
|
565
|
-
|
|
566
|
-
```bash
|
|
567
|
-
bun run test
|
|
568
|
-
```
|
|
569
|
-
|
|
570
|
-
Expected: All remaining tests pass. `shortcut-registry.test.ts` was deleted — that's expected. Other test files should be unaffected.
|
|
571
|
-
|
|
572
|
-
- [ ] **Step 3: Run lint**
|
|
573
|
-
|
|
574
|
-
```bash
|
|
575
|
-
bun run check
|
|
576
|
-
```
|
|
577
|
-
|
|
578
|
-
Expected: No new lint errors. Fix any issues.
|
|
579
|
-
|
|
580
|
-
- [ ] **Step 4: Build**
|
|
581
|
-
|
|
582
|
-
```bash
|
|
583
|
-
bun run build
|
|
584
|
-
```
|
|
585
|
-
|
|
586
|
-
Expected: Successful production build.
|
|
587
|
-
|
|
588
|
-
- [ ] **Step 5: Manual smoke test**
|
|
589
|
-
|
|
590
|
-
```bash
|
|
591
|
-
bun dev -- test-file.md
|
|
592
|
-
```
|
|
593
|
-
|
|
594
|
-
Verify in browser:
|
|
595
|
-
- Document renders correctly
|
|
596
|
-
- Can select text and add comments
|
|
597
|
-
- Margin notes appear
|
|
598
|
-
- TOC sidebar shows (always, no fullscreen toggle)
|
|
599
|
-
- Settings modal opens with theme, font, language (no shortcuts, no editor scheme)
|
|
600
|
-
- Actions menu has no fullscreen toggle
|
|
601
|
-
- No minimap on right edge
|
|
602
|
-
- Copy All works
|
|
603
|
-
- No console errors
|
|
604
|
-
|
|
605
|
-
- [ ] **Step 6: Commit any fixes**
|
|
606
|
-
|
|
607
|
-
```bash
|
|
608
|
-
git add -A
|
|
609
|
-
git commit -m "fix: resolve any remaining pruning issues"
|
|
610
|
-
```
|
|
611
|
-
|
|
612
|
-
---
|
|
613
|
-
|
|
614
|
-
### Task 13: Replace Radix Dialog with native `<dialog>`
|
|
615
|
-
|
|
616
|
-
Remove `@radix-ui/react-dialog` (and the 156-line wrapper) in favor of the HTML5 `<dialog>` element, which provides built-in backdrop, focus trap, and `Escape` to close.
|
|
617
|
-
|
|
618
|
-
**Files:**
|
|
619
|
-
- Rewrite: `src/components/ui/Dialog.tsx`
|
|
620
|
-
|
|
621
|
-
- [ ] **Step 1: Rewrite Dialog.tsx with native `<dialog>`**
|
|
622
|
-
|
|
623
|
-
```tsx
|
|
624
|
-
// src/components/ui/Dialog.tsx
|
|
625
|
-
import { X } from "lucide-react";
|
|
626
|
-
import { useEffect, useRef } from "react";
|
|
627
|
-
import { cn } from "../../lib/utils";
|
|
628
|
-
|
|
629
|
-
interface DialogProps {
|
|
630
|
-
open: boolean;
|
|
631
|
-
onOpenChange: (open: boolean) => void;
|
|
632
|
-
children: React.ReactNode;
|
|
633
|
-
}
|
|
634
|
-
|
|
635
|
-
function Dialog({ open, onOpenChange, children }: DialogProps) {
|
|
636
|
-
const ref = useRef<HTMLDialogElement>(null);
|
|
637
|
-
|
|
638
|
-
useEffect(() => {
|
|
639
|
-
const dialog = ref.current;
|
|
640
|
-
if (!dialog) return;
|
|
641
|
-
|
|
642
|
-
if (open && !dialog.open) {
|
|
643
|
-
dialog.showModal();
|
|
644
|
-
} else if (!open && dialog.open) {
|
|
645
|
-
dialog.close();
|
|
646
|
-
}
|
|
647
|
-
}, [open]);
|
|
648
|
-
|
|
649
|
-
useEffect(() => {
|
|
650
|
-
const dialog = ref.current;
|
|
651
|
-
if (!dialog) return;
|
|
652
|
-
|
|
653
|
-
const handleClose = () => onOpenChange(false);
|
|
654
|
-
dialog.addEventListener("close", handleClose);
|
|
655
|
-
return () => dialog.removeEventListener("close", handleClose);
|
|
656
|
-
}, [onOpenChange]);
|
|
657
|
-
|
|
658
|
-
// Close on backdrop click
|
|
659
|
-
const handleClick = (e: React.MouseEvent<HTMLDialogElement>) => {
|
|
660
|
-
if (e.target === ref.current) onOpenChange(false);
|
|
661
|
-
};
|
|
662
|
-
|
|
663
|
-
return (
|
|
664
|
-
<dialog
|
|
665
|
-
ref={ref}
|
|
666
|
-
onClick={handleClick}
|
|
667
|
-
className="backdrop:bg-black/20 dark:backdrop:bg-black/40 backdrop:backdrop-blur-sm bg-transparent p-0 m-auto max-w-none"
|
|
668
|
-
>
|
|
669
|
-
{open ? children : null}
|
|
670
|
-
</dialog>
|
|
671
|
-
);
|
|
672
|
-
}
|
|
673
|
-
|
|
674
|
-
function DialogContent({
|
|
675
|
-
className,
|
|
676
|
-
children,
|
|
677
|
-
}: {
|
|
678
|
-
className?: string;
|
|
679
|
-
children: React.ReactNode;
|
|
680
|
-
}) {
|
|
681
|
-
return (
|
|
682
|
-
<div
|
|
683
|
-
className={cn(
|
|
684
|
-
"w-full bg-white/95 dark:bg-zinc-900/95 backdrop-blur-sm shadow-lg border border-zinc-200/40 dark:border-zinc-700/40 rounded-xl flex flex-col",
|
|
685
|
-
className,
|
|
686
|
-
)}
|
|
687
|
-
>
|
|
688
|
-
{children}
|
|
689
|
-
</div>
|
|
690
|
-
);
|
|
691
|
-
}
|
|
692
|
-
|
|
693
|
-
function DialogHeader({
|
|
694
|
-
className,
|
|
695
|
-
children,
|
|
696
|
-
onClose,
|
|
697
|
-
}: {
|
|
698
|
-
className?: string;
|
|
699
|
-
children: React.ReactNode;
|
|
700
|
-
onClose?: () => void;
|
|
701
|
-
}) {
|
|
702
|
-
return (
|
|
703
|
-
<div
|
|
704
|
-
className={cn(
|
|
705
|
-
"flex items-center justify-between pl-4 pr-3 py-3 border-b border-zinc-100 dark:border-zinc-800",
|
|
706
|
-
className,
|
|
707
|
-
)}
|
|
708
|
-
>
|
|
709
|
-
{children}
|
|
710
|
-
{onClose && (
|
|
711
|
-
<button
|
|
712
|
-
type="button"
|
|
713
|
-
onClick={onClose}
|
|
714
|
-
className="size-7 inline-flex items-center justify-center rounded-lg text-zinc-600 dark:text-zinc-400 hover:bg-zinc-100 dark:hover:bg-zinc-800"
|
|
715
|
-
>
|
|
716
|
-
<X className="w-4 h-4" />
|
|
717
|
-
</button>
|
|
718
|
-
)}
|
|
719
|
-
</div>
|
|
720
|
-
);
|
|
721
|
-
}
|
|
722
|
-
|
|
723
|
-
function DialogTitle({
|
|
724
|
-
className,
|
|
725
|
-
children,
|
|
726
|
-
}: {
|
|
727
|
-
className?: string;
|
|
728
|
-
children: React.ReactNode;
|
|
729
|
-
}) {
|
|
730
|
-
return (
|
|
731
|
-
<h2
|
|
732
|
-
className={cn(
|
|
733
|
-
"text-sm font-medium text-zinc-900 dark:text-zinc-100",
|
|
734
|
-
className,
|
|
735
|
-
)}
|
|
736
|
-
>
|
|
737
|
-
{children}
|
|
738
|
-
</h2>
|
|
739
|
-
);
|
|
740
|
-
}
|
|
741
|
-
|
|
742
|
-
function DialogBody({
|
|
743
|
-
className,
|
|
744
|
-
children,
|
|
745
|
-
}: {
|
|
746
|
-
className?: string;
|
|
747
|
-
children: React.ReactNode;
|
|
748
|
-
}) {
|
|
749
|
-
return (
|
|
750
|
-
<div className={cn("flex-1 overflow-auto p-4", className)}>{children}</div>
|
|
751
|
-
);
|
|
752
|
-
}
|
|
753
|
-
|
|
754
|
-
export { Dialog, DialogBody, DialogContent, DialogHeader, DialogTitle };
|
|
755
|
-
```
|
|
756
|
-
|
|
757
|
-
- [ ] **Step 2: Update SettingsModal and RawModal to use new Dialog API**
|
|
758
|
-
|
|
759
|
-
The new Dialog no longer has a built-in close button inside DialogContent. Instead, pass `onClose` to `DialogHeader`:
|
|
760
|
-
|
|
761
|
-
```tsx
|
|
762
|
-
// In SettingsModal.tsx / RawModal.tsx — adjust DialogHeader usage:
|
|
763
|
-
<Dialog open={isOpen} onOpenChange={(open) => { if (!open) onClose(); }}>
|
|
764
|
-
<DialogContent className="max-w-md">
|
|
765
|
-
<DialogHeader onClose={onClose}>
|
|
766
|
-
<DialogTitle>{t("settings.title")}</DialogTitle>
|
|
767
|
-
</DialogHeader>
|
|
768
|
-
<DialogBody>...</DialogBody>
|
|
769
|
-
</DialogContent>
|
|
770
|
-
</Dialog>
|
|
771
|
-
```
|
|
772
|
-
|
|
773
|
-
Remove any imports of `DialogTrigger`, `DialogClose`, `DialogPortal`, `DialogOverlay`, `DialogDescription` — they no longer exist.
|
|
774
|
-
|
|
775
|
-
- [ ] **Step 3: Commit**
|
|
776
|
-
|
|
777
|
-
```bash
|
|
778
|
-
git add src/components/ui/Dialog.tsx src/components/SettingsModal.tsx src/components/RawModal.tsx
|
|
779
|
-
git commit -m "refactor: replace Radix Dialog with native <dialog> element"
|
|
780
|
-
```
|
|
781
|
-
|
|
782
|
-
---
|
|
783
|
-
|
|
784
|
-
### Task 14: Replace Radix DropdownMenu with lightweight custom dropdown
|
|
785
|
-
|
|
786
|
-
Replace `@radix-ui/react-dropdown-menu` with a simple custom dropdown using the existing `useClickOutside` hook.
|
|
787
|
-
|
|
788
|
-
**Files:**
|
|
789
|
-
- Rewrite: `src/components/ui/DropdownMenu.tsx`
|
|
790
|
-
|
|
791
|
-
- [ ] **Step 1: Rewrite DropdownMenu.tsx**
|
|
792
|
-
|
|
793
|
-
```tsx
|
|
794
|
-
// src/components/ui/DropdownMenu.tsx
|
|
795
|
-
import { createContext, use, useCallback, useRef, useState } from "react";
|
|
796
|
-
import { useClickOutside } from "../../hooks/useClickOutside";
|
|
797
|
-
import { cn } from "../../lib/utils";
|
|
798
|
-
|
|
799
|
-
interface DropdownState {
|
|
800
|
-
open: boolean;
|
|
801
|
-
setOpen: (open: boolean) => void;
|
|
802
|
-
}
|
|
803
|
-
|
|
804
|
-
const DropdownContext = createContext<DropdownState>({ open: false, setOpen: () => {} });
|
|
805
|
-
|
|
806
|
-
function DropdownMenu({
|
|
807
|
-
open: controlledOpen,
|
|
808
|
-
onOpenChange,
|
|
809
|
-
children,
|
|
810
|
-
}: {
|
|
811
|
-
open?: boolean;
|
|
812
|
-
onOpenChange?: (open: boolean) => void;
|
|
813
|
-
children: React.ReactNode;
|
|
814
|
-
}) {
|
|
815
|
-
const [internalOpen, setInternalOpen] = useState(false);
|
|
816
|
-
const isControlled = controlledOpen !== undefined;
|
|
817
|
-
const open = isControlled ? controlledOpen : internalOpen;
|
|
818
|
-
const setOpen = useCallback(
|
|
819
|
-
(v: boolean) => {
|
|
820
|
-
if (!isControlled) setInternalOpen(v);
|
|
821
|
-
onOpenChange?.(v);
|
|
822
|
-
},
|
|
823
|
-
[isControlled, onOpenChange],
|
|
824
|
-
);
|
|
825
|
-
|
|
826
|
-
const ref = useRef<HTMLDivElement>(null);
|
|
827
|
-
useClickOutside(ref, () => setOpen(false));
|
|
828
|
-
|
|
829
|
-
return (
|
|
830
|
-
<DropdownContext value={{ open, setOpen }}>
|
|
831
|
-
<div ref={ref} className="relative inline-block">
|
|
832
|
-
{children}
|
|
833
|
-
</div>
|
|
834
|
-
</DropdownContext>
|
|
835
|
-
);
|
|
836
|
-
}
|
|
837
|
-
|
|
838
|
-
function DropdownMenuTrigger({
|
|
839
|
-
asChild,
|
|
840
|
-
children,
|
|
841
|
-
...props
|
|
842
|
-
}: {
|
|
843
|
-
asChild?: boolean;
|
|
844
|
-
children: React.ReactNode;
|
|
845
|
-
} & React.ButtonHTMLAttributes<HTMLButtonElement>) {
|
|
846
|
-
const { open, setOpen } = use(DropdownContext);
|
|
847
|
-
|
|
848
|
-
if (asChild && children && typeof children === "object" && "props" in children) {
|
|
849
|
-
const child = children as React.ReactElement<Record<string, unknown>>;
|
|
850
|
-
return (
|
|
851
|
-
<child.type
|
|
852
|
-
{...child.props}
|
|
853
|
-
onClick={(e: React.MouseEvent) => {
|
|
854
|
-
setOpen(!open);
|
|
855
|
-
if (typeof child.props.onClick === "function") child.props.onClick(e);
|
|
856
|
-
}}
|
|
857
|
-
/>
|
|
858
|
-
);
|
|
859
|
-
}
|
|
860
|
-
|
|
861
|
-
return (
|
|
862
|
-
<button type="button" onClick={() => setOpen(!open)} {...props}>
|
|
863
|
-
{children}
|
|
864
|
-
</button>
|
|
865
|
-
);
|
|
866
|
-
}
|
|
867
|
-
|
|
868
|
-
function DropdownMenuContent({
|
|
869
|
-
className,
|
|
870
|
-
align = "start",
|
|
871
|
-
children,
|
|
872
|
-
}: {
|
|
873
|
-
className?: string;
|
|
874
|
-
align?: "start" | "end";
|
|
875
|
-
children: React.ReactNode;
|
|
876
|
-
}) {
|
|
877
|
-
const { open } = use(DropdownContext);
|
|
878
|
-
if (!open) return null;
|
|
879
|
-
|
|
880
|
-
return (
|
|
881
|
-
<div
|
|
882
|
-
className={cn(
|
|
883
|
-
"absolute top-full mt-1 z-50 min-w-[8rem] overflow-hidden rounded-xl py-1",
|
|
884
|
-
"bg-white/95 dark:bg-zinc-900/95 backdrop-blur-sm shadow-lg border border-zinc-200/40 dark:border-zinc-700/40",
|
|
885
|
-
align === "end" ? "right-0" : "left-0",
|
|
886
|
-
className,
|
|
887
|
-
)}
|
|
888
|
-
>
|
|
889
|
-
{children}
|
|
890
|
-
</div>
|
|
891
|
-
);
|
|
892
|
-
}
|
|
893
|
-
|
|
894
|
-
function DropdownMenuItem({
|
|
895
|
-
className,
|
|
896
|
-
variant = "default",
|
|
897
|
-
onSelect,
|
|
898
|
-
children,
|
|
899
|
-
...props
|
|
900
|
-
}: {
|
|
901
|
-
className?: string;
|
|
902
|
-
variant?: "default" | "destructive";
|
|
903
|
-
onSelect?: () => void;
|
|
904
|
-
children: React.ReactNode;
|
|
905
|
-
title?: string;
|
|
906
|
-
}) {
|
|
907
|
-
const { setOpen } = use(DropdownContext);
|
|
908
|
-
|
|
909
|
-
return (
|
|
910
|
-
<button
|
|
911
|
-
type="button"
|
|
912
|
-
className={cn(
|
|
913
|
-
"w-full px-3 py-1.5 text-left text-sm outline-none select-none transition-colors duration-150 flex items-center gap-2 cursor-default",
|
|
914
|
-
variant === "default" &&
|
|
915
|
-
"text-zinc-600 dark:text-zinc-400 hover:bg-zinc-50 dark:hover:bg-zinc-800 hover:text-zinc-900 dark:hover:text-zinc-100",
|
|
916
|
-
variant === "destructive" &&
|
|
917
|
-
"text-red-600 dark:text-red-400 hover:bg-red-50 dark:hover:bg-red-950 hover:text-red-700 dark:hover:text-red-300",
|
|
918
|
-
"[&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-3.5",
|
|
919
|
-
className,
|
|
920
|
-
)}
|
|
921
|
-
onClick={() => {
|
|
922
|
-
onSelect?.();
|
|
923
|
-
setOpen(false);
|
|
924
|
-
}}
|
|
925
|
-
{...props}
|
|
926
|
-
>
|
|
927
|
-
{children}
|
|
928
|
-
</button>
|
|
929
|
-
);
|
|
930
|
-
}
|
|
931
|
-
|
|
932
|
-
function DropdownMenuSeparator({ className }: { className?: string }) {
|
|
933
|
-
return (
|
|
934
|
-
<div className={cn("my-1 h-px bg-zinc-100 dark:bg-zinc-800", className)} />
|
|
935
|
-
);
|
|
936
|
-
}
|
|
937
|
-
|
|
938
|
-
export {
|
|
939
|
-
DropdownMenu,
|
|
940
|
-
DropdownMenuContent,
|
|
941
|
-
DropdownMenuItem,
|
|
942
|
-
DropdownMenuSeparator,
|
|
943
|
-
DropdownMenuTrigger,
|
|
944
|
-
};
|
|
945
|
-
```
|
|
946
|
-
|
|
947
|
-
- [ ] **Step 2: Verify consumers still work**
|
|
948
|
-
|
|
949
|
-
The API shape is intentionally similar to Radix (`DropdownMenu`, `DropdownMenuTrigger`, `DropdownMenuContent`, `DropdownMenuItem`, `DropdownMenuSeparator`). Consumers (ActionsMenu, SettingsModal) should need minimal changes — mainly removing unused imports like `DropdownMenuGroup` or `DropdownMenuLabel` if referenced.
|
|
950
|
-
|
|
951
|
-
- [ ] **Step 3: Commit**
|
|
952
|
-
|
|
953
|
-
```bash
|
|
954
|
-
git add src/components/ui/DropdownMenu.tsx
|
|
955
|
-
git commit -m "refactor: replace Radix DropdownMenu with lightweight custom dropdown"
|
|
956
|
-
```
|
|
957
|
-
|
|
958
|
-
---
|
|
959
|
-
|
|
960
|
-
### Task 15: Replace cva/Slot in Button and Text
|
|
961
|
-
|
|
962
|
-
Remove `class-variance-authority` and `@radix-ui/react-slot` dependencies from Button and Text. Use plain Tailwind class helpers.
|
|
963
|
-
|
|
964
|
-
**Files:**
|
|
965
|
-
- Modify: `src/components/ui/Button.tsx`
|
|
966
|
-
- Modify: `src/components/ui/Text.tsx`
|
|
967
|
-
|
|
968
|
-
- [ ] **Step 1: Rewrite Button.tsx**
|
|
969
|
-
|
|
970
|
-
```tsx
|
|
971
|
-
// src/components/ui/Button.tsx
|
|
972
|
-
import { cn } from "../../lib/utils";
|
|
973
|
-
|
|
974
|
-
const baseStyles =
|
|
975
|
-
"inline-flex items-center justify-center gap-2 rounded-lg text-sm font-medium transition-colors duration-150 active:scale-[0.98] disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0";
|
|
976
|
-
|
|
977
|
-
const variantStyles = {
|
|
978
|
-
default: "bg-blue-600 text-white hover:bg-blue-700",
|
|
979
|
-
secondary:
|
|
980
|
-
"bg-zinc-100 dark:bg-zinc-800 text-zinc-900 dark:text-zinc-100 hover:bg-zinc-200 dark:hover:bg-zinc-700",
|
|
981
|
-
outline:
|
|
982
|
-
"border border-zinc-200 dark:border-zinc-700 bg-white dark:bg-zinc-900 text-zinc-700 dark:text-zinc-300 hover:bg-zinc-50 dark:hover:bg-zinc-800",
|
|
983
|
-
ghost:
|
|
984
|
-
"text-zinc-600 dark:text-zinc-400 hover:bg-zinc-100 dark:hover:bg-zinc-800 hover:text-zinc-900 dark:hover:text-zinc-100",
|
|
985
|
-
destructive: "bg-red-600 text-white hover:bg-red-700",
|
|
986
|
-
link: "text-zinc-600 dark:text-zinc-400 underline-offset-4 hover:underline",
|
|
987
|
-
} as const;
|
|
988
|
-
|
|
989
|
-
const sizeStyles = {
|
|
990
|
-
default: "h-9 px-4",
|
|
991
|
-
sm: "h-8 px-3 text-xs",
|
|
992
|
-
lg: "h-10 px-6",
|
|
993
|
-
icon: "size-9",
|
|
994
|
-
} as const;
|
|
995
|
-
|
|
996
|
-
type ButtonVariant = keyof typeof variantStyles;
|
|
997
|
-
type ButtonSize = keyof typeof sizeStyles;
|
|
998
|
-
|
|
999
|
-
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
|
1000
|
-
variant?: ButtonVariant;
|
|
1001
|
-
size?: ButtonSize;
|
|
1002
|
-
}
|
|
1003
|
-
|
|
1004
|
-
function Button({
|
|
1005
|
-
className,
|
|
1006
|
-
variant = "default",
|
|
1007
|
-
size = "default",
|
|
1008
|
-
...props
|
|
1009
|
-
}: ButtonProps) {
|
|
1010
|
-
return (
|
|
1011
|
-
<button
|
|
1012
|
-
type="button"
|
|
1013
|
-
className={cn(baseStyles, variantStyles[variant], sizeStyles[size], className)}
|
|
1014
|
-
{...props}
|
|
1015
|
-
/>
|
|
1016
|
-
);
|
|
1017
|
-
}
|
|
1018
|
-
|
|
1019
|
-
export { Button };
|
|
1020
|
-
export type { ButtonVariant, ButtonSize };
|
|
1021
|
-
```
|
|
1022
|
-
|
|
1023
|
-
- [ ] **Step 2: Rewrite Text.tsx**
|
|
1024
|
-
|
|
1025
|
-
```tsx
|
|
1026
|
-
// src/components/ui/Text.tsx
|
|
1027
|
-
import { use } from "react";
|
|
1028
|
-
import { SettingsContext } from "../../contexts/SettingsContext";
|
|
1029
|
-
import { cn } from "../../lib/utils";
|
|
1030
|
-
import { FontFamilies } from "../../types";
|
|
1031
|
-
|
|
1032
|
-
const variantStyles = {
|
|
1033
|
-
title: "text-lg font-semibold tracking-tight text-zinc-900 dark:text-zinc-100",
|
|
1034
|
-
section: "text-sm font-medium text-zinc-900 dark:text-zinc-100",
|
|
1035
|
-
subsection: "text-xs font-medium text-zinc-700 dark:text-zinc-300",
|
|
1036
|
-
overline: "text-xs font-medium text-zinc-500 dark:text-zinc-400 uppercase tracking-wider",
|
|
1037
|
-
body: "text-sm text-zinc-600 dark:text-zinc-400",
|
|
1038
|
-
caption: "text-xs text-zinc-500 dark:text-zinc-400",
|
|
1039
|
-
micro: "text-[10px] text-zinc-400 dark:text-zinc-500",
|
|
1040
|
-
} as const;
|
|
1041
|
-
|
|
1042
|
-
type TextVariant = keyof typeof variantStyles;
|
|
1043
|
-
|
|
1044
|
-
interface TextProps extends React.HTMLAttributes<HTMLElement> {
|
|
1045
|
-
variant?: TextVariant;
|
|
1046
|
-
as?: "p" | "span" | "div" | "h1" | "h2" | "h3" | "label";
|
|
1047
|
-
}
|
|
1048
|
-
|
|
1049
|
-
function Text({
|
|
1050
|
-
className,
|
|
1051
|
-
variant = "body",
|
|
1052
|
-
as: Tag = "p",
|
|
1053
|
-
...props
|
|
1054
|
-
}: TextProps) {
|
|
1055
|
-
const settings = use(SettingsContext);
|
|
1056
|
-
const fontClass = settings
|
|
1057
|
-
? settings.fontFamily === FontFamilies.SANS_SERIF
|
|
1058
|
-
? "font-sans"
|
|
1059
|
-
: "font-serif"
|
|
1060
|
-
: undefined;
|
|
1061
|
-
|
|
1062
|
-
return (
|
|
1063
|
-
<Tag
|
|
1064
|
-
className={cn(fontClass, variantStyles[variant], className)}
|
|
1065
|
-
{...props}
|
|
1066
|
-
/>
|
|
1067
|
-
);
|
|
1068
|
-
}
|
|
1069
|
-
|
|
1070
|
-
export { Text, variantStyles as textVariants };
|
|
1071
|
-
export type { TextVariant };
|
|
1072
|
-
```
|
|
1073
|
-
|
|
1074
|
-
**IMPORTANT cross-cutting changes:**
|
|
1075
|
-
|
|
1076
|
-
1. The `asChild` pattern is removed. All consumers (13 files!) that use `<Text asChild>` must switch to `<Text as="span">` (or `as="h1"`, etc). Similarly, `<Button asChild>` usages become plain `<button>` elements with Button's styles.
|
|
1077
|
-
|
|
1078
|
-
2. `textVariants` changes from a cva function `textVariants({ variant: "caption" })` to a plain object `variantStyles.caption`. The export alias is kept for compatibility, but ALL call sites must change from function syntax to property access. Known consumers: `App.tsx` (Toaster options), `DropdownMenu.tsx` (rewritten in Task 14), `Dialog.tsx` (rewritten in Task 13).
|
|
1079
|
-
|
|
1080
|
-
Search for all `asChild` usages and update them:
|
|
1081
|
-
|
|
1082
|
-
```bash
|
|
1083
|
-
grep -r "asChild" src/ --include="*.tsx" -l
|
|
1084
|
-
```
|
|
1085
|
-
|
|
1086
|
-
Each `<Text variant="title" asChild><h1>` becomes `<Text variant="title" as="h1">`.
|
|
1087
|
-
Each `<Text variant="caption" asChild><span>` becomes `<Text variant="caption" as="span">`.
|
|
1088
|
-
|
|
1089
|
-
Similarly, `<Button asChild>` usages need to be converted to plain `<button>` or `<a>` elements with Button's styles applied via className.
|
|
1090
|
-
|
|
1091
|
-
- [ ] **Step 3: Update all asChild consumers**
|
|
1092
|
-
|
|
1093
|
-
Search and replace all `asChild` usages across the codebase. Common patterns:
|
|
1094
|
-
|
|
1095
|
-
```tsx
|
|
1096
|
-
// Before
|
|
1097
|
-
<Text variant="title" asChild><h1>readit</h1></Text>
|
|
1098
|
-
// After
|
|
1099
|
-
<Text variant="title" as="h1">readit</Text>
|
|
1100
|
-
|
|
1101
|
-
// Before
|
|
1102
|
-
<Text variant="caption" asChild><span>...</span></Text>
|
|
1103
|
-
// After
|
|
1104
|
-
<Text variant="caption" as="span">...</Text>
|
|
1105
|
-
```
|
|
1106
|
-
|
|
1107
|
-
- [ ] **Step 4: Commit**
|
|
1108
|
-
|
|
1109
|
-
```bash
|
|
1110
|
-
git add src/components/ui/Button.tsx src/components/ui/Text.tsx
|
|
1111
|
-
git add -A # catch all consumer updates
|
|
1112
|
-
git commit -m "refactor: replace cva/Slot with plain Tailwind helpers in Button and Text"
|
|
1113
|
-
```
|
|
1114
|
-
|
|
1115
|
-
---
|
|
1116
|
-
|
|
1117
|
-
### Task 16: Remove Radix and cva packages
|
|
1118
|
-
|
|
1119
|
-
**Files:**
|
|
1120
|
-
- Modify: `package.json`
|
|
1121
|
-
|
|
1122
|
-
- [ ] **Step 1: Uninstall packages**
|
|
1123
|
-
|
|
1124
|
-
```bash
|
|
1125
|
-
bun remove @radix-ui/react-dialog @radix-ui/react-dropdown-menu @radix-ui/react-slot class-variance-authority
|
|
1126
|
-
```
|
|
1127
|
-
|
|
1128
|
-
- [ ] **Step 2: Verify build**
|
|
1129
|
-
|
|
1130
|
-
```bash
|
|
1131
|
-
bun run typecheck && bun run build
|
|
1132
|
-
```
|
|
1133
|
-
|
|
1134
|
-
- [ ] **Step 3: Commit**
|
|
1135
|
-
|
|
1136
|
-
```bash
|
|
1137
|
-
git add package.json bun.lockb
|
|
1138
|
-
git commit -m "chore: remove Radix UI and class-variance-authority dependencies"
|
|
1139
|
-
```
|
|
1140
|
-
|
|
1141
|
-
---
|
|
1142
|
-
|
|
1143
|
-
### Task 17: Final verification (phase 2)
|
|
1144
|
-
|
|
1145
|
-
- [ ] **Step 1: Run full check suite**
|
|
1146
|
-
|
|
1147
|
-
```bash
|
|
1148
|
-
bun run typecheck && bun run test && bun run check && bun run build
|
|
1149
|
-
```
|
|
1150
|
-
|
|
1151
|
-
- [ ] **Step 2: Manual smoke test**
|
|
1152
|
-
|
|
1153
|
-
Same verification as Task 12 Step 5, plus:
|
|
1154
|
-
- Settings modal opens and closes correctly (native dialog)
|
|
1155
|
-
- Actions dropdown opens/closes, items are clickable
|
|
1156
|
-
- All dropdown menus in settings work (theme, font, language)
|
|
1157
|
-
- No console errors
|
|
1158
|
-
|
|
1159
|
-
- [ ] **Step 3: Commit any fixes**
|
|
1160
|
-
|
|
1161
|
-
```bash
|
|
1162
|
-
git add -A
|
|
1163
|
-
git commit -m "chore: pruning complete — removed features, Radix, cva"
|
|
1164
|
-
```
|
|
1165
|
-
|
|
1166
|
-
---
|
|
1167
|
-
|
|
1168
|
-
## Out of Scope (Future Tasks)
|
|
1169
|
-
|
|
1170
|
-
These are high-impact optimizations identified during analysis but not part of this pruning pass:
|
|
1171
|
-
|
|
1172
|
-
1. **Lazy-load mermaid** — dynamic `import()` only when mermaid fences detected. Currently loads ~2MB+ eagerly.
|
|
1173
|
-
2. **Replace react-syntax-highlighter** — switch to Shiki (lighter, tree-shakeable) or plain `<pre>` with minimal highlighting.
|
|
1174
|
-
3. **Simplify CSS utility stack** — currently using `clsx` + `tailwind-merge`. After removing `cva`, evaluate if both are still needed.
|
|
1175
|
-
4. **Flatten remaining state layers** — the Zustand store + CommentContext + hooks could be simplified further.
|
|
1176
|
-
5. **Lazy-load heavy components** — `React.lazy()` for SettingsModal, RawModal, MermaidDiagram.
|