add public routes for viewing qr code + switched using qr-code-styling for qr code generation

main
TZGyn 1 year ago
parent 338839974e
commit ee81c52172
Signed by: TZGyn
GPG Key ID: 122EAF77AE81FD4A

Binary file not shown.

@ -18,4 +18,4 @@ primary_region = 'iad'
[[vm]]
size = 'shared-cpu-1x'
memory = '512mb'
memory = '256mb'

@ -20,7 +20,6 @@
"@sveltejs/kit": "^2.5.5",
"@sveltejs/vite-plugin-svelte": "^3.0.2",
"@types/pg": "^8.11.6",
"@types/qrcode": "^1.5.5",
"autoprefixer": "^10.4.14",
"bun-types": "^1.0.11",
"drizzle-kit": "^0.23.1",
@ -57,7 +56,7 @@
"oslo": "^1.2.0",
"pg": "^8.11.5",
"postgres": "^3.4.3",
"qrcode": "^1.5.3",
"qr-code-styling": "^1.6.0-rc.1",
"resend": "^3.4.0",
"svelte-sonner": "^0.3.10",
"sveltekit-superforms": "^2.12.2",

@ -6,11 +6,9 @@ export const handle: Handle = async ({ event, resolve }) => {
const pathname = event.url.pathname
const protected_api = ['/api/logout']
if (
pathname.startsWith('/dashboard') ||
protected_api.includes(pathname)
pathname.startsWith('/api')
) {
if (!sessionId) {
redirect(303, '/login')

@ -10,6 +10,8 @@
<Sonner
theme={$mode}
expand
richColors
class="toaster group"
toastOptions={{
classes: {

@ -1,9 +1,9 @@
<script lang="ts">
import QRCode from 'qrcode'
import { Button } from '$lib/components/ui/button'
import { toast } from 'svelte-sonner'
import * as DropdownMenu from '$lib/components/ui/dropdown-menu'
import { Badge } from '$lib/components/ui/badge'
import QRCodeStyling from 'qr-code-styling'
export let background = '#fff'
export let color = '#000'
@ -34,23 +34,28 @@
}
async function generateQrCode() {
try {
image = await QRCode.toDataURL(value, {
const qrcodestyling = new QRCodeStyling({
data: value,
width: 300,
height: 300,
margin: 10,
qrOptions: {
errorCorrectionLevel: 'L',
margin: 1,
scale: 20,
color: {
light: background,
dark: color,
typeNumber: 0,
},
backgroundOptions: {
color: background,
},
dotsOptions: {
color: color,
},
cornersSquareOptions: {
type: 'square',
},
})
} catch (e) {
image = await QRCode.toDataURL(value, {
errorCorrectionLevel: 'L',
margin: 1,
scale: 20,
})
}
const blob = await qrcodestyling.getRawData()
if (!blob) return
image = URL.createObjectURL(blob)
}
$: {
@ -60,25 +65,28 @@
}
</script>
<div class="flex flex-col gap-4 items-center h-full">
<div class="flex h-full flex-col items-center gap-4">
<Badge variant="secondary">
{value}
</Badge>
<img src={image} alt={value} width={300} height={300} />
<div class="flex gap-4 w-full">
<Button class="w-full" on:click={copyImageToClipboard}
>Copy Image</Button>
<div class="flex w-full gap-4">
<Button class="w-full" on:click={copyImageToClipboard}>
Copy Image
</Button>
<DropdownMenu.Root>
<DropdownMenu.Trigger asChild let:builder>
<Button builders={[builder]} class="w-full">QR Link</Button>
</DropdownMenu.Trigger>
<DropdownMenu.Content>
<DropdownMenu.Item href={`/url/${code}/qr`} target="_blank">
Standard
</DropdownMenu.Item>
<DropdownMenu.Item
href={`/api/shortener/${code}/qr`}
target="_blank">Standard</DropdownMenu.Item>
<DropdownMenu.Item
href={`/api/shortener/${code}/qr?color=true`}
target="_blank">With Color</DropdownMenu.Item>
href={`/url/${code}/qr?color=true`}
target="_blank">
With Color
</DropdownMenu.Item>
</DropdownMenu.Content>
</DropdownMenu.Root>
</div>

@ -1,9 +1,9 @@
<script lang="ts">
import QRCode from 'qrcode'
import { Button } from '$lib/components/ui/button'
import { toast } from 'svelte-sonner'
import * as DropdownMenu from '$lib/components/ui/dropdown-menu'
import { Badge } from '$lib/components/ui/badge'
import QRCodeStyling from 'qr-code-styling'
export let background = '#fff'
export let color = '#000'
@ -34,23 +34,28 @@
}
async function generateQrCode() {
try {
image = await QRCode.toDataURL(value, {
const qrcodestyling = new QRCodeStyling({
data: value,
width: 300,
height: 300,
margin: 10,
qrOptions: {
errorCorrectionLevel: 'L',
margin: 1,
scale: 20,
color: {
light: background,
dark: color,
typeNumber: 0,
},
backgroundOptions: {
color: background,
},
dotsOptions: {
color: color,
},
cornersSquareOptions: {
type: 'square',
},
})
} catch (e) {
image = await QRCode.toDataURL(value, {
errorCorrectionLevel: 'L',
margin: 1,
scale: 20,
})
}
const blob = await qrcodestyling.getRawData()
if (!blob) return
image = URL.createObjectURL(blob)
}
$: {
@ -60,25 +65,28 @@
}
</script>
<div class="flex flex-col gap-4 items-center h-full">
<div class="flex h-full flex-col items-center gap-4">
<Badge variant="secondary">
{value}
</Badge>
<img src={image} alt={value} width={300} height={300} />
<div class="flex gap-4 w-full">
<Button class="w-full" on:click={copyImageToClipboard}
>Copy Image</Button>
<div class="flex w-full gap-4">
<Button class="w-full" on:click={copyImageToClipboard}>
Copy Image
</Button>
<DropdownMenu.Root>
<DropdownMenu.Trigger asChild let:builder>
<Button builders={[builder]} class="w-full">QR Link</Button>
</DropdownMenu.Trigger>
<DropdownMenu.Content>
<DropdownMenu.Item href={`/url/${code}/qr`} target="_blank">
Standard
</DropdownMenu.Item>
<DropdownMenu.Item
href={`/api/shortener/${code}/qr`}
target="_blank">Standard</DropdownMenu.Item>
<DropdownMenu.Item
href={`/api/shortener/${code}/qr?color=true`}
target="_blank">With Color</DropdownMenu.Item>
href={`/url/${code}/qr?color=true`}
target="_blank">
With Color
</DropdownMenu.Item>
</DropdownMenu.Content>
</DropdownMenu.Root>
</div>

@ -1,6 +1,6 @@
<script>
import { onMount } from 'svelte'
import QRCode from 'qrcode'
import QRCodeStyling from 'qr-code-styling'
import { browser } from '$app/environment'
export let background = '#fff'
@ -15,15 +15,28 @@
}
try {
image = await QRCode.toDataURL(value, {
const qrcodestyling = new QRCodeStyling({
data: value,
width: 300,
height: 300,
margin: 10,
qrOptions: {
errorCorrectionLevel: 'L',
margin: 1,
scale: 20,
color: {
light: background,
dark: color,
typeNumber: 0,
},
backgroundOptions: {
color: background,
},
dotsOptions: {
color: color,
},
cornersSquareOptions: {
type: 'square',
},
})
const blob = await qrcodestyling.getRawData()
if (!blob) return
image = URL.createObjectURL(blob)
} catch (e) {
image = ''
}

@ -10,12 +10,14 @@
<p class="text-muted-foreground">Manage your account settings.</p>
</div>
<Separator class="my-4 lg:my-6" />
<div class="flex h-auto flex-col overflow-hidden lg:flex-row">
<div
class="flex h-auto w-full flex-col justify-center overflow-hidden lg:flex-row">
<aside
class="flex-grow border-b pb-4 lg:max-w-[200px] lg:border-none">
<SidebarNav />
</aside>
<div class="m-0 flex h-auto flex-grow overflow-hidden p-0">
<div
class="m-0 flex h-auto max-w-[600px] flex-grow overflow-hidden p-0">
<ScrollArea class="mt-0 w-full">
<div class="w-full max-w-xl py-6 lg:px-8 lg:py-0">
<slot />

@ -1,6 +1,6 @@
<script>
import { onMount } from 'svelte'
import QRCode from 'qrcode'
import QRCodeStyling from 'qr-code-styling'
import { browser } from '$app/environment'
export let background = '#fff'
@ -15,15 +15,28 @@
}
try {
image = await QRCode.toDataURL(value, {
const qrcodestyling = new QRCodeStyling({
data: value,
width: 300,
height: 300,
margin: 10,
qrOptions: {
errorCorrectionLevel: 'L',
margin: 1,
scale: 20,
color: {
light: background,
dark: color,
typeNumber: 0,
},
backgroundOptions: {
color: background,
},
dotsOptions: {
color: color,
},
cornersSquareOptions: {
type: 'square',
},
})
const blob = await qrcodestyling.getRawData()
if (!blob) return
image = URL.createObjectURL(blob)
} catch (e) {
image = ''
}

@ -1,6 +0,0 @@
import type { PageServerLoad } from './$types'
import { redirect } from '@sveltejs/kit'
export const load = (async () => {
return redirect(300, '/')
}) satisfies PageServerLoad

@ -0,0 +1,14 @@
<script>
import { goto } from '$app/navigation'
import Button from '$lib/components/ui/button/button.svelte'
</script>
<div class="fixed left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2">
<div class="flex flex-col items-center gap-12">
<div class="flex flex-col items-center gap-4">
<div class="text-4xl font-bold">404</div>
<div class="text-4xl font-bold">Invalid Url</div>
</div>
<Button on:click={() => goto('/')} class="w-fit">Return</Button>
</div>
</div>

@ -1,17 +1,16 @@
import { db } from '$lib/db'
import type { RequestHandler } from './$types'
import QRCode from 'qrcode'
import { redirect } from '@sveltejs/kit'
import { env } from '$env/dynamic/public'
import type { PageServerLoad } from './$types'
const shortenerUrl = env.PUBLIC_SHORTENER_URL
export const GET: RequestHandler = async (event) => {
const shortenerId = event.params.id
export const load = (async (event) => {
const { id } = event.params
const color = event.url.searchParams.get('color')
const shortener = await db.query.shortener.findFirst({
where: (shortener, { eq }) => eq(shortener.code, shortenerId),
where: (shortener, { eq }) => eq(shortener.code, id),
with: {
user: {
with: {
@ -23,23 +22,25 @@ export const GET: RequestHandler = async (event) => {
})
if (!shortener) {
redirect(303, '/')
redirect(301, `/dashboard/links`)
}
let colorSetting = {}
let colorSetting: {
color: { background: string | null; foreground: string | null }
} | null = null
if (color === 'true') {
if (shortener.project) {
colorSetting = {
color: {
light: shortener.project.qr_background,
dark: shortener.project.qr_foreground,
background: shortener.project.qr_background,
foreground: shortener.project.qr_foreground,
},
}
} else if (shortener.user.setting) {
colorSetting = {
color: {
light: shortener.user.setting.qr_background,
dark: shortener.user.setting.qr_foreground,
background: shortener.user.setting.qr_background,
foreground: shortener.user.setting.qr_foreground,
},
}
}
@ -50,17 +51,5 @@ export const GET: RequestHandler = async (event) => {
? shortener.project.custom_domain || shortenerUrl
: shortenerUrl
const image = await QRCode.toBuffer(url + '/' + shortenerId, {
type: 'png',
errorCorrectionLevel: 'L',
margin: 1,
scale: 20,
...colorSetting,
})
return new Response(image, {
headers: {
'Content-Type': 'image/png',
},
})
}
return { shortener, url, colorSetting, shortenerId: id }
}) satisfies PageServerLoad

@ -0,0 +1,79 @@
<script lang="ts">
import { Button } from '$lib/components/ui/button'
import { toast } from 'svelte-sonner'
import { Badge } from '$lib/components/ui/badge'
import QRCodeStyling from 'qr-code-styling'
import { onMount } from 'svelte'
import * as Card from '$lib/components/ui/card'
export let data
let image = ''
const copyImageToClipboard = async () => {
if (!image) return
const imageData = await fetch(image)
const imageBlob = await imageData.blob()
try {
navigator.clipboard.write([
new ClipboardItem({
'image/png': imageBlob,
}),
])
toast.success('Copied Image To Clipboard')
} catch (error) {
toast.error(
'Unable to copy item to clipboard. If you are using firefox, you can change the setting dom.events.asyncclipboard.clipboarditem in about:config to true',
)
}
}
async function generateQrCode() {
const qrcodestyling = new QRCodeStyling({
data: data.url + '/' + data.shortenerId,
width: 300,
height: 300,
margin: 10,
qrOptions: {
errorCorrectionLevel: 'L',
typeNumber: 0,
},
backgroundOptions: {
color: data.colorSetting?.color.background || '#fff',
},
dotsOptions: {
color: data.colorSetting?.color.foreground || '#000',
},
cornersSquareOptions: {
type: 'square',
},
})
const blob = await qrcodestyling.getRawData()
if (!blob) return
image = URL.createObjectURL(blob)
}
onMount(() => {
generateQrCode()
})
</script>
<Card.Root
class="fixed left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2">
<Card.Header class="flex-col items-center gap-4">
<Badge variant="secondary" class="w-fit">
{data.url + '/' + data.shortenerId}
</Badge>
<img
src={image}
alt={data.url + '/' + data.shortenerId}
width={300}
height={300} />
<Button class="w-full" on:click={copyImageToClipboard}>
Copy Image
</Button>
</Card.Header>
</Card.Root>

@ -3,7 +3,7 @@
import Button from '$lib/components/ui/button/button.svelte'
</script>
<div class="flex h-full w-full items-center justify-center">
<div class="fixed left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2">
<div class="flex flex-col items-center gap-12">
<div class="flex flex-col items-center gap-4">
<div class="text-4xl font-bold">404</div>
Loading…
Cancel
Save