minecraft-clone / src /components /ui /CreativeInventory.tsx
TomatitoToho's picture
Upload src/components/ui/CreativeInventory.tsx with huggingface_hub
472ffa5 verified
Raw
History Blame Contribute Delete
5.42 kB
'use client'
import { useState, useMemo } from 'react'
import { useUIStore } from '@/stores/uiStore'
import { usePlayerStore } from '@/stores/playerStore'
import { BLOCK_DEFS, CREATIVE_BLOCKS, BLOCK_CATEGORIES } from '@/engine/constants'
const CATEGORY_TABS = [
{ key: 'all', label: 'All' },
{ key: 'Natural', label: 'Natural' },
{ key: 'Wood', label: 'Wood' },
{ key: 'Ores', label: 'Ores' },
{ key: 'Wool', label: 'Wool' },
{ key: 'Concrete', label: 'Concrete' },
{ key: 'Glass', label: 'Glass' },
{ key: 'Bricks', label: 'Bricks' },
{ key: 'Functional', label: 'Functional' },
{ key: 'Redstone', label: 'Redstone' },
{ key: 'Nether', label: 'Nether' },
{ key: 'End', label: 'End' },
{ key: 'Plants', label: 'Plants' },
{ key: 'Lights', label: 'Lights' },
{ key: 'Mineral Blocks', label: 'Minerals' },
{ key: 'Copper', label: 'Copper' },
{ key: 'Terracotta', label: 'Terracotta' },
]
export function CreativeInventory() {
const { showInventory, setShowInventory } = useUIStore()
const { player } = usePlayerStore()
const [activeTab, setActiveTab] = useState('all')
const [searchQuery, setSearchQuery] = useState('')
if (!showInventory || !player) return null
const handleSelect = (blockId: number) => {
const { hotbarSlot } = useUIStore.getState()
const newHotbar = [...player.inventory.hotbar]
newHotbar[hotbarSlot] = { id: blockId, count: 64, damage: 0 }
usePlayerStore.setState({
player: { ...player, inventory: { ...player.inventory, hotbar: newHotbar } }
})
}
// Get blocks for current tab
const displayBlocks = useMemo(() => {
let blocks: number[]
if (activeTab === 'all') {
blocks = CREATIVE_BLOCKS
} else {
blocks = BLOCK_CATEGORIES[activeTab] || []
}
// Apply search filter
if (searchQuery) {
const query = searchQuery.toLowerCase()
blocks = blocks.filter(id => {
const def = BLOCK_DEFS[id]
return def && def.name.toLowerCase().includes(query)
})
}
return blocks
}, [activeTab, searchQuery])
return (
<div className="absolute inset-0 bg-black/70 flex items-center justify-center z-50"
onClick={(e) => { if (e.target === e.currentTarget) setShowInventory(false) }}>
<div className="bg-[#1a1a2e]/95 border border-gray-600/50 rounded-lg w-full max-w-2xl mx-4 max-h-[85vh] flex flex-col backdrop-blur-sm shadow-2xl">
{/* Header */}
<div className="flex items-center justify-between p-3 border-b border-gray-700/50">
<h3 className="text-white text-lg font-bold">Creative Inventory</h3>
<button className="text-gray-400 hover:text-white text-xl px-2"
onClick={() => setShowInventory(false)}>✕</button>
</div>
{/* Search */}
<div className="px-3 pt-2">
<input
type="text"
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
placeholder="Search blocks..."
className="w-full px-3 py-1.5 bg-gray-800/80 border border-gray-600/50 rounded text-white text-sm placeholder-gray-500 focus:outline-none focus:border-blue-500"
/>
</div>
{/* Category tabs */}
<div className="flex flex-wrap gap-1 px-3 py-2 overflow-x-auto">
{CATEGORY_TABS.map(tab => (
<button
key={tab.key}
className={`px-2 py-0.5 text-xs rounded transition-colors ${
activeTab === tab.key
? 'bg-blue-600 text-white'
: 'bg-gray-700/60 text-gray-300 hover:bg-gray-600/60'
}`}
onClick={() => setActiveTab(tab.key)}
>
{tab.label}
</button>
))}
</div>
{/* Block grid */}
<div className="flex-1 overflow-y-auto p-3">
<div className="grid grid-cols-9 gap-1">
{displayBlocks.map((blockId) => {
const def = BLOCK_DEFS[blockId]
if (!def) return null
return (
<div
key={blockId}
className="w-9 h-9 sm:w-10 sm:h-10 rounded cursor-pointer border border-gray-700/50 hover:border-white/80 flex items-center justify-center transition-all duration-75 hover:scale-110 relative group"
style={{ backgroundColor: def.color + '44' }}
onClick={() => handleSelect(blockId)}
title={def.name}
>
<div className="w-6 h-6 rounded-sm shadow-inner" style={{ backgroundColor: def.color }} />
<div className="hidden group-hover:block absolute -top-8 left-1/2 -translate-x-1/2 bg-black/90 text-white text-xs px-2 py-0.5 rounded whitespace-nowrap z-10 border border-gray-600/50">
{def.name}
</div>
</div>
)
})}
</div>
{displayBlocks.length === 0 && (
<div className="text-gray-500 text-center py-8">No blocks found</div>
)}
</div>
{/* Footer */}
<div className="p-2 border-t border-gray-700/50 flex items-center justify-between">
<p className="text-gray-500 text-xs">{displayBlocks.length} blocks</p>
<p className="text-gray-600 text-xs">Click a block to add to hotbar</p>
</div>
</div>
</div>
)
}