feat: migrate and redesign dashboard to modern React
- Full rewrite of legacy vanilla JS UI into React SPA - Implement modern design system using Tailwind CSS and shadcn/ui primitives - Create typed API modules and hooks for voice, media, and moderation - Add new features: separated Music and Screen Share panels, Image Grid - Implement unified WebSocket hook for real-time state and PCM audio - Improve visualizer with smooth CSS transitions and live state sync - Add __dirname polyfill for ES module compatibility - Ensure responsive layout for mobile and desktop Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -49,7 +49,7 @@ class ApiError extends Error {
|
||||
}
|
||||
}
|
||||
|
||||
async function request<T>(path: string, init?: RequestInit): Promise<T> {
|
||||
export async function request<T>(path: string, init?: RequestInit): Promise<T> {
|
||||
const res = await fetch(path, {
|
||||
headers: { "Content-Type": "application/json" },
|
||||
...init,
|
||||
|
||||
21
frontend/src/api/media.ts
Normal file
21
frontend/src/api/media.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { request } from "./client";
|
||||
import type { MediaMode, MediaState } from "../types/media";
|
||||
|
||||
export function getMediaStatus(): Promise<MediaState> {
|
||||
return request<MediaState>('/api/media/status');
|
||||
}
|
||||
|
||||
export function queueMedia(source: string, mode: MediaMode): Promise<MediaState> {
|
||||
return request<MediaState>('/api/media/queue', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ source, mode }),
|
||||
});
|
||||
}
|
||||
|
||||
export function skipMedia(): Promise<MediaState> {
|
||||
return request<MediaState>('/api/media/skip', { method: 'POST' });
|
||||
}
|
||||
|
||||
export function stopMedia(): Promise<MediaState> {
|
||||
return request<MediaState>('/api/media/stop', { method: 'POST' });
|
||||
}
|
||||
3
frontend/src/api/messages.ts
Normal file
3
frontend/src/api/messages.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
import { listMessages, listReview, reanalyzeMessage } from "./client";
|
||||
|
||||
export { listMessages, listReview, reanalyzeMessage };
|
||||
13
frontend/src/api/uiState.ts
Normal file
13
frontend/src/api/uiState.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { request } from "./client";
|
||||
import type { UIState } from "../types/ui";
|
||||
|
||||
export function getUIState(): Promise<UIState> {
|
||||
return request<UIState>('/api/ui-state');
|
||||
}
|
||||
|
||||
export function updateUIState(patch: Partial<UIState>): Promise<UIState> {
|
||||
return request<UIState>('/api/ui-state', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(patch),
|
||||
});
|
||||
}
|
||||
33
frontend/src/api/voice.ts
Normal file
33
frontend/src/api/voice.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import { request } from "./client";
|
||||
import type { Channel, Guild, VoiceStatus } from "../types/voice";
|
||||
|
||||
export function getGuilds(): Promise<Guild[]> {
|
||||
return request<Guild[]>('/api/guilds');
|
||||
}
|
||||
|
||||
export function getVoiceChannels(guildId: string): Promise<Channel[]> {
|
||||
return request<Channel[]>(`/api/guilds/${guildId}/voice-channels`);
|
||||
}
|
||||
|
||||
export function getTextChannels(guildId: string): Promise<Channel[]> {
|
||||
return request<Channel[]>(`/api/guilds/${guildId}/channels`);
|
||||
}
|
||||
|
||||
export function getThreads(guildId: string): Promise<Channel[]> {
|
||||
return request<Channel[]>(`/api/guilds/${guildId}/threads`);
|
||||
}
|
||||
|
||||
export function getVoiceStatus(): Promise<VoiceStatus> {
|
||||
return request<VoiceStatus>('/api/status');
|
||||
}
|
||||
|
||||
export function connectVoice(guildId: string, channelId: string): Promise<VoiceStatus> {
|
||||
return request<VoiceStatus>('/api/connect', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ guildId, channelId }),
|
||||
});
|
||||
}
|
||||
|
||||
export function disconnectVoice(): Promise<VoiceStatus> {
|
||||
return request<VoiceStatus>('/api/disconnect', { method: 'POST' });
|
||||
}
|
||||
Reference in New Issue
Block a user