truecanvas 0.2.0 → 0.3.0

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.
@@ -5,33 +5,39 @@ import {
5
5
  EditError,
6
6
  Git,
7
7
  Workspace,
8
+ addVitePlugin,
8
9
  allNodes,
9
10
  attrCode,
10
11
  componentJsx,
12
+ configStatus,
11
13
  describeComponent,
12
14
  findDevice,
13
15
  findFrame,
14
16
  findNode,
15
17
  frameChanges,
16
- idOf,
17
18
  initProject,
18
- loadConfig,
19
19
  outlineDoc,
20
20
  parseCanvas,
21
- parseModule,
22
21
  readDesignTokens,
23
22
  shadcnAdd,
24
23
  shadcnInit,
25
24
  shadcnRegistry,
26
25
  shadcnStatus,
26
+ syncRoute,
27
27
  textCode,
28
- walk,
28
+ viteStylesheets,
29
29
  wrapConfigExport,
30
30
  writeCompare
31
- } from "../chunk-ZPARY6OD.js";
31
+ } from "../chunk-XWQ5MS24.js";
32
+ import {
33
+ injectIds
34
+ } from "../chunk-TSHD2S36.js";
35
+ import {
36
+ loadConfig
37
+ } from "../chunk-PBKX3SBC.js";
32
38
  import {
33
39
  Catalog
34
- } from "../chunk-T2TCBSTG.js";
40
+ } from "../chunk-WU7NBTJH.js";
35
41
  import {
36
42
  ICON_LIBRARIES,
37
43
  iconLibraries,
@@ -39,25 +45,6 @@ import {
39
45
  loadIcons,
40
46
  searchIcons
41
47
  } from "../chunk-C4SATRZT.js";
42
-
43
- // src/core/inject.ts
44
- import MagicString from "magic-string";
45
- function injectIds(source, file) {
46
- let ast;
47
- try {
48
- ast = parseModule(source);
49
- } catch {
50
- return source;
51
- }
52
- const s = new MagicString(source);
53
- walk(ast, (node) => {
54
- if (node.type !== "JSXOpeningElement") return;
55
- if (node.attributes.some((a) => a.type === "JSXAttribute" && a.name.name === "data-tc")) return;
56
- const id = file ? `${file}#${idOf(node)}` : idOf(node);
57
- s.appendLeft((node.typeParameters ?? node.name).end, ` data-tc="${id}"`);
58
- });
59
- return s.toString();
60
- }
61
48
  export {
62
49
  CanvasEditor,
63
50
  Catalog,
@@ -67,9 +54,11 @@ export {
67
54
  Git,
68
55
  ICON_LIBRARIES,
69
56
  Workspace,
57
+ addVitePlugin,
70
58
  allNodes,
71
59
  attrCode,
72
60
  componentJsx,
61
+ configStatus,
73
62
  describeComponent,
74
63
  findDevice,
75
64
  findFrame,
@@ -89,7 +78,9 @@ export {
89
78
  shadcnInit,
90
79
  shadcnRegistry,
91
80
  shadcnStatus,
81
+ syncRoute,
92
82
  textCode,
83
+ viteStylesheets,
93
84
  wrapConfigExport,
94
85
  writeCompare
95
86
  };
@@ -0,0 +1,2 @@
1
+ import{i as e,t}from"./react-DB-4Zxce.js";import{A as n,C as r,D as i,S as a,T as o,_ as s,b as c,g as l,h as u,i as d,k as f,n as p,t as m,v as h,w as g,x as _,y as v}from"./Menu-BFifVcgz.js";var y={name:`cloud-download`,size:24,node:[[`path`,{d:`M12 13v8l-4-4`,key:`1f5nwf`}],[`path`,{d:`m12 21 4-4`,key:`1lfcce`}],[`path`,{d:`M4.393 15.269A7 7 0 1 1 15.71 8h1.79a4.5 4.5 0 0 1 2.436 8.284`,key:`ui1hmy`}]],aliases:[`download-cloud`]};y.node;var b=f(y),x={name:`cpu`,size:24,node:[[`path`,{d:`M12 20v2`,key:`1lh1kg`}],[`path`,{d:`M12 2v2`,key:`tus03m`}],[`path`,{d:`M17 20v2`,key:`1rnc9c`}],[`path`,{d:`M17 2v2`,key:`11trls`}],[`path`,{d:`M2 12h2`,key:`1t8f8n`}],[`path`,{d:`M2 17h2`,key:`7oei6x`}],[`path`,{d:`M2 7h2`,key:`asdhe0`}],[`path`,{d:`M20 12h2`,key:`1q8mjw`}],[`path`,{d:`M20 17h2`,key:`1fpfkl`}],[`path`,{d:`M20 7h2`,key:`1o8tra`}],[`path`,{d:`M7 20v2`,key:`4gnj0m`}],[`path`,{d:`M7 2v2`,key:`1i4yhu`}],[`rect`,{x:`4`,y:`4`,width:`16`,height:`16`,rx:`2`,key:`1vbyd7`}],[`rect`,{x:`8`,y:`8`,width:`8`,height:`8`,rx:`1`,key:`z9xiuo`}]]};x.node;var S=f(x),C={name:`folder-open`,size:24,node:[[`path`,{d:`m6 14 1.5-2.9A2 2 0 0 1 9.24 10H20a2 2 0 0 1 1.94 2.5l-1.54 6a2 2 0 0 1-1.95 1.5H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h3.9a2 2 0 0 1 1.69.9l.81 1.2a2 2 0 0 0 1.67.9H18a2 2 0 0 1 2 2v2`,key:`usdka0`}]]};C.node;var w=f(C),T={name:`folder-plus`,size:24,node:[[`path`,{d:`M12 10v6`,key:`1bos4e`}],[`path`,{d:`M9 13h6`,key:`1uhe8q`}],[`path`,{d:`M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Z`,key:`1kt360`}]]};T.node;var E=f(T),D={name:`folder`,size:24,node:[[`path`,{d:`M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Z`,key:`1kt360`}]]};D.node;var O=f(D),k={name:`power`,size:24,node:[[`path`,{d:`M12 2v10`,key:`mnfbl`}],[`path`,{d:`M18.4 6.6a9 9 0 1 1-12.77.04`,key:`obofu9`}]]};k.node;var A=f(k),j={name:`triangle-alert`,size:24,node:[[`path`,{d:`m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3`,key:`wmoenq`}],[`path`,{d:`M12 9v4`,key:`juzpu7`}],[`path`,{d:`M12 17h.01`,key:`p32p05`}]],aliases:[`alert-triangle`]};j.node;var M=f(j),N={name:`wand-sparkles`,size:24,node:[[`path`,{d:`m21.64 3.64-1.28-1.28a1.21 1.21 0 0 0-1.72 0L2.36 18.64a1.21 1.21 0 0 0 0 1.72l1.28 1.28a1.2 1.2 0 0 0 1.72 0L21.64 5.36a1.2 1.2 0 0 0 0-1.72`,key:`ul74o6`}],[`path`,{d:`m14 7 3 3`,key:`1r5n42`}],[`path`,{d:`M5 6v4`,key:`ilb8ba`}],[`path`,{d:`M19 14v4`,key:`blhpug`}],[`path`,{d:`M10 2v2`,key:`7u0qdc`}],[`path`,{d:`M7 8H3`,key:`zfb6yr`}],[`path`,{d:`M21 16h-4`,key:`1cnmox`}],[`path`,{d:`M11 3H9`,key:`1obp7u`}]],aliases:[`wand-2`]};N.node;var P=f(N),F=n(),I=e(t(),1),L=l();async function R(e,t){let n=await fetch(e,t===void 0?void 0:{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify(t)}),r=await n.json();if(!n.ok)throw Error(r.error??`Request failed (${n.status})`);return r}var z=e=>e.replace(/^\/home\/[^/]+/,`~`);function B(){let e=(()=>{try{return JSON.parse(localStorage.getItem(`tc:uiTheme`)??`"system"`)}catch{return`system`}})(),t=e===`dark`||e===`system`&&window.matchMedia(`(prefers-color-scheme: dark)`).matches;document.documentElement.dataset.ui=t?`dark`:`light`}function V(){let[e,t]=(0,I.useState)(null),[n,i]=(0,I.useState)(()=>localStorage.getItem(`tc:hubTab`)??`dashboard`),[o,c]=(0,I.useState)(null),[l,d]=(0,I.useState)(!0),f=(0,I.useRef)(0),p=(0,I.useCallback)(()=>{let e=++f.current;R(`/api/hub/state`).then(n=>e===f.current&&t(n)).catch(()=>{})},[]);(0,I.useEffect)(()=>{B();let e=window.matchMedia(`(prefers-color-scheme: dark)`);e.addEventListener(`change`,B),p();let t=new EventSource(`/api/hub/events`);t.onmessage=()=>p(),t.onopen=()=>{d(!0),p()},t.onerror=()=>d(!1);let n=setInterval(p,5e3);return()=>{e.removeEventListener(`change`,B),t.close(),clearInterval(n)}},[p]);let m=(0,I.useMemo)(()=>(e?.projects??[]).filter(e=>e.running),[e]),h=(0,I.useRef)(null);(0,I.useEffect)(()=>{e&&(m.some(e=>e.path===h.current)&&(h.current=null),n!==`dashboard`&&n!==h.current&&!m.some(e=>e.path===n)&&i(`dashboard`))},[e,m,n]),(0,I.useEffect)(()=>{localStorage.setItem(`tc:hubTab`,n),R(`/api/hub/active`,{path:n===`dashboard`?``:n}).catch(()=>{})},[n]);let g=(0,I.useRef)(Date.now());(0,I.useEffect)(()=>{let t=e?.focus;!t||t.at<=g.current||!m.some(e=>e.path===t.path)||(g.current=t.at,i(t.path))},[e,m]);let _=m.find(e=>e.path===n)?.name;(0,I.useEffect)(()=>{document.title=_?`${_} · Truecanvas`:`Truecanvas`},[_]);let v=async e=>{h.current=e.path,i(e.path);try{await R(`/api/hub/open`,{path:e.path})}catch(e){h.current=null,c(e.message)}p()},y=async e=>{let t=m.findIndex(t=>t.path===e.path);n===e.path&&i(m[t+1]?.path??m[t-1]?.path??`dashboard`);try{await R(`/api/hub/close`,{path:e.path})}catch(e){c(e.message)}p()};(0,I.useEffect)(()=>{let e=e=>{if(!e.ctrlKey)return;let t=[`dashboard`,...m.map(e=>e.path)];if(e.key===`Tab`){e.preventDefault();let r=t.indexOf(n);i(t[(r+(e.shiftKey?-1:1)+t.length)%t.length])}};return window.addEventListener(`keydown`,e),()=>window.removeEventListener(`keydown`,e)},[m,n]);let b=m.reduce((e,t)=>e+(t.running?.memory??0),0),[x,C]=(0,I.useState)(!1),[w,T]=(0,I.useState)(!1),E=async()=>{C(!1),await fetch(`/api/hub/quit`,{method:`POST`}).catch(()=>{}),T(!0),setTimeout(()=>window.close(),300)};return(0,I.useEffect)(()=>{let e=e=>{e.ctrlKey&&(e.key===`q`||e.key===`Q`)&&(e.preventDefault(),m.length?C(!0):E())};return window.addEventListener(`keydown`,e),()=>window.removeEventListener(`keydown`,e)}),w?(0,L.jsxs)(`div`,{className:`hub-center`,style:{height:`100%`},children:[(0,L.jsx)(`img`,{src:`/favicon.svg`,width:44,height:44,alt:``}),(0,L.jsx)(`div`,{style:{fontWeight:600,marginTop:6},children:`Truecanvas has quit`}),(0,L.jsx)(`div`,{className:`muted`,children:"You can close this window. Open it again from your app launcher or with `truecanvas`."})]}):(0,L.jsxs)(`div`,{className:`hub`,children:[(0,L.jsxs)(`header`,{className:`tabbar`,role:`tablist`,children:[(0,L.jsxs)(`button`,{role:`tab`,"aria-selected":n===`dashboard`,className:`hub-tab home-tab${n===`dashboard`?` on`:``}`,onClick:()=>i(`dashboard`),children:[(0,L.jsx)(r,{size:14}),(0,L.jsx)(`span`,{children:`Dashboard`})]}),(0,L.jsx)(`span`,{className:`tab-sep`}),(0,L.jsx)(`div`,{className:`tab-strip`,children:m.map(e=>(0,L.jsxs)(`div`,{role:`tab`,tabIndex:0,"aria-selected":n===e.path,className:`hub-tab${n===e.path?` on`:``}`,onClick:()=>i(e.path),onAuxClick:t=>t.button===1&&void y(e),title:z(e.path),children:[e.running?.status===`starting`?(0,L.jsx)(a,{size:14,className:`spin-working`}):e.running?.status===`failed`?(0,L.jsx)(M,{size:14,className:`warn`}):(0,L.jsx)(H,{path:e.path}),(0,L.jsx)(`span`,{className:`label`,children:e.name}),(0,L.jsx)(`button`,{className:`tab-close`,"aria-label":`Close ${e.name}`,onClick:t=>{t.stopPropagation(),y(e)},children:(0,L.jsx)(s,{size:12})})]},e.path))}),(0,L.jsxs)(`div`,{className:`tabbar-right`,children:[b>0&&(0,L.jsx)(u,{label:`Memory used by open projects (app + Truecanvas)`,side:`bottom`,children:(0,L.jsxs)(`span`,{className:`mem-chip`,children:[(0,L.jsx)(S,{size:12}),` `,b>=1024?`${(b/1024).toFixed(1)} GB`:`${b} MB`]})}),(0,L.jsx)(U,{onQuit:()=>C(!0)})]})]}),x&&(0,L.jsx)(W,{running:m.map(e=>e.name),onCancel:()=>C(!1),onQuit:()=>void E()}),(0,L.jsxs)(`main`,{className:`hub-body`,children:[n===`dashboard`&&e&&(0,L.jsx)(K,{state:e,onOpen:v,refresh:p}),m.map(e=>(0,L.jsx)(G,{project:e,visible:n===e.path,onRetry:()=>void v(e)},e.path)),!l&&(0,L.jsxs)(`div`,{className:`banner`,role:`status`,style:{top:12},children:[(0,L.jsx)(a,{size:14,className:`spin-working`}),(0,L.jsx)(`div`,{className:`muted`,children:`Lost connection to Truecanvas. Reconnecting…`})]}),o&&(0,L.jsxs)(`div`,{className:`banner`,role:`alert`,style:{top:12},children:[(0,L.jsx)(`span`,{className:`dot`}),(0,L.jsx)(`div`,{children:o}),(0,L.jsx)(`button`,{className:`icon-btn`,"aria-label":`Dismiss`,onClick:()=>c(null),children:(0,L.jsx)(s,{size:14})})]})]})]})}function H({path:e,size:t=14}){let[n,r]=(0,I.useState)(!1);return n?(0,L.jsx)(O,{size:t,className:`folder-icon`}):(0,L.jsx)(`img`,{className:`project-favicon`,src:`/api/hub/icon?path=${encodeURIComponent(e)}`,width:t,height:t,alt:``,onError:()=>r(!0)})}function U({onQuit:e}){let[t,n]=(0,I.useState)(null);return(0,L.jsxs)(L.Fragment,{children:[(0,L.jsx)(u,{label:`Truecanvas`,side:`bottom`,children:(0,L.jsx)(`button`,{className:`icon-btn app-menu-btn`,"aria-label":`Truecanvas menu`,onClick:e=>{let t=e.currentTarget.getBoundingClientRect();n({x:t.right-220,y:t.bottom+6})},children:(0,L.jsx)(o,{size:16})})}),t&&(0,L.jsx)(m,{x:t.x,y:t.y,onClose:()=>n(null),items:[{label:`Reload window`,icon:(0,L.jsx)(v,{size:14}),kbd:`Ctrl+R`,onSelect:()=>location.reload()},`sep`,{label:`Quit Truecanvas`,icon:(0,L.jsx)(A,{size:14}),kbd:`Ctrl+Q`,danger:!0,onSelect:e}]})]})}function W({running:e,onCancel:t,onQuit:n}){return(0,L.jsxs)(d,{title:`Quit Truecanvas?`,role:`alertdialog`,width:380,onClose:t,children:[(0,L.jsx)(`p`,{className:`muted`,children:e.length?`This also stops ${e.length===1?`the app`:`the apps`} it started: ${e.join(`, `)}. Your files are saved as you edit.`:`Your files are saved as you edit.`}),(0,L.jsxs)(`div`,{className:`modal-actions`,children:[(0,L.jsx)(`button`,{className:`btn outline`,onClick:t,children:`Cancel`}),(0,L.jsx)(`button`,{className:`btn danger-solid`,autoFocus:!0,onClick:n,children:`Quit`})]})]})}function G({project:e,visible:t,onRetry:n}){let r=e.running;return(0,L.jsxs)(`div`,{className:`project-view`,style:{display:t?`block`:`none`},children:[r.status===`ready`&&(0,L.jsx)(`iframe`,{title:e.name,src:`${r.editor}/`,allow:`clipboard-read; clipboard-write`}),r.status===`starting`&&(0,L.jsxs)(`div`,{className:`hub-center`,children:[(0,L.jsx)(a,{size:22,className:`spin-working`}),(0,L.jsxs)(`div`,{className:`muted`,children:[`Starting `,e.name,`…`]}),(0,L.jsx)(`div`,{className:`faint`,children:`Your app and its Truecanvas editor are booting.`})]}),r.status===`failed`&&(0,L.jsxs)(`div`,{className:`hub-center`,children:[(0,L.jsx)(M,{size:22,className:`warn`}),(0,L.jsxs)(`div`,{style:{fontWeight:600},children:[e.name,` didn’t start`]}),(0,L.jsx)(`pre`,{className:`job-log`,style:{maxWidth:640},children:r.error}),(0,L.jsxs)(`button`,{className:`btn primary`,onClick:n,children:[(0,L.jsx)(v,{size:13}),` Try again`]})]})]})}function K({state:e,onOpen:t,refresh:n}){let[r,a]=(0,I.useState)(null),[l,u]=(0,I.useState)(null),[d,f]=(0,I.useState)(null),[_,v]=(0,I.useState)(null),[y,x]=(0,I.useState)(``),[S,C]=(0,I.useState)(null);(0,I.useEffect)(()=>{R(`/api/hub/discover`).then(e=>a(e.found)).catch(()=>a([]))},[e.projects.length]);let T=async(e,t)=>{let n=await R(e,t);v(n)},D=e.projects.filter(e=>!y||`${e.name} ${e.path}`.toLowerCase().includes(y.toLowerCase()));return(0,L.jsxs)(`div`,{className:`dashboard scroll`,children:[(0,L.jsxs)(`div`,{className:`dash-inner`,children:[(0,L.jsxs)(`div`,{className:`dash-head`,children:[(0,L.jsxs)(`div`,{children:[(0,L.jsx)(`h1`,{children:`Projects`}),(0,L.jsx)(`p`,{className:`muted`,children:`Each project is a Next.js or Vite app. Its canvases are .tsx files in the repo.`})]}),(0,L.jsxs)(`div`,{className:`dash-actions`,children:[(0,L.jsxs)(`div`,{className:`field`,style:{width:200},children:[(0,L.jsx)(`span`,{className:`prefix`,children:(0,L.jsx)(h,{size:13})}),(0,L.jsx)(`input`,{value:y,placeholder:`Search projects`,onChange:e=>x(e.target.value)})]}),(0,L.jsxs)(`button`,{className:`btn outline`,onClick:()=>u(`open`),children:[(0,L.jsx)(w,{size:14}),` Open folder`]}),(0,L.jsxs)(`button`,{className:`btn outline`,onClick:()=>u(`clone`),children:[(0,L.jsx)(b,{size:14}),` Clone from GitHub`]}),(0,L.jsxs)(`button`,{className:`btn primary`,onClick:()=>u(`new`),children:[(0,L.jsx)(c,{size:14}),` New project`]})]})]}),D.length===0&&!y&&(0,L.jsxs)(`div`,{className:`dash-empty`,children:[(0,L.jsx)(E,{size:28}),(0,L.jsx)(`div`,{style:{fontWeight:600,marginTop:10},children:`No projects yet`}),(0,L.jsx)(`div`,{className:`muted`,children:`Open a Next.js or Vite app from your computer, clone one from GitHub, or create a new one.`})]}),(0,L.jsx)(`div`,{className:`project-grid`,children:D.map(e=>(0,L.jsxs)(`div`,{className:`project-card${e.running?` live`:``}${e.exists?``:` missing`}`,role:`button`,tabIndex:0,onClick:()=>e.ready&&e.exists&&t(e),onKeyDown:n=>n.key===`Enter`&&e.ready&&t(e),onContextMenu:t=>{t.preventDefault(),C({x:t.clientX,y:t.clientY,p:e})},children:[(0,L.jsxs)(`div`,{className:`card-top`,children:[(0,L.jsx)(`span`,{className:`card-icon`,children:(0,L.jsx)(H,{path:e.path,size:22})}),(0,L.jsx)(`button`,{className:`icon-btn sm`,"aria-label":`Options for ${e.name}`,onClick:t=>{t.stopPropagation();let n=t.currentTarget.getBoundingClientRect();C({x:n.left,y:n.bottom+4,p:e})},children:(0,L.jsx)(o,{size:14})})]}),(0,L.jsx)(`div`,{className:`card-name`,children:e.name}),(0,L.jsx)(`div`,{className:`card-path faint`,children:z(e.path)}),(0,L.jsx)(`div`,{className:`card-meta`,children:e.exists?e.ready?(0,L.jsxs)(L.Fragment,{children:[(0,L.jsxs)(`span`,{className:`faint`,children:[e.canvases,` `,e.canvases===1?`page`:`pages`,` · `,p(e.lastOpened,`long`)]}),e.running&&(0,L.jsxs)(`span`,{className:`live-tag`,children:[(0,L.jsx)(`span`,{className:`live-dot`}),` `,e.running.memory?`${e.running.memory} MB`:`open`]})]}):(0,L.jsxs)(`button`,{className:`btn primary sm-btn`,onClick:t=>{t.stopPropagation(),T(`/api/hub/setup`,{path:e.path})},children:[(0,L.jsx)(P,{size:13}),` Set up Truecanvas`]}):(0,L.jsx)(`span`,{className:`chip`,children:`Folder missing`})})]},e.path))}),r&&r.length>0&&(0,L.jsxs)(L.Fragment,{children:[(0,L.jsx)(`h2`,{children:`Found on this computer`}),(0,L.jsx)(`div`,{className:`found-list`,children:r.map(e=>(0,L.jsxs)(`div`,{className:`found-row`,children:[(0,L.jsx)(H,{path:e.path,size:16}),(0,L.jsx)(`span`,{className:`name`,children:e.name}),(0,L.jsx)(`span`,{className:`faint path`,children:z(e.path)}),(0,L.jsx)(`button`,{className:`btn outline`,onClick:async()=>{await R(`/api/hub/add`,{path:e.path}),n()},children:`Add`})]},e.path))})]})]}),S&&(0,L.jsx)(m,{x:S.x,y:S.y,onClose:()=>C(null),items:[...S.p.ready?[{label:`Open`,icon:(0,L.jsx)(i,{size:14}),onSelect:()=>t(S.p)}]:[],...S.p.ready?[]:[{label:`Set up Truecanvas`,icon:(0,L.jsx)(P,{size:14}),onSelect:()=>void T(`/api/hub/setup`,{path:S.p.path})}],...S.p.ready?[{label:`Pull requests…`,icon:(0,L.jsx)(g,{size:14}),onSelect:()=>f(S.p)}]:[],...S.p.running?[{label:`Stop app`,icon:(0,L.jsx)(A,{size:14}),onSelect:()=>void R(`/api/hub/close`,{path:S.p.path}).then(n)}]:[],`sep`,{label:`Remove from list`,icon:(0,L.jsx)(s,{size:14}),danger:!0,onSelect:()=>void R(`/api/hub/forget`,{path:S.p.path}).then(n)}]}),l===`open`&&(0,L.jsx)(J,{onClose:()=>u(null),onPick:async e=>{let r=await R(`/api/hub/add`,{path:e});u(null),n(),r.ready&&t({path:r.path})}}),l===`clone`&&(0,L.jsx)(Y,{onClose:()=>u(null),onClone:async(e,t)=>{u(null),await T(`/api/hub/clone`,{repo:e,parent:t})}}),d&&(0,L.jsx)(X,{project:d,onClose:()=>f(null),onOpened:()=>{let e=d;f(null),t(e)}}),l===`new`&&(0,L.jsx)(Z,{onClose:()=>u(null),onCreate:async(e,t)=>{u(null),await T(`/api/hub/create`,{name:e,parent:t})}}),_&&(0,L.jsx)(Q,{job:_,onClose:e=>{v(null),n(),e&&t({path:e})}})]})}function q({title:e,children:t,onClose:n,width:r=460}){return(0,L.jsx)(d,{title:e,width:r,onClose:n,children:t})}function J({onClose:e,onPick:t}){let[n,r]=(0,I.useState)(`~/Github`),[i,a]=(0,I.useState)(null),[o,s]=(0,I.useState)(null),c=e=>void t(e).catch(e=>s(e.message)),[l,u]=(0,I.useState)(null);return(0,I.useEffect)(()=>{let e=!1,t=setTimeout(()=>{R(`/api/hub/ls?path=${encodeURIComponent(n)}`).then(t=>{e||(a(t),u(n),s(null))}).catch(t=>!e&&s(t.message))},150);return()=>{e=!0,clearTimeout(t)}},[n]),(0,L.jsxs)(q,{title:`Open a project folder`,onClose:e,width:520,children:[(0,L.jsx)(`p`,{className:`muted`,children:`Pick the root of a Next.js or Vite app (the folder with its package.json).`}),(0,L.jsxs)(`div`,{className:`field`,children:[(0,L.jsx)(`span`,{className:`prefix`,children:(0,L.jsx)(O,{size:13})}),(0,L.jsx)(`input`,{autoFocus:!0,value:n,onChange:e=>r(e.target.value),onKeyDown:e=>e.key===`Enter`&&c(i&&l===n?i.path:n),spellCheck:!1})]}),(0,L.jsxs)(`div`,{className:`dir-list`,children:[i&&(0,L.jsxs)(`button`,{className:`dir-row`,onClick:()=>r(`${i.path}/..`),children:[(0,L.jsx)(O,{size:14,className:`faint`}),` ..`]}),i?.dirs.map(e=>(0,L.jsxs)(`button`,{className:`dir-row`,onClick:()=>r(`${i.path}/${e.name}`),onDoubleClick:()=>e.next&&c(`${i.path}/${e.name}`),children:[(0,L.jsx)(O,{size:14,className:e.next?``:`faint`}),(0,L.jsx)(`span`,{children:e.name}),e.next&&(0,L.jsx)(`span`,{className:`chip accent`,children:`App`})]},e.name)),o&&(0,L.jsx)(`div`,{className:`faint`,style:{padding:8},children:o})]}),(0,L.jsxs)(`div`,{className:`modal-actions`,children:[(0,L.jsx)(`button`,{className:`btn outline`,onClick:e,children:`Cancel`}),(0,L.jsxs)(`button`,{className:`btn primary`,onClick:()=>c(i?.path??n),children:[`Open `,i?z(i.path).split(`/`).pop():``]})]})]})}function Y({onClose:e,onClone:t}){let[n,r]=(0,I.useState)(null),[i,a]=(0,I.useState)(``),[o,s]=(0,I.useState)(`~/Github`);(0,I.useEffect)(()=>{R(`/api/hub/github/repos`).then(r).catch(e=>r({gh:!1,error:e.message,repos:[]}))},[]);let c=/^(https?:|git@|ssh:|file:)/.test(i.trim())||/^[\w.-]+\/[\w.-]+$/.test(i.trim()),l=(n?.repos??[]).filter(e=>!i||`${e.nameWithOwner} ${e.description??``}`.toLowerCase().includes(i.toLowerCase()));return(0,L.jsxs)(q,{title:`Clone from GitHub`,onClose:e,width:560,children:[(0,L.jsx)(`p`,{className:`muted`,children:`Clones the repo, installs its dependencies and sets up Truecanvas if it isn't there yet. Then it's one click to open.`}),(0,L.jsxs)(`div`,{className:`field`,children:[(0,L.jsx)(`span`,{className:`prefix`,children:(0,L.jsx)(h,{size:13})}),(0,L.jsx)(`input`,{autoFocus:!0,value:i,placeholder:`Search your repositories, or paste owner/name or a git URL`,onChange:e=>a(e.target.value),onKeyDown:e=>e.key===`Enter`&&c&&t(i.trim(),o),spellCheck:!1})]}),(0,L.jsxs)(`div`,{className:`dir-list`,style:{height:260},children:[n===null&&(0,L.jsx)(`div`,{className:`faint`,style:{padding:10},children:`Loading your repositories…`}),n&&!n.gh&&(0,L.jsxs)(`div`,{className:`faint`,style:{padding:10,lineHeight:1.5},children:[`The GitHub CLI isn't signed in, so your repositories can't be listed. Paste a git URL above, or run `,(0,L.jsx)(`span`,{className:`mono`,children:`gh auth login`}),` in a terminal.`]}),c&&!l.some(e=>e.nameWithOwner===i.trim())&&(0,L.jsxs)(`button`,{className:`dir-row`,onClick:()=>t(i.trim(),o),children:[(0,L.jsx)(b,{size:14}),(0,L.jsxs)(`span`,{children:[`Clone `,(0,L.jsx)(`strong`,{children:i.trim()})]})]}),l.map(e=>(0,L.jsxs)(`button`,{className:`dir-row repo-row`,onClick:()=>t(e.nameWithOwner,o),title:e.description??``,children:[e.isPrivate?(0,L.jsx)(_,{size:13,className:`faint`}):(0,L.jsx)(b,{size:13,className:`faint`}),(0,L.jsx)(`span`,{style:{fontWeight:500},children:e.nameWithOwner}),(0,L.jsx)(`span`,{className:`faint`,style:{marginLeft:`auto`,whiteSpace:`nowrap`},children:p(Date.parse(e.updatedAt),`long`)})]},e.nameWithOwner))]}),(0,L.jsxs)(`div`,{className:`field`,style:{marginTop:10},children:[(0,L.jsx)(`span`,{className:`prefix`,children:(0,L.jsx)(O,{size:13})}),(0,L.jsx)(`input`,{value:o,onChange:e=>s(e.target.value),"aria-label":`Clone into`,spellCheck:!1})]}),(0,L.jsx)(`div`,{className:`modal-actions`,style:{marginTop:12},children:(0,L.jsx)(`button`,{className:`btn outline`,onClick:e,children:`Cancel`})})]})}function X({project:e,onClose:t,onOpened:n}){let[r,i]=(0,I.useState)(null),[o,s]=(0,I.useState)(null),[c,l]=(0,I.useState)(null);(0,I.useEffect)(()=>{R(`/api/hub/prs?path=${encodeURIComponent(e.path)}`).then(i).catch(e=>i({error:e.message,prs:[]}))},[e.path]);let u=async t=>{s(t),l(null);try{await R(`/api/hub/pr-checkout`,{path:e.path,number:String(t)}),n()}catch(e){l(e.message)}finally{s(null)}};return(0,L.jsxs)(q,{title:`Pull requests · ${e.name}`,onClose:t,width:560,children:[(0,L.jsx)(`p`,{className:`muted`,children:`Open a pull request to see its design in Truecanvas: its branch is checked out and the canvases show that version.`}),(0,L.jsxs)(`div`,{className:`dir-list`,style:{height:280},children:[r===null&&(0,L.jsx)(`div`,{className:`faint`,style:{padding:10},children:`Loading…`}),r?.error&&(0,L.jsx)(`div`,{className:`faint`,style:{padding:10},children:r.error}),r&&!r.error&&r.prs.length===0&&(0,L.jsx)(`div`,{className:`faint`,style:{padding:10},children:`No open pull requests.`}),r?.prs.map(e=>(0,L.jsxs)(`button`,{className:`dir-row repo-row`,disabled:o!==null,onClick:()=>void u(e.number),children:[o===e.number?(0,L.jsx)(a,{size:14,className:`spin-working`}):(0,L.jsx)(g,{size:14,className:e.isDraft?`faint`:`pr-open`}),(0,L.jsxs)(`span`,{style:{fontWeight:500,overflow:`hidden`,textOverflow:`ellipsis`,whiteSpace:`nowrap`},children:[`#`,e.number,` `,e.title]}),(0,L.jsxs)(`span`,{className:`faint`,style:{marginLeft:`auto`,whiteSpace:`nowrap`},children:[e.author?.login,` · `,p(Date.parse(e.updatedAt),`long`)]})]},e.number))]}),c&&(0,L.jsx)(`div`,{className:`hub-error`,children:c}),(0,L.jsx)(`div`,{className:`modal-actions`,style:{marginTop:12},children:(0,L.jsx)(`button`,{className:`btn outline`,onClick:t,children:`Close`})})]})}function Z({onClose:e,onCreate:t}){let[n,r]=(0,I.useState)(``),[i,a]=(0,I.useState)(`~/Github`),o=n.trim().toLowerCase().replace(/[^a-z0-9-_]+/g,`-`).replace(/^-+|-+$/g,``);return(0,L.jsxs)(q,{title:`New project`,onClose:e,children:[(0,L.jsx)(`p`,{className:`muted`,children:`Creates a Next.js app with TypeScript and Tailwind, then sets up Truecanvas in it.`}),(0,L.jsxs)(`div`,{style:{display:`grid`,gap:8},children:[(0,L.jsxs)(`div`,{className:`field`,children:[(0,L.jsx)(`span`,{className:`prefix`,children:`Name`}),(0,L.jsx)(`input`,{autoFocus:!0,value:n,placeholder:`my-app`,onChange:e=>r(e.target.value),onKeyDown:e=>e.key===`Enter`&&o&&t(o,i)})]}),(0,L.jsxs)(`div`,{className:`field`,children:[(0,L.jsx)(`span`,{className:`prefix`,children:`In`}),(0,L.jsx)(`input`,{value:i,onChange:e=>a(e.target.value),spellCheck:!1})]}),o&&(0,L.jsx)(`div`,{className:`faint mono`,children:`${i.replace(/\/$/,``)}/${o}`})]}),(0,L.jsxs)(`div`,{className:`modal-actions`,style:{marginTop:16},children:[(0,L.jsx)(`button`,{className:`btn outline`,onClick:e,children:`Cancel`}),(0,L.jsx)(`button`,{className:`btn primary`,disabled:!o,onClick:()=>t(o,i),children:`Create project`})]})]})}function Q({job:e,onClose:t}){let[n,r]=(0,I.useState)(e),i=(0,I.useRef)(null);return(0,I.useEffect)(()=>{if(n.status!==`running`)return;let e=setInterval(()=>void R(`/api/hub/jobs/${n.id}`).then(r),700);return()=>clearInterval(e)},[n.id,n.status]),(0,I.useEffect)(()=>{i.current?.scrollTo({top:i.current.scrollHeight})},[n.log.length]),(0,I.useEffect)(()=>{if(n.status!==`done`||!n.result)return;let e=setTimeout(()=>t(n.result),700);return()=>clearTimeout(e)},[n.status,n.result]),(0,L.jsxs)(q,{title:n.title,onClose:()=>n.status!==`running`&&t(),width:600,children:[(0,L.jsxs)(`div`,{className:`job-status`,children:[n.status===`running`?(0,L.jsx)(a,{size:16,className:`spin-working`}):n.status===`done`?(0,L.jsx)(`span`,{className:`live-dot`}):(0,L.jsx)(M,{size:16,className:`warn`}),(0,L.jsx)(`span`,{children:n.status===`running`?`Working… this can take a minute.`:n.status===`done`?`Done.`:`Something went wrong.`})]}),(0,L.jsx)(`pre`,{className:`job-log`,ref:i,children:n.log.slice(-120).join(`
2
+ `)}),(0,L.jsx)(`div`,{className:`modal-actions`,children:n.status===`done`&&n.result?(0,L.jsx)(`button`,{className:`btn primary`,onClick:()=>t(n.result),children:`Opening…`}):(0,L.jsx)(`button`,{className:`btn outline`,disabled:n.status===`running`,onClick:()=>t(),children:`Close`})})]})}(0,F.createRoot)(document.getElementById(`root`)).render((0,L.jsx)(V,{}));