Files
buildpath/frontend/components/build/Viewer.vue

261 lines
6.1 KiB
Vue

<script setup lang="ts">
import { getCoreItems, getLateGameItems } from '~/utils/buildHelpers'
import BuildVariantSelector from '~/components/build/BuildVariantSelector.vue'
import CompactRuneSelector from '~/components/build/CompactRuneSelector.vue'
import ItemRow from '~/components/build/ItemRow.vue'
const props = defineProps<{
builds: Builds
}>()
// State
const currentlySelectedBuild = ref(0)
// Use composables for data fetching
const { itemMap } = useItemMap()
const { perks, perkStyles } = useRuneStyles()
// Use composable for builds management
const { builds } = useBuilds(toRef(props, 'builds'))
const currentBuild = computed(() => builds.value[currentlySelectedBuild.value])
// Late game items for current build
const lateGameItems = computed(() => {
if (!currentBuild.value) return []
return getLateGameItems(currentBuild.value).slice(0, 6)
})
const currentlySelectedRunes = ref(0)
// Reset selected build when variant changes
watch(
() => currentBuild,
() => {
currentlySelectedBuild.value = 0
currentlySelectedRunes.value = 0
}
)
function selectRune(index: number): void {
currentlySelectedRunes.value = index
}
function selectBuild(index: number): void {
currentlySelectedBuild.value = index
}
</script>
<template>
<div v-if="currentBuild" class="build-viewer">
<div style="display: flex">
<BuildVariantSelector
v-for="(build, i) in builds"
:key="i"
:keystone-id="build.runeKeystone"
:item-id="build.items.children[0].data"
:keystore="perks"
:item-map="itemMap"
:pickrate="build.pickrate"
:selected="currentBuild == build"
:index="i"
@select="selectBuild"
/>
</div>
<!-- Main Build Content -->
<div class="build-content">
<!-- Left Column: Summoner Spells + Runes -->
<div class="build-left-column">
<!-- Rune Page -->
<div class="rune-section">
<h3 class="section-title">Runes</h3>
<div class="rune-page-wrapper">
<RunePage
v-if="currentBuild.runes"
:primary-style-id="currentBuild.runes[currentlySelectedRunes].primaryStyle"
:secondary-style-id="currentBuild.runes[currentlySelectedRunes].secondaryStyle"
:selection-ids="currentBuild.runes[currentlySelectedRunes].selections"
/>
</div>
<!-- Compact Rune Selector -->
<CompactRuneSelector
:runes="currentBuild.runes"
:perks="perks"
:perk-styles="perkStyles"
:selected-index="currentlySelectedBuild"
@select="selectRune"
/>
</div>
</div>
<!-- Right Column: Items -->
<div class="build-right-column">
<h3 class="section-title">Items</h3>
<!-- Start/Support + Boots Container -->
<div class="item-row-group">
<!-- Start Item (root of the tree) -->
<ItemRow
v-if="currentBuild.startItems && currentBuild.startItems.length > 0"
label="Start"
:items="currentBuild.startItems"
:item-map="itemMap"
:total-count="currentBuild.count"
/>
<!-- Support Items -->
<ItemRow
v-if="currentBuild.suppItems && currentBuild.suppItems.length > 0"
label="Support"
:items="currentBuild.suppItems"
:item-map="itemMap"
:total-count="currentBuild.count"
/>
<!-- Boots (regular or rush) -->
<ItemRow
:label="currentBuild.bootsFirst > 0.5 ? 'Boots Rush' : 'Boots'"
:items="currentBuild.boots.slice(0, 2)"
:item-map="itemMap"
:total-count="currentBuild.count"
:max-items="2"
/>
</div>
<!-- Core Items Tree (children of start item) -->
<div v-if="currentBuild.items?.children?.length" class="item-row">
<span class="item-row-label">Core</span>
<ItemTree :tree="getCoreItems(currentBuild)" />
</div>
<!-- Late Game -->
<ItemRow
v-if="lateGameItems.length > 0"
label="Late Game"
:items="lateGameItems"
:item-map="itemMap"
:total-count="currentBuild.count"
:max-items="6"
/>
</div>
</div>
</div>
</template>
<style>
.build-viewer {
width: 100%;
max-width: 1100px;
margin: 0 auto;
display: flex;
flex-direction: column;
align-items: center;
}
/* Main Build Content */
.build-content {
display: flex;
justify-content: center;
gap: 80px;
padding: 0 24px;
width: 100%;
}
.section-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 12px;
}
.section-title {
font-size: 1rem;
font-weight: 600;
margin-bottom: 10px;
color: #4a9eff;
text-transform: uppercase;
letter-spacing: 0.5px;
}
/* Left Column: Runes + Summoner Spells */
.build-left-column {
display: flex;
flex-direction: column;
gap: 40px;
}
.rune-section {
display: flex;
flex-direction: column;
}
.rune-page-wrapper {
margin-top: -45px;
transform: scale(0.7);
transform-origin: center;
}
/* Right Column: Items */
.build-right-column {
display: flex;
flex-direction: column;
gap: 20px;
}
.item-row-group {
display: flex;
flex-wrap: wrap;
gap: 24px;
align-items: flex-start;
}
.item-row {
display: flex;
flex-direction: column;
gap: 4px;
}
.item-row-label {
font-size: 0.8rem;
font-weight: 500;
color: var(--color-on-surface);
opacity: 0.6;
text-transform: uppercase;
letter-spacing: 0.5px;
}
/* Responsive: Mobile */
@media only screen and (max-width: 900px) {
.build-content {
flex-direction: column;
gap: 40px;
align-items: center;
}
.build-left-column {
order: 1;
align-items: center;
}
.build-right-column {
order: 2;
align-items: center;
}
.section-title {
font-size: 0.9rem;
}
.rune-section,
.summoner-spells-section {
align-items: center;
}
.rune-page-wrapper {
transform: scale(1);
transform-origin: center center;
margin-top: 0px;
}
}
</style>