From 06afa35b385b1b7e3ece1e5fe770ca89f14cbacd Mon Sep 17 00:00:00 2001 From: Toaster2 Date: Sat, 29 Nov 2025 14:52:13 +0100 Subject: [PATCH 01/19] Show level team pick status --- src/app/api/types/levels/level.ts | 1 + .../items/level-statistics.component.ts | 26 ++++++++++++++++--- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/src/app/api/types/levels/level.ts b/src/app/api/types/levels/level.ts index 22b2c3ef..6a598c74 100644 --- a/src/app/api/types/levels/level.ts +++ b/src/app/api/types/levels/level.ts @@ -14,6 +14,7 @@ export interface Level { uniquePlays: number; publisher: User | undefined; teamPicked: boolean; + dateTeamPicked: Date | undefined; gameVersion: number; score: number; slotType: number; diff --git a/src/app/components/items/level-statistics.component.ts b/src/app/components/items/level-statistics.component.ts index ce015014..e9da8140 100644 --- a/src/app/components/items/level-statistics.component.ts +++ b/src/app/components/items/level-statistics.component.ts @@ -1,20 +1,37 @@ import {Component, Input} from '@angular/core'; import {Level} from "../../api/types/levels/level"; -import {faHeart, faPlay, faStar, faThumbsDown, faThumbsUp} from "@fortawesome/free-solid-svg-icons"; +import {faCircleCheck, faHeart, faPlay, faStar, faThumbsDown, faThumbsUp} from "@fortawesome/free-solid-svg-icons"; import {StatisticComponent} from "../ui/info/statistic.component"; +import { DateComponent } from "../ui/info/date.component"; +import { FaIconComponent } from "@fortawesome/angular-fontawesome"; +import { TooltipComponent } from "../ui/text/tooltip.component"; @Component({ selector: 'app-level-statistics', imports: [ - StatisticComponent - ], + StatisticComponent, + DateComponent, + FaIconComponent, + TooltipComponent +], template: ` -
+
+ @if (level.teamPicked) { +
+ + + + + @if (level.dateTeamPicked != null) { + + } +
+ }
` }) @@ -25,4 +42,5 @@ export class LevelStatisticsComponent { protected readonly faHeart = faHeart; protected readonly faStar = faStar; protected readonly faPlay = faPlay; + protected readonly faCircleCheck = faCircleCheck; } From 51f12d7e4b1dd2109472123d31e21f9179f26019 Mon Sep 17 00:00:00 2001 From: Toaster2 Date: Sat, 29 Nov 2025 15:06:51 +0100 Subject: [PATCH 02/19] Refactor formatting out of DateComponent, unify team pick tooltips --- .../items/level-statistics.component.ts | 35 +++++++++++++------ src/app/components/ui/info/date.component.ts | 32 ++--------------- src/app/helpers/date-time.ts | 33 +++++++++++++++++ 3 files changed, 61 insertions(+), 39 deletions(-) create mode 100644 src/app/helpers/date-time.ts diff --git a/src/app/components/items/level-statistics.component.ts b/src/app/components/items/level-statistics.component.ts index e9da8140..12e0c0f1 100644 --- a/src/app/components/items/level-statistics.component.ts +++ b/src/app/components/items/level-statistics.component.ts @@ -2,15 +2,14 @@ import {Component, Input} from '@angular/core'; import {Level} from "../../api/types/levels/level"; import {faCircleCheck, faHeart, faPlay, faStar, faThumbsDown, faThumbsUp} from "@fortawesome/free-solid-svg-icons"; import {StatisticComponent} from "../ui/info/statistic.component"; -import { DateComponent } from "../ui/info/date.component"; import { FaIconComponent } from "@fortawesome/angular-fontawesome"; import { TooltipComponent } from "../ui/text/tooltip.component"; +import { getFormattedDateTime, getShortDateTime } from '../../helpers/date-time'; @Component({ selector: 'app-level-statistics', imports: [ StatisticComponent, - DateComponent, FaIconComponent, TooltipComponent ], @@ -22,21 +21,37 @@ import { TooltipComponent } from "../ui/text/tooltip.component"; @if (level.teamPicked) { -
- + +
- - - @if (level.dateTeamPicked != null) { - - } -
+

{{this.getShortDateTime()}}

+
+ }
` }) export class LevelStatisticsComponent { @Input({required: true}) level: Level = undefined!; + + ngOnInit() { + if (this.level.dateTeamPicked != null) { + this.level.dateTeamPicked = new Date(this.level.dateTeamPicked); + } + } + + protected getFormattedDateTime(): string { + if (this.level.dateTeamPicked == null) return "unknown"; + + return getFormattedDateTime(this.level.dateTeamPicked); + } + + protected getShortDateTime(): string { + if (this.level.dateTeamPicked == null) return ""; + + return getShortDateTime(this.level.dateTeamPicked); + } + protected readonly faThumbsUp = faThumbsUp; protected readonly faThumbsDown = faThumbsDown; protected readonly faHeart = faHeart; diff --git a/src/app/components/ui/info/date.component.ts b/src/app/components/ui/info/date.component.ts index 94c20148..6dcfcbb9 100644 --- a/src/app/components/ui/info/date.component.ts +++ b/src/app/components/ui/info/date.component.ts @@ -11,6 +11,7 @@ import { } from '@angular/core'; import {TooltipComponent} from "../text/tooltip.component"; import {isPlatformBrowser} from "@angular/common"; +import { getFormattedDateTime, getShortDateTime } from '../../../helpers/date-time'; @Component({ selector: 'app-date', @@ -44,8 +45,6 @@ export class DateComponent implements OnInit, OnDestroy { return isPlatformBrowser(this.platformId); } - protected recentText = "just now"; - // this setter is actually required to be here; this is not a hold-over from the old site // for some reason, javascript's date parser doesn't create a full Date object. // so we need to do this horse-shit. @@ -55,36 +54,11 @@ export class DateComponent implements OnInit, OnDestroy { } get moment(): string { - const now = new Date(); - const totalSeconds = Math.floor((now.getTime() - this._date.getTime()) / 1000); - - const intervals: { [key: string]: number } = { - year: 31536000, - month: 2592000, - week: 604800, - day: 86400, - hour: 3600, - minute: 60, - second: 1, - }; - - if (totalSeconds < 20) - return this.recentText; - - for (const interval in intervals) { - const time = Math.floor(totalSeconds / intervals[interval]); - if (time > 1) { - return `${time} ${interval}s ago`; - } else if (time == 1) { - return `a${interval == "hour" ? 'n' : ''} ${interval} ago`; - } - } - - return this.recentText; + return getShortDateTime(this._date); } get formattedDate(): string { - return `${this._date.toLocaleDateString()} @ ${this._date.toLocaleTimeString()}`; + return getFormattedDateTime(this._date); } ngOnDestroy() { diff --git a/src/app/helpers/date-time.ts b/src/app/helpers/date-time.ts new file mode 100644 index 00000000..0b226943 --- /dev/null +++ b/src/app/helpers/date-time.ts @@ -0,0 +1,33 @@ +export function getFormattedDateTime(date: Date) { + return `${date.toLocaleDateString()} @ ${date.toLocaleTimeString()}`; +} + +export function getShortDateTime(date: Date) { + const recentText = "just now"; + const now = new Date(); + const totalSeconds = Math.floor((now.getTime() - date.getTime()) / 1000); + + const intervals: { [key: string]: number } = { + year: 31536000, + month: 2592000, + week: 604800, + day: 86400, + hour: 3600, + minute: 60, + second: 1, + }; + + if (totalSeconds < 20) + return recentText; + + for (const interval in intervals) { + const time = Math.floor(totalSeconds / intervals[interval]); + if (time > 1) { + return `${time} ${interval}s ago`; + } else if (time == 1) { + return `a${interval == "hour" ? 'n' : ''} ${interval} ago`; + } + } + + return recentText; +} \ No newline at end of file From f7ad1814377aef6e97cc58a3dc60af7b039b6349 Mon Sep 17 00:00:00 2001 From: Toaster2 Date: Sat, 29 Nov 2025 16:00:39 +0100 Subject: [PATCH 03/19] Refactor team pick status into an own component --- .../items/level-statistics.component.ts | 16 ++----- .../items/level-team-pick-status.component.ts | 45 +++++++++++++++++++ 2 files changed, 49 insertions(+), 12 deletions(-) create mode 100644 src/app/components/items/level-team-pick-status.component.ts diff --git a/src/app/components/items/level-statistics.component.ts b/src/app/components/items/level-statistics.component.ts index 12e0c0f1..ea7227b2 100644 --- a/src/app/components/items/level-statistics.component.ts +++ b/src/app/components/items/level-statistics.component.ts @@ -1,17 +1,15 @@ import {Component, Input} from '@angular/core'; import {Level} from "../../api/types/levels/level"; -import {faCircleCheck, faHeart, faPlay, faStar, faThumbsDown, faThumbsUp} from "@fortawesome/free-solid-svg-icons"; +import {faHeart, faPlay, faStar, faThumbsDown, faThumbsUp} from "@fortawesome/free-solid-svg-icons"; import {StatisticComponent} from "../ui/info/statistic.component"; -import { FaIconComponent } from "@fortawesome/angular-fontawesome"; -import { TooltipComponent } from "../ui/text/tooltip.component"; import { getFormattedDateTime, getShortDateTime } from '../../helpers/date-time'; +import { LevelTeamPickStatusComponent } from "./level-team-pick-status.component"; @Component({ selector: 'app-level-statistics', imports: [ StatisticComponent, - FaIconComponent, - TooltipComponent + LevelTeamPickStatusComponent ], template: `
@@ -21,12 +19,7 @@ import { getFormattedDateTime, getShortDateTime } from '../../helpers/date-time' @if (level.teamPicked) { - -
- -

{{this.getShortDateTime()}}

-
-
+ }
` @@ -57,5 +50,4 @@ export class LevelStatisticsComponent { protected readonly faHeart = faHeart; protected readonly faStar = faStar; protected readonly faPlay = faPlay; - protected readonly faCircleCheck = faCircleCheck; } diff --git a/src/app/components/items/level-team-pick-status.component.ts b/src/app/components/items/level-team-pick-status.component.ts new file mode 100644 index 00000000..8d4e3234 --- /dev/null +++ b/src/app/components/items/level-team-pick-status.component.ts @@ -0,0 +1,45 @@ +import {Component, Input} from '@angular/core'; +import {Level} from "../../api/types/levels/level"; +import {faCircleCheck} from "@fortawesome/free-solid-svg-icons"; +import { FaIconComponent } from "@fortawesome/angular-fontawesome"; +import { TooltipComponent } from "../ui/text/tooltip.component"; +import { getFormattedDateTime, getShortDateTime } from '../../helpers/date-time'; + +@Component({ + selector: 'app-level-team-pick-status', + imports: [ + FaIconComponent, + TooltipComponent +], + template: ` + +
+ +

{{this.getShortDateTime()}}

+
+
+ ` +}) +export class LevelTeamPickStatusComponent { + @Input({required: true}) level: Level = undefined!; + + ngOnInit() { + if (this.level.dateTeamPicked != null) { + this.level.dateTeamPicked = new Date(this.level.dateTeamPicked); + } + } + + protected getFormattedDateTime(): string { + if (this.level.dateTeamPicked == null) return "unknown"; + + return getFormattedDateTime(this.level.dateTeamPicked); + } + + protected getShortDateTime(): string { + if (this.level.dateTeamPicked == null) return ""; + + return getShortDateTime(this.level.dateTeamPicked); + } + + protected readonly faCircleCheck = faCircleCheck; +} From a532ccf2e8d2dc2334e1c96c4e7b68c41fe7a5be Mon Sep 17 00:00:00 2001 From: Toaster2 Date: Sat, 29 Nov 2025 16:02:03 +0100 Subject: [PATCH 04/19] Stuff I forgot to remove after previous refactor --- .../items/level-statistics.component.ts | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/src/app/components/items/level-statistics.component.ts b/src/app/components/items/level-statistics.component.ts index ea7227b2..df5417b0 100644 --- a/src/app/components/items/level-statistics.component.ts +++ b/src/app/components/items/level-statistics.component.ts @@ -27,24 +27,6 @@ import { LevelTeamPickStatusComponent } from "./level-team-pick-status.component export class LevelStatisticsComponent { @Input({required: true}) level: Level = undefined!; - ngOnInit() { - if (this.level.dateTeamPicked != null) { - this.level.dateTeamPicked = new Date(this.level.dateTeamPicked); - } - } - - protected getFormattedDateTime(): string { - if (this.level.dateTeamPicked == null) return "unknown"; - - return getFormattedDateTime(this.level.dateTeamPicked); - } - - protected getShortDateTime(): string { - if (this.level.dateTeamPicked == null) return ""; - - return getShortDateTime(this.level.dateTeamPicked); - } - protected readonly faThumbsUp = faThumbsUp; protected readonly faThumbsDown = faThumbsDown; protected readonly faHeart = faHeart; From c52c0ca607a02c6fe7f761b2777d7c3223f551f9 Mon Sep 17 00:00:00 2001 From: Toaster2 Date: Sat, 29 Nov 2025 17:43:50 +0100 Subject: [PATCH 05/19] Show level reupload data --- src/app/api/types/levels/level.ts | 2 ++ .../items/level-preview.component.ts | 27 ++++++++++++------- ...riginal-publisher-router-link.component.ts | 18 +++++++++++++ src/app/pages/level/level.component.html | 6 +++++ src/app/pages/level/level.component.ts | 4 ++- 5 files changed, 46 insertions(+), 11 deletions(-) create mode 100644 src/app/components/ui/text/links/original-publisher-router-link.component.ts diff --git a/src/app/api/types/levels/level.ts b/src/app/api/types/levels/level.ts index 6a598c74..f826cb68 100644 --- a/src/app/api/types/levels/level.ts +++ b/src/app/api/types/levels/level.ts @@ -13,6 +13,8 @@ export interface Level { totalPlays: number; uniquePlays: number; publisher: User | undefined; + originalPublisher: string | undefined; + isReUpload: boolean; teamPicked: boolean; dateTeamPicked: Date | undefined; gameVersion: number; diff --git a/src/app/components/items/level-preview.component.ts b/src/app/components/items/level-preview.component.ts index c6261493..ab9743b6 100644 --- a/src/app/components/items/level-preview.component.ts +++ b/src/app/components/items/level-preview.component.ts @@ -8,19 +8,21 @@ import {GamePipe} from "../../pipes/game.pipe"; import {DateComponent} from "../ui/info/date.component"; import {DefaultPipe} from "../../pipes/default.pipe"; import {LabelComponent} from "../ui/info/label.component"; +import { OriginalPublisherRouterLink } from "../ui/text/links/original-publisher-router-link.component"; @Component({ selector: 'app-level-preview', imports: [ - UserLinkComponent, - LevelAvatarComponent, - LevelStatisticsComponent, - LevelRouterLinkComponent, - GamePipe, - DateComponent, - DefaultPipe, - LabelComponent - ], + UserLinkComponent, + LevelAvatarComponent, + LevelStatisticsComponent, + LevelRouterLinkComponent, + GamePipe, + DateComponent, + DefaultPipe, + LabelComponent, + OriginalPublisherRouterLink +], template: `
@@ -35,7 +37,12 @@ import {LabelComponent} from "../ui/info/label.component";
- by +

by

+ + @if (level.isReUpload) { +

(originally by )

+ } +
diff --git a/src/app/components/ui/text/links/original-publisher-router-link.component.ts b/src/app/components/ui/text/links/original-publisher-router-link.component.ts new file mode 100644 index 00000000..e8ecaa65 --- /dev/null +++ b/src/app/components/ui/text/links/original-publisher-router-link.component.ts @@ -0,0 +1,18 @@ +import {Component, Input} from '@angular/core'; +import {RouterLink} from "@angular/router"; +import { Level } from '../../../../api/types/levels/level'; + +@Component({ + selector: 'app-original-publisher-router-link', + imports: [ + RouterLink + ], + template: ` + + {{level.originalPublisher ?? this.unknownName}} + ` +}) +export class OriginalPublisherRouterLink { + @Input({required: true}) public level: Level = undefined!; + protected unknownName: string = "Unknown"; +} diff --git a/src/app/pages/level/level.component.html b/src/app/pages/level/level.component.html index 44cf539f..871ef578 100644 --- a/src/app/pages/level/level.component.html +++ b/src/app/pages/level/level.component.html @@ -5,6 +5,12 @@ by + + @if (level.isReUpload) { + + (originally by ) + + }
Published for {{level.gameVersion | game: isMobile}} diff --git a/src/app/pages/level/level.component.ts b/src/app/pages/level/level.component.ts index e7272f92..d04ed1ac 100644 --- a/src/app/pages/level/level.component.ts +++ b/src/app/pages/level/level.component.ts @@ -26,6 +26,7 @@ import {AuthenticationService} from "../../api/authentication.service"; import { ExtendedUser } from '../../api/types/users/extended-user'; import { FancyHeaderLevelButtonsComponent } from '../../components/ui/layouts/fancy-header-level-buttons.component'; import { LevelRelations } from '../../api/types/levels/level-relations'; +import { OriginalPublisherRouterLink } from "../../components/ui/text/links/original-publisher-router-link.component"; @Component({ @@ -47,7 +48,8 @@ import { LevelRelations } from '../../api/types/levels/level-relations'; PaneTitleComponent, EventPageComponent, RouterLink, - SlugPipe + SlugPipe, + OriginalPublisherRouterLink ], providers: [ SlugPipe From 14d10dba262c383b32aa39a368173cc825f597bb Mon Sep 17 00:00:00 2001 From: Toaster2 Date: Sat, 29 Nov 2025 20:01:26 +0100 Subject: [PATCH 06/19] Forematting --- src/app/components/items/level-team-pick-status.component.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/components/items/level-team-pick-status.component.ts b/src/app/components/items/level-team-pick-status.component.ts index 8d4e3234..dd4ea803 100644 --- a/src/app/components/items/level-team-pick-status.component.ts +++ b/src/app/components/items/level-team-pick-status.component.ts @@ -14,8 +14,8 @@ import { getFormattedDateTime, getShortDateTime } from '../../helpers/date-time' template: `
- -

{{this.getShortDateTime()}}

+ +

{{this.getShortDateTime()}}

` From a55d52a0c4c7baad5c79b938c560bf89403ec409 Mon Sep 17 00:00:00 2001 From: Toaster2 Date: Sat, 29 Nov 2025 21:25:33 +0100 Subject: [PATCH 07/19] Improve reupload username styling --- .../components/items/level-preview.component.ts | 10 ++++++---- .../original-publisher-router-link.component.ts | 7 +++++-- src/app/pages/level/level.component.html | 15 ++++++++++----- 3 files changed, 21 insertions(+), 11 deletions(-) diff --git a/src/app/components/items/level-preview.component.ts b/src/app/components/items/level-preview.component.ts index ab9743b6..17033013 100644 --- a/src/app/components/items/level-preview.component.ts +++ b/src/app/components/items/level-preview.component.ts @@ -36,11 +36,13 @@ import { OriginalPublisherRouterLink } from "../ui/text/links/original-publisher -
-

by

- +
@if (level.isReUpload) { -

(originally by )

+

by

+

()

+ } + @else { +

by

} diff --git a/src/app/components/ui/text/links/original-publisher-router-link.component.ts b/src/app/components/ui/text/links/original-publisher-router-link.component.ts index e8ecaa65..bab91d7a 100644 --- a/src/app/components/ui/text/links/original-publisher-router-link.component.ts +++ b/src/app/components/ui/text/links/original-publisher-router-link.component.ts @@ -8,8 +8,11 @@ import { Level } from '../../../../api/types/levels/level'; RouterLink ], template: ` - - {{level.originalPublisher ?? this.unknownName}} + + {{level.originalPublisher ?? this.unknownName}} + + ` }) export class OriginalPublisherRouterLink { diff --git a/src/app/pages/level/level.component.html b/src/app/pages/level/level.component.html index 871ef578..0ab9a64d 100644 --- a/src/app/pages/level/level.component.html +++ b/src/app/pages/level/level.component.html @@ -2,13 +2,18 @@ - - by - - @if (level.isReUpload) { + + by + + - + + uploaded by + + } + @else { - (originally by ) + by } From b59ac14fe03d521915976ddc45ca25767c333a53 Mon Sep 17 00:00:00 2001 From: Toaster2 Date: Sun, 30 Nov 2025 11:57:56 +0100 Subject: [PATCH 08/19] Split date formatting methods further --- src/app/helpers/date-time.ts | 38 +++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/src/app/helpers/date-time.ts b/src/app/helpers/date-time.ts index 0b226943..05636982 100644 --- a/src/app/helpers/date-time.ts +++ b/src/app/helpers/date-time.ts @@ -4,24 +4,13 @@ export function getFormattedDateTime(date: Date) { export function getShortDateTime(date: Date) { const recentText = "just now"; - const now = new Date(); - const totalSeconds = Math.floor((now.getTime() - date.getTime()) / 1000); - - const intervals: { [key: string]: number } = { - year: 31536000, - month: 2592000, - week: 604800, - day: 86400, - hour: 3600, - minute: 60, - second: 1, - }; + const totalSeconds = getDifferenceFromNowAsTotalSeconds(date); if (totalSeconds < 20) return recentText; - for (const interval in intervals) { - const time = Math.floor(totalSeconds / intervals[interval]); + for (const interval in timeIntervals) { + const time = Math.floor(totalSeconds / timeIntervals[interval]); if (time > 1) { return `${time} ${interval}s ago`; } else if (time == 1) { @@ -30,4 +19,25 @@ export function getShortDateTime(date: Date) { } return recentText; +} + +export const timeIntervals: { [key: string]: number } = { + year: 31536000, + month: 2592000, + week: 604800, + day: 86400, + hour: 3600, + minute: 60, + second: 1, +}; + +export function getDifferenceFromNowAsTotalSeconds(date: Date) { + const now = new Date(); + return Math.floor((now.getTime() - date.getTime()) / 1000); +} + +export function isOlderThanMonths(date: Date, months: number) { + const totalSeconds = getDifferenceFromNowAsTotalSeconds(date); + const time = Math.floor(totalSeconds / timeIntervals["month"]); + return time > 0; } \ No newline at end of file From ce9bd25497b0dcd7f1aa35db7f2e50e2d242cbdb Mon Sep 17 00:00:00 2001 From: Toaster2 Date: Sun, 30 Nov 2025 11:58:50 +0100 Subject: [PATCH 09/19] Highlight team pick info if team pick was less than a month ago --- .../items/level-team-pick-status.component.ts | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/app/components/items/level-team-pick-status.component.ts b/src/app/components/items/level-team-pick-status.component.ts index dd4ea803..d6c16949 100644 --- a/src/app/components/items/level-team-pick-status.component.ts +++ b/src/app/components/items/level-team-pick-status.component.ts @@ -3,29 +3,34 @@ import {Level} from "../../api/types/levels/level"; import {faCircleCheck} from "@fortawesome/free-solid-svg-icons"; import { FaIconComponent } from "@fortawesome/angular-fontawesome"; import { TooltipComponent } from "../ui/text/tooltip.component"; -import { getFormattedDateTime, getShortDateTime } from '../../helpers/date-time'; +import { getFormattedDateTime, getShortDateTime, isOlderThanMonths } from '../../helpers/date-time'; +import { NgClass } from '@angular/common'; @Component({ selector: 'app-level-team-pick-status', imports: [ FaIconComponent, - TooltipComponent + TooltipComponent, + NgClass ], template: ` -
- -

{{this.getShortDateTime()}}

-
+ +
+ +

{{this.getShortDateTime()}}

+
` }) export class LevelTeamPickStatusComponent { @Input({required: true}) level: Level = undefined!; + isRecent: boolean = false; ngOnInit() { if (this.level.dateTeamPicked != null) { this.level.dateTeamPicked = new Date(this.level.dateTeamPicked); + this.isRecent = !isOlderThanMonths(this.level.dateTeamPicked, 1); } } From dbc28f0682ecb7cd8786d11db14dcd56f87ca41e Mon Sep 17 00:00:00 2001 From: Toaster2 Date: Sun, 30 Nov 2025 12:10:59 +0100 Subject: [PATCH 10/19] Simplify showing publisher on level page at the cost of not showing them next to the title anymore --- src/app/pages/level/level.component.html | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/app/pages/level/level.component.html b/src/app/pages/level/level.component.html index 0ab9a64d..ecde8a6a 100644 --- a/src/app/pages/level/level.component.html +++ b/src/app/pages/level/level.component.html @@ -3,18 +3,15 @@ @if (level.isReUpload) { - - by - - - - - uploaded by - +

+ by , + uploaded by +

} @else { - +

by - +

}
From cf78c87d07a13723da595aa0541019104b82010f Mon Sep 17 00:00:00 2001 From: Toaster2 Date: Sun, 30 Nov 2025 15:13:15 +0100 Subject: [PATCH 11/19] Expose modded status, slightly reorder level header to match a certain draft more --- src/app/api/types/levels/level.ts | 1 + .../items/level-preview.component.ts | 14 ++++- .../ui/info/larger-label.component.ts | 17 ++++++ .../layouts/fancy-header-buttons.component.ts | 2 +- .../ui/layouts/fancy-header.component.ts | 16 ++++-- src/app/pages/level/level.component.html | 55 +++++++++++++++++-- src/app/pages/level/level.component.ts | 8 ++- 7 files changed, 98 insertions(+), 15 deletions(-) create mode 100644 src/app/components/ui/info/larger-label.component.ts diff --git a/src/app/api/types/levels/level.ts b/src/app/api/types/levels/level.ts index f826cb68..0ee498c1 100644 --- a/src/app/api/types/levels/level.ts +++ b/src/app/api/types/levels/level.ts @@ -15,6 +15,7 @@ export interface Level { publisher: User | undefined; originalPublisher: string | undefined; isReUpload: boolean; + isModded: boolean; teamPicked: boolean; dateTeamPicked: Date | undefined; gameVersion: number; diff --git a/src/app/components/items/level-preview.component.ts b/src/app/components/items/level-preview.component.ts index 17033013..6077d10e 100644 --- a/src/app/components/items/level-preview.component.ts +++ b/src/app/components/items/level-preview.component.ts @@ -9,6 +9,7 @@ import {DateComponent} from "../ui/info/date.component"; import {DefaultPipe} from "../../pipes/default.pipe"; import {LabelComponent} from "../ui/info/label.component"; import { OriginalPublisherRouterLink } from "../ui/text/links/original-publisher-router-link.component"; +import { TooltipComponent } from "../ui/text/tooltip.component"; @Component({ selector: 'app-level-preview', @@ -21,7 +22,8 @@ import { OriginalPublisherRouterLink } from "../ui/text/links/original-publisher DateComponent, DefaultPipe, LabelComponent, - OriginalPublisherRouterLink + OriginalPublisherRouterLink, + TooltipComponent ], template: `
@@ -49,7 +51,15 @@ import { OriginalPublisherRouterLink } from "../ui/text/links/original-publisher
- {{level.gameVersion | game: true}} + + {{level.gameVersion | game: true}} + + + @if (level.isModded) { + + Modded + + } diff --git a/src/app/components/ui/info/larger-label.component.ts b/src/app/components/ui/info/larger-label.component.ts new file mode 100644 index 00000000..24e3818c --- /dev/null +++ b/src/app/components/ui/info/larger-label.component.ts @@ -0,0 +1,17 @@ +import {Component, Input} from '@angular/core'; +import {NgClass} from "@angular/common"; + +@Component({ + selector: 'app-larger-label', + imports: [ + NgClass + ], + template: ` +
+ +
+ ` +}) +export class LargerLabelComponent { + @Input() primary: boolean = false; +} diff --git a/src/app/components/ui/layouts/fancy-header-buttons.component.ts b/src/app/components/ui/layouts/fancy-header-buttons.component.ts index e6266145..4c4ce341 100644 --- a/src/app/components/ui/layouts/fancy-header-buttons.component.ts +++ b/src/app/components/ui/layouts/fancy-header-buttons.component.ts @@ -19,7 +19,7 @@ import {faEllipsisV} from "@fortawesome/free-solid-svg-icons"; -
+
-
- - +
+
+ + + +
+
+ +
-
+
+ +
` }) diff --git a/src/app/pages/level/level.component.html b/src/app/pages/level/level.component.html index ecde8a6a..659a02d5 100644 --- a/src/app/pages/level/level.component.html +++ b/src/app/pages/level/level.component.html @@ -1,4 +1,18 @@ @if (level) { + +
+

+ Published +

+ + @if(level.updateDate) { +

+ Updated +

+ } +
+
+ @@ -14,14 +28,43 @@

}
-
- Published for {{level.gameVersion | game: isMobile}} - - @if(level.updateDate) {, - updated - + + +
+ + {{level.gameVersion | game: isMobile}} + + + @if (level.isModded) { + + Modded + }
+ + @if (!isMobile) { +
+
+

published

+
+ + @if(level.updateDate) { +
+

updated

+
+ } +
+ } + @else { +
+ published + + @if(level.updateDate) {, + updated + } +
+ } + @if(relations && !isMobile) { diff --git a/src/app/pages/level/level.component.ts b/src/app/pages/level/level.component.ts index d04ed1ac..619bff6d 100644 --- a/src/app/pages/level/level.component.ts +++ b/src/app/pages/level/level.component.ts @@ -3,7 +3,7 @@ import {Level} from "../../api/types/levels/level"; import {ClientService} from "../../api/client.service"; import {ActivatedRoute, RouterLink} from "@angular/router"; import {SlugPipe} from "../../pipes/slug.pipe"; -import { AsyncPipe, isPlatformBrowser, } from "@angular/common"; +import { AsyncPipe, isPlatformBrowser } from "@angular/common"; import {LevelStatisticsComponent} from "../../components/items/level-statistics.component"; import {DefaultPipe} from "../../pipes/default.pipe"; import {LevelAvatarComponent} from "../../components/ui/photos/level-avatar.component"; @@ -27,6 +27,8 @@ import { ExtendedUser } from '../../api/types/users/extended-user'; import { FancyHeaderLevelButtonsComponent } from '../../components/ui/layouts/fancy-header-level-buttons.component'; import { LevelRelations } from '../../api/types/levels/level-relations'; import { OriginalPublisherRouterLink } from "../../components/ui/text/links/original-publisher-router-link.component"; +import { LargerLabelComponent } from "../../components/ui/info/larger-label.component"; +import { TooltipComponent } from "../../components/ui/text/tooltip.component"; @Component({ @@ -49,7 +51,9 @@ import { OriginalPublisherRouterLink } from "../../components/ui/text/links/orig EventPageComponent, RouterLink, SlugPipe, - OriginalPublisherRouterLink + OriginalPublisherRouterLink, + LargerLabelComponent, + TooltipComponent ], providers: [ SlugPipe From 27f490e3c6c3d15f9244a61f313a411d8f432d74 Mon Sep 17 00:00:00 2001 From: Toaster2 Date: Sun, 30 Nov 2025 16:37:38 +0100 Subject: [PATCH 12/19] Shorten team pick hint on level preview, always keep it yellow, other styling fixes --- .../items/level-preview.component.ts | 2 +- .../items/level-statistics.component.ts | 3 ++- .../items/level-team-pick-status.component.ts | 18 +++++++++--------- .../ui/layouts/fancy-header.component.ts | 2 +- src/app/helpers/date-time.ts | 12 +++--------- src/app/pages/level/level.component.html | 6 +++--- 6 files changed, 19 insertions(+), 24 deletions(-) diff --git a/src/app/components/items/level-preview.component.ts b/src/app/components/items/level-preview.component.ts index 6077d10e..38d754e0 100644 --- a/src/app/components/items/level-preview.component.ts +++ b/src/app/components/items/level-preview.component.ts @@ -36,7 +36,7 @@ import { TooltipComponent } from "../ui/text/tooltip.component"; [title]=level.title>{{ level.title | default: "Unnamed Level" }}

- +
@if (level.isReUpload) { diff --git a/src/app/components/items/level-statistics.component.ts b/src/app/components/items/level-statistics.component.ts index df5417b0..cee7ccb1 100644 --- a/src/app/components/items/level-statistics.component.ts +++ b/src/app/components/items/level-statistics.component.ts @@ -19,13 +19,14 @@ import { LevelTeamPickStatusComponent } from "./level-team-pick-status.component @if (level.teamPicked) { - + }
` }) export class LevelStatisticsComponent { @Input({required: true}) level: Level = undefined!; + @Input() short: boolean = false; protected readonly faThumbsUp = faThumbsUp; protected readonly faThumbsDown = faThumbsDown; diff --git a/src/app/components/items/level-team-pick-status.component.ts b/src/app/components/items/level-team-pick-status.component.ts index d6c16949..8c9f771f 100644 --- a/src/app/components/items/level-team-pick-status.component.ts +++ b/src/app/components/items/level-team-pick-status.component.ts @@ -3,34 +3,34 @@ import {Level} from "../../api/types/levels/level"; import {faCircleCheck} from "@fortawesome/free-solid-svg-icons"; import { FaIconComponent } from "@fortawesome/angular-fontawesome"; import { TooltipComponent } from "../ui/text/tooltip.component"; -import { getFormattedDateTime, getShortDateTime, isOlderThanMonths } from '../../helpers/date-time'; -import { NgClass } from '@angular/common'; +import { getFormattedDateTime, getShortDateTime } from '../../helpers/date-time'; @Component({ selector: 'app-level-team-pick-status', imports: [ FaIconComponent, - TooltipComponent, - NgClass + TooltipComponent ], template: ` - + -
+
-

{{this.getShortDateTime()}}

+ @if (!short) { +

team picked {{this.getShortDateTime()}}

+ } +
` }) export class LevelTeamPickStatusComponent { @Input({required: true}) level: Level = undefined!; - isRecent: boolean = false; + @Input() short: boolean = false; ngOnInit() { if (this.level.dateTeamPicked != null) { this.level.dateTeamPicked = new Date(this.level.dateTeamPicked); - this.isRecent = !isOlderThanMonths(this.level.dateTeamPicked, 1); } } diff --git a/src/app/components/ui/layouts/fancy-header.component.ts b/src/app/components/ui/layouts/fancy-header.component.ts index 95b748ea..7c284252 100644 --- a/src/app/components/ui/layouts/fancy-header.component.ts +++ b/src/app/components/ui/layouts/fancy-header.component.ts @@ -33,7 +33,7 @@ import { NgTemplateOutlet } from "@angular/common";
-
+
diff --git a/src/app/helpers/date-time.ts b/src/app/helpers/date-time.ts index 05636982..7c9dde41 100644 --- a/src/app/helpers/date-time.ts +++ b/src/app/helpers/date-time.ts @@ -4,7 +4,8 @@ export function getFormattedDateTime(date: Date) { export function getShortDateTime(date: Date) { const recentText = "just now"; - const totalSeconds = getDifferenceFromNowAsTotalSeconds(date); + const now = new Date(); + const totalSeconds = Math.floor((now.getTime() - date.getTime()) / 1000); if (totalSeconds < 20) return recentText; @@ -32,12 +33,5 @@ export const timeIntervals: { [key: string]: number } = { }; export function getDifferenceFromNowAsTotalSeconds(date: Date) { - const now = new Date(); - return Math.floor((now.getTime() - date.getTime()) / 1000); -} - -export function isOlderThanMonths(date: Date, months: number) { - const totalSeconds = getDifferenceFromNowAsTotalSeconds(date); - const time = Math.floor(totalSeconds / timeIntervals["month"]); - return time > 0; + } \ No newline at end of file diff --git a/src/app/pages/level/level.component.html b/src/app/pages/level/level.component.html index 659a02d5..cc3815b3 100644 --- a/src/app/pages/level/level.component.html +++ b/src/app/pages/level/level.component.html @@ -43,13 +43,13 @@
@if (!isMobile) { -
-
+
+

published

@if(level.updateDate) { -
+

updated

} From 7ebc1024972baa2801ffc518dbd4f3552e8bed50 Mon Sep 17 00:00:00 2001 From: Toaster2 Date: Sun, 30 Nov 2025 16:45:13 +0100 Subject: [PATCH 13/19] The forgotten removals --- src/app/helpers/date-time.ts | 6 +----- src/app/pages/level/level.component.html | 14 -------------- 2 files changed, 1 insertion(+), 19 deletions(-) diff --git a/src/app/helpers/date-time.ts b/src/app/helpers/date-time.ts index 7c9dde41..b709ed85 100644 --- a/src/app/helpers/date-time.ts +++ b/src/app/helpers/date-time.ts @@ -30,8 +30,4 @@ export const timeIntervals: { [key: string]: number } = { hour: 3600, minute: 60, second: 1, -}; - -export function getDifferenceFromNowAsTotalSeconds(date: Date) { - -} \ No newline at end of file +}; \ No newline at end of file diff --git a/src/app/pages/level/level.component.html b/src/app/pages/level/level.component.html index cc3815b3..f2ace0ac 100644 --- a/src/app/pages/level/level.component.html +++ b/src/app/pages/level/level.component.html @@ -1,18 +1,4 @@ @if (level) { - -
-

- Published -

- - @if(level.updateDate) { -

- Updated -

- } -
-
- From 2d1df030ffc8c5fc88f393e0f86eb1c83b9d3bda Mon Sep 17 00:00:00 2001 From: Toaster2 Date: Sun, 30 Nov 2025 17:04:21 +0100 Subject: [PATCH 14/19] Optimize team pick date formatting --- .../items/level-team-pick-status.component.ts | 21 +++++++------------ 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/src/app/components/items/level-team-pick-status.component.ts b/src/app/components/items/level-team-pick-status.component.ts index 8c9f771f..7ddd8358 100644 --- a/src/app/components/items/level-team-pick-status.component.ts +++ b/src/app/components/items/level-team-pick-status.component.ts @@ -12,12 +12,12 @@ import { getFormattedDateTime, getShortDateTime } from '../../helpers/date-time' TooltipComponent ], template: ` - +
@if (!short) { -

team picked {{this.getShortDateTime()}}

+

team picked {{this.shortTime}}

}
@@ -28,23 +28,16 @@ export class LevelTeamPickStatusComponent { @Input({required: true}) level: Level = undefined!; @Input() short: boolean = false; + protected formattedTime: string = "unknown"; + protected shortTime: string = ""; + ngOnInit() { if (this.level.dateTeamPicked != null) { this.level.dateTeamPicked = new Date(this.level.dateTeamPicked); + this.shortTime = getShortDateTime(this.level.dateTeamPicked); + this.formattedTime = getFormattedDateTime(this.level.dateTeamPicked); } } - protected getFormattedDateTime(): string { - if (this.level.dateTeamPicked == null) return "unknown"; - - return getFormattedDateTime(this.level.dateTeamPicked); - } - - protected getShortDateTime(): string { - if (this.level.dateTeamPicked == null) return ""; - - return getShortDateTime(this.level.dateTeamPicked); - } - protected readonly faCircleCheck = faCircleCheck; } From 0bf7d4788d760e0bf4a14500adfef236566ee99b Mon Sep 17 00:00:00 2001 From: Toaster2 Date: Mon, 1 Dec 2025 18:29:57 +0100 Subject: [PATCH 15/19] Make publisher string clearer for reuploads + improve wrapping, don't show update date if level was never updated --- src/app/pages/level/level.component.html | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/app/pages/level/level.component.html b/src/app/pages/level/level.component.html index f2ace0ac..cc3fdc7f 100644 --- a/src/app/pages/level/level.component.html +++ b/src/app/pages/level/level.component.html @@ -3,10 +3,10 @@ @if (level.isReUpload) { -

- by , - uploaded by -

+
+ originally by , + uploaded by +
} @else {

@@ -34,7 +34,7 @@

published

- @if(level.updateDate) { + @if(level.updateDate != level.publishDate) {

updated

@@ -45,7 +45,7 @@
published - @if(level.updateDate) {, + @if(level.updateDate != level.publishDate) {, updated }
From 53272da55c71b86d65b02a77edcfd072da676013 Mon Sep 17 00:00:00 2001 From: Toaster2 Date: Fri, 6 Feb 2026 22:32:06 +0100 Subject: [PATCH 16/19] Revert setting Level.dateTeamPicked's type to Date | undefined --- src/app/api/types/levels/level.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/api/types/levels/level.ts b/src/app/api/types/levels/level.ts index 602b2277..fbd043f3 100644 --- a/src/app/api/types/levels/level.ts +++ b/src/app/api/types/levels/level.ts @@ -10,7 +10,7 @@ export interface Level { isReUpload: boolean; isModded: boolean; teamPicked: boolean; - dateTeamPicked: Date | undefined; + dateTeamPicked: Date; gameVersion: number; score: number; slotType: number; From 119b0c48cbad9a0bac5f21e3eb2a8661422bfdbe Mon Sep 17 00:00:00 2001 From: Toaster2 Date: Sat, 7 Feb 2026 11:27:47 +0100 Subject: [PATCH 17/19] Shorten team pick notice for mobile widths --- .../items/level-team-pick-status.component.ts | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/app/components/items/level-team-pick-status.component.ts b/src/app/components/items/level-team-pick-status.component.ts index 7ddd8358..fded4978 100644 --- a/src/app/components/items/level-team-pick-status.component.ts +++ b/src/app/components/items/level-team-pick-status.component.ts @@ -4,6 +4,7 @@ import {faCircleCheck} from "@fortawesome/free-solid-svg-icons"; import { FaIconComponent } from "@fortawesome/angular-fontawesome"; import { TooltipComponent } from "../ui/text/tooltip.component"; import { getFormattedDateTime, getShortDateTime } from '../../helpers/date-time'; +import { LayoutService } from '../../services/layout.service'; @Component({ selector: 'app-level-team-pick-status', @@ -16,10 +17,14 @@ import { getFormattedDateTime, getShortDateTime } from '../../helpers/date-time'
+ @if (!short) { -

team picked {{this.shortTime}}

+ @if (!isMobile) { + team picked + } + + {{this.shortTime}} } -
` @@ -30,6 +35,11 @@ export class LevelTeamPickStatusComponent { protected formattedTime: string = "unknown"; protected shortTime: string = ""; + protected isMobile: boolean = false; + + constructor(protected layout: LayoutService) { + this.layout.isMobile.subscribe(v => this.isMobile = v); + } ngOnInit() { if (this.level.dateTeamPicked != null) { From 17f7eb25f1ed4b61aba79a72ed8a6dcb88546229 Mon Sep 17 00:00:00 2001 From: Toaster2 Date: Sat, 7 Feb 2026 11:39:11 +0100 Subject: [PATCH 18/19] Add and use emphasized-primary as a color --- src/app/components/items/level-team-pick-status.component.ts | 3 +-- tailwind.config.js | 2 ++ 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/app/components/items/level-team-pick-status.component.ts b/src/app/components/items/level-team-pick-status.component.ts index fded4978..22c51236 100644 --- a/src/app/components/items/level-team-pick-status.component.ts +++ b/src/app/components/items/level-team-pick-status.component.ts @@ -14,8 +14,7 @@ import { LayoutService } from '../../services/layout.service'; ], template: ` - -
+
@if (!short) { diff --git a/tailwind.config.js b/tailwind.config.js index 165fc15e..6edbce5d 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -19,6 +19,8 @@ const defaultColors = { "secondary-bright": "#E2CFE5", + "emphasized-primary": "#F2AA00", + "red": "#E52E2E", "green": "#52BC24", "dark-green": "#4a9e27ff", From a4a7b3a65bf1d6ba5baa58f85ad95cd7af27ea36 Mon Sep 17 00:00:00 2001 From: Toaster2 Date: Sat, 7 Feb 2026 11:48:51 +0100 Subject: [PATCH 19/19] Slightly better wording --- src/app/pages/level/level.component.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/pages/level/level.component.html b/src/app/pages/level/level.component.html index cc3fdc7f..173bbaf2 100644 --- a/src/app/pages/level/level.component.html +++ b/src/app/pages/level/level.component.html @@ -5,7 +5,7 @@ @if (level.isReUpload) {
originally by , - uploaded by + reuploaded by
} @else {