From ad3d329dc2f91d41cf2aafc1ec60b4f54fa314e4 Mon Sep 17 00:00:00 2001 From: Nikita Guryev Date: Fri, 21 Mar 2025 10:53:42 +0300 Subject: [PATCH 01/15] feat(top-bar): updated docs examples (#DS-3487) --- packages/components-dev/main.scss | 2 + packages/components/top-bar/top-bar.en.md | 71 +++++-- packages/components/top-bar/top-bar.ru.md | 73 ++++--- .../docs-examples/components/top-bar/index.ts | 25 ++- .../top-bar-actions-example.ts | 132 ++++++++++++ .../top-bar-active-breadcrumb-example.ts | 153 ------------- .../top-bar-breadcrumbs-adaptive-example.ts | 201 ++++++++++++++++++ .../top-bar-breadcrumbs-example.ts | 87 +++++--- .../top-bar-overflow-example.ts | 80 ++++++- .../top-bar-overview-example.ts | 114 ++++++---- ...ar-secondary-actions-responsive-example.ts | 174 --------------- .../top-bar-secondary-actions-example.ts | 96 --------- .../top-bar-title-counter-adaptive-example.ts | 197 +++++++++++++++++ .../top-bar-title-counter-example.ts | 131 ++++++++++++ packages/docs-examples/example-module.ts | 68 +++--- 15 files changed, 1013 insertions(+), 591 deletions(-) create mode 100644 packages/docs-examples/components/top-bar/top-bar-actions/top-bar-actions-example.ts delete mode 100644 packages/docs-examples/components/top-bar/top-bar-active-breadcrumb/top-bar-active-breadcrumb-example.ts create mode 100644 packages/docs-examples/components/top-bar/top-bar-breadcrumbs-adaptive/top-bar-breadcrumbs-adaptive-example.ts delete mode 100644 packages/docs-examples/components/top-bar/top-bar-secondary-actions-responsive/top-bar-secondary-actions-responsive-example.ts delete mode 100644 packages/docs-examples/components/top-bar/top-bar-secondary-actions/top-bar-secondary-actions-example.ts create mode 100644 packages/docs-examples/components/top-bar/top-bar-title-counter-adaptive/top-bar-title-counter-adaptive-example.ts create mode 100644 packages/docs-examples/components/top-bar/top-bar-title-counter/top-bar-title-counter-example.ts diff --git a/packages/components-dev/main.scss b/packages/components-dev/main.scss index cd4027df8..5a10ac094 100644 --- a/packages/components-dev/main.scss +++ b/packages/components-dev/main.scss @@ -4,6 +4,8 @@ @use '../components/core/styles/visual/layout'; +@use '../components/core/styles/common/list'; + @use '../../apps/docs/src/styles/koobiq/default-theme/css-tokens.css'; @use '../../apps/docs/src/styles/koobiq/default-theme/css-tokens-light.css'; @use '../../apps/docs/src/styles/koobiq/default-theme/css-tokens-dark.css'; diff --git a/packages/components/top-bar/top-bar.en.md b/packages/components/top-bar/top-bar.en.md index 849040f18..05c0c67d2 100644 --- a/packages/components/top-bar/top-bar.en.md +++ b/packages/components/top-bar/top-bar.en.md @@ -1,46 +1,71 @@ -The `Top Bar` is a toolbar that remains visible on the page at all times, providing quick access to navigation and -controls. Depending on the interface requirements, it can include breadcrumbs, a title, action buttons, and other -elements. Below are various ways to use the toolbar and recommendations for adapting it to different scenarios. +The `Top Bar` is a toolbar that always remains visible on the page and provides quick access to navigation and controls. + + + +Depending on the interface requirements, it may include a logo, a title, breadcrumbs, action buttons, and other elements. + +### Page Title + +This content option is suitable for initial screens when there is no need to display the navigation path. + + + +If you need to display the number of objects on the current page, you can do so by showing a special counter next to the page title: + + ### Breadcrumbs -Use breadcrumbs to display the navigation path. This panel is always visible and helps users navigate the application. +For internal pages of a specific module, using breadcrumbs is an excellent option. This helps users navigate the application more easily. -### Replacing Breadcrumbs with a Title +### Action Buttons -For a more compact layout, replace breadcrumbs with a title that reflects the current section. +On the right side of the toolbar, there is a dedicated area for placing any actions that need to be displayed on the current page. - +We recommend using the following set of actions (from left to right): -### Active Breadcrumb Display +- Indicators (e.g., data refresh indicator) +- A group of icon buttons (e.g., filters) +- Frequently used actions as buttons (e.g., "Add...", "Share") +- Additional actions in a dropdown menu, where all secondary actions related to the current page can be placed. -The last breadcrumb in the navigation is always active and can be used for various actions. + - +### Responsive Mode -### Additional Actions +Internal elements can adjust to the toolbar size. -Additional (secondary) actions are placed in a dropdown menu for better UI convenience. +The acceptable distance between the left side and the right side with actions is **80px.** - +#### Breadcrumbs Variant -### Responsive Behavior +When the panel is compressed, the breadcrumbs will adjust as follows: -Additional actions can be moved into the dropdown menu as the screen width decreases, ensuring a seamless user experience across different devices. + - +A more detailed explanation of breadcrumb compression is provided on the [breadcrumbs](https://koobiq.io/en/components/breadcrumbs/overview) page. -### Minimum Spacing Between Elements +#### Page Title Variant - +The variant using only the page title will adjust as follows: -To ensure usability: + -- Hide button text when the screen width decreases. -- Show a tooltip with the button text on hover. -- Maintain a minimum spacing of **80px**, set via `--kbq-top-bar-spacer-min-width`. It applies to Top Bar elements, including the header. -- If a long title does not fit, truncate it with an ellipsis (**"Dashbo..."**). +#### Scroll Behavior + +The toolbar can remain fixed while scrolling the page. + +
+ +
+
Documentation Questions & Feedback
+
+ +If you have questions or want to contribute, please [create an issue](https://github.com/koobiq/angular-components/issues/new/choose) on our GitHub. + +
+
diff --git a/packages/components/top-bar/top-bar.ru.md b/packages/components/top-bar/top-bar.ru.md index aeb967a9d..cac7a55fe 100644 --- a/packages/components/top-bar/top-bar.ru.md +++ b/packages/components/top-bar/top-bar.ru.md @@ -1,49 +1,72 @@ `Top Bar` — это панель инструментов, которая всегда остается видимой на странице и обеспечивает быстрый доступ к -навигации -и управлению. В зависимости от требований интерфейса, она может включать хлебные крошки, заголовок, кнопки действий и -другие элементы. Ниже представлены различные варианты использования toolbar и рекомендации по его адаптации под разные -сценарии. +навигации и управлению. + + + +В зависимости от требований интерфейса, она может включать логотип, заголовок, хлебные крошки, кнопки действий и другие элементы. + +### Заголовок страницы + +Данный вариант наполнения подходит для начальных экранов, когда отсутствует необходимость в отображении навигационного пути. + + + +Если необходимо вывести количество объектов на текущей странице, то это можно сделать с помощью отображения рядом с заголовком страницы специального счетчика: + + ### Хлебные крошки -Используйте хлебные крошки для отображения пути навигации. Эта панель всегда видна и помогает пользователю -ориентироваться в приложении. +Для внутренних страниц отдельного модуля отлично подойдет вариант с хлебными крошками. 
Это поможет пользователю легче ориентироваться в приложении. -### Замена хлебных крошек заголовком +### Кнопки действий -Если требуется более компактное представление, замените хлебные крошки заголовком, отображающим текущий раздел. +В правой части панели инструментов располагается область для размещения любых действий, которые необходимо отобразить на текущей страницы. - +Мы рекомендуем использовать следующий набор действий (слева направо): -### Отображение активной крошки +- Индикаторы (Например, индикатор обновления данных) +- Группа кнопок-иконок (Фильтры) +- Частые действия в виде кнопок (Например, «Добавить…», «Поделиться») +- Дополнительные действия в виде дропдаун меню, куда можно отнести все второстепенные действия относящиеся к текущей странице. -Последняя крошка в навигации всегда активна и может использоваться для различных действий. + - +### Адаптивный режим -### Дополнительные действия +Внутренние элементы могут подстраиваться под размер панели. -Дополнительные (второстепенные) действия выносятся в выпадающее меню. +Допустимое расстояние между левой стороной и правой стороной с действиями – **80px.** - +#### Вариант с хлебными крошками -#### Адаптивное поведение +При сжатии панели хлебные крошки будут перестраиваться следующим образом: -Дополнительные действия могут скрываться в выпадающее меню при уменьшении ширины экрана, обеспечивая удобную навигацию на разных устройствах. + - +#### Вариант с заголовком страницы -### Минимальный отступ между элементами +Вариант с использованием только заголовка будет перестраиваться следующим образом: - + -Чтобы обеспечить удобство взаимодействия: +Более подробно сжатие хлебных крошек разобрано на странице [хлебных крошек](https://koobiq.io/ru/components/breadcrumbs/overview). -- Скрывайте текст на кнопках при уменьшении ширины экрана. -- Добавляйте тултип с текстом при наведении. -- Соблюдайте минимальный отступ **80px**, задаваемый через `--kbq-top-bar-spacer-min-width`. Он применяется к элементам топ-меню, включая заголовок. -- Чтобы длинный заголовок не ломал верстку, скрывайте часть текста многоточием (**"Дашбо..."**). +#### Поведение при прокрутке + +Панель может фиксироваться при прокрутке страницы. + +
+ +
+
Вопросы и предложения по документации
+
+ +Если у вас есть вопросы или вы хотите внести свой вклад в написание документации, пожалуйста, [создайте issue](https://github.com/koobiq/angular-components/issues/new/choose) в нашем репозитории на GitHub. + +
+
diff --git a/packages/docs-examples/components/top-bar/index.ts b/packages/docs-examples/components/top-bar/index.ts index 39d4a8b50..26aff633f 100644 --- a/packages/docs-examples/components/top-bar/index.ts +++ b/packages/docs-examples/components/top-bar/index.ts @@ -1,27 +1,30 @@ import { NgModule } from '@angular/core'; -import { TopBarActiveBreadcrumbExample } from './top-bar-active-breadcrumb/top-bar-active-breadcrumb-example'; +import { TopBarActionsExample } from './top-bar-actions/top-bar-actions-example'; +import { TopBarBreadcrumbsAdaptiveExample } from './top-bar-breadcrumbs-adaptive/top-bar-breadcrumbs-adaptive-example'; import { TopBarBreadcrumbsExample } from './top-bar-breadcrumbs/top-bar-breadcrumbs-example'; import { TopBarOverflowExample } from './top-bar-overflow/top-bar-overflow-example'; import { TopBarOverviewExample } from './top-bar-overview/top-bar-overview-example'; -import { TopBarSecondaryActionsResponsiveExample } from './top-bar-secondary-actions-responsive/top-bar-secondary-actions-responsive-example'; -import { TopBarSecondaryActionsExample } from './top-bar-secondary-actions/top-bar-secondary-actions-example'; +import { TopBarTitleCounterAdaptiveExample } from './top-bar-title-counter-adaptive/top-bar-title-counter-adaptive-example'; +import { TopBarTitleCounterExample } from './top-bar-title-counter/top-bar-title-counter-example'; export { - TopBarActiveBreadcrumbExample, + TopBarActionsExample, + TopBarBreadcrumbsAdaptiveExample, TopBarBreadcrumbsExample, TopBarOverflowExample, TopBarOverviewExample, - TopBarSecondaryActionsExample, - TopBarSecondaryActionsResponsiveExample + TopBarTitleCounterAdaptiveExample, + TopBarTitleCounterExample }; const EXAMPLES = [ - TopBarOverviewExample, - TopBarOverflowExample, + TopBarActionsExample, TopBarBreadcrumbsExample, - TopBarActiveBreadcrumbExample, - TopBarSecondaryActionsExample, - TopBarSecondaryActionsResponsiveExample + TopBarOverflowExample, + TopBarOverviewExample, + TopBarTitleCounterExample, + TopBarTitleCounterAdaptiveExample, + TopBarBreadcrumbsAdaptiveExample ]; @NgModule({ diff --git a/packages/docs-examples/components/top-bar/top-bar-actions/top-bar-actions-example.ts b/packages/docs-examples/components/top-bar/top-bar-actions/top-bar-actions-example.ts new file mode 100644 index 000000000..42c9c9827 --- /dev/null +++ b/packages/docs-examples/components/top-bar/top-bar-actions/top-bar-actions-example.ts @@ -0,0 +1,132 @@ +import { BreakpointObserver } from '@angular/cdk/layout'; +import { ChangeDetectionStrategy, Component, inject } from '@angular/core'; +import { takeUntilDestroyed, toSignal } from '@angular/core/rxjs-interop'; +import { KbqButtonModule, KbqButtonStyles } from '@koobiq/components/button'; +import { KbqComponentColors, PopUpPlacements } from '@koobiq/components/core'; +import { KbqDropdownModule } from '@koobiq/components/dropdown'; +import { KbqIconModule } from '@koobiq/components/icon'; +import { KbqOverflowItemsModule } from '@koobiq/components/overflow-items'; +import { KbqToolTipModule } from '@koobiq/components/tooltip'; +import { KbqTopBarModule } from '@koobiq/components/top-bar'; +import { map } from 'rxjs/operators'; + +type ExampleAction = { + id: string; + icon?: string; + text?: string; + action?: () => void; + style: KbqButtonStyles | string; + color: KbqComponentColors; +}; + +/** + * @title TopBar Actions + */ +@Component({ + standalone: true, + selector: 'top-bar-actions-example', + imports: [ + KbqTopBarModule, + KbqButtonModule, + KbqToolTipModule, + KbqIconModule, + KbqDropdownModule, + KbqOverflowItemsModule + ], + template: ` + +
+ Actions +
+ +
+ +
+ @for (action of actions; track action.id) { + + } + +
+ + + + @for (action of actions; track action.id) { + @if (kbqOverflowItems.hiddenItemIDs().has(action.id)) { + + } + } + +
+
+
+ `, + styles: ` + .kbq-overflow-items { + max-width: 400px; + } + `, + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class TopBarActionsExample { + isDesktop = toSignal( + inject(BreakpointObserver) + .observe('(min-width: 900px)') + .pipe( + takeUntilDestroyed(), + map(({ matches }) => matches) + ), + { initialValue: true } + ); + readonly actions: ExampleAction[] = [ + { + id: 'refresh', + icon: 'kbq-arrows-rotate_16', + text: 'Refresh', + color: KbqComponentColors.Contrast, + style: KbqButtonStyles.Transparent + }, + { + id: 'search', + icon: 'kbq-magnifying-glass_16', + color: KbqComponentColors.Contrast, + style: KbqButtonStyles.Transparent + }, + { id: 'list', icon: 'kbq-list_16', color: KbqComponentColors.Contrast, style: KbqButtonStyles.Transparent }, + { id: 'filter', icon: 'kbq-filter_16', color: KbqComponentColors.Contrast, style: KbqButtonStyles.Transparent }, + { id: 'button1', text: 'Button', color: KbqComponentColors.ContrastFade, style: '' }, + { id: 'button2', text: 'Button', color: KbqComponentColors.Contrast, style: '' } + ]; + + protected readonly KbqComponentColors = KbqComponentColors; + protected readonly KbqButtonStyles = KbqButtonStyles; + protected readonly PopUpPlacements = PopUpPlacements; +} diff --git a/packages/docs-examples/components/top-bar/top-bar-active-breadcrumb/top-bar-active-breadcrumb-example.ts b/packages/docs-examples/components/top-bar/top-bar-active-breadcrumb/top-bar-active-breadcrumb-example.ts deleted file mode 100644 index 2e325e91a..000000000 --- a/packages/docs-examples/components/top-bar/top-bar-active-breadcrumb/top-bar-active-breadcrumb-example.ts +++ /dev/null @@ -1,153 +0,0 @@ -import { BreakpointObserver } from '@angular/cdk/layout'; -import { AsyncPipe } from '@angular/common'; -import { ChangeDetectionStrategy, Component, computed, inject, signal } from '@angular/core'; -import { takeUntilDestroyed, toSignal } from '@angular/core/rxjs-interop'; -import { FormsModule } from '@angular/forms'; -import { RouterLink } from '@angular/router'; -import { KbqFormFieldModule } from '@koobiq/components-experimental/form-field'; -import { KbqBreadcrumbsModule } from '@koobiq/components/breadcrumbs'; -import { KbqButtonModule, KbqButtonStyles } from '@koobiq/components/button'; -import { KbqComponentColors, PopUpPlacements } from '@koobiq/components/core'; -import { KbqIconModule } from '@koobiq/components/icon'; -import { KbqInputModule } from '@koobiq/components/input'; -import { KbqPopoverModule } from '@koobiq/components/popover'; -import { KbqTextareaModule } from '@koobiq/components/textarea'; -import { KbqToolTipModule } from '@koobiq/components/tooltip'; -import { KbqTopBarModule } from '@koobiq/components/top-bar'; -import { map } from 'rxjs/operators'; - -/** - * @title TopBar Active Breadcrumb - */ -@Component({ - standalone: true, - selector: 'top-bar-active-breadcrumb-example', - imports: [ - FormsModule, - AsyncPipe, - RouterLink, - KbqTopBarModule, - KbqButtonModule, - KbqToolTipModule, - KbqIconModule, - KbqBreadcrumbsModule, - KbqFormFieldModule, - KbqInputModule, - KbqTextareaModule, - KbqPopoverModule - ], - template: ` - - -
-
- @for (action of actions; track $index) { - - } -
-
- `, - changeDetection: ChangeDetectionStrategy.OnPush -}) -export class TopBarActiveBreadcrumbExample { - isDesktop = toSignal( - inject(BreakpointObserver) - .observe('(min-width: 900px)') - .pipe( - takeUntilDestroyed(), - map(({ matches }) => matches) - ), - { initialValue: true } - ); - - readonly value = signal(null); - - readonly breadcrumbActionText = 'New dashboard'; - readonly actions = [ - { - title: 'Add widget', - style: KbqButtonStyles.Transparent, - color: KbqComponentColors.Contrast, - icon: 'kbq-plus_16' - }, - { - title: 'Cancel', - style: KbqButtonStyles.Outline, - color: KbqComponentColors.ContrastFade, - icon: 'kbq-undo_16' - }, - { - title: 'Save', - style: '', - color: KbqComponentColors.Contrast, - icon: 'kbq-floppy-disk_16', - disabled: computed(() => !this.value()) - } - ]; - - protected readonly KbqComponentColors = KbqComponentColors; - protected readonly KbqButtonStyles = KbqButtonStyles; - protected readonly PopUpPlacements = PopUpPlacements; -} diff --git a/packages/docs-examples/components/top-bar/top-bar-breadcrumbs-adaptive/top-bar-breadcrumbs-adaptive-example.ts b/packages/docs-examples/components/top-bar/top-bar-breadcrumbs-adaptive/top-bar-breadcrumbs-adaptive-example.ts new file mode 100644 index 000000000..31e10230c --- /dev/null +++ b/packages/docs-examples/components/top-bar/top-bar-breadcrumbs-adaptive/top-bar-breadcrumbs-adaptive-example.ts @@ -0,0 +1,201 @@ +import { BreakpointObserver } from '@angular/cdk/layout'; +import { ChangeDetectionStrategy, Component, inject } from '@angular/core'; +import { takeUntilDestroyed, toSignal } from '@angular/core/rxjs-interop'; +import { RouterLink } from '@angular/router'; +import { KbqBreadcrumbsModule } from '@koobiq/components/breadcrumbs'; +import { KbqButtonModule, KbqButtonStyles } from '@koobiq/components/button'; +import { KbqComponentColors, PopUpPlacements } from '@koobiq/components/core'; +import { KbqDropdownModule } from '@koobiq/components/dropdown'; +import { KbqIconModule } from '@koobiq/components/icon'; +import { KbqOverflowItemsModule } from '@koobiq/components/overflow-items'; +import { KbqToolTipModule } from '@koobiq/components/tooltip'; +import { KbqTopBarModule } from '@koobiq/components/top-bar'; +import { map } from 'rxjs/operators'; + +type ExampleAction = { + id: string; + icon?: string; + text?: string; + action?: () => void; + style: KbqButtonStyles | string; + color: KbqComponentColors; +}; + +@Component({ + standalone: true, + selector: 'example-top-bar-breadcrumbs', + imports: [ + KbqTopBarModule, + KbqButtonModule, + KbqToolTipModule, + KbqIconModule, + KbqDropdownModule, + KbqOverflowItemsModule, + KbqBreadcrumbsModule, + RouterLink + ], + template: ` + +
+
+ + + + + + +
+
+ +
+
+
+
+ + + + + + + + + +
+
+ `, + styles: ` + :host { + display: flex; + align-items: center; + justify-content: center; + height: 72px; + resize: horizontal; + max-width: 100%; + min-width: 110px; + overflow: hidden; + container-type: inline-size; + + .kbq-top-bar { + width: 100%; + } + } + + .example-kbq-top-bar__title { + display: inline-flex; + } + + .kbq-overflow-items { + max-width: 210px; + } + `, + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class ExampleTopBarBreadcrumbs { + isDesktop = toSignal( + inject(BreakpointObserver) + .observe('(min-width: 900px)') + .pipe( + takeUntilDestroyed(), + map(({ matches }) => matches) + ), + { initialValue: true } + ); + + readonly actions: ExampleAction[] = [ + { id: 'filter', icon: 'kbq-filter_16', color: KbqComponentColors.Contrast, style: KbqButtonStyles.Transparent }, + { id: 'button1', text: 'Apply', color: KbqComponentColors.Contrast, style: '' }, + { id: 'button2', text: 'Button 2', color: KbqComponentColors.ContrastFade, style: '' } + ]; + + protected readonly KbqComponentColors = KbqComponentColors; + protected readonly KbqButtonStyles = KbqButtonStyles; + protected readonly PopUpPlacements = PopUpPlacements; +} + +/** + * @title Top Bar Breadcrumbs Adaptive + */ +@Component({ + standalone: true, + imports: [ExampleTopBarBreadcrumbs], + selector: 'top-bar-breadcrumbs-adaptive-example', + template: ` +
+ За основу берется автоматическое сокращение хлебных крошек, когда средние пункты скрываются при отсутствии + свободного пространства. +
+ + +
+ Если пространство становится еще уже, то скрывается и левый крайний уровень у хлебных крошек, оставляя + видимым только крайний правый уровень. +
+ + +
+ Минимальная ширина левой стороны зависит от заголовка текущего пункта, который может быть обрезан до 3 + символов с добавлением трех точек (…). +
+ + +
+ После достижения минимальной ширины у левой стороны можно приступить к сжатию правой стороны с действиями. +
+ + `, + styles: ` + ::ng-deep .docs-live-example__example_top-bar-title-counter-adaptive { + background: var(--kbq-background-bg-secondary); + } + + div { + color: var(--kbq-foreground-contrast-secondary); + margin: var(--kbq-size-s) var(--kbq-size-s) 0; + } + `, + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class TopBarBreadcrumbsAdaptiveExample {} diff --git a/packages/docs-examples/components/top-bar/top-bar-breadcrumbs/top-bar-breadcrumbs-example.ts b/packages/docs-examples/components/top-bar/top-bar-breadcrumbs/top-bar-breadcrumbs-example.ts index deb397df5..c5ee47940 100644 --- a/packages/docs-examples/components/top-bar/top-bar-breadcrumbs/top-bar-breadcrumbs-example.ts +++ b/packages/docs-examples/components/top-bar/top-bar-breadcrumbs/top-bar-breadcrumbs-example.ts @@ -1,11 +1,11 @@ import { BreakpointObserver } from '@angular/cdk/layout'; -import { AsyncPipe } from '@angular/common'; import { ChangeDetectionStrategy, Component, inject } from '@angular/core'; import { takeUntilDestroyed, toSignal } from '@angular/core/rxjs-interop'; import { RouterLink } from '@angular/router'; import { KbqBreadcrumbsModule } from '@koobiq/components/breadcrumbs'; import { KbqButtonModule, KbqButtonStyles } from '@koobiq/components/button'; import { KbqComponentColors, PopUpPlacements } from '@koobiq/components/core'; +import { KbqDropdownModule } from '@koobiq/components/dropdown'; import { KbqIconModule } from '@koobiq/components/icon'; import { KbqToolTipModule } from '@koobiq/components/tooltip'; import { KbqTopBarModule } from '@koobiq/components/top-bar'; @@ -18,53 +18,82 @@ import { map } from 'rxjs/operators'; standalone: true, selector: 'top-bar-breadcrumbs-example', imports: [ - AsyncPipe, RouterLink, KbqTopBarModule, KbqButtonModule, KbqToolTipModule, KbqIconModule, - KbqBreadcrumbsModule + KbqBreadcrumbsModule, + KbqDropdownModule ], changeDetection: ChangeDetectionStrategy.OnPush, template: `
-
- +
+ + + + + +
-
- @for (action of actions; track $index) { - - } + + + + + + + + +
` diff --git a/packages/docs-examples/components/top-bar/top-bar-overflow/top-bar-overflow-example.ts b/packages/docs-examples/components/top-bar/top-bar-overflow/top-bar-overflow-example.ts index 58504116b..aba628244 100644 --- a/packages/docs-examples/components/top-bar/top-bar-overflow/top-bar-overflow-example.ts +++ b/packages/docs-examples/components/top-bar/top-bar-overflow/top-bar-overflow-example.ts @@ -1,6 +1,5 @@ import { BreakpointObserver } from '@angular/cdk/layout'; import { CdkScrollable } from '@angular/cdk/overlay'; -import { AsyncPipe } from '@angular/common'; import { AfterViewInit, ChangeDetectionStrategy, @@ -11,8 +10,10 @@ import { WritableSignal } from '@angular/core'; import { takeUntilDestroyed, toSignal } from '@angular/core/rxjs-interop'; +import { KbqBadgeModule } from '@koobiq/components/badge'; import { KbqButtonModule, KbqButtonStyles } from '@koobiq/components/button'; import { KbqComponentColors, PopUpPlacements } from '@koobiq/components/core'; +import { KbqDlModule } from '@koobiq/components/dl'; import { KbqIconModule } from '@koobiq/components/icon'; import { KbqToolTipModule } from '@koobiq/components/tooltip'; import { KbqTopBarModule } from '@koobiq/components/top-bar'; @@ -25,21 +26,23 @@ import { auditTime, map } from 'rxjs/operators'; standalone: true, selector: 'top-bar-overflow-example', imports: [ - AsyncPipe, CdkScrollable, KbqTopBarModule, KbqButtonModule, KbqToolTipModule, - KbqIconModule + KbqIconModule, + KbqDlModule, + KbqBadgeModule ], changeDetection: ChangeDetectionStrategy.OnPush, template: `
-
- +
+ Page + + 13 294
-
Dashboard
@@ -63,23 +66,80 @@ import { auditTime, map } from 'rxjs/operators';
-
Scroll down ⬇️ to see box-shadow
+
+ + Описание + + В НАСА описывают случай, когда человек случайно оказался в пространстве, близком к вакууму + (давление ниже 1 Па) из-за утечки воздуха из скафандра. + + + Статус + Значок + + Статус + Новый + + Дополнительно + + Космос — это бескрайнее пространство, полное загадок и чудес. Он начинается за пределами нашей + атмосферы и простирается до самых дальних уголков Вселенной. В космосе находятся миллиарды + звезд, планет и галактик, каждая из которых имеет свою уникальную историю и характеристики. + Исследование космоса помогает нам лучше понять не только саму Вселенную, но и наше место в ней. +
+
+ Одним из самых захватывающих аспектов космоса является его бесконечность. Ученые до сих пор не + могут точно определить, где заканчивается Вселенная. Существуют теории о том, что она может быть + бесконечной или же иметь определенные границы. Это открывает множество вопросов о том, что + находится за пределами видимого космоса и какие формы жизни могут существовать на других + планетах. Космические исследования также играют важную роль в развитии технологий на Земле. + Многие изобретения, которые мы используем в повседневной жизни, были разработаны благодаря + космическим программам. Например, спутниковая навигация, системы связи и даже некоторые + медицинские технологии имеют свои корни в космических исследованиях. Это показывает, как + изучение космоса может приносить пользу человечеству в целом. Наконец, космос вдохновляет людей + на творчество и мечты. С детства мы смотрим на звезды и задаемся вопросами о том, что может быть + за пределами нашей планеты. Фильмы, книги и искусство часто черпают вдохновение из космоса, + создавая образы, которые захватывают воображение. Это стремление к исследованию и открытию + нового делает космос не только научной, но и культурной частью нашей жизни. +
+
+
`, styles: ` + ::ng-deep .docs-live-example__example_top-bar-overflow { + background: var(--kbq-background-bg-secondary); + padding: var(--kbq-size-3xl); + } + :host { display: flex; flex-direction: column; height: 400px; + border-radius: var(--kbq-size-border-radius); + border: 1px solid var(--kbq-line-contrast-less); + background: var(--kbq-background-bg); + } + + :host .kbq-top-bar { + border-radius: var(--kbq-size-border-radius) var(--kbq-size-border-radius) 0 0; } .overflow-content-example { height: 100%; overflow-y: auto; scroll-behavior: smooth; - border: 1px solid var(--kbq-line-contrast-less); - border-top: 0; - border-radius: 0 0 var(--kbq-size-border-radius) var(--kbq-size-border-radius); + padding: 0 var(--kbq-size-xxl); + } + + .example-kbq-top-bar__counter { + color: var(--kbq-foreground-contrast-tertiary); + flex: 1; + } + + .example-kbq-top-bar__title { + display: inline-flex; + white-space: nowrap; } ` }) diff --git a/packages/docs-examples/components/top-bar/top-bar-overview/top-bar-overview-example.ts b/packages/docs-examples/components/top-bar/top-bar-overview/top-bar-overview-example.ts index 90ecd7dba..996223c7e 100644 --- a/packages/docs-examples/components/top-bar/top-bar-overview/top-bar-overview-example.ts +++ b/packages/docs-examples/components/top-bar/top-bar-overview/top-bar-overview-example.ts @@ -1,9 +1,9 @@ import { BreakpointObserver } from '@angular/cdk/layout'; -import { AsyncPipe } from '@angular/common'; import { ChangeDetectionStrategy, Component, inject } from '@angular/core'; import { takeUntilDestroyed, toSignal } from '@angular/core/rxjs-interop'; import { KbqButtonModule, KbqButtonStyles } from '@koobiq/components/button'; import { KbqComponentColors, PopUpPlacements } from '@koobiq/components/core'; +import { KbqDropdownModule } from '@koobiq/components/dropdown'; import { KbqIconModule } from '@koobiq/components/icon'; import { KbqToolTipModule } from '@koobiq/components/tooltip'; import { KbqTopBarModule } from '@koobiq/components/top-bar'; @@ -16,41 +16,86 @@ import { map } from 'rxjs/operators'; standalone: true, selector: 'top-bar-overview-example', imports: [ - AsyncPipe, KbqTopBarModule, KbqButtonModule, KbqToolTipModule, - KbqIconModule + KbqIconModule, + KbqDropdownModule ], template: ` -
-
- +
+
+ + + + + +
-
Dashboard
+
Dashboards
- @for (action of actions; track $index) { - - } + + + + + + + +
`, @@ -67,27 +112,6 @@ export class TopBarOverviewExample { { initialValue: true } ); - readonly actions = [ - { - title: 'Add widget', - style: KbqButtonStyles.Transparent, - color: KbqComponentColors.Contrast, - icon: 'kbq-plus_16' - }, - { - title: 'Cancel', - style: KbqButtonStyles.Outline, - color: KbqComponentColors.ContrastFade, - icon: 'kbq-undo_16' - }, - { - title: 'Save', - style: '', - color: KbqComponentColors.Contrast, - icon: 'kbq-floppy-disk_16' - } - ]; - protected readonly KbqComponentColors = KbqComponentColors; protected readonly KbqButtonStyles = KbqButtonStyles; protected readonly PopUpPlacements = PopUpPlacements; diff --git a/packages/docs-examples/components/top-bar/top-bar-secondary-actions-responsive/top-bar-secondary-actions-responsive-example.ts b/packages/docs-examples/components/top-bar/top-bar-secondary-actions-responsive/top-bar-secondary-actions-responsive-example.ts deleted file mode 100644 index 32c3f2c95..000000000 --- a/packages/docs-examples/components/top-bar/top-bar-secondary-actions-responsive/top-bar-secondary-actions-responsive-example.ts +++ /dev/null @@ -1,174 +0,0 @@ -import { BreakpointObserver } from '@angular/cdk/layout'; -import { ChangeDetectionStrategy, Component, inject } from '@angular/core'; -import { takeUntilDestroyed, toSignal } from '@angular/core/rxjs-interop'; -import { KbqButtonModule, KbqButtonStyles } from '@koobiq/components/button'; -import { KbqComponentColors, KbqOptionModule, PopUpPlacements } from '@koobiq/components/core'; -import { KbqDropdownModule } from '@koobiq/components/dropdown'; -import { KbqIconModule } from '@koobiq/components/icon'; -import { KbqOverflowItemsModule } from '@koobiq/components/overflow-items'; -import { KbqToolTipModule } from '@koobiq/components/tooltip'; -import { KbqTopBarModule } from '@koobiq/components/top-bar'; -import { map } from 'rxjs/operators'; - -type ExampleAction = { - id: string; - icon: string; -}; - -/** - * @title TopBar Secondary Actions Responsive - */ -@Component({ - standalone: true, - selector: 'top-bar-secondary-actions-responsive-example', - imports: [ - KbqTopBarModule, - KbqOverflowItemsModule, - KbqDropdownModule, - KbqButtonModule, - KbqIconModule, - KbqOptionModule, - KbqToolTipModule - ], - changeDetection: ChangeDetectionStrategy.OnPush, - template: ` - -
-
- -
-
Dashboard
-
- -
- -
- - - -
- @for (action of secondaryActions; track action.id) { - - } -
- - - - - @for (action of secondaryActions; track action.id) { - @if (kbqOverflowItems.hiddenItemIDs().has(action.id)) { - - } - } - -
-
-
-
- `, - styles: ` - .kbq-overflow-items { - max-width: 451px; - gap: var(--kbq-top-bar-right-gap); - height: 100%; - padding: 1px; - } - - .kbq-top-bar-container__end { - position: relative; - flex-grow: 1; - overflow: hidden; - height: 100%; - flex-wrap: nowrap; - white-space: nowrap; - padding: 1px; - } - - @media screen and (max-width: 768px) { - .kbq-overflow-items { - max-width: 152px; - } - } - - @media screen and (min-width: 1201px) { - .kbq-overflow-items { - max-width: 32px; - } - } - ` -}) -export class TopBarSecondaryActionsResponsiveExample { - isDesktop = toSignal( - inject(BreakpointObserver) - .observe('(min-width: 900px)') - .pipe( - takeUntilDestroyed(), - map(({ matches }) => matches) - ), - { initialValue: true } - ); - - readonly secondaryActions: ExampleAction[] = [ - { id: 'Verdict', icon: 'kbq-question-circle_16' }, - { id: 'Link to incident', icon: 'kbq-link_16' }, - { id: 'Archive', icon: 'kbq-box-archive-arrow-down_16' }, - { id: 'Remove', icon: 'kbq-trash_16' } - ]; - - protected readonly PopUpPlacements = PopUpPlacements; - protected readonly KbqComponentColors = KbqComponentColors; - protected readonly KbqButtonStyles = KbqButtonStyles; -} diff --git a/packages/docs-examples/components/top-bar/top-bar-secondary-actions/top-bar-secondary-actions-example.ts b/packages/docs-examples/components/top-bar/top-bar-secondary-actions/top-bar-secondary-actions-example.ts deleted file mode 100644 index 6b071d673..000000000 --- a/packages/docs-examples/components/top-bar/top-bar-secondary-actions/top-bar-secondary-actions-example.ts +++ /dev/null @@ -1,96 +0,0 @@ -import { ChangeDetectionStrategy, Component } from '@angular/core'; -import { KbqButtonModule, KbqButtonStyles } from '@koobiq/components/button'; -import { KbqComponentColors, KbqOptionModule, PopUpPlacements } from '@koobiq/components/core'; -import { KbqDropdownModule } from '@koobiq/components/dropdown'; -import { KbqIconModule } from '@koobiq/components/icon'; -import { KbqOverflowItemsModule } from '@koobiq/components/overflow-items'; -import { KbqTopBarModule } from '@koobiq/components/top-bar'; - -type ExampleAction = { - id: string; - icon: string; -}; - -/** - * @title TopBar Secondary Actions Simple - */ -@Component({ - standalone: true, - selector: 'top-bar-secondary-actions-example', - imports: [ - KbqTopBarModule, - KbqOverflowItemsModule, - KbqDropdownModule, - KbqButtonModule, - KbqIconModule, - KbqOptionModule - ], - changeDetection: ChangeDetectionStrategy.OnPush, - template: ` - -
-
- -
-
Dashboard
-
- -
- -
- @for (action of actions; track action.id) { - - } -
- - - - - @for (action of actions; track action.id) { - @if (kbqOverflowItems.hiddenItemIDs().has(action.id)) { - - } - } - -
-
-
- `, - styles: ` - .kbq-overflow-items { - padding: 1px; - } - ` -}) -export class TopBarSecondaryActionsExample { - readonly actions: ExampleAction[] = [ - { id: 'Responsible', icon: 'kbq-user_16' }, - { id: 'Status', icon: 'kbq-arrow-right-s_16' }, - { id: 'Verdict', icon: 'kbq-question-circle_16' }, - { id: 'Link to incident', icon: 'kbq-link_16' }, - { id: 'Archive', icon: 'kbq-box-archive-arrow-down_16' }, - { id: 'Remove', icon: 'kbq-trash_16' } - ]; - - protected readonly PopUpPlacements = PopUpPlacements; - protected readonly KbqComponentColors = KbqComponentColors; - protected readonly KbqButtonStyles = KbqButtonStyles; -} diff --git a/packages/docs-examples/components/top-bar/top-bar-title-counter-adaptive/top-bar-title-counter-adaptive-example.ts b/packages/docs-examples/components/top-bar/top-bar-title-counter-adaptive/top-bar-title-counter-adaptive-example.ts new file mode 100644 index 000000000..9bc1f9153 --- /dev/null +++ b/packages/docs-examples/components/top-bar/top-bar-title-counter-adaptive/top-bar-title-counter-adaptive-example.ts @@ -0,0 +1,197 @@ +import { BreakpointObserver } from '@angular/cdk/layout'; +import { ChangeDetectionStrategy, Component, inject } from '@angular/core'; +import { takeUntilDestroyed, toSignal } from '@angular/core/rxjs-interop'; +import { KbqButtonModule, KbqButtonStyles } from '@koobiq/components/button'; +import { KbqComponentColors, PopUpPlacements } from '@koobiq/components/core'; +import { KbqDropdownModule } from '@koobiq/components/dropdown'; +import { KbqIconModule } from '@koobiq/components/icon'; +import { KbqOverflowItemsModule } from '@koobiq/components/overflow-items'; +import { KbqToolTipModule } from '@koobiq/components/tooltip'; +import { KbqTopBarModule } from '@koobiq/components/top-bar'; +import { map } from 'rxjs/operators'; + +type ExampleAction = { + id: string; + icon?: string; + text?: string; + action?: () => void; + style: KbqButtonStyles | string; + color: KbqComponentColors; +}; + +@Component({ + standalone: true, + selector: 'example-top-bar', + imports: [ + KbqTopBarModule, + KbqButtonModule, + KbqToolTipModule, + KbqIconModule, + KbqDropdownModule, + KbqOverflowItemsModule + ], + template: ` + +
+
+ + + + + + +
+
+ Page Header + + 10 +
+
+ +
+ +
+ @for (action of actions; track action.id) { + + } + +
+ + + + @for (action of actions; track action.id) { + @if (kbqOverflowItems.hiddenItemIDs().has(action.id)) { + + } + } + +
+
+
+ `, + styles: ` + :host { + display: flex; + align-items: center; + justify-content: center; + height: 72px; + resize: horizontal; + max-width: 100%; + min-width: 110px; + overflow: hidden; + container-type: inline-size; + + .kbq-top-bar { + width: 100%; + } + } + + .example-kbq-top-bar__counter { + color: var(--kbq-foreground-contrast-tertiary); + } + + .example-kbq-top-bar__title { + display: inline-flex; + } + + .kbq-overflow-items { + max-width: 210px; + } + `, + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class ExampleTopBar { + isDesktop = toSignal( + inject(BreakpointObserver) + .observe('(min-width: 900px)') + .pipe( + takeUntilDestroyed(), + map(({ matches }) => matches) + ), + { initialValue: true } + ); + + readonly actions: ExampleAction[] = [ + { id: 'filter', icon: 'kbq-filter_16', color: KbqComponentColors.Contrast, style: KbqButtonStyles.Transparent }, + { id: 'button1', text: 'Apply', color: KbqComponentColors.Contrast, style: '' }, + { id: 'button2', text: 'Button 2', color: KbqComponentColors.ContrastFade, style: '' } + ]; + + protected readonly KbqComponentColors = KbqComponentColors; + protected readonly KbqButtonStyles = KbqButtonStyles; + protected readonly PopUpPlacements = PopUpPlacements; +} + +/** + * @title Top Bar Title And Counter Adaptive + */ +@Component({ + standalone: true, + imports: [ExampleTopBar], + selector: 'top-bar-title-counter-adaptive-example', + template: ` +
When there is free space, the title and actions are fully displayed.
+ + +
+ The minimum width of the left side depends on the page title, which can be truncated to 3 characters with + the addition of three dots (…). +
+ + +
+ After reaching the minimum width of the left side, you can start compressing the right side with the + actions. +
+ + `, + styles: ` + ::ng-deep .docs-live-example__example_top-bar-title-counter-adaptive { + background: var(--kbq-background-bg-secondary); + } + + div { + color: var(--kbq-foreground-contrast-secondary); + margin: var(--kbq-size-s) var(--kbq-size-s) 0; + } + `, + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class TopBarTitleCounterAdaptiveExample {} diff --git a/packages/docs-examples/components/top-bar/top-bar-title-counter/top-bar-title-counter-example.ts b/packages/docs-examples/components/top-bar/top-bar-title-counter/top-bar-title-counter-example.ts new file mode 100644 index 000000000..b176486aa --- /dev/null +++ b/packages/docs-examples/components/top-bar/top-bar-title-counter/top-bar-title-counter-example.ts @@ -0,0 +1,131 @@ +import { BreakpointObserver } from '@angular/cdk/layout'; +import { ChangeDetectionStrategy, Component, inject } from '@angular/core'; +import { takeUntilDestroyed, toSignal } from '@angular/core/rxjs-interop'; +import { KbqButtonModule, KbqButtonStyles } from '@koobiq/components/button'; +import { KbqComponentColors, PopUpPlacements } from '@koobiq/components/core'; +import { KbqDropdownModule } from '@koobiq/components/dropdown'; +import { KbqIconModule } from '@koobiq/components/icon'; +import { KbqToolTipModule } from '@koobiq/components/tooltip'; +import { KbqTopBarModule } from '@koobiq/components/top-bar'; +import { map } from 'rxjs/operators'; + +/** + * @title TopBar With Title And Counter + */ +@Component({ + standalone: true, + selector: 'top-bar-title-counter-example', + imports: [ + KbqTopBarModule, + KbqButtonModule, + KbqToolTipModule, + KbqIconModule, + KbqDropdownModule + ], + template: ` + +
+
+ + + + + + +
+
+ Dashboards + + 13 294 +
+
+ +
+ +
+ + + + + + + + +
+
+ `, + styles: ` + .example-kbq-top-bar__counter { + color: var(--kbq-foreground-contrast-tertiary); + } + + .example-kbq-top-bar__title { + display: inline-flex; + } + `, + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class TopBarTitleCounterExample { + isDesktop = toSignal( + inject(BreakpointObserver) + .observe('(min-width: 900px)') + .pipe( + takeUntilDestroyed(), + map(({ matches }) => matches) + ), + { initialValue: true } + ); + + protected readonly KbqComponentColors = KbqComponentColors; + protected readonly KbqButtonStyles = KbqButtonStyles; + protected readonly PopUpPlacements = PopUpPlacements; +} diff --git a/packages/docs-examples/example-module.ts b/packages/docs-examples/example-module.ts index 44301a80f..220328b38 100644 --- a/packages/docs-examples/example-module.ts +++ b/packages/docs-examples/example-module.ts @@ -3685,16 +3685,30 @@ export const EXAMPLE_COMPONENTS: {[id: string]: LiveExample} = { "primaryFile": "tooltip-style-example.ts", "importPath": "components/tooltip" }, - "top-bar-active-breadcrumb": { - "packagePath": "components/top-bar/top-bar-active-breadcrumb", - "title": "TopBar Active Breadcrumb", - "componentName": "TopBarActiveBreadcrumbExample", + "top-bar-actions": { + "packagePath": "components/top-bar/top-bar-actions", + "title": "TopBar Actions", + "componentName": "TopBarActionsExample", "files": [ - "top-bar-active-breadcrumb-example.ts" + "top-bar-actions-example.ts" ], - "selector": "top-bar-active-breadcrumb-example", + "selector": "top-bar-actions-example", "additionalComponents": [], - "primaryFile": "top-bar-active-breadcrumb-example.ts", + "primaryFile": "top-bar-actions-example.ts", + "importPath": "components/top-bar" + }, + "top-bar-breadcrumbs-adaptive": { + "packagePath": "components/top-bar/top-bar-breadcrumbs-adaptive", + "title": "Top Bar Breadcrumbs Adaptive", + "componentName": "TopBarBreadcrumbsAdaptiveExample", + "files": [ + "top-bar-breadcrumbs-adaptive-example.ts" + ], + "selector": "top-bar-breadcrumbs-adaptive-example", + "additionalComponents": [ + "ExampleTopBarBreadcrumbs" + ], + "primaryFile": "top-bar-breadcrumbs-adaptive-example.ts", "importPath": "components/top-bar" }, "top-bar-breadcrumbs": { @@ -3733,28 +3747,30 @@ export const EXAMPLE_COMPONENTS: {[id: string]: LiveExample} = { "primaryFile": "top-bar-overview-example.ts", "importPath": "components/top-bar" }, - "top-bar-secondary-actions-responsive": { - "packagePath": "components/top-bar/top-bar-secondary-actions-responsive", - "title": "TopBar Secondary Actions Responsive", - "componentName": "TopBarSecondaryActionsResponsiveExample", + "top-bar-title-counter-adaptive": { + "packagePath": "components/top-bar/top-bar-title-counter-adaptive", + "title": "Top Bar Title And Counter Adaptive", + "componentName": "TopBarTitleCounterAdaptiveExample", "files": [ - "top-bar-secondary-actions-responsive-example.ts" + "top-bar-title-counter-adaptive-example.ts" ], - "selector": "top-bar-secondary-actions-responsive-example", - "additionalComponents": [], - "primaryFile": "top-bar-secondary-actions-responsive-example.ts", + "selector": "top-bar-title-counter-adaptive-example", + "additionalComponents": [ + "ExampleTopBar" + ], + "primaryFile": "top-bar-title-counter-adaptive-example.ts", "importPath": "components/top-bar" }, - "top-bar-secondary-actions": { - "packagePath": "components/top-bar/top-bar-secondary-actions", - "title": "TopBar Secondary Actions Simple", - "componentName": "TopBarSecondaryActionsExample", + "top-bar-title-counter": { + "packagePath": "components/top-bar/top-bar-title-counter", + "title": "TopBar With Title And Counter", + "componentName": "TopBarTitleCounterExample", "files": [ - "top-bar-secondary-actions-example.ts" + "top-bar-title-counter-example.ts" ], - "selector": "top-bar-secondary-actions-example", + "selector": "top-bar-title-counter-example", "additionalComponents": [], - "primaryFile": "top-bar-secondary-actions-example.ts", + "primaryFile": "top-bar-title-counter-example.ts", "importPath": "components/top-bar" }, "tree-select-child-selection-overview": { @@ -4667,7 +4683,9 @@ return import('@koobiq/docs-examples/components/tooltip'); return import('@koobiq/docs-examples/components/tooltip'); case 'tooltip-style': return import('@koobiq/docs-examples/components/tooltip'); - case 'top-bar-active-breadcrumb': + case 'top-bar-actions': +return import('@koobiq/docs-examples/components/top-bar'); + case 'top-bar-breadcrumbs-adaptive': return import('@koobiq/docs-examples/components/top-bar'); case 'top-bar-breadcrumbs': return import('@koobiq/docs-examples/components/top-bar'); @@ -4675,9 +4693,9 @@ return import('@koobiq/docs-examples/components/top-bar'); return import('@koobiq/docs-examples/components/top-bar'); case 'top-bar-overview': return import('@koobiq/docs-examples/components/top-bar'); - case 'top-bar-secondary-actions-responsive': + case 'top-bar-title-counter-adaptive': return import('@koobiq/docs-examples/components/top-bar'); - case 'top-bar-secondary-actions': + case 'top-bar-title-counter': return import('@koobiq/docs-examples/components/top-bar'); case 'tree-select-child-selection-overview': return import('@koobiq/docs-examples/components/tree-select'); From 9e42fe4d2de7d7d3c5a8a9ae39a51b423b0b8709 Mon Sep 17 00:00:00 2001 From: Nikita Guryev Date: Wed, 26 Mar 2025 18:18:45 +0300 Subject: [PATCH 02/15] chore(top-bar): dev example --- packages/components-dev/top-bar/template.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/components-dev/top-bar/template.html b/packages/components-dev/top-bar/template.html index 80887b5c3..8e9f58f5f 100644 --- a/packages/components-dev/top-bar/template.html +++ b/packages/components-dev/top-bar/template.html @@ -1,4 +1,4 @@
- +
From 2f498d257e8d7577d191f7c1f9a058b7f7a2a932 Mon Sep 17 00:00:00 2001 From: Nikita Guryev Date: Wed, 9 Apr 2025 18:11:59 +0300 Subject: [PATCH 03/15] chore: fixed examples & layout bugs --- .../docs-live-example-viewer.scss | 1 + apps/docs/src/assets/example-icon.svg | 12 +++ apps/docs/src/styles/_examples.scss | 13 ++- packages/components/top-bar/top-bar.scss | 8 ++ packages/components/top-bar/top-bar.ts | 11 ++- .../top-bar-actions-example.ts | 2 +- .../top-bar-breadcrumbs-adaptive-example.ts | 2 +- .../top-bar-breadcrumbs-example.ts | 39 +------- .../top-bar-overflow-example.ts | 90 ++++++++++++------- .../top-bar-overview-example.ts | 17 +--- .../top-bar-title-counter-adaptive-example.ts | 44 +++------ .../top-bar-title-counter-example.ts | 17 +--- .../components/top-bar.api.md | 2 + 13 files changed, 126 insertions(+), 132 deletions(-) create mode 100644 apps/docs/src/assets/example-icon.svg diff --git a/apps/docs/src/app/components/live-example-viewer/docs-live-example-viewer.scss b/apps/docs/src/app/components/live-example-viewer/docs-live-example-viewer.scss index 5da1eef03..74d291715 100644 --- a/apps/docs/src/app/components/live-example-viewer/docs-live-example-viewer.scss +++ b/apps/docs/src/app/components/live-example-viewer/docs-live-example-viewer.scss @@ -6,6 +6,7 @@ border-radius: inherit; border-bottom-left-radius: 0; border-bottom-right-radius: 0; + background: var(--docs-live-example-example-background); } .docs-live-example-viewer { diff --git a/apps/docs/src/assets/example-icon.svg b/apps/docs/src/assets/example-icon.svg new file mode 100644 index 000000000..e1b8f6efa --- /dev/null +++ b/apps/docs/src/assets/example-icon.svg @@ -0,0 +1,12 @@ + + + + diff --git a/apps/docs/src/styles/_examples.scss b/apps/docs/src/styles/_examples.scss index c42fcf2a3..2e0540283 100644 --- a/apps/docs/src/styles/_examples.scss +++ b/apps/docs/src/styles/_examples.scss @@ -1,3 +1,12 @@ -.docs-live-example__example_breadcrumbs-with-auto-wrap-adaptive { - background: var(--kbq-background-bg-secondary); +.docs-live-example__example { + &.docs-live-example__example_top-bar-overflow, + &.docs-live-example__example_top-bar-breadcrumbs-adaptive, + &.docs-live-example__example_top-bar-title-counter-adaptive, + &.docs-live-example__example_breadcrumbs-with-auto-wrap-adaptive { + --docs-live-example-example-background: var(--kbq-background-bg-secondary); + } + + &.docs-live-example__example_top-bar-overflow { + padding: var(--kbq-size-3xl); + } } diff --git a/packages/components/top-bar/top-bar.scss b/packages/components/top-bar/top-bar.scss index 1233cec08..046fd62ae 100644 --- a/packages/components/top-bar/top-bar.scss +++ b/packages/components/top-bar/top-bar.scss @@ -27,6 +27,14 @@ gap: var(--kbq-top-bar-right-gap); } + &.kbq-top-bar-container__with-overflow-items { + gap: unset; + + > .kbq-overflow-item:not(:last-of-type) { + margin-right: var(--kbq-top-bar-right-gap); + } + } + &.kbq-top-bar_with-shadow { box-shadow: var(--kbq-top-bar-shadow-bottom); transition: box-shadow var(--kbq-top-bar-shadow-transition); diff --git a/packages/components/top-bar/top-bar.ts b/packages/components/top-bar/top-bar.ts index 401e835b5..0ae5e00af 100644 --- a/packages/components/top-bar/top-bar.ts +++ b/packages/components/top-bar/top-bar.ts @@ -3,10 +3,12 @@ import { ChangeDetectionStrategy, Component, Directive, + inject, input, Input, ViewEncapsulation } from '@angular/core'; +import { KbqOverflowItems } from '@koobiq/components/overflow-items'; @Directive({ standalone: true, @@ -26,7 +28,8 @@ export class KbqTopBarSpacer {} host: { class: 'kbq-top-bar-container', '[class.kbq-top-bar-container__start]': 'placement() === "start"', - '[class.kbq-top-bar-container__end]': 'placement() === "end"' + '[class.kbq-top-bar-container__end]': 'placement() === "end"', + '[class.kbq-top-bar-container__with-overflow-items]': 'overflowItems' } }) export class KbqTopBarContainer { @@ -34,6 +37,12 @@ export class KbqTopBarContainer { * Conditionally applies a CSS class based on the value */ placement = input.required<'start' | 'end'>(); + /** + * Track if container has `KbqOverflowItems` directive assigned. + * Used to replace `gap` with `margin` so `KbqOverflowItems` will calculate correct width on resize. + * @docs-private + */ + protected readonly overflowItems = inject(KbqOverflowItems, { optional: true, self: true }); } @Component({ diff --git a/packages/docs-examples/components/top-bar/top-bar-actions/top-bar-actions-example.ts b/packages/docs-examples/components/top-bar/top-bar-actions/top-bar-actions-example.ts index 42c9c9827..ae6e2a043 100644 --- a/packages/docs-examples/components/top-bar/top-bar-actions/top-bar-actions-example.ts +++ b/packages/docs-examples/components/top-bar/top-bar-actions/top-bar-actions-example.ts @@ -97,7 +97,7 @@ type ExampleAction = { changeDetection: ChangeDetectionStrategy.OnPush }) export class TopBarActionsExample { - isDesktop = toSignal( + readonly isDesktop = toSignal( inject(BreakpointObserver) .observe('(min-width: 900px)') .pipe( diff --git a/packages/docs-examples/components/top-bar/top-bar-breadcrumbs-adaptive/top-bar-breadcrumbs-adaptive-example.ts b/packages/docs-examples/components/top-bar/top-bar-breadcrumbs-adaptive/top-bar-breadcrumbs-adaptive-example.ts index 31e10230c..140bebf0a 100644 --- a/packages/docs-examples/components/top-bar/top-bar-breadcrumbs-adaptive/top-bar-breadcrumbs-adaptive-example.ts +++ b/packages/docs-examples/components/top-bar/top-bar-breadcrumbs-adaptive/top-bar-breadcrumbs-adaptive-example.ts @@ -134,7 +134,7 @@ type ExampleAction = { changeDetection: ChangeDetectionStrategy.OnPush }) export class ExampleTopBarBreadcrumbs { - isDesktop = toSignal( + readonly isDesktop = toSignal( inject(BreakpointObserver) .observe('(min-width: 900px)') .pipe( diff --git a/packages/docs-examples/components/top-bar/top-bar-breadcrumbs/top-bar-breadcrumbs-example.ts b/packages/docs-examples/components/top-bar/top-bar-breadcrumbs/top-bar-breadcrumbs-example.ts index c5ee47940..9add585c4 100644 --- a/packages/docs-examples/components/top-bar/top-bar-breadcrumbs/top-bar-breadcrumbs-example.ts +++ b/packages/docs-examples/components/top-bar/top-bar-breadcrumbs/top-bar-breadcrumbs-example.ts @@ -31,20 +31,7 @@ import { map } from 'rxjs/operators';
- - - - - - + example icon
-
- @for (action of actions; track $index) { +
+ @for (action of actions; track action.id) { } + +
+ + + + @for (action of actions; track action.id) { + @if (kbqOverflowItems.hiddenItemIDs().has(action.id)) { + + } + } + +
@@ -77,9 +113,6 @@ import { auditTime, map } from 'rxjs/operators'; Статус Значок - Статус - Новый - Дополнительно Космос — это бескрайнее пространство, полное загадок и чудес. Он начинается за пределами нашей @@ -107,11 +140,6 @@ import { auditTime, map } from 'rxjs/operators';
`, styles: ` - ::ng-deep .docs-live-example__example_top-bar-overflow { - background: var(--kbq-background-bg-secondary); - padding: var(--kbq-size-3xl); - } - :host { display: flex; flex-direction: column; @@ -119,10 +147,14 @@ import { auditTime, map } from 'rxjs/operators'; border-radius: var(--kbq-size-border-radius); border: 1px solid var(--kbq-line-contrast-less); background: var(--kbq-background-bg); - } - :host .kbq-top-bar { - border-radius: var(--kbq-size-border-radius) var(--kbq-size-border-radius) 0 0; + .kbq-top-bar { + border-radius: var(--kbq-size-border-radius) var(--kbq-size-border-radius) 0 0; + } + + .kbq-overflow-items { + max-width: 291px; + } } .overflow-content-example { @@ -144,7 +176,7 @@ import { auditTime, map } from 'rxjs/operators'; ` }) export class TopBarOverflowExample implements AfterViewInit { - isDesktop = toSignal( + readonly isDesktop = toSignal( inject(BreakpointObserver) .observe('(min-width: 768px)') .pipe( @@ -158,19 +190,17 @@ export class TopBarOverflowExample implements AfterViewInit { readonly hasOverflow: WritableSignal = signal(false); - readonly actions = [ - { - title: 'Cancel', - style: KbqButtonStyles.Outline, - color: KbqComponentColors.ContrastFade, - icon: 'kbq-undo_16' - }, + readonly actions: ExampleAction[] = [ { - title: 'Save', - style: '', + id: 'search', + icon: 'kbq-magnifying-glass_16', color: KbqComponentColors.Contrast, - icon: 'kbq-floppy-disk_16' - } + style: KbqButtonStyles.Transparent + }, + { id: 'list', icon: 'kbq-list_16', color: KbqComponentColors.Contrast, style: KbqButtonStyles.Transparent }, + { id: 'filter', icon: 'kbq-filter_16', color: KbqComponentColors.Contrast, style: KbqButtonStyles.Transparent }, + { id: 'button1', text: 'Add object', color: KbqComponentColors.Contrast, style: '' }, + { id: 'button2', text: 'Button', color: KbqComponentColors.ContrastFade, style: '' } ]; protected readonly PopUpPlacements = PopUpPlacements; diff --git a/packages/docs-examples/components/top-bar/top-bar-overview/top-bar-overview-example.ts b/packages/docs-examples/components/top-bar/top-bar-overview/top-bar-overview-example.ts index 996223c7e..fe72d13b9 100644 --- a/packages/docs-examples/components/top-bar/top-bar-overview/top-bar-overview-example.ts +++ b/packages/docs-examples/components/top-bar/top-bar-overview/top-bar-overview-example.ts @@ -30,20 +30,7 @@ import { map } from 'rxjs/operators'; placement="start" >
- - - - - - + example icon
Dashboards
@@ -102,7 +89,7 @@ import { map } from 'rxjs/operators'; changeDetection: ChangeDetectionStrategy.OnPush }) export class TopBarOverviewExample { - isDesktop = toSignal( + readonly isDesktop = toSignal( inject(BreakpointObserver) .observe('(min-width: 900px)') .pipe( diff --git a/packages/docs-examples/components/top-bar/top-bar-title-counter-adaptive/top-bar-title-counter-adaptive-example.ts b/packages/docs-examples/components/top-bar/top-bar-title-counter-adaptive/top-bar-title-counter-adaptive-example.ts index 9bc1f9153..fb2088745 100644 --- a/packages/docs-examples/components/top-bar/top-bar-title-counter-adaptive/top-bar-title-counter-adaptive-example.ts +++ b/packages/docs-examples/components/top-bar/top-bar-title-counter-adaptive/top-bar-title-counter-adaptive-example.ts @@ -38,20 +38,7 @@ type ExampleAction = { placement="start" >
- - - - - - + example icon
Page Header @@ -112,17 +99,21 @@ type ExampleAction = { align-items: center; justify-content: center; height: 72px; - resize: horizontal; max-width: 100%; min-width: 110px; - overflow: hidden; container-type: inline-size; .kbq-top-bar { width: 100%; + overflow: hidden; } } + :host .kbq-overflow-items { + max-width: 190px; + min-width: 32px; + } + .example-kbq-top-bar__counter { color: var(--kbq-foreground-contrast-tertiary); } @@ -130,15 +121,11 @@ type ExampleAction = { .example-kbq-top-bar__title { display: inline-flex; } - - .kbq-overflow-items { - max-width: 210px; - } `, changeDetection: ChangeDetectionStrategy.OnPush }) export class ExampleTopBar { - isDesktop = toSignal( + readonly isDesktop = toSignal( inject(BreakpointObserver) .observe('(min-width: 900px)') .pipe( @@ -167,29 +154,26 @@ export class ExampleTopBar { imports: [ExampleTopBar], selector: 'top-bar-title-counter-adaptive-example', template: ` -
When there is free space, the title and actions are fully displayed.
+
+ When there is free space, the title and actions are fully displayed. +
-
+
The minimum width of the left side depends on the page title, which can be truncated to 3 characters with the addition of three dots (…).
-
+
After reaching the minimum width of the left side, you can start compressing the right side with the actions.
`, styles: ` - ::ng-deep .docs-live-example__example_top-bar-title-counter-adaptive { - background: var(--kbq-background-bg-secondary); - } - - div { + :host .example-text { color: var(--kbq-foreground-contrast-secondary); - margin: var(--kbq-size-s) var(--kbq-size-s) 0; } `, changeDetection: ChangeDetectionStrategy.OnPush diff --git a/packages/docs-examples/components/top-bar/top-bar-title-counter/top-bar-title-counter-example.ts b/packages/docs-examples/components/top-bar/top-bar-title-counter/top-bar-title-counter-example.ts index b176486aa..70bb10863 100644 --- a/packages/docs-examples/components/top-bar/top-bar-title-counter/top-bar-title-counter-example.ts +++ b/packages/docs-examples/components/top-bar/top-bar-title-counter/top-bar-title-counter-example.ts @@ -30,20 +30,7 @@ import { map } from 'rxjs/operators'; placement="start" >
- - - - - - + example icon
Dashboards @@ -115,7 +102,7 @@ import { map } from 'rxjs/operators'; changeDetection: ChangeDetectionStrategy.OnPush }) export class TopBarTitleCounterExample { - isDesktop = toSignal( + readonly isDesktop = toSignal( inject(BreakpointObserver) .observe('(min-width: 900px)') .pipe( diff --git a/tools/public_api_guard/components/top-bar.api.md b/tools/public_api_guard/components/top-bar.api.md index 05e892f88..8a31501ef 100644 --- a/tools/public_api_guard/components/top-bar.api.md +++ b/tools/public_api_guard/components/top-bar.api.md @@ -6,6 +6,7 @@ import * as i0 from '@angular/core'; import { InputSignal } from '@angular/core'; +import { KbqOverflowItems } from '@koobiq/components/overflow-items'; // @public (undocumented) export class KbqTopBar { @@ -20,6 +21,7 @@ export class KbqTopBar { // @public export class KbqTopBarContainer { + protected readonly overflowItems: KbqOverflowItems | null; placement: InputSignal<"start" | "end">; // (undocumented) static ɵdir: i0.ɵɵDirectiveDeclaration; From 2e81d8c3957bb6a24c0e9f3f412d4bed369cd60e Mon Sep 17 00:00:00 2001 From: Nikita Guryev Date: Fri, 11 Apr 2025 17:46:42 +0300 Subject: [PATCH 04/15] chore: fixed examples & layout --- packages/components/top-bar/top-bar.en.md | 4 +-- packages/components/top-bar/top-bar.ru.md | 8 ++--- packages/components/top-bar/top-bar.scss | 6 ++-- .../top-bar-actions-example.ts | 2 +- .../top-bar-breadcrumbs-adaptive-example.ts | 35 +++++-------------- .../top-bar-breadcrumbs-example.ts | 6 ++-- .../top-bar-title-counter-adaptive-example.ts | 2 +- 7 files changed, 24 insertions(+), 39 deletions(-) diff --git a/packages/components/top-bar/top-bar.en.md b/packages/components/top-bar/top-bar.en.md index 05c0c67d2..a1995c4da 100644 --- a/packages/components/top-bar/top-bar.en.md +++ b/packages/components/top-bar/top-bar.en.md @@ -16,7 +16,7 @@ If you need to display the number of objects on the current page, you can do so ### Breadcrumbs -For internal pages of a specific module, using breadcrumbs is an excellent option. This helps users navigate the application more easily. +For internal pages of a specific module, using [breadcrumbs](/en/components/breadcrumbs) is an excellent option. This helps users navigate the application more easily. @@ -37,7 +37,7 @@ We recommend using the following set of actions (from left to right): Internal elements can adjust to the toolbar size. -The acceptable distance between the left side and the right side with actions is **80px.** +The minimum allowed spacing between the left side and the right side with actions is **80px** and is defined using the CSS variable `--kbq-top-bar-spacer-min-width`. #### Breadcrumbs Variant diff --git a/packages/components/top-bar/top-bar.ru.md b/packages/components/top-bar/top-bar.ru.md index cac7a55fe..9dc60fb78 100644 --- a/packages/components/top-bar/top-bar.ru.md +++ b/packages/components/top-bar/top-bar.ru.md @@ -17,17 +17,17 @@ ### Хлебные крошки -Для внутренних страниц отдельного модуля отлично подойдет вариант с хлебными крошками. 
Это поможет пользователю легче ориентироваться в приложении. +Для внутренних страниц отдельного модуля отлично подойдет вариант с [хлебными крошками](/ru/components/breadcrumbs). 
Это поможет пользователю легче ориентироваться в приложении. ### Кнопки действий -В правой части панели инструментов располагается область для размещения любых действий, которые необходимо отобразить на текущей страницы. +В правой части панели инструментов располагается область для размещения любых действий, которые необходимо отобразить на текущей странице. Мы рекомендуем использовать следующий набор действий (слева направо): -- Индикаторы (Например, индикатор обновления данных) +- Индикаторы (например, индикатор обновления данных) - Группа кнопок-иконок (Фильтры) - Частые действия в виде кнопок (Например, «Добавить…», «Поделиться») - Дополнительные действия в виде дропдаун меню, куда можно отнести все второстепенные действия относящиеся к текущей странице. @@ -38,7 +38,7 @@ Внутренние элементы могут подстраиваться под размер панели. -Допустимое расстояние между левой стороной и правой стороной с действиями – **80px.** +Допустимое минимальное расстояние между левой частью и правой частью с действиями составляет **80px** и задается через CSS-переменную `--kbq-top-bar-spacer-min-width`. #### Вариант с хлебными крошками diff --git a/packages/components/top-bar/top-bar.scss b/packages/components/top-bar/top-bar.scss index 046fd62ae..46e4fcfcf 100644 --- a/packages/components/top-bar/top-bar.scss +++ b/packages/components/top-bar/top-bar.scss @@ -14,12 +14,14 @@ .kbq-top-bar-spacer { height: 100%; - flex: 1 0 var(--kbq-top-bar-spacer-min-width); + flex: 0 0 var(--kbq-top-bar-spacer-min-width); } .kbq-top-bar-container__start { display: flex; gap: var(--kbq-top-bar-left-gap); + flex: 1; + justify-content: flex-start; } .kbq-top-bar-container__end { @@ -27,7 +29,7 @@ gap: var(--kbq-top-bar-right-gap); } - &.kbq-top-bar-container__with-overflow-items { + .kbq-top-bar-container__with-overflow-items { gap: unset; > .kbq-overflow-item:not(:last-of-type) { diff --git a/packages/docs-examples/components/top-bar/top-bar-actions/top-bar-actions-example.ts b/packages/docs-examples/components/top-bar/top-bar-actions/top-bar-actions-example.ts index ae6e2a043..46527d657 100644 --- a/packages/docs-examples/components/top-bar/top-bar-actions/top-bar-actions-example.ts +++ b/packages/docs-examples/components/top-bar/top-bar-actions/top-bar-actions-example.ts @@ -91,7 +91,7 @@ type ExampleAction = { `, styles: ` .kbq-overflow-items { - max-width: 400px; + max-width: 368px; } `, changeDetection: ChangeDetectionStrategy.OnPush diff --git a/packages/docs-examples/components/top-bar/top-bar-breadcrumbs-adaptive/top-bar-breadcrumbs-adaptive-example.ts b/packages/docs-examples/components/top-bar/top-bar-breadcrumbs-adaptive/top-bar-breadcrumbs-adaptive-example.ts index 140bebf0a..500d3ff57 100644 --- a/packages/docs-examples/components/top-bar/top-bar-breadcrumbs-adaptive/top-bar-breadcrumbs-adaptive-example.ts +++ b/packages/docs-examples/components/top-bar/top-bar-breadcrumbs-adaptive/top-bar-breadcrumbs-adaptive-example.ts @@ -38,22 +38,9 @@ type ExampleAction = {
- - - - - - + example icon
-
+