Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/jeremybise/twentynineteen-hugo.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeremy Bise <jeremy.bise@thosegeeks.com>2019-04-17 17:25:46 +0300
committerJeremy Bise <jeremy.bise@thosegeeks.com>2019-04-17 17:25:46 +0300
commit2095d341178a30956e66799428d229d7e6f363ea (patch)
tree23ac5709aff0b0830bdd7bb490e3e45d3e76781f
parent83b7e483856793bcac02281d1bc554ed53a2a573 (diff)
search generally functional
-rw-r--r--README.md24
-rw-r--r--assets/scss/main.scss4
-rw-r--r--layouts/_default/search.html36
-rw-r--r--layouts/index.json5
-rw-r--r--layouts/partials/footer/footer-widgets.html12
-rw-r--r--static/js/search.js126
-rw-r--r--static/syntax.css70
-rw-r--r--theme.toml3
8 files changed, 202 insertions, 78 deletions
diff --git a/README.md b/README.md
index 78b9426..d62778e 100644
--- a/README.md
+++ b/README.md
@@ -87,6 +87,25 @@ pygmentsUseClasses=true
pygmentsCodefences=true
```
+## Search
+
+Add the JSON output format to your `config.toml` to create the index:
+
+```toml
+[outputs]
+ home = ["HTML", "RSS", "JSON"]
+```
+
+Add `search.md` at the root of your `content` folder with the following frontmatter:
+
+```yaml
+---
+title: "Search"
+type: static
+layout: search
+---
+```
+
## Google Analytics
Add your Google Analytics Tracking Code ID to your `config.toml`:
@@ -95,6 +114,7 @@ Add your Google Analytics Tracking Code ID to your `config.toml`:
The asynchronous tracking script will be included on pages on the live server, but not the dev server.
-## Roadmap
+## Getting Help
+
-- [ ] Include search via Lunr or Fuse \ No newline at end of file
+## Contributing
diff --git a/assets/scss/main.scss b/assets/scss/main.scss
index 02fa5a0..3391d19 100644
--- a/assets/scss/main.scss
+++ b/assets/scss/main.scss
@@ -81,4 +81,8 @@ $color__border-abbr: #666;
.main-navigation .main-menu>li.menu-item-has-children .submenu-expand svg {
width: 24px;
height: 24px;
+}
+
+.searchPage-field {
+ padding: .36rem .66rem;
} \ No newline at end of file
diff --git a/layouts/_default/search.html b/layouts/_default/search.html
new file mode 100644
index 0000000..d2a1738
--- /dev/null
+++ b/layouts/_default/search.html
@@ -0,0 +1,36 @@
+{{ define "main" }}
+ <header class="page-header">
+ <h1 class="page-title">
+ Search results for:
+ <form action="{{ "search" | absURL }}">
+ <input placeholder="Search..." id="search-query" name="s" class="searchPage-field" />
+ </form>
+ </h1>
+ </header>
+
+ <div id="search-results"></div>
+
+ <script id="search-result-template" type="text/x-js-template">
+ <div id="summary-${key}">
+ <article class="post entry">
+ <header class="entry-header">
+ <h2 class="entry-title"><a href="${link}">${title}</a></h2>
+ </header>
+ <div class="entry-content">
+ <p>${snippet}</p>
+ </div>
+ <div class="entry-footer">
+ ${ isset tags }<span class="cat-links">Tags: ${tags}</span>${ end }
+ ${ isset categories }<p>Categories: ${categories}</p>${ end }
+ </div>
+ </article>
+ </div>
+ </script>
+{{ end }}
+
+{{ define "footer_scripts" }}
+ <script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/fuse.js/3.2.0/fuse.min.js"></script>
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/mark.js/8.11.1/jquery.mark.min.js"></script>
+ <script src="{{ "js/search.js" | absURL }}"></script>
+{{ end }}
diff --git a/layouts/index.json b/layouts/index.json
new file mode 100644
index 0000000..c93f805
--- /dev/null
+++ b/layouts/index.json
@@ -0,0 +1,5 @@
+{{- $.Scratch.Add "index" slice -}}
+{{- range .Site.RegularPages -}}
+ {{- $.Scratch.Add "index" (dict "title" .Title "tags" .Params.tags "categories" .Params.categories "contents" .Plain "permalink" .Permalink) -}}
+{{- end -}}
+{{- $.Scratch.Get "index" | jsonify -}}
diff --git a/layouts/partials/footer/footer-widgets.html b/layouts/partials/footer/footer-widgets.html
index 167f776..414a794 100644
--- a/layouts/partials/footer/footer-widgets.html
+++ b/layouts/partials/footer/footer-widgets.html
@@ -1,8 +1,14 @@
<aside class="widget-area" role="complementary" aria-label="Footer">
<div class="widget-column">
- <!-- <section id="search" class="widget widget_search">
- <h2 class="widget-title">Search</h2>
- </section> -->
+ <section id="search" class="widget widget_search">
+ <form role="search" class="search-form" action="/search/">
+ <label>
+ <span class="screen-reader-text">Search for:</span>
+ <input type="search" class="search-field" placeholder="Search ..." value name="s">
+ </label>
+ <input type="submit" class="search-submit" value="Search">
+ </form>
+ </section>
<section id="recent-posts" class="widget widget_recent_entries">
<h2 class="widget-title">Recent Posts</h2>
diff --git a/static/js/search.js b/static/js/search.js
new file mode 100644
index 0000000..d6204d5
--- /dev/null
+++ b/static/js/search.js
@@ -0,0 +1,126 @@
+summaryInclude = 60;
+var fuseOptions = {
+ shouldSort: true,
+ includeMatches: true,
+ threshold: 0.0,
+ tokenize: true,
+ location: 0,
+ distance: 100,
+ maxPatternLength: 32,
+ minMatchCharLength: 1,
+ keys: [
+ { name: "title", weight: 0.8 },
+ { name: "contents", weight: 0.5 },
+ { name: "tags", weight: 0.3 },
+ { name: "categories", weight: 0.3 }
+ ]
+};
+
+var searchQuery = param("s");
+if (searchQuery) {
+ $("#search-query").val(searchQuery);
+ executeSearch(searchQuery);
+} else {
+ $("#search-results").append("<p>Please enter a word or phrase above</p>");
+}
+
+function executeSearch(searchQuery) {
+ $.getJSON("/index.json", function(data) {
+ var pages = data;
+ var fuse = new Fuse(pages, fuseOptions);
+ var result = fuse.search(searchQuery);
+ console.log({ matches: result });
+ if (result.length > 0) {
+ populateResults(result);
+ } else {
+ $("#search-results").append("<p>No matches found</p>");
+ }
+ });
+}
+
+function populateResults(result) {
+ $.each(result, function(key, value) {
+ var contents = value.item.contents;
+ var snippet = "";
+ var snippetHighlights = [];
+ var tags = [];
+ if (fuseOptions.tokenize) {
+ snippetHighlights.push(searchQuery);
+ } else {
+ $.each(value.matches, function(matchKey, mvalue) {
+ if (mvalue.key == "tags" || mvalue.key == "categories") {
+ snippetHighlights.push(mvalue.value);
+ } else if (mvalue.key == "contents") {
+ start =
+ mvalue.indices[0][0] - summaryInclude > 0
+ ? mvalue.indices[0][0] - summaryInclude
+ : 0;
+ end =
+ mvalue.indices[0][1] + summaryInclude < contents.length
+ ? mvalue.indices[0][1] + summaryInclude
+ : contents.length;
+ snippet += contents.substring(start, end);
+ snippetHighlights.push(
+ mvalue.value.substring(
+ mvalue.indices[0][0],
+ mvalue.indices[0][1] - mvalue.indices[0][0] + 1
+ )
+ );
+ }
+ });
+ }
+
+ if (snippet.length < 1) {
+ snippet += contents.substring(0, summaryInclude * 2);
+ }
+ //pull template from hugo templarte definition
+ var templateDefinition = $("#search-result-template").html();
+ //replace values
+ var output = render(templateDefinition, {
+ key: key,
+ title: value.item.title,
+ link: value.item.permalink,
+ tags: value.item.tags,
+ categories: value.item.categories,
+ snippet: snippet
+ });
+ $("#search-results").append(output);
+
+ $.each(snippetHighlights, function(snipkey, snipvalue) {
+ $("#summary-" + key).mark(snipvalue);
+ });
+ });
+}
+
+function param(name) {
+ return decodeURIComponent(
+ (location.search.split(name + "=")[1] || "").split("&")[0]
+ ).replace(/\+/g, " ");
+}
+
+function render(templateString, data) {
+ var conditionalMatches, conditionalPattern, copy;
+ conditionalPattern = /\$\{\s*isset ([a-zA-Z]*) \s*\}(.*)\$\{\s*end\s*}/g;
+ //since loop below depends on re.lastInxdex, we use a copy to capture any manipulations whilst inside the loop
+ copy = templateString;
+ while (
+ (conditionalMatches = conditionalPattern.exec(templateString)) !== null
+ ) {
+ if (data[conditionalMatches[1]]) {
+ //valid key, remove conditionals, leave contents.
+ copy = copy.replace(conditionalMatches[0], conditionalMatches[2]);
+ } else {
+ //not valid, remove entire section
+ copy = copy.replace(conditionalMatches[0], "");
+ }
+ }
+ templateString = copy;
+ //now any conditionals removed we can do simple substitution
+ var key, find, re;
+ for (key in data) {
+ find = "\\$\\{\\s*" + key + "\\s*\\}";
+ re = new RegExp(find, "g");
+ templateString = templateString.replace(re, data[key]);
+ }
+ return templateString;
+}
diff --git a/static/syntax.css b/static/syntax.css
deleted file mode 100644
index e3b54c8..0000000
--- a/static/syntax.css
+++ /dev/null
@@ -1,70 +0,0 @@
-/* Background */ .chroma { color: #272822; background-color: #fafafa }
-/* Error */ .chroma .err { color: #960050; background-color: #1e0010 }
-/* LineTableTD */ .chroma .lntd { vertical-align: top; padding: 0; margin: 0; border: 0; }
-/* LineTable */ .chroma .lntable { border-spacing: 0; padding: 0; margin: 0; border: 0; width: auto; overflow: auto; display: block; }
-/* LineHighlight */ .chroma .hl { display: block; width: 100%;background-color: #ffffcc }
-/* LineNumbersTable */ .chroma .lnt { margin-right: 0.4em; padding: 0 0.4em 0 0.4em;color: #7f7f7f }
-/* LineNumbers */ .chroma .ln { margin-right: 0.4em; padding: 0 0.4em 0 0.4em;color: #7f7f7f }
-/* Keyword */ .chroma .k { color: #00a8c8 }
-/* KeywordConstant */ .chroma .kc { color: #00a8c8 }
-/* KeywordDeclaration */ .chroma .kd { color: #00a8c8 }
-/* KeywordNamespace */ .chroma .kn { color: #f92672 }
-/* KeywordPseudo */ .chroma .kp { color: #00a8c8 }
-/* KeywordReserved */ .chroma .kr { color: #00a8c8 }
-/* KeywordType */ .chroma .kt { color: #00a8c8 }
-/* Name */ .chroma .n { color: #111111 }
-/* NameAttribute */ .chroma .na { color: #75af00 }
-/* NameBuiltin */ .chroma .nb { color: #111111 }
-/* NameBuiltinPseudo */ .chroma .bp { color: #111111 }
-/* NameClass */ .chroma .nc { color: #75af00 }
-/* NameConstant */ .chroma .no { color: #00a8c8 }
-/* NameDecorator */ .chroma .nd { color: #75af00 }
-/* NameEntity */ .chroma .ni { color: #111111 }
-/* NameException */ .chroma .ne { color: #75af00 }
-/* NameFunction */ .chroma .nf { color: #75af00 }
-/* NameFunctionMagic */ .chroma .fm { color: #111111 }
-/* NameLabel */ .chroma .nl { color: #111111 }
-/* NameNamespace */ .chroma .nn { color: #111111 }
-/* NameOther */ .chroma .nx { color: #75af00 }
-/* NameProperty */ .chroma .py { color: #111111 }
-/* NameTag */ .chroma .nt { color: #f92672 }
-/* NameVariable */ .chroma .nv { color: #111111 }
-/* NameVariableClass */ .chroma .vc { color: #111111 }
-/* NameVariableGlobal */ .chroma .vg { color: #111111 }
-/* NameVariableInstance */ .chroma .vi { color: #111111 }
-/* NameVariableMagic */ .chroma .vm { color: #111111 }
-/* Literal */ .chroma .l { color: #ae81ff }
-/* LiteralDate */ .chroma .ld { color: #d88200 }
-/* LiteralString */ .chroma .s { color: #d88200 }
-/* LiteralStringAffix */ .chroma .sa { color: #d88200 }
-/* LiteralStringBacktick */ .chroma .sb { color: #d88200 }
-/* LiteralStringChar */ .chroma .sc { color: #d88200 }
-/* LiteralStringDelimiter */ .chroma .dl { color: #d88200 }
-/* LiteralStringDoc */ .chroma .sd { color: #d88200 }
-/* LiteralStringDouble */ .chroma .s2 { color: #d88200 }
-/* LiteralStringEscape */ .chroma .se { color: #8045ff }
-/* LiteralStringHeredoc */ .chroma .sh { color: #d88200 }
-/* LiteralStringInterpol */ .chroma .si { color: #d88200 }
-/* LiteralStringOther */ .chroma .sx { color: #d88200 }
-/* LiteralStringRegex */ .chroma .sr { color: #d88200 }
-/* LiteralStringSingle */ .chroma .s1 { color: #d88200 }
-/* LiteralStringSymbol */ .chroma .ss { color: #d88200 }
-/* LiteralNumber */ .chroma .m { color: #ae81ff }
-/* LiteralNumberBin */ .chroma .mb { color: #ae81ff }
-/* LiteralNumberFloat */ .chroma .mf { color: #ae81ff }
-/* LiteralNumberHex */ .chroma .mh { color: #ae81ff }
-/* LiteralNumberInteger */ .chroma .mi { color: #ae81ff }
-/* LiteralNumberIntegerLong */ .chroma .il { color: #ae81ff }
-/* LiteralNumberOct */ .chroma .mo { color: #ae81ff }
-/* Operator */ .chroma .o { color: #f92672 }
-/* OperatorWord */ .chroma .ow { color: #f92672 }
-/* Punctuation */ .chroma .p { color: #111111 }
-/* Comment */ .chroma .c { color: #75715e }
-/* CommentHashbang */ .chroma .ch { color: #75715e }
-/* CommentMultiline */ .chroma .cm { color: #75715e }
-/* CommentSingle */ .chroma .c1 { color: #75715e }
-/* CommentSpecial */ .chroma .cs { color: #75715e }
-/* CommentPreproc */ .chroma .cp { color: #75715e }
-/* CommentPreprocFile */ .chroma .cpf { color: #75715e }
-/* GenericEmph */ .chroma .ge { font-style: italic }
-/* GenericStrong */ .chroma .gs { font-weight: bold }
diff --git a/theme.toml b/theme.toml
index de3bce2..8852ad1 100644
--- a/theme.toml
+++ b/theme.toml
@@ -7,9 +7,6 @@ tags = ["blog", "clean", "color configuration"]
features = ["blog", "clean", "color configuration"]
min_version = "0.54.0"
-pygmentsUseClasses=true
-pygmentsCodefences=true
-
[author]
name = "Jeremy Bise"
homepage = "https://jeremybise.com/"