Refine BIM glass theming and panel scroll layout
This commit is contained in:
+104
-13
@@ -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?.();
|
||||
};
|
||||
|
||||
@@ -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?.();
|
||||
|
||||
Reference in New Issue
Block a user