Merge branch 'fix/v1.3.1-fonts-handoff' into 'main'
fix(fonts): align all text sizes to handoff spec via Tailwind theme See merge request 2-6/2-6-4/terravault/ordinis!45
This commit is contained in:
@@ -15,7 +15,7 @@ export function AuthBadge() {
|
||||
|
||||
if (auth.isLoading) {
|
||||
return (
|
||||
<span className="text-2xs uppercase tracking-[0.10em] text-mute">
|
||||
<span className="text-cap text-mute">
|
||||
{t('loading')}
|
||||
</span>
|
||||
)
|
||||
|
||||
@@ -327,7 +327,7 @@ const FieldBody = ({
|
||||
<div>
|
||||
<FieldLabel required={required}>
|
||||
{label}{' '}
|
||||
<span className="text-2xs uppercase tracking-[0.10em] text-mute ml-1">i18n</span>
|
||||
<span className="text-cap text-mute ml-1">i18n</span>
|
||||
</FieldLabel>
|
||||
<div className="space-y-2 pl-3 border-l-2 border-line mt-1">
|
||||
{supportedLocales.map((loc) => (
|
||||
|
||||
@@ -126,7 +126,7 @@ export function Sidebar() {
|
||||
{visibleSections.map((section, idx) => (
|
||||
<div key={idx} className="flex flex-col gap-0.5">
|
||||
{section.label && (
|
||||
<div className="px-3 py-1 font-display uppercase tracking-[0.10em] text-mute text-[10.5px] leading-none">
|
||||
<div className="text-cap px-3 py-1 text-mute">
|
||||
{section.label}
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -224,7 +224,7 @@ export const CascadeConfirmDialog = ({
|
||||
<div>
|
||||
<label
|
||||
htmlFor="cascade-reason"
|
||||
className="text-2xs text-ink-2 uppercase tracking-[0.10em]"
|
||||
className="text-cap text-ink-2"
|
||||
>
|
||||
{t('cascade.reason.label')}
|
||||
</label>
|
||||
@@ -242,7 +242,7 @@ export const CascadeConfirmDialog = ({
|
||||
<div>
|
||||
<label
|
||||
htmlFor="cascade-confirm"
|
||||
className="text-2xs text-ink-2 uppercase tracking-[0.10em]"
|
||||
className="text-cap text-ink-2"
|
||||
>
|
||||
{t('cascade.confirmGate.label', { word: 'CONFIRM' })}
|
||||
</label>
|
||||
|
||||
@@ -181,7 +181,7 @@ export function DictionaryHubView({ detail }: { detail: DictionaryDetail }) {
|
||||
{detail.description}
|
||||
</p>
|
||||
)}
|
||||
<div className="mt-4 pt-3 border-t border-line flex items-center justify-between text-2xs uppercase tracking-[0.10em] text-mute">
|
||||
<div className="text-cap mt-4 pt-3 border-t border-line flex items-center justify-between text-mute">
|
||||
<span>{detail.bundle}</span>
|
||||
<span>{detail.supportedLocales.join(', ')}</span>
|
||||
{typeof detail.recordCount === 'number' && (
|
||||
|
||||
@@ -341,7 +341,7 @@ export const DictionaryEditorDialog = ({ open, mode, onClose, onSuccess }: Props
|
||||
<div className="md:col-span-2">
|
||||
<label
|
||||
htmlFor="approval-min-role"
|
||||
className="text-2xs uppercase tracking-[0.10em] text-ink-2"
|
||||
className="text-cap text-ink-2"
|
||||
>
|
||||
{t('schema.approvalMinRole.label')}
|
||||
</label>
|
||||
|
||||
@@ -51,7 +51,7 @@ export const PropertyEditor = ({
|
||||
return (
|
||||
<div className="border border-line rounded-lg p-3 space-y-3 bg-white">
|
||||
<div className="flex items-start justify-between gap-2">
|
||||
<span className="text-2xs uppercase tracking-[0.10em] text-mute">
|
||||
<span className="text-cap text-mute">
|
||||
{t('schema.property')} #{index + 1}
|
||||
</span>
|
||||
<div className="flex items-center gap-1">
|
||||
|
||||
@@ -53,7 +53,7 @@ export function TimeTravelPicker({
|
||||
<div className="flex flex-col gap-3 px-4 py-3 rounded-md border border-warn bg-warn-bg text-sm">
|
||||
<div className="flex items-center gap-2">
|
||||
<ClockCounterClockwiseIcon weight="bold" size={16} className="text-warn" />
|
||||
<span className="text-2xs font-display uppercase tracking-[0.10em] text-ink-2">
|
||||
<span className="text-cap font-display text-ink-2">
|
||||
{t('timeTravel.label')}
|
||||
</span>
|
||||
<button
|
||||
@@ -340,7 +340,7 @@ function QuickPresets({ onPick }: { onPick: (deltaMs: number) => void }) {
|
||||
]
|
||||
return (
|
||||
<div className="flex flex-wrap items-center gap-1.5">
|
||||
<span className="text-2xs uppercase tracking-[0.10em] text-mute font-display mr-1">
|
||||
<span className="text-cap text-mute font-display mr-1">
|
||||
{t('timeTravel.quickPresets')}
|
||||
</span>
|
||||
{presets.map((p) => (
|
||||
@@ -348,7 +348,7 @@ function QuickPresets({ onPick }: { onPick: (deltaMs: number) => void }) {
|
||||
key={p.key}
|
||||
type="button"
|
||||
onClick={() => onPick(p.deltaMs)}
|
||||
className="px-2.5 py-1 rounded-full border border-line hover:border-accent hover:bg-accent/4 text-2xs font-mono uppercase tracking-[0.10em] text-ink transition-colors"
|
||||
className="text-cap px-2.5 py-1 rounded-full border border-line hover:border-accent hover:bg-accent/4 font-mono text-ink transition-colors"
|
||||
>
|
||||
{p.label}
|
||||
</button>
|
||||
|
||||
@@ -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>
|
||||
)}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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 />
|
||||
|
||||
@@ -146,11 +146,36 @@
|
||||
--font-mono: 'JetBrains Mono', 'SF Mono', monospace;
|
||||
--font-display: 'Tektur', 'Inter', sans-serif;
|
||||
|
||||
/* Font sizes per design_handoff_ordinis_mdm/README.md spec.
|
||||
* Override Tailwind defaults так чтобы существующие utility classes
|
||||
* автоматически соответствовали handoff:
|
||||
* text-sm : 13px (workhorse — body, buttons, tabs)
|
||||
* text-xs : 12px (default, без изменений — secondary meta)
|
||||
* text-2xs : 11px (custom — IDs, dates, table mono meta)
|
||||
* Tektur caps 10.5px → используй .cap или text-cap utility (отдельно).
|
||||
* Table cells 12.5px / page titles 17px / modal titles 22px — explicit
|
||||
* через text-[Npx] arbitrary value по месту. */
|
||||
--text-sm: 13px;
|
||||
--text-sm--line-height: 1.4;
|
||||
--text-2xs: 11px;
|
||||
--text-2xs--line-height: 1.35;
|
||||
|
||||
--radius-sm: 4px;
|
||||
--radius-md: 6px;
|
||||
--radius-lg: 8px;
|
||||
}
|
||||
|
||||
/* Tektur caps utility — handoff 10.5px uppercase tracking 0.10em.
|
||||
* Codemod target: replace `text-2xs uppercase tracking-[0.10em]` → `text-cap`. */
|
||||
@utility text-cap {
|
||||
font-family: var(--font-display);
|
||||
font-size: 10.5px;
|
||||
line-height: 1;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.10em;
|
||||
}
|
||||
|
||||
html, body, #root {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ export const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
||||
{label && (
|
||||
<label
|
||||
htmlFor={inputId}
|
||||
className="text-2xs font-medium font-display uppercase tracking-[0.10em] text-mute leading-none"
|
||||
className="text-cap font-medium font-display text-mute leading-none"
|
||||
>
|
||||
{label}
|
||||
{required && <span className="text-pink ml-0.5">*</span>}
|
||||
|
||||
@@ -26,7 +26,7 @@ export function PageHeader({
|
||||
return (
|
||||
<div className={cn('flex flex-col gap-1 mb-4', className)} {...props}>
|
||||
{breadcrumb && (
|
||||
<div className="text-2xs font-display uppercase tracking-[0.10em] text-mute leading-tight mb-1">
|
||||
<div className="text-cap font-display text-mute leading-tight mb-1">
|
||||
{breadcrumb}
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -55,7 +55,7 @@ export const TextArea = React.forwardRef<HTMLTextAreaElement, TextAreaProps>(
|
||||
{label && (
|
||||
<label
|
||||
htmlFor={inputId}
|
||||
className="text-2xs font-medium font-display uppercase tracking-[0.10em] text-mute leading-none"
|
||||
className="text-cap font-medium font-display text-mute leading-none"
|
||||
>
|
||||
{label}
|
||||
{required && <span className="text-pink ml-0.5">*</span>}
|
||||
|
||||
Reference in New Issue
Block a user