Skip to content

Commit c8025a4

Browse files
author
DavidQ
committed
Restore the missing filter UI and full phase listing on /samples/index.html.
Keep the shared style/header consistency work intact while restoring expected samples page behavior. PR: BUILD_PR_STYLE_SAMPLES_INDEX_FILTER_AND_PHASE_LIST_RESTORE
1 parent 60e25e6 commit c8025a4

6 files changed

Lines changed: 216 additions & 47 deletions

File tree

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
Samples index restore strategy
2+
3+
Goal:
4+
- restore missing filter UI
5+
- restore full phase listing
6+
- keep shared style migration intact
7+
8+
Compare against:
9+
- prior known-good samples index behavior if available
10+
- current rendered DOM/data path
11+
- current header/body/shared-shell changes
12+
13+
Keep scope surgical and behavior-focused.

docs/operations/dev/codex_commands.md

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,22 @@ MODEL: GPT-5.4-codex
22
REASONING: high
33

44
COMMAND:
5-
Create BUILD_PR_STYLE_INDEX_HEADER_AND_BODY_CONSISTENCY_FIX
5+
Create BUILD_PR_STYLE_SAMPLES_INDEX_FILTER_AND_PHASE_LIST_RESTORE
66

77
Rules:
88
- output ONLY the final zip to:
9-
<project folder>/tmp/BUILD_PR_STYLE_INDEX_HEADER_AND_BODY_CONSISTENCY_FIX.zip
9+
<project folder>/tmp/BUILD_PR_STYLE_SAMPLES_INDEX_FILTER_AND_PHASE_LIST_RESTORE.zip
1010
- do NOT create staging folders in <project folder>/tmp
1111
- do NOT modify roadmap in the PR bundle
1212
- Codex updates roadmap during execution only if execution-backed status changes are earned
1313
- no embedded <style> blocks
1414
- no inline style=""
1515
- no JS-generated styling
16-
- keep scope limited to:
17-
/index.html
18-
/games/index.html
19-
/samples/index.html
20-
/tools/index.html only as needed for shared consistency
16+
- keep scope limited to /samples/index.html and directly related shared dependencies only
2117

2218
Required work:
23-
1. Treat /tools/index.html as the current good visual baseline.
24-
2. Compare it against /index.html, /games/index.html, and /samples/index.html.
25-
3. Normalize the three non-matching pages so the shared header stretches full width the same way.
26-
4. Normalize the three non-matching pages so the body/theme colors match the tools page.
27-
5. Prefer fixing shared CSS imports, body classes, and shared shell usage over ad hoc page-specific hacks.
28-
6. Keep the change narrow, testable, and visually consistent.
19+
1. Restore the filter UI on /samples/index.html if missing or hidden.
20+
2. Restore rendering of all phases on /samples/index.html.
21+
3. Verify filtering works correctly after restoration.
22+
4. Preserve the shared header/body consistency behavior.
23+
5. Keep the change narrow, testable, and behavior-restoring rather than redesigning.
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
Fix the main entry pages so they match the working tools/index.html baseline for full-width header behavior and shared body/theme colors.
1+
Restore the missing filter UI and full phase listing on /samples/index.html.
22

3-
Scope is limited to the four main entry pages and shared consistency fixes only.
3+
Keep the shared style/header consistency work intact while restoring expected samples page behavior.
44

5-
PR: BUILD_PR_STYLE_INDEX_HEADER_AND_BODY_CONSISTENCY_FIX
5+
PR: BUILD_PR_STYLE_SAMPLES_INDEX_FILTER_AND_PHASE_LIST_RESTORE
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# BUILD_PR_STYLE_SAMPLES_INDEX_FILTER_AND_PHASE_LIST_RESTORE
2+
3+
## Purpose
4+
Restore the missing samples filter UI and full phase listing on `/samples/index.html` after the shared style migration work.
5+
6+
## Single PR Purpose
7+
Fix `/samples/index.html` so it shows:
8+
- the filter controls
9+
- all phases
10+
11+
## Confirmed Symptom
12+
`/samples/index.html` currently does not show:
13+
- the filter
14+
- all phases
15+
16+
## Required Fix Direction
17+
1. Restore the filter UI if it is missing or hidden.
18+
2. Restore the full phase list if it is truncated, filtered incorrectly, or not rendering all groups.
19+
3. Keep the page aligned with the shared style system.
20+
4. Do not redesign the page.
21+
5. Prefer restoring existing functionality over inventing new behavior.
22+
23+
## Likely Root Causes To Check
24+
- filter markup removed or not mounted
25+
- filter hidden by CSS or collapsible behavior
26+
- wrong body/page-shell classes interfering with visibility
27+
- sample list data source not fully loaded
28+
- phase grouping loop broken
29+
- CSS selector collision hiding sections
30+
- page script not running or mounting expected controls
31+
- over-aggressive refactor from the entry-page consistency work
32+
33+
## Required Rules
34+
- no embedded `<style>` blocks
35+
- no inline `style=""`
36+
- no JS-generated styling
37+
- keep scope limited to `/samples/index.html` and its directly related shared script/CSS dependencies only
38+
- preserve the new shared header/body consistency work
39+
- restore behavior, do not redesign
40+
41+
## Acceptance
42+
- `/samples/index.html` shows the filter UI
43+
- `/samples/index.html` shows all phases
44+
- filtering behavior works as intended
45+
- page remains aligned with the shared style system
46+
- no regressions to header/body consistency
47+
- change is visually testable

