feat: add embed for place game
This commit is contained in:
@@ -1,11 +1,16 @@
|
||||
<script setup lang="ts">
|
||||
import { onMounted } from "vue";
|
||||
import { RouterView } from "vue-router";
|
||||
import { computed, onMounted } from "vue";
|
||||
import { RouterView, useRoute } from "vue-router";
|
||||
import AppHeader from "@/layout/AppHeader.vue";
|
||||
import AppFooter from "@/layout/AppFooter.vue";
|
||||
import { useUserStore } from "@/stores/user";
|
||||
|
||||
const userStore = useUserStore();
|
||||
const route = useRoute();
|
||||
// Embed routes (e.g. place/embed) are meant to be dropped into an <iframe>
|
||||
// as-is - the header/footer chrome would just eat into the fixed space a
|
||||
// stream overlay or OBS browser source gives it.
|
||||
const isEmbed = computed(() => route.meta.embed === true);
|
||||
|
||||
onMounted(() => {
|
||||
userStore.loadUserData();
|
||||
@@ -14,10 +19,10 @@ onMounted(() => {
|
||||
|
||||
<template>
|
||||
<div class="min-h-screen flex flex-col">
|
||||
<AppHeader />
|
||||
<AppHeader v-if="!isEmbed" />
|
||||
<main class="flex-1 flex flex-col">
|
||||
<RouterView />
|
||||
</main>
|
||||
<AppFooter />
|
||||
<AppFooter v-if="!isEmbed" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
<script setup lang="ts">
|
||||
import { onMounted, ref } from "vue";
|
||||
import { usePlaceSocket } from "@/composables/usePlaceSocket";
|
||||
import { PALETTE } from "@/palette";
|
||||
|
||||
interface Props {
|
||||
eventPath: string;
|
||||
}
|
||||
|
||||
const props = defineProps<Props>();
|
||||
|
||||
// Read-only: fed straight into an <iframe> elsewhere (a stream overlay, a
|
||||
// README, another site), so there's no header, palette, or click handling
|
||||
// here - just the live canvas. Reachable without login (see place_embed in
|
||||
// urls.py) since an OBS browser source can't do the CAS SSO login flow.
|
||||
const canvasRef = ref<HTMLCanvasElement | null>(null);
|
||||
let ctx: CanvasRenderingContext2D | null = null;
|
||||
|
||||
function drawPixel(x: number, y: number, colorIndex: number) {
|
||||
if (!ctx) return;
|
||||
ctx.fillStyle = PALETTE[colorIndex];
|
||||
ctx.fillRect(x, y, 1, 1);
|
||||
}
|
||||
|
||||
const { connected, gridWidth, gridHeight } = usePlaceSocket(props.eventPath, drawPixel);
|
||||
|
||||
onMounted(() => {
|
||||
ctx = canvasRef.value?.getContext("2d") ?? null;
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="w-screen h-screen bg-base-200 flex items-center justify-center overflow-hidden">
|
||||
<span class="badge badge-xs absolute top-2 left-2 opacity-70"
|
||||
:class="connected ? 'badge-success' : 'badge-error'" />
|
||||
<canvas ref="canvasRef" :width="gridWidth" :height="gridHeight" :style="{
|
||||
width: 'min(100vw, 100vh)',
|
||||
aspectRatio: `${gridWidth} / ${gridHeight}`,
|
||||
imageRendering: 'pixelated',
|
||||
}" />
|
||||
</div>
|
||||
</template>
|
||||
@@ -5,6 +5,7 @@ import Market from "@/Market.vue";
|
||||
import Noita from "@/Noita.vue";
|
||||
import OpusMagnum from "@/OpusMagnum.vue";
|
||||
import Place from "@/Place.vue";
|
||||
import PlaceEmbed from "@/PlaceEmbed.vue";
|
||||
import Submissions from "@/Submissions.vue";
|
||||
import SubmissionsSelect from "@/SubmissionsSelect.vue";
|
||||
import { usePageHeaderStore } from "@/stores/pageHeader";
|
||||
@@ -16,6 +17,9 @@ declare module "vue-router" {
|
||||
// usePageHeaderStore() instead and leave this out.
|
||||
titleKey?: string;
|
||||
getBackRoute?: (route: RouteLocationNormalizedLoaded) => RouteLocationRaw;
|
||||
// Skips AppHeader/AppFooter (see App.vue) - for pages meant to be
|
||||
// dropped into an <iframe> as-is, like place/embed.
|
||||
embed?: boolean;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,6 +72,13 @@ export const router = createRouter({
|
||||
props: true,
|
||||
meta: { titleKey: "place.header", getBackRoute: eventHome },
|
||||
},
|
||||
{
|
||||
path: "/:eventPath/place/embed",
|
||||
name: "place-embed",
|
||||
component: PlaceEmbed,
|
||||
props: true,
|
||||
meta: { embed: true },
|
||||
},
|
||||
{
|
||||
path: "/:eventPath/submissions/:gamePath",
|
||||
name: "submissions-select",
|
||||
|
||||
Reference in New Issue
Block a user