feat: restyle navbar #284

Merged
ptran merged 6 commits from homepage into main 2025-06-04 10:23:17 +00:00
9 changed files with 268 additions and 132 deletions

View file

@ -21,7 +21,8 @@
{
"glob": "**/*",
"input": "public"
}
},
"src/assets"
],
"styles": [
"src/styles.css"

View file

@ -4,7 +4,7 @@
</div>
<div class="grid grid-cols-1 lg:grid-cols-4 gap-6">
<div class="lg:col-span-3">
<div class="lg:col-span-4">
<div class="flex justify-between items-center mb-6">
<h3 class="section-heading text-2xl">Alle Spiele</h3>
<div class="flex space-x-2">
@ -18,24 +18,54 @@
</div>
<div class="slider-container">
<div class="slider-grid">
<div class="card group" *ngFor="let game of featuredGames">
<div class="relative overflow-hidden rounded-lg">
<img
[src]="game.image"
[alt]="game.name"
class="w-full aspect-[4/3] object-cover transition-transform duration-300 group-hover:scale-105"
/>
<div
class="absolute inset-0 bg-gradient-to-t from-deep-blue/95 via-deep-blue/50 to-transparent opacity-0 group-hover:opacity-100 transition-all duration-300 ease-in-out"
>
<div class="min-w-full space-y-4">
<!-- Top row with 3 games -->
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
<div class="card group" *ngFor="let game of featuredGames.slice(0, 3)">
<div class="relative overflow-hidden rounded-lg">
<img
[src]="game.image"
[alt]="game.name"
class="w-full aspect-[4/3] object-cover transition-transform duration-300 group-hover:scale-105"
/>
<div
class="absolute bottom-4 left-4 right-4 transform translate-y-4 group-hover:translate-y-0 transition-transform duration-300"
class="absolute inset-0 bg-gradient-to-t from-deep-blue/95 via-deep-blue/50 to-transparent opacity-0 group-hover:opacity-100 transition-all duration-300 ease-in-out"
>
<h4 class="game-heading">{{ game.name }}</h4>
<button class="button-primary w-full py-2" (click)="navigateToGame(game.route)">
Jetzt Spielen
</button>
<div
class="absolute bottom-4 left-4 right-4 transform translate-y-4 group-hover:translate-y-0 transition-transform duration-300"
>
<h4 class="game-heading">{{ game.name }}</h4>
<button class="button-primary w-full py-2" (click)="navigateToGame(game.route)">
Jetzt Spielen
</button>
</div>
</div>
</div>
</div>
</div>
<!-- Bottom row with 2 games centered -->
<div
class="grid grid-cols-1 sm:grid-cols-2 gap-4 max-w-2xl mx-auto xl:max-w-3xl xl:gap-6"
>
<div class="card group" *ngFor="let game of featuredGames.slice(3, 5)">
<div class="relative overflow-hidden rounded-lg">
<img
[src]="game.image"
[alt]="game.name"
class="w-full aspect-[4/3] object-cover transition-transform duration-300 group-hover:scale-105"
/>
<div
class="absolute inset-0 bg-gradient-to-t from-deep-blue/95 via-deep-blue/50 to-transparent opacity-0 group-hover:opacity-100 transition-all duration-300 ease-in-out"
>
<div
class="absolute bottom-4 left-4 right-4 transform translate-y-4 group-hover:translate-y-0 transition-transform duration-300"
>
<h4 class="game-heading">{{ game.name }}</h4>
<button class="button-primary w-full py-2" (click)="navigateToGame(game.route)">
Jetzt Spielen
</button>
</div>
</div>
</div>
</div>
@ -43,53 +73,5 @@
</div>
</div>
</div>
<div class="lg:col-span-1 space-y-6">
<div class="card p-4">
<h3 class="section-heading text-xl mb-4">Konto</h3>
<div class="space-y-4">
<button class="button-primary w-full py-2" (click)="openDepositModal()">Einzahlen</button>
<app-deposit
[isOpen]="isDepositModalOpen"
(closeModalEmitter)="closeDepositModal()"
></app-deposit>
<button
class="bg-deep-blue-light hover:bg-deep-blue-contrast w-full py-2 rounded"
(click)="openTransactionModal()"
>
Transaktionen
</button>
<app-transaction-history
[isOpen]="isTransactionModalOpen"
(closeEventEmitter)="closeTransactionModal()"
/>
</div>
</div>
<app-confirmation
[successful]="isDepositSuccessful"
(closeConfirmation)="closeDepositConfirmationModal()"
></app-confirmation>
<div class="card p-4">
<h3 class="section-heading text-xl mb-4">Letzte Transaktionen</h3>
<div class="space-y-3">
<div
class="flex justify-between items-center"
*ngFor="let transaction of (recentTransactionData | async)?.transactions"
>
<div>
<p class="text-sm font-medium">{{ transaction.status }}</p>
<p class="text-xs text-text-secondary">
{{ transaction.createdAt | date: 'd.m.y H:m' }}
</p>
</div>
<span [class]="transaction.amount > 0 ? 'text-emerald' : 'text-accent-red'">
{{ transaction.amount | currency: 'EUR' }}
</span>
</div>
</div>
</div>
</div>
</div>
</div>

View file

@ -1,34 +1,18 @@
import { ChangeDetectionStrategy, Component, inject, OnInit } from '@angular/core';
import { AsyncPipe, CurrencyPipe, DatePipe, NgFor } from '@angular/common';
import { DepositComponent } from '../deposit/deposit.component';
import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
import { NgFor } from '@angular/common';
import { ActivatedRoute, Router } from '@angular/router';
import { ConfirmationComponent } from '@shared/components/confirmation/confirmation.component';
import { Game } from 'app/model/Game';
import { Observable } from 'rxjs';
import { TransactionService } from '@service/transaction.service';
import format from 'ajv/dist/vocabularies/format';
import { TransactionHistoryComponent } from '../transaction-history/transaction-history.component';
import { TransactionData } from '../../model/TransactionData';
@Component({
selector: 'app-homepage',
standalone: true,
imports: [
CurrencyPipe,
NgFor,
DepositComponent,
ConfirmationComponent,
AsyncPipe,
DatePipe,
TransactionHistoryComponent,
],
imports: [NgFor],
templateUrl: './home.component.html',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export default class HomeComponent implements OnInit {
isDepositModalOpen = false;
isDepositSuccessful = false;
isTransactionModalOpen = false;
constructor(
public route: ActivatedRoute,
@ -78,35 +62,10 @@ export default class HomeComponent implements OnInit {
},
];
allGames: Game[] = [...this.featuredGames];
recentTransactionData: Observable<TransactionData> =
inject(TransactionService).getUsersTransactions(5);
openDepositModal() {
this.isDepositModalOpen = true;
}
closeDepositModal() {
this.isDepositModalOpen = false;
}
openDepositConfirmationModal() {
this.isDepositSuccessful = true;
}
openTransactionModal() {
this.isTransactionModalOpen = true;
}
closeDepositConfirmationModal() {
this.isDepositSuccessful = false;
}
closeTransactionModal() {
this.isTransactionModalOpen = false;
}
navigateToGame(route: string) {
this.router.navigate([route]);
}

View file

@ -1,40 +1,118 @@
<nav class="bg-deep-blue border-b border-deep-blue-contrast">
<div class="max-w-full mx-auto px-4">
<div class="flex justify-between items-center h-14">
<nav class="bg-deep-blue-light border-b border-emerald-500/30 shadow-lg">
<div class="max-w-full mx-auto px-6">
<div class="flex justify-between items-center h-16">
<div class="flex items-center space-x-6">
<a routerLink="/" class="nav-brand">
<span>Trustworthy Casino</span>
<a routerLink="/" class="flex items-center space-x-3 group">
<div class="flex flex-col">
<span class="text-xl font-bold text-white"> Trustworthy Casino </span>
<span class="text-xs text-emerald-400 font-medium">Trust. Play. Win.</span>
</div>
</a>
<div class="hidden md:flex items-center space-x-1">
<a routerLink="/home" class="nav-link">Spiele</a>
<a
routerLink="/home"
class="flex items-center px-4 py-2 text-white/90 hover:text-white font-medium rounded-lg hover:bg-white/10 transition-colors duration-200"
>
<img class="mr-2 w-4 h-4" src="assets/games.svg" alt="gamess" />
Spiele
</a>
</div>
</div>
<div class="hidden md:flex items-center space-x-4">
<div class="hidden md:flex items-center space-x-2">
@if (!isLoggedIn()) {
<button (click)="showLogin.emit()" class="button-primary px-4 py-1.5">Anmelden</button>
<button
(click)="showLogin.emit()"
class="flex items-center px-4 py-2 text-white font-medium border border-emerald-500 rounded-lg hover:bg-emerald-500/10 transition-colors duration-200"
>
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M11 16l-4-4m0 0l4-4m-4 4h14m-5 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h7a3 3 0 013 3v1"
/>
</svg>
Anmelden
</button>
<button
(click)="showRegister.emit()"
class="bg-emerald-700 text-white hover:bg-emerald-600 px-4 py-1.5 rounded"
class="flex items-center px-4 py-2 bg-emerald-600 text-white font-medium rounded-lg hover:bg-emerald-500 transition-colors duration-200"
>
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M18 9v3m0 0v3m0-3h3m-3 0h-3m-2-5a4 4 0 11-8 0 4 4 0 018 0zM3 20a6 6 0 0112 0v1H3v-1z"
/>
</svg>
Registrieren
</button>
}
@if (isLoggedIn()) {
<div
class="text-white font-bold bg-deep-blue-contrast rounded-full px-4 py-2 text-sm hover:bg-deep-blue-contrast/80 hover:cursor-pointer hover:scale-105 transition-all active:scale-95 select-none duration-300"
routerLink="/home"
class="flex items-center px-4 py-2 bg-slate-700 border border-emerald-500/30 rounded-lg font-medium"
>
<span [class]="balance() < 0 ? 'text-accent-red' : ''">
<span class="text-emerald-400 text-sm mr-2">Guthaben:</span>
<span
[class]="balance() < 0 ? 'text-red-400 font-bold' : 'text-white font-bold'"
class="text-sm"
>
<app-animated-number [value]="balance()" [duration]="0.5"></app-animated-number>
</span>
</div>
<button (click)="logout()" class="button-primary px-4 py-1.5">Abmelden</button>
<button
class="flex items-center px-4 py-2 bg-emerald-600 text-white font-medium rounded-lg hover:bg-emerald-500 transition-colors duration-200"
(click)="openDepositModal()"
>
<img class="mr-2 w-3 h-3" src="assets/deposit.svg" alt="deposits" />
Einzahlen
</button>
<app-deposit
[isOpen]="isDepositModalOpen"
(closeModalEmitter)="closeDepositModal()"
></app-deposit>
<button
class="flex items-center px-4 py-2 bg-slate-700 text-white font-medium rounded-lg hover:bg-slate-600 border border-slate-600 transition-colors duration-200"
(click)="openTransactionModal()"
>
<img class="mr-2 w-4 h-4" src="assets/transaction.svg" alt="transactions" />
Transaktionen
</button>
<app-transaction-history
[isOpen]="isTransactionModalOpen"
(closeEventEmitter)="closeTransactionModal()"
/>
<button
(click)="logout()"
class="flex items-center px-4 py-2 text-red-400 font-medium border border-red-500/50 rounded-lg hover:bg-red-500/10 transition-colors duration-200"
>
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1"
/>
</svg>
Abmelden
</button>
}
</div>
<div class="md:hidden">
<button (click)="toggleMenu()" class="nav-toggle">
<button
(click)="toggleMenu()"
class="p-2 text-white hover:text-emerald-400 rounded-lg transition-colors duration-200"
>
<svg
class="h-6 w-6"
[class.hidden]="isMenuOpen"
@ -68,25 +146,95 @@
</div>
<div [class]="isMenuOpen ? 'block' : 'hidden'" class="md:hidden">
<div class="nav-mobile-menu">
<a routerLink="/games" class="nav-mobile-link">Spiele</a>
<div class="pt-2 space-y-2">
<div class="px-2 pt-2 pb-4 space-y-3 bg-slate-700 rounded-lg mt-2">
<a
routerLink="/home"
class="flex items-center px-4 py-3 text-white/90 hover:text-white hover:bg-white/10 rounded-lg transition-colors duration-200"
>
<img class="mr-2 w-4 h-4" src="assets/games.svg" alt="gamess" />
Spiele
</a>
<div class="border-t border-slate-600 pt-3 space-y-3">
@if (!isLoggedIn()) {
<button
(click)="showLogin.emit()"
class="button-primary w-full py-1.5 block text-center"
class="w-full flex items-center justify-center px-4 py-3 text-white font-medium border border-emerald-500 rounded-lg hover:bg-emerald-500/10 transition-colors duration-200"
>
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M11 16l-4-4m0 0l4-4m-4 4h14m-5 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h7a3 3 0 013 3v1"
/>
</svg>
Anmelden
</button>
<button
(click)="showRegister.emit()"
class="bg-emerald-700 text-white hover:bg-emerald-600 w-full py-1.5 rounded block text-center"
class="w-full flex items-center justify-center px-4 py-3 bg-emerald-600 text-white font-medium rounded-lg hover:bg-emerald-500 transition-colors duration-200"
>
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M18 9v3m0 0v3m0-3h3m-3 0h-3m-2-5a4 4 0 11-8 0 4 4 0 018 0zM3 20a6 6 0 0112 0v1H3v-1z"
/>
</svg>
Registrieren
</button>
}
@if (isLoggedIn()) {
<button (click)="logout()" class="button-primary w-full py-1.5">Abmelden</button>
<div
class="flex items-center justify-center px-4 py-3 bg-slate-700 border border-emerald-500/30 rounded-lg"
>
<span class="text-emerald-400 text-sm font-medium mr-2">Guthaben:</span>
<span
[class]="balance() < 0 ? 'text-red-400 font-bold' : 'text-white font-bold'"
class="text-sm"
>
<app-animated-number [value]="balance()" [duration]="0.5"></app-animated-number>
</span>
</div>
<button
(click)="openDepositModal()"
class="w-full flex items-center justify-center px-4 py-3 bg-emerald-600 text-white font-medium rounded-lg hover:bg-emerald-500 transition-colors duration-200"
>
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M12 6v6m0 0v6m0-6h6m-6 0H6"
/>
</svg>
Einzahlen
</button>
<button
(click)="openTransactionModal()"
class="w-full flex items-center justify-center px-4 py-3 bg-slate-700 text-white font-medium rounded-lg hover:bg-slate-600 border border-slate-600 transition-colors duration-200"
>
Transaktionen
</button>
<button
(click)="logout()"
class="w-full flex items-center justify-center px-4 py-3 text-red-400 font-medium border border-red-500/50 rounded-lg hover:bg-red-500/10 transition-colors duration-200"
>
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1"
/>
</svg>
Abmelden
</button>
}
</div>
</div>

View file

@ -12,16 +12,20 @@ import { RouterModule } from '@angular/router';
import { AuthService } from '@service/auth.service';
import { Subscription } from 'rxjs';
import { AnimatedNumberComponent } from '@blackjack/components/animated-number/animated-number.component';
import { DepositComponent } from '../../../feature/deposit/deposit.component';
import { TransactionHistoryComponent } from '../../../feature/transaction-history/transaction-history.component';
@Component({
selector: 'app-navbar',
templateUrl: './navbar.component.html',
standalone: true,
imports: [RouterModule, AnimatedNumberComponent],
imports: [RouterModule, AnimatedNumberComponent, DepositComponent, TransactionHistoryComponent],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class NavbarComponent implements OnInit, OnDestroy {
isMenuOpen = false;
isDepositModalOpen = false;
isTransactionModalOpen = false;
private authService: AuthService = inject(AuthService);
isLoggedIn = signal(this.authService.isLoggedIn());
@ -51,4 +55,20 @@ export class NavbarComponent implements OnInit, OnDestroy {
toggleMenu() {
this.isMenuOpen = !this.isMenuOpen;
}
openDepositModal() {
this.isDepositModalOpen = true;
}
closeDepositModal() {
this.isDepositModalOpen = false;
}
openTransactionModal() {
this.isTransactionModalOpen = true;
}
closeTransactionModal() {
this.isTransactionModalOpen = false;
}
}

View file

@ -0,0 +1,4 @@
<svg style="color: white;" xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 16 16">
<path fill="currentColor" d="m8 16l-2-3h1v-2h2v2h1zm7-15v8H1V1zm1-1H0v10h16z"/>
<path fill="currentColor" d="M8 2a3 3 0 1 1 0 6h5V7h1V3h-1V2zM5 5a3 3 0 0 1 3-3H3v1H2v4h1v1h5a3 3 0 0 1-3-3"/>
</svg>

After

Width:  |  Height:  |  Size: 314 B

View file

@ -0,0 +1,6 @@
<svg style="color: white;" xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 512 512">
<path fill="currentColor"
d="M495.24 267.592L445.066 41.083A32.04 32.04 0 0 0 406.9 16.76L180.393 66.934a32 32 0 0 0-24.322 38.166l21.021 94.9H48a32.036 32.036 0 0 0-32 32v232a32.036 32.036 0 0 0 32 32h232a32.036 32.036 0 0 0 32-32V340.957l158.917-35.2a32.04 32.04 0 0 0 24.323-38.165M280 464H48V232h136.181l22.063 99.606a32.03 32.03 0 0 0 31.18 25.092a32.3 32.3 0 0 0 6.984-.769l35.6-7.886L280.02 464Zm184-189.487l-226.513 50.173l-50.173-226.51L413.824 48l50.193 226.505Z"/>
<path fill="currentColor"
d="M80 264h40v40H80zm0 128h40v40H80zm128 0h40v40h-40zm-64-64h40v40h-40zm81.456-205.433l39.054-8.644l8.644 39.055l-39.054 8.644zm152.672 97.223l39.054-8.65l8.65 39.054l-39.054 8.65zm-76.324-48.649l39.053-8.65l8.65 39.053l-39.052 8.65z"/>
</svg>

After

Width:  |  Height:  |  Size: 882 B

View file

@ -0,0 +1,12 @@
<svg
xmlns="http://www.w3.org/2000/svg"
width="1em"
height="1em"
viewBox="0 0 24 24"
style="color: white;"
>
<g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" color="currentColor">
<path d="M4.58 8.607L2 8.454C3.849 3.704 9.158 1 14.333 2.344c5.513 1.433 8.788 6.918 7.314 12.25c-1.219 4.411-5.304 7.337-9.8 7.406"/>
<path d="M12 22C6.5 22 2 17 2 11m11.604-1.278c-.352-.37-1.213-1.237-2.575-.62c-1.361.615-1.577 2.596.482 2.807c.93.095 1.537-.11 2.093.47c.556.582.659 2.198-.761 2.634s-2.341-.284-2.588-.509m1.653-6.484v.79m0 6.337v.873"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 639 B

View file

@ -52,7 +52,7 @@ a {
}
.slider-grid {
@apply min-w-full grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4;
@apply min-w-full grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4;
}
.welcome-bonus {
@ -71,6 +71,10 @@ a {
@apply font-bold text-text-primary text-sm mb-2;
}
.game-heading {
@apply font-bold text-text-primary text-lg mb-2;
}
.game-heading-xl {
@apply font-bold text-text-primary text-xl mb-2;
}