Site · Showcase: apps built with Ely, from the public Ely-GPUI-Showcases repo at a pinned commit

The build fetches showcase.lock's commit and runs the catalog's own validator. /showcase/ lists featured apps first, then the rest by newest or stars, with categories and search; /showcase/<id>/ shows previews, links and the README. The header drops its sound switch below 414px so the fourth link fits.
This commit is contained in:
ZacharyZhang-NY committed 2026-10-04 21:39:13 -04:00
1 parent 78bf5917a5
commit faf0987cf8
17 files changed
+567 -13

No files matched your search

+125
View File
@@ -0,0 +1,125 @@
import { Link } from "@tanstack/react-router";
import { useEffect, useState } from "react";
import { counts, cover, filtered, sorted, split, SUBMIT, type App, type Catalog, type Sort } from "../apps";
import data from "../showcase.json";
export const catalog = data as Catalog;
/** The day an app joined, as its manifest wrote it. */
export const joined = (app: App) =>
new Date(`${app.publishedAt.slice(0, 10)}T00:00:00Z`).toLocaleDateString("en-US", { year: "numeric", month: "short", day: "numeric", timeZone: "UTC" });
export const starCount = (n: number) => `${new Intl.NumberFormat("en-US", { notation: "compact" }).format(n)} ${n === 1 ? "star" : "stars"}`;
function Card({ app }: { app: App }) {
return (
<li className="app">
<Link to="/showcase/$app/" params={{ app: app.id }}>
<span className="app-shot">
<img src={cover(app)} alt="" loading="lazy" />
</span>
<span className="app-name">
{app.name}
{app.building && <span className="app-tag">Building</span>}
</span>
<span className="app-by">{app.author}</span>
<span className="app-text">{app.description}</span>
<span className="app-meta">
<span>{app.platforms.join(" · ")}</span>
{app.stars !== undefined && <span>{starCount(app.stars)}</span>}
<span>{joined(app)}</span>
</span>
</Link>
</li>
);
}
function Grid({ apps, label }: { apps: App[]; label: string }) {
return (
<ul className="apps" aria-label={label}>
{apps.map((a) => (
<Card key={a.id} app={a} />
))}
</ul>
);
}
export function Submit() {
return (
<section className="submit">
<h2>Built something with Ely?</h2>
<p>Add it by pull request to the showcase repository.</p>
<a className="button" href={SUBMIT} rel="noopener">
Submit your app
</a>
</section>
);
}
export function Showcase() {
const [query, setQuery] = useState("");
const [category, setCategory] = useState<string | null>(null);
const [sort, setSort] = useState<Sort>("newest");
useEffect(() => {
document.title = "Showcase · Ely";
}, []);
const { featured, rest } = split(catalog);
const searching = query.trim() !== "" || category !== null;
const found = sorted(filtered(catalog.apps, query, category), sort);
const empty = catalog.apps.length === 0;
return (
<>
<section className="showcase">
<h1>Showcase.</h1>
<p className="lede">Apps built with Ely.</p>
{empty ? (
<p className="none">No apps yet. Yours could be the first.</p>
) : (
<>
<input className="find" type="search" placeholder={`Search ${catalog.apps.length} apps`} aria-label="Search apps" value={query} onChange={(e) => setQuery(e.target.value)} onKeyDown={(e) => e.key === "Escape" && setQuery("")} />
<div className="filters">
<div className="chips" role="group" aria-label="Category">
<button className="chip" aria-pressed={category === null} onClick={() => setCategory(null)}>
All <span>{catalog.apps.length}</span>
</button>
{counts(catalog).map(([key, label, n]) => (
<button key={key} className="chip" aria-pressed={category === key} onClick={() => setCategory(key)}>
{label} <span>{n}</span>
</button>
))}
</div>
<div className="chips" role="group" aria-label="Sort">
<button className="chip" aria-pressed={sort === "newest"} onClick={() => setSort("newest")}>
Newest
</button>
<button className="chip" aria-pressed={sort === "stars"} onClick={() => setSort("stars")}>
Most stars
</button>
</div>
</div>
{searching ? (
found.length ? <Grid apps={found} label="Matching apps" /> : <p className="none">Nothing matches.</p>
) : (
<>
{featured.length > 0 && (
<>
<h2 className="apps-title">Featured</h2>
<Grid apps={featured} label="Featured apps" />
</>
)}
{rest.length > 0 && (
<>
<h2 className="apps-title">{featured.length ? "More apps" : "All apps"}</h2>
<Grid apps={sorted(rest, sort)} label={featured.length ? "More apps" : "All apps"} />
</>
)}
</>
)}
</>
)}
</section>
<Submit />
</>
);
}
+68
View File
@@ -0,0 +1,68 @@
import { Link, useParams } from "@tanstack/react-router";
import { useEffect } from "react";
import { catalog, joined, starCount, Submit } from "./Showcase";
import { NotFound } from "./NotFound";
export function ShowcaseApp() {
const { app: id } = useParams({ strict: false });
const app = catalog.apps.find((a) => a.id === id);
useEffect(() => {
if (app) document.title = `${app.name} · Showcase · Ely`;
}, [app]);
if (!app) return <NotFound what={`No app named ${id} in the showcase.`} />;
return (
<>
<article className="app-page">
<Link className="crumb" to="/showcase/">
← Showcase
</Link>
<h1>
{app.name}
{app.building && <span className="app-tag">Building</span>}
</h1>
<p className="app-by">{app.author}</p>
<p className="lede">{app.description}</p>
<div className="app-links">
{app.website && (
<a className="button" href={app.website} rel="noopener">
Website
</a>
)}
{app.source && (
<a className={app.website ? "text" : "button"} href={app.source} rel="noopener">
Source
</a>
)}
</div>
<dl className="app-facts">
<div>
<dt>Category</dt>
<dd>{catalog.categories[app.category]}</dd>
</div>
<div>
<dt>Platforms</dt>
<dd>{app.platforms.join(", ")}</dd>
</div>
{app.stars !== undefined && (
<div>
<dt>GitHub</dt>
<dd>{starCount(app.stars)}</dd>
</div>
)}
<div>
<dt>Added</dt>
<dd>{joined(app)}</dd>
</div>
</dl>
<div className="app-previews">
{app.previews.map((name, i) => (
<img key={name} src={`/showcase/${app.id}/${name}`} alt={`${app.name}, screenshot ${i + 1} of ${app.previews.length}`} loading={i ? "lazy" : "eager"} />
))}
</div>
{app.html && <div className="prose app-readme" dangerouslySetInnerHTML={{ __html: app.html }} />}
</article>
<Submit />
</>
);
}