interface updates

pull/144/head
Henrique Dias 2016-06-26 23:03:27 +01:00
parent 0f18f74848
commit 44cd9bf930
6 changed files with 208 additions and 124 deletions

View File

@ -100,7 +100,25 @@ button, select {
text-transform: none text-transform: none
} }
button, html [type="button"], [type="reset"], [type="submit"] { 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 { button::-moz-focus-inner, [type="button"]::-moz-focus-inner, [type="reset"]::-moz-focus-inner, [type="submit"]::-moz-focus-inner {
border-style: none; border-style: none;
@ -110,9 +128,10 @@ button:-moz-focusring, [type="button"]:-moz-focusring, [type="reset"]:-moz-focus
outline: 1px dotted ButtonText outline: 1px dotted ButtonText
} }
fieldset { fieldset {
border: 1px solid #c0c0c0; border: none;
margin: 0 2px; margin: 0;
padding: 0.35em 0.625em 0.75em padding: 0;
break-inside: avoid;
} }
legend { legend {
box-sizing: border-box; box-sizing: border-box;
@ -326,10 +345,10 @@ header p i {
color: rgba(255, 255, 255, .31); color: rgba(255, 255, 255, .31);
} }
header #logout { header #logout {
background-color: rgba(0,0,0,0.1); background-color: rgba(0, 0, 0, 0.1);
border-radius: 0; border-radius: 0;
margin: -0.5em -0.5em -0.5em 0; margin: -0.5em -0.5em -0.5em 0;
padding: .5em; padding: .5em;
} }
header p i { header p i {
vertical-align: middle; vertical-align: middle;
@ -430,22 +449,15 @@ header form input {
.action:hover i { .action:hover i {
background-color: rgba(0, 0, 0, .1); background-color: rgba(0, 0, 0, .1);
} }
.floating { .floating {
position: fixed; position: fixed;
bottom: 1em; bottom: 1em;
right: 1em; right: 1em;
} }
.floating .action { .floating .action {
background-color: #68EFAD; background-color: #68EFAD;
color: #306e50; color: #306e50;
box-shadow: 0 1px 3px rgba(0, 0, 0, .06), 0 1px 2px rgba(0, 0, 0, .12); box-shadow: 0 1px 3px rgba(0, 0, 0, .06), 0 1px 2px rgba(0, 0, 0, .12);
}
#newfolder i {
transform: rotate(45deg);
} }
/* LISTING */ /* LISTING */
@ -510,44 +522,65 @@ i.spin {
/* EDITOR */ /* 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 { #editor .frontmatter {
/* border: 1px solid #ddd; */ column-count: 2;
/* background: #fff; */
column-count: 3;
column-gap: 1em; column-gap: 1em;
margin-bottom: 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; display: block;
width: 19%; border-radius: .2em;
font-size: 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; margin: 0;
padding: 0; padding: 0;
border: 0;
background-color: rgba(0, 0, 0, .05);
} }
#editor button { #editor .block label {
display: none; display: block;
color: #212121;
font-weight: 500;
} }
#editor textarea[name="content"] {
display: none;
}
#editor h3 { #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;
} }

View File

@ -80,7 +80,7 @@
{{ if .IsDir }} {{ if .IsDir }}
<div class="floating"> <div class="floating">
<div class="action" id="newfolder"> <div class="action" id="newfolder">
<i class="material-icons">close</i> <i class="material-icons">add</i>
</div> </div>
</div> </div>
{{ end }} {{ end }}

View File

