{"version":"https://jsonfeed.org/version/1.1","title":"tbsch Theme","home_page_url":"https://theme.docs.tbsch.de/","feed_url":"https://theme.docs.tbsch.de/feed.json","description":"A modern, privacy-friendly Hugo theme — demo \u0026 documentation.","language":"en","authors":[{"name":"Max Mustermann","url":"https://theme.docs.tbsch.de/"}],"items":[{"id":"https://theme.docs.tbsch.de/post/2026-02-23-welcome/","url":"https://theme.docs.tbsch.de/post/2026-02-23-welcome/","title":"Welcome to the tbsch theme","summary":"An overview of the tbsch theme and how this demo site is structured.","date_published":"2026-02-23T00:00:00Z","date_modified":"2026-02-23T00:00:00Z","tags":["Basics","hugo","theme","getting-started"],"_social":{"hashtags":[],"mentions":{"mastodon":[],"bluesky":[]}},"content_text":"tbsch is a standalone Hugo theme - fast, privacy-friendly and free of external CDNs. This site shows every feature with a real, working example. Great to have you here! This demo doubles as the theme’s documentation. Instead of a dry reference you’ll find living examples: each post introduces one functional area and shows in its source how it is done.\nWhat the theme brings along # Solarflare design - a gradient running from orange through pink to violet, background heroes and a floating pill header. Automatic dark mode with a manual toggle and no flash on load. Token-based design system - spacing, typography, radii and motion as CSS custom properties. Images that take care of themselves - every Markdown image is converted to WebP, served responsively and zoomable via lightbox. Shortcodes for lead paragraphs, buttons, tabs, galleries, GitHub cards, Mermaid diagrams, KaTeX math and inline icons. GitHub-style admonitions (\u003e [!note], \u003e [!warning], …), collapsible too. Search (Pagefind, client-side), three feeds (RSS, Atom, JSON Feed) and an IndieWeb setup (microformats2, webmentions). Privacy: all fonts and libraries are hosted locally; external embeds go through the consent manager Klaro. How to read this demo Look at each post rendered and, in parallel, glance at its index.md. The Markdown source is the actual manual.\nWhere to start # Topic Post Markdown \u0026 typography Markdown basics Callout boxes Admonitions Shortcodes Shortcodes at a glance Images \u0026 galleries Images and galleries Diagrams \u0026 math Diagrams and math Front matter \u0026 SEO Front matter and SEO Working through them in order is best - or jump straight to whatever topic interests you right now."},{"id":"https://theme.docs.tbsch.de/post/2026-02-16-front-matter-and-seo/","url":"https://theme.docs.tbsch.de/post/2026-02-16-front-matter-and-seo/","title":"Front matter and SEO","summary":"All theme front-matter parameters and their exact effect: display toggles, values, the feature image and the discovery block for SEO.","date_published":"2026-02-16T00:00:00Z","date_modified":"2026-03-01T00:00:00Z","tags":["Basics","seo","front-matter","configuration"],"_social":{"hashtags":[],"mentions":{"mastodon":[],"bluesky":[]}},"content_text":"The theme reads a whole set of its own front-matter parameters. Almost every one has a global default in params.yaml and can be overridden per page (or per section via cascade). The resolution order is: front matter → global default → theme fallback.\nTheme parameters go in the params: block Everything the theme evaluates goes into the params: block - keeping it clear what comes from Hugo and what from the theme. Every example here does exactly that.\nSome toggles are flipped on this page on purpose This post sets showReadingTime: false and showWordCount: false (so both are hidden in the hero, though they show on every other post) and showLikes: true (so the like button appears at the end - it is off by default).\nFront-matter layout # --- title: \"My post\" # read by Hugo date: 2026-02-16 draft: false description: \"…\" categories: [\"Features\"] # taxonomies tags: [\"hugo\"] params: # everything theme-specific in this block showReadingTime: false featureimage: cover.webp discovery: noindex: true --- Display toggles # Boolean toggles - the value shown is the default; set the parameter in your params: block to override it (an explicit false always wins):\nparams: showDate: true # default: on publication date in the hero showDateUpdated: true # default: on \"Updated\" date from lastmod in the hero showReadingTime: true # default: on reading time in the meta row showWordCount: true # default: on word count in the meta row showTaxonomies: true # default: on tags \u0026 categories in the hero showTableOfContents: true # default: on floating table of contents (on the left) showHeadingAnchors: true # default: on direct-link anchor on every heading showAuthor: true # default: on author box at the end showLikes: false # default: off like button (heart) at the end - opt-in showSharingLinks: true # default: on sharing bar showComments: true # default: on reactions/comments at the end showPagination: true # default: on prev/next within the section showRelatedContent: true # default: on \"Related posts\" below the article showDraftLabel: true # default: on \"Draft\" badge while draft: true seriesOpened: true # default: on series box starts expanded Value parameters # Parameters that take a value rather than a toggle:\nparams: # Show only these networks in the sharing bar (keys from data/sharing.yaml); # overrides the global set from params.yaml. sharingLinks: [\"bluesky\", \"mastodon\", \"email\"] # Number of \"Related posts\" (default 3) when showRelatedContent is on. relatedContentLimit: 5 # Author name for this page's structured data (Person/JSON-LD) ONLY; # overrides the default author from params.yaml. author: \"Guest author\" Social tags for cross-posting (socialTags) # socialTags is not a flat list but a block with hashtags and mentions (per network). It is not rendered on the page; it is written into the JSON Feed under a _social extension - from there a cross-posting service picks it up and appends the hashtags and @-mentions when auto-posting to Mastodon or Bluesky.\nparams: socialTags: hashtags: - SelfHosted - DNS - PiHole mentions: mastodon: [\"selfhosted@lemmy.world\"] bluesky: [\"mariushosting.com\"] Feature image (featureimage) # The theme resolves the hero/feature image in this order:\nparams.featureimage (local path or absolute URL), an image named *background*/*feature*/*cover*/*thumbnail* in the bundle, the site’s defaultBackgroundImage from params.yaml. params: featureimage: cover.webp # image in the post bundle … # featureimage: https://…/og.png # … or an absolute URL The discovery block (crawling, indexing, search) # For SEO the theme brings its own discovery: block - Hugo has no equivalent. All toggles have a sensible default; you only set the deviation:\nparams: discovery: noindex: true # default false → \u003cmeta name=\"robots\" content=\"noindex\"\u003e nofollow: true # default false → appends nofollow sitemap: false # default true → drop the page from sitemap.xml search: false # default true → drop the page from the Pagefind search llms: false # default true → drop the page from llms.txt partials/seo-robots.html is the single source of the robots directive (front matter → 404 → default index, follow); it emits only the opt-out tokens (noindex/nofollow), never the implicit index, follow. The sitemap is coupled to it: any noindex page drops out of the sitemap automatically.\nThe thin tag term pages set exactly that via a cascade in content/tags/_index.md; the legal pages (see Privacy) combine noindex with search: false + llms: false and outputs: [\"HTML\"].\nCurated tag hubs (linkTitle + discovery) # A tag term page is thin and noindex by default (the cascade above). To turn a tag into an indexable evergreen hub - a curated landing page that owns the head term while its individual posts keep their long-tails - give the tag its own _index.md under content/tags/\u003ctag\u003e/:\n# content/tags/seo/_index.md --- title: \"Search engine optimization\" # page \u003ch1\u003e + SEO title linkTitle: \"seo\" # short label shown in the tag chips description: \"…\" # hero lede + meta description discovery: noindex: false # opt back in, overriding the thin-tag cascade sitemap: true --- Intro paragraph(s), rendered above the list of tagged posts. The page’s own discovery overrides the kind: term cascade from content/tags/_index.md, so this one term goes index, follow and returns to the sitemap; the body renders as an intro above the posts.\ntitle vs. linkTitle The tag chips (the #tag pills in a post hero and in the /tags/ cloud) render .LinkTitle, while the hub page renders .Title as its \u003ch1\u003e. So a descriptive title: \"Search engine optimization\" can head the page while linkTitle: \"seo\" keeps every chip a tidy #seo - without linkTitle the full title would leak into each chip. (Chips are lower-cased in CSS, so linkTitle only needs to be the short form, not the exact casing.)\nAuthor profile (authorProfile) # On an “About me” page, authorProfile: true emits ProfilePage and Person JSON-LD (with sameAs links from params.author.links) - see the About me page.\nparams: authorProfile: true Category icon (categoryIcon) # In a category’s _index.md (content/categories/\u003cname\u003e/), categoryIcon sets the Tabler icon shown on the category card (default tag):\n# content/categories/features/_index.md params: categoryIcon: rocket Hugo’s own keys # Hugo reads these itself, not the theme:\ntitle, date, lastmod, draft - title and dates. lastmod is shown as the “Updated” date (when showDateUpdated is on). description, summary - meta description and lede/teaser. categories, tags, series - the theme’s three taxonomies. translationKey - links the language variants of a post. slug, url - URL control. outputs - output formats (e.g. HTML only). aliases - client-side redirect stubs (automatically noindex), handy for old or short URLs: aliases: - /old-url/ - /l/shortlink The full list of these keys lives in the Hugo front matter documentation ."},{"id":"https://theme.docs.tbsch.de/post/2026-02-09-diagrams-and-math/","url":"https://theme.docs.tbsch.de/post/2026-02-09-diagrams-and-math/","title":"Diagrams and math","summary":"The full range of Chart.js (charts), KaTeX (math) and Mermaid (diagrams): chart/diagram types, math typesetting and how they load only when needed.","date_published":"2026-02-09T00:00:00Z","date_modified":"2026-02-09T00:00:00Z","tags":["Features","charts","mermaid","katex","diagrams"],"_social":{"hashtags":[],"mentions":{"mastodon":[],"bluesky":[]}},"content_text":"Chart.js (charts), KaTeX (math) and Mermaid (diagrams) are self-hosted and only loaded when the respective shortcode appears on the page - no unnecessary JavaScript on pages without them. The shortcodes post introduces them in brief; here we go into depth. Every example has two tabs: Example shows the result, Code the source.\nCharts: the basics # The chart shortcode renders a canvas with Chart.js . The inner content is the chart’s config as JSON (type + data); an optional title sets the canvas' accessible label. Axis, grid and text colours bind to the theme tokens and re-theme live when you toggle dark mode; series without a colour of their own are filled from the site’s accent palette.\nLine chart # Example Code { \"type\": \"line\", \"data\": { \"labels\": [\"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\", \"Sat\", \"Sun\"], \"datasets\": [ { \"label\": \"Desktop\", \"data\": [120, 132, 101, 134, 90, 60, 70], \"tension\": 0.35 }, { \"label\": \"Mobile\", \"data\": [220, 182, 191, 234, 210, 150, 160], \"tension\": 0.35 } ] } } Bar chart # Two datasets render as grouped bars; a legend is added automatically.\nExample Code { \"type\": \"bar\", \"data\": { \"labels\": [\"Q1\", \"Q2\", \"Q3\", \"Q4\"], \"datasets\": [ { \"label\": \"2025\", \"data\": [42, 55, 48, 61] }, { \"label\": \"2026\", \"data\": [51, 63, 59, 74] } ] } } Doughnut chart # For a single series of proportions, give the dataset an explicit backgroundColor array so each slice gets its own colour.\nExample Code { \"type\": \"doughnut\", \"data\": { \"labels\": [\"Organic\", \"Direct\", \"Social\", \"Referral\"], \"datasets\": [ { \"data\": [58, 22, 12, 8], \"backgroundColor\": [\"#ff5d8f\", \"#f59e0b\", \"#8b5cf6\", \"#12a594\"] } ] } } Radar chart # Example Code { \"type\": \"radar\", \"data\": { \"labels\": [\"Performance\", \"Accessibility\", \"Best Practices\", \"SEO\", \"PWA\"], \"datasets\": [ { \"label\": \"Before\", \"data\": [72, 88, 80, 90, 40] }, { \"label\": \"After\", \"data\": [98, 100, 95, 100, 80] } ] } } KaTeX: the basics # Place the marker shortcode {{\u003c katex \u003e}} on the page once - it loads the KaTeX renderer. You then write the actual math right in the prose with $ ... $ (inline) or $$ ... $$ (display); one marker covers the whole page.\nExample Code Inline: $E = mc^2$ sits in the middle of a sentence without blowing up the line height. In display mode the formula is centred on its own line:\n$$ \\int_{-\\infty}^{\\infty} e^{-x^2}\\,dx = \\sqrt{\\pi} $$Inline: $E = mc^2$ in the middle of a sentence. $$ \\int_{-\\infty}^{\\infty} e^{-x^2}\\,dx = \\sqrt{\\pi} $$ Fractions, roots, powers and indices # Example Code $$ \\frac{-b \\pm \\sqrt{b^2 - 4ac}}{2a} \\qquad \\sqrt[3]{x} \\qquad a_{i,j}^{2} $$$$ \\frac{-b \\pm \\sqrt{b^2 - 4ac}}{2a} \\qquad \\sqrt[3]{x} \\qquad a_{i,j}^{2} $$ Sums, products, limits # Example Code $$ \\sum_{k=1}^{n} k = \\frac{n(n+1)}{2} \\qquad \\prod_{i=1}^{n} i = n! \\qquad \\lim_{x \\to 0} \\frac{\\sin x}{x} = 1 $$$$ \\sum_{k=1}^{n} k = \\frac{n(n+1)}{2} \\qquad \\prod_{i=1}^{n} i = n! \\qquad \\lim_{x \\to 0} \\frac{\\sin x}{x} = 1 $$ Greek letters and operators # Example Code $$ \\alpha,\\ \\beta,\\ \\gamma,\\ \\Delta,\\ \\Omega \\qquad \\nabla \\cdot \\vec{E} = \\frac{\\rho}{\\varepsilon_0} \\qquad x \\in \\mathbb{R},\\ A \\subseteq B $$$$ \\alpha,\\ \\beta,\\ \\gamma,\\ \\Delta,\\ \\Omega \\qquad \\nabla \\cdot \\vec{E} = \\frac{\\rho}{\\varepsilon_0} \\qquad x \\in \\mathbb{R},\\ A \\subseteq B $$ Matrices # Example Code $$ \\begin{pmatrix} a \u0026 b \\\\ c \u0026 d \\end{pmatrix} \\begin{pmatrix} x \\\\ y \\end{pmatrix} = \\begin{pmatrix} ax + by \\\\ cx + dy \\end{pmatrix} $$$$ \\begin{pmatrix} a \u0026 b \\\\ c \u0026 d \\end{pmatrix} \\begin{pmatrix} x \\\\ y \\end{pmatrix} = \\begin{pmatrix} ax + by \\\\ cx + dy \\end{pmatrix} $$ Aligned multi-line and cases # Use aligned to line up on \u0026, and cases for piecewise definitions:\nExample Code $$ \\begin{aligned} f(x) \u0026= (x+1)^2 \\\\ \u0026= x^2 + 2x + 1 \\end{aligned} \\qquad |x| = \\begin{cases} x, \u0026 \\text{if } x \\ge 0 \\\\ -x, \u0026 \\text{otherwise} \\end{cases} $$$$ \\begin{aligned} f(x) \u0026= (x+1)^2 \\\\ \u0026= x^2 + 2x + 1 \\end{aligned} \\qquad |x| = \\begin{cases} x, \u0026 \\text{if } x \\ge 0 \\\\ -x, \u0026 \\text{otherwise} \\end{cases} $$ Mermaid: the basics # You describe the diagram as text between {{\u003c mermaid \u003e}} and {{\u003c /mermaid \u003e}} - Mermaid renders it to SVG in the browser. The first line picks the diagram type (graph/flowchart, sequenceDiagram, classDiagram, …).\nExample Code graph LR A[Markdown] --\u003e B{Render hook} B --\u003e C[WebP] B --\u003e D[Lightbox] graph LR A[Markdown] --\u003e B{Render hook} B --\u003e C[WebP] B --\u003e D[Lightbox] Flow direction and node shapes # graph/flowchart supports the directions TD (top→down), LR, RL and BT. The brackets around the node text set its shape: [box], (round), ([stadium]), {diamond}, ((circle)).\nExample Code flowchart TD Start([Start]) --\u003e Check{All green?} Check --\u003e|yes| Deploy[Deploy] Check --\u003e|no| Fix(Fix errors) Fix --\u003e Check Deploy --\u003e Done((Done)) flowchart TD Start([Start]) --\u003e Check{All green?} Check --\u003e|yes| Deploy[Deploy] Check --\u003e|no| Fix(Fix errors) Fix --\u003e Check Deploy --\u003e Done((Done)) Sequence diagram # For interactions between participants - with activation bars and notes.\nExample Code sequenceDiagram participant V as Visitor participant S as Server V-\u003e\u003eS: GET /post/... activate S S--\u003e\u003eV: HTML (pre-rendered) deactivate S Note over V: Apply dark mode (no flash) sequenceDiagram participant V as Visitor participant S as Server V-\u003e\u003eS: GET /post/... activate S S--\u003e\u003eV: HTML (pre-rendered) deactivate S Note over V: Apply dark mode (no flash) Class diagram # Example Code classDiagram class Post { +string Title +Date Date +render() string } class Series { +string Name } Series \"1\" o-- \"*\" Post : contains classDiagram class Post { +string Title +Date Date +render() string } class Series { +string Name } Series \"1\" o-- \"*\" Post : contains State diagram # Example Code stateDiagram-v2 [*] --\u003e Draft Draft --\u003e Review: submit Review --\u003e Draft: changes Review --\u003e Published: approve Published --\u003e [*] stateDiagram-v2 [*] --\u003e Draft Draft --\u003e Review: submit Review --\u003e Draft: changes Review --\u003e Published: approve Published --\u003e [*] Gantt chart # Example Code gantt title Project roadmap dateFormat YYYY-MM-DD section Planning Concept :done, des1, 2026-01-01, 2026-01-07 Draft :active, des2, 2026-01-08, 5d section Build Build : des3, after des2, 10d Test \u0026 launch : des4, after des3, 4d gantt title Project roadmap dateFormat YYYY-MM-DD section Planning Concept :done, des1, 2026-01-01, 2026-01-07 Draft :active, des2, 2026-01-08, 5d section Build Build : des3, after des2, 10d Test \u0026 launch : des4, after des3, 4d Pie chart # Example Code pie showData title Time per task \"Writing\" : 45 \"Tinkering\": 35 \"Cleanup\" : 20 pie showData title Time per task \"Writing\" : 45 \"Tinkering\": 35 \"Cleanup\" : 20 ER diagram # Example Code erDiagram CATEGORY ||--o{ POST : has POST }o--o{ TAG : tagged-with erDiagram CATEGORY ||--o{ POST : has POST }o--o{ TAG : tagged-with Mermaid automatically adopts the light or dark colour scheme and re-renders live when you toggle dark mode - try the switch in the top right while a diagram is visible.\nUnder the hood # What both shortcodes take care of in the background - with no extra effort:\nSelf-hosted, no CDN. Mermaid, KaTeX (fonts included) and Chart.js are vendored from npm into the theme and served from your own domain - GDPR-friendly, no third-party requests. Only when needed. The libraries land only on pages that use the mermaid, katex or chart shortcode (.HasShortcode). Pages without diagrams, formulas or charts load no extra JavaScript. CSP-friendly. The init scripts load as regular \u003cscript src\u003e with subresource integrity and defer, not inline - a strict Content Security Policy without unsafe-inline stays possible. Live dark mode. A MutationObserver on html.dark re-renders the diagrams and re-themes the charts as soon as the colour scheme changes (Mermaid and Chart.js only theme at render time). Stable sizes. Mermaid measures text boxes at render time; the init waits for document.fonts.ready so diagrams are measured with the loaded font and don’t jump in size between reloads. Safe. Mermaid runs with securityLevel: \"strict\". KaTeX auto-render only processes the prose regions of the page and leaves code blocks untouched - so $ signs in examples stay put. "},{"id":"https://theme.docs.tbsch.de/post/2026-02-02-images-and-galleries/","url":"https://theme.docs.tbsch.de/post/2026-02-02-images-and-galleries/","title":"Images and galleries","summary":"How the theme processes images - WebP, responsive, zoomable - plus captions, sizes and galleries.","date_published":"2026-02-02T00:00:00Z","date_modified":"2026-02-02T00:00:00Z","tags":["Features","images","gallery","lightbox"],"_social":{"hashtags":[],"mentions":{"mastodon":[],"bluesky":[]}},"content_text":"This post has a feature image: an image named feature.webp in the post bundle is automatically picked up as the hero background. (Alternatively, featureimage: in the front matter applies, or an image named *background*/*cover*/*thumbnail* in the bundle, or the site’s defaultBackgroundImage.)\nThe image render hook # Every perfectly ordinary Markdown image is automatically converted to WebP, served responsively in several sizes (srcset), lazy-loaded - and zoomable via lightbox (PhotoSwipe). You simply write:\n![A workflow as a diagram](workflow.webp) Clicking the image opens the full resolution. No manual converting, no linking to the original image.\nCaptions # A Markdown title (in quotes after the URL) becomes the visible caption - and at the same time the caption in the lightbox:\n![Alt text](workflow.webp \"A **caption** with Markdown.\") A caption with Markdown.Image sizes # Via a block attribute on the line below the image you can limit the width - small, medium, large or wide:\n![Alt](workflow.webp) {class=\"medium\"} All four sizes side by side - small (narrow, e.g. for portrait screenshots), medium, large and wide (breaks out of the text column):\nsmallmediumlargewideGallery - automatic # The gallery shortcode lays out several images as columns (masonry). In automatic mode you simply write one image per line; cols sets the number of columns (default 3, 1 on phones). All images of a gallery form one contiguous, swipeable lightbox group.\nThe split is sequential, not alternating: with six images and three columns, images 1-2 end up in the first column, 3-4 in the second and 5-6 in the third. On narrow viewports the columns dissolve and the images flow back underneath each other in source order. A caption (Markdown title, see above) works inside a gallery too - visible below the image and as the lightbox caption:\n{{\u003c gallery cols=\"3\" \u003e}} ![Living room](galerie/bild-1.webp \"The dashboard in the living room.\") ![Inverter](galerie/bild-2.webp) ![Mini PC](galerie/bild-3.webp) ![On the Mac](galerie/bild-4.webp) ![On the iPhone](galerie/bild-5.webp) ![Window sensor](galerie/bild-6.webp) {{\u003c /gallery \u003e}} The dashboard in the living room. Gallery - explicit columns # For full control over which image sits in which column, nest gallery-column. The cols parameter is ignored in this mode - the number of columns follows from the number of gallery-column blocks, and within a column the images stack in the order you write them. That lets you distribute portrait and landscape shots deliberately, or pin a particular image to the top left. Lightbox grouping and mobile behaviour are the same as in automatic mode.\n{{\u003c gallery \u003e}} {{\u003c gallery-column \u003e}} ![Living room](galerie/bild-1.webp) ![Mini PC](galerie/bild-3.webp) {{\u003c /gallery-column \u003e}} {{\u003c gallery-column \u003e}} ![Inverter](galerie/bild-2.webp) ![Window sensor](galerie/bild-6.webp) {{\u003c /gallery-column \u003e}} {{\u003c /gallery \u003e}} Linked images # An image that is itself a link is not added to the lightbox group - handy for clickable logos:\n[![Hugo logo](galerie/bild-3.webp)](https://gohugo.io) Under the hood # What the gallery takes care of in the background - no further parameters needed:\nEvery image goes through the normal image render hook: WebP conversion, several srcset sizes, lazy loading. The sizes hint is rewritten per gallery to the actual column width (with three columns roughly a third of the viewport) - so the browser fetches the smallest fitting variant instead of the full width. The columns are flex columns, not CSS multi-columns: every column starts at the same top edge in every browser, with no engine-dependent balancing. On phones display: contents dissolves the columns - the images stack underneath each other in source order again. ","image":"https://theme.docs.tbsch.de/post/2026-02-02-images-and-galleries/feature_hu_9b41f50389646781.webp"},{"id":"https://theme.docs.tbsch.de/post/2026-01-26-shortcodes/","url":"https://theme.docs.tbsch.de/post/2026-01-26-shortcodes/","title":"Shortcodes at a glance","summary":"The theme’s shortcodes: accordion, buttons, card, carousel, gallery, GitHub, icons, KaTeX, lead, Mermaid, chart, specs and tabs.","date_published":"2026-01-26T00:00:00Z","date_modified":"2026-01-26T00:00:00Z","tags":["Features","shortcodes","hugo"],"_social":{"hashtags":[],"mentions":{"mastodon":[],"bluesky":[]}},"content_text":"The theme ships with a handful of shortcodes - here they are, sorted alphabetically. Diagrams (Mermaid) and math (KaTeX) show up here in brief and are covered in depth in Diagrams and math.\nAccordion # Collapsible sections based on native \u003cdetails\u003e - no JavaScript at all. By default only one entry is open at a time; with single=\"false\" several may be open. With open=\"true\" an entry starts expanded.\n{{\u003c accordion \u003e}} {{\u003c accordion-item label=\"What is a shortcode?\" icon=\"puzzle\" \u003e}} A reusable building block written as **Markdown**. {{\u003c /accordion-item \u003e}} {{\u003c accordion-item label=\"Do I need JavaScript?\" open=\"true\" \u003e}} No - it uses native `\u003cdetails\u003e`/`\u003csummary\u003e`. {{\u003c /accordion-item \u003e}} {{\u003c /accordion \u003e}} What is a shortcode? A reusable building block that you call right inside your Markdown. Do I need JavaScript for this? No - the accordion uses native \u003cdetails\u003e/\u003csummary\u003e and works even with JavaScript disabled. Can more than one entry be open? Not by default - set single=\"false\" to allow it. Amazon # Renders an affiliate product as a card. You only pass the affiliate reflink; the title, description, image and price come from a build-time cache (data/products.yaml), which script/fetch-amazon-products.js fills from the Amazon Creators API — the site build itself never calls Amazon. The product image loads from Amazon’s CDN only after consent via Klaro, and the link carries rel=\"sponsored\" (which automatically shows the advertising disclosure). The price is shown only while the cached data is fresh (\u003c 24 h), per Amazon’s terms.\n{{\u003c amazon \"https://amzlink.to/az0sqPpjSZX54\" \u003e}} Midea Portasplit Cool Mobile Klimaanlage nur Kühlung\nView on Amazon It also works inside the card grid — drop several amazon shortcodes between card-grid tags and they line up as equal-height cells:\n{{\u003c card-grid cols=2 \u003e}} {{\u003c amazon \"https://amzlink.to/az0sqPpjSZX54\" \u003e}} {{\u003c amazon \"https://amzlink.to/az0demo1234\" \u003e}} {{\u003c /card-grid \u003e}} Midea Portasplit Cool Mobile Klimaanlage nur Kühlung\nView on Amazon Raspberry Pi 5 (8 GB RAM)\nQuad-Core Cortex-A76 @ 2,4 GHz, PCIe 2.0, Dual-4K-HDMI — der Einplatinenrechner für dein nächstes Homelab-Projekt.\nView on Amazon Buttons # A button is a link styled as a push button.\n{{\u003c button href=\"https://gohugo.io\" target=\"_blank\" \u003e}}To the Hugo docs{{\u003c /button \u003e}} {{\u003c button href=\"https://example.com/produkt\" sponsored=\"true\" \u003e}}Affiliate link{{\u003c /button \u003e}} To the Hugo docs Affiliate link With sponsored=\"true\" the button gets a shopping-cart icon and rel=\"sponsored\" - which automatically shows the advertising disclosure at the top of the page (scroll up and see). Instead of href you can also pass pageRef=\"posts/01-willkommen\" for internal targets.\nCard # Embeds a post, category, series or page as a card right inside the text - in the same look as the cards on the list pages. The type is detected automatically; type=\"article|category|series|page\" overrides it.\n{{\u003c card \"posts/01-willkommen\" \u003e}} {{\u003c card \"series/example-series\" \u003e}} Welcome to the tbsch theme Welcome to the tbsch themeBasicsAn overview of the tbsch theme: what it can do, how this demo is structured and where to start.\nFeb 23, 2026 2 min Example Series 3 partsA three-part series showing how the theme links related posts together.\nPart 1: Example Series, part 1: The beginning Part 2: Example Series, part 2: The middle Part 3: Example Series, part 3: The end Card grid # Several cards side by side, in the same grid look as the hub pages. cols (optional, default 2, at most 4) sets the desktop column count; on narrow viewports the grid collapses to a single column. The content should consist of card shortcodes.\n{{\u003c card-grid \u003e}} {{\u003c card \"posts/01-willkommen\" \u003e}} {{\u003c card \"series/example-series\" \u003e}} {{\u003c /card-grid \u003e}} Welcome to the tbsch theme Welcome to the tbsch themeBasicsAn overview of the tbsch theme: what it can do, how this demo is structured and where to start.\nFeb 23, 2026 2 min Example Series 3 partsA three-part series showing how the theme links related posts together.\nPart 1: Example Series, part 1: The beginning Part 2: Example Series, part 2: The middle Part 3: Example Series, part 3: The end With cols=3:\n{{\u003c card-grid cols=3 \u003e}} {{\u003c card \"posts/02-markdown-grundlagen\" \u003e}} {{\u003c card \"posts/03-admonitions\" \u003e}} {{\u003c card \"posts/05-bilder-und-galerien\" \u003e}} {{\u003c /card-grid \u003e}} Markdown basics \u0026 typography Markdown basics \u0026 typographyBasicsHeadings, lists, tables, code, footnotes, quotes - how the theme renders standard Markdown.\nJan 12, 2026 4 min Admonitions - callout boxes Admonitions - callout boxesFeaturesAll coloured callout boxes in GitHub alert style: note, tip, warning, danger and more - collapsible too.\nJan 19, 2026 2 min Images and galleries Images and galleriesFeaturesThe image render hook (WebP, responsive, zoomable), image sizes, captions and the gallery shortcodes.\nFeb 2, 2026 3 min Carousel # A horizontally swipeable carousel. Each slide can contain an image or arbitrary Markdown. Without JavaScript it remains a strip operable via swipe/scroll; with JS it gains arrow buttons, dots and keyboard control (arrow keys).\nBy default the carousel wraps around to the first slide after the last one; loop=\"false\" turns that off (the arrows then stop at the ends). With auto=5 it advances automatically every 5 seconds - only with loop active, paused on hover/focus (the timer then resumes where it stopped), and it respects reduced motion. The active slide’s pill fills up with the timer. ratio sets the frame’s aspect ratio (default \"16 / 9\", e.g. ratio=\"21 / 9\" or ratio=\"4 / 3\").\n{{\u003c carousel \u003e}} {{\u003c carousel-slide \u003e}}![Alp](carousel-1.webp){{\u003c /carousel-slide \u003e}} {{\u003c carousel-slide \u003e}} ### Markdown too Each slide takes **any** content - headings, lists, code. {{\u003c /carousel-slide \u003e}} {{\u003c /carousel \u003e}} Images or Markdown # Each slide takes any content:\nHeadings and body text Lists Code And with autoplay (auto=5) and text-only slides - their content is indented so the arrows never cover it:\n{{\u003c carousel auto=5 ratio=\"21 / 9\" \u003e}} {{\u003c carousel-slide \u003e}}### Slide one …{{\u003c /carousel-slide \u003e}} {{\u003c carousel-slide \u003e}}### Slide two …{{\u003c /carousel-slide \u003e}} {{\u003c carousel-slide \u003e}}### Slide three …{{\u003c /carousel-slide \u003e}} {{\u003c /carousel \u003e}} Slide one # Advances automatically every 5 seconds.\nSlide two # Hover or focus pauses the autoplay.\nSlide three # After the last slide it wraps around to the first (loop).\nChart # A chart via self-hosted Chart.js, loaded only when the shortcode is present. The inner content is the Chart.js configuration as valid JSON; axes, grid and legend follow the theme and re-colour live when you toggle dark mode.\n{{\u003c chart title=\"Monthly visitors\" \u003e}} { \"type\": \"bar\", \"data\": { \"labels\": [\"Jan\", \"Feb\", \"Mar\"], \"datasets\": [{ \"label\": \"Visitors\", \"data\": [820, 932, 1290] }] } } {{\u003c /chart \u003e}} Gallery # The gallery shortcode arranges several images as masonry columns. In automatic mode you simply write one image per line; cols (optional, default 3) sets the number of desktop columns, collapsing to a single column on phones. All images of a gallery form one swipeable lightbox group (PhotoSwipe); linked images ([![…](…)](url)) stay plain links and are not part of the group.\n{{\u003c gallery cols=\"2\" \u003e}} ![Living room](galerie-1.webp) ![Inverter](galerie-2.webp) ![Mini PC](galerie-3.webp) ![On the Mac](galerie-4.webp) {{\u003c /gallery \u003e}} Instead of the automatic split you can fill the columns explicitly with nested gallery-column blocks - cols is then ignored and the number of columns follows from the number of blocks. All the details (column logic, captions, responsive sizes, linked images) are covered in Images and galleries.\nGitHub # Embeds the OpenGraph preview of a repository. The external preview image only loads after consent via the consent manager Klaro - the link to the project always works.\n{{\u003c github repo=\"gohugoio/hugo\" \u003e}} Visit gohugoio/hugo on GitHub Icons # {{\u003c ti name \u003e}} places a Tabler icon right in the text that scales with the font size - e.g. or . Any name from the Tabler outline set works (deliberately outline only, not filled - the theme mounts just the stroke set so every icon speaks the same line language).\nKaTeX # Place the marker shortcode {{\u003c katex \u003e}} on the page once - it loads the (self-hosted) KaTeX renderer. After that you write math inline with $ ... $ and display with $$ ... $$; KaTeX loads only when the marker is present.\n{{\u003c katex \u003e}} Inline: Euler's identity $e^{i\\pi} + 1 = 0$. Inline: Euler’s identity $e^{i\\pi} + 1 = 0$, and the Gauss sum in display:\n$$ \\sum_{k=1}^{n} k = \\frac{n(n+1)}{2} $$Display, matrix and multi-line formulas are shown in Diagrams and math.\nLead # A highlighted introductory paragraph. The content is rendered as Markdown.\n{{\u003c lead \u003e}} A **lead** paragraph sums up the post in a sentence or two. {{\u003c /lead \u003e}} A lead paragraph sums up the post in a sentence or two - set larger and visually distinct from the body text. Mermaid # Write a diagram as text inside a mermaid shortcode. The (self-hosted) Mermaid loads only when the shortcode is present and automatically follows the light or dark colour scheme (including live toggles).\n{{\u003c mermaid \u003e}} graph LR A[Markdown] --\u003e B[HTML] {{\u003c /mermaid \u003e}} graph LR A[Markdown] --\u003e B[HTML] Flowcharts, sequence, class, state, Gantt and further diagram types are shown in Diagrams and math.\nSpecs # A spec sheet lists a product’s key facts as icon-labelled rows. Add title2 plus a value2 per row to turn it into a side-by-side comparison of two products.\n{{\u003c specs title=\"Midea PortaSplit Cool\" badge=\"Data sheet\" \u003e}} {{\u003c spec icon=\"snowflake\" label=\"Cooling capacity\" value=\"2.35 kW\" \u003e}} {{\u003c spec icon=\"tag\" label=\"Price (RRP)\" value=\"€899\" \u003e}} {{\u003c /specs \u003e}} Data sheetMidea PortaSplit Cool Cooling capacity 2.35 kW (8,000 BTU) Rooms up to 28 m² Noise (silent mode) 38 dB(A) Price (RRP) €899 Pass title2 for a comparison of two products; image/image2 add a product photo per column and link/link2 a buy button:\nComparisonPortaSplit CoolPortaSplit Cooling capacity 2.35 kW (8,000 BTU)3.5 kW (12,000 BTU) Rooms up to 28 m²42 m² Noise (silent mode) 38 dB(A)39 dB(A) Heating NoYes Price (RRP) €899€1,199View offer View offer Tabs # Tabs group alternative content (e.g. per operating system). Tabs sharing the same group synchronise site-wide: pick “macOS” in one group and all other groups jump to “macOS” as well. group is only the internal sync key; label sets the tablist’s screen-reader-announced name (without label it falls back to the localized default “Tabs” - never the group key itself).\n{{\u003c tabs group=\"os\" label=\"Operating system\" \u003e}} {{\u003c tab label=\"Linux\" icon=\"brand-debian\" \u003e}} `sudo apt install hugo` {{\u003c /tab \u003e}} {{\u003c tab label=\"macOS\" icon=\"brand-apple\" \u003e}} `brew install hugo` {{\u003c /tab \u003e}} {{\u003c /tabs \u003e}} Linux macOS Windows Install via package manager:\nsudo apt install hugo Install via Homebrew:\nbrew install hugo Install via Winget:\nwinget install Hugo.Hugo.Extended With default=\"macOS\" a tab other than the first is preselected; with md=false a tab’s content is not interpreted as Markdown.\nThis second group uses the same group=\"os\" - switch the operating system above and watch it follow along (the choice is remembered, too):\nLinux macOS Windows Configuration file at ~/.config/hugo.toml.Configuration file at ~/Library/Application Support/hugo.toml.Configuration file at %AppData%\\hugo.toml. "},{"id":"https://theme.docs.tbsch.de/post/2026-01-19-admonitions-callout-boxes/","url":"https://theme.docs.tbsch.de/post/2026-01-19-admonitions-callout-boxes/","title":"Admonitions - callout boxes","summary":"All coloured callout boxes in GitHub alert style - collapsible and with custom titles.","date_published":"2026-01-19T00:00:00Z","date_modified":"2026-01-19T00:00:00Z","tags":["Features","markdown","admonitions"],"_social":{"hashtags":[],"mentions":{"mastodon":[],"bluesky":[]}},"content_text":"Callout boxes are created from GitHub-style alerts in perfectly normal Markdown: a blockquote whose first line contains [!type]. The blockquote render hook turns it into a coloured box with icon and title.\nThe types # \u003e [!note] \u003e This is how you write a callout box. Note A neutral note. note is the default type.\nInfo A piece of information - like note, just in blue.\nTip A helpful tip (tip).\nSuccess It worked! success is for completed things and successes.\nImportant Something important (important) that shouldn’t be missed.\nWarning A warning (warning) - caution is advised here.\nCaution caution - one level more serious.\nDanger Careful, something can break here - danger.\nFailure Something has failed (failure).\nQuestion An open question or an FAQ entry - question.\nCustom title # Write the title after the type:\n\u003e [!tip] My custom title \u003e Content of the box. My custom title The default title (“Tip”) is replaced by your text.\nCollapsible # A + turns the box into an expanded \u003cdetails\u003e, a - into a collapsed one:\n\u003e [!info]- Collapsed - tap to expand \u003e This content is hidden initially. Collapsed - tap to expand This content is hidden initially and expands on click.\nExpanded - can be collapsed This box is open but can be collapsed.\nAliases # Many common spellings are translated automatically, e.g. [!warning]/[!attention], [!tip]/[!hint], [!danger]/[!error], [!success]/[!check]/[!done] or [!question]/[!faq].\nTip hint is an alias for tip.\nThere is also an affiliate type for advertising disclosures - the theme also shows it automatically at the top of posts containing affiliate links."},{"id":"https://theme.docs.tbsch.de/post/2026-01-12-markdown-basics-typography/","url":"https://theme.docs.tbsch.de/post/2026-01-12-markdown-basics-typography/","title":"Markdown basics \u0026 typography","summary":"How the theme renders standard Markdown: typography, lists, tables, code, footnotes and more.","date_published":"2026-01-12T00:00:00Z","date_modified":"2026-01-12T00:00:00Z","tags":["Basics","markdown","typography","code"],"_social":{"hashtags":[],"mentions":{"mastodon":[],"bluesky":[]}},"content_text":"This post shows how the theme renders perfectly ordinary Markdown - the reading typography, the table of contents (on the left when there is enough room) and the direct links on every heading are all generated automatically.\nEvery example comes with two tabs: Markdown shows the rendered result, Raw the source behind it.\nHeadings \u0026 table of contents # # H1 is reserved for the page title (the theme renders it in the hero) - content therefore starts at ##. This post’s own ## headings end up in the table of contents and get a direct link (anchor) on hover; the depth is controlled by tableOfContents in markup.yaml (H2–H4 here). The demo headings inside the tab are rendered in isolation and keep the table of contents clean.\nMarkdown Raw Heading H2 # Heading H3 # Heading H4 # Heading H5 # Heading H6 # ## Heading H2 ### Heading H3 #### Heading H4 ##### Heading H5 ###### Heading H6 Text formatting # Internal links are best set via the relref shortcode - like this one to the welcome post; external links open in a new tab and automatically get a matching icon (the URL→icon mapping lives in data/link-icons.yaml).\nMarkdown Raw Text can be bold, italic, both, struck through or set as inline code. Emojis work as well 😎.\nA paragraph with an external link - it opens in a new tab and carries its icon.\nText can be **bold**, *italic*, ***both***, ~~struck through~~ or set as `inline code`. Emojis work as well :sunglasses:. A paragraph with an [external link](https://gohugo.io) - it opens in a new tab and carries its icon. Lists # Markdown Raw Unordered:\nFirst item Second item Nested Another one Third item Ordered:\nStep one Step two Step three Task list:\nTheme installed Demo read Own site built Unordered: - First item - Second item - Nested - Another one - Third item Ordered: 1. Step one 2. Step two 3. Step three Task list: - [x] Theme installed - [x] Demo read - [ ] Own site built Quotes # For coloured callout boxes see the post Admonitions - a plain blockquote is passed through unchanged by the blockquote render hook:\nMarkdown Raw A plain blockquote. Multiple lines are joined into a single paragraph.\n\u003e A plain blockquote. Multiple lines are joined into a single paragraph. Tables # Markdown Raw Feature Default Overridable per page Table of contents on yes Reading time on yes Related posts on yes Sharing bar on yes | Feature | Default | Overridable per page | | --- | :---: | :---: | | Table of contents | on | yes | | Reading time | on | yes | | Related posts | on | yes | | Sharing bar | on | yes | Code # Inline code like hugo server sits in the middle of the text. Code blocks are highlighted class-based with Chroma, so the light and dark palettes can be shipped separately:\nMarkdown Raw // A small example package main import \"fmt\" func main() { fmt.Println(\"Hello from the tbsch theme!\") } # A post's front matter title: \"My post\" date: 2026-01-01 tags: [\"hugo\", \"theme\"] @@ config @@ -baseURL = \"https://old.example\" +baseURL = \"https://tbsch.de\" languageCode = \"en\" ```go // A small example package main import \"fmt\" func main() { fmt.Println(\"Hello from the tbsch theme!\") } ``` ```yaml # A post's front matter title: \"My post\" date: 2026-01-01 tags: [\"hugo\", \"theme\"] ``` ```diff @@ config @@ -baseURL = \"https://old.example\" +baseURL = \"https://tbsch.de\" languageCode = \"en\" ``` Footnotes # Footnotes are placed at the end of the text and linked - and additionally appear as a popover when you hover a reference with the mouse or focus it via keyboard. (Inside the tab, the footnote list renders at the end of the tab content; in a real post it sits at the end of the post.)\nMarkdown Raw Markdown footnotes1 are placed at the end and linked - and additionally appear as a popover when you hover a footnote reference like this one2 with the mouse or focus it via keyboard.\nThis is the first footnote. ↩︎\nAnd this is the second, with a link . ↩︎\nMarkdown footnotes[^1] are placed at the end and linked - and additionally appear as a popover when you hover a footnote reference like this one[^2] with the mouse or focus it via keyboard. [^1]: This is the first footnote. [^2]: And this is the second, with a [link](https://gohugo.io/content-management/shortcodes/). Dividers # Markdown Raw A horizontal rule separates sections:\nThat’s it for the basics.\nA horizontal rule separates sections: --- That's it for the basics. "},{"id":"https://theme.docs.tbsch.de/post/2025-12-15-example-series-part-3-the-end/","url":"https://theme.docs.tbsch.de/post/2025-12-15-example-series-part-3-the-end/","title":"Example Series, part 3: The end","summary":"Third and final part of the example series.","date_published":"2025-12-15T00:00:00Z","date_modified":"2025-12-15T00:00:00Z","tags":["Features","series"],"_social":{"hashtags":[],"mentions":{"mastodon":[],"bluesky":[]}},"content_text":"The third and final part. That completes the series - the box at the top lists all three parts in order.\nBack to the beginning."},{"id":"https://theme.docs.tbsch.de/post/2025-12-08-example-series-part-2-the-middle/","url":"https://theme.docs.tbsch.de/post/2025-12-08-example-series-part-2-the-middle/","title":"Example Series, part 2: The middle","summary":"Second part of the example series.","date_published":"2025-12-08T00:00:00Z","date_modified":"2025-12-08T00:00:00Z","tags":["Features","series"],"_social":{"hashtags":[],"mentions":{"mastodon":[],"bluesky":[]}},"content_text":"The second part. The series box now marks this post as the current one and links to the remaining parts.\nBack to part 1 or on to part 3."},{"id":"https://theme.docs.tbsch.de/post/2025-12-01-example-series-part-1-the-beginning/","url":"https://theme.docs.tbsch.de/post/2025-12-01-example-series-part-1-the-beginning/","title":"Example Series, part 1: The beginning","summary":"First part of the example series: how series work in the theme.","date_published":"2025-12-01T00:00:00Z","date_modified":"2025-12-01T00:00:00Z","tags":["Features","series"],"_social":{"hashtags":[],"mentions":{"mastodon":[],"bluesky":[]}},"content_text":"This is the first part of the series. At the top you can see the series box with all parts - the current one is highlighted. The box is created by the front matter alone:\nseries: - Example Series The order of the parts follows from the publication date - no extra ordering field is needed.\nIt continues in part 2."}]}