Add show/hide Link + QR toggles for every SimpleX link (default hidden)

Reusable link box (Jinja macro in _macros.html + shared JS/CSS/QR lib in
base.html): a 'Link' button toggles the URL (with copy) and a 'QR' button toggles
a lazily-rendered QR of the same link — both hidden by default. Applied to the
profile address, profile groups & channels, and the profile cards on the list
pages. Centralize robustCopy in base.html; drop the per-page duplicates and the
old async group-link fetch (groups now use their known link).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Jon
2026-06-05 22:46:26 +01:00
parent 3456ed9411
commit 332b4a1801
4 changed files with 93 additions and 100 deletions

View File

@@ -16,6 +16,7 @@
<link rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;700&display=swap" rel="stylesheet">
<script src="https://unpkg.com/htmx.org@1.9.12/dist/htmx.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/qrcode/build/qrcode.min.js"></script>
<script>
document.addEventListener('htmx:configRequest', function(evt) {
const m = document.cookie.match(/(?:^|;\s*)token=([^;]+)/);
@@ -279,6 +280,20 @@
dialog { background: var(--card); color: var(--text); border: 1px solid var(--border);
border-radius: 12px; padding: 28px; max-width: 480px; width: 90%; }
dialog::backdrop { background: rgba(0,0,0,0.5); }
/* reusable SimpleX link box: Link + QR toggles, both hidden by default */
.lb-btn { display: inline-flex; align-items: center; gap: 6px;
padding: 4px 10px; font-size: 12px; font-weight: 600; border-radius: 6px;
background: transparent; border: 1px solid var(--border); color: var(--accent);
cursor: pointer; font-family: inherit; }
.lb-btn:hover { background: var(--bg); }
.lb-btn.on { background: var(--accent); color: var(--btn-light-text); border-color: var(--accent); }
.lb-link { display: flex; align-items: center; gap: 8px; margin-top: 8px; }
.lb-link .addr-link { flex: 1; min-width: 0; color: var(--muted); font-family: monospace;
font-size: 12px; text-decoration: none; word-break: break-all; }
.lb-link .addr-link:hover { color: var(--accent); text-decoration: underline; }
.lb-qr { margin-top: 10px; }
.lb-qr canvas { background: #fff; border-radius: 8px; padding: 8px; }
</style>
{% block head %}{% endblock %}
</head>
@@ -347,6 +362,46 @@
localStorage.setItem('sidebar-collapsed', collapsed ? '1' : '');
}
// Clipboard that also works over plain-HTTP LAN (navigator.clipboard needs a secure context).
function robustCopy(text) {
if (navigator.clipboard && window.isSecureContext) {
return navigator.clipboard.writeText(text).catch(() => fallbackCopy(text));
}
return Promise.resolve(fallbackCopy(text));
}
function fallbackCopy(text) {
const ta = document.createElement('textarea');
ta.value = text; ta.style.position = 'fixed'; ta.style.opacity = '0';
document.body.appendChild(ta); ta.focus(); ta.select();
try { document.execCommand('copy'); } catch (e) {}
document.body.removeChild(ta);
}
function flashCheck(btn) {
const o = btn.innerHTML;
btn.innerHTML = '<i class="fa-solid fa-check"></i>';
setTimeout(() => btn.innerHTML = o, 1500);
}
// Reusable SimpleX link box: Link + QR toggles (both hidden by default).
function _sxUrl(id) { const a = document.getElementById('lb-url-' + id); return a ? a.getAttribute('href') : ''; }
function sxToggleLink(id, btn) {
const el = document.getElementById('lb-link-' + id); if (!el) return;
const show = el.style.display === 'none';
el.style.display = show ? '' : 'none';
btn.classList.toggle('on', show);
}
function sxToggleQr(id, btn) {
const w = document.getElementById('lb-qr-' + id); if (!w) return;
const show = w.style.display === 'none';
w.style.display = show ? '' : 'none';
btn.classList.toggle('on', show);
if (show && !w.dataset.r && window.QRCode) {
QRCode.toCanvas(document.getElementById('lb-qrc-' + id), _sxUrl(id), {width: 180}, () => {});
w.dataset.r = '1';
}
}
function sxCopy(id, btn) { robustCopy(_sxUrl(id)).then(() => flashCheck(btn)); }
// Sidebar clock: 24h time + day-of-week date
function tickClock() {
const now = new Date();