More tweaks
All checks were successful
Build & Test WASM / build-and-test (push) Successful in 1m42s
All checks were successful
Build & Test WASM / build-and-test (push) Successful in 1m42s
This commit is contained in:
@@ -8,6 +8,7 @@
|
|||||||
let manualMode = false;
|
let manualMode = false;
|
||||||
let selectedPrefix = null;
|
let selectedPrefix = null;
|
||||||
let patchesLoaded = false;
|
let patchesLoaded = false;
|
||||||
|
let isRestore = false;
|
||||||
|
|
||||||
// DOM elements
|
// DOM elements
|
||||||
const stepNav = document.getElementById('step-nav');
|
const stepNav = document.getElementById('step-nav');
|
||||||
@@ -27,10 +28,10 @@
|
|||||||
const manualModel = document.getElementById('manual-model');
|
const manualModel = document.getElementById('manual-model');
|
||||||
const manualChromeHint = document.getElementById('manual-chrome-hint');
|
const manualChromeHint = document.getElementById('manual-chrome-hint');
|
||||||
const btnDeviceNext = document.getElementById('btn-device-next');
|
const btnDeviceNext = document.getElementById('btn-device-next');
|
||||||
|
const btnDeviceRestore = document.getElementById('btn-device-restore');
|
||||||
const btnPatchesBack = document.getElementById('btn-patches-back');
|
const btnPatchesBack = document.getElementById('btn-patches-back');
|
||||||
const btnPatchesNext = document.getElementById('btn-patches-next');
|
const btnPatchesNext = document.getElementById('btn-patches-next');
|
||||||
const btnBuildBack = document.getElementById('btn-build-back');
|
const btnBuildBack = document.getElementById('btn-build-back');
|
||||||
const btnBuild = document.getElementById('btn-build');
|
|
||||||
const btnWrite = document.getElementById('btn-write');
|
const btnWrite = document.getElementById('btn-write');
|
||||||
const btnDownload = document.getElementById('btn-download');
|
const btnDownload = document.getElementById('btn-download');
|
||||||
const btnRetry = document.getElementById('btn-retry');
|
const btnRetry = document.getElementById('btn-retry');
|
||||||
@@ -41,6 +42,7 @@
|
|||||||
const deviceStatus = document.getElementById('device-status');
|
const deviceStatus = document.getElementById('device-status');
|
||||||
const patchContainer = document.getElementById('patch-container');
|
const patchContainer = document.getElementById('patch-container');
|
||||||
const buildStatus = document.getElementById('build-status');
|
const buildStatus = document.getElementById('build-status');
|
||||||
|
const existingTgzWarning = document.getElementById('existing-tgz-warning');
|
||||||
const writeInstructions = document.getElementById('write-instructions');
|
const writeInstructions = document.getElementById('write-instructions');
|
||||||
const downloadInstructions = document.getElementById('download-instructions');
|
const downloadInstructions = document.getElementById('download-instructions');
|
||||||
const firmwareVersionLabel = document.getElementById('firmware-version-label');
|
const firmwareVersionLabel = document.getElementById('firmware-version-label');
|
||||||
@@ -74,12 +76,12 @@
|
|||||||
// --- Patch count ---
|
// --- Patch count ---
|
||||||
function updatePatchCount() {
|
function updatePatchCount() {
|
||||||
const count = patchUI.getEnabledCount();
|
const count = patchUI.getEnabledCount();
|
||||||
btnPatchesNext.disabled = count === 0;
|
btnPatchesNext.disabled = false;
|
||||||
patchCountHint.textContent = count === 0
|
if (count === 0) {
|
||||||
? 'Select at least one patch to continue.'
|
patchCountHint.textContent = 'No patches selected — continuing will restore the original unpatched firmware.';
|
||||||
: count === 1
|
} else {
|
||||||
? '1 patch selected.'
|
patchCountHint.textContent = count === 1 ? '1 patch selected.' : count + ' patches selected.';
|
||||||
: count + ' patches selected.';
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
patchUI.onChange = updatePatchCount;
|
patchUI.onChange = updatePatchCount;
|
||||||
@@ -134,8 +136,10 @@
|
|||||||
const version = manualVersion.value;
|
const version = manualVersion.value;
|
||||||
selectedPrefix = null;
|
selectedPrefix = null;
|
||||||
|
|
||||||
|
const modelHint = document.getElementById('manual-model-hint');
|
||||||
if (!version) {
|
if (!version) {
|
||||||
manualModel.hidden = true;
|
manualModel.hidden = true;
|
||||||
|
modelHint.hidden = true;
|
||||||
btnManualConfirm.disabled = true;
|
btnManualConfirm.disabled = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -149,6 +153,7 @@
|
|||||||
manualModel.appendChild(opt);
|
manualModel.appendChild(opt);
|
||||||
}
|
}
|
||||||
manualModel.hidden = false;
|
manualModel.hidden = false;
|
||||||
|
modelHint.hidden = false;
|
||||||
btnManualConfirm.disabled = true;
|
btnManualConfirm.disabled = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -191,8 +196,10 @@
|
|||||||
const match = available.find(p => p.version === info.firmware);
|
const match = available.find(p => p.version === info.firmware);
|
||||||
|
|
||||||
if (match) {
|
if (match) {
|
||||||
deviceStatus.className = 'status-supported';
|
deviceStatus.className = '';
|
||||||
deviceStatus.textContent = 'Patches available for firmware ' + info.firmware + '.';
|
deviceStatus.textContent =
|
||||||
|
'KoboPatch Web UI currently supports this version of the firmware. ' +
|
||||||
|
'You can choose to customize it or simply restore the original software.';
|
||||||
|
|
||||||
await patchUI.loadFromURL('patches/' + match.filename);
|
await patchUI.loadFromURL('patches/' + match.filename);
|
||||||
patchUI.render(patchContainer);
|
patchUI.render(patchContainer);
|
||||||
@@ -200,6 +207,8 @@
|
|||||||
patchesLoaded = true;
|
patchesLoaded = true;
|
||||||
configureFirmwareStep(info.firmware, info.serialPrefix);
|
configureFirmwareStep(info.firmware, info.serialPrefix);
|
||||||
|
|
||||||
|
btnDeviceNext.hidden = false;
|
||||||
|
btnDeviceRestore.hidden = false;
|
||||||
showStep(stepDevice);
|
showStep(stepDevice);
|
||||||
} else {
|
} else {
|
||||||
deviceStatus.className = 'status-unsupported';
|
deviceStatus.className = 'status-unsupported';
|
||||||
@@ -207,6 +216,7 @@
|
|||||||
'No patches available for firmware ' + info.firmware + '. ' +
|
'No patches available for firmware ' + info.firmware + '. ' +
|
||||||
'Supported versions: ' + available.map(p => p.version).join(', ');
|
'Supported versions: ' + available.map(p => p.version).join(', ');
|
||||||
btnDeviceNext.hidden = true;
|
btnDeviceNext.hidden = true;
|
||||||
|
btnDeviceRestore.hidden = true;
|
||||||
showStep(stepDevice);
|
showStep(stepDevice);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@@ -220,6 +230,12 @@
|
|||||||
if (patchesLoaded) goToPatches();
|
if (patchesLoaded) goToPatches();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
btnDeviceRestore.addEventListener('click', () => {
|
||||||
|
if (!patchesLoaded) return;
|
||||||
|
isRestore = true;
|
||||||
|
goToBuild();
|
||||||
|
});
|
||||||
|
|
||||||
async function loadPatchesForVersion(version, available) {
|
async function loadPatchesForVersion(version, available) {
|
||||||
const match = available.find(p => p.version === version);
|
const match = available.find(p => p.version === version);
|
||||||
if (!match) return false;
|
if (!match) return false;
|
||||||
@@ -247,12 +263,24 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
btnPatchesNext.addEventListener('click', () => {
|
btnPatchesNext.addEventListener('click', () => {
|
||||||
if (patchUI.getEnabledCount() === 0) return;
|
isRestore = patchUI.getEnabledCount() === 0;
|
||||||
goToBuild();
|
goToBuild();
|
||||||
});
|
});
|
||||||
|
|
||||||
// --- Step 3: Review & Build ---
|
// --- Step 3: Review & Build ---
|
||||||
|
const btnBuild = document.getElementById('btn-build');
|
||||||
|
const firmwareDescription = document.getElementById('firmware-description');
|
||||||
|
|
||||||
function goToBuild() {
|
function goToBuild() {
|
||||||
|
if (isRestore) {
|
||||||
|
firmwareDescription.textContent =
|
||||||
|
'will be downloaded and extracted without modifications to restore the original unpatched software:';
|
||||||
|
btnBuild.textContent = 'Restore Original Firmware';
|
||||||
|
} else {
|
||||||
|
firmwareDescription.textContent =
|
||||||
|
'will be downloaded automatically from Kobo\u2019s servers and will be patched after the download completes:';
|
||||||
|
btnBuild.textContent = 'Build Patched Firmware';
|
||||||
|
}
|
||||||
setNavStep(3);
|
setNavStep(3);
|
||||||
showStep(stepFirmware);
|
showStep(stepFirmware);
|
||||||
}
|
}
|
||||||
@@ -320,7 +348,7 @@
|
|||||||
const firmwareBytes = await downloadFirmware(firmwareURL);
|
const firmwareBytes = await downloadFirmware(firmwareURL);
|
||||||
appendLog('Firmware downloaded: ' + (firmwareBytes.length / 1024 / 1024).toFixed(1) + ' MB');
|
appendLog('Firmware downloaded: ' + (firmwareBytes.length / 1024 / 1024).toFixed(1) + ' MB');
|
||||||
|
|
||||||
buildProgress.textContent = 'Applying patches...';
|
buildProgress.textContent = isRestore ? 'Extracting firmware...' : 'Applying patches...';
|
||||||
const configYAML = patchUI.generateConfig();
|
const configYAML = patchUI.generateConfig();
|
||||||
const patchFiles = patchUI.getPatchFileBytes();
|
const patchFiles = patchUI.getPatchFileBytes();
|
||||||
|
|
||||||
@@ -334,9 +362,17 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
resultTgz = result.tgz;
|
resultTgz = result.tgz;
|
||||||
buildStatus.textContent =
|
const sizeTxt = (resultTgz.length / 1024 / 1024).toFixed(1) + ' MB';
|
||||||
'Patching complete. KoboRoot.tgz is ' +
|
const action = isRestore ? 'Firmware extracted' : 'Patching complete';
|
||||||
(resultTgz.length / 1024).toFixed(0) + ' KB.';
|
const description = isRestore
|
||||||
|
? 'This will restore the original unpatched software.'
|
||||||
|
: '';
|
||||||
|
buildStatus.innerHTML =
|
||||||
|
action + '. <strong>KoboRoot.tgz</strong> (' + sizeTxt + ') is ready. ' +
|
||||||
|
(description ? description + ' ' : '') +
|
||||||
|
(manualMode
|
||||||
|
? 'Download the file and copy it to your Kobo.'
|
||||||
|
: 'Write it directly to your connected Kobo, or download for manual installation.');
|
||||||
|
|
||||||
const doneLog = document.getElementById('done-log');
|
const doneLog = document.getElementById('done-log');
|
||||||
doneLog.textContent = buildLog.textContent;
|
doneLog.textContent = buildLog.textContent;
|
||||||
@@ -349,6 +385,18 @@
|
|||||||
btnDownload.disabled = false;
|
btnDownload.disabled = false;
|
||||||
writeInstructions.hidden = true;
|
writeInstructions.hidden = true;
|
||||||
downloadInstructions.hidden = true;
|
downloadInstructions.hidden = true;
|
||||||
|
existingTgzWarning.hidden = true;
|
||||||
|
|
||||||
|
// Check if a KoboRoot.tgz already exists on the device.
|
||||||
|
if (!manualMode && device.directoryHandle) {
|
||||||
|
try {
|
||||||
|
const koboDir = await device.directoryHandle.getDirectoryHandle('.kobo');
|
||||||
|
await koboDir.getFileHandle('KoboRoot.tgz');
|
||||||
|
existingTgzWarning.hidden = false;
|
||||||
|
} catch {
|
||||||
|
// No existing file — that's fine.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
setNavStep(4);
|
setNavStep(4);
|
||||||
showStep(stepDone);
|
showStep(stepDone);
|
||||||
@@ -421,7 +469,9 @@
|
|||||||
manualMode = false;
|
manualMode = false;
|
||||||
selectedPrefix = null;
|
selectedPrefix = null;
|
||||||
patchesLoaded = false;
|
patchesLoaded = false;
|
||||||
|
isRestore = false;
|
||||||
btnDeviceNext.hidden = false;
|
btnDeviceNext.hidden = false;
|
||||||
|
btnDeviceRestore.hidden = false;
|
||||||
|
|
||||||
if (hasFileSystemAccess) {
|
if (hasFileSystemAccess) {
|
||||||
setNavStep(1);
|
setNavStep(1);
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>KoboPatch Web UI</title>
|
<title>KoboPatch Web UI</title>
|
||||||
<link rel="stylesheet" href="style.css?ts=1773666969">
|
<link rel="stylesheet" href="style.css?ts=1773669670">
|
||||||
<script src="https://cdn.jsdelivr.net/npm/jszip@3/dist/jszip.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/jszip@3/dist/jszip.min.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
@@ -27,9 +27,8 @@
|
|||||||
<!-- Step 1a: Connect device (automatic, Chromium only) -->
|
<!-- Step 1a: Connect device (automatic, Chromium only) -->
|
||||||
<section id="step-connect" class="step" hidden>
|
<section id="step-connect" class="step" hidden>
|
||||||
<div class="warning">
|
<div class="warning">
|
||||||
Patching modifies system files on your Kobo. If something goes wrong,
|
<b>Patching modifies system files on your Kobo, and <u>will void your warranty</u>.</b> This process allows for custom modifications to be applied, or undone. If something has gone wrong,
|
||||||
you may need to <a href="https://help.kobo.com/hc/en-us/articles/360017605314-Manual-reset-your-Kobo-Clara-HD-Kobo-Nia-Kobo-Elipsa-Kobo-Clara-2E-Kobo-Elipsa-2E" target="_blank">manually reset your device</a>.
|
you may need to <a href="https://help.kobo.com/hc/en-us/articles/360017605314-Manual-reset-your-Kobo-Clara-HD-Kobo-Nia-Kobo-Elipsa-Kobo-Clara-2E-Kobo-Elipsa-2E" target="_blank">manually reset your device</a>.
|
||||||
Proceed with care.
|
|
||||||
</div>
|
</div>
|
||||||
<p>
|
<p>
|
||||||
Connect your Kobo e-reader via USB. It should appear as a removable drive.
|
Connect your Kobo e-reader via USB. It should appear as a removable drive.
|
||||||
@@ -53,13 +52,21 @@
|
|||||||
Tip: if you use Chrome or Edge, this tool can auto-detect your device
|
Tip: if you use Chrome or Edge, this tool can auto-detect your device
|
||||||
and write patched files directly to it. Even easier, but sadly requires a Chromium based browser.
|
and write patched files directly to it. Even easier, but sadly requires a Chromium based browser.
|
||||||
</p>
|
</p>
|
||||||
<p>Select your Kobo model and firmware version.</p>
|
<p>Select your Kobo model and firmware version.
|
||||||
|
Not sure which model you have?
|
||||||
|
<a href="https://help.kobo.com/hc/en-us/articles/360019676973-Identify-your-Kobo-eReader-or-Kobo-tablet" target="_blank">Identify your Kobo eReader</a>.
|
||||||
|
</p>
|
||||||
<select id="manual-version">
|
<select id="manual-version">
|
||||||
<option value="">-- Select firmware version --</option>
|
<option value="">-- Select firmware version --</option>
|
||||||
</select>
|
</select>
|
||||||
<select id="manual-model" hidden>
|
<select id="manual-model" hidden>
|
||||||
<option value="">-- Select your Kobo model --</option>
|
<option value="">-- Select your Kobo model --</option>
|
||||||
</select>
|
</select>
|
||||||
|
<p id="manual-model-hint" class="fallback-hint" hidden>
|
||||||
|
You can identify your model by the serial number prefix shown on your Kobo
|
||||||
|
under <strong>Settings > Device information</strong>.
|
||||||
|
Match the first characters (e.g. N428) to the list above.
|
||||||
|
</p>
|
||||||
<button id="btn-manual-confirm" class="primary" disabled>Continue ›</button>
|
<button id="btn-manual-confirm" class="primary" disabled>Continue ›</button>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
@@ -79,8 +86,9 @@
|
|||||||
<span id="device-firmware" class="value">--</span>
|
<span id="device-firmware" class="value">--</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="device-status"></div>
|
<p id="device-status"></p>
|
||||||
<div class="step-actions">
|
<div class="step-actions">
|
||||||
|
<button id="btn-device-restore" class="secondary">Restore Unpatched Software</button>
|
||||||
<button id="btn-device-next" class="primary">Configure Patches ›</button>
|
<button id="btn-device-next" class="primary">Configure Patches ›</button>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
@@ -100,8 +108,8 @@
|
|||||||
<section id="step-firmware" class="step" hidden>
|
<section id="step-firmware" class="step" hidden>
|
||||||
<p id="firmware-auto-info">
|
<p id="firmware-auto-info">
|
||||||
Firmware <strong id="firmware-version-label"></strong> for
|
Firmware <strong id="firmware-version-label"></strong> for
|
||||||
<strong id="firmware-device-label"></strong> will be downloaded
|
<strong id="firmware-device-label"></strong>
|
||||||
automatically from Kobo's servers and will be patched after the download completes:<br>
|
<span id="firmware-description">will be downloaded automatically from Kobo's servers and will be patched after the download completes:</span><br>
|
||||||
<code id="firmware-download-url"></code><br>
|
<code id="firmware-download-url"></code><br>
|
||||||
<span id="firmware-verify-notice">
|
<span id="firmware-verify-notice">
|
||||||
You can verify if this URL matches your Kobo's model on
|
You can verify if this URL matches your Kobo's model on
|
||||||
@@ -131,11 +139,15 @@
|
|||||||
<p id="build-progress">Starting...</p>
|
<p id="build-progress">Starting...</p>
|
||||||
</div>
|
</div>
|
||||||
<pre id="build-log" class="build-log"></pre>
|
<pre id="build-log" class="build-log"></pre>
|
||||||
|
<p class="fallback-hint">Please wait while the patch is being applied...</p>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<!-- Step 5: Install -->
|
<!-- Step 5: Install -->
|
||||||
<section id="step-done" class="step" hidden>
|
<section id="step-done" class="step" hidden>
|
||||||
<div id="build-status" class="info-banner"></div>
|
<p id="build-status" class="install-summary"></p>
|
||||||
|
<div id="existing-tgz-warning" class="warning" hidden>
|
||||||
|
An existing KoboRoot.tgz file was found on your Kobo and has not been applied yet. It will be overwritten.
|
||||||
|
</div>
|
||||||
<details class="log-details">
|
<details class="log-details">
|
||||||
<summary>Build log</summary>
|
<summary>Build log</summary>
|
||||||
<pre id="done-log" class="build-log done-log"></pre>
|
<pre id="done-log" class="build-log done-log"></pre>
|
||||||
@@ -170,9 +182,9 @@
|
|||||||
</main>
|
</main>
|
||||||
|
|
||||||
<!-- wasm_exec.js loaded by patch-worker.js inside the Web Worker -->
|
<!-- wasm_exec.js loaded by patch-worker.js inside the Web Worker -->
|
||||||
<script src="kobo-device.js?ts=1773666969"></script>
|
<script src="kobo-device.js?ts=1773669670"></script>
|
||||||
<script src="kobopatch.js?ts=1773666969"></script>
|
<script src="kobopatch.js?ts=1773669670"></script>
|
||||||
<script src="patch-ui.js?ts=1773666969"></script>
|
<script src="patch-ui.js?ts=1773669670"></script>
|
||||||
<script src="app.js?ts=1773666969"></script>
|
<script src="app.js?ts=1773669670"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -76,19 +76,9 @@ function getDevicesForVersion(version) {
|
|||||||
const versionMap = FIRMWARE_DOWNLOADS[version];
|
const versionMap = FIRMWARE_DOWNLOADS[version];
|
||||||
if (!versionMap) return [];
|
if (!versionMap) return [];
|
||||||
const devices = [];
|
const devices = [];
|
||||||
const seen = {};
|
|
||||||
for (const prefix of Object.keys(versionMap)) {
|
for (const prefix of Object.keys(versionMap)) {
|
||||||
const model = KOBO_MODELS[prefix] || 'Unknown (' + prefix + ')';
|
const model = KOBO_MODELS[prefix] || 'Unknown';
|
||||||
// Track duplicates to disambiguate with serial prefix
|
devices.push({ prefix, model: model + ' (' + prefix + ')' });
|
||||||
if (seen[model]) seen[model].push(prefix);
|
|
||||||
else seen[model] = [prefix];
|
|
||||||
}
|
|
||||||
for (const prefix of Object.keys(versionMap)) {
|
|
||||||
const model = KOBO_MODELS[prefix] || 'Unknown (' + prefix + ')';
|
|
||||||
const label = seen[model].length > 1
|
|
||||||
? model + ' (serial ' + prefix + '...)'
|
|
||||||
: model;
|
|
||||||
devices.push({ prefix, model: label });
|
|
||||||
}
|
}
|
||||||
return devices;
|
return devices;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ async function loadWasm() {
|
|||||||
|
|
||||||
const go = new Go();
|
const go = new Go();
|
||||||
const result = await WebAssembly.instantiateStreaming(
|
const result = await WebAssembly.instantiateStreaming(
|
||||||
fetch('kobopatch.wasm?ts=1773666969'),
|
fetch('kobopatch.wasm?ts=1773669670'),
|
||||||
go.importObject
|
go.importObject
|
||||||
);
|
);
|
||||||
go.run(result.instance);
|
go.run(result.instance);
|
||||||
|
|||||||
@@ -213,17 +213,13 @@ button:disabled {
|
|||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
button.btn-success {
|
button.btn-success,
|
||||||
background: var(--success-text);
|
|
||||||
border-color: var(--success-text);
|
|
||||||
color: #fff;
|
|
||||||
opacity: 1;
|
|
||||||
cursor: default;
|
|
||||||
}
|
|
||||||
|
|
||||||
button.btn-success:hover {
|
button.btn-success:hover {
|
||||||
background: var(--success-text);
|
background: var(--success-text);
|
||||||
border-color: var(--success-text);
|
border-color: var(--success-text);
|
||||||
|
color: #fff;
|
||||||
|
cursor: default;
|
||||||
|
opacity: 0.7;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Cards */
|
/* Cards */
|
||||||
@@ -433,6 +429,7 @@ input[type="file"] {
|
|||||||
|
|
||||||
#build-actions {
|
#build-actions {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
gap: 0.75rem;
|
gap: 0.75rem;
|
||||||
margin-top: 1.25rem;
|
margin-top: 1.25rem;
|
||||||
}
|
}
|
||||||
@@ -541,6 +538,14 @@ input[type="file"] {
|
|||||||
color: var(--text-secondary);
|
color: var(--text-secondary);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Install summary */
|
||||||
|
.install-summary {
|
||||||
|
font-size: 0.93rem;
|
||||||
|
color: var(--text);
|
||||||
|
line-height: 1.6;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
/* Install instructions */
|
/* Install instructions */
|
||||||
.install-instructions {
|
.install-instructions {
|
||||||
margin-top: 1rem;
|
margin-top: 1rem;
|
||||||
|
|||||||
Reference in New Issue
Block a user