Skip to content

Commit 74c00e1

Browse files
committed
feat: update components
1 parent 199a65b commit 74c00e1

File tree

16 files changed

+324
-101
lines changed

16 files changed

+324
-101
lines changed

src/components/stateless/OrbitingCircles/index.tsx

Lines changed: 89 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import React from 'react'
22
import clsx from 'clsx'
3+
import { theme } from 'antd'
34

45
export interface OrbitingItem {
56
content: React.ReactNode
@@ -15,6 +16,8 @@ export interface OrbitingCirclesProps extends React.HTMLAttributes<HTMLDivElemen
1516
items?: OrbitingItem[]
1617
showPath?: boolean
1718
centerText?: string
19+
centerTextStyle?: React.CSSProperties
20+
centerTextClassName?: string
1821
}
1922

2023
/**
@@ -29,20 +32,40 @@ export interface OrbitingCirclesProps extends React.HTMLAttributes<HTMLDivElemen
2932
* - iconSize: number (size of the item)
3033
* @param {boolean} showPath - Whether to show the orbital path
3134
* @param {string} centerText - Text to display in the center
35+
* @param {React.CSSProperties} centerTextStyle - Custom style for the center text
36+
* @param {string} centerTextClassName - Custom class name for the center text
3237
*/
3338
const OrbitingCircles = ({
3439
className,
3540
items = [],
3641
showPath = true,
3742
centerText = 'Orbit',
43+
centerTextStyle,
44+
centerTextClassName,
3845
...props
3946
}: OrbitingCirclesProps) => {
47+
const { token } = theme.useToken()
48+
49+
const calculatedItems = React.useMemo(
50+
() =>
51+
items.map((item, index) => ({
52+
...item,
53+
radius: item.radius || 100 + index * 40,
54+
duration: item.duration || 20,
55+
reverse: item.reverse !== undefined ? item.reverse : index % 2 === 0,
56+
iconSize: item.iconSize || 30,
57+
delay: item.delay || 0,
58+
})),
59+
[items]
60+
)
61+
4062
return (
4163
<div
4264
className={clsx(
43-
'bg-background relative flex h-[500px] w-full flex-col items-center justify-center overflow-hidden rounded-lg',
65+
'relative flex h-[500px] w-full flex-col items-center justify-center overflow-hidden rounded-lg',
4466
className
4567
)}
68+
style={{ backgroundColor: token.colorBgLayout, ...props.style }}
4669
{...props}
4770
>
4871
{/* Inject Keyframes locally to ensure they exist */}
@@ -58,68 +81,75 @@ const OrbitingCircles = ({
5881
`}</style>
5982

6083
{/* Center Point (Optional, for visual reference) */}
61-
<span className="pointer-events-none bg-gradient-to-b from-black to-gray-300/80 bg-clip-text text-center text-8xl leading-none font-semibold whitespace-pre-wrap text-transparent dark:from-white dark:to-slate-900/10">
84+
<span
85+
className={clsx(
86+
'pointer-events-none bg-clip-text text-center text-4xl leading-none font-bold tracking-tighter whitespace-pre-wrap text-transparent md:text-6xl',
87+
centerTextClassName
88+
)}
89+
style={{
90+
backgroundImage: `linear-gradient(to bottom, ${token.colorText}, ${token.colorTextQuaternary})`,
91+
zIndex: 1,
92+
...centerTextStyle,
93+
}}
94+
>
6295
{centerText}
6396
</span>
6497

65-
{/* Render Orbits and Items */}
66-
<div className="absolute inset-0 flex items-center justify-center">
67-
{items.map((item, index) => {
68-
const radius = item.radius || 100 + index * 40 // Default radius increment if not provided
69-
const duration = item.duration || 20
70-
const reverse = item.reverse || index % 2 === 0 // Alternate direction by default
71-
const iconSize = item.iconSize || 30
72-
const delay = item.delay || 0
73-
74-
return (
75-
<React.Fragment key={index}>
76-
{/* Orbital Path */}
77-
{showPath && (
78-
<svg
79-
xmlns="http://www.w3.org/2000/svg"
80-
version="1.1"
81-
className="pointer-events-none absolute inset-0 h-full w-full"
82-
style={{
83-
zIndex: 0,
84-
}}
85-
>
86-
<circle
87-
className="stroke-black/10 stroke-1 dark:stroke-white/10"
88-
cx="50%"
89-
cy="50%"
90-
r={radius}
91-
fill="none"
92-
/>
93-
</svg>
94-
)}
98+
{/* Render Orbital Paths (Single SVG for performance) */}
99+
{showPath && (
100+
<svg
101+
xmlns="http://www.w3.org/2000/svg"
102+
version="1.1"
103+
className="pointer-events-none absolute inset-0 h-full w-full"
104+
style={{ zIndex: 0 }}
105+
>
106+
{calculatedItems.map((item, index) => (
107+
<circle
108+
key={index}
109+
className="stroke-1"
110+
cx="50%"
111+
cy="50%"
112+
r={item.radius}
113+
fill="none"
114+
stroke={token.colorBorder}
115+
style={{ opacity: 0.5 }}
116+
/>
117+
))}
118+
</svg>
119+
)}
95120

96-
{/* Orbiting Item */}
97-
<div
98-
style={
99-
{
100-
'--radius': radius,
101-
'--duration': duration,
102-
'--icon-size': `${iconSize}px`,
103-
width: iconSize,
104-
height: iconSize,
105-
position: 'absolute',
106-
top: '50%',
107-
left: '50%',
108-
marginTop: -iconSize / 2,
109-
marginLeft: -iconSize / 2,
110-
animation: `orbit ${duration}s linear infinite`,
111-
animationDirection: reverse ? 'reverse' : 'normal',
112-
animationDelay: `${delay}s`,
113-
zIndex: 10,
114-
} as React.CSSProperties
115-
}
116-
className="flex items-center justify-center rounded-full bg-white/10 backdrop-blur-sm"
117-
>
118-
{item.content}
119-
</div>
120-
</React.Fragment>
121-
)
122-
})}
121+
{/* Render Orbiting Items */}
122+
<div className="absolute inset-0 flex items-center justify-center">
123+
{calculatedItems.map((item, index) => (
124+
<div
125+
key={index}
126+
style={
127+
{
128+
'--radius': item.radius,
129+
'--duration': item.duration,
130+
'--icon-size': `${item.iconSize}px`,
131+
width: item.iconSize,
132+
height: item.iconSize,
133+
position: 'absolute',
134+
top: '50%',
135+
left: '50%',
136+
marginTop: -item.iconSize / 2,
137+
marginLeft: -item.iconSize / 2,
138+
animation: `orbit ${item.duration}s linear infinite`,
139+
animationDirection: item.reverse ? 'reverse' : 'normal',
140+
animationDelay: `${item.delay}s`,
141+
zIndex: 10,
142+
backgroundColor: token.colorBgContainer,
143+
// Set initial transform to prevent items from bunching in center before animation starts
144+
transform: `rotate(0deg) translateY(calc(var(--radius) * 1px)) rotate(0deg)`,
145+
willChange: 'transform',
146+
} as React.CSSProperties
147+
}
148+
className="flex items-center justify-center rounded-full shadow-sm backdrop-blur-sm"
149+
>
150+
{item.content}
151+
</div>
152+
))}
123153
</div>
124154
</div>
125155
)

src/components/stateless/PointerMove/index.jsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ const PointerMove = () => {
1111
if (ref.current) {
1212
const handlePointerMove = ({ clientX, clientY }) => {
1313
const element = ref.current
14+
if (!element) return
1415
// calculate x and y coordinates
1516
const x = clientX + (element.offsetLeft + element.offsetWidth)
1617
const y = clientY + (element.offsetTop + element.offsetHeight)

src/components/stateless/SlideButton/index.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ const SlideButton = ({
2222
return (
2323
<span
2424
className={clsx(
25-
'relative cursor-pointer overflow-hidden px-[10px] py-[10px] text-[14px] tracking-[5px] uppercase no-underline shadow-[0_20px_50px_rgba(0,0,0,0.5)]',
25+
'relative cursor-pointer overflow-hidden py-[10px] pr-[10px] pl-[15px] text-[14px] tracking-[5px] uppercase no-underline shadow-[0_20px_50px_rgba(0,0,0,0.5)]',
2626
'bg-[var(--bg-color)] text-[var(--text-color)]',
2727
className
2828
)}

src/components/stateless/Sparkles/index.jsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@ import Particles, { initParticlesEngine } from '@tsparticles/react'
33
import { loadSlim } from '@tsparticles/slim'
44
import clsx from 'clsx'
55
import { motion, useAnimation } from 'motion/react'
6+
import { theme } from 'antd'
67

78
const SparklesCore = (props) => {
9+
const { token } = theme.useToken()
810
const { id, className, background, minSize, maxSize, speed, particleColor, particleDensity } = props
911
const [init, setInit] = useState(false)
1012
useEffect(() => {
@@ -38,7 +40,7 @@ const SparklesCore = (props) => {
3840
options={{
3941
background: {
4042
color: {
41-
value: background || '#0d47a1',
43+
value: background || token.colorBgLayout,
4244
},
4345
},
4446
fullScreen: {
@@ -99,7 +101,7 @@ const SparklesCore = (props) => {
99101
},
100102
},
101103
color: {
102-
value: particleColor || '#ffffff',
104+
value: particleColor || token.colorText,
103105
animation: {
104106
h: {
105107
count: 0,

src/config/menu.config.jsx

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ import {
3030
AppstoreOutlined,
3131
CodeOutlined,
3232
ProjectOutlined,
33+
FileTextOutlined,
34+
ThunderboltOutlined,
35+
ToolOutlined,
3336
} from '@ant-design/icons'
3437
import { t } from 'i18next' // 注意:这里可能需要处理 i18n
3538

@@ -82,13 +85,13 @@ const rawMainLayoutMenu = [
8285
key: '/tech/frontend/vue/plugins',
8386
icon: <AppstoreOutlined />,
8487
children: [
85-
{ label: 'Vue3 API', key: '/tech/frontend/vue/plugins/vue3' },
86-
{ label: '性能优化', key: '/tech/frontend/vue/plugins/perf' },
88+
{ label: 'Vue3 API', key: '/tech/frontend/vue/plugins/vue3', icon: <FileTextOutlined /> },
89+
{ label: '性能优化', key: '/tech/frontend/vue/plugins/perf', icon: <ThunderboltOutlined /> },
8790
],
8891
},
8992
],
9093
},
91-
{ label: 'Angular', key: '/tech/frontend/angular' },
94+
{ label: 'Angular', key: '/tech/frontend/angular', icon: <Html5Outlined /> },
9295
],
9396
},
9497
],
@@ -105,8 +108,8 @@ const rawMainLayoutMenu = [
105108
key: '/build',
106109
icon: <ApartmentOutlined />,
107110
children: [
108-
{ label: 'Webpack', key: '/build/webpack' },
109-
{ label: 'Vite', key: '/build/vite' },
111+
{ label: 'Webpack', key: '/build/webpack', icon: <ToolOutlined /> },
112+
{ label: 'Vite', key: '/build/vite', icon: <ThunderboltOutlined /> },
110113
],
111114
},
112115
{

src/pages/build/vite/index.jsx

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import React from 'react'
2+
import { Typography, Card } from 'antd'
3+
4+
const { Title, Paragraph } = Typography
5+
6+
const VitePage = () => {
7+
return (
8+
<div className="p-4">
9+
<Card>
10+
<Title level={2}>Vite</Title>
11+
<Paragraph>这里是 Vite 构建工具的相关介绍页面。</Paragraph>
12+
</Card>
13+
</div>
14+
)
15+
}
16+
17+
export default VitePage

src/pages/build/webpack/index.jsx

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import React from 'react'
2+
import { Typography, Card } from 'antd'
3+
4+
const { Title, Paragraph } = Typography
5+
6+
const WebpackPage = () => {
7+
return (
8+
<div className="p-4">
9+
<Card>
10+
<Title level={2}>Webpack</Title>
11+
<Paragraph>这里是 Webpack 构建工具的相关介绍页面。</Paragraph>
12+
</Card>
13+
</div>
14+
)
15+
}
16+
17+
export default WebpackPage

0 commit comments

Comments
 (0)