Add cancel, history, revert, and quality-of-life features
UX - Add elapsed-time counter and Cancel button to in-flight generations, wired through AbortController so partial responses are discarded cleanly. The cancel action is available from both the input panel and the results header. - Add a Recent generations panel below the input. The last 6 successful generations are saved to localStorage; one click reloads both the input fields and the generated assets. - Add a Revert button to every editable card. It appears the moment the current value diverges from the last generated value and restores the field with a single click. - Add an Empty state to the right panel with a friendly hint pointing at the Generate button and the Settings page. - Add a 'Try an example' button that fills the input with a random starter idea (idea + mood + vocals). - Add Cmd/Ctrl+Enter as a keyboard shortcut to generate. - Add a Footer with project info and a privacy reminder. - Add a 'Clear saved key' button to the Settings page so the user can remove the API key without overwriting it. Bug fix - Settings > Test Connection used to save the in-progress form values to localStorage before testing. It now uses the in-memory candidate config, so failed tests don't pollute the saved config. Code quality - Extract the duplicated useAutoHeight hook to src/lib/useAutoHeight.ts. - Extract a useElapsed hook for the loading timer. - Move InputValues into src/lib/types.ts (was duplicated in InputPanel.tsx) and add SECTION_LABELS, replacing the humanizeSection switch in HomePage. - Centralize the filename sanitization: HomePage now calls sanitizeFilename from zip.ts instead of duplicating the regex. - Add previewConfig / testConnectionWithConfig helpers to llm.ts to support in-memory connection tests.
This commit is contained in:
+38
-25
@@ -1,27 +1,27 @@
|
||||
// Domain types shared across the app. These mirror the JSON shape produced by
|
||||
// the `generate-song` edge function.
|
||||
// the LLM module.
|
||||
|
||||
export type Language =
|
||||
| 'English'
|
||||
| 'Deutsch'
|
||||
| 'Español'
|
||||
| 'Français'
|
||||
| 'Italiano'
|
||||
| 'Português'
|
||||
| 'Polski'
|
||||
| 'Other';
|
||||
| "English"
|
||||
| "Deutsch"
|
||||
| "Español"
|
||||
| "Français"
|
||||
| "Italiano"
|
||||
| "Português"
|
||||
| "Polski"
|
||||
| "Other";
|
||||
|
||||
export type Vocals = 'vocals' | 'instrumental';
|
||||
export type Vocals = "vocals" | "instrumental";
|
||||
|
||||
export type GenerationSection =
|
||||
| 'all'
|
||||
| 'lyrics'
|
||||
| 'style'
|
||||
| 'titles'
|
||||
| 'video_prompts'
|
||||
| 'youtube_description';
|
||||
| "all"
|
||||
| "lyrics"
|
||||
| "style"
|
||||
| "titles"
|
||||
| "video_prompts"
|
||||
| "youtube_description";
|
||||
|
||||
export type VideoPromptType = 'Abstract' | 'Cinematic' | 'Hybrid';
|
||||
export type VideoPromptType = "Abstract" | "Cinematic" | "Hybrid";
|
||||
|
||||
export interface VideoPrompt {
|
||||
type: VideoPromptType;
|
||||
@@ -40,7 +40,7 @@ export interface SongAssets {
|
||||
|
||||
export interface GenerateRequest {
|
||||
input: string;
|
||||
language: string; // 'English' or free-text from "Other"
|
||||
language: string; // 'English' or free-text from "Other"
|
||||
mood?: string;
|
||||
vocals: Vocals;
|
||||
section: GenerationSection;
|
||||
@@ -53,16 +53,29 @@ export interface ConfigDisplay {
|
||||
api_key_set: boolean;
|
||||
}
|
||||
|
||||
export interface SaveConfigPayload {
|
||||
api_endpoint: string;
|
||||
api_key: string; // empty string => keep existing
|
||||
model_name: string;
|
||||
}
|
||||
|
||||
export interface TestConnectionResult {
|
||||
success: boolean;
|
||||
message: string;
|
||||
}
|
||||
|
||||
export interface InputValues {
|
||||
idea: string;
|
||||
language: Language | string;
|
||||
customLanguage: string;
|
||||
mood: string;
|
||||
vocals: Vocals;
|
||||
}
|
||||
|
||||
export const NEGATIVE_VIDEO_PROMPT =
|
||||
'text, watermark, logo, flash, abrupt cuts, camera shake, faces, hands, distortion, blur';
|
||||
"text, watermark, logo, flash, abrupt cuts, camera shake, faces, hands, distortion, blur";
|
||||
|
||||
// Human-readable labels for each regenerable section — used by toasts and the
|
||||
// history panel. Keep in sync with `GenerationSection`.
|
||||
export const SECTION_LABELS: Record<GenerationSection, string> = {
|
||||
all: "everything",
|
||||
titles: "titles",
|
||||
lyrics: "lyrics",
|
||||
style: "style",
|
||||
video_prompts: "video prompts",
|
||||
youtube_description: "description",
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user