Add player count display with periodic updates to home page

This commit is contained in:
akastijn 2025-10-18 02:43:23 +02:00
parent 6ad3b5221a
commit 29a28e712e
2 changed files with 177 additions and 143 deletions

View File

@ -1,157 +1,160 @@
<ng-container> <ng-container>
<app-header [current_page]="'home'" height="100vh" <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> <div class="title" header-content>
<h1 style="display: none;">Altitude</h1> <h1 style="display: none;">Altitude</h1>
<img id="header-img" ngSrc="/public/img/logos/logo.png" alt="The Altitude Minecraft Server" height="319" <img id="header-img" ngSrc="/public/img/logos/logo.png" alt="The Altitude Minecraft Server" height="319"
width="550"> width="550">
<h2 style="font-size: 2.5em;" id="homeh2">Altitude now on {{ ALTITUDE_VERSION }}!</h2> <h2 style="font-size: 2.5em;" id="homeh2">Altitude now on {{ ALTITUDE_VERSION }}!</h2>
<a id="scroll-button" (click)="scrollToSection()"> <a id="scroll-button" (click)="scrollToSection()">
<span></span> <span></span>
<p style="display: none;">Scroll Down</p> <p style="display: none;">Scroll Down</p>
</a> </a>
</div> </div>
</app-header> </app-header>
<main> <main>
<section id="scrollingpoint" style="background: #202020; text-align: center; padding: 80px 0;"> <section id="scrollingpoint" style="background: #202020; text-align: center; padding: 80px 0;">
<!-- TODO load player count from old api or backend?--> @if (this.playerCount() === null) {
<h2 style="color: white;"><span class="player-count">Loading...</span></h2> <h2 style="color: white;"><span class="player-count">Loading...</span></h2>
<h2 style="color: white;">Server IP: play.alttd.com</h2> } @else {
<div style="padding-top: 35px;"> <h2 style="color: white;"><span class="player-count">{{ playerCount() }}</span></h2>
<app-copy-ip></app-copy-ip> }
</div> <h2 style="color: white;">Server IP: play.alttd.com</h2>
</section> <div style="padding-top: 35px;">
<section class="darkmodeSection"> <app-copy-ip></app-copy-ip>
<div class="container"> </div>
<div class="paragraph"> </section>
<h2>Adventure Begins</h2> <section class="darkmodeSection">
<p>You awake in a strange town, where are you? There are residents running about trading with each other and <div class="container">
stories of distant realms with more towns. It's time to write your story. Welcome to Altitude, the laid-back <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> 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> </div>
<img ngSrc="/public/img/items/bookquill.png" style="width: 150px; align-self: center; margin: 0 auto;" </div>
alt="Alternative Altitude Server Logo" </div>
height="150" width="150"> </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>
</section> </div>
<!-- </div>
<section id="section1"> </section>
<div class="container" id="video"> <section id="section2">
<h2 style="display: none;">YouTube Trailer</h2> <div class="customContainer">
<div style="border-radius:5px;overflow:hidden;position:relative;width:100%"> <h2 style="color: white; padding-bottom: 35px; font-size: 2.8em;">Survival Shaped by You</h2>
<img style="width: 100%" src="https://img.youtube.com/vi/Nzbj9Dbv5Wk/maxresdefault.jpg" alt="Altitude YouTube Trailer"> <p style="color: white; padding-bottom: 35px; font-size: 1.1em; margin: auto;">Altitude is built by the
<div id="youtube"> community, for the community. We've added features requested by our members and several custom plugins to
<div class="play" onclick="playVideo()"></div> 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> </div>
</div> </a>
</div> </div>
</section> <div class="pluginColumn">
--> <h2>Dynamic map</h2>
<section class="darkmodeSection"> <p>See the world and the players around it in real-time! The map shows the entire survival world with claims
<div class="container" style="padding: 10px 0 80px 0"> and warps.</p>
<iframe id="discord-widget" src="https://discordapp.com/widget?id=141644560005595136&theme=dark"></iframe> <a [routerLink]="['/map']">
<div class="paragraph" id="discord-p"> <div class="button-outer">
<h2>Meet the Community</h2> <span class="button-inner">Visit Map</span>
<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> </a>
</div> </div>
</section> <div class="pluginColumn">
<section id="section2"> <h2>Player Shops</h2>
<div class="customContainer"> <p>Our economy is built on player shops, encouraging player interaction and putting the control in your
<h2 style="color: white; padding-bottom: 35px; font-size: 2.8em;">Survival Shaped by You</h2> hands.</p>
<p style="color: white; padding-bottom: 35px; font-size: 1.1em; margin: auto;">Altitude is built by the <a [routerLink]="['/economy']">
community, for the community. We've added features requested by our members and several custom plugins to <div class="button-outer">
create our "perfect" survival experience.</p> <span class="button-inner">Shop Guide</span>
<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> </div>
<div class="pluginColumn"> </a>
<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>
<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>
</section> </div>
<section class="remove-mobile darkmodeSection"> </div>
<div class="customContainer"> </section>
<h2 style="padding-bottom: 35px; font-size: 2.8em;">Community Builds</h2> <section class="remove-mobile darkmodeSection">
<p style="padding-bottom: 35px; font-size: 1.1em; margin: auto;">Thank you to our brilliant players for sharing <div class="customContainer">
their impressive builds. Take a look at some of them here!<br> <h2 style="padding-bottom: 35px; font-size: 2.8em;">Community Builds</h2>
If you know of any builds that should be featured, please let us know!</p> <p style="padding-bottom: 35px; font-size: 1.1em; margin: auto;">Thank you to our brilliant players for sharing
<div class="sliderWrapper"> their impressive builds. Take a look at some of them here!<br>
<div class="sliderContent"> If you know of any builds that should be featured, please let us know!</p>
<div class="indexSlider"> <div class="sliderWrapper">
<div id="go-left" (click)="previousSlide()" class="circleBehind goLeft"></div> <div class="sliderContent">
<div id="go-right" (click)="nextSlide()" class="circleBehind goRight"></div> <div class="indexSlider">
<div class="display"> <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" <span class="slide"
[style.background-image]="'url(' + slide + ')'" [style.background-image]="'url(' + slide + ')'"
[style.opacity]="carouselOpacity" [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> </div>
</div> <div class="dots">
</section> @for (slide of getSlideIndices(); track slide) {
<section style="background: #202020;"> <span class="dot" (click)="setSlide(slide)" [ngClass]="getDotClass(slide)"></span>
<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> </div>
</section> </div>
<a (click)="this.scrollService.scrollToTop()" class="scroll-up-button, active"> </div>
<span></span> </div>
<p style="display: none;">Scroll Down</p> </section>
</a> <section style="background: #202020;">
</main> <div class="customContainer">
</ng-container> <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

@ -1,12 +1,22 @@
import {Component, OnInit} from '@angular/core'; import {Component, inject, OnDestroy, OnInit, signal} from '@angular/core';
import {Title} from '@angular/platform-browser'; import {Title} from '@angular/platform-browser';
import {ALTITUDE_VERSION} from '@custom-types/constant'; import {ALTITUDE_VERSION} from '@custom-types/constant';
import {ScrollService} from '@services/scroll.service'; 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 {HeaderComponent} from '@header/header.component';
import {CopyIpComponent} from '@shared-components/copy-ip/copy-ip.component'; import {CopyIpComponent} from '@shared-components/copy-ip/copy-ip.component';
import {RouterLink} from '@angular/router'; import {RouterLink} from '@angular/router';
import {JwtHelperService} from '@auth0/angular-jwt'; import {JwtHelperService} from '@auth0/angular-jwt';
import {interval, map} from 'rxjs';
import {HttpClient} from '@angular/common/http';
import {startWith} from 'rxjs/operators';
interface MinecraftServerStatus {
online?: boolean;
players?: {
online?: number;
};
}
@Component({ @Component({
standalone: true, standalone: true,
@ -24,9 +34,16 @@ import {JwtHelperService} from '@auth0/angular-jwt';
templateUrl: './home.component.html', templateUrl: './home.component.html',
styleUrl: './home.component.scss' styleUrl: './home.component.scss'
}) })
export class HomeComponent implements OnInit { export class HomeComponent implements OnInit, OnDestroy {
constructor(private titleService: Title, public scrollService: ScrollService) { private httpClient = inject(HttpClient);
} private titleService = inject(Title);
public scrollService = inject(ScrollService);
public playerCount = signal<null | number>(null);
private playerCountUpdateInterval = interval(60000).pipe(
startWith(() => 0),
).subscribe(() => {
this.updatePlayerCount();
});
private slides: string[] = ["/public/img/backgrounds/caruselimage2.png", private slides: string[] = ["/public/img/backgrounds/caruselimage2.png",
"/public/img/backgrounds/caruselimage4.png", "/public/img/backgrounds/caruselimage4.png",
@ -44,6 +61,10 @@ export class HomeComponent implements OnInit {
this.randomizeSlides() this.randomizeSlides()
} }
ngOnDestroy(): void {
this.playerCountUpdateInterval.unsubscribe();
}
private randomizeSlides(): void { private randomizeSlides(): void {
const array = [...this.slides]; const array = [...this.slides];
@ -108,5 +129,15 @@ export class HomeComponent implements OnInit {
} }
} }
private updatePlayerCount() {
this.httpClient.get<MinecraftServerStatus>('https://api.mcsrvstat.us/2/play.alttd.com').pipe(
map(response => {
if (response.online && response.players && response.players.online) {
this.playerCount.set(response.players.online);
}
})
).subscribe();
}
protected readonly ALTITUDE_VERSION = ALTITUDE_VERSION; protected readonly ALTITUDE_VERSION = ALTITUDE_VERSION;
} }