diff --git a/frontend/dcViewer.css b/frontend/dcViewer.css index a4d8dbe..c2ff846 100644 --- a/frontend/dcViewer.css +++ b/frontend/dcViewer.css @@ -359,6 +359,103 @@ header { display: none; } +.side-panel.is-collapsed { + display: none !important; +} + +.inspector-panel-header { + display: flex; + align-items: center; + justify-content: space-between; + min-height: 28px; + margin: 0 0 8px; +} + +.inspector-panel-header h3 { + margin: 0; +} + +.inspector-collapse-btn { + display: grid; + place-items: center; + width: 28px; + height: 28px; + margin: -2px -2px 0 8px; + padding: 0; + border: 0; + border-radius: 10px; + background: transparent; + color: var(--modal-btn-primary, var(--accent)); + cursor: pointer; + font: inherit; + font-size: 18px; + font-weight: 900; + line-height: 1; + outline: none; + transition: background 140ms ease, transform 100ms ease; +} + +.inspector-collapse-btn:hover { + background: var(--nodedc-glass-control-hover); +} + +.inspector-collapse-btn:active { + transform: translateY(1px); +} + +.inspector-collapse-btn:focus, +.inspector-collapse-btn:focus-visible { + outline: none; + box-shadow: none; +} + +.inspector-restore-tray { + position: fixed; + right: 12px; + bottom: 12px; + width: 320px; + padding: 0 14px; + z-index: 12; + box-sizing: border-box; + pointer-events: none; +} + +.inspector-restore-button { + display: flex; + align-items: center; + justify-content: center; + width: 100%; + height: 40px; + padding: 0 16px; + border: 0; + border-radius: 14px; + background: var(--modal-btn-primary, var(--accent)); + color: var(--modal-btn-primary-contrast, #15170f); + box-shadow: var(--nodedc-glass-control-shadow); + cursor: pointer; + font: inherit; + font-size: 12px; + font-weight: 800; + line-height: 1; + text-transform: uppercase; + pointer-events: auto; + transition: filter 140ms ease, transform 100ms ease; +} + +.inspector-restore-button:hover { + filter: brightness(1.05); +} + +.inspector-restore-button:active { + transform: translateY(1px); +} + +.inspector-restore-button:focus, +.inspector-restore-button:focus-visible { + outline: none; + box-shadow: none; +} + .panel-section { background: transparent; border: none; @@ -371,6 +468,10 @@ header { font-size: 15px; } +.panel-section .inspector-panel-header h3 { + margin: 0; +} + .panel-section p, .panel-section ul { margin: 0; diff --git a/frontend/dcViewer.js b/frontend/dcViewer.js index 6bc624b..286b628 100644 --- a/frontend/dcViewer.js +++ b/frontend/dcViewer.js @@ -16,6 +16,9 @@ const dropZone = document.getElementById("dropZone"); const viewerWrapper = document.querySelector(".viewer-wrapper"); const headerEl = document.querySelector("header"); const sidePanelEl = document.querySelector(".side-panel"); +const inspectorCollapseButton = document.getElementById("inspectorCollapseButton"); +const inspectorRestoreTray = document.getElementById("inspectorRestoreTray"); +const inspectorRestoreButton = document.getElementById("inspectorRestoreButton"); const fileInput = document.getElementById("fileInput"); const chooseFileBtn = document.getElementById("chooseFile"); const examplesBar = document.getElementById("examplesBar"); @@ -220,6 +223,7 @@ let activeDisplayMode = "source"; let activeLightingMode = "ambient"; let activeNavigationAxis = "auto"; let activeZoomSpeed = 20; +let inspectorCollapsed = false; let displayModeSelect = null; let lightingModeSelect = null; let navigationAxisSelect = null; @@ -1077,7 +1081,13 @@ const rebuildNavCube = (sdk) => { const updatePanelsVisibility = () => { const hasModels = activeModels.length > 0; - if (sidePanelEl) sidePanelEl.style.display = hasModels ? "flex" : "none"; + if (sidePanelEl) { + sidePanelEl.classList.toggle("is-collapsed", hasModels && inspectorCollapsed); + sidePanelEl.style.display = hasModels && !inspectorCollapsed ? "flex" : "none"; + } + if (inspectorRestoreTray) { + inspectorRestoreTray.hidden = !hasModels || !inspectorCollapsed; + } if (treeContainer) treeContainer.classList.toggle("hidden", !hasModels); const showActions = hasModels || !!currentProjectMeta || !!lastAttemptedProjectId; if (saveProjectSection) { @@ -1104,6 +1114,15 @@ const updatePanelsVisibility = () => { } }; +const setInspectorCollapsed = (collapsed) => { + inspectorCollapsed = !!collapsed; + if (inspectorCollapseButton) { + inspectorCollapseButton.setAttribute("aria-expanded", String(!inspectorCollapsed)); + } + updatePanelsVisibility(); + focusCanvasAndControls(); +}; + const centerFromAABB = (aabb) => { if (!Array.isArray(aabb) || aabb.length !== 6) return [0, 0, 0]; return [ @@ -3685,6 +3704,8 @@ const loadProjectSnapshot = async (project) => { }); zoomSpeedControl.replaceChildren(zoomSpeedSlider); } + inspectorCollapseButton?.addEventListener("click", () => setInspectorCollapsed(true)); + inspectorRestoreButton?.addEventListener("click", () => setInspectorCollapsed(false)); loadProjectsList().catch(() => { templatesMenu?.setData({ templates: templateFallbacks, projects: [], error: "API недоступно" }); }); diff --git a/frontend/index.html b/frontend/index.html index 632bb06..5538782 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -124,9 +124,18 @@ -