You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
website/news.go

162 lines
3.3 KiB
Go

package main
import (
"bytes"
"os"
"path"
"sort"
"strings"
"time"
"github.com/yuin/goldmark"
"github.com/yuin/goldmark/extension"
"github.com/yuin/goldmark/parser"
"github.com/yuin/goldmark/renderer/html"
mathjax "github.com/litao91/goldmark-mathjax"
"gopkg.in/yaml.v3"
)
var md goldmark.Markdown
func init() {
md = goldmark.New(
goldmark.WithExtensions(
extension.GFM,
extension.Typographer,
// Questo pacchetto ha un nome stupido perché in realtà si occupa solo del parsing lato server del Markdown mentre lato client usiamo KaTeX.
mathjax.NewMathJax(),
),
goldmark.WithParserOptions(
parser.WithAutoHeadingID(),
),
goldmark.WithRendererOptions(
html.WithHardWraps(),
html.WithXHTML(),
),
)
}
type ArticleFrontMatter struct {
Title string `yaml:"title"`
Description string `yaml:"description"`
Tags []string `yaml:"tags,flow"`
PublishDate string `yaml:"publish_date"`
Important bool `yaml:"important"`
}
type Article struct {
Id string
Title string
Description string
Tags []string
PublishDate time.Time
Important bool
SourceMarkdown string
OutputHTML string
}
type ArticleRegistry struct {
Articles map[string]*Article
}
func removeBlanks(v []string) []string {
r := []string{}
for _, s := range v {
if len(strings.TrimSpace(s)) > 0 {
r = append(r, s)
}
}
return r
}
func (ar *ArticleRegistry) LoadArticle(name string) (*Article, error) {
fileBytes, err := os.ReadFile(path.Join("./news/", name+".md"))
if err != nil {
return nil, err
}
source := string(fileBytes)
// TODO: Ehm bugia esiste "https://github.com/yuin/goldmark-meta" però boh per ora funge tutto
parts := removeBlanks(strings.Split(source, "---"))
frontMatterSource := parts[0]
markdownSource := strings.Join(parts[1:], "---")
var frontMatter ArticleFrontMatter
if err := yaml.Unmarshal([]byte(frontMatterSource), &frontMatter); err != nil {
return nil, err
}
publishDate, err := time.Parse("2006/01/02 15:04", frontMatter.PublishDate)
if err != nil {
return nil, err
}
var buf bytes.Buffer
if err := md.Convert([]byte(markdownSource), &buf); err != nil {
return nil, err
}
article := &Article{
Id: name,
Title: frontMatter.Title,
Description: frontMatter.Description,
Tags: frontMatter.Tags,
PublishDate: publishDate,
Important: frontMatter.Important,
SourceMarkdown: markdownSource,
OutputHTML: buf.String(),
}
ar.Articles[name] = article
return article, nil
}
func (ar *ArticleRegistry) LoadAll() ([]*Article, error) {
entries, err := os.ReadDir("./news")
if err != nil {
return nil, err
}
articles := []*Article{}
for _, entry := range entries {
if !entry.IsDir() {
name := strings.TrimRight(entry.Name(), ".md")
article, err := ar.LoadArticle(name)
if err != nil {
return nil, err
}
articles = append(articles, article)
}
}
sort.Slice(articles, func(i, j int) bool {
return articles[i].PublishDate.After(articles[j].PublishDate)
})
return articles, nil
}
func NewArticleRegistry() *ArticleRegistry {
return &ArticleRegistry{
map[string]*Article{},
}
}
func (ar *ArticleRegistry) Render(name string) (string, error) {
article, err := ar.LoadArticle(name)
if err != nil {
return "", err
}
return article.OutputHTML, nil
}