1
0
mirror of https://github.com/osmarks/mycorrhiza.git synced 2024-10-30 03:36:16 +00:00

Implement new content file format

This commit is contained in:
Timur Ismagilov 2020-06-20 20:17:13 +05:00
parent c96ba3e08f
commit cea18eaa03
24 changed files with 1718 additions and 71 deletions

View File

@ -101,18 +101,20 @@ func getHypha(name string) (*Hypha, bool) {
// revisionFromHttpData creates a new revison for hypha `h`. All data is fetched from `rq`, except for BinaryMime and BinaryPath which require additional processing. You'll have te insert the revision to `h` yourself.
func revisionFromHttpData(h *Hypha, rq *http.Request) *Revision {
idStr := strconv.Itoa(h.NewestRevisionInt() + 1)
log.Println(idStr)
log.Printf("Creating revision %s from http data", idStr)
rev := &Revision{
Id: h.NewestRevisionInt() + 1,
FullName: h.FullName,
Tags: makeTagsSlice(rq.PostFormValue("tags")),
Comment: rq.PostFormValue("comment"),
Author: rq.PostFormValue("author"),
Time: int(time.Now().Unix()),
TextMime: rq.PostFormValue("text_mime"),
TextPath: filepath.Join(h.Path, idStr+".txt"),
// Fields left: BinaryMime, BinaryPath
Id: h.NewestRevisionInt() + 1,
FullName: h.FullName,
ShortName: filepath.Base(h.FullName),
Tags: makeTagsSlice(rq.PostFormValue("tags")),
Comment: rq.PostFormValue("comment"),
Author: rq.PostFormValue("author"),
Time: int(time.Now().Unix()),
TextMime: rq.PostFormValue("text_mime"),
// Fields left: BinaryMime, BinaryPath, BinaryName, TextName, TextPath
}
rev.desiredTextFilename() // TextName is set now
rev.TextPath = filepath.Join(h.Path, rev.TextName)
return rev
}
@ -139,11 +141,13 @@ func writeBinaryFileFromHttpData(h *Hypha, oldRev Revision, newRev *Revision, rq
log.Println("No binary data passed for", newRev.FullName)
newRev.BinaryMime = oldRev.BinaryMime
newRev.BinaryPath = oldRev.BinaryPath
newRev.BinaryName = oldRev.BinaryName
log.Println("Set previous revision's binary data")
return nil
}
newRev.BinaryMime = handler.Header.Get("Content-Type")
newRev.BinaryPath = filepath.Join(h.Path, newRev.IdAsStr()+".bin")
newRev.BinaryName = newRev.desiredBinaryFilename()
data, err := ioutil.ReadAll(file)
if err != nil {
log.Println(err)
@ -186,5 +190,7 @@ func HandlerUpdate(w http.ResponseWriter, rq *http.Request) {
log.Println("Current hyphae storage is", hyphae)
w.WriteHeader(http.StatusOK)
w.Write([]byte("Saved successfully"))
w.Header().Set("Content-Type", "text/html; charset=utf-8")
d := map[string]string{"Name": h.FullName}
w.Write([]byte(renderFromMap(d, "updateOk.html")))
}

View File

@ -71,7 +71,7 @@ func (h *Hypha) CreateDir() error {
// SaveJson dumps the hypha's metadata to `meta.json` file.
func (h *Hypha) SaveJson() {
data, err := json.Marshal(h)
data, err := json.MarshalIndent(h, "", "\t")
if err != nil {
log.Println("Failed to create JSON of hypha.", err)
return

Binary file not shown.

View File

@ -4,6 +4,7 @@ import (
"fmt"
"io/ioutil"
"log"
"mime"
"net/http"
"strconv"
@ -24,6 +25,8 @@ type Revision struct {
BinaryMime string `json:"binary_mime"`
TextPath string `json:"-"`
BinaryPath string `json:"-"`
TextName string `json:"text_name"`
BinaryName string `json:"binary_name"`
}
// IdAsStr returns revision's id as a string.
@ -37,9 +40,34 @@ func (rev *Revision) hasBinaryData() bool {
return rev.BinaryMime != ""
}
// desiredBinaryFilename returns string that represents filename to use when saving a binary content file of a new revison.
// It also sets the corresponding field in `rev`.
func (rev *Revision) desiredBinaryFilename() string {
ts, err := mime.ExtensionsByType(rev.BinaryMime)
if err != nil || ts == nil {
rev.BinaryName = rev.IdAsStr() + ".bin"
} else {
rev.BinaryName = rev.IdAsStr() + ts[0]
}
return rev.BinaryName
}
// desiredTextFilename returns string that represents filename to use when saving a text content file of a new revison.
// It also sets the corresponding field in `rev`.
func (rev *Revision) desiredTextFilename() string {
ts, err := mime.ExtensionsByType(rev.TextMime)
if err != nil || ts == nil {
log.Println("No idea how I should name this one:", rev.TextMime)
rev.TextName = rev.IdAsStr() + ".txt"
} else {
log.Println("A good extension would be one of these:", ts)
rev.TextName = rev.IdAsStr() + ts[0]
}
return rev.TextName
}
// AsHtml returns HTML representation of the revision.
// If there is an error, it will be told about it in `w`.
// In any case, some http data is written to `w`.
func (rev *Revision) AsHtml(w http.ResponseWriter) (ret string, err error) {
ret += `<article class="page">
<h1 class="page__title">` + rev.FullName + `</h1>
@ -56,9 +84,6 @@ func (rev *Revision) AsHtml(w http.ResponseWriter) (ret string, err error) {
return "", err
}
w.Header().Set("Content-Type", "text/html; charset=utf-8")
w.WriteHeader(http.StatusOK)
// TODO: support more markups.
// TODO: support mycorrhiza extensions like transclusion.
switch rev.TextMime {

View File

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 43 KiB

View File

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 34 KiB

BIN
w/m/Fruit/Apple/4.bin Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 427 KiB

2
w/m/Fruit/Apple/4.txt Normal file
View File

@ -0,0 +1,2 @@
Я́блоко — сочный плод яблони, который употребляется в пищу в свежем виде, служит сырьём в кулинарии и для приготовления напитков. Наибольшее распространение получила яблоня домашняя, реже выращивают яблоню сливолистную. Размер красных, зелёных или жёлтых шаровидных плодов 5—13 см в диаметре. Происходит из Центральной Азии, где до сих пор произрастает дикорастущий предок яблони домашней — яблоня Сиверса. На сегодняшний день существует множество сортов этого вида яблони, произрастающих в различных климатических условиях. По времени созревания отличают летние, осенние и зимние сорта, более поздние сорта отличаются хорошей стойкостью.

View File

@ -1 +1,52 @@
{"views":0,"deleted":false,"revisions":{"1":{"tags":["img"],"name":"Apple","comment":"add apple pic hehehe","author":"bouncepaw","time":1591639464,"text_mime":"text/plain","binary_mime":"image/jpeg"},"2":{"tags":null,"name":"","comment":"Update Fruit/Apple","author":"","time":1592570366,"text_mime":"text/plain","binary_mime":"image/jpeg"},"3":{"tags":null,"name":"","comment":"Test fs dumping","author":"","time":1592570926,"text_mime":"text/plain","binary_mime":"image/jpeg"}}}
{
"views": 0,
"deleted": false,
"revisions": {
"1": {
"tags": [
"img"
],
"name": "Apple",
"comment": "add apple pic hehehe",
"author": "bouncepaw",
"time": 1591639464,
"text_mime": "text/plain",
"binary_mime": "image/jpeg",
"text_name": "1.txt",
"binary_name": "1.jpg"
},
"2": {
"tags": null,
"name": "Apple",
"comment": "Update Fruit/Apple",
"author": "",
"time": 1592570366,
"text_mime": "text/plain",
"binary_mime": "image/jpeg",
"text_name": "2.txt",
"binary_name": "2.jpg"
},
"3": {
"tags": null,
"name": "Apple",
"comment": "Test fs dumping",
"author": "",
"time": 1592570926,
"text_mime": "text/plain",
"binary_mime": "image/jpeg",
"text_name": "3.txt",
"binary_name": "2.jpg"
},
"4": {
"tags": null,
"name": "",
"comment": "copypaste from wikipedia",
"author": "",
"time": 1592663126,
"text_mime": "text/markdown",
"binary_mime": "image/jpeg",
"text_name": "4.txt",
"binary_name": "4.jpg"
}
}
}

View File

@ -6,7 +6,8 @@
"author": "bouncepaw",
"comment": "create Fruit",
"tags": ["fetus", "tasty"],
"text_mime": "text/markdown"
"text_mime": "text/markdown",
"text_name": "1.md"
},
"2":{
"name": "Fruit",
@ -14,7 +15,8 @@
"author": "fungimaster",
"comment": "update Fruit",
"tags": ["fetus", "tasty"],
"text_mime": "text/markdown"
"text_mime": "text/markdown",
"text_name": "2.md"
}
}
}

205
w/m/sys/main.css/3.css Normal file
View File

@ -0,0 +1,205 @@
*, *::before, *::after {
box-sizing: border-box;
}
html {
height: 100%;
}
body {
font: 15px/1.5 system-ui, -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Helvetica', 'PT Sans', 'Roboto', 'Arial', sans-serif;
max-width: 500px;
min-height: 100%;
margin: 0 auto;
padding: 12px 24px;
}
@media (min-width: 700px) {
body {
}
}
.shroom {
margin: 0;
}
.shroom__button {
border-radius: 8px;
padding: 8px 16px 8px 0;
border: none;
background: #f0f2f4;
color: #444;
font: inherit;
font-size: 15px;
font-weight: 500;
text-align: left;
}
.shroom span {
margin-left: 16px;
margin-right: 8px;
font-size: 20px;
vertical-align: -0.04em;
}
.mushroom .shroom__button {
background: #44484a;
color: #dddfe4;
}
.header {
padding: 8px 0;
}
.header h1 {
margin: 0;
font-size: 18px;
font-weight: 600;
letter-spacing: 0.02em;
color: #222428;
}
a {
color: #44e;
}
a:visited {
color: #44a;
}
h1, h2, h3, h4, h5, h6 {
margin: 1em 0 0.25em;
}
.page {
font-size: 16px;
line-height: 1.666;
max-width: 40em;
hyphens: auto;
white-space: break-spaces;
}
.page__amnt {
max-width: 100%;
}
.page__title {
font-family: 'PT Serif', 'Georgia', serif;
font-size: 36px;
font-weight: normal;
}
.edit-box { display: grid; grid-template-columns: 7fr 5fr; }
.edit-box .naviwrapper__buttons { grid-column: 1; grid-row: 2 }
.edit-box__left { grid-column: 1; grid-row: 2 }
.edit-box__right { grid-column: 2; grid-row: 1 / span 2 }
footer {
padding: 1em 0;
font-size: 12px;
color: #888;
}
footer a, footer a:visited {
color: #666;
}
.left-panel {
display: none;
}
.left-panel.active {
display: block;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: #fafafa;
}
.left-panel.active .sidebar {
background: #fff;
}
.left-panel__in {
width: 100%;
height: 100%;
max-width: 500px;
margin: 0 auto;
padding: 12px 24px;
}
.left-panel__contents {
width: 100%;
display: grid;
grid-template-rows: auto 1fr auto;
}
.left-panel .shroom {
margin-bottom: 16px;
}
@media (min-width: 700px) {
body {
max-width: 1200px;
padding: 8px 16px;
padding-right: 274px; /* 250px + 16px + 16px */
}
.shroom {
display: none;
}
.page {
font-size: 18px;
}
.left-panel {
display: block;
position: fixed;
top: 0;
bottom: 0;
width: 274px; /* 250px + 24px * 2 */
right: 0;
}
.left-panel__contents {
height: 100%;
}
}
.sidebar {
padding: 16px 0;
border-radius: 8px;
background: #f4f4f4;
}
.hypha-actions ul {
margin: 0;
padding: 0;
}
.hypha-actions li {
list-style: none;
}
.hypha-actions a {
display: block;
padding: 6px 16px;
font: inherit;
text-decoration: none;
color: #666;
transition: 0.1s background;
}
aside .hypha-actions a:hover {
background: #eaeaea;
}

206
w/m/sys/main.css/4.txt Normal file
View File

@ -0,0 +1,206 @@
*, *::before, *::after {
box-sizing: border-box;
}
html {
height: 100%;
}
body {
font: 15px/1.5 system-ui, -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Helvetica', 'PT Sans', 'Roboto', 'Arial', sans-serif;
max-width: 500px;
min-height: 100%;
margin: 0 auto;
padding: 12px 24px;
}
@media (min-width: 700px) {
body {
}
}
.shroom {
margin: 0;
}
.shroom__button {
border-radius: 8px;
padding: 8px 16px 8px 0;
border: none;
background: #f0f2f4;
color: #444;
font: inherit;
font-size: 15px;
font-weight: 500;
text-align: left;
}
.shroom span {
margin-left: 16px;
margin-right: 8px;
font-size: 20px;
vertical-align: -0.04em;
}
.mushroom .shroom__button {
background: #44484a;
color: #dddfe4;
}
.header {
padding: 8px 0;
}
.header h1 {
margin: 0;
font-size: 18px;
font-weight: 600;
letter-spacing: 0.02em;
color: #222428;
}
a {
color: #44e;
}
a:visited {
color: #44a;
}
h1, h2, h3, h4, h5, h6 {
margin: 1em 0 0.25em;
}
.page {
font-size: 16px;
line-height: 1.666;
max-width: 40em;
hyphens: auto;
white-space: break-spaces;
}
.page__amnt {
max-width: 100%;
}
.page__title {
font-family: 'PT Serif', 'Georgia', serif;
font-size: 36px;
font-weight: normal;
}
.edit-box { display: grid; grid-template-columns: 7fr 5fr; }
.edit-box .naviwrapper__buttons { grid-column: 1; grid-row: 2 }
.edit-box__left { grid-column: 1; grid-row: 2 }
.edit-box__right { grid-column: 2; grid-row: 1 / span 2; padding-right: 16px }
footer {
padding: 1em 0;
font-size: 12px;
color: #888;
}
footer a, footer a:visited {
color: #666;
}
.left-panel {
display: none;
}
.left-panel.active {
display: block;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: #fafafa;
}
.left-panel.active .sidebar {
background: #fff;
}
.left-panel__in {
width: 100%;
height: 100%;
max-width: 500px;
margin: 0 auto;
padding: 12px 24px;
}
.left-panel__contents {
width: 100%;
display: grid;
grid-template-rows: auto 1fr auto;
}
.left-panel .shroom {
margin-bottom: 16px;
}
@media (min-width: 700px) {
body {
max-width: 1200px;
padding: 8px 16px;
padding-right: 274px; /* 250px + 16px + 16px */
}
.shroom {
display: none;
}
.page {
font-size: 18px;
}
.left-panel {
display: block;
position: fixed;
top: 0;
bottom: 0;
width: 274px; /* 250px + 24px * 2 */
right: 0;
}
.left-panel__contents {
height: 100%;
}
}
.sidebar {
padding: 16px 0;
border-radius: 8px;
background: #f4f4f4;
}
.hypha-actions ul {
margin: 0;
padding: 0;
}
.hypha-actions li {
list-style: none;
}
.hypha-actions a {
display: block;
padding: 6px 16px;
font: inherit;
text-decoration: none;
color: #666;
transition: 0.1s background;
}
aside .hypha-actions a:hover {
background: #eaeaea;
}

210
w/m/sys/main.css/5.css Normal file
View File

@ -0,0 +1,210 @@
*, *::before, *::after {
box-sizing: border-box;
}
html {
height: 100%;
}
body {
font: 15px/1.5 system-ui, -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Helvetica', 'PT Sans', 'Roboto', 'Arial', sans-serif;
max-width: 500px;
min-height: 100%;
margin: 0 auto;
padding: 12px 24px;
}
@media (min-width: 700px) {
body {
}
}
.shroom {
margin: 0;
}
.shroom__button {
border-radius: 8px;
padding: 8px 16px 8px 0;
border: none;
background: #f0f2f4;
color: #444;
font: inherit;
font-size: 15px;
font-weight: 500;
text-align: left;
}
.shroom span {
margin-left: 16px;
margin-right: 8px;
font-size: 20px;
vertical-align: -0.04em;
}
.mushroom .shroom__button {
background: #44484a;
color: #dddfe4;
}
.header {
padding: 8px 0;
}
.header h1 {
margin: 0;
font-size: 18px;
font-weight: 600;
letter-spacing: 0.02em;
color: #222428;
}
a {
color: #44e;
}
a:visited {
color: #44a;
}
h1, h2, h3, h4, h5, h6 {
margin: 1em 0 0.25em;
}
.page {
font-size: 16px;
line-height: 1.666;
max-width: 40em;
hyphens: auto;
}
.page pre {
white-space: break-spaces;
}
.page__amnt {
max-width: 100%;
}
.page__title {
font-family: 'PT Serif', 'Georgia', serif;
font-size: 36px;
font-weight: normal;
}
.edit-box { display: grid; grid-template-columns: 7fr 5fr; }
.edit-box .naviwrapper__buttons { grid-column: 1; grid-row: 2 }
.edit-box__left { grid-column: 1; grid-row: 2 }
.edit-box__right { grid-column: 2; grid-row: 1 / span 2; padding-right: 16px }
footer {
padding: 1em 0;
font-size: 12px;
color: #888;
}
footer a, footer a:visited {
color: #666;
}
.left-panel {
display: none;
}
.left-panel.active {
display: block;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: #fafafa;
}
.left-panel.active .sidebar {
background: #fff;
}
.left-panel__in {
width: 100%;
height: 100%;
max-width: 500px;
margin: 0 auto;
padding: 12px 24px;
}
.left-panel__contents {
width: 100%;
display: grid;
grid-template-rows: auto 1fr auto;
}
.left-panel .shroom {
margin-bottom: 16px;
}
@media (min-width: 700px) {
body {
max-width: 1200px;
padding: 8px 16px;
padding-right: 274px; /* 250px + 16px + 16px */
}
.shroom {
display: none;
}
.page {
font-size: 18px;
}
.left-panel {
display: block;
position: fixed;
top: 0;
bottom: 0;
width: 274px; /* 250px + 24px * 2 */
right: 0;
}
.left-panel__contents {
height: 100%;
}
}
.sidebar {
padding: 16px 0;
border-radius: 8px;
background: #f4f4f4;
}
.hypha-actions ul {
margin: 0;
padding: 0;
}
.hypha-actions li {
list-style: none;
}
.hypha-actions a {
display: block;
padding: 6px 16px;
font: inherit;
text-decoration: none;
color: #666;
transition: 0.1s background;
}
aside .hypha-actions a:hover {
background: #eaeaea;
}

211
w/m/sys/main.css/6.css Normal file
View File

@ -0,0 +1,211 @@
*, *::before, *::after {
box-sizing: border-box;
}
html {
height: 100%;
}
body {
font: 15px/1.5 system-ui, -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Helvetica', 'PT Sans', 'Roboto', 'Arial', sans-serif;
max-width: 500px;
min-height: 100%;
margin: 0 auto;
padding: 12px 24px;
}
@media (min-width: 700px) {
body {
}
}
.shroom {
margin: 0;
}
.shroom__button {
border-radius: 8px;
padding: 8px 16px 8px 0;
border: none;
background: #f0f2f4;
color: #444;
font: inherit;
font-size: 15px;
font-weight: 500;
text-align: left;
}
.shroom span {
margin-left: 16px;
margin-right: 8px;
font-size: 20px;
vertical-align: -0.04em;
}
.mushroom .shroom__button {
background: #44484a;
color: #dddfe4;
}
.header {
padding: 8px 0;
}
.header h1 {
margin: 0;
font-size: 18px;
font-weight: 600;
letter-spacing: 0.02em;
color: #222428;
}
a {
color: #44e;
}
a:visited {
color: #44a;
}
h1, h2, h3, h4, h5, h6 {
margin: 1em 0 0.25em;
}
.page {
font-size: 16px;
line-height: 1.666;
max-width: 40em;
hyphens: auto;
}
.page pre {
white-space: break-spaces;
}
.page__amnt {
max-width: 100%;
}
.page__title {
font-family: 'PT Serif', 'Georgia', serif;
font-size: 36px;
font-weight: normal;
}
.edit-box { display: grid; grid-template-columns: 7fr 5fr; }
.edit-box .naviwrapper__buttons { grid-column: 1; grid-row: 2 }
.edit-box__left { grid-column: 1; grid-row: 2 }
.edit-box__right { grid-column: 2; grid-row: 1 / span 2; padding-right: 16px }
footer {
padding: 1em 0;
font-size: 12px;
color: #888;
}
footer a, footer a:visited {
color: #666;
}
.left-panel {
display: none;
}
.left-panel.active {
display: block;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: #fafafa;
}
.left-panel.active .sidebar {
background: #fff;
}
.left-panel__in {
width: 100%;
height: 100%;
max-width: 500px;
margin: 0 auto;
padding: 12px 24px;
}
.left-panel__contents {
width: 100%;
display: grid;
grid-template-rows: auto 1fr auto;
}
.left-panel .shroom {
margin-bottom: 16px;
}
@media (min-width: 700px) {
body {
max-width: 1200px;
padding: 8px 16px;
padding-right: 274px;
}
.shroom {
display: none;
}
.page {
font-size: 18px;
}
.left-panel {
display: block;
position: fixed;
top: 0;
bottom: 0;
width: 274px;
right: 0;
}
.left-panel__contents {
height: 100%;
}
}
.sidebar {
padding: 16px 0;
border-radius: 8px;
background: #f4f4f4;
}
.hypha-actions ul {
margin: 0;
padding: 0;
}
.hypha-actions li {
list-style: none;
}
.hypha-actions a {
display: block;
padding: 6px 16px;
font: inherit;
text-decoration: none;
color: #666;
transition: 0.1s background;
}
aside .hypha-actions a:hover {
background: #eaeaea;
}

207
w/m/sys/main.css/7.css Normal file
View File

@ -0,0 +1,207 @@
*, *::before, *::after {
box-sizing: border-box;
}
html {
height: 100%;
}
body {
font: 15px/1.5 system-ui, -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Helvetica', 'PT Sans', 'Roboto', 'Arial', sans-serif;
max-width: 500px;
min-height: 100%;
margin: 0 auto;
padding: 12px 24px;
}
.shroom {
margin: 0;
}
.shroom__button {
border-radius: 8px;
padding: 8px 16px 8px 0;
border: none;
background: #f0f2f4;
color: #444;
font: inherit;
font-size: 15px;
font-weight: 500;
text-align: left;
}
.shroom span {
margin-left: 16px;
margin-right: 8px;
font-size: 20px;
vertical-align: -0.04em;
}
.mushroom .shroom__button {
background: #44484a;
color: #dddfe4;
}
.header {
padding: 8px 0;
}
.header h1 {
margin: 0;
font-size: 18px;
font-weight: 600;
letter-spacing: 0.02em;
color: #222428;
}
a {
color: #44e;
}
a:visited {
color: #44a;
}
h1, h2, h3, h4, h5, h6 {
margin: 1em 0 0.25em;
}
.page {
font-size: 16px;
line-height: 1.666;
max-width: 40em;
hyphens: auto;
}
.page pre {
white-space: break-spaces;
}
.page__amnt {
max-width: 100%;
}
.page__title {
font-family: 'PT Serif', 'Georgia', serif;
font-size: 36px;
font-weight: normal;
}
.edit-box { display: grid; grid-template-columns: 7fr 5fr; }
.edit-box .naviwrapper__buttons { grid-column: 1; grid-row: 2 }
.edit-box__left { grid-column: 1; grid-row: 2 }
.edit-box__right { grid-column: 2; grid-row: 1 / span 2; padding-right: 16px }
footer {
padding: 1em 0;
font-size: 12px;
color: #888;
}
footer a, footer a:visited {
color: #666;
}
.left-panel {
display: none;
}
.left-panel.active {
display: block;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: #fafafa;
}
.left-panel.active .sidebar {
background: #fff;
}
.left-panel__in {
width: 100%;
height: 100%;
max-width: 500px;
margin: 0 auto;
padding: 12px 24px;
}
.left-panel__contents {
width: 100%;
display: grid;
grid-template-rows: auto 1fr auto;
}
.left-panel .shroom {
margin-bottom: 16px;
}
@media (min-width: 700px) {
body {
max-width: 1200px;
padding: 8px 16px;
padding-right: 274px;
}
.shroom {
display: none;
}
.page {
font-size: 18px;
}
.left-panel {
display: block;
position: fixed;
top: 0;
bottom: 0;
width: 274px;
right: 0;
}
.left-panel__contents {
height: 100%;
}
}
.sidebar {
padding: 16px 0;
border-radius: 8px;
background: #f4f4f4;
}
.hypha-actions ul {
margin: 0;
padding: 0;
}
.hypha-actions li {
list-style: none;
}
.hypha-actions a {
display: block;
padding: 6px 16px;
font: inherit;
text-decoration: none;
color: #666;
transition: 0.1s background;
}
aside .hypha-actions a:hover {
background: #eaeaea;
}

211
w/m/sys/main.css/8.css Normal file
View File

@ -0,0 +1,211 @@
*, *::before, *::after {
box-sizing: border-box;
}
html {
height: 100%;
}
body {
font: 15px/1.5 system-ui, -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Helvetica', 'PT Sans', 'Roboto', 'Arial', sans-serif;
max-width: 500px;
min-height: 100%;
margin: 0 auto;
padding: 12px 24px;
}
.shroom {
margin: 0;
}
.shroom__button {
border-radius: 8px;
padding: 8px 16px 8px 0;
border: none;
background: #f0f2f4;
color: #444;
font: inherit;
font-size: 15px;
font-weight: 500;
text-align: left;
}
.shroom span {
margin-left: 16px;
margin-right: 8px;
font-size: 20px;
vertical-align: -0.04em;
}
.mushroom .shroom__button {
background: #44484a;
color: #dddfe4;
}
.header {
padding: 8px 0;
}
.header h1 {
margin: 0;
font-size: 18px;
font-weight: 600;
letter-spacing: 0.02em;
color: #222428;
}
a {
color: #44e;
}
a:visited {
color: #44a;
}
h1, h2, h3, h4, h5, h6 {
margin: 1em 0 0.25em;
}
.page {
font-size: 16px;
line-height: 1.666;
max-width: 40em;
hyphens: auto;
}
.page pre {
white-space: break-spaces;
}
.page__amnt {
max-width: 100%;
}
.page__title {
font-family: 'PT Serif', 'Georgia', serif;
font-size: 36px;
font-weight: normal;
}
.edit-box {
display: grid;
grid-template-columns: 7fr 5fr;
}
.edit-box .naviwrapper__buttons { grid-column: 1; grid-row: 2 }
.edit-box__left { grid-column: 1; grid-row: 2 }
.edit-box__right { grid-column: 2; grid-row: 1 / span 2; padding-right: 16px }
footer {
padding: 1em 0;
font-size: 12px;
color: #888;
}
footer a, footer a:visited {
color: #666;
}
.left-panel {
display: none;
}
.left-panel.active {
display: block;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: #fafafa;
}
.left-panel.active .sidebar {
background: #fff;
}
.left-panel__in {
width: 100%;
height: 100%;
max-width: 500px;
margin: 0 auto;
padding: 12px 24px;
}
.left-panel__contents {
width: 100%;
display: grid;
grid-template-rows: auto 1fr auto;
}
.left-panel .shroom {
margin-bottom: 16px;
}
@media (min-width: 700px) {
body {
max-width: 1200px;
padding: 8px 16px;
padding-right: 274px;
}
.shroom {
display: none;
}
.page {
font-size: 18px;
}
.left-panel {
display: block;
position: fixed;
top: 0;
bottom: 0;
width: 274px;
right: 0;
}
.left-panel__contents {
height: 100%;
}
}
.sidebar {
padding: 16px 0;
border-radius: 8px;
background: #f4f4f4;
}
.hypha-actions ul {
margin: 0;
padding: 0;
}
.hypha-actions li {
list-style: none;
}
.hypha-actions a {
display: block;
padding: 6px 16px;
font: inherit;
text-decoration: none;
color: #666;
transition: 0.1s background;
}
aside .hypha-actions a:hover {
background: #eaeaea;
}

215
w/m/sys/main.css/9.css Normal file
View File

@ -0,0 +1,215 @@
*, *::before, *::after {
box-sizing: border-box;
}
html {
height: 100%;
}
body {
font: 15px/1.5 system-ui, -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Helvetica', 'PT Sans', 'Roboto', 'Arial', sans-serif;
max-width: 500px;
min-height: 100%;
margin: 0 auto;
padding: 12px 24px;
}
.shroom {
margin: 0;
}
.shroom__button {
border-radius: 8px;
padding: 8px 16px 8px 0;
border: none;
background: #f0f2f4;
color: #444;
font: inherit;
font-size: 15px;
font-weight: 500;
text-align: left;
}
.shroom span {
margin-left: 16px;
margin-right: 8px;
font-size: 20px;
vertical-align: -0.04em;
}
.mushroom .shroom__button {
background: #44484a;
color: #dddfe4;
}
.header {
padding: 8px 0;
}
.header h1 {
margin: 0;
font-size: 18px;
font-weight: 600;
letter-spacing: 0.02em;
color: #222428;
}
a {
color: #44e;
}
a:visited {
color: #44a;
}
h1, h2, h3, h4, h5, h6 {
margin: 1em 0 0.25em;
}
.page {
font-size: 16px;
line-height: 1.666;
max-width: 40em;
hyphens: auto;
}
.page pre {
white-space: break-spaces;
}
.page__amnt {
max-width: 100%;
}
.page__title {
font-family: 'PT Serif', 'Georgia', serif;
font-size: 36px;
font-weight: normal;
}
.edit-box {
display: grid;
grid-template-columns: 7fr 5fr;
}
.edit-box .naviwrapper__buttons {
grid-column: 1;
grid-row: 2;
}
.edit-box__left { grid-column: 1; grid-row: 2 }
.edit-box__right { grid-column: 2; grid-row: 1 / span 2; padding-right: 16px }
footer {
padding: 1em 0;
font-size: 12px;
color: #888;
}
footer a, footer a:visited {
color: #666;
}
.left-panel {
display: none;
}
.left-panel.active {
display: block;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: #fafafa;
}
.left-panel.active .sidebar {
background: #fff;
}
.left-panel__in {
width: 100%;
height: 100%;
max-width: 500px;
margin: 0 auto;
padding: 12px 24px;
}
.left-panel__contents {
width: 100%;
display: grid;
grid-template-rows: auto 1fr auto;
}
.left-panel .shroom {
margin-bottom: 16px;
}
@media (min-width: 700px) {
body {
max-width: 1200px;
padding: 8px 16px;
padding-right: 274px;
}
.shroom {
display: none;
}
.page {
font-size: 18px;
}
.left-panel {
display: block;
position: fixed;
top: 0;
bottom: 0;
width: 274px;
right: 0;
}
.left-panel__contents {
height: 100%;
}
}
.sidebar {
padding: 16px 0;
border-radius: 8px;
background: #f4f4f4;
}
.hypha-actions ul {
margin: 0;
padding: 0;
}
.hypha-actions li {
list-style: none;
}
.hypha-actions a {
display: block;
padding: 6px 16px;
font: inherit;
text-decoration: none;
color: #666;
transition: 0.1s background;
}
aside .hypha-actions a:hover {
background: #eaeaea;
}

View File

@ -1 +1,123 @@
{"views":0,"deleted":false,"revisions":{"1":{"tags":null,"name":"main.css","comment":"make a placeholder style","author":"wikimind","time":1592244023,"text_mime":"text/css","binary_mime":""},"2":{"tags":[""],"name":"","comment":"Update sys/main.css","author":"","time":1592589679,"text_mime":"text/css","binary_mime":""}}}
{
"views": 0,
"deleted": false,
"revisions": {
"1": {
"tags": [
""
],
"name": "main.css",
"comment": "make a placeholder style",
"author": "wikimind",
"time": 1592244023,
"text_mime": "text/css",
"binary_mime": "",
"text_name": "1.css",
"binary_name": ""
},
"2": {
"tags": [
""
],
"name": "main.css",
"comment": "Update sys/main.css",
"author": "who could it be?",
"time": 1592589679,
"text_mime": "text/css",
"binary_mime": "",
"text_name": "2.css",
"binary_name": ""
},
"3": {
"tags": [
""
],
"name": "main.css",
"comment": "Update sys/main.css",
"author": "",
"time": 1592663412,
"text_mime": "text/css",
"binary_mime": "",
"text_name": "3.css",
"binary_name": ""
},
"4": {
"tags": [
""
],
"name": "main.css",
"comment": "Update sys/main.css",
"author": "",
"time": 1592664073,
"text_mime": "text/css",
"binary_mime": "",
"text_name": "4.txt",
"binary_name": ""
},
"5": {
"tags": [
""
],
"name": "main.css",
"comment": "Update sys/main.css",
"author": "",
"time": 1592664242,
"text_mime": "text/css",
"binary_mime": "",
"text_name": "5.css",
"binary_name": ""
},
"6": {
"tags": [
""
],
"name": "main.css",
"comment": "Update sys/main.css",
"author": "",
"time": 1592665138,
"text_mime": "text/css",
"binary_mime": "",
"text_name": "6.css",
"binary_name": ""
},
"7": {
"tags": [
""
],
"name": "main.css",
"comment": "Update sys/main.css",
"author": "",
"time": 1592665647,
"text_mime": "text/css",
"binary_mime": "",
"text_name": "7.css",
"binary_name": ""
},
"8": {
"tags": [
""
],
"name": "main.css",
"comment": "Update sys/main.css",
"author": "",
"time": 1592666004,
"text_mime": "text/css",
"binary_mime": "",
"text_name": "8.css",
"binary_name": ""
},
"9": {
"tags": [
""
],
"name": "main.css",
"comment": "Update sys/main.css",
"author": "",
"time": 1592666188,
"text_mime": "text/css",
"binary_mime": "",
"text_name": "9.css",
"binary_name": ""
}
}
}

View File

@ -0,0 +1,8 @@
<html>
<head>
<title>Saved {{ .Name }}</title>
</head>
<body>
<p>Saved successfully. <a href="/{{ .Name }}">Go back</a></p>
</body>
</html>

68
walk.go
View File

@ -6,6 +6,7 @@ import (
"log"
"path/filepath"
"regexp"
"strconv"
)
const (
@ -13,8 +14,6 @@ const (
hyphaUrl = `/{hypha:` + hyphaPattern + `}`
revisionPattern = `[\d]+`
revQuery = `{rev:` + revisionPattern + `}`
revTxtPattern = revisionPattern + `\.txt`
revBinPattern = revisionPattern + `\.bin`
metaJsonPattern = `meta\.json`
)
@ -23,64 +22,37 @@ var (
)
// matchNameToEverything matches `name` to all filename patterns and returns 4 boolean results.
func matchNameToEverything(name string) (revTxtM, revBinM, metaJsonM, hyphaM bool) {
func matchNameToEverything(name string) (metaJsonM, hyphaM bool) {
// simpleMatch reduces boilerplate. Errors are ignored because I trust my regex skills.
simpleMatch := func(s string, p string) bool {
m, _ := regexp.MatchString(p, s)
return m
}
return simpleMatch(name, revTxtPattern),
simpleMatch(name, revBinPattern),
simpleMatch(name, metaJsonPattern),
return simpleMatch(name, metaJsonPattern),
simpleMatch(name, hyphaPattern)
}
// stripLeadingInt finds number in the beginning of `s` and returns it.
func stripLeadingInt(s string) string {
return leadingInt.FindString(s)
}
// hyphaDirRevsValidate checks if `dto` is ok.
// It also deletes pair with "0" as key so there is no revision with this id.
func hyphaDirRevsValidate(dto map[string]map[string]string) (res bool) {
if _, ok := dto["0"]; ok {
delete(dto, "0")
}
return len(dto) > 0
}
// scanHyphaDir scans directory at `fullPath` and tells what it has found.
func scanHyphaDir(fullPath string) (valid bool, revs map[string]map[string]string, possibleSubhyphae []string, metaJsonPath string, err error) {
revs = make(map[string]map[string]string)
func scanHyphaDir(fullPath string) (valid bool, possibleSubhyphae []string, metaJsonPath string, err error) {
nodes, err := ioutil.ReadDir(fullPath)
if err != nil {
return // implicit return values
}
for _, node := range nodes {
revTxtM, revBinM, metaJsonM, hyphaM := matchNameToEverything(node.Name())
metaJsonM, hyphaM := matchNameToEverything(node.Name())
switch {
case hyphaM && node.IsDir():
possibleSubhyphae = append(possibleSubhyphae, filepath.Join(fullPath, node.Name()))
case revTxtM && !node.IsDir():
revId := stripLeadingInt(node.Name())
if _, ok := revs[revId]; !ok {
revs[revId] = make(map[string]string)
}
revs[revId]["txt"] = filepath.Join(fullPath, node.Name())
case revBinM && !node.IsDir():
revId := stripLeadingInt(node.Name())
if _, ok := revs[revId]; !ok {
revs[revId] = make(map[string]string)
}
revs[revId]["bin"] = filepath.Join(fullPath, node.Name())
case metaJsonM && !node.IsDir():
metaJsonPath = filepath.Join(fullPath, "meta.json")
// Other nodes are ignored. It is not promised they will be ignored in future versions
}
}
valid = hyphaDirRevsValidate(revs)
if metaJsonPath != "" {
valid = true
}
return // implicit return values
}
@ -93,7 +65,7 @@ func hyphaName(fullPath string) string {
// recurFindHyphae recursively searches for hyphae in passed directory path.
func recurFindHyphae(fullPath string) map[string]*Hypha {
hyphae := make(map[string]*Hypha)
valid, revs, possibleSubhyphae, metaJsonPath, err := scanHyphaDir(fullPath)
valid, possibleSubhyphae, metaJsonPath, err := scanHyphaDir(fullPath)
if err != nil {
return hyphae
}
@ -126,24 +98,18 @@ func recurFindHyphae(fullPath string) map[string]*Hypha {
err = json.Unmarshal(metaJsonContents, &h)
if err != nil {
log.Printf("Error when unmarshaling `%s`; skipping", metaJsonPath)
log.Println(err)
return hyphae
}
// Fill in every revision paths
for id, paths := range revs {
if r, ok := h.Revisions[id]; ok {
r.FullName = filepath.Join(h.parentName, r.ShortName)
for fType, fPath := range paths {
switch fType {
case "bin":
r.BinaryPath = fPath
case "txt":
r.TextPath = fPath
}
}
} else {
log.Printf("Error when reading hyphae from disk: hypha `%s`'s meta.json provided no information about revision `%s`, but files %s are provided; skipping\n", h.FullName, id, paths)
// fill in rooted paths to content files and full names
for idStr, rev := range h.Revisions {
rev.FullName = filepath.Join(h.parentName, rev.ShortName)
rev.Id, _ = strconv.Atoi(idStr)
if rev.BinaryName != "" {
rev.BinaryPath = filepath.Join(fullPath, rev.BinaryName)
}
rev.TextPath = filepath.Join(fullPath, rev.TextName)
}
// Now the hypha should be ok, gotta send structs