Give projects and members their own pages
The API has always served a project's and a member's detail, with `path` and `alternates` in three languages, and the site had nowhere to show it. A project now has its page — tagline, status, technologies, description, technical decisions, what was learned, gallery, client, dates, lead, team, repositories and open calls — and so does a member: headline, bio, links, technologies and projects. Cards on the landing link to both. Addresses follow the API's rule read backwards (core/routes.ts): pages at the root, records under a section named in their language, the default language unprefixed. One catch-all route serves them all. Not a route per shape: Analog registers each loader as an internal Nitro route, and Nitro's router cannot hold `/:prefix/:slug` beside `/:prefix/:section/:slug` — the first became unreachable. The frame around a record (header, footer, lights, 404/503, title, description, canonical, hreflang) is one component now, PageShell, and each type only brings its body, all sharing one layout partial. Also fixes chips that stepped down one row after the first, on the landing's cards too: @pi/ui's reset gives every `li + li` a top margin, right for prose and wrong for a row spaced by `gap`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
85
landing/src/app/core/routes.spec.ts
Normal file
85
landing/src/app/core/routes.spec.ts
Normal file
@@ -0,0 +1,85 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
import { DEFAULT_LOCALE, SUPPORTED_LOCALES } from './api';
|
||||
import { homeHref, resolveRoute, SECTIONS } from './routes';
|
||||
|
||||
describe('resolveRoute', () => {
|
||||
it('reads a page at the root as the default language', () => {
|
||||
expect(resolveRoute('/sobre-nosotros')).toEqual({
|
||||
type: 'page',
|
||||
locale: DEFAULT_LOCALE,
|
||||
slug: 'sobre-nosotros',
|
||||
});
|
||||
});
|
||||
|
||||
it('reads a prefixed page in the language it names', () => {
|
||||
expect(resolveRoute('/en/about-us')).toEqual({
|
||||
type: 'page',
|
||||
locale: 'en',
|
||||
slug: 'about-us',
|
||||
});
|
||||
expect(resolveRoute('/ca/qui-som/')).toEqual({
|
||||
type: 'page',
|
||||
locale: 'ca',
|
||||
slug: 'qui-som',
|
||||
});
|
||||
});
|
||||
|
||||
it('reads a record under its section, in each language', () => {
|
||||
expect(resolveRoute('/proyectos/catalogo')).toEqual({
|
||||
type: 'project',
|
||||
locale: 'es',
|
||||
slug: 'catalogo',
|
||||
});
|
||||
expect(resolveRoute('/en/projects/catalogo')).toEqual({
|
||||
type: 'project',
|
||||
locale: 'en',
|
||||
slug: 'catalogo',
|
||||
});
|
||||
expect(resolveRoute('/ca/equip/ada')).toEqual({
|
||||
type: 'member',
|
||||
locale: 'ca',
|
||||
slug: 'ada',
|
||||
});
|
||||
expect(resolveRoute('/ca/col-labora/frontend')).toEqual({
|
||||
type: 'call',
|
||||
locale: 'ca',
|
||||
slug: 'frontend',
|
||||
});
|
||||
});
|
||||
|
||||
// A section only means something in its own language: `/projects/x` is not
|
||||
// an address the API hands out for Spanish.
|
||||
it('refuses a section spelled in another language', () => {
|
||||
expect(resolveRoute('/projects/catalogo')).toBeNull();
|
||||
expect(resolveRoute('/en/proyectos/catalogo')).toBeNull();
|
||||
});
|
||||
|
||||
// The API never spells the default language with a prefix, so one record
|
||||
// has one address rather than two.
|
||||
it('refuses the default language as a prefix', () => {
|
||||
expect(resolveRoute('/es/sobre-nosotros')).toBeNull();
|
||||
expect(resolveRoute('/es/proyectos/catalogo')).toBeNull();
|
||||
});
|
||||
|
||||
it('refuses what is not shaped like a record', () => {
|
||||
expect(resolveRoute('/')).toBeNull();
|
||||
expect(resolveRoute('/fr/a-propos')).toBeNull();
|
||||
expect(resolveRoute('/proyectos/catalogo/extra')).toBeNull();
|
||||
});
|
||||
|
||||
it('knows every section in every language', () => {
|
||||
for (const sections of Object.values(SECTIONS)) {
|
||||
expect(Object.keys(sections).sort()).toEqual(
|
||||
[...SUPPORTED_LOCALES].sort(),
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('homeHref', () => {
|
||||
it('answers on ?lang= for every language but the default', () => {
|
||||
expect(homeHref(DEFAULT_LOCALE)).toBe('/');
|
||||
expect(homeHref('ca')).toBe('/?lang=ca');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user