From 9246935fd779cf6be342e610ebb8c9fdc459c9e4 Mon Sep 17 00:00:00 2001 From: pyr0ball Date: Mon, 13 Apr 2026 12:30:48 -0700 Subject: [PATCH] feat: Hall of Chaos easter egg -- HallOfChaosView + long-press trigger Adds the Hall of Chaos overlay component (recipe blooper gallery with static CSS tilts, chaos level counter, panel-local overlay) and wires the 800ms long-press trigger on the Bloopers filter tab in CommunityFeedPanel. Pairs with the backend /community/hall-of-chaos endpoint and test added in Task 10. --- .../src/components/CommunityFeedPanel.vue | 26 +++ frontend/src/components/HallOfChaosView.vue | 182 ++++++++++++++++++ 2 files changed, 208 insertions(+) create mode 100644 frontend/src/components/HallOfChaosView.vue diff --git a/frontend/src/components/CommunityFeedPanel.vue b/frontend/src/components/CommunityFeedPanel.vue index 4b9db11..e3c53b1 100644 --- a/frontend/src/components/CommunityFeedPanel.vue +++ b/frontend/src/components/CommunityFeedPanel.vue @@ -12,6 +12,9 @@ :class="['btn', 'tab-btn', activeFilter === f.id ? 'btn-primary' : 'btn-secondary']" @click="setFilter(f.id)" @keydown="onFilterKeydown" + @pointerdown="f.id === 'recipe_blooper' ? onBlooperPointerDown($event) : undefined" + @pointerup="f.id === 'recipe_blooper' ? onBlooperPointerCancel() : undefined" + @pointerleave="f.id === 'recipe_blooper' ? onBlooperPointerCancel() : undefined" >{{ f.label }} @@ -103,6 +106,12 @@ @published="onPlanPublished" /> + + + @@ -111,6 +120,7 @@ import { ref, onMounted } from 'vue' import { useCommunityStore } from '../stores/community' import CommunityPostCard from './CommunityPostCard.vue' import PublishPlanModal from './PublishPlanModal.vue' +import HallOfChaosView from './HallOfChaosView.vue' const emit = defineEmits<{ 'plan-forked': [payload: { plan_id: number; week_start: string }] @@ -120,6 +130,22 @@ const store = useCommunityStore() const activeFilter = ref('all') const showPublishPlan = ref(false) +const showHallOfChaos = ref(false) +let blooperHoldTimer: ReturnType | null = null + +function onBlooperPointerDown(_e: PointerEvent) { + blooperHoldTimer = setTimeout(() => { + showHallOfChaos.value = true + blooperHoldTimer = null + }, 800) +} + +function onBlooperPointerCancel() { + if (blooperHoldTimer !== null) { + clearTimeout(blooperHoldTimer) + blooperHoldTimer = null + } +} const filters = [ { id: 'all', label: 'All' }, diff --git a/frontend/src/components/HallOfChaosView.vue b/frontend/src/components/HallOfChaosView.vue new file mode 100644 index 0000000..087d417 --- /dev/null +++ b/frontend/src/components/HallOfChaosView.vue @@ -0,0 +1,182 @@ + + + + +