Refine BIM glass theming and panel scroll layout

This commit is contained in:
CODEX
2026-06-20 21:55:23 +03:00
parent 3584359833
commit ad3a4f3877
5 changed files with 307 additions and 113 deletions
+104 -13
View File
@@ -102,6 +102,92 @@ const readableTextColor = (value) => {
return (lum + 0.05) / 0.05 >= 1.05 / (lum + 0.05) ? "#15170f" : "#f5f5fa";
};
const clamp = (value, min, max) => Math.max(min, Math.min(max, value));
const colorParts = (value, fallback) => {
const parsed = parseColor(value);
if (parsed && parsed.every((channel) => Number.isFinite(channel))) return parsed;
const parsedFallback = parseColor(fallback);
if (parsedFallback && parsedFallback.every((channel) => Number.isFinite(channel))) return parsedFallback;
return [28, 28, 28];
};
const alphaValue = (value, fallback) => {
const numeric = Number(value);
return Number.isFinite(numeric) ? clamp(numeric, 0, 1) : fallback;
};
const rgba = (parts, alpha) => {
const [r, g, b] = parts.map((channel) => Math.round(clamp(channel, 0, 255)));
return `rgba(${r}, ${g}, ${b}, ${clamp(alpha, 0, 1).toFixed(3)})`;
};
const applyGlassSettings = (root, s) => {
const panelColor = colorParts(s.modalBg, defaultSettings.modalBg);
const focusColor = colorParts(s.modalFocus, defaultSettings.modalFocus);
const controlColor = colorParts(s.modalElement, s.modalFocus || defaultSettings.modalElement);
const outlineColor = colorParts(s.modalBorder, s.modalElementOutline || defaultSettings.modalBorder);
const controlOutlineColor = colorParts(s.modalElementOutline, s.modalBorder || defaultSettings.modalElementOutline);
const modalBgAlpha = alphaValue(s.modalBgAlpha, defaultSettings.modalBgAlpha);
const modalFocusAlpha = alphaValue(s.modalFocusAlpha, defaultSettings.modalFocusAlpha);
const panelAlpha = clamp(0.24 + modalBgAlpha * 0.48, 0.32, 0.88);
const panelStrongAlpha = clamp(panelAlpha + 0.1, 0.42, 0.92);
const panelSoftAlpha = clamp(panelAlpha - 0.16, 0.2, 0.72);
const sectionAlpha = clamp(modalFocusAlpha * 0.6, 0.04, 0.42);
const controlAlpha = clamp(0.12 + modalFocusAlpha * 0.9, 0.16, 0.66);
const controlHoverAlpha = clamp(controlAlpha + 0.08, 0.22, 0.74);
const outlineAlpha = clamp(0.055 + modalFocusAlpha * 0.18, 0.065, 0.2);
const controlOutlineAlpha = clamp(0.045 + modalFocusAlpha * 0.12, 0.055, 0.16);
const panelBg = rgba(panelColor, panelAlpha);
const panelBgStrong = rgba(panelColor, panelStrongAlpha);
const panelBgSoft = rgba(panelColor, panelSoftAlpha);
const sectionBg = rgba(focusColor, sectionAlpha);
const outline = rgba(outlineColor, outlineAlpha);
const outlineBright = rgba(outlineColor, clamp(outlineAlpha + 0.05, 0.08, 0.26));
const outlineMid = rgba(outlineColor, clamp(outlineAlpha + 0.015, 0.07, 0.22));
const outlineDim = rgba(outlineColor, clamp(outlineAlpha * 0.62, 0.04, 0.16));
const controlBg = rgba(controlColor, controlAlpha);
const controlHover = rgba(focusColor, controlHoverAlpha);
const controlShadow = rgba(controlOutlineColor, controlOutlineAlpha);
root.style.setProperty("--nodedc-glass-panel-bg", panelBg);
root.style.setProperty("--nodedc-glass-panel-bg-strong", panelBgStrong);
root.style.setProperty("--nodedc-glass-panel-bg-soft", panelBgSoft);
root.style.setProperty(
"--nodedc-glass-panel-surface",
`linear-gradient(180deg, rgba(255, 255, 255, 0.052) 0%, rgba(255, 255, 255, 0.014) 100%), ${panelBg}`
);
root.style.setProperty(
"--nodedc-glass-panel-surface-strong",
`linear-gradient(180deg, rgba(255, 255, 255, 0.06) 0%, rgba(255, 255, 255, 0.016) 100%), ${panelBgStrong}`
);
root.style.setProperty(
"--nodedc-glass-section-bg",
`linear-gradient(180deg, rgba(255, 255, 255, 0.038) 0%, rgba(255, 255, 255, 0.01) 100%), ${sectionBg}`
);
root.style.setProperty("--nodedc-glass-outline", outline);
root.style.setProperty(
"--nodedc-glass-outline-gradient",
`linear-gradient(180deg, ${outlineBright} 0%, ${outlineMid} 56%, ${outlineDim} 100%)`
);
root.style.setProperty("--nodedc-glass-panel-shadow", `inset 0 1px 0 ${outlineDim}, 0 22px 72px rgba(0, 0, 0, 0.42)`);
root.style.setProperty(
"--nodedc-glass-control-bg",
`linear-gradient(180deg, rgba(255, 255, 255, 0.052) 0%, rgba(255, 255, 255, 0.018) 100%), ${controlBg}`
);
root.style.setProperty(
"--nodedc-glass-control-hover",
`linear-gradient(180deg, rgba(255, 255, 255, 0.075) 0%, rgba(255, 255, 255, 0.026) 100%), ${controlHover}`
);
root.style.setProperty("--nodedc-glass-control-shadow", `inset 0 1px 0 ${controlShadow}`);
root.style.setProperty("--nodedc-header-dropdown-bg", panelBgStrong);
root.style.setProperty("--nodedc-header-dropdown-item-bg", controlBg);
root.style.setProperty("--nodedc-header-dropdown-item-hover-bg", controlHover);
root.style.setProperty("--nodedc-header-dropdown-item-active-bg", s.toolbarBgActive);
root.style.setProperty("--nodedc-header-dropdown-item-active-color", readableTextColor(s.toolbarBgActive));
};
const applySettings = (s) => {
const root = document.documentElement;
root.style.setProperty("--bg-outer", s.bgOuter);
@@ -137,6 +223,7 @@ const applySettings = (s) => {
root.style.setProperty("--modal-element", s.modalElement);
root.style.setProperty("--modal-element-outline", s.modalElementOutline);
root.style.setProperty("--modal-radius", s.modalRadius);
applyGlassSettings(root, s);
root.style.setProperty("--border", s.border);
root.style.setProperty("--text", s.text);
root.style.setProperty("--panel", s.panel);
@@ -259,6 +346,10 @@ export function createSettingsMenu({ panel, controls = {}, onChange = null, onSh
header.appendChild(closeBtn);
panel.appendChild(header);
const body = document.createElement("div");
body.className = "settings-panel-body";
panel.appendChild(body);
const section = (title) => {
const box = document.createElement("div");
box.className = "settings-section";
@@ -357,7 +448,7 @@ export function createSettingsMenu({ panel, controls = {}, onChange = null, onSh
addColor(font, "Фон холста низ", "canvasBottom");
addColor(font, "Фон загрузки верх", "loadingTop");
addColor(font, "Фон загрузки низ", "loadingBottom");
panel.appendChild(font);
body.appendChild(font);
const buttons = section("Кнопки");
addColor(buttons, "Плюс", "plus");
@@ -374,26 +465,26 @@ export function createSettingsMenu({ panel, controls = {}, onChange = null, onSh
step: 1,
formatValue: (val) => `${Math.round(val)}%`,
});
panel.appendChild(buttons);
body.appendChild(buttons);
const projectButtons = section("Кнопки проектов");
addColor(projectButtons, "Проекты (заливка)", "projectBtnFill");
addColor(projectButtons, "Проекты (бордер)", "projectBtnBorder");
addColor(projectButtons, "Проекты (hover)", "projectBtnHover");
panel.appendChild(projectButtons);
body.appendChild(projectButtons);
const modalButtons = section("Кнопки модалок");
addColor(modalButtons, "Модальная primary", "modalBtnPrimary");
addColor(modalButtons, "Модальная secondary", "modalBtnSecondary");
addColor(modalButtons, "Лоудер", "loaderColor");
panel.appendChild(modalButtons);
body.appendChild(modalButtons);
const toolbar = section("Toolbar");
addColor(toolbar, "Фон", "toolbarBg");
addColor(toolbar, "Актив", "toolbarBgActive");
addColor(toolbar, "Бордер", "toolbarBorder");
addColor(toolbar, "Outline", "toolbarOutline");
panel.appendChild(toolbar);
body.appendChild(toolbar);
const navCube = section("NavCube");
addColor(navCube, "Грани", "navCubeBase");
@@ -412,7 +503,7 @@ export function createSettingsMenu({ panel, controls = {}, onChange = null, onSh
setVal("navCubeEdgeAlpha", Math.max(0, Math.min(1, Number(val) / 100)));
},
});
panel.appendChild(navCube);
body.appendChild(navCube);
const sectionCut = section("Разрез / сечение");
addColor(sectionCut, "Ось X", "sectionAxisX");
@@ -468,7 +559,7 @@ export function createSettingsMenu({ panel, controls = {}, onChange = null, onSh
setVal("sectionPlaneEdgeAlpha", Math.max(0, Math.min(1, Number(val) / 100)));
},
});
panel.appendChild(sectionCut);
body.appendChild(sectionCut);
const commentTargets = section("Таргеты комментариев");
addColor(commentTargets, "Активный: цвет", "commentTargetActiveColor");
@@ -521,14 +612,14 @@ export function createSettingsMenu({ panel, controls = {}, onChange = null, onSh
setVal("commentTargetPassiveSize", Math.max(12, Math.min(48, Math.round(Number(val)))));
},
});
panel.appendChild(commentTargets);
body.appendChild(commentTargets);
const measure = section("Линейка");
addColor(measure, "Линия/бордер", "measureLine");
addColor(measure, "Плашка", "measureLabel");
addColor(measure, "Текст плашки", "measureLabelText");
addColor(measure, "Кружок", "measureDot");
panel.appendChild(measure);
body.appendChild(measure);
const viewport = section("Viewport");
const addCheck = (label, checked, handler) => {
@@ -548,7 +639,7 @@ export function createSettingsMenu({ panel, controls = {}, onChange = null, onSh
if (controls.toggleEdges) addCheck("Рёбра", controls.toggleEdges.checked, (v) => { controls.toggleEdges.checked = v; controls.toggleEdges.dispatchEvent(new Event("change")); });
if (controls.toggleTransparent) addCheck("Прозрачный фон", controls.toggleTransparent.checked, (v) => { controls.toggleTransparent.checked = v; controls.toggleTransparent.dispatchEvent(new Event("change")); });
if (controls.addMode) addCheck("Добавлять в сцену", controls.addMode.checked, (v) => { controls.addMode.checked = v; });
panel.appendChild(viewport);
body.appendChild(viewport);
const modals = section("Модальные окна");
addColor(modals, "Основной фон", "modalBg");
@@ -598,18 +689,18 @@ export function createSettingsMenu({ panel, controls = {}, onChange = null, onSh
setVal("modalRadius", val);
},
});
panel.appendChild(modals);
body.appendChild(modals);
const cube = section("Выделение объектов");
addColor(cube, "Подсветка объектов", "highlight");
panel.appendChild(cube);
body.appendChild(cube);
};
const show = () => {
render();
if (panel) {
panel.classList.remove("hidden");
panel.style.display = "grid";
panel.style.display = "flex";
}
onShow?.();
};
+9 -5
View File
@@ -89,11 +89,15 @@ export function createTemplatesMenu({ panel, fetchProjects, openProject, onShow,
header.appendChild(actions);
panel.appendChild(header);
const body = document.createElement("div");
body.className = "templates-panel-body";
panel.appendChild(body);
if (state.loading) {
const loadingEl = document.createElement("div");
loadingEl.className = "templates-empty";
loadingEl.textContent = "Загрузка списка проектов...";
panel.appendChild(loadingEl);
body.appendChild(loadingEl);
return;
}
@@ -102,11 +106,11 @@ export function createTemplatesMenu({ panel, fetchProjects, openProject, onShow,
errorEl.className = "templates-empty";
errorEl.style.color = "var(--error)";
errorEl.textContent = state.error;
panel.appendChild(errorEl);
body.appendChild(errorEl);
}
panel.appendChild(renderSection("Шаблоны", state.templates, "Нет шаблонов"));
panel.appendChild(renderSection("Мои проекты", state.projects, "Нет сохранённых проектов"));
body.appendChild(renderSection("Шаблоны", state.templates, "Нет шаблонов"));
body.appendChild(renderSection("Мои проекты", state.projects, "Нет сохранённых проектов"));
};
const load = async () => {
@@ -137,7 +141,7 @@ export function createTemplatesMenu({ panel, fetchProjects, openProject, onShow,
render();
if (panel) {
panel.classList.remove("hidden");
panel.style.display = "grid";
panel.style.display = "flex";
}
load();
onShow?.();