diff --git a/frontend/bun.lock b/frontend/bun.lock index f09b071..91de068 100644 --- a/frontend/bun.lock +++ b/frontend/bun.lock @@ -14,6 +14,10 @@ "@angular/platform-browser": "^18.2.0", "@angular/platform-browser-dynamic": "^18.2.0", "@angular/router": "^18.2.0", + "@fortawesome/angular-fontawesome": "^1.0.0", + "@fortawesome/fontawesome-svg-core": "^6.7.2", + "@fortawesome/free-brands-svg-icons": "^6.7.2", + "@fortawesome/free-solid-svg-icons": "^6.7.2", "@stripe/stripe-js": "^5.6.0", "@tailwindcss/postcss": "^4.0.3", "keycloak-angular": "^16.0.1", @@ -373,6 +377,16 @@ "@eslint/plugin-kit": ["@eslint/plugin-kit@0.2.5", "", { "dependencies": { "@eslint/core": "^0.10.0", "levn": "^0.4.1" } }, "sha512-lB05FkqEdUg2AA0xEbUz0SnkXT1LcCTa438W4IWTUh4hdOnVbQyOJ81OrDXsJk/LSiJHubgGEFoR5EHq1NsH1A=="], + "@fortawesome/angular-fontawesome": ["@fortawesome/angular-fontawesome@1.0.0", "", { "dependencies": { "@fortawesome/fontawesome-svg-core": "^6.7.1", "tslib": "^2.8.1" }, "peerDependencies": { "@angular/core": "^19.0.0" } }, "sha512-EC2fYuXIuw2ld1kzJi+zysWus6OeGGfLQtbh0hW9zyyq5aBo8ZJkcJKBsVQ8E6Mg7nHyTWaXn+sdcXTPDWz+UQ=="], + + "@fortawesome/fontawesome-common-types": ["@fortawesome/fontawesome-common-types@6.7.2", "", {}, "sha512-Zs+YeHUC5fkt7Mg1l6XTniei3k4bwG/yo3iFUtZWd/pMx9g3fdvkSK9E0FOC+++phXOka78uJcYb8JaFkW52Xg=="], + + "@fortawesome/fontawesome-svg-core": ["@fortawesome/fontawesome-svg-core@6.7.2", "", { "dependencies": { "@fortawesome/fontawesome-common-types": "6.7.2" } }, "sha512-yxtOBWDrdi5DD5o1pmVdq3WMCvnobT0LU6R8RyyVXPvFRd2o79/0NCuQoCjNTeZz9EzA9xS3JxNWfv54RIHFEA=="], + + "@fortawesome/free-brands-svg-icons": ["@fortawesome/free-brands-svg-icons@6.7.2", "", { "dependencies": { "@fortawesome/fontawesome-common-types": "6.7.2" } }, "sha512-zu0evbcRTgjKfrr77/2XX+bU+kuGfjm0LbajJHVIgBWNIDzrhpRxiCPNT8DW5AdmSsq7Mcf9D1bH0aSeSUSM+Q=="], + + "@fortawesome/free-solid-svg-icons": ["@fortawesome/free-solid-svg-icons@6.7.2", "", { "dependencies": { "@fortawesome/fontawesome-common-types": "6.7.2" } }, "sha512-GsBrnOzU8uj0LECDfD5zomZJIjrPhIlWU82AHwa2s40FKH+kcxQaBvBo3Z4TxyZHIyX8XTDxsyA33/Vx9eFuQA=="], + "@humanfs/core": ["@humanfs/core@0.19.1", "", {}, "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA=="], "@humanfs/node": ["@humanfs/node@0.16.6", "", { "dependencies": { "@humanfs/core": "^0.19.1", "@humanwhocodes/retry": "^0.3.0" } }, "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw=="], diff --git a/frontend/package.json b/frontend/package.json index c6be094..c79aae0 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -23,6 +23,10 @@ "@angular/platform-browser": "^18.2.0", "@angular/platform-browser-dynamic": "^18.2.0", "@angular/router": "^18.2.0", + "@fortawesome/angular-fontawesome": "^1.0.0", + "@fortawesome/fontawesome-svg-core": "^6.7.2", + "@fortawesome/free-brands-svg-icons": "^6.7.2", + "@fortawesome/free-solid-svg-icons": "^6.7.2", "@stripe/stripe-js": "^5.6.0", "@tailwindcss/postcss": "^4.0.3", "keycloak-angular": "^16.0.1", @@ -49,4 +53,4 @@ "typescript": "~5.5.2", "typescript-eslint": "8.23.0" } -} \ No newline at end of file +} diff --git a/frontend/src/app/app.component.html b/frontend/src/app/app.component.html index 0680b43..41260d2 100644 --- a/frontend/src/app/app.component.html +++ b/frontend/src/app/app.component.html @@ -1 +1,6 @@ - +
+
+ +
+ +
diff --git a/frontend/src/app/app.component.ts b/frontend/src/app/app.component.ts index 7dea888..bbc5fb6 100644 --- a/frontend/src/app/app.component.ts +++ b/frontend/src/app/app.component.ts @@ -2,11 +2,12 @@ import { Component, ChangeDetectionStrategy } from '@angular/core'; import { CommonModule } from '@angular/common'; import { RouterOutlet } from '@angular/router'; import { KeycloakAngularModule } from 'keycloak-angular'; +import { FooterComponent } from './shared/components/footer/footer.component'; @Component({ selector: 'app-root', standalone: true, - imports: [CommonModule, RouterOutlet, KeycloakAngularModule], + imports: [CommonModule, RouterOutlet, KeycloakAngularModule, FooterComponent], providers: [], templateUrl: './app.component.html', styleUrl: './app.component.css', diff --git a/frontend/src/app/app.config.ts b/frontend/src/app/app.config.ts index c6b9f77..8401ece 100644 --- a/frontend/src/app/app.config.ts +++ b/frontend/src/app/app.config.ts @@ -4,6 +4,7 @@ import { provideExperimentalZonelessChangeDetection, } from '@angular/core'; import { provideRouter } from '@angular/router'; +import { FontAwesomeModule } from '@fortawesome/angular-fontawesome'; import { routes } from './app.routes'; import { @@ -38,6 +39,7 @@ export const appConfig: ApplicationConfig = { providers: [ provideRouter(routes), KeycloakAngularModule, + FontAwesomeModule, { provide: APP_INITIALIZER, useFactory: initializeApp, diff --git a/frontend/src/app/feature/deposit/deposit.component.ts b/frontend/src/app/feature/deposit/deposit.component.ts index 6b8393d..36ec63f 100644 --- a/frontend/src/app/feature/deposit/deposit.component.ts +++ b/frontend/src/app/feature/deposit/deposit.component.ts @@ -7,7 +7,6 @@ import { environment } from '../../../environments/environment'; import { NgIf } from '@angular/common'; import { MatDialogActions, - MatDialogClose, MatDialogContent, MatDialogRef, MatDialogTitle, @@ -23,7 +22,6 @@ import { MatButton } from '@angular/material/button'; MatDialogTitle, MatDialogContent, MatDialogActions, - MatDialogClose, MatButton, ], templateUrl: './deposit.component.html', diff --git a/frontend/src/app/feature/home/home.component.html b/frontend/src/app/feature/home/home.component.html index b85ce29..27cec95 100644 --- a/frontend/src/app/feature/home/home.component.html +++ b/frontend/src/app/feature/home/home.component.html @@ -1,14 +1,4 @@ - +
diff --git a/frontend/src/app/feature/home/home.component.ts b/frontend/src/app/feature/home/home.component.ts index a4b2b8b..7475214 100644 --- a/frontend/src/app/feature/home/home.component.ts +++ b/frontend/src/app/feature/home/home.component.ts @@ -3,10 +3,11 @@ import { KeycloakService } from 'keycloak-angular'; import { MatDialog } from '@angular/material/dialog'; import { DepositComponent } from '../deposit/deposit.component'; +import { NavbarComponent } from '../../shared/components/navbar/navbar.component'; @Component({ selector: 'app-homepage', standalone: true, - imports: [], + imports: [NavbarComponent], templateUrl: './home.component.html', changeDetection: ChangeDetectionStrategy.OnPush, }) diff --git a/frontend/src/app/feature/landing/landing.component.html b/frontend/src/app/feature/landing/landing.component.html index 80d5974..fb7e0e2 100644 --- a/frontend/src/app/feature/landing/landing.component.html +++ b/frontend/src/app/feature/landing/landing.component.html @@ -1,5 +1,142 @@ -@if (isLoggedIn) { - -} @else { - -} + + +
+
+
+
+

+ Willkommensbonus +

+
200% bis zu 500€
+

+ 200 Freispiele

+ + +
+ +
+

Beliebte Spiele

+
+
+
+
+
+
+

Slots

+

Klassische Spielautomaten

+ +
+
+
+
+

Plinko

+

Spannendes Geschicklichkeitsspiel

+ +
+
+ +
+ +
+
+
+

Poker

+

Texas Hold'em & mehr

+ +
+
+
+
+

Liars Dice

+

Würfelspiel mit Strategie

+ +
+
+ +
+
+
+ + + + +
+ +
+
+
+ +
+
+
50 Mio.€+
+
Ausgezahlt
+
+ +
+
10 Mio.+
+
Spiele
+
+ +
+
24/7
+
Support *
+
+
+
+
+
diff --git a/frontend/src/app/feature/landing/landing.component.ts b/frontend/src/app/feature/landing/landing.component.ts index d2e28c0..7fa92b6 100644 --- a/frontend/src/app/feature/landing/landing.component.ts +++ b/frontend/src/app/feature/landing/landing.component.ts @@ -1,21 +1,55 @@ -import { Component, inject } from '@angular/core'; -import { KeycloakService } from 'keycloak-angular'; -import { RouterLink } from '@angular/router'; +import { ChangeDetectionStrategy, Component, OnInit, OnDestroy } from '@angular/core'; +import { NavbarComponent } from '../../shared/components/navbar/navbar.component'; +import { NgFor } from '@angular/common'; @Component({ - selector: 'app-landing', + selector: 'app-landing-page', standalone: true, - imports: [RouterLink], + imports: [NavbarComponent, NgFor], templateUrl: './landing.component.html', + changeDetection: ChangeDetectionStrategy.OnPush, }) -export class LandingComponent { - private keycloakService: KeycloakService = inject(KeycloakService); +export class LandingComponent implements OnInit, OnDestroy { + currentSlide = 0; + private autoplayInterval: ReturnType | undefined; - public isLoggedIn = this.keycloakService.isLoggedIn(); + ngOnInit() { + this.startAutoplay(); + } - public login() { - const baseUrl = window.location.origin; + ngOnDestroy() { + this.stopAutoplay(); + } - this.keycloakService.login({ redirectUri: `${baseUrl}/home` }); + prevSlide() { + this.currentSlide = this.currentSlide === 0 ? 1 : 0; + this.resetAutoplay(); + } + + nextSlide() { + this.currentSlide = this.currentSlide === 1 ? 0 : 1; + this.resetAutoplay(); + } + + goToSlide(index: number) { + this.currentSlide = index; + this.resetAutoplay(); + } + + private startAutoplay() { + this.autoplayInterval = setInterval(() => { + this.nextSlide(); + }, 5000); + } + + private stopAutoplay() { + if (this.autoplayInterval) { + clearInterval(this.autoplayInterval); + } + } + + private resetAutoplay() { + this.stopAutoplay(); + this.startAutoplay(); } } diff --git a/frontend/src/app/shared/components/footer/footer.component.html b/frontend/src/app/shared/components/footer/footer.component.html new file mode 100644 index 0000000..87c4682 --- /dev/null +++ b/frontend/src/app/shared/components/footer/footer.component.html @@ -0,0 +1,80 @@ +
+
+
+ + + +
+ +
+ + + + + + + +
+
+
+ +
+
+ +
+
+
+
diff --git a/frontend/src/app/shared/components/footer/footer.component.ts b/frontend/src/app/shared/components/footer/footer.component.ts new file mode 100644 index 0000000..1c3b309 --- /dev/null +++ b/frontend/src/app/shared/components/footer/footer.component.ts @@ -0,0 +1,22 @@ +import { ChangeDetectionStrategy, Component } from '@angular/core'; +import { FontAwesomeModule } from '@fortawesome/angular-fontawesome'; +import { faMoneyBillTransfer, faCreditCard, faWallet } from '@fortawesome/free-solid-svg-icons'; +import { faPaypal, faGooglePay, faApplePay } from '@fortawesome/free-brands-svg-icons'; + +@Component({ + selector: 'app-footer', + standalone: true, + templateUrl: './footer.component.html', + imports: [FontAwesomeModule], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class FooterComponent { + currentYear: number = new Date().getFullYear(); + + faPaypal = faPaypal; + faCreditCard = faCreditCard; + faMoneyBillTransfer = faMoneyBillTransfer; + faWallet = faWallet; + faGooglePay = faGooglePay; + faApplePay = faApplePay; +} diff --git a/frontend/src/app/shared/components/navbar/navbar.component.html b/frontend/src/app/shared/components/navbar/navbar.component.html new file mode 100644 index 0000000..6ce24cc --- /dev/null +++ b/frontend/src/app/shared/components/navbar/navbar.component.html @@ -0,0 +1,70 @@ + diff --git a/frontend/src/app/shared/components/navbar/navbar.component.ts b/frontend/src/app/shared/components/navbar/navbar.component.ts new file mode 100644 index 0000000..ba86e73 --- /dev/null +++ b/frontend/src/app/shared/components/navbar/navbar.component.ts @@ -0,0 +1,34 @@ +import { ChangeDetectionStrategy, Component, inject } from '@angular/core'; +import { RouterModule } from '@angular/router'; +import { KeycloakService } from 'keycloak-angular'; + +@Component({ + selector: 'app-navbar', + templateUrl: './navbar.component.html', + standalone: true, + imports: [RouterModule], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class NavbarComponent { + isMenuOpen = false; + private keycloakService: KeycloakService = inject(KeycloakService); + + isLoggedIn = this.keycloakService.isLoggedIn(); + + login() { + try { + const baseUrl = window.location.origin; + this.keycloakService.login({ redirectUri: `${baseUrl}/home` }); + } catch (error) { + console.error('Login failed:', error); + } + } + + logout() { + this.keycloakService.logout(); + } + + toggleMenu() { + this.isMenuOpen = !this.isMenuOpen; + } +} diff --git a/frontend/src/styles.css b/frontend/src/styles.css index 12c08a1..d19c673 100644 --- a/frontend/src/styles.css +++ b/frontend/src/styles.css @@ -1,19 +1,143 @@ @import 'tailwindcss'; @theme { - --color-deep-blue: #0f212e; - --color-deep-blue-light: #1a2c38; - --color-deep-blue-contrast: #1b2c3b; - --color-light-blue: #1475e1; + --color-deep-blue: #0a1219; + --color-deep-blue-light: #121e27; + --color-deep-blue-contrast: #1a2835; + + --color-emerald: #10b981; + --color-emerald-dark: #059669; + --color-emerald-light: #34d399; + + --color-text-primary: #ffffff; + --color-text-secondary: #94a3b8; + --color-text-tertiary: #64748b; + + --color-accent-yellow: #fbbf24; + --color-accent-red: #ef4444; + --color-accent-purple: #8b5cf6; } body { - @apply bg-deep-blue text-gray-100; + @apply !bg-deep-blue !text-text-primary h-full; +} + +button, +a { + @apply cursor-pointer active:scale-95 !text-text-primary transition-all duration-200; +} + +.card { + @apply bg-deep-blue-contrast rounded-lg overflow-hidden shadow-lg hover:shadow-xl transition-shadow duration-300; +} + +.button-base { + @apply bg-emerald hover:bg-emerald-dark !text-text-primary transition-all duration-300 active:scale-95 rounded; +} + +.game-card-content { + @apply p-4; +} + +.nav-button { + @apply hidden lg:block absolute top-1/2 -translate-y-1/2 bg-deep-blue-contrast hover:bg-deep-blue-contrast/90 !text-text-primary p-3 rounded-full opacity-0 group-hover:opacity-100 transition-all duration-300 shadow-lg hover:scale-110; +} + +.slider-container { + @apply flex transition-transform duration-500 ease-out; +} + +.slider-grid { + @apply min-w-full grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4; +} + +.welcome-bonus { + @apply !text-4xl sm:!text-5xl lg:!text-7xl !font-extrabold !text-emerald-light mb-3 sm:mb-4; +} + +.bonus-description { + @apply !text-text-secondary !text-base sm:!text-lg mb-6 sm:mb-8; +} + +.section-heading { + @apply !font-bold !text-text-primary; +} + +.game-heading { + @apply !font-bold !text-text-primary !text-sm mb-2; +} + +.game-text { + @apply !text-text-secondary !text-sm mb-4; +} + +.stat-container { + @apply bg-deep-blue-contrast rounded-lg shadow-lg p-4 sm:p-6 !text-center; +} + +.stat-number { + @apply !text-xl sm:!text-2xl !font-bold !text-emerald; +} + +.stat-text { + @apply !text-text-secondary !text-sm; +} + +.nav-brand { + @apply flex items-center !text-text-primary !text-xl !font-semibold; +} + +.nav-link { + @apply px-3 py-2 rounded-md !font-normal !text-sm !text-text-secondary hover:!text-text-primary hover:bg-deep-blue-contrast transition-all duration-200; +} + +.nav-toggle { + @apply !text-text-secondary hover:!text-text-primary transition-colors duration-200; +} + +.nav-mobile-menu { + @apply p-2 pt-2 mb-4 space-y-1 bg-deep-blue-contrast rounded-b-lg; +} + +.nav-mobile-link { + @apply block px-3 py-2 rounded-md !text-sm !text-text-secondary hover:!text-text-primary hover:bg-deep-blue-light transition-all duration-200; +} + +.footer-section { + @apply col-span-2 md:col-span-1; +} + +.footer-heading { + @apply !text-text-primary !text-sm !font-semibold mb-4; +} + +.footer-link { + @apply !text-text-secondary hover:!text-text-primary !text-sm transition-all duration-200; +} + +.footer-payment-method { + @apply bg-deep-blue rounded p-3 flex items-center justify-center space-x-2 hover:bg-deep-blue/50 transition-all duration-200; +} + +.footer-payment-icon { + @apply !text-text-secondary !text-lg; +} + +.footer-payment-text { + @apply !text-text-secondary !text-xs !whitespace-nowrap; +} + +.footer-copyright { + @apply !text-text-secondary !text-sm; +} + +.footer-disclaimer { + @apply !text-xs; } .mat-mdc-dialog-container { - --mdc-dialog-container-color: var(--color-deep-blue-light) !important; - --mdc-dialog-subhead-color: #ffffff !important; - --mdc-dialog-supporting-text-color: #9ca3af !important; - --mdc-dialog-container-shape: 6px !important; + --mdc-dialog-container-color: var(--color-deep-blue-light) important; + --mdc-dialog-subhead-color: var(--color-text-primary) important; + --mdc-dialog-supporting-text-color: var(--color-text-secondary) important; + --mdc-dialog-container-shape: 6px important; }