diff --git a/apps/client/src/scenes/lobby/LobbyScene.tsx b/apps/client/src/scenes/lobby/LobbyScene.tsx index 237bf95..f8dea50 100644 --- a/apps/client/src/scenes/lobby/LobbyScene.tsx +++ b/apps/client/src/scenes/lobby/LobbyScene.tsx @@ -4,6 +4,7 @@ import { config } from "@client/config"; import { OVERLAY_BUTTON_STYLE } from "@client/scenes/shared/styles/overlayStyles"; import { LobbyRuleModal } from "./components/LobbyRuleModal"; +import { LobbyStartConfirmModal } from "./components/LobbyStartConfirmModal"; import { LOBBY_BACK_BUTTON_STYLE, LOBBY_BACKGROUND_STYLE, @@ -72,6 +73,7 @@ const [selectedFieldSizePreset, setSelectedFieldSizePreset] = useState(config.GAME_CONFIG.DEFAULT_FIELD_PRESET); const [isRuleModalOpen, setIsRuleModalOpen] = useState(false); + const [isStartConfirmVisible, setIsStartConfirmVisible] = useState(false); useEffect(() => { setSelectedStartPlayerCount((prev) => { @@ -87,13 +89,22 @@ }); }, [minimumStartPlayerCount, maxStartPlayerCount]); - const handleStart = () => { + const handleStartClick = () => { + setIsStartConfirmVisible(true); + }; + + const handleStartConfirm = () => { + setIsStartConfirmVisible(false); onStart({ targetPlayerCount: selectedStartPlayerCount, fieldSizePreset: selectedFieldSizePreset, }); }; + const handleStartCancel = () => { + setIsStartConfirmVisible(false); + }; + const toFieldPresetLabel = (preset: FieldSizePreset): string => { const range = config.GAME_CONFIG.FIELD_PRESETS[preset].recommendedPlayers; const baseLabel = @@ -191,7 +202,7 @@ ))} - @@ -249,6 +260,13 @@ onClose={() => { setIsRuleModalOpen(false); }} /> )} + + {isStartConfirmVisible && ( + + )} ); }; diff --git a/apps/client/src/scenes/lobby/components/LobbyStartConfirmModal.styles.ts b/apps/client/src/scenes/lobby/components/LobbyStartConfirmModal.styles.ts new file mode 100644 index 0000000..53a567b --- /dev/null +++ b/apps/client/src/scenes/lobby/components/LobbyStartConfirmModal.styles.ts @@ -0,0 +1,65 @@ +/** + * LobbyStartConfirmModal.styles + * ゲームスタート確認モーダルのスタイル定数を定義する + */ +import type { CSSProperties } from "react"; +import { + OVERLAY_PANEL_BASE_STYLE, + OVERLAY_PANEL_FOOTER_BASE_STYLE, + OVERLAY_PANEL_HEADER_BASE_STYLE, +} from "@client/scenes/shared/styles/overlayStyles"; + +/** オーバーレイ背景のスタイル */ +export const LOBBY_START_CONFIRM_OVERLAY_STYLE: CSSProperties = { + position: "fixed", + inset: 0, + background: "rgba(0, 0, 0, 0.72)", + zIndex: 120, + display: "flex", + alignItems: "center", + justifyContent: "center", + padding: "16px", +}; + +/** 確認パネルのスタイル */ +export const LOBBY_START_CONFIRM_PANEL_STYLE: CSSProperties = { + ...OVERLAY_PANEL_BASE_STYLE, + width: "min(360px, 100%)", + display: "flex", + flexDirection: "column", +}; + +/** 確認パネルヘッダーのスタイル */ +export const LOBBY_START_CONFIRM_HEADER_STYLE: CSSProperties = { + ...OVERLAY_PANEL_HEADER_BASE_STYLE, + fontSize: "1.1rem", + fontWeight: 800, +}; + +/** 確認パネル本文のスタイル */ +export const LOBBY_START_CONFIRM_BODY_STYLE: CSSProperties = { + padding: "20px 18px", + fontSize: "1rem", + lineHeight: 1.6, + color: "rgba(255, 255, 255, 0.85)", +}; + +/** 確認パネルフッターのスタイル */ +export const LOBBY_START_CONFIRM_FOOTER_STYLE: CSSProperties = { + ...OVERLAY_PANEL_FOOTER_BASE_STYLE, + display: "flex", + gap: "10px", + justifyContent: "flex-end", +}; + +/** 「はい」ボタンのスタイル */ +export const LOBBY_START_CONFIRM_YES_BUTTON_STYLE: CSSProperties = { + padding: "10px 24px", + fontSize: "0.95rem", + cursor: "pointer", + borderRadius: "8px", + border: "none", + background: "#4ade80", + color: "#111", + fontWeight: 700, +}; diff --git a/apps/client/src/scenes/lobby/components/LobbyStartConfirmModal.tsx b/apps/client/src/scenes/lobby/components/LobbyStartConfirmModal.tsx new file mode 100644 index 0000000..131e4a9 --- /dev/null +++ b/apps/client/src/scenes/lobby/components/LobbyStartConfirmModal.tsx @@ -0,0 +1,45 @@ +/** + * LobbyStartConfirmModal + * ゲームスタート前の確認ダイアログ + */ +import { OVERLAY_BUTTON_STYLE } from "@client/scenes/shared/styles/overlayStyles"; +import { + LOBBY_START_CONFIRM_BODY_STYLE, + LOBBY_START_CONFIRM_FOOTER_STYLE, + LOBBY_START_CONFIRM_HEADER_STYLE, + LOBBY_START_CONFIRM_OVERLAY_STYLE, + LOBBY_START_CONFIRM_PANEL_STYLE, + LOBBY_START_CONFIRM_YES_BUTTON_STYLE, +} from "./LobbyStartConfirmModal.styles"; + +type LobbyStartConfirmModalProps = { + onConfirm: () => void; + onCancel: () => void; +}; + +/** ゲームスタートの最終確認を表示するモーダル */ +export const LobbyStartConfirmModal = ({ + onConfirm, + onCancel, +}: LobbyStartConfirmModalProps) => { + return ( +
+
+
ゲームスタート
+ +
+ ゲームを開始しますか? +
+ +
+ + +
+
+
+ ); +}; diff --git a/apps/client/src/scenes/lobby/styles/LobbyScene.styles.ts b/apps/client/src/scenes/lobby/styles/LobbyScene.styles.ts index b93d465..768171e 100644 --- a/apps/client/src/scenes/lobby/styles/LobbyScene.styles.ts +++ b/apps/client/src/scenes/lobby/styles/LobbyScene.styles.ts @@ -112,8 +112,10 @@ borderRadius: "8px", fontWeight: "bold", boxShadow: "0 4px 6px rgba(0,0,0,0.3)", + marginTop: "clamp(8px, 2dvh, 16px)", }; + /** 非オーナー待機表示のスタイル */ export const LOBBY_WAITING_STYLE: CSSProperties = { padding: "20px",