Skip to content

Commit 076e00d

Browse files
committed
improve about dialog
1 parent cce9711 commit 076e00d

9 files changed

Lines changed: 411 additions & 2 deletions

File tree

desktop/packaging/icon.png

32.4 KB
Loading

desktop/packaging/icon.svg

Lines changed: 13 additions & 0 deletions
Loading

desktop/renderer/about-theme.js

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
const PREFERENCES_KEY = 'appPreferences';
2+
3+
function readDarkPreference() {
4+
try {
5+
const raw = localStorage.getItem(PREFERENCES_KEY);
6+
if (raw === null) return false;
7+
8+
const preferences = JSON.parse(raw);
9+
return preferences !== null && typeof preferences === 'object' && preferences.theme === 'dark';
10+
} catch {
11+
return false;
12+
}
13+
}
14+
15+
function applyTheme() {
16+
const dark = readDarkPreference();
17+
document.documentElement.classList.toggle('dark', dark);
18+
document
19+
.querySelector('meta[name="theme-color"]')
20+
?.setAttribute('content', dark ? '#0d120f' : '#f9faf8');
21+
}
22+
23+
applyTheme();
24+
window.addEventListener('storage', (event) => {
25+
if (event.key === PREFERENCES_KEY) applyTheme();
26+
});

desktop/renderer/about.css

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
:root {
2+
color-scheme: light;
3+
font-family: 'Avenir Next', Avenir, 'Segoe UI', sans-serif;
4+
background: #f9faf8;
5+
color: #191a18;
6+
--canvas-base: #f9faf8;
7+
--canvas-bg-subtle: #eceee9;
8+
--canvas-line: #c7cac4;
9+
--canvas-text: #4f524d;
10+
--canvas-text-contrast: #191a18;
11+
--canvas-solid-hover: #757874;
12+
--accent: #30a46c;
13+
--accent-text: #18794e;
14+
--accent-on-soft: #153226;
15+
--detail-surface: rgb(255 255 255 / 72%);
16+
--scanline: rgb(25 26 24 / 3%);
17+
}
18+
19+
:root.dark {
20+
color-scheme: dark;
21+
background: #0d120f;
22+
color: #eaeee9;
23+
--canvas-base: #0d120f;
24+
--canvas-bg-subtle: #151a17;
25+
--canvas-line: #2f3b34;
26+
--canvas-text: #a4b5ac;
27+
--canvas-text-contrast: #eaeee9;
28+
--canvas-solid-hover: #687c70;
29+
--accent-text: #4cc38a;
30+
--accent-on-soft: #e5fbeb;
31+
--detail-surface: rgb(21 26 23 / 72%);
32+
--scanline: rgb(255 255 255 / 3%);
33+
}
34+
35+
* {
36+
box-sizing: border-box;
37+
}
38+
39+
body {
40+
min-height: 100vh;
41+
margin: 0;
42+
overflow: hidden;
43+
background:
44+
radial-gradient(circle at 50% 8%, rgb(48 164 108 / 13%), transparent 38%),
45+
linear-gradient(145deg, var(--canvas-bg-subtle) 0%, var(--canvas-base) 70%);
46+
}
47+
48+
body::before {
49+
position: fixed;
50+
inset: 0;
51+
pointer-events: none;
52+
content: '';
53+
opacity: 0.22;
54+
background-image: linear-gradient(var(--scanline) 1px, transparent 1px);
55+
background-size: 100% 4px;
56+
}
57+
58+
[data-slot='about-card'] {
59+
position: relative;
60+
display: flex;
61+
min-height: 100vh;
62+
padding: 44px 54px 34px;
63+
align-items: center;
64+
flex-direction: column;
65+
text-align: center;
66+
}
67+
68+
[data-slot='brand-mark'] {
69+
display: grid;
70+
width: 112px;
71+
height: 112px;
72+
margin-bottom: 22px;
73+
place-items: center;
74+
filter: drop-shadow(0 18px 30px rgb(0 0 0 / 35%));
75+
}
76+
77+
[data-slot='app-icon'] {
78+
display: block;
79+
width: 112px;
80+
height: 112px;
81+
}
82+
83+
[data-slot='app-name'] {
84+
margin: 0;
85+
font-size: 38px;
86+
font-weight: 650;
87+
letter-spacing: -0.025em;
88+
line-height: 1.05;
89+
}
90+
91+
[data-slot='tagline'] {
92+
max-width: 350px;
93+
margin: 13px 0 26px;
94+
color: var(--canvas-text);
95+
font-size: 14px;
96+
line-height: 1.55;
97+
}
98+
99+
[data-slot='build-details'] {
100+
display: grid;
101+
width: 100%;
102+
margin: 0 0 22px;
103+
padding: 15px 18px;
104+
grid-template-columns: 0.8fr 1.2fr;
105+
border: 1px solid var(--canvas-line);
106+
border-radius: 12px;
107+
background: var(--detail-surface);
108+
}
109+
110+
[data-slot='build-detail'] {
111+
min-width: 0;
112+
}
113+
114+
[data-slot='build-detail'] + [data-slot='build-detail'] {
115+
border-left: 1px solid var(--canvas-line);
116+
}
117+
118+
[data-slot='build-label'] {
119+
margin-bottom: 5px;
120+
color: var(--canvas-solid-hover);
121+
font-size: 10px;
122+
font-weight: 700;
123+
letter-spacing: 0.11em;
124+
text-transform: uppercase;
125+
}
126+
127+
[data-slot='build-value'] {
128+
margin: 0;
129+
overflow: hidden;
130+
color: var(--canvas-text-contrast);
131+
font-family: ui-monospace, 'SFMono-Regular', Consolas, monospace;
132+
font-size: 11px;
133+
text-overflow: ellipsis;
134+
white-space: nowrap;
135+
}
136+
137+
[data-slot='project-link'] {
138+
display: inline-flex;
139+
min-height: 42px;
140+
padding: 0 19px;
141+
align-items: center;
142+
gap: 9px;
143+
border: 1px solid var(--accent);
144+
border-radius: 999px;
145+
color: var(--accent-on-soft);
146+
font-size: 13px;
147+
font-weight: 700;
148+
text-decoration: none;
149+
transition:
150+
background-color 140ms ease,
151+
box-shadow 140ms ease,
152+
transform 140ms ease;
153+
}
154+
155+
[data-slot='project-link']:hover {
156+
background: rgb(48 164 108 / 14%);
157+
box-shadow: 0 8px 24px rgb(48 164 108 / 14%);
158+
transform: translateY(-1px);
159+
}
160+
161+
[data-slot='project-link']:focus-visible {
162+
outline: 3px solid rgb(48 164 108 / 35%);
163+
outline-offset: 3px;
164+
}
165+
166+
[data-slot='external-mark'] {
167+
color: var(--accent-text);
168+
font-size: 15px;
169+
}
170+
171+
[data-slot='about-footer'] {
172+
display: flex;
173+
width: calc(100% - 108px);
174+
margin-top: auto;
175+
padding-top: 22px;
176+
justify-content: space-between;
177+
border-top: 1px solid var(--canvas-line);
178+
color: var(--canvas-solid-hover);
179+
font-family: ui-monospace, 'SFMono-Regular', Consolas, monospace;
180+
font-size: 10px;
181+
letter-spacing: 0.04em;
182+
}

