Replace deprecated Angular directives (*ngFor, *ngIf) with modern Angular template syntax. Remove unused CommonModule imports across components for optimization. Clean up excess spacing and formatting in HTML files.

This commit is contained in:
akastijn 2025-07-15 21:48:23 +02:00
parent d3ef296784
commit c2b9a8a574
37 changed files with 689 additions and 646 deletions

View File

@ -15,11 +15,12 @@
"prefix": "app",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:browser",
"builder": "@angular/build:application",
"options": {
"outputPath": "dist",
"outputPath": {
"base": "dist"
},
"index": "src/index.html",
"main": "src/main.ts",
"polyfills": [
"zone.js"
],
@ -34,7 +35,8 @@
"styles": [
"src/styles.scss"
],
"scripts": []
"scripts": [],
"browser": "src/main.ts"
},
"configurations": {
"production": {
@ -47,9 +49,7 @@
"optimization": true,
"outputHashing": "all",
"sourceMap": false,
"namedChunks": false,
"vendorChunk": false,
"buildOptimizer": true
"namedChunks": false
},
"development": {
"sourceMap": true,
@ -71,14 +71,12 @@
"optimization": true,
"outputHashing": "all",
"sourceMap": false,
"namedChunks": false,
"vendorChunk": false,
"buildOptimizer": true
"namedChunks": false
}
}
},
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"builder": "@angular/build:dev-server",
"configurations": {
"production": {
"buildTarget": "frontend:build:production"
@ -90,10 +88,10 @@
"defaultConfiguration": "development"
},
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n"
"builder": "@angular/build:extract-i18n"
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"builder": "@angular/build:karma",
"options": {
"polyfills": [
"zone.js",
@ -119,5 +117,31 @@
},
"cli": {
"analytics": false
},
"schematics": {
"@schematics/angular:component": {
"type": "component"
},
"@schematics/angular:directive": {
"type": "directive"
},
"@schematics/angular:service": {
"type": "service"
},
"@schematics/angular:guard": {
"typeSeparator": "."
},
"@schematics/angular:interceptor": {
"typeSeparator": "."
},
"@schematics/angular:module": {
"typeSeparator": "."
},
"@schematics/angular:pipe": {
"typeSeparator": "."
},
"@schematics/angular:resolver": {
"typeSeparator": "."
}
}
}

View File

@ -14,14 +14,14 @@
"private": true,
"dependencies": {
"@angular/cdk": "^19.2.18",
"@angular/common": "^19.2.0",
"@angular/compiler": "^19.2.0",
"@angular/core": "^19.2.0",
"@angular/forms": "^19.2.0",
"@angular/common": "^20.1.0",
"@angular/compiler": "^20.1.0",
"@angular/core": "^20.1.0",
"@angular/forms": "^20.1.0",
"@angular/material": "^19.2.19",
"@angular/platform-browser": "^19.2.0",
"@angular/platform-browser-dynamic": "^19.2.0",
"@angular/router": "^19.2.0",
"@angular/platform-browser": "^20.1.0",
"@angular/platform-browser-dynamic": "^20.1.0",
"@angular/router": "^20.1.0",
"@auth0/angular-jwt": "^5.2.0",
"@types/three": "^0.177.0",
"ngx-cookie-service": "^19.1.2",
@ -31,9 +31,9 @@
"zone.js": "~0.15.0"
},
"devDependencies": {
"@angular-devkit/build-angular": "^19.2.5",
"@angular/cli": "^19.2.5",
"@angular/compiler-cli": "^19.2.0",
"@angular/build": "^20.1.0",
"@angular/cli": "^20.1.0",
"@angular/compiler-cli": "^20.1.0",
"@types/jasmine": "~5.1.0",
"jasmine-core": "~5.6.0",
"karma": "~6.4.0",

View File

@ -1,15 +1,14 @@
import {Component} from '@angular/core';
import {ScrollService} from '@services/scroll.service';
import {CommonModule} from '@angular/common';
import {HeaderComponent} from '@header/header.component';
@Component({
selector: 'app-about',
standalone: true,
imports: [
CommonModule,
HeaderComponent
],
],
templateUrl: './about.component.html',
styleUrl: './about.component.scss'
})

View File

@ -1,15 +1,14 @@
import {Component} from '@angular/core';
import {ScrollService} from '@services/scroll.service';
import {CommonModule} from '@angular/common';
import {HeaderComponent} from '@header/header.component';
@Component({
selector: 'app-birthdays',
standalone: true,
imports: [
CommonModule,
HeaderComponent
],
],
templateUrl: './birthdays.component.html',
styleUrl: './birthdays.component.scss'
})

View File

@ -1,16 +1,15 @@
import {Component} from '@angular/core';
import {ScrollService} from '@services/scroll.service';
import {CommonModule, NgOptimizedImage} from '@angular/common';
import { NgOptimizedImage } from '@angular/common';
import {HeaderComponent} from '@header/header.component';
@Component({
selector: 'app-socials',
standalone: true,
imports: [
CommonModule,
HeaderComponent,
NgOptimizedImage
],
],
templateUrl: './socials.component.html',
styleUrl: './socials.component.scss'
})

View File

@ -1,10 +1,10 @@
<ng-container>
<app-header [current_page]="'team'" height="450px" background_image="/public/img/backgrounds/staff.png"
[overlay_gradient]="0.5">>
[overlay_gradient]="0.5">>
<div class="title" header-content>
<h1>Staffing Team</h1>
<h2>The team that makes Altitude happen. Your owners, admins, moderators, and trainees are all working together to
create Altitude, to create home. This is where the magic happens.</h2>
create Altitude, to create home. This is where the magic happens.</h2>
</div>
</app-header>
@ -12,61 +12,75 @@
<section class="darkmodeSection">
<div class="container teamContainer">
<h2 class="sectionTitle">Management</h2>
<div *ngFor="let member of getTeamMembers('owner') | async" class="member">
<img [ngSrc]="getAvatarUrl(member)" alt="{{member.name}}'s Minecraft skin"
height="160" width="160" style="width: 160px;">
<h2>{{ member.name }}</h2>
<p>Owner</p>
</div>
<div *ngFor="let member of getTeamMembers('manager') | async" class="member">
<img [ngSrc]="getAvatarUrl(member)" alt="{{member.name}}'s Minecraft skin"
height="160" width="160" style="width: 160px;">
<h2>{{ member.name }}</h2>
<p>Manager</p>
</div>
</div>
</section>
<section class="darkmodeSectionThree">
<div class="container teamContainer">
<h2 class="sectionTitle">Admins</h2>
<div *ngFor="let member of getTeamMembers('admin') | async" class="member">
<img [ngSrc]="getAvatarUrl(member)" alt="{{member.name}}'s Minecraft skin"
height="160" width="160" style="width: 160px;">
<h2>{{ member.name }}</h2>
<p>Admin</p>
</div>
</div>
</section>
<section class="darkmodeSection">
<div class="container teamContainer">
<h2 class="sectionTitle">Head Moderators</h2>
<div *ngFor="let member of getTeamMembers('headmod') | async" class="member">
<img [ngSrc]="getAvatarUrl(member)" alt="{{member.name}}'s Minecraft skin"
height="160" width="160" style="width: 160px;">
<h2>{{ member.name }}</h2>
<p>Head Mod</p>
</div>
</div>
</section>
<section class="darkmodeSectionThree">
<div class="container teamContainer">
<h2 class="sectionTitle">Moderators</h2>
<div *ngFor="let member of getTeamMembers('moderator') | async" class="member">
<img [ngSrc]="getAvatarUrl(member)" alt="{{member.name}}'s Minecraft skin"
height="160" width="160" style="width: 160px;">
<h2>{{ member.name }}</h2>
</div>
</div>
</section>
<section *ngIf="(getTeamMembers('trainee') | async)?.length ?? 0 > 0" class="darkmodeSection">
<div class="container teamContainer">
<h2 class="sectionTitle">Trainees</h2>
<div *ngFor="let member of getTeamMembers('trainee') | async" class="member">
<img [ngSrc]="getAvatarUrl(member)" alt="{{member.name}}'s Minecraft skin"
height="160" width="160" style="width: 160px;">
<h2>{{ member.name }}</h2>
</div>
</div>
</section>
</main>
</ng-container>
@for (member of getTeamMembers('owner') | async; track member) {
<div class="member">
<img [ngSrc]="getAvatarUrl(member)" alt="{{member.name}}'s Minecraft skin"
height="160" width="160" style="width: 160px;">
<h2>{{ member.name }}</h2>
<p>Owner</p>
</div>
}
@for (member of getTeamMembers('manager') | async; track member) {
<div class="member">
<img [ngSrc]="getAvatarUrl(member)" alt="{{member.name}}'s Minecraft skin"
height="160" width="160" style="width: 160px;">
<h2>{{ member.name }}</h2>
<p>Manager</p>
</div>
}
</div>
</section>
<section class="darkmodeSectionThree">
<div class="container teamContainer">
<h2 class="sectionTitle">Admins</h2>
@for (member of getTeamMembers('admin') | async; track member) {
<div class="member">
<img [ngSrc]="getAvatarUrl(member)" alt="{{member.name}}'s Minecraft skin"
height="160" width="160" style="width: 160px;">
<h2>{{ member.name }}</h2>
<p>Admin</p>
</div>
}
</div>
</section>
<section class="darkmodeSection">
<div class="container teamContainer">
<h2 class="sectionTitle">Head Moderators</h2>
@for (member of getTeamMembers('headmod') | async; track member) {
<div class="member">
<img [ngSrc]="getAvatarUrl(member)" alt="{{member.name}}'s Minecraft skin"
height="160" width="160" style="width: 160px;">
<h2>{{ member.name }}</h2>
<p>Head Mod</p>
</div>
}
</div>
</section>
<section class="darkmodeSectionThree">
<div class="container teamContainer">
<h2 class="sectionTitle">Moderators</h2>
@for (member of getTeamMembers('moderator') | async; track member) {
<div class="member">
<img [ngSrc]="getAvatarUrl(member)" alt="{{member.name}}'s Minecraft skin"
height="160" width="160" style="width: 160px;">
<h2>{{ member.name }}</h2>
</div>
}
</div>
</section>
@if ((getTeamMembers('trainee') | async)?.length ?? 0 > 0) {
<section class="darkmodeSection">
<div class="container teamContainer">
<h2 class="sectionTitle">Trainees</h2>
@for (member of getTeamMembers('trainee') | async; track member) {
<div class="member">
<img [ngSrc]="getAvatarUrl(member)" alt="{{member.name}}'s Minecraft skin"
height="160" width="160" style="width: 160px;">
<h2>{{ member.name }}</h2>
</div>
}
</div>
</section>
}
</main>
</ng-container>

