Browse Source

Use responsive skeleton

Andy Hochhaus 2 years ago
parent
commit
c98c52f2bf
11 changed files with 148 additions and 61 deletions
  1. 1 1
      .gitignore
  2. 4 1
      Makefile
  3. 64 8
      src/www/gss/base.gss
  4. 22 15
      src/www/login.htm
  5. 1 1
      src/www/mail.htm
  6. 3 1
      src/www/not_found.htm
  7. 36 29
      src/www/register.htm
  8. 2 0
      src/www/resource.go
  9. BIN
      src/www/roboto.woff
  10. 1 0
      src/www/skeleton.htm
  11. 14 5
      src/www/www.go

+ 1 - 1
.gitignore

@@ -1,4 +1,4 @@
-# Copyright (c) 2013 Andy Hochhaus. All Rights Reserved.
+# Copyright (c) 2013-2016 Andy Hochhaus. All Rights Reserved.
 # Use of this source code is governed by the "GNU AFFERO GENERAL PUBLIC
 # LICENSE" license that can be found in the LICENSE file. See the AUTHORS file
 # for names of contributors.

+ 4 - 1
Makefile

@@ -17,7 +17,7 @@ GSS := $(wildcard src/www/gss/*.gss) \
 JS := $(wildcard src/www/js/*.js)
 
 all: go $(RDIR)/compiled.css $(RDIR)/compiled.js $(RDIR)/sprite.png \
-	$(RDIR)/favicon.ico
+	$(RDIR)/favicon.ico $(RDIR)/roboto.woff
 
 $(RDIR)/compiled.css: | $(RDIR)
 
@@ -69,6 +69,9 @@ $(RDIR)/sprite.png: src/www/img/sprite.png
 $(RDIR)/favicon.ico: src/www/img/favicon.ico
 	cp src/www/img/favicon.ico $(RDIR)/favicon.ico
 
+$(RDIR)/roboto.woff: src/www/roboto.woff
+	cp src/www/img/favicon.ico $(RDIR)/favicon.ico
+
 lint:
 	find src/mail src/mammoth src/www -name *.go -type f | \
 		xargs -I {} go fmt {}

+ 64 - 8
src/www/gss/base.gss

@@ -1,35 +1,91 @@
 /**
- * Copyright (c) 2013 Andy Hochhaus. All Rights Reserved.
+ * Copyright (c) 2013-2016 Andy Hochhaus. All Rights Reserved.
  * Use of this source code is governed by the "GNU AFFERO GENERAL PUBLIC
  * LICENSE" license that can be found in the LICENSE file. See the AUTHORS file
  * for names of contributors.
  */
 
+@font-face {
+  font-family: 'Roboto';
+  font-style: normal;
+  font-weight: 400;
+  src: local('Roboto'), local('Roboto-Regular'),
+       url(/r/roboto.woff) format('woff');
+}
+
 html, body {
   padding: 0;
   margin: 0;
+  font-family: 'Roboto', sans-serif;
+  color: #111;
+  box-sizing: border-box;
 }
 
 *, *:before, *:after {
-  -moz-box-sizing: border-box;
-  -webkit-box-sizing: border-box;
-  box-sizing: border-box;
+  box-sizing: inherit;
+}
+
+a, a:link, a:visited, a:active {
+  color: #1155cc;
+  text-decoration: none;
 }
 
 input {
   padding: 5px;
 }
 
-.register-form {
+.left {
+  text-align: left;
+}
+
+.register_form {
   background-color: #e3e3e3;
-  padding: 10px;
-  float: right;
+  padding: .5em;
+  border-radius: 3px;
+  margin: 1em 0;
 }
 
 .error {
   color: red;
 }
 
-.width-full {
+.input {
   width: 100%;
+  margin: 0 0 .5em 0;
 }
+
+.input_first {
+  width: 49%;
+  margin: 0 3px .5em 0;
+}
+
+.input_last {
+  width: 49%;
+  margin: 0 0 .5em 3px;
+}
+
+.input_button {
+  width: 100%;
+  color: white;
+  background: #2196f3;
+  border: 0;
+  border-radius: 3px;
+  font-weight: bold;
+}
+
+.outside_page {
+  padding: .5em;
+  width: 100%;
+  max-width: 340px;
+  margin: 0 auto;
+  text-align: center;
+}
+
+footer {
+  color: #555;
+}
+
+.outside_footer {
+  padding: 1em 0;
+  font-size: .75em;
+}

+ 22 - 15
src/www/login.htm

@@ -6,20 +6,27 @@ of contributors.
 */}}
 
 {{define "content"}}
-<form method="post" class="{{css "register-form"}}">
-  <noscript>
-    <div class="{{css "error"}}">JavaScript is required.</div>
-  </noscript>
-  <div id="unsupported" class="{{css "error"}}"></div>
-  <div>
-    <input name="email" id="email"{{if .Email}} value="{{.Email}}"{{end}} class="{{css "width-full"}}" placeholder="Email">
-  </div>
-  <div>
-    <input type="password" name="password" id="password" class="{{css "width-full"}}" placeholder="Password">
+<div class="{{css "outside_page"}}">
+  <header>
+    <a href="/" class="{{css "goog-inline-block"}} {{css "mammoth-logo"}}"></a>
+  </header>
+  <form method="post" class="{{css "register_form"}}">
+    <noscript>
+      <div class="{{css "error"}}">JavaScript is required.</div>
+    </noscript>
+    <div id="unsupported" class="{{css "error"}}"></div>
+    <div>
+      <input name="email" id="email"{{if .Email}} value="{{.Email}}"{{end}} class="{{css "input"}}" placeholder="Email">
+    </div>
+    <div>
+      <input type="password" name="password" id="password" class="{{css "input"}}" placeholder="Password">
     {{if .Error}}<div class="{{css "error"}}">{{.Error}}</div>{{end}}
-  </div>
-  <input type="submit" id="login" name="login" value="Sign in" disabled>
-</form>
-<a href="/" class="{{css "goog-inline-block"}} {{css "mammoth-logo"}}"></a><br>
-<a href="/register">Register for account</a>
+    </div>
+    <input class="{{css "input_button"}}" type="submit" id="login" name="login" value="Sign in" disabled>
+  </form>
+  <a href="/register">Create account</a>
+  <footer class="{{css "outside_footer"}}">
+    &copy; 2016 Mammoth Mail
+  </footer>
+</div>
 {{end}}

+ 1 - 1
src/www/mail.htm

@@ -6,7 +6,7 @@ of contributors.
 */}}
 
 {{define "content"}}
