fix styles and build options, add error handling, start StaticFileManager implementation
This commit is contained in:
parent
3683e53c2a
commit
034d325ae3
9 changed files with 152 additions and 83 deletions
|
@ -1,10 +1,21 @@
|
||||||
package archetype
|
package archetype
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
type BuildStatus struct {
|
type BuildStatus struct {
|
||||||
Success bool
|
Success bool
|
||||||
Message string
|
Message string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Page struct {
|
||||||
|
Title string
|
||||||
|
Content string
|
||||||
|
Edited time.Time
|
||||||
|
Error string
|
||||||
|
}
|
||||||
|
|
||||||
type ConfigOption struct {
|
type ConfigOption struct {
|
||||||
Name string
|
Name string
|
||||||
Type string
|
Type string
|
||||||
|
@ -18,7 +29,7 @@ type Adapter interface {
|
||||||
GetConfig() map[ConfigOption]string
|
GetConfig() map[ConfigOption]string
|
||||||
SetConfig(map[ConfigOption]string) error
|
SetConfig(map[ConfigOption]string) error
|
||||||
ListPages() map[string]string
|
ListPages() map[string]string
|
||||||
GetPage(string) (Page, error)
|
GetPage(string) Page
|
||||||
FormatPage(string) string
|
FormatPage(string) string
|
||||||
FormattingHelp() string
|
FormattingHelp() string
|
||||||
CreatePage(slug, title, content string) error
|
CreatePage(slug, title, content string) error
|
||||||
|
|
|
@ -72,16 +72,25 @@ func (self *EurekaAdapter) ListPages() map[string]string {
|
||||||
return pages
|
return pages
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *EurekaAdapter) GetPage(filename string) (Page, error) {
|
func (self *EurekaAdapter) GetPage(filename string) Page {
|
||||||
|
if strings.Contains(filename, "../") || strings.Contains(filename, "..\\") {
|
||||||
|
return Page{
|
||||||
|
Error: "You cannot escape!",
|
||||||
|
}
|
||||||
|
}
|
||||||
fullPath := filepath.Join(self.Root, "inc", filename)
|
fullPath := filepath.Join(self.Root, "inc", filename)
|
||||||
f, err := os.ReadFile(fullPath)
|
f, err := os.ReadFile(fullPath)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return Page{}, err
|
return Page{
|
||||||
|
Error: err.Error(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !strings.HasSuffix(filename, ".htm") {
|
if !strings.HasSuffix(filename, ".htm") {
|
||||||
return Page{}, errors.New("Page file extension is not '.htm'")
|
return Page{
|
||||||
|
Error: "Page file extension is not '.htm'",
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
title := strings.Replace(
|
title := strings.Replace(
|
||||||
|
@ -93,7 +102,7 @@ func (self *EurekaAdapter) GetPage(filename string) (Page, error) {
|
||||||
Title: title,
|
Title: title,
|
||||||
Content: content,
|
Content: content,
|
||||||
Edited: fileInfo.ModTime(),
|
Edited: fileInfo.ModTime(),
|
||||||
}, nil
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *EurekaAdapter) FormatPage(raw string) string {
|
func (self *EurekaAdapter) FormatPage(raw string) string {
|
||||||
|
@ -111,6 +120,10 @@ func (self *EurekaAdapter) CreatePage(slug, title, content string) error {
|
||||||
slug = strings.ReplaceAll(title, " ", "_") + ".htm"
|
slug = strings.ReplaceAll(title, " ", "_") + ".htm"
|
||||||
path := filepath.Join(self.Root, "inc", slug)
|
path := filepath.Join(self.Root, "inc", slug)
|
||||||
|
|
||||||
|
if strings.Contains(slug, "../") || strings.Contains(slug, "..\\") {
|
||||||
|
return errors.New("You cannot escape!")
|
||||||
|
}
|
||||||
|
|
||||||
_, err := os.Stat(path)
|
_, err := os.Stat(path)
|
||||||
if err == nil || !os.IsNotExist(err) {
|
if err == nil || !os.IsNotExist(err) {
|
||||||
return errors.New("File already exists")
|
return errors.New("File already exists")
|
||||||
|
@ -127,6 +140,12 @@ func (self *EurekaAdapter) CreatePage(slug, title, content string) error {
|
||||||
func (self *EurekaAdapter) SavePage(oldSlug, newSlug, title, content string) error {
|
func (self *EurekaAdapter) SavePage(oldSlug, newSlug, title, content string) error {
|
||||||
// eureka creates titles from slugs, so we transform the title into the slug
|
// eureka creates titles from slugs, so we transform the title into the slug
|
||||||
newSlug = strings.ReplaceAll(title, " ", "_") + ".htm"
|
newSlug = strings.ReplaceAll(title, " ", "_") + ".htm"
|
||||||
|
|
||||||
|
if strings.Contains(newSlug, "../") || strings.Contains(newSlug, "..\\") ||
|
||||||
|
strings.Contains(oldSlug, "../") || strings.Contains(oldSlug, "..\\") {
|
||||||
|
return errors.New("You cannot escape!")
|
||||||
|
}
|
||||||
|
|
||||||
f, err := os.Create(filepath.Join(self.Root, "inc", newSlug))
|
f, err := os.Create(filepath.Join(self.Root, "inc", newSlug))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -151,6 +170,10 @@ func (self *EurekaAdapter) SavePage(oldSlug, newSlug, title, content string) err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *EurekaAdapter) DeletePage(slug string) error {
|
func (self *EurekaAdapter) DeletePage(slug string) error {
|
||||||
|
if strings.Contains(slug, "../") || strings.Contains(slug, "..\\") {
|
||||||
|
return errors.New("You cannot escape!")
|
||||||
|
}
|
||||||
|
|
||||||
siteRoot := self.Config[ConfigOption{
|
siteRoot := self.Config[ConfigOption{
|
||||||
Name: "SITEROOT",
|
Name: "SITEROOT",
|
||||||
Type: "string",
|
Type: "string",
|
||||||
|
@ -164,14 +187,14 @@ func (self *EurekaAdapter) DeletePage(slug string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *EurekaAdapter) Build(buildOptions map[string][]string) BuildStatus {
|
func (self *EurekaAdapter) Build(buildOptions map[string][]string) BuildStatus {
|
||||||
|
twtxt := strings.Join(buildOptions["twtxt"], " ")
|
||||||
twtxt := buildOptions["twtxt"][0]
|
cmdArgs := []string{}
|
||||||
cmdArgs := ""
|
|
||||||
if twtxt != "" {
|
if twtxt != "" {
|
||||||
cmdArgs += "-t " + twtxt
|
cmdArgs = append(cmdArgs, "-t")
|
||||||
|
cmdArgs = append(cmdArgs, twtxt)
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd := exec.Command("./build.sh", cmdArgs)
|
cmd := exec.Command("./build.sh", cmdArgs...)
|
||||||
cmd.Dir = self.Root
|
cmd.Dir = self.Root
|
||||||
out, err := cmd.CombinedOutput()
|
out, err := cmd.CombinedOutput()
|
||||||
|
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
package archetype
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Page struct {
|
|
||||||
Title string
|
|
||||||
Content string
|
|
||||||
Edited time.Time
|
|
||||||
}
|
|
16
archetype/staticFileManager.go
Normal file
16
archetype/staticFileManager.go
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
package archetype
|
||||||
|
|
||||||
|
type StaticFileManager struct {
|
||||||
|
Root string
|
||||||
|
ShowHtml bool
|
||||||
|
ShowHidden bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type FileManager interface {
|
||||||
|
Init(cfg Config) error
|
||||||
|
ListTree() []string
|
||||||
|
ListSubTree(root string) []string
|
||||||
|
AddFile(path string, file interface{}) error
|
||||||
|
MkDir(path string) error
|
||||||
|
Remove(path string) error
|
||||||
|
}
|
76
nirvash.go
76
nirvash.go
|
@ -3,9 +3,9 @@ package main
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
core "nilfm.cc/git/nirvash/archetype"
|
core "nilfm.cc/git/nirvash/archetype"
|
||||||
shell "nilfm.cc/git/nirvash/lfo"
|
. "nilfm.cc/git/nirvash/lfo"
|
||||||
"nilfm.cc/git/quartzgun/indentalUserDB"
|
"nilfm.cc/git/quartzgun/indentalUserDB"
|
||||||
"nilfm.cc/git/quartzgun/middleware"
|
. "nilfm.cc/git/quartzgun/middleware"
|
||||||
"nilfm.cc/git/quartzgun/renderer"
|
"nilfm.cc/git/quartzgun/renderer"
|
||||||
"nilfm.cc/git/quartzgun/router"
|
"nilfm.cc/git/quartzgun/router"
|
||||||
"os"
|
"os"
|
||||||
|
@ -40,14 +40,14 @@ func main() {
|
||||||
rtr.Get("/login", renderer.Template(
|
rtr.Get("/login", renderer.Template(
|
||||||
pathConcat(templateRoot, "login.html")))
|
pathConcat(templateRoot, "login.html")))
|
||||||
|
|
||||||
rtr.Post("/login", middleware.Authorize("/", udb, "/login?tryagain=1"))
|
rtr.Post("/login", Authorize("/", udb, "/login?tryagain=1"))
|
||||||
|
|
||||||
rtr.Get("/logout", middleware.Bunt("/", udb, "/login?tryagain=1"))
|
rtr.Get("/logout", Bunt("/", udb, "/login?tryagain=1"))
|
||||||
|
|
||||||
rtr.Get(
|
rtr.Get(
|
||||||
"/",
|
"/",
|
||||||
middleware.Protected(
|
Protected(
|
||||||
shell.WithAdapter(
|
WithAdapter(
|
||||||
renderer.Template(
|
renderer.Template(
|
||||||
pathConcat(templateRoot, "cms_list.html"),
|
pathConcat(templateRoot, "cms_list.html"),
|
||||||
pathConcat(templateRoot, "header.html"),
|
pathConcat(templateRoot, "header.html"),
|
||||||
|
@ -59,9 +59,9 @@ func main() {
|
||||||
|
|
||||||
rtr.Get(
|
rtr.Get(
|
||||||
`/edit/(?P<Slug>\S+)`,
|
`/edit/(?P<Slug>\S+)`,
|
||||||
middleware.Fortify(
|
Fortify(
|
||||||
middleware.Protected(
|
Protected(
|
||||||
shell.WithAdapter(
|
WithAdapter(
|
||||||
renderer.Template(
|
renderer.Template(
|
||||||
pathConcat(templateRoot, "cms_edit.html"),
|
pathConcat(templateRoot, "cms_edit.html"),
|
||||||
pathConcat(templateRoot, "header.html"),
|
pathConcat(templateRoot, "header.html"),
|
||||||
|
@ -73,10 +73,10 @@ func main() {
|
||||||
|
|
||||||
rtr.Post(
|
rtr.Post(
|
||||||
`/save/(?P<Slug>\S+)`,
|
`/save/(?P<Slug>\S+)`,
|
||||||
middleware.Defend(
|
Defend(
|
||||||
middleware.Protected(
|
Protected(
|
||||||
shell.WithAdapter(
|
WithAdapter(
|
||||||
shell.EnsurePageData(
|
EnsurePageData(
|
||||||
renderer.Template(
|
renderer.Template(
|
||||||
pathConcat(templateRoot, "cms_save.html"),
|
pathConcat(templateRoot, "cms_save.html"),
|
||||||
pathConcat(templateRoot, "header.html"),
|
pathConcat(templateRoot, "header.html"),
|
||||||
|
@ -91,9 +91,9 @@ func main() {
|
||||||
|
|
||||||
rtr.Get(
|
rtr.Get(
|
||||||
`/new`,
|
`/new`,
|
||||||
middleware.Fortify(
|
Fortify(
|
||||||
middleware.Protected(
|
Protected(
|
||||||
shell.WithAdapter(
|
WithAdapter(
|
||||||
renderer.Template(
|
renderer.Template(
|
||||||
pathConcat(templateRoot, "cms_new.html"),
|
pathConcat(templateRoot, "cms_new.html"),
|
||||||
pathConcat(templateRoot, "header.html"),
|
pathConcat(templateRoot, "header.html"),
|
||||||
|
@ -105,10 +105,10 @@ func main() {
|
||||||
|
|
||||||
rtr.Post(
|
rtr.Post(
|
||||||
`/create`,
|
`/create`,
|
||||||
middleware.Defend(
|
Defend(
|
||||||
middleware.Protected(
|
Protected(
|
||||||
shell.WithAdapter(
|
WithAdapter(
|
||||||
shell.EnsurePageData(
|
EnsurePageData(
|
||||||
renderer.Template(
|
renderer.Template(
|
||||||
pathConcat(templateRoot, "cms_create.html"),
|
pathConcat(templateRoot, "cms_create.html"),
|
||||||
pathConcat(templateRoot, "header.html"),
|
pathConcat(templateRoot, "header.html"),
|
||||||
|
@ -123,9 +123,9 @@ func main() {
|
||||||
|
|
||||||
rtr.Get(
|
rtr.Get(
|
||||||
`/build`,
|
`/build`,
|
||||||
middleware.Fortify(
|
Fortify(
|
||||||
middleware.Protected(
|
Protected(
|
||||||
shell.WithAdapter(
|
WithAdapter(
|
||||||
renderer.Template(
|
renderer.Template(
|
||||||
pathConcat(templateRoot, "build.html"),
|
pathConcat(templateRoot, "build.html"),
|
||||||
pathConcat(templateRoot, "header.html"),
|
pathConcat(templateRoot, "header.html"),
|
||||||
|
@ -137,10 +137,10 @@ func main() {
|
||||||
|
|
||||||
rtr.Post(
|
rtr.Post(
|
||||||
`/build-run`,
|
`/build-run`,
|
||||||
middleware.Defend(
|
Defend(
|
||||||
middleware.Protected(
|
Protected(
|
||||||
shell.SanitizeFormMap(
|
SanitizeFormMap(
|
||||||
shell.WithAdapter(
|
WithAdapter(
|
||||||
renderer.Template(
|
renderer.Template(
|
||||||
pathConcat(templateRoot, "build_run.html"),
|
pathConcat(templateRoot, "build_run.html"),
|
||||||
pathConcat(templateRoot, "header.html"),
|
pathConcat(templateRoot, "header.html"),
|
||||||
|
@ -154,9 +154,9 @@ func main() {
|
||||||
|
|
||||||
rtr.Post(
|
rtr.Post(
|
||||||
`/delete/(?P<Slug>\S+)`,
|
`/delete/(?P<Slug>\S+)`,
|
||||||
middleware.Defend(
|
Defend(
|
||||||
middleware.Protected(
|
Protected(
|
||||||
shell.WithAdapter(
|
WithAdapter(
|
||||||
renderer.Template(
|
renderer.Template(
|
||||||
pathConcat(templateRoot, "delete.html"),
|
pathConcat(templateRoot, "delete.html"),
|
||||||
pathConcat(templateRoot, "header.html"),
|
pathConcat(templateRoot, "header.html"),
|
||||||
|
@ -170,9 +170,9 @@ func main() {
|
||||||
|
|
||||||
rtr.Get(
|
rtr.Get(
|
||||||
`/config`,
|
`/config`,
|
||||||
middleware.Fortify(
|
Fortify(
|
||||||
middleware.Protected(
|
Protected(
|
||||||
shell.WithAdapter(
|
WithAdapter(
|
||||||
renderer.Template(
|
renderer.Template(
|
||||||
pathConcat(templateRoot, "config.html"),
|
pathConcat(templateRoot, "config.html"),
|
||||||
pathConcat(templateRoot, "header.html"),
|
pathConcat(templateRoot, "header.html"),
|
||||||
|
@ -184,11 +184,11 @@ func main() {
|
||||||
|
|
||||||
rtr.Post(
|
rtr.Post(
|
||||||
`/config-set`,
|
`/config-set`,
|
||||||
middleware.Defend(
|
Defend(
|
||||||
middleware.Protected(
|
Protected(
|
||||||
shell.SanitizeFormMap(
|
SanitizeFormMap(
|
||||||
shell.FormMapToAdapterConfig(
|
FormMapToAdapterConfig(
|
||||||
shell.WithAdapter(
|
WithAdapter(
|
||||||
renderer.Template(
|
renderer.Template(
|
||||||
pathConcat(templateRoot, "config_set.html"),
|
pathConcat(templateRoot, "config_set.html"),
|
||||||
pathConcat(templateRoot, "header.html"),
|
pathConcat(templateRoot, "header.html"),
|
||||||
|
|
|
@ -3,7 +3,6 @@ body {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-family: sans-serif;
|
font-family: sans-serif;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
height: 100vh;
|
|
||||||
background: black;
|
background: black;
|
||||||
color: white;
|
color: white;
|
||||||
background: url('/static/bg2.png');
|
background: url('/static/bg2.png');
|
||||||
|
@ -16,6 +15,7 @@ body {
|
||||||
background: url('/static/bg.png');
|
background: url('/static/bg.png');
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
background-position: center center;
|
background-position: center center;
|
||||||
|
height: 100vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
.login {
|
.login {
|
||||||
|
@ -48,7 +48,7 @@ body {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.login form input, .login form input:-internal-autofill-selected {
|
.login form input, #user-input, #password-input {
|
||||||
display: block;
|
display: block;
|
||||||
margin: 1em;
|
margin: 1em;
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
|
@ -60,7 +60,7 @@ body {
|
||||||
padding: 0.2em;
|
padding: 0.2em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.login form input[type="text"], login form input[type="password"] {
|
.login form input[type="text"], .login form input[type="password"] {
|
||||||
transition: border 1s;
|
transition: border 1s;
|
||||||
outline: none;
|
outline: none;
|
||||||
margin-bottom: -17px;
|
margin-bottom: -17px;
|
||||||
|
@ -73,7 +73,6 @@ body {
|
||||||
|
|
||||||
|
|
||||||
.login form input[type="submit"] {
|
.login form input[type="submit"] {
|
||||||
margin-top: -17px;
|
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
transition: background 1s, color 1s;
|
transition: background 1s, color 1s;
|
||||||
}
|
}
|
||||||
|
@ -84,7 +83,7 @@ body {
|
||||||
}
|
}
|
||||||
|
|
||||||
.login .error {
|
.login .error {
|
||||||
positon: relative;
|
position: relative;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
|
@ -109,11 +108,12 @@ h1 {
|
||||||
|
|
||||||
nav {
|
nav {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
background: rgba(0,0,0,0.8);
|
background: rgba(0,0,0,0.8);
|
||||||
padding-top: 0.5em;
|
padding-top: 0.5em;
|
||||||
padding-bottom: 0.5em;
|
padding-bottom: 0.5em;
|
||||||
position: sticky;
|
position: sticky;
|
||||||
top: 0px;
|
top: 0px;
|
||||||
|
z-index: 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
nav ul {
|
nav ul {
|
||||||
|
@ -136,9 +136,23 @@ a:hover {
|
||||||
color: cyan;
|
color: cyan;
|
||||||
}
|
}
|
||||||
|
|
||||||
a.new-page-button {
|
.new-page-button-wrapper {
|
||||||
|
display: block;
|
||||||
|
width: 80%;
|
||||||
|
max-width: 500px;
|
||||||
position: sticky;
|
position: sticky;
|
||||||
top: 0;
|
top: 5em;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
z-index: 2;
|
||||||
|
text-align: right;
|
||||||
|
height: 0;
|
||||||
|
overflow-y: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
a.new-page-button {
|
||||||
|
position: relative;
|
||||||
|
top: 1em;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
background: transparent;
|
background: transparent;
|
||||||
border: solid 2px lightgray;
|
border: solid 2px lightgray;
|
||||||
|
@ -147,8 +161,6 @@ a.new-page-button {
|
||||||
padding: 0.2em;
|
padding: 0.2em;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
transition: background 1s, color 1s;
|
transition: background 1s, color 1s;
|
||||||
float: right;
|
|
||||||
z-index: 2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
a.new-page-button:hover {
|
a.new-page-button:hover {
|
||||||
|
@ -164,8 +176,7 @@ h2 {
|
||||||
display: block;
|
display: block;
|
||||||
border-left: 8px solid cyan;
|
border-left: 8px solid cyan;
|
||||||
padding-left: 8px;
|
padding-left: 8px;
|
||||||
position: sticky;
|
position: relative;
|
||||||
top: 3em;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.page-list, form.editor, form.build, form.configurator, span.adapter-error, span.adapter-success, .danger-zone {
|
.page-list, form.editor, form.build, form.configurator, span.adapter-error, span.adapter-success, .danger-zone {
|
||||||
|
@ -177,7 +188,6 @@ h2 {
|
||||||
padding: 2em;
|
padding: 2em;
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
max-height: calc(100vh - 20em);
|
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -210,6 +220,12 @@ form.editor input[type="text"], form.configurator input[type="text"], form.confi
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
form.editor input.slug-input {
|
||||||
|
font-size: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
form.editor input.title-input {
|
form.editor input.title-input {
|
||||||
font-size: 150%;
|
font-size: 150%;
|
||||||
}
|
}
|
||||||
|
@ -230,7 +246,7 @@ form.editor textarea {
|
||||||
}
|
}
|
||||||
|
|
||||||
form.configurator textarea {
|
form.configurator textarea {
|
||||||
marign: 0;
|
margin: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 5em;
|
height: 5em;
|
||||||
}
|
}
|
||||||
|
@ -272,3 +288,7 @@ form.editor input[type="submit"]:hover,form.build input[type="submit"]:hover, .d
|
||||||
form input[hidden] {
|
form input[hidden] {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
form input[readonly] {
|
||||||
|
border: none;
|
||||||
|
}
|
|
@ -6,6 +6,12 @@
|
||||||
|
|
||||||
{{ template "header" . }}
|
{{ template "header" . }}
|
||||||
|
|
||||||
|
{{ if ($page).Error }}
|
||||||
|
<h2>Page Error</h2>
|
||||||
|
|
||||||
|
<span class="adapter-error">{{($page).Error}}</span>
|
||||||
|
{{ else }}
|
||||||
|
|
||||||
<h2>Edit Page</h2>
|
<h2>Edit Page</h2>
|
||||||
|
|
||||||
<form class="editor" method="POST" action="/save/{{$slug}}">
|
<form class="editor" method="POST" action="/save/{{$slug}}">
|
||||||
|
@ -14,12 +20,12 @@
|
||||||
{{ end }}
|
{{ end }}
|
||||||
<input hidden name="csrfToken" value="{{$csrfToken}}"/>
|
<input hidden name="csrfToken" value="{{$csrfToken}}"/>
|
||||||
<input hidden name="oldSlug" value="{{$slug}}"/>
|
<input hidden name="oldSlug" value="{{$slug}}"/>
|
||||||
{{ if $editableSlugs }}
|
<label for="title">Title</label><br/>
|
||||||
|
<input class="title-input" id="title" type="text" name="title" value="{{($page).Title}}" required/><br/>
|
||||||
|
{{ if $editableSlugs }}
|
||||||
<label for="slug">Slug</label><br/>
|
<label for="slug">Slug</label><br/>
|
||||||
<input class="slug-input" id="slug" type="text" name="slug" value="{{$slug}}" required/><br/>
|
<input class="slug-input" id="slug" type="text" name="slug" value="{{$slug}}" required/><br/>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
<label for="title">Title</label><br/>
|
|
||||||
<input class="title-input" id="title" type="text" name="title" value="{{($page).Title}}" required/><br/>
|
|
||||||
<span class="edited-time">last edited {{($page).Edited.Format "2006-01-02 15:04"}}</span><br/>
|
<span class="edited-time">last edited {{($page).Edited.Format "2006-01-02 15:04"}}</span><br/>
|
||||||
<label for="content">Content</label><br/>
|
<label for="content">Content</label><br/>
|
||||||
<textarea class="content-input" id="content" name="content" required>{{($page).Content}}</textarea><br/>
|
<textarea class="content-input" id="content" name="content" required>{{($page).Content}}</textarea><br/>
|
||||||
|
@ -38,4 +44,7 @@
|
||||||
<input type="submit" value="DELETE"/>
|
<input type="submit" value="DELETE"/>
|
||||||
</form>
|
</form>
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
{{ template "footer" . }}
|
{{ template "footer" . }}
|
||||||
|
|
|
@ -4,8 +4,11 @@
|
||||||
|
|
||||||
<h2>Pages</h2>
|
<h2>Pages</h2>
|
||||||
|
|
||||||
<div class="page-list">
|
<div class="new-page-button-wrapper">
|
||||||
<a class="new-page-button" href="/new">New Page</a>
|
<a class="new-page-button" href="/new">New Page</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="page-list">
|
||||||
<ul>
|
<ul>
|
||||||
{{ range $slug, $title := $pages }}
|
{{ range $slug, $title := $pages }}
|
||||||
<li><a href="/edit/{{$slug}}">{{$title}}</a></li>
|
<li><a href="/edit/{{$slug}}">{{$title}}</a></li>
|
||||||
|
@ -13,6 +16,4 @@
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="static-files-list">
|
{{ template "footer" .}}
|
||||||
</div>
|
|
||||||
{{ template "footer" .}}
|
|
||||||
|
|
|
@ -11,12 +11,12 @@
|
||||||
<span class="edit-error">Empty fields are not allowed - please try again</span><br/>
|
<span class="edit-error">Empty fields are not allowed - please try again</span><br/>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
<input hidden name="csrfToken" value="{{$csrfToken}}"/>
|
<input hidden name="csrfToken" value="{{$csrfToken}}"/>
|
||||||
|
<label for="title">Title</label><br/>
|
||||||
|
<input class="title-input" id="title" type="text" name="title" required/><br/>
|
||||||
{{ if $editableSlugs }}
|
{{ if $editableSlugs }}
|
||||||
<label for="slug">Slug</label><br/>
|
<label for="slug">Slug</label><br/>
|
||||||
<input class="slug-input" id="slug" type="text" name="slug" required/><br/>
|
<input class="slug-input" id="slug" type="text" name="slug" required/><br/>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
<label for="title">Title</label><br/>
|
|
||||||
<input class="title-input" id="title" type="text" name="title" required/><br/>
|
|
||||||
<label for="content">Content</label><br/>
|
<label for="content">Content</label><br/>
|
||||||
<textarea class="content-input" id="content" name="content" required></textarea><br/>
|
<textarea class="content-input" id="content" name="content" required></textarea><br/>
|
||||||
<input type="submit" value="Save"/>
|
<input type="submit" value="Save"/>
|
||||||
|
|
Loading…
Reference in a new issue