3af7f5e804
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.
83 lines
3.1 KiB
TypeScript
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>
|
|
)
|
|
}
|