diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0d391ad7337..ef483ad48f5 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -257,7 +257,9 @@ Layer5 uses ES-Lint to maintain code quality & consistency in our UI Code. Every documentation page is also published as Markdown at `/index.md`, with the page title, description, and body content and no navigation, sidebar, footer, or styling. A **View as Markdown** link to it appears in the page's -right-hand meta column (wide screens). Hugo also generates +right-hand meta column (wide screens). The home page and the `/videos/` landing +page have no meta column, so they show no link, but their Markdown is still +published and listed in `llms.txt`. Hugo also generates [`/llms.txt`](https://llmstxt.org/) (an index of pages) and `/llms-full.txt` (full content of every page) at the site root for AI agents. @@ -269,10 +271,16 @@ it, and Docsy v0.14.3 has no equivalent; see the `layouts/_default/single.md` and `list.md` override the module's templates so shortcodes (including `ref` links) are expanded in each page's Markdown. -If you add a new page layout, include `{{ partial "page-markdown-link.html" . }}` -in it, or reuse `page-meta-links.html`, so the new pages keep the link. To leave -a path out of `llms.txt` and `llms-full.txt`, add it to `exclude` under -`[params.llms]` in `hugo.toml`. +If you add a new page layout, render the link only through +`{{ partial "page-meta-links.html" . }}` in the right-hand meta column. Don't call +`page-markdown-link.html` directly, or the link appears outside the meta column. + +To leave a path out of `llms.txt` and `llms-full.txt`, add it to `exclude` under +`[params.llms]` in `hugo.toml`. To keep only the newest N pages of a section +(by front matter `date`), add it to `[params.llms.limit_sections]`; Kanvas +releases are capped at 5 this way. That cap lives in `layouts/index.llms` and +`layouts/index.llmsfull`, which are copies of the module's templates with one +added block, so re-check them against the module when you update it. # Reviews All contributors are invited to review pull requests. See this short video on [how to review a pull request](https://www.youtube.com/watch?v=isLfo7jfE6g&feature=youtu.be). diff --git a/hugo.toml b/hugo.toml index 2ce503ed027..9e40e8c4155 100644 --- a/hugo.toml +++ b/hugo.toml @@ -372,3 +372,7 @@ enable = false generate_llms_txt = true generate_llms_full_txt = true exclude = ["/tags/**", "/categories/**", "/search/"] + # Keep only the newest N pages (by `date`) of a section in llms.txt / llms-full.txt. + # Implemented by the local overrides layouts/index.llms and layouts/index.llmsfull. + [params.llms.limit_sections] + "/kanvas/reference/releases/" = 5 diff --git a/layouts/home.html b/layouts/home.html index 426adad53ba..cde5d4acf6c 100644 --- a/layouts/home.html +++ b/layouts/home.html @@ -3,7 +3,4 @@ {{ with .Content }} {{ . }} {{ end }} -
- {{ partial "page-markdown-link.html" . }} -
{{ end }} diff --git a/layouts/index.llms b/layouts/index.llms new file mode 100644 index 00000000000..704f32df0b1 --- /dev/null +++ b/layouts/index.llms @@ -0,0 +1,147 @@ +{{- /* + llms.txt — Hugo Module by GetHugoThemes + https://github.com/gethugothemes/hugo-modules/llms-txt + + Generates /llms.txt following the llmstxt.org specification. + Grouped by Hugo sections. Respects params.llms.generate_llms_txt, include, and exclude. +*/ -}} + +{{- define "partials/llms_is_valid_page.html" -}} +{{- $url := .url -}} +{{- $includeList := .includeList -}} +{{- $excludeList := .excludeList -}} +{{- $isIncluded := false -}} +{{- if eq (len $includeList) 0 }}{{ $isIncluded = true }}{{ else -}} +{{- range $includeList -}} + {{- if strings.HasSuffix . "/**" }}{{ if strings.HasPrefix $url (strings.TrimSuffix "/**" .) }}{{ $isIncluded = true }}{{ end -}} + {{- else if strings.HasSuffix . "/*" }}{{ $dir := strings.TrimSuffix "*" . }}{{ if and (strings.HasPrefix $url $dir) (ne $url $dir) (not (strings.Contains (strings.TrimSuffix "/" (strings.TrimPrefix $dir $url)) "/")) }}{{ $isIncluded = true }}{{ end -}} + {{- else }}{{ if eq $url . }}{{ $isIncluded = true }}{{ end -}} + {{- end -}} +{{- end -}} +{{- end -}} +{{- $isExcluded := false -}} +{{- range $excludeList -}} + {{- if strings.HasSuffix . "/**" }}{{ if strings.HasPrefix $url (strings.TrimSuffix "/**" .) }}{{ $isExcluded = true }}{{ end -}} + {{- else if strings.HasSuffix . "/*" }}{{ $dir := strings.TrimSuffix "*" . }}{{ if and (strings.HasPrefix $url $dir) (ne $url $dir) (not (strings.Contains (strings.TrimSuffix "/" (strings.TrimPrefix $dir $url)) "/")) }}{{ $isExcluded = true }}{{ end -}} + {{- else }}{{ if eq $url . }}{{ $isExcluded = true }}{{ end -}} + {{- end -}} +{{- end -}} +{{- return (and $isIncluded (not $isExcluded)) -}} +{{- end -}} + +{{- $llms := site.Params.llms | default dict -}} +{{- if ne ($llms.generate_llms_txt | default true) false -}} +{{- $rawExcludeList := $llms.exclude | default slice -}} +{{- $includeList := $llms.include | default slice -}} + +{{- /* Clean Exclude List (Include takes precedence for exact matches) */ -}} +{{- $excludeList := slice -}} +{{- range $rawExcludeList -}} + {{- if not (in $includeList .) -}} + {{- $excludeList = $excludeList | append . -}} + {{- end -}} +{{- end -}} + +{{- /* Local override: keep only the newest N pages under each section in params.llms.limit_sections */ -}} +{{- range $path, $n := $llms.limit_sections | default dict -}} + {{- with site.GetPage $path -}} + {{- range after $n .RegularPagesRecursive.ByDate.Reverse -}} + {{- $excludeList = $excludeList | append .RelPermalink -}} + {{- end -}} + {{- end -}} +{{- end -}} + +# {{ site.Title }} + +> {{ site.Params.metadata.description | default site.Params.description | default site.Title }} + +## Pages + +{{- /* Home page */ -}} +{{- $home := site.Home }} +{{- $showHome := partial "llms_is_valid_page.html" (dict "url" $home.RelPermalink "includeList" $includeList "excludeList" $excludeList) }} +{{- if $showHome }} +{{- $homeUrl := $home.Permalink -}} +{{- with $home.OutputFormats.Get "md" }}{{- $homeUrl = .Permalink -}}{{- end }} +- [{{ $home.Title | default "Home" }}]({{ $homeUrl }}){{ with $home.Params.description }}: {{ . }}{{ end }} +{{- end }} + +{{- /* Standalone section pages (top-level sections with no pages at any depth) */ -}} +{{- range site.Home.Sections }} +{{- if not .RegularPagesRecursive }} +{{- if and .Title .Permalink }} +{{- $show := partial "llms_is_valid_page.html" (dict "url" .RelPermalink "includeList" $includeList "excludeList" $excludeList) }} +{{- if $show }} +{{- $url := .Permalink -}} +{{- with .OutputFormats.Get "md" }}{{- $url = .Permalink -}}{{- end }} +- [{{ .Title }}]({{ $url }}){{ with .Params.description }}: {{ . }}{{ end }} +{{- end }} +{{- end }} +{{- end }} +{{- end }} + +{{- /* Root-level regular pages: About, Contact, etc. */ -}} +{{- range site.Home.RegularPages }} +{{- $show := partial "llms_is_valid_page.html" (dict "url" .RelPermalink "includeList" $includeList "excludeList" $excludeList) }} +{{- if $show }} +{{- $url := .Permalink -}} +{{- with .OutputFormats.Get "md" }}{{- $url = .Permalink -}}{{- end }} +- [{{ .Title }}]({{ $url }}){{ with .Params.description | default (.Summary | plainify | truncate 120) }}: {{ . }}{{ end }} +{{- end }} +{{- end }} + +{{- /* Content sections: Blog, Docs, etc. — top-level only, all nested pages included */ -}} +{{- range site.Home.Sections }} +{{- if .RegularPagesRecursive }} +{{- $section := . }} +{{- $validPages := where .RegularPagesRecursive ".Permalink" "ne" "" }} +{{- $filteredPages := slice }} +{{- range $validPages }} + {{- $page := . }} + {{- $show := partial "llms_is_valid_page.html" (dict "url" $page.RelPermalink "includeList" $includeList "excludeList" $excludeList) }} + {{- if $show }}{{- $filteredPages = $filteredPages | append $page }}{{- end }} +{{- end }} +{{- if $filteredPages }} + +## {{ $section.Title }} +{{- $sectionUrl := $section.Permalink -}} +{{- with $section.OutputFormats.Get "md" }}{{- $sectionUrl = .Permalink -}}{{- end }} +- [{{ $section.Title }}]({{ $sectionUrl }}){{ with $section.Params.description }}: {{ . }}{{ end }} +{{ range $filteredPages }} +{{- if .Title }} +{{- $url := .Permalink -}} +{{- with .OutputFormats.Get "md" }}{{- $url = .Permalink -}}{{- end }} +- [{{ .Title }}]({{ $url }}){{ with .Params.description | default (.Summary | plainify | truncate 120) }}: {{ . }}{{ end }} +{{- end }} +{{- end }} +{{- end }} +{{- end }} +{{- end }} + +{{- /* Taxonomy pages */ -}} +{{- range $taxonomyName, $taxonomy := site.Taxonomies }} +{{- $taxPage := site.GetPage $taxonomyName }} +{{- if $taxPage }} +{{- $showTax := partial "llms_is_valid_page.html" (dict "url" $taxPage.RelPermalink "includeList" $includeList "excludeList" $excludeList) }} +{{- if $showTax }} + +## {{ $taxPage.Title | default ($taxonomyName | humanize) }} +{{- $taxUrl := $taxPage.Permalink -}} +{{- with $taxPage.OutputFormats.Get "md" }}{{- $taxUrl = .Permalink -}}{{- end }} +- [{{ $taxPage.Title | default ($taxonomyName | humanize) }}]({{ $taxUrl }}){{ with $taxPage.Params.description }}: {{ . }}{{ end }} +{{- range $termName, $weightedPages := $taxonomy }} +{{- $termPage := site.GetPage (printf "%s/%s" $taxonomyName $termName) }} +{{- if $termPage }} +{{- $showTerm := partial "llms_is_valid_page.html" (dict "url" $termPage.RelPermalink "includeList" $includeList "excludeList" $excludeList) }} +{{- if $showTerm }} +{{- $url := $termPage.Permalink -}} +{{- with $termPage.OutputFormats.Get "md" }}{{- $url = .Permalink -}}{{- end }} +- [{{ $termPage.Title | default $termName }}]({{ $url }}){{ with $termPage.Params.description }}: {{ . }}{{ end }} +{{- end }} +{{- end }} +{{- end }} +{{- end }} +{{- end }} +{{- end }} + +{{- end -}} diff --git a/layouts/index.llmsfull b/layouts/index.llmsfull new file mode 100644 index 00000000000..7e281606ac7 --- /dev/null +++ b/layouts/index.llmsfull @@ -0,0 +1,194 @@ +{{- /* + llms-full.txt — Hugo Module by GetHugoThemes + https://github.com/gethugothemes/hugo-modules/llms-txt + + Generates /llms-full.txt — the full-content companion to llms.txt. + Respects params.llms.generate_llms_full_txt, include, and exclude settings. +*/ -}} + +{{- define "partials/llms_full_is_valid_page.html" -}} +{{- $url := .url -}} +{{- $includeList := .includeList -}} +{{- $excludeList := .excludeList -}} +{{- $isIncluded := false -}} +{{- if eq (len $includeList) 0 }}{{ $isIncluded = true }}{{ else -}} +{{- range $includeList -}} + {{- if strings.HasSuffix . "/**" }}{{ if strings.HasPrefix $url (strings.TrimSuffix "/**" .) }}{{ $isIncluded = true }}{{ end -}} + {{- else if strings.HasSuffix . "/*" }}{{ $dir := strings.TrimSuffix "*" . }}{{ if and (strings.HasPrefix $url $dir) (ne $url $dir) (not (strings.Contains (strings.TrimSuffix "/" (strings.TrimPrefix $dir $url)) "/")) }}{{ $isIncluded = true }}{{ end -}} + {{- else }}{{ if eq $url . }}{{ $isIncluded = true }}{{ end -}} + {{- end -}} +{{- end -}} +{{- end -}} +{{- $isExcluded := false -}} +{{- range $excludeList -}} + {{- if strings.HasSuffix . "/**" }}{{ if strings.HasPrefix $url (strings.TrimSuffix "/**" .) }}{{ $isExcluded = true }}{{ end -}} + {{- else if strings.HasSuffix . "/*" }}{{ $dir := strings.TrimSuffix "*" . }}{{ if and (strings.HasPrefix $url $dir) (ne $url $dir) (not (strings.Contains (strings.TrimSuffix "/" (strings.TrimPrefix $dir $url)) "/")) }}{{ $isExcluded = true }}{{ end -}} + {{- else }}{{ if eq $url . }}{{ $isExcluded = true }}{{ end -}} + {{- end -}} +{{- end -}} +{{- return (and $isIncluded (not $isExcluded)) -}} +{{- end -}} + +{{- $llms := site.Params.llms | default dict -}} +{{- if ne ($llms.generate_llms_full_txt | default true) false -}} +{{- $rawExcludeList := $llms.exclude | default slice -}} +{{- $includeList := $llms.include | default slice -}} + +{{- /* Clean Exclude List (Include takes precedence for exact matches) */ -}} +{{- $excludeList := slice -}} +{{- range $rawExcludeList -}} + {{- if not (in $includeList .) -}} + {{- $excludeList = $excludeList | append . -}} + {{- end -}} +{{- end -}} + +{{- /* Local override: keep only the newest N pages under each section in params.llms.limit_sections */ -}} +{{- range $path, $n := $llms.limit_sections | default dict -}} + {{- with site.GetPage $path -}} + {{- range after $n .RegularPagesRecursive.ByDate.Reverse -}} + {{- $excludeList = $excludeList | append .RelPermalink -}} + {{- end -}} + {{- end -}} +{{- end -}} + +# {{ site.Title }} + +> {{ site.Params.metadata.description | default site.Params.description | default site.Title }} + +{{- /* Home Page */ -}} +{{- $home := site.Home }} +{{- $showHome := partial "llms_full_is_valid_page.html" (dict "url" $home.RelPermalink "includeList" $includeList "excludeList" $excludeList) }} +{{- if $showHome }} +{{- $homeUrl := $home.Permalink -}} +{{- with $home.OutputFormats.Get "md" }}{{- $homeUrl = .Permalink -}}{{- end }} + +-------------------------------------------------------------------------------- +title: "{{ $home.Title | default "Home" }}" +url: {{ $homeUrl }} +{{ with $home.Params.description }}description: {{ . }} +{{ end -}} +-------------------------------------------------------------------------------- +{{ if $home.RawContent }}{{ $home.RawContent }}{{ else }}{{ $home.Params.description }}{{ end }} +{{- end }} + +{{- /* Standalone section pages (top-level sections with no pages at any depth) */ -}} +{{- range site.Home.Sections }} +{{- if not .RegularPagesRecursive }} +{{- if and .Title .Permalink }} +{{- $show := partial "llms_full_is_valid_page.html" (dict "url" .RelPermalink "includeList" $includeList "excludeList" $excludeList) }} +{{- if $show }} +{{- $url := .Permalink -}} +{{- with .OutputFormats.Get "md" }}{{- $url = .Permalink -}}{{- end }} + +-------------------------------------------------------------------------------- +title: "{{ .Title }}" +url: {{ $url }} +{{ with .Params.description }}description: {{ . }} +{{ end -}} +-------------------------------------------------------------------------------- +{{ if .RawContent }}{{ .RawContent }}{{ else }}{{ .Params.description }}{{ end }} +{{- end }} +{{- end }} +{{- end }} +{{- end }} + +{{- /* Root-level regular pages: About, Contact, etc. */ -}} +{{- range site.Home.RegularPages }} +{{- $show := partial "llms_full_is_valid_page.html" (dict "url" .RelPermalink "includeList" $includeList "excludeList" $excludeList) }} +{{- if $show }} +{{- $url := .Permalink -}} +{{- with .OutputFormats.Get "md" }}{{- $url = .Permalink -}}{{- end }} + +-------------------------------------------------------------------------------- +title: "{{ .Title }}" +url: {{ $url }} +{{ with .Date }}date: "{{ .Format "2006-01-02" }}" +{{ end -}} +{{ with .Params.description }}description: {{ . }} +{{ end -}} +-------------------------------------------------------------------------------- +{{ if .RawContent }}{{ .RawContent }}{{ else }}{{ .Summary | plainify }}{{ end }} +{{- end }} +{{- end }} + +{{- /* Content sections: Blog, Docs, etc. — top-level only, all nested pages included */ -}} +{{- range site.Home.Sections }} +{{- if .RegularPagesRecursive }} + +{{- /* Section index page content block */ -}} +{{- $showSection := partial "llms_full_is_valid_page.html" (dict "url" .RelPermalink "includeList" $includeList "excludeList" $excludeList) }} +{{- if $showSection }} +{{- $sectionUrl := .Permalink -}} +{{- with .OutputFormats.Get "md" }}{{- $sectionUrl = .Permalink -}}{{- end }} + +-------------------------------------------------------------------------------- +title: "{{ .Title }}" +url: {{ $sectionUrl }} +{{ with .Params.description }}description: {{ . }} +{{ end -}} +-------------------------------------------------------------------------------- +{{ if .RawContent }}{{ .RawContent }}{{ else }}{{ .Params.description }}{{ end }} +{{- end }} + +{{- /* All nested pages recursively */ -}} +{{- range where .RegularPagesRecursive ".Permalink" "ne" "" }} +{{- if .Title }} +{{- $show := partial "llms_full_is_valid_page.html" (dict "url" .RelPermalink "includeList" $includeList "excludeList" $excludeList) }} +{{- if $show }} +{{- $url := .Permalink -}} +{{- with .OutputFormats.Get "md" }}{{- $url = .Permalink -}}{{- end }} + +-------------------------------------------------------------------------------- +title: "{{ .Title }}" +url: {{ $url }} +{{ with .Date }}date: "{{ .Format "2006-01-02" }}" +{{ end -}} +{{ with .Params.description }}description: {{ . }} +{{ end -}} +-------------------------------------------------------------------------------- +{{ if .RawContent }}{{ .RawContent }}{{ else }}{{ .Summary | plainify }}{{ end }} +{{- end }} +{{- end }} +{{- end }} +{{- end }} +{{- end }} + +{{- /* Taxonomy list and term pages */ -}} +{{- range $taxonomyName, $taxonomy := site.Taxonomies }} +{{- $taxPage := site.GetPage $taxonomyName }} +{{- if $taxPage }} +{{- $showTax := partial "llms_full_is_valid_page.html" (dict "url" $taxPage.RelPermalink "includeList" $includeList "excludeList" $excludeList) }} +{{- if $showTax }} +{{- $taxUrl := $taxPage.Permalink -}} +{{- with $taxPage.OutputFormats.Get "md" }}{{- $taxUrl = .Permalink -}}{{- end }} + +-------------------------------------------------------------------------------- +title: "{{ $taxPage.Title | default ($taxonomyName | humanize) }}" +url: {{ $taxUrl }} +{{ with $taxPage.Params.description }}description: {{ . }} +{{ end -}} +-------------------------------------------------------------------------------- +{{ if $taxPage.RawContent }}{{ $taxPage.RawContent }}{{ else }}{{ $taxPage.Params.description }}{{ end }} +{{- range $termName, $weightedPages := $taxonomy }} +{{- $termPage := site.GetPage (printf "%s/%s" $taxonomyName $termName) }} +{{- if $termPage }} +{{- $showTerm := partial "llms_full_is_valid_page.html" (dict "url" $termPage.RelPermalink "includeList" $includeList "excludeList" $excludeList) }} +{{- if $showTerm }} +{{- $termUrl := $termPage.Permalink -}} +{{- with $termPage.OutputFormats.Get "md" }}{{- $termUrl = .Permalink -}}{{- end }} + +-------------------------------------------------------------------------------- +title: "{{ $termPage.Title | default $termName }}" +url: {{ $termUrl }} +{{ with $termPage.Params.description }}description: {{ . }} +{{ end -}} +-------------------------------------------------------------------------------- +{{ if $termPage.RawContent }}{{ $termPage.RawContent }}{{ else }}{{ $termPage.Params.description }}{{ end }} +{{- end }} +{{- end }} +{{- end }} +{{- end }} +{{- end }} +{{- end }} + +{{- end -}} diff --git a/layouts/video/video.html b/layouts/video/video.html index ed85fbcd3bc..4782ee210ed 100644 --- a/layouts/video/video.html +++ b/layouts/video/video.html @@ -12,9 +12,6 @@

{{ .Title }}

{{ .Description }}

-
- {{ partial "page-markdown-link.html" . }} -
{{ if .Params.featured_video }} {{ $featuredImage := .Params.featured_image }}