Add frame based navigation
authorr <r@freesoftwareextremist.com>
Tue, 18 Feb 2020 22:15:37 +0000 (22:15 +0000)
committerr <r@freesoftwareextremist.com>
Tue, 18 Feb 2020 22:15:37 +0000 (22:15 +0000)
29 files changed:
.gitignore
BUGS [new file with mode: 0644]
model/settings.go
renderer/model.go
renderer/renderer.go
service/auth.go
service/logging.go
service/service.go
service/transport.go
static/style.css
templates/about.tmpl
templates/emoji.tmpl
templates/error.tmpl
templates/header.tmpl
templates/likedby.tmpl
templates/nav.tmpl [new file with mode: 0644]
templates/navigation.tmpl [deleted file]
templates/notification.tmpl
templates/postform.tmpl
templates/retweetedby.tmpl
templates/root.tmpl [new file with mode: 0644]
templates/search.tmpl
templates/settings.tmpl
templates/signin.tmpl
templates/status.tmpl
templates/thread.tmpl
templates/timeline.tmpl
templates/user.tmpl
templates/usersearch.tmpl

index 516f77b9dfa5f2979175e48ca1df5c321a87a3b6..037bea639a5411516b4ff1752da12d7d30c41377 100644 (file)
@@ -1,2 +1,3 @@
 bloat
 database
+bloat.def.conf
diff --git a/BUGS b/BUGS
new file mode 100644 (file)
index 0000000..4972d14
--- /dev/null
+++ b/BUGS
@@ -0,0 +1,3 @@
+Here's a list of known bugs in bloat:
+
+- <frameset> and <frame> tags are not supported in HTML5
index 7d227475e60a730ba945a6a7112ef81eb5246d97..b1463c7848719459d206c17493c9601e082bca5d 100644 (file)
@@ -1,21 +1,23 @@
 package model
 
 type Settings struct {
-       DefaultVisibility string `json:"default_visibility"`
-       CopyScope         bool   `json:"copy_scope"`
-       ThreadInNewTab    bool   `json:"thread_in_new_tab"`
-       MaskNSFW          bool   `json:"mask_nfsw"`
-       FluorideMode      bool   `json:"fluoride_mode"`
-       DarkMode          bool   `json:"dark_mode"`
+       DefaultVisibility        string `json:"default_visibility"`
+       CopyScope                bool   `json:"copy_scope"`
+       ThreadInNewTab           bool   `json:"thread_in_new_tab"`
+       MaskNSFW                 bool   `json:"mask_nfsw"`
+       AutoRefreshNotifications bool   `json:"auto_refresh_notifications"`
+       FluorideMode             bool   `json:"fluoride_mode"`
+       DarkMode                 bool   `json:"dark_mode"`
 }
 
 func NewSettings() *Settings {
        return &Settings{
-               DefaultVisibility: "public",
-               CopyScope:         true,
-               ThreadInNewTab:    false,
-               MaskNSFW:          true,
-               FluorideMode:      false,
-               DarkMode:          false,
+               DefaultVisibility:        "public",
+               CopyScope:                true,
+               ThreadInNewTab:           false,
+               MaskNSFW:                 true,
+               AutoRefreshNotifications: false,
+               FluorideMode:             false,
+               DarkMode:                 false,
        }
 }
index 842dd71db3d88ee518604d7eb267ef333509ab88..45d3117fd55a4f9aec5a4e5714b0ce906a4c09d5 100644 (file)
@@ -14,30 +14,17 @@ type Context struct {
        UserID         string
 }
 
