Search per tab, style, db update

This commit is contained in:
rogier committed 2025-10-06 21:56:58 +02:00
1 parent 80ddd17d45
commit 9b43c28ee3
10 files changed
+148 -58

No files matched your search

+5 -3
View File
@@ -19,8 +19,8 @@ try {
// Create a new tab // Create a new tab
$data = json_decode(file_get_contents('php://input'), true); $data = json_decode(file_get_contents('php://input'), true);
if (isset($data['name'])) { if (isset($data['name'])) {
$stmt = $pdo->prepare("INSERT INTO tabs (name, user_id) VALUES (?, ?)"); $stmt = $pdo->prepare("INSERT INTO tabs (name, user_id, show_search_bar) VALUES (?, ?, ?)");
$stmt->execute([$data['name'], $data['user_id'] ?? null]); $stmt->execute([$data['name'], $data['user_id'] ?? null, $data['show_search_bar'] ?? 1]);
$response = ['id' => $pdo->lastInsertId(), 'name' => $data['name']]; $response = ['id' => $pdo->lastInsertId(), 'name' => $data['name']];
} else { } else {
http_response_code(400); // Bad Request http_response_code(400); // Bad Request
@@ -42,6 +42,7 @@ try {
'theme' => $data['theme'] ?? null, 'theme' => $data['theme'] ?? null,
'theme_transparency' => $data['theme_transparency'] ?? null, 'theme_transparency' => $data['theme_transparency'] ?? null,
'column_count' => $data['column_count'] ?? 5, 'column_count' => $data['column_count'] ?? 5,
'show_search_bar' => $data['show_search_bar'] ?? 1,
]; ];
// Handle empty strings to set them to NULL for proper fallback // Handle empty strings to set them to NULL for proper fallback
@@ -65,7 +66,8 @@ try {
background_saturation = :background_saturation, background_saturation = :background_saturation,
theme = :theme, theme = :theme,
theme_transparency = :theme_transparency, theme_transparency = :theme_transparency,
column_count = :column_count column_count = :column_count,
show_search_bar = :show_search_bar
WHERE id = :id WHERE id = :id
"); ");
+13 -1
View File
@@ -23,7 +23,8 @@ try {
'background_saturation' => 'INTEGER DEFAULT 100', 'background_saturation' => 'INTEGER DEFAULT 100',
'theme' => 'TEXT DEFAULT NULL', 'theme' => 'TEXT DEFAULT NULL',
'theme_transparency' => 'INTEGER DEFAULT NULL', 'theme_transparency' => 'INTEGER DEFAULT NULL',
'login_token' => 'VARCHAR(255)' 'login_token' => 'VARCHAR(255)',
'show_search_bar' => 'INTEGER DEFAULT 1'
]; ];
$columns_added = false; $columns_added = false;
@@ -77,6 +78,17 @@ try {
} }
} }
// --- Check settings table for show_search_bar setting ---
$settings_check = $pdo->prepare("SELECT value FROM settings WHERE key = 'show_search_bar'");
$settings_check->execute();
if (!$settings_check->fetch()) {
$pdo->prepare("INSERT INTO settings (key, value) VALUES (?, ?)")->execute(['show_search_bar', '1']);
$messages[] = "Added 'show_search_bar' setting to settings table.";
$columns_added = true;
} else {
$messages[] = "Setting 'show_search_bar' already exists in settings table.";
}
if ($columns_added) { if ($columns_added) {
echo json_encode(['success' => true, 'message' => 'Database updated successfully!', 'details' => $messages]); echo json_encode(['success' => true, 'message' => 'Database updated successfully!', 'details' => $messages]);
} else { } else {
+49 -8
View File
@@ -192,9 +192,6 @@ body.dark-background-active .form-text,
} }
/* Custom styles for transparent theme */ /* Custom styles for transparent theme */
[data-bs-theme="transparent"] {
/* Transparent theme styles can be added here if needed */
}
/* New navbar layout */ /* New navbar layout */
.container-fluid { .container-fluid {
@@ -232,20 +229,64 @@ body.user-settings-page .search-container-center {
position: absolute; position: absolute;
left: 50%; left: 50%;
transform: translateX(-50%); transform: translateX(-50%);
max-width: 600px; max-width: 500px;
width: 100%; width: 100%;
z-index: 10; z-index: 10;
} }
.search-container-center .input-group {
border-radius: 25px;
overflow: hidden;
background-color: rgba(255, 255, 255, 0.05);
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.1);
}
.search-container-center .form-control { .search-container-center .form-control {
font-size: 1.1rem; font-size: 1rem;
padding: 0.75rem 1rem; padding: 0.6rem 1rem;
height: auto; height: auto;
border: none;
background-color: transparent;
color: white;
box-shadow: none;
}
.search-container-center .form-control:focus {
border: none;
box-shadow: none;
background-color: transparent;
outline: none;
}
.search-container-center .form-control::placeholder {
color: rgba(255, 255, 255, 0.6);
} }
.search-container-center .btn { .search-container-center .btn {
padding: 0.75rem 1rem; padding: 0.6rem 0.8rem;
font-size: 1.1rem; font-size: 1rem;
background-color: transparent;
border: none;
color: rgba(255, 255, 255, 0.7);
transition: all 0.2s ease;
}
.search-container-center .btn:hover {
background-color: rgba(255, 255, 255, 0.1);
color: white;
}
/* Reset button styling */
.search-container-center #searchResetButton {
background-color: transparent;
border: none;
color: rgba(255, 255, 255, 0.5);
}
.search-container-center #searchResetButton:hover {
background-color: rgba(255, 255, 255, 0.1);
color: white;
} }
.search-results { .search-results {
+20 -4
View File
@@ -115,18 +115,34 @@ if ($theme === 'dark' || in_array('dark-background-active', $body_classes)) {
</div> </div>
<!-- Center: Search Bar --> <!-- Center: Search Bar -->
<?php
// Check if search bar should be shown
$show_search_bar = true;
// First check global setting
if (($settings['show_search_bar'] ?? '1') !== '1') {
$show_search_bar = false;
}
// Then check tab-specific setting if current tab data is available
if (isset($current_tab_data) && $current_tab_data && isset($current_tab_data['show_search_bar'])) {
$show_search_bar = ($current_tab_data['show_search_bar'] == 1);
}
if ($show_search_bar): ?>
<div class="search-container-center"> <div class="search-container-center">
<div class="input-group search"> <div class="input-group search">
<input type="text" class="form-control" id="searchInput" placeholder="<?php echo translate('index_search_placeholder'); ?>" autocomplete="off"> <input type="text" class="form-control" id="searchInput" placeholder="<?php echo translate('index_search_placeholder'); ?>" autocomplete="off">
<button class="btn btn-outline-secondary" type="button" id="searchButton"> <button class="btn btn-outline-secondary" type="button" id="searchResetButton" style="display: none;">
<i class="bi bi-search"></i> <i class="bi bi-x"></i>
</button> </button>
<button class="btn btn-outline-secondary" type="button" id="searchEngineButton" title="Zoek op internet"> <button class="btn btn-primary" type="button" id="searchButton">
<i class="bi bi-globe"></i> <i class="bi bi-search"></i>
</button> </button>
</div> </div>
<div id="searchResults" class="search-results"></div> <div id="searchResults" class="search-results"></div>
</div> </div>
<?php endif; ?>
<!-- Right side: Navigation --> <!-- Right side: Navigation -->
<div class="navbar-right"> <div class="navbar-right">
+13
View File
@@ -53,6 +53,13 @@ if ($db_initialized) {
$pdo->exec("ALTER TABLE users ADD COLUMN role TEXT NOT NULL DEFAULT 'user'"); $pdo->exec("ALTER TABLE users ADD COLUMN role TEXT NOT NULL DEFAULT 'user'");
$pdo->exec("UPDATE users SET role = 'admin' WHERE id = 1"); $pdo->exec("UPDATE users SET role = 'admin' WHERE id = 1");
} }
// Add show_search_bar setting if it doesn't exist
$stmt = $pdo->prepare("SELECT value FROM settings WHERE key = 'show_search_bar'");
$stmt->execute();
if (!$stmt->fetch()) {
$pdo->prepare("INSERT INTO settings (key, value) VALUES (?, ?)")->execute(['show_search_bar', '1']);
}
} }
if (!$db_initialized) { if (!$db_initialized) {
@@ -85,6 +92,7 @@ if (!$db_initialized) {
'language' => 'en', 'language' => 'en',
'favicon_extractor_url' => 'https://favicon.hibbit.cloud', 'favicon_extractor_url' => 'https://favicon.hibbit.cloud',
'debug_mode' => '0', 'debug_mode' => '0',
'show_search_bar' => '1',
'theme' => 'transparent', 'theme' => 'transparent',
'background_image_url' => '', 'background_image_url' => '',
'background_brightness' => '50', 'background_brightness' => '50',
@@ -174,6 +182,11 @@ if (tableExists($pdo, 'tabs') && !columnExists($pdo, 'tabs', 'column_count')) {
$pdo->exec("ALTER TABLE tabs ADD COLUMN column_count INTEGER DEFAULT 5"); $pdo->exec("ALTER TABLE tabs ADD COLUMN column_count INTEGER DEFAULT 5");
} }
// Migration: Add show_search_bar to tabs table if it doesn't exist
if (tableExists($pdo, 'tabs') && !columnExists($pdo, 'tabs', 'show_search_bar')) {
$pdo->exec("ALTER TABLE tabs ADD COLUMN show_search_bar INTEGER DEFAULT 1");
}
// Check if tab_id column exists in bookmarks table // Check if tab_id column exists in bookmarks table
if (!columnExists($pdo, 'bookmarks', 'tab_id')) { if (!columnExists($pdo, 'bookmarks', 'tab_id')) {
$pdo->exec("ALTER TABLE bookmarks ADD COLUMN tab_id INTEGER"); $pdo->exec("ALTER TABLE bookmarks ADD COLUMN tab_id INTEGER");
+17 -33
View File
@@ -394,9 +394,10 @@ function optimizeImage(path) {
function initSearch() { function initSearch() {
const searchInput = document.getElementById('searchInput'); const searchInput = document.getElementById('searchInput');
const searchButton = document.getElementById('searchButton'); const searchButton = document.getElementById('searchButton');
const searchEngineButton = document.getElementById('searchEngineButton'); const searchResetButton = document.getElementById('searchResetButton');
const searchResults = document.getElementById('searchResults'); const searchResults = document.getElementById('searchResults');
// Check if search bar is enabled and elements exist
if (!searchInput || !searchResults) return; if (!searchInput || !searchResults) return;
let searchTimeout; let searchTimeout;
@@ -410,6 +411,13 @@ function initSearch() {
clearTimeout(searchTimeout); clearTimeout(searchTimeout);
const query = this.value.trim(); const query = this.value.trim();
// Show/hide reset button based on input content
if (query.length > 0) {
searchResetButton.style.display = 'block';
} else {
searchResetButton.style.display = 'none';
}
if (query.length < 2) { if (query.length < 2) {
hideSearchResults(); hideSearchResults();
return; return;
@@ -430,16 +438,17 @@ function initSearch() {
}); });
} }
// Search engine button click // Reset button click
if (searchEngineButton) { if (searchResetButton) {
searchEngineButton.addEventListener('click', function() { searchResetButton.addEventListener('click', function() {
const query = searchInput.value.trim(); searchInput.value = '';
if (query) { searchResetButton.style.display = 'none';
searchOnWeb(query); hideSearchResults();
} searchInput.focus();
}); });
} }
// Hide search results when clicking outside // Hide search results when clicking outside
document.addEventListener('click', function(event) { document.addEventListener('click', function(event) {
if (!searchInput.contains(event.target) && !searchResults.contains(event.target)) { if (!searchInput.contains(event.target) && !searchResults.contains(event.target)) {
@@ -525,20 +534,6 @@ function initSearch() {
</div> </div>
`; `;
} else { } else {
// Add search engine options
searchResults.innerHTML = `
<div class="search-engine-results">
<div class="search-engine-item" onclick="searchOnWeb('${query}')">
<i class="bi bi-globe me-2"></i>
Zoek "${query}" op Google
</div>
<div class="search-engine-item" onclick="searchOnDuckDuckGo('${query}')">
<i class="bi bi-search me-2"></i>
Zoek "${query}" op DuckDuckGo
</div>
</div>
`;
// Add bookmark results // Add bookmark results
results.forEach(bookmark => { results.forEach(bookmark => {
const resultItem = document.createElement('div'); const resultItem = document.createElement('div');
@@ -576,14 +571,3 @@ function initSearch() {
searchResults.classList.remove('show'); 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');
}
+3
View File
@@ -70,6 +70,7 @@ return [
'settings_favicon_extractor_url' => 'Favicon Extractor Base URL', 'settings_favicon_extractor_url' => 'Favicon Extractor Base URL',
'settings_favicon_extractor_url_help' => 'Provide the service base URL (e.g., http://localhost:3000). The path /favicon/{URL}?larger=true will be appended automatically.', 'settings_favicon_extractor_url_help' => 'Provide the service base URL (e.g., http://localhost:3000). The path /favicon/{URL}?larger=true will be appended automatically.',
'settings_debug_mode' => 'Enable Debug mode', 'settings_debug_mode' => 'Enable Debug mode',
'settings_show_search_bar' => 'Show search bar',
'settings_save_settings_button' => 'Save Settings', 'settings_save_settings_button' => 'Save Settings',
'settings_user_account_title' => 'User Account', 'settings_user_account_title' => 'User Account',
'settings_new_password' => 'New Password (leave blank to keep current)', 'settings_new_password' => 'New Password (leave blank to keep current)',
@@ -146,4 +147,6 @@ return [
'tab_clear_token_confirm' => 'Are you sure you want to clear the login token? The unique URL will no longer work.', 'tab_clear_token_confirm' => 'Are you sure you want to clear the login token? The unique URL will no longer work.',
'tooltip_copy_to_clipboard' => 'Copy to clipboard', 'tooltip_copy_to_clipboard' => 'Copy to clipboard',
'tooltip_copied' => 'Copied!', 'tooltip_copied' => 'Copied!',
'tab_show_search_bar' => 'Show search bar',
'tab_show_search_bar_help' => 'Enable or disable the search bar for this specific tab. This overrides the global search bar setting.',
]; ];
+3
View File
@@ -70,6 +70,7 @@ return [
'settings_favicon_extractor_url' => 'Favicon Extractor Basis URL', 'settings_favicon_extractor_url' => 'Favicon Extractor Basis URL',
'settings_favicon_extractor_url_help' => 'Geef de basis-URL van de service op (bijv. http://localhost:3000). Het pad /favicon/{URL}?larger=true wordt automatisch toegevoegd.', 'settings_favicon_extractor_url_help' => 'Geef de basis-URL van de service op (bijv. http://localhost:3000). Het pad /favicon/{URL}?larger=true wordt automatisch toegevoegd.',
'settings_debug_mode' => 'Foutopsporingsmodus inschakelen', 'settings_debug_mode' => 'Foutopsporingsmodus inschakelen',
'settings_show_search_bar' => 'Zoekbalk weergeven',
'settings_save_settings_button' => 'Instellingen Opslaan', 'settings_save_settings_button' => 'Instellingen Opslaan',
'settings_user_account_title' => 'Gebruikersaccount', 'settings_user_account_title' => 'Gebruikersaccount',
'settings_new_password' => 'Nieuw Wachtwoord (laat leeg om huidige te behouden)', 'settings_new_password' => 'Nieuw Wachtwoord (laat leeg om huidige te behouden)',
@@ -147,6 +148,8 @@ return [
'tab_clear_token_confirm' => 'Weet je zeker dat je de inlog-token wilt wissen? De unieke URL werkt dan niet meer.', '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_copy_to_clipboard' => 'Kopieer naar klembord',
'tooltip_copied' => 'Gekopieerd!', 'tooltip_copied' => 'Gekopieerd!',
'tab_show_search_bar' => 'Zoekbalk weergeven',
'tab_show_search_bar_help' => 'Schakel de zoekbalk in of uit voor dit specifieke tabblad. Dit overschrijft de globale zoekbalk instelling.',
// Search functionality // Search functionality
'search_placeholder' => 'Zoeken (Ctrl+K)', 'search_placeholder' => 'Zoeken (Ctrl+K)',
+5 -1
View File
@@ -31,7 +31,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
} }
// Handle checkboxes separately, as they are not sent when unchecked // Handle checkboxes separately, as they are not sent when unchecked
$checkboxes = ['display_site_title', 'open_new_tab', 'dashboard_protected']; $checkboxes = ['display_site_title', 'open_new_tab', 'dashboard_protected', 'show_search_bar'];
foreach ($checkboxes as $key) { foreach ($checkboxes as $key) {
$upsert_stmt->execute([$key, isset($_POST[$key]) ? '1' : '0']); $upsert_stmt->execute([$key, isset($_POST[$key]) ? '1' : '0']);
} }
@@ -292,6 +292,10 @@ require_once 'include/header.php';
<input class="form-check-input" type="checkbox" role="switch" id="dashboard_protected" name="dashboard_protected" value="1" <?php echo ($settings['dashboard_protected'] ?? '0') === '1' ? 'checked' : ''; ?>> <input class="form-check-input" type="checkbox" role="switch" id="dashboard_protected" name="dashboard_protected" value="1" <?php echo ($settings['dashboard_protected'] ?? '0') === '1' ? 'checked' : ''; ?>>
<label class="form-check-label" for="dashboard_protected"><?php echo translate('settings_dashboard_protection'); ?></label> <label class="form-check-label" for="dashboard_protected"><?php echo translate('settings_dashboard_protection'); ?></label>
</div> </div>
<div class="mb-3 form-check form-switch">
<input class="form-check-input" type="checkbox" role="switch" id="show_search_bar" name="show_search_bar" value="1" <?php echo ($settings['show_search_bar'] ?? '1') === '1' ? 'checked' : ''; ?>>
<label class="form-check-label" for="show_search_bar"><?php echo translate('settings_show_search_bar'); ?></label>
</div>
<div class="mb-3"> <div class="mb-3">
<label for="remember_me_duration" class="form-label"><?php echo translate('settings_stay_logged_in'); ?></label> <label for="remember_me_duration" class="form-label"><?php echo translate('settings_stay_logged_in'); ?></label>
<select class="form-select" id="remember_me_duration" name="remember_me_duration"> <select class="form-select" id="remember_me_duration" name="remember_me_duration">
+20 -8
View File
@@ -87,13 +87,22 @@ require_once 'include/header.php';
<?php endforeach; ?> <?php endforeach; ?>
</select> </select>
</div> </div>
<div class="mb-3"> <div class="row">
<label for="edit-tab-column-count" class="form-label">Column Count (Tablet/Desktop)</label> <div class="col-md-6 mb-3">
<select id="edit-tab-column-count" class="form-select"> <label for="edit-tab-column-count" class="form-label">Column Count (Tablet/Desktop)</label>
<option value="4">4</option> <select id="edit-tab-column-count" class="form-select">
<option value="5">5</option> <option value="4">4</option>
<option value="6">6</option> <option value="5">5</option>
</select> <option value="6">6</option>
</select>
</div>
<div class="col-md-6 mb-3">
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" role="switch" id="edit-tab-show-search-bar" name="edit-tab-show-search-bar">
<label class="form-check-label" for="edit-tab-show-search-bar"><?php echo translate('tab_show_search_bar'); ?></label>
</div>
<div class="form-text"><?php echo translate('tab_show_search_bar_help'); ?></div>
</div>
</div> </div>
<div class="mb-3"> <div class="mb-3">
<label for="edit-tab-login-url" class="form-label"><?php echo translate('tab_unique_url_label'); ?></label> <label for="edit-tab-login-url" class="form-label"><?php echo translate('tab_unique_url_label'); ?></label>
@@ -365,6 +374,7 @@ document.addEventListener('DOMContentLoaded', function() {
document.getElementById('edit-tab-name').value = tabData.name; document.getElementById('edit-tab-name').value = tabData.name;
document.getElementById('edit-tab-owner').value = tabData.user_id || ''; document.getElementById('edit-tab-owner').value = tabData.user_id || '';
document.getElementById('edit-tab-column-count').value = tabData.column_count || '5'; document.getElementById('edit-tab-column-count').value = tabData.column_count || '5';
document.getElementById('edit-tab-show-search-bar').checked = (tabData.show_search_bar ?? 1) == 1;
// Populate login url // Populate login url
const loginUrlInput = document.getElementById('edit-tab-login-url'); const loginUrlInput = document.getElementById('edit-tab-login-url');
@@ -510,6 +520,7 @@ document.addEventListener('DOMContentLoaded', function() {
const name = document.getElementById('edit-tab-name').value.trim(); const name = document.getElementById('edit-tab-name').value.trim();
const ownerId = document.getElementById('edit-tab-owner').value; const ownerId = document.getElementById('edit-tab-owner').value;
const columnCount = document.getElementById('edit-tab-column-count').value; const columnCount = document.getElementById('edit-tab-column-count').value;
const showSearchBar = document.getElementById('edit-tab-show-search-bar').checked ? 1 : 0;
// Get theme and background values from the other modal's inputs // Get theme and background values from the other modal's inputs
const theme = document.getElementById('edit-tab-theme').value; const theme = document.getElementById('edit-tab-theme').value;
@@ -529,6 +540,7 @@ document.addEventListener('DOMContentLoaded', function() {
name: name, name: name,
user_id: ownerId, user_id: ownerId,
column_count: columnCount, column_count: columnCount,
show_search_bar: showSearchBar,
theme: theme, theme: theme,
theme_transparency: transparency, theme_transparency: transparency,
background_image_url: backgroundUrl, background_image_url: backgroundUrl,
@@ -555,7 +567,7 @@ document.addEventListener('DOMContentLoaded', function() {
await fetch('api/tabs.php', { await fetch('api/tabs.php', {
method: 'POST', method: 'POST',
headers: { 'Content-Type': 'application/json' }, headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name: name, user_id: userId }) body: JSON.stringify({ name: name, user_id: userId, show_search_bar: 1 })
}); });
newTabNameInput.value = ''; newTabNameInput.value = '';
newTabUserInput.value = ''; newTabUserInput.value = '';