41 Commits

Author SHA1 Message Date
hehh
532cbafd8e feat(audio): 重构音频播放功能以支持iframe隔离播放
- 将音频播放器移至独立的iframe中以提升性能和隔离性
- 实现主页面与iframe之间的postMessage通信机制
- 添加音频播放状态同步和UI更新逻辑
- 支持自动播放控制和用户交互检测
- 实现播放状态持久化存储和恢复功能
- 优化移动端音频控制体验
- 添加版权信息更新和国际化支持
2025-11-30 16:42:00 +08:00
hehh
30e13e5bde feat(audio): 优化音频自动播放逻辑以适应浏览器策略
- 添加用户交互检查,避免浏览器阻止自动播放
- 实现一次性用户交互监听器,提升播放体验
- 保留requestAnimationFrame以确保播放时机准确
- 增加多种用户交互事件支持(点击、触摸、键盘、鼠标移动)
2025-11-30 16:13:15 +08:00
hehh
41184ad1d8 feat(about): 扩展渐变色板并优化技术标签样式
- 新增 15 种 CSS 渐变色变量(从 --gradient-11 到 --gradient-25)
- 为白天和夜间主题添加对应的新技术标签颜色类(.tag-color-11 到 .tag-color-25)
- 更新 JavaScript 中 gradientId 的取值范围从 10 扩展到 25
- 移除旧的控制台日志输出
- 调整配置文件中的空行格式,提升可读性
2025-11-30 16:02:49 +08:00
hehh
bff0b529d2 fix(audio): 修复音频自动播放问题
- 使用 requestAnimationFrame 包装音频播放逻辑
- 确保在用户交互后正确触发播放
- 保留原有的静默错误处理机制

style(artalk): 优化移动端评论样式

