@tanstack/cta-ui 0.15.2 → 0.15.4
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/assets/index-BLGJkAxX.css +1 -0
- package/dist/assets/index-DPjMQkKx.js +208 -0
- package/dist/assets/index-DPjMQkKx.js.map +1 -0
- package/dist/index.html +3 -2
- package/index.html +1 -0
- package/lib/engine-handling/create-app-wrapper.ts +3 -4
- package/lib/engine-handling/generate-initial-payload.ts +12 -20
- package/lib/engine-handling/server-environment.ts +2 -2
- package/lib/index.ts +33 -15
- package/lib-dist/engine-handling/create-app-wrapper.js +3 -2
- package/lib-dist/engine-handling/generate-initial-payload.d.ts +8 -6
- package/lib-dist/engine-handling/generate-initial-payload.js +9 -14
- package/lib-dist/engine-handling/server-environment.d.ts +3 -3
- package/lib-dist/index.d.ts +1 -0
- package/lib-dist/index.js +29 -11
- package/package.json +3 -32
- package/src/index.tsx +2 -42
- package/src/main.tsx +0 -1
- package/src/styles.css +2 -0
- package/src/types.d.ts +13 -8
- package/dist/assets/index-BktnQA5a.js +0 -213
- package/dist/assets/index-BktnQA5a.js.map +0 -1
- package/dist/assets/index-CpoUtYXp.css +0 -1
- package/dist/logo-color-100w.png +0 -0
- package/dist/logo192.png +0 -0
- package/dist/logo512.png +0 -0
- package/dist/tailwind.svg +0 -1
- package/dist/tanstack.png +0 -0
- package/dist/typescript.svg +0 -1
- package/lib/engine-handling/framework-registration.ts +0 -11
- package/lib-dist/engine-handling/framework-registration.d.ts +0 -1
- package/lib-dist/engine-handling/framework-registration.js +0 -10
- package/public/logo-color-100w.png +0 -0
- package/public/logo192.png +0 -0
- package/public/logo512.png +0 -0
- package/public/tailwind.svg +0 -1
- package/public/tanstack.png +0 -0
- package/public/typescript.svg +0 -1
- package/src/components/StatusList.tsx +0 -22
- package/src/components/add-on-info-dialog.tsx +0 -39
- package/src/components/background-animation.tsx +0 -229
- package/src/components/cta-sidebar.tsx +0 -50
- package/src/components/custom-add-on-dialog.tsx +0 -79
- package/src/components/file-navigator.tsx +0 -203
- package/src/components/file-tree.tsx +0 -35
- package/src/components/file-viewer.tsx +0 -67
- package/src/components/header.tsx +0 -31
- package/src/components/sidebar-items/add-ons.tsx +0 -94
- package/src/components/sidebar-items/mode-selector.tsx +0 -57
- package/src/components/sidebar-items/project-name.tsx +0 -28
- package/src/components/sidebar-items/run-add-ons.tsx +0 -71
- package/src/components/sidebar-items/run-create-app.tsx +0 -82
- package/src/components/sidebar-items/starter.tsx +0 -123
- package/src/components/sidebar-items/typescript-switch.tsx +0 -52
- package/src/components/starters-carousel.tsx +0 -45
- package/src/components/startup-dialog.tsx +0 -71
- package/src/components/toaster.tsx +0 -29
- package/src/components/ui/button.tsx +0 -61
- package/src/components/ui/carousel.tsx +0 -239
- package/src/components/ui/checkbox.tsx +0 -30
- package/src/components/ui/dialog.tsx +0 -138
- package/src/components/ui/dropdown-menu.tsx +0 -255
- package/src/components/ui/input.tsx +0 -21
- package/src/components/ui/label.tsx +0 -22
- package/src/components/ui/popover.tsx +0 -46
- package/src/components/ui/separator.tsx +0 -28
- package/src/components/ui/sheet.tsx +0 -137
- package/src/components/ui/sidebar.tsx +0 -726
- package/src/components/ui/skeleton.tsx +0 -13
- package/src/components/ui/sonner.tsx +0 -23
- package/src/components/ui/switch.tsx +0 -29
- package/src/components/ui/table.tsx +0 -114
- package/src/components/ui/tabs.tsx +0 -64
- package/src/components/ui/toggle-group.tsx +0 -71
- package/src/components/ui/toggle.tsx +0 -49
- package/src/components/ui/tooltip.tsx +0 -61
- package/src/components/ui/tree-view.tsx +0 -497
- package/src/file-classes.ts +0 -54
- package/src/hooks/use-mobile.ts +0 -19
- package/src/hooks/use-mounted.ts +0 -9
- package/src/hooks/use-preferred-reduced-motion.ts +0 -27
- package/src/hooks/use-streaming-status.ts +0 -70
- package/src/lib/api.ts +0 -92
- package/src/lib/utils.ts +0 -6
- package/src/store/add-ons.ts +0 -81
- package/src/store/project.ts +0 -347
- package/tests/store/add-ons.test.ts +0 -222
- package/vitest.config.ts +0 -6
|
@@ -1,203 +0,0 @@
|
|
|
1
|
-
import { useMemo, useState } from 'react'
|
|
2
|
-
import { FileText, Folder } from 'lucide-react'
|
|
3
|
-
|
|
4
|
-
import FileViewer from './file-viewer'
|
|
5
|
-
import FileTree from './file-tree'
|
|
6
|
-
|
|
7
|
-
import type { FileTreeItem } from '@/types'
|
|
8
|
-
|
|
9
|
-
import { Label } from '@/components/ui/label'
|
|
10
|
-
import { Switch } from '@/components/ui/switch'
|
|
11
|
-
|
|
12
|
-
import {
|
|
13
|
-
useApplicationMode,
|
|
14
|
-
useDryRun,
|
|
15
|
-
useFilters,
|
|
16
|
-
useOriginalOutput,
|
|
17
|
-
useProjectLocalFiles,
|
|
18
|
-
useReady,
|
|
19
|
-
} from '@/store/project'
|
|
20
|
-
|
|
21
|
-
import { getFileClass, twClasses } from '@/file-classes'
|
|
22
|
-
|
|
23
|
-
export function Filters() {
|
|
24
|
-
const { includedFiles, toggleFilter } = useFilters()
|
|
25
|
-
|
|
26
|
-
return (
|
|
27
|
-
<div className="bg-white dark:bg-black/40 shadow-xl p-4 rounded-lg flex flex-row items-center gap-4 mb-2">
|
|
28
|
-
<h3 className="font-medium whitespace-nowrap">File Filters</h3>
|
|
29
|
-
<div className="flex flex-row items-center">
|
|
30
|
-
<Switch
|
|
31
|
-
id="unchanged"
|
|
32
|
-
checked={includedFiles.includes('unchanged')}
|
|
33
|
-
onCheckedChange={() => toggleFilter('unchanged')}
|
|
34
|
-
className="mr-2"
|
|
35
|
-
/>
|
|
36
|
-
<Label htmlFor="unchanged" className={twClasses.unchanged}>
|
|
37
|
-
Unchanged
|
|
38
|
-
</Label>
|
|
39
|
-
</div>
|
|
40
|
-
<div className="flex flex-row items-center">
|
|
41
|
-
<Switch
|
|
42
|
-
id="added"
|
|
43
|
-
checked={includedFiles.includes('added')}
|
|
44
|
-
onCheckedChange={() => toggleFilter('added')}
|
|
45
|
-
className="mr-2"
|
|
46
|
-
/>
|
|
47
|
-
<Label htmlFor="added" className={twClasses.added}>
|
|
48
|
-
Added
|
|
49
|
-
</Label>
|
|
50
|
-
</div>
|
|
51
|
-
<div className="flex flex-row items-center">
|
|
52
|
-
<Switch
|
|
53
|
-
id="modified"
|
|
54
|
-
checked={includedFiles.includes('modified')}
|
|
55
|
-
onCheckedChange={() => toggleFilter('modified')}
|
|
56
|
-
className="mr-2"
|
|
57
|
-
/>
|
|
58
|
-
<Label htmlFor="modified" className={twClasses.modified}>
|
|
59
|
-
Modified
|
|
60
|
-
</Label>
|
|
61
|
-
</div>
|
|
62
|
-
<div className="flex flex-row items-center">
|
|
63
|
-
<Switch
|
|
64
|
-
id="deleted"
|
|
65
|
-
checked={includedFiles.includes('deleted')}
|
|
66
|
-
onCheckedChange={() => toggleFilter('deleted')}
|
|
67
|
-
className="mr-2"
|
|
68
|
-
/>
|
|
69
|
-
<Label htmlFor="deleted" className={twClasses.deleted}>
|
|
70
|
-
Deleted
|
|
71
|
-
</Label>
|
|
72
|
-
</div>
|
|
73
|
-
<div className="flex flex-row items-center">
|
|
74
|
-
<Switch
|
|
75
|
-
id="overwritten"
|
|
76
|
-
checked={includedFiles.includes('overwritten')}
|
|
77
|
-
onCheckedChange={() => toggleFilter('overwritten')}
|
|
78
|
-
className="mr-2"
|
|
79
|
-
/>
|
|
80
|
-
<Label htmlFor="overwritten" className={twClasses.overwritten}>
|
|
81
|
-
Overwritten
|
|
82
|
-
</Label>
|
|
83
|
-
</div>
|
|
84
|
-
</div>
|
|
85
|
-
)
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
export default function FileNavigator() {
|
|
89
|
-
const [selectedFile, setSelectedFile] = useState<string | null>(
|
|
90
|
-
'./package.json',
|
|
91
|
-
)
|
|
92
|
-
|
|
93
|
-
const projectFiles = useOriginalOutput()
|
|
94
|
-
const localTree = useProjectLocalFiles()
|
|
95
|
-
const dryRunOutput = useDryRun()
|
|
96
|
-
|
|
97
|
-
const mode = useApplicationMode()
|
|
98
|
-
|
|
99
|
-
const tree = dryRunOutput.files
|
|
100
|
-
const originalTree =
|
|
101
|
-
mode === 'setup' ? dryRunOutput.files : projectFiles.files
|
|
102
|
-
const deletedFiles = dryRunOutput.deletedFiles
|
|
103
|
-
|
|
104
|
-
const [originalFileContents, setOriginalFileContents] = useState<string>()
|
|
105
|
-
const [modifiedFileContents, setModifiedFileContents] = useState<string>()
|
|
106
|
-
|
|
107
|
-
const { includedFiles } = useFilters()
|
|
108
|
-
|
|
109
|
-
const fileTree = useMemo(() => {
|
|
110
|
-
const treeData: Array<FileTreeItem> = []
|
|
111
|
-
|
|
112
|
-
const allFileSet = Array.from(
|
|
113
|
-
new Set([
|
|
114
|
-
...Object.keys(tree),
|
|
115
|
-
...Object.keys(localTree),
|
|
116
|
-
...Object.keys(originalTree),
|
|
117
|
-
]),
|
|
118
|
-
)
|
|
119
|
-
|
|
120
|
-
allFileSet.sort().forEach((file) => {
|
|
121
|
-
const strippedFile = file.replace('./', '')
|
|
122
|
-
const parts = strippedFile.split('/')
|
|
123
|
-
|
|
124
|
-
let currentLevel = treeData
|
|
125
|
-
parts.forEach((part, index) => {
|
|
126
|
-
const existingNode = currentLevel.find((node) => node.name === part)
|
|
127
|
-
if (existingNode) {
|
|
128
|
-
currentLevel = existingNode.children || []
|
|
129
|
-
} else {
|
|
130
|
-
const fileInfo = getFileClass(
|
|
131
|
-
file,
|
|
132
|
-
tree,
|
|
133
|
-
originalTree,
|
|
134
|
-
localTree,
|
|
135
|
-
deletedFiles,
|
|
136
|
-
)
|
|
137
|
-
|
|
138
|
-
if (
|
|
139
|
-
index === parts.length - 1 &&
|
|
140
|
-
!includedFiles.includes(fileInfo.fileClass)
|
|
141
|
-
) {
|
|
142
|
-
return
|
|
143
|
-
}
|
|
144
|
-
if (index === parts.length - 1 && file === selectedFile) {
|
|
145
|
-
setModifiedFileContents(fileInfo.modifiedFile)
|
|
146
|
-
setOriginalFileContents(fileInfo.originalFile)
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
const newNode: FileTreeItem = {
|
|
150
|
-
id: parts.slice(0, index + 1).join('/'),
|
|
151
|
-
name: part,
|
|
152
|
-
fullPath: strippedFile,
|
|
153
|
-
children: index < parts.length - 1 ? [] : undefined,
|
|
154
|
-
icon:
|
|
155
|
-
index < parts.length - 1
|
|
156
|
-
? () => <Folder className="w-4 h-4 mr-2" />
|
|
157
|
-
: () => <FileText className="w-4 h-4 mr-2" />,
|
|
158
|
-
onClick:
|
|
159
|
-
index === parts.length - 1
|
|
160
|
-
? () => {
|
|
161
|
-
setSelectedFile(file)
|
|
162
|
-
setModifiedFileContents(fileInfo.modifiedFile)
|
|
163
|
-
setOriginalFileContents(fileInfo.originalFile)
|
|
164
|
-
}
|
|
165
|
-
: undefined,
|
|
166
|
-
className: twClasses[fileInfo.fileClass],
|
|
167
|
-
...fileInfo,
|
|
168
|
-
contents: tree[file] || localTree[file] || originalTree[file],
|
|
169
|
-
}
|
|
170
|
-
currentLevel.push(newNode)
|
|
171
|
-
currentLevel = newNode.children!
|
|
172
|
-
}
|
|
173
|
-
})
|
|
174
|
-
})
|
|
175
|
-
return treeData
|
|
176
|
-
}, [tree, originalTree, localTree, includedFiles])
|
|
177
|
-
|
|
178
|
-
const ready = useReady()
|
|
179
|
-
|
|
180
|
-
if (!ready) {
|
|
181
|
-
return null
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
return (
|
|
185
|
-
<div className="bg-white dark:bg-black/50 rounded-lg p-2 sm:p-4">
|
|
186
|
-
{mode === 'add' && <Filters />}
|
|
187
|
-
<div className="flex flex-row @container">
|
|
188
|
-
<div className="w-1/3 @6xl:w-1/4 bg-gray-500/10 rounded-l-lg">
|
|
189
|
-
<FileTree selectedFile={selectedFile} tree={fileTree} />
|
|
190
|
-
</div>
|
|
191
|
-
<div className="w-2/3 @6xl:w-3/4">
|
|
192
|
-
{selectedFile && modifiedFileContents ? (
|
|
193
|
-
<FileViewer
|
|
194
|
-
filePath={selectedFile}
|
|
195
|
-
originalFile={originalFileContents}
|
|
196
|
-
modifiedFile={modifiedFileContents}
|
|
197
|
-
/>
|
|
198
|
-
) : null}
|
|
199
|
-
</div>
|
|
200
|
-
</div>
|
|
201
|
-
</div>
|
|
202
|
-
)
|
|
203
|
-
}
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import { useMemo } from 'react'
|
|
2
|
-
import { FileText, Folder } from 'lucide-react'
|
|
3
|
-
|
|
4
|
-
import type { FileTreeItem } from '@/types.js'
|
|
5
|
-
|
|
6
|
-
import { TreeView } from '@/components/ui/tree-view'
|
|
7
|
-
|
|
8
|
-
export default function FileTree({
|
|
9
|
-
selectedFile,
|
|
10
|
-
tree,
|
|
11
|
-
}: {
|
|
12
|
-
selectedFile: string | null
|
|
13
|
-
tree: Array<FileTreeItem>
|
|
14
|
-
}) {
|
|
15
|
-
const initialExpandedItemIds = useMemo(
|
|
16
|
-
() => [
|
|
17
|
-
'src',
|
|
18
|
-
'src/routes',
|
|
19
|
-
'src/components',
|
|
20
|
-
'src/components/ui',
|
|
21
|
-
'src/lib',
|
|
22
|
-
],
|
|
23
|
-
[],
|
|
24
|
-
)
|
|
25
|
-
|
|
26
|
-
return (
|
|
27
|
-
<TreeView
|
|
28
|
-
initialSelectedItemId={selectedFile?.replace('./', '') ?? undefined}
|
|
29
|
-
initialExpandedItemIds={initialExpandedItemIds}
|
|
30
|
-
data={tree}
|
|
31
|
-
defaultNodeIcon={() => <Folder className="w-4 h-4 mr-2" />}
|
|
32
|
-
defaultLeafIcon={() => <FileText className="w-4 h-4 mr-2" />}
|
|
33
|
-
/>
|
|
34
|
-
)
|
|
35
|
-
}
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
import CodeMirror from '@uiw/react-codemirror'
|
|
2
|
-
import CodeMirrorMerge from 'react-codemirror-merge'
|
|
3
|
-
|
|
4
|
-
import { javascript } from '@codemirror/lang-javascript'
|
|
5
|
-
import { json } from '@codemirror/lang-json'
|
|
6
|
-
import { css } from '@codemirror/lang-css'
|
|
7
|
-
import { html } from '@codemirror/lang-html'
|
|
8
|
-
|
|
9
|
-
import { githubDarkInit } from '@uiw/codemirror-theme-github'
|
|
10
|
-
|
|
11
|
-
const theme = githubDarkInit({
|
|
12
|
-
settings: {
|
|
13
|
-
background: 'oklch(0.07 0.005 285.823)',
|
|
14
|
-
foreground: '#c9d1d9',
|
|
15
|
-
gutterBackground: 'oklch(0.22 0.005 285.823)',
|
|
16
|
-
},
|
|
17
|
-
})
|
|
18
|
-
|
|
19
|
-
export default function FileViewer({
|
|
20
|
-
originalFile,
|
|
21
|
-
modifiedFile,
|
|
22
|
-
filePath,
|
|
23
|
-
}: {
|
|
24
|
-
originalFile?: string
|
|
25
|
-
modifiedFile: string
|
|
26
|
-
filePath: string
|
|
27
|
-
}) {
|
|
28
|
-
function getLanguage(file: string) {
|
|
29
|
-
if (file.endsWith('.js') || file.endsWith('.jsx')) {
|
|
30
|
-
return javascript({ jsx: true })
|
|
31
|
-
}
|
|
32
|
-
if (file.endsWith('.ts') || file.endsWith('.tsx')) {
|
|
33
|
-
return javascript({ typescript: true, jsx: true })
|
|
34
|
-
}
|
|
35
|
-
if (file.endsWith('.json')) {
|
|
36
|
-
return json()
|
|
37
|
-
}
|
|
38
|
-
if (file.endsWith('.css')) {
|
|
39
|
-
return css()
|
|
40
|
-
}
|
|
41
|
-
if (file.endsWith('.html')) {
|
|
42
|
-
return html()
|
|
43
|
-
}
|
|
44
|
-
return javascript()
|
|
45
|
-
}
|
|
46
|
-
const language = getLanguage(filePath)
|
|
47
|
-
|
|
48
|
-
if (!originalFile || originalFile === modifiedFile) {
|
|
49
|
-
return (
|
|
50
|
-
<CodeMirror
|
|
51
|
-
value={modifiedFile}
|
|
52
|
-
theme={theme}
|
|
53
|
-
height="100vh"
|
|
54
|
-
width="100%"
|
|
55
|
-
readOnly
|
|
56
|
-
extensions={[language]}
|
|
57
|
-
className="text-lg"
|
|
58
|
-
/>
|
|
59
|
-
)
|
|
60
|
-
}
|
|
61
|
-
return (
|
|
62
|
-
<CodeMirrorMerge orientation="a-b" theme={theme} className="text-lg">
|
|
63
|
-
<CodeMirrorMerge.Original value={originalFile} extensions={[language]} />
|
|
64
|
-
<CodeMirrorMerge.Modified value={modifiedFile} extensions={[language]} />
|
|
65
|
-
</CodeMirrorMerge>
|
|
66
|
-
)
|
|
67
|
-
}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
export function AppHeader() {
|
|
2
|
-
return (
|
|
3
|
-
<div className="bg-white dark:bg-black/50 rounded-lg p-2 sm:p-4 flex items-center gap-2 text-lg sm:text-xl shadow-xl">
|
|
4
|
-
<div className="flex items-center gap-1.5">
|
|
5
|
-
<img
|
|
6
|
-
src="/logo-color-100w.png"
|
|
7
|
-
alt="TanStack Logo"
|
|
8
|
-
className="w-[30px] rounded-full overflow-hidden border-2 border-black dark:border-none"
|
|
9
|
-
/>
|
|
10
|
-
<div className="font-black text-xl uppercase">TanStack</div>
|
|
11
|
-
</div>
|
|
12
|
-
<svg
|
|
13
|
-
stroke="currentColor"
|
|
14
|
-
fill="currentColor"
|
|
15
|
-
stroke-width="0"
|
|
16
|
-
viewBox="0 0 256 512"
|
|
17
|
-
height="1em"
|
|
18
|
-
width="1em"
|
|
19
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
20
|
-
>
|
|
21
|
-
<path d="M224.3 273l-136 136c-9.4 9.4-24.6 9.4-33.9 0l-22.6-22.6c-9.4-9.4-9.4-24.6 0-33.9l96.4-96.4-96.4-96.4c-9.4-9.4-9.4-24.6 0-33.9L54.3 103c9.4-9.4 24.6-9.4 33.9 0l136 136c9.5 9.4 9.5 24.6.1 34z"></path>
|
|
22
|
-
</svg>
|
|
23
|
-
<div className="hover:text-blue-500 flex items-center gap-2">
|
|
24
|
-
Create TanStack App{' '}
|
|
25
|
-
<span className="bg-gradient-to-r from-blue-500 to-cyan-500 text-white text-xs font-bold px-2 py-0.5 rounded">
|
|
26
|
-
ALPHA
|
|
27
|
-
</span>
|
|
28
|
-
</div>
|
|
29
|
-
</div>
|
|
30
|
-
)
|
|
31
|
-
}
|
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
import { useMemo, useState, Fragment } from 'react'
|
|
2
|
-
import { InfoIcon } from 'lucide-react'
|
|
3
|
-
|
|
4
|
-
import type { AddOnInfo } from '@/types'
|
|
5
|
-
|
|
6
|
-
import { Switch } from '@/components/ui/switch'
|
|
7
|
-
import { Label } from '@/components/ui/label'
|
|
8
|
-
|
|
9
|
-
import { useAddOns } from '@/store/project'
|
|
10
|
-
|
|
11
|
-
import ImportCustomAddOn from '@/components/custom-add-on-dialog'
|
|
12
|
-
import AddOnInfoDialog from '@/components/add-on-info-dialog'
|
|
13
|
-
|
|
14
|
-
const addOnTypeLabels: Record<string, string> = {
|
|
15
|
-
toolchain: 'Toolchain',
|
|
16
|
-
'add-on': 'Add-on',
|
|
17
|
-
example: 'Example',
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export default function SelectedAddOns() {
|
|
21
|
-
const { availableAddOns, addOnState, toggleAddOn } = useAddOns()
|
|
22
|
-
|
|
23
|
-
const sortedAddOns = useMemo(() => {
|
|
24
|
-
return availableAddOns.sort((a, b) => {
|
|
25
|
-
return a.name.localeCompare(b.name)
|
|
26
|
-
})
|
|
27
|
-
}, [availableAddOns])
|
|
28
|
-
|
|
29
|
-
const [infoAddOn, setInfoAddOn] = useState<AddOnInfo>()
|
|
30
|
-
|
|
31
|
-
return (
|
|
32
|
-
<>
|
|
33
|
-
<AddOnInfoDialog
|
|
34
|
-
addOn={infoAddOn}
|
|
35
|
-
onClose={() => setInfoAddOn(undefined)}
|
|
36
|
-
/>
|
|
37
|
-
{Object.keys(addOnTypeLabels).map((type) => (
|
|
38
|
-
<Fragment key={type}>
|
|
39
|
-
{sortedAddOns.filter((addOn) => addOn.type === type).length > 0 && (
|
|
40
|
-
<div
|
|
41
|
-
key={`${type}-add-ons`}
|
|
42
|
-
className="block p-4 bg-gray-500/10 hover:bg-gray-500/20 rounded-lg transition-colors space-y-4 active"
|
|
43
|
-
>
|
|
44
|
-
<h3 className="font-medium">{addOnTypeLabels[type]}</h3>
|
|
45
|
-
<div className="flex flex-row flex-wrap">
|
|
46
|
-
{sortedAddOns
|
|
47
|
-
.filter((addOn) => addOn.type === type)
|
|
48
|
-
.map((addOn) => (
|
|
49
|
-
<div
|
|
50
|
-
key={addOn.id}
|
|
51
|
-
className="w-1/2 flex flex-row justify-between pr-4"
|
|
52
|
-
>
|
|
53
|
-
<div className="p-1 flex flex-row items-center">
|
|
54
|
-
<Switch
|
|
55
|
-
id={addOn.id}
|
|
56
|
-
checked={addOnState[addOn.id].selected}
|
|
57
|
-
disabled={!addOnState[addOn.id].enabled}
|
|
58
|
-
onCheckedChange={() => {
|
|
59
|
-
toggleAddOn(addOn.id)
|
|
60
|
-
}}
|
|
61
|
-
/>
|
|
62
|
-
<Label
|
|
63
|
-
htmlFor={addOn.id}
|
|
64
|
-
className="pl-2 font-semibold text-gray-300"
|
|
65
|
-
>
|
|
66
|
-
{addOn.smallLogo && (
|
|
67
|
-
<img
|
|
68
|
-
src={`data:image/svg+xml,${encodeURIComponent(
|
|
69
|
-
addOn.smallLogo,
|
|
70
|
-
)}`}
|
|
71
|
-
alt={addOn.name}
|
|
72
|
-
className="w-5"
|
|
73
|
-
/>
|
|
74
|
-
)}
|
|
75
|
-
{addOn.name}
|
|
76
|
-
</Label>
|
|
77
|
-
<InfoIcon
|
|
78
|
-
className="ml-2 w-4 text-gray-600"
|
|
79
|
-
onClick={() => setInfoAddOn(addOn)}
|
|
80
|
-
/>
|
|
81
|
-
</div>
|
|
82
|
-
</div>
|
|
83
|
-
))}
|
|
84
|
-
</div>
|
|
85
|
-
</div>
|
|
86
|
-
)}
|
|
87
|
-
</Fragment>
|
|
88
|
-
))}
|
|
89
|
-
<div className="mt-4">
|
|
90
|
-
<ImportCustomAddOn />
|
|
91
|
-
</div>
|
|
92
|
-
</>
|
|
93
|
-
)
|
|
94
|
-
}
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import { CodeIcon, FileIcon } from 'lucide-react'
|
|
2
|
-
|
|
3
|
-
import type { Mode } from '@tanstack/cta-engine'
|
|
4
|
-
|
|
5
|
-
import { ToggleGroup, ToggleGroupItem } from '@/components/ui/toggle-group'
|
|
6
|
-
|
|
7
|
-
import {
|
|
8
|
-
setRouterMode,
|
|
9
|
-
useApplicationMode,
|
|
10
|
-
useModeEditable,
|
|
11
|
-
useRouterMode,
|
|
12
|
-
} from '@/store/project'
|
|
13
|
-
|
|
14
|
-
export default function ModeSelector() {
|
|
15
|
-
const mode = useApplicationMode()
|
|
16
|
-
const enableMode = useModeEditable()
|
|
17
|
-
const routerMode = useRouterMode()
|
|
18
|
-
|
|
19
|
-
if (mode !== 'setup') {
|
|
20
|
-
return null
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
return (
|
|
24
|
-
<div className="flex flex-col @md:flex-row @md:items-center gap-2 items-start">
|
|
25
|
-
<h3 className="font-medium whitespace-nowrap">Router Mode</h3>
|
|
26
|
-
<div className="flex flex-row justify-center items-center">
|
|
27
|
-
<ToggleGroup
|
|
28
|
-
type="single"
|
|
29
|
-
value={routerMode}
|
|
30
|
-
onValueChange={(v: string) => {
|
|
31
|
-
if (v) {
|
|
32
|
-
setRouterMode(v as Mode)
|
|
33
|
-
}
|
|
34
|
-
}}
|
|
35
|
-
className="rounded-md border-2 border-gray-500/10"
|
|
36
|
-
>
|
|
37
|
-
<ToggleGroupItem
|
|
38
|
-
value="code-router"
|
|
39
|
-
className="px-4"
|
|
40
|
-
disabled={!enableMode}
|
|
41
|
-
>
|
|
42
|
-
<CodeIcon className="w-4 h-4" />
|
|
43
|
-
Code Router
|
|
44
|
-
</ToggleGroupItem>
|
|
45
|
-
<ToggleGroupItem
|
|
46
|
-
value="file-router"
|
|
47
|
-
className="px-4"
|
|
48
|
-
disabled={!enableMode}
|
|
49
|
-
>
|
|
50
|
-
<FileIcon className="w-4 h-4" />
|
|
51
|
-
File Router
|
|
52
|
-
</ToggleGroupItem>
|
|
53
|
-
</ToggleGroup>
|
|
54
|
-
</div>
|
|
55
|
-
</div>
|
|
56
|
-
)
|
|
57
|
-
}
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { Input } from '@/components/ui/input'
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
setProjectName,
|
|
5
|
-
useApplicationMode,
|
|
6
|
-
useProjectName,
|
|
7
|
-
} from '@/store/project'
|
|
8
|
-
|
|
9
|
-
export default function ProjectName() {
|
|
10
|
-
const name = useProjectName()
|
|
11
|
-
const mode = useApplicationMode()
|
|
12
|
-
|
|
13
|
-
if (mode !== 'setup') {
|
|
14
|
-
return null
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
return (
|
|
18
|
-
<div className="flex flex-row gap-2 items-center">
|
|
19
|
-
<h3 className="font-medium whitespace-nowrap">Project Name</h3>
|
|
20
|
-
<Input
|
|
21
|
-
value={name}
|
|
22
|
-
placeholder="my-app"
|
|
23
|
-
onChange={(e) => setProjectName(e.target.value)}
|
|
24
|
-
className="w-full bg-gray-500/10 rounded-md px-2 py-1 min-w-[200px] text-sm"
|
|
25
|
-
/>
|
|
26
|
-
</div>
|
|
27
|
-
)
|
|
28
|
-
}
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
import { useState } from 'react'
|
|
2
|
-
|
|
3
|
-
import { Button } from '@/components/ui/button'
|
|
4
|
-
import {
|
|
5
|
-
Dialog,
|
|
6
|
-
DialogContent,
|
|
7
|
-
DialogFooter,
|
|
8
|
-
DialogHeader,
|
|
9
|
-
DialogTitle,
|
|
10
|
-
} from '@/components/ui/dialog'
|
|
11
|
-
|
|
12
|
-
import { useAddOns, useApplicationMode } from '@/store/project'
|
|
13
|
-
import useStreamingStatus from '@/hooks/use-streaming-status'
|
|
14
|
-
import StatusList from '@/components/StatusList'
|
|
15
|
-
import { addToAppStreaming, shutdown } from '@/lib/api'
|
|
16
|
-
|
|
17
|
-
export default function RunAddOns() {
|
|
18
|
-
const { chosenAddOns } = useAddOns()
|
|
19
|
-
const [isRunning, setIsRunning] = useState(false)
|
|
20
|
-
const { streamItems, monitorStream, finished } = useStreamingStatus()
|
|
21
|
-
|
|
22
|
-
const mode = useApplicationMode()
|
|
23
|
-
|
|
24
|
-
if (mode !== 'add') {
|
|
25
|
-
return null
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
async function onAddToApp() {
|
|
29
|
-
setIsRunning(true)
|
|
30
|
-
monitorStream(await addToAppStreaming(chosenAddOns))
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
return (
|
|
34
|
-
<div>
|
|
35
|
-
<Dialog open={isRunning}>
|
|
36
|
-
<DialogContent
|
|
37
|
-
className="sm:min-w-[425px] sm:max-w-fit"
|
|
38
|
-
hideCloseButton
|
|
39
|
-
>
|
|
40
|
-
<DialogHeader>
|
|
41
|
-
<DialogTitle>Adding Add-Ons</DialogTitle>
|
|
42
|
-
</DialogHeader>
|
|
43
|
-
<StatusList streamItems={streamItems} finished={finished} />
|
|
44
|
-
<DialogFooter>
|
|
45
|
-
<Button
|
|
46
|
-
variant="default"
|
|
47
|
-
onClick={async () => {
|
|
48
|
-
await shutdown()
|
|
49
|
-
window.close()
|
|
50
|
-
}}
|
|
51
|
-
disabled={!finished}
|
|
52
|
-
>
|
|
53
|
-
Exit This Application
|
|
54
|
-
</Button>
|
|
55
|
-
</DialogFooter>
|
|
56
|
-
</DialogContent>
|
|
57
|
-
</Dialog>
|
|
58
|
-
|
|
59
|
-
<div className="flex flex-col gap-2">
|
|
60
|
-
<Button
|
|
61
|
-
variant="default"
|
|
62
|
-
onClick={onAddToApp}
|
|
63
|
-
disabled={chosenAddOns.length === 0 || isRunning}
|
|
64
|
-
className="w-full"
|
|
65
|
-
>
|
|
66
|
-
Add These Add-Ons To Your App
|
|
67
|
-
</Button>
|
|
68
|
-
</div>
|
|
69
|
-
</div>
|
|
70
|
-
)
|
|
71
|
-
}
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
import { useState } from 'react'
|
|
2
|
-
import { HammerIcon } from 'lucide-react'
|
|
3
|
-
|
|
4
|
-
import { Button } from '@/components/ui/button'
|
|
5
|
-
import {
|
|
6
|
-
Dialog,
|
|
7
|
-
DialogContent,
|
|
8
|
-
DialogFooter,
|
|
9
|
-
DialogHeader,
|
|
10
|
-
DialogTitle,
|
|
11
|
-
} from '@/components/ui/dialog'
|
|
12
|
-
|
|
13
|
-
import useStreamingStatus from '@/hooks/use-streaming-status'
|
|
14
|
-
import {
|
|
15
|
-
useAddOns,
|
|
16
|
-
useApplicationMode,
|
|
17
|
-
useProjectOptions,
|
|
18
|
-
useProjectStarter,
|
|
19
|
-
} from '@/store/project'
|
|
20
|
-
import StatusList from '@/components/StatusList'
|
|
21
|
-
import { createAppStreaming, shutdown } from '@/lib/api'
|
|
22
|
-
|
|
23
|
-
export default function RunCreateApp() {
|
|
24
|
-
const [isRunning, setIsRunning] = useState(false)
|
|
25
|
-
const { streamItems, monitorStream, finished } = useStreamingStatus()
|
|
26
|
-
|
|
27
|
-
const mode = useApplicationMode()
|
|
28
|
-
const options = useProjectOptions()
|
|
29
|
-
const { chosenAddOns } = useAddOns()
|
|
30
|
-
const { projectStarter } = useProjectStarter()
|
|
31
|
-
|
|
32
|
-
if (mode !== 'setup') {
|
|
33
|
-
return null
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
async function onAddToApp() {
|
|
37
|
-
setIsRunning(true)
|
|
38
|
-
monitorStream(
|
|
39
|
-
await createAppStreaming(options, chosenAddOns, projectStarter),
|
|
40
|
-
)
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
return (
|
|
44
|
-
<div>
|
|
45
|
-
<Dialog open={isRunning}>
|
|
46
|
-
<DialogContent
|
|
47
|
-
className="sm:min-w-[425px] sm:max-w-fit"
|
|
48
|
-
hideCloseButton
|
|
49
|
-
>
|
|
50
|
-
<DialogHeader>
|
|
51
|
-
<DialogTitle>Creating Your Application</DialogTitle>
|
|
52
|
-
</DialogHeader>
|
|
53
|
-
<StatusList streamItems={streamItems} finished={finished} />
|
|
54
|
-
<DialogFooter>
|
|
55
|
-
<Button
|
|
56
|
-
variant="default"
|
|
57
|
-
onClick={async () => {
|
|
58
|
-
await shutdown()
|
|
59
|
-
window.close()
|
|
60
|
-
}}
|
|
61
|
-
disabled={!finished}
|
|
62
|
-
>
|
|
63
|
-
Exit This Application
|
|
64
|
-
</Button>
|
|
65
|
-
</DialogFooter>
|
|
66
|
-
</DialogContent>
|
|
67
|
-
</Dialog>
|
|
68
|
-
|
|
69
|
-
<div className="flex flex-col gap-2">
|
|
70
|
-
<Button
|
|
71
|
-
variant="default"
|
|
72
|
-
onClick={onAddToApp}
|
|
73
|
-
disabled={isRunning}
|
|
74
|
-
className="w-full"
|
|
75
|
-
>
|
|
76
|
-
<HammerIcon className="w-4 h-4" />
|
|
77
|
-
Build Your App
|
|
78
|
-
</Button>
|
|
79
|
-
</div>
|
|
80
|
-
</div>
|
|
81
|
-
)
|
|
82
|
-
}
|