Skip to content

Commit 3e72132

Browse files
authored
Merge pull request #19 from thavelick/alternating-row-colors
Add alternating row colors to settings dialog
2 parents 93daeca + 6b8f6ec commit 3e72132

File tree

4 files changed

+167
-52
lines changed

4 files changed

+167
-52
lines changed

public_html/search.js

Lines changed: 99 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,90 @@
11
const DEFAULT_BANG = "d";
22

33
const bangs = {
4-
al: "https://kiwix.tristanhavelick.com/search?content=archlinux_en_all_nopic_2022-05&pattern={{{s}}}",
5-
cl: "https://denver.craigslist.org/search/?query={{{s}}}",
6-
d: "https://lite.duckduckgo.com/lite?q={{{s}}}&kl=us-en",
7-
e: "https://www.ebay.com/sch/i.html?_nkw={{{s}}}&rt=nc&LH_ItemCondition=4",
8-
jw: "https://www.justwatch.com/us/search?q={{{s}}}",
9-
k: "https://kiwix.tristanhavelick.com/search?pattern={{{s}}}",
10-
m: "https://search.marginalia.nu/search?query={{{s}}}",
11-
py: "https://kiwix.tristanhavelick.com/search?content=python-3.10.2&pattern={{{s}}}",
12-
sg: "https://app.thestorygraph.com/browse?search_term={{{s}}}",
13-
ytt: "https://youtranscript.tristanhavelick.com/search?search_term={{{s}}}",
14-
x: "https://searxng.tristanhavelick.com/search?q={{{s}}}",
15-
gh: "https://github.com/search?q={{{s}}}",
16-
ghr: "https://github.com/{{{s}}}",
17-
wb: "https://web.archive.org/web/{{{s}}}",
18-
g: "https://www.google.com/search?q={{{s}}}",
19-
ddg: "https://duckduckgo.com/?q={{{s}}}",
20-
a: "https://www.amazon.com/s?k={{{s}}}",
21-
pypi: "https://pypi.org/search/?q={{{s}}}",
22-
w: "https://en.wikipedia.org/wiki/Special:Search?search={{{s}}}",
23-
i: "https://duckduckgo.com/?q={{{s}}}&iax=images&ia=images",
24-
yt: "https://www.youtube.com/results?search_query={{{s}}}",
4+
al: {
5+
url: "https://kiwix.tristanhavelick.com/search?content=archlinux_en_all_nopic_2022-05&pattern={{{s}}}",
6+
description: "ArchLinux Wiki",
7+
},
8+
cl: {
9+
url: "https://denver.craigslist.org/search/?query={{{s}}}",
10+
description: "Denver Craigslist",
11+
},
12+
d: {
13+
url: "https://lite.duckduckgo.com/lite?q={{{s}}}&kl=us-en",
14+
description: "DuckDuckGo Lite",
15+
},
16+
e: {
17+
url: "https://www.ebay.com/sch/i.html?_nkw={{{s}}}&rt=nc&LH_ItemCondition=4",
18+
description: "eBay (used items)",
19+
},
20+
jw: {
21+
url: "https://www.justwatch.com/us/search?q={{{s}}}",
22+
description: "JustWatch (streaming search)",
23+
},
24+
k: {
25+
url: "https://kiwix.tristanhavelick.com/search?pattern={{{s}}}",
26+
description: "Kiwix Offline Content",
27+
},
28+
m: {
29+
url: "https://search.marginalia.nu/search?query={{{s}}}",
30+
description: "Marginalia Search",
31+
},
32+
py: {
33+
url: "https://kiwix.tristanhavelick.com/search?content=python-3.10.2&pattern={{{s}}}",
34+
description: "Python Documentation",
35+
},
36+
sg: {
37+
url: "https://app.thestorygraph.com/browse?search_term={{{s}}}",
38+
description: "The StoryGraph (books)",
39+
},
40+
ytt: {
41+
url: "https://youtranscript.tristanhavelick.com/search?search_term={{{s}}}",
42+
description: "YouTube Transcript Search",
43+
},
44+
x: {
45+
url: "https://searxng.tristanhavelick.com/search?q={{{s}}}",
46+
description: "SearXNG",
47+
},
48+
gh: {
49+
url: "https://github.com/search?q={{{s}}}",
50+
description: "GitHub Search",
51+
},
52+
ghr: {
53+
url: "https://github.com/{{{s}}}",
54+
description: "GitHub Repository",
55+
},
56+
wb: {
57+
url: "https://web.archive.org/web/{{{s}}}",
58+
description: "Wayback Machine",
59+
},
60+
g: {
61+
url: "https://www.google.com/search?q={{{s}}}",
62+
description: "Google Search",
63+
},
64+
ddg: {
65+
url: "https://duckduckgo.com/?q={{{s}}}",
66+
description: "DuckDuckGo",
67+
},
68+
a: {
69+
url: "https://www.amazon.com/s?k={{{s}}}",
70+
description: "Amazon",
71+
},
72+
pypi: {
73+
url: "https://pypi.org/search/?q={{{s}}}",
74+
description: "Python Package Index",
75+
},
76+
w: {
77+
url: "https://en.wikipedia.org/wiki/Special:Search?search={{{s}}}",
78+
description: "Wikipedia",
79+
},
80+
i: {
81+
url: "https://duckduckgo.com/?q={{{s}}}&iax=images&ia=images",
82+
description: "DuckDuckGo Images",
83+
},
84+
yt: {
85+
url: "https://www.youtube.com/results?search_query={{{s}}}",
86+
description: "YouTube",
87+
},
2588
};
2689

