Home

blog @main - refs - log -
-
https://git.jolheiser.com/blog.git
My nonexistent blog
blog / templates.go
- raw
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
package main

import (
	"bytes"
	"fmt"
	"strings"
	"time"

	"github.com/BurntSushi/toml"
	chromahtml "github.com/alecthomas/chroma/v2/formatters/html"
	"github.com/yuin/goldmark"
	emoji "github.com/yuin/goldmark-emoji"
	highlighting "github.com/yuin/goldmark-highlighting/v2"
	meta "github.com/yuin/goldmark-meta"
	"github.com/yuin/goldmark/extension"
	"github.com/yuin/goldmark/parser"
	"github.com/yuin/goldmark/renderer/html"
)

// Articles by Category
type Articles map[string][]Article

type Article struct {
	Content string
	Meta
}

func (a Article) Slug() string {
	return strings.NewReplacer(" ", "-").Replace(strings.ToLower(a.Meta.Title))
}

type Meta struct {
	Title    string
	Summary  string
	Date     time.Time
	Category string
	Draft    bool
	path     string
}

type Author struct {
	Name  string
	Email string
}

func Parse(content string) (Article, error) {
	lines := strings.Split(content, "\n")

	start, end := -1, -1
	for idx, line := range lines {
		if strings.TrimSpace(line) == "" {
			continue
		}

		if isTOMLSeparator(line) {
			if start == -1 {
				start = idx
				continue
			}
			end = idx
			break
		}
	}

	var meta Meta
	body := content
	if start != -1 && end != -1 {
		body = strings.Join(lines[end+1:], "\n")
		if err := toml.Unmarshal([]byte(strings.Join(lines[start+1:end], "\n")), &meta); err != nil {
			return Article{}, fmt.Errorf("could not parse frontmatter: %w", err)
		}
	}

	var buf bytes.Buffer
	err := Markdown.Convert([]byte(body), &buf)
	if err != nil {
		return Article{}, fmt.Errorf("could not convert article: %w", err)
	}

	return Article{
		Content: buf.String(),
		Meta:    meta,
	}, nil
}

func isTOMLSeparator(line string) bool {
	for _, char := range line {
		if char != '+' {
			return false
		}
	}
	return true
}

func Published(articles []Article) int {
	var num int
	for _, a := range articles {
		if !a.Draft {
			num++
		}
	}
	return num
}

var (
	opts = []chromahtml.Option{
		chromahtml.WithClasses(true),
		chromahtml.WithAllClasses(true),
		// chromahtml.WithLineNumbers(true),
	}
	Markdown = goldmark.New(
		goldmark.WithParserOptions(
			parser.WithAutoHeadingID(),
		),
		goldmark.WithRendererOptions(
			html.WithUnsafe(),
		),
		goldmark.WithExtensions(
			extension.GFM,
			extension.Footnote,
			meta.Meta,
			emoji.Emoji,
			highlighting.NewHighlighting(
				highlighting.WithFormatOptions(
					opts...,
				),
			),
		),
	)
	CSS = chromahtml.New(opts...)
)