add loading indicator, inactive and banned indicators
Some checks failed
Deploy App / docker (ubuntu-latest) (push) Has been cancelled
Some checks failed
Deploy App / docker (ubuntu-latest) (push) Has been cancelled
This commit is contained in:
parent
49e205f4cf
commit
0c774cca1b
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "scoresaberutils-script",
|
"name": "scoresaberutils-script",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "The TamperMonkey script for ScoreSaber Utils",
|
"description": "TamperMonkey script for ScoreSaber Utils",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "webpack --config webpack.config.js",
|
"build": "webpack --config webpack.config.js",
|
||||||
"dev": "webpack --config webpack.config.js --watch"
|
"dev": "webpack --config webpack.config.js --watch"
|
||||||
|
@ -24,6 +24,9 @@ export function pageChangeCallback(callback: (path: string) => void) {
|
|||||||
* @param baseClass The base class of the element
|
* @param baseClass The base class of the element
|
||||||
*/
|
*/
|
||||||
export function getSvelteClass(baseClass: string): string | null {
|
export function getSvelteClass(baseClass: string): string | null {
|
||||||
|
if (!baseClass.startsWith(".")) {
|
||||||
|
baseClass = `.${baseClass.split(" ").join(".")}`;
|
||||||
|
}
|
||||||
const element = document.querySelector(baseClass);
|
const element = document.querySelector(baseClass);
|
||||||
if (!element) {
|
if (!element) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import {API_URL} from "../consts";
|
import { API_URL } from "../consts";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a player from the ScoreSaber Utils API
|
* Gets a player from the ScoreSaber Utils API
|
||||||
@ -8,13 +8,15 @@ import {API_URL} from "../consts";
|
|||||||
export async function getPlayer(id: string) {
|
export async function getPlayer(id: string) {
|
||||||
const response = await fetch(`${API_URL}/account/${id}`);
|
const response = await fetch(`${API_URL}/account/${id}`);
|
||||||
|
|
||||||
|
const json = await response.json();
|
||||||
|
|
||||||
// There was an error fetching the player
|
// There was an error fetching the player
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error("Failed to fetch player");
|
throw new Error(json.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the player's data
|
// Return the player's data
|
||||||
return response.json();
|
return json;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -23,4 +25,4 @@ export async function getPlayer(id: string) {
|
|||||||
export function getPlayerIdFromUrl(): string {
|
export function getPlayerIdFromUrl(): string {
|
||||||
const url = new URL(location.href);
|
const url = new URL(location.href);
|
||||||
return url.pathname.split("/")[2];
|
return url.pathname.split("/")[2];
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import Page from "../page";
|
import Page from "../page";
|
||||||
import {getElement, getSvelteClass} from "../../common/page-utils";
|
import { getElement, getSvelteClass } from "../../common/page-utils";
|
||||||
import {getPlayer, getPlayerIdFromUrl} from "../../common/player";
|
import { getPlayer, getPlayerIdFromUrl } from "../../common/player";
|
||||||
|
|
||||||
export default class PlayerPage extends Page {
|
export default class PlayerPage extends Page {
|
||||||
constructor() {
|
constructor() {
|
||||||
@ -8,16 +8,35 @@ export default class PlayerPage extends Page {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async onLoad() {
|
public async onLoad() {
|
||||||
|
let loadingElement;
|
||||||
|
let titleElement;
|
||||||
try {
|
try {
|
||||||
// Wait for the title element to load, so we know the page is fully loaded
|
// Wait for the title element to load, so we know the page is fully loaded
|
||||||
const titleElement = await getElement(".title.is-5.player.has-text-centered-mobile", 250);
|
titleElement = await getElement(
|
||||||
|
".title.is-5.player.has-text-centered-mobile",
|
||||||
|
);
|
||||||
|
const id: string = getPlayerIdFromUrl();
|
||||||
|
|
||||||
const id = getPlayerIdFromUrl();
|
loadingElement = await this.addLoadingElement(titleElement);
|
||||||
const player = await getPlayer(id);
|
const player: any = await getPlayer(id);
|
||||||
|
loadingElement(); // Remove the loading element
|
||||||
|
|
||||||
await this.addStats(player); // Add our custom stats
|
await this.addStats(player); // Add our custom stats
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Failed to load player page", error);
|
loadingElement(); // Remove the loading element
|
||||||
|
|
||||||
|
if (error.message.includes("inactive")) {
|
||||||
|
await this.addLoadingElement(
|
||||||
|
titleElement,
|
||||||
|
"This player is inactive, no extra data available",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (error.message.includes("banned")) {
|
||||||
|
await this.addLoadingElement(
|
||||||
|
titleElement,
|
||||||
|
"This player is banned, no extra data available",
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -26,11 +45,11 @@ export default class PlayerPage extends Page {
|
|||||||
*
|
*
|
||||||
* @param player the player to add stats for
|
* @param player the player to add stats for
|
||||||
*/
|
*/
|
||||||
private async addStats(player: any) {
|
private async addStats(player: any): Promise<void> {
|
||||||
await this.addStat(
|
await this.addStat(
|
||||||
"+1 PP",
|
"+1 PP",
|
||||||
`${player.rawPerGlobalPerformancePoints.toFixed(2)}pp`,
|
`${player.rawPerGlobalPerformancePoints.toFixed(2)}pp`,
|
||||||
"Raw performance points to gain +1 global PP"
|
"Raw performance points to gain +1 global PP",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,16 +60,53 @@ export default class PlayerPage extends Page {
|
|||||||
* @param value the value of the stat
|
* @param value the value of the stat
|
||||||
* @param hover the hover text of the stat
|
* @param hover the hover text of the stat
|
||||||
*/
|
*/
|
||||||
private async addStat(stat: string, value: string, hover?: string) {
|
private async addStat(
|
||||||
const statsContainer = await getElement(".stats-container");
|
stat: string,
|
||||||
const statElement = document.createElement("div");
|
value: string,
|
||||||
const svelteClass = getSvelteClass(".stats-container");
|
hover?: string,
|
||||||
|
): Promise<void> {
|
||||||
|
const statsContainer: HTMLElement = await getElement(".stats-container");
|
||||||
|
const statElement: HTMLDivElement = document.createElement("div");
|
||||||
|
const svelteClass: string = getSvelteClass(".stats-container");
|
||||||
|
|
||||||
statElement.className = `stat-item ${svelteClass}`;
|
statElement.className = `stat-item ${svelteClass}`;
|
||||||
statElement.innerHTML = `
|
statElement.innerHTML = `
|
||||||
<span class="stat-title ${svelteClass}">${stat}</span>
|
<span class="stat-title ${svelteClass}">${stat}</span>
|
||||||
<span class="stat-spacer ${svelteClass}"></span>
|
<span class="stat-spacer ${svelteClass}"></span>
|
||||||
<span class="stat-content ${hover && "has-hover"} ${svelteClass}" ${hover && `title="${hover}"`}>${value}</span>`;
|
<span class="stat-content ${hover && "has-hover"} ${svelteClass}" ${hover && `title="${hover}"`}>${value}</span>`;
|
||||||
statsContainer.appendChild(statElement);
|
statsContainer.appendChild(statElement); // Add the stat to the stats container
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
/**
|
||||||
|
* Create a loading element to show the user
|
||||||
|
*
|
||||||
|
* @param element the element to append the loading element to
|
||||||
|
* @param text the text to show in the loading element
|
||||||
|
* @returns the loading element
|
||||||
|
*/
|
||||||
|
private async addLoadingElement(
|
||||||
|
element: HTMLElement,
|
||||||
|
text: string = "Loading SSU data...",
|
||||||
|
): Promise<() => void> {
|
||||||
|
const svelteClass: string = getSvelteClass(element.className);
|
||||||
|
|
||||||
|
// The divider element
|
||||||
|
const dividerElement: HTMLDivElement = document.createElement("div");
|
||||||
|
dividerElement.className = `divider ${svelteClass}`;
|
||||||
|
|
||||||
|
// The loading element
|
||||||
|
const loadingElement: HTMLSpanElement = document.createElement("span");
|
||||||
|
loadingElement.className = `title-header ${svelteClass} font-size: 1rem;`;
|
||||||
|
loadingElement.style.alignSelf = "flex-end";
|
||||||
|
loadingElement.innerHTML = `
|
||||||
|
<p>${text}</p>`;
|
||||||
|
|
||||||
|
element.appendChild(dividerElement);
|
||||||
|
element.appendChild(loadingElement);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
dividerElement.remove();
|
||||||
|
loadingElement.remove();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -2,7 +2,7 @@ export default class Page {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* The route of the page
|
* The route of the page
|
||||||
* eg: /ranking
|
* eg: /ranking/
|
||||||
*/
|
*/
|
||||||
private readonly _route: string;
|
private readonly _route: string;
|
||||||
|
|
||||||
@ -13,7 +13,7 @@ export default class Page {
|
|||||||
/*
|
/*
|
||||||
* This gets called when the page is loaded
|
* This gets called when the page is loaded
|
||||||
*/
|
*/
|
||||||
public onLoad() {}
|
public async onLoad() {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The route of the page
|
* The route of the page
|
||||||
|
@ -27,7 +27,7 @@ module.exports = {
|
|||||||
author: "fascinated7 (discord)",
|
author: "fascinated7 (discord)",
|
||||||
"run-at": "document-end",
|
"run-at": "document-end",
|
||||||
match: "https://scoresaber.com/*",
|
match: "https://scoresaber.com/*",
|
||||||
version: `1.0.0-${process.env.GIT_REV.substring(0, 7) || "dev"}`,
|
version: `1.0.0-${process.env.GIT_REV ? process.env.GIT_REV.substring(0, 7) : "dev"}`,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
],
|
],
|
||||||
|
Loading…
Reference in New Issue
Block a user