feat: attachment preview

Signed-off-by: Sebastian <krupinski01@gmail.com>
This commit is contained in:
2026-06-18 19:07:39 -04:00
parent 0af38cf50c
commit 34dc636d13
6 changed files with 197 additions and 13 deletions
+48
View File
@@ -0,0 +1,48 @@
/**
* mediaViewer — bridges the Mail UI to the standalone media_viewer module
*/
import { defineAsyncComponent } from 'vue'
import { useIntegrationStore } from '@KTXC'
const MEDIA_VIEWER_FORMAT_POINT = 'media_viewer_format'
const MEDIA_VIEWER_POINT = 'media_viewer'
function mimeMatchesPattern(mime: string, pattern: string): boolean {
if (pattern.endsWith('/*')) {
return mime.startsWith(pattern.slice(0, -1))
}
return mime === pattern
}
function mimeMatchesViewer(mime: string, mimeTypes?: string[], mimePatterns?: string[]): boolean {
if (mimeTypes?.includes(mime)) return true
if (mimePatterns) {
for (const pattern of mimePatterns) {
if (mimeMatchesPattern(mime, pattern)) return true
}
}
return false
}
/** True if a leaf viewer is registered for this MIME type. */
export function mediaViewerCanDisplay(mime: string | null | undefined): boolean {
if (!mime) return false
const viewers = useIntegrationStore().getItems(MEDIA_VIEWER_FORMAT_POINT)
return viewers.some(viewer =>
mimeMatchesViewer(
mime,
viewer.meta?.mimeTypes as string[] | undefined,
viewer.meta?.mimePatterns as string[] | undefined,
),
)
}
export function mediaViewerComponent(type: 'dialog' | 'popover' = 'dialog') {
// The integration store prefixes ids with the module handle
// (e.g. 'media_viewer.dialog'), so match on the suffix.
const entry = useIntegrationStore().getItems(MEDIA_VIEWER_POINT).find(i => i.id.endsWith(`.${type}`))
return entry?.component
? defineAsyncComponent(entry.component as () => Promise<unknown>)
: null
}