Skip to content

Commit ad291db

Browse files
committed
feat: 提供可关闭的浮窗
1 parent 0e4ed52 commit ad291db

File tree

1 file changed

+91
-85
lines changed

1 file changed

+91
-85
lines changed

app/components/ActivityTicker.tsx

Lines changed: 91 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import Image from "next/image";
44
import Link from "next/link";
55
import React, { useCallback, useEffect, useMemo, useState } from "react";
6-
import { ChevronLeft, ChevronRight } from "lucide-react";
6+
import { ChevronLeft, ChevronRight, X } from "lucide-react";
77
import {
88
activityEventsConfig,
99
type ActivityEvent,
@@ -44,19 +44,11 @@ export function ActivityTicker({ className }: ActivityTickerProps) {
4444
const [activeIndex, setActiveIndex] = useState(0);
4545
const totalEvents = events.length;
4646

47-
// 拖拽坐标
48-
const [offset, setOffset] = useState({ x: 0, y: 0 });
49-
const [dragStart, setDragStart] = useState<{ x: number; y: number } | null>(
50-
null,
51-
);
52-
53-
const handlePointerDown = (event: React.PointerEvent<HTMLDivElement>) => {
54-
event.currentTarget.setPointerCapture(event.pointerId);
55-
setDragStart({ x: event.clientX - offset.x, y: event.clientY - offset.y });
56-
};
47+
// 控制浮窗显隐
48+
const [isClosed, setIsClosed] = useState(false);
5749

5850
useEffect(() => {
59-
if (totalEvents <= 1) {
51+
if (isClosed || totalEvents <= 1) {
6052
return;
6153
}
6254

@@ -66,7 +58,7 @@ export function ActivityTicker({ className }: ActivityTickerProps) {
6658
}, ROTATION_INTERVAL_MS);
6759

6860
return () => window.clearInterval(timer);
69-
}, [totalEvents, activeIndex]);
61+
}, [totalEvents, activeIndex, isClosed]);
7062

