159 lines
5.9 KiB
Vue
159 lines
5.9 KiB
Vue
<template>
|
|
<div class="h-full flex flex-col p-4 bg-[#1b1026] overflow-y-auto custom-scrollbar relative">
|
|
|
|
<!-- Table Background styling -->
|
|
<div class="absolute inset-0 bg-[#231533] opacity-50 pointer-events-none" />
|
|
|
|
<!-- Main Action Grid -->
|
|
<div class="flex-grow z-10">
|
|
<PixelFrame class="h-full bg-[#2b193f]">
|
|
<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">
|
|
<button
|
|
@click="handleActionClick(action.id)"
|
|
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"
|
|
>
|
|
<!-- 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>
|
|
</div>
|
|
|
|
<!-- Text Label -->
|
|
<span class="text-[10px] text-[#8f80a0] group-hover:text-white group-active:text-[#1b1026] font-bold text-center leading-tight font-mono">
|
|
{{ 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';
|
|
|
|
type EntityStats = any;
|
|
|
|
interface Props {
|
|
playerStats?: EntityStats;
|
|
}
|
|
|
|
const props = defineProps<Props>();
|
|
const emit = defineEmits(['feed', 'play', 'train', 'puzzle', 'clean', 'heal', 'openInventory', 'openGodSystem', 'openShop', 'openAdventure', 'toggleSleep', 'debugAddItems']);
|
|
|
|
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'
|
|
},
|
|
{
|
|
id: 'debug',
|
|
label: '測試',
|
|
color: '#ff00ff',
|
|
pixelPath: 'M2 2H8V3H2V2ZM2 7H8V8H2V7ZM2 3H3V7H2V3ZM7 3H8V7H7V3ZM4 4H6V6H4V4Z' // Box with dot
|
|
}
|
|
];
|
|
|
|
const displayActions = computed(() => {
|
|
const actions = [...BASE_ACTIONS];
|
|
const isSleeping = props.playerStats?.isSleeping;
|
|
|
|
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
|
|
};
|
|
|
|
// Insert sleep action before 'pray' (index 7)
|
|
actions.splice(7, 0, sleepAction);
|
|
|
|
return actions;
|
|
});
|
|
|
|
const handleActionClick = (id: string) => {
|
|
// 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');
|
|
else if (id === 'fight') emit('openAdventure');
|
|
else if (id === 'sleep' || id === 'wake') emit('toggleSleep');
|
|
else if (id === 'pray') emit('openGodSystem');
|
|
else if (id === 'shop') emit('openShop');
|
|
else if (id === 'debug') emit('debugAddItems');
|
|
};
|
|
</script>
|