Visitar URL original
Custom Icons · Issue #12 · unplugin/unplugin-icons · GitHub
Skip to content

Custom Icons #12

Closed
Closed

Description

@NoelDeMartin

This is great, I've tried using the vscode-iconify with Vitesse and the DX is super good, I don't think I'll want to go back to the older days!

Which raises the following question: Is it possible to configure custom svgs to be loaded using the same system? I know since the icons are my own, I can just pack them in the project or create my own component to load them (which is what I've been doing so far). But it'd be great to be able of using the same affordances as the other icons, like seeing the icon preview in vscode and such.

Activity

  1. antfu commented on Feb 3, 2021

    @antfu
    Member

    Thanks, glad you enjoy the workflow!

    For the custom icon sets, it's indeed possible for vite-plugin-icons to support it. But we'd need to design a good API and conventions for loading the custom icons. What would you expect for how the API looks like to you can configure it?

  2. NoelDeMartin commented on Feb 3, 2021

    @NoelDeMartin
    Author

    Well, using Vitesse as an example, and assuming I have a custom icon called my-custom-icon.svg, I'd like to use it like this:

    <vitesse-my-custom-icon />

    Where "vitesse" is the namespace of my app, maybe by default it could be "app" if it isn't specified, so you'd write:

    <app-my-custom-icon />

    And I think it's pretty common to have icons under src/assets/icons, so that could also be a good default. Although I'm not sure if it's possible to know where the root of the project is.

    With these, I think the configuration could be something like this:

    // Specifying everything...
    ViteIconsResolver({
        customIcons: {
            folder: '/~/assets/icons', // defaults to 'src/assets/icons'
            componentPrefix: 'vitesse', // defaults to 'app'
        },
    });
    
    // Or using all the defaults
    ViteIconsResolver({
        customIcons: true;
    });

    And I would expect this to make any .svg from that folder available as an icon, using the file name as the icon name :).

    Edit: Maybe they could be called localIcons or something else, if that's more clear. Naming is hard 😅.

  3. JohnCampionJr commented on Feb 6, 2021

    @JohnCampionJr

    Could I also suggest an ability to import an Iconify JSON bundle? As an example, Font Awesome Pro JSONs are available but not part of the public Iconify bundles.

  4. chojnicki commented on Mar 2, 2021

    @chojnicki
    Contributor

    I resolved problem, but not by using this package.

    Vite-plugin-icons uses vite-plugin-components from same author (thanks @antfu for awesome work) for auto-discovery components, so Installed this instead. Then I combined this with vite-plugin-vue-svg for importing .svg as components. Simple as that, now we have universal package for any icons pack :)

    After doing everything ready to work, I found that actually @antfu did exactly that in example from 3 days ago....
    https://github.com/antfu/vite-plugin-components/blob/master/examples/vue3/vite.config.ts

    But sure similar functionality should be available in vite-plugin-icons because it would be more straightforward. Anyone should be using any icons they want. After all this package is named "-icons" and not "-iconify" ;)

  5. oliverpool commented on Aug 20, 2021

    @oliverpool

    I really like this package, since it supports both vue 2 and 3 (maybe the compiler part could be integrated into https://github.com/vueuse/vue-demi ;-).

    we'd need to design a good API and conventions for loading the custom icons. What would you expect for how the API looks like to you can configure it?

    After thinking about it, I would propose to add one configuration key customCollections (or some other name) of type Record<string, IconCollection>:

    export interface IconCollection {
      getIconData(icon: string): object | null; // like Iconify, { "body": "<path ...>", "width": 20, "height": 20} should be enough
    }
    export default {
      plugins: [
        Vue(),
        Icons({
          customCollections: {
              'app': new LazyCollection('./folder'),
          }
        })
      ],
    }

    This customCollection would be checked before (or inside) the getCollection(name) call.

    In this case, LazyCollection could make a lookup in the ./folder on every call to getIconData. However I would expressly let implementations of IconCollection outside of this package, since there might be a lot of usecases (caching / svgo compression / FontAwesomePro / fallback...).
    Maybe one implementation could live in this repo to serve as a base for the users to implement their own IconCollection.


    Maybe the getIconData should be async (since loading the file would be done in a non-blocking way), but I don't have enough package experience to know if this is a good idea or not.


    I think this very minimal API would be quite a powerful addition to this package, since it would make it pluggable to a lot of icon sources.

    If enough people think that this would be a good idea, I would be glad to craft a PR.

    @antfu thank you for you awesome work for the vue community!

  6. antfu commented on Aug 30, 2021

    @antfu
    Member

    Could anyone offer me a small sample of custom icons (with the folder/file structure you would like) for me to experiment with the API design? It would be great if their license allow me to include them as examples in this repo in the future. Thanks!

  7. pinned this issue on Aug 30, 2021
  8. m5o commented on Aug 31, 2021

    @m5o

    💡 The Popular category from Icons8 is free, for example.
    They only want to include a link and the License seems open source friendly for all the other categories.
    Icons8 key feature: they offer icons in many different styles, icon naming and meaning are consistent. Useful for theming applications, you just need to change the icon style/file structure. Maybe this is a resource you’ll find interesting. ✌️

  9. Akryum commented on Sep 14, 2021

    @Akryum
    Contributor

    Here are some icons I made, you are free to use them however you want:

    ~/src/assets/icons/SteeringWheel.svg

    <svg
        fill="none"
        stroke-linecap="round"
        stroke-linejoin="round"
        stroke-width="2"
        viewBox="0 0 24 24"
        stroke="currentColor"
      ><path d="M12 14V20M10 12L4 10M14 12L20 10M21 12a9 9 0 11-18 0 9 9 0 0118 0zM14 12a2 2 0 11-4 0 2 2 0 014 0z" /></svg>

    ~/src/assets/icons/Car.svg

    <svg
        fill="none"
        stroke-linecap="round"
        stroke-linejoin="round"
        stroke-width="2"
        viewBox="0 0 24 24"
        stroke="currentColor"
      ><path d="M17 10a4 4 0 0 0-4-4h-2a4 4 0 0 0-4 4m5-4v4M3 16h2m4 0h6m4 0h2v-3a3 3 0 0 0-3-3h-12a3 3 0 0 0-3 3v3M9 16a2 2 0 1 1-4 0a2 2 0 0 1 4 0zM19 16a2 2 0 1 1-4 0a2 2 0 0 1 4 0z" /></svg>
  10. antfu commented on Sep 14, 2021

    @antfu
    Member

    Thanks everyone, it's now landed as v0.11!
    https://github.com/antfu/unplugin-icons#custom-icons

  11. oliverpool commented on Sep 16, 2021

    @oliverpool

    Works perfectly, thank you so much!

  12. jceb commented on Oct 7, 2021

    @jceb
    Contributor

    Just as a reference, in order to integrate FontAwesome Pro icons via vite use some configuration like this.

    Add npm dependencies, esp. @fortawesome/fontawesome-pro.

    vite.config.js:

    import { defineConfig } from "vite";
    import Icons from "unplugin-icons/vite";
    import IconsResolver from "unplugin-icons/resolver";
    import AutoImport from "unplugin-auto-import/vite";
    import { FileSystemIconLoader } from "unplugin-icons/loaders";
    import { promises as fs } from "fs";
    
    export default defineConfig({
      plugins: [
        ...,
        AutoImport({
          resolvers: [
            IconsResolver({
              prefix: "Icon",
              extension: "jsx",
              customCollections: [
                "fap-brands",
                "fap-duotone",
                "fap-light",
                "fap-regular",
                "fap-solid",
              ],
            }),
          ],
        }),
    
        Icons({
          compiler: "solid",
          customCollections: {
            "fap-brands": FileSystemIconLoader(
              "PATH_TO/node_modules/@fortawesome/fontawesome-pro/svgs/brands",
            ),
            "fap-duotone": FileSystemIconLoader(
              "PATH_TO/node_modules/@fortawesome/fontawesome-pro/svgs/duotone",
            ),
            "fap-regular": FileSystemIconLoader(
              "PATH_TO/node_modules/@fortawesome/fontawesome-pro/svgs/regular",
            ),
            "fap-solid": FileSystemIconLoader(
              "PATH_TO/node_modules/@fortawesome/fontawesome-pro/svgs/solid",
            ),
            "fap-light": FileSystemIconLoader(
              "PATH_TO/node_modules/@fortawesome/fontawesome-pro/svgs/light",
            ),
          },
        }),
      ],
    });

    Then import icons by placing this in your react/solid code: <IconFapSolidEnveleope />.

  13. jceb commented on Oct 8, 2021

    @jceb
    Contributor

    Actually, the above mentioned approach has one big disadvantage: the fontawesome icons don't come with the SVG attribute fill="currentColor" so the color can't be changed.

    In order to make it work one has to build the icons first with a build script that's described here: iconify/iconify#4 (comment)

    However, the compiled json files can be loaded directly into unplugin-icons because the loader (https://github.com/antfu/unplugin-icons/blob/e0cb01043b6eb462f4ea42b9b054382874495285/src/core/modern.ts#L51) is hard-coded receive only icons that are part of @iconify/json (https://github.com/antfu/unplugin-icons/blob/e0cb01043b6eb462f4ea42b9b054382874495285/src/core/loader.ts#L74). The customCollections attribute doesn't accept the JSON data structure that @iconify uses, instead it directly expects SVGs.

    To make it work, I created a custom loader function that uses the same code as searchForIcon. Here's the whole code in vite.config.js:

    import { defineConfig } from "vite";
    import solid from "solid-start";
    import Icons from "unplugin-icons/vite";
    import IconsResolver from "unplugin-icons/resolver";
    import AutoImport from "unplugin-auto-import/vite";
    import _fab from "./json/fab.json";
    import _fad from "./json/fad.json";
    import _fal from "./json/fal.json";
    import _far from "./json/far.json";
    import _fas from "./json/fas.json";
    import { iconToSVG } from "@iconify/utils/lib/svg/build";
    import { getIconData } from "@iconify/utils/lib/icon-set/get-icon";
    import { defaults as DefaultIconCustomizations } from "@iconify/utils/lib/customisations";
    
    const getIcon = (iconSet) => (iconName) => {
      const iconData = getIconData(iconSet, iconName, true);
      if (iconData) {
        const scale = 1;
        const { attributes, body } = iconToSVG(iconData, {
          ...DefaultIconCustomizations,
          height: `${scale}em`,
          width: `${scale}em`,
        });
        return `<svg ${Object.entries(attributes)
          .map((i) => `${i[0]}="${i[1]}"`)
          .join(" ")}>${body}</svg>`;
      }
    };
    
    const fab = getIcon(_fab);
    const fad = getIcon(_fad);
    const fal = getIcon(_fal);
    const far = getIcon(_far);
    const fas = getIcon(_fas);
    
    
    export default defineConfig({
      plugins: [
        solid(),
        AutoImport({
          resolvers: [
            IconsResolver({
              prefix: "Icon",
              extension: "jsx",
              customCollections: [
                "fap-brands",
                "fap-duotone",
                "fap-light",
                "fap-regular",
                "fap-solid",
              ],
            }),
          ],
        }),
    
        Icons({
          compiler: "solid",
          customCollections: {
            "fap-brands": fab,
            "fap-duotone": fad,
            "fap-light": fal,
            "fap-regular": far,
            "fap-solid": fas,
          },
        }),
      ],
    });
  14. antfu commented on Oct 8, 2021

    @antfu
    Member

    @jceb thanks for the update! If you see a way to make it general, I am happy to have a PR to include this loader into the plugin directly.

  15. jceb commented on Oct 8, 2021

    @jceb
    Contributor

    @antfu I created an issue and would appreciate your input on the "unplugin-icons" way of doing things.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requesthelp wantedExtra attention is needed

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions