feat: Add mobile responsive layout, open room access, and admin room management

Mobile Responsive Layout:
- Add useMediaQuery, useIsMobile, useIsTablet, useIsDesktop hooks for device detection
- Create MobileHeader component with hamburger menu and action drawer
- Create BottomToolbar for mobile navigation (Files, Members)
- Create SlidePanel component for full-screen mobile sidebars
- Update RoomDetail.tsx with mobile/desktop conditional rendering
- Update RoomList.tsx with single-column grid and touch-friendly buttons
- Add CSS custom properties for safe areas and touch targets (min 44px)
- Add mobile viewport meta tags for notched devices

Open Room Access:
- All authenticated users can view all rooms (not just their own)
- Users can join active rooms they're not members of
- Add is_member field to room responses
- Update room list API to return all rooms by default

Admin Room Management:
- Add permanent delete functionality for system admins
- Add delete confirmation dialog with room title verification
- Broadcast room deletion via WebSocket to connected users
- Add users search API for adding members

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
egg
2025-12-05 09:12:10 +08:00
parent 1e44a63a8e
commit 1d5d4d447d
48 changed files with 3505 additions and 401 deletions

View File

@@ -1,12 +1,19 @@
"""WebSocket connection pool management"""
from fastapi import WebSocket
from typing import Dict, List, Set
from typing import Dict, List, Set, Any
from datetime import datetime
import asyncio
import json
from collections import defaultdict
def json_serializer(obj: Any) -> str:
"""Custom JSON serializer for objects not serializable by default json code"""
if isinstance(obj, datetime):
return obj.isoformat()
raise TypeError(f"Object of type {type(obj).__name__} is not JSON serializable")
class ConnectionInfo:
"""Information about a WebSocket connection"""
def __init__(self, websocket: WebSocket, user_id: str, room_id: str):
@@ -93,7 +100,7 @@ class WebSocketManager:
if room_id not in self._room_connections:
return
message_json = json.dumps(message)
message_json = json.dumps(message, default=json_serializer)
# Collect disconnected connections
disconnected = []
@@ -124,7 +131,7 @@ class WebSocketManager:
return
conn_info = self._user_connections[user_id]
message_json = json.dumps(message)
message_json = json.dumps(message, default=json_serializer)
try:
await conn_info.websocket.send_text(message_json)