diff --git a/src/app/app.component.html b/src/app/app.component.html
index 1cc32689..af1197e3 100644
--- a/src/app/app.component.html
+++ b/src/app/app.component.html
@@ -1,18 +1,11 @@
-
+
\ No newline at end of file
diff --git a/src/app/app.component.ts b/src/app/app.component.ts
index 996312b7..6837c641 100644
--- a/src/app/app.component.ts
+++ b/src/app/app.component.ts
@@ -3,19 +3,41 @@ import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
- styleUrls: ['./app.component.css'],
+ styleUrls: ['./app.component.css'], // This is for component-specific styles.
})
export class AppComponent implements OnInit {
title = 'DSOMM';
+ isNightMode = false;
menuIsOpen: boolean = true;
ngOnInit(): void {
+ // Load menu state
let menuState: string | null = localStorage.getItem('state.menuIsOpen');
+
if (menuState === 'false') {
setTimeout(() => {
this.menuIsOpen = false;
}, 600);
}
+
+ // Load night mode state
+ let nightModeState: string | null =
+ localStorage.getItem('state.isNightMode');
+
+ if (nightModeState === 'true') {
+ this.isNightMode = true;
+ document.body.classList.add('night-mode');
+ }
+ }
+
+ toggleTheme(): void {
+ this.isNightMode = !this.isNightMode;
+ if (this.isNightMode) {
+ document.body.classList.add('night-mode');
+ } else {
+ document.body.classList.remove('night-mode');
+ }
+ localStorage.setItem('state.isNightMode', this.isNightMode.toString());
}
toggleMenu(): void {
diff --git a/src/app/component/matrix/matrix.component.html b/src/app/component/matrix/matrix.component.html
index 7831cfe5..9eed13a0 100644
--- a/src/app/component/matrix/matrix.component.html
+++ b/src/app/component/matrix/matrix.component.html
@@ -6,13 +6,26 @@
+ [selected]="currentSubDimensions.includes(subDimension)">
{{ subDimension }}
+
+
+
+
+
Activity Tag Filter
diff --git a/src/app/component/matrix/matrix.component.ts b/src/app/component/matrix/matrix.component.ts
index c91e59ee..37f1abe5 100644
--- a/src/app/component/matrix/matrix.component.ts
+++ b/src/app/component/matrix/matrix.component.ts
@@ -1,4 +1,11 @@
-import { Component, OnInit, ElementRef, ViewChild } from '@angular/core';
+import {
+ Component,
+ OnInit,
+ ElementRef,
+ ViewChild,
+ ViewChildren,
+ QueryList,
+} from '@angular/core';
import { COMMA, ENTER } from '@angular/cdk/keycodes';
import { FormControl } from '@angular/forms';
import { Observable } from 'rxjs';
@@ -16,6 +23,7 @@ export interface MatrixElement {
Dimension: string;
SubDimension: string;
}
+
@UntilDestroy()
@Component({
selector: 'app-matrix',
@@ -24,14 +32,10 @@ export interface MatrixElement {
})
export class MatrixComponent implements OnInit {
MATRIX_DATA: MatrixElement[] = [];
-
Routing: string = '/activity-description';
-
YamlObject: any;
levels: string[] = [];
-
displayedColumns: string[] = ['Dimension', 'SubDimension'];
-
lvlColumn: string[] = [];
allRows: string[] = [];
dataSource: any = new MatTableDataSource(this.MATRIX_DATA);
@@ -39,6 +43,21 @@ export class MatrixComponent implements OnInit {
activityVisible: string[] = [];
allDimensionNames: string[] = [];
+ // For autocomplete filters
+ filteredSubDimension: Observable;
+ filteredActivities: Observable;
+ autoCompeteResults: string[] = [];
+ autoCompleteActivityResults: string[] = [];
+ separatorKeysCodes: number[] = [ENTER, COMMA];
+ rowCtrl = new FormControl('');
+ rowCtrlActivity = new FormControl('');
+
+ listTags: string[] = [];
+ currentTags: string[] = [];
+
+ listSubDimension: string[] = [];
+ currentSubDimensions: string[] = [];
+
constructor(private yaml: ymlService, private router: Router) {
this.filteredSubDimension = this.rowCtrl.valueChanges.pipe(
startWith(null),
@@ -55,61 +74,53 @@ export class MatrixComponent implements OnInit {
)
);
}
+
reload() {
window.location.reload();
}
- // function to initialize if level columns exists
ngOnInit(): void {
this.yaml.setURI('./assets/YAML/meta.yaml');
- // Function sets column header
+ // Set column header information
this.yaml.getJson().subscribe(data => {
this.YamlObject = data;
- // Levels header
this.levels = this.YamlObject['strings']['en']['maturity_levels'];
- // pushes Levels in displayed column
for (let k = 1; k <= this.levels.length; k++) {
this.displayedColumns.push('level' + k);
this.lvlColumn.push('level' + k);
}
});
- var activitySet = new Set();
+ const activitySet = new Set();
- //gets value from generated folder
+ // Load generated data
this.yaml.setURI('./assets/YAML/generated/generated.yaml');
- // Function sets data
this.yaml.getJson().subscribe(data => {
this.YamlObject = data;
-
this.allDimensionNames = Object.keys(this.YamlObject);
for (let i = 0; i < this.allDimensionNames.length; i++) {
- var subdimensionsInCurrentDimension = Object.keys(
+ const subdimensionsInCurrentDimension = Object.keys(
this.YamlObject[this.allDimensionNames[i]]
);
-
for (let j = 0; j < subdimensionsInCurrentDimension.length; j++) {
- var temp: any = {
+ let temp: any = {
Dimension: this.allDimensionNames[i],
SubDimension: subdimensionsInCurrentDimension[j],
};
for (let k = 0; k < this.levels.length; k++) {
- temp = {
- ...temp,
- [this.lvlColumn[k] as keyof number]: [],
- };
+ temp = { ...temp, [this.lvlColumn[k] as keyof number]: [] };
}
- var activityInCurrentSubDimension: string[] = Object.keys(
+ const activityInCurrentSubDimension: string[] = Object.keys(
this.YamlObject[this.allDimensionNames[i]][
subdimensionsInCurrentDimension[j]
]
);
for (let a = 0; a < activityInCurrentSubDimension.length; a++) {
- var currentActivityName = activityInCurrentSubDimension[a];
- var tagsInCurrentActivity: string[] =
+ const currentActivityName = activityInCurrentSubDimension[a];
+ const tagsInCurrentActivity: string[] =
this.YamlObject[this.allDimensionNames[i]][
subdimensionsInCurrentDimension[j]
][currentActivityName].tags;
@@ -120,11 +131,10 @@ export class MatrixComponent implements OnInit {
}
try {
- var lvlOfActivity: number =
+ const lvlOfActivity: number =
this.YamlObject[this.allDimensionNames[i]][
subdimensionsInCurrentDimension[j]
][currentActivityName]['level'];
-
(
temp[
this.lvlColumn[lvlOfActivity - 1] as keyof number
@@ -150,9 +160,13 @@ export class MatrixComponent implements OnInit {
chipsControl = new FormControl(['chipsControl']);
chipList!: MatChipList;
- // @ViewChild(MatChip)
- listTags: string[] = [];
- currentTags: string[] = [];
+ @ViewChild('rowInput') rowInput!: ElementRef;
+ @ViewChild('activityInput') activityInput!: ElementRef;
+
+ // Query only the subdimension chips using the unique template reference (e.g. "chipRef")
+ @ViewChildren('chipRef') subChips!: QueryList;
+
+ // --- Tag Chips Methods ---
createActivityTags(activitySet: Set): void {
activitySet.forEach(tag => {
this.listTags.push(tag);
@@ -167,16 +181,15 @@ export class MatrixComponent implements OnInit {
if (chip.selected) {
this.currentTags = [...this.currentTags, chip.value];
this.activityVisible = this.currentTags;
- this.updateActivitesBeingDisplayed();
} else {
this.currentTags = this.currentTags.filter(o => o !== chip.value);
this.activityVisible = this.currentTags;
- this.updateActivitesBeingDisplayed();
}
+ this.updateActivitesBeingDisplayed();
}
- listSubDimension: string[] = [];
- currentSubDimensions: string[] = [];
+ // --- SubDimension Chips Methods ---
+
createSubDimensionList(): void {
let i = 0;
while (i < this.MATRIX_DATA.length) {
@@ -190,61 +203,103 @@ export class MatrixComponent implements OnInit {
}
}
- toggleSubDimensionSelection(chip: MatChip) {
- chip.toggleSelected();
- if (chip.selected) {
- this.currentSubDimensions = [...this.currentSubDimensions, chip.value];
- this.subDimensionVisible = this.currentSubDimensions;
- this.selectedSubDimension(chip.value);
- } else {
+ // Toggle subdimension selection based on its string value
+ toggleSubDimensionSelection(subDimension: string): void {
+ if (this.currentSubDimensions.includes(subDimension)) {
+ // Remove the subdimension from the filter
this.currentSubDimensions = this.currentSubDimensions.filter(
- o => o !== chip.value
+ sd => sd !== subDimension
);
- this.subDimensionVisible = this.currentSubDimensions;
- this.removeSubDimensionFromFilter(chip.value);
+ this.removeSubDimensionFromFilter(subDimension);
+ } else {
+ // Add the subdimension to the filter
+ this.currentSubDimensions = [...this.currentSubDimensions, subDimension];
+ this.selectedSubDimension(subDimension);
}
+ // Update the filter and displayed activities
+ this.subDimensionVisible = this.currentSubDimensions;
+ this.updateActivitesBeingDisplayed();
}
- //chips
- separatorKeysCodes: number[] = [ENTER, COMMA];
- rowCtrl = new FormControl('');
- rowCtrlActivity = new FormControl('');
- filteredSubDimension: Observable;
- filteredActivities: Observable;
- autoCompeteResults: string[] = [];
- autoCompleteActivityResults: string[] = [];
+ // Method to reset/deselect all subdimension filters
+ resetSubDimensionFilters(): void {
+ this.subChips.forEach((chip: MatChip) => {
+ chip.selected = false;
+ });
+ // Also clear the filter arrays and update the table
+ this.currentSubDimensions = [];
+ this.subDimensionVisible = [];
+ this.updateActivitesBeingDisplayed();
+ }
- @ViewChild('rowInput') rowInput!: ElementRef;
- @ViewChild('activityInput') activityInput!: ElementRef;
+ // When a subdimension is selected manually, update the visible filter
+ selectedSubDimension(value: string): void {
+ if (!this.subDimensionVisible.includes(value)) {
+ this.subDimensionVisible.push(value);
+ }
+ this.updateActivitesBeingDisplayed();
+ }
+
+ // Method to select all subdimension filters
+ selectAllSubDimensionFilters(): void {
+ // Set the current filters to include all subdimensions
+ this.currentSubDimensions = [...this.listSubDimension];
+ // Update the visible filters
+ this.subDimensionVisible = [...this.listSubDimension];
+ // Loop through each chip and mark it as selected
+ this.subChips.forEach((chip: MatChip) => {
+ chip.selected = true;
+ });
+ // Refresh the activities displayed in the table
+ this.updateActivitesBeingDisplayed();
+ }
+
+ removeSubDimensionFromFilter(value: string): void {
+ const index = this.subDimensionVisible.indexOf(value);
+ if (index >= 0) {
+ this.subDimensionVisible.splice(index, 1);
+ }
+ this.autoCompeteResults.push(value);
+ this.updateActivitesBeingDisplayed();
+ }
+ // --- Filtering Methods (for autocomplete) ---
+ private filterSubDimension(value: string): string[] {
+ return this.autoCompeteResults.filter(
+ row => row.toLowerCase().indexOf(value.toLowerCase()) === 0
+ );
+ }
+
+ private filterActivity(value: string): string[] {
+ return this.autoCompleteActivityResults.filter(
+ activity => activity.toLowerCase().indexOf(value.toLowerCase()) === 0
+ );
+ }
+
+ // --- Table Data Update ---
updateActivitesBeingDisplayed(): void {
- // Iterate over all objects and create new MATRIX_DATA
- var updatedActivities: any = [];
+ const updatedActivities: any = [];
for (let i = 0; i < this.allDimensionNames.length; i++) {
- var subdimensionsInCurrentDimension = Object.keys(
+ const subdimensionsInCurrentDimension = Object.keys(
this.YamlObject[this.allDimensionNames[i]]
);
-
for (let j = 0; j < subdimensionsInCurrentDimension.length; j++) {
- var temp: any = {
+ let temp: any = {
Dimension: this.allDimensionNames[i],
SubDimension: subdimensionsInCurrentDimension[j],
};
for (let k = 0; k < this.levels.length; k++) {
- temp = {
- ...temp,
- [this.lvlColumn[k] as keyof number]: [],
- };
+ temp = { ...temp, [this.lvlColumn[k] as keyof number]: [] };
}
- var activityInCurrentSubDimension: string[] = Object.keys(
+ const activityInCurrentSubDimension: string[] = Object.keys(
this.YamlObject[this.allDimensionNames[i]][
subdimensionsInCurrentDimension[j]
]
);
for (let a = 0; a < activityInCurrentSubDimension.length; a++) {
- var currentActivityName = activityInCurrentSubDimension[a];
- var tagsInCurrentActivity: string[] =
+ const currentActivityName = activityInCurrentSubDimension[a];
+ const tagsInCurrentActivity: string[] =
this.YamlObject[this.allDimensionNames[i]][
subdimensionsInCurrentDimension[j]
][currentActivityName].tags;
@@ -258,11 +313,10 @@ export class MatrixComponent implements OnInit {
}
if (flag === 1) {
try {
- var lvlOfActivity: number =
+ const lvlOfActivity: number =
this.YamlObject[this.allDimensionNames[i]][
subdimensionsInCurrentDimension[j]
][currentActivityName]['level'];
-
(
temp[
this.lvlColumn[lvlOfActivity - 1] as keyof number
@@ -278,38 +332,10 @@ export class MatrixComponent implements OnInit {
}
}
}
-
this.dataSource.data = JSON.parse(JSON.stringify(updatedActivities));
}
- removeSubDimensionFromFilter(row: string): void {
- let index = this.subDimensionVisible.indexOf(row);
- if (index >= 0) {
- this.subDimensionVisible.splice(index, 1);
- }
- this.autoCompeteResults.push(row);
- this.updateActivitesBeingDisplayed();
- }
-
- //Add chips
- selectedSubDimension(value: string): void {
- this.subDimensionVisible.push(value);
- this.updateActivitesBeingDisplayed();
- }
-
- private filterSubDimension(value: string): string[] {
- return this.autoCompeteResults.filter(
- row => row.toLowerCase().indexOf(value.toLowerCase()) === 0
- );
- }
- private filterActivity(value: string): string[] {
- return this.autoCompleteActivityResults.filter(
- activity => activity.toLowerCase().indexOf(value.toLowerCase()) === 0
- );
- }
-
- // activity description routing + providing parameters
-
+ // --- Routing ---
navigate(
uuid: String,
dim: string,
@@ -317,7 +343,7 @@ export class MatrixComponent implements OnInit {
lvl: Number,
activityName: string
) {
- let navigationExtras: NavigationExtras = {
+ const navigationExtras: NavigationExtras = {
queryParams: {
uuid: uuid,
dimension: dim,
diff --git a/src/custom-theme.scss b/src/custom-theme.scss
index 85ffe50c..d1b590f5 100644
--- a/src/custom-theme.scss
+++ b/src/custom-theme.scss
@@ -1,44 +1,80 @@
-
-// Custom Theming for Angular Material
-// For more information: https://material.angular.io/guide/theming
@use '@angular/material' as mat;
-// Plus imports for other components in your app.
-// Include the common styles for Angular Material. We include this here so that you only
-// have to load a single css file for Angular Material in your app.
-// Be sure that you only ever include this mixin once!
+// ----------------------------------------------
+// Custom Theme Maps for Body Styles
+// ----------------------------------------------
+$light-theme: (
+ background: white,
+ text: black,
+ link: blue
+);
-$custom-typography: mat.define-typography-level(
- $font-family: montserrat,
- $font-weight: 400,
- $font-size: 1rem,
- $line-height: 1,
- $letter-spacing: normal,
+$custom-dark-theme: ( // renamed to avoid conflict with Angular Material variables
+ background: #2c2c2c,
+ text: #e0e0e0,
+ link: #bb86fc
);
+// ----------------------------------------------
+// Angular Material Core Styles & Typography
+// ----------------------------------------------
+$custom-typography: mat.define-typography-level(
+ $font-family: montserrat,
+ $font-weight: 400,
+ $font-size: 1rem,
+ $line-height: 1,
+ $letter-spacing: normal,
+);
@include mat.core($custom-typography);
-// Define the palettes for your theme using the Material Design palettes available in palette.scss
-// (imported above). For each palette, you can optionally specify a default, lighter, and darker
-// hue. Available color palettes: https://material.io/design/color/
-$DSOMM-primary: mat.define-palette(mat.$green-palette,400);
+// ----------------------------------------------
+// Angular Material Palettes
+// ----------------------------------------------
+$DSOMM-primary: mat.define-palette(mat.$green-palette, 400);
$DSOMM-accent: mat.define-palette(mat.$pink-palette, A200, A100, A400);
-
-// The warn palette is optional (defaults to red).
$DSOMM-warn: mat.define-palette(mat.$red-palette);
-// Create the theme object. A theme consists of configurations for individual
-// theming systems such as "color" or "typography".
-$DSOMM-theme: mat.define-light-theme((
- color: (
- primary: $DSOMM-primary,
- accent: $DSOMM-accent,
- warn: $DSOMM-warn,
- )
+// ----------------------------------------------
+// Define Angular Material Light and Dark Themes
+// ----------------------------------------------
+$DSOMM-light-theme: mat.define-light-theme((
+ color: (
+ primary: $DSOMM-primary,
+ accent: $DSOMM-accent,
+ warn: $DSOMM-warn,
+ )
));
-// Include theme styles for core and each component used in your app.
-// Alternatively, you can import and @include the theme mixins for each component
-// that you are using.
-@include mat.all-component-themes($DSOMM-theme);
+$DSOMM-dark-theme: mat.define-dark-theme((
+ color: (
+ primary: $DSOMM-primary, // using the same palette; adjust if needed
+ accent: $DSOMM-accent,
+ warn: $DSOMM-warn,
+ )
+));
+
+// Include Angular Material styles for the light theme by default
+@include mat.all-component-themes($DSOMM-light-theme);
+
+// ----------------------------------------------
+// Mixin to Apply Custom Body Styles
+// ----------------------------------------------
+@mixin apply-theme($theme) {
+ background-color: map-get($theme, background);
+ color: map-get($theme, text);
+
+ a {
+ color: map-get($theme, link);
+ }
+}
+
+// Apply custom light theme styles to the body by default
+body {
+ @include apply-theme($light-theme);
+}
+// When night mode is active, override with custom dark theme styles and include Angular Material dark theme
+body.night-mode {
+ @include apply-theme($custom-dark-theme);
+ @include mat.all-component-themes($DSOMM-dark-theme);
+}
\ No newline at end of file
diff --git a/src/styles.css b/src/styles.css
index 3f9148db..815187b5 100644
--- a/src/styles.css
+++ b/src/styles.css
@@ -1,8 +1,31 @@
-/* You can add global styles to this file, and also import other style files */
+/* Global Styles and Reset */
+html, body {
+ height: 100%;
+ margin: 0;
+ font-family: Roboto, "Helvetica Neue", sans-serif;
+}
+
+/* Light Theme Variables (Default) */
+:root {
+ --bg-color: white;
+ --text-color: black;
+ --link-color: blue;
+}
-html, body { height: 100%; }
-body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; }
+/* Dark Theme Variables */
+body.night-mode {
+ --bg-color: #121212;
+ --text-color: #e0e0e0;
+ --link-color: blue;
+}
+
+/* Apply Theme Variables */
+body {
+ background-color: var(--bg-color);
+ color: var(--text-color);
+}
+/* Existing Styles */
.userday table :is(td, th) {
border: 1px solid black;
padding: 0.3em;
@@ -18,6 +41,7 @@ body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; }
margin-right: 10px;
}
-.usage-dimensions img {
- max-width: 40rem;
+/* Link Colors */
+a {
+ color: var(--link-color);
}
\ No newline at end of file