Compare commits

..

14 Commits

Author SHA1 Message Date
m038 9f798daaa3 Add remote-deploy target: pull user repo and install plugins 2026-06-13 21:11:00 +02:00
m038 c7877f3ce0 Pin Grav version, install plugins as part of remote-install 2026-06-13 21:08:50 +02:00
m038 bc3df5c24b Split SERVER into REMOTE_USER/HOST/HOME, rename USER_REPO to REPO 2026-06-13 21:06:48 +02:00
m038 596b94519f Remove chown from install script 2026-06-13 21:05:08 +02:00
m038 766b7edcdd Derive WEBROOT_USER from WEBROOT, remove from env 2026-06-13 21:03:43 +02:00
m038 ef8c0e1a32 Add WEBROOT_USER for chown, pass to remote-install 2026-06-13 21:02:33 +02:00
m038 2b9a926338 Pass Gitea credentials to remote-install, clean up after clone 2026-06-13 20:53:58 +02:00
m038 643b1ccc61 Fix env var forwarding in remote-install, add remote-clean target 2026-06-13 20:51:53 +02:00
m038 a815593f52 Rename server-* targets to remote-*, update README 2026-06-13 20:30:12 +02:00
m038 8154628101 Rename deploy/pull-content to content-push/content-pull 2026-06-13 20:29:28 +02:00
m038 59f8795670 Update README to reflect VPS and git subtree deployment 2026-06-13 19:21:22 +02:00
m038 5bbaa8bb8b Add server make targets, install script, and .env setup
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-13 19:18:22 +02:00
m038 e0444fa40c Add deploy and pull-content Makefile targets for user repo
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-13 18:52:39 +02:00
m038 103e344408 Rename image fields and implement werk-in-detail gallery
- Rename image_main/image_secondary/image_logo/image_portrait to
  portret/extra_1/logo/extra_2 in pages, blueprints, and templates
