forked from trent_larson/crowd-funder-for-time-pwa
- Fix Vue template syntax in App.vue by using proper event handler format - Update Vite config to properly handle ESM imports and crypto modules - Add manual chunks for better code splitting - Improve environment variable handling in vite-env.d.ts - Fix TypeScript linting errors in App.vue
182 lines
4.8 KiB
Vue
182 lines
4.8 KiB
Vue
<template>
|
|
<div v-if="visible" class="dialog-overlay z-[60]">
|
|
<div class="dialog relative">
|
|
<div class="text-lg text-center font-light relative z-50">
|
|
<div
|
|
id="ViewHeading"
|
|
class="text-center font-bold absolute top-0 left-0 right-0 px-4 py-0.5 bg-black/50 text-white leading-none"
|
|
>
|
|
Add Photo
|
|
</div>
|
|
<div
|
|
class="text-lg text-center px-2 py-0.5 leading-none absolute right-0 top-0 text-white"
|
|
@click="close()"
|
|
>
|
|
<font-awesome icon="xmark" class="w-[1em]" />
|
|
</div>
|
|
</div>
|
|
|
|
<div>
|
|
<div class="text-center mt-8">
|
|
<div>
|
|
<font-awesome
|
|
icon="camera"
|
|
class="bg-gradient-to-b from-blue-400 to-blue-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white px-2 py-2 rounded-md"
|
|
@click="openPhotoDialog()"
|
|
/>
|
|
</div>
|
|
<div class="mt-4">
|
|
<input type="file" @change="uploadImageFile" />
|
|
</div>
|
|
<div class="mt-4">
|
|
<span class="mt-2">
|
|
... or paste a URL:
|
|
<input v-model="imageUrl" type="text" class="border-2" />
|
|
</span>
|
|
<span class="ml-2">
|
|
<font-awesome
|
|
v-if="imageUrl"
|
|
icon="check"
|
|
class="bg-gradient-to-b from-blue-400 to-blue-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white px-2 py-2 rounded-md cursor-pointer"
|
|
@click="acceptUrl"
|
|
/>
|
|
<!-- so that there's no shifting when it becomes visible -->
|
|
<font-awesome
|
|
v-else
|
|
icon="check"
|
|
class="text-white bg-white px-2 py-2"
|
|
/>
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<PhotoDialog ref="photoDialog" />
|
|
</template>
|
|
|
|
<script lang="ts">
|
|
import axios from 'axios'
|
|
import { ref } from 'vue'
|
|
import { Component, Vue } from 'vue-facing-decorator'
|
|
|
|
import PhotoDialog from '../components/PhotoDialog.vue'
|
|
import { NotificationIface } from '../constants/app'
|
|
|
|
const inputImageFileNameRef = ref<Blob>()
|
|
|
|
@Component({
|
|
components: { PhotoDialog }
|
|
})
|
|
export default class ImageMethodDialog extends Vue {
|
|
$notify!: (notification: NotificationIface, timeout?: number) => void
|
|
|
|
claimType: string
|
|
crop: boolean = false
|
|
imageCallback: (imageUrl?: string) => void = () => {}
|
|
imageUrl?: string
|
|
visible = false
|
|
|
|
open(setImageFn: (arg: string) => void, claimType: string, crop?: boolean) {
|
|
this.claimType = claimType
|
|
this.crop = !!crop
|
|
this.imageCallback = setImageFn
|
|
|
|
this.visible = true
|
|
}
|
|
|
|
openPhotoDialog(blob?: Blob, fileName?: string) {
|
|
this.visible = false
|
|
;(this.$refs.photoDialog as PhotoDialog).open(
|
|
this.imageCallback,
|
|
this.claimType,
|
|
this.crop,
|
|
blob,
|
|
fileName
|
|
)
|
|
}
|
|
|
|
async uploadImageFile(event: Event) {
|
|
this.visible = false
|
|
|
|
inputImageFileNameRef.value = event.target.files[0]
|
|
// https://developer.mozilla.org/en-US/docs/Web/API/File
|
|
// ... plus it has a `type` property from my testing
|
|
const file = inputImageFileNameRef.value
|
|
if (file != null) {
|
|
const reader = new FileReader()
|
|
reader.onload = async (e) => {
|
|
const data = e.target?.result as ArrayBuffer
|
|
if (data) {
|
|
const blob = new Blob([new Uint8Array(data)], {
|
|
type: file.type
|
|
})
|
|
this.openPhotoDialog(blob, file.name as string)
|
|
}
|
|
}
|
|
reader.readAsArrayBuffer(file as Blob)
|
|
}
|
|
}
|
|
|
|
async acceptUrl() {
|
|
this.visible = false
|
|
if (this.crop) {
|
|
try {
|
|
const urlBlobResponse: Blob = await axios.get(this.imageUrl as string, {
|
|
responseType: 'blob' // This ensures the data is returned as a Blob
|
|
})
|
|
const fullUrl = new URL(this.imageUrl as string)
|
|
const fileName = fullUrl.pathname.split('/').pop() as string
|
|
;(this.$refs.photoDialog as PhotoDialog).open(
|
|
this.imageCallback,
|
|
this.claimType,
|
|
this.crop,
|
|
urlBlobResponse.data as Blob,
|
|
fileName
|
|
)
|
|
} catch (error) {
|
|
this.$notify(
|
|
{
|
|
group: 'alert',
|
|
type: 'danger',
|
|
title: 'Error',
|
|
text: 'There was an error retrieving that image.'
|
|
},
|
|
5000
|
|
)
|
|
}
|
|
} else {
|
|
this.imageCallback(this.imageUrl)
|
|
}
|
|
}
|
|
|
|
close() {
|
|
this.visible = false
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style>
|
|
.dialog-overlay {
|
|
z-index: 50;
|
|
position: fixed;
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
bottom: 0;
|
|
background-color: rgba(0, 0, 0, 0.5);
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
padding: 1.5rem;
|
|
}
|
|
|
|
.dialog {
|
|
background-color: white;
|
|
padding: 1rem;
|
|
border-radius: 0.5rem;
|
|
width: 100%;
|
|
max-width: 700px;
|
|
}
|
|
</style>
|