fix(fonts): align all text sizes to handoff spec via Tailwind theme overrides

Глобальные правки через @theme в styles.css вместо 200+ точечных правок:

- text-sm: 14px -> 13px (handoff workhorse — body, buttons, tabs)
- text-2xs: undefined -> 11px (handoff IDs, mono meta — было невидимо)
- @utility text-cap: 10.5px Tektur uppercase 0.10em (handoff caps)

Codemod (30 sites): text-2xs + uppercase + tracking-[0.10em] -> text-cap.
Sidebar section labels consolidated с explicit text-[10.5px] на text-cap.

Покрывает 64 text-sm + 148 text-2xs автоматически. Table cells (12.5px)
и page/modal titles (17px/22px) остаются explicit text-[Npx] arbitrary
values по месту — нет slots в Tailwind scale.
This commit is contained in:
Zimin A.N.
2026-05-11 14:12:57 +03:00
parent 780de70fc5
commit 71432e9ae7
19 changed files with 56 additions and 31 deletions
+3 -3
View File
@@ -299,7 +299,7 @@ function ActiveFilterChips({ filters, onRemove }: ActiveFilterChipsProps) {
const { t } = useTranslation()
return (
<div className="flex flex-wrap items-center gap-2">
<span className="text-2xs uppercase tracking-[0.10em] text-ink-2">
<span className="text-cap text-ink-2">
{t('audit.filter.active')}
</span>
{filters.map((f) => (
@@ -506,7 +506,7 @@ function AuditRow({ row }: { row: AuditEntry }) {
<TableCell colSpan={8}>
<div className="grid grid-cols-1 md:grid-cols-2 gap-3 bg-line/30 rounded p-3">
<div>
<div className="text-2xs uppercase tracking-[0.10em] text-ink-2 mb-1">
<div className="text-cap text-ink-2 mb-1">
{t('audit.diff.before')}
</div>
<pre className="text-2xs font-mono whitespace-pre-wrap break-all bg-white border border-line rounded p-2 max-h-60 overflow-auto">
@@ -516,7 +516,7 @@ function AuditRow({ row }: { row: AuditEntry }) {
</pre>
</div>
<div>
<div className="text-2xs uppercase tracking-[0.10em] text-ink-2 mb-1">
<div className="text-cap text-ink-2 mb-1">
{t('audit.diff.after')}
</div>
<pre className="text-2xs font-mono whitespace-pre-wrap break-all bg-white border border-line rounded p-2 max-h-60 overflow-auto">
@@ -1390,7 +1390,7 @@ function FieldsTabContent({ detail }: { detail: { schemaJson: import('@/api/clie
return (
<div className="rounded-lg border border-line overflow-hidden">
<table className="w-full text-sm">
<thead className="bg-surface-2 text-2xs font-display uppercase tracking-[0.10em] text-mute">
<thead className="text-cap bg-surface-2 font-display text-mute">
<tr>
<th className="text-left px-3 py-2">name</th>
<th className="text-left px-3 py-2">type</th>
@@ -253,7 +253,7 @@ function DictionariesPage() {
/>
</div>
<span className="text-2xs uppercase tracking-[0.10em] text-mute whitespace-nowrap font-mono">
<span className="text-cap text-mute whitespace-nowrap font-mono">
{filtered.length}/{data.length}
</span>
@@ -372,7 +372,7 @@ function DictionariesPage() {
<span className="text-sm uppercase tracking-[0.10em] text-accent font-mono font-medium">
{bundle}
</span>
<span className="text-2xs uppercase tracking-[0.10em] text-mute">
<span className="text-cap text-mute">
· {items.length} {t('dict.list.records.short')}
</span>
</h2>
@@ -482,7 +482,7 @@ const DictCard = ({ d, t }: { d: DictionaryDefinition; t: TFunc }) => {
)}
{hasFkRow && (
<div className="flex flex-wrap items-center gap-1.5 mt-2.5">
<span className="text-2xs font-display uppercase tracking-[0.10em] text-mute mr-1">
<span className="text-cap font-display text-mute mr-1">
{t('dict.list.fk.usedBy', { count: refBy.length })}
</span>
{refBy.slice(0, MAX_REFBY_CHIPS).map((dep) => (
@@ -509,7 +509,7 @@ const DictCard = ({ d, t }: { d: DictionaryDefinition; t: TFunc }) => {
v{d.schemaVersion}
</span>
{typeof d.recordCount === 'number' && (
<span className="text-2xs font-display uppercase tracking-[0.10em] text-mute/80 whitespace-nowrap">
<span className="text-cap font-display text-mute/80 whitespace-nowrap">
{t('dict.list.recordCount', { count: d.recordCount })}
</span>
)}
+1 -1
View File
@@ -165,7 +165,7 @@ function StatCard({ label, value, tone }: StatCardProps) {
: 'text-accent'
return (
<div className="bg-white border border-line rounded-lg p-4">
<div className="text-2xs uppercase tracking-[0.10em] text-ink-2 mb-1">
<div className="text-cap text-ink-2 mb-1">
{label}
</div>
<div className={`text-2xl font-sans tabular-nums ${colour}`}>{value}</div>
+3 -3
View File
@@ -423,7 +423,7 @@ function ReviewDrawer({ draftId, onClose }: DrawerProps) {
<div className="grid grid-cols-1 md:grid-cols-2 gap-3">
<div>
<p className="text-2xs uppercase tracking-[0.10em] text-mute mb-1">
<p className="text-cap text-mute mb-1">
{t('reviews.drawer.live')}
</p>
{liveQ.isLoading && <LoadingBlock size="sm" label={t('loading')} />}
@@ -439,7 +439,7 @@ function ReviewDrawer({ draftId, onClose }: DrawerProps) {
)}
</div>
<div>
<p className="text-2xs uppercase tracking-[0.10em] text-mute mb-1">
<p className="text-cap text-mute mb-1">
{t('reviews.drawer.proposed')}
</p>
{draft.operation === 'CLOSE' ? (
@@ -463,7 +463,7 @@ function ReviewDrawer({ draftId, onClose }: DrawerProps) {
<div className="border-t border-line pt-3 space-y-2">
<label
htmlFor="review-comment"
className="text-2xs uppercase tracking-[0.10em] text-ink-2"
className="text-cap text-ink-2"
>
{t('reviews.drawer.comment')}
</label>
+4 -4
View File
@@ -169,7 +169,7 @@ function WebhookDetailPage() {
{data.scopeFilter.map((s) => (
<span
key={s}
className="inline-flex items-center gap-1 text-2xs uppercase tracking-[0.10em]"
className="text-cap inline-flex items-center gap-1"
>
<span className={`inline-block size-2 rounded-full ${SCOPE_DOT[s]}`} aria-hidden />
{s}
@@ -394,7 +394,7 @@ function TestResultAlert({
<div className="space-y-1 text-sm">
{result.httpStatus != null && (
<div>
<span className="text-2xs uppercase tracking-[0.10em] text-mute mr-2">
<span className="text-cap text-mute mr-2">
HTTP
</span>
<span className="font-mono">{result.httpStatus}</span>
@@ -402,7 +402,7 @@ function TestResultAlert({
)}
{result.latencyMs != null && (
<div>
<span className="text-2xs uppercase tracking-[0.10em] text-mute mr-2">
<span className="text-cap text-mute mr-2">
{t('webhooks.test.latency')}
</span>
<span className="font-mono">{result.latencyMs} ms</span>
@@ -421,7 +421,7 @@ function TestResultAlert({
function InfoRow({ label, children }: { label: string; children: React.ReactNode }) {
return (
<div>
<div className="text-2xs uppercase tracking-[0.10em] text-mute mb-1">
<div className="text-cap text-mute mb-1">
{label}
</div>
<div>{children}</div>
@@ -182,7 +182,7 @@ function ScopeChips({ scopes }: { scopes?: DataScope[] | null }) {
{scopes.map((s) => (
<span
key={s}
className="inline-flex items-center gap-1 text-2xs uppercase tracking-[0.10em]"
className="text-cap inline-flex items-center gap-1"
title={s}
>
<span className={`inline-block size-2 rounded-full ${SCOPE_DOT[s]}`} aria-hidden />