Merge pull request #121 from dtentiion/main

Fix UI overflow, add classic MC launcher UI, text truncation
This commit is contained in:
gardenGnostic 2026-03-10 10:29:56 +01:00 committed by GitHub
commit 8f1aec38be
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 479 additions and 42 deletions

View file

@ -42,7 +42,15 @@
</div>
<div class="content-area" style="flex-direction: row; align-items: stretch; padding: 0;">
<!-- Classic Mode: Logo + Splash (only visible in classic theme) -->
<div class="classic-logo-area" id="classic-logo-area">
<div style="position: relative;">
<img src="minecraftlogo.png" class="mc-logo-img" alt="Minecraft Logo" style="margin-bottom: 0; margin-top: 0;">
<div id="classic-splash-text" class="splash-text">Splash!</div>
</div>
</div>
<!-- Left Side: Main Menu -->
<div class="menu-column" style="flex: 2; display: flex; flex-direction: column; align-items: center; justify-content: center; position: relative; z-index: 5;">
<div class="relative">
@ -239,6 +247,13 @@
</label>
</div>
<div class="mc-input-group">
<label class="mc-label" style="display: flex; align-items: center; cursor: pointer;">
<input type="checkbox" id="classic-theme-checkbox" class="nav-item" style="width: 24px; height: 24px; margin-right: 12px; cursor: pointer;" tabindex="0">
Use Classic Minecraft Launcher UI
</label>
</div>
<div class="flex gap-4 w-full mt-4">
<div id="btn-options-done" class="btn-mc flex-grow nav-item" onclick="saveOptions()" tabindex="0">DONE</div>
<div id="btn-options-cancel" class="btn-mc flex-grow nav-item" onclick="toggleOptions(false)" tabindex="0">CANCEL</div>
@ -330,6 +345,47 @@
</div>
</div>
<!-- Classic Launcher Bottom Bar (only shown when classic theme is active) -->
<div id="classic-bottom-bar" class="classic-bottom-bar">
<!-- Left: Profile Section -->
<div class="classic-profile-section">
<div class="classic-avatar" id="classic-avatar">S</div>
<div class="classic-profile-info">
<div class="classic-username-label">Logged in as</div>
<div class="classic-username-display" id="classic-username-display">Player</div>
</div>
<div class="classic-mini-btn" onclick="toggleProfile(true)" title="Edit Profile">Edit Profile</div>
<div class="classic-mini-btn" onclick="openSkinManager()" title="Change Skin">Skin</div>
</div>
<!-- Center: Play Button -->
<div class="classic-center-section">
<div class="btn-mc btn-play classic-play-btn nav-item" id="classic-btn-play" onclick="launchGame()" tabindex="0">PLAY</div>
</div>
<!-- Right: Version + Nav -->
<div class="classic-right-section">
<div class="classic-version-row">
<span class="version-label" style="font-size: 16px; white-space: nowrap;">Version:</span>
<div id="classic-version-select-box" class="version-select-box nav-item" tabindex="0" style="height: 40px; font-size: 16px; flex-grow: 1; padding-right: 51px;">
<span id="classic-version-display">Loading...</span>
<div class="select-arrow" style="width: 36px;"></div>
<select id="classic-version-select" class="hidden-select" onchange="syncVersionFromClassic()">
<option>Loading...</option>
</select>
</div>
<div class="btn-mc btn-mini nav-item" onclick="checkForUpdatesManual()" title="Check for Updates" tabindex="0" style="width: 40px !important; height: 40px; max-width: 40px !important;">
<img src="restart.png" alt="Update">
</div>
</div>
<div class="classic-nav-links">
<span class="classic-link nav-item" onclick="toggleInstances(true)" tabindex="0">Instances</span>
<span class="classic-link nav-item" onclick="toggleServers(true)" tabindex="0">Servers</span>
<span class="classic-link nav-item" onclick="toggleOptions(true)" tabindex="0">Options</span>
</div>
</div>
</div>
<div id="toast">NOTIFICATION</div>
<div id="music-toggle" class="music-btn nav-item" onclick="toggleMusic()" title="Toggle Music" tabindex="0">

4
package-lock.json generated
View file

