Skip to content

Commit 7e14738

Browse files
committed
Fix search bar on all pages: about, libraries, index — use absolute URLs
1 parent 4ced16c commit 7e14738

5 files changed

Lines changed: 63 additions & 135 deletions

File tree

about/index.html

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,7 @@
4040
</style>
4141
</head>
4242
<body>
43-
<nav>
44-
<a href="../" class="nav-logo">
45-
<img src="../assets/cpp-logo.png" alt="C++ Mode">
46-
<span>C++ Mode</span>
47-
</a>
48-
<button class="hamburger" onclick="document.querySelector('.sidebar-outer').classList.toggle('open')"></button>
49-
</nav>
43+
<nav id="site-nav"></nav>
5044
<div class="layout">
5145
<div class="sidebar-outer">
5246
<div id="site-sidebar">
@@ -81,5 +75,6 @@ <h2>Who is it for</h2>
8175
</div>
8276
</div>
8377
<footer><p>C++ Mode for Processing</p></footer>
78+
<script src="../assets/nav.js"></script>
8479
</body>
8580
</html>

assets/nav.js

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
(function() {
2+
const SITE = 'https://processing-cpp.github.io';
23
const path = window.location.pathname;
3-
const isRoot = path === '/' || path.endsWith('/index.html') && path.split('/').length <= 2;
44
const parts = path.replace(/\/$/, '').split('/').filter(Boolean);
5-
const prefix = (isRoot || parts.length === 0) ? '/' : '../';
5+
const isRoot = parts.length === 0 || (parts.length === 1 && parts[0] === 'index.html');
6+
const prefix = isRoot ? '/' : '../';
67

78
function isActive(name) { return path.includes('/' + name); }
8-
99
function link(name, label) {
1010
const active = isActive(name) ? ' class="active"' : '';
1111
return `<a href="${prefix}${name}"${active}>${label}</a>`;
@@ -34,8 +34,10 @@
3434
`;
3535
}
3636

37-
// Load search
38-
const script = document.createElement('script');
39-
script.src = prefix + 'assets/search.js';
40-
document.head.appendChild(script);
37+
// Load search via absolute URL — works from any page depth
38+
if (!document.getElementById('search-wrap')) {
39+
const s = document.createElement('script');
40+
s.src = SITE + '/assets/search.js';
41+
document.head.appendChild(s);
42+
}
4143
})();

assets/search.js

Lines changed: 48 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
(function() {
2-
const BASE = 'https://processing-cpp.github.io';
2+
const SITE = 'https://processing-cpp.github.io';
33

4-
// Inject search bar into nav after nav.js runs
54
function injectSearch() {
65
const nav = document.getElementById('site-nav');
76
if (!nav) return;
7+
if (document.getElementById('search-wrap')) return; // already injected
88

99
const wrap = document.createElement('div');
1010
wrap.id = 'search-wrap';
@@ -19,82 +19,33 @@
1919
const style = document.createElement('style');
2020
style.textContent = `
2121
#search-wrap { position: relative; margin-left: auto; padding-right: 1rem; }
22-
#search-box { position: relative; }
2322
#search-input {
24-
width: 220px;
25-
padding: 6px 12px;
26-
border: 1px solid #e0e0e0;
27-
border-radius: 20px;
28-
font-size: 13px;
29-
font-family: inherit;
30-
background: #f8f8f8;
31-
outline: none;
23+
width: 220px; padding: 6px 12px;
24+
border: 1px solid #e0e0e0; border-radius: 20px;
25+
font-size: 13px; font-family: inherit;
26+
background: #f8f8f8; outline: none;
3227
transition: border-color 0.15s, width 0.2s;
3328
}
34-
#search-input:focus {
35-
border-color: #aaa;
36-
background: #fff;
37-
width: 280px;
38-
}
29+
#search-input:focus { border-color: #aaa; background: #fff; width: 280px; }
3930
#search-results {
40-
position: absolute;
41-
top: calc(100% + 8px);
42-
right: 0;
43-
width: 360px;
44-
background: #fff;
45-
border: 1px solid #e0e0e0;
46-
border-radius: 8px;
31+
position: absolute; top: calc(100% + 8px); right: 0;
32+
width: 360px; background: #fff;
33+
border: 1px solid #e0e0e0; border-radius: 8px;
4734
box-shadow: 0 8px 24px rgba(0,0,0,0.1);
48-
max-height: 400px;
49-
overflow-y: auto;
50-
z-index: 1000;
51-
}
52-
.search-result {
53-
display: block;
54-
padding: 10px 14px;
55-
border-bottom: 1px solid #f0f0f0;
56-
text-decoration: none;
57-
color: #111;
58-
transition: background 0.1s;
59-
}
60-
.search-result:last-child { border-bottom: none; }
61-
.search-result:hover { background: #f8f8f8; }
62-
.search-result-name {
63-
font-family: "SF Mono","Fira Code",monospace;
64-
font-size: 13px;
65-
font-weight: 600;
66-
color: #111;
67-
}
68-
.search-result-name mark {
69-
background: #fff3b0;
70-
color: #111;
71-
border-radius: 2px;
72-
padding: 0 1px;
73-
}
74-
.search-result-cat {
75-
font-size: 11px;
76-
color: #aaa;
77-
margin-top: 1px;
78-
}
79-
.search-result-desc {
80-
font-size: 12px;
81-
color: #666;
82-
margin-top: 3px;
83-
white-space: nowrap;
84-
overflow: hidden;
85-
text-overflow: ellipsis;
86-
}
87-
.search-no-results {
88-
padding: 16px 14px;
89-
font-size: 13px;
90-
color: #aaa;
91-
text-align: center;
35+
max-height: 400px; overflow-y: auto; z-index: 9999;
9236
}
37+
.sr { display: block; padding: 10px 14px; border-bottom: 1px solid #f0f0f0; text-decoration: none; color: #111; }
38+
.sr:last-child { border-bottom: none; }
39+
.sr:hover, .sr:focus { background: #f8f8f8; outline: none; }
40+
.sr-name { font-family: "SF Mono","Fira Code",monospace; font-size: 13px; font-weight: 600; }
41+
.sr-name mark { background: #fff3b0; border-radius: 2px; padding: 0 1px; color: #111; }
42+
.sr-cat { font-size: 11px; color: #aaa; margin-top: 1px; }
43+
.sr-desc { font-size: 12px; color: #666; margin-top: 3px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
44+
.sr-empty { padding: 16px 14px; font-size: 13px; color: #aaa; text-align: center; }
9345
@media (max-width: 768px) {
94-
#search-wrap { padding-right: 0.5rem; }
95-
#search-input { width: 140px; }
96-
#search-input:focus { width: 180px; }
97-
#search-results { width: 280px; right: 0; }
46+
#search-input { width: 130px; }
47+
#search-input:focus { width: 170px; }
48+
#search-results { width: 280px; }
9849
}
9950
`;
10051
document.head.appendChild(style);
@@ -103,59 +54,58 @@
10354
const results = document.getElementById('search-results');
10455
let index = null;
10556

106-
// Load index
107-
fetch(BASE + '/assets/search-index.json')
57+
// Always use absolute URL so it works from any page depth
58+
fetch(SITE + '/assets/search-index.json')
10859
.then(r => r.json())
109-
.then(data => { index = data; });
60+
.then(d => { index = d; });
11061

111-
function highlight(text, query) {
112-
const escaped = query.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
113-
return text.replace(new RegExp(`(${escaped})`, 'gi'), '<mark>$1</mark>');
62+
function esc(s) { return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); }
63+
64+
function highlight(text, q) {
65+
return text.replace(new RegExp(`(${esc(q)})`, 'gi'), '<mark>$1</mark>');
11466
}
11567

116-
function search(q) {
117-
if (!index || q.length < 1) { results.hidden = true; return; }
68+
function doSearch(q) {
69+
if (!index || !q) { results.hidden = true; return; }
11870
const ql = q.toLowerCase();
119-
const matches = index.filter(e =>
71+
const hits = index.filter(e =>
12072
e.name.toLowerCase().includes(ql) ||
12173
e.cat.toLowerCase().includes(ql) ||
12274
e.desc.toLowerCase().includes(ql)
12375
).slice(0, 12);
12476

125-
if (!matches.length) {
126-
results.innerHTML = `<div class="search-no-results">No results for "${q}"</div>`;
127-
results.hidden = false;
128-
return;
77+
if (!hits.length) {
78+
results.innerHTML = `<div class="sr-empty">No results for "${q}"</div>`;
79+
} else {
80+
results.innerHTML = hits.map(e => {
81+
const cat = e.subcat ? `${e.cat} / ${e.subcat}` : e.cat;
82+
return `<a class="sr" href="${SITE}${e.url}">
83+
<div class="sr-name">${highlight(e.name, q)}</div>
84+
<div class="sr-cat">${cat}</div>
85+
<div class="sr-desc">${e.desc}</div>
86+
</a>`;
87+
}).join('');
12988
}
130-
131-
results.innerHTML = matches.map(e => {
132-
const cat = e.subcat ? `${e.cat} / ${e.subcat}` : e.cat;
133-
return `<a class="search-result" href="${BASE}${e.url}">
134-
<div class="search-result-name">${highlight(e.name, q)}</div>
135-
<div class="search-result-cat">${cat}</div>
136-
<div class="search-result-desc">${e.desc}</div>
137-
</a>`;
138-
}).join('');
13989
results.hidden = false;
14090
}
14191

142-
input.addEventListener('input', e => search(e.target.value.trim()));
92+
input.addEventListener('input', e => doSearch(e.target.value.trim()));
14393

14494
input.addEventListener('keydown', e => {
14595
if (e.key === 'Escape') { results.hidden = true; input.blur(); }
14696
if (e.key === 'Enter') {
147-
const first = results.querySelector('.search-result');
97+
const first = results.querySelector('.sr');
14898
if (first) window.location.href = first.href;
14999
}
150100
if (e.key === 'ArrowDown') {
151101
e.preventDefault();
152-
const items = [...results.querySelectorAll('.search-result')];
153-
if (items.length) items[0].focus();
102+
const first = results.querySelector('.sr');
103+
if (first) first.focus();
154104
}
155105
});
156106

157107
results.addEventListener('keydown', e => {
158-
const items = [...results.querySelectorAll('.search-result')];
108+
const items = [...results.querySelectorAll('.sr')];
159109
const idx = items.indexOf(document.activeElement);
160110
if (e.key === 'ArrowDown' && idx < items.length - 1) { e.preventDefault(); items[idx+1].focus(); }
161111
if (e.key === 'ArrowUp') { e.preventDefault(); idx > 0 ? items[idx-1].focus() : input.focus(); }

index.html

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -108,22 +108,7 @@
108108
</head>
109109
<body>
110110

111-
<nav>
112-
<div class="nav-logo">
113-
<img src="assets/cpp-logo.png" alt="C++ Mode">
114-
<span>C++ Mode</span>
115-
</div>
116-
<div style="display:flex;align-items:center;gap:1.5rem;">
117-
<div class="search-wrap">
118-
<svg viewBox="0 0 24 24" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
119-
<circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/>
120-
</svg>
121-
<input type="text" id="search-input" placeholder="Search..." autocomplete="off">
122-
<div class="search-results" id="search-results"></div>
123-
</div>
124-
<button class="hamburger" onclick="document.getElementById('sidebar').classList.toggle('open')"></button>
125-
</div>
126-
</nav>
111+
<nav id="site-nav"></nav>
127112

128113
<div class="layout">
129114
<div class="sidebar" id="sidebar">
@@ -262,5 +247,6 @@ <h2>Examples</h2>
262247
};
263248
});
264249
</script>
250+
<script src="./assets/nav.js"></script>
265251
</body>
266252
</html>

libraries/index.html

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,7 @@
4040
</style>
4141
</head>
4242
<body>
43-
<nav>
44-
<a href="../" class="nav-logo">
45-
<img src="../assets/cpp-logo.png" alt="C++ Mode">
46-
<span>C++ Mode</span>
47-
</a>
48-
<button class="hamburger" onclick="document.querySelector('.sidebar-outer').classList.toggle('open')"></button>
49-
</nav>
43+
<nav id="site-nav"></nav>
5044
<div class="layout">
5145
<div class="sidebar-outer">
5246
<div id="site-sidebar">
@@ -124,5 +118,6 @@ <h2>Math</h2>
124118
</div>
125119
</div>
126120
<footer><p>C++ Mode for Processing</p></footer>
121+
<script src="../assets/nav.js"></script>
127122
</body>
128123
</html>

0 commit comments

Comments
 (0)