Compare commits

...

3 Commits

Author SHA1 Message Date
DelLevin-Home
5e33d53ea3 博客文章优化 2026-05-18 00:54:08 +08:00
DelLevin-Home
fa4c784b96 加入留言板博客按钮 2026-05-18 00:02:14 +08:00
DelLevin-Home
66ece06271 优化内容 2026-05-17 18:56:05 +08:00
11 changed files with 1787 additions and 20 deletions

View File

@@ -36,6 +36,7 @@
@import url("./static/css/main.css");
@import url("./static/css/memos.css");
@import url("./static/css/game_dialog.css");
@import url("./static/css/guestbook.css");
</style>
<title data-i18n="page_title">白荼 - BAITU</title>
</head>
@@ -47,6 +48,78 @@
<img id="lang-switch-btn" src="./static/img/中文.png" alt="Switch Language" title="切换语言" />
</div>
<!-- 留言板按钮 -->
<div class="guestbook-btn-container">
<button id="guestbook-btn" class="guestbook-btn" title="留言板">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M21 15C21 15.5304 20.7893 16.0391 20.4142 16.4142C20.0391 16.7893 19.5304 17 19 17H7L3 21V7C3 6.46957 3.21071 5.96086 3.58579 5.58579C3.96086 5.21071 4.46957 5 5 5H19C19.5304 5 20.0391 5.21071 20.4142 5.58579C20.7893 5.96086 21 6.46957 21 7V15Z"
stroke="#666" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
<span class="btn-label" data-i18n="btn_guestbook">留言板</span>
</button>
<!-- Hover 浮动预览面板 -->
<div id="guestbook-preview" class="guestbook-preview">
<div class="preview-header">
<h3 data-i18n="guestbook_title">留言板</h3>
</div>
<div class="preview-body">
<!-- 最新留言预览将在这里动态加载 -->
</div>
</div>
</div>
<!-- 博客文章按钮 -->
<div class="blog-posts-btn-container">
<button id="blog-posts-btn" class="blog-posts-btn" title="博客文章">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M14 2H6C5.46957 2 4.96086 2.21071 4.58579 2.58579C4.21071 2.96086 4 3.46957 4 4V20C4 20.5304 4.21071 21.0391 4.58579 21.4142C4.96086 21.7893 5.46957 22 6 22H18C18.5304 22 19.0391 21.7893 19.4142 21.4142C19.7893 21.0391 20 20.5304 20 20V8L14 2Z"
stroke="#666" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M14 2V8H20" stroke="#666" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M16 13H8" stroke="#666" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M16 17H8" stroke="#666" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M10 9H8" stroke="#666" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
<span class="btn-label" data-i18n="btn_blog_posts">博客文章</span>
</button>
<!-- Hover 浮动预览面板 -->
<div id="blog-posts-preview" class="blog-posts-preview">
<div class="preview-header">
<h3 data-i18n="blog_latest_posts">最新文章</h3>
</div>
<div class="preview-body blog-posts-list">
<!-- 最新文章预览将在这里动态加载 -->
</div>
</div>
</div>
<!-- 完整博客文章弹窗(点击后显示) -->
<div id="blog-posts-full-modal" class="guestbook-full-modal">
<div class="full-modal-content">
<div class="guestbook-header">
<h2>博客文章</h2>
<button id="blog-posts-close" class="guestbook-close" title="关闭">&times;</button>
</div>
<div class="guestbook-body">
<!-- 文章列表将在这里动态加载 -->
</div>
</div>
</div>
<!-- 完整留言板弹窗(点击后显示) -->
<div id="guestbook-full-modal" class="guestbook-full-modal">
<div class="full-modal-content">
<div class="guestbook-header">
<h2 data-i18n="guestbook_title">留言板</h2>
<button id="guestbook-close" class="guestbook-close" title="关闭">&times;</button>
</div>
<div class="guestbook-body">
<!-- 留言列表将在这里动态加载 -->
</div>
</div>
</div>
<!-- 头部导航 -->
<div class="nav-tabs">
<div class="nav-tab active" data-tab="about"><span data-i18n="nav_about"></span></div>
@@ -253,6 +326,8 @@
<script src="./static/js/websites_my.js"></script>
<script src="./static/js/memos.js"></script>
<script src="./static/js/map-footprint.js"></script>
<script src="./static/js/guestbook.js"></script>
<script src="./static/js/blog_posts.js"></script>
<script src="./static/js/tabchange.js"></script>
</body>

View File

@@ -8,7 +8,10 @@
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
width: 300px;
display: none;
transition: opacity 0.2s ease;
opacity: 0;
transform: translateY(10px) scale(0.95);
transition: opacity 0.6s cubic-bezier(0.4, 0, 0.2, 1),
transform 0.6s cubic-bezier(0.4, 0, 0.2, 1);
}
/* 悬浮框内容 */

826
static/css/guestbook.css Normal file
View File

