Skip to content

Commit 9545562

Browse files
author
web3blind
committed
Persist sound settings and remove mobile overlay collisions
1 parent 2eb3c2f commit 9545562

7 files changed

Lines changed: 48 additions & 21 deletions

File tree

app/css/main.css

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -307,10 +307,7 @@ body {
307307

308308
/* Toast */
309309
#toast-container {
310-
position: sticky;
311-
top: 0;
312-
left: 0;
313-
right: 0;
310+
position: static;
314311
z-index: 1000;
315312
display: flex;
316313
flex-direction: column;
@@ -353,10 +350,7 @@ body {
353350

354351
/* Connection status */
355352
#connection-status {
356-
position: sticky;
357-
top: 0;
358-
left: auto;
359-
right: auto;
353+
position: static;
360354
transform: none;
361355
display: none;
362356
text-align: center;
@@ -1037,7 +1031,7 @@ body {
10371031
.quests-screen h1 { margin-bottom: 16px; }
10381032
.quest-tabs {
10391033
display: grid;
1040-
grid-template-columns: repeat(2, minmax(0, 1fr));
1034+
grid-template-columns: 1fr;
10411035
gap: 8px;
10421036
margin-bottom: 16px;
10431037
}

app/index.html

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
<link rel="manifest" href="manifest.json">
1212
<link rel="icon" type="image/png" sizes="192x192" href="assets/icons/icon-192.png">
1313
<link rel="apple-touch-icon" href="assets/icons/icon-192.png">
14-
<link rel="stylesheet" href="css/main.css?v=20260711b">
14+
<link rel="stylesheet" href="css/main.css?v=20260711c">
1515
<link rel="stylesheet" href="css/themes.css">
1616
<link rel="stylesheet" href="css/accessibility.css">
1717
</head>
@@ -169,7 +169,7 @@
169169
<script src="js/engine/daily-leaderboard.js"></script>
170170

171171
<!-- UI Components -->
172-
<script src="js/ui/sound.js"></script>
172+
<script src="js/ui/sound.js?v=20260711c"></script>
173173
<script src="js/ui/components/progress-bar.js"></script>
174174
<script src="js/ui/components/toast.js?v=20260711b"></script>
175175
<script src="js/ui/components/modal.js"></script>
@@ -193,7 +193,7 @@
193193
<script src="js/ui/screens/crafting.js?v=20260621j"></script>
194194
<script src="js/ui/screens/quests.js?v=20260621n"></script>
195195
<script src="js/ui/screens/world-boss.js"></script>
196-
<script src="js/ui/screens/settings.js"></script>
196+
<script src="js/ui/screens/settings.js?v=20260711c"></script>
197197
<script src="js/ui/screens/help.js"></script>
198198
<script src="js/ui/screens/leaderboard.js"></script>
199199

app/js/ui/screens/settings.js

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,17 @@ var SettingsScreen = (function() {
1616
return !!fallback;
1717
}
1818

19+
function _getStoredNumber(key, fallback) {
20+
try {
21+
var value = localStorage.getItem(STORAGE_PREFIX + key);
22+
if (value !== null && value !== '') {
23+
var num = parseFloat(value);
24+
if (!isNaN(num)) return num;
25+
}
26+
} catch (e) {}
27+
return fallback;
28+
}
29+
1930
function _setStoredBool(key, value) {
2031
try {
2132
localStorage.setItem(STORAGE_PREFIX + key, value ? '1' : '0');
@@ -31,6 +42,8 @@ var SettingsScreen = (function() {
3142
var currentLang = Helpers.getCurrentLang ? Helpers.getCurrentLang() : 'ru';
3243
var highContrast = _getStoredBool('high_contrast', false);
3344
var reducedMotion = _getStoredBool('reduced_motion', false);
45+
var sfxVolume = Math.round(_getStoredNumber('sfx_volume', 0.5) * 100);
46+
if (typeof SoundManager !== 'undefined') SoundManager.setVolume(sfxVolume / 100);
3447

3548
el.innerHTML =
3649
'<div class="settings-screen">' +
@@ -48,7 +61,7 @@ var SettingsScreen = (function() {
4861
// Sound
4962
'<section class="settings-section" aria-label="' + t('settings_sound') + '">' +
5063
'<h2>' + t('settings_sound') + '</h2>' +
51-
_renderSlider('sfx-volume', t('settings_sfx'), 50) +
64+
_renderSlider('sfx-volume', t('settings_sfx'), sfxVolume) +
5265
_renderSlider('music-volume', t('settings_music'), 50) +
5366
_renderToggle('narrator-toggle', t('narrator_toggle'), true) +
5467
'<div class="settings-field">' +

app/js/ui/sound.js

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,22 @@
55
var SoundManager = (function() {
66
'use strict';
77

8+
var STORAGE_PREFIX = (typeof VizMagicConfig !== 'undefined' && VizMagicConfig.STORAGE_PREFIX) ? VizMagicConfig.STORAGE_PREFIX : 'viz_magic_';
9+
10+
function _getStoredNumber(key, fallback) {
11+
try {
12+
var value = localStorage.getItem(STORAGE_PREFIX + key);
13+
if (value !== null && value !== '') {
14+
var num = parseFloat(value);
15+
if (!isNaN(num)) return num;
16+
}
17+
} catch (e) {}
18+
return fallback;
19+
}
20+
821
var audioCtx = null;
922
var enabled = true;
10-
var volume = 0.5;
23+
var volume = _getStoredNumber('sfx_volume', 0.5);
1124
var sounds = {};
1225

1326
/**
@@ -27,7 +40,7 @@ var SoundManager = (function() {
2740
* @param {string} soundId
2841
*/
2942
function play(soundId) {
30-
if (!enabled) return;
43+
if (!enabled || volume <= 0) return;
3144
// Lazily initialize on first play call — this always happens inside a user gesture
3245
if (!audioCtx) init();
3346
if (!audioCtx) return;
@@ -641,6 +654,9 @@ var SoundManager = (function() {
641654
*/
642655
function setVolume(vol) {
643656
volume = Math.max(0, Math.min(1, vol));
657+
try {
658+
localStorage.setItem(STORAGE_PREFIX + 'sfx_volume', String(volume));
659+
} catch (e) {}
644660
}
645661

646662
/**

app/sw.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// Viz Magic — Service Worker
2-
var CACHE_NAME = 'viz-magic-v30';
2+
var CACHE_NAME = 'viz-magic-v31';
33
var ASSETS = [
44
'/',
55
'/index.html',

tests/core-screen-accessibility-smoke.test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ async function run() {
9090
var badLogs = logs.filter(function(l) { return l.type === 'error' || l.type === 'pageerror'; });
9191
assert.deepStrictEqual(failed, [], 'all core screens should render with named controls and no raw keys');
9292
assert.deepStrictEqual(badLogs, [], 'core screen smoke should not emit console errors/page errors');
93-
assert.ok(result.cachesKeys.indexOf('viz-magic-v30') !== -1, 'service worker cache should use latest cache name');
93+
assert.ok(result.cachesKeys.indexOf('viz-magic-v31') !== -1, 'service worker cache should use latest cache name');
9494
assert.ok(result.scripts.some(function(src) { return src.indexOf('helpers.js?v=20260621l') !== -1; }), 'helpers script should be cache-busted');
9595
assert.ok(result.scripts.some(function(src) { return src.indexOf('territory.js?v=20260621l') !== -1; }), 'territory script should be cache-busted');
9696
assert.ok(result.scripts.some(function(src) { return src.indexOf('state-engine.js?v=20260621m') !== -1; }), 'state engine script should be cache-busted');

tests/player-bug-regressions.test.js

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -335,7 +335,7 @@ test('high-traffic UI narration, screen announcements, and inventory stat labels
335335

336336
test('service worker updates quickly and keeps navigations network-first', function () {
337337
const swJs = read('app/sw.js');
338-
assert.ok(/viz-magic-v30/.test(swJs), 'service worker cache version should be bumped');
338+
assert.ok(/viz-magic-v31/.test(swJs), 'service worker cache version should be bumped');
339339
assert.ok(/self\.skipWaiting\(\)/.test(swJs), 'service worker should activate new cache without waiting for all tabs to close');
340340
assert.ok(/self\.clients\.claim\(\)/.test(swJs), 'service worker should claim clients after activation');
341341
assert.ok(/event\.request\.mode === 'navigate'[\s\S]*fetch\(event\.request\)/.test(swJs), 'navigation requests should prefer network to avoid stale cached index');
@@ -375,10 +375,14 @@ test('mobile entry helpers cover keyboard paste, home-screen shortcut, nav parit
375375
assert.ok(/nav_bazaar/.test(homeJs) && /nav_crafting/.test(homeJs), 'home primary labels should reuse bottom-nav translation keys');
376376
assert.ok(/actionType === 'chronicle_post'[\s\S]*_normalizeDedupeText/.test(chronicleJs), 'chronicle post dedupe should ignore temporary block numbers');
377377
assert.ok(/insertBefore\(container, appMain\)/.test(toastJs), 'toast strip should be inserted before app-main so it does not cover headings');
378-
assert.ok(/#connection-status[\s\S]*position:\s*sticky/.test(mainCss), 'connection status should stay in normal flow instead of covering headings');
379-
assert.ok(/\.quest-tabs[\s\S]*grid-template-columns:\s*repeat\(2, minmax\(0, 1fr\)\)/.test(mainCss), 'quest tabs should render as a two-column mobile grid');
378+
assert.ok(/#connection-status[\s\S]*position:\s*static/.test(mainCss), 'connection status should stay in normal flow instead of covering headings');
379+
assert.ok(/\.quest-tabs[\s\S]*grid-template-columns:\s*1fr/.test(mainCss), 'quest tabs should render as one full-width column on mobile');
380380
assert.ok(/role', type === 'error' \? 'alert' : 'status'/.test(toastJs), 'only errors should be assertive toast alerts');
381-
assert.ok(/viz-magic-v30/.test(read('app/sw.js')), 'service worker cache should be bumped for UI changes');
381+
assert.ok(/function _getStoredNumber/.test(read('app/js/ui/screens/settings.js')), 'settings should read stored sound slider values');
382+
assert.ok(/SoundManager\.setVolume\(sfxVolume \/ 100\)/.test(read('app/js/ui/screens/settings.js')), 'settings should apply stored SFX volume on render');
383+
assert.ok(/localStorage\.setItem\(STORAGE_PREFIX \+ 'sfx_volume'/.test(read('app/js/ui/sound.js')), 'sound manager should persist SFX volume');
384+
assert.ok(/var volume = _getStoredNumber\('sfx_volume', 0\.5\)/.test(read('app/js/ui/sound.js')), 'sound manager should restore persisted SFX volume');
385+
assert.ok(/viz-magic-v31/.test(read('app/sw.js')), 'service worker cache should be bumped for UI changes');
382386
});
383387

384388
if (process.exitCode) {

0 commit comments

Comments
 (0)