feat: add menus (repas)
All checks were successful
Deploy to Netlify / Deploy to Netlify (push) Successful in 1m54s
All checks were successful
Deploy to Netlify / Deploy to Netlify (push) Successful in 1m54s
This commit is contained in:
parent
b42236e730
commit
052e59f1ac
12 changed files with 387 additions and 48 deletions
|
|
@ -27,6 +27,7 @@ import TabContent from "~/components/home/tab-content";
|
||||||
import { MainLayout } from "~/layout";
|
import { MainLayout } from "~/layout";
|
||||||
import { forceReload } from "~/lib/utils";
|
import { forceReload } from "~/lib/utils";
|
||||||
import { SyncButton } from "../sync-status";
|
import { SyncButton } from "../sync-status";
|
||||||
|
import WeekNavigation from "./week-navigation";
|
||||||
|
|
||||||
export default function Home({ user }: { user: User }) {
|
export default function Home({ user }: { user: User }) {
|
||||||
// Handle query parameters
|
// Handle query parameters
|
||||||
|
|
@ -54,16 +55,6 @@ export default function Home({ user }: { user: User }) {
|
||||||
const setStartDate = (date: DateTime) =>
|
const setStartDate = (date: DateTime) =>
|
||||||
updateQuery("start", date.startOf("week").toISODate()!);
|
updateQuery("start", date.startOf("week").toISODate()!);
|
||||||
|
|
||||||
const handlePreviousWeek = () => {
|
|
||||||
const previousWeek = startDate.minus({ weeks: 1 });
|
|
||||||
setStartDate(previousWeek);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleNextWeek = () => {
|
|
||||||
const nextWeek = startDate.plus({ weeks: 1 });
|
|
||||||
setStartDate(nextWeek);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Fetch colles from API
|
// Fetch colles from API
|
||||||
const {
|
const {
|
||||||
studentColles,
|
studentColles,
|
||||||
|
|
@ -188,22 +179,7 @@ export default function Home({ user }: { user: User }) {
|
||||||
</Tabs>
|
</Tabs>
|
||||||
|
|
||||||
{/* Week Navigation */}
|
{/* Week Navigation */}
|
||||||
<div className="mb-0">
|
<WeekNavigation startDate={startDate} setStartDate={setStartDate} />
|
||||||
<div className="flex flex-row items-center justify-between gap-2">
|
|
||||||
<Button variant="outline" size="sm" onClick={handlePreviousWeek}>
|
|
||||||
<ChevronLeft className="h-10 w-10" />
|
|
||||||
</Button>
|
|
||||||
<div className="flex-1">
|
|
||||||
<DatePickerWithRange
|
|
||||||
startDate={startDate}
|
|
||||||
setStartDate={setStartDate}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<Button variant="outline" size="sm" onClick={handleNextWeek}>
|
|
||||||
<ChevronRight className="h-10 w-10" />
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Filter component */}
|
{/* Filter component */}
|
||||||
<div className="flex gap-2 pb-0 pt-2">
|
<div className="flex gap-2 pb-0 pt-2">
|
||||||
|
|
|
||||||
41
app/components/home/week-navigation.tsx
Normal file
41
app/components/home/week-navigation.tsx
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
import { ChevronLeft, ChevronRight } from "lucide-react";
|
||||||
|
import { Button } from "../ui/button";
|
||||||
|
import DatePickerWithRange from "./date-picker";
|
||||||
|
import type { DateTime } from "luxon";
|
||||||
|
|
||||||
|
export default function WeekNavigation({
|
||||||
|
startDate,
|
||||||
|
setStartDate,
|
||||||
|
}: {
|
||||||
|
startDate: DateTime;
|
||||||
|
setStartDate: (date: DateTime) => void;
|
||||||
|
}) {
|
||||||
|
const handlePreviousWeek = () => {
|
||||||
|
const previousWeek = startDate.minus({ weeks: 1 });
|
||||||
|
setStartDate(previousWeek);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleNextWeek = () => {
|
||||||
|
const nextWeek = startDate.plus({ weeks: 1 });
|
||||||
|
setStartDate(nextWeek);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="mb-0">
|
||||||
|
<div className="flex flex-row items-center justify-between gap-2">
|
||||||
|
<Button variant="outline" size="sm" onClick={handlePreviousWeek}>
|
||||||
|
<ChevronLeft className="h-10 w-10" />
|
||||||
|
</Button>
|
||||||
|
<div className="flex-1">
|
||||||
|
<DatePickerWithRange
|
||||||
|
startDate={startDate}
|
||||||
|
setStartDate={setStartDate}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<Button variant="outline" size="sm" onClick={handleNextWeek}>
|
||||||
|
<ChevronRight className="h-10 w-10" />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
67
app/components/repas/date-picker.tsx
Normal file
67
app/components/repas/date-picker.tsx
Normal file
|
|
@ -0,0 +1,67 @@
|
||||||
|
import { DateTime } from "luxon";
|
||||||
|
import { CalendarIcon } from "lucide-react";
|
||||||
|
import { fr } from "date-fns/locale";
|
||||||
|
import { Calendar } from "~/components/ui/calendar";
|
||||||
|
import {
|
||||||
|
Popover,
|
||||||
|
PopoverContent,
|
||||||
|
PopoverTrigger,
|
||||||
|
} from "~/components/ui/popover";
|
||||||
|
import { cn } from "~/lib/utils";
|
||||||
|
|
||||||
|
export default function DatePickerWithRange({
|
||||||
|
className,
|
||||||
|
startDate,
|
||||||
|
setStartDate,
|
||||||
|
}: {
|
||||||
|
className?: string;
|
||||||
|
startDate: DateTime;
|
||||||
|
setStartDate: (date: DateTime) => void;
|
||||||
|
}) {
|
||||||
|
function handleDateSelect(selectedDate?: Date) {
|
||||||
|
if (selectedDate) {
|
||||||
|
setStartDate(DateTime.fromJSDate(selectedDate));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={cn("grid gap-2 w-full", className)}>
|
||||||
|
<Popover>
|
||||||
|
<PopoverTrigger asChild>
|
||||||
|
<button
|
||||||
|
id="date"
|
||||||
|
className={
|
||||||
|
"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 h-9 px-4 py-2 has-[>svg]:px-3 border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:border-input dark:hover:bg-input/50 " +
|
||||||
|
cn(
|
||||||
|
"w-full justify-start text-left font-normal",
|
||||||
|
!startDate && "text-muted-foreground"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<CalendarIcon className="mr-2 h-4 w-4" />
|
||||||
|
Menu du {formatDate(startDate, true)}
|
||||||
|
</button>
|
||||||
|
</PopoverTrigger>
|
||||||
|
<PopoverContent className="w-auto p-0" align="start">
|
||||||
|
<Calendar
|
||||||
|
mode="single"
|
||||||
|
selected={startDate.toJSDate()}
|
||||||
|
defaultMonth={startDate.startOf("month").toJSDate()}
|
||||||
|
onSelect={handleDateSelect}
|
||||||
|
weekStartsOn={1}
|
||||||
|
locale={fr}
|
||||||
|
className="rounded-md border shadow-sm"
|
||||||
|
captionLayout="dropdown"
|
||||||
|
/>
|
||||||
|
</PopoverContent>
|
||||||
|
</Popover>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const formatDate = (date: DateTime, includeYear = false) => {
|
||||||
|
const localDate = date.setLocale("fr");
|
||||||
|
return includeYear
|
||||||
|
? localDate.toFormat("dd MMM yyyy")
|
||||||
|
: localDate.toFormat("dd MMM");
|
||||||
|
};
|
||||||
41
app/components/repas/day-navigation.tsx
Normal file
41
app/components/repas/day-navigation.tsx
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
import { ChevronLeft, ChevronRight } from "lucide-react";
|
||||||
|
import { Button } from "../ui/button";
|
||||||
|
import type { DateTime } from "luxon";
|
||||||
|
import DatePickerWithRange from "./date-picker";
|
||||||
|
|
||||||
|
export default function DayNavigation({
|
||||||
|
startDate,
|
||||||
|
setStartDate,
|
||||||
|
}: {
|
||||||
|
startDate: DateTime;
|
||||||
|
setStartDate: (date: DateTime) => void;
|
||||||
|
}) {
|
||||||
|
const handlePreviousDay = () => {
|
||||||
|
const previousDay = startDate.minus({ days: 1 });
|
||||||
|
setStartDate(previousDay);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleNextDay = () => {
|
||||||
|
const nextDay = startDate.plus({ days: 1 });
|
||||||
|
setStartDate(nextDay);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="mb-2">
|
||||||
|
<div className="flex flex-row items-center justify-between gap-2">
|
||||||
|
<Button variant="outline" size="sm" onClick={handlePreviousDay}>
|
||||||
|
<ChevronLeft className="h-10 w-10" />
|
||||||
|
</Button>
|
||||||
|
<div className="flex-1">
|
||||||
|
<DatePickerWithRange
|
||||||
|
startDate={startDate}
|
||||||
|
setStartDate={setStartDate}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<Button variant="outline" size="sm" onClick={handleNextDay}>
|
||||||
|
<ChevronRight className="h-10 w-10" />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
67
app/components/repas/index.tsx
Normal file
67
app/components/repas/index.tsx
Normal file
|
|
@ -0,0 +1,67 @@
|
||||||
|
import { useState } from "react";
|
||||||
|
import { Tabs, TabsList, tabsStyle, TabsTrigger } from "~/components/ui/tabs";
|
||||||
|
import BottomNavigation from "~/components/bottom-nav";
|
||||||
|
import { CalendarCheck, ChefHat } from "lucide-react";
|
||||||
|
import WIP from "./wip";
|
||||||
|
import Menus from "./menus";
|
||||||
|
|
||||||
|
const tabs = [
|
||||||
|
{
|
||||||
|
value: "menu",
|
||||||
|
label: "Menus",
|
||||||
|
icon: <ChefHat className="h-4 w-4" />,
|
||||||
|
content: <Menus />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: "bjrepas",
|
||||||
|
label: "BJ Repas",
|
||||||
|
icon: <CalendarCheck className="h-4 w-4" />,
|
||||||
|
content: <WIP />,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export default function RepasPage() {
|
||||||
|
// user / notifications / preferences tabs
|
||||||
|
const [activeTab, setActiveTab] = useState(tabs[0].value);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="space-y-6 pb-20 md:pb-0">
|
||||||
|
{/* Tabs */}
|
||||||
|
<Tabs
|
||||||
|
defaultValue={tabs[0].value}
|
||||||
|
value={activeTab}
|
||||||
|
onValueChange={setActiveTab}
|
||||||
|
className="max-w-md w-full"
|
||||||
|
>
|
||||||
|
<TabsList className="w-full p-0 bg-background justify-start border-b rounded-none">
|
||||||
|
{tabs.map((tab) => (
|
||||||
|
<TabsTrigger
|
||||||
|
key={tab.value}
|
||||||
|
value={tab.value}
|
||||||
|
className={tabsStyle}
|
||||||
|
>
|
||||||
|
{tab.icon}
|
||||||
|
{tab.label}
|
||||||
|
</TabsTrigger>
|
||||||
|
))}
|
||||||
|
</TabsList>
|
||||||
|
</Tabs>
|
||||||
|
|
||||||
|
{/* Tab Content */}
|
||||||
|
<div className="pt-2">
|
||||||
|
{tabs.map((tab) => (
|
||||||
|
<div
|
||||||
|
key={tab.value}
|
||||||
|
className={`${
|
||||||
|
activeTab === tab.value ? "block" : "hidden"
|
||||||
|
} transition-all duration-300`}
|
||||||
|
>
|
||||||
|
{tab.content}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<BottomNavigation activeId="repas" />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
81
app/components/repas/menu-card.tsx
Normal file
81
app/components/repas/menu-card.tsx
Normal file
|
|
@ -0,0 +1,81 @@
|
||||||
|
import { Card, CardContent, CardHeader, CardTitle } from "~/components/ui/card";
|
||||||
|
import { Utensils, Salad, Cake, CookingPot, Icon, Carrot } from "lucide-react";
|
||||||
|
import { cheese } from "@lucide/lab";
|
||||||
|
|
||||||
|
interface Course {
|
||||||
|
name: string;
|
||||||
|
description: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Meal {
|
||||||
|
name: string;
|
||||||
|
courses: Course[];
|
||||||
|
}
|
||||||
|
|
||||||
|
const getCourseIcon = (courseName: string) => {
|
||||||
|
const name = courseName.toLowerCase();
|
||||||
|
if (name.includes("hors")) return <Salad className="h-6 w-6" />;
|
||||||
|
if (name.includes("plat")) return <CookingPot className="h-6 w-6" />;
|
||||||
|
if (name.includes("garniture")) return <Carrot className="h-6 w-6" />;
|
||||||
|
if (name.includes("fromage"))
|
||||||
|
return <Icon iconNode={cheese} className="h-6 w-6" />;
|
||||||
|
if (name.includes("dessert")) return <Cake className="h-6 w-6" />;
|
||||||
|
return <Utensils className="h-6 w-6" />;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function DailyMenu({ meals }: { meals: Meal[] }) {
|
||||||
|
if (meals.length === 0) {
|
||||||
|
return (
|
||||||
|
<div className="flex items-center justify-center p-4">
|
||||||
|
<p className="text-muted-foreground">
|
||||||
|
Aucun menu disponible pour ce jour.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="px-4 py-2">
|
||||||
|
<h2 className="text-2xl font-bold mb-4">
|
||||||
|
{meals.length > 1 ? "Menus" : "Menu"} du jour
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
{meals.map((meal, mealIndex) => (
|
||||||
|
<Card key={mealIndex} className="w-full mb-6">
|
||||||
|
<CardHeader className="pb-6">
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<div className="flex items-center gap-3">
|
||||||
|
<div>
|
||||||
|
<CardTitle className="text-xl2 font-bold text-foreground capitalize">
|
||||||
|
<Utensils className="inline h-5 w-5 mr-4 text-primary" />
|
||||||
|
{meal.name}
|
||||||
|
</CardTitle>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</CardHeader>
|
||||||
|
|
||||||
|
<CardContent className="pt-0 pb-4">
|
||||||
|
<div className="space-y-4">
|
||||||
|
{meal.courses.map((course, courseIndex) => (
|
||||||
|
<div key={courseIndex} className="flex items-start gap-3">
|
||||||
|
<div className="p-2 rounded-full bg-primary/10">
|
||||||
|
{getCourseIcon(course.name)}
|
||||||
|
</div>
|
||||||
|
<div className="flex-1 min-w-0">
|
||||||
|
<h4 className="text-sm font-semibold text-primary mb-1">
|
||||||
|
{course.name}
|
||||||
|
</h4>
|
||||||
|
<p className="text-sm text-muted-foreground leading-relaxed">
|
||||||
|
{course.description}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
31
app/components/repas/menus.tsx
Normal file
31
app/components/repas/menus.tsx
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
import { useMenus } from "~/lib/api";
|
||||||
|
import { DailyMenu } from "./menu-card";
|
||||||
|
import { DateTime } from "luxon";
|
||||||
|
import { useState } from "react";
|
||||||
|
import DayNavigation from "./day-navigation";
|
||||||
|
|
||||||
|
export default function Menus() {
|
||||||
|
const { isLoading, error, menus } = useMenus();
|
||||||
|
const [date, setDate] = useState(DateTime.now().startOf("day"));
|
||||||
|
|
||||||
|
const findMenuForDate = (date: DateTime) => {
|
||||||
|
return menus?.find((menu: any) => {
|
||||||
|
const menuDate = DateTime.fromISO(menu.date).startOf("day");
|
||||||
|
return menuDate.equals(date);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="space-y-4">
|
||||||
|
{isLoading && <p>Chargement des menus...</p>}
|
||||||
|
{error && (
|
||||||
|
<p className="text-red-500">Erreur lors du chargement des menus.</p>
|
||||||
|
)}
|
||||||
|
{menus && menus.length === 0 && <p>Aucun menu disponible.</p>}
|
||||||
|
|
||||||
|
{/* Menus */}
|
||||||
|
<DayNavigation startDate={date} setStartDate={setDate} />
|
||||||
|
<DailyMenu meals={findMenuForDate(date)?.meals || []} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
23
app/components/repas/wip.tsx
Normal file
23
app/components/repas/wip.tsx
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
import { Github } from "lucide-react";
|
||||||
|
import { Button } from "../ui/button";
|
||||||
|
|
||||||
|
export default function WIP() {
|
||||||
|
return (
|
||||||
|
<div className="text-center mt-10">
|
||||||
|
<h2 className="text-xl font-semibold">
|
||||||
|
⚠️ Cette fonctionnalité n’est pas encore implémentée.
|
||||||
|
</h2>
|
||||||
|
<p className="mt-4">
|
||||||
|
Vous pouvez contribuer au développement du projet ici :
|
||||||
|
</p>
|
||||||
|
<Button
|
||||||
|
className="mt-4"
|
||||||
|
variant="default"
|
||||||
|
onClick={() => window.open(import.meta.env.VITE_GITHUB_URL, "_blank")}
|
||||||
|
>
|
||||||
|
<Github />
|
||||||
|
Contribuer sur GitHub
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -457,3 +457,26 @@ export const useAverages = (period: string) => {
|
||||||
...props,
|
...props,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* === REPAS API ===
|
||||||
|
*/
|
||||||
|
const fetchMenus = async () => {
|
||||||
|
return makeRequest(`/menus`, "Échec de la récupération des menus");
|
||||||
|
};
|
||||||
|
export const useMenus = () => {
|
||||||
|
const { data, ...props } = useQuery({
|
||||||
|
queryKey: ["menus"],
|
||||||
|
queryFn: fetchMenus,
|
||||||
|
staleTime: Duration.fromObject({
|
||||||
|
hours: 6, // 6 hours
|
||||||
|
}).toMillis(),
|
||||||
|
gcTime: Duration.fromObject({
|
||||||
|
days: 1, // 1 day
|
||||||
|
}).toMillis(),
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
menus: data || [],
|
||||||
|
...props,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,7 @@ import Loader from "~/components/loader";
|
||||||
import { MainLayout } from "~/layout";
|
import { MainLayout } from "~/layout";
|
||||||
import { AUTH_ERROR, useUser } from "~/lib/api";
|
import { AUTH_ERROR, useUser } from "~/lib/api";
|
||||||
import { forceReload } from "~/lib/utils";
|
import { forceReload } from "~/lib/utils";
|
||||||
import { Button } from "~/components/ui/button";
|
import RepasPage from "~/components/repas";
|
||||||
import { Github } from "lucide-react";
|
|
||||||
import BottomNavigation from "~/components/bottom-nav";
|
|
||||||
|
|
||||||
export default function Repas() {
|
export default function Repas() {
|
||||||
const { user, isLoading, error } = useUser();
|
const { user, isLoading, error } = useUser();
|
||||||
|
|
@ -29,25 +27,7 @@ export default function Repas() {
|
||||||
</h1>
|
</h1>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{/* Under construction message */}
|
<RepasPage />
|
||||||
<div className="text-center mt-10">
|
|
||||||
<h2 className="text-xl font-semibold">
|
|
||||||
⚠️ Cette fonctionnalité n’est pas encore implémentée.
|
|
||||||
</h2>
|
|
||||||
<p className="mt-4">
|
|
||||||
Vous pouvez contribuer au développement du projet ici :
|
|
||||||
</p>
|
|
||||||
<Button
|
|
||||||
className="mt-4"
|
|
||||||
variant="default"
|
|
||||||
onClick={() => window.open(import.meta.env.VITE_GITHUB_URL, "_blank")}
|
|
||||||
>
|
|
||||||
<Github />
|
|
||||||
Contribuer sur GitHub
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<BottomNavigation activeId="repas" />
|
|
||||||
</MainLayout>
|
</MainLayout>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@
|
||||||
"deploy": "netlify deploy --prod --dir=./build/client --message=\"Deploy to Netlify from Forgejo\" --site=$NETLIFY_SITE_ID --auth=$NETLIFY_AUTH_TOKEN --no-build"
|
"deploy": "netlify deploy --prod --dir=./build/client --message=\"Deploy to Netlify from Forgejo\" --site=$NETLIFY_SITE_ID --auth=$NETLIFY_AUTH_TOKEN --no-build"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@lucide/lab": "^0.1.2",
|
||||||
"@marsidev/react-turnstile": "^1.1.0",
|
"@marsidev/react-turnstile": "^1.1.0",
|
||||||
"@radix-ui/react-accordion": "^1.2.12",
|
"@radix-ui/react-accordion": "^1.2.12",
|
||||||
"@radix-ui/react-avatar": "^1.1.10",
|
"@radix-ui/react-avatar": "^1.1.10",
|
||||||
|
|
|
||||||
8
pnpm-lock.yaml
generated
8
pnpm-lock.yaml
generated
|
|
@ -8,6 +8,9 @@ importers:
|
||||||
|
|
||||||
.:
|
.:
|
||||||
dependencies:
|
dependencies:
|
||||||
|
'@lucide/lab':
|
||||||
|
specifier: ^0.1.2
|
||||||
|
version: 0.1.2
|
||||||
'@marsidev/react-turnstile':
|
'@marsidev/react-turnstile':
|
||||||
specifier: ^1.1.0
|
specifier: ^1.1.0
|
||||||
version: 1.1.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
|
version: 1.1.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
|
||||||
|
|
@ -1255,6 +1258,9 @@ packages:
|
||||||
'@jridgewell/trace-mapping@0.3.9':
|
'@jridgewell/trace-mapping@0.3.9':
|
||||||
resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==}
|
resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==}
|
||||||
|
|
||||||
|
'@lucide/lab@0.1.2':
|
||||||
|
resolution: {integrity: sha512-VprF2BJa7ZuTGOhUd5cf8tHJXyL63wdxcGieAiVVoR9hO0YmPsnZO0AGqDiX2/br+/MC6n8BoJcmPilltOXIJA==}
|
||||||
|
|
||||||
'@lukeed/ms@2.0.2':
|
'@lukeed/ms@2.0.2':
|
||||||
resolution: {integrity: sha512-9I2Zn6+NJLfaGoz9jN3lpwDgAYvfGeNYdbAIjJOqzs4Tpc+VU3Jqq4IofSUBKajiDS8k9fZIg18/z13mpk1bsA==}
|
resolution: {integrity: sha512-9I2Zn6+NJLfaGoz9jN3lpwDgAYvfGeNYdbAIjJOqzs4Tpc+VU3Jqq4IofSUBKajiDS8k9fZIg18/z13mpk1bsA==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
|
@ -7804,6 +7810,8 @@ snapshots:
|
||||||
'@jridgewell/resolve-uri': 3.1.2
|
'@jridgewell/resolve-uri': 3.1.2
|
||||||
'@jridgewell/sourcemap-codec': 1.5.4
|
'@jridgewell/sourcemap-codec': 1.5.4
|
||||||
|
|
||||||
|
'@lucide/lab@0.1.2': {}
|
||||||
|
|
||||||
'@lukeed/ms@2.0.2': {}
|
'@lukeed/ms@2.0.2': {}
|
||||||
|
|
||||||
'@mapbox/node-pre-gyp@2.0.0(supports-color@10.0.0)':
|
'@mapbox/node-pre-gyp@2.0.0(supports-color@10.0.0)':
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue