Private
Public Access
Every top-level page independently hardcoded a full-viewport height (.chat-shell: 100vh, .admin-page: 100%, .login-screen family: min-height 100vh), assuming it alone owned the whole viewport. UpdateBanner renders globally above all of them (App.tsx), so its height just stacked on top instead of the page shrinking to make room -- on ChatShellPage specifically (overflow: hidden), that clipped the bottom of the screen and hid the composer behind the visible edge. Made #root a flex column shared by the banner and whichever page is routed, with each page now using flex: 1; min-height: 0 to fill whatever space is actually left instead of assuming the full viewport. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
DS Chat frontend (Phase 1)
React + Vite PWA. Login, room list, and chat views wired to the backend's
REST API and /ws/chat WebSocket endpoint. See ../README.md
and ../backend/README.md for full local setup.
Dev
npm install
npm run dev
The dev server proxies /api and /ws to http://localhost:8000 (see
vite.config.ts), so the backend must be running for anything beyond the
login page to work.
Build
npm run build
Generates the PWA manifest and service worker via vite-plugin-pwa into dist/.
Layout
src/
main.tsx, App.tsx routes: /login, /rooms, /rooms/:roomId
api/ fetch wrappers (client, auth, rooms)
ws/useChatSocket.ts WebSocket hook (join/send/receive)
context/AuthContext.tsx current-user state, hydrated via GET /api/auth/me
components/ ProtectedRoute, RoomListItem, MessageList, MessageInput
pages/ LoginPage, RoomListPage, ChatRoomPage