customization page
This commit is contained in:
parent
fd40eb276c
commit
f5d5d208fe
1
.gitignore
vendored
1
.gitignore
vendored
@ -1 +1,2 @@
|
|||||||
homepage
|
homepage
|
||||||
|
.env
|
||||||
|
225
bookmark.go
225
bookmark.go
@ -5,8 +5,8 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
func DefaultBookmarks() []Bookmark {
|
||||||
Bookmarks = []Bookmark{
|
return []Bookmark{
|
||||||
{
|
{
|
||||||
Title: "DuckDuckGo",
|
Title: "DuckDuckGo",
|
||||||
Image: "https://duckduckgo.com/assets/logo_homepage.alt.v108.svg",
|
Image: "https://duckduckgo.com/assets/logo_homepage.alt.v108.svg",
|
||||||
@ -14,130 +14,22 @@ var (
|
|||||||
Color: "#e37151",
|
Color: "#e37151",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Title: "Cloud",
|
Title: "Google Dark",
|
||||||
Image: "https://cloud.tordarus.net/svg/core/logo/logo?color=ffffff&v=1",
|
Image: "https://www.google.com/images/branding/googlelogo/2x/googlelogo_light_color_272x92dp.png",
|
||||||
Link: "https://cloud.tordarus.net/",
|
Link: "https://google.com/",
|
||||||
Color: "#007ec2",
|
Color: "#202124",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Title: "ProtonMail",
|
Title: "Google Light",
|
||||||
Image: "https://protonmail.com/images/pm-logo-white.svg",
|
Image: "https://www.google.de/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png",
|
||||||
Link: "https://protonmail.com/",
|
Link: "https://google.com/",
|
||||||
Color: "#253163",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Title: "Anilist",
|
|
||||||
Image: "https://anilist.co/img/icons/icon.svg",
|
|
||||||
Link: "https://anilist.co/",
|
|
||||||
Color: "#2b2d42",
|
|
||||||
IconPadding: "0.5em",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Title: "Torrents",
|
|
||||||
Image: "/transmission.png",
|
|
||||||
Link: "https://torrents.tordarus.net/",
|
|
||||||
Color: "#e7402c",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Title: "Nyaa.si",
|
|
||||||
Image: "https://progsoft.net/images/nyaa-v2-icon-a591b5ae622eb38f31c00297cf9b53fd88c058ef.png",
|
|
||||||
Link: "https://nyaa.si/",
|
|
||||||
Color: "#e7402c",
|
|
||||||
ImageSize: "111%",
|
|
||||||
IconPadding: "0em",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Title: "Adblock",
|
|
||||||
Image: "/pihole.svg",
|
|
||||||
Link: "https://adblock.tordarus.net/",
|
|
||||||
Color: "#272c30",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Title: "Postbank",
|
|
||||||
Image: "https://wintouch.de/wp-content/uploads/2014/06/Postbank-Icon.png",
|
|
||||||
Link: "https://meine.postbank.de/",
|
|
||||||
Color: "#ffcc00",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Title: "DKB",
|
|
||||||
Image: "https://vdiv-sa.de/wp-content/uploads/2016/08/DKB_AG_web_RGB.jpg",
|
|
||||||
Link: "https://www.dkb.de/",
|
|
||||||
Color: "#ffffff",
|
Color: "#ffffff",
|
||||||
},
|
},
|
||||||
{
|
|
||||||
Title: "Finanzen",
|
|
||||||
Image: "https://docs.firefly-iii.org/img/logo.png",
|
|
||||||
Link: "https://finance.tordarus.net",
|
|
||||||
Color: "#ffffff",
|
|
||||||
ImageSize: "cover",
|
|
||||||
IconPadding: "0em",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Title: "YouTube",
|
|
||||||
Image: "https://upload.wikimedia.org/wikipedia/commons/thumb/4/42/YouTube_light_icon_%282017%29.svg/1280px-YouTube_light_icon_%282017%29.svg.png",
|
|
||||||
Color: "#ff0000",
|
|
||||||
Link: "https://www.youtube.com/",
|
|
||||||
IconPadding: "1.5em",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Title: "Netflix",
|
|
||||||
Image: "https://1000logos.net/wp-content/uploads/2017/05/emblem-Netflix.jpg",
|
|
||||||
Color: "#000000",
|
|
||||||
Link: "https://www.netflix.com/",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Title: "Jisho",
|
|
||||||
Image: "https://assets.jisho.org/assets/jisho-logo-v4@2x-7330091c079b9dd59601401b052b52e103978221c8fb6f5e22406d871fcc746a.png",
|
|
||||||
Link: "https://jisho.org/",
|
|
||||||
Color: "#ffffff",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Title: "Wadoku",
|
|
||||||
Image: "https://www.wadoku.de/img/wadoku_logo.svg",
|
|
||||||
Link: "https://www.wadoku.de/",
|
|
||||||
Color: "#ffffff",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Title: "Übersetzer",
|
|
||||||
Image: "https://tools.avans.nl/tools/image/wZkdyaMblN.jpg",
|
|
||||||
Link: "https://www.deepl.com/translator",
|
|
||||||
Color: "#042b48",
|
|
||||||
ImageSize: "cover",
|
|
||||||
IconPadding: "0em",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
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: "/gitea.png", //"https://git.tordarus.net/assets/img/logo.svg",
|
|
||||||
Link: "https://git.tordarus.net",
|
|
||||||
Color: "#609926",
|
|
||||||
ImageSize: "cover",
|
|
||||||
IconPadding: "0em",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Title: "Regexr",
|
|
||||||
Image: "https://raw.githubusercontent.com/gskinner/regexr/master/dev/icons/RegExr.svg",
|
|
||||||
Link: "https://regex.tordarus.net",
|
|
||||||
Color: "#101112",
|
|
||||||
ImageSize: "contain",
|
|
||||||
IconPadding: "0em",
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
Title: "Wikipedia",
|
Title: "Wikipedia",
|
||||||
Image: "https://upload.wikimedia.org/wikipedia/commons/8/80/Wikipedia-logo-v2.svg",
|
Image: "https://upload.wikimedia.org/wikipedia/commons/8/80/Wikipedia-logo-v2.svg",
|
||||||
Link: "https://www.wikipedia.org/",
|
|
||||||
Color: "#ffffff",
|
Color: "#ffffff",
|
||||||
|
Link: "https://www.wikipedia.org/",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Title: "Reddit",
|
Title: "Reddit",
|
||||||
@ -148,67 +40,64 @@ var (
|
|||||||
IconPadding: "0em",
|
IconPadding: "0em",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Title: "Tagesschau",
|
Title: "YouTube",
|
||||||
Image: "https://m47ch.com/wp-content/uploads/2010/12/Tagesschau.png",
|
Image: "https://upload.wikimedia.org/wikipedia/commons/thumb/4/42/YouTube_light_icon_%282017%29.svg/1280px-YouTube_light_icon_%282017%29.svg.png",
|
||||||
Link: "https://www.tagesschau.de/",
|
Link: "https://www.youtube.com/",
|
||||||
Color: "#003f8c",
|
Color: "#ff0000",
|
||||||
|
IconPadding: "1.5em",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Title: "Golem",
|
Title: "Netflix",
|
||||||
Image: "https://www.golem.de/staticrl/images/golem-logo-opt2.svg",
|
Image: "https://1000logos.net/wp-content/uploads/2017/05/emblem-Netflix.jpg",
|
||||||
Link: "https://www.golem.de/",
|
Link: "https://www.netflix.com/",
|
||||||
Color: "#000000",
|
Color: "#000000",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Title: "Comico",
|
Title: "Übersetzer",
|
||||||
Image: "https://play-lh.googleusercontent.com/xZ5bfg-XfyEmM1641bXduE27w44OmyWeVspg626wRYF0ejAgZAvsRKP4sECblfmnpg=w512",
|
Image: "https://tools.avans.nl/tools/image/wZkdyaMblN.jpg",
|
||||||
Link: "https://comico.jp/",
|
Link: "https://www.deepl.com/translator",
|
||||||
Color: "#f40000",
|
Color: "#042b48",
|
||||||
ImageSize: "cover",
|
ImageSize: "cover",
|
||||||
IconPadding: "0em",
|
IconPadding: "0em",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Title: "Manganelo",
|
Title: "Cloud",
|
||||||
Image: "https://manganato.com/themes/hm/images/logo.png",
|
Image: "https://cloud.tordarus.net/svg/core/logo/logo?color=ffffff\u0026v=1",
|
||||||
Link: "https://manganato.com/",
|
Link: "https://cloud.tordarus.net/",
|
||||||
Color: "#ffffff",
|
Color: "#007ec2",
|
||||||
ImageSize: "contain",
|
|
||||||
IconPadding: "0em",
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Title: "Manga List",
|
Title: "Passwörter",
|
||||||
Image: "https://www.firstcomicsnews.com/wp-content/uploads/2020/09/manga-logo.png",
|
Image: "https://raw.githubusercontent.com/dani-garcia/vaultwarden/main/resources/vaultwarden-logo-white.svg",
|
||||||
Link: "https://manga.tordarus.net/",
|
Link: "https://pw.tordarus.net",
|
||||||
Color: "#be151b",
|
Color: "#175ddc",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
)
|
|
||||||
|
|
||||||
type Bookmark struct {
|
|
||||||
Title string
|
|
||||||
Image string
|
|
||||||
ImageSize string
|
|
||||||
IconPadding string
|
|
||||||
Color string
|
|
||||||
Link string
|
|
||||||
HideBorder bool
|
|
||||||
Order int
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func ParseBookmarks() {
|
type Bookmark struct {
|
||||||
// set default values
|
Title string `json:"title"`
|
||||||
for i := range Bookmarks {
|
Image string `json:"image"`
|
||||||
if Bookmarks[i].Color == "" {
|
ImageSize string `json:"image_size"`
|
||||||
Bookmarks[i].Color = DefaultSettings.Background
|
IconPadding string `json:"icon_padding"`
|
||||||
}
|
Color string `json:"color"`
|
||||||
if Bookmarks[i].ImageSize == "" {
|
Link string `json:"link"`
|
||||||
Bookmarks[i].ImageSize = "contain"
|
HideBorder bool `json:"hide_border"`
|
||||||
}
|
Order int `json:"order"`
|
||||||
}
|
}
|
||||||
|
|
||||||
sort.SliceStable(Bookmarks, func(i, j int) bool {
|
func (b *Bookmark) GetColor() string {
|
||||||
return Bookmarks[i].Order < Bookmarks[j].Order
|
if b.Color == "" {
|
||||||
})
|
b.Color = "transparent"
|
||||||
|
}
|
||||||
|
return b.Color
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Bookmark) GetImageSize() string {
|
||||||
|
if b.ImageSize == "" {
|
||||||
|
b.ImageSize = "contain"
|
||||||
|
}
|
||||||
|
return b.ImageSize
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Bookmark) SmallLink() string {
|
func (b *Bookmark) SmallLink() string {
|
||||||
@ -218,3 +107,13 @@ func (b *Bookmark) SmallLink() string {
|
|||||||
lnk = strings.TrimSuffix(lnk, "/")
|
lnk = strings.TrimSuffix(lnk, "/")
|
||||||
return lnk
|
return lnk
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Reorder(bookmarks []Bookmark) {
|
||||||
|
sort.SliceStable(bookmarks, func(i, j int) bool {
|
||||||
|
return bookmarks[i].Order < bookmarks[j].Order
|
||||||
|
})
|
||||||
|
|
||||||
|
for index := range bookmarks {
|
||||||
|
bookmarks[index].Order = index * 10
|
||||||
|
}
|
||||||
|
}
|
||||||
|
262
bookmarks.json
Normal file
262
bookmarks.json
Normal file
@ -0,0 +1,262 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"title": "DuckDuckGo",
|
||||||
|
"image": "https://duckduckgo.com/assets/logo_homepage.alt.v108.svg",
|
||||||
|
"image_size": "",
|
||||||
|
"icon_padding": "",
|
||||||
|
"color": "#e37151",
|
||||||
|
"link": "https://duckduckgo.com/",
|
||||||
|
"hide_border": false,
|
||||||
|
"order": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Cloud",
|
||||||
|
"image": "https://cloud.tordarus.net/svg/core/logo/logo?color=ffffff\u0026v=1",
|
||||||
|
"image_size": "",
|
||||||
|
"icon_padding": "",
|
||||||
|
"color": "#007ec2",
|
||||||
|
"link": "https://cloud.tordarus.net/",
|
||||||
|
"hide_border": false,
|
||||||
|
"order": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "ProtonMail",
|
||||||
|
"image": "https://protonmail.com/images/pm-logo-white.svg",
|
||||||
|
"image_size": "",
|
||||||
|
"icon_padding": "",
|
||||||
|
"color": "#253163",
|
||||||
|
"link": "https://protonmail.com/",
|
||||||
|
"hide_border": false,
|
||||||
|
"order": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Anilist",
|
||||||
|
"image": "https://anilist.co/img/icons/icon.svg",
|
||||||
|
"image_size": "",
|
||||||
|
"icon_padding": "0.5em",
|
||||||
|
"color": "#2b2d42",
|
||||||
|
"link": "https://anilist.co/",
|
||||||
|
"hide_border": false,
|
||||||
|
"order": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Torrents",
|
||||||
|
"image": "/transmission.png",
|
||||||
|
"image_size": "",
|
||||||
|
"icon_padding": "",
|
||||||
|
"color": "#e7402c",
|
||||||
|
"link": "https://torrents.tordarus.net/",
|
||||||
|
"hide_border": false,
|
||||||
|
"order": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Nyaa.si",
|
||||||
|
"image": "https://progsoft.net/images/nyaa-v2-icon-a591b5ae622eb38f31c00297cf9b53fd88c058ef.png",
|
||||||
|
"image_size": "111%",
|
||||||
|
"icon_padding": "0em",
|
||||||
|
"color": "#e7402c",
|
||||||
|
"link": "https://nyaa.si/",
|
||||||
|
"hide_border": false,
|
||||||
|
"order": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Adblock",
|
||||||
|
"image": "/pihole.svg",
|
||||||
|
"image_size": "",
|
||||||
|
"icon_padding": "",
|
||||||
|
"color": "#272c30",
|
||||||
|
"link": "https://adblock.tordarus.net/",
|
||||||
|
"hide_border": false,
|
||||||
|
"order": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Postbank",
|
||||||
|
"image": "https://wintouch.de/wp-content/uploads/2014/06/Postbank-Icon.png",
|
||||||
|
"image_size": "",
|
||||||
|
"icon_padding": "",
|
||||||
|
"color": "#ffcc00",
|
||||||
|
"link": "https://meine.postbank.de/",
|
||||||
|
"hide_border": false,
|
||||||
|
"order": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "DKB",
|
||||||
|
"image": "https://vdiv-sa.de/wp-content/uploads/2016/08/DKB_AG_web_RGB.jpg",
|
||||||
|
"image_size": "",
|
||||||
|
"icon_padding": "",
|
||||||
|
"color": "#ffffff",
|
||||||
|
"link": "https://www.dkb.de/",
|
||||||
|
"hide_border": false,
|
||||||
|
"order": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Finanzen",
|
||||||
|
"image": "https://docs.firefly-iii.org/img/logo.png",
|
||||||
|
"image_size": "cover",
|
||||||
|
"icon_padding": "0em",
|
||||||
|
"color": "#ffffff",
|
||||||
|
"link": "https://finance.tordarus.net",
|
||||||
|
"hide_border": false,
|
||||||
|
"order": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "YouTube",
|
||||||
|
"image": "https://upload.wikimedia.org/wikipedia/commons/thumb/4/42/YouTube_light_icon_%282017%29.svg/1280px-YouTube_light_icon_%282017%29.svg.png",
|
||||||
|
"image_size": "",
|
||||||
|
"icon_padding": "1.5em",
|
||||||
|
"color": "#ff0000",
|
||||||
|
"link": "https://www.youtube.com/",
|
||||||
|
"hide_border": false,
|
||||||
|
"order": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Netflix",
|
||||||
|
"image": "https://1000logos.net/wp-content/uploads/2017/05/emblem-Netflix.jpg",
|
||||||
|
"image_size": "",
|
||||||
|
"icon_padding": "",
|
||||||
|
"color": "#000000",
|
||||||
|
"link": "https://www.netflix.com/",
|
||||||
|
"hide_border": false,
|
||||||
|
"order": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Jisho",
|
||||||
|
"image": "https://assets.jisho.org/assets/jisho-logo-v4@2x-7330091c079b9dd59601401b052b52e103978221c8fb6f5e22406d871fcc746a.png",
|
||||||
|
"image_size": "",
|
||||||
|
"icon_padding": "",
|
||||||
|
"color": "#ffffff",
|
||||||
|
"link": "https://jisho.org/",
|
||||||
|
"hide_border": false,
|
||||||
|
"order": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Wadoku",
|
||||||
|
"image": "https://www.wadoku.de/img/wadoku_logo.svg",
|
||||||
|
"image_size": "",
|
||||||
|
"icon_padding": "",
|
||||||
|
"color": "#ffffff",
|
||||||
|
"link": "https://www.wadoku.de/",
|
||||||
|
"hide_border": false,
|
||||||
|
"order": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Übersetzer",
|
||||||
|
"image": "https://tools.avans.nl/tools/image/wZkdyaMblN.jpg",
|
||||||
|
"image_size": "cover",
|
||||||
|
"icon_padding": "0em",
|
||||||
|
"color": "#042b48",
|
||||||
|
"link": "https://www.deepl.com/translator",
|
||||||
|
"hide_border": false,
|
||||||
|
"order": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "WaniKani",
|
||||||
|
"image": "https://assets.wanikani.com/assets/logo--retro-colors-b79775af8773b5a416e4ec3fae02e62d391b7e88e57f9fe0c2e4997a3383b002.png",
|
||||||
|
"image_size": "",
|
||||||
|
"icon_padding": "",
|
||||||
|
"color": "#ffffff",
|
||||||
|
"link": "https://www.wanikani.com/",
|
||||||
|
"hide_border": false,
|
||||||
|
"order": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Passwörter",
|
||||||
|
"image": "https://raw.githubusercontent.com/dani-garcia/vaultwarden/main/resources/vaultwarden-logo-white.svg",
|
||||||
|
"image_size": "",
|
||||||
|
"icon_padding": "",
|
||||||
|
"color": "#175ddc",
|
||||||
|
"link": "https://pw.tordarus.net",
|
||||||
|
"hide_border": false,
|
||||||
|
"order": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Projekte",
|
||||||
|
"image": "/gitea.png",
|
||||||
|
"image_size": "cover",
|
||||||
|
"icon_padding": "0em",
|
||||||
|
"color": "#609926",
|
||||||
|
"link": "https://git.tordarus.net",
|
||||||
|
"hide_border": false,
|
||||||
|
"order": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Regexr",
|
||||||
|
"image": "https://raw.githubusercontent.com/gskinner/regexr/master/dev/icons/RegExr.svg",
|
||||||
|
"image_size": "contain",
|
||||||
|
"icon_padding": "0em",
|
||||||
|
"color": "#101112",
|
||||||
|
"link": "https://regex.tordarus.net",
|
||||||
|
"hide_border": false,
|
||||||
|
"order": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Wikipedia",
|
||||||
|
"image": "https://upload.wikimedia.org/wikipedia/commons/8/80/Wikipedia-logo-v2.svg",
|
||||||
|
"image_size": "",
|
||||||
|
"icon_padding": "",
|
||||||
|
"color": "#ffffff",
|
||||||
|
"link": "https://www.wikipedia.org/",
|
||||||
|
"hide_border": false,
|
||||||
|
"order": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Reddit",
|
||||||
|
"image": "https://www.redditinc.com/assets/images/site/reddit-logo.png",
|
||||||
|
"image_size": "cover",
|
||||||
|
"icon_padding": "0em",
|
||||||
|
"color": "#ff4300",
|
||||||
|
"link": "https://www.reddit.com/",
|
||||||
|
"hide_border": false,
|
||||||
|
"order": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Tagesschau",
|
||||||
|
"image": "https://m47ch.com/wp-content/uploads/2010/12/Tagesschau.png",
|
||||||
|
"image_size": "",
|
||||||
|
"icon_padding": "",
|
||||||
|
"color": "#003f8c",
|
||||||
|
"link": "https://www.tagesschau.de/",
|
||||||
|
"hide_border": false,
|
||||||
|
"order": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Golem",
|
||||||
|
"image": "https://www.golem.de/staticrl/images/golem-logo-opt2.svg",
|
||||||
|
"image_size": "",
|
||||||
|
"icon_padding": "",
|
||||||
|
"color": "#000000",
|
||||||
|
"link": "https://www.golem.de/",
|
||||||
|
"hide_border": false,
|
||||||
|
"order": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Comico",
|
||||||
|
"image": "https://play-lh.googleusercontent.com/xZ5bfg-XfyEmM1641bXduE27w44OmyWeVspg626wRYF0ejAgZAvsRKP4sECblfmnpg=w512",
|
||||||
|
"image_size": "cover",
|
||||||
|
"icon_padding": "0em",
|
||||||
|
"color": "#f40000",
|
||||||
|
"link": "https://comico.jp/",
|
||||||
|
"hide_border": false,
|
||||||
|
"order": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Manganelo",
|
||||||
|
"image": "https://manganato.com/themes/hm/images/logo.png",
|
||||||
|
"image_size": "contain",
|
||||||
|
"icon_padding": "0em",
|
||||||
|
"color": "#ffffff",
|
||||||
|
"link": "https://manganato.com/",
|
||||||
|
"hide_border": false,
|
||||||
|
"order": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Manga List",
|
||||||
|
"image": "https://www.firstcomicsnews.com/wp-content/uploads/2020/09/manga-logo.png",
|
||||||
|
"image_size": "",
|
||||||
|
"icon_padding": "",
|
||||||
|
"color": "#be151b",
|
||||||
|
"link": "https://manga.tordarus.net/",
|
||||||
|
"hide_border": false,
|
||||||
|
"order": 0
|
||||||
|
}
|
||||||
|
]
|
8
go.mod
8
go.mod
@ -2,4 +2,10 @@ module git.tordarus.net/Tordarus/homepage
|
|||||||
|
|
||||||
go 1.18
|
go 1.18
|
||||||
|
|
||||||
require golang.org/x/text v0.3.7 // indirect
|
require (
|
||||||
|
git.milar.in/milarin/slices v0.0.4
|
||||||
|
github.com/gorilla/sessions v1.2.1
|
||||||
|
golang.org/x/text v0.3.7
|
||||||
|
)
|
||||||
|
|
||||||
|
require github.com/gorilla/securecookie v1.1.1 // indirect
|
||||||
|
6
go.sum
6
go.sum
@ -1,2 +1,8 @@
|
|||||||
|
git.milar.in/milarin/slices v0.0.4 h1:z92jgsKcnLPLfgXkTVCzH2XXesfXzhe0Osx+PkfCHVI=
|
||||||
|
git.milar.in/milarin/slices v0.0.4/go.mod h1:NOr53AOeur/qscu/FBj3lsFR262PNYBccLYSTCAXRk4=
|
||||||
|
github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ=
|
||||||
|
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
|
||||||
|
github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7FsgI=
|
||||||
|
github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
|
||||||
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
|
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
|
||||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
|
96
main.go
96
main.go
@ -2,6 +2,9 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"embed"
|
"embed"
|
||||||
|
"encoding/gob"
|
||||||
|
"encoding/hex"
|
||||||
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
@ -9,9 +12,13 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
_ "embed"
|
_ "embed"
|
||||||
|
|
||||||
|
"git.milar.in/milarin/slices"
|
||||||
|
"github.com/gorilla/sessions"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -27,12 +34,15 @@ var (
|
|||||||
StaticFS embed.FS
|
StaticFS embed.FS
|
||||||
|
|
||||||
Templates *template.Template
|
Templates *template.Template
|
||||||
|
|
||||||
|
SessionStore = sessions.NewCookieStore(Must(hex.DecodeString(os.Getenv("SESSION_KEY"))))
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
flag.Parse()
|
gob.Register([]Bookmark{})
|
||||||
|
gob.Register(&Settings{})
|
||||||
|
|
||||||
ParseBookmarks()
|
flag.Parse()
|
||||||
|
|
||||||
if tmpl, err := template.New("homepage").ParseFS(TemplateFS, "templates/*"); err == nil {
|
if tmpl, err := template.New("homepage").ParseFS(TemplateFS, "templates/*"); err == nil {
|
||||||
Templates = tmpl
|
Templates = tmpl
|
||||||
@ -41,8 +51,11 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
http.HandleFunc("/", handler)
|
http.HandleFunc("/", handler)
|
||||||
|
http.HandleFunc("/customize", customize)
|
||||||
|
http.HandleFunc("/save-changes", saveChanges)
|
||||||
http.HandleFunc("/search", search)
|
http.HandleFunc("/search", search)
|
||||||
http.HandleFunc("/style.css", style)
|
http.HandleFunc("/style.css", ProvideFile("static/style.css", "text/css"))
|
||||||
|
http.HandleFunc("/customize.js", ProvideFile("static/customize.js", "application/javascript"))
|
||||||
http.HandleFunc("/icons.ttf", ProvideFile("static/icons.ttf", "font/ttf"))
|
http.HandleFunc("/icons.ttf", ProvideFile("static/icons.ttf", "font/ttf"))
|
||||||
http.HandleFunc("/transmission.png", ProvideFile("static/transmission.png", "image/png"))
|
http.HandleFunc("/transmission.png", ProvideFile("static/transmission.png", "image/png"))
|
||||||
http.HandleFunc("/pihole.svg", ProvideFile("static/pihole.svg", "image/svg+xml"))
|
http.HandleFunc("/pihole.svg", ProvideFile("static/pihole.svg", "image/svg+xml"))
|
||||||
@ -53,10 +66,12 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func handler(w http.ResponseWriter, r *http.Request) {
|
func handler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
session, _ := SessionStore.Get(r, "settings")
|
||||||
|
|
||||||
data := &TmplData{
|
data := &TmplData{
|
||||||
text: GetText(r),
|
text: GetText(r),
|
||||||
Bookmarks: Bookmarks,
|
Bookmarks: GetValueDefault(session, "bookmarks", DefaultBookmarks()),
|
||||||
Settings: DefaultSettings,
|
Settings: GetValueDefault(session, "settings", DefaultSettings()),
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := Templates.ExecuteTemplate(w, "index.html", data); err != nil {
|
if err := Templates.ExecuteTemplate(w, "index.html", data); err != nil {
|
||||||
@ -64,22 +79,6 @@ func handler(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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 ProvideFile(path, contentType string) http.HandlerFunc {
|
func ProvideFile(path, contentType string) http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
file, err := StaticFS.Open(path)
|
file, err := StaticFS.Open(path)
|
||||||
@ -95,6 +94,9 @@ func ProvideFile(path, contentType string) http.HandlerFunc {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func search(w http.ResponseWriter, r *http.Request) {
|
func search(w http.ResponseWriter, r *http.Request) {
|
||||||
|
session, _ := SessionStore.Get(r, "settings")
|
||||||
|
settings := GetValueDefault(session, "settings", DefaultSettings())
|
||||||
|
|
||||||
if err := r.ParseForm(); err != nil {
|
if err := r.ParseForm(); err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
@ -109,12 +111,62 @@ func search(w http.ResponseWriter, r *http.Request) {
|
|||||||
w.WriteHeader(http.StatusMovedPermanently)
|
w.WriteHeader(http.StatusMovedPermanently)
|
||||||
} else {
|
} else {
|
||||||
// search string
|
// search string
|
||||||
w.Header().Add("Location", fmt.Sprintf("https://duckduckgo.com/?q=%s", query))
|
w.Header().Add("Location", fmt.Sprintf(settings.Search, query))
|
||||||
w.WriteHeader(http.StatusMovedPermanently)
|
w.WriteHeader(http.StatusMovedPermanently)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func customize(w http.ResponseWriter, r *http.Request) {
|
||||||
|
session, _ := SessionStore.Get(r, "settings")
|
||||||
|
|
||||||
|
text := GetText(r)
|
||||||
|
|
||||||
|
bookmarks := slices.Map(GetValueDefault(session, "bookmarks", DefaultBookmarks()), func(b Bookmark) BookmarkData {
|
||||||
|
return BookmarkData{
|
||||||
|
Bookmark: &b,
|
||||||
|
text: text,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
data := &CustomizeData{
|
||||||
|
text: text,
|
||||||
|
Bookmarks: bookmarks,
|
||||||
|
Settings: GetValueDefault(session, "settings", DefaultSettings()),
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := Templates.ExecuteTemplate(w, "customize.html", data); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func saveChanges(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if r.Method != "POST" {
|
||||||
|
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
session, _ := SessionStore.Get(r, "settings")
|
||||||
|
|
||||||
|
sessionData := &SessionData{}
|
||||||
|
err := json.NewDecoder(r.Body).Decode(&sessionData)
|
||||||
|
if err != nil {
|
||||||
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
|
fmt.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
Reorder(sessionData.Bookmarks)
|
||||||
|
session.Values["bookmarks"] = sessionData.Bookmarks
|
||||||
|
session.Values["settings"] = sessionData.Settings
|
||||||
|
|
||||||
|
if err := session.Save(r, w); err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func ParseURI(uri string) (*url.URL, error) {
|
func ParseURI(uri string) (*url.URL, error) {
|
||||||
if !strings.HasPrefix(uri, "http://") && !strings.HasPrefix(uri, "https://") {
|
if !strings.HasPrefix(uri, "http://") && !strings.HasPrefix(uri, "https://") {
|
||||||
uri = "https://" + uri
|
uri = "https://" + uri
|
||||||
|
6
session_data.go
Normal file
6
session_data.go
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
type SessionData struct {
|
||||||
|
Bookmarks []Bookmark `json:"bookmarks"`
|
||||||
|
Settings *Settings `json:"settings"`
|
||||||
|
}
|
24
settings.go
24
settings.go
@ -1,19 +1,17 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
type Settings struct {
|
type Settings struct {
|
||||||
Background string
|
Background string `json:"background_color"`
|
||||||
IconMargin string
|
Foreground string `json:"foreground_color"`
|
||||||
IconPadding string
|
Search string `json:"search_query"`
|
||||||
IconWidth string
|
BorderRadius string `json:"border_radius"`
|
||||||
IconHeight string
|
|
||||||
BorderRadius string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var DefaultSettings = &Settings{
|
func DefaultSettings() *Settings {
|
||||||
Background: "#2b2a33",
|
return &Settings{
|
||||||
IconMargin: "0.5em",
|
Background: "#2b2a33",
|
||||||
IconPadding: "1em",
|
Foreground: "#ffffff",
|
||||||
IconWidth: "10em",
|
Search: "https://duckduckgo.com/?q=%s",
|
||||||
IconHeight: "10em",
|
BorderRadius: "1.5%",
|
||||||
BorderRadius: "0.15em",
|
}
|
||||||
}
|
}
|
||||||
|
135
static/customize.js
Normal file
135
static/customize.js
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
window.addEventListener("load", main);
|
||||||
|
|
||||||
|
function main() {
|
||||||
|
const bgColor = document.querySelector("#bg-color");
|
||||||
|
const fgColor = document.querySelector("#fg-color");
|
||||||
|
const borderRadius = document.querySelector("#border-radius");
|
||||||
|
|
||||||
|
bgColor.addEventListener("change", () => document.body.style.backgroundColor = bgColor.value);
|
||||||
|
fgColor.addEventListener("change", () => document.body.style.color = fgColor.value);
|
||||||
|
borderRadius.addEventListener("change", () => document.querySelector(":root").style.setProperty("--bookmark-border-radius", borderRadius.value));
|
||||||
|
|
||||||
|
const save = document.querySelector("#button");
|
||||||
|
save.addEventListener("click", saveChanges);
|
||||||
|
|
||||||
|
const addBookmark = document.querySelector("#add-bookmark");
|
||||||
|
const firstBookmark = document.querySelector(".customizer");
|
||||||
|
|
||||||
|
addBookmark.style.width = `${firstBookmark.offsetWidth}px`;
|
||||||
|
addBookmark.style.height = `${firstBookmark.offsetHeight}px`;
|
||||||
|
addBookmark.style.lineHeight = `${firstBookmark.offsetHeight}px`;
|
||||||
|
|
||||||
|
addBookmark.addEventListener("click", () => {
|
||||||
|
const bookmark = firstBookmark.cloneNode(true);
|
||||||
|
initBookmark(bookmark);
|
||||||
|
clearBookmarkData(bookmark);
|
||||||
|
document.querySelector("#customize-container").insertBefore(bookmark, addBookmark);
|
||||||
|
});
|
||||||
|
|
||||||
|
document.querySelectorAll(".customizer").forEach(initBookmark);
|
||||||
|
}
|
||||||
|
|
||||||
|
function saveChanges() {
|
||||||
|
const bookmarks = [];
|
||||||
|
document.querySelectorAll(".customizer").forEach(element => bookmarks.push(buildDataForBoomark(element)));
|
||||||
|
|
||||||
|
const settings = {
|
||||||
|
background_color: document.querySelector("#bg-color").value,
|
||||||
|
foreground_color: document.querySelector("#fg-color").value,
|
||||||
|
search_query: document.querySelector("#search-string").value,
|
||||||
|
border_radius: document.querySelector("#border-radius").value
|
||||||
|
};
|
||||||
|
|
||||||
|
const data = { bookmarks, settings }
|
||||||
|
|
||||||
|
fetch("/save-changes", {
|
||||||
|
method: "POST",
|
||||||
|
body: JSON.stringify(data)
|
||||||
|
}).then(() => {
|
||||||
|
window.location = "/";
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildDataForBoomark(element) {
|
||||||
|
const form = element.querySelector("form");
|
||||||
|
|
||||||
|
const title = form.querySelector("#bookmark-name");
|
||||||
|
const link = form.querySelector("#bookmark-link");
|
||||||
|
const image = form.querySelector("#bookmark-image");
|
||||||
|
const imageSize = form.querySelector("#bookmark-imagesize");
|
||||||
|
const iconPadding = form.querySelector("#bookmark-iconpadding");
|
||||||
|
const color = form.querySelector("#bookmark-color");
|
||||||
|
const hideBorder = form.querySelector("#bookmark-border");
|
||||||
|
const order = form.querySelector("#bookmark-order");
|
||||||
|
|
||||||
|
return {
|
||||||
|
title: title.value,
|
||||||
|
image: image.value,
|
||||||
|
image_size: imageSize.value,
|
||||||
|
icon_padding: iconPadding.value,
|
||||||
|
color: color.value,
|
||||||
|
link: link.value,
|
||||||
|
hide_border: hideBorder.checked,
|
||||||
|
order: parseInt(order.value)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearBookmarkData(bookmark) {
|
||||||
|
const a = bookmark.querySelector(".bookmark");
|
||||||
|
const form = bookmark.querySelector("form");
|
||||||
|
const bg = a.querySelector(".background");
|
||||||
|
|
||||||
|
const title = form.querySelector("#bookmark-name");
|
||||||
|
const link = form.querySelector("#bookmark-link");
|
||||||
|
const image = form.querySelector("#bookmark-image");
|
||||||
|
const imageSize = form.querySelector("#bookmark-imagesize");
|
||||||
|
const iconPadding = form.querySelector("#bookmark-iconpadding");
|
||||||
|
const color = form.querySelector("#bookmark-color");
|
||||||
|
const hideBorder = form.querySelector("#bookmark-border");
|
||||||
|
const order = form.querySelector("#bookmark-order");
|
||||||
|
|
||||||
|
let orderValue = 0;
|
||||||
|
document.querySelectorAll(".customizer").forEach(element => {
|
||||||
|
orderValue = Math.max(orderValue, element.querySelector("#bookmark-order").value);
|
||||||
|
});
|
||||||
|
|
||||||
|
title.value = "";
|
||||||
|
link.value = "";
|
||||||
|
image.value = "";
|
||||||
|
imageSize.value = "contain";
|
||||||
|
iconPadding.value = "";
|
||||||
|
color.value = "#ffffff";
|
||||||
|
hideBorder.value = false;
|
||||||
|
order.value = orderValue + 10;
|
||||||
|
bg.style.backgroundImage = "";
|
||||||
|
a.style.backgroundColor = "#ffffff";
|
||||||
|
}
|
||||||
|
|
||||||
|
function initBookmark(bookmark) {
|
||||||
|
const a = bookmark.querySelector(".bookmark");
|
||||||
|
const del = bookmark.querySelector(".delete");
|
||||||
|
const form = bookmark.querySelector("form");
|
||||||
|
const bg = a.querySelector(".background");
|
||||||
|
|
||||||
|
const title = form.querySelector("#bookmark-name");
|
||||||
|
const link = form.querySelector("#bookmark-link");
|
||||||
|
const image = form.querySelector("#bookmark-image");
|
||||||
|
const imageSize = form.querySelector("#bookmark-imagesize");
|
||||||
|
const iconPadding = form.querySelector("#bookmark-iconpadding");
|
||||||
|
const color = form.querySelector("#bookmark-color");
|
||||||
|
const hideBorder = form.querySelector("#bookmark-border");
|
||||||
|
|
||||||
|
del.addEventListener("click", () => {
|
||||||
|
const question = title.value == "" ? "Do you want to delete this bookmark?" : `Do you want to delete '${title.value}'?`
|
||||||
|
if (confirm(question)) {
|
||||||
|
bookmark.parentElement.removeChild(bookmark);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
link.addEventListener("change", () => a.setAttribute("href", link.value));
|
||||||
|
image.addEventListener("change", () => bg.style.backgroundImage = `url(${image.value})`);
|
||||||
|
imageSize.addEventListener("change", () => bg.style.backgroundSize = imageSize.value);
|
||||||
|
iconPadding.addEventListener("change", () => a.style.padding = iconPadding.value);
|
||||||
|
color.addEventListener("change", () => a.style.backgroundColor = color.value);
|
||||||
|
hideBorder.addEventListener("change", () => a.style.boxShadow = hideBorder.value ? "" : "0px 0px 3px black");
|
||||||
|
}
|
315
static/style.css
Normal file
315
static/style.css
Normal file
@ -0,0 +1,315 @@
|
|||||||
|
@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. */
|
||||||
|
|
||||||
|
/* Support for Safari and Chrome. */
|
||||||
|
text-rendering: optimizeLegibility;
|
||||||
|
|
||||||
|
/* Support for Firefox. */
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
|
||||||
|
/* Support for IE. */
|
||||||
|
font-feature-settings: 'liga';
|
||||||
|
}
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--bookmark-width: 10em;
|
||||||
|
--bookmark-height: 10em;
|
||||||
|
--bookmark-margin: 0.5em;
|
||||||
|
--bookmark-padding: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
html, body {
|
||||||
|
width: 100%;
|
||||||
|
min-height: 100vh;
|
||||||
|
font-size: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
background-color: #2b2a33;
|
||||||
|
}
|
||||||
|
|
||||||
|
main {
|
||||||
|
width: 100%;
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
#main-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
#bookmark-container {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: center;
|
||||||
|
align-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#search {
|
||||||
|
margin: 3em auto;
|
||||||
|
max-width: calc(100% - 2em);
|
||||||
|
}
|
||||||
|
|
||||||
|
#search form {
|
||||||
|
--input-font-size: 1.2em;
|
||||||
|
--width: 30rem;
|
||||||
|
--height: 2.5rem;
|
||||||
|
|
||||||
|
position: relative;
|
||||||
|
display: block;
|
||||||
|
width: var(--width);
|
||||||
|
height: var(--height);
|
||||||
|
|
||||||
|
max-width: 100%;
|
||||||
|
|
||||||
|
background-color: rgba(0, 0, 0, 0.5);
|
||||||
|
border: 1px solid black;
|
||||||
|
border-radius: 0.25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
#search form input[type="search"] {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
display: inline-block;
|
||||||
|
width: calc(100% - var(--height));
|
||||||
|
height: var(--height);
|
||||||
|
border: 0;
|
||||||
|
padding: 0 0.5em;
|
||||||
|
box-sizing: border-box;
|
||||||
|
outline: 0;
|
||||||
|
color: inherit;
|
||||||
|
background-color: transparent;
|
||||||
|
transition: all 0.2s ease-in-out;
|
||||||
|
font-size: var(--input-font-size);
|
||||||
|
}
|
||||||
|
|
||||||
|
#search form label[for="submit"] {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
display: inline-block;
|
||||||
|
width: var(--height);
|
||||||
|
height: var(--height);
|
||||||
|
margin-left: 0;
|
||||||
|
margin-right: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
transition: all 0.2s ease-in-out;
|
||||||
|
font-size: var(--input-font-size);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
#search form label[for="submit"] span {
|
||||||
|
transform: translate(0.3em, 0.3em);
|
||||||
|
}
|
||||||
|
|
||||||
|
#search form input[type="submit"] {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bookmark {
|
||||||
|
display: block;
|
||||||
|
box-sizing: border-box;
|
||||||
|
transition: all 0.2s ease-in-out;
|
||||||
|
|
||||||
|
width: var(--bookmark-width);
|
||||||
|
height: var(--bookmark-height);
|
||||||
|
margin: var(--bookmark-margin);
|
||||||
|
padding: var(--bookmark-padding);
|
||||||
|
border-radius: var(--bookmark-border-radius);
|
||||||
|
}
|
||||||
|
|
||||||
|
.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;
|
||||||
|
|
||||||
|
border-radius: var(--bookmark-border-radius);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 30em) {
|
||||||
|
.bookmark {
|
||||||
|
width: calc(var(--bookmark-width) * 0.5);
|
||||||
|
height: calc(var(--bookmark-height) * 0.5);
|
||||||
|
padding: calc(var(--bookmark-padding) * 0.5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#button {
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
top: 0.25em;
|
||||||
|
right: 0.5em;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
#customize-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.customizer {
|
||||||
|
margin: 1em;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
background-color: rgba(255, 255, 255, 0.15);
|
||||||
|
border-radius: 0.25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.customizer > form {
|
||||||
|
margin: 0.5em;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: auto auto;
|
||||||
|
grid-auto-rows: max-content;
|
||||||
|
gap: 0.25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
form label {
|
||||||
|
margin-right: 0.25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.customizer > form input {
|
||||||
|
background-color: rgba(0, 0, 0, 0.25);
|
||||||
|
border: 1px solid black;
|
||||||
|
color: inherit;
|
||||||
|
padding: 0.25em;
|
||||||
|
border-radius: 0.2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.customizer > form input:not([type="checkbox"]):not([type="file"]):not([type="color"]):focus {
|
||||||
|
outline-style: solid;
|
||||||
|
outline-color: #aaa;
|
||||||
|
}
|
||||||
|
|
||||||
|
#add-bookmark {
|
||||||
|
margin: 1em;
|
||||||
|
color: white;
|
||||||
|
background-color: darkgreen;
|
||||||
|
text-align: center;
|
||||||
|
border-radius: 0.25em;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.25s ease-in-out;
|
||||||
|
|
||||||
|
width: 618px;
|
||||||
|
height: 259px;
|
||||||
|
line-height: 259px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#add-bookmark:hover,
|
||||||
|
#add-bookmark:focus {
|
||||||
|
background-color: green;
|
||||||
|
transition: all 0.25s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
#add-bookmark .material-icons {
|
||||||
|
font-size: 8em;
|
||||||
|
line-height: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.delete {
|
||||||
|
background-color: #cc0000;
|
||||||
|
color: white;
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0.5em;
|
||||||
|
left: 0.5em;
|
||||||
|
width: 2em;
|
||||||
|
height: 2em;
|
||||||
|
text-align: center;
|
||||||
|
border-radius: 0.25em;
|
||||||
|
box-shadow: 0px 0px 3px #333;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.25s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.delete:hover,
|
||||||
|
.delete:focus {
|
||||||
|
transform: scale(1.25);
|
||||||
|
transition: all 0.25s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fixed {
|
||||||
|
position: fixed !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#top-panel {
|
||||||
|
background-color: rgba(255, 255, 255, 0.15);
|
||||||
|
padding: 1em;
|
||||||
|
border-bottom: 1px solid black;
|
||||||
|
}
|
||||||
|
|
||||||
|
#top-panel h1 {
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
#top-panel > form {
|
||||||
|
max-width: 30em;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: auto auto;
|
||||||
|
grid-auto-rows: max-content;
|
||||||
|
gap: 0.25em;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
#top-panel > form input {
|
||||||
|
background-color: rgba(0, 0, 0, 0.25);
|
||||||
|
border: 1px solid black;
|
||||||
|
color: inherit;
|
||||||
|
padding: 0.25em;
|
||||||
|
border-radius: 0.2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
#top-panel > form input:not([type="checkbox"]):not([type="file"]):not([type="color"]):focus {
|
||||||
|
outline-style: solid;
|
||||||
|
outline-color: #aaa;
|
||||||
|
}
|
||||||
|
|
||||||
|
#top-panel > form > * {
|
||||||
|
display: block;
|
||||||
|
}
|
@ -1,3 +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 }}'>
|
<a href="{{ .Link }}" class="bookmark" style='background-color: {{ .GetColor }}; {{ 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>
|
<div class="background" style='background-image: url("{{ .Image }}"); background-size: {{ .GetImageSize }}'></div>
|
||||||
</a>
|
</a>
|
||||||
|
33
templates/customize-bookmark.html
Normal file
33
templates/customize-bookmark.html
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
<div class="customizer">
|
||||||
|
<a href="{{ .Link }}" class="bookmark" style='background-color: {{ .GetColor }}; {{ 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: {{ .GetImageSize }}'></div>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a class="delete"><span class="material-icons">delete</span></a>
|
||||||
|
|
||||||
|
<form>
|
||||||
|
<label for="bookmark-name">{{ .Translate "Name" }}</label>
|
||||||
|
<input type="text" id="bookmark-name" name="bookmark-name" value="{{ .Title }}" />
|
||||||
|
|
||||||
|
<label for="bookmark-link">{{ .Translate "Link" }}</label>
|
||||||
|
<input type="url" id="bookmark-link" name="bookmark-link" value="{{ .Link }}" />
|
||||||
|
|
||||||
|
<label for="bookmark-image">{{ .Translate "Image" }}</label>
|
||||||
|
<input type="url" id="bookmark-image" name="bookmark-image" value="{{ .Image }}" />
|
||||||
|
|
||||||
|
<label for="bookmark-imagesize">{{ .Translate "Image size" }}</label>
|
||||||
|
<input list="image-sizes" id="bookmark-imagesize" name="bookmark-imagesize" value="{{ .ImageSize }}" />
|
||||||
|
|
||||||
|
<label for="bookmark-iconpadding">{{ .Translate "Image padding" }}</label>
|
||||||
|
<input list="image-paddings" id="bookmark-iconpadding" name="bookmark-iconpadding" value="{{ .IconPadding }}" />
|
||||||
|
|
||||||
|
<label for="bookmark-color">{{ .Translate "Color" }}</label>
|
||||||
|
<input type="color" id="bookmark-color" name="bookmark-color" value="{{ .Color }}" />
|
||||||
|
|
||||||
|
<label for="bookmark-border">{{ .Translate "Hide border" }}</label>
|
||||||
|
<input type="checkbox" id="bookmark-border" name="bookmark-border" {{ if .HideBorder }} checked {{ end }} />
|
||||||
|
|
||||||
|
<label for="bookmark-order">{{ .Translate "Order priority" }}</label>
|
||||||
|
<input type="number" id="bookmark-order" name="bookmark-order" value="{{ .Order }}" />
|
||||||
|
</form>
|
||||||
|
</div>
|
70
templates/customize.html
Normal file
70
templates/customize.html
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<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 "Customize Homepage" }}</title>
|
||||||
|
<link rel="stylesheet" type="text/css" href="/style.css" />
|
||||||
|
<script src="/customize.js"></script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
:root {
|
||||||
|
--bookmark-border-radius: {{ .Settings.BorderRadius }};
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
background-color: {{ .Settings.Background }};
|
||||||
|
color: {{ .Settings.Foreground }};
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<datalist id="image-sizes">
|
||||||
|
<option value="cover">cover</option>
|
||||||
|
<option value="contain">contain</option>
|
||||||
|
<option value="100%">100%</option>
|
||||||
|
<option value="0px">0px</option>
|
||||||
|
</datalist>
|
||||||
|
<datalist id="image-paddings">
|
||||||
|
<option value="10%">10%</option>
|
||||||
|
<option value="0px">0px</option>
|
||||||
|
<option value="10px">10px</option>
|
||||||
|
<option value="1em">1em</option>
|
||||||
|
</datalist>
|
||||||
|
<datalist id="search-strings">
|
||||||
|
<option value="https://www.google.de/search?q=%s">Google</option>
|
||||||
|
<option value="https://duckduckgo.com/?q=%s">DuckDuckGo</option>
|
||||||
|
<option value="https://www.startpage.com/do/search?query=%s">Startpage</option>
|
||||||
|
<option value="https://www.bing.com/search?q=%s">Bing</option>
|
||||||
|
<option value="https://de.search.yahoo.com/search?p=%s">Yahoo</option>
|
||||||
|
</datalist>
|
||||||
|
<main>
|
||||||
|
<a id="button" class="fixed" href="#">
|
||||||
|
<span class="material-icons">save</span>
|
||||||
|
</a>
|
||||||
|
<div id="top-panel">
|
||||||
|
<h1>{{ .Translate "Settings" }}</h1>
|
||||||
|
<form>
|
||||||
|
<label for="search-string">{{ .Translate "Search engine" }}</label>
|
||||||
|
<input list="search-strings" id="search-string" name="search-string" value="{{ .Settings.Search }}" />
|
||||||
|
|
||||||
|
<label for="bg-color">{{ .Translate "Background color" }}</label>
|
||||||
|
<input type="color" id="bg-color" name="bg-color" value="{{ .Settings.Background }}" />
|
||||||
|
|
||||||
|
<label for="fg-color">{{ .Translate "Foreground color" }}</label>
|
||||||
|
<input type="color" id="fg-color" name="fg-color" value="{{ .Settings.Foreground }}" />
|
||||||
|
|
||||||
|
<label for="border-radius">{{ .Translate "Border radius" }}</label>
|
||||||
|
<input type="text" id="border-radius" name="border-radius" value="{{ .Settings.BorderRadius }}" />
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<section id="customize-container">
|
||||||
|
{{ range .Bookmarks }}
|
||||||
|
{{ template "customize-bookmark.html" . }}
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
<a id="add-bookmark"><span class="material-icons">add</span></a>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -6,11 +6,24 @@
|
|||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>{{ .Translate "Homepage" }}</title>
|
<title>{{ .Translate "Homepage" }}</title>
|
||||||
<link rel="stylesheet" type="text/css" href="style.css" />
|
<link rel="stylesheet" type="text/css" href="/style.css" />
|
||||||
|
|
||||||
|
<style>
|
||||||
|
:root {
|
||||||
|
--bookmark-border-radius: {{ .Settings.BorderRadius }};
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
background-color: {{ .Settings.Background }};
|
||||||
|
color: {{ .Settings.Foreground }};
|
||||||
|
}
|
||||||
|
</style>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<main>
|
<main id="main-container">
|
||||||
|
<a id="button" href="/customize">
|
||||||
|
<span class="material-icons">settings</span>
|
||||||
|
</a>
|
||||||
<section id="search">
|
<section id="search">
|
||||||
<form method="post" action="/search">
|
<form method="post" action="/search">
|
||||||
<datalist id="bookmarks">
|
<datalist id="bookmarks">
|
||||||
@ -31,4 +44,4 @@
|
|||||||
</main>
|
</main>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
@ -1,175 +0,0 @@
|
|||||||
@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%;
|
|
||||||
min-height: 100vh;
|
|
||||||
font-size: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
background-color: {{ .Background }};
|
|
||||||
}
|
|
||||||
|
|
||||||
main {
|
|
||||||
width: 100%;
|
|
||||||
min-height: 100vh;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: center;
|
|
||||||
margin-bottom: 0.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
#bookmark-container {
|
|
||||||
width: 100%;
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
justify-content: center;
|
|
||||||
align-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
#search {
|
|
||||||
margin: 3em auto;
|
|
||||||
max-width: calc(100% - 2em);
|
|
||||||
}
|
|
||||||
|
|
||||||
#search form {
|
|
||||||
--input-font-size: 1.2em;
|
|
||||||
--width: 30rem;
|
|
||||||
--height: 2.5rem;
|
|
||||||
|
|
||||||
position: relative;
|
|
||||||
display: block;
|
|
||||||
width: var(--width);
|
|
||||||
height: var(--height);
|
|
||||||
|
|
||||||
max-width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
#search form input[type="search"] {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
display: inline-block;
|
|
||||||
width: calc(100% - var(--height));
|
|
||||||
height: var(--height);
|
|
||||||
border: 1px solid black;
|
|
||||||
padding: 0 0.5em;
|
|
||||||
box-sizing: border-box;
|
|
||||||
outline: 0;
|
|
||||||
background-color: black;
|
|
||||||
color: white;
|
|
||||||
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"] {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
right: 0;
|
|
||||||
display: inline-block;
|
|
||||||
width: var(--height);
|
|
||||||
height: var(--height);
|
|
||||||
margin-left: 0;
|
|
||||||
border: 1px solid black;
|
|
||||||
box-sizing: border-box;
|
|
||||||
background-color: black;
|
|
||||||
color: white;
|
|
||||||
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"] span {
|
|
||||||
transform: translate(0.3em, 0.3em);
|
|
||||||
}
|
|
||||||
|
|
||||||
#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;
|
|
||||||
|
|
||||||
border-radius: {{ .BorderRadius }};
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (max-width: 30em) {
|
|
||||||
.bookmark {
|
|
||||||
width: calc({{ .IconWidth }} * 0.5);
|
|
||||||
height: calc({{ .IconHeight }} * 0.5);
|
|
||||||
padding: calc({{ .IconPadding }} * 0.5);
|
|
||||||
}
|
|
||||||
}
|
|
27
text.go
27
text.go
@ -22,22 +22,37 @@ var (
|
|||||||
Languages = map[language.Tag]Text{
|
Languages = map[language.Tag]Text{
|
||||||
language.English: {
|
language.English: {
|
||||||
Strings: map[string]string{
|
Strings: map[string]string{
|
||||||
"Homepage": "Homepage",
|
"Homepage": "Homepage",
|
||||||
"Search": "Search",
|
"Search": "Search",
|
||||||
|
"Search engine": "Search engine",
|
||||||
|
"Settings": "Settings",
|
||||||
|
"Background color": "Background color",
|
||||||
|
"Foreground color": "Foreground color",
|
||||||
|
"Border radius": "Border radius",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
language.German: {
|
language.German: {
|
||||||
Strings: map[string]string{
|
Strings: map[string]string{
|
||||||
"Homepage": "Homepage",
|
"Homepage": "Homepage",
|
||||||
"Search": "Suche",
|
"Search": "Suche",
|
||||||
|
"Search engine": "Suchmaschine",
|
||||||
|
"Settings": "Einstellungen",
|
||||||
|
"Background color": "Hintergrundfarbe",
|
||||||
|
"Foreground color": "Textfarbe",
|
||||||
|
"Border radius": "Randradius",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
language.Japanese: {
|
language.Japanese: {
|
||||||
Strings: map[string]string{
|
Strings: map[string]string{
|
||||||
"Homepage": "ホームページ",
|
"Homepage": "ホームページ",
|
||||||
"Search": "検索",
|
"Search": "検索",
|
||||||
|
"Search engine": "検索エンジン",
|
||||||
|
"Settings": "設定",
|
||||||
|
"Background color": "背景色",
|
||||||
|
"Foreground color": "描画色",
|
||||||
|
"Border radius": "境界半径",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
23
tmpl_data.go
23
tmpl_data.go
@ -13,3 +13,26 @@ func (d *TmplData) Translate(str string) string {
|
|||||||
func (d *TmplData) Language() string {
|
func (d *TmplData) Language() string {
|
||||||
return d.text.Language
|
return d.text.Language
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type CustomizeData struct {
|
||||||
|
text *Text
|
||||||
|
Bookmarks []BookmarkData
|
||||||
|
Settings *Settings
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *CustomizeData) Translate(str string) string {
|
||||||
|
return d.text.Translate(str)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *CustomizeData) Language() string {
|
||||||
|
return d.text.Language
|
||||||
|
}
|
||||||
|
|
||||||
|
type BookmarkData struct {
|
||||||
|
*Bookmark
|
||||||
|
text *Text
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bd *BookmarkData) Translate(str string) string {
|
||||||
|
return bd.text.Translate(str)
|
||||||
|
}
|
||||||
|
35
utils.go
Normal file
35
utils.go
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gorilla/sessions"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Must[T any](value T, err error) T {
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetValue[K any, T any](session *sessions.Session, key K) (T, bool) {
|
||||||
|
value, ok := session.Values[key]
|
||||||
|
if !ok && value == nil {
|
||||||
|
return *new(T), false
|
||||||
|
}
|
||||||
|
|
||||||
|
castedValue, ok := value.(T)
|
||||||
|
if !ok {
|
||||||
|
return *new(T), false
|
||||||
|
}
|
||||||
|
|
||||||
|
return castedValue, true
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetValueDefault[K any, T any](session *sessions.Session, key K, defaultValue T) T {
|
||||||
|
v, ok := GetValue[K, T](session, key)
|
||||||
|
if !ok {
|
||||||
|
return defaultValue
|
||||||
|
}
|
||||||
|
|
||||||
|
return v
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user