Skip to content

Commit 97c2faf

Browse files
committed
update components to shadcn's button and slider
1 parent deaaa82 commit 97c2faf

File tree

5 files changed

+90
-100
lines changed

5 files changed

+90
-100
lines changed

src/app/layout.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ export default function RootLayout({
2424
children: React.ReactNode;
2525
}>) {
2626
return (
27-
<html lang="en">
27+
<html lang="en" className="dark">
2828
<body
2929
className={`${geistSans.variable} ${geistMono.variable} antialiased`}
3030
>

src/components/Sidebar.tsx

Lines changed: 65 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
// src/components/Sidebar.tsx
22
"use client";
3-
import { useEffect, useState, ChangeEvent, useCallback, useRef } from "react";
3+
import { useEffect, useState, useCallback, useRef } from "react";
44
import { generateRandomPoint } from "@/lib/utils/randomPoint";
55
import { SidebarProps, ShapeType } from "@/types";
66
import { theme } from "@/lib/theme";
77
import Image from "next/image";
88
import TestMode from "./TestMode";
9+
import { Button } from "@/components/ui/button";
10+
import { Slider } from "@/components/ui/slider";
911

1012
export default function Sidebar({
1113
shapeState,
@@ -59,13 +61,10 @@ export default function Sidebar({
5961
[shapeType, updateShapeState, setIsDrawingPolygon],
6062
);
6163

62-
// Handle value changes with debouncing
63-
const handleValueChange = useCallback(
64-
(
65-
e: ChangeEvent<HTMLInputElement>,
66-
valueType: "radiusX" | "radiusY" | "rotation",
67-
) => {
68-
const value = e.target.value;
64+
// Handle slider value changes
65+
const handleSliderChange = useCallback(
66+
(values: number[], valueType: "radiusX" | "radiusY" | "rotation") => {
67+
const value = values[0].toString();
6968

7069
// Update local input state
7170
if (valueType === "radiusX") {
@@ -145,7 +144,7 @@ export default function Sidebar({
145144
};
146145

147146
return (
148-
<div className="w-80 bg-black shadow-md p-4 overflow-auto h-screen text-white">
147+
<div className="w-80 bg-background shadow-md p-4 overflow-auto h-screen text-white">
149148
<div className="flex flex-col items-center justify-center select-none">
150149
<Image
151150
src="/PickRandomSpot/logo.svg"
@@ -178,12 +177,9 @@ export default function Sidebar({
178177
<div className="mb-4">
179178
<h2 className="text-lg font-semibold mb-2">Shape Type</h2>
180179
<div className="grid grid-cols-3 gap-2">
181-
<button
182-
className={`px-2 py-1 rounded transition-colors ${
183-
shapeType === "ellipse"
184-
? "bg-emerald-600 text-white"
185-
: "bg-gray-700 hover:bg-gray-600"
186-
}`}
180+
<Button
181+
className={shapeType === "ellipse" ? "text-white" : ""}
182+
variant={shapeType === "ellipse" ? "default" : "outline"}
187183
style={
188184
shapeType === "ellipse"
189185
? { backgroundColor: theme.shapes.ellipse.color }
@@ -192,13 +188,10 @@ export default function Sidebar({
192188
onClick={() => handleShapeTypeChange("ellipse")}
193189
>
194190
Ellipse
195-
</button>
196-
<button
197-
className={`px-2 py-1 rounded transition-colors ${
198-
shapeType === "rectangle"
199-
? "bg-amber-600 text-white"
200-
: "bg-gray-700 hover:bg-gray-600"
201-
}`}
191+
</Button>
192+
<Button
193+
className={shapeType === "rectangle" ? "text-white" : ""}
194+
variant={shapeType === "rectangle" ? "default" : "outline"}
202195
style={
203196
shapeType === "rectangle"
204197
? { backgroundColor: theme.shapes.rectangle.color }
@@ -207,13 +200,10 @@ export default function Sidebar({
207200
onClick={() => handleShapeTypeChange("rectangle")}
208201
>
209202
Rectangle
210-
</button>
211-
<button
212-
className={`px-2 py-1 rounded transition-colors ${
213-
shapeType === "polygon"
214-
? "bg-purple-600 text-white"
215-
: "bg-gray-700 hover:bg-gray-600"
216-
}`}
203+
</Button>
204+
<Button
205+
className={shapeType === "polygon" ? "text-white" : ""}
206+
variant={shapeType === "polygon" ? "default" : "outline"}
217207
style={
218208
shapeType === "polygon"
219209
? { backgroundColor: theme.shapes.polygon.color }
@@ -222,7 +212,7 @@ export default function Sidebar({
222212
onClick={() => handleShapeTypeChange("polygon")}
223213
>
224214
Polygon
225-
</button>
215+
</Button>
226216
</div>
227217
</div>
228218

@@ -238,43 +228,45 @@ export default function Sidebar({
238228
</p>
239229
{points.length > 2 && (
240230
<p className="mb-2">
241-
{/* Remove reference to clicking near first point */}
242231
Click &quot;Complete Drawing&quot; when you&apos;re finished
243232
adding points.
244233
</p>
245234
)}
246-
<button
247-
className="px-2 py-1 rounded bg-green-600 hover:bg-green-700 text-white mt-2 mr-2"
235+
<Button
236+
variant="default"
237+
className="mr-2 mt-2"
248238
onClick={() => {
249239
// Complete the polygon instead of canceling
250240
setIsDrawingPolygon(false);
251241
}}
252242
disabled={points.length < 3}
253243
>
254244
Complete Drawing
255-
</button>
256-
<button
257-
className="px-2 py-1 rounded bg-red-600 hover:bg-red-700 text-white mt-2"
245+
</Button>
246+
<Button
247+
variant="destructive"
248+
className="mt-2"
258249
onClick={() => {
259250
updateShapeState({ points: [] });
260251
setIsDrawingPolygon(false);
261252
}}
262253
>
263254
Cancel Drawing
264-
</button>
255+
</Button>
265256
</div>
266257
) : points.length > 2 ? (
267258
<div>
268259
<p className="mb-2">Polygon with {points.length} points</p>
269-
<button
270-
className="px-2 py-1 rounded bg-blue-600 hover:bg-blue-700 text-white mt-2"
260+
<Button
261+
variant="default"
262+
className="mt-2"
271263
onClick={() => {
272264
// Keep existing points when redrawing
273265
setIsDrawingPolygon(true);
274266
}}
275267
>
276268
Redraw Polygon
277-
</button>
269+
</Button>
278270
</div>
279271
) : (
280272
<p className="text-gray-400">
@@ -296,54 +288,54 @@ export default function Sidebar({
296288

297289
{/* Width/Radius X */}
298290
<div className="mb-4">
299-
<label className="block text-sm font-medium mb-1">
291+
<label className="select-none block text-sm font-medium mb-1">
300292
{shapeType === "rectangle" ? "Width" : "Radius X"} (km):{" "}
301293
{radiusXInput}
302294
</label>
303-
<input
304-
type="range"
305-
min="0.1"
306-
max="100"
307-
step="0.1"
308-
value={radiusXInput}
309-
onChange={(e) => handleValueChange(e, "radiusX")}
310-
className="w-full"
295+
<Slider
296+
min={0.1}
297+
max={100}
298+
step={0.1}
299+
value={[parseFloat(radiusXInput)]}
300+
onValueChange={(values) =>
301+
handleSliderChange(values, "radiusX")
302+
}
311303
/>
312304
</div>
313305

314306
{/* Height/Radius Y (only for ellipse and rectangle) */}
315307
{(shapeType === "ellipse" || shapeType === "rectangle") && (
316308
<div className="mb-4">
317-
<label className="block text-sm font-medium mb-1">
309+
<label className="select-none block text-sm font-medium mb-1">
318310
{shapeType === "rectangle" ? "Height" : "Radius Y"} (km):{" "}
319311
{radiusYInput}
320312
</label>
321-
<input
322-
type="range"
323-
min="0.1"
324-
max="100"
325-
step="0.1"
326-
value={radiusYInput}
327-
onChange={(e) => handleValueChange(e, "radiusY")}
328-
className="w-full"
313+
<Slider
314+
min={0.1}
315+
max={100}
316+
step={0.1}
317+
value={[parseFloat(radiusYInput)]}
318+
onValueChange={(values) =>
319+
handleSliderChange(values, "radiusY")
320+
}
329321
/>
330322
</div>
331323
)}
332324

333325
{/* Rotation (only for ellipse and rectangle) */}
334326
{(shapeType === "ellipse" || shapeType === "rectangle") && (
335327
<div className="mb-4">
336-
<label className="block text-sm font-medium mb-1">
328+
<label className="select-none block text-sm font-medium mb-1">
337329
Rotation (°): {rotationInput}
338330
</label>
339-
<input
340-
type="range"
341-
min="0"
342-
max="360"
343-
step="1"
344-
value={rotationInput}
345-
onChange={(e) => handleValueChange(e, "rotation")}
346-
className="w-full"
331+
<Slider
332+
min={0}
333+
max={360}
334+
step={1}
335+
value={[parseFloat(rotationInput)]}
336+
onValueChange={(values) =>
337+
handleSliderChange(values, "rotation")
338+
}
347339
/>
348340
</div>
349341
)}
@@ -356,9 +348,9 @@ export default function Sidebar({
356348
</div>
357349

358350
<div className="space-y-2">
359-
<button
360-
className="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded w-full transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
361-
style={{ backgroundColor: theme.colors.primary }}
351+
<Button
352+
variant="default"
353+
className="w-full"
362354
onClick={generateRandomSpot}
363355
disabled={
364356
(shapeState.shapeType === "polygon" &&
@@ -367,14 +359,11 @@ export default function Sidebar({
367359
}
368360
>
369361
Generate Random Point
370-
</button>
362+
</Button>
371363

372-
<button
373-
className="border border-gray-500 hover:bg-gray-700 px-4 py-2 rounded w-full transition-colors"
374-
onClick={clearSelection}
375-
>
364+
<Button variant="outline" className="w-full" onClick={clearSelection}>
376365
Clear Selection
377-
</button>
366+
</Button>
378367
</div>
379368

380369
{randomLat !== null && randomLng !== null && (

src/components/TestMode.tsx

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import { useState } from "react";
44
import { generateRandomPoint } from "@/lib/utils/randomPoint";
55
import { ShapeState } from "@/types";
6+
import { Button } from "@/components/ui/button";
67

78
interface TestModeProps {
89
shapeState: ShapeState;
@@ -73,7 +74,7 @@ export default function TestMode({
7374
</div>
7475

7576
<div className="mt-2">
76-
<label className="block text-sm mb-1">Number of test points:</label>
77+
<label className="select-none block text-sm mb-1">Number of test points:</label>
7778
<div className="flex space-x-2">
7879
<input
7980
type="number"
@@ -85,25 +86,25 @@ export default function TestMode({
8586
}
8687
className="bg-gray-700 text-white px-2 py-1 rounded w-24"
8788
/>
88-
<button
89+
<Button
8990
onClick={generateTestPoints}
9091
disabled={isGenerating}
91-
className={`px-2 py-1 rounded text-sm flex-grow ${
92-
isGenerating ? "bg-gray-600" : "bg-yellow-600 hover:bg-yellow-500"
93-
}`}
92+
variant={isGenerating ? "outline" : "default"}
93+
className={`text-sm flex-grow ${isGenerating ? "" : "bg-yellow-600 hover:bg-yellow-500"}`}
9494
>
9595
{isGenerating ? "Generating..." : "Generate Test Points"}
96-
</button>
96+
</Button>
9797
</div>
9898
</div>
9999

100100
<div className="flex space-x-2 mt-2">
101-
<button
101+
<Button
102102
onClick={clearTestPoints}
103-
className="px-2 py-1 rounded text-sm bg-red-700 hover:bg-red-600 w-full"
103+
variant="destructive"
104+
className="text-sm w-full"
104105
>
105106
Clear Test Points
106-
</button>
107+
</Button>
107108
</div>
108109

109110
<p className="text-xs text-gray-400 mt-2">
@@ -112,4 +113,4 @@ export default function TestMode({
112113
</p>
113114
</div>
114115
);
115-
}
116+
}

src/components/ui/button.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { cva, type VariantProps } from "class-variance-authority"
55
import { cn } from "@/lib/utils"
66

77
const buttonVariants = cva(
8-
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-[color,box-shadow] 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",
8+
"cursor-pointer select-none inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-[color,box-shadow] 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",
99
{
1010
variants: {
1111
variant: {

0 commit comments

Comments
 (0)