BUILD126 - легкие правки по интерфейсу
This commit is contained in:
2
app.py
2
app.py
@@ -29,7 +29,7 @@ from ui_builder import install_ui_builder
|
|||||||
from khl_site.khl_data_center import APP as khl_site_app
|
from khl_site.khl_data_center import APP as khl_site_app
|
||||||
|
|
||||||
BASE_DIR = Path(__file__).resolve().parent
|
BASE_DIR = Path(__file__).resolve().parent
|
||||||
BUILD_VERSION = "2026.08.27.1"
|
BUILD_VERSION = "2026.08.27.2"
|
||||||
# compatibility: BUILD_VERSION = "2026.08.26.1"
|
# compatibility: BUILD_VERSION = "2026.08.26.1"
|
||||||
# compatibility: BUILD_VERSION = "2026.08.25.1"
|
# compatibility: BUILD_VERSION = "2026.08.25.1"
|
||||||
# compatibility: BUILD_VERSION = "2026.08.24.15"
|
# compatibility: BUILD_VERSION = "2026.08.24.15"
|
||||||
|
|||||||
@@ -574,7 +574,7 @@ class UIBuilderManager:
|
|||||||
"description": str(selector.get("description") or "")[:300],
|
"description": str(selector.get("description") or "")[:300],
|
||||||
"group_id": group_id if group_id in valid_group_ids else "",
|
"group_id": group_id if group_id in valid_group_ids else "",
|
||||||
"button_id": button_id if button_id in valid_button_ids else "",
|
"button_id": button_id if button_id in valid_button_ids else "",
|
||||||
"style": "select" if str(selector.get("style") or "segments") == "select" else "segments",
|
"style": str(selector.get("style") or "segments") if str(selector.get("style") or "segments") in {"segments", "select", "periods"} else "segments",
|
||||||
"options": options,
|
"options": options,
|
||||||
"default_value": default_value,
|
"default_value": default_value,
|
||||||
"sort_order": int(selector.get("sort_order") if str(selector.get("sort_order", "")).lstrip("-").isdigit() else selector_index * 10),
|
"sort_order": int(selector.get("sort_order") if str(selector.get("sort_order", "")).lstrip("-").isdigit() else selector_index * 10),
|
||||||
|
|||||||
@@ -2494,7 +2494,7 @@ function startCustomTooltips() {
|
|||||||
description: String(selector?.description || "").slice(0, 300),
|
description: String(selector?.description || "").slice(0, 300),
|
||||||
group_id: String(selector?.group_id || "").slice(0, 48),
|
group_id: String(selector?.group_id || "").slice(0, 48),
|
||||||
button_id: String(selector?.button_id || "").slice(0, 48),
|
button_id: String(selector?.button_id || "").slice(0, 48),
|
||||||
style: String(selector?.style || "segments") === "select" ? "select" : "segments",
|
style: ["select", "periods"].includes(String(selector?.style || "segments")) ? String(selector.style) : "segments",
|
||||||
options: fallbackOptions,
|
options: fallbackOptions,
|
||||||
default_value: defaultValue,
|
default_value: defaultValue,
|
||||||
sort_order: Number.isFinite(Number(selector?.sort_order)) ? Number(selector.sort_order) : index * 10,
|
sort_order: Number.isFinite(Number(selector?.sort_order)) ? Number(selector.sort_order) : index * 10,
|
||||||
@@ -8824,7 +8824,7 @@ function openHockeyPrematchButtonsEditor() {
|
|||||||
let activeEditorSection = "buttons";
|
let activeEditorSection = "buttons";
|
||||||
if (activeEditorGroupId === "__ungrouped") activeEditorGroupId = "";
|
if (activeEditorGroupId === "__ungrouped") activeEditorGroupId = "";
|
||||||
if (activeEditorGroupId && !draftGroups.some((group) => group.id === activeEditorGroupId)) activeEditorGroupId = draftGroups[0]?.id || "";
|
if (activeEditorGroupId && !draftGroups.some((group) => group.id === activeEditorGroupId)) activeEditorGroupId = draftGroups[0]?.id || "";
|
||||||
const collapsedEditorGroups = new Set();
|
const collapsedEditorGroups = new Set(["", ...draftGroups.map((group) => String(group.id || ""))]);
|
||||||
|
|
||||||
const groupButtons = (groupId) => draft
|
const groupButtons = (groupId) => draft
|
||||||
.filter((button) => String(button.group_id || "") === String(groupId || ""))
|
.filter((button) => String(button.group_id || "") === String(groupId || ""))
|
||||||
@@ -8875,9 +8875,12 @@ function openHockeyPrematchButtonsEditor() {
|
|||||||
<label>ID для SQL<input type="text" maxlength="48" data-quick-selector-field="id" data-quick-selector-id="${escapeHtml(selector.id)}" value="${escapeHtml(selector.id)}"></label>
|
<label>ID для SQL<input type="text" maxlength="48" data-quick-selector-field="id" data-quick-selector-id="${escapeHtml(selector.id)}" value="${escapeHtml(selector.id)}"></label>
|
||||||
<label>Вкладка<select data-quick-selector-field="group_id" data-quick-selector-id="${escapeHtml(selector.id)}">${hockeyPrematchGroupOptions(draftGroups, selector.group_id)}</select></label>
|
<label>Вкладка<select data-quick-selector-field="group_id" data-quick-selector-id="${escapeHtml(selector.id)}">${hockeyPrematchGroupOptions(draftGroups, selector.group_id)}</select></label>
|
||||||
<label>Рядом с кнопкой<select data-quick-selector-field="button_id" data-quick-selector-id="${escapeHtml(selector.id)}">${hockeyQuickPanelButtonOptions(draft, selector.button_id)}</select></label>
|
<label>Рядом с кнопкой<select data-quick-selector-field="button_id" data-quick-selector-id="${escapeHtml(selector.id)}">${hockeyQuickPanelButtonOptions(draft, selector.button_id)}</select></label>
|
||||||
<label>Вид<select data-quick-selector-field="style" data-quick-selector-id="${escapeHtml(selector.id)}">${triggerSelectOptions([["segments","Маленькие кнопки"],["select","Выпадающий список"]], selector.style)}</select></label>
|
<label>Вид<select data-quick-selector-field="style" data-quick-selector-id="${escapeHtml(selector.id)}">${triggerSelectOptions([["segments","Маленькие кнопки"],["select","Выпадающий список"],["periods","Периоды матча · авто"]], selector.style)}</select></label>
|
||||||
<label class="quick-selector-options-field">Варианты <small>значение=подпись; разделитель — точка с запятой</small><input type="text" data-quick-selector-options="${escapeHtml(selector.id)}" value="${escapeHtml(quickPanelSelectorOptionsText(selector))}" placeholder="all=МАТЧ; 1=1; 2=2; 3=3"></label>
|
${selector.style === "periods"
|
||||||
<label class="quick-selector-default-field">По умолчанию<input type="text" maxlength="64" data-quick-selector-field="default_value" data-quick-selector-id="${escapeHtml(selector.id)}" value="${escapeHtml(selector.default_value)}"></label>
|
? `<label class="quick-selector-options-field quick-selector-auto-note">Периоды <small>Автоматически из режима текущего матча</small><input type="text" value="1 · 2 · 3 · ОТ / ОТ1, ОТ2…" disabled></label>
|
||||||
|
<label class="quick-selector-default-field">По умолчанию<input type="text" value="1" disabled></label>`
|
||||||
|
: `<label class="quick-selector-options-field">Варианты <small>значение=подпись; разделитель — точка с запятой</small><input type="text" data-quick-selector-options="${escapeHtml(selector.id)}" value="${escapeHtml(quickPanelSelectorOptionsText(selector))}" placeholder="all=МАТЧ; 1=1; 2=2; 3=3"></label>
|
||||||
|
<label class="quick-selector-default-field">По умолчанию<input type="text" maxlength="64" data-quick-selector-field="default_value" data-quick-selector-id="${escapeHtml(selector.id)}" value="${escapeHtml(selector.default_value)}"></label>`}
|
||||||
<button type="button" class="icon-btn danger" data-quick-selector-delete="${escapeHtml(selector.id)}" title="Удалить переключатель">×</button>
|
<button type="button" class="icon-btn danger" data-quick-selector-delete="${escapeHtml(selector.id)}" title="Удалить переключатель">×</button>
|
||||||
</article>`;
|
</article>`;
|
||||||
|
|
||||||
@@ -9112,6 +9115,9 @@ function openHockeyPrematchButtonsEditor() {
|
|||||||
activeEditorGroupId = String(selector.group_id || "");
|
activeEditorGroupId = String(selector.group_id || "");
|
||||||
collapsedEditorGroups.delete(activeEditorGroupId);
|
collapsedEditorGroups.delete(activeEditorGroupId);
|
||||||
renderEditor();
|
renderEditor();
|
||||||
|
} else if (field === "style") {
|
||||||
|
if (selector.style === "periods") selector.default_value = "1";
|
||||||
|
renderEditor();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -9233,11 +9239,57 @@ function hockeyMatchRuntimeValues() {
|
|||||||
return values && typeof values === "object" ? values : {};
|
return values && typeof values === "object" ? values : {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function quickPanelPeriodLabel(value) {
|
||||||
|
const key = String(value || "").toLowerCase();
|
||||||
|
if (key === "1" || key === "2" || key === "3") return key;
|
||||||
|
if (key === "ot") return "ОТ";
|
||||||
|
const match = key.match(/^ot(\d+)$/);
|
||||||
|
return match ? `ОТ${match[1]}` : String(value || "");
|
||||||
|
}
|
||||||
|
|
||||||
|
function quickPanelSelectorRuntimeOptions(selector) {
|
||||||
|
if (String(selector?.style || "") !== "periods") return Array.isArray(selector?.options) ? selector.options : [];
|
||||||
|
const control = getByPath(state.data, "hockey.game_control") || {};
|
||||||
|
const tournament = getByPath(state.data, "hockey.selected_tournament") || {};
|
||||||
|
const stage = String(control?.stage || tournament?.stage_key || "").toLowerCase();
|
||||||
|
const raw = Array.isArray(control?.period_options) ? control.period_options : [];
|
||||||
|
let options = raw
|
||||||
|
.map((item) => ({ value: String(item?.value || ""), label: quickPanelPeriodLabel(item?.value) }))
|
||||||
|
.filter((item) => {
|
||||||
|
if (["1", "2", "3"].includes(item.value)) return true;
|
||||||
|
if (stage === "playoff") return /^ot\d+$/.test(item.value);
|
||||||
|
return item.value === "ot";
|
||||||
|
});
|
||||||
|
if (!options.length) {
|
||||||
|
options = [
|
||||||
|
{ value: "1", label: "1" },
|
||||||
|
{ value: "2", label: "2" },
|
||||||
|
{ value: "3", label: "3" },
|
||||||
|
];
|
||||||
|
if (stage === "playoff") {
|
||||||
|
const current = String(control?.current_period || "").toLowerCase().match(/^ot(\d+)$/);
|
||||||
|
const count = Math.max(2, Number(current?.[1] || 0) + 1);
|
||||||
|
for (let number = 1; number <= count; number += 1) options.push({ value: `ot${number}`, label: `ОТ${number}` });
|
||||||
|
} else {
|
||||||
|
options.push({ value: "ot", label: "ОТ" });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const seen = new Set();
|
||||||
|
return options.filter((item) => {
|
||||||
|
if (!item.value || seen.has(item.value)) return false;
|
||||||
|
seen.add(item.value);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function quickPanelSelectorValue(selector) {
|
function quickPanelSelectorValue(selector) {
|
||||||
|
const options = quickPanelSelectorRuntimeOptions(selector);
|
||||||
const values = hockeyMatchRuntimeValues();
|
const values = hockeyMatchRuntimeValues();
|
||||||
const stored = String(values[`panel.${selector.id}.value`] ?? "");
|
const stored = String(values[`panel.${selector.id}.value`] ?? "");
|
||||||
if (selector.options.some((option) => option.value === stored)) return stored;
|
if (options.some((option) => option.value === stored)) return stored;
|
||||||
return selector.default_value || selector.options[0]?.value || "";
|
const configuredDefault = String(selector?.default_value || "");
|
||||||
|
if (options.some((option) => option.value === configuredDefault)) return configuredDefault;
|
||||||
|
return options[0]?.value || "";
|
||||||
}
|
}
|
||||||
|
|
||||||
async function hockeyRefreshQuickPanelMapping() {
|
async function hockeyRefreshQuickPanelMapping() {
|
||||||
@@ -9355,16 +9407,18 @@ function hockeyScoreDockMarkup() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function quickPanelSelectorMarkup(selector) {
|
function quickPanelSelectorMarkup(selector) {
|
||||||
|
const options = quickPanelSelectorRuntimeOptions(selector);
|
||||||
const current = quickPanelSelectorValue(selector);
|
const current = quickPanelSelectorValue(selector);
|
||||||
const tooltip = selector.description || selector.label;
|
const tooltip = selector.description || selector.label;
|
||||||
if (selector.style === "select") {
|
if (selector.style === "select") {
|
||||||
return `<label class="quick-command-selector is-select" data-tooltip="${escapeHtml(tooltip)}"><span>${escapeHtml(selector.label)}</span><select data-quick-selector-runtime="${escapeHtml(selector.id)}">${selector.options.map((option) => `<option value="${escapeHtml(option.value)}" ${option.value === current ? "selected" : ""}>${escapeHtml(option.label)}</option>`).join("")}</select></label>`;
|
return `<label class="quick-command-selector is-select" data-tooltip="${escapeHtml(tooltip)}"><span>${escapeHtml(selector.label)}</span><select data-quick-selector-runtime="${escapeHtml(selector.id)}">${options.map((option) => `<option value="${escapeHtml(option.value)}" ${option.value === current ? "selected" : ""}>${escapeHtml(option.label)}</option>`).join("")}</select></label>`;
|
||||||
}
|
}
|
||||||
return `<div class="quick-command-selector is-segments" data-tooltip="${escapeHtml(tooltip)}"><span>${escapeHtml(selector.label)}</span><div>${selector.options.map((option) => `<button type="button" data-quick-selector-runtime="${escapeHtml(selector.id)}" data-quick-selector-value="${escapeHtml(option.value)}" class="${option.value === current ? "active" : ""}">${escapeHtml(option.label)}</button>`).join("")}</div></div>`;
|
const modeClass = selector.style === "periods" ? " is-match-periods" : "";
|
||||||
|
return `<div class="quick-command-selector is-segments${modeClass}" data-tooltip="${escapeHtml(tooltip)}"><span>${escapeHtml(selector.label)}</span><div>${options.map((option) => `<button type="button" data-quick-selector-runtime="${escapeHtml(selector.id)}" data-quick-selector-value="${escapeHtml(option.value)}" class="${option.value === current ? "active" : ""}">${escapeHtml(option.label)}</button>`).join("")}</div></div>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function hockeyApplyQuickSelector(selector, value, label = "") {
|
async function hockeyApplyQuickSelector(selector, value, label = "") {
|
||||||
const option = selector.options.find((item) => item.value === value);
|
const option = quickPanelSelectorRuntimeOptions(selector).find((item) => item.value === value);
|
||||||
const displayLabel = String(label || option?.label || value);
|
const displayLabel = String(label || option?.label || value);
|
||||||
await hockeySetMatchValues({
|
await hockeySetMatchValues({
|
||||||
[`panel.${selector.id}.value`]: value,
|
[`panel.${selector.id}.value`]: value,
|
||||||
@@ -9379,7 +9433,7 @@ async function hockeyCommitQuickPanelButtonContext(button, attachedSelectors, {
|
|||||||
};
|
};
|
||||||
for (const selector of attachedSelectors) {
|
for (const selector of attachedSelectors) {
|
||||||
const value = quickPanelSelectorValue(selector);
|
const value = quickPanelSelectorValue(selector);
|
||||||
const option = selector.options.find((item) => item.value === value);
|
const option = quickPanelSelectorRuntimeOptions(selector).find((item) => item.value === value);
|
||||||
patch[`panel.${selector.id}.value`] = value;
|
patch[`panel.${selector.id}.value`] = value;
|
||||||
patch[`panel.${selector.id}.label`] = option?.label || value;
|
patch[`panel.${selector.id}.label`] = option?.label || value;
|
||||||
patch[`panel.last_button.${selector.id}`] = value;
|
patch[`panel.last_button.${selector.id}`] = value;
|
||||||
@@ -9440,7 +9494,7 @@ function renderHockeyQuickCommandDock() {
|
|||||||
const selector = selectors.find((item) => item.id === control.dataset.quickSelectorRuntime);
|
const selector = selectors.find((item) => item.id === control.dataset.quickSelectorRuntime);
|
||||||
if (!selector) return;
|
if (!selector) return;
|
||||||
const value = control.tagName === "SELECT" ? control.value : String(control.dataset.quickSelectorValue || "");
|
const value = control.tagName === "SELECT" ? control.value : String(control.dataset.quickSelectorValue || "");
|
||||||
const option = selector.options.find((item) => item.value === value);
|
const option = quickPanelSelectorRuntimeOptions(selector).find((item) => item.value === value);
|
||||||
try {
|
try {
|
||||||
await hockeyApplyQuickSelector(selector, value, option?.label || value);
|
await hockeyApplyQuickSelector(selector, value, option?.label || value);
|
||||||
toast(`Параметр «${selector.label}»: ${option?.label || value}`);
|
toast(`Параметр «${selector.label}»: ${option?.label || value}`);
|
||||||
|
|||||||
@@ -7837,3 +7837,82 @@ body.hockey-navigation-open .runtime-viewport.has-hockey-pbp { gap: 14px !import
|
|||||||
.prematch-editor-selector-row .quick-selector-options-field,
|
.prematch-editor-selector-row .quick-selector-options-field,
|
||||||
.prematch-editor-selector-row .quick-selector-default-field { grid-column: auto; }
|
.prematch-editor-selector-row .quick-selector-default-field { grid-column: auto; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* BUILD126 — collapsed lower-panel editor, pinned footer, automatic match-period selector. */
|
||||||
|
.modal-card.modal-prematch-full,
|
||||||
|
.modal-card:has(.prematch-editor) {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
.modal-prematch-full .modal-head,
|
||||||
|
.modal-card:has(.prematch-editor) .modal-head {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
}
|
||||||
|
.modal-prematch-full .prematch-editor,
|
||||||
|
.modal-card:has(.prematch-editor) .prematch-editor {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
min-height: 0;
|
||||||
|
height: auto;
|
||||||
|
grid-template-rows: auto minmax(0, 1fr) auto;
|
||||||
|
}
|
||||||
|
.prematch-editor-section:not(.player-selection-editor) {
|
||||||
|
min-height: 0;
|
||||||
|
display: grid;
|
||||||
|
grid-template-rows: auto minmax(0, 1fr);
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.prematch-editor-section:not(.player-selection-editor) > .prematch-editor-list {
|
||||||
|
min-height: 0;
|
||||||
|
height: 100%;
|
||||||
|
max-height: none;
|
||||||
|
overflow-y: auto;
|
||||||
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
|
.modal-prematch-full .prematch-editor-actions,
|
||||||
|
.modal-card:has(.prematch-editor) .prematch-editor-actions {
|
||||||
|
position: relative;
|
||||||
|
inset: auto;
|
||||||
|
flex: 0 0 auto;
|
||||||
|
margin: 0;
|
||||||
|
padding: 10px 0 0;
|
||||||
|
box-shadow: 0 -10px 22px rgba(5, 12, 20, .18);
|
||||||
|
}
|
||||||
|
.quick-selector-auto-note input:disabled {
|
||||||
|
color: #79a9d7;
|
||||||
|
border-color: rgba(77, 156, 255, .28);
|
||||||
|
background: rgba(77, 156, 255, .055);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
.quick-command-selector.is-match-periods {
|
||||||
|
min-height: 38px;
|
||||||
|
padding: 3px 6px;
|
||||||
|
border-color: rgba(77, 156, 255, .34);
|
||||||
|
background: rgba(77, 156, 255, .045);
|
||||||
|
}
|
||||||
|
.quick-command-selector.is-match-periods > span {
|
||||||
|
color: #6f9bca;
|
||||||
|
}
|
||||||
|
.quick-command-selector.is-match-periods > div {
|
||||||
|
gap: 3px;
|
||||||
|
}
|
||||||
|
.quick-command-selector.is-match-periods button {
|
||||||
|
min-width: 31px;
|
||||||
|
height: 29px;
|
||||||
|
padding: 0 8px;
|
||||||
|
border-color: #324f6d;
|
||||||
|
border-radius: 7px;
|
||||||
|
color: #c7d8e9;
|
||||||
|
background: #0d1c2c;
|
||||||
|
font-size: 9px;
|
||||||
|
}
|
||||||
|
.quick-command-selector.is-match-periods button:hover {
|
||||||
|
border-color: #4d9cff;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
.quick-command-selector.is-match-periods button.active {
|
||||||
|
color: #eef7ff;
|
||||||
|
border-color: #4d9cff;
|
||||||
|
background: #245f9d;
|
||||||
|
box-shadow: 0 0 0 1px rgba(77, 156, 255, .12), inset 0 -2px 0 rgba(117, 190, 255, .45);
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user