Skip to content

fix: improve compare scatter chart legend#2493

Open
graphieros wants to merge 4 commits intomainfrom
compare-scatter-legend
Open

fix: improve compare scatter chart legend#2493
graphieros wants to merge 4 commits intomainfrom
compare-scatter-legend

Conversation

@graphieros
Copy link
Copy Markdown
Contributor

@graphieros graphieros commented Apr 12, 2026

Follow up to #2472

This improves the legend of the scatter chart on the compare page, by positioning the items on the side, below the select inputs.
On mobile, the previous behavior is maintained.

image

One downside: the legend is not part of the png export, however since the chart bears labels above datapoints, we can live with that.

@vercel
Copy link
Copy Markdown

vercel bot commented Apr 12, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
npmx.dev Ready Ready Preview, Comment Apr 12, 2026 8:22pm
2 Skipped Deployments
Project Deployment Actions Updated (UTC)
docs.npmx.dev Ignored Ignored Preview Apr 12, 2026 8:22pm
npmx-lunaria Ignored Ignored Apr 12, 2026 8:22pm

Request Review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 12, 2026

📝 Walkthrough

Walkthrough

Responsive legend placement was added to the FacetScatterChart component: component width is measured to set an isMobile flag (640px breakpoint), a readyTeleport flag defers Teleport rendering until mount, and legend markup was refactored to a semantic <ul>/<li> structure with Teleport-based placement into dedicated legend containers.

Changes

Cohort / File(s) Summary
Legend Responsiveness Refactor
app/components/Compare/FacetScatterChart.vue
Added width-based isMobile detection (640px) via element sizing; introduced readyTeleport to defer Teleport until DOM targets exist; added outer #compare-scatter-legend and inner #compare-scatter-legend-inner containers and conditional Teleport targets; converted legend markup to semantic <ul>/<li> with adjusted button spacing and aria-hidden color-dot wrapper; added translated h3 header and removed sm:self-end/sm:mb-17 from the left column wrapper.

Suggested reviewers

  • ghostdevv
  • alexdln
🚥 Pre-merge checks | ✅ 2
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'fix: improve compare scatter chart legend' directly describes the main change: enhancing the legend component of the scatter chart with improved positioning and responsive behaviour.
Description check ✅ Passed The PR description directly addresses the changeset, explaining the legend improvement for the scatter chart on the compare page with clear context about positioning and mobile behaviour.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch compare-scatter-legend

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.

@codecov
Copy link
Copy Markdown

codecov bot commented Apr 12, 2026

Codecov Report

❌ Patch coverage is 47.36842% with 10 lines in your changes missing coverage. Please review.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
app/components/Compare/FacetScatterChart.vue 47.36% 10 Missing ⚠️

📢 Thoughts on this report? Let us know!

Copy link
Copy Markdown
Contributor

@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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@app/components/Compare/FacetScatterChart.vue`:
- Around line 372-409: The mobile teleport target <div
id="compare-scatter-legend-inner"> currently lacks the labelled semantics
present on the desktop target; update that element so it mirrors the desktop
target's accessibility attributes (add role="group" and aria-labelledby pointing
to the same legend label id used by the desktop container) so the Teleported
legend (template `#legend` and Teleport) retains the labelled semantics on mobile;
ensure the referenced label element id exists (or add a visually-hidden label)
to match the desktop aria-labelledby target.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 33dc18dc-5a54-48fc-81d1-820e1d09862c

📥 Commits

Reviewing files that changed from the base of the PR and between f70a11b and d0fea09.

📒 Files selected for processing (1)
  • app/components/Compare/FacetScatterChart.vue

Copy link
Copy Markdown
Contributor

@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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@app/components/Compare/FacetScatterChart.vue`:
- Around line 350-355: The component renders two legend containers that both use
role="group" and the same aria-labelledby ("scatter-chart-legend-packages"),
which exposes duplicate/empty groups to assistive tech; locate the div with
id="compare-scatter-legend" and the other legend container that reuses
aria-labelledby="scatter-chart-legend-packages" inside FacetScatterChart.vue and
change the behavior so only a non-empty legend is in the a11y tree—either
conditionally render the empty container (render it only when it has items), or
keep it rendered but add aria-hidden="true" (or remove role/aria-labelledby)
when empty; ensure the remaining visible legend keeps role="group" and the
aria-labelledby value.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 6e8fdee5-45d2-4153-a4fe-992f3d879eec

📥 Commits

Reviewing files that changed from the base of the PR and between d0fea09 and 78b668b.

📒 Files selected for processing (1)
  • app/components/Compare/FacetScatterChart.vue

Copy link
Copy Markdown
Contributor

@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.

Actionable comments posted: 1

🧹 Nitpick comments (1)
app/components/Compare/FacetScatterChart.vue (1)

19-23: Keep the JS/mobile switch tied to the same breakpoint source as the layout.

isMobile now decides which legend container is used, while the layout itself still flips with sm: utilities. Hard-coding 640 here means the JS and CSS can drift later, leaving the legend in the wrong place for the rendered layout.

Also applies to: 310-345

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

In `@app/components/Compare/FacetScatterChart.vue` around lines 19 - 23, Replace
the hard-coded mobile breakpoint (mobileBreakpointWidth = 640) with a value read
from a CSS custom property so JS uses the same breakpoint source as the layout:
define a global CSS var (e.g. --screen-sm) that matches Tailwind's sm breakpoint
in your stylesheet, then in this component read it via
getComputedStyle(rootEl).getPropertyValue('--screen-sm') (parseInt) and use that
value when computing isMobile; update the symbols mobileBreakpointWidth and
isMobile (which use useElementSize and rootEl) to derive the breakpoint from the
CSS var instead of the literal 640.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@app/components/Compare/FacetScatterChart.vue`:
- Around line 285-290: The custom legend slot is currently guarded by
readyTeleport which hides the slot briefly and lets VueUiScatter render its
default legend; remove the v-if from the template slot so the custom legend slot
is always present, and instead add the v-if="readyTeleport" only to the Teleport
element that mounts the legend; keep the readyTeleport shallowRef and onMounted
logic as-is and ensure the slot markup (customLegend / whatever slot name is
used) remains unconditional while only the <Teleport> wrapper is conditional.

---

Nitpick comments:
In `@app/components/Compare/FacetScatterChart.vue`:
- Around line 19-23: Replace the hard-coded mobile breakpoint
(mobileBreakpointWidth = 640) with a value read from a CSS custom property so JS
uses the same breakpoint source as the layout: define a global CSS var (e.g.
--screen-sm) that matches Tailwind's sm breakpoint in your stylesheet, then in
this component read it via
getComputedStyle(rootEl).getPropertyValue('--screen-sm') (parseInt) and use that
value when computing isMobile; update the symbols mobileBreakpointWidth and
isMobile (which use useElementSize and rootEl) to derive the breakpoint from the
CSS var instead of the literal 640.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 699646b7-d367-429a-a238-1584b5d2ab59

📥 Commits

Reviewing files that changed from the base of the PR and between 78b668b and 5486e45.

📒 Files selected for processing (1)
  • app/components/Compare/FacetScatterChart.vue

@graphieros graphieros requested a review from alexdln April 12, 2026 20:24
@graphieros graphieros enabled auto-merge April 12, 2026 20:27
@serhalp serhalp added the needs review This PR is waiting for a review from a maintainer label Apr 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs review This PR is waiting for a review from a maintainer

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants