feat: simplify codebase to just use golang and tailwindcss
This commit is contained in:
14
.gitignore
vendored
14
.gitignore
vendored
@@ -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
30
.golangci.yml
Normal 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$
|
||||
45
api/hello.go
45
api/hello.go
@@ -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
18
assets/assets.go
Normal 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
BIN
assets/banner.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 949 KiB |
135
assets/colors.css
Normal file
135
assets/colors.css
Normal 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;
|
||||
}
|
||||
93
assets/fonts/CalSans-LICENSE
Normal file
93
assets/fonts/CalSans-LICENSE
Normal 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.
|
||||
BIN
assets/fonts/CalSans-SemiBold.ttf
Normal file
BIN
assets/fonts/CalSans-SemiBold.ttf
Normal file
Binary file not shown.
BIN
assets/fonts/CalSans-SemiBold.woff
Normal file
BIN
assets/fonts/CalSans-SemiBold.woff
Normal file
Binary file not shown.
94
assets/fonts/RedHatText-LICENSE
Normal file
94
assets/fonts/RedHatText-LICENSE
Normal 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.
|
||||
BIN
assets/fonts/RedHatText-Regular.otf
Normal file
BIN
assets/fonts/RedHatText-Regular.otf
Normal file
Binary file not shown.
BIN
assets/fonts/RedHatText-Regular.ttf
Normal file
BIN
assets/fonts/RedHatText-Regular.ttf
Normal file
Binary file not shown.
BIN
assets/fonts/RedHatText-Regular.woff2
Normal file
BIN
assets/fonts/RedHatText-Regular.woff2
Normal file
Binary file not shown.
BIN
assets/photo.jpg
Normal file
BIN
assets/photo.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.4 MiB |
133
assets/tailwind.css
Normal file
133
assets/tailwind.css
Normal 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");
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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
194
flake.lock
generated
@@ -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"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
65
flake.nix
65
flake.nix
@@ -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
9
go.mod
@@ -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
8
go.sum
@@ -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=
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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/**"
|
||||
]
|
||||
}
|
||||
@@ -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
117
main.go
@@ -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)
|
||||
}
|
||||
|
||||
79
makefile
79
makefile
@@ -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)
|
||||
|
||||
|
||||
|
||||
11
package.json
11
package.json
@@ -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"
|
||||
}
|
||||
}
|
||||
@@ -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 © 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
1762
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
43
router.go
Normal file
43
router.go
Normal 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.
@@ -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 |
@@ -1 +0,0 @@
|
||||
test
|
||||
0
tailwind.config.js
Normal file
0
tailwind.config.js
Normal file
103
templates/landing.html
Normal file
103
templates/landing.html
Normal 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}}
|
||||
17
templates/layouts/base.html
Normal file
17
templates/layouts/base.html
Normal 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
24
templates/svg/013.html
Normal 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
52
templates/templates.go
Normal 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
|
||||
},
|
||||
}
|
||||
)
|
||||
@@ -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(),
|
||||
],
|
||||
});
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"$schema": "https://openapi.vercel.sh/vercel.json",
|
||||
"outputDirectory": "dist"
|
||||
}
|
||||
|
||||
2
x
2
x
Submodule x updated: 6ea200aa64...d6fe09dbcd
Reference in New Issue
Block a user