Skip to content

Commit

Permalink
feat:Interactive-Icon-Cloud (magicuidesign#43)
Browse files Browse the repository at this point in the history
* feat:Interactive-Icon-Cloud

* fix:minor-fix

* fix: small fixes

---------

Co-authored-by: Dillion Verma <hello@dillion.io>
  • Loading branch information
prakashsp23 and dillionverma authored May 24, 2024
1 parent 43efa51 commit 680ece5
Show file tree
Hide file tree
Showing 7 changed files with 231 additions and 5 deletions.
6 changes: 6 additions & 0 deletions config/docs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,12 @@ export const docsConfig: DocsConfig = {
items: [],
label: "New",
},
{
title: "Interactive Icon Cloud",
href: `/docs/components/icon-cloud`,
items: [],
label: "New",
},
],
},
{
Expand Down
58 changes: 58 additions & 0 deletions content/docs/components/icon-cloud.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
---
title: Interactive Icon Cloud
date: 2024-05-24
description: An interactive 3D tag cloud component
author: dillionverma
published: true
---

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

<Steps>

### Installation

Copy and paste the following code into your project.

```bash
npm i react-icon-cloud
```

```text
components/magicui/icon-cloud.tsx
```

<ComponentSource name="icon-cloud" />

</Steps>

## Props

## Cloud
| Prop | type | default | description |
|:--------------:|:-------------------------------------------------:|:-------:|:---------------------------------------------------------------:|
| canvasProps | HTMLAttributes < HTMLCanvasElement > \| undefined | {} | Attributes that will be passed to the underlying canvas element |
| children | Tag[] | [] | Tags rendered using the provided renderers |
| containerProps | HTMLAttributes < HTMLDivElement > \| undefined | {} | Attributes passed to the root div element |
| id | string \| number \| undefined | uuid | Should be provided when using SSR |
| options | IOptions \| undefined | {} | https://www.goat1000.com/tagcanvas-options.php |
| maxSpeed | int | 0.04 | To adjust the rotation speed in idle state |
| minSpeed | int | 0.02 | To adjust the rotation speed when hovering |

## renderSimpleIcon
Used to create a tag for the Cloud component
| Prop | type | default | description |
|:----------------:|:-----------------------------------------------:|:---------:|:--------------------------------------------------------------------------------------------------------------------------------------------------------------:|
| aProps | HTMLAttributes < HTMLAnchorElement > \| undefined | {} | Attributes passed to the underlying anchor element |
| bgHex | string \| undefined | '#fff' | The string hex of the background the icon will be rendered on. Ex: '#fff'. Used to determine if the min contrast ratio for the icons default color will be met |
| fallbackHex | string \| undefined | '#000' | The color of the icon if the minContrastRatio is not met Ex: '#000' |
| icon | any | undefined | The simple icon object you would like to render. Ex: import icon from "simple-icons/icons/javascript";
| imgProps | HTMLAttributes < HTMLImageElement > \| undefined | {} | Attributes passed to the underlying img element | |
| minContrastRatio | number \| undefined | 1 | 0 - 21 The min contrast ratio between icon and bgHex before the fallbackHex will be used for the icon color |
| size | number \| undefined | 42 | The size in px of the icon |

## fetchSimpleIcons
Used when you cant statically import simple icons during built time. Calling this will use `fetch` to get icons for each provided slug.
| Prop | type | default | description |
|:----------------:|:-----------------------------------------------:|:---------:|:--------------------------------------------------------------------------------------------------------------------------------------------------------------:|
| slugs | string[] | | Slugs to fetch svgs and colors for. The return icons may be passed to renderSimpleIcon |
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@
"react-dom": "18.2.0",
"react-email": "1.9.4",
"react-hook-form": "^7.45.0",
"react-icon-cloud": "^4.1.4",
"react-spring": "^9.7.3",
"react-tweet": "^3.1.1",
"react-wrap-balancer": "^1.0.0",
Expand Down
28 changes: 24 additions & 4 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

42 changes: 42 additions & 0 deletions registry/components/example/icon-cloud-demo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import IconCloud from "@/registry/components/magicui/icon-cloud";

const slugs = [
"typescript",
"javascript",
"dart",
"java",
"react",
"flutter",
"android",
"html5",
"css3",
"nodedotjs",
"express",
"nextdotjs",
"prisma",
"amazonaws",
"postgresql",
"firebase",
"nginx",
"vercel",
"testinglibrary",
"jest",
"cypress",
"docker",
"git",
"jira",
"github",
"gitlab",
"visualstudiocode",
"androidstudio",
"sonarqube",
"figma",
];

export default function IconCloudDemo() {
return (
<div className="relative flex h-full w-full max-w-[32rem] items-center justify-center overflow-hidden rounded-lg border bg-background px-20 pb-20 pt-8 ">
<IconCloud iconSlugs={slugs} />
</div>
);
}
87 changes: 87 additions & 0 deletions registry/components/magicui/icon-cloud.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
"use client";

import { useTheme } from "next-themes";
import { useEffect, useMemo, useState } from "react";
import {
Cloud,
fetchSimpleIcons,
ICloud,
renderSimpleIcon,
SimpleIcon,
} from "react-icon-cloud";

export const cloudProps: Omit<ICloud, "children"> = {
containerProps: {
style: {
display: "flex",
justifyContent: "center",
alignItems: "center",
width: "100%",
paddingTop: 40,
},
},
options: {
reverse: true,
depth: 1,
wheelZoom: false,
imageScale: 2,
activeCursor: "default",
tooltip: "native",
initial: [0.1, -0.1],
clickToFront: 500,
tooltipDelay: 0,
outlineColour: "#0000",
maxSpeed: 0.04,
minSpeed: 0.02,
},
};

export const renderCustomIcon = (icon: SimpleIcon, theme: string) => {
const bgHex = theme === "light" ? "#f3f2ef" : "#080510";
const fallbackHex = theme === "light" ? "#6e6e73" : "#ffffff";
const minContrastRatio = theme === "dark" ? 2 : 1.2;

return renderSimpleIcon({
icon,
bgHex,
fallbackHex,
minContrastRatio,
size: 42,
aProps: {
href: undefined,
target: undefined,
rel: undefined,
onClick: (e: any) => e.preventDefault(),
},
});
};

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

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

export default function IconCloud({ iconSlugs }: DynamicCloudProps) {
const [data, setData] = useState<IconData | null>(null);
const { theme } = useTheme();

useEffect(() => {
fetchSimpleIcons({ slugs: iconSlugs }).then(setData);
}, [iconSlugs]);

const renderedIcons = useMemo(() => {
if (!data) return null;

return Object.values(data.simpleIcons).map((icon) =>
renderCustomIcon(icon, theme || "light"),
);
}, [data, theme]);

return (
// @ts-ignore
<Cloud {...cloudProps}>
<>{renderedIcons}</>
</Cloud>
);
}
14 changes: 13 additions & 1 deletion registry/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,11 @@ const ui: Registry = {
type: "components:ui",
files: ["registry/components/magicui/flip-text.tsx"],
},
"icon-cloud": {
name: "icon-cloud",
type: "components:ui",
files: ["registry/components/magicui/icon-cloud.tsx"],
},
};

const example: Registry = {
Expand Down Expand Up @@ -677,8 +682,15 @@ const example: Registry = {
() => import("@/registry/components/example/flip-text-demo"),
),
},
"icon-cloud-demo": {
name: "icon-cloud-demo",
type: "components:example",
files: ["registry/components/example/icon-cloud-demo.tsx"],
component: React.lazy(
() => import("@/registry/components/example/icon-cloud-demo"),
),
},
};

export const registry: Registry = {
...ui,
...example,
Expand Down

0 comments on commit 680ece5

Please sign in to comment.