From 854a73b0e9c9bfa85d40def9e4ec3a2814723f71 Mon Sep 17 00:00:00 2001 From: shuaiplus <2327005759@qq.com> Date: Sun, 1 Jun 2025 00:00:10 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8F=91=E5=B8=83=E5=89=8D=E7=9A=84=E8=B0=83?= =?UTF-8?q?=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/css/form-animation.css | 2 +- client/js/room.js | 18 ++++++++++- client/js/ui.js | 11 ++++++- client/js/util.emoji.js | 3 +- client/js/util.file.js | 9 ++++-- client/js/util.i18n.js | 57 ++++++++++++++++++++++------------- client/js/util.settings.js | 5 +-- client/js/util.theme.js | 4 +-- 8 files changed, 76 insertions(+), 33 deletions(-) diff --git a/client/css/form-animation.css b/client/css/form-animation.css index c95139a..0528944 100644 --- a/client/css/form-animation.css +++ b/client/css/form-animation.css @@ -16,7 +16,7 @@ .input-group input:focus + .floating-label, .input-group input:not(:placeholder-shown) + .floating-label { color: #30a8f7; - transform: translateY(-35px); + transform: translateY(-40px); } .input-group .floating-label span { diff --git a/client/js/room.js b/client/js/room.js index a86bc20..c25df09 100644 --- a/client/js/room.js +++ b/client/js/room.js @@ -365,4 +365,20 @@ export function exitRoom() { return false } -export { roomsData, activeRoomIndex }; \ No newline at end of file +export { roomsData, activeRoomIndex }; + +// Listen for sidebar username update event +// 监听侧边栏用户名更新事件 +window.addEventListener('updateSidebarUsername', () => { + if (activeRoomIndex >= 0 && roomsData[activeRoomIndex]) { + const rd = roomsData[activeRoomIndex]; + const sidebarUsername = document.getElementById('sidebar-username'); + if (sidebarUsername && rd.myUserName) { + sidebarUsername.textContent = rd.myUserName; + } + // Also update the avatar to ensure consistency + if (rd.myUserName) { + setSidebarAvatar(rd.myUserName); + } + } +}); \ No newline at end of file diff --git a/client/js/ui.js b/client/js/ui.js index 3d0dca8..facfb87 100644 --- a/client/js/ui.js +++ b/client/js/ui.js @@ -70,7 +70,7 @@ function validateRoomData(roomData) { // Copy text to clipboard with fallback // 复制文本到剪贴板(含降级处理) -function copyToClipboard(text, successMessage = t('action.copied', 'Copied to clipboard!'), errorPrefix = t('action.copy_failed', 'Copy failed, text:')) { +function copyToClipboard(text, successMessage = t('action.copied', 'Copied to clipboard!'), errorPrefix = t('action.copy_failed', 'Copy failed, url:')) { if (!text) { window.addSystemMsg && window.addSystemMsg(t('action.nothing_to_copy', 'Nothing to copy')); return; @@ -568,4 +568,13 @@ window.addEventListener('languageChange', () => { // Refresh chat input placeholder updateChatInputStyle(); +}); + +// Listen for regenerate login form event +// 监听重新生成登录表单事件 +window.addEventListener('regenerateLoginForm', () => { + const loginFormContainer = document.getElementById('login-form'); + if (loginFormContainer) { + loginFormContainer.innerHTML = generateLoginForm(false); + } }); \ No newline at end of file diff --git a/client/js/util.emoji.js b/client/js/util.emoji.js index 8abd714..a8beae0 100644 --- a/client/js/util.emoji.js +++ b/client/js/util.emoji.js @@ -66,10 +66,9 @@ export function setupEmojiPicker({ // 点击外部隐藏选择器 on(document, 'click', (ev) => { if (!picker.contains(ev.target) && ev.target !== btn) { - hidePickerWithAnimation(); + hidePickerWithAnimation(); } }); - console.log('Emoji picker initialized successfully') } catch (error) { console.error('Failed to initialize emoji picker:', error) } diff --git a/client/js/util.file.js b/client/js/util.file.js index 3e4d8b5..9f964bd 100644 --- a/client/js/util.file.js +++ b/client/js/util.file.js @@ -3,6 +3,9 @@ import { deflate, inflate } from 'fflate'; import { showFileUploadModal } from './util.fileUpload.js'; +// 分卷大小统一配置 +const DEFAULT_VOLUME_SIZE = 512 * 1024; // 512KB + // File transfer state management // 文件传输状态管理 window.fileTransfers = new Map(); @@ -49,9 +52,11 @@ async function calculateHash(data) { return hashArray.map(b => b.toString(16).padStart(2, '0')).join(''); } + + // Compress file into volumes with optimized compression // 将文件压缩为分卷,优化压缩算法 -async function compressFileToVolumes(file, volumeSize = 96 * 1024) { // 96KB原始数据,base64后约128KB +async function compressFileToVolumes(file, volumeSize = DEFAULT_VOLUME_SIZE) { // 96KB原始数据,base64后约128KB return new Promise((resolve, reject) => { const reader = new FileReader(); reader.onload = async function(e) { @@ -97,7 +102,7 @@ async function compressFileToVolumes(file, volumeSize = 96 * 1024) { // 96KB原 // Compress multiple files into a single archive with volumes // 将多个文件压缩为单个分卷归档 -async function compressFilesToArchive(files, volumeSize = 96 * 1024) { try { +async function compressFilesToArchive(files, volumeSize = DEFAULT_VOLUME_SIZE) { try { // Create a simple archive format: [file1_size][file1_name_length][file1_name][file1_data][file2_size]... // 创建简单的归档格式 const archiveData = []; diff --git a/client/js/util.i18n.js b/client/js/util.i18n.js index c97b0cb..f1cd099 100644 --- a/client/js/util.i18n.js +++ b/client/js/util.i18n.js @@ -41,9 +41,9 @@ const LANGUAGES = { 'file.selected_files': 'Selected Files', 'file.clear_all': 'Clear All', 'file.cancel': 'Cancel', - 'file.send_files': 'Send Files', - 'file.sending': 'Sending', - 'file.receiving': 'Receiving', 'file.files': 'files', + 'file.send_files': 'Send Files', 'file.sending': 'Sending', + 'file.receiving': 'Receiving', + 'file.files': 'files', 'file.total': 'Total', 'file.files_selected': '{count} files selected, {size} total', 'file.upload_files': 'Upload Files', @@ -124,9 +124,9 @@ const LANGUAGES = { 'file.selected_files': '已选择的文件', 'file.clear_all': '清空所有', 'file.cancel': '取消', - 'file.send_files': '发送文件', - 'file.sending': '发送中', - 'file.receiving': '接收中', 'file.files': '个文件', + 'file.send_files': '发送文件', 'file.sending': '发送中', + 'file.receiving': '接收中', + 'file.files': '个文件', 'file.total': '总计', 'file.files_selected': '选中 {count} 个文件,总计 {size}', 'file.upload_files': '上传文件', @@ -164,7 +164,7 @@ const LANGUAGES = { 'system.file_send_failed': '文件发送失败:', 'system.joined': '加入了对话', 'system.left': '离开了对话', - 'system.secured': '连接已安全', + 'system.secured': '已建立端到端安全连接', 'system.private_message_failed': '无法发送私信给', 'system.private_file_failed': '无法发送私密文件给', 'system.user_not_connected': '用户可能未完全连接。', @@ -228,9 +228,31 @@ export function getAvailableLanguages() { export function initI18n(settings) { if (settings && settings.language) { setLanguage(settings.language); + } else { + // Auto-detect browser language + // 自动检测浏览器语言 + const browserLang = detectBrowserLanguage(); + setLanguage(browserLang); } } +// Detect browser language and return supported language code +// 检测浏览器语言并返回支持的语言代码 +function detectBrowserLanguage() { + const navigatorLang = navigator.language || navigator.userLanguage || 'en'; + + // Extract language code (e.g., 'zh-CN' -> 'zh', 'en-US' -> 'en') + const langCode = navigatorLang.split('-')[0].toLowerCase(); + + // Check if we support this language + if (LANGUAGES[langCode]) { + return langCode; + } + + // Default fallback to English + return 'en'; +} + // Update static HTML text elements // 更新HTML中的静态文本元素 export function updateStaticTexts() { @@ -245,27 +267,20 @@ export function updateStaticTexts() { if (loginTitle) { loginTitle.textContent = t('ui.enter_node', 'Enter a Node'); } - - // Update login form content with new translations + // Update login form content with new translations const loginFormContainer = document.getElementById('login-form'); if (loginFormContainer) { - // Import and regenerate login form with current language - import('./ui.js').then(({ generateLoginForm }) => { - loginFormContainer.innerHTML = generateLoginForm(false); - }); + // Use a custom event to trigger form regeneration instead of dynamic import + // 使用自定义事件触发表单重新生成,而不是动态导入 + window.dispatchEvent(new CustomEvent('regenerateLoginForm')); } // Update sidebar username label const sidebarUsername = document.getElementById('sidebar-username'); if (sidebarUsername) { - import('./room.js').then(roomMod => { - const roomsData = roomMod.roomsData; - const activeRoomIndex = roomMod.activeRoomIndex; - const rd = roomsData && roomsData.length > 0 && activeRoomIndex >= 0 ? roomsData[activeRoomIndex] : null; - sidebarUsername.textContent = rd && rd.myUserName ? rd.myUserName : t('ui.my_name', 'My Name'); - }).catch(() => { - sidebarUsername.textContent = t('ui.my_name', 'My Name'); - }); + // Use a custom event to update sidebar username instead of dynamic import + // 使用自定义事件更新侧边栏用户名,而不是动态导入 + window.dispatchEvent(new CustomEvent('updateSidebarUsername')); } // Update "Enter a Node" text in sidebar const joinRoomText = document.getElementById('join-room-text'); diff --git a/client/js/util.settings.js b/client/js/util.settings.js index 2d4ac43..c11c7bb 100644 --- a/client/js/util.settings.js +++ b/client/js/util.settings.js @@ -23,8 +23,9 @@ import { t, setLanguage, getCurrentLanguage, initI18n } from './util.i18n.js'; const DEFAULT_SETTINGS = { notify: false, sound: false, - theme: 'theme1', - language: 'en' // 'en' for English, 'zh' for Chinese + theme: 'theme1' + // 注意:我们不设置默认语言,让系统自动检测浏览器语言 + // Note: We don't set a default language, let the system auto-detect browser language }; // Load settings from localStorage diff --git a/client/js/util.theme.js b/client/js/util.theme.js index 445e874..9a5a354 100644 --- a/client/js/util.theme.js +++ b/client/js/util.theme.js @@ -82,11 +82,9 @@ export function applyTheme(themeId) { } else { mainElement.style.background = theme.background; } - // Add transition effect for smooth theme switching - // 添加过渡效果,实现平滑的主题切换 + // Add transition effect for smooth theme switching // 添加过渡效果,实现平滑的主题切换 mainElement.style.transition = 'background 0.5s ease-in-out, background-image 0.5s ease-in-out'; - console.log(`Applied theme: ${themeId}`); return true; } else { console.warn('Main element not found');