Skip to content

Commit 78c7746

Browse files
samejr0ski
authored andcommitted
Adds new style variants to the tabs
1 parent 56c94f4 commit 78c7746

1 file changed

Lines changed: 119 additions & 11 deletions

File tree

  • apps/webapp/app/components/primitives

apps/webapp/app/components/primitives/Tabs.tsx

Lines changed: 119 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,44 +5,146 @@ import { type ShortcutDefinition, useShortcutKeys } from "~/hooks/useShortcutKey
55
import { cn } from "~/utils/cn";
66
import { ShortcutKey } from "./ShortcutKey";
77

8+
const variants = {
9+
underline: {
10+
base: "bg-charcoal-700",
11+
active: "text-text-bright hover:bg-charcoal-750/50",
12+
},
13+
"pipe-divider": {
14+
base: "bg-charcoal-700/50",
15+
active: "text-text-bright bg-charcoal-700 rounded-[2px] border border-charcoal-600/50",
16+
},
17+
segmented: {
18+
base: "bg-charcoal-700/50",
19+
active: "text-text-bright bg-charcoal-700 rounded-[2px] border border-charcoal-600/50",
20+
},
21+
};
22+
23+
export type Variants = keyof typeof variants;
24+
825
export type TabsProps = {
926
tabs: {
1027
label: string;
1128
to: string;
1229
}[];
1330
className?: string;
1431
layoutId: string;
32+
variant?: Variants;
1533
};
1634

17-
export function Tabs({ tabs, className, layoutId }: TabsProps) {
35+
export function Tabs({ tabs, className, layoutId, variant = "underline" }: TabsProps) {
1836
return (
19-
<TabContainer className={className}>
37+
<TabContainer className={className} variant={variant}>
2038
{tabs.map((tab, index) => (
21-
<TabLink key={index} to={tab.to} layoutId={layoutId}>
39+
<TabLink key={index} to={tab.to} layoutId={layoutId} variant={variant}>
2240
{tab.label}
2341
</TabLink>
2442
))}
2543
</TabContainer>
2644
);
2745
}
2846

29-
export function TabContainer({ children, className }: { children: ReactNode; className?: string }) {
30-
return (
31-
<div className={cn(`flex flex-row gap-x-6 border-b border-grid-bright`, className)}>
32-
{children}
33-
</div>
34-
);
47+
export function TabContainer({
48+
children,
49+
className,
50+
variant = "underline",
51+
}: {
52+
children: ReactNode;
53+
className?: string;
54+
variant?: Variants;
55+
}) {
56+
if (variant === "segmented") {
57+
return (
58+
<div
59+
className={cn("relative flex h-10 items-center rounded bg-charcoal-700/50 p-1", className)}
60+
>
61+
{children}
62+
</div>
63+
);
64+
}
65+
66+
if (variant === "underline") {
67+
return (
68+
<div className={cn(`flex gap-x-6 border-b border-grid-bright`, className)}>{children}</div>
69+
);
70+
}
71+
72+
return <div className={cn(`flex`, className)}>{children}</div>;
3573
}
3674

3775
export function TabLink({
3876
to,
3977
children,
4078
layoutId,
79+
variant = "underline",
4180
}: {
4281
to: string;
4382
children: ReactNode;
4483
layoutId: string;
84+
variant?: Variants;
4585
}) {
86+
if (variant === "segmented") {
87+
return (
88+
<NavLink
89+
to={to}
90+
className="group relative flex h-full grow items-center justify-center focus-custom"
91+
end
92+
>
93+
{({ isActive, isPending }) => {
94+
const active = isActive || isPending;
95+
return (
96+
<>
97+
<div className="relative z-10 flex h-full w-full items-center justify-center px-3 py-[0.13rem]">
98+
<span
99+
className={cn(
100+
"text-sm transition duration-200",
101+
active
102+
? "text-text-bright"
103+
: "text-text-dimmed transition hover:text-text-bright"
104+
)}
105+
>
106+
{children}
107+
</span>
108+
</div>
109+
{active && (
110+
<motion.div
111+
layoutId={layoutId}
112+
transition={{ duration: 0.4, type: "spring" }}
113+
className="absolute inset-0 rounded-[2px] border border-charcoal-500/50 bg-charcoal-600"
114+
/>
115+
)}
116+
</>
117+
);
118+
}}
119+
</NavLink>
120+
);
121+
}
122+
123+
if (variant === "pipe-divider") {
124+
return (
125+
<NavLink
126+
to={to}
127+
className="group flex flex-col items-center border-r border-charcoal-700 px-2 pt-1 focus-custom first:pl-0 last:border-none"
128+
end
129+
>
130+
{({ isActive, isPending }) => {
131+
const active = isActive || isPending;
132+
return (
133+
<span
134+
className={cn(
135+
"text-sm transition duration-200",
136+
active ? "text-text-link" : "text-text-dimmed transition hover:text-text-bright"
137+
)}
138+
>
139+
{children}
140+
</span>
141+
);
142+
}}
143+
</NavLink>
144+
);
145+
}
146+
147+
// underline variant (default)
46148
return (
47149
<NavLink to={to} className="group flex flex-col items-center pt-1 focus-custom" end>
48150
{({ isActive, isPending }) => {
@@ -51,13 +153,19 @@ export function TabLink({
51153
<span
52154
className={cn(
53155
"text-sm transition duration-200",
54-
isActive || isPending ? "text-text-bright" : "text-text-bright"
156+
isActive || isPending
157+
? "text-text-bright"
158+
: "text-text-dimmed hover:text-text-bright"
55159
)}
56160
>
57161
{children}
58162
</span>
59163
{isActive || isPending ? (
60-
<motion.div layoutId={layoutId} className="mt-1 h-0.5 w-full bg-indigo-500" />
164+
<motion.div
165+
layoutId={layoutId}
166+
transition={{ type: "spring", stiffness: 500, damping: 30 }}
167+
className="mt-1 h-0.5 w-full bg-indigo-500"
168+
/>
61169
) : (
62170
<div className="mt-1 h-0.5 w-full bg-charcoal-500 opacity-0 transition duration-200 group-hover:opacity-100" />
63171
)}

0 commit comments

Comments
 (0)