feat: simplify codebase to just use golang and tailwindcss

This commit is contained in:
Guz
2026-02-09 15:40:35 -03:00
parent 91caf703dc
commit bc3ef25c9c
45 changed files with 910 additions and 2570 deletions

14
.gitignore vendored
View File

@@ -1,9 +1,7 @@
node_modules
Session.vim
.direnv
.vercel
*_templ.go
dist
.dist
out.css
.tmp
.env
*.db
tmp
bin
static/uno.css
.direnv

30
.golangci.yml Normal file
View File

@@ -0,0 +1,30 @@
version: "2"
run:
modules-download-mode: readonly
linters:
default: none
enable:
- errcheck
- govet
- ineffassign
- revive
- staticcheck
exclusions:
generated: lax
paths:
- third_party$
- builtin$
- examples$
issues:
max-issues-per-linter: 0
max-same-issues: 0
formatters:
enable:
- gofumpt
- goimports
exclusions:
generated: lax
paths:
- third_party$
- builtin$
- examples$

View File

@@ -1,45 +0,0 @@
package api
import (
"encoding/json"
"fmt"
"io"
"math/rand/v2"
"net/http"
)
type helloObj struct {
Language string
Hello string
}
func getHelloList() ([]helloObj, error) {
res, err := http.Get("https://raw.githubusercontent.com/novellac/multilanguage-hello-json/master/hello.json")
if err != nil {
return nil, err
}
bytes, err := io.ReadAll(res.Body)
if err != nil {
return nil, err
}
var hellos []helloObj
err = json.Unmarshal(bytes, &hellos)
if err != nil {
return nil, err
}
return hellos, nil
}
func Hello(w http.ResponseWriter, r *http.Request) {
hellos, err := getHelloList()
var hello string
if err != nil {
hello = "Welcome!"
} else {
hello = hellos[rand.IntN(len(hellos)-1)].Hello
}
fmt.Fprint(w, hello)
}

18
assets/assets.go Normal file
View File

@@ -0,0 +1,18 @@
package assets
import (
"embed"
"io/fs"
"os"
)
func New() fs.FS {
return embedded
}
//go:embed tailwind.css fonts/*
var embedded embed.FS
func Dev(dir string) fs.FS {
return os.DirFS(dir)
}

BIN
assets/banner.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 949 KiB

135
assets/colors.css Normal file
View File

@@ -0,0 +1,135 @@
@custom-variant dark (&:where(.dark, .dark *));
@theme {
--color-cyan-1: #fafdfe;
--color-cyan-2: #f2fafb;
--color-cyan-3: #def7f9;
--color-cyan-4: #caf1f6;
--color-cyan-5: #b5e9f0;
--color-cyan-6: #9ddde7;
--color-cyan-7: #7dcedc;
--color-cyan-8: #3db9cf;
--color-cyan-9: #00a2c7;
--color-cyan-10: #0797b9;
--color-cyan-11: #107d98;
--color-cyan-12: #0d3c48;
--color-grass-1: #fbfefb;
--color-grass-2: #f5fbf5;
--color-grass-3: #e9f6e9;
--color-grass-4: #daf1db;
--color-grass-5: #c9e8ca;
--color-grass-6: #b2ddb5;
--color-grass-7: #94ce9a;
--color-grass-8: #65ba74;
--color-grass-9: #46a758;
--color-grass-10: #3e9b4f;
--color-grass-11: #2a7e3b;
--color-grass-12: #203c25;
--color-purple-1: #fefcfe;
--color-purple-2: #fbf7fe;
--color-purple-3: #f7edfe;
--color-purple-4: #f2e2fc;
--color-purple-5: #ead5f9;
--color-purple-6: #e0c4f4;
--color-purple-7: #d1afec;
--color-purple-8: #be93e4;
--color-purple-9: #8e4ec6;
--color-purple-10: #8347b9;
--color-purple-11: #8145b5;
--color-purple-12: #402060;
--color-red-1: #fffcfc;
--color-red-2: #fff7f7;
--color-red-3: #feebec;
--color-red-4: #ffdbdc;
--color-red-5: #ffcdce;
--color-red-6: #fdbdbe;
--color-red-7: #f4a9aa;
--color-red-8: #eb8e90;
--color-red-9: #e5484d;
--color-red-10: #dc3e42;
--color-red-11: #ce2c31;
--color-red-12: #641723;
--color-yellow-1: #fdfdf9;
--color-yellow-2: #fefce9;
--color-yellow-3: #fffab8;
--color-yellow-4: #fff394;
--color-yellow-5: #ffe770;
--color-yellow-6: #f3d768;
--color-yellow-7: #e4c767;
--color-yellow-8: #d5ae39;
--color-yellow-9: #ffe629;
--color-yellow-10: #ffdc00;
--color-yellow-11: #9e6c00;
--color-yellow-12: #473b1f;
}
.dark {
--color-cyan-1: #0b161a;
--color-cyan-2: #101b20;
--color-cyan-3: #082c36;
--color-cyan-4: #003848;
--color-cyan-5: #004558;
--color-cyan-6: #045468;
--color-cyan-7: #12677e;
--color-cyan-8: #11809c;
--color-cyan-9: #00a2c7;
--color-cyan-10: #23afd0;
--color-cyan-11: #4ccce6;
--color-cyan-12: #b6ecf7;
--color-grass-1: #0e1511;
--color-grass-2: #141a15;
--color-grass-3: #1b2a1e;
--color-grass-4: #1d3a24;
--color-grass-5: #25482d;
--color-grass-6: #2d5736;
--color-grass-7: #366740;
--color-grass-8: #3e7949;
--color-grass-9: #46a758;
--color-grass-10: #53b365;
--color-grass-11: #71d083;
--color-grass-12: #c2f0c2;
--color-purple-1: #18111b;
--color-purple-2: #1e1523;
--color-purple-3: #301c3b;
--color-purple-4: #3d224e;
--color-purple-5: #48295c;
--color-purple-6: #54346b;
--color-purple-7: #664282;
--color-purple-8: #8457aa;
--color-purple-9: #8e4ec6;
--color-purple-10: #9a5cd0;
--color-purple-11: #d19dff;
--color-purple-12: #ecd9fa;
--color-red-1: #191111;
--color-red-2: #201314;
--color-red-3: #3b1219;
--color-red-4: #500f1c;
--color-red-5: #611623;
--color-red-6: #72232d;
--color-red-7: #8c333a;
--color-red-8: #b54548;
--color-red-9: #e5484d;
--color-red-10: #ec5d5e;
--color-red-11: #ff9592;
--color-red-12: #ffd1d9;
--color-yellow-1: #14120b;
--color-yellow-2: #1b180f;
--color-yellow-3: #2d2305;
--color-yellow-4: #362b00;
--color-yellow-5: #433500;
--color-yellow-6: #524202;
--color-yellow-7: #665417;
--color-yellow-8: #836a21;
--color-yellow-9: #ffe629;
--color-yellow-10: #ffff57;
--color-yellow-11: #f5e147;
--color-yellow-12: #f6eeb4;
}

