469 lines
9.7 KiB
Vue
469 lines
9.7 KiB
Vue
|
|
<template>
|
|||
|
|
<div v-if="isOpen" class="inventory-modal" @click.self="close">
|
|||
|
|
<div class="inventory-container">
|
|||
|
|
<!-- 標題欄 -->
|
|||
|
|
<div class="inventory-header">
|
|||
|
|
<h3>🎒 Inventory</h3>
|
|||
|
|
<button class="close-btn" @click="close">✕</button>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<!-- 主要內容 -->
|
|||
|
|
<div class="inventory-content">
|
|||
|
|
<!-- 左側:角色裝備 -->
|
|||
|
|
<div class="equipment-panel">
|
|||
|
|
<div class="character-display">
|
|||
|
|
<div class="pet-preview"></div>
|
|||
|
|
</div>
|
|||
|
|
<div class="equipment-slots">
|
|||
|
|
<div class="equip-slot head" title="Head">
|
|||
|
|
<span class="slot-icon">🎩</span>
|
|||
|
|
</div>
|
|||
|
|
<div class="equip-slot body" title="Body">
|
|||
|
|
<span class="slot-icon">👕</span>
|
|||
|
|
</div>
|
|||
|
|
<div class="equip-slot accessory" title="Accessory">
|
|||
|
|
<span class="slot-icon">💍</span>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<!-- 快速資訊 -->
|
|||
|
|
<div class="quick-stats">
|
|||
|
|
<div class="stat-row">
|
|||
|
|
<span>💰</span>
|
|||
|
|
<span>{{ coins }}</span>
|
|||
|
|
</div>
|
|||
|
|
<div class="stat-row">
|
|||
|
|
<span>⚔️</span>
|
|||
|
|
<span>{{ attack }}</span>
|
|||
|
|
</div>
|
|||
|
|
<div class="stat-row">
|
|||
|
|
<span>🛡️</span>
|
|||
|
|
<span>{{ defense }}</span>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<!-- 右側:物品格子 -->
|
|||
|
|
<div class="items-panel">
|
|||
|
|
<!-- 分類標籤 -->
|
|||
|
|
<div class="category-tabs">
|
|||
|
|
<button
|
|||
|
|
v-for="category in categories"
|
|||
|
|
:key="category.id"
|
|||
|
|
:class="['tab', { active: activeCategory === category.id }]"
|
|||
|
|
@click="activeCategory = category.id"
|
|||
|
|
>
|
|||
|
|
{{ category.icon }} {{ category.name }}
|
|||
|
|
</button>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<!-- 物品網格 -->
|
|||
|
|
<div class="item-grid">
|
|||
|
|
<div
|
|||
|
|
v-for="i in 24"
|
|||
|
|
:key="i"
|
|||
|
|
class="item-slot"
|
|||
|
|
:class="{ filled: items[i - 1] }"
|
|||
|
|
@click="selectItem(i - 1)"
|
|||
|
|
>
|
|||
|
|
<span v-if="items[i - 1]" class="item-icon">
|
|||
|
|
{{ items[i - 1].icon }}
|
|||
|
|
</span>
|
|||
|
|
<span v-if="items[i - 1] && items[i - 1].count > 1" class="item-count">
|
|||
|
|
{{ items[i - 1].count }}
|
|||
|
|
</span>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<!-- 底部操作欄 -->
|
|||
|
|
<div class="action-bar">
|
|||
|
|
<button class="action-btn" @click="useItem">Use</button>
|
|||
|
|
<button class="action-btn" @click="dropItem">Drop</button>
|
|||
|
|
<button class="action-btn sort" @click="sortItems">Sort</button>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</template>
|
|||
|
|
|
|||
|
|
<script setup>
|
|||
|
|
import { ref } from 'vue'
|
|||
|
|
|
|||
|
|
const props = defineProps({
|
|||
|
|
isOpen: {
|
|||
|
|
type: Boolean,
|
|||
|
|
default: false
|
|||
|
|
},
|
|||
|
|
coins: {
|
|||
|
|
type: Number,
|
|||
|
|
default: 0
|
|||
|
|
},
|
|||
|
|
attack: {
|
|||
|
|
type: Number,
|
|||
|
|
default: 10
|
|||
|
|
},
|
|||
|
|
defense: {
|
|||
|
|
type: Number,
|
|||
|
|
default: 5
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
const emit = defineEmits(['close', 'use-item', 'drop-item'])
|
|||
|
|
|
|||
|
|
const activeCategory = ref('all')
|
|||
|
|
const selectedSlot = ref(null)
|
|||
|
|
|
|||
|
|
const categories = [
|
|||
|
|
{ id: 'all', name: 'All', icon: '📦' },
|
|||
|
|
{ id: 'equipment', name: 'Gear', icon: '⚔️' },
|
|||
|
|
{ id: 'consumable', name: 'Food', icon: '🍖' },
|
|||
|
|
{ id: 'material', name: 'Items', icon: '💎' }
|
|||
|
|
]
|
|||
|
|
|
|||
|
|
// 示例物品數據
|
|||
|
|
const items = ref([
|
|||
|
|
{ icon: '🍖', count: 5 },
|
|||
|
|
{ icon: '💊', count: 3 },
|
|||
|
|
{ icon: '🗡️', count: 1 },
|
|||
|
|
{ icon: '🛡️', count: 1 },
|
|||
|
|
null, null, null, null,
|
|||
|
|
{ icon: '💎', count: 10 },
|
|||
|
|
null, null, null,
|
|||
|
|
null, null, null, null,
|
|||
|
|
null, null, null, null,
|
|||
|
|
null, null, null, null
|
|||
|
|
])
|
|||
|
|
|
|||
|
|
const close = () => {
|
|||
|
|
emit('close')
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const selectItem = (index) => {
|
|||
|
|
selectedSlot.value = index
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const useItem = () => {
|
|||
|
|
if (selectedSlot.value !== null && items.value[selectedSlot.value]) {
|
|||
|
|
emit('use-item', items.value[selectedSlot.value])
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const dropItem = () => {
|
|||
|
|
if (selectedSlot.value !== null && items.value[selectedSlot.value]) {
|
|||
|
|
emit('drop-item', items.value[selectedSlot.value])
|
|||
|
|
items.value[selectedSlot.value] = null
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const sortItems = () => {
|
|||
|
|
// 簡單排序邏輯
|
|||
|
|
const nonNullItems = items.value.filter(item => item !== null)
|
|||
|
|
items.value = [...nonNullItems, ...Array(24 - nonNullItems.length).fill(null)]
|
|||
|
|
}
|
|||
|
|
</script>
|
|||
|
|
|
|||
|
|
<style scoped>
|
|||
|
|
.inventory-modal {
|
|||
|
|
position: fixed;
|
|||
|
|
top: 0;
|
|||
|
|
left: 0;
|
|||
|
|
width: 100%;
|
|||
|
|
height: 100%;
|
|||
|
|
background: rgba(0, 0, 0, 0.7);
|
|||
|
|
display: flex;
|
|||
|
|
align-items: center;
|
|||
|
|
justify-content: center;
|
|||
|
|
z-index: 1000;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.inventory-container {
|
|||
|
|
width: 90%;
|
|||
|
|
max-width: 800px;
|
|||
|
|
max-height: 90vh;
|
|||
|
|
background: var(--color-panel);
|
|||
|
|
border: 3px solid var(--color-accent);
|
|||
|
|
border-radius: 16px;
|
|||
|
|
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.8);
|
|||
|
|
overflow-y: auto;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* 手機直向 */
|
|||
|
|
@media (max-width: 480px) {
|
|||
|
|
.inventory-container {
|
|||
|
|
width: 95%;
|
|||
|
|
max-width: none;
|
|||
|
|
max-height: 95vh;
|
|||
|
|
border-radius: 12px;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* 平板 */
|
|||
|
|
@media (min-width: 481px) and (max-width: 768px) {
|
|||
|
|
.inventory-container {
|
|||
|
|
width: 92%;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.inventory-header {
|
|||
|
|
background: linear-gradient(135deg, #a29bfe 0%, #6c5ce7 100%);
|
|||
|
|
padding: 16px 20px;
|
|||
|
|
border-radius: 12px 12px 0 0;
|
|||
|
|
display: flex;
|
|||
|
|
justify-content: space-between;
|
|||
|
|
align-items: center;
|
|||
|
|
border-bottom: 3px solid #5a4a3a;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.inventory-header h3 {
|
|||
|
|
margin: 0;
|
|||
|
|
color: white;
|
|||
|
|
font-size: 18px;
|
|||
|
|
text-shadow: 2px 2px 0 rgba(0, 0, 0, 0.3);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.close-btn {
|
|||
|
|
width: 32px;
|
|||
|
|
height: 32px;
|
|||
|
|
background: rgba(255, 255, 255, 0.2);
|
|||
|
|
border: 2px solid white;
|
|||
|
|
border-radius: 8px;
|
|||
|
|
color: white;
|
|||
|
|
font-size: 18px;
|
|||
|
|
cursor: pointer;
|
|||
|
|
transition: all 0.2s;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.close-btn:hover {
|
|||
|
|
background: rgba(255, 255, 255, 0.3);
|
|||
|
|
transform: scale(1.1);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.inventory-content {
|
|||
|
|
display: grid;
|
|||
|
|
grid-template-columns: 200px 1fr;
|
|||
|
|
gap: 16px;
|
|||
|
|
padding: 16px;
|
|||
|
|
min-height: 500px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* 手機直向:垂直堆疊 */
|
|||
|
|
@media (max-width: 480px) {
|
|||
|
|
.inventory-content {
|
|||
|
|
grid-template-columns: 1fr;
|
|||
|
|
gap: 12px;
|
|||
|
|
padding: 12px;
|
|||
|
|
min-height: auto;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.equipment-panel {
|
|||
|
|
max-height: 200px;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* 手機橫向 */
|
|||
|
|
@media (max-width: 768px) and (orientation: landscape) {
|
|||
|
|
.inventory-content {
|
|||
|
|
min-height: 300px;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* 左側裝備欄 */
|
|||
|
|
.equipment-panel {
|
|||
|
|
background: rgba(255, 255, 255, 0.6);
|
|||
|
|
border: 3px solid #5a4a3a;
|
|||
|
|
border-radius: 12px;
|
|||
|
|
padding: 12px;
|
|||
|
|
display: flex;
|
|||
|
|
flex-direction: column;
|
|||
|
|
gap: 12px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.character-display {
|
|||
|
|
width: 100%;
|
|||
|
|
height: 150px;
|
|||
|
|
background: linear-gradient(135deg, #ffeaa7 0%, #fdcb6e 100%);
|
|||
|
|
border: 3px solid #5a4a3a;
|
|||
|
|
border-radius: 8px;
|
|||
|
|
display: flex;
|
|||
|
|
align-items: center;
|
|||
|
|
justify-content: center;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.pet-preview {
|
|||
|
|
width: 80px;
|
|||
|
|
height: 80px;
|
|||
|
|
background: #ff6b9d;
|
|||
|
|
border: 3px solid #5a4a3a;
|
|||
|
|
border-radius: 50%;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.equipment-slots {
|
|||
|
|
display: flex;
|
|||
|
|
flex-direction: column;
|
|||
|
|
gap: 8px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.equip-slot {
|
|||
|
|
height: 48px;
|
|||
|
|
background: rgba(255, 255, 255, 0.8);
|
|||
|
|
border: 3px solid #5a4a3a;
|
|||
|
|
border-radius: 8px;
|
|||
|
|
display: flex;
|
|||
|
|
align-items: center;
|
|||
|
|
justify-content: center;
|
|||
|
|
font-size: 24px;
|
|||
|
|
cursor: pointer;
|
|||
|
|
transition: all 0.2s;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.equip-slot:hover {
|
|||
|
|
background: #ffeaa7;
|
|||
|
|
transform: scale(1.05);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.quick-stats {
|
|||
|
|
display: flex;
|
|||
|
|
flex-direction: column;
|
|||
|
|
gap: 6px;
|
|||
|
|
padding-top: 8px;
|
|||
|
|
border-top: 2px solid #5a4a3a;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.stat-row {
|
|||
|
|
display: flex;
|
|||
|
|
justify-content: space-between;
|
|||
|
|
padding: 4px 8px;
|
|||
|
|
background: rgba(255, 255, 255, 0.5);
|
|||
|
|
border-radius: 6px;
|
|||
|
|
font-size: 14px;
|
|||
|
|
font-weight: bold;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* 右側物品欄 */
|
|||
|
|
.items-panel {
|
|||
|
|
display: flex;
|
|||
|
|
flex-direction: column;
|
|||
|
|
gap: 12px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.category-tabs {
|
|||
|
|
display: flex;
|
|||
|
|
gap: 8px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.tab {
|
|||
|
|
padding: 8px 16px;
|
|||
|
|
background: rgba(255, 255, 255, 0.6);
|
|||
|
|
border: 3px solid #5a4a3a;
|
|||
|
|
border-radius: 8px;
|
|||
|
|
font-size: 12px;
|
|||
|
|
cursor: pointer;
|
|||
|
|
transition: all 0.2s;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.tab:hover {
|
|||
|
|
background: rgba(255, 255, 255, 0.8);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.tab.active {
|
|||
|
|
background: linear-gradient(135deg, #74b9ff 0%, #a29bfe 100%);
|
|||
|
|
color: white;
|
|||
|
|
transform: translateY(-2px);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.item-grid {
|
|||
|
|
display: grid;
|
|||
|
|
grid-template-columns: repeat(6, 1fr);
|
|||
|
|
gap: 8px;
|
|||
|
|
background: var(--color-panel-light);
|
|||
|
|
border: 2px solid var(--color-border);
|
|||
|
|
border-radius: 12px;
|
|||
|
|
padding: 12px;
|
|||
|
|
flex: 1;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* 手機直向:4列 */
|
|||
|
|
@media (max-width: 480px) {
|
|||
|
|
.item-grid {
|
|||
|
|
grid-template-columns: repeat(4, 1fr);
|
|||
|
|
gap: 6px;
|
|||
|
|
padding: 8px;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* 平板:5列 */
|
|||
|
|
@media (min-width: 481px) and (max-width: 768px) {
|
|||
|
|
.item-grid {
|
|||
|
|
grid-template-columns: repeat(5, 1fr);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.item-slot {
|
|||
|
|
aspect-ratio: 1;
|
|||
|
|
background: rgba(255, 255, 255, 0.8);
|
|||
|
|
border: 3px solid #5a4a3a;
|
|||
|
|
border-radius: 8px;
|
|||
|
|
display: flex;
|
|||
|
|
align-items: center;
|
|||
|
|
justify-content: center;
|
|||
|
|
font-size: 28px;
|
|||
|
|
cursor: pointer;
|
|||
|
|
position: relative;
|
|||
|
|
transition: all 0.2s;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.item-slot:hover {
|
|||
|
|
background: #ffeaa7;
|
|||
|
|
transform: scale(1.05);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.item-slot.filled {
|
|||
|
|
background: rgba(255, 255, 255, 1);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.item-count {
|
|||
|
|
position: absolute;
|
|||
|
|
bottom: 2px;
|
|||
|
|
right: 4px;
|
|||
|
|
font-size: 10px;
|
|||
|
|
font-weight: bold;
|
|||
|
|
background: rgba(0, 0, 0, 0.6);
|
|||
|
|
color: white;
|
|||
|
|
padding: 2px 4px;
|
|||
|
|
border-radius: 4px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.action-bar {
|
|||
|
|
display: flex;
|
|||
|
|
gap: 8px;
|
|||
|
|
justify-content: flex-end;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.action-btn {
|
|||
|
|
padding: 12px 24px;
|
|||
|
|
background: linear-gradient(135deg, #55efc4 0%, #00b894 100%);
|
|||
|
|
border: 3px solid #5a4a3a;
|
|||
|
|
border-radius: 8px;
|
|||
|
|
color: white;
|
|||
|
|
font-weight: bold;
|
|||
|
|
font-size: 14px;
|
|||
|
|
cursor: pointer;
|
|||
|
|
transition: all 0.2s;
|
|||
|
|
text-shadow: 1px 1px 0 rgba(0, 0, 0, 0.3);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.action-btn:hover {
|
|||
|
|
transform: translateY(-2px);
|
|||
|
|
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.action-btn:active {
|
|||
|
|
transform: translateY(0);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.action-btn.sort {
|
|||
|
|
background: linear-gradient(135deg, #74b9ff 0%, #0984e3 100%);
|
|||
|
|
}
|
|||
|
|
</style>
|