Compare commits
No commits in common. "7b5d816992fe26594fbfbedfd46baef708b9d1ca" and "42a96cbb6e81d509d218a36d4cf78fe68742d11e" have entirely different histories.
7b5d816992
...
42a96cbb6e
14 changed files with 53 additions and 196 deletions
7
.gitignore
vendored
7
.gitignore
vendored
|
@ -172,10 +172,3 @@ dist
|
||||||
.svelte-kit
|
.svelte-kit
|
||||||
|
|
||||||
# End of https://www.toptal.com/developers/gitignore/api/node
|
# End of https://www.toptal.com/developers/gitignore/api/node
|
||||||
|
|
||||||
# Test files
|
|
||||||
public/
|
|
||||||
config.json
|
|
||||||
legal.html
|
|
||||||
test.html
|
|
||||||
test.json
|
|
||||||
|
|
138
README.md
138
README.md
|
@ -1,7 +1,8 @@
|
||||||
# Now
|
# Now
|
||||||
Self-hostable bio page website, like carrd, guns.lol and many more!
|
|
||||||
|
|
||||||
Lightweight and heavily customizable Go application.
|
Self-hostable bio page website!
|
||||||
|
|
||||||
|
Lightweight and heavily customizable Go application!
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
@ -10,139 +11,8 @@ Lightweight and heavily customizable Go application.
|
||||||

|

