Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3313e17efa | ||
|
|
f8bba997bf | ||
|
|
4cf4d1695f | ||
|
|
1b5abe4de1 | ||
|
|
5dfbbdb775 | ||
|
|
7e1948c93f | ||
|
|
3718f6ec7c | ||
|
|
ce108bc07d | ||
|
|
da84a76e79 | ||
|
|
d679eb4661 | ||
|
|
0f7525a23c | ||
|
|
727280147a |
1
.gitignore
vendored
1
.gitignore
vendored
@ -1 +1,2 @@
|
||||
mycorrhiza
|
||||
.idea
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
**Mycorrhiza Wiki** is a lightweight file-system wiki engine that uses Git for keeping history. [Main wiki](https://mycorrhiza.wiki)
|
||||
|
||||
<img src="https://mycorrhiza.wiki/binary/release/1.15/screenshot" alt="A screenshot of mycorrhiza.wiki's home page in the Safari browser" width="700">
|
||||
<img src="https://mycorrhiza.wiki/binary/release/1.15.1/screenshot" alt="A screenshot of mycorrhiza.wiki's home page in the Safari browser" width="700">
|
||||
|
||||
|
||||
## Features
|
||||
|
||||
10
go.mod
10
go.mod
@ -7,16 +7,14 @@ require (
|
||||
github.com/go-ini/ini v1.67.0
|
||||
github.com/gorilla/feeds v1.2.0
|
||||
github.com/gorilla/mux v1.8.1
|
||||
github.com/valyala/quicktemplate v1.7.0
|
||||
golang.org/x/crypto v0.27.0
|
||||
golang.org/x/term v0.24.0
|
||||
golang.org/x/text v0.18.0
|
||||
golang.org/x/crypto v0.31.0
|
||||
golang.org/x/term v0.27.0
|
||||
golang.org/x/text v0.21.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/stretchr/testify v1.7.0 // indirect
|
||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||
golang.org/x/sys v0.25.0 // indirect
|
||||
golang.org/x/sys v0.28.0 // indirect
|
||||
)
|
||||
|
||||
// Use this trick to test local Mycomarkup changes, replace the path with yours,
|
||||
|
||||
37
go.sum
37
go.sum
@ -1,18 +1,13 @@
|
||||
git.sr.ht/~bouncepaw/mycomarkup/v5 v5.6.0 h1:zAZwMF+6x8U/nunpqPRVYoDiqVUMBHI04PG8GsDrFOk=
|
||||
git.sr.ht/~bouncepaw/mycomarkup/v5 v5.6.0/go.mod h1:TCzFBqW11En4EjLfcQtJu8C/Ro7FIFR8vZ+nM9f6Q28=
|
||||
github.com/andybalholm/brotli v1.0.2/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
|
||||
github.com/andybalholm/brotli v1.0.3/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/go-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A=
|
||||
github.com/go-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
|
||||
github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/gorilla/feeds v1.2.0 h1:O6pBiXJ5JHhPvqy53NsjKOThq+dNFm8+DFrxBEdzSCc=
|
||||
github.com/gorilla/feeds v1.2.0/go.mod h1:WMib8uJP3BbY+X8Szd1rA5Pzhdfh+HCCAYT2z7Fza6Y=
|
||||
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
|
||||
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
|
||||
github.com/klauspost/compress v1.13.4/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
|
||||
github.com/klauspost/compress v1.13.5/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
@ -24,30 +19,14 @@ github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/f
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||
github.com/valyala/fasthttp v1.30.0/go.mod h1:2rsYD01CKFrjjsvFxx75KlEUNpWNBY9JWD3K/7o2Cus=
|
||||
github.com/valyala/quicktemplate v1.7.0 h1:LUPTJmlVcb46OOUY3IeD9DojFpAVbsG+5WFTcjMJzCM=
|
||||
github.com/valyala/quicktemplate v1.7.0/go.mod h1:sqKJnoaOF88V07vkO+9FL8fb9uZg/VPSJnLYn+LmLk8=
|
||||
github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
|
||||
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
|
||||
golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A=
|
||||
golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
|
||||
golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.24.0 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM=
|
||||
golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
|
||||
golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
|
||||
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
||||
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
|
||||
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q=
|
||||
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
|
||||
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
|
||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
||||
@ -6,7 +6,7 @@ You can upload any media file, but only those listed below will be displayed on
|
||||
|
||||
* **Images:** jpg, gif, png, webp, svg, ico
|
||||
* **Video:** ogg, webm, mp4
|
||||
* **Audio:** ogg, webm, mp3
|
||||
* **Audio:** ogg, webm, mp3, flac, wav
|
||||
|
||||
== How to upload media?
|
||||
For non-existent hyphae, upload a file in the //Upload media// section.
|
||||
|
||||
@ -2,16 +2,67 @@ package history
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"html"
|
||||
"log/slog"
|
||||
"net/url"
|
||||
"os"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/bouncepaw/mycorrhiza/internal/cfg"
|
||||
"github.com/bouncepaw/mycorrhiza/internal/files"
|
||||
)
|
||||
|
||||
// WithRevisions returns an HTML representation of `revs` that is meant to be inserted in a history page.
|
||||
func WithRevisions(hyphaName string, revs []Revision) string {
|
||||
var buf strings.Builder
|
||||
|
||||
for _, grp := range groupRevisionsByMonth(revs) {
|
||||
currentYear := grp[0].Time.Year()
|
||||
currentMonth := grp[0].Time.Month()
|
||||
sectionId := fmt.Sprintf("%04d-%02d", currentYear, currentMonth)
|
||||
|
||||
buf.WriteString(fmt.Sprintf(
|
||||
`<section class="history__month">
|
||||
<a href="#%s" class="history__month-anchor">
|
||||
<h2 id="%s" class="history__month-title">%d %s</h2>
|
||||
</a>
|
||||
<ul class="history__entries">`,
|
||||
sectionId, sectionId, currentYear, currentMonth.String(),
|
||||
))
|
||||
|
||||
for _, rev := range grp {
|
||||
buf.WriteString(fmt.Sprintf(
|
||||
`<li class="history__entry">
|
||||
<a class="history-entry" href="/rev/%s/%s">
|
||||
<time class="history-entry__time">%s</time>
|
||||
</a>
|
||||
<span class="history-entry__hash"><a href="/primitive-diff/%s/%s">%s</a></span>
|
||||
<span class="history-entry__msg">%s</span>`,
|
||||
rev.Hash, hyphaName,
|
||||
rev.timeToDisplay(),
|
||||
rev.Hash, hyphaName, rev.Hash,
|
||||
html.EscapeString(rev.Message),
|
||||
))
|
||||
|
||||
if rev.Username != "anon" {
|
||||
buf.WriteString(fmt.Sprintf(
|
||||
`<span class="history-entry__author">by <a href="/hypha/%s/%s" rel="author">%s</a></span>`,
|
||||
cfg.UserHypha, rev.Username, rev.Username,
|
||||
))
|
||||
}
|
||||
|
||||
buf.WriteString("</li>\n")
|
||||
}
|
||||
|
||||
buf.WriteString(`</ul></section>`)
|
||||
}
|
||||
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// Revision represents a revision of a hypha.
|
||||
type Revision struct {
|
||||
// Hash is usually short.
|
||||
@ -24,6 +75,62 @@ type Revision struct {
|
||||
hyphaeAffectedBuf []string
|
||||
}
|
||||
|
||||
// HyphaeDiffsHTML returns a comma-separated list of diffs links of current revision for every affected file as HTML string.
|
||||
func (rev Revision) HyphaeDiffsHTML() string {
|
||||
entries := rev.hyphaeAffected()
|
||||
if len(entries) == 1 {
|
||||
return fmt.Sprintf(
|
||||
`<a href="/primitive-diff/%s/%s">%s</a>`,
|
||||
rev.Hash, entries[0], rev.Hash,
|
||||
)
|
||||
}
|
||||
|
||||
var buf strings.Builder
|
||||
for i, hyphaName := range entries {
|
||||
if i > 0 {
|
||||
buf.WriteString(`<span aria-hidden="true">, </span>`)
|
||||
}
|
||||
buf.WriteString(`<a href="/primitive-diff/`)
|
||||
buf.WriteString(rev.Hash)
|
||||
buf.WriteString(`/`)
|
||||
buf.WriteString(hyphaName)
|
||||
buf.WriteString(`">`)
|
||||
if i == 0 {
|
||||
buf.WriteString(rev.Hash)
|
||||
buf.WriteString(" ")
|
||||
}
|
||||
buf.WriteString(hyphaName)
|
||||
buf.WriteString(`</a>`)
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// descriptionForFeed generates a good enough HTML contents for a web feed.
|
||||
func (rev *Revision) descriptionForFeed() string {
|
||||
return fmt.Sprintf(
|
||||
`<p><b>%s</b> (by %s at %s)</p>
|
||||
<p>Hyphae affected: %s</p>
|
||||
<pre><code>%s</code></pre>`,
|
||||
rev.Message, rev.Username, rev.TimeString(),
|
||||
rev.HyphaeLinksHTML(),
|
||||
rev.textDiff(),
|
||||
)
|
||||
}
|
||||
|
||||
// HyphaeLinksHTML returns a comma-separated list of hyphae that were affected by this revision as HTML string.
|
||||
func (rev Revision) HyphaeLinksHTML() string {
|
||||
var buf strings.Builder
|
||||
for i, hyphaName := range rev.hyphaeAffected() {
|
||||
if i > 0 {
|
||||
buf.WriteString(`<span aria-hidden="true">, <span>`)
|
||||
}
|
||||
|
||||
urlSafeHyphaName := url.PathEscape(hyphaName)
|
||||
buf.WriteString(fmt.Sprintf(`<a href="/hypha/%s">%s</a>`, urlSafeHyphaName, hyphaName))
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// gitLog calls `git log` and parses the results.
|
||||
func gitLog(args ...string) ([]Revision, error) {
|
||||
args = append([]string{
|
||||
|
||||
@ -1,73 +0,0 @@
|
||||
{% import "fmt" %}
|
||||
{% import "github.com/bouncepaw/mycorrhiza/internal/cfg" %}
|
||||
|
||||
HyphaeLinksHTML returns a comma-separated list of hyphae that were affected by this revision as HTML string.
|
||||
{% func (rev Revision) HyphaeLinksHTML() %}
|
||||
{% stripspace %}
|
||||
{% for i, hyphaName := range rev.hyphaeAffected() %}
|
||||
{% if i > 0 %}
|
||||
<span aria-hidden="true">, </span>
|
||||
{% endif %}
|
||||
<a href="/hypha/{%s hyphaName %}">{%s hyphaName %}</a>
|
||||
{% endfor %}
|
||||
{% endstripspace %}
|
||||
{% endfunc %}
|
||||
|
||||
|
||||
HyphaeDiffsHTML returns a comma-separated list of diffs links of current revision for every affected file as HTML string.
|
||||
{% func (rev Revision) HyphaeDiffsHTML() %}
|
||||
{% code entries := rev.hyphaeAffected() %}
|
||||
{% stripspace %}
|
||||
{% if len(entries) == 1 %}
|
||||
<a href="/primitive-diff/{%s rev.Hash %}/{%s entries[0] %}">{%s rev.Hash %}</a>
|
||||
{% else %}
|
||||
{% for i, hyphaName := range entries %}
|
||||
{% if i > 0 %}
|
||||
<span aria-hidden="true">, </span>
|
||||
{% endif %}
|
||||
<a href="/primitive-diff/{%s rev.Hash %}/{%s hyphaName %}">
|
||||
{% if i == 0 %}
|
||||
{%s rev.Hash %}
|
||||
{% endif %}
|
||||
{%s hyphaName %}</a>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endstripspace %}
|
||||
{% endfunc %}
|
||||
|
||||
descriptionForFeed generates a good enough HTML contents for a web feed.
|
||||
{% func (rev *Revision) descriptionForFeed() %}
|
||||
<p><b>{%s rev.Message %}</b> (by {%s rev.Username %} at {%s rev.TimeString() %})</p>
|
||||
<p>Hyphae affected: {%= rev.HyphaeLinksHTML() %}</p>
|
||||
<pre><code>{%s rev.textDiff() %}</code></pre>
|
||||
{% endfunc %}
|
||||
|
||||
WithRevisions returns an html representation of `revs` that is meant to be inserted in a history page.
|
||||
{% func WithRevisions(hyphaName string, revs []Revision) %}
|
||||
{% for _, grp := range groupRevisionsByMonth(revs) %}
|
||||
{% code
|
||||
currentYear := grp[0].Time.Year()
|
||||
currentMonth := grp[0].Time.Month()
|
||||
sectionId := fmt.Sprintf("%04d-%02d", currentYear, currentMonth)
|
||||
%}
|
||||
<section class="history__month">
|
||||
<a href="#{%s sectionId %}" class="history__month-anchor">
|
||||
<h2 id="{%s sectionId %}" class="history__month-title">{%d currentYear %} {%s currentMonth.String() %}</h2>
|
||||
</a>
|
||||
<ul class="history__entries">
|
||||
{% for _, rev := range grp %}
|
||||
<li class="history__entry">
|
||||
<a class="history-entry" href="/rev/{%s rev.Hash %}/{%s hyphaName %}">
|
||||
<time class="history-entry__time">{%s rev.timeToDisplay() %}</time>
|
||||
</a>
|
||||
<span class="history-entry__hash"><a href="/primitive-diff/{%s rev.Hash %}/{%s hyphaName %}">{%s rev.Hash %}</a></span>
|
||||
<span class="history-entry__msg">{%s rev.Message %}</span>
|
||||
{% if rev.Username != "anon" %}
|
||||
<span class="history-entry__author">by <a href="/hypha/{%s cfg.UserHypha %}/{%s rev.Username %}" rel="author">{%s rev.Username %}</a></span>
|
||||
{% endif %}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</section>
|
||||
{% endfor %}
|
||||
{% endfunc %}
|
||||
@ -1,384 +0,0 @@
|
||||
// Code generated by qtc from "view.qtpl". DO NOT EDIT.
|
||||
// See https://github.com/valyala/quicktemplate for details.
|
||||
|
||||
//line history/view.qtpl:1
|
||||
package history
|
||||
|
||||
//line history/view.qtpl:1
|
||||
import "fmt"
|
||||
|
||||
//line history/view.qtpl:2
|
||||
import "github.com/bouncepaw/mycorrhiza/internal/cfg"
|
||||
|
||||
// HyphaeLinksHTML returns a comma-separated list of hyphae that were affected by this revision as HTML string.
|
||||
|
||||
//line history/view.qtpl:5
|
||||
import (
|
||||
qtio422016 "io"
|
||||
|
||||
qt422016 "github.com/valyala/quicktemplate"
|
||||
)
|
||||
|
||||
//line history/view.qtpl:5
|
||||
var (
|
||||
_ = qtio422016.Copy
|
||||
_ = qt422016.AcquireByteBuffer
|
||||
)
|
||||
|
||||
//line history/view.qtpl:5
|
||||
func (rev Revision) StreamHyphaeLinksHTML(qw422016 *qt422016.Writer) {
|
||||
//line history/view.qtpl:5
|
||||
qw422016.N().S(`
|
||||
`)
|
||||
//line history/view.qtpl:7
|
||||
for i, hyphaName := range rev.hyphaeAffected() {
|
||||
//line history/view.qtpl:8
|
||||
if i > 0 {
|
||||
//line history/view.qtpl:8
|
||||
qw422016.N().S(`<span aria-hidden="true">, </span>`)
|
||||
//line history/view.qtpl:10
|
||||
}
|
||||
//line history/view.qtpl:10
|
||||
qw422016.N().S(`<a href="/hypha/`)
|
||||
//line history/view.qtpl:11
|
||||
qw422016.E().S(hyphaName)
|
||||
//line history/view.qtpl:11
|
||||
qw422016.N().S(`">`)
|
||||
//line history/view.qtpl:11
|
||||
qw422016.E().S(hyphaName)
|
||||
//line history/view.qtpl:11
|
||||
qw422016.N().S(`</a>`)
|
||||
//line history/view.qtpl:12
|
||||
}
|
||||
//line history/view.qtpl:13
|
||||
qw422016.N().S(`
|
||||
`)
|
||||
//line history/view.qtpl:14
|
||||
}
|
||||
|
||||
//line history/view.qtpl:14
|
||||
func (rev Revision) WriteHyphaeLinksHTML(qq422016 qtio422016.Writer) {
|
||||
//line history/view.qtpl:14
|
||||
qw422016 := qt422016.AcquireWriter(qq422016)
|
||||
//line history/view.qtpl:14
|
||||
rev.StreamHyphaeLinksHTML(qw422016)
|
||||
//line history/view.qtpl:14
|
||||
qt422016.ReleaseWriter(qw422016)
|
||||
//line history/view.qtpl:14
|
||||
}
|
||||
|
||||
//line history/view.qtpl:14
|
||||
func (rev Revision) HyphaeLinksHTML() string {
|
||||
//line history/view.qtpl:14
|
||||
qb422016 := qt422016.AcquireByteBuffer()
|
||||
//line history/view.qtpl:14
|
||||
rev.WriteHyphaeLinksHTML(qb422016)
|
||||
//line history/view.qtpl:14
|
||||
qs422016 := string(qb422016.B)
|
||||
//line history/view.qtpl:14
|
||||
qt422016.ReleaseByteBuffer(qb422016)
|
||||
//line history/view.qtpl:14
|
||||
return qs422016
|
||||
//line history/view.qtpl:14
|
||||
}
|
||||
|
||||
// HyphaeDiffsHTML returns a comma-separated list of diffs links of current revision for every affected file as HTML string.
|
||||
|
||||
//line history/view.qtpl:18
|
||||
func (rev Revision) StreamHyphaeDiffsHTML(qw422016 *qt422016.Writer) {
|
||||
//line history/view.qtpl:18
|
||||
qw422016.N().S(`
|
||||
`)
|
||||
//line history/view.qtpl:19
|
||||
entries := rev.hyphaeAffected()
|
||||
|
||||
//line history/view.qtpl:19
|
||||
qw422016.N().S(`
|
||||
`)
|
||||
//line history/view.qtpl:21
|
||||
if len(entries) == 1 {
|
||||
//line history/view.qtpl:21
|
||||
qw422016.N().S(`<a href="/primitive-diff/`)
|
||||
//line history/view.qtpl:22
|
||||
qw422016.E().S(rev.Hash)
|
||||
//line history/view.qtpl:22
|
||||
qw422016.N().S(`/`)
|
||||
//line history/view.qtpl:22
|
||||
qw422016.E().S(entries[0])
|
||||
//line history/view.qtpl:22
|
||||
qw422016.N().S(`">`)
|
||||
//line history/view.qtpl:22
|
||||
qw422016.E().S(rev.Hash)
|
||||
//line history/view.qtpl:22
|
||||
qw422016.N().S(`</a>`)
|
||||
//line history/view.qtpl:23
|
||||
} else {
|
||||
//line history/view.qtpl:24
|
||||
for i, hyphaName := range entries {
|
||||
//line history/view.qtpl:25
|
||||
if i > 0 {
|
||||
//line history/view.qtpl:25
|
||||
qw422016.N().S(`<span aria-hidden="true">, </span>`)
|
||||
//line history/view.qtpl:27
|
||||
}
|
||||
//line history/view.qtpl:27
|
||||
qw422016.N().S(`<a href="/primitive-diff/`)
|
||||
//line history/view.qtpl:28
|
||||
qw422016.E().S(rev.Hash)
|
||||
//line history/view.qtpl:28
|
||||
qw422016.N().S(`/`)
|
||||
//line history/view.qtpl:28
|
||||
qw422016.E().S(hyphaName)
|
||||
//line history/view.qtpl:28
|
||||
qw422016.N().S(`">`)
|
||||
//line history/view.qtpl:29
|
||||
if i == 0 {
|
||||
//line history/view.qtpl:30
|
||||
qw422016.E().S(rev.Hash)
|
||||
//line history/view.qtpl:30
|
||||
qw422016.N().S(` `)
|
||||
//line history/view.qtpl:31
|
||||
}
|
||||
//line history/view.qtpl:32
|
||||
qw422016.E().S(hyphaName)
|
||||
//line history/view.qtpl:32
|
||||
qw422016.N().S(`</a>`)
|
||||
//line history/view.qtpl:33
|
||||
}
|
||||
//line history/view.qtpl:34
|
||||
}
|
||||
//line history/view.qtpl:35
|
||||
qw422016.N().S(`
|
||||
`)
|
||||
//line history/view.qtpl:36
|
||||
}
|
||||
|
||||
//line history/view.qtpl:36
|
||||
func (rev Revision) WriteHyphaeDiffsHTML(qq422016 qtio422016.Writer) {
|
||||
//line history/view.qtpl:36
|
||||
qw422016 := qt422016.AcquireWriter(qq422016)
|
||||
//line history/view.qtpl:36
|
||||
rev.StreamHyphaeDiffsHTML(qw422016)
|
||||
//line history/view.qtpl:36
|
||||
qt422016.ReleaseWriter(qw422016)
|
||||
//line history/view.qtpl:36
|
||||
}
|
||||
|
||||
//line history/view.qtpl:36
|
||||
func (rev Revision) HyphaeDiffsHTML() string {
|
||||
//line history/view.qtpl:36
|
||||
qb422016 := qt422016.AcquireByteBuffer()
|
||||
//line history/view.qtpl:36
|
||||
rev.WriteHyphaeDiffsHTML(qb422016)
|
||||
//line history/view.qtpl:36
|
||||
qs422016 := string(qb422016.B)
|
||||
//line history/view.qtpl:36
|
||||
qt422016.ReleaseByteBuffer(qb422016)
|
||||
//line history/view.qtpl:36
|
||||
return qs422016
|
||||
//line history/view.qtpl:36
|
||||
}
|
||||
|
||||
// descriptionForFeed generates a good enough HTML contents for a web feed.
|
||||
|
||||
//line history/view.qtpl:39
|
||||
func (rev *Revision) streamdescriptionForFeed(qw422016 *qt422016.Writer) {
|
||||
//line history/view.qtpl:39
|
||||
qw422016.N().S(`
|
||||
<p><b>`)
|
||||
//line history/view.qtpl:40
|
||||
qw422016.E().S(rev.Message)
|
||||
//line history/view.qtpl:40
|
||||
qw422016.N().S(`</b> (by `)
|
||||
//line history/view.qtpl:40
|
||||
qw422016.E().S(rev.Username)
|
||||
//line history/view.qtpl:40
|
||||
qw422016.N().S(` at `)
|
||||
//line history/view.qtpl:40
|
||||
qw422016.E().S(rev.TimeString())
|
||||
//line history/view.qtpl:40
|
||||
qw422016.N().S(`)</p>
|
||||
<p>Hyphae affected: `)
|
||||
//line history/view.qtpl:41
|
||||
rev.StreamHyphaeLinksHTML(qw422016)
|
||||
//line history/view.qtpl:41
|
||||
qw422016.N().S(`</p>
|
||||
<pre><code>`)
|
||||
//line history/view.qtpl:42
|
||||
qw422016.E().S(rev.textDiff())
|
||||
//line history/view.qtpl:42
|
||||
qw422016.N().S(`</code></pre>
|
||||
`)
|
||||
//line history/view.qtpl:43
|
||||
}
|
||||
|
||||
//line history/view.qtpl:43
|
||||
func (rev *Revision) writedescriptionForFeed(qq422016 qtio422016.Writer) {
|
||||
//line history/view.qtpl:43
|
||||
qw422016 := qt422016.AcquireWriter(qq422016)
|
||||
//line history/view.qtpl:43
|
||||
rev.streamdescriptionForFeed(qw422016)
|
||||
//line history/view.qtpl:43
|
||||
qt422016.ReleaseWriter(qw422016)
|
||||
//line history/view.qtpl:43
|
||||
}
|
||||
|
||||
//line history/view.qtpl:43
|
||||
func (rev *Revision) descriptionForFeed() string {
|
||||
//line history/view.qtpl:43
|
||||
qb422016 := qt422016.AcquireByteBuffer()
|
||||
//line history/view.qtpl:43
|
||||
rev.writedescriptionForFeed(qb422016)
|
||||
//line history/view.qtpl:43
|
||||
qs422016 := string(qb422016.B)
|
||||
//line history/view.qtpl:43
|
||||
qt422016.ReleaseByteBuffer(qb422016)
|
||||
//line history/view.qtpl:43
|
||||
return qs422016
|
||||
//line history/view.qtpl:43
|
||||
}
|
||||
|
||||
// WithRevisions returns an html representation of `revs` that is meant to be inserted in a history page.
|
||||
|
||||
//line history/view.qtpl:46
|
||||
func StreamWithRevisions(qw422016 *qt422016.Writer, hyphaName string, revs []Revision) {
|
||||
//line history/view.qtpl:46
|
||||
qw422016.N().S(`
|
||||
`)
|
||||
//line history/view.qtpl:47
|
||||
for _, grp := range groupRevisionsByMonth(revs) {
|
||||
//line history/view.qtpl:47
|
||||
qw422016.N().S(`
|
||||
`)
|
||||
//line history/view.qtpl:49
|
||||
currentYear := grp[0].Time.Year()
|
||||
currentMonth := grp[0].Time.Month()
|
||||
sectionId := fmt.Sprintf("%04d-%02d", currentYear, currentMonth)
|
||||
|
||||
//line history/view.qtpl:52
|
||||
qw422016.N().S(`
|
||||
<section class="history__month">
|
||||
<a href="#`)
|
||||
//line history/view.qtpl:54
|
||||
qw422016.E().S(sectionId)
|
||||
//line history/view.qtpl:54
|
||||
qw422016.N().S(`" class="history__month-anchor">
|
||||
<h2 id="`)
|
||||
//line history/view.qtpl:55
|
||||
qw422016.E().S(sectionId)
|
||||
//line history/view.qtpl:55
|
||||
qw422016.N().S(`" class="history__month-title">`)
|
||||
//line history/view.qtpl:55
|
||||
qw422016.N().D(currentYear)
|
||||
//line history/view.qtpl:55
|
||||
qw422016.N().S(` `)
|
||||
//line history/view.qtpl:55
|
||||
qw422016.E().S(currentMonth.String())
|
||||
//line history/view.qtpl:55
|
||||
qw422016.N().S(`</h2>
|
||||
</a>
|
||||
<ul class="history__entries">
|
||||
`)
|
||||
//line history/view.qtpl:58
|
||||
for _, rev := range grp {
|
||||
//line history/view.qtpl:58
|
||||
qw422016.N().S(`
|
||||
<li class="history__entry">
|
||||
<a class="history-entry" href="/rev/`)
|
||||
//line history/view.qtpl:60
|
||||
qw422016.E().S(rev.Hash)
|
||||
//line history/view.qtpl:60
|
||||
qw422016.N().S(`/`)
|
||||
//line history/view.qtpl:60
|
||||
qw422016.E().S(hyphaName)
|
||||
//line history/view.qtpl:60
|
||||
qw422016.N().S(`">
|
||||
<time class="history-entry__time">`)
|
||||
//line history/view.qtpl:61
|
||||
qw422016.E().S(rev.timeToDisplay())
|
||||
//line history/view.qtpl:61
|
||||
qw422016.N().S(`</time>
|
||||
</a>
|
||||
<span class="history-entry__hash"><a href="/primitive-diff/`)
|
||||
//line history/view.qtpl:63
|
||||
qw422016.E().S(rev.Hash)
|
||||
//line history/view.qtpl:63
|
||||
qw422016.N().S(`/`)
|
||||
//line history/view.qtpl:63
|
||||
qw422016.E().S(hyphaName)
|
||||
//line history/view.qtpl:63
|
||||
qw422016.N().S(`">`)
|
||||
//line history/view.qtpl:63
|
||||
qw422016.E().S(rev.Hash)
|
||||
//line history/view.qtpl:63
|
||||
qw422016.N().S(`</a></span>
|
||||
<span class="history-entry__msg">`)
|
||||
//line history/view.qtpl:64
|
||||
qw422016.E().S(rev.Message)
|
||||
//line history/view.qtpl:64
|
||||
qw422016.N().S(`</span>
|
||||
`)
|
||||
//line history/view.qtpl:65
|
||||
if rev.Username != "anon" {
|
||||
//line history/view.qtpl:65
|
||||
qw422016.N().S(`
|
||||
<span class="history-entry__author">by <a href="/hypha/`)
|
||||
//line history/view.qtpl:66
|
||||
qw422016.E().S(cfg.UserHypha)
|
||||
//line history/view.qtpl:66
|
||||
qw422016.N().S(`/`)
|
||||
//line history/view.qtpl:66
|
||||
qw422016.E().S(rev.Username)
|
||||
//line history/view.qtpl:66
|
||||
qw422016.N().S(`" rel="author">`)
|
||||
//line history/view.qtpl:66
|
||||
qw422016.E().S(rev.Username)
|
||||
//line history/view.qtpl:66
|
||||
qw422016.N().S(`</a></span>
|
||||
`)
|
||||
//line history/view.qtpl:67
|
||||
}
|
||||
//line history/view.qtpl:67
|
||||
qw422016.N().S(`
|
||||
</li>
|
||||
`)
|
||||
//line history/view.qtpl:69
|
||||
}
|
||||
//line history/view.qtpl:69
|
||||
qw422016.N().S(`
|
||||
</ul>
|
||||
</section>
|
||||
`)
|
||||
//line history/view.qtpl:72
|
||||
}
|
||||
//line history/view.qtpl:72
|
||||
qw422016.N().S(`
|
||||
`)
|
||||
//line history/view.qtpl:73
|
||||
}
|
||||
|
||||
//line history/view.qtpl:73
|
||||
func WriteWithRevisions(qq422016 qtio422016.Writer, hyphaName string, revs []Revision) {
|
||||
//line history/view.qtpl:73
|
||||
qw422016 := qt422016.AcquireWriter(qq422016)
|
||||
//line history/view.qtpl:73
|
||||
StreamWithRevisions(qw422016, hyphaName, revs)
|
||||
//line history/view.qtpl:73
|
||||
qt422016.ReleaseWriter(qw422016)
|
||||
//line history/view.qtpl:73
|
||||
}
|
||||
|
||||
//line history/view.qtpl:73
|
||||
func WithRevisions(hyphaName string, revs []Revision) string {
|
||||
//line history/view.qtpl:73
|
||||
qb422016 := qt422016.AcquireByteBuffer()
|
||||
//line history/view.qtpl:73
|
||||
WriteWithRevisions(qb422016, hyphaName, revs)
|
||||
//line history/view.qtpl:73
|
||||
qs422016 := string(qb422016.B)
|
||||
//line history/view.qtpl:73
|
||||
qt422016.ReleaseByteBuffer(qb422016)
|
||||
//line history/view.qtpl:73
|
||||
return qs422016
|
||||
//line history/view.qtpl:73
|
||||
}
|
||||
2
httpd.go
2
httpd.go
@ -32,7 +32,7 @@ func serveHTTP(handler http.Handler) (err error) {
|
||||
func startUnixSocketServer(server *http.Server, socketPath string) error {
|
||||
err := os.Remove(socketPath)
|
||||
if err != nil {
|
||||
return err
|
||||
slog.Warn("Failed to clean up old socket", "err", err)
|
||||
}
|
||||
|
||||
listener, err := net.Listen("unix", socketPath)
|
||||
|
||||
@ -109,22 +109,22 @@ type Telegram struct {
|
||||
// configuration. Call it sometime during the initialization.
|
||||
func ReadConfigFile(path string) error {
|
||||
cfg := &Config{
|
||||
WikiName: "Mycorrhiza Wiki",
|
||||
NaviTitleIcon: "🍄",
|
||||
WikiName: "Lyxi's Vault",
|
||||
NaviTitleIcon: "🦇",
|
||||
Hyphae: Hyphae{
|
||||
HomeHypha: "home",
|
||||
UserHypha: "u",
|
||||
HeaderLinksHypha: "",
|
||||
HeaderLinksHypha: "u/alyxbatte/header",
|
||||
RedirectionCategory: "redirection",
|
||||
},
|
||||
Network: Network{
|
||||
ListenAddr: "127.0.0.1:1737",
|
||||
ListenAddr: "0.0.0.0:1737",
|
||||
URL: "",
|
||||
},
|
||||
Authorization: Authorization{
|
||||
UseAuth: false,
|
||||
UseAuth: true,
|
||||
AllowRegistration: false,
|
||||
RegistrationLimit: 0,
|
||||
RegistrationLimit: 1,
|
||||
Locked: false,
|
||||
UseWhiteList: false,
|
||||
WhiteList: []string{},
|
||||
|
||||
@ -40,20 +40,33 @@ func DataFromFilename(fullPath string) (name string, isText bool, skip bool) {
|
||||
|
||||
var mapMime2Ext = map[string]string{
|
||||
"application/octet-stream": "bin",
|
||||
"image/jpeg": "jpg",
|
||||
"image/gif": "gif",
|
||||
"image/png": "png",
|
||||
"image/webp": "webp",
|
||||
"image/svg+xml": "svg",
|
||||
"image/x-icon": "ico",
|
||||
"application/ogg": "ogg",
|
||||
"video/webm": "webm",
|
||||
"audio/mp3": "mp3",
|
||||
"video/mp4": "mp4",
|
||||
|
||||
"image/jpeg": "jpg",
|
||||
"image/gif": "gif",
|
||||
"image/png": "png",
|
||||
"image/webp": "webp",
|
||||
"image/svg+xml": "svg",
|
||||
"image/x-icon": "ico",
|
||||
|
||||
"application/ogg": "ogg",
|
||||
"video/webm": "webm",
|
||||
"audio/mp3": "mp3",
|
||||
"audio/mpeg": "mp3",
|
||||
"audio/mpeg3": "mp3",
|
||||
"video/mp4": "mp4",
|
||||
"audio/flac": "flac",
|
||||
|
||||
"audio/wav": "wav",
|
||||
"audio/vnd.wav": "wav",
|
||||
"audio/vnd.wave": "wav",
|
||||
"audio/wave": "wav",
|
||||
"audio/x-pn-wav": "wav",
|
||||
"audio/x-wav": "wav",
|
||||
}
|
||||
|
||||
var mapExt2Mime = map[string]string{
|
||||
".bin": "application/octet-stream",
|
||||
".bin": "application/octet-stream",
|
||||
|
||||
".jpg": "image/jpeg",
|
||||
".jpeg": "image/jpeg",
|
||||
".gif": "image/gif",
|
||||
@ -61,8 +74,12 @@ var mapExt2Mime = map[string]string{
|
||||
".webp": "image/webp",
|
||||
".svg": "image/svg+xml",
|
||||
".ico": "image/x-icon",
|
||||
|
||||
".ogg": "application/ogg",
|
||||
".webm": "video/webm",
|
||||
".mp3": "audio/mp3",
|
||||
".mp3": "audio/mpeg",
|
||||
".mp4": "video/mp4",
|
||||
".flac": "audio/flac",
|
||||
|
||||
"wav": "audio/wav",
|
||||
}
|
||||
|
||||
8
main.go
8
main.go
@ -1,10 +1,10 @@
|
||||
// Command mycorrhiza is a program that runs a mycorrhiza wiki.
|
||||
//
|
||||
//go:generate go run github.com/valyala/quicktemplate/qtc -dir=history
|
||||
//go:generate go run github.com/valyala/quicktemplate/qtc -dir=mycoopts
|
||||
package main
|
||||
|
||||
import (
|
||||
"log/slog"
|
||||
"os"
|
||||
|
||||
"github.com/bouncepaw/mycorrhiza/history"
|
||||
"github.com/bouncepaw/mycorrhiza/internal/backlinks"
|
||||
"github.com/bouncepaw/mycorrhiza/internal/categories"
|
||||
@ -19,8 +19,6 @@ import (
|
||||
"github.com/bouncepaw/mycorrhiza/web"
|
||||
"github.com/bouncepaw/mycorrhiza/web/static"
|
||||
"github.com/bouncepaw/mycorrhiza/web/viewutil"
|
||||
"log/slog"
|
||||
"os"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
@ -2,10 +2,14 @@ package mycoopts
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"html"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/bouncepaw/mycorrhiza/internal/cfg"
|
||||
"github.com/bouncepaw/mycorrhiza/internal/hyphae"
|
||||
"github.com/bouncepaw/mycorrhiza/interwiki"
|
||||
"github.com/bouncepaw/mycorrhiza/l18n"
|
||||
"github.com/bouncepaw/mycorrhiza/util"
|
||||
|
||||
"git.sr.ht/~bouncepaw/mycomarkup/v5/options"
|
||||
@ -54,3 +58,58 @@ func MarkupOptions(hyphaName string) options.Options {
|
||||
ImgSrcFormatForInterwikiPrefix: interwiki.ImgSrcFormatFor,
|
||||
}.FillTheRest()
|
||||
}
|
||||
|
||||
func mediaRaw(h *hyphae.MediaHypha) string {
|
||||
return Media(h, l18n.New("en", "en"))
|
||||
}
|
||||
|
||||
func Media(h *hyphae.MediaHypha, lc *l18n.Localizer) string {
|
||||
name := html.EscapeString(h.CanonicalName())
|
||||
|
||||
switch filepath.Ext(h.MediaFilePath()) {
|
||||
case ".jpg", ".gif", ".png", ".webp", ".svg", ".ico":
|
||||
return fmt.Sprintf(
|
||||
`<div class="binary-container binary-container_with-img">
|
||||
<a href="/binary/%s"><img src="/binary/%s"/></a>
|
||||
</div>`,
|
||||
name, name,
|
||||
)
|
||||
|
||||
case ".ogg", ".webm", ".mp4":
|
||||
return fmt.Sprintf(
|
||||
`<div class="binary-container binary-container_with-video">
|
||||
<video controls>
|
||||
<source src="/binary/%s"/>
|
||||
<p>%s <a href="/binary/%s">%s</a></p>
|
||||
</video>
|
||||
</div>`,
|
||||
name,
|
||||
html.EscapeString(lc.Get("ui.media_novideo")),
|
||||
name,
|
||||
html.EscapeString(lc.Get("ui.media_novideo_link")),
|
||||
)
|
||||
|
||||
case ".mp3", ".wav", ".flac":
|
||||
return fmt.Sprintf(
|
||||
`<div class="binary-container binary-container_with-audio">
|
||||
<audio controls>
|
||||
<source src="/binary/%s"/>
|
||||
<p>%s <a href="/binary/%s">%s</a></p>
|
||||
</audio>
|
||||
</div>`,
|
||||
name,
|
||||
html.EscapeString(lc.Get("ui.media_noaudio")),
|
||||
name,
|
||||
html.EscapeString(lc.Get("ui.media_noaudio_link")),
|
||||
)
|
||||
|
||||
default:
|
||||
return fmt.Sprintf(
|
||||
`<div class="binary-container binary-container_with-nothing">
|
||||
<p><a href="/binary/%s">%s</a></p>
|
||||
</div>`,
|
||||
name,
|
||||
html.EscapeString(lc.Get("ui.media_download")),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,37 +0,0 @@
|
||||
{% import "path/filepath" %}
|
||||
|
||||
{% import "github.com/bouncepaw/mycorrhiza/internal/hyphae" %}
|
||||
{% import "github.com/bouncepaw/mycorrhiza/l18n" %}
|
||||
|
||||
{% func mediaRaw(h *hyphae.MediaHypha) %}{%= Media(h, l18n.New("en", "en")) %}{% endfunc %}
|
||||
|
||||
{% func Media(h *hyphae.MediaHypha, lc *l18n.Localizer) %}
|
||||
{% switch filepath.Ext(h.MediaFilePath()) %}
|
||||
|
||||
{% case ".jpg", ".gif", ".png", ".webp", ".svg", ".ico" %}
|
||||
<div class="binary-container binary-container_with-img">
|
||||
<a href="/binary/{%s= h.CanonicalName() %}"><img src="/binary/{%s= h.CanonicalName() %}"/></a>
|
||||
</div>
|
||||
|
||||
{% case ".ogg", ".webm", ".mp4" %}
|
||||
<div class="binary-container binary-container_with-video">
|
||||
<video controls>
|
||||
<source src="/binary/{%s= h.CanonicalName() %}"/>
|
||||
<p>{%s lc.Get("ui.media_novideo") %} <a href="/binary/{%s= h.CanonicalName() %}">{%s lc.Get("ui.media_novideo_link") %}</a></p>
|
||||
</video>
|
||||
</div>
|
||||
|
||||
{% case ".mp3" %}
|
||||
<div class="binary-container binary-container_with-audio">
|
||||
<audio controls>
|
||||
<source src="/binary/{%s= h.CanonicalName() %}"/>
|
||||
<p>{%s lc.Get("ui.media_noaudio") %} <a href="/binary/{%s= h.CanonicalName() %}">{%s lc.Get("ui.media_noaudio_link") %}</a></p>
|
||||
</audio>
|
||||
</div>
|
||||
|
||||
{% default %}
|
||||
<div class="binary-container binary-container_with-nothing">
|
||||
<p><a href="/binary/{%s= h.CanonicalName() %}">{%s lc.Get("ui.media_download") %}</a></p>
|
||||
</div>
|
||||
{% endswitch %}
|
||||
{% endfunc %}
|
||||
@ -1,190 +0,0 @@
|
||||
// Code generated by qtc from "view.qtpl". DO NOT EDIT.
|
||||
// See https://github.com/valyala/quicktemplate for details.
|
||||
|
||||
//line mycoopts/view.qtpl:1
|
||||
package mycoopts
|
||||
|
||||
//line mycoopts/view.qtpl:1
|
||||
import "path/filepath"
|
||||
|
||||
//line mycoopts/view.qtpl:3
|
||||
import "github.com/bouncepaw/mycorrhiza/internal/hyphae"
|
||||
|
||||
//line mycoopts/view.qtpl:4
|
||||
import "github.com/bouncepaw/mycorrhiza/l18n"
|
||||
|
||||
//line mycoopts/view.qtpl:6
|
||||
import (
|
||||
qtio422016 "io"
|
||||
|
||||
qt422016 "github.com/valyala/quicktemplate"
|
||||
)
|
||||
|
||||
//line mycoopts/view.qtpl:6
|
||||
var (
|
||||
_ = qtio422016.Copy
|
||||
_ = qt422016.AcquireByteBuffer
|
||||
)
|
||||
|
||||
//line mycoopts/view.qtpl:6
|
||||
func streammediaRaw(qw422016 *qt422016.Writer, h *hyphae.MediaHypha) {
|
||||
//line mycoopts/view.qtpl:6
|
||||
StreamMedia(qw422016, h, l18n.New("en", "en"))
|
||||
//line mycoopts/view.qtpl:6
|
||||
}
|
||||
|
||||
//line mycoopts/view.qtpl:6
|
||||
func writemediaRaw(qq422016 qtio422016.Writer, h *hyphae.MediaHypha) {
|
||||
//line mycoopts/view.qtpl:6
|
||||
qw422016 := qt422016.AcquireWriter(qq422016)
|
||||
//line mycoopts/view.qtpl:6
|
||||
streammediaRaw(qw422016, h)
|
||||
//line mycoopts/view.qtpl:6
|
||||
qt422016.ReleaseWriter(qw422016)
|
||||
//line mycoopts/view.qtpl:6
|
||||
}
|
||||
|
||||
//line mycoopts/view.qtpl:6
|
||||
func mediaRaw(h *hyphae.MediaHypha) string {
|
||||
//line mycoopts/view.qtpl:6
|
||||
qb422016 := qt422016.AcquireByteBuffer()
|
||||
//line mycoopts/view.qtpl:6
|
||||
writemediaRaw(qb422016, h)
|
||||
//line mycoopts/view.qtpl:6
|
||||
qs422016 := string(qb422016.B)
|
||||
//line mycoopts/view.qtpl:6
|
||||
qt422016.ReleaseByteBuffer(qb422016)
|
||||
//line mycoopts/view.qtpl:6
|
||||
return qs422016
|
||||
//line mycoopts/view.qtpl:6
|
||||
}
|
||||
|
||||
//line mycoopts/view.qtpl:8
|
||||
func StreamMedia(qw422016 *qt422016.Writer, h *hyphae.MediaHypha, lc *l18n.Localizer) {
|
||||
//line mycoopts/view.qtpl:8
|
||||
qw422016.N().S(`
|
||||
`)
|
||||
//line mycoopts/view.qtpl:9
|
||||
switch filepath.Ext(h.MediaFilePath()) {
|
||||
//line mycoopts/view.qtpl:11
|
||||
case ".jpg", ".gif", ".png", ".webp", ".svg", ".ico":
|
||||
//line mycoopts/view.qtpl:11
|
||||
qw422016.N().S(`
|
||||
<div class="binary-container binary-container_with-img">
|
||||
<a href="/binary/`)
|
||||
//line mycoopts/view.qtpl:13
|
||||
qw422016.N().S(h.CanonicalName())
|
||||
//line mycoopts/view.qtpl:13
|
||||
qw422016.N().S(`"><img src="/binary/`)
|
||||
//line mycoopts/view.qtpl:13
|
||||
qw422016.N().S(h.CanonicalName())
|
||||
//line mycoopts/view.qtpl:13
|
||||
qw422016.N().S(`"/></a>
|
||||
</div>
|
||||
|
||||
`)
|
||||
//line mycoopts/view.qtpl:16
|
||||
case ".ogg", ".webm", ".mp4":
|
||||
//line mycoopts/view.qtpl:16
|
||||
qw422016.N().S(`
|
||||
<div class="binary-container binary-container_with-video">
|
||||
<video controls>
|
||||
<source src="/binary/`)
|
||||
//line mycoopts/view.qtpl:19
|
||||
qw422016.N().S(h.CanonicalName())
|
||||
//line mycoopts/view.qtpl:19
|
||||
qw422016.N().S(`"/>
|
||||
<p>`)
|
||||
//line mycoopts/view.qtpl:20
|
||||
qw422016.E().S(lc.Get("ui.media_novideo"))
|
||||
//line mycoopts/view.qtpl:20
|
||||
qw422016.N().S(` <a href="/binary/`)
|
||||
//line mycoopts/view.qtpl:20
|
||||
qw422016.N().S(h.CanonicalName())
|
||||
//line mycoopts/view.qtpl:20
|
||||
qw422016.N().S(`">`)
|
||||
//line mycoopts/view.qtpl:20
|
||||
qw422016.E().S(lc.Get("ui.media_novideo_link"))
|
||||
//line mycoopts/view.qtpl:20
|
||||
qw422016.N().S(`</a></p>
|
||||
</video>
|
||||
</div>
|
||||
|
||||
`)
|
||||
//line mycoopts/view.qtpl:24
|
||||
case ".mp3":
|
||||
//line mycoopts/view.qtpl:24
|
||||
qw422016.N().S(`
|
||||
<div class="binary-container binary-container_with-audio">
|
||||
<audio controls>
|
||||
<source src="/binary/`)
|
||||
//line mycoopts/view.qtpl:27
|
||||
qw422016.N().S(h.CanonicalName())
|
||||
//line mycoopts/view.qtpl:27
|
||||
qw422016.N().S(`"/>
|
||||
<p>`)
|
||||
//line mycoopts/view.qtpl:28
|
||||
qw422016.E().S(lc.Get("ui.media_noaudio"))
|
||||
//line mycoopts/view.qtpl:28
|
||||
qw422016.N().S(` <a href="/binary/`)
|
||||
//line mycoopts/view.qtpl:28
|
||||
qw422016.N().S(h.CanonicalName())
|
||||
//line mycoopts/view.qtpl:28
|
||||
qw422016.N().S(`">`)
|
||||
//line mycoopts/view.qtpl:28
|
||||
qw422016.E().S(lc.Get("ui.media_noaudio_link"))
|
||||
//line mycoopts/view.qtpl:28
|
||||
qw422016.N().S(`</a></p>
|
||||
</audio>
|
||||
</div>
|
||||
|
||||
`)
|
||||
//line mycoopts/view.qtpl:32
|
||||
default:
|
||||
//line mycoopts/view.qtpl:32
|
||||
qw422016.N().S(`
|
||||
<div class="binary-container binary-container_with-nothing">
|
||||
<p><a href="/binary/`)
|
||||
//line mycoopts/view.qtpl:34
|
||||
qw422016.N().S(h.CanonicalName())
|
||||
//line mycoopts/view.qtpl:34
|
||||
qw422016.N().S(`">`)
|
||||
//line mycoopts/view.qtpl:34
|
||||
qw422016.E().S(lc.Get("ui.media_download"))
|
||||
//line mycoopts/view.qtpl:34
|
||||
qw422016.N().S(`</a></p>
|
||||
</div>
|
||||
`)
|
||||
//line mycoopts/view.qtpl:36
|
||||
}
|
||||
//line mycoopts/view.qtpl:36
|
||||
qw422016.N().S(`
|
||||
`)
|
||||
//line mycoopts/view.qtpl:37
|
||||
}
|
||||
|
||||
//line mycoopts/view.qtpl:37
|
||||
func WriteMedia(qq422016 qtio422016.Writer, h *hyphae.MediaHypha, lc *l18n.Localizer) {
|
||||
//line mycoopts/view.qtpl:37
|
||||
qw422016 := qt422016.AcquireWriter(qq422016)
|
||||
//line mycoopts/view.qtpl:37
|
||||
StreamMedia(qw422016, h, lc)
|
||||
//line mycoopts/view.qtpl:37
|
||||
qt422016.ReleaseWriter(qw422016)
|
||||
//line mycoopts/view.qtpl:37
|
||||
}
|
||||
|
||||
//line mycoopts/view.qtpl:37
|
||||
func Media(h *hyphae.MediaHypha, lc *l18n.Localizer) string {
|
||||
//line mycoopts/view.qtpl:37
|
||||
qb422016 := qt422016.AcquireByteBuffer()
|
||||
//line mycoopts/view.qtpl:37
|
||||
WriteMedia(qb422016, h, lc)
|
||||
//line mycoopts/view.qtpl:37
|
||||
qs422016 := string(qb422016.B)
|
||||
//line mycoopts/view.qtpl:37
|
||||
qt422016.ReleaseByteBuffer(qb422016)
|
||||
//line mycoopts/view.qtpl:37
|
||||
return qs422016
|
||||
//line mycoopts/view.qtpl:37
|
||||
}
|
||||
@ -258,8 +258,8 @@ func handlerHypha(w http.ResponseWriter, rq *http.Request) {
|
||||
if err == nil {
|
||||
ctx, _ := mycocontext.ContextFromStringInput(string(fileContentsT), mycoopts.MarkupOptions(hyphaName))
|
||||
getOpenGraph, descVisitor, imgVisitor := tools.OpenGraphVisitors(ctx)
|
||||
openGraph = template.HTML(getOpenGraph())
|
||||
ast := mycomarkup.BlockTree(ctx, descVisitor, imgVisitor)
|
||||
openGraph = template.HTML(getOpenGraph())
|
||||
contents = template.HTML(mycomarkup.BlocksToHTML(ctx, ast))
|
||||
}
|
||||
switch h := h.(type) {
|
||||
|
||||
@ -317,7 +317,7 @@ kbd {
|
||||
top: 0;
|
||||
left: 50%;
|
||||
width: 100%;
|
||||
max-width: 800px;
|
||||
max-width: 1000px;
|
||||
margin: 96px auto;
|
||||
padding: 24px;
|
||||
transform: translate(-50%, 0);
|
||||
@ -354,7 +354,7 @@ kbd {
|
||||
margin: 0;
|
||||
padding: 8px;
|
||||
border: none;
|
||||
background: url(/web/static/icon/x.svg) no-repeat 8px 8px / 16px 16px;
|
||||
background: url(/static/icon/x.svg) no-repeat 8px 8px / 16px 16px;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
cursor: pointer;
|
||||
|
||||
@ -285,8 +285,8 @@ rrh.shortcuts.addGroup(new ShortcutGroup('Common', null, [
|
||||
if (document.body.dataset.rrhAddr.startsWith('/hypha')) {
|
||||
rrh.shortcuts.addGroup(new ShortcutGroup('Hypha', null, [
|
||||
new Shortcut('', $$('article .wikilink'), 'First 9 hypha′s links'),
|
||||
new Shortcut(['p', 'Alt+ArrowLeft', 'Ctrl+Alt+ArrowLeft'], $('.prevnext__prev'), 'Previous hypha'),
|
||||
new Shortcut(['n', 'Alt+ArrowRight', 'Ctrl+Alt+ArrowRight'], $('.prevnext__next'), 'Next hypha'),
|
||||
new Shortcut(['p', 'Alt+Shift+ArrowLeft', 'Ctrl+Alt+ArrowLeft'], $('.prevnext__prev'), 'Previous hypha'),
|
||||
new Shortcut(['n', 'Alt+Shift+ArrowRight', 'Ctrl+Alt+ArrowRight'], $('.prevnext__next'), 'Next hypha'),
|
||||
new Shortcut(['s', 'Alt+ArrowUp', 'Ctrl+Alt+ArrowUp'], $$('.navi-title a').slice(1, -1).slice(-1)[0], 'Parent hypha'),
|
||||
new Shortcut(['c', 'Alt+ArrowDown', 'Ctrl+Alt+ArrowDown'], $('.subhyphae__link'), 'First child hypha'),
|
||||
new Shortcut(['e', isMac ? 'Meta+Enter' : 'Ctrl+Enter'], $('.btn__link_navititle[href^="/edit/"]'), 'Edit this hypha'),
|
||||
|
||||
Loading…
Reference in New Issue
Block a user