Skip to content

Commit f716377

Browse files
committed
chore: moving to jotai
1 parent 22b28c9 commit f716377

14 files changed

+228
-227
lines changed

packages/cta-ui/package.json

+3-2
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,13 @@
4141
"@tanstack/react-start": "^1.114.3",
4242
"@tanstack/react-store": "^0.7.0",
4343
"@tanstack/router-plugin": "^1.114.3",
44-
"@tanstack/store": "^0.7.0",
4544
"@uiw/codemirror-theme-github": "^4.23.10",
4645
"@uiw/react-codemirror": "^4.23.10",
4746
"class-variance-authority": "^0.7.1",
4847
"clsx": "^2.1.1",
4948
"execa": "^9.5.2",
49+
"jotai": "^2.12.3",
50+
"jotai-tanstack-query": "^0.9.0",
5051
"lucide-react": "^0.476.0",
5152
"next-themes": "^0.4.6",
5253
"react": "^19.0.0",
@@ -65,8 +66,8 @@
6566
"@types/node": "^22.14.1",
6667
"@types/react": "^19.0.8",
6768
"@types/react-dom": "^19.0.3",
68-
"@vitest/coverage-v8": "3.1.1",
6969
"@vitejs/plugin-react": "^4.3.4",
70+
"@vitest/coverage-v8": "3.1.1",
7071
"jsdom": "^26.0.0",
7172
"typescript": "^5.7.2",
7273
"vite": "^6.1.0",

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

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useStore } from '@tanstack/react-store'
1+
import { useAtomValue } from 'jotai'
22
import {
33
Sidebar,
44
SidebarContent,
@@ -18,8 +18,8 @@ import StarterDialog from '@/components/sidebar-items/starter'
1818
import { applicationMode, isInitialized } from '@/store/project'
1919

2020
export function AppSidebar() {
21-
const ready = useStore(isInitialized)
22-
const mode = useStore(applicationMode)
21+
const ready = useAtomValue(isInitialized)
22+
const mode = useAtomValue(applicationMode)
2323

2424
return (
2525
<Sidebar>

packages/cta-ui/src/components/custom-add-on-dialog.tsx

+6-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { useState } from 'react'
2-
import { useStore } from '@tanstack/react-store'
2+
import { useAtomValue, useSetAtom } from 'jotai'
33
import { toast } from 'sonner'
44
import { TicketPlusIcon } from 'lucide-react'
55

@@ -19,16 +19,18 @@ export default function CustomAddOnDialog() {
1919
const [url, setUrl] = useState('')
2020
const [open, setOpen] = useState(false)
2121

22-
const mode = useStore(projectOptions).mode
22+
const mode = useAtomValue(projectOptions).mode
23+
const setCustomAddOns = useSetAtom(customAddOns)
24+
const toggle = useSetAtom(toggleAddOn)
2325

2426
async function onImport() {
2527
const response = await fetch(`/api/load-remote-add-on?url=${url}`)
2628
const data = await response.json()
2729

2830
if (!data.error) {
29-
customAddOns.setState((state) => [...state, data])
31+
setCustomAddOns((state) => [...state, data])
3032
if (data.modes.includes(mode)) {
31-
toggleAddOn(data.id)
33+
toggle(data.id)
3234
}
3335
setOpen(false)
3436
} else {

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

+12-11
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { useMemo, useState } from 'react'
2-
import { useStore } from '@tanstack/react-store'
2+
import { useAtomValue, useSetAtom } from 'jotai'
33
import { FileText, Folder } from 'lucide-react'
44

55
import FileViewer from './file-viewer'
@@ -9,11 +9,10 @@ import type { FileTreeItem } from '@/types'
99

1010
import { Label } from '@/components/ui/label'
1111
import { Checkbox } from '@/components/ui/checkbox'
12-
import { Separator } from '@/components/ui/separator'
13-
import { useSidebar } from '@/components/ui/sidebar'
1412

1513
import {
1614
applicationMode,
15+
dryRunAtom,
1716
includeFiles,
1817
isInitialized,
1918
projectFiles,
@@ -23,12 +22,12 @@ import {
2322
import { getFileClass, twClasses } from '@/file-classes'
2423

2524
export function Filters() {
26-
const includedFiles = useStore(includeFiles)
27-
25+
const includedFiles = useAtomValue(includeFiles)
26+
const setIncludeFiles = useSetAtom(includeFiles)
2827
function toggleFilter(
2928
filter: 'unchanged' | 'added' | 'modified' | 'deleted' | 'overwritten',
3029
) {
31-
includeFiles.setState((state) => {
30+
setIncludeFiles((state) => {
3231
if (state.includes(filter)) {
3332
return state.filter((file) => file !== filter)
3433
}
@@ -105,18 +104,19 @@ export default function FileNavigator() {
105104
'./package.json',
106105
)
107106

108-
const { output, originalOutput } = useStore(projectFiles)
109-
const localTree = useStore(projectLocalFiles)
107+
const { originalOutput } = useAtomValue(projectFiles)
108+
const localTree = useAtomValue(projectLocalFiles)
109+
const { data: output } = useAtomValue(dryRunAtom)
110110

111-
const mode = useStore(applicationMode)
111+
const mode = useAtomValue(applicationMode)
112112
const tree = output.files
113113
const originalTree = mode === 'setup' ? output.files : originalOutput.files
114114
const deletedFiles = output.deletedFiles
115115

116116
const [originalFileContents, setOriginalFileContents] = useState<string>()
117117
const [modifiedFileContents, setModifiedFileContents] = useState<string>()
118118

119-
const includedFiles = useStore(includeFiles)
119+
const includedFiles = useAtomValue(includeFiles)
120120

121121
const fileTree = useMemo(() => {
122122
const treeData: Array<FileTreeItem> = []
@@ -187,7 +187,8 @@ export default function FileNavigator() {
187187
return treeData
188188
}, [tree, originalTree, localTree, includedFiles])
189189

190-
const ready = useStore(isInitialized)
190+
const ready = useAtomValue(isInitialized)
191+
191192
if (!ready) {
192193
return null
193194
}

packages/cta-ui/src/components/sidebar-items/add-ons.tsx

+5-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { useMemo, useState } from 'react'
2-
import { useStore } from '@tanstack/react-store'
2+
import { useAtomValue, useSetAtom } from 'jotai'
33
import { InfoIcon } from 'lucide-react'
44

55
import type { AddOnInfo } from '@/types'
@@ -19,8 +19,9 @@ const addOnTypeLabels: Record<string, string> = {
1919
}
2020

2121
export default function SelectedAddOns() {
22-
const addOns = useStore(availableAddOns)
23-
const addOnStatus = useStore(addOnState)
22+
const addOns = useAtomValue(availableAddOns)
23+
const addOnStatus = useAtomValue(addOnState)
24+
const toggle = useSetAtom(toggleAddOn)
2425

2526
const sortedAddOns = useMemo(() => {
2627
return addOns.sort((a, b) => {
@@ -57,7 +58,7 @@ export default function SelectedAddOns() {
5758
checked={addOnStatus[addOn.id].selected}
5859
disabled={!addOnStatus[addOn.id].enabled}
5960
onCheckedChange={() => {
60-
toggleAddOn(addOn.id)
61+
toggle(addOn.id)
6162
}}
6263
/>
6364
<Label

packages/cta-ui/src/components/sidebar-items/mode-selector.tsx

+11-12
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,17 @@
1-
import { useStore } from '@tanstack/react-store'
1+
import { useAtomValue, useSetAtom } from 'jotai'
22
import { CodeIcon, FileIcon } from 'lucide-react'
33

44
import type { Mode } from '@tanstack/cta-engine'
55

66
import { ToggleGroup, ToggleGroupItem } from '@/components/ui/toggle-group'
77

8-
import {
9-
applicationMode,
10-
modeEditable,
11-
projectOptions,
12-
setMode,
13-
} from '@/store/project'
8+
import { applicationMode, modeEditable, projectOptions } from '@/store/project'
149

1510
export default function ModeSelector() {
16-
const mode = useStore(applicationMode)
17-
const options = useStore(projectOptions)
18-
const enableMode = useStore(modeEditable)
11+
const mode = useAtomValue(applicationMode)
12+
const enableMode = useAtomValue(modeEditable)
13+
const routerMode = useAtomValue(projectOptions).mode
14+
const setRouterMode = useSetAtom(projectOptions)
1915

2016
if (mode !== 'setup') {
2117
return null
@@ -26,10 +22,13 @@ export default function ModeSelector() {
2622
<div className="flex flex-row justify-center items-center mt-4">
2723
<ToggleGroup
2824
type="single"
29-
value={options.mode}
25+
value={routerMode}
3026
onValueChange={(v: string) => {
3127
if (v) {
32-
setMode(v as Mode)
28+
setRouterMode((state) => ({
29+
...state,
30+
mode: v as Mode,
31+
}))
3332
}
3433
}}
3534
>

packages/cta-ui/src/components/sidebar-items/project-name.tsx

+5-4
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
1-
import { useStore } from '@tanstack/react-store'
1+
import { useAtomValue, useSetAtom } from 'jotai'
22

33
import { Input } from '@/components/ui/input'
44
import { SidebarGroupLabel } from '@/components/ui/sidebar'
55

66
import { applicationMode, projectOptions } from '@/store/project'
77

88
export default function ProjectName() {
9-
const name = useStore(projectOptions)
10-
const mode = useStore(applicationMode)
9+
const name = useAtomValue(projectOptions)
10+
const mode = useAtomValue(applicationMode)
11+
const setProjectOptions = useSetAtom(projectOptions)
1112

1213
if (mode !== 'setup') {
1314
return null
@@ -20,7 +21,7 @@ export default function ProjectName() {
2021
value={name.projectName}
2122
placeholder="my-app"
2223
onChange={(e) => {
23-
projectOptions.setState((state) => ({
24+
setProjectOptions((state) => ({
2425
...state,
2526
projectName: e.target.value,
2627
}))

packages/cta-ui/src/components/sidebar-items/run-add-ons.tsx

+5-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { useState } from 'react'
2-
import { useStore } from '@tanstack/react-store'
2+
import { useAtomValue } from 'jotai'
33

44
import { Button } from '@/components/ui/button'
55
import {
@@ -13,12 +13,13 @@ import {
1313
import { applicationMode, selectedAddOns } from '@/store/project'
1414

1515
export default function RunAddOns() {
16-
const currentlySelectedAddOns = useStore(selectedAddOns)
16+
const currentlySelectedAddOns = useAtomValue(selectedAddOns)
1717
const [isRunning, setIsRunning] = useState(false)
1818
const [output, setOutput] = useState('')
1919
const [finished, setFinished] = useState(false)
2020

21-
const mode = useStore(applicationMode)
21+
const mode = useAtomValue(applicationMode)
22+
const selAddOns = useAtomValue(selectedAddOns)
2223

2324
if (mode !== 'add') {
2425
return null
@@ -31,7 +32,7 @@ export default function RunAddOns() {
3132
const streamingReq = await fetch('/api/add-to-app', {
3233
method: 'POST',
3334
body: JSON.stringify({
34-
addOns: selectedAddOns.state.map((addOn) => addOn.id),
35+
addOns: selAddOns.map((addOn) => addOn.id),
3536
}),
3637
headers: {
3738
'Content-Type': 'application/json',

packages/cta-ui/src/components/sidebar-items/run-create-app.tsx

+7-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { useState } from 'react'
2-
import { useStore } from '@tanstack/react-store'
2+
import { useAtomValue } from 'jotai'
33
import { HammerIcon } from 'lucide-react'
44

55
import { Button } from '@/components/ui/button'
@@ -23,8 +23,10 @@ export default function RunCreateApp() {
2323
const [output, setOutput] = useState('')
2424
const [finished, setFinished] = useState(false)
2525

26-
const mode = useStore(applicationMode)
27-
const options = useStore(projectOptions)
26+
const mode = useAtomValue(applicationMode)
27+
const options = useAtomValue(projectOptions)
28+
const selAddOns = useAtomValue(selectedAddOns)
29+
const projStarter = useAtomValue(projectStarter)
2830

2931
if (mode !== 'setup') {
3032
return null
@@ -39,8 +41,8 @@ export default function RunCreateApp() {
3941
body: JSON.stringify({
4042
options: {
4143
...options,
42-
chosenAddOns: selectedAddOns.state.map((addOn) => addOn.id),
43-
starter: projectStarter.state?.url || undefined,
44+
chosenAddOns: selAddOns.map((addOn) => addOn.id),
45+
starter: projStarter?.url || undefined,
4446
},
4547
}),
4648
headers: {

packages/cta-ui/src/components/sidebar-items/starter.tsx

+9-11
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { useState } from 'react'
2-
import { useStore } from '@tanstack/react-store'
2+
import { useAtomValue, useSetAtom } from 'jotai'
33
import { FileBoxIcon, TrashIcon } from 'lucide-react'
44

55
import { toast } from 'sonner'
@@ -14,21 +14,19 @@ import {
1414
DialogTitle,
1515
} from '@/components/ui/dialog'
1616

17-
import {
18-
applicationMode,
19-
projectStarter,
20-
removeStarter,
21-
setStarter,
22-
} from '@/store/project'
17+
import { applicationMode, projectStarter } from '@/store/project'
2318

2419
export default function Starter() {
2520
const [url, setUrl] = useState('')
2621
const [open, setOpen] = useState(false)
2722

28-
const mode = useStore(applicationMode)
23+
const mode = useAtomValue(applicationMode)
24+
25+
const starterName = useAtomValue(projectStarter)?.name
26+
const starterBanner = useAtomValue(projectStarter)?.banner
27+
28+
const setStarter = useSetAtom(projectStarter)
2929

30-
const starterName = useStore(projectStarter)?.name
31-
const starterBanner = useStore(projectStarter)?.banner
3230
if (mode !== 'setup') {
3331
return null
3432
}
@@ -67,7 +65,7 @@ export default function Starter() {
6765
size="sm"
6866
className="mr-2"
6967
onClick={() => {
70-
removeStarter()
68+
setStarter(undefined)
7169
}}
7270
>
7371
<TrashIcon className="w-4 h-4" />

packages/cta-ui/src/components/sidebar-items/typescript-switch.tsx

+9-8
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1-
import { useStore } from '@tanstack/react-store'
1+
import { useAtomValue, useSetAtom } from 'jotai'
22

33
import { Label } from '@/components/ui/label'
44
import { Switch } from '@/components/ui/switch'
5-
import { cn } from '@/lib/utils'
65

76
import {
87
applicationMode,
@@ -12,10 +11,12 @@ import {
1211
} from '@/store/project'
1312

1413
export default function TypescriptSwitch() {
15-
const options = useStore(projectOptions)
16-
const mode = useStore(applicationMode)
17-
const enableTailwind = useStore(tailwindEditable)
18-
const enableTypeScript = useStore(typeScriptEditable)
14+
const options = useAtomValue(projectOptions)
15+
const mode = useAtomValue(applicationMode)
16+
const enableTailwind = useAtomValue(tailwindEditable)
17+
const enableTypeScript = useAtomValue(typeScriptEditable)
18+
19+
const setProjectOptions = useSetAtom(projectOptions)
1920

2021
if (mode !== 'setup') {
2122
return null
@@ -28,7 +29,7 @@ export default function TypescriptSwitch() {
2829
id="typescript-switch"
2930
checked={options.typescript}
3031
onCheckedChange={(checked) => {
31-
projectOptions.setState((state) => ({
32+
setProjectOptions((state) => ({
3233
...state,
3334
typescript: checked,
3435
}))
@@ -45,7 +46,7 @@ export default function TypescriptSwitch() {
4546
id="tailwind-switch"
4647
checked={options.tailwind}
4748
onCheckedChange={(checked) => {
48-
projectOptions.setState((state) => ({
49+
setProjectOptions((state) => ({
4950
...state,
5051
tailwind: checked,
5152
}))

0 commit comments

Comments
 (0)