Tier 5 refactor: molecule extraction, browser tests, project sub-nav#69
Merged
felipebalbi merged 13 commits intoMay 15, 2026
Merged
Conversation
The home hero shipped two large CTA tiles -- "Getting started" and "Projects" -- right under a navigation bar that already has both as top-level links. The duplication was visually loud and added two hard-coded fixed-pixel widths (lg:w-[478px], h-[176px]) plus inline styles that fought the surrounding flex layout. This commit drops the tiles and lets the headline + subtitle span the row. The Welcome + video block underneath is unchanged. Drive-by typography migration of the Welcome block onto <Heading> / <Text> from the design system, and a couple of inline-style -> Tailwind cleanups (object-contain block mb-4, rounded-[10px], max-w-screen) that were left over from earlier passes. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Adds DOM-level browser tests using wasm-bindgen-test, runnable via `wasm-pack test --headless --firefox --test wasm`. These cover behavior the host-side `cargo test` cannot reach. Tests in `tests/wasm.rs`: * `themed_icon_renders_picture_with_dark_source_and_light_img` - `<ThemedIcon>` emits the expected `<picture>/<source>/<img>` shape with the prefers-color-scheme media query. * `team_hero_renders_back_button_anchor` - `<TeamHero>` renders the history.back() anchor. * `header_logo_is_wrapped_in_home_anchor` - clicking the logo navigates to `/` (the t27 logo-as-home behavior). * `header_mobile_menu_toggles_aria_expanded` - the mobile burger toggles `aria-expanded` correctly. The assertion is async with a microtask flush helper because Leptos applies reactive attribute updates on the next microtask, not synchronously with the click handler. Infrastructure: * `wasm-bindgen-test`, `wasm-bindgen-futures`, and `js-sys` added as dev-dependencies. * `mod components` -> `pub mod components` in `src/lib.rs` so integration tests can reach the UI types. `data` and `pages` remain private. * New `wasm-test` job in `.github/workflows/ci.yaml` runs the browser tests headlessly under Firefox on `ubuntu-latest` (which ships Firefox by default; wasm-pack auto-fetches a matching geckodriver). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The "→ label" link with separate non-underlined arrow span and underlined label appeared verbatim in three places. Hoist it into `components/ui/arrow_link.rs` as a reusable design-system molecule that auto-detects external URLs (uses `<a target=_blank rel=...>`) vs. internal routes (uses `leptos_router::components::A`) from the `href` scheme. Migrated: * `DocumentationTraining` -- the 5-link "Documentation" footer list now collapses to a single `<ArrowLink size=Large external=link.external />` per item. * `ProjectsComponent::ProjectLink` -- now a thin wrapper that forwards to `<ArrowLink>`. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The "themed icon stacked above content in a left-aligned column" pattern recurs across the landing page value-prop cards, the documentation footer, and the team hero. Hoist it into `components/ui/icon_block.rs` with two size presets: * `IconBlockSize::Standard` -- the `.icon` size used by the value-prop / community cards. * `IconBlockSize::Hero` -- the larger 80/150px responsive icon used by the documentation footer and other hero rows. Migrated the documentation footer's icon column to `<IconBlock>` as the first consumer; remaining call sites land in t32 (value-prop cards) and follow-on commits. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The three landing-page Value Proposition cards shared an icon+H3+body shape. Hoist into `components/ui/value_prop_card.rs`, which composes [\IconBlock\] + [\Heading\] (H3) + [\Text\] (Large) and applies the `md:flex-1` equal-share Tailwind class so the cards still split the row evenly. The landing-page section drops from 3x10-line raw blocks to 3x6-line `<ValuePropCard ... />` calls. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The 100-line landing-page view block was a single `LandingPage` component holding four logically distinct sections back-to-back: hero, value proposition, projects intro + tiles, and the closing two-column call-to-action. Hoist each into its own file under `src/components/landing/`: * `hero_section.rs` -- `<HeroSection>` * `value_proposition_section.rs` -- `<ValuePropositionSection>` * `projects_section.rs` -- `<ProjectsSection>` (intro + tiles) * `closing_columns_section.rs` -- `<ClosingColumnsSection>` `components/landing_page.rs` collapses to an 18-line shell that renders the four sections in order. The new `landing` module is registered in `components/mod.rs`. No visual changes; the rendered DOM is identical, just sourced from smaller files. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Tier 5's stated rationale for landing wasm-bindgen-test (t29) second was that later refactors get safety-netted by browser tests as they go in. The molecule and section commits (t30-t33) shipped without matching DOM tests; this commit closes that gap. Adds eight tests in `tests/wasm.rs`: * `arrow_link_external_renders_target_blank_and_external_class` - external href produces `target="_blank"`, `rel="noopener noreferrer"`, and the `external-link` wrapper class with both arrow and label spans present. * `arrow_link_internal_renders_router_anchor_without_target` - internal href produces an `internal-link` wrapper, no `target` attribute, and routes via `leptos_router::A` (wrapped in `<Router>`). * `icon_block_wraps_themed_icon_with_children` - `<IconBlock>` emits a `<picture>` followed by the supplied children. * `value_prop_card_contains_icon_title_and_body` - title and body strings are present alongside the icon. * `hero_section_renders_headline`, `value_proposition_section_renders_three_cards`, `projects_section_renders_intro_and_three_image_buttons`, `closing_columns_section_renders_both_columns` - each landing section composes correctly and exposes its known unique copy. Reuses the existing `mount` helper. Switches from `Element::query_selector_all` (not in our web-sys feature set) to `Element::get_elements_by_tag_name` for tag-count assertions. No production code changes. `cargo test` (host): 40 pass. `wasm-pack test --headless --firefox --test wasm`: 12 pass. Going forward: every new molecule/section in t34-t37 lands with its DOM test in the same commit. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Two intro layouts shared a "stack-on-mobile, two-columns-on-md+"
shape: the projects-page hero (System Firmware Domains) and every
project introduction hero. Both also rendered a recurring
`<Mono>{LABEL}</Mono>` + body block (WHAT / WHY / WHO).
* New `ui/two_column_intro.rs` -- `<TwoColumnIntro left=.. right=.. />`
bakes in the [\Section\] shell, the responsive flex row, and the
`mt-8 md:mt-0` mobile-spacing on the right column. Slot props
use [\ViewFnOnce\] so callers pass plain `|| view! { ... }`
closures instead of boxed children.
* New `ui/labeled_section.rs` -- `<LabeledSection label="WHAT">..</LabeledSection>`
emits a Mono label followed by the supplied body content, removing
the manual Mono+body pairing at every call site.
Migrated:
* `projects_component.rs` -- the System Firmware Domains hero row
is now a single `<TwoColumnIntro>` + two `<LabeledSection>`s.
* `project_introduction.rs` -- WHAT / WHY / WHO blocks now use
`<LabeledSection>`.
t38-mandate honored: two new wasm tests in `tests/wasm.rs`:
* `two_column_intro_places_left_and_right_in_separate_columns`
-- asserts the row has exactly two children, the slots land in
the correct one, and the right column carries the `mt-8` mobile
spacing.
* `labeled_section_renders_uppercase_label_then_children` --
asserts source-order (label before body) and label presence.
`cargo test`: 40 pass. `wasm-pack test --headless --firefox`:
14 pass.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Documentation footer rendered each link as `<li><ArrowLink size=Large external=link.external .../></li>`. Hoist into `ui/doc_link_item.rs` so the wrapper-li shape lives in one place and any future "list of brand links" surface (e.g. the announcements card in t36) can reuse it without re-deriving the size + li wrapping rules. Migrated `DocumentationTraining` to use `<DocLinkItem href title external />`. t38-mandate: two new wasm tests in `tests/wasm.rs`: * `doc_link_item_external_renders_li_with_arrow_link` -- external href produces `<li>` containing an anchor with `target=_blank` and the title text. * `doc_link_item_internal_uses_router_anchor` -- internal href produces an anchor without `target`, wrapped in `<Router>` so `leptos_router::A` has its context. `cargo test`: 40 pass. `wasm-pack test --headless --firefox`: 16 pass. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Two coupled cleanups for the announcements page:
* New `src/data/announcements.rs` -- `Announcement` struct
(slug / link_label / title) and an `ANNOUNCEMENTS` slice as
the canonical source of announcement metadata. Also exposes
`index_of(slug) -> Option<usize>` so the URL `?id=` lookup
doesn't have to re-implement linear search at the call site.
Three host-side unit tests cover slug uniqueness and index_of.
* New `ui/announcement_card.rs` -- `<AnnouncementCard title=>..</>`
bakes in the styled detail-panel wrapper (responsive padding,
`h2` title row, `p2` body) so the page no longer has to spell
out the typography classes inline.
* Refactored `pages/announcements.rs`:
- Imports the data module instead of defining the announcement
list inline.
- Renders each detail panel via `<AnnouncementCard>`.
- Extracted `slug_from_query()` so the `?id=` parsing has
a name and is no longer entangled with the effect closure.
- Effect now uses `index_of()` to convert slug -> index.
t38-mandate: one new wasm test in `tests/wasm.rs` --
`announcement_card_renders_title_and_body` asserts the title is
present, the body children render, and the title precedes the body
in source order.
`cargo test`: 43 pass (3 new in announcements.rs).
`wasm-pack test --headless --firefox`: 17 pass.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add a horizontal <ProjectTabs> nav rendered between the project hero and the repository graph on each of the three project pages (/boot-firmware, /embedded-controller, /windows-ec-services). The active tab carries aria-current="page" and is bolded; the other two tabs are plain router links to the sibling project pages, so visitors can hop directly between projects without backing out to /projects. ProjectCopy gains short_label and route fields so the tabs derive their links and labels from the existing data module rather than hard-coding strings in the component. Tests: two new wasm-bindgen tests (tabs render exactly three anchors with the correct hrefs and aria-current; the active marker follows the active prop) plus three host unit tests on the data mapping. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
runk build --release failed with a flood of wasm-validator errors
along the lines of:
[wasm-validator error in function NNNN] unexpected false:
memory.copy operations require bulk memory operations
[--enable-bulk-memory-opt]
Trunk's bundled wasm-opt (binaryen v123) does not enable the
bulk-memory feature by default, but rustc 1.82+ (and several of our
dependencies) emit `memory.copy` instructions, so wasm-opt rejects
the staged wasm before it can be optimised.
Forward `--enable-bulk-memory` and `--enable-nontrapping-float-to-int`
to wasm-opt via Trunk's `data-wasm-opt-params` attribute on the
`rust` link in `index.html`. These are the same target features
the rustc wasm32 target enables, so the optimiser now accepts the
input and the release pipeline succeeds.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
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.
Tier 5 refactor: molecule extraction, browser tests, project sub-nav
Builds on the design-system primitives landed in #68. This tier
extracts the recurring composite UI patterns into named molecules
in
src/components/ui/andsrc/components/landing/, addsbrowser-side wasm-bindgen tests for the new components, and
introduces cross-project navigation tabs.
Highlights
on the home hero (they duplicated the menu bar one row above).
tests/wasm.rsintegration suite + Firefoxwasm-packjob in CI. Helpers:mount()(per-test container),next_tick()(microtask flush for Leptos reactive updates).backfill matching DOM tests for each:
<ArrowLink>(auto-detects external byhttp(s)://)<IconBlock>(Standard / Hero size presets)<ValuePropCard>(composes IconBlock + Heading + Text)<TwoColumnIntro>+<LabeledSection>(slot-style propsvia
ViewFnOnceso callers pass plain closures)<DocLinkItem><AnnouncementCard>+src/data/announcements.rslanding_page.rsinto per-sectionfiles under
src/components/landing/; the page shell collapsesto 18 lines.
<ProjectTabs>strip on each projectpage so visitors hop between sibling projects in one click.
Active tab carries
aria-current="page". Project URLs andshort labels now live on
ProjectCopyso the tabs deriveeverything from
src/data/projects.rs.--enable-bulk-memoryand--enable-nontrapping-float-to-inttowasm-optviadata-wasm-opt-paramsonindex.html. Trunk's bundledwasm-opt v123rejectedrustc 1.82+memory.copyoutput without these flags, breaking
trunk build --release.Tests
cargo test-- 46 host tests pass.wasm-pack test --headless --firefox --test wasm-- 19 browsertests pass.
cargo clippy --target wasm32-unknown-unknown --all-targets --no-deps -- -D warnings-- clean.trunk build --release-- now succeeds.Going-forward convention introduced this tier: every new molecule
or section ships with its DOM test in the same commit.