Skip to content

Commit

Permalink
feat: layout v2
Browse files Browse the repository at this point in the history
Signed-off-by: Dafnik <git@dafnik.me>
  • Loading branch information
Dafnik committed Apr 29, 2024
1 parent c915f1a commit da1e727
Show file tree
Hide file tree
Showing 42 changed files with 1,198 additions and 185 deletions.
6 changes: 6 additions & 0 deletions compose-local-dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,12 @@ services:
- RATE_LIMIT_ENABLED=true
- RATE_LIMIT_DURATION_IN_SECONDS=120
- RATE_LIMIT_TRIES=40
- STRIPE_ENABLED=false
- STRIPE_KEYS_SECRET=sk_test
- STRIPE_KEYS_PUBLISHABLE=pk_test
- STRIPE_WEBHOOK_SEED_ENABLED=false
- STRIPE_WEBHOOK_URL=https://not-existing.kellner.team/api/v1/public/webhooks/stripe
- STRIPE_WEBHOOK_SECRET=testabc
networks:
- kellner-backend
# No healthcheck possible as the container is distroless and therefor has no bash nor other tools to make requests
Expand Down
14 changes: 7 additions & 7 deletions src/app/_shared/ui/footer/footer.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import {injectWindow} from 'dfx-helper';
<div
class="d-flex flex-column flex-sm-row gap-2 text-body-secondary align-items-center justify-content-center justify-content-sm-between"
>
<a href="https://kellner.team" rel="noreferrer" target="_blank">
<a href="https://kellner.team" rel="noreferrer" target="_blank" style="padding-bottom: 2px;">
<div class="d-flex align-items-center py-1 gap-1 ms-1">
<svg width="80pt" height="23pt" viewBox="0 0 118 23" xmlns="http://www.w3.org/2000/svg">
<g
Expand Down Expand Up @@ -63,19 +63,19 @@ import {injectWindow} from 'dfx-helper';
</div>
<div class="d-flex flex-wrap align-items-center gap-2 text-body-emphasis justify-content-center justify-content-md-end">
<div>
<button type="button" class="btn btn-link px-0" (click)="openAbout()">
{{ 'ABOUT' | transloco }}
</button>
<a routerLink="/info/privacypolicy">
{{ 'ABOUT_PRIVACY_POLICY' | transloco }}
</a>
</div>
<div>
<a routerLink="/info/imprint">
{{ 'ABOUT_IMPRINT' | transloco }}
</a>
</div>
<div>
<a routerLink="/info/privacypolicy">
{{ 'ABOUT_PRIVACY_POLICY' | transloco }}
</a>
<button type="button" class="btn btn-link px-0" (click)="openAbout()">
{{ 'ABOUT' | transloco }}
</button>
</div>
</div>
</div>
Expand Down
44 changes: 44 additions & 0 deletions src/app/_shared/ui/theme-switcher.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import {Component, inject} from '@angular/core';
import {NgbDropdown, NgbDropdownButtonItem, NgbDropdownItem, NgbDropdownMenu, NgbDropdownToggle} from '@ng-bootstrap/ng-bootstrap';
import {ThemeService} from '@shared/services/theme.service';
import {BiComponent} from 'dfx-bootstrap-icons';

