initial commit
This commit is contained in:
127
app/mailadm/layouts/main.go.tpl
Normal file
127
app/mailadm/layouts/main.go.tpl
Normal file
@@ -0,0 +1,127 @@
|
||||
{{define "main"}}
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="Mail Admin.">
|
||||
|
||||
<title>mailadm</title>
|
||||
|
||||
<script src="/htmx.org@1.9.2.js" integrity="sha384-L6OqL9pRWyyFU3+/bjdSri+iIphTN/bvYyM37tICVyOJkWZLpP2vGn6VUEXgzg6h" crossorigin="anonymous"></script>
|
||||
<link rel="stylesheet" href="/pure-min@3.0.0.css" integrity="sha384-X38yfunGUhNzHpBaEBsWLO+A0HDYOQi8ufWDkZ0k9e0eXz/tH3II7uKZ9msv++Ls" crossorigin="anonymous">
|
||||
<link rel="stylesheet" href="/layout.css" crossorigin="anonymous">
|
||||
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
|
||||
<link rel="manifest" href="/site.webmanifest">
|
||||
</head>
|
||||
|
||||
<body id="layout" class="content pure-g">
|
||||
|
||||
<nav id="nav" class="pure-u">
|
||||
<input id="menu-toggle" type="checkbox" />
|
||||
<label class='menu-button-container' for="menu-toggle">
|
||||
<div class='menu-button'></div>
|
||||
|
||||
<div class="nav-inner">
|
||||
<button class="primary-button pure-button">Compose</button>
|
||||
|
||||
<div class="pure-menu">
|
||||
<ul class="pure-menu-list">
|
||||
<li class="pure-menu-item"><a href="#" class="pure-menu-link">Inbox <span class="email-count">(2)</span></a></li>
|
||||
<li class="pure-menu-item"><a href="#" class="pure-menu-link">Important</a></li>
|
||||
<li class="pure-menu-item"><a href="#" class="pure-menu-link">Sent</a></li>
|
||||
<li class="pure-menu-item"><a href="#" class="pure-menu-link">Drafts</a></li>
|
||||
<li class="pure-menu-item"><a href="#" class="pure-menu-link">Trash</a></li>
|
||||
<li class="pure-menu-heading">Labels</li>
|
||||
<li class="pure-menu-item"><a href="#" class="pure-menu-link"><span class="email-label-personal"></span>Personal</a></li>
|
||||
<li class="pure-menu-item"><a href="#" class="pure-menu-link"><span class="email-label-work"></span>Work</a></li>
|
||||
<li class="pure-menu-item"><a href="#" class="pure-menu-link"><span class="email-label-travel"></span>Travel</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div id="list" class="pure-u-1">
|
||||
<div class="email-item email-item-selected pure-g">
|
||||
<div class="pure-u">
|
||||
<img width="64" height="64" alt="Tilo Mitra's avatar" class="email-avatar" src="/img/common/tilo-avatar.png">
|
||||
</div>
|
||||
|
||||
<div class="pure-u-3-4">
|
||||
<h5 class="email-name">Tilo Mitra</h5>
|
||||
<h4 class="email-subject">Hello from Toronto</h4>
|
||||
<p class="email-desc">
|
||||
Hey, I just wanted to check in with you from Toronto. I got here earlier today.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="email-item email-item-unread pure-g">
|
||||
<div class="pure-u">
|
||||
<img width="64" height="64" alt="Eric Ferraiuolo's avatar" class="email-avatar" src="/img/common/ericf-avatar.png">
|
||||
</div>
|
||||
|
||||
<div class="pure-u-3-4">
|
||||
<h5 class="email-name">Eric Ferraiuolo</h5>
|
||||
<h4 class="email-subject">Re: Pull Requests</h4>
|
||||
<p class="email-desc">
|
||||
Hey, I had some feedback for pull request #51. We should center the menu so it looks better on mobile.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="email-item pure-g">
|
||||
<div class="pure-u">
|
||||
<img width="64" height="64" alt="Reid Burke's avatar" class="email-avatar" src="/img/common/reid-avatar.png">
|
||||
</div>
|
||||
|
||||
<div class="pure-u-3-4">
|
||||
<h5 class="email-name">Reid Burke</h5>
|
||||
<h4 class="email-subject">Re: Design Language</h4>
|
||||
<p class="email-desc">
|
||||
Excepteur sint occaecat cupidatat non proident, sunt in culpa.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="email-item pure-g">
|
||||
<div class="pure-u">
|
||||
<img width="64" height="64" alt="Yahoo! Finance's Avatar" class="email-avatar" src="/img/common/yfinance-avatar.png">
|
||||
</div>
|
||||
|
||||
<div class="pure-u-3-4">
|
||||
<h5 class="email-name">Yahoo! Finance</h5>
|
||||
<h4 class="email-subject">How to protect your finances from winter storms</h4>
|
||||
<p class="email-desc">
|
||||
Mauris tempor mi vitae sem aliquet pharetra. Fusce in dui purus, nec malesuada mauris.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="email-item pure-g">
|
||||
<div class="pure-u">
|
||||
<img width="64" height="64" alt="Yahoo! News' avatar" class="email-avatar" src="/img/common/ynews-avatar.png">
|
||||
</div>
|
||||
|
||||
<div class="pure-u-3-4">
|
||||
<h5 class="email-name">Yahoo! News</h5>
|
||||
<h4 class="email-subject">Summary for April 3rd, 2021</h4>
|
||||
<p class="email-desc">
|
||||
We found 10 news articles that you may like.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<secton id="main" class="pure-u-1">
|
||||
{{template "content" .}}
|
||||
</section>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
{{end}}
|
||||
74
app/mailadm/mailadm.go
Normal file
74
app/mailadm/mailadm.go
Normal file
@@ -0,0 +1,74 @@
|
||||
package mailadm
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"io/fs"
|
||||
"log"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"text/template"
|
||||
|
||||
"go.sour.is/pkg/lg"
|
||||
)
|
||||
|
||||
var (
|
||||
//go:embed pages/* layouts/*
|
||||
files embed.FS
|
||||
templates map[string]*template.Template
|
||||
)
|
||||
|
||||
type mailadm struct{}
|
||||
|
||||
func New() *mailadm {
|
||||
return &mailadm{}
|
||||
}
|
||||
|
||||
func (s *mailadm) RegisterHTTP(mux *http.ServeMux) {
|
||||
mux.Handle("/mailadm/", lg.Htrace(s, "mailadm"))
|
||||
|
||||
s.loadTemplates()
|
||||
}
|
||||
func (s *mailadm) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
if r.URL.Path == "/mailadm/clicked" {
|
||||
templates["edit.go.tpl"].Execute(w, r.URL.Query())
|
||||
return
|
||||
}
|
||||
|
||||
templates["home.go.tpl"].Execute(w, nil)
|
||||
}
|
||||
|
||||
var funcMap = map[string]any{
|
||||
"addone": func(s string) string {
|
||||
if i, err := strconv.Atoi(s); err == nil {
|
||||
return strconv.Itoa(i + 1)
|
||||
}
|
||||
return s
|
||||
},
|
||||
}
|
||||
|
||||
func (s *mailadm) loadTemplates() error {
|
||||
if templates != nil {
|
||||
return nil
|
||||
}
|
||||
templates = make(map[string]*template.Template)
|
||||
tmplFiles, err := fs.ReadDir(files, "pages")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, tmpl := range tmplFiles {
|
||||
if tmpl.IsDir() {
|
||||
continue
|
||||
}
|
||||
pt := template.New(tmpl.Name())
|
||||
pt.Funcs(funcMap)
|
||||
pt, err = pt.ParseFS(files, "pages/"+tmpl.Name(), "layouts/*.go.tpl")
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
|
||||
return err
|
||||
}
|
||||
templates[tmpl.Name()] = pt
|
||||
}
|
||||
return nil
|
||||
}
|
||||
3
app/mailadm/pages/edit.go.tpl
Normal file
3
app/mailadm/pages/edit.go.tpl
Normal file
@@ -0,0 +1,3 @@
|
||||
<button hx-get="/mailadm/clicked?times={{ addone ( .Get "times" ) }}" hx-swap="outerHTML">
|
||||
Clicked {{ .Get "times" }} times!
|
||||
</button>
|
||||
8
app/mailadm/pages/home.go.tpl
Normal file
8
app/mailadm/pages/home.go.tpl
Normal file
@@ -0,0 +1,8 @@
|
||||
{{template "main" .}}
|
||||
|
||||
{{define "content"}}
|
||||
<h2>What is this?</h2>
|
||||
<button hx-get="/mailadm/clicked?times=1" hx-swap="outerHTML">
|
||||
Click Me!
|
||||
</button>
|
||||
{{end}}
|
||||
6
app/root/assets/about.txt
Normal file
6
app/root/assets/about.txt
Normal file
@@ -0,0 +1,6 @@
|
||||
This favicon was generated using the following graphics from Twitter Twemoji:
|
||||
|
||||
- Graphics Title: 2699.svg
|
||||
- Graphics Author: Copyright 2020 Twitter, Inc and other contributors (https://github.com/twitter/twemoji)
|
||||
- Graphics Source: https://github.com/twitter/twemoji/blob/master/assets/svg/2699.svg
|
||||
- Graphics License: CC-BY 4.0 (https://creativecommons.org/licenses/by/4.0/)
|
||||
BIN
app/root/assets/android-chrome-192x192.png
Normal file
BIN
app/root/assets/android-chrome-192x192.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 10 KiB |
BIN
app/root/assets/android-chrome-512x512.png
Normal file
BIN
app/root/assets/android-chrome-512x512.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 35 KiB |
BIN
app/root/assets/apple-touch-icon.png
Normal file
BIN
app/root/assets/apple-touch-icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 9.5 KiB |
BIN
app/root/assets/favicon-16x16.png
Normal file
BIN
app/root/assets/favicon-16x16.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 539 B |
BIN
app/root/assets/favicon-32x32.png
Normal file
BIN
app/root/assets/favicon-32x32.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.2 KiB |
BIN
app/root/assets/favicon.ico
Normal file
BIN
app/root/assets/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
1
app/root/assets/htmx.org@1.9.2.js
Normal file
1
app/root/assets/htmx.org@1.9.2.js
Normal file
File diff suppressed because one or more lines are too long
26
app/root/assets/index.html
Normal file
26
app/root/assets/index.html
Normal file
@@ -0,0 +1,26 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>tools</title>
|
||||
|
||||
<script src="/htmx.org@1.9.2.js" integrity="sha384-L6OqL9pRWyyFU3+/bjdSri+iIphTN/bvYyM37tICVyOJkWZLpP2vGn6VUEXgzg6h" crossorigin="anonymous"></script>
|
||||
<link rel="stylesheet" href="/pure-min.css" integrity="sha384-X38yfunGUhNzHpBaEBsWLO+A0HDYOQi8ufWDkZ0k9e0eXz/tH3II7uKZ9msv++Ls" crossorigin="anonymous">
|
||||
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
|
||||
<link rel="manifest" href="/site.webmanifest">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<nav>
|
||||
<ol>
|
||||
<li><a href="/mailadm/">mailadm</a></li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
274
app/root/assets/layout.css
Normal file
274
app/root/assets/layout.css
Normal file
@@ -0,0 +1,274 @@
|
||||
/*
|
||||
* -- BASE STYLES --
|
||||
* Most of these are inherited from Base, but I want to change a few.
|
||||
*/
|
||||
body {
|
||||
color: #333;
|
||||
}
|
||||
|
||||
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
color: #1b98f8;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* -- HELPER STYLES --
|
||||
* Over-riding some of the .pure-button styles to make my buttons look unique
|
||||
*/
|
||||
.primary-button,
|
||||
.secondary-button {
|
||||
-webkit-box-shadow: none;
|
||||
-moz-box-shadow: none;
|
||||
box-shadow: none;
|
||||
border-radius: 20px;
|
||||
}
|
||||
.primary-button {
|
||||
color: #fff;
|
||||
background: #1b98f8;
|
||||
margin: 1em 0;
|
||||
}
|
||||
.secondary-button {
|
||||
background: #fff;
|
||||
border: 1px solid #ddd;
|
||||
color: #666;
|
||||
padding: 0.5em 2em;
|
||||
font-size: 80%;
|
||||
}
|
||||
|
||||
/*
|
||||
* -- LAYOUT STYLES --
|
||||
* This layout consists of three main elements, `#nav` (navigation bar), `#list` (email list), and `#main` (email content). All 3 elements are within `#layout`
|
||||
*/
|
||||
#layout, #nav, #list, #main {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/* Make the navigation 100% width on phones */
|
||||
#nav {
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
position: relative;
|
||||
background: rgb(37, 42, 58);
|
||||
text-align: center;
|
||||
}
|
||||
/* Show the "Menu" button on phones */
|
||||
#nav .nav-menu-button {
|
||||
display: block;
|
||||
top: 0.5em;
|
||||
right: 0.5em;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
/* When "Menu" is clicked, the navbar should be 80% height */
|
||||
#nav.active {
|
||||
height: 80%;
|
||||
}
|
||||
/* Don't show the navigation items... */
|
||||
.nav-inner {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* ...until the "Menu" button is clicked */
|
||||
#nav.active .nav-inner {
|
||||
display: block;
|
||||
padding: 2em 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* -- NAV BAR STYLES --
|
||||
* Styling the default .pure-menu to look a little more unique.
|
||||
*/
|
||||
#nav .pure-menu {
|
||||
background: transparent;
|
||||
border: none;
|
||||
text-align: left;
|
||||
}
|
||||
#nav .pure-menu-link:hover,
|
||||
#nav .pure-menu-link:focus {
|
||||
background: rgb(55, 60, 90);
|
||||
}
|
||||
#nav .pure-menu-link {
|
||||
color: #fff;
|
||||
margin-left: 0.5em;
|
||||
}
|
||||
#nav .pure-menu-heading {
|
||||
border-bottom: none;
|
||||
font-size:110%;
|
||||
color: rgb(75, 113, 151);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* -- EMAIL STYLES --
|
||||
* Styles relevant to the email messages, labels, counts, and more.
|
||||
*/
|
||||
.email-count {
|
||||
color: rgb(75, 113, 151);
|
||||
}
|
||||
|
||||
.email-label-personal,
|
||||
.email-label-work,
|
||||
.email-label-travel {
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
display: inline-block;
|
||||
margin-right: 0.5em;
|
||||
border-radius: 3px;
|
||||
}
|
||||
.email-label-personal {
|
||||
background: #ffc94c;
|
||||
}
|
||||
.email-label-work {
|
||||
background: #41ccb4;
|
||||
}
|
||||
.email-label-travel {
|
||||
background: #40c365;
|
||||
}
|
||||
|
||||
|
||||
/* Email Item Styles */
|
||||
.email-item {
|
||||
padding: 0.9em 1em;
|
||||
border-bottom: 1px solid #ddd;
|
||||
border-left: 6px solid transparent;
|
||||
}
|
||||
.email-avatar {
|
||||
border-radius: 3px;
|
||||
margin-right: 0.5em;
|
||||
}
|
||||
.email-name,
|
||||
.email-subject {
|
||||
margin: 0;
|
||||
}
|
||||
.email-name {
|
||||
text-transform: uppercase;
|
||||
color: #999;
|
||||
}
|
||||
.email-desc {
|
||||
font-size: 80%;
|
||||
margin: 0.4em 0;
|
||||
}
|
||||
|
||||
.email-item-selected {
|
||||
background: #eee;
|
||||
}
|
||||
.email-item-unread {
|
||||
border-left: 6px solid #1b98f8;
|
||||
}
|
||||
|
||||
/* Email Content Styles */
|
||||
.email-content-header, .email-content-body, .email-content-footer {
|
||||
padding: 1em 2em;
|
||||
}
|
||||
.email-content-header {
|
||||
border-bottom: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.email-content-title {
|
||||
margin: 0.5em 0 0;
|
||||
}
|
||||
.email-content-subtitle {
|
||||
font-size: 1em;
|
||||
margin: 0;
|
||||
font-weight: normal;
|
||||
}
|
||||
.email-content-subtitle span {
|
||||
color: #999;
|
||||
}
|
||||
.email-content-controls {
|
||||
margin-top: 2em;
|
||||
text-align: right;
|
||||
}
|
||||
.email-content-controls .secondary-button {
|
||||
margin-bottom: 0.3em;
|
||||
}
|
||||
|
||||
.email-avatar {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* -- TABLET (AND UP) MEDIA QUERIES --
|
||||
* On tablets and other medium-sized devices, we want to customize some
|
||||
* of the mobile styles.
|
||||
*/
|
||||
@media (min-width: 40em) {
|
||||
|
||||
/* Move the layout over so we can fit the nav + list in on the left */
|
||||
#layout {
|
||||
padding-left:500px; /* "left col (nav + list)" width */
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* These are position:fixed; elements that will be in the left 500px of the screen */
|
||||
#nav, #list {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
overflow: auto;
|
||||
}
|
||||
#nav {
|
||||
margin-left:-500px; /* "left col (nav + list)" width */
|
||||
width:150px;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/* Show the menu items on the larger screen */
|
||||
.nav-inner {
|
||||
display: block;
|
||||
padding: 2em 0;
|
||||
}
|
||||
|
||||
/* Hide the "Menu" button on larger screens */
|
||||
#nav .nav-menu-button {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#list {
|
||||
margin-left: -350px;
|
||||
width: 100%;
|
||||
height: 33%;
|
||||
border-bottom: 1px solid #ddd;
|
||||
}
|
||||
|
||||
#main {
|
||||
position: fixed;
|
||||
top: 33%;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 150px;
|
||||
overflow: auto;
|
||||
width: auto; /* so that it's not 100% */
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* -- DESKTOP (AND UP) MEDIA QUERIES --
|
||||
* On desktops and other large-sized devices, we want to customize some
|
||||
* of the mobile styles.
|
||||
*/
|
||||
@media (min-width: 60em) {
|
||||
|
||||
/* This will take up the entire height, and be a little thinner */
|
||||
#list {
|
||||
margin-left: -350px;
|
||||
width:350px;
|
||||
height: 100%;
|
||||
border-right: 1px solid #ddd;
|
||||
}
|
||||
|
||||
/* This will now take up it's own column, so don't need position: fixed; */
|
||||
#main {
|
||||
position: static;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
11
app/root/assets/pure-min@3.0.0.css
Normal file
11
app/root/assets/pure-min@3.0.0.css
Normal file
File diff suppressed because one or more lines are too long
1
app/root/assets/site.webmanifest
Normal file
1
app/root/assets/site.webmanifest
Normal file
@@ -0,0 +1 @@
|
||||
{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"}
|
||||
27
app/root/root.go
Normal file
27
app/root/root.go
Normal file
@@ -0,0 +1,27 @@
|
||||
package root
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"io/fs"
|
||||
"net/http"
|
||||
|
||||
"go.sour.is/pkg/lg"
|
||||
)
|
||||
|
||||
var (
|
||||
//go:embed assets/*
|
||||
files embed.FS
|
||||
)
|
||||
|
||||
type root struct{}
|
||||
|
||||
func New() *root {
|
||||
return &root{}
|
||||
}
|
||||
|
||||
func (s *root) RegisterHTTP(mux *http.ServeMux) {
|
||||
a, _ := fs.Sub(files, "assets")
|
||||
assets := http.StripPrefix("/", http.FileServer(http.FS(a)))
|
||||
|
||||
mux.Handle("/", lg.Htrace(assets, "mailadm-assets"))
|
||||
}
|
||||
Reference in New Issue
Block a user