ui: CHANGE icons in frontend #31

This commit is contained in:
Caffeine Fueled 2026-09-02 17:03:29 +02:00
parent 082a9f81d7
commit 8dbe149970
Signed by: cf7
GPG key ID: CA295D643074C68C

43
app.py
View file

@ -207,10 +207,12 @@ HTML = """<!doctype html>
header { display:flex; justify-content:space-between; align-items:center; margin-bottom: .5rem; flex-shrink: 0; } header { display:flex; justify-content:space-between; align-items:center; margin-bottom: .5rem; flex-shrink: 0; }
a,button { padding:.35rem 0; text-decoration:none; border:1px solid var(--border); border-radius:4px; background:var(--btn-bg); color:var(--text); cursor:pointer; font-size:.9rem; font-weight:bold; min-width:2rem; text-align:center; display:inline-block; } a,button { padding:.35rem 0; text-decoration:none; border:1px solid var(--border); border-radius:4px; background:var(--btn-bg); color:var(--text); cursor:pointer; font-size:.9rem; font-weight:bold; min-width:2rem; text-align:center; display:inline-block; }
a:hover,button:hover { background:var(--btn-hover); } a:hover,button:hover { background:var(--btn-hover); }
#lock-btn { font-weight:normal; } /* Icon buttons: inline SVG so glyphs render the same on every platform */
.ibtn { display:inline-flex; align-items:center; justify-content:center; width:2rem; height:2rem; padding:0; }
.ic { width:1.05rem; height:1.05rem; fill:none; stroke:currentColor; stroke-width:2; stroke-linecap:round; stroke-linejoin:round; pointer-events:none; }
#status { font-size:.9rem; opacity:.7; margin-left:.5rem; } #status { font-size:.9rem; opacity:.7; margin-left:.5rem; }
#status::before { content: "●"; margin-right: .3rem; color: #ef4444; } #status::before { content:""; display:inline-block; width:.55em; height:.55em; border-radius:50%; margin-right:.35rem; background:#ef4444; }
#status.connected::before { color: #22c55e; } #status.connected::before { background:#22c55e; }
#peers { font-size:.95rem; font-weight:bold; margin-left:.5rem; margin-right:.3rem; color:#22c55e; display:none; } #peers { font-size:.95rem; font-weight:bold; margin-left:.5rem; margin-right:.3rem; color:#22c55e; display:none; }
#wrap { display:grid; grid-template-columns: max-content 1fr; border:1px solid var(--border); border-radius:4px; overflow:hidden; #wrap { display:grid; grid-template-columns: max-content 1fr; border:1px solid var(--border); border-radius:4px; overflow:hidden;
flex: 1; } flex: 1; }
@ -243,16 +245,25 @@ HTML = """<!doctype html>
#auth-submit { width:100%; padding:.45rem; background:#000; color:#fff; border:none; #auth-submit { width:100%; padding:.45rem; background:#000; color:#fff; border:none;
border-radius:4px; font-size:.95rem; cursor:pointer; } border-radius:4px; font-size:.95rem; cursor:pointer; }
</style> </style>
<svg width="0" height="0" style="position:absolute" aria-hidden="true" focusable="false"><defs>
<symbol id="i-copy" viewBox="0 0 24 24"><rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></symbol>
<symbol id="i-check" viewBox="0 0 24 24"><path d="M20 6 9 17l-5-5"/></symbol>
<symbol id="i-plus" viewBox="0 0 24 24"><path d="M12 5v14M5 12h14"/></symbol>
<symbol id="i-lock" viewBox="0 0 24 24"><rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></symbol>
<symbol id="i-moon" viewBox="0 0 24 24"><path d="M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z"/></symbol>
<symbol id="i-sun" viewBox="0 0 24 24"><circle cx="12" cy="12" r="4"/><path d="M12 2v2M12 20v2M4.9 4.9l1.4 1.4M17.7 17.7l1.4 1.4M2 12h2M20 12h2M6.3 17.7l-1.4 1.4M19.1 4.9l-1.4 1.4"/></symbol>
<symbol id="i-info" viewBox="0 0 24 24"><circle cx="12" cy="12" r="10"/><path d="M12 16v-4M12 8h.01"/></symbol>
</defs></svg>
<header> <header>
<div> <div>
<strong id="padname"></strong><span id="peers"></span><span id="status">disconnected</span> <strong id="padname"></strong><span id="peers"></span><span id="status">disconnected</span>
</div> </div>
<div style="position:relative; display:flex; align-items:center; gap:.25rem;"> <div style="position:relative; display:flex; align-items:center; gap:.25rem;">
<button id="copy" onclick="copyToClipboard()" title="Copy to clipboard"></button> <button id="copy" class="ibtn" onclick="copyToClipboard()" title="Copy to clipboard" aria-label="Copy to clipboard"><svg class="ic"><use href="#i-copy"/></svg></button>
<a id="newpad" href="/" target="_blank" title="Opens a new pad in a new tab">+</a> <a id="newpad" class="ibtn" href="/" target="_blank" title="Opens a new pad in a new tab" aria-label="New pad"><svg class="ic"><use href="#i-plus"/></svg></a>
<button id="lock-btn" onclick="togglePwPanel()" title="No password click to set one">🔒</button> <button id="lock-btn" class="ibtn" onclick="togglePwPanel()" title="No password click to set one"><svg class="ic"><use href="#i-lock"/></svg></button>
<button id="theme-btn" onclick="toggleTheme()" title="Toggle dark/light mode"></button> <button id="theme-btn" class="ibtn" onclick="toggleTheme()" title="Toggle dark/light mode" aria-label="Toggle dark/light mode"><svg class="ic"><use href="#i-moon"/></svg></button>
<a id="info" href="/system/info" title="System info"></a> <a id="info" class="ibtn" href="/system/info" title="System info" aria-label="System info"><svg class="ic"><use href="#i-info"/></svg></a>
<div id="pw-panel"> <div id="pw-panel">
<label>Password protection</label> <label>Password protection</label>
<input id="pw-input" type="password" placeholder="New password…" onkeydown="if(event.key==='Enter')setPassword()"/> <input id="pw-input" type="password" placeholder="New password…" onkeydown="if(event.key==='Enter')setPassword()"/>
@ -282,6 +293,7 @@ HTML = """<!doctype html>
<script> <script>
const $ = s => document.querySelector(s); const $ = s => document.querySelector(s);
const setIcon = (el, name) => el.querySelector("use").setAttribute("href", "#i-" + name);
const proto = location.protocol === "https:" ? "wss" : "ws"; const proto = location.protocol === "https:" ? "wss" : "ws";
const rand = () => { const rand = () => {
const arr = new Uint8Array(8); const arr = new Uint8Array(8);
@ -293,7 +305,7 @@ const rand = () => {
// Theme // Theme
function applyTheme(dark) { function applyTheme(dark) {
document.documentElement.setAttribute('data-theme', dark ? 'dark' : 'light'); document.documentElement.setAttribute('data-theme', dark ? 'dark' : 'light');
$('#theme-btn').textContent = dark ? '' : ''; setIcon($('#theme-btn'), dark ? 'sun' : 'moon');
} }
function toggleTheme() { function toggleTheme() {
const isDark = document.documentElement.getAttribute('data-theme') === 'dark'; const isDark = document.documentElement.getAttribute('data-theme') === 'dark';
@ -376,11 +388,9 @@ function removePassword() {
function updateLockBtn() { function updateLockBtn() {
const btn = $("#lock-btn"); const btn = $("#lock-btn");
if (isProtected) { if (isProtected) {
btn.textContent = "🔒︎";
btn.classList.add("locked"); btn.classList.add("locked");
btn.title = "Password protected click to manage"; btn.title = "Password protected click to manage";
} else { } else {
btn.textContent = "🔒︎";
btn.classList.remove("locked"); btn.classList.remove("locked");
btn.title = "No password click to set one"; btn.title = "No password click to set one";
} }
@ -478,19 +488,14 @@ $("#newpad").addEventListener("click", (e) => { e.preventDefault(); window.open(
async function copyToClipboard() { async function copyToClipboard() {
try { try {
await navigator.clipboard.writeText(ta.value); await navigator.clipboard.writeText(ta.value);
const btn = $("#copy");
const original = btn.textContent;
btn.textContent = "";
setTimeout(() => { btn.textContent = original; }, 1500);
} catch (err) { } catch (err) {
// Fallback for older browsers // Fallback for older browsers
ta.select(); ta.select();
document.execCommand('copy'); document.execCommand('copy');
const btn = $("#copy");
const original = btn.textContent;
btn.textContent = "";
setTimeout(() => { btn.textContent = original; }, 1500);
} }
const btn = $("#copy");
setIcon(btn, "check");
setTimeout(() => setIcon(btn, "copy"), 1500);
} }
// Adjust cursor position after a remote text update. // Adjust cursor position after a remote text update.