Compare commits

..

10 commits

Author SHA1 Message Date
7b5d816992
feat(style): modify root font-size for more consistent design 2025-08-15 14:15:16 +02:00
cc84579214
feat(style): better default background and better default fonts 2025-08-15 14:05:04 +02:00
b87964e81f
feat(config): supports external link for images 2025-08-01 12:54:51 +02:00
b7829c5268
feat(legal): update credit link 2025-07-30 18:41:29 +02:00
William Hergès
7b79fb02bb
fix(custom page): crash
disable rel me in these pages
2025-07-19 23:27:03 +02:00
William Hergès
f009b61110
feat(cli): option to set port 2025-07-19 23:06:15 +02:00
Anhgelus Morhtuuzh
e9e5325bf8
ci(git): ignore test files 2025-05-19 23:56:11 +02:00
Anhgelus Morhtuuzh
d7598a843e
feat(social): supports rel-me links 2025-05-19 23:55:02 +02:00
Anhgelus Morhtuuzh
cf36d7daa9
docs(info): fix various typo in readme 2025-03-10 11:45:52 +01:00
Anhgelus Morhtuuzh
17c7e46f3b
docs(info): add config section in readme 2025-03-10 11:42:48 +01:00
14 changed files with 196 additions and 53 deletions

7
.gitignore vendored
View file

@ -172,3 +172,10 @@ dist
.svelte-kit
# End of https://www.toptal.com/developers/gitignore/api/node
# Test files
public/
config.json
legal.html
test.html
test.json

138
README.md
View file

@ -1,8 +1,7 @@
# Now
Self-hostable bio page website, like carrd, guns.lol and many more!
Self-hostable bio page website!
Lightweight and heavily customizable Go application!
Lightweight and heavily customizable Go application.
![Screenshot of the main page](./example.jpg)
@ -11,8 +10,139 @@ Lightweight and heavily customizable Go application!
![Screenshot of a custom page](./games.webp)
## 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.
Coming soon
You can change the font by adding a file named `font.woff2` inside the `public` directory.
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

View file

@ -160,6 +160,9 @@
},
"custom_pages": {
"type": "array"
},
"rel_me_links": {
"type": "array"
}
},
"additionalProperties": false,

22
data.go
View file

