Browse Source
Reviewed-on: https://gitea.anomalistdesign.com/trent_larson/crowd-funder-for-time-pwa/pulls/125d9085ced6df7dc7bdcd899959cea6489cab7f8b8
6 changed files with 161 additions and 17 deletions
@ -0,0 +1,97 @@ |
|||
<template> |
|||
<Teleport to="body"> |
|||
<Transition name="fade"> |
|||
<div |
|||
v-if="isOpen" |
|||
class="fixed inset-0 z-50 flex flex-col bg-black/90" |
|||
> |
|||
<!-- Header bar - fixed height to prevent overlap --> |
|||
<div class="h-16 flex justify-between items-center px-4 bg-black"> |
|||
<button |
|||
class="text-white text-2xl p-2 rounded-full hover:bg-white/10" |
|||
@click="close" |
|||
> |
|||
<fa icon="xmark" /> |
|||
</button> |
|||
|
|||
<!-- Mobile share button --> |
|||
<button |
|||
v-if="isMobile" |
|||
class="text-white text-xl p-2 rounded-full hover:bg-white/10" |
|||
@click="handleShare" |
|||
> |
|||
<fa icon="ellipsis" /> |
|||
</button> |
|||
</div> |
|||
|
|||
<!-- Image container - fill remaining space --> |
|||
<div class="flex-1 flex items-center justify-center p-2"> |
|||
<div class="w-full h-full flex items-center justify-center"> |
|||
<img |
|||
:src="imageUrl" |
|||
class="max-h-[calc(100vh-5rem)] w-full h-full object-contain" |
|||
@click.stop |
|||
alt="expanded shared content" |
|||
/> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</Transition> |
|||
</Teleport> |
|||
</template> |
|||
|
|||
<script lang="ts"> |
|||
import { Component, Vue, Prop } from "vue-facing-decorator"; |
|||
import { UAParser } from "ua-parser-js"; |
|||
|
|||
@Component({ emits: ["update:isOpen"] }) |
|||
export default class ImageViewer extends Vue { |
|||
@Prop() imageUrl!: string; |
|||
@Prop() imageData!: Blob | null; |
|||
@Prop() isOpen!: boolean; |
|||
|
|||
userAgent = new UAParser(); |
|||
|
|||
get isMobile() { |
|||
const os = this.userAgent.getOS().name; |
|||
return os === "iOS" || os === "Android"; |
|||
} |
|||
|
|||
close() { |
|||
this.$emit("update:isOpen", false); |
|||
} |
|||
|
|||
async handleShare() { |
|||
const os = this.userAgent.getOS().name; |
|||
|
|||
try { |
|||
if (os === "iOS" || os === "Android") { |
|||
if (navigator.share) { |
|||
// Always share the URL since it's more reliable across platforms |
|||
await navigator.share({ |
|||
url: this.imageUrl |
|||
}); |
|||
} else { |
|||
// Fallback for browsers without share API |
|||
window.open(this.imageUrl, "_blank"); |
|||
} |
|||
} |
|||
} catch (error) { |
|||
console.warn("Share failed, opening in new tab:", error); |
|||
window.open(this.imageUrl, "_blank"); |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style scoped> |
|||
.fade-enter-active, |
|||
.fade-leave-active { |
|||
transition: opacity 0.2s ease; |
|||
} |
|||
|
|||
.fade-enter-from, |
|||
.fade-leave-to { |
|||
opacity: 0; |
|||
} |
|||
</style> |
Loading…
Reference in new issue