diff --git a/README.md b/README.md index 0a9db69..d15c034 100644 --- a/README.md +++ b/README.md @@ -344,6 +344,13 @@ Then put it behind your existing reverse proxy like everything else action — resolved server-side (one atomic operation, not one request per track) the same way launching a playlist already expands into everything it contains — see docs/architecture.md +- [x] Picture-in-picture for the video player (standard + `requestPictureInPicture`, confirmed present on Android Chrome) — + asked for directly for mobile, where there's no second window to + put this app in while switching apps — see docs/architecture.md +- [x] Installable as a PWA (manifest + icons, standalone display, + no service worker — this app has nothing worth caching offline) + — see docs/architecture.md - [x] Mobile navigation redesigned as a bottom sheet (Accueil / Bibliothèques / Listes de lecture) instead of a horizontally scrolling sidebar — see docs/architecture.md diff --git a/client/build.mjs b/client/build.mjs index 0290eef..55fb725 100644 --- a/client/build.mjs +++ b/client/build.mjs @@ -11,7 +11,7 @@ // npm run watch -> rebuilds on save, for local dev (see README's // Running locally section) import * as esbuild from 'esbuild'; -import { copyFileSync, mkdirSync } from 'fs'; +import { copyFileSync, cpSync, mkdirSync } from 'fs'; import path from 'path'; import { fileURLToPath } from 'url'; @@ -20,6 +20,11 @@ const outdir = path.join(here, 'dist'); mkdirSync(outdir, { recursive: true }); copyFileSync(path.join(here, 'src', 'index.html'), path.join(outdir, 'index.html')); +// PWA manifest + icons (manifest.webmanifest, icons/*) - see +// docs/architecture.md's "Progressive Web App" section. Copied wholesale +// rather than named file-by-file like index.html above, so adding another +// icon later needs no build.mjs change. +cpSync(path.join(here, 'src', 'public'), outdir, { recursive: true }); const buildOptions = { entryPoints: [path.join(here, 'src', 'app.ts')], diff --git a/client/src/index.html b/client/src/index.html index e57676f..ecb359c 100644 --- a/client/src/index.html +++ b/client/src/index.html @@ -4,6 +4,24 @@ Watch Party + + + + + + + + + + + + diff --git a/client/src/public/icons/apple-touch-icon.png b/client/src/public/icons/apple-touch-icon.png new file mode 100644 index 0000000..c8262c7 Binary files /dev/null and b/client/src/public/icons/apple-touch-icon.png differ diff --git a/client/src/public/icons/favicon.png b/client/src/public/icons/favicon.png new file mode 100644 index 0000000..bcc545f Binary files /dev/null and b/client/src/public/icons/favicon.png differ diff --git a/client/src/public/icons/icon-192.png b/client/src/public/icons/icon-192.png new file mode 100644 index 0000000..e533df5 Binary files /dev/null and b/client/src/public/icons/icon-192.png differ diff --git a/client/src/public/icons/icon-512-maskable.png b/client/src/public/icons/icon-512-maskable.png new file mode 100644 index 0000000..b20de6e Binary files /dev/null and b/client/src/public/icons/icon-512-maskable.png differ diff --git a/client/src/public/icons/icon-512.png b/client/src/public/icons/icon-512.png new file mode 100644 index 0000000..983626f Binary files /dev/null and b/client/src/public/icons/icon-512.png differ diff --git a/client/src/public/manifest.webmanifest b/client/src/public/manifest.webmanifest new file mode 100644 index 0000000..f6a2eaa --- /dev/null +++ b/client/src/public/manifest.webmanifest @@ -0,0 +1,16 @@ +{ + "name": "Watch Party", + "short_name": "Watch Party", + "description": "Regardez et écoutez en même temps que les autres utilisateurs de votre serveur Emby.", + "lang": "fr", + "start_url": "/", + "display": "standalone", + "background_color": "#151216", + "theme_color": "#221d24", + "categories": ["entertainment", "multimedia"], + "icons": [ + { "src": "icons/icon-192.png", "sizes": "192x192", "type": "image/png", "purpose": "any" }, + { "src": "icons/icon-512.png", "sizes": "512x512", "type": "image/png", "purpose": "any" }, + { "src": "icons/icon-512-maskable.png", "sizes": "512x512", "type": "image/png", "purpose": "maskable" } + ] +} diff --git a/client/src/views/player/Player.css b/client/src/views/player/Player.css index 04fce66..54412fe 100644 --- a/client/src/views/player/Player.css +++ b/client/src/views/player/Player.css @@ -366,6 +366,15 @@ .fsBtn:hover { background: rgba(255, 255, 255, .18); } +/* #pipBtn while active - same "clearly-on" treatment as .iconBtn's own + [aria-pressed="true"] rule (#castBtn), just scoped to .fsBtn instead - + the two aren't combined onto one shared class since .iconBtn and + .fsBtn otherwise disagree on padding/border-radius/background. */ +.fsBtn[aria-pressed="true"] { + color: #ff9800; + background: rgba(255, 152, 0, .18); +} + /* Replaces the video content while casting - the local