Skip to content

Commit e40ed5c

Browse files
authored
Merge branch 'main' into Diubii/card
2 parents 8d16fc7 + ade80e3 commit e40ed5c

15 files changed

Lines changed: 247 additions & 50 deletions

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,12 @@
2424
"clsx": "^2.1.1",
2525
"cmdk": "1.1.1",
2626
"geist": "^1.5.1",
27-
"lucide-react": "^0.545.0",
2827
"next": "^15.5.14",
2928
"next-themes": "^0.4.6",
3029
"react": "^19.2.3",
3130
"react-dom": "^19.2.3",
3231
"react-hook-form": "^7.68.0",
32+
"react-icons": "^5.6.0",
3333
"tailwind-merge": "^3.4.0",
3434
"tailwindcss-animate": "^1.0.7",
3535
"zod": "^4.2.1"

pnpm-lock.yaml

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

src/app/page.tsx

Lines changed: 54 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,60 @@
1-
import { Users } from "lucide-react"
2-
import { Button } from "@/components/ui/button"
3-
import { ButtonWithIcon } from "@/components/ui/buttonWithIcon"
1+
import { FiBook, FiBookOpen, FiClipboard, FiFileText, FiPenTool, FiTriangle, FiUploadCloud } from "react-icons/fi"
2+
import { CardIcon } from "@/components/card-icon"
3+
import { Hero } from "@/components/home/hero"
4+
5+
const schoolCards = [
6+
{ title: "Scuola di Architettura", icon: FiTriangle, size: "md" },
7+
{ title: "Scuola di Design", icon: FiPenTool, size: "md" },
8+
{ title: "Scuola di Ingegneria", icon: FiBookOpen, size: "md" },
9+
] as const
10+
11+
const materialCards = [
12+
{
13+
title: "Carica",
14+
description:
15+
"Hai appunti, dispense o temi d'esame che vuoi condividere? Caricali qui! Il tuo contributo è prezioso per aiutare migliaia di colleghi con materiale aggiornato!",
16+
icon: FiUploadCloud,
17+
size: "lg",
18+
},
19+
{
20+
title: "Visualizza",
21+
description:
22+
"Cerca ciò che ti serve per il tuo prossimo esame. Naviga tra i corsi di studio e trova facilmente appunti, esercizi e dispense condivisi da altri studenti come te.",
23+
icon: FiBookOpen,
24+
size: "lg",
25+
},
26+
] as const
27+
28+
const otherCards = [
29+
{ title: "Dispense", icon: FiBook, size: "sm" },
30+
{ title: "Appunti", icon: FiFileText, size: "sm" },
31+
{ title: "Esami", icon: FiClipboard, size: "sm" },
32+
] as const
433

