Skip to content

Commit 1a236f4

Browse files
authored
Feat/provider: add provider create and edit router & adjust some styles (#122)
* feat: 添加提供商创建和编辑页面,优化导航项和流计数显示 * feat: 添加 MarqueeBackground 组件并在多个地方应用,优化背景动画显示 * feat: 重构提供商创建流程,添加自定义配置步骤和导航功能 * feat: 添加 AnimatedNavItem 组件并重构客户端和请求导航项 * feat: 优化布局组件,调整样式和结构,增强响应式设计 * feat: 更新 AntigravityTokenImport 组件样式,增强视觉效果和响应式设计 * refactor: standardize import statements and improve code formatting across multiple components - Updated import statements to use consistent single quotes. - Reformatted code for better readability, including consistent spacing and line breaks. - Enhanced the structure of function parameters for clarity. - Improved the handling of conditional rendering and state management in provider components. - Cleaned up comments and ensured they are relevant and concise. * feat: 更新 ProviderRowContent 组件样式,增强拖拽交互体验
1 parent e80a703 commit 1a236f4

27 files changed

+581
-453
lines changed

web/src/components/layout/app-layout.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,14 @@ export function AppLayout() {
1313
const timeoutSeconds = parseInt(settings?.force_project_timeout || '30', 10);
1414

1515
return (
16-
<SidebarProvider>
16+
<SidebarProvider className="h-svh! min-h-0! overflow-hidden">
1717
<AppSidebar />
18-
<SidebarInset>
18+
<SidebarInset className="flex flex-col">
1919
{/* Mobile header with sidebar trigger */}
20-
<header className="flex h-12 items-center gap-2 border-b px-4 md:hidden">
20+
<header className="flex h-12 shrink-0 items-center gap-2 border-b px-4 md:hidden">
2121
<SidebarTrigger />
2222
</header>
23-
<div className="@container/main h-full">
23+
<div className="@container/main flex-1 min-h-0 overflow-hidden">
2424
<Outlet />
2525
</div>
2626
</SidebarInset>
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import { NavLink, useLocation } from 'react-router-dom';
2+
import { StreamingBadge } from '@/components/ui/streaming-badge';
3+
import { MarqueeBackground } from '@/components/ui/marquee-background';
4+
import { SidebarMenuBadge, SidebarMenuButton, SidebarMenuItem } from '@/components/ui/sidebar';
5+
import { cn } from '@/lib/utils';
6+
import type { ReactNode } from 'react';
7+
8+
interface AnimatedNavItemProps {
9+
/** The route path to navigate to */
10+
to: string;
11+
/** Function to check if the route is active */
12+
isActive: (pathname: string) => boolean;
13+
/** Tooltip text */
14+
tooltip: string;
15+
/** Icon element */
16+
icon: ReactNode;
17+
/** Label text */
18+
label: string;
19+
/** Streaming count for badge */
20+
streamingCount: number;
21+
/** Color for marquee and badge */
22+
color: string;
23+
}
24+
25+
/**
26+
* Reusable navigation item with marquee background and streaming badge
27+
*/
28+
export function AnimatedNavItem({
29+
to,
30+
isActive: isActiveFn,
31+
tooltip,
32+
icon,
33+
label,
34+
streamingCount,
35+
color,
36+
}: AnimatedNavItemProps) {
37+
const location = useLocation();
38+
const isActive = isActiveFn(location.pathname);
39+
40+
return (
41+
<SidebarMenuItem>
42+
<SidebarMenuButton
43+
render={<NavLink to={to} />}
44+
isActive={isActive}
45+
tooltip={tooltip}
46+
className={cn(
47+
'relative overflow-hidden',
48+
isActive && 'bg-transparent! hover:bg-sidebar-accent/50!',
49+
)}
50+
>
51+
<MarqueeBackground show={streamingCount > 0} color={color} opacity={0.3} />
52+
<span className="relative z-10">{icon}</span>
53+
<span className="relative z-10">{label}</span>
54+
</SidebarMenuButton>
55+
<SidebarMenuBadge>
56+
<StreamingBadge count={streamingCount} color={color} />
57+
</SidebarMenuBadge>
58+
</SidebarMenuItem>
59+
);
60+
}

web/src/components/layout/app-sidebar/client-routes-items.tsx

Lines changed: 11 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,33 @@
1-
import { NavLink, useLocation } from 'react-router-dom';
21
import {
32
ClientIcon,
43
allClientTypes,
54
getClientName,
65
getClientColor,
76
} from '@/components/icons/client-icons';
8-
import { StreamingBadge } from '@/components/ui/streaming-badge';
9-
import { MarqueeBackground } from '@/components/ui/marquee-background';
107
import { useStreamingRequests } from '@/hooks/use-streaming';
118
import type { ClientType } from '@/lib/transport';
12-
import { SidebarMenuButton, SidebarMenuItem, SidebarMenuBadge } from '@/components/ui/sidebar';
9+
import { AnimatedNavItem } from './animated-nav-item';
1310

1411
function ClientNavItem({
1512
clientType,
16-
streamingCount
13+
streamingCount,
1714
}: {
1815
clientType: ClientType;
1916
streamingCount: number;
2017
}) {
21-
const location = useLocation();
2218
const color = getClientColor(clientType);
2319
const clientName = getClientName(clientType);
24-
const isActive = location.pathname === `/routes/${clientType}`;
2520

2621
return (
27-
<SidebarMenuItem>
28-
<SidebarMenuButton
29-
render={<NavLink to={`/routes/${clientType}`} />}
30-
isActive={isActive}
31-
tooltip={clientName}
32-
className="relative overflow-hidden"
33-
>
34-
<MarqueeBackground show={streamingCount > 0 && !isActive} color={color} opacity={0.5} />
35-
<ClientIcon type={clientType} size={18} className="relative z-10" />
36-
<span className="relative z-10">{clientName}</span>
37-
</SidebarMenuButton>
38-
<SidebarMenuBadge>
39-
<StreamingBadge count={streamingCount} color={color} />
40-
</SidebarMenuBadge>
41-
</SidebarMenuItem>
22+
<AnimatedNavItem
23+
to={`/routes/${clientType}`}
24+
isActive={(pathname) => pathname === `/routes/${clientType}`}
25+
tooltip={clientName}
26+
icon={<ClientIcon type={clientType} size={18} />}
27+
label={clientName}
28+
streamingCount={streamingCount}
29+
color={color}
30+
/>
4231
);
4332
}
4433

web/src/components/layout/app-sidebar/index.tsx

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ export function AppSidebar() {
1616
const versionDisplay = proxyStatus?.version ?? '...';
1717

1818
return (
19-
<Sidebar collapsible="icon">
19+
<Sidebar collapsible="icon" className="border-border">
2020
<SidebarHeader>
2121
<NavProxyStatus />
2222
</SidebarHeader>
@@ -37,6 +37,3 @@ export function AppSidebar() {
3737
</Sidebar>
3838
);
3939
}
40-
41-
// Alias for backwards compatibility
42-
export { AppSidebar as SidebarNav };
Lines changed: 10 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,25 @@
1-
import { NavLink, useLocation } from 'react-router-dom';
21
import { useTranslation } from 'react-i18next';
32
import { Activity } from 'lucide-react';
4-
import { StreamingBadge } from '@/components/ui/streaming-badge';
5-
import { MarqueeBackground } from '@/components/ui/marquee-background';
63
import { useStreamingRequests } from '@/hooks/use-streaming';
7-
import { SidebarMenuBadge, SidebarMenuButton, SidebarMenuItem } from '@/components/ui/sidebar';
4+
import { AnimatedNavItem } from './animated-nav-item';
85

96
/**
107
* Requests navigation item with streaming badge and marquee animation
118
*/
129
export function RequestsNavItem() {
13-
const location = useLocation();
1410
const { total } = useStreamingRequests();
1511
const { t } = useTranslation();
16-
const isActive =
17-
location.pathname === '/requests' || location.pathname.startsWith('/requests/');
1812
const color = 'var(--color-success)'; // emerald-500
1913

2014
return (
21-
<SidebarMenuItem>
22-
<SidebarMenuButton
23-
render={<NavLink to="/requests" />}
24-
isActive={isActive}
25-
tooltip={t('requests.title')}
26-
className="relative"
27-
>
28-
<MarqueeBackground show={total > 0 && !isActive} color={color} opacity={0.4} />
29-
<Activity className="relative z-10" />
30-
<span className="relative z-10">{t('requests.title')}</span>
31-
</SidebarMenuButton>
32-
<SidebarMenuBadge>
33-
<StreamingBadge count={total} color={color} />
34-
</SidebarMenuBadge>
35-
</SidebarMenuItem>
15+
<AnimatedNavItem
16+
to="/requests"
17+
isActive={(pathname) => pathname === '/requests' || pathname.startsWith('/requests/')}
18+
tooltip={t('requests.title')}
19+
icon={<Activity />}
20+
label={t('requests.title')}
21+
streamingCount={total}
22+
color={color}
23+
/>
3624
);
3725
}

web/src/components/layout/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
export { AppLayout } from './app-layout';
2-
export { SidebarNav } from './app-sidebar';
2+
export { AppSidebar } from './app-sidebar';
33
export { PageHeader } from './page-header';
44
export { NavProxyStatus } from './nav-proxy-status';
55
export { SidebarRenderer } from './app-sidebar/sidebar-renderer';

web/src/components/layout/nav-proxy-status.tsx

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import { Radio, Check, Copy } from 'lucide-react';
33
import { useProxyStatus } from '@/hooks/queries';
44
import { useSidebar } from '@/components/ui/sidebar';
55
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
6-
import { Button } from '../ui';
76
import { useTranslation } from 'react-i18next';
87

98
export function NavProxyStatus() {
@@ -60,20 +59,20 @@ export function NavProxyStatus() {
6059
}
6160

6261
return (
63-
<Button
64-
variant={'ghost'}
65-
onClick={handleCopy}
66-
className="h-auto border-none p-2 flex items-center gap-2 group w-full rounded-lg transition-all cursor-pointer"
67-
title={`Click to copy: ${fullUrl}`}
68-
>
69-
<div className="w-8 h-8 rounded-lg bg-emerald-400/10 flex items-center justify-center shrink-0 group-hover:bg-emerald-400/20 transition-colors">
62+
<div className="h-auto border-none p-2 flex items-center gap-2 w-full rounded-lg transition-all group">
63+
<div className="w-8 h-8 rounded-lg bg-emerald-400/10 flex items-center justify-center shrink-0 transition-colors cursor-default">
7064
<Radio size={16} className="text-emerald-400" />
7165
</div>
7266
<div className="flex flex-col items-start flex-1 min-w-0">
7367
<span className="text-caption text-text-muted">{t('proxy.listeningOn')}</span>
74-
<span className="font-mono font-medium text-text-primary truncate">{proxyAddress}</span>
68+
<span className="font-mono font-medium text-text-primary truncate">{proxyAddress}</span>
7569
</div>
76-
<div className="shrink-0 text-muted-foreground relative w-4 h-4">
70+
<button
71+
type="button"
72+
onClick={handleCopy}
73+
className="shrink-0 text-muted-foreground relative w-4 h-4 cursor-pointer hover:text-foreground transition-colors"
74+
title={`Click to copy: ${fullUrl}`}
75+
>
7776
<Copy
7877
size={14}
7978
className={`absolute inset-0 transition-all ${
@@ -86,7 +85,7 @@ export function NavProxyStatus() {
8685
copied ? 'scale-100 opacity-100' : 'scale-0 opacity-0'
8786
}`}
8887
/>
89-
</div>
90-
</Button>
88+
</button>
89+
</div>
9190
);
9291
}

0 commit comments

Comments
 (0)