feat: cov.jpg cover image + retina thumbnails

This commit is contained in:
relikd
2023-02-28 20:53:15 +01:00
parent 477d134cd1
commit 19fc20b624
12 changed files with 76 additions and 37 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

View File

@@ -14,9 +14,7 @@ from .durationcluster import (
from .ingredients import IngredientsListType from .ingredients import IngredientsListType
from .latex import TexSources, raw_text_to_tex, html_to_tex from .latex import TexSources, raw_text_to_tex, html_to_tex
from .settings import Settings from .settings import Settings
from .utils import ( from .utils import fillupText, replace_atref_urls, cover_image, noUmlauts
fillupText, replace_atref_urls, sorted_images, title_image, noUmlauts
)
class MainPlugin(Plugin): class MainPlugin(Plugin):
@@ -33,8 +31,7 @@ class MainPlugin(Plugin):
'replaceAtRefURLs': replace_atref_urls, 'replaceAtRefURLs': replace_atref_urls,
'performGroupBy': self.performGroupBy, 'performGroupBy': self.performGroupBy,
'sorted_images': sorted_images, 'cover_image': cover_image,
'title_image': title_image,
'latexStr': raw_text_to_tex, 'latexStr': raw_text_to_tex,
'latexHtml': html_to_tex, 'latexHtml': html_to_tex,

View File

@@ -1,9 +1,10 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from jinja2.loaders import split_template_path # lookup_template_name() from lektor.context import get_ctx
from jinja2.loaders import split_template_path # lookup_template_path()
from markupsafe import Markup from markupsafe import Markup
import os import os
import unicodedata import unicodedata
from typing import TYPE_CHECKING, Dict, Union, Optional, List from typing import TYPE_CHECKING, Dict, Union, Optional, Tuple
if TYPE_CHECKING: if TYPE_CHECKING:
from lektor.db import Page, Image from lektor.db import Page, Image
from lektor.environment import Environment from lektor.environment import Environment
@@ -51,21 +52,25 @@ def replace_atref_urls(text: str, label: Optional[str] = None) -> str:
return Markup(' '.join(result)) return Markup(' '.join(result))
def sorted_images(obj: 'Page', attr: str = 'record_label') -> List['Image']: def cover_image(obj: 'Page') -> Optional['Image']:
return sorted(obj.attachments.images, ''' Find cover image (cov.jpg or sorted first) and apply thumbnail. '''
key=lambda x: getattr(x, attr)) # type:ignore[no-any-return] best = None
for img in obj.attachments.images: # type: Image
if img['_id'].rsplit('.')[0] == 'cov':
def title_image(obj: 'Page', attr: str = 'record_label', small: bool = False) \ best = img
-> Optional['Image']: break
imgs = sorted_images(obj, attr) if not best or img['_id'] < best['_id']:
img = imgs[0] if imgs else None best = img
if img and small: if best:
img = img.thumbnail(200, 150, mode='crop') ctx = get_ctx()
return img if ctx:
ctx.pad.db.track_record_dependency(best)
return retina_thumbnail(best, w=200, h=150, mode='crop')[0]
return None
def noUmlauts(text: str) -> str: def noUmlauts(text: str) -> str:
''' Remove umlauts and other unix-path incompatible characters. '''
# try: # try:
# data = unicode(text, 'utf-8') # data = unicode(text, 'utf-8')
# except (TypeError, NameError): # except (TypeError, NameError):
@@ -77,9 +82,47 @@ def noUmlauts(text: str) -> str:
def lookup_template_path(name: str, env: 'Environment') -> Optional[str]: def lookup_template_path(name: str, env: 'Environment') -> Optional[str]:
''' Find path to template with name. '''
pieces = split_template_path(name) pieces = split_template_path(name)
for base in env.jinja_env.loader.searchpath: for base in env.jinja_env.loader.searchpath:
path = os.path.join(base, *pieces) path = os.path.join(base, *pieces)
if os.path.isfile(path): if os.path.isfile(path):
return path return path
return None return None
def retina_thumbnail(
image: 'Image',
w: Optional[int] = None,
h: Optional[int] = None,
*,
mode: Optional[str] = None,
maxwidth: int = 99999999,
retina: int = 2,
) -> Tuple['Image', int, int]:
''' Constraint an image size with the least possible params. '''
if mode:
assert w and h, 'if using a crop mode, width and height are mandatory.'
else:
w = min(w, maxwidth * retina) if (w and w < image.width) else None
h = h if (h and h < image.height) else None
if w and h:
if h >= w / image.width * image.height:
h = None
else:
w = None
if w:
other = round(w / image.width * image.height)
elif h:
other = round(h / image.height * image.width)
else:
return image, image.width, image.height
ew, eh = w or other, h or other
w = (w * retina) if w and (w * retina < image.width) else None
h = (h * retina) if h and (h * retina < image.height) else None
if not w and not h:
return image, ew, eh
else:
img = image.thumbnail(width=w, height=h, mode=mode, upscale=False)
return img, ew, eh

View File

@@ -18,8 +18,7 @@
\begin{document} \begin{document}
\makefrontmatter \makefrontmatter
{%- for recipe in site.get('/recipes', alt=this.alt).children -%} {%- for recipe in site.get('/recipes', alt=this.alt).children %}
{%- set img = recipe | title_image(small=True) %}
{# recipe title (start on new page) #} {# recipe title (start on new page) #}
\newrecipe{ {{- recipe._slug -}} }{ {{- recipe.name | latexStr -}} } \newrecipe{ {{- recipe._slug -}} }{ {{- recipe.name | latexStr -}} }
@@ -29,6 +28,7 @@
\footer{ {{- recipe.source.url | latexStr -}} }{ {{- recipe.source.host | latexStr -}} } \footer{ {{- recipe.source.url | latexStr -}} }{ {{- recipe.source.host | latexStr -}} }
{# enumerate ingredients -#} {# enumerate ingredients -#}
{%- set img = recipe | cover_image -%}
\begin{ingredients}{ {{- img | url(absolute=True) if img else '' -}} } \begin{ingredients}{ {{- img | url(absolute=True) if img else '' -}} }
{%- for ing in recipe.ingredients %} {%- for ing in recipe.ingredients %}

View File

@@ -12,7 +12,7 @@
</head> </head>
<body> {#- ontouchstart="" #} <body> {#- ontouchstart="" #}
<header> <header>
<a id="logo" href="{{ site.get('/', this.alt)|url }}">recipe lekture</a> <a id="logo" href="{{ '/'|url }}">recipe lekture</a>
<nav> <nav>
<ul> <ul>
{%- set allRecipes = site.get('/recipes', this.alt) %} {%- set allRecipes = site.get('/recipes', this.alt) %}
@@ -47,7 +47,7 @@
we could use `site.get('/recipes.tex@LatexPDF', alt=this.alt) | url` we could use `site.get('/recipes.tex@LatexPDF', alt=this.alt) | url`
but then this will create a dependency on all recipes but then this will create a dependency on all recipes
-#} -#}
<a href="{{ '/'|url(alt=this.alt) + 'recipes.pdf' }}" download="recipes-{{ this.alt }}.pdf" title="{{ bag('i18n+' + this.alt, 'other.get_pdf') }}">{#--#} <a href="{{ '/'|url + 'recipes.pdf' }}" download="recipes-{{ this.alt }}.pdf" title="{{ bag('i18n+' + this.alt, 'other.get_pdf') }}">{#--#}
<img class="h1em" alt="(PDF)" height="20" src="{{ '/img/icon-pdf.svg'|url }}">{#--#} <img class="h1em" alt="(PDF)" height="20" src="{{ '/img/icon-pdf.svg'|url }}">{#--#}
</a> </a>
{%- set url_without_alt = ('.'|url(absolute=True))[4:] -%} {%- set url_without_alt = ('.'|url(absolute=True))[4:] -%}

View File

@@ -1,8 +1,6 @@
{%- macro render_recipe_list(recipes, limit=0) -%} {%- macro render_recipes(recipes) -%}
<div class="tile-grid"> <div class="tile-grid">
{%- for recipe in recipes -%} {%- for recipe in recipes -%}
{%- if limit == 0 or loop.index <= limit -%}
{%- set img = recipe | title_image(small=True) -%}
<a href="{{ recipe|url }}">{#--#} <a href="{{ recipe|url }}">{#--#}
<div class="recipe-tile"> <div class="recipe-tile">
@@ -15,10 +13,11 @@
</div> </div>
</div> </div>
{#- show image or placeholder text #} {#- show image or placeholder text -#}
{% if img -%} {%- set img = recipe | cover_image -%}
{%- if img %}
<img class="lozad" data-src="{{ img|url }}"> <img class="lozad" data-src="{{ img|url }}">
{%- else -%} {%- else %}
<div class="placeholder">No Image</div> <div class="placeholder">No Image</div>
{%- endif -%} {%- endif -%}
@@ -26,7 +25,6 @@
<p>{{ recipe.name }}</p> <p>{{ recipe.name }}</p>
</div>{#--#} </div>{#--#}
</a> </a>
{%- endif -%}
{%- endfor %} {%- endfor %}
</div> </div>
{%- endmacro -%} {%- endmacro -%}

View File

@@ -4,7 +4,8 @@
<article class="recipe"> <article class="recipe">
<!-- date added: {{ this.date }} --> <!-- date added: {{ this.date }} -->
<section id="img-carousel" class="v-scroll center"> <section id="img-carousel" class="v-scroll center">
{%- for img in this | sorted_images %} {%- for img in this.attachments.images | sort(attribute='_id')
if img._id.rsplit('.')[0] != 'cov' %}
<img class="lozad" data-src="{{ img|url }}" height="400"> <img class="lozad" data-src="{{ img|url }}" height="400">
{%- endfor -%} {%- endfor -%}
</section> </section>

View File

@@ -1,5 +1,5 @@
{% extends "layout.html" %} {% extends "layout.html" %}
{% from "macros/recipes.html" import render_recipe_list %} {% from "macros/recipes.html" import render_recipes %}
{% from "macros/pagination.html" import render_pagination_all %} {% from "macros/pagination.html" import render_pagination_all %}
{% block title %}{{ bag('i18n+' + this.alt, 'title.recipes') }}{% endblock %} {% block title %}{{ bag('i18n+' + this.alt, 'title.recipes') }}{% endblock %}
{% block body %} {% block body %}
@@ -8,6 +8,6 @@
}} <a href="/static/pdf-{{ this.alt }}.pdf" download="recipes-{{ this.alt }}.pdf" title="{{ }} <a href="/static/pdf-{{ this.alt }}.pdf" download="recipes-{{ this.alt }}.pdf" title="{{
bag('i18n+' + this.alt, 'other.get_pdf') bag('i18n+' + this.alt, 'other.get_pdf')
}}"><img class="h1em" alt="(PDF)" height="20pt" src="{{ '/img/icon-pdf.svg'|url }}"></a></h1> }}"><img class="h1em" alt="(PDF)" height="20pt" src="{{ '/img/icon-pdf.svg'|url }}"></a></h1>
{{ render_recipe_list(this.pagination.items) }} {{ render_recipes(this.pagination.items) }}
{{ render_pagination_all(this.pagination) }} {{ render_pagination_all(this.pagination) }}
{% endblock %} {% endblock %}

View File

@@ -1,8 +1,8 @@
{% extends "layout.html" %} {% extends "layout.html" %}
{% from "macros/recipes.html" import render_recipe_list %} {% from "macros/recipes.html" import render_recipes %}
{% block body %} {% block body %}
<h1>{{ bag('i18n+' + this.alt, 'title.latest') }}</h1> <h1>{{ bag('i18n+' + this.alt, 'title.latest') }}</h1>
<div class="latest"> <div class="latest">
{{ render_recipe_list(site.query('recipes', this.alt).order_by('-date', 'name'), limit=6) }} {{ render_recipes(site.query('/recipes', this.alt).order_by('-date', 'name').limit(6)) }}
</div> </div>
{% endblock %} {% endblock %}

View File

@@ -1,9 +1,9 @@
{% extends "layout.html" %} {% extends "layout.html" %}
{% from "macros/recipes.html" import render_recipe_list %} {% from "macros/recipes.html" import render_recipes %}
{% from "macros/pagination.html" import render_pagination_all %} {% from "macros/pagination.html" import render_pagination_all %}
{% block title %}{{ this.name }}{% endblock %} {% block title %}{{ this.name }}{% endblock %}
{% block body %} {% block body %}
<h1>Tag: {{ this.name }}</h1> <h1>Tag: {{ this.name }}</h1>
{{ render_recipe_list(this.pagination.items) }} {{ render_recipes(this.pagination.items) }}
{{ render_pagination_all(this.pagination) }} {{ render_pagination_all(this.pagination) }}
{% endblock %} {% endblock %}