diff --git a/src/app/guides/page.tsx b/src/app/guides/page.tsx index e9d039f3..20742968 100644 --- a/src/app/guides/page.tsx +++ b/src/app/guides/page.tsx @@ -1,6 +1,8 @@ import type { Metadata } from "next" import { FiBook, FiFileText } from "react-icons/fi" import { CardIcon } from "@/components/card-icon" +import { CONTAINER, PAGE_HERO, PAGE_MAIN } from "@/components/layout/page" +import { Hero } from "@/components/ui/hero" const guides = [ { @@ -26,15 +28,14 @@ export const metadata: Metadata = { export default function GuidesHome() { return ( -
-
-
-

- Guide -

-
+
+
+ +
-
+ {/* Two equal paths: same height, side by side from sm, and the whole card is the link */} +
+
{guides.map((guide) => ( ))}
-
+
) } diff --git a/src/components/associations/associations-list.tsx b/src/components/associations/associations-list.tsx index 65dd312a..d22670e6 100644 --- a/src/components/associations/associations-list.tsx +++ b/src/components/associations/associations-list.tsx @@ -12,6 +12,7 @@ import { } from "react-icons/fi" import AccordionAssociation from "@/components/accordion-association" import type { GradientIconType } from "@/components/gradient-icon" +import { EMPTY_STATE } from "@/components/layout/page" import type { ApiOutput } from "@/types" type Association = ApiOutput["web"]["associations"]["getAllAssociations"][number] @@ -33,11 +34,7 @@ const LINK_CONFIG: { key: keyof AssociationLinks; label: string; icon: GradientI export function AssociationsList({ associations }: { associations: Association[] }) { if (associations.length === 0) { // The query returns an empty list on backend errors too, so the message covers both cases - return ( -

- Le associazioni non sono disponibili al momento. Riprova più tardi. -

- ) + return

Le associazioni non sono disponibili al momento. Riprova più tardi.

} const accordionItems = associations.map((association) => ({ diff --git a/src/components/faqs/faqs-tabs.tsx b/src/components/faqs/faqs-tabs.tsx index c1080bd6..632cd4a8 100644 --- a/src/components/faqs/faqs-tabs.tsx +++ b/src/components/faqs/faqs-tabs.tsx @@ -4,6 +4,7 @@ import type { IconType } from "react-icons" import { FiBookOpen, FiDollarSign, FiEdit, FiFileText, FiHelpCircle, FiSend } from "react-icons/fi" import AccordionList from "@/components/accordion-list" import CalloutItem from "@/components/callout-item" +import { EMPTY_STATE } from "@/components/layout/page" import TabsNavigation from "@/components/tabs" import { Tabs } from "@/components/tabs/tabs" import { TabsContent } from "@/components/tabs/tabs-content" @@ -19,9 +20,6 @@ const ICONS: Record = { send: FiSend, } -const EMPTY_STATE = - "typo-body-large rounded-rectangles border border-slate-300 border-dashed px-6 py-10 text-center text-slate-600" - export function FaqsTabs({ categories }: { categories: FaqCategory[] }) { const tabs = categories.map((category) => ({ value: String(category.categoryId), diff --git a/src/components/groups/extra-groups.tsx b/src/components/groups/extra-groups.tsx index f0b25c96..a381cb5c 100644 --- a/src/components/groups/extra-groups.tsx +++ b/src/components/groups/extra-groups.tsx @@ -1,5 +1,6 @@ import { CardCourseGroup } from "@/components/card-course-group" -import { GROUPS_COLUMN, GroupsPageHeader } from "@/components/groups/page-header" +import { FLOW_MAIN, FlowHeader } from "@/components/layout/flow-header" +import { EMPTY_STATE } from "@/components/layout/page" import { getVisibleGroups } from "@/queries/groups" import { EXTRA_LABEL, matchesLabelBranch } from "@/utils/labels" import { mergeGroupsByTitle } from "@/utils/merge-groups" @@ -11,8 +12,8 @@ export async function ExtraGroups() { ) return ( -
- +
+ {extraGroups.length > 0 ? (
@@ -28,7 +29,7 @@ export async function ExtraGroups() { ))}
) : ( -

Nessun gruppo extra disponibile al momento.

+

Nessun gruppo extra disponibile al momento.

)}
) diff --git a/src/components/groups/groups-result.tsx b/src/components/groups/groups-result.tsx index b0ff9c99..591b4ddd 100644 --- a/src/components/groups/groups-result.tsx +++ b/src/components/groups/groups-result.tsx @@ -1,6 +1,7 @@ import { notFound } from "next/navigation" import { CardCourseGroup } from "@/components/card-course-group" -import { GROUPS_COLUMN, GroupsPageHeader } from "@/components/groups/page-header" +import { FLOW_MAIN, FlowHeader } from "@/components/layout/flow-header" +import { EMPTY_STATE } from "@/components/layout/page" import { getLevel, getSchool } from "@/components/wizard/constants" import { getVisibleGroups } from "@/queries/groups" import type { VisibleGroup } from "@/queries/types" @@ -107,8 +108,8 @@ export async function GroupsResult({ ] return ( -
- + ))} - {!hasAnyGroup && ( -

- Nessun gruppo disponibile al momento per questo corso. -

- )} + {!hasAnyGroup &&

Nessun gruppo disponibile al momento per questo corso.

}
) } diff --git a/src/components/guides/constants.ts b/src/components/guides/constants.ts index 742951ef..e53f618c 100644 --- a/src/components/guides/constants.ts +++ b/src/components/guides/constants.ts @@ -1,26 +1,7 @@ -export const LOREM_GUIDES = [ - { - value: "lorem-ipsum-dolor-sit-amet", - trigger: "Lorem ipsum dolor sit amet", - content: - "Consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.", - }, - { - value: "ut-enim-ad-minim-veniam", - trigger: "Ut enim ad minim veniam", - content: - "Quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium.", - }, - { - value: "duis-aute-irure-dolor", - trigger: "Duis aute irure dolor", - content: - "In reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt.", - }, - { - value: "excepteur-sint-occaecat", - trigger: "Excepteur sint occaecat", - content: - "Cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt.", - }, -] +import type { AccordionListItem } from "@/components/accordion-list/types" + +// The guides have no content yet, and how they will be organised is still open: until then the pages show their empty state. +export const GENERAL_GUIDES: AccordionListItem[] = [] + +/** Guides for a given course, by course slug. */ +export const COURSE_GUIDES: Record = {} diff --git a/src/components/guides/general-guides.tsx b/src/components/guides/general-guides.tsx index 48b62904..321f7169 100644 --- a/src/components/guides/general-guides.tsx +++ b/src/components/guides/general-guides.tsx @@ -1,38 +1,17 @@ -import Link from "next/link" -import { FiArrowLeft, FiX } from "react-icons/fi" import AccordionList from "@/components/accordion-list" -import { LOREM_GUIDES } from "@/components/guides/constants" +import { GENERAL_GUIDES } from "@/components/guides/constants" +import { FLOW_MAIN, FlowHeader } from "@/components/layout/flow-header" +import { EMPTY_STATE } from "@/components/layout/page" export function GeneralGuides() { return ( -
-
- - - -
-

Guide Generali

-
- - - -
+
+ - {LOREM_GUIDES.length > 0 ? ( - + {GENERAL_GUIDES.length > 0 ? ( + ) : ( -

- Nessuna guida disponibile al momento. -

+

Nessuna guida disponibile al momento.

)}
) diff --git a/src/components/guides/guides-result.tsx b/src/components/guides/guides-result.tsx index bf98f20f..32f2b5ee 100644 --- a/src/components/guides/guides-result.tsx +++ b/src/components/guides/guides-result.tsx @@ -1,8 +1,8 @@ -import Link from "next/link" import { notFound } from "next/navigation" -import { FiArrowLeft, FiX } from "react-icons/fi" import AccordionList from "@/components/accordion-list" -import { LOREM_GUIDES } from "@/components/guides/constants" +import { COURSE_GUIDES } from "@/components/guides/constants" +import { FLOW_MAIN, FlowHeader } from "@/components/layout/flow-header" +import { EMPTY_STATE } from "@/components/layout/page" import { getLevel, getSchool } from "@/components/wizard/constants" import { getVisibleGroups } from "@/queries/groups" import { courseFacetsForLevel, humanizeSlug } from "@/utils/labels" @@ -28,38 +28,22 @@ export async function GuidesResult({ const courseName = humanizeSlug(course) + const guides = COURSE_GUIDES[course] ?? [] + return ( -
-
- - - -
-

{courseName}

-

- Laurea {currentLevel.name} -

-
- - - -
+
+ - {LOREM_GUIDES.length > 0 ? ( - + {guides.length > 0 ? ( + ) : ( -

- Nessuna guida disponibile al momento per questo corso. -

+

Nessuna guida disponibile al momento per questo corso.

)}
) diff --git a/src/components/groups/page-header.tsx b/src/components/layout/flow-header.tsx similarity index 74% rename from src/components/groups/page-header.tsx rename to src/components/layout/flow-header.tsx index ef06eb8c..6f86ccc6 100644 --- a/src/components/groups/page-header.tsx +++ b/src/components/layout/flow-header.tsx @@ -1,8 +1,13 @@ import Link from "next/link" import { FiArrowLeft, FiX } from "react-icons/fi" +import { CONTAINER } from "@/components/layout/page" +import { cn } from "@/lib/utils" -/** Figma's list column for group results (~1040px at 1728), with the shared 24/40px gutters. */ -export const GROUPS_COLUMN = "mx-auto w-full min-w-0 max-w-5xl px-6 sm:px-10" +/** The narrower column of the pages a wizard leads to (group results, guides), with the site's gutters. */ +export const FLOW_COLUMN = cn(CONTAINER, "min-w-0 max-w-5xl") + +/** Page shell for those pages: the top padding leaves the fixed header ~48px of air on phones. */ +export const FLOW_MAIN = `${FLOW_COLUMN} flex min-h-svh flex-col gap-12 pt-44 pb-32 md:gap-16 md:pt-52` const iconLinkClass = "grid size-10 shrink-0 place-items-center rounded-full bg-white/60 outline-none transition-colors hover:bg-white focus-visible:ring-2 focus-visible:ring-blue-secondary" @@ -11,7 +16,7 @@ const iconLinkClass = * Back button, centred title and optional close button. A three-column grid keeps a long course name from running * under the buttons on phones. */ -export function GroupsPageHeader({ +export function FlowHeader({ title, subtitle, backHref, diff --git a/src/components/layout/page.ts b/src/components/layout/page.ts index 495b9d2a..fcde2497 100644 --- a/src/components/layout/page.ts +++ b/src/components/layout/page.ts @@ -27,3 +27,7 @@ export const PAGE_HERO = `${PAGE_HERO_TOP} pb-8 md:pb-12 xl:pb-24` /** A section made of a heading block followed by its content. */ export const SECTION_STACK = `${CONTAINER} flex flex-col gap-10 md:gap-14` + +/** Placeholder for a list with nothing to show yet: dashed, so it reads as "empty" rather than as a card. */ +export const EMPTY_STATE = + "typo-body-large wrap-anywhere rounded-rectangles border border-slate-300 border-dashed px-6 py-10 text-center text-slate-600" diff --git a/src/components/projects/project-list.tsx b/src/components/projects/project-list.tsx index 72ee5c4a..6429d5f8 100644 --- a/src/components/projects/project-list.tsx +++ b/src/components/projects/project-list.tsx @@ -2,6 +2,7 @@ import { type ReactNode, useId, useState } from "react" import { FiArrowDown, FiArrowUp } from "react-icons/fi" +import { EMPTY_STATE } from "@/components/layout/page" import { PeekCarousel } from "../peek-carousel" import { Button } from "../ui/button" import { ProjectCard } from "./project-card" @@ -66,9 +67,5 @@ export function ProjectList({ /** Shown in place of an empty list: says so plainly and points to the one thing the reader can do about it. */ export function ProjectsEmpty({ children }: { children: ReactNode }) { - return ( -
- {children} -
- ) + return
{children}
} diff --git a/src/components/wizard/course-step.tsx b/src/components/wizard/course-step.tsx index a3b570ac..c2872829 100644 --- a/src/components/wizard/course-step.tsx +++ b/src/components/wizard/course-step.tsx @@ -2,6 +2,7 @@ import Link from "next/link" import { notFound } from "next/navigation" import { FiChevronRight } from "react-icons/fi" import { CardCourse } from "@/components/card-course" +import { EMPTY_STATE } from "@/components/layout/page" import { getLevel, getSchool } from "@/components/wizard/constants" import { CourseFilters, type FilterOption } from "@/components/wizard/course-filters" import { WizardShell } from "@/components/wizard/wizard-shell" @@ -76,9 +77,7 @@ export async function CourseStep({ } >
- {courseSlugs.length === 0 && ( -

Nessun corso disponibile al momento.

- )} + {courseSlugs.length === 0 &&

Nessun corso disponibile al momento.

} {courseSlugs.map((course) => { const facets = facetsByCourse.get(course) ?? [] const courseCampus = campusFacet(facets)