initial commit

This commit is contained in:
Timon Ringwald 2022-05-08 14:32:13 +02:00
commit d6a2316b16
12 changed files with 502 additions and 0 deletions

127
bookmark.go Normal file
View File

@ -0,0 +1,127 @@
package main
import "sort"
var (
Bookmarks = []Bookmark{
{
Title: "DuckDuckGo",
Image: "https://duckduckgo.com/assets/logo_homepage.alt.v108.svg",
Color: "#1c1c1c",
Link: "https://duckduckgo.com/",
},
{
Title: "Postbank",
Image: "https://meine.postbank.de/bundles/@pbs/patternlib_pb/lib/runtime/assets/images/logo-claim.svg",
Color: "#ffcc00",
Link: "https://meine.postbank.de/#/login",
},
{
Title: "YouTube",
Image: "https://upload.wikimedia.org/wikipedia/commons/1/1f/YouTube_light_logo_%282017%29.svg",
Color: "#ff0000",
Link: "https://www.youtube.com/",
},
{
Title: "Jisho",
Image: "https://assets.jisho.org/assets/jisho-logo-v4@2x-7330091c079b9dd59601401b052b52e103978221c8fb6f5e22406d871fcc746a.png",
Link: "https://jisho.com/",
Color: "#ffffff",
},
{
Title: "Wadoku",
Image: "https://www.wadoku.de/img/wadoku_logo.svg",
Link: "https://www.wadoku.de/",
Color: "#ffffff",
},
{
Title: "Übersetzer",
Image: "https://static.deepl.com/img/logo/DeepL_Logo_darkBlue_v2.svg",
Link: "https://www.deepl.com/translator",
Color: "#ffffff",
},
{
Title: "WaniKani",
Image: "https://assets.wanikani.com/assets/logo--retro-colors-b79775af8773b5a416e4ec3fae02e62d391b7e88e57f9fe0c2e4997a3383b002.png",
Link: "https://www.wanikani.com/",
Color: "#ffffff",
},
{
Title: "Passwörter",
Image: "https://raw.githubusercontent.com/dani-garcia/vaultwarden/main/resources/vaultwarden-logo-white.svg",
Link: "https://pw.tordarus.net",
Color: "#175ddc",
},
{
Title: "Projekte",
Image: "https://git.tordarus.net/assets/img/logo.svg",
Link: "https://git.tordarus.net",
Color: "#383c4a",
},
{
Title: "Wikipedia",
Image: "https://upload.wikimedia.org/wikipedia/commons/8/80/Wikipedia-logo-v2.svg",
Link: "https://www.wikipedia.org/",
Color: "#ffffff",
},
{
Title: "Reddit",
Image: "https://www.redditinc.com/assets/images/site/reddit-logo.png",
Link: "https://www.reddit.com/",
Color: "#ff4300",
},
{
Title: "Tagesschau",
Image: "https://m47ch.com/wp-content/uploads/2010/12/Tagesschau.png",
Link: "https://www.golem.de/",
Color: "#003f8c",
},
{
Title: "Golem",
Image: "https://www.golem.de/staticrl/images/golem-logo-opt2.svg",
Link: "https://www.golem.de/",
Color: "#000000",
},
{
Title: "Comico",
Image: "https://play-lh.googleusercontent.com/xZ5bfg-XfyEmM1641bXduE27w44OmyWeVspg626wRYF0ejAgZAvsRKP4sECblfmnpg=w512",
ImageSize: "cover",
IconPadding: "0em",
Link: "https://comico.jp/",
Color: "#f40000",
},
{
Title: "Manganelo",
Image: "https://manganato.com/themes/hm/images/logo.png",
Link: "https://manganato.com/",
Color: "#ffffff",
},
}
)
type Bookmark struct {
Title string
Image string
ImageSize string
IconPadding string
Color string
Link string
HideBorder bool
Order int
}
func ParseBookmarks() {
// set default values
for i := range Bookmarks {
if Bookmarks[i].Color == "" {
Bookmarks[i].Color = DefaultSettings.Background
}
if Bookmarks[i].ImageSize == "" {
Bookmarks[i].ImageSize = "contain"
}
}
sort.SliceStable(Bookmarks, func(i, j int) bool {
return Bookmarks[i].Order < Bookmarks[j].Order
})
}

5
go.mod Normal file
View File

