diff --git a/src/app/app.component.ts b/src/app/app.component.ts index d3ae4d6..c87c883 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -1,7 +1,8 @@ -import { Component, OnInit, AfterViewInit } from '@angular/core'; -import { Router, RouterEvent } from '@angular/router'; -import { LocalStorage, LocalStorageService } from 'ngx-webstorage' +import { Component, OnInit } from '@angular/core'; +import { Router } from '@angular/router'; +import { LocalStorage } from 'ngx-webstorage' import { GoWebViewInit } from './services/go'; +import { UiService } from './services/ui.service'; @Component({ selector: 'app-root', @@ -12,7 +13,10 @@ import { GoWebViewInit } from './services/go'; export class AppComponent implements OnInit{ title = 'go-web'; - constructor(private router: Router, private storage: LocalStorageService) { } + constructor( + private router: Router, + private ui: UiService + ) { } @LocalStorage('theme', 'dark') public theme!: string @@ -23,17 +27,11 @@ export class AppComponent implements OnInit{ console.log("Navigating to route:" + event.detail) }) - this.setTheme(this.theme) - this.storage.observe('theme').subscribe(value => { - this.setTheme(this.theme) - }) + this.ui.setTheme(this.theme) + this.ui.detectThemeChange() } ngAfterViewInit(){ GoWebViewInit() } - - setTheme (theme: string) { - document.querySelector('html')?.setAttribute('data-theme', theme) - } } diff --git a/src/app/components/main/main-menu/main-menu.component.scss b/src/app/components/main/main-menu/main-menu.component.scss index 50760e1..917d275 100644 --- a/src/app/components/main/main-menu/main-menu.component.scss +++ b/src/app/components/main/main-menu/main-menu.component.scss @@ -14,6 +14,8 @@ box-sizing: border-box; backdrop-filter: blur(64px); overflow-y: auto; + z-index: 20; + position: relative; .menu-search-panel { display: flex; diff --git a/src/app/components/main/main-root/main-root.component.html b/src/app/components/main/main-root/main-root.component.html index bc88ed3..c87a9b2 100644 --- a/src/app/components/main/main-root/main-root.component.html +++ b/src/app/components/main/main-root/main-root.component.html @@ -1,4 +1,6 @@ -
+
+
+
diff --git a/src/app/components/main/main-root/main-root.component.scss b/src/app/components/main/main-root/main-root.component.scss index fd27ace..0051930 100644 --- a/src/app/components/main/main-root/main-root.component.scss +++ b/src/app/components/main/main-root/main-root.component.scss @@ -5,27 +5,54 @@ height: 100vh; overflow: hidden; - img { - position: absolute; - height: 100%; - top: 0; - left: 50%; - translate: -50% 0%; - } - .main-wrapper { display: flex; width: 100vw; height: 100vh; background-size: cover; position: inherit; - } - .content { - flex: 1; - background-color: var(--sk-right-content); - display: flex; - backdrop-filter: blur(2rem); - // overflow-y: auto; + .content { + flex: 1; + background-color: var(--sk-right-content); + display: flex; + position: relative; + z-index: 20; + backdrop-filter: blur(2rem); + // overflow-y: auto; + } + } +} + +:host::ng-deep { + + .backdrop-image { + width: 100vw; + height: 100vh; + position: absolute; + background-color: var(--sk-background); + z-index: 0; + left: 0; + top: 0; + + .layer { + position: absolute; + left: 0; + top: 0; + width: 100%; + height: 100%; + background-size: cover; + background-position: center; + z-index: 10; + transition: opacity 3s linear; + + &.hidden { + opacity: 0; + } + + &.secondary { + z-index: 5; + } + } } } diff --git a/src/app/components/main/main-root/main-root.component.ts b/src/app/components/main/main-root/main-root.component.ts index 3db5e08..e4275c5 100644 --- a/src/app/components/main/main-root/main-root.component.ts +++ b/src/app/components/main/main-root/main-root.component.ts @@ -1,4 +1,6 @@ -import { Component, OnInit } from '@angular/core'; +import { Component, ElementRef, inject, OnInit } from '@angular/core'; +import { asapScheduler, asyncScheduler, of, queueScheduler, scheduled, Subscription } from 'rxjs'; +import { UiService } from 'src/app/services/ui.service'; @Component({ selector: 'app-main-root', @@ -6,9 +8,91 @@ import { Component, OnInit } from '@angular/core'; styleUrls: ['./main-root.component.scss'], }) export class MainRootComponent implements OnInit { - image: string = 'assets/games/minecraft/backgrounds/7.webp'; + image: string = 'assets/games/minecraft/backgrounds/compressed/7.webp'; + uiService = inject(UiService) + subs: Map = new Map() + timer: number = 0 - constructor() {} + queue: string[] = [] + transitionEnded: boolean = true - ngOnInit(): void {} + constructor( + private element: ElementRef + ) {} + + ngOnInit(): void { + this.observeImageChange() + this.setImage(this.image, true) + } + + ngOnDestroy(): void { + //Called once, before the instance is destroyed. + //Add 'implements OnDestroy' to the class. + this.subs.forEach(sub => sub.unsubscribe()) + } + + observeImageChange() { + this.subs.set( + 'image-change', + this.uiService.imageChange.subscribe({ + next: (url: string) => { + this.queueImageChange(url) + // this.setImage(url) + } + }) + ) + } + + queueImageChange(url: string) { + if (this.queue.length > 0 || !this.transitionEnded) { + this.queue.push(url) + return + } + + this.setImage(url) + } + + next() { + if (!this.queue.length) return + + this.setImage(this.queue.splice(0, 1)[0]) + } + + setImage(url: string, init = false) { + if (!init) + this.transitionEnded = false + + this.image = url + + let wrapper = this.element.nativeElement.querySelector('.backdrop-image') + if (!wrapper) return + + const image = document.createElement('img') + image.onload = () => { + if (!wrapper || init) return + + let current = wrapper.querySelector('.layer:not(.secondary)'), secondary = wrapper.querySelectorAll('.layer.secondary') + + current?.classList.add('hidden') + + clearTimeout(this.timer) + this.timer = window.setTimeout(() => { + secondary.forEach(value => value.classList.remove('secondary')) + current?.remove() + this.transitionEnded = true + + this.next() + }, 3200) + } + image.src = url + + const layer = document.createElement('div') + layer.classList.add('layer') + + if (!init) + layer.classList.add('secondary') + + layer.style.backgroundImage = `url(${url})` + wrapper.append(layer) + } } diff --git a/src/app/components/main/sections/game-page/game-overview/game-overview.component.html b/src/app/components/main/sections/game-page/game-overview/game-overview.component.html index 8e00eb9..528b008 100644 --- a/src/app/components/main/sections/game-page/game-overview/game-overview.component.html +++ b/src/app/components/main/sections/game-page/game-overview/game-overview.component.html @@ -20,7 +20,7 @@ -
+
{{field.label}} {{field.value}} {{field.value}} diff --git a/src/app/components/main/sections/game-page/game-overview/game-overview.component.scss b/src/app/components/main/sections/game-page/game-overview/game-overview.component.scss index 6816024..74e643f 100644 --- a/src/app/components/main/sections/game-page/game-overview/game-overview.component.scss +++ b/src/app/components/main/sections/game-page/game-overview/game-overview.component.scss @@ -7,7 +7,7 @@ display: flex; align-items: flex-start; display: flex; - gap: var(--sk-gap-xxxl); + gap: var(--sk-gap-m); padding-bottom: var(--sk-gap-xxxl); } @@ -16,6 +16,12 @@ flex-direction: column; gap: var(--sk-gap-s); + &.filled { + background-color: rgba(255, 255, 255, 0.25); + padding: 0.75rem 1.25rem; + border-radius: 0.5rem; + } + skirda-text { line-height: 140%; } diff --git a/src/app/components/main/sections/game-page/game-page.component.ts b/src/app/components/main/sections/game-page/game-page.component.ts index 59269b0..29cdec3 100644 --- a/src/app/components/main/sections/game-page/game-page.component.ts +++ b/src/app/components/main/sections/game-page/game-page.component.ts @@ -1,10 +1,12 @@ -import { OnDestroy, TemplateRef, ViewChild } from '@angular/core'; +import { inject, OnDestroy, TemplateRef, ViewChild } from '@angular/core'; import { Component, OnInit } from '@angular/core'; +import { NavigationEnd, Router } from '@angular/router'; import { PopupConfiguration } from 'projects/ui/src/lib/popup/popup.class'; import { PopupDirective } from 'projects/ui/src/lib/popup/popup.directive'; import { PopupService } from 'projects/ui/src/lib/popup/popup.service'; import { first, Subscription } from 'rxjs'; import { Game } from 'src/app/interfaces/game.interface'; +import { UiService } from 'src/app/services/ui.service'; @Component({ selector: 'app-game-page', @@ -13,6 +15,7 @@ import { Game } from 'src/app/interfaces/game.interface'; }) export class GamePageComponent implements OnInit, OnDestroy { // @ViewChild(PopupDirective, { static: true }) popupPortal!: PopupDirective; + uiService = inject(UiService) subs: Map = new Map(); game: Game = { gameId: 'minecraft', @@ -24,14 +27,43 @@ export class GamePageComponent implements OnInit, OnDestroy { currentSection: string = 'overview'; friends: string[] = ['svensken', 'cyberdream', 'e11te']; - constructor() {} // private popup: PopupService + tempImages = [ + 'assets/games/minecraft/backgrounds/compressed/0.webp', + 'assets/games/minecraft/backgrounds/compressed/1.webp', + 'assets/games/minecraft/backgrounds/compressed/2.webp', + 'assets/games/minecraft/backgrounds/compressed/3.webp', + 'assets/games/minecraft/backgrounds/compressed/4.webp', + 'assets/games/minecraft/backgrounds/compressed/5.webp', + 'assets/games/minecraft/backgrounds/compressed/6.webp', + 'assets/games/minecraft/backgrounds/compressed/7.webp', + 'assets/games/minecraft/backgrounds/compressed/8.webp', + ] - ngOnInit(): void {} + constructor( + private router: Router + ) {} // private popup: PopupService + + ngOnInit(): void { + this.observeNavigation() + } ngOnDestroy(): void { this.subs.forEach((value) => value.unsubscribe()); } + observeNavigation() { + this.router.events.subscribe({ + next: (event) => { + if (event instanceof NavigationEnd) + this.uiService.setImage(this.getRandomImage()) + } + }) + } + + getRandomImage() { + return this.tempImages[Math.floor(0 + Math.random() * ((this.tempImages.length - 1) + 1 - 0))] + } + // openPopup(template?: TemplateRef) { // this.subs.set( // 'popup-events', diff --git a/src/app/services/ui.service.spec.ts b/src/app/services/ui.service.spec.ts new file mode 100644 index 0000000..fa9f878 --- /dev/null +++ b/src/app/services/ui.service.spec.ts @@ -0,0 +1,16 @@ +import { TestBed } from '@angular/core/testing'; + +import { UiService } from './ui.service'; + +describe('UiService', () => { + let service: UiService; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(UiService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); diff --git a/src/app/services/ui.service.ts b/src/app/services/ui.service.ts new file mode 100644 index 0000000..8e2f3f2 --- /dev/null +++ b/src/app/services/ui.service.ts @@ -0,0 +1,27 @@ +import { EventEmitter, inject, Injectable, Output } from '@angular/core'; +import { LocalStorageService } from 'ngx-webstorage'; + +@Injectable({ + providedIn: 'root' +}) +export class UiService { + storage = inject(LocalStorageService) + + @Output() imageChange: EventEmitter = new EventEmitter() + + constructor() { } + + setTheme (theme: string) { + document.querySelector('html')?.setAttribute('data-theme', theme) + } + + detectThemeChange() { + this.storage.observe('theme').subscribe(value => { + this.setTheme(value) + }) + } + + setImage(url: string) { + this.imageChange.emit(url) + } +} diff --git a/src/assets/games/minecraft/backgrounds/compressed/0.webp b/src/assets/games/minecraft/backgrounds/compressed/0.webp new file mode 100644 index 0000000..6252656 Binary files /dev/null and b/src/assets/games/minecraft/backgrounds/compressed/0.webp differ diff --git a/src/assets/games/minecraft/backgrounds/compressed/1.webp b/src/assets/games/minecraft/backgrounds/compressed/1.webp new file mode 100644 index 0000000..12af7cf Binary files /dev/null and b/src/assets/games/minecraft/backgrounds/compressed/1.webp differ diff --git a/src/assets/games/minecraft/backgrounds/compressed/2.webp b/src/assets/games/minecraft/backgrounds/compressed/2.webp new file mode 100644 index 0000000..49d85fc Binary files /dev/null and b/src/assets/games/minecraft/backgrounds/compressed/2.webp differ diff --git a/src/assets/games/minecraft/backgrounds/compressed/3.webp b/src/assets/games/minecraft/backgrounds/compressed/3.webp new file mode 100644 index 0000000..93e5836 Binary files /dev/null and b/src/assets/games/minecraft/backgrounds/compressed/3.webp differ diff --git a/src/assets/games/minecraft/backgrounds/compressed/4.webp b/src/assets/games/minecraft/backgrounds/compressed/4.webp new file mode 100644 index 0000000..2ad97e5 Binary files /dev/null and b/src/assets/games/minecraft/backgrounds/compressed/4.webp differ diff --git a/src/assets/games/minecraft/backgrounds/compressed/5.webp b/src/assets/games/minecraft/backgrounds/compressed/5.webp new file mode 100644 index 0000000..2068802 Binary files /dev/null and b/src/assets/games/minecraft/backgrounds/compressed/5.webp differ diff --git a/src/assets/games/minecraft/backgrounds/compressed/6.webp b/src/assets/games/minecraft/backgrounds/compressed/6.webp new file mode 100644 index 0000000..e8babac Binary files /dev/null and b/src/assets/games/minecraft/backgrounds/compressed/6.webp differ diff --git a/src/assets/games/minecraft/backgrounds/compressed/7.webp b/src/assets/games/minecraft/backgrounds/compressed/7.webp new file mode 100644 index 0000000..33dfff0 Binary files /dev/null and b/src/assets/games/minecraft/backgrounds/compressed/7.webp differ diff --git a/src/assets/games/minecraft/backgrounds/compressed/8.webp b/src/assets/games/minecraft/backgrounds/compressed/8.webp new file mode 100644 index 0000000..2f4e7f7 Binary files /dev/null and b/src/assets/games/minecraft/backgrounds/compressed/8.webp differ diff --git a/src/styles.scss b/src/styles.scss index 88677e3..980d074 100644 --- a/src/styles.scss +++ b/src/styles.scss @@ -1,6 +1,6 @@ @use 'src/light'; @use 'src/dark'; -@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800;900&display=swap'); +@import url('https://fonts.googleapis.com/css2?family=Inter+Tight:wght@400;500;600;700;800;900&display=swap'); html, body { background-color: var(--sk-background); @@ -9,10 +9,12 @@ html, body { margin: 0; font-family: var(--font); user-select: none; + letter-spacing: 0.04rem; } button, input, textarea { font-family: var(--font); + letter-spacing: 0.04rem; } @media (prefers-color-scheme: dark) { @@ -36,12 +38,15 @@ html[data-theme="dark"]:root { } :root { - --font: 'Inter', system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; + --font: 'Inter Tight', system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; } /* Works on Firefox */ * { scrollbar-width: thin; + -webkit-user-drag: none; + -webkit-app-region: no-drag; + // cursor: default; } *::-webkit-scrollbar {