Skip to content

Commit 73350d8

Browse files
committed
chore: clean up the CSS for the UI
1 parent ceb8b69 commit 73350d8

18 files changed

+603
-140
lines changed

packages/cta-ui/index.html

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,14 @@
44
<meta charset="UTF-8" />
55
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
66
<title>TanStack CTA</title>
7+
<link rel="preconnect" href="https://fonts.googleapis.com" />
8+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="" />
9+
<link
10+
rel="stylesheet"
11+
href="https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap"
12+
/>
713
</head>
8-
<body class="dark bg-black text-white dark">
14+
<body class="dark">
915
<div id="root"></div>
1016
<script type="module" src="/src/main.tsx"></script>
1117
</body>

packages/cta-ui/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
"zustand": "^5.0.3"
6161
},
6262
"devDependencies": {
63+
"@tailwindcss/typography": "^0.5.16",
6364
"@testing-library/dom": "^10.4.0",
6465
"@testing-library/react": "^16.2.0",
6566
"@types/cors": "^2.8.17",
9.45 KB
Loading
Lines changed: 229 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,229 @@
1+
import * as React from 'react'
2+
import { twMerge } from 'tailwind-merge'
3+
4+
import { useMounted } from '@/hooks/use-mounted'
5+
import { usePrefersReducedMotion } from '@/hooks/use-preferred-reduced-motion'
6+
7+
export function BackgroundAnimation() {
8+
const canvasRef = React.useRef<HTMLCanvasElement>(null)
9+
const prefersReducedMotion = usePrefersReducedMotion()
10+
const mounted = useMounted()
11+
const isHomePage = false
12+
13+
React.useEffect(() => {
14+
if (prefersReducedMotion !== false) {
15+
return
16+
}
17+
18+
const canvas = canvasRef.current
19+
20+
let morphDuration = 2000
21+
const waitDuration = 1000 * 60 * 2
22+
23+
const easingFn = cubicBezier(0.645, 0.045, 0.355, 1.0)
24+
25+
if (canvas) {
26+
const ctx = canvas.getContext('2d')!
27+
28+
let rafId: ReturnType<typeof requestAnimationFrame> | null = null
29+
let timeout: ReturnType<typeof setTimeout> | null = null
30+
let startTime = performance.now()
31+
32+
function createBlobs() {
33+
return shuffle([
34+
{
35+
color: { h: 10, s: 100, l: 50 },
36+
},
37+
{
38+
color: { h: 40, s: 100, l: 50 },
39+
},
40+
{
41+
color: { h: 150, s: 100, l: 50 },
42+
},
43+
{
44+
color: { h: 200, s: 100, l: 50 },
45+
},
46+
]).map((blob) => ({
47+
...blob,
48+
x: Math.random() * canvas!.width,
49+
y: Math.random() * canvas!.height,
50+
r: Math.random() * 500 + 700,
51+
colorH: blob.color.h,
52+
colorS: blob.color.s,
53+
colorL: blob.color.l,
54+
}))
55+
}
56+
57+
function shuffle<T>(array: T[]) {
58+
for (let i = array.length - 1; i > 0; i--) {
59+
const j = Math.floor(Math.random() * (i + 1))
60+
;[array[i], array[j]] = [array[j], array[i]]
61+
}
62+
return array
63+
}
64+
65+
let startBlobs = createBlobs()
66+
let currentBlobs = startBlobs
67+
let targetBlobs: ReturnType<typeof createBlobs> = []
68+
69+
function resizeHandler() {
70+
// Create an offscreen canvas and copy the current content
71+
const offscreen = document.createElement('canvas')
72+
offscreen.width = canvas!.width
73+
offscreen.height = canvas!.height
74+
offscreen.getContext('2d')!.drawImage(canvas!, 0, 0)
75+
76+
// Resize the main canvas
77+
canvas!.width = window.innerWidth
78+
canvas!.height = window.innerHeight
79+
80+
// Stretch and redraw the saved content to fill the new size
81+
ctx.drawImage(offscreen, 0, 0, canvas!.width, canvas!.height)
82+
}
83+
84+
function start() {
85+
if (timeout) {
86+
clearTimeout(timeout)
87+
}
88+
if (rafId) {
89+
cancelAnimationFrame(rafId)
90+
}
91+
92+
startBlobs = JSON.parse(JSON.stringify(currentBlobs))
93+
targetBlobs = createBlobs()
94+
startTime = performance.now()
95+
animate()
96+
}
97+
98+
function animate() {
99+
ctx.clearRect(0, 0, canvas!.width, canvas!.height)
100+
101+
const time = performance.now() - startTime
102+
const progress = time / morphDuration
103+
const easedProgress = easingFn(progress)
104+
105+
// Draw the blobs
106+
startBlobs.forEach((startBlob, i) => {
107+
const targetBlob = targetBlobs[i]
108+
109+
currentBlobs[i].x = interpolate(
110+
startBlob.x,
111+
targetBlob.x,
112+
easedProgress,
113+
)
114+
currentBlobs[i].y = interpolate(
115+
startBlob.y,
116+
targetBlob.y,
117+
easedProgress,
118+
)
119+
120+
const gradient = ctx.createRadialGradient(
121+
currentBlobs[i].x,
122+
currentBlobs[i].y,
123+
0,
124+
currentBlobs[i].x,
125+
currentBlobs[i].y,
126+
currentBlobs[i].r,
127+
)
128+
129+
currentBlobs[i].colorH = interpolate(
130+
startBlob.colorH,
131+
targetBlob.colorH,
132+
easedProgress,
133+
)
134+
currentBlobs[i].colorS = interpolate(
135+
startBlob.colorS,
136+
targetBlob.colorS,
137+
easedProgress,
138+
)
139+
currentBlobs[i].colorL = interpolate(
140+
startBlob.colorL,
141+
targetBlob.colorL,
142+
easedProgress,
143+
)
144+
145+
gradient.addColorStop(
146+
0,
147+
`hsla(${currentBlobs[i].colorH}, ${currentBlobs[i].colorS}%, ${currentBlobs[i].colorL}%, 1)`,
148+
)
149+
gradient.addColorStop(
150+
1,
151+
`hsla(${currentBlobs[i].colorH}, ${currentBlobs[i].colorS}%, ${currentBlobs[i].colorL}%, 0)`,
152+
)
153+
154+
ctx.fillStyle = gradient
155+
ctx.beginPath()
156+
ctx.arc(
157+
currentBlobs[i].x,
158+
currentBlobs[i].y,
159+
currentBlobs[i].r,
160+
0,
161+
Math.PI * 2,
162+
)
163+
ctx.fill()
164+
})
165+
166+
if (progress < 1) {
167+
rafId = requestAnimationFrame(animate)
168+
} else {
169+
timeout = setTimeout(() => {
170+
morphDuration = 4000
171+
start()
172+
}, waitDuration)
173+
}
174+
}
175+
176+
resizeHandler()
177+
start()
178+
window.addEventListener('resize', resizeHandler)
179+
180+
return () => {
181+
if (rafId) {
182+
cancelAnimationFrame(rafId)
183+
}
184+
if (timeout) {
185+
clearTimeout(timeout)
186+
}
187+
window.removeEventListener('resize', resizeHandler)
188+
}
189+
}
190+
}, [prefersReducedMotion])
191+
192+
return (
193+
<div
194+
className={twMerge(
195+
'fixed inset-0 z-0 opacity-20 pointer-events-none',
196+
'transition-opacity duration-[2s] ease-linear',
197+
'[&+*]:relative',
198+
mounted
199+
? isHomePage
200+
? 'opacity-10 dark:opacity-20'
201+
: 'opacity-10 dark:opacity-20'
202+
: 'opacity-0',
203+
)}
204+
>
205+
<canvas ref={canvasRef} />
206+
</div>
207+
)
208+
}
209+
210+
function cubicBezier(p1x: number, p1y: number, p2x: number, p2y: number) {
211+
return function (t: number) {
212+
const cx = 3 * p1x
213+
const bx = 3 * (p2x - p1x) - cx
214+
const ax = 1 - cx - bx
215+
216+
const cy = 3 * p1y
217+
const by = 3 * (p2y - p1y) - cy
218+
const ay = 1 - cy - by
219+
220+
const x = ((ax * t + bx) * t + cx) * t
221+
const y = ((ay * t + by) * t + cy) * t
222+
223+
return y
224+
}
225+
}
226+
227+
function interpolate(start: number, end: number, progress: number) {
228+
return start + (end - start) * progress
229+
}
Lines changed: 28 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,3 @@
1-
import {
2-
Sidebar,
3-
SidebarContent,
4-
SidebarFooter,
5-
SidebarGroup,
6-
SidebarHeader,
7-
} from '@/components/ui/sidebar'
8-
91
import SelectedAddOns from '@/components/sidebar-items/add-ons'
102
import RunAddOns from '@/components/sidebar-items/run-add-ons'
113
import RunCreateApp from '@/components/sidebar-items/run-create-app'
@@ -14,42 +6,45 @@ import ModeSelector from '@/components/sidebar-items/mode-selector'
146
import TypescriptSwitch from '@/components/sidebar-items/typescript-switch'
157
import StarterDialog from '@/components/sidebar-items/starter'
168

9+
import { ChevronRightIcon } from 'lucide-react'
10+
1711
import { useApplicationMode, useReady } from '@/store/project'
1812

1913
export function AppSidebar() {
2014
const ready = useReady()
2115
const mode = useApplicationMode()
2216

2317
return (
24-
<Sidebar>
25-
<SidebarHeader className="flex justify-center items-center">
26-
<img src="/tanstack.png" className="w-3/5" />
27-
</SidebarHeader>
28-
<SidebarContent>
29-
{ready && (
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">
3324
<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">
3427
<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">
3530
<TypescriptSwitch />
36-
</SidebarGroup>
37-
)}
38-
<SidebarGroup>
39-
<SelectedAddOns />
40-
</SidebarGroup>
41-
{mode === 'setup' && (
42-
<SidebarGroup>
43-
<StarterDialog />
44-
</SidebarGroup>
45-
)}
46-
</>
47-
)}
48-
</SidebarContent>
49-
<SidebarFooter className="mb-5">
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">
5045
<RunAddOns />
5146
<RunCreateApp />
52-
</SidebarFooter>
53-
</Sidebar>
47+
</div>
48+
</div>
5449
)
5550
}

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

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -184,14 +184,12 @@ export default function FileNavigator() {
184184
}
185185

186186
return (
187-
<div
188-
className={`flex flex-row border-1 rounded-md mr-10 p-2 inset-shadow-gray-600 inset-shadow-sm`}
189-
>
190-
<div className="w-1/4 max-w-1/4 pr-2">
187+
<div className="bg-white dark:bg-black/50 rounded-lg p-2 sm:p-4 flex">
188+
<div className="w-1/4 max-w-1/4 bg-gray-500/10 rounded-l-lg">
191189
{mode === 'add' && <Filters />}
192190
<FileTree selectedFile={selectedFile} tree={fileTree} />
193191
</div>
194-
<div className="max-w-3/4 w-3/4 pl-2">
192+
<div className="max-w-3/4 w-3/4">
195193
{selectedFile && modifiedFileContents ? (
196194
<FileViewer
197195
filePath={selectedFile}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
}

0 commit comments

Comments
 (0)