diff options
author | Zack Scholl <zack.scholl@gmail.com> | 2018-03-23 14:46:45 +0300 |
---|---|---|
committer | Zack Scholl <zack.scholl@gmail.com> | 2018-03-23 14:46:45 +0300 |
commit | becba818e2e76118f501af294c68a617ced09141 (patch) | |
tree | ed2750bbe3837b68ba94ed3fc3b4a47fda144107 | |
parent | ad62d40429bec75eeb2e1d8d9c3d29970b03d567 (diff) |
Added search, reformated
-rw-r--r-- | layouts/_default/index.json | 5 | ||||
-rw-r--r-- | layouts/_default/search.html | 77 | ||||
-rwxr-xr-x | layouts/_default/single.html | 175 | ||||
-rwxr-xr-x | layouts/partials/header.html | 30 | ||||
-rw-r--r-- | layouts/partials/middle.html | 84 | ||||
-rw-r--r-- | static/css/style4.css | 198 | ||||
-rw-r--r-- | static/js/search.js | 109 |
7 files changed, 585 insertions, 93 deletions
diff --git a/layouts/_default/index.json b/layouts/_default/index.json new file mode 100644 index 0000000..c93f805 --- /dev/null +++ b/layouts/_default/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/_default/search.html b/layouts/_default/search.html new file mode 100644 index 0000000..d1bdea1 --- /dev/null +++ b/layouts/_default/search.html @@ -0,0 +1,77 @@ +{{ partial "header.html" . }} +<div id="documentbody"> + <div class="wtblog"> + <div class="maintext"> + <div class="wikitext titlehack"> + <h2>Search</h2> + </div> + <div class="wikitext"> + <section class="resume-section p-3 p-lg-5 d-flex flex-column"> + <div class="my-auto" > + <form action="{{ "search" | absURL }}"> + <input id="search-query" name="s"/> + </form> + <div id="search-results"> + <h3>Matching pages</h3> + </div> + </div> + </section> + <!-- this template is sucked in by search.js and appended to the search-results div above. So editing here will adjust style --> + <script id="search-result-template" type="text/x-js-template"> + <div id="summary-${key}"> + <h4><a href="${link}">${title}</a></h4> + <p>${snippet}</p> + ${ isset tags }<p>Tags: ${tags}</p>${ end } + ${ isset categories }<p>Categories: ${categories}</p>${ end } + </div> + </script> + </div> + + + </div> + <div class="sidebar"> + <div class="readme"> + <div class="wikitext"> + <!-- <p>These are my + <a href="/~cks/space/blog/">WanderingThoughts</a> + <br> ( + <a href="/~cks/space/AboutBlog">About the blog</a>) + </p> --> + <p> + <a href="/">Full index of entries</a> + </p> + <p>Twitter: + <a href="https://twitter.com/yakczar/">@yakczar</a> + </p> + <p align="center">* * *</p> + <p> +<pre> + /\___/\ + ( o o ) + ( =^= ) + ( ) + ( ) + ( ))))))))))) + +</pre> + </p> + </div> + </div> + <!-- <div class="sidesearch" style="font-size: small"> + <form method=get action="/~cks/space/">Search: + <input name=search size=15> + </form> + </div> --> + </div> + </div> + </div> + <hr> + + +<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> + + +{{ partial "footer.html" . }} diff --git a/layouts/_default/single.html b/layouts/_default/single.html index 0fe3c6e..1a976a9 100755 --- a/layouts/_default/single.html +++ b/layouts/_default/single.html @@ -2,73 +2,128 @@ <div id="loadingMask" style="width: 100%; height: 100%; position: fixed; background: #fff;"></div>
<script>
-function fadeOut(el) {
- el.style.opacity = 1;
-
- var last = +new Date();
- var tick = function() {
- el.style.opacity = +el.style.opacity - (new Date() - last) / 80;
- last = +new Date();
- // console.log(el.style.opacity);
+ function fadeOut(el) {
+ el.style.opacity = 1;
+
+ var last = +new Date();
+ var tick = function () {
+ el.style.opacity = +el.style.opacity - (new Date() - last) / 80;
+ last = +new Date();
+ // console.log(el.style.opacity);
+
+ if (el.style.opacity > 0) {
+ (window.requestAnimationFrame && requestAnimationFrame(tick)) || setTimeout(tick, 16);
+ } else {
+ el.style.display = 'none';
+ }
+ };
- if (el.style.opacity > 0) {
- (window.requestAnimationFrame && requestAnimationFrame(tick)) || setTimeout(tick, 16);
- } else {
- el.style.display='none';
+ tick();
}
- };
-
- tick();
-}
-function ready(fn) {
- if (document.attachEvent ? document.readyState === "complete" : document.readyState !== "loading") {
- el = document.getElementById('loadingMask');
- fadeOut(el);
- var elements = document.querySelectorAll("img");
- Array.prototype.forEach.call(elements, function(el, i) {
- if (el.getAttribute("alt")) {
- const caption = document.createElement('figcaption');
- var node = document.createTextNode(el.getAttribute("alt"));
- caption.appendChild(node);
- const wrapper = document.createElement('figure');
- wrapper.className = 'image';
- el.parentNode.insertBefore(wrapper, el);
- el.parentNode.removeChild(el);
- wrapper.appendChild(el);
- wrapper.appendChild(caption);
- }
- });
-
- } else {
- document.addEventListener('DOMContentLoaded', fn);
+ function ready(fn) {
+ if (document.attachEvent ? document.readyState === "complete" : document.readyState !== "loading") {
+ el = document.getElementById('loadingMask');
+ fadeOut(el);
+ var elements = document.querySelectorAll("img");
+ Array.prototype.forEach.call(elements, function (el, i) {
+ if (el.getAttribute("alt")) {
+ const caption = document.createElement('figcaption');
+ var node = document.createTextNode(el.getAttribute("alt"));
+ caption.appendChild(node);
+ const wrapper = document.createElement('figure');
+ wrapper.className = 'image';
+ el.parentNode.insertBefore(wrapper, el);
+ el.parentNode.removeChild(el);
+ wrapper.appendChild(el);
+ wrapper.appendChild(caption);
+ }
+ });
+
+ } else {
+ document.addEventListener('DOMContentLoaded', fn);
+ }
}
-}
-window.onload = ready;
+ window.onload = ready;
</script>
-<div class="content">
- <h1>{{ .Title }} <aside>{{ range .Params.tags }}<a href="/tags/{{.}}/" class="w3-tag">/{{.}}</a> {{end}}</aside></h1>
- {{ .Content }}
-</div>
-
-
-
-{{ if (eq .Type "post") }}
- <p><small><em>Written {{ .Date.Format "January 2, 2006"}}. </em>
- {{ if $.Site.Params.twitter }}
- Send feedback to <a href="https://twitter.com/intent/tweet?text=%40{{ $.Site.Params.twitter }}%20%23{{ replace (.URL) "/" "" }}%20">@{{ $.Site.Params.twitter }}</a>.
- {{ end }}
- </small></p>
-
- <p>
- {{ if .PrevInSection }}<a href="{{ .PrevInSection.URL }}">← {{ .PrevInSection.Title }}</a> {{end}}
- {{ if .NextInSection }}<a href="{{ .NextInSection.URL }}" style="float:right;">{{ .NextInSection.Title }} →</a>{{ end }}
- </p>
-{{ end }}
-
+<div id="documentbody">
+ <div class="wtblog">
+ <div class="maintext">
+ <div class="wikitext titlehack">
+ <h2>{{ .Title }}</h2>
+ <div class="posttitle" style="opacity: 0.6;">
+ <small>{{ .Date.Format "January 2, 2006"}}</small>
+ </div>
+ </div>
+ <div class="wikitext">
+ {{ .Content }}
+ </div>
+
+ <small>Written on
+ <a href="/~cks/space/blog/2018/03/18/">{{ .Date.Format "2"}}</a>
+ <a href="/~cks/space/blog/2018/03/">{{ .Date.Format "January"}}</a>
+ <a href="/~cks/space/blog/2018/">{{ .Date.Format "2006"}}</a>.</small>
+ <br>
+ <table border=0 width="100%">
+ <tr>
+ <td width="50%" style="padding-right: 0.5em">
+ <table>
+ <tr>
+ <td> « </td>
+ <td>
+ {{ if .PrevInSection }}
+ <a href="{{ .PrevInSection.URL }}">{{ .PrevInSection.Title }}</a> {{end}}
+ </td>
+ </tr>
+ </table>
+ </td>
+ <td width="50%" style="padding-left: 0.5em; border-left: 1px dotted;">
+ <table>
+ <tr>
+ <td>
+ {{ if .NextInSection }}
+ <a href="{{ .NextInSection.URL }}" style="float:right;">{{ .NextInSection.Title }}</a>{{ end }}
+ </td>
+ <td> » </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+ </div>
+ <div class="sidebar">
+ <div class="readme">
+ <div class="wikitext">
+ <!-- <p>These are my
+ <a href="/~cks/space/blog/">WanderingThoughts</a>
+ <br> (
+ <a href="/~cks/space/AboutBlog">About the blog</a>)
+ </p> -->
+ <p>
+ <a href="/">Full index of entries</a>
+ </p>
+ <p>Twitter:
+ <a href="https://twitter.com/yakczar/">@yakczar</a>
+ </p>
+ <p align="center">* * *</p>
+ <p>Categories:
+ {{ range $i, $e := .Params.Tags }}{{ if $i }}, {{ end }}<a href="/tags/{{$e}}/">{{ $e }}</a>{{ end }}
+ </p>
+
+ </div>
+ </div>
+ <div class="sidesearch" style="font-size: small">
+ <form onsubmit="location.href='/search/?s=' + document.getElementById('myInput').value; return false;">
+ Search: <input type="text" id="myInput" size=15 />
+ </form>
+ </div>
+ </div>
+ </div>
+</div>
+<hr>
-{{ partial "footer.html" . }}
+{{ partial "footer.html" . }}
\ No newline at end of file diff --git a/layouts/partials/header.html b/layouts/partials/header.html index f4e54a3..1937116 100755 --- a/layouts/partials/header.html +++ b/layouts/partials/header.html @@ -37,15 +37,21 @@ {{ if $.Site.Params.analytics }} <img src="https://analytics.schollz.com/1.png?page={{ .Permalink }}" width=1px height=1px style="float:right;"> {{ end }} -<header > - <a href="/" style="float: left;color:#777;"><strong>{{ $.Site.Title }}</strong> - </a> - <a href="/index.xml" style="color:#777;float: left;"><strong> - - <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-rss"><path d="M4 11a9 9 0 0 1 9 9"></path><path d="M4 4a16 16 0 0 1 16 16"></path><circle cx="5" cy="19" r="1"></circle></svg> -</strong></a> -{{ range $i, $e:= $.Site.Params.navigation }}{{ if eq $i 0}}{{else}} · {{end}}{{ with $.Site.GetPage "page" . }}<a href="{{ lower .Permalink }}" style="color:#777;"><strong>{{ title .Title }}</strong></a>{{ end }}{{ end }} -{{ if .Draft }} -DRAFT -{{ end }} -</header> + +<div id="header"> + <div class="left"> + <a href="/">Zack's Notablog</a> </div> + <div class="right"> + <a href="/index.xml" style="color:#777;float: left;"> + <strong> + + <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" + stroke-linecap="round" stroke-linejoin="round" class="feather feather-rss"> + <path d="M4 11a9 9 0 0 1 9 9"></path> + <path d="M4 4a16 16 0 0 1 16 16"></path> + <circle cx="5" cy="19" r="1"></circle> + </svg> + </strong> + </a> + </div> + </div>
\ No newline at end of file diff --git a/layouts/partials/middle.html b/layouts/partials/middle.html index 2e1d531..9e7f528 100644 --- a/layouts/partials/middle.html +++ b/layouts/partials/middle.html @@ -1,22 +1,64 @@ - - -<div class="content"> -<h1>{{ title .Data.Term }} posts</h1> - {{ range first 100000 .Pages }} - {{ if eq .Type "post"}} - <p> - <aside>{{ .Date.Format "January 2, 2006"}} - <!--{{ if .Params.tags }} - /// <em>{{ range $i, $e := .Params.tags }}{{ if $i }}, {{ end }}<a href="/tags/{{$e}}/">{{ $e }}</a>{{ end }} - </em> - - {{ end }}--> - </aside> - <a href="{{ .Permalink }}" style="color:black;">{{ .Title }}</a>{{ if .Draft }} <span style="color:#FF4136;">(unpublished)</span> -{{ end }} - </p> - {{ end }} - {{ end }} -</div> - +<div id="documentbody"> + <div class="wtblog"> + <div class="maintext"> + <div class="wikitext titlehack"> + <h2>{{ title .Data.Term }} posts</h2> + </div> + <div class="wikitext"> + {{ range first 100000 .Pages }} + {{ if eq .Type "post"}} + <p> + <aside>{{ .Date.Format "January 2, 2006"}} + <!--{{ if .Params.tags }} + /// <em>{{ range $i, $e := .Params.tags }}{{ if $i }}, {{ end }}<a href="/tags/{{$e}}/">{{ $e }}</a>{{ end }} + </em> + + {{ end }}--> + </aside> + <a href="{{ .Permalink }}" style="color:black;">{{ .Title }}</a>{{ if .Draft }} <span style="color:#FF4136;">(unpublished)</span> + {{ end }} + </p> + {{ end }} + {{ end }} + </div> + + + </div> + <div class="sidebar"> + <div class="readme"> + <div class="wikitext"> + <!-- <p>These are my + <a href="/~cks/space/blog/">WanderingThoughts</a> + <br> ( + <a href="/~cks/space/AboutBlog">About the blog</a>) + </p> --> + <p> + <a href="/">Full index of entries</a> + </p> + <p>Twitter: + <a href="https://twitter.com/yakczar/">@yakczar</a> + </p> + <p align="center">* * *</p> + <p> +<pre> + /\___/\ + ( o o ) + ( =^= ) + ( ) + ( ) + ( ))))))))))) + +</pre> + </p> + </div> + </div> + <div class="sidesearch" style="font-size: small"> + <form onsubmit="location.href='/search/?s=' + document.getElementById('myInput').value; return false;"> + Search: <input type="text" id="myInput" size=15 /> + </form> + </div> + </div> + </div> + </div> + <hr> diff --git a/static/css/style4.css b/static/css/style4.css new file mode 100644 index 0000000..e781b50 --- /dev/null +++ b/static/css/style4.css @@ -0,0 +1,198 @@ +#header { font-size: small; } +div.left { float: left; } +div.right { float: right; } + +/* + * This forces the entire top header to be separated from the content + * by some whitespace. Because the interior divs are both floated, + * we cannot reliably put the margin on the #header div itself. Instead + * we attach it to both floating divs. 1em is about one normal lineheight. + */ +#header > div { margin-bottom: 1em;} + +.clear { clear: both; } +#documentbody { clear: both; } + +table.wikitable { + border-collapse: collapse; +} +.wikitable td { + border: 1px; + border-style: solid; + padding: .3em; + vertical-align: top; +} + +.wikitext > h1, .wikitext > h2, .wikitext > h3, .wikitext > h4 { + margin-top: 0.5em; +} + +.titlehack h1, .titlehack h2, .titlehack h3, .titlehack h4 { + margin-bottom: 0.1em; +} + +/* + * horizontal tables in wikitext are funny because they also get the + * normal wikitext <td> CSS as well, so we have to override bits of + * it. + */ +.wikitext table.horizontal { + vertical-align: top; + border-collapse: collapse; +} +.wikitext table.horizontal td { + text-align: left; + border-style: dotted; + border-width: 0 0 1px 0; +} +.wikitext table.horizontal td + td { + padding-left: 1em; +} +.wikitext table.horizontal tr { + border-bottom: 1px dotted; +} + +.comment .wikitext pre { + white-space: pre-wrap; +} + +/* + * The bottom table whitespace should be about 1em, which we get + * through .5em bottom padding of the last row of <td>s plus + * .5em margin-bottom of the table itself. + */ +table.blogtitles { + border-collapse: collapse; + margin-bottom: .5em; +} +.blogtitles td { + vertical-align: top; + text-align: left; + padding-bottom: .5em; +} +.blogtitles td + td { + padding-left: 0.5em; +} + +#atomfeeds { + font-size: small; + margin-top: .4em; + margin-bottom: .4em; +} + +/* + The CSS based version of column layouts done with display: table-*. + We have multiple wrapping divs because you apparently can't attach + borders to 'display: table-row;' divs. .siderow && .mainrow divs + will become table rows in the minimized version and are table cells + in the normal one. + We also set a maximum width of the overall text column of about 45em + (76% of 60em); if you're on a really wide display you get a centered + column of text instead of hugely wide lines. + + TODO: push top of sidebar down somehow without pushing down top of main + text. + http://stackoverflow.com/questions/16398823/why-does-a-div-with-display-table-cell-not-affected-by-margin +*/ +.wttitle { + text-align: center; +} + +.wtblog { + display: table; + max-width: 60em; + margin-left: auto; margin-right: auto; +} +.maintext { + display: table-cell; width: 76%; + padding: 1px 1.5em 1px 1px; +} +.sidebar { + display: table-cell; width: 24%; + padding: 1px 1px 1px 0.5em; + border-left: 1px dotted; +} + +/* Resize on small width and on the iPad Mini in portrait. + I don't know why the iPad Mini doesn't resize without an explicit + match but this is life in the CSS mines (instead it shrinks the + text size, NOT HELPFUL). + + aarg: http://stephen.io/mediaqueries/#iPadMini +http://stackoverflow.com/questions/16262542/ipad-mini-specfic-css-media-queries +*/ +@media only screen and (max-width: 45em), + only screen and (max-device-width: 45em), + only screen and (orientation: portrait) and (max-device-width: 50em) { + .wtblog { + display: block; + } + .maintext { + display: block; width: auto; + padding: 0 1em 0 0.25em; + } + .sidebar { + display: block; width: auto; + font-size: 80%; + padding: 0 0 0.5em 4px; + border-style: dotted none none; + border-width: 1px 0 0; + margin-top: 10px; + } + .sidesearch { display: none; } +} + +/* On really small screens start deleting things */ +@media screen and (max-width: 25em) { + .right { display: none; } + .wttitle { display: none; } +} + +/* on the iPad Mini in portrait mode, enlarge text size. */ +@media only screen and (min-device-width: 768px) and + (max-device-width: 1024px) and (-webkit-min-device-pixel-ratio: 1) + and (orientation: portrait) { + .maintext { font-size: 120%; padding: 0 1em 0 1em; } + .sidebar { font-size: 100%; } +} +/* with a <meta> viewport, need to *shrink* the font size slightly on an + iPad Mini in landscape? */ +@media only screen and (min-device-width: 768px) and + (max-device-width: 1024px) and (-webkit-min-device-pixel-ratio: 1) + and (orientation: landscape) { + .maintext, .sidebar { font-size: 90%; } +} + +img { + width: 100%; + display: block; + vertical-align: top; + text-align: center; +} + +figcaption { + color: #777; + font-style: italic; + text-align: center; +} + +figure { + display: block; + border: 0px solid #303030; +} + +a:hover { + color: #777; + border-bottom: 1px solid #777; +} + +a:focus { + color: #777; + border-bottom: 1px solid #777; +} + +a { + border-bottom: 1px solid #3366BB ; + text-decoration: none; + color: #3366BB ; +}
\ No newline at end of file diff --git a/static/js/search.js b/static/js/search.js new file mode 100644 index 0000000..a80a8b8 --- /dev/null +++ b/static/js/search.js @@ -0,0 +1,109 @@ + +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; +} |