Skip to content

Commit

Permalink
feat: adding image props in icon-cloud (#463)
Browse files Browse the repository at this point in the history
  • Loading branch information
itsarghyadas authored Dec 24, 2024
1 parent bf698d9 commit 30fad57
Show file tree
Hide file tree
Showing 6 changed files with 76 additions and 11 deletions.
13 changes: 13 additions & 0 deletions __registry__/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1609,6 +1609,19 @@ export const Index: Record<string, any> = {
subcategory: "undefined",
chunks: [],
},
"icon-cloud-demo-2": {
name: "icon-cloud-demo-2",
type: "registry:example",
registryDependencies: ["icon-cloud"],
files: ["registry/default/example/icon-cloud-demo-2.tsx"],
component: React.lazy(
() => import("@/registry/default/example/icon-cloud-demo-2.tsx"),
),
source: "",
category: "undefined",
subcategory: "undefined",
chunks: [],
},
"gradual-spacing-demo": {
name: "gradual-spacing-demo",
type: "registry:example",
Expand Down
7 changes: 5 additions & 2 deletions content/docs/components/icon-cloud.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,16 @@ npm install react-icon-cloud next-themes

<ComponentSource name="icon-cloud" />

<Step>Update the import paths to match your project setup.</Step>

</Steps>

</TabsContent>

</Tabs>

## With Images

<ComponentPreview name="icon-cloud-demo-2" />

## ⚠️ Warning

> Avoid using the IconCloud component in parent components where the component interacts with hooks or undergoes frequent state changes. Such interactions may lead to unexpected behavior, such as continuous spinning.
Expand All @@ -58,6 +60,7 @@ npm install react-icon-cloud next-themes
Displays a dynamic cloud of icons from the Simple Icons library based on provided slugs.
| Prop | type | default | description |
|:----------------:|:-----------------------------------------------:|:---------:|:--------------------------------------------------------------------------------------------------------------------------------------------------------------:|
| imageArray | string[] | | An array of image URLs corresponding to the images you want to display. |
| iconSlugs | string[] | |An array of icon slugs corresponding to the icons you want to display. Each slug should match a supported icon from the Simple Icons library. |

### Cloud
Expand Down
2 changes: 1 addition & 1 deletion public/r/styles/default/icon-cloud.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"files": [
{
"path": "magicui/icon-cloud.tsx",
"content": "\"use client\";\n\nimport { useEffect, useMemo, useState } from \"react\";\nimport { useTheme } from \"next-themes\";\nimport {\n Cloud,\n fetchSimpleIcons,\n ICloud,\n renderSimpleIcon,\n SimpleIcon,\n} from \"react-icon-cloud\";\n\nexport const cloudProps: Omit<ICloud, \"children\"> = {\n containerProps: {\n style: {\n display: \"flex\",\n justifyContent: \"center\",\n alignItems: \"center\",\n width: \"100%\",\n paddingTop: 40,\n },\n },\n options: {\n reverse: true,\n depth: 1,\n wheelZoom: false,\n imageScale: 2,\n activeCursor: \"default\",\n tooltip: \"native\",\n initial: [0.1, -0.1],\n clickToFront: 500,\n tooltipDelay: 0,\n outlineColour: \"#0000\",\n maxSpeed: 0.04,\n minSpeed: 0.02,\n // dragControl: false,\n },\n};\n\nexport const renderCustomIcon = (icon: SimpleIcon, theme: string) => {\n const bgHex = theme === \"light\" ? \"#f3f2ef\" : \"#080510\";\n const fallbackHex = theme === \"light\" ? \"#6e6e73\" : \"#ffffff\";\n const minContrastRatio = theme === \"dark\" ? 2 : 1.2;\n\n return renderSimpleIcon({\n icon,\n bgHex,\n fallbackHex,\n minContrastRatio,\n size: 42,\n aProps: {\n href: undefined,\n target: undefined,\n rel: undefined,\n onClick: (e: any) => e.preventDefault(),\n },\n });\n};\n\nexport type DynamicCloudProps = {\n iconSlugs: string[];\n};\n\ntype IconData = Awaited<ReturnType<typeof fetchSimpleIcons>>;\n\nexport default function IconCloud({ iconSlugs }: DynamicCloudProps) {\n const [data, setData] = useState<IconData | null>(null);\n const { theme } = useTheme();\n\n useEffect(() => {\n fetchSimpleIcons({ slugs: iconSlugs }).then(setData);\n }, [iconSlugs]);\n\n const renderedIcons = useMemo(() => {\n if (!data) return null;\n\n return Object.values(data.simpleIcons).map((icon) =>\n renderCustomIcon(icon, theme || \"light\"),\n );\n }, [data, theme]);\n\n return (\n // @ts-ignore\n <Cloud {...cloudProps}>\n <>{renderedIcons}</>\n </Cloud>\n );\n}\n",
"content": "\"use client\";\n\nimport { useEffect, useMemo, useState } from \"react\";\nimport { useTheme } from \"next-themes\";\nimport {\n Cloud,\n fetchSimpleIcons,\n ICloud,\n renderSimpleIcon,\n SimpleIcon,\n} from \"react-icon-cloud\";\n\nexport type DynamicCloudProps = {\n iconSlugs?: string[]; // Made iconSlugs optional\n imageArray?: string[];\n};\n\nexport const cloudProps: Omit<ICloud, \"children\"> = {\n containerProps: {\n style: {\n display: \"flex\",\n justifyContent: \"center\",\n alignItems: \"center\",\n width: \"100%\",\n paddingTop: 40,\n },\n },\n options: {\n reverse: true,\n depth: 1,\n wheelZoom: false,\n imageScale: 2,\n activeCursor: \"default\",\n tooltip: \"native\",\n initial: [0.1, -0.1],\n clickToFront: 500,\n tooltipDelay: 0,\n outlineColour: \"#0000\",\n maxSpeed: 0.04,\n minSpeed: 0.02,\n // dragControl: false,\n },\n};\n\nexport const renderCustomIcon = (\n icon: SimpleIcon,\n theme: string,\n imageArray?: string[],\n) => {\n const bgHex = theme === \"light\" ? \"#f3f2ef\" : \"#080510\";\n const fallbackHex = theme === \"light\" ? \"#6e6e73\" : \"#ffffff\";\n const minContrastRatio = theme === \"dark\" ? 2 : 1.2;\n\n return renderSimpleIcon({\n icon,\n bgHex,\n fallbackHex,\n minContrastRatio,\n size: 42,\n aProps: {\n href: undefined,\n target: undefined,\n rel: undefined,\n onClick: (e: any) => e.preventDefault(),\n },\n });\n};\n\ntype IconData = Awaited<ReturnType<typeof fetchSimpleIcons>>;\n\nexport default function IconCloud({\n iconSlugs = [], // Default to an empty array if not provided\n imageArray,\n}: DynamicCloudProps) {\n const [data, setData] = useState<IconData | null>(null);\n const { theme } = useTheme();\n\n useEffect(() => {\n if (iconSlugs.length > 0) {\n // Check if iconSlugs is not empty\n fetchSimpleIcons({ slugs: iconSlugs }).then(setData);\n }\n }, [iconSlugs]);\n\n const renderedIcons = useMemo(() => {\n if (!data) return null;\n\n return Object.values(data.simpleIcons).map((icon) =>\n renderCustomIcon(icon, theme || \"light\"),\n );\n }, [data, theme]);\n\n return (\n // @ts-ignore\n <Cloud {...cloudProps}>\n <>\n <>{renderedIcons}</>\n {imageArray &&\n imageArray.length > 0 &&\n imageArray.map((image, index) => {\n return (\n <a key={index} href=\"#\" onClick={(e) => e.preventDefault()}>\n <img height=\"42\" width=\"42\" alt=\"A globe\" src={image} />\n </a>\n );\n })}\n </>\n </Cloud>\n );\n}\n",
"type": "registry:ui",
"target": ""
}
Expand Down
20 changes: 20 additions & 0 deletions registry/default/example/icon-cloud-demo-2.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import IconCloud from "@/registry/default/magicui/icon-cloud";

const images = [
"https://images.unsplash.com/photo-1720048171230-c60d162f93a0?q=80&w=1974&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDF8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
"https://plus.unsplash.com/premium_photo-1675553988173-a5249b5815fe?q=80&w=1964&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
"https://plus.unsplash.com/premium_photo-1675297844586-534b030564e0?q=80&w=1964&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
"https://plus.unsplash.com/premium_photo-1675555581018-7f1a352ff9a6?q=80&w=1964&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
"https://images.unsplash.com/photo-1719937050517-68d4e2a1702e?q=80&w=1974&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
"https://images.unsplash.com/photo-1719937050517-68d4e2a1702e?q=80&w=1974&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
"https://plus.unsplash.com/premium_photo-1674747904717-fec17671e235?q=80&w=1964&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
"https://images.unsplash.com/photo-1719937050517-68d4e2a1702e?q=80&w=1974&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
];

export default function IconCloudDemo() {
return (
<div className="relative flex size-full max-w-lg items-center justify-center overflow-hidden rounded-lg border bg-background px-20 pb-20 pt-8 ">
<IconCloud imageArray={images} />
</div>
);
}
39 changes: 31 additions & 8 deletions registry/default/magicui/icon-cloud.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable @next/next/no-img-element */
"use client";

import { useEffect, useMemo, useState } from "react";
Expand All @@ -10,6 +11,11 @@ import {
SimpleIcon,
} from "react-icon-cloud";

export type DynamicCloudProps = {
iconSlugs?: string[]; // Made iconSlugs optional
imageArray?: string[];
};

export const cloudProps: Omit<ICloud, "children"> = {
containerProps: {
style: {
Expand Down Expand Up @@ -37,7 +43,11 @@ export const cloudProps: Omit<ICloud, "children"> = {
},
};

export const renderCustomIcon = (icon: SimpleIcon, theme: string) => {
export const renderCustomIcon = (
icon: SimpleIcon,
theme: string,
imageArray?: string[],
) => {
const bgHex = theme === "light" ? "#f3f2ef" : "#080510";
const fallbackHex = theme === "light" ? "#6e6e73" : "#ffffff";
const minContrastRatio = theme === "dark" ? 2 : 1.2;
Expand All @@ -57,18 +67,20 @@ export const renderCustomIcon = (icon: SimpleIcon, theme: string) => {
});
};

export type DynamicCloudProps = {
iconSlugs: string[];
};

type IconData = Awaited<ReturnType<typeof fetchSimpleIcons>>;

export default function IconCloud({ iconSlugs }: DynamicCloudProps) {
export default function IconCloud({
iconSlugs = [], // Default to an empty array if not provided
imageArray,
}: DynamicCloudProps) {
const [data, setData] = useState<IconData | null>(null);
const { theme } = useTheme();

useEffect(() => {
fetchSimpleIcons({ slugs: iconSlugs }).then(setData);
if (iconSlugs.length > 0) {
// Check if iconSlugs is not empty
fetchSimpleIcons({ slugs: iconSlugs }).then(setData);
}
}, [iconSlugs]);

const renderedIcons = useMemo(() => {
Expand All @@ -82,7 +94,18 @@ export default function IconCloud({ iconSlugs }: DynamicCloudProps) {
return (
// @ts-ignore
<Cloud {...cloudProps}>
<>{renderedIcons}</>
<>
<>{renderedIcons}</>
{imageArray &&
imageArray.length > 0 &&
imageArray.map((image, index) => {
return (
<a key={index} href="#" onClick={(e) => e.preventDefault()}>
<img height="42" width="42" alt="A globe" src={image} />
</a>
);
})}
</>
</Cloud>
);
}
6 changes: 6 additions & 0 deletions registry/registry-examples.ts
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,12 @@ export const examples: Registry = [
registryDependencies: ["icon-cloud"],
files: ["example/icon-cloud-demo.tsx"],
},
{
name: "icon-cloud-demo-2",
type: "registry:example",
registryDependencies: ["icon-cloud"],
files: ["example/icon-cloud-demo-2.tsx"],
},
{
name: "gradual-spacing-demo",
type: "registry:example",
Expand Down

0 comments on commit 30fad57

Please sign in to comment.