タイムテーブル・ステージ進行
ステージ企画や各会場プログラムのタイムテーブルおよび進行状況の可視化。現在時刻に連動した進行中プログラムの自動ハイライトと進捗バー表示に対応。
使い方
参加者向け
import EventStatus from "@/features/event/components/EventStatus";
<EventStatus />Hooks src/features/event/hooks/useEventData.ts
静的 JSON ファイル public/data/events.json からスケジュールデータを非同期ロードし、現在時刻やフィルターに応じたイベント一覧を提供します。
| プロパティ / 関数 | 型 | 役割 |
|---|---|---|
filteredEvents | Event[] | 開催日程およびフィルター (1時間以内 / すべて) に適合したイベント配列 |
filterMode | "hour" | "all" | 現在のフィルターモード (直近1時間以内 / 全表示) |
setFilterMode(mode) | (mode : "hour" | "all") => void | フィルターモードの切り替え |
currentTime | Dayjs | TimeContext から取得したアプリ共通の現在時刻 |
getEventTime(timeStr) | (timeStr : string) => Dayjs | 当日の日付と時刻文字列を結合した Dayjs インスタンスを生成 |
newIndexMap | Map<string, number> | 「すべて」展開時に新規表示されるカードのアニメーション遅延 (Stagger) 計算用インデックスマップ |
コード
プログレスバーの進捗率計算
現在時刻 currentTime と企画の開始・終了時刻からミリ秒単位で進捗パーセンテージ (0〜100%) を動的算出します。
const calculateProgress = (startStr: string, endStr: string, current: Dayjs) => {
const start = dayjs(`${current.format("YYYY-MM-DD")} ${startStr}`);
const end = dayjs(`${current.format("YYYY-MM-DD")} ${endStr}`);
if (current.isBefore(start)) return 0;
if (current.isAfter(end)) return 100;
const totalDuration = end.diff(start);
const elapsed = current.diff(start);
return Math.min(100, Math.max(0, (elapsed / totalDuration) * 100));
};newIndexMap によるアニメーション遅延制御
フィルターを「1時間以内」から「すべて」に切り替えた際、すでに画面上にあった項目は維持し、新しく追加展開されるカードにのみインデックスを割り振って時間差 (Stagger) フェードインさせます。
// useEventData 内で新規要素のみをカウント
const newIndex = newIndexMap.get(event.name);
const isNewItem = newIndex !== undefined;
const enterDelay = isNewItem ? 0.1 + newIndex * 0.06 : 0;
// Framer Motion で新規要素のみ遅延アニメーション
<motion.div
layout
initial={isNewItem ? { opacity: 0, y: 30, scale: 0.8 } : false}
animate={{ opacity: isFinished ? 0.4 : 1, y: 0, scale: 1 }}
transition={{ delay: enterDelay }}
/>データ構造 public/data/events.json
開催日程別 (day1, day2, ...) に企画名と開始・終了時刻を定義します。
{
"day1": [
{ "name": "オープニング", "start": "10:00", "end": "10:20" },
{ "name": "ライブステージ", "start": "10:40", "end": "12:00" }
],
"day2": [
{ "name": "ダンスパフォーマンス", "start": "11:00", "end": "12:30" }
]
}