accesibilidad: Atkinson Hyperlegible + toggle claro/oscuro (#196)
Mu-plugin fea-accesibilidad.php: - Atkinson Hyperlegible (OFL) self-hosted, subset latin regular+bold, sustituye la tipografia global del cuerpo sin selector. - Toggle claro/oscuro persistente (localStorage), anti-flash en wp_head, boton inyectado junto al selector de idioma en el header. - color-scheme: dark para controles nativos (audio, inputs) + overrides puntuales donde el sitio fija colores claros a mano (hero, tarjetas, selector de idioma, buscador movil, beta feedback, cookie consent). - Acento mas claro (#e8899e) solo en modo oscuro: el carmesi de marca (#8b1a2e) no llega a 2:1 de contraste sobre el fondo casi negro. QA local (docker wordpress-web, capturas Playwright en tools/e2e/out/): portada, tarjetas y single verificados en claro y oscuro.
This commit is contained in:
@@ -0,0 +1,243 @@
|
||||
<?php
|
||||
/**
|
||||
* Plugin Name: Fe Adulta — Accesibilidad (tipografía + contraste)
|
||||
* Description: Tipografía Atkinson Hyperlegible global (self-hosted) + toggle
|
||||
* claro/oscuro persistente, pensado para el público mayor de
|
||||
* Fe Adulta (issue rafa/feadulta#196, evidencia en comment #609).
|
||||
* Version: 1.0
|
||||
*
|
||||
* Alcance decidido en el issue (2026-08-08): SOLO dos cosas, sin más superficie
|
||||
* de UI que la necesaria —
|
||||
* 1. Atkinson Hyperlegible sustituye la tipografía del cuerpo, sin selector.
|
||||
* 2. Un único toggle claro/oscuro persistente (claro por defecto).
|
||||
* Nada de panel de accesibilidad, A+/Aa ni cambio de tamaño de letra.
|
||||
*/
|
||||
|
||||
if (!defined('ABSPATH')) exit;
|
||||
|
||||
if (!defined('FEA_A11Y_ACCENT_DARK')) {
|
||||
// Variante clara del carmesí de marca (#8b1a2e) para que enlaces/foco
|
||||
// cumplan contraste AA sobre fondo casi negro (el carmesí original da
|
||||
// ~1.8:1 sobre #0d0d0d, muy por debajo del 4.5:1 que exige texto).
|
||||
define('FEA_A11Y_ACCENT_DARK', '#e8899e');
|
||||
}
|
||||
|
||||
/* ── 1) Anti-flash: fija el tema ANTES de que el navegador pinte nada ─────
|
||||
* Se engancha con prioridad muy baja para salir de los primeros bytes de
|
||||
* <head>, igual que el resto del sitio guarda preferencias en localStorage
|
||||
* (ver fea-beta-feedback.php). Sin esto habría un parpadeo claro→oscuro. */
|
||||
add_action('wp_head', function () {
|
||||
if (is_admin()) return;
|
||||
?>
|
||||
<script>(function(){try{
|
||||
var t = localStorage.getItem('fea_theme');
|
||||
if (t === 'dark') document.documentElement.setAttribute('data-fea-theme', 'dark');
|
||||
}catch(e){}})();</script>
|
||||
<?php
|
||||
}, 1);
|
||||
|
||||
/* ── 2) Fuente self-hosted + estilos de tema oscuro ───────────────────── */
|
||||
add_action('wp_head', function () {
|
||||
if (is_admin()) return;
|
||||
$base = plugins_url('fea-accesibilidad/fonts', __FILE__);
|
||||
$accent_dark = FEA_A11Y_ACCENT_DARK;
|
||||
?>
|
||||
<style id="fea-a11y">
|
||||
/* ── Atkinson Hyperlegible (Braille Institute, OFL), subset latin ──── */
|
||||
@font-face {
|
||||
font-family: 'Atkinson Hyperlegible';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url('<?php echo esc_url($base); ?>/atkinson-hyperlegible-regular.woff2') format('woff2');
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Atkinson Hyperlegible';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
font-display: swap;
|
||||
src: url('<?php echo esc_url($base); ?>/atkinson-hyperlegible-bold.woff2') format('woff2');
|
||||
}
|
||||
|
||||
/* Sustitución global del cuerpo de texto (no opcional, issue #196).
|
||||
Especificidad baja a propósito: el menú (fea-ui.php, issue #95) usa
|
||||
una sans de UI más específica y debe seguir ganando. */
|
||||
body {
|
||||
font-family: 'Atkinson Hyperlegible', system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
|
||||
}
|
||||
|
||||
/* ── Toggle claro/oscuro: botón inyectado junto al selector de idioma ── */
|
||||
#fea-theme-btn {
|
||||
display: inline-flex; align-items: center; justify-content: center;
|
||||
width: 30px; height: 30px; border-radius: 50%;
|
||||
border: 1px solid rgba(0,0,0,0.25); background: none; color: inherit;
|
||||
cursor: pointer; font-size: 0.95rem; line-height: 1; padding: 0;
|
||||
}
|
||||
#fea-theme-btn:hover { background: rgba(0,0,0,0.06); }
|
||||
|
||||
/* ══════════════════════════════════════════════════════════════════
|
||||
MODO OSCURO — activado por [data-fea-theme="dark"] en <html>
|
||||
══════════════════════════════════════════════════════════════════ */
|
||||
html[data-fea-theme="dark"] {
|
||||
/* Deja que el navegador oscurezca controles nativos gratis:
|
||||
audio/video, scrollbars, checkboxes, selects sin estilo propio. */
|
||||
color-scheme: dark;
|
||||
--wp--preset--color--base: #0d0d0d;
|
||||
--wp--preset--color--contrast: #ececec;
|
||||
}
|
||||
html[data-fea-theme="dark"] body {
|
||||
background-color: #0d0d0d !important;
|
||||
color: #ececec !important;
|
||||
}
|
||||
html[data-fea-theme="dark"] a { color: <?php echo esc_html($accent_dark); ?>; }
|
||||
html[data-fea-theme="dark"] a:focus-visible,
|
||||
html[data-fea-theme="dark"] button:focus-visible {
|
||||
outline-color: <?php echo esc_html($accent_dark); ?> !important;
|
||||
}
|
||||
|
||||
/* Cabecera/pie y bloques de grupo sin fondo explícito heredan el body;
|
||||
solo hay que corregir los pocos sitios con color fijo en claro. */
|
||||
html[data-fea-theme="dark"] input,
|
||||
html[data-fea-theme="dark"] textarea,
|
||||
html[data-fea-theme="dark"] select {
|
||||
background-color: #1c1c1c;
|
||||
color: #ececec;
|
||||
border-color: #3a3a3a;
|
||||
}
|
||||
|
||||
/* Portada — franja hero (fea-homepage.php) */
|
||||
html[data-fea-theme="dark"] .fea-hero-band {
|
||||
background: linear-gradient(180deg, #1a1512, #0d0d0d);
|
||||
border-bottom-color: #2a2320;
|
||||
}
|
||||
html[data-fea-theme="dark"] .fea-hero-title,
|
||||
html[data-fea-theme="dark"] .fea-section-title {
|
||||
color: #ececec;
|
||||
}
|
||||
html[data-fea-theme="dark"] .fea-section-label,
|
||||
html[data-fea-theme="dark"] .fea-section-more,
|
||||
html[data-fea-theme="dark"] .fea-card-author {
|
||||
color: <?php echo esc_html($accent_dark); ?>;
|
||||
}
|
||||
html[data-fea-theme="dark"] .fea-hero-meta { color: #b8afa8; }
|
||||
|
||||
/* Tarjetas de autor/artículo (fea-homepage.php) */
|
||||
html[data-fea-theme="dark"] .fea-card {
|
||||
background: #161311;
|
||||
border-color: #2a2320;
|
||||
}
|
||||
html[data-fea-theme="dark"] .fea-card-title a { color: #ececec; }
|
||||
|
||||
/* Selector de idioma (fea-homepage.php) */
|
||||
html[data-fea-theme="dark"] #fea-lang-btn { border-color: rgba(255,255,255,0.3); }
|
||||
html[data-fea-theme="dark"] #fea-lang-btn:hover,
|
||||
html[data-fea-theme="dark"] #fea-theme-btn:hover { background: rgba(255,255,255,0.08); }
|
||||
html[data-fea-theme="dark"] #fea-theme-btn { border-color: rgba(255,255,255,0.3); }
|
||||
html[data-fea-theme="dark"] #fea-lang-dropdown {
|
||||
background: #161311; border-color: #3a3a3a;
|
||||
box-shadow: 0 6px 16px rgba(0,0,0,.5);
|
||||
}
|
||||
html[data-fea-theme="dark"] #fea-lang-dropdown a { color: #ececec; }
|
||||
html[data-fea-theme="dark"] #fea-lang-dropdown a:hover { background: #241f1c; }
|
||||
html[data-fea-theme="dark"] #fea-lang-dropdown a[aria-current] { background: #2a2320; color: #fff; }
|
||||
|
||||
/* Buscador móvil (fea-search.php) */
|
||||
html[data-fea-theme="dark"] .fea-search-bar { background: #0d0d0d; border-bottom-color: #2a2320; }
|
||||
html[data-fea-theme="dark"] .fea-search { background: #1c1c1c; border-color: #3a3a3a; }
|
||||
html[data-fea-theme="dark"] .fea-search input[type=search] { color: #ececec; }
|
||||
|
||||
/* Reproductor de audio (fea-audio-player.php) — el <audio> nativo ya
|
||||
cambia solo vía color-scheme; solo hace falta la etiqueta de texto. */
|
||||
html[data-fea-theme="dark"] .fea-audio-label { color: #b8afa8; }
|
||||
|
||||
/* Barra y tarjeta de Beta Feedback (fea-beta-feedback.php) */
|
||||
html[data-fea-theme="dark"] #fea-beta-bar {
|
||||
background: #161311; border-top-color: #2a2320; color: #ececec;
|
||||
}
|
||||
html[data-fea-theme="dark"] #fea-beta-bar .fea-beta-dismiss { color: #b8afa8; }
|
||||
html[data-fea-theme="dark"] #fea-fb .fea-fb-card {
|
||||
background: #161311; border-color: #3a3a3a; color: #ececec;
|
||||
}
|
||||
html[data-fea-theme="dark"] #fea-fb button.fea-fb-vote {
|
||||
background: #1c1c1c; border-color: #3a3a3a; color: #ececec;
|
||||
}
|
||||
html[data-fea-theme="dark"] #fea-fb button.fea-fb-vote.sel {
|
||||
border-color: <?php echo esc_html($accent_dark); ?>; background: #2a1418;
|
||||
}
|
||||
html[data-fea-theme="dark"] #fea-fb textarea { background: #1c1c1c; border-color: #3a3a3a; color: #ececec; }
|
||||
|
||||
/* Barra de consentimiento de cookies (fea-cookie-consent.php) */
|
||||
html[data-fea-theme="dark"] #fea-cc {
|
||||
background: #161311 !important; color: #ececec !important; border-top-color: #2a2320 !important;
|
||||
}
|
||||
html[data-fea-theme="dark"] #fea-cc a { color: #b8afa8 !important; }
|
||||
html[data-fea-theme="dark"] #fea-cc .fea-cc-reject { color: #ececec !important; border-color: #3a3a3a !important; }
|
||||
</style>
|
||||
<?php
|
||||
}, 30);
|
||||
|
||||
/* ── 3) Botón de toggle, inyectado en el header junto al selector de idioma ──
|
||||
* Mismo patrón que el selector de idioma (fea-homepage.php): se crea por JS
|
||||
* y se inserta en el nav del header, para no tocar el template FSE. */
|
||||
add_action('wp_footer', function () {
|
||||
if (is_admin()) return;
|
||||
?>
|
||||
<script>
|
||||
(function() {
|
||||
var btn = document.createElement('button');
|
||||
btn.id = 'fea-theme-btn';
|
||||
btn.type = 'button';
|
||||
btn.setAttribute('aria-pressed', document.documentElement.getAttribute('data-fea-theme') === 'dark' ? 'true' : 'false');
|
||||
btn.setAttribute('aria-label', 'Cambiar a modo oscuro');
|
||||
btn.textContent = document.documentElement.getAttribute('data-fea-theme') === 'dark' ? '☀️' : '🌙';
|
||||
|
||||
function setLabel(isDark) {
|
||||
btn.setAttribute('aria-pressed', isDark ? 'true' : 'false');
|
||||
btn.setAttribute('aria-label', isDark ? 'Cambiar a modo claro' : 'Cambiar a modo oscuro');
|
||||
btn.textContent = isDark ? '☀️' : '🌙';
|
||||
}
|
||||
|
||||
btn.addEventListener('click', function() {
|
||||
var isDark = document.documentElement.getAttribute('data-fea-theme') === 'dark';
|
||||
if (isDark) {
|
||||
document.documentElement.removeAttribute('data-fea-theme');
|
||||
} else {
|
||||
document.documentElement.setAttribute('data-fea-theme', 'dark');
|
||||
}
|
||||
setLabel(!isDark);
|
||||
try { localStorage.setItem('fea_theme', !isDark ? 'dark' : 'light'); } catch (e) {}
|
||||
});
|
||||
|
||||
function inject() {
|
||||
var header = document.querySelector('header.wp-block-template-part') || document.querySelector('header');
|
||||
if (!header) return;
|
||||
var navGroup = header.querySelector('.wp-block-navigation__container') || header.querySelector('nav');
|
||||
var li = document.createElement('li');
|
||||
li.className = 'wp-block-navigation-item';
|
||||
li.style.cssText = 'display:flex;align-items:center;margin-left:0.5rem;';
|
||||
li.appendChild(btn);
|
||||
if (!navGroup) {
|
||||
header.style.position = 'relative';
|
||||
li.style.cssText = 'position:absolute;top:50%;right:1.5rem;transform:translateY(-50%);';
|
||||
header.appendChild(li);
|
||||
return;
|
||||
}
|
||||
// Insertar después del selector de idioma si ya se inyectó, si no, al final del nav.
|
||||
var langSwitcher = navGroup.querySelector('#fea-lang-switcher');
|
||||
if (langSwitcher) {
|
||||
var anchor = langSwitcher;
|
||||
while (anchor.parentNode && anchor.parentNode !== navGroup) anchor = anchor.parentNode;
|
||||
anchor.parentNode.insertBefore(li, anchor.nextSibling);
|
||||
} else {
|
||||
navGroup.appendChild(li);
|
||||
}
|
||||
}
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', inject);
|
||||
} else {
|
||||
inject();
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
<?php
|
||||
}, 21);
|
||||
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user