aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--assets/iosevka-aile-regular.woffbin0 -> 11672 bytes
-rw-r--r--assets/iosevka-aile-regular.woff2bin0 -> 9516 bytes
-rw-r--r--assets/main.js2
-rw-r--r--assets/style.css2
-rw-r--r--css/main.scss9
-rw-r--r--fonts/iosevka-aile-regular.ttfbin0 -> 497504 bytes
-rw-r--r--gopherproxy.go26
-rw-r--r--js/main.ts32
-rw-r--r--template.go13
10 files changed, 77 insertions, 9 deletions
diff --git a/Makefile b/Makefile
index feebcfd..1d65cf0 100644
--- a/Makefile
+++ b/Makefile
@@ -10,6 +10,8 @@ build: clean
10 tsc --strict --module none --outFile /dev/stdout js/* | terser --compress --mangle -o assets/main.js -- 10 tsc --strict --module none --outFile /dev/stdout js/* | terser --compress --mangle -o assets/main.js --
11 pyftsubset fonts/iosevka-term-ss03-regular.ttf --name-IDs+=0,4,6 --text-file=fonts/glyphs.txt --flavor='woff' --with-zopfli --output-file='assets/iosevka-term-ss03-regular.woff' 11 pyftsubset fonts/iosevka-term-ss03-regular.ttf --name-IDs+=0,4,6 --text-file=fonts/glyphs.txt --flavor='woff' --with-zopfli --output-file='assets/iosevka-term-ss03-regular.woff'
12 pyftsubset fonts/iosevka-term-ss03-regular.ttf --name-IDs+=0,4,6 --text-file=fonts/glyphs.txt --flavor='woff2' --output-file='assets/iosevka-term-ss03-regular.woff2' 12 pyftsubset fonts/iosevka-term-ss03-regular.ttf --name-IDs+=0,4,6 --text-file=fonts/glyphs.txt --flavor='woff2' --output-file='assets/iosevka-term-ss03-regular.woff2'
13 pyftsubset fonts/iosevka-aile-regular.ttf --name-IDs+=0,4,6 --text-file=fonts/glyphs.txt --flavor='woff' --with-zopfli --output-file='assets/iosevka-aile-regular.woff'
14 pyftsubset fonts/iosevka-aile-regular.ttf --name-IDs+=0,4,6 --text-file=fonts/glyphs.txt --flavor='woff2' --output-file='assets/iosevka-aile-regular.woff2'
13 go build -o ./gopherproxy ./cmd/gopherproxy/main.go 15 go build -o ./gopherproxy ./cmd/gopherproxy/main.go
14 16
15profile: 17profile:
diff --git a/assets/iosevka-aile-regular.woff b/assets/iosevka-aile-regular.woff
new file mode 100644
index 0000000..fa16c36
--- /dev/null
+++ b/assets/iosevka-aile-regular.woff
Binary files differ
diff --git a/assets/iosevka-aile-regular.woff2 b/assets/iosevka-aile-regular.woff2
new file mode 100644
index 0000000..fa3b36c
--- /dev/null
+++ b/assets/iosevka-aile-regular.woff2
Binary files differ
diff --git a/assets/main.js b/assets/main.js
index a30a250..be36478 100644
--- a/assets/main.js
+++ b/assets/main.js
@@ -1 +1 @@
"use strict";var KeyValueStore=function(){function e(e){this.data=e;for(var t=0,n=Object.keys(e);t<n.length;t++){var a=n[t],l=e[a];if(l.valueRange&&-1===l.valueRange.indexOf(l.value))throw new Error('Invalid value "'+l.value+'" for ID "'+a+'"')}}return e.prototype.getValue=function(e){return this.data[e].value},e.prototype.setValue=function(e,t){var n=this.data[e];if(n.valueRange&&-1===n.valueRange.indexOf(t))throw new Error('Invalid value "'+t+'" for ID "'+e+'"');n.value=t,n.callbacks&&n.callbacks.forEach((function(e){e(t)}))},e.prototype.cycleValue=function(e,t){void 0===t&&(t=1);var n=this.data[e];if(!n)throw new Error('Invalid ID "'+e+'"');var a=n.value;if(n.valueRange){var l=n.valueRange.indexOf(a)+t;l>=n.valueRange.length?l=0:l<0&&(l=n.valueRange.length-1),a=n.value=n.valueRange[l]}else{if("number"!=typeof a)throw new Error("Can't cycle \""+e+'"');a+=t,n.value=a}return n.callbacks&&n.callbacks.forEach((function(e){e(a)})),a},e.prototype.addCallback=function(e,t){var n=this.data[e];n.callbacks||(n.callbacks=[]),n.callbacks.push(t)},e}();function ensureSetting(e,t){var n=localStorage.getItem(e);return null===n&&(n=t,localStorage.setItem(e,n)),n}var settings=new KeyValueStore({wordWrap:{value:"1"===ensureSetting("word-wrap","1"),callbacks:[function(e){localStorage.setItem("word-wrap",e?"1":"0")}],valueRange:[!1,!0]},imagePreviews:{value:"1"===ensureSetting("image-previews","1"),callbacks:[function(e){localStorage.setItem("image-previews",e?"1":"0")}],valueRange:[!1,!0]},clickablePlainLinks:{value:"1"===ensureSetting("clickable-plain-links","1"),callbacks:[function(e){localStorage.setItem("clickable-plain-links",e?"1":"0")}],valueRange:[!1,!0]}});function generateImageThumbnails(){for(var e=document.querySelectorAll(".link--IMG, .link--GIF"),t=e.length,n=function(){var n=e[t],a=n.href.replace(/^(.*?)\/I/,"$1/T"),l=document.createTextNode("\n"),i=document.createElement("span");i.classList.add("type-annotation"),i.textContent=" -> ";var r=document.createElement("img");r.src=a,r.addEventListener("load",(function(e){r.classList.remove("faded")}));var s=document.createElement("a");s.classList.add("img-preview"),s.href=n.href,s.addEventListener("click",(function(e){return e.preventDefault(),r.classList.add("faded"),r.classList.contains("expanded")?(r.classList.remove("expanded"),r.src=a):(r.classList.add("expanded"),r.src=s.href),!1})),s.append(r),n.parentNode.insertBefore(s,n.nextSibling),n.parentNode.insertBefore(i,s),n.parentNode.insertBefore(l,i)};t--;)n()}function removeImageThumbnails(){for(var e=document.querySelectorAll(".link--IMG, .link--GIF"),t=e.length;t--;)for(var n=e[t],a=3;a--&&n.nextSibling;)n.nextSibling.remove()}function generateMarkupForPlainLinks(){if(document.body.classList.contains("is-plain")){var e=document.getElementsByClassName("content")[0];e.innerHTML=e.innerHTML.replace(/\b[a-z]*:\/\/[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,}\b[-a-zA-Z0-9@:%_\+.~#?&//=]*/g,(function(e){var t=e;return 0===t.indexOf("gopher://")&&(t=t.replace(/^gopher:\/\/(.*)$/,location.origin+"/$1")),'<a href="'+t+'">'+e+"</a>"})),e.innerHTML=e.innerHTML.replace(/\bmailto:[-a-zA-Z0-9@:%._\+~#=]+@(?:[-a-zA-Z0-9@:%._\+~#=]+\.)+[a-z]{2,}\b/g,(function(e){return'<a href="'+e+'">'+e+"</a>"}))}}function removeMarkupForPlainLinks(){if(document.body.classList.contains("is-plain"))for(var e=document.getElementsByClassName("content")[0],t=e.getElementsByTagName("a"),n=t.length;n--;){var a=t[n],l=document.createTextNode(a.textContent);e.replaceChild(l,a)}}!function(){for(var e=document.getElementsByClassName("link--QRY"),t=e.length;t--;)e[t].addEventListener("click",(function(e){e.preventDefault();var t=prompt("Please enter required input: ","");return null!==t&&""!==t&&(window.location.href=e.target.href+"?"+t),!1}))}(),function(){for(var e=document.getElementsByClassName("location__prefix"),t=e.length;t--;)e[t].addEventListener("click",(function(e){e.preventDefault();var t=prompt("Please enter new location: ","");return null!==t&&""!==t.trim()&&(0===(t=t.trim()).indexOf("gopher://")&&(t=t.substring(9)),window.location.href=window.location.origin+"/"+t),!1}))}(),function(){var e=document.getElementsByClassName("content")[0],t=document.getElementsByClassName("setting--image-previews")[0].getElementsByClassName("setting__value")[0],n=function(e,n){void 0===n&&(n=!1),e?generateImageThumbnails():n||removeImageThumbnails(),t.textContent=e?"[yes]":"[no]"};t.addEventListener("click",(function(e){return e.preventDefault(),settings.cycleValue("imagePreviews"),!1})),n(settings.getValue("imagePreviews"),!0),settings.addCallback("imagePreviews",n);var a=document.getElementsByClassName("setting--word-wrap")[0].getElementsByClassName("setting__value")[0],l=function(t){t?e.classList.add("content--wrap"):e.classList.remove("content--wrap"),a.textContent=t?"[yes]":"[no]"};a.addEventListener("click",(function(e){return e.preventDefault(),settings.cycleValue("wordWrap"),!1})),l(settings.getValue("wordWrap")),settings.addCallback("wordWrap",l);var i=document.getElementsByClassName("setting--clickable-plain-links")[0].getElementsByClassName("setting__value")[0],r=function(e){e?generateMarkupForPlainLinks():removeMarkupForPlainLinks(),i.textContent=e?"[yes]":"[no]"};i.addEventListener("click",(function(e){return e.preventDefault(),settings.cycleValue("clickablePlainLinks"),!1})),r(settings.getValue("clickablePlainLinks")),settings.addCallback("clickablePlainLinks",r)}(),function(){for(var e=document.getElementsByClassName("modal"),t=e.length,n=function(){var n=e[t],a=n.getElementsByClassName("modal__content")[0],l=n.getElementsByClassName("modal__close-btn")[0];document.addEventListener("click",(function(e){n.classList.contains("modal--visible")&&(e.target===a||a.contains(e.target)||(n.classList.remove("modal--visible"),e.preventDefault(),e.stopPropagation()))}),!0),document.addEventListener("keydown",(function(e){n.classList.contains("modal--visible")&&27===e.keyCode&&n.classList.remove("modal--visible")})),l.addEventListener("click",(function(e){return e.preventDefault(),n.classList.remove("modal--visible"),!1}))};t--;)n();var a=document.getElementsByClassName("settings-btn")[0],l=document.getElementsByClassName("modal--settings")[0];a.addEventListener("click",(function(e){return e.preventDefault(),l.classList.add("modal--visible"),!1}))}(); \ No newline at end of file "use strict";var KeyValueStore=function(){function e(e){this.data=e;for(var t=0,n=Object.keys(e);t<n.length;t++){var a=n[t],l=e[a];if(l.valueRange&&-1===l.valueRange.indexOf(l.value))throw new Error('Invalid value "'+l.value+'" for ID "'+a+'"')}}return e.prototype.getValue=function(e){return this.data[e].value},e.prototype.setValue=function(e,t){var n=this.data[e];if(n.valueRange&&-1===n.valueRange.indexOf(t))throw new Error('Invalid value "'+t+'" for ID "'+e+'"');n.value=t,n.callbacks&&n.callbacks.forEach((function(e){e(t)}))},e.prototype.cycleValue=function(e,t){void 0===t&&(t=1);var n=this.data[e];if(!n)throw new Error('Invalid ID "'+e+'"');var a=n.value;if(n.valueRange){var l=n.valueRange.indexOf(a)+t;l>=n.valueRange.length?l=0:l<0&&(l=n.valueRange.length-1),a=n.value=n.valueRange[l]}else{if("number"!=typeof a)throw new Error("Can't cycle \""+e+'"');a+=t,n.value=a}return n.callbacks&&n.callbacks.forEach((function(e){e(a)})),a},e.prototype.addCallback=function(e,t){var n=this.data[e];n.callbacks||(n.callbacks=[]),n.callbacks.push(t)},e}();function ensureSetting(e,t){var n=localStorage.getItem(e);return null===n&&(n=t,localStorage.setItem(e,n)),n}var settings=new KeyValueStore({wordWrap:{value:"1"===ensureSetting("word-wrap","1"),callbacks:[function(e){localStorage.setItem("word-wrap",e?"1":"0")}],valueRange:[!1,!0]},monospaceFont:{value:"1"===ensureSetting("monospace-font","1"),callbacks:[function(e){localStorage.setItem("monospace-font",e?"1":"0")}],valueRange:[!1,!0]},imagePreviews:{value:"1"===ensureSetting("image-previews","1"),callbacks:[function(e){localStorage.setItem("image-previews",e?"1":"0")}],valueRange:[!1,!0]},clickablePlainLinks:{value:"1"===ensureSetting("clickable-plain-links","1"),callbacks:[function(e){localStorage.setItem("clickable-plain-links",e?"1":"0")}],valueRange:[!1,!0]}});function generateImageThumbnails(){for(var e=document.querySelectorAll(".link--IMG, .link--GIF"),t=e.length,n=function(){var n=e[t],a=n.href.replace(/^(.*?)\/I/,"$1/T"),l=document.createTextNode("\n"),s=document.createElement("span");s.classList.add("type-annotation"),s.textContent=" -> ";var i=document.createElement("img");i.src=a,i.addEventListener("load",(function(e){i.classList.remove("faded")}));var o=document.createElement("a");o.classList.add("img-preview"),o.href=n.href,o.addEventListener("click",(function(e){return e.preventDefault(),i.classList.add("faded"),i.classList.contains("expanded")?(i.classList.remove("expanded"),i.src=a):(i.classList.add("expanded"),i.src=o.href),!1})),o.append(i),n.parentNode.insertBefore(o,n.nextSibling),n.parentNode.insertBefore(s,o),n.parentNode.insertBefore(l,s)};t--;)n()}function removeImageThumbnails(){for(var e=document.querySelectorAll(".link--IMG, .link--GIF"),t=e.length;t--;)for(var n=e[t],a=3;a--&&n.nextSibling;)n.nextSibling.remove()}function generateMarkupForPlainLinks(){if(document.body.classList.contains("is-plain")){var e=document.getElementsByClassName("content")[0];e.innerHTML=e.innerHTML.replace(/\b[a-z]*:\/\/[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,}\b[-a-zA-Z0-9@:%_\+.~#?&//=]*/g,(function(e){var t=e;return 0===t.indexOf("gopher://")&&(t=t.replace(/^gopher:\/\/(.*)$/,location.origin+"/$1")),'<a href="'+t+'">'+e+"</a>"})),e.innerHTML=e.innerHTML.replace(/\bmailto:[-a-zA-Z0-9@:%._\+~#=]+@(?:[-a-zA-Z0-9@:%._\+~#=]+\.)+[a-z]{2,}\b/g,(function(e){return'<a href="'+e+'">'+e+"</a>"}))}}function removeMarkupForPlainLinks(){if(document.body.classList.contains("is-plain"))for(var e=document.getElementsByClassName("content")[0],t=e.getElementsByTagName("a"),n=t.length;n--;){var a=t[n],l=document.createTextNode(a.textContent);e.replaceChild(l,a)}}!function(){for(var e=document.getElementsByClassName("link--QRY"),t=e.length;t--;)e[t].addEventListener("click",(function(e){e.preventDefault();var t=prompt("Please enter required input: ","");return null!==t&&""!==t&&(window.location.href=e.target.href+"?"+t),!1}))}(),function(){for(var e=document.getElementsByClassName("location__prefix"),t=e.length;t--;)e[t].addEventListener("click",(function(e){e.preventDefault();var t=prompt("Please enter new location: ","");return null!==t&&""!==t.trim()&&(0===(t=t.trim()).indexOf("gopher://")&&(t=t.substring(9)),window.location.href=window.location.origin+"/"+t),!1}))}(),function(){var e=document.getElementsByClassName("content")[0],t=document.getElementsByClassName("setting--image-previews")[0].getElementsByClassName("setting__value")[0],n=function(e,n){void 0===n&&(n=!1),e?generateImageThumbnails():n||removeImageThumbnails(),t.textContent=e?"[yes]":"[no]"};t.addEventListener("click",(function(e){return e.preventDefault(),settings.cycleValue("imagePreviews"),!1})),n(settings.getValue("imagePreviews"),!0),settings.addCallback("imagePreviews",n);var a=document.getElementsByClassName("setting--monospace-font")[0].getElementsByClassName("setting__value")[0],l=function(t){t?e.classList.add("content--has-monospace-font"):e.classList.remove("content--has-monospace-font"),a.textContent=t?"[yes]":"[no]"};a.addEventListener("click",(function(e){return e.preventDefault(),settings.cycleValue("monospaceFont"),!1})),l(settings.getValue("monospaceFont")),settings.addCallback("monospaceFont",l);var s=document.getElementsByClassName("setting--word-wrap")[0].getElementsByClassName("setting__value")[0],i=function(t){t?e.classList.add("content--wrap"):e.classList.remove("content--wrap"),s.textContent=t?"[yes]":"[no]"};s.addEventListener("click",(function(e){return e.preventDefault(),settings.cycleValue("wordWrap"),!1})),i(settings.getValue("wordWrap")),settings.addCallback("wordWrap",i);var o=document.getElementsByClassName("setting--clickable-plain-links")[0].getElementsByClassName("setting__value")[0],r=function(e){e?generateMarkupForPlainLinks():removeMarkupForPlainLinks(),o.textContent=e?"[yes]":"[no]"};o.addEventListener("click",(function(e){return e.preventDefault(),settings.cycleValue("clickablePlainLinks"),!1})),r(settings.getValue("clickablePlainLinks")),settings.addCallback("clickablePlainLinks",r)}(),function(){for(var e=document.getElementsByClassName("modal"),t=e.length,n=function(){var n=e[t],a=n.getElementsByClassName("modal__content")[0],l=n.getElementsByClassName("modal__close-btn")[0];document.addEventListener("click",(function(e){n.classList.contains("modal--visible")&&(e.target===a||a.contains(e.target)||(n.classList.remove("modal--visible"),e.preventDefault(),e.stopPropagation()))}),!0),document.addEventListener("keydown",(function(e){n.classList.contains("modal--visible")&&27===e.keyCode&&n.classList.remove("modal--visible")})),l.addEventListener("click",(function(e){return e.preventDefault(),n.classList.remove("modal--visible"),!1}))};t--;)n();var a=document.getElementsByClassName("settings-btn")[0],l=document.getElementsByClassName("modal--settings")[0];a.addEventListener("click",(function(e){return e.preventDefault(),l.classList.add("modal--visible"),!1}))}(); \ No newline at end of file
diff --git a/assets/style.css b/assets/style.css
index 1ad0b19..28efa0b 100644
--- a/assets/style.css
+++ b/assets/style.css
@@ -1 +1 @@
body{margin:0;padding:0;background-color:#14171a;color:#cad1d8;font-family:"Iosevka Term SS03","IBM Plex Mono","Fira Code","Fira Mono","Roboto Mono","Droid Sans Mono",Monaco,Consolas,Courier,monospace;font-size:1.0625em;line-height:1.5}h1,h2,h3,h4,h5,h6{font:inherit;color:#fff;margin:0}button{background:none;border:0;padding:0;color:#fff;font:inherit;text-decoration:underline;cursor:pointer}button:focus{outline:1px dotted currentColor}img{display:inline-block;vertical-align:top;max-width:8em;margin:.1em 0}img::selection{background-color:rgba(239,198,138,0.35)}img.expanded{max-width:40em;max-width:80ch}img.faded{opacity:.5}strong{font-weight:normal}::selection{color:#000;background-color:rgba(239,198,138,0.996)}:link{color:#fff}:visited{color:#cad1d8}:link:hover,:visited:hover{color:#fff}.header-base{display:flex;flex-direction:row;align-items:center;justify-content:space-between;border-bottom:1px solid #353a3f}.header{padding:.9em 1em;color:#929ba3}.location{flex:0 1 auto;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;text-overflow:ellipsis '|';margin-right:.5em}.location__prefix{margin-right:.3em;color:#929ba3}@media (hover: hover){.location__prefix:hover{color:#fff}}.location__prefix--mobile{display:none}.location__slash{margin:0 .3em}.location__uripart{color:#fff}.location__uripart+.location__slash+.location__uripart{color:#cad1d8}.location__uripart:link:hover,.location__uripart:visited:hover{color:#fff}.actions{flex:0 0 auto}.actions :visited{color:#fff}.action{display:inline}.action+.action::before{content:' | '}.wrap{padding:2em 1em;text-align:center}.content{box-sizing:border-box;display:inline-block;min-width:0;max-width:100%;margin:0;padding:0;text-align:left;font:inherit}.content--wrap{white-space:pre-wrap;word-wrap:break-word}.content--has-type-annotations{padding-left:3em;padding-left:5ch}.type-annotation{margin-left:-3em;margin-left:-5ch;color:#929ba3;white-space:pre}.modal{position:fixed;top:0;left:0;z-index:100;display:none;width:100%;height:100%;box-sizing:border-box;padding:2em;background-color:rgba(0,0,0,0.75)}.modal--visible{display:block}.modal__content{max-width:30em;padding:1.5em 1.8em;margin:0 auto;background-color:#14171a;box-shadow:0 .3em 2em #000;text-align:left}.modal__head{padding-bottom:.75em;margin-bottom:1.5em}.modal__title{padding-right:1em;white-space:nowrap;text-overflow:ellipsis;overflow:hidden;text-transform:uppercase}.setting{display:flex;flex-direction:row;align-items:baseline;justify-content:space-between}.setting::after{order:2;flex:1 1 auto;display:block;height:0;margin:0 .5em;border-bottom:2px dotted #353a3f;content:''}.setting__label{order:1}.setting__value{order:3}@media screen and (max-width: 800px){body{font-size:1em}.modal{padding:1em}.modal__content{padding:1em 1.3em}}@media screen and (max-width: 500px){.location__prefix{display:none}.location__prefix--mobile{display:inline}.action{display:block}.action+.action::before{content:''}}@media screen and (max-width: 280px){.location__prefix--mobile{display:none}} body{margin:0;padding:0;background-color:#14171a;color:#cad1d8;font-family:"Iosevka Term SS03","IBM Plex Mono","Fira Code","Fira Mono","Roboto Mono","Droid Sans Mono",Monaco,Consolas,Courier,monospace;font-size:1.0625em;line-height:1.5}h1,h2,h3,h4,h5,h6{font:inherit;color:#fff;margin:0}button{background:none;border:0;padding:0;color:#fff;font:inherit;text-decoration:underline;cursor:pointer}button:focus{outline:1px dotted currentColor}img{display:inline-block;vertical-align:top;max-width:8em;margin:.1em 0}img::selection{background-color:rgba(239,198,138,0.35)}img.expanded{max-width:40em;max-width:80ch}img.faded{opacity:.5}strong{font-weight:normal}::selection{color:#000;background-color:rgba(239,198,138,0.996)}:link{color:#fff}:visited{color:#cad1d8}:link:hover,:visited:hover{color:#fff}.header-base{display:flex;flex-direction:row;align-items:center;justify-content:space-between;border-bottom:1px solid #353a3f}.header{padding:.9em 1em;color:#929ba3}.location{flex:0 1 auto;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;text-overflow:ellipsis '|';margin-right:.5em}.location__prefix{margin-right:.3em;color:#929ba3}@media (hover: hover){.location__prefix:hover{color:#fff}}.location__prefix--mobile{display:none}.location__slash{margin:0 .3em}.location__uripart{color:#fff}.location__uripart+.location__slash+.location__uripart{color:#cad1d8}.location__uripart:link:hover,.location__uripart:visited:hover{color:#fff}.actions{flex:0 0 auto}.actions :visited{color:#fff}.action{display:inline}.action+.action::before{content:' | '}.wrap{padding:2em 1em;text-align:center}.content{box-sizing:border-box;display:inline-block;min-width:0;max-width:100%;margin:0;padding:0;text-align:left;font:inherit;font-family:"Iosevka Aile","Fira Sans","Roboto","Droid Sans",sans-serif}.content--wrap{white-space:pre-wrap;word-wrap:break-word}.content--has-type-annotations{padding-left:3em;padding-left:5ch}.content--has-monospace-font{font-family:"Iosevka Term SS03","IBM Plex Mono","Fira Code","Fira Mono","Roboto Mono","Droid Sans Mono",Monaco,Consolas,Courier,monospace}.type-annotation{margin-left:-3em;margin-left:-5ch;color:#929ba3;white-space:pre;font-family:"Iosevka Term SS03","IBM Plex Mono","Fira Code","Fira Mono","Roboto Mono","Droid Sans Mono",Monaco,Consolas,Courier,monospace}.modal{position:fixed;top:0;left:0;z-index:100;display:none;width:100%;height:100%;box-sizing:border-box;padding:2em;background-color:rgba(0,0,0,0.75)}.modal--visible{display:block}.modal__content{max-width:30em;padding:1.5em 1.8em;margin:0 auto;background-color:#14171a;box-shadow:0 .3em 2em #000;text-align:left}.modal__head{padding-bottom:.75em;margin-bottom:1.5em}.modal__title{padding-right:1em;white-space:nowrap;text-overflow:ellipsis;overflow:hidden;text-transform:uppercase}.setting{display:flex;flex-direction:row;align-items:baseline;justify-content:space-between}.setting::after{order:2;flex:1 1 auto;display:block;height:0;margin:0 .5em;border-bottom:2px dotted #353a3f;content:''}.setting__label{order:1}.setting__value{order:3}@media screen and (max-width: 800px){body{font-size:1em}.modal{padding:1em}.modal__content{padding:1em 1.3em}}@media screen and (max-width: 500px){.location__prefix{display:none}.location__prefix--mobile{display:inline}.action{display:block}.action+.action::before{content:''}}@media screen and (max-width: 280px){.location__prefix--mobile{display:none}}
diff --git a/css/main.scss b/css/main.scss
index a6b1ee9..4cf5285 100644
--- a/css/main.scss
+++ b/css/main.scss
@@ -10,7 +10,8 @@ $border: mix(hsl(210, 100%, 95%), $background, 16%);
10$sel-background: rgba($accent, .996); 10$sel-background: rgba($accent, .996);
11$sel-text: #000; 11$sel-text: #000;
12 12
13$font-monospace: 'Iosevka Term SS03', 'IBM Plex Mono', 'Fira Code', 'Fira Mono', 'Roboto Mono', 'Droid Sans Mono', Monaco, Consolas, Courier, monospace; 13$font-monospace: 'Iosevka Term SS03', 'IBM Plex Mono', 'Fira Code', 'Fira Mono', 'Roboto Mono', 'Droid Sans Mono', Monaco, Consolas, Courier, monospace;
14$font-proportional: 'Iosevka Aile', 'Fira Sans', 'Roboto', 'Droid Sans', sans-serif;
14 15
15// 16//
16// Basic element styles 17// Basic element styles
@@ -198,6 +199,7 @@ strong {
198 padding: 0; 199 padding: 0;
199 text-align: left; 200 text-align: left;
200 font: inherit; 201 font: inherit;
202 font-family: $font-proportional;
201 203
202 &--wrap { 204 &--wrap {
203 white-space: pre-wrap; 205 white-space: pre-wrap;
@@ -208,6 +210,10 @@ strong {
208 padding-left: 3em; 210 padding-left: 3em;
209 padding-left: 5ch; 211 padding-left: 5ch;
210 } 212 }
213
214 &--has-monospace-font {
215 font-family: $font-monospace;
216 }
211} 217}
212 218
213.type-annotation { 219.type-annotation {
@@ -215,6 +221,7 @@ strong {
215 margin-left: -5ch; 221 margin-left: -5ch;
216 color: $text-minus; 222 color: $text-minus;
217 white-space: pre; 223 white-space: pre;
224 font-family: $font-monospace;
218} 225}
219 226
220// 227//
diff --git a/fonts/iosevka-aile-regular.ttf b/fonts/iosevka-aile-regular.ttf
new file mode 100644
index 0000000..7cad586
--- /dev/null
+++ b/fonts/iosevka-aile-regular.ttf
Binary files differ
diff --git a/gopherproxy.go b/gopherproxy.go
index d98ef7c..34e6ff8 100644
--- a/gopherproxy.go
+++ b/gopherproxy.go
@@ -30,10 +30,12 @@ type Item struct {
30} 30}
31 31
32type AssetList struct { 32type AssetList struct {
33 Style string 33 Style string
34 JS string 34 JS string
35 FontW string 35 FontW string
36 FontW2 string 36 FontW2 string
37 PropFontW string
38 PropFontW2 string
37} 39}
38 40
39func renderDirectory(w http.ResponseWriter, tpl *template.Template, assetList AssetList, uri string, hostport string, d gopher.Directory) error { 41func renderDirectory(w http.ResponseWriter, tpl *template.Template, assetList AssetList, uri string, hostport string, d gopher.Directory) error {
@@ -299,6 +301,18 @@ func ListenAndServe(bind, robotsfile string, robotsdebug bool, vipsconcurrency i
299 } 301 }
300 fontw2Asset := fmt.Sprintf("/iosevka-term-ss03-regular-%x.woff2", md5.Sum(fontdataw2)) 302 fontw2Asset := fmt.Sprintf("/iosevka-term-ss03-regular-%x.woff2", md5.Sum(fontdataw2))
301 303
304 propfontdataw, err := box.Find("iosevka-aile-regular.woff")
305 if err != nil {
306 propfontdataw = []byte{}
307 }
308 propfontwAsset := fmt.Sprintf("/iosevka-aile-regular-%x.woff", md5.Sum(propfontdataw))
309
310 propfontdataw2, err := box.Find("iosevka-aile-regular.woff2")
311 if err != nil {
312 propfontdataw2 = []byte{}
313 }
314 propfontw2Asset := fmt.Sprintf("/iosevka-aile-regular-%x.woff2", md5.Sum(propfontdataw2))
315
302 styledata, err := box.Find("style.css") 316 styledata, err := box.Find("style.css")
303 if err != nil { 317 if err != nil {
304 styledata = []byte{} 318 styledata = []byte{}
@@ -368,13 +382,15 @@ func ListenAndServe(bind, robotsfile string, robotsdebug bool, vipsconcurrency i
368 ConcurrencyLevel: vipsconcurrency, 382 ConcurrencyLevel: vipsconcurrency,
369 }) 383 })
370 384
371 http.HandleFunc("/", GopherHandler(tpl, robotsdata, AssetList{styleAsset, jsAsset, fontwAsset, fontw2Asset}, robotsdebug, uri)) 385 http.HandleFunc("/", GopherHandler(tpl, robotsdata, AssetList{styleAsset, jsAsset, fontwAsset, fontw2Asset, propfontwAsset, propfontw2Asset}, robotsdebug, uri))
372 http.HandleFunc("/robots.txt", RobotsTxtHandler(robotstxtdata)) 386 http.HandleFunc("/robots.txt", RobotsTxtHandler(robotstxtdata))
373 http.HandleFunc("/favicon.ico", FaviconHandler(favicondata)) 387 http.HandleFunc("/favicon.ico", FaviconHandler(favicondata))
374 http.HandleFunc(styleAsset, StyleHandler(styledata)) 388 http.HandleFunc(styleAsset, StyleHandler(styledata))
375 http.HandleFunc(jsAsset, JavaScriptHandler(jsdata)) 389 http.HandleFunc(jsAsset, JavaScriptHandler(jsdata))
376 http.HandleFunc(fontwAsset, FontHandler(false, fontdataw)) 390 http.HandleFunc(fontwAsset, FontHandler(false, fontdataw))
377 http.HandleFunc(fontw2Asset, FontHandler(true, fontdataw2)) 391 http.HandleFunc(fontw2Asset, FontHandler(true, fontdataw2))
392 http.HandleFunc(propfontwAsset, FontHandler(false, propfontdataw))
393 http.HandleFunc(propfontw2Asset, FontHandler(true, propfontdataw2))
378 //http.Handle("/assets/", http.StripPrefix("/assets/", http.FileServer(http.Dir("assets/")))) 394 //http.Handle("/assets/", http.StripPrefix("/assets/", http.FileServer(http.Dir("assets/"))))
379 395
380 return http.ListenAndServe(bind, nil) 396 return http.ListenAndServe(bind, nil)
diff --git a/js/main.ts b/js/main.ts
index 32c5a5b..29b4a68 100644
--- a/js/main.ts
+++ b/js/main.ts
@@ -21,6 +21,15 @@ const settings = new KeyValueStore({
21 ], 21 ],
22 valueRange: [false, true] 22 valueRange: [false, true]
23 }, 23 },
24 monospaceFont: {
25 value: ensureSetting('monospace-font', '1') === '1',
26 callbacks: [
27 value => {
28 localStorage.setItem('monospace-font', value ? '1' : '0');
29 }
30 ],
31 valueRange: [false, true]
32 },
24 imagePreviews: { 33 imagePreviews: {
25 value: ensureSetting('image-previews', '1') === '1', 34 value: ensureSetting('image-previews', '1') === '1',
26 callbacks: [ 35 callbacks: [
@@ -110,6 +119,29 @@ const settings = new KeyValueStore({
110 119
111 // 120 //
112 121
122 const settingMonospaceFontEl = document.getElementsByClassName('setting--monospace-font')[0];
123 const settingMonospaceFontValueEl = settingMonospaceFontEl.getElementsByClassName('setting__value')[0];
124 const settingMonospaceFontCallback = (value: boolean) => {
125 if (value) {
126 contentEl.classList.add("content--has-monospace-font");
127 } else {
128 contentEl.classList.remove("content--has-monospace-font");
129 }
130
131 settingMonospaceFontValueEl.textContent = value ? '[yes]' : '[no]';
132 }
133
134 settingMonospaceFontValueEl.addEventListener('click', e => {
135 e.preventDefault();
136 settings.cycleValue('monospaceFont');
137 return false;
138 });
139
140 settingMonospaceFontCallback(settings.getValue('monospaceFont'));
141 settings.addCallback('monospaceFont', settingMonospaceFontCallback);
142
143 //
144
113 const settingWordWrapEl = document.getElementsByClassName('setting--word-wrap')[0]; 145 const settingWordWrapEl = document.getElementsByClassName('setting--word-wrap')[0];
114 const settingWordWrapValueEl = settingWordWrapEl.getElementsByClassName('setting__value')[0]; 146 const settingWordWrapValueEl = settingWordWrapEl.getElementsByClassName('setting__value')[0];
115 const settingWordWrapCallback = (value: boolean) => { 147 const settingWordWrapCallback = (value: boolean) => {
diff --git a/template.go b/template.go
index 7aee61a..54aa53a 100644
--- a/template.go
+++ b/template.go
@@ -15,6 +15,13 @@ var tpltext = `<!doctype html>
15 src: url('{{ .Assets.FontW2 }}') format('woff2'), 15 src: url('{{ .Assets.FontW2 }}') format('woff2'),
16 url('{{ .Assets.FontW }}') format('woff'); 16 url('{{ .Assets.FontW }}') format('woff');
17 } 17 }
18 @font-face {
19 font-family: 'Iosevka Aile';
20 font-style: normal;
21 font-weight: normal;
22 src: url('{{ .Assets.PropFontW2 }}') format('woff2'),
23 url('{{ .Assets.PropFontW }}') format('woff');
24 }
18 </style> 25 </style>
19 </head> 26 </head>
20 <body class="{{ if not .Lines }}is-plain{{ end }}"> 27 <body class="{{ if not .Lines }}is-plain{{ end }}">
@@ -63,7 +70,7 @@ var tpltext = `<!doctype html>
63 </div> 70 </div>
64 </header> 71 </header>
65 <main class="wrap"> 72 <main class="wrap">
66 <pre class="content{{ if .Lines }} content--has-type-annotations{{ end }}"> 73 <pre class="content content--has-monospace-font{{ if .Lines }} content--has-type-annotations{{ end }}">
67 {{- if .Lines -}} 74 {{- if .Lines -}}
68 {{- $content := "" -}} 75 {{- $content := "" -}}
69 {{- range .Lines -}} 76 {{- range .Lines -}}
@@ -92,6 +99,10 @@ var tpltext = `<!doctype html>
92 <strong class="setting__label">Wrap wide content</strong> 99 <strong class="setting__label">Wrap wide content</strong>
93 <button class="setting__value">[N/A]</button> 100 <button class="setting__value">[N/A]</button>
94 </div> 101 </div>
102 <div class="setting setting--monospace-font">
103 <strong class="setting__label">Monospace font</strong>
104 <button class="setting__value">[N/A]</button>
105 </div>
95 <div class="setting setting--image-previews"> 106 <div class="setting setting--image-previews">
96 <strong class="setting__label">Image thumbnails</strong> 107 <strong class="setting__label">Image thumbnails</strong>
97 <button class="setting__value">[N/A]</button> 108 <button class="setting__value">[N/A]</button>