Skip to content

Commit 3083276

Browse files
committed
fix slider position
1 parent e2c278c commit 3083276

2 files changed

Lines changed: 58 additions & 7 deletions

File tree

components/playground-workspace.tsx

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
"use client";
22

3+
import { useCallback, useState } from "react";
34
import { useAtom, useAtomValue, useSetAtom } from "jotai";
45
import { Monitor, Smartphone } from "lucide-react";
56
import { CoverPreview } from "@/components/cover-preview";
@@ -56,10 +57,21 @@ export function PlaygroundWorkspace({
5657
const [orientation, setOrientation] = useAtom(orientationAtom);
5758
const config = useAtomValue(configAtom);
5859
const setConfig = useSetAtom(configAtom);
60+
const [bottomWhitespace, setBottomWhitespace] = useState(0);
5961

6062
// Code snippet uses fluid layout (content-based sizing)
6163
const useFluidLayout = config.layoutId === "code-snippet";
6264

65+
const handleViewportMetricsChange = useCallback(
66+
(metrics: { bottomWhitespace: number }) => {
67+
const nextValue = Math.round(metrics.bottomWhitespace);
68+
setBottomWhitespace((previousValue) =>
69+
previousValue === nextValue ? previousValue : nextValue
70+
);
71+
},
72+
[]
73+
);
74+
6375
const handleOrientationChange = (newOrientation: Orientation) => {
6476
// Check if current layout supports new orientation
6577
const currentDef = getLayoutDefinition(config.layoutId);
@@ -175,6 +187,7 @@ export function PlaygroundWorkspace({
175187
isLoading={isAnalyzingColors}
176188
loadingText="Analyzing colors..."
177189
fluidLayout={useFluidLayout}
190+
onViewportMetricsChange={handleViewportMetricsChange}
178191
>
179192
<CoverPreview />
180193
</PreviewViewport>
@@ -188,7 +201,16 @@ export function PlaygroundWorkspace({
188201
</div>
189202

190203
{!useFluidLayout && (
191-
<ScreenshotZoomSlider value={screenshotZoom} onChange={setScreenshotZoom} />
204+
<div
205+
className="relative z-10"
206+
style={
207+
bottomWhitespace
208+
? { transform: `translateY(-${bottomWhitespace}px)` }
209+
: undefined
210+
}
211+
>
212+
<ScreenshotZoomSlider value={screenshotZoom} onChange={setScreenshotZoom} />
213+
</div>
192214
)}
193215
</div>
194216
</div>

components/preview-viewport.tsx

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,14 @@ interface PreviewViewportProps {
1212
isLoading?: boolean;
1313
loadingText?: string;
1414
fluidLayout?: boolean; // For content-based sizing (code snippet)
15+
onViewportMetricsChange?: (metrics: {
16+
scale: number;
17+
containerWidth: number;
18+
containerHeight: number;
19+
scaledWidth: number;
20+
scaledHeight: number;
21+
bottomWhitespace: number;
22+
}) => void;
1523
}
1624

1725
const DEFAULT_SURFACE = {
@@ -27,12 +35,31 @@ export function PreviewViewport({
2735
isLoading = false,
2836
loadingText = "Loading...",
2937
fluidLayout = false,
38+
onViewportMetricsChange,
3039
}: PreviewViewportProps) {
3140
const containerRef = useRef<HTMLDivElement | null>(null);
3241
const [scale, setScale] = useState(1);
3342
const [hasMeasured, setHasMeasured] = useState(false);
3443
const rafRef = useRef<number | undefined>(undefined);
3544

45+
const reportMetrics = useCallback(
46+
(nextScale: number, containerWidth: number, containerHeight: number) => {
47+
const scaledWidth = surfaceWidth * nextScale;
48+
const scaledHeight = surfaceHeight * nextScale;
49+
const bottomWhitespace = Math.max(0, containerHeight - scaledHeight);
50+
51+
onViewportMetricsChange?.({
52+
scale: nextScale,
53+
containerWidth,
54+
containerHeight,
55+
scaledWidth,
56+
scaledHeight,
57+
bottomWhitespace,
58+
});
59+
},
60+
[onViewportMetricsChange, surfaceHeight, surfaceWidth]
61+
);
62+
3663
// Throttled scale update using requestAnimationFrame
3764
const updateScale = useCallback(() => {
3865
if (rafRef.current) return; // Already scheduled
@@ -42,17 +69,18 @@ export function PreviewViewport({
4269
if (!containerRef.current) return;
4370
const containerWidth = containerRef.current.clientWidth;
4471
const containerHeight = containerRef.current.clientHeight;
45-
if (!containerWidth || !containerHeight || !surfaceWidth || !surfaceHeight) return;
72+
if (!containerWidth || !surfaceWidth || !surfaceHeight) return;
4673

4774
// Scale to fit both width and height, ensuring entire canvas is visible without scrolling
4875
const scaleX = containerWidth / surfaceWidth;
49-
const scaleY = containerHeight / surfaceHeight;
76+
const scaleY = containerHeight ? containerHeight / surfaceHeight : Number.POSITIVE_INFINITY;
5077
const nextScale = Math.min(scaleX, scaleY, 1);
5178

5279
setScale(nextScale);
5380
setHasMeasured(true);
81+
reportMetrics(nextScale, containerWidth, containerHeight);
5482
});
55-
}, [surfaceWidth, surfaceHeight]);
83+
}, [surfaceWidth, surfaceHeight, reportMetrics]);
5684

5785
useLayoutEffect(() => {
5886
if (fluidLayout) {
@@ -66,13 +94,14 @@ export function PreviewViewport({
6694
// Initial scale calculation - fit both width and height
6795
const containerWidth = node.clientWidth;
6896
const containerHeight = node.clientHeight;
69-
if (containerWidth && containerHeight && surfaceWidth && surfaceHeight) {
97+
if (containerWidth && surfaceWidth && surfaceHeight) {
7098
const scaleX = containerWidth / surfaceWidth;
71-
const scaleY = containerHeight / surfaceHeight;
99+
const scaleY = containerHeight ? containerHeight / surfaceHeight : Number.POSITIVE_INFINITY;
72100
const nextScale = Math.min(scaleX, scaleY, 1);
73101

74102
setScale(nextScale);
75103
setHasMeasured(true);
104+
reportMetrics(nextScale, containerWidth, containerHeight);
76105
}
77106

78107
const observer = new ResizeObserver(updateScale);
@@ -82,7 +111,7 @@ export function PreviewViewport({
82111
observer.disconnect();
83112
if (rafRef.current) cancelAnimationFrame(rafRef.current);
84113
};
85-
}, [surfaceWidth, surfaceHeight, updateScale, fluidLayout]);
114+
}, [surfaceWidth, surfaceHeight, updateScale, fluidLayout, reportMetrics]);
86115

87116
// Fluid layout: content determines size, no fixed canvas
88117
if (fluidLayout) {

0 commit comments

Comments
 (0)