设置项改成设置栏

This commit is contained in:
shuaiplus committed 2025-05-30 23:13:44 +08:00
1 parent 742e2fd66d
commit 3f1093aee3
7 files changed
+220 -118

No files matched your search

+1
View File
@@ -49,3 +49,4 @@ client/build/
# Ignore coverage # Ignore coverage
coverage/ coverage/
dist/ dist/
新增功能.md
+19 -7
View File
@@ -70,10 +70,9 @@
* { * {
touch-action: pan-y; touch-action: pan-y;
} } .sidebar,
.rightbar,
.sidebar, .settings-sidebar {
.rightbar {
position: fixed; position: fixed;
top: 0; top: 0;
bottom: 0; bottom: 0;
@@ -95,6 +94,19 @@
transform: translateX(0); transform: translateX(0);
} }
.settings-sidebar {
left: 0;
max-width: 80vw;
width: 80vw !important;
transform: translateX(-100%);
border-right: 1px solid #e0e0e0;
z-index: 1001; /* Higher than normal sidebar */
}
.settings-sidebar.mobile-open {
transform: translateX(0);
}
.rightbar { .rightbar {
right: 0; right: 0;
max-width: 70vw; max-width: 70vw;
@@ -143,11 +155,11 @@
.mobile-info-btn:active { .mobile-info-btn:active {
background: #e0e0e0; background: #e0e0e0;
transform: scale(0.93); transform: scale(0.93);
} } .settings-panel-card {
.settings-panel-card {
left: 2vw !important; left: 2vw !important;
} }
/* Settings sidebar mobile styles - removed duplicate rules since they are above */
} }
.member.private-chat-active { .member.private-chat-active {
+74 -46
View File
@@ -52,74 +52,102 @@ body {
display: block; display: block;
} }
.settings-panel { /* New settings sidebar styles */
display: none; .settings-sidebar {
position: fixed; width: 250px;
left: 0;
top: 0;
right: 0;
bottom: 0;
z-index: 9999;
pointer-events: none;
background: none;
}
.settings-panel-card {
background: #fff; background: #fff;
border-radius: 16px; border-right: 1px solid #e0e0e0;
box-shadow: 0 2px 24px rgba(60, 80, 100, 0.18);
padding: 15px 15px 15px 15px;
min-width: 210px;
position: absolute;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 10px; box-shadow: 2px 0 8px #e0e0e0a0;
pointer-events: auto; transition: width 0.3s ease;
opacity: 0; position: relative;
transform: translateY(-10px) scale(0.95);
transition: opacity 0.3s ease, transform 0.3s ease;
} }
.settings-panel-card.open-anim { .settings-header {
opacity: 1; display: flex;
transform: translateY(0) scale(1); align-items: center;
padding: 17.2px 18px 10px 17px;
background: #fff;
border-bottom: 1px solid #dcdcdc;
position: relative;
} }
.settings-panel-card.close-anim { .settings-back-btn {
opacity: 0; background: none;
transform: translateY(-10px) scale(0.95); border: none;
cursor: pointer;
padding: 4px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
transition: background-color 0.2s ease;
margin-right: 12px;
}
.settings-back-btn:hover {
background: #f5f5f5;
} }
.settings-title { .settings-title {
font-size: 1.3rem; font-size: 1.3rem;
font-weight: 600; font-weight: 600;
margin-bottom: 10px; margin: 0;
color: #30a8f7; color: #30a8f7;
text-align: left; }
.settings-content {
flex: 1;
padding: 20px;
overflow-y: auto;
background: #fff;
}
.settings-section {
margin-bottom: 24px;
}
.settings-section-title {
font-size: 1.1rem;
font-weight: 600;
margin-bottom: 12px;
color: #222;
border-bottom: 1px solid #f0f0f0;
padding-bottom: 8px;
} }
.settings-item { .settings-item {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
font-size: 1.08rem;
color: #222;
margin-bottom: 8px;
}
.settings-item select {
font-size: 1rem; font-size: 1rem;
border-radius: 8px; color: #222;
border: 1px solid #e0e0e0; margin-bottom: 12px;
padding: 4px 10px; padding: 8px 0;
background: #fafbfc;
outline: none;
transition: border-color 0.2s ease, background-color 0.2s ease;
} }
.settings-item select:focus { .settings-item-label {
border-color: #30a8f7; flex: 1;
background: #fff; margin-right: 12px;
}
.settings-item-description {
font-size: 0.9rem;
color: #666;
margin-top: 4px;
}
/* Old settings panel - hide */
.settings-panel {
display: none !important;
}
/* Old settings panel styles - remove */
.settings-panel-card,
.settings-panel-card.open-anim,
.settings-panel-card.close-anim {
display: none !important;
} }
.switch { .switch {
+15 -2
View File
@@ -15,10 +15,23 @@
<!-- 登录表单内容将由JavaScript动态生成 --> <!-- 登录表单内容将由JavaScript动态生成 -->
<!-- Login form content will be dynamically generated by JavaScript --> <!-- Login form content will be dynamically generated by JavaScript -->
</form> </form>
</div> </div> <div class="container" id="chat-container" style="display:none;">
<div class="container" id="chat-container" style="display:none;">
<div class="mobile-sidebar-mask" id="mobile-sidebar-mask"></div> <div class="mobile-sidebar-mask" id="mobile-sidebar-mask"></div>
<div class="mobile-rightbar-mask" id="mobile-rightbar-mask"></div> <div class="mobile-rightbar-mask" id="mobile-rightbar-mask"></div>
<!-- Settings panel as a sidebar replacement -->
<div class="settings-sidebar" id="settings-sidebar" style="display:none;">
<div class="settings-header">
<button class="settings-back-btn" id="settings-back-btn" title="返回" aria-label="返回">
<svg width="24px" height="24px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M15 18L9 12L15 6" stroke="#808080" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</button>
<h2 class="settings-title">设置</h2>
</div>
<div class="settings-content" id="settings-content">
<!-- Settings content will be populated by JavaScript -->
</div>
</div>
<div class="sidebar" id="sidebar"> <div class="sidebar" id="sidebar">
<div class="sidebar-user"> <span class="avatar" id="sidebar-user-avatar"></span> <span class="sidebar-username" id="sidebar-username">My Name</span> <button class="settings-btn" id="settings-btn" title="设置" aria-label="设置"> <svg width="30px" height="30px" viewBox="0 0 24 24" fill="none" <div class="sidebar-user"> <span class="avatar" id="sidebar-user-avatar"></span> <span class="sidebar-username" id="sidebar-username">My Name</span> <button class="settings-btn" id="settings-btn" title="设置" aria-label="设置"> <svg width="30px" height="30px" viewBox="0 0 24 24" fill="none"
xmlns="http://www.w3.org/2000/svg"> xmlns="http://www.w3.org/2000/svg">
+9 -11
View File
@@ -112,7 +112,6 @@ window.addEventListener('DOMContentLoaded', () => {
setupImagePreview(); setupImagePreview();
setupEmojiPicker(); setupEmojiPicker();
initSettings(); initSettings();
const settingsBtn = $id('settings-btn'); // 设置按钮 / Settings button const settingsBtn = $id('settings-btn'); // 设置按钮 / Settings button
if (settingsBtn) { if (settingsBtn) {
settingsBtn.onclick = (e) => { settingsBtn.onclick = (e) => {
@@ -121,17 +120,16 @@ window.addEventListener('DOMContentLoaded', () => {
} }
} }
// 点击其他地方时关闭设置面板 // 设置返回按钮事件处理 / Settings back button event handler
// Close settings panel when clicking outside const settingsBackBtn = $id('settings-back-btn');
document.addEventListener('click', (ev) => { if (settingsBackBtn) {
const panel = $id('settings-panel'); settingsBackBtn.onclick = (e) => {
if (panel && panel.style.display === 'block') { e.stopPropagation();
const card = panel.querySelector('.settings-panel-card'); closeSettingsPanel(); // 关闭设置面板 / Close settings panel
if (card && !card.contains(ev.target) && ev.target.id !== 'settings-btn') {
closeSettingsPanel();
}
} }
}); }
// 点击其他地方时关闭设置面板 (已移除,因为现在使用侧边栏形式)
// Close settings panel when clicking outside (removed since we now use sidebar format)
const input = document.querySelector('.input-message-input'); // 消息输入框 / Message input box const input = document.querySelector('.input-message-input'); // 消息输入框 / Message input box
if (input) { if (input) {
+18 -6
View File
@@ -16,6 +16,9 @@ import {
import { import {
$id $id
} from './util.dom.js'; } from './util.dom.js';
import {
closeSettingsPanel
} from './util.settings.js';
// Render the main header // Render the main header
// 渲染主标题栏 // 渲染主标题栏
@@ -37,6 +40,7 @@ export function renderMainHeader() {
export function setupMobileUIHandlers() { export function setupMobileUIHandlers() {
const sidebar = document.getElementById('sidebar'); const sidebar = document.getElementById('sidebar');
const rightbar = document.getElementById('rightbar'); const rightbar = document.getElementById('rightbar');
const settingsSidebar = document.getElementById('settings-sidebar');
const mobileMenuBtn = document.getElementById('mobile-menu-btn'); const mobileMenuBtn = document.getElementById('mobile-menu-btn');
const mobileInfoBtn = document.getElementById('mobile-info-btn'); const mobileInfoBtn = document.getElementById('mobile-info-btn');
const sidebarMask = document.getElementById('mobile-sidebar-mask'); const sidebarMask = document.getElementById('mobile-sidebar-mask');
@@ -66,10 +70,14 @@ export function setupMobileUIHandlers() {
e.stopPropagation(); e.stopPropagation();
sidebar.classList.add('mobile-open'); sidebar.classList.add('mobile-open');
sidebarMask.classList.add('active') sidebarMask.classList.add('active')
}; }; sidebarMask.onclick = function() {
sidebarMask.onclick = function() { // Check if settings sidebar is open
sidebar.classList.remove('mobile-open'); if (settingsSidebar && settingsSidebar.classList.contains('mobile-open')) {
sidebarMask.classList.remove('active') closeSettingsPanel();
} else {
sidebar.classList.remove('mobile-open');
sidebarMask.classList.remove('active');
}
} }
} }
if (mobileInfoBtn && rightbar && rightbarMask) { if (mobileInfoBtn && rightbar && rightbarMask) {
@@ -82,8 +90,7 @@ export function setupMobileUIHandlers() {
rightbar.classList.remove('mobile-open'); rightbar.classList.remove('mobile-open');
rightbarMask.classList.remove('active') rightbarMask.classList.remove('active')
} }
} } document.addEventListener('click', function(ev) {
document.addEventListener('click', function(ev) {
if (!isMobile()) return; if (!isMobile()) return;
if (sidebar && sidebar.classList.contains('mobile-open')) { if (sidebar && sidebar.classList.contains('mobile-open')) {
if (!sidebar.contains(ev.target) && ev.target !== mobileMenuBtn) { if (!sidebar.contains(ev.target) && ev.target !== mobileMenuBtn) {
@@ -91,6 +98,11 @@ export function setupMobileUIHandlers() {
if (sidebarMask) sidebarMask.classList.remove('active') if (sidebarMask) sidebarMask.classList.remove('active')
} }
} }
if (settingsSidebar && settingsSidebar.classList.contains('mobile-open')) {
if (!settingsSidebar.contains(ev.target)) {
closeSettingsPanel();
}
}
if (rightbar && rightbar.classList.contains('mobile-open')) { if (rightbar && rightbar.classList.contains('mobile-open')) {
if (!rightbar.contains(ev.target) && ev.target !== mobileInfoBtn) { if (!rightbar.contains(ev.target) && ev.target !== mobileInfoBtn) {
rightbar.classList.remove('mobile-open'); rightbar.classList.remove('mobile-open');
+84 -46
View File
@@ -64,19 +64,38 @@ function askNotificationPermission(callback) {
// Setup the settings panel UI // Setup the settings panel UI
// 设置设置面板 UI // 设置设置面板 UI
function setupSettingsPanel() { function setupSettingsPanel() {
let panel = $id('settings-panel'); const settingsSidebar = $id('settings-sidebar');
if (!panel) { const settingsContent = $id('settings-content');
panel = createElement('div', { if (!settingsSidebar || !settingsContent) return;
id: 'settings-panel',
class: 'settings-panel'
}, `<div class="settings-panel-card"><div class="settings-title">Settings</div><div class="settings-item"><span>Desktop Notification</span><label class="switch"><input type="checkbox"id="settings-notify"><span class="slider"></span></label></div><div class="settings-item"><span>Sound Notification</span><label class="switch"><input type="checkbox"id="settings-sound"><span class="slider"></span></label></div></div>`);
document.body.appendChild(panel)
}
const settings = loadSettings(); const settings = loadSettings();
const notifyCheckbox = $('#settings-notify', panel); // Create settings content HTML
const soundCheckbox = $('#settings-sound', panel); settingsContent.innerHTML = `
if (notifyCheckbox) notifyCheckbox.checked = !!settings.notify; <div class="settings-section">
if (soundCheckbox) soundCheckbox.checked = !!settings.sound; <div class="settings-section-title">通知设置</div>
<div class="settings-item">
<div class="settings-item-label">
<div>桌面通知</div>
</div>
<label class="switch">
<input type="checkbox" id="settings-notify" ${settings.notify ? 'checked' : ''}>
<span class="slider"></span>
</label>
</div>
<div class="settings-item">
<div class="settings-item-label">
<div>声音通知</div>
</div>
<label class="switch">
<input type="checkbox" id="settings-sound" ${settings.sound ? 'checked' : ''}>
<span class="slider"></span>
</label>
</div>
</div>
`;
const notifyCheckbox = $('#settings-notify', settingsContent);
const soundCheckbox = $('#settings-sound', settingsContent);
on(notifyCheckbox, 'change', e => { on(notifyCheckbox, 'change', e => {
const checked = e.target.checked; const checked = e.target.checked;
if (checked) { if (checked) {
@@ -91,13 +110,12 @@ function setupSettingsPanel() {
settings.sound = false; settings.sound = false;
if (soundCheckbox) soundCheckbox.checked = false; if (soundCheckbox) soundCheckbox.checked = false;
saveSettings(settings); saveSettings(settings);
applySettings(settings); applySettings(settings); // 防止重复通知,添加一个标志位
// 防止重复通知,添加一个标志位 if (!settingsSidebar._notificationShown) {
if (!panel._notificationShown) {
new Notification('Notifications enabled', { new Notification('Notifications enabled', {
body: 'You will receive alerts here.' body: 'You will receive alerts here.'
}); });
panel._notificationShown = true; // 设置标志位 settingsSidebar._notificationShown = true; // 设置标志位
} }
} else { } else {
settings.notify = false; settings.notify = false;
@@ -110,10 +128,9 @@ function setupSettingsPanel() {
} else { } else {
settings.notify = false; settings.notify = false;
saveSettings(settings); saveSettings(settings);
applySettings(settings); applySettings(settings); // 重置标志位
// 重置标志位 if (settingsSidebar._notificationShown) {
if (panel._notificationShown) { settingsSidebar._notificationShown = false;
panel._notificationShown = false;
} }
} }
}); });
@@ -128,41 +145,62 @@ function setupSettingsPanel() {
}); });
} }
// Check if device is mobile
function isMobile() {
return window.innerWidth <= 768;
}
// Open the settings panel // Open the settings panel
// 打开设置面板 // 打开设置面板
function openSettingsPanel() { function openSettingsPanel() {
const settingsSidebar = $id('settings-sidebar');
const sidebar = $id('sidebar');
const sidebarMask = $id('mobile-sidebar-mask');
if (!settingsSidebar || !sidebar) return;
if (isMobile()) {
// Mobile: hide main sidebar and show settings sidebar with mask
sidebar.classList.remove('mobile-open');
settingsSidebar.style.display = 'flex';
settingsSidebar.classList.add('mobile-open');
if (sidebarMask) {
sidebarMask.classList.add('active');
}
} else {
// Desktop: hide main sidebar and show settings sidebar
sidebar.style.display = 'none';
settingsSidebar.style.display = 'flex';
}
// Setup settings content
setupSettingsPanel(); setupSettingsPanel();
const panel = $id('settings-panel');
const btn = $id('settings-btn');
if (!btn || !panel) return;
if (panel.style.display === 'block') return;
const btnRect = btn.getBoundingClientRect();
panel.style.display = 'block';
const card = $('.settings-panel-card', panel);
if (!card) return;
card.style.position = 'fixed';
card.style.left = btnRect.left + 'px';
card.style.top = (btnRect.bottom + 8) + 'px';
card.style.transform = 'translateX(0)';
removeClass(card, 'close-anim');
// 强制触发重绘,然后添加打开动画
card.offsetHeight; // 强制重绘
addClass(card, 'open-anim');
} }
// Close the settings panel // Close the settings panel
// 关闭设置面板 // 关闭设置面板
function closeSettingsPanel() { function closeSettingsPanel() {
const panel = $id('settings-panel'); const settingsSidebar = $id('settings-sidebar');
if (!panel) return; const sidebar = $id('sidebar');
const card = $('.settings-panel-card', panel); const sidebarMask = $id('mobile-sidebar-mask');
if (!card) return;
removeClass(card, 'open-anim'); if (!settingsSidebar || !sidebar) return;
addClass(card, 'close-anim');
setTimeout(() => { if (isMobile()) {
panel.style.display = 'none'; // Mobile: hide settings sidebar and mask, show main sidebar if needed
removeClass(card, 'close-anim') settingsSidebar.classList.remove('mobile-open');
}, 300) if (sidebarMask) {
sidebarMask.classList.remove('active');
}
// Don't auto-show main sidebar on mobile - let user click menu button
setTimeout(() => {
settingsSidebar.style.display = 'none';
}, 300); // Wait for animation to complete
} else {
// Desktop: hide settings sidebar and show main sidebar
settingsSidebar.style.display = 'none';
sidebar.style.display = 'flex';
}
} }
// Initialize settings on page load // Initialize settings on page load