Add analyzer and frontend lint guardrails
This commit is contained in:
@@ -10,7 +10,6 @@ import {
|
||||
escapeHtml,
|
||||
isLinked,
|
||||
linkedPeerTitles,
|
||||
renderLinkBadge,
|
||||
safeUrl,
|
||||
sortByName,
|
||||
} from "./ui-utils.js";
|
||||
@@ -23,7 +22,9 @@ function updateSuggestButtonState() {
|
||||
const count = state.mySuggestions?.length ?? 0;
|
||||
const blocked = count >= limit;
|
||||
btn.disabled = blocked || state.phase !== "Suggest";
|
||||
btn.textContent = blocked ? t("suggest.maxReached") : t("suggest.addButton");
|
||||
btn.textContent = blocked
|
||||
? t("suggest.maxReached")
|
||||
: t("suggest.addButton");
|
||||
}
|
||||
|
||||
export function renderMySuggestions() {
|
||||
@@ -35,7 +36,12 @@ export function renderMySuggestions() {
|
||||
const allowDelete = state.phase === "Suggest" || state.me?.isAdmin;
|
||||
sortByName(state.mySuggestions).forEach((s) =>
|
||||
wrap.appendChild(
|
||||
buildCard(s, { showAuthor: false, allowDelete, allowEdit, lockTitle }),
|
||||
buildCard(s, {
|
||||
showAuthor: false,
|
||||
allowDelete,
|
||||
allowEdit,
|
||||
lockTitle,
|
||||
}),
|
||||
),
|
||||
);
|
||||
updateSuggestButtonState();
|
||||
@@ -69,7 +75,12 @@ export function renderPhaseTitles() {
|
||||
|
||||
export function buildCard(
|
||||
s,
|
||||
{ showAuthor = false, allowDelete = false, allowEdit = false, lockTitle = false },
|
||||
{
|
||||
showAuthor = false,
|
||||
allowDelete = false,
|
||||
allowEdit = false,
|
||||
lockTitle = false,
|
||||
},
|
||||
) {
|
||||
const card = document.createElement("article");
|
||||
card.className = "game-card";
|
||||
@@ -92,9 +103,10 @@ export function buildCard(
|
||||
const linkChip = linked
|
||||
? `<button class="chip icon link-chip${state.me?.isAdmin ? " link-chip-action" : ""}" data-unlink="${s.id}" type="button" title="${linkTooltipSafe}">🔗</button>`
|
||||
: "";
|
||||
const visual = hasImage && safeShot
|
||||
? `<button class="card-visual" data-img="${safeShot}" aria-label="${t("card.openScreenshot")}" style="background-image:url('${cssEscapeUrl(safeShot)}')"></button>`
|
||||
: `<div class="card-visual"></div>`;
|
||||
const visual =
|
||||
hasImage && safeShot
|
||||
? `<button class="card-visual" data-img="${safeShot}" aria-label="${t("card.openScreenshot")}" style="background-image:url('${cssEscapeUrl(safeShot)}')"></button>`
|
||||
: `<div class="card-visual"></div>`;
|
||||
const hasPlayers = s.minPlayers || s.maxPlayers;
|
||||
const players = hasPlayers
|
||||
? `${t("card.players", {
|
||||
@@ -252,9 +264,13 @@ function buildSuggestionForm(initial = {}, lockTitle = false) {
|
||||
return form;
|
||||
|
||||
function initCharCounters(formEl) {
|
||||
const inputs = formEl.querySelectorAll("input[maxlength], textarea[maxlength]");
|
||||
const inputs = formEl.querySelectorAll(
|
||||
"input[maxlength], textarea[maxlength]",
|
||||
);
|
||||
inputs.forEach((input) => {
|
||||
const counter = formEl.querySelector(`.char-counter[data-for="${input.name}"]`);
|
||||
const counter = formEl.querySelector(
|
||||
`.char-counter[data-for="${input.name}"]`,
|
||||
);
|
||||
if (!counter) return;
|
||||
const update = () => {
|
||||
const max = input.maxLength;
|
||||
@@ -268,7 +284,13 @@ function buildSuggestionForm(initial = {}, lockTitle = false) {
|
||||
}
|
||||
}
|
||||
|
||||
function openSuggestionModal({ title, submitLabel, initial = {}, onSubmit, lockTitle = false }) {
|
||||
function openSuggestionModal({
|
||||
title,
|
||||
submitLabel,
|
||||
initial = {},
|
||||
onSubmit,
|
||||
lockTitle = false,
|
||||
}) {
|
||||
const overlay = document.createElement("div");
|
||||
overlay.className = "edit-modal";
|
||||
const panel = document.createElement("div");
|
||||
@@ -323,7 +345,8 @@ function openSuggestionModal({ title, submitLabel, initial = {}, onSubmit, lockT
|
||||
clearError();
|
||||
const min = data.minPlayers;
|
||||
const max = data.maxPlayers;
|
||||
const inRange = (v) => v == null || (Number.isInteger(v) && v >= 1 && v <= 32);
|
||||
const inRange = (v) =>
|
||||
v == null || (Number.isInteger(v) && v >= 1 && v <= 32);
|
||||
const valid =
|
||||
inRange(min) &&
|
||||
inRange(max) &&
|
||||
@@ -450,7 +473,9 @@ function openDeleteConfirmModal(s) {
|
||||
|
||||
function openUnlinkConfirm(s) {
|
||||
const peers = linkedPeerTitles(s);
|
||||
const names = peers.length ? peers.join(", ") : t("admin.unlinkUnknownPeers");
|
||||
const names = peers.length
|
||||
? peers.join(", ")
|
||||
: t("admin.unlinkUnknownPeers");
|
||||
openConfirmModal({
|
||||
title: t("admin.unlinkTitle"),
|
||||
body: t("admin.unlinkBody", { name: s.name, peers: names }),
|
||||
|
||||
Reference in New Issue
Block a user