From ad3a4f38774d17b3b78d61f479fd716afdf30541 Mon Sep 17 00:00:00 2001 From: CODEX Date: Sat, 20 Jun 2026 21:55:23 +0300 Subject: [PATCH] Refine BIM glass theming and panel scroll layout --- frontend/dcViewer.css | 103 +++++++++++------ frontend/dcViewer.js | 4 +- frontend/index.html | 182 +++++++++++++++++++++---------- frontend/src/ui/settingsMenu.js | 117 +++++++++++++++++--- frontend/src/ui/templatesMenu.js | 14 ++- 5 files changed, 307 insertions(+), 113 deletions(-) diff --git a/frontend/dcViewer.css b/frontend/dcViewer.css index 36d8dcd..a940cc6 100644 --- a/frontend/dcViewer.css +++ b/frontend/dcViewer.css @@ -68,11 +68,11 @@ --comment-target-passive: #f5f5fa; --comment-target-passive-alpha: 0.58; --comment-target-passive-size: 22px; - --nodedc-header-dropdown-bg: rgba(11, 11, 14, 0.94); - --nodedc-header-dropdown-item-bg: rgba(42, 42, 46, 0.74); - --nodedc-header-dropdown-item-hover-bg: rgba(42, 42, 46, 0.86); - --nodedc-header-dropdown-item-active-bg: rgba(47, 47, 52, 0.96); - --nodedc-header-dropdown-item-active-color: #ffffff; + --nodedc-header-dropdown-bg: var(--nodedc-glass-panel-bg-strong); + --nodedc-header-dropdown-item-bg: var(--nodedc-glass-control-bg); + --nodedc-header-dropdown-item-hover-bg: var(--nodedc-glass-control-hover); + --nodedc-header-dropdown-item-active-bg: var(--toolbar-bg-active); + --nodedc-header-dropdown-item-active-color: var(--toolbar-bg-active-contrast); --nodedc-glass-panel-bg: rgba(28, 28, 30, 0.72); --nodedc-glass-panel-bg-strong: rgba(28, 28, 30, 0.82); --nodedc-glass-panel-bg-soft: rgba(28, 28, 30, 0.56); @@ -398,17 +398,17 @@ header { bottom: 12px; width: 320px; max-height: calc(100vh - 90px); - overflow: auto; + overflow: hidden; background: var(--nodedc-glass-panel-surface); border: 1px solid var(--nodedc-glass-outline); border-radius: var(--modal-radius, 16px); - padding: 12px; + padding: 0; box-shadow: var(--nodedc-glass-panel-shadow); backdrop-filter: var(--nodedc-glass-filter); -webkit-backdrop-filter: var(--nodedc-glass-filter); display: flex; flex-direction: column; - gap: 10px; + gap: 0; z-index: 11; display: none; } @@ -418,8 +418,7 @@ header { } .inspector-panel-header { - position: sticky; - top: -12px; + position: relative; z-index: 5; flex: 0 0 auto; display: grid; @@ -428,9 +427,9 @@ header { gap: 10px; height: calc(var(--env-control-h) + 20px); min-height: var(--env-control-h); - margin: -12px -12px 0; + margin: 0; padding: 12px 12px 8px 16px; - background: var(--nodedc-glass-panel-surface-strong); + background: transparent; border-radius: var(--modal-radius, 16px) var(--modal-radius, 16px) 0 0; color: var(--text); font-weight: 700; @@ -443,6 +442,16 @@ header { line-height: 1.2; } +.inspector-panel-body { + flex: 1 1 auto; + min-height: 0; + overflow: auto; + padding: 0 12px 12px; + display: flex; + flex-direction: column; + gap: 10px; +} + .inspector-collapse-btn { display: grid; place-items: center; @@ -561,16 +570,16 @@ header { } .comments-panel-header { - position: sticky; - top: 0; + position: relative; z-index: 5; + flex: 0 0 auto; display: grid; grid-template-columns: minmax(0, 1fr) var(--env-control-h); align-items: center; gap: 10px; min-height: calc(var(--env-control-h) + 20px); padding: 12px 12px 8px 16px; - background: var(--nodedc-glass-panel-surface-strong); + background: transparent; border-radius: var(--modal-radius, 16px) var(--modal-radius, 16px) 0 0; color: var(--text); font-weight: 700; @@ -590,6 +599,7 @@ header { } .comments-panel-body { + flex: 1 1 auto; min-height: 0; overflow: auto; padding: 0 12px 12px; @@ -1323,13 +1333,14 @@ header { background: var(--nodedc-glass-panel-surface); border: 1px solid var(--nodedc-glass-outline); border-radius: var(--modal-radius, 14px); - padding: 12px; - display: grid; - gap: 10px; + padding: 0; + display: flex; + flex-direction: column; + gap: 0; width: var(--templates-width, 280px); min-height: 200px; max-height: 420px; - overflow: auto; + overflow: hidden; box-shadow: var(--nodedc-glass-panel-shadow); z-index: 20; backdrop-filter: var(--nodedc-glass-filter); @@ -1341,23 +1352,32 @@ header { } .templates-panel .templates-header { - position: sticky; - top: -12px; + position: relative; z-index: 5; + flex: 0 0 auto; display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: 10px; height: calc(var(--env-control-h) + 20px); min-height: var(--env-control-h); - margin: -12px -12px 0; + margin: 0; padding: 12px 12px 8px 16px; border-radius: var(--modal-radius, 14px) var(--modal-radius, 14px) 0 0; - background: var(--nodedc-glass-panel-surface-strong); + background: transparent; color: var(--text); font-weight: 700; } +.templates-panel .templates-panel-body { + flex: 1 1 auto; + min-height: 0; + overflow: auto; + padding: 0 12px 12px; + display: grid; + gap: 10px; +} + .templates-panel .templates-title { font-size: 13px; line-height: 1.2; @@ -1530,6 +1550,8 @@ header { width: var(--templates-width, 280px); max-width: min(var(--templates-width, 350px), calc(100vw - 32px)); padding: 12px; + gap: 10px; + overflow: auto; z-index: 40; } @@ -2376,13 +2398,14 @@ header { background: var(--nodedc-glass-panel-surface); border: 1px solid var(--nodedc-glass-outline); border-radius: var(--modal-radius, 14px); - padding: 12px; - display: grid; - gap: 10px; + padding: 0; + display: flex; + flex-direction: column; + gap: 0; width: var(--settings-width, 350px); min-height: 420px; max-height: min(720px, calc(100vh - 72px)); - overflow: auto; + overflow: hidden; box-shadow: var(--nodedc-glass-panel-shadow); z-index: 22; font-size: 12px; @@ -2391,9 +2414,9 @@ header { } .settings-panel .settings-header { - position: sticky; - top: -12px; + position: relative; z-index: 5; + flex: 0 0 auto; display: grid; grid-template-columns: minmax(0, 1fr) var(--env-control-h); align-items: center; @@ -2402,12 +2425,21 @@ header { font-weight: 700; height: calc(var(--env-control-h) + 20px); min-height: var(--env-control-h); - margin: -12px -12px 0; + margin: 0; padding: 12px 12px 8px 16px; - background: var(--nodedc-glass-panel-surface-strong); + background: transparent; border-radius: var(--modal-radius, 14px) var(--modal-radius, 14px) 0 0; } +.settings-panel .settings-panel-body { + flex: 1 1 auto; + min-height: 0; + overflow: auto; + padding: 0 12px 12px; + display: grid; + gap: 10px; +} + .settings-panel .settings-title { font-size: 13px; line-height: 1.2; @@ -3120,13 +3152,14 @@ body[data-viewer-mode="guest"] .inspector-restore-tray { background: var(--nodedc-glass-panel-surface); border: 1px solid var(--nodedc-glass-outline); border-radius: var(--modal-radius, 14px); - padding: 10px; - display: grid; - gap: 10px; + padding: 0; + display: flex; + flex-direction: column; + gap: 0; width: var(--templates-width, 280px); min-height: 200px; max-height: 420px; - overflow: auto; + overflow: hidden; box-shadow: var(--nodedc-glass-panel-shadow); z-index: 20; backdrop-filter: var(--nodedc-glass-filter); diff --git a/frontend/dcViewer.js b/frontend/dcViewer.js index c745897..c667507 100644 --- a/frontend/dcViewer.js +++ b/frontend/dcViewer.js @@ -3,8 +3,8 @@ const SDK_URL = "./lib/dc-camera-context.es.js?v=3"; import { createLogo } from "./src/ui/logo.js"; import { toolbarConfig, applyToolbarVars } from "./src/ui/toolbar.js"; -import { createTemplatesMenu } from "./src/ui/templatesMenu.js?v=2"; -import { createSettingsMenu } from "./src/ui/settingsMenu.js?v=9"; +import { createTemplatesMenu } from "./src/ui/templatesMenu.js?v=3"; +import { createSettingsMenu } from "./src/ui/settingsMenu.js?v=11"; import { createMeasurementModal } from "./src/ui/measurementModal.js"; import { createGlassSelect } from "./src/ui/glassSelect.js"; import { createSliderControl } from "./src/ui/controls/slider.js"; diff --git a/frontend/index.html b/frontend/index.html index 0ba7f3f..358318d 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -64,6 +64,69 @@ const lum = 0.2126 * toLinear(rgb[0]) + 0.7152 * toLinear(rgb[1]) + 0.0722 * toLinear(rgb[2]); 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 = () => { + const panelColor = colorParts(s.modalBg, "#1c1c1c"); + const focusColor = colorParts(s.modalFocus, "#292929"); + const controlColor = colorParts(s.modalElement, s.modalFocus || "#262626"); + const outlineColor = colorParts(s.modalBorder, s.modalElementOutline || "#1c1c1c"); + const controlOutlineColor = colorParts(s.modalElementOutline, s.modalBorder || "#262626"); + const modalBgAlpha = alphaValue(s.modalBgAlpha, 1); + const modalFocusAlpha = alphaValue(s.modalFocusAlpha, 0.35); + 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); + + set("--nodedc-glass-panel-bg", panelBg); + set("--nodedc-glass-panel-bg-strong", panelBgStrong); + set("--nodedc-glass-panel-bg-soft", panelBgSoft); + set("--nodedc-glass-panel-surface", `linear-gradient(180deg, rgba(255, 255, 255, 0.052) 0%, rgba(255, 255, 255, 0.014) 100%), ${panelBg}`); + set("--nodedc-glass-panel-surface-strong", `linear-gradient(180deg, rgba(255, 255, 255, 0.06) 0%, rgba(255, 255, 255, 0.016) 100%), ${panelBgStrong}`); + set("--nodedc-glass-section-bg", `linear-gradient(180deg, rgba(255, 255, 255, 0.038) 0%, rgba(255, 255, 255, 0.01) 100%), ${sectionBg}`); + set("--nodedc-glass-outline", outline); + set("--nodedc-glass-outline-gradient", `linear-gradient(180deg, ${outlineBright} 0%, ${outlineMid} 56%, ${outlineDim} 100%)`); + set("--nodedc-glass-panel-shadow", `inset 0 1px 0 ${outlineDim}, 0 22px 72px rgba(0, 0, 0, 0.42)`); + set("--nodedc-glass-control-bg", `linear-gradient(180deg, rgba(255, 255, 255, 0.052) 0%, rgba(255, 255, 255, 0.018) 100%), ${controlBg}`); + set("--nodedc-glass-control-hover", `linear-gradient(180deg, rgba(255, 255, 255, 0.075) 0%, rgba(255, 255, 255, 0.026) 100%), ${controlHover}`); + set("--nodedc-glass-control-shadow", `inset 0 1px 0 ${controlShadow}`); + set("--nodedc-header-dropdown-bg", panelBgStrong); + set("--nodedc-header-dropdown-item-bg", controlBg); + set("--nodedc-header-dropdown-item-hover-bg", controlHover); + set("--nodedc-header-dropdown-item-active-bg", s.toolbarBgActive); + set("--nodedc-header-dropdown-item-active-color", s.toolbarBgActive ? readableTextColor(s.toolbarBgActive) : undefined); + }; set("--bg-outer", s.bgOuter); set("--canvas-top", s.canvasTop); set("--canvas-bottom", s.canvasBottom); @@ -88,6 +151,7 @@ set("--modal-element", s.modalElement); set("--modal-element-outline", s.modalElementOutline); set("--modal-radius", s.modalRadius); + applyGlassSettings(); set("--project-btn-fill", s.projectBtnFill); set("--project-btn-border", s.projectBtnBorder); set("--project-btn-hover", s.projectBtnHover); @@ -134,7 +198,7 @@ - +
@@ -186,68 +250,70 @@ -
-
-
-
-
Режим отображения
-
+
+
+
+
+
+
Режим отображения
+
+
+
+
Свет
+
+
+ +
-
-
Свет
-
+
+
+

Название проекта

+ +
+
+
+

Глобальные координаты

+
Центр выделения (мировые)
+
+ + +
- +
+

Трансформации

+
Перемещение
+
+ + +
-
+
Вращение (deg)
+
+ + + +
+
Масштаб
+
+ + + +
+ Выберите объект в инспекторе или сцене, чтобы редактировать.
-
-
-

Название проекта

- -
-
-
-

Глобальные координаты

-
Центр выделения (мировые)
-
- - - +
+

Журнал

+
-
-
-

Трансформации

-
Перемещение
-
- - - +
+ + +
-
Вращение (deg)
-
- - - -
-
Масштаб
-
- - - -
- Выберите объект в инспекторе или сцене, чтобы редактировать. -
-
-

Журнал

-
-
-
- - -