@@ -1,7 +1,9 @@ | |||
/output | |||
/.env | |||
/theme/style/fonts | |||
__pycache__ | |||
*.JPG | |||
*.jpg | |||
*.yml |
@@ -0,0 +1,41 @@ | |||
<!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> |
@@ -0,0 +1,45 @@ | |||
{% 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 %} |
@@ -0,0 +1,158 @@ | |||
{% 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 %} |
@@ -0,0 +1,6 @@ | |||
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/) |
@@ -0,0 +1 @@ | |||
{"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"} |
@@ -0,0 +1,288 @@ | |||
/* 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%; | |||
} | |||
} |