Skip to content

STU-375: Replace sidebar landing layout with responsive hero and product navigation - #80

Closed
sgardoll wants to merge 15 commits into
mainfrom
sgardoll/stu-375-replace-the-sidebar-landing-layout-with-the-responsive-hero
Closed

sgardoll wants to merge 15 commits into
mainfrom
sgardoll/stu-375-replace-the-sidebar-landing-layout-with-the-responsive-hero

Conversation

@sgardoll

@sgardoll sgardoll commented Sep 22, 2026 •

Copy link
Copy Markdown
Owner

Closes STU-375.

What this PR does

  • Replaces the sidebar/demo navigation landing shell with a responsive hero: fixed full-width topbar, paired-C brand mark + wordmark, exported hero copy, centered composer, and separate Home, Account, Plans surfaces.
  • Adds a hash-based switchView router in app.js that preserves back/forward/reload and auth query-token handling.
  • Wires the topbar and credits modal through the STU-374 shared controls.
  • Keeps all existing modals, generation/deploy modules, and auth/session initialization intact.

New / modified files

  • index.html — new shell/hero/view markup and styles.
  • app.js — router, shell UI updates, credits helpers, generation-stage wiring.
  • e2e/stu375-hero-navigation.spec.js — Playwright tests for viewports, zoom, navigation, focus isolation, and history.
  • playwright.config.js / package.json / package-lock.json — Playwright setup.

Verification

  • npm test — 274/274 passing.
  • npm run build — production bundle built successfully.
  • npx playwright test e2e/stu375-hero-navigation.spec.js — 5/5 passing.

Notes

  • The full WebGL field background and walkthrough morph are not implemented here; they are owned by STU-389 and STU-391 respectively.
  • The current results stage is embedded as a full-screen overlay to avoid disturbing generation/deploy logic.

RetriggerConfidence Score: 5/5

The PR appears safe to merge; the only outstanding feedback is a non-blocking accuracy issue in dependency-verification notices.

Fix All in DevinFindings

  1. P2 Approximation Warning Misstates Checks ▶
Fix with agent prompt
### Issue 1
src/customCodeVerification.js:217-220
`approximate` is populated for every unrepresentable dependency without considering which classes are actually compiled. A deployment containing only `dart:`-only classes, whose checks are exact, therefore still reports “Verified approximately.” If all relevant classes are skipped, the result can also report both “Not verified” and “Verified approximately” for the same dependency. This makes the success result an inaccurate account of which checks were performed. Limit these notices to compiled classes with `package:` imports.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Summary

This PR replaces the sidebar landing shell with a responsive hero and hash-based Home, Account, and Plans navigation, integrates accessible shared modal controls, adds browser and accessibility coverage to CI, and refines custom-code dependency verification. Greptile automatically discovered a related ticket that helped explain the purpose of this PR: provide responsive product surfaces while preserving navigation history, authentication query-token handling, keyboard focus, and session state.

  • Adds responsive hero, topbar, product views, and generation-stage transitions.
  • Preserves hash navigation across reload and browser history while moving focus into newly selected views.
  • Adds shared modal focus management and dedicated UI/accessibility tests.
  • Makes dependency verification decisions per class and reports reduced-graph checks separately.
  • Pins CI actions, minimizes workflow permissions, and runs the new verification suites.

Reviews (4) · Last reviewed commit: "fix: scope the verification skip to dire..."

STU-368. Which packages the Flutter SDK supplies was decided by a
hand-maintained name list kept in three places, and flutter_web_plugins was in
none of them. Every project declaring it - which is every web-enabled project
with a plugin - read it as a dependency that could not be reproduced, and the
deploy was refused for a package most of its classes never imported.

The project's own pubspec already says where each package comes from; the
parser read those lines and threw them away. It now returns them as
sourceKey/sourceValue, so the classification is exact and cannot fall behind
the SDK:

  sdk:                            -> the Flutter SDK, reproduced from the name
  a nested version:               -> a constraint written on its own line
  git: / path: / nested hosted:   -> not expressible in the manifest

SDK_DEPENDENCIES is gone. The runner's allowedSdkPackages is gone too - it
independently refused the same deploy with 'Unsupported SDK package'. That
allowlist was also the only validation of an sdkPackages entry, so the package
name pattern now does that job; without the swap a caller-supplied name would
reach the generated pubspec unchecked. The runner still writes 'sdk: flutter'
itself, so that value never comes from a caller.

Refusal is now scoped per class, to that class's own imports, so one git: entry
no longer leaves an entire deploy uncompiled.

The accept/warn split already existed and is unchanged: a real analyzer error
refuses with 422, and a class that could not be compiled is pushed with its
warning logged before the provisioning request.

Corrects DEPLOYMENT.md, which still described the scaffolding-closure
compilation that reverting a1238f0 removed, and still claimed that nothing
unverified is deployed.

Verified: 274/274 tests, deploy guard 9/9, proxies 30/30, build clean, dart
analyze on the runner reports no issues.
- Add src/designTokens.css as the single shipping token stylesheet, extracted
  from the canonical custom-code-connect-hero.html :root token set.
