feat(ui): integrate official shadcn/ui + Radix primitives + cmdk + cva in src/components/ui
This commit is contained in:
1 parent
cbc47336d6
commit
07d2050c5f
21 files changed
+1606
-471
No files matched your search
@@ -2,6 +2,8 @@ import React from 'react';
|
|||||||
import { BookOpen, LayoutGrid, Moon, Search, Sun, Terminal } from 'lucide-react';
|
import { BookOpen, LayoutGrid, Moon, Search, Sun, Terminal } from 'lucide-react';
|
||||||
import { usePortalStore } from '../store/usePortalStore';
|
import { usePortalStore } from '../store/usePortalStore';
|
||||||
import type { RouteModeId } from '../types/telemetry';
|
import type { RouteModeId } from '../types/telemetry';
|
||||||
|
import { Button } from './ui/button';
|
||||||
|
import { Tabs, TabsList, TabsTrigger } from './ui/tabs';
|
||||||
|
|
||||||
const MODES: Array<{ id: RouteModeId; label: string }> = [
|
const MODES: Array<{ id: RouteModeId; label: string }> = [
|
||||||
{ id: 'auto', label: '智能路由' },
|
{ id: 'auto', label: '智能路由' },
|
||||||
@@ -29,15 +31,15 @@ export const TopRibbon: React.FC = () => {
|
|||||||
<>
|
<>
|
||||||
{/* =====================================================================
|
{/* =====================================================================
|
||||||
Tier 1: Standard AppShell Global Top Navbar (h-14, NEVER wraps!)
|
Tier 1: Standard AppShell Global Top Navbar (h-14, NEVER wraps!)
|
||||||
Left: Brand + View Tabs (中控台 / Storybook)
|
Left: Brand + Radix Tabs (中控台 / Storybook)
|
||||||
Far Right (Red Box): Search (Cmd+K) + AGY Terminal + Theme Switcher
|
Far Right: Search (Cmd+K) + AGY Terminal + Theme Switcher
|
||||||
===================================================================== */}
|
===================================================================== */}
|
||||||
<header
|
<header
|
||||||
className="border-b hl-border sticky top-0 z-30 backdrop-blur-md"
|
className="border-b hl-border sticky top-0 z-30 backdrop-blur-md"
|
||||||
style={{ backgroundColor: 'color-mix(in srgb, var(--bg-card) 88%, transparent)' }}
|
style={{ backgroundColor: 'color-mix(in srgb, var(--bg-card) 88%, transparent)' }}
|
||||||
>
|
>
|
||||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 h-14 flex items-center justify-between gap-4">
|
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 h-14 flex items-center justify-between gap-4">
|
||||||
{/* Left Group: Brand Logo + Navigation Tabs */}
|
{/* Left Group: Brand Logo + Official Radix Navigation Tabs */}
|
||||||
<div className="flex items-center gap-4 shrink-0">
|
<div className="flex items-center gap-4 shrink-0">
|
||||||
<div
|
<div
|
||||||
onClick={() => setViewMode('dashboard')}
|
onClick={() => setViewMode('dashboard')}
|
||||||
@@ -58,47 +60,30 @@ export const TopRibbon: React.FC = () => {
|
|||||||
|
|
||||||
<div className="h-4 w-[1px] hl-muted" />
|
<div className="h-4 w-[1px] hl-muted" />
|
||||||
|
|
||||||
{/* View Switcher Tabs: Dashboard vs Storybook */}
|
{/* View Switcher Tabs via @radix-ui/react-tabs */}
|
||||||
<nav className="flex items-center gap-1 text-xs">
|
<Tabs
|
||||||
<button
|
value={viewMode}
|
||||||
onClick={() => setViewMode('dashboard')}
|
onValueChange={(v) => setViewMode(v as 'dashboard' | 'storybook')}
|
||||||
className="px-2.5 py-1.5 rounded-md font-medium flex items-center gap-1.5 transition-all cursor-pointer"
|
>
|
||||||
style={
|
<TabsList>
|
||||||
viewMode === 'dashboard'
|
<TabsTrigger value="dashboard">
|
||||||
? {
|
<LayoutGrid className="w-3.5 h-3.5" />
|
||||||
backgroundColor: 'var(--bg-muted)',
|
<span>中控台</span>
|
||||||
color: 'var(--text-main)',
|
</TabsTrigger>
|
||||||
}
|
<TabsTrigger value="storybook">
|
||||||
: { color: 'var(--text-muted)' }
|
<BookOpen className="w-3.5 h-3.5" />
|
||||||
}
|
<span>Storybook 设计规范</span>
|
||||||
>
|
</TabsTrigger>
|
||||||
<LayoutGrid className="w-3.5 h-3.5" />
|
</TabsList>
|
||||||
<span>中控台</span>
|
</Tabs>
|
||||||
</button>
|
|
||||||
|
|
||||||
<button
|
|
||||||
onClick={() => setViewMode('storybook')}
|
|
||||||
className="px-2.5 py-1.5 rounded-md font-medium flex items-center gap-1.5 transition-all cursor-pointer"
|
|
||||||
style={
|
|
||||||
viewMode === 'storybook'
|
|
||||||
? {
|
|
||||||
backgroundColor: 'var(--bg-muted)',
|
|
||||||
color: 'var(--text-main)',
|
|
||||||
}
|
|
||||||
: { color: 'var(--text-muted)' }
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<BookOpen className="w-3.5 h-3.5" />
|
|
||||||
<span>Storybook 设计规范</span>
|
|
||||||
</button>
|
|
||||||
</nav>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Far Right Group: Pinned to Right Edge (Search + AGY + Theme Switcher) */}
|
{/* Far Right Group: Pinned to Right Edge (Search + AGY + Theme Switcher) */}
|
||||||
<div className="flex items-center gap-2.5 shrink-0 ml-auto">
|
<div className="flex items-center gap-2.5 shrink-0 ml-auto">
|
||||||
<button
|
<Button
|
||||||
|
variant="outline"
|
||||||
onClick={() => setShowCmdPalette(true)}
|
onClick={() => setShowCmdPalette(true)}
|
||||||
className="hl-btn-outline px-3 py-1.5 text-xs flex items-center gap-3 cursor-pointer"
|
className="gap-3"
|
||||||
title="按 Cmd+K 唤起全局命令面板"
|
title="按 Cmd+K 唤起全局命令面板"
|
||||||
>
|
>
|
||||||
<span className="flex items-center gap-1.5" style={{ color: 'var(--text-muted)' }}>
|
<span className="flex items-center gap-1.5" style={{ color: 'var(--text-muted)' }}>
|
||||||
@@ -111,15 +96,12 @@ export const TopRibbon: React.FC = () => {
|
|||||||
>
|
>
|
||||||
⌘K
|
⌘K
|
||||||
</kbd>
|
</kbd>
|
||||||
</button>
|
</Button>
|
||||||
|
|
||||||
<button
|
<Button onClick={() => setShowAgyModal(true)}>
|
||||||
onClick={() => setShowAgyModal(true)}
|
|
||||||
className="hl-btn-primary px-3 py-1.5 text-xs flex items-center gap-1.5 cursor-pointer"
|
|
||||||
>
|
|
||||||
<Terminal className="w-3.5 h-3.5" />
|
<Terminal className="w-3.5 h-3.5" />
|
||||||
<span>AGY 终端</span>
|
<span>AGY 终端</span>
|
||||||
</button>
|
</Button>
|
||||||
|
|
||||||
{/* Top-Right Theme Toggle (Pinned at Far Right Corner!) */}
|
{/* Top-Right Theme Toggle (Pinned at Far Right Corner!) */}
|
||||||
<div className="flex items-center p-0.5 rounded-lg hl-muted border hl-border text-xs">
|
<div className="flex items-center p-0.5 rounded-lg hl-muted border hl-border text-xs">
|
||||||
@@ -163,7 +145,7 @@ export const TopRibbon: React.FC = () => {
|
|||||||
{/* =====================================================================
|
{/* =====================================================================
|
||||||
Tier 2: Subheader Telemetry & Route Mode Bar (Aligned with Grid)
|
Tier 2: Subheader Telemetry & Route Mode Bar (Aligned with Grid)
|
||||||
Left: 4 Hardware & Network Gauges
|
Left: 4 Hardware & Network Gauges
|
||||||
Right: Route Mode Segmented Switcher (智能路由 / 443 / 10443 / LAN)
|
Right: Route Mode Segmented Switcher via @radix-ui/react-tabs
|
||||||
===================================================================== */}
|
===================================================================== */}
|
||||||
{viewMode === 'dashboard' && (
|
{viewMode === 'dashboard' && (
|
||||||
<div className="border-b hl-border" style={{ backgroundColor: 'var(--bg-card)' }}>
|
<div className="border-b hl-border" style={{ backgroundColor: 'var(--bg-card)' }}>
|
||||||
@@ -217,27 +199,20 @@ export const TopRibbon: React.FC = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Right: Route Mode Switcher (Pinned to Right Edge of Subheader) */}
|
{/* Right: Route Mode Switcher via @radix-ui/react-tabs */}
|
||||||
<div className="flex items-center p-0.5 rounded-lg hl-muted border hl-border text-xs ml-auto">
|
<Tabs
|
||||||
{MODES.map((m) => (
|
value={routeMode}
|
||||||
<button
|
onValueChange={(v) => setRouteMode(v as RouteModeId)}
|
||||||
key={m.id}
|
className="ml-auto"
|
||||||
onClick={() => setRouteMode(m.id)}
|
>
|
||||||
className="px-2.5 py-1 rounded-md font-medium transition-all cursor-pointer"
|
<TabsList>
|
||||||
style={
|
{MODES.map((m) => (
|
||||||
routeMode === m.id
|
<TabsTrigger key={m.id} value={m.id}>
|
||||||
? {
|
{m.label}
|
||||||
backgroundColor: 'var(--bg-card)',
|
</TabsTrigger>
|
||||||
color: 'var(--text-main)',
|
))}
|
||||||
boxShadow: '0 1px 2px rgba(0,0,0,0.08)',
|
</TabsList>
|
||||||
}
|
</Tabs>
|
||||||
: { color: 'var(--text-muted)' }
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{m.label}
|
|
||||||
</button>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
Reference in new issue
Block a user