@ -1,44 +1,55 @@
{{ define "blocks" }} {{ define "blocks" }}
{{ range $key, $value := . }} {{ if .Fields }}<div class="group">{{ end }}
{{ range $key, $value := .Fields }}
{{ if eq $value.Parent.Type "array" }}
<div id="{{ $value.Name }}-{{ $key }}" data-type="array-item">
{{ template "value" $value }}
<div class="action delete">
<i class="material-icons">close</i>
</div>
</div>
{{ else }}
<div class="block" id="block-{{ $value.Name }}" data-content="{{ $value.Name }}">
<label for="{{ $value.Name }}">{{ SplitCapitalize $value.Title }}</label>
{{ template "value" $value }}
<div class="action delete">
<i class="material-icons">close</i>
</div>
</div>
{{ end }}
{{ end }}
{{ if .Fields }}</div>{{ end }}
{{ if or (eq $value.Type "object") (eq $value.Type "array") }} {{ range $key, $value := .Arrays }}
<fieldset id="{{ $value.Name }}" data-type="{{ $value.Type }}"> {{ template "fielset" $value }}
<h3>{{ SplitCapitalize $value.Title }}</h3> {{ end }}
<span class="actions">
<button class="add">&#43;</button>
<button class="delete">&#8722;</button>
</span>
{{ template "blocks" $value.Content }}
</fieldset>
{{ else }}
{{ if not (eq $value.Parent.Type "array") }} {{ range $key, $value := .Objects }}
<div class="block" id="block-{{ $value.Name }}" data-content="{{ $value.Name }}"> {{ template "fielset" $value }}
<label for="{{ $value.Name }}">{{ SplitCapitalize $value.Title }}</label> {{ end }}
<span class="actions"> {{ end }}
<button class="delete">&#8722;</button>
</span>
{{ end }}
{{ if eq $value.Parent.Type "array" }}
<div id="{{ $value.Name }}-{{ $key }}" data-type="array-item">
{{ end }}
{{ if eq $value.HTMLType "textarea" }}
<textarea class="scroll" name="{{ $value.Name }}:{{ $value.Type }}" id="{{ $value.Name }}" data-parent-type="{{ $value.Parent.Type }}">{{ $value.Content }}</textarea>
{{ else if eq $value.HTMLType "datetime" }}
<input name="{{ $value.Name }}:{{ $value.Type }}" id="{{ $value.Name }}" value="{{ $value.Content.Format "2006-01-02T15:04" }}" type="datetime-local" data-parent-type="{{ $value.Parent.Type }}"></input>
{{ else }}
<input name="{{ $value.Name }}:{{ $value.Type }}" id="{{ $value.Name }}" value="{{ $value.Content }}" type="{{ $value.HTMLType }}" data-parent-type="{{ $value.Parent.Type }}"></input>
{{ end }}
{{ if not (eq $value.Parent.Type "array") }}</div>{{ end }}
{{ if eq $value.Parent.Type "array" }}
<span class="actions"><button class="delete">&#8722;</button></span></div>
{{ end }}
{{ define "value" }}
{{ if eq .HTMLType "textarea" }}
<textarea class="scroll" name="{{ .Name }}:{{ .Type }}" id="{{.Name }}" data-parent-type="{{ .Parent.Type }}">{{ .Content.Other }}</textarea>
{{ else if eq .HTMLType "datetime" }}
<input name="{{ .Name }}:{{ .Type }}" id="{{ .Name }}" value="{{ .Content.Other.Format "2006-01-02T15:04" }}" type="datetime-local" data-parent-type="{{ .Parent.Type }}"></input>
{{ else }}
<input name="{{ .Name }}:{{ .Type }}" id="{{ .Name }}" value="{{ .Content.Other }}" type="{{ .HTMLType }}" data-parent-type="{{ .Parent.Type }}"></input>
{{ end }} {{ end }}
{{ end }} {{ end }}
{{ define "fielset" }}
<fieldset id="{{ .Name }}" data-type="{{ .Type }}">
<h3>{{ SplitCapitalize .Title }}</h3>
<div class="action add">
<i class="material-icons">add</i>
</div>
<div class="action delete">
<i class="material-icons">close</i>
</div>
{{ template "blocks" .Content }}
</fieldset>
{{ end }} {{ end }}

View File

@ -84,6 +84,7 @@ func (f FileManager) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, err
} }
// VCS commands // VCS commands
if r.Header.Get("Command") != "" { if r.Header.Get("Command") != "" {
// TODO: not implemented on frontend
vcs.Handle(w, r, c) vcs.Handle(w, r, c)
} }
// Creates a new folder // Creates a new folder

View File

@ -5,7 +5,7 @@ import (
"path/filepath" "path/filepath"
"strings" "strings"
"github.com/hacdias/caddy-hugo/tools/frontmatter" "github.com/hacdias/caddy-filemanager/internal/frontmatter"
"github.com/spf13/hugo/parser" "github.com/spf13/hugo/parser"
) )
@ -14,7 +14,7 @@ type Editor struct {
Class string Class string
Mode string Mode string
Content string Content string
FrontMatter interface{} FrontMatter *frontmatter.Content
} }
// GetEditor gets the editor based on a FileInfo struct // GetEditor gets the editor based on a FileInfo struct

View File

