theNewDynamic/gohugo-theme-ananke

bug: colums break in posts view with AsciiDoc admonitions

Closed this issue · 5 comments

The colums in the page that lists all posts (in my case rezepte/ (recipies)) breaks when I use AsciiDoc and it's admonitions. I suspect this is not an AsciiDoc problem, but a more general problem how data for the columns to create the block listing is acquired and rendered.

Expected Behavior

I would expect 3 columns rendering a block each representing / featuring a single post.

Current Behavior

The page renders 2 columns only. The second column includes two posts, whereas the second post is shown indented. The indentation stems from the start of an admonition which belongs to the first post. The page's footer is also rendered as part of the second column. Feels as if a <div> has been opened, but not closed anymore, causing all following content to be in the wrong place.

Possible Solution

Please don't tell me to use Markdown instead. I'm a real AsciiDoc fanboy. ;-)

Steps to Reproduce

See https://foodpr0n.de/de/rezepte/ and examine the HTML source output or take a look at the screenshot I've attached.

Screenshot 2024-11-04 at 09-27-54 Rezepte foodpr0n

The bigger picture (we need context)

I'm using current macOS Sequoia Version 15.1 (24B83)

hugo v0.136.5+extended darwin/arm64 BuildDate=2024-10-24T12:26:27Z VendorInfo=brew
go: stable 1.23.2
% git submodule status
0306b6a themes/ananke (v2.10.1-prerelease.3-3-g0306b6a)
% hugo mod graph
project ananke

Hugo Config

archetypedir = 'archetypes'
assetdir = 'assets'
baseurl = 'https://foodpr0n.de/'
cachedir = '/Users/p/Library/Caches/hugo_cache'
capitalizelisttitles = true
contentdir = 'content'
datadir = 'data'
defaultcontentlanguage = 'de'
defaultcontentlanguageinsubdir = true
enablerobotstxt = true
environment = 'production'
i18ndir = 'i18n'
languagecode = 'de-de'
layoutdir = 'layouts'
mainsections = ['rezepte']
pluralizelisttitles = true
publishdir = 'public'
resourcedir = '../resources'
sectionpagesmenu = 'main'
staticdir = ['static']
summarylength = 70
theme = ['ananke']
themesdir = 'themes'
timeout = '30s'
title = 'foodpr0n'
titlecasestyle = 'AP'
workingdir = '/Users/p/Projekte/p/foodpr0n.de'

[build]
useresourcecachewhen = 'fallback'

[build.buildstats]

[[build.cachebusters]]
source = '(postcss|tailwind).config.js'
target = '(css|styles|scss|sass)'

[caches]
[caches.assets]
dir = ':resourceDir/_gen'
maxage = -1

[caches.getcsv]
dir = ':cacheDir/:project'
maxage = -1

[caches.getjson]
dir = ':cacheDir/:project'
maxage = -1

[caches.getresource]
dir = ':cacheDir/:project'
maxage = -1

[caches.images]
dir = ':resourceDir/_gen'
maxage = -1

[caches.misc]
dir = ':cacheDir/:project'
maxage = -1

[caches.modules]
dir = ':cacheDir/modules'
maxage = -1

[deployment]
invalidatecdn = true
maxdeletes = 256
workers = 10

[frontmatter]
date = ['date', 'publishdate', 'pubdate', 'published', 'lastmod', 'modified']
expirydate = ['expirydate', 'unpublishdate']
lastmod = [':git', 'lastmod', 'modified', 'date', 'publishdate', 'pubdate', 'published']
publishdate = ['publishdate', 'pubdate', 'published', 'date']

[httpcache]
[httpcache.cache]
[httpcache.cache.for]
excludes = ['**']

[[httpcache.polls]]
disable = true
high = '0s'
low = '0s'

[httpcache.polls.for]
  includes = ['**']

[imaging]
bgcolor = '#ffffff'
hint = 'photo'
quality = 75
resamplefilter = 'box'

[languages]
[languages.de]
languagecode = 'de-de'

[markup]
defaultmarkdownhandler = 'goldmark'

[markup.asciidocext]
backend = 'html5'
failurelevel = 'fatal'
noheaderorfooter = true
safemode = 'unsafe'

