diff --git a/apps/client/src/scenes/lobby/LobbyScene.tsx b/apps/client/src/scenes/lobby/LobbyScene.tsx index 8b22573..ee9bdbc 100644 --- a/apps/client/src/scenes/lobby/LobbyScene.tsx +++ b/apps/client/src/scenes/lobby/LobbyScene.tsx @@ -4,7 +4,9 @@ import { config } from "@client/config"; import { socketManager } from "@client/network/SocketManager"; import { OVERLAY_BUTTON_STYLE } from "@client/scenes/shared/styles/overlayStyles"; +import { GearIcon } from "./components/GearIcon"; import { LobbyRuleModal } from "./components/LobbyRuleModal"; +import { LobbySettingsModal } from "./components/LobbySettingsModal"; import { LobbyStartConfirmModal } from "./components/LobbyStartConfirmModal"; import { LOBBY_BACK_BUTTON_STYLE, @@ -14,13 +16,12 @@ LOBBY_HOST_SETTINGS_LABEL_STYLE, LOBBY_HOST_SETTINGS_STYLE, LOBBY_HOST_SETTINGS_VALUE_STYLE, - LOBBY_LABEL_STYLE, LOBBY_LEFT_INNER_STYLE, LOBBY_LEFT_PANEL_STYLE, LOBBY_PLAYER_LIST_HEADER_STYLE, LOBBY_PLAYER_LIST_ITEM_STYLE, LOBBY_PLAYER_LIST_PANEL_STYLE, - LOBBY_SELECT_STYLE, + LOBBY_SETTINGS_GEAR_BUTTON_STYLE, LOBBY_START_BUTTON_STYLE, LOBBY_TITLE_STYLE, LOBBY_WAITING_STYLE, @@ -78,6 +79,7 @@ useState(config.GAME_CONFIG.DEFAULT_FIELD_PRESET); const [isRuleModalOpen, setIsRuleModalOpen] = useState(false); const [isStartConfirmVisible, setIsStartConfirmVisible] = useState(false); + const [isSettingsModalOpen, setIsSettingsModalOpen] = useState(false); useEffect(() => { setSelectedStartPlayerCount((prev) => { @@ -172,6 +174,16 @@ タイトルへ戻る + {isMeOwner && ( + + )} +

ルーム: {room.roomId} (待機中)

@@ -182,42 +194,6 @@
{isMeOwner ? (
- - - - - - @@ -300,6 +276,19 @@ onCancel={handleStartCancel} /> )} + + {isSettingsModalOpen && ( + { setIsSettingsModalOpen(false); }} + /> + )} ); }; diff --git a/apps/client/src/scenes/lobby/components/GearIcon.tsx b/apps/client/src/scenes/lobby/components/GearIcon.tsx new file mode 100644 index 0000000..b478b34 --- /dev/null +++ b/apps/client/src/scenes/lobby/components/GearIcon.tsx @@ -0,0 +1,20 @@ +/** + * GearIcon + * 歯車SVGアイコンコンポーネント + */ +type Props = { + size?: number; +}; + +/** 歯車SVGアイコン */ +export const GearIcon = ({ size = 22 }: Props) => ( + +); diff --git a/apps/client/src/scenes/lobby/components/LobbySettingsModal.styles.ts b/apps/client/src/scenes/lobby/components/LobbySettingsModal.styles.ts new file mode 100644 index 0000000..519d34e --- /dev/null +++ b/apps/client/src/scenes/lobby/components/LobbySettingsModal.styles.ts @@ -0,0 +1,78 @@ +/** + * LobbySettingsModal.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_SETTINGS_MODAL_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_SETTINGS_MODAL_PANEL_STYLE: CSSProperties = { + ...OVERLAY_PANEL_BASE_STYLE, + width: "min(400px, 100%)", + display: "flex", + flexDirection: "column", +}; + +/** 設定パネルヘッダーのスタイル */ +export const LOBBY_SETTINGS_MODAL_HEADER_STYLE: CSSProperties = { + ...OVERLAY_PANEL_HEADER_BASE_STYLE, + fontSize: "1.1rem", + fontWeight: 800, +}; + +/** 設定パネル本文のスタイル */ +export const LOBBY_SETTINGS_MODAL_BODY_STYLE: CSSProperties = { + padding: "20px 18px", + display: "flex", + flexDirection: "column", + gap: "14px", +}; + +/** 設定パネルフッターのスタイル */ +export const LOBBY_SETTINGS_MODAL_FOOTER_STYLE: CSSProperties = { + ...OVERLAY_PANEL_FOOTER_BASE_STYLE, + display: "flex", + justifyContent: "flex-end", +}; + +/** 設定ラベルのスタイル */ +export const LOBBY_SETTINGS_MODAL_LABEL_STYLE: CSSProperties = { + fontSize: "0.95rem", + fontWeight: 700, + color: "rgba(255, 255, 255, 0.85)", +}; + +/** 設定セレクトボックスのスタイル */ +export const LOBBY_SETTINGS_MODAL_SELECT_STYLE: CSSProperties = { + width: "100%", + padding: "10px 12px", + borderRadius: "8px", + border: "1px solid rgba(255,255,255,0.4)", + background: "rgba(0,0,0,0.55)", + color: "white", + fontSize: "1rem", + fontWeight: 700, +}; + +/** 設定フィールド(ラベル+セレクト)のラッパースタイル */ +export const LOBBY_SETTINGS_MODAL_FIELD_STYLE: CSSProperties = { + display: "flex", + flexDirection: "column", + gap: "6px", +}; diff --git a/apps/client/src/scenes/lobby/components/LobbySettingsModal.tsx b/apps/client/src/scenes/lobby/components/LobbySettingsModal.tsx new file mode 100644 index 0000000..829ce14 --- /dev/null +++ b/apps/client/src/scenes/lobby/components/LobbySettingsModal.tsx @@ -0,0 +1,101 @@ +/** + * LobbySettingsModal + * ホスト用のゲーム設定(人数・フィールドサイズ)を変更するモーダル + */ +import type { FieldSizePreset } from "@repo/shared"; +import { OVERLAY_BUTTON_STYLE } from "@client/scenes/shared/styles/overlayStyles"; +import { + LOBBY_SETTINGS_MODAL_BODY_STYLE, + LOBBY_SETTINGS_MODAL_FIELD_STYLE, + LOBBY_SETTINGS_MODAL_FOOTER_STYLE, + LOBBY_SETTINGS_MODAL_HEADER_STYLE, + LOBBY_SETTINGS_MODAL_LABEL_STYLE, + LOBBY_SETTINGS_MODAL_OVERLAY_STYLE, + LOBBY_SETTINGS_MODAL_PANEL_STYLE, + LOBBY_SETTINGS_MODAL_SELECT_STYLE, +} from "./LobbySettingsModal.styles"; + +type LobbySettingsModalProps = { + startPlayerCountOptions: number[]; + selectedStartPlayerCount: number; + onChangeStartPlayerCount: (count: number) => void; + fieldPresetOptions: FieldSizePreset[]; + selectedFieldSizePreset: FieldSizePreset; + onChangeFieldSizePreset: (preset: FieldSizePreset) => void; + toFieldPresetLabel: (preset: FieldSizePreset) => string; + onClose: () => void; +}; + +/** ホスト用ゲーム設定ポップアップ */ +export const LobbySettingsModal = ({ + startPlayerCountOptions, + selectedStartPlayerCount, + onChangeStartPlayerCount, + fieldPresetOptions, + selectedFieldSizePreset, + onChangeFieldSizePreset, + toFieldPresetLabel, + onClose, +}: LobbySettingsModalProps) => { + return ( +
+
+
ゲーム設定
+ +
+
+ + +
+ +
+ + +
+
+ +
+ +
+
+
+ ); +}; diff --git a/apps/client/src/scenes/lobby/styles/LobbyScene.styles.ts b/apps/client/src/scenes/lobby/styles/LobbyScene.styles.ts index 6ca66a1..6948237 100644 --- a/apps/client/src/scenes/lobby/styles/LobbyScene.styles.ts +++ b/apps/client/src/scenes/lobby/styles/LobbyScene.styles.ts @@ -3,7 +3,7 @@ * LobbyScene の描画スタイル定数を集約する */ import type { CSSProperties } from "react"; -import { safeLeft, safeTop } from "@client/styles/safeArea"; +import { safeLeft, safeRight, safeTop } from "@client/styles/safeArea"; /** 背景アニメーション画像レイヤーのスタイル */ export const LOBBY_BACKGROUND_STYLE: CSSProperties = { @@ -46,6 +46,27 @@ left: safeLeft(20), }; +/** 歯車(設定)ボタンのスタイル */ +export const LOBBY_SETTINGS_GEAR_BUTTON_STYLE: CSSProperties = { + position: "absolute", + top: safeTop(16), + right: safeRight(16), + width: "42px", + height: "42px", + padding: 0, + display: "flex", + alignItems: "center", + justifyContent: "center", + borderRadius: "50%", + border: "1px solid rgba(255,255,255,0.35)", + background: "rgba(0,0,0,0.55)", + color: "white", + cursor: "pointer", + backdropFilter: "blur(6px)", + boxShadow: "0 2px 8px rgba(0,0,0,0.4)", + transition: "background 0.2s, transform 0.2s", +}; + /** ルームタイトルのスタイル */ export const LOBBY_TITLE_STYLE: CSSProperties = { fontSize: "clamp(1.5rem, 4vw, 2rem)",