Skip to content

Commit 3d0aa67

Browse files
committed
merged @vbakke's commit and hope to have fixed the theming, all working via side b utton. Will merge PR and then update to DSOMM before contributing.
1 parent 6371c90 commit 3d0aa67

6 files changed

Lines changed: 112 additions & 25 deletions

File tree

src/app/app.component.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { Component, OnInit } from '@angular/core';
2+
import { ThemeService } from './service/theme.service';
23

34
@Component({
45
selector: 'app-root',
@@ -9,6 +10,10 @@ export class AppComponent implements OnInit {
910
title = 'DSOMM';
1011
menuIsOpen: boolean = true;
1112

13+
constructor(private themeService: ThemeService) {
14+
this.themeService.initTheme();
15+
}
16+
1217
ngOnInit(): void {
1318
let menuState: string | null = localStorage.getItem('state.menuIsOpen');
1419
if (menuState === 'false') {

src/app/component/circular-heatmap/circular-heatmap.component.ts

Lines changed: 39 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import {
1515
ModalMessageComponent,
1616
DialogInfo,
1717
} from '../modal-message/modal-message.component';
18+
import { ThemeService } from '../../service/theme.service';
1819

1920
export interface activitySchema {
2021
uuid: string;
@@ -83,28 +84,53 @@ export class CircularHeatmapComponent implements OnInit {
8384
constructor(
8485
private yaml: ymlService,
8586
private router: Router,
87+
private themeService: ThemeService,
8688
public modal: ModalMessageComponent
8789
) {
8890
this.showOverlay = false;
8991
this.showFilters = true;
9092
this.theme = 'light';
93+
this.theme = this.themeService.getTheme();
94+
9195
this.theme_colors = this.themes[this.theme];
9296
}
9397

9498
ngOnInit(): void {
95-
console.log(`${this.perfNow()}s: ngOnInit`);
96-
this.theme = localStorage.getItem('theme') || 'light';
97-
this.theme_colors = this.themes[this.theme];
99+
const savedTheme = this.themeService.getTheme() || 'light';
100+
this.themeService.setTheme(savedTheme); // sets .light-theme or .dark-theme
101+
102+
requestAnimationFrame(() => {
103+
// Now the DOM has the correct class and CSS vars are live
104+
const css = getComputedStyle(document.body);
105+
this.theme_colors = {
106+
background: css.getPropertyValue('--heatmap-background').trim(),
107+
filled: css.getPropertyValue('--heatmap-filled').trim(),
108+
disabled: css.getPropertyValue('--heatmap-disabled').trim(),
109+
cursor: css.getPropertyValue('--heatmap-cursor').trim(),
110+
stroke: css.getPropertyValue('--heatmap-stroke').trim(),
111+
};
98112

99-
// Ensure that Levels and Teams load before MaturityData
100-
// using promises, since ngOnInit does not support async/await
101-
this.LoadMaturityLevels()
102-
.then(() => this.LoadTeamsFromMetaYaml())
103-
.then(() => this.LoadMaturityDataFromGeneratedYaml())
104-
.then(() => {
105-
console.log(`${this.perfNow()}s: set filters: ${this.chips?.length}`);
106-
this.matChipsArray = this.chips.toArray();
107-
});
113+
this.LoadMaturityLevels()
114+
.then(() => this.LoadTeamsFromMetaYaml())
115+
.then(() => this.LoadMaturityDataFromGeneratedYaml())
116+
.then(() => {
117+
this.matChipsArray = this.chips.toArray();
118+
});
119+
});
120+
121+
// Reactively handle theme changes (if user toggles later)
122+
this.themeService.theme$.subscribe((theme: string) => {
123+
const css = getComputedStyle(document.body);
124+
this.theme_colors = {
125+
background: css.getPropertyValue('--heatmap-background').trim(),
126+
filled: css.getPropertyValue('--heatmap-filled').trim(),
127+
disabled: css.getPropertyValue('--heatmap-disabled').trim(),
128+
cursor: css.getPropertyValue('--heatmap-cursor').trim(),
129+
stroke: css.getPropertyValue('--heatmap-stroke').trim(),
130+
};
131+
132+
this.reColorHeatmap(); // repaint segments with new theme
133+
});
108134
}
109135

110136
@ViewChildren(MatChip) chips!: QueryList<MatChip>;
@@ -569,7 +595,7 @@ export class CircularHeatmapComponent implements OnInit {
569595
.startAngle(sa)
570596
.endAngle(ea)
571597
)
572-
.attr('stroke', '#252525')
598+
.attr('stroke', _self.theme_colors['stroke'])
573599
.attr('fill', function (d) {
574600
return color(accessor(d));
575601
});

src/app/component/sidenav-buttons/sidenav-buttons.component.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { Component, OnInit } from '@angular/core';
2+
import { ThemeService } from '../../service/theme.service';
23

34
@Component({
45
selector: 'app-sidenav-buttons',
@@ -36,18 +37,20 @@ export class SidenavButtonsComponent implements OnInit {
3637

3738
isNightMode = false;
3839

39-
constructor() {}
40+
constructor(private themeService: ThemeService) {}
4041

4142
ngOnInit(): void {
4243
const themePref = localStorage.getItem('theme');
43-
this.isNightMode = themePref === 'night';
44+
this.isNightMode = themePref === 'dark';
4445
this.applyTheme();
4546
}
4647

4748
toggleTheme(): void {
49+
console.log('[toggleTheme] Triggered');
50+
4851
this.isNightMode = !this.isNightMode;
49-
this.applyTheme();
50-
localStorage.setItem('theme', this.isNightMode ? 'night' : 'light');
52+
const newTheme = this.isNightMode ? 'dark' : 'light';
53+
this.themeService.setTheme(newTheme);
5154
}
5255

5356
private applyTheme(): void {

src/app/service/theme.service.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { Injectable } from '@angular/core';
2+
import { BehaviorSubject } from 'rxjs';
3+
4+
@Injectable({ providedIn: 'root' })
5+
export class ThemeService {
6+
private themeSubject = new BehaviorSubject<string>('light');
7+
public readonly theme$ = this.themeSubject.asObservable();
8+
9+
constructor() {
10+
const savedTheme = localStorage.getItem('theme') || 'light';
11+
this.setTheme(savedTheme);
12+
}
13+
14+
initTheme(): void {
15+
const saved = localStorage.getItem('theme') || 'light';
16+
this.setTheme(saved);
17+
}
18+
19+
setTheme(theme: string): void {
20+
document.body.classList.remove('light-theme', 'dark-theme');
21+
document.body.classList.add(`${theme}-theme`);
22+
23+
// Force this before other reads
24+
requestAnimationFrame(() => {
25+
this.themeSubject.next(theme);
26+
localStorage.setItem('theme', theme);
27+
});
28+
}
29+
30+
getTheme(): string {
31+
return this.themeSubject.value;
32+
}
33+
}

src/custom-theme.scss

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -66,19 +66,27 @@ $DSOMM-dark-theme: mat.define-dark-theme((
6666
// Light Mode Styles
6767
// ----------------------------------------------
6868
body {
69-
@include apply-theme($light-theme);
70-
@include mat.all-component-themes($DSOMM-light-theme);
7169

7270
.title-button,
7371
h1, h2, h3, h4, h5, h6 {
7472
color: map-get($light-theme, text);
7573
}
7674
}
7775

76+
.light-theme {
77+
--heatmap-filled: #4caf50;
78+
--heatmap-disabled: #888888;
79+
--heatmap-cursor: #3f51b5;
80+
--heatmap-background: white;
81+
--heatmap-stroke: black;
82+
83+
@include mat.all-component-themes($DSOMM-light-theme);
84+
}
85+
7886
// ----------------------------------------------
7987
// Dark Mode Styles
8088
// ----------------------------------------------
81-
body.night-mode {
89+
body.dark-theme {
8290
@include apply-theme($custom-dark-theme);
8391
@include mat.all-component-themes($DSOMM-dark-theme);
8492

@@ -87,6 +95,7 @@ body.night-mode {
8795
color: map-get($custom-dark-theme, text);
8896
}
8997

98+
9099
// Common containers
91100
mat-card,
92101
.mat-dialog-container,
@@ -126,17 +135,28 @@ body.night-mode {
126135
}
127136

128137
// Circular heatmap (radar chart)
129-
.circular-heat text,
130-
.labels.segment text {
131-
fill: #ffffff !important;
132-
}
138+
133139

134140
.circular-heat line,
135141
.circular-heat path {
136142
stroke: #000000;
137143
}
138144
}
139145

146+
.dark-theme {
147+
148+
149+
--heatmap-filled: #4caf50;
150+
--heatmap-disabled: #666666;
151+
--heatmap-cursor: #80deea;
152+
--heatmap-background: #bbbbbb;
153+
--heatmap-stroke: #000000;
154+
155+
156+
157+
@include mat.all-component-themes($DSOMM-dark-theme);
158+
}
159+
140160
.button-container {
141161
display: flex;
142162
flex-direction: column; // Vertical alignment

src/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
rel="stylesheet"
1818
href="https://cdnjs.cloudflare.com/ajax/libs/github-fork-ribbon-css/0.2.3/gh-fork-ribbon.min.css" />
1919
</head>
20-
<body class="mat-typography">
20+
<body class="light-theme">
2121
<app-root></app-root>
2222
</body>
2323
</html>

0 commit comments

Comments
 (0)