- Add extra_2 image slot to home and CV (hidden on mobile)
- Wire werk-in-detail to real child pages instead of picsum placeholders
- Remove glightbox CDN dependency from werk-in-detail
- Add album blueprint, template, and grote-objecten album page

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-13 18:49:29 +02:00
30 changed files with 247 additions and 52 deletions
+9
View File
@@ -0,0 +1,9 @@
REMOTE_USER=root
REMOTE_HOST=example.com
REMOTE_HOME=/home/example.com
REPO=https://gitea.example.com/user/natascha-rieter.nl-user.git
GRAV_VERSION=1.7.49.5
GITEA_HOST=gitea.example.com
GITEA_USER=natascha-deploy
GITEA_TOKEN=your-token-here
+3
View File
@@ -1,3 +1,6 @@
# Environment
.env
# Grav CMS
user/accounts/
user/data/
+30
View File
@@ -1,3 +1,10 @@
-include .env
export
SSH := $(REMOTE_USER)@$(REMOTE_HOST)
WEBROOT := $(REMOTE_HOME)/public_html
# Local dev
start:
docker compose up -d
@@ -8,3 +15,26 @@ setup: start install-plugins
install-plugins:
docker exec natascha_grav php /app/www/public/bin/gpm install $(shell cat plugins.txt | tr '\n' ' ') -y
# Content (user repo)
content-push:
git subtree push --prefix=user user-deploy main
content-pull:
git subtree pull --prefix=user user-deploy main --squash
# Remote
remote-install:
ssh $(SSH) "WEBROOT=$(WEBROOT) REPO=$(REPO) GRAV_VERSION=$(GRAV_VERSION) PLUGINS='$(shell cat plugins.txt | tr '\n' ' ')' GITEA_HOST=$(GITEA_HOST) GITEA_USER=$(GITEA_USER) GITEA_TOKEN=$(GITEA_TOKEN) bash -s" < scripts/server-install.sh
remote-deploy:
ssh $(SSH) "cd $(WEBROOT)/user && git pull && cd $(WEBROOT) && php bin/gpm install $(shell cat plugins.txt | tr '\n' ' ') -y"
remote-install-plugins:
ssh $(SSH) "cd $(WEBROOT) && php bin/gpm install $(shell cat plugins.txt | tr '\n' ' ') -y"
remote-upgrade-grav:
ssh $(SSH) "cd $(WEBROOT) && php bin/grav upgrade"
remote-clean:
ssh $(SSH) "cd $(WEBROOT) && php bin/grav clearcache"
+58 -13
View File
@@ -13,20 +13,31 @@ This starts the container and installs all plugins listed in `plugins.txt` via G
Other commands:
```
make start # start the container
make stop # stop the container
make install-plugins # (re)install plugins from plugins.txt
make start # start the container
make stop # stop the container
make install-plugins # (re)install plugins from plugins.txt
```
Site runs at http://localhost:8080.
## Repository structure
This project uses two git repositories:
| Repo | Contents | Purpose |
|------|----------|---------|
| `natascha-rieter-nl` (this repo) | Docker setup, Makefile, scripts | Local dev and server management |
| `natascha-rieter.nl-user` | Contents of `user/` | Deployed to production, synced with Git Sync |
The `user/` folder in this repo is linked to the user repo via git subtree.
### What goes where
| Path | Description | In git |
|------|-------------|--------|
| `user/config/` | Site and plugin configuration | yes |
| `user/pages/` | Page content | yes (see deployment note) |
| `user/themes/natascha/` | Custom theme | yes |
| `user/config/` | Site and plugin configuration | user repo |
| `user/pages/` | Page content | user repo |
| `user/themes/natascha/` | Custom theme | user repo |
| `user/plugins/` | Plugins (see plugins.txt) | no |
| `user/accounts/` | Admin credentials | no |
| `user/data/` | Runtime data | no |
@@ -34,16 +45,50 @@ Site runs at http://localhost:8080.
## Deployment
Production is shared hosting. Deploy via FTP.
Production runs on a VPS with Apache. The user repo is cloned into the Grav `user/` folder on the server and kept in sync via the Git Sync plugin.
### Initial deploy
Upload the full `user/` directory (including locally installed plugins from `user/plugins/`).
### Remote config
### Subsequent deploys
**Only upload** `user/themes/` and `user/config/`. Do **not** overwrite `user/pages/` — content is managed online by editors after go-live and a deploy would overwrite their changes.
Copy `.env.example` to `.env` and fill in your values (gitignored):
> **Future improvement**: once the site is live and content is stable, move `user/pages/` to `.gitignore` entirely (Option 1). Content backups should be handled separately (e.g. a server-side backup solution), not via git.
```
SERVER=user@example.com
WEBROOT=/path/to/public_html
USER_REPO=ssh://git@gitea.example.com/user/repo.git
```
### First-time install
```
make remote-install
```
This SSHes into the server and runs `scripts/server-install.sh`, which installs Grav and clones the user repo.
### Deploying content changes
```
make content-push # push local user/ changes to the user repo on Gitea
make content-pull # pull editor's content changes back locally
```
After `make content-push`, trigger a deploy on the server:
```
make remote-deploy # pull latest user repo changes and install plugins on server
```
### Remote maintenance
```
make remote-install-plugins # install/update plugins from plugins.txt on server
make remote-upgrade-grav # upgrade Grav core on server
make remote-clean # clear Grav cache on server
```
## Plugins
Plugins are not committed to git. The full list is in `plugins.txt`. To install locally, run `make install-plugins`. On the production server, plugins must be uploaded manually (no CLI access on shared hosting).
Plugins are not committed to git. The full list is in `plugins.txt`.
- Locally: `make install-plugins`
- Remotely: `make remote-install-plugins`
+33
View File
@@ -0,0 +1,33 @@
#!/bin/bash
set -e
: "${WEBROOT:?WEBROOT is not set}"
: "${REPO:?REPO is not set}"
: "${GRAV_VERSION:?GRAV_VERSION is not set}"
: "${PLUGINS:?PLUGINS is not set}"
: "${GITEA_HOST:?GITEA_HOST is not set}"
: "${GITEA_USER:?GITEA_USER is not set}"
: "${GITEA_TOKEN:?GITEA_TOKEN is not set}"
echo "==> Downloading Grav $GRAV_VERSION"
cd "$WEBROOT"
wget -q "https://getgrav.org/download/core/grav-admin/$GRAV_VERSION" -O grav-admin.zip
unzip -q grav-admin.zip
mv grav-admin/* grav-admin/.htaccess .
rm -rf grav-admin grav-admin.zip
echo "==> Cloning user repo"
printf 'machine %s\nlogin %s\npassword %s\n' "$GITEA_HOST" "$GITEA_USER" "$GITEA_TOKEN" > ~/.netrc
chmod 600 ~/.netrc
rm -rf user
git clone "$REPO" user
rm ~/.netrc
echo "==> Installing plugins"
php bin/gpm install $PLUGINS -y
echo "==> Setting permissions"
find "$WEBROOT" -type f -exec chmod 664 {} \;
find "$WEBROOT" -type d -exec chmod 775 {} \;
echo "==> Done. Visit your domain to complete setup."
+4 -3
View File
@@ -4,9 +4,10 @@ menu: Home
published: true
sitemap:
lastmod: '19-04-2026 00:00'
image_main: portret-2.jpg
image_secondary: portret-1.jpg
image_logo: logo-blauw.png
portret: portret-2.jpg
extra_1: portret-1.jpg
logo: logo-blauw.png
extra_2: ''
---
I create small sculptures, reliefs, clay paintings, modelled figures and wheel-thrown work. My work is emotional and poetic with a monumental character. The outdoor objects are frost-resistant. In my clay paintings I combine ceramic and painting techniques. Working with clay is for me the same as writing a poem. In recent years I have been almost exclusively occupied with monumental commissions. I work on commission and give courses and workshops.
+4 -3
View File
@@ -4,9 +4,10 @@ menu: Home
published: true
sitemap:
lastmod: '18-04-2026 21:48'
image_secondary: portret-1.jpg
image_main: portret-2.jpg
image_logo: logo-blauw.png
portret: portret-2.jpg
extra_1: portret-1.jpg
logo: logo-blauw.png
extra_2: ''
---
Ik maak kleinplastieken, reliëfs, kleischilderijen, geboetseerde beelden en draaiwerk. Mijn werk is emotioneel en poëtisch met een monumentaal karakter. De objecten voor buiten zijn winterhard. In mijn kleischilderijen worden de keramische- en schilderstechniek met elkaar gecombineerd. Het werken met klei is voor mij het zelfde als het schrijven van een gedicht. De laatste jaren ben ik bijna uitsluitend met monumentale opdrachten bezig geweest. Ik werk in opdracht en geef cursussen en workshops.
+4 -2
View File
@@ -1,8 +1,10 @@
---
title: Natascha Rieter Curriculum Vitae
menu: CV
image_portrait: portret-1.jpg
image_logo: logo-blauw.png
portret: portret-1.jpg
extra_1: ''
logo: logo-blauw.png
extra_2: ''
---
Natascha Rieter, born in Roermond (1948), has lived since 1988 in Margraten, in the hamlet of Groot Welsden, where she and her husband Siegfried Gorinskat (also a ceramist, who passed away in 2006) established their studios in a typical half-timbered farmhouse. Both artists enjoy great renown in the art world for their ceramic works. In 1989 they opened Ceramic Gallery "Groot Welsden" — with great success. Natascha Rieter is an emotional and poetic artist for whom ceramics is the mirror of the soul.
+4 -2
View File
@@ -1,8 +1,10 @@
---
title: Natascha Rieter Curriculum Vitae
menu: CV
image_portrait: portret-1.jpg
image_logo: logo-blauw.png
portret: portret-1.jpg
extra_1: ''
logo: logo-blauw.png
extra_2: ''
---
Natascha Rieter, geboren te Roermond (1948), woont sinds 1988 te Margraten, in het gehucht Groot Welsden, waar zij met haar man Siegfried Gorinskat (ook keramist) (2006 gestorven) in een typische vakwerkboerderij hun ateliers hebben gevestigd. Beide kunstenaars genieten vanwege hun keramische werken grote bekendheid in de kunstwereld. In 1989 openden zij Keramiek Galerie "Groot Welsden" en niet zonder succes. Natascha Rieter is een emotioneel en poëtisch kunstenaar voor wie keramiek de spiegel van de ziel is.
Binary file not shown.

After

Width:  |  Height:  |  Size: 149 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 159 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

@@ -0,0 +1,7 @@
---
title: 'Large objects'
sitemap:
lastmod: '13-06-2026 13:29'
---
A series of larges objects made in the last years
@@ -0,0 +1,8 @@
---
title: 'Grote objecten'
sitemap:
lastmod: '13-06-2026 13:29'
media_order: '10298359_1112080642156692_2004541195504715933_o_1112080642156692.jpg,1936306_1105443762820380_8216889586053322199_n_1105443762820380.jpg,10683502_1112079375490152_4488529684021326036_o_1112079375490152.jpg,11053920_1112081192156637_6689568670232240087_o_1112081192156637.jpg,12029743_1107926249238798_5277465818662466467_o_1107926249238798.jpg,12418905_1112080445490045_6622839067204183466_o_1112080445490045.jpg,12418905_1112080975489992_3344234153253759058_o_1112080975489992.jpg,12418926_1112081552156601_1127226366914273536_o_1112081552156601.jpg,12493616_1112080162156740_7951360208797715360_o_1112080162156740.jpg,12495917_1112079482156808_5584179686913736172_o_1112079482156808.jpg,12496352_1112081338823289_3609436053778783843_o_1112081338823289.jpg,12593704_1112080822156674_1315022773915505238_o_1112080822156674.jpg'
---
Een serie van grote objecte gemaakt in de afgelopen jaren
@@ -0,0 +1,4 @@
title: Album
'@extends':
type: default
context: blueprints://pages
+12 -4
View File
@@ -13,11 +13,19 @@ form:
type: tab
title: Inhoud
fields:
header.image_portrait:
header.portret:
type: pagemediaselect
label: 'Portretfoto'
label: 'Portret (zichtbaar op mobiel)'
preview_images: true
header.image_logo:
header.extra_1:
type: pagemediaselect
label: 'Logo'
label: 'Extra foto (verborgen op mobiel)'
preview_images: true
header.logo:
type: pagemediaselect
label: 'Logo (zichtbaar op mobiel)'
preview_images: true
header.extra_2:
type: pagemediaselect
label: 'Extra foto rechts (verborgen op mobiel)'
preview_images: true
+10 -6
View File
@@ -13,15 +13,19 @@ form:
type: tab
title: Inhoud
fields:
header.image_main:
header.portret:
type: pagemediaselect
label: 'Portretfoto (hoofdafbeelding)'
label: 'Portret (zichtbaar op mobiel)'
preview_images: true
header.image_secondary:
header.extra_1:
type: pagemediaselect
label: 'Portretfoto (tweede afbeelding, zichtbaar vanaf tablet)'
label: 'Extra foto (verborgen op mobiel)'
preview_images: true
header.image_logo:
header.logo:
type: pagemediaselect
label: 'Logo'
label: 'Logo (zichtbaar op mobiel)'
preview_images: true
header.extra_2:
type: pagemediaselect
label: 'Extra foto rechts (verborgen op mobiel)'
preview_images: true
@@ -0,0 +1,26 @@
{% extends 'partials/base.html.twig' %}
{% block extra_css %}
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/glightbox/dist/css/glightbox.min.css">
{% endblock %}
{% block extra_js %}
<script src="https://cdn.jsdelivr.net/npm/glightbox/dist/js/glightbox.min.js" defer></script>
{% endblock %}
{% block content %}
<div class="row mb-3">
<div class="col-12 col-lg-8 offset-lg-2">
<h1 class="funky-font main-header text-center">{{ page.title }}</h1>
{{ content|raw }}
</div>
</div>
<div class="row g-3">
{% for name, img in page.media.images %}
<div class="col-6 col-md-4 col-lg-3">
<a href="{{ img.url }}" class="glightbox gallery-item" data-gallery="{{ page.slug }}">
<div class="gallery-thumb">
<img src="{{ img.url }}" loading="lazy" alt="{{ page.title }}">
</div>
</a>
</div>
{% endfor %}
</div>
{% endblock %}
+10 -4
View File
@@ -2,15 +2,21 @@
{% set page_class = 'row p-3' %}
{% block content %}
<div class="col-12 col-md-3 p-3">
{% set img_portrait = page.header.image_portrait ? page.media[page.header.image_portrait].url : url('theme://images/portret-1.jpg') %}
<img src="{{ img_portrait }}" class="img-fluid mb-3" alt="Portret Natascha Rieter">
{% set portret = page.header.portret ? page.media[page.header.portret].url : url('theme://images/portret-1.jpg') %}
<img src="{{ portret }}" class="img-fluid mb-3" alt="Portret Natascha Rieter">
{% if page.header.extra_1 %}
<img src="{{ page.media[page.header.extra_1].url }}" class="img-fluid mb-3 d-none d-md-block" loading="lazy" alt="Portret Natascha Rieter">
{% endif %}
</div>
<div class="col-12 col-md-6 p-3 text-start">
<h1 class="funky-font main-header text-center">{{ page.title }}</h1>
{{ content|raw }}
</div>
<div class="col-12 col-md-3 p-3 text-center">
{% set img_logo = page.header.image_logo ? page.media[page.header.image_logo].url : url('theme://images/logo-blauw.png') %}
<img src="{{ img_logo }}" class="img-fluid mb-3" loading="lazy" alt="Logo Galerie Groot Welsden">
{% set logo = page.header.logo ? page.media[page.header.logo].url : url('theme://images/logo-blauw.png') %}
<img src="{{ logo }}" class="img-fluid mb-3" loading="lazy" alt="Logo Galerie Groot Welsden">
{% if page.header.extra_2 %}
<img src="{{ page.media[page.header.extra_2].url }}" class="img-fluid d-none d-md-block" loading="lazy" alt="Portret Natascha Rieter">
{% endif %}
</div>
{% endblock %}
@@ -2,17 +2,20 @@
{% set page_class = 'row p-3' %}
{% block content %}
<div class="col-12 col-md-6 col-lg-3 p-3">
{% set img_main = page.header.image_main ? page.media[page.header.image_main].url : url('theme://images/portret-2.jpg') %}
{% set img_secondary = page.header.image_secondary ? page.media[page.header.image_secondary].url : url('theme://images/portret-1.jpg') %}
<img src="{{ img_main }}" class="img-fluid mb-3" alt="Portret Natascha Rieter">
<img src="{{ img_secondary }}" class="img-fluid d-none d-md-block" loading="lazy" alt="Portret Natascha Rieter">
{% set portret = page.header.portret ? page.media[page.header.portret].url : url('theme://images/portret-2.jpg') %}
{% set extra_1 = page.header.extra_1 ? page.media[page.header.extra_1].url : url('theme://images/portret-1.jpg') %}
<img src="{{ portret }}" class="img-fluid mb-3" alt="Portret Natascha Rieter">
<img src="{{ extra_1 }}" class="img-fluid mb-3 d-none d-md-block" loading="lazy" alt="Portret Natascha Rieter">
</div>
<div class="col-12 col-md-6 col-lg-6 p-3 text-start">
<h1 class="funky-font main-header text-center">{{ page.title }}</h1>
{{ content|raw }}
</div>
<div class="col-12 col-md-6 col-lg-3 p-3 text-center">
{% set img_logo = page.header.image_logo ? page.media[page.header.image_logo].url : url('theme://images/logo-blauw.png') %}
<img src="{{ img_logo }}" class="img-fluid mb-3" loading="lazy" alt="Logo Galerie Groot Welsden">
{% set logo = page.header.logo ? page.media[page.header.logo].url : url('theme://images/logo-blauw.png') %}
<img src="{{ logo }}" class="img-fluid mb-3" loading="lazy" alt="Logo Galerie Groot Welsden">
{% if page.header.extra_2 %}
<img src="{{ page.media[page.header.extra_2].url }}" class="img-fluid d-none d-md-block" loading="lazy" alt="Portret Natascha Rieter">
{% endif %}
</div>
{% endblock %}
@@ -1,21 +1,24 @@
{% extends 'partials/base.html.twig' %}
{% block extra_css %}
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/glightbox/dist/css/glightbox.min.css">
{% endblock %}
{% block extra_js %}
<script src="https://cdn.jsdelivr.net/npm/glightbox/dist/js/glightbox.min.js" defer></script>
{% endblock %}
{% block content %}
<div class="row mb-3">
<h1 class="funky-font main-header text-center">{{ page.title }}</h1>
</div>
<div class="row g-3">
{% for i in 1..8 %}
{% for child in page.children %}
{% if child.published %}
<div class="col-6 col-md-4 col-lg-3">
<a href="https://picsum.photos/seed/detail{{ i }}/800/800" class="glightbox gallery-item" data-gallery="detail" data-description="Werk {{ i }}">
<div class="gallery-thumb"><img src="https://picsum.photos/seed/detail{{ i }}/350/350" loading="lazy" alt="Werk {{ i }}"></div>
<a href="{{ child.url }}" class="gallery-item d-block">
<div class="gallery-thumb">
{% for name, img in child.media.images %}
{% if loop.first %}
<img src="{{ img.url }}" loading="lazy" alt="{{ child.title }}">
{% endif %}
{% endfor %}
</div>
<p class="mt-2 text-center small">{{ child.title }}</p>
</a>
</div>
{% endif %}
{% endfor %}
</div>
{% endblock %}