add search functionality

This commit is contained in:
Eric Blommel
2024-12-10 19:36:54 +01:00
parent c8c9c64ef2
commit b6a9585125
3 changed files with 130 additions and 47 deletions

View File

@@ -1,31 +0,0 @@
// Update search function with fallback animation
function handleSearch() {
const searchTerm = document.getElementById('searchInput').value.toLowerCase();
const topicCards = document.querySelectorAll('.topic-card');
topicCards.forEach(card => {
const title = card.querySelector('.topic-title')?.textContent.toLowerCase() || '';
const description = card.querySelector('.topic-description')?.textContent.toLowerCase() || '';
const relatedTopics = Array.from(card.querySelectorAll('.related-topics li'))
.map(li => li.textContent.toLowerCase())
.join(' ');
const content = `${title} ${description} ${relatedTopics}`;
if (content.includes(searchTerm)) {
card.style.display = 'block';
if (window.gsap) {
gsap.to(card, {
opacity: 1,
y: 0,
duration: 0.3
});
} else {
card.style.opacity = 1;
card.style.transform = 'translateY(0)';
}
} else {
card.style.display = 'none';
}
});
}

View File

@@ -17,12 +17,11 @@
<!-- Login/Logout Button -->
<div class="flex items-center space-x-4">
<!-- Search Bar TODO: Implement search functionality -->
<form action="search.php" method="GET" class="relative flex items-center">
<input type="text" name="query" placeholder="Suche..."
class="w-64 px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--primary-color)] pl-10">
<i class="fas fa-search absolute left-3 text-gray-400"></i>
</form>
<!-- Search Button -->
<button id="openSearchDialog"
class="bg-white text-[var(--primary-color)] border-2 border-[var(--primary-color)] w-10 h-10 flex items-center justify-center rounded-lg hover:bg-[var(--primary-color)] hover:text-white transition duration-300">
<i class="fas fa-search"></i>
</button>
<?php
require_once("classes/User.php");
@@ -31,21 +30,26 @@
?>
<div class="relative">
<!-- Dropdown Trigger -->
<button id="userDropdownToggle" class="bg-[var(--primary-color)] text-white px-4 py-2 rounded-lg hover:bg-[var(--accent-color)] transition duration-300 flex items-center">
<button id="userDropdownToggle"
class="bg-[var(--primary-color)] text-white px-4 py-2 rounded-lg hover:bg-[var(--accent-color)] transition duration-300 flex items-center">
<span><?php echo htmlspecialchars($_SESSION['user']->getUsername()); ?></span>
<i class="fas fa-chevron-down ml-2"></i>
</button>
<!-- Dropdown Menu -->
<div id="userDropdownMenu" class="hidden absolute right-0 mt-2 w-48 bg-white rounded-lg shadow-lg border">
<a href="account.php" class="block px-4 py-2 text-gray-700 hover:bg-gray-100 rounded-t-lg flex items-center">
<div id="userDropdownMenu"
class="hidden absolute right-0 mt-2 w-48 bg-white rounded-lg shadow-lg border">
<a href="account.php"
class="block px-4 py-2 text-gray-700 hover:bg-gray-100 rounded-t-lg flex items-center">
<i class="fas fa-user mr-2"></i> Accountseite
</a>
<button id="dropdownChangePasswordButton" class="block w-full text-left px-4 py-2 text-gray-700 hover:bg-gray-100 flex items-center">
<button id="dropdownChangePasswordButton"
class="block w-full text-left px-4 py-2 text-gray-700 hover:bg-gray-100 flex items-center">
<i class="fas fa-key mr-2"></i> Passwort ändern
</button>
<form id="dropdownLogoutForm" action="logout.php" method="POST" class="block">
<button type="submit" class="w-full text-left px-4 py-2 text-gray-700 hover:bg-gray-100 rounded-b-lg flex items-center">
<button type="submit"
class="w-full text-left px-4 py-2 text-gray-700 hover:bg-gray-100 rounded-b-lg flex items-center">
<i class="fas fa-sign-out-alt mr-2"></i> Logout
</button>
</form>
@@ -102,7 +106,8 @@ if (!isset($_SESSION['user']) || !$_SESSION['user']->isLoggedIn()) {
<?php
if (isset($_SESSION['user']) && $_SESSION['user']->isLoggedIn()) {
?>
<div id="changePasswordPopup" class="hidden fixed inset-0 bg-black/50 flex items-center justify-center z-50" role="dialog"
<div id="changePasswordPopup" class="hidden fixed inset-0 bg-black/50 flex items-center justify-center z-50"
role="dialog"
aria-labelledby="changePasswordTitle" aria-hidden="true">
<div class="bg-white p-8 rounded-lg shadow-lg w-full max-w-sm relative">
<button id="closeChangePasswordPopupButton" class="absolute top-2 right-2 text-gray-500 text-xl"
@@ -112,15 +117,18 @@ if (isset($_SESSION['user']) && $_SESSION['user']->isLoggedIn()) {
<form id="changePasswordForm" action="password.php" method="POST">
<div class="mb-4">
<label for="currentPassword" class="block text-gray-700 mb-2">Aktuelles Passwort:</label>
<input type="password" id="currentPassword" name="currentPassword" class="w-full p-2 border rounded-lg" required>
<input type="password" id="currentPassword" name="currentPassword"
class="w-full p-2 border rounded-lg" required>
</div>
<div class="mb-4">
<label for="newPassword" class="block text-gray-700 mb-2">Neues Passwort:</label>
<input type="password" id="newPassword" name="newPassword" class="w-full p-2 border rounded-lg" required>
<input type="password" id="newPassword" name="newPassword" class="w-full p-2 border rounded-lg"
required>
</div>
<div class="mb-4">
<label for="confirmNewPassword" class="block text-gray-700 mb-2">Neues Passwort bestätigen:</label>
<input type="password" id="confirmNewPassword" name="confirmNewPassword" class="w-full p-2 border rounded-lg" required>
<input type="password" id="confirmNewPassword" name="confirmNewPassword"
class="w-full p-2 border rounded-lg" required>
</div>
<button type="submit"
class="w-full bg-[var(--primary-color)] text-white px-4 py-2 rounded-lg hover:bg-[var(--accent-color)] transition duration-300">
@@ -145,6 +153,16 @@ if (isset($_SESSION['user']) && $_SESSION['user']->isLoggedIn()) {
</div>
</div>
<!-- Search Dialog -->
<div id="searchDialog" class="hidden fixed inset-0 bg-black/50 flex items-center justify-center z-50">
<div class="bg-white p-8 rounded-lg shadow-lg w-full max-w-lg relative">
<button id="closeSearchDialog" class="absolute top-2 right-2 text-gray-500 text-xl">&times;</button>
<h2 class="text-2xl font-bold mb-6 text-center">Suche</h2>
<input type="text" id="searchInput" placeholder="Search..." class="w-full p-2 border rounded-lg mb-4">
<div id="searchResults" class="max-h-64 overflow-y-auto"></div>
</div>
</div>
<script>
// JavaScript to handle opening and closing of the login popup
const loginButton = document.getElementById('loginButton');
@@ -189,7 +207,6 @@ if (isset($_SESSION['user']) && $_SESSION['user']->isLoggedIn()) {
});
// JavaScript to handle opening and closing of the change password popup
const changePasswordButton = document.getElementById('changePasswordButton');
const changePasswordPopup = document.getElementById('changePasswordPopup');
@@ -304,5 +321,62 @@ if (isset($_SESSION['user']) && $_SESSION['user']->isLoggedIn()) {
}
});
}
document.getElementById('openSearchDialog').addEventListener('click', function () {
document.getElementById('searchDialog').classList.remove('hidden');
});
document.getElementById('closeSearchDialog').addEventListener('click', function () {
document.getElementById('searchDialog').classList.add('hidden');
});
function debounce(func, delay) {
let debounceTimer;
return function () {
const context = this;
const args = arguments;
clearTimeout(debounceTimer);
debounceTimer = setTimeout(() => func.apply(context, args), delay);
};
}
const searchInput = document.getElementById('searchInput');
const resultsContainer = document.getElementById('searchResults');
searchInput.addEventListener('input', debounce(function () {
const query = this.value.toLowerCase();
resultsContainer.innerHTML = '';
if (query.length > 0) {
fetch('search.php?query=' + query)
.then(response => response.json())
.then(data => {
data.forEach(item => {
const resultItem = document.createElement('div');
resultItem.classList.add('p-4', 'mb-2', 'rounded-lg', 'bg-white', 'hover:bg-gray-100', 'transition', 'duration-100', 'flex', 'items-center', 'space-x-2', 'cursor-pointer');
const subjectSpan = document.createElement('span');
subjectSpan.classList.add('font-bold');
subjectSpan.textContent = item.displayName.split(' - ')[0];
const breadcrumbSpan = document.createElement('span');
breadcrumbSpan.classList.add('text-gray-500');
breadcrumbSpan.textContent = item.displayName.split(' - ').slice(1).join(' > ');
resultItem.appendChild(subjectSpan);
resultItem.appendChild(breadcrumbSpan);
resultItem.addEventListener('click', function () {
if (item.type === 'subject') {
window.location.href = 'subject.php?subject=' + item.id;
} else {
window.location.href = 'topic.php?subject=' + item.subjectId + '&topic=' + item.id;
}
});
resultsContainer.appendChild(resultItem);
});
});
}
}, 300));
</script>

40
webseite/search.php Normal file
View File

@@ -0,0 +1,40 @@
<?php
require_once("classes/SubjectData.php");
require_once("classes/TopicData.php");
if (!isset($_GET['query'])) {
die(json_encode([]));
}
$query = strtolower(trim($_GET['query']));
$subjects = SubjectData::getAll();
$results = [];
foreach ($subjects as $subject) {
if (strpos(strtolower($subject->displayName), $query) !== false) {
$results[] = [
'type' => 'subject',
'id' => $subject->id,
'displayName' => $subject->displayName
];
}
foreach ($subject->topics as $topic) {
if (
strpos(strtolower($subject->displayName), $query) !== false ||
strpos(strtolower($topic->displayName), $query) !== false ||
strpos(strtolower($topic->description), $query) !== false ||
strpos(strtolower($topic->article), $query) !== false
) {
$results[] = [
'type' => 'topic',
'subjectId' => $topic->subjectId,
'id' => $topic->id,
'displayName' => $subject->displayName . ' - ' . $topic->displayName
];
}
}
}
header('Content-Type: application/json');
echo json_encode($results);
?>