mirror of
https://github.com/PhaseII-eAmusement-Network/PhaseWeb3-Vue.git
synced 2026-03-21 17:54:26 -05:00
Clean up all score page logic, centralize table formatting and parsing, add more game metadata
Some checks are pending
Build / build (push) Waiting to run
Some checks are pending
Build / build (push) Waiting to run
This commit is contained in:
parent
e4a5b21779
commit
9bf57adc7d
|
|
@ -1,4 +1,4 @@
|
|||
VITE_APP_VERSION="3.0.32"
|
||||
VITE_APP_VERSION="3.0.33"
|
||||
VITE_API_URL="http://localhost:8000/"
|
||||
VITE_API_KEY="your_api_key_should_be_here"
|
||||
VITE_ASSET_PATH="/assets"
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
VITE_APP_VERSION="3.0.32"
|
||||
VITE_APP_VERSION="3.0.33"
|
||||
VITE_API_URL="https://restfulsleep.phaseii.network"
|
||||
VITE_API_KEY="your_api_key_should_be_here"
|
||||
VITE_ASSET_PATH="https://cdn.phaseii.network/file/PhaseII/web-assets"
|
||||
|
|
|
|||
|
|
@ -31,5 +31,6 @@
|
|||
"3.0.29": ["- (Major) Finish arcade PASELI support", "- (Minor) Clean up arcade page, add button for opening owner", "- (Bugfix) Fix table upper curved edges"],
|
||||
"3.0.30": ["- (Major) Rewrite auth flow at backend and frontend", "- (Minor) Add auth to all api calls", "- (Bugfix) Fix bad user auth bug", "- (Minor) Add more greetings"],
|
||||
"3.0.31": ["- (Major) Change all date formatting to a sortable format", "- (Minor) Add news archive page", "- (Bugfix) Add real news limiting", "- (Shrimp) Add more shrimp"],
|
||||
"3.0.32": ["- (Major) Change phase \"Attempt\" to \"Score\"", "- (Bugfix) Fix pop'n music version sorting", "- (Bugfix) Fix Gitadora chart data formatting issues", "- (Bugfix) Filter personal records to songs with scores"]
|
||||
"3.0.32": ["- (Major) Change phase \"Attempt\" to \"Score\"", "- (Bugfix) Fix pop'n music version sorting", "- (Bugfix) Fix Gitadora chart data formatting issues", "- (Bugfix) Filter personal records to songs with scores"],
|
||||
"3.0.33": ["- (Major) Condense all score tables to one parser and format", "- (Major) Add more game metadata", "- (Bugfix) Fix difficulties showing as `NaN`", "- (Beta) Add a developmental device plugin for card effect"]
|
||||
}
|
||||
|
|
@ -361,8 +361,9 @@ export const gameData = [
|
|||
noRivals: true,
|
||||
useUnicode: true,
|
||||
scoreHeaders: [
|
||||
{ text: "Combos", value: "data.combo" },
|
||||
{ text: "Medal", value: "data.medal" },
|
||||
{ text: "Clear Gauge", value: "data.clear_gauge", width: 120 },
|
||||
{ text: "Combos", value: "data.combo", width: 120 },
|
||||
{ text: "Medal", value: "data.medal", width: 120 },
|
||||
],
|
||||
chartTable: {
|
||||
0: "LIGHT",
|
||||
|
|
@ -441,7 +442,10 @@ export const gameData = [
|
|||
icon: null,
|
||||
cardBG: null,
|
||||
noRivals: true,
|
||||
scoreHeaders: [{ text: "Combos", value: "data.combo" }],
|
||||
scoreHeaders: [
|
||||
{ text: "Combos", value: "data.combo", width: 120 },
|
||||
{ text: "Halo", value: "data.param", width: 120 },
|
||||
],
|
||||
chartTable: {
|
||||
0: "1A",
|
||||
1: "2A",
|
||||
|
|
|
|||
13
src/constants/scoreDataFilters.js
Normal file
13
src/constants/scoreDataFilters.js
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
export function shouldRenderChart(difficulty, chartTable, chartKey) {
|
||||
const invalidDifficulties = [0, -1, "-1", null];
|
||||
const hasValidDifficulty = !invalidDifficulties.includes(difficulty);
|
||||
const hasChartInTable = !!chartTable?.[chartKey];
|
||||
return hasValidDifficulty && hasChartInTable;
|
||||
}
|
||||
|
||||
export function formatDifficulty(difficulty, difficultyDenom = 1) {
|
||||
if (isNaN(difficulty / difficultyDenom)) {
|
||||
return difficulty;
|
||||
}
|
||||
return difficulty / difficultyDenom;
|
||||
}
|
||||
143
src/constants/table/scores.js
Normal file
143
src/constants/table/scores.js
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
import { formatSortableDate } from "@/constants/date";
|
||||
import { formatDifficulty } from "@/constants/scoreDataFilters";
|
||||
|
||||
export function scoreHeaders(thisGame) {
|
||||
const headers = [
|
||||
{ text: "Player", value: "username", width: 120 },
|
||||
{ text: "New PB", value: "newRecord", width: 100 },
|
||||
{ text: "Timestamp", value: "timestamp", width: 140 },
|
||||
{ text: "Song", value: "song.name", width: 180 },
|
||||
{ text: "Artist", value: "song.artist", width: 150 },
|
||||
{ text: "Chart", value: "song.chart", width: 100 },
|
||||
{ text: "Grade", value: "data.rank", width: 80 },
|
||||
{ text: "Score", value: "points", width: 120 },
|
||||
];
|
||||
|
||||
if (thisGame.scoreHeaders) {
|
||||
for (var header of thisGame.scoreHeaders) {
|
||||
headers.push(header);
|
||||
}
|
||||
}
|
||||
|
||||
return headers;
|
||||
}
|
||||
|
||||
export function personalScoreHeaders(thisGame) {
|
||||
const headers = [
|
||||
{ text: "Timestamp", value: "timestamp", width: 140 },
|
||||
{ text: "New PB", value: "newRecord", width: 100 },
|
||||
{ text: "Song", value: "song.name", width: 180 },
|
||||
{ text: "Artist", value: "song.artist", width: 180 },
|
||||
{ text: "Chart", value: "song.chart", width: 120 },
|
||||
{ text: "Grade", value: "data.rank", width: 80 },
|
||||
{ text: "Score", value: "points", width: 120 },
|
||||
];
|
||||
|
||||
if (thisGame.scoreHeaders) {
|
||||
for (var header of thisGame.scoreHeaders) {
|
||||
headers.push(header);
|
||||
}
|
||||
}
|
||||
|
||||
return headers;
|
||||
}
|
||||
|
||||
export function formatScoreTable(thisGame, scores) {
|
||||
var formattedItems = [];
|
||||
for (var item of scores) {
|
||||
if (item.newRecord) {
|
||||
item.newRecord = "✅";
|
||||
} else {
|
||||
item.newRecord = "";
|
||||
}
|
||||
|
||||
if (item.timestamp) {
|
||||
item.timestamp = formatSortableDate(item.timestamp);
|
||||
}
|
||||
|
||||
if (item.points != undefined) {
|
||||
item.points = item.points
|
||||
.toString()
|
||||
.replace(/\B(?<!\.\d*)(?=(\d{3})+(?!\d))/g, ",");
|
||||
}
|
||||
|
||||
if (item.data?.stats?.score != undefined) {
|
||||
item.exscore = item.points.toString();
|
||||
item.points = item.data?.stats?.score
|
||||
.toString()
|
||||
.replace(/\B(?<!\.\d*)(?=(\d{3})+(?!\d))/g, ",");
|
||||
}
|
||||
|
||||
if (item.song?.chart != undefined && thisGame.chartTable) {
|
||||
item.song.chart = `${thisGame.chartTable[item.song?.chart]} - ${formatDifficulty(
|
||||
item.song.data?.difficulty,
|
||||
thisGame.difficultyDenom,
|
||||
)}`;
|
||||
}
|
||||
|
||||
if (item.data?.halo != undefined && thisGame.haloTable) {
|
||||
item.data.halo = thisGame.haloTable[item.data?.halo];
|
||||
}
|
||||
|
||||
if (item.data?.medal != undefined && thisGame.medalTable) {
|
||||
item.data.medal = thisGame.medalTable[item.data?.medal];
|
||||
}
|
||||
|
||||
if (item.data?.clear_status != undefined && thisGame.medalTable) {
|
||||
item.data.medal = thisGame.medalTable[item.data?.clear_status];
|
||||
}
|
||||
|
||||
if (item.data?.rank != undefined && thisGame.rankTable) {
|
||||
item.data.rank = thisGame.rankTable[item.data?.rank];
|
||||
}
|
||||
|
||||
if (item.data?.result_rank != undefined && thisGame.rankTable) {
|
||||
item.data.rank = thisGame.rankTable[item.data?.result_rank];
|
||||
}
|
||||
|
||||
if (item.data?.grade != undefined && thisGame.rankTable) {
|
||||
item.data.rank = thisGame.rankTable[item.data?.grade];
|
||||
}
|
||||
|
||||
if (item.data?.skill_perc > 0) {
|
||||
item.data.skill_perc = `${item.data?.skill_perc / 100}%`;
|
||||
} else {
|
||||
item.data.skill_perc = "0%";
|
||||
}
|
||||
|
||||
if (item.data?.skill_points) {
|
||||
item.data.skill_points = item.data?.skill_points / 10;
|
||||
}
|
||||
|
||||
if (item.data?.perc > 0) {
|
||||
item.data.perc = `${item.data?.perc / 100}%`;
|
||||
} else {
|
||||
item.data.perc = "0%";
|
||||
}
|
||||
|
||||
if (item.data?.new_skill) {
|
||||
item.data.new_skill = item.data?.new_skill / 10;
|
||||
}
|
||||
|
||||
if (item.data?.music_rate) {
|
||||
item.data.music_rate = item.data?.music_rate / 10;
|
||||
}
|
||||
|
||||
if (item.data?.excellent) {
|
||||
item.medal = "EX FC";
|
||||
} else if (item.data?.fullcombo) {
|
||||
item.medal = "FC";
|
||||
} else if (item.data?.clear) {
|
||||
item.medal = "CLEARED";
|
||||
} else {
|
||||
item.medal = "FAILED";
|
||||
}
|
||||
|
||||
if (item.data?.clear_gauge !== undefined) {
|
||||
item.data.clear_gauge = `${item.data?.clear_gauge / 10}%`;
|
||||
}
|
||||
|
||||
formattedItems.push(item);
|
||||
}
|
||||
return formattedItems;
|
||||
}
|
||||
|
|
@ -12,6 +12,11 @@ import GameHeader from "@/components/Cards/GameHeader.vue";
|
|||
|
||||
import { APIGetRecordData } from "@/stores/api/music";
|
||||
import { getGameInfo } from "@/constants";
|
||||
import {
|
||||
shouldRenderChart,
|
||||
formatDifficulty,
|
||||
} from "@/constants/scoreDataFilters";
|
||||
|
||||
const $route = useRoute();
|
||||
const $router = useRouter();
|
||||
var gameId = $route.params.game;
|
||||
|
|
@ -99,14 +104,22 @@ const filteredSongs = computed(() => {
|
|||
<template v-for="chart of song.charts" :key="chart.db_id">
|
||||
<div
|
||||
v-if="
|
||||
chart.data?.difficulty != 0 &&
|
||||
thisGame.chartTable[chart.chart]
|
||||
shouldRenderChart(
|
||||
chart.data?.difficulty,
|
||||
thisGame.chartTable,
|
||||
chart.chart,
|
||||
)
|
||||
"
|
||||
class="bg-gray-900 dark:bg-gray-700 p-4 rounded-lg"
|
||||
>
|
||||
<h2 class="text-md md:text-lg">
|
||||
{{ thisGame.chartTable[chart.chart] }} -
|
||||
{{ chart.data?.difficulty / (thisGame.difficultyDenom ?? 1) }}
|
||||
{{
|
||||
formatDifficulty(
|
||||
chart.data?.difficulty,
|
||||
thisGame.difficultyDenom,
|
||||
)
|
||||
}}
|
||||
</h2>
|
||||
{{
|
||||
chart.record
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import GeneralTable from "@/components/GeneralTable.vue";
|
|||
import CardBox from "@/components/CardBox.vue";
|
||||
import GameHeader from "@/components/Cards/GameHeader.vue";
|
||||
import { getGameInfo } from "@/constants";
|
||||
import { formatSortableDate } from "@/constants/date";
|
||||
import { formatScoreTable, scoreHeaders } from "@/constants/table/scores";
|
||||
|
||||
const $route = useRoute();
|
||||
const $router = useRouter();
|
||||
|
|
@ -32,128 +32,15 @@ if (!thisGame) {
|
|||
}
|
||||
|
||||
const scores = ref([]);
|
||||
|
||||
const headers = [
|
||||
{ text: "Player", value: "username", width: 120 },
|
||||
{ text: "New PB", value: "newRecord", width: 100 },
|
||||
{ text: "Timestamp", value: "timestamp", width: 140 },
|
||||
{ text: "Song", value: "song.name", width: 180 },
|
||||
{ text: "Artist", value: "song.artist", width: 150 },
|
||||
{ text: "Chart", value: "song.chart", width: 100 },
|
||||
{ text: "Grade", value: "data.rank", width: 80 },
|
||||
{ text: "Score", value: "points", width: 120 },
|
||||
];
|
||||
|
||||
if (thisGame.scoreHeaders) {
|
||||
for (var header of thisGame.scoreHeaders) {
|
||||
headers.push(header);
|
||||
}
|
||||
}
|
||||
|
||||
// headers.push({ text: "Type", value: "type", width: 80 });
|
||||
|
||||
onMounted(async () => {
|
||||
try {
|
||||
const data = await mainStore.getAttemptData(gameID);
|
||||
scores.value = formatScores(data);
|
||||
scores.value = formatScoreTable(thisGame, data);
|
||||
} catch (error) {
|
||||
console.error("Failed to fetch score data:", error);
|
||||
}
|
||||
});
|
||||
|
||||
function formatScores(scores) {
|
||||
var formattedItems = [];
|
||||
for (var item of scores) {
|
||||
if (item.newRecord) {
|
||||
item.newRecord = "✅";
|
||||
} else {
|
||||
item.newRecord = "";
|
||||
}
|
||||
|
||||
if (item.timestamp) {
|
||||
item.timestamp = formatSortableDate(item.timestamp);
|
||||
}
|
||||
|
||||
if (item.points != undefined) {
|
||||
item.points = item.points
|
||||
.toString()
|
||||
.replace(/\B(?<!\.\d*)(?=(\d{3})+(?!\d))/g, ",");
|
||||
}
|
||||
|
||||
if (item.data?.stats?.score != undefined) {
|
||||
item.exscore = item.points.toString();
|
||||
item.points = item.data?.stats?.score
|
||||
.toString()
|
||||
.replace(/\B(?<!\.\d*)(?=(\d{3})+(?!\d))/g, ",");
|
||||
}
|
||||
|
||||
if (item.song?.chart != undefined && thisGame.chartTable) {
|
||||
item.song.chart = thisGame.chartTable[item.song?.chart];
|
||||
}
|
||||
|
||||
if (item.data?.halo != undefined && thisGame.haloTable) {
|
||||
item.data.halo = thisGame.haloTable[item.data?.halo];
|
||||
}
|
||||
|
||||
if (item.data?.medal != undefined && thisGame.medalTable) {
|
||||
item.data.medal = thisGame.medalTable[item.data?.medal];
|
||||
}
|
||||
|
||||
if (item.data?.clear_status != undefined && thisGame.medalTable) {
|
||||
item.data.medal = thisGame.medalTable[item.data?.clear_status];
|
||||
}
|
||||
|
||||
if (item.data?.rank != undefined && thisGame.rankTable) {
|
||||
item.data.rank = thisGame.rankTable[item.data?.rank];
|
||||
}
|
||||
|
||||
if (item.data?.result_rank != undefined && thisGame.rankTable) {
|
||||
item.data.rank = thisGame.rankTable[item.data?.result_rank];
|
||||
}
|
||||
|
||||
if (item.data?.grade != undefined && thisGame.rankTable) {
|
||||
item.data.rank = thisGame.rankTable[item.data?.grade];
|
||||
}
|
||||
|
||||
if (item.data?.skill_perc > 0) {
|
||||
item.data.skill_perc = `${item.data?.skill_perc / 100}%`;
|
||||
} else {
|
||||
item.data.skill_perc = "0%";
|
||||
}
|
||||
|
||||
if (item.data?.skill_points) {
|
||||
item.data.skill_points = item.data?.skill_points / 10;
|
||||
}
|
||||
|
||||
if (item.data?.perc > 0) {
|
||||
item.data.perc = `${item.data?.perc / 100}%`;
|
||||
} else {
|
||||
item.data.perc = "0%";
|
||||
}
|
||||
|
||||
if (item.data?.new_skill) {
|
||||
item.data.new_skill = item.data?.new_skill / 10;
|
||||
}
|
||||
|
||||
if (item.data?.music_rate) {
|
||||
item.data.music_rate = item.data?.music_rate / 10;
|
||||
}
|
||||
|
||||
if (item.data?.excellent) {
|
||||
item.medal = "EX FC";
|
||||
} else if (item.data?.fullcombo) {
|
||||
item.medal = "FC";
|
||||
} else if (item.data?.clear) {
|
||||
item.medal = "CLEARED";
|
||||
} else {
|
||||
item.medal = "FAILED";
|
||||
}
|
||||
|
||||
formattedItems.push(item);
|
||||
}
|
||||
return formattedItems;
|
||||
}
|
||||
|
||||
const navigateToSong = (item) => {
|
||||
const songId = item.song.id;
|
||||
$router.push(`/games/${gameID}/song/${songId}`);
|
||||
|
|
@ -175,7 +62,7 @@ const navigateToSong = (item) => {
|
|||
|
||||
<CardBox has-table>
|
||||
<GeneralTable
|
||||
:headers="headers"
|
||||
:headers="scoreHeaders(thisGame)"
|
||||
:items="scores"
|
||||
@row-clicked="navigateToSong"
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -13,6 +13,11 @@ import GameHeader from "@/components/Cards/GameHeader.vue";
|
|||
import { APIGetRecordData } from "@/stores/api/music";
|
||||
import { APIGetProfile } from "@/stores/api/profile";
|
||||
import { getGameInfo } from "@/constants";
|
||||
import {
|
||||
shouldRenderChart,
|
||||
formatDifficulty,
|
||||
} from "@/constants/scoreDataFilters";
|
||||
|
||||
const $route = useRoute();
|
||||
const $router = useRouter();
|
||||
var gameId = $route.params.game;
|
||||
|
|
@ -156,15 +161,21 @@ const songsWithRecords = computed(() => {
|
|||
<template v-if="chart.record">
|
||||
<div
|
||||
v-if="
|
||||
chart.data?.difficulty != 0 &&
|
||||
thisGame.chartTable[chart.chart]
|
||||
shouldRenderChart(
|
||||
chart.data?.difficulty,
|
||||
thisGame.chartTable,
|
||||
chart.chart,
|
||||
)
|
||||
"
|
||||
class="bg-gray-900 dark:bg-gray-700 p-4 rounded-lg"
|
||||
>
|
||||
<h2 class="text-md lg:text-lg">
|
||||
{{ thisGame.chartTable[chart.chart] }} -
|
||||
{{
|
||||
chart.data?.difficulty / (thisGame.difficultyDenom ?? 1)
|
||||
formatDifficulty(
|
||||
chart.data?.difficulty,
|
||||
thisGame.difficultyDenom,
|
||||
)
|
||||
}}
|
||||
</h2>
|
||||
{{
|
||||
|
|
|
|||
|
|
@ -10,10 +10,13 @@ import BaseButton from "@/components/BaseButton.vue";
|
|||
import GeneralTable from "@/components/GeneralTable.vue";
|
||||
import CardBox from "@/components/CardBox.vue";
|
||||
import GameHeader from "@/components/Cards/GameHeader.vue";
|
||||
import { formatSortableDate } from "@/constants/date";
|
||||
|
||||
import { APIGetProfile } from "@/stores/api/profile";
|
||||
import { getGameInfo } from "@/constants";
|
||||
import {
|
||||
formatScoreTable,
|
||||
personalScoreHeaders,
|
||||
} from "@/constants/table/scores";
|
||||
|
||||
const $route = useRoute();
|
||||
const $router = useRouter();
|
||||
|
|
@ -39,28 +42,10 @@ if (!thisGame) {
|
|||
const myProfile = ref(null);
|
||||
const scores = ref([]);
|
||||
|
||||
const headers = [
|
||||
{ text: "Timestamp", value: "timestamp", width: 140 },
|
||||
{ text: "New PB", value: "newRecord", width: 100 },
|
||||
{ text: "Song", value: "song.name", width: 180 },
|
||||
{ text: "Artist", value: "song.artist", width: 180 },
|
||||
{ text: "Chart", value: "song.chart", width: 100 },
|
||||
{ text: "Grade", value: "data.rank", width: 80 },
|
||||
{ text: "Score", value: "points", width: 120 },
|
||||
];
|
||||
|
||||
if (thisGame.scoreHeaders) {
|
||||
for (var header of thisGame.scoreHeaders) {
|
||||
headers.push(header);
|
||||
}
|
||||
}
|
||||
|
||||
// headers.push({ text: "Type", value: "type", width: 80 });
|
||||
|
||||
onMounted(async () => {
|
||||
try {
|
||||
const data = await mainStore.getAttemptData(gameID, profileUserId);
|
||||
scores.value = formatScores(data);
|
||||
scores.value = formatScoreTable(thisGame, data);
|
||||
} catch (error) {
|
||||
console.error("Failed to fetch score data:", error);
|
||||
}
|
||||
|
|
@ -78,99 +63,6 @@ async function loadProfile() {
|
|||
}
|
||||
}
|
||||
|
||||
function formatScores(scores) {
|
||||
var formattedItems = [];
|
||||
for (var item of scores) {
|
||||
if (item.newRecord) {
|
||||
item.newRecord = "✅";
|
||||
} else {
|
||||
item.newRecord = "";
|
||||
}
|
||||
|
||||
if (item.timestamp) {
|
||||
item.timestamp = formatSortableDate(item.timestamp);
|
||||
}
|
||||
|
||||
if (item.points != undefined) {
|
||||
item.points = item.points
|
||||
.toString()
|
||||
.replace(/\B(?<!\.\d*)(?=(\d{3})+(?!\d))/g, ",");
|
||||
}
|
||||
|
||||
if (item.data?.stats?.score != undefined) {
|
||||
item.exscore = item.points.toString();
|
||||
item.points = item.data?.stats?.score
|
||||
.toString()
|
||||
.replace(/\B(?<!\.\d*)(?=(\d{3})+(?!\d))/g, ",");
|
||||
}
|
||||
|
||||
if (item.song?.chart != undefined && thisGame.chartTable) {
|
||||
item.song.chart = thisGame.chartTable[item.song?.chart];
|
||||
}
|
||||
|
||||
if (item.data?.halo != undefined && thisGame.haloTable) {
|
||||
item.data.halo = thisGame.haloTable[item.data?.halo];
|
||||
}
|
||||
|
||||
if (item.data?.medal != undefined && thisGame.medalTable) {
|
||||
item.data.medal = thisGame.medalTable[item.data?.medal];
|
||||
}
|
||||
|
||||
if (item.data?.clear_status != undefined && thisGame.medalTable) {
|
||||
item.data.medal = thisGame.medalTable[item.data?.clear_status];
|
||||
}
|
||||
|
||||
if (item.data?.rank != undefined && thisGame.rankTable) {
|
||||
item.data.rank = thisGame.rankTable[item.data?.rank];
|
||||
}
|
||||
|
||||
if (item.data?.result_rank != undefined && thisGame.rankTable) {
|
||||
item.data.rank = thisGame.rankTable[item.data?.result_rank];
|
||||
}
|
||||
|
||||
if (item.data?.grade != undefined && thisGame.rankTable) {
|
||||
item.data.rank = thisGame.rankTable[item.data?.grade];
|
||||
}
|
||||
|
||||
if (item.data?.skill_perc > 0) {
|
||||
item.data.skill_perc = `${item.data?.skill_perc / 100}%`;
|
||||
} else {
|
||||
item.data.skill_perc = "0%";
|
||||
}
|
||||
|
||||
if (item.data?.skill_points) {
|
||||
item.data.skill_points = item.data?.skill_points / 10;
|
||||
}
|
||||
|
||||
if (item.data?.perc > 0) {
|
||||
item.data.perc = `${item.data?.perc / 100}%`;
|
||||
} else {
|
||||
item.data.perc = "0%";
|
||||
}
|
||||
|
||||
if (item.data?.new_skill) {
|
||||
item.data.new_skill = item.data?.new_skill / 10;
|
||||
}
|
||||
|
||||
if (item.data?.music_rate) {
|
||||
item.data.music_rate = item.data?.music_rate / 10;
|
||||
}
|
||||
|
||||
if (item.data?.excellent) {
|
||||
item.medal = "EX FC";
|
||||
} else if (item.data?.fullcombo) {
|
||||
item.medal = "FC";
|
||||
} else if (item.data?.clear) {
|
||||
item.medal = "CLEARED";
|
||||
} else {
|
||||
item.medal = "FAILED";
|
||||
}
|
||||
|
||||
formattedItems.push(item);
|
||||
}
|
||||
return formattedItems;
|
||||
}
|
||||
|
||||
const navigateToSong = (item) => {
|
||||
const songId = item.song.id;
|
||||
$router.push(`/games/${gameID}/song/${songId}`);
|
||||
|
|
@ -208,7 +100,7 @@ const navigateToSong = (item) => {
|
|||
|
||||
<CardBox has-table>
|
||||
<GeneralTable
|
||||
:headers="headers"
|
||||
:headers="personalScoreHeaders(thisGame)"
|
||||
:items="scores"
|
||||
@row-clicked="navigateToSong"
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -14,7 +14,8 @@ import GameHeader from "@/components/Cards/GameHeader.vue";
|
|||
|
||||
import { APIGetTopScore } from "@/stores/api/music";
|
||||
import { getGameInfo } from "@/constants";
|
||||
import { formatSortableDate } from "@/constants/date";
|
||||
import { formatDifficulty } from "@/constants/scoreDataFilters";
|
||||
import { formatScoreTable } from "@/constants/table/scores";
|
||||
const $route = useRoute();
|
||||
const $router = useRouter();
|
||||
var gameId = $route.params.game;
|
||||
|
|
@ -69,9 +70,10 @@ const chartOptions = computed(() => {
|
|||
)
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
.map((chart, index) => {
|
||||
const label = `${thisGame.chartTable[chart.chart]} - ${
|
||||
chart.data?.difficulty / (thisGame.difficultyDenom ?? 1)
|
||||
}`;
|
||||
const label = `${thisGame.chartTable[chart.chart]} - ${formatDifficulty(
|
||||
chart.data?.difficulty,
|
||||
thisGame.difficultyDenom,
|
||||
)}`;
|
||||
return { id: chart.chart, label };
|
||||
})
|
||||
);
|
||||
|
|
@ -82,97 +84,9 @@ const selectedChartRecords = computed(() => {
|
|||
const chart = JSON.parse(
|
||||
JSON.stringify(songData.value.charts[chartSelector.currentChart]),
|
||||
);
|
||||
return formatScores(chart?.records ?? []);
|
||||
return formatScoreTable(thisGame, chart?.records ?? []);
|
||||
});
|
||||
|
||||
function formatScores(scores) {
|
||||
var formattedItems = [];
|
||||
for (var rawItem of scores) {
|
||||
const item = { ...rawItem };
|
||||
if (item.timestamp) {
|
||||
item.timestamp = formatSortableDate(item.timestamp);
|
||||
}
|
||||
|
||||
if (item.points != undefined) {
|
||||
item.points = item.points
|
||||
.toString()
|
||||
.replace(/\B(?<!\.\d*)(?=(\d{3})+(?!\d))/g, ",");
|
||||
}
|
||||
|
||||
if (item.data?.stats?.score != undefined) {
|
||||
item.exscore = item.points.toString();
|
||||
item.points = item.data?.stats?.score
|
||||
.toString()
|
||||
.replace(/\B(?<!\.\d*)(?=(\d{3})+(?!\d))/g, ",");
|
||||
}
|
||||
|
||||
if (item.song?.chart != undefined && thisGame.chartTable) {
|
||||
item.song.chart = thisGame.chartTable[item.song?.chart];
|
||||
}
|
||||
|
||||
if (item.data?.halo != undefined && thisGame.haloTable) {
|
||||
item.data.halo = thisGame.haloTable[item.data?.halo];
|
||||
}
|
||||
|
||||
if (item.data?.medal != undefined && thisGame.medalTable) {
|
||||
item.data.medal = thisGame.medalTable[item.data?.medal];
|
||||
}
|
||||
|
||||
if (item.data?.clear_status != undefined && thisGame.medalTable) {
|
||||
item.data.medal = thisGame.medalTable[item.data?.clear_status];
|
||||
}
|
||||
|
||||
if (item.data?.rank != undefined && thisGame.rankTable) {
|
||||
item.data.rank = thisGame.rankTable[item.data?.rank];
|
||||
}
|
||||
|
||||
if (item.data?.result_rank != undefined && thisGame.rankTable) {
|
||||
item.data.rank = thisGame.rankTable[item.data?.result_rank];
|
||||
}
|
||||
|
||||
if (item.data?.grade != undefined && thisGame.rankTable) {
|
||||
item.data.rank = thisGame.rankTable[item.data?.grade];
|
||||
}
|
||||
|
||||
if (item.data?.skill_perc > 0) {
|
||||
item.data.skill_perc = `${item.data?.skill_perc / 100}%`;
|
||||
} else {
|
||||
item.data.skill_perc = "0%";
|
||||
}
|
||||
|
||||
if (item.data?.skill_points) {
|
||||
item.data.skill_points = item.data?.skill_points / 10;
|
||||
}
|
||||
|
||||
if (item.data?.perc > 0) {
|
||||
item.data.perc = `${item.data?.perc / 100}%`;
|
||||
} else {
|
||||
item.data.perc = "0%";
|
||||
}
|
||||
|
||||
if (item.data?.new_skill) {
|
||||
item.data.new_skill = item.data?.new_skill / 10;
|
||||
}
|
||||
|
||||
if (item.data?.music_rate) {
|
||||
item.data.music_rate = item.data?.music_rate / 10;
|
||||
}
|
||||
|
||||
if (item.data?.excellent) {
|
||||
item.medal = "EX FC";
|
||||
} else if (item.data?.fullcombo) {
|
||||
item.medal = "FC";
|
||||
} else if (item.data?.clear) {
|
||||
item.medal = "CLEARED";
|
||||
} else {
|
||||
item.medal = "FAILED";
|
||||
}
|
||||
|
||||
formattedItems.push(item);
|
||||
}
|
||||
return formattedItems;
|
||||
}
|
||||
|
||||
const navigateToProfile = (item) => {
|
||||
const userId = item.userId;
|
||||
$router.push(`/games/${gameId}/profiles/${userId}`);
|
||||
|
|
@ -200,9 +114,10 @@ const navigateToProfile = (item) => {
|
|||
thisGame.chartTable[chart.chart]
|
||||
"
|
||||
color="info"
|
||||
:label="`${thisGame.chartTable[chart.chart]} - ${
|
||||
chart.data?.difficulty / (thisGame.difficultyDenom ?? 1)
|
||||
}`"
|
||||
:label="`${thisGame.chartTable[chart.chart]} - ${formatDifficulty(
|
||||
chart.data?.difficulty,
|
||||
thisGame.difficultyDenom,
|
||||
)}`"
|
||||
/>
|
||||
</template>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<script setup>
|
||||
import { ref, onMounted } from "vue";
|
||||
import { ref, onMounted, onUnmounted } from "vue";
|
||||
import { PhFileImage } from "@phosphor-icons/vue";
|
||||
import SectionMain from "@/components/SectionMain.vue";
|
||||
import CardBox from "@/components/CardBox.vue";
|
||||
|
|
@ -29,6 +29,22 @@ async function loadVideos() {
|
|||
|
||||
onMounted(async () => {
|
||||
await loadVideos();
|
||||
|
||||
// 🌐 Mobile tilt support
|
||||
if (window.DeviceOrientationEvent) {
|
||||
// Request permission on iOS
|
||||
if (typeof DeviceOrientationEvent.requestPermission === "function") {
|
||||
try {
|
||||
const response = await DeviceOrientationEvent.requestPermission();
|
||||
if (response !== "granted") return;
|
||||
} catch (e) {
|
||||
console.warn("Device orientation permission denied {1}", e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener("deviceorientation", handleDeviceTilt);
|
||||
}
|
||||
});
|
||||
|
||||
function filterContent(data) {
|
||||
|
|
@ -79,6 +95,24 @@ function resetTransform(id) {
|
|||
shine.style.opacity = "0";
|
||||
}
|
||||
}
|
||||
|
||||
function handleDeviceTilt(event) {
|
||||
const { beta, gamma } = event; // beta: x-axis (front/back), gamma: y-axis (left/right)
|
||||
if (beta === null || gamma === null) return;
|
||||
|
||||
// Clamp values for smooth motion
|
||||
const rotateX = Math.max(Math.min(beta - 45, 15), -15); // limit between -15° to +15°
|
||||
const rotateY = Math.max(Math.min(gamma, 15), -15);
|
||||
|
||||
const cards = document.querySelectorAll(".tilt-card");
|
||||
cards.forEach((card) => {
|
||||
card.style.transform = `rotateX(${rotateX / 3}deg) rotateY(${rotateY / 3}deg) scale(1.02)`;
|
||||
});
|
||||
}
|
||||
|
||||
onUnmounted(() => {
|
||||
window.removeEventListener("deviceorientation", handleDeviceTilt);
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user