@Component({
template: `
<div class="theme-switcher">
<div ngbDropdown display="dynamic">
<button type="button" class="btn btn-primary" ngbDropdownToggle>
<bi [name]="themeService.selectedTheme().icon" />
</button>
<div ngbDropdownMenu aria-labelledby="themeDropdown" class="p-1">
@for (theme of themeService.themes; track theme.id) {
<button
type="button"
ngbDropdownItem
class="rounded-1 mt-1"
[class.active]="theme.id === themeService.selectedTheme().id"
(click)="themeService.setTheme(theme.id)"
>
<bi [name]="theme.icon" />
{{ theme.name }}
</button>
}
</div>
</div>
</div>
`,
styles: `
.theme-switcher {
z-index: 1000;
right: 20px;
bottom: 40px;
position: fixed;
}
`,
standalone: true,
imports: [BiComponent, NgbDropdown, NgbDropdownButtonItem, NgbDropdownItem, NgbDropdownMenu, NgbDropdownToggle],
selector: 'app-theme-switcher',
})
export class ThemeSwitcherComponent {
themeService = inject(ThemeService);
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {s_from} from 'dfts-helper';
import {HasDelete, HasGetAll, HasGetSingle} from 'dfx-helper';

import {BehaviorSubject, map, Observable, switchMap, tap} from 'rxjs';
import {ActiveSystemNotificationsService} from './active-system-notifications.service';
import {ActiveSystemNotificationsService} from '../../../_layout/_services/active-system-notifications.service';

@Injectable({providedIn: 'root'})
export class SystemNotificationsService
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import {Component, inject} from '@angular/core';
import {BiComponent} from 'dfx-bootstrap-icons';
import {ActiveSystemNotificationsService} from '../_services/active-system-notifications.service';
import {AppSystemNotificationAlertComponent} from './system-notification-alert.component';

@Component({
template: `
@if (activeSystemNotificationsService.allSystemNotifications().length > 0) {
<div class="d-flex flex-column gap-3 my-2">
@for (systemNotification of activeSystemNotificationsService.getFilteredSystemNotifications(); track systemNotification.id) {
<app-system-notification-alert [notification]="systemNotification" (ignore)="activeSystemNotificationsService.ignore($event)" />
}
<div class="d-flex justify-content-end">
@if (activeSystemNotificationsService.ignoredSystemNotifications().length === 0) {
<small>
<bi name="arrows-collapse" class="me-2" />
<a (click)="activeSystemNotificationsService.ignoreAll()">Alle verstecken</a>

Check warning on line 17 in src/app/home/_layout/_components/active-system-notifications.component.ts

View workflow job for this annotation

GitHub Actions / eslint

click must be accompanied by either keyup, keydown or keypress event for accessibility

Check warning on line 17 in src/app/home/_layout/_components/active-system-notifications.component.ts

View workflow job for this annotation

GitHub Actions / eslint

Elements with interaction handlers must be focusable
</small>
} @else {
<small>
<bi name="arrows-expand" class="me-2" />
<a (click)="activeSystemNotificationsService.resetIgnore()">

Check warning on line 22 in src/app/home/_layout/_components/active-system-notifications.component.ts

View workflow job for this annotation

GitHub Actions / eslint

click must be accompanied by either keyup, keydown or keypress event for accessibility

Check warning on line 22 in src/app/home/_layout/_components/active-system-notifications.component.ts

View workflow job for this annotation

GitHub Actions / eslint

Elements with interaction handlers must be focusable
{{ activeSystemNotificationsService.ignoredSystemNotifications().length }}x Nachricht(en) anzeigen
</a>
</small>
}
</div>
</div>
}
`,
standalone: true,
selector: 'app-active-system-notifications',

imports: [BiComponent, AppSystemNotificationAlertComponent],
})
export class ActiveSystemNotificationsComponent {
activeSystemNotificationsService = inject(ActiveSystemNotificationsService);
}
146 changes: 146 additions & 0 deletions src/app/home/_layout/_components/colors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
export function s_toColor(str: string): string {
// Simple hashing function to generate an index
let hash = 0;
for (let i = 0; i < str.length; i++) {
hash = str.charCodeAt(i) + ((hash << 5) - hash);
}

// Take the remainder of hash divided by the length of colorList
const index = Math.abs(hash) % colors.length;

return colors[index];
}

const colors = [
'#fca5a5',
'#f87171',
'#ef4444',
'#dc2626',
'#b91c1c',
'#991b1b',
'#7f1d1d',
'#450a0a',
'#fdba74',
'#fb923c',
'#f97316',
'#ea580c',
'#c2410c',
'#9a3412',
'#7c2d12',
'#431407',
'#fcd34d',
'#fbbf24',
'#f59e0b',
'#d97706',
'#b45309',
'#92400e',
'#78350f',
'#451a03',
'#fef08a',
'#fde047',
'#facc15',
'#eab308',
'#ca8a04',
'#a16207',
'#854d0e',
'#713f12',
'#422006',
'#bef264',
'#a3e635',
'#84cc16',
'#65a30d',
'#4d7c0f',
'#3f6212',
'#365314',
'#1a2e05',
'#4ade80',
'#22c55e',
'#16a34a',
'#15803d',
'#166534',
'#14532d',
'#052e16',
'#34d399',
'#10b981',
'#059669',
'#047857',
'#065f46',
'#064e3b',
'#022c22',
'#14b8a6',
'#0d9488',
'#0f766e',
'#115e59',
'#134e4a',
'#042f2e',
'#22d3ee',
'#06b6d4',
'#0891b2',
'#0e7490',
'#155e75',
'#164e63',
'#083344',
'#7dd3fc',
'#38bdf8',
'#0ea5e9',
'#0284c7',
'#0369a1',
'#075985',
'#0c4a6e',
'#082f49',
'#bfdbfe',
'#93c5fd',
'#60a5fa',
'#3b82f6',
'#2563eb',
'#1d4ed8',
'#1e40af',
'#1e3a8a',
'#172554',
'#c7d2fe',
'#a5b4fc',
'#818cf8',
'#6366f1',
'#4f46e5',
'#4338ca',
'#3730a3',
'#312e81',
'#1e1b4b',
'#c4b5fd',
'#a78bfa',
'#8b5cf6',
'#7c3aed',
'#4c1d95',
'#2e1065',
'#c084fc',
'#a855f7',
'#9333ea',
'#7e22ce',
'#6b21a8',
'#581c87',
'#3b0764',
'#f0abfc',
'#e879f9',
'#d946ef',
'#c026d3',
'#a21caf',
'#86198f',
'#701a75',
'#4a044e',
'#f9a8d4',
'#f472b6',
'#ec4899',
'#db2777',
'#be185d',
'#9d174d',
'#831843',
'#500724',
'#fda4af',
'#fb7185',
'#f43f5e',
'#e11d48',
'#be123c',
'#9f1239',
'#881337',
'#4c0519',
];
34 changes: 34 additions & 0 deletions src/app/home/_layout/_components/maintenance-warning.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import {Component} from '@angular/core';
import {TranslocoPipe} from '@ngneat/transloco';
import {BiComponent} from 'dfx-bootstrap-icons';
import {DfxHideIfOffline, DfxHideIfPingSucceeds} from 'dfx-helper';

@Component({
template: `
<div hideIfOffline>
<div hideIfPingSucceeds url="/json" refreshTime="10">
<div class="alert alert-warning" role="alert">
<div class="d-flex gap-3 align-items-center">
<bi name="exclamation-triangle-fill" />
<div>
<b>{{ 'ABOUT_MAINTENANCE_1' | transloco }}</b>
<br />
{{ 'ABOUT_MAINTENANCE_2' | transloco }}
<br />
{{ 'ABOUT_MAINTENANCE_3' | transloco }}
<a style="text-decoration: underline; color: #664d03" href="https://status.kellner.team" target="_blank" rel="noreferrer"
>status.kellner.team</a
>.
<br />
{{ 'ABOUT_MAINTENANCE_4' | transloco }}
</div>
</div>
</div>
</div>
</div>
`,
standalone: true,
selector: 'app-maintenance-warning',
imports: [DfxHideIfOffline, DfxHideIfPingSucceeds, BiComponent, TranslocoPipe],
})
export class MaintenanceWarningComponent {}
52 changes: 52 additions & 0 deletions src/app/home/_layout/_components/mobile-nav.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import {Component, effect, inject} from '@angular/core';
import {takeUntilDestroyed} from '@angular/core/rxjs-interop';
import {NavigationEnd, Router} from '@angular/router';
import {NgbActiveOffcanvas} from '@ng-bootstrap/ng-bootstrap';
import {IsMobileService} from 'dfx-helper';
import {filter} from 'rxjs';
import {NavComponent} from './nav.component';

@Component({
template: `
<div class="offcanvas-header d-flex justify-content-end">
<h1 class="visually-hidden" id="offcanvas-mobile-nav">Navigation</h1>
<button type="button" class="btn-close" aria-label="Close" (click)="offcanvas.close()"></button>
</div>
<div class="offcanvas-body h-100">
<app-nav class="d-flex flex-column flex-shrink-0 h-100" />
</div>
`,
styles: `
/* Opening offcanvas as a component requires this style in order to scroll */
:host {
height: 100%;
display: flex;
flex-direction: column;
}
`,
standalone: true,
selector: 'app-mobile-nav',
imports: [NavComponent],
})
export class MobileNavComponent {
offcanvas = inject(NgbActiveOffcanvas);

constructor() {
inject(Router)
.events.pipe(
takeUntilDestroyed(),
filter((it) => it instanceof NavigationEnd),
)
.subscribe(() => {
this.offcanvas.close();
});

const isMobile = inject(IsMobileService).isMobile;

effect(() => {
if (!isMobile()) {
this.offcanvas.close();
}
});
}
}

0 comments on commit da1e727

Please sign in to comment.