Responsiveness tweaks

This commit is contained in:
2026-05-27 09:13:18 +12:00
parent b8342e07a8
commit c8838a485d
3 changed files with 156 additions and 38 deletions
+7 -19
View File
@@ -1,13 +1,17 @@
<#
Deploy embycovers to an Asustor NAS over SSH/SCP from Windows PowerShell.
Syncs project files to the NAS, then runs `docker compose build` and
`docker compose up -d` on the remote. All runtime configuration (Emby URL,
API key, ports, volumes) comes from docker-compose.yml — edit it there.
Prerequisites on your Windows machine:
- OpenSSH Client installed. Test with: ssh -V
- SSH enabled on the Asustor NAS.
- Docker / Docker Compose available on the Asustor NAS.
Example:
.\deploy.ps1 -NasHost MATT-NAS -NasUser admin -EmbyUrl http://192.168.1.50:8096 -EmbyApiKey abcdef123456
.\deploy.ps1 -NasHost MATT-NAS -NasUser ssh
#>
param(
@@ -17,15 +21,7 @@ param(
[Parameter(Mandatory = $true)]
[string]$NasUser,
[string]$RemoteAppDir = "/share/Docker/embycovers",
[Parameter(Mandatory = $true)]
[string]$EmbyUrl,
[Parameter(Mandatory = $true)]
[string]$EmbyApiKey,
[int]$HostPort = 8500
[string]$RemoteAppDir = "/share/Docker/embycovers"
)
$ErrorActionPreference = "Stop"
@@ -43,8 +39,6 @@ $LocalDir = Split-Path -Parent $MyInvocation.MyCommand.Path
$Remote = "$NasUser@$NasHost"
Write-Host "Deploying embycovers to ${Remote}:$RemoteAppDir"
Write-Host "Emby URL: $EmbyUrl"
Write-Host "Host port: $HostPort"
ssh $Remote @"
set -e
@@ -72,16 +66,11 @@ if ($LogoFiles) {
Invoke-Expression $ScpCmd
}
# Patch docker-compose.yml on the NAS with the supplied Emby settings, then build & run.
# Build and run on the NAS using values from docker-compose.yml.
$RemoteCommands = @"
set -e
cd '$RemoteAppDir'
# Patch compose env vars and host port from deployment parameters.
sed -i "s#EMBY_URL=.*#EMBY_URL=$EmbyUrl#g" docker-compose.yml
sed -i "s#EMBY_API_KEY=.*#EMBY_API_KEY=$EmbyApiKey#g" docker-compose.yml
sed -i "s#\"8500:8500\"#\"$HostPort:8500\"#g" docker-compose.yml
if command -v docker-compose >/dev/null 2>&1; then
docker-compose build
docker-compose up -d
@@ -94,6 +83,5 @@ fi
ssh $Remote $RemoteCommands
Write-Host "Deployment complete."
Write-Host "App should be reachable at: http://${NasHost}:$HostPort"
Write-Host "To view logs:"
Write-Host " ssh $Remote 'cd $RemoteAppDir && docker compose logs -f'"
+17 -10
View File
@@ -1,18 +1,25 @@
services:
emby-thumb-gen:
embycovers:
build: .
container_name: emby-thumb-gen
container_name: embytoolkit
ports:
- "8500:8500"
environment:
- EMBY_URL=http://your-emby-server:8096
- EMBY_API_KEY=your-api-key-here
- TZ=Pacific/Auckland
- EMBY_URL=http://10.0.0.2:8096
- EMBY_API_KEY=b9af54b630f6448289ab96422add567a
# Optional external artwork providers:
# - TMDB_BEARER_TOKEN=your-tmdb-read-access-token
# - TMDB_API_KEY=your-tmdb-v3-api-key
# - GOOGLE_CUSTOM_SEARCH_API_KEY=your-google-api-key
# - GOOGLE_CUSTOM_SEARCH_ENGINE_ID=your-google-search-engine-id
# - TMDB_BEARER_TOKEN=
# - TMDB_API_KEY=
# - GOOGLE_CUSTOM_SEARCH_API_KEY=
# - GOOGLE_CUSTOM_SEARCH_ENGINE_ID=
volumes:
- ./output:/app/output
- ./cache:/app/cache
- /share/Docker/embytoolkit/output:/app/output
- /share/Docker/embytoolkit/cache:/app/cache
restart: unless-stopped
networks:
- npm_network
networks:
npm_network:
external: true
+132 -9
View File
@@ -28,18 +28,60 @@
}
* { box-sizing: border-box; }
html, body { height: 100%; }
body {
margin: 0;
background: var(--bg);
color: var(--text);
font-family: 'DM Sans', sans-serif;
display: grid;
grid-template-columns: 220px 1fr;
grid-template-columns: 240px 1fr;
height: 100vh;
height: 100svh;
overflow: hidden;
}
/* ── Mobile top bar (hidden on desktop) ── */
.app-topbar {
display: none;
align-items: center;
gap: 12px;
padding: 10px 14px;
background: var(--surface);
border-bottom: 1px solid var(--border);
position: sticky;
top: 0;
z-index: 30;
}
.app-topbar-brand {
display: flex;
align-items: center;
gap: 10px;
font-weight: 700;
letter-spacing: -0.03em;
}
.icon-btn {
width: 38px; height: 38px;
display: inline-grid; place-items: center;
border-radius: 10px;
border: 1px solid var(--border);
background: var(--surface2);
color: var(--text);
cursor: pointer;
}
.icon-btn:hover { background: var(--surface3); }
.nav-scrim {
display: none;
position: fixed;
inset: 0;
background: rgba(0,0,0,0.55);
z-index: 40;
opacity: 0;
transition: opacity 0.18s ease;
}
.nav-scrim.show { opacity: 1; }
/* ── App Nav Sidebar ── */
.app-nav {
display: flex;
@@ -108,9 +150,14 @@
.dot.off { background: var(--red); box-shadow: 0 0 6px var(--red); }
.page {
padding: 20px 22px 26px;
padding: 24px clamp(16px, 2.4vw, 36px) 32px;
overflow-y: auto;
}
.page-inner {
width: 100%;
max-width: 1680px;
margin: 0 auto;
}
.hero {
display: flex;
align-items: flex-start;
@@ -203,8 +250,14 @@
.grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 14px;
grid-template-columns: repeat(auto-fill, minmax(min(100%, 340px), 1fr));
gap: 16px;
}
@media (min-width: 1600px) {
.grid { grid-template-columns: repeat(auto-fill, minmax(380px, 1fr)); gap: 18px; }
}
@media (min-width: 2200px) {
.grid { grid-template-columns: repeat(auto-fill, minmax(420px, 1fr)); }
}
.card {
@@ -351,31 +404,89 @@
.toast.ok { background: var(--green-bg); border: 1px solid var(--green); color: var(--green); }
.toast.err { background: rgba(248,113,113,.1); border: 1px solid var(--red); color: var(--red); }
/* Ultra-wide tweak: widen the content cap a touch more on huge displays */
@media (min-width: 2400px) {
.page-inner { max-width: 1920px; }
}
@media (max-width: 1100px) {
body { grid-template-columns: 200px 1fr; }
}
@media (max-width: 980px) {
.hero, .toolbar, .pager {
flex-direction: column;
align-items: stretch;
}
.toolbar-actions, .pager-actions {
justify-content: space-between;
justify-content: flex-start;
}
}
@media (max-width: 720px) {
/* ── Mobile: drawer nav ── */
@media (max-width: 860px) {
body {
grid-template-columns: 1fr;
grid-template-rows: auto 1fr;
}
.app-topbar { display: flex; }
.app-nav {
position: fixed;
top: 0; left: 0; bottom: 0;
width: min(82vw, 300px);
z-index: 50;
transform: translateX(-100%);
transition: transform 0.22s cubic-bezier(0.4,0,0.2,1);
box-shadow: 0 30px 60px rgba(0,0,0,0.4);
}
body.nav-open .app-nav { transform: translateX(0); }
body.nav-open .nav-scrim { display: block; }
.page { padding: 16px; }
.header { padding: 0 16px; }
}
@media (max-width: 720px) {
.toolbar { padding: 12px; }
.toolbar-actions { gap: 8px; }
.toolbar-actions .btn,
.toolbar-actions .chip-toggle { flex: 1 1 auto; justify-content: center; }
.card {
grid-template-columns: 84px minmax(0, 1fr);
grid-template-columns: 92px minmax(0, 1fr);
gap: 12px;
padding: 12px;
min-height: 0;
}
.card-poster { width: 84px; }
.card-poster { width: 92px; }
.card-title { font-size: 16px; }
.card-actions { flex-wrap: wrap; }
.card-actions .btn { width: 100%; }
}
@media (max-width: 480px) {
.card {
grid-template-columns: 1fr;
}
.card-poster {
width: 100%;
aspect-ratio: 16 / 9;
object-fit: cover;
}
.hero-copy h2 { font-size: 22px; }
}
</style>
</head>
<body>
<header class="app-topbar">
<button class="icon-btn" id="navToggle" aria-label="Open navigation">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><line x1="3" y1="6" x2="21" y2="6"/><line x1="3" y1="12" x2="21" y2="12"/><line x1="3" y1="18" x2="21" y2="18"/></svg>
</button>
<div class="app-topbar-brand">
<span>EmbyToolkit</span>
</div>
</header>
<div class="nav-scrim" id="navScrim"></div>
<nav class="app-nav">
<div class="app-nav-brand">
<div class="app-nav-logo">
@@ -408,6 +519,7 @@
</nav>
<main class="page">
<div class="page-inner">
<section class="hero">
<div class="hero-copy">
<h2>Current Airing Shows</h2>
@@ -448,6 +560,7 @@
<button class="btn" id="btnNext" disabled>Next</button>
</div>
</section>
</div>
</main>
<div class="toast" id="toast"></div>
@@ -483,6 +596,16 @@ const btnPrev = $('#btnPrev');
const btnNext = $('#btnNext');
const toast = $('#toast');
const navToggle = $('#navToggle');
const navScrim = $('#navScrim');
if (navToggle && navScrim) {
const closeNav = () => document.body.classList.remove('nav-open');
navToggle.addEventListener('click', () => document.body.classList.toggle('nav-open'));
navScrim.addEventListener('click', closeNav);
document.querySelectorAll('.app-nav-item').forEach((link) => link.addEventListener('click', closeNav));
window.addEventListener('keydown', (e) => { if (e.key === 'Escape') closeNav(); });
}
function esc(value) {
const div = document.createElement('div');
div.textContent = value ?? '';