diff --git a/VERSION.properties b/VERSION.properties index aba3165e..56b1a50f 100644 --- a/VERSION.properties +++ b/VERSION.properties @@ -1,2 +1,2 @@ -client.version=1.14.0 +client.version=1.14.1 server.version=1.12.0 diff --git a/docs/UI-Design/UI-v4-for-dev.md b/docs/UI-Design/UI-v4-for-dev.md new file mode 100644 index 00000000..9e978625 --- /dev/null +++ b/docs/UI-Design/UI-v4-for-dev.md @@ -0,0 +1,65 @@ +# UI v3–v4: что нужно от сервера и что знать разработчику + +Макет V3/V4 перенесён в настоящий код (v3) и доведён по экранам (v4): палитра «Сияние», лента канала, обсуждение, +личный чат, вход и регистрация, уведомления, настройки, просмотр фото. Всё сделано на текущем API без его изменений. +Там, где интерфейсу не хватает сервера, UI к этому готов: нет данных – элемент просто не появляется. + +## Нужно от сервера + +1. **Кто недавно ответил** – миниатюры рядом со счётчиком обсуждения в ленте канала. + Поле `recentRepliers: string[]` (до двух логинов, свежие первыми) у сообщений в `GetChannelMessages` + и `GetMessageThread`. UI: `channel-view.js`, `mapApiMessageToPost` → `recentRepliers`. Нет поля – нет миниатюр. + +2. **«Не уведомлять об ответах» в обсуждении.** Пункт меню обсуждения сейчас запоминает выбор только на устройстве + (`localStorage`, ключ `shine-ui-thread-muted-v1`) и на уведомления не влияет. Нужна настройка пользователя + «без уведомлений об ответах в этом обсуждении» (по ссылке на исходную запись), учитываемая при создании + уведомлений `reply`. Удобно через существующий `UpsertUserSetting`. + +3. **Ссылка на комментарий.** «Поделиться комментарием» даёт ссылку на обсуждение с якорем `#comment-`. + Роутер якорь игнорирует. Нужно: при открытии обсуждения с таким якорем прокрутить к комментарию и подсветить + (в UI для этого есть `jumpTo` в `channel-thread-view.js`). + +4. **Уведомления об ответах – на что ответили** (по желанию). В уведомлении есть только текст ответа (`sourceText`). + Чтобы показать «в ответ на: …», нужен короткий текст исходного сообщения (`targetText`) в `GetNotifications`. + +5. **Стоимость публикации** (экран «Публикация · подтверждение» макета). Шага подтверждения в приложении нет – + запись уходит сразу. Если публикация станет платной или будет ждать Arweave, нужна цена до отправки. + +## Нужно от разработчика + +6. **Удалить `pages/key-storage-view.js` и маршрут `/key-storage`.** Экран никуда не подключён: в поля вписаны + описания ключей, «OK» вызывает `authorizeSession()` без данных. Настоящий выбор ключей – `registration-keys-view.js` + (переделан в v4). Вместе с ним можно убрать `.key-storage-option*` / `.key-storage-note*` в `developer-tools.css`. + +## Что важно знать об изменениях v4 + +- **Второстепенные кнопки** – одна роль во всём приложении, включая экраны устройств и серверов: прозрачная, рамка, цвет `--action`. +- **Полоса прокрутки скрыта по умолчанию** (`scrollbar: 'hidden'` в режимах оболочки `app.js`) – как было у каналов, + ленты и обсуждения. Прокрутка работает, контент не прыгает при появлении полосы. +- **Один зазор под шапкой:** `--page-top-gap` в `main.css` (12 px). Его берут `app-shell.css`, каналы и экраны входа – + свои отступы сверху экранам не нужны. +- **Шапка корневых разделов** (Чаты, Каналы, Связи, Уведомления, Профиль) – заголовок по центру, 24 px (`.topbar--root`). +- **Переключатели `.tabs`** – высотой с поле ввода (44 px, кнопки 34 px); `.tabs--dense` – для 4–5 коротких пунктов + (фильтр чатов вместо чипов). +- **Новые общие компоненты:** `components/media-viewer.js` + `styles/components/media-viewer.css` (фото/видео на весь экран, + «1/3» и «Скачать» под фото; заменил `openAttachmentViewer` и кнопку скачивания на фото), `components/shine-wordmark.js` + (надпись «СИЯНИЕ» в контурах, шрифт Tenor Sans, OFL), переключатель `.switch` (перенесён из `settings.css` в `primitives.css`). +- **Иконки** – только из `ui-icon.js` (добавлены `eye`, `eyeOff`; `iconHtml(name, filled, className)`). Текстовые символы + вместо иконок («↻», «+», «✕») заменены. +- **«Дополнительные настройки»** теперь открываются пятью быстрыми нажатиями на заголовок «Настройки» + (логотип над настройками убран). +- **Стартовый экран:** знак по центру, кнопки внизу; сияние мандалы – два вращающихся слоя в `preauth.css` + (`.auth-logo-wrap::before/::after`), фаза случайная; при `prefers-reduced-motion` неподвижно. +- **Тексты:** в строках интерфейса только среднее тире с пробелами «–» (длинное «—» заменено везде, кроме комментариев). +- Уведомления – список как в чатах; «Настройки входа» – одна карточка серверов со статусом-пилюлей, проверка при открытии; + вход с другого устройства – код, таймер, три шага. + +## Найденные ошибки (не наши) + +7. `styles/components/avatar.css`: `url("../assets/glass_overlay_faithful.png")` ведёт в `styles/assets/…` – файла там нет, + стеклянный ободок аватара не загружается. Путь должен быть `../../assets/…`. +8. Обработчик ошибок в `index.html` показывал красную плашку «BOOT ERROR ResizeObserver loop…» – это предупреждение + браузера, не ошибка. В v3 отсеивается. +9. Пункты 1–2 из `ISSUES-for-dev.md` (подписки у логинов с заглавными, превью «Сообщение недоступно») по-прежнему актуальны. +10. Вход по паролю на `http://` по адресу в локальной сети не работает («Криптография браузера недоступна»): WebCrypto есть + только на https и localhost. Это ограничение браузера – для проверки с телефона нужен https. diff --git a/shine-UI/index.html b/shine-UI/index.html index 3430e76f..27982da3 100644 --- a/shine-UI/index.html +++ b/shine-UI/index.html @@ -6,7 +6,7 @@ name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover, interactive-widget=resizes-visual" /> - + @@ -45,7 +45,7 @@ window.__SHINE_BUILD_HASH__ = '20260901134200';
- ✳ SHiNEDESIGN STUDY / 01 + ✳ SHiNEDESIGN STUDY / 01 Концепции · сентябрь 2026
-
КАНАЛЫ / СООБЩЕНИЯ / ОТВЕТЫ

Ближе к разговору.

Четыре характера. Один привычный путь от канала к ответу.
Выберите экран и сравните — или нажмите на элементы внутри макета.

-
01—04

Меньше визуального шума.
Больше места людям и мыслям.

+
КАНАЛЫ / СООБЩЕНИЯ / ОТВЕТЫ

Ближе к разговору.

Четыре характера. Один привычный путь от канала к ответу.
Выберите экран и сравните – или нажмите на элементы внутри макета.

+
01–04

Меньше визуального шума.
Больше места людям и мыслям.

