From a0cf4797004683c81e25436e1df80f1557e08707 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriele=20Vigan=C3=B2?= Date: Tue, 27 Oct 2026 13:36:42 +0000 Subject: [PATCH] feat(home): refine homepage layout, proportions and card states MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Hero: fluid title (36→72px) back on two lines on desktop, freshman link grouped with the primary action instead of floating in the corner, shorter hero so Materials is reachable. - Materials and Projects: one container (max 1536px, 24/40/64px gutters), Figma's mirrored title/cards composition from xl, a centred stacked layout below it, and content-sized cards in min/max-bounded grids so card widths no longer halve across breakpoints. - Project cards show where they lead (domain + arrow) in the corner Figma reserves for an action; the mobile carousel peeks the next card. - Only cards with a destination react to hover; linked cards get a keyboard focus ring. "Carica" no longer links to "#", the material shortcuts open the real archive. - About us: section-sized instead of full screen, h2, grey gradient per the style guide rule (decorated background or coloured text, not both). - Shared: fluid display utilities, CardCaption footer slot, visible carousel dots. Co-Authored-By: Claude Opus 5.5 --- src/components/card-caption.tsx | 19 ++++-- src/components/card-icon/index.tsx | 3 +- src/components/home/about-us.tsx | 9 +-- src/components/home/hero.tsx | 40 +++++------ src/components/home/materials.tsx | 105 ++++++++++++++++------------- src/components/home/projects.tsx | 56 +++++++++------ src/components/ui/carousel.tsx | 7 +- src/lib/utils.ts | 2 + src/styles/typography.css | 14 ++++ 9 files changed, 159 insertions(+), 96 deletions(-) diff --git a/src/components/card-caption.tsx b/src/components/card-caption.tsx index 0f04b10..43fe8e3 100644 --- a/src/components/card-caption.tsx +++ b/src/components/card-caption.tsx @@ -1,6 +1,7 @@ import Link from "next/link" import type { ReactNode } from "react" import type { IconType } from "react-icons" +import { cn } from "@/lib/utils" import { Card, CardAction, CardContent, CardHeader, CardTitle } from "./ui/card" export function CardCaption({ @@ -9,6 +10,7 @@ export function CardCaption({ icon, iconPosition = "right", href, + footer, className, }: { title: string @@ -16,18 +18,27 @@ export function CardCaption({ icon?: IconType iconPosition?: "top" | "right" href?: string + /** Pinned to the bottom of the card, e.g. where a link leads to. */ + footer?: ReactNode className?: string }) { return ( - - {href && } + // Only cards that lead somewhere react to hover + a:focus-visible]:ring-2 has-[>a:focus-visible]:ring-blue-secondary", className)} + > + {href && } {title} {icon && } - {typeof caption === "string" ?

{caption}

: caption}
+ + {typeof caption === "string" ?

{caption}

: caption} +
+ {footer &&
{footer}
}
) } diff --git a/src/components/card-icon/index.tsx b/src/components/card-icon/index.tsx index ea19725..79105d7 100644 --- a/src/components/card-icon/index.tsx +++ b/src/components/card-icon/index.tsx @@ -22,13 +22,14 @@ export function CardIcon(props: CardIconProps) { a:focus-visible]:ring-2 has-[>a:focus-visible]:ring-blue-secondary", className )} > diff --git a/src/components/home/about-us.tsx b/src/components/home/about-us.tsx index f879f91..37570e8 100644 --- a/src/components/home/about-us.tsx +++ b/src/components/home/about-us.tsx @@ -4,13 +4,14 @@ import { Button } from "@/components/ui/button" export function AboutUs() { return ( -
-

+
+ {/* Grey gradient only: the background already carries the decoration (style guide: shapes OR coloured text) */} +

PoliNetwork unisce gli studenti del Poli: gruppi, risorse e supporto, tutti in un'unica community. -

+

- - -
- + {/* The freshman path sits next to the primary action, instead of floating alone in the corner */} +
+ + +
+
) diff --git a/src/components/home/materials.tsx b/src/components/home/materials.tsx index 102a8a1..07fad77 100644 --- a/src/components/home/materials.tsx +++ b/src/components/home/materials.tsx @@ -4,80 +4,95 @@ import { CardIcon } from "@/components/card-icon" import { Button } from "@/components/ui/button" import { CardCaption } from "../card-caption" +const MATERIALS_URL = "https://polinetwork.org/it/materials/view/" + +// "Carica" has no destination yet (the old upload page is empty), so it stays a plain card instead of a dead link const featuredCards = [ { title: "Carica", description: - "Hai appunti, dispense o temi d'esame che vuoi condividere? Caricali qui! Il tuo contributo é prezioso per aiutare migliaia di colleghi con materiale aggiornato!", + "Hai appunti, dispense o temi d'esame che vuoi condividere? Caricali qui! Il tuo contributo è prezioso per aiutare migliaia di colleghi con materiale aggiornato!", icon: FiUploadCloud, - size: "lg", - href: "#", }, { title: "Visualizza", description: - "Cerca cio 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.", + "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.", icon: FiBookOpen, - size: "lg", - href: "#", + href: MATERIALS_URL, }, -] as const +] +// The archive has no per-type pages: every shortcut opens it const quickLinks = [ - { title: "Dispense", icon: FiBook, size: { base: "xs", sm: "sm" }, href: "#" }, - { title: "Esami", icon: FiFileText, size: { base: "xs", sm: "sm" }, href: "#" }, - { - title: "Appunti", - icon: FiClipboard, - size: { base: "xs", sm: "sm" }, - href: "https://polinetwork.org/it/materials/view/", - }, -] as const + { title: "Dispense", icon: FiBook }, + { title: "Esami", icon: FiFileText }, + { title: "Appunti", icon: FiClipboard }, +] export function Materials() { return ( -
-
- {/* Desktop Cards */} -
- {featuredCards.map((card) => ( - - ))} -
- {/* Mobile Cards */} -
- {featuredCards.map((card) => ( - - ))} -
+
+