View File

@ -1,7 +1,7 @@
import {Component} from '@angular/core';
import {ScrollService} from '@services/scroll.service';
import {BASE_PATH, Player, TeamService} from '@api';
import {CommonModule, NgOptimizedImage} from '@angular/common';
import { CommonModule, NgOptimizedImage } from '@angular/common';
import {HeaderComponent} from '@header/header.component';
import {CookieService} from 'ngx-cookie-service';
import {map, Observable, shareReplay} from 'rxjs';

View File

@ -1,13 +1,12 @@
import {Component} from '@angular/core';
import {CommonModule} from '@angular/common';
import {HeaderComponent} from '@header/header.component';
@Component({
standalone: true,
imports: [
CommonModule,
HeaderComponent
],
],
selector: 'app-map',
templateUrl: './map.component.html',
styleUrl: './map.component.scss'

View File

@ -1,16 +1,15 @@
import {Component} from '@angular/core';
import {ALTITUDE_VERSION} from '@custom-types/constant';
import {CommonModule, NgOptimizedImage} from '@angular/common';
import { NgOptimizedImage } from '@angular/common';
import {RouterLink} from '@angular/router';
@Component({
selector: 'app-footer',
standalone: true,
imports: [
CommonModule,
RouterLink,
NgOptimizedImage
],
],
templateUrl: './footer.component.html',
styleUrl: './footer.component.scss'
})

View File

@ -1,6 +1,6 @@
import {Component} from '@angular/core';
import {ScrollService} from '@services/scroll.service';
import {CommonModule} from '@angular/common';
import {HeaderComponent} from '@header/header.component';
import {RouterLink} from '@angular/router';
@ -8,10 +8,9 @@ import {RouterLink} from '@angular/router';
selector: 'app-privacy',
standalone: true,
imports: [
CommonModule,
HeaderComponent,
RouterLink
],
],
templateUrl: './privacy.component.html',
styleUrl: './privacy.component.scss'
})

View File

@ -1,7 +1,7 @@
import {Component} from '@angular/core';
import {ScrollService} from '@services/scroll.service';
import {HeaderComponent} from '@header/header.component';
import {CommonModule} from '@angular/common';
import {RouterLink} from '@angular/router';
@Component({
@ -9,10 +9,9 @@ import {RouterLink} from '@angular/router';
standalone: true,
templateUrl: './terms.component.html',
imports: [
CommonModule,
HeaderComponent,
RouterLink
],
],
styleUrl: './terms.component.scss'
})
export class TermsComponent {

View File

@ -1,17 +1,17 @@
<ng-container>
<app-header [current_page]="currentPage" height="200px" background_image="/public/img/backgrounds/staff.png"
[overlay_gradient]="0.5">
[overlay_gradient]="0.5">
<div class="title" header-content>
<h1>{{ formTitle }}</h1>
</div>
</app-header>
<ng-container *ngIf="!type">
<ng-container *ngFor="let formType of FormType | keyvalue">
@if (!type) {
@for (formType of FormType | keyvalue; track formType) {
<button mat-raised-button (click)="setFormType(formType.value)">
{{ formType }}
</button>
</ng-container>
</ng-container>
}
}
<div>
<ng-content select="[form-content]"></ng-content>
</div>

View File

@ -3,7 +3,7 @@ import {HeaderComponent} from '@header/header.component';
import {MatDialog} from '@angular/material/dialog';
import {ActivatedRoute} from '@angular/router';
import {LoginDialogComponent} from '@shared-components/login/login.component';
import {KeyValuePipe, NgForOf, NgIf} from '@angular/common';
import { KeyValuePipe } from '@angular/common';
import {FormType} from './form_type';
import {MatButton} from '@angular/material/button';
import {AuthService} from '@services/auth.service';
@ -12,11 +12,9 @@ import {AuthService} from '@services/auth.service';
selector: 'app-forms',
imports: [
HeaderComponent,
NgIf,
NgForOf,
MatButton,
KeyValuePipe
],
],
templateUrl: './forms.component.html',
styleUrl: './forms.component.scss'
})

View File

