aboutsummaryrefslogtreecommitdiff
path: root/themes
diff options
context:
space:
mode:
authorSimon Ser <contact@emersion.fr>2020-03-19 18:03:13 +0100
committerSimon Ser <contact@emersion.fr>2020-03-19 18:03:13 +0100
commitc182fbde6334f07873700d6a487155fb3f493403 (patch)
tree11089f6315dbc9a21300f546ffa5abb8c09a53c4 /themes
parent9eac0b453a21918f7533e78aa0fbb4d07cdbf474 (diff)
downloadalps-c182fbde6334f07873700d6a487155fb3f493403.tar.gz
alps-c182fbde6334f07873700d6a487155fb3f493403.zip
themes/alps: new theme
Diffstat (limited to 'themes')
-rw-r--r--themes/alps/assets/helpers.js24
-rw-r--r--themes/alps/assets/style.css269
-rw-r--r--themes/alps/compose.html40
-rw-r--r--themes/alps/foot.html3
-rw-r--r--themes/alps/head.html10
-rw-r--r--themes/alps/login.html26
-rw-r--r--themes/alps/mailbox.html66
-rw-r--r--themes/alps/message.html154
-rw-r--r--themes/alps/messages-header.html45
-rw-r--r--themes/alps/nav.html12
10 files changed, 649 insertions, 0 deletions
diff --git a/themes/alps/assets/helpers.js b/themes/alps/assets/helpers.js
new file mode 100644
index 0000000..344dd17
--- /dev/null
+++ b/themes/alps/assets/helpers.js
@@ -0,0 +1,24 @@
+(function() {
+ var sheet = document.styleSheets[0];
+ var addCSSRule = function(selector, rules, index) {
+ if ("insertRule" in sheet) {
+ sheet.insertRule(selector + "{" + rules + "}", index);
+ return;
+ }
+ if ("addRule" in sheet) {
+ sheet.addRule(selector, rules, index);
+ }
+ };
+
+ var checkboxAll = document.getElementById("action-checkbox-all");
+ if (checkboxAll) {
+ addCSSRule(".message-list-checkbox", "display: table-cell !important;");
+ checkboxAll.addEventListener("click", function(ev) {
+ var allChecked = this.checked;
+ var inputs = document.querySelectorAll("tr .message-list-checkbox input");
+ Array.prototype.slice.apply().forEach(function(cb) {
+ cb.checked = allChecked;
+ });
+ });
+ }
+})();
diff --git a/themes/alps/assets/style.css b/themes/alps/assets/style.css
new file mode 100644
index 0000000..16db44c
--- /dev/null
+++ b/themes/alps/assets/style.css
@@ -0,0 +1,269 @@
+/* Box sizing rules */
+*,
+*::before,
+*::after {
+ box-sizing: border-box;
+}
+
+/* Remove default padding */
+ul[class],
+ol[class] {
+ padding: 0;
+}
+
+/* Remove default margin */
+body,
+h1,
+h2,
+h3,
+h4,
+p,
+ul[class],
+ol[class],
+li,
+figure,
+figcaption,
+blockquote,
+dl,
+dd {
+ margin: 0;
+}
+
+/* Set core body defaults */
+body {
+ min-height: 100vh;
+ scroll-behavior: smooth;
+ text-rendering: optimizeSpeed;
+ line-height: 1.5;
+}
+
+/* Remove list styles on ul, ol elements with a class attribute */
+ul[class],
+ol[class] {
+ list-style: none;
+}
+
+/* A elements that don't have a class get default styles */
+a:not([class]) {
+ text-decoration-skip-ink: auto;
+}
+
+/* Make images easier to work with */
+img {
+ max-width: 100%;
+ display: block;
+}
+
+/* Natural flow and rhythm in articles by default */
+article > * + * {
+ margin-top: 1em;
+}
+
+/* Inherit fonts for inputs and buttons */
+input,
+button,
+textarea,
+select {
+ font: inherit;
+}
+
+/* Remove all animations and transitions for people that prefer not to see them */
+@media (prefers-reduced-motion: reduce) {
+ * {
+ animation-duration: 0.01ms !important;
+ animation-iteration-count: 1 !important;
+ transition-duration: 0.01ms !important;
+ scroll-behavior: auto !important;
+ }
+}
+/** { box-sizing: content-box; }*/
+body { font-family: arial,sans-serif; font-size: 13px; padding: 0; margin: 0;
+ min-width: 1024px; min-height: 100vh; display: flex; flex-direction: column;
+}
+
+input[type="text"],
+input[type="email"],
+input[type="password"],
+input[type="file"],
+textarea {
+ margin: 0;
+ border: none;
+ border: 1px solid #e0e0e0;
+ box-shadow: inset 1px 1px 0 #f8f8f8;
+ border-radius: 2px;
+ font-size: 13px;
+ padding: 0.3rem 0.5rem 0.3rem 0.5rem;
+ background-color: white;
+}
+
+.page-wrap {
+ display: flex;
+ flex: 1 100%;
+ flex-direction: row;
+}
+
+a { color: #15c; }
+button { font-size: 1rem; }
+header { border-bottom: 1px solid #e0e0e0;}
+header nav,
+footer { padding: 0.5rem 1rem 0.5rem 0.5rem; }
+header nav { min-height: 1rem; }
+/*header nav strong { color: #555; }*/
+header nav > a { margin-right: 1rem; }
+header nav span { color: #757373; }
+header nav div { float: right; }
+header nav div > a{ margin-left: 1rem; }
+header a.active { font-weight: bold; color: black; text-decoration: none; }
+
+
+footer { text-align: right; }
+
+.actions { padding: 0.5rem; }
+
+.container { flex: 1 auto; display: flex; flex-direction: column; flex-wrap: nowrap; min-width: 0; }
+
+
+aside { flex: 0 0 180px; }
+aside a { 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 { flex: 1 100%; display: flex; flex-direction: column; padding: 0.5rem 1rem 0.5rem 0.5rem; min-width: 0; }
+
+aside a.active,
+main { background-color: #f6f6f6; }
+aside a.compose-mail.active { color: #008d47; }
+aside a.compose-mail.active,
+main.compose { background-color: #f6fff6; }
+main.compose { flex: 1 auto; padding: 1rem; }
+main.compose form { flex: 1 auto; display: flex; flex-direction: column; }
+main.compose form label { margin-top: 5px; }
+main.compose form label span { display: inline-block; font-weight: bold; min-width: 100px; }
+main.compose form input { width: 80%; }
+main.compose form textarea { flex: 1 auto; resize: none; margin-top: 1rem; }
+main.compose button[type="submit"] { padding: 0.4rem 1rem 0.35rem; font-weight: bold; }
+main.compose .actions { text-align: right; }
+main table { border-collapse: collapse; width: 100%; border: 1px solid #eee; }
+main table td { white-space: nowrap; padding: 0.3rem; color: #757373;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ max-width: 200px;
+}
+main table tbody tr { border-bottom: 1px solid #eee; }
+main table td a { text-decoration: none; }
+
+
+main table td a:hover { text-decoration: underline; }
+
+main.message pre { flex: 1 auto; padding: 1rem; white-space: pre-wrap; word-break: break-all; background-color: white; border: 1px solid #eee; max-width: 100% }
+main.message table { background-color: white; }
+main.message th { width: 5%;}
+main.message h1 { font-size: 1.2rem; padding: 0.5rem;}
+
+.message-list-subject a { color: #77c; }
+
+
+.message-list-unread .message-list-sender,
+.message-list-unread .message-list-subject,
+.message-list-unread .message-list-date { font-weight: bold; }
+
+.message-list-unread .message-list-sender,
+.message-list-unread .message-list-date { color: black;}
+
+.message-list-date {
+ text-align: right;
+ padding-right: 0.5rem;
+}
+
+.message-list-unread .message-list-subject a { color: #00c; }
+
+.message-list-unread {
+ background-color: white;
+ border-left: 1px solid #f2f2f2;
+ border-right: 1px solid #f2f2f2;
+}
+.message-list-unread td { opacity: 1; }
+
+aside .compose-mail {
+ color: #008d47;
+ font-weight: bold;
+ /*background-color: #f5fcf2;*/
+ text-decoration: none;
+}
+
+main table th {
+ text-align: left;
+ padding: 0.3rem; font-weight: normal;
+}
+
+main table thead {
+ border-bottom: 1px solid #e0e0e0;
+ background-color: white;
+}
+main table tfoot {
+ border-top: 1px solid #e0e0e0;
+ background-color: white;
+}
+
+th form { display: inline; }
+th input[type="text"] {
+ flex: 1;
+ margin: 0;
+}
+th input[type="text"] + button {
+ margin-left: -4rem;
+ width: 4rem;
+ border-top-left-radius: 0;
+ border-bottom-left-radius: 0;
+}
+
+.actions-wrap { display: flex; flex-direction: row; }
+.actions-message { margin-right: 1rem; }
+.actions-pagination { margin-left: 1rem; display: flex; flex-direction: row; }
+.actions-search { flex: 1 auto; display: flex; flex-direction: row; }
+
+
+input[type="submit"],
+.button,
+button,
+.button-link {
+ margin: 0;
+ cursor: pointer;
+ text-decoration: none;
+ text-align: center;
+ display: inline-block;
+ /*padding: 0.4rem 0.4rem 0.35rem;*/
+ padding: 0.3rem 0.3rem 0.25rem;
+ min-width: 1rem;
+ font-size: 12px;
+ border: 1px solid #ddd;
+ border-radius: 3px;
+ vertical-align: middle;
+}
+.button-link {
+ border: 1px solid transparent;
+ text-decoration: none;
+}
+.button-link:hover {
+ text-decoration: underline;
+}
+
+input[type="submit"],
+.button,
+button {
+ background-color: #f5f5f5;
+ border: 1px solid #ddd;
+ color: black;
+}
+
+.button:hover,
+button:hover {
+ background-color: white;
+}
+
+.button:active,
+button:active {
+ color: #ccc;
+ background-color: #f8f8f8;
+}
+
+.message-list-checkbox { display: none; }
diff --git a/themes/alps/compose.html b/themes/alps/compose.html
new file mode 100644
index 0000000..57e5a84
--- /dev/null
+++ b/themes/alps/compose.html
@@ -0,0 +1,40 @@
+{{template "head.html"}}
+{{template "nav.html" .}}
+
+
+<div class="page-wrap">
+ <aside>
+ <a href="/compose" class="compose-mail active">Compose&nbsp;Mail</a>
+ <a href="/mailbox/INBOX">Inbox</a>
+ <a href="/mailbox/Drafts">Drafts</a>
+ <a href="/mailbox/Sent">Sent</a>
+ <a href="/mailbox/Archive">Archive</a>
+ <a href="/mailbox/Junk">Junk</a>
+ <a href="/mailbox/Trash">Trash</a>
+ </aside>
+
+ <div class="container">
+ <main class="compose">
+
+ <form method="post" action="" enctype="multipart/form-data">
+ <input type="hidden" name="in_reply_to" value="{{.Message.InReplyTo}}">
+ <label><span>From</span><input type="email" name="from" id="from" value="{{.Message.From}}" /></label>
+ <label><span>To</span><input type="email" name="to" id="to" value="{{.Message.ToString}}" multiple {{ if not .Message.To }} autofocus{{ end }}/></label>
+ <label><span>Subject</span><input type="text" name="subject" id="subject" value="{{.Message.Subject}}" {{ if .Message.To }} autofocus{{ end }}/></label>
+ <label><span>Attachments</span><input type="file" name="attachments" id="attachments" multiple></label>
+
+ <textarea name="text" class="body">{{.Message.Text}}</textarea>
+
+ <div class="actions">
+ <button type="submit">Send Message</button>
+ &nbsp;&nbsp;
+ <a href="/mailbox/INBOX">Discard</a>
+ </div>
+ </form>
+
+ </main>
+ </div>
+</div>
+
+
+{{template "foot.html"}}
diff --git a/themes/alps/foot.html b/themes/alps/foot.html
new file mode 100644
index 0000000..248e5d4
--- /dev/null
+++ b/themes/alps/foot.html
@@ -0,0 +1,3 @@
+ <script type="text/javascript" src="/themes/alps/assets/helpers.js"></script>
+ </body>
+</html>
diff --git a/themes/alps/head.html b/themes/alps/head.html
new file mode 100644
index 0000000..a6f679f
--- /dev/null
+++ b/themes/alps/head.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <meta name="theme-color" content="#ffffff">
+ <title>Webmail</title>
+ <link rel="stylesheet" href="/themes/alps/assets/style.css">
+ </head>
+ <body>
diff --git a/themes/alps/login.html b/themes/alps/login.html
new file mode 100644
index 0000000..3357142
--- /dev/null
+++ b/themes/alps/login.html
@@ -0,0 +1,26 @@
+{{template "head.html"}}
+ <h1>koushin webmail</h1>
+
+ <form method="post" action="/login">
+ <p>
+ <label>
+ <strong>Username</strong>
+ <br/>
+ <input type="text" name="username" id="username" autofocus />
+ </label>
+ </p>
+ <br/>
+ <p>
+ <label>
+ <strong>Password</strong>
+ <br/>
+ <input type="password" name="password" id="password" />
+ </label>
+ </p>
+ <br/>
+ <p>
+ <button>Sign in</button>
+ </p>
+</form>
+
+{{template "foot.html"}}
diff --git a/themes/alps/mailbox.html b/themes/alps/mailbox.html
new file mode 100644
index 0000000..6d870ba
--- /dev/null
+++ b/themes/alps/mailbox.html
@@ -0,0 +1,66 @@
+{{template "head.html"}}
+{{template "nav.html" . }}
+
+<div class="page-wrap">
+ <aside>
+ <!-- the logo image, dimensions 200x32 may be present or not -->
+ <a href="/compose" class="compose-mail">Compose&nbsp;Mail</a>
+ {{$current := .Mailbox}}
+ {{range .Mailboxes}}
+ <a href="/mailbox/{{.Name | pathescape}}"
+ {{ if eq $current.Name .Name }}class="active"{{ end }}>
+ {{ if eq .Name "INBOX" }}
+ Inbox
+ {{else}}
+ {{.Name}}
+ {{end}}
+ {{ if eq $current.Name .Name }}
+ {{ if $current.Unseen }}({{ $current.Unseen }}){{ end }}
+ {{ end }}
+ </a>
+ {{end}}
+ </aside>
+
+ <div class="container">
+ <form id="messages-form" method="post"></form>
+ <main>
+ <table>
+ <thead>
+ {{ template "messages-header.html" . }}
+ </thead>
+ <tbody>
+ {{range .Messages}}
+ <tr data="{{.Flags}}" class="message-list-item {{ if not (.HasFlag "\\Seen") }}message-list-unread{{ end }}">
+ <td width="1%" class="message-list-checkbox">
+ <input type="checkbox" name="uids" value="{{.Uid}}" form="messages-form">
+ </td>
+ <td width="10%" class="message-list-sender">
+ {{ range .Envelope.From }}
+ {{ if .PersonalName }}
+ {{.PersonalName}}
+ {{ else }}
+ {{.MailboxName}}@{{.HostName}}
+ {{ end }}
+ {{ end }}
+ </td>
+ <td width="80%" class="message-list-subject">
+ <a href="/message/{{$.Mailbox.Name | pathescape}}/{{.Uid}}?part={{.TextPartName}}">
+ {{if .Envelope.Subject}}
+ {{.Envelope.Subject}}
+ {{else}}
+ (No subject)
+ {{end}}
+ </a>
+ </td>
+ <td width="9%" nowrap="" class="message-list-date">{{ .Envelope.Date | formatdate }}</td>
+ </tr>
+ {{ end }}
+ </tbody>
+ <tfoot>
+ {{ template "messages-header.html" .}}
+ </tfoot>
+ </table>
+ </main>
+ </div>
+</div>
+{{template "foot.html"}}
diff --git a/themes/alps/message.html b/themes/alps/message.html
new file mode 100644
index 0000000..38ae948
--- /dev/null
+++ b/themes/alps/message.html
@@ -0,0 +1,154 @@
+{{template "head.html"}}
+{{template "nav.html" .}}
+
+<div class="page-wrap">
+ {{$current := .Mailbox}}
+ <aside>
+ <!-- the logo image, dimensions 200x32 may be present or not -->
+ <a href="/compose" class="compose-mail">Compose&nbsp;Mail</a>
+ <!-- TODO: get mailbox list from render data -->
+ <a href="/mailbox/INBOX" {{ if eq $current.Name "INBOX" }}class="active"{{ end }}>Inbox {{ if $current.Unseen }}({{ $current.Unseen }}){{ end }}</a>
+ <a href="/mailbox/Drafts" {{ if eq $current.Name "Drafts" }}class="active"{{ end }}>Drafts</a>
+ <a href="/mailbox/Sent" {{ if eq $current.Name "Sent" }}class="active"{{ end }}>Sent</a>
+ <a href="/mailbox/Archive" {{ if eq $current.Name "Archive" }}class="active"{{ end }}>Archive {{ if $current.Unseen }}({{ $current.Unseen }}){{ end }}</a>
+ <a href="/mailbox/Junk" {{ if eq $current.Name "Junk" }}class="active"{{ end }}>Junk {{ if $current.Unseen }}({{ $current.Unseen }}){{ end }}</a>
+ <a href="/mailbox/Trash" {{ if eq $current.Name "Trash" }}class="active"{{ end }}>Trash</a>
+ </aside>
+
+ <div class="container">
+ <main class="message">
+
+
+<table>
+ <tr>
+ <tr>
+ <th colspan="2">
+ <div class="actions-wrap">
+ <div class="actions-message">
+ <a href="/mailbox/{{.Mailbox.Name | pathescape}}?page={{.MailboxPage}}" class="button-link">« Back</a>
+ &nbsp;&nbsp;
+
+ {{ if and (ne .Mailbox.Name "Archive") (ne .Mailbox.Name "Drafts") (ne .Mailbox.Name "Sent") }}
+ <form method="post" action="/message/{{.Mailbox.Name | pathescape}}/move">
+ <input type="hidden" name="uids" value="{{.Message.Uid}}">
+ <input type="hidden" name="to" value="Archive">
+ <button>Archive</button>
+ </form>
+ {{ end }}
+
+ {{ if and (ne .Mailbox.Name "INBOX") (ne .Mailbox.Name "Sent") (ne .Mailbox.Name "Drafts") }}
+ <form method="post" action="/message/{{.Mailbox.Name | pathescape}}/move">
+ <input type="hidden" name="uids" value="{{.Message.Uid}}">
+ <input type="hidden" name="to" value="INBOX">
+ <button>
+ {{ if (eq .Mailbox.Name "Junk") }}
+ Not Spam
+ {{ else }}
+ Move to Inbox
+ {{ end }}
+ </button>
+ </form>
+ {{ end }}
+
+ {{ if or (eq .Mailbox.Name "INBOX") (eq .Mailbox.Name "Trash") }}
+ <form method="post" action="/message/{{.Mailbox.Name | pathescape}}/move">
+ <input type="hidden" name="uids" value="{{.Message.Uid}}">
+ &nbsp;&nbsp;
+ <input type="hidden" name="to" value="Junk">
+ <button>Report Spam</button>
+ </form>
+ {{ end }}
+
+ {{ if or (eq .Mailbox.Name "Trash") (eq .Mailbox.Name "Junk") }}
+ <form method="post" action="/message/{{.Mailbox.Name | pathescape}}/delete">
+ <input type="hidden" name="uids" value="{{.Message.Uid}}">
+ <button>Delete Permanently</button>
+ </form>
+ {{ else }}
+ <form method="post" action="/message/{{.Mailbox.Name | pathescape}}/move">
+ <input type="hidden" name="uids" value="{{.Message.Uid}}">
+ &nbsp;&nbsp;
+ <input type="hidden" name="to" value="Trash">
+ <button>Delete</button>
+ </form>
+ {{ end }}
+
+ <form method="post" action="/message/{{.Mailbox.Name | pathescape}}/flag">
+ <input type="hidden" name="uids" value="{{.Message.Uid}}">
+ <input type="hidden" name="flags" value="\Seen">
+ <input type="hidden" name="action" value="remove">
+ <button>Mark&nbsp;Unread</button>
+ </form>
+
+ <form method="post" action="/message/{{.Mailbox.Name | pathescape}}/move">
+ <input type="hidden" name="uids" value="{{.Message.Uid}}">
+ <select name="to">
+ {{range .Mailboxes}}
+ <option value="{{.Name}}" {{if eq .Name $.Mailbox.Name}}selected>Move to...{{else}}>{{.Name}}{{ end }}</option>
+ {{end}}
+ </select>
+ <input type="submit" value="Move">
+ </form>
+ &nbsp;&nbsp;
+
+ <a href="{{.Message.Uid}}/reply?part={{.Part.PathString}}">Reply</a>
+ &nbsp;&nbsp;
+ <a href="{{.Message.Uid}}/forward?part={{.Part.PathString}}">Forward</a>
+ </div>
+ </div>
+ </th>
+</tr>
+
+ </tr>
+ <tr>
+ <th colspan="2">
+ <h1>
+ {{if .Message.Envelope.Subject}}
+ {{.Message.Envelope.Subject}}
+ {{else}}
+ (No subject)
+ {{end}}
+ </h1>
+ </th>
+ </tr>
+
+ <tr>
+ <th>From:</th>
+ <td>{{template "addr-list" .Message.Envelope.From}}</td>
+ </tr>
+ <tr>
+ <th>Date:</th>
+ <td>{{.Message.Envelope.Date | formatdate}}</td>
+ </tr>
+ <tr>
+ <th>To:</th><td>{{template "addr-list" .Message.Envelope.To}}</td>
+ </tr>
+ {{if .Message.Envelope.Cc}}
+ <tr>
+ <th>Cc:</th><td>{{template "addr-list" .Message.Envelope.Cc}}</td>
+ </tr>
+ {{end}}
+ {{if .Message.Envelope.Bcc}}
+ <tr>
+ <th>Bcc:</th>
+ <td>{{template "addr-list" .Message.Envelope.Bcc}}</td>
+ </tr>
+ {{ end }}
+</table>
+
+{{define "addr-list"}}
+ {{range $i, $addr := .}}
+ {{if $i}},{{end}}
+ <strong>{{.PersonalName}}</strong>
+ &lt;<a href="/compose?to={{.Address}}">{{.Address}}</a>&gt;
+ {{end}}
+{{end}}
+
+{{if .View}}
+ {{.View}}
+{{else}}
+ <p>Can't preview this message part.</p>
+ <a href="{{.Message.Uid}}/raw?part={{.Part.PathString}}">Download</a>
+{{end}}
+
+{{template "foot.html"}}
diff --git a/themes/alps/messages-header.html b/themes/alps/messages-header.html
new file mode 100644
index 0000000..9384fb6
--- /dev/null
+++ b/themes/alps/messages-header.html
@@ -0,0 +1,45 @@
+<tr>
+ <th width="1%" class="message-list-checkbox">
+ <input type="checkbox" id="action-checkbox-all"/>
+ </th>
+ <th colspan="3">
+ <div class="actions-wrap">
+ <div class="actions-message">
+ {{ if and (eq .Mailbox.Name "INBOX") (not (eq .Mailbox.Name "Archive")) }}
+ <button form="messages-form" formaction="/message/{{.Mailbox.Name | pathescape}}/move?to=Archive">Archive</button>
+ &nbsp;&nbsp;
+ {{ end }}
+
+ {{ if or (eq .Mailbox.Name "INBOX") (eq .Mailbox.Name "Trash") }}
+ <button form="messages-form" formaction="/message/{{.Mailbox.Name | pathescape}}/move?to=Junk">Report Spam</button>
+ {{ end }}
+
+ {{ if ne .Mailbox.Name "Trash"}}
+ <button form="messages-form" formaction="/message/{{.Mailbox.Name | pathescape}}/move?to=Trash">Delete</button>
+ {{ else }}
+ <button form="messages-form" formaction="/message/{{.Mailbox.Name | pathescape}}/delete">Delete Permanently</button>
+ {{ end }}
+
+ &nbsp;&nbsp;
+ <a href="{{ .GlobalData.Path }}" class="button-link">Refresh</a>
+ </div>
+
+ <form action="" method="post" class="actions-search">
+ <input type="text" name="query" value="{{.Query}}" placeholder="Search messages...">
+ <button>Search</button>
+ </form>
+
+ {{if or (ge .PrevPage 0) (ge .NextPage 0) }}
+ <div class="actions-pagination">
+ {{if ge .PrevPage 0}}
+ {{if ge .PrevPage 1}}<a href="?page=0" class="button-link">«</a>{{ end }}
+ <a href="?page={{.PrevPage}}" class="button-link">‹</a>
+ {{end}}
+ {{if ge .NextPage 0}}
+ <a href="?page={{.NextPage}}" class="button-link">›</a>
+ {{end}}
+ </div>
+ {{ end }}
+ </div>
+ </th>
+</tr>
diff --git a/themes/alps/nav.html b/themes/alps/nav.html
new file mode 100644
index 0000000..820b2e3
--- /dev/null
+++ b/themes/alps/nav.html
@@ -0,0 +1,12 @@
+<header>
+ <nav>
+ <a href="/" class="active">Email</a>
+ <a href="/calendar">Calendar</a>
+ <a href="/contacts">Contacts</a>
+ <div>
+ <span>{{ .GlobalData.Username }}</span>
+ <a href="/settings">Settings</a>
+ <a href="/logout">Sign Out</a>
+ </div>
+ </nav>
+</header>