UI - МЕЖПРОЕКТНАЯ КОММУНИКАЦИЯ: внешний контур, auth empty state и HDESIGN update

This commit is contained in:
DCCONSTRUCTIONS
2026-04-20 13:30:04 +03:00
parent b1f980bc7f
commit 9553c81752
16 changed files with 551 additions and 294 deletions
+106 -2
View File
@@ -99,6 +99,42 @@
- жёсткие border-outline
- светлый фон, если основной экран тёмный
- Search shell внутри popup должен использовать тот же стиль, что и сам popup.
- Filled CTA внутри popup и модалок подчиняются тому же правилу:
- светлый акцентный фон
- тёмный/чёрный текст
- hover только в более светлый тон того же цвета
### Portal правило
- Если selector/dropdown открывается внутри:
- scroll-контейнера
- detail-pane
- карточки
- properties section
- sidebar
- sticky header
он не должен рендериться inline.
- Такой popup обязан рендериться на верхнем слое через `portal` (`document.body` или эквивалент).
- Inline popup в ограниченном контейнере считается дефектом, потому что даёт:
- клиппинг
- налезание на соседние блоки
- старую “врезанную” верстку
### Portal anchor snippet
```tsx
{isOpen &&
typeof document !== "undefined" &&
createPortal(
<Combobox.Options className="fixed z-[420]" static>
<div
data-prevent-outside-click
className="nodedc-dropdown-surface nodedc-external-popup-anchor"
>
...
</div>
</Combobox.Options>,
document.body
)}
```
### Reusable классы
- Accent CTA:
@@ -167,9 +203,9 @@
## Drag and drop
- Drag overlay использует акцентный контур.
- Delete dropzone:
- без красного технического свечения
- без красного технического свечения и без red-tinted text/fill
- текст локализован
- акцентный outline допустим
- акцентный outline обязателен
## Тексты
- Пользовательский UI на русском, если экран русифицирован.
@@ -183,3 +219,71 @@
- Если блок визуально расходится со стилем системы, не добавлять поверх временную wrapper-заплатку. Нужно либо перевести блок на shared-компонент, либо переверстать локальную структуру под shared-классы.
- Для экранов со вкладками/переключателями нельзя оставлять flash старой верстки. Перед refetch нужно очищать stale store-data и показывать loading shell.
- Если карточки или списки разных модулей должны быть одинаковыми по канону, нельзя лечить это внешней обёрткой. Нужно менять сам внутренний layout item-компонента.
- Для `Внешних контуров` это значит:
- список карточек правится на уровне `list-item.tsx`, а не через внешний wrapper
- gap между карточками должен совпадать с каноном `Внутреннего контура`
- актуальный gap списка на текущем каноне: `space-y-2`
- toolbar-навигация и inline actions не должны использовать старые квадратные `IconButton` остатки
- свойства `Приоритет / Метки / Статус` не должны рисовать внутренние boxed-chip артефакты
- filled CTA вроде `Добавить запрос` используют `nodedc-external-primary-button` и всегда имеют тёмный текст
- filled CTA используют чёрный/почти-чёрный текст всегда; белый текст на светлом акценте запрещён
- secondary meta-иконки в карточке списка не должны иметь отдельную серую подложку, если по канону это простой inline icon
- popup выбора `Приоритет / Метки` внутри detail view не рендерится inline в property-row; он обязан уходить в `portal`
- секции с dropdown-trigger внутри blur/glass shell обязаны иметь `overflow: visible` и `isolation: isolate`, иначе popup визуально “тонет” внутри блока
- при переключении `Открытые / Закрытые` store обязан очистить stale request list до нового fetch, чтобы пользователь не видел flash старой верстки
- карточка списка `Внешних контуров` правится на уровне `list-item.tsx`, а не внешней обёрткой:
- верхняя и нижняя оси собираются как у карточки `Внутреннего контура`
- gap между карточками совпадает с каноном `Внутреннего контура`
- empty-state иконки без декоративной подложки; если иконка визуально “плывёт”, корректируется сам SVG/media-box
### Внешние контуры: code anchors
- Header CTA:
```tsx
<Button className="nodedc-external-primary-button">...</Button>
```
- List spacing:
```tsx
<div key={routeTab} className="space-y-2">
{filteredRequestIds.map((requestId) => (
<ExternalContoursListItem key={requestId} ... />
))}
</div>
```
- Property control:
```tsx
<div className="nodedc-external-property-control text-[13px] font-medium">
<SomeIcon className="h-3.5 w-3.5 flex-shrink-0 text-tertiary" />
<span className="text-primary">...</span>
</div>
```
- Root tab switch without stale flash:
```tsx
void handleCurrentTab(workspaceSlug, projectId, nextTab);
router.push(`...currentTab=${nextTab}`);
```
- Store-side tab reset:
```ts
this.requestIds = [];
this.requests = {};
this.loader = "init-loading";
this.currentTab = tab;
```
- Portal popup с фиксированной стратегией:
```tsx
const { styles, attributes } = usePopper(referenceElement, popperElement, {
strategy: "fixed",
placement: placement ?? "bottom-start",
});
```
- Контейнер секции с trigger:
```tsx
<div className="nodedc-external-section overflow-visible px-4 py-4">
...
</div>
```