import { el, safeHref } from '../dom.js'; 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())); // Root is a div so we can host two sibling 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 ↗'), // 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; }