Skip to content

Commit 63d3e52

Browse files
author
DavidQ
committed
Tighten the samples index metadata and filter/tile UX behavior.
Make tags real, sort dropdowns alphabetically with no duplicates, keep classes out of the description text, and use explicit Pinned/Unpinned text values while preserving preview-image launch behavior. PR: BUILD_PR_SAMPLES_METADATA_TAG_NORMALIZATION_AND_FILTER_BAR_UX
1 parent 9c5f542 commit 63d3e52

9 files changed

Lines changed: 244 additions & 124 deletions

docs/dev/reports/samples_metadata_and_filter_bar_strategy.txt

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,13 @@ Samples metadata + filter/tile UX strategy
33
Goals:
44
- convert tags into real metadata
55
- keep class as a broad category
6-
- surface class values clearly
7-
- sort class filter values alphabetically
6+
- keep classes separate from description text
7+
- sort dropdown values alphabetically with no duplicates
88
- keep search on the same row as Phase/Class/Tag
9-
- move pin affordance to preview top-right if cleanly supported
10-
- use green for pinned state
9+
- use explicit Pinned/Unpinned text instead of colored pin icons
10+
- preserve preview image launch behavior
11+
- preserve hover zoom behavior
1112

1213
Preserve:
1314
- current accepted page shell
14-
- preview image launch behavior
15-
- hover zoom behavior
1615
- shared header/body consistency

docs/operations/dev/codex_commands.md

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,12 @@ Rules:
1919
Required work:
2020
1. Normalize sample metadata so tags are real descriptive tags instead of duplicates of class values.
2121
2. Keep/assign a clear class value for each sample.
22-
3. Include/display the class list for each sample.
23-
4. Ensure class filter values are sorted alphabetically.
24-
5. Put search on the same row as Phase, Class, and Tag.
25-
6. Move the pin affordance to the top-right over the preview image if the current tile structure allows it cleanly.
26-
7. Make the pinned visual state green instead of red.
27-
8. Preserve preview image launch behavior and hover zoom.
28-
9. Keep filtering and pinning behavior working.
29-
10. Keep the change narrow, testable, and behavior-focused rather than redesigning the page.
22+
3. If classes are shown for each sample, show them outside the description text.
23+
4. Do NOT append classes/tags/phase metadata into the sample description body.
24+
5. Ensure class filter values are sorted alphabetically and contain no duplicates.
25+
6. Ensure tag filter values are sorted alphabetically and contain no duplicates.
26+
7. Put search on the same row as Phase, Class, and Tag.
27+
8. Use explicit `Pinned` / `Unpinned` text values instead of a red/green icon treatment.
28+
9. Preserve preview image launch behavior and hover zoom.
29+
10. Keep filtering and pinning behavior working.
30+
11. Keep the change narrow, testable, and behavior-focused rather than redesigning the page.
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
Normalize samples metadata and tighten samples index filter/tile UX.
1+
Tighten the samples index metadata and filter/tile UX behavior.
22

3-
Convert tags into real descriptive tags, surface class values clearly, alphabetize class filter options, align search with Phase/Class/Tag, and move the pin affordance to the preview top-right with a green pinned state.
3+
Make tags real, sort dropdowns alphabetically with no duplicates, keep classes out of the description text, and use explicit Pinned/Unpinned text values while preserving preview-image launch behavior.
44

55
PR: BUILD_PR_SAMPLES_METADATA_TAG_NORMALIZATION_AND_FILTER_BAR_UX

docs/pr/BUILD_PR_SAMPLES_METADATA_TAG_NORMALIZATION_AND_FILTER_BAR_UX.md

Lines changed: 42 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -6,55 +6,66 @@ Improve `/samples/index.html` sample discovery by normalizing metadata and tight
66
## Single PR Purpose
77
Fix the samples metadata and filter/tile behavior in one focused pass:
88
- make tags real tags instead of duplicated class values
9-
- expose the sample class list clearly
10-
- sort classes alphabetically
9+
- expose the sample class list correctly
10+
- sort dropdown values alphabetically with no duplicates
1111
- align search on the same row as Phase / Class / Tag
12-
- move the pin affordance to the top-right over the preview image if allowed by the current tile structure
13-
- use green instead of red when pinned
12+
- restore pin behavior using explicit text values instead of colored icons
13+
- keep preview image as the launch link with hover zoom
1414

1515
## Metadata Rules
1616
### Class
1717
- each sample must have a clear class value
1818
- class values should be broad categories
19-
- class options presented in the UI must be sorted alphabetically
19+
- class filter options presented in the UI must be sorted alphabetically
20+
- class filter options must not contain duplicates
2021

