Highlighting and Markdown Blog Integration in the Gallery theme

Hi everyone!

I am actively using an amazing Gallery theme to build my hobby photo gallery. Can anyone share a recipe or a modification example of integrating the set of static blog pages alongside the gallery, addressing them via links in the page menu and footer? Now the built-in text formatting styles don’t seem to be convenient and controllable. Especially, I would like to have the possibility to publish snippets of source code with syntax highlighting. Unfortunately, I am not a web developer to learn fast about how to do that.

Do you mean you’d like to add a separate section (e.g, /blog/) for posts, and link it in both the hamburger menu and footer? Did I understand that correctly?

For the built-in text formatting styles, you’ll need edit/add rules under a .prose class in the assets/custom.css file.

For syntax highlighting, take a look at Hugo’s guide: Syntax highlighting styles

If you can share your repository, we can offer more targeted help. Just note that your theme is mainly designed as a gallery theme, not a blog theme.

Yes, exactly that! Unfortunately, I have no repository to share, but this is exactly what I want to do.

Thanks for pointing me to that, and I will appreciate if you would give me a couple of links to the live examples and/or snippets!

About adding a separate /blog/ section (take what I say with a pinch of salt since I haven’t actually used this theme or tested the code).

Backup your site if you don’t use git before you try to do anything

Create a new file at layouts/_default/list.html in your project’s root folder with the following content:

{{ define "main" }}
  {{ partial "title.html" . }}
  {{ if eq .Page.Params.type "blog" }}
  <section class="blog">
    {{ range .Pages }}
      <h2><a href="{{ .RelPermalink }}">{{ .LinkTitle }}</a></h2>
    {{ end }}
  </section>
  {{ else }}
  <section class="galleries">
    {{ range where .Pages "Params.private" "ne" true }}
      {{ partial "album-card.html" . }}
    {{ end }}
    {{ .Content }}
  </section>
  {{ end }}
{{ end }}

Then, create a file at content/blog/_index.md and include this in its front matter:

type: "blog"

After that, any post you create (for example: blog/post1.md, blog/post2.md) will automatically be listed on the blog page.


For syntax highlighting, Hugo’s styles page has everything you need just follow the instructions.
Add to your hugo.toml or hugo.yaml the snippet shown there, for example:

[markup]
  [markup.highlight]
    style = "monokai"

Replace "monokai" with any preferred style from the list on that page.