7163
const handlePrev = useCallback(() => {
7264
if (totalEvents <= 1) {
@@ -86,90 +78,104 @@ export function ActivityTicker({ className }: ActivityTickerProps) {
8678
return null;
8779
}
8880

81+
if (isClosed) {
82+
return null;
83+
}
84+
8985
const activeEvent = events[activeIndex];
9086
const coverSrc = activeEvent.coverUrl;
9187
const showPlayback = activeEvent.deprecated && Boolean(activeEvent.playback);
9288

9389
return (
94-
<aside
95-
className={cn(
96-
"relative w-full overflow-hidden rounded-2xl border border-border bg-background/70 text-left shadow-md backdrop-blur supports-[backdrop-filter]:bg-background/50",
97-
className,
98-
)}
99-
>
100-
<div className="group relative aspect-[5/4] w-full overflow-hidden">
101-
<Image
102-
src={coverSrc}
103-
alt={activeEvent.name}
104-
fill
105-
sizes="(min-width: 1024px) 320px, (min-width: 640px) 288px, 90vw"
106-
priority
107-
className="object-contain object-top"
108-
/>
109-
{/* 下半透明渐变,用于保证文字与按钮对比度 */}
110-
<div className="absolute inset-x-0 bottom-0 h-1/2 bg-gradient-to-t from-black/70 via-black/30 to-transparent" />
111-
{events.length > 1 && (
112-
<>
113-
{/* 多条活动时显示手动切换指示器 */}
114-
<div className="absolute inset-x-0 top-0 flex justify-end gap-1 p-3">
115-
{events.map((event, idx) => (
116-
<button
117-
key={`${event.name}-${idx}`}
118-
type="button"
119-
onClick={() => setActiveIndex(idx)}
120-
aria-label={`切换到 ${event.name}`}
121-
className={cn(
122-
"h-1.5 w-6 rounded-full transition-opacity",
123-
idx === activeIndex
124-
? "bg-white/90 opacity-100"
125-
: "bg-white/40 opacity-60 hover:opacity-85",
126-
)}
127-
/>
128-
))}
129-
</div>
130-
<button
131-
type="button"
132-
aria-label="上一条活动"
133-
onClick={handlePrev}
134-
className="absolute left-3 top-1/2 z-30 flex h-9 w-9 -translate-y-1/2 items-center justify-center rounded-full bg-black/35 text-white shadow-sm transition hover:bg-black/55 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white/70"
135-
>
136-
<ChevronLeft className="h-4 w-4" />
137-
</button>
138-
<button
139-
type="button"
140-
aria-label="下一条活动"
141-
onClick={handleNext}
142-
className="absolute right-3 top-1/2 z-30 flex h-9 w-9 -translate-y-1/2 items-center justify-center rounded-full bg-black/35 text-white shadow-sm transition hover:bg-black/55 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white/70"
143-
>
144-
<ChevronRight className="h-4 w-4" />
145-
</button>
146-
</>
90+
<div className="group relative">
91+
<button
92+
type="button"
93+
aria-label="关闭活动轮播"
94+
onClick={() => setIsClosed(true)}
95+
className="pointer-events-none absolute -top-3 -right-3 z-40 flex h-7 w-7 items-center justify-center rounded-full border border-border bg-background text-foreground opacity-0 shadow transition group-hover:pointer-events-auto group-hover:opacity-100 focus-visible:pointer-events-auto focus-visible:opacity-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
96+
>
97+
<X className="h-4 w-4" />
98+
</button>
99+
<aside
100+
className={cn(
101+
"relative w-full overflow-hidden rounded-2xl border border-border bg-background/70 text-left shadow-md backdrop-blur supports-[backdrop-filter]:bg-background/50",
102+
className,
147103
)}
148-
{/* 底部毛玻璃按钮,根据 deprecated 控制回放按钮可见性 */}
149-
<div
150-
className={cn(
151-
"absolute inset-x-0 bottom-0 top-3/4 z-10 grid border-t border-white/15 bg-white/20 text-sm font-medium text-white shadow-lg backdrop-blur-md",
152-
showPlayback ? "grid-cols-2" : "grid-cols-1",
104+
>
105+
<div className="relative aspect-[5/4] w-full overflow-hidden">
106+
<Image
107+
src={coverSrc}
108+
alt={activeEvent.name}
109+
fill
110+
sizes="(min-width: 1024px) 320px, (min-width: 640px) 288px, 90vw"
111+
priority
112+
className="object-contain object-top"
113+
/>
114+
{/* 下半透明渐变,用于保证文字与按钮对比度 */}
115+
<div className="absolute inset-x-0 bottom-0 h-1/2 bg-gradient-to-t from-black/70 via-black/30 to-transparent" />
116+
{events.length > 1 && (
117+
<>
118+
{/* 多条活动时显示手动切换指示器 */}
119+
<div className="absolute inset-x-0 top-0 flex justify-end gap-1 p-3">
120+
{events.map((event, idx) => (
121+
<button
122+
key={`${event.name}-${idx}`}
123+
type="button"
124+
onClick={() => setActiveIndex(idx)}
125+
aria-label={`切换到 ${event.name}`}
126+
className={cn(
127+
"h-1.5 w-6 rounded-full transition-opacity",
128+
idx === activeIndex
129+
? "bg-white/90 opacity-100"
130+
: "bg-white/40 opacity-60 hover:opacity-85",
131+
)}
132+
/>
133+
))}
134+
</div>
135+
<button
136+
type="button"
137+
aria-label="上一条活动"
138+
onClick={handlePrev}
139+
className="absolute left-3 top-1/2 z-30 flex h-9 w-9 -translate-y-1/2 items-center justify-center rounded-full bg-black/35 text-white shadow-sm transition hover:bg-black/55 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white/70"
140+
>
141+
<ChevronLeft className="h-4 w-4" />
142+
</button>
143+
<button
144+
type="button"
145+
aria-label="下一条活动"
146+
onClick={handleNext}
147+
className="absolute right-3 top-1/2 z-30 flex h-9 w-9 -translate-y-1/2 items-center justify-center rounded-full bg-black/35 text-white shadow-sm transition hover:bg-black/55 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white/70"
148+
>
149+
<ChevronRight className="h-4 w-4" />
150+
</button>
151+
</>
153152
)}
154-
>
155-
<Link
156-
href={activeEvent.discord}
157-
prefetch={false}
158-
className="flex h-full items-center justify-center px-3 text-white transition-colors hover:bg-white/25 hover:text-white"
153+
{/* 底部毛玻璃按钮,根据 deprecated 控制回放按钮可见性 */}
154+
<div
155+
className={cn(
156+
"absolute inset-x-0 bottom-0 top-3/4 z-10 grid border-t border-white/15 bg-white/20 text-sm font-medium text-white shadow-lg backdrop-blur-md",
157+
showPlayback ? "grid-cols-2" : "grid-cols-1",
158+
)}
159159
>
160-
Discord
161-
</Link>
162-
{showPlayback && (
163160
<Link
164-
href={activeEvent.playback as string}
161+
href={activeEvent.discord}
165162
prefetch={false}
166-
className="flex h-full items-center justify-center border-l border-white/15 px-3 text-white transition-colors hover:bg-white/25 hover:text-white"
163+
className="flex h-full items-center justify-center px-3 text-white transition-colors hover:bg-white/25 hover:text-white"
167164
>
168-
Playback
165+
Discord
169166
</Link>
170-
)}
167+
{showPlayback && (
168+
<Link
169+
href={activeEvent.playback as string}
170+
prefetch={false}
171+
className="flex h-full items-center justify-center border-l border-white/15 px-3 text-white transition-colors hover:bg-white/25 hover:text-white"
172+
>
173+
Playback
174+
</Link>
175+
)}
176+
</div>
171177
</div>
172-
</div>
173-
</aside>
178+
</aside>
179+
</div>
174180
);
175181
}

0 commit comments

Comments
 (0)