|
|
@ -1,4 +1,11 @@ |
|
|
|
<script lang="ts" setup> |
|
|
|
<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 { |
|
|
|
interface Props { |
|
|
|
isFullscreen?: boolean |
|
|
|
isFullscreen?: boolean |
|
|
|
} |
|
|
|
} |
|
|
@ -36,6 +43,12 @@ const expandExtension = () => { |
|
|
|
|
|
|
|
|
|
|
|
collapsed.value = false |
|
|
|
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 handleDuplicateExtension = async (id: string, open: boolean = false) => { |
|
|
|
const duplicatedExt = await duplicateExtension(id) |
|
|
|
const duplicatedExt = await duplicateExtension(id) |
|
|
@ -49,17 +62,18 @@ const handleDuplicateExtension = async (id: string, open: boolean = false) => { |
|
|
|
|
|
|
|
|
|
|
|
<template> |
|
|
|
<template> |
|
|
|
<div |
|
|
|
<div |
|
|
|
class="extension-header px-3 py-2" |
|
|
|
v-if="(isFullscreen && fullscreen) || !isFullscreen" |
|
|
|
|
|
|
|
class="extension-header flex items-center" |
|
|
|
:class="{ |
|
|
|
:class="{ |
|
|
|
'border-b-1 border-gray-200 h-[49px]': !collapsed, |
|
|
|
'border-b-1 border-nc-gray-medium h-[49px]': !collapsed && !isFullscreen, |
|
|
|
'collapsed border-transparent h-[48px]': collapsed, |
|
|
|
'collapsed border-transparent h-[48px]': collapsed && !isFullscreen, |
|
|
|
|
|
|
|
'px-3 py-2 gap-1': !isFullscreen, |
|
|
|
|
|
|
|
'gap-3 px-4 pt-4 pb-[15px] border-b-1 border-nc-gray-medium': isFullscreen, |
|
|
|
}" |
|
|
|
}" |
|
|
|
@click="expandExtension" |
|
|
|
@click="expandExtension" |
|
|
|
> |
|
|
|
> |
|
|
|
<div class="extension-header-left max-w-[calc(100%_-_100px)]"> |
|
|
|
<slot v-if="isFullscreen" name="prefix"></slot> |
|
|
|
<!-- Todo: enable later when we support extension reordering --> |
|
|
|
<NcButton v-if="!isFullscreen" size="xs" type="text" class="nc-extension-drag-handler !px-1" @click.stop> |
|
|
|
<!-- eslint-disable vue/no-constant-condition --> |
|
|
|
|
|
|
|
<NcButton size="xs" type="text" class="nc-extension-drag-handler !px-1" @click.stop> |
|
|
|
|
|
|
|
<GeneralIcon icon="ncDrag" class="flex-none text-gray-500" /> |
|
|
|
<GeneralIcon icon="ncDrag" class="flex-none text-gray-500" /> |
|
|
|
</NcButton> |
|
|
|
</NcButton> |
|
|
|
|
|
|
|
|
|
|
@ -67,33 +81,44 @@ const handleDuplicateExtension = async (id: string, open: boolean = false) => { |
|
|
|
v-if="extensionManifest" |
|
|
|
v-if="extensionManifest" |
|
|
|
:src="getExtensionAssetsUrl(extensionManifest.iconUrl)" |
|
|
|
:src="getExtensionAssetsUrl(extensionManifest.iconUrl)" |
|
|
|
alt="icon" |
|
|
|
alt="icon" |
|
|
|
class="h-8 w-8 object-contain" |
|
|
|
class="h-8 w-8 object-contain flex-none" |
|
|
|
/> |
|
|
|
/> |
|
|
|
|
|
|
|
<div v-if="titleEditMode" class="flex-1"> |
|
|
|
<a-input |
|
|
|
<a-input |
|
|
|
v-if="titleEditMode && !fullscreen" |
|
|
|
|
|
|
|
ref="titleInput" |
|
|
|
ref="titleInput" |
|
|
|
v-model:value="tempTitle" |
|
|
|
v-model:value="tempTitle" |
|
|
|
type="text" |
|
|
|
type="text" |
|
|
|
class="flex-grow !h-8 !px-1 !py-1 !-ml-1 !rounded-lg w-4/5 extension-title" |
|
|
|
class="flex-1 !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 |
|
|
|
@click.stop |
|
|
|
@keyup.enter="updateExtensionTitle" |
|
|
|
@keyup.enter="updateExtensionTitle" |
|
|
|
@keyup.esc="updateExtensionTitle" |
|
|
|
@keyup.esc="updateExtensionTitle" |
|
|
|
@blur="updateExtensionTitle" |
|
|
|
@blur="updateExtensionTitle" |
|
|
|
> |
|
|
|
> |
|
|
|
</a-input> |
|
|
|
</a-input> |
|
|
|
|
|
|
|
</div> |
|
|
|
|
|
|
|
|
|
|
|
<NcTooltip v-else show-on-truncate-only class="truncate"> |
|
|
|
<NcTooltip v-else show-on-truncate-only class="truncate flex-1"> |
|
|
|
<template #title> |
|
|
|
<template #title> |
|
|
|
{{ extension.title }} |
|
|
|
{{ extension.title }} |
|
|
|
</template> |
|
|
|
</template> |
|
|
|
<span class="extension-title cursor-pointer" @dblclick.stop="enableEditMode" @click.stop> |
|
|
|
<span |
|
|
|
|
|
|
|
class="extension-title cursor-pointer" |
|
|
|
|
|
|
|
:class="{ |
|
|
|
|
|
|
|
'text-lg font-semibold ': isFullscreen, |
|
|
|
|
|
|
|
}" |
|
|
|
|
|
|
|
@dblclick.stop="enableEditMode" |
|
|
|
|
|
|
|
@click.stop |
|
|
|
|
|
|
|
> |
|
|
|
{{ extension.title }} |
|
|
|
{{ extension.title }} |
|
|
|
</span> |
|
|
|
</span> |
|
|
|
</NcTooltip> |
|
|
|
</NcTooltip> |
|
|
|
</div> |
|
|
|
<slot v-if="isFullscreen" name="extra"></slot> |
|
|
|
<div class="extension-header-right" @click.stop> |
|
|
|
|
|
|
|
<ExtensionsExtensionHeaderMenu |
|
|
|
<ExtensionsExtensionHeaderMenu |
|
|
|
:active-error="activeError" |
|
|
|
:is-fullscreen="isFullscreen" |
|
|
|
class="nc-extension-menu" |
|
|
|
class="nc-extension-menu" |
|
|
|
@rename="enableEditMode" |
|
|
|
@rename="enableEditMode" |
|
|
|
@duplicate="handleDuplicateExtension(extension.id, true)" |
|
|
|
@duplicate="handleDuplicateExtension(extension.id, true)" |
|
|
@ -101,20 +126,24 @@ const handleDuplicateExtension = async (id: string, open: boolean = false) => { |
|
|
|
@clear-data="extension.clear()" |
|
|
|
@clear-data="extension.clear()" |
|
|
|
@delete="extension.delete()" |
|
|
|
@delete="extension.delete()" |
|
|
|
/> |
|
|
|
/> |
|
|
|
<NcButton v-if="!activeError" type="text" size="xs" class="nc-extension-expand-btn !px-1" @click="fullscreen = true"> |
|
|
|
<template v-if="!isFullscreen"> |
|
|
|
|
|
|
|
<NcButton v-if="!activeError" size="xs" type="text" class="nc-extension-expand-btn !px-1" @click.stop="fullscreen = true"> |
|
|
|
<GeneralIcon icon="ncMaximize2" class="h-3.5 w-3.5" /> |
|
|
|
<GeneralIcon icon="ncMaximize2" class="h-3.5 w-3.5" /> |
|
|
|
</NcButton> |
|
|
|
</NcButton> |
|
|
|
<NcButton size="xs" type="text" class="!px-1" @click="collapsed = !collapsed"> |
|
|
|
<NcButton size="xs" type="text" class="!px-1" @click.stop="collapsed = !collapsed"> |
|
|
|
<GeneralIcon :icon="collapsed ? 'arrowDown' : 'arrowUp'" class="flex-none" /> |
|
|
|
<GeneralIcon :icon="collapsed ? 'arrowDown' : 'arrowUp'" class="flex-none" /> |
|
|
|
</NcButton> |
|
|
|
</NcButton> |
|
|
|
</div> |
|
|
|
</template> |
|
|
|
|
|
|
|
<template v-else> |
|
|
|
|
|
|
|
<NcButton :size="isFullscreen ? 'small' : 'xs'" type="text" class="flex-none !px-1" @click="fullscreen = false"> |
|
|
|
|
|
|
|
<GeneralIcon icon="close" /> |
|
|
|
|
|
|
|
</NcButton> |
|
|
|
|
|
|
|
</template> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</template> |
|
|
|
</template> |
|
|
|
|
|
|
|
|
|
|
|
<style lang="scss" scoped> |
|
|
|
<style lang="scss" scoped> |
|
|
|
.extension-header { |
|
|
|
.extension-header { |
|
|
|
@apply flex justify-between; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
&.collapsed:not(:hover) { |
|
|
|
&.collapsed:not(:hover) { |
|
|
|
.nc-extension-expand-btn, |
|
|
|
.nc-extension-expand-btn, |
|
|
|
.nc-extension-menu { |
|
|
|
.nc-extension-menu { |
|
|
|