Conceptual: nav: rebuild the header, add a Start building menu - #5765
Draft
dimitrieh wants to merge 14 commits into
Draft
Conceptual: nav: rebuild the header, add a Start building menu#5765dimitrieh wants to merge 14 commits into
dimitrieh wants to merge 14 commits into
Conversation
A first FlowFuse instance can start in three places, and the header only advertised one of them. "Start building" now opens a menu offering Cloud, the visitor's own edge hardware, and the AI agent they already use. - Rows come from chrome.header.startBuilding, shared by both renderers. A row names either a reserved CTA destination or its own label and href, so the Cloud row keeps firing cta-sign-up from ctaDestinations.json and the sign-up funnel stays one event. Its copy is a third position-keyed label there, not a caller-supplied string. - "Install on edge" leaves the utility bar; it is the edge row now. The remaining quick links gain pr-4 so Sign In lines up with the Book a Demo button's label rather than its outer edge. - The panel is a content-width mega panel: same flush white surface, top border, left-aligned icon rows and hover-intent delay as the other nav panels, sized to three rows instead of the viewport. Separator lines between rows, because each row is a different way to start. - The trigger rests, hovers and underlines like any other top-level nav item; the rules are restated because it sits outside #nav-content. - nav-text CTAs can now carry a leading nav icon, so the Cloud row matches the icon rows beside it on both stacks. - chrome.test.mjs guards the new rows: icons resolve and are in the Nuxt map, each row names exactly one destination, both renderers draw it.
3.5rem, set as a min-height with centring rather than as vertical padding, so a label that wraps at a narrow width grows its row instead of overflowing it. The panel now reads as an extension of the bar it drops out of rather than a denser list pinned under it.
Three things the panels did not do. Panels are sized to their own content instead of running to both viewport edges. Each one now hangs off the header as a bordered card whose left edge sits on the same line as the logo and the first nav item, so the columns have an edge to be read against. The panels measure 1115 to 1208px at 1440px wide, where every one of them used to be 1440. A full-bleed band carrying three columns of links spent most of its width on empty white. A dropdown is a link as well as a trigger where the section has a landing page: Platform to /product/, Solutions to /industries/. Resources has no index page and Company's nearest thing is /about/, one page inside the section rather than the section itself, so both stay triggers only. Under md the drawer suppresses the navigation and expands the section as before. "See all industries" leaves the Solutions panel, since the trigger above it is now that link. The product tiers carry a description line. Only that column has them, so the panel drops the subgrid row alignment it shares across columns: a described row is two lines tall, and the plain columns beside it were inheriting that height and drifting apart with nothing in the gaps. Two shared rules had to learn about the new markup: the chevron's scale/rotate matched any span in a header link, which shrank every description by a quarter, and the dropdown min-width floored a panel at its containing block's width, which for a mega panel is the whole nav.
…rlining Hover was an animated line under the label, which only appeared while the pointer was literally over the text. Every hover surface in the header now fills instead - top-level item, panel row, Start building row - and the label colours from the row rather than from itself, so the whole block reacts wherever in it the pointer sits. The fill spans the bar's full height: an anchor trigger was 8px shorter than a span one, because `.ff-nav-dropdown a` pins anchors to py-3 while every other trigger is a span on py-4, and that padding is what gives the bar its height. Divisions: a rule between the top-level items, a rule between a panel's columns, and a rule above every panel row. The column rule is drawn by the eyebrow and the list together, both stretched to their grid rows so the two segments meet as one line. The Product panel (renamed from Platform, and the trigger goes to /product/) is now the product tiers plus a pricing and security column. Its Components and Capabilities columns are retired, along with the Product row that duplicated the trigger above it. Every retired entry is recorded under header._retired in chrome.json with where it was and why, and all fifteen are still listed in the footer's Product section, so none of those pages left the site chrome.
The panel gave forty links the same weight as four, which is what made it read as noise rather than structure. It now has a hierarchy: - The first column is the panel's answer to "what is this section". Its rows are ruled and fill on hover, edge to edge across the column, with the row's own padding providing the inset rather than the panel's. - Every column after it is a plain link list under an eyebrow: tighter, no rule, no fill, just a colour change. - A feature row (the product tiers) is a 76px block: a 36px icon centred against the whole row rather than hanging off the first line, then the title and description stacked beside it. Columns butt against their divider with no gap, so a row runs the full width of its column and the rule under it meets the rule beside it. Rules between the top-level items are gone; the bar is plain again and only the panels are divided. The highlight card goes with them. It was an image promo occupying the panel's first track in every dropdown, and the three banded grid templates existed mostly to reserve room for it. Those are now plain auto tracks and the panels are as tall as their rows. Column targeting moved from :nth-child to explicit ff-nav-col--primary / --rest classes: a column can now omit its eyebrow (the Product tiers, since the dropdown above already names them) and that shifts every child index in the panel.
A panel's first column no longer carries an eyebrow: the dropdown above it already names the section, and without one the column's first rule sits on the panel's top edge instead of under a label. Every later column keeps its eyebrow. Each primary row now ends in a chevron, drawn from borders rather than an icon file. It marks the row as somewhere to go and anchors the row's right edge, so the rule under it reads as the width of a block rather than as a line that happens to be longer than its label. The primary column also gets a real minimum width for the same reason, since several of them hold labels far shorter than the row they sit in. Measured on all four panels: rows sit flush against the panel's left border and end exactly on the column divider. The four dropped headings are recorded under header._retiredHeadings in chrome.json alongside the retired links.
Two things the panels could not do while they were pure CSS. The panel's left edge now follows the trigger that opened it. Content-width panels left-aligned to the nav put the Company panel most of the width of the page away from the word "Company"; it is pulled back only when that would push it past the right of the viewport, which needs the measured panel width and so cannot be a stylesheet rule. Moving between two open menus now goes through the View Transition API. That needs a state change to animate, and while the panels opened on :hover there was no state, only two elements that happened to be under the pointer at different moments. src/js/nav-panels.js owns the open state and hands the swap to document.startViewTransition(); both panels take the same view-transition-name for its duration, which is what makes the browser tween one box into the other rather than blink between them. Opening from nothing and closing to nothing stay a plain fade. Progressive enhancement throughout: `js-nav` on <html> switches the stylesheet from :hover-driven opening to class-driven, so with the script absent the header behaves exactly as it did. Below md none of it runs. One source for both stacks, the route nav-tracking.js already takes: 11ty passes the file through, Nuxt lists it in head.script and picks it up from the 11ty output. Also fixes the shared-row coupling behind the stranded secondary columns: each column now owns one grid cell and stacks its own links, instead of every column sharing one row per link with every other column. And the panel's row template moved from a md:grid-rows-[auto_1fr] class in chrome.json to style.css, because Tailwind never extracted that arbitrary value out of the JSON and the panel had silently had no row template at all. A guard now fails if grid rows are declared in the data file again.
Measured before and after at the widths each one appeared at. - Panels lost 50px off their right edge at 768: three columns asked for 816px inside a 768px panel and overflow: hidden cut "See all integrati" mid-word. The column floors narrow below lg, so the widest panel fits the narrowest desktop. Clipping is now 0 at every width, was 50px at 768, 38px at 780, 18px at 800. - "Start building" wrapped at 1024, which grew the header from 56px to 80px and pushed every panel down to y=124. It no longer wraps: 128x56 and a 56px header at 1024, panels back at y=100. - The panel anchoring clamped to the window rather than to the content container, so a wide panel finished 16px from the window edge while the rest of the page stopped at an 80px gutter. Company ended at 1424 against a container edge of 1360; both Resources and Company now land on 1360 exactly. - Column eyebrows sat hard against the panel's top border once the panel's own padding went, because the existing rule pins their padding with !important. 21px above the label now, was 0. - Start building rows measured 56, 57, 57: the separator is a border on the li, so the rows carrying one were a pixel taller. All three are 56 now. Not fixed, and recorded rather than quietly dropped: the "More" overflow menu below 768 still wears the old floating-card styling; the mobile drawer indents a section's primary and secondary rows differently; "Pricing" reaches the drawer twice, as a top-level item and inside the Product panel. The audit also found /js/nav-tracking.js and /js/nav-panels.js 502 on the Nuxt dev server. That is the dev container, which cannot serve 11ty's passthrough assets; a production build copies them into nuxt/public via prod:eleventy-nuxt. It does mean the Nuxt dev server cannot be used to check anything script-driven, including the panel anchoring.
…ity bar Three top-level items. Customers fronts four named accounts, most recent first - Aperia Technologies, Energinet, Neoception, Walter - drawn from the twelve stories in src/customer-stories/ by their story.brand, with the trigger itself going to /customer-stories/. Icons follow each story's domain rather than repeating one generic mark. Solutions becomes Industries and takes the same shape as the panels beside it: the industries as the ruled primary column, then two plain link columns for use cases and architectures. That split is already in the content and was not surfaced anywhere - a page under /use-cases/ carrying `values:` is a use case, the six that do not describe an architecture. The By Integration column leaves the panel. Blog moves from the utility bar to the nav, leaving About us / Docs / Support / Sign In in the bar. Nothing is now reachable twice from the same bar: Customer Stories leaves the Resources panel (its column becomes Tools, holding the ROI calculator), and Blog leaves Resources > Learn. Those, and the eight integrations, are recorded under header._retired with where they were and why; all of them are still listed in the footer. Also fixes a bug in nav-panels.js this exposed: a closed panel kept the inline `left` it was given at a wider viewport, and since it is absolutely positioned but only hidden, that still counted towards the document's scrollable width. At 1024 the page scrolled to 1186. Offsets are cleared when a panel closes and re-measured on resize; verified 1024/1024 with every panel opened in turn and with none open. At 1024 the bar now collapses Industrial AI and Pricing into More, which is what that overflow menu is for, and the header stays 56px.
… border Primary rows were 39px under a 56px bar. 3.5rem is the floor now, the same one the Start building menu uses, so a row of a panel is never shorter than the row it dropped out of. The Product panel's feature rows are unaffected: their padding already carries them to 76px, above the floor. The primary column has no eyebrow, so its first row sits directly on the panel's top border and drew its own rule on top of it - two lines a pixel apart. The panel draws that edge; a row only draws the ones between rows. Secondary columns are left alone. A plain link list reads correctly at its own tighter rhythm, and stretching those rows to 56px would flatten the difference between a section's answer and its supporting links. Measured on all five panels: primary rows 56px (Product 75/76), first row border-top 0, 1px from panel top to first row, secondary rows still 37px.
Blog gains a panel, which is also what makes the order possible: every top-level item is a dropdown now, so the requested sequence is just the order of one array and neither template had to learn to interleave a second list. The panel is the blog's own tags, split the way the rest of the panels are - Releases, How-To, Node-RED, AI and News as the primary ruled column, then the technology tags under More topics. Tag routes are /blog/<tag>/, and the "All" tag is left out because the trigger already goes to /blog/. Pricing and Industrial AI leave the top nav. Neither becomes unreachable from the header: Pricing is in the Product panel's Pricing & security column, and Industrial AI is the Start building menu's "From your personal AI agent" row. Both are also in the footer, and both are recorded under header._retired with where they went. Losing those two also bought back the width they were taking. At 1024 all six items now fit with the header at 56px, no panel clipped, nothing overshooting the container and no horizontal document scroll - where the bar previously had to collapse two items into More to fit. header.direct is empty as a result, so nothing is nav-collapsible and the More menu stays hidden. The overflow machinery is left in place: it is what catches a seventh item, or a longer label, without anyone noticing.
…column Under a "Latest posts" heading, because a column of headlines with no label does not say what it is - unlike every other primary column, where the dropdown above it already names the section. Posts cannot live in chrome.json, so a column may now name a `source` instead of listing links, and the templates fill it from that data file. The file is generated by scripts/build_latest_posts.mjs, which reads the frontmatter under src/blog the way src/_data/blogPosts.js already does, drops anything dated in the future, and keeps the newest five. One generated file rather than a query per renderer. 11ty could read the posts through blogPosts.js and Nuxt through its content collection, but that is two queries, two sort orders and two definitions of "published", and the two headers would drift the first time one of them changed. This is imported by both, exactly as chrome.json is. Verified: both serve the same five titles in the same order. It regenerates as the first step of `build` and `build:nuxt`, so what ships is never the committed snapshot. The snapshot is committed anyway, so a fresh checkout renders the nav without running anything first. A post row wraps, unlike every other row in a panel: the panel sets white-space: nowrap so a menu word never breaks mid-label, which would have stretched the panel to the length of the longest headline instead.
main moved the Node-RED library into /docs and took those links out of the footer's Solutions section, which now keeps only OPC UA and a link to all integrations. The note recording why the By Integration column left the Industries panel still claimed the footer listed them.
✅ Deploy Preview for flowforge-website ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
✅ Deploy Preview for flowforge-website ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
5 tasks
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.

