idk, working on showcase XD
This commit is contained in:
parent
fd03b7b9cf
commit
82251d5272
@ -17,12 +17,15 @@
|
|||||||
"@astrojs/sitemap": "^3.1.1",
|
"@astrojs/sitemap": "^3.1.1",
|
||||||
"@astrojs/tailwind": "^5.1.0",
|
"@astrojs/tailwind": "^5.1.0",
|
||||||
"@radix-ui/react-dropdown-menu": "^2.0.6",
|
"@radix-ui/react-dropdown-menu": "^2.0.6",
|
||||||
|
"@radix-ui/react-slot": "^1.0.2",
|
||||||
|
"@radix-ui/react-tabs": "^1.0.4",
|
||||||
"@types/react": "^18.2.74",
|
"@types/react": "^18.2.74",
|
||||||
"@types/react-dom": "^18.2.24",
|
"@types/react-dom": "^18.2.24",
|
||||||
"astro": "^4.5.6",
|
"astro": "^4.5.6",
|
||||||
"class-variance-authority": "^0.7.0",
|
"class-variance-authority": "^0.7.0",
|
||||||
"clsx": "^2.1.0",
|
"clsx": "^2.1.0",
|
||||||
"cmdk": "^1.0.0",
|
"cmdk": "^1.0.0",
|
||||||
|
"embla-carousel-react": "^8.0.2",
|
||||||
"lucide-react": "^0.365.0",
|
"lucide-react": "^0.365.0",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
|
@ -23,18 +23,15 @@ dependencies:
|
|||||||
'@astrojs/tailwind':
|
'@astrojs/tailwind':
|
||||||
specifier: ^5.1.0
|
specifier: ^5.1.0
|
||||||
version: 5.1.0(astro@4.5.6)(tailwindcss@3.4.1)
|
version: 5.1.0(astro@4.5.6)(tailwindcss@3.4.1)
|
||||||
'@radix-ui/react-dialog':
|
|
||||||
specifier: ^1.0.5
|
|
||||||
version: 1.0.5(@types/react-dom@18.2.24)(@types/react@18.2.74)(react-dom@18.2.0)(react@18.2.0)
|
|
||||||
'@radix-ui/react-dropdown-menu':
|
'@radix-ui/react-dropdown-menu':
|
||||||
specifier: ^2.0.6
|
specifier: ^2.0.6
|
||||||
version: 2.0.6(@types/react-dom@18.2.24)(@types/react@18.2.74)(react-dom@18.2.0)(react@18.2.0)
|
version: 2.0.6(@types/react-dom@18.2.24)(@types/react@18.2.74)(react-dom@18.2.0)(react@18.2.0)
|
||||||
'@radix-ui/react-popover':
|
|
||||||
specifier: ^1.0.7
|
|
||||||
version: 1.0.7(@types/react-dom@18.2.24)(@types/react@18.2.74)(react-dom@18.2.0)(react@18.2.0)
|
|
||||||
'@radix-ui/react-slot':
|
'@radix-ui/react-slot':
|
||||||
specifier: ^1.0.2
|
specifier: ^1.0.2
|
||||||
version: 1.0.2(@types/react@18.2.74)(react@18.2.0)
|
version: 1.0.2(@types/react@18.2.74)(react@18.2.0)
|
||||||
|
'@radix-ui/react-tabs':
|
||||||
|
specifier: ^1.0.4
|
||||||
|
version: 1.0.4(@types/react-dom@18.2.24)(@types/react@18.2.74)(react-dom@18.2.0)(react@18.2.0)
|
||||||
'@types/react':
|
'@types/react':
|
||||||
specifier: ^18.2.74
|
specifier: ^18.2.74
|
||||||
version: 18.2.74
|
version: 18.2.74
|
||||||
@ -53,6 +50,9 @@ dependencies:
|
|||||||
cmdk:
|
cmdk:
|
||||||
specifier: ^1.0.0
|
specifier: ^1.0.0
|
||||||
version: 1.0.0(@types/react-dom@18.2.24)(@types/react@18.2.74)(react-dom@18.2.0)(react@18.2.0)
|
version: 1.0.0(@types/react-dom@18.2.24)(@types/react@18.2.74)(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
embla-carousel-react:
|
||||||
|
specifier: ^8.0.2
|
||||||
|
version: 8.0.2(react@18.2.0)
|
||||||
lucide-react:
|
lucide-react:
|
||||||
specifier: ^0.365.0
|
specifier: ^0.365.0
|
||||||
version: 0.365.0(react@18.2.0)
|
version: 0.365.0(react@18.2.0)
|
||||||
@ -1116,41 +1116,6 @@ packages:
|
|||||||
react-remove-scroll: 2.5.5(@types/react@18.2.74)(react@18.2.0)
|
react-remove-scroll: 2.5.5(@types/react@18.2.74)(react@18.2.0)
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/@radix-ui/react-popover@1.0.7(@types/react-dom@18.2.24)(@types/react@18.2.74)(react-dom@18.2.0)(react@18.2.0):
|
|
||||||
resolution: {integrity: sha512-shtvVnlsxT6faMnK/a7n0wptwBD23xc1Z5mdrtKLwVEfsEMXodS0r5s0/g5P0hX//EKYZS2sxUjqfzlg52ZSnQ==}
|
|
||||||
peerDependencies:
|
|
||||||
'@types/react': '*'
|
|
||||||
'@types/react-dom': '*'
|
|
||||||
react: ^16.8 || ^17.0 || ^18.0
|
|
||||||
react-dom: ^16.8 || ^17.0 || ^18.0
|
|
||||||
peerDependenciesMeta:
|
|
||||||
'@types/react':
|
|
||||||
optional: true
|
|
||||||
'@types/react-dom':
|
|
||||||
optional: true
|
|
||||||
dependencies:
|
|
||||||
'@babel/runtime': 7.24.4
|
|
||||||
'@radix-ui/primitive': 1.0.1
|
|
||||||
'@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.74)(react@18.2.0)
|
|
||||||
'@radix-ui/react-context': 1.0.1(@types/react@18.2.74)(react@18.2.0)
|
|
||||||
'@radix-ui/react-dismissable-layer': 1.0.5(@types/react-dom@18.2.24)(@types/react@18.2.74)(react-dom@18.2.0)(react@18.2.0)
|
|
||||||
'@radix-ui/react-focus-guards': 1.0.1(@types/react@18.2.74)(react@18.2.0)
|
|
||||||
'@radix-ui/react-focus-scope': 1.0.4(@types/react-dom@18.2.24)(@types/react@18.2.74)(react-dom@18.2.0)(react@18.2.0)
|
|
||||||
'@radix-ui/react-id': 1.0.1(@types/react@18.2.74)(react@18.2.0)
|
|
||||||
'@radix-ui/react-popper': 1.1.3(@types/react-dom@18.2.24)(@types/react@18.2.74)(react-dom@18.2.0)(react@18.2.0)
|
|
||||||
'@radix-ui/react-portal': 1.0.4(@types/react-dom@18.2.24)(@types/react@18.2.74)(react-dom@18.2.0)(react@18.2.0)
|
|
||||||
'@radix-ui/react-presence': 1.0.1(@types/react-dom@18.2.24)(@types/react@18.2.74)(react-dom@18.2.0)(react@18.2.0)
|
|
||||||
'@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.24)(@types/react@18.2.74)(react-dom@18.2.0)(react@18.2.0)
|
|
||||||
'@radix-ui/react-slot': 1.0.2(@types/react@18.2.74)(react@18.2.0)
|
|
||||||
'@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.74)(react@18.2.0)
|
|
||||||
'@types/react': 18.2.74
|
|
||||||
'@types/react-dom': 18.2.24
|
|
||||||
aria-hidden: 1.2.4
|
|
||||||
react: 18.2.0
|
|
||||||
react-dom: 18.2.0(react@18.2.0)
|
|
||||||
react-remove-scroll: 2.5.5(@types/react@18.2.74)(react@18.2.0)
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/@radix-ui/react-popper@1.1.3(@types/react-dom@18.2.24)(@types/react@18.2.74)(react-dom@18.2.0)(react@18.2.0):
|
/@radix-ui/react-popper@1.1.3(@types/react-dom@18.2.24)(@types/react@18.2.74)(react-dom@18.2.0)(react@18.2.0):
|
||||||
resolution: {integrity: sha512-cKpopj/5RHZWjrbF2846jBNacjQVwkP068DfmgrNJXpvVWrOvlAmE9xSiy5OqeE+Gi8D9fP+oDhUnPqNMY8/5w==}
|
resolution: {integrity: sha512-cKpopj/5RHZWjrbF2846jBNacjQVwkP068DfmgrNJXpvVWrOvlAmE9xSiy5OqeE+Gi8D9fP+oDhUnPqNMY8/5w==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@ -1289,6 +1254,34 @@ packages:
|
|||||||
react: 18.2.0
|
react: 18.2.0
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/@radix-ui/react-tabs@1.0.4(@types/react-dom@18.2.24)(@types/react@18.2.74)(react-dom@18.2.0)(react@18.2.0):
|
||||||
|
resolution: {integrity: sha512-egZfYY/+wRNCflXNHx+dePvnz9FbmssDTJBtgRfDY7e8SE5oIo3Py2eCB1ckAbh1Q7cQ/6yJZThJ++sgbxibog==}
|
||||||
|
peerDependencies:
|
||||||
|
'@types/react': '*'
|
||||||
|
'@types/react-dom': '*'
|
||||||
|
react: ^16.8 || ^17.0 || ^18.0
|
||||||
|
react-dom: ^16.8 || ^17.0 || ^18.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@types/react':
|
||||||
|
optional: true
|
||||||
|
'@types/react-dom':
|
||||||
|
optional: true
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.24.4
|
||||||
|
'@radix-ui/primitive': 1.0.1
|
||||||
|
'@radix-ui/react-context': 1.0.1(@types/react@18.2.74)(react@18.2.0)
|
||||||
|
'@radix-ui/react-direction': 1.0.1(@types/react@18.2.74)(react@18.2.0)
|
||||||
|
'@radix-ui/react-id': 1.0.1(@types/react@18.2.74)(react@18.2.0)
|
||||||
|
'@radix-ui/react-presence': 1.0.1(@types/react-dom@18.2.24)(@types/react@18.2.74)(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
'@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.24)(@types/react@18.2.74)(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
'@radix-ui/react-roving-focus': 1.0.4(@types/react-dom@18.2.24)(@types/react@18.2.74)(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
'@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.74)(react@18.2.0)
|
||||||
|
'@types/react': 18.2.74
|
||||||
|
'@types/react-dom': 18.2.24
|
||||||
|
react: 18.2.0
|
||||||
|
react-dom: 18.2.0(react@18.2.0)
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@radix-ui/react-use-callback-ref@1.0.1(@types/react@18.2.74)(react@18.2.0):
|
/@radix-ui/react-use-callback-ref@1.0.1(@types/react@18.2.74)(react@18.2.0):
|
||||||
resolution: {integrity: sha512-D94LjX4Sp0xJFVaoQOd3OO9k7tpBYNOXdVhkltUbGv2Qb9OXdrg/CpsjlZv7ia14Sylv398LswWBVVu5nqKzAQ==}
|
resolution: {integrity: sha512-D94LjX4Sp0xJFVaoQOd3OO9k7tpBYNOXdVhkltUbGv2Qb9OXdrg/CpsjlZv7ia14Sylv398LswWBVVu5nqKzAQ==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@ -2284,6 +2277,28 @@ packages:
|
|||||||
resolution: {integrity: sha512-w+9yAVHoHhysCa+gln7AzbO9CdjFcL/wN/5dd+XW/Msl2d/4+WisEaCF1nty0xbAKaxdaJfgLB2296U7zZB7BA==}
|
resolution: {integrity: sha512-w+9yAVHoHhysCa+gln7AzbO9CdjFcL/wN/5dd+XW/Msl2d/4+WisEaCF1nty0xbAKaxdaJfgLB2296U7zZB7BA==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/embla-carousel-react@8.0.2(react@18.2.0):
|
||||||
|
resolution: {integrity: sha512-RHe1GKLulOW8EDN+cJgbFbVVfRXcaLT2/89dyVw3ONGgVpZjD19wB87I1LUZ1aCzOSrTccx0PFSQanK4OOfGPA==}
|
||||||
|
peerDependencies:
|
||||||
|
react: ^16.8.0 || ^17.0.1 || ^18.0.0
|
||||||
|
dependencies:
|
||||||
|
embla-carousel: 8.0.2
|
||||||
|
embla-carousel-reactive-utils: 8.0.2(embla-carousel@8.0.2)
|
||||||
|
react: 18.2.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/embla-carousel-reactive-utils@8.0.2(embla-carousel@8.0.2):
|
||||||
|
resolution: {integrity: sha512-nLZqDkQdO0hvOP49/dUwjkkepMnUXgIzhyRuDjwGqswpB4Ibnc5M+w7rSQQAM+uMj0cPaXnYOTlv8XD7I/zVNw==}
|
||||||
|
peerDependencies:
|
||||||
|
embla-carousel: 8.0.2
|
||||||
|
dependencies:
|
||||||
|
embla-carousel: 8.0.2
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/embla-carousel@8.0.2:
|
||||||
|
resolution: {integrity: sha512-bogsDO8xosuh/l3PxIvA5AMl3+BnRVAse9sDW/60amzj4MbGS5re4WH5eVEXiuH8G1/3G7QUAX2QNr3Yx8z5rA==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/emoji-regex@10.3.0:
|
/emoji-regex@10.3.0:
|
||||||
resolution: {integrity: sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==}
|
resolution: {integrity: sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==}
|
||||||
dev: false
|
dev: false
|
||||||
|
11
src/components/Showcase.astro
Normal file
11
src/components/Showcase.astro
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
---
|
||||||
|
import SinglePage from "../layouts/SinglePage.astro";
|
||||||
|
import { ShowcaseTabs } from "./ShowcaseTabs.jsx";
|
||||||
|
|
||||||
|
import { dictionary } from "../i18n/dictionary";
|
||||||
|
const { title, description } = dictionary[Astro.currentLocale];
|
||||||
|
---
|
||||||
|
|
||||||
|
<SinglePage>
|
||||||
|
<ShowcaseTabs client:load/>
|
||||||
|
</SinglePage>
|
93
src/components/ShowcaseTabs.jsx
Normal file
93
src/components/ShowcaseTabs.jsx
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
import { Button } from "../components/ui/button"
|
||||||
|
import {
|
||||||
|
Card,
|
||||||
|
CardContent,
|
||||||
|
CardDescription,
|
||||||
|
CardFooter,
|
||||||
|
CardHeader,
|
||||||
|
CardTitle,
|
||||||
|
} from "../components/ui/card"
|
||||||
|
import {
|
||||||
|
Tabs,
|
||||||
|
TabsContent,
|
||||||
|
TabsList,
|
||||||
|
TabsTrigger,
|
||||||
|
} from "../components/ui/tabs"
|
||||||
|
import {
|
||||||
|
Carousel,
|
||||||
|
CarouselContent,
|
||||||
|
CarouselItem,
|
||||||
|
CarouselNext,
|
||||||
|
CarouselPrevious,
|
||||||
|
} from "../components/ui/carousel"
|
||||||
|
|
||||||
|
const data = [{
|
||||||
|
value: "thisPage",
|
||||||
|
handle: "1",
|
||||||
|
title: "This Page",
|
||||||
|
description: "random text",
|
||||||
|
images: [{ src: "temp.jpg", alt: "text" }, { src: "temp.jpg", alt: "text2" }]
|
||||||
|
}, {
|
||||||
|
value: "thatPage",
|
||||||
|
title: "That Page",
|
||||||
|
handle: "2",
|
||||||
|
description: "random text",
|
||||||
|
images: [{ src: "temp.jpg", alt: "text" }, { src: "temp.jpg", alt: "text2" }]
|
||||||
|
}, {
|
||||||
|
value: "otherPge",
|
||||||
|
title: "Other Page",
|
||||||
|
handle: "3",
|
||||||
|
description: "random text",
|
||||||
|
images: [{ src: "temp.jpg", alt: "text" }, { src: "temp.jpg", alt: "text2" }]
|
||||||
|
}];
|
||||||
|
|
||||||
|
export function ShowcaseTabs() {
|
||||||
|
return (
|
||||||
|
<Tabs defaultValue={data[0].value} className="h-full">
|
||||||
|
|
||||||
|
{data.map((item) => (
|
||||||
|
<TabsContent value={item.value} className="">
|
||||||
|
<Card className="h-full">
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle>{item.title}</CardTitle>
|
||||||
|
<CardDescription>
|
||||||
|
{item.description}
|
||||||
|
</CardDescription>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<Carousel className="w-full h-full" opts={{ align: "start", loop: "true" }}>
|
||||||
|
<CarouselContent>
|
||||||
|
{item.images.map((image, index) => (
|
||||||
|
<CarouselItem key={index}>
|
||||||
|
<Card>
|
||||||
|
<CardContent className="flex aspect-square items-center justify-center p-6">
|
||||||
|
<img src={image.src} alt={image.alt} />
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</CarouselItem>
|
||||||
|
))}
|
||||||
|
</CarouselContent>
|
||||||
|
<div className="w-full pt-10 grid grid-cols-2 gap-4 ">
|
||||||
|
<div className="col-start-1 flex text-center justify-center w-full h-full">
|
||||||
|
<CarouselPrevious />
|
||||||
|
</div>
|
||||||
|
<div className="col-start-2 flex justify-center">
|
||||||
|
<CarouselNext />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Carousel>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</TabsContent>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
<TabsList className={`grid w-full mt-4 grid-cols-${data.length}`}>
|
||||||
|
{data.map((item) => (
|
||||||
|
<TabsTrigger value={item.value}>{item.handle}</TabsTrigger>
|
||||||
|
))}
|
||||||
|
</TabsList>
|
||||||
|
|
||||||
|
</Tabs>
|
||||||
|
)
|
||||||
|
}
|
@ -5,7 +5,7 @@ import { cva } from "class-variance-authority";
|
|||||||
import { cn } from "../../lib/utils"
|
import { cn } from "../../lib/utils"
|
||||||
|
|
||||||
const buttonVariants = cva(
|
const buttonVariants = cva(
|
||||||
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
|
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
|
||||||
{
|
{
|
||||||
variants: {
|
variants: {
|
||||||
variant: {
|
variant: {
|
||||||
@ -13,7 +13,7 @@ const buttonVariants = cva(
|
|||||||
destructive:
|
destructive:
|
||||||
"bg-destructive text-destructive-foreground hover:bg-destructive/90",
|
"bg-destructive text-destructive-foreground hover:bg-destructive/90",
|
||||||
outline:
|
outline:
|
||||||
"border border-input bg-background hover:bg-primary hover:text-accent-foreground",
|
"border border-input bg-background hover:bg-accent hover:text-accent-foreground",
|
||||||
secondary:
|
secondary:
|
||||||
"bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
"bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
||||||
ghost: "hover:bg-accent hover:text-accent-foreground",
|
ghost: "hover:bg-accent hover:text-accent-foreground",
|
||||||
|
50
src/components/ui/card.jsx
Normal file
50
src/components/ui/card.jsx
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
import * as React from "react"
|
||||||
|
|
||||||
|
import { cn } from "../../lib/utils"
|
||||||
|
|
||||||
|
const Card = React.forwardRef(({ className, ...props }, ref) => (
|
||||||
|
<div
|
||||||
|
ref={ref}
|
||||||
|
className={cn("rounded-lg border bg-card text-card-foreground shadow-sm", className)}
|
||||||
|
{...props} />
|
||||||
|
))
|
||||||
|
Card.displayName = "Card"
|
||||||
|
|
||||||
|
const CardHeader = React.forwardRef(({ className, ...props }, ref) => (
|
||||||
|
<div
|
||||||
|
ref={ref}
|
||||||
|
className={cn("flex flex-col space-y-1.5 p-6", className)}
|
||||||
|
{...props} />
|
||||||
|
))
|
||||||
|
CardHeader.displayName = "CardHeader"
|
||||||
|
|
||||||
|
const CardTitle = React.forwardRef(({ className, ...props }, ref) => (
|
||||||
|
<h3
|
||||||
|
ref={ref}
|
||||||
|
className={cn("text-2xl font-semibold leading-none tracking-tight", className)}
|
||||||
|
{...props} />
|
||||||
|
))
|
||||||
|
CardTitle.displayName = "CardTitle"
|
||||||
|
|
||||||
|
const CardDescription = React.forwardRef(({ className, ...props }, ref) => (
|
||||||
|
<p
|
||||||
|
ref={ref}
|
||||||
|
className={cn("text-sm text-muted-foreground", className)}
|
||||||
|
{...props} />
|
||||||
|
))
|
||||||
|
CardDescription.displayName = "CardDescription"
|
||||||
|
|
||||||
|
const CardContent = React.forwardRef(({ className, ...props }, ref) => (
|
||||||
|
<div ref={ref} className={cn("p-6 pt-0", className)} {...props} />
|
||||||
|
))
|
||||||
|
CardContent.displayName = "CardContent"
|
||||||
|
|
||||||
|
const CardFooter = React.forwardRef(({ className, ...props }, ref) => (
|
||||||
|
<div
|
||||||
|
ref={ref}
|
||||||
|
className={cn("flex items-center p-6 pt-0", className)}
|
||||||
|
{...props} />
|
||||||
|
))
|
||||||
|
CardFooter.displayName = "CardFooter"
|
||||||
|
|
||||||
|
export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent }
|
189
src/components/ui/carousel.jsx
Normal file
189
src/components/ui/carousel.jsx
Normal file
@ -0,0 +1,189 @@
|
|||||||
|
import * as React from "react"
|
||||||
|
import useEmblaCarousel from "embla-carousel-react";
|
||||||
|
import { ArrowLeft, ArrowRight } from "lucide-react"
|
||||||
|
|
||||||
|
import { cn } from "../../lib/utils"
|
||||||
|
import { Button } from "../../components/ui/button"
|
||||||
|
|
||||||
|
const CarouselContext = React.createContext(null)
|
||||||
|
|
||||||
|
function useCarousel() {
|
||||||
|
const context = React.useContext(CarouselContext)
|
||||||
|
|
||||||
|
if (!context) {
|
||||||
|
throw new Error("useCarousel must be used within a <Carousel />")
|
||||||
|
}
|
||||||
|
|
||||||
|
return context
|
||||||
|
}
|
||||||
|
|
||||||
|
const Carousel = React.forwardRef((
|
||||||
|
{
|
||||||
|
orientation = "horizontal",
|
||||||
|
opts,
|
||||||
|
setApi,
|
||||||
|
plugins,
|
||||||
|
className,
|
||||||
|
children,
|
||||||
|
...props
|
||||||
|
},
|
||||||
|
ref
|
||||||
|
) => {
|
||||||
|
const [carouselRef, api] = useEmblaCarousel({
|
||||||
|
...opts,
|
||||||
|
axis: orientation === "horizontal" ? "x" : "y",
|
||||||
|
}, plugins)
|
||||||
|
const [canScrollPrev, setCanScrollPrev] = React.useState(false)
|
||||||
|
const [canScrollNext, setCanScrollNext] = React.useState(false)
|
||||||
|
|
||||||
|
const onSelect = React.useCallback((api) => {
|
||||||
|
if (!api) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
setCanScrollPrev(api.canScrollPrev())
|
||||||
|
setCanScrollNext(api.canScrollNext())
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const scrollPrev = React.useCallback(() => {
|
||||||
|
api?.scrollPrev()
|
||||||
|
}, [api])
|
||||||
|
|
||||||
|
const scrollNext = React.useCallback(() => {
|
||||||
|
api?.scrollNext()
|
||||||
|
}, [api])
|
||||||
|
|
||||||
|
const handleKeyDown = React.useCallback((event) => {
|
||||||
|
if (event.key === "ArrowLeft") {
|
||||||
|
event.preventDefault()
|
||||||
|
scrollPrev()
|
||||||
|
} else if (event.key === "ArrowRight") {
|
||||||
|
event.preventDefault()
|
||||||
|
scrollNext()
|
||||||
|
}
|
||||||
|
}, [scrollPrev, scrollNext])
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (!api || !setApi) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
setApi(api)
|
||||||
|
}, [api, setApi])
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (!api) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
onSelect(api)
|
||||||
|
api.on("reInit", onSelect)
|
||||||
|
api.on("select", onSelect)
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
api?.off("select", onSelect)
|
||||||
|
};
|
||||||
|
}, [api, onSelect])
|
||||||
|
|
||||||
|
return (
|
||||||
|
(<CarouselContext.Provider
|
||||||
|
value={{
|
||||||
|
carouselRef,
|
||||||
|
api: api,
|
||||||
|
opts,
|
||||||
|
orientation:
|
||||||
|
orientation || (opts?.axis === "y" ? "vertical" : "horizontal"),
|
||||||
|
scrollPrev,
|
||||||
|
scrollNext,
|
||||||
|
canScrollPrev,
|
||||||
|
canScrollNext,
|
||||||
|
}}>
|
||||||
|
<div
|
||||||
|
ref={ref}
|
||||||
|
onKeyDownCapture={handleKeyDown}
|
||||||
|
className={cn("relative", className)}
|
||||||
|
role="region"
|
||||||
|
aria-roledescription="carousel"
|
||||||
|
{...props}>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
</CarouselContext.Provider>)
|
||||||
|
);
|
||||||
|
})
|
||||||
|
Carousel.displayName = "Carousel"
|
||||||
|
|
||||||
|
const CarouselContent = React.forwardRef(({ className, ...props }, ref) => {
|
||||||
|
const { carouselRef, orientation } = useCarousel()
|
||||||
|
|
||||||
|
return (
|
||||||
|
(<div ref={carouselRef} className="overflow-hidden">
|
||||||
|
<div
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
"flex",
|
||||||
|
orientation === "horizontal" ? "-ml-4" : "-mt-4 flex-col",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props} />
|
||||||
|
</div>)
|
||||||
|
);
|
||||||
|
})
|
||||||
|
CarouselContent.displayName = "CarouselContent"
|
||||||
|
|
||||||
|
const CarouselItem = React.forwardRef(({ className, ...props }, ref) => {
|
||||||
|
const { orientation } = useCarousel()
|
||||||
|
|
||||||
|
return (
|
||||||
|
(<div
|
||||||
|
ref={ref}
|
||||||
|
role="group"
|
||||||
|
aria-roledescription="slide"
|
||||||
|
className={cn(
|
||||||
|
"min-w-0 shrink-0 grow-0 basis-full",
|
||||||
|
orientation === "horizontal" ? "pl-4" : "pt-4",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props} />)
|
||||||
|
);
|
||||||
|
})
|
||||||
|
CarouselItem.displayName = "CarouselItem"
|
||||||
|
|
||||||
|
const CarouselPrevious = React.forwardRef(({ className, variant = "outline", size = "icon", ...props }, ref) => {
|
||||||
|
const { orientation, scrollPrev, canScrollPrev } = useCarousel()
|
||||||
|
|
||||||
|
return (
|
||||||
|
(<Button
|
||||||
|
ref={ref}
|
||||||
|
variant={variant}
|
||||||
|
size={size}
|
||||||
|
className={cn(" h-8 w-8 rounded-full", className)}
|
||||||
|
disabled={!canScrollPrev}
|
||||||
|
onClick={scrollPrev}
|
||||||
|
{...props}>
|
||||||
|
<ArrowLeft className="h-4 w-4" />
|
||||||
|
<span className="sr-only">Previous slide</span>
|
||||||
|
</Button>)
|
||||||
|
);
|
||||||
|
})
|
||||||
|
CarouselPrevious.displayName = "CarouselPrevious"
|
||||||
|
|
||||||
|
const CarouselNext = React.forwardRef(({ className, variant = "outline", size = "icon", ...props }, ref) => {
|
||||||
|
const { orientation, scrollNext, canScrollNext } = useCarousel()
|
||||||
|
|
||||||
|
return (
|
||||||
|
(<Button
|
||||||
|
ref={ref}
|
||||||
|
variant={variant}
|
||||||
|
size={size}
|
||||||
|
className={cn("h-8 w-8 rounded-full", className)}
|
||||||
|
disabled={!canScrollNext}
|
||||||
|
onClick={scrollNext}
|
||||||
|
{...props}>
|
||||||
|
<ArrowRight className="h-4 w-4" />
|
||||||
|
<span className="sr-only">Next slide</span>
|
||||||
|
</Button>)
|
||||||
|
);
|
||||||
|
})
|
||||||
|
CarouselNext.displayName = "CarouselNext"
|
||||||
|
|
||||||
|
export { Carousel, CarouselContent, CarouselItem, CarouselPrevious, CarouselNext };
|
41
src/components/ui/tabs.jsx
Normal file
41
src/components/ui/tabs.jsx
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
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(({ 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(({ 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(({ 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 }
|
@ -2,9 +2,11 @@
|
|||||||
import MainLayout from "../../layouts/MainLayout.astro";
|
import MainLayout from "../../layouts/MainLayout.astro";
|
||||||
import Hero from "../../components/Hero.astro";
|
import Hero from "../../components/Hero.astro";
|
||||||
import About from "../../components/About.astro";
|
import About from "../../components/About.astro";
|
||||||
|
import Showcase from "../../components/Showcase.astro";
|
||||||
|
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
import { dictionary } from "../../i18n/dictionary";
|
import { dictionary } from "../../i18n/dictionary";
|
||||||
|
|
||||||
const { title, description } = dictionary[Astro.currentLocale];
|
const { title, description } = dictionary[Astro.currentLocale];
|
||||||
|
|
||||||
export async function getStaticPaths() {
|
export async function getStaticPaths() {
|
||||||
@ -16,5 +18,5 @@ export async function getStaticPaths() {
|
|||||||
<MainLayout title={title} description={description} lang={Astro.currentLocale} themeOverride="theme_auto">
|
<MainLayout title={title} description={description} lang={Astro.currentLocale} themeOverride="theme_auto">
|
||||||
<Hero />
|
<Hero />
|
||||||
<About />
|
<About />
|
||||||
<Hero />
|
<Showcase />
|
||||||
</MainLayout>
|
</MainLayout>
|
Loading…
Reference in New Issue
Block a user