Compact home page entries; set up Compose for Arcane git sync

Podium, Spotlight and Grid render smaller on the home page on desktop so
one entry no longer fills the screen; list pages keep full size.

Compose now builds on every deploy (pull_policy: build), stores data in
the canon-data named volume outside the synced folder (CANON_DATA_PATH
overrides), and takes optional bind/port/version settings.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
cdnutterandClaude Opus 5.5 committed 2026-09-30 14:13:47 -07:00
1 parent 33053d1c5f
commit 218bb296ee
4 files changed
+71 -3

No files matched your search

+10
View File
@@ -20,3 +20,13 @@ CANON_IGDB_CLIENT_SECRET=
# CANON_HOST=0.0.0.0 # all network interfaces; 127.0.0.1 = this machine only
# CANON_PORT=4242
# CANON_LOG_LEVEL=debug
# ---- Docker Compose only (not read by Canon itself) ----
# Where the database and images live. Default: the canon_canon-data volume.
# Use an absolute host path to keep them in a folder (writable by UID 1000).
# CANON_DATA_PATH=/srv/canon
# Host address and port to publish on.
# CANON_BIND=0.0.0.0
# CANON_PUBLISH_PORT=4242
# Version label baked into the image at build time.
# CANON_VERSION=dev
+17
View File
@@ -37,6 +37,23 @@ To skip the setup page, set `CANON_ADMIN_USERNAME` and `CANON_ADMIN_PASSWORD` in
Canon listens on all network interfaces (`0.0.0.0`) by default, so phones and other computers on your network can open `http://<this computer's IP>:4242`. When run outside Docker, the startup log prints the exact addresses. If another device can't connect, the host's firewall is probably blocking the port (for example `sudo ufw allow 4242/tcp`). To keep Canon private to one machine, set `CANON_HOST=127.0.0.1`, or publish `127.0.0.1:4242:4242` in `docker-compose.yml`.
### With Arcane (Git sync)
The compose file works as an [Arcane](https://getarcane.app) project synced from this repository:
1. **Projects → New → Git sync**, direction **Pull**, compose file path `docker-compose.yml`.
2. Turn on **Redeploy after sync** to rebuild whenever you push. `pull_policy: build` makes every deploy build the image from the synced source; it never looks for `canon:latest` on a registry.
3. Put your settings (admin account, API keys) in the project's environment in Arcane. Arcane writes them to `.env`, which Canon reads.
The database lives in the `canon_canon-data` named volume, outside the synced folder, so a sync can't overwrite or delete it. To use a host folder instead, set `CANON_DATA_PATH` to an absolute path (it must be writable by UID 1000). To move data from an existing `./data` folder into the volume:
```sh
docker compose stop canon
docker run --rm -v "$PWD/data:/from" -v canon_canon-data:/to alpine sh -c 'cp -a /from/. /to/ && chown -R 1000:1000 /to'
```
The compose file joins the external `chromanet` network; create it first (`docker network create chromanet`) or remove the `networks` entries.
### Without Compose
```sh
+19 -3
View File
@@ -1,21 +1,37 @@
name: canon
# Works with a plain `docker compose up -d --build` and with Arcane's Git sync
# (Pull). Arcane pulls this file's whole directory, so the build context is
# the repository itself.
services:
canon:
build: .
build:
context: .
args:
VERSION: ${CANON_VERSION:-dev}
image: canon:latest
# Never look for canon:latest on a registry: every deploy (including
# Arcane's "Pull image" / "Redeploy after sync") builds from the source
# that was just synced.
pull_policy: build
container_name: canon
restart: unless-stopped
ports:
- "0.0.0.0:4242:4242"
- "${CANON_BIND:-0.0.0.0}:${CANON_PUBLISH_PORT:-4242}:4242"
volumes:
- ./data:/data
# A named volume by default, so a Git sync never touches the database.
# Set CANON_DATA_PATH to a host folder (e.g. ./data) to keep it there.
- ${CANON_DATA_PATH:-canon-data}:/data
env_file:
- path: .env
required: false
networks:
- chromanet
volumes:
canon-data:
networks:
chromanet:
external: true
+25
View File
@@ -166,6 +166,10 @@ code { font: 0.9em ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; bac
.items { list-style: none; margin: 0; padding: 0; }
.items--grid { display: grid; gap: 22px 18px; grid-template-columns: repeat(auto-fill, minmax(156px, 1fr)); }
.aspect-square .items--grid { grid-template-columns: repeat(auto-fill, minmax(168px, 1fr)); }
@media (min-width: 641px) {
.page-home .items--grid { grid-template-columns: repeat(auto-fill, minmax(132px, 1fr)); }
.page-home .aspect-square .items--grid { grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); }
}
@media (max-width: 640px) {
.items--grid { grid-template-columns: repeat(auto-fill, minmax(118px, 1fr)); gap: 16px 12px; }
.aspect-square .items--grid { grid-template-columns: repeat(auto-fill, minmax(132px, 1fr)); }
@@ -325,6 +329,21 @@ code { font: 0.9em ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; bac
.podium-card { padding-bottom: 10px; }
}
/* The home page is a preview of every list, so its podium is compact; the
list page keeps the full-size one. */
@media (min-width: 641px) {
.page-home .podium { max-width: 580px; gap: 0 16px; }
.page-home .podium--2 { max-width: 390px; }
.page-home .podium--1 { grid-template-columns: minmax(0, 190px); }
.page-home .podium-card { gap: 10px; padding-bottom: 10px; }
.page-home .podium-card .item-title { font-size: 14.5px; }
.page-home .podium-spot--1 .item-title { font-size: 16px; }
.page-home .podium-step { font-size: 22px; }
.page-home .podium-spot--1 .podium-step { height: 56px; font-size: 28px; }
.page-home .podium-spot--2 .podium-step { height: 40px; }
.page-home .podium-spot--3 .podium-step { height: 28px; font-size: 18px; }
}
/* "Show N more" under a podium: the browser's own <details>, so it works
without JavaScript. */
.more { padding-top: 18px; }
@@ -372,6 +391,12 @@ code { font: 0.9em ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; bac
display: -webkit-box; -webkit-line-clamp: 4; -webkit-box-orient: vertical; overflow: hidden;
}
.spotlight-more { margin-top: 10px; }
@media (min-width: 641px) {
.page-home .spotlight, .page-home .aspect-square .spotlight { grid-template-columns: 150px 1fr; gap: 24px; padding: 18px; }
.page-home .spotlight-rank { font-size: 32px; }
.page-home .spotlight-title { font-size: clamp(20px, 2.2vw, 26px); }
.page-home .spotlight-desc, .page-home .spotlight-note { -webkit-line-clamp: 3; font-size: 14.5px; }
}
@media (max-width: 640px) {
.spotlight, .aspect-square .spotlight { grid-template-columns: 1fr; gap: 18px; padding: 18px; }
.spotlight-art { width: min(100%, 220px); justify-self: center; }