diff --git a/index.html b/index.html index 2b4f8b5..563576d 100644 --- a/index.html +++ b/index.html @@ -13,9 +13,9 @@
LegacyLauncher
-
-
-
×
+ + +
@@ -201,6 +201,12 @@
+ +
@@ -254,6 +260,13 @@
+
+ +
+
diff --git a/renderer.js b/renderer.js index 6c98d06..4d2dddc 100644 --- a/renderer.js +++ b/renderer.js @@ -9,6 +9,10 @@ const DEFAULT_REPO = "smartcmd/MinecraftConsoles"; const DEFAULT_EXEC = "Minecraft.Client.exe"; const TARGET_FILE = "LCEWindows64.zip"; const LAUNCHER_REPO = "gradenGnostic/LegacyLauncher"; +const REPO_PRESETS = { + default: 'smartcmd/MinecraftConsoles', + noWatermark: 'cath0degaytube/MinecraftConsoles' +}; let instances = []; let currentInstanceId = null; @@ -108,21 +112,22 @@ const GamepadManager = { const left = isPressed(14) || axisX < -threshold; const right = isPressed(15) || axisX > threshold; - if (up) { this.navigate('up'); this.lastInputTime = now; } - else if (down) { this.navigate('down'); this.lastInputTime = now; } - else if (left) { this.navigate('left'); this.lastInputTime = now; } - else if (right) { this.navigate('right'); this.lastInputTime = now; } + if (up) { UiSoundManager.setInputSource('controller'); this.navigate('up'); this.lastInputTime = now; } + else if (down) { UiSoundManager.setInputSource('controller'); this.navigate('down'); this.lastInputTime = now; } + else if (left) { UiSoundManager.setInputSource('controller'); this.navigate('left'); this.lastInputTime = now; } + else if (right) { UiSoundManager.setInputSource('controller'); this.navigate('right'); this.lastInputTime = now; } - else if (isPressed(4)) { this.cycleActiveSelection(-1); this.lastInputTime = now; } - else if (isPressed(5)) { this.cycleActiveSelection(1); this.lastInputTime = now; } + else if (isPressed(4)) { UiSoundManager.setInputSource('controller'); this.cycleActiveSelection(-1); this.lastInputTime = now; } + else if (isPressed(5)) { UiSoundManager.setInputSource('controller'); this.cycleActiveSelection(1); this.lastInputTime = now; } - else if (isPressed(1)) { this.cancelCurrent(); this.lastInputTime = now; } + else if (isPressed(1)) { UiSoundManager.setInputSource('controller'); this.cancelCurrent(); this.lastInputTime = now; } - else if (isPressed(2)) { checkForUpdatesManual(); this.lastInputTime = now; } + else if (isPressed(2)) { UiSoundManager.setInputSource('controller'); checkForUpdatesManual(); this.lastInputTime = now; } } const aPressed = isPressed(0); if (aPressed && !this.lastAPressed) { + UiSoundManager.setInputSource('controller'); this.clickActive(); } this.lastAPressed = aPressed; @@ -218,7 +223,24 @@ const GamepadManager = { if (active && active.classList.contains('nav-item')) { active.classList.add('active-bump'); setTimeout(() => active.classList.remove('active-bump'), 100); - + + if (active.id === 'version-select-box') { + this.cycleActiveSelection(1); + return; + } + if (active.id === 'classic-version-select-box') { + const classicSelect = document.getElementById('classic-version-select'); + if (classicSelect) { + classicSelect.selectedIndex = (classicSelect.selectedIndex + 1) % classicSelect.options.length; + syncVersionFromClassic(); + } + return; + } + if (active.id === 'compat-select-box') { + this.cycleActiveSelection(1); + return; + } + if (active.tagName === 'INPUT' && active.type === 'checkbox') { active.checked = !active.checked; active.dispatchEvent(new Event('change')); @@ -313,6 +335,15 @@ const UiSoundManager = { lastPlayedAt: {}, cooldownMs: 70, lastHoverItem: null, + inputSource: 'mouse', + + setInputSource(source) { + this.inputSource = source; + }, + + shouldPlay() { + return this.inputSource === 'controller'; + }, init() { Object.entries(this.files).forEach(([key, file]) => { @@ -321,6 +352,11 @@ const UiSoundManager = { this.cache[key].volume = key === 'cursor' ? 0.45 : 0.6; }); + const markMouseInput = () => this.setInputSource('mouse'); + ['mousemove', 'mousedown', 'touchstart', 'wheel', 'keydown'].forEach((ev) => { + document.addEventListener(ev, markMouseInput, { passive: true }); + }); + document.addEventListener('focusin', (e) => { if (e.target?.classList?.contains('nav-item')) this.play('cursor'); }); @@ -349,6 +385,7 @@ const UiSoundManager = { }, play(name) { + if (!this.shouldPlay()) return; const now = Date.now(); if (this.lastPlayedAt[name] && now - this.lastPlayedAt[name] < this.cooldownMs) return; this.lastPlayedAt[name] = now; @@ -534,6 +571,24 @@ function focusPrimaryPlayButton() { setTimeout(() => target.classList.remove('controller-active'), 180); } +function syncRepoPresetFromInput() { + const presetSelect = document.getElementById('repo-preset-select'); + const repoInput = document.getElementById('repo-input'); + if (!presetSelect || !repoInput) return; + + if (repoInput.value.trim() === REPO_PRESETS.default) presetSelect.value = REPO_PRESETS.default; + else if (repoInput.value.trim() === REPO_PRESETS.noWatermark) presetSelect.value = REPO_PRESETS.noWatermark; + else presetSelect.value = 'custom'; +} + +function applyRepoPreset() { + const presetSelect = document.getElementById('repo-preset-select'); + const repoInput = document.getElementById('repo-input'); + if (!presetSelect || !repoInput) return; + if (presetSelect.value === 'custom') return; + repoInput.value = presetSelect.value; +} + window.onload = async () => { try { await migrateLegacyConfig(); @@ -546,13 +601,17 @@ window.onload = async () => { const serverCheck = document.getElementById('server-checkbox'); const installInput = document.getElementById('install-path-input'); - if (repoInput) repoInput.value = currentInstance.repo; + if (repoInput) { + repoInput.value = currentInstance.repo; + repoInput.addEventListener('input', syncRepoPresetFromInput); + } if (execInput) execInput.value = currentInstance.execPath; if (usernameInput) usernameInput.value = await Store.get('legacy_username', ""); if (ipInput) ipInput.value = currentInstance.ip; if (portInput) portInput.value = currentInstance.port; if (serverCheck) serverCheck.checked = currentInstance.isServer; if (installInput) installInput.value = currentInstance.installPath; + syncRepoPresetFromInput(); if (process.platform === 'linux' || process.platform === 'darwin') { const compatContainer = document.getElementById('compat-option-container'); @@ -572,6 +631,7 @@ window.onload = async () => { // Initialize features await loadTheme(); + await loadSteamDeckMode(); fetchGitHubData(); checkForLauncherUpdates(); loadSplashText(); @@ -731,6 +791,7 @@ async function switchInstance(id) { await saveInstancesToStore(); document.getElementById('repo-input').value = currentInstance.repo; + syncRepoPresetFromInput(); document.getElementById('exec-input').value = currentInstance.execPath; document.getElementById('ip-input').value = currentInstance.ip; document.getElementById('port-input').value = currentInstance.port; @@ -1250,6 +1311,9 @@ function toggleOptions(show) { // Sync classic theme checkbox to current state const cb = document.getElementById('classic-theme-checkbox'); if (cb) cb.checked = document.body.classList.contains('classic-theme'); + const steamDeckCb = document.getElementById('steamdeck-mode-checkbox'); + if (steamDeckCb) steamDeckCb.checked = document.body.classList.contains('steamdeck-mode'); + syncRepoPresetFromInput(); document.activeElement?.blur(); modal.style.display = 'flex'; modal.style.opacity = '1'; UiSoundManager.play('popupOpen'); } @@ -1364,8 +1428,11 @@ async function saveOptions() { currentInstance.customCompatPath = customProtonPath; } const isClassic = document.getElementById('classic-theme-checkbox')?.checked || false; + const isSteamDeckMode = document.getElementById('steamdeck-mode-checkbox')?.checked || false; await Store.set('legacy_classic_theme', isClassic); + await Store.set('legacy_steamdeck_mode', isSteamDeckMode); applyTheme(isClassic); + applySteamDeckMode(isSteamDeckMode); await saveInstancesToStore(); toggleOptions(false); fetchGitHubData(); updatePlayButtonText(); showToast("Settings Saved"); } @@ -1596,6 +1663,19 @@ async function loadTheme() { applyTheme(isClassic); } +async function loadSteamDeckMode() { + const autoSteamDeck = isSteamDeckEnvironment(); + const saved = await Store.get('legacy_steamdeck_mode', null); + const enabled = saved === null ? autoSteamDeck : saved; + const cb = document.getElementById('steamdeck-mode-checkbox'); + if (cb) cb.checked = enabled; + applySteamDeckMode(enabled); +} + +function applySteamDeckMode(enabled) { + document.body.classList.toggle('steamdeck-mode', !!enabled); +} + function applyTheme(isClassic) { document.body.classList.toggle('classic-theme', isClassic); if (isClassic) { @@ -1806,6 +1886,7 @@ window.checkForUpdatesManual = checkForUpdatesManual; window.browseInstallDir = browseInstallDir; window.openGameDir = openGameDir; window.toggleMusic = toggleMusic; +window.applyRepoPreset = applyRepoPreset; window.getInstallDir = getInstallDir; window.showToast = showToast; window.toggleInstances = toggleInstances; diff --git a/skin_manager.js b/skin_manager.js index 97b1ddf..031a496 100644 --- a/skin_manager.js +++ b/skin_manager.js @@ -19,6 +19,13 @@ document.addEventListener('DOMContentLoaded', () => { if (skinInput) skinInput.addEventListener('change', (e) => handleSkinFile(e.target.files[0])); if (dropZone) { + dropZone.addEventListener('click', () => skinInput?.click()); + dropZone.addEventListener('keydown', (e) => { + if (e.key === 'Enter' || e.key === ' ') { + e.preventDefault(); + skinInput?.click(); + } + }); dropZone.addEventListener('dragover', (e) => { e.preventDefault(); dropZone.classList.add('border-green-500'); diff --git a/style.css b/style.css index 4f073df..9901299 100644 --- a/style.css +++ b/style.css @@ -94,6 +94,15 @@ body { background: #c42b1c; } + +.win-btn.nav-item:focus { + transform: scale(1.08); + z-index: 1001; + box-shadow: 0 0 0 1px rgba(255,255,255,0.95), 0 0 8px rgba(255,255,255,0.55) !important; + background: #444; + color: #fff; +} + .main-wrapper { display: flex; flex-grow: 1; @@ -364,6 +373,11 @@ body { filter: brightness(1.08); } +.nav-item:hover { + outline: 1px solid rgba(255,255,255,0.92) !important; + box-shadow: 0 0 0 1px rgba(255,255,255,0.85), 0 0 12px rgba(255, 255, 255, 0.52), 0 0 24px rgba(90, 170, 255, 0.22) !important; +} + .nav-item.active-bump { transform: scale(0.95) !important; transition: transform 0.1s !important; @@ -402,6 +416,46 @@ body { text-shadow: 2px 2px 0 #000; } +/* Steam Deck optimized mode */ +body.steamdeck-mode .title-bar { + height: 40px; +} + +body.steamdeck-mode .title-bar-text { + font-size: 18px; +} + +body.steamdeck-mode .btn-mc { + min-height: 68px; + font-size: 28px; +} + +body.steamdeck-mode .btn-play { + min-height: 110px; + font-size: 52px; +} + +body.steamdeck-mode .version-select-box { + height: 64px; + font-size: 26px; +} + +body.steamdeck-mode .mc-input, +body.steamdeck-mode #repo-preset-select, +body.steamdeck-mode .mc-label, +body.steamdeck-mode .classic-link { + font-size: 20px !important; +} + +body.steamdeck-mode .nav-item:focus { + transform: scale(1.06); + box-shadow: 0 0 0 2px rgba(255,255,255,0.95), 0 0 22px rgba(255,255,255,0.7), 0 0 34px rgba(90,170,255,0.36) !important; +} + +body.steamdeck-mode .sidebar { + width: 420px; +} + .version-row { display: flex; width: 500px;