Browse Source

fix(nc-gui): extension panel resize issue

pull/9351/head
Ramesh Mane 3 months ago
parent
commit
98cdf41963
  1. 251
      packages/nc-gui/components/extensions/Pane.vue
  2. 40
      packages/nc-gui/components/tabs/Smartsheet.vue

251
packages/nc-gui/components/extensions/Pane.vue

@ -17,8 +17,6 @@ const {
const { $e } = useNuxtApp() const { $e } = useNuxtApp()
const isReady = ref(false)
const searchExtensionRef = ref<HTMLInputElement>() const searchExtensionRef = ref<HTMLInputElement>()
const extensionHeaderRef = ref<HTMLDivElement>() const extensionHeaderRef = ref<HTMLDivElement>()
@ -27,6 +25,13 @@ const searchQuery = ref<string>('')
const showSearchBox = ref(false) const showSearchBox = ref(false)
const panelSize = computed(() => {
if (isPanelExpanded.value) {
return extensionPanelSize.value
}
return 0
})
const { width } = useElementSize(extensionHeaderRef) const { width } = useElementSize(extensionHeaderRef)
const isOpenSearchBox = computed(() => { const isOpenSearchBox = computed(() => {
@ -54,14 +59,6 @@ const toggleMarket = () => {
isMarketVisible.value = !isMarketVisible.value isMarketVisible.value = !isMarketVisible.value
} }
const normalizePaneMaxWidth = computed(() => {
if (isReady.value) {
return 60
} else {
return extensionPanelSize.value
}
})
const onMove = async (_event: { moved: { newIndex: number; oldIndex: number; element: ExtensionType } }) => { const onMove = async (_event: { moved: { newIndex: number; oldIndex: number; element: ExtensionType } }) => {
let { let {
moved: { newIndex = 0, oldIndex = 0, element }, moved: { newIndex = 0, oldIndex = 0, element },
@ -100,20 +97,6 @@ const onMove = async (_event: { moved: { newIndex: number; oldIndex: number; ele
$e('a:extension:reorder') $e('a:extension:reorder')
} }
defineExpose({
onReady: () => {
isReady.value = true
},
})
watch(isPanelExpanded, (newValue) => {
if (newValue && !isReady.value) {
setTimeout(() => {
isReady.value = true
}, 300)
}
})
onClickOutside(searchExtensionRef, () => { onClickOutside(searchExtensionRef, () => {
if (searchQuery.value) { if (searchQuery.value) {
return return
@ -130,125 +113,119 @@ onMounted(() => {
</script> </script>
<template> <template>
<Pane <Pane :size="panelSize" max-size="60%" class="nc-extension-pane">
v-if="isPanelExpanded" <Transition name="layout" :duration="150">
:size="extensionPanelSize" <div v-if="isPanelExpanded" class="flex flex-col">
min-size="10%" <div
max-size="60%" ref="extensionHeaderRef"
class="nc-extension-pane" class="h-[var(--toolbar-height)] flex items-center gap-3 px-4 py-2 border-b-1 border-gray-200 bg-white"
:style="{ >
minWidth: isReady ? '300px' : `${normalizePaneMaxWidth}%`, <div
maxWidth: `${normalizePaneMaxWidth}%`, class="flex items-center gap-3 font-weight-700 text-gray-700 text-base"
}" :class="{
> 'flex-1': !isOpenSearchBox,
<div }"
ref="extensionHeaderRef"
class="h-[var(--toolbar-height)] flex items-center gap-3 px-4 py-2 border-b-1 border-gray-200 bg-white"
>
<div
class="flex items-center gap-3 font-weight-700 text-gray-700 text-base"
:class="{
'flex-1': !isOpenSearchBox,
}"
>
<GeneralIcon icon="ncPuzzleSolid" class="h-5 w-5 text-gray-700 opacity-85" />
<span v-if="!isOpenSearchBox || width >= 507">Extensions</span>
</div>
<div
class="flex justify-end"
:class="{
'flex-1': isOpenSearchBox,
}"
>
<NcButton v-if="!isOpenSearchBox" size="xs" type="text" class="!px-1" @click="handleShowSearchInput">
<GeneralIcon icon="search" class="flex-none !text-gray-500" />
</NcButton>
<div v-else class="flex flex-grow items-center justify-end !max-w-[300px]">
<a-input
ref="searchExtensionRef"
v-model:value="searchQuery"
type="text"
class="nc-input-border-on-value !h-7 !px-3 !py-1 !rounded-lg"
placeholder="Search Extension"
allow-clear
@keydown.esc="handleCloseSearchbox"
> >
<template #prefix> <GeneralIcon icon="ncPuzzleSolid" class="h-5 w-5 text-gray-700 opacity-85" />
<GeneralIcon icon="search" class="mr-2 h-4 w-4 text-gray-500 group-hover:text-black" /> <span v-if="!isOpenSearchBox || width >= 507">Extensions</span>
</template>
</a-input>
</div>
</div>
<NcButton type="secondary" size="xs" @click="toggleMarket">
<div class="flex items-center gap-1 text-xs max-w-full -ml-3px">
<GeneralIcon icon="plus" />
{{ $t('general.install') }}
</div>
</NcButton>
</div>
<template v-if="extensionList.length === 0">
<div class="flex items-center flex-col gap-4 w-full nc-scrollbar-md text-center p-4">
<GeneralIcon icon="ncPuzzleSolid" class="h-12 w-12 flex-none mt-[120px] text-gray-500 !stroke-transparent" />
<div class="font-weight-700 text-base">No extensions added</div>
<div class="text-sm text-gray-700">Add Extensions from the community extensions marketplace</div>
<NcButton size="small" @click="toggleMarket">
<div class="flex items-center gap-1 -ml-3px">
<GeneralIcon icon="plus" />
{{ $t('general.install') }}
</div> </div>
</NcButton> <div
<!-- Todo: add docs link --> class="flex justify-end"
<NcButton size="small" type="secondary"> :class="{
<div class="flex items-center gap-1.5"> 'flex-1': isOpenSearchBox,
<GeneralIcon icon="externalLink" /> }"
{{ $t('activity.goToDocs') }} >
</div> <NcButton v-if="!isOpenSearchBox" size="xs" type="text" class="!px-1" @click="handleShowSearchInput">
</NcButton> <GeneralIcon icon="search" class="flex-none !text-gray-500" />
</div> </NcButton>
</template> <div v-else class="flex flex-grow items-center justify-end !max-w-[300px]">
<template v-else> <a-input
<Draggable ref="searchExtensionRef"
:model-value="filteredExtensionList" v-model:value="searchQuery"
draggable=".nc-extension-item" type="text"
item-key="id" class="nc-input-border-on-value !h-7 !px-3 !py-1 !rounded-lg"
handle=".nc-extension-drag-handler" placeholder="Search Extension"
ghost-class="ghost" allow-clear
class="nc-extension-list-wrapper flex items-center flex-col gap-3 w-full nc-scrollbar-md py-4" @keydown.esc="handleCloseSearchbox"
:class="{ >
'h-full': searchQuery && !filteredExtensionList.length && extensionList.length, <template #prefix>
}" <GeneralIcon icon="search" class="mr-2 h-4 w-4 text-gray-500 group-hover:text-black" />
@start="(e) => e.target.classList.add('grabbing')" </template>
@end="(e) => e.target.classList.remove('grabbing')" </a-input>
@change="onMove($event)" </div>
>
<template #item="{ element: ext }">
<div class="nc-extension-item w-full">
<ExtensionsWrapper :extension-id="ext.id" />
</div> </div>
</template> <NcButton type="secondary" size="xs" @click="toggleMarket">
<template v-if="searchQuery && !filteredExtensionList.length && extensionList.length" #header> <div class="flex items-center gap-1 text-xs max-w-full -ml-3px">
<div class="w-full h-full flex-1 flex items-center justify-center"> <GeneralIcon icon="plus" />
<div class="pb-6 text-gray-500 flex flex-col items-center gap-6 text-center"> {{ $t('general.install') }}
<img
src="~assets/img/placeholder/no-search-result-found.png"
class="!w-[164px] flex-none"
alt="No search results found"
/>
{{ $t('title.noResultsMatchedYourSearch') }}
</div> </div>
</NcButton>
</div>
<template v-if="extensionList.length === 0">
<div class="flex items-center flex-col gap-4 w-full nc-scrollbar-md text-center p-4">
<GeneralIcon icon="ncPuzzleSolid" class="h-12 w-12 flex-none mt-[120px] text-gray-500 !stroke-transparent" />
<div class="font-weight-700 text-base">No extensions added</div>
<div class="text-sm text-gray-700">Add Extensions from the community extensions marketplace</div>
<NcButton size="small" @click="toggleMarket">
<div class="flex items-center gap-1 -ml-3px">
<GeneralIcon icon="plus" />
{{ $t('general.install') }}
</div>
</NcButton>
<!-- Todo: add docs link -->
<NcButton size="small" type="secondary">
<div class="flex items-center gap-1.5">
<GeneralIcon icon="externalLink" />
{{ $t('activity.goToDocs') }}
</div>
</NcButton>
</div> </div>
</template> </template>
</Draggable> <template v-else>
</template> <Draggable
<ExtensionsMarket v-if="isMarketVisible" v-model="isMarketVisible" /> :model-value="filteredExtensionList"
<ExtensionsDetails draggable=".nc-extension-item"
v-if="isDetailsVisible && detailsExtensionId" item-key="id"
v-model="isDetailsVisible" handle=".nc-extension-drag-handler"
:extension-id="detailsExtensionId" ghost-class="ghost"
:from="detailsFrom" class="nc-extension-list-wrapper flex items-center flex-col gap-3 w-full nc-scrollbar-md py-4"
/> :class="{
'h-full': searchQuery && !filteredExtensionList.length && extensionList.length,
}"
@start="(e) => e.target.classList.add('grabbing')"
@end="(e) => e.target.classList.remove('grabbing')"
@change="onMove($event)"
>
<template #item="{ element: ext }">
<div class="nc-extension-item w-full">
<ExtensionsWrapper :extension-id="ext.id" />
</div>
</template>
<template v-if="searchQuery && !filteredExtensionList.length && extensionList.length" #header>
<div class="w-full h-full flex-1 flex items-center justify-center">
<div class="pb-6 text-gray-500 flex flex-col items-center gap-6 text-center">
<img
src="~assets/img/placeholder/no-search-result-found.png"
class="!w-[164px] flex-none"
alt="No search results found"
/>
{{ $t('title.noResultsMatchedYourSearch') }}
</div>
</div>
</template>
</Draggable>
</template>
<ExtensionsMarket v-if="isMarketVisible" v-model="isMarketVisible" />
<ExtensionsDetails
v-if="isDetailsVisible && detailsExtensionId"
v-model="isDetailsVisible"
:extension-id="detailsExtensionId"
:from="detailsFrom"
/>
</div>
</Transition>
</Pane> </Pane>
</template> </template>

40
packages/nc-gui/components/tabs/Smartsheet.vue

@ -80,8 +80,6 @@ useProvideSmartsheetLtarHelpers(meta)
const grid = ref() const grid = ref()
const extensionPaneRef = ref()
const onDrop = async (event: DragEvent) => { const onDrop = async (event: DragEvent) => {
event.preventDefault() event.preventDefault()
try { try {
@ -161,36 +159,40 @@ watch([activeViewTitleOrId, activeTableId], () => {
handleSidebarOpenOnMobileForNonViews() handleSidebarOpenOnMobileForNonViews()
}) })
const { leftSidebarWidth, windowSize } = storeToRefs(useSidebarStore())
const { isPanelExpanded, extensionPanelSize } = useExtensions() const { isPanelExpanded, extensionPanelSize } = useExtensions()
const contentSize = computed(() => {
if (isPanelExpanded.value && extensionPanelSize.value) {
return 100 - extensionPanelSize.value
} else {
return 100
}
})
const contentMaxSize = computed(() => {
if (!isPanelExpanded.value) {
return 100
} else {
return ((windowSize.value - leftSidebarWidth.value - 300) / (windowSize.value - leftSidebarWidth.value)) * 100
}
})
const onResize = (sizes: { min: number; max: number; size: number }[]) => { const onResize = (sizes: { min: number; max: number; size: number }[]) => {
if (sizes.length === 2) { if (sizes.length === 2) {
if (!sizes[1].size) return if (!sizes[1].size) return
extensionPanelSize.value = sizes[1].size extensionPanelSize.value = sizes[1].size
} }
} }
const onReady = () => {
if (isPanelExpanded.value && extensionPaneRef.value) {
// wait until extension pane animation complete
setTimeout(() => {
extensionPaneRef.value?.onReady()
}, 300)
}
}
</script> </script>
<template> <template>
<div class="nc-container flex flex-col h-full" @drop="onDrop" @dragover.prevent> <div class="nc-container flex flex-col h-full" @drop="onDrop" @dragover.prevent>
<LazySmartsheetTopbar /> <LazySmartsheetTopbar />
<div style="height: calc(100% - var(--topbar-height))"> <div style="height: calc(100% - var(--topbar-height))">
<Splitpanes <Splitpanes v-if="openedViewsTab === 'view'" class="nc-extensions-content-resizable-wrapper" @resized="onResize">
v-if="openedViewsTab === 'view'" <Pane class="flex flex-col h-full min-w-0" :max-size="contentMaxSize" :size="contentSize">
class="nc-extensions-content-resizable-wrapper"
@ready="onReady"
@resized="onResize"
>
<Pane class="flex flex-col h-full min-w-0" :size="isPanelExpanded && extensionPanelSize ? 100 - extensionPanelSize : 100">
<LazySmartsheetToolbar v-if="!isForm" /> <LazySmartsheetToolbar v-if="!isForm" />
<div <div
:style="{ height: isForm || isMobileMode ? '100%' : 'calc(100% - var(--toolbar-height))' }" :style="{ height: isForm || isMobileMode ? '100%' : 'calc(100% - var(--toolbar-height))' }"
@ -217,7 +219,7 @@ const onReady = () => {
</Transition> </Transition>
</div> </div>
</Pane> </Pane>
<ExtensionsPane ref="extensionPaneRef" /> <ExtensionsPane />
</Splitpanes> </Splitpanes>
<SmartsheetDetails v-else /> <SmartsheetDetails v-else />
</div> </div>

Loading…
Cancel
Save