Customize a part of list.html for a specific content type?

I have a default list template for all my lists, located in my themes folder (/themes/<THEME>/layouts/_default/list.html).

list.html

{{ define "main" }}
	<!-- TITLE-->
	{{ block "title" . }}
		{{ partial "title.html" . }}
	{{ end }}

	<!-- CONTENT -->
	{{ block "content" . }}
		{{ partial "content.html" . }}
	{{ end  }}

	<!-- PAGE LIST -->
	{{ block "pages" . }}
		{{ partial "pages.html" . }}
	{{ end }}

	<!-- FILE LIST -->
	{{ block "files" . }}
		{{ partial "files.html" . }}
	{{ end }}
{{ end }}

baseof.html

...
<main id="main">
    {{ block "main" . }}{{ end }}
</main>
...

I also have a content type called images and I want to tweak a bit how the list is displayed for it specifically, namely I want to alter the contents of the “files” block so that instead of containing:

{{ partial "files.html" . }}

It contains:

<div class="viewer"></div>
{{ partial "files.html" . }}

Soliton #0

Just create a /layout/images/list.html file and fill it with:

{{ define "main" }}
	<!-- TITLE-->
	{{ block "title" . }}
		{{ partial "title.html" . }}
	{{ end }}

	<!-- CONTENT -->
	{{ block "content" . }}
		{{ partial "content.html" . }}
	{{ end  }}

	<!-- PAGE LIST -->
	{{ block "pages" . }}
		{{ partial "pages.html" . }}
	{{ end }}

	<!-- FILE LIST -->
	{{ block "files" . }}
                <div class="viewer"></div>
		{{ partial "files.html" . }}
	{{ end }}
{{ end }}

Con: Works perfectly, but now I have duplicate template code (I shouldn’t have to re-define TITLE, CONTENT, PAGE… only FILE).

Solution #1

Somehow somewhere place a {{ define "files" }}? I don’t think you can use define and block with list.html however, only baseof.html.

Con: Not possible?

Solution #2

Create a files-top.html partial, place it within the “files” block like so:

...
<!-- FILE LIST -->
{{ block "files" . }}
	{{ partial "files-top.html" . }}
{{ end }}
...

And let it contain:

{{ partial "files.html" . }}

And then somehow replace the contents of files-top.html for images only to:

<div class="viewer"></div>
{{ partial "files.html" . }}

But while it is possible to make a specific list.html and single.html for specific content types like images you can’t do it with partials I belive… well you can create a partial with the same name but then it would overwrite it for all content types, not just “images”.

Con: Not possible?

Solution #3

Make a files-top.html partial with the content type label at the start (e.g. images-files-top.html) but instead of making Hugo handle which to use you dynamically check for type specific partials using template code, e.g. :

...
{{ $custom_template := ( printf "%s-files-top.html" .Type ) }}
{{ $custom_template_path := ( printf "partials/%s" $custom_template ) }}
						
{{ if templates.Exists $custom_template_path  }}
	{{ partial $custom_template . }}
{{ else }}
	{{ partial "files-top.html" . }}
{{ end }}
...

Con: Works perfectly, but perhaps there is a more “native” non-template language way to do this?

Solution #4

… ?


If there are no better solutions I’ll probably just go with Solution #3.


EDIT - An extra solution

Just define custom partials within the list type frontmatter (content/<TYPE>/_index.md) and let the list.html use that if defined.

Why not

{{ if eq .Type $foo }}
<div class="viewer"></div>
{{ end }}
{{ partial "files.html" . }}