summaryrefslogtreecommitdiffstats
path: root/assets/js/search.js
diff options
context:
space:
mode:
Diffstat (limited to 'assets/js/search.js')
-rw-r--r--assets/js/search.js134
1 files changed, 134 insertions, 0 deletions
diff --git a/assets/js/search.js b/assets/js/search.js
new file mode 100644
index 0000000..8fb6262
--- /dev/null
+++ b/assets/js/search.js
@@ -0,0 +1,134 @@
+// Lazy-load search index from JSON file (language-aware)
+async function loadSearchIndex() {
+ if (window.searchIndex) {
+ return window.searchIndex;
+ }
+ try {
+ // Detect current language from URL
+ const isItalian = window.location.pathname.startsWith('/it/');
+ const indexPath = isItalian ? '/it/search-index.json' : '/search-index.json';
+
+ const response = await fetch(indexPath);
+ if (!response.ok) throw new Error('Failed to load search index');
+ window.searchIndex = await response.json();
+ return window.searchIndex;
+ } catch (error) {
+ console.error('Error loading search index:', error);
+ return [];
+ }
+}
+
+// Filter articles by query (case-insensitive, max 5 results)
+function filterArticles(query, articles) {
+ if (!query.trim()) {
+ return [];
+ }
+ const lowerQuery = query.toLowerCase();
+ return articles
+ .filter(article =>
+ article.title.toLowerCase().includes(lowerQuery) ||
+ article.summary.toLowerCase().includes(lowerQuery)
+ )
+ .slice(0, 5);
+}
+
+// Register Alpine.js components
+document.addEventListener('alpine:init', () => {
+ // Desktop search modal component
+ Alpine.data('searchOverlay', () => ({
+ isOpen: false,
+ searchQuery: '',
+ filteredArticles: [],
+ allArticles: [],
+ indexLoaded: false,
+
+ async open() {
+ this.isOpen = true;
+ await this.ensureIndexLoaded();
+ this.$nextTick(() => {
+ const input = this.$el.querySelector('#search-input-desktop');
+ if (input) input.focus();
+ });
+ },
+
+ close() {
+ this.isOpen = false;
+ this.searchQuery = '';
+ this.filteredArticles = [];
+ },
+
+ async ensureIndexLoaded() {
+ if (!this.indexLoaded) {
+ this.allArticles = await loadSearchIndex();
+ this.indexLoaded = true;
+ }
+ },
+
+ filterArticles(query) {
+ this.searchQuery = query;
+ this.filteredArticles = filterArticles(query, this.allArticles);
+ },
+
+ handleEscape(event) {
+ if (event.key === 'Escape') {
+ this.close();
+ }
+ }
+ }));
+
+ // Mobile search component (integrated into hamburger menu)
+ Alpine.data('mobileSearch', () => ({
+ searchQuery: '',
+ filteredArticles: [],
+ allArticles: [],
+ indexLoaded: false,
+
+ async ensureIndexLoaded() {
+ if (!this.indexLoaded) {
+ this.allArticles = await loadSearchIndex();
+ this.indexLoaded = true;
+ }
+ },
+
+ filterArticles(query) {
+ this.searchQuery = query;
+ this.filteredArticles = filterArticles(query, this.allArticles);
+ }
+ }));
+
+ // Refactored 404 page component
+ Alpine.data('notFoundPage', () => ({
+ showEasterEgg: false,
+ searchQuery: '',
+ filteredArticles: [],
+ allArticles: [],
+ indexLoaded: false,
+
+ async init() {
+ await this.ensureIndexLoaded();
+ },
+
+ async ensureIndexLoaded() {
+ if (!this.indexLoaded) {
+ this.allArticles = await loadSearchIndex();
+ this.indexLoaded = true;
+ }
+ },
+
+ filterArticles(query) {
+ this.searchQuery = query;
+ this.filteredArticles = filterArticles(query, this.allArticles);
+ },
+
+ toggleEasterEgg() {
+ this.showEasterEgg = !this.showEasterEgg;
+ },
+
+ goToRandomArticle() {
+ if (this.allArticles.length > 0) {
+ const randomArticle = this.allArticles[Math.floor(Math.random() * this.allArticles.length)];
+ window.location.href = randomArticle.url;
+ }
+ }
+ }));
+});