Refining image input ui
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<outlined-input
|
<outlined-input
|
||||||
:name="label"
|
:name="label"
|
||||||
class="smart-image-input mb-3 pt-4"
|
class="smart-image-input mb-3"
|
||||||
:data-id="id"
|
:data-id="id"
|
||||||
:class="{ dragging }"
|
:class="{ dragging }"
|
||||||
@click="openImageInputDialog"
|
@click="openImageInputDialog"
|
||||||
@@ -9,11 +9,37 @@
|
|||||||
@dragleave="handleDragLeave"
|
@dragleave="handleDragLeave"
|
||||||
@drop="handleDrop"
|
@drop="handleDrop"
|
||||||
>
|
>
|
||||||
<img
|
<template v-if="value">
|
||||||
v-if="value"
|
<img
|
||||||
class="image"
|
v-if="value"
|
||||||
:src="value"
|
class="image"
|
||||||
|
:src="value"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="image-overlay"
|
||||||
|
:class="themeClasses"
|
||||||
|
/>
|
||||||
|
<v-btn
|
||||||
|
v-if="value"
|
||||||
|
icon
|
||||||
|
dark
|
||||||
|
class="clear-button ma-1"
|
||||||
|
@click.stop="change(undefined)"
|
||||||
|
>
|
||||||
|
<v-icon>mdi-close</v-icon>
|
||||||
|
</v-btn>
|
||||||
|
</template>
|
||||||
|
<div
|
||||||
|
v-else
|
||||||
|
class="add-image-text d-flex align-center justify-center"
|
||||||
>
|
>
|
||||||
|
Add image
|
||||||
|
<v-icon
|
||||||
|
right
|
||||||
|
>
|
||||||
|
mdi-image-outline
|
||||||
|
</v-icon>
|
||||||
|
</div>
|
||||||
</outlined-input>
|
</outlined-input>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -61,6 +87,13 @@ export default {
|
|||||||
OutlinedInput,
|
OutlinedInput,
|
||||||
},
|
},
|
||||||
mixins: [SmartInput],
|
mixins: [SmartInput],
|
||||||
|
inject: {
|
||||||
|
theme: {
|
||||||
|
default: {
|
||||||
|
isDark: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
props: {
|
props: {
|
||||||
label: {
|
label: {
|
||||||
type: String,
|
type: String,
|
||||||
@@ -73,6 +106,14 @@ export default {
|
|||||||
dragging: false,
|
dragging: false,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
computed: {
|
||||||
|
themeClasses() {
|
||||||
|
return {
|
||||||
|
'theme--dark': this.theme.isDark,
|
||||||
|
'theme--light': !this.theme.isDark,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
watch: {
|
watch: {
|
||||||
file(file){
|
file(file){
|
||||||
if (!file) return;
|
if (!file) return;
|
||||||
@@ -129,6 +170,11 @@ export default {
|
|||||||
data: {
|
data: {
|
||||||
href: this.value,
|
href: this.value,
|
||||||
},
|
},
|
||||||
|
callback: (href) => {
|
||||||
|
if (href) {
|
||||||
|
this.change(href);
|
||||||
|
}
|
||||||
|
},
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
handleUrlChange() {
|
handleUrlChange() {
|
||||||
@@ -161,12 +207,21 @@ export default {
|
|||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.smart-image-input {
|
.smart-image-input {
|
||||||
|
position: relative;
|
||||||
min-height: 120px;
|
min-height: 120px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
.image {
|
.image {
|
||||||
|
min-height: 100px;
|
||||||
max-height: 400px;
|
max-height: 400px;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
|
margin-bottom: -7px;
|
||||||
|
}
|
||||||
|
.clear-button {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
}
|
}
|
||||||
.dragging {
|
.dragging {
|
||||||
border-style: dashed;
|
border-style: dashed;
|
||||||
@@ -177,4 +232,34 @@ export default {
|
|||||||
.outlined-input.dragging.theme--light:not(.no-hover) {
|
.outlined-input.dragging.theme--light:not(.no-hover) {
|
||||||
border-color: rgba(0,0,0,.86);
|
border-color: rgba(0,0,0,.86);
|
||||||
}
|
}
|
||||||
|
.image-overlay {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
height: 12px;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
.image-overlay.theme--dark {
|
||||||
|
background: linear-gradient(180deg, rgba(0,0,0,0.8) 0%, rgba(0,0,0,0) 100%);
|
||||||
|
}
|
||||||
|
.image-overlay.theme--light {
|
||||||
|
background: linear-gradient(180deg, rgba(255,255,255,1) 0%, rgba(255,255,255,0) 100%);
|
||||||
|
}
|
||||||
|
.add-image-text {
|
||||||
|
opacity: 0.7;
|
||||||
|
height: 118px;
|
||||||
|
}
|
||||||
|
.smart-image-input:hover .add-image-text {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.smart-image-input > legend {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
.smart-image-input .clear-button i {
|
||||||
|
text-shadow: 0 0 4px #000, 0 0 4px #000 ;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
@@ -3,6 +3,7 @@
|
|||||||
<template slot="toolbar">
|
<template slot="toolbar">
|
||||||
<v-tabs
|
<v-tabs
|
||||||
v-model="tab"
|
v-model="tab"
|
||||||
|
:color="$vuetify.theme.themes.dark.accent"
|
||||||
grow
|
grow
|
||||||
>
|
>
|
||||||
<v-tab>User Files</v-tab>
|
<v-tab>User Files</v-tab>
|
||||||
@@ -12,99 +13,109 @@
|
|||||||
<v-tabs-items
|
<v-tabs-items
|
||||||
slot="unwrapped-content"
|
slot="unwrapped-content"
|
||||||
v-model="tab"
|
v-model="tab"
|
||||||
class="fill-height"
|
class="file-input-content fill-height"
|
||||||
>
|
>
|
||||||
<v-tab-item
|
<v-tab-item
|
||||||
class="fill-height"
|
class="fill-height"
|
||||||
style="overflow: auto;"
|
style="overflow: auto;"
|
||||||
>
|
>
|
||||||
<v-card-text
|
<div
|
||||||
class="user-image-list d-flex flex-wrap"
|
class="user-image-list pa-4 d-flex flex-wrap"
|
||||||
>
|
>
|
||||||
<image-field
|
<v-img
|
||||||
v-for="file in userImages"
|
v-for="file in userImages"
|
||||||
:key="file._id"
|
:key="file._id"
|
||||||
class="image-field"
|
:data-id="`image-${file._id}`"
|
||||||
:name="file.name"
|
class="user-image ma-1 v-sheet"
|
||||||
:href="file.href"
|
:class="{'elevation-4': file.href === href}"
|
||||||
:aspect-ratio="0.2"
|
height="250"
|
||||||
/>
|
:src="file.href"
|
||||||
<image-field
|
@click="selectUserImage(file.href)"
|
||||||
name="Example image 3"
|
|
||||||
href="https://picsum.photos/1000/1000"
|
|
||||||
/>
|
|
||||||
<image-field
|
|
||||||
name="Example image 2"
|
|
||||||
href="https://picsum.photos/500/600"
|
|
||||||
/>
|
|
||||||
<image-field
|
|
||||||
name="Example image 3"
|
|
||||||
href="https://picsum.photos/850/700"
|
|
||||||
/>
|
|
||||||
<v-col
|
|
||||||
class="mb-3"
|
|
||||||
v-bind="{cols: 12, sm: 6, md: 4}"
|
|
||||||
>
|
>
|
||||||
<v-btn
|
<v-btn
|
||||||
outlined
|
class="zoom-button"
|
||||||
style="height: 100%; width: 100%; min-height: 120px;"
|
icon
|
||||||
class="archive-button"
|
@click.stop="previewImage(file._id, file.href)"
|
||||||
:color="fileUploadError ? 'error' : undefined"
|
|
||||||
:disabled="fileUploadInProgress"
|
|
||||||
@click="$refs.archiveFileInput.click()"
|
|
||||||
>
|
>
|
||||||
<v-icon left>
|
<v-icon>mdi-magnify-plus</v-icon>
|
||||||
mdi-file-upload-outline
|
|
||||||
</v-icon>
|
|
||||||
<template v-if="fileUploadError">
|
|
||||||
{{ fileUploadError }}
|
|
||||||
</template>
|
|
||||||
<template v-else>
|
|
||||||
Upload Image
|
|
||||||
</template>
|
|
||||||
<v-progress-linear
|
|
||||||
v-if="fileUploadInProgress"
|
|
||||||
:value="fileUploadProgress"
|
|
||||||
:indeterminate="fileUploadIndeterminate"
|
|
||||||
/>
|
|
||||||
</v-btn>
|
</v-btn>
|
||||||
</v-col>
|
</v-img>
|
||||||
</v-card-text>
|
<v-btn
|
||||||
|
outlined
|
||||||
|
class="upload-image-button ma-1"
|
||||||
|
:color="fileUploadError ? 'error' : undefined"
|
||||||
|
:disabled="fileUploadInProgress"
|
||||||
|
@click="$refs.archiveFileInput.click()"
|
||||||
|
>
|
||||||
|
<v-icon left>
|
||||||
|
mdi-file-upload-outline
|
||||||
|
</v-icon>
|
||||||
|
<template v-if="fileUploadError">
|
||||||
|
{{ fileUploadError }}
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
Upload Image
|
||||||
|
</template>
|
||||||
|
<v-progress-linear
|
||||||
|
v-if="fileUploadInProgress"
|
||||||
|
:value="fileUploadProgress"
|
||||||
|
:indeterminate="fileUploadIndeterminate"
|
||||||
|
/>
|
||||||
|
</v-btn>
|
||||||
|
<div style="height: 0;" />
|
||||||
|
<div style="height: 0;" />
|
||||||
|
<div style="height: 0;" />
|
||||||
|
</div>
|
||||||
</v-tab-item>
|
</v-tab-item>
|
||||||
<v-tab-item
|
<v-tab-item
|
||||||
class="fill-height"
|
class="fill-height"
|
||||||
>
|
>
|
||||||
<v-card-text class="fill-height d-flex align-center">
|
<v-card-text class="fill-height d-flex flex-column justify-center align-center">
|
||||||
<text-field
|
<v-text-field
|
||||||
|
v-model="inputHref"
|
||||||
label="Direct link to image"
|
label="Direct link to image"
|
||||||
:value="href"
|
class="flex-grow-0"
|
||||||
|
style="width: 100%"
|
||||||
/>
|
/>
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
</v-tab-item>
|
</v-tab-item>
|
||||||
</v-tabs-items>
|
</v-tabs-items>
|
||||||
<v-spacer slot="actions" />
|
<v-spacer
|
||||||
|
slot="actions"
|
||||||
|
/>
|
||||||
<v-btn
|
<v-btn
|
||||||
|
v-if="tab === 1"
|
||||||
|
slot="actions"
|
||||||
|
color="accent"
|
||||||
|
outlined
|
||||||
|
:disabled="!inputHref"
|
||||||
|
@click="selectUserImage(inputHref)"
|
||||||
|
>
|
||||||
|
<v-icon left>
|
||||||
|
mdi-check
|
||||||
|
</v-icon>
|
||||||
|
Save
|
||||||
|
</v-btn>
|
||||||
|
<v-btn
|
||||||
|
v-else
|
||||||
slot="actions"
|
slot="actions"
|
||||||
text
|
text
|
||||||
@click="$store.dispatch('popDialogStack')"
|
@click="$emit('pop')"
|
||||||
>
|
>
|
||||||
Done
|
Close
|
||||||
</v-btn>
|
</v-btn>
|
||||||
</dialog-base>
|
</dialog-base>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="js">
|
<script lang="js">
|
||||||
import DialogBase from '/imports/client/ui/dialogStack/DialogBase.vue';
|
import DialogBase from '/imports/client/ui/dialogStack/DialogBase.vue';
|
||||||
import UserImages from '/imports/api/files/userImages/UserImages';
|
|
||||||
import ImageField from '/imports/client/ui/properties/viewers/shared/ImageField.vue';
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
DialogBase,
|
DialogBase,
|
||||||
ImageField,
|
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
currentHref: {
|
href: {
|
||||||
type: String,
|
type: String,
|
||||||
default: undefined,
|
default: undefined,
|
||||||
},
|
},
|
||||||
@@ -113,23 +124,69 @@ export default {
|
|||||||
return {
|
return {
|
||||||
tab: 0,
|
tab: 0,
|
||||||
progress: 0,
|
progress: 0,
|
||||||
href: this.currentHref,
|
inputHref: this.href,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
meteor: {
|
meteor: {
|
||||||
userImages() {
|
userImages() {
|
||||||
return UserImages.find({});
|
// return UserImages.find({});
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
_id: '1',
|
||||||
|
name: 'Example image 1',
|
||||||
|
href: 'https://picsum.photos/1000/1000',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
_id: '2',
|
||||||
|
name: 'Example image 2',
|
||||||
|
href: 'https://picsum.photos/500/600',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
_id: '3',
|
||||||
|
name: 'Example image 3',
|
||||||
|
href: 'https://picsum.photos/850/700',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
previewImage(id, href) {
|
||||||
|
this.$store.commit('pushDialogStack', {
|
||||||
|
component: 'image-preview-dialog',
|
||||||
|
elementId: `image-${id}`,
|
||||||
|
data: {
|
||||||
|
href: href,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
selectUserImage(href) {
|
||||||
|
this.$store.dispatch('popDialogStack', href);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="css" scoped>
|
<style lang="css" scoped>
|
||||||
.user-image-list {
|
.user-image-list > * {
|
||||||
|
height: 250px;
|
||||||
|
width: 250px;
|
||||||
|
flex-basis: 200px;
|
||||||
|
flex-grow: 1;
|
||||||
|
flex-shrink: 1;
|
||||||
}
|
}
|
||||||
|
.user-image-list > .upload-image-button {
|
||||||
.image-field > fieldset {
|
height: 250px;
|
||||||
|
}
|
||||||
|
.user-image {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.user-image.elevation-4 {
|
||||||
|
border: 2px solid #f44336;
|
||||||
|
}
|
||||||
|
.zoom-button {
|
||||||
|
position: absolute;
|
||||||
|
cursor: zoom-in;
|
||||||
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -73,7 +73,7 @@
|
|||||||
<smart-image-input
|
<smart-image-input
|
||||||
label="Image input"
|
label="Image input"
|
||||||
:value="inputImageHref"
|
:value="inputImageHref"
|
||||||
@change="(val, ack) => {inputImageHref = val; ack()}"
|
@change="(val, ack) => {inputImageHref = val; /*ack()*/}"
|
||||||
/>
|
/>
|
||||||
</v-col>
|
</v-col>
|
||||||
</v-row>
|
</v-row>
|
||||||
|
|||||||
Reference in New Issue
Block a user