Add global search to site header with Cmd+K shortcut
Search input in the site header that submits to /discover?q=term.
Cmd+K (or Ctrl+K) focuses the search input from anywhere on the site.
- Search form between logo and nav links
- Compact mono-font input styled to match header
- Mobile: appears below header when hamburger menu is open
- Keyboard shortcuts help updated to show Cmd+K
- Uses existing discover search backend (pg_trgm trigram matching)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
4 files changed,
+54 insertions,
-1 deletion
| 22 |
22 |
|
- [ ] Monitor scheduler.rs (1249), git/mod.rs (624), license_keys.rs (684) for growth
|
| 23 |
23 |
|
|
| 24 |
24 |
|
### UX — Remaining
|
| 25 |
|
- |
- [ ] **[HIGH]** Add global search to site header — search only exists on /discover page. Add input to `site_header.html` with Cmd+K shortcut
|
|
25 |
+ |
- [x] **[HIGH]** Add global search to site header — search input in header nav, Cmd+K shortcut to focus, form GET to /discover, responsive mobile layout
|
| 26 |
26 |
|
|
| 27 |
27 |
|
### UX — Deferred (post-beta table stakes)
|
| 28 |
28 |
|
- [ ] Reviews/ratings system for items
|
| 155 |
155 |
|
var form = document.activeElement?.closest('form');
|
| 156 |
156 |
|
if (form) { var btn = form.querySelector('button[type="submit"]'); if (btn) btn.click(); }
|
| 157 |
157 |
|
}
|
|
158 |
+ |
// Cmd+K / Ctrl+K — focus search (works even in inputs)
|
|
159 |
+ |
if ((e.metaKey || e.ctrlKey) && (e.key === 'k' || e.key === 'K')) {
|
|
160 |
+ |
e.preventDefault();
|
|
161 |
+ |
var searchInput = document.getElementById('header-search-input');
|
|
162 |
+ |
if (searchInput) { searchInput.focus(); searchInput.select(); }
|
|
163 |
+ |
}
|
| 158 |
164 |
|
// ? — show keyboard shortcuts help (not in inputs)
|
| 159 |
165 |
|
if (e.key === '?' && !inInput && !e.metaKey && !e.ctrlKey) {
|
| 160 |
166 |
|
e.preventDefault();
|
| 179 |
185 |
|
+ '<button type="button" class="modal-close" onclick="document.getElementById(\'shortcuts-help\').remove()">×</button>'
|
| 180 |
186 |
|
+ '</div>'
|
| 181 |
187 |
|
+ '<table style="width: 100%; font-size: 0.9rem;">'
|
|
188 |
+ |
+ '<tr><td style="padding: 0.3rem 0;"><kbd>Cmd+K</kbd></td><td>Search</td></tr>'
|
| 182 |
189 |
|
+ '<tr><td style="padding: 0.3rem 0;"><kbd>?</kbd></td><td>Show this help</td></tr>'
|
| 183 |
190 |
|
+ '<tr><td style="padding: 0.3rem 0;"><kbd>Esc</kbd></td><td>Close modal / overlay</td></tr>'
|
| 184 |
191 |
|
+ '<tr><td style="padding: 0.3rem 0;"><kbd>Cmd+S</kbd></td><td>Save current form</td></tr>'
|
| 1057 |
1057 |
|
display: contents;
|
| 1058 |
1058 |
|
}
|
| 1059 |
1059 |
|
|
|
1060 |
+ |
/* Header search */
|
|
1061 |
+ |
.header-search {
|
|
1062 |
+ |
flex: 0 1 220px;
|
|
1063 |
+ |
margin: 0 1rem;
|
|
1064 |
+ |
}
|
|
1065 |
+ |
|
|
1066 |
+ |
.header-search input {
|
|
1067 |
+ |
width: 100%;
|
|
1068 |
+ |
padding: 0.35rem 0.6rem;
|
|
1069 |
+ |
font-size: 0.85rem;
|
|
1070 |
+ |
font-family: var(--font-mono);
|
|
1071 |
+ |
border: 1px solid var(--border);
|
|
1072 |
+ |
background: var(--background);
|
|
1073 |
+ |
color: var(--detail);
|
|
1074 |
+ |
border-radius: 3px;
|
|
1075 |
+ |
}
|
|
1076 |
+ |
|
|
1077 |
+ |
.header-search input:focus {
|
|
1078 |
+ |
outline: 2px solid var(--accent);
|
|
1079 |
+ |
outline-offset: -1px;
|
|
1080 |
+ |
}
|
|
1081 |
+ |
|
| 1060 |
1082 |
|
/* Hamburger toggle — hidden by default, shown at 768px */
|
| 1061 |
1083 |
|
.nav-toggle-checkbox {
|
| 1062 |
1084 |
|
display: none;
|
| 3619 |
3641 |
|
display: block;
|
| 3620 |
3642 |
|
}
|
| 3621 |
3643 |
|
|
|
3644 |
+ |
.header-search {
|
|
3645 |
+ |
display: none;
|
|
3646 |
+ |
flex: none;
|
|
3647 |
+ |
margin: 0;
|
|
3648 |
+ |
width: 100%;
|
|
3649 |
+ |
}
|
|
3650 |
+ |
|
|
3651 |
+ |
.nav-toggle-checkbox:checked ~ .header-search {
|
|
3652 |
+ |
display: block;
|
|
3653 |
+ |
position: absolute;
|
|
3654 |
+ |
top: 100%;
|
|
3655 |
+ |
left: 0;
|
|
3656 |
+ |
right: 0;
|
|
3657 |
+ |
padding: 0.75rem 1.5rem;
|
|
3658 |
+ |
background: var(--background);
|
|
3659 |
+ |
border-bottom: 1px solid var(--border);
|
|
3660 |
+ |
z-index: 11;
|
|
3661 |
+ |
}
|
|
3662 |
+ |
|
| 3622 |
3663 |
|
.site-header nav {
|
| 3623 |
3664 |
|
display: none;
|
| 3624 |
3665 |
|
position: absolute;
|
| 6 |
6 |
|
<span></span>
|
| 7 |
7 |
|
<span></span>
|
| 8 |
8 |
|
</label>
|
|
9 |
+ |
<form action="/discover" method="get" class="header-search" role="search">
|
|
10 |
+ |
<input type="search" name="q" id="header-search-input"
|
|
11 |
+ |
placeholder="Search... (Cmd+K)" autocomplete="off"
|
|
12 |
+ |
aria-label="Search items and projects">
|
|
13 |
+ |
</form>
|
| 9 |
14 |
|
<nav aria-label="Main navigation">
|
| 10 |
15 |
|
<div class="nav-links">
|
| 11 |
16 |
|
<a href="/">Library</a>
|