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:
49
README.md
49
README.md
@@ -150,11 +150,13 @@ landing/src/
|
||||
core/copy.ts the chrome's own words, in es / en / ca
|
||||
core/icons.ts the icon set, inlined and registered as literals
|
||||
core/pi-strings.ts the strings `@pi/ui` translates on its own
|
||||
core/content-page.ts the load function both content-page routes share
|
||||
core/routes.ts which record an address belongs to (resolveRoute)
|
||||
core/routed-page.ts the load function for every address but the landing
|
||||
pages/(home).server.ts one load function, eleven parallel calls
|
||||
pages/(home).page.ts the landing itself
|
||||
pages/[slug].page.ts a page the panel publishes, default language
|
||||
pages/[locale]/[slug].page.ts the same, in any other language
|
||||
pages/[...path].page.ts everything else: pages, projects, members, 404
|
||||
ui/page-shell.ts header, footer, lights, 404/503 and SEO around a record
|
||||
ui/routed-page.ts picks the body for the record's type
|
||||
ui/ presentational components, one per payload type
|
||||
(thin wrappers over `@pi/ui`), each with its `.scss`
|
||||
server/
|
||||
@@ -186,9 +188,13 @@ page component through `injectResponse()` (`@analogjs/router/tokens`), which is
|
||||
the *render* request's response; the one a page `load` sees belongs to the
|
||||
internal request Analog resolves loaders through and never reaches the browser.
|
||||
That is also why the 404 status comes from middleware instead — except for
|
||||
addresses shaped like a content page, where only the API knows whether the page
|
||||
exists: the middleware lets those through and `ui/content-page.ts` sets the 404
|
||||
itself from `ngOnInit`, once its input has arrived.
|
||||
addresses shaped like a record, where only the API knows whether it exists: the
|
||||
middleware lets those through and `ui/page-shell.ts` sets the 404 itself from
|
||||
`ngOnInit`, once its input has arrived.
|
||||
|
||||
**`@pi/ui`'s reset spaces every `li + li`** with a top margin — right for a
|
||||
list of prose, wrong for a row of chips laid out with `gap`, where it dropped
|
||||
every chip but the first. Lists spaced by `gap` reset it on their own `> li`.
|
||||
|
||||
**Empty sections disappear**, along with their entry in the nav — a young site
|
||||
shows a hero and a contact form rather than eight headings over nothing.
|
||||
@@ -202,14 +208,29 @@ page cached with `s-maxage` that varied on `Accept-Language` would hand the
|
||||
second visitor the wrong language anyway. The switcher in the header is three
|
||||
plain links, and `<html lang>` follows.
|
||||
|
||||
**Content pages are the exception**, because the API decides their address: a
|
||||
page's `path` and `alternates` put the default language unprefixed and every
|
||||
other one under its code — `/sobre-nosotros`, `/en/about-us`, `/ca/qui-som` —
|
||||
so those are the routes that answer. `core/api.ts#contentRoute` is the one rule
|
||||
for that shape; `/es/…` is not one of them, so a page has one address rather
|
||||
than two. The switcher on a page follows `alternates`, and a language the page
|
||||
has no translation for leads to the landing in that language instead of a 404.
|
||||
The same `alternates` become `hreflang` links, with a `canonical`.
|
||||
**Records are the exception**, because the API decides their address: a
|
||||
record's `path` and `alternates` put the default language unprefixed and every
|
||||
other one under its code, pages at the root and everything else under a section
|
||||
named in that language:
|
||||
|
||||
```
|
||||
/sobre-nosotros /en/about-us /ca/qui-som
|
||||
/proyectos/catalogo /en/projects/catalogo /ca/projectes/catalogo
|
||||
/equipo/ada /en/team/ada /ca/equip/ada
|
||||
```
|
||||
|
||||
`core/routes.ts#resolveRoute` is that rule read backwards, and its `SECTIONS`
|
||||
mirror the API's `config/site.php` (`paths`) — a change there has to be made
|
||||
here too. `/es/…` is not a shape the API produces, so a record has one address
|
||||
rather than two. The switcher on a record follows `alternates`, and a language
|
||||
it has no translation for leads to the landing in that language instead of a
|
||||
404. The same `alternates` become `hreflang` links, with a `canonical`.
|
||||
|
||||
**One catch-all route** (`pages/[...path]`) serves every address but the
|
||||
landing, and `resolveRoute` sorts the shapes out. Not one route per shape:
|
||||
Analog registers each loader as an internal Nitro route, and Nitro's router
|
||||
cannot hold two parameters of different names at the same depth —
|
||||
`/:prefix/:slug` beside `/:prefix/:section/:slug` made the first unreachable.
|
||||
|
||||
Featured pages go in the header after the section anchors; every page is in the
|
||||
footer.
|
||||
|
||||
Reference in New Issue
Block a user