mirror of
https://github.com/knutwurst/patchdl.git
synced 2026-10-06 05:00:22 +02:00
Switch web UI to dark English interface
This commit is contained in:
1 parent
56f54fc1a0
commit
64bce0a3b5
4 files changed
+117
-116
No files matched your search
@@ -13,7 +13,7 @@ static const char status_json[] =
|
|||||||
"{"
|
"{"
|
||||||
"\"firmware\":\"11.60\","
|
"\"firmware\":\"11.60\","
|
||||||
"\"firmware_build\":\"0x11600000\","
|
"\"firmware_build\":\"0x11600000\","
|
||||||
"\"dns_guard\":\"Aktiv\","
|
"\"dns_guard\":\"Active\","
|
||||||
"\"resolver\":\"Internal allowlist\","
|
"\"resolver\":\"Internal allowlist\","
|
||||||
"\"free_space_mb\":64218,"
|
"\"free_space_mb\":64218,"
|
||||||
"\"download_dir\":\"/mnt/usb0/patches\""
|
"\"download_dir\":\"/mnt/usb0/patches\""
|
||||||
|
|||||||
+43
-43
@@ -11,13 +11,13 @@ const SOURCE_TYPES = {
|
|||||||
label: "Official",
|
label: "Official",
|
||||||
className: "ok",
|
className: "ok",
|
||||||
installAllowed: true,
|
installAllowed: true,
|
||||||
description: "Echte Installation",
|
description: "Native console installation",
|
||||||
},
|
},
|
||||||
external: {
|
external: {
|
||||||
label: "External",
|
label: "External",
|
||||||
className: "external",
|
className: "external",
|
||||||
installAllowed: true,
|
installAllowed: true,
|
||||||
description: "Echte externe Installation",
|
description: "Real external installation",
|
||||||
},
|
},
|
||||||
shadowmount: {
|
shadowmount: {
|
||||||
label: "Shadowmount",
|
label: "Shadowmount",
|
||||||
@@ -29,7 +29,7 @@ const SOURCE_TYPES = {
|
|||||||
label: "Unknown",
|
label: "Unknown",
|
||||||
className: "blocked",
|
className: "blocked",
|
||||||
installAllowed: false,
|
installAllowed: false,
|
||||||
description: "Blockiert",
|
description: "Blocked",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -37,7 +37,7 @@ const fallback = {
|
|||||||
status: {
|
status: {
|
||||||
firmware: "11.60",
|
firmware: "11.60",
|
||||||
firmware_build: "0x11600000",
|
firmware_build: "0x11600000",
|
||||||
dns_guard: "Aktiv",
|
dns_guard: "Active",
|
||||||
resolver: "Internal allowlist",
|
resolver: "Internal allowlist",
|
||||||
free_space_mb: 64218,
|
free_space_mb: 64218,
|
||||||
download_dir: "/mnt/usb0/patches",
|
download_dir: "/mnt/usb0/patches",
|
||||||
@@ -132,7 +132,7 @@ const fallback = {
|
|||||||
name: "Demon's Souls",
|
name: "Demon's Souls",
|
||||||
version: "01.004.000",
|
version: "01.004.000",
|
||||||
progress: 64,
|
progress: 64,
|
||||||
detail: "4.8 GB von 7.5 GB",
|
detail: "4.8 GB of 7.5 GB",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
logs: [
|
logs: [
|
||||||
@@ -204,7 +204,7 @@ function bindEvents() {
|
|||||||
|
|
||||||
els.refreshBtn.addEventListener("click", loadInitialData);
|
els.refreshBtn.addEventListener("click", loadInitialData);
|
||||||
els.saveBtn.addEventListener("click", saveConfig);
|
els.saveBtn.addEventListener("click", saveConfig);
|
||||||
els.pauseAllBtn.addEventListener("click", () => showToast("Queue wurde pausiert."));
|
els.pauseAllBtn.addEventListener("click", () => showToast("Queue paused."));
|
||||||
}
|
}
|
||||||
|
|
||||||
async function loadInitialData() {
|
async function loadInitialData() {
|
||||||
@@ -224,7 +224,7 @@ async function loadInitialData() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
render();
|
render();
|
||||||
showToast(state.usingFallback ? "Demo-Daten geladen. API noch nicht erreichbar." : "Daten aktualisiert.");
|
showToast(state.usingFallback ? "Demo data loaded. API is not reachable yet." : "Data refreshed.");
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getJson(url, fallbackValue) {
|
async function getJson(url, fallbackValue) {
|
||||||
@@ -252,7 +252,7 @@ function renderStatus() {
|
|||||||
els.dnsValue.textContent = state.status.dns_guard || "--";
|
els.dnsValue.textContent = state.status.dns_guard || "--";
|
||||||
els.resolverValue.textContent = state.status.resolver || "--";
|
els.resolverValue.textContent = state.status.resolver || "--";
|
||||||
els.spaceValue.textContent = formatMb(state.status.free_space_mb);
|
els.spaceValue.textContent = formatMb(state.status.free_space_mb);
|
||||||
els.downloadDirValue.textContent = state.status.download_dir || state.config.download_dir || "Download Ziel";
|
els.downloadDirValue.textContent = state.status.download_dir || state.config.download_dir || "Download target";
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderSettings() {
|
function renderSettings() {
|
||||||
@@ -276,7 +276,7 @@ function renderGames() {
|
|||||||
if (!visible.length) {
|
if (!visible.length) {
|
||||||
const empty = document.createElement("div");
|
const empty = document.createElement("div");
|
||||||
empty.className = "empty-state";
|
empty.className = "empty-state";
|
||||||
empty.textContent = "Keine Titel fuer diesen Filter.";
|
empty.textContent = "No titles match this filter.";
|
||||||
els.gameGrid.appendChild(empty);
|
els.gameGrid.appendChild(empty);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -319,8 +319,8 @@ function createGameCard(game) {
|
|||||||
<div class="subline" style="margin-top:8px">
|
<div class="subline" style="margin-top:8px">
|
||||||
${statusPill(game)}
|
${statusPill(game)}
|
||||||
${sourcePill(game)}
|
${sourcePill(game)}
|
||||||
${installBlocked ? `<span class="pill blocked">Install gesperrt</span>` : `<span class="pill ok">Install erlaubt</span>`}
|
${installBlocked ? `<span class="pill blocked">Install blocked</span>` : `<span class="pill ok">Install allowed</span>`}
|
||||||
<span class="pill">${game.enabled ? "Aktiv" : "Aus"}</span>
|
<span class="pill">${game.enabled ? "Enabled" : "Off"}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="source-path">${escapeHtml(sourceDetail(game))}</div>
|
<div class="source-path">${escapeHtml(sourceDetail(game))}</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -329,9 +329,9 @@ function createGameCard(game) {
|
|||||||
const versions = document.createElement("div");
|
const versions = document.createElement("div");
|
||||||
versions.className = "version-grid";
|
versions.className = "version-grid";
|
||||||
versions.innerHTML = `
|
versions.innerHTML = `
|
||||||
${versionBox("Installiert", game.installed_version || "--")}
|
${versionBox("Installed", game.installed_version || "--")}
|
||||||
${versionBox("Kompatibel", game.compatible_version || "Keine")}
|
${versionBox("Compatible", game.compatible_version || "None")}
|
||||||
${versionBox("Neueste", `${game.latest_version || "--"} / FW ${game.latest_required_fw || "--"}`)}
|
${versionBox("Latest", `${game.latest_version || "--"} / FW ${game.latest_required_fw || "--"}`)}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const controls = document.createElement("div");
|
const controls = document.createElement("div");
|
||||||
@@ -341,7 +341,7 @@ function createGameCard(game) {
|
|||||||
controlRow.className = "control-row";
|
controlRow.className = "control-row";
|
||||||
|
|
||||||
const mode = document.createElement("select");
|
const mode = document.createElement("select");
|
||||||
mode.title = "Update-Modus";
|
mode.title = "Update mode";
|
||||||
[
|
[
|
||||||
["disabled", "Disabled"],
|
["disabled", "Disabled"],
|
||||||
["download_only", "Download only"],
|
["download_only", "Download only"],
|
||||||
@@ -358,7 +358,7 @@ function createGameCard(game) {
|
|||||||
mode.addEventListener("change", () => updateGame(game.title_id, { mode: mode.value, enabled: mode.value !== "disabled" }));
|
mode.addEventListener("change", () => updateGame(game.title_id, { mode: mode.value, enabled: mode.value !== "disabled" }));
|
||||||
|
|
||||||
const pin = document.createElement("input");
|
const pin = document.createElement("input");
|
||||||
pin.title = "Maximale Content-Version";
|
pin.title = "Maximum content version";
|
||||||
pin.placeholder = "max ver";
|
pin.placeholder = "max ver";
|
||||||
pin.value = game.max_content_ver || "";
|
pin.value = game.max_content_ver || "";
|
||||||
pin.addEventListener("change", () => updateGame(game.title_id, { max_content_ver: pin.value.trim() }));
|
pin.addEventListener("change", () => updateGame(game.title_id, { max_content_ver: pin.value.trim() }));
|
||||||
@@ -370,11 +370,11 @@ function createGameCard(game) {
|
|||||||
actions.innerHTML = `
|
actions.innerHTML = `
|
||||||
<button class="row-button" data-action="check">
|
<button class="row-button" data-action="check">
|
||||||
<svg><use href="#icon-refresh"></use></svg>
|
<svg><use href="#icon-refresh"></use></svg>
|
||||||
Pruefen
|
Check
|
||||||
</button>
|
</button>
|
||||||
<button class="row-button is-primary" data-action="download" ${!isDownloadAllowed(game) ? "disabled" : ""} title="${escapeHtml(downloadTitle(game))}">
|
<button class="row-button is-primary" data-action="download" ${!isDownloadAllowed(game) ? "disabled" : ""} title="${escapeHtml(downloadTitle(game))}">
|
||||||
<svg><use href="#icon-download"></use></svg>
|
<svg><use href="#icon-download"></use></svg>
|
||||||
Laden
|
Download
|
||||||
</button>
|
</button>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@@ -399,8 +399,8 @@ function versionBox(label, value) {
|
|||||||
function statusPill(game) {
|
function statusPill(game) {
|
||||||
if (game.status === "blocked") return `<span class="pill blocked">${escapeHtml(blockedLabel(game))}</span>`;
|
if (game.status === "blocked") return `<span class="pill blocked">${escapeHtml(blockedLabel(game))}</span>`;
|
||||||
if (game.status === "queued") return `<span class="pill warn">In Queue</span>`;
|
if (game.status === "queued") return `<span class="pill warn">In Queue</span>`;
|
||||||
if (game.status === "available") return `<span class="pill ok">Update verfuegbar</span>`;
|
if (game.status === "available") return `<span class="pill ok">Update available</span>`;
|
||||||
return `<span class="pill">Aktuell</span>`;
|
return `<span class="pill">Current</span>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function sourcePill(game) {
|
function sourcePill(game) {
|
||||||
@@ -418,16 +418,16 @@ function sourceType(game) {
|
|||||||
|
|
||||||
function sourceDetail(game) {
|
function sourceDetail(game) {
|
||||||
const src = sourceType(game);
|
const src = sourceType(game);
|
||||||
if (src === "shadowmount") return `Mount: ${game.mount_from || "unbekannte Quelle"}`;
|
if (src === "shadowmount") return `Mount: ${game.mount_from || "unknown source"}`;
|
||||||
if (src === "external") return `External: ${game.source_path || "externe App-Metadaten"}`;
|
if (src === "external") return `External: ${game.source_path || "external app metadata"}`;
|
||||||
if (src === "official") return game.source_path || "Offizielle Installation";
|
if (src === "official") return game.source_path || "Official installation";
|
||||||
return "Quelle nicht eindeutig erkannt";
|
return "Source could not be identified";
|
||||||
}
|
}
|
||||||
|
|
||||||
function blockedLabel(game) {
|
function blockedLabel(game) {
|
||||||
if (sourceType(game) === "unknown") return "Quelle unbekannt";
|
if (sourceType(game) === "unknown") return "Unknown source";
|
||||||
if (!game.compatible_version) return "FW blockiert";
|
if (!game.compatible_version) return "FW blocked";
|
||||||
return "Blockiert";
|
return "Blocked";
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderQueue() {
|
function renderQueue() {
|
||||||
@@ -435,7 +435,7 @@ function renderQueue() {
|
|||||||
if (!state.downloads.length) {
|
if (!state.downloads.length) {
|
||||||
const empty = document.createElement("div");
|
const empty = document.createElement("div");
|
||||||
empty.className = "empty-state";
|
empty.className = "empty-state";
|
||||||
empty.textContent = "Keine aktiven Downloads.";
|
empty.textContent = "No active downloads.";
|
||||||
els.queueList.appendChild(empty);
|
els.queueList.appendChild(empty);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -463,8 +463,8 @@ function renderSourcePolicies() {
|
|||||||
row.className = "policy-row";
|
row.className = "policy-row";
|
||||||
row.innerHTML = `
|
row.innerHTML = `
|
||||||
<span class="pill ${info.className}">${escapeHtml(info.label)}</span>
|
<span class="pill ${info.className}">${escapeHtml(info.label)}</span>
|
||||||
<strong>${policy.allow_install ? "Install erlaubt" : "Install gesperrt"}</strong>
|
<strong>${policy.allow_install ? "Install allowed" : "Install blocked"}</strong>
|
||||||
<em>${policy.allow_download ? "Download erlaubt" : "Download gesperrt"} - ${escapeHtml(info.description)}</em>
|
<em>${policy.allow_download ? "Download allowed" : "Download blocked"} - ${escapeHtml(info.description)}</em>
|
||||||
`;
|
`;
|
||||||
return row;
|
return row;
|
||||||
});
|
});
|
||||||
@@ -487,10 +487,10 @@ async function saveConfig() {
|
|||||||
try {
|
try {
|
||||||
await postJson(API.config, config);
|
await postJson(API.config, config);
|
||||||
state.config = config;
|
state.config = config;
|
||||||
showToast("Konfiguration gespeichert.");
|
showToast("Configuration saved.");
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
state.config = config;
|
state.config = config;
|
||||||
showToast("Konfiguration lokal aktualisiert. API noch nicht erreichbar.");
|
showToast("Configuration updated locally. API is not reachable yet.");
|
||||||
}
|
}
|
||||||
|
|
||||||
renderSettings();
|
renderSettings();
|
||||||
@@ -513,8 +513,8 @@ async function runTitleAction(titleId, action) {
|
|||||||
|
|
||||||
if (action === "download" && game.compatible_version) {
|
if (action === "download" && game.compatible_version) {
|
||||||
const detail = isInstallBlocked(game)
|
const detail = isInstallBlocked(game)
|
||||||
? "Download only - Install durch Source-Policy gesperrt"
|
? "Download only - install blocked by source policy"
|
||||||
: "Wartet auf Start";
|
: "Waiting to start";
|
||||||
game.queued = true;
|
game.queued = true;
|
||||||
game.status = "queued";
|
game.status = "queued";
|
||||||
if (!state.downloads.some((item) => item.title_id === titleId)) {
|
if (!state.downloads.some((item) => item.title_id === titleId)) {
|
||||||
@@ -527,10 +527,10 @@ async function runTitleAction(titleId, action) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
state.logs.push(`[${timeNow()}] Queued ${game.title_id} ${game.compatible_version} (${sourceType(game)}, install=${isInstallBlocked(game) ? "blocked" : "allowed"})`);
|
state.logs.push(`[${timeNow()}] Queued ${game.title_id} ${game.compatible_version} (${sourceType(game)}, install=${isInstallBlocked(game) ? "blocked" : "allowed"})`);
|
||||||
showToast(`${game.title_id} wurde zur Queue hinzugefuegt.`);
|
showToast(`${game.title_id} was added to the queue.`);
|
||||||
} else {
|
} else {
|
||||||
state.logs.push(`[${timeNow()}] Check requested for ${game.title_id}`);
|
state.logs.push(`[${timeNow()}] Check requested for ${game.title_id}`);
|
||||||
showToast(`${game.title_id} wird geprueft.`);
|
showToast(`${game.title_id} check queued.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
renderGames();
|
renderGames();
|
||||||
@@ -544,7 +544,7 @@ function updateGame(titleId, patch) {
|
|||||||
if (sourceType(game) === "unknown" && patch.mode && !["disabled", "check_only"].includes(patch.mode)) {
|
if (sourceType(game) === "unknown" && patch.mode && !["disabled", "check_only"].includes(patch.mode)) {
|
||||||
patch.mode = "check_only";
|
patch.mode = "check_only";
|
||||||
patch.enabled = true;
|
patch.enabled = true;
|
||||||
showToast(`${titleId}: Quelle unbekannt, nur Check only erlaubt.`);
|
showToast(`${titleId}: unknown source, check only is allowed.`);
|
||||||
}
|
}
|
||||||
Object.assign(game, patch);
|
Object.assign(game, patch);
|
||||||
if (patch.mode === "disabled") game.enabled = false;
|
if (patch.mode === "disabled") game.enabled = false;
|
||||||
@@ -573,11 +573,11 @@ function sourcePolicyForType(type) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function downloadTitle(game) {
|
function downloadTitle(game) {
|
||||||
if (!game.enabled) return "Titel ist deaktiviert.";
|
if (!game.enabled) return "Title is disabled.";
|
||||||
if (!game.compatible_version) return "Keine kompatible Update-Version verfuegbar.";
|
if (!game.compatible_version) return "No compatible update version is available.";
|
||||||
if (!sourcePolicy(game).allow_download) return "Download ist fuer diese Quelle gesperrt.";
|
if (!sourcePolicy(game).allow_download) return "Downloads are blocked for this source.";
|
||||||
if (isInstallBlocked(game)) return "Download erlaubt, Installation bleibt fuer diese Quelle gesperrt.";
|
if (isInstallBlocked(game)) return "Download allowed; installs stay blocked for this source.";
|
||||||
return "Kompatibles Update laden.";
|
return "Download compatible update.";
|
||||||
}
|
}
|
||||||
|
|
||||||
async function postJson(url, body) {
|
async function postJson(url, body) {
|
||||||
@@ -620,7 +620,7 @@ function clone(value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function timeNow() {
|
function timeNow() {
|
||||||
return new Date().toLocaleTimeString("de-DE", { hour12: false });
|
return new Date().toLocaleTimeString("en-US", { hour12: false });
|
||||||
}
|
}
|
||||||
|
|
||||||
let toastTimer;
|
let toastTimer;
|
||||||
|
|||||||
+24
-24
@@ -1,5 +1,5 @@
|
|||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html lang="de">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
@@ -60,7 +60,7 @@
|
|||||||
<nav class="nav-list">
|
<nav class="nav-list">
|
||||||
<a class="nav-link is-active" href="#games">
|
<a class="nav-link is-active" href="#games">
|
||||||
<svg><use href="#icon-download"></use></svg>
|
<svg><use href="#icon-download"></use></svg>
|
||||||
Spiele
|
Games
|
||||||
</a>
|
</a>
|
||||||
<a class="nav-link" href="#downloads">
|
<a class="nav-link" href="#downloads">
|
||||||
<svg><use href="#icon-refresh"></use></svg>
|
<svg><use href="#icon-refresh"></use></svg>
|
||||||
@@ -81,15 +81,15 @@
|
|||||||
<header class="topbar">
|
<header class="topbar">
|
||||||
<div>
|
<div>
|
||||||
<p class="eyebrow">Standalone ELF Web UI</p>
|
<p class="eyebrow">Standalone ELF Web UI</p>
|
||||||
<h1>Spielupdates kontrolliert laden</h1>
|
<h1>Controlled game patch downloads</h1>
|
||||||
</div>
|
</div>
|
||||||
<div class="topbar-actions">
|
<div class="topbar-actions">
|
||||||
<button class="icon-button" id="refreshBtn" title="Status und Spiele neu pruefen">
|
<button class="icon-button" id="refreshBtn" title="Refresh status and games">
|
||||||
<svg><use href="#icon-refresh"></use></svg>
|
<svg><use href="#icon-refresh"></use></svg>
|
||||||
</button>
|
</button>
|
||||||
<button class="primary-button" id="saveBtn">
|
<button class="primary-button" id="saveBtn">
|
||||||
<svg><use href="#icon-save"></use></svg>
|
<svg><use href="#icon-save"></use></svg>
|
||||||
Speichern
|
Save
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
@@ -103,32 +103,32 @@
|
|||||||
<article class="metric">
|
<article class="metric">
|
||||||
<span>DNS Guard</span>
|
<span>DNS Guard</span>
|
||||||
<strong id="dnsValue">--</strong>
|
<strong id="dnsValue">--</strong>
|
||||||
<em>Sony blockiert per nanoDNS</em>
|
<em>Sony blocked by nanoDNS</em>
|
||||||
</article>
|
</article>
|
||||||
<article class="metric">
|
<article class="metric">
|
||||||
<span>CDN Zugriff</span>
|
<span>CDN Access</span>
|
||||||
<strong id="resolverValue">--</strong>
|
<strong id="resolverValue">--</strong>
|
||||||
<em>Nur PatchDL Resolver</em>
|
<em>PatchDL resolver only</em>
|
||||||
</article>
|
</article>
|
||||||
<article class="metric">
|
<article class="metric">
|
||||||
<span>Speicher</span>
|
<span>Storage</span>
|
||||||
<strong id="spaceValue">--</strong>
|
<strong id="spaceValue">--</strong>
|
||||||
<em id="downloadDirValue">Download Ziel</em>
|
<em id="downloadDirValue">Download target</em>
|
||||||
</article>
|
</article>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="toolbar" id="games">
|
<section class="toolbar" id="games">
|
||||||
<div class="search-box">
|
<div class="search-box">
|
||||||
<svg><use href="#icon-search"></use></svg>
|
<svg><use href="#icon-search"></use></svg>
|
||||||
<input id="searchInput" type="search" placeholder="Titel, Title ID oder Content ID suchen" />
|
<input id="searchInput" type="search" placeholder="Search title, Title ID, or Content ID" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="segmented" role="tablist" aria-label="Filter">
|
<div class="segmented" role="tablist" aria-label="Filter">
|
||||||
<button class="is-selected" data-filter="all">Alle</button>
|
<button class="is-selected" data-filter="all">All</button>
|
||||||
<button data-filter="enabled">Aktiv</button>
|
<button data-filter="enabled">Enabled</button>
|
||||||
<button data-filter="available">Updates</button>
|
<button data-filter="available">Updates</button>
|
||||||
<button data-filter="shadowmount">Shadow</button>
|
<button data-filter="shadowmount">Shadow</button>
|
||||||
<button data-filter="blocked">Blockiert</button>
|
<button data-filter="blocked">Blocked</button>
|
||||||
<button data-filter="queued">Queue</button>
|
<button data-filter="queued">Queue</button>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
@@ -140,7 +140,7 @@
|
|||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
<div>
|
<div>
|
||||||
<p class="eyebrow">Downloads</p>
|
<p class="eyebrow">Downloads</p>
|
||||||
<h2>Aktive Queue</h2>
|
<h2>Active Queue</h2>
|
||||||
</div>
|
</div>
|
||||||
<button class="ghost-button" id="pauseAllBtn">
|
<button class="ghost-button" id="pauseAllBtn">
|
||||||
<svg><use href="#icon-pause"></use></svg>
|
<svg><use href="#icon-pause"></use></svg>
|
||||||
@@ -154,7 +154,7 @@
|
|||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
<div>
|
<div>
|
||||||
<p class="eyebrow">Policy</p>
|
<p class="eyebrow">Policy</p>
|
||||||
<h2>Update Regeln</h2>
|
<h2>Update Rules</h2>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -167,32 +167,32 @@
|
|||||||
</select>
|
</select>
|
||||||
</label>
|
</label>
|
||||||
<label class="field">
|
<label class="field">
|
||||||
<span>Download Ordner</span>
|
<span>Download Folder</span>
|
||||||
<input id="downloadDir" type="text" spellcheck="false" />
|
<input id="downloadDir" type="text" spellcheck="false" />
|
||||||
</label>
|
</label>
|
||||||
<label class="switch-row">
|
<label class="switch-row">
|
||||||
<input id="installAfterDownload" type="checkbox" />
|
<input id="installAfterDownload" type="checkbox" />
|
||||||
<span>
|
<span>
|
||||||
<strong>Nach Download installieren</strong>
|
<strong>Install after download</strong>
|
||||||
<em>Globaler Default, pro Spiel ueberschreibbar</em>
|
<em>Global default, overridable per game</em>
|
||||||
</span>
|
</span>
|
||||||
</label>
|
</label>
|
||||||
<label class="switch-row">
|
<label class="switch-row">
|
||||||
<input id="deleteAfterInstall" type="checkbox" />
|
<input id="deleteAfterInstall" type="checkbox" />
|
||||||
<span>
|
<span>
|
||||||
<strong>PKG nach Installation loeschen</strong>
|
<strong>Delete PKG after install</strong>
|
||||||
<em>Nur wenn Installation erfolgreich war</em>
|
<em>Only after a successful install</em>
|
||||||
</span>
|
</span>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="allowlist">
|
<div class="allowlist">
|
||||||
<span>Interne CDN Allowlist</span>
|
<span>Internal CDN Allowlist</span>
|
||||||
<div id="allowlistHosts"></div>
|
<div id="allowlistHosts"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="source-policy">
|
<div class="source-policy">
|
||||||
<span>Install Schutz</span>
|
<span>Install Protection</span>
|
||||||
<div id="sourcePolicyList"></div>
|
<div id="sourcePolicyList"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -202,7 +202,7 @@
|
|||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
<div>
|
<div>
|
||||||
<p class="eyebrow">Runtime</p>
|
<p class="eyebrow">Runtime</p>
|
||||||
<h2>Letzte Ereignisse</h2>
|
<h2>Recent Events</h2>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<pre id="logOutput" tabindex="0"></pre>
|
<pre id="logOutput" tabindex="0"></pre>
|
||||||
|
|||||||
+49
-48
@@ -1,21 +1,21 @@
|
|||||||
:root {
|
:root {
|
||||||
color-scheme: light;
|
color-scheme: dark;
|
||||||
--bg: #f6f7f4;
|
--bg: #0b0d10;
|
||||||
--surface: #ffffff;
|
--surface: #14181d;
|
||||||
--surface-2: #eeefe9;
|
--surface-2: #1b2027;
|
||||||
--ink: #1f2420;
|
--ink: #edf2f7;
|
||||||
--muted: #697069;
|
--muted: #9aa6b2;
|
||||||
--border: #d7dbd2;
|
--border: #2a313a;
|
||||||
--green: #247857;
|
--green: #38c172;
|
||||||
--green-dark: #155f42;
|
--green-dark: #63d994;
|
||||||
--green-soft: #dff3e9;
|
--green-soft: rgba(56, 193, 114, 0.16);
|
||||||
--amber: #b87516;
|
--amber: #f2b84b;
|
||||||
--amber-soft: #fff1d6;
|
--amber-soft: rgba(242, 184, 75, 0.16);
|
||||||
--red: #b54343;
|
--red: #ff6b6b;
|
||||||
--red-soft: #ffe4e4;
|
--red-soft: rgba(255, 107, 107, 0.15);
|
||||||
--blue: #2d6d9d;
|
--blue: #58a6ff;
|
||||||
--blue-soft: #deeff8;
|
--blue-soft: rgba(88, 166, 255, 0.15);
|
||||||
--shadow: 0 18px 50px rgba(31, 36, 32, 0.1);
|
--shadow: 0 18px 50px rgba(0, 0, 0, 0.38);
|
||||||
--radius: 8px;
|
--radius: 8px;
|
||||||
font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
||||||
}
|
}
|
||||||
@@ -69,9 +69,9 @@ svg {
|
|||||||
top: 0;
|
top: 0;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
padding: 20px 16px;
|
padding: 20px 16px;
|
||||||
background: #1e241f;
|
background: #0f1216;
|
||||||
color: #f7f8f4;
|
color: var(--ink);
|
||||||
border-right: 1px solid #111611;
|
border-right: 1px solid #222932;
|
||||||
}
|
}
|
||||||
|
|
||||||
.brand {
|
.brand {
|
||||||
@@ -87,8 +87,8 @@ svg {
|
|||||||
place-items: center;
|
place-items: center;
|
||||||
width: 42px;
|
width: 42px;
|
||||||
height: 42px;
|
height: 42px;
|
||||||
border: 1px solid rgba(255, 255, 255, 0.18);
|
border: 1px solid rgba(255, 255, 255, 0.16);
|
||||||
background: #2b6f50;
|
background: #247857;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
font-weight: 800;
|
font-weight: 800;
|
||||||
}
|
}
|
||||||
@@ -101,7 +101,7 @@ svg {
|
|||||||
.brand span {
|
.brand span {
|
||||||
display: block;
|
display: block;
|
||||||
margin-top: 2px;
|
margin-top: 2px;
|
||||||
color: #b8c2ba;
|
color: var(--muted);
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,14 +116,14 @@ svg {
|
|||||||
gap: 10px;
|
gap: 10px;
|
||||||
min-height: 40px;
|
min-height: 40px;
|
||||||
padding: 0 10px;
|
padding: 0 10px;
|
||||||
color: #cbd3cc;
|
color: #b6c0ca;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-link:hover,
|
.nav-link:hover,
|
||||||
.nav-link.is-active {
|
.nav-link.is-active {
|
||||||
background: rgba(255, 255, 255, 0.09);
|
background: rgba(255, 255, 255, 0.08);
|
||||||
color: #ffffff;
|
color: #ffffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -230,7 +230,7 @@ h2 {
|
|||||||
border: 1px solid var(--border);
|
border: 1px solid var(--border);
|
||||||
background: var(--surface);
|
background: var(--surface);
|
||||||
border-radius: var(--radius);
|
border-radius: var(--radius);
|
||||||
box-shadow: 0 1px 0 rgba(31, 36, 32, 0.04);
|
box-shadow: 0 1px 0 rgba(255, 255, 255, 0.03);
|
||||||
}
|
}
|
||||||
|
|
||||||
.metric span,
|
.metric span,
|
||||||
@@ -298,7 +298,7 @@ h2 {
|
|||||||
.segmented button.is-selected {
|
.segmented button.is-selected {
|
||||||
background: var(--surface);
|
background: var(--surface);
|
||||||
color: var(--ink);
|
color: var(--ink);
|
||||||
box-shadow: 0 1px 2px rgba(31, 36, 32, 0.08);
|
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.28);
|
||||||
}
|
}
|
||||||
|
|
||||||
.game-grid {
|
.game-grid {
|
||||||
@@ -315,7 +315,7 @@ h2 {
|
|||||||
border: 1px solid var(--border);
|
border: 1px solid var(--border);
|
||||||
background: var(--surface);
|
background: var(--surface);
|
||||||
border-radius: var(--radius);
|
border-radius: var(--radius);
|
||||||
box-shadow: 0 1px 0 rgba(31, 36, 32, 0.04);
|
box-shadow: 0 1px 0 rgba(255, 255, 255, 0.03);
|
||||||
}
|
}
|
||||||
|
|
||||||
.game-title {
|
.game-title {
|
||||||
@@ -366,31 +366,31 @@ h2 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.pill.ok {
|
.pill.ok {
|
||||||
border-color: #b7dec9;
|
border-color: rgba(56, 193, 114, 0.34);
|
||||||
background: var(--green-soft);
|
background: var(--green-soft);
|
||||||
color: var(--green-dark);
|
color: var(--green-dark);
|
||||||
}
|
}
|
||||||
|
|
||||||
.pill.warn {
|
.pill.warn {
|
||||||
border-color: #f0cd91;
|
border-color: rgba(242, 184, 75, 0.38);
|
||||||
background: var(--amber-soft);
|
background: var(--amber-soft);
|
||||||
color: #81500b;
|
color: var(--amber);
|
||||||
}
|
}
|
||||||
|
|
||||||
.pill.external {
|
.pill.external {
|
||||||
border-color: #b7d8e8;
|
border-color: rgba(88, 166, 255, 0.34);
|
||||||
background: var(--blue-soft);
|
background: var(--blue-soft);
|
||||||
color: #1e547a;
|
color: var(--blue);
|
||||||
}
|
}
|
||||||
|
|
||||||
.pill.shadow {
|
.pill.shadow {
|
||||||
border-color: #d0c4eb;
|
border-color: rgba(181, 146, 255, 0.34);
|
||||||
background: #eee8fb;
|
background: rgba(181, 146, 255, 0.14);
|
||||||
color: #584080;
|
color: #c7b1ff;
|
||||||
}
|
}
|
||||||
|
|
||||||
.pill.blocked {
|
.pill.blocked {
|
||||||
border-color: #f0b8b8;
|
border-color: rgba(255, 107, 107, 0.34);
|
||||||
background: var(--red-soft);
|
background: var(--red-soft);
|
||||||
color: var(--red);
|
color: var(--red);
|
||||||
}
|
}
|
||||||
@@ -414,7 +414,7 @@ h2 {
|
|||||||
.version-box {
|
.version-box {
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
background: #f8f9f6;
|
background: var(--surface-2);
|
||||||
border: 1px solid var(--border);
|
border: 1px solid var(--border);
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
}
|
}
|
||||||
@@ -497,7 +497,7 @@ h2 {
|
|||||||
gap: 12px;
|
gap: 12px;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 12px;
|
padding: 12px;
|
||||||
background: #f8f9f6;
|
background: var(--surface-2);
|
||||||
border: 1px solid var(--border);
|
border: 1px solid var(--border);
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
}
|
}
|
||||||
@@ -521,7 +521,7 @@ h2 {
|
|||||||
height: 8px;
|
height: 8px;
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
background: #e3e6de;
|
background: #242b33;
|
||||||
border-radius: 999px;
|
border-radius: 999px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -555,7 +555,7 @@ h2 {
|
|||||||
min-height: 38px;
|
min-height: 38px;
|
||||||
padding: 0 10px;
|
padding: 0 10px;
|
||||||
border: 1px solid var(--border);
|
border: 1px solid var(--border);
|
||||||
background: #f8f9f6;
|
background: var(--surface-2);
|
||||||
color: var(--ink);
|
color: var(--ink);
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
}
|
}
|
||||||
@@ -566,7 +566,7 @@ h2 {
|
|||||||
gap: 10px;
|
gap: 10px;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
border: 1px solid var(--border);
|
border: 1px solid var(--border);
|
||||||
background: #f8f9f6;
|
background: var(--surface-2);
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -622,7 +622,7 @@ h2 {
|
|||||||
gap: 8px;
|
gap: 8px;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
background: #f8f9f6;
|
background: var(--surface-2);
|
||||||
border: 1px solid var(--border);
|
border: 1px solid var(--border);
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
}
|
}
|
||||||
@@ -646,7 +646,7 @@ h2 {
|
|||||||
min-height: 26px;
|
min-height: 26px;
|
||||||
padding: 0 8px;
|
padding: 0 8px;
|
||||||
background: var(--blue-soft);
|
background: var(--blue-soft);
|
||||||
color: #1e547a;
|
color: var(--blue);
|
||||||
border-radius: 999px;
|
border-radius: 999px;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
font-weight: 800;
|
font-weight: 800;
|
||||||
@@ -662,8 +662,8 @@ pre {
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 12px;
|
padding: 12px;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
background: #1f2420;
|
background: #0f1216;
|
||||||
color: #e9eee8;
|
color: #dfe7ef;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
line-height: 1.55;
|
line-height: 1.55;
|
||||||
@@ -685,8 +685,9 @@ pre {
|
|||||||
z-index: 10;
|
z-index: 10;
|
||||||
max-width: min(420px, calc(100vw - 36px));
|
max-width: min(420px, calc(100vw - 36px));
|
||||||
padding: 12px 14px;
|
padding: 12px 14px;
|
||||||
color: #ffffff;
|
color: var(--ink);
|
||||||
background: #1f2420;
|
background: #171c22;
|
||||||
|
border: 1px solid var(--border);
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
box-shadow: var(--shadow);
|
box-shadow: var(--shadow);
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
|
|||||||
Reference in new issue
Block a user