diff --git a/edit/edit.go b/edit/edit.go index a1823dd5..022fa4dc 100644 --- a/edit/edit.go +++ b/edit/edit.go @@ -66,7 +66,10 @@ func Execute(w http.ResponseWriter, r *http.Request) (int, error) { w.Header().Set("Content-Type", "application/json") w.Write([]byte("{}")) - go commands.Execute() + + if r.Header.Get("X-Save-Mode") == "Publish" { + go commands.Execute() + } } else { if _, err := os.Stat(filename); os.IsNotExist(err) { log.Print(err) diff --git a/frontmatter/frontmatter.go b/frontmatter/frontmatter.go index 1601a2b7..98990c21 100644 --- a/frontmatter/frontmatter.go +++ b/frontmatter/frontmatter.go @@ -16,16 +16,42 @@ func Pretty(content []byte) (interface{}, error) { return []string{}, err } - return rawToPretty(front, ""), nil + return rawToPretty(front, "", ""), nil } type frontmatter struct { - Name string - Content interface{} - SubContent bool + Name string + Content interface{} + Parent string + Type string } -func rawToPretty(config interface{}, master string) interface{} { +func rawToPretty(config interface{}, master string, parent string) interface{} { + if utils.IsSlice(config) { + settings := make([]interface{}, len(config.([]interface{}))) + + for index, element := range config.([]interface{}) { + c := new(frontmatter) + c.Name = master + c.Parent = parent + + if utils.IsMap(element) { + c.Type = "object" + c.Content = rawToPretty(element, c.Name, "object") + } else if utils.IsSlice(element) { + c.Type = "array" + c.Content = rawToPretty(element, c.Name, "array") + } else { + c.Type = "text" + c.Content = element + } + + settings[index] = c + } + + return settings + } + var mapsNames []string var stringsNames []string @@ -46,14 +72,18 @@ func rawToPretty(config interface{}, master string) interface{} { for index := range names { c := new(frontmatter) c.Name = names[index] - c.SubContent = false + c.Parent = parent i := config.(map[string]interface{})[names[index]] if utils.IsMap(i) { - c.Content = rawToPretty(i, c.Name) - c.SubContent = true + c.Type = "object" + c.Content = rawToPretty(i, c.Name, "object") + } else if utils.IsSlice(i) { + c.Type = "array" + c.Content = rawToPretty(i, c.Name, "array") } else { + c.Type = "text" c.Content = i } diff --git a/static/css/main.css b/static/css/main.css index 83e03b9a..061d9329 100644 --- a/static/css/main.css +++ b/static/css/main.css @@ -11,15 +11,13 @@ header { left: 0; height: 3em; width: 100%; - background-color: #EEE; + background-color: #263238; padding: 0 2em; box-sizing: border-box; z-index: 999; - color: #555; + color: #eee; } -header nav {} - header nav ul { margin: 0; padding: 0; @@ -63,7 +61,49 @@ header nav ul li a:hover { main { top: 3em; - position: relative; + left: 0; + position: fixed; + width: 100%; + height: 100%; + overflow: inherit; +} + +.container { + box-sizing: border-box; + top: 3em; + height: auto; + max-height: 100%; + bottom: 0; +} + +.container.left { + position: fixed; + left: 0; + width: 25%; + background-color: #37474F; + overflow: auto; + color: #eee; + padding: 1.5em 1.5em; +} + +.container.main { + position: fixed; + right: 0; + width: 75%; + overflow: auto; + padding: 0; + margin-bottom: 3em; +} + +.container *:first-child { + margin-top: 0; +} + +.container.main textarea { + height: 100%; + width: 100%; + padding: 2em 5em; + box-sizing: border-box; } .content { @@ -75,16 +115,15 @@ main { textarea { width: 100%; min-height: 50em; - resize: vertical; border: 0; + resize: vertical; + box-sizing: content-box; font-family: inherit; } /* FORMS */ -form {} - form input { color: rgba(0, 0, 0, 0.41); width: 15em; @@ -92,6 +131,7 @@ form input { margin: .5em 0; border: 1px solid #fff; transition: .5s ease-out all; + background-color: transparent; } form input:focus { @@ -103,4 +143,69 @@ form input:focus { form label { width: 10.5em; display: inline-block; +} + +form fieldset { + border: 0; + margin: 0; + padding: 0; +} + +form legend { + font-size: 1.5em; +} + +form .container.left input { + width: 100%; + background-color: #fff; + border-radius: 5px; + padding: .5em 1em; + box-sizing: border-box; +} + +form .container.left input:focus { + border: 1px solid #ddd; +} + +form .container.left label {} + +form .container.left legend { + font-size: 1em; + font-weight: bold; +} + +.action-bar { + position: fixed; + bottom: 0; + right: 0; + width: 75%; + background-color: #455A64; + height: 3em; + display: flex; + padding: 0.5em 1em; + box-sizing: border-box; +} + +.action-bar .left { + margin-right: auto; +} + +.action-bar *:last-child { + margin-left: 1em; +} + +button, input[type="submit"] { + border: 0; + color: #fff; + margin: 0; + padding: .5em 1em; + border-radius: 10px; + font-size: .9em; + width: auto; + line-height: 1em; + background-color: #BBB; +} + +button.default, input[type="submit"].default { + background-color: #2196F3; } \ No newline at end of file diff --git a/static/css/scrollbar.css b/static/css/scrollbar.css new file mode 100644 index 00000000..cc60ba5a --- /dev/null +++ b/static/css/scrollbar.css @@ -0,0 +1,146 @@ +/* perfect-scrollbar v0.6.5 */ + +.ps-container { + -ms-touch-action: none; + overflow: hidden !important; +} + +.ps-container.ps-active-x > .ps-scrollbar-x-rail, .ps-container.ps-active-y > .ps-scrollbar-y-rail { + display: block; +} + +.ps-container.ps-in-scrolling { + pointer-events: none; +} + +.ps-container.ps-in-scrolling.ps-x > .ps-scrollbar-x-rail { + background-color: #eee; + opacity: 0.9; +} + +.ps-container.ps-in-scrolling.ps-x > .ps-scrollbar-x-rail > .ps-scrollbar-x { + background-color: #999; +} + +.ps-container.ps-in-scrolling.ps-y > .ps-scrollbar-y-rail { + background-color: #eee; + opacity: 0.9; +} + +.ps-container.ps-in-scrolling.ps-y > .ps-scrollbar-y-rail > .ps-scrollbar-y { + background-color: #999; +} + +.ps-container > .ps-scrollbar-x-rail { + display: none; + position: absolute; + /* please don't change 'position' */ + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + -ms-border-radius: 4px; + border-radius: 4px; + opacity: 0; + -webkit-transition: background-color .2s linear, opacity .2s linear; + -moz-transition: background-color .2s linear, opacity .2s linear; + -o-transition: background-color .2s linear, opacity .2s linear; + transition: background-color .2s linear, opacity .2s linear; + bottom: 3px; + /* there must be 'bottom' for ps-scrollbar-x-rail */ + height: 8px; +} + +.ps-container > .ps-scrollbar-x-rail > .ps-scrollbar-x { + position: absolute; + /* please don't change 'position' */ + background-color: #aaa; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + -ms-border-radius: 4px; + border-radius: 4px; + -webkit-transition: background-color .2s linear; + -moz-transition: background-color .2s linear; + -o-transition: background-color .2s linear; + transition: background-color .2s linear; + bottom: 0; + /* there must be 'bottom' for ps-scrollbar-x */ + height: 8px; +} + +.ps-container > .ps-scrollbar-y-rail { + display: none; + position: absolute; + /* please don't change 'position' */ + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + -ms-border-radius: 4px; + border-radius: 4px; + opacity: 0; + -webkit-transition: background-color .2s linear, opacity .2s linear; + -moz-transition: background-color .2s linear, opacity .2s linear; + -o-transition: background-color .2s linear, opacity .2s linear; + transition: background-color .2s linear, opacity .2s linear; + right: 3px; + /* there must be 'right' for ps-scrollbar-y-rail */ + width: 8px; +} + +.ps-container > .ps-scrollbar-y-rail > .ps-scrollbar-y { + position: absolute; + /* please don't change 'position' */ + background-color: #aaa; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + -ms-border-radius: 4px; + border-radius: 4px; + -webkit-transition: background-color .2s linear; + -moz-transition: background-color .2s linear; + -o-transition: background-color .2s linear; + transition: background-color .2s linear; + right: 0; + /* there must be 'right' for ps-scrollbar-y */ + width: 8px; +} + +.ps-container:hover.ps-in-scrolling { + pointer-events: none; +} + +.ps-container:hover.ps-in-scrolling.ps-x > .ps-scrollbar-x-rail { + background-color: #eee; + opacity: 0.9; +} + +.ps-container:hover.ps-in-scrolling.ps-x > .ps-scrollbar-x-rail > .ps-scrollbar-x { + background-color: #999; +} + +.ps-container:hover.ps-in-scrolling.ps-y > .ps-scrollbar-y-rail { + background-color: #eee; + opacity: 0.9; +} + +.ps-container:hover.ps-in-scrolling.ps-y > .ps-scrollbar-y-rail > .ps-scrollbar-y { + background-color: #999; +} + +.ps-container:hover > .ps-scrollbar-x-rail, .ps-container:hover > .ps-scrollbar-y-rail { + opacity: 0.6; +} + +.ps-container:hover > .ps-scrollbar-x-rail:hover { + background-color: #eee; + opacity: 0.9; +} + +.ps-container:hover > .ps-scrollbar-x-rail:hover > .ps-scrollbar-x { + background-color: #999; +} + +.ps-container:hover > .ps-scrollbar-y-rail:hover { + background-color: #eee; + opacity: 0.9; +} + +.ps-container:hover > .ps-scrollbar-y-rail:hover > .ps-scrollbar-y { + background-color: #999; +} \ No newline at end of file diff --git a/static/js/app.js b/static/js/app.js index d15814be..cb4ab6f7 100644 --- a/static/js/app.js +++ b/static/js/app.js @@ -1,18 +1,21 @@ $(document).ready(function() { + $('.scroll').perfectScrollbar(); + + $('form').submit(function(event) { var data = JSON.stringify($(this).serializeField()) var url = $(this).attr('action') + var action = $(this).find("input[type=submit]:focus").val(); - console.log(data) + console.log(data); $.ajax({ type: 'POST', url: url, data: data, beforeSend: function(xhr) { - // add publish and save - xhr.setRequestHeader('X-Save-Mode', 'publish'); - } + xhr.setRequestHeader('X-Save-Mode', action); + }, dataType: 'json', encode: true, }).done(function(data) { @@ -47,12 +50,20 @@ $(document).ready(function() { $.fn.serializeField = function() { var result = {}; this.each(function() { - $(this).find("> *").each(function() { + $(this).find(".container > *").each(function() { var $this = $(this); var name = $this.attr("name"); if ($this.is("fieldset") && name) { - result[name] = $this.serializeField(); + if ($this.attr("type") == "array") { + result[this.name] = []; + + $.each($this.serializeArray(), function() { + result[this.name].push(this.value); + }); + } else { + result[name] = $this.serializeField(); + } } else { $.each($this.serializeArray(), function() { result[this.name] = this.value; diff --git a/templates/base_full.tmpl b/templates/base_full.tmpl index c7231659..2b021090 100644 --- a/templates/base_full.tmpl +++ b/templates/base_full.tmpl @@ -12,9 +12,11 @@ + + @@ -38,4 +40,4 @@ - \ No newline at end of file + diff --git a/templates/edit.tmpl b/templates/edit.tmpl index fea9a3ac..7c869e5d 100644 --- a/templates/edit.tmpl +++ b/templates/edit.tmpl @@ -1,14 +1,24 @@ {{ define "content" }} {{ with .Body }} -
-

Editing {{ .Name }}

- -
- {{ template "frontmatter" .FrontMatter }} - - -
+
+
+

Metadata

+ {{ template "frontmatter" .FrontMatter }}
-{{ end }} {{ end }} \ No newline at end of file +
+ +
+ +
+ + + +
+ +
+ +{{ end }} {{ end }} diff --git a/templates/frontmatter.tmpl b/templates/frontmatter.tmpl index f705aa39..154bc3ac 100644 --- a/templates/frontmatter.tmpl +++ b/templates/frontmatter.tmpl @@ -1,12 +1,15 @@ {{ define "frontmatter" }} {{ range $key, $value := . }} - {{ if $value.SubContent }} -
+ {{ if or (eq $value.Type "object") (eq $value.Type "array") }} +
{{ splitCapitalize $value.Name }} {{ template "frontmatter" $value.Content }} +
- {{ else}} + {{ else }} + {{ if not (eq $value.Parent "array") }} + {{ end }}
{{ end }} {{ end }} diff --git a/utils/utils.go b/utils/utils.go index 534c9c04..1f5433ff 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -27,6 +27,14 @@ func IsMap(sth interface{}) bool { return reflect.ValueOf(sth).Kind() == reflect.Map } +func IsSlice(sth interface{}) bool { + return reflect.ValueOf(sth).Kind() == reflect.Slice +} + +func IsArray(sth interface{}) bool { + return reflect.ValueOf(sth).Kind() == reflect.Array +} + func SplitCapitalize(name string) string { var words []string l := 0