Repository navigation
Add hub pages at /drink/, /menu/<family>/ and /shape/<pattern>/ - #126
Merged
Merged
Conversation
Every row on the Menu is written by app.js, so the front page linked none of the 185 drink pages under it. The sitemap listed them and nothing else did. scripts/pages.py now writes 25 hub pages beside the drink pages: /drink/ indexes every drink A to Z with its ingredient line, /menu/<family>/ is one section of the printed card and /shape/<pattern>/ is one of the shapes kin.py files. Both filings come from data/cocktails.json and data/kin.json, so neither is recomputed here and leadBottle stays in app.js. Every hub links every other hub with the count of drinks it holds. index.html links /drink/ from the Info tab and from the noscript fallback, and each drink page links the section and the shape it belongs to and the index. A drink page's BreadcrumbList is four steps now, from the front page down. Each hub carries a CollectionPage over an ItemList on the same #person and #website ids the rest of the site uses, and sitemap.xml lists 211 URLs with each hub dated by the newest drink it lists. stage.py reads which pages take the ?v= stamp off pages.OWNED rather than a regex of its own, and SERVED carries menu/ and shape/. check_assets.check_present fails on any local reference that does not resolve to a file, which catches a hub link with no page behind it; check_stamps fails on a served page that links the stylesheet with no stamp to land on; check_files resolves absolute paths, which it could not before. check_style.page_files and check_assets.served_texts read pages.OWNED, so the hubs are linted and dash-checked like the drink pages. pages.py refuses a section or shape id that is not a slug, and an orphaned hub is reported and deleted the same way an orphaned drink page is. test_checks.py goes from 316 to 322 cases. app.css adds .page__eyebrow a and .page__note a to the group that marks a link, because a bare anchor here inherits its colour and carries no underline. robots.txt, llms.txt, README.md and CLAUDE.md say where the hubs are, and CLAUDE.md records that a family id and a pattern id are stable keys now, like a cocktail id and a shelf bit.
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.
Every row on the Menu is written by
app.js, so the address a crawler reads atfewbottles.com/linked none of the 185 drink pages under it. The sitemap listed them and nothing else did. A sitemap is discovery only: it carries no anchor text, no context and no importance, so the drink pages sat as orphans off the one page with external links pointing at it, and any crawler that does not render JavaScript saw a site with no interior.This adds the pages that make that path exist, and the checks that keep it existing.
What is new
scripts/pages.pywrites 25 hub pages beside the 185 drink pages./drink/indexes every drink A to Z, each with the bottles that go in it./menu/<family>/is one section of the printed card. 15 of them, from Gin at 48 drinks to Absinthe at 1./shape/<pattern>/is one of the shapeskin.pyfiles. 9 of them, from Martini at 44 to Old-Fashioned at 8.Both filings are already data,
familyindata/cocktails.jsonandpatternindata/kin.json, so neither is recomputed here and a third filing is not invented.leadBottlestays inapp.js, because the All view is a view and not an address.The link graph this produces
Measured on the committed HTML, not asserted:
Those come from 185 links on
/drink/, 185 from the family hubs, 185 from the shape hubs and 1,110 from the kin lists the drink pages already carried. The front page still links no drink directly, which is correct, it links/drink/twice instead, so every drink page and every hub is two clicks from the front page in raw HTML with nothing running.Each hub also links every other hub with the count of drinks it holds, each drink page links the section and the shape it belongs to, and
index.htmllinks/drink/from the Info tab and from the<noscript>fallback. Those two are the only hand written links added; everything past them is generated, so the front page cannot drift from the menu.Structured data
A drink page's
BreadcrumbListis four steps now rather than two: the front page, the index, its section, the drink. Each hub carries aCollectionPageover anItemListof what it lists, on the same#personand#websiteidsindex.htmlalready uses.sitemap.xmlis 211 URLs, with the hubs between the front page and the drinks and each one dated by the newest drink it lists.Checks added, because a link graph rots quietly
check_assets.check_present: every local reference from every served file resolves to a file that is in the repo. Nothing checked this before, and it is what catches a hub link with no page behind it.check_assets.check_stampsnow fails on a served page that links the stylesheet with no release stamp to land on, so a new kind of page cannot ship taking the edge's four hour oldapp.css.check_assets.check_filesresolves absolute paths. It could not before, which is why/drink/inindex.htmlwas the first thing to break the build.stage.pyreads which pages take the?v=stamp offpages.OWNEDrather than a regex of its own, andSERVEDcarriesmenu/andshape/.check_style.page_filesandcheck_assets.served_textsreadpages.OWNEDtoo, so the hubs are linted, alt-text checked and dash checked exactly like the drink pages. 212 static pages now, from 187.pages.pyrefuses a section or shape id that is not a slug, and an orphaned hub is reported and deleted the same way an orphaned drink page is. Tested by planting stray hub pages and runningmake pages.BreadcrumbListitem must be an absolute URL on the origin.test_checks.pygoes from 316 to 322 cases.One consequence worth agreeing to before merge
A family id and a pattern id are stable keys from here on, like a cocktail id and a shelf bit. They are addresses now. Renaming
ginorold-fashionedmoves a page, the old address answers with404.html, and whatever that page had accumulated is gone.CLAUDE.mdrecords this in a new section,Being found.Design
The hubs have no CSS of their own. They are the classes the drink pages and
404.htmlalready carry, so light, dark and print were settled before the first hub existed. The one rule they cost is on the drink page:aiscolor: inheritwith no underline everywhere here, so.page__eyebrow aand.page__note ajoin the group that marks a link, or the section and the shape read as plain words.What the adversarial pass caught, and I fixed
/menu/vermouth/while the other three were absolute. Fixed, with a check over four pages that every crumb is an address.CLAUDE.md. Rewritten positively.kin.jsonever named a pattern it did not define. Linked only when the hub exists.What I ran
make verifygreen: 322 checker cases, 24 unit cases, 212 static pages linted, 211 sitemap URLs, every code still agreeing with its build.make stage V=v9.9.9rehearsed the release: 215 stamps land exactly once, and the two inline script hashes are unchanged, so this needs no Content-Security-Policy edit in Cloudflare before the tag.Headless Chrome at 390 and 1280, in dark, light and print emulation, over a family hub, the index and a drink page.
Not checked: offline behaviour live.
sw.jsputs the hubs in the network first branch exactly like drink pages, withoffline.htmlas the fallback, but I did not install the worker over https and pull the plug. Separately, an empty menu still dies atmax(days)in the sitemap, which is pre-existing and which the index hub would now share.Reviewer notes
git diff origin/main...HEAD -- drink/adonis/index.htmlis representative of all of them./menu/absinthe/and/menu/fernet/are one drink pages, which a search engine may read as thin. They are honest, and dropping them would leave those two drinks with one fewer way in.lastmodis the newest drink it lists, so a sibling section's count changing does not move it. Understating is the safer direction, since alastmodthat is wrong in the other direction is one Google stops reading.