feat/frontend: add tooltips for runes
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { CDRAGON_BASE, mapPath } from '~/utils/cdragon'
|
||||||
import type { PerkStyle, Perk } from '~/types/cdragon'
|
import type { PerkStyle, Perk } from '~/types/cdragon'
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
@@ -59,14 +60,13 @@ refreshStyles()
|
|||||||
:key="slotIndex"
|
:key="slotIndex"
|
||||||
class="rune-slot"
|
class="rune-slot"
|
||||||
>
|
>
|
||||||
<NuxtImg
|
<RuneIcon
|
||||||
v-for="perk in slot.perks"
|
v-for="perkId in slot.perks"
|
||||||
:key="perk"
|
:key="perkId"
|
||||||
width="48"
|
:perk="perks.get(perkId)"
|
||||||
:class="
|
:size="48"
|
||||||
'rune-img rune-keystone ' + (props.selectionIds.includes(perk) ? 'rune-activated' : '')
|
:is-active="props.selectionIds.includes(perkId)"
|
||||||
"
|
:is-keystone="true"
|
||||||
:src="'https://raw.communitydragon.org/latest/' + mapPath(perks.get(perk).iconPath)"
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
@@ -74,12 +74,12 @@ refreshStyles()
|
|||||||
:key="slotIndex"
|
:key="slotIndex"
|
||||||
class="rune-slot"
|
class="rune-slot"
|
||||||
>
|
>
|
||||||
<NuxtImg
|
<RuneIcon
|
||||||
v-for="perk in slot.perks"
|
v-for="perkId in slot.perks"
|
||||||
:key="perk"
|
:key="perkId"
|
||||||
width="48"
|
:perk="perks.get(perkId)"
|
||||||
:class="'rune-img ' + (props.selectionIds.includes(perk) ? 'rune-activated' : '')"
|
:size="48"
|
||||||
:src="'https://raw.communitydragon.org/latest/' + mapPath(perks.get(perk).iconPath)"
|
:is-active="props.selectionIds.includes(perkId)"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -93,17 +93,14 @@ refreshStyles()
|
|||||||
:key="slotIndex"
|
:key="slotIndex"
|
||||||
class="rune-slot"
|
class="rune-slot"
|
||||||
>
|
>
|
||||||
<NuxtImg
|
<RuneIcon
|
||||||
v-for="perk in slot.perks"
|
v-for="perkId in slot.perks"
|
||||||
:key="perk"
|
:key="perkId"
|
||||||
width="48"
|
:perk="perks.get(perkId)"
|
||||||
:class="'rune-img ' + (props.selectionIds.includes(perk) ? 'rune-activated' : '')"
|
:size="48"
|
||||||
:src="'https://raw.communitydragon.org/latest/' + mapPath(perks.get(perk).iconPath)"
|
:is-active="props.selectionIds.includes(perkId)"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<!-- <div class="rune-slot mini" v-for="slot in primaryStyle.slots.slice(4, 7)">
|
|
||||||
<img width="32" v-for="perk in slot.perks" :class="'rune-img ' + (props.selectionIds.includes(perk) ? 'rune-activated' : '')" :src="'https://raw.communitydragon.org/latest/' + mapPath(perks.get(perk).iconPath)"/>
|
|
||||||
</div> -->
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -126,19 +123,6 @@ refreshStyles()
|
|||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
.rune-img {
|
|
||||||
max-width: 100%;
|
|
||||||
overflow: hidden;
|
|
||||||
filter: grayscale(1);
|
|
||||||
border: 1px var(--color-on-surface) solid;
|
|
||||||
border-radius: 50%;
|
|
||||||
}
|
|
||||||
.rune-keystone {
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
.rune-activated {
|
|
||||||
filter: none;
|
|
||||||
}
|
|
||||||
.rune-spacer-bar {
|
.rune-spacer-bar {
|
||||||
margin-left: 20px;
|
margin-left: 20px;
|
||||||
margin-right: 20px;
|
margin-right: 20px;
|
||||||
@@ -151,10 +135,6 @@ refreshStyles()
|
|||||||
margin-top: 20px;
|
margin-top: 20px;
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
}
|
}
|
||||||
.rune-img {
|
|
||||||
width: 24px;
|
|
||||||
height: 24px;
|
|
||||||
}
|
|
||||||
.rune-style-img {
|
.rune-style-img {
|
||||||
width: 24px;
|
width: 24px;
|
||||||
height: 24px;
|
height: 24px;
|
||||||
|
|||||||
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>
|
||||||
366
frontend/components/rune/RuneTooltip.vue
Normal file
366
frontend/components/rune/RuneTooltip.vue
Normal file
@@ -0,0 +1,366 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { CDRAGON_BASE, mapPath } from '~/utils/cdragon'
|
||||||
|
|
||||||
|
import type { Perk } from '~/types/cdragon'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
perk: Perk | null
|
||||||
|
show: boolean
|
||||||
|
x: number
|
||||||
|
y: number
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = defineProps<Props>()
|
||||||
|
|
||||||
|
// Parse the long description to extract styled content
|
||||||
|
// Rune descriptions use HTML-like tags including special lol-uikit tags
|
||||||
|
interface TextSegment {
|
||||||
|
type: string
|
||||||
|
content: string
|
||||||
|
color?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseRuneDescription(description: string | undefined): TextSegment[] {
|
||||||
|
if (!description) return []
|
||||||
|
|
||||||
|
const segments: TextSegment[] = []
|
||||||
|
|
||||||
|
// Pattern to match various tag types:
|
||||||
|
// - Simple tags: <status>, <keyword>, </status>
|
||||||
|
// - Tags with attributes: <font color='#FF8000'>, <lol-uikit-tooltipped-keyword ...>
|
||||||
|
// - Self-closing or complex tags
|
||||||
|
const tagPattern = /<(\/?)([a-zA-Z][a-zA-Z0-9-]*)([^>]*)>/g
|
||||||
|
|
||||||
|
let lastIndex = 0
|
||||||
|
const tagStack: Array<{ type: string; color?: string }> = []
|
||||||
|
|
||||||
|
let match
|
||||||
|
while ((match = tagPattern.exec(description)) !== null) {
|
||||||
|
// Add any text before this tag
|
||||||
|
if (match.index > lastIndex) {
|
||||||
|
const text = description.slice(lastIndex, match.index)
|
||||||
|
if (text) {
|
||||||
|
const currentStyle = tagStack.length > 0 ? tagStack[tagStack.length - 1] : { type: 'text' }
|
||||||
|
segments.push({
|
||||||
|
type: currentStyle.type,
|
||||||
|
content: text,
|
||||||
|
color: currentStyle.color
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const [fullMatch, isClosing, tagName, attributes] = match
|
||||||
|
|
||||||
|
// Normalize tag name (handle lol-uikit-tooltipped-keyword -> keyword)
|
||||||
|
let normalizedTag = tagName
|
||||||
|
if (tagName === 'lol-uikit-tooltipped-keyword') {
|
||||||
|
normalizedTag = 'keyword'
|
||||||
|
} else if (tagName === 'lol-uikit-tooltipped-link') {
|
||||||
|
normalizedTag = 'keyword'
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isClosing) {
|
||||||
|
// Opening tag - extract color if present
|
||||||
|
const colorMatch = attributes.match(/color=['"]([^'"]+)['"]/i)
|
||||||
|
const color = colorMatch ? colorMatch[1] : undefined
|
||||||
|
|
||||||
|
tagStack.push({ type: normalizedTag, color })
|
||||||
|
} else {
|
||||||
|
// Closing tag
|
||||||
|
tagStack.pop()
|
||||||
|
}
|
||||||
|
|
||||||
|
lastIndex = match.index + fullMatch.length
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add any remaining text
|
||||||
|
if (lastIndex < description.length) {
|
||||||
|
const text = description.slice(lastIndex)
|
||||||
|
if (text) {
|
||||||
|
const currentStyle = tagStack.length > 0 ? tagStack[tagStack.length - 1] : { type: 'text' }
|
||||||
|
segments.push({
|
||||||
|
type: currentStyle.type,
|
||||||
|
content: text,
|
||||||
|
color: currentStyle.color
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return segments
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get CSS class for text segment type
|
||||||
|
function getSegmentClass(segment: TextSegment): string {
|
||||||
|
const classMap: Record<string, string> = {
|
||||||
|
text: '',
|
||||||
|
highlight: 'stat-highlight',
|
||||||
|
passive: 'tag-passive',
|
||||||
|
active: 'tag-active',
|
||||||
|
keyword: 'tag-keyword',
|
||||||
|
keywordMajor: 'tag-keyword-major',
|
||||||
|
keywordStealth: 'tag-keyword-stealth',
|
||||||
|
status: 'tag-status',
|
||||||
|
speed: 'tag-speed',
|
||||||
|
scaleMana: 'tag-scaling',
|
||||||
|
scaleHealth: 'tag-scaling',
|
||||||
|
scaleAP: 'tag-scaling',
|
||||||
|
scaleAD: 'tag-scaling',
|
||||||
|
scaleArmor: 'tag-scaling',
|
||||||
|
scaleMR: 'tag-scaling',
|
||||||
|
scaleLevel: 'tag-scaling',
|
||||||
|
scaleBonusHealth: 'tag-scaling',
|
||||||
|
scaleBonusMana: 'tag-scaling',
|
||||||
|
scaleMaxHealth: 'tag-scaling',
|
||||||
|
spellName: 'tag-spellname',
|
||||||
|
unique: 'tag-unique',
|
||||||
|
rarityMythic: 'tag-rarity-mythic',
|
||||||
|
rarityLegendary: 'tag-rarity-legendary',
|
||||||
|
rarityGeneric: 'tag-rarity-generic',
|
||||||
|
magicDamage: 'tag-magic-damage',
|
||||||
|
physicalDamage: 'tag-physical-damage',
|
||||||
|
trueDamage: 'tag-true-damage',
|
||||||
|
healing: 'tag-healing',
|
||||||
|
shield: 'tag-shield',
|
||||||
|
attention: 'stat-highlight',
|
||||||
|
onHit: 'tag-onhit',
|
||||||
|
color: ''
|
||||||
|
}
|
||||||
|
return classMap[segment.type] || ''
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render text segments to HTML
|
||||||
|
function renderSegments(segments: TextSegment[]): string {
|
||||||
|
return segments
|
||||||
|
.map(segment => {
|
||||||
|
const cssClass = getSegmentClass(segment)
|
||||||
|
|
||||||
|
// If segment has a color, use it directly (handles <font color='...'> tags)
|
||||||
|
if (segment.color) {
|
||||||
|
return `<span style="color: ${segment.color}">${segment.content}</span>`
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cssClass) {
|
||||||
|
return `<span class="${cssClass}">${segment.content}</span>`
|
||||||
|
}
|
||||||
|
|
||||||
|
return segment.content
|
||||||
|
})
|
||||||
|
.join('')
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parsed description
|
||||||
|
const parsedLongDesc = computed<TextSegment[]>(() => {
|
||||||
|
return parseRuneDescription(props.perk?.longDesc)
|
||||||
|
})
|
||||||
|
|
||||||
|
const hasLongDesc = computed(() => {
|
||||||
|
return parsedLongDesc.value.length > 0
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Teleport to="body">
|
||||||
|
<Transition name="fade">
|
||||||
|
<div
|
||||||
|
v-if="show && perk"
|
||||||
|
class="rune-tooltip"
|
||||||
|
:style="{
|
||||||
|
left: x + 'px',
|
||||||
|
top: y + 'px'
|
||||||
|
}"
|
||||||
|
@mouseenter.stop
|
||||||
|
>
|
||||||
|
<!-- Header -->
|
||||||
|
<div class="tooltip-header">
|
||||||
|
<NuxtImg class="tooltip-icon" :src="CDRAGON_BASE + mapPath(perk.iconPath)" />
|
||||||
|
<div class="tooltip-title">
|
||||||
|
<h3>{{ perk.name || 'Unknown Rune' }}</h3>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Long Description (detailed) -->
|
||||||
|
<div v-if="hasLongDesc" class="tooltip-long-desc">
|
||||||
|
<!-- eslint-disable vue/no-v-html -->
|
||||||
|
<div v-html="renderSegments(parsedLongDesc)"></div>
|
||||||
|
<!-- eslint-enable vue/no-v-html -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Transition>
|
||||||
|
</Teleport>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.rune-tooltip {
|
||||||
|
position: fixed;
|
||||||
|
z-index: 1000;
|
||||||
|
background: var(--tooltip-bg);
|
||||||
|
border: 1px solid var(--tooltip-border);
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 12px;
|
||||||
|
max-width: 320px;
|
||||||
|
min-width: 250px;
|
||||||
|
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4);
|
||||||
|
pointer-events: none;
|
||||||
|
font-family: 'Inter', sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Header */
|
||||||
|
.tooltip-header {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
border-bottom: 1px solid var(--tooltip-header-border);
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip-icon {
|
||||||
|
width: 48px;
|
||||||
|
height: 48px;
|
||||||
|
border-radius: 50%;
|
||||||
|
flex-shrink: 0;
|
||||||
|
background: rgba(0, 0, 0, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip-title {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip-title h3 {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--tooltip-text);
|
||||||
|
line-height: 1.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Long Description */
|
||||||
|
.tooltip-long-desc {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
color: var(--tooltip-text-dim);
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Text segment styles */
|
||||||
|
.tooltip-long-desc :deep(.stat-highlight) {
|
||||||
|
color: var(--tooltip-highlight);
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip-long-desc :deep(.tag-passive) {
|
||||||
|
color: var(--tooltip-effect-passive);
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip-long-desc :deep(.tag-active) {
|
||||||
|
color: var(--tooltip-effect-active);
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip-long-desc :deep(.tag-keyword) {
|
||||||
|
color: var(--tooltip-keyword);
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip-long-desc :deep(.tag-keyword-major) {
|
||||||
|
color: var(--tooltip-keyword-major);
|
||||||
|
font-weight: 700;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip-long-desc :deep(.tag-keyword-stealth) {
|
||||||
|
color: var(--tooltip-keyword-stealth);
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip-long-desc :deep(.tag-status) {
|
||||||
|
color: var(--tooltip-status);
|
||||||
|
font-weight: 500;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip-long-desc :deep(.tag-speed),
|
||||||
|
.tooltip-long-desc :deep(.tag-scaling) {
|
||||||
|
color: var(--tooltip-scaling);
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip-long-desc :deep(.tag-healing) {
|
||||||
|
color: var(--tooltip-healing);
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip-long-desc :deep(.tag-shield) {
|
||||||
|
color: var(--tooltip-shield);
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip-long-desc :deep(.tag-magic-damage) {
|
||||||
|
color: var(--tooltip-magic-damage);
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip-long-desc :deep(.tag-physical-damage) {
|
||||||
|
color: var(--tooltip-physical-damage);
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip-long-desc :deep(.tag-true-damage) {
|
||||||
|
color: var(--tooltip-true-damage);
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip-long-desc :deep(.tag-onhit) {
|
||||||
|
background: rgba(52, 152, 219, 0.2);
|
||||||
|
color: var(--tooltip-onhit);
|
||||||
|
padding: 1px 4px;
|
||||||
|
border-radius: 3px;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip-long-desc :deep(.tag-spellname) {
|
||||||
|
color: var(--tooltip-spellname);
|
||||||
|
font-weight: 600;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip-long-desc :deep(.tag-unique) {
|
||||||
|
color: var(--tooltip-effect-unique);
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
letter-spacing: 0.5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip-long-desc :deep(.tag-rarity-mythic) {
|
||||||
|
color: var(--tooltip-effect-mythic);
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip-long-desc :deep(.tag-rarity-legendary) {
|
||||||
|
color: var(--tooltip-effect-legendary);
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip-long-desc :deep(.tag-rarity-generic) {
|
||||||
|
color: var(--tooltip-effect-epic);
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Transition */
|
||||||
|
.fade-enter-active,
|
||||||
|
.fade-leave-active {
|
||||||
|
transition: opacity 0.15s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fade-enter-from,
|
||||||
|
.fade-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -32,6 +32,8 @@ type Perk = {
|
|||||||
id: number
|
id: number
|
||||||
name: string
|
name: string
|
||||||
iconPath: string
|
iconPath: string
|
||||||
|
shortDesc?: string
|
||||||
|
longDesc?: string
|
||||||
}
|
}
|
||||||
type PerkStyle = {
|
type PerkStyle = {
|
||||||
id: number
|
id: number
|
||||||
|
|||||||
Reference in New Issue
Block a user