fix(loader): index.md article slug = folder name; skip subject-root index.md

This commit is contained in:
sam
2026-09-10 15:51:14 +10:00
parent ad445742bc
commit e578f1278f

View File

@@ -180,6 +180,12 @@ func (c *Content) loadSubject(slug string) (*Subject, error) {
// (skips _prefixed dirs/files: config, templates). Supports both flat
// subjects/<s>/<slug>.md and folder-per-article subjects/<s>/<slug>/<slug>.md.
func (c *Content) loadFilesUnder(dir string, out *[]*Article) error {
return c.loadFilesUnderDepth(dir, out, 0)
}
// loadFilesUnderDepth: depth 0 = collection/subject root (skip index.md as it's the
// subject's own index), depth 1+ = article folders (index.md IS the article).
func (c *Content) loadFilesUnderDepth(dir string, out *[]*Article, depth int) error {
entries, err := os.ReadDir(dir)
if err != nil {
return err
@@ -189,17 +195,21 @@ func (c *Content) loadFilesUnder(dir string, out *[]*Article) error {
if e.IsDir() {
// recurse one level (article folder) — skip hidden/_ folders (e.g. _attachments)
if !strings.HasPrefix(name, "_") {
c.loadFilesUnder(path.Join(dir, name), out)
c.loadFilesUnderDepth(path.Join(dir, name), out, depth + 1)
}
continue
}
if !strings.HasSuffix(name, ".md") {
continue
}
// skip _ files (config, templates) BUT _index.md is the real article in a folder
// skip _ files (config, templates) — but index.md/_index.md in a folder is the article
if strings.HasPrefix(name, "_") && name != "_index.md" {
continue
}
// at the subject/collection root (depth 0), index.md = the subject's own index — skip
if depth == 0 && (name == "index.md" || name == "_index.md") {
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)
@@ -338,15 +348,16 @@ func parseFrontMatter(text string) (FrontMatter, string, bool) {
}
// slugOf derives a slug from a file path: dir/file.md -> file
// slugOf derives a slug from a file path: dir/index.md -> folder name (Decap nested),
// otherwise dir/file.md -> file base.
func slugOf(full string) string {
base := path.Base(full)
base = strings.TrimSuffix(base, ".md")
// article files are now <folder>/_index.md — the slug is the folder name.
if base == "_index" {
// article files are now <folder>/index.md (Decap nested) — slug is the folder name.
if base == "_index" || base == "index" {
dir := path.Dir(full)
base = path.Base(dir)
}
// lowercase for URL-friendly slugs
return strings.ToLower(base)
}