style(css): 优化 about.css 样式结构与可读性
- 将所有 CSS 规则展开为多行格式以提高可读性 - 统一缩进和空格风格,增强代码一致性 - 重新组织媒体查询和组件样式块顺序 - 补充遗漏的闭合大括号和分号 - 优化注释排版,使其更清晰易懂 - 确保渐变文本样式在不同浏览器中的兼容性 - 调整移动端技术标签显示方式,隐藏桌面端3D容器 - 完善夜间模式下的文本阴影效果 - 增强悬停状态过渡动画流畅度 - 修复部分元素在小屏幕上的布局问题
This commit is contained in:
@@ -10,7 +10,7 @@
|
||||
<link rel="stylesheet" href="css/style.css">
|
||||
<link rel="stylesheet" href="css/about.css">
|
||||
<!-- Artalk 评论样式 -->
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/artalk/2.9.1/Artalk.css">
|
||||
<link rel="stylesheet" href="https://cdn.bootcdn.net/ajax/libs/artalk/2.9.1/Artalk.css">
|
||||
<link rel="icon" href="favicon.ico">
|
||||
</head>
|
||||
<body>
|
||||
@@ -263,7 +263,7 @@
|
||||
<!-- 脚本:BootCDN jQuery -->
|
||||
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
|
||||
<script src="js/config.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/artalk/2.9.1/Artalk.js"></script>
|
||||
<script src="https://cdn.bootcdn.net/ajax/libs/artalk/2.9.1/Artalk.js"></script>
|
||||
<script src="js/about.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
1317
css/about.css
1317
css/about.css
File diff suppressed because it is too large
Load Diff
67
js/about.js
67
js/about.js
@@ -117,20 +117,6 @@ class ThemeManager {
|
||||
=========================== */
|
||||
class DataManager {
|
||||
constructor() {
|
||||
// Fallback Data if APIs fail
|
||||
this.defaults = {
|
||||
repos: [
|
||||
{name: "yunxiao-LLM-reviewer", desc: "AI Code Reviewer based on LLM", stars: 9, url: "#"},
|
||||
{name: "hexo-theme-stellar", desc: "Comprehensive Hexo theme", stars: 5, url: "#"},
|
||||
{name: "Universal-IoT-Java", desc: "IoT Platform Demo", stars: 2, url: "#"}
|
||||
],
|
||||
posts: [
|
||||
{title: "Vector Database Guide", date: "2025-01-02", cat: "Tech", url: "#"},
|
||||
{title: "Spring Boot 3.0 Features", date: "2024-12-30", cat: "Java", url: "#"},
|
||||
{title: "Microservices Patterns", date: "2024-12-28", cat: "Arch", url: "#"}
|
||||
],
|
||||
user: { repos: 165, followers: 6, created: "2018-05-14" }
|
||||
};
|
||||
this.init();
|
||||
}
|
||||
|
||||
@@ -142,7 +128,7 @@ class DataManager {
|
||||
// 优先缓存 -> API -> 默认值
|
||||
async fetchGithub() {
|
||||
const user = (window.SiteConfig?.github?.username) || 'listener-He';
|
||||
const cacheKey = (window.SiteConfig?.github?.cache?.cacheKey) || 'gh_data_v2';
|
||||
const cacheKey = (window.SiteConfig?.cacheKeys?.github?.key) || 'gh_data_v2';
|
||||
const cached = JSON.parse(localStorage.getItem(cacheKey));
|
||||
const now = Date.now();
|
||||
|
||||
@@ -160,8 +146,8 @@ class DataManager {
|
||||
fetch(`https://api.github.com/users/${user}/repos?sort=stars&per_page=100`)
|
||||
]);
|
||||
|
||||
const userData = uRes.status === 'fulfilled' ? await uRes.value.json() : this.defaults.user;
|
||||
let repoData = rRes.status === 'fulfilled' ? await rRes.value.json() : this.defaults.repos;
|
||||
const userData = uRes.status === 'fulfilled' ? await uRes.value.json() : (window.SiteConfig?.defaults?.user);
|
||||
let repoData = rRes.status === 'fulfilled' ? await rRes.value.json() : (window.SiteConfig?.defaults?.repos);
|
||||
|
||||
// 过滤掉fork项目并按星数排序
|
||||
if (Array.isArray(repoData)) {
|
||||
@@ -180,38 +166,39 @@ class DataManager {
|
||||
|
||||
} catch (e) {
|
||||
console.warn("GH API Fail", e);
|
||||
this.renderUser(this.defaults.user);
|
||||
this.renderRepos(this.defaults.repos);
|
||||
this.renderUser(window.SiteConfig?.defaults?.user);
|
||||
this.renderRepos(window.SiteConfig?.defaults?.repos);
|
||||
}
|
||||
}
|
||||
|
||||
renderUser(data) {
|
||||
const years = new Date().getFullYear() - new Date(data.created_at || this.defaults.user.created).getFullYear();
|
||||
const years = new Date().getFullYear() - new Date(data.created_at || (window.SiteConfig?.defaults?.user?.created)).getFullYear();
|
||||
$('#coding-years').text(years + "+");
|
||||
$('#github-repos').text(data.public_repos || this.defaults.user.repos);
|
||||
$('#github-followers').text(data.followers || this.defaults.user.followers);
|
||||
$('#github-repos').text(data.public_repos || (window.SiteConfig?.defaults?.user?.repos));
|
||||
$('#github-followers').text(data.followers || (window.SiteConfig?.defaults?.user?.followers));
|
||||
}
|
||||
|
||||
renderRepos(list) {
|
||||
if(!Array.isArray(list)) list = this.defaults.repos;
|
||||
if(!Array.isArray(list)) list = window.SiteConfig?.defaults?.repos;
|
||||
let html = '';
|
||||
list.slice(0, 5).forEach(repo => {
|
||||
list.slice(0, 12).forEach(repo => {
|
||||
// Fix: API field compatibility
|
||||
const stars = repo.stargazers_count !== undefined ? repo.stargazers_count : (repo.stars || 0);
|
||||
const forks = repo.forks_count !== undefined ? repo.forks_count : (repo.forks || 0);
|
||||
const desc = repo.description || repo.desc || 'No description.';
|
||||
const url = repo.html_url || repo.url || '#';
|
||||
const dShort = (desc || '').length > 120 ? (desc.slice(0, 117) + '...') : desc;
|
||||
|
||||
html += `
|
||||
<div class="repo-card" onclick="window.open('${url}')">
|
||||
<div class="repo-head">
|
||||
<span>${repo.name}</span>
|
||||
<span class="gradient-text">${repo.name}</span>
|
||||
<span>
|
||||
<i class="ri-star-fill"></i> ${stars}
|
||||
<i class="ri-git-branch-fill"></i> ${forks}
|
||||
</span>
|
||||
</div>
|
||||
<div class="repo-desc">${desc}</div>
|
||||
<div class="repo-desc">${dShort}</div>
|
||||
</div>`;
|
||||
});
|
||||
$('#projects-container').html(html);
|
||||
@@ -220,7 +207,7 @@ class DataManager {
|
||||
// 从RSS获取博客文章
|
||||
async fetchBlog() {
|
||||
const rssUrl = window.SiteConfig?.blog?.rssUrl || 'https://blog.hehouhui.cn/api/rss';
|
||||
const cacheKey = window.SiteConfig?.blog?.cache?.key || 'blog_data_v2';
|
||||
const cacheKey = (window.SiteConfig?.cacheKeys?.blog?.key) || 'blog_data_v2';
|
||||
const cached = JSON.parse(localStorage.getItem(cacheKey));
|
||||
const now = Date.now();
|
||||
|
||||
@@ -279,7 +266,7 @@ class DataManager {
|
||||
this.renderBlog(data);
|
||||
} catch (e2) {
|
||||
console.warn("Local JSON Fail", e2);
|
||||
this.renderBlog(this.defaults.posts);
|
||||
this.renderBlog(window.SiteConfig?.defaults?.posts);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -371,10 +358,7 @@ class UIManager {
|
||||
const container = document.getElementById('tech-container');
|
||||
if(!container) return;
|
||||
|
||||
const techStackRaw = window.SiteConfig?.techStack || [
|
||||
{name:'Java'},{name:'Spring'},{name:'Docker'},{name:'K8s'},{name:'Python'},{name:'Redis'},
|
||||
{name:'React'},{name:'Vue'},{name:'MySQL'},{name:'MongoDB'},{name:'Linux'},{name:'Git'}
|
||||
];
|
||||
const techStackRaw = window.SiteConfig?.techStack || [];
|
||||
const techStack = techStackRaw.map((item, idx) => {
|
||||
const name = item.name || '';
|
||||
const hash = Array.from(name).reduce((a,c)=>a+c.charCodeAt(0),0);
|
||||
@@ -395,14 +379,10 @@ class UIManager {
|
||||
extendedTechStack.forEach((item, index) => {
|
||||
const el = document.createElement('span');
|
||||
el.className = 'tech-tag-mobile';
|
||||
// 添加不同颜色的渐变类
|
||||
const colorClass = `tag-color-${(index % 5) + 1}`;
|
||||
const colorClass = `tag-color-${item.gradientId || ((index % 10) + 1)}`;
|
||||
el.classList.add(colorClass);
|
||||
el.innerText = item.name;
|
||||
// 确保只显示文字,没有背景和边框
|
||||
el.style.background = 'none';
|
||||
el.style.border = 'none';
|
||||
el.style.color = 'transparent';
|
||||
container.appendChild(el);
|
||||
});
|
||||
} else {
|
||||
@@ -415,20 +395,16 @@ class UIManager {
|
||||
techStack.forEach((item, index) => {
|
||||
const el = document.createElement('a');
|
||||
el.className = 'tech-tag-3d';
|
||||
// 添加不同颜色的渐变类
|
||||
const colorClass = `tag-color-${(index % 5) + 1}`;
|
||||
const colorClass = `tag-color-${item.gradientId || ((index % 10) + 1)}`;
|
||||
el.classList.add(colorClass);
|
||||
el.innerText = item.name;
|
||||
// 移除背景和边框样式,只保留文字
|
||||
el.style.background = 'none';
|
||||
el.style.border = 'none';
|
||||
el.style.color = 'transparent';
|
||||
container.appendChild(el);
|
||||
tags.push({ el, x:0, y:0, z:0 });
|
||||
});
|
||||
|
||||
// 增大球体半径以避免标签重叠
|
||||
let radius = 300;
|
||||
// 动态半径,避免容器溢出
|
||||
let radius = Math.max(160, Math.min(container.offsetWidth, container.offsetHeight) / 2 - 24);
|
||||
const dtr = Math.PI/180;
|
||||
let lasta=1, lastb=1;
|
||||
let active=false, mouseX=0, mouseY=0;
|
||||
@@ -471,7 +447,8 @@ class UIManager {
|
||||
let rx2=rx1*cb + rz1*sb, ry2=ry1, rz2=rx1*-sb + rz1*cb;
|
||||
tag.x=rx2; tag.y=ry2; tag.z=rz2;
|
||||
|
||||
let scale = (tag.z + radius)/(2*radius) + 0.5;
|
||||
let scale = (tag.z + radius)/(2*radius) + 0.45;
|
||||
scale = Math.min(Math.max(scale, 0.7), 1.15);
|
||||
let opacity = (tag.z + radius)/(2*radius) + 0.2;
|
||||
|
||||
tag.el.style.opacity = Math.min(Math.max(opacity, 0.1), 1);
|
||||
|
||||
44
js/config.js
44
js/config.js
@@ -62,6 +62,12 @@ const SiteConfig = {
|
||||
expirationDays: 1
|
||||
}
|
||||
},
|
||||
|
||||
// 通用缓存键与TTL(毫秒)
|
||||
cacheKeys: {
|
||||
github: { key: 'gh_data_v2', ttlMs: 3600000 },
|
||||
blog: { key: 'blog_data_v2', ttlMs: 3600000 }
|
||||
},
|
||||
|
||||
techStack: [
|
||||
{ name: 'Java', category: 'core', weight: 5 },
|
||||
@@ -103,6 +109,21 @@ const SiteConfig = {
|
||||
{ name: 'ClickHouse', category: 'data', weight: 1 },
|
||||
{ name: 'Postgresql', category: 'data', weight: 1 }
|
||||
],
|
||||
|
||||
// 默认数据(当API或RSS不可用时使用)
|
||||
defaults: {
|
||||
repos: [
|
||||
{name: "yunxiao-LLM-reviewer", desc: "AI Code Reviewer based on LLM", stars: 9, url: "#"},
|
||||
{name: "hexo-theme-stellar", desc: "Comprehensive Hexo theme", stars: 5, url: "#"},
|
||||
{name: "Universal-IoT-Java", desc: "IoT Platform Demo", stars: 2, url: "#"}
|
||||
],
|
||||
posts: [
|
||||
{title: "Vector Database Guide", date: "2025-01-02", cat: "Tech", url: "#"},
|
||||
{title: "Spring Boot 3.0 Features", date: "2024-12-30", cat: "Java", url: "#"},
|
||||
{title: "Microservices Patterns", date: "2024-12-28", cat: "Arch", url: "#"}
|
||||
],
|
||||
user: { repos: 165, followers: 6, created: "2018-05-14" }
|
||||
},
|
||||
|
||||
socialCards: {
|
||||
rings: [130, 180, 230],
|
||||
@@ -136,13 +157,26 @@ const SiteConfig = {
|
||||
};
|
||||
|
||||
if (Array.isArray(SiteConfig.techStack)) {
|
||||
SiteConfig.techStack = SiteConfig.techStack.map((item, idx) => {
|
||||
const categoryGradientMap = {
|
||||
core: 7,
|
||||
backend: 4,
|
||||
data: 9,
|
||||
ops: 10,
|
||||
ai: 3
|
||||
};
|
||||
const vividSet = [1, 4, 7, 8];
|
||||
|
||||
SiteConfig.techStack = SiteConfig.techStack.map((item) => {
|
||||
const name = item.name || '';
|
||||
const hash = Array.from(name).reduce((a, c) => a + c.charCodeAt(0), 0);
|
||||
const gid = (item.gradientId && Number.isFinite(Number(item.gradientId)))
|
||||
? Math.max(1, Math.min(10, Number(item.gradientId)))
|
||||
: (hash % 10) + 1;
|
||||
return { ...item, gradientId: gid };
|
||||
if (item.gradientId && Number.isFinite(Number(item.gradientId))) {
|
||||
return { ...item, gradientId: Math.max(1, Math.min(10, Number(item.gradientId))) };
|
||||
}
|
||||
let base = categoryGradientMap[item.category] || ((hash % 10) + 1);
|
||||
if (Number(item.weight) >= 5) {
|
||||
base = vividSet[hash % vividSet.length];
|
||||
}
|
||||
return { ...item, gradientId: base };
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user