@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,70 +0,0 @@
1
- ---
2
- title: Cache Storage API Calls
3
- impact: LOW-MEDIUM
4
- impactDescription: reduces expensive I/O
5
- tags: javascript, localStorage, storage, caching, performance
6
- ---
7
-
8
- ## Cache Storage API Calls
9
-
10
- `localStorage`, `sessionStorage`, and `document.cookie` are synchronous and expensive. Cache reads in memory.
11
-
12
- **Incorrect (reads storage on every call):**
13
-
14
- ```typescript
15
- function getTheme() {
16
- return localStorage.getItem('theme') ?? 'light'
17
- }
18
- // Called 10 times = 10 storage reads
19
- ```
20
-
21
- **Correct (Map cache):**
22
-
23
- ```typescript
24
- const storageCache = new Map<string, string | null>()
25
-
26
- function getLocalStorage(key: string) {
27
- if (!storageCache.has(key)) {
28
- storageCache.set(key, localStorage.getItem(key))
29
- }
30
- return storageCache.get(key)
31
- }
32
-
33
- function setLocalStorage(key: string, value: string) {
34
- localStorage.setItem(key, value)
35
- storageCache.set(key, value) // keep cache in sync
36
- }
37
- ```
38
-
39
- Use a Map (not a hook) so it works everywhere: utilities, event handlers, not just React components.
40
-
41
- **Cookie caching:**
42
-
43
- ```typescript
44
- let cookieCache: Record<string, string> | null = null
45
-
46
- function getCookie(name: string) {
47
- if (!cookieCache) {
48
- cookieCache = Object.fromEntries(
49
- document.cookie.split('; ').map(c => c.split('='))
50
- )
51
- }
52
- return cookieCache[name]
53
- }
54
- ```
55
-
56
- **Important (invalidate on external changes):**
57
-
58
- If storage can change externally (another tab, server-set cookies), invalidate cache:
59
-
60
- ```typescript
61
- window.addEventListener('storage', (e) => {
62
- if (e.key) storageCache.delete(e.key)
63
- })
64
-
65
- document.addEventListener('visibilitychange', () => {
66
- if (document.visibilityState === 'visible') {
67
- storageCache.clear()
68
- }
69
- })
70
- ```
@@ -1,32 +0,0 @@
1
- ---
2
- title: Combine Multiple Array Iterations
3
- impact: LOW-MEDIUM
4
- impactDescription: reduces iterations
5
- tags: javascript, arrays, loops, performance
6
- ---
7
-
8
- ## Combine Multiple Array Iterations
9
-
10
- Multiple `.filter()` or `.map()` calls iterate the array multiple times. Combine into one loop.
11
-
12
- **Incorrect (3 iterations):**
13
-
14
- ```typescript
15
- const admins = users.filter(u => u.isAdmin)
16
- const testers = users.filter(u => u.isTester)
17
- const inactive = users.filter(u => !u.isActive)
18
- ```
19
-
20
- **Correct (1 iteration):**
21
-
22
- ```typescript
23
- const admins: User[] = []
24
- const testers: User[] = []
25
- const inactive: User[] = []
26
-
27
- for (const user of users) {
28
- if (user.isAdmin) admins.push(user)
29
- if (user.isTester) testers.push(user)
30
- if (!user.isActive) inactive.push(user)
31
- }
32
- ```
@@ -1,50 +0,0 @@
1
- ---
2
- title: Early Return from Functions
3
- impact: LOW-MEDIUM
4
- impactDescription: avoids unnecessary computation
5
- tags: javascript, functions, optimization, early-return
6
- ---
7
-
8
- ## Early Return from Functions
9
-
10
- Return early when result is determined to skip unnecessary processing.
11
-
12
- **Incorrect (processes all items even after finding answer):**
13
-
14
- ```typescript
15
- function validateUsers(users: User[]) {
16
- let hasError = false
17
- let errorMessage = ''
18
-
19
- for (const user of users) {
20
- if (!user.email) {
21
- hasError = true
22
- errorMessage = 'Email required'
23
- }
24
- if (!user.name) {
25
- hasError = true
26
- errorMessage = 'Name required'
27
- }
28
- // Continues checking all users even after error found
29
- }
30
-
31
- return hasError ? { valid: false, error: errorMessage } : { valid: true }
32
- }
33
- ```
34
-
35
- **Correct (returns immediately on first error):**
36
-
37
- ```typescript
38
- function validateUsers(users: User[]) {
39
- for (const user of users) {
40
- if (!user.email) {
41
- return { valid: false, error: 'Email required' }
42
- }
43
- if (!user.name) {
44
- return { valid: false, error: 'Name required' }
45
- }
46
- }
47
-
48
- return { valid: true }
49
- }
50
- ```
@@ -1,60 +0,0 @@
1
- ---
2
- title: Use flatMap to Map and Filter in One Pass
3
- impact: LOW-MEDIUM
4
- impactDescription: eliminates intermediate array
5
- tags: javascript, arrays, flatMap, filter, performance
6
- ---
7
-
8
- ## Use flatMap to Map and Filter in One Pass
9
-
10
- **Impact: LOW-MEDIUM (eliminates intermediate array)**
11
-
12
- Chaining `.map().filter(Boolean)` creates an intermediate array and iterates twice. Use `.flatMap()` to transform and filter in a single pass.
13
-
14
- **Incorrect (2 iterations, intermediate array):**
15
-
16
- ```typescript
17
- const userNames = users
18
- .map(user => user.isActive ? user.name : null)
19
- .filter(Boolean)
20
- ```
21
-
22
- **Correct (1 iteration, no intermediate array):**
23
-
24
- ```typescript
25
- const userNames = users.flatMap(user =>
26
- user.isActive ? [user.name] : []
27
- )
28
- ```
29
-
30
- **More examples:**
31
-
32
- ```typescript
33
- // Extract valid emails from responses
34
- // Before
35
- const emails = responses
36
- .map(r => r.success ? r.data.email : null)
37
- .filter(Boolean)
38
-
39
- // After
40
- const emails = responses.flatMap(r =>
41
- r.success ? [r.data.email] : []
42
- )
43
-
44
- // Parse and filter valid numbers
45
- // Before
46
- const numbers = strings
47
- .map(s => parseInt(s, 10))
48
- .filter(n => !isNaN(n))
49
-
50
- // After
51
- const numbers = strings.flatMap(s => {
52
- const n = parseInt(s, 10)
53
- return isNaN(n) ? [] : [n]
54
- })
55
- ```
56
-
57
- **When to use:**
58
- - Transforming items while filtering some out
59
- - Conditional mapping where some inputs produce no output
60
- - Parsing/validating where invalid inputs should be skipped
@@ -1,45 +0,0 @@
1
- ---
2
- title: Hoist RegExp Creation
3
- impact: LOW-MEDIUM
4
- impactDescription: avoids recreation
5
- tags: javascript, regexp, optimization, memoization
6
- ---
7
-
8
- ## Hoist RegExp Creation
9
-
10
- Don't create RegExp inside render. Hoist to module scope or memoize with `useMemo()`.
11
-
12
- **Incorrect (new RegExp every render):**
13
-
14
- ```tsx
15
- function Highlighter({ text, query }: Props) {
16
- const regex = new RegExp(`(${query})`, 'gi')
17
- const parts = text.split(regex)
18
- return <>{parts.map((part, i) => ...)}</>
19
- }
20
- ```
21
-
22
- **Correct (memoize or hoist):**
23
-
24
- ```tsx
25
- const EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
26
-
27
- function Highlighter({ text, query }: Props) {
28
- const regex = useMemo(
29
- () => new RegExp(`(${escapeRegex(query)})`, 'gi'),
30
- [query]
31
- )
32
- const parts = text.split(regex)
33
- return <>{parts.map((part, i) => ...)}</>
34
- }
35
- ```
36
-
37
- **Warning (global regex has mutable state):**
38
-
39
- Global regex (`/g`) has mutable `lastIndex` state:
40
-
41
- ```typescript
42
- const regex = /foo/g
43
- regex.test('foo') // true, lastIndex = 3
44
- regex.test('foo') // false, lastIndex = 0
45
- ```
@@ -1,37 +0,0 @@
1
- ---
2
- title: Build Index Maps for Repeated Lookups
3
- impact: LOW-MEDIUM
4
- impactDescription: 1M ops to 2K ops
5
- tags: javascript, map, indexing, optimization, performance
6
- ---
7
-
8
- ## Build Index Maps for Repeated Lookups
9
-
10
- Multiple `.find()` calls by the same key should use a Map.
11
-
12
- **Incorrect (O(n) per lookup):**
13
-
14
- ```typescript
15
- function processOrders(orders: Order[], users: User[]) {
16
- return orders.map(order => ({
17
- ...order,
18
- user: users.find(u => u.id === order.userId)
19
- }))
20
- }
21
- ```
22
-
23
- **Correct (O(1) per lookup):**
24
-
25
- ```typescript
26
- function processOrders(orders: Order[], users: User[]) {
27
- const userById = new Map(users.map(u => [u.id, u]))
28
-
29
- return orders.map(order => ({
30
- ...order,
31
- user: userById.get(order.userId)
32
- }))
33
- }
34
- ```
35
-
36
- Build map once (O(n)), then all lookups are O(1).
37
- For 1000 orders × 1000 users: 1M ops → 2K ops.
@@ -1,49 +0,0 @@
1
- ---
2
- title: Early Length Check for Array Comparisons
3
- impact: MEDIUM-HIGH
4
- impactDescription: avoids expensive operations when lengths differ
5
- tags: javascript, arrays, performance, optimization, comparison
6
- ---
7
-
8
- ## Early Length Check for Array Comparisons
9
-
10
- When comparing arrays with expensive operations (sorting, deep equality, serialization), check lengths first. If lengths differ, the arrays cannot be equal.
11
-
12
- In real-world applications, this optimization is especially valuable when the comparison runs in hot paths (event handlers, render loops).
13
-
14
- **Incorrect (always runs expensive comparison):**
15
-
16
- ```typescript
17
- function hasChanges(current: string[], original: string[]) {
18
- // Always sorts and joins, even when lengths differ
19
- return current.sort().join() !== original.sort().join()
20
- }
21
- ```
22
-
23
- Two O(n log n) sorts run even when `current.length` is 5 and `original.length` is 100. There is also overhead of joining the arrays and comparing the strings.
24
-
25
- **Correct (O(1) length check first):**
26
-
27
- ```typescript
28
- function hasChanges(current: string[], original: string[]) {
29
- // Early return if lengths differ
30
- if (current.length !== original.length) {
31
- return true
32
- }
33
- // Only sort when lengths match
34
- const currentSorted = current.toSorted()
35
- const originalSorted = original.toSorted()
36
- for (let i = 0; i < currentSorted.length; i++) {
37
- if (currentSorted[i] !== originalSorted[i]) {
38
- return true
39
- }
40
- }
41
- return false
42
- }
43
- ```
44
-
45
- This new approach is more efficient because:
46
- - It avoids the overhead of sorting and joining the arrays when lengths differ
47
- - It avoids consuming memory for the joined strings (especially important for large arrays)
48
- - It avoids mutating the original arrays
49
- - It returns early when a difference is found
@@ -1,82 +0,0 @@
1
- ---
2
- title: Use Loop for Min/Max Instead of Sort
3
- impact: LOW
4
- impactDescription: O(n) instead of O(n log n)
5
- tags: javascript, arrays, performance, sorting, algorithms
6
- ---
7
-
8
- ## Use Loop for Min/Max Instead of Sort
9
-
10
- Finding the smallest or largest element only requires a single pass through the array. Sorting is wasteful and slower.
11
-
12
- **Incorrect (O(n log n) - sort to find latest):**
13
-
14
- ```typescript
15
- interface Project {
16
- id: string
17
- name: string
18
- updatedAt: number
19
- }
20
-
21
- function getLatestProject(projects: Project[]) {
22
- const sorted = [...projects].sort((a, b) => b.updatedAt - a.updatedAt)
23
- return sorted[0]
24
- }
25
- ```
26
-
27
- Sorts the entire array just to find the maximum value.
28
-
29
- **Incorrect (O(n log n) - sort for oldest and newest):**
30
-
31
- ```typescript
32
- function getOldestAndNewest(projects: Project[]) {
33
- const sorted = [...projects].sort((a, b) => a.updatedAt - b.updatedAt)
34
- return { oldest: sorted[0], newest: sorted[sorted.length - 1] }
35
- }
36
- ```
37
-
38
- Still sorts unnecessarily when only min/max are needed.
39
-
40
- **Correct (O(n) - single loop):**
41
-
42
- ```typescript
43
- function getLatestProject(projects: Project[]) {
44
- if (projects.length === 0) return null
45
-
46
- let latest = projects[0]
47
-
48
- for (let i = 1; i < projects.length; i++) {
49
- if (projects[i].updatedAt > latest.updatedAt) {
50
- latest = projects[i]
51
- }
52
- }
53
-
54
- return latest
55
- }
56
-
57
- function getOldestAndNewest(projects: Project[]) {
58
- if (projects.length === 0) return { oldest: null, newest: null }
59
-
60
- let oldest = projects[0]
61
- let newest = projects[0]
62
-
63
- for (let i = 1; i < projects.length; i++) {
64
- if (projects[i].updatedAt < oldest.updatedAt) oldest = projects[i]
65
- if (projects[i].updatedAt > newest.updatedAt) newest = projects[i]
66
- }
67
-
68
- return { oldest, newest }
69
- }
70
- ```
71
-
72
- Single pass through the array, no copying, no sorting.
73
-
74
- **Alternative (Math.min/Math.max for small arrays):**
75
-
76
- ```typescript
77
- const numbers = [5, 2, 8, 1, 9]
78
- const min = Math.min(...numbers)
79
- const max = Math.max(...numbers)
80
- ```
81
-
82
- This works for small arrays, but can be slower or just throw an error for very large arrays due to spread operator limitations. Maximal array length is approximately 124000 in Chrome 143 and 638000 in Safari 18; exact numbers may vary - see [the fiddle](https://jsfiddle.net/qw1jabsx/4/). Use the loop approach for reliability.
@@ -1,24 +0,0 @@
1
- ---
2
- title: Use Set/Map for O(1) Lookups
3
- impact: LOW-MEDIUM
4
- impactDescription: O(n) to O(1)
5
- tags: javascript, set, map, data-structures, performance
6
- ---
7
-
8
- ## Use Set/Map for O(1) Lookups
9
-
10
- Convert arrays to Set/Map for repeated membership checks.
11
-
12
- **Incorrect (O(n) per check):**
13
-
14
- ```typescript
15
- const allowedIds = ['a', 'b', 'c', ...]
16
- items.filter(item => allowedIds.includes(item.id))
17
- ```
18
-
19
- **Correct (O(1) per check):**
20
-
21
- ```typescript
22
- const allowedIds = new Set(['a', 'b', 'c', ...])
23
- items.filter(item => allowedIds.has(item.id))
24
- ```
@@ -1,57 +0,0 @@
1
- ---
2
- title: Use toSorted() Instead of sort() for Immutability
3
- impact: MEDIUM-HIGH
4
- impactDescription: prevents mutation bugs in React state
5
- tags: javascript, arrays, immutability, react, state, mutation
6
- ---
7
-
8
- ## Use toSorted() Instead of sort() for Immutability
9
-
10
- `.sort()` mutates the array in place, which can cause bugs with React state and props. Use `.toSorted()` to create a new sorted array without mutation.
11
-
12
- **Incorrect (mutates original array):**
13
-
14
- ```typescript
15
- function UserList({ users }: { users: User[] }) {
16
- // Mutates the users prop array!
17
- const sorted = useMemo(
18
- () => users.sort((a, b) => a.name.localeCompare(b.name)),
19
- [users]
20
- )
21
- return <div>{sorted.map(renderUser)}</div>
22
- }
23
- ```
24
-
25
- **Correct (creates new array):**
26
-
27
- ```typescript
28
- function UserList({ users }: { users: User[] }) {
29
- // Creates new sorted array, original unchanged
30
- const sorted = useMemo(
31
- () => users.toSorted((a, b) => a.name.localeCompare(b.name)),
32
- [users]
33
- )
34
- return <div>{sorted.map(renderUser)}</div>
35
- }
36
- ```
37
-
38
- **Why this matters in React:**
39
-
40
- 1. Props/state mutations break React's immutability model - React expects props and state to be treated as read-only
41
- 2. Causes stale closure bugs - Mutating arrays inside closures (callbacks, effects) can lead to unexpected behavior
42
-
43
- **Browser support (fallback for older browsers):**
44
-
45
- `.toSorted()` is available in all modern browsers (Chrome 110+, Safari 16+, Firefox 115+, Node.js 20+). For older environments, use spread operator:
46
-
47
- ```typescript
48
- // Fallback for older browsers
49
- const sorted = [...items].sort((a, b) => a.value - b.value)
50
- ```
51
-
52
- **Other immutable array methods:**
53
-
54
- - `.toSorted()` - immutable sort
55
- - `.toReversed()` - immutable reverse
56
- - `.toSpliced()` - immutable splice
57
- - `.with()` - immutable element replacement
@@ -1,26 +0,0 @@
1
- ---
2
- title: Use Activity Component for Show/Hide
3
- impact: MEDIUM
4
- impactDescription: preserves state/DOM
5
- tags: rendering, activity, visibility, state-preservation
6
- ---
7
-
8
- ## Use Activity Component for Show/Hide
9
-
10
- Use React's `<Activity>` to preserve state/DOM for expensive components that frequently toggle visibility.
11
-
12
- **Usage:**
13
-
14
- ```tsx
15
- import { Activity } from 'react'
16
-
17
- function Dropdown({ isOpen }: Props) {
18
- return (
19
- <Activity mode={isOpen ? 'visible' : 'hidden'}>
20
- <ExpensiveMenu />
21
- </Activity>
22
- )
23
- }
24
- ```
25
-
26
- Avoids expensive re-renders and state loss.
@@ -1,47 +0,0 @@
1
- ---
2
- title: Animate SVG Wrapper Instead of SVG Element
3
- impact: LOW
4
- impactDescription: enables hardware acceleration
5
- tags: rendering, svg, css, animation, performance
6
- ---
7
-
8
- ## Animate SVG Wrapper Instead of SVG Element
9
-
10
- Many browsers don't have hardware acceleration for CSS3 animations on SVG elements. Wrap SVG in a `<div>` and animate the wrapper instead.
11
-
12
- **Incorrect (animating SVG directly - no hardware acceleration):**
13
-
14
- ```tsx
15
- function LoadingSpinner() {
16
- return (
17
- <svg
18
- className="animate-spin"
19
- width="24"
20
- height="24"
21
- viewBox="0 0 24 24"
22
- >
23
- <circle cx="12" cy="12" r="10" stroke="currentColor" />
24
- </svg>
25
- )
26
- }
27
- ```
28
-
29
- **Correct (animating wrapper div - hardware accelerated):**
30
-
31
- ```tsx
32
- function LoadingSpinner() {
33
- return (
34
- <div className="animate-spin">
35
- <svg
36
- width="24"
37
- height="24"
38
- viewBox="0 0 24 24"
39
- >
40
- <circle cx="12" cy="12" r="10" stroke="currentColor" />
41
- </svg>
42
- </div>
43
- )
44
- }
45
- ```
46
-
47
- This applies to all CSS transforms and transitions (`transform`, `opacity`, `translate`, `scale`, `rotate`). The wrapper div allows browsers to use GPU acceleration for smoother animations.
@@ -1,40 +0,0 @@
1
- ---
2
- title: Use Explicit Conditional Rendering
3
- impact: LOW
4
- impactDescription: prevents rendering 0 or NaN
5
- tags: rendering, conditional, jsx, falsy-values
6
- ---
7
-
8
- ## Use Explicit Conditional Rendering
9
-
10
- Use explicit ternary operators (`? :`) instead of `&&` for conditional rendering when the condition can be `0`, `NaN`, or other falsy values that render.
11
-
12
- **Incorrect (renders "0" when count is 0):**
13
-
14
- ```tsx
15
- function Badge({ count }: { count: number }) {
16
- return (
17
- <div>
18
- {count && <span className="badge">{count}</span>}
19
- </div>
20
- )
21
- }
22
-
23
- // When count = 0, renders: <div>0</div>
24
- // When count = 5, renders: <div><span class="badge">5</span></div>
25
- ```
26
-
27
- **Correct (renders nothing when count is 0):**
28
-
29
- ```tsx
30
- function Badge({ count }: { count: number }) {
31
- return (
32
- <div>
33
- {count > 0 ? <span className="badge">{count}</span> : null}
34
- </div>
35
- )
36
- }
37
-
38
- // When count = 0, renders: <div></div>
39
- // When count = 5, renders: <div><span class="badge">5</span></div>
40
- ```
@@ -1,38 +0,0 @@
1
- ---
2
- title: CSS content-visibility for Long Lists
3
- impact: HIGH
4
- impactDescription: faster initial render
5
- tags: rendering, css, content-visibility, long-lists
6
- ---
7
-
8
- ## CSS content-visibility for Long Lists
9
-
10
- Apply `content-visibility: auto` to defer off-screen rendering.
11
-
12
- **CSS:**
13
-
14
- ```css
15
- .message-item {
16
- content-visibility: auto;
17
- contain-intrinsic-size: 0 80px;
18
- }
19
- ```
20
-
21
- **Example:**
22
-
23
- ```tsx
24
- function MessageList({ messages }: { messages: Message[] }) {
25
- return (
26
- <div className="overflow-y-auto h-screen">
27
- {messages.map(msg => (
28
- <div key={msg.id} className="message-item">
29
- <Avatar user={msg.author} />
30
- <div>{msg.content}</div>
31
- </div>
32
- ))}
33
- </div>
34
- )
35
- }
36
- ```
37
-
38
- For 1000 messages, browser skips layout/paint for ~990 off-screen items (10× faster initial render).