mirror of
https://github.com/PhaseII-eAmusement-Network/PhaseWeb3-Vue.git
synced 2026-09-12 03:05:15 -05:00
Add game header card, add admin page for arcades, fix bugs
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
VITE_APP_VERSION="3.0.5"
|
||||
VITE_APP_VERSION="3.0.6"
|
||||
VITE_API_URL="http://10.5.7.5:8000/"
|
||||
VITE_API_KEY="your_api_key_should_be_here"
|
||||
VITE_ASSET_PATH="/assets"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
VITE_APP_VERSION="3.0.5"
|
||||
VITE_APP_VERSION="3.0.6"
|
||||
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"
|
||||
|
||||
@@ -3,5 +3,6 @@
|
||||
"3.0.2": ["- (Feature) Added new greetings", "- (Feature) Added new user background", "- (Feature) Added toggle for disabling/enabling this popup", "- (Feature) Added version info to footer", "- (Feature) Fill in more profile data on personal profile view", "- (Fix) DDR stats now work again", "- (Fix) DDR player weight can now be set (kinda)"],
|
||||
"3.0.3": ["- (Feature) Discord avatars are now reactive!", "- (Feature) New profile badges! I'll be working on a backend for these soon™️", "- (Optimization) Fix this box's formatting on mobile."],
|
||||
"3.0.4": ["- (Feature) Add performance event flag settings for SOUND VOLTEX EXCEED GEAR"],
|
||||
"3.0.5": ["- (Feature) Add profile badges based on Discord server roles. Expands Discord linking capabilities."]
|
||||
"3.0.5": ["- (Feature) Add profile badges based on Discord server roles. Expands Discord linking capabilities."],
|
||||
"3.0.6": ["- (Major) Replace non-standard game cards with a standardized and new header card. May break some layouts so PLEASE REPORT BUGS!", "- (Feature) Create song detail page, not yet completed or reactive.", "- (Bugfix) Fix issue where deleteSession fails if the session has already been deleted.", "- (Minor) Edit ring color on red buttons", "- (Admin) Add Arcades admin page", "- (Bugfix) Fix incorrect prop types for Notes Radar"]
|
||||
}
|
||||
@@ -95,7 +95,7 @@ export const getButtonColor = (
|
||||
lightDark: "border-gray-100 dark:border-slate-800",
|
||||
contrast: "border-gray-800 dark:border-white",
|
||||
success: "border-emerald-600 dark:border-emerald-800",
|
||||
danger: "border-red-600 dark:border-ruby-950",
|
||||
danger: "border-red-600 dark:border-red-950",
|
||||
warning: "border-yellow-600 dark:border-yellow-950",
|
||||
info: "border-blue-600 dark:border-blue-950",
|
||||
},
|
||||
|
||||
@@ -50,6 +50,10 @@ defineProps({
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
smallContent: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -82,7 +86,9 @@ defineProps({
|
||||
:prefix="prefix"
|
||||
:suffix="suffix"
|
||||
/>
|
||||
<div :class="numColor">
|
||||
<div
|
||||
:class="numColor + (smallContent ? ` text-lg font-normal` : ``)"
|
||||
>
|
||||
<slot />
|
||||
</div>
|
||||
</h1>
|
||||
|
||||
153
src/components/Cards/GameHeader.vue
Normal file
153
src/components/Cards/GameHeader.vue
Normal file
@@ -0,0 +1,153 @@
|
||||
<script setup>
|
||||
import { ref, watch } from "vue";
|
||||
import { useRoute } from "vue-router";
|
||||
import {
|
||||
mdiHome,
|
||||
mdiCog,
|
||||
mdiAccountDetails,
|
||||
mdiPlaylistMusicOutline,
|
||||
mdiSwordCross,
|
||||
} from "@mdi/js";
|
||||
import BaseButton from "@/components/BaseButton.vue";
|
||||
import GameTitleLine from "@/components/GameTitleLine.vue";
|
||||
import { getVideoSource, getCardStyle } from "@/constants/sources";
|
||||
|
||||
import { useMainStore } from "@/stores/main";
|
||||
const mainStore = useMainStore();
|
||||
const $route = useRoute();
|
||||
const userProfiles = ref(mainStore.userProfiles);
|
||||
watch(
|
||||
() => mainStore.userProfiles,
|
||||
(newValue) => {
|
||||
userProfiles.value = newValue;
|
||||
}
|
||||
);
|
||||
|
||||
const props = defineProps({
|
||||
game: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
version: {
|
||||
type: Number,
|
||||
default: null,
|
||||
},
|
||||
});
|
||||
|
||||
function loadRoutes() {
|
||||
const navigationData = [
|
||||
{
|
||||
label: `${
|
||||
props.game.shortName ? props.game.shortName : props.game.name
|
||||
} Home`,
|
||||
icon: mdiHome,
|
||||
path: `/#/games/${props.game.id}/`,
|
||||
route: "game_page",
|
||||
color: "success",
|
||||
},
|
||||
// {
|
||||
// label: "Network Records",
|
||||
// icon: mdiFormatListText,
|
||||
// path: `/#/games/${props.game.id}/records`,
|
||||
// route: "",
|
||||
// color: "success",
|
||||
// },
|
||||
];
|
||||
|
||||
if (userProfiles.value.some((profile) => profile.game === props.game.id)) {
|
||||
navigationData.push({
|
||||
label: "My Profile",
|
||||
icon: mdiAccountDetails,
|
||||
path: `/#/games/${props.game.id}/profiles/${mainStore.userId}`,
|
||||
route: "game_profile",
|
||||
color: "info",
|
||||
});
|
||||
|
||||
navigationData.push({
|
||||
label: "Edit Profile",
|
||||
icon: mdiCog,
|
||||
path: `/#/games/${props.game.id}/edit`,
|
||||
route: "edit_profile",
|
||||
color: "warning",
|
||||
});
|
||||
|
||||
if (!props.game.noRivals) {
|
||||
navigationData.push({
|
||||
label: "Rivals",
|
||||
icon: mdiSwordCross,
|
||||
path: `/#/games/${props.game.id}/rivals`,
|
||||
route: "game_rivals",
|
||||
color: "danger",
|
||||
});
|
||||
}
|
||||
|
||||
if (!props.game.noScores) {
|
||||
navigationData.push({
|
||||
label: "My Scores",
|
||||
icon: mdiPlaylistMusicOutline,
|
||||
path: `/#/games/${props.game.id}/scores/${mainStore.userId}`,
|
||||
color: "info",
|
||||
});
|
||||
}
|
||||
|
||||
// navigationData.push({
|
||||
// label: "My Records",
|
||||
// icon: mdiFormatListText,
|
||||
// path: `/#/games/${props.game.id}/`,
|
||||
// route: "game_page",
|
||||
// color: "success",
|
||||
// });
|
||||
}
|
||||
|
||||
if (!props.game.noScores) {
|
||||
navigationData.push({
|
||||
label: "Network Scores",
|
||||
icon: mdiPlaylistMusicOutline,
|
||||
path: `/#/games/${props.game.id}/scores`,
|
||||
route: "all_scores",
|
||||
color: "info",
|
||||
});
|
||||
}
|
||||
|
||||
return navigationData;
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
v-if="game"
|
||||
:style="getCardStyle(game, version)"
|
||||
class="rounded-2xl mb-6 card-container"
|
||||
>
|
||||
<video
|
||||
autoplay
|
||||
muted
|
||||
loop
|
||||
playsinline
|
||||
:src="getVideoSource(game, version)"
|
||||
class="background-video"
|
||||
></video>
|
||||
<div class="bg-white dark:bg-slate-900/90 rounded-2xl card-content">
|
||||
<GameTitleLine :path="game.icon" :title="game.name">
|
||||
<div class="w-full">
|
||||
<div class="w-full">
|
||||
<slot />
|
||||
</div>
|
||||
<div
|
||||
class="w-full grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:flex gap-3"
|
||||
>
|
||||
<template v-for="item of loadRoutes()" :key="item.path">
|
||||
<BaseButton
|
||||
v-if="item.route != $route.name"
|
||||
:href="item.path"
|
||||
:icon="item.icon"
|
||||
:label="item.label"
|
||||
:color="item.color"
|
||||
/>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</GameTitleLine>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -26,7 +26,7 @@ ChartJS.register(
|
||||
|
||||
const props = defineProps({
|
||||
profile: {
|
||||
type: Number,
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
game: {
|
||||
|
||||
@@ -17,16 +17,18 @@ const hasSlot = computed(() => useSlots().default);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="pt-6 mb-6 flex items-center justify-between">
|
||||
<div class="flex items-center justify-start space-x-2">
|
||||
<GameIcon :path="path" class="w-12 h-12 p-1 drop-shadow-md" />
|
||||
<div class="space-y-1">
|
||||
<section class="mb-2">
|
||||
<div
|
||||
class="text-center lg:text-left items-center justify-center lg:justify-start gap-2"
|
||||
>
|
||||
<div class="flex items-center justify-start">
|
||||
<GameIcon :path="path" class="w-12 h-12 p-1 drop-shadow-md" />
|
||||
<h1 class="text-2xl md:text-3xl leading-tight">
|
||||
{{ title }}
|
||||
</h1>
|
||||
<div class="w-full flex gap-1">
|
||||
<slot v-if="hasSlot" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="w-full flex gap-1 mb-4">
|
||||
<slot v-if="hasSlot" />
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -25,7 +25,7 @@ const hasSlot = computed(() => useSlots().default);
|
||||
<template>
|
||||
<section
|
||||
:class="{ 'pt-6': !main }"
|
||||
class="mb-6 flex items-center justify-between"
|
||||
class="mb-6 md:flex items-center md:justify-between space-y-2 md:space-y-0"
|
||||
>
|
||||
<div class="flex items-center justify-start">
|
||||
<IconRounded
|
||||
|
||||
@@ -27,3 +27,15 @@ export function getCardStyle(game, version) {
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
export function customStyle(src) {
|
||||
if (!src) {
|
||||
return null;
|
||||
} else {
|
||||
return `
|
||||
background-image: url('${src}');
|
||||
background-size: cover;
|
||||
background-repeat: no-repeat;
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -158,10 +158,6 @@ const menuAside = computed(() => {
|
||||
label: "Arcades",
|
||||
to: "/admin/arcades",
|
||||
},
|
||||
{
|
||||
label: "Machines",
|
||||
to: "/admin/machines",
|
||||
},
|
||||
{
|
||||
label: "Cards",
|
||||
to: "/admin/cards",
|
||||
|
||||
@@ -173,14 +173,6 @@ const routes = [
|
||||
name: "admin_arcades",
|
||||
component: () => import("@/views/Admin/ArcadesView.vue"),
|
||||
},
|
||||
{
|
||||
meta: {
|
||||
title: "Machines",
|
||||
},
|
||||
path: "/admin/machines",
|
||||
name: "admin_machines",
|
||||
component: () => import("@/views/Admin/MachinesView.vue"),
|
||||
},
|
||||
{
|
||||
meta: {
|
||||
title: "Cards",
|
||||
@@ -325,6 +317,17 @@ const routes = [
|
||||
hotReload: true, // disables Hot Reload
|
||||
},
|
||||
},
|
||||
{
|
||||
meta: {
|
||||
title: "Song Overview",
|
||||
},
|
||||
path: "/games/:game/song/:songId",
|
||||
name: "song_overview",
|
||||
component: () => import("@/views/Game/SongView.vue"),
|
||||
options: {
|
||||
hotReload: true, // disables Hot Reload
|
||||
},
|
||||
},
|
||||
{
|
||||
meta: {
|
||||
title: "View Scores",
|
||||
|
||||
@@ -10,6 +10,16 @@ export async function APIAdminDashboard() {
|
||||
}
|
||||
}
|
||||
|
||||
export async function APIAdminArcades() {
|
||||
try {
|
||||
const data = await mainStore.callApi(`/admin/arcades`);
|
||||
return data.data;
|
||||
} catch (error) {
|
||||
console.log("Error loading arcades:", error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
export async function checkArcadeName(arcadeName) {
|
||||
try {
|
||||
const data = await mainStore.callApi(
|
||||
|
||||
@@ -208,6 +208,11 @@ export const useMainStore = defineStore("main", {
|
||||
},
|
||||
|
||||
async deleteUserSession() {
|
||||
if (!loadUserAuthKey()) {
|
||||
this.userLoaded = false;
|
||||
return null;
|
||||
}
|
||||
|
||||
const request = {
|
||||
sessionId: loadUserAuthKey(),
|
||||
};
|
||||
|
||||
@@ -1,30 +1,200 @@
|
||||
<script setup>
|
||||
import { mdiFlagCheckered, mdiSecurity } from "@mdi/js";
|
||||
import { ref, reactive, onMounted } from "vue";
|
||||
import { useRouter } from "vue-router";
|
||||
import {
|
||||
mdiStoreOutline,
|
||||
mdiStoreEditOutline,
|
||||
mdiStorePlusOutline,
|
||||
} from "@mdi/js";
|
||||
import SectionMain from "@/components/SectionMain.vue";
|
||||
import CardBox from "@/components/CardBox.vue";
|
||||
import CardBoxWidget from "@/components/CardBoxWidget.vue";
|
||||
import GeneralTable from "@/components/GeneralTable.vue";
|
||||
import LayoutAuthenticated from "@/layouts/LayoutAuthenticated.vue";
|
||||
import SectionTitleLine from "@/components/SectionTitleLine.vue";
|
||||
import BaseButton from "@/components/BaseButton.vue";
|
||||
import FormField from "@/components/FormField.vue";
|
||||
import FormControl from "@/components/FormControl.vue";
|
||||
|
||||
import { APIAdminArcades } from "@/stores/api/admin";
|
||||
|
||||
const $router = useRouter();
|
||||
const arcadeData = ref([]);
|
||||
const headers = [
|
||||
{
|
||||
text: "Name",
|
||||
value: "name",
|
||||
width: 150,
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
text: "Description",
|
||||
value: "description",
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
text: "Owners",
|
||||
value: "owners",
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
text: "PASELI Enabled",
|
||||
value: "data.paseli_enabled",
|
||||
width: 50,
|
||||
},
|
||||
{
|
||||
text: "Infinite PASELI",
|
||||
value: "data.paseli_infinite",
|
||||
width: 50,
|
||||
},
|
||||
{
|
||||
text: "Beta Enabled",
|
||||
value: "data.is_beta",
|
||||
width: 50,
|
||||
sortable: true,
|
||||
},
|
||||
];
|
||||
|
||||
onMounted(async () => {
|
||||
loadData();
|
||||
});
|
||||
|
||||
async function loadData() {
|
||||
try {
|
||||
const data = await APIAdminArcades();
|
||||
var formattedItems = [];
|
||||
for (var item of data) {
|
||||
if (item.timestamp) {
|
||||
const date = new Date(item.timestamp * 1000);
|
||||
item.timestamp = date.toLocaleString();
|
||||
}
|
||||
|
||||
if (item.owners) {
|
||||
item.owners = item.owners.join(", ");
|
||||
}
|
||||
|
||||
formattedItems.push(item);
|
||||
}
|
||||
|
||||
arcadeData.value = formattedItems;
|
||||
} catch (error) {
|
||||
console.error("Failed to fetch client data:", error);
|
||||
}
|
||||
}
|
||||
|
||||
const openArcade = (item) => {
|
||||
const arcadeId = item.id;
|
||||
$router.push(`/arcade/${arcadeId}`);
|
||||
};
|
||||
|
||||
const filterForm = reactive({
|
||||
filter: null,
|
||||
});
|
||||
|
||||
function filterArcades() {
|
||||
if (filterForm.filter) {
|
||||
return arcadeData.value.filter(
|
||||
(arcade) =>
|
||||
arcade.name.toLowerCase().includes(filterForm.filter.toLowerCase()) ||
|
||||
arcade.description
|
||||
.toLowerCase()
|
||||
.includes(filterForm.filter.toLowerCase()) ||
|
||||
arcade.owners.toLowerCase().includes(filterForm.filter.toLowerCase())
|
||||
);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<LayoutAuthenticated>
|
||||
<SectionMain>
|
||||
<CardBox class="mb-6 p-1">
|
||||
<h1 class="text-3xl">Arcade Management</h1>
|
||||
<p class="text-sm text-gray-400">Enter an arcade to manage it</p>
|
||||
</CardBox>
|
||||
|
||||
<SectionTitleLine
|
||||
:icon="mdiSecurity"
|
||||
title="Network Administration"
|
||||
color="text-red-600"
|
||||
:icon="mdiStoreOutline"
|
||||
title="All Arcades"
|
||||
color="text-blue-400"
|
||||
main
|
||||
/>
|
||||
|
||||
<div class="grid grid-cols-1 gap-6 sm:grid-cols-2 md:grid-cols-3 mb-6">
|
||||
<CardBoxWidget :number="1" label="User Account(s)" />
|
||||
<CardBoxWidget :number="2" label="Registered Arcades" />
|
||||
<CardBoxWidget :number="3" label="Published Scores" />
|
||||
</div>
|
||||
<CardBox has-table class="mb-6">
|
||||
<div
|
||||
class="bg-white dark:bg-slate-900/95 rounded-2xl lg:flex lg:justify-between"
|
||||
>
|
||||
<div class="w-full">
|
||||
<GeneralTable
|
||||
:headers="headers"
|
||||
:items="arcadeData"
|
||||
@row-clicked="openArcade"
|
||||
/>
|
||||
<h1 class="mx-4 mt-1 mb-2 text-md lg:text-lg">
|
||||
Click row to open arcade
|
||||
</h1>
|
||||
</div>
|
||||
</div>
|
||||
</CardBox>
|
||||
|
||||
<SectionTitleLine :icon="mdiFlagCheckered" title="Recent Errors" />
|
||||
<CardBox> </CardBox>
|
||||
<SectionTitleLine
|
||||
:icon="mdiStoreEditOutline"
|
||||
title="Search Arcades"
|
||||
color="text-amber-600"
|
||||
main
|
||||
/>
|
||||
<CardBox class="mb-6">
|
||||
<FormField
|
||||
label="Search"
|
||||
help="Search by name, description, or owner."
|
||||
class="w-full md:w-1/3"
|
||||
>
|
||||
<FormControl
|
||||
v-model="filterForm.filter"
|
||||
:model-value="filterForm.filter"
|
||||
/>
|
||||
</FormField>
|
||||
|
||||
<div class="grid gap-4">
|
||||
<div
|
||||
v-for="arcade of filterArcades()"
|
||||
:key="arcade.id"
|
||||
class="bg-slate-800 p-4 rounded-xl"
|
||||
>
|
||||
<div class="md:flex w-full place-content-between">
|
||||
<div>
|
||||
<h1 class="text-lg md:text-xl">{{ arcade.name }}</h1>
|
||||
<h2 class="text-md md:text-lg">
|
||||
{{ arcade.description }}
|
||||
</h2>
|
||||
<h2 class="text-md">Managed by {{ arcade.owners }}</h2>
|
||||
</div>
|
||||
|
||||
<div class="flex align-middle mt-2 md:mt-0">
|
||||
<BaseButton
|
||||
label="Open Arcade"
|
||||
color="info"
|
||||
@click="openArcade(arcade)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</CardBox>
|
||||
|
||||
<SectionTitleLine
|
||||
:icon="mdiStorePlusOutline"
|
||||
title="Create Arcade"
|
||||
color="text-emerald-600"
|
||||
main
|
||||
/>
|
||||
<CardBox is-form class="row-span-1" @submit.prevent="createClient()">
|
||||
<BaseButton
|
||||
color="info"
|
||||
:small="false"
|
||||
label="Arcade Onboarding"
|
||||
to="/admin/onboarding"
|
||||
/>
|
||||
</CardBox>
|
||||
</SectionMain>
|
||||
</LayoutAuthenticated>
|
||||
</template>
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
<script setup>
|
||||
import { mdiFlagCheckered, mdiSecurity } from "@mdi/js";
|
||||
import SectionMain from "@/components/SectionMain.vue";
|
||||
import CardBox from "@/components/CardBox.vue";
|
||||
import CardBoxWidget from "@/components/CardBoxWidget.vue";
|
||||
import LayoutAuthenticated from "@/layouts/LayoutAuthenticated.vue";
|
||||
import SectionTitleLine from "@/components/SectionTitleLine.vue";
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<LayoutAuthenticated>
|
||||
<SectionMain>
|
||||
<SectionTitleLine
|
||||
:icon="mdiSecurity"
|
||||
title="Network Administration"
|
||||
color="text-red-600"
|
||||
main
|
||||
/>
|
||||
|
||||
<div class="grid grid-cols-1 gap-6 sm:grid-cols-2 md:grid-cols-3 mb-6">
|
||||
<CardBoxWidget :number="1" label="User Account(s)" />
|
||||
<CardBoxWidget :number="2" label="Registered Arcades" />
|
||||
<CardBoxWidget :number="3" label="Published Scores" />
|
||||
</div>
|
||||
|
||||
<SectionTitleLine :icon="mdiFlagCheckered" title="Recent Errors" />
|
||||
<CardBox> </CardBox>
|
||||
</SectionMain>
|
||||
</LayoutAuthenticated>
|
||||
</template>
|
||||
@@ -1,10 +1,11 @@
|
||||
<script setup>
|
||||
import { reactive, onMounted, watch, ref } from "vue";
|
||||
import { useRoute, useRouter } from "vue-router";
|
||||
import { mdiAccountTieHat, mdiBackburger } from "@mdi/js";
|
||||
import { mdiAccountTieHat } from "@mdi/js";
|
||||
import SectionMain from "@/components/SectionMain.vue";
|
||||
import CardBox from "@/components/CardBox.vue";
|
||||
import BaseButton from "@/components/BaseButton.vue";
|
||||
import GameHeader from "@/components/Cards/GameHeader.vue";
|
||||
import ProfileCard from "@/components/Cards/ProfileCard.vue";
|
||||
import LayoutAuthenticated from "@/layouts/LayoutAuthenticated.vue";
|
||||
import SectionTitleLine from "@/components/SectionTitleLine.vue";
|
||||
@@ -25,7 +26,6 @@ import {
|
||||
transformUnicode,
|
||||
} from "@/constants/values";
|
||||
import { getGameInfo } from "@/constants";
|
||||
import { getVideoSource, getCardStyle } from "@/constants/sources";
|
||||
import { getGameOptions } from "@/constants/options";
|
||||
|
||||
const $route = useRoute();
|
||||
@@ -120,61 +120,39 @@ async function updateProfile() {
|
||||
<template>
|
||||
<LayoutAuthenticated>
|
||||
<SectionMain>
|
||||
<div class="md:flex pb-6 md:justify-between md:items-center">
|
||||
<BaseButton
|
||||
:icon="mdiBackburger"
|
||||
:href="`/#/games/${gameID}`"
|
||||
class="w-full md:w-auto"
|
||||
color="info"
|
||||
label="Go Back"
|
||||
/>
|
||||
<GameHeader :game="thisGame" :version="versionForm.currentVersion">
|
||||
<div
|
||||
v-if="thisGame.versions && myProfile"
|
||||
class="mt-2 md:mt-0 md:w-1/3 md:text-right"
|
||||
class="w-full md:flex md:-mt-[75px] mb-4 place-content-end"
|
||||
>
|
||||
<h2 class="text-md sm:text-lg md:text-xl font-bold p-2">
|
||||
Select Version
|
||||
</h2>
|
||||
<FormControl
|
||||
v-model="versionForm.currentVersion"
|
||||
:options="filterVersions(myProfile.versions)"
|
||||
/>
|
||||
<div class="md:w-1/3 md:text-right">
|
||||
<h2 class="text-md sm:text-lg md:text-xl font-bold p-2">
|
||||
Select Version
|
||||
</h2>
|
||||
<FormControl
|
||||
v-model="versionForm.currentVersion"
|
||||
:options="filterVersions(myProfile.versions)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="myProfile" class="w-full">
|
||||
<ProfileCard
|
||||
:game="gameID"
|
||||
:version="versionForm.currentVersion"
|
||||
:profile="myProfile"
|
||||
use-small
|
||||
>
|
||||
</ProfileCard>
|
||||
</div>
|
||||
</GameHeader>
|
||||
|
||||
<SectionTitleLine
|
||||
v-if="versionForm.currentVersion"
|
||||
:icon="mdiAccountTieHat"
|
||||
title="Profile Customizations"
|
||||
main
|
||||
/>
|
||||
<div
|
||||
v-if="versionForm.currentVersion && myProfile"
|
||||
:style="getCardStyle(thisGame, versionForm.currentVersion)"
|
||||
class="rounded-2xl mb-6 card-container"
|
||||
>
|
||||
<video
|
||||
autoplay
|
||||
muted
|
||||
loop
|
||||
playsinline
|
||||
:src="getVideoSource(thisGame, versionForm.currentVersion)"
|
||||
class="background-video"
|
||||
></video>
|
||||
<div
|
||||
class="bg-white dark:bg-slate-900/90 rounded-2xl pt-6 p-3 card-content"
|
||||
>
|
||||
<div class="w-full">
|
||||
<ProfileCard
|
||||
v-if="myProfile"
|
||||
use-small
|
||||
:game="gameID"
|
||||
:profile="myProfile"
|
||||
:version="versionForm.currentVersion"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="versionForm.currentVersion && myProfile">
|
||||
<CardBox is-form>
|
||||
<form @submit.prevent="updateProfile()">
|
||||
|
||||
@@ -1,15 +1,10 @@
|
||||
<script setup>
|
||||
import { reactive, ref, onMounted, watch } from "vue";
|
||||
import { useRoute, useRouter } from "vue-router";
|
||||
import {
|
||||
mdiAccountMultiple,
|
||||
mdiPlaylistMusicOutline,
|
||||
mdiFormatListText,
|
||||
} from "@mdi/js";
|
||||
import { mdiAccountMultiple } from "@mdi/js";
|
||||
import SectionMain from "@/components/SectionMain.vue";
|
||||
import BaseButton from "@/components/BaseButton.vue";
|
||||
import GameHeader from "@/components/Cards/GameHeader.vue";
|
||||
import SectionTitleLine from "@/components/SectionTitleLine.vue";
|
||||
import GameTitleLine from "@/components/GameTitleLine.vue";
|
||||
import LayoutAuthenticated from "@/layouts/LayoutAuthenticated.vue";
|
||||
import CardBox from "@/components/CardBox.vue";
|
||||
import FormControl from "@/components/FormControl.vue";
|
||||
@@ -18,7 +13,6 @@ import GeneralTable from "@/components/GeneralTable.vue";
|
||||
|
||||
import { APIGetProfile, APIGetAllProfiles } from "@/stores/api/profile";
|
||||
import { getGameInfo } from "@/constants";
|
||||
import { getVideoSource, getCardStyle } from "@/constants/sources";
|
||||
import { dashCode } from "@/constants/userData";
|
||||
import { getIIDXDan } from "@/constants/danClass";
|
||||
|
||||
@@ -158,68 +152,32 @@ const navigateToProfile = (item) => {
|
||||
<template>
|
||||
<LayoutAuthenticated>
|
||||
<SectionMain>
|
||||
<div
|
||||
:style="getCardStyle(thisGame, versionForm.currentVersion)"
|
||||
class="rounded-2xl mb-6 card-container"
|
||||
>
|
||||
<video
|
||||
autoplay
|
||||
muted
|
||||
loop
|
||||
playsinline
|
||||
:src="getVideoSource(thisGame, versionForm.currentVersion)"
|
||||
class="background-video"
|
||||
></video>
|
||||
<GameHeader :game="thisGame" :version="versionForm.currentVersion">
|
||||
<div
|
||||
class="bg-white dark:bg-slate-900/90 rounded-2xl pt-6 p-3 card-content"
|
||||
v-if="thisGame.versions && myProfile"
|
||||
class="w-full md:flex md:-mt-[75px] mb-4 place-content-end"
|
||||
>
|
||||
<div class="w-full">
|
||||
<div
|
||||
class="md:flex md:px-5 md:space-x-10 md:justify-between md:items-center"
|
||||
>
|
||||
<GameTitleLine :path="thisGame.icon" :title="thisGame.name" />
|
||||
<div
|
||||
v-if="thisGame.versions && myProfile"
|
||||
class="md:w-1/3 md:text-right"
|
||||
>
|
||||
<h2 class="text-md sm:text-lg md:text-xl font-bold p-2">
|
||||
Select Version
|
||||
</h2>
|
||||
<FormControl
|
||||
v-model="versionForm.currentVersion"
|
||||
:options="filterVersions(myProfile.versions)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="myProfile" class="w-full pt-6 pb-10">
|
||||
<ProfileCard
|
||||
:game="gameID"
|
||||
:version="versionForm.currentVersion"
|
||||
:profile="myProfile"
|
||||
>
|
||||
</ProfileCard>
|
||||
</div>
|
||||
<div v-else class="md:w-1/2 grid grid-cols-1 md:grid-cols-2 gap-3">
|
||||
<BaseButton
|
||||
v-if="!thisGame.noScores"
|
||||
:href="`/#/games/${gameID}/scores`"
|
||||
:icon="mdiPlaylistMusicOutline"
|
||||
:outline="false"
|
||||
color="info"
|
||||
label="Network Scores"
|
||||
/>
|
||||
<BaseButton
|
||||
v-if="!thisGame.noRecords"
|
||||
:href="`/#/games/${gameID}/records`"
|
||||
:icon="mdiFormatListText"
|
||||
:outline="false"
|
||||
color="info"
|
||||
label="Network Records"
|
||||
<div class="md:w-1/3 md:text-right">
|
||||
<h2 class="text-md sm:text-lg md:text-xl font-bold p-2">
|
||||
Select Version
|
||||
</h2>
|
||||
<FormControl
|
||||
v-model="versionForm.currentVersion"
|
||||
:options="filterVersions(myProfile.versions)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="myProfile" class="w-full">
|
||||
<ProfileCard
|
||||
:game="gameID"
|
||||
:version="versionForm.currentVersion"
|
||||
:profile="myProfile"
|
||||
use-small
|
||||
>
|
||||
</ProfileCard>
|
||||
</div>
|
||||
</GameHeader>
|
||||
|
||||
<SectionTitleLine :icon="mdiAccountMultiple" title="All Players" main />
|
||||
<CardBox has-table>
|
||||
|
||||
@@ -8,7 +8,7 @@ import LayoutAuthenticated from "@/layouts/LayoutAuthenticated.vue";
|
||||
import SectionTitleLine from "@/components/SectionTitleLine.vue";
|
||||
import GeneralTable from "@/components/GeneralTable.vue";
|
||||
import CardBox from "@/components/CardBox.vue";
|
||||
import BaseButton from "@/components/BaseButton.vue";
|
||||
import GameHeader from "@/components/Cards/GameHeader.vue";
|
||||
import { getGameInfo } from "@/constants";
|
||||
|
||||
const $route = useRoute();
|
||||
@@ -148,6 +148,8 @@ function formatScores(scores) {
|
||||
<template>
|
||||
<LayoutAuthenticated>
|
||||
<SectionMain>
|
||||
<GameHeader :game="thisGame" />
|
||||
|
||||
<SectionTitleLine
|
||||
:icon="mdiCounter"
|
||||
:title="`All ${
|
||||
@@ -156,19 +158,6 @@ function formatScores(scores) {
|
||||
main
|
||||
/>
|
||||
|
||||
<div
|
||||
class="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-4 2xl:grid-cols-5 gap-3 pb-6"
|
||||
>
|
||||
<BaseButton
|
||||
:icon="mdiHome"
|
||||
:href="`/#/games/${gameID}`"
|
||||
color="info"
|
||||
:label="`${
|
||||
thisGame.shortName ? thisGame.shortName : thisGame.name
|
||||
} Home`"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<CardBox has-table>
|
||||
<GeneralTable :headers="headers" :items="scores" />
|
||||
</CardBox>
|
||||
|
||||
@@ -2,13 +2,14 @@
|
||||
import { ref, onMounted } from "vue";
|
||||
import { useRoute, useRouter } from "vue-router";
|
||||
import { useMainStore } from "@/stores/main";
|
||||
import { mdiCounter, mdiBackburger, mdiHome } from "@mdi/js";
|
||||
import { mdiCounter, mdiAccountDetails } from "@mdi/js";
|
||||
import SectionMain from "@/components/SectionMain.vue";
|
||||
import LayoutAuthenticated from "@/layouts/LayoutAuthenticated.vue";
|
||||
import SectionTitleLine from "@/components/SectionTitleLine.vue";
|
||||
import BaseButton from "@/components/BaseButton.vue";
|
||||
import GeneralTable from "@/components/GeneralTable.vue";
|
||||
import CardBox from "@/components/CardBox.vue";
|
||||
import BaseButton from "@/components/BaseButton.vue";
|
||||
import GameHeader from "@/components/Cards/GameHeader.vue";
|
||||
|
||||
import { APIGetProfile } from "@/stores/api/profile";
|
||||
import { getGameInfo } from "@/constants";
|
||||
@@ -175,32 +176,22 @@ function formatScores(scores) {
|
||||
<LayoutAuthenticated>
|
||||
<SectionMain>
|
||||
<template v-if="myProfile">
|
||||
<GameHeader :game="thisGame" :profile="myProfile" />
|
||||
<SectionTitleLine
|
||||
:icon="mdiCounter"
|
||||
:title="`${myProfile.username}'s ${
|
||||
thisGame.shortName ? thisGame.shortName : thisGame.name
|
||||
} Scores`"
|
||||
main
|
||||
/>
|
||||
<div
|
||||
class="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-4 2xl:grid-cols-5 gap-3 pb-6"
|
||||
>
|
||||
<BaseButton
|
||||
:icon="mdiBackburger"
|
||||
:href="`/#/games/${gameID}/profiles/${myProfile.userId}`"
|
||||
:icon="mdiAccountDetails"
|
||||
:href="`/#/games/${thisGame.id}/profiles/${myProfile.userId}`"
|
||||
:outline="false"
|
||||
color="info"
|
||||
:label="`${myProfile.username}'s Profile`"
|
||||
/>
|
||||
|
||||
<BaseButton
|
||||
:icon="mdiHome"
|
||||
:href="`/#/games/${gameID}`"
|
||||
color="info"
|
||||
:label="`${
|
||||
thisGame.shortName ? thisGame.shortName : thisGame.name
|
||||
} Home`"
|
||||
/>
|
||||
</div>
|
||||
</SectionTitleLine>
|
||||
|
||||
<CardBox has-table>
|
||||
<GeneralTable :headers="headers" :items="scores" />
|
||||
|
||||
@@ -3,7 +3,6 @@ import { reactive, ref, onMounted, watch } from "vue";
|
||||
import { useRoute, useRouter } from "vue-router";
|
||||
import {
|
||||
mdiAccountOutline,
|
||||
mdiBackburger,
|
||||
mdiPlaylistMusicOutline,
|
||||
mdiFormatListText,
|
||||
mdiChartBarStacked,
|
||||
@@ -16,6 +15,7 @@ import SectionMain from "@/components/SectionMain.vue";
|
||||
import CardBoxWidget from "@/components/CardBoxWidget.vue";
|
||||
import CardBox from "@/components/CardBox.vue";
|
||||
import BaseButton from "@/components/BaseButton.vue";
|
||||
import GameHeader from "@/components/Cards/GameHeader.vue";
|
||||
import ProfileCard from "@/components/Cards/ProfileCard.vue";
|
||||
import LayoutAuthenticated from "@/layouts/LayoutAuthenticated.vue";
|
||||
import SectionTitleLine from "@/components/SectionTitleLine.vue";
|
||||
@@ -358,17 +358,8 @@ async function generateTimeline(myProfile) {
|
||||
<LayoutAuthenticated>
|
||||
<template v-if="myProfile">
|
||||
<SectionMain>
|
||||
<div class="md:flex pb-6 md:justify-between md:items-center">
|
||||
<BaseButton
|
||||
:icon="mdiBackburger"
|
||||
:href="`/#/games/${gameID}`"
|
||||
class="w-full md:w-auto"
|
||||
color="info"
|
||||
:label="`${
|
||||
thisGame.shortName ? thisGame.shortName : thisGame.name
|
||||
} Home`"
|
||||
/>
|
||||
|
||||
<GameHeader :game="thisGame" />
|
||||
<SectionTitleLine :icon="mdiAccountOutline" title="View Profile" main>
|
||||
<div
|
||||
v-if="thisGame.versions && myProfile"
|
||||
class="mt-2 md:mt-0 md:w-1/3 md:text-right"
|
||||
@@ -381,8 +372,7 @@ async function generateTimeline(myProfile) {
|
||||
:options="filterVersions(myProfile.versions)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<SectionTitleLine :icon="mdiAccountOutline" title="View Profile" main />
|
||||
</SectionTitleLine>
|
||||
<div
|
||||
v-if="versionForm.currentVersion && myProfile"
|
||||
:style="getCardStyle()"
|
||||
@@ -406,7 +396,10 @@ async function generateTimeline(myProfile) {
|
||||
:version="versionForm.currentVersion"
|
||||
:profile="myProfile"
|
||||
>
|
||||
<div class="md:w-1/3 grid grid-cols-1 md:grid-cols-2 gap-3">
|
||||
<div
|
||||
v-if="!thisGame.noScores"
|
||||
class="md:w-1/3 grid grid-cols-1 md:grid-cols-2 gap-3"
|
||||
>
|
||||
<BaseButton
|
||||
:href="`/#/games/${gameID}/scores/${myProfile.userId}`"
|
||||
:icon="mdiPlaylistMusicOutline"
|
||||
|
||||
@@ -5,16 +5,15 @@ import { mdiSwordCross, mdiPlus } from "@mdi/js";
|
||||
import SectionMain from "@/components/SectionMain.vue";
|
||||
import CardBox from "@/components/CardBox.vue";
|
||||
import BaseButton from "@/components/BaseButton.vue";
|
||||
import GameHeader from "@/components/Cards/GameHeader.vue";
|
||||
import ProfileCard from "@/components/Cards/ProfileCard.vue";
|
||||
import LayoutAuthenticated from "@/layouts/LayoutAuthenticated.vue";
|
||||
import SectionTitleLine from "@/components/SectionTitleLine.vue";
|
||||
import GameTitleLine from "@/components/GameTitleLine.vue";
|
||||
import FormField from "@/components/FormField.vue";
|
||||
import FormControl from "@/components/FormControl.vue";
|
||||
import FormField from "@/components/FormField.vue";
|
||||
|
||||
import { APIGetProfile, APIGetAllProfiles } from "@/stores/api/profile";
|
||||
import { getGameInfo } from "@/constants";
|
||||
import { getVideoSource, getCardStyle } from "@/constants/sources";
|
||||
import { dashCode } from "@/constants/userData";
|
||||
|
||||
const $route = useRoute();
|
||||
@@ -113,51 +112,32 @@ function filterProfiles() {
|
||||
<template>
|
||||
<LayoutAuthenticated>
|
||||
<SectionMain>
|
||||
<div
|
||||
:style="getCardStyle(thisGame, versionForm.currentVersion)"
|
||||
class="rounded-2xl mb-6 card-container"
|
||||
>
|
||||
<video
|
||||
autoplay
|
||||
muted
|
||||
loop
|
||||
playsinline
|
||||
:src="getVideoSource(thisGame, versionForm.currentVersion)"
|
||||
class="background-video"
|
||||
></video>
|
||||
<GameHeader :game="thisGame" :version="versionForm.currentVersion">
|
||||
<div
|
||||
class="bg-white dark:bg-slate-900/90 rounded-2xl pt-6 p-3 card-content"
|
||||
v-if="thisGame.versions && profile"
|
||||
class="w-full md:flex md:-mt-[75px] mb-4 place-content-end"
|
||||
>
|
||||
<div class="w-full">
|
||||
<div
|
||||
class="md:flex md:px-5 md:space-x-10 md:justify-between md:items-center"
|
||||
>
|
||||
<GameTitleLine :path="thisGame.icon" :title="thisGame.name" />
|
||||
<div
|
||||
v-if="thisGame.versions && profile"
|
||||
class="md:w-1/3 md:text-right"
|
||||
>
|
||||
<h2 class="text-md sm:text-lg md:text-xl font-bold p-2">
|
||||
Select Version
|
||||
</h2>
|
||||
<FormControl
|
||||
v-model="versionForm.currentVersion"
|
||||
:options="filterVersions(profile.versions)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="profile" class="w-full">
|
||||
<ProfileCard
|
||||
:game="gameID"
|
||||
:version="versionForm.currentVersion"
|
||||
:profile="profile"
|
||||
use-small
|
||||
>
|
||||
</ProfileCard>
|
||||
<div class="md:w-1/3 md:text-right">
|
||||
<h2 class="text-md sm:text-lg md:text-xl font-bold p-2">
|
||||
Select Version
|
||||
</h2>
|
||||
<FormControl
|
||||
v-model="versionForm.currentVersion"
|
||||
:options="filterVersions(profile.versions)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="profile" class="w-full">
|
||||
<ProfileCard
|
||||
:game="gameID"
|
||||
:version="versionForm.currentVersion"
|
||||
:profile="profile"
|
||||
use-small
|
||||
>
|
||||
</ProfileCard>
|
||||
</div>
|
||||
</GameHeader>
|
||||
|
||||
<SectionTitleLine :icon="mdiPlus" title="Add a Rival" main />
|
||||
<CardBox v-if="versionForm.currentVersion" class="mb-6">
|
||||
|
||||
108
src/views/Game/SongView.vue
Normal file
108
src/views/Game/SongView.vue
Normal file
@@ -0,0 +1,108 @@
|
||||
<script setup>
|
||||
import { reactive } from "vue";
|
||||
import {
|
||||
mdiPlaylistMusic,
|
||||
mdiFormatListBulleted,
|
||||
mdiFormatListNumbered,
|
||||
} from "@mdi/js";
|
||||
import SectionMain from "@/components/SectionMain.vue";
|
||||
import LayoutAuthenticated from "@/layouts/LayoutAuthenticated.vue";
|
||||
import SectionTitleLine from "@/components/SectionTitleLine.vue";
|
||||
import CardBox from "@/components/CardBox.vue";
|
||||
import CardBoxWidget from "@/components/CardBoxWidget.vue";
|
||||
import GeneralTable from "@/components/GeneralTable.vue";
|
||||
import FormControl from "@/components/FormControl.vue";
|
||||
import PillTag from "@/components/PillTag.vue";
|
||||
import GameHeader from "@/components/Cards/GameHeader.vue";
|
||||
import { customStyle } from "@/constants/sources";
|
||||
|
||||
import { getGameInfo } from "@/constants";
|
||||
const game = getGameInfo("ddromni");
|
||||
|
||||
const headers = [];
|
||||
headers.push({
|
||||
text: "Player",
|
||||
value: "username",
|
||||
sortable: true,
|
||||
width: 120,
|
||||
});
|
||||
|
||||
const versionForm = reactive({
|
||||
currentVersion: 0,
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<LayoutAuthenticated>
|
||||
<SectionMain>
|
||||
<GameHeader :game="game" />
|
||||
<SectionTitleLine :icon="mdiPlaylistMusic" title="Song Overview" main />
|
||||
<CardBox
|
||||
class="mb-6"
|
||||
has-table
|
||||
:style="
|
||||
customStyle(
|
||||
`https://i.ytimg.com/vi/Y57dcTj_5RE/hqdefault.jpg?sqp=-oaymwEmCOADEOgC8quKqQMa8AEB-AH-BIAC4AOKAgwIABABGF0gZSgxMA8=&rs=AOn4CLAWbVnmUyvvmgKiVTF2OnqIdF_2Lg`
|
||||
)
|
||||
"
|
||||
>
|
||||
<div class="grid gap-4 bg-slate-900/90 card-content">
|
||||
<div>
|
||||
<h1 class="text-3xl font-bold">MY BABY MAMA</h1>
|
||||
<h2 class="text-2xl">ANQUETTE</h2>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-3 sm:flex gap-2">
|
||||
<PillTag color="success" label="SP Beginner - 5" />
|
||||
<PillTag color="info" label="SP Difficult - 6" />
|
||||
<PillTag color="warning" label="SP Expert - 9" />
|
||||
</div>
|
||||
</div>
|
||||
</CardBox>
|
||||
|
||||
<SectionTitleLine
|
||||
:icon="mdiFormatListNumbered"
|
||||
title="Top Records"
|
||||
main
|
||||
/>
|
||||
<div class="grid grid-cols-2 lg:grid-cols-5 gap-4 mb-6">
|
||||
<CardBoxWidget label="SP Beginner" small-content
|
||||
>Unclaimed</CardBoxWidget
|
||||
>
|
||||
<CardBoxWidget label="SP Difficult" small-content
|
||||
>SIRO - 877,010</CardBoxWidget
|
||||
>
|
||||
<CardBoxWidget label="SP Expert" small-content
|
||||
>CHRS4LFE - 1,000,000 MFC</CardBoxWidget
|
||||
>
|
||||
</div>
|
||||
|
||||
<div class="flex place-content-between mb-2">
|
||||
<SectionTitleLine
|
||||
:icon="mdiFormatListBulleted"
|
||||
title="All Scores"
|
||||
main
|
||||
/>
|
||||
<div class="md:w-1/3 md:text-right">
|
||||
<h2 class="text-md sm:text-lg md:text-xl font-bold p-2">
|
||||
Select Chart
|
||||
</h2>
|
||||
<FormControl
|
||||
v-model="versionForm.currentVersion"
|
||||
:options="[{ id: 0, label: 'SP Beginner - 5' }]"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<CardBox has-table>
|
||||
<div
|
||||
class="bg-white dark:bg-slate-900/95 rounded-2xl lg:flex lg:justify-between"
|
||||
>
|
||||
<div class="w-full">
|
||||
<GeneralTable :headers="headers" :items="[]" />
|
||||
</div>
|
||||
</div>
|
||||
</CardBox>
|
||||
</SectionMain>
|
||||
</LayoutAuthenticated>
|
||||
</template>
|
||||
Reference in New Issue
Block a user