@dendelion/paper-camp 0.22.0 → 0.23.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/app/assets/{index-DxnAxo8U.js → index-B0T4zOOc.js} +2 -2
- package/dist/app/assets/{index-DxnAxo8U.js.map → index-B0T4zOOc.js.map} +1 -1
- package/dist/app/assets/{index-CDlMKeg5.js → index-CFMhKXQf.js} +2 -2
- package/dist/app/assets/{index-CDlMKeg5.js.map → index-CFMhKXQf.js.map} +1 -1
- package/dist/app/assets/{index-jxEIOkqg.js → index-CKO_a_mt.js} +2 -2
- package/dist/app/assets/{index-jxEIOkqg.js.map → index-CKO_a_mt.js.map} +1 -1
- package/dist/app/assets/{index-BzD-BgRl.js → index-CTHTRX-O.js} +2 -2
- package/dist/app/assets/{index-BzD-BgRl.js.map → index-CTHTRX-O.js.map} +1 -1
- package/dist/app/assets/{index-UOItJyt3.js → index-CeEpQji6.js} +2 -2
- package/dist/app/assets/{index-UOItJyt3.js.map → index-CeEpQji6.js.map} +1 -1
- package/dist/app/assets/{index-DgEJTUYT.js → index-DC_F8eQU.js} +2 -2
- package/dist/app/assets/{index-DgEJTUYT.js.map → index-DC_F8eQU.js.map} +1 -1
- package/dist/app/assets/{index-BS3GyKvd.js → index-DoH_Ktpt.js} +2 -2
- package/dist/app/assets/{index-BS3GyKvd.js.map → index-DoH_Ktpt.js.map} +1 -1
- package/dist/app/assets/{index-Bkouj3B7.js → index-Twqzhu_o.js} +2 -2
- package/dist/app/assets/{index-Bkouj3B7.js.map → index-Twqzhu_o.js.map} +1 -1
- package/dist/app/assets/{main-DEUaro51.css → main-BAlJ6w7u.css} +1 -1
- package/dist/app/assets/{main-BPr1R-3E.js → main-CDkrPxrg.js} +106 -106
- package/dist/app/assets/main-CDkrPxrg.js.map +1 -0
- package/dist/app/assets/{sidebar-section-CVvP-dC0.js → sidebar-section-7T-4hlR4.js} +2 -2
- package/dist/app/assets/{sidebar-section-CVvP-dC0.js.map → sidebar-section-7T-4hlR4.js.map} +1 -1
- package/dist/app/index.html +2 -2
- package/dist/cli/index.js +1781 -1731
- package/dist/cli/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/app/assets/main-BPr1R-3E.js.map +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{u as b,G as L,E as D,r as j,H as M,I as B,K as F,L as G,j as e,N as T,v as H,i as A,J as y,O as U,q,C as V,Q as $,S as J,R as O,M as z,T as K,g as R,U as _,V as N,P as w,p as E}from"./main-
|
|
1
|
+
import{u as b,G as L,E as D,r as j,H as M,I as B,K as F,L as G,j as e,N as T,v as H,i as A,J as y,O as U,q,C as V,Q as $,S as J,R as O,M as z,T as K,g as R,U as _,V as N,P as w,p as E}from"./main-CDkrPxrg.js";import{W as je}from"./main-CDkrPxrg.js";const W=()=>{const s=b(n=>n.roadmap),t=b(n=>n.roadmapError),o=b(n=>n.loadRoadmap),i=b(n=>n.roadmapFilters),a=b(n=>n.plans),m=L(),{item:l}=D({from:"/roadmap"}),u=j.useRef(null),[d,h]=j.useState(null);j.useEffect(()=>{o()},[o]),j.useEffect(()=>{var x;if(!l||!s)return;const n=(x=u.current)==null?void 0:x.querySelector(".roadmap-item-highlighted");n==null||n.scrollIntoView({behavior:"smooth",block:"center"})},[l,s]);const f=n=>(a==null?void 0:a.entries.filter(x=>x.subject===n.name))??[],r=async(n,x,S)=>{await B(n,x,S),await o()},c=(n,x,S)=>{h({horizonTitle:n,item:x,candidateName:S})},p=s?M(s,i):[],g=p.reduce((n,x)=>n+x.items.length,0),v=i.horizons.length>0||i.statuses.length>0;return{roadmap:s,roadmapError:t,loadRoadmap:o,horizons:p,totalVisible:g,hasActiveFilters:v,highlightedItem:l,containerRef:u,promoting:d,setPromoting:h,graduatedByItem:f,handleAddCandidate:r,handlePromote:c,onOpenGraduated:m}},Q=["in-progress","review","planned","idea","done","dropped"],Z=()=>{const s=b(c=>c.roadmap),t=b(c=>c.roadmapFilters),o=b(c=>c.toggleRoadmapHorizon),i=b(c=>c.toggleRoadmapStatus),[a,m]=j.useState(!1),l=(s==null?void 0:s.horizons.map(c=>c.title))??[],u=s?F(s,t):{},d=s?G(s,t):{},h=new Set(t.horizons),f=new Set(t.statuses),r=Q.filter(c=>(d[c]??0)>0||f.has(c));return{roadmap:s,horizonTitles:l,horizonCounts:u,statusCounts:d,activeHorizons:h,activeStatuses:f,visibleStatuses:r,addOpen:a,setAddOpen:m,toggleRoadmapHorizon:o,toggleRoadmapStatus:i}},X=({open:s,horizonTitles:t,onClose:o})=>{const i=b(n=>n.loadRoadmap),[a,m]=j.useState(t[0]??""),[l,u]=j.useState(""),[d,h]=j.useState(""),[f,r]=j.useState(!1),[c,p]=j.useState(null),g=j.useRef(t);g.current=t,j.useEffect(()=>{s&&(m(g.current[0]??""),u(""),h(""),p(null),r(!1))},[s]);const v=async()=>{if(!(!l.trim()||!a)){r(!0),p(null);try{await U(a,l.trim(),d.trim()),await i(),o()}catch(n){p(n.message)}finally{r(!1)}}};return e.jsx(T,{open:s,onClose:o,title:"Add roadmap item",size:"small",children:e.jsxs("div",{className:"flex flex-col gap-4",children:[e.jsx(H,{size:"small",value:a,onChange:m,disabled:f,options:t.map(n=>({value:n,label:n}))}),e.jsx(A,{size:"small",value:l,onChange:n=>u(n.target.value),placeholder:"Item name…",disabled:f,autoFocus:!0}),e.jsx(A,{size:"small",value:d,onChange:n=>h(n.target.value),onKeyDown:n=>{n.key==="Enter"&&v()},placeholder:"Description…",disabled:f}),c&&e.jsx("p",{className:"m-0 text-watercolor-rose-dark text-sm",children:c}),e.jsxs("div",{className:"flex justify-end gap-2",children:[e.jsx(y,{type:"button",variant:"ghost",onClick:o,disabled:f,children:"Cancel"}),e.jsx(y,{type:"button",variant:"primary",onClick:v,disabled:f||!l.trim()||!a,children:f?"Adding…":"Add item"})]})]})})},C="__no-subject__",Y=({horizonTitle:s,item:t,candidateName:o,onClose:i,onPromoted:a})=>{const m=b(x=>x.promoteRoadmapItem),l=b(x=>x.launchIdeaExtend),{subjects:u,available:d}=q(),[h,f]=j.useState(C),[r,c]=j.useState(!1),[p,g]=j.useState(null),{toast:v}=V();j.useEffect(()=>{t&&(f(o?t.name:C),c(!1),g(null))},[t,o]);const n=async()=>{if(!(!t||!s)){c(!0),g(null);try{const x=await m(s,t,h===C?void 0:h,o??void 0),S=b.getState().ideaEntries.find(k=>k.id===x);if(S)try{await l(x,$(S,s))}catch(k){v({title:"Idea created, but the refine agent failed to launch",description:J(k.message),variant:"error"})}a(),i()}catch(x){g(x.message)}finally{c(!1)}}};return e.jsx(T,{open:t!==null,onClose:i,title:o??(t==null?void 0:t.name)??"",size:"small",children:e.jsxs("div",{className:"flex flex-col gap-4",children:[!o&&e.jsx("p",{className:"m-0 opacity-80",children:t==null?void 0:t.description}),e.jsx("div",{children:e.jsx(H,{size:"small",value:h,onChange:f,disabled:r||!d,options:[{value:C,label:"No subject"},...!d&&h!==C?[{value:h,label:h}]:[],...u.map(x=>({value:x,label:x}))]})}),p&&e.jsx("p",{className:"m-0 text-watercolor-rose-dark text-sm",children:p}),e.jsxs("div",{className:"flex justify-end gap-2",children:[e.jsx(y,{type:"button",variant:"ghost",onClick:i,disabled:r,children:"Cancel"}),e.jsx(y,{type:"button",variant:"primary",onClick:n,disabled:r,children:r?"Promoting…":"Promote to idea"})]})]})})},ee=({onAdd:s})=>{const[t,o]=j.useState(""),[i,a]=j.useState(!1),m=async()=>{if(t.trim()){a(!0);try{await s(t.trim()),o("")}finally{a(!1)}}};return e.jsxs("div",{className:"flex gap-2",children:[e.jsx(A,{size:"small",value:t,onChange:l=>o(l.target.value),onKeyDown:l=>{l.key==="Enter"&&m()},placeholder:"Add option…",disabled:i,className:"flex-1"}),e.jsx(y,{type:"button",variant:"ghost",size:"small",onClick:m,disabled:i||!t.trim(),children:"Add"})]})},se=({name:s,onPromote:t})=>e.jsx(O,{size:"small",texture:"kraft",className:"plan-row-card",children:e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("span",{className:"flex-1",children:s}),e.jsx(y,{type:"button",variant:"ghost",size:"small",onClick:t,children:"Promote to idea"})]})}),te=({goal:s})=>{const[t,o]=j.useState(!1),[i,...a]=s.split(/\n{2,}/),m=a.length>0;return e.jsxs("div",{className:"mb-6 pb-4 border-b border-black/[8%]",children:[e.jsx("span",{className:"font-handwritten text-xs font-semibold opacity-[0.55]",children:"The goal"}),e.jsxs("div",{className:"text-sm leading-relaxed opacity-80 mt-2",children:[e.jsx(z,{children:i}),t&&m&&e.jsx(z,{children:a.join(`
|
|
2
2
|
|
|
3
3
|
`)})]}),m&&e.jsx("button",{type:"button",onClick:()=>o(l=>!l),className:"bg-transparent border-none p-0 mt-2 cursor-pointer text-2xs opacity-[0.65] underline",children:t?"Show less":"Show more"})]})},ae="outline-[rgba(200,154,90,0.5)]",I={fill:"rgba(0, 0, 0, 0.06)",text:"rgba(0, 0, 0, 0.55)"},ne=(s,t)=>{const o=new Set,i=t.map(a=>(a.id&&o.add(a.id),a.idea&&o.add(a.idea),{key:a.title,label:a.title,status:a.status,pr:a.pr,planId:a.id,planTitle:a.title}));for(const a of s)o.has(a.id)||i.push({key:a.id,label:a.id,status:a.status,pr:a.pr});return i},oe=({idea:s,onOpen:t})=>e.jsx(O,{size:"small",texture:"kraft",className:"plan-row-card",children:e.jsxs("div",{className:"flex items-center gap-3",children:[t?e.jsx("button",{type:"button",onClick:t,className:"flex-1 min-w-0 overflow-hidden text-ellipsis whitespace-nowrap bg-transparent border-none p-0 cursor-pointer [font:inherit] text-inherit text-left",children:s.label}):e.jsx("span",{className:"flex-1 min-w-0 overflow-hidden text-ellipsis whitespace-nowrap",children:s.label}),s.pr&&e.jsx(K,{pr:s.pr}),e.jsx(R,{size:"small",fillColor:N[s.status].fill,textColor:N[s.status].text,children:_[s.status]})]})}),le=({done:s,total:t})=>{const o=t>0?Math.round(s/t*100):0;return e.jsx("div",{className:"w-24 h-1.5 rounded-full bg-black/[0.08] overflow-hidden shrink-0",children:e.jsx("div",{className:`h-full rounded-full ${t>0?"bg-watercolor-green":"bg-transparent"}`,style:{width:`${o}%`}})})},re=s=>({shipped:s.filter(t=>t.status==="done").length,queued:s.filter(t=>t.status!=="done"&&t.status!=="dropped").length}),ie=({size:s=14})=>e.jsx("svg",{width:s,height:s,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round","aria-hidden":"true",children:e.jsx("polyline",{points:"9 18 15 12 9 6"})}),de=({item:s,graduated:t,highlighted:o,onPromote:i,onPromoteCandidate:a,onAddCandidate:m,onOpenGraduated:l})=>{const[u,d]=j.useState(o),{shipped:h,queued:f}=re(t),r=s.candidates.length,c=ne(s.links,t);return j.useEffect(()=>{o&&d(!0)},[o]),e.jsxs("div",{className:`border-b border-black/10 last:border-b-0 ${o?`roadmap-item-highlighted outline outline-2 outline-offset-[-2px] ${ae}`:""}`,children:[e.jsxs("button",{type:"button","aria-expanded":u,onClick:()=>d(p=>!p),className:"flex w-full items-center gap-3 py-2.5 px-0 bg-transparent border-none cursor-pointer text-left [font:inherit] text-inherit",children:[e.jsx("span",{className:`inline-flex items-center opacity-50 shrink-0 ${u?"rotate-90":""}`,children:e.jsx(ie,{})}),e.jsx("span",{className:"font-semibold flex-1 min-w-0 truncate",children:s.name}),e.jsx(le,{done:s.rollup.done,total:s.rollup.total}),f>0&&e.jsxs(R,{size:"small",fillColor:N.planned.fill,textColor:N.planned.text,children:[f," in queue"]}),h>0&&e.jsxs(R,{size:"small",fillColor:N.done.fill,textColor:N.done.text,children:[h," shipped"]}),r>0&&e.jsxs(R,{size:"small",fillColor:I.fill,textColor:I.text,children:[r," candidate",r===1?"":"s"]})]}),u&&e.jsxs("div",{className:"flex flex-col gap-1 pl-6 pb-4",children:[e.jsx("span",{className:"text-sm opacity-70",children:s.description}),c.map(p=>e.jsx(oe,{idea:p,onOpen:p.planTitle?()=>l(p.planId,p.planTitle):void 0},p.key)),s.candidates.map(p=>e.jsx(se,{name:p,onPromote:()=>a(p)},p)),e.jsx(ee,{onAdd:m}),e.jsx(y,{type:"button",variant:"ghost",size:"small",onClick:i,className:"self-start",children:"Promote to idea"})]})]})},ce="font-handwritten text-md font-semibold opacity-70 leading-none pt-2 px-1 pb-0",pe=({horizon:s,highlightedItem:t,graduatedByItem:o,onPromote:i,onAddCandidate:a,onOpenGraduated:m})=>e.jsxs("div",{className:"flex flex-col gap-1",children:[e.jsx("div",{className:ce,children:s.title}),e.jsx("div",{className:"flex flex-col",children:s.items.map(l=>e.jsx(de,{item:l,graduated:o(l),highlighted:l.name===t,onPromote:()=>i(l),onPromoteCandidate:u=>i(l,u),onAddCandidate:u=>a(l.name,u),onOpenGraduated:m},l.name))})]}),xe=()=>{const{roadmap:s,roadmapError:t,loadRoadmap:o,horizons:i,totalVisible:a,hasActiveFilters:m,highlightedItem:l,containerRef:u,promoting:d,setPromoting:h,graduatedByItem:f,handleAddCandidate:r,handlePromote:c,onOpenGraduated:p}=W();return t?e.jsxs("div",{children:[e.jsx(w,{children:"Roadmap"}),e.jsx("p",{className:"opacity-50",children:"Couldn't load the roadmap — the server may need a restart to pick up new routes."})]}):s?s.horizons.length===0?e.jsxs("div",{children:[e.jsx(w,{children:"Roadmap"}),e.jsx("p",{className:"opacity-50",children:"No `ROADMAP.md` found at the project root."})]}):e.jsxs("div",{ref:u,children:[e.jsx(w,{children:"Roadmap"}),e.jsx(te,{goal:s.goal}),a===0?e.jsx("p",{className:"opacity-50 py-6 px-0 text-center",children:m?"Nothing matches these filters — clear one from the sidebar to see more.":"No roadmap items yet — add one from the sidebar."}):e.jsx("div",{className:"flex flex-col gap-6",children:i.filter(g=>g.items.length>0).map(g=>e.jsx(pe,{horizon:g,highlightedItem:l,graduatedByItem:f,onPromote:(v,n)=>c(g.title,v,n),onAddCandidate:(v,n)=>r(g.title,v,n),onOpenGraduated:p},g.title))}),e.jsx(Y,{horizonTitle:(d==null?void 0:d.horizonTitle)??null,item:(d==null?void 0:d.item)??null,candidateName:d==null?void 0:d.candidateName,onClose:()=>h(null),onPromoted:o})]}):e.jsxs("div",{children:[e.jsx(w,{children:"Roadmap"}),e.jsx("p",{className:"opacity-50",children:"Loading…"})]})},P="pc-row-label font-handwritten text-xs font-semibold opacity-[0.45]",ue=()=>{const{roadmap:s,horizonTitles:t,horizonCounts:o,statusCounts:i,activeHorizons:a,activeStatuses:m,visibleStatuses:l,addOpen:u,setAddOpen:d,toggleRoadmapHorizon:h,toggleRoadmapStatus:f}=Z();return s?e.jsxs("div",{className:"flex flex-col",children:[e.jsx("div",{className:"flex h-[64px] items-center",children:e.jsx(y,{type:"button",variant:"primary",size:"small",onClick:()=>d(!0),disabled:t.length===0,children:"+ Add item"})}),e.jsxs("div",{children:[e.jsx("div",{className:P,children:"Horizon"}),e.jsx("div",{className:"flex flex-col",children:t.map(r=>e.jsx(E,{size:"small",active:a.has(r),onClick:()=>h(r),className:"pc-row text-xs",action:e.jsx("span",{className:"text-2xs text-ink-500",children:o[r]??0}),children:r},r))})]}),e.jsxs("div",{children:[e.jsx("div",{className:P,children:"Status"}),e.jsxs("div",{className:"flex flex-col",children:[l.length===0&&e.jsx("span",{className:"opacity-50 text-2xs",children:"No linked ideas"}),l.map(r=>e.jsx(E,{size:"small",active:m.has(r),onClick:()=>f(r),className:"pc-row text-xs",icon:e.jsx("span",{className:"w-[9px] h-[9px] rounded-full shrink-0",style:{background:N[r].text}}),action:e.jsx("span",{className:"text-2xs text-ink-500",children:i[r]??0}),children:_[r]},r))]})]}),e.jsx(X,{open:u,horizonTitles:t,onClose:()=>d(!1)})]}):null};export{xe as RoadmapPage,ue as RoadmapSidebar,je as useRoadmapItemNames};
|
|
4
|
-
//# sourceMappingURL=index-
|
|
4
|
+
//# sourceMappingURL=index-B0T4zOOc.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index-DxnAxo8U.js","sources":["../../../src/app/features/roadmap/hooks/use-roadmap-page.ts","../../../src/app/features/roadmap/hooks/use-roadmap-sidebar.ts","../../../src/app/features/roadmap/modals/add-roadmap-item-modal.tsx","../../../src/app/features/roadmap/modals/promote-roadmap-item-modal.tsx","../../../src/app/features/roadmap/views/add-candidate-form.tsx","../../../src/app/features/roadmap/views/candidate-row.tsx","../../../src/app/features/roadmap/views/goal-banner.tsx","../../../src/app/features/roadmap/constants.ts","../../../src/app/features/roadmap/views/idea-row.tsx","../../../src/app/features/roadmap/views/progress-bar.tsx","../../../src/app/features/roadmap/views/roadmap-item-row.tsx","../../../src/app/features/roadmap/views/horizon-section.tsx","../../../src/app/features/roadmap/roadmap-page.tsx","../../../src/app/features/roadmap/roadmap-sidebar.tsx"],"sourcesContent":["import { useOpenEntity } from '@/app/hooks';\nimport { addRoadmapCandidate } from '@/app/services/content/docs-api';\nimport { useAppStore } from '@/app/stores/app-store';\nimport type { PlanEntry, ResolvedRoadmapItem } from '@/types/index';\nimport { useSearch } from '@tanstack/react-router';\nimport { useEffect, useRef, useState } from 'react';\nimport { filterHorizons } from '../helpers';\n\ninterface Promoting {\n horizonTitle: string;\n item: ResolvedRoadmapItem;\n candidateName?: string;\n}\n\nexport const useRoadmapPage = () => {\n const roadmap = useAppStore((s) => s.roadmap);\n const roadmapError = useAppStore((s) => s.roadmapError);\n const loadRoadmap = useAppStore((s) => s.loadRoadmap);\n const filters = useAppStore((s) => s.roadmapFilters);\n const plans = useAppStore((s) => s.plans);\n const openEntity = useOpenEntity();\n const { item: highlightedItem } = useSearch({ from: '/roadmap' });\n const containerRef = useRef<HTMLDivElement>(null);\n const [promoting, setPromoting] = useState<Promoting | null>(null);\n\n useEffect(() => {\n loadRoadmap();\n }, [loadRoadmap]);\n\n useEffect(() => {\n if (!highlightedItem || !roadmap) return;\n const row = containerRef.current?.querySelector('.roadmap-item-highlighted');\n row?.scrollIntoView({ behavior: 'smooth', block: 'center' });\n }, [highlightedItem, roadmap]);\n\n const graduatedByItem = (item: ResolvedRoadmapItem): PlanEntry[] =>\n plans?.entries.filter((p) => p.subject === item.name) ?? [];\n\n const handleAddCandidate = async (horizonTitle: string, itemName: string, name: string) => {\n await addRoadmapCandidate(horizonTitle, itemName, name);\n await loadRoadmap();\n };\n\n const handlePromote = (\n horizonTitle: string,\n item: ResolvedRoadmapItem,\n candidateName?: string,\n ) => {\n setPromoting({ horizonTitle, item, candidateName });\n };\n\n const horizons = roadmap ? filterHorizons(roadmap, filters) : [];\n const totalVisible = horizons.reduce((count, horizon) => count + horizon.items.length, 0);\n const hasActiveFilters = filters.horizons.length > 0 || filters.statuses.length > 0;\n\n return {\n roadmap,\n roadmapError,\n loadRoadmap,\n horizons,\n totalVisible,\n hasActiveFilters,\n highlightedItem,\n containerRef,\n promoting,\n setPromoting,\n graduatedByItem,\n handleAddCandidate,\n handlePromote,\n onOpenGraduated: openEntity,\n };\n};\n","import { useAppStore } from '@/app/stores/app-store';\nimport type { PlanStatus } from '@/types/index';\nimport { useState } from 'react';\nimport { horizonItemCounts, statusItemCounts } from '../helpers';\n\nconst STATUS_CHIP_ORDER: PlanStatus[] = [\n 'in-progress',\n 'review',\n 'planned',\n 'idea',\n 'done',\n 'dropped',\n];\n\nexport const useRoadmapSidebar = () => {\n const roadmap = useAppStore((s) => s.roadmap);\n const filters = useAppStore((s) => s.roadmapFilters);\n const toggleRoadmapHorizon = useAppStore((s) => s.toggleRoadmapHorizon);\n const toggleRoadmapStatus = useAppStore((s) => s.toggleRoadmapStatus);\n const [addOpen, setAddOpen] = useState(false);\n\n const horizonTitles = roadmap?.horizons.map((horizon) => horizon.title) ?? [];\n const horizonCounts = roadmap ? horizonItemCounts(roadmap, filters) : {};\n const statusCounts = roadmap ? statusItemCounts(roadmap, filters) : {};\n const activeHorizons = new Set(filters.horizons);\n const activeStatuses = new Set(filters.statuses);\n const visibleStatuses = STATUS_CHIP_ORDER.filter(\n (status) => (statusCounts[status] ?? 0) > 0 || activeStatuses.has(status),\n );\n\n return {\n roadmap,\n horizonTitles,\n horizonCounts,\n statusCounts,\n activeHorizons,\n activeStatuses,\n visibleStatuses,\n addOpen,\n setAddOpen,\n toggleRoadmapHorizon,\n toggleRoadmapStatus,\n };\n};\n","import { addRoadmapItem } from '@/app/services/content/docs-api';\nimport { useAppStore } from '@/app/stores/app-store';\nimport { Button, Input, Modal, Select } from '@dendelion/paper-ui';\nimport { useEffect, useRef, useState } from 'react';\n\ninterface AddRoadmapItemModalProps {\n open: boolean;\n horizonTitles: string[];\n onClose: () => void;\n}\n\nexport const AddRoadmapItemModal = ({ open, horizonTitles, onClose }: AddRoadmapItemModalProps) => {\n const loadRoadmap = useAppStore((s) => s.loadRoadmap);\n const [horizon, setHorizon] = useState(horizonTitles[0] ?? '');\n const [name, setName] = useState('');\n const [description, setDescription] = useState('');\n const [saving, setSaving] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const horizonTitlesRef = useRef(horizonTitles);\n horizonTitlesRef.current = horizonTitles;\n\n useEffect(() => {\n if (open) {\n setHorizon(horizonTitlesRef.current[0] ?? '');\n setName('');\n setDescription('');\n setError(null);\n setSaving(false);\n }\n }, [open]);\n\n const handleAdd = async () => {\n if (!name.trim() || !horizon) return;\n setSaving(true);\n setError(null);\n try {\n await addRoadmapItem(horizon, name.trim(), description.trim());\n await loadRoadmap();\n onClose();\n } catch (err) {\n setError((err as Error).message);\n } finally {\n setSaving(false);\n }\n };\n\n return (\n <Modal open={open} onClose={onClose} title=\"Add roadmap item\" size=\"small\">\n <div className=\"flex flex-col gap-4\">\n <Select\n size=\"small\"\n value={horizon}\n onChange={setHorizon}\n disabled={saving}\n options={horizonTitles.map((title) => ({ value: title, label: title }))}\n />\n <Input\n size=\"small\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n placeholder=\"Item name…\"\n disabled={saving}\n autoFocus\n />\n <Input\n size=\"small\"\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === 'Enter') handleAdd();\n }}\n placeholder=\"Description…\"\n disabled={saving}\n />\n {error && <p className=\"m-0 text-watercolor-rose-dark text-sm\">{error}</p>}\n <div className=\"flex justify-end gap-2\">\n <Button type=\"button\" variant=\"ghost\" onClick={onClose} disabled={saving}>\n Cancel\n </Button>\n <Button\n type=\"button\"\n variant=\"primary\"\n onClick={handleAdd}\n disabled={saving || !name.trim() || !horizon}\n >\n {saving ? 'Adding…' : 'Add item'}\n </Button>\n </div>\n </div>\n </Modal>\n );\n};\n","import { buildRoadmapPromotePrompt } from '@/app/features/plans/prompts';\nimport { useSubjectVocabulary } from '@/app/hooks/use-subject-vocabulary';\nimport { useAppStore } from '@/app/stores/app-store';\nimport { oneLineErrorSummary } from '@/app/utils/error-summary';\nimport type { RoadmapItem } from '@/types/index';\nimport { Button, Modal, Select, useToast } from '@dendelion/paper-ui';\nimport { useEffect, useState } from 'react';\n\nconst NO_SUBJECT = '__no-subject__';\n\ninterface PromoteRoadmapItemModalProps {\n horizonTitle: string | null;\n item: RoadmapItem | null;\n candidateName?: string | null;\n onClose: () => void;\n onPromoted: () => void;\n}\n\nexport const PromoteRoadmapItemModal = ({\n horizonTitle,\n item,\n candidateName,\n onClose,\n onPromoted,\n}: PromoteRoadmapItemModalProps) => {\n const promoteRoadmapItem = useAppStore((s) => s.promoteRoadmapItem);\n const launchIdeaExtend = useAppStore((s) => s.launchIdeaExtend);\n const { subjects, available: subjectsAvailable } = useSubjectVocabulary();\n const [subject, setSubject] = useState(NO_SUBJECT);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const { toast } = useToast();\n\n useEffect(() => {\n if (item) {\n // A candidate defaults to its parent item's name — the \"big bet becomes a\n // Subject\" rule — but the picker still lets the user override it.\n setSubject(candidateName ? item.name : NO_SUBJECT);\n setLoading(false);\n setError(null);\n }\n }, [item, candidateName]);\n\n const handlePromote = async () => {\n if (!item || !horizonTitle) return;\n setLoading(true);\n setError(null);\n try {\n const id = await promoteRoadmapItem(\n horizonTitle,\n item,\n subject === NO_SUBJECT ? undefined : subject,\n candidateName ?? undefined,\n );\n const idea = useAppStore.getState().ideaEntries.find((e) => e.id === id);\n if (idea) {\n try {\n await launchIdeaExtend(id, buildRoadmapPromotePrompt(idea, horizonTitle));\n } catch (err) {\n // The idea was created either way — a failed refine launch just means\n // no background research ran, not that the promotion itself failed.\n toast({\n title: 'Idea created, but the refine agent failed to launch',\n description: oneLineErrorSummary((err as Error).message),\n variant: 'error',\n });\n }\n }\n onPromoted();\n onClose();\n } catch (err) {\n setError((err as Error).message);\n } finally {\n setLoading(false);\n }\n };\n\n return (\n <Modal\n open={item !== null}\n onClose={onClose}\n title={candidateName ?? item?.name ?? ''}\n size=\"small\"\n >\n <div className=\"flex flex-col gap-4\">\n {!candidateName && <p className=\"m-0 opacity-80\">{item?.description}</p>}\n <div>\n <Select\n size=\"small\"\n value={subject}\n onChange={setSubject}\n disabled={loading || !subjectsAvailable}\n options={[\n { value: NO_SUBJECT, label: 'No subject' },\n ...(!subjectsAvailable && subject !== NO_SUBJECT\n ? [{ value: subject, label: subject }]\n : []),\n ...subjects.map((s) => ({ value: s, label: s })),\n ]}\n />\n </div>\n {error && <p className=\"m-0 text-watercolor-rose-dark text-sm\">{error}</p>}\n <div className=\"flex justify-end gap-2\">\n <Button type=\"button\" variant=\"ghost\" onClick={onClose} disabled={loading}>\n Cancel\n </Button>\n <Button type=\"button\" variant=\"primary\" onClick={handlePromote} disabled={loading}>\n {loading ? 'Promoting…' : 'Promote to idea'}\n </Button>\n </div>\n </div>\n </Modal>\n );\n};\n","import { Button, Input } from '@dendelion/paper-ui';\nimport { useState } from 'react';\n\ninterface AddCandidateFormProps {\n onAdd: (name: string) => Promise<void>;\n}\n\nexport const AddCandidateForm = ({ onAdd }: AddCandidateFormProps) => {\n const [name, setName] = useState('');\n const [saving, setSaving] = useState(false);\n\n const handleAdd = async () => {\n if (!name.trim()) return;\n setSaving(true);\n try {\n await onAdd(name.trim());\n setName('');\n } finally {\n setSaving(false);\n }\n };\n\n return (\n <div className=\"flex gap-2\">\n <Input\n size=\"small\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === 'Enter') handleAdd();\n }}\n placeholder=\"Add option…\"\n disabled={saving}\n className=\"flex-1\"\n />\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"small\"\n onClick={handleAdd}\n disabled={saving || !name.trim()}\n >\n Add\n </Button>\n </div>\n );\n};\n","import { Button, Card } from '@dendelion/paper-ui';\n\ninterface CandidateRowProps {\n name: string;\n onPromote: () => void;\n}\n\nexport const CandidateRow = ({ name, onPromote }: CandidateRowProps) => (\n <Card size=\"small\" texture=\"kraft\" className=\"plan-row-card\">\n <div className=\"flex items-center gap-3\">\n <span className=\"flex-1\">{name}</span>\n <Button type=\"button\" variant=\"ghost\" size=\"small\" onClick={onPromote}>\n Promote to idea\n </Button>\n </div>\n </Card>\n);\n","import { Markdown } from '@/app/components/markdown';\nimport { useState } from 'react';\n\ninterface GoalBannerProps {\n goal: string;\n}\n\nexport const GoalBanner = ({ goal }: GoalBannerProps) => {\n const [expanded, setExpanded] = useState(false);\n const [firstParagraph, ...restParagraphs] = goal.split(/\\n{2,}/);\n const hasMore = restParagraphs.length > 0;\n\n return (\n <div className=\"mb-6 pb-4 border-b border-black/[8%]\">\n <span className=\"font-handwritten text-xs font-semibold opacity-[0.55]\">The goal</span>\n <div className=\"text-sm leading-relaxed opacity-80 mt-2\">\n <Markdown>{firstParagraph}</Markdown>\n {expanded && hasMore && <Markdown>{restParagraphs.join('\\n\\n')}</Markdown>}\n </div>\n {hasMore && (\n <button\n type=\"button\"\n onClick={() => setExpanded((v) => !v)}\n className=\"bg-transparent border-none p-0 mt-2 cursor-pointer text-2xs opacity-[0.65] underline\"\n >\n {expanded ? 'Show less' : 'Show more'}\n </button>\n )}\n </div>\n );\n};\n","export const HIGHLIGHT_OUTLINE_CLASS = 'outline-[rgba(200,154,90,0.5)]';\n\nexport const CANDIDATE_STAMP = {\n fill: 'rgba(0, 0, 0, 0.06)',\n text: 'rgba(0, 0, 0, 0.55)',\n};\n","import { PrBadge } from '@/app/features/plans/components/pr-badge';\nimport { STATUS_LABEL, STATUS_STAMP } from '@/app/features/plans/constants';\nimport type { PlanEntry, PlanStatus, PrInfo, RoadmapLink } from '@/types/index';\nimport { Card, Stamp } from '@dendelion/paper-ui';\n\nexport interface MergedIdea {\n key: string;\n label: string;\n status: PlanStatus;\n pr?: PrInfo;\n planId?: string;\n planTitle?: string;\n}\n\nexport const mergeIdeas = (links: RoadmapLink[], graduated: PlanEntry[]): MergedIdea[] => {\n const represented = new Set<string>();\n const merged: MergedIdea[] = graduated.map((plan) => {\n if (plan.id) represented.add(plan.id);\n if (plan.idea) represented.add(plan.idea);\n return {\n key: plan.title,\n label: plan.title,\n status: plan.status,\n pr: plan.pr,\n planId: plan.id,\n planTitle: plan.title,\n };\n });\n for (const link of links) {\n if (represented.has(link.id)) continue;\n merged.push({ key: link.id, label: link.id, status: link.status, pr: link.pr });\n }\n return merged;\n};\n\ninterface IdeaRowProps {\n idea: MergedIdea;\n onOpen?: () => void;\n}\n\nexport const IdeaRow = ({ idea, onOpen }: IdeaRowProps) => (\n <Card size=\"small\" texture=\"kraft\" className=\"plan-row-card\">\n <div className=\"flex items-center gap-3\">\n {onOpen ? (\n <button\n type=\"button\"\n onClick={onOpen}\n className=\"flex-1 min-w-0 overflow-hidden text-ellipsis whitespace-nowrap bg-transparent border-none p-0 cursor-pointer [font:inherit] text-inherit text-left\"\n >\n {idea.label}\n </button>\n ) : (\n <span className=\"flex-1 min-w-0 overflow-hidden text-ellipsis whitespace-nowrap\">\n {idea.label}\n </span>\n )}\n {idea.pr && <PrBadge pr={idea.pr} />}\n <Stamp\n size=\"small\"\n fillColor={STATUS_STAMP[idea.status].fill}\n textColor={STATUS_STAMP[idea.status].text}\n >\n {STATUS_LABEL[idea.status]}\n </Stamp>\n </div>\n </Card>\n);\n","interface ProgressBarProps {\n done: number;\n total: number;\n}\n\nexport const ProgressBar = ({ done, total }: ProgressBarProps) => {\n const percent = total > 0 ? Math.round((done / total) * 100) : 0;\n return (\n <div className=\"w-24 h-1.5 rounded-full bg-black/[0.08] overflow-hidden shrink-0\">\n <div\n className={`h-full rounded-full ${total > 0 ? 'bg-watercolor-green' : 'bg-transparent'}`}\n style={{ width: `${percent}%` }}\n />\n </div>\n );\n};\n","import { STATUS_STAMP } from '@/app/features/plans/constants';\nimport type { PlanEntry, ResolvedRoadmapItem } from '@/types/index';\nimport { Button, Stamp } from '@dendelion/paper-ui';\nimport { useEffect, useState } from 'react';\nimport { CANDIDATE_STAMP, HIGHLIGHT_OUTLINE_CLASS } from '../constants';\nimport { AddCandidateForm } from './add-candidate-form';\nimport { CandidateRow } from './candidate-row';\nimport { IdeaRow, mergeIdeas } from './idea-row';\nimport { ProgressBar } from './progress-bar';\n\nconst graduationCounts = (graduated: PlanEntry[]) => ({\n shipped: graduated.filter((p) => p.status === 'done').length,\n queued: graduated.filter((p) => p.status !== 'done' && p.status !== 'dropped').length,\n});\n\nconst ChevronRightIcon = ({ size = 14 }: { size?: number }) => (\n <svg\n width={size}\n height={size}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n <polyline points=\"9 18 15 12 9 6\" />\n </svg>\n);\n\ninterface RoadmapItemRowProps {\n item: ResolvedRoadmapItem;\n graduated: PlanEntry[];\n highlighted: boolean;\n onPromote: () => void;\n onPromoteCandidate: (candidateName: string) => void;\n onAddCandidate: (name: string) => Promise<void>;\n onOpenGraduated: (id: string | undefined, title: string) => void;\n}\n\nexport const RoadmapItemRow = ({\n item,\n graduated,\n highlighted,\n onPromote,\n onPromoteCandidate,\n onAddCandidate,\n onOpenGraduated,\n}: RoadmapItemRowProps) => {\n const [expanded, setExpanded] = useState(highlighted);\n const { shipped, queued } = graduationCounts(graduated);\n const candidates = item.candidates.length;\n const ideas = mergeIdeas(item.links, graduated);\n\n useEffect(() => {\n if (highlighted) setExpanded(true);\n }, [highlighted]);\n\n return (\n <div\n className={`border-b border-black/10 last:border-b-0 ${highlighted ? `roadmap-item-highlighted outline outline-2 outline-offset-[-2px] ${HIGHLIGHT_OUTLINE_CLASS}` : ''}`}\n >\n <button\n type=\"button\"\n aria-expanded={expanded}\n onClick={() => setExpanded((v) => !v)}\n className=\"flex w-full items-center gap-3 py-2.5 px-0 bg-transparent border-none cursor-pointer text-left [font:inherit] text-inherit\"\n >\n <span\n className={`inline-flex items-center opacity-50 shrink-0 ${expanded ? 'rotate-90' : ''}`}\n >\n <ChevronRightIcon />\n </span>\n <span className=\"font-semibold flex-1 min-w-0 truncate\">{item.name}</span>\n <ProgressBar done={item.rollup.done} total={item.rollup.total} />\n {queued > 0 && (\n <Stamp\n size=\"small\"\n fillColor={STATUS_STAMP.planned.fill}\n textColor={STATUS_STAMP.planned.text}\n >\n {queued} in queue\n </Stamp>\n )}\n {shipped > 0 && (\n <Stamp size=\"small\" fillColor={STATUS_STAMP.done.fill} textColor={STATUS_STAMP.done.text}>\n {shipped} shipped\n </Stamp>\n )}\n {candidates > 0 && (\n <Stamp size=\"small\" fillColor={CANDIDATE_STAMP.fill} textColor={CANDIDATE_STAMP.text}>\n {candidates} candidate{candidates === 1 ? '' : 's'}\n </Stamp>\n )}\n </button>\n {expanded && (\n <div className=\"flex flex-col gap-1 pl-6 pb-4\">\n <span className=\"text-sm opacity-70\">{item.description}</span>\n {ideas.map((idea) => (\n <IdeaRow\n key={idea.key}\n idea={idea}\n onOpen={\n idea.planTitle\n ? () => onOpenGraduated(idea.planId, idea.planTitle as string)\n : undefined\n }\n />\n ))}\n {item.candidates.map((candidateName) => (\n <CandidateRow\n key={candidateName}\n name={candidateName}\n onPromote={() => onPromoteCandidate(candidateName)}\n />\n ))}\n <AddCandidateForm onAdd={onAddCandidate} />\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"small\"\n onClick={onPromote}\n className=\"self-start\"\n >\n Promote to idea\n </Button>\n </div>\n )}\n </div>\n );\n};\n","import type { PlanEntry, ResolvedRoadmapHorizon, ResolvedRoadmapItem } from '@/types/index';\nimport { RoadmapItemRow } from './roadmap-item-row';\n\nconst HORIZON_HEADER_CLASSES =\n 'font-handwritten text-md font-semibold opacity-70 leading-none pt-2 px-1 pb-0';\n\ninterface HorizonSectionProps {\n horizon: ResolvedRoadmapHorizon;\n highlightedItem: string | undefined;\n graduatedByItem: (item: ResolvedRoadmapItem) => PlanEntry[];\n onPromote: (item: ResolvedRoadmapItem, candidateName?: string) => void;\n onAddCandidate: (itemName: string, name: string) => Promise<void>;\n onOpenGraduated: (id: string | undefined, title: string) => void;\n}\n\nexport const HorizonSection = ({\n horizon,\n highlightedItem,\n graduatedByItem,\n onPromote,\n onAddCandidate,\n onOpenGraduated,\n}: HorizonSectionProps) => (\n <div className=\"flex flex-col gap-1\">\n <div className={HORIZON_HEADER_CLASSES}>{horizon.title}</div>\n <div className=\"flex flex-col\">\n {horizon.items.map((item) => (\n <RoadmapItemRow\n key={item.name}\n item={item}\n graduated={graduatedByItem(item)}\n highlighted={item.name === highlightedItem}\n onPromote={() => onPromote(item)}\n onPromoteCandidate={(candidateName) => onPromote(item, candidateName)}\n onAddCandidate={(name) => onAddCandidate(item.name, name)}\n onOpenGraduated={onOpenGraduated}\n />\n ))}\n </div>\n </div>\n);\n","import { PageTitle } from '@/app/components/page-title';\nimport { useRoadmapPage } from './hooks';\nimport { PromoteRoadmapItemModal } from './modals';\nimport { GoalBanner, HorizonSection } from './views';\n\nexport const RoadmapPage = () => {\n const {\n roadmap,\n roadmapError,\n loadRoadmap,\n horizons,\n totalVisible,\n hasActiveFilters,\n highlightedItem,\n containerRef,\n promoting,\n setPromoting,\n graduatedByItem,\n handleAddCandidate,\n handlePromote,\n onOpenGraduated,\n } = useRoadmapPage();\n\n if (roadmapError) {\n return (\n <div>\n <PageTitle>Roadmap</PageTitle>\n <p className=\"opacity-50\">\n Couldn't load the roadmap — the server may need a restart to pick up new routes.\n </p>\n </div>\n );\n }\n\n if (!roadmap) {\n return (\n <div>\n <PageTitle>Roadmap</PageTitle>\n <p className=\"opacity-50\">Loading…</p>\n </div>\n );\n }\n\n if (roadmap.horizons.length === 0) {\n return (\n <div>\n <PageTitle>Roadmap</PageTitle>\n <p className=\"opacity-50\">No `ROADMAP.md` found at the project root.</p>\n </div>\n );\n }\n\n return (\n <div ref={containerRef}>\n <PageTitle>Roadmap</PageTitle>\n <GoalBanner goal={roadmap.goal} />\n {totalVisible === 0 ? (\n <p className=\"opacity-50 py-6 px-0 text-center\">\n {hasActiveFilters\n ? 'Nothing matches these filters — clear one from the sidebar to see more.'\n : 'No roadmap items yet — add one from the sidebar.'}\n </p>\n ) : (\n <div className=\"flex flex-col gap-6\">\n {horizons\n .filter((horizon) => horizon.items.length > 0)\n .map((horizon) => (\n <HorizonSection\n key={horizon.title}\n horizon={horizon}\n highlightedItem={highlightedItem}\n graduatedByItem={graduatedByItem}\n onPromote={(item, candidateName) =>\n handlePromote(horizon.title, item, candidateName)\n }\n onAddCandidate={(itemName, name) =>\n handleAddCandidate(horizon.title, itemName, name)\n }\n onOpenGraduated={onOpenGraduated}\n />\n ))}\n </div>\n )}\n <PromoteRoadmapItemModal\n horizonTitle={promoting?.horizonTitle ?? null}\n item={promoting?.item ?? null}\n candidateName={promoting?.candidateName}\n onClose={() => setPromoting(null)}\n onPromoted={loadRoadmap}\n />\n </div>\n );\n};\n","import { STATUS_LABEL, STATUS_STAMP } from '@/app/features/plans/constants';\nimport { Button, ListItem } from '@dendelion/paper-ui';\nimport { useRoadmapSidebar } from './hooks';\nimport { AddRoadmapItemModal } from './modals';\n\n// Matches SidebarSection — handwritten, no caps, one grid cell.\nconst sectionLabelClass = 'pc-row-label font-handwritten text-xs font-semibold opacity-[0.45]';\n\nexport const RoadmapSidebar = () => {\n const {\n roadmap,\n horizonTitles,\n horizonCounts,\n statusCounts,\n activeHorizons,\n activeStatuses,\n visibleStatuses,\n addOpen,\n setAddOpen,\n toggleRoadmapHorizon,\n toggleRoadmapStatus,\n } = useRoadmapSidebar();\n\n if (!roadmap) return null;\n\n return (\n <div className=\"flex flex-col\">\n <div className=\"flex h-[64px] items-center\">\n <Button\n type=\"button\"\n variant=\"primary\"\n size=\"small\"\n onClick={() => setAddOpen(true)}\n disabled={horizonTitles.length === 0}\n >\n + Add item\n </Button>\n </div>\n\n <div>\n <div className={sectionLabelClass}>Horizon</div>\n <div className=\"flex flex-col\">\n {horizonTitles.map((title) => (\n <ListItem\n key={title}\n size=\"small\"\n active={activeHorizons.has(title)}\n onClick={() => toggleRoadmapHorizon(title)}\n className=\"pc-row text-xs\"\n action={<span className=\"text-2xs text-ink-500\">{horizonCounts[title] ?? 0}</span>}\n >\n {title}\n </ListItem>\n ))}\n </div>\n </div>\n\n <div>\n <div className={sectionLabelClass}>Status</div>\n <div className=\"flex flex-col\">\n {visibleStatuses.length === 0 && (\n <span className=\"opacity-50 text-2xs\">No linked ideas</span>\n )}\n {visibleStatuses.map((status) => (\n <ListItem\n key={status}\n size=\"small\"\n active={activeStatuses.has(status)}\n onClick={() => toggleRoadmapStatus(status)}\n className=\"pc-row text-xs\"\n icon={\n <span\n className=\"w-[9px] h-[9px] rounded-full shrink-0\"\n style={{ background: STATUS_STAMP[status].text }}\n />\n }\n action={<span className=\"text-2xs text-ink-500\">{statusCounts[status] ?? 0}</span>}\n >\n {STATUS_LABEL[status]}\n </ListItem>\n ))}\n </div>\n </div>\n\n <AddRoadmapItemModal\n open={addOpen}\n horizonTitles={horizonTitles}\n onClose={() => setAddOpen(false)}\n />\n </div>\n );\n};\n"],"names":["useRoadmapPage","roadmap","useAppStore","s","roadmapError","loadRoadmap","filters","plans","openEntity","useOpenEntity","highlightedItem","useSearch","containerRef","useRef","promoting","setPromoting","useState","useEffect","row","_a","graduatedByItem","item","p","handleAddCandidate","horizonTitle","itemName","name","addRoadmapCandidate","handlePromote","candidateName","horizons","filterHorizons","totalVisible","count","horizon","hasActiveFilters","STATUS_CHIP_ORDER","useRoadmapSidebar","toggleRoadmapHorizon","toggleRoadmapStatus","addOpen","setAddOpen","horizonTitles","horizonCounts","horizonItemCounts","statusCounts","statusItemCounts","activeHorizons","activeStatuses","visibleStatuses","status","AddRoadmapItemModal","open","onClose","setHorizon","setName","description","setDescription","saving","setSaving","error","setError","horizonTitlesRef","handleAdd","addRoadmapItem","err","jsx","Modal","jsxs","Select","title","Input","e","Button","NO_SUBJECT","PromoteRoadmapItemModal","onPromoted","promoteRoadmapItem","launchIdeaExtend","subjects","subjectsAvailable","useSubjectVocabulary","subject","setSubject","loading","setLoading","toast","useToast","id","idea","buildRoadmapPromotePrompt","oneLineErrorSummary","AddCandidateForm","onAdd","CandidateRow","onPromote","Card","GoalBanner","goal","expanded","setExpanded","firstParagraph","restParagraphs","hasMore","Markdown","v","HIGHLIGHT_OUTLINE_CLASS","CANDIDATE_STAMP","mergeIdeas","links","graduated","represented","merged","plan","link","IdeaRow","onOpen","PrBadge","Stamp","STATUS_STAMP","STATUS_LABEL","ProgressBar","done","total","percent","graduationCounts","ChevronRightIcon","size","RoadmapItemRow","highlighted","onPromoteCandidate","onAddCandidate","onOpenGraduated","shipped","queued","candidates","ideas","HORIZON_HEADER_CLASSES","HorizonSection","RoadmapPage","PageTitle","sectionLabelClass","RoadmapSidebar","ListItem"],"mappings":"yPAcO,MAAMA,EAAiB,IAAM,CAClC,MAAMC,EAAUC,EAAaC,GAAMA,EAAE,OAAO,EACtCC,EAAeF,EAAaC,GAAMA,EAAE,YAAY,EAChDE,EAAcH,EAAaC,GAAMA,EAAE,WAAW,EAC9CG,EAAUJ,EAAaC,GAAMA,EAAE,cAAc,EAC7CI,EAAQL,EAAaC,GAAMA,EAAE,KAAK,EAClCK,EAAaC,EAAA,EACb,CAAE,KAAMC,CAAA,EAAoBC,EAAU,CAAE,KAAM,WAAY,EAC1DC,EAAeC,EAAAA,OAAuB,IAAI,EAC1C,CAACC,EAAWC,CAAY,EAAIC,EAAAA,SAA2B,IAAI,EAEjEC,EAAAA,UAAU,IAAM,CACdZ,EAAA,CACF,EAAG,CAACA,CAAW,CAAC,EAEhBY,EAAAA,UAAU,IAAM,OACd,GAAI,CAACP,GAAmB,CAACT,EAAS,OAClC,MAAMiB,GAAMC,EAAAP,EAAa,UAAb,YAAAO,EAAsB,cAAc,6BAChDD,GAAA,MAAAA,EAAK,eAAe,CAAE,SAAU,SAAU,MAAO,UACnD,EAAG,CAACR,EAAiBT,CAAO,CAAC,EAE7B,MAAMmB,EAAmBC,IACvBd,GAAA,YAAAA,EAAO,QAAQ,OAAQe,GAAMA,EAAE,UAAYD,EAAK,QAAS,CAAA,EAErDE,EAAqB,MAAOC,EAAsBC,EAAkBC,IAAiB,CACzF,MAAMC,EAAoBH,EAAcC,EAAUC,CAAI,EACtD,MAAMrB,EAAA,CACR,EAEMuB,EAAgB,CACpBJ,EACAH,EACAQ,IACG,CACHd,EAAa,CAAE,aAAAS,EAAc,KAAAH,EAAM,cAAAQ,CAAA,CAAe,CACpD,EAEMC,EAAW7B,EAAU8B,EAAe9B,EAASK,CAAO,EAAI,CAAA,EACxD0B,EAAeF,EAAS,OAAO,CAACG,EAAOC,IAAYD,EAAQC,EAAQ,MAAM,OAAQ,CAAC,EAClFC,EAAmB7B,EAAQ,SAAS,OAAS,GAAKA,EAAQ,SAAS,OAAS,EAElF,MAAO,CACL,QAAAL,EACA,aAAAG,EACA,YAAAC,EACA,SAAAyB,EACA,aAAAE,EACA,iBAAAG,EACA,gBAAAzB,EACA,aAAAE,EACA,UAAAE,EACA,aAAAC,EACA,gBAAAK,EACA,mBAAAG,EACA,cAAAK,EACA,gBAAiBpB,CAAA,CAErB,EClEM4B,EAAkC,CACtC,cACA,SACA,UACA,OACA,OACA,SACF,EAEaC,EAAoB,IAAM,CACrC,MAAMpC,EAAUC,EAAaC,GAAMA,EAAE,OAAO,EACtCG,EAAUJ,EAAaC,GAAMA,EAAE,cAAc,EAC7CmC,EAAuBpC,EAAaC,GAAMA,EAAE,oBAAoB,EAChEoC,EAAsBrC,EAAaC,GAAMA,EAAE,mBAAmB,EAC9D,CAACqC,EAASC,CAAU,EAAIzB,EAAAA,SAAS,EAAK,EAEtC0B,GAAgBzC,GAAA,YAAAA,EAAS,SAAS,IAAKiC,GAAYA,EAAQ,SAAU,CAAA,EACrES,EAAgB1C,EAAU2C,EAAkB3C,EAASK,CAAO,EAAI,CAAA,EAChEuC,EAAe5C,EAAU6C,EAAiB7C,EAASK,CAAO,EAAI,CAAA,EAC9DyC,EAAiB,IAAI,IAAIzC,EAAQ,QAAQ,EACzC0C,EAAiB,IAAI,IAAI1C,EAAQ,QAAQ,EACzC2C,EAAkBb,EAAkB,OACvCc,IAAYL,EAAaK,CAAM,GAAK,GAAK,GAAKF,EAAe,IAAIE,CAAM,CAAA,EAG1E,MAAO,CACL,QAAAjD,EACA,cAAAyC,EACA,cAAAC,EACA,aAAAE,EACA,eAAAE,EACA,eAAAC,EACA,gBAAAC,EACA,QAAAT,EACA,WAAAC,EACA,qBAAAH,EACA,oBAAAC,CAAA,CAEJ,EChCaY,EAAsB,CAAC,CAAE,KAAAC,EAAM,cAAAV,EAAe,QAAAW,KAAwC,CACjG,MAAMhD,EAAcH,EAAaC,GAAMA,EAAE,WAAW,EAC9C,CAAC+B,EAASoB,CAAU,EAAItC,EAAAA,SAAS0B,EAAc,CAAC,GAAK,EAAE,EACvD,CAAChB,EAAM6B,CAAO,EAAIvC,EAAAA,SAAS,EAAE,EAC7B,CAACwC,EAAaC,CAAc,EAAIzC,EAAAA,SAAS,EAAE,EAC3C,CAAC0C,EAAQC,CAAS,EAAI3C,EAAAA,SAAS,EAAK,EACpC,CAAC4C,EAAOC,CAAQ,EAAI7C,EAAAA,SAAwB,IAAI,EAChD8C,EAAmBjD,EAAAA,OAAO6B,CAAa,EAC7CoB,EAAiB,QAAUpB,EAE3BzB,EAAAA,UAAU,IAAM,CACVmC,IACFE,EAAWQ,EAAiB,QAAQ,CAAC,GAAK,EAAE,EAC5CP,EAAQ,EAAE,EACVE,EAAe,EAAE,EACjBI,EAAS,IAAI,EACbF,EAAU,EAAK,EAEnB,EAAG,CAACP,CAAI,CAAC,EAET,MAAMW,EAAY,SAAY,CAC5B,GAAI,GAACrC,EAAK,KAAA,GAAU,CAACQ,GACrB,CAAAyB,EAAU,EAAI,EACdE,EAAS,IAAI,EACb,GAAI,CACF,MAAMG,EAAe9B,EAASR,EAAK,OAAQ8B,EAAY,MAAM,EAC7D,MAAMnD,EAAA,EACNgD,EAAA,CACF,OAASY,EAAK,CACZJ,EAAUI,EAAc,OAAO,CACjC,QAAA,CACEN,EAAU,EAAK,CACjB,EACF,EAEA,OACEO,EAAAA,IAACC,EAAA,CAAM,KAAAf,EAAY,QAAAC,EAAkB,MAAM,mBAAmB,KAAK,QACjE,SAAAe,EAAAA,KAAC,MAAA,CAAI,UAAU,sBACb,SAAA,CAAAF,EAAAA,IAACG,EAAA,CACC,KAAK,QACL,MAAOnC,EACP,SAAUoB,EACV,SAAUI,EACV,QAAShB,EAAc,IAAK4B,IAAW,CAAE,MAAOA,EAAO,MAAOA,GAAQ,CAAA,CAAA,EAExEJ,EAAAA,IAACK,EAAA,CACC,KAAK,QACL,MAAO7C,EACP,SAAW8C,GAAMjB,EAAQiB,EAAE,OAAO,KAAK,EACvC,YAAY,aACZ,SAAUd,EACV,UAAS,EAAA,CAAA,EAEXQ,EAAAA,IAACK,EAAA,CACC,KAAK,QACL,MAAOf,EACP,SAAWgB,GAAMf,EAAee,EAAE,OAAO,KAAK,EAC9C,UAAYA,GAAM,CACZA,EAAE,MAAQ,SAAST,EAAA,CACzB,EACA,YAAY,eACZ,SAAUL,CAAA,CAAA,EAEXE,GAASM,EAAAA,IAAC,IAAA,CAAE,UAAU,wCAAyC,SAAAN,EAAM,EACtEQ,EAAAA,KAAC,MAAA,CAAI,UAAU,yBACb,SAAA,CAAAF,EAAAA,IAACO,EAAA,CAAO,KAAK,SAAS,QAAQ,QAAQ,QAASpB,EAAS,SAAUK,EAAQ,SAAA,QAAA,CAE1E,EACAQ,EAAAA,IAACO,EAAA,CACC,KAAK,SACL,QAAQ,UACR,QAASV,EACT,SAAUL,GAAU,CAAChC,EAAK,KAAA,GAAU,CAACQ,EAEpC,WAAS,UAAY,UAAA,CAAA,CACxB,CAAA,CACF,CAAA,CAAA,CACF,CAAA,CACF,CAEJ,ECnFMwC,EAAa,iBAUNC,EAA0B,CAAC,CACtC,aAAAnD,EACA,KAAAH,EACA,cAAAQ,EACA,QAAAwB,EACA,WAAAuB,CACF,IAAoC,CAClC,MAAMC,EAAqB3E,EAAaC,GAAMA,EAAE,kBAAkB,EAC5D2E,EAAmB5E,EAAaC,GAAMA,EAAE,gBAAgB,EACxD,CAAE,SAAA4E,EAAU,UAAWC,CAAA,EAAsBC,EAAA,EAC7C,CAACC,EAASC,CAAU,EAAInE,EAAAA,SAAS0D,CAAU,EAC3C,CAACU,EAASC,CAAU,EAAIrE,EAAAA,SAAS,EAAK,EACtC,CAAC4C,EAAOC,CAAQ,EAAI7C,EAAAA,SAAwB,IAAI,EAChD,CAAE,MAAAsE,CAAA,EAAUC,EAAA,EAElBtE,EAAAA,UAAU,IAAM,CACVI,IAGF8D,EAAWtD,EAAgBR,EAAK,KAAOqD,CAAU,EACjDW,EAAW,EAAK,EAChBxB,EAAS,IAAI,EAEjB,EAAG,CAACxC,EAAMQ,CAAa,CAAC,EAExB,MAAMD,EAAgB,SAAY,CAChC,GAAI,GAACP,GAAQ,CAACG,GACd,CAAA6D,EAAW,EAAI,EACfxB,EAAS,IAAI,EACb,GAAI,CACF,MAAM2B,EAAK,MAAMX,EACfrD,EACAH,EACA6D,IAAYR,EAAa,OAAYQ,EACrCrD,GAAiB,MAAA,EAEb4D,EAAOvF,EAAY,SAAA,EAAW,YAAY,KAAMsE,GAAMA,EAAE,KAAOgB,CAAE,EACvE,GAAIC,EACF,GAAI,CACF,MAAMX,EAAiBU,EAAIE,EAA0BD,EAAMjE,CAAY,CAAC,CAC1E,OAASyC,EAAK,CAGZqB,EAAM,CACJ,MAAO,sDACP,YAAaK,EAAqB1B,EAAc,OAAO,EACvD,QAAS,OAAA,CACV,CACH,CAEFW,EAAA,EACAvB,EAAA,CACF,OAASY,EAAK,CACZJ,EAAUI,EAAc,OAAO,CACjC,QAAA,CACEoB,EAAW,EAAK,CAClB,EACF,EAEA,OACEnB,EAAAA,IAACC,EAAA,CACC,KAAM9C,IAAS,KACf,QAAAgC,EACA,MAAOxB,IAAiBR,GAAA,YAAAA,EAAM,OAAQ,GACtC,KAAK,QAEL,SAAA+C,EAAAA,KAAC,MAAA,CAAI,UAAU,sBACZ,SAAA,CAAA,CAACvC,GAAiBqC,MAAC,IAAA,CAAE,UAAU,iBAAkB,0BAAM,YAAY,QACnE,MAAA,CACC,SAAAA,EAAAA,IAACG,EAAA,CACC,KAAK,QACL,MAAOa,EACP,SAAUC,EACV,SAAUC,GAAW,CAACJ,EACtB,QAAS,CACP,CAAE,MAAON,EAAY,MAAO,YAAA,EAC5B,GAAI,CAACM,GAAqBE,IAAYR,EAClC,CAAC,CAAE,MAAOQ,EAAS,MAAOA,CAAA,CAAS,EACnC,CAAA,EACJ,GAAGH,EAAS,IAAK5E,IAAO,CAAE,MAAOA,EAAG,MAAOA,GAAI,CAAA,CACjD,CAAA,EAEJ,EACCyD,GAASM,EAAAA,IAAC,IAAA,CAAE,UAAU,wCAAyC,SAAAN,EAAM,EACtEQ,EAAAA,KAAC,MAAA,CAAI,UAAU,yBACb,SAAA,CAAAF,EAAAA,IAACO,EAAA,CAAO,KAAK,SAAS,QAAQ,QAAQ,QAASpB,EAAS,SAAU+B,EAAS,SAAA,QAAA,CAE3E,EACAlB,EAAAA,IAACO,EAAA,CAAO,KAAK,SAAS,QAAQ,UAAU,QAAS7C,EAAe,SAAUwD,EACvE,SAAAA,EAAU,aAAe,iBAAA,CAC5B,CAAA,CAAA,CACF,CAAA,CAAA,CACF,CAAA,CAAA,CAGN,EC1GaQ,GAAmB,CAAC,CAAE,MAAAC,KAAmC,CACpE,KAAM,CAACnE,EAAM6B,CAAO,EAAIvC,EAAAA,SAAS,EAAE,EAC7B,CAAC0C,EAAQC,CAAS,EAAI3C,EAAAA,SAAS,EAAK,EAEpC+C,EAAY,SAAY,CAC5B,GAAKrC,EAAK,OACV,CAAAiC,EAAU,EAAI,EACd,GAAI,CACF,MAAMkC,EAAMnE,EAAK,MAAM,EACvB6B,EAAQ,EAAE,CACZ,QAAA,CACEI,EAAU,EAAK,CACjB,EACF,EAEA,OACES,EAAAA,KAAC,MAAA,CAAI,UAAU,aACb,SAAA,CAAAF,EAAAA,IAACK,EAAA,CACC,KAAK,QACL,MAAO7C,EACP,SAAW8C,GAAMjB,EAAQiB,EAAE,OAAO,KAAK,EACvC,UAAYA,GAAM,CACZA,EAAE,MAAQ,SAAST,EAAA,CACzB,EACA,YAAY,cACZ,SAAUL,EACV,UAAU,QAAA,CAAA,EAEZQ,EAAAA,IAACO,EAAA,CACC,KAAK,SACL,QAAQ,QACR,KAAK,QACL,QAASV,EACT,SAAUL,GAAU,CAAChC,EAAK,KAAA,EAC3B,SAAA,KAAA,CAAA,CAED,EACF,CAEJ,ECvCaoE,GAAe,CAAC,CAAE,KAAApE,EAAM,UAAAqE,CAAA,IACnC7B,EAAAA,IAAC8B,EAAA,CAAK,KAAK,QAAQ,QAAQ,QAAQ,UAAU,gBAC3C,SAAA5B,EAAAA,KAAC,MAAA,CAAI,UAAU,0BACb,SAAA,CAAAF,EAAAA,IAAC,OAAA,CAAK,UAAU,SAAU,SAAAxC,EAAK,EAC/BwC,EAAAA,IAACO,EAAA,CAAO,KAAK,SAAS,QAAQ,QAAQ,KAAK,QAAQ,QAASsB,EAAW,SAAA,iBAAA,CAEvE,CAAA,CAAA,CACF,CAAA,CACF,ECRWE,GAAa,CAAC,CAAE,KAAAC,KAA4B,CACvD,KAAM,CAACC,EAAUC,CAAW,EAAIpF,EAAAA,SAAS,EAAK,EACxC,CAACqF,EAAgB,GAAGC,CAAc,EAAIJ,EAAK,MAAM,QAAQ,EACzDK,EAAUD,EAAe,OAAS,EAExC,OACElC,EAAAA,KAAC,MAAA,CAAI,UAAU,uCACb,SAAA,CAAAF,EAAAA,IAAC,OAAA,CAAK,UAAU,wDAAwD,SAAA,WAAQ,EAChFE,EAAAA,KAAC,MAAA,CAAI,UAAU,0CACb,SAAA,CAAAF,EAAAA,IAACsC,GAAU,SAAAH,CAAA,CAAe,EACzBF,GAAYI,GAAWrC,EAAAA,IAACsC,GAAU,SAAAF,EAAe,KAAK;AAAA;AAAA,CAAM,CAAA,CAAE,CAAA,EACjE,EACCC,GACCrC,EAAAA,IAAC,SAAA,CACC,KAAK,SACL,QAAS,IAAMkC,EAAaK,GAAM,CAACA,CAAC,EACpC,UAAU,uFAET,WAAW,YAAc,WAAA,CAAA,CAC5B,EAEJ,CAEJ,EC9BaC,GAA0B,iCAE1BC,EAAkB,CAC7B,KAAM,sBACN,KAAM,qBACR,ECSaC,GAAa,CAACC,EAAsBC,IAAyC,CACxF,MAAMC,MAAkB,IAClBC,EAAuBF,EAAU,IAAKG,IACtCA,EAAK,IAAIF,EAAY,IAAIE,EAAK,EAAE,EAChCA,EAAK,MAAMF,EAAY,IAAIE,EAAK,IAAI,EACjC,CACL,IAAKA,EAAK,MACV,MAAOA,EAAK,MACZ,OAAQA,EAAK,OACb,GAAIA,EAAK,GACT,OAAQA,EAAK,GACb,UAAWA,EAAK,KAAA,EAEnB,EACD,UAAWC,KAAQL,EACbE,EAAY,IAAIG,EAAK,EAAE,GAC3BF,EAAO,KAAK,CAAE,IAAKE,EAAK,GAAI,MAAOA,EAAK,GAAI,OAAQA,EAAK,OAAQ,GAAIA,EAAK,GAAI,EAEhF,OAAOF,CACT,EAOaG,GAAU,CAAC,CAAE,KAAA1B,EAAM,OAAA2B,CAAA,IAC9BlD,EAAAA,IAAC8B,EAAA,CAAK,KAAK,QAAQ,QAAQ,QAAQ,UAAU,gBAC3C,SAAA5B,EAAAA,KAAC,MAAA,CAAI,UAAU,0BACZ,SAAA,CAAAgD,EACClD,EAAAA,IAAC,SAAA,CACC,KAAK,SACL,QAASkD,EACT,UAAU,qJAET,SAAA3B,EAAK,KAAA,CAAA,EAGRvB,EAAAA,IAAC,OAAA,CAAK,UAAU,iEACb,WAAK,MACR,EAEDuB,EAAK,IAAMvB,MAACmD,EAAA,CAAQ,GAAI5B,EAAK,GAAI,EAClCvB,EAAAA,IAACoD,EAAA,CACC,KAAK,QACL,UAAWC,EAAa9B,EAAK,MAAM,EAAE,KACrC,UAAW8B,EAAa9B,EAAK,MAAM,EAAE,KAEpC,SAAA+B,EAAa/B,EAAK,MAAM,CAAA,CAAA,CAC3B,CAAA,CACF,CAAA,CACF,EC5DWgC,GAAc,CAAC,CAAE,KAAAC,EAAM,MAAAC,KAA8B,CAChE,MAAMC,EAAUD,EAAQ,EAAI,KAAK,MAAOD,EAAOC,EAAS,GAAG,EAAI,EAC/D,OACEzD,EAAAA,IAAC,MAAA,CAAI,UAAU,mEACb,SAAAA,EAAAA,IAAC,MAAA,CACC,UAAW,uBAAuByD,EAAQ,EAAI,sBAAwB,gBAAgB,GACtF,MAAO,CAAE,MAAO,GAAGC,CAAO,GAAA,CAAI,CAAA,EAElC,CAEJ,ECLMC,GAAoBf,IAA4B,CACpD,QAASA,EAAU,OAAQxF,GAAMA,EAAE,SAAW,MAAM,EAAE,OACtD,OAAQwF,EAAU,OAAQxF,GAAMA,EAAE,SAAW,QAAUA,EAAE,SAAW,SAAS,EAAE,MACjF,GAEMwG,GAAmB,CAAC,CAAE,KAAAC,EAAO,MACjC7D,EAAAA,IAAC,MAAA,CACC,MAAO6D,EACP,OAAQA,EACR,QAAQ,YACR,KAAK,OACL,OAAO,eACP,YAAY,IACZ,cAAc,QACd,eAAe,QACf,cAAY,OAEZ,SAAA7D,EAAAA,IAAC,WAAA,CAAS,OAAO,gBAAA,CAAiB,CAAA,CACpC,EAaW8D,GAAiB,CAAC,CAC7B,KAAA3G,EACA,UAAAyF,EACA,YAAAmB,EACA,UAAAlC,EACA,mBAAAmC,EACA,eAAAC,EACA,gBAAAC,CACF,IAA2B,CACzB,KAAM,CAACjC,EAAUC,CAAW,EAAIpF,EAAAA,SAASiH,CAAW,EAC9C,CAAE,QAAAI,EAAS,OAAAC,GAAWT,GAAiBf,CAAS,EAChDyB,EAAalH,EAAK,WAAW,OAC7BmH,EAAQ5B,GAAWvF,EAAK,MAAOyF,CAAS,EAE9C7F,OAAAA,EAAAA,UAAU,IAAM,CACVgH,KAAyB,EAAI,CACnC,EAAG,CAACA,CAAW,CAAC,EAGd7D,EAAAA,KAAC,MAAA,CACC,UAAW,4CAA4C6D,EAAc,oEAAoEvB,EAAuB,GAAK,EAAE,GAEvK,SAAA,CAAAtC,EAAAA,KAAC,SAAA,CACC,KAAK,SACL,gBAAe+B,EACf,QAAS,IAAMC,EAAaK,GAAM,CAACA,CAAC,EACpC,UAAU,6HAEV,SAAA,CAAAvC,EAAAA,IAAC,OAAA,CACC,UAAW,gDAAgDiC,EAAW,YAAc,EAAE,GAEtF,eAAC2B,GAAA,CAAA,CAAiB,CAAA,CAAA,EAEpB5D,EAAAA,IAAC,OAAA,CAAK,UAAU,wCAAyC,WAAK,KAAK,EACnEA,EAAAA,IAACuD,IAAY,KAAMpG,EAAK,OAAO,KAAM,MAAOA,EAAK,OAAO,KAAA,CAAO,EAC9DiH,EAAS,GACRlE,EAAAA,KAACkD,EAAA,CACC,KAAK,QACL,UAAWC,EAAa,QAAQ,KAChC,UAAWA,EAAa,QAAQ,KAE/B,SAAA,CAAAe,EAAO,WAAA,CAAA,CAAA,EAGXD,EAAU,GACTjE,EAAAA,KAACkD,EAAA,CAAM,KAAK,QAAQ,UAAWC,EAAa,KAAK,KAAM,UAAWA,EAAa,KAAK,KACjF,SAAA,CAAAc,EAAQ,UAAA,EACX,EAEDE,EAAa,GACZnE,EAAAA,KAACkD,EAAA,CAAM,KAAK,QAAQ,UAAWX,EAAgB,KAAM,UAAWA,EAAgB,KAC7E,SAAA,CAAA4B,EAAW,aAAWA,IAAe,EAAI,GAAK,GAAA,CAAA,CACjD,CAAA,CAAA,CAAA,EAGHpC,GACC/B,EAAAA,KAAC,MAAA,CAAI,UAAU,gCACb,SAAA,CAAAF,EAAAA,IAAC,OAAA,CAAK,UAAU,qBAAsB,SAAA7C,EAAK,YAAY,EACtDmH,EAAM,IAAK/C,GACVvB,EAAAA,IAACiD,GAAA,CAEC,KAAA1B,EACA,OACEA,EAAK,UACD,IAAM2C,EAAgB3C,EAAK,OAAQA,EAAK,SAAmB,EAC3D,MAAA,EALDA,EAAK,GAAA,CAQb,EACApE,EAAK,WAAW,IAAKQ,GACpBqC,EAAAA,IAAC4B,GAAA,CAEC,KAAMjE,EACN,UAAW,IAAMqG,EAAmBrG,CAAa,CAAA,EAF5CA,CAAA,CAIR,EACDqC,EAAAA,IAAC0B,GAAA,CAAiB,MAAOuC,CAAA,CAAgB,EACzCjE,EAAAA,IAACO,EAAA,CACC,KAAK,SACL,QAAQ,QACR,KAAK,QACL,QAASsB,EACT,UAAU,aACX,SAAA,iBAAA,CAAA,CAED,CAAA,CACF,CAAA,CAAA,CAAA,CAIR,EChIM0C,GACJ,gFAWWC,GAAiB,CAAC,CAC7B,QAAAxG,EACA,gBAAAxB,EACA,gBAAAU,EACA,UAAA2E,EACA,eAAAoC,EACA,gBAAAC,CACF,IACEhE,EAAAA,KAAC,MAAA,CAAI,UAAU,sBACb,SAAA,CAAAF,EAAAA,IAAC,MAAA,CAAI,UAAWuE,GAAyB,SAAAvG,EAAQ,MAAM,EACvDgC,EAAAA,IAAC,OAAI,UAAU,gBACZ,WAAQ,MAAM,IAAK7C,GAClB6C,EAAAA,IAAC8D,GAAA,CAEC,KAAA3G,EACA,UAAWD,EAAgBC,CAAI,EAC/B,YAAaA,EAAK,OAASX,EAC3B,UAAW,IAAMqF,EAAU1E,CAAI,EAC/B,mBAAqBQ,GAAkBkE,EAAU1E,EAAMQ,CAAa,EACpE,eAAiBH,GAASyG,EAAe9G,EAAK,KAAMK,CAAI,EACxD,gBAAA0G,CAAA,EAPK/G,EAAK,IAAA,CASb,CAAA,CACH,CAAA,EACF,EClCWsH,GAAc,IAAM,CAC/B,KAAM,CACJ,QAAA1I,EACA,aAAAG,EACA,YAAAC,EACA,SAAAyB,EACA,aAAAE,EACA,iBAAAG,EACA,gBAAAzB,EACA,aAAAE,EACA,UAAAE,EACA,aAAAC,EACA,gBAAAK,EACA,mBAAAG,EACA,cAAAK,EACA,gBAAAwG,CAAA,EACEpI,EAAA,EAEJ,OAAII,SAEC,MAAA,CACC,SAAA,CAAA8D,EAAAA,IAAC0E,GAAU,SAAA,SAAA,CAAO,EAClB1E,EAAAA,IAAC,IAAA,CAAE,UAAU,aAAa,SAAA,kFAAA,CAE1B,CAAA,EACF,EAICjE,EASDA,EAAQ,SAAS,SAAW,SAE3B,MAAA,CACC,SAAA,CAAAiE,EAAAA,IAAC0E,GAAU,SAAA,SAAA,CAAO,EAClB1E,EAAAA,IAAC,IAAA,CAAE,UAAU,aAAa,SAAA,4CAAA,CAA0C,CAAA,EACtE,EAKFE,EAAAA,KAAC,MAAA,CAAI,IAAKxD,EACR,SAAA,CAAAsD,EAAAA,IAAC0E,GAAU,SAAA,SAAA,CAAO,EAClB1E,EAAAA,IAAC+B,GAAA,CAAW,KAAMhG,EAAQ,IAAA,CAAM,EAC/B+B,IAAiB,EAChBkC,EAAAA,IAAC,IAAA,CAAE,UAAU,mCACV,SAAA/B,EACG,0EACA,kDAAA,CACN,EAEA+B,EAAAA,IAAC,MAAA,CAAI,UAAU,sBACZ,SAAApC,EACE,OAAQI,GAAYA,EAAQ,MAAM,OAAS,CAAC,EAC5C,IAAKA,GACJgC,EAAAA,IAACwE,GAAA,CAEC,QAAAxG,EACA,gBAAAxB,EACA,gBAAAU,EACA,UAAW,CAACC,EAAMQ,IAChBD,EAAcM,EAAQ,MAAOb,EAAMQ,CAAa,EAElD,eAAgB,CAACJ,EAAUC,IACzBH,EAAmBW,EAAQ,MAAOT,EAAUC,CAAI,EAElD,gBAAA0G,CAAA,EAVKlG,EAAQ,KAAA,CAYhB,EACL,EAEFgC,EAAAA,IAACS,EAAA,CACC,cAAc7D,GAAA,YAAAA,EAAW,eAAgB,KACzC,MAAMA,GAAA,YAAAA,EAAW,OAAQ,KACzB,cAAeA,GAAA,YAAAA,EAAW,cAC1B,QAAS,IAAMC,EAAa,IAAI,EAChC,WAAYV,CAAA,CAAA,CACd,EACF,SAtDG,MAAA,CACC,SAAA,CAAA6D,EAAAA,IAAC0E,GAAU,SAAA,SAAA,CAAO,EAClB1E,EAAAA,IAAC,IAAA,CAAE,UAAU,aAAa,SAAA,UAAA,CAAQ,CAAA,EACpC,CAqDN,ECtFM2E,EAAoB,qEAEbC,GAAiB,IAAM,CAClC,KAAM,CACJ,QAAA7I,EACA,cAAAyC,EACA,cAAAC,EACA,aAAAE,EACA,eAAAE,EACA,eAAAC,EACA,gBAAAC,EACA,QAAAT,EACA,WAAAC,EACA,qBAAAH,EACA,oBAAAC,CAAA,EACEF,EAAA,EAEJ,OAAKpC,EAGHmE,EAAAA,KAAC,MAAA,CAAI,UAAU,gBACb,SAAA,CAAAF,EAAAA,IAAC,MAAA,CAAI,UAAU,6BACb,SAAAA,EAAAA,IAACO,EAAA,CACC,KAAK,SACL,QAAQ,UACR,KAAK,QACL,QAAS,IAAMhC,EAAW,EAAI,EAC9B,SAAUC,EAAc,SAAW,EACpC,SAAA,YAAA,CAAA,EAGH,SAEC,MAAA,CACC,SAAA,CAAAwB,EAAAA,IAAC,MAAA,CAAI,UAAW2E,EAAmB,SAAA,UAAO,QACzC,MAAA,CAAI,UAAU,gBACZ,SAAAnG,EAAc,IAAK4B,GAClBJ,EAAAA,IAAC6E,EAAA,CAEC,KAAK,QACL,OAAQhG,EAAe,IAAIuB,CAAK,EAChC,QAAS,IAAMhC,EAAqBgC,CAAK,EACzC,UAAU,iBACV,aAAS,OAAA,CAAK,UAAU,wBAAyB,SAAA3B,EAAc2B,CAAK,GAAK,EAAE,EAE1E,SAAAA,CAAA,EAPIA,CAAA,CASR,CAAA,CACH,CAAA,EACF,SAEC,MAAA,CACC,SAAA,CAAAJ,EAAAA,IAAC,MAAA,CAAI,UAAW2E,EAAmB,SAAA,SAAM,EACzCzE,EAAAA,KAAC,MAAA,CAAI,UAAU,gBACZ,SAAA,CAAAnB,EAAgB,SAAW,GAC1BiB,MAAC,OAAA,CAAK,UAAU,sBAAsB,SAAA,kBAAe,EAEtDjB,EAAgB,IAAKC,GACpBgB,EAAAA,IAAC6E,EAAA,CAEC,KAAK,QACL,OAAQ/F,EAAe,IAAIE,CAAM,EACjC,QAAS,IAAMX,EAAoBW,CAAM,EACzC,UAAU,iBACV,KACEgB,EAAAA,IAAC,OAAA,CACC,UAAU,wCACV,MAAO,CAAE,WAAYqD,EAAarE,CAAM,EAAE,IAAA,CAAK,CAAA,EAGnD,aAAS,OAAA,CAAK,UAAU,wBAAyB,SAAAL,EAAaK,CAAM,GAAK,EAAE,EAE1E,WAAaA,CAAM,CAAA,EAbfA,CAAA,CAeR,CAAA,CAAA,CACH,CAAA,EACF,EAEAgB,EAAAA,IAACf,EAAA,CACC,KAAMX,EACN,cAAAE,EACA,QAAS,IAAMD,EAAW,EAAK,CAAA,CAAA,CACjC,EACF,EAlEmB,IAoEvB"}
|
|
1
|
+
{"version":3,"file":"index-B0T4zOOc.js","sources":["../../../src/app/features/roadmap/hooks/use-roadmap-page.ts","../../../src/app/features/roadmap/hooks/use-roadmap-sidebar.ts","../../../src/app/features/roadmap/modals/add-roadmap-item-modal.tsx","../../../src/app/features/roadmap/modals/promote-roadmap-item-modal.tsx","../../../src/app/features/roadmap/views/add-candidate-form.tsx","../../../src/app/features/roadmap/views/candidate-row.tsx","../../../src/app/features/roadmap/views/goal-banner.tsx","../../../src/app/features/roadmap/constants.ts","../../../src/app/features/roadmap/views/idea-row.tsx","../../../src/app/features/roadmap/views/progress-bar.tsx","../../../src/app/features/roadmap/views/roadmap-item-row.tsx","../../../src/app/features/roadmap/views/horizon-section.tsx","../../../src/app/features/roadmap/roadmap-page.tsx","../../../src/app/features/roadmap/roadmap-sidebar.tsx"],"sourcesContent":["import { useOpenEntity } from '@/app/hooks';\nimport { addRoadmapCandidate } from '@/app/services/content/docs-api';\nimport { useAppStore } from '@/app/stores/app-store';\nimport type { PlanEntry, ResolvedRoadmapItem } from '@/types/index';\nimport { useSearch } from '@tanstack/react-router';\nimport { useEffect, useRef, useState } from 'react';\nimport { filterHorizons } from '../helpers';\n\ninterface Promoting {\n horizonTitle: string;\n item: ResolvedRoadmapItem;\n candidateName?: string;\n}\n\nexport const useRoadmapPage = () => {\n const roadmap = useAppStore((s) => s.roadmap);\n const roadmapError = useAppStore((s) => s.roadmapError);\n const loadRoadmap = useAppStore((s) => s.loadRoadmap);\n const filters = useAppStore((s) => s.roadmapFilters);\n const plans = useAppStore((s) => s.plans);\n const openEntity = useOpenEntity();\n const { item: highlightedItem } = useSearch({ from: '/roadmap' });\n const containerRef = useRef<HTMLDivElement>(null);\n const [promoting, setPromoting] = useState<Promoting | null>(null);\n\n useEffect(() => {\n loadRoadmap();\n }, [loadRoadmap]);\n\n useEffect(() => {\n if (!highlightedItem || !roadmap) return;\n const row = containerRef.current?.querySelector('.roadmap-item-highlighted');\n row?.scrollIntoView({ behavior: 'smooth', block: 'center' });\n }, [highlightedItem, roadmap]);\n\n const graduatedByItem = (item: ResolvedRoadmapItem): PlanEntry[] =>\n plans?.entries.filter((p) => p.subject === item.name) ?? [];\n\n const handleAddCandidate = async (horizonTitle: string, itemName: string, name: string) => {\n await addRoadmapCandidate(horizonTitle, itemName, name);\n await loadRoadmap();\n };\n\n const handlePromote = (\n horizonTitle: string,\n item: ResolvedRoadmapItem,\n candidateName?: string,\n ) => {\n setPromoting({ horizonTitle, item, candidateName });\n };\n\n const horizons = roadmap ? filterHorizons(roadmap, filters) : [];\n const totalVisible = horizons.reduce((count, horizon) => count + horizon.items.length, 0);\n const hasActiveFilters = filters.horizons.length > 0 || filters.statuses.length > 0;\n\n return {\n roadmap,\n roadmapError,\n loadRoadmap,\n horizons,\n totalVisible,\n hasActiveFilters,\n highlightedItem,\n containerRef,\n promoting,\n setPromoting,\n graduatedByItem,\n handleAddCandidate,\n handlePromote,\n onOpenGraduated: openEntity,\n };\n};\n","import { useAppStore } from '@/app/stores/app-store';\nimport type { PlanStatus } from '@/types/index';\nimport { useState } from 'react';\nimport { horizonItemCounts, statusItemCounts } from '../helpers';\n\nconst STATUS_CHIP_ORDER: PlanStatus[] = [\n 'in-progress',\n 'review',\n 'planned',\n 'idea',\n 'done',\n 'dropped',\n];\n\nexport const useRoadmapSidebar = () => {\n const roadmap = useAppStore((s) => s.roadmap);\n const filters = useAppStore((s) => s.roadmapFilters);\n const toggleRoadmapHorizon = useAppStore((s) => s.toggleRoadmapHorizon);\n const toggleRoadmapStatus = useAppStore((s) => s.toggleRoadmapStatus);\n const [addOpen, setAddOpen] = useState(false);\n\n const horizonTitles = roadmap?.horizons.map((horizon) => horizon.title) ?? [];\n const horizonCounts = roadmap ? horizonItemCounts(roadmap, filters) : {};\n const statusCounts = roadmap ? statusItemCounts(roadmap, filters) : {};\n const activeHorizons = new Set(filters.horizons);\n const activeStatuses = new Set(filters.statuses);\n const visibleStatuses = STATUS_CHIP_ORDER.filter(\n (status) => (statusCounts[status] ?? 0) > 0 || activeStatuses.has(status),\n );\n\n return {\n roadmap,\n horizonTitles,\n horizonCounts,\n statusCounts,\n activeHorizons,\n activeStatuses,\n visibleStatuses,\n addOpen,\n setAddOpen,\n toggleRoadmapHorizon,\n toggleRoadmapStatus,\n };\n};\n","import { addRoadmapItem } from '@/app/services/content/docs-api';\nimport { useAppStore } from '@/app/stores/app-store';\nimport { Button, Input, Modal, Select } from '@dendelion/paper-ui';\nimport { useEffect, useRef, useState } from 'react';\n\ninterface AddRoadmapItemModalProps {\n open: boolean;\n horizonTitles: string[];\n onClose: () => void;\n}\n\nexport const AddRoadmapItemModal = ({ open, horizonTitles, onClose }: AddRoadmapItemModalProps) => {\n const loadRoadmap = useAppStore((s) => s.loadRoadmap);\n const [horizon, setHorizon] = useState(horizonTitles[0] ?? '');\n const [name, setName] = useState('');\n const [description, setDescription] = useState('');\n const [saving, setSaving] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const horizonTitlesRef = useRef(horizonTitles);\n horizonTitlesRef.current = horizonTitles;\n\n useEffect(() => {\n if (open) {\n setHorizon(horizonTitlesRef.current[0] ?? '');\n setName('');\n setDescription('');\n setError(null);\n setSaving(false);\n }\n }, [open]);\n\n const handleAdd = async () => {\n if (!name.trim() || !horizon) return;\n setSaving(true);\n setError(null);\n try {\n await addRoadmapItem(horizon, name.trim(), description.trim());\n await loadRoadmap();\n onClose();\n } catch (err) {\n setError((err as Error).message);\n } finally {\n setSaving(false);\n }\n };\n\n return (\n <Modal open={open} onClose={onClose} title=\"Add roadmap item\" size=\"small\">\n <div className=\"flex flex-col gap-4\">\n <Select\n size=\"small\"\n value={horizon}\n onChange={setHorizon}\n disabled={saving}\n options={horizonTitles.map((title) => ({ value: title, label: title }))}\n />\n <Input\n size=\"small\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n placeholder=\"Item name…\"\n disabled={saving}\n autoFocus\n />\n <Input\n size=\"small\"\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === 'Enter') handleAdd();\n }}\n placeholder=\"Description…\"\n disabled={saving}\n />\n {error && <p className=\"m-0 text-watercolor-rose-dark text-sm\">{error}</p>}\n <div className=\"flex justify-end gap-2\">\n <Button type=\"button\" variant=\"ghost\" onClick={onClose} disabled={saving}>\n Cancel\n </Button>\n <Button\n type=\"button\"\n variant=\"primary\"\n onClick={handleAdd}\n disabled={saving || !name.trim() || !horizon}\n >\n {saving ? 'Adding…' : 'Add item'}\n </Button>\n </div>\n </div>\n </Modal>\n );\n};\n","import { buildRoadmapPromotePrompt } from '@/app/features/plans/prompts';\nimport { useSubjectVocabulary } from '@/app/hooks/use-subject-vocabulary';\nimport { useAppStore } from '@/app/stores/app-store';\nimport { oneLineErrorSummary } from '@/app/utils/error-summary';\nimport type { RoadmapItem } from '@/types/index';\nimport { Button, Modal, Select, useToast } from '@dendelion/paper-ui';\nimport { useEffect, useState } from 'react';\n\nconst NO_SUBJECT = '__no-subject__';\n\ninterface PromoteRoadmapItemModalProps {\n horizonTitle: string | null;\n item: RoadmapItem | null;\n candidateName?: string | null;\n onClose: () => void;\n onPromoted: () => void;\n}\n\nexport const PromoteRoadmapItemModal = ({\n horizonTitle,\n item,\n candidateName,\n onClose,\n onPromoted,\n}: PromoteRoadmapItemModalProps) => {\n const promoteRoadmapItem = useAppStore((s) => s.promoteRoadmapItem);\n const launchIdeaExtend = useAppStore((s) => s.launchIdeaExtend);\n const { subjects, available: subjectsAvailable } = useSubjectVocabulary();\n const [subject, setSubject] = useState(NO_SUBJECT);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const { toast } = useToast();\n\n useEffect(() => {\n if (item) {\n // A candidate defaults to its parent item's name — the \"big bet becomes a\n // Subject\" rule — but the picker still lets the user override it.\n setSubject(candidateName ? item.name : NO_SUBJECT);\n setLoading(false);\n setError(null);\n }\n }, [item, candidateName]);\n\n const handlePromote = async () => {\n if (!item || !horizonTitle) return;\n setLoading(true);\n setError(null);\n try {\n const id = await promoteRoadmapItem(\n horizonTitle,\n item,\n subject === NO_SUBJECT ? undefined : subject,\n candidateName ?? undefined,\n );\n const idea = useAppStore.getState().ideaEntries.find((e) => e.id === id);\n if (idea) {\n try {\n await launchIdeaExtend(id, buildRoadmapPromotePrompt(idea, horizonTitle));\n } catch (err) {\n // The idea was created either way — a failed refine launch just means\n // no background research ran, not that the promotion itself failed.\n toast({\n title: 'Idea created, but the refine agent failed to launch',\n description: oneLineErrorSummary((err as Error).message),\n variant: 'error',\n });\n }\n }\n onPromoted();\n onClose();\n } catch (err) {\n setError((err as Error).message);\n } finally {\n setLoading(false);\n }\n };\n\n return (\n <Modal\n open={item !== null}\n onClose={onClose}\n title={candidateName ?? item?.name ?? ''}\n size=\"small\"\n >\n <div className=\"flex flex-col gap-4\">\n {!candidateName && <p className=\"m-0 opacity-80\">{item?.description}</p>}\n <div>\n <Select\n size=\"small\"\n value={subject}\n onChange={setSubject}\n disabled={loading || !subjectsAvailable}\n options={[\n { value: NO_SUBJECT, label: 'No subject' },\n ...(!subjectsAvailable && subject !== NO_SUBJECT\n ? [{ value: subject, label: subject }]\n : []),\n ...subjects.map((s) => ({ value: s, label: s })),\n ]}\n />\n </div>\n {error && <p className=\"m-0 text-watercolor-rose-dark text-sm\">{error}</p>}\n <div className=\"flex justify-end gap-2\">\n <Button type=\"button\" variant=\"ghost\" onClick={onClose} disabled={loading}>\n Cancel\n </Button>\n <Button type=\"button\" variant=\"primary\" onClick={handlePromote} disabled={loading}>\n {loading ? 'Promoting…' : 'Promote to idea'}\n </Button>\n </div>\n </div>\n </Modal>\n );\n};\n","import { Button, Input } from '@dendelion/paper-ui';\nimport { useState } from 'react';\n\ninterface AddCandidateFormProps {\n onAdd: (name: string) => Promise<void>;\n}\n\nexport const AddCandidateForm = ({ onAdd }: AddCandidateFormProps) => {\n const [name, setName] = useState('');\n const [saving, setSaving] = useState(false);\n\n const handleAdd = async () => {\n if (!name.trim()) return;\n setSaving(true);\n try {\n await onAdd(name.trim());\n setName('');\n } finally {\n setSaving(false);\n }\n };\n\n return (\n <div className=\"flex gap-2\">\n <Input\n size=\"small\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === 'Enter') handleAdd();\n }}\n placeholder=\"Add option…\"\n disabled={saving}\n className=\"flex-1\"\n />\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"small\"\n onClick={handleAdd}\n disabled={saving || !name.trim()}\n >\n Add\n </Button>\n </div>\n );\n};\n","import { Button, Card } from '@dendelion/paper-ui';\n\ninterface CandidateRowProps {\n name: string;\n onPromote: () => void;\n}\n\nexport const CandidateRow = ({ name, onPromote }: CandidateRowProps) => (\n <Card size=\"small\" texture=\"kraft\" className=\"plan-row-card\">\n <div className=\"flex items-center gap-3\">\n <span className=\"flex-1\">{name}</span>\n <Button type=\"button\" variant=\"ghost\" size=\"small\" onClick={onPromote}>\n Promote to idea\n </Button>\n </div>\n </Card>\n);\n","import { Markdown } from '@/app/components/markdown';\nimport { useState } from 'react';\n\ninterface GoalBannerProps {\n goal: string;\n}\n\nexport const GoalBanner = ({ goal }: GoalBannerProps) => {\n const [expanded, setExpanded] = useState(false);\n const [firstParagraph, ...restParagraphs] = goal.split(/\\n{2,}/);\n const hasMore = restParagraphs.length > 0;\n\n return (\n <div className=\"mb-6 pb-4 border-b border-black/[8%]\">\n <span className=\"font-handwritten text-xs font-semibold opacity-[0.55]\">The goal</span>\n <div className=\"text-sm leading-relaxed opacity-80 mt-2\">\n <Markdown>{firstParagraph}</Markdown>\n {expanded && hasMore && <Markdown>{restParagraphs.join('\\n\\n')}</Markdown>}\n </div>\n {hasMore && (\n <button\n type=\"button\"\n onClick={() => setExpanded((v) => !v)}\n className=\"bg-transparent border-none p-0 mt-2 cursor-pointer text-2xs opacity-[0.65] underline\"\n >\n {expanded ? 'Show less' : 'Show more'}\n </button>\n )}\n </div>\n );\n};\n","export const HIGHLIGHT_OUTLINE_CLASS = 'outline-[rgba(200,154,90,0.5)]';\n\nexport const CANDIDATE_STAMP = {\n fill: 'rgba(0, 0, 0, 0.06)',\n text: 'rgba(0, 0, 0, 0.55)',\n};\n","import { PrBadge } from '@/app/features/plans/components/pr-badge';\nimport { STATUS_LABEL, STATUS_STAMP } from '@/app/features/plans/constants';\nimport type { PlanEntry, PlanStatus, PrInfo, RoadmapLink } from '@/types/index';\nimport { Card, Stamp } from '@dendelion/paper-ui';\n\nexport interface MergedIdea {\n key: string;\n label: string;\n status: PlanStatus;\n pr?: PrInfo;\n planId?: string;\n planTitle?: string;\n}\n\nexport const mergeIdeas = (links: RoadmapLink[], graduated: PlanEntry[]): MergedIdea[] => {\n const represented = new Set<string>();\n const merged: MergedIdea[] = graduated.map((plan) => {\n if (plan.id) represented.add(plan.id);\n if (plan.idea) represented.add(plan.idea);\n return {\n key: plan.title,\n label: plan.title,\n status: plan.status,\n pr: plan.pr,\n planId: plan.id,\n planTitle: plan.title,\n };\n });\n for (const link of links) {\n if (represented.has(link.id)) continue;\n merged.push({ key: link.id, label: link.id, status: link.status, pr: link.pr });\n }\n return merged;\n};\n\ninterface IdeaRowProps {\n idea: MergedIdea;\n onOpen?: () => void;\n}\n\nexport const IdeaRow = ({ idea, onOpen }: IdeaRowProps) => (\n <Card size=\"small\" texture=\"kraft\" className=\"plan-row-card\">\n <div className=\"flex items-center gap-3\">\n {onOpen ? (\n <button\n type=\"button\"\n onClick={onOpen}\n className=\"flex-1 min-w-0 overflow-hidden text-ellipsis whitespace-nowrap bg-transparent border-none p-0 cursor-pointer [font:inherit] text-inherit text-left\"\n >\n {idea.label}\n </button>\n ) : (\n <span className=\"flex-1 min-w-0 overflow-hidden text-ellipsis whitespace-nowrap\">\n {idea.label}\n </span>\n )}\n {idea.pr && <PrBadge pr={idea.pr} />}\n <Stamp\n size=\"small\"\n fillColor={STATUS_STAMP[idea.status].fill}\n textColor={STATUS_STAMP[idea.status].text}\n >\n {STATUS_LABEL[idea.status]}\n </Stamp>\n </div>\n </Card>\n);\n","interface ProgressBarProps {\n done: number;\n total: number;\n}\n\nexport const ProgressBar = ({ done, total }: ProgressBarProps) => {\n const percent = total > 0 ? Math.round((done / total) * 100) : 0;\n return (\n <div className=\"w-24 h-1.5 rounded-full bg-black/[0.08] overflow-hidden shrink-0\">\n <div\n className={`h-full rounded-full ${total > 0 ? 'bg-watercolor-green' : 'bg-transparent'}`}\n style={{ width: `${percent}%` }}\n />\n </div>\n );\n};\n","import { STATUS_STAMP } from '@/app/features/plans/constants';\nimport type { PlanEntry, ResolvedRoadmapItem } from '@/types/index';\nimport { Button, Stamp } from '@dendelion/paper-ui';\nimport { useEffect, useState } from 'react';\nimport { CANDIDATE_STAMP, HIGHLIGHT_OUTLINE_CLASS } from '../constants';\nimport { AddCandidateForm } from './add-candidate-form';\nimport { CandidateRow } from './candidate-row';\nimport { IdeaRow, mergeIdeas } from './idea-row';\nimport { ProgressBar } from './progress-bar';\n\nconst graduationCounts = (graduated: PlanEntry[]) => ({\n shipped: graduated.filter((p) => p.status === 'done').length,\n queued: graduated.filter((p) => p.status !== 'done' && p.status !== 'dropped').length,\n});\n\nconst ChevronRightIcon = ({ size = 14 }: { size?: number }) => (\n <svg\n width={size}\n height={size}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n <polyline points=\"9 18 15 12 9 6\" />\n </svg>\n);\n\ninterface RoadmapItemRowProps {\n item: ResolvedRoadmapItem;\n graduated: PlanEntry[];\n highlighted: boolean;\n onPromote: () => void;\n onPromoteCandidate: (candidateName: string) => void;\n onAddCandidate: (name: string) => Promise<void>;\n onOpenGraduated: (id: string | undefined, title: string) => void;\n}\n\nexport const RoadmapItemRow = ({\n item,\n graduated,\n highlighted,\n onPromote,\n onPromoteCandidate,\n onAddCandidate,\n onOpenGraduated,\n}: RoadmapItemRowProps) => {\n const [expanded, setExpanded] = useState(highlighted);\n const { shipped, queued } = graduationCounts(graduated);\n const candidates = item.candidates.length;\n const ideas = mergeIdeas(item.links, graduated);\n\n useEffect(() => {\n if (highlighted) setExpanded(true);\n }, [highlighted]);\n\n return (\n <div\n className={`border-b border-black/10 last:border-b-0 ${highlighted ? `roadmap-item-highlighted outline outline-2 outline-offset-[-2px] ${HIGHLIGHT_OUTLINE_CLASS}` : ''}`}\n >\n <button\n type=\"button\"\n aria-expanded={expanded}\n onClick={() => setExpanded((v) => !v)}\n className=\"flex w-full items-center gap-3 py-2.5 px-0 bg-transparent border-none cursor-pointer text-left [font:inherit] text-inherit\"\n >\n <span\n className={`inline-flex items-center opacity-50 shrink-0 ${expanded ? 'rotate-90' : ''}`}\n >\n <ChevronRightIcon />\n </span>\n <span className=\"font-semibold flex-1 min-w-0 truncate\">{item.name}</span>\n <ProgressBar done={item.rollup.done} total={item.rollup.total} />\n {queued > 0 && (\n <Stamp\n size=\"small\"\n fillColor={STATUS_STAMP.planned.fill}\n textColor={STATUS_STAMP.planned.text}\n >\n {queued} in queue\n </Stamp>\n )}\n {shipped > 0 && (\n <Stamp size=\"small\" fillColor={STATUS_STAMP.done.fill} textColor={STATUS_STAMP.done.text}>\n {shipped} shipped\n </Stamp>\n )}\n {candidates > 0 && (\n <Stamp size=\"small\" fillColor={CANDIDATE_STAMP.fill} textColor={CANDIDATE_STAMP.text}>\n {candidates} candidate{candidates === 1 ? '' : 's'}\n </Stamp>\n )}\n </button>\n {expanded && (\n <div className=\"flex flex-col gap-1 pl-6 pb-4\">\n <span className=\"text-sm opacity-70\">{item.description}</span>\n {ideas.map((idea) => (\n <IdeaRow\n key={idea.key}\n idea={idea}\n onOpen={\n idea.planTitle\n ? () => onOpenGraduated(idea.planId, idea.planTitle as string)\n : undefined\n }\n />\n ))}\n {item.candidates.map((candidateName) => (\n <CandidateRow\n key={candidateName}\n name={candidateName}\n onPromote={() => onPromoteCandidate(candidateName)}\n />\n ))}\n <AddCandidateForm onAdd={onAddCandidate} />\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"small\"\n onClick={onPromote}\n className=\"self-start\"\n >\n Promote to idea\n </Button>\n </div>\n )}\n </div>\n );\n};\n","import type { PlanEntry, ResolvedRoadmapHorizon, ResolvedRoadmapItem } from '@/types/index';\nimport { RoadmapItemRow } from './roadmap-item-row';\n\nconst HORIZON_HEADER_CLASSES =\n 'font-handwritten text-md font-semibold opacity-70 leading-none pt-2 px-1 pb-0';\n\ninterface HorizonSectionProps {\n horizon: ResolvedRoadmapHorizon;\n highlightedItem: string | undefined;\n graduatedByItem: (item: ResolvedRoadmapItem) => PlanEntry[];\n onPromote: (item: ResolvedRoadmapItem, candidateName?: string) => void;\n onAddCandidate: (itemName: string, name: string) => Promise<void>;\n onOpenGraduated: (id: string | undefined, title: string) => void;\n}\n\nexport const HorizonSection = ({\n horizon,\n highlightedItem,\n graduatedByItem,\n onPromote,\n onAddCandidate,\n onOpenGraduated,\n}: HorizonSectionProps) => (\n <div className=\"flex flex-col gap-1\">\n <div className={HORIZON_HEADER_CLASSES}>{horizon.title}</div>\n <div className=\"flex flex-col\">\n {horizon.items.map((item) => (\n <RoadmapItemRow\n key={item.name}\n item={item}\n graduated={graduatedByItem(item)}\n highlighted={item.name === highlightedItem}\n onPromote={() => onPromote(item)}\n onPromoteCandidate={(candidateName) => onPromote(item, candidateName)}\n onAddCandidate={(name) => onAddCandidate(item.name, name)}\n onOpenGraduated={onOpenGraduated}\n />\n ))}\n </div>\n </div>\n);\n","import { PageTitle } from '@/app/components/page-title';\nimport { useRoadmapPage } from './hooks';\nimport { PromoteRoadmapItemModal } from './modals';\nimport { GoalBanner, HorizonSection } from './views';\n\nexport const RoadmapPage = () => {\n const {\n roadmap,\n roadmapError,\n loadRoadmap,\n horizons,\n totalVisible,\n hasActiveFilters,\n highlightedItem,\n containerRef,\n promoting,\n setPromoting,\n graduatedByItem,\n handleAddCandidate,\n handlePromote,\n onOpenGraduated,\n } = useRoadmapPage();\n\n if (roadmapError) {\n return (\n <div>\n <PageTitle>Roadmap</PageTitle>\n <p className=\"opacity-50\">\n Couldn't load the roadmap — the server may need a restart to pick up new routes.\n </p>\n </div>\n );\n }\n\n if (!roadmap) {\n return (\n <div>\n <PageTitle>Roadmap</PageTitle>\n <p className=\"opacity-50\">Loading…</p>\n </div>\n );\n }\n\n if (roadmap.horizons.length === 0) {\n return (\n <div>\n <PageTitle>Roadmap</PageTitle>\n <p className=\"opacity-50\">No `ROADMAP.md` found at the project root.</p>\n </div>\n );\n }\n\n return (\n <div ref={containerRef}>\n <PageTitle>Roadmap</PageTitle>\n <GoalBanner goal={roadmap.goal} />\n {totalVisible === 0 ? (\n <p className=\"opacity-50 py-6 px-0 text-center\">\n {hasActiveFilters\n ? 'Nothing matches these filters — clear one from the sidebar to see more.'\n : 'No roadmap items yet — add one from the sidebar.'}\n </p>\n ) : (\n <div className=\"flex flex-col gap-6\">\n {horizons\n .filter((horizon) => horizon.items.length > 0)\n .map((horizon) => (\n <HorizonSection\n key={horizon.title}\n horizon={horizon}\n highlightedItem={highlightedItem}\n graduatedByItem={graduatedByItem}\n onPromote={(item, candidateName) =>\n handlePromote(horizon.title, item, candidateName)\n }\n onAddCandidate={(itemName, name) =>\n handleAddCandidate(horizon.title, itemName, name)\n }\n onOpenGraduated={onOpenGraduated}\n />\n ))}\n </div>\n )}\n <PromoteRoadmapItemModal\n horizonTitle={promoting?.horizonTitle ?? null}\n item={promoting?.item ?? null}\n candidateName={promoting?.candidateName}\n onClose={() => setPromoting(null)}\n onPromoted={loadRoadmap}\n />\n </div>\n );\n};\n","import { STATUS_LABEL, STATUS_STAMP } from '@/app/features/plans/constants';\nimport { Button, ListItem } from '@dendelion/paper-ui';\nimport { useRoadmapSidebar } from './hooks';\nimport { AddRoadmapItemModal } from './modals';\n\n// Matches SidebarSection — handwritten, no caps, one grid cell.\nconst sectionLabelClass = 'pc-row-label font-handwritten text-xs font-semibold opacity-[0.45]';\n\nexport const RoadmapSidebar = () => {\n const {\n roadmap,\n horizonTitles,\n horizonCounts,\n statusCounts,\n activeHorizons,\n activeStatuses,\n visibleStatuses,\n addOpen,\n setAddOpen,\n toggleRoadmapHorizon,\n toggleRoadmapStatus,\n } = useRoadmapSidebar();\n\n if (!roadmap) return null;\n\n return (\n <div className=\"flex flex-col\">\n <div className=\"flex h-[64px] items-center\">\n <Button\n type=\"button\"\n variant=\"primary\"\n size=\"small\"\n onClick={() => setAddOpen(true)}\n disabled={horizonTitles.length === 0}\n >\n + Add item\n </Button>\n </div>\n\n <div>\n <div className={sectionLabelClass}>Horizon</div>\n <div className=\"flex flex-col\">\n {horizonTitles.map((title) => (\n <ListItem\n key={title}\n size=\"small\"\n active={activeHorizons.has(title)}\n onClick={() => toggleRoadmapHorizon(title)}\n className=\"pc-row text-xs\"\n action={<span className=\"text-2xs text-ink-500\">{horizonCounts[title] ?? 0}</span>}\n >\n {title}\n </ListItem>\n ))}\n </div>\n </div>\n\n <div>\n <div className={sectionLabelClass}>Status</div>\n <div className=\"flex flex-col\">\n {visibleStatuses.length === 0 && (\n <span className=\"opacity-50 text-2xs\">No linked ideas</span>\n )}\n {visibleStatuses.map((status) => (\n <ListItem\n key={status}\n size=\"small\"\n active={activeStatuses.has(status)}\n onClick={() => toggleRoadmapStatus(status)}\n className=\"pc-row text-xs\"\n icon={\n <span\n className=\"w-[9px] h-[9px] rounded-full shrink-0\"\n style={{ background: STATUS_STAMP[status].text }}\n />\n }\n action={<span className=\"text-2xs text-ink-500\">{statusCounts[status] ?? 0}</span>}\n >\n {STATUS_LABEL[status]}\n </ListItem>\n ))}\n </div>\n </div>\n\n <AddRoadmapItemModal\n open={addOpen}\n horizonTitles={horizonTitles}\n onClose={() => setAddOpen(false)}\n />\n </div>\n );\n};\n"],"names":["useRoadmapPage","roadmap","useAppStore","s","roadmapError","loadRoadmap","filters","plans","openEntity","useOpenEntity","highlightedItem","useSearch","containerRef","useRef","promoting","setPromoting","useState","useEffect","row","_a","graduatedByItem","item","p","handleAddCandidate","horizonTitle","itemName","name","addRoadmapCandidate","handlePromote","candidateName","horizons","filterHorizons","totalVisible","count","horizon","hasActiveFilters","STATUS_CHIP_ORDER","useRoadmapSidebar","toggleRoadmapHorizon","toggleRoadmapStatus","addOpen","setAddOpen","horizonTitles","horizonCounts","horizonItemCounts","statusCounts","statusItemCounts","activeHorizons","activeStatuses","visibleStatuses","status","AddRoadmapItemModal","open","onClose","setHorizon","setName","description","setDescription","saving","setSaving","error","setError","horizonTitlesRef","handleAdd","addRoadmapItem","err","jsx","Modal","jsxs","Select","title","Input","e","Button","NO_SUBJECT","PromoteRoadmapItemModal","onPromoted","promoteRoadmapItem","launchIdeaExtend","subjects","subjectsAvailable","useSubjectVocabulary","subject","setSubject","loading","setLoading","toast","useToast","id","idea","buildRoadmapPromotePrompt","oneLineErrorSummary","AddCandidateForm","onAdd","CandidateRow","onPromote","Card","GoalBanner","goal","expanded","setExpanded","firstParagraph","restParagraphs","hasMore","Markdown","v","HIGHLIGHT_OUTLINE_CLASS","CANDIDATE_STAMP","mergeIdeas","links","graduated","represented","merged","plan","link","IdeaRow","onOpen","PrBadge","Stamp","STATUS_STAMP","STATUS_LABEL","ProgressBar","done","total","percent","graduationCounts","ChevronRightIcon","size","RoadmapItemRow","highlighted","onPromoteCandidate","onAddCandidate","onOpenGraduated","shipped","queued","candidates","ideas","HORIZON_HEADER_CLASSES","HorizonSection","RoadmapPage","PageTitle","sectionLabelClass","RoadmapSidebar","ListItem"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import{u as i,a as S,j as e,J as V,r as j,f as w,d as u,M as R,b,P as L,i as $,p as v}from"./main-
|
|
1
|
+
import{u as i,a as S,j as e,J as V,r as j,f as w,d as u,M as R,b,P as L,i as $,p as v}from"./main-CDkrPxrg.js";import{S as g}from"./sidebar-section-7T-4hlR4.js";const N=(s,r)=>s.toLowerCase().includes(r.toLowerCase()),k=(s,r,a=120)=>{const o=s.toLowerCase().indexOf(r.toLowerCase());if(o===-1)return s.slice(0,a);const c=Math.max(0,o-40),l=Math.min(s.length,o+r.length+40);let h=s.slice(c,l);return c>0&&(h=`…${h}`),l<s.length&&(h=`${h}…`),h},T=({query:s})=>{const r=i(n=>n.repoDocs),a=i(n=>n.setActiveDocTitle),o=i(n=>n.setDocSearchQuery),c=S(),l=[];for(const n of r)(N(n.name,s)||N(n.content,s))&&l.push({title:n.name,snippet:k(n.content,s)});const h=n=>{c({to:"/docs/$section",params:{section:"repo-docs"}}),a(n),o("")};return l.length===0?e.jsxs("p",{className:"opacity-50",children:['No results found for "',s,'".']}):e.jsxs("div",{children:[e.jsxs("p",{className:"mb-3 text-sm opacity-50",children:[l.length," result",l.length===1?"":"s",' for "',s,'"']}),e.jsx("div",{className:"flex flex-col gap-1",children:l.map(n=>e.jsx(V,{variant:"ghost",size:"small",fullWidth:!0,onClick:()=>h(n.title),className:"justify-start px-3 py-2",children:e.jsxs("span",{className:"text-left",children:[e.jsx("span",{className:"mb-[0.2rem] block font-display-luminari text-[0.95rem] font-semibold",children:n.title}),e.jsx("span",{className:"text-sm opacity-60",children:n.snippet})]})},n.title))})]})},C=s=>{const[r,a]=j.useState(null);return j.useEffect(()=>{if(a(null),!s)return;let o=!1;return w(s).then(c=>{o||a(c)}).catch(()=>{}),()=>{o=!0}},[s]),r},Q=()=>{const s=i(o=>o.activeReleaseVersion),r=C(s);if(!s)return null;if(!r)return e.jsxs("div",{children:[e.jsx("h2",{className:`${u} m-0 mb-4`,children:s}),e.jsxs("p",{className:"opacity-50",children:["No release notes found for ",s,"."]})]});if(r.length===0)return e.jsxs("div",{children:[e.jsx("h2",{className:`${u} m-0 mb-4`,children:s}),e.jsx("p",{className:"opacity-50",children:"No ideas could be resolved for this release."})]});const a=r.map(o=>`### ${o.label}
|
|
2
2
|
|
|
3
3
|
${o.ideas.map(c=>`- ${c.title} (${c.id})`).join(`
|
|
4
4
|
`)}`).join(`
|
|
5
5
|
|
|
6
6
|
`);return e.jsxs("div",{children:[e.jsx("h2",{className:`${u} m-0 mb-4`,children:s}),e.jsx("div",{className:"text-base leading-[1.7] text-ink-900",children:e.jsx(R,{children:a})})]})},A=()=>{const s=i(c=>c.repoDocs),r=i(c=>c.activeDocTitle),a=s.find(c=>c.name===r);if(!a)return null;const o=a.name.endsWith(".md");return e.jsxs("div",{children:[e.jsx("h2",{className:`${u} m-0 mb-4`,children:a.name}),o?e.jsx("div",{className:"text-base leading-[1.7] text-ink-900",children:e.jsx(R,{children:a.content})}):e.jsx("pre",{className:"overflow-x-auto whitespace-pre-wrap rounded-md bg-black/[4%] p-4 font-mono text-xs leading-normal",children:a.content})]})},F=()=>{const s=i(c=>c.docSearchQuery),r=i(c=>c.activeDocTitle),a=i(c=>c.activeReleaseVersion),o=b();return s.trim()?e.jsx("div",{children:e.jsx(T,{query:s})}):o==="repo-docs"&&r?e.jsx("div",{children:e.jsx(A,{})}):o==="release-notes"&&a?e.jsx("div",{children:e.jsx(Q,{})}):e.jsxs("div",{children:[e.jsx(L,{children:"Docs"}),e.jsx("p",{className:"opacity-50",children:"Pick a doc from the sidebar — start with a repo doc if you're new here."})]})},E=()=>{const s=i(t=>t.repoDocs),r=i(t=>t.repoDocsLoading),a=i(t=>t.loadRepoDocs),o=i(t=>t.activeDocTitle),c=i(t=>t.setActiveDocTitle),l=i(t=>t.docSearchQuery),h=i(t=>t.setDocSearchQuery),n=i(t=>t.releaseVersions),p=i(t=>t.releaseVersionsLoading),m=i(t=>t.loadReleaseVersions),f=i(t=>t.activeReleaseVersion),d=i(t=>t.setActiveReleaseVersion),y=b(),D=S();return j.useEffect(()=>{a()},[a]),j.useEffect(()=>{m()},[m]),{repoDocs:s,repoDocsLoading:r,activeDocTitle:o,docSearchQuery:l,setDocSearchQuery:h,releaseVersions:n,releaseVersionsLoading:p,activeReleaseVersion:f,activeDocSection:y,selectRepoDoc:t=>{D({to:"/docs/$section",params:{section:"repo-docs"}}),c(t)},selectReleaseVersion:t=>{D({to:"/docs/$section",params:{section:"release-notes"}}),d(t)}}},M=s=>s.charAt(0).toUpperCase()+s.slice(1).toLowerCase(),x=({children:s})=>e.jsx("span",{className:"block px-3 py-1 text-sm italic opacity-[0.35]",children:s}),H=()=>{const{repoDocs:s,repoDocsLoading:r,activeDocTitle:a,docSearchQuery:o,setDocSearchQuery:c,releaseVersions:l,releaseVersionsLoading:h,activeReleaseVersion:n,activeDocSection:p,selectRepoDoc:m,selectReleaseVersion:f}=E();return e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"flex h-[64px] items-center",children:e.jsx($,{size:"small","aria-label":"Search docs",placeholder:"Search docs…",value:o,onChange:d=>c(d.target.value)})}),e.jsx(g,{label:"Repo Docs",children:r&&s.length===0?e.jsx(x,{children:"Loading…"}):s.length>0?s.map(d=>e.jsx(v,{size:"small",className:"pc-row text-xs",active:p==="repo-docs"&&a===d.name,onClick:()=>m(d.name),children:M(d.name)},d.name)):e.jsx(x,{children:"No repo docs found"})}),e.jsx(g,{label:"Releases",children:h&&l.length===0?e.jsx(x,{children:"Loading…"}):l.length>0?l.map(d=>e.jsx(v,{size:"small",className:"pc-row text-xs",active:p==="release-notes"&&n===d,onClick:()=>f(d),children:d},d)):e.jsx(x,{children:"No releases yet"})})]})};export{F as DocsPage,H as DocsSidebar};
|
|
7
|
-
//# sourceMappingURL=index-
|
|
7
|
+
//# sourceMappingURL=index-CFMhKXQf.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index-CDlMKeg5.js","sources":["../../../src/app/features/docs/components/docs-search.tsx","../../../src/app/features/docs/hooks/use-release-notes.ts","../../../src/app/features/docs/components/release-notes-detail.tsx","../../../src/app/features/docs/components/repo-doc-detail.tsx","../../../src/app/features/docs/docs-page.tsx","../../../src/app/features/docs/hooks/use-docs-sidebar.ts","../../../src/app/features/docs/components/docs-sidebar.tsx"],"sourcesContent":["import { useAppStore } from '@/app/stores/app-store';\nimport { Button } from '@dendelion/paper-ui';\nimport { useNavigate } from '@tanstack/react-router';\n\ninterface SearchMatch {\n title: string;\n snippet: string;\n}\n\ninterface DocsSearchProps {\n query: string;\n}\n\nconst searchIn = (text: string, query: string): boolean =>\n text.toLowerCase().includes(query.toLowerCase());\n\nconst snippet = (text: string, query: string, maxLen = 120): string => {\n const idx = text.toLowerCase().indexOf(query.toLowerCase());\n if (idx === -1) return text.slice(0, maxLen);\n const start = Math.max(0, idx - 40);\n const end = Math.min(text.length, idx + query.length + 40);\n let s = text.slice(start, end);\n if (start > 0) s = `…${s}`;\n if (end < text.length) s = `${s}…`;\n return s;\n};\n\nexport const DocsSearch = ({ query }: DocsSearchProps) => {\n const repoDocs = useAppStore((s) => s.repoDocs);\n const setActiveDocTitle = useAppStore((s) => s.setActiveDocTitle);\n const setDocSearchQuery = useAppStore((s) => s.setDocSearchQuery);\n const navigate = useNavigate();\n\n const results: SearchMatch[] = [];\n\n for (const f of repoDocs) {\n if (searchIn(f.name, query) || searchIn(f.content, query)) {\n results.push({\n title: f.name,\n snippet: snippet(f.content, query),\n });\n }\n }\n\n const handleSelect = (title: string) => {\n navigate({ to: '/docs/$section', params: { section: 'repo-docs' } });\n setActiveDocTitle(title);\n setDocSearchQuery('');\n };\n\n if (results.length === 0) {\n return <p className=\"opacity-50\">No results found for \"{query}\".</p>;\n }\n\n return (\n <div>\n <p className=\"mb-3 text-sm opacity-50\">\n {results.length} result{results.length === 1 ? '' : 's'} for \"{query}\"\n </p>\n <div className=\"flex flex-col gap-1\">\n {results.map((m) => (\n <Button\n key={m.title}\n variant=\"ghost\"\n size=\"small\"\n fullWidth\n onClick={() => handleSelect(m.title)}\n className=\"justify-start px-3 py-2\"\n >\n <span className=\"text-left\">\n <span className=\"mb-[0.2rem] block font-display-luminari text-[0.95rem] font-semibold\">\n {m.title}\n </span>\n <span className=\"text-sm opacity-60\">{m.snippet}</span>\n </span>\n </Button>\n ))}\n </div>\n </div>\n );\n};\n","import { fetchReleaseNotes } from '@/app/services/release-notes-api';\nimport type { ReleaseNoteSection } from '@/types/index';\nimport { useEffect, useState } from 'react';\n\nexport const useReleaseNotes = (version: string | null): ReleaseNoteSection[] | null => {\n const [sections, setSections] = useState<ReleaseNoteSection[] | null>(null);\n\n useEffect(() => {\n setSections(null);\n if (!version) return;\n let cancelled = false;\n fetchReleaseNotes(version)\n .then((result) => {\n if (!cancelled) setSections(result);\n })\n .catch(() => {});\n return () => {\n cancelled = true;\n };\n }, [version]);\n\n return sections;\n};\n","import { detailHeadingClassName } from '@/app/components/detail-heading-style';\nimport { Markdown } from '@/app/components/markdown';\nimport { useAppStore } from '@/app/stores/app-store';\nimport { useReleaseNotes } from '../hooks/use-release-notes';\n\nexport const ReleaseNotesDetail = () => {\n const version = useAppStore((s) => s.activeReleaseVersion);\n const sections = useReleaseNotes(version);\n if (!version) return null;\n\n if (!sections) {\n return (\n <div>\n <h2 className={`${detailHeadingClassName} m-0 mb-4`}>{version}</h2>\n <p className=\"opacity-50\">No release notes found for {version}.</p>\n </div>\n );\n }\n\n if (sections.length === 0) {\n return (\n <div>\n <h2 className={`${detailHeadingClassName} m-0 mb-4`}>{version}</h2>\n <p className=\"opacity-50\">No ideas could be resolved for this release.</p>\n </div>\n );\n }\n\n const markdown = sections\n .map(\n (section) =>\n `### ${section.label}\\n\\n${section.ideas.map((idea) => `- ${idea.title} (${idea.id})`).join('\\n')}`,\n )\n .join('\\n\\n');\n\n return (\n <div>\n <h2 className={`${detailHeadingClassName} m-0 mb-4`}>{version}</h2>\n <div className=\"text-base leading-[1.7] text-ink-900\">\n <Markdown>{markdown}</Markdown>\n </div>\n </div>\n );\n};\n","import { detailHeadingClassName } from '@/app/components/detail-heading-style';\nimport { Markdown } from '@/app/components/markdown';\nimport { useAppStore } from '@/app/stores/app-store';\n\nexport const RepoDocDetail = () => {\n const repoDocs = useAppStore((s) => s.repoDocs);\n const activeDocTitle = useAppStore((s) => s.activeDocTitle);\n\n const file = repoDocs.find((f) => f.name === activeDocTitle);\n if (!file) return null;\n\n const isMarkdown = file.name.endsWith('.md');\n\n return (\n <div>\n <h2 className={`${detailHeadingClassName} m-0 mb-4`}>{file.name}</h2>\n\n {isMarkdown ? (\n <div className=\"text-base leading-[1.7] text-ink-900\">\n <Markdown>{file.content}</Markdown>\n </div>\n ) : (\n <pre className=\"overflow-x-auto whitespace-pre-wrap rounded-md bg-black/[4%] p-4 font-mono text-xs leading-normal\">\n {file.content}\n </pre>\n )}\n </div>\n );\n};\n","import { PageTitle } from '@/app/components/page-title';\nimport { useResolvedDocSection } from '@/app/hooks';\nimport { useAppStore } from '@/app/stores/app-store';\nimport { DocsSearch } from './components/docs-search';\nimport { ReleaseNotesDetail } from './components/release-notes-detail';\nimport { RepoDocDetail } from './components/repo-doc-detail';\n\nexport const DocsPage = () => {\n const docSearchQuery = useAppStore((s) => s.docSearchQuery);\n const activeDocTitle = useAppStore((s) => s.activeDocTitle);\n const activeReleaseVersion = useAppStore((s) => s.activeReleaseVersion);\n const activeDocSection = useResolvedDocSection();\n\n if (docSearchQuery.trim()) {\n return (\n <div>\n <DocsSearch query={docSearchQuery} />\n </div>\n );\n }\n\n if (activeDocSection === 'repo-docs' && activeDocTitle) {\n return (\n <div>\n <RepoDocDetail />\n </div>\n );\n }\n\n if (activeDocSection === 'release-notes' && activeReleaseVersion) {\n return (\n <div>\n <ReleaseNotesDetail />\n </div>\n );\n }\n\n return (\n <div>\n <PageTitle>Docs</PageTitle>\n <p className=\"opacity-50\">\n Pick a doc from the sidebar — start with a repo doc if you're new here.\n </p>\n </div>\n );\n};\n","import { useResolvedDocSection } from '@/app/hooks';\nimport { useAppStore } from '@/app/stores/app-store';\nimport { useNavigate } from '@tanstack/react-router';\nimport { useEffect } from 'react';\n\nexport const useDocsSidebar = () => {\n const repoDocs = useAppStore((s) => s.repoDocs);\n const repoDocsLoading = useAppStore((s) => s.repoDocsLoading);\n const loadRepoDocs = useAppStore((s) => s.loadRepoDocs);\n const activeDocTitle = useAppStore((s) => s.activeDocTitle);\n const setActiveDocTitle = useAppStore((s) => s.setActiveDocTitle);\n const docSearchQuery = useAppStore((s) => s.docSearchQuery);\n const setDocSearchQuery = useAppStore((s) => s.setDocSearchQuery);\n const releaseVersions = useAppStore((s) => s.releaseVersions);\n const releaseVersionsLoading = useAppStore((s) => s.releaseVersionsLoading);\n const loadReleaseVersions = useAppStore((s) => s.loadReleaseVersions);\n const activeReleaseVersion = useAppStore((s) => s.activeReleaseVersion);\n const setActiveReleaseVersion = useAppStore((s) => s.setActiveReleaseVersion);\n const activeDocSection = useResolvedDocSection();\n const navigate = useNavigate();\n\n useEffect(() => {\n loadRepoDocs();\n }, [loadRepoDocs]);\n\n useEffect(() => {\n loadReleaseVersions();\n }, [loadReleaseVersions]);\n\n const selectRepoDoc = (name: string) => {\n navigate({ to: '/docs/$section', params: { section: 'repo-docs' } });\n setActiveDocTitle(name);\n };\n\n const selectReleaseVersion = (version: string) => {\n navigate({ to: '/docs/$section', params: { section: 'release-notes' } });\n setActiveReleaseVersion(version);\n };\n\n return {\n repoDocs,\n repoDocsLoading,\n activeDocTitle,\n docSearchQuery,\n setDocSearchQuery,\n releaseVersions,\n releaseVersionsLoading,\n activeReleaseVersion,\n activeDocSection,\n selectRepoDoc,\n selectReleaseVersion,\n };\n};\n","import { Input, ListItem } from '@dendelion/paper-ui';\nimport { SidebarSection } from '../../plans/components/sidebar-section';\nimport { useDocsSidebar } from '../hooks';\n\nconst simplecaseLabel = (name: string) =>\n name.charAt(0).toUpperCase() + name.slice(1).toLowerCase();\n\nconst EmptyState = ({ children }: { children: React.ReactNode }) => (\n <span className=\"block px-3 py-1 text-sm italic opacity-[0.35]\">{children}</span>\n);\n\nexport const DocsSidebar = () => {\n const {\n repoDocs,\n repoDocsLoading,\n activeDocTitle,\n docSearchQuery,\n setDocSearchQuery,\n releaseVersions,\n releaseVersionsLoading,\n activeReleaseVersion,\n activeDocSection,\n selectRepoDoc,\n selectReleaseVersion,\n } = useDocsSidebar();\n\n return (\n <>\n <div className=\"flex h-[64px] items-center\">\n <Input\n size=\"small\"\n aria-label=\"Search docs\"\n placeholder=\"Search docs…\"\n value={docSearchQuery}\n onChange={(e) => setDocSearchQuery(e.target.value)}\n />\n </div>\n\n <SidebarSection label=\"Repo Docs\">\n {repoDocsLoading && repoDocs.length === 0 ? (\n <EmptyState>Loading…</EmptyState>\n ) : repoDocs.length > 0 ? (\n repoDocs.map((f) => (\n <ListItem\n key={f.name}\n size=\"small\"\n className=\"pc-row text-xs\"\n active={activeDocSection === 'repo-docs' && activeDocTitle === f.name}\n onClick={() => selectRepoDoc(f.name)}\n >\n {simplecaseLabel(f.name)}\n </ListItem>\n ))\n ) : (\n <EmptyState>No repo docs found</EmptyState>\n )}\n </SidebarSection>\n\n <SidebarSection label=\"Releases\">\n {releaseVersionsLoading && releaseVersions.length === 0 ? (\n <EmptyState>Loading…</EmptyState>\n ) : releaseVersions.length > 0 ? (\n releaseVersions.map((version) => (\n <ListItem\n key={version}\n size=\"small\"\n className=\"pc-row text-xs\"\n active={activeDocSection === 'release-notes' && activeReleaseVersion === version}\n onClick={() => selectReleaseVersion(version)}\n >\n {version}\n </ListItem>\n ))\n ) : (\n <EmptyState>No releases yet</EmptyState>\n )}\n </SidebarSection>\n </>\n );\n};\n"],"names":["searchIn","text","query","snippet","maxLen","idx","start","end","s","DocsSearch","repoDocs","useAppStore","setActiveDocTitle","setDocSearchQuery","navigate","useNavigate","results","f","handleSelect","title","jsxs","m","jsx","Button","useReleaseNotes","version","sections","setSections","useState","useEffect","cancelled","fetchReleaseNotes","result","ReleaseNotesDetail","detailHeadingClassName","markdown","section","idea","Markdown","RepoDocDetail","activeDocTitle","file","isMarkdown","DocsPage","docSearchQuery","activeReleaseVersion","activeDocSection","useResolvedDocSection","PageTitle","useDocsSidebar","repoDocsLoading","loadRepoDocs","releaseVersions","releaseVersionsLoading","loadReleaseVersions","setActiveReleaseVersion","name","simplecaseLabel","EmptyState","children","DocsSidebar","selectRepoDoc","selectReleaseVersion","Fragment","Input","e","SidebarSection","ListItem"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index-CFMhKXQf.js","sources":["../../../src/app/features/docs/components/docs-search.tsx","../../../src/app/features/docs/hooks/use-release-notes.ts","../../../src/app/features/docs/components/release-notes-detail.tsx","../../../src/app/features/docs/components/repo-doc-detail.tsx","../../../src/app/features/docs/docs-page.tsx","../../../src/app/features/docs/hooks/use-docs-sidebar.ts","../../../src/app/features/docs/components/docs-sidebar.tsx"],"sourcesContent":["import { useAppStore } from '@/app/stores/app-store';\nimport { Button } from '@dendelion/paper-ui';\nimport { useNavigate } from '@tanstack/react-router';\n\ninterface SearchMatch {\n title: string;\n snippet: string;\n}\n\ninterface DocsSearchProps {\n query: string;\n}\n\nconst searchIn = (text: string, query: string): boolean =>\n text.toLowerCase().includes(query.toLowerCase());\n\nconst snippet = (text: string, query: string, maxLen = 120): string => {\n const idx = text.toLowerCase().indexOf(query.toLowerCase());\n if (idx === -1) return text.slice(0, maxLen);\n const start = Math.max(0, idx - 40);\n const end = Math.min(text.length, idx + query.length + 40);\n let s = text.slice(start, end);\n if (start > 0) s = `…${s}`;\n if (end < text.length) s = `${s}…`;\n return s;\n};\n\nexport const DocsSearch = ({ query }: DocsSearchProps) => {\n const repoDocs = useAppStore((s) => s.repoDocs);\n const setActiveDocTitle = useAppStore((s) => s.setActiveDocTitle);\n const setDocSearchQuery = useAppStore((s) => s.setDocSearchQuery);\n const navigate = useNavigate();\n\n const results: SearchMatch[] = [];\n\n for (const f of repoDocs) {\n if (searchIn(f.name, query) || searchIn(f.content, query)) {\n results.push({\n title: f.name,\n snippet: snippet(f.content, query),\n });\n }\n }\n\n const handleSelect = (title: string) => {\n navigate({ to: '/docs/$section', params: { section: 'repo-docs' } });\n setActiveDocTitle(title);\n setDocSearchQuery('');\n };\n\n if (results.length === 0) {\n return <p className=\"opacity-50\">No results found for \"{query}\".</p>;\n }\n\n return (\n <div>\n <p className=\"mb-3 text-sm opacity-50\">\n {results.length} result{results.length === 1 ? '' : 's'} for \"{query}\"\n </p>\n <div className=\"flex flex-col gap-1\">\n {results.map((m) => (\n <Button\n key={m.title}\n variant=\"ghost\"\n size=\"small\"\n fullWidth\n onClick={() => handleSelect(m.title)}\n className=\"justify-start px-3 py-2\"\n >\n <span className=\"text-left\">\n <span className=\"mb-[0.2rem] block font-display-luminari text-[0.95rem] font-semibold\">\n {m.title}\n </span>\n <span className=\"text-sm opacity-60\">{m.snippet}</span>\n </span>\n </Button>\n ))}\n </div>\n </div>\n );\n};\n","import { fetchReleaseNotes } from '@/app/services/release-notes-api';\nimport type { ReleaseNoteSection } from '@/types/index';\nimport { useEffect, useState } from 'react';\n\nexport const useReleaseNotes = (version: string | null): ReleaseNoteSection[] | null => {\n const [sections, setSections] = useState<ReleaseNoteSection[] | null>(null);\n\n useEffect(() => {\n setSections(null);\n if (!version) return;\n let cancelled = false;\n fetchReleaseNotes(version)\n .then((result) => {\n if (!cancelled) setSections(result);\n })\n .catch(() => {});\n return () => {\n cancelled = true;\n };\n }, [version]);\n\n return sections;\n};\n","import { detailHeadingClassName } from '@/app/components/detail-heading-style';\nimport { Markdown } from '@/app/components/markdown';\nimport { useAppStore } from '@/app/stores/app-store';\nimport { useReleaseNotes } from '../hooks/use-release-notes';\n\nexport const ReleaseNotesDetail = () => {\n const version = useAppStore((s) => s.activeReleaseVersion);\n const sections = useReleaseNotes(version);\n if (!version) return null;\n\n if (!sections) {\n return (\n <div>\n <h2 className={`${detailHeadingClassName} m-0 mb-4`}>{version}</h2>\n <p className=\"opacity-50\">No release notes found for {version}.</p>\n </div>\n );\n }\n\n if (sections.length === 0) {\n return (\n <div>\n <h2 className={`${detailHeadingClassName} m-0 mb-4`}>{version}</h2>\n <p className=\"opacity-50\">No ideas could be resolved for this release.</p>\n </div>\n );\n }\n\n const markdown = sections\n .map(\n (section) =>\n `### ${section.label}\\n\\n${section.ideas.map((idea) => `- ${idea.title} (${idea.id})`).join('\\n')}`,\n )\n .join('\\n\\n');\n\n return (\n <div>\n <h2 className={`${detailHeadingClassName} m-0 mb-4`}>{version}</h2>\n <div className=\"text-base leading-[1.7] text-ink-900\">\n <Markdown>{markdown}</Markdown>\n </div>\n </div>\n );\n};\n","import { detailHeadingClassName } from '@/app/components/detail-heading-style';\nimport { Markdown } from '@/app/components/markdown';\nimport { useAppStore } from '@/app/stores/app-store';\n\nexport const RepoDocDetail = () => {\n const repoDocs = useAppStore((s) => s.repoDocs);\n const activeDocTitle = useAppStore((s) => s.activeDocTitle);\n\n const file = repoDocs.find((f) => f.name === activeDocTitle);\n if (!file) return null;\n\n const isMarkdown = file.name.endsWith('.md');\n\n return (\n <div>\n <h2 className={`${detailHeadingClassName} m-0 mb-4`}>{file.name}</h2>\n\n {isMarkdown ? (\n <div className=\"text-base leading-[1.7] text-ink-900\">\n <Markdown>{file.content}</Markdown>\n </div>\n ) : (\n <pre className=\"overflow-x-auto whitespace-pre-wrap rounded-md bg-black/[4%] p-4 font-mono text-xs leading-normal\">\n {file.content}\n </pre>\n )}\n </div>\n );\n};\n","import { PageTitle } from '@/app/components/page-title';\nimport { useResolvedDocSection } from '@/app/hooks';\nimport { useAppStore } from '@/app/stores/app-store';\nimport { DocsSearch } from './components/docs-search';\nimport { ReleaseNotesDetail } from './components/release-notes-detail';\nimport { RepoDocDetail } from './components/repo-doc-detail';\n\nexport const DocsPage = () => {\n const docSearchQuery = useAppStore((s) => s.docSearchQuery);\n const activeDocTitle = useAppStore((s) => s.activeDocTitle);\n const activeReleaseVersion = useAppStore((s) => s.activeReleaseVersion);\n const activeDocSection = useResolvedDocSection();\n\n if (docSearchQuery.trim()) {\n return (\n <div>\n <DocsSearch query={docSearchQuery} />\n </div>\n );\n }\n\n if (activeDocSection === 'repo-docs' && activeDocTitle) {\n return (\n <div>\n <RepoDocDetail />\n </div>\n );\n }\n\n if (activeDocSection === 'release-notes' && activeReleaseVersion) {\n return (\n <div>\n <ReleaseNotesDetail />\n </div>\n );\n }\n\n return (\n <div>\n <PageTitle>Docs</PageTitle>\n <p className=\"opacity-50\">\n Pick a doc from the sidebar — start with a repo doc if you're new here.\n </p>\n </div>\n );\n};\n","import { useResolvedDocSection } from '@/app/hooks';\nimport { useAppStore } from '@/app/stores/app-store';\nimport { useNavigate } from '@tanstack/react-router';\nimport { useEffect } from 'react';\n\nexport const useDocsSidebar = () => {\n const repoDocs = useAppStore((s) => s.repoDocs);\n const repoDocsLoading = useAppStore((s) => s.repoDocsLoading);\n const loadRepoDocs = useAppStore((s) => s.loadRepoDocs);\n const activeDocTitle = useAppStore((s) => s.activeDocTitle);\n const setActiveDocTitle = useAppStore((s) => s.setActiveDocTitle);\n const docSearchQuery = useAppStore((s) => s.docSearchQuery);\n const setDocSearchQuery = useAppStore((s) => s.setDocSearchQuery);\n const releaseVersions = useAppStore((s) => s.releaseVersions);\n const releaseVersionsLoading = useAppStore((s) => s.releaseVersionsLoading);\n const loadReleaseVersions = useAppStore((s) => s.loadReleaseVersions);\n const activeReleaseVersion = useAppStore((s) => s.activeReleaseVersion);\n const setActiveReleaseVersion = useAppStore((s) => s.setActiveReleaseVersion);\n const activeDocSection = useResolvedDocSection();\n const navigate = useNavigate();\n\n useEffect(() => {\n loadRepoDocs();\n }, [loadRepoDocs]);\n\n useEffect(() => {\n loadReleaseVersions();\n }, [loadReleaseVersions]);\n\n const selectRepoDoc = (name: string) => {\n navigate({ to: '/docs/$section', params: { section: 'repo-docs' } });\n setActiveDocTitle(name);\n };\n\n const selectReleaseVersion = (version: string) => {\n navigate({ to: '/docs/$section', params: { section: 'release-notes' } });\n setActiveReleaseVersion(version);\n };\n\n return {\n repoDocs,\n repoDocsLoading,\n activeDocTitle,\n docSearchQuery,\n setDocSearchQuery,\n releaseVersions,\n releaseVersionsLoading,\n activeReleaseVersion,\n activeDocSection,\n selectRepoDoc,\n selectReleaseVersion,\n };\n};\n","import { Input, ListItem } from '@dendelion/paper-ui';\nimport { SidebarSection } from '../../plans/components/sidebar-section';\nimport { useDocsSidebar } from '../hooks';\n\nconst simplecaseLabel = (name: string) =>\n name.charAt(0).toUpperCase() + name.slice(1).toLowerCase();\n\nconst EmptyState = ({ children }: { children: React.ReactNode }) => (\n <span className=\"block px-3 py-1 text-sm italic opacity-[0.35]\">{children}</span>\n);\n\nexport const DocsSidebar = () => {\n const {\n repoDocs,\n repoDocsLoading,\n activeDocTitle,\n docSearchQuery,\n setDocSearchQuery,\n releaseVersions,\n releaseVersionsLoading,\n activeReleaseVersion,\n activeDocSection,\n selectRepoDoc,\n selectReleaseVersion,\n } = useDocsSidebar();\n\n return (\n <>\n <div className=\"flex h-[64px] items-center\">\n <Input\n size=\"small\"\n aria-label=\"Search docs\"\n placeholder=\"Search docs…\"\n value={docSearchQuery}\n onChange={(e) => setDocSearchQuery(e.target.value)}\n />\n </div>\n\n <SidebarSection label=\"Repo Docs\">\n {repoDocsLoading && repoDocs.length === 0 ? (\n <EmptyState>Loading…</EmptyState>\n ) : repoDocs.length > 0 ? (\n repoDocs.map((f) => (\n <ListItem\n key={f.name}\n size=\"small\"\n className=\"pc-row text-xs\"\n active={activeDocSection === 'repo-docs' && activeDocTitle === f.name}\n onClick={() => selectRepoDoc(f.name)}\n >\n {simplecaseLabel(f.name)}\n </ListItem>\n ))\n ) : (\n <EmptyState>No repo docs found</EmptyState>\n )}\n </SidebarSection>\n\n <SidebarSection label=\"Releases\">\n {releaseVersionsLoading && releaseVersions.length === 0 ? (\n <EmptyState>Loading…</EmptyState>\n ) : releaseVersions.length > 0 ? (\n releaseVersions.map((version) => (\n <ListItem\n key={version}\n size=\"small\"\n className=\"pc-row text-xs\"\n active={activeDocSection === 'release-notes' && activeReleaseVersion === version}\n onClick={() => selectReleaseVersion(version)}\n >\n {version}\n </ListItem>\n ))\n ) : (\n <EmptyState>No releases yet</EmptyState>\n )}\n </SidebarSection>\n </>\n );\n};\n"],"names":["searchIn","text","query","snippet","maxLen","idx","start","end","s","DocsSearch","repoDocs","useAppStore","setActiveDocTitle","setDocSearchQuery","navigate","useNavigate","results","f","handleSelect","title","jsxs","m","jsx","Button","useReleaseNotes","version","sections","setSections","useState","useEffect","cancelled","fetchReleaseNotes","result","ReleaseNotesDetail","detailHeadingClassName","markdown","section","idea","Markdown","RepoDocDetail","activeDocTitle","file","isMarkdown","DocsPage","docSearchQuery","activeReleaseVersion","activeDocSection","useResolvedDocSection","PageTitle","useDocsSidebar","repoDocsLoading","loadRepoDocs","releaseVersions","releaseVersionsLoading","loadReleaseVersions","setActiveReleaseVersion","name","simplecaseLabel","EmptyState","children","DocsSidebar","selectRepoDoc","selectReleaseVersion","Fragment","Input","e","SidebarSection","ListItem"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{c as K,r as u,C as U,j as e,e as L,g as F,R as P,J as S,w as A,h as te,k as X,l as ae,s as D,D as I,m as ne,n as H,o as le,u as z,t as Q,$ as ie,q as oe,a as Z,A as q,v as B,x as ce,y as re,i as G,z as de,B as ee,P as me,p as M}from"./main-BPr1R-3E.js";import{S as $}from"./sidebar-section-CVvP-dC0.js";const he=async()=>{try{const s=await fetch(K("/api/merge-policy"));return s.ok?await s.json():null}catch{return null}},pe=async()=>{try{const s=await fetch(K("/api/merge-policy/apply"),{method:"POST"});return s.ok?await s.json():null}catch{return null}},V=["phase","planDraft","ideaExtend","commitSuggest","feedback","codeReview"],ue={phase:"Phase run",planDraft:"Plan draft",ideaExtend:"Idea extend",commitSuggest:"Commit suggest",feedback:"Scout chat",codeReview:"Code review"},xe={ok:{fill:"rgba(143, 185, 150, 0.25)",text:"#5E8A66",label:"Ready"},warn:{fill:"rgba(212, 163, 115, 0.25)",text:"#A67B4F",label:"Needs attention"},missing:{fill:"rgba(201, 139, 139, 0.25)",text:"#6E3A3A",label:"Missing"}},_={upToDate:{fill:"rgba(143, 185, 150, 0.25)",text:"#5E8A66"},outdated:{fill:"rgba(212, 163, 115, 0.25)",text:"#A67B4F"}},ge="rgba(143, 185, 150, 0.25)",se={allowSquashMerge:!0,allowMergeCommit:!1,allowRebaseMerge:!1,squashMergeCommitTitle:"PR_TITLE",squashMergeCommitMessage:"PR_BODY"},Y=[{key:"allowSquashMerge",label:"Allow squash merge"},{key:"allowMergeCommit",label:"Allow merge commit"},{key:"allowRebaseMerge",label:"Allow rebase merge"},{key:"squashMergeCommitTitle",label:"Squash commit title"},{key:"squashMergeCommitMessage",label:"Squash commit message"}];function W(s){return typeof s=="boolean"?s?"Yes":"No":s}function fe(s){return Y.every(t=>s[t.key]===se[t.key])}const je=({label:s,current:t,recommended:l,isLast:a})=>{const r=t===l;return e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"flex items-center gap-3 pb-2 pt-2",children:[e.jsx("span",{className:"flex-1",children:s}),e.jsx("span",{className:r?"opacity-[0.65] font-normal":"font-semibold",children:W(t)}),!r&&e.jsxs("span",{className:"opacity-[0.45]",children:["→ ",W(l)]})]}),!a&&e.jsx(A,{})]})},ve=()=>{const[s,t]=u.useState(void 0),[l,a]=u.useState(!1),{toast:r}=U();u.useEffect(()=>{he().then(t)},[]);const h=async()=>{a(!0);const n=await pe();a(!1),(n==null?void 0:n.status)==="ok"?(t(n),r({title:"Merge policy applied",variant:"success"})):r({title:"Failed to apply merge policy",description:(n==null?void 0:n.status)==="unavailable"?n.reason:void 0,variant:"error"})},p=(s==null?void 0:s.status)==="ok"&&fe(s.policy);return e.jsxs("div",{children:[e.jsxs("div",{className:"mb-6",children:[e.jsx("h2",{className:"m-0",children:"Merge Policy"}),e.jsx("p",{className:"opacity-50 mt-1",children:"Paper Camp's canonical policy: squash-only merges, with the commit title and body taken from the PR."})]}),s===void 0&&e.jsx("p",{children:"Loading…"}),s===null&&e.jsx(L,{variant:"warning",children:"Failed to load merge policy."}),(s==null?void 0:s.status)==="unavailable"&&e.jsx(L,{variant:"warning",children:s.reason}),(s==null?void 0:s.status)==="ok"&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"flex items-center gap-3 mb-3",children:[e.jsx("span",{className:"font-medium",children:s.repo}),e.jsx(F,{size:"small",fillColor:p?_.upToDate.fill:_.outdated.fill,textColor:p?_.upToDate.text:_.outdated.text,children:p?"Matches recommended policy":"Differs from recommended policy"})]}),e.jsx(P,{size:"small",texture:"kraft",children:Y.map((n,o)=>e.jsx(je,{label:n.label,current:s.policy[n.key],recommended:se[n.key],isLast:o===Y.length-1},n.key))}),e.jsx("div",{className:"mt-4",children:e.jsx(S,{size:"small",onClick:h,disabled:l||p,children:l?"Applying…":"Apply recommended policy"})})]})]})},be=()=>{const s=u.useRef(null),[t,l]=u.useState(void 0),{iconDataUri:a,loading:r}=te(),[h,p]=u.useState(null),n=h??a,[o,y]=u.useState(!1),[v,x]=u.useState(""),[N,k]=u.useState(""),{toast:g}=U();return u.useEffect(()=>{X().then(i=>{l(i),(i==null?void 0:i.port)!==void 0&&x(String(i.port)),(i==null?void 0:i.projectName)!==void 0&&k(i.projectName)})},[]),{fileRef:s,config:t,identityLoading:r,iconDataUri:n,uploading:o,portInput:v,setPortInput:x,nameInput:N,setNameInput:k,handleSaveAgentConfig:async(i,b)=>{const d=t==null?void 0:t.defaultAgents,j={phase:(d==null?void 0:d.phase)??I.phase,planDraft:(d==null?void 0:d.planDraft)??I.planDraft,ideaExtend:(d==null?void 0:d.ideaExtend)??I.ideaExtend,commitSuggest:(d==null?void 0:d.commitSuggest)??I.commitSuggest,feedback:(d==null?void 0:d.feedback)??I.feedback,codeReview:(d==null?void 0:d.codeReview)??I.codeReview,[i]:b};if(i==="codeReview"&&ne(b,j.phase)){g({title:"Failed to save",description:"Code review must use a different model than Phase run.",variant:"error"});return}const{ok:R,error:E}=await D({defaultAgents:j});R?(l(T=>T&&{...T,defaultAgents:j}),g({title:"Saved",variant:"success"})):g({title:"Failed to save",description:E,variant:"error"})},handleSavePort:async()=>{const i=Number(v);if(!t||!Number.isInteger(i)||i<=0||i===t.port)return;const{ok:b,error:d}=await D({port:i});b?(l(j=>j&&{...j,port:i}),g({title:"Saved",description:"Restart `paper-camp dev` to apply the new port.",variant:"success"})):g({title:"Failed to save",description:d,variant:"error"})},handleToggleIntegration:async()=>{var R,E,T;if(!t)return;const i=!(((E=(R=t.integration)==null?void 0:R.toolbar)==null?void 0:E.enabled)??!0),b={...t.integration,toolbar:{...(T=t.integration)==null?void 0:T.toolbar,enabled:i}},{ok:d,error:j}=await D({integration:b});d?(l(O=>O&&{...O,integration:b}),g({title:"Saved",variant:"success"})):g({title:"Failed to save",description:j,variant:"error"})},handleSaveName:async()=>{const i=N.trim();if(!t||!i||i===t.projectName)return;const{ok:b,error:d}=await D({projectName:i});b?(l(j=>j&&{...j,projectName:i}),k(i),g({title:"Saved",variant:"success"})):g({title:"Failed to save",description:d,variant:"error"})},handleFile:async i=>{var j;const b=(j=i.target.files)==null?void 0:j[0];if(!b)return;y(!0);const d=new FileReader;d.onloadend=async()=>{const R=d.result,E=await ae(R);y(!1),E?(p(R),g({title:"Saved",variant:"success"})):g({title:"Failed to save",variant:"error"})},d.readAsDataURL(b)}}},ye=()=>{const[s,t]=u.useState(null),[l,a]=u.useState(!1),[r,h]=u.useState(null),[p,n]=u.useState(null),[o,y]=u.useState(!1),{toast:v}=U(),x=u.useCallback(c=>{if(c===null){a(!0);return}a(!1),t(c)},[]);u.useEffect(()=>{H().then(x),X().then(c=>y((c==null?void 0:c.setupDismissed)??!1))},[x]);const N=async c=>{h(c),x(await H()),h(null)},k=async c=>{n(c);const w=await le(c);w?t(i=>(i==null?void 0:i.map(b=>b.id===c?w:b))??i):v({title:"Failed to connect",variant:"error"}),n(null)},g=async()=>{const c=!o,{ok:w}=await D({setupDismissed:c});w?(y(c),v({title:"Saved",variant:"success"})):v({title:"Failed to save",variant:"error"})},m=(s==null?void 0:s.every(c=>c.status==="ok"))??!0,f=(s==null?void 0:s.filter(c=>c.kind==="external"))??[],C=(s==null?void 0:s.filter(c=>c.kind==="local"))??[];return{connections:s,loadFailed:l,reloadingId:r,connectingId:p,setupDismissed:o,handleRecheck:N,handleConnect:k,handleDismissToggle:g,allOk:m,externalConnections:f,localConnections:C}},Ne=2e3,Se=s=>{const t=z(o=>o.loginRelay),l=z(o=>o.startLoginRelay),a=z(o=>o.loadLoginRelayStatus),r=z(o=>o.cancelLoginRelay),{toast:h}=U(),p=u.useRef(null),n=t==null?void 0:t.phase;return u.useEffect(()=>{if(n!=="starting"&&n!=="awaiting-authorization")return;const o=window.setInterval(()=>a(),Ne);return()=>window.clearInterval(o)},[n,a]),u.useEffect(()=>{const o=t==null?void 0:t.authorizeUrl;n!=="awaiting-authorization"||!o||p.current===o||(p.current=o,window.open(o,"_blank","noopener,noreferrer"))},[n,t==null?void 0:t.authorizeUrl]),u.useEffect(()=>{n==="success"?(h({title:"Signed in",variant:"success"}),s()):n==="error"&&h({title:"Sign-in failed",description:t==null?void 0:t.error,variant:"error"})},[n]),{phase:n,authorizeUrl:t==null?void 0:t.authorizeUrl,startLoginRelay:l,cancelLoginRelay:r}},we=({connection:s,onConnect:t,connecting:l})=>{const{connect:a}=s;return a?a.kind==="command"&&a.runnable?e.jsx(S,{size:"small",onClick:()=>t(s.id),disabled:l,children:l?"Running…":`Run \`${a.command}\``}):a.kind==="command"?e.jsx("div",{className:"mt-2",children:e.jsx(Q,{code:a.command})}):a.kind==="link"?e.jsx(S,{size:"small",onClick:()=>window.open(a.url,"_blank","noopener,noreferrer"),children:a.label}):e.jsx("p",{className:"opacity-[0.65] text-sm mt-2 mx-0 mb-0",children:a.message}):null},ke=["claude auth login","claude setup-token"],Ae=()=>e.jsxs("div",{className:"mt-2 flex flex-col gap-2",children:[e.jsx("p",{className:"opacity-[0.65] text-sm m-0",children:"The in-app relay couldn't complete. Run one of these in a terminal instead:"}),ke.map(s=>e.jsx(Q,{code:s},s)),e.jsxs("p",{className:"opacity-50 text-sm m-0",children:["Alternatively, set ",e.jsx("code",{children:"ANTHROPIC_API_KEY"})," in the server's environment — that bills as API usage rather than your Max subscription, so treat it as a fallback, not the default."]})]}),Ce=({onSignedIn:s})=>{const{phase:t,authorizeUrl:l,startLoginRelay:a,cancelLoginRelay:r}=Se(s);return t==="starting"?e.jsx(S,{size:"small",disabled:!0,children:"Starting…"}):t==="awaiting-authorization"?e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(S,{size:"small",onClick:()=>l&&window.open(l,"_blank","noopener,noreferrer"),children:"Reopen sign-in tab"}),e.jsx(S,{size:"small",onClick:()=>r(),children:"Cancel"})]}):e.jsxs("div",{children:[e.jsx(S,{size:"small",onClick:()=>a(),children:"Sign in"}),t==="error"&&e.jsx(Ae,{})]})},Ie="agent:claude-code",J=({connection:s,isLast:t,onRecheck:l,rechecking:a,onConnect:r,connecting:h})=>{const p=xe[s.status];return e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"pb-3 pt-3",children:[e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("span",{className:"flex-1 font-medium",children:s.label}),s.authenticated===!1&&e.jsx(ie,{content:"Installed, but not signed in",children:e.jsx(F,{size:"small",variant:"warning",children:"Not signed in"})}),e.jsx(F,{size:"small",fillColor:p.fill,textColor:p.text,children:p.label}),e.jsx(S,{size:"small",onClick:()=>l(s.id),disabled:a,children:a?"Checking…":"Recheck"})]}),e.jsxs("p",{className:"opacity-[0.65] text-sm mt-1 mx-0 mb-0",children:["Unlocks: ",s.unlocks]}),e.jsx("p",{className:"opacity-50 text-sm mt-1 mx-0 mb-0",children:s.detail}),e.jsx("div",{className:"mt-2",children:s.id===Ie&&s.authenticated===!1?e.jsx(Ce,{onSignedIn:()=>l(s.id)}):e.jsx(we,{connection:s,onConnect:r,connecting:h})})]}),!t&&e.jsx(A,{})]})},Re=()=>{const{connections:s,loadFailed:t,reloadingId:l,connectingId:a,setupDismissed:r,handleRecheck:h,handleConnect:p,handleDismissToggle:n,allOk:o,externalConnections:y,localConnections:v}=ye();return e.jsxs("div",{children:[e.jsx("div",{className:"mb-6",children:e.jsx("h2",{className:"m-0",children:"Setup"})}),s===null&&!t&&e.jsx("p",{children:"Loading…"}),t&&e.jsx("div",{className:"mb-4",children:e.jsx(L,{variant:"warning",children:"Failed to load connections. Try refreshing."})}),s&&e.jsxs(e.Fragment,{children:[!o&&e.jsx("div",{className:"mb-4",children:e.jsx(L,{variant:"warning",children:"Some connections are incomplete — features that depend on them stay disabled until fixed. Run the connect command below, then recheck."})}),y.length>0&&e.jsxs("div",{className:"mb-4",children:[e.jsx("p",{className:"opacity-[0.45] text-sm mt-0 mb-2",children:"External services — reached on your behalf with their own remote credential."}),e.jsx(P,{size:"small",texture:"kraft",children:y.map((x,N)=>e.jsx(J,{connection:x,isLast:N===y.length-1,onRecheck:h,rechecking:l===x.id,onConnect:p,connecting:a===x.id},x.id))})]}),v.length>0&&e.jsxs("div",{className:"mb-4",children:[e.jsx("p",{className:"opacity-[0.45] text-sm mt-0 mb-2",children:"Local adapters — driven on this machine with their own local session."}),e.jsx(P,{size:"small",texture:"kraft",children:v.map((x,N)=>e.jsx(J,{connection:x,isLast:N===v.length-1,onRecheck:h,rechecking:l===x.id,onConnect:p,connecting:a===x.id},x.id))})]}),e.jsx("div",{className:"mt-4",children:e.jsx(S,{size:"small",onClick:n,children:r?"Show Setup on open again":"Don't show Setup on open"})})]})]})},Ee=()=>{const{subjects:s,loading:t,available:l}=oe(),a=Z();return e.jsxs("div",{children:[e.jsxs("div",{className:"mb-6",children:[e.jsx("h2",{className:"m-0",children:"Subjects"}),e.jsx("p",{className:"opacity-50 mt-1",children:"Subjects are the roadmap's bets and standing concerns. Edit the vocabulary on the Roadmap page."})]}),t&&e.jsx("p",{children:"Loading…"}),!t&&!l&&e.jsx("p",{className:"opacity-60 m-0",children:"Couldn't load subjects — check the server config."}),!t&&l&&e.jsxs(P,{size:"small",texture:"kraft",children:[s.length===0&&e.jsx("p",{className:"opacity-[0.45] m-0 pb-2",children:"No subjects yet."}),s.map((r,h)=>e.jsxs("div",{children:[e.jsx("div",{className:"pb-2 pt-2",children:r}),h<s.length-1&&e.jsx(A,{})]},r)),s.length>0&&e.jsx(A,{}),e.jsx("div",{className:"pt-3",children:e.jsx(S,{size:"small",onClick:()=>a({to:"/roadmap"}),children:"Go to Roadmap"})})]})]})},Te=140,De=160,Le=110,Pe=({taskKey:s,agentConfig:t,isLast:l,onSave:a,authorConfig:r})=>{const h=q[t.agent]??q["claude-code"],p=r&&r.agent===t.agent?r.model??"":void 0,n=Array.isArray(h.model)?h.model.filter(m=>m!==p):h.model,o=h.effort,[y,v]=u.useState(t.model??"");u.useEffect(()=>{v(t.model??"")},[t.model]);const x=m=>{var w;const f=m,C=q[f],c={agent:f};t.model&&(C.model===null||(w=C.model)!=null&&w.includes(t.model))&&(c.model=t.model),t.effort&&Array.isArray(C.effort)&&(c.effort=t.effort),a(s,c)},N=m=>{a(s,{...t,model:m||void 0})},k=()=>{a(s,{...t,model:y||void 0})},g=m=>{a(s,{...t,effort:m||void 0})};return e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"flex items-center gap-3 pb-2 pt-2",children:[e.jsx("span",{className:"w-[110px] shrink-0 text-sm opacity-[0.65]",children:ue[s]}),e.jsx(B,{size:"small",width:Te,value:t.agent,onChange:x,options:ce.map(m=>({value:m,label:re[m]}))}),Array.isArray(n)?e.jsx(B,{size:"small",width:De,value:t.model??"",onChange:N,options:[...p===""?[]:[{value:"",label:"Default"}],...n.map(m=>({value:m,label:m}))]}):n===null?e.jsx(G,{size:"small",className:"w-[160px]",value:y,placeholder:"Default model",onChange:m=>v(m.target.value),onBlur:k}):null,e.jsx("div",{className:Array.isArray(o)?"visible":"invisible",children:e.jsx(B,{size:"small",width:Le,value:t.effort??"",onChange:g,options:[{value:"",label:"Default"},...(Array.isArray(o)?o:[]).map(m=>({value:m,label:m}))]})})]}),!l&&e.jsx(A,{})]})},ze=()=>e.jsxs("div",{className:"flex items-center gap-3 pb-1",children:[e.jsx("span",{className:"w-[110px] shrink-0 text-sm opacity-[0.45]",children:"Task"}),e.jsx("span",{className:"w-[140px] shrink-0 text-sm opacity-[0.45]",children:"Agent"}),e.jsx("span",{className:"w-[160px] shrink-0 text-sm opacity-[0.45]",children:"Model"}),e.jsx("span",{className:"w-[110px] shrink-0 text-sm opacity-[0.45]",children:"Effort"})]}),Me=()=>{var g,m;const{fileRef:s,config:t,identityLoading:l,iconDataUri:a,uploading:r,portInput:h,setPortInput:p,nameInput:n,setNameInput:o,handleSaveAgentConfig:y,handleSavePort:v,handleToggleIntegration:x,handleSaveName:N,handleFile:k}=be();return e.jsxs("div",{children:[e.jsx("div",{className:"mb-6",children:e.jsx("h2",{className:"m-0",children:"Project Info"})}),t===void 0&&e.jsx("p",{children:"Loading…"}),t===null&&e.jsxs(L,{variant:"warning",children:["No papercamp/config.json found — run ",e.jsx("code",{children:"paper-camp init"})," in this directory first."]}),t&&e.jsxs(P,{size:"small",texture:"kraft",children:[e.jsxs("div",{className:"flex items-end gap-3 pb-3",children:[e.jsx(G,{value:n,onChange:f=>o(f.target.value),onBlur:N,label:"Project Name"}),e.jsxs(F,{size:"small",fillColor:ge,textColor:de.accentGreenDark,children:["v",t.version]})]}),e.jsx(A,{}),e.jsxs("div",{className:"flex items-center gap-3 pb-3 pt-3",children:[a&&e.jsx("img",{src:a,alt:"Project icon",className:"w-10 h-10 object-contain shrink-0 rounded"}),e.jsxs("div",{children:[e.jsx("input",{ref:s,type:"file",accept:".svg,.png,.jpg,.jpeg,.gif,.webp",onChange:k,className:"hidden"}),e.jsx(S,{size:"small",onClick:()=>{var f;return(f=s.current)==null?void 0:f.click()},disabled:r,children:r?"Uploading…":"Choose File"}),l&&e.jsx("p",{className:"text-sm opacity-50 mt-1 mx-0 mb-0",children:"Loading…"}),!l&&!a&&!r&&e.jsx("p",{className:"text-sm opacity-[0.45] mt-1 mx-0 mb-0",children:"No icon set."})]})]}),e.jsx(A,{}),e.jsx("div",{className:"flex items-end gap-3 pb-3 pt-3",children:e.jsx(G,{type:"number",value:h,onChange:f=>p(f.target.value),onBlur:v,label:"Port",helperText:"Default for `paper-camp dev`. Restart the server to apply a change."})}),e.jsx(A,{}),e.jsxs("div",{className:"flex items-center justify-between gap-3 pb-3 pt-3",children:[e.jsxs("div",{children:[e.jsx("p",{className:"m-0",children:"In-app dev toolbar"}),e.jsx("p",{className:"opacity-[0.45] text-sm mt-1 mx-0 mb-0",children:"Inject the paper-camp toolbar into this project's dev server via the Vite plugin."})]}),e.jsx(S,{size:"small",onClick:x,children:((m=(g=t.integration)==null?void 0:g.toolbar)==null?void 0:m.enabled)??!0?"Disable":"Enable"})]}),e.jsx(A,{}),e.jsx(ze,{}),V.map((f,C)=>{var c,w;return e.jsx(Pe,{taskKey:f,agentConfig:((c=t.defaultAgents)==null?void 0:c[f])??I[f],isLast:C===V.length-1,onSave:y,authorConfig:f==="codeReview"?((w=t.defaultAgents)==null?void 0:w.phase)??I.phase:void 0},f)})]}),e.jsxs("p",{className:"opacity-[0.45] text-sm mt-4",children:[e.jsx("strong",{children:"Initialized:"})," ",t?new Date(t.initializedAt).toLocaleString():"—"]})]})},Ue=()=>{const s=ee();return e.jsxs("div",{children:[e.jsx(me,{children:"Settings"}),s==="subjects"?e.jsx(Ee,{}):s==="setup"?e.jsx(Re,{}):s==="merge-policy"?e.jsx(ve,{}):e.jsx(Me,{})]})},Oe=()=>{const s=ee(),t=Z();return e.jsxs(e.Fragment,{children:[e.jsxs($,{label:"General",children:[e.jsx(M,{size:"small",className:"pc-row text-xs",active:s===null,onClick:()=>t({to:"/settings"}),children:"Project Info"}),e.jsx(M,{size:"small",className:"pc-row text-xs",active:s==="setup",onClick:()=>t({to:"/settings/$section",params:{section:"setup"}}),children:"Setup"}),e.jsx(M,{size:"small",className:"pc-row text-xs",active:s==="merge-policy",onClick:()=>t({to:"/settings/$section",params:{section:"merge-policy"}}),children:"Merge Policy"})]}),e.jsx($,{label:"Ideas",children:e.jsx(M,{size:"small",className:"pc-row text-xs",active:s==="subjects",onClick:()=>t({to:"/settings/$section",params:{section:"subjects"}}),children:"Subjects"})})]})};export{Ue as SettingsPage,Oe as SettingsSidebar};
|
|
2
|
-
//# sourceMappingURL=index-
|
|
1
|
+
import{c as K,r as u,C as U,j as e,e as L,g as F,R as P,J as S,w as A,h as te,k as X,l as ae,s as D,D as I,m as ne,n as H,o as le,u as z,t as Q,$ as ie,q as oe,a as Z,A as q,v as B,x as ce,y as re,i as G,z as de,B as ee,P as me,p as M}from"./main-CDkrPxrg.js";import{S as $}from"./sidebar-section-7T-4hlR4.js";const he=async()=>{try{const s=await fetch(K("/api/merge-policy"));return s.ok?await s.json():null}catch{return null}},pe=async()=>{try{const s=await fetch(K("/api/merge-policy/apply"),{method:"POST"});return s.ok?await s.json():null}catch{return null}},V=["phase","planDraft","ideaExtend","commitSuggest","feedback","codeReview"],ue={phase:"Phase run",planDraft:"Plan draft",ideaExtend:"Idea extend",commitSuggest:"Commit suggest",feedback:"Scout chat",codeReview:"Code review"},xe={ok:{fill:"rgba(143, 185, 150, 0.25)",text:"#5E8A66",label:"Ready"},warn:{fill:"rgba(212, 163, 115, 0.25)",text:"#A67B4F",label:"Needs attention"},missing:{fill:"rgba(201, 139, 139, 0.25)",text:"#6E3A3A",label:"Missing"}},_={upToDate:{fill:"rgba(143, 185, 150, 0.25)",text:"#5E8A66"},outdated:{fill:"rgba(212, 163, 115, 0.25)",text:"#A67B4F"}},ge="rgba(143, 185, 150, 0.25)",se={allowSquashMerge:!0,allowMergeCommit:!1,allowRebaseMerge:!1,squashMergeCommitTitle:"PR_TITLE",squashMergeCommitMessage:"PR_BODY"},Y=[{key:"allowSquashMerge",label:"Allow squash merge"},{key:"allowMergeCommit",label:"Allow merge commit"},{key:"allowRebaseMerge",label:"Allow rebase merge"},{key:"squashMergeCommitTitle",label:"Squash commit title"},{key:"squashMergeCommitMessage",label:"Squash commit message"}];function W(s){return typeof s=="boolean"?s?"Yes":"No":s}function fe(s){return Y.every(t=>s[t.key]===se[t.key])}const je=({label:s,current:t,recommended:l,isLast:a})=>{const r=t===l;return e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"flex items-center gap-3 pb-2 pt-2",children:[e.jsx("span",{className:"flex-1",children:s}),e.jsx("span",{className:r?"opacity-[0.65] font-normal":"font-semibold",children:W(t)}),!r&&e.jsxs("span",{className:"opacity-[0.45]",children:["→ ",W(l)]})]}),!a&&e.jsx(A,{})]})},ve=()=>{const[s,t]=u.useState(void 0),[l,a]=u.useState(!1),{toast:r}=U();u.useEffect(()=>{he().then(t)},[]);const h=async()=>{a(!0);const n=await pe();a(!1),(n==null?void 0:n.status)==="ok"?(t(n),r({title:"Merge policy applied",variant:"success"})):r({title:"Failed to apply merge policy",description:(n==null?void 0:n.status)==="unavailable"?n.reason:void 0,variant:"error"})},p=(s==null?void 0:s.status)==="ok"&&fe(s.policy);return e.jsxs("div",{children:[e.jsxs("div",{className:"mb-6",children:[e.jsx("h2",{className:"m-0",children:"Merge Policy"}),e.jsx("p",{className:"opacity-50 mt-1",children:"Paper Camp's canonical policy: squash-only merges, with the commit title and body taken from the PR."})]}),s===void 0&&e.jsx("p",{children:"Loading…"}),s===null&&e.jsx(L,{variant:"warning",children:"Failed to load merge policy."}),(s==null?void 0:s.status)==="unavailable"&&e.jsx(L,{variant:"warning",children:s.reason}),(s==null?void 0:s.status)==="ok"&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"flex items-center gap-3 mb-3",children:[e.jsx("span",{className:"font-medium",children:s.repo}),e.jsx(F,{size:"small",fillColor:p?_.upToDate.fill:_.outdated.fill,textColor:p?_.upToDate.text:_.outdated.text,children:p?"Matches recommended policy":"Differs from recommended policy"})]}),e.jsx(P,{size:"small",texture:"kraft",children:Y.map((n,o)=>e.jsx(je,{label:n.label,current:s.policy[n.key],recommended:se[n.key],isLast:o===Y.length-1},n.key))}),e.jsx("div",{className:"mt-4",children:e.jsx(S,{size:"small",onClick:h,disabled:l||p,children:l?"Applying…":"Apply recommended policy"})})]})]})},be=()=>{const s=u.useRef(null),[t,l]=u.useState(void 0),{iconDataUri:a,loading:r}=te(),[h,p]=u.useState(null),n=h??a,[o,y]=u.useState(!1),[v,x]=u.useState(""),[N,k]=u.useState(""),{toast:g}=U();return u.useEffect(()=>{X().then(i=>{l(i),(i==null?void 0:i.port)!==void 0&&x(String(i.port)),(i==null?void 0:i.projectName)!==void 0&&k(i.projectName)})},[]),{fileRef:s,config:t,identityLoading:r,iconDataUri:n,uploading:o,portInput:v,setPortInput:x,nameInput:N,setNameInput:k,handleSaveAgentConfig:async(i,b)=>{const d=t==null?void 0:t.defaultAgents,j={phase:(d==null?void 0:d.phase)??I.phase,planDraft:(d==null?void 0:d.planDraft)??I.planDraft,ideaExtend:(d==null?void 0:d.ideaExtend)??I.ideaExtend,commitSuggest:(d==null?void 0:d.commitSuggest)??I.commitSuggest,feedback:(d==null?void 0:d.feedback)??I.feedback,codeReview:(d==null?void 0:d.codeReview)??I.codeReview,[i]:b};if(i==="codeReview"&&ne(b,j.phase)){g({title:"Failed to save",description:"Code review must use a different model than Phase run.",variant:"error"});return}const{ok:R,error:E}=await D({defaultAgents:j});R?(l(T=>T&&{...T,defaultAgents:j}),g({title:"Saved",variant:"success"})):g({title:"Failed to save",description:E,variant:"error"})},handleSavePort:async()=>{const i=Number(v);if(!t||!Number.isInteger(i)||i<=0||i===t.port)return;const{ok:b,error:d}=await D({port:i});b?(l(j=>j&&{...j,port:i}),g({title:"Saved",description:"Restart `paper-camp dev` to apply the new port.",variant:"success"})):g({title:"Failed to save",description:d,variant:"error"})},handleToggleIntegration:async()=>{var R,E,T;if(!t)return;const i=!(((E=(R=t.integration)==null?void 0:R.toolbar)==null?void 0:E.enabled)??!0),b={...t.integration,toolbar:{...(T=t.integration)==null?void 0:T.toolbar,enabled:i}},{ok:d,error:j}=await D({integration:b});d?(l(O=>O&&{...O,integration:b}),g({title:"Saved",variant:"success"})):g({title:"Failed to save",description:j,variant:"error"})},handleSaveName:async()=>{const i=N.trim();if(!t||!i||i===t.projectName)return;const{ok:b,error:d}=await D({projectName:i});b?(l(j=>j&&{...j,projectName:i}),k(i),g({title:"Saved",variant:"success"})):g({title:"Failed to save",description:d,variant:"error"})},handleFile:async i=>{var j;const b=(j=i.target.files)==null?void 0:j[0];if(!b)return;y(!0);const d=new FileReader;d.onloadend=async()=>{const R=d.result,E=await ae(R);y(!1),E?(p(R),g({title:"Saved",variant:"success"})):g({title:"Failed to save",variant:"error"})},d.readAsDataURL(b)}}},ye=()=>{const[s,t]=u.useState(null),[l,a]=u.useState(!1),[r,h]=u.useState(null),[p,n]=u.useState(null),[o,y]=u.useState(!1),{toast:v}=U(),x=u.useCallback(c=>{if(c===null){a(!0);return}a(!1),t(c)},[]);u.useEffect(()=>{H().then(x),X().then(c=>y((c==null?void 0:c.setupDismissed)??!1))},[x]);const N=async c=>{h(c),x(await H()),h(null)},k=async c=>{n(c);const w=await le(c);w?t(i=>(i==null?void 0:i.map(b=>b.id===c?w:b))??i):v({title:"Failed to connect",variant:"error"}),n(null)},g=async()=>{const c=!o,{ok:w}=await D({setupDismissed:c});w?(y(c),v({title:"Saved",variant:"success"})):v({title:"Failed to save",variant:"error"})},m=(s==null?void 0:s.every(c=>c.status==="ok"))??!0,f=(s==null?void 0:s.filter(c=>c.kind==="external"))??[],C=(s==null?void 0:s.filter(c=>c.kind==="local"))??[];return{connections:s,loadFailed:l,reloadingId:r,connectingId:p,setupDismissed:o,handleRecheck:N,handleConnect:k,handleDismissToggle:g,allOk:m,externalConnections:f,localConnections:C}},Ne=2e3,Se=s=>{const t=z(o=>o.loginRelay),l=z(o=>o.startLoginRelay),a=z(o=>o.loadLoginRelayStatus),r=z(o=>o.cancelLoginRelay),{toast:h}=U(),p=u.useRef(null),n=t==null?void 0:t.phase;return u.useEffect(()=>{if(n!=="starting"&&n!=="awaiting-authorization")return;const o=window.setInterval(()=>a(),Ne);return()=>window.clearInterval(o)},[n,a]),u.useEffect(()=>{const o=t==null?void 0:t.authorizeUrl;n!=="awaiting-authorization"||!o||p.current===o||(p.current=o,window.open(o,"_blank","noopener,noreferrer"))},[n,t==null?void 0:t.authorizeUrl]),u.useEffect(()=>{n==="success"?(h({title:"Signed in",variant:"success"}),s()):n==="error"&&h({title:"Sign-in failed",description:t==null?void 0:t.error,variant:"error"})},[n]),{phase:n,authorizeUrl:t==null?void 0:t.authorizeUrl,startLoginRelay:l,cancelLoginRelay:r}},we=({connection:s,onConnect:t,connecting:l})=>{const{connect:a}=s;return a?a.kind==="command"&&a.runnable?e.jsx(S,{size:"small",onClick:()=>t(s.id),disabled:l,children:l?"Running…":`Run \`${a.command}\``}):a.kind==="command"?e.jsx("div",{className:"mt-2",children:e.jsx(Q,{code:a.command})}):a.kind==="link"?e.jsx(S,{size:"small",onClick:()=>window.open(a.url,"_blank","noopener,noreferrer"),children:a.label}):e.jsx("p",{className:"opacity-[0.65] text-sm mt-2 mx-0 mb-0",children:a.message}):null},ke=["claude auth login","claude setup-token"],Ae=()=>e.jsxs("div",{className:"mt-2 flex flex-col gap-2",children:[e.jsx("p",{className:"opacity-[0.65] text-sm m-0",children:"The in-app relay couldn't complete. Run one of these in a terminal instead:"}),ke.map(s=>e.jsx(Q,{code:s},s)),e.jsxs("p",{className:"opacity-50 text-sm m-0",children:["Alternatively, set ",e.jsx("code",{children:"ANTHROPIC_API_KEY"})," in the server's environment — that bills as API usage rather than your Max subscription, so treat it as a fallback, not the default."]})]}),Ce=({onSignedIn:s})=>{const{phase:t,authorizeUrl:l,startLoginRelay:a,cancelLoginRelay:r}=Se(s);return t==="starting"?e.jsx(S,{size:"small",disabled:!0,children:"Starting…"}):t==="awaiting-authorization"?e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(S,{size:"small",onClick:()=>l&&window.open(l,"_blank","noopener,noreferrer"),children:"Reopen sign-in tab"}),e.jsx(S,{size:"small",onClick:()=>r(),children:"Cancel"})]}):e.jsxs("div",{children:[e.jsx(S,{size:"small",onClick:()=>a(),children:"Sign in"}),t==="error"&&e.jsx(Ae,{})]})},Ie="agent:claude-code",J=({connection:s,isLast:t,onRecheck:l,rechecking:a,onConnect:r,connecting:h})=>{const p=xe[s.status];return e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"pb-3 pt-3",children:[e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("span",{className:"flex-1 font-medium",children:s.label}),s.authenticated===!1&&e.jsx(ie,{content:"Installed, but not signed in",children:e.jsx(F,{size:"small",variant:"warning",children:"Not signed in"})}),e.jsx(F,{size:"small",fillColor:p.fill,textColor:p.text,children:p.label}),e.jsx(S,{size:"small",onClick:()=>l(s.id),disabled:a,children:a?"Checking…":"Recheck"})]}),e.jsxs("p",{className:"opacity-[0.65] text-sm mt-1 mx-0 mb-0",children:["Unlocks: ",s.unlocks]}),e.jsx("p",{className:"opacity-50 text-sm mt-1 mx-0 mb-0",children:s.detail}),e.jsx("div",{className:"mt-2",children:s.id===Ie&&s.authenticated===!1?e.jsx(Ce,{onSignedIn:()=>l(s.id)}):e.jsx(we,{connection:s,onConnect:r,connecting:h})})]}),!t&&e.jsx(A,{})]})},Re=()=>{const{connections:s,loadFailed:t,reloadingId:l,connectingId:a,setupDismissed:r,handleRecheck:h,handleConnect:p,handleDismissToggle:n,allOk:o,externalConnections:y,localConnections:v}=ye();return e.jsxs("div",{children:[e.jsx("div",{className:"mb-6",children:e.jsx("h2",{className:"m-0",children:"Setup"})}),s===null&&!t&&e.jsx("p",{children:"Loading…"}),t&&e.jsx("div",{className:"mb-4",children:e.jsx(L,{variant:"warning",children:"Failed to load connections. Try refreshing."})}),s&&e.jsxs(e.Fragment,{children:[!o&&e.jsx("div",{className:"mb-4",children:e.jsx(L,{variant:"warning",children:"Some connections are incomplete — features that depend on them stay disabled until fixed. Run the connect command below, then recheck."})}),y.length>0&&e.jsxs("div",{className:"mb-4",children:[e.jsx("p",{className:"opacity-[0.45] text-sm mt-0 mb-2",children:"External services — reached on your behalf with their own remote credential."}),e.jsx(P,{size:"small",texture:"kraft",children:y.map((x,N)=>e.jsx(J,{connection:x,isLast:N===y.length-1,onRecheck:h,rechecking:l===x.id,onConnect:p,connecting:a===x.id},x.id))})]}),v.length>0&&e.jsxs("div",{className:"mb-4",children:[e.jsx("p",{className:"opacity-[0.45] text-sm mt-0 mb-2",children:"Local adapters — driven on this machine with their own local session."}),e.jsx(P,{size:"small",texture:"kraft",children:v.map((x,N)=>e.jsx(J,{connection:x,isLast:N===v.length-1,onRecheck:h,rechecking:l===x.id,onConnect:p,connecting:a===x.id},x.id))})]}),e.jsx("div",{className:"mt-4",children:e.jsx(S,{size:"small",onClick:n,children:r?"Show Setup on open again":"Don't show Setup on open"})})]})]})},Ee=()=>{const{subjects:s,loading:t,available:l}=oe(),a=Z();return e.jsxs("div",{children:[e.jsxs("div",{className:"mb-6",children:[e.jsx("h2",{className:"m-0",children:"Subjects"}),e.jsx("p",{className:"opacity-50 mt-1",children:"Subjects are the roadmap's bets and standing concerns. Edit the vocabulary on the Roadmap page."})]}),t&&e.jsx("p",{children:"Loading…"}),!t&&!l&&e.jsx("p",{className:"opacity-60 m-0",children:"Couldn't load subjects — check the server config."}),!t&&l&&e.jsxs(P,{size:"small",texture:"kraft",children:[s.length===0&&e.jsx("p",{className:"opacity-[0.45] m-0 pb-2",children:"No subjects yet."}),s.map((r,h)=>e.jsxs("div",{children:[e.jsx("div",{className:"pb-2 pt-2",children:r}),h<s.length-1&&e.jsx(A,{})]},r)),s.length>0&&e.jsx(A,{}),e.jsx("div",{className:"pt-3",children:e.jsx(S,{size:"small",onClick:()=>a({to:"/roadmap"}),children:"Go to Roadmap"})})]})]})},Te=140,De=160,Le=110,Pe=({taskKey:s,agentConfig:t,isLast:l,onSave:a,authorConfig:r})=>{const h=q[t.agent]??q["claude-code"],p=r&&r.agent===t.agent?r.model??"":void 0,n=Array.isArray(h.model)?h.model.filter(m=>m!==p):h.model,o=h.effort,[y,v]=u.useState(t.model??"");u.useEffect(()=>{v(t.model??"")},[t.model]);const x=m=>{var w;const f=m,C=q[f],c={agent:f};t.model&&(C.model===null||(w=C.model)!=null&&w.includes(t.model))&&(c.model=t.model),t.effort&&Array.isArray(C.effort)&&(c.effort=t.effort),a(s,c)},N=m=>{a(s,{...t,model:m||void 0})},k=()=>{a(s,{...t,model:y||void 0})},g=m=>{a(s,{...t,effort:m||void 0})};return e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"flex items-center gap-3 pb-2 pt-2",children:[e.jsx("span",{className:"w-[110px] shrink-0 text-sm opacity-[0.65]",children:ue[s]}),e.jsx(B,{size:"small",width:Te,value:t.agent,onChange:x,options:ce.map(m=>({value:m,label:re[m]}))}),Array.isArray(n)?e.jsx(B,{size:"small",width:De,value:t.model??"",onChange:N,options:[...p===""?[]:[{value:"",label:"Default"}],...n.map(m=>({value:m,label:m}))]}):n===null?e.jsx(G,{size:"small",className:"w-[160px]",value:y,placeholder:"Default model",onChange:m=>v(m.target.value),onBlur:k}):null,e.jsx("div",{className:Array.isArray(o)?"visible":"invisible",children:e.jsx(B,{size:"small",width:Le,value:t.effort??"",onChange:g,options:[{value:"",label:"Default"},...(Array.isArray(o)?o:[]).map(m=>({value:m,label:m}))]})})]}),!l&&e.jsx(A,{})]})},ze=()=>e.jsxs("div",{className:"flex items-center gap-3 pb-1",children:[e.jsx("span",{className:"w-[110px] shrink-0 text-sm opacity-[0.45]",children:"Task"}),e.jsx("span",{className:"w-[140px] shrink-0 text-sm opacity-[0.45]",children:"Agent"}),e.jsx("span",{className:"w-[160px] shrink-0 text-sm opacity-[0.45]",children:"Model"}),e.jsx("span",{className:"w-[110px] shrink-0 text-sm opacity-[0.45]",children:"Effort"})]}),Me=()=>{var g,m;const{fileRef:s,config:t,identityLoading:l,iconDataUri:a,uploading:r,portInput:h,setPortInput:p,nameInput:n,setNameInput:o,handleSaveAgentConfig:y,handleSavePort:v,handleToggleIntegration:x,handleSaveName:N,handleFile:k}=be();return e.jsxs("div",{children:[e.jsx("div",{className:"mb-6",children:e.jsx("h2",{className:"m-0",children:"Project Info"})}),t===void 0&&e.jsx("p",{children:"Loading…"}),t===null&&e.jsxs(L,{variant:"warning",children:["No papercamp/config.json found — run ",e.jsx("code",{children:"paper-camp init"})," in this directory first."]}),t&&e.jsxs(P,{size:"small",texture:"kraft",children:[e.jsxs("div",{className:"flex items-end gap-3 pb-3",children:[e.jsx(G,{value:n,onChange:f=>o(f.target.value),onBlur:N,label:"Project Name"}),e.jsxs(F,{size:"small",fillColor:ge,textColor:de.accentGreenDark,children:["v",t.version]})]}),e.jsx(A,{}),e.jsxs("div",{className:"flex items-center gap-3 pb-3 pt-3",children:[a&&e.jsx("img",{src:a,alt:"Project icon",className:"w-10 h-10 object-contain shrink-0 rounded"}),e.jsxs("div",{children:[e.jsx("input",{ref:s,type:"file",accept:".svg,.png,.jpg,.jpeg,.gif,.webp",onChange:k,className:"hidden"}),e.jsx(S,{size:"small",onClick:()=>{var f;return(f=s.current)==null?void 0:f.click()},disabled:r,children:r?"Uploading…":"Choose File"}),l&&e.jsx("p",{className:"text-sm opacity-50 mt-1 mx-0 mb-0",children:"Loading…"}),!l&&!a&&!r&&e.jsx("p",{className:"text-sm opacity-[0.45] mt-1 mx-0 mb-0",children:"No icon set."})]})]}),e.jsx(A,{}),e.jsx("div",{className:"flex items-end gap-3 pb-3 pt-3",children:e.jsx(G,{type:"number",value:h,onChange:f=>p(f.target.value),onBlur:v,label:"Port",helperText:"Default for `paper-camp dev`. Restart the server to apply a change."})}),e.jsx(A,{}),e.jsxs("div",{className:"flex items-center justify-between gap-3 pb-3 pt-3",children:[e.jsxs("div",{children:[e.jsx("p",{className:"m-0",children:"In-app dev toolbar"}),e.jsx("p",{className:"opacity-[0.45] text-sm mt-1 mx-0 mb-0",children:"Inject the paper-camp toolbar into this project's dev server via the Vite plugin."})]}),e.jsx(S,{size:"small",onClick:x,children:((m=(g=t.integration)==null?void 0:g.toolbar)==null?void 0:m.enabled)??!0?"Disable":"Enable"})]}),e.jsx(A,{}),e.jsx(ze,{}),V.map((f,C)=>{var c,w;return e.jsx(Pe,{taskKey:f,agentConfig:((c=t.defaultAgents)==null?void 0:c[f])??I[f],isLast:C===V.length-1,onSave:y,authorConfig:f==="codeReview"?((w=t.defaultAgents)==null?void 0:w.phase)??I.phase:void 0},f)})]}),e.jsxs("p",{className:"opacity-[0.45] text-sm mt-4",children:[e.jsx("strong",{children:"Initialized:"})," ",t?new Date(t.initializedAt).toLocaleString():"—"]})]})},Ue=()=>{const s=ee();return e.jsxs("div",{children:[e.jsx(me,{children:"Settings"}),s==="subjects"?e.jsx(Ee,{}):s==="setup"?e.jsx(Re,{}):s==="merge-policy"?e.jsx(ve,{}):e.jsx(Me,{})]})},Oe=()=>{const s=ee(),t=Z();return e.jsxs(e.Fragment,{children:[e.jsxs($,{label:"General",children:[e.jsx(M,{size:"small",className:"pc-row text-xs",active:s===null,onClick:()=>t({to:"/settings"}),children:"Project Info"}),e.jsx(M,{size:"small",className:"pc-row text-xs",active:s==="setup",onClick:()=>t({to:"/settings/$section",params:{section:"setup"}}),children:"Setup"}),e.jsx(M,{size:"small",className:"pc-row text-xs",active:s==="merge-policy",onClick:()=>t({to:"/settings/$section",params:{section:"merge-policy"}}),children:"Merge Policy"})]}),e.jsx($,{label:"Ideas",children:e.jsx(M,{size:"small",className:"pc-row text-xs",active:s==="subjects",onClick:()=>t({to:"/settings/$section",params:{section:"subjects"}}),children:"Subjects"})})]})};export{Ue as SettingsPage,Oe as SettingsSidebar};
|
|
2
|
+
//# sourceMappingURL=index-CKO_a_mt.js.map
|