From d43c4925017e450d9ec67cb9b45d6d88748cbbc3 Mon Sep 17 00:00:00 2001 From: sam Date: Wed, 9 Sep 2026 13:59:17 +1000 Subject: [PATCH] =?UTF-8?q?feat:=20publish=20control=20=E2=80=94=20missing?= =?UTF-8?q?=20'published:'=20defaults=20true;=20published:false=20hides=20?= =?UTF-8?q?article=20from=20all=20routes=20+=20listings;=20subjects=20date?= =?UTF-8?q?-sorted=20so=20Topics=20boxes/dropdowns=20show=20newest?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/content.go | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/app/src/content.go b/app/src/content.go index 1c45198..37a64dd 100644 --- a/app/src/content.go +++ b/app/src/content.go @@ -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 }