Enhance contributing guidelines in CONTRIBUTING.md with a readable link, update curriculum JSON structure to include chapter tiers, and improve catalog chapter card display with tier badges. Update package.json for testing scripts and add contributing URL in zola.toml. Refactor frontend components and styles for better integration of new features.

This commit is contained in:
Hananoshika Yomaru 2026-05-19 05:34:25 -07:00
parent 8c986c1ed7
commit 81b316e08d
33 changed files with 6944 additions and 152 deletions

View file

@ -1,6 +1,6 @@
import { For, Show } from "solid-js";
import type { CatalogChapter } from "../../../data/catalog.types";
import { curriculumBadgeClass } from "../lib/catalog-badge";
import { curriculumBadgeClass, tierBadgeLabel } from "../lib/catalog-badge";
export type CatalogChapterCardProps = {
chapter: CatalogChapter;
@ -24,6 +24,14 @@ function appendMeta(parent: HTMLElement, chapter: CatalogChapter) {
meta.appendChild(badge);
}
const tierLabel = tierBadgeLabel(chapter.tier);
if (tierLabel) {
const tier = document.createElement("span");
tier.className = "catalog-badge catalog-badge--extension";
tier.textContent = tierLabel;
meta.appendChild(tier);
}
if (chapter.status === "planned") {
const soon = document.createElement("span");
soon.className = "book-chapter-badge book-chapter-badge--planned";
@ -154,6 +162,9 @@ export function CatalogChapterCard(props: CatalogChapterCardProps) {
<span class={`catalog-badge ${curriculumBadgeClass(curriculum)}`}>{curriculum}</span>
)}
</For>
<Show when={tierBadgeLabel(props.chapter.tier)}>
{(label) => <span class="catalog-badge catalog-badge--extension">{label()}</span>}
</Show>
<Show when={props.chapter.status === "planned"}>
<span class="book-chapter-badge book-chapter-badge--planned">Coming soon</span>
</Show>

View file

@ -0,0 +1,166 @@
import { createSignal, Show } from "solid-js";
import { render } from "solid-js/web";
const GRAPH_EDGES: Array<{ from: string; to: string }> = [
{ from: "quadratic", to: "sequences" },
{ from: "quadratic", to: "functions" },
{ from: "sequences", to: "linear-programming" },
{ from: "functions", to: "linear-programming" },
];
function GraphPrereqDemo() {
const [focus, setFocus] = createSignal<string | null>(null);
const nodeLit = (id: string) => {
const active = focus();
if (!active) return false;
if (id === active) return true;
return GRAPH_EDGES.some(
(edge) =>
(edge.from === active && edge.to === id) || (edge.from === id && edge.to === active)
);
};
const toggle = (id: string) => setFocus((prev) => (prev === id ? null : id));
return (
<div class="contributing-graph-demo" aria-label="Interactive prerequisite graph example">
<p class="contributing-demo__hint">
Click a topic to highlight its prerequisites and follow-on chapters.
</p>
<div class="contributing-graph-demo__layout">
<button
type="button"
class="contributing-graph-demo__node contributing-graph-demo__node--root"
classList={{ "is-lit": nodeLit("quadratic") }}
onClick={() => toggle("quadratic")}
>
Quadratic equations
</button>
<span class="contributing-graph-demo__fork" aria-hidden="true">
↙
<span class="contributing-graph-demo__fork-line" />
↘
</span>
<div class="contributing-graph-demo__row">
<button
type="button"
class="contributing-graph-demo__node"
classList={{ "is-lit": nodeLit("sequences") }}
onClick={() => toggle("sequences")}
>
Sequences
</button>
<button
type="button"
class="contributing-graph-demo__node"
classList={{ "is-lit": nodeLit("functions") }}
onClick={() => toggle("functions")}
>
Functions
</button>
</div>
<span class="contributing-graph-demo__join" aria-hidden="true">
↘
<span class="contributing-graph-demo__join-line" />
↙
</span>
<button
type="button"
class="contributing-graph-demo__node contributing-graph-demo__node--merge"
classList={{ "is-lit": nodeLit("linear-programming") }}
onClick={() => toggle("linear-programming")}
>
Linear programming
</button>
</div>
</div>
);
}
function CatalogViewsDemo() {
const [view, setView] = createSignal<"list" | "map">("list");
return (
<div class="contributing-views-demo" aria-label="Catalog list and map views">
<div class="contributing-views-demo__tabs" role="tablist" aria-label="Preview catalog views">
<button
type="button"
role="tab"
class="contributing-views-demo__tab"
classList={{ "is-active": view() === "list" }}
aria-selected={view() === "list"}
onClick={() => setView("list")}
>
List
</button>
<button
type="button"
role="tab"
class="contributing-views-demo__tab"
classList={{ "is-active": view() === "map" }}
aria-selected={view() === "map"}
onClick={() => setView("map")}
>
Map
</button>
</div>
<div class="contributing-views-demo__panel" role="tabpanel">
<Show
when={view() === "list"}
fallback={
<div class="contributing-views-demo__map">
<div class="contributing-views-demo__map-col">
<span class="contributing-views-demo__strand">Number &amp; Algebra</span>
<span class="contributing-views-demo__map-node is-root">Directed numbers</span>
<span class="contributing-views-demo__map-arrow" aria-hidden="true">
↓
</span>
<span class="contributing-views-demo__map-node">Quadratic equations</span>
<span class="contributing-views-demo__map-fork" aria-hidden="true">
↙ ↘
</span>
<div class="contributing-views-demo__map-row">
<span class="contributing-views-demo__map-node is-small">Sequences</span>
<span class="contributing-views-demo__map-node is-small">Functions</span>
</div>
</div>
<p class="contributing-views-demo__caption">
Arrows come from <code>graph.edges</code> only — strand order in JSON does not draw
links.
</p>
</div>
}
>
<ol class="contributing-views-demo__list">
<li>
<span class="contributing-views-demo__list-num">01</span>
<span class="contributing-views-demo__list-title">Quadratic equations</span>
<span class="contributing-views-demo__list-badge">DSE</span>
</li>
<li>
<span class="contributing-views-demo__list-num">02</span>
<span class="contributing-views-demo__list-title">Sequences &amp; series</span>
<span class="contributing-views-demo__list-badge is-muted">Coming soon</span>
</li>
</ol>
<p class="contributing-views-demo__caption">
List order follows the <code>chapters[]</code> array — your table of contents.
</p>
</Show>
</div>
</div>
);
}
export function mountContributingDemos() {
const graphRoot = document.getElementById("contributing-demo-graph");
if (graphRoot) {
render(() => <GraphPrereqDemo />, graphRoot);
}
const viewsRoot = document.getElementById("contributing-demo-views");
if (viewsRoot) {
render(() => <CatalogViewsDemo />, viewsRoot);
}
}