-<div>
+<div class="{{css "outside_page"}}">
   Loading {{.Email}}...
 </div>
 {{end}}

+ 3 - 1
src/www/not_found.htm

@@ -6,5 +6,7 @@ of contributors.
 */}}
 
 {{define "content"}}
-The page you're looking for could not be found.
+<div class="{{css "outside_page"}}">
+  The page you're looking for could not be found.
+</div>
 {{end}}

+ 36 - 29
src/www/register.htm

@@ -6,33 +6,40 @@ of contributors.
 */}}
 
 {{define "content"}}
-<form method="post" class="{{css "register-form"}}">
-  <noscript>
-    <div class="{{css "error"}}">JavaScript is required.</div>
-  </noscript>
-  <div id="unsupported" class="{{css "error"}}"></div>
-  <div>
-    <b>Name</b><br>
-    <input name="first" id="first"{{if .First}} value="{{.First}}"{{end}} placeholder="First">
-    <input name="last" id="last"{{if .Last}} value="{{.Last}}"{{end}} placeholder="Last">
-    {{if .NameError}}<div class="{{css "error"}}">{{.NameError}}</div>{{end}}
-  </div>
-  <div>
-    <b>Your current email address</b><br>
-    <input name="email" id="email"{{if .Email}} value="{{.Email}}"{{end}} class="{{css "width-full"}}">
-    {{if .EmailError}}<div class="{{css "error"}}">{{.EmailError}}</div>{{end}}
-  </div>
-  <div>
-    <b>Create a password</b><br>
-    <input type="password" name="password" id="password"{{if .Password}} value="{{.Password}}"{{end}} class="{{css "width-full"}}">
-    {{if .PasswordError}}<div class="{{css "error"}}">{{.PasswordError}}</div>{{end}}
-  </div>
-  <div>
-    <b>Confirm your password</b><br>
-    <input type="password" name="password_confirm" id="password_confirm"{{if .PasswordConfirm}} value="{{.PasswordConfirm}}"{{end}} class="{{css "width-full"}}">
-    {{if .PasswordConfirmError}}<div class="{{css "error"}}">{{.PasswordConfirmError}}</div>{{end}}
-  </div>
-  <input type="submit" name="register" id="register" value="Create Account" disabled>
-</form>
-<a href="/" class="{{css "goog-inline-block"}} {{css "mammoth-logo"}}"></a><br>
+<div class="{{css "outside_page"}}">
+  <header>
+    <a href="/" class="{{css "goog-inline-block"}} {{css "mammoth-logo"}}"></a>
+  </header>
+  <form method="post" class="{{css "register_form"}}">
+    <noscript>
+      <div class="{{css "error"}}">JavaScript is required.</div>
+    </noscript>
+    <div id="unsupported" class="{{css "error"}}"></div>
+    <div>
+      <div class="{{css "left"}}"><b>Name</b></div>
+      <input name="first" id="first"{{if .First}} value="{{.First}}"{{end}} placeholder="First" class="{{css "input_first"}}">
+      <input name="last" id="last"{{if .Last}} value="{{.Last}}"{{end}} placeholder="Last" class="{{css "input_last"}}">
+      {{if .NameError}}<div class="{{css "error"}}">{{.NameError}}</div>{{end}}
+    </div>
+    <div>
+      <div class="{{css "left"}}"><b>Your current email address</b></div>
+      <input name="email" id="email"{{if .Email}} value="{{.Email}}"{{end}} class="{{css "input"}}">
+      {{if .EmailError}}<div class="{{css "error"}}">{{.EmailError}}</div>{{end}}
+    </div>
+    <div>
+      <div class="{{css "left"}}"><b>Create a password</b></div>
+      <input type="password" name="password" id="password"{{if .Password}} value="{{.Password}}"{{end}} class="{{css "input"}}">
+      {{if .PasswordError}}<div class="{{css "error"}}">{{.PasswordError}}</div>{{end}}
+    </div>
+    <div>
+      <div class="{{css "left"}}"><b>Confirm your password</b></div>
+      <input type="password" name="password_confirm" id="password_confirm"{{if .PasswordConfirm}} value="{{.PasswordConfirm}}"{{end}} class="{{css "input"}}">
+      {{if .PasswordConfirmError}}<div class="{{css "error"}}">{{.PasswordConfirmError}}</div>{{end}}
+    </div>
+    <input class="{{css "input_button"}}" type="submit" name="register" id="register" value="Create Account" disabled>
+  </form>
+  <footer class="{{css "outside_footer"}}">
+    &copy; 2016 Mammoth Mail
+  </footer>
+</div>
 {{end}}

