@foliokit/cms-ui 0.0.0 → 0.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm2022/index.js +3 -1
- package/esm2022/index.js.map +1 -1
- package/esm2022/lib/app-shell/app-shell.component.js +52 -0
- package/esm2022/lib/app-shell/app-shell.component.js.map +1 -0
- package/esm2022/lib/shell-config.token.js +3 -0
- package/esm2022/lib/shell-config.token.js.map +1 -0
- package/esm2022/lib/theme.service.js +45 -0
- package/esm2022/lib/theme.service.js.map +1 -0
- package/index.d.ts +3 -1
- package/lib/app-shell/app-shell.component.d.ts +17 -0
- package/lib/shell-config.token.d.ts +9 -0
- package/lib/theme.service.d.ts +11 -0
- package/package.json +24 -3
- package/esm2022/lib/cms-ui/cms-ui.js +0 -11
- package/esm2022/lib/cms-ui/cms-ui.js.map +0 -1
- package/lib/cms-ui/cms-ui.d.ts +0 -5
package/esm2022/index.js
CHANGED
package/esm2022/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../libs/cms-ui/src/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAC","sourcesContent":["export * from './lib/
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../libs/cms-ui/src/index.ts"],"names":[],"mappings":"AAAA,cAAc,qCAAqC,CAAC;AACpD,cAAc,qBAAqB,CAAC;AACpC,cAAc,0BAA0B,CAAC","sourcesContent":["export * from './lib/app-shell/app-shell.component';\nexport * from './lib/theme.service';\nexport * from './lib/shell-config.token';\n"]}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { ChangeDetectionStrategy, Component, inject, signal, } from '@angular/core';
|
|
2
|
+
import { BreakpointObserver, Breakpoints } from '@angular/cdk/layout';
|
|
3
|
+
import { MatSidenavModule } from '@angular/material/sidenav';
|
|
4
|
+
import { MatToolbarModule } from '@angular/material/toolbar';
|
|
5
|
+
import { MatIconModule } from '@angular/material/icon';
|
|
6
|
+
import { MatButtonModule } from '@angular/material/button';
|
|
7
|
+
import { SHELL_CONFIG } from '../shell-config.token';
|
|
8
|
+
import { ThemeService } from '../theme.service';
|
|
9
|
+
import * as i0 from "@angular/core";
|
|
10
|
+
import * as i1 from "@angular/material/sidenav";
|
|
11
|
+
import * as i2 from "@angular/material/toolbar";
|
|
12
|
+
import * as i3 from "@angular/material/icon";
|
|
13
|
+
import * as i4 from "@angular/material/button";
|
|
14
|
+
export class AppShellComponent {
|
|
15
|
+
config = inject(SHELL_CONFIG);
|
|
16
|
+
theme = inject(ThemeService);
|
|
17
|
+
isMobile = signal(false, ...(ngDevMode ? [{ debugName: "isMobile" }] : /* istanbul ignore next */ []));
|
|
18
|
+
sidenavOpen = signal(false, ...(ngDevMode ? [{ debugName: "sidenavOpen" }] : /* istanbul ignore next */ []));
|
|
19
|
+
breakpointObserver = inject(BreakpointObserver);
|
|
20
|
+
bpSub;
|
|
21
|
+
ngOnInit() {
|
|
22
|
+
this.bpSub = this.breakpointObserver
|
|
23
|
+
.observe([Breakpoints.XSmall, Breakpoints.Small])
|
|
24
|
+
.subscribe((state) => {
|
|
25
|
+
const mobile = state.matches;
|
|
26
|
+
this.isMobile.set(mobile);
|
|
27
|
+
this.sidenavOpen.set(!mobile);
|
|
28
|
+
});
|
|
29
|
+
this.theme.apply();
|
|
30
|
+
}
|
|
31
|
+
ngOnDestroy() {
|
|
32
|
+
this.bpSub?.unsubscribe();
|
|
33
|
+
}
|
|
34
|
+
toggleSidenav() {
|
|
35
|
+
this.sidenavOpen.update((open) => !open);
|
|
36
|
+
}
|
|
37
|
+
toggleTheme() {
|
|
38
|
+
this.theme.toggle();
|
|
39
|
+
}
|
|
40
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: AppShellComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
41
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.4", type: AppShellComponent, isStandalone: true, selector: "folio-app-shell", ngImport: i0, template: "<mat-sidenav-container class=\"shell-container\">\n <mat-sidenav\n class=\"shell-sidenav\"\n [mode]=\"isMobile() ? 'over' : 'side'\"\n [opened]=\"sidenavOpen()\"\n (openedChange)=\"sidenavOpen.set($event)\"\n >\n <ng-content select=\"[shellNav]\" />\n </mat-sidenav>\n\n <mat-sidenav-content class=\"shell-content\">\n <mat-toolbar class=\"shell-toolbar\">\n @if (isMobile()) {\n <button mat-icon-button aria-label=\"Toggle navigation\" (click)=\"toggleSidenav()\">\n <mat-icon>menu</mat-icon>\n </button>\n }\n\n @if (config.logoUrl) {\n <img [src]=\"config.logoUrl\" [alt]=\"config.appName\" class=\"shell-logo\" />\n }\n <span class=\"shell-app-name\">{{ config.appName }}</span>\n\n <span class=\"flex-1\"></span>\n\n <button\n mat-icon-button\n [attr.aria-label]=\"theme.scheme() === 'dark' ? 'Switch to light mode' : 'Switch to dark mode'\"\n (click)=\"toggleTheme()\"\n >\n <mat-icon>{{ theme.scheme() === 'dark' ? 'light_mode' : 'dark_mode' }}</mat-icon>\n </button>\n\n <ng-content select=\"[shellHeaderActions]\" />\n\n @if (config.showAuth) {\n <ng-content select=\"[shellAuthSlot]\" />\n }\n </mat-toolbar>\n\n <main class=\"shell-main\">\n <ng-content />\n </main>\n </mat-sidenav-content>\n</mat-sidenav-container>\n", styles: [":host{display:block;height:100%}.shell-container{height:100%;background-color:var(--mat-sys-surface)}.shell-sidenav{width:260px;border-right:1px solid var(--mat-sys-outline-variant);background-color:var(--mat-sys-surface-container-low)}.shell-toolbar{position:sticky;top:0;z-index:100;background-color:var(--mat-sys-surface-container);border-bottom:1px solid var(--mat-sys-outline-variant);gap:4px}.shell-logo{height:32px;width:auto;margin-right:8px}.shell-app-name{font-size:1.125rem;font-weight:600;color:var(--mat-sys-on-surface);white-space:nowrap}.shell-content{display:flex;flex-direction:column;background-color:var(--mat-sys-surface)}.shell-main{flex:1;overflow-y:auto}\n"], dependencies: [{ kind: "ngmodule", type: MatSidenavModule }, { kind: "component", type: i1.MatSidenav, selector: "mat-sidenav", inputs: ["fixedInViewport", "fixedTopGap", "fixedBottomGap"], exportAs: ["matSidenav"] }, { kind: "component", type: i1.MatSidenavContainer, selector: "mat-sidenav-container", exportAs: ["matSidenavContainer"] }, { kind: "component", type: i1.MatSidenavContent, selector: "mat-sidenav-content" }, { kind: "ngmodule", type: MatToolbarModule }, { kind: "component", type: i2.MatToolbar, selector: "mat-toolbar", inputs: ["color"], exportAs: ["matToolbar"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i4.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
42
|
+
}
|
|
43
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: AppShellComponent, decorators: [{
|
|
44
|
+
type: Component,
|
|
45
|
+
args: [{ selector: 'folio-app-shell', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [
|
|
46
|
+
MatSidenavModule,
|
|
47
|
+
MatToolbarModule,
|
|
48
|
+
MatIconModule,
|
|
49
|
+
MatButtonModule,
|
|
50
|
+
], template: "<mat-sidenav-container class=\"shell-container\">\n <mat-sidenav\n class=\"shell-sidenav\"\n [mode]=\"isMobile() ? 'over' : 'side'\"\n [opened]=\"sidenavOpen()\"\n (openedChange)=\"sidenavOpen.set($event)\"\n >\n <ng-content select=\"[shellNav]\" />\n </mat-sidenav>\n\n <mat-sidenav-content class=\"shell-content\">\n <mat-toolbar class=\"shell-toolbar\">\n @if (isMobile()) {\n <button mat-icon-button aria-label=\"Toggle navigation\" (click)=\"toggleSidenav()\">\n <mat-icon>menu</mat-icon>\n </button>\n }\n\n @if (config.logoUrl) {\n <img [src]=\"config.logoUrl\" [alt]=\"config.appName\" class=\"shell-logo\" />\n }\n <span class=\"shell-app-name\">{{ config.appName }}</span>\n\n <span class=\"flex-1\"></span>\n\n <button\n mat-icon-button\n [attr.aria-label]=\"theme.scheme() === 'dark' ? 'Switch to light mode' : 'Switch to dark mode'\"\n (click)=\"toggleTheme()\"\n >\n <mat-icon>{{ theme.scheme() === 'dark' ? 'light_mode' : 'dark_mode' }}</mat-icon>\n </button>\n\n <ng-content select=\"[shellHeaderActions]\" />\n\n @if (config.showAuth) {\n <ng-content select=\"[shellAuthSlot]\" />\n }\n </mat-toolbar>\n\n <main class=\"shell-main\">\n <ng-content />\n </main>\n </mat-sidenav-content>\n</mat-sidenav-container>\n", styles: [":host{display:block;height:100%}.shell-container{height:100%;background-color:var(--mat-sys-surface)}.shell-sidenav{width:260px;border-right:1px solid var(--mat-sys-outline-variant);background-color:var(--mat-sys-surface-container-low)}.shell-toolbar{position:sticky;top:0;z-index:100;background-color:var(--mat-sys-surface-container);border-bottom:1px solid var(--mat-sys-outline-variant);gap:4px}.shell-logo{height:32px;width:auto;margin-right:8px}.shell-app-name{font-size:1.125rem;font-weight:600;color:var(--mat-sys-on-surface);white-space:nowrap}.shell-content{display:flex;flex-direction:column;background-color:var(--mat-sys-surface)}.shell-main{flex:1;overflow-y:auto}\n"] }]
|
|
51
|
+
}] });
|
|
52
|
+
//# sourceMappingURL=app-shell.component.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app-shell.component.js","sourceRoot":"","sources":["../../../../../../libs/cms-ui/src/lib/app-shell/app-shell.component.ts","../../../../../../libs/cms-ui/src/lib/app-shell/app-shell.component.html"],"names":[],"mappings":"AAAA,OAAO,EACL,uBAAuB,EACvB,SAAS,EACT,MAAM,EAGN,MAAM,GACP,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEtE,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;;;;;;AAehD,MAAM,OAAO,iBAAiB;IACT,MAAM,GAAG,MAAM,CAAC,YAAY,CAAC,CAAC;IAC9B,KAAK,GAAG,MAAM,CAAC,YAAY,CAAC,CAAC;IAE7B,QAAQ,GAAG,MAAM,CAAC,KAAK,+EAAC,CAAC;IACzB,WAAW,GAAG,MAAM,CAAC,KAAK,kFAAC,CAAC;IAE9B,kBAAkB,GAAG,MAAM,CAAC,kBAAkB,CAAC,CAAC;IACzD,KAAK,CAAgB;IAE7B,QAAQ;QACN,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,kBAAkB;aACjC,OAAO,CAAC,CAAC,WAAW,CAAC,MAAM,EAAE,WAAW,CAAC,KAAK,CAAC,CAAC;aAChD,SAAS,CAAC,CAAC,KAAK,EAAE,EAAE;YACnB,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC;YAC7B,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YAC1B,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC;QAChC,CAAC,CAAC,CAAC;QACL,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;IACrB,CAAC;IAED,WAAW;QACT,IAAI,CAAC,KAAK,EAAE,WAAW,EAAE,CAAC;IAC5B,CAAC;IAES,aAAa;QACrB,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;IAC3C,CAAC;IAES,WAAW;QACnB,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;IACtB,CAAC;uGA/BU,iBAAiB;2FAAjB,iBAAiB,2EC9B9B,k3CA6CA,guBDrBI,gBAAgB,0YAChB,gBAAgB,gJAChB,aAAa,mLACb,eAAe;;2FAGN,iBAAiB;kBAb7B,SAAS;+BACE,iBAAiB,mBAGV,uBAAuB,CAAC,MAAM,cACnC,IAAI,WACP;wBACP,gBAAgB;wBAChB,gBAAgB;wBAChB,aAAa;wBACb,eAAe;qBAChB","sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n inject,\n OnDestroy,\n OnInit,\n signal,\n} from '@angular/core';\nimport { BreakpointObserver, Breakpoints } from '@angular/cdk/layout';\nimport { Subscription } from 'rxjs';\nimport { MatSidenavModule } from '@angular/material/sidenav';\nimport { MatToolbarModule } from '@angular/material/toolbar';\nimport { MatIconModule } from '@angular/material/icon';\nimport { MatButtonModule } from '@angular/material/button';\nimport { SHELL_CONFIG } from '../shell-config.token';\nimport { ThemeService } from '../theme.service';\n\n@Component({\n selector: 'folio-app-shell',\n templateUrl: './app-shell.component.html',\n styleUrl: './app-shell.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n standalone: true,\n imports: [\n MatSidenavModule,\n MatToolbarModule,\n MatIconModule,\n MatButtonModule,\n ],\n})\nexport class AppShellComponent implements OnInit, OnDestroy {\n protected readonly config = inject(SHELL_CONFIG);\n protected readonly theme = inject(ThemeService);\n\n protected readonly isMobile = signal(false);\n protected readonly sidenavOpen = signal(false);\n\n private readonly breakpointObserver = inject(BreakpointObserver);\n private bpSub?: Subscription;\n\n ngOnInit(): void {\n this.bpSub = this.breakpointObserver\n .observe([Breakpoints.XSmall, Breakpoints.Small])\n .subscribe((state) => {\n const mobile = state.matches;\n this.isMobile.set(mobile);\n this.sidenavOpen.set(!mobile);\n });\n this.theme.apply();\n }\n\n ngOnDestroy(): void {\n this.bpSub?.unsubscribe();\n }\n\n protected toggleSidenav(): void {\n this.sidenavOpen.update((open) => !open);\n }\n\n protected toggleTheme(): void {\n this.theme.toggle();\n }\n}\n","<mat-sidenav-container class=\"shell-container\">\n <mat-sidenav\n class=\"shell-sidenav\"\n [mode]=\"isMobile() ? 'over' : 'side'\"\n [opened]=\"sidenavOpen()\"\n (openedChange)=\"sidenavOpen.set($event)\"\n >\n <ng-content select=\"[shellNav]\" />\n </mat-sidenav>\n\n <mat-sidenav-content class=\"shell-content\">\n <mat-toolbar class=\"shell-toolbar\">\n @if (isMobile()) {\n <button mat-icon-button aria-label=\"Toggle navigation\" (click)=\"toggleSidenav()\">\n <mat-icon>menu</mat-icon>\n </button>\n }\n\n @if (config.logoUrl) {\n <img [src]=\"config.logoUrl\" [alt]=\"config.appName\" class=\"shell-logo\" />\n }\n <span class=\"shell-app-name\">{{ config.appName }}</span>\n\n <span class=\"flex-1\"></span>\n\n <button\n mat-icon-button\n [attr.aria-label]=\"theme.scheme() === 'dark' ? 'Switch to light mode' : 'Switch to dark mode'\"\n (click)=\"toggleTheme()\"\n >\n <mat-icon>{{ theme.scheme() === 'dark' ? 'light_mode' : 'dark_mode' }}</mat-icon>\n </button>\n\n <ng-content select=\"[shellHeaderActions]\" />\n\n @if (config.showAuth) {\n <ng-content select=\"[shellAuthSlot]\" />\n }\n </mat-toolbar>\n\n <main class=\"shell-main\">\n <ng-content />\n </main>\n </mat-sidenav-content>\n</mat-sidenav-container>\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shell-config.token.js","sourceRoot":"","sources":["../../../../../libs/cms-ui/src/lib/shell-config.token.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAU/C,MAAM,CAAC,MAAM,YAAY,GAAG,IAAI,cAAc,CAAc,cAAc,CAAC,CAAC","sourcesContent":["import { InjectionToken } from '@angular/core';\nimport type { NavItem } from '@foliokit/cms-core';\n\nexport interface ShellConfig {\n appName: string;\n logoUrl?: string;\n showAuth?: boolean;\n nav?: NavItem[];\n}\n\nexport const SHELL_CONFIG = new InjectionToken<ShellConfig>('SHELL_CONFIG');\n"]}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { inject, Injectable, PLATFORM_ID, signal } from '@angular/core';
|
|
2
|
+
import { isPlatformBrowser } from '@angular/common';
|
|
3
|
+
import * as i0 from "@angular/core";
|
|
4
|
+
const STORAGE_KEY = 'folio-theme';
|
|
5
|
+
export class ThemeService {
|
|
6
|
+
platformId = inject(PLATFORM_ID);
|
|
7
|
+
scheme = signal(this.resolveInitialScheme(), ...(ngDevMode ? [{ debugName: "scheme" }] : /* istanbul ignore next */ []));
|
|
8
|
+
toggle() {
|
|
9
|
+
this.scheme.update((s) => (s === 'light' ? 'dark' : 'light'));
|
|
10
|
+
this.apply();
|
|
11
|
+
}
|
|
12
|
+
apply() {
|
|
13
|
+
if (!isPlatformBrowser(this.platformId))
|
|
14
|
+
return;
|
|
15
|
+
const current = this.scheme();
|
|
16
|
+
document.documentElement.setAttribute('data-theme', current);
|
|
17
|
+
try {
|
|
18
|
+
localStorage.setItem(STORAGE_KEY, current);
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
// localStorage may be unavailable (private browsing, etc.)
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
resolveInitialScheme() {
|
|
25
|
+
if (!isPlatformBrowser(this.platformId))
|
|
26
|
+
return 'light';
|
|
27
|
+
try {
|
|
28
|
+
const stored = localStorage.getItem(STORAGE_KEY);
|
|
29
|
+
if (stored === 'light' || stored === 'dark')
|
|
30
|
+
return stored;
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
// ignore
|
|
34
|
+
}
|
|
35
|
+
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
|
36
|
+
return prefersDark ? 'dark' : 'light';
|
|
37
|
+
}
|
|
38
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: ThemeService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
39
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: ThemeService, providedIn: 'root' });
|
|
40
|
+
}
|
|
41
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: ThemeService, decorators: [{
|
|
42
|
+
type: Injectable,
|
|
43
|
+
args: [{ providedIn: 'root' }]
|
|
44
|
+
}] });
|
|
45
|
+
//# sourceMappingURL=theme.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"theme.service.js","sourceRoot":"","sources":["../../../../../libs/cms-ui/src/lib/theme.service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AACxE,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;;AAIpD,MAAM,WAAW,GAAG,aAAa,CAAC;AAGlC,MAAM,OAAO,YAAY;IACN,UAAU,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC;IAEzC,MAAM,GAAG,MAAM,CAAc,IAAI,CAAC,oBAAoB,EAAE,6EAAC,CAAC;IAEnE,MAAM;QACJ,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;QAC9D,IAAI,CAAC,KAAK,EAAE,CAAC;IACf,CAAC;IAED,KAAK;QACH,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,UAAU,CAAC;YAAE,OAAO;QAChD,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;QAC9B,QAAQ,CAAC,eAAe,CAAC,YAAY,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;QAC7D,IAAI,CAAC;YACH,YAAY,CAAC,OAAO,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;QAC7C,CAAC;QAAC,MAAM,CAAC;YACP,2DAA2D;QAC7D,CAAC;IACH,CAAC;IAEO,oBAAoB;QAC1B,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,UAAU,CAAC;YAAE,OAAO,OAAO,CAAC;QAExD,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,YAAY,CAAC,OAAO,CAAC,WAAW,CAAuB,CAAC;YACvE,IAAI,MAAM,KAAK,OAAO,IAAI,MAAM,KAAK,MAAM;gBAAE,OAAO,MAAM,CAAC;QAC7D,CAAC;QAAC,MAAM,CAAC;YACP,SAAS;QACX,CAAC;QAED,MAAM,WAAW,GAAG,MAAM,CAAC,UAAU,CAAC,8BAA8B,CAAC,CAAC,OAAO,CAAC;QAC9E,OAAO,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC;IACxC,CAAC;uGAjCU,YAAY;2GAAZ,YAAY,cADC,MAAM;;2FACnB,YAAY;kBADxB,UAAU;mBAAC,EAAE,UAAU,EAAE,MAAM,EAAE","sourcesContent":["import { inject, Injectable, PLATFORM_ID, signal } from '@angular/core';\nimport { isPlatformBrowser } from '@angular/common';\n\nexport type ColorScheme = 'light' | 'dark';\n\nconst STORAGE_KEY = 'folio-theme';\n\n@Injectable({ providedIn: 'root' })\nexport class ThemeService {\n private readonly platformId = inject(PLATFORM_ID);\n\n readonly scheme = signal<ColorScheme>(this.resolveInitialScheme());\n\n toggle(): void {\n this.scheme.update((s) => (s === 'light' ? 'dark' : 'light'));\n this.apply();\n }\n\n apply(): void {\n if (!isPlatformBrowser(this.platformId)) return;\n const current = this.scheme();\n document.documentElement.setAttribute('data-theme', current);\n try {\n localStorage.setItem(STORAGE_KEY, current);\n } catch {\n // localStorage may be unavailable (private browsing, etc.)\n }\n }\n\n private resolveInitialScheme(): ColorScheme {\n if (!isPlatformBrowser(this.platformId)) return 'light';\n\n try {\n const stored = localStorage.getItem(STORAGE_KEY) as ColorScheme | null;\n if (stored === 'light' || stored === 'dark') return stored;\n } catch {\n // ignore\n }\n\n const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;\n return prefersDark ? 'dark' : 'light';\n }\n}\n"]}
|
package/index.d.ts
CHANGED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { OnDestroy, OnInit } from '@angular/core';
|
|
2
|
+
import { ThemeService } from '../theme.service';
|
|
3
|
+
import * as i0 from "@angular/core";
|
|
4
|
+
export declare class AppShellComponent implements OnInit, OnDestroy {
|
|
5
|
+
protected readonly config: import("@foliokit/cms-ui").ShellConfig;
|
|
6
|
+
protected readonly theme: ThemeService;
|
|
7
|
+
protected readonly isMobile: import("@angular/core").WritableSignal<boolean>;
|
|
8
|
+
protected readonly sidenavOpen: import("@angular/core").WritableSignal<boolean>;
|
|
9
|
+
private readonly breakpointObserver;
|
|
10
|
+
private bpSub?;
|
|
11
|
+
ngOnInit(): void;
|
|
12
|
+
ngOnDestroy(): void;
|
|
13
|
+
protected toggleSidenav(): void;
|
|
14
|
+
protected toggleTheme(): void;
|
|
15
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<AppShellComponent, never>;
|
|
16
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<AppShellComponent, "folio-app-shell", never, {}, {}, never, ["[shellNav]", "[shellHeaderActions]", "[shellAuthSlot]", "*"], true, never>;
|
|
17
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { InjectionToken } from '@angular/core';
|
|
2
|
+
import type { NavItem } from '@foliokit/cms-core';
|
|
3
|
+
export interface ShellConfig {
|
|
4
|
+
appName: string;
|
|
5
|
+
logoUrl?: string;
|
|
6
|
+
showAuth?: boolean;
|
|
7
|
+
nav?: NavItem[];
|
|
8
|
+
}
|
|
9
|
+
export declare const SHELL_CONFIG: InjectionToken<ShellConfig>;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import * as i0 from "@angular/core";
|
|
2
|
+
export type ColorScheme = 'light' | 'dark';
|
|
3
|
+
export declare class ThemeService {
|
|
4
|
+
private readonly platformId;
|
|
5
|
+
readonly scheme: import("@angular/core").WritableSignal<ColorScheme>;
|
|
6
|
+
toggle(): void;
|
|
7
|
+
apply(): void;
|
|
8
|
+
private resolveInitialScheme;
|
|
9
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<ThemeService, never>;
|
|
10
|
+
static ɵprov: i0.ɵɵInjectableDeclaration<ThemeService>;
|
|
11
|
+
}
|
package/package.json
CHANGED
|
@@ -1,12 +1,33 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@foliokit/cms-ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.2",
|
|
4
|
+
"description": "Angular shell layout components and theme service for FolioKit CMS",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"angular",
|
|
7
|
+
"cms",
|
|
8
|
+
"foliokit",
|
|
9
|
+
"app-shell",
|
|
10
|
+
"material"
|
|
11
|
+
],
|
|
12
|
+
"license": "MIT",
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "https://github.com/dougwilliamson/foliokit"
|
|
16
|
+
},
|
|
4
17
|
"publishConfig": {
|
|
5
18
|
"access": "public"
|
|
6
19
|
},
|
|
7
20
|
"peerDependencies": {
|
|
8
|
-
"@angular/
|
|
9
|
-
"@angular/
|
|
21
|
+
"@angular/cdk": "^21.2.2",
|
|
22
|
+
"@angular/common": "^21.2.4",
|
|
23
|
+
"@angular/core": "^21.2.4",
|
|
24
|
+
"@angular/material": "^21.2.2",
|
|
25
|
+
"@foliokit/cms-core": "^0.4.2"
|
|
26
|
+
},
|
|
27
|
+
"peerDependenciesMeta": {
|
|
28
|
+
"@foliokit/cms-core": {
|
|
29
|
+
"optional": true
|
|
30
|
+
}
|
|
10
31
|
},
|
|
11
32
|
"sideEffects": false,
|
|
12
33
|
"module": "esm2022/foliokit-cms-ui.js",
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { Component } from '@angular/core';
|
|
2
|
-
import * as i0 from "@angular/core";
|
|
3
|
-
export class CmsUi {
|
|
4
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: CmsUi, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
5
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.1.6", type: CmsUi, isStandalone: true, selector: "lib-cms-ui", ngImport: i0, template: "<p>CmsUi works!</p>\n", styles: [""] });
|
|
6
|
-
}
|
|
7
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: CmsUi, decorators: [{
|
|
8
|
-
type: Component,
|
|
9
|
-
args: [{ selector: 'lib-cms-ui', imports: [], template: "<p>CmsUi works!</p>\n" }]
|
|
10
|
-
}] });
|
|
11
|
-
//# sourceMappingURL=cms-ui.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"cms-ui.js","sourceRoot":"","sources":["../../../../../../libs/cms-ui/src/lib/cms-ui/cms-ui.ts","../../../../../../libs/cms-ui/src/lib/cms-ui/cms-ui.html"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;;AAQ1C,MAAM,OAAO,KAAK;uGAAL,KAAK;2FAAL,KAAK,sECRlB,uBACA;;2FDOa,KAAK;kBANjB,SAAS;+BACE,YAAY,WACb,EAAE","sourcesContent":["import { Component } from '@angular/core';\n\n@Component({\n selector: 'lib-cms-ui',\n imports: [],\n templateUrl: './cms-ui.html',\n styleUrl: './cms-ui.scss',\n})\nexport class CmsUi {}\n","<p>CmsUi works!</p>\n"]}
|