From b9c8278246e66bddc5c6afe7261caabfe58dad7b Mon Sep 17 00:00:00 2001 From: danoloan10 Date: Wed, 5 Jul 2023 18:55:41 +0200 Subject: [PATCH] Plantillas y dropdowns CSS --- admin/index.html | 35 ---- main.go | 259 ++++------------------------- static/admin.css | 47 ++++-- static/style.css | 3 + templates/admin.html | 50 ++++++ index.html => templates/index.html | 30 ++-- 6 files changed, 137 insertions(+), 287 deletions(-) delete mode 100644 admin/index.html create mode 100644 templates/admin.html rename index.html => templates/index.html (81%) diff --git a/admin/index.html b/admin/index.html deleted file mode 100644 index b2222b7..0000000 --- a/admin/index.html +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - - - splog: zona del admin 馃槑 - - -

Zona del admin 馃槑

-
- -
-
-
-
-
-
-
- -
-
-
- -
-
-
-
- - - - diff --git a/main.go b/main.go index 56aab5f..923e989 100644 --- a/main.go +++ b/main.go @@ -1,281 +1,91 @@ package main import ( - "os" - "encoding/json" "crypto/sha512" - "fmt" - "net/http" - "io/ioutil" - "sort" - "strconv" - "strings" - "sync" - "time" "encoding/hex" + "html/template" + "io" + "net/http" + "strconv" + "time" + + "muse/storage" "github.com/labstack/echo" "github.com/labstack/echo/middleware" - "github.com/gorilla/feeds" ) type ( - JSTime time.Time - Entry struct { - Artist string `json:"artist" form:"artist"` - Linkto string `json:"linkto,omitempty" form:"linkto,omitempty"` - Track string `json:"track,omitempty" form:"track,omitempty"` - Album string `json:"album,omitempty" form:"album,omitempty"` - Cover string `json:"cover,omitempty" form:"cover,omitempty"` - Date JSTime `json:"date" form:"date"` - } Response struct { Ok bool `json:"ok"` Message string `json:"message"` } -) - -type ( - entryList struct { - filename string - modtime time.Time - v []Entry - mu sync.RWMutex + TemplateRenderer struct { + template *template.Template } + Template string ) const ( - jsTimeLayout = "2006-01-02" adminUsername = "danolo" adminPassword = "bd4cad796950f50352225de3c773d8f3c39622bc17f34ad661eabe615cdf6d32751c5751e0648dc17d890f40330018334a2ae899878f200f6dc80121ddb70cc9" ) var ( - list *entryList = &entryList{ - filename: "/var/lib/muse.json", - modtime: time.Unix(0, 0), + list *storage.EntryList = &storage.EntryList{ + Filename: "/var/lib/muse.json", + ModTime: time.Unix(0, 0), } ) -func (ct *JSTime) UnmarshalJSON(b []byte) (err error) { - s := strings.Trim(string(b), `"`) - nt, err := time.Parse(jsTimeLayout, s) - *ct = JSTime(nt) - return +// TemplateRenderer +func (renderer *TemplateRenderer) Render(w io.Writer, name string, data interface{}, c echo.Context) error { + return renderer.template.ExecuteTemplate(w, name, data) } -func (ct JSTime) MarshalJSON() ([]byte, error) { - return []byte(ct.String()), nil -} - -func (ct *JSTime) String() string { - t := time.Time(*ct) - return fmt.Sprintf("%q", t.Format(jsTimeLayout)) -} - -func (list *entryList) Len() int { return len(list.v) } -func (list *entryList) Swap(i, j int) { list.v[i], list.v[j] = list.v[j], list.v[i] } -func (list *entryList) Less(i, j int) bool { - return time.Time(list.v[i].Date).After(time.Time(list.v[j].Date)) -} - -func (list *entryList) modified() (mod bool) { - info, err := os.Stat(list.filename) +func (template Template) TemplateController(c echo.Context) (err error) { + entries, err := list.GetEntries() if err == nil { - mod = list.modtime.Before(info.ModTime()) - list.modtime = info.ModTime() - } else { - mod = true + err = c.Render(http.StatusOK, string(template), entries) } return } -func (list *entryList) write() (err error) { - data, err := json.MarshalIndent(list.v, "", " ") - if err == nil { - err = ioutil.WriteFile(list.filename, data, 0644) - } - if err == nil { - list.modtime = time.Now() - } - return -} - -func (list *entryList) read() (err error) { - if list.modified() { - list.v = make([]Entry, 0, len(list.v)) - if data, err := ioutil.ReadFile(list.filename); err == nil { - err = json.Unmarshal(data, &list.v) - } - } - return -} - -func (list *entryList) addEntry(entry *Entry) (err error) { - list.mu.Lock() - defer list.mu.Unlock() - - if err = list.read(); err == nil { - list.v = append(list.v, *entry) - sort.Sort(list) - err = list.write() - } - - return -} - -func (list *entryList) readSliceList(oval int, nval int) (entries []Entry, err error) { - list.mu.RLock() - defer list.mu.RUnlock() - - if nval <= 0 { - nval = list.Len() - } - - if oval <= 0 { - oval = 0 - } - - err = list.read() - if err == nil { - if oval >= list.Len() { - entries = nil - } else if oval+nval >= list.Len() { - entries = list.v[oval:] - } else { - entries = list.v[oval : oval+nval] - } - } - - return -} - -func (list *entryList) deleteElement(pos int) (err error) { - list.mu.Lock() - defer list.mu.Unlock() - - if err = list.read(); err == nil { - if pos >= 0 && pos < list.Len() { - if pos == 0 { - list.v = list.v[pos+1:] - } else if pos == list.Len() - 1 { - list.v = list.v[:pos] - } else { - list.v = append(list.v[:pos], list.v[pos+1:]...) - } - - err = list.write() - } - } - - return -} - -// TODO rutas relativas -func (list *entryList) getFeed() (feed *feeds.Feed) { - list.mu.RLock() - defer list.mu.RUnlock() - - err := list.read() - - if err == nil { - feed = &feeds.Feed { - Title: "danoloan.es muse", - Link: &feeds.Link { Href: "https://danoloan.es/muse" }, - Description: "bit谩cora musical de danoloan", - Author: &feeds.Author { Name: "danoloan", Email: "danolo@danoloan.es" }, - } - - feed.Items = make([]*feeds.Item, 0, list.Len()) - for _, elem := range list.v { - item := &feeds.Item { - Created: time.Time(elem.Date), - } - - if elem.Track != "" { - item.Title = elem.Track - } else if elem.Album != "" { - item.Title = elem.Album - } - - item.Description = fmt.Sprintf("

%s - %s

\n", item.Title, elem.Artist) - if elem.Cover != ""{ - item.Description = fmt.Sprintf("%s\n", item.Description, elem.Cover) - } - - if elem.Linkto != "" { - item.Link = &feeds.Link{ Href: elem.Linkto } - } else { - item.Link = &feeds.Link{ Href: "https://danoloan.es/muse" } - } - - feed.Items = append(feed.Items, item) - } - } - - return -} - -func ListController(c echo.Context) (res error) { - var err error - var oval, nval int - - oval, err = strconv.Atoi(c.QueryParam("o")) - if err != nil { - oval = 0 - } - - nval, err = strconv.Atoi(c.QueryParam("n")) - if err != nil { - nval = 0 - } - - slice, err := list.readSliceList(oval, nval) - if err == nil { - res = c.JSON(http.StatusOK, slice) - } else { - response := Response{ false, "Error fetching song list" } - res = c.JSON(http.StatusInternalServerError, response) - } - - return -} - -func AddController(c echo.Context) (error) { +func AddController(c echo.Context) error { var res Response var status int var err error - entry := new(Entry) + entry := new(storage.Entry) if err = c.Bind(entry); err != nil { - res = Response{ false, err.Error() } + res = Response{false, err.Error()} status = http.StatusBadRequest - } else if err = list.addEntry(entry); err != nil { - res = Response{ false, "Failed to write into list" } + } else if err = list.AddEntry(entry); err != nil { + res = Response{false, "Failed to write into list"} status = http.StatusInternalServerError } else { - res = Response{ true, "OK" } + res = Response{true, "OK"} status = http.StatusOK } return c.JSON(status, res) } -func DelController(c echo.Context) (error) { +func DelController(c echo.Context) error { var res Response var status int var pos int pos, err := strconv.Atoi(c.QueryParam("p")) if err == nil { - err = list.deleteElement(pos) + err = list.DeleteElement(pos) } if err == nil { - res = Response{ true, "OK" } + res = Response{true, "OK"} status = http.StatusOK } else { - res = Response{ false, "Failed to delete from list" } + res = Response{false, "Failed to delete from list"} status = http.StatusInternalServerError } @@ -292,7 +102,7 @@ func auth(username, password string, c echo.Context) (bool, error) { } func RSSController(c echo.Context) (err error) { - if blob, err := list.getFeed().ToRss(); err == nil { + if blob, err := list.GetFeed().ToRss(); err == nil { c.Blob(http.StatusOK, "application/xml", []byte(blob)) } return @@ -301,16 +111,19 @@ func RSSController(c echo.Context) (err error) { func main() { e := echo.New() - e.GET("/list", ListController) + e.Renderer = &TemplateRenderer{ + template: template.Must(template.ParseGlob("templates/*.html")), + } + e.GET("/", Template("index.html").TemplateController) e.GET("/rss", RSSController) - e.Static("/", "index.html") + e.Static("/static", "static") admin := e.Group("/admin", middleware.BasicAuth(auth)) admin.POST("/add", AddController) admin.GET("/del", DelController) - admin.Static("/", "admin/index.html") + admin.GET("/", Template("admin.html").TemplateController) admin.Static("/static", "admin/static") e.Logger.Fatal(e.Start(":30303")) diff --git a/static/admin.css b/static/admin.css index 7ce8032..ed1559c 100644 --- a/static/admin.css +++ b/static/admin.css @@ -1,3 +1,7 @@ +* { + max-width: inherit; +} + input { width: 100%; box-sizing: border-box; @@ -17,17 +21,6 @@ footer > a { display: inline-block; } -.action { - padding: 20px; -} -.action[result]::after { - content: attr(result); - display: block; - padding-top: 1em; - text-align: center; - font-size: 0.75em; -} - .action-wrap { margin: 0.5em auto; border-radius: 6px; @@ -61,11 +54,41 @@ footer > a { overflow: auto; } -.cajetin { +/* Dropdown */ +button.dropdown { width: 100%; display: block; padding: 0.5em; } +button.dropdown { + padding: 0; +} +button.dropdown > input[type=checkbox] { + display: none; +} +button.dropdown > label { + padding: 0.5em; + display: block; + cursor: pointer; +} +button.dropdown:has(input[type=checkbox]:checked) ~ .action { + max-height: 50vh; + padding: 20px; +} + +.action { + max-height: 0; + padding: 0; + transition: max-height 0.2s linear; +} + +.action[result]::after { + content: attr(result); + display: block; + padding-top: 1em; + text-align: center; + font-size: 0.75em; +} .data-elem { display: block; diff --git a/static/style.css b/static/style.css index 6c4deae..5689e82 100644 --- a/static/style.css +++ b/static/style.css @@ -58,12 +58,14 @@ button, .button { cursor: pointer; } +input[type=checkbox].button:hover ~ button, input[type=button]:hover, input[type=submit]:hover, button:hover, .button:hover { background-color: #444; } +input[type=checkbox].button:active ~ button, input[type=button]:active, input[type=submit]:active, button:active, @@ -100,6 +102,7 @@ hr { background-color: #eee; } + input[type=checkbox].button:hover ~ button, input[type=button]:hover, input[type=submit]:hover, button:hover, diff --git a/templates/admin.html b/templates/admin.html new file mode 100644 index 0000000..b77f7cc --- /dev/null +++ b/templates/admin.html @@ -0,0 +1,50 @@ + + + + + + + + splog: zona del admin 馃槑 + + +

Zona del admin 馃槑

+
+ +
+
+
+
+
+
+
+ +
+
+
+ +
+
+ {{ range . }} + + {{ end }} +
+
+
+ + + diff --git a/index.html b/templates/index.html similarity index 81% rename from index.html rename to templates/index.html index 49e49f3..e66c20c 100644 --- a/index.html +++ b/templates/index.html @@ -20,7 +20,7 @@ body { display: inline-table; background-color: #333; color: #ddd; - transition: transform .1s; + transition: transform .1s; box-sizing: border-box; word-break: break-word; font-size: calc(0.5em + 1vw); @@ -31,6 +31,10 @@ body { background-color: #373737; } +main > a { + font-size: 0px; +} + .title { margin: 10px 20px; font-weight: bold; @@ -122,8 +126,6 @@ nav > a:hover { } - -
@@ -148,22 +150,16 @@ nav > a:hover { Zona del admin 馃槑
-
-
-