/output | /output | ||||
/.env | /.env | ||||
/theme/style/fonts | |||||
__pycache__ | __pycache__ | ||||
*.JPG | *.JPG | ||||
*.jpg | *.jpg | ||||
*.yml |
<!doctype html><!-- This is a valid HTML5 document. --> | |||||
<!-- Screen readers, SEO, extensions and so on. --> | |||||
<html lang="{% block lang %}fr{% endblock lang %}"> | |||||
<head> | |||||
<!-- Has to be within the first 1024 bytes, hence before the `title` element | |||||
See: https://www.w3.org/TR/2012/CR-html5-20121217/document-metadata.html#charset --> | |||||
<meta charset="utf-8"> | |||||
<!-- Why no `X-UA-Compatible` meta: https://stackoverflow.com/a/6771584 --> | |||||
<!-- The viewport meta is quite crowded and we are responsible for that. | |||||
See: https://codepen.io/tigt/post/meta-viewport-for-2015 --> | |||||
<meta name="viewport" content="width=device-width,initial-scale=1"> | |||||
<!-- Required to make a valid HTML5 document. --> | |||||
<title>{% block title %}{% endblock %} — David Larlet</title> | |||||
<!-- Source : https://favicon.io/emoji-favicons/camera --> | |||||
<!-- The emoji graphics are from the open source project Twemoji. | |||||
The graphics are copyright 2020 Twitter, Inc and other contributors. | |||||
The graphics are licensed under CC-BY 4.0. --> | |||||
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png"> | |||||
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png"> | |||||
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png"> | |||||
<link rel="manifest" href="/site.webmanifest"> | |||||
<link rel="stylesheet" href="style/main.css"> | |||||
{% block extra_head %}{% endblock %} | |||||
</head> | |||||
<body> | |||||
<main> | |||||
<div class="container"> | |||||
{% block container %}{% endblock %} | |||||
</div> | |||||
</main> | |||||
<footer> | |||||
<hr> | |||||
<p class="u-center"> | |||||
© | |||||
<a href="https://larlet.fr/david/" title="Site principal">David Larlet</a> | |||||
- | |||||
<a href="mailto:david%40larlet.fr" title="Envoyer un courriel">Demandez pour une réutilisation</a>, ça me permettra de vous fournir une meilleure qualité 🤗. | |||||
</p> | |||||
</footer> | |||||
{% block extra_bottom %}{% endblock %} | |||||
</body> |
{% extends "base.html.j2" %} | |||||
{% block title %}Photos & vidéos{% endblock %} | |||||
{% block extra_head %} | |||||
<!-- CanIHazMoreComplexityPlease? https://htmlhead.dev/ --> | |||||
<meta | |||||
name="twitter:image" property="og:image" itemprop="image" | |||||
content="https://media.larlet.fr/2021--paysages/jpg/15_660x440.jpg" | |||||
> | |||||
{% endblock %} | |||||
{% block container %} | |||||
<div class="galleries"> | |||||
{% for gallery in galleries -%} | |||||
{% if not gallery.private %} | |||||
<div class="gallery-cover"> | |||||
<a href="{{ gallery.cover_photo.page_url }}"> | |||||
<picture> | |||||
<source | |||||
srcset=" | |||||
{%- for size in sizes %} | |||||
{{ gallery.cover_photo.gallery_slug }}/webp/{{ gallery.cover_photo.name }}_{{ size.0 }}x{{ size.1 }}.webp {{ size.0 }}w{% if not loop.last%},{% endif %} | |||||
{%- endfor -%} | |||||
" | |||||
sizes="min((100vw - 2rem), 330px)" | |||||
type="image/webp"> | |||||
<img | |||||
src="{{ gallery.cover_photo.gallery_slug }}/jpg/{{ gallery.cover_photo.name }}_{{ sizes.0.0 }}x{{ sizes.0.1 }}.jpg" | |||||
width="{{ gallery.cover_photo.width }}" height="{{ gallery.cover_photo.height }}" | |||||
srcset=" | |||||
{%- for size in sizes %} | |||||
{{ gallery.cover_photo.gallery_slug }}/jpg/{{ gallery.cover_photo.name }}_{{ size.0 }}x{{ size.1 }}.jpg {{ size.0 }}w{% if not loop.last%},{% endif %} | |||||
{%- endfor -%} | |||||
" | |||||
sizes="min((100vw - 2rem), 330px)" | |||||
alt="TODO" loading="lazy" decoding="async"> | |||||
<figcaption>{{ gallery.name }}</figcaption> | |||||
</picture> | |||||
</a> | |||||
</div> | |||||
{% endif %} | |||||
{% endfor %} | |||||
</div> | |||||
{% endblock %} |
{% extends "base.html.j2" %} | |||||
{% block title %}{{ gallery.name }}{% endblock %} | |||||
{% block extra_head %} | |||||
<!-- CanIHazMoreComplexityPlease? https://htmlhead.dev/ --> | |||||
<meta | |||||
name="twitter:image" property="og:image" itemprop="image" | |||||
content="https://media.larlet.fr/{{ photo.gallery_slug }}/jpg/{{ photo.name }}_{{ sizes.0.0 }}x{{ sizes.0.1 }}.jpg" | |||||
> | |||||
{% endblock %} | |||||
{% block container %} | |||||
<div class="hero u-center"> | |||||
<picture> | |||||
<source | |||||
srcset=" | |||||
{%- for size in sizes %} | |||||
{{ photo.gallery_slug }}/webp/{{ photo.name }}_{{ size.0 }}x{{ size.1 }}.webp {{ size.0 }}w{% if not loop.last%},{% endif %} | |||||
{%- endfor -%} | |||||
" | |||||
sizes="min(100vw, calc(100vh * {{ photo.width }} / {{ photo.height }}))" | |||||
type="image/webp"> | |||||
<img | |||||
src="{{ photo.gallery_slug }}/jpg/{{ photo.name }}_{{ sizes.0.0 }}x{{ sizes.0.1 }}.jpg" | |||||
width="{{ photo.width }}" height="{{ photo.height }}" | |||||
srcset=" | |||||
{%- for size in sizes %} | |||||
{{ photo.gallery_slug }}/jpg/{{ photo.name }}_{{ size.0 }}x{{ size.1 }}.jpg {{ size.0 }}w{% if not loop.last%},{% endif %} | |||||
{%- endfor -%} | |||||
" | |||||
sizes="min(100vw, calc(100vh * {{ photo.width }} / {{ photo.height }}))" | |||||
alt="TODO"> | |||||
</picture> | |||||
</div> | |||||
<h1>{{ gallery.name }}{% if gallery.private %} (🔒 privé){% endif %}</h1> | |||||
<nav> | |||||
<p class="u-center"> | |||||
{% if previous %} | |||||
<a href="{{ previous.page_url }}" | |||||
title="Photo précédente, vous pouvez utiliser la flèche du clavier ←" | |||||
>← Photo précédente</a> | |||||
• | |||||
{% endif %} | |||||
<a href="/" | |||||
title="Retour à l’accueil, vous pouvez utiliser la flèche du clavier ↑" | |||||
>↑ Retour aux albums{% if gallery.private %} publics{% endif %}</a> | |||||
{% if next %} | |||||
• | |||||
<a href="{{ next.page_url }}" | |||||
title="Photo suivante, vous pouvez utiliser la flèche du clavier →" | |||||
>Photo suivante →</a> | |||||
{% endif %} | |||||
</p> | |||||
</nav> | |||||
{# TODO: less manual! #} | |||||
{% if gallery.type == "video" %} | |||||
<div class="u-center"> | |||||
<div class="iframe-container"><iframe src="https://player.vimeo.com/video/580086949?h=0833bc929c" frameborder="0" allow="autoplay; fullscreen; picture-in-picture" allowfullscreen></iframe></div> | |||||
<p><a href="https://vimeo.com/580086949/0833bc929c">Évasion (lire sur Vimeo)</a></p> | |||||
<hr> | |||||
<div class="iframe-container"><iframe src="https://player.vimeo.com/video/540447287?h=323e810be3" frameborder="0" allow="autoplay; fullscreen; picture-in-picture" allowfullscreen></iframe></div> | |||||
<p><a href="https://vimeo.com/540447287/323e810be3">Contemplation (lire sur Vimeo)</a></p> | |||||
<hr> | |||||
<div class="iframe-container"><iframe src="https://player.vimeo.com/video/516515235?h=45826baa92" frameborder="0" allow="autoplay; fullscreen; picture-in-picture" allowfullscreen></iframe></div> | |||||
<p><a href="https://vimeo.com/516515235/45826baa92">Précipitation (lire sur Vimeo)</a></p> | |||||
<hr> | |||||
<div class="iframe-container"><iframe src="https://player.vimeo.com/video/492686199?h=31ac11260c" frameborder="0" allow="autoplay; fullscreen; picture-in-picture" allowfullscreen></iframe></div> | |||||
<p><a href="https://vimeo.com/492686199/31ac11260c">Arrakice (lire sur Vimeo)</a></p> | |||||
<hr> | |||||
<div class="iframe-container"><iframe src="https://player.vimeo.com/video/473661570?h=46af2e921e" frameborder="0" allow="autoplay; fullscreen; picture-in-picture" allowfullscreen></iframe></div> | |||||
<p><a href="https://vimeo.com/473661570/46af2e921e">Chaos (lire sur Vimeo)</a></p> | |||||
</div> | |||||
{% endif %} | |||||
<div class="gallery"> | |||||
{% for gallery_photo in gallery.photos %} | |||||
{% if not gallery_photo.url == photo.url %} | |||||
<div class="photo{% if gallery_photo.narrow %} narrow{% endif %}{% if gallery_photo.wide %} wide{% endif %}"> | |||||
<a href="{{ gallery_photo.page_url }}"> | |||||
<picture> | |||||
<source | |||||
srcset=" | |||||
{%- for size in sizes %} | |||||
{{ gallery_photo.gallery_slug }}/webp/{{ gallery_photo.name }}_{{ size.0 }}x{{ size.1 }}.webp {{ size.0 }}w{% if not loop.last%},{% endif %} | |||||
{%- endfor -%} | |||||
" | |||||
sizes="{% if gallery_photo.narrow %}150px{% else %}310px{% endif %}" | |||||
type="image/webp"> | |||||
<img | |||||
src="{{ gallery_photo.gallery_slug }}/jpg/{{ gallery_photo.name }}_{{ sizes.0.0 }}x{{ sizes.0.1 }}.jpg" | |||||
width="{{ gallery_photo.width }}" height="{{ gallery_photo.height }}" | |||||
srcset=" | |||||
{%- for size in sizes %} | |||||
{{ gallery_photo.gallery_slug }}/jpg/{{ gallery_photo.name }}_{{ size.0 }}x{{ size.1 }}.jpg {{ size.0 }}w{% if not loop.last%},{% endif %} | |||||
{%- endfor -%} | |||||
" | |||||
sizes="{% if gallery_photo.narrow %}150px{% else %}310px{% endif %}" | |||||
alt="TODO" loading="lazy" decoding="async"> | |||||
</picture> | |||||
</a> | |||||
</div> | |||||
{% endif %} | |||||
{% endfor %} | |||||
</div> | |||||
<nav> | |||||
<p class="u-center" | |||||
data-controller="navigation" | |||||
data-action="keydown@window->navigation#navigate" | |||||
> | |||||
{% if previous %} | |||||
<a href="{{ previous.page_url }}" | |||||
title="Photo précédente, vous pouvez utiliser la flèche du clavier ←" | |||||
data-navigation-target="previous" | |||||
>← Photo précédente</a> | |||||
• | |||||
{% endif %} | |||||
<a href="/" | |||||
title="Retour à l’accueil, vous pouvez utiliser la flèche du clavier ↑" | |||||
data-navigation-target="up" | |||||
>↑ Retour aux albums{% if gallery.private %} publics{% endif %}</a> | |||||
{% if next %} | |||||
• | |||||
<a href="{{ next.page_url }}" | |||||
title="Photo suivante, vous pouvez utiliser la flèche du clavier →" | |||||
data-navigation-target="next" | |||||
>Photo suivante →</a> | |||||
{% endif %} | |||||
</p> | |||||
</nav> | |||||
{% endblock %} | |||||
{% block extra_bottom %} | |||||
<script type="module"> | |||||
import { Application, Controller } from "/scripts/stimulus-3.0.1.js" | |||||
window.Stimulus = Application.start() | |||||
// window.Stimulus.debug = true | |||||
Stimulus.register("navigation", class extends Controller { | |||||
static targets = [ "previous", "next", "up" ] | |||||
navigate(event) { | |||||
const key = event.key | |||||
if (key === "ArrowLeft" && this.hasPreviousTarget) { | |||||
this.previousTarget.click() | |||||
} | |||||
if (key === "ArrowRight" && this.hasNextTarget) { | |||||
this.nextTarget.click() | |||||
} | |||||
if (key === "ArrowUp" && this.hasUpTarget) { | |||||
this.upTarget.click() | |||||
} | |||||
} | |||||
}) | |||||
</script> | |||||
{% endblock %} |
This favicon was generated using the following graphics from Twitter Twemoji: | |||||
- Graphics Title: 1f4f7.svg | |||||
- Graphics Author: Copyright 2020 Twitter, Inc and other contributors (https://github.com/twitter/twemoji) | |||||
- Graphics Source: https://github.com/twitter/twemoji/blob/master/assets/svg/1f4f7.svg | |||||
- Graphics License: CC-BY 4.0 (https://creativecommons.org/licenses/by/4.0/) |
{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#f7f7f7","background_color":"#f7f7f7","display":"standalone"} |
/* Section polices */ | |||||
/* Fonts definition, a different font is in use between light and dark mode | |||||
in order to improve the readability of the text. */ | |||||
@font-face { | |||||
font-family: 'triplicate_t4p'; | |||||
src: url('fonts/triplicate_t4_poly_regular.woff2') format('woff2'), | |||||
url('fonts/triplicate_t4_poly_regular.woff') format('woff'); | |||||
font-weight: normal; | |||||
font-style: normal; | |||||
font-display: swap; | |||||
} | |||||
@font-face { | |||||
font-family: 'triplicate_t4p'; | |||||
src: url('fonts/triplicate_t4_poly_bold.woff2') format('woff2'), | |||||
url('fonts/triplicate_t4_poly_bold.woff') format('woff'); | |||||
font-weight: bold; | |||||
font-style: normal; | |||||
font-display: swap; | |||||
} | |||||
@font-face { | |||||
font-family: 'triplicate_t4p'; | |||||
src: url('fonts/triplicate_t4_poly_italic.woff2') format('woff2'), | |||||
url('fonts/triplicate_t4_poly_italic.woff') format('woff'); | |||||
font-weight: normal; | |||||
font-style: italic; | |||||
font-display: swap; | |||||
} | |||||
@font-face { | |||||
font-family: 'triplicate_t3'; | |||||
src: url('fonts/triplicate_t3_regular.woff2') format('woff2'), | |||||
url('fonts/triplicate_t3_regular.woff') format('woff'); | |||||
font-weight: normal; | |||||
font-style: normal; | |||||
font-display: swap; | |||||
} | |||||
@font-face { | |||||
font-family: 'triplicate_t3'; | |||||
src: url('fonts/triplicate_t3_bold.woff2') format('woff2'), | |||||
url('fonts/triplicate_t3_bold.woff') format('woff'); | |||||
font-weight: bold; | |||||
font-style: normal; | |||||
font-display: swap; | |||||
} | |||||
@font-face { | |||||
font-family: 'triplicate_t3'; | |||||
src: url('fonts/triplicate_t3_italic.woff2') format('woff2'), | |||||
url('fonts/triplicate_t3_italic.woff') format('woff'); | |||||
font-weight: normal; | |||||
font-style: italic; | |||||
font-display: swap; | |||||
} | |||||
* { | |||||
box-sizing: border-box; | |||||
} | |||||
:root:not(.forced-dark), | |||||
.forced-light { | |||||
/* This tells the browser which color themes my app supports | |||||
See https://web.dev/prefers-color-scheme/#stylesheet-architecture */ | |||||
color-scheme: light dark; | |||||
/* For a smooth transition between light/dark modes | |||||
See https://web.dev/prefers-color-scheme/#smooth-transitions-between-modes */ | |||||
--duration: 0.5s; | |||||
--timing: ease; | |||||
--font-family: 'triplicate_t4p', Courier, Menlo, Monaco, 'DejaVu Sans Mono', Consolas, monospace; | |||||
--background-color: #f7f7f7; | |||||
--text-color: #07486c; | |||||
--remarkdown-color: SteelBlue; | |||||
--link-color: RoyalBlue; | |||||
--link-visited-color: RebeccaPurple; | |||||
--link-hover-color: var(--background-color); | |||||
--link-hover-background-color: var(--link-color); | |||||
--image-filter: none; | |||||
--target-after-color: #07486c; | |||||
--mark-background: LightGoldenRodYellow; | |||||
} | |||||
@media (prefers-color-scheme: dark) { | |||||
:root:not(.forced-light), | |||||
.forced-dark { | |||||
--font-family: 'triplicate_t3', 'Courier New', Menlo, Monaco, 'DejaVu Sans Mono', Consolas, monospace; | |||||
--background-color: #272727; | |||||
--text-color: Linen; | |||||
--remarkdown-color: Orange; | |||||
--link-color: #ffff2b; | |||||
--link-visited-color: Khaki; | |||||
--link-hover-color: var(--background-color); | |||||
--link-hover-background-color: var(--link-visited-color); | |||||
--image-filter: grayscale(.5) brightness(.8) contrast(1.2); | |||||
--target-after-color: DarkOrange; | |||||
--mark-background: Orange; | |||||
} | |||||
} | |||||
html { | |||||
/* Applying it to the html element will provide smooth scrolling to anchors | |||||
https://developer.mozilla.org/en-US/docs/Web/CSS/scroll-behavior */ | |||||
scroll-behavior: smooth; | |||||
/* Only supported by Firefox, how fun? */ | |||||
scrollbar-color: var(--background-color) var(--target-after-color); | |||||
} | |||||
/* General stuff. */ | |||||
body { | |||||
margin: 0 auto; | |||||
padding: 0 .5rem; | |||||
font-family: var(--font-family); | |||||
background-color: var(--background-color); | |||||
color: var(--text-color); | |||||
transition: | |||||
color var(--duration) var(--timing), | |||||
background-color var(--duration) var(--timing); | |||||
-moz-osx-font-smoothing: grayscale; | |||||
-webkit-font-smoothing: antialiased; | |||||
} | |||||
a { | |||||
color: var(--text-color); | |||||
} | |||||
h1 { | |||||
margin-top: 0; | |||||
text-align: center; | |||||
word-wrap: break-word; | |||||
margin-bottom: 1.75rem; | |||||
font-size: 2rem; | |||||
line-height: 2.5rem; | |||||
} | |||||
img { | |||||
max-width: 100%; | |||||
max-height: 100%; | |||||
max-inline-size: 100%; | |||||
block-size: auto; | |||||
} | |||||
figcaption { | |||||
text-align: center; | |||||
} | |||||
hr { | |||||
height: 1.5em; | |||||
line-height: 1.5em; | |||||
margin: 1.5em 0 1.5em; | |||||
border: none; | |||||
color: inherit; | |||||
text-align: center; | |||||
} | |||||
hr::before { | |||||
content: "* * * *"; | |||||
} | |||||
.container { | |||||
max-width: 70rem; | |||||
margin-left: auto; | |||||
margin-right: auto; | |||||
padding-left: .5rem; | |||||
padding-right: .5rem; | |||||
} | |||||
.galleries { | |||||
display: flex; | |||||
flex-wrap: wrap; | |||||
justify-content: space-evenly; | |||||
margin-top: 1rem; | |||||
} | |||||
.gallery-cover { | |||||
width: 330px; | |||||
max-width: 100%; | |||||
margin-bottom: 2rem; | |||||
margin-right: .5rem; | |||||
} | |||||
.gallery-cover img { | |||||
border-radius: 0.25rem; | |||||
} | |||||
.photo { | |||||
width: 20rem; | |||||
max-width: 100%; | |||||
margin-right: .5rem; | |||||
margin-bottom: 2rem; | |||||
} | |||||
.hero img { | |||||
max-height: 100vh; | |||||
width: auto; | |||||
} | |||||
.u-center { | |||||
text-align: center; | |||||
} | |||||
/* See https://www.benmarshall.me/responsive-iframes/ */ | |||||
.iframe-container { | |||||
overflow: hidden; | |||||
/* 16:9 aspect ratio */ | |||||
padding-top: 56.25%; | |||||
position: relative; | |||||
} | |||||
.iframe-container iframe { | |||||
border: 0; | |||||
height: 100%; | |||||
left: 0; | |||||
position: absolute; | |||||
top: 0; | |||||
width: 100%; | |||||
} | |||||
@media only screen and (max-width: 600px) { | |||||
nav a { | |||||
display: block; | |||||
} | |||||
} | |||||
/* See https://sylvaindurand.org/masonry-photo-grid-in-pure-css/ */ | |||||
@media only screen and (min-width: 600px) { | |||||
.gallery { | |||||
display: flex; | |||||
width: 100%; | |||||
flex-flow: row wrap; | |||||
margin-left: -4px; | |||||
} | |||||
.gallery div { | |||||
overflow: hidden; | |||||
margin: 0 0 8px 8px; | |||||
flex: auto; | |||||
height: 250px; | |||||
min-width: 150px; | |||||
} | |||||
.gallery div:nth-child(8n+1) { | |||||
width: 310px; | |||||
} | |||||
.gallery div:nth-child(8n+2) { | |||||
width: 270px; | |||||
} | |||||
.gallery div:nth-child(8n+3) { | |||||
width: 260px; | |||||
} | |||||
.gallery div:nth-child(8n+4) { | |||||
width: 310px; | |||||
} | |||||
.gallery div:nth-child(8n+5) { | |||||
width: 240px; | |||||
} | |||||
.gallery div:nth-child(8n+6) { | |||||
width: 190px; | |||||
} | |||||
.gallery div:nth-child(8n+7) { | |||||
width: 210px; | |||||
} | |||||
.gallery div:nth-child(8n+8) { | |||||
width: 170px; | |||||
} | |||||
.gallery div.wide { | |||||
width: 650px; | |||||
} | |||||
.gallery div.tall { | |||||
width: 650px; | |||||
height: 450px; | |||||
} | |||||
.gallery div.narrow { | |||||
width: 120px; | |||||
} | |||||
.gallery img { | |||||
object-fit: cover; | |||||
width: 100%; | |||||
height: 100%; | |||||
} | |||||
} |