diff --git a/content/showArticle.php b/content/showArticle.php index 254fd4f..71cea81 100644 --- a/content/showArticle.php +++ b/content/showArticle.php @@ -5,6 +5,30 @@ $repliesByParent = []; $articleObj = null; include_once 'php/controller/showArticle-controller.php'; +require_once 'php/model/UserManager.php'; + +$userManager = UserManager::getInstance(); + +/** + * Liefert den vollständigen Namen zu einer gespeicherten E-Mail-Adresse. + * Falls kein Benutzer gefunden wird, wird die E-Mail als Ersatz angezeigt. + */ +function getCommentAuthorName($email, $userManager) +{ + $email = trim($email); + $user = $userManager->findUser($email); + + if ($user === null) { + return $email; + } + + $vorname = trim($user["vorname"] ?? ""); + $nachname = trim($user["nachname"] ?? ""); + + $fullName = trim($vorname . " " . $nachname); + + return $fullName !== "" ? $fullName : $email; +} /* * Ermittelt, ob ohne JavaScript auf einen Kommentar * geantwortet werden soll. @@ -178,7 +202,14 @@ if ($replyAuthor === null) {
- getAuthor()); ?>
+ getAuthor(),
+ $userManager
+ )
+ );
+ ?>
@@ -313,7 +344,14 @@ if ($replyAuthor === null) {
- getAuthor()); ?>
+ getAuthor(),
+ $userManager
+ )
+ );
+ ?>
diff --git a/css/main.css b/css/main.css
index e72f17f..a2bc707 100644
--- a/css/main.css
+++ b/css/main.css
@@ -154,21 +154,32 @@ h1 {
.button {
width: 100%;
- padding: 12px;
+ padding: 14px;
background-color: #2563eb;
color: white;
- border: none;
+ border: 2px solid transparent;
border-radius: 8px;
font-size: 1rem;
font-weight: bold;
cursor: pointer;
- transition: background-color 0.2s, transform 0.2s, box-shadow 0.2s;
+ transition:
+ background-color 0.2s ease,
+ transform 0.2s ease,
+ box-shadow 0.2s ease,
+ border-color 0.2s ease;
}
.button:hover {
+ background-color: #1e40af;
+ border-color: #93c5fd;
+ transform: translateY(-3px) scale(1.01);
+ box-shadow: 0 8px 18px rgba(37, 99, 235, 0.35);
+}
+
+.button:active {
background-color: #1d4ed8;
- transform: translateY(-2px);
- box-shadow: 0 4px 10px rgba(0,0,0,0.15);
+ transform: translateY(1px) scale(0.99);
+ box-shadow: 0 2px 5px rgba(37, 99, 235, 0.25);
}
.register-link {
@@ -225,4 +236,182 @@ h1 {
text-align: center;
text-decoration: none;
box-sizing: border-box;
+}
+
+/* Deutlichere Klickreaktion für Kategorien */
+.category-link:active {
+ transform: translateY(1px);
+ box-shadow: none;
+}
+
+/* Sichtbare Tastatur-Markierung */
+.button:focus-visible,
+.category-link:focus-visible,
+.article-link a:focus-visible,
+.register-link a:focus-visible {
+ outline: 3px solid #fbbf24;
+ outline-offset: 3px;
+}
+/* Kommentarbereich */
+
+#comments-list {
+ display: flex;
+ flex-direction: column;
+ gap: 20px;
+ margin-bottom: 40px;
+}
+
+#comments-list > div,
+.comment {
+ background-color: #ffffff;
+ border: 1px solid #dbe3ec;
+ border-radius: 12px;
+ padding: 24px;
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.06);
+ transition:
+ transform 0.2s ease,
+ box-shadow 0.2s ease,
+ border-color 0.2s ease;
+}
+
+#comments-list > div:hover,
+.comment:hover {
+ transform: translateY(-3px);
+ border-color: #93c5fd;
+ box-shadow: 0 8px 20px rgba(0, 0, 0, 0.12);
+}
+
+#comments-list textarea,
+#comment-content {
+ width: 100%;
+ box-sizing: border-box;
+ padding: 14px;
+ border: 1px solid #cbd5e1;
+ border-radius: 8px;
+ font-size: 1rem;
+ resize: vertical;
+ transition:
+ border-color 0.2s ease,
+ box-shadow 0.2s ease;
+}
+
+#comments-list textarea:focus,
+#comment-content:focus {
+ outline: none;
+ border-color: #2563eb;
+ box-shadow: 0 0 0 4px rgba(37, 99, 235, 0.18);
+}
+
+#comments-list a {
+ color: #2563eb;
+ font-weight: bold;
+ text-decoration: none;
+ border-radius: 4px;
+ transition:
+ color 0.2s ease,
+ background-color 0.2s ease;
+}
+
+#comments-list a:hover {
+ color: #1e40af;
+ background-color: #dbeafe;
+ text-decoration: underline;
+}
+
+#comments-list button {
+ cursor: pointer;
+}
+.delete-comment-button {
+ display: inline-block;
+ background: #ffffff;
+ color: #dc2626;
+ border: 2px solid #dc2626;
+ border-radius: 8px;
+ padding: 10px 18px;
+ font-size: 0.95rem;
+ font-weight: 600;
+ cursor: pointer;
+ transition:
+ background-color 0.25s ease,
+ color 0.25s ease,
+ transform 0.2s ease,
+ box-shadow 0.2s ease;
+ }
+
+.delete-comment-button:hover {
+ background: #dc2626;
+ color: #ffffff;
+ transform: translateY(-2px);
+ box-shadow: 0 6px 14px rgba(220,38,38,0.25);
+}
+
+.delete-comment-button:active {
+ transform: translateY(1px);
+ box-shadow: none;
+}
+.delete-comment-form {
+ margin-top: 12px;
+ margin-bottom: 12px;
+}
+/* Button zum Öffnen der Kommentarbearbeitung */
+.edit-comment-button {
+ display: inline-block;
+ width: auto;
+ padding: 10px 18px;
+ background-color: #2563eb;
+ color: #ffffff;
+ border: 2px solid #2563eb;
+ border-radius: 8px;
+ font-size: 0.95rem;
+ font-weight: 600;
+ cursor: pointer;
+ list-style: none;
+ transition:
+ background-color 0.2s ease,
+ border-color 0.2s ease,
+ transform 0.2s ease,
+ box-shadow 0.2s ease;
+}
+
+/* Entfernt das normale Dreieck in einigen Browsern */
+.edit-comment-button::-webkit-details-marker {
+ display: none;
+}
+
+/* Eigenes Symbol vor dem Text */
+.edit-comment-button::before {
+ content: "✏ ";
+}
+
+.edit-comment-button:hover {
+ background-color: #1e40af;
+ border-color: #1e40af;
+ transform: translateY(-2px);
+ box-shadow: 0 5px 12px rgba(37, 99, 235, 0.3);
+}
+
+.edit-comment-button:active {
+ transform: translateY(1px);
+ box-shadow: none;
+}
+
+.edit-comment-button:focus-visible {
+ outline: 3px solid #fbbf24;
+ outline-offset: 3px;
+}
+
+/* Abstand zwischen Bearbeiten und Löschen */
+.edit-comment-details {
+ margin-bottom: 12px;
+}
+
+/* Geöffneter Bearbeitungsbereich */
+.edit-comment-details[open] .edit-comment-button {
+ margin-bottom: 12px;
+ background-color: #1e40af;
+}
+
+/* Geändertes Symbol, wenn der Bereich geöffnet ist */
+.edit-comment-details[open] .edit-comment-button::before {
+ content: "▲ ";
}
\ No newline at end of file
diff --git a/css/navbar.css b/css/navbar.css
index fa5f5b3..9d9b208 100644
--- a/css/navbar.css
+++ b/css/navbar.css
@@ -248,7 +248,7 @@ CSS für die navbar
z-index: 1000;
transition: left 0.3s ease;
padding: 2rem 1rem;
- box-shadow: 2px 0 10px rgba(0,0,0,0.5);
+ box-shadow: 2px 0 10px rgba(0, 0, 0, 0.5);
overflow-y: auto;
/* Genug Abstand oben rechts, damit Links nicht hinter dem X liegen */
@@ -328,5 +328,89 @@ CSS für die navbar
padding: 0.8rem 1rem;
cursor: pointer;
}
+}
+ /* Deutlichere Hover-Effekte für die Navigation */
-}
\ No newline at end of file
+ .nav__dropdown-toggle,
+ .nav__link {
+ border-radius: 6px;
+ transition:
+ background-color 0.2s ease,
+ color 0.2s ease,
+ transform 0.2s ease;
+ }
+
+ .nav__dropdown-toggle:hover,
+ .nav__link:hover {
+ background-color: #ffffff;
+ color: #1d4ed8;
+ transform: translateY(-2px);
+ }
+
+ /* Sichtbare Reaktion beim Anklicken */
+ .nav__dropdown-toggle:active,
+ .nav__link:active {
+ transform: translateY(1px);
+ }
+
+ /* Deutlichere Effekte für Anmelden, Registrieren usw. */
+ .nav__button {
+ transition:
+ background-color 0.2s ease,
+ color 0.2s ease,
+ transform 0.2s ease,
+ box-shadow 0.2s ease;
+ }
+
+ .nav__button:hover {
+ background-color: #2563eb;
+ color: #ffffff;
+ transform: translateY(-2px);
+ box-shadow: 0 4px 10px rgba(0, 0, 0, 0.3);
+ }
+
+ .nav__button:active {
+ transform: translateY(1px);
+ box-shadow: none;
+ }
+
+ /* Deutlichere Hervorhebung der Einträge im Dropdown-Menü */
+ .nav__dropdown-menu a {
+ display: block;
+ transition:
+ background-color 0.2s ease,
+ color 0.2s ease,
+ padding-left 0.2s ease;
+ }
+
+ .nav__dropdown-menu a:hover {
+ background-color: #dbeafe;
+ color: #1d4ed8;
+ padding-left: 1.4rem;
+ }
+
+ /* Effekt für den Suchbutton */
+ .nav__search-button {
+ transition:
+ background-color 0.2s ease,
+ color 0.2s ease,
+ transform 0.2s ease;
+ }
+
+ .nav__search-button:hover {
+ background-color: #2563eb;
+ color: #ffffff;
+ }
+
+ .nav__search-button:active {
+ transform: scale(0.95);
+ }
+
+ /* Sichtbare Markierung bei Tastaturbedienung */
+ .nav a:focus-visible,
+ .nav button:focus-visible,
+ .nav input:focus-visible,
+ .nav label:focus-visible {
+ outline: 3px solid #fbbf24;
+ outline-offset: 3px;
+ }
diff --git a/php/ajax/add-comment.php b/php/ajax/add-comment.php
index b71f5c4..41f4af3 100644
--- a/php/ajax/add-comment.php
+++ b/php/ajax/add-comment.php
@@ -4,6 +4,7 @@ if (session_status() === PHP_SESSION_NONE) {
}
require_once "../model/CommentManager.php";
+require_once "../model/UserManager.php";
require_once "../model/ArticleManager.php";
require_once "../../includes/csrf.php";
@@ -211,13 +212,29 @@ try {
$parentCommentId
);
+ $userManager = UserManager::getInstance();
+ $user = $userManager->findUser($_SESSION["user_email"]);
+
+ $authorName = $_SESSION["user_email"];
+
+ if ($user !== null) {
+ $vorname = trim($user["vorname"] ?? "");
+ $nachname = trim($user["nachname"] ?? "");
+
+ $fullName = trim($vorname . " " . $nachname);
+
+ if ($fullName !== "") {
+ $authorName = $fullName;
+ }
+ }
+
sendCommentResponse(
true,
"Der Kommentar wurde erfolgreich gespeichert.",
$articleId,
[
"commentId" => $commentId,
- "author" => $_SESSION["user_email"],
+ "author" => $authorName,
"content" => $content,
"created" => date("Y-m-d H:i:s"),
"parentCommentId" => $parentCommentId
diff --git a/php/model/DatabaseArticleManager.php b/php/model/DatabaseArticleManager.php
index 4e4140a..f145546 100644
--- a/php/model/DatabaseArticleManager.php
+++ b/php/model/DatabaseArticleManager.php
@@ -76,10 +76,7 @@ class DatabaseArticleManager implements ArticleManagerDAO {
return intval($db->lastInsertId());
} catch (PDOException $e) {
- // NEU: Die rohe PDO-Fehlermeldung wird nicht mehr direkt in die
- // eigene Exception übernommen (Kapselung), sondern durch eine
- // generische, sprechende Meldung ersetzt - analog zu den übrigen
- // Methoden dieser Klasse und zu DatabaseUserManager.
+
throw new InternalServerErrorException("internal_error");
}
}
@@ -284,14 +281,14 @@ class DatabaseArticleManager implements ArticleManagerDAO {
$db = $this->getConnection();
$sql = "SELECT id, title, content, author, category, tags, created
- FROM articles
- WHERE title LIKE :keyword
- OR content LIKE :keyword
- OR tags LIKE :keyword";
+ FROM articles
+ WHERE title LIKE :keyword
+ OR content LIKE :keyword
+ OR tags LIKE :keyword;";
$command = $db->prepare($sql);
- // Wildcards für die Suche hinzufügen
+ // Wildcards für die SQL-Suche hinzufügen
$searchParam = '%' . $cleankeyword . '%';
$command->execute([
@@ -302,10 +299,11 @@ class DatabaseArticleManager implements ArticleManagerDAO {
$filteredArticles = [];
foreach ($rows as $row) {
- $likes = $this->getLikesForArticle(intval($row['id']));
+ $articleId = intval($row['id']);
+ $likes = $this->getLikesForArticle($articleId);
$filteredArticles[] = new Article(
- intval($row['id']),
+ $articleId,
$row['title'] ?? '',
$row['content'] ?? '',
$row['author'] ?? '',
@@ -323,6 +321,7 @@ class DatabaseArticleManager implements ArticleManagerDAO {
}
}
+
/**
* Holt alle User-IDs, die einen bestimmten Beitrag geliked haben.
*