@ -1,6 +1,6 @@
<ng-container>
<header id="top"
[ngStyle]="{ 'background-image': getBackgroundImage(),'height': height, 'background-position': getBackgroundPosition() }">
[ngStyle]="{ 'background-image': getBackgroundImage(),'height': height, 'background-position': getBackgroundPosition() }">
<nav id="nav" [ngClass]="active">
<div class="container">
<div id="mobile_nav">
@ -27,7 +27,7 @@
<li><a [routerLink]="['/customfeatures']">Custom Features</a></li>
<li><a
href="https://kanboard.alttd.com/public/board/ef0c28f3d022f7e98801bbc97278e9a523c7c6dc2a3b0c58c47e2ebdbd1e">Suggestion
Board</a></li>
Board</a></li>
</ul>
</li>
<li>
@ -62,98 +62,106 @@
<li><a href="https://alttd.com/blog/">Blog</a></li>
</ul>
</li>
<li *ngIf="!isAuthenticated">
<a (click)="openLoginDialog()">
Login
</a>
</li>
@if (!isAuthenticated) {
<li>
<a (click)="openLoginDialog()">
Login
</a>
</li>
}
</ul>
</div>
</div>
<a href="/"><img ngSrc="/public/img/logos/logo.png" priority alt="Altitude Server Logo" height="319"
width="550"></a>
width="550"></a>
<ul id="nav_list">
<li class="nav_li"><a [id]="getCurrentPageId(['home'])" class="nav_link" href="/" [ngClass]="active">Home</a>
</li>
<li class="nav_li">
</li>
<li class="nav_li">
<span [id]="getCurrentPageId(['map', 'customfeatures', 'economy', 'events', 'mypet', 'warps',
'skyblock', 'claiming'])" class="nav_link fake_link" [ngClass]="active">Features</span>
<ul class="dropdown">
<li class="nav_li"><a class="nav_link2" [routerLink]="['/map']">Map</a></li>
<li class="nav_li"><a class="nav_link2" [routerLink]="['/economy']">Economy</a></li>
<!-- <li class="navli"><a class="nav_link2" [routerLink]="['/events']">Events</a></li> -->
<li class="nav_li"><a class="nav_link2" [routerLink]="['/claiming']">Land Claiming</a></li>
<li class="nav_li"><a class="nav_link2" [routerLink]="['/mypet']">MyPet</a></li>
<li class="nav_li"><a class="nav_link2" [routerLink]="['/warps']">Warps</a></li>
<li class="nav_li"><a class="nav_link2" [routerLink]="['/skyblock']">Skyblock</a></li>
<li class="nav_li"><a class="nav_link2" [routerLink]="['/customfeatures']">Custom Features</a></li>
<li class="nav_li"><a class="nav_link2"
href="https://kanboard.alttd.com/public/board/ef0c28f3d022f7e98801bbc97278e9a523c7c6dc2a3b0c58c47e2ebdbd1e">Suggestion
Board</a></li>
</ul>
</li>
<li class="nav_li">
<ul class="dropdown">
<li class="nav_li"><a class="nav_link2" [routerLink]="['/map']">Map</a></li>
<li class="nav_li"><a class="nav_link2" [routerLink]="['/economy']">Economy</a></li>
<!-- <li class="navli"><a class="nav_link2" [routerLink]="['/events']">Events</a></li> -->
<li class="nav_li"><a class="nav_link2" [routerLink]="['/claiming']">Land Claiming</a></li>
<li class="nav_li"><a class="nav_link2" [routerLink]="['/mypet']">MyPet</a></li>
<li class="nav_li"><a class="nav_link2" [routerLink]="['/warps']">Warps</a></li>
<li class="nav_li"><a class="nav_link2" [routerLink]="['/skyblock']">Skyblock</a></li>
<li class="nav_li"><a class="nav_link2" [routerLink]="['/customfeatures']">Custom Features</a></li>
<li class="nav_li"><a class="nav_link2"
href="https://kanboard.alttd.com/public/board/ef0c28f3d022f7e98801bbc97278e9a523c7c6dc2a3b0c58c47e2ebdbd1e">Suggestion
Board</a></li>
</ul>
</li>
<li class="nav_li">
<span
[id]="getCurrentPageId(['guide', 'faq', 'ranks', 'rules', 'commandlist', 'mapart', 'lag', 'staffpowers',
'nicknames', 'bans', 'discord-bans'])" class="nav_link fake_link" [ngClass]="active">Reference</span>
<ul class="dropdown">
<li class="nav_li"><a class="nav_link2" [routerLink]="['/guide']">Guide Book</a></li>
<!-- <li class="navli"><a class="nav_link2" [routerLink]="['/faq']">FAQ</a></li> -->
<li class="nav_li"><a class="nav_link2" [routerLink]="['/ranks']">Ranks</a></li>
<li class="nav_li"><a class="nav_link2" [routerLink]="['/rules']">Rules</a></li>
<li class="nav_li"><a class="nav_link2" [routerLink]="['/commandlist']">Command List</a></li>
<li class="nav_li"><a class="nav_link2" [routerLink]="['/mapart']">Mapart</a></li>
<li class="nav_li"><a class="nav_link2" [routerLink]="['/lag']">Reducing Lag</a></li>
<li class="nav_li"><a class="nav_link2" [routerLink]="['/staffpowers']">Staff Powers</a></li>
<li class="nav_li"><a class="nav_link2" [routerLink]="['/nicknames']">Nicknames</a></li>
<li class="nav_li"><a class="nav_link2" [routerLink]="['/bans']">Minecraft Bans</a></li>
<li class="nav_li"><a class="nav_link2" [routerLink]="['/discord-bans']">Discord Bans</a></li>
</ul>
</li>
<li class="nav_li"><a class="nav_link" target="_blank" rel="noopener"
href="https://discordapp.com/invite/TGqpzCJ" [ngClass]="active">Discord</a></li>
<li class="nav_li"><a [id]="getCurrentPageId(['vote'])" class="nav_link" [routerLink]="['/vote']"
[ngClass]="active">Vote</a>
</li>
<li class="nav_li">
<a class="nav_link" target="_blank" rel="noopener" href="https://store.alttd.com"
[ngClass]="active">Store</a>
</li>
<li class="nav_li">
<a [id]="getCurrentPageId(['about', 'team', 'community', 'birthdays'])"
class="nav_link fake_link" [ngClass]="active">Altitude</a>
<ul class="dropdown">
<li class="nav_li"><a class="nav_link2" [routerLink]="['/about']">About Us</a></li>
<li class="nav_li"><a class="nav_link2" [routerLink]="['/socials']">Socials</a></li>
<li class="nav_li"><a class="nav_link2" [routerLink]="['/team']">Team</a></li>
<li class="nav_li"><a class="nav_link2" [routerLink]="['/birthdays']">Famous Birthdays</a></li>
<li class="nav_li"><a class="nav_link2" [routerLink]="['/community']">Community</a></li>
<li class="nav_li"><a class="nav_link2" target="_blank" rel="noopener" [routerLink]="['/contact']">Contact
Us</a></li>
<li class="nav_li"><a class="nav_link2" target="_blank" rel="noopener" href="https://alttd.com/appeal">Ban
Appeal</a></li>
<li class="nav_li"><a class="nav_link2" target="_blank" href="https://alttd.com/blog/">Blog</a></li>
</ul>
</li>
@if (isAuthenticated) {
<li class="nav_li">
<a [id]="getCurrentPageId(['particles'])"
class="nav_link fake_link" [ngClass]="active">Special</a>
@if (hasAccess(['HEAD_MOD'])) {
<ul class="dropdown">
<li class="nav_li"><a class="nav_link2" [routerLink]="['/guide']">Guide Book</a></li>
<!-- <li class="navli"><a class="nav_link2" [routerLink]="['/faq']">FAQ</a></li> -->
<li class="nav_li"><a class="nav_link2" [routerLink]="['/ranks']">Ranks</a></li>
<li class="nav_li"><a class="nav_link2" [routerLink]="['/rules']">Rules</a></li>
<li class="nav_li"><a class="nav_link2" [routerLink]="['/commandlist']">Command List</a></li>
<li class="nav_li"><a class="nav_link2" [routerLink]="['/mapart']">Mapart</a></li>
<li class="nav_li"><a class="nav_link2" [routerLink]="['/lag']">Reducing Lag</a></li>
<li class="nav_li"><a class="nav_link2" [routerLink]="['/staffpowers']">Staff Powers</a></li>
<li class="nav_li"><a class="nav_link2" [routerLink]="['/nicknames']">Nicknames</a></li>
<li class="nav_li"><a class="nav_link2" [routerLink]="['/bans']">Minecraft Bans</a></li>
<li class="nav_li"><a class="nav_link2" [routerLink]="['/discord-bans']">Discord Bans</a></li>
</ul>
</li>
<li class="nav_li"><a class="nav_link" target="_blank" rel="noopener"
href="https://discordapp.com/invite/TGqpzCJ" [ngClass]="active">Discord</a></li>
<li class="nav_li"><a [id]="getCurrentPageId(['vote'])" class="nav_link" [routerLink]="['/vote']"
[ngClass]="active">Vote</a>
</li>
<li class="nav_li">
<a class="nav_link" target="_blank" rel="noopener" href="https://store.alttd.com"
[ngClass]="active">Store</a>
</li>
<li class="nav_li">
<a [id]="getCurrentPageId(['about', 'team', 'community', 'birthdays'])"
class="nav_link fake_link" [ngClass]="active">Altitude</a>
<ul class="dropdown">
<li class="nav_li"><a class="nav_link2" [routerLink]="['/about']">About Us</a></li>
<li class="nav_li"><a class="nav_link2" [routerLink]="['/socials']">Socials</a></li>
<li class="nav_li"><a class="nav_link2" [routerLink]="['/team']">Team</a></li>
<li class="nav_li"><a class="nav_link2" [routerLink]="['/birthdays']">Famous Birthdays</a></li>
<li class="nav_li"><a class="nav_link2" [routerLink]="['/community']">Community</a></li>
<li class="nav_li"><a class="nav_link2" target="_blank" rel="noopener" [routerLink]="['/contact']">Contact
Us</a></li>
<li class="nav_li"><a class="nav_link2" target="_blank" rel="noopener" href="https://alttd.com/appeal">Ban
Appeal</a></li>
<li class="nav_li"><a class="nav_link2" target="_blank" href="https://alttd.com/blog/">Blog</a></li>
</ul>
</li>
<li class="nav_li" *ngIf="isAuthenticated">
<a [id]="getCurrentPageId(['particles'])"
class="nav_link fake_link" [ngClass]="active">Special</a>
<ul class="dropdown" *ngIf="hasAccess(['HEAD_MOD'])">
<li class="nav_li"><a class="nav_link2" [routerLink]="['/particles']">Particles</a></li>
</ul>
</li>
<li class="nav_li login-button" *ngIf="!isAuthenticated">
<a class="nav_link fake_link" (click)="openLoginDialog()">
Login
</a>
</li>
</ul>
}
</li>
}
@if (!isAuthenticated) {
<li class="nav_li login-button">
<a class="nav_link fake_link" (click)="openLoginDialog()">
Login
</a>
</li>
}
</ul>
<app-theme></app-theme>
</div>
</nav>
<app-theme></app-theme>
</div>
</nav>
<ng-content select="[header-content]"></ng-content>
<ng-content select="[header-content]"></ng-content>
</header>
</header>
</ng-container>

View File

