Compare commits
41 Commits
version-2.
...
version-2.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
532cbafd8e | ||
|
|
30e13e5bde | ||
|
|
41184ad1d8 | ||
|
|
bff0b529d2 | ||
|
|
b179431aaa | ||
|
|
569ad36db1 | ||
|
|
d0cd750e22 | ||
|
|
ccda6074be | ||
|
|
1b94b8bf93 | ||
|
|
9a73273c34 | ||
|
|
ea04260290 | ||
|
|
9c8a1f035f | ||
|
|
a4cd5d6535 | ||
|
|
c2585ea504 | ||
|
|
3589df9032 | ||
|
|
99d5420024 | ||
|
|
f66c17095b | ||
|
|
86468a9f77 | ||
|
|
0c55a90662 | ||
|
|
0eac618a71 | ||
|
|
200da80262 | ||
|
|
753f12e5d9 | ||
|
|
50fcc7454d | ||
|
|
747021c259 | ||
|
|
9f0d3d0a2a | ||
|
|
ac6c85a490 | ||
|
|
7f959b1b34 | ||
|
|
d3cd2b69fe | ||
|
|
eec6778f8d | ||
|
|
0fbfd7b6dd | ||
|
|
ace68a0bad | ||
|
|
01e55e6d82 | ||
|
|
f9a1587587 | ||
|
|
cea62b1c77 | ||
|
|
c293d31969 | ||
|
|
20b46b9fd2 | ||
|
|
b606b54d9b | ||
|
|
ff78d2c8b4 | ||
|
|
14e669178e | ||
|
|
d8290974b5 | ||
|
|
56d260e0d6 |
@@ -139,7 +139,7 @@ Home/
|
|||||||
|
|
||||||
## 🚀 快速开始
|
## 🚀 快速开始
|
||||||
|
|
||||||
``shell
|
```shell
|
||||||
# 克隆项目
|
# 克隆项目
|
||||||
git clone https://github.com/listener-He/Home.git
|
git clone https://github.com/listener-He/Home.git
|
||||||
|
|
||||||
@@ -181,7 +181,7 @@ open about.html
|
|||||||
- [x] 添加骨架屏加载效果
|
- [x] 添加骨架屏加载效果
|
||||||
- [x] 实现数据缓存机制,提升页面加载速度
|
- [x] 实现数据缓存机制,提升页面加载速度
|
||||||
- [x] 添加淡入动画效果,提升用户体验
|
- [x] 添加淡入动画效果,提升用户体验
|
||||||
- [x] 实现 PWA 支持,支持离线访问
|
|
||||||
|
|
||||||
### 待完成
|
### 待完成
|
||||||
- [ ] 添加更多数据源(如 Twitter、知乎等)
|
- [ ] 添加更多数据源(如 Twitter、知乎等)
|
||||||
@@ -193,6 +193,7 @@ open about.html
|
|||||||
- [ ] 添加更多主题选项(如高对比度模式等)
|
- [ ] 添加更多主题选项(如高对比度模式等)
|
||||||
- [ ] 实现深色模式下的图片优化处理
|
- [ ] 实现深色模式下的图片优化处理
|
||||||
- [ ] 添加无障碍访问支持(ARIA 属性完善)
|
- [ ] 添加无障碍访问支持(ARIA 属性完善)
|
||||||
|
- [ ] 实现 PWA 支持,支持离线访问
|
||||||
|
|
||||||
## 🙏 鸣谢与致敬
|
## 🙏 鸣谢与致敬
|
||||||
|
|
||||||
|
|||||||
145
about.html
@@ -1,17 +1,16 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="zh-CN">
|
<html lang="zh-CN" data-lang="zh">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover">
|
||||||
<title>关于我 - Honesty</title>
|
<title>关于我 - Honesty</title>
|
||||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||||
<!-- PWA相关配置 -->
|
|
||||||
<meta name="theme-color" content="#6c5ce7">
|
|
||||||
<link rel="manifest" href="./manifest.json">
|
|
||||||
|
|
||||||
<!--SEO信息 -->
|
<!--SEO信息 -->
|
||||||
<meta name="description" content="关于Honesty,关于HeHouHui,关于HeHui,关于明厚, About Me Honesty, About Me HeHouHui, About Me HeHui">
|
<meta name="description" content="关于Honesty,关于HeHouHui,关于HeHui,关于明厚, About Me Honesty, About Me HeHouHui, About Me HeHui">
|
||||||
<meta name="keywords" content="Honesty,HeHouHui,HeHui,明厚">
|
<meta name="keywords" content="Honesty,HeHouHui,HeHui,明厚">
|
||||||
|
<link rel="canonical" href="https://www.hehouhui.cn/about.html">
|
||||||
<meta name="author" content="Honesty">
|
<meta name="author" content="Honesty">
|
||||||
|
|
||||||
<!-- 社交平台分享优化 -->
|
<!-- 社交平台分享优化 -->
|
||||||
@@ -22,6 +21,7 @@
|
|||||||
<meta property="og:description" content="我是一名充满热情的Java后端开发工程师,专注于AI技术的探索与应用。来自湖南,现在上海工作,享受在这座充满活力的城市中追求技术梦想。">
|
<meta property="og:description" content="我是一名充满热情的Java后端开发工程师,专注于AI技术的探索与应用。来自湖南,现在上海工作,享受在这座充满活力的城市中追求技术梦想。">
|
||||||
<meta property="og:image" content="https://www.hehouhui.cn/images/avatar.jpeg">
|
<meta property="og:image" content="https://www.hehouhui.cn/images/avatar.jpeg">
|
||||||
<meta property="og:site_name" content="Honesty的个人主页">
|
<meta property="og:site_name" content="Honesty的个人主页">
|
||||||
|
<meta property="og:locale" content="zh_CN">
|
||||||
|
|
||||||
<!-- Twitter -->
|
<!-- Twitter -->
|
||||||
<meta property="twitter:card" content="summary_large_image">
|
<meta property="twitter:card" content="summary_large_image">
|
||||||
@@ -30,6 +30,9 @@
|
|||||||
<meta property="twitter:description" content="我是一名充满热情的Java后端开发工程师,专注于AI技术的探索与应用。来自湖南,现在上海工作,享受在这座充满活力的城市中追求技术梦想。">
|
<meta property="twitter:description" content="我是一名充满热情的Java后端开发工程师,专注于AI技术的探索与应用。来自湖南,现在上海工作,享受在这座充满活力的城市中追求技术梦想。">
|
||||||
<meta property="twitter:image" content="https://www.hehouhui.cn/images/avatar.jpeg">
|
<meta property="twitter:image" content="https://www.hehouhui.cn/images/avatar.jpeg">
|
||||||
<meta property="twitter:site" content="@Honesty861024">
|
<meta property="twitter:site" content="@Honesty861024">
|
||||||
|
<link rel="alternate" hreflang="zh-cn" href="https://www.hehouhui.cn/about.html">
|
||||||
|
<link rel="alternate" hreflang="en" href="https://www.hehouhui.cn/about.html?lang=en">
|
||||||
|
<link rel="alternate" hreflang="x-default" href="https://www.hehouhui.cn/about.html">
|
||||||
|
|
||||||
<!-- 微信小程序/朋友圈分享 -->
|
<!-- 微信小程序/朋友圈分享 -->
|
||||||
<meta property="wechat:image" content="https://www.hehouhui.cn/images/avatar.jpeg">
|
<meta property="wechat:image" content="https://www.hehouhui.cn/images/avatar.jpeg">
|
||||||
@@ -39,7 +42,6 @@
|
|||||||
<!-- 核心资源:使用 BootCDN 加速 -->
|
<!-- 核心资源:使用 BootCDN 加速 -->
|
||||||
<link href="https://cdn.bootcdn.net/ajax/libs/normalize/8.0.1/normalize.min.css" rel="stylesheet">
|
<link href="https://cdn.bootcdn.net/ajax/libs/normalize/8.0.1/normalize.min.css" rel="stylesheet">
|
||||||
<link href="https://cdn.bootcdn.net/ajax/libs/remixicon/3.5.0/remixicon.min.css" rel="stylesheet">
|
<link href="https://cdn.bootcdn.net/ajax/libs/remixicon/3.5.0/remixicon.min.css" rel="stylesheet">
|
||||||
<link rel="stylesheet" href="css/style.css?version=20251125">
|
|
||||||
<link rel="stylesheet" href="css/about.css?version=20251125">
|
<link rel="stylesheet" href="css/about.css?version=20251125">
|
||||||
<!-- Artalk 评论样式 -->
|
<!-- Artalk 评论样式 -->
|
||||||
<link rel="stylesheet" href="https://cdn.bootcdn.net/ajax/libs/artalk/2.9.1/Artalk.css">
|
<link rel="stylesheet" href="https://cdn.bootcdn.net/ajax/libs/artalk/2.9.1/Artalk.css">
|
||||||
@@ -87,11 +89,11 @@
|
|||||||
<div class="nav-divider"></div>
|
<div class="nav-divider"></div>
|
||||||
|
|
||||||
<!-- 功能按钮 -->
|
<!-- 功能按钮 -->
|
||||||
<button id="lang-btn" class="action-btn" aria-label="Switch Language">
|
<button id="lang-btn" class="action-btn" aria-label="Switch Language" tabindex="0">
|
||||||
<i class="ri-translate-2"></i>
|
<i class="ri-translate-2"></i>
|
||||||
<span class="btn-text">CN/EN</span>
|
<span class="btn-text">CN/EN</span>
|
||||||
</button>
|
</button>
|
||||||
<button id="theme-btn" class="action-btn" aria-label="Toggle Theme">
|
<button id="theme-btn" class="action-btn" aria-label="Toggle Theme" tabindex="0">
|
||||||
<i class="ri-sun-line icon-sun"></i>
|
<i class="ri-sun-line icon-sun"></i>
|
||||||
<i class="ri-moon-line icon-moon"></i>
|
<i class="ri-moon-line icon-moon"></i>
|
||||||
</button>
|
</button>
|
||||||
@@ -108,7 +110,7 @@
|
|||||||
<div class="bento-card area-profile">
|
<div class="bento-card area-profile">
|
||||||
<div class="profile-content">
|
<div class="profile-content">
|
||||||
<div class="avatar-ring">
|
<div class="avatar-ring">
|
||||||
<img src="images/avatar.jpeg" alt="Honesty" class="avatar-img">
|
<img src="images/avatar.jpeg" alt="Honesty" class="avatar-img" loading="lazy">
|
||||||
<div class="status-dot" data-i18n="status.online">Online</div>
|
<div class="status-dot" data-i18n="status.online">Online</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="profile-info">
|
<div class="profile-info">
|
||||||
@@ -120,12 +122,12 @@
|
|||||||
</div>
|
</div>
|
||||||
<!-- 6个社交链接 (PC端显示) -->
|
<!-- 6个社交链接 (PC端显示) -->
|
||||||
<div class="social-dock desktop-social">
|
<div class="social-dock desktop-social">
|
||||||
<a href="https://github.com/listener-He" target="_blank" class="s-icon"><i class="ri-github-fill"></i></a>
|
<a href="https://github.com/listener-He" target="_blank" class="s-icon" aria-label="GitHub profile" tabindex="0"><i class="ri-github-fill"></i></a>
|
||||||
<a href="mailto:hehouhui@foxmail.com" class="s-icon"><i class="ri-mail-send-fill"></i></a>
|
<a href="mailto:hehouhui@foxmail.com" class="s-icon" aria-label="Email contact" tabindex="0"><i class="ri-mail-send-fill"></i></a>
|
||||||
<a href="https://blog.hehouhui.cn" target="_blank" class="s-icon"><i class="ri-pages-line"></i></a>
|
<a href="https://twitter.com/Honesty861024" target="_blank" class="s-icon" aria-label="Twitter profile" tabindex="0"><i class="ri-twitter-line"></i></a>
|
||||||
<a href="https://www.zhihu.com/people/wen-xin-92-2-57" target="_blank" class="s-icon"><i class="ri-zhihu-line"></i></a>
|
<a href="https://www.zhihu.com/people/wen-xin-92-2-57" target="_blank" class="s-icon" aria-label="Zhihu profile" tabindex="0"><i class="ri-zhihu-line"></i></a>
|
||||||
<a href="javascript:void(0);" onclick="toggleWechat()" class="s-icon"><i class="ri-wechat-fill"></i></a>
|
<a href="javascript:void(0);" onclick="toggleWechat()" class="s-icon" aria-label="WeChat QR code" tabindex="0"><i class="ri-wechat-fill"></i></a>
|
||||||
<a href="https://juejin.cn/user/3659591622878503" target="_blank" class="s-icon"><i class="ri-code-box-line"></i></a>
|
<a href="https://juejin.cn/user/3659591622878503" target="_blank" class="s-icon" aria-label="Juejin profile" tabindex="0"><i class="ri-code-box-line"></i></a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -157,11 +159,11 @@
|
|||||||
<span class="stat-key" data-i18n="stats.followers">Followers</span>
|
<span class="stat-key" data-i18n="stats.followers">Followers</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="stat-item">
|
<div class="stat-item">
|
||||||
<span class="stat-val neon-font" id="busuanzi_value_site_pv">0</span>
|
<span class="stat-val neon-font" id="busuanzi_site_pv">0</span>
|
||||||
<span class="stat-key" data-i18n="stats.visitNum">Visit num</span>
|
<span class="stat-key" data-i18n="stats.visitNum">Visit num</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="stat-item">
|
<div class="stat-item">
|
||||||
<span class="stat-val neon-font" id="busuanzi_value_site_uv">0</span>
|
<span class="stat-val neon-font" id="busuanzi_site_uv">0</span>
|
||||||
<span class="stat-key" data-i18n="stats.visitors">Visitors</span>
|
<span class="stat-key" data-i18n="stats.visitors">Visitors</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -173,7 +175,7 @@
|
|||||||
<span class="mbti-code gradient-text">INFJ</span>
|
<span class="mbti-code gradient-text">INFJ</span>
|
||||||
<span class="mbti-name" data-i18n="mbti.name">Advocate</span>
|
<span class="mbti-name" data-i18n="mbti.name">Advocate</span>
|
||||||
<span class="mbti-icon">
|
<span class="mbti-icon">
|
||||||
<img src="images/INFJ.png" alt="INFJ" style="width:32px;height:32px;border-radius:50%;border:2px solid rgba(255,255,255,0.4)"/>
|
<img src="images/INFJ.webp" alt="INFJ" style="width:32px;height:32px;border-radius:50%;border:2px solid rgba(255,255,255,0.4)" loading="lazy"/>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<p class="mbti-desc" data-i18n="mbti.desc">"理想主义与道德感,果断决绝的行动力。深度洞察与创意,关怀与同理心。"</p>
|
<p class="mbti-desc" data-i18n="mbti.desc">"理想主义与道德感,果断决绝的行动力。深度洞察与创意,关怀与同理心。"</p>
|
||||||
@@ -238,12 +240,12 @@
|
|||||||
|
|
||||||
<!-- 移动端显示的社交栏 (6个链接) -->
|
<!-- 移动端显示的社交栏 (6个链接) -->
|
||||||
<div class="bento-card area-social-mobile mobile-social">
|
<div class="bento-card area-social-mobile mobile-social">
|
||||||
<a href="https://github.com/listener-He" class="ms-btn"><i class="ri-github-fill"></i></a>
|
<a href="https://github.com/listener-He" class="ms-btn" aria-label="GitHub profile" tabindex="0"><i class="ri-github-fill"></i></a>
|
||||||
<a href="mailto:hehouhui@foxmail.com" class="ms-btn"><i class="ri-mail-send-fill"></i></a>
|
<a href="mailto:hehouhui@foxmail.com" class="ms-btn" aria-label="Email contact" tabindex="0"><i class="ri-mail-send-fill"></i></a>
|
||||||
<a href="https://blog.hehouhui.cn" class="ms-btn"><i class="ri-pages-line"></i></a>
|
<a href="https://twitter.com/Honesty861024" class="ms-btn" aria-label="Twitter profile" tabindex="0"><i class="ri-twitter-line"></i></a>
|
||||||
<a href="https://www.zhihu.com/people/wen-xin-92-2-57" class="ms-btn"><i class="ri-zhihu-line"></i></a>
|
<a href="https://www.zhihu.com/people/wen-xin-92-2-57" class="ms-btn" aria-label="Zhihu profile" tabindex="0"><i class="ri-zhihu-line"></i></a>
|
||||||
<a href="javascript:void(0);" onclick="toggleWechat()" class="ms-btn"><i class="ri-wechat-fill"></i></a>
|
<a href="javascript:void(0);" onclick="toggleWechat()" class="ms-btn" aria-label="WeChat QR code" tabindex="0"><i class="ri-wechat-fill"></i></a>
|
||||||
<a href="https://juejin.cn/user/3659591622878503" class="ms-btn"><i class="ri-code-box-line"></i></a>
|
<a href="https://juejin.cn/user/3659591622878503" class="ms-btn" aria-label="Juejin profile" tabindex="0"><i class="ri-code-box-line"></i></a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -292,14 +294,15 @@
|
|||||||
|
|
||||||
<!-- 移动端悬浮功能按钮 -->
|
<!-- 移动端悬浮功能按钮 -->
|
||||||
<div class="mobile-fab">
|
<div class="mobile-fab">
|
||||||
<button id="fab-main" class="fab-main" aria-label="Actions"><i class="ri-magic-line"></i><span class="fab-label">Tools</span></button>
|
<button id="fab-main" class="fab-main" aria-label="Actions" tabindex="0"><i class="ri-magic-line"></i><span class="fab-label">Tools</span></button>
|
||||||
<div class="fab-menu" id="fab-menu">
|
<div class="fab-menu" id="fab-menu">
|
||||||
<button id="fab-lang" class="fab-item"><i class="ri-translate-2"></i><span class="fab-text">Lang</span></button>
|
<button id="fab-lang" class="fab-item" tabindex="0"><i class="ri-translate-2"></i><span class="fab-text">Lang</span></button>
|
||||||
<button id="fab-theme" class="fab-item"><i class="ri-moon-line"></i><span class="fab-text">Theme</span></button>
|
<button id="fab-theme" class="fab-item" tabindex="0"><i class="ri-moon-line"></i><span class="fab-text">Theme</span></button>
|
||||||
<button id="fab-music" class="fab-item"><i class="ri-music-2-line"></i><span class="fab-text">Play</span></button>
|
<button id="fab-music" class="fab-item" tabindex="0"><i class="ri-music-2-line"></i><span class="fab-text">Play</span></button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<audio id="site-audio" class="site-audio" src="data/至少做一件离谱的事-Kiri T.mp3" autoplay loop preload="auto"></audio>
|
<!-- 隐藏的音频播放iframe -->
|
||||||
|
<iframe id="audio-player-iframe" src="audio-player.html" style="display: none;"></iframe>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
<!-- 微信弹窗 -->
|
<!-- 微信弹窗 -->
|
||||||
@@ -308,7 +311,7 @@
|
|||||||
<button class="modal-close" onclick="toggleWechat()"><i class="ri-close-line"></i></button>
|
<button class="modal-close" onclick="toggleWechat()"><i class="ri-close-line"></i></button>
|
||||||
<h3 data-i18n="modal.wechat">Official Account</h3>
|
<h3 data-i18n="modal.wechat">Official Account</h3>
|
||||||
<div class="qr-box">
|
<div class="qr-box">
|
||||||
<img src="https://blog-file.hehouhui.cn/wechat/mp-honesy.jpg" alt="WeChat QR" onerror="this.style.display='none';this.nextElementSibling.style.display='block'">
|
<img src="./images/mp-honesy.jpg" alt="WeChat QR" onerror="this.style.display='none';this.nextElementSibling.style.display='block'" loading="lazy">
|
||||||
<!-- <div class="qr-fallback">QR Load Failed</div>-->
|
<!-- <div class="qr-fallback">QR Load Failed</div>-->
|
||||||
</div>
|
</div>
|
||||||
<p data-i18n="modal.desc">Scan to follow Tech Share</p>
|
<p data-i18n="modal.desc">Scan to follow Tech Share</p>
|
||||||
@@ -316,7 +319,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<footer class="site-footer">
|
<footer class="site-footer">
|
||||||
<p>© 2018 <span id="currentYear"></span> Honesty. All rights reserved. <a class="icp" href="https://beian.miit.gov.cn/" target="_blank">湘ICP备20014902号</a> Powered By <a href="https://pages.edgeone.ai/" target="_blank"> Tencent EdgeOne </a></p>
|
<p>Copyright © 2018 <span id="currentYear"></span> Honesty. All rights reserved. <a class="icp" href="https://beian.miit.gov.cn/" target="_blank">湘ICP备20014902号</a> Powered By <a href="https://pages.edgeone.ai/" target="_blank"> Tencent EdgeOne </a></p>
|
||||||
<script>
|
<script>
|
||||||
document.getElementById("currentYear").textContent = ' - ' + new Date().getFullYear();
|
document.getElementById("currentYear").textContent = ' - ' + new Date().getFullYear();
|
||||||
</script>
|
</script>
|
||||||
@@ -324,12 +327,9 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 脚本:BootCDN jQuery / Artalk -->
|
<!-- 脚本:BootCDN jQuery / Artalk -->
|
||||||
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
|
<script src="js/jquery.min.js"></script>
|
||||||
<script src="js/config.js?version=20251125"></script>
|
<script src="js/config.js?version=20251125"></script>
|
||||||
<script src="https://cdn.bootcdn.net/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="https://cdn.jsdelivr.net/npm/artalk@latest/dist/i18n/zh-cn.js"></script>
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/artalk@latest/dist/i18n/en.js"></script>
|
|
||||||
<script src="js/about.js?version=20251125"></script>
|
<script src="js/about.js?version=20251125"></script>
|
||||||
|
|
||||||
<!-- 不蒜子统计 -->
|
<!-- 不蒜子统计 -->
|
||||||
@@ -368,53 +368,24 @@
|
|||||||
|
|
||||||
<!-- 自动格式化脚本 -->
|
<!-- 自动格式化脚本 -->
|
||||||
<script>
|
<script>
|
||||||
// 核心格式化函数:支持 K / W / M,保留最多两位小数,去除尾随零
|
// 监听不蒜子数据的错误兜底
|
||||||
function formatWithUnit(num) {
|
|
||||||
num = Number(num);
|
|
||||||
if (isNaN(num) || num < 0) return '0';
|
|
||||||
|
|
||||||
// 小于 1000:直接显示
|
|
||||||
if (num < 1_000) {
|
|
||||||
return Math.floor(num).toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 1K ~ 9.99K
|
|
||||||
if (num < 10_000) {
|
|
||||||
let val = (num / 1_000).toFixed(2);
|
|
||||||
return parseFloat(val) + 'K';
|
|
||||||
}
|
|
||||||
|
|
||||||
// 1W ~ 99.99W (1W = 10,000)
|
|
||||||
if (num < 1_000_000) {
|
|
||||||
let val = (num / 10_000).toFixed(2);
|
|
||||||
return parseFloat(val) + 'W';
|
|
||||||
}
|
|
||||||
|
|
||||||
// ≥ 1M
|
|
||||||
let val = (num / 1_000_000).toFixed(2);
|
|
||||||
return parseFloat(val) + 'M';
|
|
||||||
}
|
|
||||||
|
|
||||||
// 监听不蒜子数据更新并格式化
|
|
||||||
function initFormatter() {
|
function initFormatter() {
|
||||||
const pvEl = document.getElementById(SiteConfig.analytics.busuanzi.site_pv_id);
|
const pvEl = document.getElementById(SiteConfig.analytics.busuanzi.site_pv_id);
|
||||||
const uvEl = document.getElementById(SiteConfig.analytics.busuanzi.site_uv_id);
|
const uvEl = document.getElementById(SiteConfig.analytics.busuanzi.site_uv_id);
|
||||||
|
|
||||||
if (!pvEl && !uvEl) return;
|
if (!pvEl && !uvEl) return;
|
||||||
|
console.log('[Busuanzi]', 'Formatting... Listener observer');
|
||||||
const observer = new MutationObserver(() => {
|
const observer = new MutationObserver(() => {
|
||||||
if (pvEl?.textContent) {
|
if (pvEl?.textContent) {
|
||||||
const raw = pvEl.textContent.trim().replace(/[,,]/g, '');
|
if (pvEl.textContent.includes('禁用')) {
|
||||||
const num = parseFloat(raw);
|
pvEl.textContent = '-';
|
||||||
if (!isNaN(num)) {
|
return;
|
||||||
pvEl.textContent = formatWithUnit(num);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (uvEl?.textContent) {
|
if (uvEl?.textContent) {
|
||||||
const raw = uvEl.textContent.trim().replace(/[,,]/g, '');
|
if (uvEl.textContent.includes('禁用')) {
|
||||||
const num = parseFloat(raw);
|
uvEl.textContent = '-';
|
||||||
if (!isNaN(num)) {
|
return;
|
||||||
uvEl.textContent = formatWithUnit(num);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -430,37 +401,5 @@
|
|||||||
initFormatter();
|
initFormatter();
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<!-- PWA注册 -->
|
|
||||||
<script>
|
|
||||||
if ('serviceWorker' in navigator) {
|
|
||||||
window.addEventListener('load', function() {
|
|
||||||
setTimeout(() => {
|
|
||||||
navigator.serviceWorker.register('./js/sw.js')
|
|
||||||
.then(function(registration) {
|
|
||||||
console.log('SW registered: ', registration);
|
|
||||||
})
|
|
||||||
.catch(function(registrationError) {
|
|
||||||
console.log('SW registration failed: ', registrationError);
|
|
||||||
});
|
|
||||||
}, 3000); // 页面稳定后再注册
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- Apple PWA支持 -->
|
|
||||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
|
||||||
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
|
|
||||||
<meta name="apple-mobile-web-app-title" content="Honesty">
|
|
||||||
<link rel="apple-touch-icon" href="./images/avatar.jpeg">
|
|
||||||
|
|
||||||
<!-- Windows PWA支持 -->
|
|
||||||
<meta name="msapplication-TileImage" content="./images/avatar.jpeg">
|
|
||||||
<meta name="msapplication-TileColor" content="#6c5ce7">
|
|
||||||
<meta name="msapplication-tap-highlight" content="no">
|
|
||||||
|
|
||||||
<!-- 其他PWA相关meta标签 -->
|
|
||||||
<meta name="mobile-web-app-capable" content="yes">
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
208
audio-player.html
Normal file
@@ -0,0 +1,208 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Audio Player</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<audio id="audio-player" controls autoplay style="display: none;"></audio>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const audio = document.getElementById('audio-player');
|
||||||
|
let currentSrc = '';
|
||||||
|
let isStateBroadcasting = false;
|
||||||
|
|
||||||
|
// 监听来自主页面的消息
|
||||||
|
window.addEventListener('message', function(event) {
|
||||||
|
// 允许来自同域的所有窗口的消息
|
||||||
|
if (event.origin !== window.location.origin) return;
|
||||||
|
|
||||||
|
const data = event.data;
|
||||||
|
|
||||||
|
switch (data.action) {
|
||||||
|
case 'play':
|
||||||
|
// 如果当前正在播放,则暂停;否则播放
|
||||||
|
if (audio.paused) {
|
||||||
|
audio.play().catch(e => console.error('播放失败:', e));
|
||||||
|
} else {
|
||||||
|
audio.pause();
|
||||||
|
}
|
||||||
|
// 发送状态更新回所有可能的窗口
|
||||||
|
broadcastState();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'pause':
|
||||||
|
if (!audio.paused) {
|
||||||
|
audio.pause();
|
||||||
|
}
|
||||||
|
broadcastState();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'setTrack':
|
||||||
|
if (currentSrc !== data.src) {
|
||||||
|
currentSrc = data.src;
|
||||||
|
audio.src = data.src;
|
||||||
|
audio.load();
|
||||||
|
// 自动播放新曲目
|
||||||
|
setTimeout(() => {
|
||||||
|
audio.play().catch(e => console.error('播放失败:', e));
|
||||||
|
broadcastState();
|
||||||
|
}, 100);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'setVolume':
|
||||||
|
audio.volume = data.volume;
|
||||||
|
broadcastState();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'getCurrentState':
|
||||||
|
// 向请求方发送当前状态
|
||||||
|
event.source.postMessage({
|
||||||
|
action: 'currentState',
|
||||||
|
playing: !audio.paused,
|
||||||
|
src: audio.src,
|
||||||
|
volume: audio.volume,
|
||||||
|
currentTime: audio.currentTime,
|
||||||
|
duration: audio.duration || 0
|
||||||
|
}, event.origin);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 广播状态到所有可能监听的窗口
|
||||||
|
function broadcastState() {
|
||||||
|
if (isStateBroadcasting) return; // 防止状态广播循环
|
||||||
|
|
||||||
|
isStateBroadcasting = true;
|
||||||
|
window.parent.postMessage({
|
||||||
|
action: 'stateChange',
|
||||||
|
playing: !audio.paused,
|
||||||
|
src: audio.src,
|
||||||
|
volume: audio.volume,
|
||||||
|
currentTime: audio.currentTime,
|
||||||
|
duration: audio.duration || 0
|
||||||
|
}, '*');
|
||||||
|
|
||||||
|
// 保存播放状态
|
||||||
|
savePlaybackState();
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
isStateBroadcasting = false;
|
||||||
|
}, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 监听音频事件并通知主页面
|
||||||
|
audio.addEventListener('play', function() {
|
||||||
|
broadcastState();
|
||||||
|
});
|
||||||
|
|
||||||
|
audio.addEventListener('pause', function() {
|
||||||
|
broadcastState();
|
||||||
|
});
|
||||||
|
|
||||||
|
audio.addEventListener('ended', function() {
|
||||||
|
window.parent.postMessage({
|
||||||
|
action: 'trackEnded'
|
||||||
|
}, '*');
|
||||||
|
});
|
||||||
|
|
||||||
|
// 页面加载完成后通知主页面
|
||||||
|
window.addEventListener('load', function() {
|
||||||
|
// 恢复之前保存的播放状态
|
||||||
|
restorePlaybackState();
|
||||||
|
|
||||||
|
window.parent.postMessage({
|
||||||
|
action: 'playerReady'
|
||||||
|
}, '*');
|
||||||
|
});
|
||||||
|
|
||||||
|
// 页面可见性变化时处理
|
||||||
|
document.addEventListener('visibilitychange', function() {
|
||||||
|
if (!document.hidden) {
|
||||||
|
// 页面变为可见时,广播当前状态
|
||||||
|
setTimeout(broadcastState, 100);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 页面即将卸载时保存播放状态
|
||||||
|
window.addEventListener('beforeunload', function() {
|
||||||
|
savePlaybackState();
|
||||||
|
});
|
||||||
|
|
||||||
|
// 保存播放状态到 sessionStorage
|
||||||
|
function savePlaybackState() {
|
||||||
|
try {
|
||||||
|
sessionStorage.setItem('audioState', JSON.stringify({
|
||||||
|
src: audio.src,
|
||||||
|
currentTime: audio.currentTime,
|
||||||
|
playing: !audio.paused,
|
||||||
|
volume: audio.volume,
|
||||||
|
timestamp: Date.now()
|
||||||
|
}));
|
||||||
|
} catch (e) {
|
||||||
|
console.error('保存音频状态失败:', e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从 sessionStorage 恢复播放状态
|
||||||
|
function restorePlaybackState() {
|
||||||
|
try {
|
||||||
|
const savedState = sessionStorage.getItem('audioState');
|
||||||
|
if (savedState) {
|
||||||
|
const state = JSON.parse(savedState);
|
||||||
|
// 如果状态保存时间不超过1小时,则恢复播放
|
||||||
|
if (Date.now() - state.timestamp < 3600000) {
|
||||||
|
currentSrc = state.src;
|
||||||
|
audio.src = state.src;
|
||||||
|
audio.volume = state.volume !== undefined ? state.volume : 1.0;
|
||||||
|
audio.currentTime = state.currentTime || 0;
|
||||||
|
|
||||||
|
// 确保在用户交互后才尝试播放
|
||||||
|
if (state.playing) {
|
||||||
|
// 检查是否已经有用户交互
|
||||||
|
if (document.hasFocus()) {
|
||||||
|
// 稍微延迟播放,确保一切准备就绪
|
||||||
|
setTimeout(() => {
|
||||||
|
audio.play().catch(e => {
|
||||||
|
console.error('恢复播放失败:', e);
|
||||||
|
// 如果自动播放失败,等待用户交互后再播放
|
||||||
|
const tryPlayOnInteraction = () => {
|
||||||
|
audio.play().catch(console.error);
|
||||||
|
document.removeEventListener('click', tryPlayOnInteraction);
|
||||||
|
document.removeEventListener('touchstart', tryPlayOnInteraction);
|
||||||
|
};
|
||||||
|
|
||||||
|
document.addEventListener('click', tryPlayOnInteraction, { once: true });
|
||||||
|
document.addEventListener('touchstart', tryPlayOnInteraction, { once: true });
|
||||||
|
});
|
||||||
|
}, 300);
|
||||||
|
} else {
|
||||||
|
// 等待用户交互后再播放
|
||||||
|
const tryPlayOnInteraction = () => {
|
||||||
|
audio.play().catch(console.error);
|
||||||
|
document.removeEventListener('click', tryPlayOnInteraction);
|
||||||
|
document.removeEventListener('touchstart', tryPlayOnInteraction);
|
||||||
|
};
|
||||||
|
|
||||||
|
document.addEventListener('click', tryPlayOnInteraction, { once: true });
|
||||||
|
document.addEventListener('touchstart', tryPlayOnInteraction, { once: true });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('恢复音频状态失败:', e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
3921
css/about.css
427
css/artalk.css
@@ -3,6 +3,7 @@
|
|||||||
/* Base Artalk container styles */
|
/* Base Artalk container styles */
|
||||||
#artalk-container {
|
#artalk-container {
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
|
contain: layout style;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 确保评论区域适配白天/黑夜模式 */
|
/* 确保评论区域适配白天/黑夜模式 */
|
||||||
@@ -44,7 +45,6 @@
|
|||||||
|
|
||||||
/* Light theme styles */
|
/* Light theme styles */
|
||||||
.atk-main-editor {
|
.atk-main-editor {
|
||||||
background: rgba(255, 255, 255, 0.85) !important;
|
|
||||||
backdrop-filter: blur(28px) saturate(180%) !important;
|
backdrop-filter: blur(28px) saturate(180%) !important;
|
||||||
-webkit-backdrop-filter: blur(28px) saturate(180%) !important;
|
-webkit-backdrop-filter: blur(28px) saturate(180%) !important;
|
||||||
border: 1px solid rgba(108, 92, 231, 0.2) !important;
|
border: 1px solid rgba(108, 92, 231, 0.2) !important;
|
||||||
@@ -208,118 +208,7 @@
|
|||||||
color: #6c5ce7 !important;
|
color: #6c5ce7 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Night theme styles */
|
|
||||||
[data-theme="night"] .atk-main-editor {
|
|
||||||
background: rgba(30, 30, 35, 0.75) !important;
|
|
||||||
backdrop-filter: blur(28px) saturate(180%) !important;
|
|
||||||
-webkit-backdrop-filter: blur(28px) saturate(180%) !important;
|
|
||||||
border: 1px solid rgba(255, 255, 255, 0.12) !important;
|
|
||||||
box-shadow: 0 18px 60px rgba(0, 0, 0, 0.8) !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
[data-theme="night"] .atk-send-btn {
|
|
||||||
background: linear-gradient(135deg, #00cec9, #00b3ae) !important;
|
|
||||||
border: none !important;
|
|
||||||
border-radius: 20px !important;
|
|
||||||
padding: 8px 20px !important;
|
|
||||||
font-weight: 500 !important;
|
|
||||||
transition: all 0.3s ease !important;
|
|
||||||
box-shadow: 0 4px 15px rgba(0, 206, 201, 0.4);
|
|
||||||
}
|
|
||||||
|
|
||||||
[data-theme="night"] .atk-send-btn:hover {
|
|
||||||
background: linear-gradient(135deg, #00b3ae, #009690) !important;
|
|
||||||
transform: translateY(-2px) !important;
|
|
||||||
box-shadow: 0 6px 20px rgba(0, 206, 201, 0.6) !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
[data-theme="night"] .atk-send-btn:active {
|
|
||||||
transform: translateY(0) !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
[data-theme="night"] .atk-editor,
|
|
||||||
[data-theme="night"] .atk-editor textarea,
|
|
||||||
[data-theme="night"] .atk-editor input {
|
|
||||||
background: rgba(30, 30, 35, 0.75);
|
|
||||||
color: #dfe6e9;
|
|
||||||
}
|
|
||||||
|
|
||||||
[data-theme="night"] .atk-comment-wrap {
|
|
||||||
background: rgba(40, 40, 45, 0.85); /* 提高背景不透明度以增强可读性 */
|
|
||||||
border: 1px solid rgba(255, 255, 255, 0.12);
|
|
||||||
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5);
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
[data-theme="night"] .atk-comment-wrap:hover {
|
|
||||||
background: rgba(45, 45, 50, 0.95); /* 提高悬停时的背景不透明度 */
|
|
||||||
border: 1px solid rgba(255, 255, 255, 0.18);
|
|
||||||
box-shadow: 0 12px 40px rgba(0, 0, 0, 0.7);
|
|
||||||
}
|
|
||||||
|
|
||||||
[data-theme="night"] .atk-dialog,
|
|
||||||
[data-theme="night"] .atk-layer .atk-dialog {
|
|
||||||
background: rgba(30, 30, 35, 0.85);
|
|
||||||
color: #dfe6e9;
|
|
||||||
border: 1px solid rgba(255, 255, 255, 0.15);
|
|
||||||
box-shadow: 0 18px 60px rgba(0, 0, 0, 0.8);
|
|
||||||
}
|
|
||||||
|
|
||||||
[data-theme="night"] .atk-header-item {
|
|
||||||
color: #dfe6e9 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
[data-theme="night"] .atk-editor-textarea {
|
|
||||||
color: #dfe6e9 !important;
|
|
||||||
background: rgba(40, 40, 45, 0.5) !important;
|
|
||||||
border: 1px solid rgba(255, 255, 255, 0.08) !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
[data-theme="night"] .atk-editor-bottom .atk-item {
|
|
||||||
color: #b2bec3 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
[data-theme="night"] .atk-list-header .atk-comment-count {
|
|
||||||
color: #dfe6e9 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
[data-theme="night"] .atk-sort-select {
|
|
||||||
background: rgba(255, 255, 255, 0.08) !important;
|
|
||||||
border: 1px solid rgba(255, 255, 255, 0.15) !important;
|
|
||||||
color: #b2bec3 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
[data-theme="night"] .atk-comment .atk-nick {
|
|
||||||
color: #ffffff !important;
|
|
||||||
font-weight: 600 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
[data-theme="night"] .atk-comment .atk-date {
|
|
||||||
color: #a0aec0 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
[data-theme="night"] .atk-comment .atk-content {
|
|
||||||
color: #e2e8f0 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
[data-theme="night"] .atk-comment .atk-content a {
|
|
||||||
color: #00cec9 !important;
|
|
||||||
text-decoration: underline !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
[data-theme="night"] .atk-comment .atk-content pre {
|
|
||||||
background: rgba(20, 20, 25, 0.7) !important;
|
|
||||||
border: 1px solid rgba(255, 255, 255, 0.1) !important;
|
|
||||||
color: #e2e8f0 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
[data-theme="night"] .atk-actions .atk-action {
|
|
||||||
color: #b2bec3 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
[data-theme="night"] .atk-actions .atk-action:hover {
|
|
||||||
color: #00cec9 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Mobile specific styles */
|
/* Mobile specific styles */
|
||||||
.atk-mobile .atk-main-editor {
|
.atk-mobile .atk-main-editor {
|
||||||
@@ -456,30 +345,7 @@
|
|||||||
box-shadow: 0 6px 15px rgba(108, 92, 231, 0.25) !important;
|
box-shadow: 0 6px 15px rgba(108, 92, 231, 0.25) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-theme="night"] .atk-pagination .atk-page-item {
|
|
||||||
background: rgba(255, 255, 255, 0.08) !important;
|
|
||||||
color: #b2bec3 !important;
|
|
||||||
border: 1px solid rgba(255, 255, 255, 0.12) !important;
|
|
||||||
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.4) !important;
|
|
||||||
backdrop-filter: blur(28px) saturate(180%) !important;
|
|
||||||
-webkit-backdrop-filter: blur(28px) saturate(180%) !important;
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
[data-theme="night"] .atk-pagination .atk-page-item:hover {
|
|
||||||
background: linear-gradient(135deg, #00cec9, #00b3ae) !important;
|
|
||||||
color: white !important;
|
|
||||||
border: 1px solid rgba(0, 206, 201, 0.3) !important;
|
|
||||||
box-shadow: 0 8px 25px rgba(0, 206, 201, 0.3) !important;
|
|
||||||
transform: translateY(-2px);
|
|
||||||
}
|
|
||||||
|
|
||||||
[data-theme="night"] .atk-pagination .atk-page-item.atk-active {
|
|
||||||
background: linear-gradient(135deg, #00cec9, #00b3ae) !important;
|
|
||||||
color: white !important;
|
|
||||||
border: 1px solid rgba(0, 206, 201, 0.4) !important;
|
|
||||||
box-shadow: 0 8px 25px rgba(0, 206, 201, 0.4) !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Loading spinner */
|
/* Loading spinner */
|
||||||
.atk-loading {
|
.atk-loading {
|
||||||
@@ -516,6 +382,11 @@
|
|||||||
margin: 2px !important;
|
margin: 2px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[data-theme="night"] .atk-editor-toolbar .atk-btn {
|
||||||
|
color: #b2bec3 !important;
|
||||||
|
filter: brightness(1.3);
|
||||||
|
}
|
||||||
|
|
||||||
/* 暗色模式下聚焦边框 */
|
/* 暗色模式下聚焦边框 */
|
||||||
.atk-dark .atk-editor-textarea:focus {
|
.atk-dark .atk-editor-textarea:focus {
|
||||||
box-shadow: 0 0 0 2px rgba(66, 153, 225, 0.5) !important;
|
box-shadow: 0 0 0 2px rgba(66, 153, 225, 0.5) !important;
|
||||||
@@ -608,4 +479,290 @@
|
|||||||
[data-theme="night"] .atk-comment-wrap:hover {
|
[data-theme="night"] .atk-comment-wrap:hover {
|
||||||
background: rgba(45, 45, 50, 0.95) !important;
|
background: rgba(45, 45, 50, 0.95) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Night theme styles */
|
||||||
|
[data-theme="night"] .atk-main-editor {
|
||||||
|
background: rgba(30, 30, 35, 0.75) !important;
|
||||||
|
backdrop-filter: blur(28px) saturate(180%) !important;
|
||||||
|
-webkit-backdrop-filter: blur(28px) saturate(180%) !important;
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.12) !important;
|
||||||
|
box-shadow: 0 18px 60px rgba(0, 0, 0, 0.8) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="night"] .atk-send-btn {
|
||||||
|
background: linear-gradient(135deg, #00cec9, #00b3ae) !important;
|
||||||
|
border: none !important;
|
||||||
|
border-radius: 20px !important;
|
||||||
|
padding: 8px 20px !important;
|
||||||
|
font-weight: 500 !important;
|
||||||
|
transition: all 0.3s ease !important;
|
||||||
|
box-shadow: 0 4px 15px rgba(0, 206, 201, 0.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="night"] .atk-send-btn:hover {
|
||||||
|
background: linear-gradient(135deg, #00b3ae, #009690) !important;
|
||||||
|
transform: translateY(-2px) !important;
|
||||||
|
box-shadow: 0 6px 20px rgba(0, 206, 201, 0.6) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="night"] .atk-send-btn:active {
|
||||||
|
transform: translateY(0) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="night"] .atk-editor,
|
||||||
|
[data-theme="night"] .atk-editor textarea,
|
||||||
|
[data-theme="night"] .atk-editor input {
|
||||||
|
background: rgba(30, 30, 35, 0.75)!important;
|
||||||
|
color: #dfe6e9 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="night"] .atk-comment-wrap {
|
||||||
|
background: rgba(40, 40, 45, 0.85) !important; /* 提高背景不透明度以增强可读性 */
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.12) !important;
|
||||||
|
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5) !important;
|
||||||
|
transition: all 0.3s ease !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="night"] .atk-comment-wrap:hover {
|
||||||
|
background: rgba(45, 45, 50, 0.95) !important; /* 提高悬停时的背景不透明度 */
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.18) !important;
|
||||||
|
box-shadow: 0 12px 40px rgba(0, 0, 0, 0.7) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="night"] .atk-dialog,
|
||||||
|
[data-theme="night"] .atk-layer .atk-dialog {
|
||||||
|
background: rgba(30, 30, 35, 0.85) !important;
|
||||||
|
color: #dfe6e9 !important;
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.15) !important;
|
||||||
|
box-shadow: 0 18px 60px rgba(0, 0, 0, 0.8) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="night"] .atk-header-item {
|
||||||
|
color: #dfe6e9 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="night"] .atk-editor-textarea {
|
||||||
|
color: #1f2937 !important;
|
||||||
|
background: rgba(40, 40, 45, 0.5) !important;
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.08) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="night"] .atk-editor-bottom .atk-item {
|
||||||
|
color: #b2bec3 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="night"] .atk-list-header .atk-comment-count {
|
||||||
|
color: #dfe6e9 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="night"] .atk-sort-select {
|
||||||
|
background: rgba(255, 255, 255, 0.08) !important;
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.15) !important;
|
||||||
|
color: #b2bec3 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="night"] .atk-comment .atk-nick {
|
||||||
|
color: #ffffff !important;
|
||||||
|
font-weight: 600 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="night"] .atk-comment .atk-date {
|
||||||
|
color: #a0aec0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="night"] .atk-comment .atk-content {
|
||||||
|
color: #e2e8f0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="night"] .atk-comment .atk-content a {
|
||||||
|
color: #00cec9 !important;
|
||||||
|
text-decoration: underline !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="night"] .atk-comment .atk-content pre {
|
||||||
|
background: rgba(20, 20, 25, 0.7) !important;
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.1) !important;
|
||||||
|
color: #e2e8f0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="night"] .atk-actions .atk-action {
|
||||||
|
color: #b2bec3 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="night"] .atk-actions .atk-action:hover {
|
||||||
|
color: #00cec9 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="night"] .atk-pagination .atk-page-item {
|
||||||
|
background: rgba(255, 255, 255, 0.08) !important;
|
||||||
|
color: #b2bec3 !important;
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.12) !important;
|
||||||
|
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.4) !important;
|
||||||
|
backdrop-filter: blur(28px) saturate(180%) !important;
|
||||||
|
-webkit-backdrop-filter: blur(28px) saturate(180%) !important;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="night"] .atk-pagination .atk-page-item:hover {
|
||||||
|
background: linear-gradient(135deg, #00cec9, #00b3ae) !important;
|
||||||
|
color: white !important;
|
||||||
|
border: 1px solid rgba(0, 206, 201, 0.3) !important;
|
||||||
|
box-shadow: 0 8px 25px rgba(0, 206, 201, 0.3) !important;
|
||||||
|
transform: translateY(-2px);
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="night"] .atk-pagination .atk-page-item.atk-active {
|
||||||
|
background: linear-gradient(135deg, #00cec9, #00b3ae) !important;
|
||||||
|
color: white !important;
|
||||||
|
border: 1px solid rgba(0, 206, 201, 0.4) !important;
|
||||||
|
box-shadow: 0 8px 25px rgba(0, 206, 201, 0.4) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* PC端黑夜模式下的输入框颜色和列表样式修正 - 全面优化版 */
|
||||||
|
[data-theme="night"] .atk-editor-textarea {
|
||||||
|
background: rgba(30, 30, 35, 0.95) !important; /* 提高背景不透明度增强可读性 */
|
||||||
|
color: #ffffff !important; /* 使用更亮的文字颜色 */
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.2) !important; /* 增强边框可见性 */
|
||||||
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="night"] .atk-editor-textarea:focus {
|
||||||
|
border: 1px solid #00cec9 !important;
|
||||||
|
box-shadow: 0 0 0 3px rgba(0, 206, 201, 0.4) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="night"] .atk-comment-wrap {
|
||||||
|
background: rgba(30, 30, 35, 0.95) !important; /* 提高背景不透明度增强可读性 */
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.15) !important;
|
||||||
|
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.3) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="night"] .atk-comment-wrap:hover {
|
||||||
|
background: rgba(40, 40, 45, 0.98) !important; /* 进一步提高背景不透明度 */
|
||||||
|
border: 1px solid rgba(0, 206, 201, 0.5) !important; /* 增强边框可见性 */
|
||||||
|
box-shadow: 0 12px 32px rgba(0, 0, 0, 0.4) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="night"] .atk-list-header {
|
||||||
|
border-bottom: 1px solid rgba(255, 255, 255, 0.1) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="night"] .atk-header {
|
||||||
|
border-bottom: 1px solid rgba(255, 255, 255, 0.1) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 修复黑夜模式下插件面板的背景色问题 */
|
||||||
|
[data-theme="night"] .atk-editor-plug-wrap,
|
||||||
|
[data-theme="night"] .atk-plug-panel-wrap,
|
||||||
|
[data-theme="night"] .atk-editor-plug-emoticons,
|
||||||
|
[data-theme="night"] .atk-editor-plug-preview {
|
||||||
|
background: rgba(30, 30, 35, 0.95) !important;
|
||||||
|
color: #ffffff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="night"] .atk-plug-panel-wrap {
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.15) !important;
|
||||||
|
border-radius: 12px !important;
|
||||||
|
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.3) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="night"] .atk-editor-plug-emoticons {
|
||||||
|
border-top: 1px solid rgba(255, 255, 255, 0.08) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 优化评论底部工具栏在黑夜模式下的样式 */
|
||||||
|
[data-theme="night"] .atk-editor-bottom {
|
||||||
|
background: rgba(40, 40, 45, 0.7) !important;
|
||||||
|
border-top: 1px solid rgba(255, 255, 255, 0.08) !important;
|
||||||
|
padding: 12px 20px !important;
|
||||||
|
border-radius: 0 0 12px 12px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="night"] .atk-editor-bottom .atk-item {
|
||||||
|
color: #b2bec3 !important;
|
||||||
|
margin-right: 12px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="night"] .atk-send-btn {
|
||||||
|
background: linear-gradient(135deg, #00cec9, #00b3ae) !important;
|
||||||
|
border: none !important;
|
||||||
|
border-radius: 20px !important;
|
||||||
|
padding: 8px 20px !important;
|
||||||
|
font-weight: 500 !important;
|
||||||
|
transition: all 0.3s ease !important;
|
||||||
|
box-shadow: 0 4px 15px rgba(0, 206, 201, 0.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="night"] .atk-send-btn:hover {
|
||||||
|
background: linear-gradient(135deg, #00b3ae, #009690) !important;
|
||||||
|
transform: translateY(-2px) !important;
|
||||||
|
box-shadow: 0 6px 20px rgba(0, 206, 201, 0.6) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="night"] .atk-send-btn:active {
|
||||||
|
transform: translateY(0) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 优化评论列表项在黑夜模式下的样式 */
|
||||||
|
[data-theme="night"] .atk-comment {
|
||||||
|
color: #e2e8f0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="night"] .atk-comment .atk-nick {
|
||||||
|
color: #ffffff !important;
|
||||||
|
font-weight: 600 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="night"] .atk-comment .atk-date {
|
||||||
|
color: #a0aec0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="night"] .atk-comment .atk-content {
|
||||||
|
color: #ffffff !important; /* 使用更亮的文字颜色提高可读性 */
|
||||||
|
line-height: 1.6 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="night"] .atk-comment .atk-content a {
|
||||||
|
color: #00cec9 !important;
|
||||||
|
text-decoration: underline !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="night"] .atk-actions .atk-action {
|
||||||
|
color: #b2bec3 !important;
|
||||||
|
transition: all 0.2s ease !important;
|
||||||
|
margin-right: 15px; /* 增加回复评论组件的边距 */
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="night"] .atk-actions .atk-action:hover {
|
||||||
|
color: #00cec9 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 修复黑夜模式下评论计数和下拉菜单的可见性 */
|
||||||
|
[data-theme="night"] .atk-comment-count {
|
||||||
|
color: #ffffff !important;
|
||||||
|
font-weight: 600 !important;
|
||||||
|
text-shadow: 0 0 8px rgba(255, 255, 255, 0.3) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="night"] .atk-dropdown-wrap {
|
||||||
|
background: rgba(30, 30, 35, 0.95) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="night"] .atk-dropdown-item {
|
||||||
|
color: #ffffff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="night"] .atk-dropdown-item:hover {
|
||||||
|
background: rgba(0, 206, 201, 0.2) !important;
|
||||||
|
color: #00cec9 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="night"] .atk-dropdown-item.active {
|
||||||
|
background: rgba(0, 206, 201, 0.3) !important;
|
||||||
|
color: #00cec9 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="night"] .atk-arrow-down-icon {
|
||||||
|
filter: brightness(2) !important;
|
||||||
}
|
}
|
||||||
@@ -262,7 +262,7 @@ pre code { padding: 0; background: none; border: none; word-wrap: normal; }
|
|||||||
font-size: 1.3em;
|
font-size: 1.3em;
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
letter-spacing: 2px;
|
letter-spacing: 2px;
|
||||||
color: #f0f0f0;
|
color: #ffffff;
|
||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
}
|
}
|
||||||
@@ -275,7 +275,7 @@ pre code { padding: 0; background: none; border: none; word-wrap: normal; }
|
|||||||
line-height: 2;
|
line-height: 2;
|
||||||
letter-spacing: 2px;
|
letter-spacing: 2px;
|
||||||
color: #ffffff;
|
color: #ffffff;
|
||||||
text-shadow: 0 1px 2px rgba(141, 114, 114, 0.2) !important;
|
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.4) !important;
|
||||||
position: relative;
|
position: relative;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
font-feature-settings: 'kern' 1;
|
font-feature-settings: 'kern' 1;
|
||||||
@@ -872,7 +872,7 @@ nav {
|
|||||||
|
|
||||||
.weixin-qrcode-desc {
|
.weixin-qrcode-desc {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
color: #666;
|
color: #555;
|
||||||
margin-bottom: 15px;
|
margin-bottom: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -986,12 +986,12 @@ nav {
|
|||||||
display: inline-block;
|
display: inline-block;
|
||||||
margin: 0 5px;
|
margin: 0 5px;
|
||||||
font-size: 0.5em;
|
font-size: 0.5em;
|
||||||
color: rgba(255, 255, 255, 0.7);
|
color: rgba(255, 255, 255, 0.85);
|
||||||
line-height: 1.2;
|
line-height: 1.2;
|
||||||
}
|
}
|
||||||
|
|
||||||
.power a {
|
.power a {
|
||||||
color: rgba(255, 255, 255, 0.8);
|
color: rgba(255, 255, 255, 0.95);
|
||||||
font-size: 0.5em;
|
font-size: 0.5em;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
transition: color 0.3s ease;
|
transition: color 0.3s ease;
|
||||||
@@ -1006,8 +1006,7 @@ nav {
|
|||||||
.remark .power:not(:last-child):after {
|
.remark .power:not(:last-child):after {
|
||||||
content: "|";
|
content: "|";
|
||||||
margin-left: 8px;
|
margin-left: 8px;
|
||||||
color: rgba(255, 255, 255, 0.5);
|
color: rgba(255, 255, 255, 0.7);
|
||||||
color: rgba(255, 255, 255, 0.5);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,32 +1,58 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"id": 1011713435,
|
"name": "spring-ai-example",
|
||||||
|
"stargazers_count": 13,
|
||||||
|
"forks_count": 0,
|
||||||
|
"description": "本项目是一个基于 Spring AI 框架构建的检索增强生成(RAG)应用,旨在通过向量检索技术增强大模型的生成能力,使 AI 回答既智能又有依据。 项目采用现代化 Java 技术栈,核心框架为 Spring Boot 3.3 与 Spring AI 1.0,集成 OpenAI 模型(deepseek-r1、doubao-embedding)主打白嫖,支持 PostgreSQL+pgvector、Elasticsearch 等多种向量存储方案,并利用 Redis 实现缓存加速、Elasticsearch 管理对话记忆。",
|
||||||
|
"html_url": "https://github.com/listener-He/spring-ai-example"
|
||||||
|
},
|
||||||
|
{
|
||||||
"name": "yunxiao-LLM-reviewer",
|
"name": "yunxiao-LLM-reviewer",
|
||||||
"html_url": "https://github.com/listener-He/yunxiao-LLM-reviewer",
|
"stargazers_count": 10,
|
||||||
"description": "一款专为阿里云云效 Flow 平台设计的自动化代码审查工具。通过集成 Qwen、DeepSeek 等先进大模型,该工具能够实时分析 Git 合并请求(MR)中的代码变更,智能识别潜在问题并自动生成结构化评审意见。",
|
|
||||||
"stargazers_count": 9,
|
|
||||||
"forks_count": 3,
|
"forks_count": 3,
|
||||||
"language": "TypeScript",
|
"description": "一款专为阿里云云效 Flow 平台设计的自动化代码审查工具。通过集成 Qwen、DeepSeek 等先进大模型,该工具能够实时分析 Git 合并请求(MR)中的代码变更,智能识别潜在问题并自动生成结构化评审意见。 工具支持多维度代码检测,包括逻辑错误、安全漏洞,有效提升团队代码质量与开发效率。 作为云效 Flow 的自定义步骤,该工具可无缝集成到 CI/CD 流水线中,实现 MR 提交时的自动化代码审查,大幅减少人工评审工作量,加速代码交付流程。",
|
||||||
"updated_at": "2025-10-10T11:06:34Z"
|
"html_url": "https://github.com/listener-He/yunxiao-LLM-reviewer"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": 1064414600,
|
"name": "Home",
|
||||||
"name": "hexo-theme-stellar",
|
"stargazers_count": 2,
|
||||||
"html_url": "https://github.com/listener-He/hexo-theme-stellar",
|
|
||||||
"description": "综合型hexo主题:博客+知识库+专栏+笔记,内置海量的标签组件和动态数据组件。",
|
|
||||||
"stargazers_count": 0,
|
|
||||||
"forks_count": 0,
|
"forks_count": 0,
|
||||||
"language": null,
|
"description": "现代化个人主页,融合科技感与个性化元素,展示个人技术栈、开源项目和博客文章。",
|
||||||
"updated_at": "2025-09-26T02:12:18Z"
|
"html_url": "https://github.com/listener-He/Home"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": 1060085476,
|
"name": "collection-complete",
|
||||||
"name": "Universal-IoT-Java",
|
"stargazers_count": 2,
|
||||||
"html_url": "https://github.com/listener-He/Universal-IoT-Java",
|
"forks_count": 2,
|
||||||
"description": "通用 IoT Java 平台(示例)",
|
"description": "collection-complete 是一个用于处理集合数据并补充相关信息的Java库。它提供了链式调用的功能,可以方便地对集合中的元素进行批量操作和属性补充。全程函数式 均衡了易用性与扩展性的设计",
|
||||||
"stargazers_count": 0,
|
"html_url": "https://github.com/listener-He/collection-complete"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "keycloak-services-social-weixin",
|
||||||
|
"stargazers_count": 2,
|
||||||
|
"forks_count": 3,
|
||||||
|
"description": "",
|
||||||
|
"html_url": "https://github.com/listener-He/keycloak-services-social-weixin"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Notion-Wechat-Blog",
|
||||||
|
"stargazers_count": 1,
|
||||||
"forks_count": 0,
|
"forks_count": 0,
|
||||||
"language": null,
|
"description": "基于NotionNext作为后端的微信小程序",
|
||||||
"updated_at": "2025-10-13T02:30:28Z"
|
"html_url": "https://github.com/listener-He/Notion-Wechat-Blog"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "social-auth",
|
||||||
|
"stargazers_count": 1,
|
||||||
|
"forks_count": 0,
|
||||||
|
"description": "",
|
||||||
|
"html_url": "https://github.com/listener-He/social-auth"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "hp-lite",
|
||||||
|
"stargazers_count": 0,
|
||||||
|
"forks_count": 1,
|
||||||
|
"description": "内网穿透 轻量版 支持 https http tcp udp 支持云端动态控制穿透配置,支持免费SSL证书和续签、支持限流和IP黑白名单,多账户、统计、http、socks代理、反向代理、多设备管理等功能。",
|
||||||
|
"html_url": "https://github.com/listener-He/hp-lite"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
BIN
data/至少做一件离谱的事-Kiri T_compressed.mp3
Normal file
BIN
images/INFJ.webp
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
images/bj/1.webp
Normal file
|
After Width: | Height: | Size: 691 KiB |
BIN
images/bj/10.jpg
|
Before Width: | Height: | Size: 1.4 MiB |
BIN
images/bj/2.webp
Normal file
|
After Width: | Height: | Size: 415 KiB |
BIN
images/bj/3.webp
Normal file
|
After Width: | Height: | Size: 488 KiB |
BIN
images/bj/4.webp
Normal file
|
After Width: | Height: | Size: 1.8 MiB |
BIN
images/bj/5.webp
Normal file
|
After Width: | Height: | Size: 168 KiB |
BIN
images/bj/6.webp
Normal file
|
After Width: | Height: | Size: 1.2 MiB |
BIN
images/bj/7.webp
Normal file
|
After Width: | Height: | Size: 786 KiB |
BIN
images/bj/8.webp
Normal file
|
After Width: | Height: | Size: 1.8 MiB |
BIN
images/bj/9.jpg
|
Before Width: | Height: | Size: 1.6 MiB |
BIN
images/mp-honesy.jpg
Normal file
|
After Width: | Height: | Size: 27 KiB |
71
index.html
@@ -13,9 +13,6 @@
|
|||||||
<meta name="keywords" content="Honesty,HeHouHui,HeHui,明厚">
|
<meta name="keywords" content="Honesty,HeHouHui,HeHui,明厚">
|
||||||
<meta name="author" content="Honesty">
|
<meta name="author" content="Honesty">
|
||||||
|
|
||||||
<!-- PWA相关配置 -->
|
|
||||||
<meta name="theme-color" content="#6c5ce7">
|
|
||||||
<link rel="manifest" href="./manifest.json">
|
|
||||||
|
|
||||||
<!-- 社交平台分享优化 -->
|
<!-- 社交平台分享优化 -->
|
||||||
<!-- Open Graph / Facebook -->
|
<!-- Open Graph / Facebook -->
|
||||||
@@ -67,7 +64,7 @@
|
|||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body oncontextmenu=self.event.returnValue=false onselectstart="return false">
|
<body>
|
||||||
<header id="panel" class="panel-cover">
|
<header id="panel" class="panel-cover">
|
||||||
<script>
|
<script>
|
||||||
WIDGET = {
|
WIDGET = {
|
||||||
@@ -107,7 +104,7 @@
|
|||||||
<div class="info iUp">
|
<div class="info iUp">
|
||||||
<div class="info-back">
|
<div class="info-back">
|
||||||
<img alt="img" src="images/kl.gif"
|
<img alt="img" src="images/kl.gif"
|
||||||
class="js-avatar profilepic">
|
class="js-avatar profilepic" loading="lazy">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
@@ -266,9 +263,9 @@
|
|||||||
<div class="weixin-qrcode-container">
|
<div class="weixin-qrcode-container">
|
||||||
<div class="weixin-qrcode-title">扫描二维码</div>
|
<div class="weixin-qrcode-title">扫描二维码</div>
|
||||||
<div class="weixin-qrcode-desc">请使用微信扫一扫添加关注</div>
|
<div class="weixin-qrcode-desc">请使用微信扫一扫添加关注</div>
|
||||||
<img src="https://blog-file.hehouhui.cn/wechat/mp-honesy.jpg" alt="微信二维码"
|
<img src="./images/mp-honesy.jpg" alt="微信二维码"
|
||||||
class="weixin-qrcode-image"
|
class="weixin-qrcode-image"
|
||||||
onerror="this.src='https://cdn.jsdmirror.com/gh/listener-He/Home/images/logo.png'; this.alt='二维码加载失败'">
|
onerror="this.src='https://cdn.jsdmirror.com/gh/listener-He/Home/images/logo.png'; this.alt='二维码加载失败'" loading="lazy">
|
||||||
<button class="weixin-qrcode-close" onclick="closeWeixin()">关闭</button>
|
<button class="weixin-qrcode-close" onclick="closeWeixin()">关闭</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -280,7 +277,7 @@
|
|||||||
// 防止滚动穿透
|
// 防止滚动穿透
|
||||||
document.body.style.overflow = 'hidden';
|
document.body.style.overflow = 'hidden';
|
||||||
// 添加ESC键关闭
|
// 添加ESC键关闭
|
||||||
document.addEventListener('keydown', closeOnEsc);
|
document.addEventListener('keydown', closeOnEsc, { passive: false });
|
||||||
}
|
}
|
||||||
|
|
||||||
function closeWeixin() {
|
function closeWeixin() {
|
||||||
@@ -289,7 +286,7 @@
|
|||||||
// 恢复滚动
|
// 恢复滚动
|
||||||
document.body.style.overflow = '';
|
document.body.style.overflow = '';
|
||||||
// 移除ESC键监听
|
// 移除ESC键监听
|
||||||
document.removeEventListener('keydown', closeOnEsc);
|
document.removeEventListener('keydown', closeOnEsc, { passive: false });
|
||||||
}
|
}
|
||||||
|
|
||||||
function closeOnEsc(e) {
|
function closeOnEsc(e) {
|
||||||
@@ -303,12 +300,12 @@
|
|||||||
if (e.target === this) {
|
if (e.target === this) {
|
||||||
closeWeixin();
|
closeWeixin();
|
||||||
}
|
}
|
||||||
});
|
}, { passive: false });
|
||||||
|
|
||||||
// 阻止点击弹框内容时关闭
|
// 阻止点击弹框内容时关闭
|
||||||
document.querySelector('.weixin-qrcode-container').addEventListener('click', function (e) {
|
document.querySelector('.weixin-qrcode-container').addEventListener('click', function (e) {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
});
|
}, { passive: false });
|
||||||
</script>
|
</script>
|
||||||
</div>
|
</div>
|
||||||
<div class="remark iUp">
|
<div class="remark iUp">
|
||||||
@@ -395,7 +392,7 @@
|
|||||||
<!-- 可选:继续调用 config -->
|
<!-- 可选:继续调用 config -->
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
try {
|
try {
|
||||||
gtag('config', 'G-DYWDEVKDP0');
|
gtag('config', SiteConfig.analytics.google.id);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("Google Analytics config 失败", e);
|
console.error("Google Analytics config 失败", e);
|
||||||
}
|
}
|
||||||
@@ -414,38 +411,28 @@
|
|||||||
};
|
};
|
||||||
s.LA ? s.LA.ids && o() : (s.LA = p, s.LA.ids = [], o()), r.parentNode.insertBefore(n, r)
|
s.LA ? s.LA.ids && o() : (s.LA = p, s.LA.ids = [], o()), r.parentNode.insertBefore(n, r)
|
||||||
}()
|
}()
|
||||||
}({id: "3OBGjwDdEIRS7XZ1", ck: "3OBGjwDdEIRS7XZ1"});
|
}({id: SiteConfig.analytics.tencent.id, ck: SiteConfig.analytics.tencent.ck});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<!-- PWA注册 -->
|
<!-- 隐藏的音频播放iframe -->
|
||||||
<script>
|
<iframe id="audio-player-iframe" src="audio-player.html" style="display: none;"></iframe>
|
||||||
if ('serviceWorker' in navigator) {
|
|
||||||
window.addEventListener('load', function () {
|
<script>
|
||||||
setTimeout(() => {
|
// 音频控制逻辑
|
||||||
navigator.serviceWorker.register('./js/sw.js')
|
let audioIframe = document.getElementById('audio-player-iframe');
|
||||||
.then(function(registration) {
|
// 监听来自iframe的消息
|
||||||
console.log('SW registered: ', registration);
|
window.addEventListener('message', function(event) {
|
||||||
})
|
// 确保消息来自我们的iframe
|
||||||
.catch(function(registrationError) {
|
if (event.source !== audioIframe.contentWindow) return;
|
||||||
console.log('SW registration failed: ', registrationError);
|
const data = event.data;
|
||||||
});
|
if (data.playing && data.action === 'playerReady') {
|
||||||
}, 3000); // 页面稳定后再注册
|
// iframe准备就绪,设置初始音频
|
||||||
});
|
audioIframe.contentWindow.postMessage({
|
||||||
|
action: 'setTrack',
|
||||||
|
src: 'data/至少做一件离谱的事-Kiri T_compressed.mp3'
|
||||||
|
}, '*');
|
||||||
}
|
}
|
||||||
</script>
|
});
|
||||||
|
</script>
|
||||||
<!-- Apple PWA支持 -->
|
|
||||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
|
||||||
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
|
|
||||||
<meta name="apple-mobile-web-app-title" content="Honesty">
|
|
||||||
<link rel="apple-touch-icon" href="./images/logo.png">
|
|
||||||
|
|
||||||
<!-- Windows PWA支持 -->
|
|
||||||
<meta name="msapplication-TileImage" content="./images/avatar.jpeg">
|
|
||||||
<meta name="msapplication-TileColor" content="#6c5ce7">
|
|
||||||
<meta name="msapplication-tap-highlight" content="no">
|
|
||||||
|
|
||||||
<!-- 其他PWA相关meta标签 -->
|
|
||||||
<meta name="mobile-web-app-capable" content="yes">
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@@ -84,7 +84,7 @@ const StarrySky = function () {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
starCount = Math.ceil(canvasWidth * starCountLevel);
|
starCount = Math.ceil(canvasWidth * starCountLevel);
|
||||||
}, 200));
|
}, 200), { passive: true });
|
||||||
} else {
|
} else {
|
||||||
console.error('初始化失败,必须传入Canvas元素');
|
console.error('初始化失败,必须传入Canvas元素');
|
||||||
}
|
}
|
||||||
@@ -160,7 +160,7 @@ const StarrySky = function () {
|
|||||||
canvasContext.shadowOffsetX = 0;
|
canvasContext.shadowOffsetX = 0;
|
||||||
canvasContext.shadowOffsetY = 0;
|
canvasContext.shadowOffsetY = 0;
|
||||||
canvasContext.shadowColor = "rgb(" + star["color"] + ")";
|
canvasContext.shadowColor = "rgb(" + star["color"] + ")";
|
||||||
canvasContext.shadowBlur = 10;
|
canvasContext.shadowBlur = 5;
|
||||||
canvasContext.beginPath();
|
canvasContext.beginPath();
|
||||||
canvasContext.arc(star_x, star_y, star_radius, 0, 2 * Math.PI);
|
canvasContext.arc(star_x, star_y, star_radius, 0, 2 * Math.PI);
|
||||||
canvasContext.fill();
|
canvasContext.fill();
|
||||||
|
|||||||
477
js/about.js
@@ -53,8 +53,8 @@ class AppCore {
|
|||||||
constructor() {
|
constructor() {
|
||||||
this.i18n = new I18nManager();
|
this.i18n = new I18nManager();
|
||||||
this.theme = new ThemeManager();
|
this.theme = new ThemeManager();
|
||||||
this.data = new DataManager();
|
|
||||||
this.ui = new UIManager();
|
this.ui = new UIManager();
|
||||||
|
this.data = new DataManager();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,7 +63,23 @@ class AppCore {
|
|||||||
=========================== */
|
=========================== */
|
||||||
class I18nManager {
|
class I18nManager {
|
||||||
constructor() {
|
constructor() {
|
||||||
|
// 获取当前请求参数有无 lang 参数
|
||||||
|
try {
|
||||||
|
this.query = new URLSearchParams(window.location.search);
|
||||||
|
if (this.query.has('lang')) {
|
||||||
|
let lang = this.query.get('lang');
|
||||||
|
if (lang === 'zh' || lang === 'en') {
|
||||||
|
this.lang = lang;
|
||||||
|
setStoredLanguage(lang);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.lang) {
|
||||||
this.lang = getStoredLanguage();
|
this.lang = getStoredLanguage();
|
||||||
|
}
|
||||||
this.dict = {
|
this.dict = {
|
||||||
zh: {
|
zh: {
|
||||||
"nav.home": "首页",
|
"nav.home": "首页",
|
||||||
@@ -79,8 +95,8 @@ class I18nManager {
|
|||||||
"stats.exp": "编程年限",
|
"stats.exp": "编程年限",
|
||||||
"stats.repos": "开源项目",
|
"stats.repos": "开源项目",
|
||||||
"stats.followers": "关注者",
|
"stats.followers": "关注者",
|
||||||
"stats.visitors": "访问量",
|
"stats.visitors": "访客数",
|
||||||
"stats.visitNum": "访客数",
|
"stats.visitNum": "访问量",
|
||||||
"mbti.name": "提倡者",
|
"mbti.name": "提倡者",
|
||||||
"mbti.desc": "提倡者人格类型的人非常稀少,只有不到1%的人口属于这种类型,但他们对世界的贡献不容忽视。",
|
"mbti.desc": "提倡者人格类型的人非常稀少,只有不到1%的人口属于这种类型,但他们对世界的贡献不容忽视。",
|
||||||
"mbti.tag1": "理想主义与道德感",
|
"mbti.tag1": "理想主义与道德感",
|
||||||
@@ -120,8 +136,8 @@ class I18nManager {
|
|||||||
"stats.exp": "Years Exp",
|
"stats.exp": "Years Exp",
|
||||||
"stats.repos": "Projects",
|
"stats.repos": "Projects",
|
||||||
"stats.followers": "Followers",
|
"stats.followers": "Followers",
|
||||||
"stats.visitors": "Visitors",
|
"stats.visitors": "Access User",
|
||||||
"stats.visitNum": "Visiting guests",
|
"stats.visitNum": "Visitors",
|
||||||
"mbti.name": "Advocate",
|
"mbti.name": "Advocate",
|
||||||
"mbti.desc": "Advocates of this personality type are very rare, with less than 1% of the population belonging to this type, but their contributions to the world cannot be ignored.",
|
"mbti.desc": "Advocates of this personality type are very rare, with less than 1% of the population belonging to this type, but their contributions to the world cannot be ignored.",
|
||||||
"mbti.tag1": "Idealism & Morality",
|
"mbti.tag1": "Idealism & Morality",
|
||||||
@@ -268,28 +284,60 @@ class DataManager {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
// Parallel Fetch with timeout
|
// Parallel Fetch with timeout
|
||||||
const uRes = await this.fetchWithTimeout(`https://api.github.com/users/${user}`, { timeout: 5000 });
|
let userData, repoData;
|
||||||
const userData = uRes.ok ? await uRes.json() : (window.SiteConfig?.defaults?.user);
|
|
||||||
|
try {
|
||||||
|
const uRes = await this.fetchWithTimeout(`https://api.github.com/users/${user}`, { timeout: 1000 });
|
||||||
|
if (uRes.ok) {
|
||||||
|
userData = await uRes.json();
|
||||||
|
} else {
|
||||||
|
const fallbackUser = await this.fetchWithTimeout("./data/github_user.json", { timeout: 200 });
|
||||||
|
userData = await fallbackUser.json();
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
// Handle abort errors and other fetch errors
|
||||||
|
if (err.name === 'AbortError') {
|
||||||
|
console.warn("GitHub user fetch aborted, using fallback data");
|
||||||
|
}
|
||||||
|
const fallbackUser = await this.fetchWithTimeout("./data/github_user.json", { timeout: 200 });
|
||||||
|
userData = await fallbackUser.json();
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
let allRepos = [];
|
let allRepos = [];
|
||||||
let page = 1;
|
let page = 1;
|
||||||
const perPage = 100;
|
const perPage = 100;
|
||||||
while (page <= 10) { // 最多抓取1000条,直到满足条件或为空
|
while (page <= 50) { // 最多抓取500条,直到满足条件或为空
|
||||||
const rRes = await this.fetchWithTimeout(`https://api.github.com/users/${user}/repos?sort=stars&per_page=${perPage}&page=${page}`, { timeout: 5000 });
|
const rRes = await this.fetchWithTimeout(`https://api.github.com/users/${user}/repos?sort=pushed&direction=desc&per_page=${perPage}&page=${page}`, { timeout: 3000 });
|
||||||
if (!rRes.ok) break;
|
if (!rRes.ok) break;
|
||||||
const repos = await rRes.json();
|
const repos = await rRes.json();
|
||||||
if (!Array.isArray(repos) || repos.length === 0) break;
|
if (!Array.isArray(repos) || repos.length === 0) break;
|
||||||
allRepos = allRepos.concat(repos);
|
allRepos = allRepos.concat(repos);
|
||||||
if (repos.length < perPage || allRepos.length >= 1000) break; // 足量
|
if (repos.length < perPage || allRepos.length >= 500) break; // 足量
|
||||||
page++;
|
page++;
|
||||||
}
|
}
|
||||||
let repoData = allRepos.length ? allRepos : (window.SiteConfig?.defaults?.repos);
|
|
||||||
|
if (allRepos.length) {
|
||||||
|
repoData = allRepos;
|
||||||
|
} else {
|
||||||
|
const fallbackRepos = await this.fetchWithTimeout("./data/github_repos.json", { timeout: 300 });
|
||||||
|
repoData = await fallbackRepos.json();
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
// Handle abort errors and other fetch errors
|
||||||
|
if (err.name === 'AbortError') {
|
||||||
|
console.warn("GitHub repos fetch aborted, using fallback data");
|
||||||
|
}
|
||||||
|
const fallbackRepos = await this.fetchWithTimeout("./data/github_repos.json", { timeout: 300 });
|
||||||
|
repoData = await fallbackRepos.json();
|
||||||
|
}
|
||||||
|
|
||||||
// 过滤掉fork项目并按星数排序
|
// 过滤掉fork项目并按星数排序
|
||||||
if (Array.isArray(repoData)) {
|
if (Array.isArray(repoData)) {
|
||||||
repoData = repoData
|
repoData = repoData
|
||||||
.filter(repo => !repo.fork && (repo.stargazers_count > 0 || repo.forks_count > 0))
|
.filter(repo => !repo.fork && (repo.stargazers_count > 0 || repo.forks_count > 0))
|
||||||
.sort((a, b) => (b.stargazers_count || 0) - (a.stargazers_count || 0))
|
.sort((a, b) => (b.stargazers_count || 0) - (a.stargazers_count || 0))
|
||||||
.slice(0, 12); // 只取前12个
|
.slice(0, 16); // 只取前16个
|
||||||
}
|
}
|
||||||
|
|
||||||
const slimUser = {
|
const slimUser = {
|
||||||
@@ -328,22 +376,10 @@ class DataManager {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
formatVisitors() {
|
|
||||||
const siteVisitorDom = window.document.getElementById('busuanzi_value_site_pv');
|
|
||||||
if (siteVisitorDom) {
|
|
||||||
let count = siteVisitorDom.innerText;
|
|
||||||
if (count && count.length > 3) {
|
|
||||||
// 格式化 k,w m等单位 支持两位小数点
|
|
||||||
count = count.replace(/(\d)(?=(\d{3})+$)/g, '$1,');
|
|
||||||
count = count.replace(/(\d+)(?=(\d{3})+(?:\.\d+)?$)/g, '$0 ');
|
|
||||||
siteVisitorDom.innerText = count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
renderRepos(list) {
|
renderRepos(list) {
|
||||||
if (!Array.isArray(list)) list = window.SiteConfig?.defaults?.repos;
|
if (!Array.isArray(list)) list = window.SiteConfig?.defaults?.repos;
|
||||||
let html = '';
|
let html = '';
|
||||||
list.slice(0, 12).forEach(repo => {
|
list.forEach(repo => {
|
||||||
// Fix: API field compatibility
|
// Fix: API field compatibility
|
||||||
const stars = repo.stargazers_count !== undefined ? repo.stargazers_count : (repo.stars || 0);
|
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 forks = repo.forks_count !== undefined ? repo.forks_count : (repo.forks || 0);
|
||||||
@@ -498,6 +534,9 @@ class DataManager {
|
|||||||
=========================== */
|
=========================== */
|
||||||
class UIManager {
|
class UIManager {
|
||||||
constructor() {
|
constructor() {
|
||||||
|
this.userInteracted = false;
|
||||||
|
this.audioPlayer = null;
|
||||||
|
this.audioIframe = null;
|
||||||
this.initTechCloud();
|
this.initTechCloud();
|
||||||
this.initModal();
|
this.initModal();
|
||||||
this.initArtalk();
|
this.initArtalk();
|
||||||
@@ -560,10 +599,11 @@ class UIManager {
|
|||||||
server: window.SiteConfig.artalk.server,
|
server: window.SiteConfig.artalk.server,
|
||||||
site: window.SiteConfig.artalk.site,
|
site: window.SiteConfig.artalk.site,
|
||||||
// 多语言支持
|
// 多语言支持
|
||||||
locale: isZh ? 'zh-CN' : 'en-US',
|
locale: isZh ? 'zh-CN' : 'en',
|
||||||
// 自定义占位符(支持多语言)
|
// 自定义占位符(支持多语言)
|
||||||
placeholder: isZh ? '说点什么吧...支持 Markdown 语法,可 @用户、发送表情' : 'Leave a comment... Supports Markdown, @mentions, and Send 😊',
|
placeholder: isZh ? '说点什么吧...支持 Markdown 语法,可 @用户、发送表情' : 'Leave a comment... Supports Markdown, @mentions, and Send 😊',
|
||||||
|
// 无评论时显示
|
||||||
|
noComment: isZh ? '快来成为第一个评论的人吧~' : 'Be the first to leave a comment~😍',
|
||||||
// 发送按钮文字(多语言)
|
// 发送按钮文字(多语言)
|
||||||
sendBtn: isZh ? '发送' : 'Send',
|
sendBtn: isZh ? '发送' : 'Send',
|
||||||
loginBtn: isZh ? '发送' : 'Send',
|
loginBtn: isZh ? '发送' : 'Send',
|
||||||
@@ -576,11 +616,7 @@ class UIManager {
|
|||||||
// 启用 Markdown
|
// 启用 Markdown
|
||||||
markdown: true,
|
markdown: true,
|
||||||
|
|
||||||
// 表情面板
|
emoticons: "https://emoticons.hzchu.top/json/artalk/zaoandandandeyouyongquan.json",
|
||||||
emoji: {
|
|
||||||
// 使用默认表情包
|
|
||||||
preset: 'twemoji'
|
|
||||||
},
|
|
||||||
|
|
||||||
// 启用 @ 用户提醒功能
|
// 启用 @ 用户提醒功能
|
||||||
mention: true,
|
mention: true,
|
||||||
@@ -622,7 +658,7 @@ class UIManager {
|
|||||||
`昨天 ${date.getHours().toString().padStart(2, '0')}:${date.getMinutes().toString().padStart(2, '0')}` :
|
`昨天 ${date.getHours().toString().padStart(2, '0')}:${date.getMinutes().toString().padStart(2, '0')}` :
|
||||||
`Yesterday ${date.getHours().toString().padStart(2, '0')}:${date.getMinutes().toString().padStart(2, '0')}`;
|
`Yesterday ${date.getHours().toString().padStart(2, '0')}:${date.getMinutes().toString().padStart(2, '0')}`;
|
||||||
|
|
||||||
return date.toLocaleString(isZh ? 'zh-CN' : 'en-US', {
|
return date.toLocaleString(isZh ? 'zh-CN' : 'en', {
|
||||||
year: 'numeric',
|
year: 'numeric',
|
||||||
month: '2-digit',
|
month: '2-digit',
|
||||||
day: '2-digit',
|
day: '2-digit',
|
||||||
@@ -643,8 +679,8 @@ class UIManager {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Artalk.init(artalkConfig);
|
let artalkRef = Artalk.init(artalkConfig);
|
||||||
this.enhanceArtalkUI();
|
this.enhanceArtalkUI(artalkRef);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("Artalk Error", e);
|
console.error("Artalk Error", e);
|
||||||
const msg = isZh ? '当前评论区已关闭' : 'Comments are closed';
|
const msg = isZh ? '当前评论区已关闭' : 'Comments are closed';
|
||||||
@@ -678,7 +714,7 @@ class UIManager {
|
|||||||
this.initArtalk();
|
this.initArtalk();
|
||||||
}
|
}
|
||||||
|
|
||||||
enhanceArtalkUI() {
|
enhanceArtalkUI(artalkRef) {
|
||||||
const container = document.getElementById('artalk-container');
|
const container = document.getElementById('artalk-container');
|
||||||
if (!container) return;
|
if (!container) return;
|
||||||
|
|
||||||
@@ -703,11 +739,24 @@ class UIManager {
|
|||||||
const newTheme = document.documentElement.getAttribute('data-theme');
|
const newTheme = document.documentElement.getAttribute('data-theme');
|
||||||
const newLang = document.documentElement.getAttribute('data-lang');
|
const newLang = document.documentElement.getAttribute('data-lang');
|
||||||
console.log('Theme/Language changed:', newTheme, newLang);
|
console.log('Theme/Language changed:', newTheme, newLang);
|
||||||
|
if (newLang && newLang !== lang) {
|
||||||
// 延迟执行
|
// 延迟执行
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
// 重新加载整个评论组件
|
// 重新加载整个评论组件
|
||||||
this.reloadArtalk();
|
this.reloadArtalk();
|
||||||
}, 300);
|
}, 300);
|
||||||
|
} else if (newTheme && newTheme !== currentTheme) {
|
||||||
|
try {
|
||||||
|
artalkRef.ui.setDarkMode(newTheme === 'night')
|
||||||
|
} catch (e) {
|
||||||
|
setTimeout(() => {
|
||||||
|
// 重新加载整个评论组件
|
||||||
|
this.reloadArtalk();
|
||||||
|
}, 300);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
themeObserver.observe(document.documentElement, {
|
themeObserver.observe(document.documentElement, {
|
||||||
@@ -788,15 +837,55 @@ class UIManager {
|
|||||||
//const name = item.name || '';
|
//const name = item.name || '';
|
||||||
//const hash = Array.from(name).reduce((a, c) => a + c.charCodeAt(0), 0);
|
//const hash = Array.from(name).reduce((a, c) => a + c.charCodeAt(0), 0);
|
||||||
const gid = Number(item.gradientId) && Number.isFinite(Number(item.gradientId))
|
const gid = Number(item.gradientId) && Number.isFinite(Number(item.gradientId))
|
||||||
? Math.max(1, Math.min(10, Number(item.gradientId)))
|
? Math.max(1, Math.min(25, Number(item.gradientId)))
|
||||||
: (idx % 10) + 1;
|
: (idx % 25) + 1;
|
||||||
return {...item, gradientId: gid};
|
return {...item, gradientId: gid};
|
||||||
});
|
});
|
||||||
|
|
||||||
const isMobile = window.matchMedia('(max-width: 768px)').matches;
|
const currentState = window.matchMedia('(max-width: 768px)').matches ? 'mobile' : 'desktop';
|
||||||
container.innerHTML = '';
|
// 检查是否已保存状态到 sessionStorage
|
||||||
|
const savedState = sessionStorage.getItem('techCloudState_' + currentState);
|
||||||
|
|
||||||
if (isMobile) {
|
|
||||||
|
if (savedState) {
|
||||||
|
const parsedState = JSON.parse(savedState);
|
||||||
|
// 如果当前状态与保存的状态一致,直接使用保存的内容
|
||||||
|
if (parsedState.type === currentState) {
|
||||||
|
container.innerHTML = parsedState.html;
|
||||||
|
if (currentState === 'mobile') {
|
||||||
|
container.classList.add('mobile-scroll');
|
||||||
|
}
|
||||||
|
if (currentState === 'desktop') {
|
||||||
|
container.classList.remove('mobile-scroll');
|
||||||
|
// 重新初始化3D球体动画
|
||||||
|
this.init3DSphereAnimation(container, techStack);
|
||||||
|
}
|
||||||
|
// 监听窗口大小变化
|
||||||
|
this.setupResizeListener(container, techStack, currentState);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清空容器并重新生成
|
||||||
|
this.generateTechCloud(container, techStack, currentState);
|
||||||
|
|
||||||
|
// 监听窗口大小变化
|
||||||
|
this.setupResizeListener(container, techStack, currentState);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存技术标签云状态到 sessionStorage
|
||||||
|
saveTechCloudState(container, type) {
|
||||||
|
const state = {
|
||||||
|
type: type,
|
||||||
|
html: container.innerHTML
|
||||||
|
};
|
||||||
|
sessionStorage.setItem('techCloudState_' + type, JSON.stringify(state));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成技术标签云
|
||||||
|
generateTechCloud(container, techStack, type) {
|
||||||
|
container.innerHTML = '';
|
||||||
|
if (type === 'mobile') {
|
||||||
// Mobile: 3-row seamless marquee
|
// Mobile: 3-row seamless marquee
|
||||||
container.classList.add('mobile-scroll');
|
container.classList.add('mobile-scroll');
|
||||||
const rows = 3;
|
const rows = 3;
|
||||||
@@ -808,7 +897,7 @@ class UIManager {
|
|||||||
const appendItem = (rowEl, item, idx) => {
|
const appendItem = (rowEl, item, idx) => {
|
||||||
const el = document.createElement('span');
|
const el = document.createElement('span');
|
||||||
el.className = 'tech-tag-mobile';
|
el.className = 'tech-tag-mobile';
|
||||||
const colorClass = `tag-color-${item.gradientId || ((idx % 10) + 1)}`;
|
const colorClass = `tag-color-${item.gradientId || ((idx % 25) + 1)}`;
|
||||||
el.classList.add(colorClass);
|
el.classList.add(colorClass);
|
||||||
el.innerText = item.name;
|
el.innerText = item.name;
|
||||||
el.style.border = 'none';
|
el.style.border = 'none';
|
||||||
@@ -826,20 +915,15 @@ class UIManager {
|
|||||||
} else {
|
} else {
|
||||||
// PC: 3D Sphere
|
// PC: 3D Sphere
|
||||||
container.classList.remove('mobile-scroll');
|
container.classList.remove('mobile-scroll');
|
||||||
|
this.init3DSphereAnimation(container, techStack);
|
||||||
// 使用防抖优化尺寸计算
|
|
||||||
let resizeTimeout;
|
|
||||||
const updateContainerSize = () => {
|
|
||||||
if (resizeTimeout) {
|
|
||||||
clearTimeout(resizeTimeout);
|
|
||||||
}
|
}
|
||||||
resizeTimeout = setTimeout(() => {
|
|
||||||
init3DSphere();
|
|
||||||
}, 100);
|
|
||||||
};
|
|
||||||
|
|
||||||
// 初始化3D球体
|
// 保存当前状态
|
||||||
const init3DSphere = () => {
|
this.saveTechCloudState(container, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 初始化3D球体动画
|
||||||
|
init3DSphereAnimation(container, techStack) {
|
||||||
// 清除之前的动画
|
// 清除之前的动画
|
||||||
if (container.__animToken) {
|
if (container.__animToken) {
|
||||||
cancelAnimationFrame(container.__animToken);
|
cancelAnimationFrame(container.__animToken);
|
||||||
@@ -853,7 +937,7 @@ class UIManager {
|
|||||||
techStack.forEach((item, index) => {
|
techStack.forEach((item, index) => {
|
||||||
const el = document.createElement('a');
|
const el = document.createElement('a');
|
||||||
el.className = 'tech-tag-3d';
|
el.className = 'tech-tag-3d';
|
||||||
const colorClass = `tag-color-${item.gradientId || ((index % 10) + 1)}`;
|
const colorClass = `tag-color-${item.gradientId || ((index % 25) + 1)}`;
|
||||||
el.classList.add(colorClass);
|
el.classList.add(colorClass);
|
||||||
el.innerText = item.name;
|
el.innerText = item.name;
|
||||||
el.style.border = 'none';
|
el.style.border = 'none';
|
||||||
@@ -939,16 +1023,49 @@ class UIManager {
|
|||||||
};
|
};
|
||||||
|
|
||||||
container.__animToken = requestAnimationFrame(update);
|
container.__animToken = requestAnimationFrame(update);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置窗口大小变化监听器
|
||||||
|
setupResizeListener(container, techStack, currentType) {
|
||||||
|
// 使用防抖优化尺寸计算
|
||||||
|
let resizeTimeout;
|
||||||
|
let windowRef = currentType;
|
||||||
|
const handleResize = () => {
|
||||||
|
if (resizeTimeout) {
|
||||||
|
clearTimeout(resizeTimeout);
|
||||||
|
}
|
||||||
|
resizeTimeout = setTimeout(() => {
|
||||||
|
const isMobile = window.matchMedia('(max-width: 768px)').matches;
|
||||||
|
const currentState = isMobile ? 'mobile' : 'desktop';
|
||||||
|
if (windowRef === currentState) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
windowRef = currentState;
|
||||||
|
|
||||||
|
// 检查 sessionStorage 中是否有对应状态的内容
|
||||||
|
const savedState = sessionStorage.getItem('techCloudState_' + currentState);
|
||||||
|
if (savedState) {
|
||||||
|
// 直接使用保存的内容
|
||||||
|
const parsedState = JSON.parse(savedState);
|
||||||
|
container.innerHTML = parsedState.html;
|
||||||
|
if (currentState === 'mobile') {
|
||||||
|
container.classList.add('mobile-scroll');
|
||||||
|
}
|
||||||
|
if (currentState === 'desktop') {
|
||||||
|
container.classList.remove('mobile-scroll');
|
||||||
|
this.init3DSphereAnimation(container, techStack);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 重新生成
|
||||||
|
container.innerHTML = '';
|
||||||
|
this.generateTechCloud(container, techStack, currentState);
|
||||||
|
}
|
||||||
|
}, 100);
|
||||||
};
|
};
|
||||||
|
|
||||||
// 初始化3D球体
|
|
||||||
init3DSphere();
|
|
||||||
|
|
||||||
// 监听窗口大小变化
|
// 监听窗口大小变化
|
||||||
window.addEventListener('resize', updateContainerSize);
|
window.addEventListener('resize', handleResize);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
initFab() {
|
initFab() {
|
||||||
const main = document.getElementById('fab-main');
|
const main = document.getElementById('fab-main');
|
||||||
@@ -958,8 +1075,6 @@ class UIManager {
|
|||||||
const fMusic = document.getElementById('fab-music');
|
const fMusic = document.getElementById('fab-music');
|
||||||
if (!main || !menu || !fLang || !fTheme || !fMusic) return;
|
if (!main || !menu || !fLang || !fTheme || !fMusic) return;
|
||||||
|
|
||||||
// 添加拖拽功能
|
|
||||||
this.initDraggableFab();
|
|
||||||
|
|
||||||
const updateLabels = () => {
|
const updateLabels = () => {
|
||||||
// 使用requestAnimationFrame避免强制重排
|
// 使用requestAnimationFrame避免强制重排
|
||||||
@@ -968,10 +1083,33 @@ class UIManager {
|
|||||||
const theme = getStoredTheme();
|
const theme = getStoredTheme();
|
||||||
fLang.querySelector('.fab-text').textContent = lang === 'zh' ? 'English' : '中文';
|
fLang.querySelector('.fab-text').textContent = lang === 'zh' ? 'English' : '中文';
|
||||||
fTheme.querySelector('.fab-text').textContent = theme === 'night' ? 'Day' : 'Night';
|
fTheme.querySelector('.fab-text').textContent = theme === 'night' ? 'Day' : 'Night';
|
||||||
const playing = (this.audio && !this.audio.paused);
|
// 音频播放状态需要通过iframe通信获取
|
||||||
fMusic.querySelector('.fab-text').textContent = lang === 'zh' ? (playing ? '暂停' : '播放') : (playing ? 'Pause' : 'Play');
|
const audioIframe = document.getElementById('audio-player-iframe');
|
||||||
|
if (audioIframe && audioIframe.contentWindow) {
|
||||||
|
// 请求当前播放状态
|
||||||
|
audioIframe.contentWindow.postMessage({
|
||||||
|
action: 'getCurrentState'
|
||||||
|
}, '*');
|
||||||
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 监听来自iframe的音频状态更新
|
||||||
|
window.addEventListener('message', (event) => {
|
||||||
|
const audioIframe = document.getElementById('audio-player-iframe');
|
||||||
|
if (!audioIframe || event.source !== audioIframe.contentWindow) return;
|
||||||
|
|
||||||
|
const data = event.data;
|
||||||
|
if (data.action === 'currentState') {
|
||||||
|
const fMusic = document.getElementById('fab-music');
|
||||||
|
if (fMusic) {
|
||||||
|
const lang = getStoredLanguage();
|
||||||
|
fMusic.querySelector('.fab-text').textContent =
|
||||||
|
lang === 'zh' ? (data.playing ? '暂停' : '播放') : (data.playing ? 'Pause' : 'Play');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
main.addEventListener('click', () => {
|
main.addEventListener('click', () => {
|
||||||
menu.classList.toggle('open');
|
menu.classList.toggle('open');
|
||||||
main.setAttribute('aria-expanded', menu.classList.contains('open') ? 'true' : 'false');
|
main.setAttribute('aria-expanded', menu.classList.contains('open') ? 'true' : 'false');
|
||||||
@@ -989,17 +1127,15 @@ class UIManager {
|
|||||||
requestAnimationFrame(updateLabels);
|
requestAnimationFrame(updateLabels);
|
||||||
});
|
});
|
||||||
fMusic.addEventListener('click', () => {
|
fMusic.addEventListener('click', () => {
|
||||||
if (this.audio) {
|
const audioIframe = document.getElementById('audio-player-iframe');
|
||||||
if (this.audio.paused) {
|
if (audioIframe && audioIframe.contentWindow) {
|
||||||
this.audio.play().catch(() => {
|
// 直接发送播放指令,让iframe内部处理播放/暂停切换
|
||||||
});
|
audioIframe.contentWindow.postMessage({
|
||||||
// 清除暂停时间记录,允许下次自动播放
|
action: 'play'
|
||||||
this.clearMusicPauseTime();
|
}, '*');
|
||||||
} else {
|
|
||||||
this.audio.pause();
|
// 记录用户操作
|
||||||
// 记录暂停时间
|
this.setMusicPauseTime(); // 先记录暂停时间
|
||||||
this.setMusicPauseTime();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// 延迟更新标签以避免阻塞
|
// 延迟更新标签以避免阻塞
|
||||||
requestAnimationFrame(updateLabels);
|
requestAnimationFrame(updateLabels);
|
||||||
@@ -1008,90 +1144,127 @@ class UIManager {
|
|||||||
requestAnimationFrame(updateLabels);
|
requestAnimationFrame(updateLabels);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 初始化拖拽功能
|
|
||||||
initDraggableFab() {
|
|
||||||
const fab = document.querySelector('.mobile-fab');
|
|
||||||
if (!fab) return;
|
|
||||||
|
|
||||||
let isDragging = false;
|
|
||||||
let initialX, initialY, currentX, currentY, xOffset = 0, yOffset = 0;
|
|
||||||
fab.style.willChange = 'transform';
|
|
||||||
|
|
||||||
// 拖拽相关方法
|
|
||||||
const setTranslate = (xPos, yPos, el) => {
|
|
||||||
el.style.transform = `translate3d(${xPos}px, ${yPos}px, 0)`;
|
|
||||||
};
|
|
||||||
|
|
||||||
const dragStart = (e) => {
|
|
||||||
if (e.type === 'touchstart') {
|
|
||||||
initialX = e.touches[0].clientX - xOffset;
|
|
||||||
initialY = e.touches[0].clientY - yOffset;
|
|
||||||
} else {
|
|
||||||
initialX = e.clientX - xOffset;
|
|
||||||
initialY = e.clientY - yOffset;
|
|
||||||
}
|
|
||||||
isDragging = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
const dragEnd = () => {
|
|
||||||
initialX = currentX;
|
|
||||||
initialY = currentY;
|
|
||||||
isDragging = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
const drag = (e) => {
|
|
||||||
if (isDragging) {
|
|
||||||
e.preventDefault();
|
|
||||||
if (e.type === 'touchmove') {
|
|
||||||
currentX = e.touches[0].clientX - initialX;
|
|
||||||
currentY = e.touches[0].clientY - initialY;
|
|
||||||
} else {
|
|
||||||
currentX = e.clientX - initialX;
|
|
||||||
currentY = e.clientY - initialY;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 使用requestAnimationFrame优化拖拽动画
|
|
||||||
requestAnimationFrame(() => {
|
|
||||||
const ww = window.innerWidth;
|
|
||||||
const wh = window.innerHeight;
|
|
||||||
const rect = fab.getBoundingClientRect();
|
|
||||||
const fw = rect.width;
|
|
||||||
const fh = rect.height;
|
|
||||||
currentX = Math.max(0, Math.min(currentX, ww - fw));
|
|
||||||
currentY = Math.max(0, Math.min(currentY, wh - fh));
|
|
||||||
|
|
||||||
xOffset = currentX;
|
|
||||||
yOffset = currentY;
|
|
||||||
setTranslate(currentX, currentY, fab);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 绑定事件
|
|
||||||
fab.addEventListener('touchstart', dragStart, { passive: false });
|
|
||||||
fab.addEventListener('touchend', dragEnd, { passive: false });
|
|
||||||
fab.addEventListener('touchmove', drag, { passive: false });
|
|
||||||
fab.addEventListener('mousedown', dragStart, { passive: false });
|
|
||||||
fab.addEventListener('mouseup', dragEnd, { passive: false });
|
|
||||||
fab.addEventListener('mousemove', drag, { passive: false });
|
|
||||||
}
|
|
||||||
|
|
||||||
initAudio() {
|
initAudio() {
|
||||||
const el = document.getElementById('site-audio');
|
// 获取已存在的iframe或创建新的
|
||||||
if (!el) return;
|
let audioIframe = document.getElementById('audio-player-iframe');
|
||||||
this.audio = el;
|
if (!audioIframe) {
|
||||||
this.audio.loop = true;
|
audioIframe = document.createElement('iframe');
|
||||||
|
audioIframe.src = 'audio-player.html';
|
||||||
|
audioIframe.style.display = 'none';
|
||||||
|
audioIframe.id = 'audio-player-iframe';
|
||||||
|
document.body.appendChild(audioIframe);
|
||||||
|
}
|
||||||
|
this.audioIframe = audioIframe;
|
||||||
|
|
||||||
|
|
||||||
|
const autoPlayer = () => {
|
||||||
// 检查是否在24小时内用户暂停过音乐
|
// 检查是否在24小时内用户暂停过音乐
|
||||||
const shouldRemainPaused = this.shouldMusicRemainPaused();
|
const shouldRemainPaused = this.shouldMusicRemainPaused();
|
||||||
|
// 如果不应该保持暂停状态,则尝试播放
|
||||||
const tryPlay = () => {
|
|
||||||
if (!shouldRemainPaused) {
|
if (!shouldRemainPaused) {
|
||||||
this.audio.play().catch(() => {
|
// 添加用户交互检查,避免浏览器阻止自动播放
|
||||||
});
|
const attemptAutoplay = () => {
|
||||||
|
// 检查是否已有用户交互
|
||||||
|
if (this.userInteracted) {
|
||||||
|
this.playAudio();
|
||||||
|
} else {
|
||||||
|
// 添加一次性用户交互监听器
|
||||||
|
const enableAudio = () => {
|
||||||
|
this.userInteracted = true;
|
||||||
|
this.playAudio();
|
||||||
|
document.removeEventListener('click', enableAudio);
|
||||||
|
document.removeEventListener('touchstart', enableAudio);
|
||||||
|
document.removeEventListener('keydown', enableAudio);
|
||||||
|
document.removeEventListener('mousemove', enableAudio);
|
||||||
|
};
|
||||||
|
|
||||||
|
document.addEventListener('click', enableAudio, { once: true });
|
||||||
|
document.addEventListener('touchstart', enableAudio, { once: true });
|
||||||
|
document.addEventListener('keydown', enableAudio, { once: true });
|
||||||
|
document.addEventListener('mousemove', enableAudio, { once: true });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
tryPlay();
|
setTimeout(attemptAutoplay, 500); // 稍微延迟以确保iframe加载完成
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 监听iframe发来的消息
|
||||||
|
const handleMessage = (event) => {
|
||||||
|
// 确保消息来自我们的iframe
|
||||||
|
if (event.source !== this.audioIframe.contentWindow) return;
|
||||||
|
|
||||||
|
const data = event.data;
|
||||||
|
switch (data.action) {
|
||||||
|
case 'playerReady':
|
||||||
|
// iframe准备就绪,设置初始音频
|
||||||
|
this.setAudioTrack('data/至少做一件离谱的事-Kiri T_compressed.mp3');
|
||||||
|
autoPlayer();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'stateChange':
|
||||||
|
// 音频状态改变,更新UI
|
||||||
|
this.updateAudioUI(data.playing);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'trackEnded':
|
||||||
|
// 曲目结束
|
||||||
|
this.updateAudioUI(false);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'currentState':
|
||||||
|
// 当前状态响应
|
||||||
|
this.updateAudioUI(data.playing);
|
||||||
|
if (!data.playing) {
|
||||||
|
autoPlayer();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
window.addEventListener('message', handleMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 播放音频
|
||||||
|
playAudio() {
|
||||||
|
const audioIframe = document.getElementById('audio-player-iframe');
|
||||||
|
if (audioIframe && audioIframe.contentWindow) {
|
||||||
|
audioIframe.contentWindow.postMessage({
|
||||||
|
action: 'play'
|
||||||
|
}, '*');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 暂停音频
|
||||||
|
pauseAudio() {
|
||||||
|
const audioIframe = document.getElementById('audio-player-iframe');
|
||||||
|
if (audioIframe && audioIframe.contentWindow) {
|
||||||
|
audioIframe.contentWindow.postMessage({
|
||||||
|
action: 'pause'
|
||||||
|
}, '*');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置音频曲目
|
||||||
|
setAudioTrack(src) {
|
||||||
|
const audioIframe = document.getElementById('audio-player-iframe');
|
||||||
|
if (audioIframe && audioIframe.contentWindow) {
|
||||||
|
audioIframe.contentWindow.postMessage({
|
||||||
|
action: 'setTrack',
|
||||||
|
src: src
|
||||||
|
}, '*');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新音频UI状态
|
||||||
|
updateAudioUI(playing) {
|
||||||
|
// 更新移动端fab按钮的文本
|
||||||
|
const fMusic = document.getElementById('fab-music');
|
||||||
|
if (fMusic) {
|
||||||
|
const lang = getStoredLanguage();
|
||||||
|
fMusic.querySelector('.fab-text').textContent =
|
||||||
|
lang === 'zh' ? (playing ? '暂停' : '播放') : (playing ? 'Pause' : 'Play');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
updateCustomStyles(container, theme) {
|
updateCustomStyles(container, theme) {
|
||||||
|
|||||||
42
js/audio-service-worker.js
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
// audio-service-worker.js
|
||||||
|
// Service Worker for background audio playback
|
||||||
|
|
||||||
|
self.addEventListener('install', event => {
|
||||||
|
self.skipWaiting();
|
||||||
|
});
|
||||||
|
|
||||||
|
self.addEventListener('activate', event => {
|
||||||
|
event.waitUntil(self.clients.claim());
|
||||||
|
});
|
||||||
|
|
||||||
|
// 监听来自主页面的消息
|
||||||
|
self.addEventListener('message', async event => {
|
||||||
|
const client = event.source;
|
||||||
|
const data = event.data;
|
||||||
|
|
||||||
|
switch (data.action) {
|
||||||
|
case 'play':
|
||||||
|
// 这里只是示例,实际上Service Worker无法直接播放音频
|
||||||
|
// 我们需要采用另一种方式实现
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'pause':
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'setTrack':
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 使用 Broadcast Channel API 在页面间通信
|
||||||
|
const broadcastChannel = new BroadcastChannel('audio-control');
|
||||||
|
|
||||||
|
broadcastChannel.addEventListener('message', event => {
|
||||||
|
const data = event.data;
|
||||||
|
// 将消息转发给所有客户端
|
||||||
|
self.clients.matchAll().then(clients => {
|
||||||
|
clients.forEach(client => {
|
||||||
|
client.postMessage(data);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
43
js/config.js
@@ -18,13 +18,13 @@ const SiteConfig = {
|
|||||||
|
|
||||||
background: {
|
background: {
|
||||||
imagePaths: [
|
imagePaths: [
|
||||||
"/images/bj/1.jpg",
|
"/images/bj/1.webp",
|
||||||
"/images/bj/2.jpg",
|
"/images/bj/2.webp",
|
||||||
"/images/bj/3.jpg",
|
"/images/bj/3.webp",
|
||||||
"/images/bj/4.jpg",
|
"/images/bj/4.webp",
|
||||||
"/images/bj/5.jpg",
|
"/images/bj/5.webp",
|
||||||
"/images/bj/6.jpg",
|
"/images/bj/6.webp",
|
||||||
"/images/bj/7.jpg"
|
"/images/bj/7.webp"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -133,9 +133,9 @@ const SiteConfig = {
|
|||||||
// 站点统计配置
|
// 站点统计配置
|
||||||
analytics: {
|
analytics: {
|
||||||
busuanzi: {
|
busuanzi: {
|
||||||
src: 'https://events.vercount.one/js',
|
src: '//cdn.busuanzi.cc/busuanzi/3.6.9/busuanzi.abbr.min.js',
|
||||||
site_pv_id: 'busuanzi_value_site_pv',
|
site_pv_id: 'busuanzi_site_pv',
|
||||||
site_uv_id: 'busuanzi_value_site_uv',
|
site_uv_id: 'busuanzi_site_uv',
|
||||||
formatter: true
|
formatter: true
|
||||||
},
|
},
|
||||||
baidu: {
|
baidu: {
|
||||||
@@ -170,29 +170,6 @@ const SiteConfig = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if (Array.isArray(SiteConfig.techStack)) {
|
|
||||||
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);
|
|
||||||
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 };
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// 导出配置
|
// 导出配置
|
||||||
if (typeof module !== 'undefined' && module.exports) {
|
if (typeof module !== 'undefined' && module.exports) {
|
||||||
|
|||||||
@@ -49,18 +49,16 @@ $(document).ready(function () {
|
|||||||
/**
|
/**
|
||||||
* 自定义壁纸
|
* 自定义壁纸
|
||||||
*/
|
*/
|
||||||
var imgUrls = JSON.parse(sessionStorage.getItem("imgUrls"));
|
var imgUrls = null; //JSON.parse(sessionStorage.getItem("imgUrls"));
|
||||||
var index = sessionStorage.getItem("index");
|
|
||||||
var $panel = $('#panel');
|
var $panel = $('#panel');
|
||||||
var date = new Date();
|
var date = new Date();
|
||||||
var dayOfWeek = date.getDay();
|
var dayOfWeek = date.getDay();
|
||||||
if (imgUrls == null) {
|
if (imgUrls == null) {
|
||||||
imgUrls = [];
|
imgUrls = [];
|
||||||
index = 0;
|
|
||||||
SiteConfig.background.imagePaths.forEach(path => {
|
SiteConfig.background.imagePaths.forEach(path => {
|
||||||
imgUrls.push(path);
|
imgUrls.push(path);
|
||||||
});
|
});
|
||||||
sessionStorage.setItem("imgUrls", JSON.stringify(imgUrls));
|
//sessionStorage.setItem("imgUrls", JSON.stringify(imgUrls));
|
||||||
// sessionStorage.setItem("index", index);
|
// sessionStorage.setItem("index", index);
|
||||||
} else {
|
} else {
|
||||||
// if (index == imgUrls.length)
|
// if (index == imgUrls.length)
|
||||||
|
|||||||
93
js/sw.js
@@ -1,93 +0,0 @@
|
|||||||
// Service Worker for PWA
|
|
||||||
const CACHE_NAME = 'honesty-home-v1.0.1';
|
|
||||||
const urlsToCache = [
|
|
||||||
'./index.html',
|
|
||||||
'./about.html',
|
|
||||||
'./css/style.css',
|
|
||||||
'./css/about.css',
|
|
||||||
'./css/artalk.css',
|
|
||||||
'./js/config.js',
|
|
||||||
'./js/main.js',
|
|
||||||
'./js/about.js',
|
|
||||||
'./images/avatar.jpeg',
|
|
||||||
'./images/favicon.ico',
|
|
||||||
'./images/favicon.png',
|
|
||||||
'./images/logo.png',
|
|
||||||
'./images/INFJ.png',
|
|
||||||
'./images/kl.gif',
|
|
||||||
'./images/bj/1.jpg',
|
|
||||||
'./images/bj/2.jpg',
|
|
||||||
'./images/bj/3.jpg',
|
|
||||||
'./images/bj/4.jpg',
|
|
||||||
'./images/bj/5.jpg',
|
|
||||||
'./images/bj/6.jpg',
|
|
||||||
'./images/bj/7.jpg',
|
|
||||||
];
|
|
||||||
|
|
||||||
// 安装事件 - 缓存资源
|
|
||||||
self.addEventListener('install', event => {
|
|
||||||
event.waitUntil(
|
|
||||||
caches.open(CACHE_NAME)
|
|
||||||
.then(cache => {
|
|
||||||
console.log('Opened cache');
|
|
||||||
return cache.addAll(urlsToCache);
|
|
||||||
})
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
// 获取事件 - 拦截网络请求
|
|
||||||
self.addEventListener('fetch', event => {
|
|
||||||
// 对于非GET请求或者不是同源请求,直接跳过
|
|
||||||
if (event.request.method !== 'GET' || !event.request.url.startsWith(self.location.origin)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
event.respondWith(
|
|
||||||
caches.match(event.request)
|
|
||||||
.then(response => {
|
|
||||||
// 如果在缓存中找到响应,则返回缓存的资源
|
|
||||||
if (response) {
|
|
||||||
return response;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 克隆请求,因为请求是一个流,只能被消费一次
|
|
||||||
const fetchRequest = event.request.clone();
|
|
||||||
|
|
||||||
// 如果没有在缓存中找到,则发起网络请求
|
|
||||||
return fetch(fetchRequest).then(response => {
|
|
||||||
// 检查响应是否有效
|
|
||||||
if (!response || response.status !== 200 || response.type !== 'basic') {
|
|
||||||
return response;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 克隆响应,因为响应是一个流,只能被消费一次
|
|
||||||
const responseToCache = response.clone();
|
|
||||||
|
|
||||||
// 打开缓存并将响应添加到缓存中
|
|
||||||
caches.open(CACHE_NAME)
|
|
||||||
.then(cache => {
|
|
||||||
cache.put(event.request, responseToCache);
|
|
||||||
});
|
|
||||||
|
|
||||||
return response;
|
|
||||||
});
|
|
||||||
})
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
// 激活事件 - 清理旧缓存
|
|
||||||
self.addEventListener('activate', event => {
|
|
||||||
const cacheWhitelist = [CACHE_NAME];
|
|
||||||
|
|
||||||
event.waitUntil(
|
|
||||||
caches.keys().then(cacheNames => {
|
|
||||||
return Promise.all(
|
|
||||||
cacheNames.map(cacheName => {
|
|
||||||
if (cacheWhitelist.indexOf(cacheName) === -1) {
|
|
||||||
return caches.delete(cacheName);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
);
|
|
||||||
})
|
|
||||||
);
|
|
||||||
});
|
|
||||||