diff --git a/modules/ui/src/app/app.component.html b/modules/ui/src/app/app.component.html index 2420bec59..c5b5a7e97 100644 --- a/modules/ui/src/app/app.component.html +++ b/modules/ui/src/app/app.component.html @@ -18,6 +18,7 @@ + { expect(sideBar).toBeDefined(); }); - it('should render menu button', () => { - const button = compiled.querySelector('.app-sidebar-button-menu'); + it('should render side button menu', () => { + const sideButtonMenu = compiled.querySelector('app-side-button-menu'); - expect(button).toBeDefined(); + expect(sideButtonMenu).toBeDefined(); }); it('should render runtime button', () => { diff --git a/modules/ui/src/app/app.component.ts b/modules/ui/src/app/app.component.ts index 803dd2731..75d27acdb 100644 --- a/modules/ui/src/app/app.component.ts +++ b/modules/ui/src/app/app.component.ts @@ -29,9 +29,9 @@ import { NavigationEnd, Router, RouterModule } from '@angular/router'; import { CalloutType } from './model/callout-type'; import { Routes } from './model/routes'; import { FocusManagerService } from './services/focus-manager.service'; -import { State, Store } from '@ngrx/store'; +import { Store } from '@ngrx/store'; import { AppState } from './store/state'; -import { setIsOpenAddDevice } from './store/actions'; +import { setIsOpenAddDevice, setIsOpenProfile } from './store/actions'; import { AppStore } from './app.store'; import { TestRunService } from './services/test-run.service'; import { filter, take } from 'rxjs/operators'; @@ -54,6 +54,18 @@ import { MatRadioModule } from '@angular/material/radio'; import { CalloutComponent } from './components/callout/callout.component'; import { ReactiveFormsModule } from '@angular/forms'; import { CommonModule } from '@angular/common'; +import { SideButtonMenuComponent } from './components/side-button-menu/side-button-menu.component'; +import { Observable } from 'rxjs/internal/Observable'; +import { of } from 'rxjs/internal/observable/of'; + +export interface AddMenuItem { + icon?: string; + svgIcon?: string; + label: string; + description?: string; + onClick: () => void; + disabled$: Observable; +} const DEVICES_RUN_URL = '/assets/icons/device_run.svg'; const TESTRUN_LOGO_URL = '/assets/icons/testrun_logo_small.svg'; @@ -89,6 +101,7 @@ const QUALIFICATION_URL = '/assets/icons/qualification.svg'; TestingCompleteComponent, RouterModule, CommonModule, + SideButtonMenuComponent, ], providers: [AppStore], }) @@ -97,7 +110,6 @@ export class AppComponent implements AfterViewInit { private domSanitizer = inject(DomSanitizer); private route = inject(Router); private store = inject>(Store); - private state = inject>(State); private readonly focusManagerService = inject(FocusManagerService); private testRunService = inject(TestRunService); appStore = inject(AppStore); @@ -105,13 +117,48 @@ export class AppComponent implements AfterViewInit { public readonly CalloutType = CalloutType; public readonly StatusOfTestrun = StatusOfTestrun; public readonly Routes = Routes; - readonly toggleSettingsBtn = - viewChild.required('toggleSettingsBtn'); viewModel$ = this.appStore.viewModel$; readonly riskAssessmentLink = viewChild('riskAssessmentLink'); private skipCount = 0; + navigateToRuntime = () => { + this.route.navigate([Routes.Testing]); + this.appStore.setIsOpenStartTestrun(); + }; + + navigateToAddDevice = () => { + this.route.navigate([Routes.Devices]); + this.store.dispatch(setIsOpenAddDevice({ isOpenAddDevice: true })); + }; + + navigateToAddRiskAssessment = () => { + this.route.navigate([Routes.RiskAssessment]); + this.store.dispatch(setIsOpenProfile({ isOpenCreateProfile: true })); + }; + + menuItems: AddMenuItem[] = [ + { + svgIcon: 'testrun_logo_small', + label: 'Create new Testrun', + description: 'Configure your testing tasks', + onClick: this.navigateToRuntime, + disabled$: this.appStore.testrunButtonDisabled$, + }, + { + icon: 'home_iot_device', + label: 'Create new device', + onClick: this.navigateToAddDevice, + disabled$: of(false), + }, + { + icon: 'rule', + label: 'Create new profile', + onClick: this.navigateToAddRiskAssessment, + disabled$: of(false), + }, + ]; + constructor() { this.appStore.getDevices(); this.appStore.getRiskProfiles(); @@ -183,15 +230,6 @@ export class AppComponent implements AfterViewInit { navigateToDeviceRepository(): void { this.route.navigate([Routes.Devices]); } - navigateToAddDevice(): void { - this.route.navigate([Routes.Devices]); - this.store.dispatch(setIsOpenAddDevice({ isOpenAddDevice: true })); - } - - navigateToRuntime(): void { - this.route.navigate([Routes.Testing]); - this.appStore.setIsOpenStartTestrun(); - } navigateToRiskAssessment(): void { this.route.navigate([Routes.RiskAssessment]).then(() => { diff --git a/modules/ui/src/app/app.store.ts b/modules/ui/src/app/app.store.ts index 87f757697..c27584d01 100644 --- a/modules/ui/src/app/app.store.ts +++ b/modules/ui/src/app/app.store.ts @@ -66,6 +66,7 @@ import { FocusManagerService } from './services/focus-manager.service'; import { TestRunMqttService } from './services/test-run-mqtt.service'; import { NotificationService } from './services/notification.service'; import { Profile } from './model/profile'; +import { map } from 'rxjs/internal/operators/map'; export const CONSENT_SHOWN_KEY = 'CONSENT_SHOWN'; export const CALLOUT_STATE_KEY = 'CALLOUT_STATE'; @@ -110,6 +111,33 @@ export class AppStore extends ComponentStore { ); riskProfiles$: Observable = this.store.select(selectRiskProfiles); + testrunButtonDisabled$ = combineLatest([ + this.hasDevices$, + this.isAllDevicesOutdated$, + this.isStatusLoaded$, + this.systemStatus$, + this.hasConnectionSetting$, + ]).pipe( + map( + ([ + hasDevices, + isAllDevicesOutdated, + isStatusLoaded, + systemStatus, + hasConnectionSettings, + ]) => { + return !( + hasConnectionSettings === true && + hasDevices && + (!systemStatus || + !this.testRunService.testrunInProgress(systemStatus)) && + isStatusLoaded === true && + !isAllDevicesOutdated + ); + } + ) + ); + viewModel$ = this.select({ consentShown: this.consentShown$, hasDevices: this.hasDevices$, diff --git a/modules/ui/src/app/components/list-item/list-item.component.scss b/modules/ui/src/app/components/list-item/list-item.component.scss index 3b6c55b5e..ae8fcb418 100644 --- a/modules/ui/src/app/components/list-item/list-item.component.scss +++ b/modules/ui/src/app/components/list-item/list-item.component.scss @@ -17,23 +17,6 @@ @use 'colors'; @use '@angular/material' as mat; -// Customize the entire app. Change :root to your selector if you want to scope the styles. -::ng-deep :root { - @include mat.menu-overrides( - ( - item-label-text-color: colors.$on-surface, - item-icon-color: colors.$on-surface-variant, - container-color: colors.$surface, - item-label-text-weight: 400, - item-label-text-size: 16px, - item-label-text-font: variables.$font-text, - item-hover-state-layer-color: colors.$secondary-container, - item-with-icon-leading-spacing: 24px, - item-with-icon-trailing-spacing: 24px, - ) - ); -} - ::ng-deep { .list-item-menu { width: 220px; diff --git a/modules/ui/src/app/components/side-button-menu/side-button-menu.component.html b/modules/ui/src/app/components/side-button-menu/side-button-menu.component.html new file mode 100644 index 000000000..dee4936cd --- /dev/null +++ b/modules/ui/src/app/components/side-button-menu/side-button-menu.component.html @@ -0,0 +1,67 @@ + + + add + + + + + + + + + + + + + + + + + {{ icon }} + {{ label }} + + {{ description }} + + + diff --git a/modules/ui/src/app/components/side-button-menu/side-button-menu.component.scss b/modules/ui/src/app/components/side-button-menu/side-button-menu.component.scss new file mode 100644 index 000000000..2e73d07b1 --- /dev/null +++ b/modules/ui/src/app/components/side-button-menu/side-button-menu.component.scss @@ -0,0 +1,66 @@ +@use 'colors'; +@use 'variables'; +@use '@angular/material' as mat; + +:host { + display: flex; + justify-content: center; + width: 100%; +} + +.side-add-button-container { + position: relative; +} + +.side-add-menu-trigger { + position: absolute; + top: 0; + right: -20px; +} + +.side-add-menu-triangle { + position: absolute; + top: 18px; + left: -12px; +} + +::ng-deep .side-add-menu { + overflow: visible !important; + width: 278px; + border-radius: 4px; + padding: 0 8px; +} + +.side-add-button { + --mdc-fab-container-color: #{colors.$primary-container}; + --mat-icon-color: #{colors.$primary}; +} + +.side-add-menu-button { + gap: 12px; + border-radius: 4px; + width: 100%; + height: 56px; + display: grid; + background: inherit; + grid-template-columns: min-content auto; +} + +.side-add-menu-button-description { + color: colors.$on-surface-variant; + font-family: variables.$font-text; + font-size: 12px; + font-style: normal; + font-weight: 400; + line-height: 16px; + letter-spacing: 0.1px; +} + +.side-add-menu-button-label { + color: colors.$on-surface; + font-family: variables.$font-text; + font-size: 16px; + font-style: normal; + font-weight: 400; + line-height: 24px; +} diff --git a/modules/ui/src/app/components/side-button-menu/side-button-menu.component.spec.ts b/modules/ui/src/app/components/side-button-menu/side-button-menu.component.spec.ts new file mode 100644 index 000000000..8d261de57 --- /dev/null +++ b/modules/ui/src/app/components/side-button-menu/side-button-menu.component.spec.ts @@ -0,0 +1,105 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { MatMenuModule } from '@angular/material/menu'; +import { MatButtonModule } from '@angular/material/button'; +import { MatIconModule } from '@angular/material/icon'; +import { By } from '@angular/platform-browser'; +import { of } from 'rxjs'; +import { SideButtonMenuComponent } from './side-button-menu.component'; +import { + MatMenuHarness, + MatMenuItemHarness, +} from '@angular/material/menu/testing'; +import { HarnessLoader } from '@angular/cdk/testing'; +import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed'; + +describe('SideButtonMenuComponent', () => { + let component: SideButtonMenuComponent; + let fixture: ComponentFixture; + let loader: HarnessLoader; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ + SideButtonMenuComponent, + MatMenuModule, + MatButtonModule, + MatIconModule, + ], + }).compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(SideButtonMenuComponent); + component = fixture.componentInstance; + loader = TestbedHarnessEnvironment.loader(fixture); + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + it('should render menu button', () => { + const button = fixture.debugElement.query(By.css('.side-add-button')); + expect(button).toBeTruthy(); + }); + + describe('menu', () => { + let menu; + let items: MatMenuItemHarness[]; + const onClickSpy = jasmine.createSpy('onClick'); + + beforeEach(async () => { + fixture.componentRef.setInput('menuItems', [ + { + icon: 'home', + label: 'Home', + onClick: () => {}, + disabled$: of(true), + }, + { + icon: 'settings', + label: 'Settings', + description: 'Settings description', + onClick: onClickSpy, + disabled$: of(false), + }, + ]); + fixture.detectChanges(); + + menu = await loader.getHarness(MatMenuHarness); + await menu.open(); + items = await menu.getItems(); + }); + + it('should render menu items', async () => { + expect(items.length).toBe(2); + + const text0 = await items[0].getText(); + const text1 = await items[1].getText(); + + expect(text0).toContain('Home'); + expect(text1).toContain('Settings'); + expect(text1).toContain('Settings description'); + }); + + it('should emit the correct action when a menu item is clicked', async () => { + await items[1].click(); + + expect(onClickSpy).toHaveBeenCalled(); + }); + + it('should display the correct icons for actions', async () => { + const text0 = await items[0].getText(); + const text1 = await items[1].getText(); + + expect(text0).toContain('home'); + expect(text1).toContain('settings'); + }); + + it('should disable menu item when observable emits true', async () => { + const disabled = await items[0].isDisabled(); + expect(disabled).toBeTrue(); + }); + }); +}); diff --git a/modules/ui/src/app/components/side-button-menu/side-button-menu.component.ts b/modules/ui/src/app/components/side-button-menu/side-button-menu.component.ts new file mode 100644 index 000000000..5a5f4468d --- /dev/null +++ b/modules/ui/src/app/components/side-button-menu/side-button-menu.component.ts @@ -0,0 +1,16 @@ +import { Component, input } from '@angular/core'; +import { MatButtonModule } from '@angular/material/button'; +import { MatIconModule } from '@angular/material/icon'; +import { MatMenuModule } from '@angular/material/menu'; +import { CommonModule } from '@angular/common'; +import { AddMenuItem } from '../../app.component'; + +@Component({ + selector: 'app-side-button-menu', + imports: [MatButtonModule, MatIconModule, MatMenuModule, CommonModule], + templateUrl: './side-button-menu.component.html', + styleUrl: './side-button-menu.component.scss', +}) +export class SideButtonMenuComponent { + menuItems = input([]); +} diff --git a/modules/ui/src/app/pages/devices/devices.component.spec.ts b/modules/ui/src/app/pages/devices/devices.component.spec.ts index 4b8d45538..f693d8103 100644 --- a/modules/ui/src/app/pages/devices/devices.component.spec.ts +++ b/modules/ui/src/app/pages/devices/devices.component.spec.ts @@ -59,6 +59,7 @@ describe('DevicesComponent', () => { 'getTestModules', 'deleteDevice', ]); + mockDevicesStore.isOpenAddDevice$ = of(false); await TestBed.configureTestingModule({ imports: [ diff --git a/modules/ui/src/app/pages/devices/devices.component.ts b/modules/ui/src/app/pages/devices/devices.component.ts index 9b0a9bb49..793076e38 100644 --- a/modules/ui/src/app/pages/devices/devices.component.ts +++ b/modules/ui/src/app/pages/devices/devices.component.ts @@ -26,14 +26,12 @@ import { MatDialog, MatDialogModule } from '@angular/material/dialog'; import { Device, DeviceAction, - DeviceStatus, DeviceView, TestModule, } from '../../model/device'; import { LayoutType } from '../../model/layout-type'; import { Subject, takeUntil, timer } from 'rxjs'; import { SimpleDialogComponent } from '../../components/simple-dialog/simple-dialog.component'; -import { combineLatest } from 'rxjs/internal/observable/combineLatest'; import { FocusManagerService } from '../../services/focus-manager.service'; import { Routes } from '../../model/routes'; import { Router } from '@angular/router'; @@ -107,17 +105,10 @@ export class DevicesComponent } ngOnInit(): void { - combineLatest([ - this.devicesStore.devices$, - this.devicesStore.isOpenAddDevice$, - ]) + this.devicesStore.isOpenAddDevice$ .pipe(takeUntil(this.destroy$)) - .subscribe(([devices, isOpenAddDevice]) => { - if ( - !devices?.filter(device => device.status === DeviceStatus.VALID) - .length && - isOpenAddDevice - ) { + .subscribe(isOpenAddDevice => { + if (isOpenAddDevice) { this.openForm(); } }); diff --git a/modules/ui/src/app/pages/risk-assessment/risk-assessment.component.spec.ts b/modules/ui/src/app/pages/risk-assessment/risk-assessment.component.spec.ts index 98169ed45..3ae05d261 100644 --- a/modules/ui/src/app/pages/risk-assessment/risk-assessment.component.spec.ts +++ b/modules/ui/src/app/pages/risk-assessment/risk-assessment.component.spec.ts @@ -71,8 +71,12 @@ describe('RiskAssessmentComponent', () => { 'setFocusOnProfileForm', 'updateProfiles', 'removeProfile', + 'isOpenCreateProfile$', + 'profileFormat$', ]); + mockRiskAssessmentStore.profileFormat$ = of([]); + await TestBed.configureTestingModule({ declarations: [FakeProfileItemComponent, FakeProfileFormComponent], imports: [ @@ -107,6 +111,14 @@ describe('RiskAssessmentComponent', () => { expect(component).toBeTruthy(); }); + it('should open form if isOpenAddDevice$ as true', () => { + mockRiskAssessmentStore.profileFormat$ = of([], []); + mockRiskAssessmentStore.isOpenCreateProfile$ = of(true); + component.ngOnInit(); + + expect(component.isOpenProfileForm).toBeTrue(); + }); + describe('with no profiles data', () => { beforeEach(() => { component.viewModel$ = of({ diff --git a/modules/ui/src/app/pages/risk-assessment/risk-assessment.component.ts b/modules/ui/src/app/pages/risk-assessment/risk-assessment.component.ts index 5853ed0c9..a100215ab 100644 --- a/modules/ui/src/app/pages/risk-assessment/risk-assessment.component.ts +++ b/modules/ui/src/app/pages/risk-assessment/risk-assessment.component.ts @@ -26,11 +26,10 @@ import { } from '@angular/core'; import { RiskAssessmentStore } from './risk-assessment.store'; import { SimpleDialogComponent } from '../../components/simple-dialog/simple-dialog.component'; -import { Subject, takeUntil, timer } from 'rxjs'; +import { Subject, takeUntil, timer, Observable } from 'rxjs'; import { MatDialog } from '@angular/material/dialog'; import { LiveAnnouncer } from '@angular/cdk/a11y'; import { Profile, ProfileAction, ProfileStatus } from '../../model/profile'; -import { Observable } from 'rxjs/internal/Observable'; import { DeviceValidators } from '../devices/components/device-form/device.validators'; import { SuccessDialogComponent } from './components/success-dialog/success-dialog.component'; import { MatToolbarModule } from '@angular/material/toolbar'; @@ -51,8 +50,8 @@ import { ListLayoutComponent } from '../../components/list-layout/list-layout.co import { LayoutType } from '../../model/layout-type'; import { NoEntitySelectedComponent } from '../../components/no-entity-selected/no-entity-selected.component'; import { EntityAction, EntityActionResult } from '../../model/entity-action'; -import { of } from 'rxjs/internal/observable/of'; import { CanComponentDeactivate } from '../../guards/can-deactivate.guard'; +import { of, combineLatest, skip } from 'rxjs'; const matFormFieldDefaultOptions: MatFormFieldDefaultOptions = { hideRequiredMarker: true, @@ -114,6 +113,17 @@ export class RiskAssessmentComponent ngOnInit() { this.store.getProfilesFormat(); + + combineLatest([ + this.store.isOpenCreateProfile$, + this.store.profileFormat$.pipe(skip(1)), + ]) + .pipe(takeUntil(this.destroy$)) + .subscribe(([isOpenCreateProfile]) => { + if (isOpenCreateProfile) { + this.openForm(); + } + }); } ngOnDestroy() { diff --git a/modules/ui/src/app/pages/risk-assessment/risk-assessment.store.ts b/modules/ui/src/app/pages/risk-assessment/risk-assessment.store.ts index f55ed231e..0e1a35bd1 100644 --- a/modules/ui/src/app/pages/risk-assessment/risk-assessment.store.ts +++ b/modules/ui/src/app/pages/risk-assessment/risk-assessment.store.ts @@ -23,7 +23,10 @@ import { Profile, ProfileAction, ProfileFormat } from '../../model/profile'; import { FocusManagerService } from '../../services/focus-manager.service'; import { Store } from '@ngrx/store'; import { AppState } from '../../store/state'; -import { selectRiskProfiles } from '../../store/selectors'; +import { + selectIsOpenCreateProfile, + selectRiskProfiles, +} from '../../store/selectors'; import { setRiskProfiles } from '../../store/actions'; import { EntityAction } from '../../model/entity-action'; @@ -43,7 +46,7 @@ export class RiskAssessmentStore extends ComponentStore { profileFormat$ = this.select(state => state.profileFormat); selectedProfile$ = this.select(state => state.selectedProfile); actions$ = this.select(state => state.actions); - + isOpenCreateProfile$ = this.store.select(selectIsOpenCreateProfile); viewModel$ = this.select({ profiles: this.profiles$, profileFormat: this.profileFormat$, diff --git a/modules/ui/src/app/pages/testrun/testrun.component.ts b/modules/ui/src/app/pages/testrun/testrun.component.ts index 3c1ffd1d8..db5e79a9e 100644 --- a/modules/ui/src/app/pages/testrun/testrun.component.ts +++ b/modules/ui/src/app/pages/testrun/testrun.component.ts @@ -34,7 +34,6 @@ import { LOADER_TIMEOUT_CONFIG_TOKEN } from '../../services/loaderConfig'; import { FocusManagerService } from '../../services/focus-manager.service'; import { TestrunStore } from './testrun.store'; import { TestRunService } from '../../services/test-run.service'; -import { NotificationService } from '../../services/notification.service'; import { TestModule } from '../../model/device'; import { combineLatest } from 'rxjs/internal/observable/combineLatest'; import { CommonModule } from '@angular/common'; @@ -79,7 +78,6 @@ import { TestrunStatusCardComponent } from './components/testrun-status-card/tes export class TestrunComponent implements OnInit, OnDestroy { isOpenDownloadOptions: boolean = false; private readonly testRunService = inject(TestRunService); - private readonly notificationService = inject(NotificationService); dialog = inject(MatDialog); private readonly focusManagerService = inject(FocusManagerService); testrunStore = inject(TestrunStore); diff --git a/modules/ui/src/app/store/actions.ts b/modules/ui/src/app/store/actions.ts index 5a290109b..8ababc915 100644 --- a/modules/ui/src/app/store/actions.ts +++ b/modules/ui/src/app/store/actions.ts @@ -146,3 +146,8 @@ export const updateInternetConnection = createAction( export const fetchInterfaces = createAction('[Shared] Fetch interfaces'); export const fetchSystemConfig = createAction('[Shared] Fetch system config'); + +export const setIsOpenProfile = createAction( + '[Shared] Set Is Open Profile', + props<{ isOpenCreateProfile: boolean }>() +); diff --git a/modules/ui/src/app/store/reducers.ts b/modules/ui/src/app/store/reducers.ts index e51fde1b7..82f45dc60 100644 --- a/modules/ui/src/app/store/reducers.ts +++ b/modules/ui/src/app/store/reducers.ts @@ -136,7 +136,13 @@ export const sharedReducer = createReducer( on(Actions.fetchSystemConfigSuccess, (state, { systemConfig }) => ({ ...state, systemConfig, - })) + })), + on(Actions.setIsOpenProfile, (state, { isOpenCreateProfile }) => { + return { + ...state, + isOpenCreateProfile, + }; + }) ); export const rootReducer = sharedReducer; diff --git a/modules/ui/src/app/store/selectors.spec.ts b/modules/ui/src/app/store/selectors.spec.ts index ba6a52315..0e55184c5 100644 --- a/modules/ui/src/app/store/selectors.spec.ts +++ b/modules/ui/src/app/store/selectors.spec.ts @@ -61,6 +61,7 @@ describe('Selectors', () => { internetConnection: null, interfaces: {}, systemConfig: { network: {} }, + isOpenCreateProfile: false, }; it('should select interfaces', () => { diff --git a/modules/ui/src/app/store/selectors.ts b/modules/ui/src/app/store/selectors.ts index 2a3fb0ed9..cee4705b0 100644 --- a/modules/ui/src/app/store/selectors.ts +++ b/modules/ui/src/app/store/selectors.ts @@ -122,3 +122,8 @@ export const selectSystemConfig = createSelector( selectAppState, (state: AppState) => state.systemConfig ); + +export const selectIsOpenCreateProfile = createSelector( + selectAppState, + (state: AppState) => state.isOpenCreateProfile +); diff --git a/modules/ui/src/app/store/state.ts b/modules/ui/src/app/store/state.ts index 2ce978b6f..10de8165f 100644 --- a/modules/ui/src/app/store/state.ts +++ b/modules/ui/src/app/store/state.ts @@ -47,6 +47,7 @@ export interface AppState { testModules: TestModule[]; adapters: Adapters; internetConnection: boolean | null; + isOpenCreateProfile: boolean; } export const initialState: AppState = { @@ -71,4 +72,5 @@ export const initialState: AppState = { internetConnection: null, interfaces: {}, systemConfig: { network: {} }, + isOpenCreateProfile: false, }; diff --git a/modules/ui/src/styles.scss b/modules/ui/src/styles.scss index 6a19a3187..26cfd792e 100644 --- a/modules/ui/src/styles.scss +++ b/modules/ui/src/styles.scss @@ -64,6 +64,20 @@ color: colors.$outline-variant, ) ); + + @include mat.menu-overrides( + ( + item-label-text-color: colors.$on-surface, + item-icon-color: colors.$on-surface-variant, + container-color: colors.$surface, + item-label-text-weight: 400, + item-label-text-size: 16px, + item-label-text-font: variables.$font-text, + item-hover-state-layer-color: colors.$secondary-container, + item-with-icon-leading-spacing: 24px, + item-with-icon-trailing-spacing: 24px, + ) + ); } .consent-dialog { @@ -534,3 +548,11 @@ button:not(.mat-mdc-button-disabled) { .mat-mdc-snackbar-surface { padding-right: 0 !important; } + +.side-add-menu { + @include mat.menu-overrides( + ( + item-hover-state-layer-color: rgba(31, 31, 31, 0.08), + ) + ); +}