Chore: Port over SeriesDetail (WIP Panels)

This commit is contained in:
Youwes09
2026-05-28 23:05:02 -05:00
parent 584b917f98
commit 8c250021a0
53 changed files with 4570 additions and 885 deletions
@@ -0,0 +1,14 @@
<script lang="ts">
let { onClose, ...rest }: { onClose?: () => void; [k: string]: any } = $props()
</script>
<div class="stub-panel">
<button class="stub-close" onclick={onClose}>✕</button>
<p class="stub-label">MigrateModal</p>
</div>
<style>
.stub-panel { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px; padding: 32px; min-width: 240px; }
.stub-close { align-self: flex-end; background: none; border: none; cursor: pointer; color: var(--text-muted); font-size: 16px; }
.stub-label { color: var(--text-faint); font-size: var(--text-sm); }
</style>
@@ -0,0 +1,14 @@
<script lang="ts">
let { onClose, ...rest }: { onClose?: () => void; [k: string]: any } = $props()
</script>
<div class="stub-panel">
<button class="stub-close" onclick={onClose}>✕</button>
<p class="stub-label">SeriesLinkPanel</p>
</div>
<style>
.stub-panel { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px; padding: 32px; min-width: 240px; }
.stub-close { align-self: flex-end; background: none; border: none; cursor: pointer; color: var(--text-muted); font-size: 16px; }
.stub-label { color: var(--text-faint); font-size: var(--text-sm); }
</style>
@@ -3,49 +3,39 @@
interface Props {
children: Snippet;
class?: string;
class?: string;
enabled?: boolean;
}
let { children, class: cls = "" }: Props = $props();
let { children, class: cls = "", enabled = true }: Props = $props();
</script>
<div class="hover-3d {cls}">
<div class="hover-3d-content">
{@render children()}
<div class="shine"></div>
<div class="edge-top"></div>
<div class="edge-left"></div>
{#if enabled}
<div class="hover-3d {cls}">
<div class="hover-3d-content">
{@render children()}
</div>
<div></div><div></div><div></div>
<div></div><div></div><div></div>
<div></div><div></div>
</div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
{:else}
<div class={cls}>
{@render children()}
</div>
{/if}
<style>
.hover-3d {
display: inline-grid;
perspective: 600px;
--tx: 0;
--ty: 0;
--shine-x: 50%;
--shine-y: 50%;
--shadow-x: 0px;
--shadow-y: 0px;
--tx: 0; --ty: 0;
--shadow-x: 0px; --shadow-y: 0px;
--ease-out: linear(0, 0.931 13.8%, 1.196 21.4%, 1.343 29.8%, 1.378 36%, 1.365 43.2%, 1.059 78%, 1);
--ease-hover: linear(0, 0.708 15.2%, 0.927 23.6%, 1.067 33%, 1.12 41%, 1.13 50.2%, 1.019 83.2%, 1);
}
.hover-3d > :nth-child(n + 2) {
isolation: isolate;
z-index: 1;
scale: 1.2;
}
.hover-3d > :nth-child(n + 2) { isolation: isolate; z-index: 1; scale: 1.2; }
.hover-3d > :nth-child(2) { grid-area: 1/1/2/2; }
.hover-3d > :nth-child(3) { grid-area: 1/2/2/3; }
.hover-3d > :nth-child(4) { grid-area: 1/3/2/4; }
@@ -73,58 +63,14 @@
0 2px 6px rgba(0,0,0,0.12);
}
.hover-3d:hover > .hover-3d-content {
--ease-out: var(--ease-hover);
scale: 1.055;
}
.hover-3d:hover > .hover-3d-content { --ease-out: var(--ease-hover); scale: 1.055; }
.shine {
pointer-events: none;
position: absolute;
inset: 0;
z-index: 2;
opacity: 0;
border-radius: inherit;
background-image: radial-gradient(
ellipse 80% 60% at var(--shine-x) var(--shine-y),
rgba(255,255,255,0.22) 0%,
rgba(255,255,255,0.08) 30%,
transparent 65%
);
transition: opacity ease-out 350ms;
mix-blend-mode: screen;
}
.hover-3d:hover .shine { opacity: 1; }
.edge-top {
pointer-events: none;
position: absolute;
top: 0; left: 0; right: 0;
height: 1px;
z-index: 3;
background: linear-gradient(90deg, transparent 10%, rgba(255,255,255,0.18) 50%, transparent 90%);
opacity: 0;
transition: opacity ease-out 350ms;
}
.edge-left {
pointer-events: none;
position: absolute;
top: 0; left: 0; bottom: 0;
width: 1px;
z-index: 3;
background: linear-gradient(180deg, transparent 10%, rgba(255,255,255,0.12) 50%, transparent 90%);
opacity: 0;
transition: opacity ease-out 350ms;
}
.hover-3d:hover .edge-top,
.hover-3d:hover .edge-left { opacity: 1; }
.hover-3d:has(> :nth-child(2):hover) { --tx: -1; --ty: 1; --shine-x: 15%; --shine-y: 15%; --shadow-x: -8px; --shadow-y: -8px; }
.hover-3d:has(> :nth-child(3):hover) { --tx: -1; --ty: 0; --shine-x: 50%; --shine-y: 10%; --shadow-x: 0px; --shadow-y: -8px; }
.hover-3d:has(> :nth-child(4):hover) { --tx: -1; --ty: -1; --shine-x: 85%; --shine-y: 15%; --shadow-x: 8px; --shadow-y: -8px; }
.hover-3d:has(> :nth-child(5):hover) { --tx: 0; --ty: 1; --shine-x: 10%; --shine-y: 50%; --shadow-x: -8px; --shadow-y: 0px; }
.hover-3d:has(> :nth-child(6):hover) { --tx: 0; --ty: -1; --shine-x: 90%; --shine-y: 50%; --shadow-x: 8px; --shadow-y: 0px; }
.hover-3d:has(> :nth-child(7):hover) { --tx: 1; --ty: 1; --shine-x: 15%; --shine-y: 85%; --shadow-x: -8px; --shadow-y: 8px; }
.hover-3d:has(> :nth-child(8):hover) { --tx: 1; --ty: 0; --shine-x: 50%; --shine-y: 90%; --shadow-x: 0px; --shadow-y: 8px; }
.hover-3d:has(> :nth-child(9):hover) { --tx: 1; --ty: -1; --shine-x: 85%; --shine-y: 85%; --shadow-x: 8px; --shadow-y: 8px; }
.hover-3d:has(> :nth-child(2):hover) { --tx: -1; --ty: 1; --shadow-x: -8px; --shadow-y: -8px; }
.hover-3d:has(> :nth-child(3):hover) { --tx: -1; --ty: 0; --shadow-x: 0px; --shadow-y: -8px; }
.hover-3d:has(> :nth-child(4):hover) { --tx: -1; --ty: -1; --shadow-x: 8px; --shadow-y: -8px; }
.hover-3d:has(> :nth-child(5):hover) { --tx: 0; --ty: 1; --shadow-x: -8px; --shadow-y: 0px; }
.hover-3d:has(> :nth-child(6):hover) { --tx: 0; --ty: -1; --shadow-x: 8px; --shadow-y: 0px; }
.hover-3d:has(> :nth-child(7):hover) { --tx: 1; --ty: 1; --shadow-x: -8px; --shadow-y: 8px; }
.hover-3d:has(> :nth-child(8):hover) { --tx: 1; --ty: 0; --shadow-x: 0px; --shadow-y: 8px; }
.hover-3d:has(> :nth-child(9):hover) { --tx: 1; --ty: -1; --shadow-x: 8px; --shadow-y: 8px; }
</style>
@@ -1,7 +1,6 @@
<script lang="ts">
import { settings } from "$lib/state/settings.svelte";
import { getBlobUrl } from "$lib/core/cache/imageCache";
import { platformService } from "$lib/platform-service/index";
import { settingsState } from "$lib/state/settings.svelte";
import { getBlobUrl } from "$lib/core/cache/imageCache";
let {
src,
@@ -23,7 +22,18 @@
[key: string]: any;
} = $props();
const isAuth = $derived((settings.serverAuthMode ?? "NONE") !== "NONE");
function getServerUrl(): string {
const url = settingsState.settings.serverUrl;
return typeof url === "string" && url.trim() ? url.replace(/\/$/, "") : "http://127.0.0.1:4567";
}
function plainThumbUrl(path: string): string {
if (!path) return "";
if (path.startsWith("http")) return path;
return `${getServerUrl()}${path}`;
}
const isAuth = $derived((settingsState.settings.serverAuthMode ?? "NONE") !== "NONE");
let blobUrl = $state("");
let reqId = 0;
@@ -35,8 +45,8 @@
if (!_isAuth || !_src) { blobUrl = ""; return; }
const id = ++reqId;
const bareUrl = _src.startsWith("http") ? _src : `${platformService.getServerUrl()}${_src}`;
const id = ++reqId;
const bareUrl = _src.startsWith("http") ? _src : `${getServerUrl()}${_src}`;
getBlobUrl(bareUrl, _priority)
.then(u => { if (id === reqId) blobUrl = u; })
.catch(() => { if (id === reqId) blobUrl = ""; });
@@ -45,7 +55,7 @@
const resolved = $derived(
isAuth
? (blobUrl || undefined)
: (src ? platformService.plainThumbUrl(src) : undefined)
: (src ? plainThumbUrl(src) : undefined)
);
</script>