diff --git a/handlers.go b/handlers.go index f1eba78..1b19e9e 100644 --- a/handlers.go +++ b/handlers.go @@ -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"))) } diff --git a/hypha.go b/hypha.go index 2af293c..2eb9f09 100644 --- a/hypha.go +++ b/hypha.go @@ -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 diff --git a/mycorrhiza b/mycorrhiza deleted file mode 100755 index 47dcc16..0000000 Binary files a/mycorrhiza and /dev/null differ diff --git a/revision.go b/revision.go index fbdc170..35b653b 100644 --- a/revision.go +++ b/revision.go @@ -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 += `

` + rev.FullName + `

@@ -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 { diff --git a/w/m/Fruit/1.txt b/w/m/Fruit/1.md similarity index 100% rename from w/m/Fruit/1.txt rename to w/m/Fruit/1.md diff --git a/w/m/Fruit/2.txt b/w/m/Fruit/2.md similarity index 100% rename from w/m/Fruit/2.txt rename to w/m/Fruit/2.md diff --git a/w/m/Fruit/Apple/1.bin b/w/m/Fruit/Apple/1.jpg similarity index 100% rename from w/m/Fruit/Apple/1.bin rename to w/m/Fruit/Apple/1.jpg diff --git a/w/m/Fruit/Apple/2.bin b/w/m/Fruit/Apple/2.jpg similarity index 100% rename from w/m/Fruit/Apple/2.bin rename to w/m/Fruit/Apple/2.jpg diff --git a/w/m/Fruit/Apple/4.bin b/w/m/Fruit/Apple/4.bin new file mode 100644 index 0000000..951adc4 Binary files /dev/null and b/w/m/Fruit/Apple/4.bin differ diff --git a/w/m/Fruit/Apple/4.txt b/w/m/Fruit/Apple/4.txt new file mode 100644 index 0000000..4cfa047 --- /dev/null +++ b/w/m/Fruit/Apple/4.txt @@ -0,0 +1,2 @@ +Я́блоко — сочный плод яблони, который употребляется в пищу в свежем виде, служит сырьём в кулинарии и для приготовления напитков. Наибольшее распространение получила яблоня домашняя, реже выращивают яблоню сливолистную. Размер красных, зелёных или жёлтых шаровидных плодов 5—13 см в диаметре. Происходит из Центральной Азии, где до сих пор произрастает дикорастущий предок яблони домашней — яблоня Сиверса. На сегодняшний день существует множество сортов этого вида яблони, произрастающих в различных климатических условиях. По времени созревания отличают летние, осенние и зимние сорта, более поздние сорта отличаются хорошей стойкостью. + \ No newline at end of file diff --git a/w/m/Fruit/Apple/meta.json b/w/m/Fruit/Apple/meta.json index 85cfe94..b244423 100644 --- a/w/m/Fruit/Apple/meta.json +++ b/w/m/Fruit/Apple/meta.json @@ -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" + } + } +} \ No newline at end of file diff --git a/w/m/Fruit/meta.json b/w/m/Fruit/meta.json index d0de75f..cb14bcf 100644 --- a/w/m/Fruit/meta.json +++ b/w/m/Fruit/meta.json @@ -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" } } } diff --git a/w/m/sys/main.css/1.txt b/w/m/sys/main.css/1.css similarity index 100% rename from w/m/sys/main.css/1.txt rename to w/m/sys/main.css/1.css diff --git a/w/m/sys/main.css/2.txt b/w/m/sys/main.css/2.css similarity index 100% rename from w/m/sys/main.css/2.txt rename to w/m/sys/main.css/2.css diff --git a/w/m/sys/main.css/3.css b/w/m/sys/main.css/3.css new file mode 100644 index 0000000..ae778ab --- /dev/null +++ b/w/m/sys/main.css/3.css @@ -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; +} + + + + \ No newline at end of file diff --git a/w/m/sys/main.css/4.txt b/w/m/sys/main.css/4.txt new file mode 100644 index 0000000..c3b179b --- /dev/null +++ b/w/m/sys/main.css/4.txt @@ -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; +} + + + + + \ No newline at end of file diff --git a/w/m/sys/main.css/5.css b/w/m/sys/main.css/5.css new file mode 100644 index 0000000..6625476 --- /dev/null +++ b/w/m/sys/main.css/5.css @@ -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; +} + + + + + + \ No newline at end of file diff --git a/w/m/sys/main.css/6.css b/w/m/sys/main.css/6.css new file mode 100644 index 0000000..d8a740d --- /dev/null +++ b/w/m/sys/main.css/6.css @@ -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; +} + + + + + + + \ No newline at end of file diff --git a/w/m/sys/main.css/7.css b/w/m/sys/main.css/7.css new file mode 100644 index 0000000..5606495 --- /dev/null +++ b/w/m/sys/main.css/7.css @@ -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; +} + + + + + + + + \ No newline at end of file diff --git a/w/m/sys/main.css/8.css b/w/m/sys/main.css/8.css new file mode 100644 index 0000000..551ae81 --- /dev/null +++ b/w/m/sys/main.css/8.css @@ -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; +} + + + + + + + + + \ No newline at end of file diff --git a/w/m/sys/main.css/9.css b/w/m/sys/main.css/9.css new file mode 100644 index 0000000..e24c004 --- /dev/null +++ b/w/m/sys/main.css/9.css @@ -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; +} + + + + + + + + + + \ No newline at end of file diff --git a/w/m/sys/main.css/meta.json b/w/m/sys/main.css/meta.json index 7698b08..9035c0a 100644 --- a/w/m/sys/main.css/meta.json +++ b/w/m/sys/main.css/meta.json @@ -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":""}}} \ No newline at end of file +{ + "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": "" + } + } +} \ No newline at end of file diff --git a/w/templates/updateOk.html b/w/templates/updateOk.html new file mode 100644 index 0000000..f64067d --- /dev/null +++ b/w/templates/updateOk.html @@ -0,0 +1,8 @@ + + + Saved {{ .Name }} + + +

Saved successfully. Go back

+ + diff --git a/walk.go b/walk.go index a30f1ab..7ad2214 100644 --- a/walk.go +++ b/walk.go @@ -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