[markup.asciidocext.attributes]
  baseurl = 'https://foodpr0n.de/'

[markup.goldmark]
[markup.goldmark.extensions]
definitionlist = true
footnote = true
linkify = true
linkifyprotocol = 'https'
strikethrough = true
table = true
tasklist = true

  [markup.goldmark.extensions.cjk]
    eastasianlinebreaksstyle = 'simple'

  [markup.goldmark.extensions.extras]
    [markup.goldmark.extensions.extras.delete]

    [markup.goldmark.extensions.extras.insert]

    [markup.goldmark.extensions.extras.mark]

    [markup.goldmark.extensions.extras.subscript]

    [markup.goldmark.extensions.extras.superscript]

  [markup.goldmark.extensions.passthrough]
    [markup.goldmark.extensions.passthrough.delimiters]

  [markup.goldmark.extensions.typographer]
    apostrophe = '&rsquo;'
    ellipsis = '&hellip;'
    emdash = '&mdash;'
    endash = '&ndash;'
    leftanglequote = '&laquo;'
    leftdoublequote = '&ldquo;'
    leftsinglequote = '&lsquo;'
    rightanglequote = '&raquo;'
    rightdoublequote = '&rdquo;'
    rightsinglequote = '&rsquo;'

[markup.goldmark.parser]
  autoheadingid = true
  autoheadingidtype = 'github'
  wrapstandaloneimagewithinparagraph = true

  [markup.goldmark.parser.attribute]
    title = true

[markup.goldmark.renderer]

[markup.goldmark.renderhooks]
  [markup.goldmark.renderhooks.image]

  [markup.goldmark.renderhooks.link]

[markup.highlight]
codefences = true
linenostart = 1
linenumbersintable = true
noclasses = true
style = 'monokai'
tabwidth = 4

[markup.tableofcontents]
endlevel = 3
startlevel = 2

[mediatypes]
[mediatypes.'application/json']
delimiter = '.'
suffixes = ['json']

[mediatypes.'application/manifest+json']
delimiter = '.'
suffixes = ['webmanifest']

[mediatypes.'application/octet-stream']
delimiter = '.'

[mediatypes.'application/pdf']
delimiter = '.'
suffixes = ['pdf']

[mediatypes.'application/rss+xml']
delimiter = '.'
suffixes = ['xml', 'rss']

[mediatypes.'application/toml']
delimiter = '.'
suffixes = ['toml']

[mediatypes.'application/wasm']
delimiter = '.'
suffixes = ['wasm']

[mediatypes.'application/xml']
delimiter = '.'
suffixes = ['xml']

[mediatypes.'application/yaml']
delimiter = '.'
suffixes = ['yaml', 'yml']

[mediatypes.'font/otf']
delimiter = '.'
suffixes = ['otf']

[mediatypes.'font/ttf']
delimiter = '.'
suffixes = ['ttf']

[mediatypes.'image/bmp']
delimiter = '.'
suffixes = ['bmp']

[mediatypes.'image/gif']
delimiter = '.'
suffixes = ['gif']

[mediatypes.'image/jpeg']
delimiter = '.'
suffixes = ['jpg', 'jpeg', 'jpe', 'jif', 'jfif']

[mediatypes.'image/png']
delimiter = '.'
suffixes = ['png']

[mediatypes.'image/svg+xml']
delimiter = '.'
suffixes = ['svg']

[mediatypes.'image/tiff']
delimiter = '.'
suffixes = ['tif', 'tiff']

[mediatypes.'image/webp']
delimiter = '.'
suffixes = ['webp']

[mediatypes.'text/asciidoc']
delimiter = '.'
suffixes = ['adoc', 'asciidoc', 'ad']

[mediatypes.'text/calendar']
delimiter = '.'
suffixes = ['ics']

[mediatypes.'text/css']
delimiter = '.'
suffixes = ['css']

[mediatypes.'text/csv']
delimiter = '.'
suffixes = ['csv']

[mediatypes.'text/html']
delimiter = '.'
suffixes = ['html', 'htm']

[mediatypes.'text/javascript']
delimiter = '.'
suffixes = ['js', 'jsm', 'mjs']

