mirror of https://github.com/TZGyn/shortener
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.
228 lines
6.1 KiB
Svelte
228 lines
6.1 KiB
Svelte
<script lang="ts">
|
|
import { Separator } from '$lib/components/ui/separator'
|
|
import * as Form from '$lib/components/ui/form'
|
|
import { Input } from '$lib/components/ui/input'
|
|
import { formSchema } from './schema'
|
|
import { superForm } from 'sveltekit-superforms'
|
|
import { zodClient } from 'sveltekit-superforms/adapters'
|
|
import { toast } from 'svelte-sonner'
|
|
import DemoQr from './(components)/DemoQR.svelte'
|
|
import { LoaderCircle } from 'lucide-svelte'
|
|
import { Button } from '$lib/components/ui/button'
|
|
import { cn } from '$lib/utils'
|
|
|
|
let { data } = $props()
|
|
|
|
let qrImageInput: HTMLInputElement
|
|
|
|
const form = superForm(data.form, {
|
|
validators: zodClient(formSchema),
|
|
invalidateAll: 'force',
|
|
resetForm: true,
|
|
onResult: ({ result }) => {
|
|
if (result.status === 200) {
|
|
toast.success('QR settings updated')
|
|
}
|
|
if (result.status === 400) {
|
|
toast.error('Error updating QR settings')
|
|
}
|
|
},
|
|
})
|
|
|
|
const { form: formData, enhance, submitting } = form
|
|
</script>
|
|
|
|
<div class="space-y-6">
|
|
<div>
|
|
<h3 class="text-lg font-medium">QR</h3>
|
|
<p class="text-muted-foreground text-sm">
|
|
Update your QR settings.
|
|
</p>
|
|
</div>
|
|
<Separator />
|
|
|
|
<div class="flex justify-center">
|
|
<DemoQr
|
|
background={$formData.qr_background}
|
|
color={$formData.qr_foreground}
|
|
cornerSquareStyle={$formData.qrCornerSquareStyle}
|
|
dotStyle={$formData.qrDotStyle}
|
|
existingQrImage={data.qrImageBase64}
|
|
qrImage={$formData.qrImage} />
|
|
</div>
|
|
|
|
<form
|
|
method="POST"
|
|
use:enhance
|
|
enctype="multipart/form-data"
|
|
class="flex flex-col gap-6">
|
|
<Form.Field {form} name="qr_background">
|
|
<Form.Control let:attrs>
|
|
<Form.Label>Background Color</Form.Label>
|
|
<Input {...attrs} bind:value={$formData.qr_background} />
|
|
</Form.Control>
|
|
<Form.Description>QR Code background color</Form.Description>
|
|
<Form.FieldErrors />
|
|
</Form.Field>
|
|
<Form.Field {form} name="qr_foreground">
|
|
<Form.Control let:attrs>
|
|
<Form.Label>Foreground Color</Form.Label>
|
|
<Input {...attrs} bind:value={$formData.qr_foreground} />
|
|
</Form.Control>
|
|
<Form.Description>QR Code foreground color</Form.Description>
|
|
<Form.FieldErrors />
|
|
</Form.Field>
|
|
<Form.Field {form} name="qrImage">
|
|
<Form.Control let:attrs>
|
|
<Form.Label>
|
|
Image <span class="text-brand">(Pro)</span>
|
|
</Form.Label>
|
|
<div>
|
|
{#if !$formData.qrImage && !data.qrImageBase64}
|
|
<button
|
|
onclick={(e) => {
|
|
e.preventDefault()
|
|
qrImageInput.click()
|
|
}}>
|
|
<div
|
|
class="flex h-16 w-16 items-center justify-center rounded-lg border-4 border-dashed">
|
|
</div>
|
|
</button>
|
|
{:else}
|
|
<button
|
|
onclick={(e) => {
|
|
e.preventDefault()
|
|
qrImageInput.click()
|
|
}}>
|
|
<img
|
|
src={$formData.qrImage
|
|
? URL.createObjectURL($formData.qrImage)
|
|
: data.qrImageBase64}
|
|
alt={'image'}
|
|
width={64}
|
|
height={64} />
|
|
</button>
|
|
{/if}
|
|
</div>
|
|
<Form.Description>Click to edit</Form.Description>
|
|
<input
|
|
{...attrs}
|
|
hidden
|
|
bind:this={qrImageInput}
|
|
accept="image/png, image/jpeg"
|
|
type="file"
|
|
disabled={data.user.plan === 'free'}
|
|
oninput={(e) => {
|
|
const file = e.currentTarget.files?.item(0)
|
|
if (!file) return
|
|
|
|
if (file.size > 2097152) {
|
|
toast.error('Too Big! Max file size is 2MB')
|
|
return
|
|
}
|
|
$formData.qrImage = file
|
|
}} />
|
|
</Form.Control>
|
|
<Form.FieldErrors />
|
|
</Form.Field>
|
|
<Form.Field {form} name="qrCornerSquareStyle">
|
|
<Form.Control let:attrs>
|
|
<Form.Label>
|
|
Corner Square Style <span class="text-brand">(Pro)</span>
|
|
</Form.Label>
|
|
<Input
|
|
{...attrs}
|
|
class="hidden"
|
|
hidden
|
|
aria-hidden
|
|
bind:value={$formData.qrCornerSquareStyle} />
|
|
</Form.Control>
|
|
<div class="flex gap-4">
|
|
<Button
|
|
disabled={data.user.plan === 'free'}
|
|
onclick={() => ($formData.qrCornerSquareStyle = 'square')}
|
|
class={cn(
|
|
'flex flex-col gap-3 border p-12',
|
|
$formData.qrCornerSquareStyle === 'square'
|
|
? 'bg-primary-foreground'
|
|
: 'bg-transparent',
|
|
)}>
|
|
<div class="border-brand border-4 p-4"></div>
|
|
Square
|
|
</Button>
|
|
<Button
|
|
disabled={data.user.plan === 'free'}
|
|
onclick={() => ($formData.qrCornerSquareStyle = 'dot')}
|
|
class={cn(
|
|
'flex flex-col gap-3 border p-12',
|
|
$formData.qrCornerSquareStyle === 'dot'
|
|
? 'bg-primary-foreground'
|
|
: 'bg-transparent',
|
|
)}>
|
|
<div class="border-brand rounded-full border-4 p-4"></div>
|
|
Dot
|
|
</Button>
|
|
<Button
|
|
disabled={data.user.plan === 'free'}
|
|
onclick={() =>
|
|
($formData.qrCornerSquareStyle = 'extra-rounded')}
|
|
class={cn(
|
|
'flex flex-col gap-3 border p-12',
|
|
$formData.qrCornerSquareStyle === 'extra-rounded'
|
|
? 'bg-primary-foreground'
|
|
: 'bg-transparent',
|
|
)}>
|
|
<div class="border-brand rounded-lg border-4 p-4"></div>
|
|
Rounded
|
|
</Button>
|
|
</div>
|
|
</Form.Field>
|
|
<Form.Field {form} name="qrDotStyle">
|
|
<Form.Control let:attrs>
|
|
<Form.Label>
|
|
Dot Style <span class="text-brand">(Pro)</span>
|
|
</Form.Label>
|
|
<Input
|
|
{...attrs}
|
|
class="hidden"
|
|
hidden
|
|
aria-hidden
|
|
bind:value={$formData.qrDotStyle} />
|
|
</Form.Control>
|
|
<div class="flex gap-4">
|
|
<Button
|
|
disabled={data.user.plan === 'free'}
|
|
onclick={() => ($formData.qrDotStyle = 'square')}
|
|
class={cn(
|
|
'flex flex-col gap-3 border p-12',
|
|
$formData.qrDotStyle === 'square'
|
|
? 'bg-primary-foreground'
|
|
: 'bg-transparent',
|
|
)}>
|
|
<div class="border-brand border-4"></div>
|
|
Square
|
|
</Button>
|
|
<Button
|
|
disabled={data.user.plan === 'free'}
|
|
onclick={() => ($formData.qrDotStyle = 'rounded')}
|
|
class={cn(
|
|
'flex flex-col gap-3 border p-12',
|
|
$formData.qrDotStyle === 'rounded'
|
|
? 'bg-primary-foreground'
|
|
: 'bg-transparent',
|
|
)}>
|
|
<div class="border-brand w-4 rounded-lg border-4"></div>
|
|
Rounded
|
|
</Button>
|
|
</div>
|
|
</Form.Field>
|
|
|
|
<Form.Button class="w-fit self-end">
|
|
{#if $submitting}
|
|
<LoaderCircle class="animate-spin" />
|
|
{/if}
|
|
Save
|
|
</Form.Button>
|
|
</form>
|
|
</div>
|