- Link the stylesheet from index.html; reuse existing /fonts/Delight-VF.ttf
  and DM Mono Google Fonts path.
- Replace the legacy inline :root in index.html with only the layout
  constant --sidebar-w, preserved until its owning shell change.
- Migrate legacy variable references to new tokens:
  --main-bg -> --bg, --navy -> --fg, --label -> --muted, --sublabel -> --muted-2,
  --input-bg -> --surface-sunken, --input-border -> --border,
  --badge-bg -> --accent-soft, --badge-text -> --accent,
  --glow-color -> --accent-soft.
- Centralize :focus-visible and prefers-reduced-motion defaults in the token
  stylesheet and remove redundant local reduced-motion rules.
- No generation/deploy code changed; app.js has no affected CSS var refs.
Comment thread index.html Resolved
Comment thread app.js Resolved
Comment thread .github/workflows/ci.yml Resolved
Comment thread .github/workflows/ci.yml Resolved
…can reach a class transitively

(cherry picked from commit 9d338ad)
Below 680px the topnav was hidden with display:none, and it holds the
only link to the new #plans surface, so mobile users could reach just
Home, Account and the credits modal — Plans required hand-editing the
URL.

Replace the mobile display:none with an adaptive active-view layout:
the nav stays visible and wraps to its own topbar row under 680px with
equal-width 44px touch targets, and --topbar-h grows to 100px so the
fixed topbar keeps the viewport offset exact. No horizontal scrolling
is introduced at 360px and hidden views stay out of the focus order.
Extend the hero navigation suite with a 360x800 test asserting all
three surfaces stay reachable with touch-sized targets and that the
wrapped nav does not force horizontal scrolling.

STU-375
switchView revealed the selected surface but never moved focus into
it, and the view sections were not programmatically focusable, so
focus stayed on the topbar trigger while the content changed underneath
— keyboard and assistive-technology users were never placed in the
newly selected surface.

Give each view section tabindex=-1 and focus the revealed container
once its is-active class lands (inside the same animation frame, so
the element is visible and focusable). Focus only follows
user-initiated navigation: the first hash restore on page load keeps
focus wherever the browser put it, while later hash changes, popstate
traversals and avatar-triggered switches move focus into the surface.
Hidden views are already display:none and inert, so focus cannot land
in them. Extend the hero navigation suite with assertions that initial
load steals no focus, that keyboard and pointer navigation both land
focus in the revealed view, and that the hidden view keeps zero
focusable controls.

STU-375
The workflow ran the unit tests and the production build but never
executed the Playwright navigation suite or the accessibility modal
suite, so regressions in responsive navigation, history, zoom,
overflow and modal accessibility could merge while CI stayed green.

Install Playwright Chromium once after the production build, then run
npm run test:ui for the e2e navigation suite and npm run
test:accessibility for the modal suite. The test:ui script invokes
the Playwright runner against the checked-in config. Step naming
follows the existing workflow and the pinned-action SHA and
least-permission hardening are unchanged.

STU-375
Comment thread src/customCodeVerification.js Resolved
… scratch-graph approximation

(cherry picked from commit e300b76)
Comment on lines +217 to +220
const approximate = unrepresentable.map(
(name) =>
`Your project declares ${name} from a source that cannot be reproduced outside it, so the pre-deploy compile check runs against a scratch package graph that omits ${name}. Classes that do not import ${name} directly are still checked, but against that reduced graph, so their transitive package resolution may differ from your project's and the check is approximate for them.`,
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Approximation Warning Misstates Checks

approximate is populated for every unrepresentable dependency without considering which classes are actually compiled. A deployment containing only dart:-only classes, whose checks are exact, therefore still reports “Verified approximately.” If all relevant classes are skipped, the result can also report both “Not verified” and “Verified approximately” for the same dependency. This makes the success result an inaccurate account of which checks were performed. Limit these notices to compiled classes with package: imports.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/customCodeVerification.js
Line: 217-220

Comment:
**Approximation Warning Misstates Checks**

`approximate` is populated for every unrepresentable dependency without considering which classes are actually compiled. A deployment containing only `dart:`-only classes, whose checks are exact, therefore still reports “Verified approximately.” If all relevant classes are skipped, the result can also report both “Not verified” and “Verified approximately” for the same dependency. This makes the success result an inaccurate account of which checks were performed. Limit these notices to compiled classes with `package:` imports.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Fix in Claude Code Fix in Codex Fix in Devin

@sgardoll

Copy link
Copy Markdown
Owner Author

@greptileai — all findings from the previous review have been addressed (see new commits). Please re-review this PR.

@sgardoll

Copy link
Copy Markdown
Owner Author

Closing: this branch is already fully contained in milestone/stu-implement-updated-ui-ux, merged during the earlier integration run as db2996a (STU-375). GitHub refuses to retarget this PR to the milestone branch for that exact reason — there are no new commits between the two. The work therefore ships with the milestone → main PR and this PR no longer corresponds to anything unmerged. Nothing is lost; the commits remain in history.

@sgardoll sgardoll closed this Sep 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant