From 30fad5765cc5299bc4971e58a2c2fe5bc94e68ac Mon Sep 17 00:00:00 2001 From: Arghya Das Date: Tue, 24 Dec 2024 16:28:23 +0530 Subject: [PATCH] feat: adding image props in icon-cloud (#463) --- __registry__/index.tsx | 13 +++++++ content/docs/components/icon-cloud.mdx | 7 +++- public/r/styles/default/icon-cloud.json | 2 +- .../default/example/icon-cloud-demo-2.tsx | 20 ++++++++++ registry/default/magicui/icon-cloud.tsx | 39 +++++++++++++++---- registry/registry-examples.ts | 6 +++ 6 files changed, 76 insertions(+), 11 deletions(-) create mode 100644 registry/default/example/icon-cloud-demo-2.tsx diff --git a/__registry__/index.tsx b/__registry__/index.tsx index 361feaf35..5b9ac703c 100644 --- a/__registry__/index.tsx +++ b/__registry__/index.tsx @@ -1609,6 +1609,19 @@ export const Index: Record = { 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", diff --git a/content/docs/components/icon-cloud.mdx b/content/docs/components/icon-cloud.mdx index 1d9048f2d..136e2b8dc 100644 --- a/content/docs/components/icon-cloud.mdx +++ b/content/docs/components/icon-cloud.mdx @@ -38,14 +38,16 @@ npm install react-icon-cloud next-themes -Update the import paths to match your project setup. - +## With Images + + + ## ⚠️ 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. @@ -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 diff --git a/public/r/styles/default/icon-cloud.json b/public/r/styles/default/icon-cloud.json index 9738277b4..e1e7a58ed 100644 --- a/public/r/styles/default/icon-cloud.json +++ b/public/r/styles/default/icon-cloud.json @@ -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 = {\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>;\n\nexport default function IconCloud({ iconSlugs }: DynamicCloudProps) {\n const [data, setData] = useState(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 \n <>{renderedIcons}\n \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 = {\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>;\n\nexport default function IconCloud({\n iconSlugs = [], // Default to an empty array if not provided\n imageArray,\n}: DynamicCloudProps) {\n const [data, setData] = useState(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 \n <>\n <>{renderedIcons}\n {imageArray &&\n imageArray.length > 0 &&\n imageArray.map((image, index) => {\n return (\n e.preventDefault()}>\n \"A\n \n );\n })}\n \n \n );\n}\n", "type": "registry:ui", "target": "" } diff --git a/registry/default/example/icon-cloud-demo-2.tsx b/registry/default/example/icon-cloud-demo-2.tsx new file mode 100644 index 000000000..1f28618ac --- /dev/null +++ b/registry/default/example/icon-cloud-demo-2.tsx @@ -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 ( +
+ +
+ ); +} diff --git a/registry/default/magicui/icon-cloud.tsx b/registry/default/magicui/icon-cloud.tsx index 3161ce069..6aba68ac8 100644 --- a/registry/default/magicui/icon-cloud.tsx +++ b/registry/default/magicui/icon-cloud.tsx @@ -1,3 +1,4 @@ +/* eslint-disable @next/next/no-img-element */ "use client"; import { useEffect, useMemo, useState } from "react"; @@ -10,6 +11,11 @@ import { SimpleIcon, } from "react-icon-cloud"; +export type DynamicCloudProps = { + iconSlugs?: string[]; // Made iconSlugs optional + imageArray?: string[]; +}; + export const cloudProps: Omit = { containerProps: { style: { @@ -37,7 +43,11 @@ export const cloudProps: Omit = { }, }; -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; @@ -57,18 +67,20 @@ export const renderCustomIcon = (icon: SimpleIcon, theme: string) => { }); }; -export type DynamicCloudProps = { - iconSlugs: string[]; -}; - type IconData = Awaited>; -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(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(() => { @@ -82,7 +94,18 @@ export default function IconCloud({ iconSlugs }: DynamicCloudProps) { return ( // @ts-ignore - <>{renderedIcons} + <> + <>{renderedIcons} + {imageArray && + imageArray.length > 0 && + imageArray.map((image, index) => { + return ( + e.preventDefault()}> + A globe + + ); + })} + ); } diff --git a/registry/registry-examples.ts b/registry/registry-examples.ts index 94ae8ded3..df688a84a 100644 --- a/registry/registry-examples.ts +++ b/registry/registry-examples.ts @@ -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",