- 移除重复的 CSS 选择器定义
- 调整评论区域 padding 和字体大小
- 优化黑夜模式下评论背景透明度
- 修复移动端头像拉伸显示问题
- 移除夜间模式下不必要的边框和圆角
- 完全移除评论容器的边框和阴影样式
- 更新分页按钮的内边距和字体大小
- 修复移动端输入框背景色问题
2025-11-30 15:25:56 +08:00
hehh
b179431aaa feat(about): 优化技术标签云渲染与状态管理
- 引入 sessionStorage 缓存技术标签云状态,提升页面切换性能
- 区分移动端与桌面端渲染逻辑,实现响应式适配
- 抽离 3D 球体动画初始化方法,增强代码可维护性
- 添加窗口大小变化监听器,动态调整渲染内容
- 实现标签云生成与状态保存功能,避免重复计算
- 优化动画性能,使用 requestAnimationFrame 处理鼠标交互
2025-11-30 02:13:13 +08:00
hehh
569ad36db1 fix(css): 修复黑夜模式下插件面板和评论计数的样式问题
- 修复黑夜模式下插件面板背景色和文字颜色显示异常
- 调整插件面板边框、圆角和阴影效果
- 优化评论计数文字颜色、粗细和阴影效果
- 修复下拉菜单背景、边框和悬停状态样式
- 调整下拉菜单项的激活状态背景色
- 修复箭头图标在黑夜模式下的亮度问题
2025-11-30 00:07:51 +08:00
hehh
d0cd750e22 style(css): 调整玻璃态背景透明度并修复动画键帧格式
- 将玻璃态背景的不透明度从 0.85 调整为 0.55
- 修复 fadeIn 动画关键帧中的多余空格问题
- 确保动画过渡更加平滑自然
- 统一 CSS 样式代码格式以提高可维护性
- 优化加载过渡效果的视觉表现
- 移除不必要的样式声明以减少文件体积
2025-11-29 21:05:32 +08:00
hehh
ccda6074be feat(about): 增强 GitHub 数据获取与降级机制
- 为用户数据请求添加本地 JSON 降级方案
- 为仓库数据请求添加本地 JSON 降级方案
- 拆分用户与仓库数据获取逻辑,提高可维护性
- 增加对 AbortError 等异常情况的处理
- 移除全局异常处理中的默认配置兜底逻辑
- 优化超时设置,区分不同资源的加载时间限制
2025-11-29 21:02:32 +08:00
hehh
1b94b8bf93 feat(about): 优化夜间模式视觉效果和可访问性
- 提高玻璃态背景和文本的不透明度以增强可读性
- 调整夜间模式下评论区域的颜色和边框可见性
- 为功能按钮和链接添加tabindex属性提升键盘导航
- 增加多语言和SEO相关的meta标签及canonical链接
- 优化Artalk评论系统的主题切换逻辑和UI增强
- 更新移动端悬浮按钮和社交链接的无障碍标签
2025-11-29 20:52:30 +08:00
hehh
9a73273c34 feat(about): 添加 GitHub 数据的本地回退机制
- 在 GitHub API 请求失败时,从本地 JSON 文件获取用户数据
- 在 GitHub API 请求失败时,从本地 JSON 文件获取仓库数据
- 实现带超时的 fetch 方法以提高加载性能
- 优化错误处理逻辑,增强页面容错能力
2025-11-29 20:34:27 +08:00
hehh
ea04260290 feat(data): 更新 GitHub 仓库数据列表
- 添加 spring-ai-example 项目信息
- 更新 yunxiao-LLM-reviewer 项目描述与星标数
- 移除旧 hexo-theme-stellar 项目记录
- 添加 Home 个人主页项目信息
- 添加 collection-complete Java 库项目信息
- 添加 keycloak-services-social-weixin 项目信息
- 替换 Universal-IoT-Java 为 Notion-Wechat-Blog 项目
- 添加 social-auth 项目信息
- 添加 hp-lite 内网穿透工具项目信息
2025-11-29 20:30:53 +08:00
hehh
9c8a1f035f feat(about): 移除 Artalk.js 的异步加载属性
- 将 Artalk.js 的加载方式从异步改为同步
- 确保评论系统在页面加载时立即初始化
- 避免因异步加载导致的评论框渲染延迟问题
2025-11-29 12:21:58 +08:00
hehh
a4cd5d6535 feat(perf): 优化图片加载性能
- 为多个页面中的图片元素添加 loading="lazy" 属性
- 对 Artalk.js 脚本引入增加 async 属性以提升加载性能
- 减少初始页面加载时不必要的资源阻塞
- 提高用户访问速度与页面响应效率
2025-11-28 17:07:58 +08:00
hehh
c2585ea504 fix(audio): 修复页面加载时音频自动播放问题
- 移除音频元素的 autoplay 属性
- 将音频播放逻辑移至 window load 事件后执行
- 添加播放失败的静默错误处理
- 保留循环播放和预加载设置
- 确保用户暂停状态在24小时内被记住
- 优化音频播放时机以提升用户体验
2025-11-28 17:02:56 +08:00
hehh
3589df9032 chore(about): 更新页面元数据和音频资源引用
- 调整页面中多个区域间的空行格式
- 更新背景音乐文件名为压缩版本以优化加载
- 确保HTML标签正确闭合
2025-11-28 16:51:06 +08:00
hehh
99d5420024 chore(about): 移除冗余样式文件引用
- 删除了对 css/style.css 的重复引用
- 保留了 about 页面专用的 css/about.css 引用
- 确保样式加载顺序和依赖关系正确
2025-11-28 11:13:47 +08:00
hehh
f66c17095b refactor(css): 添加 contain 属性优化布局性能
- 在多个组件样式中添加 contain: layout style 提升渲染性能
- 移除移动端浮动按钮的拖拽功能实现
- 简化 JavaScript 中的 FAB 元素初始化逻辑
- 清理未使用的拖拽相关事件监听器绑定代码
2025-11-27 15:59:24 +08:00
hehh
86468a9f77 chore(site): 优化网站性能与样式细节
- 将 jQuery 引用从 BootCDN 改为本地文件以提升加载速度
- 移除页面 body 标签中的禁止右键和选择属性,提高用户体验
- 为事件监听器添加 passive 选项以提升滚动性能
- 调整 StarrySky.js 中 canvas 阴影模糊值以优化视觉效果
- 更新 CSS 样式颜色值,增强文字可读性与整体美观度
- 统一并优化部分文本阴影及字体抗锯齿设置
2025-11-27 15:49:12 +08:00
hehh
0c55a90662 refactor(about): 移除多语言包引入
- 删除了 artalk 多语言包的引入
- 简化了页面资源加载逻辑
- 减少了不必要的网络请求
2025-11-27 14:59:28 +08:00
hehh
0eac618a71 style(css): 优化夜间模式下的编辑器样式
- 调整夜间模式下工具栏按钮的颜色和亮度
- 修改夜间模式下输入框的背景透明度和边框颜色
- 增强夜间模式下输入框的阴影效果
- 提高夜间模式下输入框聚焦时的阴影透明度
2025-11-27 02:40:11 +08:00
hehh
200da80262 fix(main): 禁用自定义壁纸功能
- 注释掉从sessionStorage获取图片URL的代码
- 将imgUrls变量初始化为null
- 暂时禁用自定义壁纸相关逻辑
2025-11-27 02:30:29 +08:00
hehh
753f12e5d9 fix(about): 修复多语言支持中的区域设置问题
- 将默认英文区域设置从 'en-US' 更改为 'en'
- 统一日期本地化方法中的区域参数
- 确保中英文切换时的语言一致性
2025-11-27 02:24:46 +08:00
hehh
50fcc7454d feat(assets): 将图片资源从 JPG/PNG 更新为 WebP 格式
- 将 MBTI 图标从 PNG 更改为 WebP 格式以优化加载性能
- 更新背景图片路径配置以使用 WebP 图片资源
- 移除对 sessionStorage 中图片 URL 列表的重复设置逻辑
2025-11-27 02:19:45 +08:00
hehh
747021c259 feat(i18n): 支持通过URL参数设置语言
- 新增从URL查询参数中读取lang值的功能
- 支持lang参数为zh或en时设置并存储语言
- 保留原有的本地存储语言获取逻辑作为备用方案
- 添加错误处理防止URL解析异常

