aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--plugins/base/imap.go16
-rw-r--r--plugins/base/routes.go74
-rw-r--r--themes/alps/assets/style.css3
-rw-r--r--themes/alps/mailbox.html51
4 files changed, 110 insertions, 34 deletions
diff --git a/plugins/base/imap.go b/plugins/base/imap.go
index 16bd2ef..a7f4ea1 100644
--- a/plugins/base/imap.go
+++ b/plugins/base/imap.go
@@ -19,6 +19,9 @@ import (
type MailboxInfo struct {
*imap.MailboxInfo
+
+ Active bool
+ Unseen int
}
func (mbox *MailboxInfo) URL() *url.URL {
@@ -27,6 +30,15 @@ func (mbox *MailboxInfo) URL() *url.URL {
}
}
+func (mbox *MailboxInfo) HasAttr(flag string) bool {
+ for _, attr := range mbox.Attributes {
+ if attr == flag {
+ return true
+ }
+ }
+ return false
+}
+
func listMailboxes(conn *imapclient.Client) ([]MailboxInfo, error) {
ch := make(chan *imap.MailboxInfo, 10)
done := make(chan error, 1)
@@ -36,7 +48,7 @@ func listMailboxes(conn *imapclient.Client) ([]MailboxInfo, error) {
var mailboxes []MailboxInfo
for mbox := range ch {
- mailboxes = append(mailboxes, MailboxInfo{mbox})
+ mailboxes = append(mailboxes, MailboxInfo{mbox, false, -1})
}
if err := <-done; err != nil {
@@ -133,7 +145,7 @@ func getMailboxByType(conn *imapclient.Client, mboxType mailboxType) (*MailboxIn
if best == nil {
return nil, nil
}
- return &MailboxInfo{best}, nil
+ return &MailboxInfo{best, false, -1}, nil
}
func ensureMailboxSelected(conn *imapclient.Client, mboxName string) error {
diff --git a/plugins/base/routes.go b/plugins/base/routes.go
index b61b844..977b017 100644
--- a/plugins/base/routes.go
+++ b/plugins/base/routes.go
@@ -65,12 +65,57 @@ func registerRoutes(p *alps.GoPlugin) {
type MailboxRenderData struct {
alps.BaseRenderData
- Mailbox *MailboxStatus
- Inbox *MailboxStatus
- Mailboxes []MailboxInfo
- Messages []IMAPMessage
- PrevPage, NextPage int
- Query string
+ Mailbox *MailboxStatus
+ Inbox *MailboxStatus
+ CategorizedMailboxes CategorizedMailboxes
+ Mailboxes []MailboxInfo
+ Messages []IMAPMessage
+ PrevPage, NextPage int
+ Query string
+}
+
+// Organizes mailboxes into common/uncommon categories
+type CategorizedMailboxes struct {
+ Common struct {
+ Inbox *MailboxInfo
+ Drafts *MailboxInfo
+ Sent *MailboxInfo
+ Junk *MailboxInfo
+ Trash *MailboxInfo
+ Archive *MailboxInfo
+ }
+ Additional []*MailboxInfo
+}
+
+func categorizeMailboxes(mailboxes []MailboxInfo,
+ inbox *MailboxStatus, active *MailboxStatus) CategorizedMailboxes {
+
+ var out CategorizedMailboxes
+ mmap := map[string]**MailboxInfo{
+ "INBOX": &out.Common.Inbox,
+ "Drafts": &out.Common.Drafts,
+ "Sent": &out.Common.Sent,
+ "Junk": &out.Common.Junk,
+ "Trash": &out.Common.Trash,
+ "Archive": &out.Common.Archive,
+ }
+ for i, _ := range mailboxes {
+ // Populate unseen & active states
+ if mailboxes[i].Name == active.Name {
+ mailboxes[i].Unseen = int(active.Unseen)
+ mailboxes[i].Active = true
+ }
+ if mailboxes[i].Name == inbox.Name {
+ mailboxes[i].Unseen = int(inbox.Unseen)
+ }
+
+ if ptr, ok := mmap[mailboxes[i].Name]; ok {
+ *ptr = &mailboxes[i]
+ } else {
+ out.Additional = append(out.Additional, &mailboxes[i])
+ }
+ }
+ return out
}
func handleGetMailbox(ctx *alps.Context) error {
@@ -154,15 +199,18 @@ func handleGetMailbox(ctx *alps.Context) error {
title = fmt.Sprintf("(%d) %s", mbox.Unseen, title)
}
+ categorized := categorizeMailboxes(mailboxes, inbox, mbox)
+
return ctx.Render(http.StatusOK, "mailbox.html", &MailboxRenderData{
BaseRenderData: *alps.NewBaseRenderData(ctx).WithTitle(title),
- Mailbox: mbox,
- Inbox: inbox,
- Mailboxes: mailboxes,
- Messages: msgs,
- PrevPage: prevPage,
- NextPage: nextPage,
- Query: query,
+ Mailbox: mbox,
+ Inbox: inbox,
+ CategorizedMailboxes: categorized,
+ Mailboxes: mailboxes,
+ Messages: msgs,
+ PrevPage: prevPage,
+ NextPage: nextPage,
+ Query: query,
})
}
diff --git a/themes/alps/assets/style.css b/themes/alps/assets/style.css
index 6d107de..2ba4af7 100644
--- a/themes/alps/assets/style.css
+++ b/themes/alps/assets/style.css
@@ -127,7 +127,8 @@ footer { text-align: right; }
aside { flex: 0 0 180px; }
-aside a { width: 100%; display: block; padding: 0.4rem 0 0.4rem 0.5rem; }
+aside a,
+aside .noselect { width: 100%; display: block; padding: 0.4rem 0 0.4rem 0.5rem; }
aside a.active { font-weight: bold; color: black; text-decoration: none; }
aside img { display: block; }
main {
diff --git a/themes/alps/mailbox.html b/themes/alps/mailbox.html
index 4582726..e09f2b7 100644
--- a/themes/alps/mailbox.html
+++ b/themes/alps/mailbox.html
@@ -1,28 +1,43 @@
{{template "head.html" .}}
{{template "nav.html" .}}
+{{ define "mbox-link" }}
+{{ if not (.HasAttr "\\Noselect") }}
+<a href="{{.URL}}" {{ if .Active }}class="active"{{ end }}>
+ {{- if eq .Name "INBOX" -}}
+ Inbox
+ {{- else -}}
+ {{ .Name }}
+ {{- end -}}
+ {{- if .HasAttr "\\HasChildren" }}/{{ end }}
+
+ {{ if and (ne .Unseen -1) (ne .Unseen 0) }}({{ .Unseen }}){{ end }}
+</a>
+{{ else }}
+<span class="noselect">
+ {{.Name}}{{- if .HasAttr "\\HasChildren" }}/{{ end }}
+</span>
+{{ end }}
+{{ end }}
+
<div class="page-wrap">
<aside>
<!-- the logo image, dimensions 200x32 may be present or not -->
<a href="/compose" class="new">Compose&nbsp;Mail</a>
- {{range .Mailboxes}}
- <a href="{{.URL}}" {{ if eq $.Mailbox.Name .Name }}class="active"{{ end }}>
- {{ if eq .Name "INBOX" }}
- Inbox
- {{ else }}
- {{ .Name }}
- {{ end }}
-
- {{ $unseen := 0 }}
- {{ if eq .Name "INBOX" }}
- {{ $unseen = $.Inbox.Unseen }}
- {{ end }}
- {{ if eq .Name $.Mailbox.Name }}
- {{ $unseen = $.Mailbox.Unseen }}
- {{ end }}
- {{ if $unseen }}({{ $unseen }}){{ end }}
- </a>
- {{end}}
+ {{ with .CategorizedMailboxes }}
+ {{ with .Common.Inbox }}{{ template "mbox-link" . }}{{ end}}
+ {{ with .Common.Drafts }}{{ template "mbox-link" . }}{{ end}}
+ {{ with .Common.Sent }}{{ template "mbox-link" . }}{{ end}}
+ {{ with .Common.Junk }}{{ template "mbox-link" . }}{{ end}}
+ {{ with .Common.Trash }}{{ template "mbox-link" . }}{{ end}}
+ {{ with .Common.Archive }}{{ template "mbox-link" . }}{{ end}}
+ {{ if .Additional }}
+ <hr />
+ {{ range .Additional }}
+ {{ template "mbox-link" . }}
+ {{ end }}
+ {{ end }}
+ {{ end }}
</aside>
<div class="container">