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
}
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;
@ -430,24 +449,17 @@ header form input {
.action:hover i {
background-color: rgba(0, 0, 0, .1);
}
.floating {
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);
}
/* LISTING */
#listing {
@ -510,8 +522,12 @@ i.spin {
/* EDITOR */
#editor .block {
#editor .frontmatter {
column-count: 2;
column-gap: 1em;
margin-bottom: 1em;
}
#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;
border-radius: .2em;
@ -520,34 +536,51 @@ i.spin {
break-inside: avoid;
background-color: #fff;
}
#editor .frontmatter {
/* border: 1px solid #ddd; */
/* background: #fff; */
column-count: 3;
column-gap: 1em;
margin-bottom: 1em;
display: flex;
flex-direction: column;
#editor .block {
border-bottom: 1px solid #eee;
margin-bottom: .5em;
padding-bottom: .5em;
}
#editor label {
display: block;
width: 19%;
font-size: 2em;
}
#editor fieldset {
#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;
}

View File

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

View File

@ -1,44 +1,55 @@
{{ define "blocks" }}
{{ range $key, $value := . }}
{{ if or (eq $value.Type "object") (eq $value.Type "array") }}
<fieldset id="{{ $value.Name }}" data-type="{{ $value.Type }}">
<h3>{{ SplitCapitalize $value.Title }}</h3>
<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") }}
<div class="block" id="block-{{ $value.Name }}" data-content="{{ $value.Name }}">
<label for="{{ $value.Name }}">{{ SplitCapitalize $value.Title }}</label>
<span class="actions">
<button class="delete">&#8722;</button>
</span>
{{ end }}
{{ 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">
{{ 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>
{{ template "value" $value }}
<div class="action delete">
<i class="material-icons">close</i>
</div>
</div>
{{ else }}
<input name="{{ $value.Name }}:{{ $value.Type }}" id="{{ $value.Name }}" value="{{ $value.Content }}" type="{{ $value.HTMLType }}" data-parent-type="{{ $value.Parent.Type }}"></input>
<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 }}
{{ range $key, $value := .Arrays }}
{{ template "fielset" $value }}
{{ 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>
{{ range $key, $value := .Objects }}
{{ template "fielset" $value }}
{{ end }}
{{ 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 }}
{{ 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 }}

View File

@ -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

View File

@ -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

View File

@ -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
}
type frontmatter struct {
return rawToPretty(data, object), mainTitle, nil
}
// 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"
}