---
title: "Whitelabel-навигация"
description: "Закрытая карта иконок Lucide, перезапись primary-nav в паке и Layer3 overlay remap существующих слотов"
locale: "ru"
---
# Whitelabel-навигация

> **Info**
> Используйте вкладки **Founder** / **Developer** в боковой панели docs, чтобы фильтровать эту страницу. Общие разделы относятся к обеим аудиториям.

> **Warning**
> **Статус:** Layer1 chrome — это **data manifest + закрытая карта иконок**, а не варианты `*-desktop-navigation.tsx` на клон. Файла `config/navigation.config.ts` нет. Пакеты перезаписывают `lib/navigation/primary-nav.ts`. Клоны ремапят **существующие** id слотов в `lib/navigation/primary-nav-overlay.ts`. Неизвестные icon id рендерят глиф `users`.

| Прежняя привычка | Эквивалент в Ring |
|----------------|-----------------|
| Форкать `vikka-desktop-navigation.tsx` / `greenfood-navigation.tsx` | L2 пак перезаписывает `lib/navigation/primary-nav.ts` (слоты, hrefs, icon **ids**) |
| Импортировать вертикально-именованную Lucide-иконку в chrome | Добавить **generic** id в `PRIMARY_NAV_ICONS` на Layer1, затем ссылаться на этот id |
| Overlay новой mobile tab из клона | Overlay **не может** добавлять, скрывать или менять порядок слотов — меняйте манифест пака |
| Копировать `desktop-sidebar.tsx` на клон | Держите chrome на Layer1; ремапьте только `iconById` / `labelKeysById` / `hrefById` |

## Архитектура

```mermaid
flowchart TD
  Pack["L2 pack overwritesprimary-nav.ts"] --> Manifest["getPrimaryNavManifest"]
  L1["L1 BASE_MANIFEST"] --> Manifest
  Overlay["L3 primary-nav-overlay.tsremap existing ids"] --> Manifest
  Manifest --> Icons["getPrimaryNavIconprimary-nav-icons.ts"]
  Icons --> Mobile["bottom-navigation.tsx"]
  Icons --> Rail["sidebar-rail / sidebar-synced-layout"]
```

`home.preset` **не** выбирает меню. Overflow-модули (каталог `[...]`) живут в `lib/navigation/platform-menu.ts` плюс `ring-config.navigation.platformMenu`. Пакеты **не должны** перезаписывать `platform-menu.ts`; вертикальные дефолты принадлежат в `PACK.json.platformMenu` и копируются на `ring-config` клона.

### For founders

## Что можно менять без форка chrome

- **Подписи** — ключи next-intl на каждом слоте (`labelKeys`). `pack.json` пака и overlay клона могут переопределять листья. См. [Localization](/docs/customization/localization.md).
- **Какой глиф Lucide** — выберите id, который уже есть в закрытой карте (таблица ниже). Новый глиф — это изменение **Layer1**, не файл клона.
- **Href существующего слота** — L3 `hrefById` на id этого слота (тот же контракт locale → string, что и у items пака).
- **Форма mobile bar** — первые два href из манифеста, center plus (add opportunity), далее остальное. Пак, который перечисляет три href плюс overflow (и пропускает docs-or-admin), получает этот bar из тех же chrome slices. Overlay не может добавлять или скрывать эти слоты.

Не просите интегратора класть кастомный sidebar-компонент в `components/navigation/` ради brand icons.

### For developers

## Закрытая карта иконок

Путь: `lib/navigation/primary-nav-icons.ts`. Chrome вызывает `getPrimaryNavIcon(id)`. Пакеты и overlays передают только **string ids**.

| Id | Lucide export |
|----|----------------|
| `users` | `Users` (fallback for unknown ids) |
| `briefcase` | `Briefcase` |
| `store` | `Store` |
| `user` | `UserRound` |
| `file-text` | `FileText` |
| `ellipsis` | `CircleEllipsis` |
| `more-horizontal` | `MoreHorizontal` |
| `shopping-basket` | `ShoppingBasket` |
| `shopping-bag` | `ShoppingBag` |
| `building` | `Building2` |
| `newspaper` | `Newspaper` |
| `tv` | `Tv` |
| `sparkles` | `Sparkles` |
| `gamepad` | `Gamepad2` |
| `hexagon` | `Hexagon` |
| `map` | `Map` |
| `layout-grid` | `LayoutGrid` |
| `wallet` | `Wallet` |
| `bell` | `Bell` |
| `heart` | `Heart` |
| `shopping-cart` | `ShoppingCart` |
| `message-circle` | `MessageCircle` |
| `list-todo` | `ListTodo` |
| `settings` | `Settings` |
| `sun` | `Sun` |
| `orbit` | `Orbit` |
| `calendar` | `Calendar` |
| `scale` | `Scale` |
| `hash` | `Hash` |
| `type` | `Type` |
| `moon` | `Moon` |
| `compass` | `Compass` |

