1// âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ 2// Tarjeta de carrera â Hoy, Competición y Ciclocross 3// âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ 4// Una sola estructura: logo | .race-card__main (nombre, subtÃtulo, badges) | 5// .race-card__meta, con el miniperfil en .race-card__profile como banda 6// inferior. Cada página decide el contenido de cada zona; las piezas de 7// jornada de carretera (cifras, horario, perfil, resultados, activación) 8// están en stage-card.js. 9 10function hexLuminance(hex) { 11 if (!hex || !/^#[0-9a-fA-F]{3,6}$/.test(hex)) return null; 12 const h = hex.replace('#', ''); 13 const full = h.length === 3 ? h.split('').map(c => c + c).join('') : h; 14 const [r, g, b] = [0, 2, 4].map(i => parseInt(full.slice(i, i + 2), 16)); 15 return { r, g, b, lum: 0.299 * r + 0.587 * g + 0.114 * b }; 16} 17 18// Color visible como raya/borde en ambos temas: los muy claros se oscurecen. 19function safeCardColor(hex) { 20 const c = hexLuminance(hex); 21 if (!c) return '#888'; 22 if (c.lum <= 210) return hex; 23 const darken = v => Math.round(v * 0.6).toString(16).padStart(2, '0'); 24 return '#' + darken(c.r) + darken(c.g) + darken(c.b); 25} 26 27// Contenedor de la tarjeta con el color de la carrera y el borde mÃnimo de 28// los colores claros o inválidos. 29export function createRaceCard(colorHex, extraClass = '', tag = 'div') { 30 const card = document.createElement(tag); 31 const c = hexLuminance(colorHex); 32 card.className = ['race-card', extraClass, !c || c.lum > 210 ? 'race-card--light-color' : ''].filter(Boolean).join(' '); 33 card.style.setProperty('--card-color', safeCardColor(colorHex)); 34 return card; 35} 36 37export function cardLogoHtml(logoUrl, flag, hideFlag) { 38 if (logoUrl) { 39 return `<div class="race-card__logo"> 40 <img class="race-logo-img" src="${logoUrl}" alt="" loading="lazy" onerror="this.style.display='none'"> 41 ${hideFlag ? '' : `<span>${flag}</span>`} 42 </div>`; 43 } 44 return hideFlag ? '' : `<div class="race-card__flag">${flag}</div>`; 45} 46 47// Acceso a la competición o al torneo junto al nombre. 48export function overviewButtonHtml(href, label) { 49 return `<a class="race-card__overview-btn" href="${href}" aria-label="${label}" onclick="event.stopPropagation()"><span aria-hidden="true">â°</span></a>`; 50} 51 52// Zonas de la tarjeta. Todo es HTML: el llamador escapa lo que proceda. 53// `meta` va en .race-card__meta-top; `metaBlock` sustituye la columna entera 54// (categorÃas de ciclocross). 55export function raceCardHtml({ logo = '', name, sub = '', badges = '', meta = '', metaBlock = null }) { 56 return `${logo}<div class="race-card__main">` 57 + `<div class="race-card__name">${name}</div>` 58 + (sub ? `<div class="race-card__sub">${sub}</div>` : '') 59 + `<div class="race-card__badges">${badges}</div>` 60 + `</div>${metaBlock ?? `<div class="race-card__meta"><div class="race-card__meta-top">${meta}</div></div>`}`; 61} 62 63// Tarjeta sin página ni modal: tooltip al pasar el ratón y aviso al pulsar en 64// móvil (initPhTooltip de shared.js). 65export function setInfoTooltip(card, { message, name, flag, sub }) { 66 card.style.cursor = 'default'; 67 card.dataset.phTooltip = message; 68 card.dataset.phName = name; 69 card.dataset.phFlag = flag; 70 if (sub) card.dataset.phSub = sub; 71} 72
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.