Skip to content

Commit 9d5c2c4

Browse files
Splaktarandrewseguin
authored andcommitted
chore: store dev-app dark/light theme state in localStorage (#18218)
(cherry picked from commit 0665d86)
1 parent 9e6660d commit 9d5c2c4

File tree

2 files changed

+47
-15
lines changed

2 files changed

+47
-15
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)="isDark = !isDark">
37+
{{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: 44 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ import {Directionality} from '@angular/cdk/bidi';
1010
import {ChangeDetectorRef, Component, ElementRef, Inject, ViewEncapsulation} from '@angular/core';
1111
import {DevAppRippleOptions} from './ripple-options';
1212
import {DevAppDirectionality} from './dev-app-directionality';
13+
import {DOCUMENT} from '@angular/common';
14+
15+
const isDarkThemeKey = 'ANGULAR_COMPONENTS_DEV_APP_DARK_THEME';
1316

1417
/** Root component for the dev-app demos. */
1518
@Component({
@@ -19,7 +22,8 @@ import {DevAppDirectionality} from './dev-app-directionality';
1922
encapsulation: ViewEncapsulation.None,
2023
})
2124
export class DevAppLayout {
22-
dark = false;
25+
readonly darkThemeClass = 'demo-unicorn-dark-theme';
26+
_isDark = false;
2327
strongFocus = false;
2428
navItems = [
2529
{name: 'Examples', route: '/examples'},
@@ -99,9 +103,39 @@ export class DevAppLayout {
99103

100104
constructor(
101105
private _element: ElementRef<HTMLElement>, public rippleOptions: DevAppRippleOptions,
102-
@Inject(Directionality) public dir: DevAppDirectionality, cdr: ChangeDetectorRef) {
106+
@Inject(Directionality) public dir: DevAppDirectionality, cdr: ChangeDetectorRef,
107+
@Inject(DOCUMENT) private _document: Document) {
103108
dir.change.subscribe(() => cdr.markForCheck());
104109
this.updateDensityClasses();
110+
try {
111+
const isDark = localStorage.getItem(isDarkThemeKey);
112+
if (isDark != null) {
113+
// We avoid calling the setter and apply the themes directly here.
114+
// This avoids writing the same value, that we just read, back to localStorage.
115+
this._isDark = isDark === 'true';
116+
this.updateThemeClass(this._isDark);
117+
}
118+
} catch (error) {
119+
console.error(`Failed to read ${isDarkThemeKey} from localStorage: `, error);
120+
}
121+
}
122+
123+
get isDark(): boolean {
124+
return this._isDark;
125+
}
126+
127+
set isDark(value: boolean) {
128+
// Noop if the value is the same as is already set.
129+
if (value !== this._isDark) {
130+
this._isDark = value;
131+
this.updateThemeClass(this._isDark);
132+
133+
try {
134+
localStorage.setItem(isDarkThemeKey, String(value));
135+
} catch (error) {
136+
console.error(`Failed to write ${isDarkThemeKey} to localStorage: `, error);
137+
}
138+
}
105139
}
106140

107141
toggleFullscreen() {
@@ -118,15 +152,11 @@ export class DevAppLayout {
118152
}
119153
}
120154

121-
toggleTheme() {
122-
const darkThemeClass = 'demo-unicorn-dark-theme';
123-
124-
this.dark = !this.dark;
125-
126-
if (this.dark) {
127-
document.body.classList.add(darkThemeClass);
155+
updateThemeClass(isDark?: boolean) {
156+
if (isDark) {
157+
this._document.body.classList.add(this.darkThemeClass);
128158
} else {
129-
document.body.classList.remove(darkThemeClass);
159+
this._document.body.classList.remove(this.darkThemeClass);
130160
}
131161
}
132162

@@ -136,9 +166,9 @@ export class DevAppLayout {
136166
this.strongFocus = !this.strongFocus;
137167

138168
if (this.strongFocus) {
139-
document.body.classList.add(strongFocusClass);
169+
this._document.body.classList.add(strongFocusClass);
140170
} else {
141-
document.body.classList.remove(strongFocusClass);
171+
this._document.body.classList.remove(strongFocusClass);
142172
}
143173
}
144174

@@ -162,9 +192,9 @@ export class DevAppLayout {
162192
for (let i = 0; i < this.densityScales.length; i++) {
163193
const className = `demo-density-${this.densityScales[i]}`;
164194
if (i === this.currentDensityIndex) {
165-
document.body.classList.add(className);
195+
this._document.body.classList.add(className);
166196
} else {
167-
document.body.classList.remove(className);
197+
this._document.body.classList.remove(className);
168198
}
169199
}
170200
}

0 commit comments

Comments
 (0)