samples/index.html

Lines changed: 8 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -31,47 +31,24 @@ <h1>Samples Hub</h1>
3131
</details>
3232

3333
<main class="page-shell">
34-
3534
<section class="content-section">
36-
<h2>Core Phases</h2>
37-
<div class="card-grid">
38-
<a class="card-link" href="./phase-01/0101/index.html">
39-
<h3>Phase 01</h3>
40-
<p>Core engine loop, input, rendering, and foundational ECS patterns.</p>
41-
</a>
42-
<a class="card-link" href="./phase-02/0201/index.html">
43-
<h3>Phase 02</h3>
44-
<p>World systems, camera behavior, and visual/runtime progression samples.</p>
45-
</a>
46-
<a class="card-link" href="./phase-03/0301/index.html">
47-
<h3>Phase 03</h3>
48-
<p>Extended systems and integration slices for gameplay scaffolding.</p>
49-
</a>
50-
</div>
35+
<h2>Filter Phases</h2>
36+
<p>Filter by phase number, phase title, or description.</p>
37+
<label for="samples-phase-filter-input">Search</label>
38+
<input id="samples-phase-filter-input" type="text" placeholder="Phase 17, rendering, runtime..." autocomplete="off" />
39+
<p id="samples-phase-filter-status" aria-live="polite"></p>
5140
</section>
5241

5342
<section class="content-section">
54-
<h2>Advanced Phases</h2>
55-
<div class="card-grid">
56-
<a class="card-link" href="./phase-16/1601/index.html">
57-
<h3>Phase 16</h3>
58-
<p>3D support and debug-oriented execution slices.</p>
59-
</a>
60-
<a class="card-link" href="./phase-17/1701/index.html">
61-
<h3>Phase 17</h3>
62-
<p>Advanced rendering and gameplay sample expansion lane.</p>
63-
</a>
64-
<a class="card-link" href="./phase-19/1901/index.html">
65-
<h3>Phase 19</h3>
66-
<p>Runtime and integration validation-focused samples.</p>
67-
</a>
68-
</div>
43+
<h2>All Phases</h2>
44+
<div id="samples-phase-list" class="card-grid"></div>
6945
</section>
7046

7147
<div class="footer-note">
7248
Open sample pages through a local web server for stable module and asset loading.
7349
</div>
7450
</main>
7551
<script type="module" src="../src/engine/theme/mount-shared-header.js"></script>
52+
<script type="module" src="./index.render.js"></script>
7653
</body>
7754
</html>

