Newer
Older
PixelPaintWar / apps / client / src / scenes / title / TitleScene.tsx
import { useState } from "react";
// ルーム参加時送信ペイロード型
import type { roomTypes } from "@repo/shared";

type Props = {
  // 入室実行時呼び出しコールバック
  onJoin: (payload: roomTypes.JoinRoomPayload) => void;
  // 入室失敗時の表示メッセージ
  joinErrorMessage: string | null;
  // 入室リクエスト送信中フラグ
  isJoining: boolean;
};

export const TitleScene = ({ onJoin, joinErrorMessage, isJoining }: Props) => {
  // プレイヤー名入力値
  const [playerName, setPlayerName] = useState("");
  // ルームID入力値
  const [roomIdInput, setRoomIdInput] = useState("");

  // 入室ボタン活性条件
  const canJoin = playerName !== "" && roomIdInput !== "";

  // 入室実行ハンドラ
  const handleJoin = () => {
    if (canJoin) {
      onJoin({ roomId: roomIdInput, playerName });
    }
  };

  return (
    <>
      {/* 🌟 ロビー画面と同じ、横画面専用の警告と全体設定 */}
      <style>{`
        * {
          box-sizing: border-box;
        }
        .portrait-blocker {
          display: none;
          position: fixed;
          top: 0; left: 0; width: 100vw; height: 100dvh;
          background: #111;
          color: white;
          z-index: 9999;
          justify-content: center;
          align-items: center;
          flex-direction: column;
          text-align: center;
          padding: 20px;
        }
        @media screen and (orientation: portrait) {
          .portrait-blocker {
            display: flex;
          }
        }
      `}</style>

      {/* 縦画面時のブロック画面 */}
      <div className="portrait-blocker">
        <h2>画面を横向きにしてください</h2>
        <p>Please rotate your device to landscape mode.</p>
      </div>

      {/* 🌟 画面全体を覆う背景コンテナ */}
      <div
        style={{
          width: "100vw",
          height: "100dvh",
          // 💡 ここを修正: public/title.png を読み込むように変更
          backgroundImage: "url('/title.png')",
          backgroundSize: "cover",
          backgroundPosition: "center",
          // ドット絵をぼやけさせずにくっきり拡大するプロパティ
          imageRendering: "pixelated",

          // UIを下の方に配置するためのFlexbox設定
          display: "flex",
          flexDirection: "column",
          justifyContent: "flex-end", // 下に寄せる
          alignItems: "center",
          paddingBottom: "12vh", // 画像の空きスペースに合わせて調整
        }}
      >
        {/* 🌟 入力フォーム&ボタンのコンテナ */}
        <div
          style={{
            display: "flex",
            flexDirection: "column",
            alignItems: "center",
            width: "90%",
            maxWidth: "400px",
            // 画像と同化しないように、うっすらと黒い半透明の座布団を敷く(不要なら消してOK)
            backgroundColor: "rgba(0, 0, 0, 0.4)",
            padding: "20px",
            borderRadius: "12px",
            boxShadow: "0 4px 10px rgba(0, 0, 0, 0.5)",
          }}
        >
          <div
            style={{
              display: "flex",
              flexDirection: "column",
              gap: "10px",
              width: "100%",
              marginBottom: "20px",
            }}
          >
            <input
              placeholder="プレイヤー名を入力"
              value={playerName}
              onChange={(e) => setPlayerName(e.target.value)}
              style={{
                padding: "12px",
                fontSize: "clamp(1rem, 3vw, 1.2rem)",
                borderRadius: "5px",
                border: "none",
                width: "100%",
                fontFamily: "monospace",
              }}
            />
            <input
              placeholder="ルームIDを入力"
              value={roomIdInput}
              onChange={(e) => setRoomIdInput(e.target.value)}
              style={{
                padding: "12px",
                fontSize: "clamp(1rem, 3vw, 1.2rem)",
                borderRadius: "5px",
                border: "none",
                width: "100%",
                fontFamily: "monospace",
              }}
            />
          </div>

          {/* エラーメッセージ */}
          {joinErrorMessage && (
            <div
              style={{
                color: "#ff6b6b",
                marginBottom: "15px",
                fontWeight: "bold",
                textAlign: "center",
                textShadow: "1px 1px 2px black",
              }}
            >
              {joinErrorMessage}
            </div>
          )}

          {/* 参加ボタン */}
          <button
            onClick={handleJoin}
            disabled={!canJoin || isJoining}
            style={{
              padding: "15px 30px",
              fontSize: "clamp(1rem, 3vw, 1.2rem)",
              cursor: !canJoin || isJoining ? "not-allowed" : "pointer",
              backgroundColor: !canJoin || isJoining ? "#555" : "#3b82f6",
              color: "white",
              border: "none",
              borderRadius: "5px",
              width: "100%",
              fontWeight: "bold",
              fontFamily: "monospace",
              transition: "background-color 0.2s",
            }}
          >
            {isJoining ? "接続中..." : "GAME START"}
          </button>
        </div>
      </div>
    </>
  );
};