Last active
April 14, 2025 19:57
-
-
Save greven/36077217806ddd42989387a212a8c8db to your computer and use it in GitHub Desktop.
Phoenix CSS Icons
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@doc """ | |
Renders an icon. | |
Supports three icon libraries: | |
- [Heroicons](https://heroicons.com) - prefixed with "hero-" | |
- [Lucide](https://lucide.dev) - prefixed with "lucide-" | |
- [Simple Icons](https://simpleicons.org) - prefixed with "si-" | |
You can customize the size and colors of the icons by setting | |
width, height, and background color classes. | |
Icons are extracted from their respective directories and bundled within | |
your compiled app.css by the plugins in `assets/vendor/`. | |
## Examples | |
<.icon name="hero-x-mark-solid" /> | |
<.icon name="hero-arrow-path" class="ml-1 size-3 motion-safe:animate-spin" /> | |
<.icon name="lucide-github" /> | |
<.icon name="si-github" class="size-6" /> | |
<.icon name="si-elixir" class="size-5 text-purple-600" /> | |
""" | |
attr :name, :string, required: true | |
attr :class, :string, default: "size-4" | |
def icon(%{name: "hero-" <> _} = assigns) do | |
~H""" | |
<span class={[@name, @class]} /> | |
""" | |
end | |
def icon(%{name: "lucide-" <> _} = assigns) do | |
~H""" | |
<span class={[@name, @class]} /> | |
""" | |
end | |
def icon(%{name: "si-" <> _} = assigns) do | |
~H""" | |
<span class={[@name, @class]} /> | |
""" | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Add lucide.js to assets/vendor | |
const plugin = require('tailwindcss/plugin'); | |
const fs = require('fs'); | |
const path = require('path'); | |
module.exports = plugin(function ({ matchComponents, theme }) { | |
let iconsDir = path.join(__dirname, '../../deps/lucide_icons/icons'); | |
let values = {}; | |
fs.readdirSync(iconsDir).forEach((file) => { | |
if (file.endsWith('.svg')) { | |
let name = path.basename(file, '.svg'); | |
values[name] = { name, fullPath: path.join(iconsDir, file) }; | |
} | |
}); | |
matchComponents( | |
{ | |
lucide: ({ name, fullPath }) => { | |
let content = fs | |
.readFileSync(fullPath) | |
.toString() | |
.replace(/\r?\n|\r/g, ''); | |
// Clean up SVG | |
content = content | |
.replace(/width="24"/g, '') | |
.replace(/height="24"/g, '') | |
.replace(/stroke-width="2"/g, 'stroke-width="1.5"') | |
.replace(/stroke="[^"]+"/g, 'stroke="currentColor"'); | |
content = encodeURIComponent(content); | |
let size = theme('spacing.6'); // 1.5rem / 24px by default | |
return { | |
[`--lucide-${name}`]: `url('data:image/svg+xml;utf8,${content}')`, | |
'-webkit-mask': `var(--lucide-${name})`, | |
mask: `var(--lucide-${name})`, | |
'mask-repeat': 'no-repeat', | |
'background-color': 'currentColor', | |
'vertical-align': 'middle', | |
display: 'inline-block', | |
width: size, | |
height: size, | |
}; | |
}, | |
}, | |
{ values } | |
); | |
}); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# ... | |
{:heroicons, | |
github: "tailwindlabs/heroicons", | |
tag: "v2.1.5", | |
sparse: "optimized", | |
app: false, | |
compile: false, | |
depth: 1}, | |
{ | |
:lucide_icons, | |
github: "lucide-icons/lucide", | |
tag: "0.487.0", | |
sparse: "icons", | |
app: false, | |
compile: false, | |
depth: 1 | |
}, | |
{:simple_icons, | |
github: "simple-icons/simple-icons", | |
tag: "14.12.1", | |
sparse: "icons", | |
app: false, | |
compile: false, | |
depth: 1 | |
}, | |
# ... |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Add simple-icons.js to assets/vendor | |
const plugin = require('tailwindcss/plugin'); | |
const fs = require('fs'); | |
const path = require('path'); | |
module.exports = plugin(function ({ matchComponents, theme }) { | |
let iconsDir = path.join(__dirname, '../../deps/simple_icons/icons'); | |
let values = {}; | |
fs.readdirSync(iconsDir).forEach((file) => { | |
if (file.endsWith('.svg')) { | |
let name = path.basename(file, '.svg'); | |
values[name] = { name, fullPath: path.join(iconsDir, file) }; | |
} | |
}); | |
matchComponents( | |
{ | |
si: ({ name, fullPath }) => { | |
let content = fs | |
.readFileSync(fullPath) | |
.toString() | |
.replace(/\r?\n|\r/g, ''); | |
content = content.replace(/fill="[^"]+"/g, 'fill="currentColor"'); | |
content = encodeURIComponent(content); | |
let size = theme('spacing.5'); | |
return { | |
[`--si-${name}`]: `url('data:image/svg+xml;utf8,${content}')`, | |
'-webkit-mask': `var(--si-${name})`, | |
mask: `var(--si-${name})`, | |
'mask-repeat': 'no-repeat', | |
'background-color': 'currentColor', | |
'vertical-align': 'middle', | |
'mask-size': 'contain', | |
'mask-position': 'center', | |
display: 'inline-block', | |
width: size, | |
height: size, | |
}; | |
}, | |
}, | |
{ values } | |
); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
The Phoenix generator includes Heroicons by default, but while Heroicons
is a really nice set it isn't very expansive. Let's include Lucide Icons
and Simple Icons for brand icons.
Like the included Heroicons, they won't take space on the bundled CSS file as Tailwind will only include the icons used.