@ -0,0 +1,5 @@
module git.tordarus.net/Tordarus/homepage
go 1.18
require golang.org/x/text v0.3.7 // indirect

2
go.sum Normal file
View File

@ -0,0 +1,2 @@
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=

BIN
homepage Executable file

Binary file not shown.

96
main.go Normal file
View File

@ -0,0 +1,96 @@
package main
import (
"embed"
"flag"
"fmt"
"html/template"
"io"
"net/http"
_ "embed"
)
var (
intf = flag.String("i", "localhost", "interface")
port = flag.Uint("p", 80, "port")
)
var (
//go:embed templates/*
TemplateFS embed.FS
//go:embed static/*
StaticFS embed.FS
Templates *template.Template
)
func main() {
flag.Parse()
ParseBookmarks()
if tmpl, err := template.New("homepage").ParseFS(TemplateFS, "templates/*"); err == nil {
Templates = tmpl
} else {
panic(err)
}
http.HandleFunc("/", handler)
http.HandleFunc("/search", search)
http.HandleFunc("/style.css", style)
http.HandleFunc("/icons.ttf", icons)
if err := http.ListenAndServe(fmt.Sprintf("%s:%d", *intf, *port), nil); err != nil {
panic(err)
}
}
func handler(w http.ResponseWriter, r *http.Request) {
data := &TmplData{
text: GetText(r),
Bookmarks: Bookmarks,
Settings: DefaultSettings,
}
if err := Templates.ExecuteTemplate(w, "index.html", data); err != nil {
panic(err)
}
}
func style(w http.ResponseWriter, r *http.Request) {
file, err := TemplateFS.Open("templates/style.css")
if err != nil {
fmt.Println(err)
w.WriteHeader(http.StatusInternalServerError)
return
}
defer file.Close()
w.Header().Add("Content-Type", "text/css")
if err := Templates.ExecuteTemplate(w, "style.css", DefaultSettings); err != nil {
panic(err)
}
}
func icons(w http.ResponseWriter, r *http.Request) {
file, err := StaticFS.Open("static/icons.ttf")
if err != nil {
fmt.Println(err)
w.WriteHeader(http.StatusInternalServerError)
return
}
defer file.Close()
w.Header().Add("Content-Type", "font/ttf")
io.Copy(w, file)
}
func search(w http.ResponseWriter, r *http.Request) {
r.ParseForm()
query := r.Form.Get("query")
w.Header().Add("Location", fmt.Sprintf("https://duckduckgo.com/?q=%s", query))
w.WriteHeader(http.StatusMovedPermanently)
}

19
settings.go Normal file
View File

@ -0,0 +1,19 @@
package main
type Settings struct {
Background string
IconMargin string
IconPadding string
IconWidth string
IconHeight string
BorderRadius string
}
var DefaultSettings = &Settings{
Background: "#333",
IconMargin: "0.5em",
IconPadding: "1em",
IconWidth: "10em",
IconHeight: "10em",
BorderRadius: "0.15em",
}

BIN
static/icons.ttf Normal file

Binary file not shown.

3
templates/bookmark.html Normal file
View File

@ -0,0 +1,3 @@
<a href="{{ .Link }}" class="bookmark" style='background-color: {{ .Color }}; {{ if not .HideBorder }} box-shadow: 0px 0px 3px black; {{ end }}; {{ if not (eq .IconPadding "") }} padding: {{ .IconPadding }}; {{ end }}'>
<div class="background" style='background-image: url("{{ .Image }}"); background-size: {{ .ImageSize }}'></div>
</a>

29
templates/index.html Normal file
View File

@ -0,0 +1,29 @@
<!DOCTYPE html>
<html lang="{{ .Language }}">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ .Translate "Homepage" }}</title>
<link rel="stylesheet" type="text/css" href="style.css" />
</head>
<body>
<main>
<section id="search">
<form method="post" action="/search">
<input type="search" id="query" placeholder='{{ .Translate "Search" }}' name="query"><label title="search" for="submit"><span class="material-icons">search</span></label>
<input id="submit" type="submit" title="search">
</form>
</section>
<section id="bookmark-container">
{{ range .Bookmarks }}
{{ template "bookmark.html" . }}
{{ end }}
</section>
</main>
</body>
</html>

146
templates/style.css Normal file
View File

