Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
460 changes: 460 additions & 0 deletions package-lock.json

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
"@emotion/styled": "^11.14.1",
"@mui/icons-material": "^6.5.0",
"@mui/material": "^6.5.0",
"@radix-ui/react-tooltip": "^1.2.8",
"@testing-library/react": "^16.3.2",
"clsx": "^2.1.1",
"gh-pages": "^3.2.3",
"motion": "^12.38.0",
"react": "^19.2.4",
Expand All @@ -16,6 +18,7 @@
"react-router-dom": "^6.30.3",
"react-transition-group": "^4.4.5",
"sass": "^1.99.0",
"tailwind-merge": "^3.5.0",
"web-vitals": "^1.1.2"
},
"scripts": {
Expand Down
10 changes: 10 additions & 0 deletions public/icons/skills/angular.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions public/icons/skills/nextjs.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 6 additions & 1 deletion src/assets/data/skillsData.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"skills": [
{
"name": "Next.js",
"pic": "../icons/skills/nextjs.png",
"pic": "../icons/skills/nextjs.svg",
"projects": [
{
"title": "TokTown",
Expand Down Expand Up @@ -55,6 +55,11 @@
}
]
},
{
"name": "Angular",
"pic": "../icons/skills/angular.svg",
"projects": []
},
{
"name": "Redux",
"pic": "../icons/skills/redux.svg",
Expand Down
49 changes: 31 additions & 18 deletions src/components/SharedComponents/RotatingCircle/RotatingCircle.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { useMemo, type CSSProperties, type MouseEvent } from 'react';
import type { OrbitSkill, RotatingCircleData } from '../../../types/skillsData';
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '../../ui/tooltip';

const iconShell =
'flex shrink-0 items-center justify-center rounded-full border border-primary/40 bg-[rgba(12,22,38,0.92)] p-2 shadow-lg shadow-black/40 ring-1 ring-white/5 backdrop-blur-sm transition-all duration-200 hover:border-primary hover:bg-primary/10 hover:shadow-primary-glow focus:outline-none focus-visible:ring-2 focus-visible:ring-primary';
Expand All @@ -25,15 +26,20 @@ type SkillIconButtonProps = {
function SkillIconButton({ skill, showSkillPopover, className = '', style: sizeStyle }: SkillIconButtonProps) {
const extraStyle = useSanitizedSkillStyle(skill);
return (
<button
type="button"
className={`${iconShell} ${className}`}
style={{ ...extraStyle, ...sizeStyle }}
onClick={(e) => showSkillPopover(e, skill)}
aria-label={skill.name}
>
<img src={skill.pic} alt="" className="h-8 w-8 object-contain" />
</button>
<Tooltip>
<TooltipTrigger asChild>
<button
type="button"
className={`${iconShell} ${className}`}
style={{ ...extraStyle, ...sizeStyle }}
onClick={(e) => showSkillPopover(e, skill)}
aria-label={skill.name}
>
<img src={skill.pic} alt="" className="object-contain" />
</button>
</TooltipTrigger>
<TooltipContent side="top">{skill.name}</TooltipContent>
</Tooltip>
);
}

Expand Down Expand Up @@ -84,21 +90,27 @@ const RotatingCircle = ({ data, showSkillPopover }: RotatingCircleProps) => {
}}
>
<div className="-translate-x-1/2 -translate-y-1/2">
<div className="inline-flex origin-center animate-orbit-slow-reverse group-hover/stage:[animation-play-state:paused]">
<SkillIconButton
skill={skill}
showSkillPopover={showSkillPopover}
className="pointer-events-auto"
style={{ width: iconSize, height: iconSize, minWidth: iconSize, minHeight: iconSize }}
/>
<div
className="inline-flex origin-center"
style={{ transform: `rotate(${-angleDeg}deg)` }}
>
<div className="inline-flex origin-center animate-orbit-slow-reverse group-hover/stage:[animation-play-state:paused]">
<SkillIconButton
skill={skill}
showSkillPopover={showSkillPopover}
className="pointer-events-auto"
style={{ width: iconSize, height: iconSize, minWidth: iconSize, minHeight: iconSize }}
/>
</div>
</div>
</div>
</div>
);
});

return (
<div className="flex w-full shrink-0 flex-col items-center" id={data?.id}>
<TooltipProvider delayDuration={250} skipDelayDuration={120}>
<div className="flex w-full shrink-0 flex-col items-center" id={data?.id}>
<div className="group/stage w-full max-w-[300px] px-2 lg:hidden">
<div className="mb-5 flex w-full justify-center">
<span className="flex min-h-11 min-w-[8.5rem] items-center justify-center rounded-lg border border-white/20 bg-page/80 px-4 py-2 text-center text-sm font-semibold uppercase leading-normal tracking-wide text-white shadow-md backdrop-blur-sm">
Expand Down Expand Up @@ -132,7 +144,8 @@ const RotatingCircle = ({ data, showSkillPopover }: RotatingCircleProps) => {
</div>
</div>
</div>
</div>
</div>
</TooltipProvider>
);
};

Expand Down
47 changes: 47 additions & 0 deletions src/components/ui/tooltip.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import * as React from 'react';
import * as TooltipPrimitive from '@radix-ui/react-tooltip';

import { cn } from '../../lib/utils';

const TooltipProvider = TooltipPrimitive.Provider;

const Tooltip = TooltipPrimitive.Root;

const TooltipTrigger = TooltipPrimitive.Trigger;

const TooltipArrow = React.forwardRef<
React.ElementRef<typeof TooltipPrimitive.Arrow>,
React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Arrow>
>(({ className, ...props }, ref) => (
<TooltipPrimitive.Arrow
ref={ref}
width={11}
height={5}
className={cn('fill-elevated/95 stroke-white/20', className)}
{...props}
/>
));
TooltipArrow.displayName = TooltipPrimitive.Arrow.displayName;

const TooltipContent = React.forwardRef<
React.ElementRef<typeof TooltipPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>
>(({ className, sideOffset = 6, children, ...props }, ref) => (
<TooltipPrimitive.Portal>
<TooltipPrimitive.Content
ref={ref}
sideOffset={sideOffset}
className={cn(
'z-[200] max-w-xs origin-[--radix-tooltip-content-transform-origin] rounded-md border border-white/15 bg-elevated/95 px-2.5 py-1.5 text-xs font-medium text-white shadow-lg shadow-black/40 backdrop-blur-md',
className,
)}
{...props}
>
{children}
<TooltipArrow />
</TooltipPrimitive.Content>
</TooltipPrimitive.Portal>
));
TooltipContent.displayName = TooltipPrimitive.Content.displayName;

export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider, TooltipArrow };
6 changes: 6 additions & 0 deletions src/lib/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { clsx, type ClassValue } from 'clsx';
import { twMerge } from 'tailwind-merge';

export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}
Loading