Updated site to use momentum for contacting, registration, gallery and calendar, as well as some other updates to the site content
All checks were successful
Build Website / Build NPM Project (push) Successful in 1m42s
Build Website / Tag Version (push) Successful in 1m2s
Build Website / Build Container (push) Successful in 2m50s

This commit is contained in:
2026-06-05 19:19:27 -04:00
parent 3e4efc2fd2
commit 16ddd1c8a3
32 changed files with 753 additions and 311 deletions

View File

@@ -1,4 +1,4 @@
import {AfterViewInit, Component, Input, OnDestroy, OnInit} from '@angular/core';
import {AfterViewInit, Component, EventEmitter, Input, OnDestroy, OnInit, Output} from '@angular/core';
import {Photo} from '../models/photo';
@Component({
@@ -18,6 +18,7 @@ export class CarouselComponent implements OnDestroy, OnInit, AfterViewInit {
@Input() disableAutoplay = false;
@Input() index = ~~(Math.random() * this.photos.length);
@Input() height = '100%';
@Output() indexChange = new EventEmitter<number>();
ngOnInit() {
if(this.disableAutoplay) this.pause = true;
@@ -41,11 +42,13 @@ export class CarouselComponent implements OnDestroy, OnInit, AfterViewInit {
this.pause = pause;
this.index++;
if(this.index >= this.photos.length) this.index = 0;
this.indexChange.emit(this.index);
}
previous(pause = true) {
this.loading = true;
this.pause = pause;
this.index = this.index > 0 ? this.index - 1 : this.photos.length - 1;
this.indexChange.emit(this.index);
}
}

View File

@@ -1,24 +1,16 @@
<footer>
<div class="social text-center py-3" style="background: #990000">
<!-- <h2 class="mb-4">Follow us on social media</h2>-->
<!-- <div class="d-flex justify-content-around mx-auto transparent-link" style="max-width: 300px">-->
<!-- <a href="https://discord.gg/wW458KYR79" target="_blank">-->
<!-- <i class="fa-brands fa-discord fa-2xl"></i>-->
<!-- </a>-->
<!-- <a href="https://facebook.com" target="_blank" aria-label="Facebook">-->
<!-- <i class="fa-brands fa-facebook fa-2xl"></i>-->
<!-- </a>-->
<!-- <a href="https://instagram.com" target="_blank" aria-label="Instagram">-->
<!-- <i class="fa-brands fa-instagram fa-2xl"></i>-->
<!-- </a>-->
<!-- <a href="https://tiktok.com" target="_blank" aria-label="TikTok">-->
<!-- <i class="fa-brands fa-tiktok fa-2xl"></i>-->
<!-- </a>-->
<!-- <a href="https://youtube.com" target="_blank" aria-label="Youtube">-->
<!-- <i class="fa-brands fa-youtube fa-2xl"></i>-->
<!-- </a>-->
<!-- </div>-->
<!-- <h3 class="mt-4 mb-0">so we can invade your feed ⚔️</h3>-->
<div class="text-center d-flex flex-row justify-content-center align-items-center gap-3">
<hr class="flex-grow-1 m-0 opacity-75">
<div class="d-flex flex-column align-items-end">
<h2 class="mb-0">Ready to Enlist?</h2>
<p class="mb-0">Take your place in our ranks...</p>
</div>
<div class="d-flex align-items-center">
<a [routerLink]="['/register']" class="btn btn-light btn-lg">JOIN NOW</a>
</div>
<hr class="flex-grow-1 m-0 opacity-75">
</div>
</div>
<div class="bg-dark text-center text-sm-start">
<div class="d-flex flex-column flex-sm-row flex-wrap justify-content-center container p-3 pb-0">

View File

@@ -1,5 +1,6 @@
import {Component, Inject} from '@angular/core';
import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog';
import {MomentumService} from '../../services/momentum.service';
import {Photo} from '../models/photo';
export interface ImageViewerOptions {
@@ -10,12 +11,13 @@ export interface ImageViewerOptions {
@Component({
selector: 'xxx-viewer',
styles: [`
.close {
.close, .delete {
position: absolute;
top: 1rem;
right: 1rem;
z-index: 100000;
}
.close { right: 1rem; }
.delete { right: 4rem; }
::ng-deep .cdk-overlay-pane {
max-width: 100% !important;
}
@@ -24,18 +26,32 @@ export interface ImageViewerOptions {
}
`],
template: `
<button class="close" mat-icon-button aria-label="close dialog" mat-dialog-close>
<button class="close" mat-icon-button mat-dialog-close>
<mat-icon>close</mat-icon>
</button>
<xxx-carousel [photos]="photos" [index]="index" [disableAutoplay]="true"></xxx-carousel>
<button *ngIf="momentum.admin | async" class="delete me-3" mat-icon-button (click)="delete()">
<mat-icon>delete</mat-icon>
</button>
<xxx-carousel [photos]="photos" [index]="index" [disableAutoplay]="true" (indexChange)="index = $event"></xxx-carousel>
`
})
export class ImageViewerComponent {
index!: number;
photos!: Photo[];
constructor(public ref: MatDialogRef<ImageViewerComponent>, @Inject(MAT_DIALOG_DATA) data: ImageViewerOptions) {
constructor(
public ref: MatDialogRef<ImageViewerComponent>,
public momentum: MomentumService,
@Inject(MAT_DIALOG_DATA) data: ImageViewerOptions
) {
this.index = data.index || 0;
this.photos = data.photos || [];
}
async delete() {
if (!confirm('Delete this photo?')) return;
const photo = this.photos[this.index];
await this.momentum.api.storage.delete(photo.path);
this.ref.close({deleted: photo});
}
}

View File

@@ -1,4 +1,5 @@
export interface Photo {
alt: string;
src: string;
path: string;
}

View File

@@ -18,10 +18,21 @@
<mat-menu #menu="matMenu">
<ng-container *ngFor="let section of group.children; let first = first">
<mat-divider *ngIf="!first"></mat-divider>
<button *ngFor="let item of section" mat-menu-item [routerLink]="item.url" [fragment]="item.fragment">
<button *ngFor="let item of section" mat-menu-item (click)="openItem(item)">
{{item.label}}
</button>
</ng-container>
<!-- Auth items, Members menu only -->
<ng-container *ngIf="group.label === 'Members'">
<mat-divider></mat-divider>
<ng-container *ngIf="momentum.isLoggedIn | async; else guestItems">
<button mat-menu-item (click)="momentum.api.auth.logout()">Logout</button>
</ng-container>
<ng-template #guestItems>
<button mat-menu-item (click)="momentum.api.auth.handleLogin()">Login</button>
<button mat-menu-item (click)="openItem({label:'Register', url:'/register'})">Register</button>
</ng-template>
</ng-container>
</mat-menu>
</ng-container>
</div>
@@ -30,7 +41,7 @@
<mat-icon>menu</mat-icon>
</button>
<mat-menu #menu="matMenu">
<button mat-menu-item *ngFor="let item of links.topLevel" [routerLink]="item.url" [fragment]="item.fragment">
<button mat-menu-item *ngFor="let item of links.topLevel" (click)="openItem(item)">>
{{item.label}}
</button>
<ng-container *ngFor="let group of links.other">

View File

@@ -1,8 +1,8 @@
import {AfterViewInit, Component, EventEmitter, Input, OnDestroy, Output} from '@angular/core';
import {ActivatedRoute, NavigationEnd, NavigationStart, Router} from '@angular/router';
import {ActivatedRoute, NavigationStart, Router} from '@angular/router';
import {combineLatest, filter, Subscription} from 'rxjs';
import {NAVIGATION} from '../../misc/navigation';
import {BreakpointService} from '../../services/breakpoint.service';
import {NAVIGATION, NavigationItem} from '../../misc/navigation';
import {MomentumService} from '../../services/momentum.service';
@Component({
selector: 'xxx-navbar',
@@ -21,7 +21,7 @@ export class NavbarComponent implements AfterViewInit, OnDestroy {
@Output() hamburgerClick = new EventEmitter<void>();
constructor(private route: ActivatedRoute, private router: Router, public breakpoint: BreakpointService) { }
constructor(private route: ActivatedRoute, private router: Router, public momentum: MomentumService) { }
ngAfterViewInit() {
this.sub = combineLatest([this.router.events.pipe(filter((e: any) => e.navigationTrigger != 'popstate' || e instanceof NavigationStart)), this.route.fragment]).subscribe(([url, frag]) => {
@@ -34,6 +34,15 @@ export class NavbarComponent implements AfterViewInit, OnDestroy {
if(this.sub) this.sub.unsubscribe();
}
openItem(item: NavigationItem) {
// Full url
if(item.url.startsWith('http'))
location.href = item.url;
// Relative
else
this.router.navigate([item.url], {fragment: item.fragment});
}
scroll(id: string) {
const el = document.getElementById(id);
if(el) el.scrollIntoView({behavior: 'smooth'});

View File

@@ -0,0 +1,16 @@
<h2 mat-dialog-title>Upload Photos</h2>
<mat-dialog-content>
<p class="text-muted">Select the year these photos were taken then choose your files.</p>
<mat-form-field appearance="outline" class="w-100">
<mat-label>Year</mat-label>
<mat-select [(ngModel)]="year">
<mat-option *ngFor="let y of years" [value]="y">{{y}}</mat-option>
</mat-select>
</mat-form-field>
</mat-dialog-content>
<mat-dialog-actions align="end">
<button mat-button mat-dialog-close>Cancel</button>
<button mat-raised-button color="primary" (click)="upload()" [disabled]="uploading">
<mat-icon>upload</mat-icon> Choose Files
</button>
</mat-dialog-actions>

View File

@@ -0,0 +1,21 @@
import {Component} from '@angular/core';
import {MatDialogRef} from '@angular/material/dialog';
import {MomentumService} from '../../services/momentum.service';
@Component({
selector: 'xxx-uploader',
templateUrl: './uploader.component.html',
})
export class UploaderComponent {
year: number = new Date().getFullYear();
years: number[] = Array.from({length: this.year - 2006}, (_, i) => 2007 + i).reverse();
uploading = false;
constructor(private momentum: MomentumService, private ref: MatDialogRef<UploaderComponent>) {}
async upload() {
this.uploading = true;
await this.momentum.api.storage.upload(`Photos/Submissions/${this.year}`, undefined, {multiple: true, accept: 'image/*'});
this.ref.close();
}
}