From 839f8bc2d61c3929f4168ed57c23c80eec07d33e Mon Sep 17 00:00:00 2001 From: handlerug Date: Sat, 12 Jun 2021 20:51:28 +0700 Subject: [PATCH] New static files system assets.qtpl is no more! Now you can just add files to static/ folder, make sure the extension is registered in static.go (a shortcoming that'll be addressed in future Go versions), and you're done! It searches the local file system first, then falls back to the files embedded with the binary (in the static/ folder). --- assets/assets.qtpl | 38 - assets/assets.qtpl.go | 828 ------------------ flag.go | 12 +- go.mod | 2 +- main.go | 4 + {assets => static}/default.css | 11 +- static/icon/README.md | 10 + .../feed-icon.svg => static/icon/feed.svg | 0 .../icon/gemini-proto.svg | 0 .../icon/gopher-proto.svg | 0 .../icon/http-proto.svg | 0 .../icon/mailto-proto.svg | 0 static/static.go | 50 ++ {assets => static}/toolbar.js | 0 views/history.qtpl | 2 +- views/history.qtpl.go | 2 +- views/mutators.qtpl | 2 +- views/mutators.qtpl.go | 2 +- views/stuff.qtpl | 5 +- views/stuff.qtpl.go | 379 ++++---- web/web.go | 71 +- 21 files changed, 292 insertions(+), 1126 deletions(-) delete mode 100644 assets/assets.qtpl delete mode 100644 assets/assets.qtpl.go rename {assets => static}/default.css (96%) create mode 100644 static/icon/README.md rename assets/icon/feed-icon.svg => static/icon/feed.svg (100%) rename assets/icon/gemini-protocol-icon.svg => static/icon/gemini-proto.svg (100%) rename assets/icon/gopher-protocol-icon.svg => static/icon/gopher-proto.svg (100%) rename assets/icon/http-protocol-icon.svg => static/icon/http-proto.svg (100%) rename assets/icon/mailto-protocol-icon.svg => static/icon/mailto-proto.svg (100%) create mode 100644 static/static.go rename {assets => static}/toolbar.js (100%) diff --git a/assets/assets.qtpl b/assets/assets.qtpl deleted file mode 100644 index 5330a7a..0000000 --- a/assets/assets.qtpl +++ /dev/null @@ -1,38 +0,0 @@ -{%- func HelpMessage() -%} -Usage of %s: -{%- endfunc -%} - -{%- func ExampleConfig() -%} -{% cat "config.ini" %} -{%- endfunc -%} - -{% func DefaultCSS() %} -{% cat "default.css" %} -{% endfunc %} - -{% func ToolbarJS() %} -{% cat "toolbar.js" %} -{% endfunc %} - -Next three are from https://remixicon.com/ -{% func IconHTTP() %} -{% cat "icon/http-protocol-icon.svg" %} -{% endfunc %} - -{% func IconGemini() %} -{% cat "icon/gemini-protocol-icon.svg" %} -{% endfunc %} - -{% func IconMailto() %} -{% cat "icon/mailto-protocol-icon.svg" %} -{% endfunc %} - -This is a modified version of https://www.svgrepo.com/svg/232085/rat -{% func IconGopher() %} -{% cat "icon/gopher-protocol-icon.svg" %} -{% endfunc %} - -https://upload.wikimedia.org/wikipedia/commons/4/46/Generic_Feed-icon.svg -{% func IconFeed() %} -{% cat "icon/feed-icon.svg" %} -{% endfunc %} diff --git a/assets/assets.qtpl.go b/assets/assets.qtpl.go deleted file mode 100644 index 71355e9..0000000 --- a/assets/assets.qtpl.go +++ /dev/null @@ -1,828 +0,0 @@ -// Code generated by qtc from "assets.qtpl". DO NOT EDIT. -// See https://github.com/valyala/quicktemplate for details. - -//line assets/assets.qtpl:1 -package assets - -//line assets/assets.qtpl:1 -import ( - qtio422016 "io" - - qt422016 "github.com/valyala/quicktemplate" -) - -//line assets/assets.qtpl:1 -var ( - _ = qtio422016.Copy - _ = qt422016.AcquireByteBuffer -) - -//line assets/assets.qtpl:1 -func StreamHelpMessage(qw422016 *qt422016.Writer) { -//line assets/assets.qtpl:1 - qw422016.N().S(`Usage of %s: -`) -//line assets/assets.qtpl:3 -} - -//line assets/assets.qtpl:3 -func WriteHelpMessage(qq422016 qtio422016.Writer) { -//line assets/assets.qtpl:3 - qw422016 := qt422016.AcquireWriter(qq422016) -//line assets/assets.qtpl:3 - StreamHelpMessage(qw422016) -//line assets/assets.qtpl:3 - qt422016.ReleaseWriter(qw422016) -//line assets/assets.qtpl:3 -} - -//line assets/assets.qtpl:3 -func HelpMessage() string { -//line assets/assets.qtpl:3 - qb422016 := qt422016.AcquireByteBuffer() -//line assets/assets.qtpl:3 - WriteHelpMessage(qb422016) -//line assets/assets.qtpl:3 - qs422016 := string(qb422016.B) -//line assets/assets.qtpl:3 - qt422016.ReleaseByteBuffer(qb422016) -//line assets/assets.qtpl:3 - return qs422016 -//line assets/assets.qtpl:3 -} - -//line assets/assets.qtpl:5 -func StreamExampleConfig(qw422016 *qt422016.Writer) { -//line assets/assets.qtpl:6 - qw422016.N().S(`WikiName = My wiki -NaviTitleIcon = ๐Ÿ‘ - -[Hyphae] -HomeHypha = home -UserHypha = u -HeaderLinksHypha = header-links - -[Network] -HTTPPort = 8080 -URL = https://wiki -GeminiCertificatePath = /home/wiki/gemcerts - -[Authorization] -UseFixedAuth = true -FixedAuthCredentialsPath = /home/wiki/mycocredentials.json - -UseRegistration = true -RegistrationCredentialsPath = /home/wiki/mycoregistration.json -LimitRegistration = 10 -`) -//line assets/assets.qtpl:6 - qw422016.N().S(` -`) -//line assets/assets.qtpl:7 -} - -//line assets/assets.qtpl:7 -func WriteExampleConfig(qq422016 qtio422016.Writer) { -//line assets/assets.qtpl:7 - qw422016 := qt422016.AcquireWriter(qq422016) -//line assets/assets.qtpl:7 - StreamExampleConfig(qw422016) -//line assets/assets.qtpl:7 - qt422016.ReleaseWriter(qw422016) -//line assets/assets.qtpl:7 -} - -//line assets/assets.qtpl:7 -func ExampleConfig() string { -//line assets/assets.qtpl:7 - qb422016 := qt422016.AcquireByteBuffer() -//line assets/assets.qtpl:7 - WriteExampleConfig(qb422016) -//line assets/assets.qtpl:7 - qs422016 := string(qb422016.B) -//line assets/assets.qtpl:7 - qt422016.ReleaseByteBuffer(qb422016) -//line assets/assets.qtpl:7 - return qs422016 -//line assets/assets.qtpl:7 -} - -//line assets/assets.qtpl:9 -func StreamDefaultCSS(qw422016 *qt422016.Writer) { -//line assets/assets.qtpl:9 - qw422016.N().S(` -`) -//line assets/assets.qtpl:10 - qw422016.N().S(`.non-existent-hypha { } -.non-existent-hypha__ways { display: flex; flex-direction: column; width: 100%; margin: 0 0 1rem 0;} -.non-existent-hypha__way { border: 1px #999 solid; border-radius: .25rem; padding: .25rem; } -.non-existent-hypha__title { margin-bottom: 1rem; } -.non-existent-hypha__subtitle { margin: 0; } - -.amnt-grid { display: grid; grid-template-columns: 1fr 1fr; } -#upload-binary__input { display: block; margin: .25rem 0 .25rem 0; } - -.modal__title { font-size: 2rem; } -.modal__title_small { font-size: 1.5rem; } -.modal__confirmation-msg { margin: 0 0 .5rem 0; } - -.hypha-list { padding-left: 0; } -.hypha-list__entry { list-style-type: none; } -.hypha-list__link { text-decoration: none; display: inline-block; padding: .25rem; } -.hypha-list__link:hover { text-decoration: underline; } -.hypha-list__amnt-type { font-size: smaller; color: #999; } - -/* General element positions, from small to big */ -/* Phones and whatnot */ -.layout { display: grid; row-gap: 1rem; } -header { width: 100%; margin-bottom: 1rem; } -.header-links__list, .hypha-tabs__flex { margin: 0; padding: 0; display: flex; flex-wrap: wrap; } -.header-links__entry, .hypha-tabs__tab { list-style-type: none; } - -.header-links__entry { margin-right: .5rem; } -.header-links__entry_user, .header-links__entry_register { font-style:italic; } -.header-links__link { display: inline-block; padding: .25rem; text-decoration: none; } - -.hypha-tabs { padding: 0; margin: 0; } -.hypha-tabs__tab { margin-right: .5rem; padding: 0; } -.hypha-tabs__link { display: inline-block; padding: .25rem; text-decoration: none; } -.hypha-tabs__selection { display: inline-block; padding: .25rem; font-weight: bold; } - -.layout-card li { list-style-type: none; } -.backlinks__list { padding: 0; margin: 0; } -.backlinks__link { text-decoration: none; display: block; padding: .25rem; padding-left: 1.25rem; } - -@media screen and (max-width: 800px) { - .amnt-grid { grid-template-columns: 1fr; } - .layout { grid-template-columns: auto; grid-template-rows: auto auto auto; } - .main-width { width: 100%; } - main { padding: 1rem; margin: 0; } -} - -@media screen and (min-width: 500px) { - .non-existent-hypha__way { flex: 1; margin-right: .5rem; } - .non-existent-hypha__ways { flex-direction: row; } - .non-existent-hypha__way:last-child { margin-right: 0; } -} - -/* No longer a phone but still small screen: draw normal tabs, center main */ -@media screen and (min-width: 801px) { - .main-width { padding: 1rem 2rem; width: 800px; margin: 0 auto; } - main { border-radius: .25rem; } - .layout-card { width: 800px; margin: 0 auto; } - - .header-links { padding: 0; } - .header-links__entry { margin-right: 1.5rem; } - .header-links__entry_user { margin: 0 2rem 0 auto; } - .header-links__entry:nth-of-type(1), - - .hypha-tabs { padding: 0; } - .hypha-tabs__tab { border-radius: .25rem .25rem 0 0; margin-right: 0; } - .hypha-tabs__selection, .hypha-tabs__link { padding: .25rem .5rem; } - - .header-links__entry:nth-of-type(1), .hypha-tabs__tab:nth-of-type(1) { margin-left: 2rem; } -} - - -/* Wide enough to fit two columns ok */ -@media screen and (min-width: 1100px) { - .layout { display: grid; grid-template-columns: auto 1fr; column-gap: 1rem; margin: 0 1rem; row-gap: 1rem; } - .main-width { margin: 0; } - main { grid-column: 1 / span 1; grid-row: 1 / span 2; } - .relative-hyphae, .edit-toolbar { grid-column: 2 / span 1; grid-row: 1 / span 1; } - .layout-card { width: 100%; } - .edit-toolbar__buttons {display: grid; } -} - -@media screen and (min-width: 1150px) { - .edit-toolbar__buttons { grid-template-columns: 1fr 1fr; } -} - -@media screen and (min-width: 1250px) { - .layout { grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr); } - .layout-card {max-width: 18rem;} - .main-width { margin: 0 auto; } - .backlinks { grid-column: 1 / span 1; margin-right: 0; } - main { grid-column: 2 / span 1; } - .relative-hyphae, .edit-toolbar { grid-column: 3 / span 1; margin-left: 0; } - .edit-toolbar__buttons { grid-template-columns: 1fr; } - - .backlinks__title { text-align: right; } - .backlinks__link { text-align: right; padding-right: 1.25rem; padding-left: .25rem; } -} - -@media screen and (min-width: 1400px) { - .edit-toolbar__buttons { grid-template-columns: 1fr 1fr; } -} - -*, *::before, *::after {box-sizing: border-box;} -html { height:100%; padding:0; } -body {height:100%; margin:0; } -body, input { font-size:16px; font-family: 'PT Sans', 'Liberation Sans', sans-serif;} -main > form {margin-bottom:1rem;} -textarea {font-size:16px; font-family: 'PT Sans', 'Liberation Sans', sans-serif;} - -.edit { min-height: 80vh; } -.edit__title { margin-top: 0; } -.edit__preview { border: 2px dashed #ddd; } -.edit-form {height:70vh;} -.edit-form textarea {width:100%;height:95%;} -.edit-form__save { font-weight: bold; } -.edit-toolbar__buttons, .edit-toolbar__ad { margin: .5rem; } - -.icon {margin-right: .25rem; vertical-align: bottom; } - -main h1:not(.navi-title) {font-size:1.7rem;} -blockquote { margin: 0; padding-left: .75rem; } -.wikilink_external::before { display: inline-block; width: 18px; height: 16px; vertical-align: sub; } -/* .wikilink_external { padding-left: 16px; } */ -.wikilink_gopher::before { content: url("/assets/icon/gopher"); } -.wikilink_http::before { content: url("/assets/icon/http"); } -.wikilink_https::before { content: url("/assets/icon/http"); } -/* .wikilink_https { background: transparent url("/assets/icon/http") center left no-repeat; } */ -.wikilink_gemini::before { content: url("/assets/icon/gemini"); } -.wikilink_mailto::before { content: url("/assets/icon/mailto"); } - -article { overflow-wrap: break-word; word-wrap: break-word; word-break: break-word; line-height: 150%; } -main h1, main h2, main h3, main h4, main h5, main h6 { margin: 1.5rem 0 0 0; } -.heading__link { text-decoration: none; display: inline-block; } -.heading__link::after { width: 1rem; content: "ยง"; color: transparent; } -.heading__link:hover::after, .heading__link:active::after { color: #999; } -article p { margin: .5rem 0; } -article ul, ol { padding-left: 1.5rem; margin: .5rem 0; } -article code { padding: .1rem .3rem; border-radius: .25rem; font-size: 90%; font-family: 'Menlo', 'PT Mono', monospace; } -article pre.codeblock { padding:.5rem; white-space: pre-wrap; border-radius: .25rem;} -.codeblock code {padding:0; font-size:15px;} -.transclusion { border-radius: .25rem; } -.transclusion__content > *:not(.binary-container) {margin: 0.5rem; } -.transclusion__link {display: block; text-align: right; font-style: italic; margin-top: .5rem; margin-right: .25rem; text-decoration: none;} -.transclusion__link::before {content: "โ‡ ";} - -/* Derived from https://commons.wikimedia.org/wiki/File:U%2B21D2.svg */ -.launchpad__entry { list-style-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' version='1.0' width='25' height='12'%3E%3Cg transform='scale(0.7,0.8) translate(-613.21429,-421)'%3E%3Cpath fill='%23999' d='M 638.06773,429.49751 L 631.01022,436.87675 L 630.1898,436.02774 L 632.416,433.30375 L 613.46876,433.30375 L 613.46876,431.66382 L 633.82089,431.66382 L 635.57789,429.5261 L 633.79229,427.35979 L 613.46876,427.35979 L 613.46876,425.71985 L 632.416,425.71985 L 630.1898,422.99587 L 631.01022,422.08788 L 638.06773,429.49751 z '/%3E%3C/g%3E%3C/svg%3E"); } - -.binary-container { width: 100%; text-align: center; } -.binary-container_with-img img, -.binary-container_with-video video, -.binary-container_with-audio audio { max-width: 100%; max-height: 30em; width: auto; } - -.subhyphae__title { padding-bottom: .5rem; clear: both; } -.navi-title { padding-bottom: .5rem; margin: .25rem 0; } -.navi-title a {text-decoration:none; } -.navi-title__separator { margin: 0 .25rem; } -.navi-title__colon { margin-right: .5rem; } -.upload-amnt { clear: both; padding: .5rem; border-radius: .25rem; } -.upload-amnt__unattach { display: block; } -aside { clear: both; } - -.img-gallery { text-align: center; margin-top: .25rem; margin-bottom: .25rem; } -.img-gallery_many-images { border-radius: .25rem; padding: .5rem; } -.img-gallery img { max-width: 100%; max-height: 50vh; } -figure { margin: 0; } -figcaption { padding-bottom: .5rem; } - -#new-name {width:100%;} - - -.rc-entry { display: grid; list-style-type: none; padding: .25rem; grid-template-columns: 1fr 1fr; border-radius: .25rem; } -.rc-entry__time { font-style: italic; } -.rc-entry__hash { font-style: italic; text-align: right; } -.rc-entry__links, .rc-entry__msg { grid-column: 1 / span 2; } -.rc-entry__author { font-style: italic; } - -.prevnext__el { display: inline-block; min-width: 40%; padding: .5rem; margin-bottom: .25rem; text-decoration: none; border-radius: .25rem; max-width: 49%; } -.prevnext__prev { float: left; } -.prevnext__next { float: right; text-align: right; } - -.page-separator { clear: both; } -.history__entries { background-color: #eee; margin: 0; padding: 0; border-radius: .25rem; } -.history__month-anchor { text-decoration: none; color: inherit; } -.history__entry { list-style-type: none; padding: .25rem; } -.history-entry { padding: .25rem; } -.history-entry__time { font-weight: bold; } -.history-entry__author { font-style: italic; } - -table { border: #ddd 1px solid; border-radius: .25rem; min-width: 4rem; } -td { padding: .25rem; } -caption { caption-side: top; font-size: small; } - -.subhyphae__list, .subhyphae__list ul { display: flex; padding: 0; margin: 0; flex-wrap: wrap; } -.subhyphae__list ul { font-size: 90%; } -.subhyphae__entry { list-style-type: none; border: 1px solid #999; padding: 0; margin: .125rem; border-radius: .25rem; } -.subhyphae__link { display: block; padding: .25rem; text-decoration: none; } -.subhyphae__link:hover { background: #eee; } - -.relative-hyphae__list { padding: 0; margin: 0; } -.relative-hyphae__entry { clear: both; } -.relative-hyphae__count { display: inline-block; float: right; } -.relative-hyphae__entry_this { padding: .25rem .5rem; font-weight: bold; } -.relative-hyphae__link { text-decoration: none; display: block; padding: .25rem .5rem; } - -::-webkit-file-upload-button, -.btn { line-height: normal; display: inline-block; border: 1px #999 solid; border-radius: .25rem; text-decoration: none; padding: .25rem; font-size: 1rem; margin: 0; } -.btn_weak { border: 1px #999 dashed; } - -/* Color stuff */ -/* Lighter stuff #eee */ -::-webkit-file-upload-button, .btn { background-color: #eee; color: black; } -.btn:visited { color: black; } -.btn_weak { background-color: transparent; } - -article code, -article .codeblock, -.transclusion, -.img-gallery_many-images, -.rc-entry, -.prevnext__el, -table { background-color: #eee; } - -.hypha-tabs__tab { background-color: #eee; } -.hypha-tabs__tab a { color: black; } -.hypha-tabs__tab_active { border-bottom: 2px white solid; background: white; } - -@media screen and (max-width: 800px) { - .hypha-tabs, - .hypha-tabs__tab { background-color: white; } -} - -@media screen and (min-width: 801px) { - .hypha-tabs__tab { border: 1px #ddd solid; } - .hypha-tabs__tab_active { border-bottom: 1px white solid; } -} - -.layout-card { border-radius: .25rem; background-color: white; } -.layout-card__title { font-size: 1rem; margin: 0; padding: .25rem .5rem; border-radius: .25rem .25rem 0 0; } -.layout-card__title { border-bottom: 1px solid #eee; } - -/* Other stuff */ -html { background-color: #eee; -} -header { background-color: #eee; } -.header-links__link { color: black; } -.header-links__link:hover { background-color: #ddd; } -main { background-color: white; } - -blockquote { border-left: 2px #999 solid; } -.wikilink_new {color:#a55858;} -.transclusion code, .transclusion .codeblock {background-color:#ddd;} -.transclusion__link { color: black; } -.wikilink_new:visited {color:#a55858;} -.navi-title { border-bottom: #eee 1px solid; } -.upload-amnt { border: #eee 1px solid; } -td { border: #ddd 1px solid; } - -.relative-hyphae__link:hover, .backlinks__link:hover { background-color: #eee; } - -/* Dark theme! */ -@media (prefers-color-scheme: dark) { -html { background: #222; color: #ddd; } -main, article, .hypha-tabs__tab, header, .layout-card { background-color: #343434; color: #ddd; } - -a, .wikilink_external { color: #f1fa8c; } -a:visited, .wikilink_external:visited { color: #ffb86c; } -.wikilink_new, .wikilink_new:visited { color: #dd4444; } -.subhyphae__link:hover, .relative-hyphae__link:hover, .backlinks__link:hover { background-color: #444; } - -.header-links__link, .header-links__link:visited, -.prevnext__el, .prevnext__el:visited { color: #ddd; } -.header-links__link:hover { background-color: #444; } - -.hypha-tabs__tab a, .hypha-tabs__tab { color: #ddd; background-color: #232323; border: 0; } -.layout-card__title, .hypha-tabs__tab_active { background-color: #343434; } - - -.transclusion .transclusion__link { color: #ddd; } - -input[type="text"], input[type="password"], -::-webkit-file-upload-button, -.btn, -article code, -article .codeblock, -.transclusion, -.img-gallery_many-images, -.rc-entry, -.history__entry, -.prevnext__el, -.upload-amnt, -textarea, -table { border: 0; background-color: #444444; color: #ddd; } -.btn:visited { color: #ddd;} - - .btn { border: #444 solid 1px; border-radius: .25rem; } - .btn_weak { background-color: transparent; } - -.transclusion code, -.transclusion .codeblock { background-color: #454545; } -mark { background: rgba(130, 80, 30, 5); color: inherit; } -@media screen and (max-width: 800px) { - .hypha-tabs { background-color: #232323; } -} -} - - -`) -//line assets/assets.qtpl:10 - qw422016.N().S(` -`) -//line assets/assets.qtpl:11 -} - -//line assets/assets.qtpl:11 -func WriteDefaultCSS(qq422016 qtio422016.Writer) { -//line assets/assets.qtpl:11 - qw422016 := qt422016.AcquireWriter(qq422016) -//line assets/assets.qtpl:11 - StreamDefaultCSS(qw422016) -//line assets/assets.qtpl:11 - qt422016.ReleaseWriter(qw422016) -//line assets/assets.qtpl:11 -} - -//line assets/assets.qtpl:11 -func DefaultCSS() string { -//line assets/assets.qtpl:11 - qb422016 := qt422016.AcquireByteBuffer() -//line assets/assets.qtpl:11 - WriteDefaultCSS(qb422016) -//line assets/assets.qtpl:11 - qs422016 := string(qb422016.B) -//line assets/assets.qtpl:11 - qt422016.ReleaseByteBuffer(qb422016) -//line assets/assets.qtpl:11 - return qs422016 -//line assets/assets.qtpl:11 -} - -//line assets/assets.qtpl:13 -func StreamToolbarJS(qw422016 *qt422016.Writer) { -//line assets/assets.qtpl:13 - qw422016.N().S(` -`) -//line assets/assets.qtpl:14 - qw422016.N().S(`const editTextarea = document.getElementsByClassName('edit-form__textarea')[0] - -function placeCursor(position, el = editTextarea) { - el.selectionEnd = position - el.selectionStart = el.selectionEnd -} - -function getSelectedText(el = editTextarea) { - const [start, end] = [el.selectionStart, el.selectionEnd] - const text = el.value - return text.substring(start, end) -} - -function textInserter(text, cursorPosition = null, el = editTextarea) { - return function() { - const [start, end] = [el.selectionStart, el.selectionEnd] - el.setRangeText(text, start, end, 'select') - el.focus() - if (cursorPosition == null) { - placeCursor(end + text.length) - } else { - placeCursor(end + cursorPosition) - } - } -} - -function selectionWrapper(cursorPosition, prefix, postfix = null, el = editTextarea) { - return function() { - const [start, end] = [el.selectionStart, el.selectionEnd] - if (postfix == null) { - postfix = prefix - } - let text = getSelectedText(el) - let result = prefix + text + postfix - el.setRangeText(result, start, end, 'select') - el.focus() - placeCursor(end + cursorPosition) - } -} - -const wrapBold = selectionWrapper(2, '**'), - wrapItalic = selectionWrapper(2, '//'), - wrapMonospace = selectionWrapper(1, '`) -//line assets/assets.qtpl:14 - qw422016.N().S("`") -//line assets/assets.qtpl:14 - qw422016.N().S(`'), - wrapHighlighted = selectionWrapper(2, '!!'), - wrapLifted = selectionWrapper(2, '^^'), - wrapLowered = selectionWrapper(2, ',,'), - wrapStrikethrough = selectionWrapper(2, '~~'), - wrapLink = selectionWrapper(2, '[[', ']]') - -const insertHorizontalBar = textInserter('\n----\n'), - insertImgBlock = textInserter('\nimg {\n \n}\n', 10), - insertTableBlock = textInserter('\ntable {\n \n}\n', 12), - insertRocket = textInserter('\n=> '), - insertXcl = textInserter('\n<= '), - insertHeading2 = textInserter('\n## '), - insertHeading3 = textInserter('\n### '), - insertCodeblock = textInserter('\n`) -//line assets/assets.qtpl:14 - qw422016.N().S("`") -//line assets/assets.qtpl:14 - qw422016.N().S(``) -//line assets/assets.qtpl:14 - qw422016.N().S("`") -//line assets/assets.qtpl:14 - qw422016.N().S(``) -//line assets/assets.qtpl:14 - qw422016.N().S("`") -//line assets/assets.qtpl:14 - qw422016.N().S(`\n\n`) -//line assets/assets.qtpl:14 - qw422016.N().S("`") -//line assets/assets.qtpl:14 - qw422016.N().S(``) -//line assets/assets.qtpl:14 - qw422016.N().S("`") -//line assets/assets.qtpl:14 - qw422016.N().S(``) -//line assets/assets.qtpl:14 - qw422016.N().S("`") -//line assets/assets.qtpl:14 - qw422016.N().S(`\n', 5), - insertBulletedList = textInserter('\n* '), - insertNumberedList = textInserter('\n*. ') - -function insertDate() { - let date = new Date().toISOString().split('T')[0] - textInserter(date)() -} - -function insertTimeUTC() { - let time = new Date().toISOString().substring(11, 19) + " UTC" - textInserter(time)() -} - -function insertUserlink() { - const userlink = document.querySelector('.header-links__entry_user a') - const userHypha = userlink.getAttribute('href').substring(7) // no /hypha/ - textInserter('[[' + userHypha + ']]')() -} -`) -//line assets/assets.qtpl:14 - qw422016.N().S(` -`) -//line assets/assets.qtpl:15 -} - -//line assets/assets.qtpl:15 -func WriteToolbarJS(qq422016 qtio422016.Writer) { -//line assets/assets.qtpl:15 - qw422016 := qt422016.AcquireWriter(qq422016) -//line assets/assets.qtpl:15 - StreamToolbarJS(qw422016) -//line assets/assets.qtpl:15 - qt422016.ReleaseWriter(qw422016) -//line assets/assets.qtpl:15 -} - -//line assets/assets.qtpl:15 -func ToolbarJS() string { -//line assets/assets.qtpl:15 - qb422016 := qt422016.AcquireByteBuffer() -//line assets/assets.qtpl:15 - WriteToolbarJS(qb422016) -//line assets/assets.qtpl:15 - qs422016 := string(qb422016.B) -//line assets/assets.qtpl:15 - qt422016.ReleaseByteBuffer(qb422016) -//line assets/assets.qtpl:15 - return qs422016 -//line assets/assets.qtpl:15 -} - -// Next three are from https://remixicon.com/ - -//line assets/assets.qtpl:18 -func StreamIconHTTP(qw422016 *qt422016.Writer) { -//line assets/assets.qtpl:18 - qw422016.N().S(` -`) -//line assets/assets.qtpl:19 - qw422016.N().S(` -`) -//line assets/assets.qtpl:19 - qw422016.N().S(` -`) -//line assets/assets.qtpl:20 -} - -//line assets/assets.qtpl:20 -func WriteIconHTTP(qq422016 qtio422016.Writer) { -//line assets/assets.qtpl:20 - qw422016 := qt422016.AcquireWriter(qq422016) -//line assets/assets.qtpl:20 - StreamIconHTTP(qw422016) -//line assets/assets.qtpl:20 - qt422016.ReleaseWriter(qw422016) -//line assets/assets.qtpl:20 -} - -//line assets/assets.qtpl:20 -func IconHTTP() string { -//line assets/assets.qtpl:20 - qb422016 := qt422016.AcquireByteBuffer() -//line assets/assets.qtpl:20 - WriteIconHTTP(qb422016) -//line assets/assets.qtpl:20 - qs422016 := string(qb422016.B) -//line assets/assets.qtpl:20 - qt422016.ReleaseByteBuffer(qb422016) -//line assets/assets.qtpl:20 - return qs422016 -//line assets/assets.qtpl:20 -} - -//line assets/assets.qtpl:22 -func StreamIconGemini(qw422016 *qt422016.Writer) { -//line assets/assets.qtpl:22 - qw422016.N().S(` -`) -//line assets/assets.qtpl:23 - qw422016.N().S(` -`) -//line assets/assets.qtpl:23 - qw422016.N().S(` -`) -//line assets/assets.qtpl:24 -} - -//line assets/assets.qtpl:24 -func WriteIconGemini(qq422016 qtio422016.Writer) { -//line assets/assets.qtpl:24 - qw422016 := qt422016.AcquireWriter(qq422016) -//line assets/assets.qtpl:24 - StreamIconGemini(qw422016) -//line assets/assets.qtpl:24 - qt422016.ReleaseWriter(qw422016) -//line assets/assets.qtpl:24 -} - -//line assets/assets.qtpl:24 -func IconGemini() string { -//line assets/assets.qtpl:24 - qb422016 := qt422016.AcquireByteBuffer() -//line assets/assets.qtpl:24 - WriteIconGemini(qb422016) -//line assets/assets.qtpl:24 - qs422016 := string(qb422016.B) -//line assets/assets.qtpl:24 - qt422016.ReleaseByteBuffer(qb422016) -//line assets/assets.qtpl:24 - return qs422016 -//line assets/assets.qtpl:24 -} - -//line assets/assets.qtpl:26 -func StreamIconMailto(qw422016 *qt422016.Writer) { -//line assets/assets.qtpl:26 - qw422016.N().S(` -`) -//line assets/assets.qtpl:27 - qw422016.N().S(` -`) -//line assets/assets.qtpl:27 - qw422016.N().S(` -`) -//line assets/assets.qtpl:28 -} - -//line assets/assets.qtpl:28 -func WriteIconMailto(qq422016 qtio422016.Writer) { -//line assets/assets.qtpl:28 - qw422016 := qt422016.AcquireWriter(qq422016) -//line assets/assets.qtpl:28 - StreamIconMailto(qw422016) -//line assets/assets.qtpl:28 - qt422016.ReleaseWriter(qw422016) -//line assets/assets.qtpl:28 -} - -//line assets/assets.qtpl:28 -func IconMailto() string { -//line assets/assets.qtpl:28 - qb422016 := qt422016.AcquireByteBuffer() -//line assets/assets.qtpl:28 - WriteIconMailto(qb422016) -//line assets/assets.qtpl:28 - qs422016 := string(qb422016.B) -//line assets/assets.qtpl:28 - qt422016.ReleaseByteBuffer(qb422016) -//line assets/assets.qtpl:28 - return qs422016 -//line assets/assets.qtpl:28 -} - -// This is a modified version of https://www.svgrepo.com/svg/232085/rat - -//line assets/assets.qtpl:31 -func StreamIconGopher(qw422016 *qt422016.Writer) { -//line assets/assets.qtpl:31 - qw422016.N().S(` -`) -//line assets/assets.qtpl:32 - qw422016.N().S(` - - - -`) -//line assets/assets.qtpl:32 - qw422016.N().S(` -`) -//line assets/assets.qtpl:33 -} - -//line assets/assets.qtpl:33 -func WriteIconGopher(qq422016 qtio422016.Writer) { -//line assets/assets.qtpl:33 - qw422016 := qt422016.AcquireWriter(qq422016) -//line assets/assets.qtpl:33 - StreamIconGopher(qw422016) -//line assets/assets.qtpl:33 - qt422016.ReleaseWriter(qw422016) -//line assets/assets.qtpl:33 -} - -//line assets/assets.qtpl:33 -func IconGopher() string { -//line assets/assets.qtpl:33 - qb422016 := qt422016.AcquireByteBuffer() -//line assets/assets.qtpl:33 - WriteIconGopher(qb422016) -//line assets/assets.qtpl:33 - qs422016 := string(qb422016.B) -//line assets/assets.qtpl:33 - qt422016.ReleaseByteBuffer(qb422016) -//line assets/assets.qtpl:33 - return qs422016 -//line assets/assets.qtpl:33 -} - -// https://upload.wikimedia.org/wikipedia/commons/4/46/Generic_Feed-icon.svg - -//line assets/assets.qtpl:36 -func StreamIconFeed(qw422016 *qt422016.Writer) { -//line assets/assets.qtpl:36 - qw422016.N().S(` -`) -//line assets/assets.qtpl:37 - qw422016.N().S(` - - RSS feed icon - - - - - - - - - -`) -//line assets/assets.qtpl:37 - qw422016.N().S(` -`) -//line assets/assets.qtpl:38 -} - -//line assets/assets.qtpl:38 -func WriteIconFeed(qq422016 qtio422016.Writer) { -//line assets/assets.qtpl:38 - qw422016 := qt422016.AcquireWriter(qq422016) -//line assets/assets.qtpl:38 - StreamIconFeed(qw422016) -//line assets/assets.qtpl:38 - qt422016.ReleaseWriter(qw422016) -//line assets/assets.qtpl:38 -} - -//line assets/assets.qtpl:38 -func IconFeed() string { -//line assets/assets.qtpl:38 - qb422016 := qt422016.AcquireByteBuffer() -//line assets/assets.qtpl:38 - WriteIconFeed(qb422016) -//line assets/assets.qtpl:38 - qs422016 := string(qb422016.B) -//line assets/assets.qtpl:38 - qt422016.ReleaseByteBuffer(qb422016) -//line assets/assets.qtpl:38 - return qs422016 -//line assets/assets.qtpl:38 -} diff --git a/flag.go b/flag.go index 19c69d6..872f44c 100644 --- a/flag.go +++ b/flag.go @@ -1,18 +1,20 @@ package main import ( + _ "embed" "flag" "fmt" "github.com/bouncepaw/mycorrhiza/cfg" "log" "os" "path/filepath" - - "github.com/bouncepaw/mycorrhiza/assets" ) // CLI options are read and parsed here. +//go:embed assets/config.ini +var defaultConfig []byte + var printExampleConfig bool func init() { @@ -21,11 +23,11 @@ func init() { flag.Usage = printHelp } -// printHelp prints the help message. The help message is stored in assets. +// printHelp prints the help message. func printHelp() { _, err := fmt.Fprintf( flag.CommandLine.Output(), - assets.HelpMessage(), + "Usage of %s:\n", os.Args[0], ) if err != nil { @@ -40,7 +42,7 @@ func parseCliArgs() { args := flag.Args() if printExampleConfig { - fmt.Printf(assets.ExampleConfig()) + os.Stdout.Write(defaultConfig) os.Exit(0) } diff --git a/go.mod b/go.mod index e9297ed..109d91a 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/bouncepaw/mycorrhiza -go 1.14 +go 1.16 require ( git.sr.ht/~adnano/go-gemini v0.1.13 diff --git a/main.go b/main.go index 33e17f9..5f1cb7e 100644 --- a/main.go +++ b/main.go @@ -11,6 +11,7 @@ import ( "github.com/bouncepaw/mycorrhiza/history" "github.com/bouncepaw/mycorrhiza/hyphae" "github.com/bouncepaw/mycorrhiza/shroom" + "github.com/bouncepaw/mycorrhiza/static" "github.com/bouncepaw/mycorrhiza/user" "github.com/bouncepaw/mycorrhiza/web" "log" @@ -40,6 +41,9 @@ func main() { history.Start() shroom.SetHeaderLinks() + // Static files: + static.InitFS(cfg.WikiDir + "/static") + // Network: go handleGemini() web.Init() diff --git a/assets/default.css b/static/default.css similarity index 96% rename from assets/default.css rename to static/default.css index 66d41a4..8ab0fed 100644 --- a/assets/default.css +++ b/static/default.css @@ -121,12 +121,11 @@ main h1:not(.navi-title) {font-size:1.7rem;} blockquote { margin: 0; padding-left: .75rem; } .wikilink_external::before { display: inline-block; width: 18px; height: 16px; vertical-align: sub; } /* .wikilink_external { padding-left: 16px; } */ -.wikilink_gopher::before { content: url("/assets/icon/gopher"); } -.wikilink_http::before { content: url("/assets/icon/http"); } -.wikilink_https::before { content: url("/assets/icon/http"); } -/* .wikilink_https { background: transparent url("/assets/icon/http") center left no-repeat; } */ -.wikilink_gemini::before { content: url("/assets/icon/gemini"); } -.wikilink_mailto::before { content: url("/assets/icon/mailto"); } +.wikilink_gopher::before { content: url("/static/icon/gopher-proto.svg"); } +.wikilink_http::before, .wikilink_https::before { content: url("/static/icon/http-proto.svg"); } +/* .wikilink_https { background: transparent url("/static/icon/http-proto.svg") center left no-repeat; } */ +.wikilink_gemini::before { content: url("/static/icon/gemini-proto.svg"); } +.wikilink_mailto::before { content: url("/static/icon/mailto-proto.svg"); } article { overflow-wrap: break-word; word-wrap: break-word; word-break: break-word; line-height: 150%; } main h1, main h2, main h3, main h4, main h5, main h6 { margin: 1.5rem 0 0 0; } diff --git a/static/icon/README.md b/static/icon/README.md new file mode 100644 index 0000000..676093a --- /dev/null +++ b/static/icon/README.md @@ -0,0 +1,10 @@ +# Icons + +#### `{http,gemini,mailto}-proto` +These are from https://remixicon.com/. + +#### `gopher-proto` +This is a modified version of https://www.svgrepo.com/svg/232085/rat. + +#### `feed` +This one is from https://upload.wikimedia.org/wikipedia/commons/4/46/Generic_Feed-icon.svg. diff --git a/assets/icon/feed-icon.svg b/static/icon/feed.svg similarity index 100% rename from assets/icon/feed-icon.svg rename to static/icon/feed.svg diff --git a/assets/icon/gemini-protocol-icon.svg b/static/icon/gemini-proto.svg similarity index 100% rename from assets/icon/gemini-protocol-icon.svg rename to static/icon/gemini-proto.svg diff --git a/assets/icon/gopher-protocol-icon.svg b/static/icon/gopher-proto.svg similarity index 100% rename from assets/icon/gopher-protocol-icon.svg rename to static/icon/gopher-proto.svg diff --git a/assets/icon/http-protocol-icon.svg b/static/icon/http-proto.svg similarity index 100% rename from assets/icon/http-protocol-icon.svg rename to static/icon/http-proto.svg diff --git a/assets/icon/mailto-protocol-icon.svg b/static/icon/mailto-proto.svg similarity index 100% rename from assets/icon/mailto-protocol-icon.svg rename to static/icon/mailto-proto.svg diff --git a/static/static.go b/static/static.go new file mode 100644 index 0000000..f36ee71 --- /dev/null +++ b/static/static.go @@ -0,0 +1,50 @@ +package static + +import ( + "embed" + "io/fs" + "log" + "os" +) + +//go:embed *.css *.js icon +var embedFS embed.FS + +// FS serves all static files. +var FS HybridFS + +// HybridFS is a filesystem that implements fs.FS. It can serve files +// from multiple filesystems, falling back on failures. +type HybridFS struct { + fs []fs.FS +} + +// Open tries to open the requested file using all filesystems provided. +// If neither succeeds, it returns the last error. +func (f HybridFS) Open(name string) (fs.File, error) { + log.Printf("serving static file: %s\n", name) + + var file fs.File + var err error + + for _, candidate := range f.fs { + file, err = candidate.Open(name) + if err == nil { + log.Println("succeeded") + return file, nil + } + } + + log.Printf("failed: %v\n", err) + return nil, err +} + +// InitFS initializes the global HybridFS singleton with the local wiki. +func InitFS(localPath string) { + FS = HybridFS{ + fs: []fs.FS{ + os.DirFS(localPath), + embedFS, + }, + } +} diff --git a/assets/toolbar.js b/static/toolbar.js similarity index 100% rename from assets/toolbar.js rename to static/toolbar.js diff --git a/views/history.qtpl b/views/history.qtpl index 7049261..7b3cce4 100644 --- a/views/history.qtpl +++ b/views/history.qtpl @@ -45,7 +45,7 @@ if err != nil { recent changes -

Subscribe via RSS, Atom or JSON feed.

+

Subscribe via RSS, Atom or JSON feed.

{% comment %} Here I am, willing to add some accessibility using ARIA. Turns out, diff --git a/views/history.qtpl.go b/views/history.qtpl.go index 0a0462b..50cbad2 100644 --- a/views/history.qtpl.go +++ b/views/history.qtpl.go @@ -163,7 +163,7 @@ func StreamRecentChangesHTML(qw422016 *qt422016.Writer, n int) { recent changes -

Subscribe via RSS, Atom or JSON feed.

+

Subscribe via RSS, Atom or JSON feed.

`) //line views/history.qtpl:55 diff --git a/views/mutators.qtpl b/views/mutators.qtpl index 5b1c321..1ab396e 100644 --- a/views/mutators.qtpl +++ b/views/mutators.qtpl @@ -65,7 +65,7 @@ {% endif %} - + {% endfunc %} {% func EditHTML(rq *http.Request, hyphaName, textAreaFill, warning string) %} diff --git a/views/mutators.qtpl.go b/views/mutators.qtpl.go index 95ac60c..8c36ceb 100644 --- a/views/mutators.qtpl.go +++ b/views/mutators.qtpl.go @@ -141,7 +141,7 @@ func StreamToolbar(qw422016 *qt422016.Writer, u *user.User) { qw422016.N().S(` - + `) //line views/mutators.qtpl:69 } diff --git a/views/stuff.qtpl b/views/stuff.qtpl index 26117af..b3b359f 100644 --- a/views/stuff.qtpl +++ b/views/stuff.qtpl @@ -8,10 +8,11 @@ - - + {%s title %} + + {% for _, el := range headElements %}{%s= el %}{% endfor %} diff --git a/views/stuff.qtpl.go b/views/stuff.qtpl.go index 9079a25..63a6cb0 100644 --- a/views/stuff.qtpl.go +++ b/views/stuff.qtpl.go @@ -39,22 +39,23 @@ func StreamBaseHTML(qw422016 *qt422016.Writer, title, body string, u *user.User, - - + `) -//line views/stuff.qtpl:14 +//line views/stuff.qtpl:13 qw422016.E().S(title) -//line views/stuff.qtpl:14 +//line views/stuff.qtpl:13 qw422016.N().S(` + + `) -//line views/stuff.qtpl:15 +//line views/stuff.qtpl:16 for _, el := range headElements { -//line views/stuff.qtpl:15 +//line views/stuff.qtpl:16 qw422016.N().S(el) -//line views/stuff.qtpl:15 +//line views/stuff.qtpl:16 } -//line views/stuff.qtpl:15 +//line views/stuff.qtpl:16 qw422016.N().S(` @@ -62,81 +63,81 @@ func StreamBaseHTML(qw422016 *qt422016.Writer, title, body string, u *user.User, `) -//line views/stuff.qtpl:28 +//line views/stuff.qtpl:29 qw422016.N().S(body) -//line views/stuff.qtpl:28 +//line views/stuff.qtpl:29 qw422016.N().S(` `) -//line views/stuff.qtpl:29 +//line views/stuff.qtpl:30 streamomnipresentScripts(qw422016) -//line views/stuff.qtpl:29 +//line views/stuff.qtpl:30 qw422016.N().S(` `) -//line views/stuff.qtpl:32 +//line views/stuff.qtpl:33 } -//line views/stuff.qtpl:32 +//line views/stuff.qtpl:33 func WriteBaseHTML(qq422016 qtio422016.Writer, title, body string, u *user.User, headElements ...string) { -//line views/stuff.qtpl:32 +//line views/stuff.qtpl:33 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/stuff.qtpl:32 +//line views/stuff.qtpl:33 StreamBaseHTML(qw422016, title, body, u, headElements...) -//line views/stuff.qtpl:32 +//line views/stuff.qtpl:33 qt422016.ReleaseWriter(qw422016) -//line views/stuff.qtpl:32 +//line views/stuff.qtpl:33 } -//line views/stuff.qtpl:32 +//line views/stuff.qtpl:33 func BaseHTML(title, body string, u *user.User, headElements ...string) string { -//line views/stuff.qtpl:32 +//line views/stuff.qtpl:33 qb422016 := qt422016.AcquireByteBuffer() -//line views/stuff.qtpl:32 +//line views/stuff.qtpl:33 WriteBaseHTML(qb422016, title, body, u, headElements...) -//line views/stuff.qtpl:32 +//line views/stuff.qtpl:33 qs422016 := string(qb422016.B) -//line views/stuff.qtpl:32 +//line views/stuff.qtpl:33 qt422016.ReleaseByteBuffer(qb422016) -//line views/stuff.qtpl:32 +//line views/stuff.qtpl:33 return qs422016 -//line views/stuff.qtpl:32 +//line views/stuff.qtpl:33 } -//line views/stuff.qtpl:34 +//line views/stuff.qtpl:35 func StreamUserListHTML(qw422016 *qt422016.Writer) { -//line views/stuff.qtpl:34 +//line views/stuff.qtpl:35 qw422016.N().S(`

List of users

`) -//line views/stuff.qtpl:39 +//line views/stuff.qtpl:40 var ( admins = make([]string, 0) moderators = make([]string, 0) @@ -153,303 +154,303 @@ func StreamUserListHTML(qw422016 *qt422016.Writer) { } } -//line views/stuff.qtpl:54 +//line views/stuff.qtpl:55 qw422016.N().S(`

Admins

    `) -//line views/stuff.qtpl:57 +//line views/stuff.qtpl:58 for _, name := range admins { -//line views/stuff.qtpl:57 +//line views/stuff.qtpl:58 qw422016.N().S(`
  1. `) -//line views/stuff.qtpl:58 +//line views/stuff.qtpl:59 qw422016.E().S(name) -//line views/stuff.qtpl:58 +//line views/stuff.qtpl:59 qw422016.N().S(`
  2. `) -//line views/stuff.qtpl:59 +//line views/stuff.qtpl:60 } -//line views/stuff.qtpl:59 +//line views/stuff.qtpl:60 qw422016.N().S(`

Moderators

    `) -//line views/stuff.qtpl:63 +//line views/stuff.qtpl:64 for _, name := range moderators { -//line views/stuff.qtpl:63 +//line views/stuff.qtpl:64 qw422016.N().S(`
  1. `) -//line views/stuff.qtpl:64 +//line views/stuff.qtpl:65 qw422016.E().S(name) -//line views/stuff.qtpl:64 +//line views/stuff.qtpl:65 qw422016.N().S(`
  2. `) -//line views/stuff.qtpl:65 +//line views/stuff.qtpl:66 } -//line views/stuff.qtpl:65 +//line views/stuff.qtpl:66 qw422016.N().S(`

Editors

    `) -//line views/stuff.qtpl:69 +//line views/stuff.qtpl:70 for _, name := range editors { -//line views/stuff.qtpl:69 +//line views/stuff.qtpl:70 qw422016.N().S(`
  1. `) -//line views/stuff.qtpl:70 +//line views/stuff.qtpl:71 qw422016.E().S(name) -//line views/stuff.qtpl:70 +//line views/stuff.qtpl:71 qw422016.N().S(`
  2. `) -//line views/stuff.qtpl:71 +//line views/stuff.qtpl:72 } -//line views/stuff.qtpl:71 +//line views/stuff.qtpl:72 qw422016.N().S(`
`) -//line views/stuff.qtpl:75 +//line views/stuff.qtpl:76 } -//line views/stuff.qtpl:75 +//line views/stuff.qtpl:76 func WriteUserListHTML(qq422016 qtio422016.Writer) { -//line views/stuff.qtpl:75 +//line views/stuff.qtpl:76 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/stuff.qtpl:75 +//line views/stuff.qtpl:76 StreamUserListHTML(qw422016) -//line views/stuff.qtpl:75 +//line views/stuff.qtpl:76 qt422016.ReleaseWriter(qw422016) -//line views/stuff.qtpl:75 +//line views/stuff.qtpl:76 } -//line views/stuff.qtpl:75 +//line views/stuff.qtpl:76 func UserListHTML() string { -//line views/stuff.qtpl:75 +//line views/stuff.qtpl:76 qb422016 := qt422016.AcquireByteBuffer() -//line views/stuff.qtpl:75 +//line views/stuff.qtpl:76 WriteUserListHTML(qb422016) -//line views/stuff.qtpl:75 +//line views/stuff.qtpl:76 qs422016 := string(qb422016.B) -//line views/stuff.qtpl:75 +//line views/stuff.qtpl:76 qt422016.ReleaseByteBuffer(qb422016) -//line views/stuff.qtpl:75 +//line views/stuff.qtpl:76 return qs422016 -//line views/stuff.qtpl:75 +//line views/stuff.qtpl:76 } -//line views/stuff.qtpl:77 +//line views/stuff.qtpl:78 func StreamHyphaListHTML(qw422016 *qt422016.Writer) { -//line views/stuff.qtpl:77 +//line views/stuff.qtpl:78 qw422016.N().S(`

List of hyphae

This wiki has `) -//line views/stuff.qtpl:81 +//line views/stuff.qtpl:82 qw422016.N().D(hyphae.Count()) -//line views/stuff.qtpl:81 +//line views/stuff.qtpl:82 qw422016.N().S(` hyphae.

    `) -//line views/stuff.qtpl:83 +//line views/stuff.qtpl:84 for h := range hyphae.YieldExistingHyphae() { -//line views/stuff.qtpl:83 +//line views/stuff.qtpl:84 qw422016.N().S(`
  • `) -//line views/stuff.qtpl:85 +//line views/stuff.qtpl:86 qw422016.E().S(util.BeautifulName(h.Name)) -//line views/stuff.qtpl:85 +//line views/stuff.qtpl:86 qw422016.N().S(` `) -//line views/stuff.qtpl:86 +//line views/stuff.qtpl:87 if h.BinaryPath != "" { -//line views/stuff.qtpl:86 +//line views/stuff.qtpl:87 qw422016.N().S(` `) -//line views/stuff.qtpl:87 +//line views/stuff.qtpl:88 qw422016.E().S(filepath.Ext(h.BinaryPath)[1:]) -//line views/stuff.qtpl:87 +//line views/stuff.qtpl:88 qw422016.N().S(` `) -//line views/stuff.qtpl:88 +//line views/stuff.qtpl:89 } -//line views/stuff.qtpl:88 +//line views/stuff.qtpl:89 qw422016.N().S(`
  • `) -//line views/stuff.qtpl:90 +//line views/stuff.qtpl:91 } -//line views/stuff.qtpl:90 +//line views/stuff.qtpl:91 qw422016.N().S(`
`) -//line views/stuff.qtpl:94 +//line views/stuff.qtpl:95 } -//line views/stuff.qtpl:94 +//line views/stuff.qtpl:95 func WriteHyphaListHTML(qq422016 qtio422016.Writer) { -//line views/stuff.qtpl:94 +//line views/stuff.qtpl:95 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/stuff.qtpl:94 +//line views/stuff.qtpl:95 StreamHyphaListHTML(qw422016) -//line views/stuff.qtpl:94 +//line views/stuff.qtpl:95 qt422016.ReleaseWriter(qw422016) -//line views/stuff.qtpl:94 +//line views/stuff.qtpl:95 } -//line views/stuff.qtpl:94 +//line views/stuff.qtpl:95 func HyphaListHTML() string { -//line views/stuff.qtpl:94 +//line views/stuff.qtpl:95 qb422016 := qt422016.AcquireByteBuffer() -//line views/stuff.qtpl:94 +//line views/stuff.qtpl:95 WriteHyphaListHTML(qb422016) -//line views/stuff.qtpl:94 +//line views/stuff.qtpl:95 qs422016 := string(qb422016.B) -//line views/stuff.qtpl:94 +//line views/stuff.qtpl:95 qt422016.ReleaseByteBuffer(qb422016) -//line views/stuff.qtpl:94 +//line views/stuff.qtpl:95 return qs422016 -//line views/stuff.qtpl:94 +//line views/stuff.qtpl:95 } -//line views/stuff.qtpl:96 +//line views/stuff.qtpl:97 func StreamAboutHTML(qw422016 *qt422016.Writer) { -//line views/stuff.qtpl:96 +//line views/stuff.qtpl:97 qw422016.N().S(`

About `) -//line views/stuff.qtpl:100 +//line views/stuff.qtpl:101 qw422016.E().S(cfg.WikiName) -//line views/stuff.qtpl:100 +//line views/stuff.qtpl:101 qw422016.N().S(`

See /list for information about hyphae on this wiki.

`) -//line views/stuff.qtpl:118 +//line views/stuff.qtpl:119 } -//line views/stuff.qtpl:118 +//line views/stuff.qtpl:119 func WriteAboutHTML(qq422016 qtio422016.Writer) { -//line views/stuff.qtpl:118 +//line views/stuff.qtpl:119 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/stuff.qtpl:118 +//line views/stuff.qtpl:119 StreamAboutHTML(qw422016) -//line views/stuff.qtpl:118 +//line views/stuff.qtpl:119 qt422016.ReleaseWriter(qw422016) -//line views/stuff.qtpl:118 +//line views/stuff.qtpl:119 } -//line views/stuff.qtpl:118 +//line views/stuff.qtpl:119 func AboutHTML() string { -//line views/stuff.qtpl:118 +//line views/stuff.qtpl:119 qb422016 := qt422016.AcquireByteBuffer() -//line views/stuff.qtpl:118 +//line views/stuff.qtpl:119 WriteAboutHTML(qb422016) -//line views/stuff.qtpl:118 +//line views/stuff.qtpl:119 qs422016 := string(qb422016.B) -//line views/stuff.qtpl:118 +//line views/stuff.qtpl:119 qt422016.ReleaseByteBuffer(qb422016) -//line views/stuff.qtpl:118 +//line views/stuff.qtpl:119 return qs422016 -//line views/stuff.qtpl:118 +//line views/stuff.qtpl:119 } -//line views/stuff.qtpl:120 +//line views/stuff.qtpl:121 func StreamAdminPanelHTML(qw422016 *qt422016.Writer) { -//line views/stuff.qtpl:120 +//line views/stuff.qtpl:121 qw422016.N().S(`
@@ -486,80 +487,80 @@ func StreamAdminPanelHTML(qw422016 *qt422016.Writer) {
`) -//line views/stuff.qtpl:155 +//line views/stuff.qtpl:156 } -//line views/stuff.qtpl:155 +//line views/stuff.qtpl:156 func WriteAdminPanelHTML(qq422016 qtio422016.Writer) { -//line views/stuff.qtpl:155 +//line views/stuff.qtpl:156 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/stuff.qtpl:155 +//line views/stuff.qtpl:156 StreamAdminPanelHTML(qw422016) -//line views/stuff.qtpl:155 +//line views/stuff.qtpl:156 qt422016.ReleaseWriter(qw422016) -//line views/stuff.qtpl:155 +//line views/stuff.qtpl:156 } -//line views/stuff.qtpl:155 +//line views/stuff.qtpl:156 func AdminPanelHTML() string { -//line views/stuff.qtpl:155 +//line views/stuff.qtpl:156 qb422016 := qt422016.AcquireByteBuffer() -//line views/stuff.qtpl:155 +//line views/stuff.qtpl:156 WriteAdminPanelHTML(qb422016) -//line views/stuff.qtpl:155 +//line views/stuff.qtpl:156 qs422016 := string(qb422016.B) -//line views/stuff.qtpl:155 +//line views/stuff.qtpl:156 qt422016.ReleaseByteBuffer(qb422016) -//line views/stuff.qtpl:155 +//line views/stuff.qtpl:156 return qs422016 -//line views/stuff.qtpl:155 +//line views/stuff.qtpl:156 } -//line views/stuff.qtpl:157 +//line views/stuff.qtpl:158 func streamomnipresentScripts(qw422016 *qt422016.Writer) { -//line views/stuff.qtpl:157 +//line views/stuff.qtpl:158 qw422016.N().S(` `) -//line views/stuff.qtpl:158 +//line views/stuff.qtpl:159 for _, scriptPath := range cfg.OmnipresentScripts { -//line views/stuff.qtpl:158 +//line views/stuff.qtpl:159 qw422016.N().S(` `) -//line views/stuff.qtpl:160 +//line views/stuff.qtpl:161 } -//line views/stuff.qtpl:160 +//line views/stuff.qtpl:161 qw422016.N().S(` `) -//line views/stuff.qtpl:161 +//line views/stuff.qtpl:162 } -//line views/stuff.qtpl:161 +//line views/stuff.qtpl:162 func writeomnipresentScripts(qq422016 qtio422016.Writer) { -//line views/stuff.qtpl:161 +//line views/stuff.qtpl:162 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/stuff.qtpl:161 +//line views/stuff.qtpl:162 streamomnipresentScripts(qw422016) -//line views/stuff.qtpl:161 +//line views/stuff.qtpl:162 qt422016.ReleaseWriter(qw422016) -//line views/stuff.qtpl:161 +//line views/stuff.qtpl:162 } -//line views/stuff.qtpl:161 +//line views/stuff.qtpl:162 func omnipresentScripts() string { -//line views/stuff.qtpl:161 +//line views/stuff.qtpl:162 qb422016 := qt422016.AcquireByteBuffer() -//line views/stuff.qtpl:161 +//line views/stuff.qtpl:162 writeomnipresentScripts(qb422016) -//line views/stuff.qtpl:161 +//line views/stuff.qtpl:162 qs422016 := string(qb422016.B) -//line views/stuff.qtpl:161 +//line views/stuff.qtpl:162 qt422016.ReleaseByteBuffer(qb422016) -//line views/stuff.qtpl:161 +//line views/stuff.qtpl:162 return qs422016 -//line views/stuff.qtpl:161 +//line views/stuff.qtpl:162 } diff --git a/web/web.go b/web/web.go index 95b3c44..ed0ca78 100644 --- a/web/web.go +++ b/web/web.go @@ -6,20 +6,20 @@ package web import ( "fmt" "io" - "io/ioutil" "log" + "mime" "net/http" "net/url" - "os" - "strings" - "github.com/bouncepaw/mycorrhiza/assets" "github.com/bouncepaw/mycorrhiza/cfg" + "github.com/bouncepaw/mycorrhiza/static" "github.com/bouncepaw/mycorrhiza/user" "github.com/bouncepaw/mycorrhiza/util" "github.com/bouncepaw/mycorrhiza/views" ) +var stylesheets = []string{"default.css", "custom.css"} + // httpErr is used by many handlers to signal errors in a compact way. func httpErr(w http.ResponseWriter, status int, name, title, errMsg string) { log.Println(errMsg, "for", name) @@ -41,51 +41,16 @@ func httpErr(w http.ResponseWriter, status int, name, title, errMsg string) { func handlerStyle(w http.ResponseWriter, rq *http.Request) { util.PrepareRq(rq) - if _, err := os.Stat(cfg.WikiDir + "/assets/common.css"); err == nil { - http.ServeFile(w, rq, cfg.WikiDir+"/assets/common.css") - } else { - w.Header().Set("Content-Type", "text/css;charset=utf-8") - w.Write([]byte(assets.DefaultCSS())) - } - if bytes, err := ioutil.ReadFile(cfg.WikiDir + "/assets/custom.css"); err == nil { - w.Write(bytes) - } -} -func handlerToolbar(w http.ResponseWriter, rq *http.Request) { - util.PrepareRq(rq) - w.Header().Set("Content-Type", "text/javascript;charset=utf-8") - w.Write([]byte(assets.ToolbarJS())) -} - -// handlerIcon serves the requested icon. All icons are distributed as part of the Mycorrhiza binary. -// -// See assets/assets/icon/ for icons themselves, see assets/assets.qtpl for their sources. -func handlerIcon(w http.ResponseWriter, rq *http.Request) { - iconName := strings.TrimPrefix(rq.URL.Path, "/assets/icon/") - if iconName == "https" { - iconName = "http" - } - w.Header().Set("Content-Type", "image/svg+xml") - icon := func() string { - switch iconName { - case "gemini": - return assets.IconGemini() - case "mailto": - return assets.IconMailto() - case "gopher": - return assets.IconGopher() - case "feed": - return assets.IconFeed() - default: - return assets.IconHTTP() + w.Header().Set("Content-Type", mime.TypeByExtension("css")) + for _, name := range stylesheets { + file, err := static.FS.Open(name) + if err != nil { + continue } - }() - _, err := io.WriteString(w, icon) - if err != nil { - log.Println(err) + io.Copy(w, file) + file.Close() } - } func handlerUserList(w http.ResponseWriter, rq *http.Request) { @@ -113,15 +78,15 @@ func Init() { initHistory() initStuff() + // Miscellaneous http.HandleFunc("/user-list/", handlerUserList) - http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir(cfg.WikiDir+"/static")))) - http.HandleFunc("/favicon.ico", func(w http.ResponseWriter, rq *http.Request) { - http.ServeFile(w, rq, cfg.WikiDir+"/static/favicon.ico") - }) - http.HandleFunc("/assets/common.css", handlerStyle) - http.HandleFunc("/assets/toolbar.js", handlerToolbar) - http.HandleFunc("/assets/icon/", handlerIcon) http.HandleFunc("/robots.txt", handlerRobotsTxt) + + // Static assets + http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.FS(static.FS)))) + http.HandleFunc("/static/style.css", handlerStyle) + + // Index page http.HandleFunc("/", func(w http.ResponseWriter, rq *http.Request) { addr, _ := url.Parse("/hypha/" + cfg.HomeHypha) // Let's pray it never fails rq.URL = addr