Skip to content

Commit 4a38711

Browse files
committed
feat: drag and drop image support
1 parent dbad5b0 commit 4a38711

9 files changed

Lines changed: 115 additions & 9 deletions

File tree

assets/style/css/variables/color.css

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
--color-border-01: #090909;
1717
--color-border-02: #171717;
1818
--color-border-03: #202020;
19+
--color-border-04: #eee;
1920

2021
/* Typographic */
2122
--color-text-01: #999;
@@ -35,4 +36,5 @@
3536

3637
/* Overlays */
3738
--color-overlay-01: rgba(0, 0, 0, 0.1);
39+
--color-overlay-02: rgba(0, 0, 0, 0.8);
3840
}

components/Card/UploadImageCard/UploadImageCard.component.vue

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
</template>
1616

1717
<script>
18-
import { defineComponent, useContext, useStore, ref, computed } from '@nuxtjs/composition-api'
18+
import { defineComponent, useContext, useStore, ref, computed, watch } from '@nuxtjs/composition-api'
1919
import useEditor from '@/hooks/useEditor'
2020
import { AppIcon } from '@/components/Icon'
2121
@@ -26,6 +26,7 @@ export default defineComponent({
2626
setup(_, { emit }) {
2727
const context = useContext()
2828
const store = useStore()
29+
2930
const { sleep, acceptedFileExtensions, getFileExtension } = useEditor()
3031
3132
const rootRef = ref(null)
@@ -44,16 +45,31 @@ export default defineComponent({
4445
imageFileRef.value.click()
4546
}
4647
48+
const droppedFiles = computed(() => store.getters['editor/droppedFiles'])
49+
50+
watch(
51+
() => droppedFiles.value,
52+
value => {
53+
const file = value[0]
54+
setFile(file)
55+
}
56+
)
57+
4758
const handleChangeFile = () => {
59+
const file = imageFileRef.value.files[0]
60+
setFile(file)
61+
}
62+
63+
const setFile = file => {
4864
store.commit('editor/SET_IS_BUSY', true)
4965
50-
const fileExtension = getFileExtension(imageFileRef.value.files[0].name).toLowerCase()
66+
const fileExtension = getFileExtension(file.name).toLowerCase()
5167
5268
if (acceptedFileExtensions.value.includes(fileExtension)) {
5369
sleep(1000).then(() => {
5470
store.commit('editor/SET_IS_READY', true)
5571
store.commit('editor/SET_IS_BUSY', false)
56-
store.commit('editor/SET_ORIGINAL', { file: imageFileRef.value.files[0] })
72+
store.commit('editor/SET_ORIGINAL', { file: file })
5773
})
5874
} else {
5975
store.commit('editor/SET_IS_BUSY', false)
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,32 @@
11
.default-layout {
2+
$drop-target: '.drop-target';
3+
24
position: relative;
5+
6+
&--dragOver {
7+
#{$drop-target} {
8+
visibility: visible !important;
9+
}
10+
}
11+
12+
.drop-target {
13+
position: fixed;
14+
top: var(--header-height);
15+
left: 0;
16+
z-index: var(--z-index-overlay);
17+
display: flex;
18+
align-items: center;
19+
justify-content: center;
20+
width: 100%;
21+
height: calc(100vh - var(--header-height));
22+
background-color: var(--color-overlay-02);
23+
border: 2px dashed var(--color-border-04);
24+
visibility: hidden;
25+
26+
&__title {
27+
color: var(--color-text-03);
28+
font-size: var(--font-size-text-14);
29+
pointer-events: none;
30+
}
31+
}
332
}

layouts/Default/Default.layout.vue

Lines changed: 52 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,31 @@
11
<template lang="pug">
2-
.layout.default-layout
2+
.layout.default-layout(@drag.stop.prevent @dragstart.stop.prevent @dragend.stop.prevent @dragover.stop.prevent @drop.prevent)
33
AppPreloader
44
AppHeader(@on-click-credits-dialog="isOpenCreditsDialog = true")
55

66
// Main
7-
.layout__inner
7+
.layout__inner(
8+
:class="[dragEnterActiveClass]"
9+
@drag.stop.prevent
10+
@dragstart.stop.prevent
11+
@dragend.stop.prevent
12+
@dragover.stop.prevent="onDragOver"
13+
@drop.prevent="onFileDrop"
14+
)
815
.col.col-12
916
.router-view
1017
nuxt
1118

19+
// Drop target
20+
.drop-target(v-if="!preloader.isLoading && !isReady" @dragleave.stop.prevent="onDragLeave")
21+
span.drop-target__title {{ $t('uploader.drop') }}
22+
1223
// App Credits Dialog
1324
AppCreditsDialog(:is-open="isOpenCreditsDialog" @on-close="isOpenCreditsDialog = false")
1425
</template>
1526

1627
<script>
17-
import { defineComponent, ref } from '@nuxtjs/composition-api'
28+
import { defineComponent, useStore, ref, computed } from '@nuxtjs/composition-api'
1829
import { AppPreloader } from '@/components/Preloader'
1930
import { AppHeader } from '@/components/Header'
2031
import { AppCreditsDialog } from '@/components/Dialog'
@@ -26,10 +37,47 @@ export default defineComponent({
2637
AppCreditsDialog
2738
},
2839
setup() {
40+
const baseClassName = 'default-layout'
41+
42+
const store = useStore()
43+
44+
const isActiveDragOver = ref(false)
45+
2946
const isOpenCreditsDialog = ref(false)
3047
48+
const preloader = computed(() => store.getters['preloader/preloader'])
49+
const isReady = computed(() => store.getters['editor/isReady'])
50+
51+
const onDragOver = () => {
52+
isActiveDragOver.value = true
53+
}
54+
55+
const onDragLeave = () => {
56+
isActiveDragOver.value = false
57+
}
58+
59+
const onFileDrop = event => {
60+
if (!isReady.value) {
61+
store.commit('editor/SET_DROPPED_FILES', event.dataTransfer.files)
62+
63+
isActiveDragOver.value = false
64+
}
65+
}
66+
67+
const dragEnterActiveClass = computed(() => {
68+
if (isActiveDragOver.value) {
69+
return `${baseClassName}--dragOver`
70+
}
71+
})
72+
3173
return {
32-
isOpenCreditsDialog
74+
preloader,
75+
isReady,
76+
isOpenCreditsDialog,
77+
onDragOver,
78+
onDragLeave,
79+
onFileDrop,
80+
dragEnterActiveClass
3381
}
3482
}
3583
})

locales/en.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ export default {
2121
uploader: {
2222
title: 'START CROPPING',
2323
description: `Quickly crop a photo for multiple ratios on the same screen. <br> Supported ratios are; 16:9, 9:16, 1:1 and free-ratio.`,
24-
choosePhoto: 'Choose a photo'
24+
choosePhoto: 'Choose a photo',
25+
drop: 'Drop here'
2526
},
2627
editor: {
2728
chooseCustomAspectRatio: 'Choose custom ratio',

locales/tr.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ export default {
2121
uploader: {
2222
title: 'KIRPMAYA BAŞLA',
2323
description: `Birden fazla en boy oranı için tek ekranda hızlıca fotoğraf kırp. <br> 16:9, 9:16, 1:1 ve serbest oran desteklenir.`,
24-
choosePhoto: 'Fotoğraf Seç'
24+
choosePhoto: 'Fotoğraf Seç',
25+
drop: 'Görseli buraya bırak'
2526
},
2627
editor: {
2728
chooseCustomAspectRatio: 'Özel oran seç',

store/editor/getters.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
export default {
2+
droppedFiles(state) {
3+
return state.droppedFiles
4+
},
5+
26
isReady(state) {
37
return state.isReady
48
},

store/editor/mutations.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
import { cropTypeEnum } from '@/enums'
22

33
export default {
4+
SET_DROPPED_FILES(state, files) {
5+
state.droppedFiles = files
6+
},
7+
48
SET_IS_READY(state, isReady) {
59
state.isReady = isReady
610
},

store/editor/state.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { cropTypeEnum } from '@/enums'
22

33
export default () => ({
4+
droppedFiles: [],
45
isReady: false,
56
isBusy: false,
67
original: {

0 commit comments

Comments
 (0)