fix(app): brighten SVG text fallbacks so they're visible over dark overlays
All 8 SVG generators (song, podcast, news, image, film, TV, book, place) had backgrounds at 9-10% lightness which appeared black under grid gradient overlays. Bumped to 18% with proportionally brighter text and icons. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
c88e837cc9
commit
6a1ce2e185
@@ -82,10 +82,10 @@ const MICROPHONE_PATH = 'M45.04,95.45v24.11c0,1.83-1.49,3.32-3.32,3.32c-1.83,0-3
|
||||
export function generatePodcastCoverFallback(title: string, _host?: string): string {
|
||||
const hue = [...title].reduce((acc, c) => acc + c.charCodeAt(0), 0) % 360
|
||||
const svg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200">
|
||||
<rect width="200" height="200" fill="hsl(${hue}, 25%, 10%)"/>
|
||||
<rect x="3" y="3" width="194" height="194" rx="12" fill="none" stroke="hsl(${hue}, 30%, 18%)" stroke-width="1"/>
|
||||
<text x="100" y="78" text-anchor="middle" fill="hsl(${hue}, 30%, 25%)" font-family="system-ui,sans-serif" font-size="10" font-weight="500" letter-spacing="3">PODCAST</text>
|
||||
<g fill="hsl(${hue}, 35%, 40%)" transform="translate(58 82) scale(1.0)">
|
||||
<rect width="200" height="200" fill="hsl(${hue}, 30%, 18%)"/>
|
||||
<rect x="3" y="3" width="194" height="194" rx="12" fill="none" stroke="hsl(${hue}, 35%, 28%)" stroke-width="1"/>
|
||||
<text x="100" y="78" text-anchor="middle" fill="hsl(${hue}, 35%, 40%)" font-family="system-ui,sans-serif" font-size="10" font-weight="500" letter-spacing="3">PODCAST</text>
|
||||
<g fill="hsl(${hue}, 40%, 55%)" transform="translate(58 82) scale(1.0)">
|
||||
<path d="${MICROPHONE_PATH}"/>
|
||||
</g>
|
||||
</svg>`
|
||||
@@ -95,13 +95,13 @@ export function generatePodcastCoverFallback(title: string, _host?: string): str
|
||||
export function generateSongCoverFallback(title: string, artist?: string): string {
|
||||
const hue = [...(title + (artist ?? ''))].reduce((acc, c) => acc + c.charCodeAt(0), 0) % 360
|
||||
const svg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200">
|
||||
<rect width="200" height="200" fill="hsl(${hue}, 25%, 10%)"/>
|
||||
<rect x="3" y="3" width="194" height="194" rx="12" fill="none" stroke="hsl(${hue}, 35%, 18%)" stroke-width="1"/>
|
||||
<text x="100" y="80" text-anchor="middle" fill="hsl(${hue}, 30%, 25%)" font-family="system-ui,sans-serif" font-size="10" font-weight="500" letter-spacing="3">MUSIC</text>
|
||||
<circle cx="100" cy="120" r="28" fill="none" stroke="hsl(${hue}, 40%, 30%)" stroke-width="1.5"/>
|
||||
<circle cx="100" cy="120" r="8" fill="hsl(${hue}, 40%, 30%)"/>
|
||||
<text x="100" y="170" text-anchor="middle" fill="hsl(${hue}, 40%, 55%)" font-family="system-ui,sans-serif" font-size="11" font-weight="600">${escapeXml(title.length > 18 ? title.slice(0, 16) + '…' : title)}</text>
|
||||
${artist ? `<text x="100" y="185" text-anchor="middle" fill="hsl(${hue}, 25%, 40%)" font-family="system-ui,sans-serif" font-size="9">${escapeXml(artist.length > 20 ? artist.slice(0, 18) + '…' : artist)}</text>` : ''}
|
||||
<rect width="200" height="200" fill="hsl(${hue}, 30%, 18%)"/>
|
||||
<rect x="3" y="3" width="194" height="194" rx="12" fill="none" stroke="hsl(${hue}, 40%, 28%)" stroke-width="1"/>
|
||||
<text x="100" y="80" text-anchor="middle" fill="hsl(${hue}, 35%, 40%)" font-family="system-ui,sans-serif" font-size="10" font-weight="500" letter-spacing="3">MUSIC</text>
|
||||
<circle cx="100" cy="120" r="28" fill="none" stroke="hsl(${hue}, 45%, 42%)" stroke-width="1.5"/>
|
||||
<circle cx="100" cy="120" r="8" fill="hsl(${hue}, 45%, 42%)"/>
|
||||
<text x="100" y="170" text-anchor="middle" fill="hsl(${hue}, 50%, 70%)" font-family="system-ui,sans-serif" font-size="11" font-weight="600">${escapeXml(title.length > 18 ? title.slice(0, 16) + '…' : title)}</text>
|
||||
${artist ? `<text x="100" y="185" text-anchor="middle" fill="hsl(${hue}, 30%, 55%)" font-family="system-ui,sans-serif" font-size="9">${escapeXml(artist.length > 20 ? artist.slice(0, 18) + '…' : artist)}</text>` : ''}
|
||||
</svg>`
|
||||
return `data:image/svg+xml,${encodeURIComponent(svg)}`
|
||||
}
|
||||
@@ -110,15 +110,15 @@ export function generateSongCoverFallback(title: string, artist?: string): strin
|
||||
export function generateNewsFallback(title: string, source?: string): string {
|
||||
const hue = [...(title + (source ?? ''))].reduce((acc, c) => acc + c.charCodeAt(0), 0) % 360
|
||||
const svg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200">
|
||||
<rect width="200" height="200" fill="hsl(${hue}, 18%, 10%)"/>
|
||||
<rect x="3" y="3" width="194" height="194" rx="12" fill="none" stroke="hsl(${hue}, 22%, 18%)" stroke-width="1"/>
|
||||
<text x="100" y="72" text-anchor="middle" fill="hsl(${hue}, 20%, 22%)" font-family="Georgia,'Times New Roman',serif" font-size="10" font-weight="400" letter-spacing="3">NEWS</text>
|
||||
<line x1="50" y1="82" x2="150" y2="82" stroke="hsl(${hue}, 22%, 17%)" stroke-width="0.8"/>
|
||||
<line x1="40" y1="100" x2="160" y2="100" stroke="hsl(${hue}, 18%, 16%)" stroke-width="3"/>
|
||||
<line x1="50" y1="112" x2="150" y2="112" stroke="hsl(${hue}, 18%, 14%)" stroke-width="2"/>
|
||||
<line x1="55" y1="122" x2="145" y2="122" stroke="hsl(${hue}, 18%, 13%)" stroke-width="1.5"/>
|
||||
<line x1="60" y1="132" x2="140" y2="132" stroke="hsl(${hue}, 18%, 13%)" stroke-width="1"/>
|
||||
${source ? `<text x="100" y="165" text-anchor="middle" fill="hsl(${hue}, 25%, 40%)" font-family="system-ui,sans-serif" font-size="9" font-weight="400">${escapeXml(source.length > 22 ? source.slice(0, 20) + '…' : source)}</text>` : ''}
|
||||
<rect width="200" height="200" fill="hsl(${hue}, 22%, 18%)"/>
|
||||
<rect x="3" y="3" width="194" height="194" rx="12" fill="none" stroke="hsl(${hue}, 28%, 28%)" stroke-width="1"/>
|
||||
<text x="100" y="72" text-anchor="middle" fill="hsl(${hue}, 25%, 40%)" font-family="Georgia,'Times New Roman',serif" font-size="10" font-weight="400" letter-spacing="3">NEWS</text>
|
||||
<line x1="50" y1="82" x2="150" y2="82" stroke="hsl(${hue}, 28%, 28%)" stroke-width="0.8"/>
|
||||
<line x1="40" y1="100" x2="160" y2="100" stroke="hsl(${hue}, 22%, 30%)" stroke-width="3"/>
|
||||
<line x1="50" y1="112" x2="150" y2="112" stroke="hsl(${hue}, 22%, 27%)" stroke-width="2"/>
|
||||
<line x1="55" y1="122" x2="145" y2="122" stroke="hsl(${hue}, 22%, 25%)" stroke-width="1.5"/>
|
||||
<line x1="60" y1="132" x2="140" y2="132" stroke="hsl(${hue}, 22%, 24%)" stroke-width="1"/>
|
||||
${source ? `<text x="100" y="165" text-anchor="middle" fill="hsl(${hue}, 30%, 55%)" font-family="system-ui,sans-serif" font-size="9" font-weight="400">${escapeXml(source.length > 22 ? source.slice(0, 20) + '…' : source)}</text>` : ''}
|
||||
</svg>`
|
||||
return `data:image/svg+xml,${encodeURIComponent(svg)}`
|
||||
}
|
||||
@@ -127,13 +127,13 @@ export function generateNewsFallback(title: string, source?: string): string {
|
||||
export function generateImageFallback(title: string): string {
|
||||
const hue = [...title].reduce((acc, c) => acc + c.charCodeAt(0), 0) % 360
|
||||
const svg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200">
|
||||
<rect width="200" height="200" fill="hsl(${hue}, 15%, 10%)"/>
|
||||
<rect x="3" y="3" width="194" height="194" rx="12" fill="none" stroke="hsl(${hue}, 20%, 18%)" stroke-width="1"/>
|
||||
<text x="100" y="72" text-anchor="middle" fill="hsl(${hue}, 18%, 22%)" font-family="system-ui,sans-serif" font-size="10" font-weight="500" letter-spacing="3">IMAGE</text>
|
||||
<rect x="60" y="85" width="80" height="60" rx="4" fill="none" stroke="hsl(${hue}, 25%, 25%)" stroke-width="1.5"/>
|
||||
<circle cx="80" cy="102" r="6" fill="hsl(${hue}, 30%, 30%)"/>
|
||||
<path d="M60 135 L85 115 L105 128 L120 118 L140 135 Z" fill="hsl(${hue}, 25%, 20%)"/>
|
||||
<text x="100" y="170" text-anchor="middle" fill="hsl(${hue}, 30%, 45%)" font-family="system-ui,sans-serif" font-size="10" font-weight="500">${escapeXml(title.length > 20 ? title.slice(0, 18) + '…' : title)}</text>
|
||||
<rect width="200" height="200" fill="hsl(${hue}, 20%, 18%)"/>
|
||||
<rect x="3" y="3" width="194" height="194" rx="12" fill="none" stroke="hsl(${hue}, 25%, 28%)" stroke-width="1"/>
|
||||
<text x="100" y="72" text-anchor="middle" fill="hsl(${hue}, 22%, 38%)" font-family="system-ui,sans-serif" font-size="10" font-weight="500" letter-spacing="3">IMAGE</text>
|
||||
<rect x="60" y="85" width="80" height="60" rx="4" fill="none" stroke="hsl(${hue}, 30%, 38%)" stroke-width="1.5"/>
|
||||
<circle cx="80" cy="102" r="6" fill="hsl(${hue}, 35%, 40%)"/>
|
||||
<path d="M60 135 L85 115 L105 128 L120 118 L140 135 Z" fill="hsl(${hue}, 30%, 30%)"/>
|
||||
<text x="100" y="170" text-anchor="middle" fill="hsl(${hue}, 35%, 58%)" font-family="system-ui,sans-serif" font-size="10" font-weight="500">${escapeXml(title.length > 20 ? title.slice(0, 18) + '…' : title)}</text>
|
||||
</svg>`
|
||||
return `data:image/svg+xml,${encodeURIComponent(svg)}`
|
||||
}
|
||||
@@ -142,14 +142,14 @@ export function generateImageFallback(title: string): string {
|
||||
export function generatePosterFallback(title: string, year?: number): string {
|
||||
const hue = [...title].reduce((acc, c) => acc + c.charCodeAt(0), 0) % 360
|
||||
const svg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 342 513">
|
||||
<rect width="342" height="513" fill="hsl(${hue}, 20%, 9%)"/>
|
||||
<rect x="3" y="3" width="336" height="507" rx="6" fill="none" stroke="hsl(${hue}, 25%, 16%)" stroke-width="1"/>
|
||||
<text x="171" y="210" text-anchor="middle" fill="hsl(${hue}, 20%, 22%)" font-family="'Helvetica Neue',Helvetica,Arial,sans-serif" font-size="13" font-weight="400" letter-spacing="5">FILM</text>
|
||||
<line x1="121" y1="225" x2="221" y2="225" stroke="hsl(${hue}, 25%, 18%)" stroke-width="1"/>
|
||||
<text x="171" y="265" text-anchor="middle" fill="hsl(${hue}, 40%, 55%)" font-family="'Helvetica Neue',Helvetica,Arial,sans-serif" font-size="18" font-weight="700">
|
||||
<rect width="342" height="513" fill="hsl(${hue}, 25%, 18%)"/>
|
||||
<rect x="3" y="3" width="336" height="507" rx="6" fill="none" stroke="hsl(${hue}, 30%, 28%)" stroke-width="1"/>
|
||||
<text x="171" y="210" text-anchor="middle" fill="hsl(${hue}, 25%, 38%)" font-family="'Helvetica Neue',Helvetica,Arial,sans-serif" font-size="13" font-weight="400" letter-spacing="5">FILM</text>
|
||||
<line x1="121" y1="225" x2="221" y2="225" stroke="hsl(${hue}, 30%, 30%)" stroke-width="1"/>
|
||||
<text x="171" y="265" text-anchor="middle" fill="hsl(${hue}, 45%, 68%)" font-family="'Helvetica Neue',Helvetica,Arial,sans-serif" font-size="18" font-weight="700">
|
||||
${escapeXml(title.length > 20 ? title.slice(0, 18) + '…' : title)}
|
||||
</text>
|
||||
${year ? `<text x="171" y="295" text-anchor="middle" fill="hsl(${hue}, 25%, 38%)" font-family="'Helvetica Neue',Helvetica,Arial,sans-serif" font-size="14" font-weight="300">${year}</text>` : ''}
|
||||
${year ? `<text x="171" y="295" text-anchor="middle" fill="hsl(${hue}, 30%, 50%)" font-family="'Helvetica Neue',Helvetica,Arial,sans-serif" font-size="14" font-weight="300">${year}</text>` : ''}
|
||||
</svg>`
|
||||
return `data:image/svg+xml,${encodeURIComponent(svg)}`
|
||||
}
|
||||
@@ -158,14 +158,14 @@ export function generatePosterFallback(title: string, year?: number): string {
|
||||
export function generateTVSeriesFallback(title: string, year?: number): string {
|
||||
const hue = [...title].reduce((acc, c) => acc + c.charCodeAt(0), 0) % 360
|
||||
const svg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 342 513">
|
||||
<rect width="342" height="513" fill="hsl(${hue}, 18%, 9%)"/>
|
||||
<rect x="3" y="3" width="336" height="507" rx="6" fill="none" stroke="hsl(${hue}, 22%, 16%)" stroke-width="1"/>
|
||||
<text x="171" y="210" text-anchor="middle" fill="hsl(${hue}, 18%, 22%)" font-family="'SF Pro Display',system-ui,sans-serif" font-size="13" font-weight="400" letter-spacing="5">SERIES</text>
|
||||
<line x1="111" y1="225" x2="231" y2="225" stroke="hsl(${hue}, 22%, 18%)" stroke-width="1"/>
|
||||
<text x="171" y="265" text-anchor="middle" fill="hsl(${hue}, 35%, 55%)" font-family="'SF Pro Display',system-ui,sans-serif" font-size="18" font-weight="700">
|
||||
<rect width="342" height="513" fill="hsl(${hue}, 22%, 18%)"/>
|
||||
<rect x="3" y="3" width="336" height="507" rx="6" fill="none" stroke="hsl(${hue}, 28%, 28%)" stroke-width="1"/>
|
||||
<text x="171" y="210" text-anchor="middle" fill="hsl(${hue}, 22%, 38%)" font-family="'SF Pro Display',system-ui,sans-serif" font-size="13" font-weight="400" letter-spacing="5">SERIES</text>
|
||||
<line x1="111" y1="225" x2="231" y2="225" stroke="hsl(${hue}, 28%, 30%)" stroke-width="1"/>
|
||||
<text x="171" y="265" text-anchor="middle" fill="hsl(${hue}, 40%, 68%)" font-family="'SF Pro Display',system-ui,sans-serif" font-size="18" font-weight="700">
|
||||
${escapeXml(title.length > 20 ? title.slice(0, 18) + '…' : title)}
|
||||
</text>
|
||||
${year ? `<text x="171" y="295" text-anchor="middle" fill="hsl(${hue}, 22%, 38%)" font-family="'SF Pro Display',system-ui,sans-serif" font-size="14" font-weight="300">${year}</text>` : ''}
|
||||
${year ? `<text x="171" y="295" text-anchor="middle" fill="hsl(${hue}, 28%, 50%)" font-family="'SF Pro Display',system-ui,sans-serif" font-size="14" font-weight="300">${year}</text>` : ''}
|
||||
</svg>`
|
||||
return `data:image/svg+xml,${encodeURIComponent(svg)}`
|
||||
}
|
||||
@@ -322,15 +322,15 @@ loadBookCache()
|
||||
export function generateBookCoverFallback(title: string, author?: string): string {
|
||||
const hue = [...(title + (author ?? ''))].reduce((acc, c) => acc + c.charCodeAt(0), 0) % 360
|
||||
const svg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 280 420">
|
||||
<rect width="280" height="420" fill="hsl(${hue}, 20%, 9%)"/>
|
||||
<rect x="3" y="3" width="274" height="414" rx="3" fill="none" stroke="hsl(${hue}, 25%, 16%)" stroke-width="1"/>
|
||||
<line x1="22" y1="3" x2="22" y2="417" stroke="hsl(${hue}, 25%, 15%)" stroke-width="1.5"/>
|
||||
<text x="155" y="170" text-anchor="middle" fill="hsl(${hue}, 18%, 22%)" font-family="Georgia,'Times New Roman',serif" font-size="11" font-weight="400" letter-spacing="4">BOOK</text>
|
||||
<line x1="95" y1="182" x2="215" y2="182" stroke="hsl(${hue}, 22%, 17%)" stroke-width="0.8"/>
|
||||
<text x="155" y="215" text-anchor="middle" fill="hsl(${hue}, 35%, 55%)" font-family="Georgia,'Times New Roman',serif" font-size="17" font-weight="700" font-style="italic">
|
||||
<rect width="280" height="420" fill="hsl(${hue}, 20%, 18%)"/>
|
||||
<rect x="3" y="3" width="274" height="414" rx="3" fill="none" stroke="hsl(${hue}, 25%, 28%)" stroke-width="1"/>
|
||||
<line x1="22" y1="3" x2="22" y2="417" stroke="hsl(${hue}, 25%, 26%)" stroke-width="1.5"/>
|
||||
<text x="155" y="170" text-anchor="middle" fill="hsl(${hue}, 18%, 38%)" font-family="Georgia,'Times New Roman',serif" font-size="11" font-weight="400" letter-spacing="4">BOOK</text>
|
||||
<line x1="95" y1="182" x2="215" y2="182" stroke="hsl(${hue}, 22%, 30%)" stroke-width="0.8"/>
|
||||
<text x="155" y="215" text-anchor="middle" fill="hsl(${hue}, 35%, 68%)" font-family="Georgia,'Times New Roman',serif" font-size="17" font-weight="700" font-style="italic">
|
||||
${escapeXml(title.length > 22 ? title.slice(0, 20) + '…' : title)}
|
||||
</text>
|
||||
${author ? `<text x="155" y="248" text-anchor="middle" fill="hsl(${hue}, 22%, 40%)" font-family="Georgia,'Times New Roman',serif" font-size="11" font-weight="400">${escapeXml(author.length > 26 ? author.slice(0, 24) + '…' : author)}</text>` : ''}
|
||||
${author ? `<text x="155" y="248" text-anchor="middle" fill="hsl(${hue}, 22%, 55%)" font-family="Georgia,'Times New Roman',serif" font-size="11" font-weight="400">${escapeXml(author.length > 26 ? author.slice(0, 24) + '…' : author)}</text>` : ''}
|
||||
</svg>`
|
||||
return `data:image/svg+xml,${encodeURIComponent(svg)}`
|
||||
}
|
||||
@@ -366,14 +366,14 @@ export async function fetchBookCover(
|
||||
export function generatePlaceFallback(name: string, cuisine?: string): string {
|
||||
const hue = [...(name + (cuisine ?? ''))].reduce((acc, c) => acc + c.charCodeAt(0), 0) % 360
|
||||
const svg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200">
|
||||
<rect width="200" height="200" fill="hsl(${hue}, 20%, 10%)"/>
|
||||
<rect x="3" y="3" width="194" height="194" rx="12" fill="none" stroke="hsl(${hue}, 25%, 16%)" stroke-width="1"/>
|
||||
<text x="100" y="72" text-anchor="middle" fill="hsl(${hue}, 20%, 22%)" font-family="system-ui,sans-serif" font-size="9" font-weight="500" letter-spacing="3">PLACE</text>
|
||||
<g transform="translate(100 120) scale(1.8)" fill="none" stroke="hsl(${hue}, 35%, 40%)" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<rect width="200" height="200" fill="hsl(${hue}, 20%, 18%)"/>
|
||||
<rect x="3" y="3" width="194" height="194" rx="12" fill="none" stroke="hsl(${hue}, 25%, 28%)" stroke-width="1"/>
|
||||
<text x="100" y="72" text-anchor="middle" fill="hsl(${hue}, 20%, 38%)" font-family="system-ui,sans-serif" font-size="9" font-weight="500" letter-spacing="3">PLACE</text>
|
||||
<g transform="translate(100 120) scale(1.8)" fill="none" stroke="hsl(${hue}, 35%, 55%)" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M0-14C-7.7-14-14-7.7-14 0c0 10.5 14 22 14 22s14-11.5 14-22c0-7.7-6.3-14-14-14z"/>
|
||||
<circle cx="0" cy="0" r="5"/>
|
||||
</g>
|
||||
${cuisine ? `<text x="100" y="170" text-anchor="middle" fill="hsl(${hue}, 25%, 40%)" font-family="system-ui,sans-serif" font-size="9" font-weight="400">${escapeXml(cuisine.length > 22 ? cuisine.slice(0, 20) + '…' : cuisine)}</text>` : ''}
|
||||
${cuisine ? `<text x="100" y="170" text-anchor="middle" fill="hsl(${hue}, 25%, 55%)" font-family="system-ui,sans-serif" font-size="9" font-weight="400">${escapeXml(cuisine.length > 22 ? cuisine.slice(0, 20) + '…' : cuisine)}</text>` : ''}
|
||||
</svg>`
|
||||
return `data:image/svg+xml,${encodeURIComponent(svg)}`
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user