refactor: tighten shadcn admin ui polish
This commit is contained in:
@@ -35,43 +35,41 @@ export function AppDataTable<Row>({
|
||||
onRowClick
|
||||
}: AppDataTableProps<Row>) {
|
||||
return (
|
||||
<div className="overflow-hidden rounded-lg border border-border bg-surface">
|
||||
{toolbar ? <div className="border-b border-border p-3">{toolbar}</div> : null}
|
||||
<div className="overflow-hidden rounded-lg border border-border bg-card shadow-sm">
|
||||
{toolbar ? <div className="border-b border-border bg-muted/20 p-3">{toolbar}</div> : null}
|
||||
{rows.length === 0 ? (
|
||||
<div className="p-4">
|
||||
<AppEmptyState title={emptyTitle} description={emptyDescription} />
|
||||
</div>
|
||||
) : (
|
||||
<div className="overflow-x-auto">
|
||||
<Table className={tableClassName}>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<Table className={tableClassName}>
|
||||
<TableHeader className="bg-muted/30">
|
||||
<TableRow>
|
||||
{columns.map((column) => (
|
||||
<TableHead key={column.key} className={column.className}>
|
||||
{column.header}
|
||||
</TableHead>
|
||||
))}
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{rows.map((row) => (
|
||||
<TableRow
|
||||
key={getRowKey(row)}
|
||||
className={cn(onRowClick ? 'cursor-pointer' : undefined)}
|
||||
onClick={() => onRowClick?.(row)}
|
||||
>
|
||||
{columns.map((column) => (
|
||||
<TableHead key={column.key} className={column.className}>
|
||||
{column.header}
|
||||
</TableHead>
|
||||
<TableCell key={column.key} className={column.className}>
|
||||
{column.cell(row)}
|
||||
</TableCell>
|
||||
))}
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{rows.map((row) => (
|
||||
<TableRow
|
||||
key={getRowKey(row)}
|
||||
className={cn(onRowClick ? 'cursor-pointer' : undefined)}
|
||||
onClick={() => onRowClick?.(row)}
|
||||
>
|
||||
{columns.map((column) => (
|
||||
<TableCell key={column.key} className={column.className}>
|
||||
{column.cell(row)}
|
||||
</TableCell>
|
||||
))}
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</div>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
)}
|
||||
{footer ? <div className="border-t border-border px-3 py-2">{footer}</div> : null}
|
||||
{footer ? <div className="border-t border-border bg-muted/20 px-3 py-2">{footer}</div> : null}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ type AppEmptyStateProps = {
|
||||
|
||||
export function AppEmptyState({ title, description, action }: AppEmptyStateProps) {
|
||||
return (
|
||||
<div className="rounded-lg border border-dashed border-border bg-surface px-4 py-8 text-center">
|
||||
<div className="rounded-lg border border-dashed border-border bg-background px-4 py-8 text-center">
|
||||
<p className="text-sm font-medium text-foreground">{title}</p>
|
||||
{description ? <p className="mt-1 text-sm text-muted-foreground">{description}</p> : null}
|
||||
{action ? <div className="mt-4 flex justify-center">{action}</div> : null}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type * as React from 'react'
|
||||
|
||||
import { Card, CardContent, CardHeader } from '@/components/ui/card'
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
|
||||
type AppSectionProps = {
|
||||
title: string
|
||||
@@ -14,8 +14,8 @@ export function AppSection({ title, description, action, children }: AppSectionP
|
||||
<Card>
|
||||
<CardHeader className="flex flex-row items-start justify-between gap-3">
|
||||
<div>
|
||||
<h2 className="text-sm font-semibold text-foreground">{title}</h2>
|
||||
{description ? <p className="mt-1 text-sm text-muted-foreground">{description}</p> : null}
|
||||
<CardTitle className="text-sm">{title}</CardTitle>
|
||||
{description ? <CardDescription>{description}</CardDescription> : null}
|
||||
</div>
|
||||
{action}
|
||||
</CardHeader>
|
||||
|
||||
@@ -19,14 +19,14 @@ export function AppTopbar() {
|
||||
<Badge variant="info">本地环境</Badge>
|
||||
<Separator orientation="vertical" className="h-5" />
|
||||
<Button variant="ghost" size="icon" aria-label="通知">
|
||||
<Bell className="size-4" />
|
||||
<Bell data-icon="inline-start" />
|
||||
</Button>
|
||||
<Button variant="ghost" className="gap-2">
|
||||
<UserRound className="size-4" />
|
||||
<UserRound data-icon="inline-start" />
|
||||
<span>{user?.display_name || user?.username || '当前用户'}</span>
|
||||
</Button>
|
||||
<Button variant="outline" className="gap-2" onClick={() => void logout()}>
|
||||
<LogOut className="size-4" />
|
||||
<LogOut data-icon="inline-start" />
|
||||
<span>退出</span>
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user