b94912789f
Заменяет blanket override из MR !45 на типизированную type scale per design_handoff_ordinis_mdm/README.md "Scale" section. Семь semantic @utility в styles.css: text-title-xl 22/600 — modal title, section header text-title-lg 17/600 — page title в editor text-title-md 15/600 — dictionary card title text-body 13/400 — workhorse: body, buttons, tabs, inputs text-cell 12.5/500 — table cell text text-mono 11/500 — Mono: IDs, dates, FK refs (font-mono baked in) text-cap 10.5/600 — Tektur UPPERCASE caption (font/uppercase baked in) Audit phases: P1: добавил 7 утилит, font/uppercase/tracking baked где надо P2: 43 deterministic codemods (font-mono+text-2xs/[11px] → text-mono, [15/17/22]px+font-semibold → text-title-*, [12.5]px → text-cell, [10.5]px+uppercase+tracking → text-cap) P3: 64 text-sm → text-body (handoff workhorse), 84 text-2xs context-aware (TableCell → text-cell, bare → text-cell, плюс cleanup caps в backticks template literals который Phase 2 пропустил), 25 text-xs (6 → text-mono когда с font-mono, 19 → text-cell), 8 titles text-base/lg → text-title-* P4: убрал --text-2xs override (no users), оставил --text-sm: 13px scoped к @nstart/ui passthrough (см. comment в styles.css — убирается в Stage 3.9) Stats: text-body: 69 | text-cell: 99 | text-mono: 50 | text-cap: 42 text-title-xl: 5 | text-title-lg: 5 | text-title-md: 7 text-sm/text-2xs/text-xs в src/: 0 (только в styles.css комментариях) Поведение всех 277 typography usages теперь явно соответствует handoff — каждое место осознанно выбрано под роль, не плажирующий override.
53 lines
1.8 KiB
TypeScript
53 lines
1.8 KiB
TypeScript
import { Toaster as SonnerToaster, toast } from 'sonner'
|
||
import { useTheme } from '@/stores/ThemeProvider'
|
||
|
||
/**
|
||
* Toast notification provider — wraps sonner с our design tokens.
|
||
*
|
||
* Sonner = headless, кастомизируем через CSS variables. Параметризируется
|
||
* theme="light" | "dark" — берётся из ThemeProvider, авто-switch на смену темы.
|
||
*
|
||
* Использование:
|
||
* <pre>
|
||
* import { toast } from '@/ui/components/toaster'
|
||
* toast.success('Запись сохранена')
|
||
* toast.error('Ошибка валидации', { description: '...' })
|
||
* toast.promise(mutateAsync(), {loading, success, error})
|
||
* </pre>
|
||
*
|
||
* Mount: <Toaster /> один раз в main.tsx внутри ThemeProvider.
|
||
*/
|
||
export function Toaster() {
|
||
const { resolved } = useTheme()
|
||
|
||
return (
|
||
<SonnerToaster
|
||
position="bottom-right"
|
||
richColors
|
||
closeButton
|
||
theme={resolved}
|
||
toastOptions={{
|
||
// Inline styles переопределяют sonner CSS — tokens из @theme.
|
||
// На light: surface bg + ink text + line border.
|
||
// На dark: re-uses tokens автомат (другие значения cssvar).
|
||
style: {
|
||
background: 'var(--color-surface)',
|
||
color: 'var(--color-ink)',
|
||
border: '1px solid var(--color-line)',
|
||
borderRadius: 'var(--radius-lg)',
|
||
fontFamily: 'var(--font-sans)',
|
||
fontSize: '13px',
|
||
boxShadow: '0 12px 30px -10px rgba(40,25,10,0.38)',
|
||
},
|
||
classNames: {
|
||
title: 'font-medium',
|
||
description: 'text-mute text-cell',
|
||
},
|
||
}}
|
||
/>
|
||
)
|
||
}
|
||
|
||
// Re-export для удобства: `import { toast } from '@/ui/components/toaster'`.
|
||
export { toast }
|