Monorepo for Tangled tangled.org
6

Configure Feed

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

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