diff --git a/src/assets/layout/_topbar.scss b/src/assets/layout/_topbar.scss index f80e275..f5d239c 100644 --- a/src/assets/layout/_topbar.scss +++ b/src/assets/layout/_topbar.scss @@ -158,45 +158,3 @@ } } } - -.config-panel { - .config-panel-label { - font-size: 0.875rem; - color: var(--text-secondary-color); - font-weight: 600; - line-height: 1; - } - - .config-panel-colors { - > div { - padding-top: 0.5rem; - display: flex; - gap: 0.5rem; - flex-wrap: wrap; - justify-content: space-between; - - button { - border: none; - width: 1.25rem; - height: 1.25rem; - border-radius: 50%; - padding: 0; - cursor: pointer; - outline-color: transparent; - outline-width: 2px; - outline-style: solid; - outline-offset: 1px; - - &.active-color { - outline-color: var(--primary-color); - } - } - } - } - - .config-panel-settings { - display: flex; - flex-direction: column; - gap: 0.5rem; - } -} diff --git a/src/components/floatingconfigurator.ts b/src/components/floatingconfigurator.ts index 1f36b0d..547abab 100644 --- a/src/components/floatingconfigurator.ts +++ b/src/components/floatingconfigurator.ts @@ -8,7 +8,7 @@ import { LayoutService } from '@/src/service/layout/layout.service'; selector: 'floating-configurator', imports: [ButtonModule, StyleClassModule, AppConfigurator], template: ` -
+
-
- Primary -
- @for (primaryColor of primaryColors(); track primaryColor.name) { - - } -
-
-
- Surface -
- @for (surface of surfaces; track surface.name) { - - } -
-
-
- Presets - -
-
- Menu Mode - +
+
+ Primary +
+ @for (primaryColor of primaryColors(); track primaryColor.name) { + + }
+
+ Surface +
+ @for (surface of surfaces; track surface.name) { + + } +
+
+
+ Presets + +
+
+ Menu Mode + +
+
`, host: { - class: 'hidden absolute top-[3.25rem] right-0 w-64 p-4 bg-surface-0 dark:bg-surface-900 border border-surface rounded-border origin-top shadow-[0px_3px_5px_rgba(0,0,0,0.02),0px_0px_2px_rgba(0,0,0,0.05),0px_1px_4px_rgba(0,0,0,0.08)]', + class: 'hidden absolute top-[3.25rem] right-0 w-64 p-4 bg-surface-0 dark:bg-surface-900 border border-surface rounded-border origin-top shadow-[0px_3px_5px_rgba(0,0,0,0.02),0px_0px_2px_rgba(0,0,0,0.05),0px_1px_4px_rgba(0,0,0,0.08)]' } }) export class AppConfigurator { diff --git a/src/layout/applayout.ts b/src/layout/applayout.ts index 92a7130..f8e88f0 100644 --- a/src/layout/applayout.ts +++ b/src/layout/applayout.ts @@ -4,21 +4,15 @@ import { CommonModule } from '@angular/common'; import { AppTopBar } from '@/src/layout/apptopbar'; import { AppSidebar } from '@/src/layout/appsidebar'; import { NavigationEnd, Router, RouterModule } from '@angular/router'; +import { AppConfigurator } from '@/src/layout/appconfigurator'; import { AppFooter } from '@/src/layout/appfooter'; import { filter, Subscription } from 'rxjs'; import { LayoutService } from '@/src/service/layout/layout.service'; @Component({ selector: 'app-layout', - standalone:true, - imports: [ - CommonModule, - ToastModule, - AppTopBar, - AppSidebar, - RouterModule, - AppFooter, - ], + standalone: true, + imports: [CommonModule, ToastModule, AppTopBar, AppSidebar, RouterModule, AppFooter, AppConfigurator], template: `
@@ -30,9 +24,9 @@ import { LayoutService } from '@/src/service/layout/layout.service';
+
-
- `, +
` }) export class AppLayout { overlayMenuOpenSubscription: Subscription; @@ -45,23 +39,28 @@ export class AppLayout { @ViewChild(AppTopBar) appTopBar!: AppTopBar; - constructor(public layoutService: LayoutService, public renderer: Renderer2, public router: Router) { + constructor( + public layoutService: LayoutService, + public renderer: Renderer2, + public router: Router + ) { this.overlayMenuOpenSubscription = this.layoutService.overlayOpen$.subscribe(() => { if (!this.menuOutsideClickListener) { - this.menuOutsideClickListener = this.renderer.listen('document', 'click', event => { - const isOutsideClicked = !(this.appSidebar.el.nativeElement.isSameNode(event.target) || this.appSidebar.el.nativeElement.contains(event.target) - || this.appTopBar.menuButton.nativeElement.isSameNode(event.target) || this.appTopBar.menuButton.nativeElement.contains(event.target)); - - if (isOutsideClicked) { + this.menuOutsideClickListener = this.renderer.listen('document', 'click', (event) => { + if (this.isOutsideClicked(event)) { this.hideMenu(); } }); } if (!this.profileMenuOutsideClickListener) { - this.profileMenuOutsideClickListener = this.renderer.listen('document', 'click', event => { - const isOutsideClicked = !(this.appTopBar.menu.nativeElement.isSameNode(event.target) || this.appTopBar.menu.nativeElement.contains(event.target) - || this.appTopBar.topbarMenuButton.nativeElement.isSameNode(event.target) || this.appTopBar.topbarMenuButton.nativeElement.contains(event.target)); + this.profileMenuOutsideClickListener = this.renderer.listen('document', 'click', (event) => { + const isOutsideClicked = !( + this.appTopBar.menu.nativeElement.isSameNode(event.target) || + this.appTopBar.menu.nativeElement.contains(event.target) || + this.appTopBar.topbarMenuButton.nativeElement.isSameNode(event.target) || + this.appTopBar.topbarMenuButton.nativeElement.contains(event.target) + ); if (isOutsideClicked) { } @@ -73,14 +72,20 @@ export class AppLayout { } }); - this.router.events.pipe(filter(event => event instanceof NavigationEnd)) - .subscribe(() => { - this.hideMenu(); - }); + this.router.events.pipe(filter((event) => event instanceof NavigationEnd)).subscribe(() => { + this.hideMenu(); + }); + } + + isOutsideClicked(event) { + const sidebarEl = document.querySelector('.layout-sidebar'); + const topbarEl = document.querySelector('.layout-menu-button'); + + return !(sidebarEl.isSameNode(event.target) || sidebarEl.contains(event.target) || topbarEl.isSameNode(event.target) || topbarEl.contains(event.target)); } hideMenu() { - this.layoutService.layoutState.update((prev) => ({...prev, overlayMenuActive:false, staticMenuMobileActive: false, menuHoverActive: false})) + this.layoutService.layoutState.update((prev) => ({ ...prev, overlayMenuActive: false, staticMenuMobileActive: false, menuHoverActive: false })); if (this.menuOutsideClickListener) { this.menuOutsideClickListener(); this.menuOutsideClickListener = null; @@ -91,8 +96,7 @@ export class AppLayout { blockBodyScroll(): void { if (document.body.classList) { document.body.classList.add('blocked-scroll'); - } - else { + } else { document.body.className += ' blocked-scroll'; } } @@ -100,10 +104,8 @@ export class AppLayout { unblockBodyScroll(): void { if (document.body.classList) { document.body.classList.remove('blocked-scroll'); - } - else { - document.body.className = document.body.className.replace(new RegExp('(^|\\b)' + - 'blocked-scroll'.split(' ').join('|') + '(\\b|$)', 'gi'), ' '); + } else { + document.body.className = document.body.className.replace(new RegExp('(^|\\b)' + 'blocked-scroll'.split(' ').join('|') + '(\\b|$)', 'gi'), ' '); } } @@ -114,7 +116,7 @@ export class AppLayout { 'layout-static-inactive': this.layoutService.layoutState().staticMenuDesktopInactive && this.layoutService.layoutConfig().menuMode === 'static', 'layout-overlay-active': this.layoutService.layoutState().overlayMenuActive, 'layout-mobile-active': this.layoutService.layoutState().staticMenuMobileActive - } + }; } ngOnDestroy() { diff --git a/src/service/layout/layout.service.ts b/src/service/layout/layout.service.ts index 32e16a8..26c7fd3 100644 --- a/src/service/layout/layout.service.ts +++ b/src/service/layout/layout.service.ts @@ -2,7 +2,7 @@ import { Injectable, effect, signal, computed } from '@angular/core'; import { Subject } from 'rxjs'; export interface layoutConfig { - preset?: string, + preset?: string; primary?: string; surface?: string; darkTheme?: boolean; @@ -23,7 +23,7 @@ interface MenuChangeEvent { } @Injectable({ - providedIn: 'root', + providedIn: 'root' }) export class LayoutService { _config: layoutConfig = { @@ -39,12 +39,12 @@ export class LayoutService { overlayMenuActive: false, configSidebarVisible: false, staticMenuMobileActive: false, - menuHoverActive: false, + menuHoverActive: false }; layoutConfig = signal(this._config); - layoutState = signal(this._state) + layoutState = signal(this._state); private configUpdate = new Subject(); @@ -62,7 +62,7 @@ export class LayoutService { overlayOpen$ = this.overlayOpen.asObservable(); - theme = computed(() => this.layoutConfig()?.darkTheme ? 'light' : 'dark'); + theme = computed(() => (this.layoutConfig()?.darkTheme ? 'light' : 'dark')); isSidebarActive = computed(() => this.layoutState().overlayMenuActive || this.layoutState().staticMenuMobileActive); @@ -72,7 +72,7 @@ export class LayoutService { getSurface = computed(() => this.layoutConfig().surface); - isOverlay = computed(() => this.layoutConfig().menuMode === 'overlay') + isOverlay = computed(() => this.layoutConfig().menuMode === 'overlay'); transitionComplete = signal(false); @@ -81,7 +81,7 @@ export class LayoutService { constructor() { effect(() => { const config = this.layoutConfig(); - if(config) { + if (config) { this.onConfigUpdate(); } }); @@ -95,7 +95,7 @@ export class LayoutService { } this.handleDarkModeTransition(config); - }) + }); } private handleDarkModeTransition(config: layoutConfig): void { @@ -112,11 +112,15 @@ export class LayoutService { this.toggleDarkMode(config); }); - transition.ready.then(() => this.onTransitionEnd()); + transition.ready + .then(() => { + this.onTransitionEnd(); + }) + .catch(() => {}); } toggleDarkMode(config?: layoutConfig): void { - const _config = config || this.layoutConfig() + const _config = config || this.layoutConfig(); if (_config.darkTheme) { document.documentElement.classList.add('app-dark'); } else { @@ -131,10 +135,9 @@ export class LayoutService { }); } - onMenuToggle() { if (this.isOverlay()) { - this.layoutState.update((prev) => ({...prev, overlayMenuActive: !this.layoutState().overlayMenuActive})); + this.layoutState.update((prev) => ({ ...prev, overlayMenuActive: !this.layoutState().overlayMenuActive })); if (this.layoutState().overlayMenuActive) { this.overlayOpen.next(null); @@ -142,9 +145,9 @@ export class LayoutService { } if (this.isDesktop()) { - this.layoutState.update((prev) => ({...prev, staticMenuDesktopInactive: !this.layoutState().staticMenuDesktopInactive})); + this.layoutState.update((prev) => ({ ...prev, staticMenuDesktopInactive: !this.layoutState().staticMenuDesktopInactive })); } else { - this.layoutState.update((prev) => ({...prev, staticMenuMobileActive: !this.layoutState().staticMenuMobileActive})); + this.layoutState.update((prev) => ({ ...prev, staticMenuMobileActive: !this.layoutState().staticMenuMobileActive })); if (this.layoutState().staticMenuMobileActive) { this.overlayOpen.next(null); diff --git a/src/views/uikit/miscdoc.ts b/src/views/uikit/miscdoc.ts index 236060c..16b77b5 100644 --- a/src/views/uikit/miscdoc.ts +++ b/src/views/uikit/miscdoc.ts @@ -100,7 +100,6 @@ import { OverlayBadgeModule } from 'primeng/overlaybadge'; etiam sit amet nisl purus. Cursus sit amet dictum sit amet. Tristique senectus et netus et malesuada fames ac turpis egestas. Et tortor consequat id porta nibh venenatis cras sed. Diam maecenas ultricies mi eget mauris. Eget egestas purus viverra accumsan in nisl nisi. Suscipit adipiscing bibendum est ultricies integer. Mattis aliquam faucibus purus in massa tempor nec.

-