Spaces:
Running
Running
| <script lang="ts"> | |
| import { tick } from 'svelte'; | |
| import { Camera, Maximize, Minus, Plus, Video, VideoOff } from '@lucide/svelte'; | |
| import { Panel } from '@xyflow/svelte'; | |
| import { Button } from '$lib/components/ui/button'; | |
| import { viewState } from '$lib/state/view.svelte'; | |
| import { useSvelteFlow } from '@xyflow/svelte'; | |
| import * as Tooltip from '$lib/components/ui/tooltip'; | |
| import { breakpointsState } from '$lib/state/breakpoints.svelte'; | |
| import { useNodes } from '@xyflow/svelte'; | |
| const { zoomIn, zoomOut, getZoom, fitView } = useSvelteFlow(); | |
| const nodesStore = useNodes(); | |
| function requestFitView() { | |
| tick().then(() => { | |
| requestAnimationFrame(() => { | |
| const nodes = nodesStore.current; | |
| if (nodes.length === 0) return; | |
| fitView({ | |
| maxZoom: breakpointsState.isMobile ? 1 : 1.15, | |
| minZoom: 0.7, | |
| padding: breakpointsState.isMobile ? 0 : 0.15, | |
| interpolate: 'smooth', | |
| duration: 250, | |
| nodes: nodes.map((n) => ({ id: n.id })) | |
| }); | |
| }); | |
| }); | |
| } | |
| function toggleDraggable() { | |
| viewState.draggable = !viewState.draggable; | |
| localStorage.setItem('draggable', viewState.draggable.toString()); | |
| } | |
| </script> | |
| <Panel | |
| position="bottom-center" | |
| class="flex items-center justify-start gap-2 p-1 max-lg:hidden lg:p-2" | |
| > | |
| <div | |
| class="inline-flex w-fit flex-row gap-0.5 rounded-lg border border-border bg-background/30 p-1 text-primary backdrop-blur-sm" | |
| > | |
| <Button | |
| variant="ghost" | |
| size="icon-sm" | |
| onclick={() => zoomIn({ duration: 200 })} | |
| disabled={getZoom() >= 1.15} | |
| > | |
| <Plus /> | |
| </Button> | |
| <Button | |
| variant="ghost" | |
| size="icon-sm" | |
| onclick={() => zoomOut({ duration: 200 })} | |
| disabled={getZoom() <= 0.7} | |
| > | |
| <Minus /> | |
| </Button> | |
| <Button variant="ghost" size="icon-sm" onclick={requestFitView}> | |
| <Maximize /> | |
| </Button> | |
| <Tooltip.Root delayDuration={0}> | |
| <Tooltip.Trigger> | |
| <Button | |
| variant={viewState.draggable ? 'default' : 'ghost'} | |
| size="icon-sm" | |
| onclick={toggleDraggable} | |
| > | |
| {#if viewState.draggable} | |
| <Video /> | |
| {:else} | |
| <VideoOff /> | |
| {/if} | |
| </Button> | |
| </Tooltip.Trigger> | |
| <Tooltip.Content class="flex items-center gap-2"> | |
| {#if viewState.draggable} | |
| <Camera class="size-3" /> | |
| Focus camera on scene | |
| {:else} | |
| <VideoOff class="size-3" /> | |
| Free camera movement | |
| {/if} | |
| </Tooltip.Content> | |
| </Tooltip.Root> | |
| </div> | |
| </Panel> | |