feat(ui): replace sidebar with compact top header navigation
- Rewrite MainLayout from vertical sidebar to horizontal header bar - Brand left, nav tabs center, status indicator right - Simplify StatusBar to single inline layout (remove collapsed variant) - Widen content area from max-w-4xl to max-w-6xl - Remove sidebar-collapsed localStorage persistence
This commit is contained in:
1 parent
0753bbdce6
commit
7d2977b665
3 files changed
+94
-253
No files matched your search
@@ -3,15 +3,9 @@ import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { isProcessRunning, startGeminiNexus, closeGeminiNexus } from '@/actions/process';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { Play, Square, Loader2, Power } from 'lucide-react';
|
||||
import { Play, Square, Loader2 } from 'lucide-react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip';
|
||||
|
||||
interface StatusBarProps {
|
||||
isCollapsed?: boolean;
|
||||
}
|
||||
|
||||
export const StatusBar: React.FC<StatusBarProps> = ({ isCollapsed = false }) => {
|
||||
export const StatusBar: React.FC = () => {
|
||||
const { t } = useTranslation();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
@@ -44,112 +38,48 @@ export const StatusBar: React.FC<StatusBarProps> = ({ isCollapsed = false }) =>
|
||||
};
|
||||
|
||||
const isPending = startMutation.isPending || stopMutation.isPending;
|
||||
|
||||
// Collapsed View
|
||||
if (isCollapsed) {
|
||||
return (
|
||||
<div className="flex justify-center py-2">
|
||||
<TooltipProvider>
|
||||
<Tooltip delayDuration={0}>
|
||||
<TooltipTrigger asChild>
|
||||
<button
|
||||
onClick={handleToggle}
|
||||
disabled={isLoading || isPending}
|
||||
className={cn(
|
||||
'flex h-8 w-8 items-center justify-center rounded-lg transition-all duration-200',
|
||||
'disabled:opacity-50 disabled:cursor-not-allowed',
|
||||
isRunning
|
||||
? 'bg-emerald-500/10 text-emerald-400 hover:bg-emerald-500/20'
|
||||
: 'bg-white/[0.04] text-muted-foreground hover:bg-white/[0.08] hover:text-foreground',
|
||||
)}
|
||||
>
|
||||
{isPending ? (
|
||||
<Loader2 className="h-4 w-4 animate-spin" />
|
||||
) : (
|
||||
<Power className="h-4 w-4" />
|
||||
)}
|
||||
</button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="right" className="flex items-center gap-2 text-xs">
|
||||
<div
|
||||
className={cn(
|
||||
'h-1.5 w-1.5 rounded-full',
|
||||
isRunning ? 'bg-emerald-400' : 'bg-muted-foreground',
|
||||
)}
|
||||
/>
|
||||
<span>
|
||||
{isLoading
|
||||
? t('status.checking')
|
||||
: isRunning
|
||||
? t('status.running')
|
||||
: t('status.stopped')}
|
||||
</span>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// Expanded View
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
'flex items-center justify-between rounded-lg px-3 py-2 transition-all duration-200',
|
||||
isRunning
|
||||
? 'bg-emerald-500/[0.08]'
|
||||
: 'bg-white/[0.02]',
|
||||
<div className="flex items-center gap-2 rounded-md border border-white/[0.06] bg-white/[0.02] px-3 py-2">
|
||||
{isLoading ? (
|
||||
<Loader2 className="text-muted-foreground h-3 w-3 animate-spin" />
|
||||
) : (
|
||||
<div
|
||||
className={cn(
|
||||
'h-2 w-2 rounded-full',
|
||||
isRunning
|
||||
? 'bg-emerald-400 shadow-[0_0_6px_rgba(16,185,129,0.4)]'
|
||||
: 'bg-muted-foreground/50',
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
>
|
||||
<div className="flex items-center gap-2.5">
|
||||
{isLoading ? (
|
||||
<Loader2 className="h-3 w-3 shrink-0 animate-spin text-muted-foreground" />
|
||||
) : (
|
||||
<div
|
||||
className={cn(
|
||||
'h-2 w-2 shrink-0 rounded-full transition-colors duration-300',
|
||||
isRunning
|
||||
? 'bg-emerald-400 shadow-[0_0_6px_rgba(16,185,129,0.4)]'
|
||||
: 'bg-muted-foreground/50',
|
||||
)}
|
||||
/>
|
||||
<span
|
||||
className={cn(
|
||||
'text-xs font-medium',
|
||||
isRunning ? 'text-emerald-400' : 'text-muted-foreground',
|
||||
)}
|
||||
<div className="flex flex-col">
|
||||
<span className="text-[11px] font-medium uppercase tracking-wider text-muted-foreground">
|
||||
Status
|
||||
</span>
|
||||
<span className={cn(
|
||||
'text-xs font-medium leading-tight',
|
||||
isRunning ? 'text-emerald-400' : 'text-muted-foreground',
|
||||
)}>
|
||||
{isLoading
|
||||
? t('status.checking')
|
||||
: isRunning
|
||||
? t('status.running')
|
||||
: t('status.stopped')}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
>
|
||||
{isLoading ? '...' : isRunning ? 'Running' : 'Stopped'}
|
||||
</span>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={handleToggle}
|
||||
disabled={isLoading || isPending}
|
||||
className={cn(
|
||||
'h-7 gap-1.5 rounded-md px-2.5 text-xs',
|
||||
'h-7 w-7 rounded-md p-0',
|
||||
isRunning
|
||||
? 'text-emerald-400 hover:bg-emerald-500/10'
|
||||
: 'text-muted-foreground hover:bg-white/[0.06]',
|
||||
)}
|
||||
>
|
||||
{isPending ? (
|
||||
<Loader2 className="h-3 w-3 animate-spin" />
|
||||
<Loader2 className="h-3.5 w-3.5 animate-spin" />
|
||||
) : isRunning ? (
|
||||
<Square className="h-3 w-3 fill-current" />
|
||||
<Square className="h-3.5 w-3.5 fill-current" />
|
||||
) : (
|
||||
<Play className="h-3 w-3 fill-current" />
|
||||
<Play className="h-3.5 w-3.5 fill-current" />
|
||||
)}
|
||||
<span>{isRunning ? t('action.stop') : t('action.start')}</span>
|
||||
<span className="sr-only">{isRunning ? t('action.stop') : t('action.start')}</span>
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in new issue
Block a user