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