Description
Rebuilds the header nav as content-width panels with two weights of row, and adds a "Start building" menu.
Bar:
Product, Industries, Resources, Blog, Customers, Company, thenStart buildingandBook a Demo. Pricing and Industrial AI leave the bar; neither is orphaned (Pricing sits in the Product panel, Industrial AI is the Start building menu's third row, and both remain in the footer). Blog moves out of the utility bar.Panels are content-width cards anchored under the trigger that opened them, rather than one full-bleed band. Each has two weights: a primary column whose rows are ruled, fill on hover and run edge to edge, then plain link columns under an eyebrow. Previously every link in a panel carried the same weight, which is what made a forty-link panel read as noise.
Start building replaces the
Free Triallink with three ways to begin: FlowFuse Cloud, your own edge hardware, or the AI agent you already use. The Cloud row still firescta-sign-upfromctaDestinations.json, so that funnel stays one event; its copy is a third position-keyed label there, not a caller-supplied string.Blog panel lists the five latest posts, generated from
src/blogfrontmatter byscripts/build_latest_posts.mjsinto a file both renderers import. One file rather than a query per renderer: 11ty and Nuxt would otherwise have two sort orders and two definitions of "published" and would drift. It regenerates as the first step ofbuildandbuild:nuxt.src/js/nav-panels.jsowns panel position and open state, which is what lets a swap between two open menus go through the View Transition API. It is progressive enhancement: without it the panels open on hover as before.Every nav entry removed along the way is recorded under
header._retiredinchrome.jsonwith where it was and why.Known gaps
Recorded rather than quietly left:
Moreoverflow menu below 768px still wears the old floating-card styling: rounded, grey, detached from the header, while every other panel is square, white and flush.navHighlights.jsonandnav-highlight.njkare orphaned now the highlight card is gone. Left in place in case the card comes back.Book a Demois a different component on the two renderers (.ff-btnon Eleventy,UButtonon Nuxt), so it is 1.15px taller on Nuxt and drags the mobile header down by a pixel. Pre-existing, not from this branch.Related Issue(s)
None.
Checklist