Files
cms-plugins/app/src/pages/cms/index.astro
T
Oleks bfc6a65638 fix(app): architecture + UI/UX review fixes
Multi-agent arch/UX review pass. Architecture: real HTTP 404 on not-found,
breadcrumb links by slug not lowercased title, CMS pages surface their
plugins, shared status taxonomy (src/lib/statuses.ts) consumed by all three
frontend consumers, data-driven status filter, typed emdash collections
(src/emdash-collections.d.ts), removed unused @astrojs/react + react deps and
dead pnpm block, tsconfig extends Astro strict preset, dev deps pruned from
the runtime image. UI/UX: fixed StatusBadge WCAG-AA contrast, labelled the
search/filter controls, canonical URL + BreadcrumbList JSON-LD + og:type,
human status labels, filtered result count + recoverable empty state,
auto-submit filters, mobile overflow fixes, skip-to-content, :focus-visible.

Commit the npm lockfile so the Dockerfile's `npm ci` path engages.
astro check: 0 errors / 0 warnings / 0 hints.
2026-06-02 03:24:52 +03:00

36 lines
1.2 KiB
Plaintext

---
import { getEmDashCollection } from "emdash";
import Base from "../../layouts/Base.astro";
export const prerender = false;
const { entries: cmses, cacheHint } = await getEmDashCollection("cmses", {
orderBy: { title: "asc" },
});
Astro.cache.set(cacheHint);
const PLUGIN_FETCH_CAP = 10000;
const { entries: plugins } = await getEmDashCollection("plugins", { limit: PLUGIN_FETCH_CAP });
if (plugins.length >= PLUGIN_FETCH_CAP) console.warn("[cms] plugin fetch hit cap", PLUGIN_FETCH_CAP, "- counts/lists may be truncated");
const countBySource = new Map<string, number>();
const countByTarget = new Map<string, number>();
for (const p of plugins) {
const s = p.data.source_cms;
if (s) countBySource.set(s, (countBySource.get(s) ?? 0) + 1);
const t = p.data.target_cms;
if (t) countByTarget.set(t, (countByTarget.get(t) ?? 0) + 1);
}
---
<Base title="By CMS" description="Browse plugins grouped by source CMS.">
<h1>By CMS</h1>
<ul class="plugin-grid">
{cmses.map((c) => (
<li class="plugin-card">
<h3><a href={`/cms/${c.id}`}>{c.data.title}</a></h3>
<p class="meta">{countBySource.get(c.data.title) ?? 0} from · {countByTarget.get(c.data.title) ?? 0} targeting</p>
{c.data.description && <p>{c.data.description}</p>}
</li>
))}
</ul>
</Base>