2790
function buildSearchUrl(urlTemplate, searchTerm) {
@@ -39,7 +102,7 @@ function getDefaultBang(windowObj = window) {
39102

40103
function buildFallbackUrl(searchTerm, windowObj = window) {
41104
const defaultBang = getDefaultBang(windowObj);
42-
const bangUrl = bangs[defaultBang];
105+
const bangUrl = bangs[defaultBang].url;
43106
return buildSearchUrl(bangUrl, searchTerm);
44107
}
45108

@@ -59,19 +122,19 @@ function processBang(query, windowObj = window) {
59122
const bangTag = trimmed.substring(1, spaceIndex);
60123
const searchTerm = trimmed.substring(spaceIndex + 1).trim();
61124

62-
const bangUrl = bangs[bangTag];
63-
if (bangUrl) {
64-
return buildSearchUrl(bangUrl, searchTerm);
125+
const bang = bangs[bangTag];
126+
if (bang) {
127+
return buildSearchUrl(bang.url, searchTerm);
65128
}
66129
}
67130
const bangMatch = trimmed.match(/^(.+)\s+(\w+)!$/);
68131
if (bangMatch) {
69132
const searchTerm = bangMatch[1].trim();
70133
const bangTag = bangMatch[2];
71134

72-
const bangUrl = bangs[bangTag];
73-
if (bangUrl) {
74-
return buildSearchUrl(bangUrl, searchTerm);
135+
const bang = bangs[bangTag];
136+
if (bang) {
137+
return buildSearchUrl(bang.url, searchTerm);
75138
}
76139
}
77140
return buildFallbackUrl(trimmed, windowObj);
@@ -300,9 +363,9 @@ class SettingsDialog extends SettingsDialogBase {
300363
<div class="bang-list">
301364
`;
302365

303-
for (const [bangKey, bangUrl] of sortedBangs) {
366+
for (const [bangKey, bangData] of sortedBangs) {
304367
const isSelected = bangKey === currentDefault;
305-
html += `<setting-option bang-key="${bangKey}" bang-url="${bangUrl}"${isSelected ? " selected" : ""}></setting-option>`;
368+
html += `<setting-option bang-key="${bangKey}" bang-url="${bangData.url}" bang-description="${bangData.description}"${isSelected ? " selected" : ""}></setting-option>`;
306369
}
307370

308371
html += `
@@ -358,12 +421,15 @@ class SettingOption extends SettingOptionBase {
358421
render() {
359422
const bangKey = this.getAttribute("bang-key");
360423
const bangUrl = this.getAttribute("bang-url");
424+
const bangDescription = this.getAttribute("bang-description");
361425
const isSelected = this.hasAttribute("selected");
362426

363427
this.innerHTML = `
364-
<div class="bang-trigger">${bangKey}!</div>
365-
<div class="bang-url">${bangUrl}</div>
366-
<input type="radio" name="default-bang" value="${bangKey}" class="bang-radio"${isSelected ? " checked" : ""}>
428+
<div class="setting-row">
429+
<div class="bang-trigger">${bangKey}!</div>
430+
<div class="bang-description" title="${bangUrl}">${bangDescription}</div>
431+
<input type="radio" name="default-bang" value="${bangKey}" class="bang-radio"${isSelected ? " checked" : ""}>
432+
</div>
367433
`;
368434
}
369435

public_html/service-worker-lib.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
const STATIC_CACHE_NAME = "just-bangs-static-v10";
1+
const STATIC_CACHE_NAME = "just-bangs-static-v11";
22

33
const STATIC_ASSETS = [
44
"./",

public_html/style.css

Lines changed: 56 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -79,28 +79,28 @@ input[type="button"] {
7979
/* Force dark mode with class */
8080
html.dark-mode,
8181
html.dark-mode input[type="text"] {
82-
background-color: #2d4f8e !important;
82+
background-color: #2d4f8e;
8383
}
8484

8585
html.dark-mode,
8686
html.dark-mode h1,
8787
html.dark-mode input[type="text"] {
88-
color: white !important;
88+
color: white;
8989
}
9090

9191
/* Force light mode with class */
9292
html.light-mode {
93-
background: white !important;
94-
color: black !important;
93+
background: white;
94+
color: black;
9595
}
9696

9797
html.light-mode h1 {
98-
color: #2d4f8e !important;
98+
color: #2d4f8e;
9999
}
100100

101101
html.light-mode input[type="text"] {
102-
background-color: white !important;
103-
color: black !important;
102+
background-color: white;
103+
color: black;
104104
}
105105

106106
/* Dark mode toggle button */
@@ -211,7 +211,7 @@ html.dark-mode .hamburger-menu:hover {
211211
max-width: 600px;
212212
height: 100%;
213213
max-height: calc(100vh - 40px);
214-
overflow: hidden;
214+
overflow: scroll;
215215
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2);
216216
display: flex;
217217
flex-direction: column;
@@ -278,20 +278,29 @@ html.dark-mode .close-button:hover {
278278
}
279279

280280
.save-message {
281-
color: #64bb45;
281+
color: #2d5016;
282282
font-size: 14px;
283283
margin: 0;
284-
display: none;
284+
position: absolute;
285+
top: 16px;
286+
right: 16px;
287+
padding: 8px 12px;
288+
background-color: #d4edda;
289+
border: 1px solid #c3e6cb;
290+
border-radius: 6px;
291+
opacity: 0;
285292
transition: opacity 0.3s ease;
293+
pointer-events: none;
286294
}
287295

288296
.save-message.visible {
289-
display: block;
290297
opacity: 1;
291298
}
292299

293300
html.dark-mode .save-message {
294-
color: #7fd95f;
301+
color: #a3d977;
302+
background-color: #2d4f1a;
303+
border-color: #4a6b3a;
295304
}
296305

297306
/* Settings body */
@@ -303,16 +312,33 @@ html.dark-mode .save-message {
303312

304313
/* Bang list grid */
305314
.bang-list {
306-
display: grid;
307-
grid-template-columns: auto 1fr auto;
308-
gap: 12px 16px;
309-
align-items: center;
315+
display: flex;
316+
flex-direction: column;
317+
gap: 4px;
310318
margin: 16px 0;
311319
}
312320

313321
setting-option,
314322
save-message {
315-
display: contents;
323+
display: block;
324+
}
325+
326+
.setting-row {
327+
display: grid;
328+
grid-template-columns: auto 1fr auto;
329+
gap: 12px 16px;
330+
align-items: start;
331+
padding: 8px;
332+
border-radius: 4px;
333+
}
334+
335+
/* Alternating row backgrounds */
336+
setting-option:nth-child(even) .setting-row {
337+
background-color: #f0f0f0;
338+
}
339+
340+
html.dark-mode setting-option:nth-child(even) .setting-row {
341+
background-color: #3a5f9e;
316342
}
317343

318344
.bang-trigger {
@@ -329,12 +355,25 @@ html.dark-mode .bang-trigger {
329355
font-size: 14px;
330356
color: #666;
331357
word-break: break-all;
358+
line-height: 1.3;
359+
overflow-wrap: break-word;
360+
hyphens: auto;
361+
}
362+
363+
.bang-description {
364+
font-size: 14px;
365+
color: #555;
366+
cursor: help;
332367
}
333368

334369
html.dark-mode .bang-url {
335370
color: #ccc;
336371
}
337372

373+
html.dark-mode .bang-description {
374+
color: #ddd;
375+
}
376+
338377
.bang-radio {
339378
margin: 0;
340379
}

tests/integration/settings-modal.spec.js

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,21 @@ test.describe("Settings Modal", () => {
1919
await expect(settingsPanel).toHaveAttribute("aria-hidden", "true");
2020
});
2121

22-
test("should save default search engine selection", async ({ page }) => {
22+
test("should save default search engine selection and show URL tooltip on hover", async ({
23+
page,
24+
}) => {
2325
const hamburgerButton = page.locator(".hamburger-menu");
2426

2527
await hamburgerButton.click();
2628

29+
// Test hover tooltip functionality
30+
const githubDescription = page
31+
.locator(".bang-description")
32+
.filter({ hasText: "GitHub Search" });
33+
await githubDescription.hover();
34+
const titleAttribute = await githubDescription.getAttribute("title");
35+
expect(titleAttribute).toContain("https://github.com/search?q={{{s}}}");
36+
2737
const githubRadio = page.locator('input[name="default-bang"][value="gh"]');
2838
await githubRadio.click();
2939

0 commit comments

Comments
 (0)