-type HeaderData struct {
-       Title             string
-       NotificationCount int
-       CustomCSS         string
-       CSRFToken         string
-}
-
-type NavbarData struct {
-       User              *mastodon.Account
-       NotificationCount int
+type NavData struct {
+       CommonData  *CommonData
+       User        *mastodon.Account
+       PostContext model.PostContext
 }
 
 type CommonData struct {
-       HeaderData *HeaderData
-       NavbarData *NavbarData
-}
-
-func (c CommonData) IsCurrentUser(id string) bool {
-       if c.NavbarData != nil &&
-               c.NavbarData.User != nil &&
-               c.NavbarData.User.ID == id {
-               return true
-       }
-       return false
+       Title       string
+       CustomCSS   string
+       CSRFToken   string
+       AutoRefresh bool
 }
 
 type ErrorData struct {
@@ -53,13 +40,16 @@ type SigninData struct {
        *CommonData
 }
 
+type RootData struct {
+       Title string
+}
+
 type TimelineData struct {
        *CommonData
-       Title       string
-       Statuses    []*mastodon.Status
-       NextLink    string
-       PrevLink    string
-       PostContext model.PostContext
+       Title    string
+       Statuses []*mastodon.Status
+       NextLink string
+       PrevLink string
 }
 
 type ThreadData struct {
@@ -72,8 +62,9 @@ type ThreadData struct {
 type NotificationData struct {
        *CommonData
        Notifications []*mastodon.Notification
+       UnreadCount   int
+       ReadID        string
        NextLink      string
-       DarkMode      bool
 }
 
 type UserData struct {
@@ -84,7 +75,6 @@ type UserData struct {
        Users     []*mastodon.Account
        Statuses  []*mastodon.Status
        NextLink  string
-       DarkMode  bool
 }
 
 type UserSearchData struct {
index bd9ccd8432d51e219ff9a5686416e477c277ee42..293a6c63b191712edae82530a2ed85b3820d15ac 100644 (file)
@@ -19,6 +19,8 @@ type TemplateData struct {
 type Renderer interface {
        RenderSigninPage(ctx *Context, writer io.Writer, data *SigninData) (err error)
        RenderErrorPage(ctx *Context, writer io.Writer, data *ErrorData)
+       RenderRootPage(ctx *Context, writer io.Writer, data *RootData) (err error)
+       RenderNavPage(ctx *Context, writer io.Writer, data *NavData) (err error)
        RenderTimelinePage(ctx *Context, writer io.Writer, data *TimelineData) (err error)
        RenderThreadPage(ctx *Context, writer io.Writer, data *ThreadData) (err error)
        RenderNotificationPage(ctx *Context, writer io.Writer, data *NotificationData) (err error)
@@ -67,6 +69,16 @@ func (r *renderer) RenderErrorPage(ctx *Context, writer io.Writer,
        return
 }
 
+func (r *renderer) RenderNavPage(ctx *Context, writer io.Writer,
+       data *NavData) (err error) {
+       return r.template.ExecuteTemplate(writer, "nav.tmpl", WithContext(data, ctx))
+}
+
+func (r *renderer) RenderRootPage(ctx *Context, writer io.Writer,
+       data *RootData) (err error) {
+       return r.template.ExecuteTemplate(writer, "root.tmpl", WithContext(data, ctx))
+}
+
 func (r *renderer) RenderTimelinePage(ctx *Context, writer io.Writer,
        data *TimelineData) (err error) {
        return r.template.ExecuteTemplate(writer, "timeline.tmpl", WithContext(data, ctx))
index 4c5b38b8c517bbf523cd9bf02788604830c0ff20..9e6f709d248b67059c7681ce293600736fe6f4d0 100644 (file)
@@ -68,6 +68,22 @@ func (s *as) ServeSigninPage(ctx context.Context, c *model.Client) (err error) {
        return s.Service.ServeSigninPage(ctx, c)
 }
 
+func (s *as) ServeRootPage(ctx context.Context, c *model.Client) (err error) {
+       err = s.authenticateClient(ctx, c)
+       if err != nil {
+               return
+       }
+       return s.Service.ServeRootPage(ctx, c)
+}
+
+func (s *as) ServeNavPage(ctx context.Context, c *model.Client) (err error) {
+       err = s.authenticateClient(ctx, c)
+       if err != nil {
+               return
+       }
+       return s.Service.ServeNavPage(ctx, c)
+}
+
 func (s *as) ServeTimelinePage(ctx context.Context, c *model.Client, tType string,
        maxID string, minID string) (err error) {
        err = s.authenticateClient(ctx, c)
@@ -382,3 +398,16 @@ func (s *as) Delete(ctx context.Context, c *model.Client, id string) (err error)
        }
        return s.Service.Delete(ctx, c, id)
 }
+
+func (s *as) ReadNotifications(ctx context.Context, c *model.Client,
+       maxID string) (err error) {
+       err = s.authenticateClient(ctx, c)
+       if err != nil {
+               return
+       }
+       err = checkCSRF(ctx, c)
+       if err != nil {
+               return
+       }
+       return s.Service.ReadNotifications(ctx, c, maxID)
+}
index 055daddc55d73731c5ca2dac1a8c135770472ecf..795f329cc41dc87960498d5011e0d6d36cdb5996 100644 (file)
@@ -34,6 +34,22 @@ func (s *ls) ServeSigninPage(ctx context.Context, c *model.Client) (err error) {
        return s.Service.ServeSigninPage(ctx, c)
 }
 
+func (s *ls) ServeRootPage(ctx context.Context, c *model.Client) (err error) {
+       defer func(begin time.Time) {
+               s.logger.Printf("method=%v, took=%v, err=%v\n",
+                       "ServeRootPage", time.Since(begin), err)
+       }(time.Now())
+       return s.Service.ServeRootPage(ctx, c)
+}
+
+func (s *ls) ServeNavPage(ctx context.Context, c *model.Client) (err error) {
+       defer func(begin time.Time) {
+               s.logger.Printf("method=%v, took=%v, err=%v\n",
+                       "ServeNavPage", time.Since(begin), err)
+       }(time.Now())
+       return s.Service.ServeNavPage(ctx, c)
+}
+
 func (s *ls) ServeTimelinePage(ctx context.Context, c *model.Client, tType string,
        maxID string, minID string) (err error) {
        defer func(begin time.Time) {
@@ -276,3 +292,12 @@ func (s *ls) Delete(ctx context.Context, c *model.Client, id string) (err error)
        }(time.Now())
        return s.Service.Delete(ctx, c, id)
 }
+
+func (s *ls) ReadNotifications(ctx context.Context, c *model.Client,
+       maxID string) (err error) {
+       defer func(begin time.Time) {
+               s.logger.Printf("method=%v, max_id=%v, took=%v, err=%v\n",
+                       "ReadNotifications", maxID, time.Since(begin), err)
+       }(time.Now())
+       return s.Service.ReadNotifications(ctx, c, maxID)
+}
index ecd0d3fb77db0b439a800a23e84db325182eae64..9e015096e7c81f1c2b88daf9b668d24687389737 100644 (file)
@@ -21,6 +21,8 @@ var (
 type Service interface {
        ServeErrorPage(ctx context.Context, c *model.Client, err error)
        ServeSigninPage(ctx context.Context, c *model.Client) (err error)
+       ServeRootPage(ctx context.Context, c *model.Client) (err error)
+       ServeNavPage(ctx context.Context, c *model.Client) (err error)
        ServeTimelinePage(ctx context.Context, c *model.Client, tType string, maxID string, minID string) (err error)
        ServeThreadPage(ctx context.Context, c *model.Client, id string, reply bool) (err error)
        ServeLikedByPage(ctx context.Context, c *model.Client, id string) (err error)
@@ -53,6 +55,7 @@ type Service interface {
        MuteConversation(ctx context.Context, c *model.Client, id string) (err error)
        UnMuteConversation(ctx context.Context, c *model.Client, id string) (err error)
        Delete(ctx context.Context, c *model.Client, id string) (err error)
+       ReadNotifications(ctx context.Context, c *model.Client, maxID string) (err error)
 }
 
 type service struct {
@@ -126,45 +129,14 @@ func addToReplyMap(m map[string][]mastodon.ReplyInfo, key interface{},
 }
 
 func (svc *service) getCommonData(ctx context.Context, c *model.Client,
-       title string) (data *renderer.CommonData, err error) {
-
-       data = new(renderer.CommonData)
-       data.HeaderData = &renderer.HeaderData{
-               Title:             title + " - " + svc.clientName,
-               NotificationCount: 0,
-               CustomCSS:         svc.customCSS,
-       }
-
-       if c == nil || !c.Session.IsLoggedIn() {
-               return
-       }
-
-       notifications, err := c.GetNotifications(ctx, nil)
-       if err != nil {
-               return nil, err
-       }
-
-       var notificationCount int
-       for i := range notifications {
-               if notifications[i].Pleroma != nil &&
-                       !notifications[i].Pleroma.IsSeen {
-                       notificationCount++
-               }
-       }
-
-       u, err := c.GetAccountCurrentUser(ctx)
-       if err != nil {
-               return nil, err
+       title string) (data *renderer.CommonData) {
+       data = &renderer.CommonData{
+               Title:     title + " - " + svc.clientName,
+               CustomCSS: svc.customCSS,
        }
-
-       data.NavbarData = &renderer.NavbarData{
-               User:              u,
-               NotificationCount: notificationCount,
+       if c != nil && c.Session.IsLoggedIn() {
+               data.CSRFToken = c.Session.CSRFToken
        }
-
-       data.HeaderData.NotificationCount = notificationCount
-       data.HeaderData.CSRFToken = c.Session.CSRFToken
-
        return
 }
 
@@ -174,11 +146,7 @@ func (svc *service) ServeErrorPage(ctx context.Context, c *model.Client, err err
                errStr = err.Error()
        }
 
-       commonData, err := svc.getCommonData(ctx, nil, "error")
-       if err != nil {
-               return
-       }
-
+       commonData := svc.getCommonData(ctx, nil, "error")
        data := &renderer.ErrorData{
                CommonData: commonData,
                Error:      errStr,
@@ -191,11 +159,7 @@ func (svc *service) ServeErrorPage(ctx context.Context, c *model.Client, err err
 func (svc *service) ServeSigninPage(ctx context.Context, c *model.Client) (
        err error) {
 
-       commonData, err := svc.getCommonData(ctx, nil, "signin")
-       if err != nil {
-               return
-       }
-
+       commonData := svc.getCommonData(ctx, nil, "signin")
        data := &renderer.SigninData{
                CommonData: commonData,
        }
@@ -204,6 +168,37 @@ func (svc *service) ServeSigninPage(ctx context.Context, c *model.Client) (
        return svc.renderer.RenderSigninPage(rCtx, c.Writer, data)
 }
 
+func (svc *service) ServeRootPage(ctx context.Context, c *model.Client) (err error) {
+       data := &renderer.RootData{
+               Title: svc.clientName,
+       }
+
+       rCtx := getRendererContext(c)
+       return svc.renderer.RenderRootPage(rCtx, c.Writer, data)
+}
+
+func (svc *service) ServeNavPage(ctx context.Context, c *model.Client) (err error) {
+       u, err := c.GetAccountCurrentUser(ctx)
+       if err != nil {
+               return
+       }
+
+       postContext := model.PostContext{
+               DefaultVisibility: c.Session.Settings.DefaultVisibility,
+               Formats:           svc.postFormats,
+       }
+
+       commonData := svc.getCommonData(ctx, c, "Nav")
+       data := &renderer.NavData{
+               User:        u,
+               CommonData:  commonData,
+               PostContext: postContext,
+       }
+
+       rCtx := getRendererContext(c)
+       return svc.renderer.RenderNavPage(rCtx, c.Writer, data)
+}
+
 func (svc *service) ServeTimelinePage(ctx context.Context, c *model.Client,
        tType string, maxID string, minID string) (err error) {
 
@@ -269,23 +264,13 @@ func (svc *service) ServeTimelinePage(ctx context.Context, c *model.Client,
                nextLink = fmt.Sprintf("/timeline/%s?max_id=%s", tType, pg.MaxID)
        }
 
-       postContext := model.PostContext{
-               DefaultVisibility: c.Session.Settings.DefaultVisibility,
-               Formats:           svc.postFormats,
-       }
-
-       commonData, err := svc.getCommonData(ctx, c, tType+" timeline ")
-       if err != nil {
-               return
-       }
-
+       commonData := svc.getCommonData(ctx, c, tType+" timeline ")
        data := &renderer.TimelineData{
-               Title:       title,
-               Statuses:    statuses,
-               NextLink:    nextLink,
-               PrevLink:    prevLink,
-               PostContext: postContext,
-               CommonData:  commonData,
+               Title:      title,
+               Statuses:   statuses,
+               NextLink:   nextLink,
+               PrevLink:   prevLink,
+               CommonData: commonData,
        }
 
        rCtx := getRendererContext(c)
@@ -356,11 +341,7 @@ func (svc *service) ServeThreadPage(ctx context.Context, c *model.Client,
                addToReplyMap(replies, statuses[i].InReplyToID, statuses[i].ID, i+1)
        }
 
-       commonData, err := svc.getCommonData(ctx, c, "post by "+status.Account.DisplayName)
-       if err != nil {
-               return
-       }
-
+       commonData := svc.getCommonData(ctx, c, "post by "+status.Account.DisplayName)
        data := &renderer.ThreadData{
                Statuses:    statuses,
                PostContext: postContext,
@@ -380,11 +361,7 @@ func (svc *service) ServeLikedByPage(ctx context.Context, c *model.Client,
                return
        }
 
-       commonData, err := svc.getCommonData(ctx, c, "likes")
-       if err != nil {
-               return
-       }
-
+       commonData := svc.getCommonData(ctx, c, "likes")
        data := &renderer.LikedByData{
                CommonData: commonData,
                Users:      likers,
@@ -402,11 +379,7 @@ func (svc *service) ServeRetweetedByPage(ctx context.Context, c *model.Client,
                return
        }
 
-       commonData, err := svc.getCommonData(ctx, c, "retweets")
-       if err != nil {
-               return
-       }
-
+       commonData := svc.getCommonData(ctx, c, "retweets")
        data := &renderer.RetweetedByData{
                CommonData: commonData,
                Users:      retweeters,
@@ -421,6 +394,7 @@ func (svc *service) ServeNotificationPage(ctx context.Context, c *model.Client,
 
        var nextLink string
        var unreadCount int
+       var readID string
        var pg = mastodon.Pagination{
                MaxID: maxID,
                MinID: minID,
@@ -439,23 +413,19 @@ func (svc *service) ServeNotificationPage(ctx context.Context, c *model.Client,
        }
 
        if unreadCount > 0 {
-               err := c.ReadNotifications(ctx, notifications[0].ID)
-               if err != nil {
-                       return err
-               }
+               readID = notifications[0].ID
        }
 
-       if len(pg.MaxID) > 0 {
+       if len(notifications) == 20 && len(pg.MaxID) > 0 {
                nextLink = "/notifications?max_id=" + pg.MaxID
        }
 
-       commonData, err := svc.getCommonData(ctx, c, "notifications")
-       if err != nil {
-               return
-       }
-
+       commonData := svc.getCommonData(ctx, c, "notifications")
+       commonData.AutoRefresh = c.Session.Settings.AutoRefreshNotifications
        data := &renderer.NotificationData{
                Notifications: notifications,
+               UnreadCount:   unreadCount,
+               ReadID:        readID,
                NextLink:      nextLink,
                CommonData:    commonData,
        }
@@ -521,14 +491,10 @@ func (svc *service) ServeUserPage(ctx context.Context, c *model.Client,
                return errInvalidArgument
        }
 
-       commonData, err := svc.getCommonData(ctx, c, user.DisplayName)
-       if err != nil {
-               return
-       }
-
+       commonData := svc.getCommonData(ctx, c, user.DisplayName)
        data := &renderer.UserData{
                User:       user,
-               IsCurrent:  commonData.IsCurrentUser(user.ID),
+               IsCurrent:  c.Session.UserID == user.ID,
                Type:       pageType,
                Users:      users,
                Statuses:   statuses,
@@ -564,11 +530,7 @@ func (svc *service) ServeUserSearchPage(ctx context.Context, c *model.Client,
                title += " \"" + q + "\""
        }
 
-       commonData, err := svc.getCommonData(ctx, c, title)
-       if err != nil {
-               return
-       }
-
+       commonData := svc.getCommonData(ctx, c, title)
        data := &renderer.UserSearchData{
                CommonData: commonData,
                User:       user,
@@ -582,11 +544,7 @@ func (svc *service) ServeUserSearchPage(ctx context.Context, c *model.Client,
 }
 
 func (svc *service) ServeAboutPage(ctx context.Context, c *model.Client) (err error) {
-       commonData, err := svc.getCommonData(ctx, c, "about")
-       if err != nil {
-               return
-       }
-
+       commonData := svc.getCommonData(ctx, c, "about")
        data := &renderer.AboutData{
                CommonData: commonData,
        }
@@ -596,16 +554,12 @@ func (svc *service) ServeAboutPage(ctx context.Context, c *model.Client) (err er
 }
 
 func (svc *service) ServeEmojiPage(ctx context.Context, c *model.Client) (err error) {
-       commonData, err := svc.getCommonData(ctx, c, "emojis")
-       if err != nil {
-               return
-       }
-
        emojis, err := c.GetInstanceEmojis(ctx)
        if err != nil {
                return
        }
 
+       commonData := svc.getCommonData(ctx, c, "emojis")
        data := &renderer.EmojiData{
                Emojis:     emojis,
                CommonData: commonData,
@@ -636,11 +590,7 @@ func (svc *service) ServeSearchPage(ctx context.Context, c *model.Client,
                title += " \"" + q + "\""
        }
 
-       commonData, err := svc.getCommonData(ctx, c, title)
-       if err != nil {
-               return
-       }
-
+       commonData := svc.getCommonData(ctx, c, title)
        data := &renderer.SearchData{
                CommonData: commonData,
                Q:          q,
@@ -655,11 +605,7 @@ func (svc *service) ServeSearchPage(ctx context.Context, c *model.Client,
 }
 
 func (svc *service) ServeSettingsPage(ctx context.Context, c *model.Client) (err error) {
-       commonData, err := svc.getCommonData(ctx, c, "settings")
-       if err != nil {
-               return
-       }
-
+       commonData := svc.getCommonData(ctx, c, "settings")
        data := &renderer.SettingsData{
                CommonData: commonData,
                Settings:   &c.Session.Settings,
@@ -911,3 +857,8 @@ func (svc *service) Delete(ctx context.Context, c *model.Client,
        id string) (err error) {
        return c.DeleteStatus(ctx, id)
 }
+
+func (svc *service) ReadNotifications(ctx context.Context, c *model.Client,
+       maxID string) (err error) {
+       return c.ReadNotifications(ctx, maxID)
+}
index 5ce0e5670f918ccb6d2a3a8cecd3bc7b4b65437e..48e2ee26c418137a7974332209faecbb761effe7 100644 (file)
@@ -64,14 +64,30 @@ func NewHandler(s Service, staticDir string) http.Handler {
 
        rootPage := func(w http.ResponseWriter, req *http.Request) {
                sessionID, _ := req.Cookie("session_id")
-
-               location := "/signin"
                if sessionID != nil && len(sessionID.Value) > 0 {
-                       location = "/timeline/home"
+                       c := newClient(w)
+                       ctx := newCtxWithSesion(req)
+                       err := s.ServeRootPage(ctx, c)
+                       if err != nil {
+                               w.WriteHeader(http.StatusInternalServerError)
+                               s.ServeErrorPage(ctx, c, err)
+                               return
+                       }
+               } else {
+                       w.Header().Add("Location", "/signin")
+                       w.WriteHeader(http.StatusFound)
                }
+       }
 
-               w.Header().Add("Location", location)
-               w.WriteHeader(http.StatusFound)
+       navPage := func(w http.ResponseWriter, req *http.Request) {
+               c := newClient(w)
+               ctx := newCtxWithSesion(req)
+               err := s.ServeNavPage(ctx, c)
+               if err != nil {
+                       w.WriteHeader(http.StatusInternalServerError)
+                       s.ServeErrorPage(ctx, c, err)
+                       return
+               }
        }
 
        signinPage := func(w http.ResponseWriter, req *http.Request) {
@@ -297,7 +313,7 @@ func NewHandler(s Service, staticDir string) http.Handler {
                        return
                }
 
-               w.Header().Add("Location", "/timeline/home")
+               w.Header().Add("Location", "/")
                w.WriteHeader(http.StatusFound)
        }
 
@@ -326,7 +342,7 @@ func NewHandler(s Service, staticDir string) http.Handler {
                        return
                }
 
-               location := "/timeline/home" + "#status-" + id
+               location := req.Header.Get("Referer")
                if len(replyToID) > 0 {
                        location = "/thread/" + replyToID + "#status-" + id
                }
@@ -540,16 +556,18 @@ func NewHandler(s Service, staticDir string) http.Handler {
                copyScope := req.FormValue("copy_scope") == "true"
                threadInNewTab := req.FormValue("thread_in_new_tab") == "true"
                maskNSFW := req.FormValue("mask_nsfw") == "true"
+               arn := req.FormValue("auto_refresh_notifications") == "true"
                fluorideMode := req.FormValue("fluoride_mode") == "true"
                darkMode := req.FormValue("dark_mode") == "true"
 
                settings := &model.Settings{
-                       DefaultVisibility: visibility,
-                       CopyScope:         copyScope,
-                       ThreadInNewTab:    threadInNewTab,
-                       MaskNSFW:          maskNSFW,
-                       FluorideMode:      fluorideMode,
-                       DarkMode:          darkMode,
+                       DefaultVisibility:        visibility,
+                       CopyScope:                copyScope,
+                       ThreadInNewTab:           threadInNewTab,
+                       MaskNSFW:                 maskNSFW,
+                       AutoRefreshNotifications: arn,
+                       FluorideMode:             fluorideMode,
+                       DarkMode:                 darkMode,
                }
 
                err := s.SaveSettings(ctx, c, settings)
@@ -559,7 +577,7 @@ func NewHandler(s Service, staticDir string) http.Handler {
                        return
                }
 
-               w.Header().Add("Location", req.Header.Get("Referer"))
+               w.Header().Add("Location", "/")
                w.WriteHeader(http.StatusFound)
        }
 
@@ -611,6 +629,22 @@ func NewHandler(s Service, staticDir string) http.Handler {
                w.WriteHeader(http.StatusFound)
        }
 
+       readNotifications := func(w http.ResponseWriter, req *http.Request) {
+               c := newClient(w)
+               ctx := newCtxWithSesionCSRF(req, req.FormValue("csrf_token"))
+               maxID := req.URL.Query().Get("max_id")
+
+               err := s.ReadNotifications(ctx, c, maxID)
+               if err != nil {
+                       w.WriteHeader(http.StatusInternalServerError)
+                       s.ServeErrorPage(ctx, c, err)
+                       return
+               }
+
+               w.Header().Add("Location", req.Header.Get("Referer"))
+               w.WriteHeader(http.StatusFound)
+       }
+
        signout := func(w http.ResponseWriter, req *http.Request) {
                // TODO remove session from database
                http.SetCookie(w, &http.Cookie{
@@ -694,7 +728,9 @@ func NewHandler(s Service, staticDir string) http.Handler {
        }
 
        r.HandleFunc("/", rootPage).Methods(http.MethodGet)
+       r.HandleFunc("/nav", navPage).Methods(http.MethodGet)
        r.HandleFunc("/signin", signinPage).Methods(http.MethodGet)
+       r.HandleFunc("//{type}", timelinePage).Methods(http.MethodGet)
        r.HandleFunc("/timeline/{type}", timelinePage).Methods(http.MethodGet)
        r.HandleFunc("/timeline", timelineOldPage).Methods(http.MethodGet)
        r.HandleFunc("/thread/{id}", threadPage).Methods(http.MethodGet)
@@ -726,6 +762,7 @@ func NewHandler(s Service, staticDir string) http.Handler {
        r.HandleFunc("/muteconv/{id}", muteConversation).Methods(http.MethodPost)
        r.HandleFunc("/unmuteconv/{id}", unMuteConversation).Methods(http.MethodPost)
        r.HandleFunc("/delete/{id}", delete).Methods(http.MethodPost)
+       r.HandleFunc("/notifications/read", readNotifications).Methods(http.MethodPost)
        r.HandleFunc("/signout", signout).Methods(http.MethodGet)
        r.HandleFunc("/fluoride/like/{id}", fLike).Methods(http.MethodPost)
        r.HandleFunc("/fluoride/unlike/{id}", fUnlike).Methods(http.MethodPost)
index 2f80af92ac1208b19fb2451b22ef865937bfd6fe..a647d4f3eeff83ef7394c1f9a4c261972e885f9b 100644 (file)
@@ -460,6 +460,19 @@ a:hover,
        margin-top: 6px;
 }
 
+.notification-title-container>* {
+       display: inline;
+}
+
+.notification-title {
+       font-size: 18pt;
+       margin-right: 8px;
+}
+
+.notification-refresh {
+       margin-right: 8px;
+}
+
 .dark {
        background-color: #222222;
        background-image: none;
index b3c9a494134924ca467e9263f002c41dd8a4f884..d4761deec7f788433b93e022eee8900dbaae5b44 100644 (file)
@@ -1,6 +1,5 @@
 {{with .Data}}
-{{template "header.tmpl" (WithContext .HeaderData $.Ctx)}}
-{{template "navigation.tmpl" (WithContext .NavbarData $.Ctx)}}
+{{template "header.tmpl" (WithContext .CommonData $.Ctx)}}
 <div class="page-title"> About </div>
 
 <div>
index 2066afaba1259134b84cc270300c37f9878217db..3e9f0f0cf5061387c55cc437052431c367ec7061 100644 (file)
@@ -1,6 +1,5 @@
 {{with .Data}}
-{{template "header.tmpl" (WithContext .HeaderData $.Ctx)}}
-{{template "navigation.tmpl" (WithContext .NavbarData $.Ctx)}}
+{{template "header.tmpl" (WithContext .CommonData $.Ctx)}}
 <div class="page-title"> Emojis </div>
 
 <div class="emoji-list-container">
index 0d6115a91b3583c1c348e5a6892114d47d39ebdc..fc925cac6621f29f5d923d5a708a53ba778eac9b 100644 (file)
@@ -1,11 +1,11 @@
 {{with .Data}}
-{{template "header.tmpl" (WithContext .HeaderData $.Ctx)}}
+{{template "header.tmpl" (WithContext .CommonData $.Ctx)}}
 <div class="page-title"> Error </div>
 
 <div class="error-text"> {{.Error}} </div>
 <div>
        <a href="/timeline/home">Home</a>
-       <a href="/signin">Sign In</a>
+       <a href="/signin" target="_top">Sign In</a>
 </div>
 
 {{template "footer.tmpl"}}
index 2889ead1be6c4dc45ddba695b89046533fd70289..76831f2514ae117f44b8eec582ecf7a506c46265 100644 (file)
@@ -7,7 +7,10 @@
        {{if .CSRFToken}}
        <meta name="csrf_token" content="{{.CSRFToken}}">
        {{end}}
-       <title>{{if gt .NotificationCount 0}}({{.NotificationCount}}) {{end}}{{.Title}}</title>
+       {{if .AutoRefresh}}
+       <meta http-equiv="refresh" content="30">
+       {{end}}
+       <title>{{.Title}}</title>
        <link rel="stylesheet" href="/static/style.css">
        {{if .CustomCSS}}
        <link rel="stylesheet" href="{{.CustomCSS}}">
index 00857c17a5125e379c4a0107d168c303b8ebea1e..222254ccdf0db4ee5745a7647ab03c10989540de 100644 (file)
@@ -1,6 +1,5 @@
 {{with .Data}}
-{{template "header.tmpl" (WithContext .HeaderData $.Ctx)}}
-{{template "navigation.tmpl" (WithContext .NavbarData $.Ctx)}}
+{{template "header.tmpl" (WithContext .CommonData $.Ctx)}}
 <div class="page-title"> Liked By </div>
 
 {{template "userlist.tmpl" (WithContext .Users $.Ctx)}}
diff --git a/templates/nav.tmpl b/templates/nav.tmpl
new file mode 100644 (file)
index 0000000..620643e
--- /dev/null
@@ -0,0 +1,34 @@
+{{with .Data}}
+{{template "header.tmpl" (WithContext .CommonData $.Ctx)}}
+<div class="user-info">
+       <div class="user-info-img-container">
+               <a class="img-link" href="/timeline/home" title="home" target="main">
+                       <img class="user-info-img" src="{{.User.AvatarStatic}}" alt="profile-avatar" />
+               </a>
+       </div>
+       <div class="user-info-details-container">
+               <div>
+                       <span class="status-dname"> {{EmojiFilter .User.DisplayName .User.Emojis}} </span>  
+                       <a class="nav-link" href="/user/{{.User.ID}}" target="main">
+                               <span class="status-uname"> {{.User.Acct}} </span>
+                       </a>
+               </div>
+               <div>
+                       <a class="nav-link" href="/timeline/home" target="main">home</a>
+                       <a class="nav-link" href="/timeline/direct" target="main">direct</a>
+                       <a class="nav-link" href="/timeline/local" target="main">local</a>
+                       <a class="nav-link" href="/timeline/twkn" target="main">twkn</a>
+                       <a class="nav-link" href="/search" target="main">search</a>
+                       <a class="nav-link" href="/about" target="main">about</a>
+               </div>
+               <div>
+                       <a class="nav-link" href="/settings" target="_top">settings</a>
+                       <a class="nav-link" href="/signout" target="_top">sign out</a>
+               </div>
+       </div>
+</div>
+
+{{template "postform.tmpl" (WithContext .PostContext $.Ctx)}}
+
+{{template "footer.tmpl"}}
+{{end}}
diff --git a/templates/navigation.tmpl b/templates/navigation.tmpl
deleted file mode 100644 (file)
index a85f9fd..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-{{with .Data}}
-<div class="user-info">
-       <div class="user-info-img-container">
-               <a class="img-link" href="/timeline/home" title="home">
-                       <img class="user-info-img" src="{{.User.AvatarStatic}}" alt="profile-avatar" />
-               </a>
-       </div>
-       <div class="user-info-details-container">
-               <div>
-                       <span class="status-dname"> {{EmojiFilter .User.DisplayName .User.Emojis}} </span>  
-                       <a class="nav-link" href="/user/{{.User.ID}}">
-                               <span class="status-uname"> {{.User.Acct}} </span>
-                       </a>
-               </div>
-               <div>
-                       <a class="nav-link" href="/timeline/home">home</a>
-                       <a class="nav-link" href="/notifications">notifications{{if gt .NotificationCount 0}}({{.NotificationCount}}){{end}}</a>
-                       <a class="nav-link" href="/timeline/direct">direct</a>
-                       <a class="nav-link" href="/timeline/local">local</a>
-                       <a class="nav-link" href="/timeline/twkn">twkn</a>
-                       <a class="nav-link" href="/search">search</a>
-                       <a class="nav-link" href="/about">about</a>
-               </div>
-               <div>
-                       <a class="nav-link" href="/settings">settings</a>
-                       <a class="nav-link" href="/signout">sign out</a>
-               </div>
-       </div>
-</div>
-{{end}}
index 51cc6e34fcf41444541947891ea8830c48450703..9e1854cc5234ce10e5f09d8ab5ba1c5f4734158a 100644 (file)
@@ -1,14 +1,25 @@
 {{with .Data}}
-{{template "header.tmpl" (WithContext .HeaderData $.Ctx)}}
-{{template "navigation.tmpl" (WithContext .NavbarData $.Ctx)}}
-<div class="page-title"> Notifications </div>
+{{template "header.tmpl" (WithContext .CommonData $.Ctx)}}
+<div class="notification-title-container">
+       <div class="notification-title">
+               Notifications
+               {{if gt .UnreadCount 0}}({{.UnreadCount }}){{end}}
+       </div>
+       <a class="notification-refresh" href="/notifications">refresh</a>
+       {{if .ReadID}}
+       <form action="/notifications/read?max_id={{.ReadID}}" method="post">
+               <input type="hidden" name="csrf_token" value="{{$.Ctx.CSRFToken}}">
+               <input type="submit" value="read" class="btn-link">
+       </form>
+       {{end}}
+</div>
 
 {{range .Notifications}}
 <div class="notification-container {{if .Pleroma}}{{if not .Pleroma.IsSeen}}unread{{end}}{{end}}">
        {{if eq .Type "follow"}}
        <div class="notification-follow-container">
                <div class="status-profile-img-container">
-                       <a class="img-link" href="/user/{{.Account.ID}}" >
+                       <a class="img-link" href="/user/{{.Account.ID}}" target="main" >
                                <img class="status-profile-img" src="{{.Account.AvatarStatic}}" alt="profile-avatar" />
                        </a>
                </div>
@@ -31,7 +42,7 @@
 
        {{else if eq .Type "reblog"}}
        <div class="retweet-info">
-               <a class="img-link" href="/user/{{.Account.ID}}">
+               <a class="img-link" href="/user/{{.Account.ID}}" target="main">
                        <img class="status-profile-img" src="{{.Account.AvatarStatic}}" alt="avatar" />
                </a>
                <span class="status-dname"> {{EmojiFilter .Account.DisplayName .Account.Emojis}} </span>  
@@ -44,7 +55,7 @@
 
        {{else if eq .Type "favourite"}}
        <div class="retweet-info">
-               <a class="img-link" href="/user/{{.Account.ID}}">
+               <a class="img-link" href="/user/{{.Account.ID}}" target="main">
                        <img class="status-profile-img" src="{{.Account.AvatarStatic}}" alt="avatar" />
                </a>
                <span class="status-dname"> {{EmojiFilter .Account.DisplayName .Account.Emojis}} </span>  
index 51ac5e6851bb2f980f7372e1e5c2cd7c2b629c06..d5c1fb93e0a98d21c5b6bc546b40c400a14a5eb2 100644 (file)
@@ -11,7 +11,7 @@
                emoji list
        </a>
        <div class="post-form-content-container">
-               <textarea id="post-content" name="content" class="post-content" cols="50" rows="5">{{if .ReplyContext}}{{.ReplyContext.ReplyContent}}{{end}}</textarea>
+               <textarea id="post-content" name="content" class="post-content" cols="34" rows="5">{{if .ReplyContext}}{{.ReplyContext.ReplyContent}}{{end}}</textarea>
        </div>
        <div>
                {{if gt (len .Formats) 0}}
index ce0d3374478aeee2927c0505e37d43421eddb9c2..9492ee6c1cbbbba0eb9f0e0508239907ff23227c 100644 (file)
@@ -1,6 +1,5 @@
 {{with .Data}}
-{{template "header.tmpl" (WithContext .HeaderData $.Ctx)}}
-{{template "navigation.tmpl" (WithContext .NavbarData $.Ctx)}}
+{{template "header.tmpl" (WithContext .CommonData $.Ctx)}}
 <div class="page-title"> Retweeted By </div>
 
 {{template "userlist.tmpl" (WithContext .Users $.Ctx)}}
diff --git a/templates/root.tmpl b/templates/root.tmpl
new file mode 100644 (file)
index 0000000..cd33139
--- /dev/null
@@ -0,0 +1,17 @@
+{{with .Data}}
+<!DOCTYPE html>
+<html lang="en">
+<head>
+       <meta charset='utf-8'>
+       <meta content='width=device-width, initial-scale=1' name='viewport'>
+       <title>{{.Title}}</title>
+</head>
+<frameset cols="30%,*">
+       <frameset rows="316px,*">
+               <frame name="nav" class="nav-frame" src="/nav" /> 
+               <frame name="notification" class="notification-frame" src="/notifications" /> 
+       </frameset>
+       <frame name="main" class="main-frame" src="/timeline/home" /> 
+</frameset>
+</html>
+{{end}}
index 96548b55d0dbc7c6744d039d45a7981a4b7974a5..ede147e5d7f85080fbfd5f3b1cc535915ff8c8f0 100644 (file)
@@ -1,6 +1,5 @@
 {{with .Data}}
-{{template "header.tmpl" (WithContext .HeaderData $.Ctx)}}
-{{template "navigation.tmpl" (WithContext .NavbarData $.Ctx)}}
+{{template "header.tmpl" (WithContext .CommonData $.Ctx)}}
 <div class="page-title"> Search </div>
 
 <form class="search-form" action="/search" method="GET">
index e7d49e9b44ebf335b6fda00b2dfbfce56883e68e..d8ede87f3b9f0a2c282764e63182044b177147f0 100644 (file)
@@ -1,6 +1,5 @@
 {{with .Data}}
-{{template "header.tmpl" (WithContext .HeaderData $.Ctx)}}
-{{template "navigation.tmpl" (WithContext .NavbarData $.Ctx)}}
+{{template "header.tmpl" (WithContext .CommonData $.Ctx)}}
 <div class="page-title"> Settings </div>
 
 <form id="settings-form" action="/settings" method="POST">
        </div>
        <div class="settings-form-field">
                <input id="mask-nsfw" name="mask_nsfw" type="checkbox" value="true" {{if .Settings.MaskNSFW}}checked{{end}}>
-               <label for="mask-nsfw"> Mask NSFW Attachments </label>
+               <label for="mask-nsfw"> Mask NSFW attachments </label>
+       </div>
+       <div class="settings-form-field">
+               <input id="auto-refresh-notifications" name="auto_refresh_notifications" type="checkbox" value="true" {{if .Settings.AutoRefreshNotifications}}checked{{end}}>
+               <label for="auto-refresh-notifications"> Auto refresh notifications </label>
        </div>
        <div class="settings-form-field">
                <input id="fluoride-mode" name="fluoride_mode" type="checkbox" value="true" {{if .Settings.FluorideMode}}checked{{end}}>
-               <label for="fluoride-mode"> Enable Fluoride Mode </label>
+               <label for="fluoride-mode"> Enable fluoride mode </label>
        </div>
        <div class="settings-form-field">
                <input id="dark-mode" name="dark_mode" type="checkbox" value="true" {{if .Settings.DarkMode}}checked{{end}}>
index a1999486fd489ad047abea9d383ecf4f70ba17d1..069572bc1cb2b783768eb64a9e8b113beda93762 100644 (file)
@@ -1,5 +1,5 @@
 {{with .Data}}
-{{template "header.tmpl" (WithContext .HeaderData $.Ctx)}}
+{{template "header.tmpl" (WithContext .CommonData $.Ctx)}}
 <div class="page-title"> Signin </div>
 
 <form class="signin-form" action="/signin" method="post">
index 95dee206a7e16e6709b37455556e6f2689796b78..c4f2e5f41f6d4f706a1e7224fc40cd15da12845a 100644 (file)
@@ -2,7 +2,7 @@
 <div id="status-{{.ID}}" class="status-container-container">
        {{if .Reblog}}
        <div class="retweet-info">
-               <a class="img-link" href="/user/{{.Account.ID}}">
+               <a class="img-link" href="/user/{{.Account.ID}}" target="main">
                        <img class="status-profile-img" src="{{.Account.AvatarStatic}}" alt="avatar" />
                </a>
                <span class="status-dname"> {{EmojiFilter .Account.DisplayName .Account.Emojis}} </span>  
        {{with $s := .Data}}
        <div class="status-container status-{{.ID}}" data-id="{{.ID}}">
                <div class="status-profile-img-container">
-                       <a class="img-link" href="/user/{{.Account.ID}}">
+                       <a class="img-link" href="/user/{{.Account.ID}}" target="main">
                                <img class="status-profile-img" src="{{.Account.AvatarStatic}}" alt="avatar" />
                        </a>
                </div>
                <div class="status"> 
                        <div class="status-name">
                                <span class="status-dname"> {{EmojiFilter .Account.DisplayName .Account.Emojis}} </span> 
-                               <a href="/user/{{.Account.ID}}" >
+                               <a href="/user/{{.Account.ID}}"  target="main">
                                        <span class="status-uname"> {{.Account.Acct}} </span>
                                </a>
-                               <div class="more-container" title="more">
+                               <div class="more-container">
                                        <div class="remote-link">
                                                {{.Visibility}}
                                        </div>
                                        <div class="more-content">
-                                               <a class="more-link" href="{{.URL}}" target="_blank" title="source">
+                                               <a class="more-link" href="{{.URL}}" target="_blank">
                                                        source
                                                </a>
                                                {{if .Muted}}
                                                <form action="/unmuteconv/{{.ID}}" method="post">
                                                        <input type="hidden" name="csrf_token" value="{{$.Ctx.CSRFToken}}">
-                                                       <input type="submit" value="unmute" class="btn-link more-link" title="unmute">
+                                                       <input type="submit" value="unmute" class="btn-link more-link">
                                                </form>
                                                {{else}}
                                                <form action="/muteconv/{{.ID}}" method="post">
                                                        <input type="hidden" name="csrf_token" value="{{$.Ctx.CSRFToken}}">
-                                                       <input type="submit" value="mute" class="btn-link more-link" title="mute">
+                                                       <input type="submit" value="mute" class="btn-link more-link">
                                                </form>
                                                {{end}}
                                                {{if eq $.Ctx.UserID .Account.ID}}
                                                <form action="/delete/{{.ID}}" method="post">
                                                        <input type="hidden" name="csrf_token" value="{{$.Ctx.CSRFToken}}">
-                                                       <input type="submit" value="delete" class="btn-link more-link" title="delete">
+                                                       <input type="submit" value="delete" class="btn-link more-link">
                                                </form>
                                                {{end}}
                                        </div>
@@ -55,7 +55,7 @@
                        <div class="status-reply-container">
                                {{if .InReplyToID}}
                                <div class="status-reply-to">
-                                       <a class="status-reply-to-link" href="{{if not .ShowReplies}}/thread/{{.InReplyToID}}{{end}}#status-{{.InReplyToID}}"> 
+                                       <a class="status-reply-to-link" href="{{if not .ShowReplies}}/thread/{{.InReplyToID}}{{end}}#status-{{.InReplyToID}}" target="main"
                                                 reply to {{.Pleroma.InReplyToAccountAcct}} 
                                        </a>
                                </div>
                        {{end}}
                        <div class="status-action-container"> 
                                <div class="status-action">
-                                       <a href="/thread/{{.ID}}?reply=true#status-{{.ID}}" title="reply"> 
+                                       <a href="/thread/{{.ID}}?reply=true#status-{{.ID}}" target="main"> 
                                                reply
                                        </a>
-                                       <a class="status-reply-count" href="/thread/{{.ID}}#status-{{.ID}}" {{if $.Ctx.ThreadInNewTab}}target="_blank"{{end}}>
+                                       <a class="status-reply-count" href="/thread/{{.ID}}#status-{{.ID}}" target="{{if $.Ctx.ThreadInNewTab}}_blank{{else}}main{{end}}">
                                                {{if .RepliesCount}} ({{DisplayInteractionCount .RepliesCount}}) {{end}}
                                        </a>
                                </div>
                                <div class="status-action">
                                        {{if or (eq .Visibility "private") (eq .Visibility "direct")}}
-                                       <a class="status-retweet" title="this status cannot be retweeted"> 
+                                       <a class="status-retweet" href="" title="this status cannot be retweeted" target="main"> 
                                                retweet
                                        </a>
                                        {{else}}
                                        <form class="status-retweet" data-action="unretweet" action="/unretweet/{{.ID}}" method="post">
                                                <input type="hidden" name="csrf_token" value="{{$.Ctx.CSRFToken}}">
                                                <input type="hidden" name="retweeted_by_id" value="{{.RetweetedByID}}">
-                                               <input type="submit" value="unretweet" class="btn-link" title="unretweet">
+                                               <input type="submit" value="unretweet" class="btn-link">
                                        </form>
                                        {{else}}
                                        <form class="status-retweet" data-action="retweet" action="/retweet/{{.ID}}" method="post">
                                                <input type="hidden" name="csrf_token" value="{{$.Ctx.CSRFToken}}">
                                                <input type="hidden" name="retweeted_by_id" value="{{.RetweetedByID}}">
-                                               <input type="submit" value="retweet" class="btn-link" title="retweet">
+                                               <input type="submit" value="retweet" class="btn-link">
                                        </form>
                                        {{end}}
                                        {{end}}
-                                       <a class="status-retweet-count" href="/retweetedby/{{.ID}}" title="click to see the the list"> 
+                                       <a class="status-retweet-count" href="/retweetedby/{{.ID}}" title="click to see the the list" target="main"
                                                {{if .ReblogsCount}} ({{DisplayInteractionCount .ReblogsCount}}) {{end}}
                                        </a>
                                </div>
                                        <form class="status-like" data-action="unlike" action="/unlike/{{.ID}}" method="post">
                                                <input type="hidden" name="csrf_token" value="{{$.Ctx.CSRFToken}}">
                                                <input type="hidden" name="retweeted_by_id" value="{{.RetweetedByID}}">
-                                               <input type="submit" value="unlike" class="btn-link" title="unlike">
+                                               <input type="submit" value="unlike" class="btn-link">
                                        </form>
                                        {{else}}
                                        <form class="status-like" data-action="like" action="/like/{{.ID}}" method="post">
                                                <input type="hidden" name="csrf_token" value="{{$.Ctx.CSRFToken}}">
                                                <input type="hidden" name="retweeted_by_id" value="{{.RetweetedByID}}">
-                                               <input type="submit" value="like" class="btn-link" title="like">
+                                               <input type="submit" value="like" class="btn-link">
                                        </form>
                                        {{end}}
-                                       <a class="status-like-count" href="/likedby/{{.ID}}" title="click to see the the list"> 
+                                       <a class="status-like-count" href="/likedby/{{.ID}}" title="click to see the the list" target="main"
                                                {{if .FavouritesCount}} ({{DisplayInteractionCount .FavouritesCount}}) {{end}}
                                        </a>
                                </div>
                                <div class="status-action">
                                        <a class="status-time" href="{{if not .ShowReplies}}/thread/{{.ID}}{{end}}#status-{{.ID}}" 
-                                               {{if $.Ctx.ThreadInNewTab}}target="_blank"{{end}}
+                                               target="{{if $.Ctx.ThreadInNewTab}}_blank{{else}}main{{end}}"
                                                <time datetime="{{FormatTimeRFC3339 .CreatedAt}}" title="{{FormatTimeRFC822 .CreatedAt}}"> 
                                                        {{TimeSince .CreatedAt}}
                                                </time> 
index 2927ee4b04ae975d34a02d4faae8af1eee816845..8cf9ead32a5a3aa47b32d53bc1ef05cbcb8b953c 100644 (file)
@@ -1,6 +1,5 @@
 {{with $s := .Data}}
-{{template "header.tmpl" (WithContext .HeaderData $.Ctx)}}
-{{template "navigation.tmpl" (WithContext .NavbarData $.Ctx)}}
+{{template "header.tmpl" (WithContext .CommonData $.Ctx)}}
 <div class="page-title"> Thread </div>
 
 {{range .Statuses}}
index 0321c7f9dcdcad07a491fb40f2c7cef175afde51..82b624dc4a6e76e0dc618c27e13848548f3dc14c 100644 (file)
@@ -1,10 +1,7 @@
 {{with .Data}}
-{{template "header.tmpl" (WithContext .HeaderData $.Ctx)}}
-{{template "navigation.tmpl" (WithContext .NavbarData $.Ctx)}}
+{{template "header.tmpl" (WithContext .CommonData $.Ctx)}}
 <div class="page-title"> {{.Title}} </div>
 
-{{template "postform.tmpl" (WithContext .PostContext $.Ctx)}}
-
 {{range .Statuses}}
 {{template "status.tmpl" (WithContext . $.Ctx)}}
 {{end}}
index de2b5c4b4d53ea3d763e10c671cad498fb7a4559..6ea79f7a5131b61dbbda59d79898b6d1a8c5b294 100644 (file)
@@ -1,6 +1,5 @@
 {{with .Data}}
-{{template "header.tmpl" (WithContext .HeaderData $.Ctx)}}
-{{template "navigation.tmpl" (WithContext .NavbarData $.Ctx)}}
+{{template "header.tmpl" (WithContext .CommonData $.Ctx)}}
 <div class="page-title"> User </div>
 
 <div class="user-info-container">
index 8e19fd1ae92caf02dab5b6258cf57821830e5140..ca99b4c11e9589e01a8c239ba6109f1a35382645 100644 (file)
@@ -1,6 +1,5 @@
 {{with .Data}}
-{{template "header.tmpl" (WithContext .HeaderData $.Ctx)}}
-{{template "navigation.tmpl" (WithContext .NavbarData $.Ctx)}}
+{{template "header.tmpl" (WithContext .CommonData $.Ctx)}}
 <div class="page-title"> Search {{EmojiFilter .User.DisplayName .User.Emojis}}'s statuses </div>
 
 <form class="search-form" action="/usersearch/{{.User.ID}}" method="GET">