~gpanders/garchive

85d046547829084521e986793c037b30e670165b — Greg Anders 4 months ago a50c9a9
Front end style and layout updates
3 files changed, 148 insertions(+), 33 deletions(-)

M index.html
M main.go
M static/style.css
M index.html => index.html +43 -12
@@ 1,15 1,46 @@
<!DOCTYPE html>
<html>
  <head>
    <title>Archive</title>
    <link rel="stylesheet" type="text/css" href="/static/style.css">
  </head>
  <body>
    <h1>Archive</h1>
    <ul>
      {{ range . }}
      <li><a href="/ar/{{.Url}}">{{.Title}}</a></li>
      {{ end }}
    </ul>
  </body>
	<head>
		<title>Archive</title>
		<meta name="viewport" content="width=device-width, initial-scale=1.0">
		<link rel="stylesheet" type="text/css" href="/static/style.css">
	</head>
	<body class="light">
		<main>
			<section id="sidebar">
				<h1><a href="/">Archive</a></h1>
				<small><em>{{ len . }} items</em></small>
				<form class="search">
					<input type="text" name="search">
					<button>Search</button>
				</form>
				<div class="themes">
					<button class="light">Light</button>
					<button class="dark">Dark</button>
				</div>
			</section>
			<section class="links">
				<ul>
					{{ range . }}
					<li>
						<p><a class="link" href="/ar/{{.Path}}">{{.Title}}</a></p>
						<small>{{.Domain}}</small>
					</li>
					{{ end }}
				</ul>
			</section>
		</main>
		<script type="text/javascript">
			(function(d) {
				d.querySelectorAll('.themes')[0].childNodes.forEach((elem) => {
					if (elem.nodeName === "BUTTON") {
						elem.addEventListener('click', (e) => {
							e.preventDefault();
							d.body.className = elem.className;
						});
					}
				})
			})(document)
		</script>
	</body>
</html>

M main.go => main.go +18 -8
@@ 9,19 9,21 @@ import (
	"net/http"
	"os"
	"regexp"
	"strings"
)

type Link struct {
	Title string
	Url   string
	Title  string
	Path   string
	Domain string
}

var links string
var protocolRe = regexp.MustCompile("^(?:http|https|ftp)://")

func serveIndex(w http.ResponseWriter, r *http.Request) {
	url := r.URL.Path[1:]
	if url != "" {
	path := r.URL.Path[1:]
	if path != "" {
		http.Redirect(w, r, "/", http.StatusSeeOther)
		return
	}


@@ 32,7 34,8 @@ func serveIndex(w http.ResponseWriter, r *http.Request) {
		return
	}

	p, err := getLinks()
	search := r.URL.Query().Get("search")
	p, err := getLinks(search)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return


@@ 41,7 44,7 @@ func serveIndex(w http.ResponseWriter, r *http.Request) {
	t.Execute(w, p)
}

func getLinks() ([]Link, error) {
func getLinks(query string) ([]Link, error) {
	f, err := os.Open(links)
	if err != nil {
		return nil, err


@@ 57,10 60,17 @@ func getLinks() ([]Link, error) {
		return nil, err
	}

	re := regexp.MustCompile(query)

	for _, row := range rows {
		title := row[0]
		url := protocolRe.ReplaceAllLiteralString(row[1], "")
		links = append(links, Link{Title: title, Url: url})
		path := protocolRe.ReplaceAllLiteralString(row[1], "")
		if !re.MatchString(title) && !re.MatchString(path) {
			continue
		}

		domain := strings.SplitN(path, "/", 2)[0]
		links = append(links, Link{Title: title, Path: path, Domain: domain})
	}

	return links, nil

M static/style.css => static/style.css +87 -13
@@ 1,20 1,94 @@
body {
    font-family: "Helvetica", "Arial", sans-serif;
    line-height: 1.5;
    margin: 0 auto;
    max-width: 80ch;
    padding: 2ch;
	font-family: "Helvetica", "Arial", sans-serif;
	line-height: 1.5;
	margin: auto;
	height: 100vh;
	border-top: 5px solid #747369;
	box-sizing: border-box;
}
body.light {
	color: #2d2d2d;
}
body.dark {
	color: #d3d0c8;
	background: #2d2d2d;
}
h1,
h2,
h3,
h4 {
	margin: 0;
}
main {
	display: flex;
	justify-content: space-around;
	height: 100%;
	max-width: 72rem;
	margin: auto;
}
section {
	display: flex;
	flex-direction: column;
	padding: 2em;
}
input {
	padding: 0.2em;
}
.links {
	max-height: 100vh;
	overflow-y: auto;
	flex-grow: 1;
}
.search {
	display: flex;
	flex-wrap: wrap;
}
.search input {
	flex: 1 1 100%;
	margin: 1em 0;
}
ul {
    margin: 0;
    padding: 0;
    list-style: none;
	margin: 0;
	padding: 0;
	list-style: none;
}
ul > li {
    padding: 0.5em 0;
    margin-bottom: 1em;
	padding: 0;
	margin: 0 0 1em 0;
}

li > p {
	margin: 0;
}
a {
	text-decoration: none;
	color: inherit;
}
small {
	color: #747369;
}
button {
	cursor: pointer;
}
.link {
	font-weight: 500;
}
.themes {
	display: flex;
	justify-content: space-between;
	margin: 1em 0;
}
.themes button {
	border: 1px solid #747369;
	padding: 0.25em;
	flex-grow: 1;
	max-width: 45%;
}
.themes button.light {
	color: #2d2d2d;
	background: white;
}
li > a {
    text-decoration: none;
    color: inherit;
.themes button.dark {
	color: #d3d0c8;
	background: #2d2d2d;
}