@ -7,17 +7,13 @@ import (
"github.com/anhgelus/golatt"
"html/template"
"os"
"regexp"
"strconv"
"strings"
)
const (
TitleContentType = "title"
SubtitleContentType = "subtitle"
ParagraphContentType = "paragraph"
ListContentType = "list"
OrderedListContentType = "ordered_list"
ButtonsContentType = "links"
var (
regexExternalLink = regexp.MustCompile(`https?://`)
)
type ConfigData interface {
@ -34,6 +30,7 @@ type Config struct {
Color *Color `json:"colors" toml:"colors"`
Links []*Link `json:"links" toml:"links"`
Legal string `json:"legal" toml:"legal"`
RelMeLinks []string `json:"rel_me_links" toml:"rel_me_links"`
CustomPages []string `json:"custom_pages" toml:"custom_pages"`
}
@ -78,12 +75,19 @@ type Link struct {
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 {
return c.Color.GetBackground()
}
func (c *Config) GetBackgroundImage() template.CSS {
return template.CSS("--background-image: url(" + golatt.GetStaticPath(c.Image) + ");")
return template.CSS("--background-image: url(" + getImage(c.Image) + ");")
}
func (c *Config) GetTextColor() template.CSS {
@ -176,7 +180,7 @@ func (p *CustomPage) GetTextColor() template.CSS {
}
func (p *CustomPage) GetBackgroundImage() template.CSS {
return template.CSS("--background-image: url(" + golatt.GetStaticPath(p.Image) + ");")
return template.CSS("--background-image: url(" + getImage(p.Image) + ");")
}
func (p *CustomPage) GetBackground() template.CSS {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 99 KiB

22
main.go
View file

@ -7,6 +7,7 @@ import (
"fmt"
"github.com/BurntSushi/toml"
"github.com/anhgelus/golatt"
"html/template"
"log/slog"
"net/http"
"os"
@ -23,17 +24,19 @@ var (
var (
domain string
configPath string
dev bool
dev bool = false
generateToml bool
generateJson bool
port int = 80
)
func init() {
flag.StringVar(&domain, "domain", "", "domain to use")
flag.StringVar(&configPath, "config", "", "config to use")
flag.BoolVar(&dev, "dev", false, "dev mode enabled")
flag.BoolVar(&dev, "dev", dev, "dev mode enabled")
flag.BoolVar(&generateJson, "generate-json-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() {
@ -125,11 +128,19 @@ func main() {
http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
}
g.TemplateFuncMap = template.FuncMap{
"getImage": getImage,
}
host := fmt.Sprintf(":%d", port)
if dev {
slog.Info("Starting on http://localhost:8000/")
g.StartServer(":8000")
if port != 80 {
g.StartServer(host)
} else {
g.StartServer(":8000")
}
} else {
g.StartServer(":80")
g.StartServer(host)
}
}
@ -174,6 +185,7 @@ func generateConfigFile(isToml bool) {
},
Legal: "legal.html",
CustomPages: []string{"custom.json"},
RelMeLinks: []string{"https://foo.example.org/@bar"},
}
var b []byte
var err error

Binary file not shown.

Before

Width:  |  Height:  |  Size: 135 KiB

View file

@ -4,6 +4,7 @@
:root {
--text-color: #000;
font-size: 18px;
}
@font-face {
@ -13,13 +14,12 @@
body {
--background-image: ;
font-size: 18px;
font-family: "custom", "serif";
background: var(--background-image) center fixed no-repeat;
font-family: "custom", Raveo, Inter, Roboto, sans-serif;
background: #000;
background-size: cover;
color: var(--text-color);
@media only screen and (max-width: vars.$bp-little) {
background: #000;
@media only screen and (min-width: vars.$bp-little) {
background: var(--background-image) center fixed no-repeat black;
}
}
@ -101,23 +101,23 @@ p {
}
h1 {
font-size: 3rem;
font-size: 1.75rem;
}
h2 {
font-size: 2rem;
font-size: 1.5rem;
font-weight: bold;
@media only screen and (max-width: vars.$bp-little) {
font-size: 1.75rem;
font-size: 1.425rem;
}
}
h3 {
font-size: 1.5rem;
font-size: 1.35rem;
}
h4 {
font-size: 1.35rem;
font-size: 1.25rem;
}
ul, ol {

View file

@ -12,6 +12,10 @@
<style>
.links { {{ .Data.Color.Button.GetBackground }}{{ .Data.Color.Button.GetTextColor }} }
</style>
{{ else }}
{{ range .Data.RelMeLinks }}
<link rel="me" href="{{ . }}" />
{{ end }}
{{ end }}
</head>
<body style="{{ .Data.GetBackgroundImage }}{{ .Data.GetTextColor }}">
@ -24,4 +28,4 @@
<script type="module" src="{{getAssetPath "index.js"}}" defer></script>
</body>
</html>
{{end}}
{{end}}

View file

@ -1,7 +1,7 @@
{{define "body"}}
<main class="custom-page" style="{{ .GetBackground }}">
<div class="header">
<h2 class="header__title">{{ .Title }}</h2>
<h1 class="header__title">{{ .Title }}</h1>
<nav>
<a href="/">Home</a>
<a href="/tags">Tags</a>

View file

@ -2,10 +2,10 @@
<main style="{{ .GetBackground }}">
<div class="presentation">
<figure>
<img src="{{ getStaticPath .Person.Image }}" alt="{{ .Person.Name }}'s image">
<img src="{{ getImage .Person.Image }}" alt="{{ .Person.Name }}'s image">
</figure>
<div class="presentation__information">
<h2>{{ .Person.Name }}</h2>
<h1>{{ .Person.Name }}</h1>
<p>{{ .Person.Pronouns }}</p>
</div>
</div>

View file

@ -1,8 +1,8 @@
{{define "body"}}
<div class="credits-legal" style="{{ .GetBackground }}">
<h2>Legal information</h2>
<h1>Legal information</h1>
<p>
The software behind this website was made by <a href="https://www.anhgelus.world/" target="_blank">Anhgelus Morhtuuzh</a>.
The software behind this website was made by <a href="https://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
<a href="https://github.com/anhgelus/now/blob/main/LICENSE" target="_blank">AGPL</a> license.
</p>

View file

@ -1,7 +1,7 @@
{{define "body"}}
<main style="{{ .GetBackground }}">
<div class="header">
<h2 class="header__title">Tags</h2>
<h1 class="header__title">Tags</h1>
<nav>
<a href="/">Home</a>
</nav>
@ -9,7 +9,7 @@
<div class="tags" style="{{ .Color.GetTagColor }}">
{{ range $tag := .Person.Tags }}
<div class="tag" data-href="{{ .Link }}" title="{{ .Link }}">
<h4>{{ .Name }}</h4>
<h3>{{ .Name }}</h3>
<p>{{ .Description }}</p>
</div>
{{ end }}

View file

@ -1,17 +0,0 @@
<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>