Skip to content

Add organism switch button to navigation submenu#6229

Open
theosanderson wants to merge 22 commits intomainfrom
claude/organism-menu-button-B6e91
Open

Add organism switch button to navigation submenu#6229
theosanderson wants to merge 22 commits intomainfrom
claude/organism-menu-button-B6e91

Conversation

@theosanderson
Copy link
Copy Markdown
Member

@theosanderson theosanderson commented Apr 2, 2026

Adds a button to help people confused about how to switch organism to find the organism menu.

image

The rationale for this somewhat odd design is that it's confusing to have two totally different UI elements to do the same thing as part of the main UI, but it's also confusing that people expect there to be a way to change organism from the left hand UI and that they can't atm.

Because the elements are in Astro not React the code is a bit different to our normal style, and generally it probably looks quite hacky. In my view it's basically fine though.

Discussion in https://loculus.slack.com/archives/C061ZQQM3N1/p1775646115881829

🚀 Preview: https://claude-organism-menu-butt.loculus.org

claude added 2 commits April 2, 2026 17:06
Add an exchange icon button next to the organism display name in the
submenu bar. Clicking it opens the existing organism dropdown menu in
the main navigation, providing a convenient way to switch organisms
without scrolling up to the nav bar.

https://claude.ai/code/session_01QsptMMA4uYLEkcEa8uLvjb
@claude claude bot added the website Tasks related to the web application label Apr 2, 2026
@theosanderson theosanderson added the preview Triggers a deployment to argocd label Apr 2, 2026
claude and others added 12 commits April 2, 2026 17:08
…ch button

Replace inline SVG with the proper unplugin-icons import for FaExchangeAlt.

https://claude.ai/code/session_01QsptMMA4uYLEkcEa8uLvjb
The button in OrganismSubmenu.astro is server-rendered and wired via a
vanilla <script> tag, so the React hydration wrapper is not applicable.

https://claude.ai/code/session_01QsptMMA4uYLEkcEa8uLvjb
- Use #organism-menu id to find the MenuButton instead of a data
  attribute that wasn't forwarded through NavigationTab
- Make the exchange icon smaller and bottom-aligned for a subscript look

https://claude.ai/code/session_01QsptMMA4uYLEkcEa8uLvjb
On mobile, the desktop organism dropdown is hidden, so the switch button
now dispatches an 'open-sandwich-menu' custom event. The SandwichMenu
component listens for this event and opens accordingly. On desktop, it
continues to click the organism dropdown as before.

https://claude.ai/code/session_01QsptMMA4uYLEkcEa8uLvjb
When clicking the switch button on desktop, a small primary-colored dot
animates from the button to the organism dropdown menu, then the dropdown
opens. This provides a visual cue connecting the two UI elements.

https://claude.ai/code/session_01QsptMMA4uYLEkcEa8uLvjb
Clone the SVG icon from the switch button and animate it to the organism
dropdown. Uses z-index 2147483647 (max) to ensure it renders on top of
everything.

https://claude.ai/code/session_01QsptMMA4uYLEkcEa8uLvjb
Read the primary color from Tailwind at runtime via getComputedStyle on
a temporary text-primary element, instead of hardcoding the hex value.
Also add a box-shadow flash on the Organisms button when the flying icon
arrives.

https://claude.ai/code/session_01QsptMMA4uYLEkcEa8uLvjb
The flying icon inherits its original gray color from the button. The
arrival flash on the Organisms button uses the Tailwind primary color
read dynamically via getComputedStyle.

https://claude.ai/code/session_01QsptMMA4uYLEkcEa8uLvjb
The flying icon now has a primary-colored drop-shadow glow that
intensifies as it travels, making it much more visible against the
page background. Also colors the icon itself in the primary color
during flight.

https://claude.ai/code/session_01QsptMMA4uYLEkcEa8uLvjb
Replace the static drop-shadow glow with actual trailing ghost copies
of the icon that spawn every 25ms along the flight path and fade out
over 200ms, creating a visible trail behind the moving icon.