[mediatypes.'text/jsx']
delimiter = '.'
suffixes = ['jsx']

[mediatypes.'text/markdown']
delimiter = '.'
suffixes = ['md', 'mdown', 'markdown']

[mediatypes.'text/org']
delimiter = '.'
suffixes = ['org']

[mediatypes.'text/pandoc']
delimiter = '.'
suffixes = ['pandoc', 'pdc']

[mediatypes.'text/plain']
delimiter = '.'
suffixes = ['txt']

[mediatypes.'text/rst']
delimiter = '.'
suffixes = ['rst']

[mediatypes.'text/tsx']
delimiter = '.'
suffixes = ['tsx']

[mediatypes.'text/typescript']
delimiter = '.'
suffixes = ['ts']

[mediatypes.'text/x-sass']
delimiter = '.'
suffixes = ['sass']

[mediatypes.'text/x-scss']
delimiter = '.'
suffixes = ['scss']

[mediatypes.'video/3gpp']
delimiter = '.'
suffixes = ['3gpp', '3gp']

[mediatypes.'video/mp4']
delimiter = '.'
suffixes = ['mp4']

[mediatypes.'video/mpeg']
delimiter = '.'
suffixes = ['mpg', 'mpeg']

[mediatypes.'video/ogg']
delimiter = '.'
suffixes = ['ogv']

[mediatypes.'video/webm']
delimiter = '.'
suffixes = ['webm']

[mediatypes.'video/x-msvideo']
delimiter = '.'
suffixes = ['avi']

[minify]
[minify.tdewolff]
[minify.tdewolff.css]
keepcss2 = true

[minify.tdewolff.html]
  keepdefaultattrvals = true
  keepdocumenttags = true
  keependtags = true
  keepspecialcomments = true
  templatedelims = ['', '']

[minify.tdewolff.js]
  version = 2022

[minify.tdewolff.json]

[minify.tdewolff.svg]

[minify.tdewolff.xml]

[module]
noproxy = 'none'
private = '.'
proxy = 'direct'
workspace = 'off'

[module.hugoversion]

[[module.imports]]
path = 'ananke'

[[module.mounts]]
source = 'content'
target = 'content'

[[module.mounts]]
source = 'data'
target = 'data'

[[module.mounts]]
source = 'layouts'
target = 'layouts'

[[module.mounts]]
source = 'i18n'
target = 'i18n'

[[module.mounts]]
source = 'archetypes'
target = 'archetypes'

[[module.mounts]]
source = 'assets'
target = 'assets'

[[module.mounts]]
source = 'static'
target = 'static'

[outputformats]
[outputformats.amp]
basename = 'index'
ishtml = true
mediatype = 'text/html'
path = 'amp'
permalinkable = true
rel = 'amphtml'

[outputformats.calendar]
basename = 'index'
isplaintext = true
mediatype = 'text/calendar'
protocol = 'webcal://'
rel = 'alternate'

[outputformats.css]
basename = 'styles'
isplaintext = true
mediatype = 'text/css'
notalternative = true
rel = 'stylesheet'

[outputformats.csv]
basename = 'index'
isplaintext = true
mediatype = 'text/csv'
rel = 'alternate'

[outputformats.html]
basename = 'index'
ishtml = true
mediatype = 'text/html'
permalinkable = true
rel = 'canonical'
weight = 10

[outputformats.json]
basename = 'index'
isplaintext = true
mediatype = 'application/json'
rel = 'alternate'

[outputformats.markdown]
basename = 'index'
isplaintext = true
mediatype = 'text/markdown'
rel = 'alternate'

[outputformats.robots]
basename = 'robots'
isplaintext = true
mediatype = 'text/plain'
rel = 'alternate'
root = true

[outputformats.rss]
basename = 'index'
mediatype = 'application/rss+xml'
nougly = true
rel = 'alternate'

[outputformats.sitemap]
basename = 'sitemap'
mediatype = 'application/xml'
rel = 'sitemap'
ugly = true

[outputformats.webappmanifest]
basename = 'manifest'
isplaintext = true
mediatype = 'application/manifest+json'
notalternative = true
rel = 'manifest'

