Skip to content

feat(calm-hub-ui): responsive mobile layout#30

Draft
rocketstack-matt wants to merge 19 commits into
mainfrom
claude/calm-hub-ui-mobile-responsive-vrquce
Draft

feat(calm-hub-ui): responsive mobile layout#30
rocketstack-matt wants to merge 19 commits into
mainfrom
claude/calm-hub-ui-mobile-responsive-vrquce

Conversation

@rocketstack-matt

@rocketstack-matt rocketstack-matt commented Jun 20, 2026

Copy link
Copy Markdown
Owner

Description

Makes CALM Hub UI responsive so the Hub, the architecture/pattern diagram, the detail panels, and the version timeline/compare views are usable on phones and tablet‑portrait screens. Everything gates on a mobile breakpoint — desktop behaviour is unchanged.

Tracking issue: to be filed upstream in finos/architecture-as-code (this branch lives on a fork; link the upstream issue here once created).

Highlights

  • New useMediaQuery / useIsMobile hook (test‑safe; guards window.matchMedia), keyed to Tailwind's lg (1024px) breakpoint.
  • Navbar: removed the Hub/Visualizer links; added an Explore button that toggles the desktop sidebar or opens the mobile navigation. Search stays in the navbar on desktop; on mobile it lives in the explorer.
  • Mobile explorer: the tree becomes an iOS‑style drill‑down (tap to push the next level) opened as a full‑screen panel, with an always‑visible search whose results take over the explorer.
  • Mobile diagram: full‑bleed render pane; the view‑options menu (breadcrumb, Diagram/JSON/Deployments, and the component search) lives in the navbar and opens as a full‑screen overlay — its trigger shows the active view's icon. Minimap and zoom controls are hidden (pinch is native); the timeline is tucked behind a button that opens a bottom sheet.
  • Detail panels: node/relationship details open as a full‑screen overlay on mobile.
  • Compare view: the two version graphs stack vertically on mobile.
  • Fix: deep‑links and global‑search navigation load correctly on mobile (the loading lifecycle no longer depends on a desktop‑only component).

Type of Change

  • ✨ New feature (non-breaking change which adds functionality)

Affected Components

  • CALM Hub UI (calm-hub-ui/)

Testing

  • I have tested my changes locally
  • I have added/updated unit tests
  • All existing tests pass

Verified manually at ~390px, tablet‑portrait, and desktop across: Hub browse, the drill‑down explorer + search, architecture diagram (incl. a 14‑node example), the view‑options menu + component search, node detail, JSON/Deployments, the version timeline, and the compare view. npm test --workspace calm-hub-ui774 passing; lint and build clean.

Checklist

  • My commits follow the conventional commit format
  • I have updated documentation if necessary
  • I have added tests for my changes (if applicable)
  • My changes follow the project's coding standards

Screenshots

Desktop — unchanged (lg+)

Mobile (~390px)

Full‑bleed diagram (view menu in navbar) View menu — modes + component search
Drill‑down explorer + search Search results take over the explorer
Node detail (full‑screen overlay) Timeline (bottom sheet)

Compare view — graphs stack vertically on mobile

Screenshots are hosted on the docs/mobile-responsive-screenshots branch to keep this PR's diff focused on code.

🤖 Generated with Claude Code

https://claude.ai/code/session_013qUjejkMHHYktMsKXecAFN

The Hub used a rigid three-column flex layout (tree navigation, content,
details panel) with fixed/percentage widths that could not fit on phones
or tablet-portrait viewports.

- Add a useMediaQuery/useIsMobile hook (test-safe; guards window.matchMedia)
- Hub: below the lg breakpoint the tree navigation becomes an off-canvas
  drawer with a dimmed backdrop, toggled by an "Explore" button; the
  details Sidebar becomes a full-screen overlay. Desktop behaviour is
  unchanged.
- Sidebar (details panel): responsive width (w-full on mobile, w-96 on lg+)
- GlobalSearchBar: responsive input width and viewport-bounded dropdown
- SectionHeader: allow the breadcrumb and tabs to wrap instead of overflowing
- Compare view: stack the two diff graphs vertically on narrow viewports
- Add matchMedia polyfill to the vitest setup and tests for the new hook
  and the Hub mobile drawer behaviour

