You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

270 lines
7.4 KiB
Svelte

<script lang="ts">
import * as Form from '$lib/components/ui/form'
import * as Dialog from '$lib/components/ui/dialog'
import * as Select from '$lib/components/ui/select'
import { Input } from '$lib/components/ui/input'
import { Switch } from '$lib/components/ui/switch'
import { formSchema, type FormSchema } from '../schema'
import {
type SuperValidated,
type Infer,
superForm,
} from 'sveltekit-superforms'
import { zodClient } from 'sveltekit-superforms/adapters'
import { toast } from 'svelte-sonner'
import { Loader2, LoaderCircle, PlusCircle } from 'lucide-svelte'
import { buttonVariants } from '$lib/components/ui/button'
import { Checkbox } from '$lib/components/ui/checkbox'
import { ScrollArea } from '$lib/components/ui/scroll-area'
import type { Project } from '$lib/db/types'
let {
data,
projects,
dialogOpen = $bindable(),
}: {
data: SuperValidated<Infer<FormSchema>>
projects: Project[]
dialogOpen: boolean
} = $props()
let shortenerCategory = $state<string>('')
let selectedProjectName = $derived(
projects.find((project) => project.id == shortenerCategory)
?.name || 'None',
)
const form = superForm(data, {
validators: zodClient(formSchema),
invalidateAll: 'force',
resetForm: true,
onResult: ({ result }) => {
if (result.status === 200) {
dialogOpen = false
toast.success('Shortener added to project')
}
},
onError: ({ result }) => {
toast.error('Error adding shortener')
},
})
const { form: formData, enhance, submitting } = form
let inputTimer = $state<any>()
let previewData = $state<any>()
let isPreviewLoading = $state(false)
const getMetadata = async () => {
isPreviewLoading = true
clearTimeout(inputTimer)
const link =
$formData.link.startsWith('https://') ||
$formData.link.startsWith('http://')
? $formData.link
: 'https://' + $formData.link
inputTimer = setTimeout(async () => {
const response = await fetch(`/api/url/metadata?url=${link}`)
previewData = await response.json()
isPreviewLoading = false
console.log(previewData)
}, 1000)
}
</script>
<Dialog.Root bind:open={dialogOpen}>
<Dialog.Trigger
class={buttonVariants({ variant: 'default' }) + 'flex gap-2'}>
<PlusCircle />
Add Shortner
</Dialog.Trigger>
<Dialog.Content class="sm:max-w-[500px]">
<Dialog.Header>
<Dialog.Title>Add Shortener</Dialog.Title>
<Dialog.Description>
Create A New Shortener Here. Click Add To Save.
</Dialog.Description>
</Dialog.Header>
<ScrollArea class="max-h-[calc(100vh-200px)]">
<div class="grid grid-cols-4 items-center gap-4 pb-4">
<div class="font-bold">Preview</div>
<div class="col-span-4 flex flex-col justify-center border">
<div class="relative h-64 overflow-hidden">
{#if isPreviewLoading}
<div class="flex h-full items-center justify-center">
<Loader2 class="animate-spin" />
</div>
{:else if previewData}
<img
src={previewData.image}
alt=""
class="h-64 w-full object-cover" />
<div
class="bg-secondary absolute bottom-2 left-2 rounded-lg px-2">
{previewData.title}
</div>
{/if}
</div>
</div>
</div>
<form
method="POST"
use:enhance
class="flex flex-col gap-6"
action="?/create">
<Form.Field {form} name="link" class="flex flex-col gap-2">
<Form.Control>
{#snippet children({ props })}
<Form.Label>Link</Form.Label>
<Input
{...props}
bind:value={$formData.link}
placeholder="https://example.com"
oninput={getMetadata} />
{/snippet}
</Form.Control>
<Form.Description>Shortener link</Form.Description>
<Form.FieldErrors />
</Form.Field>
<Form.Field {form} name="project" class="flex flex-col gap-2">
<Form.Control>
{#snippet children({ props })}
<Form.Label>Project</Form.Label>
<Select.Root
bind:value={shortenerCategory}
type={'single'}
name={props.name}>
<Select.Trigger {...props} class="col-span-3">
{selectedProjectName}
</Select.Trigger>
<Select.Content>
<Select.Group>
<Select.Item value={''}>None</Select.Item>
<Select.Separator />
{#each projects as project}
<Select.Item value={project.id}>
{project.name}
</Select.Item>
{/each}
</Select.Group>
</Select.Content>
</Select.Root>
{/snippet}
</Form.Control>
<Form.Description>Shortener Project</Form.Description>
<Form.FieldErrors />
</Form.Field>
<Form.Field
{form}
name="custom_code_enable"
class="flex items-center gap-2 space-y-0">
<Form.Control>
{#snippet children({ props })}
<Switch
{...props}
bind:checked={$formData.custom_code_enable} />
<Form.Label>Custom Code</Form.Label>
{/snippet}
</Form.Control>
</Form.Field>
{#if $formData.custom_code_enable}
<Form.Field
{form}
name="custom_code"
class="flex flex-col gap-2">
<Form.Control>
{#snippet children({ props })}
<Input
{...props}
bind:value={$formData.custom_code}
placeholder="abcde" />
{/snippet}
</Form.Control>
<Form.Description>
Custom Code For The Shortener
</Form.Description>
<Form.FieldErrors />
</Form.Field>
{/if}
<Form.Field
{form}
name="ios"
class="flex items-center gap-2 space-y-0">
<Form.Control>
{#snippet children({ props })}
<Switch {...props} bind:checked={$formData.ios} />
<Form.Label>iOS Link</Form.Label>
{/snippet}
</Form.Control>
</Form.Field>
{#if $formData.ios}
<Form.Field
{form}
name="ios_link"
class="flex flex-col gap-2">
<Form.Control>
{#snippet children({ props })}
<Input
{...props}
bind:value={$formData.ios_link}
placeholder="https://example.com" />
{/snippet}
</Form.Control>
<Form.Description>
Shortener link for iOS
</Form.Description>
<Form.FieldErrors />
</Form.Field>
{/if}
<Form.Field
{form}
name="android"
class="flex items-center gap-2 space-y-0">
<Form.Control>
{#snippet children({ props })}
<Switch {...props} bind:checked={$formData.android} />
<Form.Label>Android Link</Form.Label>
{/snippet}
</Form.Control>
</Form.Field>
{#if $formData.android}
<Form.Field
{form}
name="android_link"
class="flex flex-col gap-2">
<Form.Control>
{#snippet children({ props })}
<Input
{...props}
bind:value={$formData.android_link}
placeholder="https://example.com" />
{/snippet}
</Form.Control>
<Form.Description>
Shortener link for Android
</Form.Description>
<Form.FieldErrors />
</Form.Field>
{/if}
<Form.Field
{form}
name="active"
class="flex items-center gap-2 space-y-0">
<Form.Control>
{#snippet children({ props })}
<Checkbox {...props} bind:checked={$formData.active} />
<Form.Label>Active</Form.Label>
{/snippet}
</Form.Control>
<Form.FieldErrors />
</Form.Field>
<Form.Button class="w-fit">
{#if $submitting}
<LoaderCircle class="animate-spin" />
{/if}
Add
</Form.Button>
</form>
</ScrollArea>
</Dialog.Content>
</Dialog.Root>