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 article
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...)
)
|