feat: initial commit, draft frontend
This commit is contained in:
90
src/routes/p/[id]/+page.svelte
Normal file
90
src/routes/p/[id]/+page.svelte
Normal file
@@ -0,0 +1,90 @@
|
||||
<script lang="ts">
|
||||
import { page } from '$app/state';
|
||||
import { goto } from '$app/navigation';
|
||||
import { Button } from 'bits-ui';
|
||||
import { Maximize, Minimize, ArrowLeft } from '@lucide/svelte';
|
||||
|
||||
const id = $derived(page.params.id);
|
||||
const src = $derived(`/projects/${id}/index.html`);
|
||||
|
||||
let isFullscreen = $state(false);
|
||||
let containerRef = $state<HTMLDivElement | null>(null);
|
||||
let iframeRef = $state<HTMLIFrameElement | null>(null);
|
||||
|
||||
const toggleFullscreen = async () => {
|
||||
if (!containerRef) return;
|
||||
|
||||
if (!document.fullscreenElement) {
|
||||
await containerRef.requestFullscreen();
|
||||
isFullscreen = true;
|
||||
iframeRef?.focus();
|
||||
} else {
|
||||
await document.exitFullscreen();
|
||||
isFullscreen = false;
|
||||
}
|
||||
};
|
||||
|
||||
const minimize = (e: KeyboardEvent) => {
|
||||
if (e.key === 'Escape') {
|
||||
if (isFullscreen) {
|
||||
isFullscreen = false;
|
||||
}
|
||||
iframeRef?.blur();
|
||||
}
|
||||
};
|
||||
|
||||
const handleFullscreenChange = () => {
|
||||
isFullscreen = !!document.fullscreenElement;
|
||||
if (!isFullscreen) {
|
||||
iframeRef?.blur();
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<svelte:window onkeydown={minimize} />
|
||||
<svelte:document onfullscreenchange={handleFullscreenChange} />
|
||||
|
||||
<main class="flex min-h-screen flex-col items-center px-4 py-8">
|
||||
<div class="relative mb-6 flex w-full max-w-4xl items-center justify-center">
|
||||
<Button.Root
|
||||
class="absolute left-0 flex items-center gap-2 rounded-md px-3 py-2 text-gray-400 transition-colors hover:bg-gray-800 hover:text-white"
|
||||
onclick={() => goto('/')}
|
||||
>
|
||||
<ArrowLeft class="h-4 w-4" />
|
||||
<span>Back</span>
|
||||
</Button.Root>
|
||||
|
||||
<h1 class="text-xl font-semibold text-white">Project {id}</h1>
|
||||
</div>
|
||||
|
||||
<div
|
||||
bind:this={containerRef}
|
||||
class="relative w-full max-w-4xl overflow-hidden rounded-md bg-black shadow-2xl ring-1 ring-gray-700/80"
|
||||
class:max-w-none={isFullscreen}
|
||||
class:h-screen={isFullscreen}
|
||||
class:rounded-none={isFullscreen}
|
||||
>
|
||||
<div class="aspect-video" class:aspect-auto={isFullscreen} class:h-full={isFullscreen}>
|
||||
<iframe
|
||||
bind:this={iframeRef}
|
||||
{src}
|
||||
title="Project: {id}"
|
||||
class="h-full w-full border-0"
|
||||
allow="fullscreen"
|
||||
></iframe>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="pointer-events-none absolute inset-x-0 bottom-0 flex items-center justify-between p-4"
|
||||
>
|
||||
<span class="text-sm text-white/50">Press ESC to exit</span>
|
||||
<Button.Root class="pointer-events-auto" onclick={toggleFullscreen}>
|
||||
{#if isFullscreen}
|
||||
<Minimize class="h-6 w-6" />
|
||||
{:else}
|
||||
<Maximize class="h-6 w-6" />
|
||||
{/if}
|
||||
</Button.Root>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
Reference in New Issue
Block a user