Feature: Pagina notize dinamica e renderizzazione del markdown

main-old
Antonio De Lucreziis 3 years ago
parent 54f5d798e8
commit e727b2f71f

@ -5,4 +5,7 @@ go 1.13
require ( require (
github.com/go-chi/chi/v5 v5.0.7 github.com/go-chi/chi/v5 v5.0.7
github.com/joho/godotenv v1.4.0 github.com/joho/godotenv v1.4.0
github.com/litao91/goldmark-mathjax v0.0.0-20210217064022-a43cf739a50f
github.com/yuin/goldmark v1.4.4
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
) )

@ -1,4 +1,21 @@
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-chi/chi/v5 v5.0.7 h1:rDTPXLDHGATaeHvVlLcR4Qe0zftYethFucbjVQ1PxU8= github.com/go-chi/chi/v5 v5.0.7 h1:rDTPXLDHGATaeHvVlLcR4Qe0zftYethFucbjVQ1PxU8=
github.com/go-chi/chi/v5 v5.0.7/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= github.com/go-chi/chi/v5 v5.0.7/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
github.com/joho/godotenv v1.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg= github.com/joho/godotenv v1.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg=
github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/litao91/goldmark-mathjax v0.0.0-20210217064022-a43cf739a50f h1:plCPYXRXDCO57qjqegCzaVf1t6aSbgCMD+zfz18POfs=
github.com/litao91/goldmark-mathjax v0.0.0-20210217064022-a43cf739a50f/go.mod h1:leg+HM7jUS84JYuY120zmU68R6+UeU6uZ/KAW7cViKE=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.4.4 h1:zNWRjYUW32G9KirMXYHQHVNFkXvMI7LpgNW2AgYAoIs=
github.com/yuin/goldmark v1.4.4/go.mod h1:rmuwmfZ0+bvzB24eSC//bk1R1Zp3hM0OXYv/G2LIilg=
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/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

