plannar 0.0.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/abap-BW9c03a7.mjs +3 -0
- package/dist/actionscript-3-B6AeQsdr.mjs +3 -0
- package/dist/ada-UAfcUgld.mjs +3 -0
- package/dist/andromeeda-Cu62joT4.mjs +4 -0
- package/dist/angular-html-C-eFVAIe.mjs +33 -0
- package/dist/angular-ts-BD6BhTYj.mjs +27 -0
- package/dist/apache-DWevXWr1.mjs +3 -0
- package/dist/apex-TPGYj5YO.mjs +3 -0
- package/dist/apl-DUmaAe2b.mjs +17 -0
- package/dist/applescript-DOvaC_Oy.mjs +3 -0
- package/dist/ara-D-j-XXGW.mjs +3 -0
- package/dist/asciidoc-Cds5g02g.mjs +3 -0
- package/dist/asm-fKrNhGI-.mjs +3 -0
- package/dist/astro-DO4Glno9.mjs +19 -0
- package/dist/aurora-x-BB0J0IeM.mjs +4 -0
- package/dist/awk-BffybAOE.mjs +3 -0
- package/dist/ayu-dark-BIk2eYyl.mjs +4 -0
- package/dist/ayu-light-pnpopa_u.mjs +4 -0
- package/dist/ayu-mirage-Dq1YQdbW.mjs +4 -0
- package/dist/ballerina-BD5CldPU.mjs +3 -0
- package/dist/bat-DMbz78YR.mjs +3 -0
- package/dist/beancount-CaTd9Bjz.mjs +3 -0
- package/dist/berry-BgUsmVaH.mjs +3 -0
- package/dist/bibtex-BS9dLuV0.mjs +3 -0
- package/dist/bicep-DWRRWjGd.mjs +3 -0
- package/dist/bird2-BlSty-nT.mjs +3 -0
- package/dist/blade-CH2DZiyx.mjs +21 -0
- package/dist/bsl-CJ91opd0.mjs +6 -0
- package/dist/c-D_Rf5vw8.mjs +6 -0
- package/dist/c3-CC9BmleM.mjs +3 -0
- package/dist/cadence-DrOG_Vzs.mjs +3 -0
- package/dist/cairo-BP4NeRvu.mjs +6 -0
- package/dist/catppuccin-frappe-CSSZy2I0.mjs +4 -0
- package/dist/catppuccin-latte-DnTXDnsj.mjs +4 -0
- package/dist/catppuccin-macchiato-Ckw0Vhkh.mjs +4 -0
- package/dist/catppuccin-mocha-BgepuhoR.mjs +4 -0
- package/dist/clarity-BUDmzLZe.mjs +3 -0
- package/dist/cli.d.mts +1 -0
- package/dist/cli.mjs +23 -0
- package/dist/clojure-WWg3It68.mjs +3 -0
- package/dist/cmake-DFHdRVuU.mjs +3 -0
- package/dist/cobol-BAR5Vngc.mjs +11 -0
- package/dist/codeowners-DVDrZMQO.mjs +3 -0
- package/dist/codeql-CyBidtfP.mjs +3 -0
- package/dist/coffee-BInjHxEE.mjs +6 -0
- package/dist/common-lisp-QjFch7-u.mjs +3 -0
- package/dist/config-FJViU9hJ.mjs +59 -0
- package/dist/coq-BsUrCVvK.mjs +3 -0
- package/dist/core/index.d.mts +50 -0
- package/dist/core/index.mjs +313 -0
- package/dist/core-styles/mdx.css +337 -0
- package/dist/core-styles/theme.css +128 -0
- package/dist/cpp-CENjCKTD.mjs +25 -0
- package/dist/crystal-CXaN9OP7.mjs +19 -0
- package/dist/csharp-D-QFUFEE.mjs +3 -0
- package/dist/css-C2wCJA_G.mjs +6 -0
- package/dist/csv-Cb3ztF11.mjs +3 -0
- package/dist/cue-BRViwSb5.mjs +3 -0
- package/dist/cypher-DsZ0r_SN.mjs +3 -0
- package/dist/d-DeVAByS9.mjs +3 -0
- package/dist/dark-plus-DnPTOHJQ.mjs +4 -0
- package/dist/dart-DWVGvPVl.mjs +3 -0
- package/dist/dax-CCVgOCrm.mjs +3 -0
- package/dist/desktop-BLG2KUib.mjs +3 -0
- package/dist/diff-CR6iDLhj.mjs +3 -0
- package/dist/docker-ByH34NvG.mjs +3 -0
- package/dist/dotenv-el5rplMn.mjs +3 -0
- package/dist/dracula-CpEdEQts.mjs +4 -0
- package/dist/dracula-soft-CZr0C0df.mjs +4 -0
- package/dist/dream-maker-DDljGJt4.mjs +3 -0
- package/dist/edge-no12TFHE.mjs +13 -0
- package/dist/editor/components.json +25 -0
- package/dist/editor/dist/assets/index-B0kdJwfN.js +11 -0
- package/dist/editor/dist/assets/index-CZwLh2NU.css +2 -0
- package/dist/editor/dist/index.html +25 -0
- package/dist/editor/index.html +24 -0
- package/dist/editor/package.json +35 -0
- package/dist/editor/src/app.tsx +82 -0
- package/dist/editor/src/comment-box.tsx +113 -0
- package/dist/editor/src/comment-list.tsx +118 -0
- package/dist/editor/src/comment-overlay.tsx +122 -0
- package/dist/editor/src/comment-state.tsx +120 -0
- package/dist/editor/src/comment-toggle.tsx +28 -0
- package/dist/editor/src/components/ui/button.tsx +58 -0
- package/dist/editor/src/components/ui/dialog.tsx +136 -0
- package/dist/editor/src/components/ui/popover.tsx +75 -0
- package/dist/editor/src/components/ui/sonner.tsx +21 -0
- package/dist/editor/src/components/ui/textarea.tsx +18 -0
- package/dist/editor/src/components/ui/tooltip.tsx +54 -0
- package/dist/editor/src/grep-source.ts +95 -0
- package/dist/editor/src/index.css +36 -0
- package/dist/editor/src/lib/utils.ts +6 -0
- package/dist/editor/src/main.tsx +10 -0
- package/dist/editor/src/mdx.d.ts +4 -0
- package/dist/editor/src/plan-list.tsx +42 -0
- package/dist/editor/src/plan-view.tsx +107 -0
- package/dist/editor/src/plannar.d.ts +6 -0
- package/dist/editor/src/prompt-dialog.tsx +61 -0
- package/dist/editor/src/sample.mdx +69 -0
- package/dist/editor/tsconfig.json +23 -0
- package/dist/editor/vite.config.ts +14 -0
- package/dist/editor/vite.shared.d.ts +12 -0
- package/dist/editor/vite.shared.ts +265 -0
- package/dist/editor-Bv5RTgcT.mjs +59 -0
- package/dist/elixir-SbOgBhDM.mjs +6 -0
- package/dist/elm-BRsMBjKT.mjs +6 -0
- package/dist/emacs-lisp-C8HQcRPk.mjs +3 -0
- package/dist/erb-C1_C5jep.mjs +11 -0
- package/dist/erlang-C5gFQJZg.mjs +6 -0
- package/dist/everforest-dark-BAMXVMpE.mjs +4 -0
- package/dist/everforest-light-C_EkXd7H.mjs +4 -0
- package/dist/export-BPZixWW4.mjs +59476 -0
- package/dist/fennel-BBDzQpxJ.mjs +3 -0
- package/dist/fish-BVKcOoo3.mjs +3 -0
- package/dist/fluent-CiEY0tx7.mjs +3 -0
- package/dist/fortran-fixed-form-DPiyERAR.mjs +6 -0
- package/dist/fortran-free-form-Dy4Ia3xC.mjs +3 -0
- package/dist/fsharp-BXAgfpA4.mjs +6 -0
- package/dist/gdresource-CRXhH7lA.mjs +11 -0
- package/dist/gdscript-DUk6d3qS.mjs +3 -0
- package/dist/gdshader-DJwZO-zm.mjs +3 -0
- package/dist/genie-B2jvDwB3.mjs +3 -0
- package/dist/gherkin-CFYsr5Em.mjs +3 -0
- package/dist/git-commit-Bb8y57z7.mjs +6 -0
- package/dist/git-rebase-BECFh1Cx.mjs +6 -0
- package/dist/github-dark-DvHYl2p7.mjs +4 -0
- package/dist/github-dark-default-MALL2Q4C.mjs +4 -0
- package/dist/github-dark-dimmed-CFzqRqSr.mjs +4 -0
- package/dist/github-dark-high-contrast-Be0PQ9D9.mjs +4 -0
- package/dist/github-light-B84bxdHo.mjs +4 -0
- package/dist/github-light-default-B49MFeR5.mjs +4 -0
- package/dist/github-light-high-contrast-B9ThWYcN.mjs +4 -0
- package/dist/gleam-B7e4lIXe.mjs +3 -0
- package/dist/glimmer-js-BxRSm1Iz.mjs +15 -0
- package/dist/glimmer-ts-B-PXhnA-.mjs +15 -0
- package/dist/glsl-DCpEHOoJ.mjs +8 -0
- package/dist/gn-oCpvJfaB.mjs +3 -0
- package/dist/gnuplot-DGkrsXyD.mjs +3 -0
- package/dist/go-DOBPmz4q.mjs +3 -0
- package/dist/graphql-KsWq5dbl.mjs +17 -0
- package/dist/groovy-JRvXAe6e.mjs +3 -0
- package/dist/gruvbox-dark-hard-DZtjD3-K.mjs +4 -0
- package/dist/gruvbox-dark-medium-CnvJvh1e.mjs +4 -0
- package/dist/gruvbox-dark-soft-DT7fdnlk.mjs +4 -0
- package/dist/gruvbox-light-hard-Z0yBUPTq.mjs +4 -0
- package/dist/gruvbox-light-medium-VcFR0ZPw.mjs +4 -0
- package/dist/gruvbox-light-soft-BjpMTObq.mjs +4 -0
- package/dist/hack-Dl36VvRT.mjs +11 -0
- package/dist/haml-CybNLmKL.mjs +13 -0
- package/dist/handlebars-CjcvRR6G.mjs +15 -0
- package/dist/haskell-9GVaCDAy.mjs +3 -0
- package/dist/haxe-BjwmQP6x.mjs +3 -0
- package/dist/hcl-CGDoStcp.mjs +3 -0
- package/dist/hjson-CH_gnwQd.mjs +3 -0
- package/dist/hlsl-ivzEgiy0.mjs +3 -0
- package/dist/horizon-BAPJOej1.mjs +4 -0
- package/dist/horizon-bright-CBbQxVuj.mjs +4 -0
- package/dist/houston-Bsel4WXn.mjs +4 -0
- package/dist/html-DfZ5CvWO.mjs +13 -0
- package/dist/html-derivative-Bl2uHcRG.mjs +6 -0
- package/dist/http-2GSJ1Ota.mjs +15 -0
- package/dist/hurl-BuTA3a1U.mjs +13 -0
- package/dist/hxml-CIJx3GAL.mjs +6 -0
- package/dist/hy-CFVRK0Nt.mjs +3 -0
- package/dist/imba-CpUXJ8TV.mjs +3 -0
- package/dist/ini-CdpG8IPX.mjs +3 -0
- package/dist/init-CK5HMoQf.mjs +228 -0
- package/dist/java-Dd2Sr4ei.mjs +6 -0
- package/dist/javascript-CZ7QJWaI.mjs +6 -0
- package/dist/jinja-rGuAaq8y.mjs +10 -0
- package/dist/jison-f_1eFoen.mjs +6 -0
- package/dist/json-ufdHUD6V.mjs +6 -0
- package/dist/json5-7RecBf2_.mjs +3 -0
- package/dist/jsonc-CBGnPf32.mjs +3 -0
- package/dist/jsonl-CmLQaM5O.mjs +3 -0
- package/dist/jsonnet-tXOQdkDx.mjs +3 -0
- package/dist/jssm-CtDTf-es.mjs +3 -0
- package/dist/jsx-BY17L1TJ.mjs +6 -0
- package/dist/julia-jv62bi7k.mjs +17 -0
- package/dist/just-C6qr4mXt.mjs +19 -0
- package/dist/kanagawa-dragon-BDtUi23j.mjs +4 -0
- package/dist/kanagawa-lotus-BBtsE-9U.mjs +4 -0
- package/dist/kanagawa-wave-DehP6Jw_.mjs +4 -0
- package/dist/kdl-DGaDNPP2.mjs +3 -0
- package/dist/kotlin-B10KLoOh.mjs +3 -0
- package/dist/kusto-iwa79TLz.mjs +3 -0
- package/dist/laserwave-oGyAE_TK.mjs +4 -0
- package/dist/latex-bq3Inh3R.mjs +6 -0
- package/dist/lean-CIMS95nW.mjs +3 -0
- package/dist/less-BmQG9s2A.mjs +3 -0
- package/dist/light-plus-BKYJg4pO.mjs +4 -0
- package/dist/liquid-BGg1u_N2.mjs +15 -0
- package/dist/llvm-D_R1tubu.mjs +3 -0
- package/dist/log-A1ddhKk2.mjs +3 -0
- package/dist/logo-CAINsCxc.mjs +3 -0
- package/dist/lua-Ctym3rMV.mjs +8 -0
- package/dist/luau-CAYz1b8d.mjs +3 -0
- package/dist/make-BoMd6Eg0.mjs +3 -0
- package/dist/markdown-q2UTVhPv.mjs +3 -0
- package/dist/marko-3VCDTT2m.mjs +15 -0
- package/dist/material-theme-B5VoDPKV.mjs +4 -0
- package/dist/material-theme-darker-B1HCXk1e.mjs +4 -0
- package/dist/material-theme-lighter-Cj_YmAmc.mjs +4 -0
- package/dist/material-theme-ocean-BaeR8VhB.mjs +4 -0
- package/dist/material-theme-palenight-DieYMRIR.mjs +4 -0
- package/dist/matlab-BmW78Ua4.mjs +3 -0
- package/dist/mdc-n4CFO8GD.mjs +13 -0
- package/dist/mdx-IgTZ_PsQ.mjs +3 -0
- package/dist/mermaid-D1WKgk1u.mjs +3 -0
- package/dist/min-dark-Da4XHK1C.mjs +4 -0
- package/dist/min-light-B1G-gK7R.mjs +4 -0
- package/dist/mipsasm-D__MkRT6.mjs +3 -0
- package/dist/mojo-CMCD6kSt.mjs +3 -0
- package/dist/monokai-Dja8c9XW.mjs +4 -0
- package/dist/moonbit-BmzABvgk.mjs +3 -0
- package/dist/move-CtOzYpc7.mjs +3 -0
- package/dist/narrat-C8ZM2zHi.mjs +3 -0
- package/dist/nextflow-BuXhAF6g.mjs +6 -0
- package/dist/nextflow-groovy-BucdoGBt.mjs +3 -0
- package/dist/nginx-DCav9fr2.mjs +6 -0
- package/dist/night-owl-CFEDim2c.mjs +4 -0
- package/dist/night-owl-light-BABXmJim.mjs +4 -0
- package/dist/nim-D9QPp5kW.mjs +21 -0
- package/dist/nix-_kfSRp5x.mjs +7 -0
- package/dist/nord-BEvLRKJz.mjs +4 -0
- package/dist/nushell-CG6WVreI.mjs +3 -0
- package/dist/objective-c-DOVmNqC4.mjs +3 -0
- package/dist/objective-cpp-BWlpWva0.mjs +3 -0
- package/dist/ocaml-Wwmuez2Q.mjs +3 -0
- package/dist/odin-ByfuPSu8.mjs +3 -0
- package/dist/one-dark-pro-CXLLrmxx.mjs +4 -0
- package/dist/one-light-1TrAkc9b.mjs +4 -0
- package/dist/openscad-CYYW-Lvy.mjs +3 -0
- package/dist/pascal-DlWtMFUC.mjs +3 -0
- package/dist/perl-F1w6BTW4.mjs +17 -0
- package/dist/php-D5RNc8cb.mjs +19 -0
- package/dist/pkl-BJSLmUc7.mjs +3 -0
- package/dist/plastic-BOdHQ7hi.mjs +4 -0
- package/dist/plsql-CtnOltln.mjs +3 -0
- package/dist/po-ChBiJtw3.mjs +3 -0
- package/dist/poimandres-sZlsXmSW.mjs +4 -0
- package/dist/polar-BRgTqojJ.mjs +3 -0
- package/dist/postcss-DAhKZdRf.mjs +3 -0
- package/dist/powerquery-BKTL9xfg.mjs +3 -0
- package/dist/powershell-BmCCV9e7.mjs +3 -0
- package/dist/prisma-C-mW5eQ1.mjs +3 -0
- package/dist/prolog-BG0_G0sz.mjs +3 -0
- package/dist/proto-Cjvlr4bQ.mjs +3 -0
- package/dist/pug-BoqONK6L.mjs +13 -0
- package/dist/puppet-CjFnVLMe.mjs +3 -0
- package/dist/purescript-Vb2OcJR8.mjs +3 -0
- package/dist/python-ARgqtcr9.mjs +3 -0
- package/dist/qml-CN98xHYu.mjs +6 -0
- package/dist/qmldir-BR3wWyS0.mjs +3 -0
- package/dist/qss-Baln5J4y.mjs +3 -0
- package/dist/r-CgkRbgWa.mjs +6 -0
- package/dist/racket-HuXCA8Np.mjs +3 -0
- package/dist/raku--XBLzYuF.mjs +3 -0
- package/dist/razor-D9GoeIvC.mjs +11 -0
- package/dist/red-DieXtVH2.mjs +4 -0
- package/dist/reg-N3tN4G1s.mjs +3 -0
- package/dist/regexp-Cmzs-b17.mjs +6 -0
- package/dist/registry-metadata/index.d.mts +40 -0
- package/dist/registry-metadata/index.mjs +163 -0
- package/dist/rel-BWA2fVVw.mjs +3 -0
- package/dist/riscv-CNsUL9F1.mjs +3 -0
- package/dist/ron-C_zPdle-.mjs +3 -0
- package/dist/rose-pine-NQGQN_Py.mjs +4 -0
- package/dist/rose-pine-dawn-CDEuRC-V.mjs +4 -0
- package/dist/rose-pine-moon-DN6_RPeE.mjs +4 -0
- package/dist/rosmsg-yiq-v07k.mjs +3 -0
- package/dist/rst-BMhVqyG1.mjs +23 -0
- package/dist/ruby-C7SejiSM.mjs +31 -0
- package/dist/rust-DYp2JQv-.mjs +3 -0
- package/dist/sas-CGU-Ko3q.mjs +6 -0
- package/dist/sass-DVKushYG.mjs +3 -0
- package/dist/scala-lpjTPFHX.mjs +3 -0
- package/dist/scheme-wOQJFUig.mjs +3 -0
- package/dist/scss-zkWWQrdN.mjs +8 -0
- package/dist/sdbl--PnDxzGT.mjs +3 -0
- package/dist/shaderlab-i7KCgReF.mjs +6 -0
- package/dist/shellscript-CaJ5viEZ.mjs +6 -0
- package/dist/shellsession-DuB7oTvQ.mjs +6 -0
- package/dist/slack-dark-6rIBdtCf.mjs +4 -0
- package/dist/slack-ochin-nUh4VZSG.mjs +4 -0
- package/dist/smalltalk-n_YRhdTv.mjs +3 -0
- package/dist/snazzy-light-DkuQw6Z-.mjs +4 -0
- package/dist/solarized-dark-DG_xfWAC.mjs +4 -0
- package/dist/solarized-light-CIcPm0uy.mjs +4 -0
- package/dist/solidity-BpTVGGR3.mjs +3 -0
- package/dist/soy-lf7Er5NU.mjs +6 -0
- package/dist/sparql-Bk-JyIQk.mjs +6 -0
- package/dist/splunk-D1Az7tvn.mjs +3 -0
- package/dist/sql-D1uCIb-4.mjs +6 -0
- package/dist/ssh-config-DAsGgEig.mjs +3 -0
- package/dist/stata-DenNw7ri.mjs +6 -0
- package/dist/status-gCBxoymh.mjs +97 -0
- package/dist/stylus-CNLem3u-.mjs +3 -0
- package/dist/surrealql-CCYzU3tm.mjs +6 -0
- package/dist/svelte-C36RW4eY.mjs +15 -0
- package/dist/swift-DAcVMcFy.mjs +3 -0
- package/dist/synthwave-84-gkUURId2.mjs +4 -0
- package/dist/system-verilog-CL1nVinO.mjs +3 -0
- package/dist/systemd-C7P5y8lI.mjs +3 -0
- package/dist/talonscript-BE-x9pgh.mjs +3 -0
- package/dist/tasl-C7s9745E.mjs +3 -0
- package/dist/tcl-BLsPJ7iC.mjs +3 -0
- package/dist/templ-Dte43-Eo.mjs +13 -0
- package/dist/terraform-v0Ek_rks.mjs +3 -0
- package/dist/tex-CRJxStv9.mjs +6 -0
- package/dist/tokyo-night-Oja5OrLi.mjs +4 -0
- package/dist/toml-wLAVRnMH.mjs +3 -0
- package/dist/ts-tags-Cs6jrN-1.mjs +59 -0
- package/dist/tsv-Qo5b4XGG.mjs +3 -0
- package/dist/tsx-CZnUd1jF.mjs +6 -0
- package/dist/turtle-Bo7XW2KG.mjs +3 -0
- package/dist/twig-A2qf0tKU.mjs +19 -0
- package/dist/typescript-DgW8lbMR.mjs +6 -0
- package/dist/typespec-DvXBeCkw.mjs +3 -0
- package/dist/typst-D73qYMMw.mjs +3 -0
- package/dist/v-CpO787mz.mjs +3 -0
- package/dist/vala-BqFlVoH_.mjs +3 -0
- package/dist/vb-Bo7BiOwD.mjs +3 -0
- package/dist/verilog-DABjKKO6.mjs +3 -0
- package/dist/vesper-tVhzEr-k.mjs +4 -0
- package/dist/vhdl-CB8TvDTZ.mjs +3 -0
- package/dist/viml-CuM98KEF.mjs +3 -0
- package/dist/vitesse-black-P6rRX5YD.mjs +4 -0
- package/dist/vitesse-dark-Di9MWjvq.mjs +4 -0
- package/dist/vitesse-light-ChosFYw8.mjs +4 -0
- package/dist/vue-BtFfPSdA.mjs +31 -0
- package/dist/vue-html-BIVhvoTt.mjs +6 -0
- package/dist/vue-vine-BRJbnPV0.mjs +19 -0
- package/dist/vyper-DYoGCYmu.mjs +3 -0
- package/dist/wasm-DhFUmAQm.mjs +7 -0
- package/dist/wasm-NKC9-wJ8.mjs +3 -0
- package/dist/wenyan-CCNBOs6Y.mjs +3 -0
- package/dist/wgsl-n1IZMc_u.mjs +3 -0
- package/dist/wikitext-5isXOJoG.mjs +3 -0
- package/dist/wit-BP1frIMq.mjs +3 -0
- package/dist/wolfram-e8E-o4Bx.mjs +3 -0
- package/dist/xml-czz4UX4-.mjs +8 -0
- package/dist/xsl-BL1DqGMX.mjs +6 -0
- package/dist/yaml-B2yUh7a5.mjs +6 -0
- package/dist/zenscript-kGsI2Rqh.mjs +3 -0
- package/dist/zig-C5f0bk_4.mjs +3 -0
- package/package.json +48 -0
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { createContext, useContext, useState, useCallback, type ReactNode } from "react";
|
|
2
|
+
import { toast } from "sonner";
|
|
3
|
+
|
|
4
|
+
export type CommentAnchor =
|
|
5
|
+
| { type: "text"; text: string }
|
|
6
|
+
| { type: "element"; tag: string; text: string };
|
|
7
|
+
|
|
8
|
+
export type Comment = {
|
|
9
|
+
id: string;
|
|
10
|
+
anchor: CommentAnchor;
|
|
11
|
+
content: string;
|
|
12
|
+
file: string;
|
|
13
|
+
line: number | null;
|
|
14
|
+
lineEnd: number | null;
|
|
15
|
+
timestamp: number;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
type CommentContextType = {
|
|
19
|
+
mode: boolean;
|
|
20
|
+
toggleMode: () => void;
|
|
21
|
+
comments: Comment[];
|
|
22
|
+
addComment: (
|
|
23
|
+
anchor: CommentAnchor,
|
|
24
|
+
content: string,
|
|
25
|
+
file: string,
|
|
26
|
+
line?: number,
|
|
27
|
+
lineEnd?: number,
|
|
28
|
+
) => void;
|
|
29
|
+
removeComment: (id: string) => void;
|
|
30
|
+
editComment: (id: string, content: string) => void;
|
|
31
|
+
clearComments: () => void;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const CommentContext = createContext<CommentContextType | null>(null);
|
|
35
|
+
|
|
36
|
+
let nextId = 0;
|
|
37
|
+
|
|
38
|
+
const TIP_TOAST_ID = "comment-tip";
|
|
39
|
+
const TIP_COOKIE = "plannar-comment-tip-seen";
|
|
40
|
+
|
|
41
|
+
function hasSeenTip(): boolean {
|
|
42
|
+
return document.cookie.includes(`${TIP_COOKIE}=1`);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function markTipSeen(): void {
|
|
46
|
+
document.cookie = `${TIP_COOKIE}=1; max-age=31536000; path=/; SameSite=Lax`;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function CommentProvider({ children }: { children: ReactNode }) {
|
|
50
|
+
const [mode, setMode] = useState(false);
|
|
51
|
+
const [comments, setComments] = useState<Comment[]>([]);
|
|
52
|
+
|
|
53
|
+
const toggleMode = useCallback(() => {
|
|
54
|
+
setMode((m) => {
|
|
55
|
+
const next = !m;
|
|
56
|
+
if (next) {
|
|
57
|
+
if (!hasSeenTip()) {
|
|
58
|
+
toast("Highlight text or click on a section to comment", {
|
|
59
|
+
id: TIP_TOAST_ID,
|
|
60
|
+
duration: Infinity,
|
|
61
|
+
dismissible: true,
|
|
62
|
+
onDismiss: markTipSeen,
|
|
63
|
+
onAutoClose: markTipSeen,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
} else {
|
|
67
|
+
toast.dismiss(TIP_TOAST_ID);
|
|
68
|
+
}
|
|
69
|
+
return next;
|
|
70
|
+
});
|
|
71
|
+
}, []);
|
|
72
|
+
|
|
73
|
+
const addComment = useCallback(
|
|
74
|
+
(anchor: CommentAnchor, content: string, file: string, line?: number, lineEnd?: number) => {
|
|
75
|
+
if (!content.trim()) return;
|
|
76
|
+
toast.dismiss(TIP_TOAST_ID);
|
|
77
|
+
const id = `comment-${++nextId}`;
|
|
78
|
+
setComments((prev) => [
|
|
79
|
+
...prev,
|
|
80
|
+
{
|
|
81
|
+
id,
|
|
82
|
+
anchor,
|
|
83
|
+
content: content.trim(),
|
|
84
|
+
file,
|
|
85
|
+
line: line ?? null,
|
|
86
|
+
lineEnd: lineEnd ?? null,
|
|
87
|
+
timestamp: Date.now(),
|
|
88
|
+
},
|
|
89
|
+
]);
|
|
90
|
+
return id;
|
|
91
|
+
},
|
|
92
|
+
[],
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
const removeComment = useCallback((id: string) => {
|
|
96
|
+
setComments((prev) => prev.filter((c) => c.id !== id));
|
|
97
|
+
}, []);
|
|
98
|
+
|
|
99
|
+
const editComment = useCallback((id: string, content: string) => {
|
|
100
|
+
setComments((prev) => prev.map((c) => (c.id === id ? { ...c, content: content.trim() } : c)));
|
|
101
|
+
}, []);
|
|
102
|
+
|
|
103
|
+
const clearComments = useCallback(() => {
|
|
104
|
+
setComments([]);
|
|
105
|
+
}, []);
|
|
106
|
+
|
|
107
|
+
return (
|
|
108
|
+
<CommentContext.Provider
|
|
109
|
+
value={{ mode, toggleMode, comments, addComment, removeComment, editComment, clearComments }}
|
|
110
|
+
>
|
|
111
|
+
{children}
|
|
112
|
+
</CommentContext.Provider>
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export function useCommentState(): CommentContextType {
|
|
117
|
+
const ctx = useContext(CommentContext);
|
|
118
|
+
if (!ctx) throw new Error("useCommentState must be used within CommentProvider");
|
|
119
|
+
return ctx;
|
|
120
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { MessageSquarePlus, MessageSquare } from "lucide-react";
|
|
2
|
+
import { useCommentState } from "./comment-state.js";
|
|
3
|
+
import { cn } from "./lib/utils.js";
|
|
4
|
+
|
|
5
|
+
export function CommentToggle() {
|
|
6
|
+
const { mode, toggleMode, comments } = useCommentState();
|
|
7
|
+
|
|
8
|
+
return (
|
|
9
|
+
<button
|
|
10
|
+
onClick={toggleMode}
|
|
11
|
+
title={mode ? "Exit comment mode" : "Enter comment mode"}
|
|
12
|
+
aria-label={mode ? "Exit comment mode" : "Enter comment mode"}
|
|
13
|
+
className={cn(
|
|
14
|
+
"fixed bottom-6 right-6 z-40 inline-flex size-10 items-center justify-center rounded-xl border bg-background shadow-lg transition-all hover:scale-105 active:scale-95",
|
|
15
|
+
mode
|
|
16
|
+
? "border-primary/40 bg-primary/10 text-primary ring-2 ring-primary/20"
|
|
17
|
+
: "border-border text-muted-foreground hover:text-foreground",
|
|
18
|
+
)}
|
|
19
|
+
>
|
|
20
|
+
{mode ? <MessageSquare className="size-4.5" /> : <MessageSquarePlus className="size-4.5" />}
|
|
21
|
+
{comments.length > 0 && (
|
|
22
|
+
<span className="absolute -right-1 -top-1 flex size-4 items-center justify-center rounded-full bg-primary text-[9px] font-bold text-primary-foreground">
|
|
23
|
+
{comments.length}
|
|
24
|
+
</span>
|
|
25
|
+
)}
|
|
26
|
+
</button>
|
|
27
|
+
);
|
|
28
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { Button as ButtonPrimitive } from "@base-ui/react/button";
|
|
2
|
+
import { cva, type VariantProps } from "class-variance-authority";
|
|
3
|
+
|
|
4
|
+
import { cn } from "../../lib/utils.js";
|
|
5
|
+
|
|
6
|
+
const buttonVariants = cva(
|
|
7
|
+
"group/button inline-flex shrink-0 items-center justify-center rounded-lg border border-transparent bg-clip-padding text-sm font-medium whitespace-nowrap transition-all outline-none select-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 active:not-aria-[haspopup]:translate-y-px disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
8
|
+
{
|
|
9
|
+
variants: {
|
|
10
|
+
variant: {
|
|
11
|
+
default: "bg-primary text-primary-foreground [a]:hover:bg-primary/80",
|
|
12
|
+
outline:
|
|
13
|
+
"border-border bg-background hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50",
|
|
14
|
+
secondary:
|
|
15
|
+
"bg-secondary text-secondary-foreground hover:bg-secondary/80 aria-expanded:bg-secondary aria-expanded:text-secondary-foreground",
|
|
16
|
+
ghost:
|
|
17
|
+
"hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:hover:bg-muted/50",
|
|
18
|
+
destructive:
|
|
19
|
+
"bg-destructive/10 text-destructive hover:bg-destructive/20 focus-visible:border-destructive/40 focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:hover:bg-destructive/30 dark:focus-visible:ring-destructive/40",
|
|
20
|
+
link: "text-primary underline-offset-4 hover:underline",
|
|
21
|
+
},
|
|
22
|
+
size: {
|
|
23
|
+
default:
|
|
24
|
+
"h-8 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2",
|
|
25
|
+
xs: "h-6 gap-1 rounded-[min(var(--radius-md),10px)] px-2 text-xs in-data-[slot=button-group]:rounded-lg has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3",
|
|
26
|
+
sm: "h-7 gap-1 rounded-[min(var(--radius-md),12px)] px-2.5 text-[0.8rem] in-data-[slot=button-group]:rounded-lg has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3.5",
|
|
27
|
+
lg: "h-9 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2",
|
|
28
|
+
icon: "size-8",
|
|
29
|
+
"icon-xs":
|
|
30
|
+
"size-6 rounded-[min(var(--radius-md),10px)] in-data-[slot=button-group]:rounded-lg [&_svg:not([class*='size-'])]:size-3",
|
|
31
|
+
"icon-sm":
|
|
32
|
+
"size-7 rounded-[min(var(--radius-md),12px)] in-data-[slot=button-group]:rounded-lg",
|
|
33
|
+
"icon-lg": "size-9",
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
defaultVariants: {
|
|
37
|
+
variant: "default",
|
|
38
|
+
size: "default",
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
function Button({
|
|
44
|
+
className,
|
|
45
|
+
variant = "default",
|
|
46
|
+
size = "default",
|
|
47
|
+
...props
|
|
48
|
+
}: ButtonPrimitive.Props & VariantProps<typeof buttonVariants>) {
|
|
49
|
+
return (
|
|
50
|
+
<ButtonPrimitive
|
|
51
|
+
data-slot="button"
|
|
52
|
+
className={cn(buttonVariants({ variant, size, className }))}
|
|
53
|
+
{...props}
|
|
54
|
+
/>
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export { Button, buttonVariants };
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { Dialog as DialogPrimitive } from "@base-ui/react/dialog";
|
|
3
|
+
|
|
4
|
+
import { cn } from "../../lib/utils.js";
|
|
5
|
+
import { Button } from "./button.js";
|
|
6
|
+
import { XIcon } from "lucide-react";
|
|
7
|
+
|
|
8
|
+
function Dialog({ ...props }: DialogPrimitive.Root.Props) {
|
|
9
|
+
return <DialogPrimitive.Root data-slot="dialog" {...props} />;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function DialogTrigger({ ...props }: DialogPrimitive.Trigger.Props) {
|
|
13
|
+
return <DialogPrimitive.Trigger data-slot="dialog-trigger" {...props} />;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function DialogPortal({ ...props }: DialogPrimitive.Portal.Props) {
|
|
17
|
+
return <DialogPrimitive.Portal data-slot="dialog-portal" {...props} />;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function DialogClose({ ...props }: DialogPrimitive.Close.Props) {
|
|
21
|
+
return <DialogPrimitive.Close data-slot="dialog-close" {...props} />;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function DialogOverlay({ className, ...props }: DialogPrimitive.Backdrop.Props) {
|
|
25
|
+
return (
|
|
26
|
+
<DialogPrimitive.Backdrop
|
|
27
|
+
data-slot="dialog-overlay"
|
|
28
|
+
className={cn(
|
|
29
|
+
"fixed inset-0 isolate z-50 bg-black/10 duration-100 supports-backdrop-filter:backdrop-blur-xs data-open:animate-in data-open:fade-in-0 data-closed:animate-out data-closed:fade-out-0",
|
|
30
|
+
className,
|
|
31
|
+
)}
|
|
32
|
+
{...props}
|
|
33
|
+
/>
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function DialogContent({
|
|
38
|
+
className,
|
|
39
|
+
children,
|
|
40
|
+
showCloseButton = true,
|
|
41
|
+
...props
|
|
42
|
+
}: DialogPrimitive.Popup.Props & {
|
|
43
|
+
showCloseButton?: boolean;
|
|
44
|
+
}) {
|
|
45
|
+
return (
|
|
46
|
+
<DialogPortal>
|
|
47
|
+
<DialogOverlay />
|
|
48
|
+
<DialogPrimitive.Popup
|
|
49
|
+
data-slot="dialog-content"
|
|
50
|
+
className={cn(
|
|
51
|
+
"fixed top-1/2 left-1/2 z-50 grid w-full max-w-[calc(100%-2rem)] -translate-x-1/2 -translate-y-1/2 gap-4 rounded-xl bg-popover p-4 text-sm text-popover-foreground ring-1 ring-foreground/10 duration-100 outline-none sm:max-w-sm data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
|
|
52
|
+
className,
|
|
53
|
+
)}
|
|
54
|
+
{...props}
|
|
55
|
+
>
|
|
56
|
+
{children}
|
|
57
|
+
{showCloseButton && (
|
|
58
|
+
<DialogPrimitive.Close
|
|
59
|
+
data-slot="dialog-close"
|
|
60
|
+
render={<Button variant="ghost" className="absolute top-2 right-2" size="icon-sm" />}
|
|
61
|
+
>
|
|
62
|
+
<XIcon />
|
|
63
|
+
<span className="sr-only">Close</span>
|
|
64
|
+
</DialogPrimitive.Close>
|
|
65
|
+
)}
|
|
66
|
+
</DialogPrimitive.Popup>
|
|
67
|
+
</DialogPortal>
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function DialogHeader({ className, ...props }: React.ComponentProps<"div">) {
|
|
72
|
+
return (
|
|
73
|
+
<div data-slot="dialog-header" className={cn("flex flex-col gap-2", className)} {...props} />
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function DialogFooter({
|
|
78
|
+
className,
|
|
79
|
+
showCloseButton = false,
|
|
80
|
+
children,
|
|
81
|
+
...props
|
|
82
|
+
}: React.ComponentProps<"div"> & {
|
|
83
|
+
showCloseButton?: boolean;
|
|
84
|
+
}) {
|
|
85
|
+
return (
|
|
86
|
+
<div
|
|
87
|
+
data-slot="dialog-footer"
|
|
88
|
+
className={cn(
|
|
89
|
+
"-mx-4 -mb-4 flex flex-col-reverse gap-2 rounded-b-xl border-t bg-muted/50 p-4 sm:flex-row sm:justify-end",
|
|
90
|
+
className,
|
|
91
|
+
)}
|
|
92
|
+
{...props}
|
|
93
|
+
>
|
|
94
|
+
{children}
|
|
95
|
+
{showCloseButton && (
|
|
96
|
+
<DialogPrimitive.Close render={<Button variant="outline" />}>Close</DialogPrimitive.Close>
|
|
97
|
+
)}
|
|
98
|
+
</div>
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function DialogTitle({ className, ...props }: DialogPrimitive.Title.Props) {
|
|
103
|
+
return (
|
|
104
|
+
<DialogPrimitive.Title
|
|
105
|
+
data-slot="dialog-title"
|
|
106
|
+
className={cn("text-base leading-none font-medium", className)}
|
|
107
|
+
{...props}
|
|
108
|
+
/>
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function DialogDescription({ className, ...props }: DialogPrimitive.Description.Props) {
|
|
113
|
+
return (
|
|
114
|
+
<DialogPrimitive.Description
|
|
115
|
+
data-slot="dialog-description"
|
|
116
|
+
className={cn(
|
|
117
|
+
"text-sm text-muted-foreground *:[a]:underline *:[a]:underline-offset-3 *:[a]:hover:text-foreground",
|
|
118
|
+
className,
|
|
119
|
+
)}
|
|
120
|
+
{...props}
|
|
121
|
+
/>
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export {
|
|
126
|
+
Dialog,
|
|
127
|
+
DialogClose,
|
|
128
|
+
DialogContent,
|
|
129
|
+
DialogDescription,
|
|
130
|
+
DialogFooter,
|
|
131
|
+
DialogHeader,
|
|
132
|
+
DialogOverlay,
|
|
133
|
+
DialogPortal,
|
|
134
|
+
DialogTitle,
|
|
135
|
+
DialogTrigger,
|
|
136
|
+
};
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { Popover as PopoverPrimitive } from "@base-ui/react/popover";
|
|
3
|
+
|
|
4
|
+
import { cn } from "../../lib/utils.js";
|
|
5
|
+
|
|
6
|
+
function Popover({ ...props }: PopoverPrimitive.Root.Props) {
|
|
7
|
+
return <PopoverPrimitive.Root data-slot="popover" {...props} />;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function PopoverTrigger({ ...props }: PopoverPrimitive.Trigger.Props) {
|
|
11
|
+
return <PopoverPrimitive.Trigger data-slot="popover-trigger" {...props} />;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function PopoverContent({
|
|
15
|
+
className,
|
|
16
|
+
align = "center",
|
|
17
|
+
alignOffset = 0,
|
|
18
|
+
side = "bottom",
|
|
19
|
+
sideOffset = 4,
|
|
20
|
+
...props
|
|
21
|
+
}: PopoverPrimitive.Popup.Props &
|
|
22
|
+
Pick<PopoverPrimitive.Positioner.Props, "align" | "alignOffset" | "side" | "sideOffset">) {
|
|
23
|
+
return (
|
|
24
|
+
<PopoverPrimitive.Portal>
|
|
25
|
+
<PopoverPrimitive.Positioner
|
|
26
|
+
align={align}
|
|
27
|
+
alignOffset={alignOffset}
|
|
28
|
+
side={side}
|
|
29
|
+
sideOffset={sideOffset}
|
|
30
|
+
className="isolate z-50"
|
|
31
|
+
>
|
|
32
|
+
<PopoverPrimitive.Popup
|
|
33
|
+
data-slot="popover-content"
|
|
34
|
+
className={cn(
|
|
35
|
+
"z-50 flex w-72 origin-(--transform-origin) flex-col gap-2.5 rounded-lg bg-popover p-2.5 text-sm text-popover-foreground shadow-md ring-1 ring-foreground/10 outline-hidden duration-100 data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
|
|
36
|
+
className,
|
|
37
|
+
)}
|
|
38
|
+
{...props}
|
|
39
|
+
/>
|
|
40
|
+
</PopoverPrimitive.Positioner>
|
|
41
|
+
</PopoverPrimitive.Portal>
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function PopoverHeader({ className, ...props }: React.ComponentProps<"div">) {
|
|
46
|
+
return (
|
|
47
|
+
<div
|
|
48
|
+
data-slot="popover-header"
|
|
49
|
+
className={cn("flex flex-col gap-0.5 text-sm", className)}
|
|
50
|
+
{...props}
|
|
51
|
+
/>
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function PopoverTitle({ className, ...props }: PopoverPrimitive.Title.Props) {
|
|
56
|
+
return (
|
|
57
|
+
<PopoverPrimitive.Title
|
|
58
|
+
data-slot="popover-title"
|
|
59
|
+
className={cn("font-medium", className)}
|
|
60
|
+
{...props}
|
|
61
|
+
/>
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function PopoverDescription({ className, ...props }: PopoverPrimitive.Description.Props) {
|
|
66
|
+
return (
|
|
67
|
+
<PopoverPrimitive.Description
|
|
68
|
+
data-slot="popover-description"
|
|
69
|
+
className={cn("text-muted-foreground", className)}
|
|
70
|
+
{...props}
|
|
71
|
+
/>
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export { Popover, PopoverContent, PopoverDescription, PopoverHeader, PopoverTitle, PopoverTrigger };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Toaster as Sonner, type ToasterProps } from "sonner";
|
|
2
|
+
|
|
3
|
+
const Toaster = ({ ...props }: ToasterProps) => {
|
|
4
|
+
return (
|
|
5
|
+
<Sonner
|
|
6
|
+
position="bottom-left"
|
|
7
|
+
className="toaster group"
|
|
8
|
+
style={
|
|
9
|
+
{
|
|
10
|
+
"--normal-bg": "var(--popover)",
|
|
11
|
+
"--normal-text": "var(--popover-foreground)",
|
|
12
|
+
"--normal-border": "var(--border)",
|
|
13
|
+
"--border-radius": "var(--radius)",
|
|
14
|
+
} as React.CSSProperties
|
|
15
|
+
}
|
|
16
|
+
{...props}
|
|
17
|
+
/>
|
|
18
|
+
);
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export { Toaster };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
|
|
3
|
+
import { cn } from "../../lib/utils.js";
|
|
4
|
+
|
|
5
|
+
function Textarea({ className, ...props }: React.ComponentProps<"textarea">) {
|
|
6
|
+
return (
|
|
7
|
+
<textarea
|
|
8
|
+
data-slot="textarea"
|
|
9
|
+
className={cn(
|
|
10
|
+
"flex field-sizing-content min-h-16 w-full rounded-lg border border-input bg-transparent px-2.5 py-2 text-base transition-colors outline-none placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:bg-input/50 disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 md:text-sm dark:bg-input/30 dark:disabled:bg-input/80 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40",
|
|
11
|
+
className,
|
|
12
|
+
)}
|
|
13
|
+
{...props}
|
|
14
|
+
/>
|
|
15
|
+
);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export { Textarea };
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { Tooltip as TooltipPrimitive } from "@base-ui/react/tooltip";
|
|
4
|
+
|
|
5
|
+
import { cn } from "../../lib/utils.js";
|
|
6
|
+
|
|
7
|
+
function TooltipProvider({ delay = 0, ...props }: TooltipPrimitive.Provider.Props) {
|
|
8
|
+
return <TooltipPrimitive.Provider data-slot="tooltip-provider" delay={delay} {...props} />;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function Tooltip({ ...props }: TooltipPrimitive.Root.Props) {
|
|
12
|
+
return <TooltipPrimitive.Root data-slot="tooltip" {...props} />;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function TooltipTrigger({ ...props }: TooltipPrimitive.Trigger.Props) {
|
|
16
|
+
return <TooltipPrimitive.Trigger data-slot="tooltip-trigger" {...props} />;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function TooltipContent({
|
|
20
|
+
className,
|
|
21
|
+
side = "top",
|
|
22
|
+
sideOffset = 4,
|
|
23
|
+
align = "center",
|
|
24
|
+
alignOffset = 0,
|
|
25
|
+
children,
|
|
26
|
+
...props
|
|
27
|
+
}: TooltipPrimitive.Popup.Props &
|
|
28
|
+
Pick<TooltipPrimitive.Positioner.Props, "align" | "alignOffset" | "side" | "sideOffset">) {
|
|
29
|
+
return (
|
|
30
|
+
<TooltipPrimitive.Portal>
|
|
31
|
+
<TooltipPrimitive.Positioner
|
|
32
|
+
align={align}
|
|
33
|
+
alignOffset={alignOffset}
|
|
34
|
+
side={side}
|
|
35
|
+
sideOffset={sideOffset}
|
|
36
|
+
className="isolate z-50"
|
|
37
|
+
>
|
|
38
|
+
<TooltipPrimitive.Popup
|
|
39
|
+
data-slot="tooltip-content"
|
|
40
|
+
className={cn(
|
|
41
|
+
"z-50 inline-flex w-fit max-w-xs origin-(--transform-origin) items-center gap-1.5 rounded-md bg-foreground px-3 py-1.5 text-xs text-background has-data-[slot=kbd]:pr-1.5 data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 **:data-[slot=kbd]:relative **:data-[slot=kbd]:isolate **:data-[slot=kbd]:z-50 **:data-[slot=kbd]:rounded-sm data-[state=delayed-open]:animate-in data-[state=delayed-open]:fade-in-0 data-[state=delayed-open]:zoom-in-95 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
|
|
42
|
+
className,
|
|
43
|
+
)}
|
|
44
|
+
{...props}
|
|
45
|
+
>
|
|
46
|
+
{children}
|
|
47
|
+
<TooltipPrimitive.Arrow className="z-50 size-2.5 translate-y-[calc(-50%-2px)] rotate-45 rounded-[2px] bg-foreground fill-foreground data-[side=bottom]:top-1 data-[side=inline-end]:top-1/2! data-[side=inline-end]:-left-1 data-[side=inline-end]:-translate-y-1/2 data-[side=inline-start]:top-1/2! data-[side=inline-start]:-right-1 data-[side=inline-start]:-translate-y-1/2 data-[side=left]:top-1/2! data-[side=left]:-right-1 data-[side=left]:-translate-y-1/2 data-[side=right]:top-1/2! data-[side=right]:-left-1 data-[side=right]:-translate-y-1/2 data-[side=top]:-bottom-2.5" />
|
|
48
|
+
</TooltipPrimitive.Popup>
|
|
49
|
+
</TooltipPrimitive.Positioner>
|
|
50
|
+
</TooltipPrimitive.Portal>
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import type { CommentAnchor } from "./comment-state.js";
|
|
2
|
+
|
|
3
|
+
export type PlanSource = {
|
|
4
|
+
source: string;
|
|
5
|
+
lines: string[];
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
export function findLineRange(
|
|
9
|
+
anchor: CommentAnchor,
|
|
10
|
+
source: PlanSource,
|
|
11
|
+
): { start: number; end: number } | null {
|
|
12
|
+
if (!source.lines.length) return null;
|
|
13
|
+
const search = anchor.text.replace(/\s+/g, " ").trim();
|
|
14
|
+
if (!search) return null;
|
|
15
|
+
|
|
16
|
+
let startLine: number | null = null;
|
|
17
|
+
|
|
18
|
+
for (let i = 0; i < source.lines.length; i++) {
|
|
19
|
+
const lineClean = source.lines[i].replace(/\s+/g, " ").trim();
|
|
20
|
+
if (lineClean.includes(search)) {
|
|
21
|
+
startLine = i + 1;
|
|
22
|
+
break;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (startLine === null) {
|
|
27
|
+
const words = search.split(/\s+/).filter((w) => w.length > 2);
|
|
28
|
+
for (let i = 0; i < source.lines.length; i++) {
|
|
29
|
+
const lineClean = source.lines[i].replace(/\s+/g, " ").trim();
|
|
30
|
+
const matchCount = words.filter((w) =>
|
|
31
|
+
lineClean.toLowerCase().includes(w.toLowerCase()),
|
|
32
|
+
).length;
|
|
33
|
+
if (matchCount >= Math.ceil(words.length / 2)) {
|
|
34
|
+
startLine = i + 1;
|
|
35
|
+
break;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
if (startLine === null) return null;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (anchor.type === "text") {
|
|
42
|
+
return { start: startLine, end: startLine };
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const headingLevel = getHeadingLevel(source.lines[startLine - 1]);
|
|
46
|
+
if (headingLevel === 0) return { start: startLine, end: startLine };
|
|
47
|
+
|
|
48
|
+
let endLine = source.lines.length;
|
|
49
|
+
for (let i = startLine; i < source.lines.length; i++) {
|
|
50
|
+
const level = getHeadingLevel(source.lines[i]);
|
|
51
|
+
if (level > 0 && level <= headingLevel) {
|
|
52
|
+
endLine = i;
|
|
53
|
+
break;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return { start: startLine, end: endLine };
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function getHeadingLevel(line: string): number {
|
|
61
|
+
const match = line.match(/^(#{1,6})\s/);
|
|
62
|
+
return match ? match[1].length : 0;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function generatePrompt(
|
|
66
|
+
comments: {
|
|
67
|
+
anchor: CommentAnchor;
|
|
68
|
+
content: string;
|
|
69
|
+
file: string;
|
|
70
|
+
line: number | null;
|
|
71
|
+
lineEnd: number | null;
|
|
72
|
+
}[],
|
|
73
|
+
): string {
|
|
74
|
+
const sorted = [...comments].sort((a, b) => (a.line ?? Infinity) - (b.line ?? Infinity));
|
|
75
|
+
if (sorted.length === 0) return "";
|
|
76
|
+
|
|
77
|
+
let prompt = "The user left the following comments for you to address:\n\n";
|
|
78
|
+
for (const c of sorted) {
|
|
79
|
+
const loc = formatLoc(c);
|
|
80
|
+
const quoted = truncateContext(c.anchor);
|
|
81
|
+
prompt += `${loc}: "${quoted}" — ${c.content}\n`;
|
|
82
|
+
}
|
|
83
|
+
return prompt.trimEnd();
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function formatLoc(c: { file: string; line: number | null; lineEnd: number | null }): string {
|
|
87
|
+
if (!c.line) return c.file;
|
|
88
|
+
if (c.lineEnd && c.lineEnd > c.line) return `lines ${c.line}-${c.lineEnd} ${c.file}`;
|
|
89
|
+
return `line ${c.line} ${c.file}`;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function truncateContext(anchor: CommentAnchor): string {
|
|
93
|
+
const cleaned = anchor.text.replace(/\s+/g, " ").trim();
|
|
94
|
+
return cleaned.length > 80 ? cleaned.slice(0, 77) + "..." : cleaned;
|
|
95
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
@import "tailwindcss";
|
|
2
|
+
@import "tw-animate-css";
|
|
3
|
+
@import "../../core-styles/theme.css";
|
|
4
|
+
|
|
5
|
+
@custom-variant dark (&:is(.dark *));
|
|
6
|
+
|
|
7
|
+
@theme inline {
|
|
8
|
+
--color-background: var(--background);
|
|
9
|
+
--color-foreground: var(--foreground);
|
|
10
|
+
--color-card: var(--card);
|
|
11
|
+
--color-card-foreground: var(--card-foreground);
|
|
12
|
+
--color-popover: var(--popover);
|
|
13
|
+
--color-popover-foreground: var(--popover-foreground);
|
|
14
|
+
--color-primary: var(--primary);
|
|
15
|
+
--color-primary-foreground: var(--primary-foreground);
|
|
16
|
+
--color-secondary: var(--secondary);
|
|
17
|
+
--color-secondary-foreground: var(--secondary-foreground);
|
|
18
|
+
--color-muted: var(--muted);
|
|
19
|
+
--color-muted-foreground: var(--muted-foreground);
|
|
20
|
+
--color-accent: var(--accent);
|
|
21
|
+
--color-accent-foreground: var(--accent-foreground);
|
|
22
|
+
--color-destructive: var(--destructive);
|
|
23
|
+
--color-destructive-foreground: var(--destructive-foreground);
|
|
24
|
+
--color-border: var(--border);
|
|
25
|
+
--color-input: var(--input);
|
|
26
|
+
--color-ring: var(--ring);
|
|
27
|
+
--color-chart-1: var(--chart-1);
|
|
28
|
+
--color-chart-2: var(--chart-2);
|
|
29
|
+
--color-chart-3: var(--chart-3);
|
|
30
|
+
--color-chart-4: var(--chart-4);
|
|
31
|
+
--color-chart-5: var(--chart-5);
|
|
32
|
+
--radius-sm: calc(var(--radius) - 4px);
|
|
33
|
+
--radius-md: calc(var(--radius) - 2px);
|
|
34
|
+
--radius-lg: var(--radius);
|
|
35
|
+
--radius-xl: calc(var(--radius) + 4px);
|
|
36
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import "./index.css";
|
|
2
|
+
import "../../core-styles/mdx.css";
|
|
3
|
+
import "virtual:plannar-global-css";
|
|
4
|
+
import { createRoot } from "react-dom/client";
|
|
5
|
+
import { App } from "./app.js";
|
|
6
|
+
|
|
7
|
+
const root = document.getElementById("root");
|
|
8
|
+
if (root) {
|
|
9
|
+
createRoot(root).render(<App />);
|
|
10
|
+
}
|