mirror of
https://github.com/nexu-io/open-design.git
synced 2026-05-31 19:04:39 +07:00
The 2026-05 plugins rebuild left three homepage/library surfaces still pointing at the retired `/skills/`, `/systems/`, and `/craft/` route trees, so visitors hit a 301 hop (or a stale facet) instead of landing directly on the new `/plugins/*` pages. Repoint them at the canonical destinations and align the homepage Labs pills with the real library. - system-card: link straight to `/plugins/design-system-<slug>/` via a new `detailHrefForSystemSlug` resolver instead of hard-coding `/systems/<slug>/` and relying on the redirect. The ~8 systems that ship no manifest (hence no detail page) degrade to `/plugins/systems/`, the same destination the legacy 301 produced, minus the hop and with no risk of linking at a page that doesn't exist. - homepage Labs pills: replace the hard-coded prototype/deck/mobile/office facets (mobile/office had drifted to stale or empty counts) with a live top-4 of `PLUGIN_CATEGORIES`, counted with the same `categorizePlugin` rule `/plugins/templates/` uses and labelled from `pcopy.category`, so the homepage stays in lockstep with the library and never shows a dead chip. Counts are surfaced through a new `CatalogCounts.templateCategories`. - remove the Craft entry points from the homepage footer, sub-page footer, header Library dropdown, and the plugins hub tile grid. The `/craft/` pages stay live; they're just no longer surfaced in site chrome. The legacy `/skills/`, `/systems/`, `/templates/` 301s added in the prior PR stay in place for inbound links and search equity. Co-authored-by: Joey-nexu <joeylee12629@gmail.com>
105 lines
4.1 KiB
Text
105 lines
4.1 KiB
Text
---
|
|
/*
|
|
* /plugins/ — top-level plugin library hub.
|
|
*
|
|
* Replaces the prior `/skills/`, `/templates/`, `/systems/`, `/craft/`
|
|
* top-level entries with a single library that mirrors how the in-app
|
|
* Plugins home is organised: artifact-producing entries under
|
|
* Templates, instruction-only skills under Skills, brand systems under
|
|
* Systems, craft principles under Craft. Visitors who land here can
|
|
* mentally map the catalogue to what they will see when they open
|
|
* Open Design itself.
|
|
*
|
|
* Anyone who already knows the slug they want skips the hub entirely
|
|
* via `/skills/<slug>/`, `/templates/<slug>/` etc. Detail-page URLs
|
|
* stay where they are; the hub is purely a discovery surface.
|
|
*/
|
|
import Layout from '../../_components/sub-page-layout.astro';
|
|
import { getCraftRecords, getSystemRecords } from '../../_lib/catalog';
|
|
import { getBundledPlugins } from '../../_lib/bundled-plugins';
|
|
import { categorizePlugin, bundledRecordOf } from '../../_lib/plugin-facets';
|
|
import { getPluginsCopy } from '../../_lib/plugins-i18n';
|
|
import { localeFromPath, localizedHref } from '../../i18n';
|
|
|
|
const locale = localeFromPath(Astro.url.pathname);
|
|
const href = (path: string) => localizedHref(path, locale);
|
|
const pcopy = getPluginsCopy(locale);
|
|
|
|
// Counts come from two sources because the underlying catalog pages
|
|
// each use whichever shape carries the data they render. Templates +
|
|
// Skills read `plugins/_official/` (the daemon's bundled-plugin
|
|
// registry, which is what the in-app Plugins home shows). Systems
|
|
// reads the legacy SystemRecord set so its detail rendering can keep
|
|
// using palette swatches from DESIGN.md — the bundled-plugin manifest
|
|
// doesn't carry palette data. The two design-systems data sources
|
|
// overlap 1:1 so the count stays consistent.
|
|
const [bundled, systems, craft] = await Promise.all([
|
|
Promise.resolve(getBundledPlugins()),
|
|
getSystemRecords(locale),
|
|
getCraftRecords(locale),
|
|
]);
|
|
|
|
const nonSystems = bundled.filter((p) => p.bucket !== 'design-systems');
|
|
const templatesSet = nonSystems.filter(
|
|
(p) => categorizePlugin(bundledRecordOf(p)) !== null,
|
|
);
|
|
const skillsSet = nonSystems.filter(
|
|
(p) => categorizePlugin(bundledRecordOf(p)) === null,
|
|
);
|
|
|
|
const templatesCount = templatesSet.length;
|
|
const skillsCount = skillsSet.length;
|
|
const systemsCount = systems.length;
|
|
const craftCount = craft.length;
|
|
const totalCount = templatesCount + skillsCount + systemsCount + craftCount;
|
|
|
|
const title = `${pcopy.hubLabel} · Open Design`;
|
|
const description = pcopy.hubLead;
|
|
|
|
const jsonLd = {
|
|
'@context': 'https://schema.org',
|
|
'@type': 'CollectionPage',
|
|
name: title,
|
|
description,
|
|
url: new URL('/plugins/', Astro.site).toString(),
|
|
isPartOf: {
|
|
'@type': 'WebSite',
|
|
name: 'Open Design',
|
|
url: Astro.site?.toString(),
|
|
},
|
|
numberOfItems: totalCount,
|
|
};
|
|
|
|
const tiles = [
|
|
{ href: href('/plugins/templates/'), title: pcopy.tileTemplates, count: templatesCount, blurb: pcopy.tileTemplatesBlurb, cta: pcopy.browseTemplates },
|
|
{ href: href('/plugins/skills/'), title: pcopy.tileSkills, count: skillsCount, blurb: pcopy.tileSkillsBlurb, cta: pcopy.browseSkills },
|
|
{ href: href('/plugins/systems/'), title: pcopy.tileSystems, count: systemsCount, blurb: pcopy.tileSystemsBlurb, cta: pcopy.browseSystems },
|
|
];
|
|
---
|
|
|
|
<Layout title={title} description={description} active="plugins" jsonLd={jsonLd}>
|
|
<header class="catalog-head">
|
|
<span class="label">{pcopy.hubLabel}</span>
|
|
<h1 class="display">
|
|
{pcopy.hubHeading(totalCount)}<span class="dot">.</span>
|
|
</h1>
|
|
<p class="lead">{pcopy.hubLead}</p>
|
|
</header>
|
|
|
|
<section class="plugins-tile-grid" aria-label={pcopy.hubLabel}>
|
|
{tiles.map((tile) => (
|
|
<a class="plugins-tile" href={tile.href}>
|
|
<div class="plugins-tile-head">
|
|
<h2 class="plugins-tile-title">{tile.title}</h2>
|
|
<span class="plugins-tile-count">{tile.count}</span>
|
|
</div>
|
|
<p class="plugins-tile-blurb">{tile.blurb}</p>
|
|
<span class="plugins-tile-cta">{tile.cta} →</span>
|
|
</a>
|
|
))}
|
|
</section>
|
|
</Layout>
|
|
|
|
{/* `.plugins-tile-grid` styles live in `app/sub-pages.css` so the
|
|
catch-all `[locale]/[...path].astro` can reuse them when rendering
|
|
the localized hub. */}
|