Files
dumpsterChat/web/src/components/MobileDrawer.tsx
T
hobokenchicken bb650ac2a0 Phase 3: Polish & PWA
Backend:
- DB: reactions table, invites table, reply_to column on messages
- gateway/events.go: added REACTION_ADD, REACTION_REMOVE events
- internal/reaction/handlers.go: reaction CRUD with WebSocket broadcast
- internal/invite/handlers.go: invite creation, info, join with code
- gateway/hub.go: presence tracking with idle detection
- gateway/client.go: idle timeout support

Frontend - Social:
- TypingIndicator: real-time 'user is typing...' display
- ReactionBar: emoji reactions on messages with counts
- EmojiPicker: searchable emoji grid for reactions
- ReplyBar: quoted reply display above messages
- MentionPopup: @mention autocomplete with user list

Frontend - PWA:
- manifest.json: PWA manifest with theme color and icons
- sw.js: service worker with cache-first strategy and push support
- stores/push.ts: push notification subscription management
- InstallPrompt: 'Add to Home Screen' banner

Frontend - Mobile:
- MobileNav: bottom nav bar for mobile (servers/channels/chat/members)
- MobileDrawer: slide-out drawer with server bar + channel list
- index.html: PWA meta tags, safe area viewport

Frontend - Polish:
- ThemeToggle: dark/light mode switch with localStorage persistence
- InviteModal: generate invite links with expiry and max uses
- JoinServer: /invite/:code join flow
- stores/typing.ts: typing indicator state management
- stores/presence.ts: real-time presence tracking
- tailwind.config.js: darkMode: 'class', light mode color tokens
- styles/index.css: light mode CSS variable overrides
2026-06-28 16:44:39 -04:00

35 lines
899 B
TypeScript

import { ServerBar } from './ServerBar.tsx';
import { ChannelList } from './ChannelList.tsx';
interface MobileDrawerProps {
isOpen: boolean;
onClose: () => void;
}
export function MobileDrawer({ isOpen, onClose }: MobileDrawerProps) {
if (!isOpen) return null;
return (
<div className="md:hidden fixed inset-0 z-50">
{/* Backdrop */}
<div
className="absolute inset-0 bg-black/50"
onClick={onClose}
/>
{/* Drawer */}
<div className="absolute left-0 top-0 bottom-0 w-[280px] bg-gb-bg flex">
{/* Server bar */}
<div className="w-[48px] bg-gb-bg-h">
<ServerBar />
</div>
{/* Channel list */}
<div className="flex-1">
<ChannelList />
</div>
</div>
{/* Swipe hint */}
<div className="absolute right-0 top-0 bottom-0 w-1 bg-gb-orange/20" />
</div>
);
}