desktop/renderer/about.html

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1" />
6+
<meta name="theme-color" content="#f9faf8" />
7+
<title>About Chia Gaming</title>
8+
<script src="about-theme.js"></script>
9+
<link rel="stylesheet" href="about.css" />
10+
</head>
11+
<body data-slot="about-page">
12+
<main data-slot="about-card">
13+
<div data-slot="brand-mark">
14+
<img data-slot="app-icon" src="about-icon.svg" alt="" />
15+
</div>
16+
17+
<h1 data-slot="app-name">Chia Gaming</h1>
18+
<p data-slot="tagline">Two-player games secured by Chia state channels.</p>
19+
20+
<dl data-slot="build-details">
21+
<div data-slot="build-detail">
22+
<dt data-slot="build-label">Version</dt>
23+
<dd data-slot="build-value" id="app-version"></dd>
24+
</div>
25+
<div data-slot="build-detail">
26+
<dt data-slot="build-label">Runtime</dt>
27+
<dd data-slot="build-value" id="runtime-version"></dd>
28+
</div>
29+
</dl>
30+
31+
<a
32+
data-slot="project-link"
33+
href="https://github.com/Chia-Network/chia-gaming"
34+
target="_blank"
35+
rel="noreferrer"
36+
>
37+
More information
38+
<span data-slot="external-mark" aria-hidden="true"></span>
39+
</a>
40+
41+
<footer data-slot="about-footer">
42+
<span data-slot="license">Apache-2.0</span>
43+
<span data-slot="copyright" id="copyright">Chia Network</span>
44+
</footer>
45+
</main>
46+
<script type="module" src="about.mjs"></script>
47+
</body>
48+
</html>