Use backticks (```) around your code blocks in Markdown to test the highlighting:

  • Three backticks before and after for code blocks.
  • One backtick before and after for inline code.

Keep in mind that your theme is actively developed, and it’s always a good idea to ask the theme’s creator directly, they might already have a recommended way to integrate sections like a blog or handle syntax highlighting.

1 Like

I ended up creating the menu button (maybe I will also update the site title string later to provide direct linking from the start page), pointing to the Blog section of the site. I created the custom-styled blog template embedded within the existing header/footer setup, and then generated the convenient SCSS template using Grok AI (it did that very well!). Using the head-custom.html template provided with the theme, I embedded the CSS template and KaTeX renderer for the blog (the KaTeX renderer also requires a separate JS provisioning template placed in math.html, which is written exactly as it is proposed in the documentation):

<!-- Custom <head> tags (e.g. analytics code) -->

<!-- Blog CSS -->
{{ $blogstyle := resources.Get "/css/blog.scss" | toCSS | minify | fingerprint }}
<link rel="stylesheet" href="{{ $blogstyle.RelPermalink }}" />

<!-- KaTeX -->
{{ if .Param "math" }}
  {{ partialCached "math.html" . }}
{{ end }}

The blog layout consists of two templates: list.html and blog.html. The list template generally follows the logic proposed by @Oxypteros, but it also handles the descriptive part of the blog posts list rendering:

{{ define "main" }}
  {{ partial "title.html" . }}
    {{ if eq .Page.Params.type "blogs" }}
    <section class="blog-list">
      <ul class="posts">
        {{/*  Sort by .Lastmod (most recent first)  */}}
        {{ range .Pages.ByLastmod.Reverse }}
          <li class="post">
            <div class="post-header">
              <time class="date">
                {{ .Lastmod | time.Format ":date_long" }}, {{ .Lastmod | time.Format ":time_long" }}
              </time>
              <h2 class="title">
                <a href="{{ .Permalink }}">{{ .Title }}</a>
              </h2>
            </div>

            {{ with .Description }}
              <p class="description">{{ . }}</p>
            {{ end }}
          </li>
        {{ end }}
      </ul>
    </section>
    {{ else }}
      <section class="galleries">
        {{ range where .Pages "Params.private" "ne" true }}
          {{ partial "album-card.html" . }}
        {{ end }}
        {{ .Content }}
      </section>
    {{ end }}
{{ end }}

blog.html template renders the content of the given blog page, distinguishing between the Blog section and the Gallery section, which allows turning on the syntax highlighter and formula renderer.

{{ define "main" }}
  {{ partial "title.html" . }}
  <article class="blog-post">
    <header class="post-meta">
      <time datetime="{{ .Lastmod.Format "2006-01-02" }}">
        {{ .Lastmod | time.Format ":date_long" }}, {{ .Lastmod | time.Format ":time_long" }} 
      </time>
    </header>

    <div class="post-content">
      {{ .Content }}
    </div>
  </article>
{{ end }}

The generated example SCSS template is hidden by a spoiler below.

blog.scss
/* -------------------------------------------------
   Global variables – GitHub Dark palette
   ------------------------------------------------- */
$bg:          #0d1117;
$fg:          #c9d1d9;   // ← main text colour (used for list links now)
$accent:      #58a6ff;   // kept only for other links (e.g. in post content)
$code-bg:     #161b22;
$border:      #30363d;
$muted:       #8b949e;
$header-fg:   #f0f6fc;   // white-ish for blog headings

/* -------------------------------------------------
   Reset & base – body only
   ------------------------------------------------- */
*,
*::before,
*::after { box-sizing: border-box; }

/* -------------------------------------------------
   Layout helpers
   ------------------------------------------------- */
.container {
  width: 90%;
  max-width: 1200px;
  margin: 0 auto;
  padding: 2rem 1rem;
}

/* =================================================
   BLOG-SPECIFIC STYLES
   ================================================= */
.blog-list,
.blog-post {
  @extend .container;

  /* ---------- Blog list ---------- */
  &.blog-list {
    .posts { list-style: none; padding: 0; margin: 0; }
    .post {
      border-bottom: 1px solid $border;
      padding: 1.5rem 0;
      &:last-child { border-bottom: none; }
    }
    .post-header {
      display: flex;
      flex-wrap: wrap;
      align-items: baseline;
      gap: 0.75rem;
      margin-bottom: 0.5rem;
    }
    .date {
      font-size: 0.9rem;
      color: $muted;
      white-space: nowrap;
    }
    .title {
      margin: 0;
      font-size: 1.02rem;
      font-weight: 600;

      /* ← CHANGED: link colour = text colour */
      a {
        color: $fg;
        text-decoration: none;
        &:hover { text-decoration: underline; }
      }
    }
    .description {
      margin: 0.25rem 0 0;
      font-size: 0.85rem;
      color: $fg;
    }
  }

  /* ---------- Single post ---------- */
  &.blog-post {
    max-width: 90%;
    margin-top: 2rem;

    .post-meta {
      margin-bottom: 1.5rem;
      font-size: 0.95rem;
      color: $muted;
    }
  }

  /* ---------- Typography (blog only) ---------- */
  h1, h2, h3, h4, h5, h6 {
    margin-top: 1.8rem;
    margin-bottom: 0.8rem;
    color: $header-fg;
    line-height: 1.3;
  }
  h1 { font-size: 2.2rem; }
  h2 { font-size: 1.8rem; }
  h3 { font-size: 1.5rem; }

  p { margin: 0 0 1rem; }

  /* Links inside post content keep accent */
  a {
    color: $accent;
    &:hover { text-decoration: underline; }
  }

  /* ---------- Code & Math ---------- */
  code {
    font-family: "Courier New", ui-monospace, SFMono-Regular, "SF Mono", Consolas, "Liberation Mono", Menlo, monospace;
    background: $code-bg;
    padding: 0.2em 0.4em;
    border-radius: 3px;
    font-size: 0.85em;
  }
  pre {
    background: $code-bg;
    padding: 1rem;
    overflow-x: auto;
    border-radius: 6px;
    margin: 1.5rem 0;
    code { background: none; padding: 0; }
  }
  .katex-display { margin: 1.5rem 0; }

  /* ---------- Media ---------- */
  img, video, iframe {
    max-width: 100%;
    height: auto;
    display: block;
    margin: 1.5rem auto;
    border-radius: 4px;
  }

  /* ---------- Blockquote & HR ---------- */
  blockquote {
    border-left: 4px solid $accent;
    margin: 1.5rem 0;
    padding-left: 1rem;
    font-style: italic;
    color: $muted;
  }
  hr {
    border: none;
    border-top: 1px solid $border;
    margin: 2rem 0;
  }

  /* ---------- Tables ---------- */
  table {
    width: 100%;
    border-collapse: collapse;
    margin: 1.5rem 0;
  }
  th, td {
    border: 1px solid $border;
    padding: 0.5rem 0.75rem;
    text-align: left;
  }
  th { background: $code-bg; }
}

/* =================================================
   RESPONSIVE (blog only)
   ================================================= */
@media (max-width: 640px) {
  .blog-list .post-header,
  .blog-post .post-header {
    flex-direction: column;
    align-items: flex-start;
  }
  .blog-list .date { margin-bottom: 0.25rem; }
}

Now, the only thing needed to render and embed the blog post into the site is to create the corresponding Markdown file in the blog subdirectory of the content root directory, with the type front matter parameter set to blogs, and the layout parameter set to blog. The content will be rendered and integrated into the site.

This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.