Compare commits

...

2 Commits

Author SHA1 Message Date
8c9da868f4 frontend: lint and format 2026-02-28 13:47:46 +01:00
45fa841f80 frontend: make sidebar smaller 2026-02-28 13:44:27 +01:00
8 changed files with 51 additions and 61 deletions

View File

@@ -1,6 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import { getHighestPickrateBuildIndex, getFirstCoreItems } from '~/utils/buildHelpers' import { getHighestPickrateBuildIndex, getFirstCoreItems } from '~/utils/buildHelpers'
import { MOCK_SUMMONER_SPELLS, BOOTS_RUSH_THRESHOLD } from '~/utils/mockData' import { MOCK_SUMMONER_SPELLS } from '~/utils/mockData'
import BuildVariantSelector from '~/components/build/BuildVariantSelector.vue' import BuildVariantSelector from '~/components/build/BuildVariantSelector.vue'
import SummonerSpells from '~/components/build/SummonerSpells.vue' import SummonerSpells from '~/components/build/SummonerSpells.vue'
import CompactRuneSelector from '~/components/build/CompactRuneSelector.vue' import CompactRuneSelector from '~/components/build/CompactRuneSelector.vue'
@@ -33,7 +33,7 @@ const { builds } = useBuilds(toRef(props, 'builds'))
// Summoner spells data - use提供的 or fall back to mock // Summoner spells data - use提供的 or fall back to mock
const displaySummonerSpells = computed(() => const displaySummonerSpells = computed(() =>
(props.summonerSpells && props.summonerSpells.length > 0) props.summonerSpells && props.summonerSpells.length > 0
? props.summonerSpells ? props.summonerSpells
: MOCK_SUMMONER_SPELLS : MOCK_SUMMONER_SPELLS
) )
@@ -43,10 +43,6 @@ const firstCoreItems = computed(() => getFirstCoreItems(props.runes, builds.valu
const highestPickrateBuildIndex = computed(() => getHighestPickrateBuildIndex(props.runes)) const highestPickrateBuildIndex = computed(() => getHighestPickrateBuildIndex(props.runes))
const bootsLabel = computed(() =>
builds.value.bootsFirst > BOOTS_RUSH_THRESHOLD ? 'Boots Rush' : 'Boots'
)
// Reset selected build when runes change // Reset selected build when runes change
watch( watch(
() => props.runes, () => props.runes,

View File

@@ -39,9 +39,9 @@ if (route.path.startsWith('/tierlist/')) {
<div class="sidebar-container"> <div class="sidebar-container">
<Logo <Logo
font-size="2.6rem" font-size="2rem"
img-width="60" img-width="45"
style="padding-left: 15px; padding-right: 15px; margin-top: 30px" style="padding-left: 10px; padding-right: 10px; margin-top: 20px"
/> />
<div v-for="(lane, i) in championLanes" :key="i"> <div v-for="(lane, i) in championLanes" :key="i">
@@ -49,22 +49,22 @@ if (route.path.startsWith('/tierlist/')) {
style=" style="
display: flex; display: flex;
align-items: center; align-items: center;
margin-top: 30px; margin-top: 20px;
padding-right: 10px; padding-right: 10px;
overflow: hidden; overflow: hidden;
" "
> >
<h1 style="font-size: 2.4rem; padding-left: 20px">{{ championName }}</h1> <h1 style="font-size: 1.8rem; padding-left: 15px">{{ championName }}</h1>
<NuxtImg <NuxtImg
format="webp" format="webp"
style="margin-left: 10px" style="margin-left: 8px"
width="40" width="30"
height="40" height="30"
:src="LANE_IMAGES[lanePositionToIndex(lane.data)]" :src="LANE_IMAGES[lanePositionToIndex(lane.data)]"
/> />
<h2 <h2
v-if="championName != null && championName != undefined && championName.length < 8" v-if="championName != null && championName != undefined && championName.length < 8"
style="margin-left: 5px; font-size: 1.8rem; font-weight: 200" style="margin-left: 5px; font-size: 1.4rem; font-weight: 200"
> >
{{ POSITIONS_STR[lanePositionToIndex(lane.data.toLowerCase())] }} {{ POSITIONS_STR[lanePositionToIndex(lane.data.toLowerCase())] }}
</h2> </h2>
@@ -74,7 +74,7 @@ if (route.path.startsWith('/tierlist/')) {
:class=" :class="
'sidebar-link ' + (state == 'build' && laneState == i ? 'sidebar-link-selected' : '') 'sidebar-link ' + (state == 'build' && laneState == i ? 'sidebar-link-selected' : '')
" "
style="margin-top: 10px; font-size: 1.9rem; padding-left: 35px" style="margin-top: 8px; font-size: 1.5rem; padding-left: 25px"
@click="handleStateChange('build', i)" @click="handleStateChange('build', i)"
> >
Build Build
@@ -85,7 +85,7 @@ if (route.path.startsWith('/tierlist/')) {
'sidebar-link ' + 'sidebar-link ' +
(state == 'alternatives' && laneState == i ? 'sidebar-link-selected' : '') (state == 'alternatives' && laneState == i ? 'sidebar-link-selected' : '')
" "
style="margin-top: 10px; font-size: 1.9rem; padding-left: 35px" style="margin-top: 8px; font-size: 1.5rem; padding-left: 25px"
@click="handleStateChange('alternatives', i)" @click="handleStateChange('alternatives', i)"
> >
Alternatives Alternatives
@@ -94,15 +94,15 @@ if (route.path.startsWith('/tierlist/')) {
:class=" :class="
'sidebar-link ' + (state == 'matchups' && laneState == i ? 'sidebar-link-selected' : '') 'sidebar-link ' + (state == 'matchups' && laneState == i ? 'sidebar-link-selected' : '')
" "
style="margin-top: 10px; font-size: 1.9rem; padding-left: 35px" style="margin-top: 8px; font-size: 1.5rem; padding-left: 25px"
@click="handleStateChange('matchups', i)" @click="handleStateChange('matchups', i)"
> >
Matchups Matchups
</h2> </h2>
</div> </div>
<div v-if="tierlistList == true" style="margin-top: 30px"> <div v-if="tierlistList == true" style="margin-top: 20px">
<h2 style="padding-left: 20px; font-size: 2.4rem; margin-bottom: 10px">Tierlist</h2> <h2 style="padding-left: 15px; font-size: 1.8rem; margin-bottom: 8px">Tierlist</h2>
<NuxtLink <NuxtLink
v-for="(pos, i) in POSITIONS" v-for="(pos, i) in POSITIONS"
:key="i" :key="i"
@@ -112,16 +112,16 @@ if (route.path.startsWith('/tierlist/')) {
<div <div
:class="selected == pos ? 'sidebar-link-selected' : ''" :class="selected == pos ? 'sidebar-link-selected' : ''"
class="sidebar-link" class="sidebar-link"
style="padding-left: 35px; display: flex; align-items: center" style="padding-left: 25px; display: flex; align-items: center"
> >
<NuxtImg <NuxtImg
format="webp" format="webp"
width="40" width="30"
height="40" height="30"
:src="LANE_IMAGES[i]" :src="LANE_IMAGES[i]"
:alt="POSITIONS_STR[i]" :alt="POSITIONS_STR[i]"
/> />
<h3 style="font-size: 2.1rem; font-weight: 200; margin-left: 10px"> <h3 style="font-size: 1.6rem; font-weight: 200; margin-left: 8px">
{{ POSITIONS_STR[i] }} {{ POSITIONS_STR[i] }}
</h3> </h3>
</div> </div>
@@ -130,14 +130,14 @@ if (route.path.startsWith('/tierlist/')) {
<div style="position: absolute; bottom: 0; margin-bottom: 10px; padding-left: 10px"> <div style="position: absolute; bottom: 0; margin-bottom: 10px; padding-left: 10px">
<template v-if="stats"> <template v-if="stats">
<h3 style="font-size: 23px; font-weight: 200">Patch {{ stats.patch }}</h3> <h3 style="font-size: 18px; font-weight: 200">Patch {{ stats.patch }}</h3>
<h3 style="font-size: 23px; font-weight: 200">{{ stats.count }} games</h3> <h3 style="font-size: 18px; font-weight: 200">{{ stats.count }} games</h3>
</template> </template>
<template v-else> <template v-else>
<h3 style="font-size: 23px; font-weight: 200; opacity: 0.5">Loading stats...</h3> <h3 style="font-size: 18px; font-weight: 200; opacity: 0.5">Loading stats...</h3>
</template> </template>
<NuxtLink to="/about"><h3>About</h3></NuxtLink> <NuxtLink to="/about"><h3>About</h3></NuxtLink>
<h2 style="font-size: 12px; font-weight: 200; margin-top: 5px"> <h2 style="font-size: 10px; font-weight: 200; margin-top: 3px">
BuildPath isn't endorsed by Riot Games and doesn't reflect the views or opinions of Riot BuildPath isn't endorsed by Riot Games and doesn't reflect the views or opinions of Riot
Games or anyone officially involved in producing or managing Riot Games properties. Riot Games or anyone officially involved in producing or managing Riot Games properties. Riot
Games, and all associated properties are trademarks or registered trademarks of Riot Games, Games, and all associated properties are trademarks or registered trademarks of Riot Games,

View File

@@ -16,7 +16,7 @@ export const useBuilds = (buildsProp: Ref<Builds>) => {
// Watch for changes and rebuild // Watch for changes and rebuild
watch( watch(
() => buildsProp.value, () => buildsProp.value,
(newBuilds) => { newBuilds => {
builds.value = deepClone(newBuilds) builds.value = deepClone(newBuilds)
trimBuildData() trimBuildData()
}, },

View File

@@ -12,7 +12,7 @@ export const useItemMap = () => {
watch( watch(
items, items,
(newItems) => { newItems => {
if (Array.isArray(newItems)) { if (Array.isArray(newItems)) {
const map = new Map<number, Item>() const map = new Map<number, Item>()
for (const item of newItems) { for (const item of newItems) {

View File

@@ -2,13 +2,17 @@
* Composable for fetching and managing rune styles and keystones * Composable for fetching and managing rune styles and keystones
* Transforms rune data into format needed for display components * Transforms rune data into format needed for display components
*/ */
export const useRuneStyles = (runes: Ref<Array<{ export const useRuneStyles = (
runes: Ref<
Array<{
count: number count: number
primaryStyle: number primaryStyle: number
secondaryStyle: number secondaryStyle: number
selections: Array<number> selections: Array<number>
pickrate: number pickrate: number
}>>) => { }>
>
) => {
const primaryStyles = ref<Array<PerkStyle>>(Array(runes.value.length)) const primaryStyles = ref<Array<PerkStyle>>(Array(runes.value.length))
const secondaryStyles = ref<Array<PerkStyle>>(Array(runes.value.length)) const secondaryStyles = ref<Array<PerkStyle>>(Array(runes.value.length))
const keystoneIds = ref<Array<number>>(Array(runes.value.length)) const keystoneIds = ref<Array<number>>(Array(runes.value.length))
@@ -19,7 +23,7 @@ export const useRuneStyles = (runes: Ref<Array<{
const perks = reactive(new Map<number, Perk>()) const perks = reactive(new Map<number, Perk>())
watch( watch(
perksData, perksData,
(newPerks) => { newPerks => {
if (Array.isArray(newPerks)) { if (Array.isArray(newPerks)) {
perks.clear() perks.clear()
for (const perk of newPerks) { for (const perk of newPerks) {

View File

@@ -15,7 +15,7 @@ export const useSummonerSpellMap = () => {
watch( watch(
summonerSpellsData, summonerSpellsData,
(newData) => { newData => {
if (Array.isArray(newData)) { if (Array.isArray(newData)) {
const map = new Map<number, SummonerSpell>() const map = new Map<number, SummonerSpell>()
for (const spell of newData) { for (const spell of newData) {

View File

@@ -38,19 +38,17 @@ export function trimLateGameItems(builds: Builds): void {
collectItemIds(builds.tree) collectItemIds(builds.tree)
// Remove late game items that appear in core // Remove late game items that appear in core
builds.lateGame = builds.lateGame.filter((item) => !coreItemIds.has(item.data)) builds.lateGame = builds.lateGame.filter(item => !coreItemIds.has(item.data))
} }
/** /**
* Gets the index of the build with the highest pickrate * Gets the index of the build with the highest pickrate
*/ */
export function getHighestPickrateBuildIndex( export function getHighestPickrateBuildIndex(runes: Array<{ pickrate: number }>): number {
runes: Array<{ pickrate: number }>
): number {
if (runes.length === 0) return 0 if (runes.length === 0) return 0
return runes.reduce((maxIdx, rune, idx, arr) => return runes.reduce(
rune.pickrate > arr[maxIdx].pickrate ? idx : maxIdx, (maxIdx, rune, idx, arr) => (rune.pickrate > arr[maxIdx].pickrate ? idx : maxIdx),
0 0
) )
} }
@@ -58,10 +56,7 @@ export function getHighestPickrateBuildIndex(
/** /**
* Gets the first core item for each build variant * Gets the first core item for each build variant
*/ */
export function getFirstCoreItems( export function getFirstCoreItems(runes: unknown[], builds: Builds): number[] {
runes: unknown[],
builds: Builds
): number[] {
return runes.map(() => { return runes.map(() => {
const tree = builds?.tree const tree = builds?.tree
return tree?.children?.[0]?.data ?? tree?.data ?? 0 return tree?.children?.[0]?.data ?? tree?.data ?? 0

View File

@@ -9,8 +9,3 @@ export const MOCK_SUMMONER_SPELLS = [
{ id: 14, count: 600, pickrate: 0.15 }, // Ignite { id: 14, count: 600, pickrate: 0.15 }, // Ignite
{ id: 3, count: 200, pickrate: 0.05 } // Exhaust { id: 3, count: 200, pickrate: 0.05 } // Exhaust
] ]
/**
* Constants used throughout the application
*/
export const BOOTS_RUSH_THRESHOLD = 0.5