7a623e8bb9
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.
244 lines
11 KiB
PHP
244 lines
11 KiB
PHP
<?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);
|