@ -1,12 +1,12 @@
{
"name": "legacylauncher",
"version": "2.2.0",
"version": "3.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "legacylauncher",
"version": "2.2.0",
"version": "3.0.0",
"license": "ISC",
"dependencies": {
"electron-store": "^6.0.1",

View file

@ -479,6 +479,7 @@ window.onload = async () => {
});
// Initialize features
await loadTheme();
fetchGitHubData();
checkForLauncherUpdates();
loadSplashText();
@ -684,45 +685,42 @@ async function checkIsInstalled(tag) {
async function updatePlayButtonText() {
const btn = document.getElementById('btn-play-main');
const classicBtn = document.getElementById('classic-btn-play');
if (!btn || isProcessing) return;
let label, disabled, running;
if (isGameRunning) {
btn.textContent = "GAME RUNNING";
btn.classList.add('running');
return;
label = "GAME RUNNING"; running = true; disabled = false;
} else {
btn.classList.remove('running');
}
// Offline / No Data Case
if (releasesData.length === 0) {
const fullPath = await getInstalledPath();
if (currentInstance.installedTag && fs.existsSync(fullPath)) {
btn.textContent = "PLAY";
btn.classList.remove('disabled');
running = false;
if (releasesData.length === 0) {
const fullPath = await getInstalledPath();
if (currentInstance.installedTag && fs.existsSync(fullPath)) {
label = "PLAY"; disabled = false;
} else {
label = "OFFLINE"; disabled = true;
}
} else {
btn.textContent = "OFFLINE";
btn.classList.add('disabled');
}
return;
}
const release = releasesData[currentReleaseIndex];
if (!release) {
btn.textContent = "PLAY";
return;
}
if (await checkIsInstalled(release.tag_name)) {
btn.textContent = "PLAY";
} else {
const fullPath = await getInstalledPath();
if (fs.existsSync(fullPath)) {
btn.textContent = "UPDATE";
} else {
btn.textContent = "INSTALL";
const release = releasesData[currentReleaseIndex];
if (!release) {
label = "PLAY"; disabled = false;
} else if (await checkIsInstalled(release.tag_name)) {
label = "PLAY"; disabled = false;
} else {
const fullPath = await getInstalledPath();
label = fs.existsSync(fullPath) ? "UPDATE" : "INSTALL";
disabled = false;
}
}
}
[btn, classicBtn].forEach(b => {
if (!b) return;
b.textContent = label;
b.classList.toggle('running', running);
if (disabled) b.classList.add('disabled'); else b.classList.remove('disabled');
});
}
function setGameRunning(running) {
@ -850,6 +848,7 @@ function populateVersions() {
if(index === 0 && display) display.textContent = opt.textContent;
});
currentReleaseIndex = 0;
syncClassicVersionSelect();
updatePlayButtonText();
}
@ -885,6 +884,7 @@ function updateSelectedRelease() {
if (!select) return;
currentReleaseIndex = select.value;
document.getElementById('current-version-display').textContent = select.options[select.selectedIndex].text;
syncClassicVersionSelect();
updatePlayButtonText();
}
@ -1036,15 +1036,18 @@ async function launchLocalClient() {
function setProcessingState(active) {
isProcessing = active;
const playBtn = document.getElementById('btn-play-main');
const classicPlayBtn = document.getElementById('classic-btn-play');
const optionsBtn = document.getElementById('btn-options');
const progressContainer = document.getElementById('progress-container');
if (active) {
if (playBtn) playBtn.classList.add('disabled');
if (classicPlayBtn) classicPlayBtn.classList.add('disabled');
if (optionsBtn) optionsBtn.classList.add('disabled');
if (progressContainer) progressContainer.style.display = 'flex';
updateProgress(0, "Preparing...");
} else {
if (playBtn) playBtn.classList.remove('disabled');
if (classicPlayBtn) classicPlayBtn.classList.remove('disabled');
if (optionsBtn) optionsBtn.classList.remove('disabled');
if (progressContainer) progressContainer.style.display = 'none';
}
@ -1135,7 +1138,12 @@ function downloadFile(url, destPath) {
function toggleOptions(show) {
if (isProcessing) return;
const modal = document.getElementById('options-modal');
if (show) { document.activeElement?.blur(); modal.style.display = 'flex'; modal.style.opacity = '1'; }
if (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');
document.activeElement?.blur(); modal.style.display = 'flex'; modal.style.opacity = '1';
}
else { modal.style.opacity = '0'; setTimeout(() => modal.style.display = 'none', 300); }
}
@ -1246,6 +1254,9 @@ async function saveOptions() {
currentInstance.compatLayer = compatSelect.value;
currentInstance.customCompatPath = customProtonPath;
}
const isClassic = document.getElementById('classic-theme-checkbox')?.checked || false;
await Store.set('legacy_classic_theme', isClassic);
applyTheme(isClassic);
await saveInstancesToStore(); toggleOptions(false); fetchGitHubData(); updatePlayButtonText(); showToast("Settings Saved");
}
@ -1255,6 +1266,7 @@ async function saveProfile() {
username = username.substring(0, 16);
}
await Store.set('legacy_username', username);
updateClassicUsername();
toggleProfile(false); showToast("Profile Updated");
}
@ -1298,10 +1310,23 @@ function updateCompatDisplay() {
}
function toggleSidebar() {
const sidebar = document.querySelector('.sidebar'); const toggleIcon = document.getElementById('sidebar-toggle-icon');
sidebar.classList.toggle('collapsed');
if (sidebar.classList.contains('collapsed')) { toggleIcon.textContent = '▶'; toggleIcon.title = 'Expand Patch Notes'; }
else { toggleIcon.textContent = '◀'; toggleIcon.title = 'Collapse Patch Notes'; }
const sidebar = document.querySelector('.sidebar');
const toggleIcon = document.getElementById('sidebar-toggle-icon');
const list = document.getElementById('updates-list');
if (sidebar.classList.contains('collapsed')) {
list.style.display = 'flex';
requestAnimationFrame(() => {
sidebar.classList.remove('collapsed');
toggleIcon.textContent = '◀';
toggleIcon.title = 'Collapse Patch Notes';
});
} else {
list.style.display = '';
sidebar.classList.add('collapsed');
toggleIcon.textContent = '▶';
toggleIcon.title = 'Expand Patch Notes';
}
}
function isNewerVersion(latest, current) {
@ -1383,6 +1408,61 @@ async function loadSplashText() {
console.error("Failed to load splash text:", e);
splashEl.textContent = "Welcome!";
}
// Also sync classic splash text
const classicSplash = document.getElementById('classic-splash-text');
if (classicSplash && splashEl) classicSplash.textContent = splashEl.textContent;
}
// ============================================================
// CLASSIC LAUNCHER THEME FUNCTIONS
// ============================================================
async function loadTheme() {
const isClassic = await Store.get('legacy_classic_theme', false);
const cb = document.getElementById('classic-theme-checkbox');
if (cb) cb.checked = isClassic;
applyTheme(isClassic);
}
function applyTheme(isClassic) {
document.body.classList.toggle('classic-theme', isClassic);
if (isClassic) {
syncClassicVersionSelect();
updateClassicUsername();
}
}
async function updateClassicUsername() {
const username = await Store.get('legacy_username', "Player");
const display = document.getElementById('classic-username-display');
const avatar = document.getElementById('classic-avatar');
if (display) display.textContent = username || "Player";
if (avatar) avatar.textContent = (username || "P")[0].toUpperCase();
}
function syncClassicVersionSelect() {
const mainSelect = document.getElementById('version-select');
const classicSelect = document.getElementById('classic-version-select');
const classicDisplay = document.getElementById('classic-version-display');
if (!mainSelect || !classicSelect) return;
// Copy options from main to classic
classicSelect.innerHTML = mainSelect.innerHTML;
classicSelect.selectedIndex = mainSelect.selectedIndex;
if (classicDisplay && classicSelect.selectedIndex >= 0) {
classicDisplay.textContent = classicSelect.options[classicSelect.selectedIndex]?.text || "Loading...";
}
}
function syncVersionFromClassic() {
const classicSelect = document.getElementById('classic-version-select');
const classicDisplay = document.getElementById('classic-version-display');
const mainSelect = document.getElementById('version-select');
if (!classicSelect || !mainSelect) return;
mainSelect.selectedIndex = classicSelect.selectedIndex;
if (classicDisplay && classicSelect.selectedIndex >= 0) {
classicDisplay.textContent = classicSelect.options[classicSelect.selectedIndex]?.text || "";
}
updateSelectedRelease();
}
async function toggleSnapshots(show, id = null) {
@ -1565,6 +1645,7 @@ window.rollbackToSnapshot = rollbackToSnapshot;
window.deleteSnapshot = deleteSnapshot;
window.createSnapshotManual = createSnapshotManual;
window.toggleSnapshots = toggleSnapshots;
window.syncVersionFromClassic = syncVersionFromClassic;
// Desktop shortcut for Linux AppImage
function ensureDesktopShortcut() {
if (typeof process === 'undefined' || process.platform !== 'linux') return;

304
style.css
View file

@ -233,6 +233,9 @@ body {
line-height: 1.6;
white-space: pre-wrap;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
overflow-wrap: break-word;
word-break: break-word;
overflow: hidden;
}
.pn-body li {
@ -420,21 +423,30 @@ body {
border: 2px solid #555;
display: flex;
align-items: center;
padding: 0 15px 6px 15px;
padding: 0 63px 6px 15px;
color: white;
font-size: 24px;
cursor: pointer;
position: relative;
transition: border-color 0.2s;
overflow: hidden;
}
.version-select-box:hover {
border-color: #fff;
}
#current-version-display,
#classic-version-display {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
flex: 1;
min-width: 0;
}
.select-arrow {
width: 48px;
height: 52px;
background: #6e6e6e;
border-left: 2px solid #555;
display: flex;
@ -443,6 +455,8 @@ body {
color: white;
position: absolute;
right: 0;
top: 0;
bottom: 0;
}
.progress-container {
@ -724,3 +738,289 @@ select.hidden-select {
::-webkit-scrollbar-thumb:hover {
background: #7e7e7e;
}
/* ============================================================
CLASSIC MINECRAFT LAUNCHER THEME
Applied when <body class="classic-theme"> is set
============================================================ */
/* --- Classic Bottom Bar (hidden by default) --- */
.classic-bottom-bar {
display: none;
height: 82px;
min-height: 82px;
background: linear-gradient(to bottom, #1a1a1a 0%, #0d0d0d 100%);
border-top: 3px solid #000;
box-shadow: inset 0 2px 0 rgba(255,255,255,0.07);
align-items: center;
padding: 0 16px;
gap: 16px;
z-index: 200;
flex-shrink: 0;
}
/* Classic Logo Area (hidden by default, shown in classic mode) */
.classic-logo-area {
display: none;
align-items: center;
justify-content: center;
padding-top: 30px;
pointer-events: none;
}
/* ---- Show/hide elements in classic mode ---- */
body.classic-theme .classic-bottom-bar {
display: flex;
}
body.classic-theme .classic-logo-area {
display: flex;
position: absolute;
top: 0;
left: 0;
right: 0;
pointer-events: none;
z-index: 3;
justify-content: center;
padding-top: 18px;
}
body.classic-theme .classic-logo-area .mc-logo-img {
width: 480px;
margin-top: 0;
margin-bottom: 0;
filter: drop-shadow(4px 4px 12px rgba(0,0,0,0.9));
}
body.classic-theme .classic-logo-area .splash-text {
top: 60%;
left: 88%;
font-size: 17px;
}
/* ---- Classic mode layout restructure ---- */
body.classic-theme {
flex-direction: column;
}
body.classic-theme .main-wrapper {
flex: 1;
min-height: 0;
}
/* Force sidebar to always be expanded in classic mode */
body.classic-theme .sidebar {
width: 320px !important;
padding: 20px 18px !important;
background: rgba(0, 0, 0, 0.82) !important;
border-right: 3px solid #000 !important;
backdrop-filter: blur(10px) !important;
}
body.classic-theme .sidebar.collapsed {
width: 320px !important;
padding: 20px 18px !important;
}
body.classic-theme .sidebar.collapsed #updates-list {
display: flex !important;
}
body.classic-theme .sidebar.collapsed .sidebar-title {
border-bottom: 2px solid #555 !important;
margin-bottom: 20px !important;
justify-content: space-between !important;
padding-bottom: 12px !important;
}
body.classic-theme .sidebar.collapsed #sidebar-title-text {
display: block !important;
}
body.classic-theme .sidebar.collapsed #sidebar-toggle-icon {
font-size: 24px !important;
}
body.classic-theme .sidebar-title {
font-size: 24px;
color: #aaa;
text-shadow: 1px 1px 0 #000;
letter-spacing: 2px;
}
body.classic-theme #sidebar-title-text::before {
content: "NEWS — ";
color: #55ff55;
font-size: 14px;
letter-spacing: 3px;
}
/* Hide center menu column in classic mode */
body.classic-theme .menu-column {
display: none !important;
}
/* Hide skin column in classic mode */
body.classic-theme .skin-column {
display: none !important;
}
/* Content area in classic: full panorama, no center column */
body.classic-theme .content-area {
position: relative;
align-items: center;
justify-content: center;
}
/* Keep progress bar visible in classic mode */
body.classic-theme .progress-container {
z-index: 100;
}
/* ---- Classic Bottom Bar Layout ---- */
.classic-profile-section {
display: flex;
align-items: center;
gap: 10px;
min-width: 0;
flex: 0 0 auto;
max-width: 380px;
}
.classic-avatar {
width: 48px;
height: 48px;
background: #4CAF50;
border: 3px solid #000;
box-shadow: inset -2px -2px 0 #2a6b2a, inset 2px 2px 0 #7ecf7e;
display: flex;
align-items: center;
justify-content: center;
font-size: 22px;
color: #fff;
font-family: 'Minecraft', monospace;
text-shadow: 2px 2px 0 #000;
flex-shrink: 0;
image-rendering: pixelated;
}
.classic-profile-info {
display: flex;
flex-direction: column;
justify-content: center;
overflow: hidden;
flex: 1 1 0;
min-width: 0;
}
.classic-username-label {
font-size: 11px;
color: #666;
letter-spacing: 1px;
white-space: nowrap;
text-transform: uppercase;
}
.classic-username-display {
font-size: 18px;
color: #eee;
text-shadow: 1px 1px 0 #000;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 100%;
}
.classic-mini-btn {
background: #3a3a3a;
border: 2px solid #000;
color: #ccc;
font-size: 13px;
padding: 4px 10px 6px;
cursor: pointer;
font-family: 'Minecraft', monospace;
box-shadow: inset -2px -2px 0 #222, inset 2px 2px 0 #555;
white-space: nowrap;
flex-shrink: 0;
}
.classic-mini-btn:hover {
background: #4a4a4a;
color: #fff;
outline: 1px solid #fff;
}
/* Center play section */
.classic-center-section {
display: flex;
align-items: center;
justify-content: center;
flex: 1;
}
.classic-play-btn {
width: 260px !important;
height: 58px !important;
font-size: 30px !important;
margin-bottom: 0 !important;
}
/* Right section: version + nav links */
.classic-right-section {
display: flex;
flex-direction: column;
align-items: flex-end;
justify-content: center;
gap: 6px;
flex: 0 0 auto;
max-width: 320px;
}
.classic-version-row {
display: flex;
align-items: center;
gap: 6px;
width: 100%;
}
.classic-nav-links {
display: flex;
gap: 14px;
align-items: center;
justify-content: flex-end;
}
.classic-link {
color: #888;
font-size: 14px;
cursor: pointer;
letter-spacing: 1px;
text-transform: uppercase;
transition: color 0.15s;
padding: 2px 4px;
}
.classic-link:hover {
color: #fff;
text-shadow: 0 0 6px rgba(255,255,255,0.4);
}
.classic-link:focus {
color: #55ff55;
outline: none;
}
/* hide the toggle arrow and disable the click in classic mode */
body.classic-theme #sidebar-toggle-icon {
display: none;
}
body.classic-theme .sidebar-title {
cursor: default;
pointer-events: none;
}
/* ---- Classic mode music button position ---- */
body.classic-theme .music-btn {
bottom: 92px;
}