refactor: interface names and properties

Signed-off-by: Sebastian <krupinski01@gmail.com>
This commit is contained in:
2026-06-18 19:19:53 -04:00
parent 4e302ea923
commit 380d8cf65e
5 changed files with 14 additions and 36 deletions
+3 -9
View File
@@ -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') {
+3 -9
View File
@@ -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>
+3 -13
View File
@@ -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
View File
@@ -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
View File
@@ -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'