pet_data/app/components/pixel/ActionArea.vue

159 lines
5.9 KiB
Vue
Raw Permalink Normal View History

2025-11-26 06:53:44 +00:00
<template>
2025-11-26 09:53:03 +00:00
<div class="h-full flex flex-col p-4 bg-[#1b1026] overflow-y-auto custom-scrollbar relative">
2025-11-26 06:53:44 +00:00
<!-- Table Background styling -->
<div class="absolute inset-0 bg-[#231533] opacity-50 pointer-events-none" />
2025-11-26 09:53:03 +00:00
<!-- Main Action Grid -->
<div class="flex-grow z-10">
2025-11-26 06:53:44 +00:00
<PixelFrame class="h-full bg-[#2b193f]">
2025-11-26 09:53:03 +00:00
<div class="grid grid-cols-4 sm:grid-cols-5 md:grid-cols-6 gap-2 p-2 h-full content-start overflow-y-auto custom-scrollbar">
<template v-for="(action, index) in displayActions" :key="index">
2025-11-26 06:53:44 +00:00
<button
@click="handleActionClick(action.id)"
2025-11-26 09:53:03 +00:00
class="aspect-square relative bg-[#1b1026] border-2 border-[#4a3b5e] hover:border-[#f6b26b] hover:bg-[#231533] active:bg-[#f6b26b] active:border-[#f6b26b] group flex flex-col items-center justify-center p-2 transition-colors"
2025-11-26 06:53:44 +00:00
>
2025-11-26 09:53:03 +00:00
<!-- Icon Container -->
<div class="mb-1 p-1 rounded-sm bg-[#231533] group-active:bg-[#1b1026] w-8 h-8 flex items-center justify-center flex-shrink-0">
<!-- Pixel Icon SVG -->
<svg width="100%" height="100%" viewBox="0 0 10 10" fill="none" xmlns="http://www.w3.org/2000/svg">
<path :d="action.pixelPath" :fill="action.color" class="group-active:fill-[#f6b26b]"/>
<path v-if="action.pixelPath2" :d="action.pixelPath2" :fill="action.color2 || action.color" :fill-opacity="action.opacity2 || 1" />
</svg>
2025-11-26 06:53:44 +00:00
</div>
2025-11-26 09:53:03 +00:00
<!-- Text Label -->
<span class="text-[10px] text-[#8f80a0] group-hover:text-white group-active:text-[#1b1026] font-bold text-center leading-tight font-mono">
2025-11-26 06:53:44 +00:00
{{ action.label }}
</span>
<!-- Corner deco -->
<div class="absolute top-0 right-0 w-1 h-1 bg-[#4a3b5e] group-hover:bg-[#f6b26b]" />
<div class="absolute bottom-0 left-0 w-1 h-1 bg-[#4a3b5e] group-hover:bg-[#f6b26b]" />
</button>
</template>
</div>
</PixelFrame>
</div>
</div>
</template>
<script setup lang="ts">
import { computed } from 'vue';
import PixelFrame from './PixelFrame.vue';
2025-11-26 09:53:03 +00:00
type EntityStats = any;
2025-11-26 06:53:44 +00:00
interface Props {
playerStats?: EntityStats;
}
const props = defineProps<Props>();
2025-11-26 15:31:46 +00:00
const emit = defineEmits(['feed', 'play', 'train', 'puzzle', 'clean', 'heal', 'openInventory', 'openGodSystem', 'openShop', 'openAdventure', 'toggleSleep', 'debugAddItems']);
2025-11-26 06:53:44 +00:00
2025-11-26 09:53:03 +00:00
const BASE_ACTIONS = [
{
id: 'feed',
label: '餵食',
color: '#9fd75b',
pixelPath: 'M4 1H6V3H4V1ZM3 3H7V4H3V3ZM2 4H8V8H2V4ZM3 8H7V9H3V8Z',
pixelPath2: 'M4 2H5V3H4V2ZM6 2H7V3H6V2Z', color2: '#e0d8f0', opacity2: 0.5
},
{
id: 'play',
label: '玩耍',
color: '#f6b26b',
pixelPath: 'M2 3H8V7H2V3ZM3 4H4V5H3V4ZM6 4H7V5H6V4ZM4 5H6V6H4V5Z'
},
{
id: 'train',
label: '訓練',
color: '#d75b5b',
pixelPath: 'M2 2H4V3H2V2ZM7 2H9V3H7V2ZM3 3H8V4H3V3ZM4 4H7V5H4V4ZM3 5H8V6H3V5ZM2 6H4V7H2V6ZM7 6H9V7H7V6Z'
},
{
id: 'puzzle',
label: '益智',
color: '#2ce8f4',
pixelPath: 'M4 1H6V3H4V1ZM2 3H4V4H2V3ZM6 3H8V4H6V3ZM1 4H3V6H1V4ZM7 4H9V6H7V4ZM4 6H6V7H4V6ZM4 7H6V9H4V7Z'
},
{
id: 'clean',
label: '清理',
color: '#8f80a0',
pixelPath: 'M7 1H9V3H7V1ZM6 3H8V4H6V3ZM5 4H7V5H5V4ZM4 5H6V6H4V5ZM3 6H5V7H3V6ZM2 7H4V9H2V7Z'
},
{
id: 'heal',
label: '治療',
color: '#9fd75b',
pixelPath: 'M2 4H4V5H2V4ZM6 4H8V5H6V4ZM2 5H8V6H2V5ZM3 6H7V7H3V6ZM4 2H6V3H4V2ZM4 7H6V8H4V7Z',
pixelPath2: 'M4 3H6V7H4V3ZM3 4H7V6H3V4Z', color2: '#e0d8f0'
},
{
id: 'fight',
label: '戰鬥',
color: '#d95763',
pixelPath: 'M2 2H3V3H2V2ZM3 3H4V4H3V3ZM4 4H5V5H4V4ZM5 5H6V6H5V5ZM6 6H7V7H6V6ZM7 7H8V8H7V7ZM7 2H8V3H7V2ZM6 3H7V4H6V3ZM3 6H4V7H3V6ZM2 7H3V8H2V7Z'
},
// Sleep/Wake will be inserted here dynamically
{
id: 'pray',
label: '祈福',
color: '#e0d8f0',
pixelPath: 'M4 1H6V3H4V1ZM2 3H8V4H2V3ZM1 4H9V5H1V4ZM2 5H8V9H2V5ZM4 6H6V8H4V6Z'
},
{
id: 'shop',
label: '商店',
color: '#ffa500',
pixelPath: 'M3 2H7V3H3V2ZM2 3H8V7H2V3ZM3 7H7V8H3V7ZM4 4H6V5H4V4Z'
2025-11-26 15:31:46 +00:00
},
{
id: 'debug',
label: '測試',
color: '#ff00ff',
pixelPath: 'M2 2H8V3H2V2ZM2 7H8V8H2V7ZM2 3H3V7H2V3ZM7 3H8V7H7V3ZM4 4H6V6H4V4Z' // Box with dot
2025-11-26 09:53:03 +00:00
}
2025-11-26 06:53:44 +00:00
];
2025-11-26 09:53:03 +00:00
const displayActions = computed(() => {
const actions = [...BASE_ACTIONS];
const isSleeping = props.playerStats?.isSleeping;
2025-11-26 06:53:44 +00:00
2025-11-26 09:53:03 +00:00
const sleepAction = isSleeping
? {
id: 'wake',
label: '起床',
color: '#ffe762',
pixelPath: 'M4 1H6V2H4V1ZM2 2H3V3H2V2ZM7 2H8V3H7V2ZM1 4H2V6H1V4ZM8 4H9V6H8V4ZM2 7H3V8H2V7ZM7 7H8V8H7V7ZM4 8H6V9H4V8ZM4 3H6V7H4V3ZM3 4H7V6H3V4Z' // Sun
}
: {
id: 'sleep',
label: '睡覺',
color: '#2ce8f4',
pixelPath: 'M3 2H6V3H3V2ZM2 3H5V4H2V3ZM2 4H4V6H2V4ZM3 6H6V7H3V6ZM5 7H8V8H5V7ZM6 3H8V6H6V3ZM6 2H8V3H6V2Z' // Moon/Zzz
};
2025-11-26 06:53:44 +00:00
2025-11-26 09:53:03 +00:00
// Insert sleep action before 'pray' (index 7)
actions.splice(7, 0, sleepAction);
return actions;
2025-11-26 06:53:44 +00:00
});
const handleActionClick = (id: string) => {
2025-11-26 09:53:03 +00:00
// Emit specific events for each action type
if (id === 'feed') emit('feed');
else if (id === 'play') emit('play');
else if (id === 'train') emit('train');
else if (id === 'puzzle') emit('puzzle');
else if (id === 'clean') emit('clean');
else if (id === 'heal') emit('heal');
2025-11-26 06:53:44 +00:00
else if (id === 'fight') emit('openAdventure');
2025-11-26 09:53:03 +00:00
else if (id === 'sleep' || id === 'wake') emit('toggleSleep');
else if (id === 'pray') emit('openGodSystem');
else if (id === 'shop') emit('openShop');
2025-11-26 15:31:46 +00:00
else if (id === 'debug') emit('debugAddItems');
2025-11-26 06:53:44 +00:00
};
</script>