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">
|
<script setup lang="ts">
|
||||||
import { ref, computed, watch, defineAsyncComponent, onUnmounted } from 'vue'
|
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'
|
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(
|
const props = withDefaults(
|
||||||
defineProps<{
|
defineProps<{
|
||||||
item: MediaItem | null
|
item: MediaItem | null
|
||||||
resolveSource: ResolveSource
|
source: MediaSource
|
||||||
presentation?: MediaPresentation
|
presentation?: MediaPresentation
|
||||||
}>(),
|
}>(),
|
||||||
{ presentation: 'fullscreen' },
|
{ presentation: 'fullscreen' },
|
||||||
@@ -48,7 +42,7 @@ async function load(item: MediaItem | null) {
|
|||||||
loading.value = true
|
loading.value = true
|
||||||
const token = item.id
|
const token = item.id
|
||||||
try {
|
try {
|
||||||
const src = await props.resolveSource(item)
|
const src = await props.source(item)
|
||||||
// Guard against races: a faster navigation may have changed the item.
|
// Guard against races: a faster navigation may have changed the item.
|
||||||
if (props.item?.id !== token) return
|
if (props.item?.id !== token) return
|
||||||
if (typeof src === 'string') {
|
if (typeof src === 'string') {
|
||||||
|
|||||||
@@ -1,21 +1,15 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, onMounted, onUnmounted } from 'vue'
|
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 { findViewer } from '@/services/viewer.ts'
|
||||||
import MediaStage from './MediaStage.vue'
|
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(
|
const props = withDefaults(
|
||||||
defineProps<{
|
defineProps<{
|
||||||
modelValue: boolean
|
modelValue: boolean
|
||||||
items: MediaItem[]
|
items: MediaItem[]
|
||||||
index: number
|
index: number
|
||||||
resolveSource: ResolveSource
|
source: MediaSource
|
||||||
/** Triggers a host download of the given item. */
|
/** Triggers a host download of the given item. */
|
||||||
download?: (item: MediaItem) => void
|
download?: (item: MediaItem) => void
|
||||||
/** Enable prev/next gallery navigation across `items`. */
|
/** Enable prev/next gallery navigation across `items`. */
|
||||||
@@ -132,7 +126,7 @@ onUnmounted(() => window.removeEventListener('keydown', handleKeydown))
|
|||||||
|
|
||||||
<!-- Stage -->
|
<!-- Stage -->
|
||||||
<div class="viewer-stage">
|
<div class="viewer-stage">
|
||||||
<MediaStage :item="currentItem" :resolve-source="resolveSource">
|
<MediaStage :item="currentItem" :source="source">
|
||||||
<template #unsupported="{ mime }">
|
<template #unsupported="{ mime }">
|
||||||
<div class="viewer-no-preview">
|
<div class="viewer-no-preview">
|
||||||
<v-icon size="64" color="grey-lighten-1">mdi-file-question-outline</v-icon>
|
<v-icon size="64" color="grey-lighten-1">mdi-file-question-outline</v-icon>
|
||||||
|
|||||||
@@ -1,23 +1,13 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed } from 'vue'
|
import { computed } from 'vue'
|
||||||
import type { MediaItem, ResolveSource } from '@/types'
|
import type { MediaItem, MediaSource } from '@/types'
|
||||||
import { findViewer } from '@/services/viewer.ts'
|
import { findViewer } from '@/services/viewer.ts'
|
||||||
import MediaStage from './MediaStage.vue'
|
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(
|
const props = withDefaults(
|
||||||
defineProps<{
|
defineProps<{
|
||||||
item: MediaItem | null
|
item: MediaItem | null
|
||||||
resolveSource: ResolveSource
|
source: MediaSource
|
||||||
/** Hover dwell before opening, in ms. */
|
/** Hover dwell before opening, in ms. */
|
||||||
openDelay?: number
|
openDelay?: number
|
||||||
}>(),
|
}>(),
|
||||||
@@ -54,7 +44,7 @@ function expand() {
|
|||||||
>
|
>
|
||||||
<v-card class="media-popover" @click="expand">
|
<v-card class="media-popover" @click="expand">
|
||||||
<div class="media-popover__stage">
|
<div class="media-popover__stage">
|
||||||
<MediaStage :item="item" :resolve-source="resolveSource" presentation="popover" />
|
<MediaStage :item="item" :source="source" presentation="popover" />
|
||||||
</div>
|
</div>
|
||||||
<div class="media-popover__hint text-caption text-medium-emphasis">
|
<div class="media-popover__hint text-caption text-medium-emphasis">
|
||||||
Click to open
|
Click to open
|
||||||
|
|||||||
+2
-2
@@ -2,7 +2,7 @@ import integrations from '@/integrations'
|
|||||||
import type {
|
import type {
|
||||||
MediaItem,
|
MediaItem,
|
||||||
MediaSource,
|
MediaSource,
|
||||||
ResolveSource,
|
MediaBlob,
|
||||||
MediaLeafProps,
|
MediaLeafProps,
|
||||||
MediaPresentation,
|
MediaPresentation,
|
||||||
MediaViewerMode,
|
MediaViewerMode,
|
||||||
@@ -16,7 +16,7 @@ export { integrations }
|
|||||||
export type {
|
export type {
|
||||||
MediaItem,
|
MediaItem,
|
||||||
MediaSource,
|
MediaSource,
|
||||||
ResolveSource,
|
MediaBlob,
|
||||||
MediaLeafProps,
|
MediaLeafProps,
|
||||||
MediaPresentation,
|
MediaPresentation,
|
||||||
MediaViewerMode,
|
MediaViewerMode,
|
||||||
|
|||||||
+3
-3
@@ -9,11 +9,11 @@ export interface MediaItem {
|
|||||||
meta?: Record<string, unknown>
|
meta?: Record<string, unknown>
|
||||||
}
|
}
|
||||||
|
|
||||||
export type MediaSource = string | Blob
|
export type MediaBlob = string | Blob
|
||||||
|
|
||||||
export type ResolveSource = (
|
export type MediaSource = (
|
||||||
item: MediaItem,
|
item: MediaItem,
|
||||||
) => MediaSource | Promise<MediaSource>
|
) => MediaBlob | Promise<MediaBlob>
|
||||||
|
|
||||||
/** Surface a host renders the stage in. */
|
/** Surface a host renders the stage in. */
|
||||||
export type MediaPresentation = 'popover' | 'fullscreen'
|
export type MediaPresentation = 'popover' | 'fullscreen'
|
||||||
|
|||||||
Reference in New Issue
Block a user