Добавьте generic глиф **сюда**, прежде чем пак или overlay сошлётся на новый id. Не накладывайте этот файл иконками с именами клона.

## Overlay socket (только remap)

Layer1 поставляет `export const PRIMARY_NAV_OVERLAY = {}` в `lib/navigation/primary-nav-overlay.ts`, чтобы webpack всегда резолвил импорт. Клон перезаписывает **этот файл** (не `primary-nav.ts`) так:

{`import { ROUTES } from '@/constants/routes'

export const PRIMARY_NAV_OVERLAY = {
  iconById: { entities: 'sun' },
  labelKeysById: { entities: ['customEntities'] },
  hrefById: { entities: (locale) => ROUTES.ENTITIES(locale) },
}`}

`getPrimaryNavManifest()` прогоняет `BASE_MANIFEST` через `applyHrefOverlay` / `applyMobileOverlay`. Id, которых **нет** в манифесте пака/L1, игнорируются.

## Mobile chrome

`components/navigation/bottom-navigation.tsx` рендерит `navItems.slice(0, 2)`, затем center add control, затем `navItems.slice(2)`. Компоненты иконок берутся из `getPrimaryNavIcon`. Desktop rail: `sidebar-rail.tsx` и `sidebar-synced-layout.tsx` используют тот же helper.

Оркестратор: `components/navigation/navigation.tsx` динамически импортирует `desktop-sidebar.tsx` и `bottom-navigation.tsx`. Публичного реестра вариантов `DesktopNavigation` нет.

## Рекомендуемый путь

Нужен новый глиф? Сначала зафиксируйте его на Layer1 (`ring/web/lib/navigation/primary-nav-icons.ts`), затем укажите id в слоте пака. Cursor skill **`layer2-preset-operator`** владеет pack `primary-nav.ts`; **`ringization-implementer`** владеет L3 overlay remap. Никто не должен копировать chrome.

**Стартовый промпт (ничего не меняет, пока вы не одобрите):**

> Add generic Lucide id `` to Layer1 `lib/navigation/primary-nav-icons.ts` before pack `` references it. Do not import vertical-named icons in chrome. Overlay may only remap existing slot ids in `primary-nav-overlay.ts`.

## Ручной путь

Подтвердите, что id слота существует в составленном манифесте `primary-nav.ts` (массивы `mobile` / `desktop`). Overlay не может изобретать id.

Если icon id отсутствует в `PRIMARY_NAV_ICONS`, добавьте Lucide-импорт и запись карты на Layer1. Неизвестные id тихо падают обратно на `users`.

Установите `icon` на слоте пака **или** `PRIMARY_NAV_OVERLAY.iconById[slotId]` на клоне. Держите `platform-menu.ts` на Layer1; вертикальные overflow-дефолты кладите в `PACK.json.platformMenu`.

## Часто задаваемые вопросы

### Влияние

#### Может ли клон скрыть вкладку Store только через overlay?

Нет. Уберите или замените слот в **pack** `primary-nav.ts` (compose overwrite). Overlay только патчит `icon` / `labelKeys` / `href` на id, которые уже существуют.

#### Что будет, если пак использует `sun`, прежде чем Layer1 его перечислит?

`getPrimaryNavIcon` возвращает `Users`. Bar не падает; глиф неправильный, пока Layer1 не завезёт id.

### Миграция

#### У нас всё ещё есть clone-local sidebar-компонент. Что вместо?

Удалите форк. Направьте compose на pack `primary-nav.ts` + empty-or-remap `primary-nav-overlay.ts`. Файлы chrome остаются на Layer1.

### Ops

#### Кто владеет `platform-menu.ts`?

Layer1. Пакеты не должны rsync поверх него. Clone `ring-config.navigation.platformMenu` (`items` / `exclude` / `extra`) — это рычаг overflow-каталога.

## Связанная документация

  
- [customization/vertical-presets](/docs/customization/vertical-presets.md) — Depends-on: L1 / L2 pack / L3 overlay compose and pack.json socket.

  
- [customization/localization](/docs/customization/localization.md) — Same-workflow: nav labelKeys resolve through Layer1 → pack → overlay messages.

  
- [customization/ringization-playbook](/docs/customization/ringization-playbook.md) — Prerequisite: chrome stays on Layer1; product stays on pack or clone overlay.

  
- [customization/customization-guide](/docs/customization/customization-guide.md) — See-also: ring-config feature flags that hide routes from nav.

  
- [features/locale-system](/docs/features/locale-system.md) — Next-step: locale env used by href builders and next-intl.
