Merge branch 'develop' into albums-multi-select-add

This commit is contained in:
graciousgrey
2025-10-11 13:40:29 +02:00
9 changed files with 120 additions and 6 deletions

View File

@@ -1,6 +1,6 @@
# PhotoPrism® Repository Guidelines
**Last Updated:** October 10, 2025
**Last Updated:** October 11, 2025
## Purpose
@@ -41,6 +41,13 @@ Learn more: https://agents.md/
- Frontend: Vue 3 + Vuetify 3 (`frontend/`)
- Docker/compose for dev/CI; Traefik is used for local TLS (`*.localssl.dev`)
### Web Templates & Shared Assets
- HTML entrypoints live under `assets/templates/`; key files are `index.gohtml`, `app.gohtml`, `app.js.gohtml`, and `splash.gohtml`. The SPA loader logic resides in `assets/static/js/app-loader.js` and is included via `app.js.gohtml`; it performs capability checks (Promise, fetch, AbortController, `script.noModule`, etc.) before appending `window.__CONFIG__.jsUri`.
- The same loader partial is reused in private packages (`pro/assets/templates/index.gohtml`, `plus/assets/templates/index.gohtml`). Whenever you touch `app.js.gohtml` or change how we load the bundle, mirror the update by running commands such as `cd pro && sed -n '1,160p' assets/templates/index.gohtml` (and similarly for `plus`) to confirm they include the shared partial instead of hard-coding `<script src="{{ .config.JsUri }}">`.
- Splash styles are defined in `frontend/src/css/splash.css`. Add new splash elements (for example `.splash-warning`) there so both public and private editions remain visually consistent.
- Browser baseline: PhotoPrism requires Safari 13 / iOS 13 or current Chrome, Edge, or Firefox. Update the message in `assets/templates/app.js.gohtml` (and the matching CSS) if support changes.
## Agent Runtime (Host vs Container)
Agents MAY run either:

View File

@@ -1,6 +1,6 @@
PhotoPrism — Backend CODEMAP
**Last Updated:** October 4, 2025
**Last Updated:** October 11, 2025
Purpose
- Give agents and contributors a fast, reliable map of where things live and how they fit together, so you can add features, fix bugs, and write tests without spelunking.
@@ -42,6 +42,12 @@ High-Level Package Map (Go)
- `internal/ffmpeg`, `internal/thumb`, `internal/meta`, `internal/form`, `internal/mutex` — media, thumbs, metadata, forms, coordination
- `pkg/*` — reusable utilities (must never import from `internal/*`), e.g. `pkg/fs`, `pkg/log`, `pkg/service/http/header`
Templates & Static Assets
- Entry HTML lives in `assets/templates/index.gohtml`, which includes the splash markup from `app.gohtml` and the SPA loader from `app.js.gohtml`.
- The loader script is implemented in `assets/static/js/app-loader.js` (included via `app.js.gohtml`) and performs capability checks (Promise, fetch, AbortController, `script.noModule`, etc.) before injecting `window.__CONFIG__.jsUri`. Update this file (and the partial) in lockstep with the templates in private repos (`pro/assets/templates/index.gohtml`, `plus/assets/templates/index.gohtml`) because they import the same partial.
- `splash.gohtml` renders the loading screen text while the bundle loads; styles are in `frontend/src/css/splash.css`.
- When adjusting browser support messaging, update both the loader partial and splash styles so the warning message stays consistent across editions.
HTTP API
- Handlers live in `internal/api/*.go` and are registered in `internal/server/routes.go`.
- Annotate new endpoints in handler files; generate docs with: `make fmt-go swag-fmt && make swag`.

View File