534
export default function Home() {
635
return (
7-
<main className="container mx-auto px-4 py-8">
8-
<h2 className="typo-headline-large bg mb-4 font-bold">Welcome to PoliNetwork</h2>
9-
<p className="mb-4">
10-
PoliNetwork is a student association dedicated to connecting and supporting students at Politecnico.
11-
</p>
12-
<div className="flex w-90 flex-col items-center justify-center gap-2 rounded-rectangles bg-red py-8">
13-
<p className="typo-body-medium text-text-accent-darkbg">Test with figma variables</p>
14-
<div className="h-20 w-20 rounded-images bg-background-blur" />
15-
<ButtonWithIcon variant="primary" icon={Users} iconPosition="left" text="Diventa socio" />
16-
<ButtonWithIcon variant="tertiary" icon={Users} iconPosition="right" text="Diventa socio" />
17-
<ButtonWithIcon variant="tertiaryBlur" icon={Users} iconPosition="left" text="Diventa socio" />
18-
<Button variant="link">Link</Button>
36+
<main className="w-full">
37+
<Hero />
38+
<div className="mx-auto flex max-w-6xl flex-col gap-12">
39+
<section>
40+
<div className="grid gap-6 sm:grid-cols-2 md:grid-cols-3">
41+
{schoolCards.map((card) => (
42+
<CardIcon key={card.title} {...card} href="#" hoverEffect />
43+
))}
44+
</div>
45+
</section>
46+
<section className="flex max-w-4xl flex-col gap-6">
47+
<div className="grid gap-32 sm:grid-cols-2">
48+
{materialCards.map((card) => (
49+
<CardIcon key={card.title} {...card} href="#" />
50+
))}
51+
</div>
52+
<div className="grid gap-16 sm:grid-cols-3">
53+
{otherCards.map((card) => (
54+
<CardIcon key={card.title} {...card} href="#" />
55+
))}
56+
</div>
57+
</section>
1958
</div>
2059
</main>
2160
)
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { GradientIcon, type GradientIconType } from "../gradient-icon"
2+
import type { CardSize } from "./types"
3+
import { getIconSizeClasses } from "./utils"
4+
5+
export function BasicCardMedia({ icon: Icon, size }: { icon: GradientIconType; size: CardSize }) {
6+
return <GradientIcon icon={Icon} className={getIconSizeClasses(size)} />
7+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { cn } from "@/lib/utils"
2+
import { GradientIcon, type GradientIconType } from "../gradient-icon"
3+
import type { CardSize } from "./types"
4+
import { getIconSizeClasses } from "./utils"
5+
6+
export function DescriptionCardMedia({ icon: Icon, size }: { icon: GradientIconType; size: CardSize }) {
7+
return (
8+
<div className={cn("relative", getIconSizeClasses(size))}>
9+
<GradientIcon icon={Icon} className="h-full w-full" />
10+
</div>
11+
)
12+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { Shape } from "@/components/shapes"
2+
3+
export function CardHoverBackground() {
4+
return (
5+
<div className="pointer-events-none absolute inset-0 z-0 overflow-hidden opacity-0 transition-opacity duration-300 group-hover/card:opacity-100">
6+
<Shape variant="big-teal" className="-top-16 -right-20 absolute h-40 w-40" />
7+
<Shape variant="big-teal" className="-bottom-21 -left-2 absolute h-70 w-70" />
8+
<div className="-top-36 -left-32 absolute h-168 w-2xl">
9+
<div className="-rotate-70 relative h-full w-full origin-center">
10+
<Shape variant="looper" className="absolute inset-0 h-full w-full object-contain" />
11+
</div>
12+
</div>
13+
</div>
14+
)
15+
}

src/components/card-icon/index.tsx

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import { Glass } from "@/components/glass"
2+
import { cn } from "@/lib/utils"
3+
import { BasicCardMedia } from "./basic-card-media"
4+
import { DescriptionCardMedia } from "./description-card-media"
5+
import { CardHoverBackground } from "./hover-background"
6+
import type { CardIconProps } from "./types"
7+
import { getCardPaddingClasses, getContentGapClasses } from "./utils"
8+
9+
export function CardIcon(props: CardIconProps) {
10+
const { title, icon, size = "md", href, hoverEffect = false, className } = props
11+
const description = "description" in props ? props.description : undefined
12+
const Root = href ? "a" : "div"
13+
const isDescriptionCard = Boolean(description)
14+
15+
return (
16+
<Glass
17+
className={cn(
18+
"w-full overflow-hidden rounded-rectangles border-white/50 bg-background-blur p-0 text-card-foreground",
19+
className
20+
)}
21+
>
22+
<Root
23+
href={href}
24+
className={cn(
25+
"group/card relative flex h-full flex-col text-left",
26+
getCardPaddingClasses(size, isDescriptionCard)
27+
)}
28+
>
29+
{hoverEffect && <CardHoverBackground />}
30+
31+
<div
32+
className={cn(
33+
"relative z-10 flex h-full flex-1 flex-col",
34+
getContentGapClasses(size),
35+
isDescriptionCard ? "justify-between" : "items-center justify-center text-center"
36+
)}
37+
>
38+
<div className="flex justify-center">
39+
{isDescriptionCard ? (
40+
<DescriptionCardMedia icon={icon} size={size} />
41+
) : (
42+
<BasicCardMedia icon={icon} size={size} />
43+
)}
44+
</div>
45+
46+
<div className={cn("flex flex-col", isDescriptionCard ? "gap-2 text-left" : "items-center text-center")}>
47+
<h3
48+
className={cn(
49+
"typo-headline-medium bg-linear-to-b from-blue-secondary to-blue-primary bg-clip-text text-transparent",
50+
isDescriptionCard ? "text-left" : "text-center"
51+
)}
52+
>
53+
{title}
54+
</h3>
55+
{description && <p className="typo-body-medium max-w-sm text-left text-text-primary">{description}</p>}
56+
</div>
57+
</div>
58+
</Root>
59+
</Glass>
60+
)
61+
}

src/components/card-icon/types.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import type { GradientIconType } from "@/components/gradient-icon"
2+
3+
export type CardSize = "sm" | "md" | "lg"
4+
5+
export type SharedCardProps = {
6+
title: string
7+
icon: GradientIconType
8+
size?: CardSize
9+
href?: string
10+
hoverEffect?: boolean
11+
className?: string
12+
}
13+
14+
export type CardWithDescriptionProps = SharedCardProps & {
15+
description: string
16+
}
17+
18+
export type CardIconProps = SharedCardProps | CardWithDescriptionProps

src/components/card-icon/utils.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import type { CardSize } from "./types"
2+
3+
export function getIconSizeClasses(size: CardSize) {
4+
if (size === "sm") return "h-14 w-14"
5+
if (size === "lg") return "h-44 w-44"
6+
return "h-32 w-32"
7+
}
8+
9+
export function getCardPaddingClasses(size: CardSize, hasDescription: boolean) {
10+
if (!hasDescription && size === "sm") return "px-8 py-4"
11+
return "p-8"
12+
}
13+
14+
export function getContentGapClasses(size: CardSize) {
15+
if (size === "sm") return "gap-2"
16+
return "gap-6"
17+
}

src/components/gradient-icon.tsx

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { type FunctionComponent, type SVGProps, useId } from "react"
2+
3+
export type GradientIconType = FunctionComponent<SVGProps<SVGSVGElement>>
4+
5+
type GradientIconProps = {
6+
icon: GradientIconType
7+
className: string
8+
}
9+
10+
export function GradientIcon({ icon: Icon, className }: GradientIconProps) {
11+
const iconId = useId().replaceAll(":", "")
12+
const gradientId = `icon-gradient-${iconId}`
13+
const maskId = `icon-mask-${iconId}`
14+
15+
return (
16+
<svg className={className} viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
17+
<defs>
18+
<linearGradient id={gradientId} x1="0%" x2="0%" y1="0%" y2="100%">
19+
<stop offset="0%" stopColor="var(--color-blue-secondary)" />
20+
<stop offset="100%" stopColor="var(--color-blue-primary)" />
21+
</linearGradient>
22+
<mask id={maskId} maskUnits="userSpaceOnUse" x="0" y="0" width="16" height="16">
23+
<Icon className={className} stroke="white" fill="none" />
24+
</mask>
25+
</defs>
26+
<rect x="0" y="0" width="16" height="16" fill={`url(#${gradientId})`} mask={`url(#${maskId})`} />
27+
</svg>
28+
)
29+
}

0 commit comments

Comments
 (0)