Signed-off-by: Matthew Bain <matt@rocketstack.co>
Follow-up to the responsive layout work, focused on the diagram experience
and a regression it exposed.

- Fix mobile data-loading regression: the URL deep-link / global-search
  loading lives inside TreeNavigation, which was unmounted on mobile until
  the drawer opened, so direct links and search results loaded nothing. The
  mobile drawer now keeps TreeNavigation mounted and slides it off-canvas
  via transform instead of unmounting.
- Hide the minimap on mobile in the single (ArchitectureGraph/PatternGraph)
  and compare (DiffGraph) views — it was oversized and overlapped the canvas.
- Collapse the node search/type-filter bar to a single icon on mobile,
  expanding on tap.
- Tuck the timeline behind a floating clock button that opens it as a bottom
  sheet (TimelineBar gains an initialExpanded prop for the sheet), instead of
  permanently occupying the short viewport.
- Make the diagram tabs icon-only on mobile and trim the Explore trigger so
  the section header stops wrapping to extra lines.

Signed-off-by: Matthew Bain <matt@rocketstack.co>
@rocketstack-matt rocketstack-matt force-pushed the claude/calm-hub-ui-mobile-responsive-vrquce branch 2 times, most recently from f82442d to e396d1d Compare June 20, 2026 13:40
rocketstack-matt and others added 17 commits June 20, 2026 13:47
On mobile the tree-navigation ("Explore") menu and the node/relationship
detail panel were partial floating cards over a dimmed backdrop. Promote
them to full-screen panels that slide in (the menu from the left, the
detail from the right), each dismissed via its own header control rather
than a backdrop tap.

- Hub: tree-navigation panel is now fixed inset-0 full-screen (kept mounted
  and slid off-canvas so deep-link/search loading still runs); the details
  overlay is full-screen with a slide-in-right animation and no backdrop.
- Sidebar: drop the card padding/rounding/shadow on mobile so it fills the
  screen edge-to-edge; keep the desktop card (lg:p-4 / lg:rounded-box).
- Add a slide-in-right keyframe utility for the detail push animation.
- Update the Hub mobile tests to assert open/closed via the dialog role.

Signed-off-by: Matthew Bain <matt@rocketstack.co>
Replace the nested expanding tree with a native-style drill-down on mobile:
each tap pushes the next level as a flat list (Namespaces -> namespace ->
resource type -> resource; Control Domains -> domain -> control), with a
back button to pop a level and a leaf tap that loads the resource.

- Add MobileNavMenu: a self-contained drill-down navigator that fetches each
  level on demand, navigates to the chosen resource URL, and (like the desktop
  tree) loads deep-linked / globally-searched resources via a URL-params effect
  so direct links still work on mobile.
- Extract the shared resource-loading/version-resolution helpers into
  navigation-loaders.ts, consumed by both TreeNavigation (desktop) and
  MobileNavMenu (mobile), removing the duplicated logic.
- Hub: render MobileNavMenu in the mobile panel (TreeNavigation stays for
  desktop); the menu closes itself when a resource is chosen.
- Tests for MobileNavMenu drill-down/back/deep-link; update Hub mobile tests.

Signed-off-by: Matthew Bain <matt@rocketstack.co>
…mobile zoom controls

- Navbar: remove the Hub and Visualizer links. Add an "Explore" button (shown
  when the page provides a handler) that toggles the explorer.
- Hub: the navbar Explore button opens the mobile drill-down panel on mobile
  and toggles the desktop sidebar on desktop; remove the in-content Explore
  button. The Visualizer keeps no nav links (reachable via /visualizer).
- Diagram: hide the ReactFlow zoom controls on mobile (single, pattern, and
  compare views) — pinch-to-zoom is the native touch interface; controls remain
  on desktop.
- Tests: Navbar mock exposes the Explore toggle; add a desktop navbar-toggle
  test; update mobile tests accordingly.

Signed-off-by: Matthew Bain <matt@rocketstack.co>
…plorer search

- Diagram: make the render pane full-bleed (drop the section-header bar and card
  chrome) and move the Diagram/JSON/Deployments switch plus the breadcrumb into a
  hamburger menu pinned to the top-right of the canvas. Offset the in-canvas node
  search so it clears the menu.
- Mobile search: add an always-visible search bar to the mobile explorer
  (MobileNavMenu); while a query is present the results take over the explorer
  body. Search stays in the navbar on desktop (hidden below lg), unchanged.
