This commit is contained in:
2026-06-06 17:00:22 +03:00
parent 0b2425f506
commit 5adb1e807b
5 changed files with 107 additions and 1 deletions

View File

@@ -1,9 +1,15 @@
import { useMe } from '@features/auth'
import { Spinner } from '@shared/ui'
import { ConverterSection } from '@widgets/converter-page'
import { LegalConverterPage } from './LegalConverterPage'
export function ConverterPage() {
const { data } = useMe()
const { data, isLoading } = useMe()
if (isLoading) {
return <Spinner fullscreen size="lg" label="Загрузка данных аккаунта" />
}
const isLegal = !!data && data.account_type !== 'individual'
return isLegal ? <LegalConverterPage /> : <ConverterSection />
}

View File

@@ -0,0 +1,71 @@
.wrap {
display: inline-flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 12px;
}
.fullscreen {
display: flex;
width: 100%;
min-height: 200px;
}
.spinner {
display: block;
border-radius: 50%;
border: 2px solid var(--glass-border);
border-top-color: var(--highlight);
animation: spin 0.7s linear infinite;
}
/* Sizes */
.sm {
width: 18px;
height: 18px;
border-width: 2px;
}
.md {
width: 32px;
height: 32px;
border-width: 3px;
}
.lg {
width: 48px;
height: 48px;
border-width: 3px;
}
.label {
font-family: var(--font-sans);
font-size: 0.875rem;
color: var(--text-secondary);
letter-spacing: 0.01em;
}
.srOnly {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
@keyframes spin {
to {
transform: rotate(360deg);
}
}
@media (prefers-reduced-motion: reduce) {
.spinner {
animation-duration: 1.6s;
}
}

View File

@@ -0,0 +1,27 @@
import styles from './Spinner.module.css'
type SpinnerSize = 'sm' | 'md' | 'lg'
interface Props {
/** Размер спиннера. По умолчанию `md`. */
size?: SpinnerSize
/** Подпись под спиннером. */
label?: string
/** Растянуть на всю высоту контейнера и отцентрировать содержимое. */
fullscreen?: boolean
className?: string
}
export function Spinner({ size = 'md', label, fullscreen, className }: Props) {
const wrapClass = [styles.wrap, fullscreen ? styles.fullscreen : '', className ?? '']
.filter(Boolean)
.join(' ')
return (
<div className={wrapClass} role="status" aria-live="polite" aria-busy="true">
<span className={`${styles.spinner} ${styles[size]}`} aria-hidden="true" />
{label ? <span className={styles.label}>{label}</span> : null}
<span className={styles.srOnly}>{label ?? 'Загрузка'}</span>
</div>
)
}

View File

@@ -0,0 +1 @@
export { Spinner } from './Spinner'

View File

@@ -8,4 +8,5 @@ export { Pill } from './Pill'
export { PrimaryButton } from './PrimaryButton'
export { Select } from './Select'
export type { SelectOption } from './Select'
export { Spinner } from './Spinner'
export { TokenIcon } from './TokenIcon'