learning-website-nextjs1-7 Exercise 2: The Front Page and the Language Colours
===============================================================================
The front page is a server component that groups the courses at build time and draws one section for each language. Each section
carries its language's colours as two CSS variables, and the page's stylesheet is a CSS Module (only this page uses the classes,
so by Chapter 5's rule they are not global).
Save as apps/languages/app/page.tsx:
import type { CSSProperties } from "react";
import Link from "next/link";
import { groupCourses } from "@lw/content";
import { buildSections } from "@lw/languages-site";
import { content } from "../lib/site";
import styles from "./home.module.css";
/** The languages front page: every language, its courses grouped the way a learner thinks about them. */
export default function Home() {
const pages = content.all();
const sections = buildSections(groupCourses(pages));
return (
<>
Languages
Courses in French, German, Hungarian and Japanese, grouped the way you would learn them: first the writing system, then the
survival courses, then everyday conversation.
) : null}
);
})}
>
);
}
Save as apps/languages/app/home.module.css:
/* The languages front page. --lang-accent and --lang-text are set for each language on its section. Only this page uses these
classes, so they are a CSS Module. */
.lead { color: var(--muted); max-width: 42rem; }
.section {
margin: 1.75rem 0; padding: .25rem 1.25rem 1rem; background: var(--surface);
border: 1px solid var(--border); border-left: 5px solid var(--lang-accent); border-radius: 0 var(--radius) var(--radius) 0;
}
.name { color: var(--lang-text); font-size: 1.5rem; margin: .8rem 0 .2rem; }
.group { font-size: .78rem; text-transform: uppercase; letter-spacing: .09em; color: var(--muted); margin: 1.1rem 0 .3rem; }
.courses { list-style: none; padding: 0; margin: 0; }
.courses li { padding: .25rem 0; }
.count { color: var(--muted); font-size: .8rem; margin-left: .5rem; }
.empty, .lessons { color: var(--muted); margin: .6rem 0 0; }
(The app's package.json gains "@lw/languages-site" and its next.config.ts adds it to transpilePackages.)
What it does:
- The courses come from groupCourses over the site's pages, so a new course appears on the front page when its folder first has a
numbered chapter, with no list to edit.
- The "Lessons and reference" line appears only for a language that has a lessons folder with pages (French 3, Hungarian 12,
Japanese 300 at the time; German has none).
- The sections carry lang="en" because the text is English, whatever language the course teaches.
Built and fetched on the real content:
npm run build -w @lw/languages 16.9 s from cold (601 pages)
sections: French, German, Hungarian, Japanese
groups: Survival French | Survival German, Everyday German | Reading and writing, Survival Hungarian |
Reading and writing, Survival Japanese, Culture
colours: --lang-accent:#4f8ef7 / #e0a82e / #5aa469 / #d64550 (text colour for Japanese: #e8707a)
courses: French Basic Conversation 1 (12 chapters), German Basic Conversation 1 to 4 (12 each), Hungarian Alphabet 1 (20), ...
A screenshot in headless Chrome shows the page as intended: a coloured left border and name for each language (blue French, gold
German, green Hungarian), the group titles in small capitals, and each course with its chapter count.
Course and chapter pages are the ones from Chapter 6: a course is a folder listing headed with the course's name, and a chapter has
a breadcrumb and previous and next links. Nothing language-specific was needed for them.
WHY THIS WORKS AS AN ANSWER
---------------------------
The page is only presentation: every decision (what is grouped with what, which colour is readable) is in the tested package.