feat: publish control — missing 'published:' defaults true; published:false hides article from all routes + listings; subjects date-sorted so Topics boxes/dropdowns show newest

This commit is contained in:
sam
2026-09-09 13:59:17 +10:00
parent 29ace856d7
commit d43c492501

View File

@@ -158,6 +158,8 @@ func (c *Content) loadSubject(slug string) (*Subject, error) {
if err := c.loadFilesUnder(dir, &s.Articles); err != nil {
return nil, err
}
// newest first within a subject (drives Topics boxes + ribbon dropdowns)
sortArticles(s.Articles)
for _, a := range s.Articles {
a.Subject = slug
c.Articles = append(c.Articles, a)
@@ -177,6 +179,7 @@ func (c *Content) loadFilesUnder(dir string, out *[]*Article) error {
continue
}
if a, err := c.loadFile(path.Join(dir, name)); err == nil {
// unpublished articles are drafts — load, then hide from all listings
*out = append(*out, a)
} else {
log.Printf("article %s: %v", name, err)
@@ -237,30 +240,36 @@ func (c *Content) findSubject(slug string) *Subject {
return nil
}
// findArticle returns the article with the given slug, or nil.
// findArticle returns the article with the given slug, or nil. Drafts are not served.
func (c *Content) findArticle(slug string) *Article {
for _, a := range c.Articles {
if a.Slug == slug {
if a.Slug == slug && a.FM.Published {
return a
}
}
return nil
}
// findArticlesBySubject returns articles in a subject, newest first.
// findArticlesBySubject returns published articles in a subject, newest first.
func (c *Content) findArticlesBySubject(slug string) []*Article {
var out []*Article
for _, a := range c.Articles {
if a.Subject == slug {
if a.Subject == slug && a.FM.Published {
out = append(out, a)
}
}
sortArticles(out)
return out
}
// latest returns up to n articles across all subjects, newest first.
// latest returns up to n published articles across all subjects, newest first.
func (c *Content) latest(n int) []*Article {
out := c.Articles
var out []*Article
for _, a := range c.Articles {
if a.FM.Published {
out = append(out, a)
}
}
sortArticles(out)
if len(out) > n {
out = out[:n]
@@ -268,10 +277,10 @@ func (c *Content) latest(n int) []*Article {
return out
}
// featured returns the first article marked featured.
// featured returns the first published article marked featured.
func (c *Content) featured() *Article {
for _, a := range c.Articles {
if a.FM.Featured {
if a.FM.Featured && a.FM.Published {
return a
}
}
@@ -296,6 +305,11 @@ func parseFrontMatter(text string) (FrontMatter, string, bool) {
if err := yaml.Unmarshal([]byte(yamlText), &fm); err != nil {
return FrontMatter{}, text, false
}
// Missing `published:` key = published (default true). go-yaml sets the
// bool to false when the key is absent, so detect absence from the raw text.
if !strings.Contains(yamlText, "published") {
fm.Published = true
}
return fm, body, true
}