diff --git a/.env.example b/.env.example index 2ff8fd0..7c3ad28 100644 --- a/.env.example +++ b/.env.example @@ -1,5 +1,7 @@ # .env にコピーして値を設定する(chmod 600 推奨) ACCESS_KEY=000000 +# 管理者キー(任意・ACCESS_KEY と別の6桁)。入力すると管理者として入室し、ハンドレンジ学習ページが見える +# ADMIN_KEY=000001 PORT=4671 # HOST=127.0.0.1 # 本番のみ設定(ローカル開発では設定しない) diff --git a/README.md b/README.md index 181bf97..5a8b711 100644 --- a/README.md +++ b/README.md @@ -37,11 +37,20 @@ http://localhost:4671 を開く。 | 変数 | 既定値 | 内容 | | --- | --- | --- | | `ACCESS_KEY` | なし(必須) | 6桁の参加キー | +| `ADMIN_KEY` | なし(任意) | 6桁の管理者キー(`ACCESS_KEY` と別の値)。入力すると管理者として入室する | | `PORT` | `4671` | 待ち受けポート | | `HOST` | `127.0.0.1` | 待ち受けアドレス。既定では外部から直接つながらない(nginx 経由で公開する) | | `PUBLIC_ORIGIN` | なし | 本番の公開URL `https://poker.kanawo.net`。設定するとこのドメイン以外(IP直打ちや別ドメイン)へのアクセスと、他オリジンからの操作を拒否する。ローカル開発では設定しない | | `SESSION_SECRET` | 自動生成 | Cookie 署名用。未指定なら `data/session-secret` に生成・保存 | +## 管理者(ハンドレンジ学習) + +`ADMIN_KEY` を入力して入室すると管理者になり、ロビーに「♠ ハンドレンジ学習」が表示される(`/range`:レンジ表と色・分類クイズ)。管理者は通常のプレイもそのままできる。 + +- 初めて開くときは鍵入力画面で `ADMIN_KEY` を入れる。すでに参加キーで入室済みのブラウザは `https://poker.kanawo.net/key?admin` を開いて管理者キーを入れる。 +- 管理者以外には `/range` とその画像・スクリプトは 404 を返す(ページがあること自体を見せない)。ファイルは `public/` の外の `admin/` に置いている。 +- 管理者キーを変えると、管理者の Cookie だけが無効になる。 + ## セキュリティ - **参加キー**: 正しいキーを入れたブラウザに HttpOnly / SameSite=Lax(HTTPS 時は Secure)の Cookie を保存。アクセスのたびに有効期限(400日)が延長されるので、以降は入力不要。 @@ -67,6 +76,7 @@ http://localhost:4671 を開く。 | `server/config.js` | `.env` の読み込みと各種上限値 | | `public/assets/blinds.js` | ブラインド計算(サーバ・ブラウザ共用) | | `public/*.html`, `public/assets/*.js` | 各画面 | +| `admin/` | 管理者専用ページ(ハンドレンジ学習・カード画像) | - テーブルはメモリ上にのみ保持(サーバ再起動で消える)。誰も接続していない状態が30分続くと自動削除。 - 名前とプレイヤーID はブラウザの localStorage に保存。リロードしても同じ席に戻れる。 diff --git a/admin/cards/10_of_clubs.png b/admin/cards/10_of_clubs.png new file mode 100644 index 0000000..18af741 Binary files /dev/null and b/admin/cards/10_of_clubs.png differ diff --git a/admin/cards/10_of_diamonds.png b/admin/cards/10_of_diamonds.png new file mode 100644 index 0000000..3bbc4e0 Binary files /dev/null and b/admin/cards/10_of_diamonds.png differ diff --git a/admin/cards/10_of_hearts.png b/admin/cards/10_of_hearts.png new file mode 100644 index 0000000..3eb83d7 Binary files /dev/null and b/admin/cards/10_of_hearts.png differ diff --git a/admin/cards/10_of_spades.png b/admin/cards/10_of_spades.png new file mode 100644 index 0000000..0b3d294 Binary files /dev/null and b/admin/cards/10_of_spades.png differ diff --git a/admin/cards/2_of_clubs.png b/admin/cards/2_of_clubs.png new file mode 100644 index 0000000..291ed97 Binary files /dev/null and b/admin/cards/2_of_clubs.png differ diff --git a/admin/cards/2_of_diamonds.png b/admin/cards/2_of_diamonds.png new file mode 100644 index 0000000..4deee7c Binary files /dev/null and b/admin/cards/2_of_diamonds.png differ diff --git a/admin/cards/2_of_hearts.png b/admin/cards/2_of_hearts.png new file mode 100644 index 0000000..75a014f Binary files /dev/null and b/admin/cards/2_of_hearts.png differ diff --git a/admin/cards/2_of_spades.png b/admin/cards/2_of_spades.png new file mode 100644 index 0000000..1ce0ffe Binary files /dev/null and b/admin/cards/2_of_spades.png differ diff --git a/admin/cards/3_of_clubs.png b/admin/cards/3_of_clubs.png new file mode 100644 index 0000000..076ab31 Binary files /dev/null and b/admin/cards/3_of_clubs.png differ diff --git a/admin/cards/3_of_diamonds.png b/admin/cards/3_of_diamonds.png new file mode 100644 index 0000000..8ee0b4b Binary files /dev/null and b/admin/cards/3_of_diamonds.png differ diff --git a/admin/cards/3_of_hearts.png b/admin/cards/3_of_hearts.png new file mode 100644 index 0000000..8e74673 Binary files /dev/null and b/admin/cards/3_of_hearts.png differ diff --git a/admin/cards/3_of_spades.png b/admin/cards/3_of_spades.png new file mode 100644 index 0000000..f9e06b4 Binary files /dev/null and b/admin/cards/3_of_spades.png differ diff --git a/admin/cards/4_of_clubs.png b/admin/cards/4_of_clubs.png new file mode 100644 index 0000000..8be9e08 Binary files /dev/null and b/admin/cards/4_of_clubs.png differ diff --git a/admin/cards/4_of_diamonds.png b/admin/cards/4_of_diamonds.png new file mode 100644 index 0000000..70e82e8 Binary files /dev/null and b/admin/cards/4_of_diamonds.png differ diff --git a/admin/cards/4_of_hearts.png b/admin/cards/4_of_hearts.png new file mode 100644 index 0000000..ceecbfe Binary files /dev/null and b/admin/cards/4_of_hearts.png differ diff --git a/admin/cards/4_of_spades.png b/admin/cards/4_of_spades.png new file mode 100644 index 0000000..95abe3e Binary files /dev/null and b/admin/cards/4_of_spades.png differ diff --git a/admin/cards/5_of_clubs.png b/admin/cards/5_of_clubs.png new file mode 100644 index 0000000..bde9777 Binary files /dev/null and b/admin/cards/5_of_clubs.png differ diff --git a/admin/cards/5_of_diamonds.png b/admin/cards/5_of_diamonds.png new file mode 100644 index 0000000..bb92525 Binary files /dev/null and b/admin/cards/5_of_diamonds.png differ diff --git a/admin/cards/5_of_hearts.png b/admin/cards/5_of_hearts.png new file mode 100644 index 0000000..d923456 Binary files /dev/null and b/admin/cards/5_of_hearts.png differ diff --git a/admin/cards/5_of_spades.png b/admin/cards/5_of_spades.png new file mode 100644 index 0000000..53a1aad Binary files /dev/null and b/admin/cards/5_of_spades.png differ diff --git a/admin/cards/6_of_clubs.png b/admin/cards/6_of_clubs.png new file mode 100644 index 0000000..a9660a0 Binary files /dev/null and b/admin/cards/6_of_clubs.png differ diff --git a/admin/cards/6_of_diamonds.png b/admin/cards/6_of_diamonds.png new file mode 100644 index 0000000..78a80ad Binary files /dev/null and b/admin/cards/6_of_diamonds.png differ diff --git a/admin/cards/6_of_hearts.png b/admin/cards/6_of_hearts.png new file mode 100644 index 0000000..361643e Binary files /dev/null and b/admin/cards/6_of_hearts.png differ diff --git a/admin/cards/6_of_spades.png b/admin/cards/6_of_spades.png new file mode 100644 index 0000000..40242a7 Binary files /dev/null and b/admin/cards/6_of_spades.png differ diff --git a/admin/cards/7_of_clubs.png b/admin/cards/7_of_clubs.png new file mode 100644 index 0000000..9d6b545 Binary files /dev/null and b/admin/cards/7_of_clubs.png differ diff --git a/admin/cards/7_of_diamonds.png b/admin/cards/7_of_diamonds.png new file mode 100644 index 0000000..6ad5f15 Binary files /dev/null and b/admin/cards/7_of_diamonds.png differ diff --git a/admin/cards/7_of_hearts.png b/admin/cards/7_of_hearts.png new file mode 100644 index 0000000..19b89a2 Binary files /dev/null and b/admin/cards/7_of_hearts.png differ diff --git a/admin/cards/7_of_spades.png b/admin/cards/7_of_spades.png new file mode 100644 index 0000000..b9f1b93 Binary files /dev/null and b/admin/cards/7_of_spades.png differ diff --git a/admin/cards/8_of_clubs.png b/admin/cards/8_of_clubs.png new file mode 100644 index 0000000..cec743c Binary files /dev/null and b/admin/cards/8_of_clubs.png differ diff --git a/admin/cards/8_of_diamonds.png b/admin/cards/8_of_diamonds.png new file mode 100644 index 0000000..ed12951 Binary files /dev/null and b/admin/cards/8_of_diamonds.png differ diff --git a/admin/cards/8_of_hearts.png b/admin/cards/8_of_hearts.png new file mode 100644 index 0000000..fb39723 Binary files /dev/null and b/admin/cards/8_of_hearts.png differ diff --git a/admin/cards/8_of_spades.png b/admin/cards/8_of_spades.png new file mode 100644 index 0000000..b6b3b38 Binary files /dev/null and b/admin/cards/8_of_spades.png differ diff --git a/admin/cards/9_of_clubs.png b/admin/cards/9_of_clubs.png new file mode 100644 index 0000000..2174db5 Binary files /dev/null and b/admin/cards/9_of_clubs.png differ diff --git a/admin/cards/9_of_diamonds.png b/admin/cards/9_of_diamonds.png new file mode 100644 index 0000000..0b933fb Binary files /dev/null and b/admin/cards/9_of_diamonds.png differ diff --git a/admin/cards/9_of_hearts.png b/admin/cards/9_of_hearts.png new file mode 100644 index 0000000..7b196d6 Binary files /dev/null and b/admin/cards/9_of_hearts.png differ diff --git a/admin/cards/9_of_spades.png b/admin/cards/9_of_spades.png new file mode 100644 index 0000000..3c3b5ff Binary files /dev/null and b/admin/cards/9_of_spades.png differ diff --git a/admin/cards/ace_of_clubs.png b/admin/cards/ace_of_clubs.png new file mode 100644 index 0000000..42bf5ec Binary files /dev/null and b/admin/cards/ace_of_clubs.png differ diff --git a/admin/cards/ace_of_diamonds.png b/admin/cards/ace_of_diamonds.png new file mode 100644 index 0000000..79cd3b8 Binary files /dev/null and b/admin/cards/ace_of_diamonds.png differ diff --git a/admin/cards/ace_of_hearts.png b/admin/cards/ace_of_hearts.png new file mode 100644 index 0000000..b422124 Binary files /dev/null and b/admin/cards/ace_of_hearts.png differ diff --git a/admin/cards/ace_of_spades.png b/admin/cards/ace_of_spades.png new file mode 100644 index 0000000..103f56d Binary files /dev/null and b/admin/cards/ace_of_spades.png differ diff --git a/admin/cards/jack_of_clubs.png b/admin/cards/jack_of_clubs.png new file mode 100644 index 0000000..5e003be Binary files /dev/null and b/admin/cards/jack_of_clubs.png differ diff --git a/admin/cards/jack_of_diamonds.png b/admin/cards/jack_of_diamonds.png new file mode 100644 index 0000000..131a977 Binary files /dev/null and b/admin/cards/jack_of_diamonds.png differ diff --git a/admin/cards/jack_of_hearts.png b/admin/cards/jack_of_hearts.png new file mode 100644 index 0000000..bf342bc Binary files /dev/null and b/admin/cards/jack_of_hearts.png differ diff --git a/admin/cards/jack_of_spades.png b/admin/cards/jack_of_spades.png new file mode 100644 index 0000000..f539c19 Binary files /dev/null and b/admin/cards/jack_of_spades.png differ diff --git a/admin/cards/king_of_clubs.png b/admin/cards/king_of_clubs.png new file mode 100644 index 0000000..68e5774 Binary files /dev/null and b/admin/cards/king_of_clubs.png differ diff --git a/admin/cards/king_of_diamonds.png b/admin/cards/king_of_diamonds.png new file mode 100644 index 0000000..e21d6a0 Binary files /dev/null and b/admin/cards/king_of_diamonds.png differ diff --git a/admin/cards/king_of_hearts.png b/admin/cards/king_of_hearts.png new file mode 100644 index 0000000..1d3c468 Binary files /dev/null and b/admin/cards/king_of_hearts.png differ diff --git a/admin/cards/king_of_spades.png b/admin/cards/king_of_spades.png new file mode 100644 index 0000000..2edbbc1 Binary files /dev/null and b/admin/cards/king_of_spades.png differ diff --git a/admin/cards/queen_of_clubs.png b/admin/cards/queen_of_clubs.png new file mode 100644 index 0000000..7be5f9a Binary files /dev/null and b/admin/cards/queen_of_clubs.png differ diff --git a/admin/cards/queen_of_diamonds.png b/admin/cards/queen_of_diamonds.png new file mode 100644 index 0000000..928f650 Binary files /dev/null and b/admin/cards/queen_of_diamonds.png differ diff --git a/admin/cards/queen_of_hearts.png b/admin/cards/queen_of_hearts.png new file mode 100644 index 0000000..21839e6 Binary files /dev/null and b/admin/cards/queen_of_hearts.png differ diff --git a/admin/cards/queen_of_spades.png b/admin/cards/queen_of_spades.png new file mode 100644 index 0000000..7983d03 Binary files /dev/null and b/admin/cards/queen_of_spades.png differ diff --git a/admin/range.css b/admin/range.css new file mode 100644 index 0000000..7eb67af --- /dev/null +++ b/admin/range.css @@ -0,0 +1,82 @@ +/* ハンドレンジ学習(管理者専用)。基本のデザインは /assets/style.css を使う */ + +.range-wrap { padding-bottom: 32px; } + +/* タブ */ +.seg { display: flex; gap: 6px; background: var(--panel); border-radius: 12px; padding: 4px; margin: 12px 0 16px; } +.seg-btn { + flex: 1; + font: inherit; + font-size: 15px; + font-weight: 800; + border: 0; + border-radius: 9px; + padding: 10px 6px; + background: transparent; + color: var(--muted); + cursor: pointer; +} +.seg-btn.active { background: var(--panel-2); color: var(--text); } + +/* レンジ表の分類ごとの色(レンジ表のデータとしての色なのでサイトの配色とは別) */ +.cat-navy { --c: #20365d; --fg: #fff; } +.cat-red { --c: #9e342e; --fg: #fff; } +.cat-yellow { --c: #ddb356; --fg: #14191f; } +.cat-green { --c: #4e8051; --fg: #101910; } +.cat-blue { --c: #6aa5c9; --fg: #14191f; } +.cat-white { --c: #f7f7f7; --fg: #222; } +.cat-gray, .cat-purple { --c: #929292; --fg: #222; } + +/* 13×13 の表 */ +.range-matrix { display: grid; grid-template-columns: repeat(13, 1fr); gap: 2px; } +.range-cell { + aspect-ratio: 1; + min-width: 0; + padding: 0; + border: 0; + border-radius: 3px; + background: var(--c); + color: var(--fg); + font: inherit; + font-size: clamp(8px, 2.4vw, 12px); + font-weight: 800; + letter-spacing: -0.04em; + cursor: pointer; + position: relative; +} +.range-cell.cat-purple { box-shadow: inset 0 0 0 2px #c12cff; } +.range-cell.selected { outline: 2px solid var(--gold); outline-offset: 1px; z-index: 1; } + +/* 凡例 */ +.range-legend { display: flex; flex-wrap: wrap; gap: 6px 12px; margin-top: 12px; font-size: 12px; color: var(--muted); } +.range-legend span { display: inline-flex; align-items: center; gap: 6px; } +.swatch-dot { width: 14px; height: 14px; border-radius: 4px; background: var(--c); flex: none; } +.swatch-dot.cat-purple { box-shadow: inset 0 0 0 2px #c12cff; } + +/* 選択したハンド */ +.sel-hand { font-size: 28px; font-weight: 900; line-height: 1.1; } +.sel-label { display: flex; align-items: center; gap: 8px; font-weight: 800; margin-top: 6px; } + +/* クイズ */ +.quiz-progress { height: 6px; background: var(--input); border-radius: 999px; overflow: hidden; margin: 16px 0 8px; } +.quiz-progress i { display: block; height: 100%; width: 0; background: var(--green); transition: width 0.2s; } +.quiz-stats { display: flex; justify-content: center; gap: 12px; font-size: 13px; color: var(--muted); } +.quiz-hand { text-align: center; margin: 12px 0; padding: 18px 12px; } +.quiz-cards { display: flex; justify-content: center; gap: 10px; min-height: 0; } +.quiz-cards img { width: min(32%, 120px); height: auto; filter: drop-shadow(0 4px 8px rgba(0, 0, 0, 0.4)); } +.quiz-hand-name { font-size: 40px; font-weight: 900; margin-top: 8px; line-height: 1.1; } +.quiz-answers { display: grid; grid-template-columns: repeat(2, 1fr); gap: 8px; } +.quiz-answers .btn { + font-size: 15px; + padding: 12px 8px; + justify-content: flex-start; + background: var(--panel-2); + color: var(--text); + border: 2px solid transparent; +} +.quiz-answers .btn:disabled { opacity: 1; } +.quiz-answers .btn.correct { border-color: var(--green); background: rgba(46, 204, 113, 0.18); } +.quiz-answers .btn.wrong { border-color: var(--red); background: rgba(255, 90, 90, 0.15); } +.quiz-feedback { margin-top: 12px; padding: 12px 14px; border-radius: 10px; background: var(--panel); font-size: 14px; } +.quiz-feedback.good { box-shadow: inset 0 0 0 2px var(--green); } +.quiz-feedback.bad { box-shadow: inset 0 0 0 2px var(--red); } diff --git a/admin/range.html b/admin/range.html new file mode 100644 index 0000000..aca7443 --- /dev/null +++ b/admin/range.html @@ -0,0 +1,75 @@ + + +
+ + + + +