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}
|
||||
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
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