mirror of
https://github.com/jamiepine/voicebox.git
synced 2026-09-15 12:50:42 -07:00
Generations now return immediately with a 'generating' status and appear
in history right away. TTS runs in a serial background queue to avoid
GPU contention. Users can kick off multiple generations without blocking.
- Async POST /generate creates DB record immediately, queues TTS work
- Serial generation queue prevents concurrent GPU access (Metal/CUDA/CPU)
- SSE endpoint GET /generate/{id}/status for real-time completion tracking
- Retry endpoint POST /generate/{id}/retry for failed generations
- Store engine and model_size on generation records for retry support
- History cards show animated loader (react-loaders) for generating/playing
- Failed generations show retry button instead of actions menu
- Model downloads happen inline in the queue instead of rejecting with 202
- Stale 'generating' records marked as failed on server startup
- Autoplay on generate setting (default: on)
- Show engine name on generation cards
- Remove sidebar generation spinner
- Checkbox alignment fix in settings
174 lines
3.9 KiB
CSS
174 lines
3.9 KiB
CSS
@import "tailwindcss" source(".");
|
|
@import "loaders.css/loaders.min.css";
|
|
|
|
@theme {
|
|
--radius-sm: calc(var(--radius) - 4px);
|
|
--radius-md: calc(var(--radius) - 2px);
|
|
--radius-lg: var(--radius);
|
|
|
|
--color-background: hsl(var(--background));
|
|
--color-foreground: hsl(var(--foreground));
|
|
|
|
--color-card: hsl(var(--card));
|
|
--color-card-foreground: hsl(var(--card-foreground));
|
|
|
|
--color-popover: hsl(var(--popover));
|
|
--color-popover-foreground: hsl(var(--popover-foreground));
|
|
|
|
--color-primary: hsl(var(--primary));
|
|
--color-primary-foreground: hsl(var(--primary-foreground));
|
|
|
|
--color-secondary: hsl(var(--secondary));
|
|
--color-secondary-foreground: hsl(var(--secondary-foreground));
|
|
|
|
--color-muted: hsl(var(--muted));
|
|
--color-muted-foreground: hsl(var(--muted-foreground));
|
|
|
|
--color-accent: hsl(var(--accent));
|
|
--color-accent-foreground: hsl(var(--accent-foreground));
|
|
|
|
--color-destructive: hsl(var(--destructive));
|
|
--color-destructive-foreground: hsl(var(--destructive-foreground));
|
|
|
|
--color-border: hsl(var(--border));
|
|
--color-input: hsl(var(--input));
|
|
--color-ring: hsl(var(--ring));
|
|
--color-sidebar: hsl(var(--sidebar));
|
|
|
|
--color-chart-1: hsl(var(--chart-1));
|
|
--color-chart-2: hsl(var(--chart-2));
|
|
--color-chart-3: hsl(var(--chart-3));
|
|
--color-chart-4: hsl(var(--chart-4));
|
|
--color-chart-5: hsl(var(--chart-5));
|
|
}
|
|
|
|
:root {
|
|
--background: 0 0% 95%;
|
|
--foreground: 222.2 84% 4.9%;
|
|
--card: 0 0% 97%;
|
|
--card-foreground: 222.2 84% 4.9%;
|
|
--popover: 0 0% 97%;
|
|
--popover-foreground: 222.2 84% 4.9%;
|
|
--primary: 222.2 47.4% 11.2%;
|
|
--primary-foreground: 210 40% 98%;
|
|
--secondary: 210 40% 92%;
|
|
--secondary-foreground: 222.2 47.4% 11.2%;
|
|
--muted: 210 40% 90%;
|
|
--muted-foreground: 215.4 16.3% 46.9%;
|
|
--accent: 43 50% 50%;
|
|
--accent-foreground: 222.2 47.4% 11.2%;
|
|
--destructive: 0 84.2% 60.2%;
|
|
--destructive-foreground: 210 40% 98%;
|
|
--border: 214.3 31.8% 85%;
|
|
--input: 214.3 31.8% 88%;
|
|
--ring: 222.2 84% 4.9%;
|
|
--sidebar: 0 0% 92%;
|
|
--radius: 0.5rem;
|
|
--chart-1: 12 76% 61%;
|
|
--chart-2: 173 58% 39%;
|
|
--chart-3: 197 37% 24%;
|
|
--chart-4: 43 74% 66%;
|
|
--chart-5: 27 87% 67%;
|
|
}
|
|
|
|
.dark {
|
|
--background: 0 0% 6%;
|
|
--foreground: 0 0% 95%;
|
|
--card: 0 0% 8%;
|
|
--card-foreground: 0 0% 95%;
|
|
--popover: 0 0% 8%;
|
|
--popover-foreground: 0 0% 95%;
|
|
--primary: 0 0% 18%;
|
|
--primary-foreground: 0 0% 95%;
|
|
--secondary: 0 0% 12%;
|
|
--secondary-foreground: 0 0% 95%;
|
|
--muted: 0 0% 12%;
|
|
--muted-foreground: 0 0% 60%;
|
|
--accent: 43 50% 45%;
|
|
--accent-foreground: 0 0% 95%;
|
|
--destructive: 0 62.8% 50%;
|
|
--destructive-foreground: 0 0% 95%;
|
|
--border: 0 0% 12%;
|
|
--input: 0 0% 12%;
|
|
--ring: 0 0% 40%;
|
|
--sidebar: 0 0% 4%;
|
|
--chart-1: 220 70% 50%;
|
|
--chart-2: 160 60% 45%;
|
|
--chart-3: 30 80% 55%;
|
|
--chart-4: 280 65% 60%;
|
|
--chart-5: 340 75% 55%;
|
|
}
|
|
|
|
@layer base {
|
|
* {
|
|
@apply border-border;
|
|
}
|
|
html,
|
|
body {
|
|
@apply overflow-hidden;
|
|
}
|
|
body {
|
|
@apply bg-background text-foreground;
|
|
}
|
|
/* Hide scrollbars globally */
|
|
* {
|
|
scrollbar-width: none; /* Firefox */
|
|
-ms-overflow-style: none; /* IE and Edge */
|
|
}
|
|
*::-webkit-scrollbar {
|
|
display: none; /* Chrome, Safari, Opera */
|
|
}
|
|
}
|
|
|
|
@layer utilities {
|
|
.writing-vertical {
|
|
writing-mode: vertical-rl;
|
|
text-orientation: mixed;
|
|
letter-spacing: 0.1em;
|
|
}
|
|
}
|
|
|
|
@keyframes fadeInScale {
|
|
from {
|
|
opacity: 0;
|
|
transform: scale(0.8);
|
|
}
|
|
to {
|
|
opacity: 1;
|
|
transform: scale(1);
|
|
}
|
|
}
|
|
|
|
@keyframes fadeIn {
|
|
from {
|
|
opacity: 0;
|
|
}
|
|
to {
|
|
opacity: 1;
|
|
}
|
|
}
|
|
|
|
.animate-fade-in-scale {
|
|
animation: fadeInScale 0.5s ease-out forwards;
|
|
}
|
|
|
|
.animate-fade-in-delayed {
|
|
animation: fadeIn 0.5s ease-out 0.15s forwards;
|
|
opacity: 0;
|
|
}
|
|
|
|
/* react-loaders */
|
|
.line-scale-pulse-out-rapid > div,
|
|
.line-scale > div {
|
|
background-color: hsl(var(--accent)) !important;
|
|
}
|
|
|
|
.loader-hidden {
|
|
display: block;
|
|
}
|
|
|
|
.loader-hidden > div > div {
|
|
animation-play-state: paused !important;
|
|
background-color: hsl(var(--muted-foreground)) !important;
|
|
}
|