a23fa3bb12cd05a922c0fb860ae97ffd3fe2baff
6
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
efa6b4a205 |
fix(brand-title): runtime substitution so GHCR-image users can override (#521 follow-up)
@Rekoo-PS confirmed the prior #521 fix landed on beta but reported the preview still shows the default "PicPeak" title — their brand is "arkan-studio". Root cause: that fix used Vite's build-time %VITE_DEFAULT_TITLE% substitution. Self-hosters running the pre-built ghcr.io/the-luap/picpeak/frontend image can't override at build time without rebuilding, so they were stuck with whatever the upstream build baked in. Pivot to runtime substitution: the frontend container now reads BRAND_TITLE / BRAND_DESCRIPTION env vars on startup and envsubsts them into index.html. Change the values in .env, restart the frontend service, done — no rebuild required. Mechanics: - frontend/index.html: tokens are now ${BRAND_TITLE} / ${BRAND_DESCRIPTION} (shell expansion syntax, passes through Vite unchanged into the built dist). - frontend/Dockerfile: install gettext (provides envsubst), snapshot /usr/share/nginx/html/index.html → index.html.tpl at build, install docker-entrypoint.sh, wire ENTRYPOINT to it. The .tpl is the immutable source — every container start re-renders index.html from .tpl, so restarts pick up new env values cleanly (no accidental "first-boot env stuck forever" trap). - frontend/docker-entrypoint.sh: applies defaults if env unset, runs envsubst (locked to BRAND_TITLE + BRAND_DESCRIPTION explicitly so /assets/*.js template literals aren't touched if anyone ever extends substitution to the bundle), execs nginx. - frontend/vite.config.ts: drop the htmlTitleDefaults plugin — no longer needed since substitution is fully runtime. - frontend/.env.example + .env.production.example: drop the VITE_DEFAULT_* docs (the vars no longer have effect). - docker-compose.yml + docker-compose.production.yml: pass BRAND_TITLE / BRAND_DESCRIPTION env into the frontend service with sensible defaults so unconfigured installs work unchanged. - .env.example: add BRAND_TITLE / BRAND_DESCRIPTION with comment pointing at the social-preview use case. Verified end-to-end against the built image: - BRAND_TITLE="Arkan Studio" BRAND_DESCRIPTION="Wedding photographs by Arkan Studio" → index.html serves <title>Arkan Studio</title> + og:title="Arkan Studio" + og:description correctly substituted. - .tpl preserves ${...} tokens so the next restart can re-substitute. - Bundle assets unaffected. - Defaults applied when env unset → <title>PicPeak</title>. Docs PR in picpeak-docs describes the two new env vars under "Social link preview fallback" in the environment-variables reference. Refs: #521 |
||
|
|
b960639035 |
fix(og): brandable static title + wider crawler UA coverage (#521)
@Rekoo-PS reported that gallery URLs sent via the WhatsApp Business API render an unbranded "PicPeak - Photo Sharing Platform" preview even though manual link sends from the WhatsApp app pick up the per-event rich preview correctly. Two root causes, two fixes: 1. WhatsApp Business and 3rd-party preview services (Twilio, LinkPreview.net, etc.) don't always crawl with the recognisable "WhatsApp/X.Y.Z" UA we matched in nginx + galleryOgService. Extend the regex (both copies) to also catch WhatsAppBot, wa-bot, LinkPreview, and Slack-ImgProxy. 2. Even with broader UA coverage, some senders cache metadata with no UA at all and fetch the static SPA shell. That shell's <title> was hard-coded to "PicPeak - Photo Sharing Platform" — embarrassingly generic for any self-hosted brand. Switch to Vite's %VITE_DEFAULT_TITLE% / %VITE_DEFAULT_DESCRIPTION% HTML substitution so self-hosters can bake their brand into the fallback at build time. Defaults stay "PicPeak" so the upstream image doesn't change behaviour for anyone. The per-event rich preview path (handleGalleryOgRequest, fired on matched crawler UAs) is unchanged — this only improves the fallback for unrecognised UAs and for the SPA-shell title that humans see in their browser tab. Adds a vite.config plugin to provide the defaults when env vars aren't set, so unsubstituted "%VITE_..." literals never reach the built HTML. Adds .env.example entries explaining the override. Tests: extend galleryOgService.shareImage.test.js with an isSocialCrawler suite that pins every documented UA (incl. the new ones) plus three browser UAs (negative) and null/empty edge cases. Verified locally: `vite build` with VITE_DEFAULT_TITLE="MyBrand" produces <title>MyBrand</title> + og:title="MyBrand"; without the env var falls back to "PicPeak". Refs: #521 |
||
|
|
1a530aeaa2 |
fix(theme): kill initial white frame + theme-aware skeleton tiles (#358 follow-up)
Two further fixes for the gallery loading sequence shown in @Rekoo-PS's frame breakdown on issue #358 — both about colours that didn't track the active theme. 1. Initial white frame (frame f1) The pre-React bootstrap script in #359 sets the cached background on documentElement, but the browser may paint the very first frame *before* that <script> tag runs (synchronous parse-time JS in the <head> is still slightly later than CSS apply-time). On first-visit dark-OS devices that meant a single white frame before the script resolved. Fix: move the OS-preference default into a <style> block that precedes the script. CSS @media (prefers-color-scheme) is applied before paint, so dark-OS devices land on dark from frame zero. The script keeps the per-gallery cache hit on top, and now also stamps the colour onto document.body in case the body element has already mounted by the time the script runs. 2. "Most annoying" skeleton tile frame (frame f4) Skeleton placeholders rendered as bright `bg-neutral-200` light grey regardless of theme. On a dark gallery that's the highest-contrast thing on screen during loading — the exact frame Rekoo-PS labelled "the most annoying" in the issue. Fix: the Skeleton component's background now reads `var(--color-surface-border)`, which ThemeContext already wires up per active theme (`#e5e5e5` light / `#2e2e2e` dark by default; per- event themes can override). The bare `<div>` no longer carries any colour utility class — the inline style supplies the active value. Also dropped the leftover `bg-white` on SkeletonCard / SkeletonTable in favour of `var(--color-surface)` for the same reason. Tests: New src/components/common/__tests__/Skeleton.test.tsx covers - Skeleton uses var(--color-surface-border, ...) - bg-neutral-200 is no longer present - SkeletonGalleryGrid tiles all inherit the theme colour - SkeletonCard surface uses var(--color-surface) |
||
|
|
f81a8728e6 |
fix(theme): pre-React bootstrap to kill white-flash on dark galleries (#358)
Opening a gallery with a dark theme briefly painted a white background between the initial HTML render and React applying the per-event theme. The HTML shipped with no theme info, so the first paint used the default (#fafafa) before /gallery/:slug/info resolved. Two-part fix. 1. Inline bootstrap script in index.html runs synchronously before React mounts. Reads the URL, looks up a per-slug background colour from localStorage (gallery-theme-bg-<slug>), and applies it to documentElement immediately. Falls back to #171717 when no cache exists and the OS prefers dark, so first visits with dark OS still land on a dark background. 2. ThemeContext.applyTheme writes the resolved background to localStorage keyed by slug whenever a gallery theme loads. Revisits then hit the bootstrap cache and never see a flash. Added a 200ms transition on html.background-color so the rare cache→API drift (e.g. theme palette changed admin-side since last visit) is a smooth fade instead of a snap. Limitation: first visit on a light-OS device to a dark gallery still flashes once. Killing that case requires a server-rendered theme hint, out of scope for an SPA bootstrap fix. The empty-skeleton-grid part of the same report is already addressed by the 300ms lazy render in #352 — Rekoo-PS just needs to update from v3.32.1-beta.0 to v3.32.2-beta.0+. |
||
|
|
42a7ae4be8 |
fix(lightbox): mobile toolbar clipping + iOS safe-area + viewport-fit (#336)
When feedback was enabled the lightbox bottom toolbar packed counter + zoom + download + like + 5-star + comments into a single row that overflowed the viewport on iPhone-class widths, putting the rating stars under the screen edge and below the iOS home indicator. Changes: - Bottom toolbar now uses flex-wrap with reduced gap/padding on mobile, so all controls fit (375px viewport: max-right 363 < 375; 390px: max-right 378 < 390; 393px: max-right 393 < 393). - pb computed as max(0.75rem, env(safe-area-inset-bottom)) so the row sits above the iOS home indicator on devices with a gesture bar. - Close button top/right now use max(1rem, env(safe-area-inset-*)) so it doesn't disappear under the notch / dynamic island. - "Swipe to navigate" hint moved from bottom-20 to bottom-40 so it clears the now-taller wrapped toolbar. - index.html viewport meta gains viewport-fit=cover to enable env(safe-area-inset-*) on iOS Safari. Verified in mobile emulation across iPhone SE (375x667), iPhone 13/14 (390x844), iPhone 14 Pro (393x852) portrait, and 14 Pro landscape (852x393) — toolbar fits, photo centered, no clipping. |
||
|
|
1773ed5f95 |
Initial commit - Project start (July 17, 2025)
continuous-integration/drone/push Build is passing
Mirror to GitHub / mirror (push) Successful in 26s
Test and Lint / backend-test (push) Successful in 1m11s
Test and Lint / frontend-test (push) Successful in 2m28s
Version and Release / version-bump (push) Successful in 32s
Version and Release / trigger-drone (push) Has been skipped
Original: feat: enhance security logging and ensure rate limit blocks are properly tracked - Add comprehensive logging for rate limit blocks with full request details - IP address (with proper proxy detection), user agent, headers, timestamps - Rate limit info (current count, limit, remaining, reset time) - Separate tracking for auth vs general endpoints - Enhance authentication failure logging - JWT validation failures with detailed error info - Admin auth attempts without token - Failed token validation with user context - All events include IP, path, method, user agent - Improve Winston logger configuration for production - Add automatic log rotation (10MB errors, 50MB combined) - Create separate security.log for auth/rate limit events - Ensure logs directory exists automatically - Add structured JSON format for log aggregation - Support container logging with LOG_TO_CONSOLE env var - Create comprehensive documentation - Security logging guide with examples - Monitoring recommendations - Configuration reference - Add test script to verify logging functionality All rate limit settings remain configurable via admin panel: - Window duration, max requests, auth limits - Skip authenticated requests option - Public endpoints only option 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]> |