fix(visimer): hold the hero headline in place while mermaid renders (PRD-8003) (#3467) - #28
Merged
Merged
Conversation
…PRD-8003) (#3467) * Hold the hero headline in place while mermaid renders The visimer.com headline is a live mermaid diagram, so on a cold load the page went through three states: a plain text headline from index.html for about 1.3s, then the fully drawn page with a 300px hole where the h1 belongs for another 600ms, then the diagram popping in. The middle state reads as broken, because the hint line points at an empty band. The 600ms hole is mermaid pulling its flowchart renderer over two dynamic imports after React mounts, then laying the diagram out. Rather than chase that down, close the window: draw a static stand-in headline that matches the real render and crossfade it out when the real one lands. src/hero-diagram.ts is the single definition of both. Its coordinates are mermaid's own output for the hero source, so the stand-in and the real diagram share a viewBox and are fitted into the same box by the same preserveAspectRatio. Measured over the band, the two differ by 0.01% of pixels at 1440px and 0% at 400px, and the 220ms crossfade covers the rest. The same module generates the first-paint markup that a small Vite plugin inlines into index.html, replacing the hand-maintained copy that used to live there. That copy carried its own geometry and sat the headline 150px from the top while the real hero puts it at 189px, so mounting moved the page under the visitor. The hero's layout values now live in site.css and both renderers read them. Note that mermaid measures its labels exactly once, and emits a layout about 2% tighter whenever it happens to render before Inter has loaded. The committed coordinates are the Inter-loaded ones, which is what a real visitor gets: the font stylesheet is preconnected and lands well before the bundle that starts the render. * Address local review on the hero stand-in Six items from the review panel, none blocking. Pass the boot HTML to String.replace as a function rather than a string. A string replacement gives $&, $' and friends their special meaning, so the day a hero string gains a dollar sign the served document would be silently corrupted, and only in the pre-React copy that nobody looks at during normal development. Move the last shared strings into hero-diagram.ts: the license label and the two hint lines were still written out in both renderers, which is the drift the module exists to prevent. licenseLabel now reads from it, so the badge and the footer follow one definition. Link the boot spacer to the real header through a --site-header-h custom property, with the header enforcing it as a floor. It stays a floor rather than a fixed height so taller content grows the header instead of being clipped by it. Correct the section comment in site.css that still described the old .mw-svg-host scope. The rules now reach the stand-in too, and a new rule written to the old scope would style only one of the pair, which is exactly how the crossfade stops being invisible. Unexport the two orientation constants, which are only composed into HERO_PLACEHOLDER_HTML in the same file. Tighten the comments: drop the point-in-time bundle size and the count of mermaid's internal imports, name all four inputs the coordinates depend on so a maintainer tuning heroConfig knows to re-derive them, and use mermaid's own arrowMarkerPath class on the arrowhead instead of claiming attribute-level fidelity while diverging on the class name. Re-verified after the changes: stand-in against the settled render still differs by 0.01% of band pixels at 1440px and 0% at 400px, hero geometry is byte-identical, in-place editing works, no console errors. * Address cloud review on the hero stand-in Four inline findings and two scope notes from pullfrog, none blocking. Compose HERO_HEADLINE from the three label constants rather than restating the sentence. It was the one string in the module still written twice, so the accessible headline and the visible diagram could drift apart, which is the duplication the module exists to remove. Escape the values heroBootHtml interpolates. The JSX consumers of those same constants get React's escaping; the raw-HTML consumer got none, so the first hero string to contain a <, an & or a quote would render correctly in the app and malformed in the served document. Same asymmetry as the dollar-sign fix, one layer up. Static entities in the template are markup rather than values and stay as authored. Stop letting two predicates decide one crossfade. The stand-in's orientation came from a media query while the diagram's came from a single mount-time read of window.innerWidth that is deliberately never re-picked, so resizing across 760px could leave a stacked stand-in fading into a left-to-right diagram in the same box. The app now renders one stand-in chosen from the source the editor actually got; the media-query pair stays, but only in the served document, which has no better option. Drop the boot block on non-landing routes. index.html is the only entry, so the landing hero also painted over /playground and /hero-loop until the bundle routed away from it. Before this change that was a line of text; a full hero reproduction is worse. An inline synchronous script removes it during parse, matching main.tsx's own pathname normalization. Correct the index.html comment that still called this a render-failure fallback. A failed parse emits render with ok false, which resolves the gate, fades the stand-in out and reveals the canvas error badge. Add a dev-only viewBox comparison in the render handler. Nothing else notices when the hand-measured coordinates stop matching mermaid, and the only symptom is a stand-in that shifts as it fades on a cold load. It checks the first render only, since an edited headline is legitimately a different shape, and import.meta.env.DEV keeps it out of the bundle. Verified: 0.01% band-pixel difference at 1440px and 0% at 400px unchanged; / keeps the stand-in while /playground and /hero-loop drop it; a 1000-to-400 resize after render leaves exactly one stand-in matching the rendered viewBox; the warning is absent from the production bundle; in-place editing works with no console errors. GitOrigin-RevId: c668267a3aef9067cd0392776a7ad61cf3fae633
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.
Copybara-translated 1 Inkeep OSS change. Rebase-merge this PR so the prepared commit lands directly on public main.