+ 2 - 0
src/www/resource.go

@@ -174,6 +174,8 @@ func setContentType(w http.ResponseWriter, r *http.Request) {
 		header.Set("Content-Type", "text/javascript")
 	case "png":
 		header.Set("Content-Type", "image/png")
+	case "woff":
+		header.Set("Content-Type", "application/font-woff")
 	}
 }
 

BIN
src/www/roboto.woff


+ 1 - 0
src/www/skeleton.htm

@@ -11,6 +11,7 @@ of contributors.
   <head>
     <meta charset="utf-8">
     <title>Mammoth Mail</title>
+    <meta name="viewport" content="width=device-width, user-scalable=no">
     <link rel="stylesheet" href="{{res "/r/compiled.css"}}">
     <link rel="shortcut icon" href="{{res "/r/favicon.ico"}}" sizes="16x16 32x32 48x48 64x64 128x128">
   </head>

+ 14 - 5
src/www/www.go

@@ -1,4 +1,4 @@
-// Copyright (c) 2013-2014 Andy Hochhaus. All Rights Reserved.
+// Copyright (c) 2013-2016 Andy Hochhaus. All Rights Reserved.
 // Use of this source code is governed by the "GNU AFFERO GENERAL PUBLIC
 // LICENSE" license that can be found in the LICENSE file. See the AUTHORS file
 // for names of contributors.
@@ -16,14 +16,13 @@ import (
 	"mail"
 	"net/http"
 	"strings"
+	"time"
 	"unicode"
 )
 
 const (
-	// TODO(hochhaus): Remove 'unsafe-inline' from style-src by removing inline
-	// CSS usage inside closure-library widgets.
 	csp = "default-src 'none'; script-src 'self'; img-src 'self'; " +
-		"connect-src 'self'; style-src 'self' 'unsafe-inline'; " +
+		"connect-src 'self'; style-src 'self'; font-src 'self'; " +
 		"report-uri /debug/errors; " +
 		"sandbox allow-forms allow-popups allow-same-origin allow-scripts;"
 )
@@ -231,7 +230,17 @@ func Serve() {
 		go serveRedirect()
 	}
 	log.Printf("Serving on: %s", mail.Config.HTTPHost)
-	server := &http.Server{Addr: mail.Config.HTTPHost, Handler: extHTTP}
+	server := &http.Server{
+		Addr:    mail.Config.HTTPHost,
+		Handler: extHTTP,
+		// {Read,Write}Timeout are passed to the underlying TCP connection and are
+		// not HTTP request aware. To allow HTTP Keep-Alive and HTTP/2 to function
+		// correctly, these timeouts must be large enough for the maximum length of
+		// a single TCP connection. Per-handler timeouts are configured with
+		// http.TimeoutHandler.
+		ReadTimeout:  30 * time.Minute,
+		WriteTimeout: 30 * time.Minute,
+	}
 	err := server.ListenAndServeTLS(
 		mail.Config.CertChainFile, mail.Config.TLSKeyFile)
 	if err != nil {