Skip to content

Commit 83ac855

Browse files
committed
feat: add dark mode
1 parent b7e24bf commit 83ac855

12 files changed

+280
-235
lines changed

angular.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,12 @@
3636
"src/manifest.webmanifest"
3737
],
3838
"styles": [
39-
"src/styles.scss"
39+
"src/styles.scss",
40+
{
41+
"input": "src/src/styles/themes/dark.scss",
42+
"bundleName": "dark-theme",
43+
"inject": false
44+
}
4045
],
4146
"scripts": [
4247
"node_modules/algoliasearch/dist/algoliasearch.umd.js",

src/app/app.component.css

Lines changed: 29 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,11 @@
1-
section span {
1+
:host {
22
display: block;
3-
padding: 10px;
3+
height: 100vh;
44
}
55

6-
mat-toolbar {
7-
text-align: center;
8-
border-bottom: 5px solid;
9-
position: fixed;
10-
top: 0;
11-
z-index: 1;
6+
section span {
7+
display: block;
8+
padding: 10px;
129
}
1310

1411
main {
@@ -40,36 +37,51 @@ main {
4037
text-transform: uppercase;
4138
}
4239

43-
footer {
40+
mat-toolbar {
41+
text-align: center;
42+
position: fixed;
43+
top: 0;
44+
z-index: 2;
4445
padding: 10px 0;
4546
position: fixed;
46-
bottom: 0;
47-
border-top: 4px solid;
47+
border-bottom: 5px solid var(--logo-background-color);
4848
width: 100%;
4949
font-size: 0.8em;
50-
background-color: white;
5150
display: flex;
52-
justify-content: center;
53-
z-index: 1;
51+
justify-content: flex-start;
52+
z-index: 10;
5453
}
5554

56-
footer a {
55+
mat-toolbar a {
5756
font-weight: bold;
5857
text-decoration: underline;
5958
}
6059

61-
footer a img {
60+
mat-toolbar a img {
6261
top: 2px;
6362
display: inline-block;
6463
position: relative;
6564
}
6665

66+
mat-toolbar.main-footer {
67+
top: unset;
68+
bottom: 0;
69+
justify-content: center;
70+
border-top: 4px solid var(--logo-background-color);
71+
border-bottom: unset;
72+
}
73+
6774
mat-sidenav {
6875
border-right: 6px solid;
6976
padding: 4px;
7077
}
7178

72-
.menu_button {
79+
.button__menu {
80+
position: absolute;
81+
}
82+
83+
.button__back {
84+
left: 40px;
7385
position: absolute;
7486
}
7587

src/app/app.component.html

Lines changed: 35 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,6 @@
1-
<mat-sidenav-container class="layout__fix-height">
2-
<mat-sidenav
3-
#snav
4-
fixedInViewport="true"
5-
mode="push"
6-
fixedBottomGap="0"
7-
autoFocus="true"
8-
class="ngxtools-palette-accent ngxtools-palette-accent-border layout__fix-height"
9-
>
10-
<mat-nav-list class="ngxtools-palette-accent-text">
11-
<mat-accordion>
12-
<mat-expansion-panel
13-
class="ngxtools-palette-accent ngxtools-palette-accent-border"
14-
>
15-
<mat-expansion-panel-header>
16-
<mat-panel-title>
17-
Themes
18-
</mat-panel-title>
19-
</mat-expansion-panel-header>
20-
<app-theme-chooser></app-theme-chooser>
21-
</mat-expansion-panel>
22-
</mat-accordion>
1+
<mat-sidenav-container fullscreen>
2+
<mat-sidenav #snav fixedInViewport="true" mode="push" fixedBottomGap="0">
3+
<mat-nav-list>
234
<a
245
mat-list-item
256
target="__blank"
@@ -30,39 +11,54 @@
3011
</mat-nav-list>
3112
</mat-sidenav>
3213

33-
<mat-sidenav-content class="layout__fix-height">
34-
<mat-toolbar
35-
class="ngxtools-palette-accent ngxtools-palette-primary-border"
36-
>
37-
<button mat-icon-button (click)="snav.toggle()" class="menu_button">
14+
<mat-sidenav-content>
15+
<mat-toolbar class="main-header border-gradient border-gradient-purple">
16+
<button mat-icon-button (click)="snav.toggle()" class="button__menu">
3817
<mat-icon>menu</mat-icon>
3918
</button>
40-
<span class="header__logo ngxtools-palette-primary-text"></span>
19+
<button mat-icon-button class="button__back" *ngIf="shouldShowBackButton()" (click)="navigateBack()">
20+
<mat-icon>arrow_back</mat-icon>
21+
</button>
22+
<a routerLink="/" class="header__logo"></a>
4123
<a
4224
mat-icon-button
4325
target="__blank"
4426
href="https://github.com/ngxtools/ngx.tools/issues"
4527
>
4628
<mat-icon>bug_report</mat-icon>
4729
</a>
30+
<button
31+
mat-icon-button
32+
(click)="toggleDarkTheme()"
33+
class="theme-toggle"
34+
aria-label="Toggle Dark Theme"
35+
>
36+
<mat-icon>{{ isDarkMode() ? "dark_mode" : "light_mode" }}</mat-icon>
37+
</button>
4838
</mat-toolbar>
4939

50-
<main class="layout__fix-height">
40+
<main class="search-result">
5141
<router-outlet></router-outlet>
5242
</main>
5343

54-
<footer
55-
class="ngxtools-palette-accent ngxtools-palette-warn-text ngxtools-palette-primary-border"
56-
>
44+
<mat-toolbar class="main-footer border-gradient border-gradient-purple">
5745
<span>
5846
Built with ❤ by
59-
<a
60-
class="ngxtools-palette-warn-text"
61-
href="https://twitter.com/manekinekko"
62-
>Wassim Chegham</a
63-
>
47+
<a href="https://twitter.com/manekinekko">Wassim Chegham</a>
6448
</span>
65-
&nbsp;&nbsp;<span>// Build: {{ version }}</span>
66-
</footer>
49+
&nbsp;&nbsp;|&nbsp;&nbsp;<span> Build: {{ version }}</span>
50+
&nbsp;&nbsp;|&nbsp;&nbsp;
51+
<a
52+
href="https://www.algolia.com"
53+
target="__blank"
54+
class="algolia-credits"
55+
>
56+
<img
57+
width="100"
58+
src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNjgiIGhlaWdodD0iMjQiPjxnIGZpbGw9Im5vbmUiPjxwYXRoIGZpbGw9IiM1NDY4RkYiIGQ9Ik03OC45ODguOTM4aDE2LjU5NGEyLjk2OCAyLjk2OCAwIDAgMSAyLjk2NiAyLjk2NlYyMC41YTIuOTY3IDIuOTY3IDAgMCAxLTIuOTY2IDIuOTY0SDc4Ljk4OGEyLjk2NyAyLjk2NyAwIDAgMS0yLjk2Ni0yLjk2NFYzLjg5N0EyLjk2MSAyLjk2MSAwIDAgMSA3OC45ODguOTM4em00MS45MzcgMTcuODY2Yy00LjM4Ni4wMi00LjM4Ni0zLjU0LTQuMzg2LTQuMTA2bC0uMDA3LTEzLjMzNiAyLjY3NS0uNDI0djEzLjI1NGMwIC4zMjIgMCAyLjM1OCAxLjcxOCAyLjM2NHYyLjI0OHptLTEwLjg0Ni0yLjE4Yy44MjEgMCAxLjQzLS4wNDcgMS44NTUtLjEyOXYtMi43MTlhNi4zMzQgNi4zMzQgMCAwIDAtMS41NzQtLjE5OSA1LjcgNS43IDAgMCAwLS44OTcuMDY5IDIuNjk5IDIuNjk5IDAgMCAwLS44MTQuMjRjLS4yNC4xMTYtLjQzOS4yOC0uNTgyLjQ5MS0uMTUuMjEyLS4yMTkuMzM1LS4yMTkuNjU2IDAgLjYyOC4yMTkuOTkxLjYxNiAxLjIzcy45MzguMzYyIDEuNjE1LjM2MnptLS4yMzMtOS43Yy44ODMgMCAxLjYyOS4xMDkgMi4yMzEuMzI4LjYwMi4yMTggMS4wODguNTI1IDEuNDQ0LjkxNS4zNjMuMzk2LjYwOS45MjIuNzYgMS40ODMuMTU3LjU2LjIzMiAxLjE3NS4yMzIgMS44NXY2Ljg3NGEzMi41IDMyLjUgMCAwIDEtMS44NjguMzE0Yy0uODM0LjEyMy0xLjc3Mi4xODUtMi44MTMuMTg1LS42OSAwLTEuMzI3LS4wNjktMS44OTUtLjE5OGE0LjAwMSA0LjAwMSAwIDAgMS0xLjQ3MS0uNjM2IDMuMDg1IDMuMDg1IDAgMCAxLS45NTEtMS4xMzRjLS4yMjYtLjQ2NS0uMzQzLTEuMTItLjM0My0xLjgwMyAwLS42NTYuMTMtMS4wNzMuMzg0LTEuNTI1YTMuMjQgMy4yNCAwIDAgMSAxLjA0Ny0xLjEwNmMuNDQ1LS4yODcuOTUtLjQ5MiAxLjUzMi0uNjE1YTguOCA4LjggMCAwIDEgMS44Mi0uMTg1IDguNDA0IDguNDA0IDAgMCAxIDEuOTcyLjI0di0uNDM4YzAtLjMwNy0uMDM1LS42LS4xMS0uODc0YTEuODggMS44OCAwIDAgMC0uMzg0LS43MyAxLjc4NCAxLjc4NCAwIDAgMC0uNzI0LS40OTMgMy4xNjQgMy4xNjQgMCAwIDAtMS4xNDMtLjIwNWMtLjYxNiAwLTEuMTc3LjA3NS0xLjY5LjE2NGE3LjczNSA3LjczNSAwIDAgMC0xLjI2LjMwN2wtLjMyMS0yLjE5MmMuMzM1LS4xMTcuODM0LS4yMzMgMS40NzgtLjM0OWExMC45OCAxMC45OCAwIDAgMSAyLjA3My0uMTc4em01Mi44NDIgOS42MjZjLjgyMiAwIDEuNDMtLjA0OCAxLjg1NC0uMTNWMTMuN2E2LjM0NyA2LjM0NyAwIDAgMC0xLjU3NC0uMTk5Yy0uMjk0IDAtLjU5NS4wMjEtLjg5Ni4wNjlhMi43IDIuNyAwIDAgMC0uODE0LjI0IDEuNDYgMS40NiAwIDAgMC0uNTgyLjQ5MWMtLjE1LjIxMi0uMjE4LjMzNS0uMjE4LjY1NiAwIC42MjguMjE4Ljk5MS42MTUgMS4yMy40MDQuMjQ1LjkzOC4zNjIgMS42MTUuMzYyem0tLjIyNi05LjY5NGMuODgzIDAgMS42MjkuMTA4IDIuMjMxLjMyNy42MDIuMjE5IDEuMDg4LjUyNiAxLjQ0NC45MTUuMzU1LjM5LjYwOS45MjMuNzU5IDEuNDgzYTYuOCA2LjggMCAwIDEgLjIzMyAxLjg1MnY2Ljg3M2MtLjQxLjA4OC0xLjAzNC4xOS0xLjg2OC4zMTQtLjgzNC4xMjMtMS43NzIuMTg0LTIuODEzLjE4NC0uNjkgMC0xLjMyNy0uMDY4LTEuODk1LS4xOThhNC4wMDEgNC4wMDEgMCAwIDEtMS40NzEtLjYzNSAzLjA4NSAzLjA4NSAwIDAgMS0uOTUxLTEuMTM0Yy0uMjI2LS40NjUtLjM0My0xLjEyLS4zNDMtMS44MDQgMC0uNjU2LjEzLTEuMDczLjM4NC0xLjUyNC4yNi0uNDUuNjA4LS44MiAxLjA0Ny0xLjEwNy40NDUtLjI4Ni45NS0uNDkxIDEuNTMyLS42MTRhOC44MDMgOC44MDMgMCAwIDEgMi43NTEtLjEzYy4zMjkuMDM0LjY3MS4wOTYgMS4wNC4xODV2LS40MzdhMy4zIDMuMyAwIDAgMC0uMTA5LS44NzUgMS44NzMgMS44NzMgMCAwIDAtLjM4NC0uNzMxIDEuNzg0IDEuNzg0IDAgMCAwLS43MjQtLjQ5MiAzLjE2NSAzLjE2NSAwIDAgMC0xLjE0My0uMjA1Yy0uNjE2IDAtMS4xNzcuMDc1LTEuNjkuMTY0YTcuNzUgNy43NSAwIDAgMC0xLjI2LjMwN2wtLjMyMS0yLjE5M2MuMzM1LS4xMTYuODM0LS4yMzIgMS40NzgtLjM0OGExMS42MzMgMTEuNjMzIDAgMCAxIDIuMDczLS4xNzd6bS04LjAzNC0xLjI3MWExLjYyNiAxLjYyNiAwIDAgMS0xLjYyOC0xLjYyYzAtLjg5NS43MjUtMS42MiAxLjYyOC0xLjYyLjkwNCAwIDEuNjMuNzI1IDEuNjMgMS42MiAwIC44OTUtLjczMyAxLjYyLTEuNjMgMS42MnptMS4zNDggMTMuMjJoLTIuNjg5VjcuMjdsMi42OS0uNDIzdjExLjk1NnptLTQuNzE0IDBjLTQuMzg2LjAyLTQuMzg2LTMuNTQtNC4zODYtNC4xMDdsLS4wMDgtMTMuMzM2IDIuNjc2LS40MjR2MTMuMjU0YzAgLjMyMiAwIDIuMzU4IDEuNzE4IDIuMzY0djIuMjQ4em0tOC42OTgtNS45MDNjMC0xLjE1Ni0uMjUzLTIuMTE5LS43NDYtMi43ODgtLjQ5My0uNjc3LTEuMTgzLTEuMDEtMi4wNjctMS4wMS0uODgyIDAtMS41NzQuMzMzLTIuMDY1IDEuMDEtLjQ5My42NzYtLjczMyAxLjYzMi0uNzMzIDIuNzg4IDAgMS4xNjguMjQ2IDEuOTUzLjc0IDIuNjMuNDkyLjY4MyAxLjE4MyAxLjAxOCAyLjA2NiAxLjAxOC44ODIgMCAxLjU3NC0uMzQyIDIuMDY3LTEuMDE5LjQ5Mi0uNjgzLjczOC0xLjQ2LjczOC0yLjYzem0yLjczNy0uMDA3YzAgLjkwMi0uMTMgMS41ODQtLjM5NyAyLjMzYTUuNTIgNS41MiAwIDAgMS0xLjEyOCAxLjkwNiA0Ljk4NiA0Ljk4NiAwIDAgMS0xLjc1MiAxLjIyM2MtLjY4NS4yODYtMS43MzkuNDUtMi4yNjUuNDUtLjUyOC0uMDA2LTEuNTc0LS4xNTctMi4yNTItLjQ1YTUuMDk2IDUuMDk2IDAgMCAxLTEuNzQ0LTEuMjIzYy0uNDg3LS41MjctLjg2My0xLjE2Mi0xLjEzNy0xLjkwNmE2LjM0NSA2LjM0NSAwIDAgMS0uNDEtMi4zM2MwLS45MDIuMTIzLTEuNzcuMzk3LTIuNTA4YTUuNTU0IDUuNTU0IDAgMCAxIDEuMTUtMS44OTIgNS4xMzMgNS4xMzMgMCAwIDEgMS43NS0xLjIxNmMuNjc5LS4yODcgMS40MjUtLjQyMyAyLjIzMi0uNDIzLjgwOCAwIDEuNTUzLjE0MiAyLjIzNy40MjNhNC44OCA0Ljg4IDAgMCAxIDEuNzUzIDEuMjE2IDUuNjQ0IDUuNjQ0IDAgMCAxIDEuMTM1IDEuODkyYy4yODcuNzM4LjQzMSAxLjYwNi40MzEgMi41MDh6bS0yMC4xMzggMGMwIDEuMTIuMjQ2IDIuMzYzLjczOCAyLjg4Mi40OTMuNTIgMS4xMy43OCAxLjkxLjc4LjQyNCAwIC44MjgtLjA2MiAxLjIwNC0uMTc4LjM3Ny0uMTE2LjY3Ny0uMjUzLjkxNy0uNDE3VjkuMzNhMTAuNDc2IDEwLjQ3NiAwIDAgMC0xLjc2Ni0uMjI2Yy0uOTcxLS4wMjgtMS43MS4zNy0yLjIzIDEuMDA0LS41MTMuNjM2LS43NzMgMS43NS0uNzczIDIuNzg4em03LjQzOCA1LjI3NGMwIDEuODI0LS40NjYgMy4xNTYtMS40MDQgNC4wMDQtLjkzNi44NDYtMi4zNjcgMS4yNy00LjI5NiAxLjI3LS43MDUgMC0yLjE3LS4xMzctMy4zNC0uMzk2bC40MzEtMi4xMThjLjk4LjIwNSAyLjI3Mi4yNiAyLjk1LjI2IDEuMDc0IDAgMS44NC0uMjE5IDIuMjk5LS42NTYuNDU5LS40MzcuNjg0LTEuMDg2LjY4NC0xLjk0OHYtLjQzN2E4LjA3IDguMDcgMCAwIDEtMS4wNDcuMzk3Yy0uNDMuMTMtLjkzLjE5OC0xLjQ5Mi4xOTgtLjczOSAwLTEuNDEtLjExNi0yLjAxOC0uMzQ5YTQuMjA2IDQuMjA2IDAgMCAxLTEuNTY3LTEuMDI1Yy0uNDMxLS40NS0uNzc0LTEuMDE3LTEuMDEzLTEuNjk0LS4yNC0uNjc3LS4zNjMtMS44ODUtLjM2My0yLjc3MyAwLS44MzQuMTMtMS44OC4zODQtMi41NzcuMjYtLjY5Ni42MjktMS4yOTggMS4xMjktMS43OTYuNDkzLS40OTggMS4wOTUtLjg4MSAxLjgtMS4xNjJhNi42MDUgNi42MDUgMCAwIDEgMi40MjgtLjQ1N2MuODcgMCAxLjY3LjEwOSAyLjQ1LjI0Ljc4LjEyOSAxLjQ0NC4yNjUgMS45ODUuNDE1VjE4LjE3eiIvPjxwYXRoIGZpbGw9IiM1RDY0OTQiIGQ9Ik02Ljk3MiA2LjY3N3YxLjYyN2MtLjcxMi0uNDQ2LTEuNTItLjY3LTIuNDI1LS42Ny0uNTg1IDAtMS4wNDUuMTMtMS4zOC4zOTFhMS4yNCAxLjI0IDAgMCAwLS41MDIgMS4wM2MwIC40MjUuMTY0Ljc2NS40OTQgMS4wMi4zMy4yNTYuODM1LjUzMiAxLjUxNi44My40NDcuMTkyLjc5NS4zNTYgMS4wNDUuNDk1LjI1LjEzOC41MzcuMzMyLjg2Mi41ODIuMzI0LjI1LjU2My41NDguNzE4Ljg5NC4xNTQuMzQ1LjIzLjc0MS4yMyAxLjE4OCAwIC45NDctLjMzNCAxLjY5MS0xLjAwNCAyLjIzNC0uNjcuNTQyLTEuNTM3LjgxNC0yLjYwMS44MTQtMS4xOCAwLTIuMTYtLjIyOS0yLjkzNi0uNjg2di0xLjcwOGMuODQuNjI4IDEuODE0Ljk0MiAyLjkyLjk0Mi41ODUgMCAxLjA0OC0uMTM2IDEuMzg4LS40MDcuMzQtLjI3MS41MS0uNjQ2LjUxLTEuMTI1IDAtLjI4Ny0uMS0uNTUtLjMwMi0uNzktLjIwMy0uMjQtLjQyLS40Mi0uNjU1LS41NDItLjIzNC0uMTIzLS41ODUtLjI5LTEuMDUzLS41MDNhNjEuMjcgNjEuMjcgMCAwIDEtLjU4Mi0uMjcxIDEzLjY3IDEzLjY3IDAgMCAxLS41NS0uMjg3IDQuMjc1IDQuMjc1IDAgMCAxLS41NjctLjM1MSA2LjkyIDYuOTIgMCAwIDEtLjQ1NS0uNGMtLjE4LS4xNy0uMzEtLjM0LS4zOS0uNTEtLjA4LS4xNy0uMTU1LS4zNy0uMjI0LS41OThhMi41NTMgMi41NTMgMCAwIDEtLjEwNC0uNzQyYzAtLjkxNS4zMzMtMS42MzguOTk4LTIuMTcuNjY0LS41MzIgMS41MjMtLjc5OCAyLjU3Ni0uNzk4Ljk2OCAwIDEuNzkzLjE3IDIuNDczLjUxem03LjQ2OCA1LjY5NnYtLjI4N2MtLjAyMi0uNjA3LS4xODctMS4wODgtLjQ5NS0xLjQ0NC0uMzA5LS4zNTctLjc1LS41MzUtMS4zMjQtLjUzNS0uNTMyIDAtLjk5LjE5NC0xLjM3My41ODMtLjM4Mi4zODgtLjYyMi45NDktLjcxNyAxLjY4M2gzLjkwOXptMS4wMDUgMi43OTJ2MS40MDRjLS41OTYuMzQtMS4zODMuNTEtMi4zNjIuNTEtMS4yNTUgMC0yLjI1NS0uMzc3LTMtMS4xMzItLjc0NC0uNzU1LTEuMTE2LTEuNzQ0LTEuMTE2LTIuOTY4IDAtMS4yOTcuMzQtMi4zMTYgMS4wMjEtMy4wNTUuNjgtLjc0IDEuNTQ4LTEuMTEgMi42LTEuMTEgMS4wMzMgMCAxLjg1Mi4zMjMgMi40NTguOTY2LjYwNi42NDQuOTEgMS41NzIuOTEgMi43ODQgMCAuMzMtLjAzMy42NzYtLjA5NiAxLjAzOGgtNS4zMTRjLjEwNy43MDIuNDA1IDEuMjM5Ljg5NCAxLjYxMS40OS4zNzIgMS4xMDYuNTU4IDEuODUuNTU4Ljg2MiAwIDEuNTgtLjIwMiAyLjE1NS0uNjA2em02LjYwNS0xLjc3aC0xLjIxMmMtLjU5NiAwLTEuMDQ1LjExNi0xLjM0OS4zNS0uMzAzLjIzNC0uNDU0LjUzMi0uNDU0Ljg5NCAwIC4zNzIuMTE3LjY2NC4zNS44NzcuMjM1LjIxMy41NzUuMzIgMS4wMjIuMzIuNTEgMCAuOTEyLS4xNDIgMS4yMDQtLjQyNC4yOTMtLjI4MS40NC0uNjUxLjQ0LTEuMTA4di0uOTF6bS00LjA2OC0yLjU1NFY5LjMyNWMuNjI3LS4zNjEgMS40NTctLjU0MiAyLjQ4OS0uNTQyIDIuMTE2IDAgMy4xNzUgMS4wMjYgMy4xNzUgMy4wOFYxN2gtMS41NDh2LS45NTdjLS40MTUuNjgtMS4xNDMgMS4wMi0yLjE4NiAxLjAyLS43NjYgMC0xLjM4LS4yMi0xLjg0My0uNjYxLS40NjItLjQ0Mi0uNjk0LTEuMDAzLS42OTQtMS42ODQgMC0uNzc2LjI5My0xLjM4Ljg3OC0xLjgxLjU4NS0uNDMxIDEuNDA0LS42NDcgMi40NTctLjY0N2gxLjM0VjExLjhjMC0uNTU0LS4xMzMtLjk3MS0uMzk5LTEuMjUzLS4yNjYtLjI4Mi0uNzA3LS40MjMtMS4zMjQtLjQyM2E0LjA3IDQuMDcgMCAwIDAtMi4zNDUuNzE4em05LjMzMy0xLjkzdjEuNDJjLjM5NC0xIDEuMTAxLTEuNSAyLjEyMy0xLjUuMTQ4IDAgLjMxMy4wMTYuNDk0LjA0OHYxLjUzMWExLjg4NSAxLjg4NSAwIDAgMC0uNzUtLjE0M2MtLjU0MiAwLS45ODkuMjQtMS4zNC43MTgtLjM1MS40NzktLjUyNyAxLjA0OC0uNTI3IDEuNzA3VjE3aC0xLjU2M1Y4LjkxaDEuNTYzem01LjAxIDQuMDg0Yy4wMjIuODIuMjcyIDEuNDkyLjc1IDIuMDE5LjQ3OS41MjYgMS4xNS43OSAyLjAxLjc5LjYzOSAwIDEuMjM1LS4xNzYgMS43ODgtLjUyN3YxLjQwNGMtLjUyMS4zMTktMS4xODYuNDc5LTEuOTk1LjQ3OS0xLjI2NSAwLTIuMjc2LS40LTMuMDMxLTEuMTk3LS43NTUtLjc5OC0xLjEzMy0xLjc5Mi0xLjEzMy0yLjk4NCAwLTEuMTYuMzgtMi4xNTEgMS4xNC0yLjk3NS43NjEtLjgyNSAxLjc5LTEuMjM3IDMuMDg4LTEuMjM3LjcwMiAwIDEuMzQ2LjE0OSAxLjkzLjQ0N3YxLjQzNmEzLjI0MiAzLjI0MiAwIDAgMC0xLjc3LS40OTVjLS44NCAwLTEuNTEzLjI2Ni0yLjAxOS43OTgtLjUwNS41MzItLjc1OCAxLjIxMy0uNzU4IDIuMDQyek00MC4yNCA1LjcydjQuNTc5Yy40NTgtMSAxLjI5My0xLjUgMi41MDUtMS41Ljc4NyAwIDEuNDIuMjQ1IDEuODk5LjczNC40NzkuNDkuNzE4IDEuMTcuNzE4IDIuMDQyVjE3aC0xLjU2NHYtNS4xMDZjMC0uNTUzLS4xNC0uOTgtLjQyMi0xLjI4NC0uMjgyLS4zMDMtLjY1Mi0uNDU1LTEuMTEtLjQ1NS0uNTMxIDAtMS4wMDIuMjAyLTEuNDExLjYwNi0uNDEuNDA1LS42MTUgMS4wMjItLjYxNSAxLjg1MVYxN2gtMS41NjNWNS43MmgxLjU2M3ptMTQuOTY2IDEwLjAyYy41OTYgMCAxLjA5Ni0uMjUzIDEuNS0uNzU4LjQwNC0uNTA2LjYwNi0xLjE1Ny42MDYtMS45NTUgMC0uOTE1LS4yMDItMS42Mi0uNjA2LTIuMTE0LS40MDQtLjQ5NS0uOTItLjc0Mi0xLjU0OC0uNzQyLS41NTMgMC0xLjA1LjIyNC0xLjQ5MS42Ny0uNDQyLjQ0Ny0uNjYyIDEuMTMzLS42NjIgMi4wNTggMCAuOTU4LjIxMiAxLjY3LjYzOCAyLjEzOC40MjUuNDY5Ljk0Ni43MDMgMS41NjMuNzAzek01My4wMDQgNS43MnY0LjQyYy41NzQtLjg5NCAxLjM4OC0xLjM0MSAyLjQ0LTEuMzQxIDEuMDIyIDAgMS44NTcuMzgzIDIuNTA2IDEuMTQ5LjY0OS43NjYuOTczIDEuNzgxLjk3MyAzLjA0NyAwIDEuMTM4LS4zMDkgMi4xMDktLjkyNSAyLjkxMi0uNjE3LjgwMy0xLjQ2MyAxLjIwNS0yLjUzNyAxLjIwNS0xLjA3NSAwLTEuODk0LS40NDctMi40NTctMS4zNFYxN2gtMS41OFY1LjcyaDEuNTh6bTkuOTA4IDExLjEwNGwtMy4yMjMtNy45MTNoMS43MzlsMS4wMDUgMi42MzIgMS4yNiAzLjQxNWMuMDk2LS4zMi40OC0xLjQ1OCAxLjE1LTMuNDE1bC45MDktMi42MzJoMS42NmwtMi45MiA3Ljg2NmMtLjc3NyAyLjA3NC0xLjk2MyAzLjExLTMuNTU5IDMuMTFhMi45MiAyLjkyIDAgMCAxLS43MzQtLjA3OXYtMS4zNGMuMTcuMDQyLjM1MS4wNjQuNTQzLjA2NCAxLjAzMiAwIDEuNzU1LS41NyAyLjE3LTEuNzA4eiIvPjxwYXRoIGZpbGw9IiNGRkYiIGQ9Ik04OS42MzIgNS45Njd2LS43NzJhLjk3OC45NzggMCAwIDAtLjk3OC0uOTc3aC0yLjI4YS45NzguOTc4IDAgMCAwLS45NzguOTc3di43OTNjMCAuMDg4LjA4Mi4xNS4xNzEuMTNhNy4xMjcgNy4xMjcgMCAwIDEgMS45ODQtLjI4Yy42NSAwIDEuMjk1LjA4OCAxLjkxNy4yNTkuMDgyLjAyLjE2NC0uMDQuMTY0LS4xM20tNi4yNDggMS4wMWwtLjM5LS4zODlhLjk3Ny45NzcgMCAwIDAtMS4zODIgMGwtLjQ2NS40NjVhLjk3My45NzMgMCAwIDAgMCAxLjM4bC4zODMuMzgzYy4wNjIuMDYxLjE1LjA0Ny4yMDUtLjAxNC4yMjYtLjMwNy40NzItLjYwMS43NDYtLjg3NC4yODEtLjI4LjU2OC0uNTI2Ljg4My0uNzUxLjA2OC0uMDQyLjA3NS0uMTM3LjAyLS4ybTQuMTYgMi40NTN2My4zNDFjMCAuMDk2LjEwNC4xNjUuMTkyLjExN2wyLjk3LTEuNTM3Yy4wNjgtLjAzNC4wODktLjExNy4wNTUtLjE4NGEzLjY5NSAzLjY5NSAwIDAgMC0zLjA4LTEuODY2Yy0uMDY4IDAtLjEzNi4wNTQtLjEzNi4xM20wIDguMDQ4YTQuNDg5IDQuNDg5IDAgMCAxLTQuNDktNC40ODIgNC40ODggNC40ODggMCAwIDEgNC40OS00LjQ4MiA0LjQ4OCA0LjQ4OCAwIDAgMSA0LjQ4OSA0LjQ4MiA0LjQ4NCA0LjQ4NCAwIDAgMS00LjQ5IDQuNDgybTAtMTAuODVhNi4zNjMgNi4zNjMgMCAxIDAgMCAxMi43MjkgNi4zNyA2LjM3IDAgMCAwIDYuMzcyLTYuMzY4IDYuMzU4IDYuMzU4IDAgMCAwLTYuMzcxLTYuMzYiLz48L2c+PC9zdmc+"
59+
alt="algolia logo"
60+
/>
61+
</a>
62+
</mat-toolbar>
6763
</mat-sidenav-content>
6864
</mat-sidenav-container>

src/app/app.component.ts

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1-
import { Component } from '@angular/core';
1+
import { Component, signal } from '@angular/core';
2+
import { Event, Router, RoutesRecognized } from '@angular/router';
23
import { environment } from 'src/environments/environment';
34
import { PromptUpdateService } from './prompt-update.service';
5+
import { ThemeManagerService } from './shared/theme-manager.service';
46

57
@Component({
68
selector: 'app-root',
@@ -9,8 +11,30 @@ import { PromptUpdateService } from './prompt-update.service';
911
})
1012
export class AppComponent {
1113
version = environment.version;
14+
isDarkMode = signal(false);
15+
shouldShowBackButton = signal(false);
1216

13-
constructor(private promptUpdateService: PromptUpdateService) {
17+
constructor(
18+
private promptUpdateService: PromptUpdateService,
19+
private themeManager: ThemeManagerService, router: Router) {
1420
this.promptUpdateService.check();
21+
this.isDarkMode.set(this.themeManager.isDarkMode);
22+
23+
router.events.subscribe((event: Event) => {
24+
if (event instanceof RoutesRecognized) {
25+
const { url } = event
26+
this.shouldShowBackButton.set(url.startsWith('/pkg'));
27+
}
28+
});
29+
}
30+
31+
toggleDarkTheme() {
32+
this.themeManager.toggleDarkTheme();
33+
this.isDarkMode.mutate(() => this.isDarkMode.set(this.themeManager.isDarkMode));
1534
}
35+
36+
navigateBack() {
37+
window.history.back();
38+
}
39+
1640
}

src/app/app.module.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
1+
import { NgModule } from '@angular/core';
2+
import { BrowserModule } from '@angular/platform-browser';
13
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
24
import { SharedModule } from './shared/shared.module';
3-
import { BrowserModule } from '@angular/platform-browser';
4-
import { NgModule } from '@angular/core';
55

6-
import { AppComponent } from './app.component';
7-
import { CoreModule } from './core/core.module';
8-
import { AppRoutingModule } from './app-routing.module';
9-
import { ThemeChooserComponent } from './theme-chooser/theme-chooser.component';
106
import { ServiceWorkerModule } from '@angular/service-worker';
117
import { environment } from '../environments/environment';
8+
import { AppRoutingModule } from './app-routing.module';
9+
import { AppComponent } from './app.component';
10+
import { CoreModule } from './core/core.module';
11+
import { DetailsComponent } from './details/details.component';
1212

1313
@NgModule({
14-
declarations: [AppComponent, ThemeChooserComponent],
14+
declarations: [AppComponent, DetailsComponent],
1515
imports: [
1616
BrowserModule,
1717
BrowserAnimationsModule,
@@ -28,4 +28,4 @@ import { environment } from '../environments/environment';
2828
providers: [],
2929
bootstrap: [AppComponent]
3030
})
31-
export class AppModule {}
31+
export class AppModule { }
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
2+
import { DOCUMENT } from '@angular/common';
3+
import { Inject, Injectable } from '@angular/core';
4+
5+
@Injectable({ providedIn: 'root' })
6+
export class ThemeManagerService {
7+
isDarkMode = false;
8+
9+
constructor(@Inject(DOCUMENT) private document: Document) {
10+
this.isDarkMode = this.#readThemePreference('ngxtools-theme-mode') === 'dark';
11+
if (this.isDarkMode) {
12+
this.#enableDarkTheme();
13+
}
14+
}
15+
16+
toggleDarkTheme() {
17+
if (this.isDarkMode) {
18+
this.#disableDarkTheme();
19+
} else {
20+
this.#enableDarkTheme();
21+
}
22+
23+
this.isDarkMode = !this.isDarkMode;
24+
this.#saveThemePreference('ngxtools-theme-mode', this.isDarkMode);
25+
}
26+
27+
#disableDarkTheme() {
28+
this.#removeStyle('dark-theme');
29+
this.document.body.classList.remove('dark-theme');
30+
}
31+
32+
#enableDarkTheme() {
33+
const href = 'dark-theme.css';
34+
this.#getLinkElementForKey('dark-theme').setAttribute('href', href);
35+
this.document.body.classList.add('dark-theme');
36+
}
37+
38+
#removeStyle(key: string) {
39+
const existingLinkElement = this.#getExistingLinkElementByKey(key);
40+
if (existingLinkElement) {
41+
this.document.head.removeChild(existingLinkElement);
42+
}
43+
}
44+
45+
#saveThemePreference(key: string, status: boolean) {
46+
localStorage.setItem(key, status ? 'dark' : 'light');
47+
}
48+
49+
#readThemePreference(key: string) {
50+
return localStorage.getItem(key) || 'light';
51+
}
52+
53+
#getLinkElementForKey(key: string) {
54+
return this.#getExistingLinkElementByKey(key) || this.#createLinkElementWithKey(key);
55+
}
56+
57+
#getExistingLinkElementByKey(key: string) {
58+
return this.document.head.querySelector(
59+
`link[rel="stylesheet"].${this.#getClassNameForKey(key)}`
60+
);
61+
}
62+
63+
#createLinkElementWithKey(key: string) {
64+
const linkEl = this.document.createElement('link');
65+
linkEl.setAttribute('rel', 'stylesheet');
66+
linkEl.classList.add(this.#getClassNameForKey(key));
67+
this.document.head.appendChild(linkEl);
68+
return linkEl;
69+
}
70+
71+
#getClassNameForKey(key: string) {
72+
return `theme-${key}`;
73+
}
74+
}

0 commit comments

Comments
 (0)