aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMitja Felicijan <mitja.felicijan@gmail.com>2022-07-22 23:27:00 +0200
committerMitja Felicijan <mitja.felicijan@gmail.com>2022-07-22 23:27:00 +0200
commit45c89b984d3f2b3bf97c8c5ee52e62aa6a4af6dc (patch)
tree098417a178a0fe4e054722a84e696d4574c98b16
parent773829d1848f1f18ef587ed5608dd72483c9be53 (diff)
downloadmitjafelicijan.com-45c89b984d3f2b3bf97c8c5ee52e62aa6a4af6dc.tar.gz
Added front end search
-rw-r--r--assets/general/elasticlunr.min.js10
-rwxr-xr-xtemplate/_includes.html3
-rwxr-xr-xtemplate/_navigation.html2
-rw-r--r--template/_search.html6
-rwxr-xr-xtemplate/index.html4
-rwxr-xr-xtemplate/post.html2
-rwxr-xr-xtemplate/script.js145
-rwxr-xr-xtemplate/style.css145
8 files changed, 227 insertions, 90 deletions
diff --git a/assets/general/elasticlunr.min.js b/assets/general/elasticlunr.min.js
new file mode 100644
index 0000000..94b20dd
--- /dev/null
+++ b/assets/general/elasticlunr.min.js
@@ -0,0 +1,10 @@
1/**
2 * elasticlunr - http://weixsong.github.io
3 * Lightweight full-text search engine in Javascript for browser search and offline search. - 0.9.5
4 *
5 * Copyright (C) 2017 Oliver Nightingale
6 * Copyright (C) 2017 Wei Song
7 * MIT Licensed
8 * @license
9 */
10!function(){function e(e){if(null===e||"object"!=typeof e)return e;var t=e.constructor();for(var n in e)e.hasOwnProperty(n)&&(t[n]=e[n]);return t}var t=function(e){var n=new t.Index;return n.pipeline.add(t.trimmer,t.stopWordFilter,t.stemmer),e&&e.call(n,n),n};t.version="0.9.5",lunr=t,t.utils={},t.utils.warn=function(e){return function(t){e.console&&console.warn&&console.warn(t)}}(this),t.utils.toString=function(e){return void 0===e||null===e?"":e.toString()},t.EventEmitter=function(){this.events={}},t.EventEmitter.prototype.addListener=function(){var e=Array.prototype.slice.call(arguments),t=e.pop(),n=e;if("function"!=typeof t)throw new TypeError("last argument must be a function");n.forEach(function(e){this.hasHandler(e)||(this.events[e]=[]),this.events[e].push(t)},this)},t.EventEmitter.prototype.removeListener=function(e,t){if(this.hasHandler(e)){var n=this.events[e].indexOf(t);-1!==n&&(this.events[e].splice(n,1),0==this.events[e].length&&delete this.events[e])}},t.EventEmitter.prototype.emit=function(e){if(this.hasHandler(e)){var t=Array.prototype.slice.call(arguments,1);this.events[e].forEach(function(e){e.apply(void 0,t)},this)}},t.EventEmitter.prototype.hasHandler=function(e){return e in this.events},t.tokenizer=function(e){if(!arguments.length||null===e||void 0===e)return[];if(Array.isArray(e)){var n=e.filter(function(e){return null===e||void 0===e?!1:!0});n=n.map(function(e){return t.utils.toString(e).toLowerCase()});var i=[];return n.forEach(function(e){var n=e.split(t.tokenizer.seperator);i=i.concat(n)},this),i}return e.toString().trim().toLowerCase().split(t.tokenizer.seperator)},t.tokenizer.defaultSeperator=/[\s\-]+/,t.tokenizer.seperator=t.tokenizer.defaultSeperator,t.tokenizer.setSeperator=function(e){null!==e&&void 0!==e&&"object"==typeof e&&(t.tokenizer.seperator=e)},t.tokenizer.resetSeperator=function(){t.tokenizer.seperator=t.tokenizer.defaultSeperator},t.tokenizer.getSeperator=function(){return t.tokenizer.seperator},t.Pipeline=function(){this._queue=[]},t.Pipeline.registeredFunctions={},t.Pipeline.registerFunction=function(e,n){n in t.Pipeline.registeredFunctions&&t.utils.warn("Overwriting existing registered function: "+n),e.label=n,t.Pipeline.registeredFunctions[n]=e},t.Pipeline.getRegisteredFunction=function(e){return e in t.Pipeline.registeredFunctions!=!0?null:t.Pipeline.registeredFunctions[e]},t.Pipeline.warnIfFunctionNotRegistered=function(e){var n=e.label&&e.label in this.registeredFunctions;n||t.utils.warn("Function is not registered with pipeline. This may cause problems when serialising the index.\n",e)},t.Pipeline.load=function(e){var n=new t.Pipeline;return e.forEach(function(e){var i=t.Pipeline.getRegisteredFunction(e);if(!i)throw new Error("Cannot load un-registered function: "+e);n.add(i)}),n},t.Pipeline.prototype.add=function(){var e=Array.prototype.slice.call(arguments);e.forEach(function(e){t.Pipeline.warnIfFunctionNotRegistered(e),this._queue.push(e)},this)},t.Pipeline.prototype.after=function(e,n){t.Pipeline.warnIfFunctionNotRegistered(n);var i=this._queue.indexOf(e);if(-1===i)throw new Error("Cannot find existingFn");this._queue.splice(i+1,0,n)},t.Pipeline.prototype.before=function(e,n){t.Pipeline.warnIfFunctionNotRegistered(n);var i=this._queue.indexOf(e);if(-1===i)throw new Error("Cannot find existingFn");this._queue.splice(i,0,n)},t.Pipeline.prototype.remove=function(e){var t=this._queue.indexOf(e);-1!==t&&this._queue.splice(t,1)},t.Pipeline.prototype.run=function(e){for(var t=[],n=e.length,i=this._queue.length,o=0;n>o;o++){for(var r=e[o],s=0;i>s&&(r=this._queue[s](r,o,e),void 0!==r&&null!==r);s++);void 0!==r&&null!==r&&t.push(r)}return t},t.Pipeline.prototype.reset=function(){this._queue=[]},t.Pipeline.prototype.get=function(){return this._queue},t.Pipeline.prototype.toJSON=function(){return this._queue.map(function(e){return t.Pipeline.warnIfFunctionNotRegistered(e),e.label})},t.Index=function(){this._fields=[],this._ref="id",this.pipeline=new t.Pipeline,this.documentStore=new t.DocumentStore,this.index={},this.eventEmitter=new t.EventEmitter,this._idfCache={},this.on("add","remove","update",function(){this._idfCache={}}.bind(this))},t.Index.prototype.on=function(){var e=Array.prototype.slice.call(arguments);return this.eventEmitter.addListener.apply(this.eventEmitter,e)},t.Index.prototype.off=function(e,t){return this.eventEmitter.removeListener(e,t)},t.Index.load=function(e){e.version!==t.version&&t.utils.warn("version mismatch: current "+t.version+" importing "+e.version);var n=new this;n._fields=e.fields,n._ref=e.ref,n.documentStore=t.DocumentStore.load(e.documentStore),n.pipeline=t.Pipeline.load(e.pipeline),n.index={};for(var i in e.index)n.index[i]=t.InvertedIndex.load(e.index[i]);return n},t.Index.prototype.addField=function(e){return this._fields.push(e),this.index[e]=new t.InvertedIndex,this},t.Index.prototype.setRef=function(e){return this._ref=e,this},t.Index.prototype.saveDocument=function(e){return this.documentStore=new t.DocumentStore(e),this},t.Index.prototype.addDoc=function(e,n){if(e){var n=void 0===n?!0:n,i=e[this._ref];this.documentStore.addDoc(i,e),this._fields.forEach(function(n){var o=this.pipeline.run(t.tokenizer(e[n]));this.documentStore.addFieldLength(i,n,o.length);var r={};o.forEach(function(e){e in r?r[e]+=1:r[e]=1},this);for(var s in r){var u=r[s];u=Math.sqrt(u),this.index[n].addToken(s,{ref:i,tf:u})}},this),n&&this.eventEmitter.emit("add",e,this)}},t.Index.prototype.removeDocByRef=function(e){if(e&&this.documentStore.isDocStored()!==!1&&this.documentStore.hasDoc(e)){var t=this.documentStore.getDoc(e);this.removeDoc(t,!1)}},t.Index.prototype.removeDoc=function(e,n){if(e){var n=void 0===n?!0:n,i=e[this._ref];this.documentStore.hasDoc(i)&&(this.documentStore.removeDoc(i),this._fields.forEach(function(n){var o=this.pipeline.run(t.tokenizer(e[n]));o.forEach(function(e){this.index[n].removeToken(e,i)},this)},this),n&&this.eventEmitter.emit("remove",e,this))}},t.Index.prototype.updateDoc=function(e,t){var t=void 0===t?!0:t;this.removeDocByRef(e[this._ref],!1),this.addDoc(e,!1),t&&this.eventEmitter.emit("update",e,this)},t.Index.prototype.idf=function(e,t){var n="@"+t+"/"+e;if(Object.prototype.hasOwnProperty.call(this._idfCache,n))return this._idfCache[n];var i=this.index[t].getDocFreq(e),o=1+Math.log(this.documentStore.length/(i+1));return this._idfCache[n]=o,o},t.Index.prototype.getFields=function(){return this._fields.slice()},t.Index.prototype.search=function(e,n){if(!e)return[];e="string"==typeof e?{any:e}:JSON.parse(JSON.stringify(e));var i=null;null!=n&&(i=JSON.stringify(n));for(var o=new t.Configuration(i,this.getFields()).get(),r={},s=Object.keys(e),u=0;u<s.length;u++){var a=s[u];r[a]=this.pipeline.run(t.tokenizer(e[a]))}var l={};for(var c in o){var d=r[c]||r.any;if(d){var f=this.fieldSearch(d,c,o),h=o[c].boost;for(var p in f)f[p]=f[p]*h;for(var p in f)p in l?l[p]+=f[p]:l[p]=f[p]}}var v,g=[];for(var p in l)v={ref:p,score:l[p]},this.documentStore.hasDoc(p)&&(v.doc=this.documentStore.getDoc(p)),g.push(v);return g.sort(function(e,t){return t.score-e.score}),g},t.Index.prototype.fieldSearch=function(e,t,n){var i=n[t].bool,o=n[t].expand,r=n[t].boost,s=null,u={};return 0!==r?(e.forEach(function(e){var n=[e];1==o&&(n=this.index[t].expandToken(e));var r={};n.forEach(function(n){var o=this.index[t].getDocs(n),a=this.idf(n,t);if(s&&"AND"==i){var l={};for(var c in s)c in o&&(l[c]=o[c]);o=l}n==e&&this.fieldSearchStats(u,n,o);for(var c in o){var d=this.index[t].getTermFrequency(n,c),f=this.documentStore.getFieldLength(c,t),h=1;0!=f&&(h=1/Math.sqrt(f));var p=1;n!=e&&(p=.15*(1-(n.length-e.length)/n.length));var v=d*a*h*p;c in r?r[c]+=v:r[c]=v}},this),s=this.mergeScores(s,r,i)},this),s=this.coordNorm(s,u,e.length)):void 0},t.Index.prototype.mergeScores=function(e,t,n){if(!e)return t;if("AND"==n){var i={};for(var o in t)o in e&&(i[o]=e[o]+t[o]);return i}for(var o in t)o in e?e[o]+=t[o]:e[o]=t[o];return e},t.Index.prototype.fieldSearchStats=function(e,t,n){for(var i in n)i in e?e[i].push(t):e[i]=[t]},t.Index.prototype.coordNorm=function(e,t,n){for(var i in e)if(i in t){var o=t[i].length;e[i]=e[i]*o/n}return e},t.Index.prototype.toJSON=function(){var e={};return this._fields.forEach(function(t){e[t]=this.index[t].toJSON()},this),{version:t.version,fields:this._fields,ref:this._ref,documentStore:this.documentStore.toJSON(),index:e,pipeline:this.pipeline.toJSON()}},t.Index.prototype.use=function(e){var t=Array.prototype.slice.call(arguments,1);t.unshift(this),e.apply(this,t)},t.DocumentStore=function(e){this._save=null===e||void 0===e?!0:e,this.docs={},this.docInfo={},this.length=0},t.DocumentStore.load=function(e){var t=new this;return t.length=e.length,t.docs=e.docs,t.docInfo=e.docInfo,t._save=e.save,t},t.DocumentStore.prototype.isDocStored=function(){return this._save},t.DocumentStore.prototype.addDoc=function(t,n){this.hasDoc(t)||this.length++,this.docs[t]=this._save===!0?e(n):null},t.DocumentStore.prototype.getDoc=function(e){return this.hasDoc(e)===!1?null:this.docs[e]},t.DocumentStore.prototype.hasDoc=function(e){return e in this.docs},t.DocumentStore.prototype.removeDoc=function(e){this.hasDoc(e)&&(delete this.docs[e],delete this.docInfo[e],this.length--)},t.DocumentStore.prototype.addFieldLength=function(e,t,n){null!==e&&void 0!==e&&0!=this.hasDoc(e)&&(this.docInfo[e]||(this.docInfo[e]={}),this.docInfo[e][t]=n)},t.DocumentStore.prototype.updateFieldLength=function(e,t,n){null!==e&&void 0!==e&&0!=this.hasDoc(e)&&this.addFieldLength(e,t,n)},t.DocumentStore.prototype.getFieldLength=function(e,t){return null===e||void 0===e?0:e in this.docs&&t in this.docInfo[e]?this.docInfo[e][t]:0},t.DocumentStore.prototype.toJSON=function(){return{docs:this.docs,docInfo:this.docInfo,length:this.length,save:this._save}},t.stemmer=function(){var e={ational:"ate",tional:"tion",enci:"ence",anci:"ance",izer:"ize",bli:"ble",alli:"al",entli:"ent",eli:"e",ousli:"ous",ization:"ize",ation:"ate",ator:"ate",alism:"al",iveness:"ive",fulness:"ful",ousness:"ous",aliti:"al",iviti:"ive",biliti:"ble",logi:"log"},t={icate:"ic",ative:"",alize:"al",iciti:"ic",ical:"ic",ful:"",ness:""},n="[^aeiou]",i="[aeiouy]",o=n+"[^aeiouy]*",r=i+"[aeiou]*",s="^("+o+")?"+r+o,u="^("+o+")?"+r+o+"("+r+")?$",a="^("+o+")?"+r+o+r+o,l="^("+o+")?"+i,c=new RegExp(s),d=new RegExp(a),f=new RegExp(u),h=new RegExp(l),p=/^(.+?)(ss|i)es$/,v=/^(.+?)([^s])s$/,g=/^(.+?)eed$/,m=/^(.+?)(ed|ing)$/,y=/.$/,S=/(at|bl|iz)$/,x=new RegExp("([^aeiouylsz])\\1$"),w=new RegExp("^"+o+i+"[^aeiouwxy]$"),I=/^(.+?[^aeiou])y$/,b=/^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/,E=/^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/,D=/^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/,F=/^(.+?)(s|t)(ion)$/,_=/^(.+?)e$/,P=/ll$/,k=new RegExp("^"+o+i+"[^aeiouwxy]$"),z=function(n){var i,o,r,s,u,a,l;if(n.length<3)return n;if(r=n.substr(0,1),"y"==r&&(n=r.toUpperCase()+n.substr(1)),s=p,u=v,s.test(n)?n=n.replace(s,"$1$2"):u.test(n)&&(n=n.replace(u,"$1$2")),s=g,u=m,s.test(n)){var z=s.exec(n);s=c,s.test(z[1])&&(s=y,n=n.replace(s,""))}else if(u.test(n)){var z=u.exec(n);i=z[1],u=h,u.test(i)&&(n=i,u=S,a=x,l=w,u.test(n)?n+="e":a.test(n)?(s=y,n=n.replace(s,"")):l.test(n)&&(n+="e"))}if(s=I,s.test(n)){var z=s.exec(n);i=z[1],n=i+"i"}if(s=b,s.test(n)){var z=s.exec(n);i=z[1],o=z[2],s=c,s.test(i)&&(n=i+e[o])}if(s=E,s.test(n)){var z=s.exec(n);i=z[1],o=z[2],s=c,s.test(i)&&(n=i+t[o])}if(s=D,u=F,s.test(n)){var z=s.exec(n);i=z[1],s=d,s.test(i)&&(n=i)}else if(u.test(n)){var z=u.exec(n);i=z[1]+z[2],u=d,u.test(i)&&(n=i)}if(s=_,s.test(n)){var z=s.exec(n);i=z[1],s=d,u=f,a=k,(s.test(i)||u.test(i)&&!a.test(i))&&(n=i)}return s=P,u=d,s.test(n)&&u.test(n)&&(s=y,n=n.replace(s,"")),"y"==r&&(n=r.toLowerCase()+n.substr(1)),n};return z}(),t.Pipeline.registerFunction(t.stemmer,"stemmer"),t.stopWordFilter=function(e){return e&&t.stopWordFilter.stopWords[e]!==!0?e:void 0},t.clearStopWords=function(){t.stopWordFilter.stopWords={}},t.addStopWords=function(e){null!=e&&Array.isArray(e)!==!1&&e.forEach(function(e){t.stopWordFilter.stopWords[e]=!0},this)},t.resetStopWords=function(){t.stopWordFilter.stopWords=t.defaultStopWords},t.defaultStopWords={"":!0,a:!0,able:!0,about:!0,across:!0,after:!0,all:!0,almost:!0,also:!0,am:!0,among:!0,an:!0,and:!0,any:!0,are:!0,as:!0,at:!0,be:!0,because:!0,been:!0,but:!0,by:!0,can:!0,cannot:!0,could:!0,dear:!0,did:!0,"do":!0,does:!0,either:!0,"else":!0,ever:!0,every:!0,"for":!0,from:!0,get:!0,got:!0,had:!0,has:!0,have:!0,he:!0,her:!0,hers:!0,him:!0,his:!0,how:!0,however:!0,i:!0,"if":!0,"in":!0,into:!0,is:!0,it:!0,its:!0,just:!0,least:!0,let:!0,like:!0,likely:!0,may:!0,me:!0,might:!0,most:!0,must:!0,my:!0,neither:!0,no:!0,nor:!0,not:!0,of:!0,off:!0,often:!0,on:!0,only:!0,or:!0,other:!0,our:!0,own:!0,rather:!0,said:!0,say:!0,says:!0,she:!0,should:!0,since:!0,so:!0,some:!0,than:!0,that:!0,the:!0,their:!0,them:!0,then:!0,there:!0,these:!0,they:!0,"this":!0,tis:!0,to:!0,too:!0,twas:!0,us:!0,wants:!0,was:!0,we:!0,were:!0,what:!0,when:!0,where:!0,which:!0,"while":!0,who:!0,whom:!0,why:!0,will:!0,"with":!0,would:!0,yet:!0,you:!0,your:!0},t.stopWordFilter.stopWords=t.defaultStopWords,t.Pipeline.registerFunction(t.stopWordFilter,"stopWordFilter"),t.trimmer=function(e){if(null===e||void 0===e)throw new Error("token should not be undefined");return e.replace(/^\W+/,"").replace(/\W+$/,"")},t.Pipeline.registerFunction(t.trimmer,"trimmer"),t.InvertedIndex=function(){this.root={docs:{},df:0}},t.InvertedIndex.load=function(e){var t=new this;return t.root=e.root,t},t.InvertedIndex.prototype.addToken=function(e,t,n){for(var n=n||this.root,i=0;i<=e.length-1;){var o=e[i];o in n||(n[o]={docs:{},df:0}),i+=1,n=n[o]}var r=t.ref;n.docs[r]?n.docs[r]={tf:t.tf}:(n.docs[r]={tf:t.tf},n.df+=1)},t.InvertedIndex.prototype.hasToken=function(e){if(!e)return!1;for(var t=this.root,n=0;n<e.length;n++){if(!t[e[n]])return!1;t=t[e[n]]}return!0},t.InvertedIndex.prototype.getNode=function(e){if(!e)return null;for(var t=this.root,n=0;n<e.length;n++){if(!t[e[n]])return null;t=t[e[n]]}return t},t.InvertedIndex.prototype.getDocs=function(e){var t=this.getNode(e);return null==t?{}:t.docs},t.InvertedIndex.prototype.getTermFrequency=function(e,t){var n=this.getNode(e);return null==n?0:t in n.docs?n.docs[t].tf:0},t.InvertedIndex.prototype.getDocFreq=function(e){var t=this.getNode(e);return null==t?0:t.df},t.InvertedIndex.prototype.removeToken=function(e,t){if(e){var n=this.getNode(e);null!=n&&t in n.docs&&(delete n.docs[t],n.df-=1)}},t.InvertedIndex.prototype.expandToken=function(e,t,n){if(null==e||""==e)return[];var t=t||[];if(void 0==n&&(n=this.getNode(e),null==n))return t;n.df>0&&t.push(e);for(var i in n)"docs"!==i&&"df"!==i&&this.expandToken(e+i,t,n[i]);return t},t.InvertedIndex.prototype.toJSON=function(){return{root:this.root}},t.Configuration=function(e,n){var e=e||"";if(void 0==n||null==n)throw new Error("fields should not be null");this.config={};var i;try{i=JSON.parse(e),this.buildUserConfig(i,n)}catch(o){t.utils.warn("user configuration parse failed, will use default configuration"),this.buildDefaultConfig(n)}},t.Configuration.prototype.buildDefaultConfig=function(e){this.reset(),e.forEach(function(e){this.config[e]={boost:1,bool:"OR",expand:!1}},this)},t.Configuration.prototype.buildUserConfig=function(e,n){var i="OR",o=!1;if(this.reset(),"bool"in e&&(i=e.bool||i),"expand"in e&&(o=e.expand||o),"fields"in e)for(var r in e.fields)if(n.indexOf(r)>-1){var s=e.fields[r],u=o;void 0!=s.expand&&(u=s.expand),this.config[r]={boost:s.boost||0===s.boost?s.boost:1,bool:s.bool||i,expand:u}}else t.utils.warn("field name in user configuration not found in index instance fields");else this.addAllFields2UserConfig(i,o,n)},t.Configuration.prototype.addAllFields2UserConfig=function(e,t,n){n.forEach(function(n){this.config[n]={boost:1,bool:e,expand:t}},this)},t.Configuration.prototype.get=function(){return this.config},t.Configuration.prototype.reset=function(){this.config={}},lunr.SortedSet=function(){this.length=0,this.elements=[]},lunr.SortedSet.load=function(e){var t=new this;return t.elements=e,t.length=e.length,t},lunr.SortedSet.prototype.add=function(){var e,t;for(e=0;e<arguments.length;e++)t=arguments[e],~this.indexOf(t)||this.elements.splice(this.locationFor(t),0,t);this.length=this.elements.length},lunr.SortedSet.prototype.toArray=function(){return this.elements.slice()},lunr.SortedSet.prototype.map=function(e,t){return this.elements.map(e,t)},lunr.SortedSet.prototype.forEach=function(e,t){return this.elements.forEach(e,t)},lunr.SortedSet.prototype.indexOf=function(e){for(var t=0,n=this.elements.length,i=n-t,o=t+Math.floor(i/2),r=this.elements[o];i>1;){if(r===e)return o;e>r&&(t=o),r>e&&(n=o),i=n-t,o=t+Math.floor(i/2),r=this.elements[o]}return r===e?o:-1},lunr.SortedSet.prototype.locationFor=function(e){for(var t=0,n=this.elements.length,i=n-t,o=t+Math.floor(i/2),r=this.elements[o];i>1;)e>r&&(t=o),r>e&&(n=o),i=n-t,o=t+Math.floor(i/2),r=this.elements[o];return r>e?o:e>r?o+1:void 0},lunr.SortedSet.prototype.intersect=function(e){for(var t=new lunr.SortedSet,n=0,i=0,o=this.length,r=e.length,s=this.elements,u=e.elements;;){if(n>o-1||i>r-1)break;s[n]!==u[i]?s[n]<u[i]?n++:s[n]>u[i]&&i++:(t.add(s[n]),n++,i++)}return t},lunr.SortedSet.prototype.clone=function(){var e=new lunr.SortedSet;return e.elements=this.toArray(),e.length=e.elements.length,e},lunr.SortedSet.prototype.union=function(e){var t,n,i;this.length>=e.length?(t=this,n=e):(t=e,n=this),i=t.clone();for(var o=0,r=n.toArray();o<r.length;o++)i.add(r[o]);return i},lunr.SortedSet.prototype.toJSON=function(){return this.toArray()},function(e,t){"function"==typeof define&&define.amd?define(t):"object"==typeof exports?module.exports=t():e.elasticlunr=t()}(this,function(){return t})}(); \ No newline at end of file
diff --git a/template/_includes.html b/template/_includes.html
index d16fa3d..8102a35 100755
--- a/template/_includes.html
+++ b/template/_includes.html
@@ -1,3 +1,4 @@
1<!-- user code --> 1<!-- user code -->
2 2
3<script src="/script.js?v=2022-01-30-01" async></script> 3<script src="/assets/general/elasticlunr.min.js"></script>
4<script src="/script.js?v=2022-07-22-02" async></script>
diff --git a/template/_navigation.html b/template/_navigation.html
index 85290a3..45a2a9e 100755
--- a/template/_navigation.html
+++ b/template/_navigation.html
@@ -13,6 +13,8 @@
13 <a href="/books.html">Books</a> 13 <a href="/books.html">Books</a>
14 14
15 <a href="/feed.rss" itemprop="url">RSS</a> 15 <a href="/feed.rss" itemprop="url">RSS</a>
16
17 <a class="cursor search-trigger">Search</a>
16 </nav> 18 </nav>
17 </header> 19 </header>
18</div> 20</div>
diff --git a/template/_search.html b/template/_search.html
new file mode 100644
index 0000000..997b35c
--- /dev/null
+++ b/template/_search.html
@@ -0,0 +1,6 @@
1<div class="blur hidden"></div>
2
3<section class="search-form hidden">
4 <input type="search" placeholder="Search ...">
5 <ul></ul>
6</section>
diff --git a/template/index.html b/template/index.html
index 8c1cc6e..cb334e1 100755
--- a/template/index.html
+++ b/template/index.html
@@ -55,6 +55,10 @@
55 55
56 {{template "_footer.html"}} 56 {{template "_footer.html"}}
57 57
58 {{template "_includes.html"}}
59
60 {{template "_search.html"}}
61
58 </body> 62 </body>
59 63
60</html> 64</html>
diff --git a/template/post.html b/template/post.html
index 564ed09..cf80b22 100755
--- a/template/post.html
+++ b/template/post.html
@@ -69,6 +69,8 @@
69 69
70 {{template "_includes.html"}} 70 {{template "_includes.html"}}
71 71
72 {{template "_search.html"}}
73
72 {{template "_libraries.html"}} 74 {{template "_libraries.html"}}
73 75
74 </body> 76 </body>
diff --git a/template/script.js b/template/script.js
index 0e1291c..3c58403 100755
--- a/template/script.js
+++ b/template/script.js
@@ -25,79 +25,88 @@ window.addEventListener('load', async () => {
25 }); 25 });
26 } 26 }
27 27
28 // comments code 28 // Search functionality
29 const commentsEndpoint = 'https://mitjafelicijan.com/comments-api'; 29
30 const commentsPlaceholder = document.querySelector('.comments'); 30 window.index = null;
31 31
32 if (commentsPlaceholder) { 32 const response = await fetch('/feed.json');
33 const guid = commentsPlaceholder.dataset.guid; 33 const feed = await response.json();
34 const name = commentsPlaceholder.querySelector('input'); 34
35 const comment = commentsPlaceholder.querySelector('textarea'); 35 window.index = elasticlunr(function () {
36 const submit = commentsPlaceholder.querySelector('button'); 36 this.addField('title');
37 const comments = commentsPlaceholder.querySelector('ul'); 37 this.addField('body');
38 38 this.setRef('id');
39 if (guid) { 39 });
40 await readAndRenderComments(guid, comments); 40
41 41 for (const item of feed.items) {
42 submit.addEventListener('click', async() => { 42 item.id = item.url;
43 submit.disabled = true; 43 window.index.addDoc({
44 await writeComments(guid, name.value, comment.value); 44 id: item.url,
45 45 title: item.title,
46 submit.disabled = false; 46 body: item.content_html,
47 name.value = ''; 47 url: item.url,
48 comment.value = ''; 48 });
49
50 await readAndRenderComments(guid, comments);
51 });
52 }
53 } 49 }
54 50
55 async function writeComments(guid, name, comment) { 51 const blur = document.querySelector('.blur');
56 const response = await fetch(commentsEndpoint, { 52 const searchForm = document.querySelector('.search-form');
57 method: 'POST', 53 const searchResultsList = document.querySelector('.search-form ul');
58 headers: { 54
59 'Accept': 'application/json', 55 function showSearchModal() {
60 'Content-Type': 'application/json' 56 blur.classList.remove('hidden');
61 }, 57 searchForm.classList.remove('hidden');
62 body: JSON.stringify({ 58
63 action: 'write', 59 // Clear search input.
64 guid, 60 searchForm.querySelector('input').value = '';
65 name, 61
66 comment, 62 // We need to clear the list before opening modal.
67 }) 63 searchResultsList.innerHTML = '';
68 }); 64
65 // Focus on search input.
66 searchForm.querySelector('input').focus();
69 } 67 }
70 68
71 async function readAndRenderComments(guid, commentsPlaceholder) { 69 document.querySelector('.search-trigger').addEventListener('click', async (evt) => {
72 const response = await fetch(commentsEndpoint, { 70 showSearchModal();
73 method: 'POST', 71 });
74 headers: { 72
75 'Accept': 'application/json', 73 document.onkeydown = function (e) {
76 'Content-Type': 'application/json' 74 // Show search modal on F key.
77 }, 75 if (blur.classList.contains('hidden')) {
78 body: JSON.stringify({ 76 if (e.key === 'f') {
79 action: 'read', 77 setTimeout(() => {
80 guid, 78 showSearchModal();
81 }) 79 }, 100);
82 }); 80 }
81 }
83 82
84 // remove all existing comments from list 83 // Hide search modal on escape key.
85 commentsPlaceholder.innerHTML = ''; 84 if (!blur.classList.contains('hidden')) {
86 85 if (e.key === 'Escape') {
87 const commentList = await response.json(); 86 blur.classList.add('hidden');
88 for (const comment of commentList.reverse()) { 87 searchForm.classList.add('hidden');
89 const date = new Date(comment.date).toLocaleDateString('en-US', { 88 }
90 year: 'numeric',
91 month: 'long',
92 day: 'numeric',
93 hour: 'numeric',
94 minute: 'numeric'
95 });
96
97 const commentElement = document.createElement('li');
98 commentElement.innerHTML = `<p><b>${comment.name}</b> - ${date}<p><p>${comment.comment}<p><hr>`;
99 commentsPlaceholder.appendChild(commentElement);
100 } 89 }
101 } 90 };
91
92 blur.addEventListener('click', async (evt) => {
93 evt.target.classList.add('hidden');
94 searchForm.classList.add('hidden');
95 });
96
97 document.querySelector('.search-form input').addEventListener('keyup', async (evt) => {
98 // Perform search.
99 const searchResults = window.index.search(evt.target.value);
100
101 // We need to clear the list before adding new results.
102 searchResultsList.innerHTML = '';
103
104 // Loop through the results and add them to the list.
105 for (const result of searchResults.slice(0, 9)) {
106 const listItem = document.createElement('li');
107 listItem.innerHTML = `<a href="${result.doc.url}">${result.doc.title}</a>`;
108 searchResultsList.appendChild(listItem);
109 }
110 });
102 111
103}); 112});
diff --git a/template/style.css b/template/style.css
index af0d7bc..ebb2b26 100755
--- a/template/style.css
+++ b/template/style.css
@@ -29,7 +29,7 @@ body {
29 background: white; 29 background: white;
30 /*font-family: 'Times New Roman', Times, serif;*/ 30 /*font-family: 'Times New Roman', Times, serif;*/
31 /*font-family: 'IBM Plex Sans', sans-serif;*/ 31 /*font-family: 'IBM Plex Sans', sans-serif;*/
32 font-family: "SF Pro Text","SF Pro Icons","Helvetica Neue","Helvetica","Arial",sans-serif; 32 font-family: "SF Pro Text", "SF Pro Icons", "Helvetica Neue", "Helvetica", "Arial", sans-serif;
33 color: var(--base-color); 33 color: var(--base-color);
34 font-size: var(--base-font-size); 34 font-size: var(--base-font-size);
35 line-height: var(--base-line-heigh); 35 line-height: var(--base-line-heigh);
@@ -54,6 +54,10 @@ hr {
54 color: #000; 54 color: #000;
55} 55}
56 56
57.cursor {
58 cursor: pointer;
59}
60
57/* width of the page */ 61/* width of the page */
58 62
59.wrapper { 63.wrapper {
@@ -74,12 +78,35 @@ a:hover {
74 78
75/* headings */ 79/* headings */
76 80
77h1 { font-size: 220%; line-height: 1.2em; } 81h1 {
78h2 { font-size: 180%; line-height: 1.2em; } 82 font-size: 220%;
79h3 { font-size: 160%; line-height: 1.2em; } 83 line-height: 1.2em;
80h4 { font-size: 140%; line-height: 1.2em; } 84}
81h5 { font-size: 120%; line-height: 1.2em; } 85
82h6 { font-size: 100%; line-height: 1.2em; } 86h2 {
87 font-size: 180%;
88 line-height: 1.2em;
89}
90
91h3 {
92 font-size: 160%;
93 line-height: 1.2em;
94}
95
96h4 {
97 font-size: 140%;
98 line-height: 1.2em;
99}
100
101h5 {
102 font-size: 120%;
103 line-height: 1.2em;
104}
105
106h6 {
107 font-size: 100%;
108 line-height: 1.2em;
109}
83 110
84h1[itemtype="headline"] { 111h1[itemtype="headline"] {
85 padding-bottom: 0; 112 padding-bottom: 0;
@@ -95,12 +122,15 @@ table {
95 width: 100%; 122 width: 100%;
96} 123}
97 124
98table, th, td { 125table,
126th,
127td {
99 border: 1px solid black; 128 border: 1px solid black;
100 text-align: left; 129 text-align: left;
101} 130}
102 131
103th, td { 132th,
133td {
104 padding: 5px 10px; 134 padding: 5px 10px;
105} 135}
106 136
@@ -268,7 +298,7 @@ code {
268 font-weight: 500; 298 font-weight: 500;
269} 299}
270 300
271pre > code { 301pre>code {
272 background: unset; 302 background: unset;
273 padding: unset; 303 padding: unset;
274 304
@@ -285,7 +315,8 @@ pre {
285 margin-block-end: 40px; 315 margin-block-end: 40px;
286} 316}
287 317
288img, video { 318img,
319video {
289 max-width: 100%; 320 max-width: 100%;
290 margin: 30px auto; 321 margin: 30px auto;
291 display: block; 322 display: block;
@@ -357,14 +388,14 @@ audio {
357 388
358/* comments */ 389/* comments */
359 390
360.comments input{ 391.comments input {
361 width: 100%; 392 width: 100%;
362 font: var(--comment-form-font); 393 font: var(--comment-form-font);
363 border: 1px solid #bbb; 394 border: 1px solid #bbb;
364 padding: 5px; 395 padding: 5px;
365} 396}
366 397
367.comments textarea{ 398.comments textarea {
368 width: 100%; 399 width: 100%;
369 height: 100px; 400 height: 100px;
370 resize: vertical; 401 resize: vertical;
@@ -384,13 +415,69 @@ audio {
384 border-top: initial !important; 415 border-top: initial !important;
385} 416}
386 417
418/* search form */
419
420.search-form {
421 position: fixed;
422 top: 120px;
423 left: 50%;
424 margin-left: -250px;
425 width: 500px;
426 padding: 30px;
427 background: #eee;
428 border-radius: 5px;
429}
430
431.blur {
432 position: fixed;
433 top: 0;
434 left: 0;
435 right: 0;
436 bottom: 0;
437 backdrop-filter: blur(15px);
438}
439
440.hidden {
441 display: none;
442}
443
444.search-form input {
445 width: 100%;
446 margin-bottom: 20px;
447 border: 1px solid #ffffff;
448 padding: 5px 10px;
449 border-radius: 3px;
450 outline: none;
451}
452
453.search-form ul {
454 list-style-type: none;
455 padding: 0;
456 margin: 0;
457}
458
459.search-form ul li {
460 margin-bottom: 5px;
461}
462
387/* responsive */ 463/* responsive */
388 464
389@media only screen and (max-width: 960px) { 465@media only screen and (max-width: 960px) {
390 main { padding: 0 20px; } 466 main {
391 footer { padding: 0 20px; } 467 padding: 0 20px;
392 h1[itemtype="headline"] { font-size: 220%; } 468 }
393 .navigation header { padding: 0 20px; } 469
470 footer {
471 padding: 0 20px;
472 }
473
474 h1[itemtype="headline"] {
475 font-size: 220%;
476 }
477
478 .navigation header {
479 padding: 0 20px;
480 }
394 481
395 article img { 482 article img {
396 max-width: 100%; 483 max-width: 100%;
@@ -400,10 +487,26 @@ audio {
400} 487}
401 488
402@media only screen and (max-width: 600px) { 489@media only screen and (max-width: 600px) {
403 .navigation header { display: block; } 490 .navigation header {
404 .navigation header h3 { text-align: center; margin-bottom: 10px; } 491 display: block;
405 .navigation header nav { text-align: center; } 492 }
406 .post-list li a h2 { font-weight: 500; } 493
494 .navigation header h3 {
495 text-align: center;
496 margin-bottom: 10px;
497 }
498
499 .navigation header nav {
500 text-align: center;
501 }
502
503 .post-list li a h2 {
504 font-weight: 500;
505 }
506
507 .search-trigger {
508 display: none;
509 }
407} 510}
408 511
409/* light/dark mode */ 512/* light/dark mode */