Custom Perspective Icon SVG Syntax

I am working on converting an open-source icon library into the format necessary for Perspective, and I am not finding great documentation on syntax that the SVG renderer is ignoring vs accepting.

Here is the repo: https://lucide.dev

An example SVG:

<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <polyline points="22 12 18 12 15 21 9 3 6 12 2 12"></polyline>
</svg>

My example converted version:

<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="transparent" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
	<g class="icon" id="activity">
		<polyline points="22 12 18 12 15 21 9 3 6 12 2 12"></polyline>
	</g>
</svg>

But I am noticing that I can't get it to recognize the additional props in the <svg> tag other than viewBox. So I am always getting a greyed out icon, unless I add properties in the designer to override fill and stroke

EDIT: It looks like the icon selection popup renders the stroke attribute in the svg tag accurately, but not the fill.

EDIT #2: It looks like if I move the styling syntax in to the group tag it works as well, just not the svg tag... so maybe this is a bug?

Also a "Crash the designer" but that this identified, there are a handful of values that can cause the designer to crash when you open the icon viewer if found inside the icons svg.

For example this is where I have fill="transparent" in the group property of an icon

You can kind of see the error in the output console, but the whole designer freezes up and I can't go select the text to share the full exception.

It does this whenever I have fill=var(--icon) or fill="transparent"

These would make great support tickets :slight_smile:

You make a good point, but just imagine the benefit all the random people following behind me will get that don't have support contracts!

Also I just didn't have time to make a call when I posted it. lol

2 Likes

To anyone curious who comes after this, here is a simple python script that converts (at least that) folder of .svg files into the icon library structure needed for Perspective.

import os, re


# Iterate through a folder of svg files and add them to one svg repo
folder = './myFolder'
repo = './myFolder.svg'
repo = open(repo, 'w')

xml_base = '<?xml version="1.0" encoding="utf-8"?>\n' \
		   '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">\n' \
		   '\t<defs>\n' \
			'\t\t<style>\n' \
			'\t\t\t.icon { display: none }\n' \
			'\t\t\t.icon:target { display: inline }\n' \
			'\t\t</style>\n' \
			'\t</defs>\n'

repo.write(xml_base)

base_tab_count = 1

for filename in os.listdir(folder):
	if filename.endswith(".svg"):
		base_tabs = '\t' * base_tab_count
		repo.write('\n%s<!--%s-->\n' % (base_tabs, filename[:-4]))
		repo.write('%s<svg viewBox="0 0 24 24" width="24" height="24">\n' % base_tabs)
		svg = open(folder + '/' + filename, 'r')
		for line in svg:
			# If the line starts with <svg, use a regex to replace the xmlns and width/height attributes
			if line.startswith('<svg'):
				line = line.replace('<svg', '<g class="icon" id="%s"' % filename[:-4])
				line = re.sub(r' xmlns="[^"]+"', '', line)
				line = re.sub(r' width="[^"]+"', '', line)
				line = re.sub(r' height="[^"]+"', '', line)
				line = re.sub(r' viewBox="[^"]+"', '', line)
				line = re.sub(r' fill="[^"]+"', ' fill="none"', line)
				line = re.sub(r' stroke="[^"]+"', ' stroke="black"', line)

			if line.startswith('</svg'):
				line = line.replace('</svg', '</g')
			
			if line != '\n':
				repo.write("%s\t%s" % (base_tabs, line))
			
		svg.close()
		repo.write('\n%s</svg>\n' % base_tabs)

repo.write('\n</svg>')
repo.close()
1 Like

You are using 8.1.22 right? it has some recent svg changes^^

Why not use an XML library? I use xmltodict in python 3.9
Not sure if it's got any C dependencies... But otherwise there should be a Java XML library you can use

Yes sir 8.1.22

To be fair, GitHub copilot wrote most of the script, I was just along for the ride

3 Likes

This was beautiful. Thank you for sharing

What a bummer!:
image

That was a well delivered point

1 Like

I am trying to get an existing working SVG into the correct format for an icon SVG.

I add the symbol with the class and id but I'm not sure what to do with the extra "g" layers?

<svg xmlns="http://www.w3.org/2000/svg">
    <symbol class="icon" id="ETECH" viewBox="0 0 24.8 24.8">
        <g id="Layer_2" data-name="Layer 2">
        <g id="Layer_1-2" data-name="Layer 1">
<path d="M14.3,7.8a1.4,1.4,0,0,0,1-.2l5.4-5.5,2,2L17.2,9.5a1.4,1.4,0,0,0-.2,1,1.1,1.1,0,0,0,.9.5h6.9V0h-11V6.9A1.1,1.1,0,0,0,14.3,7.8Z"/><circle cx="12.4" cy="12.4" r="1.7"/><path d="M6.9,11a1.1,1.1,0,0,0,.9-.5,1.4,1.4,0,0,0-.2-1L2.1,4.1l2-2L9.5,7.6a1.4,1.4,0,0,0,1,.2,1.1,1.1,0,0,0,.5-.9V0H0V6.2L4.8,11Z"/><path d="M24.8,13.8H17.9a1.1,1.1,0,0,0-.9.5,1.4,1.4,0,0,0,.2,1l5.5,5.4-2,2-5.4-5.5a1.4,1.4,0,0,0-1-.2,1.1,1.1,0,0,0-.5.9V20l4.8,4.8h6.2v-11Z"/><rect x="2.1" y="18" width="6.6" height="2.76" transform="translate(-12.1 9.5) rotate(-45)"/><rect x="11" y="22.1" width="2.8" height="2.76"/><rect y="11" width="2.8" height="2.76"/>
        </g></g>
    </symbol>
</svg>

Not sure what the layers are for but removing them got it working.

<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">  
 
    <!--E TECH Mark icon-->
    <svg viewBox="0 0 24 24">
        <g id="ETECHMark">
		<path d="M14.3,7.8a1.4,1.4,0,0,0,1-.2l5.4-5.5,2,2L17.2,9.5a1.4,1.4,0,0,0-.2,1,1.1,1.1,0,0,0,.9.5h6.9V0h-11V6.9A1.1,1.1,0,0,0,14.3,7.8Z"/><circle cx="12.4" cy="12.4" r="1.7"/><path d="M6.9,11a1.1,1.1,0,0,0,.9-.5,1.4,1.4,0,0,0-.2-1L2.1,4.1l2-2L9.5,7.6a1.4,1.4,0,0,0,1,.2,1.1,1.1,0,0,0,.5-.9V0H0V6.2L4.8,11Z"/><path d="M24.8,13.8H17.9a1.1,1.1,0,0,0-.9.5,1.4,1.4,0,0,0,.2,1l5.5,5.4-2,2-5.4-5.5a1.4,1.4,0,0,0-1-.2,1.1,1.1,0,0,0-.5.9V20l4.8,4.8h6.2v-11Z"/><rect x="2.1" y="18" width="6.6" height="2.76" transform="translate(-12.1 9.5) rotate(-45)"/><rect x="11" y="22.1" width="2.8" height="2.76"/><rect y="11" width="2.8" height="2.76"/>
        </g>
    </svg>  
</svg>