@@ -0,0 +1,826 @@
/* 留言板按钮容器 */
.guestbook-btn-container {
position: fixed;
top: 20px;
right: 80px;
z-index: 999;
}
/* 博客文章按钮容器 */
.blog-posts-btn-container {
position: fixed;
top: 115px;
right: 80px;
z-index: 999;
}
.guestbook-btn {
background: #fff;
border: 1px solid #e8e8e8;
border-radius: 50%;
width: 80px;
height: 80px;
cursor: pointer;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 4px;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
}
.blog-posts-btn {
background: #fff;
border: 1px solid #e8e8e8;
border-radius: 50%;
width: 80px;
height: 80px;
cursor: pointer;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 4px;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
}
.btn-label {
font-size: 13px;
color: #666;
line-height: 1;
}
.guestbook-btn:hover,
.blog-posts-btn:hover {
border-color: #d0d0d0;
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);
transform: translateY(-2px) scale(1.05);
}
.guestbook-btn svg,
.blog-posts-btn svg {
width: 32px;
height: 32px;
}
.guestbook-btn svg path,
.blog-posts-btn svg path {
transition: stroke 0.3s ease;
}
.guestbook-btn:hover svg path,
.blog-posts-btn:hover svg path {
stroke: #333;
}
/* Hover 浮动预览面板 */
.guestbook-preview,
.blog-posts-preview {
visibility: hidden;
position: absolute;
top: 0;
right: calc(100% + 15px); /* 在按钮左侧显示 */
width: 380px;
max-height: 400px;
background: linear-gradient(to bottom, #fafafa, #fff);
border-radius: 16px;
box-shadow: 0 12px 40px rgba(0, 0, 0, 0.15), 0 4px 12px rgba(0, 0, 0, 0.08);
z-index: 1000;
opacity: 0;
transform: translateX(20px) scale(0.95);
transform-origin: center right;
transition: opacity 0.5s cubic-bezier(0.4, 0, 0.2, 1),
transform 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275),
visibility 0.5s;
overflow: hidden;
border: 1px solid rgba(240, 240, 240, 0.8);
pointer-events: none;
backdrop-filter: blur(20px);
}
/* 当鼠标悬停在容器上时显示预览面板 */
.guestbook-btn-container:hover .guestbook-preview,
.blog-posts-btn-container:hover .blog-posts-preview {
visibility: visible;
opacity: 1;
transform: translateX(0) scale(1);
pointer-events: auto;
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.18), 0 8px 20px rgba(0, 0, 0, 0.1);
}
.preview-header {
padding: 14px 18px;
border-bottom: 1px solid #f0f0f0;
background: rgba(255, 255, 255, 0.8);
backdrop-filter: blur(10px);
}
.preview-header h3 {
margin: 0;
font-size: 15px;
color: #333;
font-weight: 500;
letter-spacing: 0.5px;
}
.preview-body {
padding: 0;
overflow-y: auto;
max-height: calc(400px - 50px);
}
.preview-item {
padding: 12px 18px;
border-bottom: 1px solid #f5f5f5;
transition: background 0.2s ease;
}
.preview-item:last-child {
border-bottom: none;
}
.preview-item:hover {
background: #fafafa;
}
.preview-nickname {
font-weight: 500;
color: #333;
font-size: 13px;
margin-bottom: 4px;
}
.preview-content {
color: #666;
font-size: 12px;
line-height: 1.5;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
.preview-time {
color: #999;
font-size: 11px;
margin-top: 4px;
}
.preview-complete {
text-align: center;
padding: 15px;
color: #bbb;
font-size: 12px;
font-style: italic;
}
/* 完整留言板弹窗(点击后显示) */
.guestbook-full-modal {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
z-index: 10000;
justify-content: center;
align-items: center;
animation: fadeIn 0.3s ease;
}
.guestbook-full-modal.active {
display: flex;
}
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
.full-modal-content {
background: #fff;
border-radius: 12px;
width: 92%;
max-width: 850px;
max-height: 92vh;
overflow: hidden;
box-shadow: 0 12px 48px rgba(0, 0, 0, 0.18);
animation: slideUp 0.3s ease;
}
@keyframes slideUp {
from {
transform: translateY(30px);
opacity: 0;
}
to {
transform: translateY(0);
opacity: 1;
}
}
/* Toast 弹窗 */
.toast-container {
position: fixed;
top: 20px;
left: 50%;
transform: translateX(-50%);
z-index: 100000;
pointer-events: none;
}
.toast {
background: rgba(51, 51, 51, 0.95);
color: #fff;
padding: 12px 24px;
border-radius: 8px;
font-size: 13px;
margin-bottom: 10px;
opacity: 0;
transform: translateY(-20px);
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
backdrop-filter: blur(10px);
}
.toast.show {
opacity: 1;
transform: translateY(0);
}
.toast.success {
background: rgba(76, 175, 80, 0.95);
}
.toast.error {
background: rgba(244, 67, 54, 0.95);
}
/* 留言板模态框 */
.guestbook-modal {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
z-index: 10000;
animation: fadeIn 0.3s ease;
}
.guestbook-modal.active {
display: flex;
justify-content: center;
align-items: center;
}
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
.guestbook-content {
background: #fff;
border-radius: 8px;
width: 90%;
max-width: 800px;
max-height: 85vh;
overflow: hidden;
/* box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15); */
animation: slideUp 0.3s ease;
}
@keyframes slideUp {
from {
transform: translateY(30px);
opacity: 0;
}
to {
transform: translateY(0);
opacity: 1;
}
}
.guestbook-header {
padding: 16px 20px;
border-bottom: 1px solid #f0f0f0;
display: flex;
justify-content: space-between;
align-items: center;
background: rgba(255, 255, 255, 0.8);
backdrop-filter: blur(10px);
}
.guestbook-header h2 {
margin: 0;
font-size: 16px;
color: #333;
font-weight: 500;
letter-spacing: 0.5px;
}
.guestbook-close {
background: none;
border: none;
font-size: 24px;
color: #999;
cursor: pointer;
line-height: 1;
padding: 0;
width: 24px;
height: 24px;
display: flex;
align-items: center;
justify-content: center;
transition: color 0.3s ease;
}
.guestbook-close:hover {
color: #333;
}
.guestbook-body {
padding: 0;
overflow-y: auto;
max-height: calc(92vh - 60px);
}
/* 留言表单 - 固定在顶部 */
.guestbook-form {
margin-bottom: 15px;
padding: 15px 20px;
border-bottom: 1px solid #eee;
position: sticky;
top: 0;
background: #fff;
z-index: 10;
}
/* 留言列表 */
.guestbook-list {
display: flex;
flex-direction: column;
gap: 8px;
padding: 15px 20px;
}
.guestbook-item {
padding: 10px 12px;
border: 1px solid #f0f0f0;
border-radius: 6px;
background: #fff;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
margin-bottom: 0;
}
.guestbook-item:hover {
border-color: #e0e0e0;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
transform: translateY(-1px);
}
.guestbook-item-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 8px;
padding-bottom: 8px;
border-bottom: 1px solid #f5f5f5;
}
/* 头像样式 */
.guestbook-item-header > div:first-child img {
width: 32px;
height: 32px;
border-radius: 50%;
object-fit: cover;
border: 2px solid #f5f5f5;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.06);
}
.guestbook-item:hover .guestbook-item-header > div:first-child img {
border-color: #e0e0e0;
transform: scale(1.05);
}
.guestbook-reply .guestbook-item-header > div:first-child img {
width: 28px;
height: 28px;
}
.guestbook-nickname {
font-weight: 500;
color: #333;
font-size: 13px;
}
.guestbook-nickname a {
color: #333;
text-decoration: none;
border-bottom: 1px dotted #999;
transition: all 0.3s ease;
}
.guestbook-nickname a:hover {
color: #000;
border-bottom-color: #333;
}
.guestbook-meta {
font-size: 11px;
color: #999;
}
.guestbook-content {
color: #555;
line-height: 1.6;
font-size: 13px;
word-wrap: break-word;
padding: 4px 0;
}
/* 美化留言内容中的 HTML 元素 */
.guestbook-content p {
margin: 0 0 6px 0;
line-height: 1.6;
}
.guestbook-content p:last-child {
margin-bottom: 0;
}
.guestbook-content a {
color: #333;
text-decoration: none;
border-bottom: 1px dotted #999;
transition: all 0.3s ease;
}
.guestbook-content a:hover {
color: #000;
border-bottom-color: #333;
}
.guestbook-content img {
max-width: 100%;
height: auto;
border-radius: 4px;
margin: 6px 0;
}
.guestbook-content blockquote {
margin: 6px 0;
padding: 8px 12px;
background: #f9f9f9;
border-left: 3px solid #ddd;
color: #666;
font-style: italic;
}
.guestbook-content code {
background: #f5f5f5;
padding: 2px 6px;
border-radius: 3px;
font-family: 'Courier New', monospace;
font-size: 13px;
color: #e74c3c;
}
.guestbook-content pre {
background: #f5f5f5;
padding: 8px;
border-radius: 4px;
overflow-x: auto;
margin: 6px 0;
}
.guestbook-content pre code {
background: none;
padding: 0;
color: #333;
}
/* 留言底部信息(浏览器、系统、地址) */
.guestbook-footer {
display: flex;
flex-wrap: wrap;
gap: 8px;
margin-top: 8px;
padding-top: 8px;
border-top: 1px solid #f5f5f5;
}
.guestbook-info-item {
display: inline-flex;
align-items: center;
gap: 4px;
font-size: 12px;
color: #999;
transition: color 0.3s ease;
}
.guestbook-info-item svg {
opacity: 0.6;
}
.guestbook-info-item:hover {
color: #666;
}
.guestbook-reply {
margin-top: 15px;
padding: 12px 15px;
background: #f9f9f9;
border-radius: 4px;
border-left: 3px solid #ddd;
}
.guestbook-reply .guestbook-item {
background: transparent;
border: none;
padding: 10px 0;
margin-bottom: 10px;
}
.guestbook-reply .guestbook-item:last-child {
margin-bottom: 0;
}
.guestbook-reply .guestbook-item:hover {
box-shadow: none;
}
.guestbook-reply .guestbook-nickname {
font-size: 13px;
color: #666;
}
.guestbook-reply .guestbook-content {
font-size: 13px;
color: #777;
line-height: 1.6;
}
/* 留言表单 - 固定在顶部 */
.guestbook-form {
margin-bottom: 12px;
padding: 12px 20px;
border-bottom: 1px solid #eee;
position: sticky;
top: 0;
background: #fff;
z-index: 10;
}
.form-row {
display: flex;
gap: 8px;
margin-bottom: 8px;
}
.form-group {
flex: 1;
}
.form-group-full {
margin-bottom: 8px;
}
.form-group label {
display: block;
margin-bottom: 3px;
color: #666;
font-size: 11px;
}
.form-group input,
.form-group textarea,
.form-group-full textarea {
width: 100%;
padding: 6px 10px;
border: 1px solid #e8e8e8;
border-radius: 4px;
font-size: 12px;
color: #333;
background: #fafafa;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
font-family: inherit;
box-sizing: border-box;
}
.form-group input:focus,
.form-group textarea:focus,
.form-group-full textarea:focus {
outline: none;
border-color: #999;
background: #fff;
box-shadow: 0 0 0 3px rgba(0, 0, 0, 0.05);
}
.form-group textarea,
.form-group-full textarea {
resize: vertical;
min-height: 50px;
line-height: 1.5;
font-family: inherit;
}
.form-group textarea::placeholder,
.form-group-full textarea::placeholder {
color: #bbb;
}
.form-submit {
text-align: right;
margin-top: 10px;
}
.submit-btn {
background: #333;
color: #fff;
border: none;
padding: 8px 20px;
border-radius: 4px;
cursor: pointer;
font-size: 13px;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.submit-btn:hover {
background: #000;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
}
.submit-btn:active {
transform: translateY(0);
}
.submit-btn:disabled {
background: #ccc;
box-shadow: none;
cursor: not-allowed;
}
/* 加载状态 */
.guestbook-loading {
text-align: center;
padding: 30px 25px;
color: #999;
font-size: 14px;
}
.guestbook-empty {
text-align: center;
padding: 40px 25px;
color: #999;
font-size: 14px;
}
/* 加载更多按钮 */
.load-more-btn {
display: block;
margin: 20px auto 20px auto;
background: #fff;
border: 1px solid #e8e8e8;
color: #666;
padding: 10px 30px;
border-radius: 20px;
cursor: pointer;
font-size: 13px;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.load-more-btn:hover {
border-color: #999;
color: #333;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
transform: translateY(-1px);
}
.load-more-btn:disabled {
color: #ccc;
border-color: #eee;
cursor: not-allowed;
}
/* 加载完成提示 */
.load-complete {
text-align: center;
padding: 20px 25px;
color: #bbb;
font-size: 13px;
font-style: italic;
}
/* 博客文章列表样式 */
.blog-post-item {
padding: 12px;
border-bottom: 1px solid #f5f5f5;
transition: background-color 0.3s ease;
}
.blog-post-item:last-child {
border-bottom: none;
}
.blog-post-item:hover {
background-color: #fafafa;
}
.blog-post-title {
font-size: 14px;
color: #333;
margin-bottom: 6px;
line-height: 1.4;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
.blog-post-meta {
display: flex;
justify-content: space-between;
align-items: center;
font-size: 11px;
color: #999;
}
.blog-post-category {
background: #f0f0f0;
padding: 2px 6px;
border-radius: 3px;
font-size: 10px;
}
/* 响应式设计 */
@media (max-width: 768px) {
.guestbook-btn-container {
right: 15px;
top: 15px;
}
.blog-posts-btn-container {
right: 15px;
top: 90px;
}
/* 移动端预览面板调整位置,避免超出屏幕 */
.guestbook-preview,
.blog-posts-preview {
right: auto;
left: calc(100% + 10px);
transform-origin: center left;
transform: translateX(-20px) scale(0.95);
}
.guestbook-btn-container:hover .guestbook-preview,
.blog-posts-btn-container:hover .blog-posts-preview {
transform: translateX(0) scale(1);
}
.guestbook-content {
width: 95%;
max-height: 90vh;
}
.guestbook-body {
padding: 0;
}
.guestbook-form {
padding: 15px 20px;
}
.guestbook-list {
padding: 20px;
}
.guestbook-loading,
.guestbook-empty,
.load-complete {
padding-left: 20px;
padding-right: 20px;
}
/* 移动端表单改为垂直排列 */
.form-row {
flex-direction: column;
gap: 15px;
}
}

View File

@@ -23,6 +23,7 @@ body {
}
.letter-container {
/* max-width: 65%; */
max-width: 850px;
margin: 0 auto;
background: white;
@@ -81,10 +82,26 @@ body {
/* 内容区域 */
.tab-content {
display: none;
opacity: 0;
transform: translateY(10px);
transition: opacity 0.6s cubic-bezier(0.4, 0, 0.2, 1),
transform 0.6s cubic-bezier(0.4, 0, 0.2, 1);
}
.tab-content.active {
display: block;
animation: tabFadeIn 0.6s cubic-bezier(0.4, 0, 0.2, 1) forwards;
}
@keyframes tabFadeIn {
from {
opacity: 0;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* 信纸纹理效果 */
@@ -181,6 +198,15 @@ body {
border: 1px solid #eee;
border-radius: 4px;
background-color: #fafafa;
cursor: pointer;
transition: transform 0.6s cubic-bezier(0.4, 0, 0.2, 1),
box-shadow 0.6s cubic-bezier(0.4, 0, 0.2, 1);
}
.tool-item:hover,
.game-item:hover {
transform: translateY(-3px);
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.08);
}
.tool-name,
@@ -248,6 +274,7 @@ body {
/* 底部版权信息 - 在信纸外部 */
#footer-wrap {
max-width: 850px;
/* max-width: 65%; */
margin: 0 auto 20px auto;
text-align: center;
padding: 20px;

View File

@@ -6,7 +6,7 @@
const endAt = Date.now(); // 当前时间的时间戳(毫秒)
const headers = {
Authorization:
"Bearer 3VvA8ETw0ahPhzuNNY+Zxi3agtfOBT2vNRbm0GcPqIyUhm7rExuwj8F8IwiQWcn/rOD2G/TnONPCFIvUECQYp6GuZRTnfOojki533vP/skqf0D6puOZDQQk8Y7ssihXnfyRu5naGhIoj1BCAC7S0D0RiYvzpSYF9zvZqvgxETrCbFazZsqUBolyJd8H2iZiM4Xx3VC+GnkZHZFgQfaaYUvm33a7CLM74PyFpPby63UExMjIPiLQRAOR2hs5wl5JAs5CTYUaq+QHCCz+tWgDQ4FPtIgoZoG8Ugnywv/YEEn1Jv9p3t8ge7m8ttThnPiZWw62PYPWQ3LpFh7nxX9jQX/Y/vaaAyacCoIP5J4VpiClA40GMMptZrThzEQjheegCilb9",
"Bearer JMQBYQLIlwUsx1tnfYI35APN3bh75JrdpWkx1uk0LJTi6QEGPlno2W2D7j8ogCAS12pXTT36VAZaGw3Pqgiw3BEViZG7o3+93zcmR4Txm0wjmHsTnig7GAxWfQMs1eRY9ACFl9KAo2n0UNgC+CqZt64PFxsKwsaIE2UzuGq1ByrCW8TQwtf76ZHg/qYYjFKAGIUEoQeDvXyCjoew25f7nN3o9GTdimkqoUt0xK/2tWCW1ROOowf6r5KDJK17jRNJGV6jwUJ9AsAd53CNp+MBOHy+E8Scrk/0ATZL3HUGSAuaFKyeITkaQTCjjwunnkxq/VAaeGXZIwI1Vt1llz0Qhbjy2G7l28FhOXm4QZLTdWXtduKwHkfAoFB+HcAWGsIdanoX",
"Content-Type": "application/json",
};
const params = new URLSearchParams({

226
static/js/blog_posts.js Normal file
View File

@@ -0,0 +1,226 @@
/**
* 博客文章功能 - 获取并展示博客最新文章
*/
(function () {
'use strict';
const BLOG_API_URL = 'https://blog.iletter.top/api/posts';
const BLOG_TOKEN = '67192cda-156a-415a-9f3c-97e90a6b818a';
const PAGE_SIZE = 10;
let currentPage = 1;
let hasMore = true;
let isLoading = false;
// DOM 元素
const blogPostsBtn = document.getElementById('blog-posts-btn');
const blogPostsPreview = document.getElementById('blog-posts-preview');
const blogPostsFullModal = document.getElementById('blog-posts-full-modal');
const blogPostsClose = document.getElementById('blog-posts-close');
const blogPostsList = document.querySelector('.blog-posts-list');
const blogPostsFullBody = document.querySelector('#blog-posts-full-modal .guestbook-body');
// 初始化
function init() {
if (!blogPostsBtn || !blogPostsFullModal) return;
// 点击按钮打开完整弹窗
blogPostsBtn.addEventListener('click', openFullModal);
// 关闭按钮
blogPostsClose.addEventListener('click', closeFullModal);
// 点击背景关闭
blogPostsFullModal.addEventListener('click', function(e) {
if (e.target === blogPostsFullModal) {
closeFullModal();
}
});
// ESC 键关闭
document.addEventListener('keydown', function(e) {
if (e.key === 'Escape' && blogPostsFullModal.classList.contains('active')) {
closeFullModal();
}
});
// 页面加载时自动加载数据(用于 Hover 预览)
loadBlogPosts(true);
}
// 打开完整弹窗
function openFullModal() {
blogPostsFullModal.classList.add('active');
document.body.style.overflow = 'hidden';
// 首次打开时加载文章
if (!document.querySelector('.blog-post-item')) {
loadBlogPosts(true);
}
}
// 关闭完整弹窗
function closeFullModal() {
blogPostsFullModal.classList.remove('active');
document.body.style.overflow = '';
}
// 加载文章列表
async function loadBlogPosts(reset = false) {
if (isLoading || (!hasMore && !reset)) return;
isLoading = true;
if (reset) {
currentPage = 1;
hasMore = true;
if (blogPostsList) blogPostsList.innerHTML = '<div class="guestbook-loading">正在加载文章...</div>';
if (blogPostsFullBody) blogPostsFullBody.innerHTML = '<div class="guestbook-loading">正在加载文章...</div>';
}
try {
const response = await fetch(`${BLOG_API_URL}?page=${currentPage}&pageSize=${PAGE_SIZE}&showContent=false&showDigest=excerpt&limit=30`, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'token': BLOG_TOKEN
}
});
if (!response.ok) {
throw new Error('Network response was not ok');
}
const result = await response.json();
const posts = result.data.dataSet || [];
const totalPages = result.data.pages || 0;
// 判断是否还有更多数据
hasMore = currentPage < totalPages;
if (reset) {
renderPosts(posts, true);
} else {
appendPosts(posts);
}
} catch (error) {
console.error('加载文章失败:', error);
if (reset) {
const errorMsg = '<div class="guestbook-empty">加载文章失败,请稍后重试</div>';
if (blogPostsList) blogPostsList.innerHTML = errorMsg;
if (blogPostsFullBody) blogPostsFullBody.innerHTML = errorMsg;
}
} finally {
isLoading = false;
}
}
// 渲染文章列表
function renderPosts(posts, isReset = false) {
let html = '';
if (!posts || posts.length === 0) {
html = '<div class="guestbook-empty">暂无文章</div>';
} else {
html = '<div class="blog-posts-container">';
posts.forEach(post => {
html += renderPostItem(post);
});
html += '</div>';
if (hasMore) {
html += `<button class="load-more-btn" onclick="window.loadMoreBlogPosts()">点击加载更多</button>`;
} else {
html += `<div class="load-complete">已显示全部</div>`;
}
}
if (blogPostsList) blogPostsList.innerHTML = html;
if (blogPostsFullBody) blogPostsFullBody.innerHTML = html;
}
// 追加文章
function appendPosts(posts) {
const containers = document.querySelectorAll('.blog-posts-container');
const loadMoreBtns = document.querySelectorAll('.load-more-btn');
const oldTips = document.querySelectorAll('.load-complete');
if (containers.length === 0) {
console.error('未找到 .blog-posts-container 容器');
return;
}
// 向所有容器追加新文章
containers.forEach(container => {
posts.forEach(post => {
const div = document.createElement('div');
div.innerHTML = renderPostItem(post);
container.appendChild(div.firstElementChild);
});
});
// 移除所有旧的加载更多按钮和提示
loadMoreBtns.forEach(btn => btn.remove());
oldTips.forEach(tip => tip.remove());
// 向所有容器后添加新的加载更多按钮或提示
if (hasMore) {
containers.forEach(container => {
const btn = document.createElement('button');
btn.className = 'load-more-btn';
btn.textContent = '点击加载更多';
btn.onclick = window.loadMoreBlogPosts;
container.after(btn);
});
} else {
containers.forEach(container => {
const tip = document.createElement('div');
tip.className = 'load-complete';
tip.textContent = '已显示全部';
container.after(tip);
});
}
console.log(`成功追加 ${posts.length} 篇文章到 ${containers.length} 个容器,当前页码: ${currentPage}`);
}
// 渲染单个文章项
function renderPostItem(post) {
const date = new Date(post.created * 1000);
const dateStr = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`;
const category = post.categories && post.categories.length > 0 ? post.categories[0].name : '未分类';
let html = `<div class="blog-post-item" onclick="window.open('${post.permalink}', '_blank')">`;
html += `<div class="blog-post-title">${escapeHtml(post.title)}</div>`;
html += `<div class="blog-post-meta">`;
html += `<span>${dateStr}</span>`;
html += `<span class="blog-post-category">${escapeHtml(category)}</span>`;
html += `</div>`;
html += `</div>`;
return html;
}
// HTML 转义
function escapeHtml(text) {
const div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
}
// 加载更多
window.loadMoreBlogPosts = function() {
if (!isLoading && hasMore) {
currentPage++;
loadBlogPosts(false);
}
};
// DOM 加载完成后初始化
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
})();

View File

@@ -287,6 +287,11 @@ function toggleGameDetailTooltip(gameElement, gameIndex) {
tooltipDiv.style.left = `${left}px`;
tooltipDiv.style.display = "block";
// 触发重绘以启动过渡动画
void tooltipDiv.offsetWidth;
tooltipDiv.style.opacity = "1";
tooltipDiv.style.transform = "translateY(0) scale(1)";
// 记录当前打开的tooltip
currentlyOpenTooltip = { element: tooltipDiv, index: gameIndex };
@@ -299,11 +304,13 @@ function toggleGameDetailTooltip(gameElement, gameIndex) {
// ========== 隐藏Tooltip的辅助函数 ==========
function hideTooltip(tooltipElement) {
if (tooltipElement) {
tooltipElement.style.display = "none";
// 如果想完全移除DOM可以取消下面两行注释但通常隐藏即可
// if (tooltipElement.parentNode) {
// tooltipElement.parentNode.removeChild(tooltipElement);
// }
tooltipElement.style.opacity = "0";
tooltipElement.style.transform = "translateY(10px) scale(0.95)";
// 等待动画结束后再隐藏 display
setTimeout(() => {
tooltipElement.style.display = "none";
}, 600);
}
}

548
static/js/guestbook.js Normal file
View File

@@ -0,0 +1,548 @@
/**
* 留言板功能 - 基于 Flask API
*/
(function () {
'use strict';
// Flask API 地址
const API_BASE_URL = 'http://localhost:8360';
const PAGE_SIZE = 10;
let currentPage = 1;
let hasMore = true;
let isLoading = false;
let allComments = []; // 存储所有已加载的留言
// DOM 元素
const guestbookBtn = document.getElementById('guestbook-btn');
const guestbookPreview = document.getElementById('guestbook-preview');
const guestbookFullModal = document.getElementById('guestbook-full-modal');
const guestbookClose = document.getElementById('guestbook-close');
const guestbookBody = document.querySelector('#guestbook-full-modal .guestbook-body');
const previewBody = document.querySelector('.preview-body');
// Toast 容器
let toastContainer = document.querySelector('.toast-container');
if (!toastContainer) {
toastContainer = document.createElement('div');
toastContainer.className = 'toast-container';
document.body.appendChild(toastContainer);
}
// 表单元素(需要动态获取,因为表单会被重新渲染)
let nicknameInput, emailInput, linkInput, contentInput, submitBtn;
// 显示 Toast 提示
function showToast(message, type = 'success', duration = 2000) {
const toast = document.createElement('div');
toast.className = `toast ${type}`;
toast.textContent = message;
toastContainer.appendChild(toast);
// 触发动画
setTimeout(() => {
toast.classList.add('show');
}, 10);
// 自动消失
setTimeout(() => {
toast.classList.remove('show');
setTimeout(() => {
toast.remove();
}, 300);
}, duration);
}
// 初始化
function init() {
if (!guestbookBtn || !guestbookFullModal) return;
// 点击按钮打开完整弹窗
guestbookBtn.addEventListener('click', openFullModal);
// 关闭按钮
guestbookClose.addEventListener('click', closeFullModal);
// 点击背景关闭
guestbookFullModal.addEventListener('click', function(e) {
if (e.target === guestbookFullModal) {
closeFullModal();
}
});
// ESC 键关闭
document.addEventListener('keydown', function(e) {
if (e.key === 'Escape' && guestbookFullModal.classList.contains('active')) {
closeFullModal();
}
});
// 预览面板触底加载
if (previewBody) {
previewBody.addEventListener('scroll', handlePreviewScroll);
}
// 表单提交事件使用事件委托
guestbookBody.addEventListener('submit', function(e) {
if (e.target && e.target.id === 'guestbook-form') {
handleSubmit(e);
}
});
// 页面加载时自动加载数据(用于 Hover 预览)
loadGuestbook(true);
}
// 切换留言板显示/隐藏
function toggleGuestbook() {
if (guestbookFullModal.classList.contains('active')) {
closeFullModal();
} else {
openFullModal();
}
}
// 打开完整弹窗
function openFullModal() {
guestbookFullModal.classList.add('active');
document.body.style.overflow = 'hidden';
// 首次打开时加载留言
if (!document.querySelector('.guestbook-list')) {
loadGuestbook(true);
}
}
// 关闭完整弹窗
function closeFullModal() {
guestbookFullModal.classList.remove('active');
document.body.style.overflow = '';
}
// 点击模态框背景关闭
function handleModalClick(e) {
if (e.target === guestbookModal) {
closeGuestbook();
}
}
// 加载留言列表
async function loadGuestbook(reset = false) {
if (isLoading || (!hasMore && !reset)) return;
isLoading = true;
if (reset) {
currentPage = 1;
hasMore = true;
guestbookBody.innerHTML = '<div class="guestbook-loading" data-i18n="guestbook_loading">正在加载留言...</div>';
} else {
// 添加加载更多按钮状态
const loadMoreBtn = document.querySelector('.load-more-btn');
if (loadMoreBtn) {
loadMoreBtn.disabled = true;
loadMoreBtn.textContent = '加载中...';
}
}
try {
const response = await fetch(`${API_BASE_URL}/api/comment?path=www.iletter.top&pageSize=${PAGE_SIZE}&page=${currentPage}`, {
method: 'GET',
headers: {
'Content-Type': 'application/json'
}
});
if (!response.ok) {
throw new Error('Network response was not ok');
}
const result = await response.json();
const comments = result.data.data || [];
const totalCount = result.data.count || 0;
const totalPages = result.data.totalPages || 0;
// 判断是否还有更多数据(根据总页数)
hasMore = currentPage < totalPages;
// 累积所有留言
if (reset) {
allComments = comments;
} else {
allComments = allComments.concat(comments);
}
if (reset) {
renderGuestbook(comments, totalCount);
} else {
appendGuestbook(comments);
}
} catch (error) {
console.error('加载留言失败:', error);
if (reset) {
guestbookBody.innerHTML = `<div class="guestbook-empty" data-i18n="guestbook_load_error">加载留言失败,请稍后重试</div>`;
}
} finally {
isLoading = false;
}
}
// 渲染留言列表
function renderGuestbook(comments, totalCount) {
let html = '';
// 先渲染表单(放在顶部)
html += renderForm();
if (!comments || comments.length === 0) {
html += `<div class="guestbook-empty" data-i18n="guestbook_no_data">暂无留言,快来抢沙发吧!</div>`;
guestbookBody.innerHTML = html;
return;
}
html += '<div class="guestbook-list">';
comments.forEach(comment => {
html += renderCommentItem(comment);
});
html += '</div>';
// 判断是否还有更多数据
if (hasMore) {
html += `<button class="load-more-btn" onclick="window.loadMoreGuestbook()">点击加载更多</button>`;
} else {
html += `<div class="load-complete">已显示全部</div>`;
}
guestbookBody.innerHTML = html;
// 同时更新 Hover 预览面板(使用累积的所有留言)
renderPreview(allComments);
}
// 渲染 Hover 预览面板
function renderPreview(comments) {
if (!previewBody || !comments || comments.length === 0) return;
let html = '';
comments.forEach(comment => {
const date = new Date(comment.time);
const timeStr = formatDate(date);
html += `<div class="preview-item">`;
html += `<div class="preview-nickname">${escapeHtml(comment.nick)}</div>`;
// 提取纯文本内容(去除 HTML 标签)
const tempDiv = document.createElement('div');
tempDiv.innerHTML = comment.comment || '';
const textContent = tempDiv.textContent || tempDiv.innerText || '';
html += `<div class="preview-content">${escapeHtml(textContent)}</div>`;
html += `<div class="preview-time">${timeStr}</div>`;
html += `</div>`;
});
// 如果已经加载完所有数据,显示提示
if (!hasMore && allComments.length > 0) {
html += `<div class="preview-complete">已全部加载</div>`;
}
previewBody.innerHTML = html;
}
// 处理预览面板滚动事件
function handlePreviewScroll(e) {
const target = e.target;
const scrollTop = target.scrollTop;
const scrollHeight = target.scrollHeight;
const clientHeight = target.clientHeight;
// 距离底部 50px 时触发加载
if (scrollHeight - scrollTop - clientHeight < 50) {
if (!isLoading && hasMore) {
currentPage++;
loadGuestbook(false);
}
}
}
// 追加留言
function appendGuestbook(comments) {
const listContainer = document.querySelector('.guestbook-list');
const loadMoreBtn = document.querySelector('.load-more-btn');
const allDataTip = document.querySelector('.guestbook-body > div:last-child');
if (!listContainer) return;
comments.forEach(comment => {
const div = document.createElement('div');
div.innerHTML = renderCommentItem(comment);
listContainer.appendChild(div.firstElementChild);
});
// 移除旧的加载更多按钮和提示
if (loadMoreBtn) {
loadMoreBtn.remove();
}
const oldTip = document.querySelector('.load-complete');
if (oldTip) {
oldTip.remove();
}
// 如果还有更多,添加新的加载更多按钮
if (hasMore) {
const btn = document.createElement('button');
btn.className = 'load-more-btn';
btn.textContent = '点击加载更多';
btn.onclick = window.loadMoreGuestbook;
listContainer.after(btn);
} else {
// 没有更多数据,显示提示
const tip = document.createElement('div');
tip.className = 'load-complete';
tip.textContent = '已显示全部';
listContainer.after(tip);
}
// 更新预览面板
renderPreview(allComments);
}
// 渲染单个留言项
function renderCommentItem(comment) {
const date = new Date(comment.time);
const timeStr = formatDate(date);
let html = `<div class="guestbook-item">`;
html += `<div class="guestbook-item-header">`;
// 头像和昵称
html += `<div style="display: flex; align-items: center; gap: 8px;">`;
if (comment.avatar) {
html += `<img src="${escapeHtml(comment.avatar)}" alt="">`;
}
// 昵称和链接
if (comment.link) {
html += `<span class="guestbook-nickname"><a href="${escapeHtml(comment.link)}" target="_blank">${escapeHtml(comment.nick)}</a></span>`;
} else {
html += `<span class="guestbook-nickname">${escapeHtml(comment.nick)}</span>`;
}
html += `</div>`;
html += `<span class="guestbook-meta">${timeStr}</span>`;
html += `</div>`;
// 内容comment 字段已经是 HTML
html += `<div class="guestbook-content">${comment.comment || ''}</div>`;
// 底部信息(浏览器、系统、地址)
html += renderCommentFooter(comment);
// 回复列表
if (comment.children && comment.children.length > 0) {
html += `<div class="guestbook-reply">`;
comment.children.forEach(reply => {
html += renderReplyItem(reply);
});
html += `</div>`;
}
html += `</div>`;
return html;
}
// 渲染留言底部信息
function renderCommentFooter(comment) {
const browser = comment.browser || '';
const os = comment.os || '';
const addr = comment.addr || '';
if (!browser && !os && !addr) return '';
let html = '<div class="guestbook-footer">';
if (browser) {
html += `<span class="guestbook-info-item"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="2" y="3" width="20" height="14" rx="2" ry="2"></rect><line x1="8" y1="21" x2="16" y2="21"></line><line x1="12" y1="17" x2="12" y2="21"></line></svg> ${escapeHtml(browser)}</span>`;
}
if (os) {
html += `<span class="guestbook-info-item"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="2" y="3" width="20" height="14" rx="2" ry="2"></rect><line x1="8" y1="21" x2="16" y2="21"></line><line x1="12" y1="17" x2="12" y2="21"></line></svg> ${escapeHtml(os)}</span>`;
}
if (addr) {
html += `<span class="guestbook-info-item"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z"></path><circle cx="12" cy="10" r="3"></circle></svg> ${escapeHtml(addr)}</span>`;
}
html += '</div>';
return html;
}
// 渲染回复项
function renderReplyItem(reply) {
const date = new Date(reply.time);
const timeStr = formatDate(date);
let html = `<div class="guestbook-item" style="margin-top: 10px;">`;
html += `<div class="guestbook-item-header">`;
html += `<div style="display: flex; align-items: center; gap: 8px;">`;
if (reply.avatar) {
html += `<img src="${escapeHtml(reply.avatar)}" alt="">`;
}
if (reply.link) {
html += `<span class="guestbook-nickname"><a href="${escapeHtml(reply.link)}" target="_blank">${escapeHtml(reply.nick)}</a></span>`;
} else {
html += `<span class="guestbook-nickname">${escapeHtml(reply.nick)}</span>`;
}
html += `</div>`;
html += `<span class="guestbook-meta">${timeStr}</span>`;
html += `</div>`;
html += `<div class="guestbook-content">${reply.comment || ''}</div>`;
html += `</div>`;
return html;
}
// 渲染表单
function renderForm() {
return `
<form id="guestbook-form" class="guestbook-form">
<div class="form-row">
<div class="form-group">
<label for="guestbook-nickname" data-i18n="guestbook_nickname">昵称(选填)</label>
<input type="text" id="guestbook-nickname" placeholder="匿名">
</div>
<div class="form-group">
<label for="guestbook-email" data-i18n="guestbook_email">邮箱(选填)</label>
<input type="email" id="guestbook-email" placeholder="用于接收回复通知">
</div>
<div class="form-group">
<label for="guestbook-link" data-i18n="guestbook_website">网站(选填)</label>
<input type="url" id="guestbook-link" placeholder="https://example.com">
</div>
</div>
<div class="form-group-full">
<label for="guestbook-content" data-i18n="guestbook_placeholder">说点什么吧...</label>
<textarea id="guestbook-content" placeholder="请输入留言内容..." required maxlength="500"></textarea>
</div>
<div class="form-submit">
<button type="submit" id="guestbook-submit" class="submit-btn" data-i18n="guestbook_submit">提交留言</button>
</div>
</form>
`;
}
// 提交留言
async function handleSubmit(e) {
e.preventDefault();
// 重新获取表单元素(因为表单可能被重新渲染)
nicknameInput = document.getElementById('guestbook-nickname');
emailInput = document.getElementById('guestbook-email');
linkInput = document.getElementById('guestbook-link');
contentInput = document.getElementById('guestbook-content');
submitBtn = document.getElementById('guestbook-submit');
const nick = nicknameInput.value.trim() || '匿名';
const email = emailInput.value.trim();
const link = linkInput.value.trim();
const comment = contentInput.value.trim();
// 验证
if (!comment) {
showToast('请输入留言内容', 'error');
return;
}
// 禁用提交按钮
submitBtn.disabled = true;
submitBtn.textContent = '提交中...';
try {
const response = await fetch(`${API_BASE_URL}/api/comment`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
nick: nick,
mail: email || '',
link: link || '',
comment: comment,
path: 'www.iletter.top',
ua: navigator.userAgent,
url: window.location.href
})
});
const data = await response.json();
if (response.ok && data.errno === 0) {
showToast(getTranslation('guestbook_submit_success') || '留言提交成功!', 'success');
// 清空表单
nicknameInput.value = '';
emailInput.value = '';
linkInput.value = '';
contentInput.value = '';
// 重新加载第一页
loadGuestbook(true);
} else {
throw new Error(data.errmsg || '提交失败');
}
} catch (error) {
console.error('提交留言失败:', error);
showToast(getTranslation('guestbook_submit_error') || '留言提交失败,请重试', 'error');
} finally {
submitBtn.disabled = false;
submitBtn.textContent = getTranslation('guestbook_submit') || '提交留言';
}
}
// 格式化日期
function formatDate(date) {
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
const hours = String(date.getHours()).padStart(2, '0');
const minutes = String(date.getMinutes()).padStart(2, '0');
return `${year}-${month}-${day} ${hours}:${minutes}`;
}
// HTML 转义
function escapeHtml(text) {
const div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
}
// 获取翻译
function getTranslation(key) {
const lang = localStorage.getItem('preferred_language') || 'zh';
const translations = {
'zh': typeof translationsZH !== 'undefined' ? translationsZH : {},
'en': typeof translationsEN !== 'undefined' ? translationsEN : {}
};
return translations[lang][key] || key;
}
// 加载更多
window.loadMoreGuestbook = function() {
if (!isLoading && hasMore) {
currentPage++;
loadGuestbook(false);
}
};
// DOM 加载完成后初始化
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
})();

View File

@@ -17,7 +17,7 @@ const translationsEN = {
about_me_p2:
'My hobbies usually involve playing games, reading books, watching anime, and I prefer staying indoors. I hate repetitive and simple work, so I often write small tools to make life easier because laziness drives my productivity. I frequently lurk on various forums and blogs, shouting "666" or "Amazing" under tech bloggers. My own blog updates sporadically, mainly recording daily life notes and technical challenges encountered.',
about_me_p3:
'This site follows a minimalist style, using pure HTML. Umami tracks UV/PV at the bottom. The Memos section uses the Memos API. It also employs Baota Cloud WAF protection and nginx caching for static resources. If you are interested, you can directly download the source code from <a href="https://gitea.iletter.top/dellevin/BaiTu-homepage" target="_blank">https://gitea.iletter.top/dellevin/BaiTu-homepage </a> and use it.',
'This site follows a minimalist style, using pure HTML. Umami tracks UV/PV at the bottom. The Memos section uses the Memos API. It also employs Baota Cloud WAF protection and nginx caching for static resources. If you are interested, you can directly download the source code from <a href="https://gitea.iletter.top/dellevin/BaiTu-homepage" target="_blank">https://gitea.iletter.top/dellevin/BaiTu-homepage </a> and use it, or through F12 view website source code download.',
about_me_p4:
"As a 99er programmer, I am glad to still have great passion for technology after starting work! If you share the same interest in technology, I would love to meet you! Let's progress and grow together!",
// 联系方式
@@ -36,7 +36,7 @@ const translationsEN = {
// 留言
leave_message_h3: "Leave a Message",
leave_message_p:
'If you have any questions or suggestions, feel free to <a href="https://blog.iletter.top/401.html" target="_blank">click here</a> to leave me a message on my blog!',
'If you have any questions or suggestions, feel free to <a href="https://blog.iletter.top/401.html" target="_blank">click here</a> to leave me a message on my blog, or click the guestbook link in the top right corner to leave a message!',
leave_message_link: "click here",
// 小界面标题
my_website_h2: "My Websites",
@@ -57,4 +57,21 @@ const translationsEN = {
"I still choose to spend the rest of my life in my own way although I am a failure.",
visitor_count_label: "Visitors:",
visit_count_label: "Total Visits:",
// Guestbook
guestbook_title: "Guestbook",
guestbook_placeholder: "Say something...",
guestbook_nickname: "Nickname (optional)",
guestbook_email: "Email (optional)",
guestbook_website: "Website (optional)",
guestbook_submit: "Submit",
guestbook_loading: "Loading messages...",
guestbook_no_data: "No messages yet, be the first to comment!",
guestbook_load_error: "Failed to load messages, please try again later",
guestbook_submit_success: "Message submitted successfully!",
guestbook_submit_error: "Failed to submit message, please try again",
guestbook_required_nickname: "Please enter a nickname",
// Top-right buttons
btn_guestbook: "Guestbook",
btn_blog_posts: "Blog Posts",
blog_latest_posts: "Latest Posts",
};

View File

@@ -17,7 +17,7 @@ const translationsZH = {
about_me_p2:
'平时的爱好也就是玩玩游戏,看看书,刷刷动漫,不爱出门,肥宅一个。讨厌重复简单的工作,会想办法偷懒写写自己的顺手的小工具什么的,毕竟懒惰是我的生产力。我也经常混迹于各大网络论坛博客并在各个技术博主下面直呼"大佬666"、"大佬牛牛牛"。自己的博客也在断断续续中更新。主要是记录生活随笔和碰到的技术难题。',
about_me_p3:
'本站秉承简约风格采用纯HTMLUmami做网站底部的uv/pv 闲言碎语模块使用memos接口。同时使用堡塔云WAF防护nginx缓存加速网站静态资源。如果您有兴趣可以直接下载本站的 <a href="https://gitea.iletter.top/dellevin/BaiTu-homepage" target="_blank">https://gitea.iletter.top/dellevin/BaiTu-homepage </a> 并使用。',
'本站秉承简约风格采用纯HTMLUmami做网站底部的uv/pv 闲言碎语模块使用memos接口。同时使用堡塔云WAF防护nginx缓存加速网站静态资源。如果您有兴趣可以直接下载本站的 <a href="https://gitea.iletter.top/dellevin/BaiTu-homepage" target="_blank">https://gitea.iletter.top/dellevin/BaiTu-homepage </a> 并使用或者通过F12查看网站源代码下载。',
about_me_p4:
"作为一个99年的码农很庆幸我在工作之后还对技术有着极大的热情如果你也对技术有着同样的兴趣也很希望认识你一同进步共同成长",
@@ -37,7 +37,7 @@ const translationsZH = {
// 留言
leave_message_h3: "留言",
leave_message_p:
'如果你有任何问题或建议,欢迎<a href="https://blog.iletter.top/401.html" target="_blank">点击此链接</a>去我的博客下面给我留言!',
'如果你有任何问题或建议,欢迎<a href="https://blog.iletter.top/401.html" target="_blank">点击此链接</a>去我的博客下面给我留言,或者点击右上角的留言板进行留言哦',
leave_message_link: "点击此链接",
// 小界面标题
my_website_h2: "我的网站",
@@ -57,4 +57,21 @@ const translationsZH = {
footer_text: "我虽然是个废物,但我仍然选择用自己喜欢的方式度过自己的余生",
visitor_count_label: "本站访客数 :",
visit_count_label: "本站总访问量 :",
// 留言板
guestbook_title: "留言板",
guestbook_placeholder: "说点什么吧...",
guestbook_nickname: "昵称(选填)",
guestbook_email: "邮箱(选填)",
guestbook_website: "网站(选填)",
guestbook_submit: "提交留言",
guestbook_loading: "正在加载留言...",
guestbook_no_data: "暂无留言,快来抢沙发吧!",
guestbook_load_error: "加载留言失败,请稍后重试",
guestbook_submit_success: "留言提交成功!",
guestbook_submit_error: "留言提交失败,请重试",
guestbook_required_nickname: "请输入昵称",
// 右上角按钮
btn_guestbook: "留言板",
btn_blog_posts: "博客文章",
blog_latest_posts: "最新文章",
};

View File

@@ -23,7 +23,7 @@ const websitesData = [
items: [
{
url: 'https://img.iletter.top/',
linkText_zh: '简单图床 - 私人图床工具',
linkText_zh: 'EsayImage2 - 私人图床工具',
linkText_en: 'EsayImage2 - Image Uploader Tool'
},
{
@@ -31,11 +31,6 @@ const websitesData = [
linkText_zh: 'Gitea - 私人git托管仓库',
linkText_en: 'Gitea - Private Git Repository'
},
// {
// url: 'http://openlist.iletter.top/',
// linkText_zh: 'OpenList - 在线云盘合集',
// linkText_en: 'OpenList - Online Cloud Disk Collection'
// },
{
url: 'http://umami.iletter.top/',
linkText_zh: 'Umami - 网站访问分析',
@@ -47,10 +42,36 @@ const websitesData = [
linkText_en: 'Beszel - Server Monitoring'
},
{
url: 'http://py.iletter.top/en-de-code',
linkText_zh: 'Base64在线加密解密 - 自写demo',
linkText_en: 'Base64 Online Encryption and Decryption - My Demo'
url: 'https://memos.iletter.top/',
linkText_zh: 'Memos - 个人随想',
linkText_en: 'Memos - Personal Thoughts'
},
{
url: 'http://frp.iletter.top/',
linkText_zh: 'FRP - 个人反向代理',
linkText_en: 'FRP - Personal Reverse Proxy'
},
{
url: 'https://bitwarden.iletter.top/',
linkText_zh: 'Bitwarden - 我的密码库',
linkText_en: 'Bitwarden - My Password Library'
},
{
url: 'http://docmost.iletter.top/',
linkText_zh: 'Docmost - 在线笔记',
linkText_en: 'Docmost - Online Notes'
},
{
url: 'http://openlist.iletter.top/',
linkText_zh: 'OpenList - 在线云盘合集',
linkText_en: 'OpenList - Online Cloud Disk Collection'
},
// {
// url: 'http://py.iletter.top/en-de-code',
// linkText_zh: 'Base64在线加密解密 - 自写demo',
// linkText_en: 'Base64 Online Encryption and Decryption - My Demo'
// },
]
}
// 如果你想添加新分类,可以仿照上面的格式: