diff --git a/packages/admin-ui/src/lib/core/src/components/app-shell/app-shell.component.ts b/packages/admin-ui/src/lib/core/src/components/app-shell/app-shell.component.ts index 7fcf559b68..2a6d617200 100644 --- a/packages/admin-ui/src/lib/core/src/components/app-shell/app-shell.component.ts +++ b/packages/admin-ui/src/lib/core/src/components/app-shell/app-shell.component.ts @@ -13,6 +13,11 @@ import { I18nService } from '../../providers/i18n/i18n.service'; import { LocalStorageService } from '../../providers/local-storage/local-storage.service'; import { ModalService } from '../../providers/modal/modal.service'; import { UiLanguageSwitcherDialogComponent } from '../ui-language-switcher-dialog/ui-language-switcher-dialog.component'; +import { + LocalizationDirectionType, + LocalizationLanguageCodeType, + LocalizationService, +} from '../../providers/localization/localization.service'; @Component({ selector: 'vdr-app-shell', @@ -22,8 +27,8 @@ import { UiLanguageSwitcherDialogComponent } from '../ui-language-switcher-dialo export class AppShellComponent implements OnInit { version = ADMIN_UI_VERSION; userName$: Observable; - uiLanguageAndLocale$: Observable<[LanguageCode, string | undefined]>; - direction$: Observable<'ltr' | 'rtl'>; + uiLanguageAndLocale$: LocalizationLanguageCodeType; + direction$: LocalizationDirectionType; availableLanguages: LanguageCode[] = []; hideVendureBranding = getAppConfig().hideVendureBranding; pageTitle$: Observable; @@ -38,25 +43,27 @@ export class AppShellComponent implements OnInit { private modalService: ModalService, private localStorageService: LocalStorageService, private breadcrumbService: BreadcrumbService, + private localizationService: LocalizationService, ) {} ngOnInit() { + this.direction$ = this.localizationService.direction$; + + this.uiLanguageAndLocale$ = this.localizationService.uiLanguageAndLocale$; + this.userName$ = this.dataService.client .userStatus() .single$.pipe(map(data => data.userStatus.username)); - this.uiLanguageAndLocale$ = this.dataService.client - .uiState() - .stream$.pipe(map(({ uiState }) => [uiState.language, uiState.locale ?? undefined])); + this.availableLanguages = this.i18nService.availableLanguages; + this.pageTitle$ = this.breadcrumbService.breadcrumbs$.pipe( map(breadcrumbs => breadcrumbs[breadcrumbs.length - 1].label), ); + this.mainNavExpanded$ = this.dataService.client .uiState() .stream$.pipe(map(({ uiState }) => uiState.mainNavExpanded)); - this.direction$ = this.uiLanguageAndLocale$.pipe( - map(([languageCode]) => (this.i18nService.isRTL(languageCode) ? 'rtl' : 'ltr')), - ); } selectUiLanguage() { diff --git a/packages/admin-ui/src/lib/core/src/components/notification/notification.component.html b/packages/admin-ui/src/lib/core/src/components/notification/notification.component.html index d736ec5eb7..5f36f1b86d 100644 --- a/packages/admin-ui/src/lib/core/src/components/notification/notification.component.html +++ b/packages/admin-ui/src/lib/core/src/components/notification/notification.component.html @@ -1,15 +1,10 @@ -
+
{{ stringifyMessage(message) | translate: translationVars }} -
+
\ No newline at end of file diff --git a/packages/admin-ui/src/lib/core/src/components/notification/notification.component.ts b/packages/admin-ui/src/lib/core/src/components/notification/notification.component.ts index 145ddfb1f0..56bb80cf8f 100644 --- a/packages/admin-ui/src/lib/core/src/components/notification/notification.component.ts +++ b/packages/admin-ui/src/lib/core/src/components/notification/notification.component.ts @@ -1,13 +1,20 @@ -import { Component, ElementRef, HostListener, ViewChild } from '@angular/core'; +import { Component, ElementRef, HostListener, OnInit, ViewChild } from '@angular/core'; import { NotificationType } from '../../providers/notification/notification.service'; +import { + LocalizationDirectionType, + LocalizationService, +} from '../../providers/localization/localization.service'; + @Component({ selector: 'vdr-notification', templateUrl: './notification.component.html', styleUrls: ['./notification.component.scss'], }) -export class NotificationComponent { +export class NotificationComponent implements OnInit { + direction$: LocalizationDirectionType; + @ViewChild('wrapper', { static: true }) wrapper: ElementRef; offsetTop = 0; message = ''; @@ -18,6 +25,15 @@ export class NotificationComponent { /* */ }; + /** + * + */ + constructor(private localizationService: LocalizationService) {} + + ngOnInit(): void { + this.direction$ = this.localizationService.direction$; + } + registerOnClickFn(fn: () => void): void { this.onClickFn = fn; } diff --git a/packages/admin-ui/src/lib/core/src/components/theme-switcher/theme-switcher.component.scss b/packages/admin-ui/src/lib/core/src/components/theme-switcher/theme-switcher.component.scss index 7cea448e4b..f76dba5bfd 100644 --- a/packages/admin-ui/src/lib/core/src/components/theme-switcher/theme-switcher.component.scss +++ b/packages/admin-ui/src/lib/core/src/components/theme-switcher/theme-switcher.component.scss @@ -1,6 +1,6 @@ :host { display: flex; - justify-content: start; + justify-content: flex-start; align-items: center; } @@ -27,10 +27,24 @@ button.theme-toggle { left: 0px; opacity: 1; } + &.default.active { color: #d6ae3f; } + &.dark.active { color: #ffdf3a; } } + +:host-context([dir='rtl']) { + .theme-icon { + left: auto; + right: 6px; + + &.active { + left: auto; + right: 0px; + } + } +} \ No newline at end of file diff --git a/packages/admin-ui/src/lib/core/src/providers/localization/localization.service.spec.ts b/packages/admin-ui/src/lib/core/src/providers/localization/localization.service.spec.ts new file mode 100644 index 0000000000..11b0e789b4 --- /dev/null +++ b/packages/admin-ui/src/lib/core/src/providers/localization/localization.service.spec.ts @@ -0,0 +1,29 @@ +import { TestBed } from '@angular/core/testing'; + +import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; +import { TestingCommonModule } from '../../../../../testing/testing-common.module'; +import { MockI18nService } from '../i18n/i18n.service.mock'; +import { DataService } from '../../data/providers/data.service'; +import { I18nService } from '../../providers/i18n/i18n.service'; +import { LocalizationService } from './localization.service'; + +describe('LocalizationService', () => { + let service: LocalizationService; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [TestingCommonModule], + providers: [ + LocalizationService, + { provide: I18nService, useClass: MockI18nService }, + { provide: DataService, useClass: class {} }, + ], + schemas: [CUSTOM_ELEMENTS_SCHEMA], + }); + service = TestBed.inject(LocalizationService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); diff --git a/packages/admin-ui/src/lib/core/src/providers/localization/localization.service.ts b/packages/admin-ui/src/lib/core/src/providers/localization/localization.service.ts new file mode 100644 index 0000000000..9b40ffc26f --- /dev/null +++ b/packages/admin-ui/src/lib/core/src/providers/localization/localization.service.ts @@ -0,0 +1,34 @@ +import { Injectable } from '@angular/core'; +import { Observable, map } from 'rxjs'; + +import { DataService } from '../../data/providers/data.service'; +import { I18nService } from '../../providers/i18n/i18n.service'; +import { LanguageCode } from '../../common/generated-types'; + +export type LocalizationDirectionType = Observable<'ltr' | 'rtl'>; +export type LocalizationLanguageCodeType = Observable<[LanguageCode, string | undefined]>; + +/** + * @description + * Provides localization helper functionality. + * + */ +@Injectable({ + providedIn: 'root', +}) +export class LocalizationService { + uiLanguageAndLocale$: LocalizationLanguageCodeType; + direction$: LocalizationDirectionType; + + constructor(private i18nService: I18nService, private dataService: DataService) { + this.uiLanguageAndLocale$ = this.dataService.client + ?.uiState() + ?.stream$?.pipe(map(({ uiState }) => [uiState.language, uiState.locale ?? undefined])); + + this.direction$ = this.uiLanguageAndLocale$?.pipe( + map(([languageCode]) => { + return this.i18nService.isRTL(languageCode) ? 'rtl' : 'ltr'; + }), + ); + } +} diff --git a/packages/admin-ui/src/lib/core/src/shared/components/dropdown/dropdown-menu.component.ts b/packages/admin-ui/src/lib/core/src/shared/components/dropdown/dropdown-menu.component.ts index 25b37db1f5..80f190f0be 100644 --- a/packages/admin-ui/src/lib/core/src/shared/components/dropdown/dropdown-menu.component.ts +++ b/packages/admin-ui/src/lib/core/src/shared/components/dropdown/dropdown-menu.component.ts @@ -1,18 +1,9 @@ -import { - ConnectedPosition, - HorizontalConnectionPos, - Overlay, - OverlayRef, - PositionStrategy, - VerticalConnectionPos, -} from '@angular/cdk/overlay'; +import { ConnectedPosition, Overlay, OverlayRef, PositionStrategy } from '@angular/cdk/overlay'; import { TemplatePortal } from '@angular/cdk/portal'; import { AfterViewInit, ChangeDetectionStrategy, Component, - ContentChild, - ElementRef, HostListener, Input, OnDestroy, @@ -23,7 +14,10 @@ import { } from '@angular/core'; import { Subscription } from 'rxjs'; -import { DropdownTriggerDirective } from './dropdown-trigger.directive'; +import { + LocalizationDirectionType, + LocalizationService, +} from '../../../providers/localization/localization.service'; import { DropdownComponent } from './dropdown.component'; export type DropdownPosition = 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right'; @@ -41,14 +35,16 @@ export type DropdownPosition = 'top-left' | 'top-right' | 'bottom-left' | 'botto selector: 'vdr-dropdown-menu', template: ` -