mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-09 11:31:27 +00:00
webapp pagescene: fix top blank space; de-topbar shared lib layout
- styles.css: move .glass into @layer components so Tailwind's .absolute utility wins the cascade. OnboardingHelper was rendering position: relative and pushing the editor down on first paint until clicking dismissed it. - SceneContainer + Stage3DBody: drop hardcoded calc(100vh - 68px) and height - 56 topbar offsets; the lib now fills its parent container. - Webapp adapter: drop the +56 getViewportSize compensation now that the lib doesn't subtract a topbar from the supplied height. - Tauri PageScene: wrap Stage3D in a calc(100vh - 56px) container (matching .topbar-spacer) so its shape is preserved. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
1 parent
3bb188eaf7
commit
fcb0ddec56
5 files changed
+48
-53
No files matched your search
@@ -5,32 +5,23 @@ import { useSession } from "../../lib/session";
|
||||
import { useSidebar } from "../../components/ui/sidebar";
|
||||
import { useWebAppPageSceneAdapter } from "./web-adapter";
|
||||
|
||||
// Stage3D was designed for the Tauri host: its outermost div is
|
||||
// `w-screen` × `calc(100vh - 68px)` and SceneContainer subtracts a
|
||||
// hardcoded 56px from the adapter-supplied viewport height to leave
|
||||
// room for the host's TopBar. The webapp lives inside a sidebar +
|
||||
// topbar shell that already takes its slice out of the viewport, so
|
||||
// this wrapper translates the lib's assumptions into webapp space:
|
||||
// Stage3D fills its parent box; this wrapper is that box. It clamps
|
||||
// the editor to the SidebarInset area and feeds the lib its rect:
|
||||
//
|
||||
// - `overflow-hidden h-full w-full` clamps the lib's viewport-sized
|
||||
// chrome to the area SidebarInset gives us, so the inset never
|
||||
// grows a scrollbar around the editor.
|
||||
// - `getViewportSize` reads the wrapper's current rect on every call
|
||||
// and adds the lib's hardcoded 56px topbar compensation, so the
|
||||
// SceneContainer's `height - 56` math lands on the wrapper rect.
|
||||
// - `overflow-hidden h-full w-full` sizes Stage3D to the inset and
|
||||
// prevents the inset from growing a scrollbar around the editor.
|
||||
// - `getViewportSize` reports the wrapper's current rect. Consumers
|
||||
// in the lib (getScale, absolute-positioned chrome) read it via
|
||||
// `useViewportSize`.
|
||||
// - The lib's `useViewportSize` only re-reads on `window` resize, so
|
||||
// a ResizeObserver here dispatches a synthetic resize whenever our
|
||||
// rect changes (sidebar collapse, peer mounts, browser resize) and
|
||||
// once on mount (the lib's `useState` initializer ran before any
|
||||
// refs were attached and saw the window-size fallback).
|
||||
// rect changes (sidebar collapse, browser resize).
|
||||
// - `transform: translateZ(0)` makes this div a containing block
|
||||
// for the lib's `position: fixed` overlays so they scope here.
|
||||
//
|
||||
// On entry the sidebar auto-collapses on desktop to give the lib's
|
||||
// 100vw-leaning layout the room it expects.
|
||||
|
||||
const LIB_TOP_BAR_COMPENSATION_PX = 56;
|
||||
|
||||
export default function PageScene() {
|
||||
const { sceneToken } = useParams<{ sceneToken?: string }>();
|
||||
const { user } = useSession();
|
||||
@@ -78,7 +69,7 @@ export default function PageScene() {
|
||||
}
|
||||
return {
|
||||
width: node.clientWidth,
|
||||
height: node.clientHeight + LIB_TOP_BAR_COMPENSATION_PX,
|
||||
height: node.clientHeight,
|
||||
};
|
||||
}, []);
|
||||
|
||||
|
||||
@@ -176,9 +176,11 @@
|
||||
}
|
||||
}
|
||||
|
||||
.glass {
|
||||
@apply relative border border-white/10 shadow-lg backdrop-blur-xl transition-colors duration-300;
|
||||
@apply bg-ui-controls/85 !important;
|
||||
@layer components {
|
||||
.glass {
|
||||
@apply relative border border-white/10 shadow-lg backdrop-blur-xl transition-colors duration-300;
|
||||
@apply bg-ui-controls/85 !important;
|
||||
}
|
||||
}
|
||||
|
||||
.liquid-glass {
|
||||
|
||||
@@ -60,12 +60,17 @@ export const PageScene = ({ sceneToken }: { sceneToken?: string }) => {
|
||||
}
|
||||
});
|
||||
|
||||
// Sized container for Stage3D. The lib fills its parent; the
|
||||
// Tauri host's TopBar lives outside this box, so we reserve space
|
||||
// here. 56px matches the `.topbar-spacer` height in base.css.
|
||||
return (
|
||||
<Stage3D
|
||||
adapter={adapter}
|
||||
sceneToken={sceneToken}
|
||||
cacheJsonString={cacheJsonString}
|
||||
onSceneSerialized={onSceneSerialized}
|
||||
/>
|
||||
<div className="w-screen" style={{ height: "calc(100vh - 56px)" }}>
|
||||
<Stage3D
|
||||
adapter={adapter}
|
||||
sceneToken={sceneToken}
|
||||
cacheJsonString={cacheJsonString}
|
||||
onSceneSerialized={onSceneSerialized}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -108,7 +108,6 @@ export const Stage3DBody = () => {
|
||||
// window.innerWidth/innerHeight when the host adapter doesn't
|
||||
// supply getViewportSize, so the layout always has sane values.
|
||||
const viewport = useViewportSize();
|
||||
const height = viewport.height - 56;
|
||||
|
||||
const getScale = () => {
|
||||
const h = viewport.height - 56;
|
||||
@@ -320,17 +319,13 @@ export const Stage3DBody = () => {
|
||||
}, [editor]);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="h-full w-full">
|
||||
<OnboardingHelper />
|
||||
|
||||
<div
|
||||
className="relative flex w-screen"
|
||||
style={{ height: "calc(100vh - 68px)" }}
|
||||
>
|
||||
<div className="relative flex h-full w-full">
|
||||
<div
|
||||
id="engine-n-panels-wrapper"
|
||||
className="flex"
|
||||
style={{ height }}
|
||||
className="flex h-full w-full"
|
||||
>
|
||||
<div className="relative w-full overflow-hidden bg-transparent">
|
||||
<SceneContainer>
|
||||
|
||||
+20
-18
@@ -1,43 +1,45 @@
|
||||
import { useCallback } from "react";
|
||||
import { useCallback, useEffect, useRef, useState } from "react";
|
||||
import { usePageSceneStore } from "../../PageSceneStore";
|
||||
import { useViewportSize } from "../../hooks/useViewportSize";
|
||||
import { Letterbox } from "./Letterbox";
|
||||
|
||||
// 56px is the artcraft host's TopBar; subtracted from the viewport
|
||||
// height so the scene container fills the area below the bar. Hosts
|
||||
// without a TopBar can pass a getViewportSize that already accounts
|
||||
// for their chrome.
|
||||
const TOP_BAR_PX = 56;
|
||||
|
||||
export const SceneContainer = ({ children }: { children: React.ReactNode }) => {
|
||||
const editorLetterBox = usePageSceneStore((s) => s.editorLetterBox);
|
||||
const { width, height } = useViewportSize();
|
||||
const containerWidth = width;
|
||||
const containerHeight = height - TOP_BAR_PX;
|
||||
const [size, setSize] = useState({ width: 0, height: 0 });
|
||||
const nodeRef = useRef<HTMLDivElement | null>(null);
|
||||
|
||||
// Sets the DOM node both on mount (truthy) and unmount (null) so the
|
||||
// engine lifecycle effect can react to the canvas unmounting when the
|
||||
// tab switches away from 3D. The previous `if (node)` filter swallowed
|
||||
// the unmount case and leaked the Editor instance.
|
||||
const callbackRef = useCallback((node: HTMLDivElement | null) => {
|
||||
nodeRef.current = node;
|
||||
usePageSceneStore.getState().setSceneContainerEl(node);
|
||||
if (node) {
|
||||
setSize({ width: node.clientWidth, height: node.clientHeight });
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const node = nodeRef.current;
|
||||
if (!node) return undefined;
|
||||
const observer = new ResizeObserver(() => {
|
||||
setSize({ width: node.clientWidth, height: node.clientHeight });
|
||||
});
|
||||
observer.observe(node);
|
||||
return () => observer.disconnect();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={callbackRef}
|
||||
id="video-scene-container"
|
||||
className="relative"
|
||||
style={{
|
||||
width: containerWidth,
|
||||
height: containerHeight,
|
||||
}}
|
||||
className="relative h-full w-full"
|
||||
>
|
||||
{children}
|
||||
<Letterbox
|
||||
isShowing={editorLetterBox}
|
||||
width={containerWidth}
|
||||
height={containerHeight}
|
||||
width={size.width}
|
||||
height={size.height}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in new issue
Block a user