mirror of
https://github.com/jamiepine/voicebox.git
synced 2026-09-18 22:30:40 -07:00
Update app version to 0.1.4 and integrate @tanstack/react-router for improved routing functionality
- Bumped version for @voicebox/app, @voicebox/landing, @voicebox/tauri, and @voicebox/web to 0.1.4. - Added @tanstack/react-router dependency for enhanced routing capabilities. - Refactored App component to utilize RouterProvider for routing management. - Created a new router configuration in router.tsx to define application routes and layout. - Updated Sidebar component to use Link from @tanstack/react-router for navigation.
This commit is contained in:
+3
-67
@@ -1,27 +1,17 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { RouterProvider } from '@tanstack/react-router';
|
||||
import voiceboxLogo from '@/assets/voicebox-logo.png';
|
||||
import { AppFrame } from '@/components/AppFrame/AppFrame';
|
||||
import { AudioTab } from '@/components/AudioTab/AudioTab';
|
||||
import { MainEditor } from '@/components/MainEditor/MainEditor';
|
||||
import { ModelsTab } from '@/components/ModelsTab/ModelsTab';
|
||||
import { ServerTab } from '@/components/ServerTab/ServerTab';
|
||||
// import { GenerationForm } from '@/components/Generation/GenerationForm';
|
||||
import ShinyText from '@/components/ShinyText';
|
||||
import { Sidebar } from '@/components/Sidebar';
|
||||
import { TitleBarDragRegion } from '@/components/TitleBarDragRegion';
|
||||
import { Toaster } from '@/components/ui/toaster';
|
||||
import { VoicesTab } from '@/components/VoicesTab/VoicesTab';
|
||||
import { TOP_SAFE_AREA_PADDING } from '@/lib/constants/ui';
|
||||
import { useModelDownloadToast } from '@/lib/hooks/useModelDownloadToast';
|
||||
import { MODEL_DISPLAY_NAMES, useRestoreActiveTasks } from '@/lib/hooks/useRestoreActiveTasks';
|
||||
import {
|
||||
isMacOS,
|
||||
isTauri,
|
||||
setKeepServerRunning,
|
||||
setupWindowCloseHandler,
|
||||
startServer,
|
||||
} from '@/lib/tauri';
|
||||
import { cn } from '@/lib/utils/cn';
|
||||
import { router } from '@/router';
|
||||
import { useServerStore } from '@/stores/serverStore';
|
||||
|
||||
// Track if server is starting to prevent duplicate starts
|
||||
@@ -51,13 +41,9 @@ const LOADING_MESSAGES = [
|
||||
];
|
||||
|
||||
function App() {
|
||||
const [activeTab, setActiveTab] = useState('main');
|
||||
const [serverReady, setServerReady] = useState(false);
|
||||
const [loadingMessageIndex, setLoadingMessageIndex] = useState(0);
|
||||
|
||||
// Monitor active downloads/generations and show toasts for them
|
||||
const activeDownloads = useRestoreActiveTasks();
|
||||
|
||||
// Sync stored setting to Rust on startup
|
||||
useEffect(() => {
|
||||
if (isTauri()) {
|
||||
@@ -172,57 +158,7 @@ function App() {
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<AppFrame>
|
||||
<div className="flex flex-1 min-h-0 overflow-hidden">
|
||||
<Sidebar activeTab={activeTab} onTabChange={setActiveTab} isMacOS={isMacOS()} />
|
||||
|
||||
<main className="flex-1 ml-20 overflow-hidden flex flex-col">
|
||||
<div className="container mx-auto px-8 max-w-[1800px] h-full overflow-hidden flex flex-col">
|
||||
{activeTab === 'main' && <MainEditor />}
|
||||
{activeTab === 'voices' && <VoicesTab />}
|
||||
{activeTab === 'audio' && <AudioTab />}
|
||||
{activeTab === 'server' && <ServerTab />}
|
||||
{activeTab === 'models' && <ModelsTab />}
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
{/* Show download toasts for any active downloads (from anywhere) */}
|
||||
{activeDownloads.map((download) => {
|
||||
const displayName = MODEL_DISPLAY_NAMES[download.model_name] || download.model_name;
|
||||
return (
|
||||
<DownloadToastRestorer
|
||||
key={download.model_name}
|
||||
modelName={download.model_name}
|
||||
displayName={displayName}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
|
||||
<Toaster />
|
||||
</AppFrame>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Component that restores a download toast for a specific model.
|
||||
*/
|
||||
function DownloadToastRestorer({
|
||||
modelName,
|
||||
displayName,
|
||||
}: {
|
||||
modelName: string;
|
||||
displayName: string;
|
||||
}) {
|
||||
// Use the download toast hook to restore the toast
|
||||
useModelDownloadToast({
|
||||
modelName,
|
||||
displayName,
|
||||
enabled: true,
|
||||
});
|
||||
|
||||
return null;
|
||||
return <RouterProvider router={router} />;
|
||||
}
|
||||
|
||||
export default App;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { Link, useMatchRoute } from '@tanstack/react-router';
|
||||
import { Box, Loader2, Mic, Server, Speaker, Volume2 } from 'lucide-react';
|
||||
import voiceboxLogo from '@/assets/voicebox-logo.png';
|
||||
import { cn } from '@/lib/utils/cn';
|
||||
@@ -5,23 +6,22 @@ import { useGenerationStore } from '@/stores/generationStore';
|
||||
import { usePlayerStore } from '@/stores/playerStore';
|
||||
|
||||
interface SidebarProps {
|
||||
activeTab: string;
|
||||
onTabChange: (tab: string) => void;
|
||||
isMacOS?: boolean;
|
||||
}
|
||||
|
||||
const tabs = [
|
||||
{ id: 'main', icon: Volume2, label: 'Generate' },
|
||||
{ id: 'voices', icon: Mic, label: 'Voices' },
|
||||
{ id: 'audio', icon: Speaker, label: 'Audio' },
|
||||
{ id: 'models', icon: Box, label: 'Models' },
|
||||
{ id: 'server', icon: Server, label: 'Server' },
|
||||
{ id: 'main', path: '/', icon: Volume2, label: 'Generate' },
|
||||
{ id: 'voices', path: '/voices', icon: Mic, label: 'Voices' },
|
||||
{ id: 'audio', path: '/audio', icon: Speaker, label: 'Audio' },
|
||||
{ id: 'models', path: '/models', icon: Box, label: 'Models' },
|
||||
{ id: 'server', path: '/server', icon: Server, label: 'Server' },
|
||||
];
|
||||
|
||||
export function Sidebar({ activeTab, onTabChange, isMacOS }: SidebarProps) {
|
||||
export function Sidebar({ isMacOS }: SidebarProps) {
|
||||
const isGenerating = useGenerationStore((state) => state.isGenerating);
|
||||
const audioUrl = usePlayerStore((state) => state.audioUrl);
|
||||
const isPlayerVisible = !!audioUrl;
|
||||
const matchRoute = useMatchRoute();
|
||||
|
||||
return (
|
||||
<div
|
||||
@@ -39,13 +39,16 @@ export function Sidebar({ activeTab, onTabChange, isMacOS }: SidebarProps) {
|
||||
<div className="flex flex-col gap-3">
|
||||
{tabs.map((tab) => {
|
||||
const Icon = tab.icon;
|
||||
const isActive = activeTab === tab.id;
|
||||
// For index route, use exact match; for others, use default matching
|
||||
const isActive =
|
||||
tab.path === '/'
|
||||
? matchRoute({ to: '/', exact: true })
|
||||
: matchRoute({ to: tab.path });
|
||||
|
||||
return (
|
||||
<button
|
||||
<Link
|
||||
key={tab.id}
|
||||
type="button"
|
||||
onClick={() => onTabChange(tab.id)}
|
||||
to={tab.path}
|
||||
className={cn(
|
||||
'w-12 h-12 rounded-full flex items-center justify-center transition-all duration-200',
|
||||
'hover:bg-muted/50',
|
||||
@@ -55,7 +58,7 @@ export function Sidebar({ activeTab, onTabChange, isMacOS }: SidebarProps) {
|
||||
aria-label={tab.label}
|
||||
>
|
||||
<Icon className="h-5 w-5" />
|
||||
</button>
|
||||
</Link>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
import { createRootRoute, createRoute, createRouter, Outlet } from '@tanstack/react-router';
|
||||
import { AppFrame } from '@/components/AppFrame/AppFrame';
|
||||
import { AudioTab } from '@/components/AudioTab/AudioTab';
|
||||
import { MainEditor } from '@/components/MainEditor/MainEditor';
|
||||
import { ModelsTab } from '@/components/ModelsTab/ModelsTab';
|
||||
import { ServerTab } from '@/components/ServerTab/ServerTab';
|
||||
import { Sidebar } from '@/components/Sidebar';
|
||||
import { Toaster } from '@/components/ui/toaster';
|
||||
import { VoicesTab } from '@/components/VoicesTab/VoicesTab';
|
||||
import { useModelDownloadToast } from '@/lib/hooks/useModelDownloadToast';
|
||||
import { MODEL_DISPLAY_NAMES, useRestoreActiveTasks } from '@/lib/hooks/useRestoreActiveTasks';
|
||||
import { isMacOS } from '@/lib/tauri';
|
||||
|
||||
// Root layout component
|
||||
function RootLayout() {
|
||||
// Monitor active downloads/generations and show toasts for them
|
||||
const activeDownloads = useRestoreActiveTasks();
|
||||
|
||||
return (
|
||||
<AppFrame>
|
||||
<div className="flex flex-1 min-h-0 overflow-hidden">
|
||||
<Sidebar isMacOS={isMacOS()} />
|
||||
|
||||
<main className="flex-1 ml-20 overflow-hidden flex flex-col">
|
||||
<div className="container mx-auto px-8 max-w-[1800px] h-full overflow-hidden flex flex-col">
|
||||
<Outlet />
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
{/* Show download toasts for any active downloads (from anywhere) */}
|
||||
{activeDownloads.map((download) => {
|
||||
const displayName = MODEL_DISPLAY_NAMES[download.model_name] || download.model_name;
|
||||
return (
|
||||
<DownloadToastRestorer
|
||||
key={download.model_name}
|
||||
modelName={download.model_name}
|
||||
displayName={displayName}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
|
||||
<Toaster />
|
||||
</AppFrame>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Component that restores a download toast for a specific model.
|
||||
*/
|
||||
function DownloadToastRestorer({
|
||||
modelName,
|
||||
displayName,
|
||||
}: {
|
||||
modelName: string;
|
||||
displayName: string;
|
||||
}) {
|
||||
// Use the download toast hook to restore the toast
|
||||
useModelDownloadToast({
|
||||
modelName,
|
||||
displayName,
|
||||
enabled: true,
|
||||
});
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// Root route with layout
|
||||
const rootRoute = createRootRoute({
|
||||
component: RootLayout,
|
||||
});
|
||||
|
||||
// Index route (main/generate)
|
||||
const indexRoute = createRoute({
|
||||
getParentRoute: () => rootRoute,
|
||||
path: '/',
|
||||
component: MainEditor,
|
||||
});
|
||||
|
||||
// Voices route
|
||||
const voicesRoute = createRoute({
|
||||
getParentRoute: () => rootRoute,
|
||||
path: '/voices',
|
||||
component: VoicesTab,
|
||||
});
|
||||
|
||||
// Audio route
|
||||
const audioRoute = createRoute({
|
||||
getParentRoute: () => rootRoute,
|
||||
path: '/audio',
|
||||
component: AudioTab,
|
||||
});
|
||||
|
||||
// Models route
|
||||
const modelsRoute = createRoute({
|
||||
getParentRoute: () => rootRoute,
|
||||
path: '/models',
|
||||
component: ModelsTab,
|
||||
});
|
||||
|
||||
// Server route
|
||||
const serverRoute = createRoute({
|
||||
getParentRoute: () => rootRoute,
|
||||
path: '/server',
|
||||
component: ServerTab,
|
||||
});
|
||||
|
||||
// Route tree
|
||||
const routeTree = rootRoute.addChildren([
|
||||
indexRoute,
|
||||
voicesRoute,
|
||||
audioRoute,
|
||||
modelsRoute,
|
||||
serverRoute,
|
||||
]);
|
||||
|
||||
// Create router
|
||||
export const router = createRouter({ routeTree });
|
||||
|
||||
// Register router for type safety
|
||||
declare module '@tanstack/react-router' {
|
||||
interface Register {
|
||||
router: typeof router;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user