Refactor appConfig component, update layoutService and implement Angular signals
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "sakai-ng",
|
"name": "sakai-ng",
|
||||||
"version": "17.0.0",
|
"version": "17.2.0",
|
||||||
"license": "PrimeNG Commercial",
|
"license": "PrimeNG Commercial",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"ng": "ng",
|
"ng": "ng",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<div class="surface-ground flex align-items-center justify-content-center min-h-screen min-w-screen overflow-hidden">
|
<div class="surface-ground flex align-items-center justify-content-center min-h-screen min-w-screen overflow-hidden">
|
||||||
<div class="flex flex-column align-items-center justify-content-center">
|
<div class="flex flex-column align-items-center justify-content-center">
|
||||||
<img src="assets/layout/images/{{layoutService.config.colorScheme === 'light' ? 'logo-dark' : 'logo-white'}}.svg" alt="Sakai logo" class="mb-5 w-6rem flex-shrink-0">
|
<img src="assets/layout/images/{{layoutService.config().colorScheme === 'light' ? 'logo-dark' : 'logo-white'}}.svg" alt="Sakai logo" class="mb-5 w-6rem flex-shrink-0">
|
||||||
<div style="border-radius:56px; padding:0.3rem; background: linear-gradient(180deg, var(--primary-color) 10%, rgba(33, 150, 243, 0) 30%);">
|
<div style="border-radius:56px; padding:0.3rem; background: linear-gradient(180deg, var(--primary-color) 10%, rgba(33, 150, 243, 0) 30%);">
|
||||||
<div class="w-full surface-card py-8 px-5 sm:px-8" style="border-radius:53px">
|
<div class="w-full surface-card py-8 px-5 sm:px-8" style="border-radius:53px">
|
||||||
<div class="text-center mb-5">
|
<div class="text-center mb-5">
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { Component, OnInit, OnDestroy } from '@angular/core';
|
|||||||
import { MenuItem } from 'primeng/api';
|
import { MenuItem } from 'primeng/api';
|
||||||
import { Product } from '../../api/product';
|
import { Product } from '../../api/product';
|
||||||
import { ProductService } from '../../service/product.service';
|
import { ProductService } from '../../service/product.service';
|
||||||
import { Subscription } from 'rxjs';
|
import { Subscription, debounceTime } from 'rxjs';
|
||||||
import { LayoutService } from 'src/app/layout/service/app.layout.service';
|
import { LayoutService } from 'src/app/layout/service/app.layout.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@@ -21,7 +21,9 @@ export class DashboardComponent implements OnInit, OnDestroy {
|
|||||||
subscription!: Subscription;
|
subscription!: Subscription;
|
||||||
|
|
||||||
constructor(private productService: ProductService, public layoutService: LayoutService) {
|
constructor(private productService: ProductService, public layoutService: LayoutService) {
|
||||||
this.subscription = this.layoutService.configUpdate$.subscribe(() => {
|
this.subscription = this.layoutService.configUpdate$
|
||||||
|
.pipe(debounceTime(25))
|
||||||
|
.subscribe((config) => {
|
||||||
this.initChart();
|
this.initChart();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ Run 'ng help' for more options.</code></pre>
|
|||||||
|
|
||||||
<pre class="app-code"><code>import { Component, OnInit } from '@angular/core';
|
<pre class="app-code"><code>import { Component, OnInit } from '@angular/core';
|
||||||
import { PrimeNGConfig } from 'primeng/api';
|
import { PrimeNGConfig } from 'primeng/api';
|
||||||
import { LayoutService } from './layout/service/app.layout.service';
|
import { LayoutService, AppConfig } from './layout/service/app.layout.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-root',
|
selector: 'app-root',
|
||||||
@@ -57,7 +57,7 @@ export class AppComponent implements OnInit {
|
|||||||
this.primengConfig.ripple = true; //enables core ripple functionality
|
this.primengConfig.ripple = true; //enables core ripple functionality
|
||||||
|
|
||||||
//optional configuration with the default configuration
|
//optional configuration with the default configuration
|
||||||
this.layoutService.config = {
|
const config: AppConfig = {
|
||||||
ripple: false, //toggles ripple on and off
|
ripple: false, //toggles ripple on and off
|
||||||
inputStyle: 'outlined', //default style for input elements
|
inputStyle: 'outlined', //default style for input elements
|
||||||
menuMode: 'static', //layout mode of the menu, valid values are "static" and "overlay"
|
menuMode: 'static', //layout mode of the menu, valid values are "static" and "overlay"
|
||||||
@@ -65,6 +65,7 @@ export class AppComponent implements OnInit {
|
|||||||
theme: 'lara-light-indigo', //default component theme for PrimeNG
|
theme: 'lara-light-indigo', //default component theme for PrimeNG
|
||||||
scale: 14 //size of the body font size to scale the whole application
|
scale: 14 //size of the body font size to scale the whole application
|
||||||
};
|
};
|
||||||
|
this.layoutService.config.set(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
}</code></pre>
|
}</code></pre>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<div id="home" class="landing-wrapper overflow-hidden">
|
<div id="home" class="landing-wrapper overflow-hidden">
|
||||||
<div class="py-4 px-4 mx-0 md:mx-6 lg:mx-8 lg:px-8 flex align-items-center justify-content-between relative lg:static mb-3">
|
<div class="py-4 px-4 mx-0 md:mx-6 lg:mx-8 lg:px-8 flex align-items-center justify-content-between relative lg:static mb-3">
|
||||||
<a class="flex align-items-center" href="#">
|
<a class="flex align-items-center" href="#">
|
||||||
<img src="assets/layout/images/{{layoutService.config.colorScheme === 'light' ? 'logo-dark' : 'logo-white'}}.svg" alt="Sakai Logo" height="50" class="mr-0 lg:mr-2"><span class="text-900 font-medium text-2xl line-height-3 mr-8">SAKAI</span>
|
<img src="assets/layout/images/{{layoutService.config().colorScheme === 'light' ? 'logo-dark' : 'logo-white'}}.svg" alt="Sakai Logo" height="50" class="mr-0 lg:mr-2"><span class="text-900 font-medium text-2xl line-height-3 mr-8">SAKAI</span>
|
||||||
</a>
|
</a>
|
||||||
<a pRipple class="cursor-pointer block lg:hidden text-700" pStyleClass="@next" enterClass="hidden" leaveToClass="hidden" [hideOnOutsideClick]="true">
|
<a pRipple class="cursor-pointer block lg:hidden text-700" pStyleClass="@next" enterClass="hidden" leaveToClass="hidden" [hideOnOutsideClick]="true">
|
||||||
<i class="pi pi-bars text-4xl"></i>
|
<i class="pi pi-bars text-4xl"></i>
|
||||||
@@ -317,7 +317,7 @@
|
|||||||
<div class="grid justify-content-between">
|
<div class="grid justify-content-between">
|
||||||
<div class="col-12 md:col-2" style="margin-top:-1.5rem;">
|
<div class="col-12 md:col-2" style="margin-top:-1.5rem;">
|
||||||
<a (click)="router.navigate(['/pages/landing'], {fragment: 'home'})" class="flex flex-wrap align-items-center justify-content-center md:justify-content-start md:mb-0 mb-3 cursor-pointer">
|
<a (click)="router.navigate(['/pages/landing'], {fragment: 'home'})" class="flex flex-wrap align-items-center justify-content-center md:justify-content-start md:mb-0 mb-3 cursor-pointer">
|
||||||
<img src="assets/layout/images/{{layoutService.config.colorScheme === 'light' ? 'logo-dark' : 'logo-white'}}.svg" alt="footer sections" width="50" height="50" class="mr-2">
|
<img src="assets/layout/images/{{layoutService.config().colorScheme === 'light' ? 'logo-dark' : 'logo-white'}}.svg" alt="footer sections" width="50" height="50" class="mr-2">
|
||||||
<h4 class="font-medium text-3xl text-900">SAKAI</h4>
|
<h4 class="font-medium text-3xl text-900">SAKAI</h4>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Component, OnDestroy, OnInit } from '@angular/core';
|
import { Component, OnDestroy, OnInit } from '@angular/core';
|
||||||
import { Subscription } from 'rxjs';
|
import { Subscription, debounceTime } from 'rxjs';
|
||||||
import { LayoutService } from 'src/app/layout/service/app.layout.service';
|
import { LayoutService } from 'src/app/layout/service/app.layout.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@@ -28,11 +28,12 @@ export class ChartsDemoComponent implements OnInit, OnDestroy {
|
|||||||
radarOptions: any;
|
radarOptions: any;
|
||||||
|
|
||||||
subscription: Subscription;
|
subscription: Subscription;
|
||||||
|
constructor(private layoutService: LayoutService) {
|
||||||
constructor(public layoutService: LayoutService) {
|
this.subscription = this.layoutService.configUpdate$
|
||||||
this.subscription = this.layoutService.configUpdate$.subscribe(config => {
|
.pipe(debounceTime(25))
|
||||||
this.initCharts();
|
.subscribe((config) => {
|
||||||
});
|
this.initCharts();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<div class="layout-footer">
|
<div class="layout-footer">
|
||||||
<img src="assets/layout/images/{{layoutService.config.colorScheme === 'light' ? 'logo-dark' : 'logo-white'}}.svg" alt="Logo" height="20" class="mr-2"/>
|
<img src="assets/layout/images/{{layoutService.config().colorScheme === 'light' ? 'logo-dark' : 'logo-white'}}.svg" alt="Logo" height="20" class="mr-2"/>
|
||||||
by
|
by
|
||||||
<span class="font-medium ml-2">PrimeNG</span>
|
<span class="font-medium ml-2">PrimeNG</span>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -97,15 +97,15 @@ export class AppLayoutComponent implements OnDestroy {
|
|||||||
|
|
||||||
get containerClass() {
|
get containerClass() {
|
||||||
return {
|
return {
|
||||||
'layout-theme-light': this.layoutService.config.colorScheme === 'light',
|
'layout-theme-light': this.layoutService.config().colorScheme === 'light',
|
||||||
'layout-theme-dark': this.layoutService.config.colorScheme === 'dark',
|
'layout-theme-dark': this.layoutService.config().colorScheme === 'dark',
|
||||||
'layout-overlay': this.layoutService.config.menuMode === 'overlay',
|
'layout-overlay': this.layoutService.config().menuMode === 'overlay',
|
||||||
'layout-static': this.layoutService.config.menuMode === 'static',
|
'layout-static': this.layoutService.config().menuMode === 'static',
|
||||||
'layout-static-inactive': this.layoutService.state.staticMenuDesktopInactive && this.layoutService.config.menuMode === 'static',
|
'layout-static-inactive': this.layoutService.state.staticMenuDesktopInactive && this.layoutService.config().menuMode === 'static',
|
||||||
'layout-overlay-active': this.layoutService.state.overlayMenuActive,
|
'layout-overlay-active': this.layoutService.state.overlayMenuActive,
|
||||||
'layout-mobile-active': this.layoutService.state.staticMenuMobileActive,
|
'layout-mobile-active': this.layoutService.state.staticMenuMobileActive,
|
||||||
'p-input-filled': this.layoutService.config.inputStyle === 'filled',
|
'p-input-filled': this.layoutService.config().inputStyle === 'filled',
|
||||||
'p-ripple-disabled': !this.layoutService.config.ripple
|
'p-ripple-disabled': !this.layoutService.config().ripple
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
</ng-container>
|
</ng-container>
|
||||||
<li>
|
<li>
|
||||||
<a href="https://www.primefaces.org/primeblocks-ng/#/">
|
<a href="https://www.primefaces.org/primeblocks-ng/#/">
|
||||||
<img src="assets/layout/images/{{layoutService.config.colorScheme === 'light' ? 'banner-primeblocks' : 'banner-primeblocks-dark'}}.png" alt="Prime Blocks" class="w-full mt-3"/>
|
<img src="assets/layout/images/{{layoutService.config().colorScheme === 'light' ? 'banner-primeblocks' : 'banner-primeblocks-dark'}}.png" alt="Prime Blocks" class="w-full mt-3"/>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<div class="layout-topbar">
|
<div class="layout-topbar">
|
||||||
<a class="layout-topbar-logo" routerLink="">
|
<a class="layout-topbar-logo" routerLink="">
|
||||||
<img src="assets/layout/images/{{layoutService.config.colorScheme === 'light' ? 'logo-dark' : 'logo-white'}}.svg" alt="logo">
|
<img src="assets/layout/images/{{layoutService.config().colorScheme === 'light' ? 'logo-dark' : 'logo-white'}}.svg" alt="logo">
|
||||||
<span>SAKAI</span>
|
<span>SAKAI</span>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
|
|||||||
@@ -23,35 +23,44 @@ export class AppConfigComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get scale(): number {
|
get scale(): number {
|
||||||
return this.layoutService.config.scale;
|
return this.layoutService.config().scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
set scale(_val: number) {
|
set scale(_val: number) {
|
||||||
this.layoutService.config.scale = _val;
|
this.layoutService.config.update((config) => ({
|
||||||
|
...config,
|
||||||
|
scale: _val,
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
get menuMode(): string {
|
get menuMode(): string {
|
||||||
return this.layoutService.config.menuMode;
|
return this.layoutService.config().menuMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
set menuMode(_val: string) {
|
set menuMode(_val: string) {
|
||||||
this.layoutService.config.menuMode = _val;
|
this.layoutService.config.update((config) => ({
|
||||||
|
...config,
|
||||||
|
menuMode: _val,
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
get inputStyle(): string {
|
get inputStyle(): string {
|
||||||
return this.layoutService.config.inputStyle;
|
return this.layoutService.config().inputStyle;
|
||||||
}
|
}
|
||||||
|
|
||||||
set inputStyle(_val: string) {
|
set inputStyle(_val: string) {
|
||||||
this.layoutService.config.inputStyle = _val;
|
this.layoutService.config().inputStyle = _val;
|
||||||
}
|
}
|
||||||
|
|
||||||
get ripple(): boolean {
|
get ripple(): boolean {
|
||||||
return this.layoutService.config.ripple;
|
return this.layoutService.config().ripple;
|
||||||
}
|
}
|
||||||
|
|
||||||
set ripple(_val: boolean) {
|
set ripple(_val: boolean) {
|
||||||
this.layoutService.config.ripple = _val;
|
this.layoutService.config.update((config) => ({
|
||||||
|
...config,
|
||||||
|
ripple: _val,
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
onConfigButtonClick() {
|
onConfigButtonClick() {
|
||||||
@@ -59,32 +68,9 @@ export class AppConfigComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
changeTheme(theme: string, colorScheme: string) {
|
changeTheme(theme: string, colorScheme: string) {
|
||||||
const themeLink = <HTMLLinkElement>document.getElementById('theme-css');
|
this.layoutService.config.update((config) => ({ ...config, theme:theme,colorScheme:colorScheme }));
|
||||||
const newHref = themeLink.getAttribute('href')!.replace(this.layoutService.config.theme, theme);
|
|
||||||
this.layoutService.config.colorScheme
|
|
||||||
this.replaceThemeLink(newHref, () => {
|
|
||||||
this.layoutService.config.theme = theme;
|
|
||||||
this.layoutService.config.colorScheme = colorScheme;
|
|
||||||
this.layoutService.onConfigUpdate();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
replaceThemeLink(href: string, onComplete: Function) {
|
|
||||||
const id = 'theme-css';
|
|
||||||
const themeLink = <HTMLLinkElement>document.getElementById('theme-css');
|
|
||||||
const cloneLinkElement = <HTMLLinkElement>themeLink.cloneNode(true);
|
|
||||||
|
|
||||||
cloneLinkElement.setAttribute('href', href);
|
|
||||||
cloneLinkElement.setAttribute('id', id + '-clone');
|
|
||||||
|
|
||||||
themeLink.parentNode!.insertBefore(cloneLinkElement, themeLink.nextSibling);
|
|
||||||
|
|
||||||
cloneLinkElement.addEventListener('load', () => {
|
|
||||||
themeLink.remove();
|
|
||||||
cloneLinkElement.setAttribute('id', id);
|
|
||||||
onComplete();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
decrementScale() {
|
decrementScale() {
|
||||||
this.scale--;
|
this.scale--;
|
||||||
@@ -97,6 +83,9 @@ export class AppConfigComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
applyScale() {
|
applyScale() {
|
||||||
document.documentElement.style.fontSize = this.scale + 'px';
|
this.layoutService.config.update((config) => ({
|
||||||
|
...config,
|
||||||
|
scale: this.scale,
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Injectable } from '@angular/core';
|
import { Injectable, effect, signal } from '@angular/core';
|
||||||
import { Subject } from 'rxjs';
|
import { Subject } from 'rxjs';
|
||||||
|
|
||||||
export interface AppConfig {
|
export interface AppConfig {
|
||||||
@@ -24,7 +24,7 @@ interface LayoutState {
|
|||||||
})
|
})
|
||||||
export class LayoutService {
|
export class LayoutService {
|
||||||
|
|
||||||
config: AppConfig = {
|
_config: AppConfig = {
|
||||||
ripple: false,
|
ripple: false,
|
||||||
inputStyle: 'outlined',
|
inputStyle: 'outlined',
|
||||||
menuMode: 'static',
|
menuMode: 'static',
|
||||||
@@ -33,6 +33,8 @@ export class LayoutService {
|
|||||||
scale: 14,
|
scale: 14,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
config = signal<AppConfig>(this._config);
|
||||||
|
|
||||||
state: LayoutState = {
|
state: LayoutState = {
|
||||||
staticMenuDesktopInactive: false,
|
staticMenuDesktopInactive: false,
|
||||||
overlayMenuActive: false,
|
overlayMenuActive: false,
|
||||||
@@ -82,7 +84,7 @@ export class LayoutService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
isOverlay() {
|
isOverlay() {
|
||||||
return this.config.menuMode === 'overlay';
|
return this.config().menuMode === 'overlay';
|
||||||
}
|
}
|
||||||
|
|
||||||
isDesktop() {
|
isDesktop() {
|
||||||
@@ -94,7 +96,58 @@ export class LayoutService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onConfigUpdate() {
|
onConfigUpdate() {
|
||||||
this.configUpdate.next(this.config);
|
this._config = { ...this.config() };
|
||||||
|
this.configUpdate.next(this.config());
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
effect(() => {
|
||||||
|
const config = this.config();
|
||||||
|
this.changeTheme();
|
||||||
|
this.changeScale(config.scale);
|
||||||
|
this.onConfigUpdate();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
changeTheme() {
|
||||||
|
const config = this.config();
|
||||||
|
const themeLink = <HTMLLinkElement>(
|
||||||
|
document.getElementById('theme-css')
|
||||||
|
);
|
||||||
|
const themeLinkHref = themeLink.getAttribute('href')!;
|
||||||
|
const newHref = themeLinkHref
|
||||||
|
.split('/')
|
||||||
|
.map((el) =>
|
||||||
|
el == this._config.theme
|
||||||
|
? (el = config.theme)
|
||||||
|
: el == `theme-${this._config.colorScheme}`
|
||||||
|
? (el = `theme-${config.colorScheme}`)
|
||||||
|
: el
|
||||||
|
)
|
||||||
|
.join('/');
|
||||||
|
|
||||||
|
this.replaceThemeLink(newHref);
|
||||||
|
}
|
||||||
|
replaceThemeLink(href: string) {
|
||||||
|
const id = 'theme-css';
|
||||||
|
let themeLink = <HTMLLinkElement>document.getElementById(id);
|
||||||
|
const cloneLinkElement = <HTMLLinkElement>themeLink.cloneNode(true);
|
||||||
|
|
||||||
|
cloneLinkElement.setAttribute('href', href);
|
||||||
|
cloneLinkElement.setAttribute('id', id + '-clone');
|
||||||
|
|
||||||
|
themeLink.parentNode!.insertBefore(
|
||||||
|
cloneLinkElement,
|
||||||
|
themeLink.nextSibling
|
||||||
|
);
|
||||||
|
cloneLinkElement.addEventListener('load', () => {
|
||||||
|
themeLink.remove();
|
||||||
|
cloneLinkElement.setAttribute('id', id);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
changeScale(value: number) {
|
||||||
|
document.documentElement.style.fontSize = `${value}px`;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user