diff --git a/include/css/style.css b/include/css/style.css index efe0a64..e337ce4 100644 --- a/include/css/style.css +++ b/include/css/style.css @@ -106,6 +106,14 @@ body[style*="background-image"] { font-size: 1.5rem; /* Increased font size for site title */ } +.navbar { + position: relative; +} + +.navbar-collapse { + position: relative; +} + /* Class to force light text color when background is dark */ body.dark-background-active { color: #f8f9fa !important; @@ -185,5 +193,220 @@ body.dark-background-active .form-text, /* Custom styles for transparent theme */ [data-bs-theme="transparent"] { - + /* Transparent theme styles can be added here if needed */ +} + +/* New navbar layout */ +.container-fluid { + display: flex; + align-items: center; + justify-content: space-between; + position: relative; +} + +.navbar-left { + flex: 0 0 auto; +} + +.navbar-right { + flex: 0 0 auto; +} + +/* Search functionality styles */ +.input-group.search { + margin-top: 16px; +} + +/* Hide search bar on login page */ +body.login-page .search-container-center { + display: none !important; +} + + +.search-container-center { + position: absolute; + left: 50%; + transform: translateX(-50%); + max-width: 600px; + width: 100%; + z-index: 10; +} + +.search-container-center .form-control { + font-size: 1.1rem; + padding: 0.75rem 1rem; + height: auto; +} + +.search-container-center .btn { + padding: 0.75rem 1rem; + font-size: 1.1rem; +} + +.search-results { + position: absolute; + top: 100%; + left: 0; + right: 0; + background: var(--bs-body-bg); + border: 1px solid var(--bs-border-color); + border-top: none; + border-radius: 0 0 0.375rem 0.375rem; + max-height: 300px; + overflow-y: auto; + z-index: 1000; + display: none; + box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075); +} + +.search-results.show { + display: block; +} + +.search-result-item { + padding: 0.75rem 1rem; + border-bottom: 1px solid var(--bs-border-color); + cursor: pointer; + transition: background-color 0.15s ease-in-out; + display: flex; + align-items: center; + gap: 0.5rem; +} + +.search-result-item:hover { + background-color: var(--bs-gray-100); +} + +.search-result-item:last-child { + border-bottom: none; +} + +.search-result-item .bookmark-icon { + width: 16px; + height: 16px; + flex-shrink: 0; +} + +.search-result-item .bookmark-info { + flex: 1; + min-width: 0; +} + +.search-result-item .bookmark-title { + font-weight: 500; + color: var(--bs-body-color); + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + margin: 0; +} + +.search-result-item .bookmark-url { + font-size: 0.875rem; + color: var(--bs-secondary); + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + margin: 0; +} + +.search-result-item .bookmark-category { + font-size: 0.75rem; + color: var(--bs-dark); + background: var(--bs-warning); + padding: 0.125rem 0.375rem; + border-radius: 0.25rem; + white-space: nowrap; + font-weight: 500; +} + +.search-no-results { + padding: 1rem; + text-align: center; + color: var(--bs-muted); + font-style: italic; +} + +.search-engine-results { + padding: 0.5rem; + background: var(--bs-info-bg-subtle); + border-bottom: 1px solid var(--bs-border-color); +} + +.search-engine-results .search-engine-item { + padding: 0.5rem; + cursor: pointer; + border-radius: 0.25rem; + transition: background-color 0.15s ease-in-out; +} + +.search-engine-item:hover { + background-color: var(--bs-info); + color: white; +} + +/* Dark theme adjustments for search */ +[data-bs-theme="dark"] .search-results { + background: var(--bs-dark); + border-color: var(--bs-gray-700); +} + +[data-bs-theme="dark"] .search-result-item:hover { + background-color: var(--bs-gray-800); +} + +[data-bs-theme="dark"] .search-result-item .bookmark-category { + color: var(--bs-dark); + background: var(--bs-warning); +} + +[data-bs-theme="dark"] .search-engine-results { + background: var(--bs-dark); +} + +[data-bs-theme="dark"] .search-engine-item:hover { + background-color: var(--bs-primary); +} + +/* Responsive search bar */ +@media (max-width: 768px) { + .container-fluid { + flex-direction: column; + align-items: stretch; + } + + .search-container-center { + position: static; + transform: none; + max-width: 100%; + margin: 1rem auto; + order: -1; + } + + .search-container-center .form-control { + font-size: 1rem; + padding: 0.6rem 0.8rem; + } + + .search-container-center .btn { + padding: 0.6rem 0.8rem; + font-size: 1rem; + } + + .search-results { + position: fixed; + top: auto; + left: 1rem; + right: 1rem; + max-height: 50vh; + } + + .navbar-collapse { + flex-direction: column; + } + + .navbar-nav { + margin-left: 0 !important; + margin-right: 0 !important; + } } diff --git a/include/header.php b/include/header.php index 6662a34..79f95e4 100644 --- a/include/header.php +++ b/include/header.php @@ -33,6 +33,11 @@ if ($theme !== 'dark' && intval($bg_brightness) < 70) { $body_classes[] = 'dark-background-active'; } +// Add any additional body classes from globals +if (isset($GLOBALS['body_class'])) { + $body_classes[] = $GLOBALS['body_class']; +} + $navbar_classes = ['navbar', 'navbar-expand-lg', 'mb-4']; if (in_array('dark-background-active', $body_classes) || $theme === 'dark') { $navbar_classes[] = 'navbar-dark'; @@ -99,17 +104,37 @@ if ($theme === 'dark' || in_array('dark-background-active', $body_classes)) {
+ diff --git a/include/js/script.js b/include/js/script.js index 2737bce..235393d 100644 --- a/include/js/script.js +++ b/include/js/script.js @@ -274,6 +274,9 @@ document.addEventListener('DOMContentLoaded', function() { // Initialize SortableJS for drag-and-drop initSortable(); + // Initialize search functionality + initSearch(); + // Add form submit handlers to format URLs before submission // Use event delegation to handle dynamically created forms document.addEventListener('submit', function(event) { @@ -385,4 +388,184 @@ function optimizeImage(path) { alert('A network error occurred: ' + error.message); }); } +} + +// Search functionality +function initSearch() { + const searchInput = document.getElementById('searchInput'); + const searchButton = document.getElementById('searchButton'); + const searchEngineButton = document.getElementById('searchEngineButton'); + const searchResults = document.getElementById('searchResults'); + + if (!searchInput || !searchResults) return; + + let searchTimeout; + let allBookmarks = []; + + // Load all bookmarks on page load + loadAllBookmarks(); + + // Search input event + searchInput.addEventListener('input', function() { + clearTimeout(searchTimeout); + const query = this.value.trim(); + + if (query.length < 2) { + hideSearchResults(); + return; + } + + searchTimeout = setTimeout(() => { + performSearch(query); + }, 300); + }); + + // Search button click + if (searchButton) { + searchButton.addEventListener('click', function() { + const query = searchInput.value.trim(); + if (query.length >= 2) { + performSearch(query); + } + }); + } + + // Search engine button click + if (searchEngineButton) { + searchEngineButton.addEventListener('click', function() { + const query = searchInput.value.trim(); + if (query) { + searchOnWeb(query); + } + }); + } + + // Hide search results when clicking outside + document.addEventListener('click', function(event) { + if (!searchInput.contains(event.target) && !searchResults.contains(event.target)) { + hideSearchResults(); + } + }); + + // Keyboard shortcuts + document.addEventListener('keydown', function(event) { + // Ctrl+K to focus search + if (event.ctrlKey && event.key === 'k') { + event.preventDefault(); + searchInput.focus(); + } + + // Escape to hide results + if (event.key === 'Escape') { + hideSearchResults(); + searchInput.blur(); + } + }); + + function loadAllBookmarks() { + // Extract bookmarks from the current page + const bookmarkElements = document.querySelectorAll('.bookmark-link, .list-group-item a'); + allBookmarks = []; + + bookmarkElements.forEach(element => { + const title = element.textContent.trim(); + const url = element.href; + const icon = element.querySelector('img')?.src || 'include/images/default-icon.png'; + + // Find category name + let categoryName = ''; + const categoryElement = element.closest('.category-column'); + if (categoryElement) { + const categoryTitle = categoryElement.querySelector('h5'); + if (categoryTitle) { + categoryName = categoryTitle.textContent.trim(); + } + } + + allBookmarks.push({ + title: title, + url: url, + icon: icon, + category: categoryName + }); + }); + } + + function performSearch(query) { + const results = allBookmarks.filter(bookmark => + bookmark.title.toLowerCase().includes(query.toLowerCase()) || + bookmark.url.toLowerCase().includes(query.toLowerCase()) || + bookmark.category.toLowerCase().includes(query.toLowerCase()) + ); + + displaySearchResults(results, query); + } + + function displaySearchResults(results, query) { + searchResults.innerHTML = ''; + + if (results.length === 0) { + searchResults.innerHTML = ` +
+ Geen bladwijzers gevonden voor "${query}" +
+ `; + } else { + // Add search engine options + searchResults.innerHTML = ` +
+
+ + Zoek "${query}" op Google +
+
+ + Zoek "${query}" op DuckDuckGo +
+
+ `; + + // Add bookmark results + results.forEach(bookmark => { + const resultItem = document.createElement('div'); + resultItem.className = 'search-result-item'; + resultItem.onclick = () => { + window.open(bookmark.url, '_blank'); + hideSearchResults(); + }; + + resultItem.innerHTML = ` + +
+
${bookmark.title}
+
${bookmark.url}
+
+ ${bookmark.category ? `${bookmark.category}` : ''} + `; + + searchResults.appendChild(resultItem); + }); + } + + showSearchResults(); + } + + function showSearchResults() { + searchResults.classList.add('show'); + } + + function hideSearchResults() { + searchResults.classList.remove('show'); + } +} + +// Search engine functions +function searchOnWeb(query) { + const searchUrl = `https://www.google.com/search?q=${encodeURIComponent(query)}`; + window.open(searchUrl, '_blank'); +} + +function searchOnDuckDuckGo(query) { + const searchUrl = `https://duckduckgo.com/?q=${encodeURIComponent(query)}`; + window.open(searchUrl, '_blank'); } \ No newline at end of file diff --git a/lang/nl.php b/lang/nl.php index 00a99da..7d36566 100644 --- a/lang/nl.php +++ b/lang/nl.php @@ -147,4 +147,11 @@ return [ 'tab_clear_token_confirm' => 'Weet je zeker dat je de inlog-token wilt wissen? De unieke URL werkt dan niet meer.', 'tooltip_copy_to_clipboard' => 'Kopieer naar klembord', 'tooltip_copied' => 'Gekopieerd!', + + // Search functionality + 'search_placeholder' => 'Zoeken (Ctrl+K)', + 'search_no_results' => 'Geen bladwijzers gevonden voor', + 'search_google' => 'Zoek op Google', + 'search_duckduckgo' => 'Zoek op DuckDuckGo', + 'search_web' => 'Zoek op internet', ]; diff --git a/login.php b/login.php index 2e75ea4..17a2ca2 100644 --- a/login.php +++ b/login.php @@ -83,6 +83,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { } } +// Add login-page class to body for CSS targeting +$GLOBALS['body_class'] = 'login-page'; require_once 'include/header.php'; ?>