first commit
This commit is contained in:
72
.idea/workspace.xml
generated
Normal file
72
.idea/workspace.xml
generated
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="AutoImportSettings">
|
||||||
|
<option name="autoReloadType" value="SELECTIVE" />
|
||||||
|
</component>
|
||||||
|
<component name="ChangeListManager">
|
||||||
|
<list default="true" id="304bc2cf-dc17-4cf0-8c50-b91baa1bac4a" name="Changes" comment="" />
|
||||||
|
<option name="SHOW_DIALOG" value="false" />
|
||||||
|
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||||
|
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
||||||
|
<option name="LAST_RESOLUTION" value="IGNORE" />
|
||||||
|
</component>
|
||||||
|
<component name="ComposerSettings">
|
||||||
|
<execution />
|
||||||
|
</component>
|
||||||
|
<component name="FileTemplateManagerImpl">
|
||||||
|
<option name="RECENT_TEMPLATES">
|
||||||
|
<list>
|
||||||
|
<option value="PHP File" />
|
||||||
|
</list>
|
||||||
|
</option>
|
||||||
|
</component>
|
||||||
|
<component name="ProjectColorInfo"><![CDATA[{
|
||||||
|
"customColor": "",
|
||||||
|
"associatedIndex": 3
|
||||||
|
}]]></component>
|
||||||
|
<component name="ProjectId" id="34vOas5nhI714FKr1LdQhjIFwqK" />
|
||||||
|
<component name="ProjectViewState">
|
||||||
|
<option name="hideEmptyMiddlePackages" value="true" />
|
||||||
|
<option name="showLibraryContents" value="true" />
|
||||||
|
</component>
|
||||||
|
<component name="PropertiesComponent"><![CDATA[{
|
||||||
|
"keyToString": {
|
||||||
|
"RunOnceActivity.ShowReadmeOnStart": "true",
|
||||||
|
"SHELLCHECK.PATH": "C:\\Users\\elrao\\AppData\\Roaming\\JetBrains\\PhpStorm2025.2\\plugins\\Shell Script\\shellcheck.exe",
|
||||||
|
"last_opened_file_path": "C:/Users/elrao/OneDrive/Documents/Projet_CMS",
|
||||||
|
"node.js.detected.package.eslint": "true",
|
||||||
|
"node.js.detected.package.tslint": "true",
|
||||||
|
"node.js.selected.package.eslint": "(autodetect)",
|
||||||
|
"node.js.selected.package.tslint": "(autodetect)",
|
||||||
|
"nodejs_package_manager_path": "npm",
|
||||||
|
"vue.rearranger.settings.migration": "true"
|
||||||
|
}
|
||||||
|
}]]></component>
|
||||||
|
<component name="RecentsManager">
|
||||||
|
<key name="CopyFile.RECENT_KEYS">
|
||||||
|
<recent name="C:\Users\elrao\OneDrive\Documents\Projet_CMS" />
|
||||||
|
</key>
|
||||||
|
</component>
|
||||||
|
<component name="SharedIndexes">
|
||||||
|
<attachedChunks>
|
||||||
|
<set>
|
||||||
|
<option value="bundled-js-predefined-d6986cc7102b-3aa1da707db6-JavaScript-PS-252.26830.95" />
|
||||||
|
<option value="bundled-php-predefined-a98d8de5180a-9b563d34894c-com.jetbrains.php.sharedIndexes-PS-252.26830.95" />
|
||||||
|
</set>
|
||||||
|
</attachedChunks>
|
||||||
|
</component>
|
||||||
|
<component name="TaskManager">
|
||||||
|
<task active="true" id="Default" summary="Default task">
|
||||||
|
<changelist id="304bc2cf-dc17-4cf0-8c50-b91baa1bac4a" name="Changes" comment="" />
|
||||||
|
<created>1762090649427</created>
|
||||||
|
<option name="number" value="Default" />
|
||||||
|
<option name="presentableId" value="Default" />
|
||||||
|
<updated>1762090649427</updated>
|
||||||
|
<workItem from="1762090650716" duration="11813000" />
|
||||||
|
</task>
|
||||||
|
<servers />
|
||||||
|
</component>
|
||||||
|
<component name="TypeScriptGeneratedFilesManager">
|
||||||
|
<option name="version" value="3" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
9
Dockerfile
Normal file
9
Dockerfile
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
FROM php:8.2-apache
|
||||||
|
LABEL authors="abdr-cms"
|
||||||
|
|
||||||
|
COPY . /var/www/html
|
||||||
|
WORKDIR /var/www/html
|
||||||
|
|
||||||
|
RUN docker-php-ext-install pdo pdo_mysql
|
||||||
|
|
||||||
|
EXPOSE 80
|
||||||
48
README.md
Normal file
48
README.md
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
Pour accéder au site : Lancez les conteneurs depuis la racine du projet avec la commande suivante (Dans un terminal qui accepte le bash par exemple GIT bash) :
|
||||||
|
|
||||||
|
./launch-dockers.sh
|
||||||
|
|
||||||
|
Une fois les conteneurs démarrés, le site sera accessible dans votre navigateur à l'adresse :
|
||||||
|
|
||||||
|
http://localhost:8080/
|
||||||
|
|
||||||
|
Accès au compte admin :
|
||||||
|
|
||||||
|
Login : user
|
||||||
|
|
||||||
|
Mdp: usecms123
|
||||||
|
|
||||||
|
Arborescence :
|
||||||
|
|
||||||
|
Projet_CMS/
|
||||||
|
│
|
||||||
|
├── admin/
|
||||||
|
│ ├── add.php
|
||||||
|
│ ├── board.php
|
||||||
|
│ ├── delete.php
|
||||||
|
│ ├── login.php
|
||||||
|
│ ├── logout.php
|
||||||
|
│ └── modif.php
|
||||||
|
│
|
||||||
|
├── assets/
|
||||||
|
│ ├── add.css
|
||||||
|
│ ├── article.css
|
||||||
|
│ ├── board.css
|
||||||
|
│ ├── delete.css
|
||||||
|
│ ├── login.css
|
||||||
|
│ ├── modif.css
|
||||||
|
│ └── style.css
|
||||||
|
│
|
||||||
|
├── bdd/
|
||||||
|
│ ├── Dockerfile
|
||||||
|
│ └── init.sql
|
||||||
|
│
|
||||||
|
├── include/
|
||||||
|
│ ├── authenticator.php
|
||||||
|
│ └── bd.php
|
||||||
|
│
|
||||||
|
├── article.php
|
||||||
|
├── Dockerfile
|
||||||
|
├── index.php
|
||||||
|
├── launch-dockers.sh
|
||||||
|
└── README.md
|
||||||
59
admin/add.php
Normal file
59
admin/add.php
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
<?php
|
||||||
|
require '../include/db.php';
|
||||||
|
require '../include/authenticator.php';
|
||||||
|
requireLogin();
|
||||||
|
|
||||||
|
$errors = [];
|
||||||
|
$titre = '';
|
||||||
|
$contenu = '';
|
||||||
|
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||||
|
$titre = trim($_POST['titre'] ?? '');
|
||||||
|
$contenu = trim($_POST['contenu'] ?? '');
|
||||||
|
|
||||||
|
if ($titre === '' || $contenu === '') {
|
||||||
|
$errors[] = 'Tous les champs sont obligatoires.';
|
||||||
|
} else {
|
||||||
|
$stmt = $pdo->prepare('INSERT INTO articles (titre, contenu, date_creation) VALUES (:titre, :contenu, :date)');
|
||||||
|
$stmt->execute([
|
||||||
|
':titre' => $titre,
|
||||||
|
':contenu' => $contenu,
|
||||||
|
':date' => date('Y-m-d H:i:s'),
|
||||||
|
]);
|
||||||
|
header('Location:board.php');
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="fr">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>Ajouter un article</title>
|
||||||
|
<link rel="stylesheet" href="../assets/add.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<header>
|
||||||
|
<h1>Ajouter un article</h1>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main>
|
||||||
|
<?php foreach ($errors as $e): ?>
|
||||||
|
<p class="error"><?= htmlspecialchars($e) ?></p>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
|
||||||
|
<form method="post">
|
||||||
|
<label>Titre
|
||||||
|
<input type="text" name="titre" value="<?= htmlspecialchars($titre) ?>" required>
|
||||||
|
</label>
|
||||||
|
<label>Contenu
|
||||||
|
<textarea name="contenu" rows="10" required><?= htmlspecialchars($contenu) ?></textarea>
|
||||||
|
</label>
|
||||||
|
<div style="display:flex; gap:10px; justify-content:center;">
|
||||||
|
<button type="submit">Publier</button>
|
||||||
|
<a href="board.php">Annuler</a>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</main>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
42
admin/board.php
Normal file
42
admin/board.php
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
<?php
|
||||||
|
require '../include/db.php';
|
||||||
|
require '../include/authenticator.php';
|
||||||
|
requireLogin();
|
||||||
|
$stmt = $pdo->query('SELECT * FROM articles ORDER BY date_creation DESC');
|
||||||
|
$articles = $stmt->fetchAll();
|
||||||
|
?>
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="fr">
|
||||||
|
<head><meta charset="UTF-8"><title>Admin - Tableau de bord</title></head>
|
||||||
|
<link rel="stylesheet" href="../assets/board.css">
|
||||||
|
<body>
|
||||||
|
<header>
|
||||||
|
<h1>Tableau de bord</h1>
|
||||||
|
<div class="header-buttons">
|
||||||
|
<a href="add.php" class="btn">Ajouter un article</a>
|
||||||
|
<a href="logout.php" class="btn">Se déconnecter</a>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main>
|
||||||
|
<table>
|
||||||
|
<tr><th>ID</th><th>Titre</th><th>Actions</th></tr>
|
||||||
|
<?php foreach ($articles as $a): ?>
|
||||||
|
<tr>
|
||||||
|
<td><?= $a['id'] ?></td>
|
||||||
|
<td><?= htmlspecialchars($a['titre']) ?></td>
|
||||||
|
<td>
|
||||||
|
<a href="modif.php?id=<?= $a['id'] ?>" class="btn">Modifier</a>
|
||||||
|
<a href="delete.php?id=<?= $a['id'] ?>" class="btn">Supprimer</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</table>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<footer>
|
||||||
|
<p>© <?= date('Y') ?> CMS. Tous droits réservés par Abd'R.</p>
|
||||||
|
</footer>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
54
admin/delete.php
Normal file
54
admin/delete.php
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
<?php
|
||||||
|
require '../include/db.php';
|
||||||
|
require '../include/authenticator.php';
|
||||||
|
requireLogin();
|
||||||
|
|
||||||
|
$id = isset($_GET['id']) ? (int)$_GET['id'] : 0;
|
||||||
|
if ($id <= 0) {
|
||||||
|
header('Location:board.php');
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$stmt = $pdo->prepare('SELECT id, titre FROM articles WHERE id = :id');
|
||||||
|
$stmt->execute([':id' => $id]);
|
||||||
|
$article = $stmt->fetch();
|
||||||
|
if (!$article) {
|
||||||
|
header('Location: board.php');
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||||
|
if (isset($_POST['confirm']) && $_POST['confirm'] === 'yes') {
|
||||||
|
$d = $pdo->prepare('DELETE FROM articles WHERE id = :id');
|
||||||
|
$d->execute([':id' => $id]);
|
||||||
|
}
|
||||||
|
header('Location: board.php');
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="fr">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>Supprimer l'article</title>
|
||||||
|
<link rel="stylesheet" href="../assets/delete.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<header>Supprimer l'article</header>
|
||||||
|
|
||||||
|
<main>
|
||||||
|
<p>Êtes-vous sûr de vouloir supprimer : <strong><?= htmlspecialchars($article['titre']) ?></strong> ?</p>
|
||||||
|
<form method="post">
|
||||||
|
<div class="form-buttons">
|
||||||
|
<button type="submit" name="confirm" value="yes">Oui, supprimer</button>
|
||||||
|
<a href="board.php" class="btn">Annuler</a>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
|
|
||||||
38
admin/login.php
Normal file
38
admin/login.php
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
<?php
|
||||||
|
require '../include/db.php';
|
||||||
|
require '../include/authenticator.php';
|
||||||
|
|
||||||
|
$error = '';
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||||
|
if (checkLogin($pdo, $_POST['login'], $_POST['password'])) {
|
||||||
|
header('Location: board.php');
|
||||||
|
exit;
|
||||||
|
} else {
|
||||||
|
$error = 'Identifiants incorrects';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="fr">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Connexion</title>
|
||||||
|
<link rel="stylesheet" href="../assets/login.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<nav>
|
||||||
|
<a href="../index.php">Accueil</a>
|
||||||
|
</nav>
|
||||||
|
<main>
|
||||||
|
<h1>Connexion</h1>
|
||||||
|
<form method="post">
|
||||||
|
<input type="text" name="login" placeholder="Login" required><br>
|
||||||
|
<input type="password" name="password" placeholder="Mot de passe" required><br>
|
||||||
|
<button type="submit">Se connecter</button>
|
||||||
|
</form>
|
||||||
|
</main>
|
||||||
|
<p class="error"><?= $error ?></p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
|
|
||||||
19
admin/logout.php
Normal file
19
admin/logout.php
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
require '../include/authenticator.php';
|
||||||
|
|
||||||
|
$_SESSION = [];
|
||||||
|
|
||||||
|
if (!function_exists('logout_user')) {
|
||||||
|
$_SESSION = [];
|
||||||
|
if (ini_get('session.use_cookies')) {
|
||||||
|
$params = session_get_cookie_params();
|
||||||
|
setcookie(session_name(), '', time() - 42000,
|
||||||
|
$params['path'], $params['domain'], $params['secure'], $params['httponly']);
|
||||||
|
}
|
||||||
|
session_destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
header('Location: ../index.php');
|
||||||
|
exit;
|
||||||
|
?>
|
||||||
|
|
||||||
73
admin/modif.php
Normal file
73
admin/modif.php
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
<?php
|
||||||
|
global $pdo;
|
||||||
|
require '../include/db.php';
|
||||||
|
require '../include/authenticator.php';
|
||||||
|
requireLogin();
|
||||||
|
|
||||||
|
$id = isset($_GET['id']) ? (int)$_GET['id'] : 0;
|
||||||
|
if ($id <= 0) {
|
||||||
|
header('Location: board.php');
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$stmt = $pdo->prepare('SELECT * FROM articles WHERE id = :id');
|
||||||
|
$stmt->execute([':id' => $id]);
|
||||||
|
$article = $stmt->fetch();
|
||||||
|
if (!$article) {
|
||||||
|
header('Location: board.php');
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$errors = [];
|
||||||
|
$titre = $article['titre'];
|
||||||
|
$contenu = $article['contenu'];
|
||||||
|
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||||
|
$titre = trim($_POST['titre'] ?? '');
|
||||||
|
$contenu = trim($_POST['contenu'] ?? '');
|
||||||
|
if ($titre === '' || $contenu === '') {
|
||||||
|
$errors[] = 'Tous les champs sont obligatoires.';
|
||||||
|
} else {
|
||||||
|
$u = $pdo->prepare('UPDATE articles SET titre = :titre, contenu = :contenu WHERE id = :id');
|
||||||
|
$u->execute([':titre' => $titre, ':contenu' => $contenu, ':id' => $id]);
|
||||||
|
header('Location: board.php');
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="fr">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>Modifier l'article</title>
|
||||||
|
<link rel="stylesheet" href="../assets/modif.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<header>Modifier l'article</header>
|
||||||
|
|
||||||
|
<section class="form-section">
|
||||||
|
<main>
|
||||||
|
<?php foreach ($errors as $e): ?>
|
||||||
|
<p class="error"><?= htmlspecialchars($e) ?></p>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
|
||||||
|
<form method="post">
|
||||||
|
<label>Titre
|
||||||
|
<input type="text" name="titre" value="<?= htmlspecialchars($titre) ?>" required>
|
||||||
|
</label>
|
||||||
|
<label>Contenu
|
||||||
|
<textarea name="contenu" rows="10" required><?= htmlspecialchars($contenu) ?></textarea>
|
||||||
|
</label>
|
||||||
|
<div class="form-buttons">
|
||||||
|
<button type="submit">Enregistrer</button>
|
||||||
|
<a href="board.php" class="btn">Annuler</a>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</main>
|
||||||
|
</section>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
|
|
||||||
35
article.php
Normal file
35
article.php
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
<?php
|
||||||
|
require 'include/db.php';
|
||||||
|
$id = isset($_GET['id']) ? (int)$_GET['id'] : 0;
|
||||||
|
$stmt = $pdo->prepare('SELECT * FROM articles WHERE id = ?');
|
||||||
|
$stmt->execute([$id]);
|
||||||
|
$article = $stmt->fetch();
|
||||||
|
if (!$article) { http_response_code(404); die('<h1>404 - Article introuvable</h1>'); }
|
||||||
|
?>
|
||||||
|
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="fr">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title><?= htmlspecialchars($article['titre']) ?></title>
|
||||||
|
<link rel="stylesheet" href="../assets/article.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<header></header>
|
||||||
|
|
||||||
|
<main>
|
||||||
|
<h1 class="article-title"><?= htmlspecialchars($article['titre']) ?></h1>
|
||||||
|
<article>
|
||||||
|
<p><?= nl2br(htmlspecialchars($article['contenu'])) ?></p>
|
||||||
|
</article>
|
||||||
|
<a href="index.php" class="btn">Retour</a>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<footer>
|
||||||
|
<p>© <?= date('Y') ?> CMS. Tous droits réservés par Abd'R.</p>
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
127
assets/add.css
Normal file
127
assets/add.css
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
/* --- Body --- */
|
||||||
|
body {
|
||||||
|
font-family: 'Segoe UI', Roboto, Arial, sans-serif;
|
||||||
|
background-color: #f3f0f9;
|
||||||
|
color: #333;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
min-height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Bande violette en haut --- */
|
||||||
|
header {
|
||||||
|
background: linear-gradient(135deg, #6a11cb, #8e2de2);
|
||||||
|
color: #fff;
|
||||||
|
padding: 12px 0;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center; /* titre centré */
|
||||||
|
align-items: center;
|
||||||
|
font-size: 1.3rem;
|
||||||
|
font-weight: 700;
|
||||||
|
box-shadow: 0 2px 5px rgba(0,0,0,0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Espace distinct entre header et formulaire --- */
|
||||||
|
section.form-section {
|
||||||
|
margin-top: 40px; /* espace entre bande et formulaire */
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Formulaire stylé --- */
|
||||||
|
form {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 15px;
|
||||||
|
background: #fff;
|
||||||
|
padding: 30px 25px;
|
||||||
|
border-radius: 10px;
|
||||||
|
border: 1px solid #e0d4f7;
|
||||||
|
box-shadow: 0 3px 6px rgba(0,0,0,0.08);
|
||||||
|
width: 90%;
|
||||||
|
max-width: 600px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Labels et Inputs --- */
|
||||||
|
form label {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #5b1dbb;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
form input[type="text"],
|
||||||
|
form textarea {
|
||||||
|
padding: 12px 15px;
|
||||||
|
border: 1px solid #dcd0f5;
|
||||||
|
border-radius: 6px;
|
||||||
|
font-size: 1rem;
|
||||||
|
resize: vertical;
|
||||||
|
transition: border-color 0.2s ease, box-shadow 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
form input[type="text"]:focus,
|
||||||
|
form textarea:focus {
|
||||||
|
outline: none;
|
||||||
|
border-color: #8e2de2;
|
||||||
|
box-shadow: 0 0 5px rgba(142,45,226,0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Boutons Publier et Annuler --- */
|
||||||
|
.form-buttons {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
button,
|
||||||
|
a.btn {
|
||||||
|
padding: 12px 25px;
|
||||||
|
background: linear-gradient(135deg, #6a11cb, #8e2de2);
|
||||||
|
color: #fff;
|
||||||
|
border: none;
|
||||||
|
border-radius: 6px;
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: 600;
|
||||||
|
text-decoration: none;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background 0.3s ease, transform 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:hover,
|
||||||
|
a.btn:hover {
|
||||||
|
background: linear-gradient(135deg, #8e2de2, #6a11cb);
|
||||||
|
transform: translateY(-2px);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Messages d'erreur --- */
|
||||||
|
.error {
|
||||||
|
color: #721c24;
|
||||||
|
background: #f8d7da;
|
||||||
|
border: 1px solid #f5c6cb;
|
||||||
|
padding: 12px;
|
||||||
|
border-radius: 6px;
|
||||||
|
width: 90%;
|
||||||
|
max-width: 600px;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
text-align: center;
|
||||||
|
box-shadow: 0 2px 4px rgba(0,0,0,0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Footer violet --- */
|
||||||
|
footer {
|
||||||
|
background: #6a11cb;
|
||||||
|
color: #fff;
|
||||||
|
text-align: center;
|
||||||
|
padding: 15px 0;
|
||||||
|
width: 100%;
|
||||||
|
box-shadow: 0 -2px 5px rgba(0,0,0,0.2);
|
||||||
|
font-size: 0.95rem;
|
||||||
|
position: fixed;
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
81
assets/article.css
Normal file
81
assets/article.css
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
/* --- Body --- */
|
||||||
|
body {
|
||||||
|
font-family: 'Segoe UI', Roboto, Arial, sans-serif;
|
||||||
|
background-color: #f3f0f9;
|
||||||
|
color: #333;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
min-height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Bande violette en haut --- */
|
||||||
|
header {
|
||||||
|
background: linear-gradient(135deg, #6a11cb, #8e2de2);
|
||||||
|
height: 50px; /* hauteur réduite */
|
||||||
|
box-shadow: 0 2px 5px rgba(0,0,0,0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Main --- */
|
||||||
|
main {
|
||||||
|
flex: 1;
|
||||||
|
margin-top: 20px; /* espace sous header */
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Titre de l'article --- */
|
||||||
|
.article-title {
|
||||||
|
color: #5b1dbb;
|
||||||
|
font-size: 2rem;
|
||||||
|
font-weight: 700;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Article --- */
|
||||||
|
article {
|
||||||
|
background: #fff;
|
||||||
|
padding: 25px 20px;
|
||||||
|
border-radius: 10px;
|
||||||
|
border: 1px solid #e0d4f7;
|
||||||
|
box-shadow: 0 3px 6px rgba(0,0,0,0.08);
|
||||||
|
width: 90%;
|
||||||
|
max-width: 800px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Bouton Retour --- */
|
||||||
|
a.btn {
|
||||||
|
padding: 12px 25px;
|
||||||
|
background: linear-gradient(135deg, #6a11cb, #8e2de2);
|
||||||
|
color: #fff;
|
||||||
|
border: none;
|
||||||
|
border-radius: 6px;
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: 600;
|
||||||
|
text-decoration: none;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background 0.3s ease, transform 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
a.btn:hover {
|
||||||
|
background: linear-gradient(135deg, #8e2de2, #6a11cb);
|
||||||
|
transform: translateY(-2px);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Footer --- */
|
||||||
|
footer {
|
||||||
|
background: #6a11cb;
|
||||||
|
color: #fff;
|
||||||
|
text-align: center;
|
||||||
|
padding: 15px 0;
|
||||||
|
width: 100%;
|
||||||
|
font-size: 0.95rem;
|
||||||
|
box-shadow: 0 -2px 5px rgba(0,0,0,0.2);
|
||||||
|
position: fixed;
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
109
assets/board.css
Normal file
109
assets/board.css
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
/* --- Body --- */
|
||||||
|
body {
|
||||||
|
font-family: 'Segoe UI', Roboto, Arial, sans-serif;
|
||||||
|
background-color: #f3f0f9;
|
||||||
|
color: #333;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
min-height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Header violet --- */
|
||||||
|
header {
|
||||||
|
background: linear-gradient(135deg, #6a11cb, #8e2de2);
|
||||||
|
color: #fff;
|
||||||
|
padding: 30px 0 15px 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
box-shadow: 0 2px 5px rgba(0,0,0,0.2);
|
||||||
|
z-index: 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Titre Tableau de bord --- */
|
||||||
|
header h1 {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 2rem;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Conteneur boutons --- */
|
||||||
|
.header-buttons {
|
||||||
|
margin-top: 10px;
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Boutons violet --- */
|
||||||
|
.btn {
|
||||||
|
padding: 10px 20px;
|
||||||
|
background: linear-gradient(135deg, #6a11cb, #8e2de2);
|
||||||
|
color: #fff;
|
||||||
|
border: none;
|
||||||
|
border-radius: 6px;
|
||||||
|
font-weight: 600;
|
||||||
|
text-decoration: none;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background 0.3s ease, transform 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn:hover {
|
||||||
|
background: linear-gradient(135deg, #8e2de2, #6a11cb);
|
||||||
|
transform: translateY(-2px);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Main contenu --- */
|
||||||
|
main {
|
||||||
|
flex: 1;
|
||||||
|
margin-top: 140px; /* hauteur du header */
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Tableau stylé --- */
|
||||||
|
table {
|
||||||
|
width: 90%;
|
||||||
|
max-width: 900px;
|
||||||
|
border-collapse: collapse;
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 8px;
|
||||||
|
overflow: hidden;
|
||||||
|
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
table th, table td {
|
||||||
|
padding: 12px 15px;
|
||||||
|
border-bottom: 1px solid #ddd;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
table th {
|
||||||
|
background-color: #8e2de2;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
table tr:hover {
|
||||||
|
background-color: #f5e9ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Footer violet --- */
|
||||||
|
footer {
|
||||||
|
background: #6a11cb;
|
||||||
|
color: #fff;
|
||||||
|
text-align: center;
|
||||||
|
padding: 15px 0;
|
||||||
|
width: 100%;
|
||||||
|
box-shadow: 0 -2px 5px rgba(0,0,0,0.2);
|
||||||
|
font-size: 0.95rem;
|
||||||
|
position: fixed;
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
75
assets/delete.css
Normal file
75
assets/delete.css
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
/* --- Body --- */
|
||||||
|
body {
|
||||||
|
font-family: 'Segoe UI', Roboto, Arial, sans-serif;
|
||||||
|
background-color: #f3f0f9;
|
||||||
|
color: #333;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
min-height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Bande violette en haut --- */
|
||||||
|
header {
|
||||||
|
background: linear-gradient(135deg, #6a11cb, #8e2de2);
|
||||||
|
color: #fff;
|
||||||
|
padding: 12px 0;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 1.3rem;
|
||||||
|
font-weight: 700;
|
||||||
|
box-shadow: 0 2px 5px rgba(0,0,0,0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Section principale distincte --- */
|
||||||
|
section.form-section {
|
||||||
|
margin-top: 40px; /* espace sous header */
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Formulaire confirmation --- */
|
||||||
|
form {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 20px;
|
||||||
|
background: #fff;
|
||||||
|
padding: 25px 20px;
|
||||||
|
border-radius: 10px;
|
||||||
|
border: 1px solid #e0d4f7;
|
||||||
|
box-shadow: 0 3px 6px rgba(0,0,0,0.08);
|
||||||
|
width: 90%;
|
||||||
|
max-width: 500px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Boutons Supprimer / Annuler --- */
|
||||||
|
.form-buttons {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
button,
|
||||||
|
a.btn {
|
||||||
|
padding: 12px 25px;
|
||||||
|
background: linear-gradient(135deg, #6a11cb, #8e2de2);
|
||||||
|
color: #fff;
|
||||||
|
border: none;
|
||||||
|
border-radius: 6px;
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: 600;
|
||||||
|
text-decoration: none;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background 0.3s ease, transform 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:hover,
|
||||||
|
a.btn:hover {
|
||||||
|
background: linear-gradient(135deg, #8e2de2, #6a11cb);
|
||||||
|
transform: translateY(-2px);
|
||||||
|
}
|
||||||
119
assets/login.css
Normal file
119
assets/login.css
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
/* --- Body --- */
|
||||||
|
body {
|
||||||
|
font-family: 'Segoe UI', Roboto, Arial, sans-serif;
|
||||||
|
background-color: #f3f0f9;
|
||||||
|
color: #333;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
min-height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center; /* CENTRAGE VERTICAL */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Header fixe violet --- */
|
||||||
|
nav {
|
||||||
|
background: linear-gradient(135deg, #6a11cb, #8e2de2);
|
||||||
|
color: #fff;
|
||||||
|
padding: 15px 30px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-start; /* Accueil à gauche */
|
||||||
|
align-items: center;
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
box-shadow: 0 2px 5px rgba(0,0,0,0.2);
|
||||||
|
z-index: 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
nav a {
|
||||||
|
color: #fff;
|
||||||
|
text-decoration: none;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 1.1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
nav a:hover {
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Conteneur du formulaire et du titre --- */
|
||||||
|
.login-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
margin-top: 80px; /* espace pour nav fixe */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Titre Connexion --- */
|
||||||
|
.login-container h1 {
|
||||||
|
color: #5b1dbb;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Formulaire centré --- */
|
||||||
|
form {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 15px;
|
||||||
|
background: #fff;
|
||||||
|
padding: 40px 30px;
|
||||||
|
border-radius: 10px;
|
||||||
|
border: 1px solid #e0d4f7;
|
||||||
|
box-shadow: 0 3px 6px rgba(0,0,0,0.08);
|
||||||
|
width: 90%;
|
||||||
|
max-width: 400px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Inputs --- */
|
||||||
|
form input[type="text"],
|
||||||
|
form input[type="password"] {
|
||||||
|
padding: 12px 15px;
|
||||||
|
border: 1px solid #dcd0f5;
|
||||||
|
border-radius: 6px;
|
||||||
|
font-size: 1rem;
|
||||||
|
transition: border-color 0.2s ease, box-shadow 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
form input[type="text"]:focus,
|
||||||
|
form input[type="password"]:focus {
|
||||||
|
outline: none;
|
||||||
|
border-color: #8e2de2;
|
||||||
|
box-shadow: 0 0 5px rgba(142,45,226,0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Bouton Se connecter --- */
|
||||||
|
form button {
|
||||||
|
padding: 12px;
|
||||||
|
background: linear-gradient(135deg, #6a11cb, #8e2de2);
|
||||||
|
color: #fff;
|
||||||
|
border: none;
|
||||||
|
border-radius: 6px;
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: 600;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background 0.3s ease, transform 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
form button:hover {
|
||||||
|
background: linear-gradient(135deg, #8e2de2, #6a11cb);
|
||||||
|
transform: translateY(-2px);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Footer violet --- */
|
||||||
|
footer {
|
||||||
|
background: #6a11cb;
|
||||||
|
color: #fff;
|
||||||
|
text-align: center;
|
||||||
|
padding: 15px 0;
|
||||||
|
width: 100%;
|
||||||
|
box-shadow: 0 -2px 5px rgba(0,0,0,0.2);
|
||||||
|
font-size: 0.95rem;
|
||||||
|
position: fixed;
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
127
assets/modif.css
Normal file
127
assets/modif.css
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
/* --- Body --- */
|
||||||
|
body {
|
||||||
|
font-family: 'Segoe UI', Roboto, Arial, sans-serif;
|
||||||
|
background-color: #f3f0f9;
|
||||||
|
color: #333;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
min-height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Bande violette en haut --- */
|
||||||
|
header {
|
||||||
|
background: linear-gradient(135deg, #6a11cb, #8e2de2);
|
||||||
|
color: #fff;
|
||||||
|
padding: 12px 0;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center; /* titre centré */
|
||||||
|
align-items: center;
|
||||||
|
font-size: 1.3rem;
|
||||||
|
font-weight: 700;
|
||||||
|
box-shadow: 0 2px 5px rgba(0,0,0,0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Espace distinct entre header et formulaire --- */
|
||||||
|
section.form-section {
|
||||||
|
margin-top: 40px; /* espace entre bande et formulaire */
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Formulaire stylé --- */
|
||||||
|
form {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 15px;
|
||||||
|
background: #fff;
|
||||||
|
padding: 30px 25px;
|
||||||
|
border-radius: 10px;
|
||||||
|
border: 1px solid #e0d4f7;
|
||||||
|
box-shadow: 0 3px 6px rgba(0,0,0,0.08);
|
||||||
|
width: 90%;
|
||||||
|
max-width: 600px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Labels et Inputs --- */
|
||||||
|
form label {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #5b1dbb;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
form input[type="text"],
|
||||||
|
form textarea {
|
||||||
|
padding: 12px 15px;
|
||||||
|
border: 1px solid #dcd0f5;
|
||||||
|
border-radius: 6px;
|
||||||
|
font-size: 1rem;
|
||||||
|
resize: vertical;
|
||||||
|
transition: border-color 0.2s ease, box-shadow 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
form input[type="text"]:focus,
|
||||||
|
form textarea:focus {
|
||||||
|
outline: none;
|
||||||
|
border-color: #8e2de2;
|
||||||
|
box-shadow: 0 0 5px rgba(142,45,226,0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Boutons Publier et Annuler --- */
|
||||||
|
.form-buttons {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
button,
|
||||||
|
a.btn {
|
||||||
|
padding: 12px 25px;
|
||||||
|
background: linear-gradient(135deg, #6a11cb, #8e2de2);
|
||||||
|
color: #fff;
|
||||||
|
border: none;
|
||||||
|
border-radius: 6px;
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: 600;
|
||||||
|
text-decoration: none;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background 0.3s ease, transform 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:hover,
|
||||||
|
a.btn:hover {
|
||||||
|
background: linear-gradient(135deg, #8e2de2, #6a11cb);
|
||||||
|
transform: translateY(-2px);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Messages d'erreur --- */
|
||||||
|
.error {
|
||||||
|
color: #721c24;
|
||||||
|
background: #f8d7da;
|
||||||
|
border: 1px solid #f5c6cb;
|
||||||
|
padding: 12px;
|
||||||
|
border-radius: 6px;
|
||||||
|
width: 90%;
|
||||||
|
max-width: 600px;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
text-align: center;
|
||||||
|
box-shadow: 0 2px 4px rgba(0,0,0,0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Footer violet --- */
|
||||||
|
footer {
|
||||||
|
background: #6a11cb;
|
||||||
|
color: #fff;
|
||||||
|
text-align: center;
|
||||||
|
padding: 15px 0;
|
||||||
|
width: 100%;
|
||||||
|
box-shadow: 0 -2px 5px rgba(0,0,0,0.2);
|
||||||
|
font-size: 0.95rem;
|
||||||
|
position: fixed;
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
137
assets/style.css
Normal file
137
assets/style.css
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
/* --- Style global --- */
|
||||||
|
body {
|
||||||
|
font-family: 'Segoe UI', Roboto, Arial, sans-serif;
|
||||||
|
line-height: 1.6;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
background-color: #f3f0f9;
|
||||||
|
color: #333;
|
||||||
|
min-height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- En-tête --- */
|
||||||
|
header {
|
||||||
|
background: linear-gradient(135deg, #6a11cb, #8e2de2); /* Dégradé violet */
|
||||||
|
color: #fff;
|
||||||
|
padding: 15px 30px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between; /* Accueil à gauche, Admin à droite */
|
||||||
|
align-items: center;
|
||||||
|
position: fixed; /* Fixé en haut */
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
z-index: 1000;
|
||||||
|
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Liens dans le header --- */
|
||||||
|
header a {
|
||||||
|
color: #fff;
|
||||||
|
text-decoration: none;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 1.1rem;
|
||||||
|
transition: opacity 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
header a:hover {
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Espace pour éviter que le contenu passe sous le header --- */
|
||||||
|
main {
|
||||||
|
flex: 1;
|
||||||
|
margin-top: 80px; /* Hauteur du header */
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Titres --- */
|
||||||
|
h1, h2, h3 {
|
||||||
|
color: #5b1dbb;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Articles --- */
|
||||||
|
article {
|
||||||
|
background: #fff;
|
||||||
|
padding: 20px;
|
||||||
|
margin: 15px auto;
|
||||||
|
width: 90%;
|
||||||
|
max-width: 800px;
|
||||||
|
border-radius: 10px;
|
||||||
|
border: 1px solid #e0d4f7;
|
||||||
|
box-shadow: 0 3px 6px rgba(0, 0, 0, 0.08);
|
||||||
|
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
article:hover {
|
||||||
|
transform: translateY(-3px);
|
||||||
|
box-shadow: 0 6px 10px rgba(0, 0, 0, 0.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Liens d’articles --- */
|
||||||
|
article h2 a {
|
||||||
|
color: #8e2de2;
|
||||||
|
text-decoration: none;
|
||||||
|
transition: color 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
article h2 a:hover {
|
||||||
|
color: #5b1dbb;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Tableaux --- */
|
||||||
|
table {
|
||||||
|
width: 90%;
|
||||||
|
margin: 25px auto;
|
||||||
|
border-collapse: collapse;
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 8px;
|
||||||
|
overflow: hidden;
|
||||||
|
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
table th, table td {
|
||||||
|
padding: 12px 15px;
|
||||||
|
border-bottom: 1px solid #ddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
table th {
|
||||||
|
background-color: #8e2de2;
|
||||||
|
color: #fff;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
table tr:hover {
|
||||||
|
background-color: #f5e9ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Messages d’erreur --- */
|
||||||
|
.error {
|
||||||
|
color: #721c24;
|
||||||
|
font-weight: 600;
|
||||||
|
border: 1px solid #f5c6cb;
|
||||||
|
background: #f8d7da;
|
||||||
|
padding: 12px;
|
||||||
|
border-radius: 6px;
|
||||||
|
width: 90%;
|
||||||
|
max-width: 800px;
|
||||||
|
margin: 10px auto;
|
||||||
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Pied de page --- */
|
||||||
|
footer {
|
||||||
|
background: #6a11cb;
|
||||||
|
color: #fff;
|
||||||
|
text-align: center;
|
||||||
|
padding: 15px 0;
|
||||||
|
position: fixed; /* Collé en bas */
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
box-shadow: 0 -2px 5px rgba(0, 0, 0, 0.2);
|
||||||
|
font-size: 0.95rem;
|
||||||
|
}
|
||||||
8
bdd/Dockerfile
Normal file
8
bdd/Dockerfile
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
FROM mysql
|
||||||
|
LABEL authors="abdr-cms"
|
||||||
|
|
||||||
|
ENV MYSQL_ROOT_PASSWORD='passwordroot'
|
||||||
|
|
||||||
|
COPY ./init.sql /docker-entrypoint-initdb.d/
|
||||||
|
|
||||||
|
EXPOSE 3306
|
||||||
20
bdd/init.sql
Normal file
20
bdd/init.sql
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
CREATE DATABASE IF NOT EXISTS cms_simple CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||||
|
|
||||||
|
USE cms_simple;
|
||||||
|
|
||||||
|
CREATE TABLE utilisateur (
|
||||||
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
login VARCHAR(50) UNIQUE NOT NULL,
|
||||||
|
password VARCHAR(255) NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
CREATE TABLE articles (
|
||||||
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
titre VARCHAR(255) NOT NULL,
|
||||||
|
contenu TEXT NOT NULL,
|
||||||
|
date_creation DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
INSERT INTO utilisateur (login, password) VALUES ('user', '$2y$10$W.kLJXFNZPdYcKXQbIyAVO0BGJQcVFc6JGYtsa1Z7SIjRDyUoOIfG');
|
||||||
32
include/authenticator.php
Normal file
32
include/authenticator.php
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
<?php
|
||||||
|
session_start();
|
||||||
|
|
||||||
|
|
||||||
|
function isLogged(): bool
|
||||||
|
{
|
||||||
|
return isset($_SESSION['user']);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function checkLogin(PDO $pdo, $login, $password): bool
|
||||||
|
{
|
||||||
|
$stmt = $pdo->prepare('SELECT * FROM utilisateur WHERE login = ?');
|
||||||
|
$stmt->execute([$login]);
|
||||||
|
$user = $stmt->fetch();
|
||||||
|
|
||||||
|
|
||||||
|
if ($user && password_verify($password, $user['password'])) {
|
||||||
|
$_SESSION['user'] = $user['login'];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function requireLogin() {
|
||||||
|
if (!isLogged()) {
|
||||||
|
header('Location: login.php');
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
12
include/db.php
Normal file
12
include/db.php
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<?php
|
||||||
|
$host = 'CMS_sql'; // nom du conteneur MySQL (dans le réseau Docker)
|
||||||
|
$dbname = 'cms_simple';
|
||||||
|
$user = 'root';
|
||||||
|
$pass = 'passwordroot';
|
||||||
|
|
||||||
|
try {
|
||||||
|
$pdo = new PDO("mysql:host=$host;dbname=$dbname;charset=utf8", $user, $pass);
|
||||||
|
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
die('Erreur de connexion : ' . $e->getMessage());
|
||||||
|
}
|
||||||
42
index.php
Normal file
42
index.php
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
<?php
|
||||||
|
require 'include/db.php';
|
||||||
|
$stmt = $pdo->query('SELECT * FROM articles ORDER BY date_creation DESC LIMIT 10');
|
||||||
|
$articles = $stmt->fetchAll();
|
||||||
|
?>
|
||||||
|
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="fr">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Accueil - CMS</title>
|
||||||
|
<link rel="stylesheet" href="assets/style.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<header>
|
||||||
|
<nav>
|
||||||
|
<a href="index.php">Accueil</a> |
|
||||||
|
<a href="admin/login.php">Administratreur</a>
|
||||||
|
</nav>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main>
|
||||||
|
<h1>Articles</h1>
|
||||||
|
<?php if (empty($articles)): ?>
|
||||||
|
<p>Aucun Article pour le moment</p>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<?php foreach ($articles as $a): ?>
|
||||||
|
<article>
|
||||||
|
<h2><a href="article.php?id=<?= $a['id'] ?>"><?= htmlspecialchars($a['titre']) ?></a></h2>
|
||||||
|
<small>Publié le <?= date('d/m/Y', strtotime($a['date_creation'])) ?></small>
|
||||||
|
<p><?= substr(htmlspecialchars($a['contenu']), 0, 200) ?>...</p>
|
||||||
|
<p><a href="article.php?id=<?= $a['id'] ?>">Lire la suite...</a></p>
|
||||||
|
</article>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<footer>
|
||||||
|
<p>© <?= date('Y') ?> CMS. Tous droits réservés par Abd'R.</p>
|
||||||
|
</footer>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
25
launch-dockers.sh
Normal file
25
launch-dockers.sh
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
docker stop CMS_sql
|
||||||
|
|
||||||
|
docker stop CMS_php
|
||||||
|
|
||||||
|
docker rm CMS_sql
|
||||||
|
|
||||||
|
docker rm CMS_php
|
||||||
|
|
||||||
|
docker network rm CMS-bridge
|
||||||
|
|
||||||
|
docker network create -d bridge CMS-bridge
|
||||||
|
|
||||||
|
cd bdd
|
||||||
|
|
||||||
|
docker build -t cms_sql .
|
||||||
|
|
||||||
|
docker run -d --name CMS_sql -p 3307:3306 --network=CMS-bridge cms_sql:latest
|
||||||
|
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
docker build -t cms_php .
|
||||||
|
|
||||||
|
docker run -d --name CMS_php -p 8080:80 --network=CMS-bridge cms_php:latest
|
||||||
Reference in New Issue
Block a user