Skip to content

Commit 54daf9a

Browse files
committed
chore: store dev-app dark/light theme state in localStorage
1 parent bff4e28 commit 54daf9a

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'},
@@ -97,9 +101,39 @@ export class DevAppLayout {
97101

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

105139
toggleFullscreen() {
@@ -116,15 +150,11 @@ export class DevAppLayout {
116150
}
117151
}
118152

119-
toggleTheme() {
120-
const darkThemeClass = 'demo-unicorn-dark-theme';
121-
122-
this.dark = !this.dark;
123-
124-
if (this.dark) {
125-
document.body.classList.add(darkThemeClass);
153+
updateThemeClass(isDark?: boolean) {
154+
if (isDark) {
155+
this._document.body.classList.add(this.darkThemeClass);
126156
} else {
127-
document.body.classList.remove(darkThemeClass);
157+
this._document.body.classList.remove(this.darkThemeClass);
128158
}
129159
}
130160

@@ -134,9 +164,9 @@ export class DevAppLayout {
134164
this.strongFocus = !this.strongFocus;
135165

136166
if (this.strongFocus) {
137-
document.body.classList.add(strongFocusClass);
167+
this._document.body.classList.add(strongFocusClass);
138168
} else {
139-
document.body.classList.remove(strongFocusClass);
169+
this._document.body.classList.remove(strongFocusClass);
140170
}
141171
}
142172

@@ -160,9 +190,9 @@ export class DevAppLayout {
160190
for (let i = 0; i < this.densityScales.length; i++) {
161191
const className = `demo-density-${this.densityScales[i]}`;
162192
if (i === this.currentDensityIndex) {
163-
document.body.classList.add(className);
193+
this._document.body.classList.add(className);
164194
} else {
165-
document.body.classList.remove(className);
195+
this._document.body.classList.remove(className);
166196
}
167197
}
168198
}

0 commit comments

Comments
 (0)