Browse Source

Merge pull request #3162 from nocodb/feat/reopen-attachment-modal

feat(gui-v2): reopen attachment modal on carousel close
pull/3163/head
navi 2 years ago committed by GitHub
parent
commit
36ef5a248c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 11
      packages/nc-gui-v2/components.d.ts
  2. 6
      packages/nc-gui-v2/components/cell/attachment/Carousel.vue
  3. 21
      packages/nc-gui-v2/components/cell/attachment/Modal.vue
  4. 3
      packages/nc-gui-v2/components/cell/attachment/index.vue
  5. 18
      packages/nc-gui-v2/components/general/PreviewAs.vue

11
packages/nc-gui-v2/components.d.ts vendored

@ -12,6 +12,7 @@ declare module '@vue/runtime-core' {
ABadgeRibbon: typeof import('ant-design-vue/es')['BadgeRibbon'] ABadgeRibbon: typeof import('ant-design-vue/es')['BadgeRibbon']
AButton: typeof import('ant-design-vue/es')['Button'] AButton: typeof import('ant-design-vue/es')['Button']
ACard: typeof import('ant-design-vue/es')['Card'] ACard: typeof import('ant-design-vue/es')['Card']
ACardMeta: typeof import('ant-design-vue/es')['CardMeta']
ACarousel: typeof import('ant-design-vue/es')['Carousel'] ACarousel: typeof import('ant-design-vue/es')['Carousel']
ACheckbox: typeof import('ant-design-vue/es')['Checkbox'] ACheckbox: typeof import('ant-design-vue/es')['Checkbox']
ACol: typeof import('ant-design-vue/es')['Col'] ACol: typeof import('ant-design-vue/es')['Col']
@ -71,6 +72,8 @@ declare module '@vue/runtime-core' {
IcRoundEdit: typeof import('~icons/ic/round-edit')['default'] IcRoundEdit: typeof import('~icons/ic/round-edit')['default']
IcRoundKeyboardArrowDown: typeof import('~icons/ic/round-keyboard-arrow-down')['default'] IcRoundKeyboardArrowDown: typeof import('~icons/ic/round-keyboard-arrow-down')['default']
IcRoundSearch: typeof import('~icons/ic/round-search')['default'] IcRoundSearch: typeof import('~icons/ic/round-search')['default']
MaterialSymbolsArrowCircleLeftRounded: typeof import('~icons/material-symbols/arrow-circle-left-rounded')['default']
MaterialSymbolsArrowCircleRightRounded: typeof import('~icons/material-symbols/arrow-circle-right-rounded')['default']
MaterialSymbolsAttachFile: typeof import('~icons/material-symbols/attach-file')['default'] MaterialSymbolsAttachFile: typeof import('~icons/material-symbols/attach-file')['default']
MaterialSymbolsChevronLeftRounded: typeof import('~icons/material-symbols/chevron-left-rounded')['default'] MaterialSymbolsChevronLeftRounded: typeof import('~icons/material-symbols/chevron-left-rounded')['default']
MaterialSymbolsChevronRightRounded: typeof import('~icons/material-symbols/chevron-right-rounded')['default'] MaterialSymbolsChevronRightRounded: typeof import('~icons/material-symbols/chevron-right-rounded')['default']
@ -84,12 +87,14 @@ declare module '@vue/runtime-core' {
MdiAccountGroup: typeof import('~icons/mdi/account-group')['default'] MdiAccountGroup: typeof import('~icons/mdi/account-group')['default']
MdiAccountOutline: typeof import('~icons/mdi/account-outline')['default'] MdiAccountOutline: typeof import('~icons/mdi/account-outline')['default']
MdiAccountPlusOutline: typeof import('~icons/mdi/account-plus-outline')['default'] MdiAccountPlusOutline: typeof import('~icons/mdi/account-plus-outline')['default']
MdiAccountSupervisorOutline: typeof import('~icons/mdi/account-supervisor-outline')['default']
MdiAlphaA: typeof import('~icons/mdi/alpha-a')['default'] MdiAlphaA: typeof import('~icons/mdi/alpha-a')['default']
MdiApi: typeof import('~icons/mdi/api')['default'] MdiApi: typeof import('~icons/mdi/api')['default']
MdiArrowExpand: typeof import('~icons/mdi/arrow-expand')['default'] MdiArrowExpand: typeof import('~icons/mdi/arrow-expand')['default']
MdiArrowLeftBold: typeof import('~icons/mdi/arrow-left-bold')['default'] MdiArrowLeftBold: typeof import('~icons/mdi/arrow-left-bold')['default']
MdiAt: typeof import('~icons/mdi/at')['default'] MdiAt: typeof import('~icons/mdi/at')['default']
MdiCalculator: typeof import('~icons/mdi/calculator')['default'] MdiCalculator: typeof import('~icons/mdi/calculator')['default']
MdiCalendarMonth: typeof import('~icons/mdi/calendar-month')['default']
MdiCardsHeart: typeof import('~icons/mdi/cards-heart')['default'] MdiCardsHeart: typeof import('~icons/mdi/cards-heart')['default']
MdiCellphoneMessage: typeof import('~icons/mdi/cellphone-message')['default'] MdiCellphoneMessage: typeof import('~icons/mdi/cellphone-message')['default']
MdiChat: typeof import('~icons/mdi/chat')['default'] MdiChat: typeof import('~icons/mdi/chat')['default']
@ -102,6 +107,7 @@ declare module '@vue/runtime-core' {
MdiContentCopy: typeof import('~icons/mdi/content-copy')['default'] MdiContentCopy: typeof import('~icons/mdi/content-copy')['default']
MdiContentSave: typeof import('~icons/mdi/content-save')['default'] MdiContentSave: typeof import('~icons/mdi/content-save')['default']
MdiDatabaseOutline: typeof import('~icons/mdi/database-outline')['default'] MdiDatabaseOutline: typeof import('~icons/mdi/database-outline')['default']
MdiDelete: typeof import('~icons/mdi/delete')['default']
MdiDeleteOutline: typeof import('~icons/mdi/delete-outline')['default'] MdiDeleteOutline: typeof import('~icons/mdi/delete-outline')['default']
MdiDiscord: typeof import('~icons/mdi/discord')['default'] MdiDiscord: typeof import('~icons/mdi/discord')['default']
MdiDotsVertical: typeof import('~icons/mdi/dots-vertical')['default'] MdiDotsVertical: typeof import('~icons/mdi/dots-vertical')['default']
@ -114,6 +120,7 @@ declare module '@vue/runtime-core' {
MdiEmail: typeof import('~icons/mdi/email')['default'] MdiEmail: typeof import('~icons/mdi/email')['default']
MdiEmailArrowRightOutline: typeof import('~icons/mdi/email-arrow-right-outline')['default'] MdiEmailArrowRightOutline: typeof import('~icons/mdi/email-arrow-right-outline')['default']
MdiExitToApp: typeof import('~icons/mdi/exit-to-app')['default'] MdiExitToApp: typeof import('~icons/mdi/exit-to-app')['default']
MdiExport: typeof import('~icons/mdi/export')['default']
MdiEyeOffOutline: typeof import('~icons/mdi/eye-off-outline')['default'] MdiEyeOffOutline: typeof import('~icons/mdi/eye-off-outline')['default']
MdiFileDocumentOutline: typeof import('~icons/mdi/file-document-outline')['default'] MdiFileDocumentOutline: typeof import('~icons/mdi/file-document-outline')['default']
MdiFileExcel: typeof import('~icons/mdi/file-excel')['default'] MdiFileExcel: typeof import('~icons/mdi/file-excel')['default']
@ -122,6 +129,7 @@ declare module '@vue/runtime-core' {
MdiFolder: typeof import('~icons/mdi/folder')['default'] MdiFolder: typeof import('~icons/mdi/folder')['default']
MdiFunction: typeof import('~icons/mdi/function')['default'] MdiFunction: typeof import('~icons/mdi/function')['default']
MdiGestureDoubleTap: typeof import('~icons/mdi/gesture-double-tap')['default'] MdiGestureDoubleTap: typeof import('~icons/mdi/gesture-double-tap')['default']
MdiGithub: typeof import('~icons/mdi/github')['default']
MdiHeart: typeof import('~icons/mdi/heart')['default'] MdiHeart: typeof import('~icons/mdi/heart')['default']
MdiHook: typeof import('~icons/mdi/hook')['default'] MdiHook: typeof import('~icons/mdi/hook')['default']
MdiInformation: typeof import('~icons/mdi/information')['default'] MdiInformation: typeof import('~icons/mdi/information')['default']
@ -139,12 +147,14 @@ declare module '@vue/runtime-core' {
MdiNumeric: typeof import('~icons/mdi/numeric')['default'] MdiNumeric: typeof import('~icons/mdi/numeric')['default']
MdiOpenInNew: typeof import('~icons/mdi/open-in-new')['default'] MdiOpenInNew: typeof import('~icons/mdi/open-in-new')['default']
MdiPlus: typeof import('~icons/mdi/plus')['default'] MdiPlus: typeof import('~icons/mdi/plus')['default']
MdiPlusBoxOutline: typeof import('~icons/mdi/plus-box-outline')['default']
MdiPlusOutline: typeof import('~icons/mdi/plus-outline')['default'] MdiPlusOutline: typeof import('~icons/mdi/plus-outline')['default']
MdiRefresh: typeof import('~icons/mdi/refresh')['default'] MdiRefresh: typeof import('~icons/mdi/refresh')['default']
MdiReload: typeof import('~icons/mdi/reload')['default'] MdiReload: typeof import('~icons/mdi/reload')['default']
MdiSearch: typeof import('~icons/mdi/search')['default'] MdiSearch: typeof import('~icons/mdi/search')['default']
MdiSlack: typeof import('~icons/mdi/slack')['default'] MdiSlack: typeof import('~icons/mdi/slack')['default']
MdiStar: typeof import('~icons/mdi/star')['default'] MdiStar: typeof import('~icons/mdi/star')['default']
MdiStarOutline: typeof import('~icons/mdi/star-outline')['default']
MdiStore: typeof import('~icons/mdi/store')['default'] MdiStore: typeof import('~icons/mdi/store')['default']
MdiTable: typeof import('~icons/mdi/table')['default'] MdiTable: typeof import('~icons/mdi/table')['default']
MdiTableArrowRight: typeof import('~icons/mdi/table-arrow-right')['default'] MdiTableArrowRight: typeof import('~icons/mdi/table-arrow-right')['default']
@ -153,6 +163,7 @@ declare module '@vue/runtime-core' {
MdiText: typeof import('~icons/mdi/text')['default'] MdiText: typeof import('~icons/mdi/text')['default']
MdiThumbUp: typeof import('~icons/mdi/thumb-up')['default'] MdiThumbUp: typeof import('~icons/mdi/thumb-up')['default']
MdiTrashCan: typeof import('~icons/mdi/trash-can')['default'] MdiTrashCan: typeof import('~icons/mdi/trash-can')['default']
MdiTwitter: typeof import('~icons/mdi/twitter')['default']
MdiUploadOutline: typeof import('~icons/mdi/upload-outline')['default'] MdiUploadOutline: typeof import('~icons/mdi/upload-outline')['default']
MdiViewListOutline: typeof import('~icons/mdi/view-list-outline')['default'] MdiViewListOutline: typeof import('~icons/mdi/view-list-outline')['default']
MdiWhatsapp: typeof import('~icons/mdi/whatsapp')['default'] MdiWhatsapp: typeof import('~icons/mdi/whatsapp')['default']

6
packages/nc-gui-v2/components/cell/attachment/Carousel.vue

@ -1,11 +1,7 @@
<script lang="ts" setup> <script lang="ts" setup>
import { onKeyDown } from '@vueuse/core' import { onKeyDown } from '@vueuse/core'
import { useAttachmentCell } from './utils' import { useAttachmentCell } from './utils'
import { isImage } from '~/utils' import { computed, isImage, onClickOutside, ref } from '#imports'
import { computed, onClickOutside, ref } from '#imports'
import MaterialSymbolsArrowCircleRightRounded from '~icons/material-symbols/arrow-circle-right-rounded'
import MaterialSymbolsArrowCircleLeftRounded from '~icons/material-symbols/arrow-circle-left-rounded'
import MdiCloseCircle from '~icons/mdi/close-circle'
const { selectedImage, visibleItems, downloadFile } = useAttachmentCell()! const { selectedImage, visibleItems, downloadFile } = useAttachmentCell()!

21
packages/nc-gui-v2/components/cell/attachment/Modal.vue

@ -2,8 +2,7 @@
import { onKeyDown } from '@vueuse/core' import { onKeyDown } from '@vueuse/core'
import { useAttachmentCell } from './utils' import { useAttachmentCell } from './utils'
import { useSortable } from './sort' import { useSortable } from './sort'
import { ref, useDropZone, useUIPermission } from '#imports' import { isImage, openLink, ref, useDropZone, useUIPermission, watch } from '#imports'
import { isImage, openLink } from '~/utils'
const { isUIAllowed } = useUIPermission() const { isUIAllowed } = useUIPermission()
@ -39,6 +38,22 @@ onKeyDown('Escape', () => {
modalVisible.value = false modalVisible.value = false
isOverDropZone.value = false isOverDropZone.value = false
}) })
function onClick(item: Record<string, any>) {
selectedImage.value = item
modalVisible.value = false
const stopHandle = watch(selectedImage, (nextImage, _, onCleanup) => {
if (!nextImage) {
setTimeout(() => {
modalVisible.value = true
}, 50)
stopHandle?.()
}
onCleanup(() => stopHandle?.())
})
}
</script> </script>
<template> <template>
@ -103,7 +118,7 @@ onKeyDown('Escape', () => {
v-if="isImage(item.title, item.mimetype)" v-if="isImage(item.title, item.mimetype)"
:style="{ backgroundImage: `url('${item.url}')` }" :style="{ backgroundImage: `url('${item.url}')` }"
class="w-full h-full bg-contain bg-center bg-no-repeat" class="w-full h-full bg-contain bg-center bg-no-repeat"
@click.stop="() => (selectedImage = item) && (modalVisible = false)" @click.stop="onClick(item)"
/> />
<component <component

3
packages/nc-gui-v2/components/cell/attachment/index.vue

@ -4,8 +4,7 @@ import { useProvideAttachmentCell } from './utils'
import { useSortable } from './sort' import { useSortable } from './sort'
import Modal from './Modal.vue' import Modal from './Modal.vue'
import Carousel from './Carousel.vue' import Carousel from './Carousel.vue'
import { computed, ref, useDropZone, useSmartsheetStoreOrThrow, watch } from '#imports' import { computed, isImage, openLink, ref, useDropZone, useSmartsheetStoreOrThrow, watch } from '#imports'
import { isImage, openLink } from '~/utils'
interface Props { interface Props {
modelValue: string | Record<string, any>[] | null modelValue: string | Record<string, any>[] | null

18
packages/nc-gui-v2/components/general/PreviewAs.vue

@ -1,6 +1,5 @@
<script lang="ts" setup> <script lang="ts" setup>
import { onUnmounted, useEventListener, useGlobal, watch } from '#imports' import { onUnmounted, useEventListener, useGlobal, useState, watch } from '#imports'
import { useState } from '#app'
import MdiAccountStar from '~icons/mdi/account-star' import MdiAccountStar from '~icons/mdi/account-star'
import MdiAccountHardHat from '~icons/mdi/account-hard-hat' import MdiAccountHardHat from '~icons/mdi/account-hard-hat'
import MdiAccountEdit from '~icons/mdi/account-edit' import MdiAccountEdit from '~icons/mdi/account-edit'
@ -54,13 +53,14 @@ watch(previewAs, () => window.location.reload())
:style="{ top: position.y, left: position.x }" :style="{ top: position.y, left: position.x }"
> >
<MdiDrag style="cursor: move" class="text-white" @mousedown="mouseDown" /> <MdiDrag style="cursor: move" class="text-white" @mousedown="mouseDown" />
<div class="divider" /> <div class="divider" />
<div class="pointer flex items-center gap-4"> <div class="pointer flex items-center gap-4">
<span>Preview as :</span> <span>Preview as :</span>
<a-radio-group v-model:value="previewAs" name="radioGroup"> <a-radio-group v-model:value="previewAs" name="radioGroup">
<a-radio v-for="role in roleList" :key="role.title" class="capitalize !text-white" :value="role.title" <a-radio v-for="role of roleList" :key="role.title" class="capitalize !text-white" :value="role.title"
>{{ role.title }} >{{ role.title }}
</a-radio> </a-radio>
</a-radio-group> </a-radio-group>
@ -77,8 +77,8 @@ watch(previewAs, () => window.location.reload())
<template v-else> <template v-else>
<template v-for="role of roleList" :key="role.title"> <template v-for="role of roleList" :key="role.title">
<a-menu-item :class="`pointer nc-preview-${role.title}`" @click="previewAs = role.title"> <a-menu-item :class="`pointer nc-preview-${role.title}`" @click="previewAs = role.title">
<div class="p-1 flex gap-2 items-center"> <div class="nc-project-menu-item group">
<component :is="roleIcon[role.title]" /> <component :is="roleIcon[role.title]" class="group-hover:text-pink-500" />
<span class="capitalize" :class="{ 'x-active--text': role.title === previewAs }">{{ role.title }}</span> <span class="capitalize" :class="{ 'x-active--text': role.title === previewAs }">{{ role.title }}</span>
</div> </div>
@ -87,8 +87,8 @@ watch(previewAs, () => window.location.reload())
<template v-if="previewAs"> <template v-if="previewAs">
<a-menu-item @click="previewAs = null"> <a-menu-item @click="previewAs = null">
<div class="p-1 flex gap-2 items-center"> <div class="nc-project-menu-item group">
<mdi-close /> <MdiClose class="group-hover:text-pink-500" />
<!-- Reset Preview --> <!-- Reset Preview -->
<span class="text-capitalize text-xs whitespace-nowrap">{{ $t('activity.resetReview') }}</span> <span class="text-capitalize text-xs whitespace-nowrap">{{ $t('activity.resetReview') }}</span>
</div> </div>
@ -98,6 +98,10 @@ watch(previewAs, () => window.location.reload())
</template> </template>
<style scoped> <style scoped>
.nc-project-menu-item {
@apply cursor-pointer flex items-center gap-2 py-2 hover:text-primary after:(content-[''] absolute top-0 left-0 bottom-0 right-0 w-full h-full bg-current opacity-0 transition transition-opactity duration-100) hover:(after:(opacity-5));
}
.floating-reset-btn { .floating-reset-btn {
@apply z-1000 index-100 fixed text-white @apply z-1000 index-100 fixed text-white
@apply flex items-center overflow-hidden whitespace-nowrap gap-4 rounded shadow-md; @apply flex items-center overflow-hidden whitespace-nowrap gap-4 rounded shadow-md;

Loading…
Cancel
Save