home page

This commit is contained in:
cdricms
2025-01-13 11:08:33 +01:00
parent a26516c6e8
commit 7813e42e3a
13 changed files with 1197 additions and 70 deletions

View File

@@ -1,6 +1,7 @@
import type { Metadata } from "next";
import { Geist, Geist_Mono } from "next/font/google";
import "./globals.css";
import Navbar from "@/components/nav-bar";
const geistSans = Geist({
variable: "--font-geist-sans",
@@ -27,6 +28,7 @@ export default function RootLayout({
<body
className={`${geistSans.variable} ${geistMono.variable} antialiased`}
>
<Navbar />
{children}
</body>
</html>

View File

@@ -1,69 +1,109 @@
import { Button } from "@/components/ui/button";
import {
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
import Image from "next/image";
import Features, { FeatureItem } from "@/components/features";
import Hero from "@/components/hero";
export default function Home() {
return (
<Card className="w-[350px]">
<CardHeader>
<CardTitle>Create project</CardTitle>
<CardDescription>
Deploy your new project in one-click.
</CardDescription>
</CardHeader>
<CardContent>
<form>
<div className="grid w-full items-center gap-4">
<div className="flex flex-col space-y-1.5">
<Label htmlFor="name">Name</Label>
<Input
id="name"
placeholder="Name of your project"
/>
</div>
<div className="flex flex-col space-y-1.5">
<Label htmlFor="framework">Framework</Label>
<Select>
<SelectTrigger id="framework">
<SelectValue placeholder="Select" />
</SelectTrigger>
<SelectContent position="popper">
<SelectItem value="next">
Next.js
</SelectItem>
<SelectItem value="sveltekit">
SvelteKit
</SelectItem>
<SelectItem value="astro">Astro</SelectItem>
<SelectItem value="nuxt">
Nuxt.js
</SelectItem>
</SelectContent>
</Select>
</div>
</div>
</form>
</CardContent>
<CardFooter className="flex justify-between">
<Button variant="outline">Cancel</Button>
<Button>Deploy</Button>
</CardFooter>
</Card>
<main>
<Hero />
<Features
title="DÉVELOPPEMENT DU SYSTÈME"
description="Latosa Escrima Concepts est un système martial dynamique et en constante évolution. Ce système repose sur une approche logique, qui progresse au fil du développement des compétences techniques des pratiquants."
cta="Envie de découvrir Latosa Escrima ?"
>
<FeatureItem
title="Les Fondements de Latosa Escrima Concepts"
position="left"
image="https://shadcnblocks.com/images/block/placeholder-2.svg"
>
<ol className="list-decimal text-justify flex flex-col gap-4">
<li>
Un Système Centré sur les Concepts{" "}
<ul className="list-disc list-inside">
<li>
Étude et application des meilleurs concepts
et stratégies issus de différentes approches
martiales.
</li>
<li>
Comprendre ce que lon fait, comment on le
fait et pourquoi on le fait.
</li>
</ul>
</li>
<li>
Éducation au Mouvement et à lEfficacité
<ul className="list-disc list-inside">
<li>
Plus quun enchaînement de techniques : une
véritable éducation aux mouvements corporels
et à lefficacité des armes.
</li>
<li>
Priorité à lauthenticité et à la réalité.
</li>
</ul>
</li>
</ol>
</FeatureItem>
<FeatureItem
title="LÉvolution du Système"
position="right"
image="https://shadcnblocks.com/images/block/placeholder-2.svg"
>
<ol className="list-none text-justify flex flex-col gap-4">
<li>
<span className="font-bold">
Les Premières Étapes
</span>
<ul className="list-disc list-inside">
<li>
Initialement centré sur les techniques et
mouvements, le système sest montré efficace
mais incomplet.
</li>
<li>
Recherche de ce qui différencie les arts
martiaux philippins des autres disciplines.
</li>
</ul>
</li>
<li>
<span className="font-bold">
La Découverte des Concepts Clés
</span>{" "}
<ul className="list-disc list-inside">
<li>
Rôle central des concepts de combat :
<ul className="list-disc list-inside pl-4">
<li>Puissance dans les frappes.</li>
<li>Blocage ferme.</li>
<li>Équilibre et attitude.</li>
</ul>
</li>
<li>
Restructuration des exercices pour intégrer
et transmettre ces concepts fondamentaux.
</li>
</ul>
</li>
</ol>
</FeatureItem>
<FeatureItem
title="Les Principes du Système Aujourdhui"
position="left"
image="https://shadcnblocks.com/images/block/placeholder-2.svg"
>
Latosa Escrima Concepts repose sur cinq concepts
fondamentaux :
<ul className="list-disc list-inside">
<li>Équilibre</li>
<li>Vitesse (Timing et Distance)</li>
<li>Puissance</li>
<li>Concentration</li>
<li>Transition</li>
</ul>
</FeatureItem>
</Features>
</main>
);
}

View File

@@ -0,0 +1,79 @@
import { ArrowRight } from "lucide-react";
const Features: React.FC<
React.PropsWithChildren<{
title: string;
description: string;
cta: string;
}>
> = ({ title, description, cta, children }) => {
return (
<section className="py-32 px-4">
<div className="container flex flex-col gap-16 lg:px-16">
<div className="lg:max-w-sm">
<h2 className="mb-3 text-xl font-semibold md:mb-4 md:text-4xl lg:mb-6">
{title}
</h2>
<p className="mb-8 text-muted-foreground lg:text-lg">
{description}
</p>
<a
href="#"
className="group flex items-center text-xs font-medium md:text-base lg:text-lg"
>
{cta}
<ArrowRight className="ml-2 size-4 transition-transform group-hover:translate-x-1" />
</a>
</div>
<div className="grid gap-6 md:grid-cols-2 lg:gap-8">
{children}
</div>
</div>
</section>
);
};
export default Features;
export const FeatureItem: React.FC<
React.PropsWithChildren<{
title: string;
image: string;
position: "left" | "right";
}>
> = ({ title, children, image, position }) => {
const _image = () => (
<div className="md:min-h-[24rem] lg:min-h-[28rem] xl:min-h-[32rem]">
<img
src={image}
alt={title}
className="aspect-[16/9] h-full w-full object-cover object-center"
/>
</div>
);
const _content = () => (
<div className="flex flex-col justify-center px-6 py-8 md:px-8 md:py-10 lg:px-10 lg:py-12">
<h3 className="mb-3 text-lg font-semibold md:mb-4 md:text-2xl lg:mb-6">
{title}
</h3>
<div className="text-muted-foreground lg:text-lg">{children}</div>
</div>
);
return (
<div
className={`flex ${position === "left" ? "flex-col" : "flex-col-reverse"} overflow-clip rounded-xl border border-border md:col-span-2 md:grid md:grid-cols-2 md:gap-6 lg:gap-8`}
>
{position === "left" ? (
<>
<_image />
<_content />
</>
) : (
<>
<_content />
<_image />
</>
)}
</div>
);
};

View File

@@ -0,0 +1,46 @@
import { ExternalLink } from "lucide-react";
import { cn } from "@/lib/utils";
import { Badge } from "@/components/ui/badge";
import { Button, buttonVariants } from "@/components/ui/button";
const Hero = () => {
return (
<section
style={{ height: "calc(100vh - 68px)" }}
className="flex justify-center items-center relative overflow-hidden py-32"
>
<div className="">
<div className="bg-blue-50 magicpattern absolute inset-x-0 top-0 -z-10 flex h-full w-full items-center justify-center opacity-100" />
<div className="mx-auto flex max-w-5xl flex-col items-center">
<div className="z-10 flex flex-col items-center gap-6 text-center">
<img
src="https://shadcnblocks.com/images/block/block-1.svg"
alt="logo"
className="h-16"
/>
<Badge variant="outline">Latosa-Escrima</Badge>
<div>
<h1 className="mb-6 text-pretty text-2xl font-bold lg:text-5xl">
Trouvez votre équilibre avec Latosa-Escrima
</h1>
<p className="text-muted-foreground lg:text-xl">
Une évolution des arts martiaux Philippins
</p>
</div>
<div className="mt-4 flex justify-center gap-2">
<Button>Nous contacter</Button>
<Button variant="outline">
À propos
<ExternalLink className="ml-2 h-4" />
</Button>
</div>
</div>
</div>
</div>
</section>
);
};
export default Hero;

View File

@@ -0,0 +1,416 @@
import { Book, Menu, Sunset, Trees, Zap } from "lucide-react";
import { cn } from "@/lib/utils";
import {
Accordion,
AccordionContent,
AccordionItem,
AccordionTrigger,
} from "@/components/ui/accordion";
import { Button, buttonVariants } from "@/components/ui/button";
import {
NavigationMenu,
NavigationMenuContent,
NavigationMenuItem,
NavigationMenuLink,
NavigationMenuList,
NavigationMenuTrigger,
navigationMenuTriggerStyle,
} from "@/components/ui/navigation-menu";
import {
Sheet,
SheetContent,
SheetHeader,
SheetTitle,
SheetTrigger,
} from "@/components/ui/sheet";
const subMenuItemsOne = [
{
title: "Blog",
description: "The latest industry news, updates, and info",
icon: <Book className="size-5 shrink-0" />,
},
{
title: "Compnay",
description: "Our mission is to innovate and empower the world",
icon: <Trees className="size-5 shrink-0" />,
},
{
title: "Careers",
description: "Browse job listing and discover our workspace",
icon: <Sunset className="size-5 shrink-0" />,
},
{
title: "Support",
description:
"Get in touch with our support team or visit our community forums",
icon: <Zap className="size-5 shrink-0" />,
},
];
const subMenuItemsTwo = [
{
title: "Help Center",
description: "Get all the answers you need right here",
icon: <Zap className="size-5 shrink-0" />,
},
{
title: "Contact Us",
description: "We are here to help you with any questions you have",
icon: <Sunset className="size-5 shrink-0" />,
},
{
title: "Status",
description: "Check the current status of our services and APIs",
icon: <Trees className="size-5 shrink-0" />,
},
{
title: "Terms of Service",
description: "Our terms and conditions for using our services",
icon: <Book className="size-5 shrink-0" />,
},
];
const Navbar = () => {
return (
<section className="p-4">
<div className="">
<nav className="hidden justify-between lg:flex">
<div className="flex items-center gap-6">
<div className="flex items-center gap-2">
<img
src="https://shadcnblocks.com/images/block/block-1.svg"
className="w-8"
alt="logo"
/>
<span className="text-xl font-bold">
Latosa-Escrima
</span>
</div>
<div className="flex items-center">
<a
className={cn(
"text-muted-foreground",
navigationMenuTriggerStyle,
buttonVariants({
variant: "ghost",
}),
)}
href="#"
>
Home
</a>
<NavigationMenu>
<NavigationMenuList>
<NavigationMenuItem className="text-muted-foreground">
<NavigationMenuTrigger>
<span>Products</span>
</NavigationMenuTrigger>
<NavigationMenuContent>
<ul className="w-80 p-3">
<NavigationMenuLink>
{subMenuItemsOne.map(
(item, idx) => (
<li key={idx}>
<a
className={cn(
"flex select-none gap-4 rounded-md p-3 leading-none no-underline outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground",
)}
href="#"
>
{item.icon}
<div>
<div className="text-sm font-semibold">
{
item.title
}
</div>
<p className="text-sm leading-snug text-muted-foreground">
{
item.description
}
</p>
</div>
</a>
</li>
),
)}
</NavigationMenuLink>
</ul>
</NavigationMenuContent>
</NavigationMenuItem>
<NavigationMenuItem className="text-muted-foreground">
<NavigationMenuTrigger>
Resources
</NavigationMenuTrigger>
<NavigationMenuContent>
<ul className="w-80 p-3">
<NavigationMenuLink>
{subMenuItemsTwo.map(
(item, idx) => (
<li key={idx}>
<a
className={cn(
"flex select-none gap-4 rounded-md p-3 leading-none no-underline outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground",
)}
href="#"
>
{item.icon}
<div>
<div className="text-sm font-semibold">
{
item.title
}
</div>
<p className="text-sm leading-snug text-muted-foreground">
{
item.description
}
</p>
</div>
</a>
</li>
),
)}
</NavigationMenuLink>
</ul>
</NavigationMenuContent>
</NavigationMenuItem>
</NavigationMenuList>
</NavigationMenu>
<a
className={cn(
"text-muted-foreground",
navigationMenuTriggerStyle,
buttonVariants({
variant: "ghost",
}),
)}
href="#"
>
Pricing
</a>
<a
className={cn(
"text-muted-foreground",
navigationMenuTriggerStyle,
buttonVariants({
variant: "ghost",
}),
)}
href="#"
>
Blog
</a>
</div>
</div>
<div className="flex gap-2">
<Button variant="outline">Log in</Button>
<Button>Sign up</Button>
</div>
</nav>
<div className="block lg:hidden">
<div className="flex items-center justify-between">
<div className="flex items-center gap-2">
<img
src="https://shadcnblocks.com/images/block/block-1.svg"
className="w-8"
alt="logo"
/>
<span className="text-xl font-bold">
Shadcn Blocks
</span>
</div>
<Sheet>
<SheetTrigger asChild>
<Button variant="outline" size="icon">
<Menu className="size-4" />
</Button>
</SheetTrigger>
<SheetContent className="overflow-y-auto">
<SheetHeader>
<SheetTitle>
<div className="flex items-center gap-2">
<img
src="https://shadcnblocks.com/images/block/block-1.svg"
className="w-8"
alt="logo"
/>
<span className="text-xl font-bold">
Shadcn Blocks
</span>
</div>
</SheetTitle>
</SheetHeader>
<div className="mb-8 mt-8 flex flex-col gap-4">
<a href="#" className="font-semibold">
Home
</a>
<Accordion
type="single"
collapsible
className="w-full"
>
<AccordionItem
value="products"
className="border-b-0"
>
<AccordionTrigger className="mb-4 py-0 font-semibold hover:no-underline">
Products
</AccordionTrigger>
<AccordionContent className="mt-2">
{subMenuItemsOne.map(
(item, idx) => (
<a
key={idx}
className={cn(
"flex select-none gap-4 rounded-md p-3 leading-none outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground",
)}
href="#"
>
{item.icon}
<div>
<div className="text-sm font-semibold">
{item.title}
</div>
<p className="text-sm leading-snug text-muted-foreground">
{
item.description
}
</p>
</div>
</a>
),
)}
</AccordionContent>
</AccordionItem>
<AccordionItem
value="resources"
className="border-b-0"
>
<AccordionTrigger className="py-0 font-semibold hover:no-underline">
Resources
</AccordionTrigger>
<AccordionContent className="mt-2">
{subMenuItemsTwo.map(
(item, idx) => (
<a
key={idx}
className={cn(
"flex select-none gap-4 rounded-md p-3 leading-none outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground",
)}
href="#"
>
{item.icon}
<div>
<div className="text-sm font-semibold">
{item.title}
</div>
<p className="text-sm leading-snug text-muted-foreground">
{
item.description
}
</p>
</div>
</a>
),
)}
</AccordionContent>
</AccordionItem>
</Accordion>
<a href="#" className="font-semibold">
Pricing
</a>
<a href="#" className="font-semibold">
Blog
</a>
</div>
<div className="border-t pt-4">
<div className="grid grid-cols-2 justify-start">
<a
className={cn(
buttonVariants({
variant: "ghost",
}),
"justify-start text-muted-foreground",
)}
href="#"
>
Press
</a>
<a
className={cn(
buttonVariants({
variant: "ghost",
}),
"justify-start text-muted-foreground",
)}
href="#"
>
Contact
</a>
<a
className={cn(
buttonVariants({
variant: "ghost",
}),
"justify-start text-muted-foreground",
)}
href="#"
>
Imprint
</a>
<a
className={cn(
buttonVariants({
variant: "ghost",
}),
"justify-start text-muted-foreground",
)}
href="#"
>
Sitemap
</a>
<a
className={cn(
buttonVariants({
variant: "ghost",
}),
"justify-start text-muted-foreground",
)}
href="#"
>
Legal
</a>
<a
className={cn(
buttonVariants({
variant: "ghost",
}),
"justify-start text-muted-foreground",
)}
href="#"
>
Cookie Settings
</a>
</div>
<div className="mt-2 flex flex-col gap-3">
<Button variant="outline">
Log in
</Button>
<Button>Sign up</Button>
</div>
</div>
</SheetContent>
</Sheet>
</div>
</div>
</div>
</section>
);
};
export default Navbar;

View File

@@ -0,0 +1,57 @@
"use client";
import * as React from "react";
import * as AccordionPrimitive from "@radix-ui/react-accordion";
import { ChevronDown } from "lucide-react";
import { cn } from "@/lib/utils";
const Accordion = AccordionPrimitive.Root;
const AccordionItem = React.forwardRef<
React.ComponentRef<typeof AccordionPrimitive.Item>,
React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Item>
>(({ className, ...props }, ref) => (
<AccordionPrimitive.Item
ref={ref}
className={cn("border-b", className)}
{...props}
/>
));
AccordionItem.displayName = "AccordionItem";
const AccordionTrigger = React.forwardRef<
React.ComponentRef<typeof AccordionPrimitive.Trigger>,
React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Trigger>
>(({ className, children, ...props }, ref) => (
<AccordionPrimitive.Header className="flex">
<AccordionPrimitive.Trigger
ref={ref}
className={cn(
"flex flex-1 items-center justify-between py-4 text-sm font-medium transition-all hover:underline text-left [&[data-state=open]>svg]:rotate-180",
className,
)}
{...props}
>
{children}
<ChevronDown className="h-4 w-4 shrink-0 text-muted-foreground transition-transform duration-200" />
</AccordionPrimitive.Trigger>
</AccordionPrimitive.Header>
));
AccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName;
const AccordionContent = React.forwardRef<
React.ComponentRef<typeof AccordionPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Content>
>(({ className, children, ...props }, ref) => (
<AccordionPrimitive.Content
ref={ref}
className="overflow-hidden text-sm data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down"
{...props}
>
<div className={cn("pb-4 pt-0", className)}>{children}</div>
</AccordionPrimitive.Content>
));
AccordionContent.displayName = AccordionPrimitive.Content.displayName;
export { Accordion, AccordionItem, AccordionTrigger, AccordionContent };

View File

@@ -0,0 +1,36 @@
import * as React from "react";
import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "@/lib/utils";
const badgeVariants = cva(
"inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
{
variants: {
variant: {
default:
"border-transparent bg-primary text-primary-foreground shadow hover:bg-primary/80",
secondary:
"border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
destructive:
"border-transparent bg-destructive text-destructive-foreground shadow hover:bg-destructive/80",
outline: "text-foreground",
},
},
defaultVariants: {
variant: "default",
},
},
);
export interface BadgeProps
extends React.HTMLAttributes<HTMLDivElement>,
VariantProps<typeof badgeVariants> {}
function Badge({ className, variant, ...props }: BadgeProps) {
return (
<div className={cn(badgeVariants({ variant }), className)} {...props} />
);
}
export { Badge, badgeVariants };

View File

@@ -0,0 +1,128 @@
import * as React from "react";
import * as NavigationMenuPrimitive from "@radix-ui/react-navigation-menu";
import { cva } from "class-variance-authority";
import { ChevronDown } from "lucide-react";
import { cn } from "@/lib/utils";
const NavigationMenu = React.forwardRef<
React.ComponentRef<typeof NavigationMenuPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Root>
>(({ className, children, ...props }, ref) => (
<NavigationMenuPrimitive.Root
ref={ref}
className={cn(
"relative z-10 flex max-w-max flex-1 items-center justify-center",
className,
)}
{...props}
>
{children}
<NavigationMenuViewport />
</NavigationMenuPrimitive.Root>
));
NavigationMenu.displayName = NavigationMenuPrimitive.Root.displayName;
const NavigationMenuList = React.forwardRef<
React.ComponentRef<typeof NavigationMenuPrimitive.List>,
React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.List>
>(({ className, ...props }, ref) => (
<NavigationMenuPrimitive.List
ref={ref}
className={cn(
"group flex flex-1 list-none items-center justify-center space-x-1",
className,
)}
{...props}
/>
));
NavigationMenuList.displayName = NavigationMenuPrimitive.List.displayName;
const NavigationMenuItem = NavigationMenuPrimitive.Item;
const navigationMenuTriggerStyle = cva(
"group inline-flex h-9 w-max items-center justify-center rounded-md bg-background px-4 py-2 text-sm font-medium transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground focus:outline-none disabled:pointer-events-none disabled:opacity-50 data-[active]:bg-accent/50 data-[state=open]:bg-accent/50",
);
const NavigationMenuTrigger = React.forwardRef<
React.ComponentRef<typeof NavigationMenuPrimitive.Trigger>,
React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Trigger>
>(({ className, children, ...props }, ref) => (
<NavigationMenuPrimitive.Trigger
ref={ref}
className={cn(navigationMenuTriggerStyle(), "group", className)}
{...props}
>
{children}{" "}
<ChevronDown
className="relative top-[1px] ml-1 h-3 w-3 transition duration-300 group-data-[state=open]:rotate-180"
aria-hidden="true"
/>
</NavigationMenuPrimitive.Trigger>
));
NavigationMenuTrigger.displayName = NavigationMenuPrimitive.Trigger.displayName;
const NavigationMenuContent = React.forwardRef<
React.ComponentRef<typeof NavigationMenuPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Content>
>(({ className, ...props }, ref) => (
<NavigationMenuPrimitive.Content
ref={ref}
className={cn(
"left-0 top-0 w-full data-[motion^=from-]:animate-in data-[motion^=to-]:animate-out data-[motion^=from-]:fade-in data-[motion^=to-]:fade-out data-[motion=from-end]:slide-in-from-right-52 data-[motion=from-start]:slide-in-from-left-52 data-[motion=to-end]:slide-out-to-right-52 data-[motion=to-start]:slide-out-to-left-52 md:absolute md:w-auto ",
className,
)}
{...props}
/>
));
NavigationMenuContent.displayName = NavigationMenuPrimitive.Content.displayName;
const NavigationMenuLink = NavigationMenuPrimitive.Link;
const NavigationMenuViewport = React.forwardRef<
React.ComponentRef<typeof NavigationMenuPrimitive.Viewport>,
React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Viewport>
>(({ className, ...props }, ref) => (
<div className={cn("absolute left-0 top-full flex justify-center")}>
<NavigationMenuPrimitive.Viewport
className={cn(
"origin-top-center relative mt-1.5 h-[var(--radix-navigation-menu-viewport-height)] w-full overflow-hidden rounded-md border bg-popover text-popover-foreground shadow data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-90 md:w-[var(--radix-navigation-menu-viewport-width)]",
className,
)}
ref={ref}
{...props}
/>
</div>
));
NavigationMenuViewport.displayName =
NavigationMenuPrimitive.Viewport.displayName;
const NavigationMenuIndicator = React.forwardRef<
React.ComponentRef<typeof NavigationMenuPrimitive.Indicator>,
React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Indicator>
>(({ className, ...props }, ref) => (
<NavigationMenuPrimitive.Indicator
ref={ref}
className={cn(
"top-full z-[1] flex h-1.5 items-end justify-center overflow-hidden data-[state=visible]:animate-in data-[state=hidden]:animate-out data-[state=hidden]:fade-out data-[state=visible]:fade-in",
className,
)}
{...props}
>
<div className="relative top-[60%] h-2 w-2 rotate-45 rounded-tl-sm bg-border shadow-md" />
</NavigationMenuPrimitive.Indicator>
));
NavigationMenuIndicator.displayName =
NavigationMenuPrimitive.Indicator.displayName;
export {
navigationMenuTriggerStyle,
NavigationMenu,
NavigationMenuList,
NavigationMenuItem,
NavigationMenuContent,
NavigationMenuTrigger,
NavigationMenuLink,
NavigationMenuIndicator,
NavigationMenuViewport,
};

View File

@@ -33,7 +33,7 @@ const SelectTrigger = React.forwardRef<
SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
const SelectScrollUpButton = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.ScrollUpButton>,
React.ComponentRef<typeof SelectPrimitive.ScrollUpButton>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollUpButton>
>(({ className, ...props }, ref) => (
<SelectPrimitive.ScrollUpButton
@@ -50,7 +50,7 @@ const SelectScrollUpButton = React.forwardRef<
SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName;
const SelectScrollDownButton = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.ScrollDownButton>,
React.ComponentRef<typeof SelectPrimitive.ScrollDownButton>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollDownButton>
>(({ className, ...props }, ref) => (
<SelectPrimitive.ScrollDownButton
@@ -68,7 +68,7 @@ SelectScrollDownButton.displayName =
SelectPrimitive.ScrollDownButton.displayName;
const SelectContent = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Content>,
React.ComponentRef<typeof SelectPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content>
>(({ className, children, position = "popper", ...props }, ref) => (
<SelectPrimitive.Portal>
@@ -100,7 +100,7 @@ const SelectContent = React.forwardRef<
SelectContent.displayName = SelectPrimitive.Content.displayName;
const SelectLabel = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Label>,
React.ComponentRef<typeof SelectPrimitive.Label>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Label>
>(({ className, ...props }, ref) => (
<SelectPrimitive.Label
@@ -112,7 +112,7 @@ const SelectLabel = React.forwardRef<
SelectLabel.displayName = SelectPrimitive.Label.displayName;
const SelectItem = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Item>,
React.ComponentRef<typeof SelectPrimitive.Item>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item>
>(({ className, children, ...props }, ref) => (
<SelectPrimitive.Item
@@ -134,7 +134,7 @@ const SelectItem = React.forwardRef<
SelectItem.displayName = SelectPrimitive.Item.displayName;
const SelectSeparator = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Separator>,
React.ComponentRef<typeof SelectPrimitive.Separator>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Separator>
>(({ className, ...props }, ref) => (
<SelectPrimitive.Separator

View File

@@ -0,0 +1,138 @@
"use client";
import * as React from "react";
import * as SheetPrimitive from "@radix-ui/react-dialog";
import { cva, type VariantProps } from "class-variance-authority";
import { X } from "lucide-react";
import { cn } from "@/lib/utils";
const Sheet = SheetPrimitive.Root;
const SheetTrigger = SheetPrimitive.Trigger;
const SheetClose = SheetPrimitive.Close;
const SheetPortal = SheetPrimitive.Portal;
const SheetOverlay = React.forwardRef<
React.ComponentRef<typeof SheetPrimitive.Overlay>,
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Overlay>
>(({ className, ...props }, ref) => (
<SheetPrimitive.Overlay
className={cn(
"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
className,
)}
{...props}
ref={ref}
/>
));
SheetOverlay.displayName = SheetPrimitive.Overlay.displayName;
const sheetVariants = cva(
"fixed z-50 gap-4 bg-background p-6 shadow-lg transition ease-in-out data-[state=closed]:duration-300 data-[state=open]:duration-500 data-[state=open]:animate-in data-[state=closed]:animate-out",
{
variants: {
side: {
top: "inset-x-0 top-0 border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top",
bottom: "inset-x-0 bottom-0 border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom",
left: "inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm",
right: "inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm",
},
},
defaultVariants: {
side: "right",
},
},
);
interface SheetContentProps
extends React.ComponentPropsWithoutRef<typeof SheetPrimitive.Content>,
VariantProps<typeof sheetVariants> {}
const SheetContent = React.forwardRef<
React.ComponentRef<typeof SheetPrimitive.Content>,
SheetContentProps
>(({ side = "right", className, children, ...props }, ref) => (
<SheetPortal>
<SheetOverlay />
<SheetPrimitive.Content
ref={ref}
className={cn(sheetVariants({ side }), className)}
{...props}
>
<SheetPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-secondary">
<X className="h-4 w-4" />
<span className="sr-only">Close</span>
</SheetPrimitive.Close>
{children}
</SheetPrimitive.Content>
</SheetPortal>
));
SheetContent.displayName = SheetPrimitive.Content.displayName;
const SheetHeader = ({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn(
"flex flex-col space-y-2 text-center sm:text-left",
className,
)}
{...props}
/>
);
SheetHeader.displayName = "SheetHeader";
const SheetFooter = ({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn(
"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
className,
)}
{...props}
/>
);
SheetFooter.displayName = "SheetFooter";
const SheetTitle = React.forwardRef<
React.ComponentRef<typeof SheetPrimitive.Title>,
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Title>
>(({ className, ...props }, ref) => (
<SheetPrimitive.Title
ref={ref}
className={cn("text-lg font-semibold text-foreground", className)}
{...props}
/>
));
SheetTitle.displayName = SheetPrimitive.Title.displayName;
const SheetDescription = React.forwardRef<
React.ComponentRef<typeof SheetPrimitive.Description>,
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Description>
>(({ className, ...props }, ref) => (
<SheetPrimitive.Description
ref={ref}
className={cn("text-sm text-muted-foreground", className)}
{...props}
/>
));
SheetDescription.displayName = SheetPrimitive.Description.displayName;
export {
Sheet,
SheetPortal,
SheetOverlay,
SheetTrigger,
SheetClose,
SheetContent,
SheetHeader,
SheetFooter,
SheetTitle,
SheetDescription,
};

View File

@@ -8,7 +8,10 @@
"name": "latosa-frontend",
"version": "0.1.0",
"dependencies": {
"@radix-ui/react-accordion": "^1.2.2",
"@radix-ui/react-dialog": "^1.1.4",
"@radix-ui/react-label": "^2.1.1",
"@radix-ui/react-navigation-menu": "^1.2.3",
"@radix-ui/react-select": "^2.1.4",
"@radix-ui/react-slot": "^1.1.1",
"class-variance-authority": "^0.7.1",
@@ -923,6 +926,37 @@
"integrity": "sha512-SJ31y+Q/zAyShtXJc8x83i9TYdbAfHZ++tUZnvjJJqFjzsdUnKsxPL6IEtBlxKkU7yzer//GQtZSV4GbldL3YA==",
"license": "MIT"
},
"node_modules/@radix-ui/react-accordion": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/@radix-ui/react-accordion/-/react-accordion-1.2.2.tgz",
"integrity": "sha512-b1oh54x4DMCdGsB4/7ahiSrViXxaBwRPotiZNnYXjLha9vfuURSAZErki6qjDoSIV0eXx5v57XnTGVtGwnfp2g==",
"license": "MIT",
"dependencies": {
"@radix-ui/primitive": "1.1.1",
"@radix-ui/react-collapsible": "1.1.2",
"@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-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-arrow": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.1.tgz",
@@ -946,6 +980,36 @@
}
}
},
"node_modules/@radix-ui/react-collapsible": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@radix-ui/react-collapsible/-/react-collapsible-1.1.2.tgz",
"integrity": "sha512-PliMB63vxz7vggcyq0IxNYk8vGDrLXVWw4+W4B8YnwI1s18x7YZYqlG9PLX7XxAJUi0g2DxP4XKJMFHh/iVh9A==",
"license": "MIT",
"dependencies": {
"@radix-ui/primitive": "1.1.1",
"@radix-ui/react-compose-refs": "1.1.1",
"@radix-ui/react-context": "1.1.1",
"@radix-ui/react-id": "1.1.0",
"@radix-ui/react-presence": "1.1.2",
"@radix-ui/react-primitive": "2.0.1",
"@radix-ui/react-use-controllable-state": "1.1.0",
"@radix-ui/react-use-layout-effect": "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-collection": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.1.tgz",
@@ -1002,6 +1066,42 @@
}
}
},
"node_modules/@radix-ui/react-dialog": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.4.tgz",
"integrity": "sha512-Ur7EV1IwQGCyaAuyDRiOLA5JIUZxELJljF+MbM/2NC0BYwfuRrbpS30BiQBJrVruscgUkieKkqXYDOoByaxIoA==",
"license": "MIT",
"dependencies": {
"@radix-ui/primitive": "1.1.1",
"@radix-ui/react-compose-refs": "1.1.1",
"@radix-ui/react-context": "1.1.1",
"@radix-ui/react-dismissable-layer": "1.1.3",
"@radix-ui/react-focus-guards": "1.1.1",
"@radix-ui/react-focus-scope": "1.1.1",
"@radix-ui/react-id": "1.1.0",
"@radix-ui/react-portal": "1.1.3",
"@radix-ui/react-presence": "1.1.2",
"@radix-ui/react-primitive": "2.0.1",
"@radix-ui/react-slot": "1.1.1",
"@radix-ui/react-use-controllable-state": "1.1.0",
"aria-hidden": "^1.1.1",
"react-remove-scroll": "^2.6.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-direction": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.0.tgz",
@@ -1125,6 +1225,42 @@
}
}
},
"node_modules/@radix-ui/react-navigation-menu": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/@radix-ui/react-navigation-menu/-/react-navigation-menu-1.2.3.tgz",
"integrity": "sha512-IQWAsQ7dsLIYDrn0WqPU+cdM7MONTv9nqrLVYoie3BPiabSfUVDe6Fr+oEt0Cofsr9ONDcDe9xhmJbL1Uq1yKg==",
"license": "MIT",
"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-dismissable-layer": "1.1.3",
"@radix-ui/react-id": "1.1.0",
"@radix-ui/react-presence": "1.1.2",
"@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",
"@radix-ui/react-use-layout-effect": "1.1.0",
"@radix-ui/react-use-previous": "1.1.0",
"@radix-ui/react-visually-hidden": "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-popper": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.1.tgz",
@@ -1181,6 +1317,30 @@
}
}
},
"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",
"integrity": "sha512-18TFr80t5EVgL9x1SwF/YGtfG+l0BS0PRAlCWBDoBEiDQjeKgnNZRVJp/oVBl24sr3Gbfwc/Qpj4OcWTQMsAEg==",
"license": "MIT",
"dependencies": {
"@radix-ui/react-compose-refs": "1.1.1",
"@radix-ui/react-use-layout-effect": "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-primitive": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.1.tgz",

View File

@@ -9,7 +9,10 @@
"lint": "next lint"
},
"dependencies": {
"@radix-ui/react-accordion": "^1.2.2",
"@radix-ui/react-dialog": "^1.1.4",
"@radix-ui/react-label": "^2.1.1",
"@radix-ui/react-navigation-menu": "^1.2.3",
"@radix-ui/react-select": "^2.1.4",
"@radix-ui/react-slot": "^1.1.1",
"class-variance-authority": "^0.7.1",

View File

@@ -56,6 +56,28 @@ export default {
md: "calc(var(--radius) - 2px)",
sm: "calc(var(--radius) - 4px)",
},
keyframes: {
"accordion-down": {
from: {
height: "0",
},
to: {
height: "var(--radix-accordion-content-height)",
},
},
"accordion-up": {
from: {
height: "var(--radix-accordion-content-height)",
},
to: {
height: "0",
},
},
},
animation: {
"accordion-down": "accordion-down 0.2s ease-out",
"accordion-up": "accordion-up 0.2s ease-out",
},
},
},
plugins: [require("tailwindcss-animate")],