squidfunk / mkdocs-material

Documentation that simply works
https://squidfunk.github.io/mkdocs-material/
MIT License
19.04k stars 3.39k forks source link

Blog: Hero images #6745

Open mathisgauthey opened 4 months ago

mathisgauthey commented 4 months ago

Context

I'm coming from Hugo with the theme hugo-theme-stack. Here's a demo page using it that looks like my old setup.

That's a blog template, with images for each posts.

@alexvoss recommended that I submit a feature request here.

Description

I'd like the blog index page to search for the first image linked inside the markdown document and use it as a thumbnail. That would allow for beautiful and easy projects portfolio inside blogs from mkdocs-material. But also a colorful blog index.

One could also overwrite it using a thumbnail: YAML key that gives the path to a file.

A default value could be the social card for that particular link maybe ?

Here's an example of my old theme :

image

Here's my current theme using mkdocs-material :

image

Related links

Use Cases

Apparently I wasn't the only one to ask for such a feature.

The image would allow us to build beautiful blogs without hassles, using the already existing blog chronological index. And we could also use it for generating projects portfolio index files automatically.

Visuals

Add the image above or below the blog post in a rectangular container, maybe ? Or just a thumbnail on the left of the blog post in the index file.

Before submitting

squidfunk commented 4 months ago

Thanks for suggesting. Duplicate of #5736 (and some other issue I currently can't find). Please use customizations to include thumbnails in posts. It's likely that we eventually add this functionality, but we're still in the collection stage of requirements, so native support for this is not planed yet. It is, however, quite easy to do this functionality yourself.

You can post also ask for more support on our discussion board.

alexvoss commented 4 months ago

That was my fault for not looking for the prior discussion of this (I suggested the FR). @squidfunk, how about I show how this can be done in the blog example that I need to pick up again? I'll post the necessary snippets here. @mathisgauthey, do you think it would be ok to have to put the image URL/path into the post meta-data? That is the most flexible option, I think, but requires some work by the post author.

mathisgauthey commented 4 months ago

That was my fault for not looking for the prior discussion of this (I suggested the FR). @squidfunk, how about I show how this can be done in the blog example that I need to pick up again? I'll post the necessary snippets here. @mathisgauthey, do you think it would be ok to have to put the image URL/path into the post meta-data? That is the most flexible option, I think, but requires some work by the post author.

I think it could be a great start thanks !

One could then think about having a default behavior for handling thumbnails on modified Blog index pages such as using the first image found in the post or reverting to the social card of the post if the plugin is activated.

squidfunk commented 4 months ago

That was my fault for not looking for the prior discussion of this (I suggested the FR). @squidfunk, how about I show how this can be done in the blog example that I need to pick up again? I'll post the necessary snippets here. @mathisgauthey, do you think it would be ok to have to put the image URL/path into the post meta-data? That is the most flexible option, I think, but requires some work by the post author.

You know what, we'll reopen it, as this has been asked for a few times, so we'll see if others would find it useful as well. We could add functionality that extracts the image and allows for overriding via meta data, but I need to investigate. I'll try to come up with a general solution for this, but in the mean time the absolute simplest solution is https://github.com/squidfunk/mkdocs-material/discussions/5406#discussioncomment-5692214.

One could then think about having a default behavior for handling thumbnails on modified Blog index pages such as using the first image found in the post or reverting to the social card of the post if the plugin is activated.

IMHO, it's a hero image, not a thumbnail 😉 Using the social card image is not really a good idea, IMHO, because it has a completely different purpose. Thus, I'd say:

  1. Check front matter
  2. Check source of blog for first encounter, or for an image tagged with the data-hero attribute (or similar)
  3. No image

We could also allow to explicitly unset the image by using something like hero: null. I think those degrees of freedom allow for very precise control and good default behavior. We could also add setting to switch it on/off completely.

squidfunk commented 4 months ago

Related:

Guts commented 4 months ago

Definitely interested too! For now, I'm using a custom template to achieve this but not relying on blog plugin.

pvdemael commented 3 weeks ago

I have a simple solution which works for me now. No doubt it can be improved much but it does the job. Some things are hardcoded but this can be changed by someone with much more dev skills. I must confess I used ChatGPT with a lot of prompts but hey, if it does the job...

In my case, only the home page must have a hero image. It needs to cycle every 4s between 4 available images with a fade effect.

The frontmatter of the home index.md page

---
hero:
  - assets/img/image1.png
  - assets/img/image2.png 
  - assets/img/image3.png
  - assets/img/image4.png

hide:
    - toc 
    - navigation

template: home.html
---

I override the home.html page with this code:

{% extends "main.html" %}

{% block hero %}
<div id="crossfade" class="hero-image">
  {% for image in page.meta.hero %}
    <div class="hero-image-inner {% if loop.first %}next{% endif %}" style="background-image: url('{{ image }}');"></div>
  {% endfor %}
  <div class="hero-text">
    <h1>Some text to add using variables</h1>
    <p>Here too</p>
    <button>And here too</button>
  </div>
</div>

<style>
  #crossfade {
    position: relative;
    width: 100%;
    height: 300px; /* Adjust height as needed */
    overflow: hidden;
  }

  .hero-image-inner {
    position: absolute;
    left: 0;
    top: 0;
    width: 100%;
    height: 100%;
    opacity: 0;
    z-index: 0;
    background-position: center;
    background-repeat: no-repeat;
    background-size: cover;
    transition: opacity 2s ease-in-out; /* Transition for opacity */
  }

  .hero-image-inner.next {
    opacity: 1;
  }

  /* Place text in the middle of the image */
  .hero-text {
    text-align: left;
    position: absolute;
    top: 50%;
    left: 10%;
    transform: translateY(-50%);
    color: white;
    z-index: 2;
    transition: opacity 2s ease-in-out; /* Transition for opacity */
  }
</style>

<script>
document.addEventListener('DOMContentLoaded', () => {
  const images = document.querySelectorAll('.hero-image-inner');
  let index = 0;

  setInterval(() => {
    images[index].classList.remove('next');
    index = (index + 1) % images.length;
    images[index].classList.add('next');
  }, 4000);
});
</script>
{% endblock %}