feat(ui): add manual reload button to preview device toggles

This commit is contained in:
2026-05-15 16:31:31 -07:00
parent feebeccd8e
commit 8cb7a9450b
3 changed files with 49 additions and 8 deletions

View File

@@ -26,7 +26,7 @@ export default function PreviewTab() {
const previews = anatomy?.hosting.previews ?? []; const previews = anatomy?.hosting.previews ?? [];
// Find the port 3000 preview if it exists, otherwise fall back to null // Find the port 3000 preview if it exists, otherwise fall back to null
const primaryPreview = previews.find(p => p.port === 3000); const primaryPreview = previews.find((p) => p.port === 3000);
const [iframeSrc, setIframeSrc] = useState<string | null>(null); const [iframeSrc, setIframeSrc] = useState<string | null>(null);
const iframeDomRef = useRef<HTMLIFrameElement | null>(null); const iframeDomRef = useRef<HTMLIFrameElement | null>(null);
@@ -34,6 +34,7 @@ export default function PreviewTab() {
const origin = typeof window !== "undefined" ? window.location.origin : ""; const origin = typeof window !== "undefined" ? window.location.origin : "";
const deviceMode = usePreviewToolbarStore((s) => s.deviceMode); const deviceMode = usePreviewToolbarStore((s) => s.deviceMode);
const refreshKey = usePreviewToolbarStore((s) => s.refreshKey);
useLayoutEffect(() => { useLayoutEffect(() => {
setIframeSrc(primaryPreview?.url ?? null); setIframeSrc(primaryPreview?.url ?? null);
@@ -72,7 +73,7 @@ export default function PreviewTab() {
</div> </div>
) : iframeSrc ? ( ) : iframeSrc ? (
<iframe <iframe
key={iframeSrc} key={`${iframeSrc}-${refreshKey}`}
src={iframeSrc} src={iframeSrc}
title="Preview" title="Preview"
ref={(el) => { ref={(el) => {
@@ -91,7 +92,9 @@ export default function PreviewTab() {
) : ( ) : (
<div style={loaderWrap}> <div style={loaderWrap}>
<p style={emptyText}>Preview not running on port 3000.</p> <p style={emptyText}>Preview not running on port 3000.</p>
<p style={{...emptyText, fontSize: '0.75rem', marginTop: 8}}>Ask the AI to start the dev server.</p> <p style={{ ...emptyText, fontSize: "0.75rem", marginTop: 8 }}>
Ask the AI to start the dev server.
</p>
</div> </div>
)} )}

View File

@@ -1,11 +1,15 @@
import { create } from 'zustand'; import { create } from "zustand";
interface PreviewToolbarState { interface PreviewToolbarState {
deviceMode: 'desktop' | 'mobile'; deviceMode: "desktop" | "mobile";
setDeviceMode: (mode: 'desktop' | 'mobile') => void; setDeviceMode: (mode: "desktop" | "mobile") => void;
refreshKey: number;
triggerRefresh: () => void;
} }
export const usePreviewToolbarStore = create<PreviewToolbarState>((set) => ({ export const usePreviewToolbarStore = create<PreviewToolbarState>((set) => ({
deviceMode: 'desktop', deviceMode: "desktop",
setDeviceMode: (mode) => set({ deviceMode: mode }), setDeviceMode: (mode) => set({ deviceMode: mode }),
refreshKey: 0,
triggerRefresh: () => set((state) => ({ refreshKey: state.refreshKey + 1 })),
})); }));

View File

@@ -91,12 +91,13 @@ export function ProjectIconRail({ workspace, projectId }: Props) {
); );
} }
import { Monitor, Smartphone } from "lucide-react"; import { Monitor, Smartphone, RotateCw } from "lucide-react";
import { usePreviewToolbarStore } from "./preview-toolbar/preview-toolbar-state"; import { usePreviewToolbarStore } from "./preview-toolbar/preview-toolbar-state";
function PreviewDeviceToggles() { function PreviewDeviceToggles() {
const deviceMode = usePreviewToolbarStore((s) => s.deviceMode); const deviceMode = usePreviewToolbarStore((s) => s.deviceMode);
const setDeviceMode = usePreviewToolbarStore((s) => s.setDeviceMode); const setDeviceMode = usePreviewToolbarStore((s) => s.setDeviceMode);
const triggerRefresh = usePreviewToolbarStore((s) => s.triggerRefresh);
return ( return (
<div <div
@@ -109,6 +110,39 @@ function PreviewDeviceToggles() {
border: "1px solid #e8e4dc", border: "1px solid #e8e4dc",
}} }}
> >
<button
onClick={triggerRefresh}
title="Reload Preview"
style={{
display: "flex",
alignItems: "center",
justifyContent: "center",
width: 28,
height: 26,
borderRadius: 6,
border: "none",
cursor: "pointer",
transition: "all 0.15s",
background: "transparent",
color: "#8c8580",
marginRight: 4,
}}
onMouseEnter={(e) => (e.currentTarget.style.color = "#1a1a1a")}
onMouseLeave={(e) => (e.currentTarget.style.color = "#8c8580")}
>
<RotateCw size={14} />
</button>
<div
style={{
width: 1,
height: 16,
background: "#d9d2c5",
alignSelf: "center",
marginRight: 4,
}}
/>
<button <button
onClick={() => setDeviceMode("desktop")} onClick={() => setDeviceMode("desktop")}
style={{ style={{