[outputs]
home = ['html', 'rss']
page = ['html']
rss = ['rss']
section = ['html', 'rss']
taxonomy = ['html', 'rss']
term = ['html', 'rss']

[page]
nextprevinsectionsortorder = 'desc'
nextprevsortorder = 'desc'

[pagination]
pagersize = 3
path = 'page'

[params]
author = 'Patrick Ben Koetter'
background_color_class = 'bg-black'
cover_dimming_class = 'bg-black-50'
date_format = '2. January 2006'
featured_image_class = 'cover bg-top'
recent_posts_number = 5
show_reading_time = true
text_color = 'dark-gray'

[params.ananke]
[params.ananke.social]
icon_path = 'ananke/socials/%s.svg'

  [params.ananke.social.email]
    username = 'patrickkoetter'

  [params.ananke.social.follow]
    networks = ['rss', 'mastodon']

  [params.ananke.social.mastodon]
    profilelink = 'https://troet.cafe/@patrickbenkoetter'

  [[params.ananke.social.networks]]
    color = '#1185fe'
    icon = 'bluesky'
    label = 'Bluesky'
    link = 'https://bsky.app/intent/compose'
    profile = 'https://bsky.app/profile/%s'
    slug = 'bluesky'

    [params.ananke.social.networks.particles]
      text = 'permalink'

  [[params.ananke.social.networks]]
    icon = 'envelope'
    label = 'Email'
    link = 'mailto:'
    slug = 'email'

    [params.ananke.social.networks.particles]
      body = 'permalink'
      subject = 'title'

  [[params.ananke.social.networks]]
    color = '#3b5998'
    icon = 'facebook'
    label = 'Facebook'
    link = 'https://facebook.com/sharer/sharer.php'
    profile = 'https://www.facebook.com/%s'
    slug = 'facebook'

    [params.ananke.social.networks.particles]
      u = 'permalink'

  [[params.ananke.social.networks]]
    color = '#6cc644'
    icon = 'github'
    label = 'GitHub'
    profile = 'https://github.com/%s/'
    slug = 'github'

  [[params.ananke.social.networks]]
    color = '#FC6D26'
    icon = 'gitlab'
    label = 'GitLab'
    profile = 'https://gitlab.com/%s/'
    slug = 'gitlab'

  [[params.ananke.social.networks]]
    color = '#ff4000'
    icon = 'hacker-news'
    label = 'Hacker News'
    link = 'https://news.ycombinator.com/submitlink'
    profile = 'https://news.ycombinator.com/user?id=%s'
    slug = 'hackernews'

    [params.ananke.social.networks.particles]
      t = 'description'
      u = 'permalink'

  [[params.ananke.social.networks]]
    color = '#e1306c'
    icon = 'instagram'
    label = 'Instagram'
    profile = 'https://www.instagram.com/%s/'
    slug = 'instagram'

  [[params.ananke.social.networks]]
    color = '#3d76ff'
    icon = 'keybase'
    label = 'Keybase'
    profile = 'https://keybase.io/%s'
    slug = 'keybase'

  [[params.ananke.social.networks]]
    color = '#0077b5'
    icon = 'linkedin'
    label = 'LinkedIn'
    link = 'https://www.linkedin.com/shareArticle'
    profile = 'http://linkedin.com/in/%s'
    slug = 'linkedin'

    [params.ananke.social.networks.particles]
      params = 'mini=true'
      source = 'permalink'
      summary = 'description'
      title = 'title'
      url = 'permalink'

  [[params.ananke.social.networks]]
    color = '#0077b5'
    icon = 'medium'
    label = 'Medium'
    profile = 'https://medium.com/@%s/'
    slug = 'medium'

  [[params.ananke.social.networks]]
    color = '#6364FF'
    icon = 'mastodon'
    label = 'Mastodon'
    slug = 'mastodon'

  [[params.ananke.social.networks]]
    color = '#e60023'
    icon = 'pinterest'
    label = 'Pinterest'
    link = 'https://pinterest.com/pin/create/button/'
    profile = 'https://www.pinterest.com/%s/'
    slug = 'pinterest'

    [params.ananke.social.networks.particles]
      description = 'description'
      media = 'permalink'
      url = 'permalink'

  [[params.ananke.social.networks]]
    color = '#ff4500'
    icon = 'reddit'
    label = 'Reddit'
    link = 'https://reddit.com/submit/'
    profile = 'https://www.reddit.com/user/%s/'
    slug = 'reddit'

    [params.ananke.social.networks.particles]
      params = 'resubmit=true'
      title = 'title'
      url = 'permalink'

  [[params.ananke.social.networks]]
    color = '#ff6f1a'
    icon = 'rss'
    label = 'RSS'
    slug = 'rss'

  [[params.ananke.social.networks]]
    color = '#E01E5A'
    icon = 'slack'
    label = 'Slack'
    slug = 'slack'

  [[params.ananke.social.networks]]
    color = '#f48024'
    icon = 'stack-overflow'
    label = 'Stack Overflow'
    profile = 'https://stackoverflow.com/users/%s'
    slug = 'stackoverflow'

  [[params.ananke.social.networks]]
    color = '#0088cc'
    icon = 'telegram'
    label = 'Telegram'
    link = 'https://telegram.me/share/url'
    profile = 'https://t.me/%s'
    slug = 'telegram'

    [params.ananke.social.networks.particles]
      text = 'description'
      url = 'permalink'

  [[params.ananke.social.networks]]
    color = '#fe2c55'
    icon = 'tiktok'
    label = 'TikTok'
    profile = 'https://www.tiktok.com/@%s'
    slug = 'tiktok'

  [[params.ananke.social.networks]]
    color = '#35465c'
    icon = 'tumblr'
    label = 'Tumblr'
    link = 'https://www.tumblr.com/widgets/share/tool'
    profile = 'https://www.tumblr.com/blog/%s'
    slug = 'tumblr'

    [params.ananke.social.networks.particles]
      canonicalurl = 'permalink'
      caption = 'description'
      content = 'description'
      params = 'posttype=link'
      sharesource = 'source'
      title = 'title'

  [[params.ananke.social.networks]]
    color = '#1da1f2'
    icon = 'twitter'
    label = 'Twitter'
    link = 'https://twitter.com/intent/tweet/'
    profile = 'https://twitter.com/%s'
    slug = 'twitter'

    [params.ananke.social.networks.particles]
      text = 'description'
      url = 'permalink'

  [[params.ananke.social.networks]]
    color = '#25d366'
    icon = 'whatsapp'
    label = 'WhatsApp'
    link = 'whatsapp://send'
    linkintext = true
    slug = 'whatsapp'

    [params.ananke.social.networks.particles]
      text = 'description'

  [[params.ananke.social.networks]]
    color = '#026466'
    icon = 'xing'
    label = 'Xing'
    link = 'https://www.xing.com/app/user'
    profile = 'https://www.xing.com/profile/%s'
    separator = ';'
    slug = 'xing'

    [params.ananke.social.networks.particles]
      params = 'op=share'
      title = 'title'
      url = 'permalink'

  [[params.ananke.social.networks]]
    color = '#000000'
    icon = 'x-twitter'
    label = 'X'
    link = 'https://twitter.com/intent/tweet/'
    profile = 'https://x.com/%s'
    slug = 'x-twitter'

    [params.ananke.social.networks.particles]
      text = 'description'
      url = 'permalink'

  [[params.ananke.social.networks]]
    color = '#cd201f'
    icon = 'youtube'
    label = 'YouTube'
    profile = 'https://www.youtube.com/@%s'
    slug = 'youtube'

  [params.ananke.social.rss]
    profilelink = 'https://foodpr0n.de/public/de/index.xml'

  [params.ananke.social.share]
    icons = true
    networks = ['email']
    sharetext = true

