interface updates
parent
0f18f74848
commit
44cd9bf930
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 }}
|
||||
|
|
|
@ -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">+</button>
|
||||
<button class="delete">−</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">−</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">−</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 }}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue