feat(disciplinas): la tarjeta y su hebra pasan a ser la misma cosa

El dibujo de convergencia llevaba desde el principio al lado de las tres
tarjetas sin relación con ellas: tres objetos sueltos en una página. Al
señalar una disciplina, su hebra se enciende en dorado y engorda, y las
otras dos se apagan al 35%.

Es mejora solo con puntero, y a propósito: no esconde nada. Las tres
tarjetas y las tres hebras están completas sin tocar el ratón, así que
quien no lo tenga no pierde nada.

Verificado en navegador, no solo en jsdom: al señalar «Digital» la hebra
central queda en rgb(196,148,46) —el dorado de marca— a 3,5px, y las
otras en rgba(170,170,170,0.35) a 2px.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
erikghandClaude Opus 5 committed 2026-08-03 15:08:19 -06:00
1 parent 7af36e2a93
commit 9a8534f10b
4 files changed
+81 -8

No files matched your search

@@ -6,6 +6,11 @@ import { useEnVista } from '@/lib/motion';
// Three strands — comunicación, digital, experiencias — meeting and leaving as
// a single gold line. The section's own lead, drawn: "No son la promesa, son
// los medios." The three are grey; only what they produce is gold.
//
// `activa` lights the strand belonging to the discipline the reader is pointing
// at, and dims the other two. Until then the drawing sat beside the three cards
// with no relationship to them; now the card and its strand are visibly the
// same thing, and the reader can see which of the three produces what.
const HEBRAS = [
'M6 18 C 60 20, 90 52, 120 60',
'M6 60 C 60 60, 90 60, 120 60',
@@ -13,15 +18,28 @@ const HEBRAS = [
];
const ESTRATEGIA = 'M120 60 L 214 60';
export function IlustracionConvergencia({ className = '' }: { className?: string }) {
export function IlustracionConvergencia({
className = '',
activa = null,
}: {
className?: string;
activa?: number | null;
}) {
const { ref, enVista, reduced } = useEnVista();
// `stroke` follows `currentColor`, so moving the text colour moves the line —
// and transition-colors carries it across instead of snapping.
const tono = (i: number) =>
activa === null ? 'text-gris-medio' : activa === i ? 'text-dorado' : 'text-gris-medio/35';
const grosor = (i: number) => (activa === i ? 3.5 : 2);
const transicion = 'transition-all duration-300 ease-out motion-reduce:transition-none';
// Plain <path> under reduced motion — motion.path would hide the drawing.
if (reduced) {
return (
<svg ref={ref} viewBox="0 0 220 120" className={className} aria-hidden="true" focusable="false">
{HEBRAS.map((d) => (
<path key={d} d={d} fill="none" stroke="currentColor" className="text-gris-medio" strokeWidth={2} strokeLinecap="round" />
{HEBRAS.map((d, i) => (
<path key={d} d={d} data-hebra={i} fill="none" stroke="currentColor" className={`${tono(i)} ${transicion}`} strokeWidth={grosor(i)} strokeLinecap="round" />
))}
<path d={ESTRATEGIA} fill="none" stroke="currentColor" className="text-dorado" strokeWidth={3} strokeLinecap="round" />
</svg>
@@ -37,7 +55,7 @@ export function IlustracionConvergencia({ className = '' }: { className?: string
return (
<svg ref={ref} viewBox="0 0 220 120" className={className} aria-hidden="true" focusable="false">
{HEBRAS.map((d, i) => (
<motion.path key={d} d={d} fill="none" stroke="currentColor" className="text-gris-medio" strokeWidth={2} strokeLinecap="round" {...dibuja(i * 0.12)} />
<motion.path key={d} d={d} data-hebra={i} fill="none" stroke="currentColor" className={`${tono(i)} ${transicion}`} strokeWidth={grosor(i)} strokeLinecap="round" {...dibuja(i * 0.12)} />
))}
<motion.path d={ESTRATEGIA} fill="none" stroke="currentColor" className="text-dorado" strokeWidth={3} strokeLinecap="round" {...dibuja(0.7)} />
</svg>
@@ -21,4 +21,29 @@ describe('<IlustracionConvergencia />', () => {
expect(anchos.length).toBeGreaterThan(0);
anchos.forEach((a) => expect(['1.5', '2', '3']).toContain(a));
});
});
it('lights one strand and dims the rest when a discipline is pointed at', () => {
const { container } = render(<IlustracionConvergencia activa={1} />);
const hebras = Array.from(container.querySelectorAll('[data-hebra]'));
expect(hebras).toHaveLength(3);
// The point of the highlight is the pairing: the reader has to be able to
// tell WHICH strand belongs to the card under the cursor. One gold, two
// faded — if all three stayed grey the drawing would still be decoration.
const doradas = hebras.filter((h) => (h.getAttribute('class') ?? '').includes('text-dorado'));
expect(doradas).toHaveLength(1);
expect(doradas[0].getAttribute('data-hebra')).toBe('1');
hebras
.filter((h) => h.getAttribute('data-hebra') !== '1')
.forEach((h) => expect(h.getAttribute('class') ?? '').toMatch(/text-gris-medio\/35/));
});
it('keeps the three strands equal when nothing is pointed at', () => {
const { container } = render(<IlustracionConvergencia />);
const hebras = Array.from(container.querySelectorAll('[data-hebra]'));
hebras.forEach((h) => {
const cls = h.getAttribute('class') ?? '';
expect(cls).toContain('text-gris-medio');
expect(cls).not.toContain('text-dorado');
});
});
});