156 lines
8.3 KiB
Svelte
156 lines
8.3 KiB
Svelte
<script lang="ts">
|
|
import { ResizablePane, ResizablePaneGroup } from "@components/ui/resizable";
|
|
import { Separator } from "@components/ui/separator";
|
|
import { manager } from "./page.svelte";
|
|
import ResizableHandle from "@components/ui/resizable/resizable-handle.svelte";
|
|
import PagesList from "./PagesList.svelte";
|
|
import EditorWithTabs from "./EditorWithTabs.svelte";
|
|
import { Popover, PopoverContent, PopoverTrigger } from "@components/ui/popover";
|
|
import { Button } from "@components/ui/button";
|
|
import { Check, ChevronsUpDown, RefreshCw, FileImage, Plus } from "lucide-svelte";
|
|
import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from "@components/ui/command";
|
|
import { cn } from "@components/utils";
|
|
import { pageRepo } from "@components/repo/page";
|
|
|
|
let branchSelectOpen = $state(false);
|
|
let imageSelectOpen = $state(false);
|
|
|
|
let fileInput: HTMLInputElement | undefined = $state();
|
|
</script>
|
|
|
|
<div class="flex-grow flex flex-col">
|
|
<ResizablePaneGroup direction="horizontal" class="flex-grow">
|
|
<ResizablePane defaultSize={20}>
|
|
<div class="overflow-y-scroll">
|
|
<div class="flex p-2 gap-2">
|
|
<Popover bind:open={branchSelectOpen}>
|
|
<PopoverTrigger>
|
|
{#snippet child({ props })}
|
|
<Button variant="outline" class="justify-between flex-1" {...props} role="combobox">
|
|
{manager.branch}
|
|
<ChevronsUpDown class="ml-2 size-4 shrink-0 opacity-50" />
|
|
</Button>
|
|
{/snippet}
|
|
</PopoverTrigger>
|
|
<PopoverContent class="p-0">
|
|
<Command>
|
|
<CommandInput placeholder="Search Branches..." />
|
|
<CommandList>
|
|
<CommandEmpty>No Branches Found.</CommandEmpty>
|
|
<CommandGroup>
|
|
{#each manager.branches as branch}
|
|
<CommandItem
|
|
value={branch}
|
|
onSelect={() => {
|
|
if (manager.anyUnsavedChanges()) {
|
|
if (!confirm("You have unsaved changes. Are you sure you want to switch branches?")) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
manager.branch = branch;
|
|
manager.pages = [];
|
|
branchSelectOpen = false;
|
|
}}
|
|
>
|
|
<Check class={cn("mr-2 size-4", branch !== manager.branch && "text-transparent")} />
|
|
{branch}
|
|
</CommandItem>
|
|
{/each}
|
|
</CommandGroup>
|
|
</CommandList>
|
|
</Command>
|
|
</PopoverContent>
|
|
</Popover>
|
|
<Button size="icon" variant="outline" onclick={() => manager.reloadImages()}>
|
|
<RefreshCw />
|
|
</Button>
|
|
<Popover bind:open={imageSelectOpen}>
|
|
<PopoverTrigger>
|
|
{#snippet child({ props })}
|
|
<Button size="icon" variant="outline" {...props}>
|
|
<FileImage />
|
|
</Button>
|
|
{/snippet}
|
|
</PopoverTrigger>
|
|
<PopoverContent side="right" class="w-[1000px] h-screen overflow-y-auto">
|
|
{#await manager.imagesLoad}
|
|
<p>Loading images...</p>
|
|
{:then images}
|
|
<div class="flex flex-col gap-2">
|
|
<div class="p-2">
|
|
<input
|
|
type="file"
|
|
accept="image/*"
|
|
class="hidden"
|
|
bind:this={fileInput}
|
|
onchange={async (e) => {
|
|
const file = e.target?.files?.[0];
|
|
if (!file) return;
|
|
|
|
const reader = new FileReader();
|
|
reader.onload = async (event) => {
|
|
const base64 = event.target?.result?.toString().split(",")[1];
|
|
if (base64) {
|
|
await $pageRepo.createImage(file.name, base64, manager.branch);
|
|
manager.reloadImages();
|
|
}
|
|
};
|
|
reader.readAsDataURL(file);
|
|
}}
|
|
/>
|
|
<Button onclick={() => fileInput?.click()} class="w-full">
|
|
<Plus class="mr-2 size-4" />
|
|
Upload Image
|
|
</Button>
|
|
</div>
|
|
<div class="grid grid-cols-4 gap-2 p-2">
|
|
{#each images as image}
|
|
<button
|
|
onclick={() => {
|
|
const backs = (manager.selectedPage?.path?.match(/\//g)?.length || 1) - 1;
|
|
|
|
const path = [...Array(backs).fill(".."), image.path.replace("src/", "")].join("/");
|
|
|
|
navigator.clipboard.writeText(path);
|
|
imageSelectOpen = false;
|
|
}}
|
|
>
|
|
<img src={image.downloadUrl} alt={image.name} class="w-full h-auto object-cover" />
|
|
</button>
|
|
{/each}
|
|
</div>
|
|
</div>
|
|
{/await}
|
|
</PopoverContent>
|
|
</Popover>
|
|
<Button
|
|
size="icon"
|
|
onclick={async () => {
|
|
const branchName = prompt("Enter branch name:");
|
|
if (branchName) {
|
|
await $pageRepo.createBranch(branchName);
|
|
manager.reloadBranches();
|
|
}
|
|
}}
|
|
>
|
|
<Plus />
|
|
</Button>
|
|
</div>
|
|
<Separator />
|
|
{#await manager.pagesLoad}
|
|
<p>Loading pages...</p>
|
|
{:then pages}
|
|
{#each Object.values(pages.dirs) as page}
|
|
<PagesList {page} path={page.name + "/"} />
|
|
{/each}
|
|
{/await}
|
|
</div>
|
|
</ResizablePane>
|
|
<ResizableHandle />
|
|
<ResizablePane defaultSize={80}>
|
|
<EditorWithTabs />
|
|
</ResizablePane>
|
|
</ResizablePaneGroup>
|
|
</div>
|