feat(health): tile opens local/remote URL with one-click alt + LAN-only marker

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
root
2026-06-08 00:57:48 +10:00
parent a3662f6ff2
commit d91e5e75c8
3 changed files with 55 additions and 4 deletions

View File

@@ -1,11 +1,33 @@
import { el, safeHref } from '../dom.js';
export function serviceTile(s) {
import { isRemoteHost, pickServiceUrls } from '../views/service_url.js';
// `remote` is injected by the caller (defaults to detecting from the current host) so
// the component stays unit-testable without stubbing window.location.
export function serviceTile(s, remote = isRemoteHost(location.hostname)) {
const { primary, alt, lanOnly } = pickServiceUrls(s, remote);
const img = el('img', { class: 'tile-icon', loading: 'lazy', src: `/api/icons/${s.icon}.png`, alt: s.name });
img.onerror = () => img.replaceWith(el('div', { class: 'tile-icon-fb' }, (s.name[0] || '?').toUpperCase()));
return el('a', { class: `tile status-${s.status}`, href: safeHref(s.url), target: '_blank', rel: 'noreferrer' },
// Root is a div so we can host two sibling <a>s (a stretched primary link + a small
// alt) without nesting anchors (invalid HTML).
const tile = el('div', { class: `tile status-${s.status}${lanOnly ? ' lan-only' : ''}` },
img,
el('div', { class: 'tile-main' },
el('div', { class: 'tile-nm' }, el('span', { class: 'dot' }), s.name),
el('div', { class: 'tile-host' }, s.host || '')),
el('span', { class: 'tile-go' }, 'open ↗'));
el('span', { class: 'tile-go' }, 'open ↗'),
// Stretched primary link covers the whole tile (see .tile-link in style.css).
el('a', { class: 'tile-link', href: safeHref(primary), target: '_blank', rel: 'noreferrer',
'aria-label': `Open ${s.name}` }));
if (lanOnly) tile.appendChild(el('span', { class: 'tile-lan', title: 'Not reachable remotely' }, 'LAN-only'));
if (alt) {
tile.appendChild(el('a', {
class: 'tile-alt', href: safeHref(alt), target: '_blank', rel: 'noreferrer',
title: remote ? 'Open via LAN' : 'Open via domain',
}, '⇄'));
}
return tile;
}