Repository navigation
feat(site): render leveling section bullets as scannable cards - #6
Merged
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Intent
The original ask was that the Turtle Knowledge Base site is still too hard to digest and not user-friendly enough for players who want to learn their class, rotation, leveling, and how to play it well. The captain approved the investigation's full recommendation set.
For this slice, implement recommendation R9: emit each leveling section's top-level bullets as structured items[] beside its Markdown so Playstyle, Stats, Mistakes, Hardcore, and equivalent sections can render as scannable cards or lists without changing the prose.
What Changed
build-data.pynow emits a leveling section's unindented Markdown bullets as anitems[]array beside the unchanged verbatimmarkdown, withcheck-data.mjsvalidating the field on generated data andtypes.tsdeclaring it optional.LevelingPagerenders sections that haveitemsas a two-column card grid of the bullets while keeping the framing prose above, and falls back to a single prose card when a section has no bullets or omitsitems.classes.json/meta.jsonand updatedPLAN.mdandsrc/data/README.mdto document the newitemsview.Risk Assessment
✅ Low: The fix is small, data-verified, and resolves exactly the reported prose-loss cases without changing any markdown or the generated-data contract.
Testing
Stood the site up with the real generator plus a production
vite preview(generated data) and aVITE_USE_FIXTURES=1build, then drove the leveling pages in headless Chrome. The generator re-emitted the committed items arrays deterministically; the generated-data validator rejects a leveling section missing items while the fixture validator accepts omitted items; and the browser renders top-level bullets as card grids for Playstyle/Stats/Mistakes/Route/Hardcore while displaying the preserved non-bullet framing prose (verified on rogue Route, rogue Hardcore and warlock Professions) and falling back to full Markdown when items are absent. Screenshots capture the rendered surfaces.python3 site/scripts/build-data.pyregenerated classes.json identical to the committed file (only meta.json's timestamp changed) and an independent extraction confirmed all 99 leveling sections' ite…itemsfrom warrior leveling section 0 madenode scripts/check-data.mjsexit 1 with 'classes[0] (warrior).leveling.sections[0]: leveling sections must include an items array'; the original…node scripts/check-data.mjs --fixturesexits 0 with 'contract OK', andnode scripts/smoke.mjs --fixturesrenders 11 routes with 0 failures.vite previewbuild,section#lv-statscontained oneulwith 5li.card,section#lv-hardcoreoneulwith 6 cards, and warlocksection#lv-routeoneulwith 4 profession…section#lv-press, items absent) rendered its full Markdown including###subheadings with noul; the fixture build of the warrior leveling page (section#lv-press) li…Pipeline
Updates from git push no-mistakes
✅ **intent** - passed
✅ No issues found.
✅ **Rebase** - passed
✅ No issues found.
🔧 **Review** - 2 issues found → auto-fixed ✅
site/src/pages/LevelingPage.tsx:27- When a leveling section has any top-level bullet, Prose renders only s.items and never renders s.markdown, so the section's non-bullet prose silently disappears from the page (there is no ProseDetails fallback for press/stats/dont/route/hardcore sections). Concrete occurrences in the committed data: rogue 'Route' loses 'The corpus gives only fragments, not a zone-by-zone route:'; rogue 'Hardcore-mode differences' loses 'Rogue is discussed as one of the easier Hardcore classes because of its escape kit, in contrast to Warrior:'; warlock 'Professions' loses 'No profession advice exists in the Warlock forum itself; the only sourced guidance is from the Hardcore Lounge'. The intent says these sections should render as scannable cards 'without changing the prose'; the Markdown is preserved in data but the displayed prose is truncated, so the user cannot read those lead-in sentences at all. This is a product decision (render the non-bullet prose alongside the cards vs. intentionally drop framing sentences), so it needs the author's call rather than a mechanical fix.site/scripts/check-data.mjs:86- checkLevelingSection now hard-requires anitemskey on every leveling section, but the committed development fixtures (site/src/data/fixtures/classes.json) intentionally omititems— the updated PLAN.md and site/src/data/README.md both state 'development fixtures omititems'. Running the validator against the documented fixture fallback (node scripts/check-data.mjs --fixtures) therefore fails with 'leveling sections must include an items array', a regression from the previous checkSection which accepted them. Make the absent-items case valid when validating fixtures (or additemsto the fixtures) so the documented fixture contract still validates.🔧 Fix applied.
✅ Re-checked - no issues remain.
✅ **Test** - passed
✅ No issues found.
python3 site/scripts/build-data.pyregenerated classes.json identical to the committed file (only meta.json's timestamp changed) and an independent extraction confirmed all 99 leveling sections' ite…itemsfrom warrior leveling section 0 madenode scripts/check-data.mjsexit 1 with 'classes[0] (warrior).leveling.sections[0]: leveling sections must include an items array'; the original…node scripts/check-data.mjs --fixturesexits 0 with 'contract OK', andnode scripts/smoke.mjs --fixturesrenders 11 routes with 0 failures.vite previewbuild,section#lv-statscontained oneulwith 5li.card,section#lv-hardcoreoneulwith 6 cards, and warlocksection#lv-routeoneulwith 4 profession…section#lv-press, items absent) rendered its full Markdown including###subheadings with noul; the fixture build of the warrior leveling page (section#lv-press) li…python3 scrape/validate.py && python3 site/scripts/test_data.py && cd site && npm ci && npm run check && npm run smokepython3 site/scripts/build-data.py(regenerated classes.json byte-identical to committed data; items deterministic)node scripts/check-data.mjs(generated contract OK, 9 classes/9 leveling guides)node scripts/check-data.mjs --fixtures(fixture contract OK with items omitted)Adversarial: deleteditemsfrom warrior leveling section 0 and rerannode scripts/check-data.mjs-> exit 1 with 'leveling sections must include an items array'; restored fileSemantic check over committedclasses.json: all 99 leveling sections'itemsequal the^[-*+]\s+(\S.*)$extraction of the section Markdown (254 items, 0 mismatches)npm run smoke(78 routes rendered, 0 failures) andnode scripts/smoke.mjs --fixtures(11 routes, 0 failures)Live browser via chrome-devtools-axi/CDP againstvite previewof the generated build (http://localhost:4188) and the fixture build (http://localhost:4189): DOM countedul/li.cardpersection[id^=lv-], asserted framing text presence, and full-page screenshots✅ **Document** - passed
✅ No issues found.
✅ **Lint** - passed
✅ No issues found.
✅ **Push** - passed
✅ No issues found.