+ Materials +

-
- {quickLinks.map((card) => ( - - ))} -
-
- -
-

- Materials -

-

- Il piu grande archivio didattico creato dagli studenti per gli studenti del Politecnico di Milano. Cerca tra +

+

+ Il più grande archivio didattico creato dagli studenti per gli studenti del Politecnico di Milano. Cerca tra migliaia di appunti, dispense, temi d'esame e molto altro. Carica i tuoi file per far crescere la community e - trova tutto cio che ti serve, organizzato per corso di studi. + trova tutto ciò che ti serve, organizzato per corso di studi.

Il più grande archivio didattico degli studenti del Politecnico. Trova appunti, dispense ed esami, oppure carica i tuoi file per far crescere la community.

+ + {/* Below xl the cards follow the text, centered and capped so they keep their proportions on tablets */} +
+
+ {featuredCards.map((card) => ( +
+ + +
+ ))} +
+ +
+ {quickLinks.map((card) => ( + + ))} +
+
) } diff --git a/src/components/home/projects.tsx b/src/components/home/projects.tsx index b66fafc..4d67233 100644 --- a/src/components/home/projects.tsx +++ b/src/components/home/projects.tsx @@ -29,14 +29,31 @@ const featuredCards = [ }, ] as const +function ProjectCard({ className, ...card }: (typeof featuredCards)[number] & { className?: string }) { + return ( + + {new URL(card.href).hostname} + + + } + /> + ) +} + export function Projects() { return ( -
-
-

- 15+ Projects -

-

+

+

+ 15+ Projects +

+ +
+

Progetti e strumenti creati dalla nostra community. Qui trovi le iniziative nate dagli studenti del Politecnico per semplificare la vita universitaria e creare innovazione. Hai un'idea o un progetto? Proponilo! Puoi trovare collaboratori, ricevere supporto dal nostro team e dare vita alla tua soluzione. @@ -46,33 +63,30 @@ export function Projects() { l’innovazione. Hai un’idea? Proponila, trova collaboratori e realizza la tua soluzione.

-
-
- {featuredCards.map((card) => ( - - ))} -
+
+ {featuredCards.map((card) => ( + + ))}
-
- - + {/* Mobile: the next card peeks in from the edge, so the row reads as scrollable */} +
+ + {featuredCards.map((card) => ( - -
- -
+ + ))}
- +
diff --git a/src/components/ui/carousel.tsx b/src/components/ui/carousel.tsx index e6bc626..9bdd932 100644 --- a/src/components/ui/carousel.tsx +++ b/src/components/ui/carousel.tsx @@ -177,8 +177,11 @@ function CarouselDots({ className, ...props }: React.ComponentProps<"div">) { onClick={() => api?.scrollTo(index)} // Figma "slider dots": 16px current dot, 12px others, 6px apart. The pseudo-element enlarges the hit area. className={cn( - "after:-inset-1.5 relative shrink-0 rounded-full border border-white/50 bg-background-blur backdrop-blur-md transition-[width,height] after:absolute after:content-[''] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-secondary", - selectedIndex === index ? "size-4" : "size-3" + "after:-inset-1.5 relative shrink-0 rounded-full border backdrop-blur-md transition-[width,height] after:absolute after:content-[''] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-secondary", + // Glass-only dots disappear on the light background: give the current one the brand colour + selectedIndex === index + ? "size-4 border-blue-primary bg-blue-primary" + : "size-3 border-slate-300 bg-background-blur" )} /> ))} diff --git a/src/lib/utils.ts b/src/lib/utils.ts index 753b67d..b2bc774 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -11,6 +11,8 @@ const twMerge = extendTailwindMerge({ "font-size": [ { typo: [ + "display-fluid-extralarge", + "display-fluid-large", "display-extralarge", "display-large", "display-medium", diff --git a/src/styles/typography.css b/src/styles/typography.css index 8daa984..08f824f 100644 --- a/src/styles/typography.css +++ b/src/styles/typography.css @@ -21,6 +21,20 @@ @apply font-dm-sans font-normal text-[2.25rem]/[44px] tracking-normal; } +/* + Fluid display, for page-level titles that would otherwise jump between fixed steps. + Figma only has 402px and 1728px frames; these interpolate between the two sizes it uses. +*/ +@utility typo-display-fluid-large { + /* ~34px at 320px, 36px at 402px viewport → 72px from ~1600px (Figma hero: 77px at 1728) */ + @apply font-dm-sans font-medium text-[clamp(2rem,1.5rem+3vw,4.5rem)] leading-[1.12] tracking-[-0.02em]; +} + +@utility typo-display-fluid-extralarge { + /* 44px at 402px viewport → 120px at 1728px (display-extralarge) */ + @apply font-dm-sans font-medium text-[clamp(2.75rem,1.25rem+6vw,7.5rem)] leading-[1.05] tracking-[-0.02em]; +} + /* Headline */ @utility typo-headline-large { @apply font-dm-sans font-normal text-[2rem]/[40px] tracking-normal;