feat: add Shaarli Pro theme with new header, styling, and JavaScript.
This commit is contained in:
+205
-9
@@ -401,16 +401,212 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
}
|
||||
});
|
||||
|
||||
// Handle filter toggle switches - using data-url like the example
|
||||
document.querySelectorAll('.toggle-switch input[type="checkbox"]').forEach(checkbox => {
|
||||
checkbox.addEventListener('change', (e) => {
|
||||
const label = e.target.closest('label');
|
||||
if (label && label.dataset.url) {
|
||||
window.location.href = label.dataset.url;
|
||||
}
|
||||
});
|
||||
// Handle filter toggle switches
|
||||
function applyFilters() {
|
||||
const isPrivate = filterPrivate?.checked || false;
|
||||
const isPublic = filterPublic?.checked || false;
|
||||
const isUntagged = filterUntagged?.checked || false;
|
||||
|
||||
let basePath = (typeof shaarli !== 'undefined' && shaarli.basePath) ? shaarli.basePath : '';
|
||||
let url = basePath + '/';
|
||||
|
||||
// Save filter state to localStorage before navigation
|
||||
const filterState = {
|
||||
private: isPrivate,
|
||||
public: isPublic,
|
||||
untagged: isUntagged,
|
||||
timestamp: Date.now()
|
||||
};
|
||||
localStorage.setItem('shaarliFilterState', JSON.stringify(filterState));
|
||||
console.log('[Filter] Saved filter state:', filterState);
|
||||
|
||||
// Build the URL based on selected filters using the correct Shaarli admin paths
|
||||
if (isPrivate && isUntagged) {
|
||||
url = basePath + '/admin/visibility/private?searchtags=';
|
||||
} else if (isPublic && isUntagged) {
|
||||
url = basePath + '/admin/visibility/public?searchtags=';
|
||||
} else if (isPrivate) {
|
||||
url = basePath + '/admin/visibility/private';
|
||||
} else if (isPublic) {
|
||||
url = basePath + '/admin/visibility/public';
|
||||
} else if (isUntagged) {
|
||||
url = basePath + '/untagged-only';
|
||||
} else {
|
||||
// No filter selected - clear the state
|
||||
localStorage.removeItem('shaarliFilterState');
|
||||
}
|
||||
|
||||
console.log('[Filter] Navigating to:', url);
|
||||
window.location.href = url;
|
||||
}
|
||||
|
||||
// Clear filters function
|
||||
function clearFilters() {
|
||||
localStorage.removeItem('shaarliFilterState');
|
||||
if (filterPrivate) filterPrivate.checked = false;
|
||||
if (filterPublic) filterPublic.checked = false;
|
||||
if (filterUntagged) filterUntagged.checked = false;
|
||||
}
|
||||
|
||||
// Private and public are mutually exclusive
|
||||
filterPrivate?.addEventListener('change', (e) => {
|
||||
if (e.target.checked && filterPublic) {
|
||||
filterPublic.checked = false;
|
||||
}
|
||||
applyFilters();
|
||||
});
|
||||
|
||||
filterPublic?.addEventListener('change', (e) => {
|
||||
if (e.target.checked && filterPrivate) {
|
||||
filterPrivate.checked = false;
|
||||
}
|
||||
applyFilters();
|
||||
});
|
||||
|
||||
filterUntagged?.addEventListener('change', () => {
|
||||
applyFilters();
|
||||
});
|
||||
|
||||
// Initialize filter states from localStorage (since Shaarli redirects after applying filters)
|
||||
(function initFilterStates() {
|
||||
console.log('[Filter Debug] ========================================');
|
||||
|
||||
// Try to read filter state from localStorage
|
||||
let savedState = null;
|
||||
try {
|
||||
const savedJson = localStorage.getItem('shaarliFilterState');
|
||||
if (savedJson) {
|
||||
savedState = JSON.parse(savedJson);
|
||||
console.log('[Filter Debug] Found saved filter state:', savedState);
|
||||
|
||||
// Check if state is not too old (30 seconds max)
|
||||
const age = Date.now() - (savedState.timestamp || 0);
|
||||
if (age > 30000) {
|
||||
console.log('[Filter Debug] Saved state is too old, ignoring');
|
||||
localStorage.removeItem('shaarliFilterState');
|
||||
savedState = null;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.log('[Filter Debug] Error reading saved state:', e);
|
||||
}
|
||||
|
||||
// Determine active filters from saved state
|
||||
let isPrivateActive = savedState?.private || false;
|
||||
let isPublicActive = savedState?.public || false;
|
||||
let isUntaggedActive = savedState?.untagged || false;
|
||||
|
||||
console.log('[Filter Debug] isPrivateActive:', isPrivateActive);
|
||||
console.log('[Filter Debug] isPublicActive:', isPublicActive);
|
||||
console.log('[Filter Debug] isUntaggedActive:', isUntaggedActive);
|
||||
|
||||
// Set checkbox states
|
||||
if (filterPrivate && isPrivateActive) {
|
||||
filterPrivate.checked = true;
|
||||
console.log('[Filter Debug] ✓ Set filterPrivate to CHECKED');
|
||||
}
|
||||
if (filterPublic && isPublicActive) {
|
||||
filterPublic.checked = true;
|
||||
console.log('[Filter Debug] ✓ Set filterPublic to CHECKED');
|
||||
}
|
||||
if (filterUntagged && isUntaggedActive) {
|
||||
filterUntagged.checked = true;
|
||||
console.log('[Filter Debug] ✓ Set filterUntagged to CHECKED');
|
||||
}
|
||||
|
||||
const hasActiveFilter = isPrivateActive || isPublicActive || isUntaggedActive;
|
||||
console.log('[Filter Debug] hasActiveFilter:', hasActiveFilter);
|
||||
console.log('[Filter Debug] ========================================');
|
||||
|
||||
// Add/update filter indicator badge on the filter button
|
||||
if (filterToggleBtn && hasActiveFilter) {
|
||||
filterToggleBtn.classList.add('has-active-filter');
|
||||
console.log('[Filter Debug] Added has-active-filter class to button');
|
||||
|
||||
// Add badge indicator if not exists
|
||||
if (!filterToggleBtn.querySelector('.filter-badge')) {
|
||||
const badge = document.createElement('span');
|
||||
badge.className = 'filter-badge';
|
||||
filterToggleBtn.appendChild(badge);
|
||||
console.log('[Filter Debug] Added filter badge');
|
||||
}
|
||||
}
|
||||
|
||||
// Create and display the filter info banner
|
||||
if (hasActiveFilter && !document.getElementById('filter-info-banner')) {
|
||||
// Build the message - describe the active filter without count
|
||||
let filterParts = [];
|
||||
|
||||
if (isPrivateActive) {
|
||||
filterParts.push('<strong>private</strong> links');
|
||||
} else if (isPublicActive) {
|
||||
filterParts.push('<strong>public</strong> links');
|
||||
}
|
||||
|
||||
if (isUntaggedActive) {
|
||||
if (filterParts.length > 0) {
|
||||
filterParts.push('without tags');
|
||||
} else {
|
||||
filterParts.push('links <strong>without tags</strong>');
|
||||
}
|
||||
}
|
||||
|
||||
let message = 'Showing ' + filterParts.join(' ');
|
||||
|
||||
console.log('[Filter Debug] filterParts:', filterParts);
|
||||
console.log('[Filter Debug] message:', message);
|
||||
|
||||
if (filterParts.length > 0) {
|
||||
// Get base path safely
|
||||
const basePath = (typeof shaarli !== 'undefined' && shaarli.basePath) ? shaarli.basePath : '';
|
||||
|
||||
const banner = document.createElement('div');
|
||||
banner.id = 'filter-info-banner';
|
||||
banner.className = 'filter-info-banner';
|
||||
banner.innerHTML = `
|
||||
<div class="filter-info-content">
|
||||
<i class="mdi mdi-filter-variant"></i>
|
||||
<span>${message}</span>
|
||||
</div>
|
||||
<button type="button" class="filter-clear-btn" id="filter-clear-btn" title="Clear filters">
|
||||
<i class="mdi mdi-close"></i>
|
||||
<span>Clear</span>
|
||||
</button>
|
||||
`;
|
||||
|
||||
// Try to find the best insertion point
|
||||
const contentToolbar = document.querySelector('.content-toolbar');
|
||||
const linklist = document.getElementById('linklist');
|
||||
const linksList = document.getElementById('links-list');
|
||||
|
||||
console.log('[Filter Debug] contentToolbar:', contentToolbar);
|
||||
console.log('[Filter Debug] linklist:', linklist);
|
||||
console.log('[Filter Debug] linksList:', linksList);
|
||||
|
||||
// Insert after the content-toolbar (pagination)
|
||||
if (contentToolbar && contentToolbar.parentNode) {
|
||||
contentToolbar.parentNode.insertBefore(banner, contentToolbar.nextSibling);
|
||||
console.log('[Filter Debug] Banner inserted after content-toolbar');
|
||||
} else if (linksList && linksList.parentNode) {
|
||||
linksList.parentNode.insertBefore(banner, linksList);
|
||||
console.log('[Filter Debug] Banner inserted before links-list');
|
||||
} else if (linklist) {
|
||||
linklist.insertBefore(banner, linklist.firstChild);
|
||||
console.log('[Filter Debug] Banner inserted at beginning of linklist');
|
||||
} else {
|
||||
console.log('[Filter Debug] Could not find insertion point for banner');
|
||||
}
|
||||
|
||||
// Add click handler to clear button
|
||||
document.getElementById('filter-clear-btn')?.addEventListener('click', () => {
|
||||
localStorage.removeItem('shaarliFilterState');
|
||||
console.log('[Filter] Cleared filter state from localStorage');
|
||||
window.location.href = basePath + '/';
|
||||
});
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
||||
// Handle links per page options
|
||||
|
||||
|
||||
@@ -421,7 +617,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
e.preventDefault();
|
||||
const value = filterInput.value;
|
||||
if (value && value > 0) {
|
||||
window.location.href = shaarli.basePath + '/?nb=' + value;
|
||||
window.location.href = shaarli.basePath + '/links-per-page?nb=' + value;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user