| import React from 'react'; |
| import { cn } from '@/lib/utils'; |
|
|
| |
| |
| |
| |
|
|
| interface MetadataItem { |
| |
| key: string; |
| |
| value: React.ReactNode; |
| |
| optional?: boolean; |
| } |
|
|
| interface MetadataListProps { |
| |
| items: MetadataItem[]; |
| |
| layout?: 'vertical' | 'horizontal'; |
| |
| className?: string; |
| } |
|
|
| |
| |
| |
| |
| export function MetadataList({ |
| items, |
| layout = 'vertical', |
| className, |
| }: MetadataListProps) { |
| |
| const visibleItems = items.filter( |
| (item) => item.value !== null && item.value !== undefined && item.value !== '' |
| ); |
|
|
| if (visibleItems.length === 0) { |
| return ( |
| <div className={cn('py-2 text-xs text-console-text-muted', className)}> |
| 暂无元数据 |
| </div> |
| ); |
| } |
|
|
| if (layout === 'horizontal') { |
| return ( |
| <div className={cn('flex flex-wrap gap-x-4 gap-y-1', className)}> |
| {visibleItems.map((item) => ( |
| <div key={item.key} className="flex items-center gap-1.5 text-xs"> |
| <span className="text-console-text-secondary">{item.key}:</span> |
| <span className="text-console-text-primary">{item.value}</span> |
| </div> |
| ))} |
| </div> |
| ); |
| } |
|
|
| return ( |
| <dl className={cn('space-y-1', className)}> |
| {visibleItems.map((item) => ( |
| <div key={item.key} className="flex items-start gap-2 text-xs"> |
| <dt className="w-24 shrink-0 text-console-text-secondary"> |
| {item.key} |
| {item.optional && ( |
| <span className="ml-1 text-console-text-muted">(可选)</span> |
| )} |
| </dt> |
| <dd className="flex-1 min-w-0 text-console-text-primary"> |
| {item.value} |
| </dd> |
| </div> |
| ))} |
| </dl> |
| ); |
| } |
|
|
| |
| |
| |
| |
| interface MetadataEntryProps { |
| |
| label: string; |
| |
| value: React.ReactNode; |
| |
| optional?: boolean; |
| |
| className?: string; |
| } |
|
|
| export function MetadataEntry({ |
| label, |
| value, |
| optional, |
| className, |
| }: MetadataEntryProps) { |
| if (value === null || value === undefined || value === '') { |
| return null; |
| } |
|
|
| return ( |
| <div className={cn('flex items-start gap-2 text-xs', className)}> |
| <span className="w-24 shrink-0 text-console-text-secondary"> |
| {label} |
| {optional && ( |
| <span className="ml-1 text-console-text-muted">(可选)</span> |
| )} |
| </span> |
| <span className="flex-1 min-w-0 text-console-text-primary"> |
| {value} |
| </span> |
| </div> |
| ); |
| } |
|
|