Skip to content

Commit 74a413a

Browse files
committed
refactor(icons): replace lucide social brand icons with custom SVGs
Lucide is deprecating brand icons (Github, Twitter, Linkedin, Instagram) in upcoming versions. Migrated all 11 SocialIconName mappings to inline SVGs loaded via import.meta.glob with ?raw query, preserving currentColor inheritance and keeping the <SocialIcon platform="..." /> API intact. - Added src/lib/icons/assets/ with 11 normalized SVGs - Added registry index.ts with extractInner helper for set:html rendering - Extended IconMappingWithFallback with optional svg?: string field - Unified website handling in SpeakerCard (removed Globe from lucide) - Icon.astro now renders raw SVGs inline when mapping.svg is present
1 parent 144f3f0 commit 74a413a

16 files changed

Lines changed: 82 additions & 50 deletions

File tree

src/components/home/SpeakerCard.astro

Lines changed: 9 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
---
2-
import { Globe } from '@lucide/astro'
32
import type { ISpeaker, ISpeakerLink } from '../../types/speakers'
43
import { texts } from '../../i18n/home'
54
import { menuTexts } from '../../i18n/menu'
@@ -57,27 +56,15 @@ const linkClasses =
5756
{
5857
speaker.links.map((link) => (
5958
<li>
60-
{link.type === 'website' ? (
61-
<a
62-
href={link.url}
63-
target="_blank"
64-
rel="noopener noreferrer"
65-
aria-label={ariaForLink(link, speaker.name)}
66-
class={linkClasses}
67-
>
68-
<Globe class="w-5 h-5" aria-hidden="true" focusable="false" />
69-
</a>
70-
) : (
71-
<a
72-
href={link.url}
73-
target="_blank"
74-
rel="noopener noreferrer"
75-
aria-label={ariaForLink(link, speaker.name)}
76-
class={linkClasses}
77-
>
78-
<SocialIcon platform={link.type} size="md" aria-hidden="true" />
79-
</a>
80-
)}
59+
<a
60+
href={link.url}
61+
target="_blank"
62+
rel="noopener noreferrer"
63+
aria-label={ariaForLink(link, speaker.name)}
64+
class={linkClasses}
65+
>
66+
<SocialIcon platform={link.type} size="md" aria-hidden="true" />
67+
</a>
8168
</li>
8269
))
8370
}

src/components/icons/Icon.astro

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ const {
1717
} = Astro.props
1818
1919
// Get the mapped icon or fallback
20-
const { icon: LucideIconComponent, fallback } = getIconMapping(name)
20+
const { icon: LucideIconComponent, svg, fallback } = getIconMapping(name)
2121
2222
// Build CSS classes
2323
const sizeClasses = IconSizes[size]
@@ -29,7 +29,7 @@ const classes = [sizeClasses, colorClasses, className, 'inline-block flex-shrink
2929
const style = color.startsWith('#') || color.startsWith('rgb') || color.startsWith('hsl') ? { color } : {}
3030
3131
// Log missing mappings in development
32-
if (!LucideIconComponent && !fallback) {
32+
if (!LucideIconComponent && !svg && !fallback) {
3333
try {
3434
if (typeof window === 'undefined' || (globalThis as any).__DEV__ !== false) {
3535
console.warn(`[Icon] No mapping found for icon "${name}". Using fallback.`)
@@ -41,7 +41,19 @@ if (!LucideIconComponent && !fallback) {
4141
---
4242

4343
{
44-
LucideIconComponent ? (
44+
svg ? (
45+
<svg
46+
xmlns="http://www.w3.org/2000/svg"
47+
viewBox="0 0 24 24"
48+
class={classes}
49+
style={style}
50+
aria-label={ariaHidden ? undefined : ariaLabel}
51+
aria-hidden={ariaHidden ? 'true' : undefined}
52+
focusable="false"
53+
set:html={svg}
54+
{...rest}
55+
/>
56+
) : LucideIconComponent ? (
4557
<LucideIconComponent
4658
class={classes}
4759
style={style}

src/lib/icons/assets/bluesky.svg

Lines changed: 1 addition & 0 deletions
Loading

src/lib/icons/assets/github.svg

Lines changed: 1 addition & 0 deletions
Loading

src/lib/icons/assets/index.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
const rawSvgs = import.meta.glob('./*.svg', {
2+
query: '?raw',
3+
import: 'default',
4+
eager: true,
5+
}) as Record<string, string>
6+
7+
function extractInner(svg: string): string {
8+
const match = svg.match(/<svg[^>]*>([\s\S]*?)<\/svg>/i)
9+
return match ? match[1].trim() : svg
10+
}
11+
12+
export const socialSvgs: Record<string, string> = Object.fromEntries(
13+
Object.entries(rawSvgs).map(([path, content]) => [
14+
path.replace('./', '').replace('.svg', ''),
15+
extractInner(content),
16+
]),
17+
)

src/lib/icons/assets/instagram.svg

Lines changed: 1 addition & 0 deletions
Loading

src/lib/icons/assets/linkedin.svg

Lines changed: 1 addition & 0 deletions
Loading

src/lib/icons/assets/mastodon.svg

Lines changed: 1 addition & 0 deletions
Loading

src/lib/icons/assets/podcasts.svg

Lines changed: 1 addition & 0 deletions
Loading

src/lib/icons/assets/rss.svg

Lines changed: 1 addition & 0 deletions
Loading

0 commit comments

Comments
 (0)