View File

@@ -0,0 +1,93 @@
Copyright 2021 The Cal Sans Project Authors (https://github.com/calcom/font)
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
https://openfontlicense.org
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,94 @@
Copyright 2021 Red Hat, Inc.,
with Reserved Font Name Red Hat.
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
http://scripts.sil.org/OFL
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
assets/photo.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

133
assets/tailwind.css Normal file
View File

@@ -0,0 +1,133 @@
@import "tailwindcss";
@import "./colors.css";
@theme static {
--font-title: "Cal Sans", var(--font-sans);
--font-text: "Red Hat Text", var(--font-sans);
--color-background: #000000;
--color-foreground: #ffffff;
--color-text: color-mix(in oklab, var(--color-foreground), black 10%);
--color-accent: #888888;
}
@layer base {
:root {
font-family: var(--font-text);
}
html {
width: 100vw;
width: 100dvw;
height: 100vh;
height: 100dvh;
overflow: hidden;
}
body {
width: 100%;
height: 100%;
overflow-y: scroll;
}
body {
margin: 0;
color: color-mix(in oklab, var(--color-foreground), black 10%);
background-color: var(--color-background);
}
p {
text-align: justify;
}
h1,
h2,
h3,
h4,
h5,
h6 {
color: var(--color-foreground);
font-family: var(--font-title);
margin-bottom: --spacing(5);
}
h1 {
font-size: var(--text-5xl);
line-height: var(--text-5xl);
--line-height: var(--text-5xl);
}
}
@layer components {
.word-carousel {
width: fit-content;
height: var(--line-height);
overflow-y: hidden;
li {
animation-name: word-carousel;
animation-duration: 20s;
animation-iteration-count: infinite;
}
}
}
@keyframes word-carousel {
0%,
14% {
transform: translateY(calc(var(--line-height) * 1));
opacity: 0;
}
15%,
29% {
transform: translateY(0px);
opacity: 1;
}
30%,
44% {
transform: translateY(calc(var(--line-height) * 1 * -1));
}
45%,
59% {
transform: translateY(calc(var(--line-height) * 2 * -1));
}
60%,
74% {
transform: translateY(calc(var(--line-height) * 3 * -1));
}
75%,
89% {
transform: translateY(calc(var(--line-height) * 4 * -1));
}
90%,
99% {
transform: translateY(calc(var(--line-height) * 5 * -1));
opacity: 1;
}
100% {
transform: translateY(calc(var(--line-height) * 6 * -1));
opacity: 0;
}
}
@font-face {
font-family: Cal Sans;
font-style: normal;
font-display: swap;
font-weight: 600;
src:
url("./fonts/CalSans-SemiBold.woff2?v=1.0") format("woff2"),
url("./fonts/CalSans-SemiBold.woff?v=1.0") format("woff"),
url("./fonts/CalSans-SemiBold.ttf?v=1.0") format("truetype");
}
@font-face {
font-family: Red Hat Text;
font-style: normal;
font-display: swap;
src:
url("./fonts/RedHatText-Regular.woff2?v=1.0") format("woff2"),
url("./fonts/RedHatText-Regular.otf?v=1.0") format("opentype"),
url("./fonts/RedHatText-Regular.ttf?v=1.0") format("truetype");
}

View File

@@ -1,28 +0,0 @@
package main
import (
"context"
"flag"
"log"
"www/config"
"www/internals"
)
func main() {
dir := flag.String("d", "./dist", "the directory to write the files")
staticDir := flag.String("s", "./static", "the directory to copy static files from")
w := internals.StaticWriter{
DistDir: dir,
StaticDir: staticDir,
Pages: config.ROUTES,
Context: context.Background(),
Logger: *log.Default(),
}
err := w.WriteAll()
if err != nil {
log.Fatal(err)
}
}

View File

@@ -1,63 +0,0 @@
package main
import (
"context"
"encoding/json"
"flag"
"fmt"
"log"
"net/http"
"os"
"www/config"
"www/internals"
)
type VercelConfig struct {
OutputDirectory string `json:"outputDirectory"`
}
var logger = log.Default()
func main() {
configPath := flag.String("c", "./vercel.json", "the path to the vercel.json file")
staticDir := flag.String("s", "./static", "the directory to copy static files from")
port := flag.Int("p", 8080, "the port to run the server")
configFile, err := os.ReadFile(*configPath)
if err != nil {
logger.Fatalf("Unable to read vercel.json file due to:\n%s", err)
}
var c VercelConfig
err = json.Unmarshal(configFile, &c)
if err != nil {
logger.Fatalf("Unable to parse vercel.json file due to:\n%s", err)
}
w := internals.StaticWriter{
DistDir: &c.OutputDirectory,
StaticDir: staticDir,
Pages: config.ROUTES,
Context: context.Background(),
Logger: *log.Default(),
}
logger.Print("Writing static files")
err = w.WriteAll()
if err != nil {
logger.Fatal(err)
}
logger.Print("Starting server")
mux := http.NewServeMux()
config.APIROUTES(mux)
mux.Handle("/", http.FileServer(http.Dir(c.OutputDirectory)))
logger.Printf("Running server at port: %v", *port)
err = http.ListenAndServe(fmt.Sprintf(":%v", *port), mux)
if err != nil {
logger.Fatalf("Server crashed due to:\n%s", err)
}
}

View File

@@ -1,17 +0,0 @@
package config
import (
"net/http"
"www/api"
"www/internals"
"www/pages"
)
var ROUTES = []internals.Page{
{Path: "index.html", Component: pages.Homepage()},
}
func APIROUTES(mux *http.ServeMux) {
mux.HandleFunc("/api/hello", api.Hello)
}

194
flake.lock generated
View File

@@ -1,106 +1,12 @@
{
"nodes": {
"flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1710146030,
"narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"flake-utils_2": {
"inputs": {
"systems": "systems_2"
},
"locked": {
"lastModified": 1694529238,
"narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "ff7b65b44d01cf9ba6a71320833626af21126384",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"flake-utils_3": {
"locked": {
"lastModified": 1667395993,
"narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"gitignore": {
"inputs": {
"nixpkgs": [
"templ",
"nixpkgs"
]
},
"locked": {
"lastModified": 1709087332,
"narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=",
"owner": "hercules-ci",
"repo": "gitignore.nix",
"rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "gitignore.nix",
"type": "github"
}
},
"gomod2nix": {
"inputs": {
"flake-utils": "flake-utils_2",
"nixpkgs": [
"templ",
"nixpkgs"
]
},
"locked": {
"lastModified": 1710154385,
"narHash": "sha256-4c3zQ2YY4BZOufaBJB4v9VBBeN2dH7iVdoJw8SDNCfI=",
"owner": "nix-community",
"repo": "gomod2nix",
"rev": "872b63ddd28f318489c929d25f1f0a3c6039c971",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "gomod2nix",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1716293225,
"narHash": "sha256-pU9ViBVE3XYb70xZx+jK6SEVphvt7xMTbm6yDIF4xPs=",
"lastModified": 1760878510,
"narHash": "sha256-K5Osef2qexezUfs0alLvZ7nQFTGS9DL2oTVsIXsqLgs=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "3eaeaeb6b1e08a016380c279f8846e0bd8808916",
"rev": "5e2a59a5b1a82f89f2c7e598302a9cacebb72a67",
"type": "github"
},
"original": {
@@ -110,101 +16,9 @@
"type": "github"
}
},
"nixpkgs_2": {
"locked": {
"lastModified": 1710565619,
"narHash": "sha256-xu/EnZCNdIj7m/QjCNIG5vrCA4TYg5uwFReb9XDxET0=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "8ac30a39abc5ea67037dfbf090d6e89f187c6e50",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-23.11",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs",
"templ": "templ"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
},
"systems_2": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
},
"templ": {
"inputs": {
"gitignore": "gitignore",
"gomod2nix": "gomod2nix",
"nixpkgs": "nixpkgs_2",
"xc": "xc"
},
"locked": {
"lastModified": 1716034419,
"narHash": "sha256-z/sb4AlFOU20sBEAu12VSXqhHQuqvj3mUu7JTvyc1pI=",
"owner": "a-h",
"repo": "templ",
"rev": "0c14a899236d115a790b5a960b5d2b50c277c77e",
"type": "github"
},
"original": {
"owner": "a-h",
"ref": "tags/v0.2.697",
"repo": "templ",
"type": "github"
}
},
"xc": {
"inputs": {
"flake-utils": "flake-utils_3",
"nixpkgs": [
"templ",
"nixpkgs"
]
},
"locked": {
"lastModified": 1709043057,
"narHash": "sha256-F/u9u1vevCUqgCz0WjcCOPcN+h9kLEP73nBqie86J2w=",
"owner": "joerdav",
"repo": "xc",
"rev": "52cfa7e7f2d5a0d97b45a6f69ff1403a901e78c6",
"type": "github"
},
"original": {
"owner": "joerdav",
"repo": "xc",
"type": "github"
"nixpkgs": "nixpkgs"
}
}
},

View File

@@ -1,34 +1,53 @@
{
description = "learning.rs";
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
flake-utils.url = "github:numtide/flake-utils";
templ.url = "github:a-h/templ?ref=tags/v0.2.697";
};
outputs =
{ self
, nixpkgs
, flake-utils
, ...
} @ inputs:
flake-utils.lib.eachDefaultSystem (system:
let
pkgs = import nixpkgs {
inherit system;
};
templ = inputs.templ.packages.${system}.templ;
in
{
devShells.default = pkgs.mkShell {
outputs = {nixpkgs, ...}: let
systems = [
"x86_64-linux"
"aarch64-linux"
"x86_64-darwin"
"aarch64-darwin"
];
forAllSystems = f:
nixpkgs.lib.genAttrs systems (system: let
pkgs = import nixpkgs {inherit system;};
in
f system pkgs);
in {
devShells = forAllSystems (system: pkgs: {
default = pkgs.mkShell {
CGO_ENABLED = "1";
hardeningDisable = ["fortify"];
GOPRIVATE = "code.capytal.cc/*";
shellHook = ''
set -a
source .env
set +a
'';
buildInputs = with pkgs; [
air
# Go tools
go
golangci-lint
templ
nodePackages_latest.vercel
nodejs_20
corepack_20
gofumpt
gotools
delve
# TailwindCSS
tailwindcss_4
# Sqlite tools
sqlite
lazysql
litecli
# S3
awscli
];
};
});
};
}

9
go.mod
View File

@@ -1,5 +1,8 @@
module www
module guz.one
go 1.22.2
go 1.25.1
require github.com/a-h/templ v0.2.697
require (
code.capytal.cc/loreddev/smalltrip v0.0.0-20251020150546-bb634f58cbb1
code.capytal.cc/loreddev/x v0.0.0-20251022004730-9a1596e9322e
)

8
go.sum
View File

@@ -1,4 +1,4 @@
github.com/a-h/templ v0.2.697 h1:OILxtWvD0NRJaoCOiZCopRDPW8paroKlGsrAiHLykNE=
github.com/a-h/templ v0.2.697/go.mod h1:5cqsugkq9IerRNucNsI4DEamdHPsoGMQy99DzydLhM8=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
code.capytal.cc/loreddev/smalltrip v0.0.0-20251020150546-bb634f58cbb1 h1:p12+x1R7M3shAyQ9z2QzVms9HuTlXN2+NYW/7BoNO4s=
code.capytal.cc/loreddev/smalltrip v0.0.0-20251020150546-bb634f58cbb1/go.mod h1:CjzhmbQIf4PlnsCF5gK/5e4qDP7JeT+7CcVvbx+DtUg=
code.capytal.cc/loreddev/x v0.0.0-20251022004730-9a1596e9322e h1:9Reo1ZdnNMCfNus46DdbQ3Bwv1hTIYlyW4vjAsawF54=
code.capytal.cc/loreddev/x v0.0.0-20251022004730-9a1596e9322e/go.mod h1:o9HsngwSWEAETuvFoOqlKj431Ri3cOL0g8Li2M49DAo=

7
go.work Normal file
View File

@@ -0,0 +1,7 @@
go 1.25.1
use (
.
./smalltrip
./x
)

View File

@@ -1,107 +0,0 @@
package internals
import (
"context"
"io"
"io/fs"
"log"
"os"
"path/filepath"
"strings"
"github.com/a-h/templ"
)
const PERMISSIONS = 0755
type Page struct {
Path string
Component templ.Component
}
type StaticWriter struct {
DistDir *string
StaticDir *string
Pages []Page
Context context.Context
Logger log.Logger
}
func (w *StaticWriter) WritePage(path string, writer func(ctx context.Context, w io.Writer) error) error {
directory := filepath.Dir(path)
err := os.MkdirAll(directory, PERMISSIONS)
if err != nil {
return err
}
f, err := os.Create(path)
if err != nil {
return err
}
defer f.Close()
err = writer(w.Context, f)
return err
}
func (w *StaticWriter) WriteAll() error {
for _, page := range w.Pages {
p := filepath.Join(*w.DistDir, page.Path)
w.Logger.Printf("Writing page %s", p)
err := w.WritePage(p, page.Component.Render)
if err != nil {
return err
}
}
err := filepath.WalkDir(*w.StaticDir, func(path string, d fs.DirEntry, err error) error {
if err != nil {
return err
} else if d.IsDir() || path == *w.StaticDir {
return nil
}
f, err := filepath.Abs(path)
if err != nil {
return err
}
s, err := filepath.Abs(*w.StaticDir)
if err != nil {
return err
}
err = w.CopyStatic(strings.TrimPrefix(f, s))
if err != nil {
return err
}
return nil
})
return err
}
func (w *StaticWriter) CopyStatic(path string) error {
c, err := os.ReadFile(filepath.Join(*w.StaticDir, path))
if err != nil {
return err
}
p := filepath.Join(*w.DistDir, path)
err = os.MkdirAll(filepath.Dir(p), PERMISSIONS)
if err != nil {
return err
}
f, err := os.Create(p)
if err != nil {
return err
}
defer f.Close()
b, err := f.Write(c)
if err != nil {
return err
}
w.Logger.Printf("Wrote %v bytes in %s", b, p)
return nil
}

View File

@@ -1,24 +0,0 @@
{
"$schema": "https://json.schemastore.org/jsconfig",
"compilerOptions": {
"checkJs": true,
"allowJs": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"moduleResolution": "node",
"skipLibCheck": true,
"sourceMap": true,
"strict": true,
"module": "ESNext",
"target": "ESNext",
"alwaysStrict": true,
"outDir": "./dist"
},
"include": [
"./uno.config.js"
],
"exclude": [
"./node_modules/**",
"./dist/**"
]
}

View File

@@ -1,27 +0,0 @@
package layouts
templ Page(title string) {
<html>
<head>
<link rel="stylesheet" href="/uno.css"/>
<style>
@font-face {
font-family: Inter;
src: url(inter.woff2);
}
@font-face {
font-family: Cal Sans;
src: url(cal-sans.woff2);
}
@font-face {
font-family: Fira Code;
src: url(fira-code.woff2);
}
</style>
<title>{ title }</title>
</head>
<body class="bg-black flex flex-col justify-center items-center w-screen h-screen overflow-hidden text-white font-sans">
{ children... }
</body>
</html>
}

117
main.go
View File

@@ -1,69 +1,82 @@
package main
import (
"context"
"errors"
"flag"
"fmt"
"log"
"log/slog"
"net/http"
"slices"
"strings"
"os"
"os/signal"
"syscall"
"www/config"
"www/internals"
"guz.one/assets"
"guz.one/templates"
)
var logger = log.Default()
var (
hostname = flag.String("hostname", "localhost", "Host to listen to")
port = flag.Uint("port", 8080, "Port to be used for the server.")
verbose = flag.Bool("verbose", false, "Print debug information on logs")
dev = flag.Bool("dev", false, "Run the server in debug mode.")
)
func init() {
flag.Parse()
}
func main() {
staticDir := flag.String("s", "./static", "the directory to copy static files from")
port := flag.Int("p", 8080, "the port to run the server")
ctx := context.Background()
log := slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{}))
mux := http.NewServeMux()
config.APIROUTES(mux)
for _, route := range config.ROUTES {
path := "/" + strings.TrimSuffix(route.Path, ".html")
if path == "/index" {
continue
}
logger.Printf("Registering page route. page=%s route=%s", route.Path, path)
mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) {
logger.Printf("Handling request. path=%s", r.URL.Path)
w.Header().Add("Content-Type", "text/html")
err := route.Component.Render(r.Context(), w)
if err != nil {
logger.Fatalf("Unable to render route %s due to %s", route.Path, err)
}
})
as := http.FileServerFS(assets.New())
if *dev {
as = http.StripPrefix("/assets/", http.FileServerFS(assets.Dev("./assets")))
}
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/" {
logger.Printf("Handling file server request. path=%s", r.URL.Path)
http.FileServer(http.Dir(*staticDir)).ServeHTTP(w, r)
return
}
logger.Printf("Handling request. path=%s", r.URL.Path)
w.Header().Add("Content-Type", "text/html")
index := slices.IndexFunc(config.ROUTES, func(route internals.Page) bool {
return route.Path == "index.html"
})
indexPage := config.ROUTES[index]
err := indexPage.Component.Render(r.Context(), w)
if err != nil {
log.Fatalf("Unable to render index page due to %s", err)
}
})
logger.Printf("Running server at port: %v", *port)
err := http.ListenAndServe(fmt.Sprintf(":%v", *port), mux)
ts, err := templates.New()
if *dev {
ts, err = templates.Dev("./templates")
}
if err != nil {
logger.Fatalf("Server crashed due to:\n%s", err)
log.Error("Error whiling initializing templates", slog.String("error", err.Error()))
os.Exit(1)
}
srv := &http.Server{
Addr: fmt.Sprintf("%s:%d", "", 8080),
Handler: &router{
assets: as,
templates: ts,
logger: log,
},
}
c, stop := signal.NotifyContext(ctx, syscall.SIGINT, syscall.SIGTERM)
defer stop()
go func() {
log.Info("Starting application",
slog.String("host", *hostname),
slog.Uint64("port", uint64(*port)),
slog.Bool("verbose", *verbose),
slog.Bool("development", *dev))
if err := srv.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
log.Error("Failed to start application server", slog.String("error", err.Error()))
os.Exit(1)
}
}()
<-c.Done()
log.Info("Stopping application gracefully")
if err := srv.Shutdown(ctx); err != nil {
log.Error("Failed to stop application server gracefully", slog.String("error", err.Error()))
os.Exit(1)
}
log.Info("FINAL")
os.Exit(0)
}