https://claude.ai/code/session_01QsptMMA4uYLEkcEa8uLvjb
@theosanderson
Copy link
Copy Markdown
Member Author

@theosanderson-agent fix types and format

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@theosanderson-agent
Copy link
Copy Markdown
Collaborator

Types are clean (tsc --noEmit and astro check both pass with no errors). Fixed one Prettier formatting issue in OrganismSubmenu.astro (expanded an arrow function body onto multiple lines). Pushed in 1b6235f.

@theosanderson
Copy link
Copy Markdown
Member Author

@theosanderson-agent get format passing

@theosanderson
Copy link
Copy Markdown
Member Author

@theosanderson-agent can we get the color from colors.json instead?

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@theosanderson-agent
Copy link
Copy Markdown
Collaborator

Fixed the Prettier formatting issue in OrganismSubmenu.astro — it was an indentation mismatch inside the <span> block.

…olor

Import mainTailwindColor from colors.json in the Astro frontmatter and
pass the primary color (shade 400) to the client-side script via a
data-primary-color attribute. This replaces the DOM probe approach that
created a temporary element with text-primary class to read the computed
color at runtime.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@theosanderson-agent
Copy link
Copy Markdown
Collaborator

Done — now importing mainTailwindColor from colors.json in the Astro frontmatter and passing the [400] shade (which matches primary.DEFAULT in the Tailwind config) to the script via a data-primary-color attribute on the button. This replaces the DOM probe approach that was creating a temporary element to read the computed style. Pushed to the branch.

@theosanderson
Copy link
Copy Markdown
Member Author

@theosanderson-agent fix format and types and format

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@theosanderson-agent
Copy link
Copy Markdown
Collaborator

Fixed: ESLint flagged an import order issue in OrganismSubmenu.astro (the colors.json import needed to be sorted before the local type imports). No type errors or test failures — all 622 tests pass.

@theosanderson theosanderson marked this pull request as ready for review April 16, 2026 11:47
@claude
Copy link
Copy Markdown
Contributor

claude bot commented Apr 16, 2026

Claude finished @theosanderson's task in 1m 45s —— View job


Code Review

  • Gather context
  • Read changed files
  • Provide review feedback

The implementation is clean and the approach makes sense — using a vanilla JS script in the Astro component to bridge to either the React desktop menu or the mobile sandwich menu is pragmatic given the mixed rendering context.

Specific comments are left inline; summary of the two points:

  1. querySelector single-matchdocument.querySelector('[data-organism-switch-button]') only wires up the first button. Fine for the current page layout (at most one organism nav rendered at a time), but fragile if that assumption changes.

  2. Rapid-click race — multiple quick clicks each start independent animation loops and each eventually call menuButton.click(), which can toggle the menu closed again. An isAnimating guard would fix this.

The rest looks good:

  • useOffCanvas.open is a stable useCallback ref, so the new useEffect in SandwichMenu won't re-register the listener on every render.
  • Ghost elements are cleaned up via setTimeout and the main wrapper is removed in the animation's final frame — no leaks.
  • primaryColor is read from colors.json at build time, not user input, so injecting it into cssText is safe.
  • The eslint-disable-next-line no-restricted-syntax comment correctly documents why a native <button> is used here instead of the app's Button wrapper (Astro SSR, no React hydration).
  • The mobile fallback via window.dispatchEvent(new Event('open-sandwich-menu')) is tidy and the cleanup in useEffect is correct.

Comment thread website/src/components/Navigation/OrganismSubmenu.astro
Comment thread website/src/components/Navigation/OrganismSubmenu.astro
Add an isAnimating flag so a second click during the in-flight icon
animation no longer queues an extra menuButton.click(), which could
otherwise toggle the menu open then immediately closed.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

preview Triggers a deployment to argocd website Tasks related to the web application

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants