fixed UI issue

This commit is contained in:
2026-10-30 17:36:45 -07:00
parent 587d70c46a
commit f8aa86eecf
2 changed files with 27 additions and 537 deletions

View File

@@ -167,147 +167,7 @@
transition: width 0.35s cubic-bezier(0.2, 0.8, 0.2, 1);
}
.button-group {
display: flex;
gap: 12px;
width: 100%;
justify-content: center;
margin-top: 6px;
}
.btn-apple {
position: relative;
overflow: hidden;
height: 44px;
min-width: 124px;
padding: 0 24px;
font-size: 14px;
font-weight: 600;
letter-spacing: -0.01em;
white-space: nowrap;
border-radius: 9999px;
border: none;
color: #ffffff;
background: rgba(255, 255, 255, 0.08);
text-shadow: 0 1px 8px rgba(0, 0, 0, 0.25);
cursor: pointer;
transition: translate 0.2s cubic-bezier(0.16, 1, 0.3, 1), scale 0.2s cubic-bezier(0.16, 1, 0.3, 1);
outline: none;
display: flex;
align-items: center;
justify-content: center;
}
.btn-apple:active {
scale: 0.97;
}
.glass-filter {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
pointer-events: none;
opacity: 0;
z-index: -1;
}
.btn-apple.glass-svg {
background: hsl(0 0% 100% / var(--glass-frost, 0));
backdrop-filter: var(--filter-id) saturate(var(--glass-saturation, 1));
}
.btn-apple.glass-frost {
background: transparent;
backdrop-filter: blur(20px) saturate(1.8);
-webkit-backdrop-filter: blur(20px) saturate(1.8);
}
.btn-primary.glass-svg {
background: hsl(0 0% 100% / calc(var(--glass-frost, 0) + 0.14));
}
.btn-primary.glass-frost {
background: rgba(255, 255, 255, 0.24);
}
.files-panel {
width: 100%;
flex-direction: column;
gap: 14px;
margin-bottom: 8px;
}
.files-list {
max-height: 170px;
overflow-y: auto;
text-align: left;
background: rgba(255, 255, 255, 0.06);
border: 1px solid rgba(255, 255, 255, 0.1);
backdrop-filter: blur(20px) saturate(1.5);
-webkit-backdrop-filter: blur(20px) saturate(1.5);
border-radius: 18px;
padding: 8px 14px;
}
.file-row {
display: flex;
align-items: center;
gap: 8px;
padding: 4px 0;
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
font-size: 11px;
color: rgba(255, 255, 255, 0.85);
cursor: pointer;
}
.file-row input[type="checkbox"] {
appearance: none;
-webkit-appearance: none;
flex-shrink: 0;
width: 16px;
height: 16px;
margin: 0;
border-radius: 5px;
border: 1px solid rgba(255, 255, 255, 0.35);
background-color: rgba(255, 255, 255, 0.08);
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M3.5 8.5l3 3 6-7' fill='none' stroke='%23111' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
background-repeat: no-repeat;
background-position: center;
background-size: 0 0;
cursor: pointer;
outline: none;
transition: background-color 0.18s ease, border-color 0.18s ease, background-size 0.18s cubic-bezier(0.2, 0.8, 0.2, 1), box-shadow 0.18s ease;
}
.file-row:hover input[type="checkbox"] {
background-color: rgba(255, 255, 255, 0.16);
}
.file-row input[type="checkbox"]:checked {
background-color: rgba(255, 255, 255, 0.95);
border-color: transparent;
background-size: 11px 11px;
}
.file-row input[type="checkbox"]:active {
transform: scale(0.92);
}
.file-name {
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.file-tag {
font-size: 10px;
padding: 1px 8px;
border-radius: 9999px;
background: rgba(255, 255, 255, 0.25);
color: #ffffff;
}
#debug-log-box {
display: none;
@@ -346,21 +206,6 @@
<div class="progress-fill" id="progress-fill"></div>
</div>
<div class="files-panel" id="files-panel" style="display: none;">
<div class="files-list" id="files-list"></div>
<div class="button-group">
<button class="btn-apple btn-primary" id="btn-files-apply">Apply Selected</button>
<button class="btn-apple btn-secondary" id="btn-files-skip">Skip</button>
</div>
</div>
<div class="button-group" id="sdk-actions" style="display: none;">
<button class="btn-apple btn-primary" id="btn-sdk-yes">Update SDK</button>
<button class="btn-apple btn-secondary" id="btn-sdk-no">Skip</button>
</div>
<div class="button-group" id="update-actions" style="display: none;">
<button class="btn-apple btn-primary" id="btn-update-yes">Update Now</button>
<button class="btn-apple btn-secondary" id="btn-update-no">Skip</button>
</div>
</div>
</div>
@@ -1008,18 +853,7 @@ void main() {
const progressTrack = document.getElementById("progress-track");
const progressFill = document.getElementById("progress-fill");
const fileLine = document.getElementById("file-line");
const actionsEl = document.getElementById("update-actions");
const btnYes = document.getElementById("btn-update-yes");
const btnNo = document.getElementById("btn-update-no");
const debugBox = document.getElementById("debug-log-box");
const filesPanel = document.getElementById("files-panel");
const filesList = document.getElementById("files-list");
const sdkActions = document.getElementById("sdk-actions");
const btnFilesApply = document.getElementById("btn-files-apply");
const btnFilesSkip = document.getElementById("btn-files-skip");
const btnSdkYes = document.getElementById("btn-sdk-yes");
const btnSdkNo = document.getElementById("btn-sdk-no");
let pendingToken = null;
function setStatus(text, color = "rgba(255, 255, 255, 0.95)") {
if (!statusEl) return;
@@ -1036,8 +870,14 @@ void main() {
}
function setProgress(pct) {
if (progressTrack) progressTrack.style.display = "block";
if (progressFill) progressFill.style.width = Math.min(100, Math.max(0, pct)) + "%";
if (!progressTrack) return;
if (pct > 0) {
progressTrack.style.display = "block";
if (progressFill) progressFill.style.width = Math.min(100, Math.max(0, pct)) + "%";
} else {
progressTrack.style.display = "none";
if (progressFill) progressFill.style.width = "0%";
}
}
function showDebug(msg) {
@@ -1078,56 +918,10 @@ void main() {
}
});
eventApi.listen("update-available", (e) => {
const data = e.payload || e;
if (data && data.latest) {
if (progressTrack) progressTrack.style.display = "none";
setStatus(`Update Available: ${data.latest}`);
if (actionsEl) actionsEl.style.display = "flex";
}
});
eventApi.listen("files-available", (e) => {
const data = e.payload || e;
if (!data || !Array.isArray(data.files)) return;
pendingToken = data.token;
if (progressTrack) progressTrack.style.display = "none";
filesList.innerHTML = "";
data.files.forEach((f) => {
const row = document.createElement("label");
row.className = "file-row";
const cb = document.createElement("input");
cb.type = "checkbox";
cb.checked = true;
cb.value = f.path;
const name = document.createElement("span");
name.className = "file-name";
name.textContent = f.path;
name.title = f.path;
const tag = document.createElement("span");
tag.className = "file-tag";
tag.textContent = f.status;
row.append(cb, name, tag);
filesList.appendChild(row);
});
setStatus(`${data.files.length} file update${data.files.length === 1 ? "" : "s"} found`);
filesPanel.style.display = "flex";
});
eventApi.listen("sdk-available", (e) => {
const data = e.payload || e;
if (!data || !data.latest) return;
pendingToken = data.token;
if (progressTrack) progressTrack.style.display = "none";
setStatus(`SDK update: ${data.current} → ${data.latest}`);
sdkActions.style.display = "flex";
});
eventApi.listen("ready", (e) => {
const data = e.payload || e;
if (data && data.url) {
if (progressTrack) progressTrack.style.display = "none";
if (actionsEl) actionsEl.style.display = "none";
if (fileLine) fileLine.textContent = "";
setStatus("Launching...");
}
@@ -1142,154 +936,8 @@ void main() {
});
}
function answerPrompt(accept, files) {
return fetch("http://127.0.0.1:4891/prompt/answer", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ token: pendingToken, accept, files })
}).catch((err) => {
setStatus("Failed to reach update service", "#ff6b6b");
showDebug(err.message);
});
}
btnFilesApply.addEventListener("click", () => {
const picked = Array.from(filesList.querySelectorAll("input:checked")).map((i) => i.value);
filesPanel.style.display = "none";
setStatus("Applying file updates...");
answerPrompt(picked.length > 0, picked);
});
btnFilesSkip.addEventListener("click", () => {
filesPanel.style.display = "none";
setStatus("Skipping file updates...");
answerPrompt(false, []);
});
btnSdkYes.addEventListener("click", () => {
sdkActions.style.display = "none";
setStatus("Updating SDK...");
answerPrompt(true, []);
});
btnSdkNo.addEventListener("click", () => {
sdkActions.style.display = "none";
setStatus("Skipping SDK update...");
answerPrompt(false, []);
});
btnYes.addEventListener("click", () => {
if (actionsEl) actionsEl.style.display = "none";
setStatus("Starting update installation...");
fetch("http://127.0.0.1:4891/update/yes", { method: "POST" }).catch((err) => {
setStatus("Failed to reach update service", "#ff6b6b");
showDebug(err.message);
});
});
btnNo.addEventListener("click", () => {
if (actionsEl) actionsEl.style.display = "none";
setStatus("Skipping update. Starting services...");
fetch("http://127.0.0.1:4891/update/no", { method: "POST" }).catch(() => { });
});
function applyGlassSurface(el, cfg) {
const c = Object.assign({
borderRadius: 38,
borderWidth: 0.07,
brightness: 50,
opacity: 0.93,
blur: 11,
displace: 0,
backgroundOpacity: 0,
saturation: 1,
distortionScale: -180,
redOffset: 0,
greenOffset: 10,
blueOffset: 20,
mixBlendMode: 'difference'
}, cfg);
const id = 'glass-' + Math.random().toString(36).slice(2, 9);
const ua = navigator.userAgent;
const blocked = (/Safari/.test(ua) && !/Chrome/.test(ua)) || /Firefox/.test(ua);
const probe = document.createElement('div');
probe.style.backdropFilter = 'url(#' + id + ')';
const supported = !blocked && probe.style.backdropFilter !== '';
el.style.setProperty('--glass-frost', c.backgroundOpacity);
el.style.setProperty('--glass-saturation', c.saturation);
if (!supported) {
el.classList.add('glass-frost');
return;
}
const channel = (name, offset, matrix) =>
'<feDisplacementMap in="SourceGraphic" in2="map" scale="' + (c.distortionScale + offset) +
'" xChannelSelector="R" yChannelSelector="G" result="d' + name + '"/>' +
'<feColorMatrix in="d' + name + '" type="matrix" values="' + matrix + '" result="' + name + '"/>';
const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
svg.setAttribute('class', 'glass-filter');
svg.setAttribute('aria-hidden', 'true');
svg.innerHTML =
'<defs><filter id="' + id + '" color-interpolation-filters="sRGB" x="0%" y="0%" width="100%" height="100%">' +
'<feImage x="0" y="0" width="100%" height="100%" preserveAspectRatio="none" result="map"/>' +
channel('r', c.redOffset, '1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0') +
channel('g', c.greenOffset, '0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0') +
channel('b', c.blueOffset, '0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0') +
'<feBlend in="r" in2="g" mode="screen" result="rg"/>' +
'<feBlend in="rg" in2="b" mode="screen" result="out"/>' +
'<feGaussianBlur in="out" stdDeviation="' + c.displace + '"/>' +
'</filter></defs>';
const image = svg.querySelector('feImage');
const redId = id + '-r';
const blueId = id + '-b';
const softId = id + '-s';
const buildMap = () => {
const rect = el.getBoundingClientRect();
const w = Math.round(rect.width) || 120;
const h = Math.round(rect.height) || 44;
const edge = Math.min(w, h) * c.borderWidth * 0.5;
const map =
'<svg width="' + w + '" height="' + h + '" viewBox="0 0 ' + w + ' ' + h + '" xmlns="http://www.w3.org/2000/svg">' +
'<defs>' +
'<linearGradient id="' + redId + '" x1="100%" y1="0%" x2="0%" y2="0%"><stop offset="0%" stop-color="#0000"/><stop offset="100%" stop-color="red"/></linearGradient>' +
'<linearGradient id="' + blueId + '" x1="0%" y1="0%" x2="0%" y2="100%"><stop offset="0%" stop-color="#0000"/><stop offset="100%" stop-color="blue"/></linearGradient>' +
'<filter id="' + softId + '" filterUnits="userSpaceOnUse" x="0" y="0" width="' + w + '" height="' + h + '" color-interpolation-filters="sRGB"><feGaussianBlur stdDeviation="' + c.blur + '"/></filter>' +
'</defs>' +
'<rect x="0" y="0" width="' + w + '" height="' + h + '" fill="black"/>' +
'<rect x="0" y="0" width="' + w + '" height="' + h + '" rx="' + c.borderRadius + '" fill="url(#' + redId + ')"/>' +
'<rect x="0" y="0" width="' + w + '" height="' + h + '" rx="' + c.borderRadius + '" fill="url(#' + blueId + ')" style="mix-blend-mode:' + c.mixBlendMode + '"/>' +
'<rect x="' + edge + '" y="' + edge + '" width="' + (w - edge * 2) + '" height="' + (h - edge * 2) + '" rx="' + c.borderRadius + '" fill="hsl(0 0% ' + c.brightness + '% / ' + c.opacity + ')" filter="url(#' + softId + ')"/>' +
'</svg>';
image.setAttribute('href', 'data:image/svg+xml,' + encodeURIComponent(map));
};
el.appendChild(svg);
el.style.setProperty('--filter-id', 'url(#' + id + ')');
el.classList.add('glass-svg');
buildMap();
new ResizeObserver(buildMap).observe(el);
}
window.addEventListener('DOMContentLoaded', () => {
const glassConfig = {
borderRadius: 50,
distortionScale: -180,
displace: 0.5,
backgroundOpacity: 0.1
};
initTauriEvents();
document.querySelectorAll('.btn-apple').forEach((el) => {
try {
applyGlassSurface(el, glassConfig);
} catch (e) {
el.classList.add('glass-frost');
}
});
try { initGradientAscii(); } catch (e) { }
});
</script>