|
28 | 28 | placeholder="Search concepts..." |
29 | 29 | class="w-full px-4 py-2 pl-10 pr-20 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary focus:border-transparent" |
30 | 30 | autocomplete="off" |
| 31 | + value="{{ query }}" |
31 | 32 | /> |
32 | 33 | <div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none"> |
33 | 34 | <i class="fas fa-search text-gray-400"></i> |
34 | 35 | </div> |
35 | 36 | <div class="absolute inset-y-0 right-0 pr-3 flex items-center"> |
36 | 37 | <kbd class="hidden md:inline-flex items-center px-2 py-1.5 text-xs font-semibold border rounded shadow-sm" style="color: var(--text-secondary); background-color: var(--nav-bg); border-color: var(--border-color)"> |
37 | | - <span id="shortcut-key">Ctrl</span><span class="mx-0.5">+</span>K |
| 38 | + <span id="shortcut-key">Esc</span> |
38 | 39 | </kbd> |
39 | 40 | </div> |
40 | 41 | <input type="hidden" name="semantic" value="true" /> |
|
95 | 96 | </div> |
96 | 97 | </footer> |
97 | 98 | <script> |
| 99 | + // Theme handling |
| 100 | + const themeToggle = document.getElementById('theme-toggle'); |
| 101 | + const themeIcon = themeToggle.querySelector('i'); |
| 102 | + |
| 103 | + // Check for saved theme preference |
| 104 | + const savedTheme = localStorage.getItem('theme') || 'light'; |
| 105 | + document.documentElement.setAttribute('data-theme', savedTheme); |
| 106 | + updateThemeIcon(savedTheme); |
| 107 | + |
| 108 | + themeToggle.addEventListener('click', () => { |
| 109 | + const currentTheme = document.documentElement.getAttribute('data-theme'); |
| 110 | + const newTheme = currentTheme === 'dark' ? 'light' : 'dark'; |
| 111 | + document.documentElement.setAttribute('data-theme', newTheme); |
| 112 | + localStorage.setItem('theme', newTheme); |
| 113 | + updateThemeIcon(newTheme); |
| 114 | + }); |
| 115 | + |
| 116 | + function updateThemeIcon(theme) { |
| 117 | + themeIcon.className = theme === 'dark' ? 'fas fa-sun' : 'fas fa-moon'; |
| 118 | + } |
| 119 | + |
| 120 | + // Prevent clicks on disabled links |
| 121 | + document.querySelectorAll('a[aria-disabled="true"]').forEach(link => { |
| 122 | + link.addEventListener('click', (e) => { |
| 123 | + e.preventDefault(); |
| 124 | + e.stopPropagation(); |
| 125 | + }); |
| 126 | + }); |
| 127 | + |
| 128 | + // Search functionality |
98 | 129 | document.addEventListener('DOMContentLoaded', function() { |
99 | 130 | document.getElementById('language').addEventListener('change', function(e) { |
100 | 131 | window.location.href = e.target.value; |
101 | 132 | }); |
102 | 133 |
|
103 | | - // Theme handling |
104 | | - const themeToggle = document.getElementById('theme-toggle'); |
105 | | - const themeIcon = themeToggle.querySelector('i'); |
106 | | - |
107 | | - // Check for saved theme preference |
108 | | - const savedTheme = localStorage.getItem('theme') || 'light'; |
109 | | - document.documentElement.setAttribute('data-theme', savedTheme); |
110 | | - updateThemeIcon(savedTheme); |
111 | | - |
112 | | - themeToggle.addEventListener('click', () => { |
113 | | - const currentTheme = document.documentElement.getAttribute('data-theme'); |
114 | | - const newTheme = currentTheme === 'dark' ? 'light' : 'dark'; |
115 | | - document.documentElement.setAttribute('data-theme', newTheme); |
116 | | - localStorage.setItem('theme', newTheme); |
117 | | - updateThemeIcon(newTheme); |
118 | | - }); |
119 | | - |
120 | | - function updateThemeIcon(theme) { |
121 | | - themeIcon.className = theme === 'dark' ? 'fas fa-sun' : 'fas fa-moon'; |
122 | | - } |
| 134 | + const searchInput = document.querySelector('input[name="query"]'); |
| 135 | + const suggestionsDiv = document.getElementById('suggestions'); |
| 136 | + let debounceTimer; |
123 | 137 |
|
124 | | - // Prevent clicks on disabled links |
125 | | - document.querySelectorAll('a[aria-disabled="true"]').forEach(link => { |
126 | | - link.addEventListener('click', (e) => { |
127 | | - e.preventDefault(); |
128 | | - e.stopPropagation(); |
129 | | - }); |
| 138 | + document.addEventListener('keydown', function(e) { |
| 139 | + if (e.key === 'Escape') { |
| 140 | + if (searchInput) { |
| 141 | + searchInput.focus(); |
| 142 | + searchInput.select(); |
| 143 | + } |
| 144 | + } |
130 | 145 | }); |
131 | 146 |
|
132 | | - // Detect OS and update shortcut key |
133 | | - const isMac = navigator.platform.toUpperCase().indexOf('MAC') >= 0; |
134 | | - if (isMac) { |
135 | | - document.getElementById('shortcut-key').textContent = '⌘'; |
136 | | - } else { |
137 | | - document.getElementById('shortcut-key').textContent = 'Ctrl'; |
| 147 | + // Debounce function |
| 148 | + function debounce(func, delay) { |
| 149 | + return function() { |
| 150 | + const context = this; |
| 151 | + const args = arguments; |
| 152 | + clearTimeout(debounceTimer); |
| 153 | + debounceTimer = setTimeout(() => func.apply(context, args), delay); |
| 154 | + }; |
138 | 155 | } |
139 | 156 |
|
140 | | - // Search functionality |
141 | | - document.addEventListener('DOMContentLoaded', function() { |
142 | | - const searchInput = document.querySelector('input[name="query"]'); |
143 | | - const suggestionsDiv = document.getElementById('suggestions'); |
144 | | - let debounceTimer; |
145 | | - |
146 | | - // Handle keyboard shortcut |
147 | | - document.addEventListener('keydown', function(e) { |
148 | | - // Check for Cmd+K (Mac) or Ctrl+K (Windows/Linux) |
149 | | - if ((e.metaKey || e.ctrlKey) && e.key === 'k') { |
150 | | - e.preventDefault(); |
151 | | - searchInput.focus(); |
152 | | - } |
153 | | - }); |
154 | | - |
155 | | - // Debounce function |
156 | | - function debounce(func, delay) { |
157 | | - return function() { |
158 | | - const context = this; |
159 | | - const args = arguments; |
160 | | - clearTimeout(debounceTimer); |
161 | | - debounceTimer = setTimeout(() => func.apply(context, args), delay); |
162 | | - }; |
| 157 | + // Fetch suggestions |
| 158 | + async function fetchSuggestions(query) { |
| 159 | + if (!query) { |
| 160 | + suggestionsDiv.classList.add('hidden'); |
| 161 | + return; |
163 | 162 | } |
164 | 163 |
|
165 | | - // Fetch suggestions |
166 | | - async function fetchSuggestions(query) { |
167 | | - if (!query) { |
168 | | - suggestionsDiv.classList.add('hidden'); |
169 | | - return; |
170 | | - } |
171 | | - |
172 | | - try { |
173 | | - const response = await fetch(`{{ suggest_api_url }}?query=${encodeURIComponent(query)}&language={{ language }}`); |
174 | | - const suggestions = await response.json(); |
175 | | - |
176 | | - if (suggestions.length > 0) { |
177 | | - const limitedSuggestions = suggestions.slice(0, 5); |
178 | | - const hasMore = suggestions.length > 5; |
179 | | - |
180 | | - suggestionsDiv.innerHTML = ` |
181 | | - ${limitedSuggestions.map(suggestion => ` |
182 | | - <div class="p-2 cursor-pointer transition-colors duration-150 hover-row" onclick="selectSuggestion('${suggestion.label}')" style="color: var(--text-color)"> |
183 | | - ${suggestion.label} |
184 | | - </div> |
185 | | - `).join('')} |
186 | | - ${hasMore ? ` |
187 | | - <div class="p-2 text-sm text-center border-t" style="color: var(--text-secondary); border-color: var(--border-color)"> |
188 | | - +${suggestions.length - 5} more results |
189 | | - </div> |
190 | | - ` : ''} |
191 | | - `; |
192 | | - suggestionsDiv.classList.remove('hidden'); |
193 | | - } else { |
194 | | - suggestionsDiv.classList.add('hidden'); |
195 | | - } |
196 | | - } catch (error) { |
197 | | - console.error('Error fetching suggestions:', error); |
| 164 | + try { |
| 165 | + const response = await fetch(`{{ suggest_api_url }}?query=${encodeURIComponent(query)}&language={{ language }}`); |
| 166 | + const suggestions = await response.json(); |
| 167 | + |
| 168 | + if (suggestions.length > 0) { |
| 169 | + const limitedSuggestions = suggestions.slice(0, 5); |
| 170 | + const hasMore = suggestions.length > 5; |
| 171 | + |
| 172 | + suggestionsDiv.innerHTML = ` |
| 173 | + ${limitedSuggestions.map(suggestion => ` |
| 174 | + <div class="p-2 cursor-pointer transition-colors duration-150 hover-row" onclick="selectSuggestion('${suggestion.label}')" style="color: var(--text-color)"> |
| 175 | + ${suggestion.label} |
| 176 | + </div> |
| 177 | + `).join('')} |
| 178 | + ${hasMore ? ` |
| 179 | + <div class="p-2 text-sm text-center border-t" style="color: var(--text-secondary); border-color: var(--border-color)"> |
| 180 | + +${suggestions.length - 5} more results |
| 181 | + </div> |
| 182 | + ` : ''} |
| 183 | + `; |
| 184 | + suggestionsDiv.classList.remove('hidden'); |
| 185 | + } else { |
198 | 186 | suggestionsDiv.classList.add('hidden'); |
199 | 187 | } |
| 188 | + } catch (error) { |
| 189 | + console.error('Error fetching suggestions:', error); |
| 190 | + suggestionsDiv.classList.add('hidden'); |
200 | 191 | } |
| 192 | + } |
201 | 193 |
|
202 | | - // Handle input with debounce |
203 | | - searchInput.addEventListener('input', debounce(function(e) { |
204 | | - fetchSuggestions(e.target.value); |
205 | | - }, 300)); |
206 | | - |
207 | | - // Handle suggestion selection |
208 | | - window.selectSuggestion = function(suggestion) { |
209 | | - searchInput.value = suggestion; |
| 194 | + // Handle input with debounce |
| 195 | + searchInput.addEventListener('input', debounce(function(e) { |
| 196 | + fetchSuggestions(e.target.value); |
| 197 | + }, 300)); |
| 198 | + |
| 199 | + // Handle suggestion selection |
| 200 | + window.selectSuggestion = function(suggestion) { |
| 201 | + searchInput.value = suggestion; |
| 202 | + suggestionsDiv.classList.add('hidden'); |
| 203 | + document.getElementById('searchForm').submit(); |
| 204 | + }; |
| 205 | + |
| 206 | + // Close suggestions when clicking outside |
| 207 | + document.addEventListener('click', function(e) { |
| 208 | + if (!searchInput.contains(e.target) && !suggestionsDiv.contains(e.target)) { |
210 | 209 | suggestionsDiv.classList.add('hidden'); |
211 | | - document.getElementById('searchForm').submit(); |
212 | | - }; |
213 | | - |
214 | | - // Close suggestions when clicking outside |
215 | | - document.addEventListener('click', function(e) { |
216 | | - if (!searchInput.contains(e.target) && !suggestionsDiv.contains(e.target)) { |
217 | | - suggestionsDiv.classList.add('hidden'); |
218 | | - } |
219 | | - }); |
| 210 | + } |
220 | 211 | }); |
221 | 212 | }); |
222 | 213 | </script> |
|
0 commit comments