@ -1,6 +1,7 @@
package main package main
import ( import (
"html/template"
"log" "log"
"net/http" "net/http"
@ -25,6 +26,8 @@ func main() {
// Templates & Renderer // Templates & Renderer
renderer := NewTemplateRenderer("base.html") renderer := NewTemplateRenderer("base.html")
articleRegistry := NewArticleRegistry()
articleRegistry.LoadAll()
// Routes // Routes
r.Get("/", func(w http.ResponseWriter, r *http.Request) { r.Get("/", func(w http.ResponseWriter, r *http.Request) {
@ -52,11 +55,35 @@ func main() {
}) })
r.Get("/news", func(w http.ResponseWriter, r *http.Request) { r.Get("/news", func(w http.ResponseWriter, r *http.Request) {
err := renderer.Render(w, "news.html", util.H{}) articles, err := articleRegistry.LoadAll()
if err != nil { if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusInternalServerError)
return return
} }
if err := renderer.Render(w, "news.html", util.H{
"Articles": articles,
}); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
})
r.Get("/news/{article}", func(w http.ResponseWriter, r *http.Request) {
article := chi.URLParam(r, "article")
htmlSource, err := articleRegistry.Render(article)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
if err := renderer.Render(w, "news-base.html", util.H{
"ContentHTML": template.HTML(htmlSource),
}); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
}) })
r.Get("/login", func(w http.ResponseWriter, r *http.Request) { r.Get("/login", func(w http.ResponseWriter, r *http.Request) {

@ -0,0 +1,161 @@
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
}

@ -0,0 +1,43 @@
---
important: yes
title: "Notiza 1"
tags: [prova, test, foo, bar]
publish_date: 2021/12/22 22:00
description: |
Lorem ipsum dolor sit amet consectetur adipisicing elit. Quis nemo aperiam, voluptas quam alias esse sed natus tempore suscipit fugiat sit delectus exercitationem numquam ipsum assumenda recusandae consequatur...
---
# Notizia 1
## Heading 2
### Heading 3
#### Heading 4
Lorem ipsum dolor, sit amet consectetur "adipisicing" elit. Repudiandae -- optio ad, consequatur **distinctio possimus** laudantium molestias similique placeat, dolore omnis et aperiam rem delectus tempora $1 + 1$ ea, cupiditate explicabo vel! Porro?
$$
\int_0^1 x^2 \mathrm d x
$$
Lorem ipsum dolor, sit amet consectetur adipisicing elit. Repudiandae optio ad, consequatur distinctio possimus _laudantium molestias similique placeat_, dolore omnis et aperiam rem [delectus tempora ea,](#) cupiditate explicabo vel! Porro?
![testing](https://picsum.photos/200/300)
Lorem ipsum dolor, sit amet consectetur adipisicing elit. Repudiandae optio ad, consequatur distinctio possimus laudantium molestias similique placeat, dolore omnis et aperiam rem delectus tempora ea, cupiditate explicabo vel! Porro?
- Item 1
- Item 2
- Item 3
- Item 4
- Item 5
- Item 5
- Item 5
- foo
- bar
```Makefile
foo
foo
```

@ -0,0 +1,38 @@
---
title: "Notiza 2"
tags: [prova, test, foo, bar]
publish_date: 2021/12/23 22:00
description: |
Lorem ipsum dolor sit amet consectetur adipisicing elit. Quis nemo aperiam, voluptas quam alias esse sed natus tempore suscipit fugiat sit delectus exercitationem numquam ipsum assumenda recusandae consequatur...
---
# Notizia 1
## Heading 2
### Heading 3
#### Heading 4
Lorem ipsum dolor, sit amet consectetur adipisicing elit. Repudiandae optio ad, consequatur **distinctio possimus** laudantium molestias similique placeat, dolore omnis et aperiam rem delectus tempora ea, cupiditate explicabo vel! Porro?
Lorem ipsum dolor, sit amet consectetur adipisicing elit. Repudiandae optio ad, consequatur distinctio possimus _laudantium molestias similique placeat_, dolore omnis et aperiam rem [delectus tempora ea,](#) cupiditate explicabo vel! Porro?
![testing](https://picsum.photos/200/300)
Lorem ipsum dolor, sit amet consectetur adipisicing elit. Repudiandae optio ad, consequatur distinctio possimus laudantium molestias similique placeat, dolore omnis et aperiam rem delectus tempora ea, cupiditate explicabo vel! Porro?
- Item 1
- Item 2
- Item 3
- Item 4
- Item 5
- Item 5
- Item 5
- foo
- bar
```Makefile
foo
foo
```

@ -0,0 +1,38 @@
---
title: "Notiza 3"
tags: [prova, test, foo, bar]
publish_date: 2021/12/24 18:00
description: |
Lorem ipsum dolor sit amet consectetur adipisicing elit. Quis nemo aperiam, voluptas quam alias esse sed natus tempore suscipit fugiat sit delectus exercitationem numquam ipsum assumenda recusandae consequatur...
---
# Notizia 1
## Heading 2
### Heading 3
#### Heading 4
Lorem ipsum dolor, sit amet consectetur adipisicing elit. Repudiandae optio ad, consequatur **distinctio possimus** laudantium molestias similique placeat, dolore omnis et aperiam rem delectus tempora ea, cupiditate explicabo vel! Porro?
Lorem ipsum dolor, sit amet consectetur adipisicing elit. Repudiandae optio ad, consequatur distinctio possimus _laudantium molestias similique placeat_, dolore omnis et aperiam rem [delectus tempora ea,](#) cupiditate explicabo vel! Porro?
![testing](https://picsum.photos/200/300)
Lorem ipsum dolor, sit amet consectetur adipisicing elit. Repudiandae optio ad, consequatur distinctio possimus laudantium molestias similique placeat, dolore omnis et aperiam rem delectus tempora ea, cupiditate explicabo vel! Porro?
- Item 1
- Item 2
- Item 3
- Item 4
- Item 5
- Item 5
- Item 5
- foo
- bar
```Makefile
foo
foo
```

@ -340,7 +340,24 @@ h1, h2, h3, h4 {
font-weight: var(--font-weight-light); font-weight: var(--font-weight-light);
} }
p { h1 {
font-size: 2rem;
}
h2 {
font-size: 1.5rem;
}
h3 {
font-size: 1.35rem;
}
h4 {
font-size: 1.2rem;
font-weight: var(--font-weight-bold);
}
p, ul, ol, li {
margin: 0.5rem 0; margin: 0.5rem 0;
width: 70ch; width: 70ch;
max-width: 100%; max-width: 100%;

@ -0,0 +1,9 @@
{{template "base" .}}
{{define "title"}}PHC • phc.dm.xxxxx.xx{{end}}
{{define "body"}}
<section>
{{ .ContentHTML }}
</section>
{{end}}

@ -4,41 +4,21 @@
{{define "body"}} {{define "body"}}
<section> <section>
<h2> <h2>Notizie Importanti</h2>
<i class="far fa-newspaper"></i>
Notizie Importanti
</h2>
<div class="card-list"> <div class="card-list">
{{ range .Articles }}
{{ if .Important }}
<div class="card"> <div class="card">
<div class="title"> <div class="title">
<a href="/news/notizia-super-wow-1"> <a href="/news/{{ .Id }}">
News 1 {{ .Title }}
</a> </a>
</div> </div>
<div class="date"> <div class="date">{{ .PublishDate.Format "2006/01/02" }}</div>
yyyy-mm-dd <div class="description">{{ .Description }}</div>
</div>
<div class="description">
Lorem ipsum dolor sit amet consectetur adipisicing elit. Quis nemo aperiam, voluptas quam alias esse sed
natus tempore suscipit fugiat sit delectus exercitationem numquam ipsum assumenda recusandae consequatur...
</div>
</div>
<div class="card">
<div class="title">
<a href="/news/notizia-super-wow-2">
News 2
</a>
</div>
<div class="date">
yyyy-mm-dd
</div>
<div class="description">
Lorem ipsum dolor sit amet consectetur adipisicing elit. Quis nemo aperiam, voluptas quam alias esse sed
natus tempore suscipit fugiat sit delectus exercitationem numquam ipsum assumenda recusandae consequatur...
</div>
</div> </div>
{{ end }}
{{ end }}
</div> </div>
</section> </section>
@ -48,72 +28,19 @@
Archivio notizie Archivio notizie
</h2> </h2>
<div class="card-list"> <div class="card-list">
{{ range .Articles }}
{{ if not .Important }}
<div class="card"> <div class="card">
<div class="title"> <div class="title">
<a href="/news/notizia-antica-1">Notizia Antica 1</a> <a href="/news/{{ .Id }}">
</div> {{ .Title }}
<div class="date">yyyy-mm-dd</div> </a>
<div class="description">
Lorem ipsum dolor sit amet consectetur adipisicing elit. Quis nemo aperiam, voluptas quam alias esse sed
natus tempore suscipit fugiat sit delectus exercitationem numquam ipsum assumenda recusandae consequatur...
</div>
</div>
<div class="card">
<div class="title">
<a href="/news/notizia-antica-2">Notizia Antica 2</a>
</div>
<div class="date">yyyy-mm-dd</div>
<div class="description">
Lorem ipsum dolor sit amet consectetur adipisicing elit. Quis nemo aperiam, voluptas quam alias esse sed
natus tempore suscipit fugiat sit delectus exercitationem numquam ipsum assumenda recusandae consequatur...
</div>
</div>
<div class="card">
<div class="title">
<a href="/news/notizia-antica-3">Notizia Antica 3</a>
</div>
<div class="date">yyyy-mm-dd</div>
<div class="description">
Lorem ipsum dolor sit amet consectetur adipisicing elit. Quis nemo aperiam, voluptas quam alias esse sed
natus tempore suscipit fugiat sit delectus exercitationem numquam ipsum assumenda recusandae consequatur...
</div>
</div>
<div class="card">
<div class="title">
<a href="/news/notizia-antica-4">Notizia Antica 4</a>
</div>
<div class="date">yyyy-mm-dd</div>
<div class="description">
Lorem ipsum dolor sit amet consectetur adipisicing elit. Quis nemo aperiam, voluptas quam alias esse sed
natus tempore suscipit fugiat sit delectus exercitationem numquam ipsum assumenda recusandae consequatur...
</div>
</div>
<div class="card">
<div class="title">
<a href="/news/notizia-antica-5">Notizia Antica 5</a>
</div>
<div class="date">yyyy-mm-dd</div>
<div class="description">
Lorem ipsum dolor sit amet consectetur adipisicing elit. Quis nemo aperiam, voluptas quam alias esse sed
natus tempore suscipit fugiat sit delectus exercitationem numquam ipsum assumenda recusandae consequatur...
</div>
</div>
<div class="card">
<div class="title">
<a href="/news/notizia-antica-6">Notizia Antica 6</a>
</div>
<div class="date">yyyy-mm-dd</div>
<div class="description">
Lorem ipsum dolor sit amet consectetur adipisicing elit. Quis nemo aperiam, voluptas quam alias esse sed
natus tempore suscipit fugiat sit delectus exercitationem numquam ipsum assumenda recusandae consequatur...
</div> </div>
<div class="date">{{ .PublishDate.Format "2006/01/02" }}</div>
<div class="description">{{ .Description }}</div>
</div> </div>
{{ end }}
{{ end }}
</div> </div>
</section> </section>
{{end}} {{end}}
Loading…
Cancel
Save