Skip to content

Commit 34ae6da

Browse files
committed
feat: profile
1 parent c9fb7a6 commit 34ae6da

3 files changed

Lines changed: 178 additions & 2 deletions

File tree

src/components/stateless/GradientAnimation/index.module.less

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
background: linear-gradient(45deg, #ff6347, #ffd700, #32cd32, #1e90ff, #8a2be2);
44
background-size: 400% 400%;
55
background-clip: text;
6-
background-clip: text;
76
font-size: 16px;
87
font-weight: 700;
98
line-height: 1.1;
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
import React, { useEffect, useState, useRef } from 'react'
2+
import clsx from 'clsx'
3+
4+
interface ShootingStar {
5+
id: number
6+
x: number
7+
y: number
8+
angle: number
9+
scale: number
10+
speed: number
11+
distance: number
12+
}
13+
14+
interface ShootingStarsProps {
15+
minSpeed?: number
16+
maxSpeed?: number
17+
minDelay?: number
18+
maxDelay?: number
19+
starColor?: string
20+
trailColor?: string
21+
starWidth?: number
22+
starHeight?: number
23+
className?: string
24+
}
25+
26+
const getRandomStartPoint = () => {
27+
const side = Math.floor(Math.random() * 4)
28+
const offset = Math.random() * window.innerWidth
29+
30+
switch (side) {
31+
case 0:
32+
return { x: offset, y: 0, angle: 45 }
33+
case 1:
34+
return { x: window.innerWidth, y: offset, angle: 135 }
35+
case 2:
36+
return { x: offset, y: window.innerHeight, angle: 225 }
37+
case 3:
38+
return { x: 0, y: offset, angle: 315 }
39+
default:
40+
return { x: 0, y: 0, angle: 45 }
41+
}
42+
}
43+
const ShootingStars: React.FC<ShootingStarsProps> = ({
44+
minSpeed = 10,
45+
maxSpeed = 30,
46+
minDelay = 1200,
47+
maxDelay = 4200,
48+
starColor = '#9E00FF',
49+
trailColor = '#2EB9DF',
50+
starWidth = 10,
51+
starHeight = 1,
52+
className,
53+
}) => {
54+
const [star, setStar] = useState<ShootingStar | null>(null)
55+
const svgRef = useRef<SVGSVGElement>(null)
56+
57+
useEffect(() => {
58+
const createStar = () => {
59+
const { x, y, angle } = getRandomStartPoint()
60+
const newStar: ShootingStar = {
61+
id: Date.now(),
62+
x,
63+
y,
64+
angle,
65+
scale: 1,
66+
speed: Math.random() * (maxSpeed - minSpeed) + minSpeed,
67+
distance: 0,
68+
}
69+
setStar(newStar)
70+
71+
const randomDelay = Math.random() * (maxDelay - minDelay) + minDelay
72+
setTimeout(createStar, randomDelay)
73+
}
74+
75+
createStar()
76+
77+
return () => {}
78+
}, [minSpeed, maxSpeed, minDelay, maxDelay])
79+
80+
useEffect(() => {
81+
const moveStar = () => {
82+
if (star) {
83+
setStar((prevStar) => {
84+
if (!prevStar) return null
85+
const newX = prevStar.x + prevStar.speed * Math.cos((prevStar.angle * Math.PI) / 180)
86+
const newY = prevStar.y + prevStar.speed * Math.sin((prevStar.angle * Math.PI) / 180)
87+
const newDistance = prevStar.distance + prevStar.speed
88+
const newScale = 1 + newDistance / 100
89+
if (newX < -20 || newX > window.innerWidth + 20 || newY < -20 || newY > window.innerHeight + 20) {
90+
return null
91+
}
92+
return {
93+
...prevStar,
94+
x: newX,
95+
y: newY,
96+
distance: newDistance,
97+
scale: newScale,
98+
}
99+
})
100+
}
101+
}
102+
103+
const animationFrame = requestAnimationFrame(moveStar)
104+
return () => cancelAnimationFrame(animationFrame)
105+
}, [star])
106+
107+
return (
108+
<svg ref={svgRef} className={clsx('absolute inset-0 h-full w-full', className)}>
109+
{star && (
110+
<rect
111+
key={star.id}
112+
x={star.x}
113+
y={star.y}
114+
width={starWidth * star.scale}
115+
height={starHeight}
116+
fill="url(#gradient)"
117+
transform={`rotate(${star.angle}, ${star.x + (starWidth * star.scale) / 2}, ${star.y + starHeight / 2})`}
118+
/>
119+
)}
120+
<defs>
121+
<linearGradient id="gradient" x1="0%" y1="0%" x2="100%" y2="100%">
122+
<stop offset="0%" style={{ stopColor: trailColor, stopOpacity: 0 }} />
123+
<stop offset="100%" style={{ stopColor: starColor, stopOpacity: 1 }} />
124+
</linearGradient>
125+
</defs>
126+
</svg>
127+
)
128+
}
129+
130+
export default ShootingStars

src/pages/profile/index.jsx

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,56 @@
11
import React, { useRef } from 'react'
22
import FixTabPanel from '@stateless/FixTabPanel'
3+
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'
4+
import { dracula } from 'react-syntax-highlighter/dist/esm/styles/prism'
35

6+
const codeString = `const profile = {
7+
name: 'wkylin.w',
8+
title: 'Full-Stack Developer',
9+
skills: [
10+
'React', 'Vue' 'NextJS', 'Redux', 'TypeScript',
11+
'MySQL', 'MongoDB', 'Docker', 'Express',
12+
'GraphQL', 'Git',
13+
],
14+
hardWorker: true,
15+
quickLearner: true,
16+
problemSolver: true,
17+
yearsOfExperience: 12,
18+
};`
419
const Profile = () => {
520
const scrollRef = useRef(null)
6-
return <FixTabPanel ref={scrollRef}>Profile</FixTabPanel>
21+
return (
22+
<FixTabPanel>
23+
<div className="code-window relative h-full w-full bg-gray-900 shadow-black">
24+
<div className="relative z-10 flex items-center bg-gray-800 px-4 py-2">
25+
<div className="flex space-x-2">
26+
<div className="h-3 w-3 rounded-full bg-red-500"></div>
27+
<div className="h-3 w-3 rounded-full bg-yellow-500"></div>
28+
<div className="h-3 w-3 rounded-full bg-green-500"></div>
29+
</div>
30+
<div className="ml-4 text-sm text-gray-400">developer.js</div>
31+
</div>
32+
<div className="relative z-20 font-mono text-3xl">
33+
<div className="relative z-20">
34+
<SyntaxHighlighter
35+
language="javascript"
36+
style={dracula}
37+
customStyle={{
38+
margin: 0,
39+
lineHeight: '1',
40+
padding: '1.5rem',
41+
background: '#0f1117',
42+
borderRadius: '0',
43+
fontSize: 'clamp(0.7rem, 2vw, 1rem)',
44+
}}
45+
showLineNumbers={true}
46+
>
47+
{codeString}
48+
</SyntaxHighlighter>
49+
</div>
50+
</div>
51+
</div>
52+
</FixTabPanel>
53+
)
754
}
855

956
export default Profile

0 commit comments

Comments
 (0)