@@ -11,7 +11,7 @@ export interface Options {
1111 * The input file to generate the favicons
1212 * Accepted formats are SVG, PNG, JPG, GIF, BMP, TIFF, WEBP
1313 */
14- input ?: string ;
14+ input ?: string | Record < number , string > ;
1515
1616 /**
1717 * The generated favicons
@@ -52,29 +52,44 @@ export interface Favicon {
5252 */
5353export function favicon ( userOptions ?: Options ) {
5454 const options = merge ( defaults , userOptions ) ;
55+ const input = typeof options . input === "string"
56+ ? { 16 : options . input }
57+ : options . input ;
5558
5659 return ( site : Site ) => {
57- async function getContent ( ) : Promise < Uint8Array | string | undefined > {
58- const content = options . input . endsWith ( ".svg" )
59- ? await site . getContent ( options . input , false )
60- : await site . getContent ( options . input , true ) ;
60+ async function getContent (
61+ file : string ,
62+ ) : Promise < Uint8Array | string | undefined > {
63+ const content = file . endsWith ( ".svg" )
64+ ? await site . getContent ( file , false )
65+ : await site . getContent ( file , true ) ;
6166
6267 if ( ! content ) {
63- log . warn ( `[favicon plugin] Input file not found: ${ options . input } ` ) ;
68+ log . warn ( `[favicon plugin] Input file not found: ${ file } ` ) ;
6469 }
6570
6671 return content ;
6772 }
6873
6974 site . process ( async function processFaviconImages ( _ , pages ) {
70- const content = await getContent ( ) ;
75+ const contents : Record < number , Uint8Array | string > = { } ;
7176
72- if ( ! content ) {
77+ for ( const [ size , file ] of Object . entries ( input ) ) {
78+ const fileContent = await getContent ( file ) ;
79+
80+ if ( fileContent ) {
81+ contents [ Number ( size ) ] = fileContent ;
82+ }
83+ }
84+
85+ if ( ! Object . keys ( contents ) . length ) {
7386 return ;
7487 }
7588
7689 const { cache } = site ;
7790 for ( const favicon of options . favicons ) {
91+ const content = getBestContent ( contents , favicon . size ) ;
92+
7893 pages . push (
7994 Page . create ( {
8095 url : favicon . url ,
@@ -89,24 +104,31 @@ export function favicon(userOptions?: Options) {
89104 }
90105
91106 // Add the svg favicon
92- if (
93- options . input . endsWith ( ".svg" ) &&
94- ! site . pages . find ( ( page ) => page . data . url === options . input ) &&
95- ! site . files . find ( ( file ) => file . outputPath === options . input )
96- ) {
97- site . pages . push (
98- Page . create ( {
99- url : options . input ,
100- content : await site . getContent (
101- options . input ,
102- false ,
103- ) ,
104- } ) ,
105- ) ;
107+ const svg = Object . entries ( input )
108+ . find ( ( [ , file ] ) => file . endsWith ( ".svg" ) ) ;
109+ if ( svg ) {
110+ const size = Number ( svg [ 0 ] ) ;
111+ const url = input [ size ] ;
112+ const content = contents [ size ] ;
113+ if (
114+ ! site . pages . find ( ( page ) => page . data . url === url ) &&
115+ ! site . files . find ( ( file ) => file . outputPath === url )
116+ ) {
117+ site . pages . push (
118+ Page . create ( {
119+ url,
120+ content,
121+ } ) ,
122+ ) ;
123+ }
106124 }
107125 } ) ;
108126
109127 site . process ( [ ".html" ] , function processFaviconPages ( pages ) {
128+ const svg = Object . entries ( input )
129+ . find ( ( [ , file ] ) => file . endsWith ( ".svg" ) ) ;
130+ const svgUrl = svg ? input [ Number ( svg [ 0 ] ) ] : null ;
131+
110132 for ( const page of pages ) {
111133 const { document } = page ;
112134
@@ -118,11 +140,11 @@ export function favicon(userOptions?: Options) {
118140 } ) ;
119141 }
120142
121- if ( options . input . endsWith ( ".svg" ) ) {
143+ if ( svgUrl ) {
122144 addIcon ( document , {
123145 rel : "icon" ,
124146 sizes : "any" ,
125- href : site . url ( options . input ) ,
147+ href : site . url ( svgUrl ) ,
126148 type : "image/svg+xml" ,
127149 } ) ;
128150 }
@@ -176,4 +198,22 @@ async function buildIco(
176198 return image ;
177199}
178200
201+ function getBestContent (
202+ content : Record < number , Uint8Array | string > ,
203+ sizes : number [ ] ,
204+ ) : Uint8Array | string {
205+ const size = Math . min ( ...sizes ) ;
206+ const availableSizes = Object . keys ( content ) . map ( Number ) ;
207+
208+ // Find the closest size available
209+ let bestSize = availableSizes [ 0 ] ;
210+ for ( const s of availableSizes ) {
211+ if ( s <= size && s > bestSize ) {
212+ bestSize = s ;
213+ }
214+ }
215+
216+ return content [ bestSize ] ;
217+ }
218+
179219export default favicon ;
0 commit comments