1
0
mirror of https://github.com/osmarks/mycorrhiza.git synced 2025-01-06 10:00:26 +00:00

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).
This commit is contained in:
handlerug 2021-06-12 20:51:28 +07:00
parent e1f6a64ace
commit 839f8bc2d6
No known key found for this signature in database
GPG Key ID: 38009F0605051491
21 changed files with 292 additions and 1126 deletions

View File

@ -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 %}

View File

@ -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(`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="16" height="16"><path fill="#999" d="M12 22C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10-4.477 10-10 10zm-2.29-2.333A17.9 17.9 0 0 1 8.027 13H4.062a8.008 8.008 0 0 0 5.648 6.667zM10.03 13c.151 2.439.848 4.73 1.97 6.752A15.905 15.905 0 0 0 13.97 13h-3.94zm9.908 0h-3.965a17.9 17.9 0 0 1-1.683 6.667A8.008 8.008 0 0 0 19.938 13zM4.062 11h3.965A17.9 17.9 0 0 1 9.71 4.333 8.008 8.008 0 0 0 4.062 11zm5.969 0h3.938A15.905 15.905 0 0 0 12 4.248 15.905 15.905 0 0 0 10.03 11zm4.259-6.667A17.9 17.9 0 0 1 15.973 11h3.965a8.008 8.008 0 0 0-5.648-6.667z"/></svg>
`)
//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(`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="16" height="16"><path fill="#999" d="M15.502 20A6.523 6.523 0 0 1 12 23.502 6.523 6.523 0 0 1 8.498 20h2.26c.326.489.747.912 1.242 1.243.495-.33.916-.754 1.243-1.243h2.259zM18 14.805l2 2.268V19H4v-1.927l2-2.268V9c0-3.483 2.504-6.447 6-7.545C15.496 2.553 18 5.517 18 9v5.805zM17.27 17L16 15.56V9c0-2.318-1.57-4.43-4-5.42C9.57 4.57 8 6.681 8 9v6.56L6.73 17h10.54zM12 11a2 2 0 1 1 0-4 2 2 0 0 1 0 4z"/></svg>
`)
//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(`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="16" height="16"><path fill="#999" d="M3 3h18a1 1 0 0 1 1 1v16a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1zm17 4.238l-7.928 7.1L4 7.216V19h16V7.238zM4.511 5l7.55 6.662L19.502 5H4.511z"/></svg>
`)
//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(`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="16" height="16">
<path fill="#999" d="M447.238,204.944v-70.459c0-8.836-7.164-16-16-16c-34.051,0-64.414,21.118-75.079,55.286
C226.094,41.594,0,133.882,0,319.435c0,0.071,0.01,0.14,0.011,0.21c0.116,44.591,36.423,80.833,81.04,80.833h171.203
c8.836,0,16-7.164,16-16c0-8.836-7.164-16-16-16H81.051c-21.441,0-39.7-13.836-46.351-33.044H496c8.836,0,16-7.164,16-16
C512,271.82,486.82,228.692,447.238,204.944z M415.238,153.216v37.805c-10.318-2.946-19.556-4.305-29.342-4.937
C390.355,168.611,402.006,157.881,415.238,153.216z M295.484,303.435L295.484,303.435c-7.562-41.495-43.948-73.062-87.593-73.062
c-8.836,0-16,7.164-16,16c0,8.836,7.164,16,16,16c25.909,0,47.826,17.364,54.76,41.062H32.722
c14.415-159.15,218.064-217.856,315.136-90.512c3.545,4.649,9.345,6.995,15.124,6.118
c55.425-8.382,107.014,29.269,115.759,84.394H295.484z"/>
<circle fill="#999" cx="415.238" cy="260.05" r="21.166"/>
</svg>
`)
//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(`<svg xmlns="http://www.w3.org/2000/svg"
id="RSSicon"
viewBox="0 0 8 8" width="256" height="256">
<title>RSS feed icon</title>
<style type="text/css">
.button {stroke: none; fill: orange;}
.symbol {stroke: none; fill: white;}
</style>
<rect class="button" width="8" height="8" rx="1.5" />
<circle class="symbol" cx="2" cy="6" r="1" />
<path class="symbol" d="m 1,4 a 3,3 0 0 1 3,3 h 1 a 4,4 0 0 0 -4,-4 z" />
<path class="symbol" d="m 1,2 a 5,5 0 0 1 5,5 h 1 a 6,6 0 0 0 -6,-6 z" />
</svg>
`)
//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
}

12
flag.go
View File

@ -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)
}

2
go.mod
View File

@ -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

View File

@ -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()

View File

@ -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; }

10
static/icon/README.md Normal file
View File

@ -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.

View File

Before

Width:  |  Height:  |  Size: 531 B

After

Width:  |  Height:  |  Size: 531 B

View File

Before

Width:  |  Height:  |  Size: 473 B

After

Width:  |  Height:  |  Size: 473 B

View File

Before

Width:  |  Height:  |  Size: 951 B

After

Width:  |  Height:  |  Size: 951 B

View File

Before

Width:  |  Height:  |  Size: 627 B

After

Width:  |  Height:  |  Size: 627 B

View File

Before

Width:  |  Height:  |  Size: 261 B

After

Width:  |  Height:  |  Size: 261 B

50
static/static.go Normal file
View File

@ -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,
},
}
}

View File

@ -45,7 +45,7 @@ if err != nil {
recent changes
</nav>
<p><img class="icon" width="20" height="20" src="/assets/icon/feed">Subscribe via <a href="/recent-changes-rss">RSS</a>, <a href="/recent-changes-atom">Atom</a> or <a href="/recent-changes-json">JSON feed</a>.</p>
<p><img class="icon" width="20" height="20" src="/static/icon/feed.svg">Subscribe via <a href="/recent-changes-rss">RSS</a>, <a href="/recent-changes-atom">Atom</a> or <a href="/recent-changes-json">JSON feed</a>.</p>
{% comment %}
Here I am, willing to add some accessibility using ARIA. Turns out,

View File

@ -163,7 +163,7 @@ func StreamRecentChangesHTML(qw422016 *qt422016.Writer, n int) {
recent changes
</nav>
<p><img class="icon" width="20" height="20" src="/assets/icon/feed">Subscribe via <a href="/recent-changes-rss">RSS</a>, <a href="/recent-changes-atom">Atom</a> or <a href="/recent-changes-json">JSON feed</a>.</p>
<p><img class="icon" width="20" height="20" src="/static/icon/feed.svg">Subscribe via <a href="/recent-changes-rss">RSS</a>, <a href="/recent-changes-atom">Atom</a> or <a href="/recent-changes-json">JSON feed</a>.</p>
`)
//line views/history.qtpl:55

