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. *