diff --git a/index.html b/index.html
index e8453dc..2b4f8b5 100644
--- a/index.html
+++ b/index.html
@@ -42,7 +42,15 @@
-
+
+
+
+
+

+
Splash!
+
+
+
@@ -239,6 +247,13 @@
+
+
+
+
DONE
CANCEL
@@ -330,6 +345,47 @@
+
+
+
+
+
S
+
+
Logged in as
+
Player
+
+
Edit Profile
+
Skin
+
+
+
+
+
+
+
+
+
Version:
+
+
Loading...
+
▼
+
+
+
+

+
+
+
+ Instances
+ Servers
+ Options
+
+
+
+
NOTIFICATION
diff --git a/package-lock.json b/package-lock.json
index 6d735f3..23a5cd5 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -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",
diff --git a/renderer.js b/renderer.js
index 53a08fa..a1b6866 100644
--- a/renderer.js
+++ b/renderer.js
@@ -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;
diff --git a/style.css b/style.css
index ee67369..15ec3ce 100644
--- a/style.css
+++ b/style.css
@@ -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 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;
+}