feat(遊戲化): 新增大廳、附身、時間流、後日談進度等遊戲化系統功能
新增角色大廳(lobby)邀約與通話、附身(possession)、時鐘(clock)抽象、 時間流與睡眠負債、後日談進度、行為選擇與旁觀反應等模組,並補齊對應冒煙 測試(R~V)與單元測試;同步調整 web/mobile 對應頁面與元件。 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
import { useEffect, useRef } from "react";
|
||||
import { Animated, Easing, type StyleProp, type ViewStyle } from "react-native";
|
||||
import { useReduceMotion } from "../lib/reduce-motion";
|
||||
|
||||
export interface HeartbeatDotProps {
|
||||
size?: number;
|
||||
color?: string;
|
||||
style?: StyleProp<ViewStyle>;
|
||||
}
|
||||
|
||||
// Q-4:未讀/推播提示紅點=小心跳,對應 apps/web 的 `.heartbeat-dot`(1.2s 循環的 opacity+scale 脈動)。
|
||||
export function HeartbeatDot({ size = 10, color = "#FF7E9D", style }: HeartbeatDotProps) {
|
||||
const reduceMotion = useReduceMotion();
|
||||
const t = useRef(new Animated.Value(0)).current;
|
||||
|
||||
useEffect(() => {
|
||||
if (reduceMotion) {
|
||||
t.setValue(0);
|
||||
return;
|
||||
}
|
||||
const loop = Animated.loop(
|
||||
Animated.sequence([
|
||||
Animated.timing(t, { toValue: 1, duration: 600, easing: Easing.inOut(Easing.ease), useNativeDriver: true }),
|
||||
Animated.timing(t, { toValue: 0, duration: 600, easing: Easing.inOut(Easing.ease), useNativeDriver: true }),
|
||||
]),
|
||||
);
|
||||
loop.start();
|
||||
return () => loop.stop();
|
||||
}, [reduceMotion, t]);
|
||||
|
||||
const scale = t.interpolate({ inputRange: [0, 1], outputRange: [1, 1.3] });
|
||||
const opacity = t.interpolate({ inputRange: [0, 1], outputRange: [1, 0.7] });
|
||||
|
||||
return (
|
||||
<Animated.View
|
||||
style={[
|
||||
{ width: size, height: size, borderRadius: size / 2, backgroundColor: color, opacity, transform: [{ scale }] },
|
||||
style,
|
||||
]}
|
||||
/>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user