@ -5,7 +5,6 @@ import {RouterLink} from '@angular/router';
import {AuthService} from '@services/auth.service';
import {Subscription} from 'rxjs';
import {LoginDialogComponent} from '@shared-components/login/login.component';
import {MatButton} from '@angular/material/button';
import {MatDialog} from '@angular/material/dialog';
@Component({
@ -14,8 +13,7 @@ import {MatDialog} from '@angular/material/dialog';
CommonModule,
ThemeComponent,
RouterLink,
NgOptimizedImage,
MatButton
NgOptimizedImage
],
selector: 'app-header',
templateUrl: './header.component.html',

View File

@ -1,157 +1,157 @@
<ng-container>
<app-header [current_page]="'home'" height="100vh"
[background_image]="'/public/img/backgrounds/120spawn-min.png'">
[background_image]="'/public/img/backgrounds/120spawn-min.png'">
<div class="title" header-content>
<h1 style="display: none;">Altitude</h1>
<img id="header-img" ngSrc="/public/img/logos/logo.png" alt="The Altitude Minecraft Server" height="319"
width="550">
<h2 style="font-size: 2.5em;" id="homeh2">Altitude now on {{ ALTITUDE_VERSION }}!</h2>
<a id="scroll-button" (click)="scrollToSection()">
<span></span>
<p style="display: none;">Scroll Down</p>
</a>
</div>
</app-header>
<main>
<section id="scrollingpoint" style="background: #202020; text-align: center; padding: 80px 0;">
<!-- TODO load player count from old api or backend?-->
<h2 style="color: white;"><span class="player-count">Loading...</span></h2>
<h2 style="color: white;">Server IP: play.alttd.com</h2>
<div style="padding-top: 35px;">
<app-copy-ip></app-copy-ip>
width="550">
<h2 style="font-size: 2.5em;" id="homeh2">Altitude now on {{ ALTITUDE_VERSION }}!</h2>
<a id="scroll-button" (click)="scrollToSection()">
<span></span>
<p style="display: none;">Scroll Down</p>
</a>
</div>
</section>
<section class="darkmodeSection">
<div class="container">
<div class="paragraph">
<h2>Adventure Begins</h2>
<p>You awake in a strange town, where are you? There are residents running about trading with each other and
stories of distant realms with more towns. It's time to write your story. Welcome to Altitude, the laid-back
community-oriented server that hosts your home for Minecraft.</p>
</app-header>
<main>
<section id="scrollingpoint" style="background: #202020; text-align: center; padding: 80px 0;">
<!-- TODO load player count from old api or backend?-->
<h2 style="color: white;"><span class="player-count">Loading...</span></h2>
<h2 style="color: white;">Server IP: play.alttd.com</h2>
<div style="padding-top: 35px;">
<app-copy-ip></app-copy-ip>
</div>
<img ngSrc="/public/img/items/bookquill.png" style="width: 150px; align-self: center; margin: 0 auto;"
alt="Alternative Altitude Server Logo"
height="150" width="150">
</div>
</section>
<!--
<section id="section1">
<div class="container" id="video">
</section>
<section class="darkmodeSection">
<div class="container">
<div class="paragraph">
<h2>Adventure Begins</h2>
<p>You awake in a strange town, where are you? There are residents running about trading with each other and
stories of distant realms with more towns. It's time to write your story. Welcome to Altitude, the laid-back
community-oriented server that hosts your home for Minecraft.</p>
</div>
<img ngSrc="/public/img/items/bookquill.png" style="width: 150px; align-self: center; margin: 0 auto;"
alt="Alternative Altitude Server Logo"
height="150" width="150">
</div>
</section>
<!--
<section id="section1">
<div class="container" id="video">
<h2 style="display: none;">YouTube Trailer</h2>
<div style="border-radius:5px;overflow:hidden;position:relative;width:100%">
<img style="width: 100%" src="https://img.youtube.com/vi/Nzbj9Dbv5Wk/maxresdefault.jpg" alt="Altitude YouTube Trailer">
<div id="youtube">
<div class="play" onclick="playVideo()"></div>
</div>
<img style="width: 100%" src="https://img.youtube.com/vi/Nzbj9Dbv5Wk/maxresdefault.jpg" alt="Altitude YouTube Trailer">
<div id="youtube">
<div class="play" onclick="playVideo()"></div>
</div>
</div>
</div>
</section>
-->
<section class="darkmodeSection">
<div class="container" style="padding: 10px 0 80px 0">
<iframe id="discord-widget" src="https://discordapp.com/widget?id=141644560005595136&theme=dark"></iframe>
<div class="paragraph" id="discord-p">
<h2>Meet the Community</h2>
<p>Altitude is home to players young and old from all around the globe, and here, everyone is family. Altitude
is your place to get together with friends and relax - and maybe enjoy some survival too. Altitude is
intended for older players, but all are welcome!</p>
<p>Don't have Discord? Keep up with news and announcements at the <a href="alttd.com/blog">blog</a>.</p>
<div style="display: flex; justify-content: center;">
<a target="_blank" rel="noopener" href="https://discordapp.com/invite/TGqpzCJ">
<div style="margin-top: 30px;" class="button-outer">
<span class="button-inner">Join Our Discord</span>
</div>
</a>
</div>
</div>
</div>
</section>
<section id="section2">
<div class="customContainer">
<h2 style="color: white; padding-bottom: 35px; font-size: 2.8em;">Survival Shaped by You</h2>
<p style="color: white; padding-bottom: 35px; font-size: 1.1em; margin: auto;">Altitude is built by the
community, for the community. We've added features requested by our members and several custom plugins to
create our "perfect" survival experience.</p>
<div class="survivalShapedContainerPlugins">
<div class="pluginColumn">
<h2>McMMO & MyPet</h2>
<p>Two of the most requested plugins on Altitude, level up yourself and your pet with these MMO-based
plugins!</p>
<a [routerLink]="['/mypet']">
<div class="button-outer">
<span class="button-inner">MyPet Info</span>
</section>
-->
<section class="darkmodeSection">
<div class="container" style="padding: 10px 0 80px 0">
<iframe id="discord-widget" src="https://discordapp.com/widget?id=141644560005595136&theme=dark"></iframe>
<div class="paragraph" id="discord-p">
<h2>Meet the Community</h2>
<p>Altitude is home to players young and old from all around the globe, and here, everyone is family. Altitude
is your place to get together with friends and relax - and maybe enjoy some survival too. Altitude is
intended for older players, but all are welcome!</p>
<p>Don't have Discord? Keep up with news and announcements at the <a href="alttd.com/blog">blog</a>.</p>
<div style="display: flex; justify-content: center;">
<a target="_blank" rel="noopener" href="https://discordapp.com/invite/TGqpzCJ">
<div style="margin-top: 30px;" class="button-outer">
<span class="button-inner">Join Our Discord</span>
</div>
</a>
</div>
</a>
</div>
</div>
<div class="pluginColumn">
<h2>Dynamic map</h2>
<p>See the world and the players around it in real-time! The map shows the entire survival world with claims
and warps.</p>
<a [routerLink]="['/map']">
<div class="button-outer">
<span class="button-inner">Visit Map</span>
</section>
<section id="section2">
<div class="customContainer">
<h2 style="color: white; padding-bottom: 35px; font-size: 2.8em;">Survival Shaped by You</h2>
<p style="color: white; padding-bottom: 35px; font-size: 1.1em; margin: auto;">Altitude is built by the
community, for the community. We've added features requested by our members and several custom plugins to
create our "perfect" survival experience.</p>
<div class="survivalShapedContainerPlugins">
<div class="pluginColumn">
<h2>McMMO & MyPet</h2>
<p>Two of the most requested plugins on Altitude, level up yourself and your pet with these MMO-based
plugins!</p>
<a [routerLink]="['/mypet']">
<div class="button-outer">
<span class="button-inner">MyPet Info</span>
</div>
</a>
</div>
</a>
</div>
<div class="pluginColumn">
<h2>Player Shops</h2>
<p>Our economy is built on player shops, encouraging player interaction and putting the control in your
hands.</p>
<a [routerLink]="['/economy']">
<div class="button-outer">
<span class="button-inner">Shop Guide</span>
<div class="pluginColumn">
<h2>Dynamic map</h2>
<p>See the world and the players around it in real-time! The map shows the entire survival world with claims
and warps.</p>
<a [routerLink]="['/map']">
<div class="button-outer">
<span class="button-inner">Visit Map</span>
</div>
</a>
</div>
</a>
<div class="pluginColumn">
<h2>Player Shops</h2>
<p>Our economy is built on player shops, encouraging player interaction and putting the control in your
hands.</p>
<a [routerLink]="['/economy']">
<div class="button-outer">
<span class="button-inner">Shop Guide</span>
</div>
</a>
</div>
</div>
</div>
</div>
</div>
</section>
<section class="remove-mobile darkmodeSection">
<div class="customContainer">
<h2 style="padding-bottom: 35px; font-size: 2.8em;">Community Builds</h2>
<p style="padding-bottom: 35px; font-size: 1.1em; margin: auto;">Thank you to our brilliant players for sharing
their impressive builds. Take a look at some of them here!<br>
If you know of any builds that should be featured, please let us know!</p>
<div class="sliderWrapper">
<div class="sliderContent">
<div class="indexSlider">
<div id="go-left" (click)="previousSlide()" class="circleBehind goLeft"></div>
<div id="go-right" (click)="nextSlide()" class="circleBehind goRight"></div>
<div class="display">
<span class="slide"
</section>
<section class="remove-mobile darkmodeSection">
<div class="customContainer">
<h2 style="padding-bottom: 35px; font-size: 2.8em;">Community Builds</h2>
<p style="padding-bottom: 35px; font-size: 1.1em; margin: auto;">Thank you to our brilliant players for sharing
their impressive builds. Take a look at some of them here!<br>
If you know of any builds that should be featured, please let us know!</p>
<div class="sliderWrapper">
<div class="sliderContent">
<div class="indexSlider">
<div id="go-left" (click)="previousSlide()" class="circleBehind goLeft"></div>
<div id="go-right" (click)="nextSlide()" class="circleBehind goRight"></div>
<div class="display">
<span class="slide"
[style.background-image]="'url(' + slide + ')'"
[style.opacity]="carouselOpacity"
[style.display]="'block'"></span>
[style.display]="'block'"></span>
</div>
</div>
<div class="dots">
@for (slide of getSlideIndices(); track slide) {
<span class="dot" (click)="setSlide(slide)" [ngClass]="getDotClass(slide)"></span>
}
</div>
</div>
</div>
<div class="dots">
<ng-container *ngFor="let slide of getSlideIndices();">
<span class="dot" (click)="setSlide(slide)" [ngClass]="getDotClass(slide)"></span>
</ng-container>
</div>
</div>
</div>
</div>
</section>
<section style="background: #202020;">
<div class="customContainer">
<h2 id="quote" style="color: white; font-family: 'minecraft-text',sans-serif; line-height: 1.3em;">"Great
community, great people, great server all round . . . If it can bring back my love for minecraft, it could
work wonders for you."</h2>
<p style="color: white; margin-top:30px;">- /u/seanhanley1993</p>
</div>
</section>
<section class="darkmodeSection">
<div class="customContainer">
<img ngSrc="/public/img/logos/log.png" alt="Alternative Altitude Server Logo" height="129"
width="120">
<h2 style="margin: 20px 0; font-size: 1.8em; padding-bottom: 0 !important;">play.alttd.com</h2>
<app-copy-ip></app-copy-ip>
</div>
</section>
<a (click)="this.scrollService.scrollToTop()" class="scroll-up-button, active">
<span></span>
<p style="display: none;">Scroll Down</p>
</a>
</main>
</ng-container>
</section>
<section style="background: #202020;">
<div class="customContainer">
<h2 id="quote" style="color: white; font-family: 'minecraft-text',sans-serif; line-height: 1.3em;">"Great
community, great people, great server all round . . . If it can bring back my love for minecraft, it could
work wonders for you."</h2>
<p style="color: white; margin-top:30px;">- /u/seanhanley1993</p>
</div>
</section>
<section class="darkmodeSection">
<div class="customContainer">
<img ngSrc="/public/img/logos/log.png" alt="Alternative Altitude Server Logo" height="129"
width="120">
<h2 style="margin: 20px 0; font-size: 1.8em; padding-bottom: 0 !important;">play.alttd.com</h2>
<app-copy-ip></app-copy-ip>
</div>
</section>
<a (click)="this.scrollService.scrollToTop()" class="scroll-up-button, active">
<span></span>
<p style="display: none;">Scroll Down</p>
</a>
</main>
</ng-container>

View File

@ -2,7 +2,7 @@ import {Component, OnInit} from '@angular/core';
import {Title} from '@angular/platform-browser';
import {ALTITUDE_VERSION} from '@custom-types/constant';
import {ScrollService} from '@services/scroll.service';
import {CommonModule, NgOptimizedImage} from '@angular/common';
import { CommonModule, NgOptimizedImage } from '@angular/common';
import {HeaderComponent} from '@header/header.component';
import {CopyIpComponent} from '@shared-components/copy-ip/copy-ip.component';
import {RouterLink} from '@angular/router';

View File

@ -6,36 +6,42 @@
<mat-card-content>
<div class="frames-container">
<mat-tab-group [selectedIndex]="frames.indexOf(currentFrame)"
(selectedIndexChange)="switchFrame(frames[$event])">
<mat-tab *ngFor="let frameId of frames" [label]="frameId">
<div class="frame-content">
<h3>Particles in {{ frameId }}</h3>
<div class="particles-list">
<div *ngFor="let particle of particleData.frames[frameId]; let i = index" class="particle-item">
<span class="particle-item-text">
Particle {{ i + 1 }}: ({{ particle.x.toFixed(2) }}, {{ particle.y.toFixed(2) }}
, {{ particle.z.toFixed(2) }})
</span>
<button mat-icon-button (click)="removeParticle(frameId, i)">
<mat-icon>delete</mat-icon>
</button>
<button mat-icon-button (click)="highlightParticle(frameId, i)">
<mat-icon>lightbulb</mat-icon>
(selectedIndexChange)="switchFrame(frames[$event])">
@for (frameId of frames; track frameId) {
<mat-tab [label]="frameId">
<div class="frame-content">
<h3>Particles in {{ frameId }}</h3>
<div class="particles-list">
@for (particle of particleData.frames[frameId]; track particle; let i = $index) {
<div class="particle-item">
<span class="particle-item-text">
Particle {{ i + 1 }}: ({{ particle.x.toFixed(2) }}, {{ particle.y.toFixed(2) }}
, {{ particle.z.toFixed(2) }})
</span>
<button mat-icon-button (click)="removeParticle(frameId, i)">
<mat-icon>delete</mat-icon>
</button>
<button mat-icon-button (click)="highlightParticle(frameId, i)">
<mat-icon>lightbulb</mat-icon>
</button>
</div>
}
@if (!particleData.frames[frameId] || particleData.frames[frameId].length === 0) {
<div
class="no-particles">
No particles in this frame. Click on the plane to add particles.
</div>
}
</div>
<div class="frame-actions">
<button mat-raised-button color="warn" (click)="removeFrame(frameId)"
[disabled]="frames.length <= 1">
Remove Frame
</button>
</div>
<div *ngIf="!particleData.frames[frameId] || particleData.frames[frameId].length === 0"
class="no-particles">
No particles in this frame. Click on the plane to add particles.
</div>
</div>
<div class="frame-actions">
<button mat-raised-button color="warn" (click)="removeFrame(frameId)"
[disabled]="frames.length <= 1">
Remove Frame
</button>
</div>
</div>
</mat-tab>
</mat-tab>
}
</mat-tab-group>
<div class="add-frame">
<button mat-raised-button color="primary" (click)="addFrame()">

View File

@ -2,7 +2,7 @@ import {Component} from '@angular/core';
import {MatButton, MatIconButton} from "@angular/material/button";
import {MatCard, MatCardContent, MatCardHeader, MatCardTitle} from "@angular/material/card";
import {MatTab, MatTabGroup} from "@angular/material/tabs";
import {NgForOf, NgIf} from "@angular/common";
import {ParticleData} from '../../models/particle.model';
import {MatIcon} from '@angular/material/icon';
import {ParticleManagerService} from '../../services/particle-manager.service';
@ -19,10 +19,8 @@ import {FrameManagerService} from '../../services/frame-manager.service';
MatIcon,
MatIconButton,
MatTab,
MatTabGroup,
NgForOf,
NgIf
],
MatTabGroup
],
templateUrl: './frames.component.html',
styleUrl: './frames.component.scss'
})

