From c21beb0bfbfe4cf919bebd37247361b90cdbac8e Mon Sep 17 00:00:00 2001 From: dpavlenishvili Date: Wed, 6 Nov 2024 15:57:12 +0400 Subject: [PATCH 1/9] feat(core): shellbar redesign, add branding and additional context area --- libs/core/shellbar/index.ts | 5 + .../shellbar-branding.component.html | 20 ++ .../shellbar-branding.component.spec.ts | 21 ++ .../shellbar-branding.component.ts | 26 ++ .../shellbar-context-area.component.spec.ts | 21 ++ .../shellbar-context-area.component.ts | 121 +++++++ .../shellbar-overflow-priority.directive.ts | 13 + .../shellbar-separator.component.spec.ts | 21 ++ .../shellbar-separator.component.ts | 16 + .../shellbar-spacer.component.spec.ts | 21 ++ .../shellbar-spacer.component.ts | 17 + libs/core/shellbar/shellbar.component.html | 24 +- libs/core/shellbar/shellbar.component.ts | 18 +- libs/core/shellbar/tokens.ts | 2 + .../shellbar-options-example.component.html | 69 ++++ .../shellbar-options-example.component.ts | 327 ++++++++++++++++++ .../shellbar/shellbar-docs.component.html | 22 ++ .../core/shellbar/shellbar-docs.component.ts | 20 +- package.json | 4 +- yarn.lock | 24 +- 20 files changed, 789 insertions(+), 23 deletions(-) create mode 100644 libs/core/shellbar/shellbar-branding/shellbar-branding.component.html create mode 100644 libs/core/shellbar/shellbar-branding/shellbar-branding.component.spec.ts create mode 100644 libs/core/shellbar/shellbar-branding/shellbar-branding.component.ts create mode 100644 libs/core/shellbar/shellbar-context-area/shellbar-context-area.component.spec.ts create mode 100644 libs/core/shellbar/shellbar-context-area/shellbar-context-area.component.ts create mode 100644 libs/core/shellbar/shellbar-overflow-priority.directive.ts create mode 100644 libs/core/shellbar/shellbar-separator/shellbar-separator.component.spec.ts create mode 100644 libs/core/shellbar/shellbar-separator/shellbar-separator.component.ts create mode 100644 libs/core/shellbar/shellbar-spacer/shellbar-spacer.component.spec.ts create mode 100644 libs/core/shellbar/shellbar-spacer/shellbar-spacer.component.ts create mode 100644 libs/docs/core/shellbar/examples/shellbar-options-example/shellbar-options-example.component.html create mode 100644 libs/docs/core/shellbar/examples/shellbar-options-example/shellbar-options-example.component.ts diff --git a/libs/core/shellbar/index.ts b/libs/core/shellbar/index.ts index 569cabbe53c..1e63345ef2c 100644 --- a/libs/core/shellbar/index.ts +++ b/libs/core/shellbar/index.ts @@ -7,8 +7,13 @@ export * from './product-menu/product-menu.component'; export * from './shellbar-action/shellbar-action.component'; export * from './shellbar-actions-mobile/shellbar-actions-mobile.component'; export * from './shellbar-actions/shellbar-actions.component'; +export * from './shellbar-branding/shellbar-branding.component'; +export * from './shellbar-context-area/shellbar-context-area.component'; export * from './shellbar-logo/shellbar-logo.component'; +export * from './shellbar-overflow-priority.directive'; +export * from './shellbar-separator/shellbar-separator.component'; export * from './shellbar-sidenav.directive'; +export * from './shellbar-spacer/shellbar-spacer.component'; export * from './shellbar-subtitle/shellbar-subtitle.component'; export * from './shellbar-title/shellbar-title.component'; export * from './shellbar.component'; diff --git a/libs/core/shellbar/shellbar-branding/shellbar-branding.component.html b/libs/core/shellbar/shellbar-branding/shellbar-branding.component.html new file mode 100644 index 00000000000..f3f74bd39b6 --- /dev/null +++ b/libs/core/shellbar/shellbar-branding/shellbar-branding.component.html @@ -0,0 +1,20 @@ +
+ + +
+ + + + + + +
+
diff --git a/libs/core/shellbar/shellbar-branding/shellbar-branding.component.spec.ts b/libs/core/shellbar/shellbar-branding/shellbar-branding.component.spec.ts new file mode 100644 index 00000000000..6b5c00130dc --- /dev/null +++ b/libs/core/shellbar/shellbar-branding/shellbar-branding.component.spec.ts @@ -0,0 +1,21 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ShellbarBrandingComponent } from './shellbar-branding.component'; + +describe('ShellbarBrandingComponent', () => { + let component: ShellbarBrandingComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ShellbarBrandingComponent] + }).compileComponents(); + + fixture = TestBed.createComponent(ShellbarBrandingComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/libs/core/shellbar/shellbar-branding/shellbar-branding.component.ts b/libs/core/shellbar/shellbar-branding/shellbar-branding.component.ts new file mode 100644 index 00000000000..853aec1de03 --- /dev/null +++ b/libs/core/shellbar/shellbar-branding/shellbar-branding.component.ts @@ -0,0 +1,26 @@ +import { ChangeDetectionStrategy, Component, Input, ViewEncapsulation } from '@angular/core'; +import { Nullable } from '@fundamental-ngx/cdk/utils'; +import { FD_SHELLBAR_BRANDING_COMPONENT } from '../tokens'; + +@Component({ + selector: 'fd-shellbar-branding', + standalone: true, + templateUrl: './shellbar-branding.component.html', + encapsulation: ViewEncapsulation.None, + changeDetection: ChangeDetectionStrategy.OnPush, + providers: [ + { + provide: FD_SHELLBAR_BRANDING_COMPONENT, + useExisting: ShellbarBrandingComponent + } + ] +}) +export class ShellbarBrandingComponent { + /** Callback that hanldles the response to clicks on any of the actions. */ + @Input() + callback: Nullable<(event: MouseEvent) => void>; + + /** add aria label dynamically to add to the button */ + @Input() + ariaLabel: Nullable; +} diff --git a/libs/core/shellbar/shellbar-context-area/shellbar-context-area.component.spec.ts b/libs/core/shellbar/shellbar-context-area/shellbar-context-area.component.spec.ts new file mode 100644 index 00000000000..133fdaeb2d9 --- /dev/null +++ b/libs/core/shellbar/shellbar-context-area/shellbar-context-area.component.spec.ts @@ -0,0 +1,21 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ShellbarContextAreaComponent } from './shellbar-context-area.component'; + +describe('ShellbarContextAreaComponent', () => { + let component: ShellbarContextAreaComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ShellbarContextAreaComponent] + }).compileComponents(); + + fixture = TestBed.createComponent(ShellbarContextAreaComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/libs/core/shellbar/shellbar-context-area/shellbar-context-area.component.ts b/libs/core/shellbar/shellbar-context-area/shellbar-context-area.component.ts new file mode 100644 index 00000000000..ea4703d60fb --- /dev/null +++ b/libs/core/shellbar/shellbar-context-area/shellbar-context-area.component.ts @@ -0,0 +1,121 @@ +import { + AfterViewInit, + ChangeDetectionStrategy, + Component, + ContentChildren, + DestroyRef, + ElementRef, + QueryList +} from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; +import { ResizeObserverService } from '@fundamental-ngx/cdk/utils'; +import { ShellbarHidePriorityDirective } from '../shellbar-overflow-priority.directive'; + +/** + * Component representing the context area of the shellbar. + * It manages the visibility of its child elements based on the available width. + */ +@Component({ + selector: 'fd-shellbar-context-area', + standalone: true, + template: ` `, + changeDetection: ChangeDetectionStrategy.OnPush, + host: { + '[class.fd-shellbar__group]': 'true', + '[class.fd-shellbar__group--context-area]': 'true' + }, + styles: [ + ` + :host { + min-width: 0; + } + ` + ] +}) +export class ShellbarContextAreaComponent implements AfterViewInit { + /** @hidden */ + @ContentChildren(ShellbarHidePriorityDirective, { descendants: true }) + priorityElements: QueryList; + + /** @hidden */ + constructor( + private el: ElementRef, + private resizeObserverService: ResizeObserverService, + private _destroyRef: DestroyRef + ) {} + + /** @hidden */ + ngAfterViewInit(): void { + this.resizeObserverService + .observe(this.el) + .pipe(takeUntilDestroyed(this._destroyRef)) + .subscribe(() => this.updateVisibility()); + requestAnimationFrame(() => this.updateVisibility()); + } + + /** + * Updates the visibility of the child elements based on the available width. + * This method ensures that the elements with the highest priority are shown + * while hiding the lower priority elements if there is not enough space. + * + * The method works by: + * 1. Sorting the elements based on their priority. + * 2. Calculating the total width of the currently shown elements. + * 3. Comparing the total width with the available width. + * 4. Iteratively hiding the last shown element if the total width exceeds the available width. + * 5. Iteratively showing the first hidden element if there is enough space. + * 6. Ensuring all elements fit within the available width without recursion. + */ + updateVisibility(): void { + const elements = this.priorityElements.toArray().sort((a, b) => a.priority - b.priority); + const availableWidth = this.getAvailableWidth(); + let allItemsWidth = this.calculateShownElementsWidth(elements); + + // Hide elements until the total width is within the available width + while (allItemsWidth > availableWidth) { + const shownElements = elements.filter((el) => el.el.nativeElement.style.display !== 'none'); + if (shownElements.length === 0) { + break; + } + shownElements[shownElements.length - 1].el.nativeElement.style.display = 'none'; + allItemsWidth = this.calculateShownElementsWidth(elements); + } + + // Show elements if there is enough space + let hiddenElements = elements.filter((el) => el.el.nativeElement.style.display === 'none'); + while (hiddenElements.length > 0 && allItemsWidth <= availableWidth) { + hiddenElements[0].el.nativeElement.style.display = ''; + allItemsWidth = this.calculateShownElementsWidth(elements); + if (allItemsWidth > availableWidth) { + hiddenElements[0].el.nativeElement.style.display = 'none'; + break; + } + hiddenElements = elements.filter((el) => el.el.nativeElement.style.display === 'none'); + } + } + + /** + * Calculates the total gap between the visible elements. + * Avoids negative gap for single or no elements. + */ + private calculateTotalGap(elementsLength: number): number { + const gap = parseFloat(window.getComputedStyle(this.el.nativeElement).gap || '0'); + return gap * Math.max(elementsLength - 1, 0); + } + + /** + * Calculates the total width of the shown elements, including the gaps. + */ + private calculateShownElementsWidth(elements: ShellbarHidePriorityDirective[]): number { + const shownElements = elements.filter((el) => el.el.nativeElement.style.display !== 'none'); + const totalWidth = shownElements.reduce((acc, el) => acc + el.el.nativeElement.clientWidth, 0); + return totalWidth + this.calculateTotalGap(shownElements.length); + } + + /** + * Gets the available width of the container. + */ + private getAvailableWidth(): number { + return this.el.nativeElement.offsetWidth; + } +} diff --git a/libs/core/shellbar/shellbar-overflow-priority.directive.ts b/libs/core/shellbar/shellbar-overflow-priority.directive.ts new file mode 100644 index 00000000000..1bf3cc28545 --- /dev/null +++ b/libs/core/shellbar/shellbar-overflow-priority.directive.ts @@ -0,0 +1,13 @@ +import { Directive, ElementRef, Input } from '@angular/core'; + +@Directive({ + selector: '[fdShellbarHidePriority]', + standalone: true +}) +export class ShellbarHidePriorityDirective { + /** @hidden */ + @Input('fdShellbarHidePriority') priority: any; + + /** @hidden */ + constructor(public el: ElementRef) {} +} diff --git a/libs/core/shellbar/shellbar-separator/shellbar-separator.component.spec.ts b/libs/core/shellbar/shellbar-separator/shellbar-separator.component.spec.ts new file mode 100644 index 00000000000..92f2f15635b --- /dev/null +++ b/libs/core/shellbar/shellbar-separator/shellbar-separator.component.spec.ts @@ -0,0 +1,21 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ShellbarSeparatorComponent } from './shellbar-separator.component'; + +describe('ShellbarSeparatorComponent', () => { + let component: ShellbarSeparatorComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ShellbarSeparatorComponent] + }).compileComponents(); + + fixture = TestBed.createComponent(ShellbarSeparatorComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/libs/core/shellbar/shellbar-separator/shellbar-separator.component.ts b/libs/core/shellbar/shellbar-separator/shellbar-separator.component.ts new file mode 100644 index 00000000000..6170a2c4169 --- /dev/null +++ b/libs/core/shellbar/shellbar-separator/shellbar-separator.component.ts @@ -0,0 +1,16 @@ +import { ChangeDetectionStrategy, Component } from '@angular/core'; + +@Component({ + selector: 'fd-shellbar-separator', + template: ``, + changeDetection: ChangeDetectionStrategy.OnPush, + standalone: true, + styles: [ + ` + :host { + display: flex; + } + ` + ] +}) +export class ShellbarSeparatorComponent {} diff --git a/libs/core/shellbar/shellbar-spacer/shellbar-spacer.component.spec.ts b/libs/core/shellbar/shellbar-spacer/shellbar-spacer.component.spec.ts new file mode 100644 index 00000000000..936d4bb0412 --- /dev/null +++ b/libs/core/shellbar/shellbar-spacer/shellbar-spacer.component.spec.ts @@ -0,0 +1,21 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ShellbarSpacerComponent } from './shellbar-spacer.component'; + +describe('ShellbarSpacerComponent', () => { + let component: ShellbarSpacerComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ShellbarSpacerComponent] + }).compileComponents(); + + fixture = TestBed.createComponent(ShellbarSpacerComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/libs/core/shellbar/shellbar-spacer/shellbar-spacer.component.ts b/libs/core/shellbar/shellbar-spacer/shellbar-spacer.component.ts new file mode 100644 index 00000000000..204ddba195e --- /dev/null +++ b/libs/core/shellbar/shellbar-spacer/shellbar-spacer.component.ts @@ -0,0 +1,17 @@ +import { ChangeDetectionStrategy, Component } from '@angular/core'; + +@Component({ + selector: 'fd-shellbar-spacer', + template: ``, + changeDetection: ChangeDetectionStrategy.OnPush, + standalone: true, + styles: [ + ` + :host { + display: flex; + flex: 1; + } + ` + ] +}) +export class ShellbarSpacerComponent {} diff --git a/libs/core/shellbar/shellbar.component.html b/libs/core/shellbar/shellbar.component.html index 846d05470d3..1817b695f69 100644 --- a/libs/core/shellbar/shellbar.component.html +++ b/libs/core/shellbar/shellbar.component.html @@ -11,16 +11,26 @@ [class.fd-shellbar__group--basis-auto]="groupFlex?.product?.flexBasisAuto" > - - @if (!_hideTitleComponents) { - -
- -
- + + @if (brandingComponent) { + + } @else { + + @if (!_hideTitleComponents) { + +
+ +
+ + } } } + @if (!_hideAllComponents) { + + + + } diff --git a/libs/core/shellbar/shellbar.component.ts b/libs/core/shellbar/shellbar.component.ts index fcbd25a52da..acec544aa33 100644 --- a/libs/core/shellbar/shellbar.component.ts +++ b/libs/core/shellbar/shellbar.component.ts @@ -28,7 +28,8 @@ import equal from 'fast-deep-equal'; import { BehaviorSubject, Subscription, debounceTime, distinctUntilChanged } from 'rxjs'; import { Breakpoints, NormalizedBreakpoint, ShellbarGroupFlexOptions, ShellbarSizes } from './model/shellbar-sizes'; import { ShellbarActionsComponent } from './shellbar-actions/shellbar-actions.component'; -import { FD_SHELLBAR_COMPONENT, FD_SHELLBAR_SEARCH_COMPONENT } from './tokens'; +import { ShellbarBrandingComponent } from './shellbar-branding/shellbar-branding.component'; +import { FD_SHELLBAR_BRANDING_COMPONENT, FD_SHELLBAR_COMPONENT, FD_SHELLBAR_SEARCH_COMPONENT } from './tokens'; /** * The shellbar offers consistent, responsive navigation across all products and applications. @@ -164,6 +165,18 @@ export class ShellbarComponent implements AfterContentInit, AfterViewInit, OnDes return this._searchComponent; } + /** + * Search component placed inside the shellbar + */ + @ContentChild(FD_SHELLBAR_BRANDING_COMPONENT, { descendants: true, static: false }) + set brandingComponent(component: Nullable) { + this._brandingComponent = component; + } + + get brandingComponent(): Nullable { + return this._brandingComponent; + } + /** @hidden */ @ContentChild(ShellbarActionsComponent) private _actions?: ShellbarActionsComponent; @@ -203,6 +216,9 @@ export class ShellbarComponent implements AfterContentInit, AfterViewInit, OnDes /** @hidden */ private _searchComponent: Nullable; + /** @hidden */ + private _brandingComponent: Nullable; + /** @hidden */ private readonly _currentSize$ = new BehaviorSubject(this._currentSize); diff --git a/libs/core/shellbar/tokens.ts b/libs/core/shellbar/tokens.ts index 49a35f5f1e1..8a76bb4bfc6 100644 --- a/libs/core/shellbar/tokens.ts +++ b/libs/core/shellbar/tokens.ts @@ -6,6 +6,8 @@ export const FD_SHELLBAR_SEARCH_CONFIG = new InjectionToken('FdShellbarSearchCon export const FD_SHELLBAR_SEARCH_COMPONENT = new InjectionToken('FdShellbarSearchComponent'); +export const FD_SHELLBAR_BRANDING_COMPONENT = new InjectionToken('FdShellbarBrandingComponent'); + export const FD_SHELLBAR_ACTION_COMPONENT = new InjectionToken('FdShellbarActionComponent'); export const FD_SHELLBAR_COMPONENT = new InjectionToken('FdShellbarComponent'); diff --git a/libs/docs/core/shellbar/examples/shellbar-options-example/shellbar-options-example.component.html b/libs/docs/core/shellbar/examples/shellbar-options-example/shellbar-options-example.component.html new file mode 100644 index 00000000000..aca2e9d60ea --- /dev/null +++ b/libs/docs/core/shellbar/examples/shellbar-options-example/shellbar-options-example.component.html @@ -0,0 +1,69 @@ + + + + + + +
+ + + + + + {{ productMenuControl }} + Subtitle + + + + + + + + + + + + @if (showSearch) { + + } + + @for (action of actions; track action) { + + } + + + + + + +
+

 

+ diff --git a/libs/docs/core/shellbar/examples/shellbar-options-example/shellbar-options-example.component.ts b/libs/docs/core/shellbar/examples/shellbar-options-example/shellbar-options-example.component.ts new file mode 100644 index 00000000000..536cd01b972 --- /dev/null +++ b/libs/docs/core/shellbar/examples/shellbar-options-example/shellbar-options-example.component.ts @@ -0,0 +1,327 @@ +import { Component } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { GenericTagComponent, IconComponent, ObjectStatusComponent } from '@fundamental-ngx/core'; +import { ButtonComponent } from '@fundamental-ngx/core/button'; +import { ContentDensityDirective } from '@fundamental-ngx/core/content-density'; +import { ProductSwitchItem, ProductSwitchModule } from '@fundamental-ngx/core/product-switch'; +import { SegmentedButtonModule } from '@fundamental-ngx/core/segmented-button'; +import { + ProductMenuComponent, + ShellbarActionComponent, + ShellbarActionsComponent, + ShellbarBrandingComponent, + ShellbarComponent, + ShellbarContextAreaComponent, + ShellbarHidePriorityDirective, + ShellbarLogoComponent, + ShellbarMenuItem, + ShellbarSeparatorComponent, + ShellbarSizes, + ShellbarSpacerComponent, + ShellbarSubtitleComponent, + ShellbarTitleComponent, + ShellbarUser, + ShellbarUserMenu +} from '@fundamental-ngx/core/shellbar'; +import { FdTranslatePipe } from '@fundamental-ngx/i18n'; +import { + PlatformSearchFieldModule, + SearchInput, + SuggestionItem, + ValueLabelItem +} from '@fundamental-ngx/platform/search-field'; + +@Component({ + selector: 'fd-shellbar-options-example', + templateUrl: './shellbar-options-example.component.html', + standalone: true, + imports: [ + SegmentedButtonModule, + FormsModule, + ButtonComponent, + ShellbarComponent, + ShellbarLogoComponent, + ProductMenuComponent, + ShellbarSubtitleComponent, + PlatformSearchFieldModule, + ContentDensityDirective, + ShellbarActionsComponent, + ShellbarActionComponent, + ProductSwitchModule, + ShellbarTitleComponent, + ShellbarBrandingComponent, + ShellbarContextAreaComponent, + ShellbarSeparatorComponent, + ShellbarSpacerComponent, + ShellbarHidePriorityDirective, + GenericTagComponent, + ObjectStatusComponent, + FdTranslatePipe, + IconComponent + ] +}) +export class ShellbarOptionsExampleComponent { + currentSize: ShellbarSizes = 'xl'; + + showSearch = true; + + sizesWidth = { + s: 320, + m: 720, + l: 1024, + xl: 1900 + }; + + searchTerm = ''; + + inputText = ''; + + productMenuControl = 'Portal'; + + categories: ValueLabelItem[] = [ + { + value: 'red', + label: 'Red' + }, + { + value: 'orange', + label: 'Orange' + }, + { + value: 'yellow', + label: 'Yellow' + }, + { + value: 'green', + label: 'Green' + }, + { + value: 'blue', + label: 'Blue' + }, + { + value: 'indigo', + label: 'Indigo' + }, + { + value: 'violet', + label: 'Violet' + } + ]; + + suggestions: SuggestionItem[] = [ + { + value: 'Apple' + }, + { + value: 'Banana' + }, + { + value: 'Blueberry' + }, + { + value: 'Cherry' + }, + { + value: 'Grape' + }, + { + value: 'Lemon' + }, + { + value: 'Lime' + }, + { + value: 'Orange' + }, + { + value: 'Peach' + }, + { + value: 'Pineapple' + }, + { + value: 'Plum' + }, + { + value: 'Raspberry' + } + ]; + + productMenuItems: ShellbarMenuItem[] = [ + { + name: 'Application A', + callback: () => { + alert('Application A Clicked'); + } + }, + { + name: 'Application B', + callback: () => { + alert('Application B Clicked'); + } + }, + { + name: 'Application C', + callback: () => { + alert('Application C Clicked'); + } + }, + { + name: 'Application D', + callback: () => { + alert('Application D Clicked'); + } + } + ]; + + user: ShellbarUser = { + fullName: 'William Willson', + colorAccent: 1 + }; + + userMenu: ShellbarUserMenu[] = [ + { text: 'Settings', callback: this.settingsCallback }, + { text: 'Sign Out', callback: this.signOutCallback } + ]; + + actions = [ + { + glyph: 'da', + callback: this.actionJouleAssistantCallback, + label: 'Joule Digital Assistant', + notificationCount: 0, + notificationLabel: 'Joule Digital Assistant' + }, + { + glyph: 'bell', + callback: this.actionNotificationCallback, + label: 'Notifications', + notificationCount: 72, + notificationLabel: 'Unread Notifications' + }, + { + glyph: 'feedback', + callback: this.actionFeedbackCallback, + label: 'Feedback', + notificationCount: 0, + notificationLabel: 'User Feedback' + }, + { + glyph: 'sys-help', + callback: this.actionHelpCallback, + label: 'Help', + notificationCount: 0, + notificationLabel: 'Help Center' + } + ]; + + productSwitcher: ProductSwitchItem[] = [ + { + title: 'Home', + subtitle: 'Central Home', + icon: 'home', + callback: () => this.productSwitcherCallback('Home '), + disabledDragAndDrop: true, + stickToPosition: true + }, + { + title: 'Analytics Cloud', + subtitle: 'Analytics Cloud', + icon: 'business-objects-experience', + selected: true + }, + { + title: 'Catalog', + subtitle: 'Ariba', + icon: 'contacts' + }, + { + title: 'Guided Buying', + icon: 'credit-card' + }, + { + title: 'Strategic Procurement', + icon: 'cart-3' + }, + { + title: 'Vendor Managemen', + subtitle: 'Fieldglass', + icon: 'shipping-status' + }, + { + title: 'Human Capital Management', + icon: 'customer' + }, + { + title: 'Sales Cloud', + subtitle: 'Sales Cloud', + icon: 'sales-notification' + }, + { + title: 'Commerce Cloud', + subtitle: 'Commerce Cloud', + icon: 'retail-store' + }, + { + title: 'Marketing Cloud', + subtitle: 'Marketing Cloud', + icon: 'marketing-campaign' + }, + { + title: 'Service Cloud', + icon: 'family-care' + }, + { + title: 'S/4HANA', + icon: 'batch-payments' + } + ]; + + settingsCallback($event): void { + console.log($event); + alert('Settings Clicked'); + } + + signOutCallback($event): void { + console.log($event); + alert('Sign Out Clicked'); + } + + actionJouleAssistantCallback($event): void { + console.log($event); + alert('Joule Digital Assistant Clicked'); + } + + actionNotificationCallback($event): void { + console.log($event); + alert('Notification Action Clicked'); + } + + actionFeedbackCallback($event): void { + console.log($event); + alert('Feedback Clicked'); + } + + actionHelpCallback($event): void { + console.log($event); + alert('Help Center Clicked'); + } + + productSwitcherCallback(product): void { + alert(product + 'Product Clicked'); + } + + brandingCallback($event): void { + console.log($event); + alert('Branding Clicked'); + } + + onSearchSubmit($event: SearchInput): void { + this.searchTerm = $event.text; + } + + onInputChange($event: SearchInput): void { + this.inputText = $event.text; + } +} diff --git a/libs/docs/core/shellbar/shellbar-docs.component.html b/libs/docs/core/shellbar/shellbar-docs.component.html index 69c431cd0a1..ef7c34f8b85 100644 --- a/libs/docs/core/shellbar/shellbar-docs.component.html +++ b/libs/docs/core/shellbar/shellbar-docs.component.html @@ -91,3 +91,25 @@ + + + + Shellbar with branding and context area + + +

+ This example demonstrates the usage of the Shellbar component with branding and context area. The branding + section includes a logo, title, and subtitle, which can be customized using the + fd-shellbar-branding component. The context area allows for additional elements such as separators, + buttons, and object statuses, which can be managed using the fd-shellbar-context-area component. +

+

+ The fdShellbarHidePriority directive is used to manage the visibility of elements within the + context area based on the available space. Elements with higher priority values will be hidden first when there + is not enough space. +

+
+ + + + diff --git a/libs/docs/core/shellbar/shellbar-docs.component.ts b/libs/docs/core/shellbar/shellbar-docs.component.ts index 98a31297059..f49a27e7b57 100644 --- a/libs/docs/core/shellbar/shellbar-docs.component.ts +++ b/libs/docs/core/shellbar/shellbar-docs.component.ts @@ -14,12 +14,15 @@ import { CustomUserMenuExampleComponent } from './examples/custom-user-menu-exam import { ShellbarBasicExampleComponent } from './examples/shellbar-basic-example.component'; import { ShellbarCollapsibleExampleComponent } from './examples/shellbar-collapsible-example.component'; import { ShellbarGrowingGroupExampleComponent } from './examples/shellbar-growing-group-example/shellbar-growing-group-example.component'; +import { ShellbarOptionsExampleComponent } from './examples/shellbar-options-example/shellbar-options-example.component'; import { ShellbarResponsiveExampleComponent } from './examples/shellbar-responsive-example/shellbar-responsive-example.component'; const shellbarBasicHTMLSrc = 'shellbar-basic-example.component.html'; const shellbarBasicTSSrc = 'shellbar-basic-example.component.ts'; const shellbarCollapsibleHTMLSrc = 'shellbar-collapsible-example.component.html'; const shellbarCollapsibleTSSrc = 'shellbar-collapsible-example.component.ts'; +const shellbarOptionsHTMLSrc = 'shellbar-options-example.component.html'; +const shellbarOptionsTSSrc = 'shellbar-options-example.component.ts'; @Component({ selector: 'app-shellbar', @@ -35,7 +38,8 @@ const shellbarCollapsibleTSSrc = 'shellbar-collapsible-example.component.ts'; ShellbarCollapsibleExampleComponent, ShellbarResponsiveExampleComponent, ShellbarGrowingGroupExampleComponent, - CustomUserMenuExampleComponent + CustomUserMenuExampleComponent, + ShellbarOptionsExampleComponent ] }) export class ShellbarDocsComponent { @@ -98,4 +102,18 @@ export class ShellbarDocsComponent { component: 'CustomUserMenuExampleComponent' }) ]; + + shellbarOptionsExample: ExampleFile[] = [ + { + language: 'html', + code: getAssetFromModuleAssets(shellbarOptionsHTMLSrc), + fileName: 'shellbar-options-example' + }, + { + language: 'typescript', + component: 'ShellbarOptionsExampleComponent', + code: getAssetFromModuleAssets(shellbarOptionsTSSrc), + fileName: 'shellbar-options-example' + } + ]; } diff --git a/package.json b/package.json index 9e0212f3c0a..c0fc6fa7d58 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,7 @@ "@angular/platform-browser": "18.0.3", "@angular/platform-browser-dynamic": "18.0.3", "@angular/router": "18.0.3", - "@fundamental-styles/cx": "0.38.0", + "@fundamental-styles/cx": "0.39.0-rc.13", "@nx/angular": "19.2.3", "@sap-theming/theming-base-content": "11.18.0", "@stackblitz/sdk": "1.9.0", @@ -58,7 +58,7 @@ "fast-deep-equal": "3.1.3", "focus-trap": "7.1.0", "focus-visible": "5.2.1", - "fundamental-styles": "0.38.0", + "fundamental-styles": "0.39.0-rc.13", "fuse.js": "7.0.0", "highlight.js": "11.7.0", "intl": "1.2.5", diff --git a/yarn.lock b/yarn.lock index bb2b112f5f5..ce705fd4c02 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3585,10 +3585,10 @@ __metadata: languageName: node linkType: hard -"@fundamental-styles/cx@npm:0.38.0": - version: 0.38.0 - resolution: "@fundamental-styles/cx@npm:0.38.0" - checksum: 10/f3ad7e8f886849260670a08b1b3a8576bacee6f4eeea1ee8363021f5a554ecd20ddaeebc2fe6e880785acc70ca6b511941bc9fe54e6c6058854317f8d7e53dfe +"@fundamental-styles/cx@npm:0.39.0-rc.13": + version: 0.39.0-rc.13 + resolution: "@fundamental-styles/cx@npm:0.39.0-rc.13" + checksum: 10/4a82c70f9c8690dd5d38f09d2cfab6e64772542003218caa531009c6f8dc715b0c46c2e439043b577ede7c026d3448ac3e65e8cc6371f155248f15a66478a02a languageName: node linkType: hard @@ -13700,7 +13700,7 @@ __metadata: "@angular/router": "npm:18.0.3" "@commitlint/cli": "npm:18.6.1" "@commitlint/config-conventional": "npm:18.6.1" - "@fundamental-styles/cx": "npm:0.38.0" + "@fundamental-styles/cx": "npm:0.39.0-rc.13" "@jsdevtools/npm-publish": "npm:3.0.1" "@nx/angular": "npm:19.2.3" "@nx/devkit": "npm:19.2.3" @@ -13757,7 +13757,7 @@ __metadata: fast-glob: "npm:3.3.1" focus-trap: "npm:7.1.0" focus-visible: "npm:5.2.1" - fundamental-styles: "npm:0.38.0" + fundamental-styles: "npm:0.39.0-rc.13" fuse.js: "npm:7.0.0" highlight.js: "npm:11.7.0" husky: "npm:8.0.2" @@ -13804,13 +13804,13 @@ __metadata: languageName: unknown linkType: soft -"fundamental-styles@npm:0.38.0": - version: 0.38.0 - resolution: "fundamental-styles@npm:0.38.0" +"fundamental-styles@npm:0.39.0-rc.13": + version: 0.39.0-rc.13 + resolution: "fundamental-styles@npm:0.39.0-rc.13" peerDependencies: - "@sap-theming/theming-base-content": ^11.18.0 - "@sap-ui/common-css": 0.38.0 - checksum: 10/5df9e1bc5590ba9af9cdb9c4f6d32507267f4d5f9c985535aac23bddcff32bf23707a64ed367f0b16f80134775afcd432f03fe6d12ed654d64a32d7517f40e7e + "@sap-theming/theming-base-content": ^11.19.0 + "@sap-ui/common-css": 0.39.0-rc.13 + checksum: 10/623129f729dbe7914d3c426c06ce9bc83f853c8c4be014402b96da193d2c80be24be18ff4e12b48267cc05778b8859f68f62bf769528a2cf646faefc1e2559aa languageName: node linkType: hard From fb0aa51a849173d7f070caf3b93a68f184f97c97 Mon Sep 17 00:00:00 2001 From: dpavlenishvili Date: Thu, 7 Nov 2024 18:44:08 +0400 Subject: [PATCH 2/9] feat(core): enhanced context area overflow logic, add second options usage of contex area, add unit tests and examples --- .../shellbar-context-area.component.spec.ts | 40 ++++++++- .../shellbar-context-area.component.ts | 90 +++++++++++++------ .../shellbar-options-example.component.html | 72 +++++++++++++-- .../shellbar/shellbar-docs.component.html | 30 +++++-- 4 files changed, 187 insertions(+), 45 deletions(-) diff --git a/libs/core/shellbar/shellbar-context-area/shellbar-context-area.component.spec.ts b/libs/core/shellbar/shellbar-context-area/shellbar-context-area.component.spec.ts index 133fdaeb2d9..0eeef5ba9d7 100644 --- a/libs/core/shellbar/shellbar-context-area/shellbar-context-area.component.spec.ts +++ b/libs/core/shellbar/shellbar-context-area/shellbar-context-area.component.spec.ts @@ -1,13 +1,39 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ShellbarContextAreaComponent } from './shellbar-context-area.component'; +import { ResizeObserverService } from '@fundamental-ngx/core/utils'; +import { ElementRef } from '@angular/core'; +import { Subject } from 'rxjs'; + +export class ResizeObservableServiceMock { + private readonly observerMap = new Map, Subject>(); + + observe(elementOrRef: Element | ElementRef): Subject { + const subj = new Subject(); + this.observerMap.set(elementOrRef, subj); + return subj; + } + + trigger(elementOrRef: Element | ElementRef, data: ResizeObserverEntry[]): void { + this.observerMap.get(elementOrRef)?.next(data); + } +} describe('ShellbarContextAreaComponent', () => { let component: ShellbarContextAreaComponent; let fixture: ComponentFixture; + let resizeObserverServiceMock: ResizeObservableServiceMock; beforeEach(async () => { + resizeObserverServiceMock = new ResizeObservableServiceMock(); + await TestBed.configureTestingModule({ - imports: [ShellbarContextAreaComponent] + imports: [ShellbarContextAreaComponent], + providers: [ + { + provide: ResizeObserverService, + useValue: resizeObserverServiceMock + } + ] }).compileComponents(); fixture = TestBed.createComponent(ShellbarContextAreaComponent); @@ -18,4 +44,16 @@ describe('ShellbarContextAreaComponent', () => { it('should create', () => { expect(component).toBeTruthy(); }); + + it('should call updateVisibility on resize event', async () => { + const updateVisibilitySpy = jest.spyOn(component, 'updateVisibility'); + + await fixture.whenRenderingDone(); + + resizeObserverServiceMock.trigger(component.el.nativeElement, []); + + fixture.detectChanges(); + + expect(updateVisibilitySpy).toHaveBeenCalled(); + }); }); diff --git a/libs/core/shellbar/shellbar-context-area/shellbar-context-area.component.ts b/libs/core/shellbar/shellbar-context-area/shellbar-context-area.component.ts index ea4703d60fb..7da79fb4e13 100644 --- a/libs/core/shellbar/shellbar-context-area/shellbar-context-area.component.ts +++ b/libs/core/shellbar/shellbar-context-area/shellbar-context-area.component.ts @@ -1,15 +1,6 @@ -import { - AfterViewInit, - ChangeDetectionStrategy, - Component, - ContentChildren, - DestroyRef, - ElementRef, - QueryList -} from '@angular/core'; +import { AfterViewInit, ChangeDetectionStrategy, Component, DestroyRef, ElementRef } from '@angular/core'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { ResizeObserverService } from '@fundamental-ngx/cdk/utils'; -import { ShellbarHidePriorityDirective } from '../shellbar-overflow-priority.directive'; /** * Component representing the context area of the shellbar. @@ -33,13 +24,9 @@ import { ShellbarHidePriorityDirective } from '../shellbar-overflow-priority.dir ] }) export class ShellbarContextAreaComponent implements AfterViewInit { - /** @hidden */ - @ContentChildren(ShellbarHidePriorityDirective, { descendants: true }) - priorityElements: QueryList; - /** @hidden */ constructor( - private el: ElementRef, + public el: ElementRef, private resizeObserverService: ResizeObserverService, private _destroyRef: DestroyRef ) {} @@ -67,30 +54,77 @@ export class ShellbarContextAreaComponent implements AfterViewInit { * 6. Ensuring all elements fit within the available width without recursion. */ updateVisibility(): void { - const elements = this.priorityElements.toArray().sort((a, b) => a.priority - b.priority); + const elements: { el: HTMLElement; priority: number }[] = this.getElementsWithPriority(); const availableWidth = this.getAvailableWidth(); - let allItemsWidth = this.calculateShownElementsWidth(elements); + const allItemsWidth = this.calculateShownElementsWidth(elements); + + this.hideElementsIfNeeded(elements, availableWidth, allItemsWidth); + this.showElementsIfNeeded(elements, availableWidth, allItemsWidth); + } + + /** + * Retrieves the child elements with their respective priority values. + * The elements are sorted based on their priority, with elements having + * higher priority shown first. + */ + private getElementsWithPriority(): { el: HTMLElement; priority: number }[] { + return [...this.el.nativeElement.childNodes] + .map((element: HTMLElement, index) => { + const hasPriorityAttribute = element.hasAttribute && element.hasAttribute('fdShellbarHidePriority'); + const priority = hasPriorityAttribute + ? parseInt(element.getAttribute('fdShellbarHidePriority')!, 10) + : index + 1; - // Hide elements until the total width is within the available width + return { el: element, priority }; + }) + .sort((a, b) => a.priority - b.priority); + } + + /** + * Hides elements if the total width exceeds the available width. + * This method will hide the last shown element iteratively until the total width + * fits within the available width. + */ + private hideElementsIfNeeded( + elements: { + el: HTMLElement; + priority: number; + }[], + availableWidth: number, + allItemsWidth: number + ): void { while (allItemsWidth > availableWidth) { - const shownElements = elements.filter((el) => el.el.nativeElement.style.display !== 'none'); + const shownElements = elements.filter((el) => el.el.style.display !== 'none'); if (shownElements.length === 0) { break; } - shownElements[shownElements.length - 1].el.nativeElement.style.display = 'none'; + shownElements[shownElements.length - 1].el.style.display = 'none'; allItemsWidth = this.calculateShownElementsWidth(elements); } + } - // Show elements if there is enough space - let hiddenElements = elements.filter((el) => el.el.nativeElement.style.display === 'none'); + /** + * Shows elements if there is enough space available. + * This method will show the first hidden element iteratively as long as there + * is sufficient space, and hide the element again if the space is exceeded. + */ + private showElementsIfNeeded( + elements: { + el: HTMLElement; + priority: number; + }[], + availableWidth: number, + allItemsWidth: number + ): void { + let hiddenElements = elements.filter((el) => el.el.style.display === 'none'); while (hiddenElements.length > 0 && allItemsWidth <= availableWidth) { - hiddenElements[0].el.nativeElement.style.display = ''; + hiddenElements[0].el.style.display = ''; allItemsWidth = this.calculateShownElementsWidth(elements); if (allItemsWidth > availableWidth) { - hiddenElements[0].el.nativeElement.style.display = 'none'; + hiddenElements[0].el.style.display = 'none'; break; } - hiddenElements = elements.filter((el) => el.el.nativeElement.style.display === 'none'); + hiddenElements = elements.filter((el) => el.el.style.display === 'none'); } } @@ -106,9 +140,9 @@ export class ShellbarContextAreaComponent implements AfterViewInit { /** * Calculates the total width of the shown elements, including the gaps. */ - private calculateShownElementsWidth(elements: ShellbarHidePriorityDirective[]): number { - const shownElements = elements.filter((el) => el.el.nativeElement.style.display !== 'none'); - const totalWidth = shownElements.reduce((acc, el) => acc + el.el.nativeElement.clientWidth, 0); + private calculateShownElementsWidth(elements: { el: HTMLElement; priority: number }[]): number { + const shownElements = elements.filter((el) => el.el.style.display !== 'none'); + const totalWidth = shownElements.reduce((acc, el) => acc + el.el.clientWidth, 0); return totalWidth + this.calculateTotalGap(shownElements.length); } diff --git a/libs/docs/core/shellbar/examples/shellbar-options-example/shellbar-options-example.component.html b/libs/docs/core/shellbar/examples/shellbar-options-example/shellbar-options-example.component.html index aca2e9d60ea..41cf2d4554f 100644 --- a/libs/docs/core/shellbar/examples/shellbar-options-example/shellbar-options-example.component.html +++ b/libs/docs/core/shellbar/examples/shellbar-options-example/shellbar-options-example.component.html @@ -5,6 +5,7 @@
+

Custom reverse context area hiding ordering

@@ -15,18 +16,78 @@ - + - - + + + + + @if (showSearch) { + + } + + @for (action of actions; track action) { + + } + + + + + + +
+ +
+

Default context area hiding ordering

+ + + + + + {{ productMenuControl }} + Subtitle + + + + + + + + + @@ -65,5 +125,3 @@
-

 

- diff --git a/libs/docs/core/shellbar/shellbar-docs.component.html b/libs/docs/core/shellbar/shellbar-docs.component.html index ef7c34f8b85..d704ce12e18 100644 --- a/libs/docs/core/shellbar/shellbar-docs.component.html +++ b/libs/docs/core/shellbar/shellbar-docs.component.html @@ -98,16 +98,28 @@

- This example demonstrates the usage of the Shellbar component with branding and context area. The branding - section includes a logo, title, and subtitle, which can be customized using the - fd-shellbar-branding component. The context area allows for additional elements such as separators, - buttons, and object statuses, which can be managed using the fd-shellbar-context-area component. -

-

- The fdShellbarHidePriority directive is used to manage the visibility of elements within the - context area based on the available space. Elements with higher priority values will be hidden first when there - is not enough space. + This example demonstrates the usage of the Shellbar component with branding and a context area. The branding + section includes a customizable logo, title, and subtitle through the + fd-shellbar-branding component. The context area can hold various elements, such as separators, + buttons, and object statuses, and is managed by the fd-shellbar-context-area component.

+

To control the visibility of elements in the context area based on available space, there are two options:

+
    +
  • + Use fdShellbarHidePriority Directive: Add the + fdShellbarHidePriority directive to each element for custom overflow management. Assign a + unique priority number to each item; elements with higher numbers will be hidden first when space is + limited. This option provides full control over the hiding order and requires unique values for each element + to establish a clear priority. +
  • +
  • + Automatic Priority Assignment: Alternatively, you can skip adding the + fdShellbarHidePriority + directive, allowing the context area to automatically set priority based on the order of elements. In this + case, elements are prioritized for hiding based on their placement within the + fd-shellbar-context-area, with earlier items hidden last. +
  • +
From efd958d4b9f2b2a0daf4eec933a12b54245e0fc0 Mon Sep 17 00:00:00 2001 From: dpavlenishvili Date: Mon, 11 Nov 2024 19:42:17 +0400 Subject: [PATCH 3/9] feat(core): enhanced context area overflow logic, add second options usage of contex area, add unit tests and examples --- .../shellbar-action-toolbar.component.html | 1 + .../shellbar-action-toolbar.component.scss | 0 .../shellbar-action-toolbar.component.spec.ts | 21 +++++++++++++++++++ .../shellbar-action-toolbar.component.ts | 11 ++++++++++ libs/core/shellbar/shellbar.component.html | 3 +++ 5 files changed, 36 insertions(+) create mode 100644 libs/core/shellbar/shellbar-action-toolbar/shellbar-action-toolbar.component.html create mode 100644 libs/core/shellbar/shellbar-action-toolbar/shellbar-action-toolbar.component.scss create mode 100644 libs/core/shellbar/shellbar-action-toolbar/shellbar-action-toolbar.component.spec.ts create mode 100644 libs/core/shellbar/shellbar-action-toolbar/shellbar-action-toolbar.component.ts diff --git a/libs/core/shellbar/shellbar-action-toolbar/shellbar-action-toolbar.component.html b/libs/core/shellbar/shellbar-action-toolbar/shellbar-action-toolbar.component.html new file mode 100644 index 00000000000..6dbc7430638 --- /dev/null +++ b/libs/core/shellbar/shellbar-action-toolbar/shellbar-action-toolbar.component.html @@ -0,0 +1 @@ + diff --git a/libs/core/shellbar/shellbar-action-toolbar/shellbar-action-toolbar.component.scss b/libs/core/shellbar/shellbar-action-toolbar/shellbar-action-toolbar.component.scss new file mode 100644 index 00000000000..e69de29bb2d diff --git a/libs/core/shellbar/shellbar-action-toolbar/shellbar-action-toolbar.component.spec.ts b/libs/core/shellbar/shellbar-action-toolbar/shellbar-action-toolbar.component.spec.ts new file mode 100644 index 00000000000..ef21ab896fa --- /dev/null +++ b/libs/core/shellbar/shellbar-action-toolbar/shellbar-action-toolbar.component.spec.ts @@ -0,0 +1,21 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ShellbarActionToolbarComponent } from './shellbar-action-toolbar.component'; + +describe('ShellbarToolbarComponent', () => { + let component: ShellbarActionToolbarComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ShellbarActionToolbarComponent] + }).compileComponents(); + + fixture = TestBed.createComponent(ShellbarActionToolbarComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/libs/core/shellbar/shellbar-action-toolbar/shellbar-action-toolbar.component.ts b/libs/core/shellbar/shellbar-action-toolbar/shellbar-action-toolbar.component.ts new file mode 100644 index 00000000000..710ec81d0f5 --- /dev/null +++ b/libs/core/shellbar/shellbar-action-toolbar/shellbar-action-toolbar.component.ts @@ -0,0 +1,11 @@ +import { CommonModule } from '@angular/common'; +import { Component } from '@angular/core'; + +@Component({ + selector: 'fd-shellbar-action-toolbar', + standalone: true, + imports: [CommonModule], + templateUrl: './shellbar-action-toolbar.component.html', + styleUrl: './shellbar-action-toolbar.component.scss' +}) +export class ShellbarActionToolbarComponent {} diff --git a/libs/core/shellbar/shellbar.component.html b/libs/core/shellbar/shellbar.component.html index 1817b695f69..df5108f4406 100644 --- a/libs/core/shellbar/shellbar.component.html +++ b/libs/core/shellbar/shellbar.component.html @@ -55,4 +55,7 @@ @if (!_hideAllComponents) { } + @if (!_hideAllComponents) { + + } From 6221f977778358e52e0f08bc6edb9c7994d58d28 Mon Sep 17 00:00:00 2001 From: dpavlenishvili Date: Mon, 18 Nov 2024 18:06:45 +0400 Subject: [PATCH 4/9] feat(core): update --- libs/core/shellbar/index.ts | 2 +- .../shellbar-action-toolbar.component.html | 1 - .../shellbar-action-toolbar.component.scss | 0 .../shellbar-action-toolbar.component.spec.ts | 21 ------- .../shellbar-action-toolbar.component.ts | 11 ---- .../shellbar-actions-mobile.component.html | 45 -------------- .../shellbar-actions-mobile.component.ts | 59 ------------------ .../shellbar-actions.component.html | 16 ++--- .../shellbar-actions.component.ts | 18 +++--- .../shellbar-toolbar.component.html | 29 +++++++++ .../shellbar-toolbar.component.ts | 61 +++++++++++++++++++ libs/core/shellbar/shellbar.component.scss | 22 +++++++ libs/core/shellbar/shellbar.module.ts | 6 +- libs/core/toolbar/toolbar.component.html | 15 ++--- libs/core/toolbar/toolbar.component.ts | 22 +++++-- .../shellbar-options-example.component.html | 19 ------ .../shellbar-options-example.component.ts | 10 ++- package.json | 4 +- yarn.lock | 24 ++++---- 19 files changed, 181 insertions(+), 204 deletions(-) delete mode 100644 libs/core/shellbar/shellbar-action-toolbar/shellbar-action-toolbar.component.html delete mode 100644 libs/core/shellbar/shellbar-action-toolbar/shellbar-action-toolbar.component.scss delete mode 100644 libs/core/shellbar/shellbar-action-toolbar/shellbar-action-toolbar.component.spec.ts delete mode 100644 libs/core/shellbar/shellbar-action-toolbar/shellbar-action-toolbar.component.ts delete mode 100644 libs/core/shellbar/shellbar-actions-mobile/shellbar-actions-mobile.component.html delete mode 100644 libs/core/shellbar/shellbar-actions-mobile/shellbar-actions-mobile.component.ts create mode 100644 libs/core/shellbar/shellbar-toolbar/shellbar-toolbar.component.html create mode 100644 libs/core/shellbar/shellbar-toolbar/shellbar-toolbar.component.ts diff --git a/libs/core/shellbar/index.ts b/libs/core/shellbar/index.ts index 1e63345ef2c..7cf06cb902e 100644 --- a/libs/core/shellbar/index.ts +++ b/libs/core/shellbar/index.ts @@ -5,7 +5,6 @@ export * from './model/shellbar-user'; export * from './model/shellbar-user-menu'; export * from './product-menu/product-menu.component'; export * from './shellbar-action/shellbar-action.component'; -export * from './shellbar-actions-mobile/shellbar-actions-mobile.component'; export * from './shellbar-actions/shellbar-actions.component'; export * from './shellbar-branding/shellbar-branding.component'; export * from './shellbar-context-area/shellbar-context-area.component'; @@ -16,6 +15,7 @@ export * from './shellbar-sidenav.directive'; export * from './shellbar-spacer/shellbar-spacer.component'; export * from './shellbar-subtitle/shellbar-subtitle.component'; export * from './shellbar-title/shellbar-title.component'; +export * from './shellbar-toolbar/shellbar-toolbar.component'; export * from './shellbar.component'; export * from './shellbar.module'; export * from './tokens'; diff --git a/libs/core/shellbar/shellbar-action-toolbar/shellbar-action-toolbar.component.html b/libs/core/shellbar/shellbar-action-toolbar/shellbar-action-toolbar.component.html deleted file mode 100644 index 6dbc7430638..00000000000 --- a/libs/core/shellbar/shellbar-action-toolbar/shellbar-action-toolbar.component.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/libs/core/shellbar/shellbar-action-toolbar/shellbar-action-toolbar.component.scss b/libs/core/shellbar/shellbar-action-toolbar/shellbar-action-toolbar.component.scss deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/libs/core/shellbar/shellbar-action-toolbar/shellbar-action-toolbar.component.spec.ts b/libs/core/shellbar/shellbar-action-toolbar/shellbar-action-toolbar.component.spec.ts deleted file mode 100644 index ef21ab896fa..00000000000 --- a/libs/core/shellbar/shellbar-action-toolbar/shellbar-action-toolbar.component.spec.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { ShellbarActionToolbarComponent } from './shellbar-action-toolbar.component'; - -describe('ShellbarToolbarComponent', () => { - let component: ShellbarActionToolbarComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - imports: [ShellbarActionToolbarComponent] - }).compileComponents(); - - fixture = TestBed.createComponent(ShellbarActionToolbarComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/libs/core/shellbar/shellbar-action-toolbar/shellbar-action-toolbar.component.ts b/libs/core/shellbar/shellbar-action-toolbar/shellbar-action-toolbar.component.ts deleted file mode 100644 index 710ec81d0f5..00000000000 --- a/libs/core/shellbar/shellbar-action-toolbar/shellbar-action-toolbar.component.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { CommonModule } from '@angular/common'; -import { Component } from '@angular/core'; - -@Component({ - selector: 'fd-shellbar-action-toolbar', - standalone: true, - imports: [CommonModule], - templateUrl: './shellbar-action-toolbar.component.html', - styleUrl: './shellbar-action-toolbar.component.scss' -}) -export class ShellbarActionToolbarComponent {} diff --git a/libs/core/shellbar/shellbar-actions-mobile/shellbar-actions-mobile.component.html b/libs/core/shellbar/shellbar-actions-mobile/shellbar-actions-mobile.component.html deleted file mode 100644 index 93f8201edff..00000000000 --- a/libs/core/shellbar/shellbar-actions-mobile/shellbar-actions-mobile.component.html +++ /dev/null @@ -1,45 +0,0 @@ -@if (shellbarActions.length > 0 || searchExists) { -
- - - - - - @if (searchExists) { -
  • - } - @for (action of shellbarActions; track action) { -
  • - @if (action.notificationCount) { - {{ action.notificationCount }} - } -
  • - } -
    -
    -
    -} diff --git a/libs/core/shellbar/shellbar-actions-mobile/shellbar-actions-mobile.component.ts b/libs/core/shellbar/shellbar-actions-mobile/shellbar-actions-mobile.component.ts deleted file mode 100644 index bff17764128..00000000000 --- a/libs/core/shellbar/shellbar-actions-mobile/shellbar-actions-mobile.component.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { - AfterContentChecked, - ChangeDetectionStrategy, - Component, - EventEmitter, - Input, - Output, - QueryList, - ViewEncapsulation -} from '@angular/core'; -import { ActionSheetModule } from '@fundamental-ngx/core/action-sheet'; -import { ButtonComponent } from '@fundamental-ngx/core/button'; -import { FdTranslatePipe } from '@fundamental-ngx/i18n'; -import { ShellbarActionComponent } from '../shellbar-action/shellbar-action.component'; - -@Component({ - selector: 'fd-shellbar-actions-mobile', - templateUrl: './shellbar-actions-mobile.component.html', - encapsulation: ViewEncapsulation.None, - changeDetection: ChangeDetectionStrategy.OnPush, - standalone: true, - imports: [ActionSheetModule, ButtonComponent, FdTranslatePipe] -}) -export class ShellbarActionsMobileComponent implements AfterContentChecked { - /** @hidden */ - @Input() - shellbarActions: QueryList; - - /** - * Whether the search is present in the shellbar. - */ - @Input() - searchExists = false; - - /** @hidden */ - @Output() - showSearch = new EventEmitter(); - - /** @hidden */ - totalNotifications: number; - - /** @hidden */ - actionClicked(item: ShellbarActionComponent, event: MouseEvent): void { - if (item.callback) { - item.callback(event); - } - } - - /** @hidden */ - ngAfterContentChecked(): void { - this.totalNotifications = 0; - - this.shellbarActions?.forEach((action) => { - if (action.notificationCount && typeof action.notificationCount === 'number') { - this.totalNotifications = this.totalNotifications + action.notificationCount; - } - }); - } -} diff --git a/libs/core/shellbar/shellbar-actions/shellbar-actions.component.html b/libs/core/shellbar/shellbar-actions/shellbar-actions.component.html index 951d2ff4e4c..fd3717c0a96 100644 --- a/libs/core/shellbar/shellbar-actions/shellbar-actions.component.html +++ b/libs/core/shellbar/shellbar-actions/shellbar-actions.component.html @@ -5,20 +5,20 @@ }
    -
    - -
    +
    @if (_addSearchIcon && !showSearch) { } - + @if (userComponent || userItem) { @if (!userComponent) { * ``` */ - @Component({ selector: 'fd-shellbar-actions', templateUrl: './shellbar-actions.component.html', - encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, host: { '[class.fd-shellbar__group]': 'true', '[class.fd-shellbar__group--actions]': 'true' }, + styles: [ + ` + :host { + flex: 1; + } + ` + ], standalone: true, - imports: [PortalModule, ShellbarActionsMobileComponent, ShellbarActionComponent, ShellbarUserMenuComponent] + imports: [PortalModule, ShellbarToolbarComponent, ShellbarActionComponent, ShellbarUserMenuComponent] }) export class ShellbarActionsComponent implements OnDestroy { /** The user data. */ diff --git a/libs/core/shellbar/shellbar-toolbar/shellbar-toolbar.component.html b/libs/core/shellbar/shellbar-toolbar/shellbar-toolbar.component.html new file mode 100644 index 00000000000..d73f06ea9f6 --- /dev/null +++ b/libs/core/shellbar/shellbar-toolbar/shellbar-toolbar.component.html @@ -0,0 +1,29 @@ +@if (shellbarActions.length > 0 || searchExists) { + + @if (searchExists) { + + } + + @for (action of shellbarActions; track action) { + + } + +} diff --git a/libs/core/shellbar/shellbar-toolbar/shellbar-toolbar.component.ts b/libs/core/shellbar/shellbar-toolbar/shellbar-toolbar.component.ts new file mode 100644 index 00000000000..6eccf33df16 --- /dev/null +++ b/libs/core/shellbar/shellbar-toolbar/shellbar-toolbar.component.ts @@ -0,0 +1,61 @@ +import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output, QueryList } from '@angular/core'; +import { ButtonBadgeDirective, ButtonComponent } from '@fundamental-ngx/core/button'; +import { ToolbarComponent, ToolbarItemDirective, ToolbarSpacerDirective } from '@fundamental-ngx/core/toolbar'; +import { FdTranslatePipe } from '@fundamental-ngx/i18n'; +import { ShellbarActionComponent } from '../shellbar-action/shellbar-action.component'; + +@Component({ + selector: 'fd-shellbar-toolbar', + templateUrl: './shellbar-toolbar.component.html', + changeDetection: ChangeDetectionStrategy.OnPush, + standalone: true, + imports: [ + ButtonComponent, + FdTranslatePipe, + ToolbarComponent, + ButtonComponent, + ToolbarItemDirective, + ButtonBadgeDirective, + ToolbarSpacerDirective + ], + styles: [ + ` + :host { + flex: 1; + } + ` + ] +}) +export class ShellbarToolbarComponent { + /** @hidden */ + @Input() + shellbarActions: QueryList; + + /** + * Whether the search is present in the shellbar. + */ + @Input() + searchExists = false; + + /** @hidden */ + @Output() + showSearch = new EventEmitter(); + + /** @hidden */ + totalNotifications; + + /** @hidden */ + actionClicked(item: ShellbarActionComponent, event: MouseEvent): void { + if (item.callback) { + item.callback(event); + } + } + + /** Handles overflow changes */ + onOverflowChanged(overflowItems: any[]): void { + // Reset totalNotifications + // this.totalNotifications = 0; + + overflowItems.forEach((item) => {}); + } +} diff --git a/libs/core/shellbar/shellbar.component.scss b/libs/core/shellbar/shellbar.component.scss index e054f951096..b70bd4ea304 100644 --- a/libs/core/shellbar/shellbar.component.scss +++ b/libs/core/shellbar/shellbar.component.scss @@ -33,3 +33,25 @@ fd-shellbar-actions { .fd-shellbar .fd-shellbar__group .fd-shellbar__button.fd-shellbar__button--menu { --fdButtonColor: var(--sapShell_TextColor); } + +.fd-shellbar__group--context-area > * { + flex-shrink: 0; +} + +.fd-shellbar.fd-shellbar--s { + gap: 0; + + .fd-shellbar__group--actions { + gap: 0; + } + + .fd-shellbar__action.fd-shellbar__action--mobile { + margin-inline: 0.25rem; + } + + .fd-object-status { + flex-shrink: 0; + white-space: nowrap; + min-width: fit-content; + } +} diff --git a/libs/core/shellbar/shellbar.module.ts b/libs/core/shellbar/shellbar.module.ts index b4ff06b06ff..46d923febd0 100644 --- a/libs/core/shellbar/shellbar.module.ts +++ b/libs/core/shellbar/shellbar.module.ts @@ -9,8 +9,8 @@ import { ShellbarSubtitleComponent } from './shellbar-subtitle/shellbar-subtitle import { ShellbarTitleComponent } from './shellbar-title/shellbar-title.component'; import { ContentDensityModule } from '@fundamental-ngx/core/content-density'; -import { ShellbarActionsMobileComponent } from './shellbar-actions-mobile/shellbar-actions-mobile.component'; import { ShellbarSidenavDirective } from './shellbar-sidenav.directive'; +import { ShellbarToolbarComponent } from './shellbar-toolbar/shellbar-toolbar.component'; import { ShellbarUserMenuComponent } from './user-menu/shellbar-user-menu.component'; @NgModule({ @@ -19,7 +19,7 @@ import { ShellbarUserMenuComponent } from './user-menu/shellbar-user-menu.compon ProductMenuComponent, ShellbarSubtitleComponent, ShellbarActionsComponent, - ShellbarActionsMobileComponent, + ShellbarToolbarComponent, ShellbarActionComponent, ShellbarLogoComponent, ShellbarTitleComponent, @@ -31,7 +31,7 @@ import { ShellbarUserMenuComponent } from './user-menu/shellbar-user-menu.compon ProductMenuComponent, ShellbarSubtitleComponent, ShellbarActionsComponent, - ShellbarActionsMobileComponent, + ShellbarToolbarComponent, ShellbarActionComponent, ShellbarLogoComponent, ShellbarTitleComponent, diff --git a/libs/core/toolbar/toolbar.component.html b/libs/core/toolbar/toolbar.component.html index 6fec2ef2efd..0f61304cd95 100644 --- a/libs/core/toolbar/toolbar.component.html +++ b/libs/core/toolbar/toolbar.component.html @@ -8,17 +8,14 @@ @if (!spacerUsed()) { } - + - +
    diff --git a/libs/core/toolbar/toolbar.component.ts b/libs/core/toolbar/toolbar.component.ts index 844e6b24a5c..bb68708ef85 100644 --- a/libs/core/toolbar/toolbar.component.ts +++ b/libs/core/toolbar/toolbar.component.ts @@ -10,19 +10,22 @@ import { contentChildren, DestroyRef, ElementRef, + EventEmitter, forwardRef, HostBinding, inject, Inject, + input, Input, Optional, + Output, QueryList, signal, SkipSelf, ViewChild, ViewEncapsulation } from '@angular/core'; -import { DYNAMIC_PAGE_HEADER_TOKEN, DynamicPageHeader } from '@fundamental-ngx/core/shared'; +import { DYNAMIC_PAGE_HEADER_TOKEN, DynamicPageHeader, HeadingLevel } from '@fundamental-ngx/core/shared'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { @@ -34,14 +37,13 @@ import { OverflowPriority, ResizeObserverService } from '@fundamental-ngx/cdk/utils'; -import { ButtonComponent } from '@fundamental-ngx/core/button'; +import { ButtonBadgeDirective, ButtonComponent } from '@fundamental-ngx/core/button'; import { ContentDensityMode, ContentDensityObserver, contentDensityObserverProviders } from '@fundamental-ngx/core/content-density'; import { PopoverModule } from '@fundamental-ngx/core/popover'; -import { HeadingLevel } from '@fundamental-ngx/core/shared'; import { TitleComponent, TitleToken } from '@fundamental-ngx/core/title'; import { BehaviorSubject, combineLatest, map, Observable, startWith } from 'rxjs'; import { ToolbarItem } from './abstract-toolbar-item.class'; @@ -86,7 +88,8 @@ export const enum OverflowPriorityEnum { PopoverModule, ButtonComponent, DynamicPortalComponent, - TitleComponent + TitleComponent, + ButtonBadgeDirective ] }) export class ToolbarComponent implements AfterViewInit, AfterViewChecked, CssClassBuilder, AfterContentInit { @@ -167,6 +170,13 @@ export class ToolbarComponent implements AfterViewInit, AfterViewChecked, CssCla @HostBinding('attr.aria-labelledby') ariaLabelledBy: string; + /** + * Event emitted whenever the overflow state changes. + * Emits an array of items currently in the overflow. + */ + @Output() + overflowChanged = new EventEmitter(); + /** @hidden */ @ViewChild('titleElement', { read: ElementRef }) titleElement: ElementRef; @@ -195,6 +205,9 @@ export class ToolbarComponent implements AfterViewInit, AfterViewChecked, CssCla /** @hidden */ overflownItems: ToolbarItem[] = []; + /** @hidden */ + badgeCount = input(); + /** @hidden */ spacerUsed = signal(false); @@ -325,6 +338,7 @@ export class ToolbarComponent implements AfterViewInit, AfterViewChecked, CssCla ); this.overflowItems$.subscribe((items) => { this.overflownItems = items; + this.overflowChanged.emit(items); this._cd.detectChanges(); }); this.buildComponentCssClass(); diff --git a/libs/docs/core/shellbar/examples/shellbar-options-example/shellbar-options-example.component.html b/libs/docs/core/shellbar/examples/shellbar-options-example/shellbar-options-example.component.html index 41cf2d4554f..891ec86ad5f 100644 --- a/libs/docs/core/shellbar/examples/shellbar-options-example/shellbar-options-example.component.html +++ b/libs/docs/core/shellbar/examples/shellbar-options-example/shellbar-options-example.component.html @@ -79,25 +79,6 @@

    Default context area hiding ordering

    Subtitle - - - - - - - - - - @if (showSearch) { Date: Tue, 19 Nov 2024 13:35:31 +0400 Subject: [PATCH 5/9] fix(core): refactored shelbar-actions flow accroding actions-toolbar. --- libs/core/shellbar/index.ts | 2 +- .../shellbar-actions-toolbar.component.html} | 6 +- .../shellbar-actions-toolbar.component.ts | 61 ++++++++++ .../shellbar-actions.component.html | 4 +- .../shellbar-actions.component.ts | 111 +++++++----------- .../shellbar-toolbar.component.ts | 61 ---------- libs/core/shellbar/shellbar.module.ts | 6 +- .../shellbar-options-example.component.ts | 2 +- 8 files changed, 115 insertions(+), 138 deletions(-) rename libs/core/shellbar/{shellbar-toolbar/shellbar-toolbar.component.html => shellbar-actions-toolbar/shellbar-actions-toolbar.component.html} (89%) create mode 100644 libs/core/shellbar/shellbar-actions-toolbar/shellbar-actions-toolbar.component.ts delete mode 100644 libs/core/shellbar/shellbar-toolbar/shellbar-toolbar.component.ts diff --git a/libs/core/shellbar/index.ts b/libs/core/shellbar/index.ts index 7cf06cb902e..fa371be516b 100644 --- a/libs/core/shellbar/index.ts +++ b/libs/core/shellbar/index.ts @@ -5,6 +5,7 @@ export * from './model/shellbar-user'; export * from './model/shellbar-user-menu'; export * from './product-menu/product-menu.component'; export * from './shellbar-action/shellbar-action.component'; +export * from './shellbar-actions-toolbar/shellbar-actions-toolbar.component'; export * from './shellbar-actions/shellbar-actions.component'; export * from './shellbar-branding/shellbar-branding.component'; export * from './shellbar-context-area/shellbar-context-area.component'; @@ -15,7 +16,6 @@ export * from './shellbar-sidenav.directive'; export * from './shellbar-spacer/shellbar-spacer.component'; export * from './shellbar-subtitle/shellbar-subtitle.component'; export * from './shellbar-title/shellbar-title.component'; -export * from './shellbar-toolbar/shellbar-toolbar.component'; export * from './shellbar.component'; export * from './shellbar.module'; export * from './tokens'; diff --git a/libs/core/shellbar/shellbar-toolbar/shellbar-toolbar.component.html b/libs/core/shellbar/shellbar-actions-toolbar/shellbar-actions-toolbar.component.html similarity index 89% rename from libs/core/shellbar/shellbar-toolbar/shellbar-toolbar.component.html rename to libs/core/shellbar/shellbar-actions-toolbar/shellbar-actions-toolbar.component.html index d73f06ea9f6..a922dd7e90c 100644 --- a/libs/core/shellbar/shellbar-toolbar/shellbar-toolbar.component.html +++ b/libs/core/shellbar/shellbar-actions-toolbar/shellbar-actions-toolbar.component.html @@ -6,19 +6,21 @@ [clearBorder]="true" [shouldOverflow]="true" [badgeCount]="totalNotifications" - (overflowChanged)="onOverflowChanged($event)" + (overflowChanged)="handleOverflow($event)" > @if (searchExists) { } + + @for (action of shellbarActions; track action) { } - - @for (action of shellbarActions; track action) {
    -@if (_addSearchIcon && !showSearch) { - -} From 2407be3e14f5997ce183b8201b8a00f666f19734 Mon Sep 17 00:00:00 2001 From: dpavlenishvili Date: Thu, 5 Dec 2024 14:16:21 +0400 Subject: [PATCH 7/9] fix(core, docs): address branding updates, improvements --- libs/core/shellbar/model/shellbar-sizes.ts | 7 + .../product-menu/product-menu.component.html | 86 ++++++------ .../shellbar-action.component.html | 2 +- .../shellbar-actions-toolbar.component.html | 30 ----- .../shellbar-actions-toolbar.component.ts | 61 --------- .../shellbar-actions.component.html | 19 +-- .../shellbar-actions.component.ts | 125 ++++++++++-------- .../shellbar-branding.component.html | 22 +-- .../shellbar-branding.component.ts | 10 +- .../shellbar-context-area.component.spec.ts | 6 +- .../shellbar-context-area.component.ts | 32 ++--- .../shellbar-logo/shellbar-logo.component.ts | 33 ++++- .../shellbar-overflow-priority.directive.ts | 4 +- .../shellbar-subtitle.component.html | 3 - .../shellbar-subtitle.component.ts | 15 ++- .../shellbar-title.component.html | 3 - .../shellbar-title.component.ts | 22 ++- libs/core/shellbar/shellbar.component.html | 2 +- libs/core/shellbar/shellbar.component.scss | 1 + libs/core/shellbar/shellbar.component.ts | 43 ++++-- libs/core/shellbar/tokens.ts | 8 ++ .../user-menu/shellbar-user-menu.component.ts | 9 +- .../shellbar-options-example.component.html | 12 +- .../shellbar/shellbar-docs.component.html | 120 ----------------- 24 files changed, 291 insertions(+), 384 deletions(-) delete mode 100644 libs/core/shellbar/shellbar-actions-toolbar/shellbar-actions-toolbar.component.html delete mode 100644 libs/core/shellbar/shellbar-actions-toolbar/shellbar-actions-toolbar.component.ts delete mode 100644 libs/core/shellbar/shellbar-subtitle/shellbar-subtitle.component.html delete mode 100644 libs/core/shellbar/shellbar-title/shellbar-title.component.html diff --git a/libs/core/shellbar/model/shellbar-sizes.ts b/libs/core/shellbar/model/shellbar-sizes.ts index 550e64bc321..0b94f89c7c1 100644 --- a/libs/core/shellbar/model/shellbar-sizes.ts +++ b/libs/core/shellbar/model/shellbar-sizes.ts @@ -1,3 +1,10 @@ +export enum ShellbarSize { + SMALL = 's', + MEDIUM = 'm', + LARGE = 'l', + EXTRA_LARGE = 'xl' +} + export type ShellbarSizes = 's' | 'm' | 'l' | 'xl'; export type Breakpoints = Record; diff --git a/libs/core/shellbar/product-menu/product-menu.component.html b/libs/core/shellbar/product-menu/product-menu.component.html index f927037213a..e9086c400c0 100644 --- a/libs/core/shellbar/product-menu/product-menu.component.html +++ b/libs/core/shellbar/product-menu/product-menu.component.html @@ -1,42 +1,44 @@ -@if (items && items.length > 0) { -

    {{ control }}

    - - - @for (item of items; track item) { -
  • - - {{ item.name }} - @if (item.glyph) { - - } - -
  • - } -
    -} @else { -

    - {{ control }} -

    -} +
    + @if (items && items.length > 0) { +

    {{ control }}

    + + + @for (item of items; track item) { +
  • + + {{ item.name }} + @if (item.glyph) { + + } + +
  • + } +
    + } @else { +

    + {{ control }} +

    + } +
    diff --git a/libs/core/shellbar/shellbar-action/shellbar-action.component.html b/libs/core/shellbar/shellbar-action/shellbar-action.component.html index a19f93dfbb4..c568eab1ebc 100644 --- a/libs/core/shellbar/shellbar-action/shellbar-action.component.html +++ b/libs/core/shellbar/shellbar-action/shellbar-action.component.html @@ -6,7 +6,7 @@ fdCozy [glyph]="glyph" [glyphFont]="glyphFont" - (click)="callback ? callback($event) : ''" + (click)="callback?.($event)" > @if (notificationCount) { diff --git a/libs/core/shellbar/shellbar-actions-toolbar/shellbar-actions-toolbar.component.html b/libs/core/shellbar/shellbar-actions-toolbar/shellbar-actions-toolbar.component.html deleted file mode 100644 index bdd07b98217..00000000000 --- a/libs/core/shellbar/shellbar-actions-toolbar/shellbar-actions-toolbar.component.html +++ /dev/null @@ -1,30 +0,0 @@ -@if (shellbarActions.length > 0 || searchExists) { - - - @if (searchExists) { - - } - - @for (action of shellbarActions; track action) { - - } - -} diff --git a/libs/core/shellbar/shellbar-actions-toolbar/shellbar-actions-toolbar.component.ts b/libs/core/shellbar/shellbar-actions-toolbar/shellbar-actions-toolbar.component.ts deleted file mode 100644 index 363322597c1..00000000000 --- a/libs/core/shellbar/shellbar-actions-toolbar/shellbar-actions-toolbar.component.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output, QueryList } from '@angular/core'; -import { ButtonBadgeDirective, ButtonComponent } from '@fundamental-ngx/core/button'; -import { ToolbarComponent, ToolbarItemDirective, ToolbarSpacerDirective } from '@fundamental-ngx/core/toolbar'; -import { FdTranslatePipe } from '@fundamental-ngx/i18n'; -import { ShellbarActionComponent } from '../shellbar-action/shellbar-action.component'; - -@Component({ - selector: 'fd-shellbar-actions-toolbar', - templateUrl: './shellbar-actions-toolbar.component.html', - changeDetection: ChangeDetectionStrategy.OnPush, - standalone: true, - imports: [ - ButtonComponent, - FdTranslatePipe, - ToolbarComponent, - ButtonComponent, - ToolbarItemDirective, - ButtonBadgeDirective, - ToolbarSpacerDirective - ], - styles: [ - ` - :host { - flex: 1; - } - ` - ] -}) -export class ShellbarActionsToolbarComponent { - /** Actions displayed in the toolbar. */ - @Input() shellbarActions: QueryList; - - /** Whether a search button exists. */ - @Input() searchExists = false; - - /** Total notification count from overflowed items. */ - @Input() totalNotifications = 0; - - /** Event emitted when the search button is clicked. */ - @Output() showSearch = new EventEmitter(); - - /** Handles action button clicks. */ - handleActionClick(action: ShellbarActionComponent, event: MouseEvent): void { - action.callback?.(event); - } - - /** Handles overflow change and recalculates notification count. */ - handleOverflow(overflowItems: any[]): void { - this.totalNotifications = overflowItems.reduce((total, item) => { - const badgeValue = this.extractBadgeValue(item._elementRef.nativeElement); - return total + (parseInt(badgeValue ?? '0', 10) || 0); - }, 0); - } - - /** Extracts the badge value from a toolbar item's nativeElement */ - private extractBadgeValue(nativeElement: HTMLElement): string | null { - const children = Array.from(nativeElement.children); - const badgeElement = children.find((child) => child.classList.contains('fd-button__badge')); - return badgeElement?.textContent?.trim() || null; - } -} diff --git a/libs/core/shellbar/shellbar-actions/shellbar-actions.component.html b/libs/core/shellbar/shellbar-actions/shellbar-actions.component.html index 39010c11384..951d2ff4e4c 100644 --- a/libs/core/shellbar/shellbar-actions/shellbar-actions.component.html +++ b/libs/core/shellbar/shellbar-actions/shellbar-actions.component.html @@ -5,17 +5,20 @@ }
    - +
    + +
    - +@if (_addSearchIcon && !showSearch) { + +} + @if (userComponent || userItem) { @if (!userComponent) { * ``` */ + @Component({ selector: 'fd-shellbar-actions', templateUrl: './shellbar-actions.component.html', + encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, host: { '[class.fd-shellbar__group]': 'true', '[class.fd-shellbar__group--actions]': 'true' }, - styles: [ - ` - :host { - flex: 1; - } - ` - ], standalone: true, - imports: [PortalModule, ShellbarActionsToolbarComponent, ShellbarActionComponent, ShellbarUserMenuComponent] + imports: [PortalModule, ShellbarActionsMobileComponent, ShellbarActionComponent, ShellbarUserMenuComponent] }) export class ShellbarActionsComponent implements OnDestroy { /** The user data. */ - @Input() user: ShellbarUser; + @Input() + user: ShellbarUser; /** The user menu data. */ - @Input() userMenu: ShellbarUserMenu[]; + @Input() + userMenu: ShellbarUserMenu[]; - /** Whether to close the popover after selecting an option. */ - @Input() closePopoverOnSelect = false; + /** When set to true, popover list will be closed after selecting the option */ + @Input() + closePopoverOnSelect = false; - /** Event emitted when the search is toggled. */ - @Output() searchOpen = new EventEmitter(); + /** + * Event emitted when search opened. + */ + @Output() + searchOpen = new EventEmitter(); - /** Shellbar action components projected into the content. */ - @ContentChildren(FD_SHELLBAR_ACTION_COMPONENT) shellbarActions: QueryList; + /** @hidden */ + @ContentChildren(FD_SHELLBAR_ACTION_COMPONENT) + shellbarActions: QueryList; - /** Shellbar user menu component projected into the content. */ - @ContentChild(ShellbarUserMenuComponent) userComponent: ShellbarUserMenuComponent; + /** @hidden */ + @ContentChild(ShellbarUserMenuComponent) + userComponent: ShellbarUserMenuComponent; - /** Shellbar user menu component view child. */ - @ViewChild(ShellbarUserMenuComponent) userComponentView: ShellbarUserMenuComponent; + /** @hidden */ + @ViewChild(ShellbarUserMenuComponent) + userComponentView: ShellbarUserMenuComponent; - /** Combobox component projected into the content. */ - @ContentChild(FD_COMBOBOX_COMPONENT) comboboxComponent: ComboboxInterface; + /** @hidden */ + @ContentChild(FD_COMBOBOX_COMPONENT) + comboboxComponent: ComboboxInterface; - /** Product switch component projected into the content. */ - @ContentChild(FD_PRODUCT_SWITCH_COMPONENT, { static: false }) productSwitchComponent: ProductSwitchComponent; + /** @hidden */ + @ContentChild(FD_PRODUCT_SWITCH_COMPONENT, { static: false }) + productSwitchComponent: ProductSwitchComponent; - /** Portal outlet for search. */ - @ViewChild(CdkPortalOutlet) _portalOutlet: Nullable; + /** @hidden */ + @ViewChild(CdkPortalOutlet) + _portalOutlet: Nullable; - /** Whether to add the search icon. */ + /** @hidden */ _addSearchIcon = false; - /** Portal for search component. */ + /** @hidden */ _searchPortal: DomPortal; - /** Whether to show the search field. */ + /** + * Whether to show the search field. + */ showSearch = false; - /** Current size of the shellbar. */ + /** @hidden */ currentSize: ShellbarSizes; /** @hidden */ private readonly _cd = inject(ChangeDetectorRef); /** @hidden */ - private readonly _shellbar = inject(FD_SHELLBAR_COMPONENT, { optional: true }); - - /** @hidden */ - private _searchComponent: Nullable; + private readonly _shellbar = inject(FD_SHELLBAR_COMPONENT, { + optional: true + }); /** @hidden */ @HostBinding('class.fd-shellbar__group--shrink') @@ -130,21 +139,28 @@ export class ShellbarActionsComponent implements OnDestroy { } /** @hidden */ - public get userItem(): ShellbarUser { - return this.userComponent ? this.userComponent.user : this.user; - } + private _searchComponent: Nullable; /** @hidden */ _toggleSearch: () => void = () => { this._setSearchVisibility(!this.showSearch); }; + /** @hidden */ + public get userItem(): ShellbarUser { + if (this.userComponent) { + return this.userComponent.user; + } else { + return this.user; + } + } + /** @hidden */ ngOnDestroy(): void { this._portalOutlet?.dispose(); } - /** Attach the search portal. */ + /** @hidden */ _attachSearch(portal: DomPortal, searchComponent: Nullable, size: ShellbarSizes): void { this._searchPortal = portal; this._addSearchIcon = true; @@ -154,32 +170,39 @@ export class ShellbarActionsComponent implements OnDestroy { this._cd.detectChanges(); } - /** Detach the search portal. */ + /** @hidden */ _detachSearch(): void { - this._portalOutlet?.detach(); + if (this._portalOutlet?.hasAttached()) { + this._portalOutlet.detach(); + } + this._addSearchIcon = false; + this._cd.detectChanges(); } /** @hidden */ _triggerItems(): void { - if (this.closePopoverOnSelect) { - this.userComponentView?.menu.close(); - this.userComponent?.menu.close(); + if (!this.closePopoverOnSelect) { + return; } + this.userComponentView?.menu.close(); + this.userComponent?.menu.close(); } - /** Set the visibility of the search field. */ + /** @hidden */ _setSearchVisibility(visible: boolean): void { this.showSearch = visible; this.searchOpen.emit(this.showSearch); - if (this.currentSize !== 's') { - this._toggleSearchPortal(visible, visible); + if (this.currentSize === 's') { + return; } + + this._toggleSearchPortal(visible, visible); } - /** Toggle the search portal. */ + /** @hidden */ private _toggleSearchPortal(visible: boolean, focusSearch = false): void { if (visible) { this._portalOutlet?.detach(); @@ -187,9 +210,7 @@ export class ShellbarActionsComponent implements OnDestroy { } else { this._portalOutlet?.detach(); } - this._cd.detectChanges(); - if (focusSearch) { this._searchComponent?.focus(); } diff --git a/libs/core/shellbar/shellbar-branding/shellbar-branding.component.html b/libs/core/shellbar/shellbar-branding/shellbar-branding.component.html index f3f74bd39b6..96394214d3d 100644 --- a/libs/core/shellbar/shellbar-branding/shellbar-branding.component.html +++ b/libs/core/shellbar/shellbar-branding/shellbar-branding.component.html @@ -1,20 +1,10 @@ -
    - +
    + -
    - + @if (titleContent || subtitleContent) { +
    - - - -
    +
    + }
    diff --git a/libs/core/shellbar/shellbar-branding/shellbar-branding.component.ts b/libs/core/shellbar/shellbar-branding/shellbar-branding.component.ts index 853aec1de03..edbaff45c0f 100644 --- a/libs/core/shellbar/shellbar-branding/shellbar-branding.component.ts +++ b/libs/core/shellbar/shellbar-branding/shellbar-branding.component.ts @@ -1,6 +1,6 @@ -import { ChangeDetectionStrategy, Component, Input, ViewEncapsulation } from '@angular/core'; +import { ChangeDetectionStrategy, Component, ContentChild, Input, ViewEncapsulation } from '@angular/core'; import { Nullable } from '@fundamental-ngx/cdk/utils'; -import { FD_SHELLBAR_BRANDING_COMPONENT } from '../tokens'; +import { FD_SHELLBAR_BRANDING_COMPONENT, FD_SHELLBAR_SUBTITLE_COMPONENT, FD_SHELLBAR_TITLE_COMPONENT } from '../tokens'; @Component({ selector: 'fd-shellbar-branding', @@ -23,4 +23,10 @@ export class ShellbarBrandingComponent { /** add aria label dynamically to add to the button */ @Input() ariaLabel: Nullable; + + /** hidden */ + @ContentChild(FD_SHELLBAR_TITLE_COMPONENT) titleContent?: HTMLElement; + + /** hidden */ + @ContentChild(FD_SHELLBAR_SUBTITLE_COMPONENT) subtitleContent?: HTMLElement; } diff --git a/libs/core/shellbar/shellbar-context-area/shellbar-context-area.component.spec.ts b/libs/core/shellbar/shellbar-context-area/shellbar-context-area.component.spec.ts index 0eeef5ba9d7..12f1493f308 100644 --- a/libs/core/shellbar/shellbar-context-area/shellbar-context-area.component.spec.ts +++ b/libs/core/shellbar/shellbar-context-area/shellbar-context-area.component.spec.ts @@ -5,16 +5,16 @@ import { ElementRef } from '@angular/core'; import { Subject } from 'rxjs'; export class ResizeObservableServiceMock { - private readonly observerMap = new Map, Subject>(); + private readonly _observerMap = new Map, Subject>(); observe(elementOrRef: Element | ElementRef): Subject { const subj = new Subject(); - this.observerMap.set(elementOrRef, subj); + this._observerMap.set(elementOrRef, subj); return subj; } trigger(elementOrRef: Element | ElementRef, data: ResizeObserverEntry[]): void { - this.observerMap.get(elementOrRef)?.next(data); + this._observerMap.get(elementOrRef)?.next(data); } } diff --git a/libs/core/shellbar/shellbar-context-area/shellbar-context-area.component.ts b/libs/core/shellbar/shellbar-context-area/shellbar-context-area.component.ts index 7da79fb4e13..3ff65057e2b 100644 --- a/libs/core/shellbar/shellbar-context-area/shellbar-context-area.component.ts +++ b/libs/core/shellbar/shellbar-context-area/shellbar-context-area.component.ts @@ -27,13 +27,13 @@ export class ShellbarContextAreaComponent implements AfterViewInit { /** @hidden */ constructor( public el: ElementRef, - private resizeObserverService: ResizeObserverService, + private _resizeObserverService: ResizeObserverService, private _destroyRef: DestroyRef ) {} /** @hidden */ ngAfterViewInit(): void { - this.resizeObserverService + this._resizeObserverService .observe(this.el) .pipe(takeUntilDestroyed(this._destroyRef)) .subscribe(() => this.updateVisibility()); @@ -54,12 +54,12 @@ export class ShellbarContextAreaComponent implements AfterViewInit { * 6. Ensuring all elements fit within the available width without recursion. */ updateVisibility(): void { - const elements: { el: HTMLElement; priority: number }[] = this.getElementsWithPriority(); - const availableWidth = this.getAvailableWidth(); - const allItemsWidth = this.calculateShownElementsWidth(elements); + const elements: { el: HTMLElement; priority: number }[] = this._getElementsWithPriority(); + const availableWidth = this._getAvailableWidth(); + const allItemsWidth = this._calculateShownElementsWidth(elements); - this.hideElementsIfNeeded(elements, availableWidth, allItemsWidth); - this.showElementsIfNeeded(elements, availableWidth, allItemsWidth); + this._hideElementsIfNeeded(elements, availableWidth, allItemsWidth); + this._showElementsIfNeeded(elements, availableWidth, allItemsWidth); } /** @@ -67,7 +67,7 @@ export class ShellbarContextAreaComponent implements AfterViewInit { * The elements are sorted based on their priority, with elements having * higher priority shown first. */ - private getElementsWithPriority(): { el: HTMLElement; priority: number }[] { + private _getElementsWithPriority(): { el: HTMLElement; priority: number }[] { return [...this.el.nativeElement.childNodes] .map((element: HTMLElement, index) => { const hasPriorityAttribute = element.hasAttribute && element.hasAttribute('fdShellbarHidePriority'); @@ -85,7 +85,7 @@ export class ShellbarContextAreaComponent implements AfterViewInit { * This method will hide the last shown element iteratively until the total width * fits within the available width. */ - private hideElementsIfNeeded( + private _hideElementsIfNeeded( elements: { el: HTMLElement; priority: number; @@ -99,7 +99,7 @@ export class ShellbarContextAreaComponent implements AfterViewInit { break; } shownElements[shownElements.length - 1].el.style.display = 'none'; - allItemsWidth = this.calculateShownElementsWidth(elements); + allItemsWidth = this._calculateShownElementsWidth(elements); } } @@ -108,7 +108,7 @@ export class ShellbarContextAreaComponent implements AfterViewInit { * This method will show the first hidden element iteratively as long as there * is sufficient space, and hide the element again if the space is exceeded. */ - private showElementsIfNeeded( + private _showElementsIfNeeded( elements: { el: HTMLElement; priority: number; @@ -119,7 +119,7 @@ export class ShellbarContextAreaComponent implements AfterViewInit { let hiddenElements = elements.filter((el) => el.el.style.display === 'none'); while (hiddenElements.length > 0 && allItemsWidth <= availableWidth) { hiddenElements[0].el.style.display = ''; - allItemsWidth = this.calculateShownElementsWidth(elements); + allItemsWidth = this._calculateShownElementsWidth(elements); if (allItemsWidth > availableWidth) { hiddenElements[0].el.style.display = 'none'; break; @@ -132,7 +132,7 @@ export class ShellbarContextAreaComponent implements AfterViewInit { * Calculates the total gap between the visible elements. * Avoids negative gap for single or no elements. */ - private calculateTotalGap(elementsLength: number): number { + private _calculateTotalGap(elementsLength: number): number { const gap = parseFloat(window.getComputedStyle(this.el.nativeElement).gap || '0'); return gap * Math.max(elementsLength - 1, 0); } @@ -140,16 +140,16 @@ export class ShellbarContextAreaComponent implements AfterViewInit { /** * Calculates the total width of the shown elements, including the gaps. */ - private calculateShownElementsWidth(elements: { el: HTMLElement; priority: number }[]): number { + private _calculateShownElementsWidth(elements: { el: HTMLElement; priority: number }[]): number { const shownElements = elements.filter((el) => el.el.style.display !== 'none'); const totalWidth = shownElements.reduce((acc, el) => acc + el.el.clientWidth, 0); - return totalWidth + this.calculateTotalGap(shownElements.length); + return totalWidth + this._calculateTotalGap(shownElements.length); } /** * Gets the available width of the container. */ - private getAvailableWidth(): number { + private _getAvailableWidth(): number { return this.el.nativeElement.offsetWidth; } } diff --git a/libs/core/shellbar/shellbar-logo/shellbar-logo.component.ts b/libs/core/shellbar/shellbar-logo/shellbar-logo.component.ts index 0d0b0b6fdba..35701e89218 100644 --- a/libs/core/shellbar/shellbar-logo/shellbar-logo.component.ts +++ b/libs/core/shellbar/shellbar-logo/shellbar-logo.component.ts @@ -1,4 +1,6 @@ -import { ChangeDetectionStrategy, Component, ViewEncapsulation } from '@angular/core'; +import { NgOptimizedImage } from '@angular/common'; +import { ChangeDetectionStrategy, Component, Input, ViewEncapsulation } from '@angular/core'; +import { Nullable } from '@fundamental-ngx/cdk/utils'; /** * The component that represents a shellbar logo. @@ -11,9 +13,34 @@ import { ChangeDetectionStrategy, Component, ViewEncapsulation } from '@angular/ */ @Component({ selector: 'fd-shellbar-logo', - template: ``, + template: ` + + `, encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, + imports: [NgOptimizedImage], standalone: true }) -export class ShellbarLogoComponent {} +export class ShellbarLogoComponent { + /** Source of the logo image */ + @Input() src: Nullable; + + /** Srcset for responsive images */ + @Input() + srcset: Nullable; + + /** Width of the logo */ + @Input() width: Nullable; + + /** Height of the logo */ + @Input() height: Nullable; + + /** Alt text for the image */ + @Input() alt: Nullable; +} diff --git a/libs/core/shellbar/shellbar-overflow-priority.directive.ts b/libs/core/shellbar/shellbar-overflow-priority.directive.ts index 1bf3cc28545..018c28ecb35 100644 --- a/libs/core/shellbar/shellbar-overflow-priority.directive.ts +++ b/libs/core/shellbar/shellbar-overflow-priority.directive.ts @@ -1,4 +1,4 @@ -import { Directive, ElementRef, Input } from '@angular/core'; +import { Directive, ElementRef, inject, Input } from '@angular/core'; @Directive({ selector: '[fdShellbarHidePriority]', @@ -9,5 +9,5 @@ export class ShellbarHidePriorityDirective { @Input('fdShellbarHidePriority') priority: any; /** @hidden */ - constructor(public el: ElementRef) {} + el = inject(ElementRef); } diff --git a/libs/core/shellbar/shellbar-subtitle/shellbar-subtitle.component.html b/libs/core/shellbar/shellbar-subtitle/shellbar-subtitle.component.html deleted file mode 100644 index 45a45a64d08..00000000000 --- a/libs/core/shellbar/shellbar-subtitle/shellbar-subtitle.component.html +++ /dev/null @@ -1,3 +0,0 @@ -
    - -
    diff --git a/libs/core/shellbar/shellbar-subtitle/shellbar-subtitle.component.ts b/libs/core/shellbar/shellbar-subtitle/shellbar-subtitle.component.ts index 812b0907612..bc0aa986479 100644 --- a/libs/core/shellbar/shellbar-subtitle/shellbar-subtitle.component.ts +++ b/libs/core/shellbar/shellbar-subtitle/shellbar-subtitle.component.ts @@ -1,4 +1,5 @@ import { ChangeDetectionStrategy, Component, ViewEncapsulation } from '@angular/core'; +import { FD_SHELLBAR_SUBTITLE_COMPONENT } from '../tokens'; /** * The component that represents a shellbar subtitle. @@ -11,9 +12,14 @@ import { ChangeDetectionStrategy, Component, ViewEncapsulation } from '@angular/ */ @Component({ selector: 'fd-shellbar-subtitle', - templateUrl: './shellbar-subtitle.component.html', + template: ` + + + + `, encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, + standalone: true, styles: [ ` fd-shellbar-subtitle { @@ -21,6 +27,11 @@ import { ChangeDetectionStrategy, Component, ViewEncapsulation } from '@angular/ } ` ], - standalone: true + providers: [ + { + provide: FD_SHELLBAR_SUBTITLE_COMPONENT, + useExisting: ShellbarSubtitleComponent + } + ] }) export class ShellbarSubtitleComponent {} diff --git a/libs/core/shellbar/shellbar-title/shellbar-title.component.html b/libs/core/shellbar/shellbar-title/shellbar-title.component.html deleted file mode 100644 index c2e387ef826..00000000000 --- a/libs/core/shellbar/shellbar-title/shellbar-title.component.html +++ /dev/null @@ -1,3 +0,0 @@ -

    - -

    diff --git a/libs/core/shellbar/shellbar-title/shellbar-title.component.ts b/libs/core/shellbar/shellbar-title/shellbar-title.component.ts index 54c4c41ba72..73a129e20dc 100644 --- a/libs/core/shellbar/shellbar-title/shellbar-title.component.ts +++ b/libs/core/shellbar/shellbar-title/shellbar-title.component.ts @@ -1,4 +1,5 @@ import { ChangeDetectionStrategy, Component, ViewEncapsulation } from '@angular/core'; +import { FD_SHELLBAR_TITLE_COMPONENT } from '../tokens'; /** * The component that represents a shellbar title. @@ -11,9 +12,26 @@ import { ChangeDetectionStrategy, Component, ViewEncapsulation } from '@angular/ */ @Component({ selector: 'fd-shellbar-title', - templateUrl: './shellbar-title.component.html', + template: ` + + + + `, encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, - standalone: true + standalone: true, + styles: [ + ` + fd-shellbar__title { + display: flex; + } + ` + ], + providers: [ + { + provide: FD_SHELLBAR_TITLE_COMPONENT, + useExisting: ShellbarTitleComponent + } + ] }) export class ShellbarTitleComponent {} diff --git a/libs/core/shellbar/shellbar.component.html b/libs/core/shellbar/shellbar.component.html index df5108f4406..3c06b4fd156 100644 --- a/libs/core/shellbar/shellbar.component.html +++ b/libs/core/shellbar/shellbar.component.html @@ -34,7 +34,7 @@ - @if (searchComponent) { + @if (searchComponent && _showMobileSearch()) {
    { if (!state.text) { - this._showMobileSearch = false; + this._showMobileSearch.set(false); this._actions?._setSearchVisibility(false); this._cd.detectChanges(); } @@ -178,7 +190,7 @@ export class ShellbarComponent implements AfterContentInit, AfterViewInit, OnDes } /** @hidden */ - @ContentChild(ShellbarActionsComponent) + @ContentChild(FD_SHELLBAR_ACTIONS_COMPONENT) private _actions?: ShellbarActionsComponent; /** @hidden */ @@ -191,12 +203,16 @@ export class ShellbarComponent implements AfterContentInit, AfterViewInit, OnDes /** @hidden */ get _hideTitleComponents(): boolean { - return this._currentSize !== 'xl' && this._currentSize !== 'l' && this._showMobileSearch; + return ( + this._currentSize !== ShellbarSize.EXTRA_LARGE && + this._currentSize !== ShellbarSize.LARGE && + this._showMobileSearch() + ); } /** @hidden */ get _hideAllComponents(): boolean { - return this._currentSize === 's' && this._showMobileSearch; + return this._currentSize === ShellbarSize.SMALL && this._showMobileSearch(); } /** @hidden */ @@ -205,7 +221,7 @@ export class ShellbarComponent implements AfterContentInit, AfterViewInit, OnDes } /** @hidden */ - _showMobileSearch = false; + _showMobileSearch = signal(false); /** @hidden */ private _groupFlex: Nullable; @@ -226,7 +242,7 @@ export class ShellbarComponent implements AfterContentInit, AfterViewInit, OnDes private _size: ShellbarSizes | undefined; /** @hidden */ - private _breakpointSize: ShellbarSizes = 'm'; + private _breakpointSize: ShellbarSizes = ShellbarSize.MEDIUM; /** @hidden */ private readonly _cd = inject(ChangeDetectorRef); @@ -282,7 +298,7 @@ export class ShellbarComponent implements AfterContentInit, AfterViewInit, OnDes /** @hidden */ _closeMobileSearch(): void { - this._showMobileSearch = false; + this._showMobileSearch.set(false); this._actions?._setSearchVisibility(false); this._cd.detectChanges(); } @@ -301,9 +317,9 @@ export class ShellbarComponent implements AfterContentInit, AfterViewInit, OnDes /** @hidden */ private _setSearchComponentListeners(): void { this._actions?.searchOpen.pipe(takeUntilDestroyed(this._destroyRef)).subscribe((showSearch) => { - this._showMobileSearch = showSearch; + this._showMobileSearch.set(showSearch); this._cd.detectChanges(); - if (this._currentSize !== 's') { + if (this._currentSize !== ShellbarSize.SMALL) { return; } @@ -325,7 +341,7 @@ export class ShellbarComponent implements AfterContentInit, AfterViewInit, OnDes private _placeSearch(): void { const size = this._currentSize$.value; - if (size === 'xl' || (size === 's' && this._showMobileSearch)) { + if (size === 'xl' || (size === ShellbarSize.SMALL && this._showMobileSearch())) { this._attachSearch(); } else { this._detachSearch(); @@ -369,6 +385,7 @@ export class ShellbarComponent implements AfterContentInit, AfterViewInit, OnDes /** @hidden */ private _attachSearch(shouldFocus = false): void { + this._showMobileSearch.set(true); if (this._searchPortalOutlet?.hasAttached()) { return; } diff --git a/libs/core/shellbar/tokens.ts b/libs/core/shellbar/tokens.ts index 8a76bb4bfc6..0159646822b 100644 --- a/libs/core/shellbar/tokens.ts +++ b/libs/core/shellbar/tokens.ts @@ -10,4 +10,12 @@ export const FD_SHELLBAR_BRANDING_COMPONENT = new InjectionToken('FdShellbarComponent'); + +export const FD_SHELLBAR_TITLE_COMPONENT = new InjectionToken('FdShellbarTitleComponent'); + +export const FD_SHELLBAR_SUBTITLE_COMPONENT = new InjectionToken('FdShellbarSubtitleComponent'); + +export const FD_SHELLBAR_USER_MENU_COMPONENT = new InjectionToken('FdShellbarUserMenuComponent'); diff --git a/libs/core/shellbar/user-menu/shellbar-user-menu.component.ts b/libs/core/shellbar/user-menu/shellbar-user-menu.component.ts index 1d61b4d4ba5..d8826c7aa82 100644 --- a/libs/core/shellbar/user-menu/shellbar-user-menu.component.ts +++ b/libs/core/shellbar/user-menu/shellbar-user-menu.component.ts @@ -14,6 +14,7 @@ import { MenuComponent, MenuModule } from '@fundamental-ngx/core/menu'; import { Placement, PopoverFillMode } from '@fundamental-ngx/core/shared'; import { ShellbarUser } from '../model/shellbar-user'; import { ShellbarUserMenu } from '../model/shellbar-user-menu'; +import { FD_SHELLBAR_USER_MENU_COMPONENT } from '../tokens'; import { ShellbarUserMenuButtonDirective } from './shellbar-user-menu-button.directive'; /** @@ -25,7 +26,13 @@ import { ShellbarUserMenuButtonDirective } from './shellbar-user-menu-button.dir templateUrl: './shellbar-user-menu.component.html', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, - imports: [ButtonComponent, MenuModule, AvatarComponent, ShellbarUserMenuButtonDirective] + imports: [ButtonComponent, MenuModule, AvatarComponent, ShellbarUserMenuButtonDirective], + providers: [ + { + provide: FD_SHELLBAR_USER_MENU_COMPONENT, + useExisting: ShellbarUserMenuComponent + } + ] }) export class ShellbarUserMenuComponent { /** The user data. */ diff --git a/libs/docs/core/shellbar/examples/shellbar-options-example/shellbar-options-example.component.html b/libs/docs/core/shellbar/examples/shellbar-options-example/shellbar-options-example.component.html index 891ec86ad5f..e8dabed3a2c 100644 --- a/libs/docs/core/shellbar/examples/shellbar-options-example/shellbar-options-example.component.html +++ b/libs/docs/core/shellbar/examples/shellbar-options-example/shellbar-options-example.component.html @@ -8,9 +8,15 @@

    Custom reverse context area hiding ordering

    - - - + {{ productMenuControl }} Subtitle diff --git a/libs/docs/core/shellbar/shellbar-docs.component.html b/libs/docs/core/shellbar/shellbar-docs.component.html index d704ce12e18..21f81dff155 100644 --- a/libs/docs/core/shellbar/shellbar-docs.component.html +++ b/libs/docs/core/shellbar/shellbar-docs.component.html @@ -1,126 +1,6 @@ - How it works - -
      -
    • The shellbar should be placed inside the shell layout container.
    • -
    • The shellbar is fluid and responsive by default with proper margins and padding built in.
    • -
    • The shellbar actions are duplicated into the overflow menu on mobile screens.
    • -
    • - Product menu data gets passed as inputs to the <fd-product-menu> component. The user, user - menu and product switcher are passed as inputs to the <fd-shellbar-actions> component. Data - for each action gets passed as inputs to the <fd-shellbar-action> component. The response to - clicks on any of these items is handled via callback functions for each object. See the 'collapsible' - example to gain an understanding of how this works. -
    • -
    -
    - - - - Basic - - This example shows the minimum shellbar for a single application product with only user settings. If no user - thumbnail is available then display initials. - - - - - - - - - - Links with collapsible menu and product switcher. - - -

    The shellbar can have 4 different sizes 's' | 'm' | 'l' | 'xl'.

    -

    - When a product has multiple links, the product links should collapse into an overflow menu on mobile screens - (s size). -

    -

    All actions, except for the user menu, should be collapsed.

    -

    - ProductSwitchComponent and ProductMenuComponent have properties straight from popover - component, so some customisation can be added, by passing inputs ex. [position]="'bottom-end'". -

    -
    - - - - - - - - Responsive Shellbar - - If no size Input property provided, Shellbar will automatically determine which size to apply based on - the current width of it. - - - - - - - - - - Shellbar with Growing groups - - -

    - The shellbar is optimized to be used with central group for the search. This creates a necessity of centering - the groups by giving them equal width. -

    -

    - If the design suggests that each group can have own width, developers can pass [groupFlex] input - property defining for each group whether it can shrink, allowing other groups to grow. -

    -
    - - - - - - - - Shellbar with custom user menu - - -

    Shellbar has ability to render custom user menu. This can be achieved by passing custom template

    -
    - - - - - - Shellbar with branding and context area - -

    - This example demonstrates the usage of the Shellbar component with branding and a context area. The branding - section includes a customizable logo, title, and subtitle through the - fd-shellbar-branding component. The context area can hold various elements, such as separators, - buttons, and object statuses, and is managed by the fd-shellbar-context-area component. -

    -

    To control the visibility of elements in the context area based on available space, there are two options:

    -
      -
    • - Use fdShellbarHidePriority Directive: Add the - fdShellbarHidePriority directive to each element for custom overflow management. Assign a - unique priority number to each item; elements with higher numbers will be hidden first when space is - limited. This option provides full control over the hiding order and requires unique values for each element - to establish a clear priority. -
    • -
    • - Automatic Priority Assignment: Alternatively, you can skip adding the - fdShellbarHidePriority - directive, allowing the context area to automatically set priority based on the order of elements. In this - case, elements are prioritized for hiding based on their placement within the - fd-shellbar-context-area, with earlier items hidden last. -
    • -
    -
    From c781af9dd65329655816842a0428f462e01aab4f Mon Sep 17 00:00:00 2001 From: dpavlenishvili Date: Mon, 9 Dec 2024 20:54:37 +0400 Subject: [PATCH 8/9] fix(core): overflow wp --- libs/core/shellbar/index.ts | 2 +- libs/core/shellbar/model/shellbar-sizes.ts | 7 -- .../product-menu/product-menu.component.html | 86 +++++++++---------- .../shellbar-action.component.html | 2 +- .../shellbar-actions-mobile.component.html | 14 +++ .../shellbar-actions-mobile.component.ts | 61 +++++++++++++ .../shellbar-actions.component.html | 10 +-- .../shellbar-actions.component.ts | 20 ++++- .../shellbar-title.component.ts | 2 +- libs/core/shellbar/shellbar.component.html | 43 ++++------ libs/core/shellbar/shellbar.component.scss | 11 +-- libs/core/shellbar/shellbar.component.ts | 42 ++++----- libs/core/shellbar/shellbar.module.ts | 6 +- 13 files changed, 184 insertions(+), 122 deletions(-) create mode 100644 libs/core/shellbar/shellbar-actions-mobile/shellbar-actions-mobile.component.html create mode 100644 libs/core/shellbar/shellbar-actions-mobile/shellbar-actions-mobile.component.ts diff --git a/libs/core/shellbar/index.ts b/libs/core/shellbar/index.ts index fa371be516b..1e63345ef2c 100644 --- a/libs/core/shellbar/index.ts +++ b/libs/core/shellbar/index.ts @@ -5,7 +5,7 @@ export * from './model/shellbar-user'; export * from './model/shellbar-user-menu'; export * from './product-menu/product-menu.component'; export * from './shellbar-action/shellbar-action.component'; -export * from './shellbar-actions-toolbar/shellbar-actions-toolbar.component'; +export * from './shellbar-actions-mobile/shellbar-actions-mobile.component'; export * from './shellbar-actions/shellbar-actions.component'; export * from './shellbar-branding/shellbar-branding.component'; export * from './shellbar-context-area/shellbar-context-area.component'; diff --git a/libs/core/shellbar/model/shellbar-sizes.ts b/libs/core/shellbar/model/shellbar-sizes.ts index 0b94f89c7c1..550e64bc321 100644 --- a/libs/core/shellbar/model/shellbar-sizes.ts +++ b/libs/core/shellbar/model/shellbar-sizes.ts @@ -1,10 +1,3 @@ -export enum ShellbarSize { - SMALL = 's', - MEDIUM = 'm', - LARGE = 'l', - EXTRA_LARGE = 'xl' -} - export type ShellbarSizes = 's' | 'm' | 'l' | 'xl'; export type Breakpoints = Record; diff --git a/libs/core/shellbar/product-menu/product-menu.component.html b/libs/core/shellbar/product-menu/product-menu.component.html index e9086c400c0..f927037213a 100644 --- a/libs/core/shellbar/product-menu/product-menu.component.html +++ b/libs/core/shellbar/product-menu/product-menu.component.html @@ -1,44 +1,42 @@ -
    - @if (items && items.length > 0) { -

    {{ control }}

    - - - @for (item of items; track item) { -
  • - - {{ item.name }} - @if (item.glyph) { - - } - -
  • - } -
    - } @else { -

    - {{ control }} -

    - } -
    +@if (items && items.length > 0) { +

    {{ control }}

    + + + @for (item of items; track item) { +
  • + + {{ item.name }} + @if (item.glyph) { + + } + +
  • + } +
    +} @else { +

    + {{ control }} +

    +} diff --git a/libs/core/shellbar/shellbar-action/shellbar-action.component.html b/libs/core/shellbar/shellbar-action/shellbar-action.component.html index c568eab1ebc..a19f93dfbb4 100644 --- a/libs/core/shellbar/shellbar-action/shellbar-action.component.html +++ b/libs/core/shellbar/shellbar-action/shellbar-action.component.html @@ -6,7 +6,7 @@ fdCozy [glyph]="glyph" [glyphFont]="glyphFont" - (click)="callback?.($event)" + (click)="callback ? callback($event) : ''" > @if (notificationCount) { diff --git a/libs/core/shellbar/shellbar-actions-mobile/shellbar-actions-mobile.component.html b/libs/core/shellbar/shellbar-actions-mobile/shellbar-actions-mobile.component.html new file mode 100644 index 00000000000..39b3ecb0d73 --- /dev/null +++ b/libs/core/shellbar/shellbar-actions-mobile/shellbar-actions-mobile.component.html @@ -0,0 +1,14 @@ +@if (shellbarActions.length > 0 || searchExists) { + + + @for (action of shellbarActions; track action; let i = $index) { +
  • + + + {{ action.label }} + +
  • + } +
    +
    +} diff --git a/libs/core/shellbar/shellbar-actions-mobile/shellbar-actions-mobile.component.ts b/libs/core/shellbar/shellbar-actions-mobile/shellbar-actions-mobile.component.ts new file mode 100644 index 00000000000..0b9238211bb --- /dev/null +++ b/libs/core/shellbar/shellbar-actions-mobile/shellbar-actions-mobile.component.ts @@ -0,0 +1,61 @@ +import { + AfterContentChecked, + ChangeDetectionStrategy, + Component, + EventEmitter, + Input, + Output, + QueryList, + ViewEncapsulation +} from '@angular/core'; +import { ActionSheetModule } from '@fundamental-ngx/core/action-sheet'; +import { ButtonComponent } from '@fundamental-ngx/core/button'; +import { MenuModule } from '@fundamental-ngx/core/menu'; +import { OverflowLayoutModule } from '@fundamental-ngx/core/overflow-layout'; +import { FdTranslatePipe } from '@fundamental-ngx/i18n'; +import { ShellbarActionComponent } from '../shellbar-action/shellbar-action.component'; + +@Component({ + selector: 'fd-shellbar-actions-mobile', + templateUrl: './shellbar-actions-mobile.component.html', + encapsulation: ViewEncapsulation.None, + changeDetection: ChangeDetectionStrategy.OnPush, + standalone: true, + imports: [ActionSheetModule, ButtonComponent, FdTranslatePipe, OverflowLayoutModule, MenuModule] +}) +export class ShellbarActionsMobileComponent implements AfterContentChecked { + /** @hidden */ + @Input() + shellbarActions: QueryList; + + /** + * Whether the search is present in the shellbar. + */ + @Input() + searchExists = false; + + /** @hidden */ + @Output() + showSearch = new EventEmitter(); + + /** @hidden */ + totalNotifications: number; + + /** @hidden */ + actionClicked(item: ShellbarActionComponent, event: MouseEvent): void { + if (item.callback) { + item.callback(event); + } + } + + /** @hidden */ + ngAfterContentChecked(): void { + this.totalNotifications = 0; + + this.shellbarActions?.forEach((action) => { + if (action.notificationCount && typeof action.notificationCount === 'number') { + this.totalNotifications = this.totalNotifications + action.notificationCount; + } + }); + } +} diff --git a/libs/core/shellbar/shellbar-actions/shellbar-actions.component.html b/libs/core/shellbar/shellbar-actions/shellbar-actions.component.html index 951d2ff4e4c..d9eeb057d8e 100644 --- a/libs/core/shellbar/shellbar-actions/shellbar-actions.component.html +++ b/libs/core/shellbar/shellbar-actions/shellbar-actions.component.html @@ -5,20 +5,20 @@ }
    -
    +
    -
    - -
    + + + @if (_addSearchIcon && !showSearch) { } - + @if (userComponent || userItem) { @if (!userComponent) { ; /** @hidden */ - @ContentChild(ShellbarUserMenuComponent) + @ContentChild(FD_SHELLBAR_USER_MENU_COMPONENT) userComponent: ShellbarUserMenuComponent; /** @hidden */ - @ViewChild(ShellbarUserMenuComponent) + @ViewChild(FD_SHELLBAR_USER_MENU_COMPONENT) userComponentView: ShellbarUserMenuComponent; /** @hidden */ @@ -165,6 +176,7 @@ export class ShellbarActionsComponent implements OnDestroy { this._searchPortal = portal; this._addSearchIcon = true; this.currentSize = size; + this.showSearch = size === 'xl'; this._searchComponent = searchComponent; this._toggleSearchPortal(this.showSearch); this._cd.detectChanges(); diff --git a/libs/core/shellbar/shellbar-title/shellbar-title.component.ts b/libs/core/shellbar/shellbar-title/shellbar-title.component.ts index 73a129e20dc..bef61676c67 100644 --- a/libs/core/shellbar/shellbar-title/shellbar-title.component.ts +++ b/libs/core/shellbar/shellbar-title/shellbar-title.component.ts @@ -22,7 +22,7 @@ import { FD_SHELLBAR_TITLE_COMPONENT } from '../tokens'; standalone: true, styles: [ ` - fd-shellbar__title { + fd-shellbar-title { display: flex; } ` diff --git a/libs/core/shellbar/shellbar.component.html b/libs/core/shellbar/shellbar.component.html index 3c06b4fd156..04e276285cf 100644 --- a/libs/core/shellbar/shellbar.component.html +++ b/libs/core/shellbar/shellbar.component.html @@ -27,35 +27,30 @@
    } @if (!_hideAllComponents) { - - - + } - @if (searchComponent && _showMobileSearch()) { -
    -
    - -
    - @if (_currentSize === 'xl' || _hideAllComponents) { -
    - -
    - } -
    - } + + + + + + + + + + + + + + + + + + @if (!_hideAllComponents) { } - @if (!_hideAllComponents) { - - }
    diff --git a/libs/core/shellbar/shellbar.component.scss b/libs/core/shellbar/shellbar.component.scss index 4439d53f252..d73f71fba13 100644 --- a/libs/core/shellbar/shellbar.component.scss +++ b/libs/core/shellbar/shellbar.component.scss @@ -20,11 +20,12 @@ } } -fd-shellbar-actions { - .fd-shellbar__search-field { - width: 100% !important; - min-width: 15rem; - } +.fd-shellbar__action.fd-shellbar__action--desktop:empty { + display: none; +} + +.fd-shellbar .fd-shellbar__group .fd-shellbar__button.fd-shellbar__button--menu { + --fdButtonColor: var(--sapShell_TextColor); } .fd-shellbar__action.fd-shellbar__action--desktop:empty { diff --git a/libs/core/shellbar/shellbar.component.ts b/libs/core/shellbar/shellbar.component.ts index 8b3c209085c..728c13511d7 100644 --- a/libs/core/shellbar/shellbar.component.ts +++ b/libs/core/shellbar/shellbar.component.ts @@ -14,8 +14,7 @@ import { QueryList, ViewChild, ViewEncapsulation, - inject, - signal + inject } from '@angular/core'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { Nullable, resizeObservable } from '@fundamental-ngx/cdk/utils'; @@ -27,13 +26,7 @@ import { SideNavigationInterface } from '@fundamental-ngx/core/side-navigation'; import { FdTranslatePipe } from '@fundamental-ngx/i18n'; import equal from 'fast-deep-equal'; import { BehaviorSubject, Subscription, debounceTime, distinctUntilChanged } from 'rxjs'; -import { - Breakpoints, - NormalizedBreakpoint, - ShellbarGroupFlexOptions, - ShellbarSize, - ShellbarSizes -} from './model/shellbar-sizes'; +import { Breakpoints, NormalizedBreakpoint, ShellbarGroupFlexOptions, ShellbarSizes } from './model/shellbar-sizes'; import { ShellbarActionsComponent } from './shellbar-actions/shellbar-actions.component'; import { ShellbarBrandingComponent } from './shellbar-branding/shellbar-branding.component'; import { @@ -160,7 +153,7 @@ export class ShellbarComponent implements AfterContentInit, AfterViewInit, OnDes .pipe(takeUntilDestroyed(this._destroyRef)) .subscribe((state) => { if (!state.text) { - this._showMobileSearch.set(false); + this._showMobileSearch = false; this._actions?._setSearchVisibility(false); this._cd.detectChanges(); } @@ -178,7 +171,7 @@ export class ShellbarComponent implements AfterContentInit, AfterViewInit, OnDes } /** - * Search component placed inside the shellbar + * branding component */ @ContentChild(FD_SHELLBAR_BRANDING_COMPONENT, { descendants: true, static: false }) set brandingComponent(component: Nullable) { @@ -203,16 +196,12 @@ export class ShellbarComponent implements AfterContentInit, AfterViewInit, OnDes /** @hidden */ get _hideTitleComponents(): boolean { - return ( - this._currentSize !== ShellbarSize.EXTRA_LARGE && - this._currentSize !== ShellbarSize.LARGE && - this._showMobileSearch() - ); + return this._currentSize !== 'xl' && this._currentSize !== 'l' && this._showMobileSearch; } /** @hidden */ get _hideAllComponents(): boolean { - return this._currentSize === ShellbarSize.SMALL && this._showMobileSearch(); + return this._currentSize === 's' && this._showMobileSearch; } /** @hidden */ @@ -221,7 +210,10 @@ export class ShellbarComponent implements AfterContentInit, AfterViewInit, OnDes } /** @hidden */ - _showMobileSearch = signal(false); + _showMobileSearch = false; + + /** @hidden */ + private _brandingComponent: Nullable; /** @hidden */ private _groupFlex: Nullable; @@ -232,9 +224,6 @@ export class ShellbarComponent implements AfterContentInit, AfterViewInit, OnDes /** @hidden */ private _searchComponent: Nullable; - /** @hidden */ - private _brandingComponent: Nullable; - /** @hidden */ private readonly _currentSize$ = new BehaviorSubject(this._currentSize); @@ -242,7 +231,7 @@ export class ShellbarComponent implements AfterContentInit, AfterViewInit, OnDes private _size: ShellbarSizes | undefined; /** @hidden */ - private _breakpointSize: ShellbarSizes = ShellbarSize.MEDIUM; + private _breakpointSize: ShellbarSizes = 'm'; /** @hidden */ private readonly _cd = inject(ChangeDetectorRef); @@ -298,7 +287,7 @@ export class ShellbarComponent implements AfterContentInit, AfterViewInit, OnDes /** @hidden */ _closeMobileSearch(): void { - this._showMobileSearch.set(false); + this._showMobileSearch = false; this._actions?._setSearchVisibility(false); this._cd.detectChanges(); } @@ -317,9 +306,9 @@ export class ShellbarComponent implements AfterContentInit, AfterViewInit, OnDes /** @hidden */ private _setSearchComponentListeners(): void { this._actions?.searchOpen.pipe(takeUntilDestroyed(this._destroyRef)).subscribe((showSearch) => { - this._showMobileSearch.set(showSearch); + this._showMobileSearch = showSearch; this._cd.detectChanges(); - if (this._currentSize !== ShellbarSize.SMALL) { + if (this._currentSize !== 's') { return; } @@ -341,7 +330,7 @@ export class ShellbarComponent implements AfterContentInit, AfterViewInit, OnDes private _placeSearch(): void { const size = this._currentSize$.value; - if (size === 'xl' || (size === ShellbarSize.SMALL && this._showMobileSearch())) { + if (size === 's' && this._showMobileSearch) { this._attachSearch(); } else { this._detachSearch(); @@ -385,7 +374,6 @@ export class ShellbarComponent implements AfterContentInit, AfterViewInit, OnDes /** @hidden */ private _attachSearch(shouldFocus = false): void { - this._showMobileSearch.set(true); if (this._searchPortalOutlet?.hasAttached()) { return; } diff --git a/libs/core/shellbar/shellbar.module.ts b/libs/core/shellbar/shellbar.module.ts index 1681b91db29..b4ff06b06ff 100644 --- a/libs/core/shellbar/shellbar.module.ts +++ b/libs/core/shellbar/shellbar.module.ts @@ -9,7 +9,7 @@ import { ShellbarSubtitleComponent } from './shellbar-subtitle/shellbar-subtitle import { ShellbarTitleComponent } from './shellbar-title/shellbar-title.component'; import { ContentDensityModule } from '@fundamental-ngx/core/content-density'; -import { ShellbarActionsToolbarComponent } from './shellbar-actions-toolbar/shellbar-actions-toolbar.component'; +import { ShellbarActionsMobileComponent } from './shellbar-actions-mobile/shellbar-actions-mobile.component'; import { ShellbarSidenavDirective } from './shellbar-sidenav.directive'; import { ShellbarUserMenuComponent } from './user-menu/shellbar-user-menu.component'; @@ -19,7 +19,7 @@ import { ShellbarUserMenuComponent } from './user-menu/shellbar-user-menu.compon ProductMenuComponent, ShellbarSubtitleComponent, ShellbarActionsComponent, - ShellbarActionsToolbarComponent, + ShellbarActionsMobileComponent, ShellbarActionComponent, ShellbarLogoComponent, ShellbarTitleComponent, @@ -31,7 +31,7 @@ import { ShellbarUserMenuComponent } from './user-menu/shellbar-user-menu.compon ProductMenuComponent, ShellbarSubtitleComponent, ShellbarActionsComponent, - ShellbarActionsToolbarComponent, + ShellbarActionsMobileComponent, ShellbarActionComponent, ShellbarLogoComponent, ShellbarTitleComponent, From 0a31d70061260ac4908d228fe91a9a3d7d728b8b Mon Sep 17 00:00:00 2001 From: dpavlenishvili Date: Mon, 23 Dec 2024 19:41:52 +0400 Subject: [PATCH 9/9] fix(deps): fix merge conflicts --- .../shellbar-actions-mobile.component.html | 55 +- .../shellbar-actions-mobile.component.ts | 4 +- .../shellbar-actions.component.html | 10 +- .../shellbar-actions.component.ts | 1 - libs/core/toolbar/toolbar.component.html | 2 +- .../shellbar/shellbar-docs.component.html | 95 + yarn.lock | 2101 ++++++++++------- 7 files changed, 1444 insertions(+), 824 deletions(-) diff --git a/libs/core/shellbar/shellbar-actions-mobile/shellbar-actions-mobile.component.html b/libs/core/shellbar/shellbar-actions-mobile/shellbar-actions-mobile.component.html index 39b3ecb0d73..93f8201edff 100644 --- a/libs/core/shellbar/shellbar-actions-mobile/shellbar-actions-mobile.component.html +++ b/libs/core/shellbar/shellbar-actions-mobile/shellbar-actions-mobile.component.html @@ -1,14 +1,45 @@ @if (shellbarActions.length > 0 || searchExists) { - - - @for (action of shellbarActions; track action; let i = $index) { -
  • - - - {{ action.label }} - -
  • - } -
    -
    +
    + + + + + + @if (searchExists) { +
  • + } + @for (action of shellbarActions; track action) { +
  • + @if (action.notificationCount) { + {{ action.notificationCount }} + } +
  • + } +
    +
    +
    } diff --git a/libs/core/shellbar/shellbar-actions-mobile/shellbar-actions-mobile.component.ts b/libs/core/shellbar/shellbar-actions-mobile/shellbar-actions-mobile.component.ts index 0b9238211bb..bff17764128 100644 --- a/libs/core/shellbar/shellbar-actions-mobile/shellbar-actions-mobile.component.ts +++ b/libs/core/shellbar/shellbar-actions-mobile/shellbar-actions-mobile.component.ts @@ -10,8 +10,6 @@ import { } from '@angular/core'; import { ActionSheetModule } from '@fundamental-ngx/core/action-sheet'; import { ButtonComponent } from '@fundamental-ngx/core/button'; -import { MenuModule } from '@fundamental-ngx/core/menu'; -import { OverflowLayoutModule } from '@fundamental-ngx/core/overflow-layout'; import { FdTranslatePipe } from '@fundamental-ngx/i18n'; import { ShellbarActionComponent } from '../shellbar-action/shellbar-action.component'; @@ -21,7 +19,7 @@ import { ShellbarActionComponent } from '../shellbar-action/shellbar-action.comp encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, - imports: [ActionSheetModule, ButtonComponent, FdTranslatePipe, OverflowLayoutModule, MenuModule] + imports: [ActionSheetModule, ButtonComponent, FdTranslatePipe] }) export class ShellbarActionsMobileComponent implements AfterContentChecked { /** @hidden */ diff --git a/libs/core/shellbar/shellbar-actions/shellbar-actions.component.html b/libs/core/shellbar/shellbar-actions/shellbar-actions.component.html index d9eeb057d8e..951d2ff4e4c 100644 --- a/libs/core/shellbar/shellbar-actions/shellbar-actions.component.html +++ b/libs/core/shellbar/shellbar-actions/shellbar-actions.component.html @@ -5,20 +5,20 @@ }
    -
    +
    - - - +
    + +
    @if (_addSearchIcon && !showSearch) { } - + @if (userComponent || userItem) { @if (!userComponent) { } - +