feat(about): 实现动态 GitHub 提交统计与页面样式优化

- 移除冗余的夜间主题 CSS 变量定义
- 新增 softPulse 动画用于按钮微光效果
- 优化主页标题动画与样式,调整颜色与阴影
- 删除重复的 hero-title 和 profile-avatar 样式定义
- 更新时间轴移动端布局逻辑并增强响应式表现
- 为社交卡片、博客、联系人等区块添加注释分隔
- 引入 Commit 统计功能,通过 GitHub API 获取真实数据
- 添加本地缓存机制以提升性能和减少请求频率
- 创建 fetchCommitCounts 函数计算周/月/年提交次数
- 构建 renderCommitStats 函数动态渲染提交统计数据
- 修复 CSS 文件末尾多余空行与格式问题
This commit is contained in:
hehh
2025-11-20 20:23:37 +08:00
parent 629eb55a41
commit e0396f952e
2 changed files with 144 additions and 144 deletions

View File

@@ -41,14 +41,6 @@
--glass-border: rgba(255, 255, 255, 0.12); --glass-border: rgba(255, 255, 255, 0.12);
} }
:root.theme-night {
--grad-a: #101216;
--grad-b: #171a1f;
--text-strong: #F2F3F5;
--text-soft: rgba(255, 255, 255, 0.9);
--glass-alpha: 0.14;
--glass-border: rgba(255, 255, 255, 0.16);
}
.theme-day .nav-logo { .theme-day .nav-logo {
color: var(--text-strong); color: var(--text-strong);
@@ -701,6 +693,11 @@ a:not(.nav-logo):not(.nav-links a):not(.social-link):not(.btn):not(.footer-info
} }
} }
@keyframes softPulse {
0%, 100% { transform: scale(1); }
50% { transform: scale(1.05); }
}
.profile-info h1 { .profile-info h1 {
margin: 0 0 0.5rem 0; margin: 0 0 0.5rem 0;
font-size: 2rem; font-size: 2rem;
@@ -798,31 +795,19 @@ a:not(.nav-logo):not(.nav-links a):not(.social-link):not(.btn):not(.footer-info
color: var(--text-strong); /* 使用主题文字颜色 */ color: var(--text-strong); /* 使用主题文字颜色 */
} }
.profile-avatar {
position: relative;
display: inline-block;
margin-bottom: 2rem;
}
.hero-title { .hero-title {
font-size: 4rem; font-size: 4rem;
font-weight: 800; font-weight: 800;
color: #2c3e50;
margin-bottom: 1rem; margin-bottom: 1rem;
background: linear-gradient(45deg, #fff, #e0e0e0); background: linear-gradient(45deg, #fff, #e0e0e0);
-webkit-background-clip: text; -webkit-background-clip: text;
-webkit-text-fill-color: transparent; -webkit-text-fill-color: transparent;
background-clip: text; background-clip: text;
animation: titleGlow 3s ease-in-out infinite; animation: titleGlow 3s ease-in-out infinite alternate;
text-shadow: 0 0 30px rgba(255, 255, 255, 0.3);
} }
.hero-subtitle {
font-size: 1.4rem;
color: rgba(255, 255, 255, 0.9);
margin-bottom: 1.5rem;
font-weight: 500;
opacity: 0.9;
}
.hero-description { .hero-description {
margin-bottom: 2rem; margin-bottom: 2rem;
@@ -840,10 +825,6 @@ a:not(.nav-logo):not(.nav-links a):not(.social-link):not(.btn):not(.footer-info
display: inline-block; display: inline-block;
} }
.avatar-image:hover {
transform: scale(1.05);
box-shadow: 0 25px 50px rgba(0, 0, 0, 0.4);
}
.avatar-ring { .avatar-ring {
position: absolute; position: absolute;
@@ -866,18 +847,6 @@ a:not(.nav-logo):not(.nav-links a):not(.social-link):not(.btn):not(.footer-info
} }
} }
.hero-title {
font-size: 4rem;
font-weight: 800;
color: #2c3e50;
margin-bottom: 1rem;
background: linear-gradient(45deg, #fff, #e0e0e0);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
animation: titleGlow 3s ease-in-out infinite alternate;
}
@keyframes titleGlow { @keyframes titleGlow {
from { from {
filter: drop-shadow(0 0 20px rgba(255, 255, 255, 0.5)); filter: drop-shadow(0 0 20px rgba(255, 255, 255, 0.5));
@@ -911,7 +880,7 @@ a:not(.nav-logo):not(.nav-links a):not(.social-link):not(.btn):not(.footer-info
font-size: 1rem; font-size: 1rem;
font-weight: 700; font-weight: 700;
box-shadow: 0 8px 25px rgba(255, 107, 107, 0.4); box-shadow: 0 8px 25px rgba(255, 107, 107, 0.4);
animation: pulse 2s infinite; animation: softPulse 2s infinite;
border: 1px solid rgba(255, 255, 255, 0.18); border: 1px solid rgba(255, 255, 255, 0.18);
} }
@@ -972,44 +941,7 @@ a:not(.nav-logo):not(.nav-links a):not(.social-link):not(.btn):not(.footer-info
opacity: 0.8; opacity: 0.8;
} }
/* 技术栈云图 - INFJ风格设计 */
.tech-cloud-section {
padding: 8rem 2rem;
background: rgba(255, 255, 255, 0.05);
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
border-radius: 50px;
margin: 2rem;
border: 1px solid rgba(255, 255, 255, 0.18);
box-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.37);
position: relative;
overflow: hidden;
}
.tech-cloud-section::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: radial-gradient(circle at 20% 80%, rgba(120, 119, 198, 0.1) 0%, transparent 50%),
radial-gradient(circle at 80% 20%, rgba(255, 119, 198, 0.1) 0%, transparent 50%),
radial-gradient(circle at 40% 40%, rgba(120, 219, 255, 0.1) 0%, transparent 50%);
pointer-events: none;
}
@keyframes gradientShift {
0% {
background-position: 0% 50%;
}
50% {
background-position: 100% 50%;
}
100% {
background-position: 0% 50%;
}
}
/* 标签浮动动画 - 仅在非球体模式下使用 */ /* 标签浮动动画 - 仅在非球体模式下使用 */
@keyframes cloudFloat { @keyframes cloudFloat {
@@ -1137,11 +1069,6 @@ a:not(.nav-logo):not(.nav-links a):not(.social-link):not(.btn):not(.footer-info
} }
} }
.cloud-tag {
flex-shrink: 0;
margin: 0 5px;
}
/* 标签云标签 */ /* 标签云标签 */
.cloud-tag { .cloud-tag {
@@ -1382,39 +1309,10 @@ a:not(.nav-logo):not(.nav-links a):not(.social-link):not(.btn):not(.footer-info
.timeline-item { .timeline-item {
display: flex; display: flex;
align-items: center; align-items: center;
margin-bottom: 4rem; margin-bottom: 3rem;
position: relative; position: relative;
} }
/* 在移动端保持单列布局 */
@media (max-width: 768px) {
.personality-timeline::before {
left: 30px;
}
.timeline-item {
flex-direction: row !important;
padding-left: 80px;
}
.timeline-icon {
position: absolute;
left: 0;
width: 60px;
height: 60px;
font-size: 1.5rem;
}
.timeline-content {
margin: 0;
margin-left: 1rem;
}
}
.timeline-item:nth-child(even) {
flex-direction: row-reverse;
}
.timeline-icon { .timeline-icon {
width: 90px; width: 90px;
height: 90px; height: 90px;
@@ -1477,7 +1375,40 @@ a:not(.nav-logo):not(.nav-links a):not(.social-link):not(.btn):not(.footer-info
font-weight: 500; font-weight: 500;
} }
/* PC端保持左右交错布局 */
@media (min-width: 769px) {
.timeline-item:nth-child(even) {
flex-direction: row-reverse;
}
}
/* 在移动端保持单列布局 */
@media (max-width: 768px) {
.personality-timeline::before {
left: 30px;
}
.timeline-item {
flex-direction: row !important;
padding-left: 80px;
}
.timeline-icon {
position: absolute;
left: 0;
width: 60px;
height: 60px;
font-size: 1.5rem;
}
.timeline-content {
margin: 0;
margin-left: 1rem;
}
}
/* GitHub项目展示 */ /* GitHub项目展示 */
.github-showcase-section { .github-showcase-section {
padding: 8rem 2rem; padding: 8rem 2rem;
background: rgba(255, 255, 255, 0.05); background: rgba(255, 255, 255, 0.05);
@@ -1581,6 +1512,7 @@ a:not(.nav-logo):not(.nav-links a):not(.social-link):not(.btn):not(.footer-info
} }
/* 博客瀑布流 */ /* 博客瀑布流 */
.blog-waterfall-section { .blog-waterfall-section {
padding: 8rem 2rem; padding: 8rem 2rem;
background: rgba(255, 255, 255, 0.05); background: rgba(255, 255, 255, 0.05);
@@ -1680,6 +1612,7 @@ a:not(.nav-logo):not(.nav-links a):not(.social-link):not(.btn):not(.footer-info
} }
/* 联系方式轨道 - 循环随机围绕动画 */ /* 联系方式轨道 - 循环随机围绕动画 */
.contact-floating-section { .contact-floating-section {
padding: 8rem 2rem; padding: 8rem 2rem;
position: relative; position: relative;
@@ -1702,8 +1635,8 @@ a:not(.nav-logo):not(.nav-links a):not(.social-link):not(.btn):not(.footer-info
right: 0; right: 0;
bottom: 0; bottom: 0;
background: radial-gradient(circle at 20% 30%, rgba(102, 126, 234, 0.1) 0%, transparent 50%), background: radial-gradient(circle at 20% 30%, rgba(102, 126, 234, 0.1) 0%, transparent 50%),
radial-gradient(circle at 80% 70%, rgba(118, 75, 162, 0.1) 0%, transparent 50%), radial-gradient(circle at 80% 70%, rgba(118, 75, 162, 0.1) 0%, transparent 50%),
radial-gradient(circle at 40% 80%, rgba(155, 89, 182, 0.1) 0%, transparent 50%); radial-gradient(circle at 40% 80%, rgba(155, 89, 182, 0.1) 0%, transparent 50%);
pointer-events: none; pointer-events: none;
z-index: 1; z-index: 1;
border-radius: 50px; border-radius: 50px;
@@ -1746,6 +1679,7 @@ a:not(.nav-logo):not(.nav-links a):not(.social-link):not(.btn):not(.footer-info
} }
/* 社交卡片 */ /* 社交卡片 */
.social-card { .social-card {
background: rgba(255, 255, 255, var(--glass-alpha)); background: rgba(255, 255, 255, var(--glass-alpha));
backdrop-filter: blur(var(--glass-blur)); backdrop-filter: blur(var(--glass-blur));
@@ -1835,6 +1769,7 @@ a:not(.nav-logo):not(.nav-links a):not(.social-link):not(.btn):not(.footer-info
} }
/* 轨道围绕动画 - 每个卡片不同的轨道路径,优化避免碰撞 */ /* 轨道围绕动画 - 每个卡片不同的轨道路径,优化避免碰撞 */
.social-card:nth-child(1) { .social-card:nth-child(1) {
animation: orbit1 20s linear infinite; animation: orbit1 20s linear infinite;
} }
@@ -1945,6 +1880,7 @@ a:not(.nav-logo):not(.nav-links a):not(.social-link):not(.btn):not(.footer-info
} }
/* 微信弹窗样式 */ /* 微信弹窗样式 */
.modal { .modal {
position: fixed; position: fixed;
z-index: 1000; z-index: 1000;
@@ -2000,6 +1936,7 @@ a:not(.nav-logo):not(.nav-links a):not(.social-link):not(.btn):not(.footer-info
} }
/* 评论系统 */ /* 评论系统 */
.comments-section { .comments-section {
padding: 8rem 2rem; padding: 8rem 2rem;
background: rgba(255, 255, 255, 0.05); background: rgba(255, 255, 255, 0.05);
@@ -2037,6 +1974,7 @@ a:not(.nav-logo):not(.nav-links a):not(.social-link):not(.btn):not(.footer-info
} }
/* 加载动画 */ /* 加载动画 */
.loading-placeholder { .loading-placeholder {
text-align: center; text-align: center;
padding: 4rem 2rem; padding: 4rem 2rem;
@@ -2223,7 +2161,7 @@ a:not(.nav-logo):not(.nav-links a):not(.social-link):not(.btn):not(.footer-info
@keyframes orbit6 { @keyframes orbit6 {
} }
/* 移动端英雄区域重构 */
.hero-container { .hero-container {
grid-template-columns: 1fr; grid-template-columns: 1fr;
text-align: center; text-align: center;
@@ -2439,6 +2377,7 @@ a:not(.nav-logo):not(.nav-links a):not(.social-link):not(.btn):not(.footer-info
} }
/* 页脚样式 - 首页风格 */ /* 页脚样式 - 首页风格 */
.footer { .footer {
background: rgba(0, 0, 0, 0.2); background: rgba(0, 0, 0, 0.2);
color: rgba(255, 255, 255, 0.8); color: rgba(255, 255, 255, 0.8);
@@ -2594,3 +2533,5 @@ a:not(.nav-logo):not(.nav-links a):not(.social-link):not(.btn):not(.footer-info
-webkit-text-fill-color: transparent; -webkit-text-fill-color: transparent;
background-clip: text; background-clip: text;
} }
/* 文件末尾 */

View File

@@ -155,35 +155,7 @@ function displayGitHubProfile(data) {
$('#github-profile').html(profileHtml); $('#github-profile').html(profileHtml);
$('#github-repos').text(data.public_repos); $('#github-repos').text(data.public_repos);
$('#github-followers').text(data.followers); $('#github-followers').text(data.followers);
initCommitStats(data.login || 'listener-He');
// 获取提交统计使用GitHub API的限制这里模拟数据
var commitsHtml = '<div class="commits-stats">' +
'<h3>提交统计</h3>' +
'<div class="commits-chart">' +
'<div class="commit-item">' +
'<span class="commit-date">本周</span>' +
'<div class="commit-bar">' +
'<div class="commit-fill" style="width: 80%"></div>' +
'</div>' +
'<span class="commit-count">24</span>' +
'</div>' +
'<div class="commit-item">' +
'<span class="commit-date">本月</span>' +
'<div class="commit-bar">' +
'<div class="commit-fill" style="width: 65%"></div>' +
'</div>' +
'<span class="commit-count">156</span>' +
'</div>' +
'<div class="commit-item">' +
'<span class="commit-date">今年</span>' +
'<div class="commit-bar">' +
'<div class="commit-fill" style="width: 90%"></div>' +
'</div>' +
'<span class="commit-count">1,247</span>' +
'</div>' +
'</div>' +
'</div>';
$('#github-commits').html(commitsHtml);
} }
// 优质项目展示 // 优质项目展示
@@ -1045,3 +1017,90 @@ function updateTechTagColors() {
} }
}); });
} }
function initCommitStats(username) {
var cacheKey = 'github_commits_cache';
var cacheTimeKey = 'github_commits_cache_time';
var now = new Date().getTime();
var oneDay = 24 * 60 * 60 * 1000;
var cached = localStorage.getItem(cacheKey);
var cachedTime = localStorage.getItem(cacheTimeKey);
if (cached && cachedTime && (now - parseInt(cachedTime)) < oneDay) {
renderCommitStats(JSON.parse(cached));
return;
}
localStorage.removeItem(cacheKey);
localStorage.removeItem(cacheTimeKey);
fetchCommitCounts(username).then(function(stats){
localStorage.setItem(cacheKey, JSON.stringify(stats));
localStorage.setItem(cacheTimeKey, now.toString());
renderCommitStats(stats);
}).catch(function(){
fetch('data/github_commits.json')
.then(function(res){ return res.json(); })
.then(function(json){ renderCommitStats(json); })
.catch(function(){ renderCommitStats({week:0,month:0,year:0}); });
});
}
function fetchCommitCounts(username) {
function fmt(d){
var y=d.getFullYear();
var m=('0'+(d.getMonth()+1)).slice(-2);
var s=('0'+d.getDate()).slice(-2);
return y+'-'+m+'-'+s;
}
var today = new Date();
var weekStart = new Date(today.getFullYear(), today.getMonth(), today.getDate()-6);
var monthStart = new Date(today.getFullYear(), today.getMonth(), today.getDate()-29);
var yearStart = new Date(today.getFullYear(), 0, 1);
var h = { 'Accept': 'application/vnd.github.cloak-preview+json' };
function q(start,end){
var url = 'https://api.github.com/search/commits?q=author:'+encodeURIComponent(username)+'+author-date:'+fmt(start)+'..'+fmt(end);
return fetch(url,{ headers: h, method:'GET' }).then(function(r){ return r.json(); }).then(function(j){ return (j && typeof j.total_count==='number')? j.total_count : 0; });
}
return Promise.all([
q(weekStart,today),
q(monthStart,today),
q(yearStart,today)
]).then(function(arr){
return { week: arr[0], month: arr[1], year: arr[2], range: { week:{start:fmt(weekStart),end:fmt(today)}, month:{start:fmt(monthStart),end:fmt(today)}, year:{start:fmt(yearStart),end:fmt(today)} }, generated_at: new Date().toISOString() };
});
}
function renderCommitStats(stats) {
var w = parseInt(stats.week||0,10);
var m = parseInt(stats.month||0,10);
var y = parseInt(stats.year||0,10);
function pct(v){
var p = 0;
if (y>0) p = Math.min(100, Math.max(5, Math.round(v*100/Math.max(y,1))));
return p;
}
var commitsHtml = '<div class="commits-stats">'+
'<h3>提交统计</h3>'+
'<div class="commits-chart">'+
'<div class="commit-item">'+
'<span class="commit-date">本周</span>'+
'<div class="commit-bar">'+
'<div class="commit-fill" style="width: '+pct(w)+'%"></div>'+
'</div>'+
'<span class="commit-count">'+w+'</span>'+
'</div>'+
'<div class="commit-item">'+
'<span class="commit-date">本月</span>'+
'<div class="commit-bar">'+
'<div class="commit-fill" style="width: '+pct(m)+'%"></div>'+
'</div>'+
'<span class="commit-count">'+m+'</span>'+
'</div>'+
'<div class="commit-item">'+
'<span class="commit-date">今年</span>'+
'<div class="commit-bar">'+
'<div class="commit-fill" style="width: 100%"></div>'+
'</div>'+
'<span class="commit-count">'+y+'</span>'+
'</div>'+
'</div>'+
'</div>';
$('#github-commits').html(commitsHtml);
}