christopherafbjur / sanity-plugin-icon-picker

MIT License
30 stars 25 forks source link

Consuming the icon in a React app #18

Closed FluidSense closed 3 years ago

FluidSense commented 3 years ago

Hello! Thanks for this great plugin, it looks really nice so far in the studio. I was just wondering how one would go ahead by converting the received data to an icon component in e.g. React?

I saw a reference to icon.component in the source code, but I cannot find anything like that in the retrieved data from Sanity. Is that unrelated or have I misconfigured something and should have access to icon.component?

christopherafbjur commented 3 years ago

Hello @FluidSense. Thank you, glad you like it so far!

It's up to you really. There's no method for rendering an icon outside of a Sanity studio. It was previously discussed to implement such a method here but I decided that it's not the responsibility of this plugin to render icons in external React projects. How ever there is a helper function available to render icons as preview media inside a Sanity Studio example here.

With all that said, if your retrieved data from Sanity look like this:

image

Then you could create a dynamic icon generator in your external React project like so:

import * as Icons from "react-icons/fa";

const DynamicFontAwesomeIcon = ({ name }) => Icons[name];

export default function App() {
  const sanityData = {
    _type: "iconPicker",
    name: "FaBeer",
    provider: "fa",
    _updatedAt: "2021-07-25T02:30:43.141Z"
  };
  const Icon = DynamicFontAwesomeIcon(sanityData);
  return (
    <div className="App">
      <Icon />
    </div>
  );
}

Note that in this example I'm using the option outputFormat: 'react' for the icon picker in the studio which will return data with the same naming convention as react-icons. The name key can then be used to render the correct icon. The provider key could also be used to implement logic for knowing which icon provider to use (using only fa aka FontAwesome in the example above).

FluidSense commented 3 years ago

Thanks for the quick answer! I'll go ahead and implement a component similar to the one in your example, and include different providers!

surjithctly commented 2 years ago

Quick question: if I used the above methods, for example for all three libraries, and user ends up using 2-3 icons, does that increase the file size drastically? or only the imported item will be loaded?

If yes, I would prefer a raw svg along with the data so that i can just render the SVG myself.

{
    _type: "iconPicker",
    name: "FaBeer",
    provider: "fa",
    svg: "<svg stroke="currentColor">..//content..</svg>"
  };
ovsw commented 2 years ago

Quick question: if I used the above methods, for example for all three libraries, and user ends up using 2-3 icons, does that increase the file size drastically? or only the imported item will be loaded?

@surjithctly

It imports the whole module and destroys performance. My Lighthouse score plummeted, mainly because of the time to interactive increasing to 9 seconds, on localhost... I see this "solution" given all the time but it only makes sense for SPAs where you don't care about loading speed that much (at least not for SEO's sake).

I agree that the best way would be to just provide the SVG code from sanity (or, if anyone else has a better idea...)

surjithctly commented 2 years ago

@ovsw Yeah, providing it as raw svg or as svg image would save a lot of bundle size for sure.

christopherafbjur commented 1 year ago

Thanks for the feedback @surjithctly @ovsw. Created a draft PR for this just now, feel free to share your thoughts there #39