@ -0,0 +1,146 @@
@font-face {
font-family: 'Material Icons';
font-style: normal;
font-weight: 400;
src: url("/icons.ttf");
src: local('Material Icons'),
local('MaterialIcons-Regular'),
url("/icons.ttf") format('truetype');
}
.material-icons {
transform: translateY(3px);
font-family: 'Material Icons';
font-weight: normal;
font-style: normal;
font-size: 24px; /* Preferred icon size */
display: inline-block;
line-height: 1;
text-transform: none;
letter-spacing: normal;
word-wrap: normal;
white-space: nowrap;
direction: ltr;
/* Support for all WebKit browsers. */
-webkit-font-smoothing: antialiased;
/* Support for Safari and Chrome. */
text-rendering: optimizeLegibility;
/* Support for Firefox. */
-moz-osx-font-smoothing: grayscale;
/* Support for IE. */
font-feature-settings: 'liga';
}
* {
margin: 0;
padding: 0;
}
html, body {
width: 100%;
height: 100%;
font-size: 100%;
}
body {
background-color: {{ .Background }};
}
main {
width: 100%;
height: 100%;
}
#bookmark-container {
width: 100%;
display: flex;
flex-wrap: wrap;
justify-content: center;
align-content: center;
}
main {
display: flex;
flex-direction: column;
justify-content: center;
}
#search {
margin: 0 auto;
margin-bottom: 5em;
}
#search form {
--input-font-size: 1.2em;
}
#search form input[type="search"] {
display: inline-block;
border: 1px solid black;
outline: 0;
background-color: black;
color: white;
padding: 0.25em 0.5em;
transition: all 0.2s ease-in-out;
border-radius: 0.25em 0 0 0.25em;
font-size: var(--input-font-size);
}
#search form input[type="search"]:focus {
box-shadow: 0px 0px 3px gray;
transition: all 0.2s ease-in-out;
}
#search form input[type="search"]:focus + label[for="submit"] {
background-color: #111;
box-shadow: 0px 0px 3px gray;
transition: all 0.2s ease-in-out;
}
#search form label[for="submit"] {
margin-left: 0;
border: 1px solid black;
background-color: black;
color: white;
padding: 0.25em 0.5em;
transition: all 0.2s ease-in-out;
border-radius: 0 0.25em 0.25em 0;
font-size: var(--input-font-size);
cursor: pointer;
}
#search form label[for="submit"] img {
display: inline-block;
}
#search form input[type="submit"] {
display: none;
}
.bookmark {
display: block;
box-sizing: border-box;
transition: all 0.2s ease-in-out;
width: {{ .IconWidth }};
height: {{ .IconHeight }};
margin: {{ .IconMargin }};
padding: {{ .IconPadding }};
border-radius: {{ .BorderRadius }};
}
.bookmark:hover {
transform: scale(1.1, 1.1);
transition: all 0.2s ease-in-out;
}
.background {
width: 100%;
height: 100%;
background-position: center;
background-size: contain;
background-repeat: no-repeat;
}

60
text.go Normal file
View File

@ -0,0 +1,60 @@
package main
import (
"fmt"
"net/http"
"golang.org/x/text/language"
)
type Text struct {
Language string
Strings map[string]string
}
func (t *Text) Translate(str string) string {
if tr, ok := t.Strings[str]; ok {
return tr
}
return str
}
var (
Languages = map[language.Tag]Text{
language.English: {
Strings: map[string]string{
"Homepage": "Homepage",
"Search": "Search",
},
},
language.German: {
Strings: map[string]string{
"Homepage": "Homepage",
"Search": "Suche",
},
},
language.Japanese: {
Strings: map[string]string{
"Homepage": "ホームページ",
"Search": "検索",
},
},
}
)
var languageMatcher = language.NewMatcher([]language.Tag{
language.English,
language.German,
language.Japanese,
})
func GetText(r *http.Request) *Text {
fmt.Println(r.Header.Get("Accept-Language"))
lang, _ := language.MatchStrings(languageMatcher, r.Header.Get("Accept-Language"))
text := Languages[lang]
base, _ := lang.Base()
text.Language = base.String()
return &text
}

15
tmpl_data.go Normal file
View File

@ -0,0 +1,15 @@
package main
type TmplData struct {
text *Text
Bookmarks []Bookmark
Settings *Settings
}
func (d *TmplData) Translate(str string) string {
return d.text.Translate(str)
}
func (d *TmplData) Language() string {
return d.text.Language
}