generated from Nodarx/template
refactor: interface names and properties
Signed-off-by: Sebastian <krupinski01@gmail.com>
This commit is contained in:
@@ -1,18 +1,12 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, watch, defineAsyncComponent, onUnmounted } from 'vue'
|
||||
import type { MediaItem, ResolveSource, MediaPresentation } from '@/types'
|
||||
import type { MediaItem, MediaSource, MediaPresentation } from '@/types'
|
||||
import { findViewer } from '@/services/viewer'
|
||||
|
||||
/**
|
||||
* MediaStage renders a single MediaItem: it resolves the matching leaf viewer
|
||||
* by MIME type, resolves the item's source (URL string used as-is, or a Blob
|
||||
* turned into a tracked object URL), and renders the leaf. Surfaces (dialog,
|
||||
* popover) wrap the stage and provide chrome.
|
||||
*/
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
item: MediaItem | null
|
||||
resolveSource: ResolveSource
|
||||
source: MediaSource
|
||||
presentation?: MediaPresentation
|
||||
}>(),
|
||||
{ presentation: 'fullscreen' },
|
||||
@@ -48,7 +42,7 @@ async function load(item: MediaItem | null) {
|
||||
loading.value = true
|
||||
const token = item.id
|
||||
try {
|
||||
const src = await props.resolveSource(item)
|
||||
const src = await props.source(item)
|
||||
// Guard against races: a faster navigation may have changed the item.
|
||||
if (props.item?.id !== token) return
|
||||
if (typeof src === 'string') {
|
||||
|
||||
@@ -1,21 +1,15 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, onMounted, onUnmounted } from 'vue'
|
||||
import type { MediaItem, ResolveSource } from '@/types'
|
||||
import type { MediaItem, MediaSource } from '@/types'
|
||||
import { findViewer } from '@/services/viewer.ts'
|
||||
import MediaStage from './MediaStage.vue'
|
||||
|
||||
/**
|
||||
* Fullscreen media viewer surface. Generic: driven entirely by `MediaItem`s and
|
||||
* a host-supplied `resolveSource`. Prev/next navigation is opt-in via
|
||||
* `navigation` and is suppressed for `standalone` viewers (which bring their
|
||||
* own chrome) so their controls never compete with a "next file" arrow.
|
||||
*/
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
modelValue: boolean
|
||||
items: MediaItem[]
|
||||
index: number
|
||||
resolveSource: ResolveSource
|
||||
source: MediaSource
|
||||
/** Triggers a host download of the given item. */
|
||||
download?: (item: MediaItem) => void
|
||||
/** Enable prev/next gallery navigation across `items`. */
|
||||
@@ -132,7 +126,7 @@ onUnmounted(() => window.removeEventListener('keydown', handleKeydown))
|
||||
|
||||
<!-- Stage -->
|
||||
<div class="viewer-stage">
|
||||
<MediaStage :item="currentItem" :resolve-source="resolveSource">
|
||||
<MediaStage :item="currentItem" :source="source">
|
||||
<template #unsupported="{ mime }">
|
||||
<div class="viewer-no-preview">
|
||||
<v-icon size="64" color="grey-lighten-1">mdi-file-question-outline</v-icon>
|
||||
|
||||
@@ -1,23 +1,13 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import type { MediaItem, ResolveSource } from '@/types'
|
||||
import type { MediaItem, MediaSource } from '@/types'
|
||||
import { findViewer } from '@/services/viewer.ts'
|
||||
import MediaStage from './MediaStage.vue'
|
||||
|
||||
/**
|
||||
* Lightweight hover-preview surface. Mounted inside a host trigger element and
|
||||
* anchored to it via Vuetify's `activator="parent"`, so the host only needs to
|
||||
* drop this component into the element it wants previewed.
|
||||
*
|
||||
* The menu renders its content lazily, so the source (and any blob fetch) is
|
||||
* only resolved once the menu actually opens after `openDelay` — a quick
|
||||
* fly-over never triggers a fetch. Clicking the preview emits `expand` so the
|
||||
* host can open the fullscreen viewer.
|
||||
*/
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
item: MediaItem | null
|
||||
resolveSource: ResolveSource
|
||||
source: MediaSource
|
||||
/** Hover dwell before opening, in ms. */
|
||||
openDelay?: number
|
||||
}>(),
|
||||
@@ -54,7 +44,7 @@ function expand() {
|
||||
>
|
||||
<v-card class="media-popover" @click="expand">
|
||||
<div class="media-popover__stage">
|
||||
<MediaStage :item="item" :resolve-source="resolveSource" presentation="popover" />
|
||||
<MediaStage :item="item" :source="source" presentation="popover" />
|
||||
</div>
|
||||
<div class="media-popover__hint text-caption text-medium-emphasis">
|
||||
Click to open
|
||||
|
||||
+2
-2
@@ -2,7 +2,7 @@ import integrations from '@/integrations'
|
||||
import type {
|
||||
MediaItem,
|
||||
MediaSource,
|
||||
ResolveSource,
|
||||
MediaBlob,
|
||||
MediaLeafProps,
|
||||
MediaPresentation,
|
||||
MediaViewerMode,
|
||||
@@ -16,7 +16,7 @@ export { integrations }
|
||||
export type {
|
||||
MediaItem,
|
||||
MediaSource,
|
||||
ResolveSource,
|
||||
MediaBlob,
|
||||
MediaLeafProps,
|
||||
MediaPresentation,
|
||||
MediaViewerMode,
|
||||
|
||||
+3
-3
@@ -9,11 +9,11 @@ export interface MediaItem {
|
||||
meta?: Record<string, unknown>
|
||||
}
|
||||
|
||||
export type MediaSource = string | Blob
|
||||
export type MediaBlob = string | Blob
|
||||
|
||||
export type ResolveSource = (
|
||||
export type MediaSource = (
|
||||
item: MediaItem,
|
||||
) => MediaSource | Promise<MediaSource>
|
||||
) => MediaBlob | Promise<MediaBlob>
|
||||
|
||||
/** Surface a host renders the stage in. */
|
||||
export type MediaPresentation = 'popover' | 'fullscreen'
|
||||
|
||||
Reference in New Issue
Block a user