improved ui

master
TZGyn 11 months ago
parent 6575add5df
commit 4f8b6b7101

@ -2,7 +2,6 @@
import { Bar, BarChart, CartesianGrid, XAxis } from "recharts";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import {
ChartConfig,
ChartContainer,
@ -22,65 +21,15 @@ const chartConfig = {
} satisfies ChartConfig;
export function DayChart({
data,
chartData,
}: {
data: {
timestamp: number;
chartData: {
day: string;
value: number;
foldtime: number;
}[];
}) {
const thisMonthTimestamp = new Date();
thisMonthTimestamp.setHours(0, 0, 0, 0);
thisMonthTimestamp.setDate(1);
const nextMonthTimestamp = new Date();
nextMonthTimestamp.setHours(0, 0, 0, 0);
nextMonthTimestamp.setDate(1);
nextMonthTimestamp.setMonth(nextMonthTimestamp.getMonth() + 1);
console.log(thisMonthTimestamp.getTime(), nextMonthTimestamp.getTime());
const thisMonthData = data.filter(
(data) =>
data.timestamp >= thisMonthTimestamp.getTime() &&
data.timestamp < nextMonthTimestamp.getTime()
);
const todayDataPerHour = thisMonthData.reduce((acc, data) => {
const day = new Date(data.timestamp).getDate();
if (!acc[day]) {
acc[day] = {
count: 1,
foldTime: data.foldtime,
};
}
acc[day].count += 1;
acc[day].foldTime += data.foldtime;
return acc;
}, {} as Record<number, { count: number; foldTime: number }>);
const thisMonthDays = new Date();
thisMonthDays.setMonth(thisMonthDays.getMonth() + 1);
thisMonthDays.setDate(1);
thisMonthDays.setDate(thisMonthDays.getDate() - 1);
const chartData = new Array(thisMonthDays.getDate()).fill(0).map((_, i) => {
const day = i + 1;
if (!todayDataPerHour[day])
return { day: "Day " + day, value: 0, foldtime: 0 };
return {
day: "Day " + day,
value: todayDataPerHour[day].count,
foldtime:
todayDataPerHour[day].foldTime / todayDataPerHour[day].count,
};
});
return (
<Card className="w-full max-w-[1200px]">
<CardHeader>
<CardTitle>This Month</CardTitle>
{/* <CardDescription>January - June 2024</CardDescription> */}
</CardHeader>
<CardContent>
<ChartContainer config={chartConfig}>
<BarChart accessibilityLayer data={chartData}>
<CartesianGrid vertical={false} />
@ -94,11 +43,7 @@ export function DayChart({
cursor={false}
content={<ChartTooltipContent indicator="line" />}
/>
<Bar
dataKey="value"
fill="var(--color-value)"
radius={4}
/>
<Bar dataKey="value" fill="var(--color-value)" radius={4} />
<Bar
dataKey="foldtime"
fill="var(--color-foldtime)"
@ -106,7 +51,5 @@ export function DayChart({
/>
</BarChart>
</ChartContainer>
</CardContent>
</Card>
);
}

@ -2,7 +2,6 @@
import { Bar, BarChart, CartesianGrid, XAxis } from "recharts";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import {
ChartConfig,
ChartContainer,
@ -22,56 +21,15 @@ const chartConfig = {
} satisfies ChartConfig;
export function HourChart({
data,
chartData,
}: {
data: {
timestamp: number;
chartData: {
hour: string;
value: number;
foldtime: number;
}[];
}) {
const todayTimestamp = new Date();
todayTimestamp.setHours(0, 0, 0, 0);
const tomorrowTimestamp = new Date();
tomorrowTimestamp.setHours(0, 0, 0, 0);
tomorrowTimestamp.setDate(tomorrowTimestamp.getDate() + 1);
console.log(todayTimestamp.getTime(), tomorrowTimestamp.getTime());
const todayData = data.filter(
(data) =>
data.timestamp >= todayTimestamp.getTime() &&
data.timestamp < tomorrowTimestamp.getTime()
);
const todayDataPerHour = todayData.reduce((acc, data) => {
const hour = new Date(data.timestamp).getHours();
if (!acc[hour]) {
acc[hour] = {
count: 1,
foldTime: data.foldtime,
};
}
acc[hour].count += 1;
acc[hour].foldTime += data.foldtime;
return acc;
}, {} as Record<number, { count: number; foldTime: number }>);
const chartData = new Array(24).fill(0).map((_, i) => {
if (!todayDataPerHour[i])
return { hour: i + 1 + ":00", value: 0, foldtime: 0 };
return {
hour: i + 1 + ":00",
value: todayDataPerHour[i].count,
foldtime: todayDataPerHour[i].foldTime / todayDataPerHour[i].count,
};
});
return (
<Card className="w-full max-w-[1200px]">
<CardHeader>
<CardTitle>Today</CardTitle>
{/* <CardDescription>January - June 2024</CardDescription> */}
</CardHeader>
<CardContent>
<ChartContainer config={chartConfig}>
<BarChart accessibilityLayer data={chartData}>
<CartesianGrid vertical={false} />
@ -85,11 +43,7 @@ export function HourChart({
cursor={false}
content={<ChartTooltipContent indicator="line" />}
/>
<Bar
dataKey="value"
fill="var(--color-value)"
radius={4}
/>
<Bar dataKey="value" fill="var(--color-value)" radius={4} />
<Bar
dataKey="foldtime"
fill="var(--color-foldtime)"
@ -97,7 +51,5 @@ export function HourChart({
/>
</BarChart>
</ChartContainer>
</CardContent>
</Card>
);
}

@ -2,7 +2,6 @@
import { Bar, BarChart, CartesianGrid, XAxis } from "recharts";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import {
ChartConfig,
ChartContainer,
@ -22,56 +21,15 @@ const chartConfig = {
} satisfies ChartConfig;
export function MinuteChart({
data,
chartData,
}: {
data: {
timestamp: number;
chartData: {
minute: string;
value: number;
foldtime: number;
}[];
}) {
const thisHourTimestamp = new Date();
thisHourTimestamp.setMinutes(0, 0, 0);
const nextHourTimestamp = new Date();
nextHourTimestamp.setHours(nextHourTimestamp.getHours() + 1);
nextHourTimestamp.setMinutes(0, 0, 0);
console.log(thisHourTimestamp.getTime(), nextHourTimestamp.getTime());
const todayData = data.filter(
(data) =>
data.timestamp >= thisHourTimestamp.getTime() &&
data.timestamp < nextHourTimestamp.getTime()
);
const todayDataPerHour = todayData.reduce((acc, data) => {
const hour = new Date(data.timestamp).getMinutes();
if (!acc[hour]) {
acc[hour] = {
count: 1,
foldTime: data.foldtime,
};
}
acc[hour].count += 1;
acc[hour].foldTime += data.foldtime;
return acc;
}, {} as Record<number, { count: number; foldTime: number }>);
const chartData = new Array(60).fill(0).map((_, i) => {
if (!todayDataPerHour[i])
return { minute: "Minute " + i, value: 0, foldtime: 0 };
return {
minute: "Minute " + i,
value: todayDataPerHour[i].count,
foldtime: todayDataPerHour[i].foldTime / todayDataPerHour[i].count,
};
});
return (
<Card className="w-full max-w-[1200px]">
<CardHeader>
<CardTitle>This Hour</CardTitle>
{/* <CardDescription>January - June 2024</CardDescription> */}
</CardHeader>
<CardContent>
<ChartContainer config={chartConfig}>
<BarChart accessibilityLayer data={chartData}>
<CartesianGrid vertical={false} />
@ -80,19 +38,13 @@ export function MinuteChart({
tickLine={false}
tickMargin={10}
axisLine={false}
tickFormatter={(value) =>
value.replace("Minute ", "")
}
tickFormatter={(value) => value.replace("Minute ", "")}
/>
<ChartTooltip
cursor={false}
content={<ChartTooltipContent indicator="line" />}
/>
<Bar
dataKey="value"
fill="var(--color-value)"
radius={4}
/>
<Bar dataKey="value" fill="var(--color-value)" radius={4} />
<Bar
dataKey="foldtime"
fill="var(--color-foldtime)"
@ -100,7 +52,5 @@ export function MinuteChart({
/>
</BarChart>
</ChartContainer>
</CardContent>
</Card>
);
}

@ -2,6 +2,15 @@ import fs from "node:fs";
import { HourChart } from "./(charts)/hour";
import { DayChart } from "./(charts)/day";
import { MinuteChart } from "./(charts)/minute";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import {
Card,
CardContent,
CardFooter,
CardHeader,
CardTitle,
} from "@/components/ui/card";
export default async function Home() {
const file = await fs.promises.readFile("./output.txt");
@ -9,20 +18,264 @@ export default async function Home() {
const lines = file.toString().split("\n");
const data = lines.map((line) => {
const [timestamp, event, value] = line.split(",");
const [timestamp, _, value] = line.split(",");
return {
timestamp: Math.round(parseFloat(timestamp) * 1000),
foldtime: parseFloat(value),
};
});
console.log(data);
const thisMonthData = convertDataToThisMonthPerDay(data);
const thisHourData = convertDataToThisHourPerMinute(data);
const todayData = convertDataToTodayPerHour(data);
return (
<main className="flex-grow w-full flex flex-col justify-center gap-4 items-center p-4">
<MinuteChart data={data} />
<HourChart data={data} />
<DayChart data={data} />
<div className="p-4 w-full bg-accent max-w-[1200px] rounded-xl flex justify-start gap-4">
<div className="flex flex-col gap-2 items-start p-4">
<span className="text-muted-foreground">This Month</span>
<h2 className="text-2xl font-bold">
{thisMonthData.reduce((acc, curr) => {
return acc + 1;
}, 0)}
{" Towel(s)"}
</h2>
<span className="text-muted-foreground">
Avg Fold Time (s):{" "}
{thisMonthData.reduce((acc, curr) => {
return acc + curr.foldtime;
}, 0) / thisMonthData.length || 0}
</span>
</div>
<div className="flex flex-col gap-2 items-start p-4">
<span className="text-muted-foreground">Today</span>
<h2 className="text-2xl font-bold">
{todayData.reduce((acc, curr) => {
return acc + 1;
}, 0)}
{" Towel(s)"}
</h2>
<span className="text-muted-foreground">
Avg Fold Time (s):{" "}
{todayData.reduce((acc, curr) => {
return acc + curr.foldtime;
}, 0) / todayData.length || 0}
</span>
</div>
<div className="flex flex-col gap-2 items-start p-4">
<span className="text-muted-foreground">This Month</span>
<h2 className="text-2xl font-bold">
{thisMonthData.reduce((acc, curr) => {
return acc + 1;
}, 0)}
{" Towel(s)"}
</h2>
<span className="text-muted-foreground">
Avg Fold Time (s):{" "}
{thisHourData.reduce((acc, curr) => {
return acc + curr.foldtime;
}, 0) / thisHourData.length || 0}
</span>
</div>
</div>
<Card className="w-full max-w-[1200px]">
<Tabs defaultValue="month" className="w-full">
<CardHeader>
<TabsList className="w-full">
<TabsTrigger className="w-full" value="month">
Month
</TabsTrigger>
<TabsTrigger className="w-full" value="day">
Day
</TabsTrigger>
<TabsTrigger className="w-full" value="hour">
Hour
</TabsTrigger>
</TabsList>
</CardHeader>
<CardContent>
<TabsContent value="month">
<DayChart
chartData={convertDataToThisMonthPerDayChartData(
thisMonthData
)}
/>
</TabsContent>
<TabsContent value="day">
<HourChart
chartData={convertDataToTodayPerHourChartData(
todayData
)}
/>
</TabsContent>
<TabsContent value="hour">
<MinuteChart
chartData={convertDataToThisHourPerMinuteChartData(
thisHourData
)}
/>
</TabsContent>
</CardContent>
<CardFooter></CardFooter>
</Tabs>
</Card>
</main>
);
}
const convertDataToThisMonthPerDay = (
data: { timestamp: number; foldtime: number }[]
) => {
const thisMonthTimestamp = new Date();
thisMonthTimestamp.setHours(0, 0, 0, 0);
thisMonthTimestamp.setDate(1);
const nextMonthTimestamp = new Date();
nextMonthTimestamp.setHours(0, 0, 0, 0);
nextMonthTimestamp.setDate(1);
nextMonthTimestamp.setMonth(nextMonthTimestamp.getMonth() + 1);
console.log(thisMonthTimestamp.getTime(), nextMonthTimestamp.getTime());
const thisMonthData = data.filter(
(data) =>
data.timestamp >= thisMonthTimestamp.getTime() &&
data.timestamp < nextMonthTimestamp.getTime()
);
return thisMonthData;
};
const convertDataToThisMonthPerDayChartData = (
data: { timestamp: number; foldtime: number }[]
) => {
const todayDataPerHour = data.reduce((acc, data) => {
const day = new Date(data.timestamp).getDate();
if (!acc[day]) {
acc[day] = {
count: 0,
foldTime: 0,
};
}
acc[day].count += 1;
acc[day].foldTime += data.foldtime;
return acc;
}, {} as Record<number, { count: number; foldTime: number }>);
const thisMonthDays = new Date();
thisMonthDays.setMonth(thisMonthDays.getMonth() + 1);
thisMonthDays.setDate(1);
thisMonthDays.setDate(thisMonthDays.getDate() - 1);
const chartData = new Array(thisMonthDays.getDate()).fill(0).map((_, i) => {
const day = i + 1;
if (!todayDataPerHour[day])
return { day: "Day " + day, value: 0, foldtime: 0 };
return {
day: "Day " + day,
value: todayDataPerHour[day].count,
foldtime:
todayDataPerHour[day].foldTime / todayDataPerHour[day].count,
};
});
return chartData;
};
const convertDataToThisHourPerMinute = (
data: { timestamp: number; foldtime: number }[]
) => {
const thisHourTimestamp = new Date();
thisHourTimestamp.setMinutes(0, 0, 0);
const nextHourTimestamp = new Date();
nextHourTimestamp.setHours(nextHourTimestamp.getHours() + 1);
nextHourTimestamp.setMinutes(0, 0, 0);
console.log(thisHourTimestamp.getTime(), nextHourTimestamp.getTime());
const todayData = data.filter(
(data) =>
data.timestamp >= thisHourTimestamp.getTime() &&
data.timestamp < nextHourTimestamp.getTime()
);
return todayData;
};
const convertDataToThisHourPerMinuteChartData = (
data: { timestamp: number; foldtime: number }[]
) => {
const todayDataPerHour = data.reduce((acc, data) => {
const hour = new Date(data.timestamp).getMinutes();
if (!acc[hour]) {
acc[hour] = {
count: 0,
foldTime: 0,
};
}
acc[hour].count += 1;
acc[hour].foldTime += data.foldtime;
return acc;
}, {} as Record<number, { count: number; foldTime: number }>);
const chartData = new Array(60).fill(0).map((_, i) => {
if (!todayDataPerHour[i])
return { minute: "Minute " + i, value: 0, foldtime: 0 };
return {
minute: "Minute " + i,
value: todayDataPerHour[i].count,
foldtime: todayDataPerHour[i].foldTime / todayDataPerHour[i].count,
};
});
return chartData;
};
const convertDataToTodayPerHour = (
data: { timestamp: number; foldtime: number }[]
) => {
const todayTimestamp = new Date();
todayTimestamp.setHours(0, 0, 0, 0);
const tomorrowTimestamp = new Date();
tomorrowTimestamp.setHours(0, 0, 0, 0);
tomorrowTimestamp.setDate(tomorrowTimestamp.getDate() + 1);
console.log(todayTimestamp.getTime(), tomorrowTimestamp.getTime());
const todayData = data.filter(
(data) =>
data.timestamp >= todayTimestamp.getTime() &&
data.timestamp < tomorrowTimestamp.getTime()
);
return todayData;
};
const convertDataToTodayPerHourChartData = (
data: { timestamp: number; foldtime: number }[]
) => {
const todayDataPerHour = data.reduce((acc, data) => {
const hour = new Date(data.timestamp).getHours();
if (!acc[hour]) {
acc[hour] = {
count: 0,
foldTime: 0,
};
}
acc[hour].count += 1;
acc[hour].foldTime += data.foldtime;
return acc;
}, {} as Record<number, { count: number; foldTime: number }>);
const chartData = new Array(24).fill(0).map((_, i) => {
if (!todayDataPerHour[i])
return { hour: i + 1 + ":00", value: 0, foldtime: 0 };
return {
hour: i + 1 + ":00",
value: todayDataPerHour[i].count,
foldtime: todayDataPerHour[i].foldTime / todayDataPerHour[i].count,
};
});
return chartData;
};

@ -0,0 +1,55 @@
"use client"
import * as React from "react"
import * as TabsPrimitive from "@radix-ui/react-tabs"
import { cn } from "@/lib/utils"
const Tabs = TabsPrimitive.Root
const TabsList = React.forwardRef<
React.ElementRef<typeof TabsPrimitive.List>,
React.ComponentPropsWithoutRef<typeof TabsPrimitive.List>
>(({ className, ...props }, ref) => (
<TabsPrimitive.List
ref={ref}
className={cn(
"inline-flex h-10 items-center justify-center rounded-md bg-muted p-1 text-muted-foreground",
className
)}
{...props}
/>
))
TabsList.displayName = TabsPrimitive.List.displayName
const TabsTrigger = React.forwardRef<
React.ElementRef<typeof TabsPrimitive.Trigger>,
React.ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger>
>(({ className, ...props }, ref) => (
<TabsPrimitive.Trigger
ref={ref}
className={cn(
"inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm",
className
)}
{...props}
/>
))
TabsTrigger.displayName = TabsPrimitive.Trigger.displayName
const TabsContent = React.forwardRef<
React.ElementRef<typeof TabsPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof TabsPrimitive.Content>
>(({ className, ...props }, ref) => (
<TabsPrimitive.Content
ref={ref}
className={cn(
"mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
className
)}
{...props}
/>
))
TabsContent.displayName = TabsPrimitive.Content.displayName
export { Tabs, TabsList, TabsTrigger, TabsContent }

119
package-lock.json generated

@ -9,6 +9,7 @@
"version": "0.1.0",
"dependencies": {
"@radix-ui/react-scroll-area": "^1.2.2",
"@radix-ui/react-tabs": "^1.1.2",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"lucide-react": "^0.469.0",
@ -439,6 +440,31 @@
"resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.1.tgz",
"integrity": "sha512-SJ31y+Q/zAyShtXJc8x83i9TYdbAfHZ++tUZnvjJJqFjzsdUnKsxPL6IEtBlxKkU7yzer//GQtZSV4GbldL3YA=="
},
"node_modules/@radix-ui/react-collection": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.1.tgz",
"integrity": "sha512-LwT3pSho9Dljg+wY2KN2mrrh6y3qELfftINERIzBUO9e0N+t0oMTyn3k9iv+ZqgrwGkRnLpNJrsMv9BZlt2yuA==",
"dependencies": {
"@radix-ui/react-compose-refs": "1.1.1",
"@radix-ui/react-context": "1.1.1",
"@radix-ui/react-primitive": "2.0.1",
"@radix-ui/react-slot": "1.1.1"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-compose-refs": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.1.tgz",
@ -481,6 +507,23 @@
}
}
},
"node_modules/@radix-ui/react-id": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.0.tgz",
"integrity": "sha512-EJUrI8yYh7WOjNOqpoJaf1jlFIH2LvtgAl+YcFqNCa+4hj64ZXmPkAKOFs/ukjz3byN6bdb/AVUqHkI8/uWWMA==",
"dependencies": {
"@radix-ui/react-use-layout-effect": "1.1.0"
},
"peerDependencies": {
"@types/react": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-presence": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.2.tgz",
@ -526,6 +569,36 @@
}
}
},
"node_modules/@radix-ui/react-roving-focus": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.1.tgz",
"integrity": "sha512-QE1RoxPGJ/Nm8Qmk0PxP8ojmoaS67i0s7hVssS7KuI2FQoc/uzVlZsqKfQvxPE6D8hICCPHJ4D88zNhT3OOmkw==",
"dependencies": {
"@radix-ui/primitive": "1.1.1",
"@radix-ui/react-collection": "1.1.1",
"@radix-ui/react-compose-refs": "1.1.1",
"@radix-ui/react-context": "1.1.1",
"@radix-ui/react-direction": "1.1.0",
"@radix-ui/react-id": "1.1.0",
"@radix-ui/react-primitive": "2.0.1",
"@radix-ui/react-use-callback-ref": "1.1.0",
"@radix-ui/react-use-controllable-state": "1.1.0"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-scroll-area": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/@radix-ui/react-scroll-area/-/react-scroll-area-1.2.2.tgz",
@ -573,6 +646,35 @@
}
}
},
"node_modules/@radix-ui/react-tabs": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.1.2.tgz",
"integrity": "sha512-9u/tQJMcC2aGq7KXpGivMm1mgq7oRJKXphDwdypPd/j21j/2znamPU8WkXgnhUaTrSFNIt8XhOyCAupg8/GbwQ==",
"dependencies": {
"@radix-ui/primitive": "1.1.1",
"@radix-ui/react-context": "1.1.1",
"@radix-ui/react-direction": "1.1.0",
"@radix-ui/react-id": "1.1.0",
"@radix-ui/react-presence": "1.1.2",
"@radix-ui/react-primitive": "2.0.1",
"@radix-ui/react-roving-focus": "1.1.1",
"@radix-ui/react-use-controllable-state": "1.1.0"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-use-callback-ref": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.0.tgz",
@ -587,6 +689,23 @@
}
}
},
"node_modules/@radix-ui/react-use-controllable-state": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.1.0.tgz",
"integrity": "sha512-MtfMVJiSr2NjzS0Aa90NPTnvTSg6C/JLCV7ma0W6+OMV78vd8OyRpID+Ng9LxzsPbLeuBnWBA1Nq30AtBIDChw==",
"dependencies": {
"@radix-ui/react-use-callback-ref": "1.1.0"
},
"peerDependencies": {
"@types/react": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-use-layout-effect": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.0.tgz",

@ -10,6 +10,7 @@
},
"dependencies": {
"@radix-ui/react-scroll-area": "^1.2.2",
"@radix-ui/react-tabs": "^1.1.2",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"lucide-react": "^0.469.0",

Loading…
Cancel
Save