Skip to content

Commit 7a14f04

Browse files
BIA3IAtoto04
andauthored
feat: add Tabs component (#86)
* feat: add Tabs component using Radix UI * feat: implement Tabs component with additional triggers for FAQs * fix: rename to FAQsPage for clarity * refactor: simplify FAQ tab rendering * feat: add TabsNavigation component for improved tab rendering * feat: refactor Tabs component structure --------- Co-authored-by: Tommaso Morganti <tommaso.morganti01@gmail.com>
1 parent adb2527 commit 7a14f04

9 files changed

Lines changed: 221 additions & 1 deletion

File tree

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
"@radix-ui/react-select": "^2.2.6",
1818
"@radix-ui/react-separator": "^1.1.8",
1919
"@radix-ui/react-slot": "^1.2.4",
20+
"@radix-ui/react-tabs": "^1.1.13",
2021
"@t3-oss/env-nextjs": "^0.13.10",
2122
"@tanstack/react-table": "^8.21.3",
2223
"babel-plugin-react-compiler": "^1.0.0",
@@ -49,4 +50,4 @@
4950
"engines": {
5051
"node": ">=24.5.2"
5152
}
52-
}
53+
}

pnpm-lock.yaml

Lines changed: 62 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/app/faqs/page.tsx

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
"use client"
2+
3+
import { FiBookOpen, FiDollarSign, FiEdit, FiFileText, FiSend } from "react-icons/fi"
4+
import TabsNavigation from "@/components/tabs"
5+
import { Tabs } from "@/components/tabs/tabs"
6+
import { TabsContent } from "@/components/tabs/tabs-content"
7+
8+
const faqItems = [
9+
{
10+
value: "tab1",
11+
label: "Lezioni",
12+
content: "Content for Tab 1",
13+
icon: FiBookOpen,
14+
},
15+
{
16+
value: "tab2",
17+
label: "Tasse",
18+
content: "Content for Tab 2",
19+
icon: FiDollarSign,
20+
},
21+
{
22+
value: "tab3",
23+
label: "Esami",
24+
content: "Content for Tab 3",
25+
icon: FiEdit,
26+
},
27+
{
28+
value: "tab4",
29+
label: "Piano di Studi",
30+
content: "Content for Tab 4",
31+
icon: FiFileText,
32+
},
33+
{
34+
value: "tab5",
35+
label: "Mobilitá Internazionale",
36+
content: (
37+
<div className="flex flex-col items-start py-4">
38+
<h1 className="typo-title-large">Content for Tab 5</h1>
39+
<p>
40+
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore
41+
magna aliqua.
42+
</p>
43+
</div>
44+
),
45+
icon: FiSend,
46+
},
47+
]
48+
49+
export default function FAQsPage() {
50+
return (
51+
<main className="w-full py-12">
52+
<Tabs defaultValue="tab5" className="flex flex-col items-center">
53+
<TabsNavigation items={faqItems} />
54+
{faqItems.map((item) => (
55+
<TabsContent value={item.value} key={item.value}>
56+
{item.content}
57+
</TabsContent>
58+
))}
59+
</Tabs>
60+
</main>
61+
)
62+
}

src/components/tabs/index.tsx

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
"use client"
2+
3+
import { cn } from "@/lib/utils"
4+
import { TabsList } from "./tabs-list"
5+
import { TabsTrigger } from "./tabs-trigger"
6+
import type { TabsNavigationProps } from "./types"
7+
8+
export default function TabsNavigation({ items, className }: TabsNavigationProps) {
9+
return (
10+
<TabsList className={cn(className)}>
11+
{items.map((item) => {
12+
const Icon = item.icon
13+
14+
return (
15+
<TabsTrigger value={item.value} key={item.value}>
16+
{Icon && <Icon className="size-4 shrink-0" />}
17+
{item.label}
18+
</TabsTrigger>
19+
)
20+
})}
21+
</TabsList>
22+
)
23+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import * as TabsPrimitive from "@radix-ui/react-tabs"
2+
import type * as React from "react"
3+
4+
import { cn } from "@/lib/utils"
5+
6+
export function TabsContent({ className, ...props }: React.ComponentProps<typeof TabsPrimitive.Content>) {
7+
return <TabsPrimitive.Content data-slot="tabs-content" className={cn("flex-1 outline-none", className)} {...props} />
8+
}

src/components/tabs/tabs-list.tsx

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import * as TabsPrimitive from "@radix-ui/react-tabs"
2+
import type * as React from "react"
3+
4+
import { cn } from "@/lib/utils"
5+
import { Glass } from "../glass"
6+
7+
export function TabsList({ className, children, ...props }: React.ComponentProps<typeof TabsPrimitive.List>) {
8+
return (
9+
<TabsPrimitive.List data-slot="tabs-list" {...props}>
10+
<Glass
11+
className={cn(
12+
"inline-flex items-center gap-2 rounded-3xl border-white/50 bg-background-blur p-2.5 text-card-foreground",
13+
className
14+
)}
15+
>
16+
{children}
17+
</Glass>
18+
</TabsPrimitive.List>
19+
)
20+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import * as TabsPrimitive from "@radix-ui/react-tabs"
2+
import type * as React from "react"
3+
4+
import { cn } from "@/lib/utils"
5+
6+
export function TabsTrigger({ className, children, ...props }: React.ComponentProps<typeof TabsPrimitive.Trigger>) {
7+
return (
8+
<TabsPrimitive.Trigger
9+
data-slot="tabs-trigger"
10+
className={cn(
11+
"group typo-label-large relative flex items-center justify-center gap-1.5 overflow-hidden whitespace-nowrap rounded-xl bg-transparent px-3 py-1.5",
12+
// "focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-white/50", // TODO Focus ring for accessibility - do we have a standard focus style?
13+
className
14+
)}
15+
{...props}
16+
>
17+
<span
18+
aria-hidden="true"
19+
className="absolute inset-0 rounded-xl bg-blue-tertiary opacity-0 transition-opacity duration-500 ease-in-out group-data-[state=active]:opacity-100"
20+
/>
21+
<span className="relative z-10 flex items-center justify-center gap-1.5">{children}</span>
22+
</TabsPrimitive.Trigger>
23+
)
24+
}

src/components/tabs/tabs.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import * as TabsPrimitive from "@radix-ui/react-tabs"
2+
import type * as React from "react"
3+
4+
import { cn } from "@/lib/utils"
5+
6+
export function Tabs({ className, ...props }: React.ComponentProps<typeof TabsPrimitive.Root>) {
7+
return <TabsPrimitive.Root data-slot="tabs" className={cn("group/tabs flex flex-col gap-2", className)} {...props} />
8+
}

src/components/tabs/types.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import type { IconType } from "react-icons"
2+
3+
export type TabsNavigationItem = {
4+
value: string
5+
label: string
6+
icon?: IconType
7+
}
8+
9+
export type TabsNavigationProps = {
10+
items: TabsNavigationItem[]
11+
className?: string
12+
}

0 commit comments

Comments
 (0)