Compare commits
3 Commits
main
...
ChatSuport
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
024e730687 | ||
|
|
c9d1457775 | ||
|
|
b2e2423978 |
@ -23,6 +23,6 @@
|
||||
<!-- <script src="%PUBLIC_URL%/vendors/perfect-scrollbar/perfect-scrollbar.min.js"></script>
|
||||
<script src="%PUBLIC_URL%/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="%PUBLIC_URL%/js/main.js"></script> -->
|
||||
<script src="https://website-widgets.pages.dev/dist/sienna.min.js" defer></script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
47
src/App.css
47
src/App.css
@ -45,3 +45,50 @@ html[data-bs-theme="dark"] .App-header {
|
||||
html[data-bs-theme="dark"] .App-link {
|
||||
color: #bb86fc;
|
||||
}
|
||||
|
||||
.top-right-chat-button-wrapper {
|
||||
position: fixed; /* 'fixed' faz ele flutuar mesmo com scroll */
|
||||
top: 20px;
|
||||
right: 20px;
|
||||
z-index: 1001; /* Garante que fique acima de outros elementos */
|
||||
}
|
||||
|
||||
/* App.css */
|
||||
|
||||
/* Container principal */
|
||||
.app-wrapper {
|
||||
display: flex; /* Organiza o conteúdo principal e o chat lado a lado */
|
||||
}
|
||||
|
||||
.main-content {
|
||||
position: relative; /* Essencial para ser o 'pai' */
|
||||
flex-grow: 1;
|
||||
transition: margin-right 0.4s ease-in-out;
|
||||
}
|
||||
.main-content.chat-open {
|
||||
margin-right: 350px;
|
||||
}
|
||||
|
||||
/* Posicionamento do botão que abre o chat */
|
||||
.chat-button-container {
|
||||
position: fixed;
|
||||
bottom: 20px;
|
||||
right: 20px;
|
||||
z-index: 999;
|
||||
}
|
||||
|
||||
|
||||
.floating-buttons-container {
|
||||
|
||||
position: fixed;
|
||||
bottom: 20px;
|
||||
right: 20px;
|
||||
z-index: 1000;
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
transition: right 0.4s ease-in-out;
|
||||
}
|
||||
|
||||
.floating-buttons-container.chat-open {
|
||||
right: 370px;
|
||||
}
|
||||
52
src/App.js
52
src/App.js
@ -1,40 +1,58 @@
|
||||
import React, { useState } from "react";
|
||||
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
|
||||
import './App.css';
|
||||
|
||||
// Suas páginas
|
||||
import LandingPage from './pages/LandingPage';
|
||||
import Login from "./pages/Login";
|
||||
import Register from "./pages/Register";
|
||||
import Forgot from "./pages/ForgotPassword";
|
||||
import PerfilSecretaria from "./perfis/perfil_secretaria/PerfilSecretaria";
|
||||
import LandingPage from './pages/LandingPage';
|
||||
import PerfilFinanceiro from "./perfis/perfil_financeiro/PerfilFinanceiro";
|
||||
import Perfiladm from "./perfis/Perfil_adm/Perfiladm";
|
||||
import PerfilMedico from "./perfis/Perfil_medico/PerfilMedico";
|
||||
|
||||
// Componentes globais de acessibilidade
|
||||
// Componentes globais
|
||||
import VlibrasWidget from "./components/VlibrasWidget";
|
||||
|
||||
import BotaoAcessibilidade from "./components/botaoacessibilidade.jsx";
|
||||
import ChatToggleButton from './components/ChatButton/ChatButton';
|
||||
import ChatSidebar from './components/ChatSidebar/ChatSidebar';
|
||||
|
||||
function App() {
|
||||
const [isChatOpen, setIsChatOpen] = useState(false);
|
||||
|
||||
const toggleChat = () => {
|
||||
setIsChatOpen(!isChatOpen);
|
||||
};
|
||||
|
||||
return (
|
||||
<Router>
|
||||
<VlibrasWidget />
|
||||
<BotaoAcessibilidade />
|
||||
<div className="app-wrapper">
|
||||
<div className={`main-content ${isChatOpen ? 'chat-open' : ''}`}>
|
||||
<VlibrasWidget />
|
||||
|
||||
<Routes>
|
||||
<Route path="/" element={<LandingPage />} />
|
||||
<Route path="/login" element={<Login />} />
|
||||
<Route path="/register" element={<Register />} />
|
||||
<Route path="/forgotPassword" element={<Forgot />} />
|
||||
<Route path="/secretaria/*" element={<PerfilSecretaria />} />
|
||||
<Route path="/financeiro/*" element={<PerfilFinanceiro />} />
|
||||
<Route path="/medico/*" element={<PerfilMedico />} />
|
||||
<Route path="/admin/*" element={<Perfiladm />} />
|
||||
<Route path="*" element={<h2>Página não encontrada</h2>} />
|
||||
</Routes>
|
||||
<div className={`floating-buttons-container ${isChatOpen ? 'chat-open' : ''}`}>
|
||||
<BotaoAcessibilidade />
|
||||
<ChatToggleButton onClick={toggleChat} />
|
||||
</div>
|
||||
|
||||
<Routes>
|
||||
<Route path="/" element={<LandingPage />} />
|
||||
<Route path="/login" element={<Login />} />
|
||||
<Route path="/register" element={<Register />} />
|
||||
<Route path="/forgotPassword" element={<Forgot />} />
|
||||
<Route path="/secretaria/*" element={<PerfilSecretaria />} />
|
||||
<Route path="/financeiro/*" element={<PerfilFinanceiro />} />
|
||||
<Route path="/medico/*" element={<PerfilMedico />} />
|
||||
<Route path="/admin/*" element={<Perfiladm />} />
|
||||
<Route path="*" element={<h2>Página não encontrada</h2>} />
|
||||
</Routes>
|
||||
</div>
|
||||
|
||||
<ChatSidebar isOpen={isChatOpen} onClose={toggleChat} />
|
||||
</div>
|
||||
</Router>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
|
||||
|
||||
27
src/components/ChatButton/ChatButton.css
Normal file
27
src/components/ChatButton/ChatButton.css
Normal file
@ -0,0 +1,27 @@
|
||||
|
||||
.chat-toggle-button {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
border-radius: 50%;
|
||||
background-color: #007bff;
|
||||
color: white;
|
||||
border: none;
|
||||
box-shadow: 0 4px 8px rgba(0,0,0,0.2);
|
||||
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
transition: background-color 0.3s ease;
|
||||
}
|
||||
|
||||
.chat-toggle-button:hover {
|
||||
background-color: #0056b3;
|
||||
}
|
||||
|
||||
.chat-toggle-button svg {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
fill: white;
|
||||
}
|
||||
15
src/components/ChatButton/ChatButton.jsx
Normal file
15
src/components/ChatButton/ChatButton.jsx
Normal file
@ -0,0 +1,15 @@
|
||||
import React from 'react';
|
||||
import './ChatButton.css';
|
||||
|
||||
const ChatButton = ({ onClick }) => {
|
||||
return (
|
||||
<button className="chat-toggle-button" onClick={onClick} aria-label="Abrir chat">
|
||||
{/* Ícone de Chat (SVG) */}
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
<path d="M20 2H4c-1.1 0-2 .9-2 2v18l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2z"></path>
|
||||
</svg>
|
||||
</button>
|
||||
);
|
||||
};
|
||||
|
||||
export default ChatButton;
|
||||
119
src/components/ChatSidebar/ChatSidebar.css
Normal file
119
src/components/ChatSidebar/ChatSidebar.css
Normal file
@ -0,0 +1,119 @@
|
||||
|
||||
.chat-sidebar {
|
||||
height: 100vh;
|
||||
width: 350px;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
background-color: #FFFFFF; /* Fundo branco limpo, como os cards */
|
||||
color: #333; /* Texto escuro padrão */
|
||||
font-family: Arial, sans-serif; /* Use a mesma fonte do seu site, se souber */
|
||||
transform: translateX(100%);
|
||||
transition: transform 0.4s ease-in-out;
|
||||
box-shadow: -2px 0 15px rgba(0, 0, 0, 0.1);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.chat-sidebar.open {
|
||||
transform: translateX(0);
|
||||
}
|
||||
.chat-header {
|
||||
padding: 15px 20px;
|
||||
background-color: #F8F9FA; /* Cinza bem claro, como o fundo do site */
|
||||
border-bottom: 1px solid #E9ECEF; /* Borda sutil */
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.chat-header h3 {
|
||||
margin: 0;
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: #212529; /* Cor do título dos cards */
|
||||
}
|
||||
|
||||
.chat-close-button {
|
||||
background: none;
|
||||
border: none;
|
||||
font-size: 24px;
|
||||
cursor: pointer;
|
||||
color: #6c757d; /* Cinza sutil para o ícone de fechar */
|
||||
transition: color 0.2s;
|
||||
}
|
||||
.chat-close-button:hover {
|
||||
color: #000;
|
||||
}
|
||||
|
||||
/* Área das Mensagens */
|
||||
.chat-messages {
|
||||
flex-grow: 1;
|
||||
padding: 20px;
|
||||
overflow-y: auto;
|
||||
background-color: #F8F9FA; /* Fundo igual ao header para consistência */
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px; /* Espaçamento entre as mensagens */
|
||||
}
|
||||
|
||||
/* Adicionando estilo para os balões de mensagem */
|
||||
.message {
|
||||
padding: 10px 15px;
|
||||
border-radius: 18px;
|
||||
max-width: 80%;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.message.received {
|
||||
background-color: #E9ECEF; /* Cinza claro para mensagens recebidas */
|
||||
color: #212529;
|
||||
align-self: flex-start; /* Alinha à esquerda */
|
||||
border-bottom-left-radius: 4px; /* Detalhe de estilo */
|
||||
}
|
||||
|
||||
.message.sent {
|
||||
background-color: #6C63FF; /* Cor principal do seu site */
|
||||
color: white;
|
||||
align-self: flex-end; /* Alinha à direita */
|
||||
border-bottom-right-radius: 4px; /* Detalhe de estilo */
|
||||
}
|
||||
|
||||
.chat-input-area {
|
||||
padding: 15px 20px;
|
||||
display: flex;
|
||||
gap: 10px; /* Espaço entre o input e o botão */
|
||||
border-top: 1px solid #E9ECEF;
|
||||
background-color: #FFFFFF; /* Fundo branco para destacar */
|
||||
}
|
||||
|
||||
.chat-input-area input {
|
||||
flex-grow: 1;
|
||||
border: 1px solid #DEE2E6; /* Borda padrão */
|
||||
border-radius: 8px; /* Bordas arredondadas como os elementos do site */
|
||||
padding: 12px 15px;
|
||||
font-size: 15px;
|
||||
color: #333;
|
||||
transition: border-color 0.2s;
|
||||
}
|
||||
|
||||
.chat-input-area input:focus {
|
||||
outline: none;
|
||||
border-color: #6C63FF; /* Destaque com a cor principal */
|
||||
box-shadow: 0 0 0 2px rgba(108, 99, 255, 0.2);
|
||||
}
|
||||
|
||||
.chat-input-area button {
|
||||
background-color: #6C63FF; /* Cor principal do seu site */
|
||||
border: none;
|
||||
color: white;
|
||||
padding: 0 25px;
|
||||
border-radius: 8px; /* Mesma borda do input */
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.2s;
|
||||
}
|
||||
.chat-input-area button:hover {
|
||||
background-color: #574ee6; /* Um tom um pouco mais escuro ao passar o mouse */
|
||||
}
|
||||
79
src/components/ChatSidebar/ChatSidebar.jsx
Normal file
79
src/components/ChatSidebar/ChatSidebar.jsx
Normal file
@ -0,0 +1,79 @@
|
||||
import React, { useState, useEffect, useRef } from 'react';
|
||||
import './ChatSidebar.css';
|
||||
|
||||
const ChatSidebar = ({ isOpen, onClose }) => {
|
||||
|
||||
const [messages, setMessages] = useState([
|
||||
{ id: 1, text: 'Olá! Como podemos ajudar você hoje?', sender: 'support' }
|
||||
]);
|
||||
const [inputValue, setInputValue] = useState('');
|
||||
const messagesEndRef = useRef(null);
|
||||
const sidebarClassName = `chat-sidebar ${isOpen ? 'open' : ''}`;
|
||||
const scrollToBottom = () => {
|
||||
messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
scrollToBottom();
|
||||
}, [messages]);
|
||||
|
||||
const handleSendMessage = () => {
|
||||
if (inputValue.trim() === '') return;
|
||||
const newMessage = {
|
||||
id: messages.length + 1,
|
||||
text: inputValue,
|
||||
sender: 'user'
|
||||
};
|
||||
setMessages(currentMessages => [...currentMessages, newMessage]);
|
||||
setInputValue('');
|
||||
setTimeout(() => {
|
||||
const supportReply = {
|
||||
id: messages.length + 2,
|
||||
text: 'Obrigado por sua mensagem. Um de nossos atendentes responderá em breve.',
|
||||
sender: 'support'
|
||||
};
|
||||
setMessages(currentMessages => [...currentMessages, supportReply]);
|
||||
}, 1000);
|
||||
};
|
||||
const handleKeyPress = (event) => {
|
||||
if (event.key === 'Enter') {
|
||||
handleSendMessage();
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={sidebarClassName}>
|
||||
<div className="chat-header">
|
||||
<h3>Suporte Online</h3>
|
||||
<button onClick={onClose} className="chat-close-button">X</button>
|
||||
</div>
|
||||
|
||||
<div className="chat-messages">
|
||||
{/* Mapeia a lista de mensagens e cria um balão para cada uma */}
|
||||
{messages.map(message => (
|
||||
<div
|
||||
key={message.id}
|
||||
className={`message ${message.sender === 'user' ? 'sent' : 'received'}`}
|
||||
>
|
||||
{message.text}
|
||||
</div>
|
||||
))}
|
||||
{/* Elemento invisível no final para o scroll automático */}
|
||||
<div ref={messagesEndRef} />
|
||||
</div>
|
||||
|
||||
<div className="chat-input-area">
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Digite sua mensagem..."
|
||||
value={inputValue}
|
||||
onChange={(e) => setInputValue(e.target.value)}
|
||||
onKeyPress={handleKeyPress}
|
||||
/>
|
||||
<button onClick={handleSendMessage}>Enviar</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ChatSidebar;
|
||||
@ -46,7 +46,7 @@ const TrocardePerfis = () => {
|
||||
value={selectedProfile}
|
||||
onChange={handleSelectChange}
|
||||
>
|
||||
<option value="">Selecionar perfil</option>
|
||||
<option value="" disabled invisible>Selecionar perfil</option>
|
||||
{options.map((opt) => (
|
||||
<option key={opt.key} value={opt.route}>
|
||||
{opt.label}
|
||||
|
||||
@ -1,272 +1,198 @@
|
||||
/* --- ESTILO PARA ESCONDER O BOTÃO ORIGINAL DO VLIBRAS --- */
|
||||
@import url('https://fonts.cdnfonts.com/css/open-dyslexic');
|
||||
|
||||
[vw-access-button] {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/* --- ESTILOS GERAIS DO COMPONENTE --- */
|
||||
.container-acessibilidade {
|
||||
position: fixed;
|
||||
bottom: 20px;
|
||||
right: 20px;
|
||||
z-index: 99998;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
pointer-events: none; /* Impede cliques no contêiner */
|
||||
}
|
||||
|
||||
.botao-flutuante-acessibilidade {
|
||||
position: relative;
|
||||
z-index: 2; /* Acima do menu */
|
||||
background: linear-gradient(45deg, #007bff, #0056b3);
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 50%;
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
border-radius: 50%;
|
||||
background-color: #007bff;
|
||||
color: white;
|
||||
border: none;
|
||||
box-shadow: 0 4px 8px rgba(0,0,0,0.2);
|
||||
cursor: pointer;
|
||||
box-shadow: 0 5px 15px rgba(0, 91, 179, 0.4);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
transition: transform 0.2s ease-in-out, box-shadow 0.2s ease;
|
||||
margin-top: 15px; /* Distância do menu */
|
||||
pointer-events: auto; /* Permite que o botão seja clicável */
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.botao-flutuante-acessibilidade:hover {
|
||||
transform: scale(1.1);
|
||||
box-shadow: 0 8px 20px rgba(0, 91, 179, 0.5);
|
||||
}
|
||||
|
||||
/* --- ESTILOS DO MENU "BALÃO" --- */
|
||||
.menu-opcoes {
|
||||
background-color: #ffffff;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.1);
|
||||
padding: 8px;
|
||||
position: absolute;
|
||||
bottom: 70px;
|
||||
right: 0;
|
||||
width: 280px;
|
||||
z-index: 1; /* Abaixo do botão principal */
|
||||
border: 1px solid #e9ecef;
|
||||
|
||||
/* Animação */
|
||||
transform-origin: bottom center;
|
||||
transform: translateY(10px) scale(0.95);
|
||||
max-height: calc(100vh - 100px);
|
||||
overflow-y: auto;
|
||||
background-color: white;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 6px 12px rgba(0,0,0,0.3);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
padding: 15px;
|
||||
transform: scale(0.95);
|
||||
transform-origin: bottom right;
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
transition: all 0.2s ease;
|
||||
pointer-events: auto; /* Permite que o menu seja clicável */
|
||||
transition: transform 0.2s ease, opacity 0.2s ease, visibility 0.2s;
|
||||
}
|
||||
|
||||
.menu-opcoes.aberto {
|
||||
transform: translateY(0) scale(1);
|
||||
transform: scale(1);
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.menu-titulo {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: #6c757d;
|
||||
padding: 8px 12px;
|
||||
border-bottom: 1px solid #f1f3f5;
|
||||
margin-bottom: 5px;
|
||||
transition: color 0.2s ease, border-bottom-color 0.2s ease;
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 10px;
|
||||
text-align: center;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
/* --- ESTILOS DOS BOTÕES E DA CHECKBOX NO MENU --- */
|
||||
.menu-opcoes button,
|
||||
.checkbox-label-button {
|
||||
width: 100%;
|
||||
padding: 12px;
|
||||
border-radius: 6px;
|
||||
border: 1px solid #ddd;
|
||||
background-color: #f9f9f9;
|
||||
cursor: pointer;
|
||||
text-align: left;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
padding: 12px;
|
||||
text-align: left;
|
||||
cursor: pointer;
|
||||
font-size: 16px;
|
||||
color: #212529;
|
||||
width: 100%;
|
||||
border-radius: 8px;
|
||||
transition: background-color 0.2s ease, color 0.2s ease;
|
||||
gap: 10px;
|
||||
font-size: 15px;
|
||||
color: #333;
|
||||
transition: background-color 0.2s;
|
||||
}
|
||||
|
||||
.menu-opcoes button:hover,
|
||||
.checkbox-label-button:hover {
|
||||
background-color: #f8f9fa;
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
|
||||
/* --- ESTILO DO INTERRUPTOR (CHECKBOX) --- */
|
||||
.checkbox-label-button {
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.checkbox-label-button input[type="checkbox"] {
|
||||
appearance: none;
|
||||
-webkit-appearance: none;
|
||||
position: relative;
|
||||
width: 44px;
|
||||
height: 24px;
|
||||
background-color: #ced4da;
|
||||
border-radius: 12px;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.3s ease-in-out;
|
||||
}
|
||||
|
||||
.checkbox-label-button input[type="checkbox"]::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 2px;
|
||||
left: 2px;
|
||||
margin-left: auto;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
background-color: white;
|
||||
border-radius: 50%;
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,0.2);
|
||||
transition: transform 0.3s ease-in-out;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.checkbox-label-button input[type="checkbox"]:checked {
|
||||
background-color: #0d6efd;
|
||||
}
|
||||
|
||||
.checkbox-label-button input[type="checkbox"]:checked::before {
|
||||
transform: translateX(20px);
|
||||
}
|
||||
|
||||
|
||||
/* --- ✨ NOVOS ESTILOS PARA O CONTROLE DE FONTE ✨ --- */
|
||||
|
||||
/* Tamanho da Fonte */
|
||||
.font-size-control {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 8px 12px;
|
||||
color: #212529;
|
||||
transition: color 0.2s ease;
|
||||
border-top: 1px solid #f1f3f5;
|
||||
margin-top: 5px;
|
||||
flex-direction: column;
|
||||
padding: 10px;
|
||||
background-color: rgba(0, 0, 0, 0.05);
|
||||
border-radius: 8px;
|
||||
margin-bottom: 5px;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.font-size-label {
|
||||
font-size: 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.font-size-buttons {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.font-size-buttons button {
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
||||
font-weight: bold;
|
||||
font-size: 16px;
|
||||
background-color: #e9ecef;
|
||||
color: #495057;
|
||||
border: 1px solid #dee2e6;
|
||||
border-radius: 6px;
|
||||
width: 36px;
|
||||
height: 32px;
|
||||
padding: 0;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
transition: background-color 0.2s ease, color 0.2s ease;
|
||||
}
|
||||
|
||||
.font-size-buttons button:hover {
|
||||
background-color: #dee2e6;
|
||||
}
|
||||
|
||||
.font-size-buttons button:disabled {
|
||||
background-color: #f8f9fa;
|
||||
color: #adb5bd;
|
||||
cursor: not-allowed;
|
||||
border-color: #f1f3f5;
|
||||
}
|
||||
|
||||
.font-size-display {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: #495057;
|
||||
min-width: 45px;
|
||||
font-size: 15px;
|
||||
}
|
||||
.font-size-buttons {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
.font-size-buttons button {
|
||||
border-radius: 50%;
|
||||
width: 38px;
|
||||
height: 38px;
|
||||
border: 1px solid #ddd;
|
||||
background-color: #fff;
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
color: #333;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0;
|
||||
}
|
||||
.font-size-buttons span {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
min-width: 50px;
|
||||
text-align: center;
|
||||
transition: color 0.2s ease;
|
||||
}
|
||||
|
||||
/* Dark mode styles */
|
||||
html[data-bs-theme="dark"] {
|
||||
|
||||
/* Floating button */
|
||||
.botao-flutuante-acessibilidade {
|
||||
background: linear-gradient(45deg, #212529, #343a40);
|
||||
color: #f8f9fa;
|
||||
box-shadow: 0 5px 15px rgba(33, 37, 41, 0.4);
|
||||
}
|
||||
.botao-flutuante-acessibilidade:hover {
|
||||
box-shadow: 0 8px 20px rgba(33, 37, 41, 0.5);
|
||||
}
|
||||
|
||||
/* Menu balloon */
|
||||
.menu-opcoes {
|
||||
background-color: #23272b;
|
||||
border: 1px solid #343a40;
|
||||
box-shadow: 0 8px 25px rgba(0,0,0,0.4);
|
||||
}
|
||||
.menu-titulo {
|
||||
color: #adb5bd;
|
||||
border-bottom: 1px solid #343a40;
|
||||
}
|
||||
|
||||
/* Menu buttons and checkbox */
|
||||
.menu-opcoes button,
|
||||
.checkbox-label-button {
|
||||
color: #f8f9fa;
|
||||
}
|
||||
.menu-opcoes button:hover,
|
||||
.checkbox-label-button:hover {
|
||||
background-color: #343a40;
|
||||
}
|
||||
|
||||
/* Checkbox switch */
|
||||
.checkbox-label-button input[type="checkbox"] {
|
||||
background-color: #495057;
|
||||
}
|
||||
.checkbox-label-button input[type="checkbox"]:checked {
|
||||
background-color: #0d6efd;
|
||||
}
|
||||
.checkbox-label-button input[type="checkbox"]::before {
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
|
||||
/* Font size control */
|
||||
.font-size-control {
|
||||
color: #f8f9fa;
|
||||
border-top: 1px solid #343a40;
|
||||
}
|
||||
.font-size-label {
|
||||
color: #f8f9fa;
|
||||
}
|
||||
.font-size-buttons button {
|
||||
background-color: #343a40;
|
||||
color: #f8f9fa;
|
||||
border: 1px solid #495057;
|
||||
}
|
||||
.font-size-buttons button:hover {
|
||||
background-color: #495057;
|
||||
}
|
||||
.font-size-buttons button:disabled {
|
||||
background-color: #23272b;
|
||||
color: #6c757d;
|
||||
border-color: #343a40;
|
||||
}
|
||||
.font-size-display {
|
||||
color: #f8f9fa;
|
||||
}
|
||||
/* Fonte para Dislexia */
|
||||
.dyslexia-font-active * {
|
||||
font-family: 'Open-Dyslexic', sans-serif !important;
|
||||
}
|
||||
|
||||
/* Espaçamento e Altura */
|
||||
.letter-spacing-active p, .letter-spacing-active li, .letter-spacing-active span, .letter-spacing-active a, .letter-spacing-active div, .letter-spacing-active td, .letter-spacing-active h1, .letter-spacing-active h2, .letter-spacing-active h3, .letter-spacing-active h4, .letter-spacing-active h5, .letter-spacing-active h6 {
|
||||
letter-spacing: 1.5px !important;
|
||||
}
|
||||
.line-height-active p, .line-height-active li, .line-height-active span, .line-height-active a, .line-height-active div, .line-height-active td, .line-height-active h1, .line-height-active h2, .line-height-active h3, .line-height-active h4, .line-height-active h5, .line-height-active h6 {
|
||||
line-height: 3 !important;
|
||||
}
|
||||
|
||||
/* Guia de Leitura */
|
||||
.reading-guide-mask {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
background: rgba(0, 0, 0, 0.7);
|
||||
z-index: 99999;
|
||||
pointer-events: none;
|
||||
transition: all 0.05s ease-out;
|
||||
}
|
||||
.reading-guide-top {
|
||||
top: 0;
|
||||
height: 0;
|
||||
}
|
||||
.reading-guide-bottom {
|
||||
bottom: 0;
|
||||
top: 100vh;
|
||||
}
|
||||
|
||||
/* Cursor Grande */
|
||||
.big-cursor-active, .big-cursor-active * {
|
||||
cursor: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24"><path fill="black" stroke="white" stroke-width="2" d="M13.64,21.97C13.14,22.21 12.54,22 12.31,21.5L10.13,16.76L7.62,18.78C7.45,18.92 7.24,19 7,19A1,1 0 0,1 6,18V4A1,1 0 0,1 7,3C7.24,3 7.45,3.08 7.62,3.22L16.39,10.22C16.78,10.5 16.88,11.05 16.6,11.45L13.64,21.97Z" /></svg>') 1 1, auto !important;
|
||||
}
|
||||
|
||||
/* Filtros de Daltonismo */
|
||||
.colorblind-protanopia { filter: url(#protanopia); }
|
||||
.colorblind-deuteranopia { filter: url(#deuteranopia); }
|
||||
.colorblind-tritanopia { filter: url(#tritanopia); }
|
||||
.colorblind-achromatopsia { filter: url(#achromatopsia); }
|
||||
|
||||
.acessibilidade-select-control {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
background-color: rgba(0, 0, 0, 0.05);
|
||||
padding: 10px;
|
||||
border-radius: 8px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
.acessibilidade-select-control label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
font-weight: 600;
|
||||
font-size: 15px;
|
||||
}
|
||||
.acessibilidade-select-control select {
|
||||
width: 100%;
|
||||
padding: 8px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #ccc;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
/* Dark Mode */
|
||||
.dark-mode .menu-opcoes { background-color: #2d2d2d; color: #f1f1f1; }
|
||||
.dark-mode .menu-titulo { color: #f1f1f1; }
|
||||
.dark-mode .menu-opcoes button, .dark-mode .checkbox-label-button { background-color: #424242; border-color: #555; color: #f1f1f1; }
|
||||
.dark-mode .menu-opcoes button:hover, .dark-mode .checkbox-label-button:hover { background-color: #535353; }
|
||||
.dark-mode .font-size-control, .dark-mode .acessibilidade-select-control { background-color: rgba(255, 255, 255, 0.1); }
|
||||
.dark-mode .font-size-buttons button { background-color: #535353; color: #f1f1f1; border-color: #666; }
|
||||
.dark-mode .acessibilidade-select-control select { background-color: #535353; color: #f1f1f1; border-color: #666; }
|
||||
@ -2,41 +2,131 @@ import React, { useState, useEffect, useRef } from 'react';
|
||||
import './botaoacessibilidade.css'; // Importando o CSS
|
||||
import { setTheme } from '../assets/static/js/components/dark';
|
||||
|
||||
// Componente para o Guia de Leitura
|
||||
function GuiaDeLeitura() {
|
||||
const topMaskRef = useRef(null);
|
||||
const bottomMaskRef = useRef(null);
|
||||
useEffect(() => {
|
||||
const handleMouseMove = (e) => {
|
||||
if (topMaskRef.current && bottomMaskRef.current) {
|
||||
const windowHeight = 40;
|
||||
const offset = windowHeight / 2;
|
||||
topMaskRef.current.style.height = `${e.clientY - offset}px`;
|
||||
bottomMaskRef.current.style.top = `${e.clientY + offset}px`;
|
||||
}
|
||||
};
|
||||
window.addEventListener('mousemove', handleMouseMove);
|
||||
return () => { window.removeEventListener('mousemove', handleMouseMove); };
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div ref={topMaskRef} className="reading-guide-mask reading-guide-top"></div>
|
||||
<div ref={bottomMaskRef} className="reading-guide-mask reading-guide-bottom"></div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
// --- COMPONENTE PRINCIPAL ---
|
||||
function BotaoAcessibilidade() {
|
||||
// Estados de todas as funcionalidades
|
||||
const [isMenuOpen, setIsMenuOpen] = useState(false);
|
||||
const [isReadOnHoverActive, setIsReadOnHoverActive] = useState(false);
|
||||
const [isDarkMode, setIsDarkMode] = useState(false);
|
||||
const [isReadOnHoverActive, setIsReadOnHoverActive] = useState(false);
|
||||
const [fontSize, setFontSize] = useState(1);
|
||||
const [isBigCursor, setIsBigCursor] = useState(false);
|
||||
const [colorblindMode, setColorblindMode] = useState('none');
|
||||
const [isReadingGuide, setIsReadingGuide] = useState(false);
|
||||
const [isDyslexiaFont, setIsDyslexiaFont] = useState(false);
|
||||
const [isLetterSpacing, setIsLetterSpacing] = useState(false);
|
||||
const [isLineHeight, setIsLineHeight] = useState(false);
|
||||
const lastSpokenTargetRef = useRef(null);
|
||||
|
||||
// Efeitos para aplicar as funcionalidades na página
|
||||
useEffect(() => { setTheme(isDarkMode ? "dark" : "light", true); }, [isDarkMode]);
|
||||
useEffect(() => {
|
||||
setTheme(isDarkMode ? "dark" : "light", true);
|
||||
}, [isDarkMode]);
|
||||
|
||||
const originalFontSize = document.documentElement.style.fontSize;
|
||||
document.documentElement.style.fontSize = `${fontSize * 100}%`;
|
||||
return () => { document.documentElement.style.fontSize = originalFontSize; };
|
||||
}, [fontSize]);
|
||||
useEffect(() => {
|
||||
if (!isReadOnHoverActive) {
|
||||
window.speechSynthesis.cancel();
|
||||
return;
|
||||
document.body.classList.toggle('big-cursor-active', isBigCursor);
|
||||
return () => { document.body.classList.remove('big-cursor-active'); };
|
||||
}, [isBigCursor]);
|
||||
useEffect(() => {
|
||||
document.body.classList.toggle('dyslexia-font-active', isDyslexiaFont);
|
||||
return () => { document.body.classList.remove('dyslexia-font-active'); };
|
||||
}, [isDyslexiaFont]);
|
||||
useEffect(() => {
|
||||
document.body.classList.toggle('letter-spacing-active', isLetterSpacing);
|
||||
return () => { document.body.classList.remove('letter-spacing-active'); };
|
||||
}, [isLetterSpacing]);
|
||||
useEffect(() => {
|
||||
document.body.classList.toggle('line-height-active', isLineHeight);
|
||||
return () => { document.body.classList.remove('line-height-active'); };
|
||||
}, [isLineHeight]);
|
||||
useEffect(() => {
|
||||
const classesToRemove = ['colorblind-protanopia', 'colorblind-deuteranopia', 'colorblind-tritanopia', 'colorblind-achromatopsia'];
|
||||
document.documentElement.classList.remove(...classesToRemove);
|
||||
if (colorblindMode !== 'none') {
|
||||
document.documentElement.classList.add(`colorblind-${colorblindMode}`);
|
||||
}
|
||||
const handleMouseOver = (event) => {
|
||||
const target = event.target;
|
||||
if (target && target !== lastSpokenTargetRef.current && target.innerText) {
|
||||
const text = target.innerText.trim();
|
||||
if (text.length > 0 && ['P', 'H1', 'H2', 'H3', 'BUTTON', 'A', 'LI', 'LABEL'].includes(target.tagName)) {
|
||||
lastSpokenTargetRef.current = target;
|
||||
}, [colorblindMode]);
|
||||
// VERSÃO DEFINITIVA - Muito mais abrangente
|
||||
useEffect(() => {
|
||||
if (!isReadOnHoverActive) {
|
||||
window.speechSynthesis.cancel();
|
||||
return;
|
||||
}
|
||||
|
||||
const handleMouseOver = (event) => {
|
||||
// Seletor muito mais completo, incluindo DIVs, SPANs, células de tabela, imagens e papéis de acessibilidade
|
||||
const selector = 'P, H1, H2, H3, H4, H5, H6, BUTTON, A, LI, LABEL, SPAN, TD, TH, DT, DD, FIGCAPTION, [role="button"], [role="link"], [role="menuitem"], IMG';
|
||||
const relevantElement = event.target.closest(selector);
|
||||
|
||||
if (relevantElement && relevantElement !== lastSpokenTargetRef.current) {
|
||||
let textToSpeak = '';
|
||||
|
||||
// Lógica especial para IMAGENS: lê o atributo "alt"
|
||||
if (relevantElement.tagName === 'IMG') {
|
||||
textToSpeak = relevantElement.getAttribute('alt');
|
||||
}
|
||||
// Lógica para outros elementos: prioriza aria-label, depois title, e por último o texto interno
|
||||
else {
|
||||
textToSpeak =
|
||||
relevantElement.getAttribute('aria-label') ||
|
||||
relevantElement.getAttribute('title') ||
|
||||
relevantElement.innerText;
|
||||
}
|
||||
|
||||
if (textToSpeak) {
|
||||
textToSpeak = textToSpeak.trim();
|
||||
|
||||
// Evita ler elementos que só têm elementos filhos, mas nenhum texto próprio direto
|
||||
const hasTextAndNoChildren = textToSpeak.length > 0 && relevantElement.children.length === 0;
|
||||
const hasTextAndIsBlock = textToSpeak.length > 0 && !['SPAN', 'A', 'STRONG', 'EM'].includes(relevantElement.tagName);
|
||||
|
||||
if (hasTextAndNoChildren || hasTextAndIsBlock) {
|
||||
lastSpokenTargetRef.current = relevantElement;
|
||||
window.speechSynthesis.cancel();
|
||||
const utterance = new SpeechSynthesisUtterance(text);
|
||||
const utterance = new SpeechSynthesisUtterance(textToSpeak);
|
||||
utterance.lang = 'pt-BR';
|
||||
window.speechSynthesis.speak(utterance);
|
||||
}
|
||||
}
|
||||
};
|
||||
document.body.addEventListener('mouseover', handleMouseOver);
|
||||
return () => {
|
||||
document.body.removeEventListener('mouseover', handleMouseOver);
|
||||
window.speechSynthesis.cancel();
|
||||
};
|
||||
}, [isReadOnHoverActive]);
|
||||
}
|
||||
};
|
||||
|
||||
document.body.addEventListener('mouseover', handleMouseOver);
|
||||
return () => {
|
||||
document.body.removeEventListener('mouseover', handleMouseOver);
|
||||
window.speechSynthesis.cancel();
|
||||
};
|
||||
}, [isReadOnHoverActive]);
|
||||
|
||||
// Funções de controle
|
||||
const handleIncreaseFontSize = () => setFontSize(prevSize => Math.min(prevSize + 0.1, 1.6));
|
||||
const handleDecreaseFontSize = () => setFontSize(prevSize => Math.max(prevSize - 0.1, 0.8));
|
||||
const handleVlibrasClick = () => {
|
||||
const originalVlibrasButton = document.querySelector('[vw-access-button]');
|
||||
if (originalVlibrasButton) {
|
||||
@ -47,53 +137,96 @@ function BotaoAcessibilidade() {
|
||||
setIsMenuOpen(false);
|
||||
};
|
||||
|
||||
const handleReadAloud = () => {
|
||||
const selectedText = window.getSelection().toString().trim();
|
||||
if (selectedText) {
|
||||
window.speechSynthesis.cancel();
|
||||
const utterance = new SpeechSynthesisUtterance(selectedText);
|
||||
utterance.lang = 'pt-BR';
|
||||
window.speechSynthesis.speak(utterance);
|
||||
} else {
|
||||
alert("Por favor, selecione um texto para ler em voz alta.");
|
||||
}
|
||||
setIsMenuOpen(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={`container-acessibilidade ${isDarkMode ? 'dark-mode' : ''}`}>
|
||||
{isReadingGuide && <GuiaDeLeitura />}
|
||||
<svg style={{ position: 'absolute', height: 0, width: 0 }}>
|
||||
<defs>
|
||||
<filter id="protanopia"><feColorMatrix in="SourceGraphic" type="matrix" values="0.567, 0.433, 0, 0, 0, 0.558, 0.442, 0, 0, 0, 0, 0.242, 0.758, 0, 0, 0, 0, 0, 1, 0"/></filter>
|
||||
<filter id="deuteranopia"><feColorMatrix in="SourceGraphic" type="matrix" values="0.625, 0.375, 0, 0, 0, 0.7, 0.3, 0, 0, 0, 0, 0.3, 0.7, 0, 0, 0, 0, 0, 1, 0"/></filter>
|
||||
<filter id="tritanopia"><feColorMatrix in="SourceGraphic" type="matrix" values="0.95, 0.05, 0, 0, 0, 0, 0.433, 0.567, 0, 0, 0, 0.475, 0.525, 0, 0, 0, 0, 0, 1, 0"/></filter>
|
||||
<filter id="achromatopsia"><feColorMatrix in="SourceGraphic" type="matrix" values="0.299, 0.587, 0.114, 0, 0, 0.299, 0.587, 0.114, 0, 0, 0.299, 0.587, 0.114, 0, 0, 0, 0, 0, 1, 0"/></filter>
|
||||
</defs>
|
||||
</svg>
|
||||
<div className={`menu-opcoes ${isMenuOpen ? 'aberto' : ''}`}>
|
||||
<div className="menu-titulo">Acessibilidade</div>
|
||||
|
||||
<div className="font-size-control">
|
||||
<div className="font-size-label">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><polyline points="4 7 4 4 20 4 20 7"></polyline><line x1="9" y1="20" x2="15" y2="20"></line><line x1="12" y1="4" x2="12" y2="20"></line></svg>
|
||||
Tamanho da Fonte
|
||||
</div>
|
||||
<div className="font-size-buttons">
|
||||
<button onClick={handleDecreaseFontSize} title="Diminuir Fonte">A-</button>
|
||||
<span>{`${Math.round(fontSize * 100)}%`}</span>
|
||||
<button onClick={handleIncreaseFontSize} title="Aumentar Fonte">A+</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="acessibilidade-select-control">
|
||||
<label htmlFor="colorblind-select">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="10"></circle><line x1="2" y1="12" x2="22" y2="12"></line><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"></path></svg>
|
||||
Modo Daltonismo
|
||||
</label>
|
||||
<select id="colorblind-select" value={colorblindMode} onChange={(e) => setColorblindMode(e.target.value)}>
|
||||
<option value="none">Desativado</option>
|
||||
<option value="protanopia">Protanopia</option>
|
||||
<option value="deuteranopia">Deuteranopia</option>
|
||||
<option value="tritanopia">Tritanopia</option>
|
||||
<option value="achromatopsia">Monocromático</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<label htmlFor="darkModeCheckbox" className="checkbox-label-button">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"></path></svg>
|
||||
Modo Escuro
|
||||
<input
|
||||
type="checkbox"
|
||||
id="darkModeCheckbox"
|
||||
checked={isDarkMode}
|
||||
onChange={() => setIsDarkMode(!isDarkMode)}
|
||||
/>
|
||||
<input type="checkbox" id="darkModeCheckbox" checked={isDarkMode} onChange={() => setIsDarkMode(!isDarkMode)} />
|
||||
</label>
|
||||
|
||||
<label htmlFor="dyslexiaFontCheckbox" className="checkbox-label-button">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"></path><line x1="12" y1="9" x2="12" y2="13"></line><line x1="12" y1="17" x2="12.01" y2="17"></line></svg>
|
||||
Fonte para Dislexia
|
||||
<input type="checkbox" id="dyslexiaFontCheckbox" checked={isDyslexiaFont} onChange={() => setIsDyslexiaFont(!isDyslexiaFont)} />
|
||||
</label>
|
||||
|
||||
<label htmlFor="letterSpacingCheckbox" className="checkbox-label-button">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"></path></svg>
|
||||
Espaçamento entre Letras
|
||||
<input type="checkbox" id="letterSpacingCheckbox" checked={isLetterSpacing} onChange={() => setIsLetterSpacing(!isLetterSpacing)} />
|
||||
</label>
|
||||
|
||||
<label htmlFor="lineHeightCheckbox" className="checkbox-label-button">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><line x1="3" y1="12" x2="21" y2="12"></line><line x1="3" y1="6" x2="21" y2="6"></line><line x1="3" y1="18" x2="21" y2="18"></line></svg>
|
||||
Altura da Linha
|
||||
<input type="checkbox" id="lineHeightCheckbox" checked={isLineHeight} onChange={() => setIsLineHeight(!isLineHeight)} />
|
||||
</label>
|
||||
|
||||
<label htmlFor="readingGuideCheckbox" className="checkbox-label-button">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><line x1="8" y1="6" x2="21" y2="6"></line><line x1="8" y1="12" x2="21" y2="12"></line><line x1="8" y1="18" x2="21" y2="18"></line><line x1="3" y1="6" x2="3.01" y2="6"></line><line x1="3" y1="12" x2="3.01" y2="12"></line><line x1="3" y1="18" x2="3.01" y2="18"></line></svg>
|
||||
Guia de Leitura
|
||||
<input type="checkbox" id="readingGuideCheckbox" checked={isReadingGuide} onChange={() => setIsReadingGuide(!isReadingGuide)} />
|
||||
</label>
|
||||
|
||||
<label htmlFor="bigCursorCheckbox" className="checkbox-label-button">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M3 3l7.07 16.97 2.51-7.39 7.39-2.51L3 3z"></path><path d="M13 13l6 6"></path></svg>
|
||||
Cursor Grande
|
||||
<input type="checkbox" id="bigCursorCheckbox" checked={isBigCursor} onChange={() => setIsBigCursor(!isBigCursor)} />
|
||||
</label>
|
||||
|
||||
<label htmlFor="readOnHoverCheckbox" className="checkbox-label-button">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M3 3l7.07 16.97 2.51-7.39 7.39-2.51L3 3z"></path><path d="M13 13l6 6"></path></svg>
|
||||
Leitura instantânea
|
||||
<input
|
||||
type="checkbox"
|
||||
id="readOnHoverCheckbox"
|
||||
checked={isReadOnHoverActive}
|
||||
onChange={() => setIsReadOnHoverActive(!isReadOnHoverActive)}
|
||||
/>
|
||||
<input type="checkbox" id="readOnHoverCheckbox" checked={isReadOnHoverActive} onChange={() => setIsReadOnHoverActive(!isReadOnHoverActive)} />
|
||||
</label>
|
||||
|
||||
{/* ADICIONADO DE VOLTA: Botão para LIBRAS */}
|
||||
<button onClick={handleVlibrasClick}>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M18 11V6a2 2 0 0 0-2-2v0a2 2 0 0 0-2 2v0" /><path d="M14 10V4a2 2 0 0 0-2-2v0a2 2 0 0 0-2 2v2" /><path d="M10 10.5V6a2 2 0 0 0-2-2v0a2 2 0 0 0-2 2v8" /><path d="M18 8a2 2 0 1 1 4 0v6a8 8 0 0 1-8 8h-4a2 2 0 0 1-2-2v-4a2 2 0 0 1 2-2h2.3" /></svg>
|
||||
Traduzir para LIBRAS
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M18 11V6a2 2 0 0 0-2-2v0a2 2 0 0 0-2 2v0" /><path d="M14 10V4a2 2 0 0 0-2-2v0a2 2 0 0 0-2 2v2" /><path d="M10 10.5V6a2 2 0 0 0-2-2v0a2 2 0 0 0-2 2v8" /><path d="M18 8a2 2 0 1 1 4 0v6a8 8 0 0 1-8 8h-4a2 2 0 0 1-2-2v-4a2 2 0 0 1 2-2h2.3" /></svg>
|
||||
Traduzir para LIBRAS
|
||||
</button>
|
||||
</div>
|
||||
<button
|
||||
className="botao-flutuante-acessibilidade"
|
||||
onClick={() => setIsMenuOpen(!isMenuOpen)}
|
||||
title="Menu de Acessibilidade"
|
||||
>
|
||||
|
||||
<button className="botao-flutuante-acessibilidade" onClick={() => setIsMenuOpen(!isMenuOpen)} title="Menu de Acessibilidade">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="30" height="30" fill="white">
|
||||
<path d="M12 2c1.1 0 2 .9 2 2s-.9 2-2 2-2-.9-2-2 .9-2 2-2zm9 7h-6v13h-2v-6h-2v6H9V9H3V7h18v2z" />
|
||||
</svg>
|
||||
@ -101,6 +234,4 @@ function BotaoAcessibilidade() {
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default BotaoAcessibilidade;
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user