-
Notifications
You must be signed in to change notification settings - Fork 155
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix: add tools hover interaction icon component (#357)
- Loading branch information
1 parent
f0323f5
commit 20b049d
Showing
3 changed files
with
204 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import HoverInteraction from "@/animata/icon/hover-interaction"; | ||
import { Meta, StoryObj } from "@storybook/react"; | ||
|
||
const meta = { | ||
title: "Icon/Hover Interaction", | ||
component: HoverInteraction, | ||
parameters: { | ||
layout: "centered", | ||
}, | ||
tags: ["autodocs"], | ||
argTypes: {}, | ||
} satisfies Meta<typeof HoverInteraction>; | ||
|
||
export default meta; | ||
type Story = StoryObj<typeof meta>; | ||
|
||
export const Primary: Story = { | ||
args: { | ||
title: "instagram", | ||
size: "4", | ||
}, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
"use client"; | ||
|
||
import React, { ElementType, useState } from "react"; | ||
import { AnimatePresence, motion } from "framer-motion"; | ||
|
||
// default imports | ||
import { | ||
FigmaLogoIcon, | ||
FramerLogoIcon, | ||
GitHubLogoIcon, | ||
InstagramLogoIcon, | ||
LinkedInLogoIcon, | ||
SquareIcon, | ||
TwitterLogoIcon, | ||
} from "@radix-ui/react-icons"; | ||
|
||
type IconSize = "1" | "2" | "3" | "4"; // source: https://www.radix-ui.com/themes/docs/components/icon-button | ||
|
||
interface IconHoverProps { | ||
title: string; // default is Square | ||
size?: IconSize; // default is 4 | ||
} | ||
|
||
const sizeClasses: Record<IconSize, string> = { | ||
"1": "w-6 h-6", | ||
"2": "w-7 h-7", | ||
"3": "w-8 h-8", | ||
"4": "w-10 h-10", | ||
}; | ||
|
||
const textSizeClasses: Record<IconSize, string> = { | ||
"1": "text-sm", | ||
"2": "text-base", | ||
"3": "text-lg", | ||
"4": "text-xl", | ||
}; | ||
|
||
const getIconForTitle = (title: string) => { | ||
const lowercaseTitle = title.toLowerCase().trim(); | ||
const iconMap: { [key: string]: ElementType } = { | ||
framer: FramerLogoIcon, | ||
"twitter/x": TwitterLogoIcon, | ||
instagram: InstagramLogoIcon, | ||
linkedin: LinkedInLogoIcon, | ||
github: GitHubLogoIcon, | ||
figma: FigmaLogoIcon | ||
}; | ||
|
||
// SquareIcon as default | ||
return (iconMap[lowercaseTitle] as ElementType) || SquareIcon; | ||
}; | ||
|
||
// twitter -> Twitter, Twitter -> Twitter, twitter/x -> Twitter/X, Twitter/x -> Twitter/X | ||
const capitalizeWithSlash = (str: string) => { | ||
return str | ||
.split("/") | ||
.map((part) => part.charAt(0).toUpperCase() + part.slice(1).toLowerCase()) | ||
.join("/"); | ||
}; | ||
|
||
export default function HoverInteraction({ | ||
// default values | ||
title = "Square", | ||
size = "4", | ||
}: IconHoverProps) { | ||
const [isHovered, setIsHovered] = useState(false); | ||
const DynamicIcon = getIconForTitle(title); | ||
|
||
const sizeClass = sizeClasses[size]; | ||
const textSizeClass = textSizeClasses[size]; | ||
|
||
const formattedTitle = capitalizeWithSlash(title); | ||
|
||
const logoVariants = { | ||
hidden: { | ||
opacity: 0, | ||
y: 0, | ||
scale: 0.5, | ||
rotate: 100, | ||
}, | ||
visible: { | ||
opacity: 1, | ||
y: 13, | ||
scale: 1, | ||
rotate: 0, | ||
transition: { | ||
type: "spring", | ||
stiffness: 100, | ||
damping: 15, | ||
duration: 0.3, | ||
}, | ||
}, | ||
exit: { | ||
opacity: 0, | ||
y: 13, | ||
scale: 0.5, | ||
rotate: 100, | ||
transition: { duration: 0.3 }, | ||
}, | ||
}; | ||
|
||
return ( | ||
<motion.div | ||
className="storybook-fix group relative flex min-h-[120px] w-full cursor-pointer items-center justify-center" | ||
onMouseEnter={() => setIsHovered(true)} | ||
onMouseLeave={() => setIsHovered(false)} | ||
> | ||
<span | ||
className={`relative text-center font-medium text-muted-foreground transition-colors duration-200 group-hover:text-black ${textSizeClass}`} | ||
> | ||
{formattedTitle} | ||
</span> | ||
<AnimatePresence> | ||
{isHovered && ( | ||
<motion.div | ||
className="absolute bottom-full left-1/2" | ||
variants={logoVariants} | ||
initial="hidden" | ||
animate="visible" | ||
exit="exit" | ||
style={{ | ||
x: "-50%", | ||
originX: 0.5, | ||
originY: 1, | ||
}} | ||
> | ||
<DynamicIcon className={sizeClass} /> | ||
</motion.div> | ||
)} | ||
</AnimatePresence> | ||
</motion.div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
--- | ||
title: Hover Interaction | ||
description: This is a component which shows icon based on text hovered by user. By default it has alreay imported Twitter/x, Framer, Figma, Instagram, GitHub, LinkedIn, and it shows Square-Box icon by default it user tries to get other icons without importing. Importing steps are provided below. | ||
author: MEbandhan | ||
--- | ||
|
||
<ComponentPreview name="icon-hover-interaction--docs" /> | ||
|
||
## Installation | ||
|
||
<Steps> | ||
<Step>Install dependencies</Step> | ||
|
||
```bash | ||
npm install framer-motion @radix-ui/react-icons | ||
``` | ||
|
||
<Step>Run the following command</Step> | ||
|
||
It will create a new file `hover-interaction.tsx` inside the `components/animata/icon` directory. | ||
|
||
```bash | ||
mkdir -p components/animata/icon && touch components/animata/icon/hover-interaction.tsx | ||
``` | ||
|
||
<Step>Paste the code</Step> | ||
|
||
Open the newly created file and paste the following code: | ||
|
||
```jsx file=<rootDir>/animata/icon/hover-interaction.tsx | ||
|
||
``` | ||
|
||
</Steps> | ||
|
||
<Step>Use the component with default/non-default interacitons</Step> | ||
|
||
defaults are mentioned in the description | ||
|
||
**Other than defaults** | ||
|
||
1. Go to the [radix-ui icon page](https://www.radix-ui.com/icons) | ||
2. Search for the icon. | ||
3. Import the icon in the copied code. If the icon name is Twitter Logo, the import will be TwitterLogoIcon | ||
4. Add switch case for that logo in **lower case**. | ||
|
||
## Credits | ||
|
||
Built by [Bandhan Majumder](https://github.com/bandhan-majumder) |