refactor(frontend): major rebuild — feature-sliced architecture + bug fixes + glass-morphism UI

Architecture:
- Feature-sliced directory: entities/, shared/, features/, widgets/
- Consolidated API client (shared/api/client.ts) — all endpoints in one file
- Single WebSocket manager (shared/ws/socket.ts) with typed event bus
- Extracted hooks: useAudioPlayback, useAudioTransmit, useLocalStorage, useUIState
- UI primitives moved to shared/ui/ with barrel export
- Added Skeleton, Toast, MobileTabBar components

Bug fixes (8/8):
1. useMemo→useEffect in RecordingsSubPanel (async side-effect anti-pattern)
2. ArrayBuffer.slice() before WebSocket send (shared buffer bug)
3. Proper useEffect dependency arrays throughout
4. Stable React keys (no index fallbacks)
5. onReanalyze properly awaited (Promise<void> return)
6. monitorGuild memoized with useMemo
7. localStorage validation with shape checking
8. Deleted duplicate socket logic (ws/client.ts removed)

UI polish:
- Glass-morphism design tokens (backdrop-blur, translucent cards)
- Gradient mesh background with subtle radial overlays
- Expandable sidebar + mobile bottom tab bar
- Skeleton loading placeholders
- Audio visualizer with CSS pulse animation

Deleted: src/api/, src/components/, src/hooks/, src/types/, src/ws/, src/lib/
Added: 40 new files across feature-sliced structure

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
MythEclipse
2026-06-01 16:42:36 +07:00
co-authored by Claude Opus 4.8
parent 1aab0d1df1
commit f5507e01f6
84 changed files with 2054 additions and 2658 deletions
+26
View File
@@ -0,0 +1,26 @@
// ─── Typed event map for WebSocket events ────────────────────────────────────
export interface WsEventMap {
message_created: { data: unknown };
message_updated: { data: unknown };
message_deleted: { data: { id: string } };
message_analyzed: { data: unknown };
attachment_uploaded: Record<string, never>;
user_state: { users: unknown[] };
ui_state: { state: unknown };
media_state: { state: unknown };
voice_recording_uploaded: { data: unknown };
}
export type WsEventType = keyof WsEventMap;
export function parseWsMessage(raw: string): { type: WsEventType; payload: Record<string, unknown> } | null {
try {
const parsed = JSON.parse(raw);
if (!parsed.type) return null;
const { type, ...rest } = parsed;
return { type: type as WsEventType, payload: rest };
} catch {
return null;
}
}