View File

@ -13,25 +13,27 @@
<mat-form-field appearance="fill" class="type-field">
<mat-label>Select Particle Type</mat-label>
<input type="text"
placeholder="Search for a particle type"
matInput
[formControl]="particleTypeControl"
[matAutocomplete]="auto">
<mat-autocomplete #auto="matAutocomplete" [displayWith]="displayFn">
<mat-option *ngFor="let type of filteredParticleTypes | async" [value]="type">
{{ type }}
</mat-option>
</mat-autocomplete>
</mat-form-field>
</div>
placeholder="Search for a particle type"
matInput
[formControl]="particleTypeControl"
[matAutocomplete]="auto">
<mat-autocomplete #auto="matAutocomplete" [displayWith]="displayFn">
@for (type of filteredParticleTypes | async; track type) {
<mat-option [value]="type">
{{ type }}
</mat-option>
}
</mat-autocomplete>
</mat-form-field>
</div>
<div class="size-slider">
<mat-slider min="0.1" max="4" step="0.1" class="full-width">
<input matSliderThumb [(ngModel)]="selectedSize">
</mat-slider>
<span>Size: {{ selectedSize }}</span>
<div class="size-slider">
<mat-slider min="0.1" max="4" step="0.1" class="full-width">
<input matSliderThumb [(ngModel)]="selectedSize">
</mat-slider>
<span>Size: {{ selectedSize }}</span>
</div>
</div>
</div>
</mat-card-content>
</mat-card>
</div>
</mat-card-content>
</mat-card>
</div>

View File

@ -10,7 +10,7 @@ import {MatInputModule} from '@angular/material/input';
import {MatAutocompleteModule} from '@angular/material/autocomplete';
import {Observable} from 'rxjs';
import {map, startWith} from 'rxjs/operators';
import {AsyncPipe, NgForOf} from '@angular/common';
import { AsyncPipe } from '@angular/common';
@Component({
selector: 'app-particle',
@ -26,9 +26,8 @@ import {AsyncPipe, NgForOf} from '@angular/common';
MatFormFieldModule,
MatInputModule,
MatAutocompleteModule,
NgForOf,
AsyncPipe
],
],
templateUrl: './particle.component.html',
styleUrl: './particle.component.scss'
})

View File

@ -22,7 +22,9 @@
<mat-form-field appearance="outline">
<mat-label>Particle Type</mat-label>
<mat-select [(ngModel)]="particleData.particle_type">
<mat-option *ngFor="let type of particleTypes" [value]="type">{{ type }}</mat-option>
@for (type of particleTypes; track type) {
<mat-option [value]="type">{{ type }}</mat-option>
}
</mat-select>
</mat-form-field>
</div>
@ -73,21 +75,21 @@
<mat-form-field appearance="outline">
<mat-label>Repeat Delay</mat-label>
<input matInput type="number" [(ngModel)]="particleData.repeat_delay"
placeholder="Enter repeat delay">
</mat-form-field>
</div>
placeholder="Enter repeat delay">
</mat-form-field>
</div>
<div class="form-row">
<mat-form-field appearance="outline">
<mat-label>Random Offset</mat-label>
<input matInput type="number" [(ngModel)]="particleData.random_offset"
placeholder="Enter random offset">
</mat-form-field>
</div>
<div class="form-row">
<mat-form-field appearance="outline">
<mat-label>Random Offset</mat-label>
<input matInput type="number" [(ngModel)]="particleData.random_offset"
placeholder="Enter random offset">
</mat-form-field>
</div>
<div class="form-row">
<mat-checkbox [(ngModel)]="particleData.stationary"><span>Stationary</span></mat-checkbox>
</div>
</mat-card-content>
</mat-card>
</div>
<div class="form-row">
<mat-checkbox [(ngModel)]="particleData.stationary"><span>Stationary</span></mat-checkbox>
</div>
</mat-card-content>
</mat-card>
</div>

