Skip to content

Commit 5fb6eb5

Browse files
committed
更新
1 parent 1149107 commit 5fb6eb5

9 files changed

Lines changed: 116 additions & 36 deletions

File tree

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<h2>About This Animation</h2>
2+
<p>This demo showcases smooth circular animations using CSS transitions. The circles dynamically update with randomized properties, creating an engaging visual effect.</p>
3+
4+
<h3>Technical Implementation</h3>
5+
6+
<h4>HTML Structure</h4>
7+
<p>A container element with the ID "app" serves as the animation canvas, containing multiple circle elements with the class "circle". Each circle is positioned absolutely within the container to allow layering effects.</p>
8+
9+
<h4>CSS Styling</h4>
10+
<p>The container is set to 500x500 pixels with a black background and relative positioning. Each circle uses CSS variables for radius definition, with a white border and 50% border-radius to create perfect circles. The circles are centered using absolute positioning combined with transform translate, ensuring they remain centered even when their size changes. A 0.2-second transition is applied to width and height properties for smooth animations.</p>
11+
12+
<h4>JavaScript Logic</h4>
13+
<p>Using jQuery, a DOM-ready callback initializes the animation. Every 100 milliseconds, an interval triggers updates for all circle elements. For each circle, a random radius between 0 and 500 pixels is generated using Math.random(). The circle's height and width are updated to this new radius, and the border width is randomized between -7 and 3 pixels. This continuous randomization creates dynamic and unpredictable visual movement.</p>
14+
15+
<h4>Key Features</h4>
16+
<p>The animation leverages CSS transitions to ensure smooth property changes, while JavaScript provides the dynamic behavior through interval-based updates. The combination of random radius, border width variation, and smooth transitions creates an engaging visual effect with layered circles appearing to breathe and morph continuously.</p>
17+
18+
<p class="codepen" data-theme-id="dark" data-height="600" data-pen-title="Circular Transition Animation" data-default-tab="result" data-slug-hash="LEbzRjZ" data-user="murisans" style="height: 600px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
19+
<span>See the Pen <a href="https://codepen.io/murisans/pen/LEbzRjZ">
20+
Circular Transition Animation</a> by 赵金灏 (<a href="https://codepen.io/murisans">@murisans</a>)
21+
on <a href="https://codepen.io">CodePen</a>.</span>
22+
</p>
23+
<script async src="https://public.codepenassets.com/embed/index.js"></script>

css/style.css

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -677,6 +677,13 @@ footer a:hover {
677677
border: 1px solid var(--border-color);
678678
}
679679

680+
.work-item .date {
681+
font-size: 0.875rem;
682+
color: var(--text-secondary);
683+
margin-bottom: 0.75rem;
684+
display: inline-block;
685+
}
686+
680687
.work-item h3 {
681688
font-size: 1.5rem;
682689
font-weight: 600;

js/components/WorkItem.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
const WorkItem = ({ title, description, techStack, onClick }) => {
1+
const WorkItem = ({ title, description, techStack, date, onClick }) => {
22
return (
33
<div className="work-item" onClick={onClick}>
4+
<span className="date">{date}</span>
45
<h3>{title}</h3>
56
<p>{description}</p>
67
<div className="tech-stack">

js/data/mock.js

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ const MockData = {
6262
tag: 'React',
6363
description: 'A comprehensive library of WCAG 2.1 compliant form components.',
6464
techStack: ['React', 'TypeScript', 'WCAG 2.1', 'ARIA'],
65+
date: 'March 15, 2024',
6566
featured: true,
6667
published: true
6768
},
@@ -72,18 +73,20 @@ const MockData = {
7273
tag: 'Design',
7374
description: 'Foundational design tokens and patterns for consistent product design.',
7475
techStack: ['CSS Variables', 'Design Tokens', 'Figma'],
76+
date: 'April 20, 2024',
7577
featured: true,
7678
published: true
7779
},
7880
{
7981
id: 3,
80-
slug: 'progressive-image-loading',
81-
title: 'Progressive Image Loading',
82-
tag: 'Performance',
83-
description: 'Image optimization with graceful degradation strategies.',
84-
techStack: ['JavaScript', 'Web Performance'],
82+
slug: 'circular-transition-animation',
83+
title: 'Circular Transition Animation',
84+
tag: 'Animation',
85+
description: 'Smooth circular animation effects using CSS transitions',
86+
techStack: ['CSS', 'Animation', 'Transition'],
87+
date: 'May 26, 2024',
8588
featured: false,
86-
published: false
89+
published: true
8790
}
8891
]
8992
};

js/data/works.dev.json

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
"tag": "React",
77
"description": "A comprehensive library of WCAG 2.1 compliant form components.",
88
"techStack": ["React", "TypeScript", "WCAG 2.1", "ARIA"],
9+
"date": "March 15, 2024",
910
"featured": true,
1011
"published": true
1112
},
@@ -16,7 +17,19 @@
1617
"tag": "Design",
1718
"description": "Foundational design tokens and patterns for consistent product design.",
1819
"techStack": ["CSS Variables", "Design Tokens", "Figma"],
20+
"date": "April 20, 2024",
1921
"featured": true,
2022
"published": true
23+
},
24+
{
25+
"id": 3,
26+
"slug": "circular-transition-animation",
27+
"title": "Circular Transition Animation",
28+
"tag": "Animation",
29+
"description": "Smooth circular animation effects using CSS transitions",
30+
"techStack": ["CSS", "Animation", "Transition"],
31+
"date": "May 26, 2024",
32+
"featured": false,
33+
"published": true
2134
}
2235
]

