your personal website on atproto - mirror
blento.app
1<script lang="ts">
2 import { getHexCSSVar } from '$lib/cards/helper';
3 import { onMount } from 'svelte';
4
5 let {
6 url,
7 icon,
8 iconColor,
9 class: className = ''
10 }: {
11 url: string;
12 icon?: string;
13 iconColor?: string;
14 class?: string;
15 } = $props();
16
17 let container: HTMLDivElement | undefined = $state();
18
19 // Convert SVG string to data URI for use as QR center image
20 function svgToDataUri(svg: string, color: string): string {
21 // Add fill color to SVG - insert fill attribute on the svg tag
22 let coloredSvg = svg;
23 if (!svg.includes('fill=')) {
24 // No fill attribute, add it to the svg tag
25 coloredSvg = svg.replace('<svg', `<svg fill="${color}"`);
26 } else {
27 // Replace existing fill attributes
28 coloredSvg = svg.replace(/fill="[^"]*"/g, `fill="${color}"`);
29 }
30 const encoded = encodeURIComponent(coloredSvg);
31 return `data:image/svg+xml,${encoded}`;
32 }
33
34 onMount(async () => {
35 if (!container) return;
36
37 // Use iconColor or accent color, ensure # prefix
38 const rawColor = iconColor || getHexCSSVar('--color-accent-600');
39 const dotColor = rawColor.startsWith('#') ? rawColor : `#${rawColor}`;
40
41 const module = await import('qr-code-styling');
42 const QRCodeStyling = module.default;
43
44 // Get container size for responsive QR
45 const rect = container.getBoundingClientRect();
46 const size = Math.min(rect.width, rect.height) || 280;
47
48 const options: ConstructorParameters<typeof QRCodeStyling>[0] = {
49 width: size,
50 height: size,
51 data: url,
52 dotsOptions: {
53 color: dotColor,
54 type: 'rounded'
55 },
56 backgroundOptions: {
57 color: '#FFF'
58 },
59 cornersSquareOptions: {
60 type: 'extra-rounded',
61 color: dotColor
62 },
63 cornersDotOptions: {
64 type: 'dot',
65 color: dotColor
66 },
67 margin: 10
68 };
69
70 // Add icon as center image if provided (as SVG string)
71 if (icon) {
72 options.image = svgToDataUri(icon, dotColor);
73 options.imageOptions = {
74 margin: 10,
75 imageSize: 0.5
76 };
77 }
78
79 const qrCode = new QRCodeStyling(options);
80 qrCode.append(container);
81 });
82</script>
83
84<div bind:this={container} class="flex items-center justify-center {className}"></div>