samples/index.render.js

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
const METADATA_PATH = "./metadata/samples.index.metadata.json";
2+
const BASE_PHASES = [
3+
"01", "02", "03", "04", "05", "06", "07", "08", "09", "10",
4+
"11", "12", "13", "14", "15", "16", "17", "18", "19"
5+
];
6+
const PHASE_FALLBACK_DETAILS = {
7+
"16": {
8+
title: "Phase 16 - 3D Foundations",
9+
description: "3D execution track including camera, input, lighting, and runtime debug slices."
10+
},
11+
"17": {
12+
title: "Phase 17 - Advanced 3D + Gameplay",
13+
description: "Extended rendering and gameplay-focused 3D samples with integrated debug surfaces."
14+
},
15+
"18": {
16+
title: "Phase 18 - Runtime Hardening",
17+
description: "Runtime and boundary hardening slices that preserve engine/shared separation."
18+
},
19+
"19": {
20+
title: "Phase 19 - Integration Validation",
21+
description: "System integration and lifecycle validation for stable execution flow."
22+
}
23+
};
24+
25+
export function normalize(value) {
26+
return typeof value === "string" ? value.trim() : "";
27+
}
28+
29+
export function dedupeSortedPhases(samples, phaseDetails) {
30+
const phaseSet = new Set();
31+
for (const detail of phaseDetails) {
32+
const id = normalize(detail.phase);
33+
if (/^\d{2}$/.test(id)) {
34+
phaseSet.add(id);
35+
}
36+
}
37+
for (const sample of samples) {
38+
const id = normalize(sample.phase);
39+
if (/^\d{2}$/.test(id)) {
40+
phaseSet.add(id);
41+
}
42+
}
43+
return [...phaseSet].sort((a, b) => Number(a) - Number(b));
44+
}
45+
46+
export function buildPhaseRows(metadata) {
47+
const samples = Array.isArray(metadata?.samples) ? metadata.samples : [];
48+
const phaseDetails = Array.isArray(metadata?.phases) ? metadata.phases : [];
49+
const detailByPhase = new Map(
50+
phaseDetails
51+
.map((detail) => [normalize(detail.phase), detail])
52+
.filter(([phase]) => /^\d{2}$/.test(phase))
53+
);
54+
const phases = dedupeSortedPhases(samples, phaseDetails);
55+
for (const basePhase of BASE_PHASES) {
56+
phases.push(basePhase);
57+
}
58+
const normalizedPhases = [...new Set(phases)].sort((a, b) => Number(a) - Number(b));
59+
return normalizedPhases.map((phase) => {
60+
const sampleCount = samples.filter((entry) => normalize(entry.phase) === phase).length;
61+
const detail = detailByPhase.get(phase) || PHASE_FALLBACK_DETAILS[phase];
62+
const title = normalize(detail?.title) || `Phase ${phase}`;
63+
const description =
64+
normalize(detail?.description) || "Phase content available in the sample lane.";
65+
return {
66+
phase,
67+
href: `./phase-${phase}/${phase}01/index.html`,
68+
title,
69+
description
70+
};
71+
});
72+
}
73+
74+
export function renderPhaseCards(container, rows) {
75+
container.innerHTML = "";
76+
for (const row of rows) {
77+
const card = document.createElement("a");
78+
card.className = "card-link";
79+
card.href = row.href;
80+
card.dataset.phase = row.phase;
81+
card.innerHTML = `<h3>${row.title}</h3><p>${row.description}</p>`;
82+
container.appendChild(card);
83+
}
84+
}
85+
86+
export function filterPhaseRows(rows, query) {
87+
const normalizedQuery = normalize(query).toLowerCase();
88+
if (!normalizedQuery) {
89+
return rows;
90+
}
91+
return rows.filter((row) => {
92+
const haystack = `${row.phase} ${row.title} ${row.description}`.toLowerCase();
93+
return haystack.includes(normalizedQuery);
94+
});
95+
}
96+
97+
export function updateStatus(statusNode, shown, total, query) {
98+
const label = normalize(query);
99+
if (!label) {
100+
statusNode.textContent = `Showing all ${total} phases.`;
101+
return;
102+
}
103+
statusNode.textContent = `Showing ${shown} of ${total} phases for "${label}".`;
104+
}
105+
106+
export async function initSamplesIndex() {
107+
const container = document.getElementById("samples-phase-list");
108+
const input = document.getElementById("samples-phase-filter-input");
109+
const statusNode = document.getElementById("samples-phase-filter-status");
110+
if (!container || !input || !statusNode) {
111+
return;
112+
}
113+
114+
try {
115+
const response = await fetch(METADATA_PATH, { cache: "no-store" });
116+
if (!response.ok) {
117+
throw new Error(`Failed to load samples metadata (${response.status})`);
118+
}
119+
const metadata = await response.json();
120+
const allRows = buildPhaseRows(metadata);
121+
const applyFilter = () => {
122+
const filteredRows = filterPhaseRows(allRows, input.value);
123+
renderPhaseCards(container, filteredRows);
124+
updateStatus(statusNode, filteredRows.length, allRows.length, input.value);
125+
};
126+
input.addEventListener("input", applyFilter);
127+
applyFilter();
128+
} catch (error) {
129+
container.innerHTML = "";
130+
statusNode.textContent = "Unable to load phase list. Verify local server access to sample metadata.";
131+
console.error(error);
132+
}
133+
}
134+
135+
if (typeof window !== "undefined" && typeof document !== "undefined") {
136+
initSamplesIndex();
137+
}

0 commit comments

Comments
 (0)