Skip to content

feat(ui): apply icon-swap transition to clipboard/check icons#215

Open
RedStar071 wants to merge 2 commits into
mainfrom
feat/icon-swap-transitions
Open

feat(ui): apply icon-swap transition to clipboard/check icons#215
RedStar071 wants to merge 2 commits into
mainfrom
feat/icon-swap-transitions

Conversation

@RedStar071

Copy link
Copy Markdown
Member

🔗 Linked issue

No issue — cosmetic/UI improvement.

🧭 Context

The project uses the transitions-dev skill for production-ready CSS transitions. The icon-swap pattern (transitions.dev #9) is the correct primitive for any slot where two icons alternate based on state (e.g. clipboard → check on copy).

Previously both copy buttons swapped icons via a dynamic :name ternary on a single UIcon, which gives an abrupt replace with no visual continuity.

📚 Description

Applies the icon-swap transition (transitions.dev #9) to both clipboard ↔ check icon pairs in the app:

  • app/assets/css/utilities.css — adds the .t-icon-swap CSS block with :root custom properties (--icon-swap-dur, --icon-swap-blur, --icon-swap-start-scale, --icon-swap-ease). Both icons sit in the same inline-grid cell; data-state="a|b" drives which icon is visible via opacity + blur + scale transition. No JavaScript required.
  • app/pages/profile.vue — copy-user-id button: replaces the single dynamic UIcon with a t-icon-swap wrapper holding both icons permanently in the DOM.
  • app/components/guild/settings/General.vue — copy-server-id button: same pattern; icon moved into a #leading slot since UButton no longer receives :icon directly.

prefers-reduced-motion is already honored globally by the existing kill-switch in utilities.css (transition-duration: 0.01ms !important), so no per-component guard is needed.

Intentionally skipped:

  • ColorModeButton.vue — sun/moon swap is driven by a full-page View Transition clip animation; applying t-icon-swap inside a VT snapshot would be redundant.
  • DisabledCommands.vue chevron — single icon rotating 180°, not a two-icon swap.

- Add .t-icon-swap CSS block to utilities.css (transitions.dev #9)
- Both icons stacked in the same grid cell; state toggles via data-state
- Apply to copy-user-id button in profile.vue
- Apply to copy-server-id button in guild settings General.vue
- prefers-reduced-motion honored via existing global kill-switch in utilities.css
Copilot AI review requested due to automatic review settings May 31, 2026 15:22
@coderabbitai

coderabbitai Bot commented May 31, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@RedStar071, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 53 minutes and 46 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: 5fc4a31d-c762-49b7-858d-8e246252a9ec

📥 Commits

Reviewing files that changed from the base of the PR and between b0bee1e and c5a9add.

📒 Files selected for processing (15)
  • .agents/skills/transitions-dev/01-card-resize.md
  • .agents/skills/transitions-dev/02-number-pop-in.md
  • .agents/skills/transitions-dev/03-notification-badge.md
  • .agents/skills/transitions-dev/04-text-states-swap.md
  • .agents/skills/transitions-dev/05-menu-dropdown.md
  • .agents/skills/transitions-dev/06-modal.md
  • .agents/skills/transitions-dev/07-panel-reveal.md
  • .agents/skills/transitions-dev/08-page-side-by-side.md
  • .agents/skills/transitions-dev/09-icon-swap.md
  • .agents/skills/transitions-dev/10-success-check.md
  • .agents/skills/transitions-dev/11-avatar-group-hover.md
  • .agents/skills/transitions-dev/12-error-state-shake.md
  • .agents/skills/transitions-dev/SKILL.md
  • .agents/skills/transitions-dev/_root.css
  • skills-lock.json
📝 Walkthrough

Walkthrough

This PR introduces a reusable CSS-based icon swap animation utility and applies it to improve visual feedback on two copy-to-clipboard buttons. The animation smoothly cross-fades between icons with configurable timing, blur, and scale effects.

Changes

Icon Swap Animation Feature

Layer / File(s) Summary
Icon swap CSS styling foundation
app/assets/css/utilities.css
Adds .t-icon-swap container styles and data-state/data-icon-driven cross-fade transitions with custom properties (--icon-swap-dur, --icon-swap-blur, --icon-swap-start-scale, --icon-swap-ease) controlling animation behaviour.
Copy button icon swap implementations
app/components/guild/settings/General.vue, app/pages/profile.vue
Server ID and user ID copy buttons refactored from conditional :icon binding to dual-icon markup wrapped in data-state-toggled containers, enabling the new cross-fade animation when copy state changes.

Suggested reviewers

  • lorypelli
🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and concisely describes the main change: applying the icon-swap transition to clipboard and check icons across the application.
Description check ✅ Passed The description is comprehensive and directly related to the changeset, explaining the rationale, implementation details, and intentional omissions.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ 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 feat/icon-swap-transitions

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.

@sentry

sentry Bot commented May 31, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 66.53%. Comparing base (be362fb) to head (c5a9add).
✅ All tests successful. No failed tests found.

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main     #215      +/-   ##
==========================================
+ Coverage   66.52%   66.53%   +0.01%     
==========================================
  Files         103      103              
  Lines        2306     2307       +1     
  Branches      472      472              
==========================================
+ Hits         1534     1535       +1     
  Misses        412      412              
  Partials      360      360              
Flag Coverage Δ
component 57.07% <100.00%> (+0.02%) ⬆️
unit 67.56% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
app/components/guild/settings/General.vue 77.19% <100.00%> (+0.40%) ⬆️
🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@codspeed-hq

codspeed-hq Bot commented May 31, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 44 untouched benchmarks


Comparing feat/icon-swap-transitions (c5a9add) with main (be362fb)

Open in CodSpeed

@coderabbitai coderabbitai Bot left a comment

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.

🧹 Nitpick comments (1)
app/assets/css/utilities.css (1)

384-391: 💤 Low value

Consider conditionally applying will-change for better performance.

The will-change property is currently set permanently on all .t-icon elements within the swap container. Best practice recommends applying will-change only during the actual transition rather than statically, to avoid unnecessary compositor layers.

Since there are only a few icon-swap buttons per page, the current impact is minimal, but you could optimise by moving will-change to a state-based rule (e.g., .t-icon-swap:hover .t-icon or during data-state transitions).

♻️ Optional optimisation
 .t-icon-swap .t-icon {
 	grid-area: 1 / 1;
 	transition:
 		opacity var(--icon-swap-dur) var(--icon-swap-ease),
 		filter var(--icon-swap-dur) var(--icon-swap-ease),
 		transform var(--icon-swap-dur) var(--icon-swap-ease);
-	will-change: opacity, filter, transform;
 }
+
+.t-icon-swap:hover .t-icon,
+.t-icon-swap:focus-within .t-icon {
+	will-change: opacity, filter, transform;
+}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/assets/css/utilities.css` around lines 384 - 391, The current
.t-icon-swap .t-icon rule applies will-change permanently; remove will-change
from that base rule and instead add a state-based rule (e.g., .t-icon-swap:hover
.t-icon, .t-icon-swap:focus .t-icon and/or .t-icon-swap[data-state="active"]
.t-icon) that sets will-change: opacity, filter, transform only while the swap
is active, ensuring the existing transitions (opacity/filter/transform using
--icon-swap-dur and --icon-swap-ease) still apply; this limits compositor hints
to the actual transition period and improves performance.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@app/assets/css/utilities.css`:
- Around line 384-391: The current .t-icon-swap .t-icon rule applies will-change
permanently; remove will-change from that base rule and instead add a
state-based rule (e.g., .t-icon-swap:hover .t-icon, .t-icon-swap:focus .t-icon
and/or .t-icon-swap[data-state="active"] .t-icon) that sets will-change:
opacity, filter, transform only while the swap is active, ensuring the existing
transitions (opacity/filter/transform using --icon-swap-dur and
--icon-swap-ease) still apply; this limits compositor hints to the actual
transition period and improves performance.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: 698345b9-dd7b-49c4-9989-a69fdd5d6bc5

📥 Commits

Reviewing files that changed from the base of the PR and between be362fb and b0bee1e.

📒 Files selected for processing (3)
  • app/assets/css/utilities.css
  • app/components/guild/settings/General.vue
  • app/pages/profile.vue

Copilot AI left a comment

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.

Pull request overview

Applies the transitions.dev #9 "icon-swap" pattern to the two clipboard ↔ check copy buttons (profile page and guild general settings), replacing the dynamic :name/:icon ternary with both icons rendered in the same grid cell and cross-faded via CSS based on data-state. Adds the reusable .t-icon-swap utility globally; relies on the existing reduced-motion kill switch.

Changes:

  • Add .t-icon-swap CSS utility and --icon-swap-* custom properties in utilities.css.
  • Refactor profile copy-user-id button to render both icons inside a .t-icon-swap wrapper.
  • Refactor guild settings copy-server-id button similarly, moving the icon out of :icon into a #leading slot.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.

File Description
app/assets/css/utilities.css New .t-icon-swap block + root custom properties for the cross-fade transition.
app/pages/profile.vue Copy-user-id button now renders both clipboard/check icons inside the swap wrapper.
app/components/guild/settings/General.vue Copy-server-id button switched from :icon prop to #leading slot using the swap wrapper.

Comment on lines +28 to +33
<template #leading>
<span class="t-icon-swap" :data-state="copied ? 'b' : 'a'" aria-hidden="true">
<UIcon name="heroicons:clipboard-document" class="t-icon" data-icon="a" />
<UIcon name="heroicons:check" class="t-icon" data-icon="b" />
</span>
</template>
Comment thread app/pages/profile.vue
Comment on lines +78 to +89
<span
class="t-icon-swap"
:data-state="copied ? 'b' : 'a'"
aria-hidden="true"
>
<UIcon
name="heroicons:clipboard-document"
class="t-icon"
data-icon="a"
/>
<UIcon name="heroicons:check" class="t-icon" data-icon="b" />
</span>
Comment on lines +384 to +391
.t-icon-swap .t-icon {
grid-area: 1 / 1;
transition:
opacity var(--icon-swap-dur) var(--icon-swap-ease),
filter var(--icon-swap-dur) var(--icon-swap-ease),
transform var(--icon-swap-dur) var(--icon-swap-ease);
will-change: opacity, filter, transform;
}
- Introduce avatar group hover transition with customizable lift, scale, and easing.
- Implement error state shake transition for form validation feedback.
- Create a comprehensive SKILL.md for transitions with usage examples and decision rules.
- Add universal CSS root variables for consistent transition styling.
- Update skills-lock.json to include transitions-dev skill.
@RedStar071 RedStar071 enabled auto-merge June 2, 2026 11:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants