mirror of https://github.com/nocodb/nocodb
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
196 lines
5.3 KiB
196 lines
5.3 KiB
<script lang="ts" setup> |
|
/** |
|
* ExtensionHeader component. |
|
* |
|
* @slot prefix - Slot for custom content to be displayed at the start of the header when in fullscreen mode. |
|
* @slot extra - Slot for additional custom content to be displayed before the options and close button in fullscreen mode. |
|
*/ |
|
|
|
interface Props { |
|
isFullscreen?: boolean |
|
} |
|
|
|
withDefaults(defineProps<Props>(), { |
|
isFullscreen: true, |
|
}) |
|
|
|
const { $e } = useNuxtApp() |
|
|
|
const { eventBus, getExtensionAssetsUrl, duplicateExtension, showExtensionDetails } = useExtensions() |
|
|
|
const { fullscreen, collapsed, extension, extensionManifest, activeError, showExpandBtn } = useExtensionHelperOrThrow() |
|
const EXTENSION_ID = extension.value.extensionId |
|
|
|
const titleInput = ref<HTMLInputElement | null>(null) |
|
|
|
const titleEditMode = ref<boolean>(false) |
|
|
|
const tempTitle = ref<string>(extension.value.title) |
|
|
|
const showExpandButton = computed(() => { |
|
return showExpandBtn.value && !activeError.value |
|
}) |
|
|
|
const enableEditMode = () => { |
|
titleEditMode.value = true |
|
tempTitle.value = extension.value.title |
|
nextTick(() => { |
|
titleInput.value?.focus() |
|
titleInput.value?.select() |
|
}) |
|
} |
|
|
|
const updateExtensionTitle = async () => { |
|
await extension.value.setTitle(tempTitle.value) |
|
titleEditMode.value = false |
|
} |
|
|
|
const expandExtension = () => { |
|
if (!collapsed.value) return |
|
|
|
collapsed.value = false |
|
} |
|
/** |
|
* Handles the duplication of an extension. |
|
* |
|
* @param id - The ID of the extension to duplicate. |
|
* @param open - Optional. If true, the duplicated extension will be opened. |
|
*/ |
|
|
|
const handleDuplicateExtension = async (id: string, open: boolean = false) => { |
|
const duplicatedExt = await duplicateExtension(id) |
|
|
|
if (duplicatedExt?.id && open) { |
|
fullscreen.value = false |
|
|
|
nextTick(() => { |
|
eventBus.emit(ExtensionsEvents.DUPLICATE, duplicatedExt.id) |
|
}) |
|
} |
|
} |
|
|
|
const toggleFullScreen = () => { |
|
fullscreen.value = true |
|
$e(`c:extensions:${EXTENSION_ID}:full-screen`) |
|
} |
|
</script> |
|
|
|
<template> |
|
<div |
|
v-if="(isFullscreen && fullscreen) || !isFullscreen" |
|
class="extension-header flex items-center" |
|
:class="{ |
|
'border-b-1 border-nc-border-gray-medium h-[49px]': !collapsed && !isFullscreen, |
|
'collapsed border-transparent h-[48px]': collapsed && !isFullscreen, |
|
'px-3 py-2 gap-1': !isFullscreen, |
|
'gap-3 px-4 pt-3 pb-[11px] border-b-1 border-nc-border-gray-medium': isFullscreen, |
|
}" |
|
@click="expandExtension" |
|
> |
|
<slot v-if="isFullscreen" name="prefix"></slot> |
|
<NcButton v-if="!isFullscreen" size="xs" type="text" class="nc-extension-drag-handler !px-1" @click.stop> |
|
<GeneralIcon icon="ncDrag" class="flex-none text-gray-500" /> |
|
</NcButton> |
|
|
|
<img |
|
v-if="extensionManifest" |
|
:src="getExtensionAssetsUrl(extensionManifest.iconUrl)" |
|
alt="icon" |
|
class="h-8 w-8 object-contain flex-none" |
|
:class="{ |
|
'mx-1': !isFullscreen, |
|
}" |
|
/> |
|
<div |
|
v-if="titleEditMode" |
|
class="flex-1" |
|
:class="{ |
|
'mr-1': !isFullscreen, |
|
}" |
|
> |
|
<a-input |
|
ref="titleInput" |
|
v-model:value="tempTitle" |
|
type="text" |
|
class="!h-8 !px-1 !py-1 !-ml-1 !rounded-lg extension-title" |
|
:class="{ |
|
'w-4/5': !isFullscreen, |
|
'!text-lg !font-semibold max-w-[420px]': isFullscreen, |
|
}" |
|
@click.stop |
|
@keyup.enter="updateExtensionTitle" |
|
@keyup.esc="updateExtensionTitle" |
|
@blur="updateExtensionTitle" |
|
> |
|
</a-input> |
|
</div> |
|
|
|
<NcTooltip v-else show-on-truncate-only class="truncate flex-1"> |
|
<template #title> |
|
{{ extension.title }} |
|
</template> |
|
<span |
|
class="extension-title cursor-pointer" |
|
:class="{ |
|
'text-lg font-semibold ': isFullscreen, |
|
'mr-1': !isFullscreen, |
|
}" |
|
@dblclick.stop="enableEditMode" |
|
@click.stop |
|
> |
|
{{ extension.title }} |
|
</span> |
|
</NcTooltip> |
|
<slot v-if="isFullscreen" name="extra"></slot> |
|
<ExtensionsExtensionHeaderMenu |
|
:is-fullscreen="isFullscreen" |
|
class="nc-extension-menu" |
|
@rename="enableEditMode" |
|
@duplicate="handleDuplicateExtension(extension.id, true)" |
|
@show-details="showExtensionDetails(extension.extensionId, 'extension')" |
|
@clear-data="extension.clear()" |
|
@delete="extension.delete()" |
|
/> |
|
|
|
<template v-if="!isFullscreen"> |
|
<NcButton |
|
v-if="showExpandButton" |
|
size="xs" |
|
type="text" |
|
class="nc-extension-expand-btn !px-1" |
|
@click.stop="toggleFullScreen" |
|
> |
|
<GeneralIcon icon="ncMaximize2" class="h-3.5 w-3.5" /> |
|
</NcButton> |
|
<NcButton size="xs" type="text" class="!px-1" @click.stop="collapsed = !collapsed"> |
|
<GeneralIcon :icon="collapsed ? 'arrowDown' : 'arrowUp'" class="flex-none" /> |
|
</NcButton> |
|
</template> |
|
<NcButton v-else :size="isFullscreen ? 'small' : 'xs'" type="text" class="flex-none !px-1" @click="fullscreen = false"> |
|
<GeneralIcon icon="close" /> |
|
</NcButton> |
|
</div> |
|
</template> |
|
|
|
<style lang="scss" scoped> |
|
.extension-header { |
|
&.collapsed:not(:hover) { |
|
.nc-extension-expand-btn, |
|
.nc-extension-menu { |
|
@apply hidden; |
|
} |
|
} |
|
|
|
.extension-header-left { |
|
@apply flex-1 flex items-center gap-2; |
|
} |
|
|
|
.extension-header-right { |
|
@apply flex items-center gap-1; |
|
} |
|
|
|
.extension-title { |
|
@apply font-weight-600; |
|
} |
|
} |
|
</style>
|
|
|