Create tooltip component (#77)
This commit is contained in:
parent
bd27dc085c
commit
e6bb39e3b3
10 changed files with 154 additions and 22 deletions
51
package-lock.json
generated
51
package-lock.json
generated
|
|
@ -10,6 +10,7 @@
|
|||
"dependencies": {
|
||||
"@astrojs/image": "0.11.4",
|
||||
"@iconify-icon/react": "1.0.1",
|
||||
"@tippyjs/react": "4.2.6",
|
||||
"clsx": "1.2.1",
|
||||
"prettier-plugin-astro": "0.7.0",
|
||||
"react": "18.2.0",
|
||||
|
|
@ -898,6 +899,15 @@
|
|||
"integrity": "sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@popperjs/core": {
|
||||
"version": "2.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.6.tgz",
|
||||
"integrity": "sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw==",
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/popperjs"
|
||||
}
|
||||
},
|
||||
"node_modules/@proload/core": {
|
||||
"version": "0.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@proload/core/-/core-0.3.3.tgz",
|
||||
|
|
@ -920,6 +930,18 @@
|
|||
"@proload/core": "^0.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@tippyjs/react": {
|
||||
"version": "4.2.6",
|
||||
"resolved": "https://registry.npmjs.org/@tippyjs/react/-/react-4.2.6.tgz",
|
||||
"integrity": "sha512-91RicDR+H7oDSyPycI13q3b7o4O60wa2oRbjlz2fyRLmHImc4vyDwuUP8NtZaN0VARJY5hybvDYrFzhY9+Lbyw==",
|
||||
"dependencies": {
|
||||
"tippy.js": "^6.3.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=16.8",
|
||||
"react-dom": ">=16.8"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/acorn": {
|
||||
"version": "4.0.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/acorn/-/acorn-4.0.6.tgz",
|
||||
|
|
@ -9280,6 +9302,14 @@
|
|||
"globrex": "^0.1.2"
|
||||
}
|
||||
},
|
||||
"node_modules/tippy.js": {
|
||||
"version": "6.3.7",
|
||||
"resolved": "https://registry.npmjs.org/tippy.js/-/tippy.js-6.3.7.tgz",
|
||||
"integrity": "sha512-E1d3oP2emgJ9dRQZdf3Kkn0qJgI6ZLpyS5z6ZkY1DF3kaQaBsGZsndEpHwx+eC+tYM41HaSNvNtLx8tU57FzTQ==",
|
||||
"dependencies": {
|
||||
"@popperjs/core": "^2.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/to-fast-properties": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
|
||||
|
|
@ -11189,6 +11219,11 @@
|
|||
"integrity": "sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==",
|
||||
"dev": true
|
||||
},
|
||||
"@popperjs/core": {
|
||||
"version": "2.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.6.tgz",
|
||||
"integrity": "sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw=="
|
||||
},
|
||||
"@proload/core": {
|
||||
"version": "0.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@proload/core/-/core-0.3.3.tgz",
|
||||
|
|
@ -11208,6 +11243,14 @@
|
|||
"tsm": "^2.1.4"
|
||||
}
|
||||
},
|
||||
"@tippyjs/react": {
|
||||
"version": "4.2.6",
|
||||
"resolved": "https://registry.npmjs.org/@tippyjs/react/-/react-4.2.6.tgz",
|
||||
"integrity": "sha512-91RicDR+H7oDSyPycI13q3b7o4O60wa2oRbjlz2fyRLmHImc4vyDwuUP8NtZaN0VARJY5hybvDYrFzhY9+Lbyw==",
|
||||
"requires": {
|
||||
"tippy.js": "^6.3.1"
|
||||
}
|
||||
},
|
||||
"@types/acorn": {
|
||||
"version": "4.0.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/acorn/-/acorn-4.0.6.tgz",
|
||||
|
|
@ -17105,6 +17148,14 @@
|
|||
"globrex": "^0.1.2"
|
||||
}
|
||||
},
|
||||
"tippy.js": {
|
||||
"version": "6.3.7",
|
||||
"resolved": "https://registry.npmjs.org/tippy.js/-/tippy.js-6.3.7.tgz",
|
||||
"integrity": "sha512-E1d3oP2emgJ9dRQZdf3Kkn0qJgI6ZLpyS5z6ZkY1DF3kaQaBsGZsndEpHwx+eC+tYM41HaSNvNtLx8tU57FzTQ==",
|
||||
"requires": {
|
||||
"@popperjs/core": "^2.9.0"
|
||||
}
|
||||
},
|
||||
"to-fast-properties": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
"dependencies": {
|
||||
"@astrojs/image": "0.11.4",
|
||||
"@iconify-icon/react": "1.0.1",
|
||||
"@tippyjs/react": "4.2.6",
|
||||
"clsx": "1.2.1",
|
||||
"prettier-plugin-astro": "0.7.0",
|
||||
"react": "18.2.0",
|
||||
|
|
|
|||
15
src/components/atoms/icon-with-tooltip.tsx
Normal file
15
src/components/atoms/icon-with-tooltip.tsx
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
import type { IconProps } from './icon';
|
||||
import Icon from './icon';
|
||||
import Tooltip, { TooltipProps } from './tooltip';
|
||||
|
||||
type Props = IconProps & Omit<TooltipProps, 'children'>;
|
||||
|
||||
const IconWithTooltip = ({ name, color, size, ...tooltipProps }: Props) => (
|
||||
<Tooltip {...tooltipProps}>
|
||||
<div>
|
||||
<Icon name={name} color={color} size={size} />
|
||||
</div>
|
||||
</Tooltip>
|
||||
);
|
||||
|
||||
export default IconWithTooltip;
|
||||
|
|
@ -5,28 +5,32 @@ import type { Section } from '@/types/data';
|
|||
import type { IconName } from '@/types/icon';
|
||||
|
||||
import Icon from './icon';
|
||||
import Tooltip from './tooltip';
|
||||
|
||||
export interface Props {
|
||||
export interface SidebarItemProps {
|
||||
section: Section;
|
||||
icon: IconName;
|
||||
title?: string;
|
||||
}
|
||||
|
||||
const SidebarItem = ({ section, icon }: Props) => {
|
||||
const SidebarItem = ({ section, icon, title = '' }: SidebarItemProps) => {
|
||||
const { hash } = useLocation();
|
||||
const href = `#${section}`;
|
||||
|
||||
const active = hash === '' ? section === MAIN_SECTION : hash === href;
|
||||
|
||||
return (
|
||||
<a
|
||||
href={href}
|
||||
className={`inline-flex justify-center items-center h-10 w-10 rounded-lg transition
|
||||
<Tooltip content={`${title || section.charAt(0).toUpperCase() + section.slice(1)} section`} placement="left">
|
||||
<a
|
||||
href={href}
|
||||
className={`inline-flex justify-center items-center h-10 w-10 rounded-lg transition
|
||||
${active ? 'bg-primary-600 text-white' : 'bg-white text-gray-400 hover:bg-primary-600 hover:text-white'}
|
||||
`}
|
||||
aria-current={active ? 'page' : undefined}
|
||||
>
|
||||
<Icon name={icon} size={20} />
|
||||
</a>
|
||||
aria-current={active ? 'page' : undefined}
|
||||
>
|
||||
<Icon name={icon} size={20} />
|
||||
</a>
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
|||
25
src/components/atoms/tooltip.tsx
Normal file
25
src/components/atoms/tooltip.tsx
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
import Tippy, { TippyProps } from '@tippyjs/react/headless';
|
||||
import type { ReactElement } from 'react';
|
||||
|
||||
export interface TooltipProps {
|
||||
children: ReactElement;
|
||||
content: string;
|
||||
placement?: TippyProps['placement'];
|
||||
}
|
||||
|
||||
const Tooltip = ({ children, content, placement = 'top' }: TooltipProps) => {
|
||||
return (
|
||||
<Tippy
|
||||
render={(attrs) => (
|
||||
<div {...attrs} className="bg-gray-700 rounded-lg px-2 py-1.5 text-white max-w-[95%] sm:max-w-xs">
|
||||
{content}
|
||||
</div>
|
||||
)}
|
||||
placement={placement}
|
||||
>
|
||||
{children}
|
||||
</Tippy>
|
||||
);
|
||||
};
|
||||
|
||||
export default Tooltip;
|
||||
|
|
@ -1,26 +1,42 @@
|
|||
---
|
||||
import Icon from '@/atoms/icon';
|
||||
import IconWithTooltip from '@/atoms/icon-with-tooltip';
|
||||
import Typography from '@/atoms/typography.astro';
|
||||
import type { IconName } from '@/types/icon';
|
||||
import type { LevelledSkill } from '@/types/skills-section';
|
||||
|
||||
import SkillLevel from './skill-level.astro';
|
||||
|
||||
export interface Props extends LevelledSkill {}
|
||||
|
||||
const { url, icon, iconColor, name, level } = Astro.props;
|
||||
const { url, icon, iconColor, name, level, description } = Astro.props;
|
||||
|
||||
const IconWrapper = url ? 'a' : 'div';
|
||||
---
|
||||
|
||||
<div class:list={['flex', 'flex-col', 'gap-2']}>
|
||||
<IconWrapper
|
||||
class:list={['flex', 'gap-2', 'h-5']}
|
||||
{...(url && { href: url, target: "_blank", rel: "noopener noreferrer" })}
|
||||
>
|
||||
<Icon client:load name={icon} color={iconColor} size={20} />
|
||||
<Typography variant="tile-subtitle">
|
||||
<span class="text-gray-700">{name}</span>
|
||||
</Typography>
|
||||
</IconWrapper>
|
||||
<div class:list={['flex', 'items-center', 'justify-between', 'h-5']}>
|
||||
<IconWrapper
|
||||
class:list={['flex', 'gap-2', 'h-5']}
|
||||
{...(url && { href: url, target: "_blank", rel: "noopener noreferrer" })}
|
||||
>
|
||||
<Icon client:load name={icon} color={iconColor} size={20} />
|
||||
<Typography variant="tile-subtitle">
|
||||
<span class="text-gray-700">{name}</span>
|
||||
</Typography>
|
||||
</IconWrapper>
|
||||
{
|
||||
description && (
|
||||
<IconWithTooltip
|
||||
client:load
|
||||
name={'akar-icons:info-fill' as IconName}
|
||||
color="#D1D5DB"
|
||||
size={14}
|
||||
content={description}
|
||||
placement="top"
|
||||
/>
|
||||
)
|
||||
}
|
||||
</div>
|
||||
<SkillLevel skillLevel={level} />
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ const data: Data = {
|
|||
main: {
|
||||
config: {
|
||||
icon: 'fa6-solid:user',
|
||||
title: 'Profile',
|
||||
},
|
||||
image: import('@/assets/my-image.jpeg'),
|
||||
fullName: 'Mark Freeman',
|
||||
|
|
|
|||
|
|
@ -26,12 +26,21 @@ const { seo, ...dataWithoutSeo } = data;
|
|||
</head>
|
||||
<body class="flex justify-center bg-gray-50">
|
||||
<div class="flex relative transform-none gap-8 w-full max-w-5xl px-2 py-3 sm:px-8 sm:py-12 lg:py-20">
|
||||
<div class="absolute -right-2">
|
||||
<div class="absolute z-40 -right-2">
|
||||
<Sidebar className="hidden xl:flex fixed">
|
||||
{
|
||||
getObjectKeys(dataWithoutSeo).map((key) => {
|
||||
const sectionData = dataWithoutSeo[key];
|
||||
return sectionData && <SidebarItem client:only="react" icon={sectionData.config.icon} section={key} />;
|
||||
return (
|
||||
sectionData && (
|
||||
<SidebarItem
|
||||
client:load
|
||||
title={sectionData.config.title}
|
||||
icon={sectionData.config.icon}
|
||||
section={key}
|
||||
/>
|
||||
)
|
||||
);
|
||||
})
|
||||
}
|
||||
</Sidebar>
|
||||
|
|
|
|||
10
src/pages/playground/tooltip.astro
Normal file
10
src/pages/playground/tooltip.astro
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
---
|
||||
import SidebarItem from '@/atoms/sidebar-item';
|
||||
import Tooltip from '@/atoms/tooltip';
|
||||
---
|
||||
|
||||
<div class="p-10">
|
||||
<Tooltip client:only="react" content="siemano">
|
||||
<SidebarItem client:load section="experience" icon="fa6-solid:user" />
|
||||
</Tooltip>
|
||||
</div>
|
||||
|
|
@ -13,5 +13,5 @@ export interface MainSection {
|
|||
downloadedFileName?: string;
|
||||
};
|
||||
socials: Social[];
|
||||
config: Omit<SectionConfig, 'title'>;
|
||||
config: SectionConfig;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue