Appearance
Шаблон Подтверждено командой
Семантика
✅ Используй семантические теги
html
<header>
<h1>Welcome to my Website</h1>
</header>
<main>
<section>
<h2>Some important text</h2>
<p>More details here in this description.</p>
</section>
</main>
<footer>...</footer>❌ Не заменяй всё на div и span
html
<div class="header">
<div>Welcome to my Website</div>
</div>
<div class="content">
<div class="post">
<div>Some important text</div>
<div>More details here in this description.</div>
</div>
</div>
<div class="footer">...</div>Вложенность
✅ Держи структуру плоской
html
<section>
<h2>Title</h2>
</section>❌ Не добавляй лишние обёртки
html
<div>
<div>
<div>
<h2>Title</h2>
</div>
</div>
</div>Простота шаблона
✅ Шаблон только про отображение
html
{{ isVisible }}❌ Не пиши составные условия в шаблоне
html
{{ b1 && b2 || !b3 }}ℹ️
Шаблон — декларативное отображение уже подготовленного состояния.
Любая логика, трансформация и вычисления должны находиться вне шаблона.
Control Flow
✅ Используй встроенный control flow
html
@for (item of items; track item.id) {
<div>{{ item.name }}</div>
}❌ Не используй структурные директивы
html
<div *ngFor="let item of items">{{ item.name }}</div>Условный рендеринг
✅ Управляй отображением на уровне родителя
html
@if (user) {
<app-profile />
}❌ Не перекладывай это на дочерний
html
@if (user) {
<div>Component html...</div>
}Локальные переменные
✅ Сохраняй в локальные переменные через @if (...; as ...)
html
@if (order().customer.primaryAddress; as address) {
<div>{{ address.city }}</div>
<div>{{ address.street }}</div>
<div>{{ address.postalCode }}</div>
@if (address.country === 'DE') {
<span>🇩🇪 Germany</span>
}
}❌ Не дублируй доступ к одним и тем же данным
html
<div>{{ order().customer.primaryAddress.city }}</div>
<div>{{ order().customer.primaryAddress.street }}</div>
<div>{{ order().customer.primaryAddress.postalCode }}</div>
@if (order().customer.primaryAddress.country === 'DE') {
<span>🇩🇪 Germany</span>
}Ссылки vs кнопки
✅ Используй <a> для навигации (даже если выглядит как кнопка)
html
<a routerLink="/profile" rtsPrimaryButton> Перейти в профиль </a>❌ Не делай навигацию через <button>
html
<button rtsPrimaryButton (click)="router.navigate(['/profile'])">Перейти в профиль</button>✅ Используй <button> для действий (даже если выглядит как ссылка)
html
<button rtsDarkLink (click)="onLogout()">Выйти</button>❌ Не делай действия через <a>
html
<a rtsDarkLink (click)="onLogout()"> Выйти </a>Автотесты
✅ Добавляй rts-at на:
- Контролы формы
html
<rts-password rts-at="passwordControl" />- Ключевые действия
html
<button rtsPrimaryButton rts-at="deleteUserButton">Удалить</button>- Важные данные
html
<span rts-at="userBalance">100 ₽</span>- Ссылки
html
<a rtsSecondaryButton [href]="environment.Poa.ServiceUrl" rts-at="generatePoaLink">
Сформировать доверенность
</a>- Тултипы
html
<rts-tooltip-manual
rtsTooltipManualHover
text="Закупка является процедурой торг за единицу товара"
rts-at="isUnitBiddingTooltip"
>
...Content
</rts-tooltip-manual>✅ Используй camelCase для нейминга