(null);
19 |
20 | useEffect(() => {
21 | const fetchStarCount = async () => {
22 | try {
23 | setIsLoading(true);
24 | const response = await fetch(
25 | `https://api.github.com/repos/${REPO_OWNER}/${REPO_NAME}`
26 | );
27 |
28 | if (!response.ok) {
29 | throw new Error(`GitHub API error: ${response.status}`);
30 | }
31 |
32 | const data = await response.json();
33 | setStarCount(data.stargazers_count);
34 | setError(null);
35 | } catch (err) {
36 | console.error("Failed to fetch star count:", err);
37 | setError("Failed to load star count");
38 | } finally {
39 | setIsLoading(false);
40 | }
41 | };
42 |
43 | fetchStarCount();
44 | }, []);
45 |
46 | return (
47 |
69 | );
70 | }
71 |
--------------------------------------------------------------------------------
/src/components/installation-section.tsx:
--------------------------------------------------------------------------------
1 | import CopyCLICommand from "@/components/copy-cli-command";
2 | import { Button } from "@/components/ui/button";
3 | import { ExternalLink } from "lucide-react";
4 | import Link from "next/link";
5 |
6 | export default function InstallationSection() {
7 | const codeUrl =
8 | "https://github.com/list-jonas/shadcn-ui-animated-tabs/blob/main/registry/animated-tabs/animated-tabs.tsx";
9 | const codeUrlLegacy =
10 | "https://github.com/list-jonas/shadcn-ui-animated-tabs/blob/legacy/registry/animated-tabs/animated-tabs.tsx";
11 |
12 | return (
13 | <>
14 |
15 | Installation
16 |
17 |
18 |
19 |
Current version:
20 |
21 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
Legacy version:
34 |
35 |
42 |
43 |
44 |
45 |
46 |
47 |
48 | >
49 | );
50 | }
51 |
--------------------------------------------------------------------------------
/src/components/showcase/default-value-tabs-showcase.tsx:
--------------------------------------------------------------------------------
1 | import {
2 | Tabs,
3 | TabsContent,
4 | TabsList,
5 | TabsTrigger,
6 | } from "@/../registry/animated-tabs/animated-tabs";
7 | import TabContent from "@/components/tab-content";
8 |
9 | export default function DefaultValueTabsShowcase() {
10 | return (
11 |
12 |
13 | Default Value Tabs
14 |
15 |
16 |
17 | Option 1
18 | Option 2
19 | Option 3
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 | );
33 | }
34 |
--------------------------------------------------------------------------------
/src/components/showcase/horizontal-tabs-showcase.tsx:
--------------------------------------------------------------------------------
1 | import {
2 | Tabs,
3 | TabsContent,
4 | TabsList,
5 | TabsTrigger,
6 | } from "@/../registry/animated-tabs/animated-tabs";
7 | import TabContent from "@/components/tab-content";
8 |
9 | export default function HorizontalTabsShowcase() {
10 | return (
11 |
12 |
13 | Horizontal Tabs
14 |
15 |
16 |
17 | Option 1
18 | Option 2
19 | Option 3
20 | Option 4
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 | );
38 | }
39 |
--------------------------------------------------------------------------------
/src/components/showcase/legacy-tabs-showcase.tsx:
--------------------------------------------------------------------------------
1 | import {
2 | Tabs,
3 | TabsContent,
4 | TabsList,
5 | TabsTrigger,
6 | } from "@/../registry/animated-tabs/legacy-animated-tabs";
7 | import TabContent from "../tab-content";
8 |
9 | export default function LegacyTabsShowcase() {
10 | return (
11 |
12 |
13 | Legacy Style
14 |
15 |
16 |
17 | Option 1
18 | Option 2
19 | Option 3
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 | );
33 | }
34 |
--------------------------------------------------------------------------------
/src/components/showcase/scrollable-tabs-showcase.tsx:
--------------------------------------------------------------------------------
1 | import {
2 | Tabs,
3 | TabsContent,
4 | TabsList,
5 | TabsTrigger,
6 | } from "@/../registry/animated-tabs/animated-tabs";
7 | import TabContent from "@/components/tab-content";
8 | import { ScrollArea, ScrollBar } from "@/components/ui/scroll-area";
9 |
10 | export default function ScrollableTabsShowcase() {
11 | return (
12 |
13 |
14 | Scrollable Tabs
15 |
16 |
17 |
18 |
19 |
20 | Option 1
21 | Option 2
22 | Option 3
23 | Option 4
24 | Option 5
25 | Option 6
26 | Option 7
27 | Option 8
28 | Option 9
29 | Option 10
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 | );
67 | }
68 |
--------------------------------------------------------------------------------
/src/components/showcase/vertical-tabs-showcase.tsx:
--------------------------------------------------------------------------------
1 | import {
2 | Tabs,
3 | TabsContent,
4 | TabsList,
5 | TabsTrigger,
6 | } from "@/../registry/animated-tabs/animated-tabs";
7 | import TabContent from "@/components/tab-content";
8 |
9 | export default function VerticalTabsShowcase() {
10 | return (
11 |
12 |
13 | Vertical Tabs
14 |
15 |
16 |
17 | Option 1
18 | Option 2
19 | Option 3
20 | Option 4
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 | );
38 | }
39 |
--------------------------------------------------------------------------------
/src/components/tab-content.tsx:
--------------------------------------------------------------------------------
1 | import { loremIpsum } from "lorem-ipsum";
2 | import { Card, CardContent, CardHeader, CardTitle } from "./ui/card";
3 |
4 | interface TabContentProps {
5 | name: string;
6 | }
7 |
8 | const TabContent = ({ name }: TabContentProps) => {
9 | return (
10 |
11 |
12 | {name}
13 |
14 |
15 |
16 | {loremIpsum({
17 | count: 1,
18 | units: "paragraph",
19 | })}
20 |
21 |
22 |
23 | );
24 | };
25 |
26 | export default TabContent;
27 |
--------------------------------------------------------------------------------
/src/components/theme/theme-provider.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import {
4 | ThemeProvider as NextThemesProvider,
5 | ThemeProviderProps,
6 | } from "next-themes";
7 |
8 | export function ThemeProvider({ children, ...props }: ThemeProviderProps) {
9 | return {children};
10 | }
11 |
--------------------------------------------------------------------------------
/src/components/theme/theme-select.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import { Moon, Sun } from "lucide-react";
4 | import { useTheme } from "next-themes";
5 |
6 | import { Button } from "@/components/ui/button";
7 |
8 | export function ThemeSelect() {
9 | const { theme, setTheme } = useTheme();
10 |
11 | const toggleTheme = () => {
12 | setTheme(theme === "dark" ? "light" : "dark");
13 | };
14 |
15 | return (
16 |
21 | );
22 | }
23 |
--------------------------------------------------------------------------------
/src/components/ui/button.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 | import { Slot } from "@radix-ui/react-slot"
3 | import { cva, type VariantProps } from "class-variance-authority"
4 |
5 | import { cn } from "@/lib/utils"
6 |
7 | const buttonVariants = cva(
8 | "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",
9 | {
10 | variants: {
11 | variant: {
12 | default:
13 | "bg-primary text-primary-foreground shadow-xs hover:bg-primary/90",
14 | destructive:
15 | "bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
16 | outline:
17 | "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50",
18 | secondary:
19 | "bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80",
20 | ghost:
21 | "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
22 | link: "text-primary underline-offset-4 hover:underline",
23 | },
24 | size: {
25 | default: "h-9 px-4 py-2 has-[>svg]:px-3",
26 | sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5",
27 | lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
28 | icon: "size-9",
29 | },
30 | },
31 | defaultVariants: {
32 | variant: "default",
33 | size: "default",
34 | },
35 | }
36 | )
37 |
38 | function Button({
39 | className,
40 | variant,
41 | size,
42 | asChild = false,
43 | ...props
44 | }: React.ComponentProps<"button"> &
45 | VariantProps & {
46 | asChild?: boolean
47 | }) {
48 | const Comp = asChild ? Slot : "button"
49 |
50 | return (
51 |
56 | )
57 | }
58 |
59 | export { Button, buttonVariants }
60 |
--------------------------------------------------------------------------------
/src/components/ui/card.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 |
3 | import { cn } from "@/lib/utils"
4 |
5 | function Card({ className, ...props }: React.ComponentProps<"div">) {
6 | return (
7 |
15 | )
16 | }
17 |
18 | function CardHeader({ className, ...props }: React.ComponentProps<"div">) {
19 | return (
20 |
28 | )
29 | }
30 |
31 | function CardTitle({ className, ...props }: React.ComponentProps<"div">) {
32 | return (
33 |
38 | )
39 | }
40 |
41 | function CardDescription({ className, ...props }: React.ComponentProps<"div">) {
42 | return (
43 |
48 | )
49 | }
50 |
51 | function CardAction({ className, ...props }: React.ComponentProps<"div">) {
52 | return (
53 |
61 | )
62 | }
63 |
64 | function CardContent({ className, ...props }: React.ComponentProps<"div">) {
65 | return (
66 |
71 | )
72 | }
73 |
74 | function CardFooter({ className, ...props }: React.ComponentProps<"div">) {
75 | return (
76 |
81 | )
82 | }
83 |
84 | export {
85 | Card,
86 | CardHeader,
87 | CardFooter,
88 | CardTitle,
89 | CardAction,
90 | CardDescription,
91 | CardContent,
92 | }
93 |
--------------------------------------------------------------------------------
/src/components/ui/input.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 |
3 | import { cn } from "@/lib/utils"
4 |
5 | function Input({ className, type, ...props }: React.ComponentProps<"input">) {
6 | return (
7 |
18 | )
19 | }
20 |
21 | export { Input }
22 |
--------------------------------------------------------------------------------
/src/components/ui/scroll-area.tsx:
--------------------------------------------------------------------------------
1 | "use client"
2 |
3 | import * as React from "react"
4 | import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area"
5 |
6 | import { cn } from "@/lib/utils"
7 |
8 | function ScrollArea({
9 | className,
10 | children,
11 | ...props
12 | }: React.ComponentProps) {
13 | return (
14 |
19 |
23 | {children}
24 |
25 |
26 |
27 |
28 | )
29 | }
30 |
31 | function ScrollBar({
32 | className,
33 | orientation = "vertical",
34 | ...props
35 | }: React.ComponentProps) {
36 | return (
37 |
50 |
54 |
55 | )
56 | }
57 |
58 | export { ScrollArea, ScrollBar }
59 |
--------------------------------------------------------------------------------
/src/components/ui/separator.tsx:
--------------------------------------------------------------------------------
1 | "use client"
2 |
3 | import * as React from "react"
4 | import * as SeparatorPrimitive from "@radix-ui/react-separator"
5 |
6 | import { cn } from "@/lib/utils"
7 |
8 | function Separator({
9 | className,
10 | orientation = "horizontal",
11 | decorative = true,
12 | ...props
13 | }: React.ComponentProps) {
14 | return (
15 |
25 | )
26 | }
27 |
28 | export { Separator }
29 |
--------------------------------------------------------------------------------
/src/components/ui/sonner.tsx:
--------------------------------------------------------------------------------
1 | "use client"
2 |
3 | import { useTheme } from "next-themes"
4 | import { Toaster as Sonner, ToasterProps } from "sonner"
5 |
6 | const Toaster = ({ ...props }: ToasterProps) => {
7 | const { theme = "system" } = useTheme()
8 |
9 | return (
10 |
22 | )
23 | }
24 |
25 | export { Toaster }
26 |
--------------------------------------------------------------------------------
/src/components/ui/tabs.tsx:
--------------------------------------------------------------------------------
1 | "use client"
2 |
3 | import * as React from "react"
4 | import * as TabsPrimitive from "@radix-ui/react-tabs"
5 |
6 | import { cn } from "@/lib/utils"
7 |
8 | function Tabs({
9 | className,
10 | ...props
11 | }: React.ComponentProps) {
12 | return (
13 |
18 | )
19 | }
20 |
21 | function TabsList({
22 | className,
23 | ...props
24 | }: React.ComponentProps) {
25 | return (
26 |
34 | )
35 | }
36 |
37 | function TabsTrigger({
38 | className,
39 | ...props
40 | }: React.ComponentProps) {
41 | return (
42 |
50 | )
51 | }
52 |
53 | function TabsContent({
54 | className,
55 | ...props
56 | }: React.ComponentProps) {
57 | return (
58 |
63 | )
64 | }
65 |
66 | export { Tabs, TabsList, TabsTrigger, TabsContent }
67 |
--------------------------------------------------------------------------------
/src/components/ui/tooltip.tsx:
--------------------------------------------------------------------------------
1 | "use client"
2 |
3 | import * as React from "react"
4 | import * as TooltipPrimitive from "@radix-ui/react-tooltip"
5 |
6 | import { cn } from "@/lib/utils"
7 |
8 | function TooltipProvider({
9 | delayDuration = 0,
10 | ...props
11 | }: React.ComponentProps) {
12 | return (
13 |
18 | )
19 | }
20 |
21 | function Tooltip({
22 | ...props
23 | }: React.ComponentProps) {
24 | return (
25 |
26 |
27 |
28 | )
29 | }
30 |
31 | function TooltipTrigger({
32 | ...props
33 | }: React.ComponentProps) {
34 | return
35 | }
36 |
37 | function TooltipContent({
38 | className,
39 | sideOffset = 0,
40 | children,
41 | ...props
42 | }: React.ComponentProps) {
43 | return (
44 |
45 |
54 | {children}
55 |
56 |
57 |
58 | )
59 | }
60 |
61 | export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider }
62 |
--------------------------------------------------------------------------------
/src/lib/utils.ts:
--------------------------------------------------------------------------------
1 | import { clsx, type ClassValue } from "clsx"
2 | import { twMerge } from "tailwind-merge"
3 |
4 | export function cn(...inputs: ClassValue[]) {
5 | return twMerge(clsx(inputs))
6 | }
7 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ES2017",
4 | "lib": ["dom", "dom.iterable", "esnext"],
5 | "allowJs": true,
6 | "skipLibCheck": true,
7 | "strict": true,
8 | "noEmit": true,
9 | "esModuleInterop": true,
10 | "module": "esnext",
11 | "moduleResolution": "bundler",
12 | "resolveJsonModule": true,
13 | "isolatedModules": true,
14 | "jsx": "preserve",
15 | "incremental": true,
16 | "plugins": [
17 | {
18 | "name": "next"
19 | }
20 | ],
21 | "paths": {
22 | "@/*": ["./src/*"]
23 | }
24 | },
25 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
26 | "exclude": ["node_modules"]
27 | }
28 |
--------------------------------------------------------------------------------