Skip to content

Replace install platform dropdown with button group#1

Closed
bschellenberger2600 wants to merge 1 commit into
mainfrom
feature/platform-install-buttons
Closed

Replace install platform dropdown with button group#1
bschellenberger2600 wants to merge 1 commit into
mainfrom
feature/platform-install-buttons

Conversation

@bschellenberger2600
Copy link
Copy Markdown
Member

@bschellenberger2600 bschellenberger2600 commented Apr 16, 2026

Summary

Replaces the platform <select> in InstallPicker with a segmented button radiogroup (macOS, Windows, Linux, Go) so the install surface matches the rest of the site’s control style.

Changes

  • Markup: role="radiogroup" / role="radio", labeled via aria-labelledby; platform label is a p.install-picker__label instead of label for.
  • Script: Same sessionStorage sync across pickers; aria-checked + roving tabindex; arrow keys and Home/End to move selection; focus stays on the active control after keyboard navigation.
  • Styles: Platform row + per-product active styling via data-product; copy button styles scoped to .install-picker__actions so platform buttons stay distinct.

How to verify

  1. npm run build
  2. On the index page, pick a platform in one install block and confirm the other product’s picker updates to match.
  3. Tab to the group, use arrows / Home / End, and confirm commands and notes update.

Summary by CodeRabbit

  • New Features

    • Added keyboard navigation support for platform selection using arrow keys, Home, and End keys.
  • Style

    • Redesigned platform selector from dropdown menu to button-based interface with improved visual feedback and usability.

Use segmented platform buttons with shared session state, radiogroup
semantics, and arrow-key navigation. Scope copy-button styles to actions
so platform controls keep their own look.

Made-with: Cursor
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 16, 2026

📝 Walkthrough

Walkthrough

The changes replace a traditional HTML <select>-based platform picker with a custom accessible button-based radiogroup interface, featuring keyboard navigation support and ARIA attributes. Updates span the component markup, JavaScript event handling, and CSS styling.

Changes

Cohort / File(s) Summary
Component Structure
src/components/InstallPicker.astro
Replaced <select> element with a <div role="radiogroup"> containing four <button role="radio"> elements. Updated label from <label> to <p> with matching id. Platform buttons use data-install-platform attributes for selection tracking.
Script Logic
src/scripts/install-pickers.ts
Replaced select-based picker mechanism with button radiogroup. Added PLATFORM_ORDER constant and coerceOs() validation. Implemented bindPlatformRadiogroup() with click and keyboard event handling (Arrow/Home/End keys). Updated renderPicker() and setPlatformEverywhere() to read/update button aria-checked state instead of select .value.
Styling
src/styles/global.css
Refactored selectors to BEM-style classes (.install-picker__label, .install-picker__platforms, .install-picker__platform-btn). Added flex-wrapped platforms container layout. Styled individual platform buttons with padding, font weight, hover states, and product-specific active coloring via data-product attribute.

Sequence Diagram

sequenceDiagram
    actor User
    participant Component as InstallPicker<br/>(Astro)
    participant Script as install-pickers<br/>(JS Logic)
    participant DOM as DOM/State
    participant Style as CSS Styling

    User->>Component: Page loads with platform picker
    Component->>DOM: Render radiogroup with buttons
    DOM->>Style: Apply default styles
    Style-->>User: Display picker UI

    User->>Script: Click platform button
    Script->>DOM: Update aria-checked state
    Script->>Script: Call syncPlatformButtons()
    DOM->>Style: Reapply active state styles
    Style-->>User: Highlight selected platform

    User->>Script: Press Arrow/Home/End key
    Script->>Script: Calculate new platform position
    Script->>DOM: Update aria-checked & focus new button
    Script->>Script: Call queueMicrotask for focus
    DOM->>Style: Apply active styling to new button
    Style-->>User: Visual feedback on selection
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 Buttons now dance where selects once stood,
Keyboard arrows flow through the neighborhood,
ARIA whispers keep the vision clear,
Radiogroups spin—accessibility's here! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: replacing a dropdown select with button-based radio controls for platform selection.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/platform-install-buttons

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (3)
src/styles/global.css (1)

510-520: Consider adding cursor: default to active platform buttons.

Active buttons retain cursor: pointer from the base style, which suggests interactivity even though re-clicking them has no meaningful effect. Setting cursor: default improves the UX signal.

