3737ICON_SOURCES = {
3838 "material" : "https://github.com/google/material-design-icons.git" ,
3939 "font_awesome" : "https://github.com/FortAwesome/Font-Awesome/archive/refs/tags/7.1.0.zip" ,
40- "remix" : "https://github.com/Remix-Design/RemixIcon/archive/refs/tags/v4.6.0.zip" ,
40+ "remix" : "https://github.com/Remix-Design/RemixIcon/archive/refs/tags/v4.8.0.zip" ,
41+ "lucide" : "https://github.com/lucide-icons/lucide/archive/refs/tags/0.562.0.zip" ,
4142}
4243ICON_EXTRACT = {
4344 "material" : "material-design-icons" ,
4445 "font_awesome" : "Font-Awesome-7.1.0" ,
45- "remix" : "RemixIcon-4.6.0" ,
46+ "remix" : "RemixIcon-4.8.0" ,
47+ "lucide" : "lucide-0.562.0" ,
4648}
4749ICONS = [
4850 # Remember to also update tests/files/all_icons.json for test coverage
@@ -189,14 +191,6 @@ def _loadMap(name: str) -> dict[str, str]:
189191 return icons
190192
191193
192- def _fixXml (svg : ET .Element ) -> str :
193- """Clean up the SVG XML and add needed fields."""
194- svg .set ("fill" , "#000000" )
195- svg .set ("height" , "128" )
196- svg .set ("width" , "128" )
197- return ET .tostring (svg ).decode ()
198-
199-
200194def _writeThemeFile (
201195 path : Path , name : str , author : str , license_ : str , icons : dict [str , ET .Element ]
202196) -> None :
@@ -210,7 +204,8 @@ def _writeThemeFile(
210204 out .write ("\n " )
211205 out .write ("# Icons\n " )
212206 for key , svg in icons .items ():
213- out .write (f"icon:{ key :<15s} = { _fixXml (svg )} \n " )
207+ icon = ET .tostring (svg ).decode ().replace ("\n " , "" )
208+ out .write (f"icon:{ key :<15s} = { icon } \n " )
214209 print (f"- Wrote: { len (icons )} icons" )
215210 print (f"- Target: { path .relative_to (UTILS .parent )} " )
216211
@@ -261,7 +256,11 @@ def processMaterialIcons(workDir: Path, iconsDir: Path, jobs: dict) -> None:
261256 fileName = f"{ icon } _24px.svg"
262257 iconFile = iconSrc / icon / f"materialsymbols{ style } " / fileName
263258 if iconFile .is_file ():
264- icons [key ] = ET .fromstring (iconFile .read_text (encoding = "utf-8" ))
259+ svg = ET .fromstring (iconFile .read_text (encoding = "utf-8" ))
260+ svg .set ("fill" , "#000000" )
261+ svg .set ("height" , "128" )
262+ svg .set ("width" , "128" )
263+ icons [key ] = svg
265264 else :
266265 print (f"Not Found: { iconFile } " )
267266
@@ -304,6 +303,9 @@ def processFontAwesome(workDir: Path, iconsDir: Path, jobs: dict) -> None:
304303 viewbox = [int (x ) for x in svg .get ("viewBox" , "" ).split ()]
305304 viewbox = [viewbox [2 ]// 2 - 256 , 0 , 512 , 512 ]
306305 svg .set ("viewBox" , " " .join (str (x ) for x in viewbox ))
306+ svg .set ("fill" , "#000000" )
307+ svg .set ("height" , "128" )
308+ svg .set ("width" , "128" )
307309 for elem in svg .iter ():
308310 elem .attrib .pop ("fill" , None )
309311 icons [key ] = svg
@@ -317,6 +319,37 @@ def processFontAwesome(workDir: Path, iconsDir: Path, jobs: dict) -> None:
317319 print ("" )
318320
319321
322+ def processLucide (workDir : Path , iconsDir : Path , jobs : dict ) -> None :
323+ """Process Lucide icons of a given spec and write output file."""
324+ srcRepo = workDir / ICON_EXTRACT ["lucide" ]
325+ if not srcRepo .is_dir ():
326+ _downloadIconPack (workDir , "lucide" )
327+
328+ for file , job in jobs .items ():
329+ name : str = job ["name" ]
330+ print (f"Processing: { name } " )
331+
332+ icons : dict [str , ET .Element ] = {}
333+ iconSrc = srcRepo / "icons"
334+ for key , icon in _loadMap ("lucide" ).items ():
335+ iconFile = iconSrc / f"{ icon } .svg"
336+ if iconFile .is_file ():
337+ svg = ET .fromstring (iconFile .read_text (encoding = "utf-8" ))
338+ ET .indent (svg , space = "" )
339+ svg .set ("fill" , "none" )
340+ svg .set ("stroke" , "#000000" )
341+ svg .set ("height" , "128" )
342+ svg .set ("width" , "128" )
343+ icons [key ] = svg
344+ else :
345+ print (f"Not Found: { iconFile } " )
346+
347+ target = iconsDir / f"{ file } .icons"
348+ _writeThemeFile (target , name , "Cole Bemis, Lucide Contributors" , "ISC/MIT License" , icons )
349+
350+ print ("" )
351+
352+
320353def processRemix (workDir : Path , iconsDir : Path , jobs : dict ) -> None :
321354 """Process Remix icons of a given spec and write output file."""
322355 srcRepo = workDir / ICON_EXTRACT ["remix" ]
@@ -351,7 +384,11 @@ def processRemix(workDir: Path, iconsDir: Path, jobs: dict) -> None:
351384 print (f"Not Found: { fileName } " )
352385 continue
353386
354- icons [key ] = ET .fromstring (iconFile .read_text (encoding = "utf-8" ))
387+ svg = ET .fromstring (iconFile .read_text (encoding = "utf-8" ))
388+ svg .set ("fill" , "#000000" )
389+ svg .set ("height" , "128" )
390+ svg .set ("width" , "128" )
391+ icons [key ] = svg
355392
356393 target = iconsDir / f"{ file } .icons"
357394 _writeThemeFile (target , name , "Remix Icon" , "Apache 2.0" , icons )
@@ -418,6 +455,13 @@ def main(args: argparse.Namespace) -> None:
418455 },
419456 })
420457
458+ if style in ("all" , "optional" , "free" , "lucide" ):
459+ processLucide (workDir , iconsDir , {
460+ "lucide" : {
461+ "name" : "Lucide" ,
462+ },
463+ })
464+
421465 if style in ("all" , "optional" , "non_free" , "remix" ):
422466 processRemix (workDir , iconsDir , {
423467 "remix_outline" : {
0 commit comments