Skip to content

Commit 3048d44

Browse files
authored
chore: refactor with components (#1043)
1 parent 43b8071 commit 3048d44

File tree

11 files changed

+355
-368
lines changed

11 files changed

+355
-368
lines changed
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import type { IconDefinition } from "@fortawesome/fontawesome-svg-core";
2+
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
3+
import { Button, Link } from "@heroui/react";
4+
5+
interface ExternalLinkButtonProps {
6+
href: string;
7+
icon: IconDefinition;
8+
children: React.ReactNode;
9+
variant?:
10+
| "light"
11+
| "flat"
12+
| "bordered"
13+
| "ghost"
14+
| "shadow"
15+
| "solid"
16+
| "faded";
17+
color?:
18+
| "default"
19+
| "primary"
20+
| "secondary"
21+
| "success"
22+
| "warning"
23+
| "danger";
24+
size?: "sm" | "md" | "lg";
25+
className?: string;
26+
isIconOnly?: boolean;
27+
fullWidth?: boolean;
28+
iconClassName?: string;
29+
animate?: boolean;
30+
}
31+
32+
export function ExternalLinkButton({
33+
href,
34+
icon,
35+
children,
36+
variant = "flat",
37+
color = "default",
38+
size = "sm",
39+
className = "",
40+
isIconOnly = false,
41+
fullWidth = false,
42+
iconClassName = "",
43+
animate = false,
44+
}: ExternalLinkButtonProps) {
45+
const buttonClass = `${fullWidth ? "w-full justify-start" : ""} ${className}`;
46+
const iconClasses = `text-sm ${animate ? "animate-pulse" : ""} ${iconClassName}`;
47+
48+
return (
49+
<Button
50+
as={Link}
51+
href={href}
52+
isExternal
53+
variant={variant}
54+
color={color}
55+
size={size}
56+
className={buttonClass}
57+
isIconOnly={isIconOnly}
58+
startContent={
59+
!isIconOnly ? (
60+
<FontAwesomeIcon icon={icon} className={iconClasses} />
61+
) : undefined
62+
}
63+
>
64+
{isIconOnly ? (
65+
<FontAwesomeIcon icon={icon} className={iconClasses} />
66+
) : (
67+
children
68+
)}
69+
</Button>
70+
);
71+
}

app/_components/feature-card.tsx

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import type { IconDefinition } from "@fortawesome/fontawesome-svg-core";
2+
import { Card, CardBody, CardHeader } from "@heroui/react";
3+
import { GradientIcon } from "./gradient-icon";
4+
5+
interface FeatureCardProps {
6+
icon: IconDefinition;
7+
title: string;
8+
description: string;
9+
gradientFrom?: string;
10+
gradientTo?: string;
11+
borderColor?: string;
12+
className?: string;
13+
}
14+
15+
export function FeatureCard({
16+
icon,
17+
title,
18+
description,
19+
gradientFrom = "primary/5",
20+
gradientTo = "primary/10",
21+
borderColor = "primary/20",
22+
className = "",
23+
}: FeatureCardProps) {
24+
return (
25+
<Card
26+
className={`bg-gradient-to-br from-${gradientFrom} to-${gradientTo} border-${borderColor} ${className}`}
27+
>
28+
<CardHeader className="pb-4">
29+
<div className="flex items-center gap-3">
30+
<GradientIcon icon={icon} size="lg" />
31+
<h3 className="text-xl font-semibold">{title}</h3>
32+
</div>
33+
</CardHeader>
34+
<CardBody className="pt-0">
35+
<p className="text-default-600">{description}</p>
36+
</CardBody>
37+
</Card>
38+
);
39+
}

app/_components/footer.tsx

Lines changed: 17 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@ import {
44
faHeart,
55
faHouseChimneyWindow,
66
} from "@fortawesome/free-solid-svg-icons";
7-
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
8-
import { Button, Divider, Link } from "@heroui/react";
7+
import { Divider, Link } from "@heroui/react";
8+
import { ExternalLinkButton } from "./external-link-button";
9+
import { GradientIcon } from "./gradient-icon";
910

1011
export function Footer() {
1112
return (
@@ -15,12 +16,10 @@ export function Footer() {
1516
{/* Logo and tagline */}
1617
<div className="flex flex-col items-center space-y-4">
1718
<div className="flex items-center gap-3">
18-
<div className="flex items-center justify-center w-10 h-10 bg-gradient-to-br from-primary-500 to-secondary-500 rounded-lg shadow-sm">
19-
<FontAwesomeIcon
20-
icon={faHouseChimneyWindow}
21-
className="text-white text-sm"
22-
/>
23-
</div>
19+
<GradientIcon
20+
icon={faHouseChimneyWindow}
21+
size="md"
22+
/>
2423
<h3 className="text-2xl font-bold bg-gradient-to-r from-primary-600 to-secondary-600 bg-clip-text text-transparent">
2524
Cabin
2625
</h3>
@@ -33,55 +32,29 @@ export function Footer() {
3332

3433
{/* Mobile navigation - only shown on small screens */}
3534
<div className="flex sm:hidden flex-wrap justify-center gap-3">
36-
<Button
37-
as={Link}
35+
<ExternalLinkButton
3836
href="https://docs.cabinpkg.com"
39-
isExternal
40-
variant="flat"
41-
size="sm"
37+
icon={faBookOpen}
4238
className="text-default-600 hover:text-primary bg-default-100 hover:bg-primary/10 transition-all"
43-
startContent={
44-
<FontAwesomeIcon
45-
icon={faBookOpen}
46-
className="text-sm"
47-
/>
48-
}
4939
>
5040
Documentation
51-
</Button>
52-
<Button
53-
as={Link}
41+
</ExternalLinkButton>
42+
<ExternalLinkButton
5443
href="https://github.com/cabinpkg"
55-
isExternal
56-
variant="flat"
57-
size="sm"
44+
icon={faGithub}
5845
className="text-default-600 hover:text-primary bg-default-100 hover:bg-primary/10 transition-all"
59-
startContent={
60-
<FontAwesomeIcon
61-
icon={faGithub}
62-
className="text-sm"
63-
/>
64-
}
6546
>
6647
GitHub
67-
</Button>
68-
<Button
69-
as={Link}
48+
</ExternalLinkButton>
49+
<ExternalLinkButton
7050
href="https://github.com/sponsors/ken-matsui"
71-
isExternal
51+
icon={faHeart}
7252
color="danger"
73-
variant="flat"
74-
size="sm"
7553
className="font-medium shadow-sm hover:shadow-md transition-shadow"
76-
startContent={
77-
<FontAwesomeIcon
78-
icon={faHeart}
79-
className="text-sm animate-pulse"
80-
/>
81-
}
54+
iconClassName="animate-pulse"
8255
>
8356
Sponsor
84-
</Button>
57+
</ExternalLinkButton>
8558
</div>
8659

8760
{/* Divider */}

app/_components/gradient-icon.tsx

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import type { IconDefinition } from "@fortawesome/fontawesome-svg-core";
2+
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
3+
4+
interface GradientIconProps {
5+
icon: IconDefinition;
6+
size?: "sm" | "md" | "lg" | "xl";
7+
className?: string;
8+
iconClassName?: string;
9+
}
10+
11+
const sizeClasses = {
12+
sm: "w-8 h-8",
13+
md: "w-10 h-10",
14+
lg: "w-12 h-12",
15+
xl: "w-16 h-16",
16+
};
17+
18+
const iconSizeClasses = {
19+
sm: "text-sm",
20+
md: "text-sm",
21+
lg: "text-lg",
22+
xl: "text-xl",
23+
};
24+
25+
export function GradientIcon({
26+
icon,
27+
size = "md",
28+
className = "",
29+
iconClassName = "",
30+
}: GradientIconProps) {
31+
return (
32+
<div
33+
className={`flex items-center justify-center ${sizeClasses[size]} bg-gradient-to-br from-primary-500 to-secondary-500 rounded-lg shadow-sm ${className}`}
34+
>
35+
<FontAwesomeIcon
36+
icon={icon}
37+
className={`text-white ${iconSizeClasses[size]} ${iconClassName}`}
38+
/>
39+
</div>
40+
);
41+
}

app/_components/header.tsx

Lines changed: 14 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,8 @@
11
import { faGithub } from "@fortawesome/free-brands-svg-icons";
22
import { faBookOpen, faHeart } from "@fortawesome/free-solid-svg-icons";
3-
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
4-
import {
5-
Button,
6-
Link,
7-
Navbar,
8-
NavbarBrand,
9-
NavbarContent,
10-
NavbarItem,
11-
} from "@heroui/react";
3+
import { Navbar, NavbarBrand, NavbarContent, NavbarItem } from "@heroui/react";
124
import NextLink from "next/link";
5+
import { ExternalLinkButton } from "./external-link-button";
136

147
import { Logo } from "./logo";
158
import { SearchButton } from "./search";
@@ -50,62 +43,41 @@ export function Header() {
5043
<NavbarContent className="gap-2 flex-shrink-0" justify="end">
5144
{/* Docs link */}
5245
<NavbarItem>
53-
<Button
54-
as={Link}
46+
<ExternalLinkButton
5547
href="https://docs.cabinpkg.com"
56-
isExternal
48+
icon={faBookOpen}
5749
variant="light"
58-
size="sm"
5950
className="text-default-600 hover:text-primary transition-colors"
60-
startContent={
61-
<FontAwesomeIcon
62-
icon={faBookOpen}
63-
className="text-sm"
64-
/>
65-
}
6651
>
6752
Docs
68-
</Button>
53+
</ExternalLinkButton>
6954
</NavbarItem>
7055

7156
{/* GitHub link */}
7257
<NavbarItem>
73-
<Button
74-
as={Link}
58+
<ExternalLinkButton
7559
href="https://github.com/cabinpkg"
76-
isExternal
60+
icon={faGithub}
7761
variant="light"
78-
size="sm"
7962
className="text-default-600 hover:text-primary transition-colors"
8063
isIconOnly
81-
aria-label="GitHub Repository"
64+
iconClassName="text-lg"
8265
>
83-
<FontAwesomeIcon
84-
icon={faGithub}
85-
className="text-lg"
86-
/>
87-
</Button>
66+
GitHub Repository
67+
</ExternalLinkButton>
8868
</NavbarItem>
8969

9070
{/* Sponsor link */}
9171
<NavbarItem>
92-
<Button
93-
as={Link}
72+
<ExternalLinkButton
9473
href="https://github.com/sponsors/ken-matsui"
95-
isExternal
74+
icon={faHeart}
9675
color="danger"
97-
variant="flat"
98-
size="sm"
9976
className="font-medium shadow-sm hover:shadow-md transition-shadow"
100-
startContent={
101-
<FontAwesomeIcon
102-
icon={faHeart}
103-
className="text-sm animate-pulse"
104-
/>
105-
}
77+
iconClassName="animate-pulse"
10678
>
10779
Sponsor
108-
</Button>
80+
</ExternalLinkButton>
10981
</NavbarItem>
11082
</NavbarContent>
11183
</div>

app/_components/logo.tsx

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,9 @@
11
import { faHouseChimneyWindow } from "@fortawesome/free-solid-svg-icons";
2-
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
2+
import { GradientIcon } from "./gradient-icon";
33

44
export const Logo = () => (
55
<div className="flex items-center gap-2 hover:opacity-80 transition-opacity">
6-
<div className="flex items-center justify-center w-8 h-8 bg-gradient-to-br from-primary-500 to-secondary-500 rounded-lg shadow-sm">
7-
<FontAwesomeIcon
8-
icon={faHouseChimneyWindow}
9-
className="text-white text-sm"
10-
/>
11-
</div>
6+
<GradientIcon icon={faHouseChimneyWindow} size="sm" />
127
<div className="hidden sm:block">
138
<h1 className="font-bold text-lg bg-gradient-to-r from-primary-600 to-secondary-600 bg-clip-text text-transparent">
149
Cabin

app/_components/section-header.tsx

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import type { IconDefinition } from "@fortawesome/fontawesome-svg-core";
2+
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
3+
4+
interface SectionHeaderProps {
5+
icon: IconDefinition;
6+
title: string;
7+
iconColor?: string;
8+
size?: "sm" | "md" | "lg";
9+
className?: string;
10+
}
11+
12+
const sizeClasses = {
13+
sm: "text-lg",
14+
md: "text-xl",
15+
lg: "text-2xl",
16+
};
17+
18+
export function SectionHeader({
19+
icon,
20+
title,
21+
iconColor = "text-primary",
22+
size = "md",
23+
className = "",
24+
}: SectionHeaderProps) {
25+
return (
26+
<div className={`flex items-center gap-2 ${className}`}>
27+
<FontAwesomeIcon icon={icon} className={`${iconColor} text-lg`} />
28+
<h2 className={`${sizeClasses[size]} font-semibold`}>{title}</h2>
29+
</div>
30+
);
31+
}

0 commit comments

Comments
 (0)