@tanstack/cta-ui 0.10.0-alpha.26 → 0.10.0-alpha.28
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/README.md +20 -0
- package/dist/assets/index-BeVre1U8.js +213 -0
- package/dist/assets/index-BeVre1U8.js.map +1 -0
- package/dist/assets/index-Co-Y5wb2.css +1 -0
- package/dist/index.html +9 -3
- package/dist/logo-color-100w.png +0 -0
- package/index.html +7 -1
- package/lib/engine-handling/add-to-app-wrapper.ts +39 -15
- package/lib/engine-handling/create-app-wrapper.ts +17 -6
- package/lib/engine-handling/file-helpers.ts +4 -2
- package/lib/engine-handling/generate-initial-payload.ts +58 -51
- package/lib/index.ts +11 -1
- package/lib/types.d.ts +18 -11
- package/lib-dist/engine-handling/add-to-app-wrapper.d.ts +2 -0
- package/lib-dist/engine-handling/add-to-app-wrapper.js +14 -9
- package/lib-dist/engine-handling/create-app-wrapper.d.ts +2 -1
- package/lib-dist/engine-handling/create-app-wrapper.js +6 -4
- package/lib-dist/engine-handling/file-helpers.js +3 -2
- package/lib-dist/engine-handling/generate-initial-payload.d.ts +14 -22
- package/lib-dist/engine-handling/generate-initial-payload.js +44 -49
- package/lib-dist/index.d.ts +2 -0
- package/lib-dist/index.js +6 -1
- package/package.json +6 -4
- package/public/logo-color-100w.png +0 -0
- package/src/components/background-animation.tsx +229 -0
- package/src/components/cta-sidebar.tsx +28 -33
- package/src/components/file-navigator.tsx +72 -74
- package/src/components/header.tsx +31 -0
- package/src/components/sidebar-items/add-ons.tsx +48 -45
- package/src/components/sidebar-items/mode-selector.tsx +6 -4
- package/src/components/sidebar-items/project-name.tsx +4 -5
- package/src/components/sidebar-items/typescript-switch.tsx +3 -3
- package/src/components/startup-dialog.tsx +4 -6
- package/src/components/ui/switch.tsx +6 -6
- package/src/hooks/use-mounted.ts +9 -0
- package/src/hooks/use-preferred-reduced-motion.ts +27 -0
- package/src/index.tsx +19 -20
- package/src/store/project.ts +36 -20
- package/src/styles.css +90 -18
- package/src/types.d.ts +1 -1
- package/tailwind.config.cjs +47 -0
- package/dist/assets/index-D0-fpgzI.js +0 -223
- package/dist/assets/index-D0-fpgzI.js.map +0 -1
- package/dist/assets/index-D5brMzJg.css +0 -1
|
@@ -1,11 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
Sidebar,
|
|
3
|
-
SidebarContent,
|
|
4
|
-
SidebarFooter,
|
|
5
|
-
SidebarGroup,
|
|
6
|
-
SidebarHeader,
|
|
7
|
-
} from '@/components/ui/sidebar'
|
|
8
|
-
|
|
9
1
|
import SelectedAddOns from '@/components/sidebar-items/add-ons'
|
|
10
2
|
import RunAddOns from '@/components/sidebar-items/run-add-ons'
|
|
11
3
|
import RunCreateApp from '@/components/sidebar-items/run-create-app'
|
|
@@ -14,6 +6,8 @@ import ModeSelector from '@/components/sidebar-items/mode-selector'
|
|
|
14
6
|
import TypescriptSwitch from '@/components/sidebar-items/typescript-switch'
|
|
15
7
|
import StarterDialog from '@/components/sidebar-items/starter'
|
|
16
8
|
|
|
9
|
+
import { ChevronRightIcon } from 'lucide-react'
|
|
10
|
+
|
|
17
11
|
import { useApplicationMode, useReady } from '@/store/project'
|
|
18
12
|
|
|
19
13
|
export function AppSidebar() {
|
|
@@ -21,35 +15,36 @@ export function AppSidebar() {
|
|
|
21
15
|
const mode = useApplicationMode()
|
|
22
16
|
|
|
23
17
|
return (
|
|
24
|
-
<
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
<>
|
|
31
|
-
{mode === 'setup' && (
|
|
32
|
-
<SidebarGroup>
|
|
18
|
+
<div className="flex flex-col gap-2">
|
|
19
|
+
{ready && (
|
|
20
|
+
<>
|
|
21
|
+
{mode === 'setup' && (
|
|
22
|
+
<div className="bg-white dark:bg-black/40 shadow-xl p-4 space-y-2 rounded-lg">
|
|
23
|
+
<div className="block p-4 bg-gray-500/10 hover:bg-gray-500/20 rounded-lg transition-colors space-y-4 active @container">
|
|
33
24
|
<ProjectName />
|
|
25
|
+
</div>
|
|
26
|
+
<div className="block p-4 bg-gray-500/10 hover:bg-gray-500/20 rounded-lg transition-colors space-y-4 active @container">
|
|
34
27
|
<ModeSelector />
|
|
28
|
+
</div>
|
|
29
|
+
<div className="block p-4 bg-gray-500/10 hover:bg-gray-500/20 rounded-lg transition-colors space-y-4 active @container">
|
|
35
30
|
<TypescriptSwitch />
|
|
36
|
-
</
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
<
|
|
31
|
+
</div>
|
|
32
|
+
</div>
|
|
33
|
+
)}
|
|
34
|
+
<div className="bg-white dark:bg-black/40 shadow-xl p-4 space-y-2 rounded-lg">
|
|
35
|
+
<SelectedAddOns />
|
|
36
|
+
</div>
|
|
37
|
+
{mode === 'setup' && (
|
|
38
|
+
<div className="bg-white dark:bg-black/40 shadow-xl p-4 space-y-2 rounded-lg">
|
|
39
|
+
<StarterDialog />
|
|
40
|
+
</div>
|
|
41
|
+
)}
|
|
42
|
+
</>
|
|
43
|
+
)}
|
|
44
|
+
<div className="mt-5">
|
|
50
45
|
<RunAddOns />
|
|
51
46
|
<RunCreateApp />
|
|
52
|
-
</
|
|
53
|
-
</
|
|
47
|
+
</div>
|
|
48
|
+
</div>
|
|
54
49
|
)
|
|
55
50
|
}
|
|
@@ -7,7 +7,7 @@ import FileTree from './file-tree'
|
|
|
7
7
|
import type { FileTreeItem } from '@/types'
|
|
8
8
|
|
|
9
9
|
import { Label } from '@/components/ui/label'
|
|
10
|
-
import {
|
|
10
|
+
import { Switch } from '@/components/ui/switch'
|
|
11
11
|
|
|
12
12
|
import {
|
|
13
13
|
useApplicationMode,
|
|
@@ -24,64 +24,62 @@ export function Filters() {
|
|
|
24
24
|
const { includedFiles, toggleFilter } = useFilters()
|
|
25
25
|
|
|
26
26
|
return (
|
|
27
|
-
<div className="p-
|
|
28
|
-
<
|
|
29
|
-
<div className="flex flex-row
|
|
30
|
-
<
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
<
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
<
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
<
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
<
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
</Label>
|
|
84
|
-
</div>
|
|
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>
|
|
85
83
|
</div>
|
|
86
84
|
</div>
|
|
87
85
|
)
|
|
@@ -184,21 +182,21 @@ export default function FileNavigator() {
|
|
|
184
182
|
}
|
|
185
183
|
|
|
186
184
|
return (
|
|
187
|
-
<div
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
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>
|
|
202
200
|
</div>
|
|
203
201
|
</div>
|
|
204
202
|
)
|
|
@@ -0,0 +1,31 @@
|
|
|
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,4 +1,4 @@
|
|
|
1
|
-
import { useMemo, useState } from 'react'
|
|
1
|
+
import { useMemo, useState, Fragment } from 'react'
|
|
2
2
|
import { InfoIcon } from 'lucide-react'
|
|
3
3
|
|
|
4
4
|
import type { AddOnInfo } from '@/types'
|
|
@@ -35,53 +35,56 @@ export default function SelectedAddOns() {
|
|
|
35
35
|
onClose={() => setInfoAddOn(undefined)}
|
|
36
36
|
/>
|
|
37
37
|
{Object.keys(addOnTypeLabels).map((type) => (
|
|
38
|
-
<
|
|
38
|
+
<Fragment key={type}>
|
|
39
39
|
{sortedAddOns.filter((addOn) => addOn.type === type).length > 0 && (
|
|
40
|
-
<
|
|
41
|
-
{
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
<div className="p-1 flex flex-row items-center">
|
|
53
|
-
<Switch
|
|
54
|
-
id={addOn.id}
|
|
55
|
-
checked={addOnState[addOn.id].selected}
|
|
56
|
-
disabled={!addOnState[addOn.id].enabled}
|
|
57
|
-
onCheckedChange={() => {
|
|
58
|
-
toggleAddOn(addOn.id)
|
|
59
|
-
}}
|
|
60
|
-
/>
|
|
61
|
-
<Label
|
|
62
|
-
htmlFor={addOn.id}
|
|
63
|
-
className="pl-2 font-semibold text-gray-300"
|
|
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"
|
|
64
52
|
>
|
|
65
|
-
|
|
66
|
-
<
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
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)}
|
|
72
80
|
/>
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
</div>
|
|
81
|
-
</div>
|
|
82
|
-
))}
|
|
83
|
-
</div>
|
|
84
|
-
</div>
|
|
81
|
+
</div>
|
|
82
|
+
</div>
|
|
83
|
+
))}
|
|
84
|
+
</div>
|
|
85
|
+
</div>
|
|
86
|
+
)}
|
|
87
|
+
</Fragment>
|
|
85
88
|
))}
|
|
86
89
|
<div className="mt-4">
|
|
87
90
|
<ImportCustomAddOn />
|
|
@@ -21,8 +21,9 @@ export default function ModeSelector() {
|
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
return (
|
|
24
|
-
|
|
25
|
-
<
|
|
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">
|
|
26
27
|
<ToggleGroup
|
|
27
28
|
type="single"
|
|
28
29
|
value={routerMode}
|
|
@@ -31,10 +32,11 @@ export default function ModeSelector() {
|
|
|
31
32
|
setRouterMode(v as Mode)
|
|
32
33
|
}
|
|
33
34
|
}}
|
|
35
|
+
className="rounded-md border-2 border-gray-500/10"
|
|
34
36
|
>
|
|
35
37
|
<ToggleGroupItem
|
|
36
38
|
value="code-router"
|
|
37
|
-
className="px-
|
|
39
|
+
className="px-4"
|
|
38
40
|
disabled={!enableMode}
|
|
39
41
|
>
|
|
40
42
|
<CodeIcon className="w-4 h-4" />
|
|
@@ -50,6 +52,6 @@ export default function ModeSelector() {
|
|
|
50
52
|
</ToggleGroupItem>
|
|
51
53
|
</ToggleGroup>
|
|
52
54
|
</div>
|
|
53
|
-
|
|
55
|
+
</div>
|
|
54
56
|
)
|
|
55
57
|
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { Input } from '@/components/ui/input'
|
|
2
|
-
import { SidebarGroupLabel } from '@/components/ui/sidebar'
|
|
3
2
|
|
|
4
3
|
import {
|
|
5
4
|
setProjectName,
|
|
@@ -16,14 +15,14 @@ export default function ProjectName() {
|
|
|
16
15
|
}
|
|
17
16
|
|
|
18
17
|
return (
|
|
19
|
-
|
|
20
|
-
<
|
|
18
|
+
<div className="flex flex-row gap-2 items-center">
|
|
19
|
+
<h3 className="font-medium whitespace-nowrap">Project Name</h3>
|
|
21
20
|
<Input
|
|
22
21
|
value={name}
|
|
23
22
|
placeholder="my-app"
|
|
24
23
|
onChange={(e) => setProjectName(e.target.value)}
|
|
25
|
-
className="w-full"
|
|
24
|
+
className="w-full bg-gray-500/10 rounded-md px-2 py-1 min-w-[200px] text-sm"
|
|
26
25
|
/>
|
|
27
|
-
|
|
26
|
+
</div>
|
|
28
27
|
)
|
|
29
28
|
}
|
|
@@ -22,8 +22,8 @@ export default function TypescriptSwitch() {
|
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
return (
|
|
25
|
-
<div className="flex
|
|
26
|
-
<div className="w-1/2 flex flex-row items-center">
|
|
25
|
+
<div className="flex">
|
|
26
|
+
<div className="w-1/2 flex flex-row items-center justify-center">
|
|
27
27
|
<Switch
|
|
28
28
|
id="typescript-switch"
|
|
29
29
|
checked={typescript}
|
|
@@ -35,7 +35,7 @@ export default function TypescriptSwitch() {
|
|
|
35
35
|
TypeScript
|
|
36
36
|
</Label>
|
|
37
37
|
</div>
|
|
38
|
-
<div className="w-1/2 flex flex-row items-center">
|
|
38
|
+
<div className="w-1/2 flex flex-row items-center justify-center">
|
|
39
39
|
<Switch
|
|
40
40
|
id="tailwind-switch"
|
|
41
41
|
checked={tailwind}
|
|
@@ -24,7 +24,7 @@ export default function StartupDialog() {
|
|
|
24
24
|
const registry = useRegistry()
|
|
25
25
|
const { open, setOpen, dontShowAgain, setDontShowAgain } = useStartupDialog()
|
|
26
26
|
|
|
27
|
-
if (mode !== 'setup' || !registry) {
|
|
27
|
+
if (mode !== 'setup' || !registry || registry?.starters?.length === 0) {
|
|
28
28
|
return null
|
|
29
29
|
}
|
|
30
30
|
|
|
@@ -49,11 +49,9 @@ export default function StartupDialog() {
|
|
|
49
49
|
Would you like to use a starter project?
|
|
50
50
|
</DialogTitle>
|
|
51
51
|
</DialogHeader>
|
|
52
|
-
|
|
53
|
-
<
|
|
54
|
-
|
|
55
|
-
</div>
|
|
56
|
-
)}
|
|
52
|
+
<div>
|
|
53
|
+
<StartersCarousel onImport={onImport} />
|
|
54
|
+
</div>
|
|
57
55
|
<DialogFooter className="flex sm:justify-between w-full">
|
|
58
56
|
<div className="flex items-center gap-2">
|
|
59
57
|
<Switch
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import * as React from
|
|
2
|
-
import * as SwitchPrimitive from
|
|
1
|
+
import * as React from 'react'
|
|
2
|
+
import * as SwitchPrimitive from '@radix-ui/react-switch'
|
|
3
3
|
|
|
4
|
-
import { cn } from
|
|
4
|
+
import { cn } from '@/lib/utils'
|
|
5
5
|
|
|
6
6
|
function Switch({
|
|
7
7
|
className,
|
|
@@ -11,15 +11,15 @@ function Switch({
|
|
|
11
11
|
<SwitchPrimitive.Root
|
|
12
12
|
data-slot="switch"
|
|
13
13
|
className={cn(
|
|
14
|
-
|
|
15
|
-
className
|
|
14
|
+
'peer data-[state=checked]:bg-primary data-[state=unchecked]:bg-input focus-visible:border-ring focus-visible:ring-ring/50 dark:data-[state=unchecked]:bg-input/80 inline-flex h-[1.15rem] w-8 shrink-0 items-center rounded-full shadow-xs transition-all outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 border-1 border-gray-500/30',
|
|
15
|
+
className,
|
|
16
16
|
)}
|
|
17
17
|
{...props}
|
|
18
18
|
>
|
|
19
19
|
<SwitchPrimitive.Thumb
|
|
20
20
|
data-slot="switch-thumb"
|
|
21
21
|
className={cn(
|
|
22
|
-
|
|
22
|
+
'bg-background dark:data-[state=unchecked]:bg-foreground dark:data-[state=checked]:bg-primary-foreground pointer-events-none block size-4 rounded-full ring-0 transition-transform data-[state=checked]:translate-x-[calc(100%-2px)] data-[state=unchecked]:translate-x-0',
|
|
23
23
|
)}
|
|
24
24
|
/>
|
|
25
25
|
</SwitchPrimitive.Root>
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import * as React from 'react'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Hook that returns the user's preference for reduced motion.
|
|
5
|
+
* @returns null if the value is not yet determined or the user's preference for reduced motion.
|
|
6
|
+
*/
|
|
7
|
+
export const usePrefersReducedMotion = () => {
|
|
8
|
+
const [prefersReducedMotion, setPrefersReducedMotion] = React.useState<
|
|
9
|
+
boolean | null
|
|
10
|
+
>(null)
|
|
11
|
+
|
|
12
|
+
React.useEffect(() => {
|
|
13
|
+
const mediaQueryList = window.matchMedia('(prefers-reduced-motion: reduce)')
|
|
14
|
+
setPrefersReducedMotion(mediaQueryList.matches)
|
|
15
|
+
|
|
16
|
+
const listener = (event: MediaQueryListEvent) => {
|
|
17
|
+
setPrefersReducedMotion(event.matches)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
mediaQueryList.addEventListener('change', listener)
|
|
21
|
+
return () => {
|
|
22
|
+
mediaQueryList.removeEventListener('change', listener)
|
|
23
|
+
}
|
|
24
|
+
}, [])
|
|
25
|
+
|
|
26
|
+
return prefersReducedMotion
|
|
27
|
+
}
|
package/src/index.tsx
CHANGED
|
@@ -2,31 +2,33 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
|
|
2
2
|
import FileNavigator from '@/components/file-navigator'
|
|
3
3
|
import StartupDialog from '@/components/startup-dialog'
|
|
4
4
|
|
|
5
|
-
import {
|
|
6
|
-
SidebarProvider,
|
|
7
|
-
SidebarTrigger,
|
|
8
|
-
useSidebar,
|
|
9
|
-
} from '@/components/ui/sidebar'
|
|
10
5
|
import { Toaster } from '@/components/toaster'
|
|
11
6
|
|
|
12
7
|
import { AppSidebar } from '@/components/cta-sidebar'
|
|
8
|
+
import { AppHeader } from '@/components/header'
|
|
9
|
+
import { BackgroundAnimation } from '@/components/background-animation'
|
|
10
|
+
import { useManager } from '@/store/project'
|
|
13
11
|
|
|
14
12
|
const queryClient = new QueryClient()
|
|
15
13
|
|
|
16
14
|
function Content() {
|
|
17
|
-
|
|
15
|
+
useManager()
|
|
18
16
|
|
|
19
17
|
return (
|
|
20
|
-
<main
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
18
|
+
<main className="min-w-[1280px]">
|
|
19
|
+
<BackgroundAnimation />
|
|
20
|
+
<div className="min-h-dvh p-2 sm:p-4 space-y-2 sm:space-y-4 @container">
|
|
21
|
+
<AppHeader />
|
|
22
|
+
<div className="flex flex-row">
|
|
23
|
+
<div className="w-1/2 @7xl:w-1/4 pr-1">
|
|
24
|
+
<AppSidebar />
|
|
25
|
+
</div>
|
|
26
|
+
<div className="w-1/2 @7xl:w-3/4 pl-1">
|
|
27
|
+
<FileNavigator />
|
|
28
|
+
</div>
|
|
29
|
+
</div>
|
|
29
30
|
</div>
|
|
31
|
+
<StartupDialog />
|
|
30
32
|
</main>
|
|
31
33
|
)
|
|
32
34
|
}
|
|
@@ -34,11 +36,8 @@ function Content() {
|
|
|
34
36
|
export default function RootComponent() {
|
|
35
37
|
return (
|
|
36
38
|
<QueryClientProvider client={queryClient}>
|
|
37
|
-
<
|
|
38
|
-
|
|
39
|
-
<Content />
|
|
40
|
-
<Toaster />
|
|
41
|
-
</SidebarProvider>
|
|
39
|
+
<Content />
|
|
40
|
+
<Toaster />
|
|
42
41
|
</QueryClientProvider>
|
|
43
42
|
)
|
|
44
43
|
}
|