Skip to content

Commit 09f0c5f

Browse files
committed
chore: store dev-app dark/light theme state in localStorage
1 parent 581d1f2 commit 09f0c5f

File tree

3 files changed

+71
-19
lines changed

3 files changed

+71
-19
lines changed

src/dev-app/dev-app/dev-app-layout.html

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,9 @@ <h1>Angular Material Demos</h1>
3333
<button mat-icon-button (click)="toggleFullscreen()" title="Toggle fullscreen">
3434
<mat-icon>fullscreen</mat-icon>
3535
</button>
36-
<button mat-button (click)="toggleTheme()">{{dark ? 'Light' : 'Dark'}} theme</button>
36+
<button mat-button (click)="theme.isDark = !this.theme.isDark">
37+
{{theme.isDark ? 'Light' : 'Dark'}} theme
38+
</button>
3739
<button mat-button (click)="rippleOptions.disabled = !rippleOptions.disabled">
3840
{{rippleOptions.disabled ? 'Enable' : 'Disable'}} ripples
3941
</button>

src/dev-app/dev-app/dev-app-layout.ts

Lines changed: 3 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@
77
*/
88

99
import {Directionality} from '@angular/cdk/bidi';
10-
import {OverlayContainer} from '@angular/cdk/overlay';
1110
import {ChangeDetectorRef, Component, ElementRef, Inject, ViewEncapsulation} from '@angular/core';
1211
import {DevAppRippleOptions} from './ripple-options';
1312
import {DevAppDirectionality} from './dev-app-directionality';
13+
import {DevAppTheme} from './dev-app-theme';
1414

1515
/** Root component for the dev-app demos. */
1616
@Component({
@@ -20,7 +20,6 @@ import {DevAppDirectionality} from './dev-app-directionality';
2020
encapsulation: ViewEncapsulation.None,
2121
})
2222
export class DevAppLayout {
23-
dark = false;
2423
navItems = [
2524
{name: 'Examples', route: '/examples'},
2625
{name: 'Autocomplete', route: '/autocomplete'},
@@ -85,8 +84,8 @@ export class DevAppLayout {
8584
];
8685

8786
constructor(
88-
private _element: ElementRef<HTMLElement>, private _overlayContainer: OverlayContainer,
89-
public rippleOptions: DevAppRippleOptions,
87+
private _element: ElementRef<HTMLElement>,
88+
public rippleOptions: DevAppRippleOptions, public theme: DevAppTheme,
9089
@Inject(Directionality) public dir: DevAppDirectionality, cdr: ChangeDetectorRef) {
9190
dir.change.subscribe(() => cdr.markForCheck());
9291
}
@@ -104,18 +103,4 @@ export class DevAppLayout {
104103
elem.msRequestFullScreen();
105104
}
106105
}
107-
108-
toggleTheme() {
109-
const darkThemeClass = 'demo-unicorn-dark-theme';
110-
111-
this.dark = !this.dark;
112-
113-
if (this.dark) {
114-
this._element.nativeElement.classList.add(darkThemeClass);
115-
this._overlayContainer.getContainerElement().classList.add(darkThemeClass);
116-
} else {
117-
this._element.nativeElement.classList.remove(darkThemeClass);
118-
this._overlayContainer.getContainerElement().classList.remove(darkThemeClass);
119-
}
120-
}
121106
}

src/dev-app/dev-app/dev-app-theme.ts

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
import {Inject, Injectable} from '@angular/core';
10+
import {OverlayContainer} from '@angular/cdk/overlay';
11+
import {DOCUMENT} from '@angular/common';
12+
13+
const isDarkThemeKey = 'isDarkTheme';
14+
15+
@Injectable({providedIn: 'root'})
16+
export class DevAppTheme {
17+
readonly darkThemeClass = 'demo-unicorn-dark-theme';
18+
private _isDark = false;
19+
20+
constructor(private _overlayContainer: OverlayContainer,
21+
@Inject(DOCUMENT) private _document: Document) {
22+
let isDark: string | null;
23+
try {
24+
isDark = localStorage.getItem(isDarkThemeKey);
25+
if (isDark != null) {
26+
this._isDark = isDark === 'true';
27+
this._isDark ? this.applyDarkTheme() : this.applyLightTheme();
28+
}
29+
} catch (error) {
30+
console.error(`Failed to read ${isDarkThemeKey} from localStorage: `, error);
31+
}
32+
}
33+
34+
get isDark(): boolean {
35+
return this._isDark;
36+
}
37+
38+
set isDark(value: boolean) {
39+
if (value != null) {
40+
this._isDark = value;
41+
42+
if (this._isDark) {
43+
this.applyDarkTheme();
44+
} else {
45+
this.applyLightTheme();
46+
}
47+
48+
try {
49+
localStorage.setItem(isDarkThemeKey, String(value));
50+
} catch (error) {
51+
console.error(`Failed to write ${isDarkThemeKey} to localStorage: `, error);
52+
}
53+
}
54+
}
55+
56+
applyDarkTheme() {
57+
this._document.body.classList.add(this.darkThemeClass);
58+
this._overlayContainer.getContainerElement().classList.add(this.darkThemeClass);
59+
}
60+
61+
applyLightTheme() {
62+
this._document.body.classList.remove(this.darkThemeClass);
63+
this._overlayContainer.getContainerElement().classList.remove(this.darkThemeClass);
64+
}
65+
}

0 commit comments

Comments
 (0)