34 lines
1.6 KiB
JavaScript
34 lines
1.6 KiB
JavaScript
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 <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 ↗'),
|
|
// 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;
|
|
}
|