|
||||||
|
|
||||||
## Config
|
## Config
|
||||||
You must have a `public` directory.
|
|
||||||
Everything located inside will be available at the path `/static/PATH` where `PATH` is the relative path inside the
|
|
||||||
`public` directory.
|
|
||||||
|
|
||||||
You can change the font by adding a file named `font.woff2` inside the `public` directory.
|
Coming soon
|
||||||
This font must be compressed by [Woff2](https://en.wikipedia.org/wiki/Web_Open_Font_Format).
|
|
||||||
(You can compress them with the command `woff2_compress` available in the package `woff2` of many Linux distributions.)
|
|
||||||
|
|
||||||
### Main config
|
|
||||||
You can create a sample config with the flag `-generate-json-config` (which generates a JSON config) or with
|
|
||||||
`-generate-toml-config` (which generates a TOML config).
|
|
||||||
A JSON schema is available for JSON configs.
|
|
||||||
|
|
||||||
The config does not depend on the markup language: a field `foo` will being named `foo` for JSON and TOML.
|
|
||||||
The TOML format is used in this section.
|
|
||||||
|
|
||||||
The root is defining the background image, the description, the file's path to the legal pages, the path to
|
|
||||||
the configs of custom pages and a list of all your ["rel-me"](https://microformats.org/wiki/rel-me) links.
|
|
||||||
(The "rel-me" links are required to
|
|
||||||
[verify a link on your Mastodon account](https://docs.joinmastodon.org/user/profile/#verification), for example.)
|
|
||||||
```toml
|
|
||||||
image = "wallpaper.webp"
|
|
||||||
description = "I am a beautiful description!"
|
|
||||||
legal = "legal.html"
|
|
||||||
custom_pages = ["custom.toml"]
|
|
||||||
rel_me_links = ["https://foo.example.org/@bar"]
|
|
||||||
```
|
|
||||||
The path is relative to the execution of the binary.
|
|
||||||
If you are using Docker, please use a static path.
|
|
||||||
|
|
||||||
The first section is defining who you are.
|
|
||||||
`image` is your pfp.
|
|
||||||
It must be placed inside the `public` directory.
|
|
||||||
```toml
|
|
||||||
[person]
|
|
||||||
name = "John Doe"
|
|
||||||
pronouns = "any"
|
|
||||||
image = "pfp.webp"
|
|
||||||
|
|
||||||
[[person.tags]]
|
|
||||||
name = "Hello"
|
|
||||||
description = "World"
|
|
||||||
link = ""
|
|
||||||
|
|
||||||
[[person.tags]]
|
|
||||||
name = "I am"
|
|
||||||
description = "a tag"
|
|
||||||
link = ""
|
|
||||||
```
|
|
||||||
|
|
||||||
Then, you define the colors of the main page.
|
|
||||||
`text` is the text's color.
|
|
||||||
`tag_hover` is the background's color of a tag when someone hover it.
|
|
||||||
`colors.background` defines the card's background (check the CSS property `gradiant` on
|
|
||||||
[MDN](https://developer.mozilla.org/en-US/docs/Web/CSS/gradient) to have more information).
|
|
||||||
`colors.buttons` defines buttons' colors.
|
|
||||||
```toml
|
|
||||||
[colors]
|
|
||||||
text = "#fff"
|
|
||||||
tag_hover = "#000"
|
|
||||||
[colors.background]
|
|
||||||
type = "linear"
|
|
||||||
angle = 141
|
|
||||||
|
|
||||||
[[colors.background.colors]]
|
|
||||||
color = "#a4a2b8"
|
|
||||||
position = 0
|
|
||||||
|
|
||||||
[[colors.background.colors]]
|
|
||||||
color = "#3b3860"
|
|
||||||
position = 40
|
|
||||||
|
|
||||||
[[colors.background.colors]]
|
|
||||||
color = "#0f0c2c"
|
|
||||||
position = 80
|
|
||||||
[colors.buttons]
|
|
||||||
text = "#4c0850"
|
|
||||||
text_hover = "#57145b"
|
|
||||||
background = "#f399d0"
|
|
||||||
background_hover = "#f5c0e0"
|
|
||||||
```
|
|
||||||
|
|
||||||
Finally, you define the link at the bottom of your card.
|
|
||||||
You can have as much of these as you want.
|
|
||||||
```toml
|
|
||||||
[[links]]
|
|
||||||
link = "/foo"
|
|
||||||
content = "Blog"
|
|
||||||
|
|
||||||
[[links]]
|
|
||||||
link = "https://www.youtube.com/@anhgelus"
|
|
||||||
content = "YouTube"
|
|
||||||
```
|
|
||||||
|
|
||||||
### Custom page config
|
|
||||||
You can create custom pages with a new config.
|
|
||||||
It can also be a JSON or a TOML file.
|
|
||||||
|
|
||||||
The root defines the title of the page, the uri (must be unique!), the image and the description.
|
|
||||||
`content` is the file's path containing the content of your custom page.
|
|
||||||
```toml
|
|
||||||
title = "Foo"
|
|
||||||
uri = "/bar"
|
|
||||||
image = "wallpaper.webp"
|
|
||||||
description = "I am a beautiful description!"
|
|
||||||
content = "foo-bar.html"
|
|
||||||
```
|
|
||||||
|
|
||||||
Then, you can define custom colors.
|
|
||||||
Check _Main config_'s colors section for more information.
|
|
||||||
The `tag_hover` field is useless here.
|
|
||||||
|
|
||||||
### HTML content files
|
|
||||||
When you define a custom page or when you have to set the legal information, you have to specify the path of an HTML
|
|
||||||
file.
|
|
||||||
It contains the content that would be displayed in the page.
|
|
||||||
You can use all HTML common tags like `h2`, `p` and `a`.
|
|
||||||
(`h1` is already used by the title.)
|
|
||||||
|
|
||||||
If you want to use buttons, you must follow this structure:
|
|
||||||
```html
|
|
||||||
<nav class="links">
|
|
||||||
<div class="link">
|
|
||||||
<a href="/">home sweet home</a>
|
|
||||||
</div>
|
|
||||||
<div class="link">
|
|
||||||
<a href="/foo">Bar</a>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
```
|
|
||||||
Their style is defined by the config.
|
|
||||||
You can change their style by defining these CSS variables `--text-color`, `--text-color-hover`, `--background` and
|
|
||||||
`--background-hover`.
|
|
||||||
|
|
||||||
## Technologies used
|
## Technologies used
|
||||||
|
|
||||||
|
|
|
@ -160,9 +160,6 @@
|
||||||
},
|
},
|
||||||
"custom_pages": {
|
"custom_pages": {
|
||||||
"type": "array"
|
"type": "array"
|
||||||
},
|
|
||||||
"rel_me_links": {
|
|
||||||
"type": "array"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
|
|
22
data.go
22
data.go
|
@ -7,13 +7,17 @@ import (
|
||||||
"github.com/anhgelus/golatt"
|
"github.com/anhgelus/golatt"
|
||||||
"html/template"
|
"html/template"
|
||||||
"os"
|
"os"
|
||||||
"regexp"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
const (
|
||||||
regexExternalLink = regexp.MustCompile(`https?://`)
|
TitleContentType = "title"
|
||||||
|
SubtitleContentType = "subtitle"
|
||||||
|
ParagraphContentType = "paragraph"
|
||||||
|
ListContentType = "list"
|
||||||
|
OrderedListContentType = "ordered_list"
|
||||||
|
ButtonsContentType = "links"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ConfigData interface {
|
type ConfigData interface {
|
||||||
|
@ -30,7 +34,6 @@ type Config struct {
|
||||||
Color *Color `json:"colors" toml:"colors"`
|
Color *Color `json:"colors" toml:"colors"`
|
||||||
Links []*Link `json:"links" toml:"links"`
|
Links []*Link `json:"links" toml:"links"`
|
||||||
Legal string `json:"legal" toml:"legal"`
|
Legal string `json:"legal" toml:"legal"`
|
||||||
RelMeLinks []string `json:"rel_me_links" toml:"rel_me_links"`
|
|
||||||
CustomPages []string `json:"custom_pages" toml:"custom_pages"`
|
CustomPages []string `json:"custom_pages" toml:"custom_pages"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,19 +78,12 @@ type Link struct {
|
||||||
Content string `json:"content" toml:"content"`
|
Content string `json:"content" toml:"content"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func getImage(s string) string {
|
|
||||||
if regexExternalLink.MatchString(s) {
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
return golatt.GetStaticPath(s)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Config) GetBackground() template.CSS {
|
func (c *Config) GetBackground() template.CSS {
|
||||||
return c.Color.GetBackground()
|
return c.Color.GetBackground()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Config) GetBackgroundImage() template.CSS {
|
func (c *Config) GetBackgroundImage() template.CSS {
|
||||||
return template.CSS("--background-image: url(" + getImage(c.Image) + ");")
|
return template.CSS("--background-image: url(" + golatt.GetStaticPath(c.Image) + ");")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Config) GetTextColor() template.CSS {
|
func (c *Config) GetTextColor() template.CSS {
|
||||||
|
@ -180,7 +176,7 @@ func (p *CustomPage) GetTextColor() template.CSS {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *CustomPage) GetBackgroundImage() template.CSS {
|
func (p *CustomPage) GetBackgroundImage() template.CSS {
|
||||||
return template.CSS("--background-image: url(" + getImage(p.Image) + ");")
|
return template.CSS("--background-image: url(" + golatt.GetStaticPath(p.Image) + ");")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *CustomPage) GetBackground() template.CSS {
|
func (p *CustomPage) GetBackground() template.CSS {
|
||||||
|
|
BIN
games.webp
Normal file
BIN
games.webp
Normal file
Binary file not shown.
After Width: | Height: | Size: 99 KiB |
20
main.go
20
main.go
|
@ -7,7 +7,6 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/BurntSushi/toml"
|
"github.com/BurntSushi/toml"
|
||||||
"github.com/anhgelus/golatt"
|
"github.com/anhgelus/golatt"
|
||||||
"html/template"
|
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
@ -24,19 +23,17 @@ var (
|
||||||
var (
|
var (
|
||||||
domain string
|
domain string
|
||||||
configPath string
|
configPath string
|
||||||
dev bool = false
|
dev bool
|
||||||
generateToml bool
|
generateToml bool
|
||||||
generateJson bool
|
generateJson bool
|
||||||
port int = 80
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
flag.StringVar(&domain, "domain", "", "domain to use")
|
flag.StringVar(&domain, "domain", "", "domain to use")
|
||||||
flag.StringVar(&configPath, "config", "", "config to use")
|
flag.StringVar(&configPath, "config", "", "config to use")
|
||||||
flag.BoolVar(&dev, "dev", dev, "dev mode enabled")
|
flag.BoolVar(&dev, "dev", false, "dev mode enabled")
|
||||||
flag.BoolVar(&generateJson, "generate-json-config", false, "generate a config example")
|
flag.BoolVar(&generateJson, "generate-json-config", false, "generate a config example")
|
||||||
flag.BoolVar(&generateToml, "generate-toml-config", false, "generate a config example")
|
flag.BoolVar(&generateToml, "generate-toml-config", false, "generate a config example")
|
||||||
flag.IntVar(&port, "port", port, "set the port to use")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
@ -128,19 +125,11 @@ func main() {
|
||||||
http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
|
http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
|
||||||
}
|
}
|
||||||
|
|
||||||
g.TemplateFuncMap = template.FuncMap{
|
|
||||||
"getImage": getImage,
|
|
||||||
}
|
|
||||||
|
|
||||||
host := fmt.Sprintf(":%d", port)
|
|
||||||
if dev {
|
if dev {
|
||||||
if port != 80 {
|
slog.Info("Starting on http://localhost:8000/")
|
||||||
g.StartServer(host)
|
|
||||||
} else {
|
|
||||||
g.StartServer(":8000")
|
g.StartServer(":8000")
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
g.StartServer(host)
|
g.StartServer(":80")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -185,7 +174,6 @@ func generateConfigFile(isToml bool) {
|
||||||
},
|
},
|
||||||
Legal: "legal.html",
|
Legal: "legal.html",
|
||||||
CustomPages: []string{"custom.json"},
|
CustomPages: []string{"custom.json"},
|
||||||
RelMeLinks: []string{"https://foo.example.org/@bar"},
|
|
||||||
}
|
}
|
||||||
var b []byte
|
var b []byte
|
||||||
var err error
|
var err error
|
||||||
|
|
BIN
music.webp
Normal file
BIN
music.webp
Normal file
Binary file not shown.
After Width: | Height: | Size: 135 KiB |
|
@ -4,7 +4,6 @@
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
--text-color: #000;
|
--text-color: #000;
|
||||||
font-size: 18px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
|
@ -14,12 +13,13 @@
|
||||||
|
|
||||||
body {
|
body {
|
||||||
--background-image: ;
|
--background-image: ;
|
||||||
font-family: "custom", Raveo, Inter, Roboto, sans-serif;
|
font-size: 18px;
|
||||||
background: #000;
|
font-family: "custom", "serif";
|
||||||
|
background: var(--background-image) center fixed no-repeat;
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
color: var(--text-color);
|
color: var(--text-color);
|
||||||
@media only screen and (min-width: vars.$bp-little) {
|
@media only screen and (max-width: vars.$bp-little) {
|
||||||
background: var(--background-image) center fixed no-repeat black;
|
background: #000;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,23 +101,23 @@ p {
|
||||||
}
|
}
|
||||||
|
|
||||||
h1 {
|
h1 {
|
||||||
font-size: 1.75rem;
|
font-size: 3rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
h2 {
|
h2 {
|
||||||
font-size: 1.5rem;
|
font-size: 2rem;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
@media only screen and (max-width: vars.$bp-little) {
|
@media only screen and (max-width: vars.$bp-little) {
|
||||||
font-size: 1.425rem;
|
font-size: 1.75rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
h3 {
|
h3 {
|
||||||
font-size: 1.35rem;
|
font-size: 1.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
h4 {
|
h4 {
|
||||||
font-size: 1.25rem;
|
font-size: 1.35rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
ul, ol {
|
ul, ol {
|
||||||
|
|
|
@ -12,10 +12,6 @@
|
||||||
<style>
|
<style>
|
||||||
.links { {{ .Data.Color.Button.GetBackground }}{{ .Data.Color.Button.GetTextColor }} }
|
.links { {{ .Data.Color.Button.GetBackground }}{{ .Data.Color.Button.GetTextColor }} }
|
||||||
</style>
|
</style>
|
||||||
{{ else }}
|
|
||||||
{{ range .Data.RelMeLinks }}
|
|
||||||
<link rel="me" href="{{ . }}" />
|
|
||||||
{{ end }}
|
|
||||||
{{ end }}
|
{{ end }}
|
||||||
</head>
|
</head>
|
||||||
<body style="{{ .Data.GetBackgroundImage }}{{ .Data.GetTextColor }}">
|
<body style="{{ .Data.GetBackgroundImage }}{{ .Data.GetTextColor }}">
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{{define "body"}}
|
{{define "body"}}
|
||||||
<main class="custom-page" style="{{ .GetBackground }}">
|
<main class="custom-page" style="{{ .GetBackground }}">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<h1 class="header__title">{{ .Title }}</h1>
|
<h2 class="header__title">{{ .Title }}</h2>
|
||||||
<nav>
|
<nav>
|
||||||
<a href="/">Home</a>
|
<a href="/">Home</a>
|
||||||
<a href="/tags">Tags</a>
|
<a href="/tags">Tags</a>
|
||||||
|
|
|
@ -2,10 +2,10 @@
|
||||||
<main style="{{ .GetBackground }}">
|
<main style="{{ .GetBackground }}">
|
||||||
<div class="presentation">
|
<div class="presentation">
|
||||||
<figure>
|
<figure>
|
||||||
<img src="{{ getImage .Person.Image }}" alt="{{ .Person.Name }}'s image">
|
<img src="{{ getStaticPath .Person.Image }}" alt="{{ .Person.Name }}'s image">
|
||||||
</figure>
|
</figure>
|
||||||
<div class="presentation__information">
|
<div class="presentation__information">
|
||||||
<h1>{{ .Person.Name }}</h1>
|
<h2>{{ .Person.Name }}</h2>
|
||||||
<p>{{ .Person.Pronouns }}</p>
|
<p>{{ .Person.Pronouns }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
{{define "body"}}
|
{{define "body"}}
|
||||||
<div class="credits-legal" style="{{ .GetBackground }}">
|
<div class="credits-legal" style="{{ .GetBackground }}">
|
||||||
<h1>Legal information</h1>
|
<h2>Legal information</h2>
|
||||||
<p>
|
<p>
|
||||||
The software behind this website was made by <a href="https://anhgelus.world/" target="_blank">Anhgelus Morhtuuzh</a>.
|
The software behind this website was made by <a href="https://www.anhgelus.world/" target="_blank">Anhgelus Morhtuuzh</a>.
|
||||||
It is available on <a href="https://github.com/anhgelus/now">GitHub</a> for free and licensed under the
|
It is available on <a href="https://github.com/anhgelus/now">GitHub</a> for free and licensed under the
|
||||||
<a href="https://github.com/anhgelus/now/blob/main/LICENSE" target="_blank">AGPL</a> license.
|
<a href="https://github.com/anhgelus/now/blob/main/LICENSE" target="_blank">AGPL</a> license.
|
||||||
</p>
|
</p>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{{define "body"}}
|
{{define "body"}}
|
||||||
<main style="{{ .GetBackground }}">
|
<main style="{{ .GetBackground }}">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<h1 class="header__title">Tags</h1>
|
<h2 class="header__title">Tags</h2>
|
||||||
<nav>
|
<nav>
|
||||||
<a href="/">Home</a>
|
<a href="/">Home</a>
|
||||||
</nav>
|
</nav>
|
||||||
|
@ -9,7 +9,7 @@
|
||||||
<div class="tags" style="{{ .Color.GetTagColor }}">
|
<div class="tags" style="{{ .Color.GetTagColor }}">
|
||||||
{{ range $tag := .Person.Tags }}
|
{{ range $tag := .Person.Tags }}
|
||||||
<div class="tag" data-href="{{ .Link }}" title="{{ .Link }}">
|
<div class="tag" data-href="{{ .Link }}" title="{{ .Link }}">
|
||||||
<h3>{{ .Name }}</h3>
|
<h4>{{ .Name }}</h4>
|
||||||
<p>{{ .Description }}</p>
|
<p>{{ .Description }}</p>
|
||||||
</div>
|
</div>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
|
17
test.html
Normal file
17
test.html
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
<h2>Hello</h2>
|
||||||
|
<p>world, what's up?</p>
|
||||||
|
<h3>Sed proin quis cursus do lobortis ultricies viverra tempus et.</h3>
|
||||||
|
<p>Lectus pulvinar lorem mi enim pharetra sed aliqua et cursus. Sit sem ut elit amet labore lectus sed at vulputate.</p>
|
||||||
|
<nav class="links">
|
||||||
|
<div class="link">
|
||||||
|
<a href="/">home sweet home</a>
|
||||||
|
</div>
|
||||||
|
<div class="link">
|
||||||
|
<a href="https://www.steampowered.com">steam</a>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
<ul>
|
||||||
|
<li>Hello 1</li>
|
||||||
|
<li>Not hello 2</li>
|
||||||
|
<li>Final element 3</li>
|
||||||
|
</ul>
|
Loading…
Add table
Add a link
Reference in a new issue