my blog https://overreacted.io

Replace SVG white backgrounds with theme-aware colors (#866)

* Replace SVG white backgrounds with theme-aware colors

Inline local SVGs and replace #ffffff with background-rotated color that works correctly under the hue-rotate filter. Also limit SVG max-width to 450px and standardize all SVG white colors.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Strip excalidraw metadata from SVGs to reduce payload size

* Make SVGs responsive by using width: 100% with max-width constraint

* Remove redundant --bg-rotated declaration

---------

Co-authored-by: Claude <noreply@anthropic.com>

authored by danabra.mov

Claude and committed by
GitHub
d47d28c7 d288ea80

+39 -19
+34 -19
app/[slug]/page.tsx
··· 15 15 16 16 overnight.colors["editor.background"] = "var(--code-bg)"; 17 17 18 - export default async function PostPage({ params }: { params: Promise<{ slug: string }> }) { 18 + export default async function PostPage({ 19 + params, 20 + }: { 21 + params: Promise<{ slug: string }>; 22 + }) { 19 23 const { slug } = await params; 20 24 const filename = "./public/" + slug + "/index.md"; 21 25 const file = await readFile(filename, "utf8"); ··· 80 84 source={content} 81 85 components={{ 82 86 a: Link, 83 - img: ({ src, ...rest }) => { 87 + img: async ({ src, ...rest }) => { 88 + if (src && !/^https?:\/\//.test(src) && src.endsWith(".svg")) { 89 + const svgPath = `./public/${slug}/${src}`; 90 + const svgContent = await readFile(svgPath, "utf8"); 91 + const colorReplacedSvg = svgContent 92 + .replace(/#ffffff/gi, "var(--bg-rotated)") 93 + .replace(/<metadata>.*?<\/metadata>/s, '') 94 + .replace("<svg", '<svg style="max-width: 450px; width: 100%; height: auto;"'); 95 + 96 + return ( 97 + <span 98 + dangerouslySetInnerHTML={{ __html: colorReplacedSvg }} 99 + style={{ 100 + filter: "var(--svg-filter)", 101 + display: "inline-block", 102 + ...rest.style, 103 + }} 104 + {...rest} 105 + /> 106 + ); 107 + } 108 + 84 109 let finalSrc = src; 85 - let finalStyle = rest.style; 86 - 87 110 if (src && !/^https?:\/\//.test(src)) { 88 111 // https://github.com/gaearon/overreacted.io/issues/827 89 112 finalSrc = `/${slug}/${src}`; 90 - if (src.endsWith('.svg')) { 91 - finalStyle = { 92 - ...rest.style, 93 - filter: 'var(--svg-filter)' 94 - }; 95 - } 96 113 } 97 - 98 - return ( 99 - <img 100 - src={finalSrc} 101 - {...rest} 102 - style={finalStyle} 103 - /> 104 - ); 114 + 115 + return <img src={finalSrc} {...rest} />; 105 116 }, 106 117 ...postComponents, 107 118 }} ··· 176 187 return dirs.map((dir) => ({ slug: dir })); 177 188 } 178 189 179 - export async function generateMetadata({ params }: { params: Promise<{ slug: string }> }) { 190 + export async function generateMetadata({ 191 + params, 192 + }: { 193 + params: Promise<{ slug: string }>; 194 + }) { 180 195 const { slug } = await params; 181 196 const file = await readFile("./public/" + slug + "/index.md", "utf8"); 182 197 let { data } = matter(file);
+5
app/global.css
··· 63 63 transition: none !important; 64 64 } 65 65 } 66 + 67 + :root { --bg-rotated: white; } 68 + @media (prefers-color-scheme: dark) { 69 + :root { --bg-rotated: rgb(221, 225, 236); } 70 + }