From 7d27bfdcaf3e76827fb28cffbc0438f9196644f5d24c9193c3dee93be2d239a7 Mon Sep 17 00:00:00 2001 From: peradas Date: Tue, 8 Sep 2026 16:13:04 +0300 Subject: [PATCH] =?UTF-8?q?=D0=9E=D0=B1=D0=BD=D0=BE=D0=B2=D0=B8=D1=82?= =?UTF-8?q?=D1=8C=20UI=20=D0=BF=D1=80=D0=BE=D1=84=D0=B8=D0=BB=D1=8F=20?= =?UTF-8?q?=D0=B8=20=D0=BD=D0=B0=D0=B2=D0=B8=D0=B3=D0=B0=D1=86=D0=B8=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- shine-UI/AGENTS.md | 1315 +- shine-UI/index.html | 6 +- shine-UI/js/app.js | 172 +- shine-UI/js/components/dropdown-menu.js | 195 +- shine-UI/js/components/header.js | 58 - shine-UI/js/components/topbar.js | 112 + shine-UI/js/pages/access-servers-view.js | 14 +- shine-UI/js/pages/add-channel-view.js | 14 +- .../js/pages/add-personal-public-chat-view.js | 14 +- shine-UI/js/pages/app-log-view.js | 12 +- shine-UI/js/pages/arweave-uploads-view.js | 102 +- shine-UI/js/pages/channel-about-view.js | 6 +- shine-UI/js/pages/channel-thread-view.js | 195 +- shine-UI/js/pages/channel-view.js | 311 +- shine-UI/js/pages/channels-list.js | 319 +- shine-UI/js/pages/chat-view.js | 308 +- shine-UI/js/pages/connect-device-view.js | 19 +- shine-UI/js/pages/contact-search-view.js | 12 +- shine-UI/js/pages/developer-settings-view.js | 12 +- shine-UI/js/pages/device-camera-view.js | 12 +- shine-UI/js/pages/device-pairing-view.js | 12 +- shine-UI/js/pages/device-qr-view.js | 12 +- shine-UI/js/pages/device-session-view.js | 12 +- shine-UI/js/pages/device-view.js | 14 +- shine-UI/js/pages/devnet-topup-view.js | 4 +- shine-UI/js/pages/entry-settings-view.js | 6 +- shine-UI/js/pages/key-storage-view.js | 6 +- shine-UI/js/pages/language-view.js | 12 +- shine-UI/js/pages/login-camera-view.js | 6 +- shine-UI/js/pages/login-password-view.js | 6 +- shine-UI/js/pages/login-view.js | 6 +- shine-UI/js/pages/messages-list.js | 154 +- shine-UI/js/pages/network-view.js | 53 +- shine-UI/js/pages/network/force-graph.js | 8 +- shine-UI/js/pages/network/node-menu.js | 2 +- shine-UI/js/pages/notifications-view.js | 4 +- shine-UI/js/pages/profile-edit-view.js | 8 +- shine-UI/js/pages/profile-view.js | 53 +- shine-UI/js/pages/profiles-view.js | 8 +- .../js/pages/public-support-queue-view.js | 12 +- shine-UI/js/pages/pwa-diagnostics-view.js | 12 +- shine-UI/js/pages/register-view.js | 6 +- .../js/pages/registration-draft-keys-view.js | 6 +- shine-UI/js/pages/registration-faq-view.js | 6 +- shine-UI/js/pages/registration-keys-view.js | 6 +- .../js/pages/registration-payment-view.js | 10 +- .../js/pages/remote-addblock-session-view.js | 14 +- shine-UI/js/pages/server-settings-view.js | 14 +- shine-UI/js/pages/settings-view.js | 12 +- shine-UI/js/pages/show-keys-view.js | 12 +- shine-UI/js/pages/solana-rpc-check-view.js | 12 +- shine-UI/js/pages/solana-users-init-view.js | 12 +- shine-UI/js/pages/topup-view.js | 6 +- .../trusted-device-login-settings-view.js | 12 +- shine-UI/js/pages/user-profile-list-view.js | 14 +- shine-UI/js/pages/user-profile-view.js | 12 +- .../js/pages/user-relation-manage-view.js | 10 +- shine-UI/js/pages/wallet-view.js | 12 +- shine-UI/js/services/attachment-format.js | 4 +- shine-UI/styles/app-shell.css | 303 + shine-UI/styles/buttons-white.css | 473 +- shine-UI/styles/components.css | 11724 ---------------- shine-UI/styles/components/attachments.css | 310 + shine-UI/styles/components/avatar.css | 271 + shine-UI/styles/components/call-ui.css | 517 + shine-UI/styles/components/dropdown-menu.css | 145 + shine-UI/styles/components/emoji-picker.css | 178 + shine-UI/styles/components/modal.css | 178 + shine-UI/styles/components/overflow-dots.css | 28 + shine-UI/styles/components/primitives.css | 596 + .../styles/components/scroll-to-bottom.css | 86 + shine-UI/styles/components/tabs.css | 54 + shine-UI/styles/components/toolbar.css | 316 + shine-UI/styles/components/topbar.css | 222 + shine-UI/styles/features/channel-thread.css | 247 + shine-UI/styles/features/channel.css | 685 + shine-UI/styles/features/channels-common.css | 438 + shine-UI/styles/features/channels-list.css | 1519 ++ shine-UI/styles/features/chat.css | 1277 ++ shine-UI/styles/features/developer-tools.css | 202 + shine-UI/styles/features/devices.css | 325 + shine-UI/styles/features/messages.css | 724 + shine-UI/styles/features/network.css | 396 + shine-UI/styles/features/notifications.css | 232 + shine-UI/styles/features/preauth.css | 971 ++ shine-UI/styles/features/profile.css | 1807 +++ shine-UI/styles/features/settings.css | 272 + shine-UI/styles/layout.css | 188 - shine-UI/styles/main.css | 8 +- shine-UI/styles/network-graph.css | 6 - 90 files changed, 14931 insertions(+), 13565 deletions(-) delete mode 100644 shine-UI/js/components/header.js create mode 100644 shine-UI/js/components/topbar.js create mode 100644 shine-UI/styles/app-shell.css delete mode 100644 shine-UI/styles/components.css create mode 100644 shine-UI/styles/components/attachments.css create mode 100644 shine-UI/styles/components/avatar.css create mode 100644 shine-UI/styles/components/call-ui.css create mode 100644 shine-UI/styles/components/dropdown-menu.css create mode 100644 shine-UI/styles/components/emoji-picker.css create mode 100644 shine-UI/styles/components/modal.css create mode 100644 shine-UI/styles/components/overflow-dots.css create mode 100644 shine-UI/styles/components/primitives.css create mode 100644 shine-UI/styles/components/scroll-to-bottom.css create mode 100644 shine-UI/styles/components/tabs.css create mode 100644 shine-UI/styles/components/toolbar.css create mode 100644 shine-UI/styles/components/topbar.css create mode 100644 shine-UI/styles/features/channel-thread.css create mode 100644 shine-UI/styles/features/channel.css create mode 100644 shine-UI/styles/features/channels-common.css create mode 100644 shine-UI/styles/features/channels-list.css create mode 100644 shine-UI/styles/features/chat.css create mode 100644 shine-UI/styles/features/developer-tools.css create mode 100644 shine-UI/styles/features/devices.css create mode 100644 shine-UI/styles/features/messages.css create mode 100644 shine-UI/styles/features/network.css create mode 100644 shine-UI/styles/features/notifications.css create mode 100644 shine-UI/styles/features/preauth.css create mode 100644 shine-UI/styles/features/profile.css create mode 100644 shine-UI/styles/features/settings.css diff --git a/shine-UI/AGENTS.md b/shine-UI/AGENTS.md index fb370711..7e7b4dd0 100644 --- a/shine-UI/AGENTS.md +++ b/shine-UI/AGENTS.md @@ -1,44 +1,1285 @@ -# AGENTS +NON-NEGOTIABLE ARCHITECTURE RULES -## Назначение проекта -Это демо-прототип мобильного веб-приложения в формате статического сайта. +- Read this file before editing. +- App/Router is the only page mount/unmount owner. +- Never restore self render + replaceWith. +- Never restore components.css. +- Never restore global button:not(...) visual reset. +- Do not add visual !important to solve cascade problems. +- Do not create fixes.css / overrides.css / compatibility.css. +- Reuse TopBar, Dropdown, Avatar and other shared components. +- Preserve accepted visual behavior unless the task explicitly requests redesign. +# AGENTS.md -## Технические ограничения -- Проект сделан без бэкенда, без базы данных и без реальных API. -- Все данные моковые и хранятся в `js/mock-data.js`. -- Навигация между экранами идет без полной перезагрузки страницы (SPA-подход на hash-router). +# Назначение -## Обязательные требования к каждому экрану -- У каждого экрана есть явный верхний заголовок на русском языке. -- У каждого экрана есть нижняя служебная подпись над toolbar в формате: - `[Русское название] ([english-page-id])`. -- `page-id` должен совпадать с именем JS-файла страницы или быть максимально близким к нему. +Этот файл — **обязательный архитектурный контракт проекта `shine-UI`**. -## Архитектурные правила -- Структура проекта должна оставаться понятной и модульной. -- Новые доработки нужно вносить аккуратно, не ломая существующую навигацию. -- Стиль проекта: темная тема, mobile-first, интерфейс на русском языке. +Любой агент, разработчик или автоматический инструмент перед изменением UI обязан сначала прочитать этот файл. -## Экраны и файлы -- Профиль: `js/pages/profile-view.js` -- Кошелёк: `js/pages/wallet-view.js` -- Настройки: `js/pages/settings-view.js` -- Личные сообщения: `js/pages/messages-list.js` -- Чат: `js/pages/chat-view.js` -- Каналы: `js/pages/channels-list.js` -- Канал: `js/pages/channel-view.js` -- Связи: `js/pages/network-view.js` -- Уведомления: `js/pages/notifications-view.js` +Главная задача правил — не только сделать новую функцию рабочей, но и **не вернуть архитектурные проблемы, которые уже были устранены предыдущими refactor stages**. -## Ключевые файлы приложения -- Точка входа: `index.html` -- Инициализация приложения: `js/app.js` -- Роутинг: `js/router.js` -- Состояние клиента: `js/state.js` -- Моки: `js/mock-data.js` -- Компоненты: `js/components/*` -- Стили: `styles/*` +Если быстрое решение конфликтует с этими правилами — быстрое решение запрещено. -## Язык пояснений -- Пояснения к коммитам, PR и merge-запросам всегда писать на русском языке. -- Комментарии в коде, встроенные справки и документацию писать по возможности на русском языке. +--- + +# 1. Общая архитектура + +Проект — vanilla JavaScript frontend. + +Не использовать и не добавлять без отдельного архитектурного решения: + +```text +React +Vue +Svelte +Solid +Preact +Redux +глобальный state framework +virtual DOM framework +новый router +``` + +Текущая архитектурная цепочка: + +```text +Foundation + ↓ +App Shell + ↓ +Shared Components + ↓ +Semantic UI roles + ↓ +Features / Pages +``` + +Направление зависимостей должно сохраняться. + +Feature может использовать shared component. + +Shared component не должен знать детали конкретного feature. + +--- + +# 2. Зафиксированный baseline + +Следующие этапы считаются завершёнными и **не должны откатываться**. + +## Stage 1 — App Shell + +Shell централизован: + +```text +AppShell +├── TopbarSlot +├── ScreenContent +├── ComposerSlot +├── BottomToolbarSlot +├── Global Top Fade +└── Global Bottom Fade +``` + +Shell управляется через `chrome`. + +--- + +## Stage 2 — Shared TopBar / Dropdown + +Используются единые: + +```text +js/components/topbar.js +styles/components/topbar.css + +js/components/dropdown-menu.js +styles/components/dropdown-menu.css +``` + +Не создавать альтернативные Header/Menu реализации внутри страниц. + +--- + +## Stage 3 — CSS ownership + +Старый: + +```text +styles/components.css +``` + +удалён. + +Его нельзя создавать снова. + +CSS разделён по владельцам: + +```text +styles/components/* +styles/features/* +``` + +--- + +## Stage 4 — CSS / Button architecture + +Старый глобальный button reset удалён. + +Запрещено возвращать архитектуру: + +```css +button:not(...):not(...) { + ... +} +``` + +Количество `!important` было уменьшено примерно: + +```text +356 → 8 +``` + +Не возвращать specificity wars и late global override layer. + +Button styling является opt-in / semantic. + +--- + +## Stage 5 — Page lifecycle + +Channel и Thread больше не создают новый instance сами через: + +```js +const next = render(...); +current.cleanup?.(); +current.replaceWith(next); +``` + +Текущая модель: + +```text +App / Router + ↓ +mount page instance + ↓ +stable page root + ↓ +page.refresh() + ↓ +local content update + +App / Router + ↓ +page.cleanup() + ↓ +unmount +``` + +Эту ownership-модель нельзя откатывать. + +--- + +# 3. Главное правило ownership + +Для любого кода сначала определить: + +```text +КТО является владельцем? +``` + +У каждого UI-аспекта должен быть один основной owner. + +Примеры: + +```text +Page lifetime → App / Router +TopBar → TopBar component + chrome +Dropdown lifecycle → Dropdown component +Generic Avatar → Avatar component +Toolbar → Toolbar component +Tabs → Tabs component +Button generic role → semantic button layer +Channel layout → Channel feature +Thread layout → Thread feature +``` + +Запрещено исправлять проблему созданием второго владельца. + +--- + +# 4. App Shell + +Страницы не должны напрямую создавать альтернативный global shell. + +Для TopBar использовать: + +```js +chrome.setTopbar(...) +``` + +Для Composer использовать существующий `chrome` API. + +Для shell mode/fades использовать существующий centralized shell contract. + +Не создавать внутри ScreenContent собственные: + +```text +global header +global fixed toolbar +альтернативный composer slot +копию top fade +копию bottom fade +``` + +если это уже принадлежит AppShell. + +--- + +# 5. Page lifecycle + +## App / Router владеет + +```text +mount page root +unmount page root +route change +заменой текущей страницы +shell slot lifecycle +``` + +## Page владеет + +```text +local state +local content +feature listeners +feature timers +feature observers +local refresh +``` + +--- + +# 6. Запрещённый self-rerender + +Внутри page нельзя делать: + +```js +const next = render(...); +screen.cleanup?.(); +screen.replaceWith(next); +``` + +или эквиваленты: + +```text +self render + replaceWith +self render + outerHTML +self cleanup + self recreation +recursive page render +``` + +для обновления текущего route. + +Если нужно обновить данные текущей страницы: + +```js +screen.refresh() +``` + +или внутренний: + +```js +refresh() +renderBody() +syncView() +``` + +должен обновить содержимое существующего instance. + +Page root при local refresh должен оставаться тем же DOM node. + +--- + +# 7. Stable root + +Нормальное поведение: + +```js +const rootBefore = screen; + +await screen.refresh(); + +rootBefore === screen; +``` + +должно оставаться истинным. + +При переходе на другой route App создаёт другой root. + +Нельзя делать так, чтобы App хранил reference на detached старый root. + +--- + +# 8. Cleanup + +Каждая page, создающая lifetime-resources, должна иметь корректный: + +```js +screen.cleanup +``` + +Cleanup должен быть безопасным при повторном вызове. + +Предпочтительный pattern: + +```js +let disposed = false; + +screen.cleanup = () => { + if (disposed) return; + disposed = true; + + // cleanup +}; +``` + +--- + +# 9. Refresh НЕ является cleanup + +Нельзя при каждом local refresh выполнять full page cleanup. + +Refresh может очищать только refresh-owned content/resources. + +Например допустимо: + +```text +старый content +старый read tracker +старые refresh timers +``` + +Но нельзя уничтожать весь page instance и создавать новый. + +--- + +# 10. Async safety + +Любая async операция, результат которой обновляет UI, должна учитывать lifetime страницы. + +Использовать существующий pattern: + +```js +if (disposed) return; +``` + +и при нескольких последовательных refresh: + +```js +const seq = ++refreshSeq; + +const result = await load(); + +if (disposed || seq !== refreshSeq) return; +``` + +Это предотвращает: + +```text +request A +↓ +refresh B +↓ +B становится актуальным +↓ +A завершается позже +↓ +A портит новый UI +``` + +--- + +# 11. Не мутировать UI после dispose + +После: + +```js +screen.cleanup() +``` + +старые async callbacks не должны: + +```text +showToast +перерисовывать screen +открывать modal +менять TopBar +менять Composer +добавлять DOM +``` + +если действие относится к уже закрытой странице. + +Перед UI commit проверять active state. + +--- + +# 12. Timers + +Lifetime-sensitive timers должны: + +1. либо быть безопасными через `isConnected` / `disposed`; +2. либо сохраняться и очищаться. + +Например: + +```js +const timer = window.setTimeout(...); +``` + +если timer принадлежит refresh/page lifecycle, должен быть очищаемым. + +Не оставлять timeout, который после navigation мутирует detached DOM. + +--- + +# 13. Listeners + +Различать: + +## Root-owned listener + +```js +screen.addEventListener(...) +``` + +Если root уничтожается вместе со listener, отдельный remove может быть не нужен. + +## Global listener + +```js +window.addEventListener(...) +document.addEventListener(...) +``` + +Он обязан иметь понятный cleanup: + +```js +window.removeEventListener(...) +``` + +Не создавать anonymous global listener, который невозможно снять. + +--- + +# 14. Modal ownership + +Если page открывает modal, нужно понимать, кому он принадлежит. + +При page cleanup нельзя оставлять modal, callback которого замыкает disposed page state. + +Для page-owned modal при unmount: + +```text +close / destroy / clear +``` + +его UI и callbacks. + +Не удалять чужой modal другой feature. + +--- + +# 15. Dropdown ownership + +Не реализовывать заново: + +```text +outside click +Escape +portal +backdrop +pressed state +resize/scroll cleanup +``` + +Использовать общий Dropdown component. + +Feature передаёт содержимое/actions. + +Dropdown component управляет своим lifecycle. + +--- + +# 16. TopBar ownership + +Не создавать новый `
` непосредственно в feature. + +Использовать общий TopBar. + +Feature может передавать: + +```text +title +left action +right action +center content +callbacks +``` + +Но generic geometry/surface TopBar принадлежит shared component. + +--- + +# 17. CSS hierarchy + +CSS должен следовать: + +```text +main / foundation +↓ +layout +↓ +app-shell +↓ +semantic/shared components +↓ +features +``` + +Нельзя решать cascade problem перестановкой «fix file» в самый конец. + +--- + +# 18. Запрещённые CSS-файлы + +Не создавать: + +```text +components.css +legacy.css +compatibility.css +fixes.css +final.css +final-fixes.css +overrides.css +patches.css +``` + +как место, куда складываются новые исключения. + +Если правило непонятно куда положить — сначала определить owner. + +--- + +# 19. Shared CSS ownership + +Generic component surface должна жить в: + +```text +styles/components/* +``` + +Примеры: + +```text +avatar.css +topbar.css +dropdown-menu.css +toolbar.css +tabs.css +modal.css +emoji-picker.css +call-ui.css +scroll-to-bottom.css +attachments.css +``` + +Feature CSS не должен возвращать альтернативную реализацию shared component. + +--- + +# 20. Feature CSS ownership + +В: + +```text +styles/features/* +``` + +допустимы: + +```text +feature layout +feature spacing +feature-specific state +feature-specific intentional variant +``` + +Не допустимы случайные переопределения generic shared component surface. + +Например feature может задавать Avatar: + +```text +size +placement +margin +``` + +но не должен случайно заново определять: + +```text +generic background +generic frame +generic glass overlay +generic fallback +``` + +--- + +# 21. Не добавлять исторические override chains + +Запрещён pattern: + +```css +.component { ... } + +/* fix */ +.screen .component { ... } + +/* final */ +.screen.feature .component { ... } + +/* really final */ +.screen.feature .component.state { + ... !important; +} +``` + +Перед добавлением нового rule проверить существующие definitions этого selector. + +Если нужен новый final result — изменить правильный owner/base/state. + +--- + +# 22. `!important` + +Новые `!important` по умолчанию запрещены. + +Перед добавлением обязательно доказать, почему проблему нельзя решить: + +```text +ownership +specificity +source order +state class +semantic role +``` + +Текущий низкий baseline нельзя ухудшать. + +Особенно запрещены: + +```css +background: ... !important; +border: ... !important; +color: ... !important; +box-shadow: ... !important; +``` + +для победы в визуальном cascade. + +--- + +# 23. Button architecture + +Старый глобальный reset возвращать запрещено. + +Нельзя: + +```css +button:not(...) { + background: transparent; + ... +} +``` + +Нельзя: + +```css +:root button { + ... +} +``` + +использовать как global visual policy. + +--- + +# 24. Перед созданием кнопки определить её роль + +Каждый новый `