Refine BIM comment modal glass and resize
This commit is contained in:
parent
7d65070f59
commit
778a56ea39
|
|
@ -720,11 +720,8 @@ header {
|
||||||
display: block;
|
display: block;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
fill: none;
|
fill: currentColor;
|
||||||
stroke: currentColor;
|
stroke: none;
|
||||||
stroke-width: 1.7;
|
|
||||||
stroke-linecap: round;
|
|
||||||
stroke-linejoin: round;
|
|
||||||
filter: drop-shadow(0 5px 12px rgba(0, 0, 0, 0.48));
|
filter: drop-shadow(0 5px 12px rgba(0, 0, 0, 0.48));
|
||||||
overflow: visible;
|
overflow: visible;
|
||||||
}
|
}
|
||||||
|
|
@ -1491,6 +1488,10 @@ header {
|
||||||
|
|
||||||
#commentModalBackdrop {
|
#commentModalBackdrop {
|
||||||
z-index: 30045;
|
z-index: 30045;
|
||||||
|
background: transparent;
|
||||||
|
backdrop-filter: none;
|
||||||
|
-webkit-backdrop-filter: none;
|
||||||
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.templates-panel.measurement-modal {
|
.templates-panel.measurement-modal {
|
||||||
|
|
@ -1632,7 +1633,7 @@ header {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
--env-control-h: 42px;
|
--env-control-h: 42px;
|
||||||
--ops-comment-accent: var(--comment-target-active, #c4ff67);
|
--ops-comment-accent: var(--comment-target-active, #c4ff67);
|
||||||
--ops-detail-bg: rgba(18, 18, 20, 0.96);
|
--ops-detail-bg: color-mix(in srgb, var(--modal-bg) var(--modal-bg-alpha, 100%), transparent);
|
||||||
--ops-detail-surface: rgba(28, 28, 31, 0.76);
|
--ops-detail-surface: rgba(28, 28, 31, 0.76);
|
||||||
--ops-detail-surface-strong: rgba(32, 32, 35, 0.92);
|
--ops-detail-surface-strong: rgba(32, 32, 35, 0.92);
|
||||||
--ops-detail-border: rgba(255, 255, 255, 0.055);
|
--ops-detail-border: rgba(255, 255, 255, 0.055);
|
||||||
|
|
@ -1647,7 +1648,6 @@ header {
|
||||||
border: 1px solid rgba(255, 255, 255, 0.06);
|
border: 1px solid rgba(255, 255, 255, 0.06);
|
||||||
border-radius: 30px;
|
border-radius: 30px;
|
||||||
background:
|
background:
|
||||||
radial-gradient(circle at 80% 20%, rgba(130, 58, 120, 0.13), transparent 34%),
|
|
||||||
linear-gradient(180deg, rgba(255, 255, 255, 0.018), rgba(255, 255, 255, 0.006)),
|
linear-gradient(180deg, rgba(255, 255, 255, 0.018), rgba(255, 255, 255, 0.006)),
|
||||||
var(--ops-detail-bg);
|
var(--ops-detail-bg);
|
||||||
box-shadow: 0 28px 80px rgba(0, 0, 0, 0.64);
|
box-shadow: 0 28px 80px rgba(0, 0, 0, 0.64);
|
||||||
|
|
@ -1669,6 +1669,81 @@ header {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.window-resize-handle {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 4;
|
||||||
|
background: transparent;
|
||||||
|
touch-action: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.window-resize-handle--n,
|
||||||
|
.window-resize-handle--s {
|
||||||
|
left: 22px;
|
||||||
|
right: 22px;
|
||||||
|
height: 10px;
|
||||||
|
cursor: ns-resize;
|
||||||
|
}
|
||||||
|
|
||||||
|
.window-resize-handle--n {
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.window-resize-handle--s {
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.window-resize-handle--e,
|
||||||
|
.window-resize-handle--w {
|
||||||
|
top: 22px;
|
||||||
|
bottom: 22px;
|
||||||
|
width: 10px;
|
||||||
|
cursor: ew-resize;
|
||||||
|
}
|
||||||
|
|
||||||
|
.window-resize-handle--e {
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.window-resize-handle--w {
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.window-resize-handle--ne,
|
||||||
|
.window-resize-handle--nw,
|
||||||
|
.window-resize-handle--se,
|
||||||
|
.window-resize-handle--sw {
|
||||||
|
width: 22px;
|
||||||
|
height: 22px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.window-resize-handle--ne {
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
cursor: nesw-resize;
|
||||||
|
}
|
||||||
|
|
||||||
|
.window-resize-handle--nw {
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
cursor: nwse-resize;
|
||||||
|
}
|
||||||
|
|
||||||
|
.window-resize-handle--se {
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
cursor: nwse-resize;
|
||||||
|
}
|
||||||
|
|
||||||
|
.window-resize-handle--sw {
|
||||||
|
left: 0;
|
||||||
|
bottom: 0;
|
||||||
|
cursor: nesw-resize;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comment-card-modal.is-expanded .window-resize-handle {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
.comment-card-modal__header {
|
.comment-card-modal__header {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
|
||||||
|
|
@ -525,7 +525,7 @@ const getShareTokenFromPath = () => {
|
||||||
|
|
||||||
const COMMENT_TARGET_ICON = `
|
const COMMENT_TARGET_ICON = `
|
||||||
<svg viewBox="0 0 24 24" aria-hidden="true">
|
<svg viewBox="0 0 24 24" aria-hidden="true">
|
||||||
<path d="M6.5 5.5h11a2.5 2.5 0 0 1 2.5 2.5v6.25a2.5 2.5 0 0 1-2.5 2.5H12l-4.3 3.1v-3.1H6.5A2.5 2.5 0 0 1 4 14.25V8a2.5 2.5 0 0 1 2.5-2.5Z"></path>
|
<path d="M6.5 4.75h11A3.25 3.25 0 0 1 20.75 8v6.25a3.25 3.25 0 0 1-3.25 3.25h-5.26l-5.29 3.82V17.5H6.5a3.25 3.25 0 0 1-3.25-3.25V8A3.25 3.25 0 0 1 6.5 4.75Z"></path>
|
||||||
</svg>
|
</svg>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|
@ -1485,6 +1485,115 @@ const setupDraggableFixedWindow = (element, handle) => {
|
||||||
handle.addEventListener("pointercancel", endDrag);
|
handle.addEventListener("pointercancel", endDrag);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const setupResizableFixedWindow = (element, { minWidth = 520, minHeight = 420, margin = 8 } = {}) => {
|
||||||
|
if (!element || element.dataset.resizableReady === "true") return;
|
||||||
|
element.dataset.resizableReady = "true";
|
||||||
|
const directions = ["n", "e", "s", "w", "ne", "nw", "se", "sw"];
|
||||||
|
let resize = null;
|
||||||
|
|
||||||
|
const fixCurrentRect = () => {
|
||||||
|
const rect = element.getBoundingClientRect();
|
||||||
|
element.style.left = `${rect.left}px`;
|
||||||
|
element.style.top = `${rect.top}px`;
|
||||||
|
element.style.right = "auto";
|
||||||
|
element.style.bottom = "auto";
|
||||||
|
element.style.width = `${rect.width}px`;
|
||||||
|
element.style.height = `${rect.height}px`;
|
||||||
|
element.style.maxHeight = "none";
|
||||||
|
element.style.transform = "none";
|
||||||
|
return rect;
|
||||||
|
};
|
||||||
|
|
||||||
|
const beginResize = (direction, pointerId, clientX, clientY) => {
|
||||||
|
bringFloatingWindowToFront(element.id === "commentModal" ? "commentModal" : element.id);
|
||||||
|
const rect = fixCurrentRect();
|
||||||
|
resize = {
|
||||||
|
pointerId,
|
||||||
|
direction,
|
||||||
|
startX: clientX,
|
||||||
|
startY: clientY,
|
||||||
|
left: rect.left,
|
||||||
|
top: rect.top,
|
||||||
|
width: rect.width,
|
||||||
|
height: rect.height,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateResize = (clientX, clientY) => {
|
||||||
|
if (!resize) return;
|
||||||
|
const dx = clientX - resize.startX;
|
||||||
|
const dy = clientY - resize.startY;
|
||||||
|
const right = resize.left + resize.width;
|
||||||
|
const bottom = resize.top + resize.height;
|
||||||
|
let left = resize.left;
|
||||||
|
let top = resize.top;
|
||||||
|
let width = resize.width;
|
||||||
|
let height = resize.height;
|
||||||
|
|
||||||
|
if (resize.direction.includes("w")) {
|
||||||
|
left = Math.max(margin, Math.min(resize.left + dx, right - minWidth));
|
||||||
|
width = right - left;
|
||||||
|
}
|
||||||
|
if (resize.direction.includes("e")) {
|
||||||
|
width = Math.max(minWidth, resize.width + dx);
|
||||||
|
width = Math.min(width, window.innerWidth - margin - left);
|
||||||
|
}
|
||||||
|
if (resize.direction.includes("n")) {
|
||||||
|
top = Math.max(margin, Math.min(resize.top + dy, bottom - minHeight));
|
||||||
|
height = bottom - top;
|
||||||
|
}
|
||||||
|
if (resize.direction.includes("s")) {
|
||||||
|
height = Math.max(minHeight, resize.height + dy);
|
||||||
|
height = Math.min(height, window.innerHeight - margin - top);
|
||||||
|
}
|
||||||
|
|
||||||
|
element.style.left = `${Math.round(left)}px`;
|
||||||
|
element.style.top = `${Math.round(top)}px`;
|
||||||
|
element.style.width = `${Math.round(width)}px`;
|
||||||
|
element.style.height = `${Math.round(height)}px`;
|
||||||
|
};
|
||||||
|
|
||||||
|
directions.forEach((direction) => {
|
||||||
|
const handle = document.createElement("span");
|
||||||
|
handle.className = `window-resize-handle window-resize-handle--${direction}`;
|
||||||
|
handle.dataset.resizeDirection = direction;
|
||||||
|
handle.setAttribute("aria-hidden", "true");
|
||||||
|
element.appendChild(handle);
|
||||||
|
handle.addEventListener("pointerdown", (event) => {
|
||||||
|
if (event.pointerType === "mouse" && event.button !== 0) return;
|
||||||
|
if (element.classList.contains("is-expanded")) return;
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
beginResize(direction, event.pointerId, event.clientX, event.clientY);
|
||||||
|
handle.setPointerCapture?.(event.pointerId);
|
||||||
|
});
|
||||||
|
handle.addEventListener("pointermove", (event) => {
|
||||||
|
if (!resize || resize.pointerId !== event.pointerId) return;
|
||||||
|
updateResize(event.clientX, event.clientY);
|
||||||
|
});
|
||||||
|
handle.addEventListener("mousedown", (event) => {
|
||||||
|
if (event.button !== 0 || element.classList.contains("is-expanded")) return;
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
beginResize(direction, "mouse", event.clientX, event.clientY);
|
||||||
|
});
|
||||||
|
const endResize = (event) => {
|
||||||
|
if (!resize || resize.pointerId !== event.pointerId) return;
|
||||||
|
handle.releasePointerCapture?.(event.pointerId);
|
||||||
|
resize = null;
|
||||||
|
};
|
||||||
|
handle.addEventListener("pointerup", endResize);
|
||||||
|
handle.addEventListener("pointercancel", endResize);
|
||||||
|
});
|
||||||
|
window.addEventListener("mousemove", (event) => {
|
||||||
|
if (!resize || resize.pointerId !== "mouse") return;
|
||||||
|
updateResize(event.clientX, event.clientY);
|
||||||
|
});
|
||||||
|
window.addEventListener("mouseup", () => {
|
||||||
|
if (resize?.pointerId === "mouse") resize = null;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const bindFooterButtonAction = (button, handler) => {
|
const bindFooterButtonAction = (button, handler) => {
|
||||||
if (!button || typeof handler !== "function") return;
|
if (!button || typeof handler !== "function") return;
|
||||||
button.addEventListener("click", handler);
|
button.addEventListener("click", handler);
|
||||||
|
|
@ -5308,6 +5417,7 @@ const loadProjectSnapshot = async (project) => {
|
||||||
registerFloatingWindowElement("commentModal", commentModal);
|
registerFloatingWindowElement("commentModal", commentModal);
|
||||||
setupDraggableFixedWindow(commentsPanel, commentsPanelHeader);
|
setupDraggableFixedWindow(commentsPanel, commentsPanelHeader);
|
||||||
setupDraggableFixedWindow(commentModal, commentModalHeader);
|
setupDraggableFixedWindow(commentModal, commentModalHeader);
|
||||||
|
setupResizableFixedWindow(commentModal, { minWidth: 560, minHeight: 420 });
|
||||||
commentsCollapseButton?.addEventListener("click", () => setCommentsCollapsed(true));
|
commentsCollapseButton?.addEventListener("click", () => setCommentsCollapsed(true));
|
||||||
commentsRestoreButton?.addEventListener("click", () => {
|
commentsRestoreButton?.addEventListener("click", () => {
|
||||||
commentsModeActive = true;
|
commentsModeActive = true;
|
||||||
|
|
|
||||||
|
|
@ -134,7 +134,7 @@
|
||||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||||
<link href="https://fonts.googleapis.com/css2?family=Manrope:wght@500;600;700&display=swap" rel="stylesheet">
|
<link href="https://fonts.googleapis.com/css2?family=Manrope:wght@500;600;700&display=swap" rel="stylesheet">
|
||||||
<link rel="stylesheet" href="./dcViewer.css?v=27">
|
<link rel="stylesheet" href="./dcViewer.css?v=29">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<header>
|
<header>
|
||||||
|
|
@ -570,6 +570,6 @@
|
||||||
<input id="fileInput" class="hidden" type="file"
|
<input id="fileInput" class="hidden" type="file"
|
||||||
accept=".xkt,.glb,.gltf,.bim,.las,.laz,.obj,.stl">
|
accept=".xkt,.glb,.gltf,.bim,.las,.laz,.obj,.stl">
|
||||||
|
|
||||||
<script type="module" src="./dcViewer.js?v=40"></script>
|
<script type="module" src="./dcViewer.js?v=43"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue