anvilsign in

collin/mahjong

1import type { Prefs } from '../game/prefs';
2import { enterFullscreen, exitFullscreen, fullscreenSupported, useFullscreen } from './fullscreen';
3
4interface Props {
5 prefs: Prefs;
6 onPrefs: (p: Prefs) => void;
7 /** Icon only, for the cramped row of controls in the middle of the table. */
8 compact?: boolean;
9}
10
11/* Corner brackets rather than a glyph: this has to read on whatever font a
12 phone happens to have, and the symbols for it are thin on the ground. */
13const Corners = ({ out }: { out: boolean }) => (
14 <svg
15 className="fs-icon"
16 viewBox="0 0 20 20"
17 width="15"
18 height="15"
19 aria-hidden
20 fill="none"
21 stroke="currentColor"
22 strokeWidth="2"
23 strokeLinecap="round"
24 strokeLinejoin="round"
25 >
26 {out ? (
27 <path d="M2 7V2h5M13 2h5v5M18 13v5h-5M7 18H2v-5" />
28 ) : (
29 <path d="M7 2v5H2M18 7h-5V2M13 18v-5h5M2 13h5v5" />
30 )}
31 </svg>
32);
33
34/**
35 * Takes the screen and gives it back — and remembers which the player wanted.
36 * The browser drops fullscreen on every reload, and this game is built to be
37 * put down and resumed, so without that memory you would be reaching for this
38 * button every single time.
39 */
40export function FullscreenToggle({ prefs, onPrefs, compact }: Props) {
41 const active = useFullscreen();
42 if (!fullscreenSupported()) return null;
43
44 return (
45 <button
46 className={`btn ghost pill fs-toggle ${compact ? 'compact' : ''} ${active ? 'on' : ''}`}
47 aria-pressed={active}
48 onClick={() => {
49 // Made here, inside the click: the same call from an effect is refused.
50 if (active) exitFullscreen();
51 else enterFullscreen();
52 onPrefs({ ...prefs, fullscreen: !active });
53 }}
54 >
55 <Corners out={!active} />
56 {!compact && <span>{active ? '離開全螢幕 Exit full screen' : '全螢幕 Full screen'}</span>}
57 </button>
58 );
59}