UNPKG

acessibilidade-widget

Version:

Um widget de acessibilidade para sites, com modos de fonte, grayscale, saturação, modo leitura, etc.

406 lines (379 loc) 12.6 kB
// src/index.js let currentFontSize = 100; let isGrayscale = false; let saturationValue = 100; let isImagesHidden = false; let isReadingMode = false; let cssInjected = false; // Flag para evitar múltiplas injeções de CSS /** * Injeta os estilos CSS automaticamente no <head>. */ function injectCSS() { const css = ` .grayscale-mode { filter: grayscale(100%) !important; -webkit-filter: grayscale(100%) !important; } .hidden-image { display: none !important; } .accessibility-btn { position: fixed !important; bottom: 80px !important; right: 20px !important; background: #007bff !important; color: white !important; padding: 10px 15px !important; border: none !important; cursor: pointer !important; font-size: 16px !important; border-radius: 6px !important; z-index: 999999 !important; } .accessibility-btn:hover { background: #0056b3 !important; } .acessibilidade-widget { position: fixed !important; bottom: 130px !important; right: 20px !important; background: #fff !important; border: 1px solid #ccc !important; padding: 10px !important; z-index: 999999 !important; box-shadow: 0 0 8px rgba(0, 0, 0, 0.2) !important; border-radius: 6px !important; font-family: Arial, sans-serif !important; display: flex !important; flex-direction: column !important; } .acessibilidade-widget button { margin: 5px !important; padding: 8px 12px !important; cursor: pointer !important; font-size: 14px !important; border: none !important; background-color: #e0e0e0 !important; border-radius: 4px !important; } .hidden { display: none !important; } body.reading-mode, body.reading-mode *:not(.acessibilidade-widget):not(.acessibilidade-widget *) { color: #333 !important; font-size: 22px !important; line-height: 1.6 !important; background: rgb(236, 236, 236) !important; } body.reading-mode img:not(.acessibilidade-widget img) { display: none !important; } body.reading-mode img:not(.acessibilidade-widget img), body.reading-mode form { display: none !important; } [vw-access-button].active { background-color: transparent !important; display: flex !important; } [vw-access-button].active img { display: none !important; } `; const style = document.createElement("style"); style.type = "text/css"; style.appendChild(document.createTextNode(css)); document.head.appendChild(style); } /** * Cria automaticamente o HTML do widget e o botão de toggle, * garantindo que sejam filhos diretos do <body>. * Agora inclui também o botão para VLibras. */ function createWidgetHTML() { // Cria o botão de toggle, se não existir. let toggleBtn = document.getElementById("toggle-accessibility"); if (!toggleBtn) { toggleBtn = document.createElement("button"); toggleBtn.id = "toggle-accessibility"; toggleBtn.className = "accessibility-btn"; toggleBtn.innerText = "Acessibilidade"; document.body.insertAdjacentElement("afterbegin", toggleBtn); } // Cria o container do widget, se não existir. let widget = document.getElementById("acessibilidade-widget"); if (!widget) { widget = document.createElement("div"); widget.id = "acessibilidade-widget"; widget.className = "acessibilidade-widget hidden"; widget.innerHTML = ` <button id="font-increase">A+</button> <button id="font-decrease">A-</button> <button id="toggle-grayscale">Monocromático</button> <button id="increase-saturation">+ Saturação</button> <button id="decrease-saturation">- Saturação</button> <button id="toggle-images">Esconder Imagens</button> <button id="toggle-reading-mode">Modo Leitura</button> <button id="libras">Libras</button> <button id="reset-accessibility" style="display: none;">Redefinir Ajustes</button> `; toggleBtn.insertAdjacentElement("afterend", widget); } } /** * Carrega o script do VLibras, se ainda não estiver carregado, e associa o evento. */ function loadVLibras() { if (!document.getElementById("vlibras-script")) { const script = document.createElement("script"); script.id = "vlibras-script"; script.src = "https://vlibras.gov.br/app/vlibras-plugin.js"; script.onload = () => { new window.VLibras.Widget('https://vlibras.gov.br/app'); attachVLibrasEvent(); }; document.head.appendChild(script); } else { attachVLibrasEvent(); } } function attachVLibrasEvent() { const librasBtn = document.getElementById("libras"); const pluginButton = document.querySelector("[vw-access-button]"); if (librasBtn && pluginButton) { librasBtn.addEventListener("click", () => { pluginButton.click(); }); } } /** * Registra o listener para o botão de toggle. */ function registerToggleButton() { const toggleBtn = document.getElementById("toggle-accessibility"); const widget = document.getElementById("acessibilidade-widget"); if (toggleBtn && widget) { toggleBtn.addEventListener("click", () => { widget.classList.toggle("hidden"); // Se o widget for aberto e o modo VLibras não estiver carregado, carrega-o if (!widget.classList.contains("hidden")) { loadVLibras(); } }); } } /** * Inicializa o widget de acessibilidade. * Injeta o CSS, cria o HTML, registra os event listeners e carrega as preferências. */ export function init() { if (!cssInjected) { injectCSS(); cssInjected = true; } createWidgetHTML(); registerToggleButton(); const btnIncrease = document.getElementById("font-increase"); const btnDecrease = document.getElementById("font-decrease"); const btnResetFont = document.getElementById("font-reset"); const btnGray = document.getElementById("toggle-grayscale"); const btnSaturUp = document.getElementById("increase-saturation"); const btnSaturDown = document.getElementById("decrease-saturation"); const btnToggleImages = document.getElementById("toggle-images"); const btnResetAll = document.getElementById("reset-accessibility"); const btnReadingMode = document.getElementById("toggle-reading-mode"); if (btnIncrease) btnIncrease.addEventListener("click", increaseFont); if (btnDecrease) btnDecrease.addEventListener("click", decreaseFont); if (btnResetFont) btnResetFont.addEventListener("click", resetFontOnly); if (btnGray) btnGray.addEventListener("click", toggleGrayscale); if (btnSaturUp) btnSaturUp.addEventListener("click", increaseSaturation); if (btnSaturDown) btnSaturDown.addEventListener("click", decreaseSaturation); if (btnToggleImages) btnToggleImages.addEventListener("click", toggleImages); if (btnResetAll) btnResetAll.addEventListener("click", resetAll); if (btnReadingMode) btnReadingMode.addEventListener("click", toggleReadingMode); loadPreferences(); } // FONTES function increaseFont() { if (currentFontSize < 200) { currentFontSize += 10; applyFontSize(); showResetButton(); savePreferences(); } } function decreaseFont() { if (currentFontSize > 60) { currentFontSize -= 10; applyFontSize(); showResetButton(); savePreferences(); } } function resetFontOnly() { currentFontSize = 100; applyFontSize(); showResetButton(); savePreferences(); } function applyFontSize() { const scale = currentFontSize / 100; const textSelectors = "p, h1, h2, h3, h4, h5, h6, span, li, a, blockquote, label, strong, em"; const textElements = document.querySelectorAll(textSelectors); textElements.forEach((el) => { if (!el.hasAttribute("data-orig-size")) { const originalSize = parseFloat(window.getComputedStyle(el).fontSize) || 16; el.setAttribute("data-orig-size", originalSize); } const baseSize = parseFloat(el.getAttribute("data-orig-size")); const newSize = baseSize * scale; el.style.fontSize = newSize + "px"; }); } // GRAYSCALE function toggleGrayscale() { isGrayscale = !isGrayscale; applyFilters(); showResetButton(); savePreferences(); } // SATURAÇÃO function increaseSaturation() { saturationValue = Math.min(saturationValue + 200, 250); applyFilters(); showResetButton(); savePreferences(); } function decreaseSaturation() { saturationValue = Math.max(saturationValue - 100, 50); applyFilters(); showResetButton(); savePreferences(); } function applyFilters() { const grayValue = isGrayscale ? "100%" : "0%"; document.documentElement.style.filter = `grayscale(${grayValue}) saturate(${saturationValue}%)`; document.documentElement.style.webkitFilter = `grayscale(${grayValue}) saturate(${saturationValue}%)`; } // IMAGENS function toggleImages() { isImagesHidden = !isImagesHidden; const allImages = document.querySelectorAll("img"); if (isImagesHidden) { allImages.forEach((img) => img.classList.add("hidden-image")); } else { allImages.forEach((img) => img.classList.remove("hidden-image")); } const btnToggleImages = document.getElementById("toggle-images"); if (btnToggleImages) { btnToggleImages.textContent = isImagesHidden ? "Mostrar Imagens" : "Esconder Imagens"; } showResetButton(); savePreferences(); } // LEITURA function toggleReadingMode() { isReadingMode = !isReadingMode; document.body.classList.toggle("reading-mode", isReadingMode); if (isReadingMode) { document.querySelectorAll("img").forEach((img) => { if (img.hasAttribute("alt")) { img.dataset.originalAlt = img.getAttribute("alt"); img.removeAttribute("alt"); } }); } else { document.querySelectorAll("img").forEach((img) => { if (img.dataset.originalAlt) { img.setAttribute("alt", img.dataset.originalAlt); delete img.dataset.originalAlt; } }); } console.log("Modo leitura ativado?", isReadingMode); showResetButton(); savePreferences(); } // RESET function resetAll() { currentFontSize = 100; isGrayscale = false; saturationValue = 100; isImagesHidden = false; isReadingMode = false; applyFontSize(); applyFilters(); const allImages = document.querySelectorAll("img"); allImages.forEach((img) => img.classList.remove("hidden-image")); document.body.classList.remove("reading-mode"); const btnToggleImages = document.getElementById("toggle-images"); if (btnToggleImages) { btnToggleImages.textContent = "Esconder Imagens"; } savePreferences(); hideResetButton(); } function showResetButton() { const btn = document.getElementById("reset-accessibility"); if (btn) { btn.style.display = "inline-block"; } } function hideResetButton() { const btn = document.getElementById("reset-accessibility"); if (btn) { btn.style.display = "none"; } } // LOCAL STORAGE function savePreferences() { localStorage.setItem("accessFontSize", currentFontSize); localStorage.setItem("accessGray", isGrayscale); localStorage.setItem("accessSaturation", saturationValue); localStorage.setItem("accessImagesHidden", isImagesHidden); localStorage.setItem("accessReadingMode", isReadingMode); } function loadPreferences() { const savedSize = localStorage.getItem("accessFontSize"); const savedGray = localStorage.getItem("accessGray"); const savedSat = localStorage.getItem("accessSaturation"); const savedImgs = localStorage.getItem("accessImagesHidden"); const savedReading = localStorage.getItem("accessReadingMode"); if (savedSize) currentFontSize = parseInt(savedSize, 10); if (savedGray === "true") isGrayscale = true; if (savedSat) saturationValue = parseInt(savedSat, 10); if (savedImgs === "true") isImagesHidden = true; if (savedReading === "true") isReadingMode = true; applyFontSize(); applyFilters(); if (isImagesHidden) { const allImages = document.querySelectorAll("img"); allImages.forEach((img) => img.classList.add("hidden-image")); const btnToggleImages = document.getElementById("toggle-images"); if (btnToggleImages) { btnToggleImages.textContent = "Mostrar Imagens"; } } if (isReadingMode) { document.body.classList.add("reading-mode"); } else { document.body.classList.remove("reading-mode"); } const changedFromDefault = currentFontSize !== 100 || isGrayscale !== false || saturationValue !== 100 || isImagesHidden !== false || isReadingMode !== false; if (changedFromDefault) { showResetButton(); } else { hideResetButton(); } }