Files
GameList/wwwroot/js/ui-utils.js

84 lines
2.4 KiB
JavaScript

import { t } from "./i18n.js";
import { state } from "./state.js";
export const sortByName = (items) =>
(items ?? [])
.slice()
.sort((a, b) => a.name.localeCompare(b.name, undefined, { sensitivity: "base" }));
export const truncate = (text, max) => {
if (!text) return "";
return text.length > max ? `${text.slice(0, max - 1)}...` : text;
};
export const escapeHtml = (value) =>
(value ?? "")
.toString()
.replace(/&/g, "&")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
.replace(/"/g, "&quot;")
.replace(/'/g, "&#39;");
export const safeUrl = (url) => {
if (!url) return null;
try {
const u = new URL(url);
if (u.protocol === "http:" || u.protocol === "https:") return u.href;
} catch {
return null;
}
return null;
};
export const cssEscapeUrl = (url) => url.replace(/['")\\]/g, "\\$&");
export function linkRootId(s) {
return s?.parentSuggestionId ?? s?.id;
}
export function linkedPeerIds(s) {
if (!s) return [];
if (Array.isArray(s.linkedIds) && s.linkedIds.length > 0) {
return s.linkedIds.filter((id) => id !== s.id);
}
if (!state.allSuggestions?.length) return [];
const root = linkRootId(s);
return state.allSuggestions
.filter((other) => linkRootId(other) === root && other.id !== s.id)
.map((other) => other.id);
}
export function linkedPeerTitles(s) {
if (!s) return [];
if (Array.isArray(s.linkedTitles) && s.linkedTitles.length > 0) {
return s.linkedTitles;
}
if (!state.allSuggestions?.length) return [];
const root = linkRootId(s);
return state.allSuggestions
.filter((other) => linkRootId(other) === root && other.id !== s.id)
.map((other) => other.name);
}
export function isLinked(s) {
return !!s?.parentSuggestionId || linkedPeerIds(s).length > 0;
}
export function linkTooltip(s) {
const peers = linkedPeerTitles(s);
if (peers.length === 0) return t("card.linked");
return t("card.linkedWith", { names: peers.join(", ") });
}
export function renderLinkBadge(s) {
if (!isLinked(s)) return "";
return `<span class="chip icon link-chip" title="${escapeHtml(linkTooltip(s))}">🔗</span>`;
}
export function buildLinkOptionLabel(s) {
const author = s.author ? ` - ${s.author}` : "";
const linked = isLinked(s) ? " 🔗" : "";
return `${s.name}${author}${linked}`;
}