feat/frontend: add tooltips for runes
This commit is contained in:
134
frontend/components/rune/RuneIcon.vue
Normal file
134
frontend/components/rune/RuneIcon.vue
Normal file
@@ -0,0 +1,134 @@
|
||||
<script setup lang="ts">
|
||||
import { CDRAGON_BASE, mapPath } from '~/utils/cdragon'
|
||||
|
||||
import type { Perk } from '~/types/cdragon'
|
||||
|
||||
interface Props {
|
||||
perk: Perk
|
||||
size?: number
|
||||
isActive?: boolean
|
||||
isKeystone?: boolean
|
||||
class?: string
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
size: 48,
|
||||
isActive: false,
|
||||
isKeystone: false,
|
||||
class: ''
|
||||
})
|
||||
|
||||
// Tooltip state - encapsulated in this component
|
||||
const tooltipState = reactive({
|
||||
show: false,
|
||||
perk: null as Perk | null,
|
||||
x: 0,
|
||||
y: 0
|
||||
})
|
||||
|
||||
const handleMouseEnter = (event: MouseEvent) => {
|
||||
tooltipState.perk = props.perk
|
||||
|
||||
// Calculate optimal position to keep tooltip within viewport
|
||||
const tooltipWidth = 300 // Maximum width from CSS
|
||||
const padding = 10 // Minimum padding from edges
|
||||
const offset = 15 // Distance from cursor
|
||||
|
||||
// Get viewport dimensions
|
||||
const viewportWidth = window.innerWidth
|
||||
const viewportHeight = window.innerHeight
|
||||
|
||||
// Right edge detection: if we're in the right half, position to the left
|
||||
let x = event.clientX + offset
|
||||
if (event.clientX + tooltipWidth + offset > viewportWidth - padding) {
|
||||
x = event.clientX - tooltipWidth - offset
|
||||
// Clamp if still off-screen
|
||||
if (x < padding) {
|
||||
x = padding
|
||||
}
|
||||
}
|
||||
|
||||
// Bottom edge detection: if we're in the bottom half, position above
|
||||
let y = event.clientY + offset
|
||||
if (event.clientY > viewportHeight * 0.7) {
|
||||
y = event.clientY - offset - 200 // Position ~200px above
|
||||
// Clamp if too high
|
||||
if (y < padding) {
|
||||
y = padding
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure Y is within reasonable bounds
|
||||
y = Math.min(y, viewportHeight - padding)
|
||||
|
||||
tooltipState.x = x
|
||||
tooltipState.y = y
|
||||
tooltipState.show = true
|
||||
}
|
||||
|
||||
const handleMouseLeave = () => {
|
||||
tooltipState.show = false
|
||||
tooltipState.perk = null
|
||||
}
|
||||
|
||||
const perkIconPath = computed(() => CDRAGON_BASE + mapPath(props.perk.iconPath))
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="rune-icon-wrapper" @mouseleave="handleMouseLeave">
|
||||
<div
|
||||
class="rune-icon"
|
||||
:class="[
|
||||
props.class,
|
||||
{
|
||||
'rune-activated': isActive,
|
||||
'rune-keystone': isKeystone
|
||||
}
|
||||
]"
|
||||
:style="{ width: size + 'px', height: size + 'px' }"
|
||||
@mouseenter="handleMouseEnter"
|
||||
>
|
||||
<NuxtImg :src="perkIconPath" :alt="perk.name || 'Rune'" class="rune-img" />
|
||||
</div>
|
||||
|
||||
<RuneTooltip
|
||||
:show="tooltipState.show"
|
||||
:perk="tooltipState.perk"
|
||||
:x="tooltipState.x"
|
||||
:y="tooltipState.y"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.rune-icon-wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.rune-icon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 50%;
|
||||
border: 1px solid var(--color-on-surface);
|
||||
overflow: hidden;
|
||||
cursor: help;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.rune-icon.rune-keystone {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.rune-img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
filter: grayscale(1);
|
||||
}
|
||||
|
||||
.rune-icon.rune-activated .rune-img {
|
||||
filter: none;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user