diff --git a/assets/public/css/styles.css b/assets/public/css/styles.css
index 52d130ec..e66e5ab2 100644
--- a/assets/public/css/styles.css
+++ b/assets/public/css/styles.css
@@ -100,7 +100,25 @@ button, select {
text-transform: none
}
button, html [type="button"], [type="reset"], [type="submit"] {
- -webkit-appearance: button
+ -webkit-appearance: button;
+ text-decoration: none;
+ color: #fff;
+ background-color: #26a69a;
+ text-align: center;
+ letter-spacing: .5px;
+ transition: .2s ease-out;
+ cursor: pointer;
+ box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.16), 0 2px 10px 0 rgba(0, 0, 0, 0.12);
+ border: none;
+ border-radius: 2px;
+ display: inline-block;
+ height: 36px;
+ line-height: 36px;
+ outline: 0;
+ padding: 0 2rem;
+ text-transform: uppercase;
+ vertical-align: middle;
+ -webkit-tap-highlight-color: transparent;
}
button::-moz-focus-inner, [type="button"]::-moz-focus-inner, [type="reset"]::-moz-focus-inner, [type="submit"]::-moz-focus-inner {
border-style: none;
@@ -110,9 +128,10 @@ button:-moz-focusring, [type="button"]:-moz-focusring, [type="reset"]:-moz-focus
outline: 1px dotted ButtonText
}
fieldset {
- border: 1px solid #c0c0c0;
- margin: 0 2px;
- padding: 0.35em 0.625em 0.75em
+ border: none;
+ margin: 0;
+ padding: 0;
+ break-inside: avoid;
}
legend {
box-sizing: border-box;
@@ -326,10 +345,10 @@ header p i {
color: rgba(255, 255, 255, .31);
}
header #logout {
- background-color: rgba(0,0,0,0.1);
- border-radius: 0;
- margin: -0.5em -0.5em -0.5em 0;
- padding: .5em;
+ background-color: rgba(0, 0, 0, 0.1);
+ border-radius: 0;
+ margin: -0.5em -0.5em -0.5em 0;
+ padding: .5em;
}
header p i {
vertical-align: middle;
@@ -430,22 +449,15 @@ header form input {
.action:hover i {
background-color: rgba(0, 0, 0, .1);
}
-
-
.floating {
- position: fixed;
- bottom: 1em;
- right: 1em;
+ position: fixed;
+ bottom: 1em;
+ right: 1em;
}
-
.floating .action {
- background-color: #68EFAD;
- color: #306e50;
- box-shadow: 0 1px 3px rgba(0, 0, 0, .06), 0 1px 2px rgba(0, 0, 0, .12);
-}
-
-#newfolder i {
- transform: rotate(45deg);
+ background-color: #68EFAD;
+ color: #306e50;
+ box-shadow: 0 1px 3px rgba(0, 0, 0, .06), 0 1px 2px rgba(0, 0, 0, .12);
}
/* LISTING */
@@ -510,44 +522,65 @@ i.spin {
/* EDITOR */
-
-#editor .block {
- box-shadow: 0 2px 5px 0 rgba(0,0,0,0.16),0 2px 10px 0 rgba(0,0,0,0.12);
- display: block;
- border-radius: .2em;
- padding: .5em;
- margin-bottom: 1em;
- break-inside: avoid;
- background-color: #fff;
-}
-
#editor .frontmatter {
- /* border: 1px solid #ddd; */
- /* background: #fff; */
- column-count: 3;
+ column-count: 2;
column-gap: 1em;
margin-bottom: 1em;
- display: flex;
- flex-direction: column;
}
-#editor label {
+#editor .group {
+ box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.16), 0 2px 10px 0 rgba(0, 0, 0, 0.12);
display: block;
- width: 19%;
- font-size: 2em;
+ border-radius: .2em;
+ padding: .5em;
+ margin-bottom: 1em;
+ break-inside: avoid;
+ background-color: #fff;
}
-#editor fieldset {
+#editor .block {
+ border-bottom: 1px solid #eee;
+ margin-bottom: .5em;
+ padding-bottom: .5em;
+}
+#editor .block:last-child {
+ border: 0;
margin: 0;
padding: 0;
- border: 0;
- background-color: rgba(0, 0, 0, .05);
}
-#editor button {
- display: none;
+#editor .block label {
+ display: block;
+ color: #212121;
+ font-weight: 500;
}
-#editor textarea[name="content"] {
- display: none;
-}
-
#editor h3 {
- font-size: .8rem;
+ margin: 0 0 .5em;
+ display: inline-block;
+ vertical-align: middle;
+ width: calc(100% - 2.5em);
+}
+#editor .block input, #editor .block .actions {
+ display: inline-block;
+}
+#editor .block input, #editor .block textarea {
+ border: 0;
+ background-color: transparent;
+ overflow: hidden;
+ color: #9E9E9E;
+ resize: none;
+ width: calc(100% - 1.5em);
+}
+#editor .action {
+ border: 0;
+ background-color: transparent;
+ font-size: .8em;
+ margin: 0;
+}
+#editor .delete {
+ color: #E53935;
+}
+#editor i {
+ padding: 0;
+}
+#editor .delete i:hover {
+ color: #B71C1C;
+ background-color: transparent;
}
diff --git a/assets/templates/base.tmpl b/assets/templates/base.tmpl
index 573ef4a1..a428f6fc 100644
--- a/assets/templates/base.tmpl
+++ b/assets/templates/base.tmpl
@@ -80,7 +80,7 @@
{{ if .IsDir }}
{{ end }}
diff --git a/assets/templates/frontmatter.tmpl b/assets/templates/frontmatter.tmpl
index 81eaaab3..0659bca5 100644
--- a/assets/templates/frontmatter.tmpl
+++ b/assets/templates/frontmatter.tmpl
@@ -1,44 +1,55 @@
{{ define "blocks" }}
-{{ range $key, $value := . }}
+ {{ if .Fields }}{{ end }}
+ {{ range $key, $value := .Fields }}
+ {{ if eq $value.Parent.Type "array" }}
+
+ {{ template "value" $value }}
+
+ close
+
+
+ {{ else }}
+
+
+ {{ template "value" $value }}
+
+ close
+
+
+ {{ end }}
+ {{ end }}
+ {{ if .Fields }}
{{ end }}
- {{ if or (eq $value.Type "object") (eq $value.Type "array") }}
-
- {{ else }}
+ {{ range $key, $value := .Arrays }}
+ {{ template "fielset" $value }}
+ {{ end }}
- {{ if not (eq $value.Parent.Type "array") }}
-
- {{ end }}
+ {{ range $key, $value := .Objects }}
+ {{ template "fielset" $value }}
+ {{ end }}
+{{ end }}
+{{ define "value" }}
+{{ if eq .HTMLType "textarea" }}
+
+{{ else if eq .HTMLType "datetime" }}
+
+{{ else }}
+
{{ end }}
{{ end }}
+
+
+{{ define "fielset" }}
+
{{ end }}
diff --git a/filemanager.go b/filemanager.go
index 98218312..d071d31f 100644
--- a/filemanager.go
+++ b/filemanager.go
@@ -84,6 +84,7 @@ func (f FileManager) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, err
}
// VCS commands
if r.Header.Get("Command") != "" {
+ // TODO: not implemented on frontend
vcs.Handle(w, r, c)
}
// Creates a new folder
diff --git a/internal/file/editor.go b/internal/file/editor.go
index 74117e5b..361a4686 100644
--- a/internal/file/editor.go
+++ b/internal/file/editor.go
@@ -5,7 +5,7 @@ import (
"path/filepath"
"strings"
- "github.com/hacdias/caddy-hugo/tools/frontmatter"
+ "github.com/hacdias/caddy-filemanager/internal/frontmatter"
"github.com/spf13/hugo/parser"
)
@@ -14,7 +14,7 @@ type Editor struct {
Class string
Mode string
Content string
- FrontMatter interface{}
+ FrontMatter *frontmatter.Content
}
// GetEditor gets the editor based on a FileInfo struct
diff --git a/internal/frontmatter/frontmatter.go b/internal/frontmatter/frontmatter.go
index f357abdf..2eedbb5f 100644
--- a/internal/frontmatter/frontmatter.go
+++ b/internal/frontmatter/frontmatter.go
@@ -1,14 +1,19 @@
package frontmatter
import (
+ "bytes"
+ "encoding/json"
+ "errors"
"log"
"reflect"
"sort"
"strings"
+ "gopkg.in/yaml.v2"
+
+ "github.com/BurntSushi/toml"
"github.com/hacdias/caddy-filemanager/utils/variables"
"github.com/spf13/cast"
- "github.com/spf13/hugo/parser"
)
const (
@@ -20,42 +25,77 @@ const (
var mainTitle = ""
// Pretty creates a new FrontMatter object
-func Pretty(content []byte) (interface{}, string, error) {
- frontType := parser.DetectFrontMatter(rune(content[0]))
- front, err := frontType.Parse(content)
+func Pretty(content []byte) (*Content, string, error) {
+ mark := rune(content[0])
+ var data interface{}
- if err != nil {
- return []string{}, mainTitle, err
+ switch mark {
+ case '-':
+ // If it's YAML
+ if err := yaml.Unmarshal(content, &data); err != nil {
+ return &Content{}, "", err
+ }
+ case '+':
+ // If it's TOML
+ content = bytes.Replace(content, []byte("+"), []byte(""), -1)
+ if _, err := toml.Decode(string(content), &data); err != nil {
+ return &Content{}, "", err
+ }
+ case '{', '[':
+ // If it's JSON
+ if err := json.Unmarshal(content, &data); err != nil {
+ return &Content{}, "", err
+ }
+ default:
+ return &Content{}, "", errors.New("Invalid frontmatter type.")
}
- object := new(frontmatter)
+ kind := reflect.ValueOf(data).Kind()
+
+ object := new(Block)
object.Type = objectType
object.Name = mainName
- return rawToPretty(front, object), mainTitle, nil
+ if kind == reflect.Map {
+ object.Type = objectType
+ } else if kind == reflect.Slice || kind == reflect.Array {
+ object.Type = arrayType
+ }
+
+ return rawToPretty(data, object), mainTitle, nil
}
-type frontmatter struct {
+// Content is the block content
+type Content struct {
+ Other interface{}
+ Fields []*Block
+ Arrays []*Block
+ Objects []*Block
+}
+
+// Block is a block
+type Block struct {
Name string
Title string
- Content interface{}
Type string
HTMLType string
- Parent *frontmatter
+ Content *Content
+ Parent *Block
}
-func rawToPretty(config interface{}, parent *frontmatter) interface{} {
- objects := []*frontmatter{}
- arrays := []*frontmatter{}
- fields := []*frontmatter{}
+func rawToPretty(config interface{}, parent *Block) *Content {
+ objects := []*Block{}
+ arrays := []*Block{}
+ fields := []*Block{}
cnf := map[string]interface{}{}
+ kind := reflect.TypeOf(config)
- if reflect.TypeOf(config) == reflect.TypeOf(map[interface{}]interface{}{}) {
+ if kind == reflect.TypeOf(map[interface{}]interface{}{}) {
for key, value := range config.(map[interface{}]interface{}) {
cnf[key.(string)] = value
}
- } else if reflect.TypeOf(config) == reflect.TypeOf([]interface{}{}) {
+ } else if kind == reflect.TypeOf([]interface{}{}) {
for key, value := range config.([]interface{}) {
cnf[string(key)] = value
}
@@ -77,18 +117,17 @@ func rawToPretty(config interface{}, parent *frontmatter) interface{} {
}
}
- sort.Sort(sortByTitle(objects))
- sort.Sort(sortByTitle(arrays))
sort.Sort(sortByTitle(fields))
-
- settings := []*frontmatter{}
- settings = append(settings, fields...)
- settings = append(settings, arrays...)
- settings = append(settings, objects...)
- return settings
+ sort.Sort(sortByTitle(arrays))
+ sort.Sort(sortByTitle(objects))
+ return &Content{
+ Fields: fields,
+ Arrays: arrays,
+ Objects: objects,
+ }
}
-type sortByTitle []*frontmatter
+type sortByTitle []*Block
func (f sortByTitle) Len() int { return len(f) }
func (f sortByTitle) Swap(i, j int) { f[i], f[j] = f[j], f[i] }
@@ -96,8 +135,8 @@ func (f sortByTitle) Less(i, j int) bool {
return strings.ToLower(f[i].Name) < strings.ToLower(f[j].Name)
}
-func handleObjects(content interface{}, parent *frontmatter, name string) *frontmatter {
- c := new(frontmatter)
+func handleObjects(content interface{}, parent *Block, name string) *Block {
+ c := new(Block)
c.Parent = parent
c.Type = objectType
c.Title = name
@@ -114,8 +153,8 @@ func handleObjects(content interface{}, parent *frontmatter, name string) *front
return c
}
-func handleArrays(content interface{}, parent *frontmatter, name string) *frontmatter {
- c := new(frontmatter)
+func handleArrays(content interface{}, parent *Block, name string) *Block {
+ c := new(Block)
c.Parent = parent
c.Type = arrayType
c.Title = name
@@ -130,8 +169,8 @@ func handleArrays(content interface{}, parent *frontmatter, name string) *frontm
return c
}
-func handleFlatValues(content interface{}, parent *frontmatter, name string) *frontmatter {
- c := new(frontmatter)
+func handleFlatValues(content interface{}, parent *Block, name string) *Block {
+ c := new(Block)
c.Parent = parent
switch reflect.ValueOf(content).Kind() {
@@ -143,14 +182,14 @@ func handleFlatValues(content interface{}, parent *frontmatter, name string) *fr
c.Type = "string"
}
- c.Content = content
+ c.Content = &Content{Other: content}
switch strings.ToLower(name) {
case "description":
c.HTMLType = "textarea"
case "date", "publishdate":
c.HTMLType = "datetime"
- c.Content = cast.ToTime(content)
+ c.Content = &Content{Other: cast.ToTime(content)}
default:
c.HTMLType = "text"
}