Versão inicial em produção

This commit is contained in:
root
2026-08-21 22:57:44 +00:00
commit fb27cd60c0
32 changed files with 3848 additions and 0 deletions
+105
View File
@@ -0,0 +1,105 @@
<?php
/**
* AçãoOpção — autenticação e controle de permissões por página.
* Inclua (require_once) depois de config.php e db.php.
*/
require_once __DIR__ . '/config.php';
require_once __DIR__ . '/db.php';
if (session_status() !== PHP_SESSION_ACTIVE) {
session_start();
}
// Páginas de administração do próprio sistema de acesso. Ficam sempre
// restritas a perfis com acesso_total, independente da tabela `paginas`
// (que serve para as páginas de negócio, essas sim configuráveis por perfil).
const AO_PAGINAS_ADMIN = [
'usuarios' => ['arquivo' => 'usuarios.php', 'nome' => 'Usuários'],
'perfis' => ['arquivo' => 'perfis.php', 'nome' => 'Perfis'],
'paginas_admin' => ['arquivo' => 'paginas_admin.php', 'nome' => 'Páginas'],
];
function ao_usuario_logado() {
return $_SESSION['ao_usuario'] ?? null;
}
function ao_exigir_login() {
if (!ao_usuario_logado()) {
$_SESSION['ao_pos_login'] = $_SERVER['REQUEST_URI'] ?? 'index.php';
header('Location: login.php');
exit;
}
}
/** true se o usuário logado pode acessar a página de negócio $chave (tabela `paginas`). */
function ao_tem_permissao($chave) {
$usuario = ao_usuario_logado();
if (!$usuario) {
return false;
}
if (!empty($usuario['acesso_total'])) {
return true;
}
return in_array($chave, $usuario['paginas'] ?? [], true);
}
/** Carrega os dados de sessão do usuário a partir do banco (login e refresh de permissões). */
function ao_carregar_sessao_usuario(PDO $pdo, array $usuarioDb, array $perfilDb) {
$paginas = [];
if (empty($perfilDb['acesso_total'])) {
$stmt = $pdo->prepare(
'SELECT p.chave FROM paginas p
INNER JOIN perfil_paginas pp ON pp.pagina_id = p.id
WHERE pp.perfil_id = ? AND p.ativo = 1'
);
$stmt->execute([$perfilDb['id']]);
$paginas = array_column($stmt->fetchAll(), 'chave');
}
$_SESSION['ao_usuario'] = [
'id' => (int) $usuarioDb['id'],
'nome' => $usuarioDb['nome'],
'email' => $usuarioDb['email'],
'perfil_id' => (int) $perfilDb['id'],
'perfil_nome' => $perfilDb['nome'],
'acesso_total' => (bool) $perfilDb['acesso_total'],
'paginas' => $paginas,
];
}
function ao_pagina_acesso_negado($ao_tema_atual = null) {
http_response_code(403);
$cor = $ao_tema_atual['cor'] ?? '#7FA653';
echo '<!doctype html><html lang="pt-BR"><head><meta charset="UTF-8">'
. '<title>Acesso negado — AçãoOpção</title>'
. '<meta name="viewport" content="width=device-width, initial-scale=1.0"></head>'
. '<body style="font-family: system-ui, sans-serif; display:flex; align-items:center; justify-content:center; '
. 'min-height:100vh; margin:0; background:#F4F5F5;">'
. '<div style="max-width:420px; text-align:center; padding:32px;">'
. '<div style="font-size:42px; margin-bottom:8px;">🔒</div>'
. '<h1 style="font-size:1.25rem; margin-bottom:8px;">Acesso negado</h1>'
. '<p style="color:#666; margin-bottom:24px;">Seu perfil não tem permissão para acessar esta página. '
. 'Fale com um administrador se precisar desse acesso.</p>'
. '<a href="index.php" style="display:inline-block; padding:10px 20px; border-radius:8px; '
. 'background:' . htmlspecialchars($cor) . '; color:#fff; text-decoration:none; font-weight:600;">Voltar</a>'
. '</div></body></html>';
exit;
}
/** Exige login e, se $chave for informada, permissão para aquela página de negócio. */
function ao_exigir_permissao($chave = null, $ao_tema_atual = null) {
ao_exigir_login();
if ($chave !== null && !ao_tem_permissao($chave)) {
ao_pagina_acesso_negado($ao_tema_atual);
}
}
/** Exige login e acesso_total (para as páginas de administração do próprio sistema). */
function ao_exigir_acesso_total($ao_tema_atual = null) {
ao_exigir_login();
$usuario = ao_usuario_logado();
if (empty($usuario['acesso_total'])) {
ao_pagina_acesso_negado($ao_tema_atual);
}
}
+76
View File
@@ -0,0 +1,76 @@
<?php
/**
* AçãoOpção — configuração de ambiente (desenvolvimento / produção).
* Inclua este arquivo antes de includes/theme.php.
*/
define('AO_AMBIENTE_ARQUIVO', __DIR__ . '/ambiente.json');
const AO_URLS = [
'desenvolvimento' => 'http://localhost:8080/claude/AcaoOpcao/',
'producao' => 'https://acaoeopcaoderivativos.systems/',
];
function ao_ler_ambiente() {
$padrao = 'desenvolvimento';
if (!file_exists(AO_AMBIENTE_ARQUIVO)) {
return $padrao;
}
$conteudo = json_decode((string) file_get_contents(AO_AMBIENTE_ARQUIVO), true);
$ambiente = is_array($conteudo) ? ($conteudo['ambiente'] ?? $padrao) : $padrao;
return array_key_exists($ambiente, AO_URLS) ? $ambiente : $padrao;
}
function ao_salvar_ambiente($ambiente) {
if (!array_key_exists($ambiente, AO_URLS)) {
return false;
}
$ok = file_put_contents(
AO_AMBIENTE_ARQUIVO,
json_encode(['ambiente' => $ambiente], JSON_PRETTY_PRINT)
);
return $ok !== false;
}
// Constantes disponíveis para o resto do sistema:
// AO_AMBIENTE 'desenvolvimento' | 'producao'
// AO_BASE_URL URL completa do ambiente ativo
// AO_IS_PRODUCAO true quando o ambiente ativo é produção (https)
define('AO_AMBIENTE', ao_ler_ambiente());
define('AO_BASE_URL', AO_URLS[AO_AMBIENTE]);
define('AO_IS_PRODUCAO', AO_AMBIENTE === 'producao');
// Credenciais do banco de dados MySQL por ambiente. Troque os valores de
// "producao" diretamente aqui, editando o arquivo no servidor — por segurança,
// evite colar senha de produção em e-mail, chat ou qualquer lugar fora deste
// arquivo. O ambiente ativo é escolhido na tela Configurações do sistema.
const AO_BANCOS = [
'desenvolvimento' => [
'host' => 'localhost',
'nome' => 'acaoopcao',
'usuario' => 'josima70_josimar',
'senha' => 'Josim@r230976',
],
'producao' => [
'host' => 'database', // ajuste se o banco de produção estiver em outro host
'nome' => 'acaoopcao',
'usuario' => 'root',
'senha' => 'Josim@r230976',
],
];
define('AO_DB_HOST', AO_BANCOS[AO_AMBIENTE]['host']);
define('AO_DB_NOME', AO_BANCOS[AO_AMBIENTE]['nome']);
define('AO_DB_USUARIO', AO_BANCOS[AO_AMBIENTE]['usuario']);
define('AO_DB_SENHA', AO_BANCOS[AO_AMBIENTE]['senha']);
/**
* Monta uma URL absoluta a partir de um caminho relativo ao projeto,
* usando a URL base do ambiente ativo. Útil para links que precisam
* ser absolutos (ex.: compartilhamento, tag canonical, e-mails).
* Os links internos do próprio sistema continuam relativos e não
* precisam desta função para funcionar nos dois ambientes.
*/
function ao_url($caminho = '') {
return rtrim(AO_BASE_URL, '/') . '/' . ltrim($caminho, '/');
}
+35
View File
@@ -0,0 +1,35 @@
<?php
/**
* AçãoOpção — conexão com o banco de dados MySQL.
* Inclua (require_once) antes de qualquer uso de $pdo.
* As credenciais usadas aqui vêm de includes/config.php (AO_BANCOS),
* de acordo com o ambiente ativo (desenvolvimento/produção).
*/
require_once __DIR__ . '/config.php';
try {
$pdo = new PDO(
"mysql:host=" . AO_DB_HOST . ";dbname=" . AO_DB_NOME . ";charset=utf8mb4",
AO_DB_USUARIO,
AO_DB_SENHA,
[
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
]
);
} catch (PDOException $e) {
http_response_code(500);
die(
'<div style="font-family: sans-serif; max-width: 640px; margin: 60px auto; padding: 24px; ' .
'border: 1px solid #e2b3ab; background: #fdf1ef; color: #7a2c22; border-radius: 8px;">' .
'<h2 style="margin-top:0;">Não foi possível conectar ao banco de dados</h2>' .
'<p>Ambiente ativo: <strong>' . htmlspecialchars(AO_AMBIENTE) . '</strong>. Verifique se o MySQL está ' .
'ativo, se o banco <strong>' . htmlspecialchars(AO_DB_NOME) . '</strong> foi criado a partir de ' .
'<code>includes/esquema.sql</code>, e se o usuário/senha em <code>includes/config.php</code> ' .
'(bloco <code>AO_BANCOS</code>) estão corretos para este ambiente.</p>' .
'<p style="font-size: 0.85rem; opacity: .8;">Detalhe técnico: ' . htmlspecialchars($e->getMessage()) . '</p>' .
'</div>'
);
}
+6
View File
@@ -0,0 +1,6 @@
</main>
<footer style="text-align:center; padding: var(--ao-space-6) var(--ao-space-4); color: var(--ao-text-muted); font-size: var(--ao-fs-xs);">
AçãoOpção protótipo de identidade visual (tema atual: <?= htmlspecialchars($ao_tema_atual['nome']) ?>)
</footer>
</body>
</html>
+232
View File
@@ -0,0 +1,232 @@
<?php
require_once __DIR__ . '/theme.php';
require_once __DIR__ . '/auth.php';
ao_exigir_login();
$ao_usuario = ao_usuario_logado();
// Página de administração do próprio sistema (usuários/perfis/páginas)?
// Essas sempre exigem acesso_total, independente da tabela `paginas`.
if (isset($pagina_ativa) && array_key_exists($pagina_ativa, AO_PAGINAS_ADMIN)) {
ao_exigir_acesso_total($ao_tema_atual);
} elseif (isset($pagina_ativa)) {
ao_exigir_permissao($pagina_ativa, $ao_tema_atual);
}
// Páginas de negócio configuráveis, na ordem cadastrada em `paginas`.
$ao_nav_paginas = $pdo->query('SELECT chave, nome, arquivo FROM paginas WHERE ativo = 1 ORDER BY ordem, nome')->fetchAll();
// "Contas" não fica mais no menu principal — mora no submenu do usuário.
// Buscamos os dados dela aqui (nome/arquivo, caso alguém renomeie em
// Páginas) para montar o link lá embaixo, já checando a permissão normal.
$ao_pagina_contas = null;
foreach ($ao_nav_paginas as $p) {
if ($p['chave'] === 'contas') {
$ao_pagina_contas = $p;
break;
}
}
?>
<!DOCTYPE html>
<html lang="pt-BR" data-ao-mode="<?= htmlspecialchars($ao_modo) ?>">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AçãoOpção<?= isset($titulo_pagina) ? ' — ' . htmlspecialchars($titulo_pagina) : '' ?></title>
<link rel="icon" href="<?= htmlspecialchars($ao_tema_atual['favicon']) ?>">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@500;600;700&family=Inter:wght@400;500;600;700&family=IBM+Plex+Mono:wght@500;600&display=swap" rel="stylesheet">
<!-- A identidade visual inteira do sistema muda ao trocar apenas este arquivo CSS -->
<link rel="stylesheet" href="<?= htmlspecialchars($ao_tema_atual['css']) ?>">
<style>
* { box-sizing: border-box; }
body { margin: 0; }
.ao-shell { max-width: 1180px; margin: 0 auto; padding: var(--ao-space-6) var(--ao-space-5); }
.ao-topbar { display: flex; align-items: center; justify-content: space-between; gap: var(--ao-space-4); }
.ao-topbar nav { display: flex; gap: var(--ao-space-4); flex-wrap: wrap; }
.ao-topbar nav a { font-size: var(--ao-fs-sm); font-weight: 600; padding: 6px 2px; border-bottom: 2px solid transparent; text-decoration: none; white-space: nowrap; }
.ao-topbar nav a.ativo { border-bottom-color: currentColor; }
.ao-nav-separador { width: 1px; align-self: stretch; background: rgba(255,255,255,.25); margin: 0 2px; }
.ao-brand-icon { width: 28px; height: 28px; border-radius: 8px; display: block; }
.ao-topbar-direita { display: flex; align-items: center; gap: var(--ao-space-4); flex-wrap: wrap; }
/* Menu do usuário (nome no cabeçalho -> submenu) */
.ao-user-menu { position: relative; }
.ao-user-menu-trigger {
display: flex; align-items: center; gap: 8px;
background: none; border: none; cursor: pointer; padding: 4px 2px;
font-family: var(--ao-font-body); color: #fff;
}
.ao-user-menu-trigger strong { font-size: var(--ao-fs-sm); color: #fff; }
.ao-user-menu-caret { font-size: 10px; color: rgba(255,255,255,.75); transition: transform .15s ease; }
.ao-user-menu.aberto .ao-user-menu-caret { transform: rotate(180deg); }
.ao-user-menu-dropdown {
display: none;
position: absolute; top: calc(100% + 12px); right: 0;
min-width: 230px;
background: var(--ao-bg-surface);
border: 1px solid var(--ao-border);
border-radius: var(--ao-radius-md);
box-shadow: var(--ao-shadow-lg);
padding: var(--ao-space-2);
z-index: 1000;
}
.ao-user-menu.aberto .ao-user-menu-dropdown { display: block; }
.ao-user-menu-dropdown a {
display: block; padding: 8px 10px; border-radius: var(--ao-radius-sm);
font-size: var(--ao-fs-sm); font-weight: 600;
color: var(--ao-text-body); text-decoration: none;
}
.ao-user-menu-dropdown a:hover, .ao-user-menu-dropdown a.ativo { background: var(--ao-bg-page); }
.ao-user-menu-separador { height: 1px; background: var(--ao-border); margin: var(--ao-space-2) 6px; }
.ao-user-menu-secao-titulo {
font-size: var(--ao-fs-xs); text-transform: uppercase; letter-spacing: .04em;
color: var(--ao-text-muted); padding: 6px 10px 4px;
}
.ao-theme-switcher { display: flex; align-items: center; gap: 8px; padding: 2px 10px 10px; }
.ao-theme-dot {
width: 20px; height: 20px; border-radius: 50%;
border: 2px solid var(--ao-border);
display: inline-block; transition: transform .15s ease;
}
.ao-theme-dot:hover { transform: scale(1.15); }
.ao-theme-dot.ativo { border-color: var(--ao-text-strong); box-shadow: 0 0 0 2px var(--ao-focus-ring); }
.ao-mode-toggle {
display: inline-flex; align-items: center; justify-content: center;
width: 28px; height: 28px; border-radius: 50%;
background: var(--ao-bg-page);
border: 1px solid var(--ao-border);
font-size: 14px; line-height: 1; text-decoration: none;
transition: background-color .15s ease, transform .15s ease;
}
.ao-mode-toggle:hover { background: var(--ao-primary-soft); transform: scale(1.08); }
.ao-page-title { margin-bottom: var(--ao-space-5); }
/* Utilitário de layout usado em vários formulários (acoes.php, usuarios.php,
operacoes.php, paginas_admin.php, index.php) para colocar campos lado a
lado. Cada uso já define seu próprio "gap" inline. */
.ao-row { display: flex; flex-wrap: wrap; }
/* Popup de cadastro/edição — compartilhado por qualquer página que use um
<div class="ao-modal-backdrop" id="...">, com a classe "is-open" para
controlar se aparece (o PHP já pode renderizar aberto, ex: ao editar). */
.ao-modal-backdrop {
display: none;
position: fixed;
inset: 0;
background: rgba(0, 0, 0, .5);
align-items: center;
justify-content: center;
padding: var(--ao-space-4);
z-index: 1000;
}
.ao-modal-backdrop.is-open { display: flex; }
.ao-modal {
background: var(--ao-bg-surface);
border-radius: var(--ao-radius-lg);
box-shadow: var(--ao-shadow-lg);
padding: var(--ao-space-5);
width: 100%;
max-width: 560px;
max-height: 90vh;
overflow-y: auto;
}
.ao-modal-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: var(--ao-space-2);
}
.ao-modal-close {
background: none;
border: none;
font-size: 1.5rem;
line-height: 1;
cursor: pointer;
color: var(--ao-text-muted);
padding: 0 var(--ao-space-1);
}
.ao-modal-close:hover { color: var(--ao-text-strong); }
body, .ao-card, .ao-table, .ao-field input, .ao-field select, .ao-field textarea, .ao-btn {
transition: background-color .2s ease, color .2s ease, border-color .2s ease;
}
@media (max-width: 900px) {
.ao-topbar { flex-wrap: wrap; gap: 12px; padding: var(--ao-space-3); }
}
</style>
</head>
<body>
<header class="ao-topbar">
<div class="ao-brand">
<img src="<?= htmlspecialchars($ao_tema_atual['icone']) ?>" alt="" class="ao-brand-icon">
<span>AçãoOpção</span>
</div>
<nav>
<?php foreach ($ao_nav_paginas as $p): ?>
<?php if ($p['chave'] === 'contas') continue; // fica no submenu do usuário ?>
<?php if (!empty($ao_usuario['acesso_total']) || in_array($p['chave'], $ao_usuario['paginas'] ?? [], true)): ?>
<a href="<?= htmlspecialchars($p['arquivo']) ?>" class="<?= ($pagina_ativa ?? '') === $p['chave'] ? 'ativo' : '' ?>"><?= htmlspecialchars($p['nome']) ?></a>
<?php endif; ?>
<?php endforeach; ?>
<?php if (!empty($ao_usuario['acesso_total'])): ?>
<span class="ao-nav-separador"></span>
<?php foreach (AO_PAGINAS_ADMIN as $chave => $info): ?>
<a href="<?= htmlspecialchars($info['arquivo']) ?>" class="<?= ($pagina_ativa ?? '') === $chave ? 'ativo' : '' ?>"><?= htmlspecialchars($info['nome']) ?></a>
<?php endforeach; ?>
<?php endif; ?>
</nav>
<div class="ao-topbar-direita">
<div class="ao-user-menu" id="ao-user-menu">
<button type="button" class="ao-user-menu-trigger" onclick="aoAlternarMenuUsuario()">
<strong><?= htmlspecialchars($ao_usuario['nome']) ?></strong>
<span class="ao-user-menu-caret">▾</span>
</button>
<div class="ao-user-menu-dropdown">
<?php if ($ao_pagina_contas && (!empty($ao_usuario['acesso_total']) || in_array('contas', $ao_usuario['paginas'] ?? [], true))): ?>
<a href="<?= htmlspecialchars($ao_pagina_contas['arquivo']) ?>" class="<?= ($pagina_ativa ?? '') === 'contas' ? 'ativo' : '' ?>"><?= htmlspecialchars($ao_pagina_contas['nome']) ?></a>
<?php endif; ?>
<a href="minha-conta.php">Minha conta</a>
<div class="ao-user-menu-separador"></div>
<div class="ao-user-menu-secao-titulo">Identidade visual</div>
<div class="ao-theme-switcher">
<?php foreach ($ao_temas_info as $chave => $info): ?>
<a href="?tema=<?= urlencode($chave) ?>"
class="ao-theme-dot <?= $ao_tema === $chave ? 'ativo' : '' ?>"
style="background: <?= htmlspecialchars($info['cor']) ?>;"
title="Trocar para <?= htmlspecialchars($info['nome']) ?>"></a>
<?php endforeach; ?>
<a href="?modo=<?= urlencode($ao_proximo_modo) ?>"
class="ao-mode-toggle"
title="Trocar para modo <?= htmlspecialchars($ao_modos_info[$ao_proximo_modo]['nome']) ?>">
<?= $ao_modo_atual['icone'] ?>
</a>
</div>
<div class="ao-user-menu-separador"></div>
<a href="logout.php">Sair</a>
</div>
</div>
</div>
</header>
<script>
function aoAlternarMenuUsuario(forcarAberto) {
var menu = document.getElementById('ao-user-menu');
if (typeof forcarAberto === 'boolean') {
menu.classList.toggle('aberto', forcarAberto);
} else {
menu.classList.toggle('aberto');
}
}
document.addEventListener('click', function (evento) {
var menu = document.getElementById('ao-user-menu');
if (menu && !menu.contains(evento.target)) {
aoAlternarMenuUsuario(false);
}
});
document.addEventListener('keydown', function (evento) {
if (evento.key === 'Escape') aoAlternarMenuUsuario(false);
});
</script>
<main class="ao-shell">
+89
View File
@@ -0,0 +1,89 @@
<?php
/**
* AçãoOpção — controle de identidade visual (tema) do sistema.
* Inclua este arquivo no topo de header.php, antes de qualquer saída HTML,
* sempre depois de includes/config.php (usamos AO_IS_PRODUCAO aqui).
*/
require_once __DIR__ . '/config.php';
$ao_temas_info = [
'verde' => [
'nome' => 'Verde',
'css' => 'assets/css/identidade-visual-verde.css',
'favicon' => 'assets/img/logos/verde/favicon.ico',
'icone' => 'assets/img/logos/verde/svg/icone-cor.svg',
'cor' => '#7FA653',
],
'marrom' => [
'nome' => 'Marrom',
'css' => 'assets/css/identidade-visual-marrom.css',
'favicon' => 'assets/img/logos/marrom/favicon.ico',
'icone' => 'assets/img/logos/marrom/svg/icone-cor.svg',
'cor' => '#A6754C',
],
'cinza' => [
'nome' => 'Cinza',
'css' => 'assets/css/identidade-visual-cinza.css',
'favicon' => 'assets/img/logos/cinza/favicon.ico',
'icone' => 'assets/img/logos/cinza/svg/icone-cor.svg',
'cor' => '#6B6F77',
],
];
$ao_modos_info = [
'claro' => ['nome' => 'Claro', 'icone' => '☀️'],
'escuro' => ['nome' => 'Escuro', 'icone' => '🌙'],
];
// Duração do cookie de identidade: 1 ano. Guardamos a escolha do usuário
// em cookie (não em sessão) justamente para que ela sobreviva ao fechar
// o navegador — é isso que "lembra" o tema/modo na próxima visita.
const AO_COOKIE_DURACAO = 60 * 60 * 24 * 365;
function ao_definir_cookie($nome, $valor) {
setcookie($nome, $valor, [
'expires' => time() + AO_COOKIE_DURACAO,
'path' => '/',
'secure' => AO_IS_PRODUCAO,
'httponly' => true,
'samesite' => 'Lax',
]);
}
// Troca de tema/modo via link "?tema=marrom" e/ou "?modo=escuro" — grava
// em cookie e redireciona para a mesma URL sem o parâmetro, para manter
// o endereço limpo. Os dois podem vir juntos na mesma requisição.
$ao_precisa_redirecionar = false;
if (isset($_GET['tema']) && array_key_exists($_GET['tema'], $ao_temas_info)) {
ao_definir_cookie('ao_tema', $_GET['tema']);
$_COOKIE['ao_tema'] = $_GET['tema'];
$ao_precisa_redirecionar = true;
}
if (isset($_GET['modo']) && array_key_exists($_GET['modo'], $ao_modos_info)) {
ao_definir_cookie('ao_modo', $_GET['modo']);
$_COOKIE['ao_modo'] = $_GET['modo'];
$ao_precisa_redirecionar = true;
}
if ($ao_precisa_redirecionar) {
$destino = strtok($_SERVER['REQUEST_URI'], '?');
header('Location: ' . $destino);
exit;
}
$ao_tema = $_COOKIE['ao_tema'] ?? 'verde';
if (!array_key_exists($ao_tema, $ao_temas_info)) {
$ao_tema = 'verde';
}
$ao_modo = $_COOKIE['ao_modo'] ?? 'claro';
if (!array_key_exists($ao_modo, $ao_modos_info)) {
$ao_modo = 'claro';
}
$ao_tema_atual = $ao_temas_info[$ao_tema];
$ao_modo_atual = $ao_modos_info[$ao_modo];
$ao_proximo_modo = $ao_modo === 'claro' ? 'escuro' : 'claro';