diff --git a/api/openapi.yaml b/api/openapi.yaml index c40297c..20c11ad 100644 --- a/api/openapi.yaml +++ b/api/openapi.yaml @@ -2014,6 +2014,10 @@ components: web_player: type: string enum: [bar, island] + search_position: + type: string + enum: [center, left, right] + description: Где в топбаре веба поиск (по умолчанию center) mobile_player: type: string enum: [cover, wave] diff --git a/apps/web/src/pages/SettingsPage.tsx b/apps/web/src/pages/SettingsPage.tsx index f0bd20c..96e6bfc 100644 --- a/apps/web/src/pages/SettingsPage.tsx +++ b/apps/web/src/pages/SettingsPage.tsx @@ -126,6 +126,19 @@ function AppearanceSection() { ]} /> +
+ {t('settings.search_position')} + + label={t('settings.search_position')} + value={user.ui_prefs.search_position ?? 'center'} + onChange={(v) => void setPrefs({ search_position: v })} + options={[ + { value: 'left', label: t('settings.search_left') }, + { value: 'center', label: t('settings.search_center') }, + { value: 'right', label: t('settings.search_right') }, + ]} + /> +
{t('settings.ambient')} diff --git a/apps/web/src/pages/home.module.css b/apps/web/src/pages/home.module.css index 3f9dbe1..7eba488 100644 --- a/apps/web/src/pages/home.module.css +++ b/apps/web/src/pages/home.module.css @@ -7,6 +7,7 @@ gap: 28px; padding: 24px 0; text-align: center; + user-select: none; /* главная — только элементы управления волной */ } .orbLabel { diff --git a/apps/web/src/styles.css b/apps/web/src/styles.css index a65d120..311db56 100644 --- a/apps/web/src/styles.css +++ b/apps/web/src/styles.css @@ -41,6 +41,19 @@ button { cursor: pointer; } +/* Элементы управления не выделяются при кликах и двойных кликах — текст остаётся выделяемым на страницах. */ +button, +[role='button'], +[role='tab'], +[role='option'], +[role='menuitem'], +[role='listitem'], +nav a, +label { + user-select: none; + -webkit-user-select: none; +} + :focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; diff --git a/apps/web/src/widgets/AppShell.module.css b/apps/web/src/widgets/AppShell.module.css index 01bfdc5..fe304d9 100644 --- a/apps/web/src/widgets/AppShell.module.css +++ b/apps/web/src/widgets/AppShell.module.css @@ -31,10 +31,11 @@ .top { grid-area: top; z-index: 30; - display: flex; + /* Три зоны: логотип, середина, профиль; поиск — в одной из них (настройка «Расположение поиска»). */ + display: grid; + grid-template-columns: 1fr auto 1fr; align-items: center; - gap: 24px; - justify-content: space-between; + gap: 16px; padding: 0 20px; border-bottom: 1px solid var(--line); background: var(--bar-a); @@ -53,9 +54,22 @@ } } +.topLeft { + display: flex; + align-items: center; + gap: 12px; + min-width: 0; +} + +.topCenter { + display: flex; + justify-content: center; +} + .topRight { display: flex; align-items: center; + justify-content: flex-end; gap: 12px; } diff --git a/apps/web/src/widgets/AppShell.tsx b/apps/web/src/widgets/AppShell.tsx index 6656aad..b26966a 100644 --- a/apps/web/src/widgets/AppShell.tsx +++ b/apps/web/src/widgets/AppShell.tsx @@ -93,6 +93,8 @@ function Shell() { const name = user.display_name ?? user.username; const staff = user.role !== 'user'; const island = user.ui_prefs.web_player === 'island'; + const searchAt = user.ui_prefs.search_position ?? 'center'; + const search = ; const counts = useCollectionCounts(); const pending = usePendingUploads(user.role === 'admin'); @@ -100,11 +102,15 @@ function Shell() {
{user.ui_prefs.ambient !== false && }
- - - +
+ + + + {searchAt === 'left' && search} +
+
{searchAt === 'center' && search}
- + {searchAt === 'right' && search} `${listId}-${i}`; return ( -
+