feat: adição de interface web gráfica para gerenciar os slides
This commit is contained in:
parent
cc3ba92caa
commit
a8d41b892d
20
.gitignore
vendored
Normal file
20
.gitignore
vendored
Normal 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/
|
BIN
Captura.png
BIN
Captura.png
Binary file not shown.
Before Width: | Height: | Size: 2.8 MiB |
BIN
Imagem1.png
BIN
Imagem1.png
Binary file not shown.
Before Width: | Height: | Size: 136 KiB |
3
README.md
Normal file
3
README.md
Normal 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
341
pasta_publica/edit.php
Normal 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>
|
@ -10,8 +10,12 @@
|
|||||||
body {font-family: Verdana, sans-serif; margin:0}
|
body {font-family: Verdana, sans-serif; margin:0}
|
||||||
img {vertical-align: middle;}
|
img {vertical-align: middle;}
|
||||||
|
|
||||||
|
|
||||||
@keyframes up {
|
@keyframes up {
|
||||||
|
from {margin-bottom: 40px;}
|
||||||
|
to {margin-bottom: 0;}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes down {
|
||||||
from {margin-bottom: -40px;}
|
from {margin-bottom: -40px;}
|
||||||
to {margin-bottom: 0;}
|
to {margin-bottom: 0;}
|
||||||
}
|
}
|
||||||
@ -143,6 +147,10 @@ img {vertical-align: middle;}
|
|||||||
animation: up .5s ease-in-out;
|
animation: up .5s ease-in-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.moan-down{
|
||||||
|
animation: down .5s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
.moan-from-left {
|
.moan-from-left {
|
||||||
animation: from-left .8s ease-in-out;
|
animation: from-left .8s ease-in-out;
|
||||||
}
|
}
|
||||||
@ -151,7 +159,6 @@ img {vertical-align: middle;}
|
|||||||
animation: from-right .8s ease-in-out;
|
animation: from-right .8s ease-in-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* On smaller screens, decrease text size */
|
|
||||||
@media only screen and (max-width: 310px) {
|
@media only screen and (max-width: 310px) {
|
||||||
.prev, .next,.text {font-size: 11px}
|
.prev, .next,.text {font-size: 11px}
|
||||||
}
|
}
|
||||||
@ -160,33 +167,18 @@ img {vertical-align: middle;}
|
|||||||
<body>
|
<body>
|
||||||
|
|
||||||
<div class="slideshow-container">
|
<div class="slideshow-container">
|
||||||
|
|
||||||
<div class="slide">
|
<div class="slide">
|
||||||
|
<img src="./imagens/img_688fb8b5c8ee6.webp" alt=""/>
|
||||||
<img src="./Imagem1.png" alt=""/>
|
<a data-moan-direction="down" class="moan-link" href="#" style="background: #339d08;">Adquira já!</a>
|
||||||
|
|
||||||
<a data-moan-direction="up" class="moan-link" href="#">Veja</a>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="slide">
|
<div class="slide">
|
||||||
|
<img src="./imagens/img_688fbff50d93b.webp" alt=""/>
|
||||||
<img src="./Captura.png" alt=""/>
|
<a data-moan-direction="up" class="moan-link" href="#" style="background: #ec606d;">Adquira Já!</a>
|
||||||
|
|
||||||
<a data-moan-direction="from-right" class="moan-link" href="#">Leia agora</a>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<a class="prev" onclick="plusSlides(-1)">❮</a>
|
<a class="prev" onclick="plusSlides(-1)">❮</a>
|
||||||
<a class="next" onclick="plusSlides(1)">❯</a>
|
<a class="next" onclick="plusSlides(1)">❯</a>
|
||||||
|
|
||||||
<div class="dots">
|
<div class="dots"><span class="dot" onclick="currentSlide(1)"></span> <span class="dot" onclick="currentSlide(2)"></span> </div></div>
|
||||||
<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") {
|
if (direction === "up") {
|
||||||
temp.classList.remove('moan-up');
|
temp.classList.remove('moan-up');
|
||||||
|
} else if (direction === "down") {
|
||||||
|
temp.classList.remove('moan-down');
|
||||||
} else if (direction === "from-left") {
|
} else if (direction === "from-left") {
|
||||||
temp.classList.remove('moan-from-left');
|
temp.classList.remove('moan-from-left');
|
||||||
} else if (direction === "from-right") {
|
} else if (direction === "from-right") {
|
||||||
@ -268,6 +262,8 @@ function showSlides(n) {
|
|||||||
|
|
||||||
if (direction === "up") {
|
if (direction === "up") {
|
||||||
link.classList.add('moan-up');
|
link.classList.add('moan-up');
|
||||||
|
} else if (direction === "down") {
|
||||||
|
link.classList.add('moan-down');
|
||||||
} else if (direction === "from-left") {
|
} else if (direction === "from-left") {
|
||||||
link.classList.add('moan-from-left');
|
link.classList.add('moan-from-left');
|
||||||
} else if (direction === "from-right") {
|
} else if (direction === "from-right") {
|
16
pasta_publica/slides.json
Normal file
16
pasta_publica/slides.json
Normal 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"
|
||||||
|
}
|
||||||
|
]
|
Loading…
x
Reference in New Issue
Block a user