This commit is contained in:
Henrique Dias 2015-09-15 11:59:48 +01:00
parent e3ac3a6a4b
commit 85aea63307
9 changed files with 354 additions and 36 deletions

View File

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

View File

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

View File

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

146
static/css/scrollbar.css Normal file
View File

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

View File

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

View File

@ -12,9 +12,11 @@
<link rel="stylesheet" href="/admin/static/css/normalize.css">
<link rel="stylesheet" href="/admin/static/css/main.css">
<link rel="stylesheet" href="/admin/static/css/scrollbar.css">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery.perfect-scrollbar/0.6.5/js/min/perfect-scrollbar.jquery.min.js"></script>
<script src="/admin/static/js/app.js"></script>
</head>
@ -38,4 +40,4 @@
</footer>
</body>
</html>
</html>

View File

@ -1,14 +1,24 @@
{{ define "content" }} {{ with .Body }}
<div class="content">
<h1>Editing {{ .Name }}</h1>
<form method="POST" action="">
{{ template "frontmatter" .FrontMatter }}
<textarea name="content">{{ .Content }}</textarea>
<input type="submit" value="Save">
</form>
<form method="POST" action="">
<div class="container left scroll">
<h2>Metadata</h2>
{{ template "frontmatter" .FrontMatter }}
</div>
{{ end }} {{ end }}
<div class="container main">
<textarea name="content" class="scroll">
{{ .Content }}
</textarea>
</div>
<div class="action-bar">
<button id="preview" class="left">Preview</button>
<input type="submit" value="Save">
<input type="submit" class="default" value="Publish">
</div>
</form>
{{ end }} {{ end }}

View File

@ -1,12 +1,15 @@
{{ define "frontmatter" }}
{{ range $key, $value := . }}
{{ if $value.SubContent }}
<fieldset name="{{ $value.Name }}">
{{ if or (eq $value.Type "object") (eq $value.Type "array") }}
<fieldset name="{{ $value.Name }}" type="{{ $value.Type }}">
<legend>{{ splitCapitalize $value.Name }}</legend>
{{ template "frontmatter" $value.Content }}
<button><i class="fa fa-plus"></i> Add field</button>
</fieldset>
{{ else}}
{{ else }}
{{ if not (eq $value.Parent "array") }}
<label for="{{ $value.Name }}">{{ splitCapitalize $value.Name }}</label>
{{ end }}
<input name="{{ $value.Name }}" id="{{ $value.Name }}" value="{{ $value.Content }}"></input><br>
{{ end }}
{{ end }}

View File

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