Do not set API_ORIGIN if deployed
This commit is contained in:
167
dashboard/src/components/ImagePicker.vue
Normal file
167
dashboard/src/components/ImagePicker.vue
Normal file
@@ -0,0 +1,167 @@
|
||||
<script setup>
|
||||
|
||||
import { useTemplateRef, ref, onMounted } from 'vue';
|
||||
|
||||
const fileInput = useTemplateRef('fileInput');
|
||||
|
||||
const props = defineProps(['src', 'fallbackSrc', 'size', 'maxSize', 'displayHeight']);
|
||||
const emits = defineEmits(['changed']);
|
||||
|
||||
const internalSrc = ref('');
|
||||
const newSrc = ref('');
|
||||
const isChanged = ref(false);
|
||||
|
||||
function onShowIconSelector() {
|
||||
fileInput.value.click();
|
||||
}
|
||||
|
||||
// function onChanged(event) {
|
||||
// emits('changed', event);
|
||||
// }
|
||||
|
||||
function dataURLtoFile(dataURL, filename) {
|
||||
// Split the data URL to get the MIME type and the base64 data
|
||||
const [metadata, base64Data] = dataURL.split(',');
|
||||
|
||||
// Extract the MIME type from the metadata
|
||||
const mimeType = metadata.match(/:(.*?);/)[1];
|
||||
|
||||
// Decode the base64 data to binary
|
||||
const binaryData = atob(base64Data);
|
||||
|
||||
// Create an array buffer from the binary data
|
||||
const arrayBuffer = new ArrayBuffer(binaryData.length);
|
||||
const view = new Uint8Array(arrayBuffer);
|
||||
for (let i = 0; i < binaryData.length; i++) {
|
||||
view[i] = binaryData.charCodeAt(i);
|
||||
}
|
||||
|
||||
// Create a Blob from the array buffer
|
||||
const blob = new Blob([arrayBuffer], { type: mimeType });
|
||||
|
||||
// Create a File object from the Blob
|
||||
const file = new File([blob], filename, { type: mimeType });
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
function onChanged(event) {
|
||||
const fr = new FileReader();
|
||||
fr.onload = function () {
|
||||
const image = new Image();
|
||||
image.onload = function () {
|
||||
const size = props.size ? parseInt(props.size) : 0;
|
||||
const maxSize = props.maxSize ? parseInt(props.maxSize) : 0;
|
||||
|
||||
const canvas = document.createElement('canvas');
|
||||
|
||||
if (maxSize) {
|
||||
if (image.naturalWidth > maxSize) {
|
||||
canvas.width = maxSize;
|
||||
canvas.height = (image.naturalHeight / image.naturalWidth) * maxSize;
|
||||
} else {
|
||||
canvas.width = image.naturalWidth;
|
||||
canvas.height = image.naturalHeight;
|
||||
}
|
||||
} else {
|
||||
canvas.width = size;
|
||||
canvas.height = size;
|
||||
}
|
||||
|
||||
const imageDimensionRatio = image.width / image.height;
|
||||
const canvasDimensionRatio = canvas.width / canvas.height;
|
||||
let renderableHeight, renderableWidth, xStart, yStart;
|
||||
|
||||
if (imageDimensionRatio > canvasDimensionRatio) {
|
||||
renderableHeight = canvas.height;
|
||||
renderableWidth = image.width * (renderableHeight / image.height);
|
||||
xStart = (canvas.width - renderableWidth) / 2;
|
||||
yStart = 0;
|
||||
} else if (imageDimensionRatio < canvasDimensionRatio) {
|
||||
renderableWidth = canvas.width;
|
||||
renderableHeight = image.height * (renderableWidth / image.width);
|
||||
xStart = 0;
|
||||
yStart = (canvas.height - renderableHeight) / 2;
|
||||
} else {
|
||||
renderableHeight = canvas.height;
|
||||
renderableWidth = canvas.width;
|
||||
xStart = 0;
|
||||
yStart = 0;
|
||||
}
|
||||
|
||||
var ctx = canvas.getContext('2d');
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
ctx.drawImage(image, xStart, yStart, renderableWidth, renderableHeight);
|
||||
|
||||
internalSrc.value = canvas.toDataURL('image/png');
|
||||
isChanged.value = true;
|
||||
|
||||
emits('changed', dataURLtoFile(internalSrc.value, 'image.png'));
|
||||
};
|
||||
|
||||
image.src = fr.result;
|
||||
};
|
||||
fr.readAsDataURL(event.target.files[0]);
|
||||
}
|
||||
|
||||
// function onClear() {
|
||||
// internalSrc.value = props.src || props.fallbackSrc;
|
||||
// newSrc.value = null;
|
||||
// isChanged.value = true;
|
||||
// }
|
||||
|
||||
onMounted(() => {
|
||||
internalSrc.value = props.src;
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<div class="image-picker">
|
||||
<input @change="onChanged($event)" type="file" ref="fileInput" style="display: none" accept="image/*"/>
|
||||
|
||||
<div id="previewIcon" class="image-picker" @click="onShowIconSelector()">
|
||||
<img :src="internalSrc" onerror="this.src = fallbackSrc" :style="{ height: displayHeight || null }" />
|
||||
<i class="image-picker-edit-indicator fa fa-pencil-alt"></i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- TODO translate -->
|
||||
<!-- <div v-show="src" class="actionable" @click="onClear()">Clear</div> -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.image-picker {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.image-picker > img {
|
||||
display: block;
|
||||
height: 320px;
|
||||
border-radius: 10px;
|
||||
box-shadow: var(--pankow-menu-shadow);
|
||||
}
|
||||
|
||||
.image-picker-edit-indicator {
|
||||
position: absolute;
|
||||
bottom: 4px;
|
||||
right: 4px;
|
||||
border-radius: 20px;
|
||||
padding: 5px;
|
||||
color: var(--pankow-text-color);
|
||||
background-color: var(--pankow-input-background-color);
|
||||
transition: all 250ms;
|
||||
}
|
||||
|
||||
.image-picker:hover .image-picker-edit-indicator {
|
||||
color: white;
|
||||
background: var(--pankow-color-primary);
|
||||
transform: scale(1.2);
|
||||
}
|
||||
|
||||
</style>
|
||||
Reference in New Issue
Block a user