Skip to content

Commit

Permalink
feat: added theme switcher
Browse files Browse the repository at this point in the history
  • Loading branch information
skyecodes committed Jul 11, 2023
1 parent 08dc0f6 commit f3b2e83
Show file tree
Hide file tree
Showing 14 changed files with 365 additions and 34 deletions.
60 changes: 51 additions & 9 deletions angular.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,33 @@
"src/favicon.ico",
"src/assets"
],
"styles": [
"@angular/material/prebuilt-themes/purple-green.css",
"src/styles.scss"
],
"scripts": []
},
"styles": [
{
"input": "src/styles.scss"
},
{
"inject": false,
"input": "src/styles/custom-themes/pink-bluegrey.scss",
"bundleName": "pink-bluegrey"
},
{
"inject": false,
"input": "src/styles/custom-themes/deeppurple-amber.scss",
"bundleName": "deeppurple-amber"
},
{
"inject": false,
"input": "src/styles/custom-themes/indigo-pink.scss",
"bundleName": "indigo-pink"
},
{
"inject": false,
"input": "src/styles/custom-themes/purple-green.scss",
"bundleName": "purple-green"
}
],
"scripts": []
},
"configurations": {
"production": {
"budgets": [
Expand Down Expand Up @@ -106,9 +127,30 @@
"src/assets"
],
"styles": [
"@angular/material/prebuilt-themes/purple-green.css",
"src/styles.scss"
],
{
"input": "src/styles.scss"
},
{
"inject": false,
"input": "src/styles/custom-themes/pink-bluegrey.scss",
"bundleName": "pink-bluegrey"
},
{
"inject": false,
"input": "src/styles/custom-themes/deeppurple-amber.scss",
"bundleName": "deeppurple-amber"
},
{
"inject": false,
"input": "src/styles/custom-themes/indigo-pink.scss",
"bundleName": "indigo-pink"
},
{
"inject": false,
"input": "src/styles/custom-themes/purple-green.scss",
"bundleName": "purple-green"
}
],
"scripts": []
}
}
Expand Down
26 changes: 26 additions & 0 deletions src/_app-theme.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
@use '@angular/material' as mat;
@use './app/app.component' as app-component;

@use 'sass:map';

@mixin theme($theme) {
$primary: map.get($theme, primary);
$accent: map.get($theme, accent);
$warn: map.get($theme, warn);
$background: map.get($theme, background);
$foreground: map.get($theme, foreground);

@include app-component.theme($primary);
}

@mixin theme-light($theme) {
$primary: map.get($theme, primary);

@include app-component.theme-light($primary);
}

@mixin theme-dark($theme) {
$primary: map.get($theme, primary);

@include app-component.theme-dark($primary);
}
39 changes: 39 additions & 0 deletions src/app/app.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,51 @@ <h3><a mat-button routerLink="/" (click)="closeSidenavIfSmall()">
</a></h3>
<span class="mat-small">v{{packageJson.version}}</span>
<span class="flex-grow-1"></span>
<a mat-icon-button [matMenuTriggerFor]="menu">
<mat-icon>palette</mat-icon>
</a>
<a mat-icon-button href="https://github.com/skyecodes/skyetools" target="_blank">
<fa-icon [icon]="faGithub"></fa-icon>
</a>
<a mat-icon-button href="https://twitter.com/skyecodes_" target="_blank">
<fa-icon [icon]="faTwitter"></fa-icon>
</a>
<mat-menu #menu="matMenu">
<button
*ngFor="let theme of themes"
mat-menu-item
[disabled]="theme.value == currentTheme"
(click)="changeTheme(theme.value)">
<mat-icon
role="img"
aria-hidden="true">
<svg
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="100%"
height="100%"
viewBox="0 0 80 80"
preserveAspectRatio="xMidYMid meet"
focusable="false">
<defs>
<path
d="M77.87 0C79.05 0 80 .95 80 2.13v75.74c0 1.17-.95 2.13-2.13 2.13H2.13C.96 80 0 79.04 0 77.87V2.13C0 .95.96 0 2.13 0h75.74z"
id="a">
</path>
<path
d="M54 40c3.32 0 6 2.69 6 6 0 1.2 0-1.2 0 0 0 3.31-2.68 6-6 6H26c-3.31 0-6-2.69-6-6 0-1.2 0 1.2 0 0 0-3.31 2.69-6 6-6h28z"
id="b">
</path>
<path d="M0 0h80v17.24H0V0z" id="c"></path>
</defs>
<use xlink:href="#a" [attr.fill]="theme.backgroundColor"></use>
<use xlink:href="#b" [attr.fill]="theme.buttonColor"></use>
<use xlink:href="#c" [attr.fill]="theme.headingColor"></use>
</svg>
</mat-icon>
<span>{{ theme.label }}</span>
</button>
</mat-menu>
</mat-toolbar>
<mat-sidenav-container>
<mat-sidenav [opened]="sidenavOpened" [mode]="sidenavMode" class="mat-elevation-z4" #sidenav>
Expand Down
27 changes: 18 additions & 9 deletions src/app/app.component.scss
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
@use 'sass:map';
@use '@angular/material' as mat;

#root {
display: flex;
Expand All @@ -10,18 +9,28 @@ mat-sidenav-container {
flex-grow: 1;
}

.link-active {
background-color: rgba(map-get(mat.$purple-palette, 700), 0.3);
}

.link-active span {
color: map-get(mat.$purple-palette, 100);
}

mat-list-item.link-active:focus::before {
background-color: inherit !important;
}

mat-nav-list {
padding: 0;
}