♻️ Optional improvement
 .install-picker[data-product='git-fire'] .install-picker__platform-btn--active {
 	color: var(--color-fire);
 	border-color: color-mix(in srgb, var(--color-fire) 45%, var(--color-border));
 	background: color-mix(in srgb, var(--color-fire) 12%, var(--color-bg));
+	cursor: default;
 }
 
 .install-picker[data-product='git-rain'] .install-picker__platform-btn--active {
 	color: var(--color-rain);
 	border-color: color-mix(in srgb, var(--color-rain) 45%, var(--color-border));
 	background: color-mix(in srgb, var(--color-rain) 12%, var(--color-bg));
+	cursor: default;
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/styles/global.css` around lines 510 - 520, Add cursor: default to the
active platform button rules so the .install-picker__platform-btn--active state
no longer shows the pointer cursor from the base .install-picker__platform-btn
styles; update both selectors (.install-picker[data-product='git-fire']
.install-picker__platform-btn--active and
.install-picker[data-product='git-rain'] .install-picker__platform-btn--active)
to include cursor: default to clearly signal non-interactivity when already
active.
src/scripts/install-pickers.ts (2)

29-37: Minor duplication with coerceOs logic.

The type guard in storedOs duplicates what coerceOs already provides. Consider reusing it for consistency.

♻️ Optional refactor
 function storedOs(): OsFamily | null {
 	try {
-		const v = sessionStorage.getItem(STORAGE_KEY);
-		if (v === 'macos' || v === 'windows' || v === 'linux' || v === 'go') return v;
+		return coerceOs(sessionStorage.getItem(STORAGE_KEY) ?? undefined);
 	} catch {
 		/* private mode */
 	}
 	return null;
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/scripts/install-pickers.ts` around lines 29 - 37, The storedOs() function
duplicates the OS validation logic; replace the manual string checks by
delegating to coerceOs: read sessionStorage.getItem(STORAGE_KEY) into a variable
inside storedOs(), then pass that value to coerceOs(...) and return its result
(or null) while preserving the try/catch for private mode; update references to
storedOs accordingly and remove the redundant string checks so coerceOs becomes
the single source of truth for OS coercion.

204-212: Picker initialization depends on copy button presence.

The early return on line 206 means if copyBtn is missing, the entire picker (including platform buttons) won't initialize. This is fine since the component always includes the copy button, but be aware of this coupling if the component structure changes.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/scripts/install-pickers.ts` around lines 204 - 212, The early return when
copyBtn is missing prevents initialization of the pickers (storedOs/detectOs,
syncPlatformButtons, renderPicker, bindPlatformRadiogroup) because the code
returns immediately if copyBtn is falsy; remove or move that early return so
picker initialization runs regardless of the presence of copyBtn (i.e., ensure
syncPlatformButtons(root, initial), renderPicker(root), and
bindPlatformRadiogroup(root) execute with the detected initial value even when
copyBtn is null) while still optionally guarding only copy-button-specific logic
behind a copyBtn check.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/scripts/install-pickers.ts`:
- Around line 29-37: The storedOs() function duplicates the OS validation logic;
replace the manual string checks by delegating to coerceOs: read
sessionStorage.getItem(STORAGE_KEY) into a variable inside storedOs(), then pass
that value to coerceOs(...) and return its result (or null) while preserving the
try/catch for private mode; update references to storedOs accordingly and remove
the redundant string checks so coerceOs becomes the single source of truth for
OS coercion.
- Around line 204-212: The early return when copyBtn is missing prevents
initialization of the pickers (storedOs/detectOs, syncPlatformButtons,
renderPicker, bindPlatformRadiogroup) because the code returns immediately if
copyBtn is falsy; remove or move that early return so picker initialization runs
regardless of the presence of copyBtn (i.e., ensure syncPlatformButtons(root,
initial), renderPicker(root), and bindPlatformRadiogroup(root) execute with the
detected initial value even when copyBtn is null) while still optionally
guarding only copy-button-specific logic behind a copyBtn check.

In `@src/styles/global.css`:
- Around line 510-520: Add cursor: default to the active platform button rules
so the .install-picker__platform-btn--active state no longer shows the pointer
cursor from the base .install-picker__platform-btn styles; update both selectors
(.install-picker[data-product='git-fire'] .install-picker__platform-btn--active
and .install-picker[data-product='git-rain']
.install-picker__platform-btn--active) to include cursor: default to clearly
signal non-interactivity when already active.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a01cb354-fc27-4030-bd6a-5c90ee51e7d0

📥 Commits

Reviewing files that changed from the base of the PR and between 37c80d4 and c6833e6.

📒 Files selected for processing (3)
  • src/components/InstallPicker.astro
  • src/scripts/install-pickers.ts
  • src/styles/global.css

@bschellenberger2600
Copy link
Copy Markdown
Member Author

@cursoragent Ibelieve this branch is now obselete

@cursor
Copy link
Copy Markdown

cursor Bot commented Apr 16, 2026

Here is what the repo shows.

The comment is right: this branch is obsolete relative to main.

main is ahead of feature/platform-install-buttons because it merged the work from feature/install-or-methods (merge commit 751882d), whose message is “Install picker: platform buttons plus Linux/Windows method options”. So main already has the platform button radiogroup and more (install-method radiogroup, detect hint, different sessionStorage keys, etc.).

Your branch tip is still the older single commit c6833e6 (“Replace install platform select…”). A test merge of origin/main into this branch conflicts in the same three files, and a straight diff shows this branch would drop the method area and detect hint from InstallPicker.astro compared to main—so merging this PR would be a regression, not a small follow-up.

PR status: PR #1 for this branch is already closed in GitHub, so there is nothing further you must do on the PR for “obsolete” to be handled.

Optional cleanup: If you want the name gone from the remote, you can delete feature/platform-install-buttons on origin when you are sure nobody still needs that pointer; I did not delete it from here since that is a destructive repo operation you may want to decide yourself.

I did not change code or push commits: the correct action is to treat main + the merged install-or-methods work as the source of truth, not this branch.

Open in Web Open in Cursor 

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