92 lines
3.1 KiB
Vue
92 lines
3.1 KiB
Vue
<template>
|
|
<div class="min-h-screen bg-gray-950 text-gray-100">
|
|
<AppHeader :total-recipes="ALL_RECIPES.length" />
|
|
|
|
<!-- Page tabs -->
|
|
<div class="flex gap-0 px-6 border-b border-gray-800 bg-gray-900/80">
|
|
<button v-for="page in PAGES" :key="page.id"
|
|
class="px-5 py-3 text-sm font-medium transition-colors border-b-2 -mb-px" :class="currentPage === page.id
|
|
? 'text-amber-400 border-amber-400'
|
|
: 'text-gray-500 border-transparent hover:text-gray-300'" @click="currentPage = page.id">
|
|
{{ page.label }}
|
|
<span v-if="page.id === 'production' && orderCount > 0"
|
|
class="ml-1.5 inline-flex items-center justify-center w-4 h-4 rounded-full bg-amber-600 text-amber-100 text-[10px] font-bold">{{
|
|
orderCount }}</span>
|
|
</button>
|
|
</div>
|
|
|
|
<!-- Calculator page -->
|
|
<div v-if="currentPage === 'calculator'" class="p-6 space-y-4">
|
|
<FilterBar :filters="filters" :result-count="profitResults.length" @set-name-filter="setNameFilter"
|
|
@set-city="setCity" @toggle-tier="toggleTier" @set-selected-item-types="setSelectedItemTypes"
|
|
@toggle-enchantment="toggleEnchantment" @reset-enchantments="resetEnchantments" @set-rrr="setRrr" />
|
|
|
|
<ProfitTable :results="profitResults" :sort-state="sortState" @sort="handleSort" />
|
|
</div>
|
|
|
|
<!-- Bill of Production page -->
|
|
<ProductionPage v-else-if="currentPage === 'production'" />
|
|
|
|
<!-- Prices page -->
|
|
<PricesPage v-else-if="currentPage === 'prices'" />
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { ref } from 'vue'
|
|
|
|
import AppHeader from './components/layout/AppHeader.vue'
|
|
import FilterBar from './components/filters/FilterBar.vue'
|
|
import ProfitTable from './components/table/ProfitTable.vue'
|
|
import PricesPage from './pages/PricesPage.vue'
|
|
import ProductionPage from './pages/ProductionPage.vue'
|
|
|
|
import { useFilters } from './composables/useFilters'
|
|
import { useCraftingProfit } from './composables/useCraftingProfit'
|
|
import { useProductionOrder } from './composables/useProductionOrder'
|
|
|
|
import { ALL_RECIPES } from './data/recipes'
|
|
import type { SortField, SortState } from './types/crafting'
|
|
|
|
// Page navigation
|
|
const { orderCount } = useProductionOrder()
|
|
|
|
const PAGES = [
|
|
{ id: 'calculator', label: 'Calculator' },
|
|
{ id: 'production', label: 'Bill of Production' },
|
|
{ id: 'prices', label: 'Prices' },
|
|
] as const
|
|
type PageId = typeof PAGES[number]['id']
|
|
const currentPage = ref<PageId>('calculator')
|
|
|
|
// Sort state
|
|
const sortState = ref<SortState>({ field: 'materialCost', direction: 'asc' })
|
|
|
|
// Filters
|
|
const {
|
|
filters,
|
|
setCity,
|
|
toggleTier,
|
|
setSelectedItemTypes,
|
|
setRrr,
|
|
setNameFilter,
|
|
toggleEnchantment,
|
|
resetEnchantments,
|
|
} = useFilters()
|
|
|
|
// Profit calculation
|
|
const { profitResults } = useCraftingProfit(ALL_RECIPES, filters, sortState)
|
|
|
|
// Sort handler
|
|
function handleSort(field: SortField) {
|
|
if (sortState.value.field === field) {
|
|
sortState.value = {
|
|
field,
|
|
direction: sortState.value.direction === 'asc' ? 'desc' : 'asc',
|
|
}
|
|
} else {
|
|
sortState.value = { field, direction: 'asc' }
|
|
}
|
|
}
|
|
</script>
|