[permalinks]

[privacy]
[privacy.disqus]

[privacy.googleanalytics]

[privacy.instagram]

[privacy.twitter]

[privacy.vimeo]

[privacy.youtube]

[related]
threshold = 80

[[related.indices]]
name = 'keywords'
type = 'basic'
weight = 100

[[related.indices]]
name = 'date'
type = 'basic'
weight = 10

[[related.indices]]
name = 'tags'
type = 'basic'
weight = 80

[security]
[security.exec]
allow = ['^(dart-)?sass(-embedded)?$', '^go$', '^git$', '^npx$', '^postcss$', '^tailwindcss$', '^asciidoctor$']
osenv = ['(?i)^((HTTPS?|NO)PROXY|PATH(EXT)?|APPDATA|TE?MP|TERM|GO\w+|(XDG_CONFIG)?HOME|USERPROFILE|SSH_AUTH_SOCK|DISPLAY|LANG|SYSTEMDRIVE)$']

[security.funcs]
getenv = ['^HUGO_', '^CI$']

[security.http]
methods = ['(?i)GET|POST']
urls = ['.*']

[server]
[[server.redirects]]
from = '**'
status = 404
to = '/404.html'

[services]
[services.disqus]

[services.googleanalytics]

[services.instagram]

[services.rss]
limit = -1

