your personal website on atproto - mirror blento.app
at remove-extra-buttons 54 lines 1.5 kB view raw
1<script lang="ts"> 2 import { getStroke } from 'perfect-freehand'; 3 import type { ContentComponentProps } from '../types'; 4 5 let { item = $bindable(), isEditing }: ContentComponentProps = $props(); 6 7 type Stroke = { 8 points: [number, number, number][]; 9 size?: number; 10 }; 11 12 function getStrokeOptions(size: number) { 13 return { size, thinning: 0.5, smoothing: 0.5, streamline: 0.5 }; 14 } 15 16 function getSvgPathFromStroke(stroke: number[][]): string { 17 if (!stroke.length) return ''; 18 19 const d = stroke.reduce( 20 (acc, [x0, y0], i, arr) => { 21 const [x1, y1] = arr[(i + 1) % arr.length]; 22 acc.push(x0, y0, (x0 + x1) / 2, (y0 + y1) / 2); 23 return acc; 24 }, 25 ['M', ...stroke[0], 'Q'] as (string | number)[] 26 ); 27 28 d.push('Z'); 29 return d.join(' '); 30 } 31 32 // Parse strokes from JSON string stored in cardData 33 function parseStrokes(): Stroke[] { 34 const strokesJson = item.cardData.strokesJson as string | undefined; 35 if (!strokesJson) return []; 36 try { 37 return JSON.parse(strokesJson) as Stroke[]; 38 } catch { 39 return []; 40 } 41 } 42 43 let strokes = $derived(parseStrokes()); 44 let viewBox = $derived((item.cardData.viewBox as string) || '0 0 100 100'); 45</script> 46 47<svg class="absolute inset-0 h-full w-full" {viewBox} preserveAspectRatio="xMidYMid meet"> 48 {#each strokes as stroke, index (index)} 49 {@const pathData = getSvgPathFromStroke( 50 getStroke(stroke.points, getStrokeOptions(stroke.size ?? 3)) 51 )} 52 <path d={pathData} class="accent:fill-white fill-black dark:fill-white" /> 53 {/each} 54</svg>