Skip to content

Commit fa5c05a

Browse files
author
linzhengyu
committed
docs: fix docstring by typescript_docstring.mdc
1 parent e594202 commit fa5c05a

File tree

5 files changed

+266
-84
lines changed

5 files changed

+266
-84
lines changed

app/components/layout/ChatModeMenu.tsx

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ interface ChatModeMenuProps {
3131
*
3232
* @param chatMode Current chat mode.
3333
* @param onModeSelect Callback function called when a mode is selected.
34+
* @param enableLiveChat Whether live chat mode is enabled. Defaults to true.
3435
* @returns JSX.Element The chat mode menu UI component.
3536
*/
3637
export default function ChatModeMenu({
@@ -42,8 +43,16 @@ export default function ChatModeMenu({
4243
const [showChatModeMenu, setShowChatModeMenu] = useState(false)
4344
const chatModeMenuRef = useRef<HTMLDivElement>(null)
4445

45-
// Close chat mode menu when clicking outside
46+
/**
47+
* Close chat mode menu when clicking outside.
48+
*/
4649
useEffect(() => {
50+
/**
51+
* Handle click outside event to close the menu.
52+
*
53+
* @param event The mouse event.
54+
* @returns void
55+
*/
4756
function handleClickOutside(event: MouseEvent) {
4857
if (
4958
chatModeMenuRef.current &&
@@ -61,6 +70,8 @@ export default function ChatModeMenu({
6170

6271
/**
6372
* Get the display text for the current chat mode.
73+
*
74+
* @returns The translated text for the current chat mode.
6475
*/
6576
const getChatModeText = () => {
6677
switch (chatMode) {
@@ -77,6 +88,11 @@ export default function ChatModeMenu({
7788

7889
/**
7990
* Handle chat mode selection.
91+
*
92+
* Calls the onModeSelect callback and closes the menu.
93+
*
94+
* @param mode The selected chat mode.
95+
* @returns void
8096
*/
8197
const handleChatModeSelect = (mode: 'text' | 'voice' | 'live') => {
8298
onModeSelect(mode)

app/components/layout/Chatbox.tsx

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
import React, { useState } from 'react'
44
import { useTranslation } from 'react-i18next'
55
import { GlobalState } from '@/library/babylonjs/core'
6-
import { States } from '@/library/babylonjs/runtime/fsm/states'
76
import {
87
Conditions,
98
ConditionedMessage,
@@ -25,6 +24,7 @@ interface ChatboxProps {
2524
* A text input component for sending chat messages.
2625
* Displays a textarea and send button, positioned at the bottom center of the screen.
2726
*
27+
* @param globalState Global state for accessing BabylonJS scene and runtime.
2828
* @returns JSX.Element The chatbox UI component.
2929
*/
3030
export default function Chatbox({ globalState }: ChatboxProps) {
@@ -33,6 +33,11 @@ export default function Chatbox({ globalState }: ChatboxProps) {
3333

3434
/**
3535
* Handle sending chat message.
36+
*
37+
* Sends the current chat message to the state machine. If an animation is currently playing,
38+
* it will interrupt the animation before sending the message.
39+
*
40+
* @returns void
3641
*/
3742
const handleSendMessage = () => {
3843
if (chatMessage.trim()) {
@@ -51,6 +56,12 @@ export default function Chatbox({ globalState }: ChatboxProps) {
5156

5257
/**
5358
* Handle Enter key press in textarea.
59+
*
60+
* Sends the message when Enter is pressed without Shift. Prevents default behavior
61+
* to avoid adding a new line.
62+
*
63+
* @param e The keyboard event from the textarea.
64+
* @returns void
5465
*/
5566
const handleTextareaKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {
5667
if (e.key === 'Enter' && !e.shiftKey) {

app/components/layout/LiveStreamInput.tsx

Lines changed: 71 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ interface LiveStreamInputProps {
3333
* A component for inputting and confirming live stream URLs.
3434
* Displays an input field and confirm button positioned next to the chat mode button.
3535
*
36+
* @param globalState Global state for accessing BabylonJS scene and runtime.
3637
* @returns JSX.Element The live stream input UI component.
3738
*/
3839
export default function LiveStreamInput({ globalState }: LiveStreamInputProps) {
@@ -44,93 +45,107 @@ export default function LiveStreamInput({ globalState }: LiveStreamInputProps) {
4445
const clientRef = useRef<DanmakuWebSocketClient | null>(null)
4546

4647
/**
47-
* 解析直播流 URL,提取服务器地址和房间标识
48-
* 支持两种格式:
48+
* Parse live stream URL and extract server address and room identifier.
49+
*
50+
* Supports two formats:
4951
* 1. file:// URL: file:///path/loader.html?url=http%3A%2F%2Flocalhost%3A12450%2Froom%2FKEY%3FroomKeyType%3D2
50-
* 2. 直接 HTTP URL: http://localhost:12450/room/KEY?roomKeyType=2
52+
* 2. Direct HTTP URL: http://localhost:12450/room/KEY?roomKeyType=2
53+
*
54+
* @param url The live stream URL to parse.
55+
* @returns An object containing serverUrl and roomKey, or null if parsing fails.
5156
*/
5257
const parseLiveStreamUrl = (url: string): { serverUrl: string; roomKey: RoomKey } | null => {
5358
try {
5459
let actualUrl = url
5560

56-
// 处理 file:// 协议的 URL
61+
// Handle file:// protocol URLs
5762
if (url.startsWith('file://')) {
5863
const urlObj = new URL(url)
59-
// 获取 url 查询参数
64+
// Get url query parameter
6065
const urlParam = urlObj.searchParams.get('url')
6166
if (!urlParam) {
62-
console.error('file:// URL 中缺少 url 参数')
67+
console.error('Missing url parameter in file:// URL')
6368
return null
6469
}
65-
// URL 解码
70+
// URL decode
6671
actualUrl = decodeURIComponent(urlParam)
6772
}
6873

69-
// 解析实际的 URL
74+
// Parse the actual URL
7075
const urlObj = new URL(actualUrl)
7176
const serverUrl = `${urlObj.protocol}//${urlObj.host}`
7277

73-
// 从路径中提取 roomKey(例如:/room/F3RY9LX2M9KW9
78+
// Extract roomKey from path (e.g., /room/F3RY9LX2M9KW9)
7479
const pathParts = urlObj.pathname.split('/').filter(Boolean)
7580
if (pathParts.length < 2 || pathParts[0] !== 'room') {
76-
console.error('URL 路径格式不正确,期望格式: /room/KEY')
81+
console.error('Invalid URL path format, expected format: /room/KEY')
7782
return null
7883
}
7984

80-
const roomValue = pathParts[1] // 获取 roomKey
85+
const roomValue = pathParts[1] // Get roomKey
8186

82-
// 从查询参数中获取 roomKeyType,默认为 2(身份码)
87+
// Get roomKeyType from query parameter, default to 2 (identity code)
8388
const roomKeyTypeParam = urlObj.searchParams.get('roomKeyType')
84-
let roomKeyType: 1 | 2 = 2 // 默认为身份码
89+
let roomKeyType: 1 | 2 = 2 // Default to identity code
8590

8691
if (roomKeyTypeParam) {
8792
const type = parseInt(roomKeyTypeParam, 10)
8893
if (type === 1 || type === 2) {
8994
roomKeyType = type as 1 | 2
9095
}
9196
} else {
92-
// 如果没有指定 roomKeyType,尝试根据 roomValue 判断
97+
// If roomKeyType is not specified, try to determine from roomValue
9398
const roomId = parseInt(roomValue, 10)
9499
if (!isNaN(roomId)) {
95-
roomKeyType = 1 // 数字则认为是房间ID
100+
roomKeyType = 1 // Numeric value is considered room ID
96101
}
97102
}
98103

99-
// 构建 roomKey
104+
// Build roomKey
100105
const roomKey: RoomKey = {
101106
type: roomKeyType,
102107
value: roomKeyType === 1 ? parseInt(roomValue, 10) : roomValue,
103108
}
104109

105110
return { serverUrl, roomKey }
106111
} catch (error) {
107-
console.error('解析 URL 失败:', error)
112+
console.error('Failed to parse URL:', error)
108113
return null
109114
}
110115
}
111116

117+
/**
118+
* Send user text message to the state machine.
119+
*
120+
* Processes messages from queues (super chat, gift, text) and sends them to the state machine
121+
* when it's in IDLE state. In auto mode, sends a "no message" notification if no messages
122+
* have been received for more than 10 seconds.
123+
*
124+
* @param lastTextMessageTime The timestamp of the last text message, or null if none.
125+
* @returns void
126+
*/
112127
const sendUserTextMessage = (lastTextMessageTime: number | null) => {
113128
if (globalState?.stateMachine?.stateValue === States.IDLE) {
114129
if (clientRef.current) {
115130
if (clientRef.current.superChatQueue.size > 0) {
116131
const message = clientRef.current.superChatQueue.dequeue()
117132
if (message) {
118-
const formattedMessages = `[${message.authorName}]发送了醒目留言: ${message.content}`
133+
const formattedMessages = `[${message.authorName}] sent super chat: ${message.content}`
119134
globalState?.stateMachine?.putConditionedMessage(
120135
new ConditionedMessage(Conditions.USER_TEXT_INPUT, { message: formattedMessages }),
121136
)
122-
console.log('[发送后台消息]: ', formattedMessages)
137+
console.log('[Send background message]: ', formattedMessages)
123138
return
124139
}
125140
}
126141
if (clientRef.current.giftQueue.size > 0) {
127142
const message = clientRef.current.giftQueue.dequeue()
128143
if (message) {
129-
const formattedMessages = `[${message.authorName}]发送了礼物: ${message.giftName}, ${message.num} `
144+
const formattedMessages = `[${message.authorName}] sent gift: ${message.giftName}, ${message.num} pieces`
130145
globalState?.stateMachine?.putConditionedMessage(
131146
new ConditionedMessage(Conditions.USER_TEXT_INPUT, { message: formattedMessages }),
132147
)
133-
console.log('[发送后台消息]: ', formattedMessages)
148+
console.log('[Send background message]: ', formattedMessages)
134149
return
135150
}
136151
}
@@ -142,111 +157,120 @@ export default function LiveStreamInput({ globalState }: LiveStreamInputProps) {
142157
globalState?.stateMachine?.putConditionedMessage(
143158
new ConditionedMessage(Conditions.USER_TEXT_INPUT, { message: formattedMessages }),
144159
)
145-
console.log('[发送后台消息]: ', formattedMessages)
160+
console.log('[Send background message]: ', formattedMessages)
146161
return
147162
}else{
148163
if (autoMode && lastTextMessageTime !== null && Date.now() - lastTextMessageTime > 10000) {
149164
globalState?.stateMachine?.putConditionedMessage(
150-
new ConditionedMessage(Conditions.USER_TEXT_INPUT, { message: '无消息/No message' }),
165+
new ConditionedMessage(Conditions.USER_TEXT_INPUT, { message: 'No message' }),
151166
)
152-
console.log('[发送后台消息]: 无消息/No message')
167+
console.log('[Send background message]: No message')
153168
}
154169
return
155170
}
156171
}
157172
}
158173
}
159174
/**
160-
* 消息处理器
175+
* Message handler for danmaku WebSocket client.
161176
*/
162177
const messageHandler: DanmakuMessageHandler = {
163178
onDebugMsg: (msg: string) => {
164-
console.log('[弹幕客户端]', msg)
179+
console.log('[Danmaku client]', msg)
165180
setConnectionStatus(msg)
166181
},
167182
onHeartBeat: (lastTextMessageTime: number | null) => {
168183
sendUserTextMessage(lastTextMessageTime)
169184
},
170185
onAddText: (message: TextMessage) => {
171-
console.log('[弹幕]', message.authorName, ':', message.content)
186+
console.log('[Danmaku]', message.authorName, ':', message.content)
172187
if (clientRef.current) {
173188
clientRef.current.messageQueue.enqueue(message)
174189
sendUserTextMessage(Date.now())
175190
}
176191
},
177192
onAddGift: (message: GiftMessage) => {
178-
console.log('[礼物]', message.authorName, ':', message.giftName, 'x', message.num)
193+
console.log('[Gift]', message.authorName, ':', message.giftName, 'x', message.num)
179194
if (clientRef.current) {
180195
clientRef.current.giftQueue.enqueue(message)
181196
sendUserTextMessage(Date.now())
182197
}
183198
},
184199
onAddMember: (message: MemberMessage) => {
185-
console.log('[成员]', message.authorName, '加入了直播间')
186-
// 这里可以添加处理成员消息的逻辑
200+
console.log('[Member]', message.authorName, 'joined the live stream')
201+
// Logic for handling member messages can be added here
187202
},
188203
onAddSuperChat: (message: SuperChatMessage) => {
189-
console.log('[超级聊天]', message.authorName, ':', message.content, '¥', message.price)
204+
console.log('[Super chat]', message.authorName, ':', message.content, '¥', message.price)
190205
if (clientRef.current) {
191206
clientRef.current.superChatQueue.enqueue(message)
192207
sendUserTextMessage(Date.now())
193208
}
194209
},
195210
onFatalError: (error: string) => {
196-
console.error('[致命错误]', error)
197-
setConnectionStatus(`连接失败: ${error}`)
211+
console.error('[Fatal error]', error)
212+
setConnectionStatus(`Connection failed: ${error}`)
198213
setIsConnected(false)
199214
},
200215
}
201216

202217
/**
203218
* Handle live stream URL confirmation.
219+
*
220+
* Parses the URL, disconnects any existing connection, and creates a new WebSocket client
221+
* to connect to the live stream server.
222+
*
223+
* @returns void
204224
*/
205225
const handleConfirm = () => {
206226
if (!liveStreamUrl.trim()) {
207227
return
208228
}
209229

210-
// 如果已经连接,先断开旧连接
230+
// If already connected, disconnect the old connection first
211231
if (clientRef.current) {
212232
clientRef.current.stop()
213233
clientRef.current = null
214234
}
215235

216-
// 解析 URL
217-
// URL 格式示例:
236+
// Parse URL
237+
// URL format examples:
218238
// - file:///path/loader.html?url=http%3A%2F%2Flocalhost%3A12450%2Froom%2FKEY%3FroomKeyType%3D2
219239
// - http://localhost:12450/room/KEY?roomKeyType=2
220240
const parsed = parseLiveStreamUrl(liveStreamUrl.trim())
221241
if (!parsed) {
222-
alert('无效的直播流 URL,请检查格式\n支持格式:\n1. file:// URL ( url 参数)\n2. http://server:port/room/KEY?roomKeyType=2')
242+
alert('Invalid live stream URL, please check the format\nSupported formats:\n1. file:// URL (with url parameter)\n2. http://server:port/room/KEY?roomKeyType=2')
223243
return
224244
}
225245

226-
// 创建 WebSocket 客户端
246+
// Create WebSocket client
227247
const client = new DanmakuWebSocketClient(parsed.serverUrl, parsed.roomKey, false)
228248
client.setMsgHandler(messageHandler)
229249
client.start()
230250

231251
clientRef.current = client
232252
setIsConnected(true)
233-
setConnectionStatus('连接中...')
253+
setConnectionStatus('Connecting...')
234254
}
235255

236256
/**
237-
* 断开连接
257+
* Handle disconnection from the live stream.
258+
*
259+
* Stops the WebSocket client and updates the connection status.
260+
*
261+
* @returns void
238262
*/
239263
const handleDisconnect = () => {
240264
if (clientRef.current) {
241265
clientRef.current.stop()
242266
clientRef.current = null
243267
setIsConnected(false)
244-
setConnectionStatus('已断开')
268+
setConnectionStatus('Disconnected')
245269
}
246270
}
247271

248272
/**
249-
* 组件卸载时清理连接
273+
* Clean up connection when component unmounts.
250274
*/
251275
useEffect(() => {
252276
return () => {
@@ -259,6 +283,11 @@ export default function LiveStreamInput({ globalState }: LiveStreamInputProps) {
259283

260284
/**
261285
* Handle Enter key press in input.
286+
*
287+
* Triggers the confirm action when Enter is pressed.
288+
*
289+
* @param e The keyboard event from the input element.
290+
* @returns void
262291
*/
263292
const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
264293
if (e.key === 'Enter') {

app/contexts/BabylonJSContext.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,7 @@ function BabylonJSProvider({
293293
return (
294294
<BabylonJSContext.Provider value={{ canvas, globalState }}>
295295
{children}
296-
<ChatModeMenu chatMode={chatMode} onModeSelect={handleChatModeSelect} enableLiveChat={true} />
296+
<ChatModeMenu chatMode={chatMode} onModeSelect={handleChatModeSelect} enableLiveChat={false} />
297297

298298
{chatMode === 'text' && (
299299
<Chatbox globalState={globalState} />

0 commit comments

Comments
 (0)