From 268c2a0d0221fc403b57eaf5246946a6058f7f6f Mon Sep 17 00:00:00 2001 From: Nico Jensch Date: Sun, 21 Jul 2024 10:50:21 +0200 Subject: [PATCH] feat(theme): persist theme choice; use routerlink for full deploy log --- frontend/src/app/app.component.ts | 19 +++--- frontend/src/app/home/home.component.ts | 64 +++++++++------------ frontend/src/app/status/status.component.ts | 20 +++++-- shared-lib/src/lib/functions.ts | 34 +++++++++-- 4 files changed, 82 insertions(+), 55 deletions(-) diff --git a/frontend/src/app/app.component.ts b/frontend/src/app/app.component.ts index c89a3662..883b7f28 100644 --- a/frontend/src/app/app.component.ts +++ b/frontend/src/app/app.component.ts @@ -1,4 +1,4 @@ -import { CAUR_CACHED_METRICS_URL } from "@./shared-lib" +import { CAUR_CACHED_METRICS_URL, loadTheme } from "@./shared-lib" import { isPlatformBrowser, NgOptimizedImage } from "@angular/common" import { HttpClient } from "@angular/common/http" import { @@ -9,7 +9,7 @@ import { OnInit, PLATFORM_ID, Renderer2, - ViewEncapsulation, + ViewEncapsulation } from "@angular/core" import { RouterLink, RouterLinkActive, RouterOutlet } from "@angular/router" import { initFlowbite } from "flowbite" @@ -24,7 +24,7 @@ import { StatusComponent } from "./status/status.component" imports: [RouterOutlet, StatusComponent, RouterLink, RouterLinkActive, NgOptimizedImage, Highlight], templateUrl: "./app.component.html", styleUrl: "./app.component.css", - encapsulation: ViewEncapsulation.None, + encapsulation: ViewEncapsulation.None }) export class AppComponent implements OnInit, AfterViewInit { title = "aur.chaotic.cx" @@ -33,11 +33,16 @@ export class AppComponent implements OnInit, AfterViewInit { @Inject(PLATFORM_ID) private platformId: object, private el: ElementRef, private httpClient: HttpClient, - private renderer: Renderer2, - ) {} + private renderer: Renderer2 + ) { + } ngOnInit(): void { - this.renderer.setStyle(this.el.nativeElement.ownerDocument.body, "backgroundColor", "#1e1e2e") + const theme = localStorage.getItem("theme") + if (theme) { + loadTheme(theme, this.renderer, this.el) + } + TimeAgo.addDefaultLocale(en) if (isPlatformBrowser(this.platformId)) { @@ -53,7 +58,7 @@ export class AppComponent implements OnInit, AfterViewInit { "30d/packages", "30d/rank/30/packages", "30d/rank/30/countries", - "30d/user-agents", + "30d/user-agents" ] routesToPreCache.forEach((route) => { this.httpClient.get(CAUR_CACHED_METRICS_URL + route) diff --git a/frontend/src/app/home/home.component.ts b/frontend/src/app/home/home.component.ts index d809ff4b..d180c48e 100644 --- a/frontend/src/app/home/home.component.ts +++ b/frontend/src/app/home/home.component.ts @@ -1,10 +1,10 @@ import { NgOptimizedImage } from "@angular/common" -import { Component, ElementRef, Renderer2 } from "@angular/core" +import { AfterViewInit, Component, ElementRef, Renderer2 } from "@angular/core" import { RouterLink, RouterLinkActive } from "@angular/router" -import { flavors } from "@catppuccin/palette" import { ChaoticAttractorComponent } from "../chaotic-attractor/chaotic-attractor.component" import { MirrorMapComponent } from "../mirror-map/mirror-map.component" import { NewsChannelComponent } from "../news-channel/news-channel.component" +import { loadTheme } from "@./shared-lib" @Component({ selector: "app-home", @@ -15,64 +15,54 @@ import { NewsChannelComponent } from "../news-channel/news-channel.component" RouterLinkActive, ChaoticAttractorComponent, MirrorMapComponent, - NewsChannelComponent, + NewsChannelComponent ], templateUrl: "./home.component.html", - styleUrl: "./home.component.css", + styleUrl: "./home.component.css" }) -export class HomeComponent { - currentTheme = "mocha" +export class HomeComponent implements AfterViewInit { + currentTheme: undefined | string = "mocha" constructor( private el: ElementRef, - private renderer: Renderer2, - ) {} + private renderer: Renderer2 + ) { + } + + ngAfterViewInit(): void { + const savedTheme = localStorage.getItem("theme") + if (savedTheme) { + this.currentTheme = savedTheme + } + } + toggleTheme(): void { const appCtp = document.getElementById("app-ctp") - // @ts-ignore + + if (appCtp === null) return const classList = appCtp.classList // Need to change this if classes every get changed or rearranged switch (this.currentTheme) { case "mocha": classList.remove("mocha") - classList.add("latte") - this.currentTheme = "latte" - this.renderer.setStyle( - this.el.nativeElement.ownerDocument.body, - "backgroundColor", - flavors.latte.colors.base.hex, - ) + this.currentTheme = loadTheme("latte", this.renderer, this.el) + localStorage.setItem("theme", "latte") break case "latte": classList.remove("latte") - classList.add("frappe") - this.currentTheme = "frappe" - this.renderer.setStyle( - this.el.nativeElement.ownerDocument.body, - "backgroundColor", - flavors.frappe.colors.base.hex, - ) + this.currentTheme = loadTheme("frappe", this.renderer, this.el) + localStorage.setItem("theme", "frappe") break case "frappe": classList.remove("frappe") - classList.add("macchiato") - this.currentTheme = "macchiato" - this.renderer.setStyle( - this.el.nativeElement.ownerDocument.body, - "backgroundColor", - flavors.macchiato.colors.base.hex, - ) + this.currentTheme = loadTheme("macchiato", this.renderer, this.el) + localStorage.setItem("theme", "macchiato") break case "macchiato": classList.remove("macchiato") - classList.add("mocha") - this.currentTheme = "mocha" - this.renderer.setStyle( - this.el.nativeElement.ownerDocument.body, - "backgroundColor", - flavors.mocha.colors.base.hex, - ) + this.currentTheme = loadTheme("mocha", this.renderer, this.el) + localStorage.setItem("theme", "mocha") } } } diff --git a/frontend/src/app/status/status.component.ts b/frontend/src/app/status/status.component.ts index d2c169bd..63bd5cd1 100644 --- a/frontend/src/app/status/status.component.ts +++ b/frontend/src/app/status/status.component.ts @@ -1,14 +1,15 @@ -import { CAUR_API_URL, CurrentQueue, headToFullDeployments, StatsObject } from "@./shared-lib" +import { CAUR_API_URL, CurrentQueue, StatsObject } from "@./shared-lib" import { AfterViewInit, Component } from "@angular/core" import { Axios } from "axios" import { DeployLogComponent } from "../deploy-log/deploy-log.component" +import { Router } from "@angular/router" @Component({ selector: "app-status", standalone: true, imports: [DeployLogComponent], templateUrl: "./status.component.html", - styleUrl: "./status.component.css", + styleUrl: "./status.component.css" }) export class StatusComponent implements AfterViewInit { currentQueue: CurrentQueue = [] @@ -16,7 +17,9 @@ export class StatusComponent implements AfterViewInit { lastUpdated: string | undefined loading = true showFullPackages = false - protected readonly headToFullDeployments = headToFullDeployments + + constructor(private router: Router) { + } ngAfterViewInit(): void { void this.getQueueStats() @@ -32,7 +35,7 @@ export class StatusComponent implements AfterViewInit { const axios = new Axios({ baseURL: CAUR_API_URL, - timeout: 10000, + timeout: 10000 }) axios .get("queue/stats") @@ -50,7 +53,7 @@ export class StatusComponent implements AfterViewInit { returnQueue.push({ status: Object.keys(currentQueue[index])[0], count: Object.values(currentQueue[index])[0].count, - packages: nameWithoutRepo, + packages: nameWithoutRepo }) } } @@ -94,4 +97,11 @@ export class StatusComponent implements AfterViewInit { this.showFullPackages = false } } + + /** + * Redirect to the full deployments page using the Angular router. + */ + headToFullDeployments() { + void this.router.navigate([`/deploy-log`]) + } } diff --git a/shared-lib/src/lib/functions.ts b/shared-lib/src/lib/functions.ts index d850c95b..3971bd17 100644 --- a/shared-lib/src/lib/functions.ts +++ b/shared-lib/src/lib/functions.ts @@ -1,6 +1,8 @@ import { Axios } from "axios" import TimeAgo from "javascript-time-ago" import { CAUR_TG_API_URL, CountNameObject, DeploymentList, DeploymentType, TgMessageList, UserAgentList } from "./types" +import { CatppuccinFlavor, flavors } from "@catppuccin/palette" +import { ElementRef, Renderer2 } from "@angular/core" /** * Parse the output of the non-single line metrics. @@ -16,7 +18,7 @@ export function parseOutput(input: string): any[] { if (!isNaN(count)) { returningArray.push({ name: name ?? "Unknown", - count, + count }) } } @@ -96,7 +98,7 @@ export function parseDeployments(messages: TgMessageList, type: DeploymentType): name: pkg, repo: repo, type: deploymentType, - log: log, + log: log }) } return deploymentList @@ -109,7 +111,7 @@ export function parseDeployments(messages: TgMessageList, type: DeploymentType): export async function getDeployments(amount: number, type: DeploymentType): Promise { const axios = new Axios({ baseURL: CAUR_TG_API_URL, - timeout: 1000, + timeout: 1000 }) let requestString @@ -153,8 +155,28 @@ export function startShortPolling(interval: any, func: () => void): void { } /** - * Redirect to the full deployment log. + * Loads the selected theme. + * @param theme The theme to load (one of CatppuccinFlavor). + * @param renderer The renderer to use. + * @param el The element to apply the theme to. */ -export function headToFullDeployments(): void { - window.location.href = "./deploy-log" +export function loadTheme(theme: string, renderer: Renderer2, el: ElementRef) { + const appCtp = document.getElementById("app-ctp") + if (appCtp === null) return + if (appCtp.classList.contains(theme)) { + return theme + } + + appCtp.classList.remove("mocha", "latte", "frappe", "macchiato") + appCtp.classList.add(theme) + + const flavor = theme as unknown as CatppuccinFlavor + // @ts-expect-error - this is always valid color + const flavorColor = flavors[flavor].colors.base.hex + renderer.setStyle( + el.nativeElement.ownerDocument.body, + "backgroundColor", + flavorColor + ) + return theme }