2122
### Tags
2223
- tags must be meaningful descriptive labels, not copies of class values
2324
- tags should reflect capabilities, behaviors, systems, or topics in the sample
24-
- examples:
25-
- physics
26-
- collision
27-
- parallax
28-
- networking
29-
- debug
30-
- editor
31-
- tilemap
32-
- input
33-
- particles
34-
- replay
25+
- tag filter options must be sorted alphabetically
26+
- tag filter options must not contain duplicates
3527
- tag filtering must use the real tag values
3628

37-
### Class List Visibility
38-
- include/display the class list for each sample
39-
- keep it readable and clearly distinct from tags
29+
### Class List Display
30+
- class information may be shown in a dedicated class area/list for each sample if needed
31+
- do NOT append or inject the class list into the main sample description text
32+
- the sample description must remain a human-readable description only
33+
34+
## Description Rule
35+
Do NOT include classes in the description text.
36+
37+
Example of what must NOT happen:
38+
`Phase 03 | Classes: ... | Tags: ...` appended into the description body.
39+
40+
Keep:
41+
- sample title
42+
- human-readable description
43+
44+
Separate from description if shown elsewhere:
45+
- phase
46+
- classes
47+
- tags
4048

4149
## Filter Bar UX Rules
4250
- search must be on the same line as:
4351
- Phase
4452
- Class
4553
- Tag
54+
- dropdown options must be alphabetically sorted
55+
- dropdown options must not contain duplicates
4656
- keep the filter bar compact and readable
4757
- preserve existing functionality
4858
- do not redesign the entire page
4959

50-
## Tile UX Rules
51-
### Pin
52-
- move pinned control/indicator to the top-right over the preview image if the tile structure allows it cleanly
53-
- pin should look like a pin, not a generic button
54-
- pinned visual state should change from red to green
55-
- preserve pinning behavior and pinned list behavior
60+
## Pin UX Rules
61+
- do NOT use a colored icon for pin/unpin state
62+
- pinned/unpinned must show explicit text values:
63+
- `Pinned`
64+
- `Unpinned`
65+
- pinning behavior and pinned list behavior must be preserved/restored
66+
- if placement over the preview image is retained, the text treatment must remain readable and clean
5667

57-
### Preview Image
68+
## Preview Image Rules
5869
- keep preview image as the launch anchor
5970
- preserve hover zoom behavior
6071
- do not break launch behavior
@@ -64,14 +75,14 @@ Fix the samples metadata and filter/tile behavior in one focused pass:
6475
- no inline `style=""`
6576
- no JS-generated styling
6677
- keep scope limited to `/samples/index.html` and directly related sample metadata/rendering/filter dependencies
67-
- preserve the accepted page shell and shared header/body consistency
78+
- preserve the current accepted page shell and shared header/body consistency
6879

6980
## Acceptance
7081
- tags are real descriptive tags, not class duplicates
71-
- class values/lists are clearly available and class filter options are alphabetical
82+
- class/tag dropdown values are alphabetical and contain no duplicates
83+
- classes are not appended into the description text
7284
- search is on the same line as Phase / Class / Tag
73-
- pinned control is top-right over the preview image when allowed
74-
- pinned state uses green, not red
75-
- preview image remains the launch anchor with hover zoom
85+
- pin state shows `Pinned` / `Unpinned` text, not red/green icon treatment
86+
- preview image remains the launch link with hover zoom
7687
- filtering and pinning continue to work
7788
- change is visually and functionally testable
Lines changed: 4 additions & 0 deletions
Loading

samples/index.css

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -64,23 +64,40 @@
6464
}
6565

6666
.sample-pin-label {
67-
position: absolute;
68-
top: 8px;
69-
right: 8px;
70-
z-index: 2;
7167
display: inline-flex;
7268
align-items: center;
7369
justify-content: center;
74-
min-width: 32px;
75-
min-height: 32px;
76-
border-radius: 999px;
77-
border: 1px solid rgba(34, 197, 94, 0.75);
78-
background: rgba(15, 23, 42, 0.72);
70+
min-width: 1.15em;
71+
min-height: 1.15em;
72+
margin-right: 8px;
73+
padding: 0;
7974
cursor: pointer;
8075
user-select: none;
76+
font-size: 1.15em;
77+
color: rgb(239, 68, 68);
8178
}
8279

