Skip to content

Commit 15d6098

Browse files
authored
Create search.js
Live search bar for Blogger
1 parent 88b5309 commit 15d6098

1 file changed

Lines changed: 94 additions & 0 deletions

File tree

dist/js/search.js

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
const dataJSON = "/feeds/posts/summary?alt=json",
2+
iconJSON = "https://cdn.jsdelivr.net/npm/meteor-icons@3/variants/icons.json",
3+
dataConfig = {
4+
cache: !0
5+
},
6+
input = document.getElementById("search-input"),
7+
results = document.getElementById("search-results"),
8+
indexConfig = Object.assign(dataConfig, {
9+
doc: {
10+
id: "id",
11+
field: ["title", "summary"],
12+
store: ["title", "url", "summary", "icon", "labels"]
13+
}
14+
}),
15+
stringToHTML = e => (new DOMParser).parseFromString(e, "text/html").body.firstChild;
16+
let iconData = {},
17+
docsIndex, displayedArticles = new Set;
18+
19+
function parseFeed(e) {
20+
return e.feed.entry.map(e => ({
21+
id: e.id.$t,
22+
title: e.title.$t,
23+
summary: e.summary ? e.summary.$t : "",
24+
url: e.link.find(e => "alternate" === e.rel).href,
25+
labels: e.category ? e.category.map(e => e.term) : [],
26+
icon: e.category && e.category.length > 0 ? e.category[0].term : "default-icon"
27+
}))
28+
}
29+
30+
function getIcon(e) {
31+
let t = {
32+
android: "android",
33+
blogger: "blogger",
34+
css: "brackets-curly",
35+
javascript: "brackets",
36+
widgets: "grid-plus",
37+
default: "folder-search"
38+
};
39+
return t[e.toLowerCase()] || t.default
40+
}
41+
42+
function init() {
43+
input.removeEventListener("focus", init), input.required = !0, fetch("/feeds/posts/summary?alt=json").then(e => e.json()).then(e => {
44+
let t = parseFeed(e);
45+
(docsIndex = FlexSearch.create("balance", indexConfig)).add(t)
46+
}).then(() => input.required = !1)
47+
}
48+
49+
function truncate(e, t) {
50+
return e.length > t ? e.slice(0, t) + "..." : e
51+
}
52+
53+
function search() {
54+
if (!docsIndex) return;
55+
results.innerHTML = "";
56+
let e = input.value.trim().toLowerCase();
57+
if (!e) return;
58+
let t = docsIndex.search(e, 10),
59+
s = new Set;
60+
t.forEach(e => {
61+
e.labels.forEach(e => {
62+
s.add(e)
63+
})
64+
}), s.forEach(e => {
65+
let s = t.filter(t => t.labels.includes(e)),
66+
r = getIcon(e),
67+
n = `<div class="search-group">
68+
<div class="search-group-title capitalize fs-6 fw-500 has-icon">
69+
<svg class="i i-${r} flex-none" viewBox="0 0 24 24">${iconData[r]}</svg>
70+
<h3 class="">${e}</h3>
71+
</div>
72+
<ul class="search-group-list"></ul>
73+
</div>`,
74+
i = stringToHTML(n),
75+
a = i.querySelector(".search-group-list");
76+
s.forEach(e => {
77+
let t = truncate(e.summary, 100),
78+
s = `<li class="search-item">
79+
<a class="search-link" href="${e.url}">
80+
<div class="search-title fs-6 fw-500">${e.title}</div>
81+
${t?`<p class="search-summary">${t}</p>`:""}
82+
</a>
83+
</li>`;
84+
a.insertAdjacentHTML("beforeend", s), displayedArticles.add(e.id)
85+
}), results.appendChild(i)
86+
})
87+
}
88+
89+
function initSearch(e, t) {
90+
e && t && (e.addEventListener("focus", init), e.addEventListener("keyup", search))
91+
}
92+
fetch("https://cdn.jsdelivr.net/npm/meteor-icons@3/variants/icons.json").then(e => e.json()).then(e => {
93+
iconData = e, initSearch(input, results)
94+
});

0 commit comments

Comments
 (0)