Skip to content
9 changes: 4 additions & 5 deletions src/app/about/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type { Metadata } from "next"
import Link from "next/link"
import { FiArrowUpRight } from "react-icons/fi"
import { ClosingCta } from "@/components/layout/closing-cta"
import { CONTAINER, PAGE_HERO, PAGE_MAIN, SECTION_TITLE } from "@/components/layout/page"
import { CONTAINER, PAGE_HERO, PAGE_MAIN, SECTION_STACK, SECTION_TITLE } from "@/components/layout/page"
import { AssociationBodies } from "@/components/structure/association-bodies"
import { BoardGallery } from "@/components/structure/board-gallery"
import { LegalStatus } from "@/components/structure/legal-status"
Expand All @@ -17,7 +17,6 @@ export const metadata: Metadata = {
"Un’organizzazione pensata per durare: scopri l’organigramma, il Direttivo, gli organi associativi e i ruoli di PoliNetwork APS.",
}

const containerClass = `${CONTAINER} flex flex-col gap-10 md:gap-14`
const titleClass = `${SECTION_TITLE} text-center`

export default function StructurePage() {
Expand All @@ -27,7 +26,7 @@ export default function StructurePage() {
<Hero title="Struttura" description="Un’organizzazione pensata per durare" />
</section>
<OrganizationChart />
<section aria-labelledby="direttivo-title" className={containerClass}>
<section aria-labelledby="direttivo-title" className={SECTION_STACK}>
<h2 id="direttivo-title" className={titleClass}>
Il Direttivo in carica
</h2>
Expand All @@ -38,13 +37,13 @@ export default function StructurePage() {
</p>
</div>
</section>
<section aria-labelledby="associazione-title" className={containerClass}>
<section aria-labelledby="associazione-title" className={SECTION_STACK}>
<h2 id="associazione-title" className={titleClass}>
Come funziona l’associazione
</h2>
<AssociationBodies />
</section>
<section aria-labelledby="partecipa-title" className={containerClass}>
<section aria-labelledby="partecipa-title" className={SECTION_STACK}>
<h2 id="partecipa-title" className={titleClass}>
Trova il tuo posto in PoliNetwork
</h2>
Expand Down
15 changes: 9 additions & 6 deletions src/app/contact/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import type { Metadata } from "next"
import { CollaboraSection } from "@/components/contact/collabora-section"
import { EmailSection } from "@/components/contact/email-section"
import { GroupsSection } from "@/components/contact/groups-section"
import { CONTAINER, PAGE_HERO, PAGE_MAIN } from "@/components/layout/page"
import { Hero } from "@/components/ui/hero"

export const metadata: Metadata = {
Expand All @@ -11,12 +12,14 @@ export const metadata: Metadata = {

export default function Contact() {
return (
<main className="mx-auto flex min-h-screen w-full flex-col items-center justify-center gap-60 px-4 py-49 md:gap-75">
<Hero
title="Contattaci"
description="Qualunque sia la tua domanda, PoliNetwork è a disposizione."
gradientDescription
/>
<main className={PAGE_MAIN}>
<section className={`${CONTAINER} ${PAGE_HERO}`}>
<Hero
title="Contattaci"
description="Qualunque sia la tua domanda, PoliNetwork è a disposizione."
gradientDescription
/>
</section>
<GroupsSection />
<CollaboraSection />
<EmailSection />
Expand Down
43 changes: 20 additions & 23 deletions src/app/projects/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ import type { Metadata } from "next"
import Image from "next/image"
import Link from "next/link"
import { notFound } from "next/navigation"
import { FiArrowLeft, FiArrowUpRight, FiUploadCloud } from "react-icons/fi"
import { FiArrowLeft, FiArrowUpRight } from "react-icons/fi"
import { Glass } from "@/components/glass"
import { GradientIcon } from "@/components/gradient-icon"
import { SECTION_LEAD, SECTION_TITLE } from "@/components/layout/page"
import { ClosingCta } from "@/components/layout/closing-cta"
import { CONTAINER, PAGE_HERO, PAGE_MAIN, SECTION_LEAD, SECTION_STACK, SECTION_TITLE } from "@/components/layout/page"
import { getProjectResources, resourceDetails } from "@/components/projects/resources"
import { Button } from "@/components/ui/button"
import { Card, CardContent, CardTitle } from "@/components/ui/card"
Expand Down Expand Up @@ -39,16 +40,21 @@ export default async function ProjectPage({ params }: Props) {
const resources = getProjectResources(project)

return (
<main className="flex w-full flex-col gap-24 pb-24 md:gap-36 md:pb-36">
<section className="mx-auto flex w-full max-w-330 flex-col gap-6 px-6 pt-52 md:pt-57.5">
<main className={PAGE_MAIN}>
<section className={`${CONTAINER} ${PAGE_HERO} flex flex-col gap-6`}>
<Link
href="/projects"
className="typo-body-medium flex w-fit items-center gap-2 text-blue-secondary underline-offset-4 hover:underline focus-visible:underline"
className="typo-body-medium flex w-fit items-center gap-2 rounded-sm text-blue-secondary underline-offset-4 outline-none hover:underline focus-visible:ring-2 focus-visible:ring-blue-secondary"
>
<FiArrowLeft aria-hidden className="size-4 shrink-0" /> Tutti i progetti
</Link>
<Glass className="grid items-center gap-8 rounded-rectangles border-white/50 bg-linear-to-br from-background-blur to-blue-tertiary/30 p-6 text-center sm:p-12 md:grid-cols-[auto_minmax(0,1fr)] md:gap-12 md:text-start">
{project.logo ? (
<Glass
className={cn(
"grid items-center gap-8 rounded-rectangles border-white/50 bg-background-blur p-6 text-center sm:p-12 md:gap-12 md:text-start",
project.logo && "md:grid-cols-[auto_minmax(0,1fr)]"
)}
>
{project.logo && (
// Project logos are app icons with their own background and corners: shown as they are, not framed
<Image
src={project.logo}
Expand All @@ -58,10 +64,6 @@ export default async function ProjectPage({ params }: Props) {
sizes="(min-width: 768px) 160px, 112px"
className="mx-auto size-28 object-contain md:size-40"
/>
) : (
<Glass className="mx-auto flex size-28 items-center justify-center rounded-rectangles border-white/50 bg-background-blur p-0 shadow-sm md:size-40">
<GradientIcon icon={FiUploadCloud} className="size-12 md:size-16" />
</Glass>
)}
<div className="flex min-w-0 flex-col gap-4">
{project.category in categoryLabels && (
Expand All @@ -74,10 +76,7 @@ export default async function ProjectPage({ params }: Props) {
</section>

{resources.length > 0 && (
<section
aria-labelledby="risorse-title"
className="mx-auto flex w-full max-w-330 flex-col gap-10 px-6 md:gap-14"
>
<section aria-labelledby="risorse-title" className={SECTION_STACK}>
<div className="flex flex-col gap-4 text-center md:text-start">
<h2 id="risorse-title" className={SECTION_TITLE}>
Come usarlo
Expand Down Expand Up @@ -135,19 +134,17 @@ export default async function ProjectPage({ params }: Props) {
</section>
)}

<section className="mx-auto w-full max-w-330 px-6">
<Glass className="flex flex-col items-center gap-6 rounded-rectangles border-white/50 bg-linear-to-br from-background-blur to-blue-tertiary/30 p-6 text-center sm:p-12">
<h2 className={SECTION_TITLE}>Scopri gli altri progetti</h2>
<p className={cn(SECTION_LEAD, "max-w-200 text-balance")}>
Strumenti e app realizzati dagli studenti del Politecnico, per gli studenti del Politecnico.
</p>
<ClosingCta
title="Scopri gli altri progetti"
lead="Strumenti e app realizzati dagli studenti del Politecnico, per gli studenti del Politecnico."
action={
<Button asChild size="lg" className="w-full sm:w-fit">
<Link href="/projects">
Tutti i progetti <FiArrowUpRight aria-hidden />
</Link>
</Button>
</Glass>
</section>
}
/>
</main>
)
}
11 changes: 8 additions & 3 deletions src/app/projects/page.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { CONTAINER, PAGE_HERO, PAGE_MAIN } from "@/components/layout/page"
import { Collection } from "@/components/projects/collection"
import { CommunityNews } from "@/components/projects/community-news"
import { Deprecated } from "@/components/projects/deprecated"
import { Upload } from "@/components/projects/upload"
import { Hero } from "@/components/ui/hero"
import { getAllProjects } from "@/queries/projects"

export const metadata = {
Expand All @@ -11,17 +13,20 @@ export const metadata = {

export const dynamic = "force-dynamic"

export default async function Home() {
export default async function ProjectsPage() {
const projects = await getAllProjects()

const news = projects.filter((project) => project.category === "news")
const general = projects.filter((project) => project.category === "general")
const deprecated = projects.filter((project) => project.category === "deprecated")

return (
<main className="w-full">
<main className={PAGE_MAIN}>
<section className={`${CONTAINER} ${PAGE_HERO}`}>
<Hero title="Projects" description="Esplora e contribuisci ai progetti degli studenti" />
</section>
<CommunityNews projects={news} />
<Collection projects={general} />
<Collection projects={general} searchable={projects} />
<Upload />
<Deprecated projects={deprecated} />
</main>
Expand Down
23 changes: 20 additions & 3 deletions src/components/card-caption.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import Image from "next/image"
import Link from "next/link"
import type { ReactNode } from "react"
import type { IconType } from "react-icons"
Expand All @@ -9,18 +10,25 @@ export function CardCaption({
caption,
icon,
iconPosition = "right",
image,
href,
footer,
className,
titleClassName,
captionClassName,
}: {
title: string
caption: ReactNode
icon?: IconType
iconPosition?: "top" | "right"
/** An image shown in place of the icon, e.g. a project's logo. */
image?: string
href?: string
/** Pinned to the bottom of the card, e.g. where a link leads to. */
footer?: ReactNode
className?: string
titleClassName?: string
captionClassName?: string
}) {
return (
// Only cards that lead somewhere react to hover
Expand All @@ -32,10 +40,19 @@ export function CardCaption({
<CardHeader
className={`typo-headline-medium relative flex ${iconPosition === "right" ? "justify-between" : "flex-col-reverse"}`}
>
<CardTitle className="typo-headline-medium">{title}</CardTitle>
{icon && <CardAction icon={icon} iconSize={iconPosition === "right" ? "md" : "lg"}></CardAction>}
<CardTitle gradient={false} className={cn("typo-headline-medium", titleClassName)}>
{/* Gradient per line (box-decoration-clone): a two-line title doesn't fade into a paler second line */}
<span className="bg-linear-to-b from-blue-secondary to-blue-primary box-decoration-clone bg-clip-text text-transparent">
{title}
</span>
</CardTitle>
{image ? (
<Image src={image} alt="" width={40} height={40} className="size-10 shrink-0 object-contain" />
) : (
icon && <CardAction icon={icon} iconSize={iconPosition === "right" ? "md" : "lg"}></CardAction>
)}
</CardHeader>
<CardContent className="typo-body-medium relative">
<CardContent className={cn("typo-body-medium relative", captionClassName)}>
{typeof caption === "string" ? <p>{caption}</p> : caption}
</CardContent>
{footer && <div className="relative mt-auto">{footer}</div>}
Expand Down
6 changes: 3 additions & 3 deletions src/components/contact-card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ export type ContactCardData = {

export function ContactCard({ title, description, email }: ContactCardData) {
return (
<Card className="h-66 w-full max-w-78 gap-6 justify-self-center p-6">
<Card className="h-auto w-full gap-4 p-6">
<CardHeader>
<CardTitle className="typo-headline-small">{title}</CardTitle>
<CardTitle className="typo-headline-small xl:typo-headline-extrasmall">{title}</CardTitle>
</CardHeader>
<CardContent className="typo-body-medium flex-1">{description}</CardContent>
<CardBottomButton variant="tertiary" asChild className="mt-auto">
<CardBottomButton variant="tertiary" asChild className="mt-auto max-w-full">
<a href={`mailto:${email}`}>{email}</a>
</CardBottomButton>
</Card>
Expand Down
21 changes: 9 additions & 12 deletions src/components/contact/collabora-section.tsx
Original file line number Diff line number Diff line change
@@ -1,27 +1,24 @@
import Link from "next/link"
import { FiArrowUpRight } from "react-icons/fi"
import { CONTAINER, SECTION_LEAD, SECTION_TITLE } from "@/components/layout/page"
import { Button } from "@/components/ui/button"

export function CollaboraSection() {
return (
<section className="flex w-full flex-row justify-center gap-8 px-6 min-[1616px]:justify-start min-[1616px]:px-36">
<div className="flex max-w-[959] flex-col gap-6">
<h2 className="typo-headline-medium md:typo-display-medium text-center min-[1616px]:text-start">
Vuoi sviluppare un progetto insieme a noi?
</h2>
<section className={CONTAINER}>
<div className="mx-auto flex max-w-3xl flex-col items-center gap-6 text-center">
<h2 className={SECTION_TITLE}>Vuoi sviluppare un progetto insieme a noi?</h2>

<div className="flex min-w-0 flex-col gap-3 text-center md:text-start">
<p className="typo-body-large md:typo-headline-small text-center min-[1616px]:text-start">
<div className={`${SECTION_LEAD} flex flex-col gap-3`}>
<p>
Siamo sempre felici di{" "}
<span className="text-blue-primary">collaborare con aziende o associazioni studentesche</span> per portare
<span className="text-blue-secondary">collaborare con aziende o associazioni studentesche</span> per portare
agli studenti del PoliMi eventi e attività di valore.
</p>
<p className="typo-body-large md:typo-headline-small text-center min-[1616px]:text-start">
Consulta la pagina dedicata per scoprire come possiamo unire le forze!
</p>
<p>Consulta la pagina dedicata per scoprire come possiamo unire le forze!</p>
</div>

<Button variant="primary" size="lg" className="w-fit gap-2 self-center min-[1616px]:self-start" asChild>
<Button variant="primary" size="lg" className="mt-2" asChild>
<Link href="/collabora">
Collabora con noi
<FiArrowUpRight />
Expand Down
20 changes: 10 additions & 10 deletions src/components/contact/email-section.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import Link from "next/link"
import { ContactCard, type ContactCardData } from "../contact-card"
import { CONTAINER, INLINE_LINK, SECTION_LEAD, SECTION_TITLE } from "../layout/page"

const contactCards: ContactCardData[] = [
{
Expand All @@ -18,8 +19,8 @@ const contactCards: ContactCardData[] = [
<>
Se vuoi candidarti come admin o come membro di un team, ti consigliamo di passare dal form disponibile nella
pagina{" "}
<Link href="/join" className="text-blue-secondary underline underline-offset-2">
Struttura
<Link href="/join" className={INLINE_LINK}>
Unisciti a noi
</Link>
.
</>
Expand All @@ -31,7 +32,7 @@ const contactCards: ContactCardData[] = [
description: (
<>
Se sei un&apos;azienda o associazione e vuoi proporre una collaborazione, puoi anche consultare la pagina{" "}
<Link href="/collabora" className="text-blue-secondary underline underline-offset-2">
<Link href="/collabora" className={INLINE_LINK}>
Collabora con Noi
</Link>{" "}
per capire cosa offriamo.
Expand All @@ -43,21 +44,20 @@ const contactCards: ContactCardData[] = [

export function EmailSection() {
return (
<section className="flex w-full flex-col gap-6 px-6 min-[1616px]:px-36">
<h2 className="typo-headline-medium md:typo-display-medium bg-linear-to-b from-text-primary to-text-secondary bg-clip-text text-center text-transparent min-[1616px]:text-start">
Hai una richiesta specifica?
</h2>
<p className="typo-body-large md:typo-headline-small pb-6 text-center text-text-primary min-[1616px]:text-start">
<section className={`${CONTAINER} flex flex-col gap-6`}>
<h2 className={SECTION_TITLE}>Hai una richiesta specifica?</h2>
<p className={SECTION_LEAD}>
Per tutto il resto,{" "}
<a href="mailto:info@polinetwork.org" className="text-blue-secondary hover:underline focus-visible:underline">
<a href="mailto:info@polinetwork.org" className={INLINE_LINK}>
puoi scriverci direttamente
</a>
.
<br />
Qui sotto trovi i contatti in base al tipo di richiesta.
</p>

<div className="flex w-full flex-wrap justify-center gap-12 xl:gap-16 min-[1616px]:justify-start">
{/* 2×2 between one and four columns, so no card is left alone on a row */}
<div className="mt-4 grid gap-4 sm:grid-cols-2 sm:gap-6 xl:grid-cols-4">
{contactCards.map((card) => (
<ContactCard key={card.email} {...card} />
))}
Expand Down
Loading
Loading