Skip to content

Commit ffbb0a3

Browse files
BrunnerLivioLivio Brunner
authored andcommitted
feat(theme): add dark mode toggle
1 parent 3e5d13e commit ffbb0a3

File tree

8 files changed

+114
-0
lines changed

8 files changed

+114
-0
lines changed

src/app/app.module.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import { BasePageComponent } from './homepage/pages/page/page.component';
3535
import { PipesComponent } from './homepage/pages/pipes/pipes.component';
3636
import { SupportComponent } from './homepage/pages/support/support.component';
3737
import { SharedModule } from './shared/shared.module';
38+
import { DarkModeToggleComponent } from './homepage/dark-mode-toggle/dark-mode-toggle.component';
3839

3940
const DEFAULT_PERFECT_SCROLLBAR_CONFIG: PerfectScrollbarConfigInterface = {
4041
suppressScrollX: true,
@@ -77,6 +78,7 @@ const DEFAULT_PERFECT_SCROLLBAR_CONFIG: PerfectScrollbarConfigInterface = {
7778
EnterpriseComponent,
7879
SocialWrapperComponent,
7980
NewsletterComponent,
81+
DarkModeToggleComponent,
8082
],
8183
bootstrap: [AppComponent],
8284
providers: [

src/app/common/social-wrapper/social-wrapper.component.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
<div class="social-wrapper">
2+
<app-dark-mode-toggle></app-dark-mode-toggle>
23
<a href="https://twitter.com/nestframework" target="_blank">
34
<i class="fab fa-twitter"></i>
45
</a>

src/app/common/social-wrapper/social-wrapper.component.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
float: right;
66
padding-right: 40px;
77
position: relative;
8+
display: flex;
89

910
a {
1011
@extend .transition-fast;
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
<button class="dark-mode-toggle" (click)="toggleDarkMode()">
2+
<span class="material-icons" *ngIf="!isDarkMode"> light_mode </span>
3+
<span class="material-icons" *ngIf="isDarkMode"> dark_mode </span>
4+
</button>
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
:host {
2+
display: block;
3+
display: flex;
4+
align-items: center;
5+
justify-content: center;
6+
}
7+
8+
.dark-mode-toggle {
9+
// Button reset
10+
border: none;
11+
margin: 0;
12+
padding: 0;
13+
width: auto;
14+
overflow: visible;
15+
background: transparent;
16+
font: inherit;
17+
line-height: normal;
18+
-webkit-font-smoothing: inherit;
19+
-moz-osx-font-smoothing: inherit;
20+
-webkit-appearance: none;
21+
22+
display: flex;
23+
align-items: center;
24+
justify-content: center;
25+
margin-left: 15px;
26+
cursor: pointer;
27+
color: #fff;
28+
29+
&:hover {
30+
color: var(--primary);
31+
}
32+
33+
.material-icons {
34+
font-size: 20px;
35+
}
36+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { ComponentFixture, TestBed } from '@angular/core/testing';
2+
3+
import { DarkModeToggleComponent } from './dark-mode-toggle.component';
4+
5+
describe('DarkModeToggleComponent', () => {
6+
let component: DarkModeToggleComponent;
7+
let fixture: ComponentFixture<DarkModeToggleComponent>;
8+
9+
beforeEach(async () => {
10+
await TestBed.configureTestingModule({
11+
declarations: [ DarkModeToggleComponent ]
12+
})
13+
.compileComponents();
14+
});
15+
16+
beforeEach(() => {
17+
fixture = TestBed.createComponent(DarkModeToggleComponent);
18+
component = fixture.componentInstance;
19+
fixture.detectChanges();
20+
});
21+
22+
it('should create', () => {
23+
expect(component).toBeTruthy();
24+
});
25+
});
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { DOCUMENT } from '@angular/common';
2+
import { Component, Inject, OnInit } from '@angular/core';
3+
4+
@Component({
5+
selector: 'app-dark-mode-toggle',
6+
templateUrl: './dark-mode-toggle.component.html',
7+
styleUrls: ['./dark-mode-toggle.component.scss'],
8+
})
9+
export class DarkModeToggleComponent implements OnInit {
10+
isDarkMode: boolean;
11+
12+
private getUserSettingsIsDarkMode(): boolean {
13+
return localStorage.getItem('DARK_MODE') === 'true';
14+
}
15+
16+
private setDarkMode(isDarkMode: boolean) {
17+
this.isDarkMode = isDarkMode;
18+
this.document.documentElement.setAttribute(
19+
'mode',
20+
isDarkMode ? 'dark' : 'light',
21+
);
22+
}
23+
24+
constructor(@Inject(DOCUMENT) private readonly document: Document) {}
25+
26+
ngOnInit() {
27+
const userPrefersDark =
28+
window.matchMedia &&
29+
window.matchMedia('(prefers-color-scheme: dark)').matches;
30+
// In case the user has used the toggle button, we prioritize it over the
31+
// system settings
32+
this.setDarkMode(this.getUserSettingsIsDarkMode() || userPrefersDark);
33+
}
34+
35+
toggleDarkMode() {
36+
const isDarkMode = !this.isDarkMode;
37+
localStorage.setItem('DARK_MODE', isDarkMode.toString());
38+
this.setDarkMode(isDarkMode);
39+
}
40+
}

src/styles.scss

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@ body {
2626
color: var(--color);
2727
margin: 0;
2828
-webkit-font-smoothing: antialiased;
29+
-webkit-transition: background 200ms cubic-bezier(0.7, 0, 0.3, 1);
30+
-moz-transition: background 200ms cubic-bezier(0.7, 0, 0.3, 1);
31+
-ms-transition: background 200ms cubic-bezier(0.7, 0, 0.3, 1);
32+
-o-transition: background 200ms cubic-bezier(0.7, 0, 0.3, 1);
33+
transition: background 200ms cubic-bezier(0.7, 0, 0.3, 1);
2934
}
3035

3136
a {

0 commit comments

Comments
 (0)