Skip to content

Commit ab0f6dd

Browse files
authored
Merge pull request #29 from zihanKuang/move-ui
Migrate layout and styling from Layer5 docs
2 parents d7432d8 + 972ef86 commit ab0f6dd

29 files changed

+2860
-141
lines changed

assets/js/offline-search.js

Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
// Adapted from code by Matt Walters https://www.mattwalters.net/posts/2018-03-28-hugo-and-lunr/
2+
3+
(function ($) {
4+
'use strict';
5+
6+
$(document).ready(function () {
7+
const $searchInput = $('.td-search input');
8+
const $searchResults = $('.td-offline-search-results');
9+
//
10+
// Register handler
11+
//
12+
13+
$searchInput.on('change', (event) => {
14+
render($(event.target));
15+
16+
// Hide keyboard on mobile browser
17+
// $searchInput.blur();
18+
});
19+
20+
// Prevent reloading page by enter key on sidebar search.
21+
$searchInput.closest('form').on('submit', () => {
22+
return false;
23+
});
24+
25+
//
26+
// Lunr
27+
//
28+
29+
let idx = null; // Lunr index
30+
const resultDetails = new Map(); // Will hold the data for the search results (titles and summaries)
31+
32+
// Set up for an Ajax call to request the JSON data file that is created by Hugo's build process
33+
$.ajax($searchInput.data('offline-search-index-json-src')).then((data) => {
34+
idx = lunr(function () {
35+
this.ref('ref');
36+
37+
// If you added more searchable fields to the search index, list them here.
38+
// Here you can specify searchable fields to the search index - e.g. individual toxonomies for you project
39+
// With "boost" you can add weighting for specific (default weighting without boost: 1)
40+
this.field('title', { boost: 5 });
41+
this.field('categories', { boost: 3 });
42+
this.field('tags', { boost: 3 });
43+
// this.field('projects', { boost: 3 }); // example for an individual toxonomy called projects
44+
this.field('description', { boost: 2 });
45+
this.field('body');
46+
47+
data.forEach((doc) => {
48+
this.add(doc);
49+
50+
resultDetails.set(doc.ref, {
51+
title: doc.title,
52+
excerpt: doc.excerpt,
53+
});
54+
});
55+
});
56+
57+
$searchInput.trigger('change');
58+
});
59+
60+
const render = ($targetSearchInput) => {
61+
//
62+
// Dispose existing popover
63+
//
64+
65+
bootstrap.Popover.getInstance($targetSearchInput[0])?.dispose();
66+
67+
//
68+
// Search
69+
//
70+
const searchQuery = $targetSearchInput.val();
71+
if (idx === null || searchQuery === "") {
72+
return;
73+
}
74+
75+
const results = idx
76+
.query((q) => {
77+
const tokens = lunr.tokenizer(searchQuery.toLowerCase());
78+
tokens.forEach((token) => {
79+
const queryString = token.toString();
80+
q.term(queryString, {
81+
boost: 100,
82+
});
83+
q.term(queryString, {
84+
wildcard:
85+
lunr.Query.wildcard.LEADING | lunr.Query.wildcard.TRAILING,
86+
boost: 10,
87+
});
88+
q.term(queryString, {
89+
editDistance: 2,
90+
});
91+
});
92+
})
93+
.slice(0, $targetSearchInput.data('offline-search-max-results'));
94+
95+
//
96+
// Make result html
97+
//
98+
99+
const $html = $('<div>');
100+
101+
$html.append(
102+
$('<div>')
103+
.css({
104+
display: 'flex',
105+
justifyContent: 'space-between',
106+
marginBottom: '1em',
107+
})
108+
.append(
109+
$('<span>').text('Search results').css({ fontWeight: 'bold' })
110+
)
111+
.append(
112+
$('<span>').addClass('td-offline-search-results__close-button')
113+
)
114+
);
115+
116+
const $searchResultBody = $('<div>').css({
117+
maxHeight: `calc(100vh - ${
118+
$targetSearchInput.offset().top - $(window).scrollTop() + 180
119+
}px)`,
120+
overflowY: 'auto',
121+
});
122+
$html.append($searchResultBody);
123+
124+
if (results.length === 0) {
125+
$searchResultBody.append(
126+
$('<p>').text(`No results found for query "${searchQuery}"`)
127+
);
128+
} else {
129+
results.forEach((r) => {
130+
const doc = resultDetails.get(r.ref);
131+
const href =
132+
$searchInput.data('offline-search-base-href') +
133+
r.ref.replace(/^\//, '');
134+
135+
const $entry = $('<div>').addClass('mt-4');
136+
137+
$entry.append(
138+
$('<small>').addClass('d-block text-muted').text(r.ref)
139+
);
140+
141+
$entry.append(
142+
$('<a>')
143+
.addClass('d-block')
144+
.css({
145+
fontSize: '1.2rem',
146+
})
147+
.attr('href', href)
148+
.text(doc.title)
149+
);
150+
151+
$entry.append($('<p>').text(doc.excerpt));
152+
153+
$searchResultBody.append($entry);
154+
});
155+
}
156+
157+
$targetSearchInput.one('shown.bs.popover', () => {
158+
$('.td-offline-search-results__close-button').on('click', () => {
159+
$targetSearchInput.val('');
160+
$targetSearchInput.trigger('change');
161+
});
162+
});
163+
164+
const popover = new bootstrap.Popover($targetSearchInput, {
165+
content: $html[0],
166+
html: true,
167+
customClass: 'td-offline-search-results',
168+
placement: 'bottom',
169+
});
170+
popover.show();
171+
};
172+
173+
//Bring focus to search bar
174+
$(document).on('keydown', function (event) {
175+
if (event.key === '/' && !(document.activeElement instanceof HTMLInputElement)) {
176+
event.preventDefault();
177+
$searchInput.focus();
178+
}
179+
});
180+
181+
$(document).on('click', function (event) {
182+
if (!$(event.target).closest('.td-search').length) {
183+
// Clicked outside the search panel
184+
$searchInput.val('');
185+
$searchInput.trigger('change');
186+
}
187+
});
188+
189+
//close the search panel when the ESC key is pressed
190+
$(document).on('keydown', function (event) {
191+
if (event.key === 'Escape') {
192+
$searchInput.val('');
193+
$searchInput.trigger('change');
194+
}
195+
});
196+
197+
198+
});
199+
})(jQuery);

assets/scss/_breadcrumb.scss

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Breadcrumb
2+
3+
.td-breadcrumbs {
4+
@media print {
5+
display: none !important;
6+
}
7+
8+
.breadcrumb {
9+
background: inherit;
10+
padding-left: 0;
11+
padding-top: 0;
12+
margin-bottom: 0;
13+
}
14+
}

0 commit comments

Comments
 (0)