|
1 | 1 | <script lang="ts"> |
2 | | - /** Controls the overall opacity of the pattern. */ |
3 | | - export let density: number = 1; |
| 2 | + import type { Component } from "svelte"; |
| 3 | + import type { SVGAttributes } from "svelte/elements"; |
| 4 | +
|
| 5 | + // --- PROPS --- |
| 6 | + type SvgComponent = Component<SVGAttributes<SVGSVGElement>>; |
| 7 | +
|
| 8 | + // --- PROPS --- |
| 9 | + /** An array of imported Svelte SVG components for the pattern. */ |
| 10 | + export let icons: SvgComponent[] = []; |
| 11 | +
|
| 12 | + /** The size of each icon in the pattern. */ |
| 13 | + export let scale: number = 50; |
| 14 | +
|
| 15 | + /** The gap between pattern tiles. A larger value means lower density. */ |
| 16 | + export let spacing: number = 100; |
| 17 | +
|
| 18 | + /** The Tailwind CSS class for the color of the icons. */ |
| 19 | + export let color: string = "red"; |
| 20 | +
|
| 21 | + /** The rotation angle for each icon in degrees. */ |
| 22 | + export let rotation: number = -15; |
| 23 | +
|
| 24 | + // --- CALCULATIONS --- |
| 25 | + // The full size of one pattern tile. |
| 26 | + $: patternSize = scale + spacing; |
| 27 | + // How many icons to fit horizontally in one tile before repeating. |
| 28 | + $: iconsPerRow = 3; |
4 | 29 | </script> |
5 | 30 |
|
6 | | -<div |
7 | | - class="absolute inset-0 z-0 text-ctp-surface1 dark:text-ctp-surface2" |
8 | | - style="opacity: {density};" |
9 | | - aria-hidden="true" |
10 | | -> |
11 | | - <svg width="100%" height="100%"> |
12 | | - <slot name="defs"></slot> |
13 | | - <!-- might need class="fill-current" --> |
14 | | - <rect width="100%" height="100%" fill="url(#controller-pattern)" /> |
15 | | - </svg> |
16 | | -</div> |
| 31 | +{#if icons.length > 0} |
| 32 | + <div class="absolute inset-0 z-0" aria-hidden="true"> |
| 33 | + <svg width="100%" height="100%"> |
| 34 | + <defs> |
| 35 | + {#each icons as icon, i} |
| 36 | + <symbol id="pattern-icon-{i}"> |
| 37 | + <svelte:component this={icon} /> |
| 38 | + </symbol> |
| 39 | + {/each} |
| 40 | + |
| 41 | + <pattern |
| 42 | + id="master-pattern" |
| 43 | + patternUnits="userSpaceOnUse" |
| 44 | + width={patternSize * iconsPerRow} |
| 45 | + height={patternSize} |
| 46 | + > |
| 47 | + {#each icons as _icon, i} |
| 48 | + <use |
| 49 | + href="#pattern-icon-{i}" |
| 50 | + x={(i % iconsPerRow) * patternSize + |
| 51 | + patternSize / 2} |
| 52 | + y={Math.floor(i / iconsPerRow) * patternSize + |
| 53 | + patternSize / 2} |
| 54 | + width={scale} |
| 55 | + height={scale} |
| 56 | + transform="rotate({rotation}, {(i % iconsPerRow) * |
| 57 | + patternSize + |
| 58 | + patternSize / 2 + |
| 59 | + scale / 2}, {Math.floor(i / iconsPerRow) * |
| 60 | + patternSize + |
| 61 | + patternSize / 2 + |
| 62 | + scale / 2})" |
| 63 | + /> |
| 64 | + {/each} |
| 65 | + </pattern> |
| 66 | + </defs> |
| 67 | + |
| 68 | + <rect |
| 69 | + width="100%" |
| 70 | + height="100%" |
| 71 | + fill="url(#master-pattern)" |
| 72 | + {color} |
| 73 | + /> |
| 74 | + </svg> |
| 75 | + </div> |
| 76 | +{/if} |
17 | 77 |
|
18 | 78 | <div class="relative z-10"> |
19 | 79 | <slot></slot> |
|
0 commit comments