Skip to content

Commit add1f8d

Browse files
committed
留言板 v1 可用
1 parent 9b570a8 commit add1f8d

5 files changed

Lines changed: 79 additions & 50 deletions

File tree

src/assets/other/comment_flag.png

661 KB
Loading

src/components/waline/DanmakuComments.astro

Lines changed: 71 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
---
22
import { Image } from 'astro:assets'
3+
34
import commentFlag from '@/assets/other/comment_flag.png'
45
import config from '@/site-config'
56
@@ -35,14 +36,16 @@ if (serverURL) {
3536
<span id='danmaku-status' class='running'>running</span>
3637
</div>
3738
<div class='terminal-controls'>
38-
<button class='control-btn' id='danmaku-toggle'>PAUSE</button>
39-
<button class='control-btn' id='danmaku-clear'>CLEAR</button>
40-
<!-- <button class='control-btn' id='danmaku-theme'>THEME</button> -->
39+
<!-- <button class='control-btn' id='danmaku-toggle'>暂停</button> -->
4140
</div>
4241
</div>
4342

4443
<div class='terminal-screen'>
45-
<Image src={commentFlag} alt="Welcome to leave comments" class="absolute bottom-4 left-4 w-[120px] h-auto opacity-70 pointer-events-none" />
44+
<Image
45+
src={commentFlag}
46+
alt='Welcome to leave comments'
47+
class='absolute bottom-4 left-4 w-[120px] h-auto pointer-events-none'
48+
/>
4649
<div class='danmaku-track'></div>
4750
<div class='danmaku-track'></div>
4851
<div class='danmaku-track'></div>
@@ -53,7 +56,7 @@ if (serverURL) {
5356

5457
<div class='status-line'>
5558
<span>Lines: <span id='danmaku-lineCount'>0</span></span>
56-
<span id='danmaku-keyboard-shortcuts'>Press SPACE to pause, C to clear</span>
59+
<span id='danmaku-keyboard-shortcuts'>Press <kbd>Space</kbd> to play , <kbd>C</kbd> to clear</span>
5760
</div>
5861
</div>
5962

@@ -68,16 +71,10 @@ if (serverURL) {
6871
}
6972

7073
let isPlaying = true
71-
let trackLastTime = [0, 0, 0, 0, 0, 0]
72-
let lineCount = 0
74+
const trackLastTime = [0, 0, 0, 0, 0, 0]
7375
let loopTimeoutId = null
7476
let commentIndex = 0
75-
76-
function toggleTheme() {
77-
const current = document.documentElement.getAttribute('data-theme')
78-
const newTheme = current === 'dark' ? 'light' : 'dark'
79-
document.documentElement.setAttribute('data-theme', newTheme)
80-
}
77+
let lineCount = 0
8178

8279
function selectBestTrack() {
8380
let bestTrack = 0
@@ -91,6 +88,48 @@ if (serverURL) {
9188
return bestTrack
9289
}
9390

91+
function truncateHtmlInline(html, maxLen) {
92+
// 去掉换行,避免输出换行
93+
html = html.replace(/^<p>|<\/p>$/g, '')
94+
95+
const tagRegex = /<\/?[^>]+>/g
96+
let textLen = 0
97+
let result = ''
98+
let lastIndex = 0
99+
let match
100+
101+
while ((match = tagRegex.exec(html)) !== null) {
102+
// 标签前的纯文字
103+
if (lastIndex < match.index) {
104+
const text = html.slice(lastIndex, match.index)
105+
if (textLen + text.length < maxLen) {
106+
result += text
107+
textLen += text.length
108+
} else {
109+
const remaining = maxLen - textLen
110+
result += text.slice(0, remaining) + '...'
111+
return result
112+
}
113+
}
114+
115+
// 保留标签本身(比如 <img>)
116+
result += match[0]
117+
lastIndex = tagRegex.lastIndex
118+
}
119+
120+
// 标签后的最后一段纯文字
121+
if (lastIndex < html.length && textLen < maxLen) {
122+
const text = html.slice(lastIndex)
123+
if (textLen + text.length <= maxLen) {
124+
result += text
125+
} else {
126+
result += text.slice(0, maxLen - textLen) + '...'
127+
}
128+
}
129+
130+
return result
131+
}
132+
94133
function createDanmaku(data) {
95134
if (!isPlaying) return
96135
const trackIndex = selectBestTrack()
@@ -99,36 +138,31 @@ if (serverURL) {
99138

100139
const danmaku = document.createElement('div')
101140
danmaku.className = 'danmaku-item not-prose'
102-
// Add admin class if applicable
103141
if (data.type === 'administrator') {
104142
danmaku.classList.add('is-admin')
105143
}
106144

107-
const cleanComment = data.comment.replace(/^<p>|<\/p>$/g, '')
145+
const cleanComment = truncateHtmlInline(data.comment, 30)
146+
const likeHtml = data.like > 0 ? `<span class="danmaku-like">👍 ${data.like}</span>` : ''
108147

109-
// New badge-like structure
110148
danmaku.innerHTML = `
111149
<img class="danmaku-avatar" src="${data.avatar}" alt="" onerror="this.style.display='none'">
112-
<span class="danmaku-nick">${data.nick}$</span>
150+
<span class="danmaku-nick">${data.nick}</span>
113151
<span class="danmaku-comment not-prose">${cleanComment}</span>
152+
${likeHtml}
114153
`
115154

116155
let duration
117156
if (window.innerWidth < 600) {
118-
// 移动端 6-10秒
119157
duration = Math.random() * 4 + 6
120158
} else {
121-
// PC端 16-24秒
122159
duration = Math.random() * 8 + 16
123160
}
124161
danmaku.style.animationDuration = `${duration}s`
125-
// const duration = Math.random() * 4 + 6 // 6-10s duration
126-
// danmaku.style.animationDuration = `${duration}s`
127162

128163
track.appendChild(danmaku)
129164
trackLastTime[trackIndex] = Date.now()
130165

131-
lineCount++
132166
const lineCountEl = document.getElementById('danmaku-lineCount')
133167
if (lineCountEl) lineCountEl.textContent = lineCount.toString()
134168

@@ -139,45 +173,36 @@ if (serverURL) {
139173
}
140174

141175
function startDanmakuLoop() {
142-
if (!isPlaying) return
176+
if (!isPlaying || comments.length === 0) return
143177
const commentData = comments[commentIndex]
144178
createDanmaku(commentData)
179+
lineCount++
145180
commentIndex = (commentIndex + 1) % comments.length
146181
loopTimeoutId = setTimeout(startDanmakuLoop, 3000)
147182
}
148183

149184
function toggleDanmaku() {
150185
isPlaying = !isPlaying
151-
const btn = document.getElementById('danmaku-toggle')
152186
const status = document.getElementById('danmaku-status')
153-
if (btn) btn.textContent = isPlaying ? 'PAUSE' : 'PLAY'
154187
if (status) {
155188
status.textContent = isPlaying ? 'running' : 'paused'
156189
status.classList.toggle('running', isPlaying)
157190
status.classList.toggle('paused', !isPlaying)
158191
}
159-
if (isPlaying) startDanmakuLoop()
160-
else clearTimeout(loopTimeoutId)
192+
if (isPlaying) {
193+
startDanmakuLoop()
194+
} else {
195+
clearTimeout(loopTimeoutId)
196+
}
161197
}
162198

163199
function clearDanmaku() {
164200
container.querySelectorAll('.danmaku-track').forEach((track) => {
165201
track.innerHTML = ''
166202
})
167203
trackLastTime.fill(0)
168-
lineCount = 0
169-
const lineCountEl = document.getElementById('danmaku-lineCount')
170-
if (lineCountEl) lineCountEl.textContent = '0'
171204
}
172205

173-
const toggleBtn = document.getElementById('danmaku-toggle')
174-
const clearBtn = document.getElementById('danmaku-clear')
175-
const themeBtn = document.getElementById('danmaku-theme')
176-
177-
if (toggleBtn) toggleBtn.addEventListener('click', toggleDanmaku)
178-
if (clearBtn) clearBtn.addEventListener('click', clearDanmaku)
179-
if (themeBtn) themeBtn.addEventListener('click', toggleTheme)
180-
181206
document.addEventListener('keydown', (e) => {
182207
if (document.activeElement !== document.body && document.activeElement !== container) return
183208
switch (e.key.toLowerCase()) {
@@ -196,7 +221,7 @@ if (serverURL) {
196221
startDanmakuLoop()
197222
}
198223

199-
setTimeout(initializeDanmaku, 0)
224+
setTimeout(initializeDanmaku, 1000)
200225
</script>
201226

202227
<style>
@@ -374,14 +399,20 @@ if (serverURL) {
374399
}
375400
:global(.danmaku-comment) {
376401
padding-right: 12px;
377-
max-width: 40ch;
378402
overflow: hidden;
379403
text-overflow: ellipsis;
380404
white-space: nowrap;
381405
display: inline-flex;
382406
align-items: center;
383407
color: var(--text);
384408
}
409+
:global(.danmaku-like) {
410+
opacity: 0.8;
411+
font-size: 12px;
412+
margin-left: 8px;
413+
color: var(--text-secondary);
414+
flex-shrink: 0;
415+
}
385416
:global(.danmaku-comment p) {
386417
display: inline;
387418
margin: 0;
@@ -447,5 +478,4 @@ if (serverURL) {
447478
.danmaku-comment img[height] {
448479
height: 28px !important;
449480
}
450-
451481
</style>

src/components/waline/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
export { default as Comment } from './Comment.astro'
22
export { default as PageInfo } from './PageInfo.astro'
3-
export { default as Pageview } from './Pageview.astro'
3+
export { default as Pageview } from './Pageview.astro'

src/pages/index.astro

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { Button, Icon, Label } from 'astro-pure/user'
77
import PageLayout from '@/layouts/BaseLayout.astro'
88
import Section from '@/components/home/Section.astro'
99
import SkillLayout from '@/components/home/SkillLayout.astro'
10-
import avatar from '@/assets/avatar.webp'
10+
import avatar from '@/assets/avatar_2.png'
1111
import config from '@/site-config'
1212
1313
const languages = [

src/pages/msgboard/index.astro

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,21 @@
11
---
22
import MsgboardLayout from '@/layouts/MsgboardLayout.astro'
33
import DanmakuComments from '@/components/waline/DanmakuComments.astro'
4-
import commentFlag from '@/assets/other/comment_flag.png'
5-
import { Image } from 'astro:assets'
64
---
75

86
<MsgboardLayout info={{ slug: '/msgboard' }}>
97
<div class="flex items-center justify-center gap-8 max-w-3xl mx-auto">
10-
<Image
8+
<!-- <Image
119
src={commentFlag}
1210
alt="comment"
1311
class="w-48 flex-shrink-0"
1412
loading="eager"
15-
/>
13+
/> -->
1614
<div class="text-left">
17-
<p class="text-xl font-semibold">有什么新鲜事想分享吗?</p>
18-
<p class="text-lg mt-2 text-muted-foreground">或只是想留下你的足迹...</p>
19-
<p class="text-lg mt-2 text-muted-foreground">期待你的声音。</p>
15+
<p class="text-xl font-semibold">留言板守则</p>
16+
<p class="text-lg mt-2 text-muted-foreground">欢迎分享你的故事、想法和新鲜事,也欢迎留下你的足迹。</p>
17+
<p class="text-lg mt-2 text-muted-foreground">请友善交流,文明发言,尊重彼此,拒绝恶意评论。</p>
18+
<p class="text-lg mt-2 text-muted-foreground">让这里成为温暖、轻松、友爱的交流空间,期待你的声音!</p>
2019
</div>
2120
</div>
2221

0 commit comments

Comments
 (0)