Frontend Guide
STORM DAY frontend is built with Vue 3 Composition API, TypeScript, Pinia for state management, and Nuxt UI components. The architecture follows Atomic Design principles.
Routes
| Path | View | Auth |
|---|---|---|
/login | LoginView.vue | Guest only |
/register | RegisterView.vue | Guest only |
/chat | ChatView.vue | Required |
Pinia Stores
authStore
Manages authentication state, persisted in localStorage.
// src/stores/auth.ts
interface AuthState {
accessToken: string | null
refreshToken: string | null
user: {
id: string
username: string
display_name: string
email: string
avatar_url?: string
} | null
}
// Actions
login(email: string, password: string): Promise<void>
register(data: RegisterData): Promise<void>
logout(): void
refresh(): Promise<void>
updateProfile(displayName: string): Promise<void>
updatePassword(currentPassword: string, newPassword: string): Promise<void>chatStore
Manages conversations, messages, members, and WebSocket connection.
// src/stores/chat.ts
interface ChatState {
conversations: Conversation[]
messagesByConversation: Record<string, Message[]>
membersByConversation: Record<string, ChatUser[]>
activeConversationId: string | null
typingUsers: Record<string, TypingUser[]>
}
// Getters
activeConversation: Conversation | null
activeMessages: Message[]
activeMembers: ChatUser[]
activeTypingUsers: TypingUser[]
membersLabel: string
systemMessage: string | null
// Actions
fetchConversations(): Promise<void>
selectConversation(id: string): Promise<void>
createConversation(memberIds: string[], name?: string): Promise<void>
deleteConversation(id: string): Promise<void>
sendMessage(content: string, options?: MessageOptions): Promise<void>
editMessage(messageId: string, content: string): Promise<void>
emitTyping(): void
initWebSocket(): void
destroyWebSocket(): voidComponent Structure
Components follow Atomic Design methodology:
src/components/
├── atoms/
│ ├── BaseAvatar.vue
│ ├── IconGhostButton.vue
│ ├── LoadingText.vue
│ ├── MessageStatusBadge.vue
│ ├── SystemMessageText.vue
│ └── BackgroundCanvas.vue
│
├── molecules/
│ ├── MessageBubble.vue
│ ├── ChatComposer.vue
│ ├── ConversationItem.vue
│ ├── DateDivider.vue
│ ├── MessageReplyQuote.vue
│ ├── MessageForwardQuote.vue
│ ├── MessageOptionsMenu.vue
│ ├── MessageSeenByAvatars.vue
│ ├── ReplyPreviewBanner.vue
│ ├── TypingIndicator.vue
│ ├── ForwardConversationPicker.vue
│ └── UserPickerItem.vue
│
├── organisms/
│ ├── ChatSidebar.vue
│ ├── ChatThread.vue
│ ├── ChatMembersRail.vue
│ ├── CreateConversationPanel.vue
│ ├── AccountSettingsModal.vue
│ ├── ConversationInfoPanel.vue
│ └── UserProfileModal.vue
│
├── templates/
│ ├── AuthLayoutTemplate.vue
│ └── ChatLayoutTemplate.vue
│
└── views/
├── LoginView.vue
├── RegisterView.vue
└── ChatView.vueKey UI Features
Dark/Light Theme
CSS variable based theming with toggle support
GSAP Animations
Fade in/out transitions between conversations and chat header animations
WebGL Background
Custom GLSL shaders with noise-based animated canvas on auth pages
Optimistic UI
Messages appear instantly with status: sending → sent → delivered → seen
Reply & Forward
Reply to messages with preview banner, forward to other conversations
Message Editing
Edit own messages within 2-minute window
Typing Indicator
Animated dots when remote users are typing
Seen Avatars
Avatar stack below last seen message in group chats
Media Upload
Attach files via composer with drag-and-drop support
Mobile Responsive
Sidebar hidden on mobile with back button in chat header
Message Features
Optimistic Send
Messages are assigned a temporary UUID and displayed immediately. The UUID is replaced with the server-generated ID on API response.
Reply Quotes
Click reply on a message to show a preview banner in the composer. The reply_to_id is sent with the message.
Forward Quotes
Click forward to open the ForwardConversationPicker modal and forward the message to another conversation.
Typing Indicator
Shows animated dots when remote users are typing. Auto-clears after 3 seconds of inactivity.
Delivery & Seen Receipts
Message status badge updates in real-time. Seen avatars stack below the last seen message in groups.
Background Resync
Silent background resync every 350ms after WebSocket events to ensure consistency.