Phase 4 of turning the game into the company landing page. - Only the menu button, a compact objective chip and the touch controls stay on screen; speed shows only while driving. - The objective chip shows the next goal in one line, its distance and an arrow that turns towards it (replaces the compass strip); tapping it opens the mission list. - One floating menu holds map, missions, status, products, real-world, camera, stable mode, sound, graphics, minimap, fullscreen, help, restart and back to the start screen. It closes on a second tap, a tap outside, Escape, or after an action. - Missions, status and help open as sheets; street label, rank bar, status panel, toolbar and compass are gone. The minimap is optional and off by default. - Share the icon set and sheet dialog between start screen and HUD. - Layout checked for phone portrait, landscape and safe areas. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
75 lines
2.8 KiB
React
75 lines
2.8 KiB
React
import { useState } from 'react';
|
|
import { GameNode } from '@/components/shared/GameNode.jsx';
|
|
import { COMPANY } from '@/config/company.js';
|
|
import { ASSETS } from '@/config/assets.js';
|
|
import { strings } from '@/i18n/fa.js';
|
|
import { Icon } from '@/components/shared/Icon.jsx';
|
|
import { StartOptions } from './StartOptions.jsx';
|
|
import { InfoSheet } from './InfoSheet.jsx';
|
|
|
|
// Company information links under the start buttons, with their icons.
|
|
const SECTIONS = [
|
|
['about', 'building'],
|
|
['contact', 'phone'],
|
|
['address', 'map'],
|
|
['faq', 'help'],
|
|
['careers', 'briefcase'],
|
|
['gallery', 'image'],
|
|
['social', 'share'],
|
|
];
|
|
|
|
/** @typedef {{nodes: object, actions: object}} StartScreenProps */
|
|
/**
|
|
* Landing-page style start screen over the slowly orbiting 3D factory: brand, the four ways
|
|
* into the game, and the company information a website would normally show.
|
|
* @param {StartScreenProps} props - Interface snapshots and actions.
|
|
* @returns {import('react').ReactElement} Start screen.
|
|
*/
|
|
export function StartScreen({ nodes, actions }) {
|
|
const [section, setSection] = useState(null);
|
|
const text = strings.landing;
|
|
|
|
return (
|
|
<GameNode as="section" id="landing" aria-labelledby="landing-title" model={nodes.landing}>
|
|
<div className="landing-panel">
|
|
<header className="flex items-center gap-3">
|
|
<img src={ASSETS.brand.logo} alt={text.logoAlt} className="h-12 w-12 rounded-xl" />
|
|
<div>
|
|
<p className="text-lg font-bold">{COMPANY.shortName}</p>
|
|
<p className="text-sm text-primary">{COMPANY.tagline}</p>
|
|
</div>
|
|
</header>
|
|
<div className="my-6 md:my-10">
|
|
<h1 id="landing-title" className="text-2xl font-black leading-snug md:text-4xl">
|
|
{text.heading}
|
|
</h1>
|
|
<p className="mt-3 max-w-md opacity-80">{text.intro}</p>
|
|
</div>
|
|
<StartOptions actions={actions} />
|
|
<nav aria-label={text.sectionsLabel} className="mt-6 flex flex-wrap gap-2">
|
|
{SECTIONS.map(([key, icon]) => (
|
|
<button key={key} type="button" className="start-chip" onClick={() => setSection(key)}>
|
|
<Icon name={icon} className="h-4 w-4" />
|
|
{key === 'about' ? text.history : text.sections[key]}
|
|
</button>
|
|
))}
|
|
<GameNode
|
|
as="button"
|
|
id="install"
|
|
type="button"
|
|
className="start-chip"
|
|
hidden
|
|
model={nodes.install}
|
|
onAction={() => actions.emit('install')}
|
|
>
|
|
<Icon name="download" className="h-4 w-4" />
|
|
{text.install}
|
|
</GameNode>
|
|
</nav>
|
|
<p className="mt-6 hidden text-xs opacity-60 md:block">{text.keys}</p>
|
|
</div>
|
|
<InfoSheet section={section} onClose={() => setSection(null)} />
|
|
</GameNode>
|
|
);
|
|
}
|