Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 | /** * Blur Placeholder Utilities * * Generate placeholder images for use with Next.js Image component's * blurDataURL property. These provide visual feedback during image loading. */ // Pre-generated base64 placeholders for common colors export const placeholders = { gray: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mN88P/BfwYACwsB/q5kG+AAAAAASUVORK5CYII=', white: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg==', dark: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==', transparent: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=', } as const; /** * Generate a shimmer effect SVG placeholder * * Creates an animated gradient effect that simulates loading * * @param w - Width of the placeholder * @param h - Height of the placeholder * @returns Base64 encoded SVG data URL */ export function shimmerPlaceholder(w: number, h: number): string { const shimmer = ` <svg width="${w}" height="${h}" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> <defs> <linearGradient id="g"> <stop stop-color="#f6f7f8" offset="0%" /> <stop stop-color="#edeef1" offset="20%" /> <stop stop-color="#f6f7f8" offset="40%" /> <stop stop-color="#f6f7f8" offset="100%" /> </linearGradient> </defs> <rect width="${w}" height="${h}" fill="#f6f7f8" /> <rect id="r" width="${w}" height="${h}" fill="url(#g)" /> <animate xlink:href="#r" attributeName="x" from="-${w}" to="${w}" dur="1s" repeatCount="indefinite" /> </svg> `; return `data:image/svg+xml;base64,${toBase64(shimmer)}`; } /** * Generate a dark mode shimmer effect SVG placeholder * * @param w - Width of the placeholder * @param h - Height of the placeholder * @returns Base64 encoded SVG data URL */ export function shimmerPlaceholderDark(w: number, h: number): string { const shimmer = ` <svg width="${w}" height="${h}" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> <defs> <linearGradient id="g"> <stop stop-color="#374151" offset="0%" /> <stop stop-color="#4b5563" offset="20%" /> <stop stop-color="#374151" offset="40%" /> <stop stop-color="#374151" offset="100%" /> </linearGradient> </defs> <rect width="${w}" height="${h}" fill="#374151" /> <rect id="r" width="${w}" height="${h}" fill="url(#g)" /> <animate xlink:href="#r" attributeName="x" from="-${w}" to="${w}" dur="1s" repeatCount="indefinite" /> </svg> `; return `data:image/svg+xml;base64,${toBase64(shimmer)}`; } /** * Generate a color-based placeholder from a hex color * * @param hexColor - Hex color code (e.g., '#f0f0f0') * @returns Base64 encoded SVG data URL */ export function colorPlaceholder(hexColor: string): string { const svg = ` <svg width="1" height="1" xmlns="http://www.w3.org/2000/svg"> <rect width="1" height="1" fill="${hexColor}" /> </svg> `; return `data:image/svg+xml;base64,${toBase64(svg)}`; } /** * Generate a gradient placeholder * * @param fromColor - Start color (hex) * @param toColor - End color (hex) * @param direction - Gradient direction * @returns Base64 encoded SVG data URL */ export function gradientPlaceholder( fromColor: string, toColor: string, direction: 'horizontal' | 'vertical' | 'diagonal' = 'vertical' ): string { const coords = { horizontal: { x1: '0%', y1: '0%', x2: '100%', y2: '0%' }, vertical: { x1: '0%', y1: '0%', x2: '0%', y2: '100%' }, diagonal: { x1: '0%', y1: '0%', x2: '100%', y2: '100%' }, }; const { x1, y1, x2, y2 } = coords[direction]; const svg = ` <svg width="10" height="10" xmlns="http://www.w3.org/2000/svg"> <defs> <linearGradient id="grad" x1="${x1}" y1="${y1}" x2="${x2}" y2="${y2}"> <stop offset="0%" style="stop-color:${fromColor}" /> <stop offset="100%" style="stop-color:${toColor}" /> </linearGradient> </defs> <rect width="10" height="10" fill="url(#grad)" /> </svg> `; return `data:image/svg+xml;base64,${toBase64(svg)}`; } /** * Convert string to base64 * Works in both Node.js and browser environments */ function toBase64(str: string): string { if (typeof window === 'undefined') { // Node.js environment return Buffer.from(str).toString('base64'); } else { // Browser environment return btoa(str); } } /** * Generate placeholder data URL for common image sizes */ export const imagePlaceholders = { /** 1x1 pixel placeholder */ pixel: placeholders.gray, /** Product image placeholder (300x300) */ product: shimmerPlaceholder(300, 300), /** Thumbnail placeholder (80x80) */ thumbnail: shimmerPlaceholder(80, 80), /** Banner placeholder (1200x400) */ banner: shimmerPlaceholder(1200, 400), /** Avatar placeholder (40x40) */ avatar: shimmerPlaceholder(40, 40), } as const; |