polish(ui): refine pause settings menu

This commit is contained in:
Tom Boullay
2026-05-31 21:42:59 +02:00
parent f11ed67452
commit efcbf9e972
3 changed files with 106 additions and 55 deletions
+71 -34
View File
@@ -3,9 +3,11 @@ import type { ReactNode } from "react";
import {
Captions,
Gauge,
LogOut,
Hand,
Laptop,
Music2,
RotateCcw,
Server,
Volume2,
X,
} from "lucide-react";
@@ -14,25 +16,19 @@ import {
GRAPHICS_PRESETS,
type GraphicsPreset,
} from "@/data/world/graphicsConfig";
import { useDebugStore } from "@/hooks/debug/useDebugStore";
import { useGameStore } from "@/managers/stores/useGameStore";
import { useSettingsStore } from "@/managers/stores/useSettingsStore";
import { useWorldSettingsStore } from "@/managers/stores/useWorldSettingsStore";
import type { HandTrackingSource } from "@/types/handTracking/handTracking";
import type { SubtitleLanguage } from "@/types/settings/settings";
import { isDebugEnabled } from "@/utils/debug/isDebugEnabled";
import { clearSiteVisited } from "@/utils/cookies/siteVisitCookie";
import { Debug } from "@/utils/debug/Debug";
function formatPercent(value: number): string {
return `${Math.round(value * 100)}%`;
}
function clearCookies(): void {
document.cookie.split(";").forEach((cookie) => {
const cookieName = cookie.split("=")[0]?.trim();
if (!cookieName) return;
document.cookie = `${cookieName}=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/`;
});
}
interface VolumeSliderProps {
id: string;
label: string;
@@ -74,6 +70,26 @@ function formatChunkDistance(distance: number): string {
return `${distance}m`;
}
const HAND_TRACKING_OPTIONS = [
{
description: "Calcul local",
icon: <Laptop size={14} aria-hidden="true" />,
label: "Sur cet ordi",
source: "browser",
},
{
description: "Soulage l'ordi",
icon: <Server size={14} aria-hidden="true" />,
label: "Mode assisté",
source: "backend",
},
] as const satisfies readonly {
description: string;
icon: ReactNode;
label: string;
source: HandTrackingSource;
}[];
interface GraphicsPresetButtonProps {
active: boolean;
preset: GraphicsPreset;
@@ -108,6 +124,9 @@ function GraphicsPresetButton({
export function GameSettingsMenu(): React.JSX.Element | null {
const resetGame = useGameStore((state) => state.resetGame);
const handTrackingSource = useDebugStore((debug) =>
debug.getHandTrackingSource(),
);
const graphicsPreset = useWorldSettingsStore(
(state) => state.graphics.preset,
);
@@ -148,18 +167,17 @@ export function GameSettingsMenu(): React.JSX.Element | null {
if (!isSettingsMenuOpen) return null;
const handleQuit = (): void => {
clearCookies();
const handleRestart = (): void => {
resetGame();
clearSiteVisited();
setSettingsMenuOpen(false);
window.location.assign("/");
};
const handleRestart = (): void => {
resetGame();
window.location.reload();
const handleHandTrackingSourceChange = (source: HandTrackingSource): void => {
Debug.getInstance().setHandTrackingSource(source);
};
const showDebugRestart = isDebugEnabled();
return (
<div className="game-settings-menu" role="dialog" aria-modal="true">
<div className="game-settings-menu__panel">
@@ -185,7 +203,7 @@ export function GameSettingsMenu(): React.JSX.Element | null {
>
<div className="game-settings-menu__section-title">
<Gauge size={16} aria-hidden="true" />
<h3 id="graphics-settings-heading">Performance</h3>
<h3 id="graphics-settings-heading">Graphisme</h3>
</div>
<div
className="game-settings-menu__choice-group game-settings-menu__choice-group--presets"
@@ -269,26 +287,45 @@ export function GameSettingsMenu(): React.JSX.Element | null {
))}
</div>
</section>
<section
className="game-settings-menu__section game-settings-menu__section--right"
aria-labelledby="hand-tracking-settings-heading"
>
<div className="game-settings-menu__section-title">
<Hand size={16} aria-hidden="true" />
<h3 id="hand-tracking-settings-heading">Détection des mains</h3>
</div>
<div
className="game-settings-menu__choice-group game-settings-menu__choice-group--hand-tracking"
aria-label="Mode de détection des mains"
>
{HAND_TRACKING_OPTIONS.map((option) => (
<button
key={option.source}
type="button"
className={
handTrackingSource === option.source ? "active" : undefined
}
onClick={() => handleHandTrackingSourceChange(option.source)}
aria-pressed={handTrackingSource === option.source}
>
{option.icon}
<span>{option.label}</span>
<small>{option.description}</small>
</button>
))}
</div>
</section>
</div>
{showDebugRestart ? (
<button
className="game-settings-menu__restart"
type="button"
onClick={handleRestart}
>
<RotateCcw size={14} aria-hidden="true" />
Recommencer
</button>
) : null}
<button
className="game-settings-menu__quit"
className="game-settings-menu__restart"
type="button"
onClick={handleQuit}
onClick={handleRestart}
>
<LogOut size={14} aria-hidden="true" />
Quitter
<RotateCcw size={14} aria-hidden="true" />
Recommencer
</button>
</div>
</div>