desktop/renderer/about.mjs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
const params = new URLSearchParams(window.location.search);
2+
3+
const version = params.get('version');
4+
const electron = params.get('electron');
5+
const chromium = params.get('chromium');
6+
7+
document.querySelector('#app-version').textContent = version ?? 'Unknown';
8+
document.querySelector('#runtime-version').textContent =
9+
electron !== null && chromium !== null
10+
? `Electron ${electron.split('.').slice(0, 2).join('.')} · Chromium ${chromium.split('.')[0]}`
11+
: 'Unknown';
12+
document.querySelector('#copyright').textContent =
13+
`Copyright © ${new Date().getFullYear()} Chia Network`;

desktop/scripts/stage-renderer.mjs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,19 @@ rmSync(OUT, { recursive: true, force: true });
2828
mkdirSync(OUT, { recursive: true });
2929
cpSync(PLAYER_BUNDLE, OUT, { recursive: true });
3030

31-
for (const file of ['index.html', 'bootstrap.mjs']) {
31+
for (const file of [
32+
'index.html',
33+
'bootstrap.mjs',
34+
'about.html',
35+
'about.css',
36+
'about.mjs',
37+
'about-theme.js',
38+
]) {
3239
copyFileSync(join(DESKTOP, 'renderer', file), join(OUT, file));
3340
}
3441

42+
copyFileSync(join(DESKTOP, 'packaging', 'icon.svg'), join(OUT, 'about-icon.svg'));
43+
3544
const favicon = join(REPO, 'front-end', 'public', 'favicon.svg');
3645
if (existsSync(favicon)) {
3746
copyFileSync(favicon, join(OUT, 'favicon.svg'));
@@ -40,6 +49,11 @@ if (existsSync(favicon)) {
4049
const errors = [
4150
'index.html',
4251
'bootstrap.mjs',
52+
'about.html',
53+
'about.css',
54+
'about.mjs',
55+
'about-theme.js',
56+
'about-icon.svg',
4357
'index.js',
4458
'index.css',
4559
'chia_gaming_wasm.js',

desktop/src/main/aboutWindow.ts

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import { BrowserWindow, app, shell } from 'electron';
2+
3+
import { APP_ORIGIN } from './appProtocol';
4+
import { log } from './log';
5+
6+
const PROJECT_URL = 'https://github.com/Chia-Network/chia-gaming';
7+
8+
let aboutWindow: BrowserWindow | null = null;
9+
10+
export function showAboutWindow(): void {
11+
if (aboutWindow !== null && !aboutWindow.isDestroyed()) {
12+
aboutWindow.show();
13+
aboutWindow.focus();
14+
return;
15+
}
16+
17+
const parent = BrowserWindow.getFocusedWindow() ?? BrowserWindow.getAllWindows()[0];
18+
const window = new BrowserWindow({
19+
width: 520,
20+
height: 590,
21+
resizable: false,
22+
maximizable: false,
23+
minimizable: false,
24+
fullscreenable: false,
25+
show: false,
26+
parent,
27+
title: 'About Chia Gaming',
28+
backgroundColor: '#0d120f',
29+
webPreferences: {
30+
sandbox: true,
31+
contextIsolation: true,
32+
nodeIntegration: false,
33+
nodeIntegrationInWorker: false,
34+
nodeIntegrationInSubFrames: false,
35+
webSecurity: true,
36+
allowRunningInsecureContent: false,
37+
experimentalFeatures: false,
38+
webviewTag: false,
39+
navigateOnDragDrop: false,
40+
spellcheck: false,
41+
devTools: !app.isPackaged,
42+
},
43+
});
44+
45+
aboutWindow = window;
46+
window.setMenuBarVisibility(false);
47+
window.webContents.setWindowOpenHandler(({ url }) => {
48+
if (url === PROJECT_URL) {
49+
void shell.openExternal(url).catch((error: unknown) => {
50+
log.error(`failed to open project website: ${String(error)}`);
51+
});
52+
} else {
53+
log.warn(`blocked About window link: ${url}`);
54+
}
55+
return { action: 'deny' };
56+
});
57+
window.once('ready-to-show', () => window.show());
58+
window.on('closed', () => {
59+
aboutWindow = null;
60+
});
61+
62+
const query = new URLSearchParams({
63+
version: app.getVersion(),
64+
electron: process.versions.electron,
65+
chromium: process.versions.chrome,
66+
});
67+
void window.loadURL(`${APP_ORIGIN}/about.html?${query.toString()}`);
68+
}

0 commit comments

Comments
 (0)