Browse Source

Initial commit

master
Jan-Lukas Else 8 months ago
commit
00b47dd1b6
7 changed files with 305 additions and 0 deletions
  1. +7
    -0
      .gitignore
  2. +3
    -0
      README.md
  3. +12
    -0
      go.mod
  4. +21
    -0
      go.sum
  5. +134
    -0
      main.go
  6. +38
    -0
      markdown.go
  7. +90
    -0
      templates/single.gohtml

+ 7
- 0
.gitignore View File

@ -0,0 +1,7 @@
# Source and output
/source
/output
# Binary
/GoBlog
# JetBrains IDEA stuff
/.idea

+ 3
- 0
README.md View File

@ -0,0 +1,3 @@
# GoBlog
This is a WORK-IN-PROGRESS static site generator written in Go. It should be very fast, but hasn't many features yet.

+ 12
- 0
go.mod View File

@ -0,0 +1,12 @@
module git.jlel.se/jlelse/GoBlog
go 1.14
require (
github.com/kr/text v0.2.0 // indirect
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
github.com/yuin/goldmark v1.1.31
github.com/yuin/goldmark-meta v0.0.0-20191126180153-f0638e958b60
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
gopkg.in/yaml.v2 v2.3.0 // indirect
)

+ 21
- 0
go.sum View File

@ -0,0 +1,21 @@
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/yuin/goldmark v1.1.7/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.31 h1:nKIhaVknZ0wOBBg0Uu6px+t218SfkLh2i/JwwOXYXqs=
github.com/yuin/goldmark v1.1.31/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark-meta v0.0.0-20191126180153-f0638e958b60 h1:gZucqLjL1eDzVWrXj4uiWeMbAopJlBR2mKQAsTGdPwo=
github.com/yuin/goldmark-meta v0.0.0-20191126180153-f0638e958b60/go.mod h1:i9VhcIHN2PxXMbQrKqXNueok6QNONoPjNMoj9MygVL0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

+ 134
- 0
main.go View File

@ -0,0 +1,134 @@
package main
import (
"fmt"
"html/template"
"io/ioutil"
"os"
"path"
"path/filepath"
"strings"
"sync"
)
type Article struct {
Path string
Content string
Meta map[string]interface{}
}
type parseResult struct {
Article *Article
Err error
}
func main() {
articles, err := parse()
if err != nil {
fmt.Println("Error:", err.Error())
return
}
fmt.Println("Finished parsing")
err = generate(articles)
if err != nil {
fmt.Println("Error:", err.Error())
return
}
fmt.Println("Finished generating")
}
func parse() ([]*Article, error) {
var files []string
_ = filepath.Walk("source", func(path string, info os.FileInfo, err error) error {
if !info.IsDir() {
files = append(files, path)
}
return nil
})
var results []parseResult
var wg sync.WaitGroup
for _, file := range files {
file := file
wg.Add(1)
go func() {
defer wg.Done()
// Read file
byteArray, err := ioutil.ReadFile(file)
if err != nil {
results = append(results, parseResult{Err: err})
return
}
// Parse markdown and meta data
content, metaData, err := convert(byteArray)
if err != nil {
results = append(results, parseResult{Err: err})
return
}
// Compute article path
articlePath := strings.TrimPrefix(file, "source/")
if strings.HasSuffix(articlePath, "index.md") {
articlePath = strings.TrimSuffix(articlePath, "/index.md")
} else {
articlePath = strings.TrimSuffix(articlePath, ".md")
}
// Save article
results = append(results, parseResult{Article: &Article{
Path: articlePath,
Content: content,
Meta: metaData,
}})
}()
}
wg.Wait()
var articles []*Article
for _, result := range results {
if result.Err != nil {
return nil, result.Err
} else {
articles = append(articles, result.Article)
}
}
return articles, nil
}
func generate(articles []*Article) error {
// Delete old files
err := os.RemoveAll("output")
if err != nil {
return err
}
// Generate new files
var wg sync.WaitGroup
templates := template.Must(template.New("").ParseFiles("templates/single.gohtml"))
for _, article := range articles {
article := article
wg.Add(1)
go func() {
var file *os.File
defer func() {
_ = file.Close()
wg.Done()
}()
err := os.MkdirAll(path.Join("output", article.Path), os.ModePerm)
if err != nil {
panic(err)
}
file, err = os.Create(path.Join("output", article.Path, "index.html"))
if err != nil {
panic(err)
}
err = templates.ExecuteTemplate(file, "single.gohtml", struct {
Article Article
Content template.HTML
}{
Article: *article,
Content: template.HTML(article.Content),
})
if err != nil {
panic(err)
}
}()
}
wg.Wait()
return nil
}

+ 38
- 0
markdown.go View File

@ -0,0 +1,38 @@
package main
import (
"bytes"
"github.com/yuin/goldmark"
meta "github.com/yuin/goldmark-meta"
"github.com/yuin/goldmark/extension"
"github.com/yuin/goldmark/parser"
"github.com/yuin/goldmark/renderer/html"
)
var markdown goldmark.Markdown
func init() {
markdown = goldmark.New(
goldmark.WithRendererOptions(
html.WithUnsafe(),
),
goldmark.WithParserOptions(
parser.WithAutoHeadingID(),
),
goldmark.WithExtensions(
meta.Meta,
extension.GFM,
extension.Footnote,
extension.Typographer,
),
)
}
func convert(source []byte) (content string, metaData map[string]interface{}, err error) {
context := parser.NewContext()
var buffer bytes.Buffer
err = markdown.Convert(source, &buffer, parser.WithContext(context))
content = buffer.String()
metaData = meta.Get(context)
return
}

+ 90
- 0
templates/single.gohtml View File

@ -0,0 +1,90 @@
<!doctype html>
<html lang=en>
<meta charset=utf-8>
<meta name=viewport content="width=device-width,initial-scale=1">
<meta http-equiv=x-ua-compatible content="IE=edge">
<title>{{ index .Article.Meta "title" }}</title>
<style>
html {
--background: #fff;
--primary: #000;
color: #000;
scrollbar-color: var(--primary) transparent
}
@media (prefers-color-scheme: dark) {
html {
--background: #000;
--primary: #fff;
color: #fff
}
}
body {
background: #fff;
background: var(--background, #fff);
font-family: sans-serif;
line-height: 1.5;
margin: 0 auto;
max-width: 750px;
padding: 10px;
word-break: break-word;
overflow-wrap: break-word
}
body * {
color: #000;
color: var(--primary, #000);
max-width: 100%
}
h1 a, h2 a {
text-decoration: none
}
img {
width: 100%
}
input, button {
border: 1px solid #000;
border: 1px solid var(--primary, #000);
background: #fff;
background: var(--background, #fff);
color: #000;
color: var(--primary, #000);
padding: 5px 10px;
border-radius: 0;
box-sizing: border-box;
text-decoration: none;
font-size: 1rem
}
blockquote {
border-left: 5px solid #000;
border-left: 5px solid var(--primary, #000);
padding-left: 20px;
margin-left: 0
}
pre {
padding: 10px;
border: 1px solid #000;
border: 1px solid var(--primary, #000);
white-space: pre-wrap
}
:not(pre) > code {
font-size: 1rem
}
code {
font-family: monospace
}
</style>
<main class=h-entry>
<article>
<h1 class=p-name>{{ index .Article.Meta "title" }}</h1>
<div class=e-content>{{ .Content }}</div>
</article>
</main>

Loading…
Cancel
Save