From b406acc8135924dd7e08937ef07571349ba210dc Mon Sep 17 00:00:00 2001 From: kurihada Date: Tue, 24 Feb 2026 19:23:06 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=98=BE=E7=A4=BA=E6=AF=8F=E4=B8=AA?= =?UTF-8?q?=E4=BA=BA=E7=9A=84=E5=AE=9E=E6=97=B6=E6=BB=91=E5=8D=A1=E8=BF=9B?= =?UTF-8?q?=E5=BA=A6=EF=BC=8C=E7=94=A8=20emoji=20=E5=A4=B4=E5=83=8F?= =?UTF-8?q?=E5=8C=BA=E5=88=86=E7=94=A8=E6=88=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 滑卡时进度条下方展示所有人的进度(如 🐸你 12/15 🐱 8/15), 等待页面也改为详细进度卡片,减少等待焦虑并增强社交临场感。 每个用户根据 userId 确定性分配 emoji 头像,无需手动输入。 --- src/app/room/[id]/page.tsx | 1 + src/components/SwipeDeck.tsx | 190 ++++++++++++++++++++++++++++++----- 2 files changed, 167 insertions(+), 24 deletions(-) diff --git a/src/app/room/[id]/page.tsx b/src/app/room/[id]/page.tsx index 1665216..94a067d 100644 --- a/src/app/room/[id]/page.tsx +++ b/src/app/room/[id]/page.tsx @@ -58,6 +58,7 @@ export default function RoomPage() { matchType={matchType} matchLikes={matchLikes} likeCounts={likeCounts} + swipeCounts={swipeCounts} userCount={userCount} onReset={handleReset} /> diff --git a/src/components/SwipeDeck.tsx b/src/components/SwipeDeck.tsx index 3706138..75060bc 100644 --- a/src/components/SwipeDeck.tsx +++ b/src/components/SwipeDeck.tsx @@ -7,7 +7,134 @@ import ActionButtons from "./ActionButtons"; import MatchResult from "./MatchResult"; import SwipeGuide from "./SwipeGuide"; import { Restaurant, SwipeDirection, MatchType } from "@/types"; -import { Heart, Undo2 } from "lucide-react"; +import { Heart, Undo2, Check } from "lucide-react"; + +const AVATARS = [ + { emoji: "🐱", bg: "bg-amber-100" }, + { emoji: "🐶", bg: "bg-orange-100" }, + { emoji: "🦊", bg: "bg-red-100" }, + { emoji: "🐰", bg: "bg-pink-100" }, + { emoji: "🐼", bg: "bg-zinc-100" }, + { emoji: "🐨", bg: "bg-sky-100" }, + { emoji: "🦁", bg: "bg-yellow-100" }, + { emoji: "🐸", bg: "bg-lime-100" }, + { emoji: "🐵", bg: "bg-stone-100" }, + { emoji: "🐷", bg: "bg-rose-100" }, + { emoji: "🐙", bg: "bg-purple-100" }, + { emoji: "🦄", bg: "bg-violet-100" }, +] as const; + +function getAvatar(uid: string) { + let hash = 0; + for (let i = 0; i < uid.length; i++) { + hash = (hash * 31 + uid.charCodeAt(i)) | 0; + } + return AVATARS[((hash % AVATARS.length) + AVATARS.length) % AVATARS.length]; +} + +function UserProgressBar({ + userId, + swipeCounts, + localIndex, + total, +}: { + userId: string; + swipeCounts: Record; + localIndex: number; + total: number; +}) { + const others = Object.entries(swipeCounts).filter(([id]) => id !== userId); + if (others.length === 0) return null; + + return ( +
+ + + {getAvatar(userId).emoji} + + 你 {localIndex}/{total} + + {others.map(([id, count]) => { + const finished = count >= total; + const avatar = getAvatar(id); + return ( + + + {avatar.emoji} + + {count}/{total} + {finished && } + + ); + })} +
+ ); +} + +function WaitingProgress({ + userId, + swipeCounts, + total, +}: { + userId: string; + swipeCounts: Record; + total: number; +}) { + const entries = Object.entries(swipeCounts); + if (entries.length <= 1) return null; + + const others = entries.filter(([id]) => id !== userId); + const finishedCount = others.filter(([, c]) => c >= total).length; + + return ( +
+
+ + + {getAvatar(userId).emoji} + + 你 {total}/{total} + + +
+ + {others.map(([id, count]) => { + const finished = count >= total; + const pct = Math.min((count / total) * 100, 100); + const avatar = getAvatar(id); + return ( +
+
+ + + {avatar.emoji} + + {count}/{total} + + {finished && } +
+ {!finished && ( +
+ +
+ )} +
+ ); + })} + +

+ {finishedCount}/{others.length} 人已完成 +

+
+ ); +} interface SwipeDeckProps { restaurants: Restaurant[]; @@ -18,6 +145,7 @@ interface SwipeDeckProps { matchType: MatchType; matchLikes: number; likeCounts: Record; + swipeCounts: Record; userCount: number; onReset: () => Promise; } @@ -31,6 +159,7 @@ export default function SwipeDeck({ matchType, matchLikes, likeCounts, + swipeCounts, userCount, onReset, }: SwipeDeckProps) { @@ -175,28 +304,36 @@ export default function SwipeDeck({ return ( <> {!allSwiped && !resolvedMatchId && ( -
-
- +
+
+
+ +
+ + {currentIndex}/{restaurants.length} + +
- - {currentIndex}/{restaurants.length} - - +
)} @@ -226,9 +363,14 @@ export default function SwipeDeck({ )} {showWaiting && ( -
+
-

等待其他人完成选择...

+

等待其他人完成选择

+
)}