Implement story management features and update dependencies

- Introduced story management functionality, including creating, listing, and managing story items.
- Added new components for story display and interaction, including StoriesTab, StoryList, and StoryContent.
- Integrated drag-and-drop functionality for reordering story items using @dnd-kit.
- Updated dependencies for @dnd-kit packages to enhance drag-and-drop capabilities.
- Bumped version for @voicebox/app, @voicebox/landing, @voicebox/tauri, and @voicebox/web to 0.1.5.
- Enhanced audio playback features to support story mode with auto-play functionality.
- Improved error handling and user feedback through toast notifications in story-related actions.
This commit is contained in:
Jamie Pine
2026-01-28 19:10:58 -08:00
parent 9d5d6cb56a
commit 3204e193fa
22 changed files with 2396 additions and 29 deletions
+77
View File
@@ -13,6 +13,13 @@ import type {
ModelStatusListResponse,
ModelDownloadRequest,
ActiveTasksResponse,
StoryCreate,
StoryResponse,
StoryDetailResponse,
StoryItemCreate,
StoryItemDetail,
StoryItemBatchUpdate,
StoryItemReorder,
} from './types';
class ApiClient {
@@ -361,6 +368,76 @@ class ApiClient {
body: JSON.stringify({ channel_ids: channelIds }),
});
}
// Stories
async listStories(): Promise<StoryResponse[]> {
return this.request<StoryResponse[]>('/stories');
}
async createStory(data: StoryCreate): Promise<StoryResponse> {
return this.request<StoryResponse>('/stories', {
method: 'POST',
body: JSON.stringify(data),
});
}
async getStory(storyId: string): Promise<StoryDetailResponse> {
return this.request<StoryDetailResponse>(`/stories/${storyId}`);
}
async updateStory(storyId: string, data: StoryCreate): Promise<StoryResponse> {
return this.request<StoryResponse>(`/stories/${storyId}`, {
method: 'PUT',
body: JSON.stringify(data),
});
}
async deleteStory(storyId: string): Promise<void> {
await this.request<void>(`/stories/${storyId}`, {
method: 'DELETE',
});
}
async addStoryItem(storyId: string, data: StoryItemCreate): Promise<StoryItemDetail> {
return this.request<StoryItemDetail>(`/stories/${storyId}/items`, {
method: 'POST',
body: JSON.stringify(data),
});
}
async removeStoryItem(storyId: string, generationId: string): Promise<void> {
await this.request<void>(`/stories/${storyId}/items/${generationId}`, {
method: 'DELETE',
});
}
async updateStoryItemTimes(storyId: string, data: StoryItemBatchUpdate): Promise<void> {
await this.request<void>(`/stories/${storyId}/items/times`, {
method: 'PUT',
body: JSON.stringify(data),
});
}
async reorderStoryItems(storyId: string, data: StoryItemReorder): Promise<StoryItemDetail[]> {
return this.request<StoryItemDetail[]>(`/stories/${storyId}/items/reorder`, {
method: 'PUT',
body: JSON.stringify(data),
});
}
async exportStoryAudio(storyId: string): Promise<Blob> {
const url = `${this.getBaseUrl()}/stories/${storyId}/export-audio`;
const response = await fetch(url);
if (!response.ok) {
const error = await response.json().catch(() => ({
detail: response.statusText,
}));
throw new Error(error.detail || `HTTP error! status: ${response.status}`);
}
return response.blob();
}
}
export const apiClient = new ApiClient();