[services.twitter]

[sitemap]
changefreq = 'monthly'
filename = 'sitemap.xml'
priority = 0.5

[taxonomies]
category = 'categories'
tag = 'tags'

.admonitionblock is not something that Ananke produces. Please check your local layouts where this might be introduced. My guess is a blockquote renderhook or a shortcode.

Going back to v0.133.1 will probably solve the issue for now.

What happens (black box diagnosis) is, that your admonition shortcode/renderhook is cut off in the automatic summary so the "proper" article closing tag is inside whatever div the shortcode opened. This is a change that happened in v0.134.

A solution might be to add a frontmatter summary without this shortcode that will override the automatically created summary. This will require manually added summaries whenever this issue occurs.

Another solution would be to change your renderhook/shortcode so that it produces a cleaned up summary without any html rendered when it is run inside of a summary. Now ask me how it knows that it is in a summary ;) probably on .IsNode being true. Might be overkill though.

Not trolling… but probably still lacking proper hugo knowledge and curious to understand:

If you take a look at the post you will see the admonitionblock is being closed correctly: https://foodpr0n.de/de/rezepte/harissa/

This said I do assume the post itself is fine, but the summary doesn't handle the HTML it grabs correctly. My understanding is, it grabs the first n-lines of HTML output from a post when it builds a summary page.

This said and if my assumptions are correct: Shouldn't the / any summary listing be format (HTML) agnostic and just e. g. grap the first 200 characters of a post and use that as feature text? This way the frontmatter summary could render any content from any content format supported by hugo.

On a sidenote: Of course I could place the admonition later in my post and avoid the problem I'm experiencing at the moment.

I think I finally understood what you wanted me to tell about adding summary to frontmatter. I was lazy and fixed my problem by setting summaryLength in hugo.toml for all posts. Thanks for pointing me into the right direction!

This said I do assume the post itself is fine, but the summary doesn't handle the HTML it grabs correctly. My understanding is, it grabs the first n-lines of HTML output from a post when it builds a summary page.

Exactly that is the problem. v0.134 (of Hugo, not the Ananke theme) changed how the summary is built and broke that. It doesn't look like there is intention to change it. So all we can do is to either not having anything HTML-like in that part of the page (very bad), or "fix" it with hacks (slightly bad), or invent a completely new way of creating summaries without using the internal tools. That is overkill in my opinion, so the front matter option on an individual case has to be it.

By the way summarylength sounds like a global configuration. You can add to each specific post (harissa.md for instance, or how ever that file might be named) a summary: summarytext front matter where you write out your individual summary. This will be preferred then to the automatic "let's parse the post and cut off the first x paragraphs" summary. It will NOT be cut, so markdown will be parsed and Asciidoc might be parsed. I have no experience with the latter, so I don't know for sure.

By the way summarylength sounds like a global configuration. You can add to each specific post (harissa.md for instance, or how ever that file might be named) a summary: summarytext front matter where you write out your individual summary. This will be preferred then to the automatic "let's parse the post and cut off the first x paragraphs" summary. It will NOT be cut, so markdown will be parsed and Asciidoc might be parsed. I have no experience with the latter, so I don't know for sure.

Yes, it is a global configuration and I am totally happy with it for the moment. In my case it shortens all post summaries about half the default length and that - in my opinion - gives a much smoother impression when I look at the listings. I'll see how it goes and if that doesn't work for me I will begin to set the summary manually per page. THX!