feat: add material crafting recipes to Fabricator
Build and Publish Mana Loop Docker Image / build-and-publish (push) Successful in 4m25s
Build and Publish Mana Loop Docker Image / build-and-publish (push) Successful in 4m25s
This commit is contained in:
@@ -7,23 +7,19 @@ import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { ScrollArea } from '@/components/ui/scroll-area';
|
||||
import { Separator } from '@/components/ui/separator';
|
||||
import { Anvil, Hammer, Package } from 'lucide-react';
|
||||
import { Anvil, FlaskConical, Hammer, Package } from 'lucide-react';
|
||||
import { MaterialRecipeCard } from './MaterialRecipeCard';
|
||||
import {
|
||||
FABRICATOR_RECIPES,
|
||||
MATERIAL_RECIPES,
|
||||
getRecipesByManaType,
|
||||
canCraftRecipe,
|
||||
MANA_TYPE_LABELS,
|
||||
} from '@/lib/game/data/fabricator-recipes';
|
||||
import { LOOT_DROPS, LOOT_RARITY_COLORS } from '@/lib/game/data/loot-drops';
|
||||
import { useCraftingStore, useManaStore } from '@/lib/game/stores';
|
||||
import type { FabricatorRecipe } from '@/lib/game/data/fabricator-recipes';
|
||||
|
||||
const MANA_TYPE_LABELS: Record<string, string> = {
|
||||
earth: '⛰️ Earth',
|
||||
metal: '🔩 Metal',
|
||||
crystal: '💎 Crystal',
|
||||
sand: '🏜️ Sand',
|
||||
};
|
||||
|
||||
function RecipeCard({
|
||||
recipe,
|
||||
materials,
|
||||
@@ -117,12 +113,14 @@ function RecipeCard({
|
||||
|
||||
export function FabricatorSubTab() {
|
||||
const [selectedManaType, setSelectedManaType] = useState<string>('earth');
|
||||
const [activeSection, setActiveSection] = useState<'equipment' | 'materials'>('equipment');
|
||||
|
||||
const lootInventory = useCraftingStore((s) => s.lootInventory);
|
||||
const equipmentCraftingProgress = useCraftingStore((s) => s.equipmentCraftingProgress);
|
||||
const rawMana = useManaStore((s) => s.rawMana);
|
||||
const elements = useManaStore((s) => s.elements);
|
||||
const startFabricatorCrafting = useCraftingStore((s) => s.startFabricatorCrafting);
|
||||
const craftMaterial = useCraftingStore((s) => s.craftMaterial);
|
||||
const cancelEquipmentCrafting = useCraftingStore((s) => s.cancelEquipmentCrafting);
|
||||
|
||||
const availableManaTypes = useMemo(() => {
|
||||
@@ -136,33 +134,64 @@ export function FabricatorSubTab() {
|
||||
|
||||
const isCrafting = equipmentCraftingProgress !== null;
|
||||
|
||||
const materialRecipes = useMemo(() => MATERIAL_RECIPES, []);
|
||||
|
||||
const handleCraft = (recipe: FabricatorRecipe) => {
|
||||
startFabricatorCrafting(recipe.id);
|
||||
if (recipe.recipeType === 'material') {
|
||||
craftMaterial(recipe.id);
|
||||
} else {
|
||||
startFabricatorCrafting(recipe.id);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
{/* Mana type filter */}
|
||||
<div className="flex gap-2 flex-wrap">
|
||||
{availableManaTypes.map((mt) => (
|
||||
<Button
|
||||
key={mt}
|
||||
variant={selectedManaType === mt ? 'default' : 'outline'}
|
||||
size="sm"
|
||||
onClick={() => setSelectedManaType(mt)}
|
||||
>
|
||||
{MANA_TYPE_LABELS[mt] ?? mt}
|
||||
</Button>
|
||||
))}
|
||||
{/* Section toggle: Equipment vs Materials */}
|
||||
<div className="flex gap-2">
|
||||
<Button
|
||||
variant={activeSection === 'equipment' ? 'default' : 'outline'}
|
||||
size="sm"
|
||||
onClick={() => setActiveSection('equipment')}
|
||||
>
|
||||
<Hammer className="w-3 h-3 mr-1" />
|
||||
Equipment
|
||||
</Button>
|
||||
<Button
|
||||
variant={activeSection === 'materials' ? 'default' : 'outline'}
|
||||
size="sm"
|
||||
onClick={() => setActiveSection('materials')}
|
||||
>
|
||||
<FlaskConical className="w-3 h-3 mr-1" />
|
||||
Materials
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{/* Mana type filter — only for equipment */}
|
||||
{activeSection === 'equipment' && (
|
||||
<div className="flex gap-2 flex-wrap">
|
||||
{availableManaTypes.map((mt) => (
|
||||
<Button
|
||||
key={mt}
|
||||
variant={selectedManaType === mt ? 'default' : 'outline'}
|
||||
size="sm"
|
||||
onClick={() => setSelectedManaType(mt)}
|
||||
>
|
||||
{MANA_TYPE_LABELS[mt] ?? mt}
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-4">
|
||||
{/* Recipe list */}
|
||||
<Card className="bg-gray-900/80 border-gray-700">
|
||||
<CardHeader className="pb-2">
|
||||
<CardTitle className="text-amber-400 text-sm flex items-center gap-2">
|
||||
<Hammer className="w-4 h-4" />
|
||||
{MANA_TYPE_LABELS[selectedManaType] ?? selectedManaType} Recipes
|
||||
{activeSection === 'equipment' ? (
|
||||
<><Hammer className="w-4 h-4" />{MANA_TYPE_LABELS[selectedManaType] ?? selectedManaType} Recipes</>
|
||||
) : (
|
||||
<><FlaskConical className="w-4 h-4" />Material Recipes</>
|
||||
)}
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
@@ -193,23 +222,43 @@ export function FabricatorSubTab() {
|
||||
) : (
|
||||
<ScrollArea className="h-80">
|
||||
<div className="space-y-2">
|
||||
{filteredRecipes.length === 0 ? (
|
||||
<div className="text-center text-gray-400 py-4">
|
||||
<Anvil className="w-12 h-12 mx-auto mb-2 opacity-50" />
|
||||
<p>No recipes for this mana type yet.</p>
|
||||
</div>
|
||||
{activeSection === 'equipment' ? (
|
||||
filteredRecipes.length === 0 ? (
|
||||
<div className="text-center text-gray-400 py-4">
|
||||
<Anvil className="w-12 h-12 mx-auto mb-2 opacity-50" />
|
||||
<p>No recipes for this mana type yet.</p>
|
||||
</div>
|
||||
) : (
|
||||
filteredRecipes.map((recipe) => (
|
||||
<RecipeCard
|
||||
key={recipe.id}
|
||||
recipe={recipe}
|
||||
materials={lootInventory.materials}
|
||||
rawMana={rawMana}
|
||||
elementalMana={elements}
|
||||
onCraft={handleCraft}
|
||||
isCrafting={isCrafting}
|
||||
/>
|
||||
))
|
||||
)
|
||||
) : (
|
||||
filteredRecipes.map((recipe) => (
|
||||
<RecipeCard
|
||||
key={recipe.id}
|
||||
recipe={recipe}
|
||||
materials={lootInventory.materials}
|
||||
rawMana={rawMana}
|
||||
elementalMana={elements}
|
||||
onCraft={handleCraft}
|
||||
isCrafting={isCrafting}
|
||||
/>
|
||||
))
|
||||
materialRecipes.length === 0 ? (
|
||||
<div className="text-center text-gray-400 py-4">
|
||||
<FlaskConical className="w-12 h-12 mx-auto mb-2 opacity-50" />
|
||||
<p>No material recipes available.</p>
|
||||
</div>
|
||||
) : (
|
||||
materialRecipes.map((recipe) => (
|
||||
<MaterialRecipeCard
|
||||
key={recipe.id}
|
||||
recipe={recipe}
|
||||
materials={lootInventory.materials}
|
||||
rawMana={rawMana}
|
||||
elementalMana={elements}
|
||||
onCraft={handleCraft}
|
||||
/>
|
||||
))
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
</ScrollArea>
|
||||
|
||||
Reference in New Issue
Block a user