centralize routes

This commit is contained in:
Georges-Antoine Assi
2025-08-25 13:25:34 -04:00
parent 940a4e766c
commit 3075ffeab4
9 changed files with 72 additions and 58 deletions

View File

@@ -100,7 +100,7 @@ start_bin_gunicorn() {
opentelemetry-instrument \
--service_name "${OTEL_SERVICE_NAME_PREFIX-}api" \
gunicorn \
--bind=0.0.0.0:5000 \
--bind=0.0.0.0:"${DEV_PORT:-5000}" \
--bind=unix:/tmp/gunicorn.sock \
--pid=/tmp/gunicorn.pid \
--forwarded-allow-ips="*" \

View File

@@ -1,47 +1,22 @@
<template>
<div class="min-h-screen text-white console-root relative">
<!-- Shield overlay to neutralize mouse input while hidden; movement wakes it -->
<div
v-if="mouseHidden"
class="fixed inset-0 z-50 cursor-none"
aria-hidden="true"
@mousemove="onMouseActivity"
@pointermove="onMouseActivity"
@mousedown.prevent
@mouseup.prevent
@click.prevent
@pointerdown.prevent
@pointerup.prevent
@wheel.prevent
@contextmenu.prevent
@dragstart.prevent
/>
<router-view v-slot="{ Component, route }">
<transition :name="getTransitionName(route)" mode="out-in" appear>
<component :is="Component" :key="route.path" />
</transition>
</router-view>
</div>
</template>
<script setup lang="ts">
import { onMounted, onUnmounted, provide, ref, watch } from "vue";
import { useRoute, type RouteLocationNormalized } from "vue-router";
import "./index.css";
import { InputBus, InputBusSymbol } from "@/console/input/bus";
import { attachKeyboard } from "@/console/input/keyboard";
import { attachGamepad } from "@/console/input/gamepad";
import { ROUTES } from "@/plugins/router";
const currentRoute = useRoute();
const route = useRoute();
const bus = new InputBus();
provide(InputBusSymbol, bus);
// Define route hierarchy for transition direction logic
const routeHierarchy = {
"console-home": 0,
"console-platform": 1,
"console-collection": 1,
"console-rom": 2,
"console-play": 3,
[ROUTES.CONSOLE_HOME]: 0,
[ROUTES.CONSOLE_PLATFORM]: 1,
[ROUTES.CONSOLE_COLLECTION]: 1,
[ROUTES.CONSOLE_ROM]: 2,
[ROUTES.CONSOLE_PLAY]: 3,
};
let previousRoute: string | null = null;
@@ -56,7 +31,10 @@ function getTransitionName(route: RouteLocationNormalized): string {
: 0;
// Special case for play mode (slide up/down)
if (currentName === "console-play" || previousRoute === "console-play") {
if (
currentName === ROUTES.CONSOLE_PLAY ||
previousRoute === ROUTES.CONSOLE_PLAY
) {
return currentLevel > previousLevel ? "slide-up" : "slide-down";
}
@@ -72,7 +50,7 @@ function getTransitionName(route: RouteLocationNormalized): string {
// Track route changes for transition direction
watch(
() => currentRoute.name,
() => route.name,
(newName, oldName) => {
if (oldName) {
previousRoute = oldName as string;
@@ -127,6 +105,33 @@ onUnmounted(() => {
window.clearTimeout(idleTimer);
});
</script>
<template>
<div class="min-h-screen text-white console-root relative">
<!-- Shield overlay to neutralize mouse input while hidden; movement wakes it -->
<div
v-if="mouseHidden"
class="fixed inset-0 z-50 cursor-none"
aria-hidden="true"
@mousemove="onMouseActivity"
@pointermove="onMouseActivity"
@mousedown.prevent
@mouseup.prevent
@click.prevent
@pointerdown.prevent
@pointerup.prevent
@wheel.prevent
@contextmenu.prevent
@dragstart.prevent
/>
<router-view v-slot="{ Component, route }">
<transition :name="getTransitionName(route)" mode="out-in" appear>
<component :is="Component" :key="route.path" />
</transition>
</router-view>
</div>
</template>
<style>
body.console-mode.mouse-hidden,
body.console-mode.mouse-hidden * {

View File

@@ -423,6 +423,7 @@ import NavigationHint from "@/console/components/NavigationHint.vue";
import { useInputScope } from "@/console/composables/useInputScope";
import type { InputAction } from "@/console/input/actions";
import { getCoreForPlatform } from "@/console/constants/cores";
import { ROUTES } from "@/plugins/router";
const route = useRoute();
const router = useRouter();
@@ -500,16 +501,20 @@ function openDetails() {
function goBackToPlatform() {
const qp = route.query as Record<string, string | undefined>;
if (qp.collection) {
router.push({ name: "console-collection", params: { id: qp.collection } });
router.push({
name: ROUTES.CONSOLE_COLLECTION,
params: { id: qp.collection },
});
return;
}
if (rom.value?.platform_id) {
router.push({
name: "console-platform",
name: ROUTES.CONSOLE_PLATFORM,
params: { id: rom.value.platform_id },
});
} else {
router.push({ name: "console-home" });
router.push({ name: ROUTES.CONSOLE_HOME });
}
}
@@ -728,7 +733,7 @@ function play() {
query.collection = Number(origin.collection);
}
router.push({
name: "console-play",
name: ROUTES.CONSOLE_PLAY,
params: { rom: romId },
query: Object.keys(query).length ? query : undefined,
});

View File

@@ -79,13 +79,14 @@ import { useRovingDom } from "@/console/composables/useRovingDom";
import { useConsoleNavStore } from "@/stores/consoleNav";
import useFavoriteToggle from "@/composables/useFavoriteToggle";
import type { SimpleRom } from "@/stores/roms";
import { ROUTES } from "@/plugins/router";
const route = useRoute();
const router = useRouter();
const navStore = useConsoleNavStore();
const { toggleFavorite: toggleFavoriteComposable } = useFavoriteToggle();
const isCollection = computed(() => route.name === "console-collection");
const isCollection = computed(() => route.name === ROUTES.CONSOLE_COLLECTION);
const platformId = computed(() =>
isCollection.value ? null : Number(route.params.id),
);
@@ -125,7 +126,7 @@ function persistIndex() {
function navigateBack() {
persistIndex();
router.push({ name: "console-home" });
router.push({ name: ROUTES.CONSOLE_HOME });
}
const headerTitle = computed(() => {
@@ -249,7 +250,7 @@ function handleAction(action: InputAction): boolean {
if (platformId.value != null) query.id = platformId.value;
if (isCollection.value) query.collection = collectionId.value!;
router.push({
name: "console-rom",
name: ROUTES.CONSOLE_ROM,
params: { rom: rom.id },
query: Object.keys(query).length ? query : undefined,
});
@@ -278,7 +279,7 @@ function selectAndOpen(i: number, rom: SimpleRomSchema) {
if (platformId.value != null) query.id = platformId.value;
if (isCollection.value) query.collection = collectionId.value!;
router.push({
name: "console-rom",
name: ROUTES.CONSOLE_ROM,
params: { rom: rom.id },
query: Object.keys(query).length ? query : undefined,
});

View File

@@ -196,6 +196,7 @@ import type { InputAction } from "@/console/input/actions";
import { useSpatialNav } from "@/console/composables/useSpatialNav";
import { useRovingDom } from "@/console/composables/useRovingDom";
import { useConsoleNavStore } from "@/stores/consoleNav";
import { ROUTES } from "@/plugins/router";
const router = useRouter();
const collectionsStore = storeCollections();
@@ -252,17 +253,17 @@ function toggleFullscreen() {
else document.exitFullscreen?.();
}
function goPlatform(id: number) {
router.push({ name: "console-platform", params: { id } });
router.push({ name: ROUTES.CONSOLE_PLATFORM, params: { id } });
}
function goGame(g: SimpleRomSchema) {
router.push({
name: "console-rom",
name: ROUTES.CONSOLE_ROM,
params: { rom: g.id },
query: { id: g.platform_id },
});
}
function goCollection(id: number) {
router.push({ name: "console-collection", params: { id } });
router.push({ name: ROUTES.CONSOLE_COLLECTION, params: { id } });
}
// Accessors for legacy global arrays registered elsewhere (SystemCard/GameCard/CollectionCard components)
@@ -425,7 +426,7 @@ function handleAction(action: InputAction): boolean {
platforms.value[selectedIndex.value]
) {
router.push({
name: "console-platform",
name: ROUTES.CONSOLE_PLATFORM,
params: { id: platforms.value[selectedIndex.value].id },
});
return true;
@@ -435,7 +436,7 @@ function handleAction(action: InputAction): boolean {
recent.value[recentIndex.value]
) {
router.push({
name: "console-rom",
name: ROUTES.CONSOLE_ROM,
params: { rom: recent.value[recentIndex.value].id },
query: { id: recent.value[recentIndex.value].platform_id },
});
@@ -446,7 +447,7 @@ function handleAction(action: InputAction): boolean {
collections.value[collectionsIndex.value]
) {
router.push({
name: "console-collection",
name: ROUTES.CONSOLE_COLLECTION,
params: { id: collections.value[collectionsIndex.value].id },
});
return true;

View File

@@ -132,6 +132,7 @@ import firmwareApi from "@/services/api/firmware";
import { useInputScope } from "@/console/composables/useInputScope";
import NavigationText from "@/console/components/NavigationText.vue";
import api from "@/services/api";
import { ROUTES } from "@/plugins/router";
const route = useRoute();
const router = useRouter();
@@ -170,7 +171,7 @@ function immediateExit() {
} catch {
/* noop */
}
router.push({ name: "console-rom", params: { rom: romId } });
router.push({ name: ROUTES.CONSOLE_ROM, params: { rom: romId } });
}
function showPrompt() {

View File

@@ -18,7 +18,6 @@ async function createCollection({
collection: Partial<UpdatedCollection>;
}): Promise<{ data: Collection }> {
const formData = new FormData();
formData.append("name", collection.name || "");
formData.append("description", collection.description || "");
formData.append("url_cover", collection.url_cover || "");
@@ -98,8 +97,9 @@ async function updateCollection({
formData.append("name", collection.name || "");
formData.append("description", collection.description || "");
formData.append("url_cover", collection.url_cover || "");
formData.append("rom_ids", JSON.stringify(collection.rom_ids));
formData.append("rom_ids", JSON.stringify(collection.rom_ids || []));
if (collection.artwork) formData.append("artwork", collection.artwork);
return api.put(`/collections/${collection.id}`, formData, {
headers: {
"Content-Type": "multipart/form-data",

View File

@@ -67,8 +67,11 @@ export default defineStore("collections", {
.getCollections()
.then(({ data: collections }) => {
this.allCollections = collections;
// Set the favorite collection
const fav = collections.find((c) => c.is_favorite);
if (fav) this.favoriteCollection = fav;
resolve(collections);
})
.catch((error) => {

View File

@@ -1,16 +1,14 @@
import { defineStore } from "pinia";
export type NavigationMode = "systems" | "recent" | "collections" | "controls";
export const useConsoleNavStore = defineStore("consoleNav", {
state: () => ({
platformIndex: 0,
recentIndex: 0,
collectionsIndex: 0,
controlIndex: 0,
navigationMode: "systems" as
| "systems"
| "recent"
| "collections"
| "controls",
navigationMode: "systems" as NavigationMode,
perPlatformGameIndex: {} as Record<number, number>,
perCollectionGameIndex: {} as Record<number, number>,
perPlatformScrollTop: {} as Record<number, number>,
@@ -22,7 +20,7 @@ export const useConsoleNavStore = defineStore("consoleNav", {
recentIndex?: number;
collectionsIndex?: number;
controlIndex?: number;
navigationMode?: "systems" | "recent" | "collections" | "controls";
navigationMode?: NavigationMode;
}) {
if (payload.platformIndex !== undefined)
this.platformIndex = payload.platformIndex;