From 5adb1e807bb0e5a421d40d6b5b129c46c9b03712 Mon Sep 17 00:00:00 2001 From: rassadin11 Date: Sat, 6 Jun 2026 17:00:22 +0300 Subject: [PATCH] spinner --- src/pages/converter/ui/ConverterPage.tsx | 8 ++- src/shared/ui/Spinner/Spinner.module.css | 71 ++++++++++++++++++++++++ src/shared/ui/Spinner/Spinner.tsx | 27 +++++++++ src/shared/ui/Spinner/index.ts | 1 + src/shared/ui/index.ts | 1 + 5 files changed, 107 insertions(+), 1 deletion(-) create mode 100644 src/shared/ui/Spinner/Spinner.module.css create mode 100644 src/shared/ui/Spinner/Spinner.tsx create mode 100644 src/shared/ui/Spinner/index.ts diff --git a/src/pages/converter/ui/ConverterPage.tsx b/src/pages/converter/ui/ConverterPage.tsx index 688b78d..fc1ef5c 100644 --- a/src/pages/converter/ui/ConverterPage.tsx +++ b/src/pages/converter/ui/ConverterPage.tsx @@ -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 + } + const isLegal = !!data && data.account_type !== 'individual' return isLegal ? : } diff --git a/src/shared/ui/Spinner/Spinner.module.css b/src/shared/ui/Spinner/Spinner.module.css new file mode 100644 index 0000000..04906ff --- /dev/null +++ b/src/shared/ui/Spinner/Spinner.module.css @@ -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; + } +} diff --git a/src/shared/ui/Spinner/Spinner.tsx b/src/shared/ui/Spinner/Spinner.tsx new file mode 100644 index 0000000..d031178 --- /dev/null +++ b/src/shared/ui/Spinner/Spinner.tsx @@ -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 ( +
+
+ ) +} diff --git a/src/shared/ui/Spinner/index.ts b/src/shared/ui/Spinner/index.ts new file mode 100644 index 0000000..fbf16c1 --- /dev/null +++ b/src/shared/ui/Spinner/index.ts @@ -0,0 +1 @@ +export { Spinner } from './Spinner' diff --git a/src/shared/ui/index.ts b/src/shared/ui/index.ts index 5cf4acc..2b31fc5 100644 --- a/src/shared/ui/index.ts +++ b/src/shared/ui/index.ts @@ -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'