Files
lanspread/design/design_reference/SoftLAN Launcher.html
T
ddidderr 91c709960a docs: update launcher design for profile and server actions
Document the profile settings added to the launcher design and the new
Start Server detail action. The settings contract now includes a persisted
username and language choice, and the game detail overlay shows Start Server
only for installed games that can host a dedicated server.

The reference mock now includes the matching Profile controls, a server icon,
server-capable sample catalog entries, and the updated detail/settings
artboards so implementation can follow the selected design direction.

Test Plan:
- git diff --cached --check

Refs: design/README.md
2026-05-21 21:32:27 +02:00

125 lines
5.9 KiB
HTML

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>SoftLAN Launcher — Redesign</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Bebas+Neue&display=swap">
<link rel="stylesheet" href="styles.css">
<style>
html, body { margin: 0; padding: 0; background: #f0eee9; height: 100%; }
/* Tighten canvas chrome a hair */
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif; }
#root { width: 100%; height: 100%; }
</style>
<script src="https://unpkg.com/react@18.3.1/umd/react.development.js" integrity="sha384-hD6/rw4ppMLGNu3tX5cjIb+uRZ7UkRJ6BPkLpg4hAu/6onKUg4lLsHAs9EBPT82L" crossorigin="anonymous"></script>
<script src="https://unpkg.com/react-dom@18.3.1/umd/react-dom.development.js" integrity="sha384-u6aeetuaXnQ38mYT8rp6sbXaQe3NL9t+IBXmnYxwkUI2Hw4bsp2Wvmx4yRQF1uAm" crossorigin="anonymous"></script>
<script src="https://unpkg.com/@babel/standalone@7.29.0/babel.min.js" integrity="sha384-m08KidiNqLdpJqLq95G/LEi8Qvjl/xUYll3QILypMoQ65QorJ9Lvtp2RXYGBFj1y" crossorigin="anonymous"></script>
<script type="text/babel" src="design-canvas.jsx"></script>
<script type="text/babel" src="tweaks-panel.jsx"></script>
<script type="text/babel" src="data.jsx"></script>
<script type="text/babel" src="components.jsx"></script>
<script type="text/babel" src="launcher.jsx"></script>
</head>
<body>
<div id="root"></div>
<script type="text/babel">
const { useState } = React;
const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
"accent": "#3b82f6",
"density": "normal",
"aspect": "square",
"bg": "gradient",
"username": "d",
"language": "en"
}/*EDITMODE-END*/;
const ACCENTS = ['#3b82f6', '#22d3ee', '#a855f7', '#22c55e', '#f59e0b', '#ef4444'];
function App() {
const [t, setTweak] = useTweaks(TWEAK_DEFAULTS);
const heroGame = GAMES.find(g => g.id === 'cs'); // installed + canHostServer → shows Play + Start Server + Uninstall
return (
<React.Fragment>
<DesignCanvas>
<DCSection id="chrome" title="Chrome variations"
subtitle="Two ways to organize the top bar — pick whichever density of controls you prefer. Click any card to open the detail overlay, or the kebab menu to open Settings.">
<DCArtboard id="single-row" label="A · Single-row + segmented filters" width={1340} height={840}>
<Launcher variant="single" tweaks={t} setTweak={setTweak}
initialFilter="all" initialSort="recent"/>
</DCArtboard>
<DCArtboard id="two-row" label="B · Two-row + underlined tabs" width={1340} height={840}>
<Launcher variant="two" tweaks={t} setTweak={setTweak}
initialFilter="installed" initialSort="az"/>
</DCArtboard>
</DCSection>
<DCSection id="detail" title="Game detail overlay"
subtitle="Opens when you click a card. Full description, metadata, primary action + secondary actions (incl. uninstall).">
<DCArtboard id="detail-modal" label="C · Detail overlay (installed, can host server)" width={1340} height={840}>
<Launcher variant="single" tweaks={t} setTweak={setTweak}
initialFilter="installed" initialSort="az"
initialOpenGame={heroGame}/>
</DCArtboard>
<DCArtboard id="detail-modal-local" label="D · Detail overlay (downloaded, not installed)" width={1340} height={840}>
<Launcher variant="single" tweaks={t} setTweak={setTweak}
initialFilter="local" initialSort="az"
initialOpenGame={GAMES.find(g => g.id === 'cod4mw')}/>
</DCArtboard>
<DCArtboard id="detail-modal-downloading" label="E · Detail overlay (downloading)" width={1340} height={840}>
<Launcher variant="two" tweaks={t} setTweak={setTweak}
initialFilter="local" initialSort="state"
initialOpenGame={GAMES.find(g => g.id === 'avp')}/>
</DCArtboard>
</DCSection>
<DCSection id="settings" title="Settings dialog"
subtitle="Same controls as the dev Tweaks panel, surfaced as an in-app preferences dialog. Open via top-bar menu → Settings.">
<DCArtboard id="settings-open" label="F · Settings dialog (open)" width={1340} height={840}>
<Launcher variant="single" tweaks={t} setTweak={setTweak}
initialFilter="all" initialSort="recent"
initialSettingsOpen={true}/>
</DCArtboard>
</DCSection>
</DesignCanvas>
<TweaksPanel>
<TweakSection label="Profile"/>
<TweakText label="Username" value={t.username}
onChange={(v) => setTweak('username', v)}/>
<TweakRadio label="Language" value={t.language}
options={[{value: 'en', label: 'English'}, {value: 'de', label: 'Deutsch'}]}
onChange={(v) => setTweak('language', v)}/>
<TweakSection label="Theme"/>
<TweakColor label="Accent" value={t.accent} options={ACCENTS}
onChange={(v) => setTweak('accent', v)}/>
<TweakRadio label="Background" value={t.bg}
options={['flat', 'gradient', 'animated']}
onChange={(v) => setTweak('bg', v)}/>
<TweakSection label="Grid"/>
<TweakRadio label="Density" value={t.density}
options={['compact', 'normal', 'large']}
onChange={(v) => setTweak('density', v)}/>
<TweakRadio label="Cover aspect" value={t.aspect}
options={['box', 'square', 'banner']}
onChange={(v) => setTweak('aspect', v)}/>
</TweaksPanel>
</React.Fragment>
);
}
ReactDOM.createRoot(document.getElementById('root')).render(<App/>);
</script>
</body>
</html>