View File

@@ -1,56 +1,43 @@
PORT?=8080
all: run
lint:
golangci-lint run .
fmt:
go fmt .
golangci-lint run --fix .
dev/server:
go run github.com/joho/godotenv/cmd/godotenv@v1.5.1 \
go run github.com/air-verse/air@v1.52.2 \
--build.cmd "go build -o tmp/bin/www ." \
--build.bin "tmp/bin/www" \
--build.exclude_dir "templates" \
--build.exclude_dir "assets" \
--build.include_ext "go" \
--build.stop_on_error "false" \
--misc.clean_on_exit true \
-- -dev -port $(PORT) -hostname 0.0.0.0
dev/assets:
tailwindcss \
-i ./assets/tailwind.css \
-o ./assets/out.css \
--watch
dev:
pnpm unocss -w &
air -build.pre_cmd 'make templ' \
-build.include_ext 'templ' \
-build.include_ext 'css' \
-proxy.enabled true \
-proxy.app_port $(PORT) \
-proxy.proxy_port $$(($(PORT) + 1)) \
-- -p $(PORT)
$(MAKE) -j2 dev/assets dev/server
dev-vercel:
air -build.pre_cmd 'make build-vercel' \
-build.include_ext 'templ' \
-build.cmd 'make build-vercel' \
-build.bin './bin/vercel' \
-proxy.enabled true \
-proxy.app_port $(PORT) \
-proxy.proxy_port $$(($(PORT) + 1)) \
-- -p $(PORT)
build:
go build -o ./.dist/app .
run: bin/www
./bin/www
run-vercel: bin/vercel
./bin/vercel
build-static: templ
pnpm unocss
go run ./cmd/build/main.go
build-vercel: bin/vercel build-static
bin/www: main.go templ
go build -o ./bin/www ./main.go
bin/vercel: cmd/vercel/main.go templ
go build -o ./bin/vercel ./cmd/vercel/main.go
# For some reason "templ generate" does not detect the files, so this is a
# workaround.
TEMPL_FILES=$(patsubst %.templ, %_templ.go, $(wildcard **/*.templ))
templ: $(TEMPL_FILES)
@echo Generating templ files
%_templ.go: %.templ
templ generate -f $^ > /dev/null
run: build
./.dist/www
clean:
if [[ -d "dist" ]]; then rm -r ./dist; fi
# Remove generated directories
if [[ -d ".dist" ]]; then rm -r ./.dist; fi
if [[ -d "tmp" ]]; then rm -r ./tmp; fi
if [[ -d "bin" ]]; then rm -r ./bin; fi
rm ./static/uno.css
rm $(TEMPL_FILES)

View File

@@ -1,11 +0,0 @@
{
"name": "www",
"version": "0.0.1",
"devDependencies": {
"@iconify-json/simple-icons": "^1.1.102",
"@iconify-json/solar": "^1.1.9",
"@types/node": "^20.12.12",
"@unocss/cli": "^0.60.3",
"unocss": "^0.60.3"
}
}

View File

@@ -1,88 +0,0 @@
package pages
import (
"www/layouts"
)
templ Homepage() {
@layouts.Page("013") {
<main>
<img src="/logo-013.svg" alt="" width="100" height="100"/>
<h1 class="font-cal">Someone who's trying to improve</h1>
<div class="text-#181818 flex flex-row justify-between items-center">
<nav>
<ul class="list-none flex flex-row gap-3 p-0">
<li class="i-simple-icons:github w-4 hover:text-#ababab transition-colors">
<a
href="https://github.com/guz013"
target="_blank"
class="opacity-0"
rel="noreferrer noopener"
>
GitHub
</a>
</li>
<li class="i-simple-icons:codeberg w-4 hover:text-#ababab transition-colors">
<a
href="https://codeberg.org/guz013"
target="_blank"
class="opacity-0"
rel="noreferrer noopener"
>
Codeberg
</a>
</li>
<li class="i-simple-icons:twitter w-4 hover:text-#ababab transition-colors">
<a
href="https://twitter.com/guz013_"
target="_blank"
class="opacity-0"
rel="noreferrer noopener"
>
Twitter
</a>
</li>
<li class="i-simple-icons:mastodon w-4 hover:text-#ababab transition-colors">
<a
href="https://mastodon.social/@guz013"
target="_blank"
class="opacity-0"
rel="noreferrer noopener"
>
Mastodon
</a>
</li>
<li class="i-simple-icons:instagram w-4 hover:text-#ababab transition-colors">
<a
href="https://instagram.com/guz013_"
target="_blank"
class="opacity-0"
rel="noreferrer noopener"
>
Instagram
</a>
</li>
<li class="i-simple-icons:pixelfed w-4 hover:text-#ababab transition-colors">
<a
href="https://pixelfed.social/@guz013"
target="_blank"
class="opacity-0"
rel="noreferrer noopener"
>
Pixelfed
</a>
</li>
</ul>
</nav>
<p class="m-0">
<a class="text-#181818 hover:text-#ababab transition-colors" href="mailto:contact.guz013@gmail.com">
2024 &copy Gustavo L. de Mello
</a>
</p>
</div>
</main>
<footer class="fixed bottom-0 text-xs font-mono ">
<p><a class="text-#181818 hover:text-#ababab" href="https://www-v2-guz013-guzsprojects.vercel.app/">new website in development</a></p>
</footer>
}
}

1762
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

43
router.go Normal file
View File

@@ -0,0 +1,43 @@
package main
import (
"log/slog"
"net/http"
"code.capytal.cc/loreddev/smalltrip"
"code.capytal.cc/loreddev/smalltrip/middleware"
"code.capytal.cc/loreddev/smalltrip/multiplexer"
"code.capytal.cc/loreddev/smalltrip/problem"
"code.capytal.cc/loreddev/x/xtemplate"
)
type router struct {
assets http.Handler
templates xtemplate.Templater
logger *slog.Logger
}
func (ctrl *router) ServeHTTP(w http.ResponseWriter, r *http.Request) {
mux := multiplexer.New()
mux = multiplexer.WithPatternRules(mux,
multiplexer.EnsureMethod(),
multiplexer.EnsureStrictEnd(),
multiplexer.EnsureTrailingSlash(),
)
router := smalltrip.NewRouter(smalltrip.WithMultiplexer(mux), smalltrip.WithLogger(ctrl.logger))
router.Use(problem.Middleware(problem.DefaultHandler))
router.Use(middleware.Logger(ctrl.logger))
router.Handle("/assets/{file...}", ctrl.assets)
router.HandleFunc("/{$}", ctrl.landing)
router.ServeHTTP(w, r)
}
func (ctrl *router) landing(w http.ResponseWriter, r *http.Request) {
if err := ctrl.templates.ExecuteTemplate(w, "landing", nil); err != nil {
problem.NewInternalServerError(err).ServeHTTP(w, r)
}
}

Binary file not shown.

Binary file not shown.

View File

@@ -1,17 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 186.23 93.51">
<defs>
<style>
.cls-1 {
fill: #fff;
}
</style>
</defs>
<g id="logos">
<g id="dark">
<polygon class="cls-1" points="68.37 51.8 22.71 2.1 5.59 17.14 51.25 66.85 68.37 51.8" />
<rect class="cls-1" x="69.45" width="23.01" height="61.64" />
<polygon class="cls-1"
points="145.09 24.19 185.73 24.19 185.73 1.68 105.09 1.68 146.25 70.92 0 71 0.01 93.51 186.23 93.41 145.09 24.19" />
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 496 B

View File

@@ -1 +0,0 @@
test

0
tailwind.config.js Normal file
View File

103
templates/landing.html Normal file
View File

@@ -0,0 +1,103 @@
{{define "landing"}}
<!doctype html>
<html lang="en" class="dark">
<head>
<meta charset="UTF-8" />
<meta name="color-scheme" content="dark light" />
<meta
name="viewport"
content="width=device-width, height=device-height, initial-scale=1.0"
/>
<title>Guz</title>
<link rel="stylesheet" href="/assets/out.css" />
</head>
<body class="">
<div class="w-full h-dvh md:flex items-center justify-center p-5">
<div class="relative md:max-w-[65rem] md:grid grid-cols-2 gap-5">
<header class="w-full h-full md:h-min mb-5 md:m-0">
<img
src="/assets/photo.jpg"
class="w-full h-full object-cover"
alt=""
/>
</header>
<main class="flex flex-col">
<h1>
Someone who's trying to improve
<ul class="word-carousel inline-block translate-y-[20%]">
<li class="text-cyan-10">their code</li>
<li class="text-purple-10">their art</li>
<li class="text-grass-10">their music</li>
<li class="text-red-10">their games</li>
<li class="text-yellow-10">their photos</li>
<li class="text-text">themselves</li>
</ul>
</h1>
<p class="text-xl">
Software Engineer since I learned that Java is a programming
language and not just a fancy world in a blocky game's title. Also
digital artist, hobbist photographer, generalist, friend and lover
during free time. Dabbling between and mashing together art and tech
is my passion.
</p>
<section
class="flex gap-1 md:flex-col w-full h-full justify-end items-center md:items-start my-5 md:my-0"
>
<h2 class="mb-0">Contact</h2>
<a href="mailto:contact@guz.one">contact@guz.one</a>
</section>
<span class="w-28 absolute right-0 bottom-0 hidden md:block">
{{template "svg-013"}}
</span>
</main>
</div>
</div>
<!-- <nav class="bg-red-500 sticky top-0 left-0"> -->
<!-- <details> -->
<!-- <summary> -->
<!-- <span class="block w-10"> {{template "svg-013"}} </span> -->
<!-- </summary> -->
<!-- <ul> -->
<!-- <li><a>Code</a></li> -->
<!-- <li><a>Art</a></li> -->
<!-- <li><a>Music</a></li> -->
<!-- <li><a>Games</a></li> -->
<!-- <li><a>Photos</a></li> -->
<!-- <li><a>Contact</a></li> -->
<!-- </ul> -->
<!-- </details> -->
<!-- </nav> -->
<!-- <article class="p-5 grid"> -->
<!-- <h2 class="text-3xl">Projects</h2> -->
<!-- <article> -->
<!-- <img src="/assets/banner.jpg" alt="" /> -->
<!-- <h3 class="text-xl">Smalltrip</h3> -->
<!-- <p> -->
<!-- A small package to help on your routes, fully compatible to Go's -->
<!-- standard library net/http. -->
<!-- </p> -->
<!-- </article> -->
<!-- <article> -->
<!-- <img src="/assets/banner.jpg" alt="" /> -->
<!-- <h3 class="text-xl">Kois.work</h3> -->
<!-- <p> -->
<!-- Lorem ipsum dolor sit amet consectetur adipisicing elit. Rem -->
<!-- consequatur asperiores officia sed ullam facere! Soluta in deleniti -->
<!-- quibusdam fuga autem recusandae minima, reiciendis iste ut. Libero -->
<!-- pariatur quis non! -->
<!-- </p> -->
<!-- </article> -->
<!-- <article> -->
<!-- <img src="/assets/banner.jpg" alt="" /> -->
<!-- <h3 class="text-xl">Depgraph</h3> -->
<!-- <p> -->
<!-- Lorem ipsum dolor sit amet consectetur adipisicing elit. Officiis -->
<!-- quaerat, ad fugiat nam sit magni neque? Eos cupiditate necessitatibus -->
<!-- vero minus ducimus quae tempore nulla aliquid nobis, dolore impedit -->
<!-- nostrum. -->
<!-- </p> -->
<!-- </article> -->
<!-- </article> -->
</body>
</html>
{{end}}

View File

@@ -0,0 +1,17 @@
{{define "layouts/base"}}
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>{{.Title}}</title>
<link href="/assets/stylesheets/out.css" rel="stylesheet" />
<script
src="https://unpkg.com/htmx.org@2.0.4/dist/htmx.js"
integrity="sha384-oeUn82QNXPuVkGCkcrInrS1twIxKhkZiFfr2TdiuObZ3n3yIeMiqcRzkIcguaof1"
crossorigin="anonymous"
></script>
</head>
{{end}} {{define "layouts/base-end"}}
</html>
{{end}}

24
templates/svg/013.html Normal file
View File

@@ -0,0 +1,24 @@
{{define "svg-013"}}
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 186.23 93.51">
<defs>
<style>
.cls-1 {
fill: currentColor;
}
</style>
</defs>
<g id="logos">
<g id="dark">
<polygon
class="cls-1"
points="68.37 51.8 22.71 2.1 5.59 17.14 51.25 66.85 68.37 51.8"
/>
<rect class="cls-1" x="69.45" width="23.01" height="61.64" />
<polygon
class="cls-1"
points="145.09 24.19 185.73 24.19 185.73 1.68 105.09 1.68 146.25 70.92 0 71 0.01 93.51 186.23 93.41 145.09 24.19"
/>
</g>
</g>
</svg>
{{end}}

52
templates/templates.go Normal file
View File

@@ -0,0 +1,52 @@
package templates
// INFO: This will probably become a new lib in loreddev/x at some point
import (
"embed"
"errors"
"fmt"
"html/template"
"os"
"code.capytal.cc/loreddev/x/xtemplate"
)
func New() (xtemplate.Template, error) {
return xtemplate.New[template.Template]("template").
Funcs(functions).
ParseFS(embedded, patterns...)
}
//go:embed *.html layouts/*.html svg/*.html
var embedded embed.FS
func Dev(dir string) (xtemplate.Template, error) {
return xtemplate.NewHot[template.Template]("template").
Funcs(functions).
ParseFS(os.DirFS(dir), patterns...)
}
var (
patterns = []string{"*.html", "layouts/*.html", "svg/*.html"}
functions = template.FuncMap{
"args": func(pairs ...any) (map[string]any, error) {
if len(pairs)%2 != 0 {
return nil, errors.New("misaligned map in template arguments")
}
m := make(map[string]any, len(pairs)/2)
for i := 0; i < len(pairs); i += 2 {
key, ok := pairs[i].(string)
if !ok {
return nil, fmt.Errorf("cannot use type %T as map key", pairs[i])
}
m[key] = pairs[i+1]
}
return m, nil
},
}
)

View File

@@ -1,48 +0,0 @@
import {
defineConfig,
presetIcons,
presetTypography,
presetUno,
presetWebFonts,
transformerDirectives,
transformerVariantGroup,
} from 'unocss';
export default defineConfig({
cli: {
entry: {
patterns: [
'./{pages,layouts}/**/*.templ',
'./static/**/*.{js,css,html}',
'!./static/uno.css',
],
outFile: './static/uno.css',
},
},
presets: [
presetIcons(),
presetTypography(),
presetUno(),
presetWebFonts({
provider: 'bunny',
fonts: {
sans: {
name: 'Inter',
provider: 'none'
},
cal: {
name: 'Cal Sans',
provider: 'none',
},
mono: {
name: 'Fira Code',
provider: 'none',
},
},
}),
],
transformers: [
transformerDirectives(),
transformerVariantGroup(),
],
});

View File

@@ -1,5 +0,0 @@
{
"$schema": "https://openapi.vercel.sh/vercel.json",
"outputDirectory": "dist"
}

2
x

Submodule x updated: 6ea200aa64...d6fe09dbcd