mirror of
https://github.com/photoprism/photoprism.git
synced 2025-12-11 16:24:11 +01:00
Merge branch 'develop' into albums-multi-select-add
This commit is contained in:
@@ -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:
|
||||
|
||||
@@ -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`.
|
||||
|
||||
84
assets/static/js/app-loader.js
Normal file
84
assets/static/js/app-loader.js
Normal 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);
|
||||
})();
|
||||
1
assets/templates/app.js.gohtml
Normal file
1
assets/templates/app.js.gohtml
Normal file
@@ -0,0 +1 @@
|
||||
<script defer src="{{ .config.StaticUri }}/js/app-loader.js"></script>
|
||||
@@ -36,6 +36,6 @@
|
||||
<body class="{{ .config.Flags }} nojs">
|
||||
|
||||
{{template "app.gohtml" .}}
|
||||
<script src="{{ .config.JsUri }}"></script>
|
||||
{{template "app.js.gohtml" .}}
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -19,6 +19,6 @@
|
||||
<body class="{{ .config.Flags }} nojs">
|
||||
|
||||
{{template "app.gohtml" .}}
|
||||
<script src="{{ .config.JsUri }}"></script>
|
||||
{{template "app.js.gohtml" .}}
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -32,6 +32,6 @@
|
||||
<body class="{{ .config.Flags }} nojs">
|
||||
|
||||
{{template "app.gohtml" .}}
|
||||
<script src="{{ .config.JsUri }}"></script>
|
||||
{{template "app.js.gohtml" .}}
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -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/"`
|
||||
|
||||
@@ -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%;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user