BUILD130 — 4 цвета + HEX/RGB ввод

This commit is contained in:
2026-09-10 11:20:08 +03:00
parent a9278b5251
commit 837d40d6ce
7 changed files with 70 additions and 12 deletions

View File

@@ -80,6 +80,23 @@
return color || "#FFFFFF";
};
const teamColorHexToRgb = (value) => {
const color = normalizeTeamColorHex(value);
if (!color) return "";
return [1, 3, 5].map((offset) => parseInt(color.slice(offset, offset + 2), 16)).join(", ");
};
const teamColorRgbToHex = (value) => {
let raw = String(value ?? "").trim();
if (!raw) return "";
raw = raw.replace(/^rgb\s*\(/i, "").replace(/\)$/, "").trim();
const parts = raw.includes(",") ? raw.split(",") : raw.split(/\s+/);
if (parts.length !== 3) return "";
const rgb = parts.map((part) => Number(String(part).trim()));
if (rgb.some((part) => !Number.isInteger(part) || part < 0 || part > 255)) return "";
return `#${rgb.map((part) => part.toString(16).padStart(2, "0")).join("").toUpperCase()}`;
};
const teamColorFieldName = (index) => index === 1 ? "color_hex" : `color_${index}_hex`;
const teamColorEnabledName = (index) => index === 1 ? "color_enabled" : `color_${index}_enabled`;
@@ -102,14 +119,15 @@
<i data-team-color-preview="${index}" style="--team-color:${escapeHtml(teamColorPreview(value))}"></i>
<input type="color" data-team-color-picker="${index}" value="${escapeHtml(teamColorPreview(value))}" tabindex="-1" aria-label="Выбрать цвет ${index} команды">
</button>
<input ${fieldNameAttr} data-team-color-text="${index}" maxlength="7" placeholder="#282E66" value="${escapeHtml(value)}" autocomplete="off" spellcheck="false">
<label class="hockey-team-color-value"><small>HEX</small><input ${fieldNameAttr} data-team-color-text="${index}" maxlength="7" placeholder="#282E66" value="${escapeHtml(value)}" autocomplete="off" spellcheck="false"></label>
<label class="hockey-team-color-value"><small>RGB</small><input data-team-color-rgb="${index}" maxlength="18" placeholder="40, 46, 102" value="${escapeHtml(teamColorHexToRgb(value))}" autocomplete="off" spellcheck="false"></label>
<button type="button" class="hockey-team-color-clear" data-team-color-clear="${index}" title="Очистить цвет ${index}">×</button>
</div>
</div>
`;
};
const teamColorsCellMarkup = (item) => [1, 2, 3].map((index) => {
const teamColorsCellMarkup = (item) => [1, 2, 3, 4].map((index) => {
const field = teamColorFieldName(index);
const enabledField = teamColorEnabledName(index);
const value = normalizeTeamColorHex(item?.[field]);
@@ -420,12 +438,13 @@
<div class="hockey-team-color-field">
<div class="hockey-team-color-field-head">
<span>Цвета команды</span>
<small>HEX можно сохранить заранее, а галочкой отдельно включать/выключать цвет в данных Mapping.</small>
<small>Цвет можно выбрать мышкой или ввести вручную в HEX / RGB; галочка отдельно включает или выключает его в Mapping.</small>
</div>
<div class="hockey-team-colors-grid">
${teamColorEditorMarkup(editing, 1)}
${teamColorEditorMarkup(editing, 2)}
${teamColorEditorMarkup(editing, 3)}
${teamColorEditorMarkup(editing, 4)}
</div>
</div>
<label class="hockey-directory-check"><input type="checkbox" name="active" ${editing?.active === false ? "" : "checked"}><span>Активна</span></label>
@@ -3126,6 +3145,7 @@
const item = modal.querySelector(`[data-team-color-item="${index}"]`);
const colorText = modal.querySelector(`[data-team-color-text="${index}"]`);
const colorPicker = modal.querySelector(`[data-team-color-picker="${index}"]`);
const colorRgb = modal.querySelector(`[data-team-color-rgb="${index}"]`);
const colorPreview = modal.querySelector(`[data-team-color-preview="${index}"]`);
const colorEnabled = modal.querySelector(`[data-team-color-enabled="${index}"]`);
const enabledCaption = item?.querySelector(".hockey-team-color-enabled small");
@@ -3139,6 +3159,7 @@
if (normalized) {
if (colorText && (commit || colorText.value !== rawValue)) colorText.value = normalized;
if (colorPicker) colorPicker.value = normalized;
if (colorRgb) colorRgb.value = teamColorHexToRgb(normalized);
if (colorPreview) colorPreview.style.setProperty("--team-color", normalized);
return normalized;
}
@@ -3148,6 +3169,7 @@
if (!String(rawValue || "").trim()) {
if (colorText && commit) colorText.value = "";
if (colorPicker) colorPicker.value = "#FFFFFF";
if (colorRgb && commit) colorRgb.value = "";
if (colorPreview) colorPreview.style.setProperty("--team-color", "#FFFFFF");
}
return "";
@@ -3167,9 +3189,28 @@
if (normalized) syncTeamColorUi(normalized);
});
colorText?.addEventListener("blur", () => syncTeamColorUi(colorText.value, { commit: true }));
colorRgb?.addEventListener("input", () => {
const normalized = teamColorRgbToHex(colorRgb.value);
if (normalized) syncTeamColorUi(normalized);
});
colorRgb?.addEventListener("blur", () => {
const raw = String(colorRgb.value || "").trim();
if (!raw) {
colorRgb.value = teamColorHexToRgb(colorText?.value || "");
return;
}
const normalized = teamColorRgbToHex(raw);
if (!normalized) {
setStatus(`RGB цвета ${index} должен содержать три целых числа 0255, например 40, 46, 102`, true);
colorRgb.focus();
return;
}
syncTeamColorUi(normalized, { commit: true });
});
colorEnabled?.addEventListener("change", updateEnabledUi);
modal.querySelector(`[data-team-color-clear="${index}"]`)?.addEventListener("click", () => {
if (colorText) colorText.value = "";
if (colorRgb) colorRgb.value = "";
if (colorEnabled) colorEnabled.checked = false;
updateEnabledUi();
syncTeamColorUi("", { commit: true });
@@ -3177,14 +3218,14 @@
});
updateEnabledUi();
};
[1, 2, 3].forEach(bindTeamColor);
[1, 2, 3, 4].forEach(bindTeamColor);
modal.querySelector("[data-team-form]")?.addEventListener("submit", async (event) => {
event.preventDefault();
const form = event.currentTarget;
const values = new FormData(form);
const normalizedColors = {};
for (const index of [1, 2, 3]) {
for (const index of [1, 2, 3, 4]) {
const field = teamColorFieldName(index);
const enabledField = teamColorEnabledName(index);
const raw = String(values.get(field) || "").trim();
@@ -3214,6 +3255,8 @@
color_2_enabled: normalizedColors.color_2_enabled,
color_3_hex: normalizedColors.color_3_hex,
color_3_enabled: normalizedColors.color_3_enabled,
color_4_hex: normalizedColors.color_4_hex,
color_4_enabled: normalizedColors.color_4_enabled,
logo_url: values.get("logo_url") || "",
active: values.has("active"),
};