@@ -0,0 +1,84 @@
'use strict';
(function () {
function supportsModernJs() {
var checks = [
{ ok: function () { return typeof window.Promise === 'function'; }, reason: 'Promise' },
{ ok: function () { return typeof window.Symbol === 'function'; }, reason: 'Symbol' },
{ ok: function () { return typeof window.fetch === 'function'; }, reason: 'fetch' },
{ ok: function () { return typeof window.URL === 'function'; }, reason: 'URL' },
{ ok: function () { return typeof window.URLSearchParams === 'function'; }, reason: 'URLSearchParams' },
{ ok: function () { return typeof window.AbortController === 'function'; }, reason: 'AbortController' },
{ ok: function () { return typeof Object.assign === 'function'; }, reason: 'Object.assign' },
{ ok: function () { return typeof Array.from === 'function'; }, reason: 'Array.from' },
{ ok: function () { return typeof Array.prototype.flat === 'function'; }, reason: 'Array.prototype.flat' },
{
ok: function () {
var script = document.createElement('script');
return 'noModule' in script;
},
reason: 'script.noModule'
}
];
for (var i = 0; i < checks.length; i++) {
if (!checks[i].ok()) {
return { ok: false, reason: checks[i].reason };
}
}
return { ok: true };
}
function showUnsupportedMessage(message) {
var body = document.body;
if (body && body.className.indexOf('unsupported-browser') === -1) {
body.className += ' unsupported-browser';
}
var progress = document.getElementById('progress');
if (progress) {
progress.style.display = 'none';
}
var busy = document.getElementById('busy-overlay');
if (busy) {
busy.style.display = 'none';
}
var splashInfo = document.getElementById('splash-info');
if (splashInfo) {
splashInfo.innerHTML = '';
var info = document.createElement('div');
info.className = 'splash-warning';
info.textContent = message;
splashInfo.appendChild(info);
}
}
function loadBundle(jsUri) {
var script = document.createElement('script');
script.src = jsUri;
script.defer = true;
document.body.appendChild(script);
}
var config = window.__CONFIG__ || {};
var jsUri = config.jsUri || config.JsUri;
var support = supportsModernJs();
window.__PHOTOPRISM_SUPPORTS__ = support.ok;
if (!support.ok) {
window.__PHOTOPRISM_SUPPORTS_REASON__ = support.reason;
showUnsupportedMessage('PhotoPrism requires Safari 13 (iOS 13) or a current version of Chrome, Edge, or Firefox. Please update your browser or switch to a supported device.');
return;
}
if (!jsUri) {
console.warn('PhotoPrism: Unable to find bundle URL (jsUri) in configuration.');
return;
}
loadBundle(jsUri);
})();

View File

@@ -0,0 +1 @@
<script defer src="{{ .config.StaticUri }}/js/app-loader.js"></script>

View File

@@ -36,6 +36,6 @@
<body class="{{ .config.Flags }} nojs">
{{template "app.gohtml" .}}
<script src="{{ .config.JsUri }}"></script>
{{template "app.js.gohtml" .}}
</body>
</html>

View File

@@ -19,6 +19,6 @@
<body class="{{ .config.Flags }} nojs">
{{template "app.gohtml" .}}
<script src="{{ .config.JsUri }}"></script>
{{template "app.js.gohtml" .}}
</body>
</html>

View File

@@ -32,6 +32,6 @@
<body class="{{ .config.Flags }} nojs">
{{template "app.gohtml" .}}
<script src="{{ .config.JsUri }}"></script>
{{template "app.js.gohtml" .}}
</body>
</html>

View File

@@ -1,5 +1,7 @@
PhotoPrism — Frontend CODEMAP
**Last Updated:** October 11, 2025
Purpose
- Help agents and contributors navigate the Vue 3 + Vuetify 3 app quickly and make safe changes.
- Use Makefile targets and scripts in `frontend/package.json` as sources of truth.
@@ -24,6 +26,12 @@ Directory Map (src)
- `src/css/*` — styles loaded by Webpack
- `src/locales/*` — gettext catalogs; extraction/compile scripts in `package.json`
Startup Templates & Splash Screen
- The HTML shell is rendered from `assets/templates/index.gohtml` (and `pro/assets/templates/index.gohtml` / `plus/...`). Each template includes `app.gohtml` for the splash markup and `app.js.gohtml` to inject the bundle.
- The loader script lives in `assets/static/js/app-loader.js` (included via `app.js.gohtml`) and checks for modern browser features (Promise, fetch, AbortController, `script.noModule`, etc.) before loading `window.__CONFIG__.jsUri`. Update the same files in private repos whenever the loader logic changes.
- Splash styles, including the `.splash-warning` fallback banner, live in `frontend/src/css/splash.css`. Keep styling changes there so public and private editions stay aligned.
- Baseline support: Safari 13 / iOS 13 or current Chrome, Edge, or Firefox. If the support matrix changes, revise the warning text in `app.js.gohtml` and the CSS message accordingly.
Runtime & Plugins
- Vue 3 + Vuetify 3 (`createVuetify`) with MDI icons; themes from `src/options/themes.js`
- Router: Vue Router 4, history base at `$config.baseUri + "/library/"`

View File

@@ -221,6 +221,15 @@ a.logo-large {
color: #bbbbb5;
}
.splash-warning {
display: block;
font-weight: 600;
color: #bbbbb5;
margin: 0 auto;
max-width: 520px;
line-height: 1.5;
}
#noscript-info.splash-info,
#noscript-info.splash-info a {
font-weight: 500;
@@ -286,4 +295,3 @@ div.loading-bar {
right: 10%;
left: 10%;
}