Skip to content

Instantly share code, notes, and snippets.

@mrdotb
Created June 9, 2024 09:01
Show Gist options
  • Select an option

  • Save mrdotb/8b78fde7dc3c8e191d1c8a4b90e21b0f to your computer and use it in GitHub Desktop.

Select an option

Save mrdotb/8b78fde7dc3c8e191d1c8a4b90e21b0f to your computer and use it in GitHub Desktop.

Revisions

  1. mrdotb created this gist Jun 9, 2024.
    12 changes: 12 additions & 0 deletions core_components.ex
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,12 @@

    def icon(%{name: "hero-" <> _} = assigns) do
    ~H"""
    <span class={[@name, @class]} />
    """
    end
    # Add the pattern match fn for lucide
    def icon(%{name: "lucide-" <> _} = assigns) do
    ~H"""
    <span class={[@name, @class]} />
    """
    end
    8 changes: 8 additions & 0 deletions mix.exs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,8 @@
    # Add the lucide repository to mix
    {:lucide,
    github: "lucide-icons/lucide",
    tag: "0.390.0",
    sparse: "icons",
    app: false,
    compile: false,
    depth: 1},
    5 changes: 5 additions & 0 deletions tailwind.config.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,5 @@
    const { heroComponent, lucideComponent } = require('./tailwind.icon-components')
    // ...
    // in plugins add
    // heroComponent,
    // lucideComponent,
    98 changes: 98 additions & 0 deletions tailwind.icon-components.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,98 @@
    const fs = require('fs')
    const path = require('path')
    const plugin = require('tailwindcss/plugin')

    exports.lucideComponent = plugin(({ matchComponents, theme }) => {
    let iconsDir = path.join(__dirname, '../deps/lucide/icons')

    const values = fs.readdirSync(iconsDir).reduce((iconsAcc, file) => {
    if (file.endsWith('.svg')) {
    const name = path.basename(file, '.svg')
    iconsAcc[name] = { name, fullPath: path.join(iconsDir, file) }
    return iconsAcc
    } else {
    return iconsAcc
    }
    }, {})

    matchComponents(
    {
    lucide: ({ name, fullPath }) => {
    const content = fs
    .readFileSync(fullPath)
    .toString()
    .replace(/\r?\n|\r/g, '')
    // Remove width and height attributes we only need viewBox
    .replace('width="24"', '')
    .replace('height="24"', '')

    let size = theme('spacing.6')
    if (name.endsWith('-mini')) {
    size = theme('spacing.5')
    } else if (name.endsWith('-micro')) {
    size = theme('spacing.4')
    }
    return {
    [`--lucide-${name}`]: `url('data:image/svg+xml;utf8,${content}')`,
    '-webkit-mask': `var(--lucide-${name})`,
    mask: `var(--lucide-${name})`,
    'background-color': 'currentColor',
    'vertical-align': 'middle',
    display: 'inline-block',
    width: size,
    height: size,
    }
    },
    },
    { values },
    )
    })

    // Embeds Hero Icons (https://heroicons.com) into your app.css bundle
    // See your `CoreComponents.icon/1` for more information.
    exports.heroComponent = plugin(({ matchComponents, theme }) => {
    let iconsDir = path.join(__dirname, '../deps/heroicons/optimized')
    const icons = [
    ['', '/24/outline'],
    ['-solid', '/24/solid'],
    ['-mini', '/20/solid'],
    ['-micro', '/16/solid'],
    ]
    const values = icons.reduce(
    (acc, [suffix, dir]) =>
    fs.readdirSync(path.join(iconsDir, dir)).reduce((iconsAcc, file) => {
    const name = path.basename(file, '.svg') + suffix
    iconsAcc[name] = { name, fullPath: path.join(iconsDir, dir, file) }
    return iconsAcc
    }, acc),
    {},
    )

    matchComponents(
    {
    hero: ({ name, fullPath }) => {
    const content = fs
    .readFileSync(fullPath)
    .toString()
    .replace(/\r?\n|\r/g, '')
    let size = theme('spacing.6')
    if (name.endsWith('-mini')) {
    size = theme('spacing.5')
    } else if (name.endsWith('-micro')) {
    size = theme('spacing.4')
    }
    return {
    [`--hero-${name}`]: `url('data:image/svg+xml;utf8,${content}')`,
    '-webkit-mask': `var(--hero-${name})`,
    mask: `var(--hero-${name})`,
    'background-color': 'currentColor',
    'vertical-align': 'middle',
    display: 'inline-block',
    width: size,
    height: size,
    }
    },
    },
    { values },
    )
    })