fork of anirudh.fi/vite that uses chroma for hl
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Atom feeds, date parsing in template, etc.

+144 -8
+93
atom/feed.go
··· 1 + package atom 2 + 3 + import ( 4 + "encoding/xml" 5 + "time" 6 + 7 + "git.icyphox.sh/vite/config" 8 + "git.icyphox.sh/vite/markdown" 9 + ) 10 + 11 + type AtomLink struct { 12 + XMLName xml.Name `xml:"link"` 13 + Href string `xml:"href,attr"` 14 + Rel string `xml:"rel,attr,omitempty"` 15 + } 16 + 17 + type AtomSummary struct { 18 + XMLName xml.Name `xml:"summary"` 19 + Content string `xml:",chardata"` 20 + Type string `xml:"type,attr"` 21 + } 22 + 23 + type AtomAuthor struct { 24 + XMLName xml.Name `xml:"author"` 25 + Name string `xml:"name"` 26 + Email string `xml:"email"` 27 + } 28 + 29 + type AtomEntry struct { 30 + XMLName xml.Name `xml:"entry"` 31 + Title string `xml:"title"` 32 + Updated string `xml:"updated"` 33 + ID string `xml:"id"` 34 + Link *AtomLink 35 + Summary *AtomSummary 36 + } 37 + 38 + type AtomFeed struct { 39 + XMLName xml.Name `xml:"feed"` 40 + Xmlns string `xml:"xmlns,attr"` 41 + Title string `xml:"title"` 42 + Subtitle string `xml:"subtitle"` 43 + ID string `xml:"id"` 44 + Updated string `xml:"updated"` 45 + Link *AtomLink 46 + Author *AtomAuthor `xml:"author"` 47 + Entries []AtomEntry 48 + } 49 + 50 + func NewAtomFeed(srcDir string, posts []markdown.Output) ([]byte, error) { 51 + entries := []AtomEntry{} 52 + config := config.Config 53 + for _, p := range posts { 54 + dateStr := p.Meta["date"] 55 + date, err := time.Parse("2006-01-02", dateStr) 56 + if err != nil { 57 + return nil, err 58 + } 59 + rfc3339 := date.Format(time.RFC3339) 60 + 61 + entry := AtomEntry{ 62 + Title: p.Meta["title"], 63 + Updated: rfc3339, 64 + ID: NewUUID().String(), 65 + Link: &AtomLink{Href: config.URL + srcDir + p.Meta["slug"]}, 66 + Summary: &AtomSummary{Content: string(p.HTML), Type: "html"}, 67 + } 68 + entries = append(entries, entry) 69 + } 70 + 71 + // 2021-07-14T00:00:00Z 72 + now := time.Now().Format(time.RFC3339) 73 + feed := &AtomFeed{ 74 + Xmlns: "http://www.w3.org/2005/Atom", 75 + Title: config.Title, 76 + ID: config.URL, 77 + Subtitle: config.Desc, 78 + Link: &AtomLink{Href: config.URL}, 79 + Author: &AtomAuthor{ 80 + Name: config.Author.Name, 81 + Email: config.Author.Email, 82 + }, 83 + Updated: now, 84 + Entries: entries, 85 + } 86 + 87 + feedXML, err := xml.MarshalIndent(feed, " ", " ") 88 + if err != nil { 89 + return nil, err 90 + } 91 + // Add the <?xml...> header. 92 + return []byte(xml.Header + string(feedXML)), nil 93 + }
+25
atom/uuid.go
··· 1 + package atom 2 + 3 + import ( 4 + "crypto/rand" 5 + "fmt" 6 + ) 7 + 8 + type UUID [16]byte 9 + 10 + // Create a new uuid v4 11 + func NewUUID() *UUID { 12 + u := &UUID{} 13 + _, err := rand.Read(u[:16]) 14 + if err != nil { 15 + panic(err) 16 + } 17 + 18 + u[8] = (u[8] | 0x80) & 0xBf 19 + u[6] = (u[6] | 0x40) & 0x4f 20 + return u 21 + } 22 + 23 + func (u *UUID) String() string { 24 + return fmt.Sprintf("%x-%x-%x-%x-%x", u[:4], u[4:6], u[6:8], u[8:10], u[10:]) 25 + }
+14 -2
commands/build.go
··· 7 7 "strings" 8 8 "time" 9 9 10 + "git.icyphox.sh/vite/atom" 10 11 "git.icyphox.sh/vite/config" 11 12 "git.icyphox.sh/vite/markdown" 12 13 "git.icyphox.sh/vite/util" ··· 137 138 138 139 // Sort posts slice by date 139 140 sort.Slice(posts, func(i, j int) bool { 140 - date1 := posts[j].Meta["date"].(time.Time) 141 - date2 := posts[i].Meta["date"].(time.Time) 141 + dateStr1 := posts[j].Meta["date"] 142 + dateStr2 := posts[i].Meta["date"] 143 + date1, _ := time.Parse("2006-01-02", dateStr1) 144 + date2, _ := time.Parse("2006-01-02", dateStr2) 142 145 return date1.Before(date2) 143 146 }) 144 147 } ··· 160 163 Body string 161 164 Posts []markdown.Output 162 165 }{config.Config, out.Meta, string(out.HTML), posts}) 166 + 167 + // Create feeds 168 + // ex: build/blog/feed.xml 169 + xml, err := atom.NewAtomFeed(d, posts) 170 + if err != nil { 171 + return err 172 + } 173 + feedFile := filepath.Join(dstDir, "feed.xml") 174 + os.WriteFile(feedFile, xml, 0755) 163 175 } 164 176 return nil 165 177 }
+2 -2
commands/new.go
··· 14 14 15 15 content := fmt.Sprintf(`--- 16 16 template: 17 - url: %s 17 + slug: %s 18 18 title: 19 19 subtitle: 20 20 date: %s ··· 24 24 if err != nil { 25 25 return err 26 26 } 27 - os.WriteFile(path, []byte(content), 0644) 27 + os.WriteFile(path, []byte(content), 0755) 28 28 return nil 29 29 }
+1 -1
markdown/frontmatter.go
··· 9 9 "gopkg.in/yaml.v3" 10 10 ) 11 11 12 - type Matter map[string]interface{} 12 + type Matter map[string]string 13 13 14 14 type MarkdownDoc struct { 15 15 Frontmatter Matter
+9 -3
markdown/markdown.go
··· 4 4 "os" 5 5 "path/filepath" 6 6 "text/template" 7 + "time" 7 8 8 9 bfc "github.com/Depado/bfchroma" 9 10 bf "github.com/russross/blackfriday/v2" ··· 46 47 // in the frontmatter. data is the template struct. 47 48 func (out *Output) RenderHTML(dst, tmplDir string, data interface{}) error { 48 49 metaTemplate := out.Meta["template"] 49 - if metaTemplate == nil { 50 + if metaTemplate == "" { 50 51 metaTemplate = "text.html" 51 52 } 52 53 53 - t, err := template.ParseGlob(filepath.Join(tmplDir, "*.html")) 54 + t, err := template.New("").Funcs(template.FuncMap{ 55 + "parsedate": func(s string) time.Time { 56 + date, _ := time.Parse("2006-01-02", s) 57 + return date 58 + }, 59 + }).ParseGlob(filepath.Join(tmplDir, "*.html")) 54 60 if err != nil { 55 61 return err 56 62 } ··· 60 66 return err 61 67 } 62 68 63 - if err = t.ExecuteTemplate(w, metaTemplate.(string), data); err != nil { 69 + if err = t.ExecuteTemplate(w, metaTemplate, data); err != nil { 64 70 return err 65 71 } 66 72 return nil