mirror of
https://github.com/zeldaret/website.git
synced 2026-10-01 15:31:26 -04:00
Merge branch 'zeldaret:master' into lost-page
This commit is contained in:
@@ -16,7 +16,6 @@ section {
|
||||
$color-bg-hl 80%,
|
||||
$color-bg);
|
||||
|
||||
max-width: 800px;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
<mat-card>
|
||||
<a [href]="data.routingURL">
|
||||
<mat-card-header>
|
||||
<mat-card-title>
|
||||
{{ data.title }}
|
||||
<fa-icon [icon]="external"></fa-icon>
|
||||
</mat-card-title>
|
||||
<mat-card-subtitle>
|
||||
<ng-container *ngIf="total != undefined">Code decompiled: <strong>{{ total }}</strong></ng-container>
|
||||
|
||||
</mat-card-subtitle>
|
||||
</mat-card-header>
|
||||
</a>
|
||||
<mat-card-actions>
|
||||
<a mat-button *ngIf="data.links.hasOwnProperty('github')" [href]="data.links.github" title="Github">
|
||||
<fa-icon [icon]="github"></fa-icon>
|
||||
<div class="caption">GitHub</div>
|
||||
</a>
|
||||
<a mat-button *ngIf="data.links.hasOwnProperty('progress')" [href]="data.links.progress" title="Progress">
|
||||
<fa-icon [icon]="chart"></fa-icon>
|
||||
<div class="caption">Progress history</div>
|
||||
<!-- <mat-icon [svgIcon]="chart"></mat-icon> -->
|
||||
</a>
|
||||
</mat-card-actions>
|
||||
</mat-card>
|
||||
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
mat-card > a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
img[mat-card-avatar] {
|
||||
border-radius: 0;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
mat-card-actions {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
mat-card-title > fa-icon {
|
||||
font-size: 16px;
|
||||
vertical-align: center;
|
||||
}
|
||||
|
||||
mat-card-actions fa-icon {
|
||||
vertical-align: center;
|
||||
}
|
||||
|
||||
mat-card-actions a {
|
||||
color: white;
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { GameComponent } from '../../game/game.component';
|
||||
|
||||
describe('GameComponent', () => {
|
||||
let component: GameComponent;
|
||||
let fixture: ComponentFixture<GameComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ GameComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(GameComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,48 @@
|
||||
import { Component, Input, OnChanges } from '@angular/core';
|
||||
import { IExternalGame } from '../../games.service.interface';
|
||||
import { faGithub } from '@fortawesome/free-brands-svg-icons';
|
||||
import { faChartLine, faExternalLinkAlt } from '@fortawesome/free-solid-svg-icons';
|
||||
import { GamesService } from '../../games.service';
|
||||
|
||||
/**
|
||||
* Displays an externally-linked game's name, decomp progress, and links.
|
||||
*/
|
||||
@Component({
|
||||
selector: 'external-game-summary',
|
||||
templateUrl: './external-game-summary.component.html',
|
||||
styleUrls: ['./external-game-summary.component.scss']
|
||||
})
|
||||
export class ExternalGameSummaryComponent implements OnChanges {
|
||||
|
||||
constructor(private gamesService: GamesService) { }
|
||||
|
||||
/**
|
||||
* The game data to use.
|
||||
*/
|
||||
@Input() data: IExternalGame;
|
||||
/**
|
||||
* Shield data.
|
||||
*/
|
||||
shield: string;
|
||||
/**
|
||||
* The percentage to display for completion.
|
||||
*/
|
||||
total?: string;
|
||||
/**
|
||||
* Icon definitions.
|
||||
*/
|
||||
github = faGithub;
|
||||
external = faExternalLinkAlt;
|
||||
chart = faChartLine;
|
||||
|
||||
ngOnChanges(): void {
|
||||
|
||||
if (this.data.shieldURL) {
|
||||
this.gamesService.getGameShield(`${this.data.shieldURL}`).subscribe(
|
||||
res => this.total = res.message,
|
||||
err => console.error(err)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
<div fxLayout="row wrap" fxLayoutAlign="center">
|
||||
<game-summary fxFlex="25%" fxFlex.xs="100%" fxFlex.sm="33%" *ngFor="let game of games" [data]="game"></game-summary>
|
||||
<external-game-summary fxFlex="25%" fxFlex.xs="100%" fxFlex.sm="33%" *ngFor="let game of externalGames" [data]="game"></external-game-summary>
|
||||
</div>
|
||||
|
||||
@@ -2,7 +2,12 @@ div {
|
||||
margin-right: -1em;
|
||||
}
|
||||
|
||||
game-summary {
|
||||
h2 {
|
||||
margin: auto;
|
||||
width: max-content;
|
||||
}
|
||||
|
||||
game-summary, external-game-summary {
|
||||
flex-grow: 0;
|
||||
margin-bottom: 12px;
|
||||
margin-right: 1em;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { GamesService } from '../games.service';
|
||||
import { IGame } from '../games.service.interface';
|
||||
import { IGame, IExternalGame } from '../games.service.interface';
|
||||
|
||||
/**
|
||||
* Container for all game summaries.
|
||||
@@ -18,12 +18,20 @@ export class GameSummariesComponent implements OnInit {
|
||||
* List of games to use for "GameSummary" components.
|
||||
*/
|
||||
games: IGame[] = [];
|
||||
/**
|
||||
* List of external games to use for "ExternalGameSummary" components.
|
||||
*/
|
||||
externalGames: IExternalGame[] = [];
|
||||
|
||||
ngOnInit(): void {
|
||||
this.gamesService.getGames().subscribe(
|
||||
res => this.games = res,
|
||||
err => console.error(err)
|
||||
)
|
||||
this.gamesService.getExternalGames().subscribe(
|
||||
res => this.externalGames = res,
|
||||
err => console.error(err)
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,18 +1,19 @@
|
||||
<mat-card>
|
||||
<a [routerLink]="'/games/' + data.slug">
|
||||
<a [routerLink]="data.routingURL">
|
||||
<mat-card-header>
|
||||
<mat-card-title>
|
||||
{{ data.title }}
|
||||
</mat-card-title>
|
||||
<mat-card-subtitle *ngIf="total!=null">Percent completion: <strong>{{ (total * 100).toFixed(2) }}%</strong></mat-card-subtitle>
|
||||
<mat-card-subtitle>
|
||||
<ng-container *ngIf="total != undefined">Code decompiled: <strong>{{ total }}</strong></ng-container>
|
||||
|
||||
</mat-card-subtitle>
|
||||
</mat-card-header>
|
||||
</a>
|
||||
<mat-card-actions>
|
||||
<a mat-icon-button *ngIf="data.links.hasOwnProperty('github')" [href]="data.links.github" title="Github">
|
||||
<a mat-button *ngIf="data.links.hasOwnProperty('github')" [href]="data.links.github" title="Github">
|
||||
<fa-icon [icon]="github"></fa-icon>
|
||||
</a>
|
||||
<a mat-icon-button *ngIf="data.links.hasOwnProperty('trello')" [href]="data.links.trello" title="Trello">
|
||||
<fa-icon [icon]="trello"></fa-icon>
|
||||
<div class="caption">GitHub</div>
|
||||
</a>
|
||||
</mat-card-actions>
|
||||
</mat-card>
|
||||
|
||||
@@ -10,3 +10,11 @@ img[mat-card-avatar] {
|
||||
mat-card-actions {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
mat-card-actions fa-icon {
|
||||
vertical-align: center;
|
||||
}
|
||||
|
||||
mat-card-actions a {
|
||||
color: white;
|
||||
}
|
||||
|
||||
@@ -22,29 +22,20 @@ export class GameSummaryComponent implements OnChanges {
|
||||
/**
|
||||
* The percentage to display for completion.
|
||||
*/
|
||||
total: number = null;
|
||||
total?: string;
|
||||
/**
|
||||
* Icon definition.
|
||||
* Icon definitions.
|
||||
*/
|
||||
github = faGithub;
|
||||
/**
|
||||
* Icon definition.
|
||||
*/
|
||||
trello = faTrello;
|
||||
|
||||
ngOnChanges(): void {
|
||||
// Matching is second
|
||||
this.gamesService.getGameCSV(this.data.csvs.matching).subscribe(
|
||||
res => {
|
||||
const points = res.split("\n").filter((line) => line != "");
|
||||
const latestPoint = points[points.length - 1];
|
||||
const column = latestPoint.split(",");
|
||||
|
||||
let i = this.data.progressMeta[0].index;
|
||||
this.total = +column[i] / +column[i + 1];
|
||||
},
|
||||
err => console.error(err)
|
||||
);
|
||||
if (this.data.shieldURL) {
|
||||
this.gamesService.getGameShield(`${this.data.shieldURL}`).subscribe(
|
||||
res => this.total = res.message,
|
||||
err => console.error(err)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -39,13 +39,15 @@ export class GameComponent implements OnInit {
|
||||
}
|
||||
else {
|
||||
this.game = res[index];
|
||||
forkJoin([
|
||||
this.gamesService.getGameCSV(this.game.csvs.nonmatching),
|
||||
this.gamesService.getGameCSV(this.game.csvs.matching)
|
||||
]).subscribe(
|
||||
res => this.csvData = res,
|
||||
err => console.error(err)
|
||||
);
|
||||
if (this.game.progressMeta.length > 0) {
|
||||
forkJoin([
|
||||
this.gamesService.getGameCSV(this.game.csvs.nonmatching),
|
||||
this.gamesService.getGameCSV(this.game.csvs.matching)
|
||||
]).subscribe(
|
||||
res => this.csvData = res,
|
||||
err => console.error(err)
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
err => {
|
||||
|
||||
@@ -5,6 +5,7 @@ import { GamesService } from './games.service';
|
||||
import { GameSummariesComponent } from './game-summaries/game-summaries.component';
|
||||
import { GameSummaryComponent } from './game-summaries/game-summary/game-summary.component';
|
||||
import { GameComponent } from './game/game.component';
|
||||
import { ExternalGameSummaryComponent } from './game-summaries/external-game-summary/external-game-summary.component'
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatCardModule } from '@angular/material/card';
|
||||
import { MatGridListModule } from '@angular/material/grid-list';
|
||||
@@ -17,6 +18,8 @@ import { ChartModule } from 'angular-highcharts';
|
||||
import { GameFAQComponent } from './game/game-faq/game-faq.component';
|
||||
import { MarkdownModule, MarkedOptions, MarkedRenderer } from 'ngx-markdown';
|
||||
|
||||
|
||||
|
||||
// function that returns `MarkedOptions` with renderer override
|
||||
export function markedOptionsFactory(): MarkedOptions {
|
||||
const renderer = new MarkedRenderer();
|
||||
@@ -48,7 +51,8 @@ export function markedOptionsFactory(): MarkedOptions {
|
||||
GameComponent,
|
||||
GameProgressComponent,
|
||||
GameChartComponent,
|
||||
GameFAQComponent
|
||||
GameFAQComponent,
|
||||
ExternalGameSummaryComponent
|
||||
],
|
||||
imports: [
|
||||
CommonModule,
|
||||
|
||||
@@ -12,6 +12,14 @@ export interface IGame {
|
||||
* The game's full title.
|
||||
*/
|
||||
title: string;
|
||||
/**
|
||||
* The URL for the card title to link to.
|
||||
*/
|
||||
routingURL: string;
|
||||
/**
|
||||
* The URL of the shield json to read.
|
||||
*/
|
||||
shieldURL: string;
|
||||
/**
|
||||
* The name of the "FAQ" MD to read.
|
||||
*/
|
||||
@@ -34,6 +42,32 @@ export interface IGame {
|
||||
progressMeta: IChart[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Game information to display and for project progress processing.
|
||||
*/
|
||||
export interface IExternalGame {
|
||||
/**
|
||||
* The string to use to identify the game.
|
||||
*/
|
||||
slug: string;
|
||||
/**
|
||||
* The game's full title.
|
||||
*/
|
||||
title: string;
|
||||
/**
|
||||
* The URL for the card title to link to.
|
||||
*/
|
||||
routingURL: string;
|
||||
/**
|
||||
* Links to display as an icon. The key defines the icon, and the value is the link href.
|
||||
*/
|
||||
links: {[type: string]: string};
|
||||
/**
|
||||
* The URL of the shield json to read.
|
||||
*/
|
||||
shieldURL: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resources to display within the Resources tab.
|
||||
*/
|
||||
@@ -133,6 +167,25 @@ export interface ISubdivision {
|
||||
description: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Describes a game's shield output.
|
||||
*/
|
||||
export interface IShield {
|
||||
/**
|
||||
* Static label in left half.
|
||||
*/
|
||||
label: string;
|
||||
/**
|
||||
* Generally the progress number.
|
||||
*/
|
||||
message: string;
|
||||
/**
|
||||
* Colour of the message background.
|
||||
*/
|
||||
color: string;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Functions to implement within "GamesService".
|
||||
*/
|
||||
@@ -143,6 +196,11 @@ export interface IGamesService {
|
||||
*/
|
||||
getGames(): Observable<IGame[]>;
|
||||
|
||||
/**
|
||||
* Get the information for all supported external games.
|
||||
*/
|
||||
getExternalGames(): Observable<IExternalGame[]>;
|
||||
|
||||
/**
|
||||
* Get all of the resources.
|
||||
*/
|
||||
@@ -155,6 +213,13 @@ export interface IGamesService {
|
||||
*/
|
||||
getGameCSV(filename: string): Observable<string>;
|
||||
|
||||
/**
|
||||
* Get the Shield data for a game.
|
||||
*
|
||||
* @param filename The filename of the desired CSV.
|
||||
*/
|
||||
getGameShield(filename: string): Observable<IShield>;
|
||||
|
||||
/**
|
||||
* Get the FAQ data for a game.
|
||||
*
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Observable } from 'rxjs';
|
||||
import { IGame, IGamesService, IResource } from './games.service.interface';
|
||||
import { IExternalGame, IGame, IGamesService, IResource, IShield } from './games.service.interface';
|
||||
|
||||
/**
|
||||
* Obtains data relating to the games.
|
||||
@@ -17,6 +17,10 @@ export class GamesService implements IGamesService {
|
||||
return this.http.get<IGame[]>("/assets/json/games.json");
|
||||
}
|
||||
|
||||
getExternalGames(): Observable<IExternalGame[]> {
|
||||
return this.http.get<IExternalGame[]>("/assets/json/external-games.json");
|
||||
}
|
||||
|
||||
getResources(): Observable<IResource[]> {
|
||||
return this.http.get<IResource[]>("/assets/json/resources.json");
|
||||
}
|
||||
@@ -25,6 +29,10 @@ export class GamesService implements IGamesService {
|
||||
return this.http.get(`/assets/csv/${filename}.csv`, { responseType: "text" });
|
||||
}
|
||||
|
||||
getGameShield(filename: string): Observable<IShield> {
|
||||
return this.http.get<IShield>(filename);
|
||||
}
|
||||
|
||||
getGameFAQ(filename: string): Observable<string> {
|
||||
return this.http.get(`/assets/md/${filename}.md`, { responseType: "text" });
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
[
|
||||
{
|
||||
"slug": "botw",
|
||||
"title": "Breath of the Wild",
|
||||
"routingURL": "https://botw.link",
|
||||
"links": {
|
||||
"github": "https://github.com/zeldaret/botw",
|
||||
"progress": "https://botw.link/progress"
|
||||
},
|
||||
"shieldURL": "https://botw.link/badges/progress.json"
|
||||
}
|
||||
]
|
||||
@@ -2,9 +2,11 @@
|
||||
{
|
||||
"slug": "oot",
|
||||
"title": "Ocarina of Time",
|
||||
"routingURL": "games/oot",
|
||||
"links": {
|
||||
"github": "https://www.github.com/zeldaret/oot"
|
||||
},
|
||||
"shieldURL": "assets/csv/progress-oot-shield.json",
|
||||
"faq": "oot_faq",
|
||||
"csvs": {
|
||||
"matching": "progress-oot-matching",
|
||||
@@ -44,9 +46,11 @@
|
||||
{
|
||||
"slug": "mm",
|
||||
"title": "Majora's Mask",
|
||||
"routingURL": "games/mm",
|
||||
"links": {
|
||||
"github": "https://www.github.com/zeldaret/mm"
|
||||
},
|
||||
"shieldURL": "assets/csv/progress-mm-shield.json",
|
||||
"faq": "mm_faq",
|
||||
"csvs": {
|
||||
"matching": "progress-mm-matching",
|
||||
@@ -130,9 +134,11 @@
|
||||
{
|
||||
"slug": "tmc",
|
||||
"title": "The Minish Cap",
|
||||
"routingURL": "games/tmc",
|
||||
"links": {
|
||||
"github": "https://www.github.com/zeldaret/tmc"
|
||||
},
|
||||
"shieldURL": "assets/csv/progress-tmc-shield.json",
|
||||
"faq": "tmc_faq",
|
||||
"csvs": {
|
||||
"matching": "progress-tmc-matching",
|
||||
@@ -175,6 +181,7 @@
|
||||
{
|
||||
"slug": "tp",
|
||||
"title": "Twilight Princess",
|
||||
"routingURL": "games/tp",
|
||||
"links": {
|
||||
"github": "https://www.github.com/zeldaret/tp"
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user