diff --git a/shine-UI/static-sites/design-examples/channels-v1/mockups.js b/shine-UI/static-sites/design-examples/channels-v1/mockups.js index 8c97645d..1d97db81 100644 --- a/shine-UI/static-sites/design-examples/channels-v1/mockups.js +++ b/shine-UI/static-sites/design-examples/channels-v1/mockups.js @@ -43,7 +43,7 @@ const channels = [ let role = 'reader'; let showKeyboard = false; const states = new Map(); -const mainText = 'Иногда лучший маршрут — чуть длиннее обычного. Сегодня свернула к реке и нашла это место. А где вы перезагружаетесь после рабочего дня?'; +const mainText = 'Иногда лучший маршрут – чуть длиннее обычного. Сегодня свернула к реке и нашла это место. А где вы перезагружаетесь после рабочего дня?'; const secondText = 'Собрала наши любимые места в один список. Добавляйте свои находки в ответах!'; const landscape = () => ``; function header(s) { @@ -198,8 +198,8 @@ function handle(s, event) { else if (action==='details') menu(s,'Данные записи','

Здесь доступны номер записи, цепочка автора, хэш и подпись. В мокапе технические данные не генерируются.

',el); else if (action==='about') menu(s,'О канале','

Замечаем красоту рядом. Делимся местами, историями и маленькими открытиями.

Автор: @'+escapeText(s.channel.owner)+'

',el); else if (action==='close-menu') { removeOverlay(s); if(s.returnFocus?.isConnected)s.returnFocus.focus({preventScroll:true}); } - else if (action==='new-channel') toast(s,'Создание канала — следующий этап проектирования'); - else if (action==='edit-demo') toast(s,'Редактор существующего сообщения — следующий этап'); + else if (action==='new-channel') toast(s,'Создание канала – следующий этап проектирования'); + else if (action==='edit-demo') toast(s,'Редактор существующего сообщения – следующий этап'); else if (action==='outside') toast(s,'Сейчас проектируем каналы. Этот раздел пока вне макета.'); } function attachEvents(s) { diff --git a/shine-UI/styles/app-shell.css b/shine-UI/styles/app-shell.css index 99be0bb5..fd4a2945 100644 --- a/shine-UI/styles/app-shell.css +++ b/shine-UI/styles/app-shell.css @@ -49,7 +49,7 @@ } .app-shell.has-minimized-call .screen-content { - padding-top: 12px; + padding-top: var(--page-top-gap); } .topbar-slot, @@ -131,7 +131,7 @@ /* Обычный scroll-container физически продолжается под прозрачным TopBar. */ .app-shell--content-under-topbar:not(.app-shell--scroll-nested):not(.app-shell--scroll-locked) .screen-content:not(.no-app-chrome) { top: var(--call-minimized-bar-height, 0px); - padding-top: calc(var(--topbar-height, 64px) + 14px); + padding-top: calc(var(--topbar-height, 64px) + var(--page-top-gap)); } /* Вложенный scroll-container (например, переписка) сам резервирует место под chrome. */ diff --git a/shine-UI/styles/buttons-white.css b/shine-UI/styles/buttons-white.css index 47b5dc38..e8cd78c9 100644 --- a/shine-UI/styles/buttons-white.css +++ b/shine-UI/styles/buttons-white.css @@ -1,7 +1,8 @@ /* Семантические роли кнопок. Геометрией сложных компонентов владеют их стили. */ .ui-button, .primary-btn, .secondary-btn, .destructive-btn, .ghost-btn, .icon-btn, .text-btn, .shine-btn { color: var(--text-primary); background: transparent; border: 0; box-shadow: none; font: inherit; cursor: pointer; transition: background-color 160ms ease, color 160ms ease; } .primary-btn { color: var(--on-accent); background: var(--accent); } -.secondary-btn { color: var(--text-primary); background: var(--surface); border: 1px solid var(--border-control); } +/* Второстепенное действие: прозрачная, тонкая рамка, текст цвета «вторичного действия». */ +.secondary-btn { color: var(--action); background: transparent; border: 1px solid var(--border-control); } .destructive-btn { color: var(--danger); } :is(.ui-button, .primary-btn, .secondary-btn, .destructive-btn, .ghost-btn, .icon-btn, .text-btn, .shine-btn):hover { filter: brightness(.96); } :is(.ui-button, .primary-btn, .secondary-btn, .destructive-btn, .ghost-btn, .icon-btn, .text-btn, .shine-btn):active { filter: brightness(.9); } @@ -16,9 +17,9 @@ text-shadow: none; } -.filled-action-buttons :is(.secondary-btn, .ghost-btn, .text-btn, .login-panel-inline-back, .profiles-close) { - color: var(--text-primary); - background: var(--surface); +.filled-action-buttons :is(.secondary-btn, .ghost-btn, .text-btn, .profiles-close) { + color: var(--action); + background: transparent; border: 1px solid var(--border-control); border-radius: var(--radius-md); box-shadow: none; @@ -27,23 +28,23 @@ .filled-action-buttons .destructive-btn { color: var(--danger); - background: var(--surface); + background: transparent; border: 1px solid var(--border-control); border-radius: var(--radius-md); } -.filled-action-buttons :is(.primary-btn, .secondary-btn, .destructive-btn, .ghost-btn, .text-btn, .shine-btn, .square-btn, .login-panel-inline-back, .registration-faq-link, .profiles-select, .profiles-close):active { +.filled-action-buttons :is(.primary-btn, .secondary-btn, .destructive-btn, .ghost-btn, .text-btn, .shine-btn, .square-btn, .registration-faq-link, .profiles-select, .profiles-close):active { transform: scale(0.98); } -.filled-action-buttons :is(.primary-btn, .secondary-btn, .destructive-btn, .ghost-btn, .text-btn, .shine-btn, .square-btn, .login-panel-inline-back, .registration-faq-link, .profiles-select, .profiles-close):disabled { +.filled-action-buttons :is(.primary-btn, .secondary-btn, .destructive-btn, .ghost-btn, .text-btn, .shine-btn, .square-btn, .registration-faq-link, .profiles-select, .profiles-close):disabled { color: var(--text-secondary); background: var(--surface-selected); border-color: transparent; } -.filled-action-buttons :is(.primary-btn, .secondary-btn, .destructive-btn, .ghost-btn, .text-btn, .shine-btn, .square-btn, .login-panel-inline-back, .registration-faq-link, .profiles-select, .profiles-close)::before, -.filled-action-buttons :is(.primary-btn, .secondary-btn, .destructive-btn, .ghost-btn, .text-btn, .shine-btn, .square-btn, .login-panel-inline-back, .registration-faq-link, .profiles-select, .profiles-close)::after { +.filled-action-buttons :is(.primary-btn, .secondary-btn, .destructive-btn, .ghost-btn, .text-btn, .shine-btn, .square-btn, .registration-faq-link, .profiles-select, .profiles-close)::before, +.filled-action-buttons :is(.primary-btn, .secondary-btn, .destructive-btn, .ghost-btn, .text-btn, .shine-btn, .square-btn, .registration-faq-link, .profiles-select, .profiles-close)::after { content: none; } diff --git a/shine-UI/styles/components/attachments.css b/shine-UI/styles/components/attachments.css index debfd7e7..97694710 100644 --- a/shine-UI/styles/components/attachments.css +++ b/shine-UI/styles/components/attachments.css @@ -137,44 +137,6 @@ } -.message-attachment-download { - display: inline-flex; - align-items: center; - min-height: 44px; - background: var(--accent); - border-radius: 999px; - color: var(--on-accent); - font-size: 0.82rem; - font-weight: 700; - padding: 0.45rem 0.75rem; - position: relative; - text-decoration: none; - width: max-content; - z-index: 3; -} - - -.message-attachment-media-frame > .message-attachment-download { - bottom: 0.5rem; - position: absolute; - right: 0.5rem; -} - -.message-attachment-download--icon { - width: 36px; - min-height: 36px; - height: 36px; - padding: 0; - justify-content: center; - border-radius: 50%; - color: #fff; - background: rgba(0, 0, 0, 0.45); - backdrop-filter: blur(6px); - -webkit-backdrop-filter: blur(6px); -} -.message-attachment-download--icon svg { width: 18px; height: 18px; } -.message-attachment-download--icon:hover { background: rgba(0, 0, 0, 0.6); } - .message-attachment-media-frame:not(.is-loaded) { background: var(--surface-selected); animation: attachment-loading 1.2s ease-in-out infinite alternate; } .message-attachment-media-frame.is-loaded { background: transparent; } @keyframes attachment-loading { from { opacity: 1; } to { opacity: .55; } } @@ -299,84 +261,32 @@ .message-attachment-file-card { grid-template-columns: auto minmax(0, 1fr); } -.message-attachment-file-card .message-attachment-download { - grid-column: 1 / -1; - } } .ar-attachment-manager-root .modal { z-index: 120; } -.attachment-viewer-modal { - z-index: 80; -} - - -.attachment-viewer-card { - background: var(--surface); - border: 1px solid var(--border-subtle); - border-radius: 1.2rem; - box-shadow: none; - color: var(--text-primary); - display: grid; - gap: 0.8rem; - max-height: 92vh; - max-width: min(94vw, 68rem); - padding: 0.9rem; - width: 100%; -} - - -.attachment-viewer-head, -.attachment-viewer-actions { - align-items: center; - display: flex; - gap: 0.8rem; - justify-content: space-between; -} - - -.attachment-viewer-title { - font-weight: 800; - min-width: 0; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} - - -.attachment-viewer-body { - align-items: center; - display: grid; - justify-items: center; - min-height: 12rem; -} - - -.attachment-viewer-media { - background: var(--background); - border-radius: 0.8rem; - max-height: 76vh; - max-width: 100%; - object-fit: contain; -} - - .ar-attachment-manager-card { max-width: min(92vw, 34rem); - gap: 16px; + gap: var(--space-3); } -.ar-attachment-manager-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; } -.ar-attachment-manager-close { width: 44px; min-width: 44px; padding: 0; font-size: 18px; color: var(--text-secondary); } -.ar-attachment-note { margin: 0; font-size: .8125rem; line-height: 1.25rem; color: var(--text-secondary); } -.ar-attachment-alt-sources { display: flex; flex-wrap: wrap; gap: 4px 16px; } -.ar-attachment-link { min-height: 44px; padding: 0; justify-self: start; color: var(--accent); background: transparent; font-weight: 500; } +/* Пустые служебные блоки (сумма, превью, ошибка) не должны давать промежутков. */ +.ar-attachment-manager-card :is(.ar-attachment-meta, .inline-error):empty, +.ar-attachment-manager-card [hidden] { display: none; } +.ar-attachment-manager-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; } +.ar-attachment-manager-close { display: grid; place-items: center; width: 44px; min-width: 44px; padding: 0; color: var(--text-secondary); } +.ar-attachment-manager-close svg { width: 20px; height: 20px; } +.ar-attachment-note { margin: 0; font-size: .8125rem; line-height: 1.25rem; color: var(--text-secondary); } +.ar-attachment-alt-sources { display: flex; flex-wrap: wrap; gap: 0 var(--space-4); } +.ar-attachment-link { min-height: 36px; padding: 0; justify-self: start; color: var(--action); background: transparent; font-size: var(--text-sm); font-weight: var(--weight-medium); } + +/* Та же высота, что у поля ввода (44), кнопка внутри – как в переключателе (34). */ .ar-attachment-file-picker { - min-height: 56px; - padding: 8px; + min-height: var(--control-height); + padding: 4px; display: flex; align-items: center; - gap: 12px; + gap: var(--space-3); border: 1px dashed var(--border-control); border-radius: 12px; background: var(--surface); @@ -387,11 +297,12 @@ .ar-attachment-file-input { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; } .ar-attachment-file-btn { flex-shrink: 0; - min-height: 40px; + min-height: 34px; padding: 0 14px; display: inline-flex; align-items: center; - border-radius: 10px; + border-radius: 8px; + font-size: var(--text-md); color: var(--on-accent); background: var(--accent); font-weight: 600; diff --git a/shine-UI/styles/components/channel-editor.css b/shine-UI/styles/components/channel-editor.css index 36d90ef1..aee23441 100644 --- a/shine-UI/styles/components/channel-editor.css +++ b/shine-UI/styles/components/channel-editor.css @@ -23,18 +23,20 @@ .channel-editor__header { min-height: calc(56px + env(safe-area-inset-top)); - padding: env(safe-area-inset-top) 6px 0; + padding: env(safe-area-inset-top) 14px 0 6px; display: grid; - grid-template-columns: 44px minmax(0, 1fr) 44px; + grid-template-columns: 44px minmax(0, 1fr) auto; + gap: 6px; align-items: center; border-bottom: 1px solid var(--border-subtle); + background: var(--surface); } .channel-editor__header h2 { font-size: 16px; line-height: 24px; font-weight: 600; - text-align: center; + text-align: left; } .channel-editor__close { @@ -225,3 +227,7 @@ @media (prefers-reduced-motion: reduce) { .channel-editor-overlay, .channel-editor { animation: none; transition: none; } } +.channel-editor__author-text { display: grid; gap: 1px; min-width: 0; } +.channel-editor__author-text small { color: var(--text-secondary); font-size: .75rem; } +.channel-editor__draft { justify-self: end; color: var(--text-secondary); font-size: .75rem; } +.channel-editor__close svg { width: 24px; height: 24px; } diff --git a/shine-UI/styles/components/compose.css b/shine-UI/styles/components/compose.css new file mode 100644 index 00000000..021c0e39 --- /dev/null +++ b/shine-UI/styles/components/compose.css @@ -0,0 +1,14 @@ +/* Строка ввода внизу экрана (обсуждение; тот же рисунок у чата): капсула с полем и эмодзи + круглая отправка */ +.compose-row { display: flex; gap: 6px; align-items: flex-end; } +.compose-field { flex: 1; min-width: 0; display: flex; align-items: flex-end; padding: 0 6px 0 12px; border: 1px solid var(--border-control); border-radius: 22px; background: var(--surface-raised); } +.compose-field:focus-within { border-color: var(--accent); } +.compose-field__input { flex: 1; min-width: 0; min-height: 44px; max-height: 132px; padding: 10px 0; border: 0; background: transparent; color: var(--text-primary); font: inherit; font-size: 1rem; line-height: 1.375rem; resize: none; field-sizing: content; outline: none; } +.compose-field__input::placeholder { color: var(--text-secondary); } +.compose-field__emoji { width: 32px; min-width: 32px; height: 44px; padding: 0; display: grid; place-items: center; border: 0; background: transparent; color: var(--text-secondary); cursor: pointer; } +.compose-field__emoji svg { width: 22px; height: 22px; } +.compose-send { width: 44px; height: 44px; min-width: 44px; padding: 0; display: grid; place-items: center; border: 0; border-radius: 50%; background: var(--accent); color: var(--on-accent); cursor: pointer; } +.compose-send svg { width: 22px; height: 22px; stroke-width: 2.2; } +.compose-send:hover:not(:disabled) { background: var(--accent-hover); } +.compose-send:active:not(:disabled) { background: var(--accent-pressed); } +.compose-send:disabled { background: var(--disabled-bg); color: var(--disabled-text); cursor: default; } +.compose-send:focus-visible, .compose-field__emoji:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; } diff --git a/shine-UI/styles/components/dropdown-menu.css b/shine-UI/styles/components/dropdown-menu.css index 06c69485..15b105f4 100644 --- a/shine-UI/styles/components/dropdown-menu.css +++ b/shine-UI/styles/components/dropdown-menu.css @@ -1,12 +1,15 @@ :root { --z-overlay: 100; --z-dropdown: 110; --z-modal: 120; } .dropdown-portal { pointer-events: none; } .dropdown-backdrop { position: fixed; inset: 0; z-index: var(--z-overlay); pointer-events: auto; background: var(--scrim); } -.dropdown-menu { position: fixed; z-index: var(--z-dropdown); display: grid; gap: 2px; padding: 6px; min-width: 196px; max-width: calc(100vw - 20px); max-height: calc(100dvh - 20px); overflow-y: auto; border: 1px solid var(--border-subtle); border-radius: 20px; background: var(--surface); color: var(--text-primary); box-shadow: var(--shadow); pointer-events: auto; } -.dropdown-menu__item { width: 100%; min-height: 44px; padding: 10px 12px; display: flex; align-items: center; gap: 10px; border: 0; border-radius: 12px; background: transparent; color: var(--text-primary); font: inherit; font-size: .875rem; line-height: 1.4; text-align: left; cursor: pointer; } -.dropdown-menu__item:hover, .dropdown-menu__item.is-selected { background: var(--surface-selected); } +.dropdown-menu { position: fixed; z-index: var(--z-dropdown); display: grid; gap: 2px; padding: 6px; min-width: 196px; max-width: calc(100vw - 20px); max-height: calc(100dvh - 20px); overflow-y: auto; border: 1px solid var(--border-control); border-radius: 14px; background: var(--surface); color: var(--text-primary); box-shadow: var(--shadow); pointer-events: auto; } +.dropdown-menu__item { width: 100%; min-height: 44px; padding: 8px 10px; display: flex; align-items: center; gap: 10px; border: 0; border-radius: 8px; background: transparent; color: var(--text-primary); font: inherit; font-size: .875rem; line-height: 1.4; text-align: left; cursor: pointer; } +.dropdown-menu__item:hover { background: var(--surface-raised); } +.dropdown-menu__item.is-selected { background: var(--surface-selected); } .dropdown-menu__item:active { background: var(--surface-selected); } .dropdown-menu__item:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: -2px; } .dropdown-menu__item.is-danger { color: var(--danger); } .dropdown-menu__item:disabled { opacity: .5; cursor: not-allowed; } -.dropdown-menu__icon, .dropdown-menu__icon svg, .dropdown-menu__item > img { width: 22px; height: 22px; flex: 0 0 22px; object-fit: contain; color: currentColor; } -.dropdown-menu__divider { height: 1px; margin: 4px 8px; background: var(--border-subtle); } +.dropdown-menu__icon, .dropdown-menu__icon svg, .dropdown-menu__item > img { width: 21px; height: 21px; flex: 0 0 21px; object-fit: contain; } +.dropdown-menu__icon { color: var(--text-secondary); } +.dropdown-menu__item.is-danger .dropdown-menu__icon { color: var(--danger); } +.dropdown-menu__divider { height: 1px; margin: 5px 8px; background: var(--border-subtle); } diff --git a/shine-UI/styles/components/media-viewer.css b/shine-UI/styles/components/media-viewer.css new file mode 100644 index 00000000..2dbf6e15 --- /dev/null +++ b/shine-UI/styles/components/media-viewer.css @@ -0,0 +1,106 @@ +/* Полноэкранный просмотр фото и видео (js/components/media-viewer.js). Чёрный фон в обеих темах – как в галереях. */ +.media-viewer { + --viewer-dim: 1; + position: fixed; + inset: 0; + z-index: 130; + display: grid; + /* Слегка прозрачный фон; размытие не даёт ленте за ним отвлекать. */ + background: rgb(0 0 0 / calc(0.88 * var(--viewer-dim))); + -webkit-backdrop-filter: blur(10px); + backdrop-filter: blur(10px); + color: #fff; + touch-action: none; + animation: media-viewer-in 160ms ease-out; +} + +/* Фото и под ним ряд «1/3 ↓» – одной группой по центру экрана. */ +.media-viewer__stage { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: var(--space-3); + min-height: 0; + padding: calc(56px + env(safe-area-inset-top)) 0 calc(var(--space-4) + env(safe-area-inset-bottom)); + transition: transform 160ms ease-out; +} + +.media-viewer__frame { display: grid; place-items: center; min-height: 0; max-width: 100%; } + +.media-viewer__media { + display: block; + max-width: 100vw; + max-height: calc(100dvh - 56px - 72px - env(safe-area-inset-top) - env(safe-area-inset-bottom)); + object-fit: contain; + user-select: none; + -webkit-user-drag: none; +} + +.media-viewer__controls { display: flex; align-items: center; justify-content: center; gap: var(--space-4); min-height: 44px; } +.media-viewer__counter { color: rgb(255 255 255 / 85%); font-size: var(--text-md); font-variant-numeric: tabular-nums; } +.media-viewer__counter[hidden] { display: none; } + +.media-viewer__bar { + position: absolute; + top: 0; + left: 0; + right: 0; + z-index: 1; + display: flex; + align-items: center; + min-height: calc(56px + env(safe-area-inset-top)); + padding: env(safe-area-inset-top) var(--space-1) 0; + transition: opacity 160ms ease; +} + +.media-viewer__btn, +.media-viewer__nav { + display: grid; + place-items: center; + width: 44px; + height: 44px; + padding: 0; + border: 0; + border-radius: var(--radius-pill); + background: transparent; + color: #fff; + cursor: pointer; +} + +.media-viewer__btn svg { width: 22px; height: 22px; } +.media-viewer__btn:hover { background: rgb(255 255 255 / 12%); } +.media-viewer__btn--round { background: rgb(255 255 255 / 16%); } +.media-viewer__btn--round:hover { background: rgb(255 255 255 / 26%); } +.media-viewer__btn:focus-visible, +.media-viewer__nav:focus-visible { outline: 2px solid #fff; outline-offset: -2px; } + +/* Стрелки листания – для компьютера; на телефоне листают смахиванием. */ +.media-viewer__nav { + position: absolute; + top: 50%; + z-index: 1; + background: rgb(255 255 255 / 14%); + transform: translateY(-50%); + transition: opacity 160ms ease; +} + +.media-viewer__nav svg { width: 22px; height: 22px; } +.media-viewer__nav--prev { left: var(--space-3); } +.media-viewer__nav--next { right: var(--space-3); } +.media-viewer__nav[hidden] { display: none; } + +@media (hover: none) { + .media-viewer__nav { display: none; } +} + +/* Нажатие на фото прячет панель – смотреть без помех. */ +.media-viewer.is-bare :is(.media-viewer__bar, .media-viewer__nav, .media-viewer__controls) { opacity: 0; pointer-events: none; } +.media-viewer__controls { transition: opacity 160ms ease; } + +@keyframes media-viewer-in { from { opacity: 0; } } + +@media (prefers-reduced-motion: reduce) { + .media-viewer { animation: none; } + .media-viewer__stage { transition: none; } +} diff --git a/shine-UI/styles/components/modal.css b/shine-UI/styles/components/modal.css index 7be74e01..90629800 100644 --- a/shine-UI/styles/components/modal.css +++ b/shine-UI/styles/components/modal.css @@ -39,3 +39,25 @@ .confirm-dialog__text { margin: 0; color: var(--text-secondary); font-size: .9375rem; line-height: 1.375rem; overflow-wrap: anywhere; } .confirm-dialog__danger { color: #fff; background: var(--danger); } :root[data-theme='dark'] .confirm-dialog__danger { color: var(--background); } + +/* Шторка с заголовком (js/components/sheet.js) */ +.sheet__card { display: grid; gap: 0; padding: 12px 16px 18px; border-radius: 22px; } +.sheet__head { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-bottom: 10px; } +.sheet__title { margin: 0; font-size: 1rem; } +.sheet__close { width: 36px; height: 36px; min-width: 36px; padding: 0; display: grid; place-items: center; border: 0; border-radius: 10px; background: transparent; color: var(--text-secondary); } +.sheet__close svg { width: 22px; height: 22px; } +.sheet__close:hover { background: var(--surface-raised); color: var(--text-primary); } +.sheet__body { display: grid; gap: 12px; font-size: .875rem; line-height: 1.3125rem; } +.sheet__body > p { margin: 0; } +.sheet__footer { display: flex; gap: 8px; margin-top: 18px; } +.sheet__footer > button { flex: 1; min-height: 44px; } + +/* «Поделиться» (js/components/share-sheet.js) */ +.share-sheet__content { display: grid; gap: 12px; } +.share-sheet__preview { padding: 12px; border-radius: 12px; background: var(--background); font-size: .875rem; line-height: 1.3125rem; } +.share-sheet__preview strong { display: block; margin-bottom: 5px; color: var(--text-secondary); font-size: .75rem; font-weight: 500; } +.share-sheet__preview p { margin: 0; display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; overflow-wrap: anywhere; } +.share-sheet__label { display: grid; gap: 5px; color: var(--text-secondary); font-size: .75rem; } +.share-sheet__link { min-height: 44px; padding: 9px 10px; border: 1px solid var(--border-control); border-radius: 10px; background: var(--surface-raised); color: var(--text-primary); font: inherit; font-size: .875rem; } +.share-sheet__copy, .share-sheet__system { width: 100%; min-height: 44px; display: inline-flex; align-items: center; justify-content: center; gap: 8px; } +.share-sheet__copy svg, .share-sheet__system svg { width: 20px; height: 20px; } diff --git a/shine-UI/styles/components/overflow-dots.css b/shine-UI/styles/components/overflow-dots.css index c4ccdf37..c2b25858 100644 --- a/shine-UI/styles/components/overflow-dots.css +++ b/shine-UI/styles/components/overflow-dots.css @@ -1,15 +1,15 @@ /* Shared overflow-dots trigger. */ /* ===== UI cleanup: main tabs, shared overflow menu and DM list (2026-08-22) ===== */ -/* Единое вертикальное троеточие для всех overflow/menu-кнопок. */ +/* Единое горизонтальное троеточие для всех overflow/menu-кнопок (как иконка more в ui-icon.js). */ .app-overflow-dots { - width: 8px; + width: 24px; height: 24px; display: inline-flex; - flex-direction: column; + flex-direction: row; align-items: center; justify-content: center; - gap: 3.5px; + gap: 4.8px; color: inherit; pointer-events: none; } @@ -17,14 +17,11 @@ .app-overflow-dots i { display: block; - width: 4px; - height: 4px; - flex: 0 0 4px; + width: 3.2px; + height: 3.2px; + flex: 0 0 3.2px; border-radius: 50%; background: currentColor; - box-shadow: - 0 0 5px color-mix(in srgb, var(--accent) 72%, transparent), - 0 0 10px color-mix(in srgb, var(--accent) 34%, transparent); } diff --git a/shine-UI/styles/components/primitives.css b/shine-UI/styles/components/primitives.css index e8450264..627ca9d8 100644 --- a/shine-UI/styles/components/primitives.css +++ b/shine-UI/styles/components/primitives.css @@ -604,3 +604,51 @@ body { overflow-x: hidden; } .empty-note { padding: var(--space-5) var(--space-4); text-align: center; color: var(--text-secondary); font-size: var(--text-sm); line-height: var(--leading-sm, 1.45); } .action-pair { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-2); } + + +/* Переключатель: . */ +.switch { + appearance: none; + -webkit-appearance: none; + flex: 0 0 auto; + width: 48px; + height: 28px; + margin: 0; + padding: 2px; + border: 1px solid var(--border-control); + border-radius: var(--radius-pill); + background: var(--surface-selected); + cursor: pointer; + transition: background-color var(--duration-fast) ease, border-color var(--duration-fast) ease; +} + +.switch::after { + content: ''; + display: block; + width: 22px; + height: 22px; + border-radius: 50%; + background: var(--text-secondary); + box-shadow: var(--shadow-sm); + transition: transform var(--duration-fast) ease, background-color var(--duration-fast) ease; +} + +.switch:checked { + border-color: var(--accent); + background: var(--accent); +} + +.switch:checked::after { + transform: translateX(20px); + background: var(--on-accent); +} + +.switch:focus-visible { + outline: 2px solid color-mix(in srgb, var(--accent) 82%, transparent); + outline-offset: 3px; +} + +.switch:disabled { + cursor: default; + opacity: .55; +} diff --git a/shine-UI/styles/components/tabs.css b/shine-UI/styles/components/tabs.css index 5483747b..b4188aeb 100644 --- a/shine-UI/styles/components/tabs.css +++ b/shine-UI/styles/components/tabs.css @@ -1,7 +1,9 @@ /* Shared tab geometry and tab primitives. */ +/* Переключатель той же высоты, что поле ввода и поиск (44 px), кнопки внутри – 34 px. */ .tabs { - min-height: 44px; + box-sizing: border-box; + min-height: var(--control-height); display: grid; grid-template-columns: repeat(2, 1fr); gap: 4px; @@ -12,13 +14,20 @@ } .tabs--three { grid-template-columns: repeat(3, minmax(0, 1fr)); } .tabs--auto { grid-template-columns: none; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); } +/* Много коротких пунктов (4–5) в одну полосу: мельче шрифт и поля. */ +.tabs--dense { display: flex; gap: 2px; } +.tabs--dense .tab-btn { flex: 1 1 auto; min-width: 0; padding: 0 6px; font-size: var(--text-sm); white-space: nowrap; } +@media (max-width: 360px) { + .tabs--dense .tab-btn { padding: 0 4px; font-size: var(--text-xs); } +} .tab-btn { - min-height: 44px; + min-height: 34px; border: 0; background: transparent; - border-radius: 9px; - padding: 8px; + border-radius: 8px; + padding: 0 8px; + font-size: var(--text-md); color: var(--text-muted); cursor: pointer; } diff --git a/shine-UI/styles/components/topbar.css b/shine-UI/styles/components/topbar.css index 5124c1fe..2dff3c18 100644 --- a/shine-UI/styles/components/topbar.css +++ b/shine-UI/styles/components/topbar.css @@ -1,5 +1,5 @@ :root { --app-topbar-base-height: 56px; --app-topbar-title-size: 1.0625rem; --app-topbar-bg: var(--background); --app-topbar-fg: var(--text-primary); --app-topbar-gold: var(--text-primary); --app-topbar-blue-glow: transparent; --app-topbar-blue-glow-soft: transparent; } -.topbar { width: 100%; min-height: calc(56px + env(safe-area-inset-top)); padding: env(safe-area-inset-top) 0 0; display: grid; grid-template-columns: minmax(44px, 1fr) minmax(0, auto) minmax(44px, 1fr); align-items: center; gap: 4px; background: var(--background); } +.topbar { width: 100%; min-height: calc(56px + env(safe-area-inset-top)); padding: env(safe-area-inset-top) 0 0; display: grid; grid-template-columns: minmax(44px, 1fr) minmax(0, auto) minmax(44px, 1fr); align-items: center; gap: 4px; background: var(--surface); border-bottom: 1px solid var(--border-subtle); } .topbar__left, .topbar__center, .topbar__right { display: flex; min-width: 0; align-items: center; } .topbar__center { justify-content: center; } .topbar__right { justify-content: flex-end; } @@ -15,6 +15,14 @@ .header-icon-svg { display: block; width: 22px; height: 22px; } .topbar__back svg { width: 24px; height: 24px; stroke-width: 2.2; } .topbar__action svg { width: 22px; height: 22px; } -.topbar--root { grid-template-columns: auto minmax(0, 1fr) auto; } -.topbar--root .topbar__center { justify-content: flex-start; } -.topbar--root .topbar__title { font-size: 1.5rem; line-height: 1.875rem; } +/* Корневые разделы (Чаты, Каналы, Связи, Уведомления, Профиль) – заголовок по центру, как на всех экранах, но крупнее. */ +.topbar--root .topbar__title { font-size: 1.5rem; line-height: 1.875rem; font-weight: 700; } + +/* Шапка-визитка: аватар и две строки слева (канал, собеседник) */ +.topbar--identity { grid-template-columns: auto minmax(0, 1fr) auto; } +.topbar--identity .topbar__center { justify-content: flex-start; } +.topbar-identity { display: flex; align-items: center; gap: 10px; min-width: 0; max-width: 100%; min-height: 44px; padding: 0 4px; border: 0; border-radius: 12px; background: transparent; color: var(--text-primary); font: inherit; text-align: left; cursor: pointer; } +.topbar-identity:disabled { cursor: default; } +.topbar-identity__text { display: grid; min-width: 0; } +.topbar-identity__title { font-size: 1rem; line-height: 1.3; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } +.topbar-identity__sub { margin-top: 2px; color: var(--text-secondary); font-size: .75rem; line-height: 1.125rem; font-weight: 400; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } diff --git a/shine-UI/styles/features/channel-thread.css b/shine-UI/styles/features/channel-thread.css index d3c543f6..d8211831 100644 --- a/shine-UI/styles/features/channel-thread.css +++ b/shine-UI/styles/features/channel-thread.css @@ -1,7 +1,44 @@ -/* Ветка сохраняет ширину текста на любой глубине. */ +/* Обсуждение (макет V4): контекст записи, «Комментарии · N», плоский список, строка ввода. */ +.channels-screen--thread { gap: 0; } .thread-block { display: grid; gap: 0; min-width: 0; } -.thread-node-level { margin-left: 0; } -.thread-block--replies > .section-title { padding: 16px 0 8px; margin: 0; color: var(--text-secondary); font-size: .875rem; font-weight: 600; } -.thread-node-heading { color: var(--text-secondary); font-size: .8125rem; } -.thread-node-card .channel-message-avatar.avatar { width: 32px; height: 32px; min-width: 32px; min-height: 32px; } -.thread-history-divider { border-top: 1px solid var(--border-subtle); margin: 8px 0; } +.thread-context { padding: 10px 0 8px; border-bottom: 1px solid var(--border-subtle); font-size: .875rem; line-height: 1.25rem; } +.thread-block--ancestors .thread-context { opacity: .8; } +.thread-context__text { margin: 0; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; white-space: pre-wrap; overflow-wrap: anywhere; } +.thread-context.is-expanded .thread-context__text { display: block; } +.thread-context__meta { display: flex; align-items: center; gap: 12px; min-height: 32px; color: var(--text-secondary); font-size: .75rem; } +.thread-context__expand, .thread-context__open { min-height: 32px; padding: 0 4px; border: 0; background: transparent; color: var(--action); font: inherit; font-size: .75rem; cursor: pointer; } +.thread-context__open { margin-left: auto; display: inline-flex; align-items: center; gap: 4px; } +.thread-context__open svg { width: 14px; height: 14px; } + +.thread-section-title { margin: 12px 0 4px; font-size: .8125rem; font-weight: 600; color: var(--text-primary); } +.channels-screen .thread-comment { display: block; margin: 0 calc(-1 * var(--page-gutter)); padding: 7px var(--page-gutter) 5px; border: 0; border-radius: 0; background: transparent; scroll-margin: 16px; } +.channels-screen .thread-comment + .thread-comment { border-top: 1px solid var(--divider-soft); } +.thread-comment.is-highlight { background: var(--surface-selected); box-shadow: inset 3px 0 var(--accent); } +.thread-comment__person { display: flex; align-items: center; gap: 7px; min-height: 26px; margin-bottom: 4px; font-size: .875rem; font-weight: 600; } +.thread-comment__who { display: inline-flex; align-items: center; gap: 7px; min-width: 0; padding: 0; border: 0; background: transparent; color: var(--text-primary); font: inherit; cursor: pointer; } +.thread-comment__who .avatar.thread-comment__avatar { width: 24px; height: 24px; min-width: 24px; min-height: 24px; font-size: 11px; } +.thread-comment__name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; } +.thread-comment__badge { padding: 1px 5px; border-radius: 5px; background: var(--surface-selected); color: var(--action); font-size: .625rem; font-weight: 400; white-space: nowrap; } +.thread-comment__person time { margin-left: auto; flex-shrink: 0; color: var(--text-secondary); font-size: .75rem; font-weight: 400; } +.thread-comment__text { margin: 0; font-size: .9375rem; line-height: 1.4375rem; white-space: pre-wrap; overflow-wrap: anywhere; } +.thread-comment__actions { display: flex; align-items: center; gap: 12px; margin-top: 2px; color: var(--text-secondary); } +.thread-comment__actions > button { min-height: 32px; min-width: 32px; padding: 0 4px; display: inline-flex; align-items: center; gap: 5px; border: 0; border-radius: 8px; background: transparent; color: inherit; font: inherit; font-size: .75rem; cursor: pointer; } +.thread-comment__actions .thread-comment__reply { padding-left: 0; color: var(--action); } +.thread-comment__actions svg { width: 21px; height: 21px; } +.thread-comment__actions .thread-comment__more { margin-left: auto; } +.thread-comment__actions .thread-comment__more svg { width: 24px; height: 24px; } + +.thread-quote { display: block; width: 100%; margin: 0 0 7px; padding: 5px 9px; border: 0; border-left: 2px solid var(--quote-line); border-radius: 0 6px 6px 0; background: var(--quote-bg); color: var(--text-secondary); font: inherit; font-size: .75rem; line-height: 1.125rem; text-align: left; cursor: pointer; } +.thread-quote strong { display: block; color: var(--action); font-weight: 500; } +.thread-quote span { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; } +button.thread-quote:hover { background: var(--surface); } +.thread-return { position: fixed; left: 50%; bottom: calc(96px + env(safe-area-inset-bottom)); transform: translateX(-50%); z-index: 5; padding: 9px 12px; border: 1px solid var(--border-subtle); border-radius: 20px; background: var(--surface-raised); color: var(--text-primary); font: inherit; font-size: .75rem; white-space: nowrap; cursor: pointer; } +.thread-empty { padding: 36px 20px; text-align: center; } + +.thread-composer { display: grid; gap: 8px; } +.thread-replying { display: flex; gap: 8px; align-items: flex-start; } +.thread-replying[hidden] { display: none; } +.thread-replying .thread-quote { margin: 0; min-width: 0; cursor: default; } +.thread-replying__cancel { width: 32px; height: 32px; flex-shrink: 0; padding: 0; display: grid; place-items: center; border: 0; background: transparent; color: var(--text-secondary); cursor: pointer; } +.thread-replying__cancel svg { width: 20px; height: 20px; } +.thread-composer__emoji { max-height: 260px; overflow: auto; } diff --git a/shine-UI/styles/features/channel.css b/shine-UI/styles/features/channel.css index 0c82a705..2e26fd99 100644 --- a/shine-UI/styles/features/channel.css +++ b/shine-UI/styles/features/channel.css @@ -6,10 +6,11 @@ .channels-screen .channel-message-card.is-focus-flash { background: var(--surface-selected); } .channel-system-event-card { padding: 8px; margin: 8px auto; width: fit-content; max-width: 100%; color: var(--text-secondary); font-size: .75rem; text-align: center; } .channel-meta-details-grid { display: grid; grid-template-columns: auto minmax(0,1fr); gap: 8px; overflow-wrap: anywhere; } -.channel-profile-avatar { width: 96px; height: 96px; border-radius: 50%; overflow: hidden; } +.channel-profile-avatar { width: var(--channel-avatar-size, 96px); height: var(--channel-avatar-size, 96px); min-width: var(--channel-avatar-size, 96px); border-radius: calc(var(--channel-avatar-size, 96px) * .28); overflow: hidden; color: var(--accent); font-size: calc(var(--channel-avatar-size, 96px) * .5); } .channel-profile-avatar img { width: 100%; height: 100%; object-fit: cover; } .channel-profile-modal-head { display: flex; gap: 12px; align-items: center; } -.channel-main-action { min-height: 44px; border-radius: 12px; padding: 10px 16px; color: var(--on-accent); background: var(--accent); } +.channel-main-action { width: 100%; min-height: 44px; display: inline-flex; align-items: center; justify-content: center; gap: 8px; border-radius: 12px; padding: 0 16px; color: var(--on-accent); background: var(--accent); font-weight: 600; } +.channel-main-action svg { width: 20px; height: 20px; } .channel-back-btn { min-height: 44px; color: var(--accent); } .entrypoint-history-list { display: grid; gap: 8px; max-height: 58vh; overflow: auto; } .entrypoint-history-item { display: grid; gap: 8px; text-align: left; padding: 12px; border-radius: 12px; background: var(--surface); color: var(--text-primary); } @@ -24,7 +25,7 @@ .channel-about-hero { display: grid; justify-items: center; gap: 4px; padding: 8px 16px 0; text-align: center; } .channel-about-avatar-slot { margin-bottom: 8px; } -.channel-about-avatar.avatar { width: 88px; height: 88px; min-width: 88px; min-height: 88px; font-size: 32px; } +.channel-about-avatar.avatar { width: 80px; height: 80px; min-width: 80px; min-height: 80px; border-radius: 24px; font-size: 36px; color: var(--accent); } .channel-about-title { margin: 0; color: var(--text-primary); font-size: 1.375rem; line-height: 1.75rem; font-weight: 600; overflow-wrap: anywhere; } .channel-about-subline { color: var(--text-secondary); font-size: .875rem; line-height: 1.25rem; overflow-wrap: anywhere; } @@ -416,3 +417,4 @@ grid-column: 1 / -1; } } +.channel-about-tiles:empty { display: none; } diff --git a/shine-UI/styles/features/channels-common.css b/shine-UI/styles/features/channels-common.css index 25d0be32..9827bc6c 100644 --- a/shine-UI/styles/features/channels-common.css +++ b/shine-UI/styles/features/channels-common.css @@ -42,7 +42,8 @@ .deleted-message-pill { min-height: 44px; text-align: left; color: var(--text-secondary); padding: 8px 0; } .channel-header-title, .channel-header-owner { display: block; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .channel-header-owner { color: var(--text-secondary); font-size: .75rem; line-height: 1rem; font-weight: 400; } -.channel-composer { display: flex; gap: 8px; padding: 8px 0; background: var(--background); } +/* Нижняя панель экранов канала: поверхность с линией сверху, как шапка */ +.channel-composer { display: flex; gap: 8px; margin: 0 -12px; padding: 9px 12px calc(11px + env(safe-area-inset-bottom)); background: var(--surface); border-top: 1px solid var(--border-subtle); } .channel-compose-bar { width: 100%; min-height: 44px; @@ -77,29 +78,36 @@ .thread-reply-context { color: var(--text-secondary); font-size: .75rem; line-height: 1.125rem; border-left: 2px solid var(--border-control); padding-left: 10px; overflow-wrap: anywhere; } @media (prefers-reduced-motion: reduce) { .channels-screen *, .channel-composer * { animation: none; scroll-behavior: auto; transition: none; } } -.channels-screen .channel-message-card.channel-message-card--owner { - gap: 6px; - margin: 0 0 8px; - padding: 10px 12px 2px 14px; - border: 1px solid var(--border-subtle); - border-radius: 16px; - background: var(--surface); - justify-self: start; - width: fit-content; - min-width: min(100%, 17rem); - max-width: 100%; -} -.channels-screen .channel-message-card--owner:has(.message-attachment-carousel) { width: 100%; } +/* Запись автора в его канале (макет V4): плоская, на всю ширину, между записями — линия с отступами */ +.channels-screen .channel-message-card.channel-message-card--owner { gap: 0; margin: 0; padding: 20px 0 8px; border: 0; position: relative; } +.channels-screen .channel-message-card--owner + .channel-message-card--owner::before { content: ''; position: absolute; top: 0; left: 0; right: 0; height: 1px; background: var(--border-subtle); } +.channels-screen .channel-message-card--owner .channel-message-body { font-size: 1rem; line-height: 1.52; } .channel-message-card--owner .channel-message-head-row[hidden] { display: none; } -.channel-message-card--owner .channel-message-body { line-height: 1.375rem; } -.channel-message-card--owner .channel-message-actions { gap: 0; margin-left: -8px; flex-wrap: nowrap; } -.channel-message-card--owner .channel-action-item { min-width: 40px; min-height: 40px; padding: 6px 8px; gap: 4px; } -.channel-message-card--owner .channel-action-icon svg { width: 20px; height: 20px; } -.channel-message-meta { display: flex; align-items: center; gap: 0; margin-left: auto; min-width: 0; } +.channel-message-card--owner .message-attachment-carousel { width: calc(100% + 2 * var(--page-gutter)); max-width: none; margin: 0 calc(-1 * var(--page-gutter)) 14px; } +.channel-message-card--owner .message-attachment-carousel-viewport { border: 0; border-radius: 0; } +.topbar-identity .avatar.channel-profile-avatar { --channel-avatar-size: 40px; width: 40px; height: 40px; min-width: 40px; min-height: 40px; font-size: 22px; border-radius: 11px; } +.channel-message-card--owner .channel-message-actions { gap: 0; margin: 6px -8px 0; min-height: 50px; flex-wrap: nowrap; } +/* Равный шаг иконок: каждое действие – ячейка 56 px, иконка у левого края, счётчик внутри ячейки (влезает и «999»). */ +.channel-message-card--owner .channel-action-item { width: 56px; min-width: 56px; min-height: 44px; padding: 0 0 0 8px; gap: 5px; justify-content: flex-start; border-radius: 10px; font-variant-numeric: tabular-nums; } +.channel-message-card--owner .channel-action-discussion { width: auto; padding-right: 8px; } +.channel-message-card--owner .channel-action-icon svg { width: 23px; height: 23px; } +.channel-message-card--owner .channel-action-share .channel-action-icon svg { width: 25px; height: 25px; } +.channel-action-item.is-liked svg { fill: currentColor; } +.channel-action-faces { display: inline-flex; align-items: center; margin-left: 2px; padding-right: 3px; } +.channel-action-faces .avatar.channel-action-face { width: 22px; height: 22px; min-width: 22px; min-height: 22px; font-size: 10px; border: 2px solid var(--background); } +.channel-action-faces .channel-action-face + .channel-action-face { margin-left: -6px; } +.channel-message-meta { display: flex; align-items: center; gap: var(--space-1); margin-left: auto; min-width: 0; padding-left: 4px; } .channel-message-meta .channel-message-time { white-space: nowrap; } .channel-message-meta .channel-message-time::before { content: none; } -.channel-message-meta .channel-message-more { width: 40px; height: 40px; min-height: 40px; margin: 0 -4px 0 0; padding: 0; font-size: 20px; } -.channel-message-card--owner .attachment-carousel, -.channel-message-card--owner [class*='attachment'] { border-radius: 12px; } +.channel-message-meta .channel-message-more { display: inline-grid; place-items: center; width: 36px; height: 44px; min-height: 44px; margin: 0 -4px 0 0; padding: 0; } +.channel-message-more svg { display: block; width: 20px; height: 20px; } +@media (max-width: 360px) { .channel-message-card--owner .channel-action-item { width: 50px; min-width: 50px; } .channel-message-meta .channel-message-time { font-size: .6875rem; } } + +/* Нижняя панель ленты: «Новая запись» у владельца, «Подписаться» у читателя */ +.channel-new-post { width: 100%; min-height: 44px; display: inline-flex; align-items: center; justify-content: center; gap: 8px; border: 0; border-radius: 12px; background: var(--surface-selected); color: var(--action); font: inherit; font-weight: 600; cursor: pointer; } +.channel-new-post svg { width: 21px; height: 21px; } +.channel-new-post:hover { background: color-mix(in srgb, var(--surface-selected) 85%, var(--text-primary)); } +.channel-new-post:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; } .channels-screen--channel, .channels-screen--thread { padding-bottom: 8px; } +.channel-message-card--owner .message-attachment-media { height: auto; max-height: 70vh; object-fit: cover; } diff --git a/shine-UI/styles/features/channels-list.css b/shine-UI/styles/features/channels-list.css index 8351eb4f..43015cef 100644 --- a/shine-UI/styles/features/channels-list.css +++ b/shine-UI/styles/features/channels-list.css @@ -24,6 +24,7 @@ .channels-list-controls { display: grid; gap: 12px; + padding-top: var(--page-top-gap); } .channels-inline-search { diff --git a/shine-UI/styles/features/chat.css b/shine-UI/styles/features/chat.css index b7149391..7b8b93f5 100644 --- a/shine-UI/styles/features/chat.css +++ b/shine-UI/styles/features/chat.css @@ -850,26 +850,19 @@ /* Поле сообщения занимает почти всю ширину; действия прижаты к правому краю. */ -.composer-slot:has(> .dm-chat-input) { - padding-left: 0; - padding-right: 4px; -} +/* Нижняя панель чата — поверхность с линией сверху, как у канала и обсуждения */ .dm-chat-input { grid-template-columns: minmax(0, 1fr) auto; align-items: end; position: relative; z-index: 10; - margin-inline: 0; - padding: 10px 0; - border-top: 0; - background: transparent; - backdrop-filter: none; - -webkit-backdrop-filter: none; - gap: 4px; - padding-left: 0; - padding-right: 0; + margin-inline: calc(-1 * var(--page-gutter)); + padding: 9px var(--page-gutter) calc(11px + env(safe-area-inset-bottom)); + border-top: 1px solid var(--border-subtle); + background: var(--surface); + gap: 6px; } @@ -891,98 +884,16 @@ -.chat-header-peer-btn { - width: 100%; - min-width: 0; - min-height: 46px; - padding: 2px 0; - border-radius: 12px; - display: flex; - align-items: center; - justify-content: flex-start; - gap: 7px; - text-align: left; - cursor: pointer; -} - - -.chat-header-peer-btn .chat-header-avatar-slot { - flex: 0 0 40px; -} - - -.chat-header-peer-text { - min-width: 0; - display: flex; - flex-direction: column; - align-items: flex-start; - justify-content: center; - gap: 2px; -} - - -.chat-header-peer-name, -.chat-header-peer-meta { - display: block; - max-width: 100%; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} - - -.chat-header-peer-name { - font-size: 14px; - line-height: 1.15; - font-weight: 650; - color: var(--text-primary); -} - - -.chat-header-peer-meta { - font-size: 11px; - line-height: 1.15; - font-weight: 500; - color: var(--text-secondary); -} - - -/* ===== DM header regression fix (2026-09-02) ===== - * The peer identity button intentionally spans the whole free header area. - * Its avatar uses a 119% glass overlay, so neither the center cell nor the - * button may clip overflow. Text keeps its own ellipsis boundary instead. - */ - - -.chat-header-peer-btn { - overflow: visible; - padding-inline: 2px; -} - - -.chat-header-peer-btn .chat-header-avatar-slot { - width: 44px; - height: 44px; - min-width: 44px; - min-height: 44px; - flex: 0 0 44px; - overflow: visible; -} - - -.chat-header-peer-btn .chat-header-avatar-slot .chat-header-avatar { - overflow: visible; -} - - -.chat-header-peer-text { - flex: 1 1 auto; - overflow: hidden; -} +/* Шапка чата — общая «визитка» (topbar.css .topbar-identity). У аватара стеклянный ободок на 119%, + * поэтому ни кнопка, ни слот аватара не обрезают содержимое; текст обрезается сам. */ +.chat-header-peer-btn { width: 100%; overflow: visible; } +.chat-header-peer-btn .chat-header-avatar-slot { width: 36px; height: 36px; min-width: 36px; flex: 0 0 36px; overflow: visible; } +.chat-header-peer-btn .chat-header-avatar-slot .avatar.chat-header-avatar { width: 36px; height: 36px; min-width: 36px; min-height: 36px; overflow: visible; } +.chat-header-peer-text { flex: 1 1 auto; overflow: hidden; } /* Shell state + Chat-owned composer adjustment (moved out of app-shell.css). */ .app-shell--scroll-nested.keyboard-open .composer-slot .dm-chat-input { - padding-bottom: 0; + padding-bottom: 9px; } @@ -1393,35 +1304,28 @@ margin-top: 2px; } -.chat-header-peer-btn { border: 0; background: transparent; color: inherit; font: inherit; } -.chat-header-peer-btn:hover { background: var(--surface); } -.chat-header-peer-btn:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: -2px; } -.chat-header-peer-name { font-size: var(--text-md); font-weight: var(--weight-bold); } -.chat-header-peer-meta { font-size: var(--text-xs); } .dm-chat-screen .bubble { - max-width: min(80%, 34rem); - padding: 8px 12px 6px; - border-radius: var(--radius-lg); + max-width: min(85%, 34rem); + padding: 10px 12px 7px; + border-radius: 17px; color: var(--text-primary); - font-size: var(--text-md); - line-height: var(--leading-md); + font-size: .9375rem; + line-height: 1.375rem; box-shadow: none; + overflow-wrap: anywhere; } -.dm-chat-screen .bubble.in { - background: var(--surface); - border: 1px solid var(--border-subtle); - border-bottom-left-radius: var(--radius-xs); - border-top-left-radius: var(--radius-lg); -} -.dm-chat-screen .bubble.out { - background: color-mix(in srgb, var(--accent) 24%, var(--surface)); - border: 1px solid color-mix(in srgb, var(--accent) 30%, var(--border-subtle)); - border-bottom-right-radius: var(--radius-xs); - border-top-right-radius: var(--radius-lg); -} -.dm-chat-screen .bubble-meta { font-size: .6875rem; line-height: 1rem; color: var(--text-secondary); } -.dm-chat-screen .bubble-status--read { color: var(--accent); } +.dm-chat-screen .bubble.in { background: var(--surface); border-bottom-left-radius: 5px; } +.dm-chat-screen .bubble.out { background: var(--bubble-out); border-bottom-right-radius: 5px; } +/* Время и статус — в конце последней строки (эксперимент V4, принят); не влезают — переносятся */ +.dm-chat-screen .bubble-text { display: inline; } +.dm-chat-screen .bubble-meta { float: right; margin: 5px 0 0 10px; display: inline-flex; align-items: center; gap: 4px; font-size: .6875rem; line-height: 1rem; color: color-mix(in srgb, var(--text-secondary) 70%, var(--text-primary)); } +.dm-chat-screen .bubble::after { content: ''; display: table; clear: both; } +.dm-chat-screen .bubble-status { display: inline-flex; min-width: 0; color: inherit; text-shadow: none; } +.dm-chat-screen .bubble-status svg { width: 16px; height: 16px; } +.dm-chat-screen .bubble-status--read { color: var(--action); } +.dm-chat-screen .bubble-status--failed { color: var(--danger); } +.dm-chat-screen .bubble-delivery-note { clear: both; } .dm-day-separator { display: flex; justify-content: center; margin: 8px 0; } .dm-day-separator span { padding: 3px 10px; border-radius: var(--radius-pill); color: var(--text-secondary); background: var(--surface); border: 1px solid var(--border-subtle); font-size: var(--text-xs); line-height: var(--leading-xs); } @@ -1431,7 +1335,7 @@ border: 1px solid var(--border-control); border-radius: 22px; color: var(--text-primary); - background: var(--surface); + background: var(--surface-raised); text-shadow: none; caret-color: var(--accent); font-size: 1rem; diff --git a/shine-UI/styles/features/developer-tools.css b/shine-UI/styles/features/developer-tools.css index 20486b5f..d9fab676 100644 --- a/shine-UI/styles/features/developer-tools.css +++ b/shine-UI/styles/features/developer-tools.css @@ -200,3 +200,7 @@ .arweave-uploads-menu-btn .app-overflow-dots { margin: auto; } + +/* Проверка Solana RPC: длинные адреса узлов переносятся, а не раздвигают экран */ +.solana-rpc-card { min-width: 0; } +.solana-rpc-url, .solana-rpc-details { min-width: 0; overflow-wrap: anywhere; } diff --git a/shine-UI/styles/features/devices.css b/shine-UI/styles/features/devices.css index bf7c5e14..ff7f18c3 100644 --- a/shine-UI/styles/features/devices.css +++ b/shine-UI/styles/features/devices.css @@ -151,13 +151,17 @@ } +/* QR для второго устройства: по центру карточки, во всю доступную ширину до 280 px. + * Фон всегда светлый — тёмный QR на тёмном фоне камеры читают плохо. */ .qr-image { - width: 64px; - height: 64px; - border-radius: 8px; + width: min(280px, 100%); + aspect-ratio: 1; + padding: 12px; + border-radius: 16px; border: 1px solid var(--border-subtle); - background: var(--text-primary); + background: #ffffff; } +.qr-image svg { display: block; width: 100%; height: 100%; } /* Pairing approve/reject use their semantic button roles; legacy green/red surfaces were not observable in Stage 3.1. */ diff --git a/shine-UI/styles/features/messages.css b/shine-UI/styles/features/messages.css index e326b891..c74fa5fe 100644 --- a/shine-UI/styles/features/messages.css +++ b/shine-UI/styles/features/messages.css @@ -757,7 +757,7 @@ button.dm-via-node:hover { border-color: color-mix(in srgb, var(--rel-link) 50%, .dm-row-time { font-size: var(--text-xs); font-weight: 400; color: var(--text-secondary); } .dm-contact-note { flex-shrink: 0; padding: 0; border: 0; border-radius: 0; background: none; color: var(--rel-contact); font-size: var(--text-xs); font-weight: var(--weight-medium); } .dm-contact-note--close_friend { color: var(--rel-family); } -.dm-filter-row { margin-bottom: var(--space-1); } +.dm-filter-row { margin: 0 0 var(--space-1); } .dm-row-meta-col { align-self: stretch; display: flex; flex-direction: column; align-items: flex-end; justify-content: center; gap: 6px; } .dm-row-meta-line { display: flex; align-items: center; gap: 0; } .dm-unread-badge { min-width: 20px; height: 20px; padding: 0 6px; display: grid; place-items: center; border-radius: var(--radius-pill); color: var(--on-accent); background: var(--accent); border: 0; font-size: var(--text-xs); font-weight: var(--weight-bold); } @@ -766,6 +766,4 @@ button.dm-via-node:hover { border-color: color-mix(in srgb, var(--rel-link) 50%, .dm-divider::before, .dm-divider::after { content: none; } .contact-search-results { gap: 0; margin-top: var(--space-3); } .contact-search-results .contact-search-results-title { margin: 0 0 var(--space-1); color: var(--text-secondary); font-size: var(--text-xs); } -.dm-filter-row { gap: 6px; } -.dm-filter-row .chip { padding: 0 12px; } .dm-row-last-message.is-encrypted { font-style: italic; } diff --git a/shine-UI/styles/features/notifications.css b/shine-UI/styles/features/notifications.css index 99a9445f..774d9c26 100644 --- a/shine-UI/styles/features/notifications.css +++ b/shine-UI/styles/features/notifications.css @@ -1,203 +1,88 @@ -/* Notifications feature styles. */ +/* Уведомления: плоский список как в чатах – аватар, имя и время, ниже текст; тонкие разделители от текста. */ +.notifications-screen { align-content: start; } +.notifications-screen .notification-feed-tabs { margin-bottom: var(--space-1); } -/* ===== Notifications glass style ===== */ -.notifications-screen { - position: relative; - isolation: isolate; - color: var(--text-primary); - min-height: 100%; - align-content: start; -} +.notifications-list { display: grid; } - -.notifications-screen::before { - content: ""; - position: absolute; - inset: -12px -12px 0; - z-index: -1; - pointer-events: none; - background: - radial-gradient(320px 320px at 86% 12%, color-mix(in srgb, var(--rel-contact) 20%, transparent), transparent 72%), - radial-gradient(280px 280px at 18% 82%, color-mix(in srgb, var(--rel-contact) 14%, transparent), transparent 72%), - radial-gradient(260px 260px at 70% 65%, color-mix(in srgb, var(--warning) 12%, transparent), transparent 75%), - var(--surface); -} - - -.notifications-screen .tabs { - background: var(--surface); - backdrop-filter: blur(18px); - -webkit-backdrop-filter: blur(18px); - border: 1px solid transparent; - border-radius: 16px; -} - - -.notifications-screen .tab-btn { - color: var(--text-secondary); -} - - -.notifications-screen .tab-btn.active { - background: color-mix(in srgb, var(--warning) 12%, transparent); - border: 1px solid transparent; - color: var(--warning); -} - - -.notifications-screen .notifications-list > .card { - background: var(--surface); - backdrop-filter: blur(24px); - -webkit-backdrop-filter: blur(24px); - border: 1px solid var(--border-subtle); - border-radius: 20px; - box-shadow: 0 0 60px color-mix(in srgb, var(--accent) 12%, transparent); -} -.notifications-screen::before { - content: none; -} - - -/* Contacts overflow menu body portal: avoids topbar overflow hit-testing on desktop/Android. */ - - -/* ===== Notifications: social event cards ===== */ -.notifications-screen .notification-card { - gap: 10px; -} - - -.notification-identity { - display: flex; - align-items: center; - gap: 10px; - min-width: 0; -} - - -.notification-avatar { - width: 40px; - height: 40px; - min-width: 40px; - min-height: 40px; - flex: 0 0 auto; -} - - -.notification-identity-text { - min-width: 0; - flex: 1 1 auto; -} - - -.notification-identity-primary { - display: flex; - align-items: baseline; - gap: 6px; - min-width: 0; - flex-wrap: wrap; -} - - -.notification-person-name { - color: var(--text-primary); - font-weight: 700; - overflow-wrap: anywhere; -} - - -.notification-login, -.notification-time-separator, -.notification-time { - color: var(--text-secondary); - font-size: 12px; -} - - -.notification-action, -.notification-content { +.notification-group-title { margin: 0; -} - - -.notification-action { + padding: var(--space-3) 0 var(--space-1); color: var(--text-secondary); - font-size: 13px; + font-size: var(--text-xs); + line-height: var(--leading-xs); + font-weight: var(--weight-bold); } +.notification-card { + position: relative; + display: grid; + grid-template-columns: 40px minmax(0, 1fr); + gap: var(--space-3); + padding: var(--space-3) 0 0; + border-radius: var(--radius-md); +} -.notification-content { +.notification-avatar { width: 40px; height: 40px; min-width: 40px; min-height: 40px; } + +.notification-card__body { + display: grid; + gap: 2px; + min-width: 0; + padding-bottom: var(--space-3); + border-bottom: 1px solid var(--divider-soft); +} + +.notification-card__head { display: flex; align-items: baseline; gap: var(--space-2); min-width: 0; } + +.notification-card__name { + flex: 1 1 auto; + min-width: 0; color: var(--text-primary); - font-size: 15px; - line-height: 1.45; + font-size: var(--text-md); + font-weight: var(--weight-bold); + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.notification-card__time { flex: 0 0 auto; color: var(--text-secondary); font-size: var(--text-xs); } + +/* Непрочитанное: точка-акцент перед временем. */ +.notification-card--new .notification-card__time::before { + content: ""; + display: inline-block; + width: 7px; + height: 7px; + margin-right: 6px; + border-radius: 50%; + background: var(--accent); + vertical-align: 1px; +} + +.notification-card__action { margin: 0; color: var(--text-secondary); font-size: var(--text-sm); line-height: var(--leading-sm); } + +.notification-card__text { + margin: 0; + color: var(--text-primary); + font-size: var(--text-md); + line-height: var(--leading-md); white-space: pre-wrap; overflow-wrap: anywhere; + display: -webkit-box; + -webkit-line-clamp: 3; + -webkit-box-orient: vertical; + overflow: hidden; } +.notification-engagement { display: flex; align-items: center; gap: var(--space-4); padding-top: var(--space-1); color: var(--text-secondary); } +.notification-engagement-item { display: inline-flex; align-items: center; gap: 4px; font-size: var(--text-xs); line-height: 1; } +.notification-engagement-icon { display: inline-flex; } +.notification-engagement-icon svg { width: 14px; height: 14px; } -.notification-engagement { - display: flex; - align-items: center; - gap: 18px; - flex-wrap: wrap; - padding-top: 2px; - color: var(--text-secondary); -} +.notification-card--clickable { cursor: pointer; } +.notification-card--clickable:hover { background: color-mix(in srgb, var(--surface-selected) 45%, transparent); } +.notification-card--clickable:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; } - -.notification-engagement-item { - display: inline-flex; - align-items: center; - gap: 5px; - min-width: 24px; - font-size: 12px; - line-height: 1; -} - - -.notification-engagement-icon { - font-size: 15px; -} - - - -.notifications-screen .notification-card--clickable { - cursor: pointer; - transition: transform 120ms ease, border-color 120ms ease, background-color 120ms ease; -} - - -.notifications-screen .notification-card--clickable:hover, -.notifications-screen .notification-card--clickable:focus-visible { - border-color: var(--border-subtle); - background: color-mix(in srgb, var(--text-primary) 6%, transparent); - outline: none; -} - - -.notifications-screen .notification-card--clickable:active { - transform: scale(0.99); -} - - - - - - - - -/* Уведомления: информационные блоки без рамок. Hover/focus не возвращает - * обводку — различение сохраняется фоном и лёгкой реакцией на нажатие. */ -.notifications-screen .notifications-list > .notification-card, -.notifications-screen .notifications-list > .notification-card:hover, -.notifications-screen .notifications-list > .notification-card:focus, -.notifications-screen .notifications-list > .notification-card:focus-visible, -.notifications-screen .notifications-list > .notification-card:active { - border: 0; - outline: 0; -} - -.notifications-screen .notifications-list > .notification-empty-state.card, .notifications-screen .notification-empty-state { margin-top: var(--space-5); padding: var(--space-5) var(--space-4); border: 0; background: none; box-shadow: none; text-align: center; justify-items: center; } -.notifications-screen .notification-empty-state strong { font-size: var(--text-md); color: var(--text-primary); } -.notifications-screen .notification-empty-state .meta-muted { max-width: 30ch; font-size: var(--text-sm); } -.notifications-screen .notification-feed-tabs { margin-bottom: var(--space-2); } +.notification-empty-state { margin-top: var(--space-5); padding: var(--space-5) var(--space-4); text-align: center; justify-items: center; } +.notification-empty-state strong { color: var(--text-primary); font-size: var(--text-md); } +.notification-empty-state .meta-muted { max-width: 30ch; font-size: var(--text-sm); } diff --git a/shine-UI/styles/features/preauth.css b/shine-UI/styles/features/preauth.css index 6959dd32..b03e1ce6 100644 --- a/shine-UI/styles/features/preauth.css +++ b/shine-UI/styles/features/preauth.css @@ -49,11 +49,11 @@ .initial-splash__logo-wrap::before { content: ""; position: absolute; - inset: 16%; + /* Сияние гаснет в пределах ~четверти размера знака — не дотягивается до краёв экрана. */ + inset: -14%; z-index: -1; border-radius: 50%; - background: color-mix(in srgb, var(--warning) 20%, transparent); - filter: blur(30px); + background: radial-gradient(closest-side, color-mix(in srgb, var(--warning) 15%, transparent), color-mix(in srgb, var(--warning) 6%, transparent) 55%, transparent); animation: shine-halo-breathe 4.8s ease-in-out infinite; } @@ -66,7 +66,7 @@ filter: drop-shadow(0 0 8px color-mix(in srgb, var(--warning) 72%, transparent)) drop-shadow(0 8px 22px color-mix(in srgb, var(--warning) 38%, transparent)); - animation: shine-logo-breathe 4.8s ease-in-out infinite; + animation: shine-logo-breathe 5.3s ease-in-out infinite; } @@ -83,13 +83,47 @@ .auth-screen--welcome { position: relative; isolation: isolate; - align-content: center; + /* Знак с надписью — у оптического центра, действия — ближе к низу, под большой палец. */ + grid-template-rows: minmax(0, 1fr) auto minmax(0, 1fr); + align-content: stretch; justify-items: center; - gap: clamp(12px, 2.4vh, 20px); - padding-block: 8px; + gap: 0; + padding-block: clamp(var(--space-5), 6vh, 56px) calc(var(--space-5) + env(safe-area-inset-bottom)); font-family: var(--font-main); } +.auth-screen--welcome .auth-logo-wrap { align-self: end; } + +.auth-screen--welcome .shine-actions { + align-self: end; + width: min(100%, 390px); + grid-template-columns: 1fr 1fr; + gap: var(--space-3) var(--space-2); +} + +.auth-screen--welcome .shine-actions > :is(.shine-btn, .secondary-btn) { + grid-column: 1 / -1; + width: 100%; + height: 52px; + min-height: 48px; + border-radius: var(--radius-lg); + font-size: var(--text-lg); + font-weight: var(--weight-bold); +} + +.auth-screen--welcome :is(.start-language-link, .start-settings-link) { + min-height: var(--control-height); + border: 0; + background: transparent; + box-shadow: none; + color: var(--text-secondary); + font-size: var(--text-sm); + font-weight: var(--weight-medium); +} + +.auth-screen--welcome .start-language-link { color: var(--accent); } +.auth-screen--welcome .start-settings-link::after { content: none; } + .screen-content.no-app-chrome:has(> .auth-screen--welcome) { overflow: hidden; @@ -97,29 +131,6 @@ } -.auth-screen--welcome::before { - content: ""; - position: absolute; - inset: -14px -14px calc(-24px - env(safe-area-inset-bottom)); - z-index: -2; - background: - radial-gradient(circle at 50% 18%, color-mix(in srgb, var(--warning) 8%, transparent), transparent 26%), - radial-gradient(circle at 50% 67%, color-mix(in srgb, var(--accent) 6%, transparent), transparent 38%), - var(--background); -} - - -.auth-screen--welcome::after { - content: ""; - position: absolute; - inset: 0; - z-index: -1; - pointer-events: none; - background: linear-gradient(90deg, transparent, color-mix(in srgb, var(--text-primary) 2%, transparent) 50%, transparent); - opacity: 0.7; -} - - .auth-screen--lower { align-content: start; padding-top: clamp(80px, 18vh, 180px); @@ -134,7 +145,7 @@ filter: drop-shadow(0 0 8px color-mix(in srgb, var(--warning) 72%, transparent)) drop-shadow(0 8px 22px color-mix(in srgb, var(--warning) 38%, transparent)); - animation: shine-logo-breathe 4.8s ease-in-out infinite; + animation: shine-logo-breathe 5.3s ease-in-out infinite; } @@ -145,26 +156,60 @@ } -.auth-logo-wrap::before { +/* Сияние знака: два медленно вращающихся навстречу веера широких мазков. Периоды взаимно простые — + мазки то сходятся, то расходятся и почти не повторяются. Эллипс шире по горизонтали, к краям гаснет. */ +.auth-logo-wrap::before, +.auth-logo-wrap::after { + --halo: color-mix(in srgb, var(--warning) 34%, transparent); + --halo-soft: color-mix(in srgb, var(--warning) 15%, transparent); content: ""; position: absolute; - inset: 16%; + /* Спад прозрачности по плавной кривой с длинным хвостом — без видимой границы овала. */ + inset: -80%; z-index: -1; + pointer-events: none; border-radius: 50%; - background: color-mix(in srgb, var(--warning) 20%, transparent); - filter: blur(30px); - animation: shine-halo-breathe 4.8s ease-in-out infinite; + -webkit-mask: radial-gradient(closest-side, #000 12%, rgb(0 0 0 / 0.8) 22%, rgb(0 0 0 / 0.58) 33%, rgb(0 0 0 / 0.4) 44%, rgb(0 0 0 / 0.26) 55%, rgb(0 0 0 / 0.16) 65%, rgb(0 0 0 / 0.09) 75%, rgb(0 0 0 / 0.045) 84%, rgb(0 0 0 / 0.018) 92%, transparent); + mask: radial-gradient(closest-side, #000 12%, rgb(0 0 0 / 0.8) 22%, rgb(0 0 0 / 0.58) 33%, rgb(0 0 0 / 0.4) 44%, rgb(0 0 0 / 0.26) 55%, rgb(0 0 0 / 0.16) 65%, rgb(0 0 0 / 0.09) 75%, rgb(0 0 0 / 0.045) 84%, rgb(0 0 0 / 0.018) 92%, transparent); + filter: blur(24px); +} + +.auth-logo-wrap::before { + background: conic-gradient(from 0deg, var(--halo) 0deg, transparent 58deg, var(--halo-soft) 104deg, transparent 150deg, var(--halo) 212deg, var(--halo-soft) 250deg, transparent 296deg, var(--halo) 360deg); + transform: scaleY(0.5); + animation: shine-halo-spin 83s linear infinite, shine-halo-breathe 7.3s ease-in-out infinite; + animation-delay: var(--halo-phase-1, 0s), var(--halo-phase-2, 0s); +} + +.auth-logo-wrap::after { + --halo: color-mix(in srgb, color-mix(in srgb, var(--warning) 82%, var(--accent)) 28%, transparent); + background: conic-gradient(from 40deg, transparent 0deg, var(--halo) 36deg, transparent 92deg, var(--halo-soft) 140deg, transparent 176deg, var(--halo) 238deg, transparent 290deg, var(--halo-soft) 322deg, transparent 360deg); + transform: scaleY(0.5); + animation: shine-halo-spin 127s linear infinite reverse, shine-halo-breathe 11.9s ease-in-out infinite; + animation-delay: var(--halo-phase-3, 0s), var(--halo-phase-4, -4s); +} + +/* На светлом фоне золото темнеет в коричневый — сияние тише. */ +:root[data-theme='light'] .auth-logo-wrap::before, +:root[data-theme='light'] .auth-logo-wrap::after { + --halo: color-mix(in srgb, var(--warning) 18%, transparent); + --halo-soft: color-mix(in srgb, var(--warning) 8%, transparent); } .auth-brand { - margin: -4px 0 clamp(4px, 1vh, 10px); + margin: clamp(20px, 3.4vh, 32px) 0 0; color: var(--text-primary); font-size: clamp(42px, 9vw, 56px); - font-weight: 500; line-height: 1; - letter-spacing: 0; - text-shadow: 0 3px 22px color-mix(in srgb, var(--warning) 20%, transparent); +} + + +.auth-brand .shine-wordmark { + display: block; + width: auto; + height: 0.5em; + overflow: visible; } @@ -206,14 +251,12 @@ } - .shine-btn:disabled { opacity: 0.45; cursor: not-allowed; } - .shine-local-demo-btn { min-height: 32px; padding: 5px 12px; @@ -245,8 +288,15 @@ @keyframes shine-halo-breathe { - 0%, 100% { opacity: 0.66; transform: scale(0.96); } - 50% { opacity: 1; transform: scale(1.05); } + 0%, 100% { opacity: 0.55; } + 50% { opacity: 1; } +} + + +/* Сначала поворот, потом сплющивание: эллипс всегда лежит горизонтально и не тянется к верхнему краю. */ +@keyframes shine-halo-spin { + from { transform: scaleY(0.5) rotate(0deg); } + to { transform: scaleY(0.5) rotate(360deg); } } @@ -265,16 +315,9 @@ .initial-splash__brand { font-size: 40px; } -.auth-screen--welcome { - gap: 10px; - } .auth-logo-wrap { width: 206px; } -.auth-brand { - font-size: 40px; - margin-bottom: 2px; - } .shine-actions { gap: 10px; } @@ -292,6 +335,7 @@ .initial-splash__logo-wrap::before, .auth-logo, .auth-logo-wrap::before, +.auth-logo-wrap::after, .shine-btn { animation: none; transition: none; @@ -456,7 +500,6 @@ .screen-content.preauth-flow:not(:has(> .auth-screen--welcome)) .field-label, .screen-content.preauth-flow:not(:has(> .auth-screen--welcome)) .auth-copy, -.screen-content.preauth-flow:not(:has(> .auth-screen--welcome)) .status-line, .screen-content.preauth-flow:not(:has(> .auth-screen--welcome)) .registration-word-number { color: var(--preauth-muted); } @@ -516,11 +559,6 @@ } -.screen-content.preauth-flow:not(:has(> .auth-screen--welcome)) .preauth-local-demo-btn { - min-height: 44px; -} - - .screen-content.preauth-flow:not(:has(> .auth-screen--welcome)) .registration-toggle, .screen-content.preauth-flow:not(:has(> .auth-screen--welcome)) .session-item { border-color: var(--preauth-line); @@ -554,11 +592,6 @@ } -.screen-content.preauth-flow:not(:has(> .auth-screen--welcome)) .registration-screen { - gap: 12px; -} - - .screen-content.preauth-flow:not(:has(> .auth-screen--welcome)) .registration-form { gap: 14px; padding: 16px; @@ -592,10 +625,19 @@ .registration-login-status { + display: block; + min-height: var(--leading-sm); margin: 0; - font-size: 13px; + font-size: var(--text-sm); + line-height: var(--leading-sm); + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; } +.registration-login-status.is-available::before { content: "✓ "; } +.registration-login-status.is-checking { color: var(--text-secondary); } + .registration-faq-link { justify-self: center; @@ -607,8 +649,6 @@ } - - @media (max-width: 360px) { .screen-content.preauth-flow:not(:has(> .auth-screen--welcome)) { padding-inline: 12px; @@ -626,11 +666,6 @@ } -.login-panel--wide { - width: min(100%, 420px); -} - - .login-panel-title { font-size: 28px; font-weight: 700; @@ -807,12 +842,35 @@ } +/* Глаз — внутри поля пароля, у правого края. */ +.registration-password-single .inline-input-row { + position: relative; + display: block; +} + +.registration-password-single .inline-input-row .input { + width: 100%; + padding-right: 48px; +} + .registration-password-toggle { + position: absolute; + top: 50%; + right: 2px; width: 44px; height: 44px; min-width: 44px; min-height: 44px; - border-radius: 14px; + border: 0; + border-radius: var(--radius-md); + background: transparent; + color: var(--text-secondary); + transform: translateY(-50%); +} + +.registration-password-toggle .key-toggle-icon { + width: 20px; + height: 20px; } @@ -833,7 +891,6 @@ } - /* Новый двухшаговый login flow */ .login-remote-server { width: 100%; @@ -854,11 +911,6 @@ } -.login-device-preparation { - width: 100%; -} - - .secret-generation-overlay { position: fixed; inset: 0; @@ -912,58 +964,302 @@ } -/* ===== Вход через другое устройство: заголовок внутри панели ===== */ -.auth-screen--other-device { - justify-content: flex-start; - padding-top: max(18px, env(safe-area-inset-top)); +/* Сохранение ключей: заголовок-итог, список с переключателями, короткий совет. */ +.keys-lead { display: grid; gap: var(--space-1); padding: var(--space-2) var(--space-1) 0; } +.keys-lead__title { margin: 0; color: var(--text-primary); font-size: var(--text-xl); line-height: var(--leading-xl); font-weight: var(--weight-bold); } +.keys-lead__text { margin: 0; color: var(--text-secondary); font-size: var(--text-md); line-height: var(--leading-md); text-wrap: pretty; } +.keys-lead__text + .keys-lead__text { margin-top: calc(-1 * var(--space-1)); } + +.keys-list { + display: grid; + border: 1px solid var(--border-subtle); + border-radius: var(--radius-lg); + background: var(--surface); + overflow: hidden; } - -.auth-screen--other-device .login-panel { - margin-top: 0; -} - - -.login-panel-inline-back { - width: 100%; - min-height: 42px; +.keys-row { display: flex; align-items: center; - justify-content: flex-start; - gap: 10px; - padding: 0 2px; - font-size: 18px; - font-weight: 700; - text-align: left; + gap: var(--space-3); + min-height: 64px; + padding: var(--space-3) var(--space-4); + cursor: pointer; +} + +.keys-row + .keys-row { border-top: 1px solid var(--border-subtle); } +.keys-row:has(.switch:disabled) { cursor: default; } +.keys-row__text { display: grid; gap: 2px; flex: 1 1 auto; min-width: 0; } +.keys-row__title { color: var(--text-primary); font-size: var(--text-md); line-height: var(--leading-md); font-weight: var(--weight-medium); } +.keys-row__hint { color: var(--text-secondary); font-size: var(--text-sm); line-height: var(--leading-sm); text-wrap: pretty; } + +.keys-note { margin: 0; padding: 0 var(--space-1); color: var(--text-secondary); font-size: var(--text-sm); line-height: var(--leading-sm); } +.keys-actions { display: grid; gap: var(--space-2); margin-top: var(--space-2); } + + +/* Оплата регистрации: «обновить баланс» — второстепенная кнопка-иконка, пока грузится — крутится. */ +.payment-refresh-btn { + display: grid; + place-items: center; + width: 44px; + min-width: 44px; + height: 44px; + padding: 0; + border: 1px solid var(--border-control); + border-radius: var(--radius-md); + background: transparent; + color: var(--action); +} + +.payment-refresh-btn svg { width: 22px; height: 22px; } +.payment-refresh-btn.is-loading:disabled { opacity: 1; cursor: progress; } +.payment-refresh-btn.is-loading svg { animation: secret-generation-spin 0.9s linear infinite; } + +@media (prefers-reduced-motion: reduce) { + .payment-refresh-btn.is-loading svg { animation: none; } } -.login-panel-inline-back > span:first-child { - font-size: 24px; - line-height: 1; +/* ===== Вход с другого устройства: код, таймер, шаги ===== */ +.pairing-who { + margin: 0; + color: var(--text-secondary); + font-size: var(--text-md); + text-align: center; } +.pairing-code-block { display: grid; gap: var(--space-4); } +.pairing-code-block[hidden] { display: none; } + +.pairing-code-card { + display: grid; + justify-items: center; + gap: var(--space-3); + padding: var(--space-5) var(--space-4) var(--space-4); + border: 1px solid var(--border-subtle); + border-radius: var(--radius-lg); + background: var(--surface); +} + +.pairing-code-card__label { + margin: 0; + color: var(--text-secondary); + font-size: var(--text-sm); +} + +.pairing-code { + color: var(--text-primary); + font-size: clamp(30px, 9vw, 38px); + font-weight: 600; + font-variant-numeric: tabular-nums; + letter-spacing: 0.06em; + line-height: 1.1; + white-space: nowrap; + user-select: all; +} + +.pairing-timer { + display: grid; + grid-template-columns: minmax(0, 1fr) auto; + align-items: center; + gap: var(--space-3); + width: min(100%, 260px); +} + +.pairing-timer__bar { + height: 4px; + border-radius: var(--radius-pill); + background: var(--surface-raised); + overflow: hidden; +} + +.pairing-timer__bar > span { + display: block; + height: 100%; + border-radius: inherit; + background: var(--accent); + transition: width 1s linear; +} + +.pairing-timer__text { + min-width: 3.2em; + color: var(--text-secondary); + font-size: var(--text-sm); + font-variant-numeric: tabular-nums; + text-align: right; +} + +.pairing-online { + margin: 0; + color: var(--text-secondary); + font-size: var(--text-sm); +} + +.pairing-online.is-online { color: var(--success); } +.pairing-online.is-online::before { content: "● "; } + +.pairing-steps { + display: grid; + gap: var(--space-2); + margin: 0; + padding: 0 var(--space-2); + list-style: none; + counter-reset: pairing-step; +} + +.pairing-steps > li { + display: grid; + grid-template-columns: 24px minmax(0, 1fr); + align-items: center; + gap: var(--space-3); + color: var(--text-primary); + font-size: var(--text-md); + line-height: var(--leading-md); + text-wrap: pretty; + counter-increment: pairing-step; +} + +.pairing-steps > li::before { + content: counter(pairing-step); + display: grid; + place-items: center; + width: 24px; + height: 24px; + border-radius: 50%; + background: var(--surface-selected); + color: var(--action); + font-size: var(--text-xs); + font-weight: var(--weight-bold); +} + +.pairing-waiting, +.pairing-notice { + display: flex; + align-items: center; + justify-content: center; + gap: var(--space-2); + margin: 0; + color: var(--text-secondary); + font-size: var(--text-sm); + text-align: center; +} + +.pairing-notice[hidden] { display: none; } +.pairing-notice > p { margin: 0; text-wrap: balance; } + +.pairing-notice.is-error { + padding: var(--space-4); + border: 1px solid color-mix(in srgb, var(--danger) 35%, transparent); + border-radius: var(--radius-lg); + background: color-mix(in srgb, var(--danger) 10%, transparent); + color: var(--danger); + font-size: var(--text-md); +} + +.pairing-spinner { + flex: 0 0 auto; + width: 14px; + height: 14px; + border: 2px solid var(--border-control); + border-top-color: var(--accent); + border-radius: 50%; + animation: secret-generation-spin 0.9s linear infinite; +} + +.pairing-spinner[hidden], +.pairing-password[hidden], +.pairing-login > .primary-btn[hidden] { display: none; } + +/* Узкие экраны: шаги остаются в одну строку. */ +@media (max-width: 360px) { + .pairing-steps > li { font-size: var(--text-sm); } +} + +@media (prefers-reduced-motion: reduce) { + .pairing-spinner { animation: none; } + .pairing-timer__bar > span { transition: none; } +} /* ===== UX refinements 2026-08-29 ===== */ -/* Start: larger breathing room between brand and actions. */ -.auth-screen--welcome .auth-brand { - margin-bottom: clamp(34px, 6vh, 58px); + + +/* Настройки входа: все серверы в одной карточке, статус — пилюля справа от подписи (она же «проверить ещё раз»). */ +.entry-servers { + display: grid; + border: 1px solid var(--border-subtle); + border-radius: var(--radius-lg); + background: var(--surface); } -.auth-screen--welcome .shine-actions { - margin-top: 0; +.entry-server { + display: grid; + gap: var(--space-2); + padding: var(--space-3) var(--space-4) var(--space-4); } +.entry-server + .entry-server { border-top: 1px solid var(--border-subtle); } -/* Entry settings actions use the existing Start button visual language without huge width side effects. */ -.screen-content.preauth-flow .server-check-btn.shine-btn { - width: auto; - height: 44px; - min-height: 44px; - padding-inline: 18px; - border-radius: 14px; - font-size: 15px; +.entry-server__head { + display: flex; + align-items: center; + justify-content: space-between; + gap: var(--space-2); +} + +.entry-server__hint { + margin: calc(-1 * var(--space-1)) 0 0; + color: var(--text-secondary); + font-size: var(--text-xs); + line-height: var(--leading-xs); + overflow-wrap: anywhere; +} + +.entry-status { + display: inline-flex; + align-items: center; + gap: 6px; + min-height: 32px; + padding: 0 var(--space-3); + border: 0; + border-radius: var(--radius-pill); + background: color-mix(in srgb, var(--action) 14%, transparent); + color: var(--action); + font-size: var(--text-sm); + font-weight: var(--weight-medium); + white-space: nowrap; +} + +.entry-status:is(.is-available, .is-unavailable)::before { + content: ""; + width: 7px; + height: 7px; + border-radius: 50%; + background: currentColor; +} + +.entry-status.is-available { + color: var(--success); + background: color-mix(in srgb, var(--success) 15%, transparent); +} + +.entry-status.is-unavailable { + color: var(--danger); + background: color-mix(in srgb, var(--danger) 15%, transparent); +} + +.entry-status.is-checking:disabled { + opacity: 1; + cursor: progress; + color: var(--text-secondary); + background: transparent; +} + +.entry-settings__actions { + display: grid; + gap: var(--space-2); + width: 100%; + margin-top: var(--space-2); } .screen-content.preauth-flow .auth-footer-actions .shine-btn { @@ -994,19 +1290,6 @@ } .screen-content.preauth-flow .topbar { background: transparent; } -.auth-screen--welcome .shine-actions { gap: var(--space-3); } -.auth-screen--welcome .start-language-link, -.auth-screen--welcome .start-settings-link { - min-height: var(--control-height); - border: 0; - background: transparent; - box-shadow: none; - color: var(--accent); - font-size: var(--text-md); - font-weight: var(--weight-medium); -} -.auth-screen--welcome .start-settings-link { color: var(--text-secondary); font-size: var(--text-sm); } -.auth-screen--welcome .start-settings-link::after { content: none; } .screen-content.preauth-flow:not(:has(> .auth-screen--welcome)) .login-choice-screen .topbar { margin-bottom: var(--space-4); } .screen-content.preauth-flow:not(:has(> .auth-screen--welcome)) .login-choice-screen .topbar__title { display: block; } @@ -1025,7 +1308,6 @@ text-underline-offset: 3px; } -.screen-content.preauth-flow:not(:has(> .auth-screen--welcome)) .topbar { min-height: 56px; margin-bottom: var(--space-2); grid-template-columns: 44px minmax(0, 1fr) 44px; } +.screen-content.preauth-flow:not(:has(> .auth-screen--welcome)) .topbar { min-height: 56px; margin-bottom: calc(var(--page-top-gap) - 10px); /* + промежуток .stack 10px */ grid-template-columns: 44px minmax(0, 1fr) 44px; } + -.auth-screen--welcome .shine-actions { width: min(100%, 420px); justify-self: center; } -.auth-screen--welcome .shine-actions > :is(.shine-btn, .secondary-btn) { width: 100%; min-height: 48px; font-size: var(--text-md); font-weight: var(--weight-bold); } diff --git a/shine-UI/styles/features/profile-page.css b/shine-UI/styles/features/profile-page.css index 3fe71187..e2561f90 100644 --- a/shine-UI/styles/features/profile-page.css +++ b/shine-UI/styles/features/profile-page.css @@ -1,6 +1,6 @@ /* Карточка профиля (js/components/profile-card.js): свой и чужой профиль в одной системе с «О канале». * Селекторы привязаны к .user-profile-screen, чтобы перекрыть старую геометрию profile.css. */ -.user-profile-screen { gap: 0; min-height: 0; overflow-x: hidden; } +.user-profile-screen { gap: 0; min-height: 0; overflow-x: clip; } /* clip, а не hidden: hidden обрезал бы и свечение аватарки сверху */ .user-profile-screen::before { content: none; } .user-profile-screen .user-profile-body { display: grid; gap: var(--space-4); padding: var(--space-2) 0 var(--space-5); } .user-profile-screen .user-profile-status:empty { display: none; } diff --git a/shine-UI/styles/features/settings.css b/shine-UI/styles/features/settings.css index 5127bb6a..98e778b5 100644 --- a/shine-UI/styles/features/settings.css +++ b/shine-UI/styles/features/settings.css @@ -142,15 +142,25 @@ } -.screen-content.settings-bordered-actions :is(.secondary-btn, .ghost-btn, .text-btn, .shine-btn, .settings-bordered-btn, .profile-relative-suggest-item) { +/* Второстепенные действия – та же роль, что во всём приложении: прозрачная кнопка, рамка, цвет «действия». */ +.screen-content.settings-bordered-actions .profile-relative-suggest-item { min-height: var(--control-height); padding-inline: 14px; border: 1px solid var(--border-subtle); border-radius: var(--radius-md); background: var(--surface); - box-shadow: none; color: var(--text-primary); font-size: var(--text-md); +} +.screen-content.settings-bordered-actions :is(.secondary-btn, .ghost-btn, .text-btn, .shine-btn, .settings-bordered-btn) { + min-height: var(--control-height); + padding-inline: 14px; + border: 1px solid var(--border-control); + border-radius: var(--radius-md); + background: transparent; + box-shadow: none; + color: var(--action); + font-size: var(--text-md); font-weight: var(--weight-medium); text-shadow: none; backdrop-filter: none; @@ -171,9 +181,9 @@ font-size: var(--text-md); font-weight: var(--weight-medium); min-height: var(--control-height); - border: 1px solid var(--border-subtle); + border: 1px solid var(--border-control); border-radius: var(--radius-md); - background: var(--surface); + background: transparent; color: var(--danger); box-shadow: none; } @@ -276,45 +286,6 @@ .language-choice-actions .shine-btn { height: 50px; } /* ===== Скрытые расширенные настройки ===== */ -.settings-shine-logo-button { - width: min(72vw, 280px); - min-height: 118px; - margin: 2px auto 10px; - padding: 6px 12px; - display: grid; - place-items: center; - border: 0; - background: transparent; - box-shadow: none; - cursor: pointer; - -webkit-tap-highlight-color: transparent; - user-select: none; -} - -.settings-shine-logo-button:hover, -.settings-shine-logo-button:focus, -.settings-shine-logo-button:active { - border: 0; - background: transparent; - box-shadow: none; - transform: none; -} - -.settings-shine-logo-button:focus-visible { - outline: 2px solid color-mix(in srgb, var(--accent) 70%, transparent); - outline-offset: 4px; - border-radius: 22px; -} - -.settings-shine-logo { - display: block; - width: 100%; - max-height: 126px; - object-fit: contain; - pointer-events: none; - filter: drop-shadow(0 12px 30px color-mix(in srgb, var(--accent) 16%, transparent)); -} - .settings-feature-toggle-row { min-height: 76px; padding: 15px 16px; @@ -343,50 +314,6 @@ color: var(--text-secondary); } -.settings-feature-switch { - appearance: none; - -webkit-appearance: none; - flex: 0 0 auto; - width: 48px; - height: 28px; - margin: 0; - padding: 2px; - border: 1px solid var(--border-control); - border-radius: var(--radius-pill); - background: var(--surface-selected); - cursor: pointer; - transition: background-color var(--duration-fast) ease, border-color var(--duration-fast) ease; -} - -.settings-feature-switch::after { - content: ''; - display: block; - width: 22px; - height: 22px; - border-radius: 50%; - background: var(--text-secondary); - box-shadow: var(--shadow-sm); - transition: transform var(--duration-fast) ease, background-color var(--duration-fast) ease; -} - -.settings-feature-switch:checked { - border-color: var(--accent); - background: var(--accent); -} - -.settings-feature-switch:checked::after { - transform: translateX(20px); - background: var(--on-accent); -} - -.settings-feature-switch:focus-visible { - outline: 2px solid color-mix(in srgb, var(--accent) 82%, transparent); - outline-offset: 3px; -} - -.settings-shine-logo-button { justify-self: center; } -.settings-shine-logo { width: 48px; height: 48px; max-height: 48px; object-fit: contain; } -.settings-shine-logo-button { min-height: 0; padding: 0; margin: 0 auto; } .settings-sections { gap: var(--space-4); } .settings-theme-card { gap: var(--space-2); } .settings-theme-editor { width: 100%; } diff --git a/shine-UI/styles/main.css b/shine-UI/styles/main.css index 0ddf72a4..a31ef04d 100644 --- a/shine-UI/styles/main.css +++ b/shine-UI/styles/main.css @@ -1,19 +1,32 @@ :root { - --background: #12141f; - --surface: #1c2031; - --surface-selected: #272c45; - --text-primary: #eceefa; - --text-secondary: #a0a6c2; - --border-subtle: #343a55; - --border-control: #6d7396; - --accent: #a9b4ff; - --on-accent: #151a3d; - --focus-ring: #a9b4ff; - --reaction-active: #ff9bb3; - --danger: #ffa7a3; - --success: #8fdab4; - --warning: #e8c585; - --scrim: #00000099; + /* Палитра по умолчанию — «Сияние» (js/services/theme-service.js, пресет aurora) */ + --background: #121419; + --surface: #1c1f27; + --surface-selected: #302b43; + --surface-raised: #272a34; + --text-primary: #f1f1f5; + --text-secondary: #a8abb8; + --border-subtle: #303440; + --border-control: #454858; + --accent: #b8aef5; + --on-accent: #211c34; + --action: #c6bff5; + --bubble-out: #39324d; + --focus-ring: #b8aef5; + --reaction-active: #b8aef5; + --danger: #f2a1ad; + --success: #91d4b0; + --warning: #edc487; + --info: #a8c9f3; + --scrim: #06080cb3; + /* Производные состояния: считаются от ролей, поэтому работают с любой палитрой */ + --accent-hover: color-mix(in srgb, var(--accent) 86%, var(--text-primary)); + --accent-pressed: color-mix(in srgb, var(--accent) 88%, var(--background)); + --disabled-bg: color-mix(in srgb, var(--surface-raised) 80%, var(--background)); + --disabled-text: color-mix(in srgb, var(--text-secondary) 72%, var(--background)); + --quote-bg: color-mix(in srgb, var(--background) 70%, var(--surface)); + --quote-line: color-mix(in srgb, var(--accent) 55%, var(--text-secondary)); + --divider-soft: color-mix(in srgb, var(--border-subtle) 70%, var(--background)); /* Язык связей: один цвет — один тип отношения во всём приложении (граф, личные, профиль). */ --rel-contact: #8c63ff; /* обычная связь / контакт */ --rel-family: #f0b82e; /* семья / близкий круг */ @@ -48,6 +61,8 @@ --space-5: 24px; --space-6: 32px; --page-gutter: var(--space-4); + /* Зазор между шапкой и первым элементом экрана – один на всё приложение. */ + --page-top-gap: var(--space-3); /* Скругления */ --radius-xs: 8px; --radius-sm: 10px; @@ -80,21 +95,25 @@ } :root[data-theme='light'] { - --background: #eef0f5; + --background: #f3f2f7; --surface: #ffffff; - --surface-selected: #dde3f5; - --text-primary: #1e2233; - --text-secondary: #5c6279; - --border-subtle: #d5d9e5; - --border-control: #8a90a8; - --accent: #4c5caa; + --surface-selected: #e8e3fa; + --surface-raised: #ecebf2; + --text-primary: #1d1b26; + --text-secondary: #5f5b6e; + --border-subtle: #e0dde8; + --border-control: #a19db2; + --accent: #5d4fc4; --on-accent: #ffffff; - --focus-ring: #4c5caa; - --reaction-active: #c02a55; - --danger: #b3261e; - --success: #2c6b4a; - --warning: #7d5a10; - --scrim: #302c2566; + --action: #5244b5; + --bubble-out: #e6e0fb; + --focus-ring: #5d4fc4; + --reaction-active: #5d4fc4; + --danger: #b3304a; + --success: #2d7552; + --warning: #8a5a0e; + --info: #2f5f9e; + --scrim: #1d1b2666; --shadow: 0 16px 42px rgba(30, 34, 51, 0.14); --shadow-sm: 0 2px 8px rgba(30, 34, 51, 0.08); --rel-contact: #6b3fe0; @@ -141,10 +160,6 @@ a { text-decoration: none; } -.notification-card--new { background: var(--accent-soft); border-color: var(--accent); } -.notification-card--new::before { content: ''; width: 7px; height: 7px; border-radius: 50%; background: currentColor; box-shadow: 0 0 10px currentColor; position: absolute; right: 12px; top: 12px; opacity: .9; } -.notification-card { position: relative; } -.notification-new-divider { text-align: center; font-size: 11px; letter-spacing: .12em; opacity: .72; padding: 6px 0; } .channel-view-topbar { position: relative; }