feat(frontend): add plyr to preview videos
This commit is contained in:
@@ -47,5 +47,8 @@
|
||||
"vite": "^7.3.1",
|
||||
"vitest": "^4.1.0",
|
||||
"vitest-browser-svelte": "^2.0.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"plyr": "^3.8.4"
|
||||
}
|
||||
}
|
||||
|
||||
40
frontend/pnpm-lock.yaml
generated
40
frontend/pnpm-lock.yaml
generated
@@ -7,6 +7,10 @@ settings:
|
||||
importers:
|
||||
|
||||
.:
|
||||
dependencies:
|
||||
plyr:
|
||||
specifier: ^3.8.4
|
||||
version: 3.8.4
|
||||
devDependencies:
|
||||
'@eslint/compat':
|
||||
specifier: ^2.0.3
|
||||
@@ -811,6 +815,9 @@ packages:
|
||||
resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==}
|
||||
engines: {node: '>= 0.6'}
|
||||
|
||||
core-js@3.49.0:
|
||||
resolution: {integrity: sha512-es1U2+YTtzpwkxVLwAFdSpaIMyQaq0PBgm3YD1W3Qpsn1NAmO3KSgZfu+oGSWVu6NvLHoHCV/aYcsE5wiB7ALg==}
|
||||
|
||||
cross-spawn@7.0.6:
|
||||
resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
|
||||
engines: {node: '>= 8'}
|
||||
@@ -820,6 +827,9 @@ packages:
|
||||
engines: {node: '>=4'}
|
||||
hasBin: true
|
||||
|
||||
custom-event-polyfill@1.0.7:
|
||||
resolution: {integrity: sha512-TDDkd5DkaZxZFM8p+1I3yAlvM3rSr1wbrOliG4yJiwinMZN8z/iGL7BTlDkrJcYTmgUSb4ywVCc3ZaUtOtC76w==}
|
||||
|
||||
debug@4.4.3:
|
||||
resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==}
|
||||
engines: {node: '>=6.0'}
|
||||
@@ -1127,6 +1137,9 @@ packages:
|
||||
resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
loadjs@4.3.0:
|
||||
resolution: {integrity: sha512-vNX4ZZLJBeDEOBvdr2v/F+0aN5oMuPu7JTqrMwp+DtgK+AryOlpy6Xtm2/HpNr+azEa828oQjOtWsB6iDtSfSQ==}
|
||||
|
||||
locate-character@3.0.0:
|
||||
resolution: {integrity: sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==}
|
||||
|
||||
@@ -1207,6 +1220,9 @@ packages:
|
||||
engines: {node: '>=18'}
|
||||
hasBin: true
|
||||
|
||||
plyr@3.8.4:
|
||||
resolution: {integrity: sha512-DrzLbK9Wol3zeiuZCleD9aUOl0KAaBHR9H6WVVVYPZ4Ya+LYxUFTgSF1jooHcMQCv96Ws96wCaZzIoP3bES8pQ==}
|
||||
|
||||
pngjs@7.0.0:
|
||||
resolution: {integrity: sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow==}
|
||||
engines: {node: '>=14.19.0'}
|
||||
@@ -1321,6 +1337,9 @@ packages:
|
||||
resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
rangetouch@2.0.1:
|
||||
resolution: {integrity: sha512-sln+pNSc8NGaHoLzwNBssFSf/rSYkqeBXzX1AtJlkJiUaVSJSbRAWJk+4omsXkN+EJalzkZhWQ3th1m0FpR5xA==}
|
||||
|
||||
readdirp@4.1.2:
|
||||
resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==}
|
||||
engines: {node: '>= 14.18.0'}
|
||||
@@ -1442,6 +1461,9 @@ packages:
|
||||
uri-js@4.4.1:
|
||||
resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
|
||||
|
||||
url-polyfill@1.1.14:
|
||||
resolution: {integrity: sha512-p4f3TTAG6ADVF3mwbXw7hGw+QJyw5CnNGvYh5fCuQQZIiuKUswqcznyV3pGDP9j0TSmC4UvRKm8kl1QsX1diiQ==}
|
||||
|
||||
util-deprecate@1.0.2:
|
||||
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
|
||||
|
||||
@@ -2163,6 +2185,8 @@ snapshots:
|
||||
|
||||
cookie@0.6.0: {}
|
||||
|
||||
core-js@3.49.0: {}
|
||||
|
||||
cross-spawn@7.0.6:
|
||||
dependencies:
|
||||
path-key: 3.1.1
|
||||
@@ -2171,6 +2195,8 @@ snapshots:
|
||||
|
||||
cssesc@3.0.0: {}
|
||||
|
||||
custom-event-polyfill@1.0.7: {}
|
||||
|
||||
debug@4.4.3:
|
||||
dependencies:
|
||||
ms: 2.1.3
|
||||
@@ -2467,6 +2493,8 @@ snapshots:
|
||||
|
||||
lilconfig@2.1.0: {}
|
||||
|
||||
loadjs@4.3.0: {}
|
||||
|
||||
locate-character@3.0.0: {}
|
||||
|
||||
locate-path@6.0.0:
|
||||
@@ -2530,6 +2558,14 @@ snapshots:
|
||||
optionalDependencies:
|
||||
fsevents: 2.3.2
|
||||
|
||||
plyr@3.8.4:
|
||||
dependencies:
|
||||
core-js: 3.49.0
|
||||
custom-event-polyfill: 1.0.7
|
||||
loadjs: 4.3.0
|
||||
rangetouch: 2.0.1
|
||||
url-polyfill: 1.1.14
|
||||
|
||||
pngjs@7.0.0: {}
|
||||
|
||||
postcss-load-config@3.1.4(postcss@8.5.8):
|
||||
@@ -2580,6 +2616,8 @@ snapshots:
|
||||
|
||||
punycode@2.3.1: {}
|
||||
|
||||
rangetouch@2.0.1: {}
|
||||
|
||||
readdirp@4.1.2: {}
|
||||
|
||||
rollup@4.60.1:
|
||||
@@ -2728,6 +2766,8 @@ snapshots:
|
||||
dependencies:
|
||||
punycode: 2.3.1
|
||||
|
||||
url-polyfill@1.1.14: {}
|
||||
|
||||
util-deprecate@1.0.2: {}
|
||||
|
||||
vite@7.3.1(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.32.0):
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
<script lang="ts">
|
||||
import type { FileRecord } from '$lib/types';
|
||||
import { fade } from 'svelte/transition';
|
||||
import VideoPreview from './VideoPreview.svelte';
|
||||
|
||||
let { file, onclose }: { file: FileRecord; onclose: () => void } = $props();
|
||||
const isVideo = $derived(file.fileType.includes('video'));
|
||||
</script>
|
||||
|
||||
<svelte:window
|
||||
@@ -14,18 +16,24 @@
|
||||
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
||||
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
||||
<div
|
||||
class="fixed inset-0 z-50 flex items-center justify-center bg-black/60"
|
||||
class="fixed inset-0 z-50 flex items-center justify-center bg-black/60 p-4"
|
||||
onclick={onclose}
|
||||
transition:fade={{ duration: 150 }}
|
||||
>
|
||||
<div
|
||||
class="flex h-2/3 w-2/3 flex-col rounded-sm border border-sky-200/20 bg-[#0f1117] p-6"
|
||||
class="relative aspect-video h-[85vh] max-w-[95vw] overflow-hidden rounded-xl border border-sky-200/20 bg-[#0f1117]"
|
||||
onclick={(e) => e.stopPropagation()}
|
||||
>
|
||||
<div class="mb-4 flex items-center justify-between">
|
||||
<span class="text-sm font-medium text-white">{file.name}</span>
|
||||
{#if isVideo}
|
||||
<VideoPreview src={`/api/files/${file.id}/download`} />
|
||||
<div
|
||||
class="pointer-events-none absolute inset-x-0 top-0 z-10 flex items-center justify-between bg-linear-to-b from-black/70 to-transparent px-4 py-3"
|
||||
>
|
||||
<span class="pointer-events-auto truncate pr-3 text-sm font-medium text-white"
|
||||
>{file.name}</span
|
||||
>
|
||||
<button
|
||||
class="cursor-pointer text-white/40 transition-colors hover:text-white"
|
||||
class="pointer-events-auto cursor-pointer text-white/70 transition-colors hover:text-white"
|
||||
onclick={onclose}
|
||||
aria-label="Close"
|
||||
>
|
||||
@@ -44,8 +52,10 @@
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<div class="flex flex-1 items-center justify-center text-sm text-white/20">
|
||||
preview coming soon
|
||||
</div>
|
||||
{:else}
|
||||
<div class="flex h-full w-full items-center justify-center text-sm text-white/40">
|
||||
No preview available
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
28
frontend/src/lib/components/VideoPreview.svelte
Normal file
28
frontend/src/lib/components/VideoPreview.svelte
Normal file
@@ -0,0 +1,28 @@
|
||||
<script lang="ts">
|
||||
import Plyr from 'plyr';
|
||||
import 'plyr/dist/plyr.css';
|
||||
|
||||
let { src }: { src: string } = $props();
|
||||
let videoElement: HTMLVideoElement;
|
||||
|
||||
$effect(() => {
|
||||
const player = new Plyr(videoElement, {
|
||||
ratio: '16:9',
|
||||
controls: [
|
||||
'play-large',
|
||||
'play',
|
||||
'progress',
|
||||
'current-time',
|
||||
'mute',
|
||||
'volume',
|
||||
'captions',
|
||||
'settings',
|
||||
'fullscreen'
|
||||
]
|
||||
});
|
||||
return () => player.destroy();
|
||||
});
|
||||
</script>
|
||||
|
||||
<!-- svelte-ignore a11y_media_has_caption -->
|
||||
<video bind:this={videoElement} {src} poster="/video-placeholder.png" playsinline controls></video>
|
||||
@@ -2,5 +2,6 @@ export type FileRecord = {
|
||||
id: number;
|
||||
name: string;
|
||||
size: number;
|
||||
fileType: string;
|
||||
uploadedAt: string;
|
||||
};
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
@import 'tailwindcss';
|
||||
@plugin '@tailwindcss/forms';
|
||||
@plugin '@tailwindcss/typography';
|
||||
@import '@fontsource/fira-mono';
|
||||
|
||||
:root {
|
||||
@@ -13,6 +11,8 @@
|
||||
--column-margin-top: 4rem;
|
||||
font-family: var(--font-body);
|
||||
color: var(--color-text);
|
||||
--plyr-color-main: var(--color-sky-400);
|
||||
--plyr-video-background: #0f1117;
|
||||
}
|
||||
|
||||
body {
|
||||
|
||||
Reference in New Issue
Block a user