ui: uniform badge sizing across record rows + fixed-width right-aligned label column in detail meta grid

This commit is contained in:
root
2026-10-17 11:25:49 +08:00
parent e0fcca75b1
commit 5ad9e8db64
15 changed files with 94 additions and 91 deletions
+9 -6
View File
@@ -1,6 +1,9 @@
import { Badge, NeutralBadge } from '@/components/ui';
import type { FootprintRow } from '@/lib/types';
// 记录徽章统一尺寸:同高 22px、最小宽 52px、居中、同字号 —— 整行排列规整
export const ROW_BADGE_CLS = 'inline-flex h-[22px] min-w-[52px] items-center justify-center gap-1 rounded-sm border px-2 text-[11.5px] font-medium whitespace-nowrap';
const STATUS_MAP: Record<string, { label: string; color: string; bg: string }> = {
draft: { label: '草稿', color: 'var(--text-3)', bg: 'var(--surface-3)' },
ongoing: { label: '进行中', color: 'var(--brand-text)', bg: 'var(--brand-subtle)' },
@@ -12,7 +15,7 @@ export function StatusBadge({ status }: { status: string }) {
const s = STATUS_MAP[status] ?? STATUS_MAP.draft;
return (
<span
className="inline-flex items-center rounded-sm px-1.5 py-px text-[11px] leading-[18px] font-medium whitespace-nowrap"
className={ROW_BADGE_CLS + ' border-transparent'}
style={{ color: s.color, backgroundColor: s.bg }}
>
{s.label}
@@ -31,7 +34,7 @@ const LEVEL_COLORS: Record<string, string> = {
export function LevelBadge({ level }: { level?: string | null }) {
if (!level) return null;
return <Badge color={LEVEL_COLORS[level] ?? 'var(--text-3)'}>{level}</Badge>;
return <Badge color={LEVEL_COLORS[level] ?? 'var(--text-3)'} className={ROW_BADGE_CLS}>{level}</Badge>;
}
const GRADE_COLORS: Record<string, string> = {
@@ -44,21 +47,21 @@ const GRADE_COLORS: Record<string, string> = {
export function GradeBadge({ grade }: { grade?: string | null }) {
if (!grade) return null;
return <Badge color={GRADE_COLORS[grade] ?? 'var(--text-3)'}>{grade}</Badge>;
return <Badge color={GRADE_COLORS[grade] ?? 'var(--text-3)'} className={ROW_BADGE_CLS}>{grade}</Badge>;
}
export function RoleBadge({ role }: { role?: string | null }) {
if (!role) return null;
return <NeutralBadge>{role}</NeutralBadge>;
return <NeutralBadge className={ROW_BADGE_CLS}>{role}</NeutralBadge>;
}
export function NegativeBadge() {
return <Badge color="var(--danger)">负面</Badge>;
return <Badge color="var(--danger)" className={ROW_BADGE_CLS}>负面</Badge>;
}
export function TypeBadge({ row }: { row: FootprintRow }) {
return (
<Badge color={row.type_color}>
<Badge color={row.type_color} className={ROW_BADGE_CLS}>
{row.type_name}
</Badge>
);
@@ -4,7 +4,7 @@ import { Pencil, Trash2, Paperclip, FileText } from 'lucide-react';
import { attachmentRead, attachmentThumb, footprintGet, listDimensions, listTypes } from '@/lib/api';
import type { Attachment, FormField } from '@/lib/types';
import { Badge, Button, Confirm, Dialog, useToast } from '@/components/ui';
import { StatusBadge, LevelBadge, GradeBadge, RoleBadge, NegativeBadge } from '@/components/common/badges';
import { StatusBadge, LevelBadge, GradeBadge, RoleBadge, NegativeBadge, ROW_BADGE_CLS } from '@/components/common/badges';
import { AttachmentPreview } from '@/components/common/AttachmentPreview';
import { makeThumb } from '@/lib/img';
import { fmtRange, fmtDateTime, fmtSize } from '@/lib/format';
@@ -135,13 +135,13 @@ export function RecordDetailDialog({ open, onClose, footprintId, onEdit }: {
<div>
<h2 className="text-[20px] font-bold leading-tight tracking-tight text-ink-1" style={{ textWrap: 'balance' }}>{d.title}</h2>
<div className="mt-2.5 flex flex-wrap items-center gap-1.5">
<Badge color={d.type_color}>{d.type_name}</Badge>
<Badge color={d.type_color} className={ROW_BADGE_CLS}>{d.type_name}</Badge>
<LevelBadge level={d.level} />
<GradeBadge grade={d.award_grade} />
<RoleBadge role={d.role} />
<StatusBadge status={d.status} />
{d.polarity === 'negative' && <NegativeBadge />}
{d.rank != null && <Badge color="var(--text-3)">第 {d.rank} 名</Badge>}
{d.rank != null && <Badge color="var(--text-3)" className={ROW_BADGE_CLS}>第 {d.rank} 名</Badge>}
</div>
</div>
@@ -272,8 +272,8 @@ export function RecordDetailDialog({ open, onClose, footprintId, onEdit }: {
function MetaItem({ label, value }: { label: string; value: string }) {
return (
<div className="flex min-w-0 gap-2">
<span className="shrink-0 text-ink-3">{label}</span>
<div className="grid min-w-0 grid-cols-[76px_1fr] gap-x-2.5">
<span className="shrink-0 text-right text-ink-3">{label}</span>
<span className="min-w-0 truncate font-medium text-ink-1" title={value}>{value}</span>
</div>
);