UI - МЕЖПРОЕКТНАЯ КОММУНИКАЦИЯ: внешний контур, auth empty state и HDESIGN update
This commit is contained in:
+106
-2
@@ -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>
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user