View File

@ -65,7 +65,7 @@
{% endif %}
</section>
</aside>
<script src="/assets/toolbar.js"></script>
<script src="/static/toolbar.js"></script>
{% endfunc %}
{% func EditHTML(rq *http.Request, hyphaName, textAreaFill, warning string) %}

View File

@ -141,7 +141,7 @@ func StreamToolbar(qw422016 *qt422016.Writer, u *user.User) {
qw422016.N().S(`
</section>
</aside>
<script src="/assets/toolbar.js"></script>
<script src="/static/toolbar.js"></script>
`)
//line views/mutators.qtpl:69
}

View File

@ -8,10 +8,11 @@
<!doctype html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta charset="utf-8">
<link rel="stylesheet" type="text/css" href="/assets/common.css">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{%s title %}</title>
<link rel="shortcut icon" href="/static/favicon.ico">
<link rel="stylesheet" type="text/css" href="/static/style.css">
{% for _, el := range headElements %}{%s= el %}{% endfor %}
</head>
<body>

View File

@ -39,22 +39,23 @@ func StreamBaseHTML(qw422016 *qt422016.Writer, title, body string, u *user.User,
<!doctype html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta charset="utf-8">
<link rel="stylesheet" type="text/css" href="/assets/common.css">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>`)
//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(`</title>
<link rel="shortcut icon" href="/static/favicon.ico">
<link rel="stylesheet" type="text/css" href="/static/style.css">
`)
//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(`
</head>
<body>
@ -62,81 +63,81 @@ func StreamBaseHTML(qw422016 *qt422016.Writer, title, body string, u *user.User,
<nav class="header-links main-width">
<ul class="header-links__list">
`)
//line views/stuff.qtpl:21
//line views/stuff.qtpl:22
for _, link := range cfg.HeaderLinks {
//line views/stuff.qtpl:21
//line views/stuff.qtpl:22
qw422016.N().S(` <li class="header-links__entry"><a class="header-links__link" href="`)
//line views/stuff.qtpl:22
//line views/stuff.qtpl:23
qw422016.E().S(link.Href)
//line views/stuff.qtpl:22
//line views/stuff.qtpl:23
qw422016.N().S(`">`)
//line views/stuff.qtpl:22
//line views/stuff.qtpl:23
qw422016.E().S(link.Display)
//line views/stuff.qtpl:22
//line views/stuff.qtpl:23
qw422016.N().S(`</a></li>
`)
//line views/stuff.qtpl:23
//line views/stuff.qtpl:24
}
//line views/stuff.qtpl:23
//line views/stuff.qtpl:24
qw422016.N().S(` `)
//line views/stuff.qtpl:24
//line views/stuff.qtpl:25
qw422016.N().S(UserMenuHTML(u))
//line views/stuff.qtpl:24
//line views/stuff.qtpl:25
qw422016.N().S(`
</ul>
</nav>
</header>
`)
//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(`
</body>
</html>
`)
//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(`
<div class="layout">
<main class="main-width user-list">
<h1>List of users</h1>
`)
//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(`
<section>
<h2>Admins</h2>
<ol>`)
//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(`
<li><a href="/page/`)
//line views/stuff.qtpl:58
//line views/stuff.qtpl:59
qw422016.E().S(cfg.UserHypha)
//line views/stuff.qtpl:58
//line views/stuff.qtpl:59
qw422016.N().S(`/`)
//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(`">`)
//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(`</a></li>
`)
//line views/stuff.qtpl:59
//line views/stuff.qtpl:60
}
//line views/stuff.qtpl:59
//line views/stuff.qtpl:60
qw422016.N().S(`</ol>
</section>
<section>
<h2>Moderators</h2>
<ol>`)
//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(`
<li><a href="/page/`)
//line views/stuff.qtpl:64
//line views/stuff.qtpl:65
qw422016.E().S(cfg.UserHypha)
//line views/stuff.qtpl:64
//line views/stuff.qtpl:65
qw422016.N().S(`/`)
//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(`">`)
//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(`</a></li>
`)
//line views/stuff.qtpl:65
//line views/stuff.qtpl:66
}
//line views/stuff.qtpl:65
//line views/stuff.qtpl:66
qw422016.N().S(`</ol>
</section>
<section>
<h2>Editors</h2>
<ol>`)
//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(`
<li><a href="/page/`)
//line views/stuff.qtpl:70
//line views/stuff.qtpl:71
qw422016.E().S(cfg.UserHypha)
//line views/stuff.qtpl:70
//line views/stuff.qtpl:71
qw422016.N().S(`/`)
//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(`">`)
//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(`</a></li>
`)
//line views/stuff.qtpl:71
//line views/stuff.qtpl:72
}
//line views/stuff.qtpl:71
//line views/stuff.qtpl:72
qw422016.N().S(`</ol>
</section>
</main>
</div>
`)
//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(`
<div class="layout">
<main class="main-width">
<h1>List of hyphae</h1>
<p>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.</p>
<ul class="hypha-list">
`)
//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(`
<li class="hypha-list__entry">
<a class="hypha-list__link" href="/hypha/`)
//line views/stuff.qtpl:85
//line views/stuff.qtpl:86
qw422016.E().S(h.Name)
//line views/stuff.qtpl:85
//line views/stuff.qtpl:86
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(`</a>
`)
//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(`
<span class="hypha-list__amnt-type">`)
//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(`</span>
`)
//line views/stuff.qtpl:88
//line views/stuff.qtpl:89
}
//line views/stuff.qtpl:88
//line views/stuff.qtpl:89
qw422016.N().S(`
</li>
`)
//line views/stuff.qtpl:90
//line views/stuff.qtpl:91
}
//line views/stuff.qtpl:90
//line views/stuff.qtpl:91
qw422016.N().S(`
</ul>
</main>
</div>
`)
//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(`
<div class="layout">
<main class="main-width">
<section>
<h1>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(`</h1>
<ul>
<li><b><a href="https://mycorrhiza.lesarbr.es">MycorrhizaWiki</a> version:</b> 1.2.0 indev</li>
`)
//line views/stuff.qtpl:103
//line views/stuff.qtpl:104
if user.AuthUsed {
//line views/stuff.qtpl:103
//line views/stuff.qtpl:104
qw422016.N().S(` <li><b>User count:</b> `)
//line views/stuff.qtpl:104
//line views/stuff.qtpl:105
qw422016.N().D(user.Count())
//line views/stuff.qtpl:104
//line views/stuff.qtpl:105
qw422016.N().S(`</li>
<li><b>Home page:</b> <a href="/">`)
//line views/stuff.qtpl:105
//line views/stuff.qtpl:106
qw422016.E().S(cfg.HomeHypha)
//line views/stuff.qtpl:105
//line views/stuff.qtpl:106
qw422016.N().S(`</a></li>
<li><b>Administrators:</b>`)
//line views/stuff.qtpl:106
//line views/stuff.qtpl:107
for i, username := range user.ListUsersWithGroup("admin") {
//line views/stuff.qtpl:107
//line views/stuff.qtpl:108
if i > 0 {
//line views/stuff.qtpl:107
//line views/stuff.qtpl:108
qw422016.N().S(`<span aria-hidden="true">, </span>
`)
//line views/stuff.qtpl:108
//line views/stuff.qtpl:109
}
//line views/stuff.qtpl:108
//line views/stuff.qtpl:109
qw422016.N().S(` <a href="/page/`)
//line views/stuff.qtpl:109
//line views/stuff.qtpl:110
qw422016.E().S(cfg.UserHypha)
//line views/stuff.qtpl:109
//line views/stuff.qtpl:110
qw422016.N().S(`/`)
//line views/stuff.qtpl:109
//line views/stuff.qtpl:110
qw422016.E().S(username)
//line views/stuff.qtpl:109
//line views/stuff.qtpl:110
qw422016.N().S(`">`)
//line views/stuff.qtpl:109
//line views/stuff.qtpl:110
qw422016.E().S(username)
//line views/stuff.qtpl:109
//line views/stuff.qtpl:110
qw422016.N().S(`</a>`)
//line views/stuff.qtpl:109
//line views/stuff.qtpl:110
}
//line views/stuff.qtpl:109
//line views/stuff.qtpl:110
qw422016.N().S(`</li>
`)
//line views/stuff.qtpl:110
//line views/stuff.qtpl:111
} else {
//line views/stuff.qtpl:110
//line views/stuff.qtpl:111
qw422016.N().S(` <li>This wiki does not use authorization</li>
`)
//line views/stuff.qtpl:112
//line views/stuff.qtpl:113
}
//line views/stuff.qtpl:112
//line views/stuff.qtpl:113
qw422016.N().S(` </ul>
<p>See <a href="/list">/list</a> for information about hyphae on this wiki.</p>
</section>
</main>
</div>
`)
//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(`
<div class="layout">
<main class="main-width">
@ -486,80 +487,80 @@ func StreamAdminPanelHTML(qw422016 *qt422016.Writer) {
</main>
</div>
`)
//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(`
<script src="`)
//line views/stuff.qtpl:159
//line views/stuff.qtpl:160
qw422016.E().S(scriptPath)
//line views/stuff.qtpl:159
//line views/stuff.qtpl:160
qw422016.N().S(`"></script>
`)
//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
}

View File

@ -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