View File

@ -2,7 +2,7 @@ import {Component} from '@angular/core';
import {MatCard, MatCardContent, MatCardHeader, MatCardTitle} from "@angular/material/card";
import {MatCheckbox} from "@angular/material/checkbox";
import {MatFormField, MatInput, MatLabel} from "@angular/material/input";
import {NgForOf} from "@angular/common";
import {FormsModule, ReactiveFormsModule} from "@angular/forms";
import {ParticleData, ParticleType} from '../../models/particle.model';
import {MatSelect} from '@angular/material/select';
@ -22,10 +22,9 @@ import {ParticleManagerService} from '../../services/particle-manager.service';
MatLabel,
MatOption,
MatSelect,
NgForOf,
ReactiveFormsModule,
FormsModule
],
],
templateUrl: './properties.component.html',
styleUrl: './properties.component.scss'
})

View File

@ -8,47 +8,49 @@
</div>
<div class="button-row">
<button mat-mini-fab color="primary" (click)="resetCamera()"
matTooltip="Reset camera">
matTooltip="Reset camera">
<mat-icon>location_searching</mat-icon>
</button>
<button mat-mini-fab color="primary" (click)="togglePlaneLock()"
[matTooltip]="isPlaneLocked ? 'Unlock Plane' : 'Lock Plane'">
[matTooltip]="isPlaneLocked ? 'Unlock Plane' : 'Lock Plane'">
<mat-icon>{{ isPlaneLocked ? 'lock' : 'lock_open' }}</mat-icon>
</button>
</div>
<div *ngIf="isPlaneLocked" class="plane-orientation-buttons">
<button mat-mini-fab color="warn" (click)="setPlaneOrientation(planeOrientations.VERTICAL_ABOVE)"
[class.active]="currentPlaneOrientation === planeOrientations.VERTICAL_ABOVE"
matTooltip="Vertical Above">
<mat-icon>arrow_upward</mat-icon>
</button>
<button mat-mini-fab color="warn" (click)="setPlaneOrientation(planeOrientations.VERTICAL_BELOW)"
[class.active]="currentPlaneOrientation === planeOrientations.VERTICAL_BELOW"
matTooltip="Vertical Below">
<mat-icon>arrow_downward</mat-icon>
</button>
<button mat-mini-fab color="primary" (click)="setPlaneOrientation(planeOrientations.HORIZONTAL_FRONT)"
[class.active]="currentPlaneOrientation === planeOrientations.HORIZONTAL_FRONT"
matTooltip="Horizontal Front">
<mat-icon>arrow_forward</mat-icon>
</button>
<button mat-mini-fab color="primary" (click)="setPlaneOrientation(planeOrientations.HORIZONTAL_BEHIND)"
[class.active]="currentPlaneOrientation === planeOrientations.HORIZONTAL_BEHIND"
matTooltip="Horizontal Behind">
<mat-icon>arrow_back</mat-icon>
</button>
<button mat-mini-fab color="accent" (click)="setPlaneOrientation(planeOrientations.HORIZONTAL_RIGHT)"
[class.active]="currentPlaneOrientation === planeOrientations.HORIZONTAL_RIGHT"
matTooltip="Horizontal Right">
<mat-icon>arrow_right</mat-icon>
</button>
<button mat-mini-fab color="accent" (click)="setPlaneOrientation(planeOrientations.HORIZONTAL_LEFT)"
[class.active]="currentPlaneOrientation === planeOrientations.HORIZONTAL_LEFT"
matTooltip="Horizontal Left">
<mat-icon>arrow_left</mat-icon>
</button>
</div>
@if (isPlaneLocked) {
<div class="plane-orientation-buttons">
<button mat-mini-fab color="warn" (click)="setPlaneOrientation(planeOrientations.VERTICAL_ABOVE)"
[class.active]="currentPlaneOrientation === planeOrientations.VERTICAL_ABOVE"
matTooltip="Vertical Above">
<mat-icon>arrow_upward</mat-icon>
</button>
<button mat-mini-fab color="warn" (click)="setPlaneOrientation(planeOrientations.VERTICAL_BELOW)"
[class.active]="currentPlaneOrientation === planeOrientations.VERTICAL_BELOW"
matTooltip="Vertical Below">
<mat-icon>arrow_downward</mat-icon>
</button>
<button mat-mini-fab color="primary" (click)="setPlaneOrientation(planeOrientations.HORIZONTAL_FRONT)"
[class.active]="currentPlaneOrientation === planeOrientations.HORIZONTAL_FRONT"
matTooltip="Horizontal Front">
<mat-icon>arrow_forward</mat-icon>
</button>
<button mat-mini-fab color="primary" (click)="setPlaneOrientation(planeOrientations.HORIZONTAL_BEHIND)"
[class.active]="currentPlaneOrientation === planeOrientations.HORIZONTAL_BEHIND"
matTooltip="Horizontal Behind">
<mat-icon>arrow_back</mat-icon>
</button>
<button mat-mini-fab color="accent" (click)="setPlaneOrientation(planeOrientations.HORIZONTAL_RIGHT)"
[class.active]="currentPlaneOrientation === planeOrientations.HORIZONTAL_RIGHT"
matTooltip="Horizontal Right">
<mat-icon>arrow_right</mat-icon>
</button>
<button mat-mini-fab color="accent" (click)="setPlaneOrientation(planeOrientations.HORIZONTAL_LEFT)"
[class.active]="currentPlaneOrientation === planeOrientations.HORIZONTAL_LEFT"
matTooltip="Horizontal Left">
<mat-icon>arrow_left</mat-icon>
</button>
</div>
}
</div>
</div>

View File

@ -1,6 +1,6 @@
import {AfterViewInit, Component, ElementRef, OnDestroy, ViewChild} from '@angular/core';
import {MatMiniFabButton} from '@angular/material/button';
import {NgIf} from '@angular/common';
import {IntersectionPlaneService, PlaneOrientation} from '../../services/intersection-plane.service';
import {MatIcon} from '@angular/material/icon';
import {MatTooltip} from '@angular/material/tooltip';
@ -16,12 +16,11 @@ import {MatFormField, MatInput, MatLabel} from '@angular/material/input';
MatIcon,
MatMiniFabButton,
MatTooltip,
NgIf,
FormsModule,
MatInput,
MatFormField,
MatLabel
],
],
templateUrl: './render-container.component.html',
styleUrl: './render-container.component.scss'
})

View File

@ -1,5 +1,5 @@
import {Component, ElementRef, ViewChild} from '@angular/core';
import {CommonModule} from '@angular/common';
import {FormsModule, ReactiveFormsModule} from '@angular/forms';
import {MatButtonModule} from '@angular/material/button';
import {MatInputModule} from '@angular/material/input';
@ -28,7 +28,6 @@ import {ParticlesService} from '@api';
selector: 'app-particles',
standalone: true,
imports: [
CommonModule,
FormsModule,
ReactiveFormsModule,
MatButtonModule,
@ -44,8 +43,8 @@ import {ParticlesService} from '@api';
PropertiesComponent,
ParticleComponent,
FramesComponent,
RenderContainerComponent,
],
RenderContainerComponent
],
templateUrl: './particles.component.html',
styleUrl: './particles.component.scss'
})

View File