- Add ExplorerSearch (inline, takeover results) alongside the existing
  navbar GlobalSearchBar.
- Tests for ExplorerSearch; stub it in the MobileNavMenu test; adjust the
  DiagramSection view-mode assertions for the new menu.

Signed-off-by: Matthew Bain <matt@rocketstack.co>
Open the diagram's view-options (breadcrumb + Diagram/JSON/Deployments) as a
full-screen overlay on mobile, consistent with the explorer and detail panels,
instead of a small dropdown. Desktop keeps the dropdown.

Signed-off-by: Matthew Bain <matt@rocketstack.co>
The view-options hamburger no longer floats over the render pane; it is
portalled into a navbar slot (#navbar-actions) so it sits in the top nav on
both mobile and desktop. Falls back to inline rendering when no navbar slot is
present (e.g. in isolated component tests).

Signed-off-by: Matthew Bain <matt@rocketstack.co>
…view icon

Desktop keeps its original section header with inline Diagram/JSON/Deployments
tabs and card chrome — the full-bleed render pane, navbar view-options menu and
full-screen view overlay now apply on mobile only. The mobile navbar trigger
shows the icon of the currently active view instead of a generic hamburger.

Signed-off-by: Matthew Bain <matt@rocketstack.co>
…menu

On mobile the in-canvas node search is replaced by a "Search components"
section inside the view-options menu. A NodeSearchProvider context lets the
menu drive the graph's search/type-filter without prop-drilling; the graph
hides its in-canvas search bar when the context is external. Desktop and the
standalone Visualizer keep the in-canvas search (graph-local state).

Signed-off-by: Matthew Bain <matt@rocketstack.co>
Centre the CALM logo in the navbar, respect device safe-area insets so the
bar never slides under the notch or overflows the viewport, restyle the
mobile view-options menu to match the explorer rows, and fold the timeline
action into that menu instead of a separate navbar button.

Signed-off-by: Matthew Bain <matt@rocketstack.co>
Replace the bottom-sheet timeline with a full-screen overlay that matches
the view-options menu chrome (header bar with title and close button),
giving the moment list and change details the full viewport on mobile.

Signed-off-by: Matthew Bain <matt@rocketstack.co>
On mobile, present the control's Requirement and Configuration as two tabs
instead of stacked panels, and reformat each pane (stacked header, view
toggle, and horizontally scrollable version pickers) to suit narrow
screens. Desktop keeps the existing two-panel layout.

Signed-off-by: Matthew Bain <matt@rocketstack.co>
…mobile-responsive-vrquce

Signed-off-by: Matthew Bain <matt@rocketstack.co>

# Conflicts:
#	calm-hub-ui/index.html
#	calm-hub-ui/src/hub/components/tree-navigation/TreeNavigation.tsx
…h renders

Add a Responsive Design section covering the useIsMobile breakpoint hook, the
mobile-only-must-not-change-desktop rule, and the established mobile patterns
(full-screen overlays, navbar-hosted actions, drill-down explorer, tabbed
detail views, safe-area handling). Strengthen the Testing section to require
verifying both desktop and mobile renders, with the matchMedia mocking pattern
for unit tests.

Signed-off-by: Matthew Bain <matt@rocketstack.co>
Address Copilot review feedback: reorder handleClear above handleKeyDown and
add it to the dependency array instead of disabling react-hooks/exhaustive-deps
(the project forbids suppressing that rule), and memoise flatResults so the
keyboard-handler dependencies stay stable.

Signed-off-by: Matthew Bain <matt@rocketstack.co>
- Restore desktop Hub (logo) home link and Visualizer nav link removed by the
  responsive rework; the logo is now a router Link (keyboard-navigable).
- Resolve the latest resource version via pickLatestVersion instead of assuming
  the service returns versions in order.
- Fall back to MediaQueryList.addListener on browsers without addEventListener.
Replace the horizontally-scrolling moment cards with an iOS-style drill-down
on mobile: the detail level shows the currently-viewed moment with a forward
chevron and version count, tapping pushes a newest-first list of all versions,
and selecting one navigates the diagram and pops back. Desktop keeps the
inline TimelineBar. Compare-from/to is not exposed on touch for now (it was
right-click only).
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