js/data/works.json

Lines changed: 8 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,13 @@
11
[
2-
{
3-
"id": 1,
4-
"slug": "accessible-form-components",
5-
"title": "Accessible Form Components Library",
6-
"tag": "React",
7-
"description": "A comprehensive library of WCAG 2.1 compliant form components.",
8-
"techStack": ["React", "TypeScript", "WCAG 2.1", "ARIA"],
9-
"featured": true,
10-
"published": false
11-
},
12-
{
13-
"id": 2,
14-
"slug": "design-system-foundation",
15-
"title": "Design System Foundation",
16-
"tag": "Design",
17-
"description": "Foundational design tokens and patterns for consistent product design.",
18-
"techStack": ["CSS Variables", "Design Tokens", "Figma"],
19-
"featured": true,
20-
"published": false
21-
},
222
{
233
"id": 3,
24-
"slug": "progressive-image-loading",
25-
"title": "Progressive Image Loading",
26-
"tag": "Performance",
27-
"description": "Image optimization with graceful degradation strategies.",
28-
"techStack": ["JavaScript", "Web Performance"],
29-
"featured": false,
30-
"published": false
4+
"slug": "circular-transition-animation",
5+
"title": "Circular Transition Animation",
6+
"tag": "Animation",
7+
"description": "Smooth circular animation effects using CSS transitions",
8+
"techStack": ["CSS", "Animation", "Transition"],
9+
"date": "May 26, 2024",
10+
"featured": true,
11+
"published": true
3112
}
3213
]

js/pages/ArticlesPage.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,20 @@ const ArticlesPage = () => {
1818
}
1919
}, [selectedArticle]);
2020

21+
useEffect(() => {
22+
const urlParams = new URLSearchParams(window.location.search);
23+
const openParam = urlParams.get('open');
24+
if (openParam && openParam.startsWith('article:')) {
25+
const slug = openParam.replace('article:', '');
26+
const article = articles.find(a => a.slug === slug);
27+
if (article) {
28+
setSelectedArticle(article);
29+
urlParams.delete('open');
30+
window.history.replaceState({}, document.title, `${window.location.pathname}${window.location.hash}?${urlParams.toString()}`);
31+
}
32+
}
33+
}, [articles]);
34+
2135
if (loading) {
2236
return <div className="loading">Loading...</div>;
2337
}

js/pages/HomePage.js

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,12 @@ const HomePage = ({ onNavigate }) => {
4141
) : (
4242
<div className="card-grid">
4343
{articles.map((article) => (
44-
<Card key={article.id} tag={article.tag} title={article.title} description={article.description} meta={article.date} onClick={() => onNavigate('articles')} />
44+
<Card key={article.id} tag={article.tag} title={article.title} description={article.description} meta={article.date} onClick={() => {
45+
const url = new URL(window.location.href);
46+
url.searchParams.set('open', `article:${article.slug}`);
47+
url.hash = '#articles';
48+
window.location.href = url.toString();
49+
}} />
4550
))}
4651
</div>
4752
)}
@@ -59,7 +64,12 @@ const HomePage = ({ onNavigate }) => {
5964
) : (
6065
<div className="card-grid">
6166
{works.map((work, index) => (
62-
<Card key={work.id} title={work.title} description={work.description} tag={work.techStack[0]} onClick={() => onNavigate('works')} />
67+
<Card key={work.id} title={work.title} description={work.description} tag={work.techStack[0]} onClick={() => {
68+
const url = new URL(window.location.href);
69+
url.searchParams.set('open', `work:${work.slug}`);
70+
url.hash = '#works';
71+
window.location.href = url.toString();
72+
}} />
6373
))}
6474
</div>
6575
)}

js/pages/WorksPage.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,36 @@ const WorksPage = () => {
1515
useEffect(() => {
1616
if (selectedWork) {
1717
window.scrollTo({ top: 0, behavior: 'smooth' });
18+
19+
// 等待DOM更新后初始化CodePen嵌入
20+
setTimeout(() => {
21+
if (window.__CPEmbed) {
22+
window.__CPEmbed();
23+
} else {
24+
// 如果CodePen脚本还没加载,动态加载
25+
const script = document.createElement('script');
26+
script.src = 'https://public.codepenassets.com/embed/index.js';
27+
script.async = true;
28+
document.head.appendChild(script);
29+
}
30+
}, 100);
1831
}
1932
}, [selectedWork]);
2033

34+
useEffect(() => {
35+
const urlParams = new URLSearchParams(window.location.search);
36+
const openParam = urlParams.get('open');
37+
if (openParam && openParam.startsWith('work:')) {
38+
const slug = openParam.replace('work:', '');
39+
const work = works.find(w => w.slug === slug);
40+
if (work) {
41+
setSelectedWork(work);
42+
urlParams.delete('open');
43+
window.history.replaceState({}, document.title, `${window.location.pathname}${window.location.hash}?${urlParams.toString()}`);
44+
}
45+
}
46+
}, [works]);
47+
2148
if (loading) {
2249
return <div className="loading">Loading...</div>;
2350
}
@@ -96,6 +123,7 @@ const WorksPage = () => {
96123
title={work.title}
97124
description={work.description}
98125
techStack={work.techStack}
126+
date={work.date}
99127
onClick={() => setSelectedWork(work)}
100128
/>
101129
))}

0 commit comments

Comments
 (0)