@ -1,6 +1,6 @@
<ng-container>
<app-header [current_page]="'bans'" height="200px" background_image="/public/img/backgrounds/staff.png"
[overlay_gradient]="0.5">>
[overlay_gradient]="0.5">>
<div class="title" header-content>
<h1>Minecraft Punishments</h1>
</div>
@ -13,78 +13,81 @@
<div class="historyButtonContainer">
<div [id]="getCurrentButtonId('all')" class="button-outer" (click)="changeHistoryPunishment('all')">
<span class="button-inner"
[ngClass]="active">All</span>
[ngClass]="active">All</span>
</div>
<div [id]="getCurrentButtonId('ban')" class="button-outer" (click)="changeHistoryPunishment('ban')">
<span class="button-inner"
[ngClass]="active">Bans</span>
[ngClass]="active">Bans</span>
</div>
<div [id]="getCurrentButtonId('mute')" class="button-outer" (click)="changeHistoryPunishment('mute')">
<span class="button-inner"
[ngClass]="active">Mutes</span>
[ngClass]="active">Mutes</span>
</div>
<div [id]="getCurrentButtonId('warn')" class="button-outer" (click)="changeHistoryPunishment('warn')">
<span class="button-inner"
[ngClass]="active">Warnings</span>
[ngClass]="active">Warnings</span>
</div>
<div [id]="getCurrentUserTypeButtonId('player')" class="button-outer" (click)="changeUserType('player')"
style="margin-left: 120px;">
style="margin-left: 120px;">
<span class="button-inner"
[ngClass]="active">Player</span>
[ngClass]="active">Player</span>
</div>
<div [id]="getCurrentUserTypeButtonId('staff')" class="button-outer" (click)="changeUserType('staff')">
<span class="button-inner"
[ngClass]="active">Staff</span>
[ngClass]="active">Staff</span>
</div>
</div>
<div class="historySearchContainer">
<input class="historySearch"
type="search"
placeholder="Search.."
[(ngModel)]="searchTerm"
(input)="filterNames()"
(keyup.enter)="search()"
>
<div class="dropdown-results" *ngIf="filteredNames.length > 0 && searchTerm">
<div
class="dropdown-item"
*ngFor="let name of filteredNames"
(mousedown)="selectName(name)">
{{ name }}
</div>
type="search"
placeholder="Search.."
[(ngModel)]="searchTerm"
(input)="filterNames()"
(keyup.enter)="search()"
>
@if (filteredNames.length > 0 && searchTerm) {
<div class="dropdown-results">
@for (name of filteredNames; track name) {
<div
class="dropdown-item"
(mousedown)="selectName(name)">
{{ name }}
</div>
}
</div>
}
</div>
</div>
<div class="historyTable">
<app-history [userType]="userType" [punishmentType]="punishmentType"
[page]="page" [searchTerm]="finalSearchTerm" (pageChange)="updatePageSize($event)"
(selectItem)="setSearch($event)">
</app-history>
</div>
<div class="changePageButtons">
<button [ngClass]="{'active': buttonActive(0), 'disabled': !buttonActive(0)}"
[disabled]="!buttonActive(0)"
(click)="setPage(0)" class="historyPageButton">
First page
</button>
<button [ngClass]="{'active': buttonActive(0), 'disabled': !buttonActive(0)}"
[disabled]="!buttonActive(0)"
(click)="previousPage()" class="historyPageButton">
Previous page
</button>
<span class="pageNumber">{{ this.page }} / {{ getMaxPage() }}</span>
<button [ngClass]="{'active': buttonActive(getMaxPage()), 'disabled': !buttonActive(getMaxPage())}"
[disabled]="!buttonActive(getMaxPage())"
(click)="nextPage()" class="historyPageButton">
Next page
</button>
<button [ngClass]="{'active': buttonActive(getMaxPage()), 'disabled': !buttonActive(getMaxPage())}"
[disabled]="!buttonActive(getMaxPage())"
(click)="setPage(getMaxPage())" class="historyPageButton">
Last page
</button>
</div>
</div>
<div class="historyTable">
<app-history [userType]="userType" [punishmentType]="punishmentType"
[page]="page" [searchTerm]="finalSearchTerm" (pageChange)="updatePageSize($event)"
(selectItem)="setSearch($event)">
</app-history>
</div>
<div class="changePageButtons">
<button [ngClass]="{'active': buttonActive(0), 'disabled': !buttonActive(0)}"
[disabled]="!buttonActive(0)"
(click)="setPage(0)" class="historyPageButton">
First page
</button>
<button [ngClass]="{'active': buttonActive(0), 'disabled': !buttonActive(0)}"
[disabled]="!buttonActive(0)"
(click)="previousPage()" class="historyPageButton">
Previous page
</button>
<span class="pageNumber">{{ this.page }} / {{ getMaxPage() }}</span>
<button [ngClass]="{'active': buttonActive(getMaxPage()), 'disabled': !buttonActive(getMaxPage())}"
[disabled]="!buttonActive(getMaxPage())"
(click)="nextPage()" class="historyPageButton">
Next page
</button>
<button [ngClass]="{'active': buttonActive(getMaxPage()), 'disabled': !buttonActive(getMaxPage())}"
[disabled]="!buttonActive(getMaxPage())"
(click)="setPage(getMaxPage())" class="historyPageButton">
Last page
</button>
</div>
</div>
</section>
</main>
</ng-container>
</section>
</main>
</ng-container>

View File

@ -2,7 +2,7 @@ import {Component, OnInit} from '@angular/core';
import {HeaderComponent} from "@header/header.component";
import {HistoryComponent} from './history/history.component';
import {HistoryCount, HistoryService} from '@api';
import {NgClass, NgForOf, NgIf} from '@angular/common';
import { NgClass } from '@angular/common';
import {FormsModule} from '@angular/forms';
import {catchError, map, Observable} from 'rxjs';
import {SearchParams} from './search-terms';
@ -12,11 +12,9 @@ import {SearchParams} from './search-terms';
imports: [
HeaderComponent,
HistoryComponent,
NgIf,
FormsModule,
NgForOf,
NgClass
],
],
templateUrl: './bans.component.html',
styleUrl: './bans.component.scss'
})

View File

@ -1,6 +1,6 @@
<ng-container>
<app-header [current_page]="'bans'" height="200px" background_image="/public/img/backgrounds/staff.png"
[overlay_gradient]="0.5">>
[overlay_gradient]="0.5">>
<div class="title" header-content>
<h1>Minecraft Punishments</h1>
</div>
@ -10,15 +10,15 @@
<section class="darkmodeSection">
<section class="columnSection">
<div class="detailsBackButton">
<ng-container *ngIf="punishment === undefined">
@if (punishment === undefined) {
<p>Loading...</p>
</ng-container>
}
<a [routerLink]="['/bans']">< Back</a>
</div>
</section>
<section class="columnSection center">
<ng-container *ngIf="punishment">
@if (punishment) {
<div>
<span class="tag tagInfo"
[ngClass]="{
@ -38,72 +38,72 @@
{{ this.historyFormat.isActive(punishment) ? 'Active' : 'Inactive' }}
</span>
</div>
</ng-container>
}
</section>
<section class="columnSection">
<div class="columnContainer">
<div class="columnParagraph">
<ng-container *ngIf="punishment">
@if (punishment) {
<div class="playerContainer">
<h2>Player</h2>
<img class="avatar" [ngSrc]="this.historyFormat.getAvatarUrl(punishment.uuid, '150')"
width="150"
height="150"
alt="{{punishment.username}}'s Minecraft skin"
>
<h3 class="detailsUsername">{{ punishment.username }}</h3>
</div>
</ng-container>
width="150"
height="150"
alt="{{punishment.username}}'s Minecraft skin"
>
<h3 class="detailsUsername">{{ punishment.username }}</h3>
</div>
}
</div>
</div>
</div>
<div class="columnContainer">
<div class="columnParagraph">
<ng-container *ngIf="punishment">
<div class="playerContainer">
<h2>Moderator</h2>
<img class="avatar" [ngSrc]="this.historyFormat.getAvatarUrl(punishment.punishedByUuid, '150')"
width="150"
height="150"
alt="{{punishment.punishedBy}}'s Minecraft skin"
>
<h3 class="detailsUsername">{{ punishment.punishedBy }}</h3>
<div class="columnContainer">
<div class="columnParagraph">
@if (punishment) {
<div class="playerContainer">
<h2>Moderator</h2>
<img class="avatar" [ngSrc]="this.historyFormat.getAvatarUrl(punishment.punishedByUuid, '150')"
width="150"
height="150"
alt="{{punishment.punishedBy}}'s Minecraft skin"
>
<h3 class="detailsUsername">{{ punishment.punishedBy }}</h3>
</div>
}
</div>
</ng-container>
</div>
</div>
<div class="columnContainer">
<div class="columnParagraph">
<ng-container *ngIf="punishment">
<div class="detailsInfo">
<h2>Reason</h2>
<p>{{ punishment.reason | removeTrailingPeriod }}</p>
</div>
<div class="columnContainer">
<div class="columnParagraph">
@if (punishment) {
<div class="detailsInfo">
<h2>Reason</h2>
<p>{{ punishment.reason | removeTrailingPeriod }}</p>
</div>
}
</div>
</ng-container>
</div>
</div>
<div class="columnContainer">
<div class="columnParagraph">
<ng-container *ngIf="punishment">
<div class="detailsInfo">
<h2>Date</h2>
<p>{{ this.historyFormat.getPunishmentTime(punishment) }}</p>
</div>
<div class="columnContainer">
<div class="columnParagraph">
@if (punishment) {
<div class="detailsInfo">
<h2>Date</h2>
<p>{{ this.historyFormat.getPunishmentTime(punishment) }}</p>
</div>
}
</div>
</ng-container>
</div>
</div>
</section>
</section>
</main>
</ng-container>
<section class="columnSection">
<ng-container *ngIf="punishment">
<span>Expires</span>
<span>{{ this.historyFormat.getExpiredTime(punishment) }}</span>
<ng-container *ngIf="punishment.removedBy !== undefined && punishment.removedBy.length > 0">
<span>Un{{ this.historyFormat.getType(punishment).toLocaleLowerCase() }} reason</span>
<span>{{ punishment.removedReason == null ? 'No reason specified' : punishment.removedReason }}</span>
</div>
</section>
</section>
</main>
</ng-container>
</ng-container>
</section>
<section class="columnSection">
@if (punishment) {
<span>Expires</span>
<span>{{ this.historyFormat.getExpiredTime(punishment) }}</span>
@if (punishment.removedBy !== undefined && punishment.removedBy.length > 0) {
<span>Un{{ this.historyFormat.getType(punishment).toLocaleLowerCase() }} reason</span>
<span>{{ punishment.removedReason == null ? 'No reason specified' : punishment.removedReason }}</span>
}
}
</section>

