feat: adição de interface web gráfica para gerenciar os slides

This commit is contained in:
Rafael Tavares Juliani 2025-08-03 17:08:18 -03:00
parent cc3ba92caa
commit a8d41b892d
7 changed files with 398 additions and 22 deletions

20
.gitignore vendored Normal file
View File

@ -0,0 +1,20 @@
# Ignorar o arquivo .env com senhas e configurações
.env
# Ignorar diretórios de upload temporário e imagens
imagens/
*.log
# Ignorar cache do sistema operacional
.DS_Store
Thumbs.db
# Ignorar arquivos temporários de editores
*.swp
*.swo
*.bak
*.tmp
# Ignorar arquivos de backup do VS Code ou outros editores
*.code-workspace
.vscode/

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 136 KiB

3
README.md Normal file
View File

@ -0,0 +1,3 @@
Pequeno slideshow para apresentar os destaques da Editora Moan e do Meta Museu da Matemática.
Em produção, troque a senha do arquivo .env.

341
pasta_publica/edit.php Normal file
View File

@ -0,0 +1,341 @@
<?php
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
session_start();
$env = parse_ini_file(__DIR__ . '/../.env');
$senha_correta = $env['PASSWORD'] ?? '';
if (isset($_POST['senha'])) {
if ($_POST['senha'] === $senha_correta) {
$_SESSION['logado'] = true;
} else {
$erro = "Senha incorreta.";
}
}
if (!($_SESSION['logado'] ?? false)) {
?>
<form method="POST">
<h2>Entrar</h2>
<?php if (!empty($erro)) echo "<p style='color:red'>$erro</p>"; ?>
<input type="password" name="senha" placeholder="Senha"/>
<button type="submit">Entrar</button>
</form>
<?php
exit;
}
$jsonPath = __DIR__ . '/slides.json';
$imagensDir = __DIR__ . '/imagens/';
$htmlPath = __DIR__ . '/index.html';
$slides = [];
if (file_exists($jsonPath)) {
$conteudo = file_get_contents($jsonPath);
$decodificado = json_decode($conteudo, true);
if (is_array($decodificado)) {
$slides = $decodificado;
}
}
// ADICIONAR SLIDE
if (isset($_POST['add'])) {
if (!is_dir($imagensDir)) mkdir($imagensDir);
$imgName = '';
if (isset($_FILES['imagem']) && $_FILES['imagem']['error'] === 0) {
$ext = strtolower(pathinfo($_FILES['imagem']['name'], PATHINFO_EXTENSION));
$permitidos = ['jpg', 'jpeg', 'png', 'webp', 'apng'];
if (in_array($ext, $permitidos)) {
$imgName = uniqid('img_') . ".$ext";
if (!move_uploaded_file($_FILES['imagem']['tmp_name'], "$imagensDir/$imgName")) {
die("Erro ao salvar a imagem.");
}
} else {
die("Formato de imagem não permitido.");
}
} else {
die("Erro no envio da imagem.");
}
$slides[] = [
'imagem' => $imgName,
'texto' => trim($_POST['texto'] ?? ''),
'cor' => $_POST['cor'] ?? '',
'direcao' => $_POST['direcao'] ?? '',
'link' => trim($_POST['link'] ?? ''),
];
if (file_put_contents($jsonPath, json_encode($slides, JSON_PRETTY_PRINT)) === false) {
die("Erro ao gravar no slides.json");
}
atualizarHTML($slides, $htmlPath);
header("Location: " . basename(__FILE__));
exit;
}
// SALVAR ALTERAÇÕES (editar e reordenar)
if (isset($_POST['save'])) {
$novos_slides = [];
$ids = array_keys($slides);
$ordem = $_POST['ordem'] ?? [];
foreach ($ids as $i) {
$texto = trim($_POST['texto'][$i] ?? '');
$cor = $_POST['cor'][$i] ?? '';
$link = trim($_POST['link'][$i] ?? '');
$direcao = $_POST['direcao'][$i] ?? '';
$ord = intval($ordem[$i] ?? 0);
$novos_slides[$i] = [
'imagem' => $slides[$i]['imagem'],
'texto' => $texto,
'cor' => $cor,
'link' => $link,
'direcao' => $direcao,
'ordem' => $ord,
];
}
usort($novos_slides, function($a, $b) {
return ($a['ordem'] ?? 0) <=> ($b['ordem'] ?? 0);
});
foreach ($novos_slides as &$slide) {
unset($slide['ordem']);
}
$slides = $novos_slides;
if (file_put_contents($jsonPath, json_encode($slides, JSON_PRETTY_PRINT)) === false) {
die("Erro ao gravar no slides.json");
}
atualizarHTML($slides, $htmlPath);
header("Location: " . basename(__FILE__));
exit;
}
// EXCLUIR SLIDE
if (isset($_GET['delete'])) {
$index = (int) $_GET['delete'];
if (isset($slides[$index])) {
$imgDel = $slides[$index]['imagem'];
@unlink("$imagensDir/$imgDel");
array_splice($slides, $index, 1);
file_put_contents($jsonPath, json_encode($slides, JSON_PRETTY_PRINT));
atualizarHTML($slides, $htmlPath);
}
header("Location: " . basename(__FILE__));
exit;
}
function atualizarHTML($slides, $htmlPath) {
$novoConteudo = '<div class="slideshow-container">' . PHP_EOL;
foreach ($slides as $slide) {
$botao = '';
if (!empty(trim($slide['texto'] ?? ''))) {
$cor = $slide['cor'] ?? '#000';
$dir = $slide['direcao'] ?? 'up';
$txt = htmlspecialchars($slide['texto']);
$link = htmlspecialchars($slide['link'] ?? '#') ?: '#';
$botao = "<a data-moan-direction=\"$dir\" class=\"moan-link\" href=\"$link\" style=\"background: $cor;\">$txt</a>";
}
$novoConteudo .= <<<HTML
<div class="slide">
<img src="./imagens/{$slide['imagem']}" alt=""/>
$botao
</div>
HTML;
}
$novoConteudo .= <<<HTML
<a class="prev" onclick="plusSlides(-1)"></a>
<a class="next" onclick="plusSlides(1)"></a>
<div class="dots">
HTML;
foreach ($slides as $i => $_) {
$n = $i + 1;
$novoConteudo .= "<span class=\"dot\" onclick=\"currentSlide($n)\"></span> ";
}
$novoConteudo .= '</div></div>';
$html = file_get_contents($htmlPath);
$novoHtml = preg_replace(
'#<div class="slideshow-container">.*?</div>\s*</div>#s',
$novoConteudo,
$html
);
file_put_contents($htmlPath, $novoHtml);
}
?>
<!DOCTYPE html>
<html lang="pt-br">
<head>
<meta charset="UTF-8" />
<title>Editar Slides</title>
<style>
body {
font-family: sans-serif;
background: linear-gradient(300deg,deepskyblue,darkviolet,blue);
background-size: 180% 180%;
background-repeat: no-repeat;
background-attachment: fixed;
animation: gradient-animation 18s ease infinite;
color: #fff;
}
@keyframes gradient-animation {
0% {
background-position: 0% 50%;
}
50% {
background-position: 100% 50%;
}
100% {
background-position: 0% 50%;
}
}
h1, h2, table {
text-align: center;
}
table {
margin: 0 auto;
}
div.form {
display: block;
margin: 0 auto;
width: 600px;
max-width: 90%;
}
a {
color: #fff;
text-decoration: none;
font-weight: bold;
}
th, td {
padding: 5px 10px;
}
button {
margin: 10px auto;
display: block;
background-color: #263748;;
color: white; /* White text */
border: none; /* No border */
padding: 10px 20px; /* Padding around the text */
font-size: 16px; /* Font size */
cursor: pointer; /* Changes mouse cursor to a hand on hover */
border-radius: 5px; /* Slightly rounded corners */
transition: background-color 0.3s ease; /* Smooth transition for hover effect */
}
button:hover {
background-color: #444;
}
button:active {
background-color: #555;
transform: translateY(1px); /* Slight downward shift for a "pressed" effect */
}
</style>
</head>
<body>
<h1>Gerenciar Slides</h1>
<p style="text-align: center;">Use imagens com a proporção 81/46. As dimensões de exibição são 405px de largura por 230px de altura.</p>
<div class="form">
<form method="POST" enctype="multipart/form-data" action="<?= basename(__FILE__) ?>">
<p><input type="file" name="imagem" required></p>
<p><input type="text" name="texto" placeholder="Texto do botão (opcional)"></p>
<p><input type="text" name="link" placeholder="Link do botão (opcional, ex: https://...)"></p>
<p><input type="color" name="cor" value="#000000"></p>
<p>
<select name="direcao">
<option value="up">De cima</option>
<option value="from-right">Da direita</option>
<option value="from-left">Da esquerda</option>
<option value="down">De baixo</option>
</select>
</p>
<p><button type="submit" name="add">Adicionar Slide</button></p>
</form>
</div>
<hr>
<h2>Editar slides existentes</h2>
<form method="POST" action="<?= basename(__FILE__) ?>">
<table border="1" cellpadding="5" cellspacing="0" style="border-collapse: collapse;">
<thead>
<tr>
<th>Ordem</th>
<th>Imagem</th>
<th>Texto do botão</th>
<th>Link do botão</th>
<th>Cor do botão</th>
<th>Direção</th>
<th>Ações</th>
</tr>
</thead>
<tbody>
<?php foreach ($slides as $i => $s): ?>
<tr>
<td>
<input type="number" name="ordem[<?= $i ?>]" value="<?= $i + 1 ?>" style="width: 50px;">
</td>
<td>
<img src="imagens/<?= $s['imagem'] ?>" style="height:50px;vertical-align:middle;">
</td>
<td>
<input type="text" name="texto[<?= $i ?>]" value="<?= htmlspecialchars($s['texto']) ?>">
</td>
<td>
<input type="text" name="link[<?= $i ?>]" value="<?= htmlspecialchars($s['link'] ?? '') ?>">
</td>
<td>
<input type="color" name="cor[<?= $i ?>]" value="<?= htmlspecialchars($s['cor'] ?: '#000000') ?>">
</td>
<td>
<select name="direcao[<?= $i ?>]">
<?php
$dirs = ['up' => 'De cima', 'from-right' => 'Da direita', 'from-left' => 'Da esquerda', 'down' => 'De baixo'];
foreach ($dirs as $val => $label): ?>
<option value="<?= $val ?>" <?= ($s['direcao'] === $val) ? 'selected' : '' ?>><?= $label ?></option>
<?php endforeach; ?>
</select>
</td>
<td>
<a href="?delete=<?= $i ?>" onclick="return confirm('Excluir este slide?')">Excluir</a>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<p><button type="submit" name="save">Salvar alterações</button></p>
</form>
</body>
</html>

