Files
NightSpire/web-next/components/ArmoryTalents.tsx
T
Inna beba7301a1 Armería: PvP campos de batalla, logros por categoría, bandas/mazmorras y página de hermandad
- PvP: pestaña Campos de batalla (pvpstats) con resultado, stats por partida y fecha/hora.
- Logros: rejilla por categoría con anillos de progreso + detalle por categoría
  (datos de Achievement.db2 + Achievement_Category.db2, iconos vía wowhead).
- Bandas: progreso por dificultad (10/25/heroico) con jefes reales de DungeonEncounter.db2
  y tooltip de jefes; agrupado por expansión (Clásico/TBC/WotLK).
- Mazmorras: mismo sistema, Normal + Heroico, Clásico/TBC/WotLK.
- Página de hermandad estilo armería: cabecera (emblema, puntos = unión de logros de
  miembros sin duplicar, nº miembros, fundada), pestañas Hermandad/Logros, roster con
  iconos de clase/raza, columna Función (rol por spec), filtros clase/función,
  orden por rango/puntos/nivel de objeto/nivel/nombre, paginación.
- Barra lateral: mensaje diario con login (iron-session, gated por pertenencia),
  logros recientes y desgloses de clases y funciones.
- Cabecera de personaje: enlace a la hermandad + nombre del reino.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 01:18:30 +00:00

123 lines
4.8 KiB
TypeScript

import { wowheadIcon, wowheadUrl, wowheadData } 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[] }
export type GlyphInfo = { name: string; icon: string }
export type TalentGroupView = {
spec: string | null
total: number
dist: number[]
trees: TalentTreeData[]
glyphs: { major: GlyphInfo[]; minor: GlyphInfo[] }
}
/**
* Renderiza UN grupo de talentos: cabecera de distribución + los 3 árboles (rejilla de
* iconos) + una 4ª columna con los Glifos (mayores/menores). Componente puro sin estado,
* usado por ArmoryTalentTab (que conmuta Primaria/Secundaria).
*/
export function ArmoryTalents({
group,
spellIcons,
locale,
labels,
}: {
group: TalentGroupView
spellIcons: Record<number, string>
locale: string
labels: { distribution: string; groupLabel: string; glyphs: string; majorGlyphs: string; minorGlyphs: string }
}) {
const { trees, glyphs, dist } = group
return (
<div className="armory-talents">
<div className="armory-tdist">
<div className="armory-tdist-label">
{labels.distribution} · {labels.groupLabel.toUpperCase()}
</div>
<div className="armory-tdist-value">{dist.join(' / ')}</div>
</div>
<div className="armory-talent-cols">
{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 className="armory-talent-tree armory-glyph-col">
<div className="armory-talent-tree-head">
<span>{labels.glyphs}</span>
<span className="armory-talent-tree-pts">
{glyphs.major.length} · {glyphs.minor.length}
</span>
</div>
{glyphs.major.length > 0 && (
<div className="armory-glyph-group">
<h3 className="armory-prof-grouptitle">{labels.majorGlyphs}</h3>
{glyphs.major.map((g, i) => (
<div className="armory-glyph" key={i}>
<span className="armory-glyph-icon" style={{ backgroundImage: `url(${wowheadIcon(g.icon, 'small')})` }} />
<span className="armory-glyph-name">{g.name}</span>
</div>
))}
</div>
)}
{glyphs.minor.length > 0 && (
<div className="armory-glyph-group">
<h3 className="armory-prof-grouptitle">{labels.minorGlyphs}</h3>
{glyphs.minor.map((g, i) => (
<div className="armory-glyph" key={i}>
<span className="armory-glyph-icon" style={{ backgroundImage: `url(${wowheadIcon(g.icon, 'small')})` }} />
<span className="armory-glyph-name">{g.name}</span>
</div>
))}
</div>
)}
{glyphs.major.length === 0 && glyphs.minor.length === 0 && (
<p className="armory-hint" style={{ padding: '8px 0' }}>
</p>
)}
</div>
</div>
</div>
)
}