mirror of
https://github.com/HananoshikaYomaru/openfreebooks.git
synced 2026-11-13 21:15:54 +00:00
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:
parent
8c986c1ed7
commit
81b316e08d
33 changed files with 6944 additions and 152 deletions
|
|
@ -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>
|
||||
|
|
|
|||
166
frontend/src/components/contributing-demos.tsx
Normal file
166
frontend/src/components/contributing-demos.tsx
Normal 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 & 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 & 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);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue