Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,11 @@ export function SidebarCardSlot({
{!isCollapsed && entry && (
<motion.div
key={entry.id}
initial={{ opacity: 0, y: 8 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: 8 }}
transition={{ duration: 0.2 }}
className="px-3 pb-2"
initial={{ opacity: 0, y: 8, scale: 0.98 }}

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.

P2: The new scale transform runs unconditionally, so users with prefers-reduced-motion enabled still receive the newly introduced scale entry/exit animation. Use useReducedMotion() to disable the added scale and transition for this slot.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At apps/desktop/src/renderer/components/SidebarCardSlot/SidebarCardSlot.tsx, line 47:

<comment>The new scale transform runs unconditionally, so users with `prefers-reduced-motion` enabled still receive the newly introduced scale entry/exit animation. Use `useReducedMotion()` to disable the added scale and transition for this slot.</comment>

<file context>
@@ -44,11 +44,11 @@ export function SidebarCardSlot({
-					exit={{ opacity: 0, y: 8 }}
-					transition={{ duration: 0.2 }}
-					className="px-3 pb-2"
+					initial={{ opacity: 0, y: 8, scale: 0.98 }}
+					animate={{ opacity: 1, y: 0, scale: 1 }}
+					exit={{ opacity: 0, y: 8, scale: 0.98 }}
</file context>

animate={{ opacity: 1, y: 0, scale: 1 }}
exit={{ opacity: 0, y: 8, scale: 0.98 }}
transition={{ duration: 0.3, ease: [0.22, 1, 0.36, 1] }}
className="px-4 pb-2"
>
<SidebarCard
badge={entry.badge}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,7 @@ export function useReleaseNotesCard(): SidebarCardEntry | null {
title: t({ message: `Paradev ${version}` }),
description: formatReleaseDate(release.date, { withYear: false }),
media: release.image ? (
<img
src={release.image}
alt=""
className="aspect-[16/9] w-full object-cover"
/>
<img src={release.image} alt="" className="block h-auto w-full" />
) : undefined,
onClick: () => {
track("release_notes_card_clicked", { version });
Expand Down
97 changes: 78 additions & 19 deletions packages/ui/src/components/ui/sidebar-card.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { msg } from "@lingui/core/macro";
import type * as React from "react";
import { LuX } from "react-icons/lu";
import { LuMinus, LuX } from "react-icons/lu";
import { i18n } from "../../lib/i18n";
import { cn } from "../../lib/utils";
import { Badge } from "./badge";
Expand Down Expand Up @@ -33,6 +33,80 @@ function SidebarCard({
className,
children,
}: SidebarCardProps) {
const dismissLabel = i18n._(
msg({
message: "Dismiss",
}),
);

if (media) {
return (
<div
data-slot="sidebar-card"
className={cn(
"group relative isolate overflow-hidden rounded-xl border border-white/10 bg-black shadow-sm",
"transition-[transform,box-shadow] duration-300 ease-out hover:-translate-y-0.5 hover:shadow-lg",
className,
)}
>
<div className="relative">
<div className="transition-transform duration-500 ease-out group-hover:scale-[1.04]">
{media}
</div>
<div className="pointer-events-none absolute inset-0 bg-gradient-to-t from-black via-black/70 via-35% to-transparent to-70%" />
<div className="pointer-events-none absolute inset-x-0 bottom-0 p-3.5">
{badge && <Badge variant="box">{badge}</Badge>}
<p
className={cn("text-sm font-medium text-white", badge && "mt-2")}
>
{title}
</p>
{description && (
<p className="mt-0.5 text-sm text-white/55 leading-snug">
{description}
</p>
)}
</div>
</div>

{onClick && (
<button
type="button"
onClick={onClick}
aria-label={title}
className="absolute inset-0 z-10 rounded-xl focus-visible:outline-2 focus-visible:outline-ring"
/>
)}

{onDismiss && (
<button
type="button"
onClick={onDismiss}
aria-label={dismissLabel}
className="absolute top-1.5 right-1.5 z-20 flex size-6 items-center justify-center rounded-md text-white/70 opacity-0 transition-[opacity,color,background-color] duration-200 hover:bg-white/10 hover:text-white focus-visible:opacity-100 group-hover:opacity-100"
>
<LuMinus className="size-3.5" />
</button>
)}

{children}

{actionLabel && onAction && (
<div className="relative z-20 px-3 pb-3">
<Button
variant="outline"
size="sm"
className="w-full h-7 text-xs"
onClick={onAction}
>
{actionLabel}
</Button>
</div>
)}
</div>
);
}

return (
<div
data-slot="sidebar-card"
Expand All @@ -51,31 +125,16 @@ function SidebarCard({
/>
)}

{media && (
<div className="-mx-1 -mt-1 mb-2.5 overflow-hidden rounded-md">
{media}
</div>
)}

{badge && <Badge variant="box">{badge}</Badge>}

{onDismiss && (
<button
type="button"
onClick={onDismiss}
aria-label={i18n._(
msg({
message: "Dismiss",
}),
)}
className={cn(
"absolute z-10 text-muted-foreground hover:text-foreground transition-colors",
media
? "-top-2 -right-2 flex size-5 items-center justify-center rounded-full border border-border bg-card shadow-sm"
: "top-2.5 right-2.5",
)}
aria-label={dismissLabel}
className="absolute top-2.5 right-2.5 z-10 text-muted-foreground hover:text-foreground transition-colors"
>
<LuX className={media ? "size-3" : "size-3.5"} />
<LuX className="size-3.5" />
</button>
)}

Expand Down
Loading