package gui const indexHTML = ` LazyUpdateManager

LazyUpdateManager

Pruefe Updates...

Updates

0
Keine Updates gefunden.
` const appCSS = ` :root { color-scheme: dark; --bg: #101114; --panel: #191b20; --panel-soft: #20242b; --text: #f1f5f9; --muted: #9aa4b2; --line: #303640; --accent: #42d392; --accent-strong: #2ab67c; --warn: #f5c451; --danger: #ff6b6b; } * { box-sizing: border-box; } body { margin: 0; min-width: 320px; min-height: 100vh; color: var(--text); background: var(--bg); font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; } button, input, select { font: inherit; } .shell { width: min(1180px, calc(100vw - 32px)); margin: 0 auto; padding: 28px 0; } .topbar { display: flex; align-items: center; justify-content: space-between; gap: 18px; margin-bottom: 18px; } h1, h2, p { margin: 0; } h1 { font-size: 28px; font-weight: 720; } h2 { font-size: 16px; font-weight: 680; } #summary { margin-top: 5px; color: var(--muted); } .actions { display: flex; gap: 10px; } button { border: 1px solid var(--line); border-radius: 8px; min-height: 40px; padding: 0 14px; color: var(--text); background: var(--panel-soft); cursor: pointer; } button:hover { border-color: var(--accent); } button:disabled { cursor: progress; opacity: 0.65; } #installBtn, form button { border-color: transparent; background: var(--accent); color: #07110d; font-weight: 700; } #installBtn:hover, form button:hover { background: var(--accent-strong); } .content { display: grid; grid-template-columns: minmax(0, 1fr) 320px; gap: 18px; align-items: start; } .panel { border: 1px solid var(--line); border-radius: 8px; background: var(--panel); } .panel-head { display: flex; align-items: center; justify-content: space-between; min-height: 54px; padding: 0 16px; border-bottom: 1px solid var(--line); } #countBadge { display: inline-flex; align-items: center; justify-content: center; min-width: 32px; height: 26px; border-radius: 999px; color: #07110d; background: var(--accent); font-weight: 760; } .warnings { margin: 14px 16px 0; padding: 12px; border: 1px solid rgba(245, 196, 81, 0.45); border-radius: 8px; color: var(--warn); background: rgba(245, 196, 81, 0.08); } .empty { padding: 44px 16px; color: var(--muted); text-align: center; } table { width: 100%; border-collapse: collapse; } th, td { padding: 12px 16px; border-bottom: 1px solid var(--line); text-align: left; vertical-align: middle; } th { color: var(--muted); font-size: 12px; text-transform: uppercase; } td { overflow-wrap: anywhere; } td:first-child { width: 92px; color: var(--accent); font-weight: 700; } tr:last-child td { border-bottom: 0; } form { display: grid; gap: 16px; padding: 16px; } label { display: grid; gap: 8px; color: var(--muted); } .toggle { grid-template-columns: 18px 1fr; align-items: center; color: var(--text); } input, select { width: 100%; min-height: 40px; border: 1px solid var(--line); border-radius: 8px; padding: 0 10px; color: var(--text); background: var(--panel-soft); } input[type="checkbox"] { width: 18px; min-height: 18px; accent-color: var(--accent); } small, #saveState { color: var(--muted); } @media (max-width: 820px) { .shell { width: min(100vw - 20px, 1180px); padding: 16px 0; } .topbar, .content { display: grid; grid-template-columns: 1fr; } .actions { grid-template-columns: 48px 1fr; display: grid; } th:nth-child(3), td:nth-child(3) { display: none; } } ` const appJS = ` const summary = document.querySelector("#summary"); const countBadge = document.querySelector("#countBadge"); const refreshBtn = document.querySelector("#refreshBtn"); const installBtn = document.querySelector("#installBtn"); const updatesTable = document.querySelector("#updatesTable"); const updatesBody = document.querySelector("#updatesBody"); const emptyState = document.querySelector("#emptyState"); const warnings = document.querySelector("#warnings"); const form = document.querySelector("#settingsForm"); const checkAur = document.querySelector("#checkAur"); const reminderHours = document.querySelector("#reminderHours"); const terminal = document.querySelector("#terminal"); const saveState = document.querySelector("#saveState"); async function request(path, options = {}) { const response = await fetch(path, { headers: { "Content-Type": "application/json" }, ...options, }); const data = await response.json(); if (!response.ok) { throw new Error(data.error || "Request failed"); } return data; } function render(data) { summary.textContent = data.summary; countBadge.textContent = data.total; installBtn.disabled = data.total === 0; checkAur.checked = data.settings.check_aur; reminderHours.value = data.settings.reminder_interval_hours; terminal.value = data.settings.terminal || "auto"; updatesBody.replaceChildren(); for (const pkg of data.packages) { const row = document.createElement("tr"); for (const value of [pkg.Source, pkg.Name, pkg.Current || "-", pkg.Available || "-"]) { const cell = document.createElement("td"); cell.textContent = value; row.appendChild(cell); } updatesBody.appendChild(row); } updatesTable.hidden = data.packages.length === 0; emptyState.hidden = data.packages.length !== 0; warnings.hidden = data.warnings.length === 0; warnings.textContent = data.warnings.join("\\n"); } async function loadStatus() { refreshBtn.disabled = true; summary.textContent = "Pruefe Updates..."; try { render(await request("/api/status")); } catch (error) { summary.textContent = error.message; } finally { refreshBtn.disabled = false; } } refreshBtn.addEventListener("click", loadStatus); installBtn.addEventListener("click", async () => { installBtn.disabled = true; try { await request("/api/install", { method: "POST" }); summary.textContent = "Installation im Terminal gestartet."; } catch (error) { summary.textContent = error.message; } finally { installBtn.disabled = false; } }); form.addEventListener("submit", async (event) => { event.preventDefault(); saveState.textContent = "Speichere..."; try { await request("/api/settings", { method: "PUT", body: JSON.stringify({ check_aur: checkAur.checked, reminder_interval_hours: Number(reminderHours.value), terminal: terminal.value, }), }); saveState.textContent = "Gespeichert"; await loadStatus(); } catch (error) { saveState.textContent = error.message; } }); loadStatus(); `