Create tooltip component (#77)

This commit is contained in:
Szymon Kin 2022-11-12 22:15:56 +01:00 committed by GitHub
parent bd27dc085c
commit e6bb39e3b3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 154 additions and 22 deletions

51
package-lock.json generated
View file

@ -10,6 +10,7 @@
"dependencies": { "dependencies": {
"@astrojs/image": "0.11.4", "@astrojs/image": "0.11.4",
"@iconify-icon/react": "1.0.1", "@iconify-icon/react": "1.0.1",
"@tippyjs/react": "4.2.6",
"clsx": "1.2.1", "clsx": "1.2.1",
"prettier-plugin-astro": "0.7.0", "prettier-plugin-astro": "0.7.0",
"react": "18.2.0", "react": "18.2.0",
@ -898,6 +899,15 @@
"integrity": "sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==", "integrity": "sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==",
"dev": true "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": { "node_modules/@proload/core": {
"version": "0.3.3", "version": "0.3.3",
"resolved": "https://registry.npmjs.org/@proload/core/-/core-0.3.3.tgz", "resolved": "https://registry.npmjs.org/@proload/core/-/core-0.3.3.tgz",
@ -920,6 +930,18 @@
"@proload/core": "^0.3.2" "@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": { "node_modules/@types/acorn": {
"version": "4.0.6", "version": "4.0.6",
"resolved": "https://registry.npmjs.org/@types/acorn/-/acorn-4.0.6.tgz", "resolved": "https://registry.npmjs.org/@types/acorn/-/acorn-4.0.6.tgz",
@ -9280,6 +9302,14 @@
"globrex": "^0.1.2" "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": { "node_modules/to-fast-properties": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", "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==", "integrity": "sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==",
"dev": true "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": { "@proload/core": {
"version": "0.3.3", "version": "0.3.3",
"resolved": "https://registry.npmjs.org/@proload/core/-/core-0.3.3.tgz", "resolved": "https://registry.npmjs.org/@proload/core/-/core-0.3.3.tgz",
@ -11208,6 +11243,14 @@
"tsm": "^2.1.4" "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": { "@types/acorn": {
"version": "4.0.6", "version": "4.0.6",
"resolved": "https://registry.npmjs.org/@types/acorn/-/acorn-4.0.6.tgz", "resolved": "https://registry.npmjs.org/@types/acorn/-/acorn-4.0.6.tgz",
@ -17105,6 +17148,14 @@
"globrex": "^0.1.2" "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": { "to-fast-properties": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",

View file

@ -21,6 +21,7 @@
"dependencies": { "dependencies": {
"@astrojs/image": "0.11.4", "@astrojs/image": "0.11.4",
"@iconify-icon/react": "1.0.1", "@iconify-icon/react": "1.0.1",
"@tippyjs/react": "4.2.6",
"clsx": "1.2.1", "clsx": "1.2.1",
"prettier-plugin-astro": "0.7.0", "prettier-plugin-astro": "0.7.0",
"react": "18.2.0", "react": "18.2.0",

View 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;

View file

@ -5,19 +5,22 @@ import type { Section } from '@/types/data';
import type { IconName } from '@/types/icon'; import type { IconName } from '@/types/icon';
import Icon from './icon'; import Icon from './icon';
import Tooltip from './tooltip';
export interface Props { export interface SidebarItemProps {
section: Section; section: Section;
icon: IconName; icon: IconName;
title?: string;
} }
const SidebarItem = ({ section, icon }: Props) => { const SidebarItem = ({ section, icon, title = '' }: SidebarItemProps) => {
const { hash } = useLocation(); const { hash } = useLocation();
const href = `#${section}`; const href = `#${section}`;
const active = hash === '' ? section === MAIN_SECTION : hash === href; const active = hash === '' ? section === MAIN_SECTION : hash === href;
return ( return (
<Tooltip content={`${title || section.charAt(0).toUpperCase() + section.slice(1)} section`} placement="left">
<a <a
href={href} href={href}
className={`inline-flex justify-center items-center h-10 w-10 rounded-lg transition className={`inline-flex justify-center items-center h-10 w-10 rounded-lg transition
@ -27,6 +30,7 @@ const SidebarItem = ({ section, icon }: Props) => {
> >
<Icon name={icon} size={20} /> <Icon name={icon} size={20} />
</a> </a>
</Tooltip>
); );
}; };

View 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;

View file

@ -1,18 +1,21 @@
--- ---
import Icon from '@/atoms/icon'; import Icon from '@/atoms/icon';
import IconWithTooltip from '@/atoms/icon-with-tooltip';
import Typography from '@/atoms/typography.astro'; import Typography from '@/atoms/typography.astro';
import type { IconName } from '@/types/icon';
import type { LevelledSkill } from '@/types/skills-section'; import type { LevelledSkill } from '@/types/skills-section';
import SkillLevel from './skill-level.astro'; import SkillLevel from './skill-level.astro';
export interface Props extends LevelledSkill {} 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'; const IconWrapper = url ? 'a' : 'div';
--- ---
<div class:list={['flex', 'flex-col', 'gap-2']}> <div class:list={['flex', 'flex-col', 'gap-2']}>
<div class:list={['flex', 'items-center', 'justify-between', 'h-5']}>
<IconWrapper <IconWrapper
class:list={['flex', 'gap-2', 'h-5']} class:list={['flex', 'gap-2', 'h-5']}
{...(url && { href: url, target: "_blank", rel: "noopener noreferrer" })} {...(url && { href: url, target: "_blank", rel: "noopener noreferrer" })}
@ -22,5 +25,18 @@ const IconWrapper = url ? 'a' : 'div';
<span class="text-gray-700">{name}</span> <span class="text-gray-700">{name}</span>
</Typography> </Typography>
</IconWrapper> </IconWrapper>
{
description && (
<IconWithTooltip
client:load
name={'akar-icons:info-fill' as IconName}
color="#D1D5DB"
size={14}
content={description}
placement="top"
/>
)
}
</div>
<SkillLevel skillLevel={level} /> <SkillLevel skillLevel={level} />
</div> </div>

View file

@ -9,6 +9,7 @@ const data: Data = {
main: { main: {
config: { config: {
icon: 'fa6-solid:user', icon: 'fa6-solid:user',
title: 'Profile',
}, },
image: import('@/assets/my-image.jpeg'), image: import('@/assets/my-image.jpeg'),
fullName: 'Mark Freeman', fullName: 'Mark Freeman',

View file

@ -26,12 +26,21 @@ const { seo, ...dataWithoutSeo } = data;
</head> </head>
<body class="flex justify-center bg-gray-50"> <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="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"> <Sidebar className="hidden xl:flex fixed">
{ {
getObjectKeys(dataWithoutSeo).map((key) => { getObjectKeys(dataWithoutSeo).map((key) => {
const sectionData = dataWithoutSeo[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> </Sidebar>

View 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>

View file

@ -13,5 +13,5 @@ export interface MainSection {
downloadedFileName?: string; downloadedFileName?: string;
}; };
socials: Social[]; socials: Social[];
config: Omit<SectionConfig, 'title'>; config: SectionConfig;
} }