8380
.sample-pin-toggle:checked + .sample-pin-label {
84-
background: rgba(34, 197, 94, 0.35);
85-
border-color: rgba(34, 197, 94, 0.95);
81+
color: rgb(34, 197, 94);
82+
}
83+
84+
.sample-title-row {
85+
display: flex;
86+
align-items: center;
87+
gap: 4px;
88+
}
89+
90+
.sample-pin-icon {
91+
display: inline-block;
92+
width: 1em;
93+
height: 1em;
94+
background-color: currentColor;
95+
-webkit-mask-image: url("./assets/icons/pin-monocolor.svg");
96+
-webkit-mask-repeat: no-repeat;
97+
-webkit-mask-position: center;
98+
-webkit-mask-size: contain;
99+
mask-image: url("./assets/icons/pin-monocolor.svg");
100+
mask-repeat: no-repeat;
101+
mask-position: center;
102+
mask-size: contain;
86103
}

samples/index.html

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,11 @@ <h1>Samples Hub</h1>
3232
</details>
3333

3434
<main class="page-shell">
35+
<section class="content-section">
36+
<h2>Pinned Samples</h2>
37+
<div id="samples-pinned-list" class="card-grid"></div>
38+
</section>
39+
3540
<section class="content-section">
3641
<h2>Filter Samples</h2>
3742
<p>Filter by phase, engine class, tag, or free-text search.</p>
@@ -62,11 +67,6 @@ <h2>Filter Samples</h2>
6267
<p id="samples-phase-filter-status" aria-live="polite"></p>
6368
</section>
6469

65-
<section class="content-section">
66-
<h2>Pinned Samples</h2>
67-
<div id="samples-pinned-list" class="card-grid"></div>
68-
</section>
69-
7070
<section class="content-section">
7171
<h2>All Phases and Samples</h2>
7272
<div id="samples-phase-list"></div>

samples/index.render.js

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,9 @@ function buildSampleRows(metadata, pinnedSet) {
8787
}
8888
const titleText = normalize(sample?.title) || "Untitled";
8989
const phaseInfo = phaseInfoMap.get(phase);
90-
const title = normalize(sample?.indexLabel) || `Sample ${id} - ${titleText}`;
90+
const explicitLabel = normalize(sample?.indexLabel);
91+
const titleAlreadyPrefixed = new RegExp(`^sample\\s+${id}\\s*-`, "i").test(titleText);
92+
const title = explicitLabel || (titleAlreadyPrefixed ? titleText : `Sample ${id} - ${titleText}`);
9193
const description = normalize(sample?.description) || "No description available.";
9294
const href = normalize(sample?.href) || `./phase-${phase}/${id}/index.html`;
9395
const tags = asArray(sample?.tags).map((tag) => normalizeTag(tag)).filter(Boolean);
@@ -191,27 +193,26 @@ function buildSampleCard(sample) {
191193
pinLabel.setAttribute("for", pinInputId);
192194
pinLabel.setAttribute("title", sample.pinned ? "Unpin" : "Pin");
193195
pinLabel.setAttribute("aria-label", sample.pinned ? "Unpin sample" : "Pin sample");
194-
pinLabel.textContent = "??";
196+
pinLabel.innerHTML = `<span class="sample-pin-icon" aria-hidden="true"></span>`;
195197

196198
previewWrap.appendChild(launch);
197-
previewWrap.appendChild(pinInput);
198-
previewWrap.appendChild(pinLabel);
199199

200200
const title = document.createElement("h3");
201-
title.innerHTML = `<a class="sample-title-link" href="${escapeHtml(sample.href)}">${escapeHtml(sample.title)}</a>`;
201+
title.className = "sample-title-row";
202+
title.appendChild(pinInput);
203+
title.appendChild(pinLabel);
204+
const titleLink = document.createElement("a");
205+
titleLink.className = "sample-title-link";
206+
titleLink.href = sample.href;
207+
titleLink.textContent = sample.title;
208+
title.appendChild(titleLink);
202209

203210
const description = document.createElement("p");
204211
description.textContent = sample.description;
205212

206-
const meta = document.createElement("p");
207-
const classLabel = sample.classTokens.length > 0 ? sample.classTokens.map((token) => token.label).join(", ") : "none";
208-
const tagLabel = sample.tags.length > 0 ? sample.tags.join(", ") : "none";
209-
meta.textContent = `Phase ${sample.phase} | Classes: ${classLabel} | Tags: ${tagLabel}`;
210-
211-
card.appendChild(previewWrap);
212213
card.appendChild(title);
214+
card.appendChild(previewWrap);
213215
card.appendChild(description);
214-
card.appendChild(meta);
215216
return card;
216217
}
217218

@@ -339,4 +340,4 @@ export async function initSamplesIndex() {
339340

340341
if (typeof window !== "undefined" && typeof document !== "undefined") {
341342
initSamplesIndex();
342-
}
343+
}

0 commit comments

Comments
 (0)