11import { Component , createSignal , createEffect , JSX , splitProps , onCleanup } from 'solid-js' ;
2-
3- // Cache for loaded SVG content
4- const svgCache = new Map < string , string > ( ) ;
2+ import { getIconName } from '../../utils/iconMap' ;
3+ import { criticalIcons } from '../../utils/criticalIcons' ;
4+ import { getFromCache , addToCache , hasInCache , clearCache } from '../../utils/iconCache' ;
55
66// Cache for failed icons to avoid retrying
77const failedIcons = new Set < string > ( ) ;
@@ -11,7 +11,7 @@ const pendingFetches = new Map<string, Promise<string | null>>();
1111
1212// Request queue to limit concurrent fetches
1313let activeFetches = 0 ;
14- const MAX_CONCURRENT_FETCHES = 4 ;
14+ const MAX_CONCURRENT_FETCHES = 10 ;
1515const fetchQueue : Array < ( ) => void > = [ ] ;
1616
1717function processQueue ( ) {
@@ -21,9 +21,6 @@ function processQueue() {
2121 }
2222}
2323
24- // Icon name mapping from various libraries to Font Awesome
25- import { getIconName } from '../../utils/iconMap' ;
26-
2724export interface IconProps extends JSX . SvgSVGAttributes < SVGSVGElement > {
2825 name : string ;
2926 size ?: number | string ;
@@ -59,9 +56,10 @@ export const Icon: Component<IconProps> = (props) => {
5956 return null ;
6057 }
6158
62- // Check cache
63- if ( svgCache . has ( iconName ) ) {
64- return svgCache . get ( iconName ) ! ;
59+ // Check memory/session cache
60+ const cached = getFromCache ( iconName ) ;
61+ if ( cached ) {
62+ return cached ;
6563 }
6664
6765 // Check if already fetching
@@ -84,7 +82,7 @@ export const Icon: Component<IconProps> = (props) => {
8482 }
8583
8684 const svgText = await response . text ( ) ;
87- svgCache . set ( iconName , svgText ) ;
85+ addToCache ( iconName , svgText ) ;
8886 resolve ( svgText ) ;
8987 } catch {
9088 failedIcons . add ( iconName ) ;
@@ -114,9 +112,17 @@ export const Icon: Component<IconProps> = (props) => {
114112 return ;
115113 }
116114
117- // Check cache synchronously first
118- if ( svgCache . has ( iconName ) ) {
119- parseSvgContent ( svgCache . get ( iconName ) ! ) ;
115+ // Tier 1: critical icons (inlined, synchronous)
116+ const inlined = criticalIcons . get ( iconName ) ;
117+ if ( inlined ) {
118+ parseSvgContent ( inlined ) ;
119+ return ;
120+ }
121+
122+ // Tier 2: memory/session cache (synchronous)
123+ const cached = getFromCache ( iconName ) ;
124+ if ( cached ) {
125+ parseSvgContent ( cached ) ;
120126 return ;
121127 }
122128
@@ -126,7 +132,7 @@ export const Icon: Component<IconProps> = (props) => {
126132 return ;
127133 }
128134
129- // Load async
135+ // Tier 3: HTTP fetch ( async)
130136 loadIcon ( iconName ) . then ( ( svgText ) => {
131137 if ( ! mounted ) return ;
132138 if ( svgText ) {
@@ -190,28 +196,69 @@ export const Icon: Component<IconProps> = (props) => {
190196export const preloadIcons = async ( iconNames : string [ ] ) : Promise < void > => {
191197 const promises = iconNames . map ( async ( name ) => {
192198 const resolvedName = getIconName ( name ) ;
193- if ( ! resolvedName || svgCache . has ( resolvedName ) ) return ;
199+ if ( ! resolvedName ) return ;
200+
201+ // Skip if available in critical icons or cache
202+ if ( criticalIcons . has ( resolvedName ) || hasInCache ( resolvedName ) ) return ;
194203
195204 try {
196205 const svgPath = `/kit-a943e80cf4-desktop/svgs-full/light/${ resolvedName } .svg` ;
197206 const response = await fetch ( svgPath ) ;
198207 if ( response . ok ) {
199208 const svgText = await response . text ( ) ;
200- svgCache . set ( resolvedName , svgText ) ;
209+ addToCache ( resolvedName , svgText ) ;
201210 }
202- } catch ( err ) {
211+ } catch {
203212 // Silently fail for preloading
204213 }
205214 } ) ;
206215
207216 await Promise . all ( promises ) ;
208217} ;
209218
219+ /**
220+ * Preload non-critical icons during idle time
221+ * Uses requestIdleCallback with setTimeout fallback
222+ */
223+ export const scheduleIdlePreload = ( iconNames : string [ ] ) : void => {
224+ const BATCH_SIZE = 5 ;
225+ let index = 0 ;
226+
227+ const processBatch = ( _deadline ?: IdleDeadline ) => {
228+ const batch : string [ ] = [ ] ;
229+ while ( index < iconNames . length && batch . length < BATCH_SIZE ) {
230+ const name = getIconName ( iconNames [ index ] ) ;
231+ index ++ ;
232+ if ( name && ! criticalIcons . has ( name ) && ! hasInCache ( name ) && ! failedIcons . has ( name ) ) {
233+ batch . push ( name ) ;
234+ }
235+ }
236+
237+ if ( batch . length > 0 ) {
238+ preloadIcons ( batch ) ;
239+ }
240+
241+ if ( index < iconNames . length ) {
242+ if ( typeof requestIdleCallback === 'function' ) {
243+ requestIdleCallback ( processBatch ) ;
244+ } else {
245+ setTimeout ( processBatch , 50 ) ;
246+ }
247+ }
248+ } ;
249+
250+ if ( typeof requestIdleCallback === 'function' ) {
251+ requestIdleCallback ( processBatch ) ;
252+ } else {
253+ setTimeout ( processBatch , 50 ) ;
254+ }
255+ } ;
256+
210257/**
211258 * Clear the icon cache (useful for memory management)
212259 */
213260export const clearIconCache = ( ) : void => {
214- svgCache . clear ( ) ;
261+ clearCache ( ) ;
215262} ;
216263
217264export default Icon ;
0 commit comments