Files
NightSpire/web-next/components/ArmoryTalents.tsx
T
Inna 3af7f5e804 Armería: muñeco de papel, talentos, actividad y caché del visor 3D
La ficha de personaje pasa a mostrar el equipo sobre el paperdoll (con
encantamientos y gemas en los tooltips de wowhead), el árbol de talentos y
la actividad reciente del personaje.

El proxy de /modelviewer/* deja de ser un rewrite de Next y pasa a un route
handler que cachea en disco los assets de zamimg, para no repetir la descarga
en cada visita.
2026-07-16 21:07:39 +00:00

83 lines
3.1 KiB
TypeScript

import { wowheadUrl, wowheadData, wowheadIcon } from '@/lib/wowhead'
export type TalentCell = { tier: number; col: number; rank: number; max: number; spell: number }
export type TalentTreeData = { index: number; name: string; points: number; talents: TalentCell[] }
/**
* Árbol de talentos estilo calculador: 3 árboles, cada uno una rejilla de casillas
* posicionadas por fila (tier) y columna. Cada casilla muestra el icono del talento
* (del hechizo de rango 1) y su rango actual/máximo; las no aprendidas van atenuadas.
* El icono va en un <span> hijo porque wowhead sobrescribe el background del <a>.
*/
export function ArmoryTalents({
trees,
spec,
total,
maxPoints,
locale,
spellIcons,
}: {
trees: TalentTreeData[]
spec: string | null
total: number
maxPoints: number
locale: string
spellIcons: Record<number, string>
}) {
return (
<div className="armory-talents">
<div className="armory-spec">
<span className="armory-spec-name">{spec}</span>
<span className="armory-spec-dist">{trees.map((tr) => tr.points).join(' / ')}</span>
<span className="armory-spec-total">
{total} / {maxPoints}
</span>
</div>
<div className="armory-talent-trees">
{trees.map((tree) => {
const maxTier = tree.talents.reduce((m, t) => Math.max(m, t.tier), 0)
return (
<div className="armory-talent-tree" key={tree.index}>
<div className="armory-talent-tree-head">
<span>{tree.name}</span>
<span className="armory-talent-tree-pts">{tree.points}</span>
</div>
<div className="armory-talent-grid" style={{ gridTemplateRows: `repeat(${maxTier + 1}, 44px)` }}>
{tree.talents.map((tal) => {
const icon = spellIcons[tal.spell]
const state = tal.rank === 0 ? 'off' : tal.rank >= tal.max ? 'max' : 'on'
return (
<a
key={`${tal.tier}-${tal.col}`}
className={`armory-talent ${state}`}
style={{ gridRow: tal.tier + 1, gridColumn: tal.col + 1 }}
href={wowheadUrl('spell', tal.spell, locale)}
data-wowhead={wowheadData('spell', tal.spell, locale)}
data-wh-icon-size="false"
data-wh-rename-link="false"
target="_blank"
rel="noopener noreferrer"
>
{icon ? (
<span
className="armory-talent-icon"
style={{ backgroundImage: `url(${wowheadIcon(icon, 'medium')})` }}
/>
) : null}
{tal.rank > 0 ? (
<span className="armory-talent-rank">
{tal.rank}/{tal.max}
</span>
) : null}
</a>
)
})}
</div>
</div>
)
})}
</div>
</div>
)
}