Skip to content

Commit aaf22b6

Browse files
committed
chore: first work on the new UI
1 parent 6c1d393 commit aaf22b6

29 files changed

+4594
-1758
lines changed

packages/cta-cli/src/cli.ts

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -87,15 +87,27 @@ export function cli({
8787

8888
program
8989
.command('add')
90-
.argument('add-on', 'Name of the add-on (or add-ons separated by commas)')
91-
.action(async (addOn: string) => {
92-
await addToApp(
93-
addOn.split(',').map((addon) => addon.trim()),
94-
{
95-
silent: false,
96-
},
97-
environment,
98-
)
90+
.argument(
91+
'[add-on]',
92+
'Name of the add-ons (or add-ons separated by spaces or commas)',
93+
)
94+
.option('--ui', 'Add with the UI')
95+
.action(async (addOn: string, options: { ui: boolean }) => {
96+
const addOns = (addOn || '').split(',').map((addon) => addon.trim())
97+
if (options.ui) {
98+
launchUI({
99+
mode: 'add',
100+
addOns,
101+
})
102+
} else {
103+
await addToApp(
104+
addOns,
105+
{
106+
silent: false,
107+
},
108+
environment,
109+
)
110+
}
99111
})
100112

101113
const addOnCommand = program.command('add-on')
@@ -115,7 +127,10 @@ export function cli({
115127
.command('ui')
116128
.description('Show the add-on developer UI')
117129
.action(() => {
118-
launchUI()
130+
launchUI({
131+
mode: 'add',
132+
addOns: [],
133+
})
119134
})
120135

121136
const starterCommand = program.command('starter')
@@ -135,7 +150,10 @@ export function cli({
135150
.command('ui')
136151
.description('Show the starter developer UI')
137152
.action(() => {
138-
launchUI()
153+
launchUI({
154+
mode: 'starter',
155+
addOns: [],
156+
})
139157
})
140158

141159
program.argument('[project-name]', 'name of the project')

packages/cta-ui/.cursorrules

Lines changed: 0 additions & 7 deletions
This file was deleted.

packages/cta-ui/lib/index.ts

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,21 @@
11
import { dirname, resolve } from 'node:path'
22
import { fileURLToPath } from 'node:url'
33

4-
export function launchUI() {
4+
export function launchUI({
5+
mode,
6+
addOns,
7+
}: {
8+
mode: 'add' | 'add-on' | 'starter'
9+
addOns: Array<string>
10+
}) {
511
const projectPath = process.cwd()
612

7-
process.env.PROJECT_PATH = projectPath
8-
9-
const configPath = resolve(
10-
dirname(fileURLToPath(import.meta.url)),
11-
'../app.config.js',
12-
)
13+
process.env.CTA_PROJECT_PATH = projectPath
14+
process.env.CTA_ADD_ONS = addOns.join(',')
15+
process.env.CTA_MODE = mode
1316

1417
const developerPath = resolve(dirname(fileURLToPath(import.meta.url)), '..')
18+
const configPath = resolve(developerPath, './app.config.js')
1519

1620
process.chdir(developerPath)
1721

packages/cta-ui/package.json

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44
"main": "./lib-dist/index.js",
55
"types": "./lib-dist/index.d.ts",
66
"scripts": {
7-
"build": "tsc -p tsconfig.lib.json"
7+
"build": "tsc -p tsconfig.lib.json",
8+
"dev": "tsc --watch -p tsconfig.lib.json",
9+
"dev:ui": "vinxi dev"
810
},
911
"dependencies": {
1012
"@codemirror/lang-css": "^6.3.1",
@@ -13,20 +15,26 @@
1315
"@codemirror/lang-json": "^6.0.1",
1416
"@radix-ui/react-accordion": "^1.2.3",
1517
"@radix-ui/react-checkbox": "^1.1.4",
16-
"@radix-ui/react-dialog": "^1.1.6",
17-
"@radix-ui/react-slot": "^1.1.2",
18+
"@radix-ui/react-dialog": "^1.1.10",
19+
"@radix-ui/react-separator": "^1.1.4",
20+
"@radix-ui/react-slot": "^1.2.0",
1821
"@radix-ui/react-tabs": "^1.1.3",
1922
"@radix-ui/react-toggle": "^1.1.2",
2023
"@radix-ui/react-toggle-group": "^1.1.2",
24+
"@radix-ui/react-tooltip": "^1.2.3",
2125
"@tailwindcss/vite": "^4.0.6",
2226
"@tanstack/cta-engine": "workspace:*",
27+
"@tanstack/cta-framework-react-cra": "workspace:*",
28+
"@tanstack/cta-framework-solid": "workspace:*",
2329
"@tanstack/react-query": "^5.66.5",
2430
"@tanstack/react-query-devtools": "^5.66.5",
2531
"@tanstack/react-router": "^1.114.3",
2632
"@tanstack/react-router-devtools": "^1.114.3",
2733
"@tanstack/react-router-with-query": "^1.114.3",
2834
"@tanstack/react-start": "^1.114.3",
35+
"@tanstack/react-store": "^0.7.0",
2936
"@tanstack/router-plugin": "^1.114.3",
37+
"@tanstack/store": "^0.7.0",
3038
"@uiw/codemirror-theme-okaidia": "^4.23.10",
3139
"@uiw/react-codemirror": "^4.23.10",
3240
"class-variance-authority": "^0.7.1",

packages/cta-ui/src/components/Header.tsx

Lines changed: 0 additions & 13 deletions
This file was deleted.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import {
2+
Sidebar,
3+
SidebarContent,
4+
SidebarFooter,
5+
SidebarGroup,
6+
SidebarHeader,
7+
} from '@/components/ui/sidebar'
8+
9+
import { SelectedAddOns } from '@/components/sidebar-items/add-ons'
10+
11+
export function AppSidebar() {
12+
return (
13+
<Sidebar>
14+
<SidebarHeader />
15+
<SidebarContent>
16+
<SidebarGroup>
17+
<SelectedAddOns />
18+
</SidebarGroup>
19+
<SidebarGroup />
20+
</SidebarContent>
21+
<SidebarFooter />
22+
</Sidebar>
23+
)
24+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { useState } from 'react'
2+
import { useStore } from '@tanstack/react-store'
3+
4+
import FileViewer from './file-viewer'
5+
import FileTree from './file-tree'
6+
7+
import { projectFiles } from '@/store/project'
8+
9+
export default function FileNavigator() {
10+
const [selectedFile, setSelectedFile] = useState<string | null>(null)
11+
12+
const { output, originalOutput } = useStore(projectFiles)
13+
14+
return (
15+
<div className="flex flex-row w-[calc(100vw-300px)]">
16+
<FileTree
17+
prefix="./"
18+
tree={output.files}
19+
originalTree={originalOutput.files}
20+
onFileSelected={(file) => {
21+
setSelectedFile(file)
22+
}}
23+
/>
24+
<div className="max-w-3/4 w-3/4 pl-2">
25+
{selectedFile ? (
26+
<FileViewer
27+
filePath={selectedFile}
28+
originalFile={originalOutput.files[selectedFile]}
29+
modifiedFile={output.files[selectedFile]}
30+
/>
31+
) : null}
32+
</div>
33+
</div>
34+
)
35+
}

packages/cta-ui/src/components/file-tree.tsx

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,30 @@
11
import { useMemo } from 'react'
22
import { FileText, Folder } from 'lucide-react'
33

4-
import { TreeView } from '@/components/ui/tree-view'
5-
64
import type { TreeDataItem } from '@/components/ui/tree-view'
75

6+
import { TreeView } from '@/components/ui/tree-view'
7+
88
export default function FileTree({
99
prefix,
1010
tree,
1111
originalTree,
1212
onFileSelected,
13-
extraTreeItems = [],
1413
}: {
1514
prefix: string
1615
tree: Record<string, string>
1716
originalTree: Record<string, string>
1817
onFileSelected: (file: string) => void
19-
extraTreeItems?: Array<TreeDataItem>
2018
}) {
2119
const computedTree = useMemo(() => {
22-
const treeData: Array<TreeDataItem> = []
20+
const treeData: Array<TreeDataItem> = [
21+
{
22+
id: 'root',
23+
name: '.',
24+
children: [],
25+
icon: () => <Folder className="w-4 h-4 mr-2" />,
26+
},
27+
]
2328

2429
function changed(file: string) {
2530
if (!originalTree[file]) {
@@ -31,7 +36,7 @@ export default function FileTree({
3136
Object.keys(tree)
3237
.sort()
3338
.forEach((file) => {
34-
const parts = file.replace(`${prefix}/`, '').split('/')
39+
const parts = file.split('/')
3540

3641
let currentLevel = treeData
3742
parts.forEach((part, index) => {
@@ -63,8 +68,8 @@ export default function FileTree({
6368
}
6469
})
6570
})
66-
return [...extraTreeItems, ...treeData]
67-
}, [prefix, tree, originalTree, extraTreeItems])
71+
return treeData
72+
}, [prefix, tree, originalTree])
6873

6974
return (
7075
<TreeView
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import { useMemo } from 'react'
2+
import { useStore } from '@tanstack/react-store'
3+
4+
import { Button } from '@/components/ui/button'
5+
6+
import { availableAddOns, selectedAddOns } from '@/store/project'
7+
8+
import { cn } from '@/lib/utils'
9+
10+
export function SelectedAddOns() {
11+
const addOns = useStore(availableAddOns)
12+
const selected = useStore(selectedAddOns)
13+
14+
const sortedAddOns = useMemo(() => {
15+
return addOns.sort((a, b) => {
16+
return a.name.localeCompare(b.name)
17+
})
18+
}, [addOns])
19+
20+
return (
21+
<>
22+
<h1 className="text-2xl font-bold">Add-ons</h1>
23+
<div className="flex flex-col gap-2">
24+
{sortedAddOns.map((addOn) => (
25+
<Button
26+
key={addOn.id}
27+
variant="outline"
28+
size="lg"
29+
className={cn('flex flex-col gap-0 align-start h-fit py-3 w-full')}
30+
onClick={() => {
31+
selectedAddOns.setState((state) => {
32+
if (state.some((a) => a.id === addOn.id)) {
33+
return state.filter((a) => a.id !== addOn.id)
34+
}
35+
return [...state, addOn]
36+
})
37+
}}
38+
style={{
39+
backgroundColor: selected.some((a) => a.id === addOn.id)
40+
? 'green'
41+
: 'transparent',
42+
}}
43+
>
44+
<div className="text-md font-bold">{addOn.name}</div>
45+
</Button>
46+
))}
47+
</div>
48+
</>
49+
)
50+
}

packages/cta-ui/src/components/ui/button.tsx

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,40 @@
1-
import * as React from "react"
2-
import { Slot } from "@radix-ui/react-slot"
3-
import { cva, type VariantProps } from "class-variance-authority"
1+
import * as React from 'react'
2+
import { Slot } from '@radix-ui/react-slot'
3+
import { cva } from 'class-variance-authority'
44

5-
import { cn } from "@/lib/utils"
5+
import type { VariantProps } from 'class-variance-authority'
6+
7+
import { cn } from '@/lib/utils'
68

79
const buttonVariants = cva(
810
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
911
{
1012
variants: {
1113
variant: {
1214
default:
13-
"bg-primary text-primary-foreground shadow-xs hover:bg-primary/90",
15+
'bg-primary text-primary-foreground shadow-xs hover:bg-primary/90',
1416
destructive:
15-
"bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
17+
'bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60',
1618
outline:
17-
"border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50",
19+
'border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50',
1820
secondary:
19-
"bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80",
21+
'bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80',
2022
ghost:
21-
"hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
22-
link: "text-primary underline-offset-4 hover:underline",
23+
'hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50',
24+
link: 'text-primary underline-offset-4 hover:underline',
2325
},
2426
size: {
25-
default: "h-9 px-4 py-2 has-[>svg]:px-3",
26-
sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5",
27-
lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
28-
icon: "size-9",
27+
default: 'h-9 px-4 py-2 has-[>svg]:px-3',
28+
sm: 'h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5',
29+
lg: 'h-10 rounded-md px-6 has-[>svg]:px-4',
30+
icon: 'size-9',
2931
},
3032
},
3133
defaultVariants: {
32-
variant: "default",
33-
size: "default",
34+
variant: 'default',
35+
size: 'default',
3436
},
35-
}
37+
},
3638
)
3739

3840
function Button({
@@ -41,11 +43,11 @@ function Button({
4143
size,
4244
asChild = false,
4345
...props
44-
}: React.ComponentProps<"button"> &
46+
}: React.ComponentProps<'button'> &
4547
VariantProps<typeof buttonVariants> & {
4648
asChild?: boolean
4749
}) {
48-
const Comp = asChild ? Slot : "button"
50+
const Comp = asChild ? Slot : 'button'
4951

5052
return (
5153
<Comp

0 commit comments

Comments
 (0)