-
-
-
{% trans "Popular Links" %}
-
- {% for item in popular_links %}
-
-
- {% empty %}
-
-
- {{ item.link.alias }}
-
-
- {% trans "Clicks" %}: {{ item.link.click_count }}
-{% trans "No popular links available" %}
- {% endfor %} + +
+
@@ -216,22 +217,24 @@
+
+
+
+
+
-
-
-
{% trans "Popular Links" %}
-
- {% for item in popular_links %}
-
-
-
- {{ item.link.alias }}
-
-
+
+ {% trans "Clicks" %}: {{ item.link.click_count }}
-
+
@@ -538,35 +541,156 @@
const localTime = utcTime.toLocaleString();
element.textContent = localTime;
});
- });
- // Random image refresh functionality
- function refreshRandomImage(img) {
- const box = img.getAttribute('data-box');
- const timestamp = new Date().getTime();
- const width = img.offsetWidth || 500;
- const height = img.offsetHeight || 500;
- const newUrl = `/api/images/random/${width}/${height}/?fit=crop&v=${timestamp}&box=${box}`;
+ // Main search functionality - Desktop
+ setupMainSearch('main-search-input', 'main-search-results');
+
+ // Main search functionality - Mobile
+ setupMainSearch('main-search-input-mobile', 'main-search-results-mobile');
- // Create new image to preload
- const newImg = new Image();
- newImg.onload = function() {
- img.style.opacity = '0.5';
- setTimeout(() => {
- img.src = newUrl;
+ function setupMainSearch(inputId, resultsId) {
+ const searchInput = document.getElementById(inputId);
+ const searchResults = document.getElementById(resultsId);
+ if (!searchInput || !searchResults) return;
+
+ let currentFocus = -1;
+
+ function debounce(func, wait) {
+ let timeout;
+ return function executedFunction(...args) {
+ const later = () => {
+ clearTimeout(timeout);
+ func(...args);
+ };
+ clearTimeout(timeout);
+ timeout = setTimeout(later, wait);
+ };
+ }
+
+ function highlightMatch(text, query) {
+ if (!query) return text;
+ const regex = new RegExp(`(${query})`, 'gi');
+ return text.replace(regex, '$1');
+ }
+
+ searchInput.addEventListener('input', debounce(function(e) {
+ const query = e.target.value.trim();
+
+ if (query.length === 0) {
+ searchResults.style.display = 'none';
+ searchResults.innerHTML = '';
+ return;
+ }
+
+ const url = `/search/aliases/?q=${encodeURIComponent(query)}`;
+
+ fetch(url)
+ .then(response => response.json())
+ .then(data => {
+ searchResults.innerHTML = '';
+ currentFocus = -1;
+
+ if (Array.isArray(data) && data.length > 0) {
+ data.forEach(item => {
+ if (item && typeof item === 'object' && 'alias' in item && 'url' in item) {
+ const div = document.createElement('div');
+ div.className = 'search-result-item p-3 hover:bg-gray-100 cursor-pointer border-b border-gray-100 last:border-b-0';
+
+ const aliasLink = document.createElement('a');
+ aliasLink.href = item.url;
+ aliasLink.innerHTML = highlightMatch(item.alias, query);
+ aliasLink.className = 'text-blue-600 hover:underline block text-lg';
+
+ div.appendChild(aliasLink);
+ searchResults.appendChild(div);
+ }
+ });
+ searchResults.style.display = 'block';
+ } else {
+ searchResults.innerHTML = '
+
+
+
+
- {% empty %}
- {% trans "No popular links available" %}
- {% endfor %} + +{% trans "No results found" %}
';
+ searchResults.style.display = 'block';
+ }
+ })
+ .catch(error => {
+ console.error('Error:', error);
+ searchResults.style.display = 'none';
+ });
+ }, 300));
+
+ searchInput.addEventListener('keydown', function(e) {
+ let items = searchResults.getElementsByClassName("search-result-item");
+
+ if (e.keyCode == 40) { // Down arrow
+ e.preventDefault();
+ currentFocus++;
+ addActive(items);
+ } else if (e.keyCode == 38) { // Up arrow
+ e.preventDefault();
+ currentFocus--;
+ addActive(items);
+ } else if (e.keyCode == 13) { // Enter
+ e.preventDefault();
+ if (currentFocus > -1 && items[currentFocus]) {
+ items[currentFocus].querySelector('a').click();
+ } else if (items.length > 0) {
+ // Go to first result if no selection
+ items[0].querySelector('a').click();
+ }
+ } else if (e.keyCode == 27) { // Escape
+ searchResults.style.display = 'none';
+ searchResults.innerHTML = '';
+ searchInput.value = '';
+ }
+ });
+
+ function addActive(items) {
+ if (!items || items.length === 0) return false;
+ removeActive(items);
+ if (currentFocus >= items.length) currentFocus = 0;
+ if (currentFocus < 0) currentFocus = (items.length - 1);
+ items[currentFocus].classList.add("bg-blue-50");
+ }
+
+ function removeActive(items) {
+ for (let i = 0; i < items.length; i++) {
+ items[i].classList.remove("bg-blue-50");
+ }
+ }
+
+ // Close dropdown when clicking outside
+ document.addEventListener('click', function(e) {
+ if (e.target !== searchInput && !searchResults.contains(e.target)) {
+ searchResults.style.display = 'none';
+ }
+ });
+ }
+
+ // Random image refresh functionality
+ window.refreshRandomImage = function(img) {
+ const box = img.getAttribute('data-box');
+ const timestamp = new Date().getTime();
+ const width = img.offsetWidth || 500;
+ const height = img.offsetHeight || 500;
+ const newUrl = `/api/images/random/${width}/${height}/?fit=crop&v=${timestamp}&box=${box}`;
+
+ const newImg = new Image();
+ newImg.onload = function() {
+ img.style.opacity = '0.5';
+ setTimeout(() => {
+ img.src = newUrl;
+ img.style.opacity = '1';
+ }, 150);
+ };
+ newImg.onerror = function() {
+ console.error('Failed to load new random image');
+ const currentUrl = new URL(img.src);
+ currentUrl.searchParams.set('v', timestamp);
+ img.src = currentUrl.toString();
img.style.opacity = '1';
- }, 150);
+ };
+ newImg.src = newUrl;
};
- newImg.onerror = function() {
- console.error('Failed to load new random image');
- // Fallback - just update timestamp on current URL
- const currentUrl = new URL(img.src);
- currentUrl.searchParams.set('v', timestamp);
- img.src = currentUrl.toString();
- img.style.opacity = '1';
- };
- newImg.src = newUrl;
- }
+ });
// Select all functionality
document.getElementById('select-all').addEventListener('change', function() {
diff --git a/links/views.py b/links/views.py
index 542574c..746fd0e 100644
--- a/links/views.py
+++ b/links/views.py
@@ -82,13 +82,6 @@ class LinkListView(ListView):
'#1abc9c', '#d35400', '#34495e', '#16a085', '#27ae60'
]
- # Add top 3 popular links to the context with random colors
- popular_links = Link.objects.order_by('-click_count')[:3]
- context['popular_links'] = [
- {'link': link, 'color': random.choice(colors)}
- for link in popular_links
- ]
-
# Add latest 3 posts to the context (most recent first)
context['latest_posts'] = Post.objects.all().order_by('-created_at')[:3]