chore(assets): 更新微信二维码图片路径

- 将about.html中的微信二维码图片地址改为相对路径
- 将index.html中的微信二维码图片地址改为相对路径
- 移除远程CDN备用加载逻辑,统一使用本地资源
2025-11-26 17:18:54 +08:00
hehh
9f0d3d0a2a fix(about): 调整GitHub用户数据获取超时时间
- 将GitHub用户数据请求的超时时间从5秒调整为1秒
- 优化用户体验,减少等待时间
- 确保快速失败,提高页面响应速度
2025-11-26 12:41:34 +08:00
hehh
ac6c85a490 refactor(about): 调整 DataManager 初始化顺序
- 将 DataManager 的初始化移到 UIManager 之后
- 保持依赖注入的一致性
- 提高代码可读性和维护性
2025-11-26 12:36:53 +08:00
hehh
7f959b1b34 style(css): 优化黑夜模式下的评论区样式
- 调整输入框背景透明度和文字颜色以提升可读性
- 增强评论区域的视觉层次和悬停效果
- 新增编辑器底部工具栏的美化样式
- 优化发送按钮的渐变背景和交互动效
- 改进评论列表项的文字颜色和链接样式
- 统一黑夜模式下各组件的边框和阴影效果
2025-11-26 10:20:53 +08:00
hehh
d3cd2b69fe fix(ui): 修复夜间模式下编辑器文本颜色显示异常
- 将夜间模式编辑器文本颜色从 #dfe6e9 调整为 #1f2937
- 确保文本在深色背景下具有更好的可读性
- 保持与其他夜间模式组件的一致性
2025-11-26 01:06:39 +08:00
hehh
eec6778f8d fix(css): 修正夜间模式下的样式问题
- 删除了 about.css 中多余的闭合括号
- 调整了 artalk.css 中夜间模式输入框的文字颜色以提高可读性
2025-11-26 01:04:12 +08:00
hehh
0fbfd7b6dd style(css): 调整黑夜模式下的输入框和评论列表样式
- 为PC端黑夜模式下的编辑器文本区域添加背景、文字颜色及边框样式
- 设置编辑器文本区域聚焦时的边框和阴影效果
- 为评论包裹元素添加黑夜模式下的背景、边框和阴影样式
- 添加评论包裹元素在悬停状态下的样式变化
- 为评论列表头部和通用头部添加底部边框样式
2025-11-26 01:02:18 +08:00
hehh
ace68a0bad feat(about): 优化夜间主题样式及统计数据显示逻辑
- 为夜间主题的区域统计添加悬停效果
- 修复CSS语法错误,移除多余闭合括号
- 调整GitHub仓库拉取逻辑,增加超时控制和排序方式
- 修改展示仓库数量从12个至16个
- 移除页面访问量的格式化函数及相关调用
- 删除冗余的数据格式化脚本,简化加载逻辑
2025-11-26 00:59:09 +08:00
hehh
01e55e6d82 feat(analytics): 添加不蒜子统计数据格式化功能
- 更新不蒜子统计元素 ID 配置
- 实现自动格式化脚本,支持 K/W/M 单位转换
- 添加对 Google 和腾讯分析配置的动态引用
- 替换博客链接为 Twitter 链接并更新图标
- 优化统计数据显示逻辑,处理禁用状态与数字格式化
2025-11-26 00:16:40 +08:00
hehh
f9a1587587 refactor(css): 重新组织夜间主题样式结构
- 将夜间主题样式从文件中间位置移动到文件末尾
- 保持所有夜间主题相关样式的一致性和完整性
- 改善代码可读性和维护性
- 确保样式在不同主题切换时的正确应用
2025-11-25 23:58:19 +08:00
hehh
cea62b1c77 feat(analytics): 更新不蒜子统计脚本并移除本地格式化逻辑
- 将不蒜子统计脚本源地址更新为官方 CDN 地址
- 移除本地实现的访问量格式化脚本
- 依赖外部库自带的格式化功能替代原有手动实现
- 简化代码结构,减少冗余逻辑
- 提升页面加载性能与维护性
- 统一使用外部库的标准格式化规则
2025-11-25 22:35:24 +08:00
hehh
c293d31969 docs(readme): 修复代码块语法和任务列表格式
- 修复 README.md 中的代码块语法,将 `-``shell` 更正为 ```shell
- 修复任务列表中的格式错误,将 `-- []` 更正为 `- [ ]`
2025-11-25 22:28:25 +08:00
hehh
20b46b9fd2 fix(css): 调整英文状态下.stat-key的字体大小
- 针对[data-lang="en"]选择器下的.stat-key元素
- 将字体大小从0.6rem改为6px
- 使用!important确保样式优先级
2025-11-25 21:52:51 +08:00
hehh
b606b54d9b fix(i18n): 修正中英文翻译标签错误
- 交换了中文环境下 stats.visitors 和 stats.visitNum 的翻译值
- 交换了英文环境下 stats.visitors 和 stats.visitNum 的翻译值
- 确保访客数和访问量的显示标签正确对应
- 避免用户统计数据展示时产生误解
2025-11-25 21:50:02 +08:00
hehh
ff78d2c8b4 Merge branch 'version-2.2'
# Conflicts:
#	about.html
#	index.html
#	js/sw.js
2025-11-25 21:46:40 +08:00
hehh
14e669178e style(css): 增强黑夜模式下的统计区域样式
- 移除旧的 stat-key 样式定义
- 添加黑夜模式下 area-stats 的背景、边框和阴影效果
- 定义黑夜模式下 stat-item 的背景及悬停效果
- 设置黑夜模式下 stat-val 的文字颜色和发光效果
- 配置黑夜模式下 stat-key 的文字颜色和微弱发光效果
2025-11-25 21:45:58 +08:00
hehh
d8290974b5 refactor(about): 重构关于页面样式与交互逻辑
- 优化技术栈展示区域,新增3D标签云效果
- 调整兴趣模块布局,增强移动端适配
- 改进统计区域响应式设计,统一白天/黑夜模式样式
- 新增移动端社交链接区域,优化触摸体验
- 引入防抖机制优化3D球体动画性能
- 增强评论系统UI,支持动态主题切换
- 完善移动端评论内容展开收起功能
- 优化Artalk评论初始化流程,提高加载效率
- 统一全局样式命名规范,提升代码可维护性
- 移除冗余CSS规则,精简样式文件体积
- 修复黑夜模式下文字渐变显示异常问题
- 改进多语言支持,增强国际化体验
2025-11-25 20:21:22 +08:00
hehh
56d260e0d6 refactor(pwa): 移除PWA相关配置和Service Worker实现
- 删除 about.html 和 index.html 中的 PWA meta 标签
- 移除 PWA 注册脚本和服务工作器文件 js/sw.js
- 清理 Apple 和 Windows PWA 支持的相关配置
- 简化应用加载逻辑,不再依赖离线缓存机制
- 更新 manifest.json 引用及相关主题颜色设置
- 优化移动端显示设置,去除 user-scalable 属性
2025-11-25 18:44:31 +08:00
27 changed files with 2746 additions and 3186 deletions

View File

@@ -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 支持,支持离线访问
## 🙏 鸣谢与致敬 ## 🙏 鸣谢与致敬

View File

@@ -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>&copy; 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 &copy; 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
View 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>

File diff suppressed because it is too large Load Diff

View File

@@ -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;
} }

View File

@@ -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);
} }

View File

@@ -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"
} }
] ]

Binary file not shown.

BIN
images/INFJ.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

BIN
images/bj/1.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 691 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 MiB

BIN
images/bj/2.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 415 KiB

BIN
images/bj/3.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 488 KiB

BIN
images/bj/4.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 MiB

BIN
images/bj/5.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 168 KiB

BIN
images/bj/6.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

BIN
images/bj/7.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 786 KiB

BIN
images/bj/8.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 MiB

BIN
images/mp-honesy.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

View File

@@ -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>

View File

@@ -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();

View File

@@ -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() {
this.lang = getStoredLanguage(); // 获取当前请求参数有无 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.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);
let allRepos = []; try {
let page = 1; const uRes = await this.fetchWithTimeout(`https://api.github.com/users/${user}`, { timeout: 1000 });
const perPage = 100; if (uRes.ok) {
while (page <= 10) { // 最多抓取1000条直到满足条件或为空 userData = await uRes.json();
const rRes = await this.fetchWithTimeout(`https://api.github.com/users/${user}/repos?sort=stars&per_page=${perPage}&page=${page}`, { timeout: 5000 }); } else {
if (!rRes.ok) break; const fallbackUser = await this.fetchWithTimeout("./data/github_user.json", { timeout: 200 });
const repos = await rRes.json(); userData = await fallbackUser.json();
if (!Array.isArray(repos) || repos.length === 0) break; }
allRepos = allRepos.concat(repos); } catch (err) {
if (repos.length < perPage || allRepos.length >= 1000) break; // 足量 // Handle abort errors and other fetch errors
page++; 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 page = 1;
const perPage = 100;
while (page <= 50) { // 最多抓取500条直到满足条件或为空
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;
const repos = await rRes.json();
if (!Array.isArray(repos) || repos.length === 0) break;
allRepos = allRepos.concat(repos);
if (repos.length < perPage || allRepos.length >= 500) break; // 足量
page++;
}
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();
} }
let repoData = allRepos.length ? allRepos : (window.SiteConfig?.defaults?.repos);
// 过滤掉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;
@@ -699,29 +735,31 @@ class UIManager {
} }
// 监听主题/语言变化 // 监听主题/语言变化
if (this._themeLangObserver) { const themeObserver = new MutationObserver(() => {
try { this._themeLangObserver.disconnect(); } catch (_) {}
}
const prevTheme = document.documentElement.getAttribute('data-theme');
const prevLang = document.documentElement.getAttribute('data-lang');
this._lastTheme = prevTheme;
this._lastLang = prevLang;
this._reloading = false;
this._themeLangObserver = new MutationObserver(() => {
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');
if (this._reloading) return; console.log('Theme/Language changed:', newTheme, newLang);
if (newTheme === this._lastTheme && newLang === this._lastLang) return; if (newLang && newLang !== lang) {
this._lastTheme = newTheme; // 延迟执行
this._lastLang = newLang; setTimeout(() => {
setTimeout(() => { // 重新加载整个评论组件
if (this._reloading) return; this.reloadArtalk();
this._reloading = true; }, 300);
this.reloadArtalk(); } else if (newTheme && newTheme !== currentTheme) {
this._reloading = false; try {
}, 300); artalkRef.ui.setDarkMode(newTheme === 'night')
} catch (e) {
setTimeout(() => {
// 重新加载整个评论组件
this.reloadArtalk();
}, 300);
}
}
}); });
this._themeLangObserver.observe(document.documentElement, {
themeObserver.observe(document.documentElement, {
attributes: true, attributes: true,
attributeFilter: ['data-theme', 'data-lang'] attributeFilter: ['data-theme', 'data-lang']
}); });
@@ -799,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;
@@ -819,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';
@@ -837,131 +915,157 @@ 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 = () => {
// 清除之前的动画
if (container.__animToken) {
cancelAnimationFrame(container.__animToken);
}
// 清空容器
container.innerHTML = '';
const tags = [];
techStack.forEach((item, index) => {
const el = document.createElement('a');
el.className = 'tech-tag-3d';
const colorClass = `tag-color-${item.gradientId || ((index % 10) + 1)}`;
el.classList.add(colorClass);
el.innerText = item.name;
el.style.border = 'none';
container.appendChild(el);
tags.push({el, x: 0, y: 0, z: 0, bw: el.offsetWidth, bh: el.offsetHeight});
});
// 动态半径,避免容器溢出,使用防抖优化
const cw = container.clientWidth;
const ch = container.clientHeight;
let radius = Math.max(160, Math.min(cw, ch) / 2 - 24);
const dtr = Math.PI / 180;
let lasta = 1, lastb = 1;
let active = false, mouseX = 0, mouseY = 0;
// 初始化位置
tags.forEach((tag, i) => {
let phi = Math.acos(-1 + (2 * i + 1) / tags.length);
let theta = Math.sqrt(tags.length * Math.PI) * phi;
tag.x = radius * Math.cos(theta) * Math.sin(phi);
tag.y = radius * Math.sin(theta) * Math.sin(phi);
tag.z = radius * Math.cos(phi);
});
container.onmouseover = () => active = true;
container.onmouseout = () => active = false;
container.onmousemove = (e) => {
// 使用requestAnimationFrame处理鼠标移动事件避免强制重排
requestAnimationFrame(() => {
let rect = container.getBoundingClientRect();
mouseX = (e.clientX - (rect.left + rect.width / 2)) / 5;
mouseY = (e.clientY - (rect.top + rect.height / 2)) / 5;
});
};
const update = () => {
let a, b;
if (active) {
a = (-Math.min(Math.max(-mouseY, -200), 200) / radius) * 2;
b = (Math.min(Math.max(-mouseX, -200), 200) / radius) * 2;
} else {
a = lasta * 0.98; // Auto rotate
b = lastb * 0.98;
}
lasta = a;
lastb = b;
if (Math.abs(a) <= 0.01 && Math.abs(b) <= 0.01 && !active) a = 0.5; // Keep spinning slowly
let sa = Math.sin(a * dtr), ca = Math.cos(a * dtr);
let sb = Math.sin(b * dtr), cb = Math.cos(b * dtr);
// 批量更新样式以减少重排
// 先收集所有需要更新的样式信息
const updates = [];
tags.forEach(tag => {
let rx1 = tag.x, ry1 = tag.y * ca - tag.z * sa, rz1 = tag.y * sa + tag.z * ca;
let ry2 = ry1, rz2 = rx1 * -sb + rz1 * cb;
tag.x = rx1 * cb + rz1 * sb;
tag.y = ry2;
tag.z = rz2;
let scale = (tag.z + radius) / (2 * radius) + 0.45;
scale = Math.min(Math.max(scale, 0.7), 1.15);
const opacity = (tag.z + radius) / (2 * radius) + 0.2;
const zIndex = parseInt(scale * 100);
const left = tag.x + cw / 2 - tag.bw / 2;
const top = tag.y + ch / 2 - tag.bh / 2;
updates.push({
el: tag.el,
transform: `translate(${left}px, ${top}px) scale(${scale})`,
opacity: opacity,
zIndex: zIndex
});
});
updates.forEach(update => {
update.el.style.transform = update.transform;
update.el.style.opacity = update.opacity;
update.el.style.zIndex = update.zIndex;
});
container.__animToken = requestAnimationFrame(update);
};
container.__animToken = requestAnimationFrame(update);
};
// 初始化3D球体
init3DSphere();
// 监听窗口大小变化
window.addEventListener('resize', updateContainerSize);
} }
// 保存当前状态
this.saveTechCloudState(container, type);
} }
// 初始化3D球体动画
init3DSphereAnimation(container, techStack) {
// 清除之前的动画
if (container.__animToken) {
cancelAnimationFrame(container.__animToken);
}
// 清空容器
container.innerHTML = '';
const tags = [];
techStack.forEach((item, index) => {
const el = document.createElement('a');
el.className = 'tech-tag-3d';
const colorClass = `tag-color-${item.gradientId || ((index % 25) + 1)}`;
el.classList.add(colorClass);
el.innerText = item.name;
el.style.border = 'none';
container.appendChild(el);
tags.push({el, x: 0, y: 0, z: 0});
});
// 动态半径,避免容器溢出,使用防抖优化
let radius = Math.max(160, Math.min(container.offsetWidth, container.offsetHeight) / 2 - 24);
const dtr = Math.PI / 180;
let lasta = 1, lastb = 1;
let active = false, mouseX = 0, mouseY = 0;
// 初始化位置
tags.forEach((tag, i) => {
let phi = Math.acos(-1 + (2 * i + 1) / tags.length);
let theta = Math.sqrt(tags.length * Math.PI) * phi;
tag.x = radius * Math.cos(theta) * Math.sin(phi);
tag.y = radius * Math.sin(theta) * Math.sin(phi);
tag.z = radius * Math.cos(phi);
});
container.onmouseover = () => active = true;
container.onmouseout = () => active = false;
container.onmousemove = (e) => {
// 使用requestAnimationFrame处理鼠标移动事件避免强制重排
requestAnimationFrame(() => {
let rect = container.getBoundingClientRect();
mouseX = (e.clientX - (rect.left + rect.width / 2)) / 5;
mouseY = (e.clientY - (rect.top + rect.height / 2)) / 5;
});
};
const update = () => {
let a, b;
if (active) {
a = (-Math.min(Math.max(-mouseY, -200), 200) / radius) * 2;
b = (Math.min(Math.max(-mouseX, -200), 200) / radius) * 2;
} else {
a = lasta * 0.98; // Auto rotate
b = lastb * 0.98;
}
lasta = a;
lastb = b;
if (Math.abs(a) <= 0.01 && Math.abs(b) <= 0.01 && !active) a = 0.5; // Keep spinning slowly
let sa = Math.sin(a * dtr), ca = Math.cos(a * dtr);
let sb = Math.sin(b * dtr), cb = Math.cos(b * dtr);
// 批量更新样式以减少重排
// 先收集所有需要更新的样式信息
const updates = [];
tags.forEach(tag => {
let rx1 = tag.x, ry1 = tag.y * ca - tag.z * sa, rz1 = tag.y * sa + tag.z * ca;
let ry2 = ry1, rz2 = rx1 * -sb + rz1 * cb;
tag.x = rx1 * cb + rz1 * sb;
tag.y = ry2;
tag.z = rz2;
let scale = (tag.z + radius) / (2 * radius) + 0.45;
scale = Math.min(Math.max(scale, 0.7), 1.15);
const opacity = (tag.z + radius) / (2 * radius) + 0.2;
const zIndex = parseInt(scale * 100);
const left = tag.x + container.offsetWidth / 2 - tag.el.offsetWidth / 2;
const top = tag.y + container.offsetHeight / 2 - tag.el.offsetHeight / 2;
updates.push({
el: tag.el,
transform: `translate(${left}px, ${top}px) scale(${scale})`,
opacity: opacity,
zIndex: zIndex
});
});
updates.forEach(update => {
update.el.style.transform = update.transform;
update.el.style.opacity = update.opacity;
update.el.style.zIndex = update.zIndex;
});
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);
};
// 监听窗口大小变化
window.addEventListener('resize', handleResize);
}
initFab() { initFab() {
const main = document.getElementById('fab-main'); const main = document.getElementById('fab-main');
@@ -971,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避免强制重排
@@ -981,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');
@@ -1002,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);
@@ -1021,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;
// 检查是否在24小时内用户暂停过音乐
const shouldRemainPaused = this.shouldMusicRemainPaused();
const tryPlay = () => { const autoPlayer = () => {
// 检查是否在24小时内用户暂停过音乐
const shouldRemainPaused = this.shouldMusicRemainPaused();
// 如果不应该保持暂停状态,则尝试播放
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 });
}
};
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;
} }
}; };
tryPlay();
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) {

View 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);
});
});
});

