diff --git a/vibn-frontend/app/[workspace]/project/[projectId]/(home)/preview/page.tsx b/vibn-frontend/app/[workspace]/project/[projectId]/(home)/preview/page.tsx index d50c9d4..91d8d89 100644 --- a/vibn-frontend/app/[workspace]/project/[projectId]/(home)/preview/page.tsx +++ b/vibn-frontend/app/[workspace]/project/[projectId]/(home)/preview/page.tsx @@ -152,6 +152,7 @@ export default function PreviewTab() { const deviceMode = usePreviewToolbarStore((s) => s.deviceMode); const refreshKey = usePreviewToolbarStore((s) => s.refreshKey); + const currentPath = usePreviewToolbarStore((s) => s.currentPath); // When the user clicks the manual refresh button in the toolbar, we don't // just want to reload the iframe — we also want to trigger the same ghost/zombie @@ -166,8 +167,16 @@ export default function PreviewTab() { }, [refreshKey]); useLayoutEffect(() => { - setIframeSrc(primaryRunning?.url ?? null); - }, [primaryRunning?.url]); + if (!primaryRunning?.url) { + setIframeSrc(null); + } else { + const base = primaryRunning.url.replace(/\/$/, ""); + const path = currentPath.startsWith("/") + ? currentPath + : `/${currentPath}`; + setIframeSrc(`${base}${path}`); + } + }, [primaryRunning?.url, currentPath]); useEffect(() => { if (!bridge || !iframeSrc || !iframeDomRef.current) return; diff --git a/vibn-frontend/components/project/preview-toolbar/preview-toolbar-state.ts b/vibn-frontend/components/project/preview-toolbar/preview-toolbar-state.ts index ffa672f..796a354 100644 --- a/vibn-frontend/components/project/preview-toolbar/preview-toolbar-state.ts +++ b/vibn-frontend/components/project/preview-toolbar/preview-toolbar-state.ts @@ -5,6 +5,8 @@ interface PreviewToolbarState { setDeviceMode: (mode: "desktop" | "tablet" | "mobile") => void; refreshKey: number; triggerRefresh: () => void; + currentPath: string; + setCurrentPath: (path: string) => void; } export const usePreviewToolbarStore = create((set) => ({ @@ -12,4 +14,6 @@ export const usePreviewToolbarStore = create((set) => ({ setDeviceMode: (mode) => set({ deviceMode: mode }), refreshKey: 0, triggerRefresh: () => set((state) => ({ refreshKey: state.refreshKey + 1 })), + currentPath: "/", + setCurrentPath: (path) => set({ currentPath: path }), })); diff --git a/vibn-frontend/components/project/project-icon-rail.tsx b/vibn-frontend/components/project/project-icon-rail.tsx index 94949ef..a3bc4aa 100644 --- a/vibn-frontend/components/project/project-icon-rail.tsx +++ b/vibn-frontend/components/project/project-icon-rail.tsx @@ -92,6 +92,8 @@ function PreviewDeviceToggles() { const deviceMode = usePreviewToolbarStore((s) => s.deviceMode); const setDeviceMode = usePreviewToolbarStore((s) => s.setDeviceMode); const triggerRefresh = usePreviewToolbarStore((s) => s.triggerRefresh); + const currentPath = usePreviewToolbarStore((s) => s.currentPath); + const setCurrentPath = usePreviewToolbarStore((s) => s.setCurrentPath); const params = useParams(); const projectId = params?.projectId as string; @@ -157,12 +159,23 @@ function PreviewDeviceToggles() { }} /> - 🌐 + + / + + setCurrentPath("/" + e.target.value.replace(/^\//, "")) + } + placeholder="path (e.g. dashboard)" style={{ background: "transparent", border: "none", @@ -172,7 +185,12 @@ function PreviewDeviceToggles() { color: "#18181b", fontSize: "0.75rem", textOverflow: "ellipsis", - paddingLeft: 4, + fontFamily: "var(--font-mono), monospace", + }} + onKeyDown={(e) => { + if (e.key === "Enter") { + triggerRefresh(); // force reload iframe + } }} />