release: v0.17.0 (#677)
See CHANGELOG.md, section [0.17.0] — 2026-09-23.
This commit is contained in:
@@ -95,7 +95,7 @@ Subpages, albums and sections are reordered in place; the order in the panel is
|
||||
|
||||
The **Journal Studio** — a split-screen editor with the blocks on the left and a live preview of the real page on the right, separated by a divider you can drag with mouse, keyboard or touch.
|
||||
|
||||
Blocks are added from a menu (heading, text, quote, photo, photo pair), reordered, and deleted; each carries a type chip so long entries stay scannable. Photos are inserted through the asset picker, which fills in the Immich asset UUID for you. The frontmatter — cover image, title, subtitle, author, date, draft flag, password — is edited as form fields.
|
||||
Blocks are added from a menu (heading, text, quote, facts, photo, photo pair, photo grid, album, map), reordered, and deleted; each carries a type chip so long entries stay scannable. Photos are inserted through the asset picker, which fills in the Immich asset UUID for you. A new entry can start from a template — Wedding, Hiking, Travel, Birthday, Portrait Session, Behind the Scenes, Pets, New Series — chosen in the create dialog; the blocks arrive with placeholder text and empty photo tiles to fill. The frontmatter — cover image, title, subtitle, author, date, draft flag, password — is edited as form fields.
|
||||
|
||||
Saving writes plain Markdown to `content/journal/<slug>.md`, which can equally be edited by hand.
|
||||
|
||||
|
||||
@@ -192,3 +192,11 @@ photos.example.com {
|
||||
> limits on the password endpoints. See
|
||||
> [Trusted Proxies](gallery-config.md#trusted-proxies) for the setting and a
|
||||
> matching nginx config.
|
||||
|
||||
Login cookies (admin session and gallery passwords) are marked `Secure` when the
|
||||
request arrived over HTTPS, which the app learns from `X-Forwarded-Proto`. Caddy
|
||||
and Traefik send it on their own; nginx needs the
|
||||
`proxy_set_header X-Forwarded-Proto $scheme;` line from the config linked above.
|
||||
Opening the app over plain HTTP, e.g. `http://server:7211` on a home network,
|
||||
works too: the cookies are then set without `Secure`, since a browser would
|
||||
discard them otherwise.
|
||||
|
||||
@@ -203,6 +203,7 @@ albums:
|
||||
password: 'secure-password'
|
||||
heroImage: 'asset-uuid'
|
||||
sort: filename
|
||||
download: true
|
||||
```
|
||||
|
||||
| Key | Description |
|
||||
@@ -215,6 +216,7 @@ albums:
|
||||
| `assetOrder` | Pinned asset UUIDs for `sort: manual` |
|
||||
| `grid` | **Experimental.** Grid override for this album only |
|
||||
| `coverPosition` | **Experimental.** Focal point for the cover crop |
|
||||
| `download` | Offer originals for download — see [Originals download](#originals-download) |
|
||||
|
||||
### Per-album grid (experimental)
|
||||
|
||||
@@ -244,6 +246,29 @@ albums:
|
||||
|
||||
Useful when the automatic centre crop cuts off a horizon or a face.
|
||||
|
||||
### Originals download
|
||||
|
||||
Opt in per album with `download: true`. Off everywhere by default, and opt-in
|
||||
on purpose: a public portfolio should not start handing out full-resolution
|
||||
originals because one client gallery needed to.
|
||||
|
||||
```yaml
|
||||
albums:
|
||||
- 'album-uuid':
|
||||
download: true
|
||||
```
|
||||
|
||||
Once enabled, visitors get a **Download album** link in the album header (every
|
||||
original as a ZIP), and — where [client proofing](#client-proofing) is on — a
|
||||
**Download selected (.zip)** action in the export dialog that zips just the
|
||||
favourited photos.
|
||||
|
||||
The download route re-checks the allowlist, the `download` flag, every password
|
||||
gate on a route to the album, and that each asset really belongs to that album,
|
||||
so an edited URL cannot reach anything else. The ZIP keeps the original
|
||||
filenames (deduplicated on collision) and is streamed, so album size does not
|
||||
drive memory use.
|
||||
|
||||
## Password Protection
|
||||
|
||||
A password can be set on the whole site, on a subpage, on a single album, and on
|
||||
@@ -567,6 +592,10 @@ The selection is encoded into the URL as a compact bitmask and mirrored into
|
||||
`localStorage`, so **nothing is stored server-side** and a set of picks can be
|
||||
shared, bookmarked, or sent back as a plain link.
|
||||
|
||||
When an album also opts into [originals download](#originals-download), the
|
||||
export dialog gains a **Download selected (.zip)** action, and the album header
|
||||
a **Download album** link.
|
||||
|
||||
Configured in `settings.yaml`:
|
||||
|
||||
```yaml
|
||||
|
||||
@@ -137,9 +137,101 @@ real aspect ratios rather than forced equal:
|
||||

|
||||
```
|
||||
|
||||
Three or more render as a grid — rows of up to three, each row justified like
|
||||
a pair (one shared height, widths from the real ratios, nothing cropped),
|
||||
stacked on phones:
|
||||
|
||||
```markdown
|
||||

|
||||
```
|
||||
|
||||
Photos in an entry open in the same lightbox as the rest of the site, with
|
||||
keyboard and swipe navigation.
|
||||
|
||||
### Facts
|
||||
|
||||
A `::facts` line followed by `Label: Value` lines in the same paragraph
|
||||
renders as a compact definition list — distance and elevation for a hike,
|
||||
date and venue for a wedding:
|
||||
|
||||
```markdown
|
||||
::facts
|
||||
Distance: 21 km
|
||||
Elevation: 1,240 m
|
||||
Start: 08:30
|
||||
```
|
||||
|
||||
The first colon splits label from value, so a time keeps its `:`. Values take
|
||||
the same inline markdown as text. Lines without a colon are ignored.
|
||||
|
||||
### Map
|
||||
|
||||
A `::map` line, with an optional caption after it, starts a map. The lines
|
||||
after it say what is on it — numbered pins in the order written, joined by
|
||||
a line:
|
||||
|
||||
```markdown
|
||||
::map Busan → Seoul
|
||||
Busan harbour: 35.098, 129.036
|
||||
photo: 8f1c0e2a-…
|
||||
photos: all
|
||||
Seoul: 37.566, 126.978
|
||||
line: off
|
||||
```
|
||||
|
||||
| Line | Puts on the map |
|
||||
| ----------------- | ------------------------------------------------------------------------------------------------- |
|
||||
| `Label: lat, lng` | A point with a label, exactly where you typed it. |
|
||||
| `lat, lng` | A point without a label. |
|
||||
| `photo: <uuid>` | One of the entry's photos, placed by its GPS. Several ids may follow, comma-separated. |
|
||||
| `photos: all` | Every geotagged photo in the entry, in the order they appear — skipping ids already listed above. |
|
||||
| `line: off` | No connecting line. The default draws one when there are two or more pins. |
|
||||
|
||||
A map with no lines renders nothing. `photo`, `photos` and `line` are reserved
|
||||
as labels; a coordinate pair that does not parse, or lies outside ±90 / ±180,
|
||||
is ignored (the Studio warns before you save).
|
||||
|
||||
Typed points are published as typed — they are your content. Photo pins are
|
||||
derived from EXIF, so they follow each album's `location:` setting the way
|
||||
the map page does: `hidden` and `country` add no pin, `city` snaps to the
|
||||
same 5 km grid, and where an album allows exact positions a journal pin is
|
||||
still snapped to a 1 km grid — the map page shows the mean of an album's
|
||||
photos in a city, never a single photo, and a story map should not be the
|
||||
first surface that places one photo at its doorstep. Photo pins are computed
|
||||
when the page renders; the Studio's preview shows typed points right away and
|
||||
leaves photo pins for the live page.
|
||||
|
||||
The block renders only while `map: true` is set in `settings.yaml`, typed
|
||||
points included — that setting also means "no map tiles from CartoDB for my
|
||||
visitors".
|
||||
|
||||
### Album
|
||||
|
||||
"The first twelve of the Seoul album", without picking each photo:
|
||||
|
||||
```markdown
|
||||
::album 371336b4-eb59-409c-b24e-a613f81ede5a
|
||||
count: 12
|
||||
skip: 0
|
||||
layout: grid
|
||||
caption: Twelve from Seoul
|
||||
```
|
||||
|
||||
| Line | Meaning |
|
||||
| -------------- | ------------------------------------------------------------------------------- |
|
||||
| `::album <id>` | The Immich album id — the Studio's album picker fills it in. |
|
||||
| `count: N` | How many photos. Default: the whole album. |
|
||||
| `skip: N` | Offset, so two blocks can split one album. Default 0. |
|
||||
| `layout: …` | `grid` (rows of three, default), `pairs` (rows of two) or `wide` (one per row). |
|
||||
| `caption: …` | One caption under the set. |
|
||||
|
||||
The block is expanded into ordinary photo blocks when the page renders, so
|
||||
the lightbox and everything else work as for hand-picked photos. Photos come
|
||||
in the album's order; if the gallery pins a manual `assetOrder` for that
|
||||
album, those come first. The album need not be published in `gallery.yaml` —
|
||||
an entry may already show any single photo by id, and the author's pick is
|
||||
the gate for a whole album just the same.
|
||||
|
||||
<p align="center">
|
||||
<img src="screenshots/journal-entry.png" width="98%" alt="A rendered journal entry with heading, body text, a fullbleed photo and a quote" />
|
||||
</p>
|
||||
@@ -147,7 +239,10 @@ keyboard and swipe navigation.
|
||||
|
||||
> [!TIP]
|
||||
> Writing asset UUIDs by hand is tedious. In the [Journal Studio](#journal-studio),
|
||||
> **Add Block → Photo** opens the asset picker and fills the UUID in for you.
|
||||
> **Add Block → Photo**, **2-Photo Pair** and **Photo Grid** open the asset
|
||||
> picker and fill the UUIDs in for you; **Facts** and **Map** have their own
|
||||
> small forms. New entries can also start from a template — Wedding, Hiking,
|
||||
> Travel and the others — instead of an empty editor.
|
||||
|
||||
## Drafts
|
||||
|
||||
|
||||
Reference in New Issue
Block a user