Skip to content

Commit 0ff2e0e

Browse files
authored
feat(website): website start (#29)
just setting up some scaffolding for the website
1 parent 0306083 commit 0ff2e0e

16 files changed

+460
-0
lines changed

go.mod

+3
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ go 1.20
44

55
require (
66
github.com/hexops/gotextdiff v1.0.3
7+
github.com/yuin/goldmark v1.6.0
78
go.lsp.dev/jsonrpc2 v0.10.0
89
go.lsp.dev/protocol v0.12.0
910
go.lsp.dev/uri v0.3.0
@@ -12,9 +13,11 @@ require (
1213
require (
1314
github.com/segmentio/asm v1.1.3 // indirect
1415
github.com/segmentio/encoding v0.3.4 // indirect
16+
github.com/yuin/goldmark-meta v1.1.0 // indirect
1517
go.lsp.dev/pkg v0.0.0-20210717090340-384b27a52fb2 // indirect
1618
go.uber.org/atomic v1.9.0 // indirect
1719
go.uber.org/multierr v1.8.0 // indirect
1820
go.uber.org/zap v1.21.0 // indirect
1921
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8 // indirect
22+
gopkg.in/yaml.v2 v2.3.0 // indirect
2023
)

go.sum

+7
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,12 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
2222
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
2323
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
2424
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
25+
github.com/yuin/goldmark v1.3.5 h1:dPmz1Snjq0kmkz159iL7S6WzdahUTHnHB5M56WFVifs=
2526
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
27+
github.com/yuin/goldmark v1.6.0 h1:boZcn2GTjpsynOsC0iJHnBWa4Bi0qzfJjthwauItG68=
28+
github.com/yuin/goldmark v1.6.0/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
29+
github.com/yuin/goldmark-meta v1.1.0 h1:pWw+JLHGZe8Rk0EGsMVssiNb/AaPMHfSRszZeUeiOUc=
30+
github.com/yuin/goldmark-meta v1.1.0/go.mod h1:U4spWENafuA7Zyg+Lj5RqK/MF+ovMYtBvXi1lBb2VP0=
2631
go.lsp.dev/jsonrpc2 v0.10.0 h1:Pr/YcXJoEOTMc/b6OTmcR1DPJ3mSWl/SWiU1Cct6VmI=
2732
go.lsp.dev/jsonrpc2 v0.10.0/go.mod h1:fmEzIdXPi/rf6d4uFcayi8HpFP1nBF99ERP1htC72Ac=
2833
go.lsp.dev/pkg v0.0.0-20210717090340-384b27a52fb2 h1:hCzQgh6UcwbKgNSRurYWSqh8MufqRRPODRBblutn4TE=
@@ -75,6 +80,8 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8
7580
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
7681
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
7782
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
83+
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
84+
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
7885
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
7986
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
8087
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

website/docs/index.md

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
title: Home
3+
---
4+
5+
# This is the homepage
6+
7+
There is no content here

website/docs/other.md

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
title: Other
3+
---
4+
# This is another page in the root
5+
6+
There is no content here

website/docs/subdir/index.md

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
---
2+
title: Some title
3+
description: A reasonable description for this page
4+
author: Anthony Bullard
5+
slug: subdir/this-is-my-slug
6+
tags:
7+
- test
8+
- other
9+
---
10+
# This is the root of subdir
11+
12+
Hopefully this works

website/main.go

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package main
2+
3+
import (
4+
"log"
5+
6+
"github.com/gamebox/gwirl/website/views/html"
7+
"github.com/gamebox/gwirl/website/ssg"
8+
)
9+
10+
func main() {
11+
log.Println("Generating docs...")
12+
engine := ssg.NewEngine("docs", html.Base, "out")
13+
14+
engine.Generate()
15+
log.Println("Complete.")
16+
}

website/out/index.html

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
2+
<!DOCTYPE html>
3+
<html>
4+
<head>
5+
<title>Home</title>
6+
</head>
7+
<body>
8+
<aside>
9+
<nav>
10+
<ul>
11+
12+
<li><a href="out/index.html"/>Home</a></li>
13+
14+
<li><a href="out/other.html"/>Other</a></li>
15+
16+
<li><a href="out/subdir/index.html"/>Some title</a></li>
17+
18+
<li><a href="out/subdir/index.html"/>Some title</a></li>
19+
20+
</ul>
21+
</nav>
22+
</aside>
23+
<h1 id="this-is-the-homepage">This is the homepage</h1>
24+
<p>There is no content here</p>
25+
26+
</body>
27+
</html>

website/out/other.html

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
2+
<!DOCTYPE html>
3+
<html>
4+
<head>
5+
<title>Other</title>
6+
</head>
7+
<body>
8+
<aside>
9+
<nav>
10+
<ul>
11+
12+
<li><a href="out/index.html"/>Home</a></li>
13+
14+
<li><a href="out/other.html"/>Other</a></li>
15+
16+
<li><a href="out/subdir/index.html"/>Some title</a></li>
17+
18+
<li><a href="out/subdir/index.html"/>Some title</a></li>
19+
20+
</ul>
21+
</nav>
22+
</aside>
23+
<h1 id="this-is-another-page-in-the-root">This is another page in the root</h1>
24+
<p>There is no content here</p>
25+
26+
</body>
27+
</html>

website/out/subdir/index.html

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
2+
<!DOCTYPE html>
3+
<html>
4+
<head>
5+
<title>Some title</title>
6+
</head>
7+
<body>
8+
<aside>
9+
<nav>
10+
<ul>
11+
12+
<li><a href="out/index.html"/>Home</a></li>
13+
14+
<li><a href="out/other.html"/>Other</a></li>
15+
16+
<li><a href="out/subdir/index.html"/>Some title</a></li>
17+
18+
<li><a href="out/subdir/index.html"/>Some title</a></li>
19+
20+
</ul>
21+
</nav>
22+
</aside>
23+
<h1 id="this-is-the-root-of-subdir">This is the root of subdir</h1>
24+
<p>Hopefully this works</p>
25+
26+
</body>
27+
</html>

website/ssg/engine.go

+149
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
package ssg
2+
3+
import (
4+
"bytes"
5+
"io/fs"
6+
"log"
7+
"os"
8+
"path/filepath"
9+
"strings"
10+
11+
"github.com/yuin/goldmark"
12+
meta "github.com/yuin/goldmark-meta"
13+
"github.com/yuin/goldmark/extension"
14+
"github.com/yuin/goldmark/parser"
15+
)
16+
17+
type Engine struct {
18+
docFiles []File
19+
layoutTemplate func(Page, string) string
20+
outputDir string
21+
baseDir string
22+
markdown goldmark.Markdown
23+
}
24+
25+
type LayoutTemplate func(Page, string) string
26+
27+
func NewEngine(docBaseDir string, layoutTemplate LayoutTemplate, outputDir string) *Engine {
28+
eng := Engine{ layoutTemplate: layoutTemplate, outputDir: outputDir, baseDir: docBaseDir }
29+
eng.markdown = goldmark.New(
30+
goldmark.WithExtensions(
31+
extension.GFM,
32+
meta.Meta,
33+
),
34+
goldmark.WithParserOptions(parser.WithAutoHeadingID()),
35+
)
36+
eng.loadDocs(docBaseDir)
37+
38+
return &eng
39+
}
40+
41+
func (e *Engine) Generate() {
42+
for i := range e.docFiles {
43+
log.Println(e.docFiles[i].osFile.Name())
44+
var buff bytes.Buffer
45+
contents, err := os.ReadFile(e.docFiles[i].osFile.Name())
46+
if err != nil {
47+
log.Printf("Could not read file %s: %v", e.docFiles[i].osFile.Name(), err)
48+
continue
49+
}
50+
context := parser.NewContext()
51+
if err = e.markdown.Convert(contents, &buff, parser.WithContext(context)); err != nil {
52+
log.Printf("Could not convert markdown file %s: %v", e.docFiles[i].osFile.Name(), err)
53+
continue
54+
}
55+
filePath := createHtmlPath(e.docFiles[i].osFile.Name(), e.baseDir, e.outputDir)
56+
metadata := meta.Get(context)
57+
metadata["_filepath"] = filePath
58+
e.docFiles[i].metadata = NewMetadata(metadata)
59+
e.docFiles[i].source = string(contents)
60+
e.docFiles[i].html = buff.String()
61+
}
62+
os.RemoveAll(e.outputDir)
63+
e.writeFiles()
64+
}
65+
66+
func (e *Engine) ensureDirectoryExists(path string) {
67+
_, err := os.Stat(path)
68+
if err != nil {
69+
err := os.MkdirAll(path, 0777)
70+
if err != nil {
71+
log.Fatalf("Error creating views directory: %v", err)
72+
}
73+
}
74+
75+
}
76+
77+
func (e *Engine) writeFiles() {
78+
pages := make([]Metadata, 0, len(e.docFiles))
79+
for i := range e.docFiles {
80+
pages = append(pages, e.docFiles[i].metadata)
81+
}
82+
for i := range e.docFiles {
83+
htmlFilePath := strings.TrimSuffix(strings.Replace(e.docFiles[i].osFile.Name(), e.baseDir, e.outputDir, 1), ".md") + ".html"
84+
dirPath := filepath.Dir(htmlFilePath)
85+
e.ensureDirectoryExists(dirPath)
86+
87+
page := NewFilePage(e.docFiles[i], pages)
88+
content := e.layoutTemplate(&page, e.docFiles[i].html)
89+
err := os.WriteFile(htmlFilePath, []byte(content), 0644)
90+
if err != nil {
91+
log.Fatalf("Error writing file %s: %v", htmlFilePath, err)
92+
}
93+
log.Printf("%s -> %s", e.docFiles[i].osFile.Name(), htmlFilePath)
94+
95+
}
96+
}
97+
98+
func (e *Engine) loadDocs(baseDir string) error {
99+
filenames := getMarkdownFiles(baseDir)
100+
101+
files := make([]File, 0, len(filenames))
102+
103+
for _, filename := range filenames {
104+
file, err := os.OpenFile(filename, os.O_RDONLY, 0755)
105+
if err != nil {
106+
log.Printf("Could not open \"%s\": %v", filename, err)
107+
return err
108+
}
109+
if file == nil {
110+
continue
111+
}
112+
files = append(files, File{osFile: file})
113+
}
114+
115+
e.docFiles = files
116+
117+
return nil
118+
}
119+
120+
func createHtmlPath(filePath string, baseDir string, destinationDir string) string {
121+
return strings.TrimSuffix(strings.Replace(filePath, baseDir, destinationDir, 1), ".md") + ".html"
122+
}
123+
124+
func getMarkdownFiles(baseDir string) []string {
125+
filenames := make([]string, 0, 10)
126+
127+
var rootProcessed bool
128+
filepath.WalkDir(baseDir, func(path string, d fs.DirEntry, err error) error {
129+
if path == baseDir && !rootProcessed {
130+
rootProcessed = true
131+
return nil
132+
}
133+
if err != nil {
134+
return err
135+
}
136+
if d.IsDir() {
137+
filenames = append(filenames, getMarkdownFiles(filepath.Join(baseDir, d.Name()))...)
138+
return nil
139+
}
140+
if filepath.Ext(d.Name()) == ".md" {
141+
filenames = append(filenames, path)
142+
return nil
143+
}
144+
return nil
145+
146+
})
147+
148+
return filenames
149+
}

website/ssg/file.go

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package ssg
2+
3+
import "os"
4+
5+
type File struct {
6+
source string
7+
html string
8+
metadata Metadata
9+
osFile *os.File
10+
}

website/ssg/filepage.go

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package ssg
2+
3+
type FilePage struct {
4+
file File
5+
site SiteMetadata
6+
}
7+
8+
func NewFilePage(file File, pages []Metadata) FilePage {
9+
return FilePage{file: file, site: SiteMetadata{pages}}
10+
}
11+
12+
func (fp *FilePage) GetBoolVar(name string) bool {
13+
return false
14+
}
15+
16+
func (fp *FilePage) GetIntVar(name string) int {
17+
return 0
18+
}
19+
20+
func (fp *FilePage) GetFloatVar(name string) float64 {
21+
return 0
22+
}
23+
24+
func (fp *FilePage) GetStringVar(name string) string {
25+
return ""
26+
}
27+
28+
func (fp *FilePage) GetVar(name string) any {
29+
return nil
30+
}
31+
32+
func (fp *FilePage) Title() string {
33+
return fp.file.metadata.Title
34+
}
35+
func (fp *FilePage) Author() string {
36+
return fp.file.metadata.Author
37+
}
38+
func (fp *FilePage) Description() string {
39+
return fp.file.metadata.Description
40+
}
41+
func (fp *FilePage) Slug() string {
42+
return fp.file.metadata.Slug
43+
}
44+
func (fp *FilePage) Tags() []string {
45+
return fp.file.metadata.Tags
46+
}
47+
func (fp *FilePage) Site() Site {
48+
return &fp.site
49+
}

0 commit comments

Comments
 (0)