diff options
author | FChannel0 <77419041+FChannel0@users.noreply.github.com> | 2021-08-20 01:35:26 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-08-20 01:35:26 -0700 |
commit | 502558e0bdaf67ca4c012fc1983f42430b8854cd (patch) | |
tree | d66b015274b962fedb28c52c0efaaa068368f2b1 | |
parent | 21917eb2ea72fe40d70c2c991e821aace5430c23 (diff) | |
parent | a497499817cbf72b295253e1a2bb1011d121ba28 (diff) |
Merge pull request #52 from KushBlazingJudah/development
Themes
-rw-r--r-- | activityPubStruct.go | 20 | ||||
-rw-r--r-- | cacheDatabase.go | 8 | ||||
-rw-r--r-- | client.go | 126 | ||||
-rw-r--r-- | database.go | 8 | ||||
-rw-r--r-- | follow.go | 2 | ||||
-rw-r--r-- | main.go | 62 | ||||
-rw-r--r-- | static/archive.html | 2 | ||||
-rw-r--r-- | static/bottom.html | 23 | ||||
-rw-r--r-- | static/css/themes/default.css | 162 | ||||
-rw-r--r-- | static/css/themes/gruvbox.css | 140 | ||||
-rw-r--r-- | static/index.html | 40 | ||||
-rw-r--r-- | static/js/posts.js | 26 | ||||
-rw-r--r-- | static/js/themes.js | 40 | ||||
-rw-r--r-- | static/main.html | 92 | ||||
-rw-r--r-- | static/manage.html | 6 | ||||
-rw-r--r-- | static/nadmin.html | 8 | ||||
-rw-r--r-- | static/ncatalog.html | 63 | ||||
-rw-r--r-- | static/nposts.html | 30 | ||||
-rw-r--r-- | static/posts.html | 12 | ||||
-rw-r--r-- | static/top.html | 130 |
20 files changed, 706 insertions, 294 deletions
diff --git a/activityPubStruct.go b/activityPubStruct.go index 459259a..8676b12 100644 --- a/activityPubStruct.go +++ b/activityPubStruct.go @@ -1,6 +1,8 @@ package main import ( + "time" + "encoding/json" "html/template" ) @@ -19,7 +21,7 @@ type ActivityRaw struct { ToRaw json.RawMessage `json:"to,omitempty"` BtoRaw json.RawMessage `json:"bto,omitempty"` CcRaw json.RawMessage `json:"cc,omitempty"` - Published string `json:"published,omitempty"` + Published time.Time `json:"published,omitempty"` ActorRaw json.RawMessage `json:"actor,omitempty"` ObjectRaw json.RawMessage `json:"object,omitempty"` } @@ -97,11 +99,11 @@ type Activity struct { Name string `json:"name,omitempty"` Summary string `json:"summary,omitempty"` Auth string `json:"auth,omitempty"` - To []string `json:"to, omitempty"` + To []string `json:"to,omitempty"` Bto []string `json:"bto,omitempty"` - Cc []string `json:"cc, omitempty"` - Published string `json:"published,omitempty"` - Object *ObjectBase `json:"object, omitempty"` + Cc []string `json:"cc,omitempty"` + Published time.Time `json:"published,omitempty"` + Object *ObjectBase `json:"object,omitempty"` } type ObjectBase struct { @@ -123,8 +125,8 @@ type ObjectBase struct { InReplyTo []ObjectBase `json:"inReplyTo,omitempty"` Location string `json:"location,omitempty"` Preview *NestedObjectBase `json:"preview,omitempty"` - Published string `json:"published,omitempty"` - Updated string `json:"updated,omitempty"` + Published time.Time `json:"published,omitempty"` + Updated time.Time `json:"updated,omitempty"` Object *NestedObjectBase `json:"object,omitempty"` Attachment []ObjectBase `json:"attachment,omitempty"` Replies *CollectionBase `json:"replies,omitempty"` @@ -169,13 +171,13 @@ type NestedObjectBase struct { InReplyTo []ObjectBase `json:"inReplyTo,omitempty"` Location string `json:"location,omitempty"` Preview ObjectBase `json:"preview,omitempty"` - Published string `json:"published,omitempty"` + Published time.Time `json:"published,omitempty"` Attachment []ObjectBase `json:"attachment,omitempty"` Replies *CollectionBase `json:"replies,omitempty"` StartTime string `json:"startTime,omitempty"` Summary string `json:"summary,omitempty"` Tag []ObjectBase `json:"tag,omitempty"` - Updated string `json:"updated,omitempty"` + Updated time.Time `json:"updated,omitempty"` Deleted string `json:"deleted,omitempty"` Url []ObjectBase `json:"url,omitempty"` Href string `json:"href,omitempty"` diff --git a/cacheDatabase.go b/cacheDatabase.go index ffe5dad..d735cfe 100644 --- a/cacheDatabase.go +++ b/cacheDatabase.go @@ -92,7 +92,7 @@ func WriteActivitytoCache(db *sql.DB, obj ObjectBase) { return } - if obj.Updated == "" { + if obj.Updated.IsZero() { obj.Updated = obj.Published } @@ -127,7 +127,7 @@ func WriteActivitytoCacheWithAttachment(db *sql.DB, obj ObjectBase, attachment O return } - if obj.Updated == "" { + if obj.Updated.IsZero() { obj.Updated = obj.Published } @@ -158,7 +158,7 @@ func WriteAttachmentToCache(db *sql.DB, obj ObjectBase) { return } - if obj.Updated == "" { + if obj.Updated.IsZero() { obj.Updated = obj.Published } @@ -189,7 +189,7 @@ func WritePreviewToCache(db *sql.DB, obj NestedObjectBase) { return } - if obj.Updated == "" { + if obj.Updated.IsZero() { obj.Updated = obj.Published } @@ -5,6 +5,7 @@ import ( "fmt" _ "github.com/lib/pq" "html/template" + "log" "net/http" "regexp" "sort" @@ -53,6 +54,7 @@ type PageData struct { ReturnTo string NewsItems []NewsItem BoardRemainer []int + Themes *[]string } type AdminPage struct { @@ -68,6 +70,7 @@ type AdminPage struct { IsLocal bool PostBlacklist []PostBlacklist AutoSubscribe bool + Themes *[]string } type Report struct { @@ -93,11 +96,31 @@ type PostBlacklist struct { Regex string } +func mod(i, j int) bool { + return i%j == 0 +} + +func sub(i, j int) int { + return i - j +} + +func unixToReadable(u int) string { + return time.Unix(int64(u), 0).Format("Jan 02, 2006") +} + +func timeToReadableLong(t time.Time) string { + return t.Format("01/02/06(Mon)15:04:05") +} + +func timeToUnix(t time.Time) string { + return fmt.Sprint(t.Unix()) +} + func IndexGet(w http.ResponseWriter, r *http.Request, db *sql.DB) { t := template.Must(template.New("").Funcs(template.FuncMap{ - "mod": func(i, j int) bool { return i%j == 0 }, - "sub": func(i, j int) int { return i - j }, - "unixtoreadable": func(u int) string { return time.Unix(int64(u), 0).Format("Jan 02, 2006") }}).ParseFiles("./static/main.html", "./static/index.html")) + "mod": mod, + "sub": sub, + "unixtoreadable": unixToReadable}).ParseFiles("./static/main.html", "./static/index.html")) actor := GetActorFromDB(db, Domain) @@ -122,13 +145,19 @@ func IndexGet(w http.ResponseWriter, r *http.Request, db *sql.DB) { data.InstanceIndex = GetCollectionFromReq("https://fchan.xyz/followers").Items data.NewsItems = getNewsFromDB(db, 3) - t.ExecuteTemplate(w, "layout", data) + data.Themes = &Themes + + err := t.ExecuteTemplate(w, "layout", data) + if err != nil { + // TODO: actual error handler + log.Printf("IndexGet: %s\n", err) + } } func NewsGet(w http.ResponseWriter, r *http.Request, db *sql.DB, timestamp int) { t := template.Must(template.New("").Funcs(template.FuncMap{ - "sub": func(i, j int) int { return i - j }, - "unixtoreadable": func(u int) string { return time.Unix(int64(u), 0).Format("Jan 02, 2006") }}).ParseFiles("./static/main.html", "./static/news.html")) + "sub": mod, + "unixtoreadable": unixToReadable}).ParseFiles("./static/main.html", "./static/news.html")) actor := GetActorFromDB(db, Domain) @@ -155,14 +184,20 @@ func NewsGet(w http.ResponseWriter, r *http.Request, db *sql.DB, timestamp int) data.Title = actor.PreferredUsername + ": " + data.NewsItems[0].Title - t.ExecuteTemplate(w, "layout", data) + data.Themes = &Themes + + err = t.ExecuteTemplate(w, "layout", data) + if err != nil { + // TODO: actual error handler + log.Printf("NewsGet: %s\n", err) + } } func AllNewsGet(w http.ResponseWriter, r *http.Request, db *sql.DB) { t := template.Must(template.New("").Funcs(template.FuncMap{ - "mod": func(i, j int) bool { return i%j == 0 }, - "sub": func(i, j int) int { return i - j }, - "unixtoreadable": func(u int) string { return time.Unix(int64(u), 0).Format("Jan 02, 2006") }}).ParseFiles("./static/main.html", "./static/anews.html")) + "mod": mod, + "sub": sub, + "unixtoreadable": unixToReadable}).ParseFiles("./static/main.html", "./static/anews.html")) actor := GetActorFromDB(db, Domain) @@ -179,7 +214,13 @@ func AllNewsGet(w http.ResponseWriter, r *http.Request, db *sql.DB) { data.Board.Restricted = actor.Restricted data.NewsItems = getNewsFromDB(db, 0) - t.ExecuteTemplate(w, "layout", data) + data.Themes = &Themes + + err := t.ExecuteTemplate(w, "layout", data) + if err != nil { + // TODO: actual error handler + log.Printf("AllNewsGet: %s\n", err) + } } func OutboxGet(w http.ResponseWriter, r *http.Request, db *sql.DB, collection Collection) { @@ -216,13 +257,15 @@ func OutboxGet(w http.ResponseWriter, r *http.Request, db *sql.DB, collection Co "parseReplyLink": func(actorId string, op string, id string, content string) template.HTML { actor := FingerActor(actorId) title := strings.ReplaceAll(ParseLinkTitle(actor.Id, op, content), `/\<`, ">") - link := "<a href=\"" + actor.Name + "/" + shortURL(actor.Outbox, op) + "#" + shortURL(actor.Outbox, id) + "\" title=\"" + title + "\">>>" + shortURL(actor.Outbox, id) + "</a>" + link := "<a href=\"" + actor.Name + "/" + shortURL(actor.Outbox, op) + "#" + shortURL(actor.Outbox, id) + "\" title=\"" + title + "\" class=\"replyLink\">>>" + shortURL(actor.Outbox, id) + "</a>" return template.HTML(link) }, "add": func(i, j int) int { return i + j }, - "sub": func(i, j int) int { return i - j }}).ParseFiles("./static/main.html", "./static/nposts.html", "./static/top.html", "./static/bottom.html", "./static/posts.html")) + "timeToReadableLong": timeToReadableLong, + "timeToUnix": timeToUnix, + "sub": sub}).ParseFiles("./static/main.html", "./static/nposts.html", "./static/top.html", "./static/bottom.html", "./static/posts.html")) actor := collection.Actor @@ -271,7 +314,13 @@ func OutboxGet(w http.ResponseWriter, r *http.Request, db *sql.DB, collection Co returnData.Pages = pages returnData.TotalPage = len(returnData.Pages) - 1 - t.ExecuteTemplate(w, "layout", returnData) + returnData.Themes = &Themes + + err := t.ExecuteTemplate(w, "layout", returnData) + if err != nil { + // TODO: actual error handler + log.Printf("OutboxGet: %s\n", err) + } } func CatalogGet(w http.ResponseWriter, r *http.Request, db *sql.DB, collection Collection) { @@ -296,7 +345,7 @@ func CatalogGet(w http.ResponseWriter, r *http.Request, db *sql.DB, collection C } return false }, - "sub": func(i, j int) int { return i - j }}).ParseFiles("./static/main.html", "./static/ncatalog.html", "./static/top.html")) + "sub": sub}).ParseFiles("./static/main.html", "./static/ncatalog.html", "./static/top.html")) actor := collection.Actor @@ -326,7 +375,13 @@ func CatalogGet(w http.ResponseWriter, r *http.Request, db *sql.DB, collection C returnData.Posts = collection.OrderedItems - t.ExecuteTemplate(w, "layout", returnData) + returnData.Themes = &Themes + + err := t.ExecuteTemplate(w, "layout", returnData) + if err != nil { + // TODO: actual error handler + log.Printf("CatalogGet: %s\n", err) + } } func ArchiveGet(w http.ResponseWriter, r *http.Request, db *sql.DB, collection Collection) { @@ -343,8 +398,8 @@ func ArchiveGet(w http.ResponseWriter, r *http.Request, db *sql.DB, collection C "parseAttachment": func(obj ObjectBase, catalog bool) template.HTML { return ParseAttachment(obj, catalog) }, - "mod": func(i, j int) bool { return i%j == 0 }, - "sub": func(i, j int) int { return i - j }}).ParseFiles("./static/main.html", "./static/archive.html", "./static/bottom.html")) + "mod": mod, + "sub": sub}).ParseFiles("./static/main.html", "./static/archive.html", "./static/bottom.html")) actor := collection.Actor @@ -374,7 +429,13 @@ func ArchiveGet(w http.ResponseWriter, r *http.Request, db *sql.DB, collection C returnData.Posts = collection.OrderedItems - t.ExecuteTemplate(w, "layout", returnData) + returnData.Themes = &Themes + + err := t.ExecuteTemplate(w, "layout", returnData) + if err != nil { + // TODO: actual error handler + log.Printf("ArchiveGet: %s\n", err) + } } func PostGet(w http.ResponseWriter, r *http.Request, db *sql.DB) { @@ -403,10 +464,12 @@ func PostGet(w http.ResponseWriter, r *http.Request, db *sql.DB) { "parseReplyLink": func(actorId string, op string, id string, content string) template.HTML { actor := FingerActor(actorId) title := strings.ReplaceAll(ParseLinkTitle(actor.Id, op, content), `/\<`, ">") - link := "<a href=\"" + actor.Name + "/" + shortURL(actor.Outbox, op) + "#" + shortURL(actor.Outbox, id) + "\" title=\"" + title + "\">>>" + shortURL(actor.Outbox, id) + "</a>" + link := "<a href=\"" + actor.Name + "/" + shortURL(actor.Outbox, op) + "#" + shortURL(actor.Outbox, id) + "\" title=\"" + title + "\" class=\"replyLink\">>>" + shortURL(actor.Outbox, id) + "</a>" return template.HTML(link) }, - "sub": func(i, j int) int { return i - j }}).ParseFiles("./static/main.html", "./static/npost.html", "./static/top.html", "./static/bottom.html", "./static/posts.html")) + "timeToReadableLong": timeToReadableLong, + "timeToUnix": timeToUnix, + "sub": sub}).ParseFiles("./static/main.html", "./static/npost.html", "./static/top.html", "./static/bottom.html", "./static/posts.html")) path := r.URL.Path actor := GetActorFromPath(db, path, "/") @@ -467,7 +530,13 @@ func PostGet(w http.ResponseWriter, r *http.Request, db *sql.DB) { returnData.PostId = shortURL(returnData.Board.To, returnData.Posts[0].Id) } - t.ExecuteTemplate(w, "layout", returnData) + returnData.Themes = &Themes + + err := t.ExecuteTemplate(w, "layout", returnData) + if err != nil { + // TODO: actual error handler + log.Printf("PostGet: %s\n", err) + } } func GetBoardCollection(db *sql.DB) []Board { @@ -724,13 +793,13 @@ func GetActorsFollowPostFromId(db *sql.DB, actors []string, id string) Collectio type ObjectBaseSortDesc []ObjectBase func (a ObjectBaseSortDesc) Len() int { return len(a) } -func (a ObjectBaseSortDesc) Less(i, j int) bool { return a[i].Updated > a[j].Updated } +func (a ObjectBaseSortDesc) Less(i, j int) bool { return a[i].Updated.After(a[j].Updated) } func (a ObjectBaseSortDesc) Swap(i, j int) { a[i], a[j] = a[j], a[i] } type ObjectBaseSortAsc []ObjectBase func (a ObjectBaseSortAsc) Len() int { return len(a) } -func (a ObjectBaseSortAsc) Less(i, j int) bool { return a[i].Published < a[j].Published } +func (a ObjectBaseSortAsc) Less(i, j int) bool { return a[i].Published.Before(a[j].Published) } func (a ObjectBaseSortAsc) Swap(i, j int) { a[i], a[j] = a[j], a[i] } type BoardSortAsc []Board @@ -886,17 +955,12 @@ func ParseLinkComments(db *sql.DB, board Actor, op string, content string, threa } } - var style string - if board.Restricted { - style = "color: #af0a0f;" - } - //replace link with quote format replyID, isReply := IsReplyToOP(db, op, parsedLink) if isReply { id := shortURL(board.Outbox, replyID) - content = strings.Replace(content, match[i][0], "<a class=\"reply\" style=\""+style+"\" title=\""+quoteTitle+"\" href=\"/"+board.Name+"/"+shortURL(board.Outbox, op)+"#"+id+"\">>>"+id+""+isOP+"</a>", -1) + content = strings.Replace(content, match[i][0], "<a class=\"reply\" title=\""+quoteTitle+"\" href=\"/"+board.Name+"/"+shortURL(board.Outbox, op)+"#"+id+"\">>>"+id+""+isOP+"</a>", -1) } else { @@ -909,7 +973,7 @@ func ParseLinkComments(db *sql.DB, board Actor, op string, content string, threa } if actor.Id != "" { - content = strings.Replace(content, match[i][0], "<a class=\"reply\" style=\""+style+"\" title=\""+quoteTitle+"\" href=\""+link+"\">>>"+shortURL(board.Outbox, parsedLink)+isOP+" →</a>", -1) + content = strings.Replace(content, match[i][0], "<a class=\"reply\" title=\""+quoteTitle+"\" href=\""+link+"\">>>"+shortURL(board.Outbox, parsedLink)+isOP+" →</a>", -1) } } } diff --git a/database.go b/database.go index 0a99086..b0a5736 100644 --- a/database.go +++ b/database.go @@ -175,16 +175,16 @@ func WriteObjectToDB(db *sql.DB, obj ObjectBase) ObjectBase { if len(obj.Attachment) > 0 { if obj.Preview.Href != "" { obj.Preview.Id = fmt.Sprintf("%s/%s", obj.Actor, CreateUniqueID(db, obj.Actor)) - obj.Preview.Published = time.Now().UTC().Format(time.RFC3339) - obj.Preview.Updated = time.Now().UTC().Format(time.RFC3339) + obj.Preview.Published = time.Now().UTC() + obj.Preview.Updated = time.Now().UTC() obj.Preview.AttributedTo = obj.Id WritePreviewToDB(db, *obj.Preview) } for i, _ := range obj.Attachment { obj.Attachment[i].Id = fmt.Sprintf("%s/%s", obj.Actor, CreateUniqueID(db, obj.Actor)) - obj.Attachment[i].Published = time.Now().UTC().Format(time.RFC3339) - obj.Attachment[i].Updated = time.Now().UTC().Format(time.RFC3339) + obj.Attachment[i].Published = time.Now().UTC() + obj.Attachment[i].Updated = time.Now().UTC() obj.Attachment[i].AttributedTo = obj.Id WriteAttachmentToDB(db, obj.Attachment[i]) WriteActivitytoDBWithAttachment(db, obj, obj.Attachment[i], *obj.Preview) @@ -214,8 +214,6 @@ func SetActorFollowerDB(db *sql.DB, activity Activity) Activity { activity.Type = "Accept" return activity } - - return activity } func SetActorFollowingDB(db *sql.DB, activity Activity) Activity { @@ -13,12 +13,14 @@ import ( "html/template" "io" "io/ioutil" + "log" "math/rand" "mime/multipart" "net/http" "net/url" "os" "os/exec" + "path" "regexp" "strconv" "strings" @@ -29,6 +31,7 @@ var Port = ":" + GetConfigValue("instanceport", "3000") var TP = GetConfigValue("instancetp", "") var Instance = GetConfigValue("instance", "") var Domain = TP + "" + Instance +var TorInstance = IsOnion(Instance) var authReq = []string{"captcha", "email", "passphrase"} @@ -51,6 +54,8 @@ var MediaHashs = make(map[string]string) var ActorCache = make(map[string]Actor) +var Themes []string + func main() { CreatedNeededDirectories() @@ -84,6 +89,22 @@ func main() { } } + // get list of themes + themes, err := ioutil.ReadDir("./static/css/themes") + if err != nil { + panic(err) + } + + for _, f := range themes { + if f.Name() == "default" { + continue + } + + if e := path.Ext(f.Name()); e == ".css" { + Themes = append(Themes, strings.TrimSuffix(f.Name(), e)) + } + } + // Allow access to public media folder fileServer := http.FileServer(http.Dir("./public")) http.Handle("/public/", http.StripPrefix("/public", neuter(fileServer))) @@ -610,7 +631,13 @@ func main() { adminData.AutoSubscribe = GetActorAutoSubscribeDB(db, actor.Id) - t.ExecuteTemplate(w, "layout", adminData) + adminData.Themes = &Themes + + err := t.ExecuteTemplate(w, "layout", adminData) + if err != nil { + // TODO: actual error handling + log.Printf("mod page: %s\n", err) + } } else if admin || actor.Id == Domain { t := template.Must(template.New("").Funcs(template.FuncMap{ @@ -645,7 +672,13 @@ func main() { adminData.PostBlacklist = GetRegexBlacklistDB(db) - t.ExecuteTemplate(w, "layout", adminData) + adminData.Themes = &Themes + + err := t.ExecuteTemplate(w, "layout", adminData) + if err != nil { + // TODO: actual error handling + log.Printf("mod page: %s\n", err) + } } }) @@ -960,9 +993,6 @@ func main() { http.Redirect(w, r, "/"+board, http.StatusSeeOther) return } - - w.WriteHeader(http.StatusBadRequest) - w.Write([]byte("")) }) http.HandleFunc("/deleteattach", func(w http.ResponseWriter, r *http.Request) { @@ -1034,9 +1064,6 @@ func main() { http.Redirect(w, r, OP, http.StatusSeeOther) return } - - w.WriteHeader(http.StatusBadRequest) - w.Write([]byte("")) }) http.HandleFunc("/marksensitive", func(w http.ResponseWriter, r *http.Request) { @@ -1091,9 +1118,6 @@ func main() { http.Redirect(w, r, OP, http.StatusSeeOther) return } - - w.WriteHeader(http.StatusBadRequest) - w.Write([]byte("")) }) http.HandleFunc("/remove", func(w http.ResponseWriter, r *http.Request) { @@ -1148,9 +1172,6 @@ func main() { http.Redirect(w, r, "/"+board, http.StatusSeeOther) return } - - w.WriteHeader(http.StatusBadRequest) - w.Write([]byte("")) }) http.HandleFunc("/removeattach", func(w http.ResponseWriter, r *http.Request) { @@ -1195,9 +1216,6 @@ func main() { http.Redirect(w, r, OP, http.StatusSeeOther) return } - - w.WriteHeader(http.StatusBadRequest) - w.Write([]byte("")) }) http.HandleFunc("/report", func(w http.ResponseWriter, r *http.Request) { @@ -1621,8 +1639,8 @@ func CreateObject(objType string) ObjectBase { var nObj ObjectBase nObj.Type = objType - nObj.Published = time.Now().UTC().Format(time.RFC3339) - nObj.Updated = time.Now().UTC().Format(time.RFC3339) + nObj.Published = time.Now().UTC() + nObj.Updated = time.Now().UTC() return nObj } @@ -1761,7 +1779,7 @@ func CreateAttachmentObject(file multipart.File, header *multipart.FileHeader) ( image.Href = Domain + "/" + tempFile.Name() image.MediaType = contentType image.Size = size - image.Published = time.Now().UTC().Format(time.RFC3339) + image.Published = time.Now().UTC() nAttachment = append(nAttachment, image) @@ -1793,7 +1811,7 @@ func ParseCommentForReplies(db *sql.DB, comment string, op string) []ObjectBase if isValid { var reply = new(ObjectBase) reply.Id = links[i] - reply.Published = time.Now().UTC().Format(time.RFC3339) + reply.Published = time.Now().UTC() validLinks = append(validLinks, *reply) } } @@ -2378,7 +2396,7 @@ func ResizeAttachmentToPreview(db *sql.DB) { var mediatype string var name string var size int - var published string + var published time.Time rows.Scan(&id, &href, &mediatype, &name, &size, &published) diff --git a/static/archive.html b/static/archive.html index b08693a..3e040bc 100644 --- a/static/archive.html +++ b/static/archive.html @@ -20,7 +20,7 @@ {{ end }} {{ define "top" }} -<h1 style="text-align: center; color: #af0a0f;">/{{ .Board.Name }}/ - {{ .Board.PrefName }}</h1> +<h1>/{{ .Board.Name }}/ - {{ .Board.PrefName }}</h1> <p style="text-align: center;">{{ .Board.Summary }}</p> <h1 style="text-align: center;">Archived Posts</h1> {{ end }} diff --git a/static/bottom.html b/static/bottom.html index 9d920c0..023deeb 100644 --- a/static/bottom.html +++ b/static/bottom.html @@ -1,20 +1,20 @@ {{ define "bottom" }} <div id="reply-box" class="popup-box" style="display: none;"> - <div id="reply-header" style="display: inline-block; width: 370px; z-index: 0; cursor: move;"></div><div id="reply-close" style="display: inline-block; float: right;"><a href="javascript:closeReply()">[X]</a></div> + <div id="reply-header" style="display: inline-block; z-index: 0; cursor: move;"></div><div id="reply-close" style="display: inline-block; float: right;"><a href="javascript:closeReply()">[X]</a></div> <form onsubmit="sessionStorage.setItem('element-closed-reply', true)" id="reply-post" action="/post" method="post" enctype="multipart/form-data"> <input id="reply-name" name="name" size="43" type="text" placeholder="Name" maxlength="100"> <input id="reply-options" name="options" size="43" type="text" placeholder="Options" maxlength="100"> - <textarea id="reply-comment" name="comment" rows="12" cols="54" style="width: 396px;" maxlength="2000" oninput="sessionStorage.setItem('element-reply-comment', document.getElementById('reply-comment').value)"></textarea> + <textarea id="reply-comment" name="comment" rows="12" cols="54" maxlength="2000" oninput="sessionStorage.setItem('element-reply-comment', document.getElementById('reply-comment').value)"></textarea> <input id="reply-file" name="file" type="file"> - <input id="reply-submit" type="submit" value="Reply" style="float: right;"><br><br> + <input id="reply-submit" type="submit" value="Reply" style="float: right;"> <input type="hidden" id="inReplyTo-box" name="inReplyTo" value="{{ .Board.InReplyTo }}"> <input type="hidden" id="sendTo" name="sendTo" value="{{ .Board.To }}"> <input type="hidden" id="boardName" name="boardName" value="{{ .Board.Name }}"> <input type="hidden" id="captchaCode" name="captchaCode" value="{{ .Board.CaptchaCode }}"> - <input type="hidden" id="returnTo" name="returnTo" value="{{ .ReturnTo }}"> - <input type="checkbox" name="sensitive"><span>Mark attachment as sensitive</span><br><br> + <input type="hidden" id="returnTo" name="returnTo" value="{{ .ReturnTo }}"><br> + <input type="checkbox" name="sensitive"><span>Mark attachment as sensitive</span><br> <div style="width: 202px; margin: 0 auto; padding-top: 12px;"> - <label for="captcha">Captcha:</label><br> + <label for="captcha">Captcha:</label><br> <input style="display: inline-block;" type="text" id="captcha" name="captcha" autocomplete="off"><br> </div> <div style="width: 230px; margin: 0 auto;"> @@ -23,19 +23,20 @@ </form> </div> -<div id="report-box" class="popup-box" style="display: none; "> - <div id="report-header" style="text-align: center; display: inline-block; width: 370px; z-index: 0; cursor: move;"></div><div id="report-close" style="display: inline-block; float: right;"><a href="javascript:closeReport()">[X]</a></div> +<div id="report-box" class="popup-box" style="display: none;"> + <div id="report-header" style="text-align: center; display: inline-block; z-index: 0; cursor: move;"></div><div id="report-close" style="display: inline-block; float: right;"><a href="javascript:closeReport()">[X]</a></div> <form onsubmit="sessionStorage.setItem('element-closed-report', true)" id="report-post" action="/report" method="post"> - <label for="comment">Reason:</label> + <label for="comment">Reason:</label><br> <textarea id="report-comment" name="comment" rows="12" cols="54" style="width: 396px;" maxlength="100" oninput="sessionStorage.setItem('element-report-comment', document.getElementById('report-comment').value)"></textarea> + <br> <input id="report-submit" type="submit" value="Report" style="float: right;"> <input type="hidden" id="report-inReplyTo-box" name="id" value="{{ .Board.InReplyTo }}"> <input type="hidden" id="sendTo" name="sendTo" value="{{ .Board.To }}"> <input type="hidden" id="boardName" name="board" value="{{ .Board.Name }}"> - <input type="hidden" name="close" value="0"> + <input type="hidden" name="close" value="0"> <input type="hidden" id="captchaCode" name="captchaCode" value="{{ .Board.CaptchaCode }}"> <div style="width: 202px; margin: 0 auto; padding-top: 12px;"> - <label for="captcha">Captcha:</label><br> + <label for="captcha">Captcha:</label><br> <input style="display: inline-block;" type="text" id="captcha" name="captcha" autocomplete="off"><br> </div> <div style="width: 230px; margin: 0 auto;"> diff --git a/static/css/themes/default.css b/static/css/themes/default.css new file mode 100644 index 0000000..24e85e6 --- /dev/null +++ b/static/css/themes/default.css @@ -0,0 +1,162 @@ +a, a:link, a:visited, a:hover, a:active { + text-decoration: none +} + +a:link, a:visited, a:active { + color: black; +} + +a:hover { + color: #de0808; +} + +body { + background-color: #eef2fe; + color: black; +} + +body.nsfw { + background-color: #ffffee; + color: #820404 +} + +h1, h2, h3, h4, h5, h6 { + color: #af0a0f; +} + +.popup-box { + border: 4px solid #d3caf0; + background-color: #eff5ff; +} + +.nsfw .popup-box { + border: 4px solid #f0e2d9; + background-color: #f9f9e0; +} + +.box { + background-color: #eff5ff; +} + +.nsfw .box { + background-color: #f9f9e0; +} + +.box-alt { + background-color: #d3caf0; +} + +.nsfw .box-alt { + background-color: #f0e2d9; +} + + +.quote { + color: #789922; +} + +.post { + background-color: #d5daf0; +} + +.nsfw .post { + background-color: #f0e0d6; +} + +:target > div > .post { + background-color: #d6bad0; +} + +.nsfw :target > div > .post { + background-color: #f0c0b0; +} + +.title { + color: #0f0c5d; +} + +.name, .tripcode { + color: #117743; +} + +a.reply { + color: #af0a0f; +} + +.replyLink { + color: #000080; + font-size: 0.8em; +} + +#newpostbtn { + text-align: center; + margin-top: 80px; +} + +#postForm { + margin: auto; +} + +#postForm tr > td:first-child { + background-color: #98e; + border: 1px black; + padding-left: 0.5em; + padding-right: 0.5em; +} + +.nsfw #postForm tr > td:first-child { + background-color: #ea8; +} + +#postForm input[type="text"], +#postForm textarea, +#reply-name, #reply-options, #reply-comment { + box-sizing: border-box; + -webkit-box-sizing:border-box; + -moz-box-sizing: border-box; +} + +#reply-name, #reply-options, #reply-comment { + width: 100%; +} + +#postForm #captcha { + display: block; + width: 100%; +} + +.popup-box { + position: absolute; + width: min-content; + z-index: 9; + display: block; +} + +/* TODO: rename */ +.box2 { + border: 4px solid #f0e2d9; + background-color: #f9f9e0; +} + +.newsbox { + padding: 25px; + border: 4px solid #f0e2d9; + background-color: #f9f9e0; +} + +.newsbox h2 { + margin: 0; + padding: 0; +} + +.newsbox-news { + text-align: left; + margin-left: 25px; + margin-top: 25px; + padding: 25px; +} + +.newsbox-news p, +.newsbox-news h3 { + margin: 0; +} diff --git a/static/css/themes/gruvbox.css b/static/css/themes/gruvbox.css new file mode 100644 index 0000000..fb40267 --- /dev/null +++ b/static/css/themes/gruvbox.css @@ -0,0 +1,140 @@ +a, a:link, a:visited, a:active { + color: #b16286; + text-decoration: none +} + +a.reply { + color: #cc241d; +} + +a:hover.reply { + color: #fb4934; +} + +body { + background: #282828; + color: #ebdbb2; + + font-family: monospace, sans-serif; + font-size: 0.9em; +} + +.popup-box { + border: 4px solid #928374; + background-color: #3c3836; +} + +.box, .box-alt { + background-color: #3c3836; +} + +.quote { + color: #98971a; +} + +.post { + background-color: #1d2021; +} + +:target > div > .post { + background-color: #504945; +} + +.subject { + color: #458588; +} + +.name { + color: #b8bb26; +} + +.tripcode { + color: #689d6a; +} + +h1,h2,h3,h4,h5,h6 { + color: #fb4934; + margin-bottom: 0.1em; +} + +.replyLink { + color: #83a598; + font-size: 0.8em; +} + +#newpostbtn { + text-align: center; + margin-top: 80px; +} + +input[type="text"] { + -webkit-appearance: none; + -webkit-border-radius: 0; +} + +#postForm { + border: 4px solid #928374; + background-color: #3c3836; + margin: auto; + +} + +#postForm tr > td:first-child { + background-color: #504945; + padding-left: 0.5em; + padding-right: 0.5em; +} + +#postForm input[type="text"], +#postForm textarea, +#reply-name, #reply-options, #reply-comment { + box-sizing: border-box; + -webkit-box-sizing:border-box; + -moz-box-sizing: border-box; +} + +#reply-name, #reply-options, #reply-comment { + width: 100%; +} + +#postForm #captcha { + display: block; + width: 100%; +} + +.popup-box { + position: absolute; + width: min-content; + z-index: 9; + display: block; +} + +/* TODO: rename */ +.box2 { + border: 4px solid #928374; + background-color: #3c3836; +} + +.newsbox { + padding: 25px; + border: 4px solid #928374; + background-color: #3c3836; +} + +.newsbox h2 { + margin: 0; + padding: 0; +} + +.newsbox-news { + text-align: left; + background-color: #504945; + margin-left: 25px; + margin-top: 25px; + padding: 25px; +} + +.newsbox-news p, +.newsbox-news h3 { + margin: 0; +} diff --git a/static/index.html b/static/index.html index b706e6b..8f1d53b 100644 --- a/static/index.html +++ b/static/index.html @@ -1,6 +1,6 @@ {{ define "header" }} <title>{{ .Title }}</title> -<meta name="description" content="{{ .PreferredUsername }} is a federated image board based on ActivityPub. The current version of the code running on the server is still a work-in-progress product, expect a bumpy ride for the time being. Get the server code here: https://github.com/FChannel0."> +<meta name="description" content="{{ .PreferredUsername }} is a federated image board based on ActivityPub. The current version of the code running on the server is still a work-in-progress product, expect a bumpy ride for the time being. Get the server code here: https://github.com/FChannel0."> <meta property="og:locale" content="en_US" /> <meta property="og:type" content="website" /> @@ -23,47 +23,45 @@ <p style="text-align: justify">{{ .PreferredUsername }} is a federated image board based on <a href="https://activitypub.rocks/">ActivityPub</a>. The current version of the code running on the server is still a work-in-progress product, expect a bumpy ride for the time being. Get the server code here: <a href="https://github.com/FChannel0">https://github.com/FChannel0</a>.</p> {{ if .Boards }} - {{ $l := len .Boards }} + {{ $l := len .Boards }} <div style="margin-top:50px;"> - <div style="display: grid;border-right: 2px solid #820404"> + <div style="display: grid;border-right: 2px solid #820404;"> {{ if lt $l 2 }} <div style="display: inline-grid; border-bottom: 2px solid #820404;border-left: 2px solid #820404;border-top: 2px solid #820404;"><span style="font-size: 1.5em;font-weight: bold;">Local boards</span></div> {{ else if eq $l 2 }} <div style="display: inline-grid; grid-column: 1 / 3; border-bottom: 2px solid #820404;border-left: 2px solid #820404;border-top: 2px solid #820404;"><span style="font-size: 1.5em;font-weight: bold;">Local boards</span></div> {{ else }} <div style="display: inline-grid;grid-column: 1 / 4;border-bottom: 2px solid #820404;border-left: 2px solid #820404;border-top: 2px solid #820404;"><span style="font-size: 1.5em;font-weight: bold;">Local boards</span></div> - {{ end }} + {{ end }} {{ range .Boards }} <div style="whitespace: nowrap;display: inline-grid;text-align: left;padding: 5px;border-bottom: 2px solid #820404;border-left: 2px solid #820404;"><a href="{{.Location}}"><b>/{{.Name}}/</b> - {{.PrefName}} {{ if not .Restricted }} [NSFW] {{ end }}</a></div> {{ end }} - {{ if gt $l 2 }} + {{ if gt $l 2 }} {{ range .BoardRemainer }} <div style="whitespace: nowrap;display: inline-grid;text-align: left;padding: 5px;border-bottom: 2px solid #820404;border-left: 2px solid #820404;"></div> {{ end }} {{ end }} - </div> + </div> </div> {{ end }} - - {{ if .NewsItems }} - <div class="popup-box" style="margin-top:50px;"> - <table style="text-align: left; margin: 25px;"> - <th> - <tr><h4><a href="/news">{{ .PreferredUsername }} News</a></h4></tr> - </th> + + {{ if .NewsItems }} + <div class="newsbox" style="margin-top:50px;"> + <h2><a href="/news">{{ .PreferredUsername }} News</a></h2> {{ range $i, $e := .NewsItems }} - <tr> - <td>{{ if $.Board.ModCred }}<a href="/{{ $.Key }}/newsdelete/{{ $e.Time }}">[Delete] </a>{{end}} - <a href="/news/{{.Time}}">{{unixtoreadable $e.Time}} - {{$e.Title}}</a> - <br><p style="margin-left: 25px;">{{$e.Content}}</p> + <div class="newsbox-news"> + <h3><a href="/news/{{.Time}}">{{unixtoreadable $e.Time}} - {{$e.Title}}</a>{{ if $.Board.ModCred }} <a href="/{{ $.Key }}/newsdelete/{{ $e.Time }}">[Delete] </a>{{end}}</h3> + <br> + + <p>{{$e.Content}}</p> </td> - </tr> + </div> {{ end }} </table> </div> - {{ end }} - - <div class="popup-box" style="margin-top:50px;"> + {{ end }} + + <div class="box2" style="margin-top:50px;"> <h4 style="margin-bottom:5px;">Current known instances</h4> <span>(always use a proxy)</span> <table style="text-align: left; margin: 25px;"> diff --git a/static/js/posts.js b/static/js/posts.js index 455e7ea..30f4893 100644 --- a/static/js/posts.js +++ b/static/js/posts.js @@ -2,29 +2,16 @@ function startNewPost(){ var el = document.getElementById("newpostbtn"); el.style="display:none;"; el.setAttribute("state", "1"); - document.getElementById("newpost").style = "display: block;"; + document.getElementById("newpost").style = ""; + sessionStorage.setItem("newpostState", true); } function stopNewPost(){ var el = document.getElementById("newpostbtn"); el.style="display:block;"; el.setAttribute("state", "0"); - document.getElementById("newpost").style = "display: hidden;"; -} - -function newpost() -{ - var state = document.getElementById("newpostbtn").getAttribute("state"); - if(state === "0") - { - startNewPost(); - sessionStorage.setItem("newpostState", true); - } - else - { - stopNewPost(); - sessionStorage.setItem("newpostState", false); - } + document.getElementById("newpost").style = "display: none;"; + sessionStorage.setItem("newpostState", false); } function shortURL(actorName, url) @@ -182,7 +169,7 @@ function quote(actorName, opid, id) var h = document.getElementById(id + "-content").offsetTop - 348; } - const boxStyle = "display: block; position: absolute; width: 400px; height: 600px; z-index: 9; top: " + h + "px; left: " + w + "px; padding: 5px;"; + const boxStyle = "top: " + h + "px; left: " + w + "px;"; box.setAttribute("style", boxStyle); sessionStorage.setItem("element-reply-style", boxStyle); sessionStorage.setItem("reply-top", h); @@ -202,7 +189,6 @@ function quote(actorName, opid, id) sessionStorage.setItem("element-reply-comment", comment.value); dragElement(header); - } function report(actorName, id) @@ -216,7 +202,7 @@ function report(actorName, id) var w = window.innerWidth / 2 - 200; var h = document.getElementById(id + "-content").offsetTop - 348; - const boxStyle = "display: block; position: absolute; width: 400px; height: 480px; z-index: 9; top: " + h + "px; left: " + w + "px; padding: 5px;"; + const boxStyle = "top: " + h + "px; left: " + w + "px;"; box.setAttribute("style", boxStyle); sessionStorage.setItem("element-report-style", boxStyle); sessionStorage.setItem("report-top", h); diff --git a/static/js/themes.js b/static/js/themes.js new file mode 100644 index 0000000..3f1b906 --- /dev/null +++ b/static/js/themes.js @@ -0,0 +1,40 @@ +function setCookie(key, value, age) { + document.cookie = key + "=" + encodeURIComponent(value) + ";sameSite=strict;max-age=" + 60 * 60 * 24 * age + ";path=/"; +} + +function getCookie(key) { + if (document.cookie.length != 0) { + return document.cookie.split('; ').find(row => row.startsWith(key)).split('=')[1]; + } + return ""; +} + +function setTheme(name) { + for (let i = 0, tags = document.getElementsByTagName("link"); i < tags.length; i++) { + if (tags[i].type === "text/css" && tags[i].title) { + tags[i].disabled = !(tags[i].title === name); + } + } + + setCookie("theme", name, 3650); +} + +function applyTheme() { + // HACK: disable all of the themes first. this for some reason makes things work. + for (let i = 0, tags = document.getElementsByTagName("link"); i < tags.length; i++) { + if (tags[i].type === "text/css" && tags[i].title) { + tags[i].disabled = true; + } + } + let theme = getCookie("theme") || "default"; + setTheme(theme); + + // reflect this in the switcher + let switcher = document.getElementById("themeSwitcher"); + for(var i = 0; i < switcher.options.length; i++) { + if (switcher.options[i].value === theme) { + switcher.selectedIndex = i; + break; + } + } +} diff --git a/static/main.html b/static/main.html index 362b7b3..794a602 100644 --- a/static/main.html +++ b/static/main.html @@ -8,81 +8,13 @@ <meta property="og:locale" content="en_US" /> <meta property="og:type" content="website" /> <link rel="icon" type="image/png" href="/static/favicon.png"> - <style> - a, a:link, a:visited, a:hover, a:active { - text-decoration: none - } - - a:link, a:visited, a:active { - color: black; - } - - a:hover { - color: #de0808; - } - - body { - {{ if .Board.Restricted }} - background-color: #eef2fe; - color: black; - {{ else }} - background-color: #ffffee; - color: #820404 - {{ end }} - } - - .popup-box { - {{ if .Board.Restricted }} - border: 4px solid #d3caf0; - background-color: #eff5ff; - {{ else }} - border: 4px solid #f0e2d9; - background-color: #f9f9e0; - {{ end }} - } - - .box { - {{ if .Board.Restricted }} - background-color: #eff5ff; - {{ else }} - background-color: #f9f9e0; - {{ end }} - } - - .box-alt { - {{ if .Board.Restricted }} - background-color: #d3caf0; - {{ else }} - background-color: #f0e2d9; - {{ end }} - } - - .quote { - color: #789922; - } - - .post { - {{ if .Board.Restricted }} - background-color: #d5daf0; - {{ else }} - background-color: #f0e0d6; - {{ end }} - } - - :target > div > .post { - {{ if .Board.Restricted }} - background-color: #d6bad0; - {{ else }} - background-color: #f0c0b0; - {{ end }} - } - .tripcode { - color: #117743; - } - </style> + <link rel="stylesheet" type="text/css" href="/static/css/themes/default.css" title="default"> + {{ range .Themes }} + <link rel="alternate stylesheet" type="text/css" href="/static/css/themes/{{.}}.css" title="{{.}}"> + {{ end }} {{ template "header" . }} </head> - <body> + <body {{ if not .Board.Restricted }}class="nsfw"{{ end }} onload="applyTheme()"> <ul style="display: inline; padding:0;"> {{ $l := len .Boards }} <li style="display: inline;">[<a href="/">Home</a>]</li> @@ -108,12 +40,24 @@ {{ template "content" . }} {{ template "bottom" . }} + + <div style="float: right;"> + Theme: + <select id="themeSwitcher" onchange="setTheme(this.options[this.selectedIndex].value)"> + {{ range .Themes }} + <option value="{{.}}">{{.}}</option> + {{ end }} + </select> + </div> + <div align="center" style="width: 500px; margin:0 auto; margin-top: 50px;"> <a href="/">[Home]</a><a href="/static/rules.html">[Rules]</a><a href="/static/faq.html">[FAQ]</a> <p>All trademarks and copyrights on this page are owned by their respective parties.</p> </div> + + <script src="/static/js/themes.js"></script> +{{ template "script" . }} </body> </html> -{{ template "script" . }} {{ end }} diff --git a/static/manage.html b/static/manage.html index 3bd621b..dc25468 100644 --- a/static/manage.html +++ b/static/manage.html @@ -20,7 +20,7 @@ {{ $board := .Board }} {{ $key := .Key }} {{ if .IsLocal }} -<div id="following" class="popup-box" style="margin-bottom: 25px; margin-top: 5px; padding: 12px;"> +<div id="following" class="box2" style="margin-bottom: 25px; margin-top: 5px; padding: 12px;"> <h4 style="margin: 0; margin-bottom: 5px;">Following</h4> {{ if .AutoSubscribe }}<a title="Auto Follow is On" href="/autosubscribe?board={{ .Board.Name }}">[Toggle Auto Follow Off]{{ else }}<a title="Auto Follow is Off" href="/autosubscribe?board={{ .Board.Name }}">[Toggle Auto Follow On]{{ end }}</a> <form id="follow-form" action="/{{ .Key }}/{{ .Board.Name }}/follow" method="post" enctype="application/x-www-form-urlencoded" style="margin-top: 5px;"> @@ -36,7 +36,7 @@ </ul> </div> -<div id="followers" class="popup-box" style="margin-bottom: 25px; padding: 12px;"> +<div id="followers" class="box2" style="margin-bottom: 25px; padding: 12px;"> <h4 style="margin: 0; margin-bottom: 5px;">Followers</h4> <ul style="display: inline-block; padding: 0; margin: 0; list-style-type: none;"> {{ range .Followers }} @@ -46,7 +46,7 @@ </div> {{ end }} -<div id="reported" class="popup-box" style="margin-bottom: 25px; padding: 12px;"> +<div id="reported" class="box2" style="margin-bottom: 25px; padding: 12px;"> <h4 style="margin: 0; margin-bottom: 5px;">Reported</h4> <ul style="display: inline-block; padding: 0; margin: 0; list-style-type: none;"> {{ $domain := .Domain }} diff --git a/static/nadmin.html b/static/nadmin.html index 5e38151..e8fbc36 100644 --- a/static/nadmin.html +++ b/static/nadmin.html @@ -26,7 +26,7 @@ </div> -<div id="following" class="popup-box" style="margin-bottom: 25px; padding: 12px;"> +<div id="following" class="box2" style="margin-bottom: 25px; padding: 12px;"> <h4 style="margin: 0; margin-bottom: 5px;">Subscribed</h4> <form id="follow-form" action="/{{ .Key }}/follow" method="post" enctype="application/x-www-form-urlencoded"> <input id="follow" name="follow" style="margin-bottom: 12px;" placeholder="http://localhost:3000/g"></input><input type="submit" value="Subscribe"><br> @@ -41,7 +41,7 @@ </ul> </div> -<div id="followers" class="popup-box" style="margin-bottom: 25px; padding: 12px; display:none;"> +<div id="followers" class="box2" style="margin-bottom: 25px; padding: 12px; display:none;"> <h4 style="margin: 0; margin-bottom: 5px;">Followers</h4> <ul style="display: inline-block; padding: 0; margin: 0; list-style-type: none;"> {{ range .Followers }} @@ -50,7 +50,7 @@ </ul> </div> -<div class="popup-box" style="margin-bottom: 25px; padding: 12px;"> +<div class="box2" style="margin-bottom: 25px; padding: 12px;"> <h3>Create News</h3> <form id="news" action="/{{ .Key }}/postnews" method="post" enctype="application/x-www-form-urlencoded"> <label>Title:</label><br> @@ -60,7 +60,7 @@ </form> </div> -<div id="regex" class="popup-box" style="margin-bottom: 25px; padding: 12px;"> +<div id="regex" class="box2" style="margin-bottom: 25px; padding: 12px;"> <h3>Regex Post Blacklist</h3> <form id="blacklist" action="/blacklist" method="post" enctype="application/x-www-form-urlencoded"> <label>Regex:</label><br> diff --git a/static/ncatalog.html b/static/ncatalog.html index e35edd0..ec8afd5 100644 --- a/static/ncatalog.html +++ b/static/ncatalog.html @@ -17,14 +17,16 @@ {{ define "content" }} {{ $board := .Board }} <hr> -<ul style="margin: 0; padding: 0; display: inline"> - <li style="display: inline"><a href="/{{ $board.Name }}">[Return]</a></li> + +<div class="navlinks"> + [<a href="/{{ $board.Name }}/">Return</a>] {{ if showArchive }} - <li style="display: inline"><a href="/{{ $board.Name }}/archive">[Archive]</a></li> + [<a href="/{{ $board.Name }}/archive">Archive</a>] {{ end }} - <li style="display: inline"><a href="#bottom">[Bottom]</a></li> - <li style="display: inline"><a href="javascript:location.reload()">[Refresh]</a></li> -</ul> + [<a href="#bottom">Bottom</a>] + [<a href="javascript:location.reload()">Refresh</a>] +</div> + <hr> <div style="padding: 10px; text-align: center;"> @@ -39,7 +41,12 @@ <a href="/marksensitive?id={{ .Id }}&board={{ $board.Actor.Name }}">[Mark Sensitive]</a> {{ end }} <div id="hide-{{ .Id }}" style="display: none;">[Hide]</div> - <div id="sensitive-{{ .Id }}" style="display: none;"><div style="position: relative; text-align: center;"><img id="sensitive-img-{{ .Id }}" style="float: left; margin-right: 10px; margin-bottom: 10px; max-width: 180px; max-height: 180px;" src="/static/sensitive.png"><div id="sensitive-text-{{ .Id }}" style="width: 170px; position: absolute; margin-top: 75px; padding: 5px; background-color: black; color: white; cursor: default; ">NSFW Content</div></div></div> + <div id="sensitive-{{ .Id }}" style="display: none;"> + <div style="position: relative; text-align: center;"> + <img id="sensitive-img-{{ .Id }}" style="float: left; margin-right: 10px; margin-bottom: 10px; max-width: 180px; max-height: 180px;" src="/static/sensitive.png"> + <div id="sensitive-text-{{ .Id }}" style="width: 170px; position: absolute; margin-top: 75px; padding: 5px; background-color: black; color: white; cursor: default; ">NSFW Content</div> + </div> + </div> <a id="{{ .Id }}-anchor" href="/{{ $board.Name }}/{{ short $board.Actor.Outbox .Id}}"> <div id="media-{{ .Id }}" style="width:180px;"> {{ parseAttachment . true }}</div> </a> @@ -67,33 +74,37 @@ } </script> {{ end }} - <a id="{{ .Id }}-link" href="/{{ $board.Name }}/{{ short $board.Actor.Outbox .Id }}"> - <div> - {{ $replies := .Replies }} - {{ if $replies }} - <span style="display: block;">R: {{ $replies.TotalItems }}{{ if $replies.TotalImgs }}/ A: {{ $replies.TotalImgs }}{{ end }}</span> - {{ end }} - {{ if .Name }} - <span style="display: block; color: #0f0c5d;"><b>{{ .Name }}</b></span> - {{ end }} + <a style="color: unset;" id="{{ .Id }}-link" href="/{{ $board.Name }}/{{ short $board.Actor.Outbox .Id }}"> + <div style="display: block;"> + {{ $replies := .Replies }} + {{ if $replies }} + <span>R: {{ $replies.TotalItems }}{{ if $replies.TotalImgs }}/ A: {{ $replies.TotalImgs }}{{ end }}</span> + {{ end }} + {{ if .Name }} + <br> + <span class="subject"><b>{{ .Name }}</b></span> + {{ end }} - {{ if .Content }} - <span style="display: block">{{.Content}}</span> - {{ end }} - </div> + {{ if .Content }} + <br> + <span>{{.Content}}</span> + {{ end }} + </div> </a> </div> {{ end }} </div> <hr> -<ul style="margin: 0; padding: 0; display: inline"> - <li style="display: inline"><a href="/{{ $board.Name }}">[Return]</a></li> + +<div class="navlinks"> + [<a href="/{{ $board.Name }}/">Return</a>] {{ if showArchive }} - <li style="display: inline"><a href="/{{ $board.Name }}/archive">[Archive]</a></li> + [<a href="/{{ $board.Name }}/archive">Archive</a>] {{ end }} - <li style="display: inline"><a id="bottom" href="#top">[Top]</a></li> - <li style="display: inline"><a href="javascript:location.reload()">[Refresh]</a></li> -</ul> + [<a href="#top">Top</a>] + [<a href="javascript:location.reload()">Refresh</a>] +</div> + <hr> {{ end }} {{ define "bottom" }} diff --git a/static/nposts.html b/static/nposts.html index 6def8b2..46d8bb1 100644 --- a/static/nposts.html +++ b/static/nposts.html @@ -15,33 +15,35 @@ {{ define "content" }} {{ $board := .Board }} <hr> -<ul style="margin: 0; padding: 0; display: inline"> - <li style="display: inline"><a href="/{{ $board.Name }}/catalog">[Catalog]</a></li> +<div class="navlinks"> + [<a href="/{{ $board.Name }}/catalog">Catalog</a>] {{ if showArchive }} - <li style="display: inline"><a href="/{{ $board.Name }}/archive">[Archive]</a></li> + [<a href="/{{ $board.Name }}/archive">Archive</a>] {{ end }} - <li style="display: inline"><a href="#bottom">[Bottom]</a></li> - <li style="display: inline"><a href="javascript:location.reload()">[Refresh]</a></li> -</ul> + [<a href="#bottom">Bottom</a>] + [<a href="javascript:location.reload()">Refresh</a>] +</div> {{ template "posts" . }} <hr> -<ul style="margin: 0; padding: 0; display: inline"> - <li style="display: inline"><a href="/{{ $board.Name }}/catalog">[Catalog]</a></li> + +<div class="navlinks"> + [<a href="/{{ $board.Name }}/catalog">Catalog</a>] {{ if showArchive }} - <li style="display: inline"><a href="/{{ $board.Name }}/archive">[Archive]</a></li> + [<a href="/{{ $board.Name }}/archive">Archive</a>] {{ end }} - <li style="display: inline"><a id="bottom" href="#top">[Top]</a></li> - <li style="display: inline"><a href="javascript:location.reload()">[Refresh]</a></li> -</ul> + [<a href="#top" id="bottom">Top</a>] + [<a href="javascript:location.reload()">Refresh</a>] +</div> + <hr> {{ if gt .TotalPage 0 }} {{ $totalPage := .TotalPage }} <ul style="float: right; margin: 0; padding: 0; display: inline"> {{ $page := .CurrentPage }} {{ if gt $page 0 }} - <li style="display: inline"><a href="/{{ $board.Name }}?page={{ sub $page 1 }}">[ < ]</a></li> + <li style="display: inline"><a href="/{{ $board.Name }}?page={{ sub $page 1 }}">[ < ]</a></li> {{ end }} {{ range $i, $e := .Pages }} {{ if eq $i $page}} @@ -51,7 +53,7 @@ {{ end }} {{ end }} {{ if lt .CurrentPage .TotalPage }} - <li style="display: inline"><a href="/{{ $board.Name }}?page={{ add $page 1 }}">[ > ]</a></li> + <li style="display: inline"><a href="/{{ $board.Name }}?page={{ add $page 1 }}">[ > ]</a></li> {{ end }} </ul> {{ end }} diff --git a/static/posts.html b/static/posts.html index 50d8b43..7110dd9 100644 --- a/static/posts.html +++ b/static/posts.html @@ -45,7 +45,10 @@ } </script> {{ end }} - <span style="color: #0f0c5d;"><b>{{ .Name }}</b></span><span style="color: #117743;"><b>{{ if .AttributedTo }} {{.AttributedTo }} {{ else }} Anonymous {{ end }}</b></span><span class="tripcode"> {{ .TripCode }} </span><span>{{ .Published }} <a id="{{ .Id }}-anchor" href="/{{ $board.Name }}/{{ short $board.Actor.Outbox $opId }}#{{ short $board.Actor.Outbox .Id }}">No.</a> <a id="{{ .Id }}-link" title="{{ .Id }}" {{ if eq .Type "Note" }} href="javascript:quote('{{ $board.Actor.Id }}', '{{ $opId }}', '{{ .Id }}')" {{ end }}>{{ short $board.Actor.Outbox .Id }}</a> {{ if ne .Type "Tombstone" }}<a href="javascript:report('{{ $board.Actor.Id }}', '{{ .Id }}')">[Report]</a>{{ end }}</span> + <span class="subject"><b>{{ .Name }}</b></span> + <span class="name"><b>{{ if .AttributedTo }} {{.AttributedTo }} {{ else }} Anonymous {{ end }}</b></span> + <span class="tripcode"> {{ .TripCode }} </span> + <span class="timestamp" data-utc="{{.Published | timeToUnix}}">{{ .Published | timeToReadableLong }} <a id="{{ .Id }}-anchor" href="/{{ $board.Name }}/{{ short $board.Actor.Outbox $opId }}#{{ short $board.Actor.Outbox .Id }}">No.</a> <a id="{{ .Id }}-link" title="{{ .Id }}" {{ if eq .Type "Note" }} href="javascript:quote('{{ $board.Actor.Id }}', '{{ $opId }}', '{{ .Id }}')" {{ end }}>{{ short $board.Actor.Outbox .Id }}</a> {{ if ne .Type "Tombstone" }}<a href="javascript:report('{{ $board.Actor.Id }}', '{{ .Id }}')">[Report]</a>{{ end }}</span> <p id="{{ .Id }}-content" style="white-space: pre-wrap; margin: 10px 30px 10px 30px;">{{ parseContent $board.Actor $opId .Content $thread }}</p> {{ if .Replies }} {{ $replies := .Replies }} @@ -57,7 +60,7 @@ {{ range $replies.OrderedItems }} <div id="{{ short $board.Actor.Outbox .Id }}"> <div style="display: inline-block; overflow: auto;"> - <div style="float: left; display: block; margin-right: 5px;">>></div> + <div style="float: left; display: block; margin-right: 5px;">>></div> <div class="post" style="overflow: auto; padding: 5px; margin-bottom: 2px;"> {{ if eq $board.ModCred $board.Domain $board.Actor.Id }} <a href="/delete?id={{ .Id }}&board={{ $board.Actor.Name }}">[Delete Post]</a> @@ -97,7 +100,10 @@ } </script> {{ end }} - <span style="color: #0f0c5d;"><b>{{ .Name }}</b></span><span style="color: #117743;"><b>{{ if .AttributedTo }} {{.AttributedTo }} {{ else }} Anonymous {{ end }}</b></span><span class="tripcode"> {{ .TripCode }} </span><span>{{ .Published }} <a id="{{ .Id }}-anchor" href="/{{ $board.Name }}/{{ short $board.Actor.Outbox $opId }}#{{ short $board.Actor.Outbox .Id }}">No. </a><a id="{{ .Id }}-link" title="{{ .Id }}" {{ if eq .Type "Note" }} href="javascript:quote('{{ $board.Actor.Id }}', '{{ $opId }}', '{{ .Id }}')" {{ end }}>{{ short $board.Actor.Outbox .Id }}</a> {{ if ne .Type "Tombstone" }}<a href="javascript:report('{{ $board.Actor.Id }}', '{{ .Id }}')">[Report]</a>{{ end }}</span> + <span class="subject"><b>{{ .Name }}</b></span> + <span class="name"><b>{{ if .AttributedTo }} {{.AttributedTo }} {{ else }} Anonymous {{ end }}</b></span> + <span class="tripcode"> {{ .TripCode }} </span> + <span class="timestamp" data-utc="{{ .Published | timeToUnix }}">{{ .Published | timeToReadableLong }} <a id="{{ .Id }}-anchor" href="/{{ $board.Name }}/{{ short $board.Actor.Outbox $opId }}#{{ short $board.Actor.Outbox .Id }}">No. </a><a id="{{ .Id }}-link" title="{{ .Id }}" {{ if eq .Type "Note" }} href="javascript:quote('{{ $board.Actor.Id }}', '{{ $opId }}', '{{ .Id }}')" {{ end }}>{{ short $board.Actor.Outbox .Id }}</a> {{ if ne .Type "Tombstone" }}<a href="javascript:report('{{ $board.Actor.Id }}', '{{ .Id }}')">[Report]</a>{{ end }}</span> {{ $parentId := .Id }} {{ if .Replies.OrderedItems }} {{ range .Replies.OrderedItems }} diff --git a/static/top.html b/static/top.html index 0081fc7..94abad7 100644 --- a/static/top.html +++ b/static/top.html @@ -1,39 +1,59 @@ {{ define "top" }} <div style="margin: 0 auto; width: 700px; margin-bottom: 100px;"> - <h1 style="text-align: center; color: #af0a0f;">/{{ .Board.Name }}/ - {{ .Board.PrefName }}</h1> + <h1 style="text-align: center;">/{{ .Board.Name }}/ - {{ .Board.PrefName }}</h1> <p style="text-align: center;">{{ .Board.Summary }}</p> {{ $len := len .Posts }} {{ if eq $len 0 }} {{ if .Board.InReplyTo }} - <h3 id="newpostbtn" state="0" style="text-align: center; margin-top: 80px; display: none;"><a href="javascript:newpost()">[Post a Reply]</a></h3> + <h3 id="newpostbtn" state="0" style="display: none;"><a href="javascript:startNewPost()">[Post a Reply]</a></h3> {{ else }} - <h3 id="newpostbtn" state="0" style="text-align: center; margin-top: 80px; display: none;"><a href="javascript:newpost()">[Start a New Thread]</a></h3> + <h3 id="newpostbtn" state="0" style="display: none;"><a href="javascript:startNewPost()">[Start a New Thread]</a></h3> {{ end }} <!-- end if inreplyto--> <div id="newpost"> - <form onsubmit="sessionStorage.setItem('element-closed-reply', true)" id="new-post" action="/post" method="post" enctype="multipart/form-data" style="margin-left: 180px;"> - <label for="name">Name:</label><br> - <input type="text" id="name" name="name" placeholder="Anonymous" maxlength="100"><br> - <label for="options">Options:</label><br> - <input type="text" id="options" name="options" maxlength="100" style="margin-right:10px">{{ if .Board.InReplyTo }}<input type="submit" value="Post">{{ end }}<br> - {{ if eq .Board.InReplyTo "" }} - <label for="subject">Subject:</label><br> - <input type="text" id="subject" name="subject" maxlength="100" style="margin-right:10px"><input type="submit" value="Post"><br> - {{ end }} - <label for="comment">Comment:</label><br> - <textarea rows="10" cols="50" id="comment" name="comment" maxlength="2000"></textarea><br> + <form onsubmit="sessionStorage.setItem('element-closed-reply', true)" id="new-post" action="/post" method="post" enctype="multipart/form-data"> + <table id="postForm"> + <tr> + <tr> + <td><label for="name">Name:</label></td> + <td><input type="text" id="name" name="name" placeholder="Anonymous" maxlength="100"> + <a onclick="stopNewPost()" style="float: right;">[X]</a> + </td> + </tr> + <tr> + <td><label for="options">Options:</label></td> + <td><input type="text" id="options" name="options" maxlength="100" style="margin-right:10px">{{ if .Board.InReplyTo }}<input type="submit" value="Post">{{ end }}</td> + </tr> + {{ if eq .Board.InReplyTo "" }} + <tr> + <td><label for="subject">Subject:</label></td> + <td><input type="text" id="subject" name="subject" maxlength="100" style="margin-right:10px"><input type="submit" value="Post"></td> + </tr> + {{ end }} + <tr> + <td><label for="comment">Comment:</label></td> + <td><textarea rows="10" cols="50" id="comment" name="comment" maxlength="2000"></textarea></td> + </tr> + <tr> + <td><label for="file">Image</label></td> + <td><input type="file" id="file" name="file" {{ if gt $len 1 }} required {{ else }} {{ if eq $len 0 }} required {{ end }} {{ end }} > + <br><input type="checkbox" name="sensitive">Mark sensitive</input></td> + </tr> + <tr> + <td><label for="captcha">Captcha:</label></td> + <td> + <div style="height: 65px; display: inline;"> + <img src="{{ .Board.Captcha }}"> + </div> + <input type="text" id="captcha" name="captcha" autocomplete="off"> + </td> + </tr> + </table> + <input type="hidden" id="inReplyTo" name="inReplyTo" value="{{ .Board.InReplyTo }}"> <input type="hidden" id="sendTo" name="sendTo" value="{{ .Board.To }}"> <input type="hidden" id="boardName" name="boardName" value="{{ .Board.Name }}"> <input type="hidden" id="captchaCode" name="captchaCode" value="{{ .Board.CaptchaCode }}"> <input type="hidden" id="returnTo" name="returnTo" value="{{ .ReturnTo }}"> - <input type="file" id="file" name="file" {{ if gt $len 1 }} required {{ else }} {{ if eq $len 0 }} required {{ end }} {{ end }} ><br><br> - <input type="checkbox" name="sensitive"><span>Mark attachment as sensitive</span><br><br> - <label stye="display: inline-block;" for="captcha">Captcha:</label> - <br> - <input style="display: inline-block;" type="text" id="captcha" name="captcha" autocomplete="off"><br> - <div style="height: 65px;"> - <img src="{{ .Board.Captcha }}"> - </div> </form> </div> @@ -41,37 +61,57 @@ {{ if eq (index .Posts 0).Type "Note" }} {{ if .Board.InReplyTo }} - <h3 id="newpostbtn" state="0" style="text-align: center; margin-top: 80px; display: none;"><a href="javascript:newpost()">[Post a Reply]</a></h3> + <h3 id="newpostbtn" state="0" style="text-align: center; margin-top: 80px; display: none;"><a href="javascript:startNewPost()">[Post a Reply]</a></h3> {{ else }} - <h3 id="newpostbtn" state="0" style="text-align: center; margin-top: 80px; display: none;"><a href="javascript:newpost()">[Start a New Thread]</a></h3> + <h3 id="newpostbtn" state="0" style="text-align: center; margin-top: 80px; display: none;"><a href="javascript:startNewPost()">[Start a New Thread]</a></h3> {{ end }} <!-- end if inreplyto--> {{ $len := len .Posts }} <div id="newpost"> - <form onsubmit="sessionStorage.setItem('element-closed-reply', true)" id="new-post" action="/post" method="post" enctype="multipart/form-data" style="margin-left: 180px;"> - <label for="name">Name:</label><br> - <input type="text" id="name" name="name" placeholder="Anonymous" maxlength="100"><br> - <label for="options">Options:</label><br> - <input type="text" id="options" name="options" maxlength="100" style="margin-right:10px">{{ if .Board.InReplyTo }}<input type="submit" value="Post">{{ end }}<br> - {{ if eq .Board.InReplyTo "" }} - <label for="subject">Subject:</label><br> - <input type="text" id="subject" name="subject" maxlength="100" style="margin-right:10px"><input type="submit" value="Post"><br> - {{ end }} - <label for="comment">Comment:</label><br> - <textarea rows="10" cols="50" id="comment" name="comment" maxlength="2000"></textarea><br> + <form onsubmit="sessionStorage.setItem('element-closed-reply', true)" id="new-post" action="/post" method="post" enctype="multipart/form-data"> + <table id="postForm"> + <tr> + <tr> + <td><label for="name">Name:</label></td> + <td><input type="text" id="name" name="name" placeholder="Anonymous" maxlength="100"> + <a onclick="stopNewPost()" style="float: right;">[X]</a> + </tr> + <tr> + <td><label for="options">Options:</label></td> + <td><input type="text" id="options" name="options" maxlength="100" style="margin-right:10px">{{ if .Board.InReplyTo }}<input type="submit" value="Post">{{ end }}</td> + </tr> + {{ if eq .Board.InReplyTo "" }} + <tr> + <td><label for="subject">Subject:</label></td> + <td><input type="text" id="subject" name="subject" maxlength="100" style="margin-right:10px"><input type="submit" value="Post"></td> + </tr> + {{ end }} + <tr> + <td><label for="comment">Comment:</label></td> + <td><textarea rows="10" cols="50" id="comment" name="comment" maxlength="2000"></textarea></td> + </tr> + <tr> + <td><label for="file">Image</label></td> + <td><input type="file" id="file" name="file" {{ if gt $len 1 }} required {{ else }} {{ if eq $len 0 }} required {{ end }} {{ end }} > + <br><input type="checkbox" name="sensitive">Mark sensitive</input></td> + </tr> + <tr> + <td><label for="captcha">Captcha:</label></td> + <td> + <div style="height: 65px; display: inline;"> + <img src="{{ .Board.Captcha }}"> + </div> + <input type="text" id="captcha" name="captcha" autocomplete="off"> + </td> + </tr> + </table> + <input type="hidden" id="inReplyTo" name="inReplyTo" value="{{ .Board.InReplyTo }}"> <input type="hidden" id="sendTo" name="sendTo" value="{{ .Board.To }}"> <input type="hidden" id="boardName" name="boardName" value="{{ .Board.Name }}"> <input type="hidden" id="captchaCode" name="captchaCode" value="{{ .Board.CaptchaCode }}"> - <input type="hidden" id="returnTo" name="returnTo" value="{{ .ReturnTo }}"> - <input type="file" id="file" name="file" {{ if gt $len 1 }} required {{ else }} {{ if eq $len 0 }} required {{ end }} {{ end }} ><br><br> - <input type="checkbox" name="sensitive"><span>Mark attachment as sensitive</span><br><br> - <label stye="display: inline-block;" for="captcha">Captcha:</label> - <br> - <input style="display: inline-block;" type="text" id="captcha" name="captcha" autocomplete="off"><br> - <div style="height: 65px;"> - <img src="{{ .Board.Captcha }}"> - </div> - </form> + <input type="hidden" id="returnTo" name="returnTo" value="{{ .ReturnTo }}"> </form> + </div> + </div> {{ else }} <h1 style="text-align: center;">Archived Post</h1> |