@mixin theme-light($primary) {
.link-active span {
color: map-get($primary, 800);
}
}

@mixin theme-dark($primary) {
.link-active span {
color: map-get($primary, 100);
}
}

@mixin theme($primary) {
.link-active {
background-color: rgba(map-get($primary, 700), 0.3) !important;
}
}
24 changes: 19 additions & 5 deletions src/app/app.component.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,28 @@
import {Component, OnDestroy, ViewChild} from '@angular/core';
import {Component, OnDestroy, OnInit, ViewChild} from '@angular/core';
import {MatDrawerMode, MatSidenav} from "@angular/material/sidenav";
import {Subject, takeUntil} from "rxjs";
import packageJson from '../../package.json';
import {faGithub, faTwitter} from "@fortawesome/free-brands-svg-icons";
import {ResponsiveService} from "./common/responsive.service";
import {links} from "./common/utils";
import {links, themes} from "./common/utils";
import {ThemeService} from "./common/theme.service";

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnDestroy {
export class AppComponent implements OnInit, OnDestroy {
destroyed = new Subject<void>();
sidenavOpened!: boolean
sidenavMode!: MatDrawerMode
@ViewChild('sidenav') sidenav!: MatSidenav;
currentTheme!: string;
protected readonly links = links
protected readonly themes = themes;

constructor(responsiveService: ResponsiveService) {
responsiveService.isSmall
constructor(private responsiveService: ResponsiveService, private themeService: ThemeService) {
this.responsiveService.isSmall
.pipe(takeUntil(this.destroyed))
.subscribe(isSmall => {
if (isSmall) {
Expand All @@ -30,6 +33,11 @@ export class AppComponent implements OnDestroy {
this.sidenavMode = 'side';
}
});
this.currentTheme = localStorage.getItem('theme') || 'purple-green'
this.themeService.setTheme(this.currentTheme);
}

ngOnInit() {
}

ngOnDestroy() {
Expand All @@ -44,4 +52,10 @@ export class AppComponent implements OnDestroy {
closeSidenavIfSmall() {
if (this.sidenavMode == 'over') this.sidenav.close()
}

changeTheme(theme: string) {
this.themeService.setTheme(theme);
this.currentTheme = theme;
localStorage.setItem('theme', theme);
}
}
16 changes: 16 additions & 0 deletions src/app/common/theme.service.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import {TestBed} from '@angular/core/testing';

import {ThemeService} from './theme.service';

describe('ThemeService', () => {
let service: ThemeService;

beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(ThemeService);
});

it('should be created', () => {
expect(service).toBeTruthy();
});
});
42 changes: 42 additions & 0 deletions src/app/common/theme.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import {Injectable} from '@angular/core';

@Injectable({
providedIn: 'root'
})
export class ThemeService {
constructor() {
}

setTheme(themeToSet: string) {
this.setStyle(
'theme',
`${themeToSet}.css`
);
}

private setStyle(key: string, href: string) {
getLinkElementForKey(key).setAttribute('href', href);
}
}

function getLinkElementForKey(key: string) {
return getExistingLinkElementByKey(key) || createLinkElementWithKey(key);
}

function getExistingLinkElementByKey(key: string) {
return document.head.querySelector(
`link[rel="stylesheet"].${getClassNameForKey(key)}`
);
}

function createLinkElementWithKey(key: string) {
const linkEl = document.createElement('link');
linkEl.setAttribute('rel', 'stylesheet');
linkEl.classList.add(getClassNameForKey(key));
document.head.appendChild(linkEl);
return linkEl;
}

function getClassNameForKey(key: string) {
return `app-${key}`;
}
55 changes: 47 additions & 8 deletions src/app/common/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ import {NgZone} from "@angular/core";
import {Observable} from "rxjs";

interface Link {
name: string,
url: string,
icon: string,
description: string
name: string;
url: string;
icon: string;
description: string;
}

export const links: Link[] = [
Expand All @@ -29,7 +29,7 @@ export const links: Link[] = [
icon: 'live_tv',
description: 'Watch movies and shows online (not made by me, only self-hosting).'
},
]
];

export class CustomErrorStateMatcher implements ErrorStateMatcher {
isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean {
Expand All @@ -39,9 +39,9 @@ export class CustomErrorStateMatcher implements ErrorStateMatcher {
}

export interface ProgressMessage {
isCompleted: boolean
progress: number
fileId: string
isCompleted: boolean;
progress: number;
fileId: string;
}

export function observeEventSource(source: EventSource, zone: NgZone) {
Expand All @@ -57,3 +57,42 @@ export function observeEventSource(source: EventSource, zone: NgZone) {
});
});
}

export interface Theme {
backgroundColor: string;
buttonColor: string;
headingColor: string;
label: string;
value: string;
}

export const themes: Theme[] = [
{
"backgroundColor": "#fff",
"buttonColor": "#ffc107",
"headingColor": "#673ab7",
"label": "Deep Purple & Amber",
"value": "deeppurple-amber"
},
{
"backgroundColor": "#fff",
"buttonColor": "#ff4081",
"headingColor": "#3f51b5",
"label": "Indigo & Pink",
"value": "indigo-pink"
},
{
"backgroundColor": "#303030",
"buttonColor": "#607d8b",
"headingColor": "#e91e63",
"label": "Pink & Blue Grey",
"value": "pink-bluegrey"
},
{
"backgroundColor": "#303030",
"buttonColor": "#4caf50",
"headingColor": "#9c27b0",
"label": "Purple & Green",
"value": "purple-green"
}
];
Loading

0 comments on commit f3b2e83

Please sign in to comment.