@ -1,14 +1,19 @@
package frontmatter package frontmatter
import ( import (
"bytes"
"encoding/json"
"errors"
"log" "log"
"reflect" "reflect"
"sort" "sort"
"strings" "strings"
"gopkg.in/yaml.v2"
"github.com/BurntSushi/toml"
"github.com/hacdias/caddy-filemanager/utils/variables" "github.com/hacdias/caddy-filemanager/utils/variables"
"github.com/spf13/cast" "github.com/spf13/cast"
"github.com/spf13/hugo/parser"
) )
const ( const (
@ -20,42 +25,77 @@ const (
var mainTitle = "" var mainTitle = ""
// Pretty creates a new FrontMatter object // Pretty creates a new FrontMatter object
func Pretty(content []byte) (interface{}, string, error) { func Pretty(content []byte) (*Content, string, error) {
frontType := parser.DetectFrontMatter(rune(content[0])) mark := rune(content[0])
front, err := frontType.Parse(content) var data interface{}
if err != nil { switch mark {
return []string{}, mainTitle, err 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.Type = objectType
object.Name = mainName 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 Name string
Title string Title string
Content interface{}
Type string Type string
HTMLType string HTMLType string
Parent *frontmatter Content *Content
Parent *Block
} }
func rawToPretty(config interface{}, parent *frontmatter) interface{} { func rawToPretty(config interface{}, parent *Block) *Content {
objects := []*frontmatter{} objects := []*Block{}
arrays := []*frontmatter{} arrays := []*Block{}
fields := []*frontmatter{} fields := []*Block{}
cnf := map[string]interface{}{} 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{}) { for key, value := range config.(map[interface{}]interface{}) {
cnf[key.(string)] = value cnf[key.(string)] = value
} }
} else if reflect.TypeOf(config) == reflect.TypeOf([]interface{}{}) { } else if kind == reflect.TypeOf([]interface{}{}) {
for key, value := range config.([]interface{}) { for key, value := range config.([]interface{}) {
cnf[string(key)] = value 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)) sort.Sort(sortByTitle(fields))
sort.Sort(sortByTitle(arrays))
settings := []*frontmatter{} sort.Sort(sortByTitle(objects))
settings = append(settings, fields...) return &Content{
settings = append(settings, arrays...) Fields: fields,
settings = append(settings, objects...) Arrays: arrays,
return settings Objects: objects,
}
} }
type sortByTitle []*frontmatter type sortByTitle []*Block
func (f sortByTitle) Len() int { return len(f) } func (f sortByTitle) Len() int { return len(f) }
func (f sortByTitle) Swap(i, j int) { f[i], f[j] = f[j], f[i] } 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) return strings.ToLower(f[i].Name) < strings.ToLower(f[j].Name)
} }
func handleObjects(content interface{}, parent *frontmatter, name string) *frontmatter { func handleObjects(content interface{}, parent *Block, name string) *Block {
c := new(frontmatter) c := new(Block)
c.Parent = parent c.Parent = parent
c.Type = objectType c.Type = objectType
c.Title = name c.Title = name
@ -114,8 +153,8 @@ func handleObjects(content interface{}, parent *frontmatter, name string) *front
return c return c
} }
func handleArrays(content interface{}, parent *frontmatter, name string) *frontmatter { func handleArrays(content interface{}, parent *Block, name string) *Block {
c := new(frontmatter) c := new(Block)
c.Parent = parent c.Parent = parent
c.Type = arrayType c.Type = arrayType
c.Title = name c.Title = name
@ -130,8 +169,8 @@ func handleArrays(content interface{}, parent *frontmatter, name string) *frontm
return c return c
} }
func handleFlatValues(content interface{}, parent *frontmatter, name string) *frontmatter { func handleFlatValues(content interface{}, parent *Block, name string) *Block {
c := new(frontmatter) c := new(Block)
c.Parent = parent c.Parent = parent
switch reflect.ValueOf(content).Kind() { switch reflect.ValueOf(content).Kind() {
@ -143,14 +182,14 @@ func handleFlatValues(content interface{}, parent *frontmatter, name string) *fr
c.Type = "string" c.Type = "string"
} }
c.Content = content c.Content = &Content{Other: content}
switch strings.ToLower(name) { switch strings.ToLower(name) {
case "description": case "description":
c.HTMLType = "textarea" c.HTMLType = "textarea"
case "date", "publishdate": case "date", "publishdate":
c.HTMLType = "datetime" c.HTMLType = "datetime"
c.Content = cast.ToTime(content) c.Content = &Content{Other: cast.ToTime(content)}
default: default:
c.HTMLType = "text" c.HTMLType = "text"
} }