View File

@@ -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) {

View File

@@ -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)

View File

@@ -1,87 +0,0 @@
const CACHE_NAME = 'honesty-home-v1.1.0';
const urlsToCache = [
'./index.html',
'./about.html',
'./css/style.css',
'./css/about.css',
'./css/artalk.css',
'./js/config.js',
'./js/about.js',
'./images/avatar.jpeg',
'./images/favicon.ico',
'./images/favicon.png',
'./images/logo.png',
'./images/INFJ.png'
];
self.addEventListener('install', event => {
event.waitUntil(
caches.open(CACHE_NAME)
.then(cache => {
return cache.addAll(urlsToCache);
})
.catch(() => Promise.resolve())
);
self.skipWaiting();
});
self.addEventListener('fetch', event => {
if (event.request.method !== 'GET' || !event.request.url.startsWith(self.location.origin)) {
return;
}
const url = new URL(event.request.url);
const isHTML = event.request.mode === 'navigate' || url.pathname.endsWith('.html');
const isVersioned = url.search && /version=/.test(url.search);
const isAudio = url.pathname.endsWith('.mp3') || url.pathname.endsWith('.wav') || url.pathname.endsWith('.ogg');
const isImage = /\.(png|jpg|jpeg|gif|webp|svg)$/i.test(url.pathname);
const isStaticAsset = /\.(css|js|json)$/i.test(url.pathname);
if (isHTML || isVersioned || isAudio) {
event.respondWith(
fetch(event.request)
.then(resp => {
if (resp && resp.status === 200 && resp.type === 'basic' && !isAudio) {
const copy = resp.clone();
caches.open(CACHE_NAME).then(cache => cache.put(event.request, copy)).catch(() => {});
}
return resp;
})
.catch(() => {
return caches.match(event.request, { ignoreSearch: true })
.then(m => m || caches.match(event.request))
})
);
return;
}
event.respondWith(
caches.match(event.request, { ignoreSearch: true })
.then(cached => {
if (cached) return cached;
return fetch(event.request).then(resp => {
if (resp && resp.status === 200 && resp.type === 'basic' && (isImage || isStaticAsset)) {
const copy = resp.clone();
caches.open(CACHE_NAME).then(cache => cache.put(event.request, copy)).catch(() => {});
}
return resp;
});
})
);
});
self.addEventListener('activate', event => {
const cacheWhitelist = [CACHE_NAME];
event.waitUntil(
caches.keys().then(cacheNames => {
return Promise.all(
cacheNames.map(cacheName => {
if (!cacheWhitelist.includes(cacheName)) {
return caches.delete(cacheName);
}
})
);
})
);
self.clients.claim();
});