portrait-only: drop landscape rotate prompt + lock to portrait
CI/CD / CI - API (dotnet build + engine sim) (push) Successful in 38s
CI/CD / CI - Web (tsc + next build) (push) Successful in 1m6s
CI/CD / Deploy - local stack (db + server + web) (push) Successful in 1m24s

- Remove RotatePrompt (the "rotate to landscape" overlay) — the app is portrait
  now, so it only blocked the UI.
- page.tsx: best-effort orientation lock switched landscape → portrait.
- Add Playwright-based store-screenshot + icon scripts (scripts/shots.js,
  game.js, icon.js); generated images are gitignored.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
soroush.asadi
2026-06-12 13:33:01 +03:30
parent 7f08249fa7
commit 66c83991d4
8 changed files with 190 additions and 64 deletions
-58
View File
@@ -1,58 +0,0 @@
"use client";
import { useEffect, useState } from "react";
import { RotateCcw } from "lucide-react";
import { useI18n } from "@/lib/i18n";
/**
* Landscape-first nudge for the game table. The Hokm table plays best wide
* (UNO-style), so when a phone is held in portrait we cover the table with a
* "rotate your device" prompt. iOS/Safari can't be force-rotated, so this is the
* reliable cross-platform path. A "play anyway" escape hatch avoids trapping
* users whose OS rotation-lock is on.
*/
export function RotatePrompt() {
const { t } = useI18n();
const [portrait, setPortrait] = useState(false);
const [dismissed, setDismissed] = useState(false);
useEffect(() => {
const check = () => {
const isPortrait = window.innerHeight > window.innerWidth;
// Only nudge on phone-sized screens (smaller side ≤ ~820px); desktops/wide
// tablets are already roomy enough.
const isPhone = Math.min(window.innerWidth, window.innerHeight) <= 820;
setPortrait(isPortrait && isPhone);
};
check();
window.addEventListener("resize", check);
window.addEventListener("orientationchange", check);
return () => {
window.removeEventListener("resize", check);
window.removeEventListener("orientationchange", check);
};
}, []);
if (!portrait || dismissed) return null;
return (
<div className="fixed inset-0 z-[80] flex flex-col items-center justify-center gap-6 bg-navy-950/96 backdrop-blur-md p-8 text-center safe-top safe-x">
<RotateCcw className="size-20 text-gold-400 motion-safe:animate-[rotateHint_2.4s_ease-in-out_infinite]" />
<h2 className="text-2xl font-black gold-text">{t("rotate.title")}</h2>
<p className="max-w-xs leading-8 text-cream/70">{t("rotate.desc")}</p>
<button
onClick={() => setDismissed(true)}
className="mt-2 text-sm text-cream/45 underline underline-offset-4 hover:text-cream/70"
>
{t("rotate.anyway")}
</button>
<style>{`
@keyframes rotateHint {
0%, 40% { transform: rotate(0deg); }
60%, 100% { transform: rotate(-90deg); }
}
`}</style>
</div>
);
}