View File

@ -10,8 +10,12 @@
body {font-family: Verdana, sans-serif; margin:0}
img {vertical-align: middle;}
@keyframes up {
from {margin-bottom: 40px;}
to {margin-bottom: 0;}
}
@keyframes down {
from {margin-bottom: -40px;}
to {margin-bottom: 0;}
}
@ -143,6 +147,10 @@ img {vertical-align: middle;}
animation: up .5s ease-in-out;
}
.moan-down{
animation: down .5s ease-in-out;
}
.moan-from-left {
animation: from-left .8s ease-in-out;
}
@ -151,7 +159,6 @@ img {vertical-align: middle;}
animation: from-right .8s ease-in-out;
}
/* On smaller screens, decrease text size */
@media only screen and (max-width: 310px) {
.prev, .next,.text {font-size: 11px}
}
@ -160,33 +167,18 @@ img {vertical-align: middle;}
<body>
<div class="slideshow-container">
<div class="slide">
<img src="./Imagem1.png" alt=""/>
<a data-moan-direction="up" class="moan-link" href="#">Veja</a>
<img src="./imagens/img_688fb8b5c8ee6.webp" alt=""/>
<a data-moan-direction="down" class="moan-link" href="#" style="background: #339d08;">Adquira já!</a>
</div>
<div class="slide">
<img src="./Captura.png" alt=""/>
<a data-moan-direction="from-right" class="moan-link" href="#">Leia agora</a>
<img src="./imagens/img_688fbff50d93b.webp" alt=""/>
<a data-moan-direction="up" class="moan-link" href="#" style="background: #ec606d;">Adquira Já!</a>
</div>
<a class="prev" onclick="plusSlides(-1)"></a>
<a class="next" onclick="plusSlides(1)"></a>
<div class="dots">
<span class="dot" onclick="currentSlide(1)"></span>
<span class="dot" onclick="currentSlide(2)"></span>
</div>
</div>
<div class="dots"><span class="dot" onclick="currentSlide(1)"></span> <span class="dot" onclick="currentSlide(2)"></span> </div></div>
@ -244,6 +236,8 @@ function showSlides(n) {
if (direction === "up") {
temp.classList.remove('moan-up');
} else if (direction === "down") {
temp.classList.remove('moan-down');
} else if (direction === "from-left") {
temp.classList.remove('moan-from-left');
} else if (direction === "from-right") {
@ -268,6 +262,8 @@ function showSlides(n) {
if (direction === "up") {
link.classList.add('moan-up');
} else if (direction === "down") {
link.classList.add('moan-down');
} else if (direction === "from-left") {
link.classList.add('moan-from-left');
} else if (direction === "from-right") {

16
pasta_publica/slides.json Normal file
View File

@ -0,0 +1,16 @@
[
{
"imagem": "img_688fb8b5c8ee6.webp",
"texto": "Adquira j\u00e1!",
"cor": "#339d08",
"link": "",
"direcao": "down"
},
{
"imagem": "img_688fbff50d93b.webp",
"texto": "Adquira J\u00e1!",
"cor": "#ec606d",
"link": "",
"direcao": "up"
}
]