View File

@ -1,6 +1,6 @@
import {Component, OnInit} from '@angular/core';
import {HistoryService, PunishmentHistory} from '@api';
import {NgClass, NgIf, NgOptimizedImage} from '@angular/common';
import { NgClass, NgOptimizedImage } from '@angular/common';
import {RemoveTrailingPeriodPipe} from '@pipes/RemoveTrailingPeriodPipe';
import {HistoryFormatService} from '../history-format.service';
import {ActivatedRoute, RouterLink} from '@angular/router';
@ -10,13 +10,12 @@ import {HeaderComponent} from '@header/header.component';
@Component({
selector: 'app-details',
imports: [
NgIf,
NgOptimizedImage,
RemoveTrailingPeriodPipe,
HeaderComponent,
RouterLink,
NgClass
],
],
templateUrl: './details.component.html',
styleUrl: './details.component.scss'
})

View File

@ -1,53 +1,55 @@
<ng-container *ngIf="history.length === 0">
@if (history.length === 0) {
<p>No history found</p>
</ng-container>
}
<ng-container *ngIf="history.length > 0">
@if (history.length > 0) {
<table [cellSpacing]="0">
<div class="historyTableHead">
<thead>
<tr>
<th class="historyType">Type</th>
<th class="historyPlayer">Player</th>
<th class="historyPlayer">Banned By</th>
<th class="historyReason">Reason</th>
<th class="historyDate">Date</th>
<th class="historyDate">Expires</th>
</tr>
<tr>
<th class="historyType">Type</th>
<th class="historyPlayer">Player</th>
<th class="historyPlayer">Banned By</th>
<th class="historyReason">Reason</th>
<th class="historyDate">Date</th>
<th class="historyDate">Expires</th>
</tr>
</thead>
</div>
<div>
<tbody>
<tr class="historyPlayerRow" *ngFor="let entry of history">
<td class="historyType" (click)="showDetailedPunishment(entry)">
{{ this.historyFormat.getType(entry) }}
</td>
<td class="historyPlayer" (click)="setSearch(entry.username, 'player')">
<div class="playerContainer">
<img class="avatar" [ngSrc]="this.historyFormat.getAvatarUrl(entry.uuid)" width="25" height="25"
alt="{{entry.username}}'s Minecraft skin">
<span class="username">{{ entry.username }}</span>
</div>
</td>
<td class="historyPlayer" (click)="setSearch(entry.punishedBy, 'staff')">
<div class="playerContainer">
<img class="avatar" [ngSrc]="this.historyFormat.getAvatarUrl(entry.punishedByUuid)" width="25" height="25"
alt="{{entry.punishedBy}}'s Minecraft skin">
<span>{{ entry.punishedBy }}</span>
</div>
</td>
<td class="historyReason" (click)="showDetailedPunishment(entry)">
{{ entry.reason | removeTrailingPeriod }}
</td>
<td class="historyDate" (click)="showDetailedPunishment(entry)">
{{ this.historyFormat.getPunishmentTime(entry) }}
</td>
<td class="historyDate" (click)="showDetailedPunishment(entry)">
{{ this.historyFormat.getExpiredTime(entry) }}
</td>
</tr>
</tbody>
</div>
</table>
</ng-container>
@for (entry of history; track entry) {
<tr class="historyPlayerRow">
<td class="historyType" (click)="showDetailedPunishment(entry)">
{{ this.historyFormat.getType(entry) }}
</td>
<td class="historyPlayer" (click)="setSearch(entry.username, 'player')">
<div class="playerContainer">
<img class="avatar" [ngSrc]="this.historyFormat.getAvatarUrl(entry.uuid)" width="25" height="25"
alt="{{entry.username}}'s Minecraft skin">
<span class="username">{{ entry.username }}</span>
</div>
</td>
<td class="historyPlayer" (click)="setSearch(entry.punishedBy, 'staff')">
<div class="playerContainer">
<img class="avatar" [ngSrc]="this.historyFormat.getAvatarUrl(entry.punishedByUuid)" width="25" height="25"
alt="{{entry.punishedBy}}'s Minecraft skin">
<span>{{ entry.punishedBy }}</span>
</div>
</td>
<td class="historyReason" (click)="showDetailedPunishment(entry)">
{{ entry.reason | removeTrailingPeriod }}
</td>
<td class="historyDate" (click)="showDetailedPunishment(entry)">
{{ this.historyFormat.getPunishmentTime(entry) }}
</td>
<td class="historyDate" (click)="showDetailedPunishment(entry)">
{{ this.historyFormat.getExpiredTime(entry) }}
</td>
</tr>
}
</tbody>
</div>
</table>
}

View File

@ -1,7 +1,7 @@
import {Component, EventEmitter, Input, OnChanges, OnInit, Output} from '@angular/core';
import {BASE_PATH, HistoryService, PunishmentHistory} from '@api';
import {catchError, map, Observable, shareReplay} from 'rxjs';
import {NgForOf, NgIf, NgOptimizedImage} from '@angular/common';
import { NgOptimizedImage } from '@angular/common';
import {CookieService} from 'ngx-cookie-service';
import {RemoveTrailingPeriodPipe} from '@pipes/RemoveTrailingPeriodPipe';
import {HttpErrorResponse} from '@angular/common/http';
@ -13,11 +13,9 @@ import {Router} from '@angular/router';
@Component({
selector: 'app-history',
imports: [
NgIf,
NgForOf,
NgOptimizedImage,
RemoveTrailingPeriodPipe
],
],
templateUrl: './history.component.html',
styleUrl: './history.component.scss',
providers: [

View File

@ -1,15 +1,14 @@
import {Component} from '@angular/core';
import {ScrollService} from '@services/scroll.service';
import {CommonModule} from '@angular/common';
import {HeaderComponent} from '@header/header.component';
@Component({
selector: 'app-vote',
standalone: true,
imports: [
CommonModule,
HeaderComponent
],
],
templateUrl: './vote.component.html',
styleUrl: './vote.component.scss'
})

View File

@ -1,13 +1,11 @@
import {Component} from '@angular/core';
import {CommonModule} from '@angular/common';
@Component({
selector: 'app-copy-ip',
templateUrl: './copy-ip.component.html',
standalone: true,
imports: [
CommonModule
],
imports: [],
styleUrl: './copy-ip.component.scss'
})
export class CopyIpComponent {

View File

@ -4,18 +4,26 @@
<mat-form-field appearance="fill" style="width: 100%">
<mat-label>Enter your code</mat-label>
<input matInput formControlName="code" type="text" (keyup)="onKeyUp()">
<mat-error *ngIf="loginForm.get('code')?.errors?.['required']">
Code is required
</mat-error>
<mat-error *ngIf="loginForm.get('code')?.errors?.['minlength']">
Code must be 8 characters
</mat-error>
<mat-error *ngIf="loginForm.get('code')?.errors?.['maxlength']">
Code cannot exceed 8 characters
</mat-error>
<mat-error *ngIf="loginForm.get('code')?.errors?.['pattern']">
Code contains invalid characters
</mat-error>
@if (loginForm.get('code')?.errors?.['required']) {
<mat-error>
Code is required
</mat-error>
}
@if (loginForm.get('code')?.errors?.['minlength']) {
<mat-error>
Code must be 8 characters
</mat-error>
}
@if (loginForm.get('code')?.errors?.['maxlength']) {
<mat-error>
Code cannot exceed 8 characters
</mat-error>
}
@if (loginForm.get('code')?.errors?.['pattern']) {
<mat-error>
Code contains invalid characters
</mat-error>
}
</mat-form-field>
</form>
</div>

View File

@ -4,7 +4,7 @@ import {FormBuilder, FormGroup, ReactiveFormsModule, Validators} from '@angular/
import {MatButtonModule} from '@angular/material/button';
import {MatInputModule} from '@angular/material/input';
import {MatFormFieldModule} from '@angular/material/form-field';
import {NgIf} from '@angular/common';
import {MatSnackBar} from '@angular/material/snack-bar';
import {AuthService} from '@services/auth.service';
@ -18,9 +18,8 @@ import {AuthService} from '@services/auth.service';
MatFormFieldModule,
MatDialogTitle,
MatDialogContent,
MatDialogActions,
NgIf
],
MatDialogActions
],
templateUrl: './login.component.html',
styleUrl: './login.component.scss'
})

View File

@ -2,13 +2,11 @@ import {Component, OnDestroy, OnInit} from '@angular/core';
import {Subscription} from 'rxjs';
import {ThemeService} from './theme.service';
import {THEME_MODE} from '@custom-types/constant';
import {CommonModule} from '@angular/common';
@Component({
standalone: true,
imports: [
CommonModule,
],
imports: [],
selector: 'app-theme',
templateUrl: './theme.component.html',
styleUrl: './theme.component.scss'