This repository has no description
1package timeline
2
3import (
4 "bytes"
5 "io/fs"
6 "log/slog"
7 "net/http"
8 "os"
9 "strings"
10
11 "github.com/adrg/frontmatter"
12 "github.com/go-chi/chi/v5"
13 "tangled.org/core/appview/config"
14 "tangled.org/core/appview/db"
15 "tangled.org/core/appview/oauth"
16 "tangled.org/core/appview/pages"
17)
18
19type postMeta struct {
20 Slug string `yaml:"slug"`
21 Title string `yaml:"title"`
22 Date string `yaml:"date"`
23 Draft bool `yaml:"draft"`
24}
25
26type Timeline struct {
27 oauth *oauth.OAuth
28 db *db.DB
29 config *config.Config
30 pages *pages.Pages
31 logger *slog.Logger
32 recentPosts []pages.BlogPost
33}
34
35func New(
36 oauth *oauth.OAuth,
37 db *db.DB,
38 config *config.Config,
39 pages *pages.Pages,
40 logger *slog.Logger,
41 postsDir string,
42) *Timeline {
43 t := &Timeline{
44 oauth: oauth,
45 db: db,
46 config: config,
47 pages: pages,
48 logger: logger,
49 }
50 t.recentPosts = loadRecentPosts(postsDir, logger)
51 return t
52}
53
54func (t *Timeline) Router() http.Handler {
55 r := chi.NewRouter()
56 r.Get("/", t.HomeOrTimeline)
57 r.Get("/home", t.Home)
58 r.Get("/timeline", t.Timeline)
59 return r
60}
61
62func loadRecentPosts(postsDir string, logger *slog.Logger) []pages.BlogPost {
63 fsys := os.DirFS(postsDir)
64 entries, err := fs.ReadDir(fsys, ".")
65 if err != nil {
66 logger.Warn("failed to read blog posts dir", "dir", postsDir, "err", err)
67 return nil
68 }
69
70 var posts []postMeta
71 for _, entry := range entries {
72 if entry.IsDir() || !strings.HasSuffix(entry.Name(), ".md") {
73 continue
74 }
75 data, err := fs.ReadFile(fsys, entry.Name())
76 if err != nil {
77 continue
78 }
79 var meta postMeta
80 if _, err := frontmatter.Parse(bytes.NewReader(data), &meta); err != nil {
81 continue
82 }
83 if meta.Draft {
84 continue
85 }
86 posts = append(posts, meta)
87 }
88
89 // sort newest-first by date string (format "2006-01-02" sorts lexicographically)
90 for i := 1; i < len(posts); i++ {
91 for j := i; j > 0 && posts[j].Date > posts[j-1].Date; j-- {
92 posts[j], posts[j-1] = posts[j-1], posts[j]
93 }
94 }
95
96 if len(posts) > 3 {
97 posts = posts[:3]
98 }
99
100 result := make([]pages.BlogPost, len(posts))
101 for i, p := range posts {
102 result[i] = pages.BlogPost{Slug: p.Slug, Title: p.Title, Date: p.Date}
103 }
104 return result
105}