mirror of
https://github.com/nextcloud/server.git
synced 2026-04-22 14:50:17 -04:00
feat(files_sharing): provide web-components based sidebar API
This fixes apps providing vue components, which is invalid and does not always work - and never work with Vue 3. Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
This commit is contained in:
parent
c5a093d842
commit
ee962f3a37
9 changed files with 256 additions and 32 deletions
|
|
@ -159,7 +159,16 @@
|
|||
<NcActionSeparator />
|
||||
|
||||
<!-- external actions -->
|
||||
<ExternalShareAction v-for="action in externalLinkActions"
|
||||
<NcActionButton v-for="action in sortedExternalShareActions"
|
||||
:key="action.id"
|
||||
@click="action.exec(share, fileInfo.node)">
|
||||
<template #icon>
|
||||
<NcIconSvgWrapper :svg="action.iconSvg" />
|
||||
</template>
|
||||
{{ action.label(share, fileInfo.node) }}
|
||||
</NcActionButton>
|
||||
|
||||
<SidebarTabExternalActionLegacy v-for="action in externalLegacyShareActions"
|
||||
:id="action.id"
|
||||
:key="action.id"
|
||||
:action="action"
|
||||
|
|
@ -230,6 +239,8 @@ import { t } from '@nextcloud/l10n'
|
|||
import moment from '@nextcloud/moment'
|
||||
import { generateUrl, getBaseUrl } from '@nextcloud/router'
|
||||
import { ShareType } from '@nextcloud/sharing'
|
||||
import { getSidebarInlineActions } from '@nextcloud/sharing/ui'
|
||||
import { toRaw } from 'vue'
|
||||
|
||||
import VueQrcode from '@chenfengyuan/vue-qrcode'
|
||||
import NcActionButton from '@nextcloud/vue/components/NcActionButton'
|
||||
|
|
@ -255,8 +266,8 @@ import PlusIcon from 'vue-material-design-icons/Plus.vue'
|
|||
|
||||
import SharingEntryQuickShareSelect from './SharingEntryQuickShareSelect.vue'
|
||||
import ShareExpiryTime from './ShareExpiryTime.vue'
|
||||
import SidebarTabExternalActionLegacy from './SidebarTabExternal/SidebarTabExternalActionLegacy.vue'
|
||||
|
||||
import ExternalShareAction from './ExternalShareAction.vue'
|
||||
import GeneratePassword from '../utils/GeneratePassword.ts'
|
||||
import Share from '../models/Share.ts'
|
||||
import SharesMixin from '../mixins/SharesMixin.js'
|
||||
|
|
@ -267,7 +278,6 @@ export default {
|
|||
name: 'SharingEntryLink',
|
||||
|
||||
components: {
|
||||
ExternalShareAction,
|
||||
NcActions,
|
||||
NcActionButton,
|
||||
NcActionCheckbox,
|
||||
|
|
@ -290,6 +300,7 @@ export default {
|
|||
PlusIcon,
|
||||
SharingEntryQuickShareSelect,
|
||||
ShareExpiryTime,
|
||||
SidebarTabExternalActionLegacy,
|
||||
},
|
||||
|
||||
mixins: [SharesMixin, ShareDetails],
|
||||
|
|
@ -323,6 +334,7 @@ export default {
|
|||
|
||||
ExternalLegacyLinkActions: OCA.Sharing.ExternalLinkActions.state,
|
||||
ExternalShareActions: OCA.Sharing.ExternalShareActions.state,
|
||||
externalShareActions: getSidebarInlineActions(),
|
||||
|
||||
// tracks whether modal should be opened or not
|
||||
showQRCode: false,
|
||||
|
|
@ -568,13 +580,25 @@ export default {
|
|||
*
|
||||
* @return {Array}
|
||||
*/
|
||||
externalLinkActions() {
|
||||
externalLegacyShareActions() {
|
||||
const filterValidAction = (action) => (action.shareType.includes(ShareType.Link) || action.shareType.includes(ShareType.Email)) && !action.advanced
|
||||
// filter only the registered actions for said link
|
||||
console.error('external legacy', this.ExternalShareActions, this.ExternalShareActions.actions.filter(filterValidAction))
|
||||
return this.ExternalShareActions.actions
|
||||
.filter(filterValidAction)
|
||||
},
|
||||
|
||||
/**
|
||||
* Additional actions for the menu
|
||||
*
|
||||
* @return {import('@nextcloud/sharing/ui').ISidebarInlineAction[]}
|
||||
*/
|
||||
sortedExternalShareActions() {
|
||||
return this.externalShareActions
|
||||
.filter((action) => action.enabled(toRaw(this.share), toRaw(this.fileInfo.node)))
|
||||
.sort((a, b) => a.order - b.order)
|
||||
},
|
||||
|
||||
isPasswordPolicyEnabled() {
|
||||
return typeof this.config.passwordPolicy === 'object'
|
||||
},
|
||||
|
|
|
|||
|
|
@ -0,0 +1,71 @@
|
|||
<!--
|
||||
- SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
|
||||
- SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
-->
|
||||
|
||||
<template>
|
||||
<component :is="action.element"
|
||||
:key="action.id"
|
||||
ref="actionElement"
|
||||
:share.prop="share"
|
||||
:node.prop="node"
|
||||
:on-save.prop="onSave" />
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import type { INode } from '@nextcloud/files'
|
||||
import type { IShare } from '@nextcloud/sharing'
|
||||
import type { ISidebarAction } from '@nextcloud/sharing/ui'
|
||||
import type { PropType } from 'vue'
|
||||
|
||||
import { ref, toRaw, watchEffect } from 'vue'
|
||||
|
||||
const props = defineProps({
|
||||
action: {
|
||||
type: Object as PropType<ISidebarAction>,
|
||||
required: true,
|
||||
},
|
||||
node: {
|
||||
type: Object as PropType<INode>,
|
||||
required: true,
|
||||
},
|
||||
share: {
|
||||
type: Object as PropType<IShare | undefined>,
|
||||
required: true,
|
||||
},
|
||||
})
|
||||
|
||||
defineExpose({ save })
|
||||
|
||||
const actionElement = ref()
|
||||
const savingCallback = ref()
|
||||
|
||||
watchEffect(() => {
|
||||
if (!actionElement.value) {
|
||||
return
|
||||
}
|
||||
|
||||
// This seems to be only needed in Vue 2 as the .prop modifier does not really work on the vue 2 version of web components
|
||||
// TODO: Remove with Vue 3
|
||||
actionElement.value.node = toRaw(props.node)
|
||||
actionElement.value.onSave = onSave
|
||||
actionElement.value.share = toRaw(props.share)
|
||||
})
|
||||
|
||||
/**
|
||||
* The share is reset thus save the state of the component.
|
||||
*/
|
||||
async function save() {
|
||||
await savingCallback.value?.()
|
||||
}
|
||||
|
||||
/**
|
||||
* Vue does not allow to call methods on wrapped web components
|
||||
* so we need to pass it per callback.
|
||||
*
|
||||
* @param callback - The callback to be called on save
|
||||
*/
|
||||
function onSave(callback: () => Promise<void>) {
|
||||
savingCallback.value = callback
|
||||
}
|
||||
</script>
|
||||
|
|
@ -4,18 +4,18 @@
|
|||
-->
|
||||
|
||||
<template>
|
||||
<Component :is="data.is"
|
||||
<component :is="data.is"
|
||||
v-bind="data"
|
||||
v-on="action.handlers">
|
||||
{{ data.text }}
|
||||
</Component>
|
||||
</component>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Share from '../models/Share.ts'
|
||||
import Share from '../../models/Share.ts'
|
||||
|
||||
export default {
|
||||
name: 'ExternalShareAction',
|
||||
name: 'SidebarTabExternalActionLegacy',
|
||||
|
||||
props: {
|
||||
id: {
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
<!--
|
||||
- SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
|
||||
- SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
-->
|
||||
|
||||
<template>
|
||||
<component :is="section.element" ref="sectionElement" :node.prop="node" />
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import type { INode } from '@nextcloud/files'
|
||||
import type { ISidebarSection } from '@nextcloud/sharing/ui'
|
||||
import type { PropType } from 'vue'
|
||||
|
||||
import { ref, watchEffect } from 'vue'
|
||||
|
||||
const props = defineProps({
|
||||
node: {
|
||||
type: Object as PropType<INode>,
|
||||
required: true,
|
||||
},
|
||||
section: {
|
||||
type: Object as PropType<ISidebarSection>,
|
||||
required: true,
|
||||
},
|
||||
})
|
||||
|
||||
// TOOD: Remove with Vue 3
|
||||
const sectionElement = ref()
|
||||
watchEffect(() => {
|
||||
sectionElement.value.node = props.node
|
||||
})
|
||||
</script>
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
<!--
|
||||
- SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
|
||||
- SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
-->
|
||||
|
||||
<template>
|
||||
<div class="sharing-tab-external-section-legacy">
|
||||
<component :is="component" :file-info="fileInfo" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, type Component, type PropType } from 'vue'
|
||||
|
||||
const props = defineProps({
|
||||
fileInfo: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
sectionCallback: {
|
||||
type: Function as PropType<(el: HTMLElement | undefined, fileInfo: unknown) => Component>,
|
||||
required: true,
|
||||
},
|
||||
})
|
||||
|
||||
const component = computed(() => props.sectionCallback(undefined, props.fileInfo))
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.sharing-tab-external-section-legacy {
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -3,6 +3,8 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import logger from './logger.ts'
|
||||
|
||||
export default class ExternalLinkActions {
|
||||
|
||||
_state
|
||||
|
|
@ -13,7 +15,7 @@ export default class ExternalLinkActions {
|
|||
|
||||
// init default values
|
||||
this._state.actions = []
|
||||
console.debug('OCA.Sharing.ExternalLinkActions initialized')
|
||||
logger.debug('OCA.Sharing.ExternalLinkActions initialized')
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -35,13 +37,13 @@ export default class ExternalLinkActions {
|
|||
* @return {boolean}
|
||||
*/
|
||||
registerAction(action) {
|
||||
OC.debug && console.warn('OCA.Sharing.ExternalLinkActions is deprecated, use OCA.Sharing.ExternalShareAction instead')
|
||||
logger.warn('OCA.Sharing.ExternalLinkActions is deprecated, use `registerSidebarAction` from `@nextcloud/sharing` instead')
|
||||
|
||||
if (typeof action === 'object' && action.icon && action.name && action.url) {
|
||||
this._state.actions.push(action)
|
||||
return true
|
||||
}
|
||||
console.error('Invalid action provided', action)
|
||||
logger.error('Invalid action provided', action)
|
||||
return false
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import logger from './logger.ts'
|
||||
|
||||
export default class ExternalShareActions {
|
||||
|
||||
_state
|
||||
|
|
@ -13,7 +15,7 @@ export default class ExternalShareActions {
|
|||
|
||||
// init default values
|
||||
this._state.actions = []
|
||||
console.debug('OCA.Sharing.ExternalShareActions initialized')
|
||||
logger.debug('OCA.Sharing.ExternalShareActions initialized')
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -44,6 +46,8 @@ export default class ExternalShareActions {
|
|||
* @return {boolean}
|
||||
*/
|
||||
registerAction(action) {
|
||||
logger.warn('OCA.Sharing.ExternalShareActions is deprecated, use `registerSidebarAction` from `@nextcloud/sharing` instead')
|
||||
|
||||
// Validate action
|
||||
if (typeof action !== 'object'
|
||||
|| typeof action.id !== 'string'
|
||||
|
|
@ -51,14 +55,14 @@ export default class ExternalShareActions {
|
|||
|| !Array.isArray(action.shareType) // [\@nextcloud/sharing.Types.Link, ...]
|
||||
|| typeof action.handlers !== 'object' // {click: () => {}, ...}
|
||||
|| !Object.values(action.handlers).every(handler => typeof handler === 'function')) {
|
||||
console.error('Invalid action provided', action)
|
||||
logger.error('Invalid action provided', action)
|
||||
return false
|
||||
}
|
||||
|
||||
// Check duplicates
|
||||
const hasDuplicate = this._state.actions.findIndex(check => check.id === action.id) > -1
|
||||
if (hasDuplicate) {
|
||||
console.error(`An action with the same id ${action.id} already exists`, action)
|
||||
logger.error(`An action with the same id ${action.id} already exists`, action)
|
||||
return false
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -187,13 +187,21 @@
|
|||
:checked.sync="showInGridView">
|
||||
{{ t('files_sharing', 'Show files in grid view') }}
|
||||
</NcCheckboxRadioSwitch>
|
||||
<ExternalShareAction v-for="action in externalLinkActions"
|
||||
|
||||
<SidebarTabExternalAction v-for="action in sortedExternalShareActions"
|
||||
:key="action.id"
|
||||
ref="externalShareActions"
|
||||
:action="action"
|
||||
:node="fileInfo.node /* TODO: Fix once we have proper Node API */"
|
||||
:share="share" />
|
||||
<SidebarTabExternalActionLegacy v-for="action in externalLegacyShareActions"
|
||||
:id="action.id"
|
||||
ref="externalLinkActions"
|
||||
:key="action.id"
|
||||
:action="action"
|
||||
:file-info="fileInfo"
|
||||
:share="share" />
|
||||
|
||||
<NcCheckboxRadioSwitch :checked.sync="setCustomPermissions">
|
||||
{{ t('files_sharing', 'Custom permissions') }}
|
||||
</NcCheckboxRadioSwitch>
|
||||
|
|
@ -264,11 +272,13 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { showError } from '@nextcloud/dialogs'
|
||||
import { emit } from '@nextcloud/event-bus'
|
||||
import { getLanguage } from '@nextcloud/l10n'
|
||||
import { ShareType } from '@nextcloud/sharing'
|
||||
import { showError } from '@nextcloud/dialogs'
|
||||
import { getSidebarActions } from '@nextcloud/sharing/ui'
|
||||
import moment from '@nextcloud/moment'
|
||||
import { toRaw } from 'vue'
|
||||
|
||||
import NcAvatar from '@nextcloud/vue/components/NcAvatar'
|
||||
import NcButton from '@nextcloud/vue/components/NcButton'
|
||||
|
|
@ -293,8 +303,8 @@ import MenuDownIcon from 'vue-material-design-icons/MenuDown.vue'
|
|||
import MenuUpIcon from 'vue-material-design-icons/MenuUp.vue'
|
||||
import DotsHorizontalIcon from 'vue-material-design-icons/DotsHorizontal.vue'
|
||||
import Refresh from 'vue-material-design-icons/Refresh.vue'
|
||||
|
||||
import ExternalShareAction from '../components/ExternalShareAction.vue'
|
||||
import SidebarTabExternalAction from '../components/SidebarTabExternal/SidebarTabExternalAction.vue'
|
||||
import SidebarTabExternalActionLegacy from '../components/SidebarTabExternal/SidebarTabExternalActionLegacy.vue'
|
||||
|
||||
import GeneratePassword from '../utils/GeneratePassword.ts'
|
||||
import Share from '../models/Share.ts'
|
||||
|
|
@ -323,7 +333,6 @@ export default {
|
|||
CloseIcon,
|
||||
CircleIcon,
|
||||
EditIcon,
|
||||
ExternalShareAction,
|
||||
LinkIcon,
|
||||
GroupIcon,
|
||||
ShareIcon,
|
||||
|
|
@ -334,7 +343,10 @@ export default {
|
|||
MenuUpIcon,
|
||||
DotsHorizontalIcon,
|
||||
Refresh,
|
||||
SidebarTabExternalAction,
|
||||
SidebarTabExternalActionLegacy,
|
||||
},
|
||||
|
||||
mixins: [ShareRequests, SharesMixin],
|
||||
props: {
|
||||
shareRequestValue: {
|
||||
|
|
@ -365,6 +377,8 @@ export default {
|
|||
initialToken: this.share.token,
|
||||
loadingToken: false,
|
||||
|
||||
externalShareActions: getSidebarActions(),
|
||||
// legacy
|
||||
ExternalShareActions: OCA.Sharing.ExternalShareActions.state,
|
||||
}
|
||||
},
|
||||
|
|
@ -754,8 +768,20 @@ export default {
|
|||
*
|
||||
* @return {Array}
|
||||
*/
|
||||
externalLinkActions() {
|
||||
sortedExternalShareActions() {
|
||||
return this.externalShareActions
|
||||
.filter((action) => action.enabled(toRaw(this.share), toRaw(this.fileInfo.node)))
|
||||
.sort((a, b) => a.order - b.order)
|
||||
},
|
||||
|
||||
/**
|
||||
* Additional actions for the menu
|
||||
*
|
||||
* @return {Array}
|
||||
*/
|
||||
externalLegacyShareActions() {
|
||||
const filterValidAction = (action) => (action.shareType.includes(ShareType.Link) || action.shareType.includes(ShareType.Email)) && action.advanced
|
||||
console.error('legacy details tab', this.ExternalShareActions, this.ExternalShareActions.actions.filter(filterValidAction))
|
||||
// filter only the advanced registered actions for said link
|
||||
return this.ExternalShareActions.actions
|
||||
.filter(filterValidAction)
|
||||
|
|
@ -1038,6 +1064,12 @@ export default {
|
|||
await this.getNode()
|
||||
emit('files:node:updated', this.node)
|
||||
|
||||
if (this.$refs.externalShareActions?.length > 0) {
|
||||
/** @type {import('vue').ComponentPublicInstance<SidebarTabExternalAction>[]} */
|
||||
const actions = this.$refs.externalShareActions
|
||||
await Promise.allSettled(actions.map((action) => action.save()))
|
||||
}
|
||||
|
||||
if (this.$refs.externalLinkActions?.length > 0) {
|
||||
await Promise.allSettled(this.$refs.externalLinkActions.map((action) => {
|
||||
if (typeof action.$children.at(0)?.onSave !== 'function') {
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
<template>
|
||||
<div class="sharingTab" :class="{ 'icon-loading': loading }">
|
||||
<!-- error message -->
|
||||
<div v-if="error" class="emptycontent" :class="{ emptyContentWithSections: sections.length > 0 }">
|
||||
<div v-if="error" class="emptycontent" :class="{ emptyContentWithSections: hasExternalSections }">
|
||||
<div class="icon icon-error" />
|
||||
<h2>{{ error }}</h2>
|
||||
</div>
|
||||
|
|
@ -108,7 +108,7 @@
|
|||
@open-sharing-details="toggleShareDetailsView" />
|
||||
</section>
|
||||
|
||||
<section v-if="sections.length > 0 && !showSharingDetailsView">
|
||||
<section v-if="hasExternalSections && !showSharingDetailsView">
|
||||
<div class="section-header">
|
||||
<h4>{{ t('files_sharing', 'Additional shares') }}</h4>
|
||||
<NcPopover popup-role="dialog">
|
||||
|
|
@ -127,11 +127,18 @@
|
|||
</NcPopover>
|
||||
</div>
|
||||
<!-- additional entries, use it with cautious -->
|
||||
<div v-for="(component, index) in sectionComponents"
|
||||
<SidebarTabExternalSection v-for="section in sortedExternalSections"
|
||||
:key="section.id"
|
||||
:section="section"
|
||||
:node="fileInfo.node /* TODO: Fix once we have proper Node API */"
|
||||
class="sharingTab__additionalContent" />
|
||||
|
||||
<!-- legacy sections: TODO: Remove as soon as possible -->
|
||||
<SidebarTabExternalSectionLegacy v-for="(section, index) in legacySections"
|
||||
:key="index"
|
||||
class="sharingTab__additionalContent">
|
||||
<component :is="component" :file-info="fileInfo" />
|
||||
</div>
|
||||
:file-info="fileInfo"
|
||||
:section-callback="section"
|
||||
class="sharingTab__additionalContent" />
|
||||
|
||||
<!-- projects (deprecated as of NC25 (replaced by related_resources) - see instance config "projects.enabled" ; ignore this / remove it / move into own section) -->
|
||||
<div v-if="projectsEnabled"
|
||||
|
|
@ -161,6 +168,7 @@ import { orderBy } from '@nextcloud/files'
|
|||
import { loadState } from '@nextcloud/initial-state'
|
||||
import { generateOcsUrl } from '@nextcloud/router'
|
||||
import { ShareType } from '@nextcloud/sharing'
|
||||
import { getSidebarSections } from '@nextcloud/sharing/ui'
|
||||
|
||||
import NcAvatar from '@nextcloud/vue/components/NcAvatar'
|
||||
import NcButton from '@nextcloud/vue/components/NcButton'
|
||||
|
|
@ -183,6 +191,8 @@ import SharingInherited from './SharingInherited.vue'
|
|||
import SharingLinkList from './SharingLinkList.vue'
|
||||
import SharingList from './SharingList.vue'
|
||||
import SharingDetailsTab from './SharingDetailsTab.vue'
|
||||
import SidebarTabExternalSection from '../components/SidebarTabExternal/SidebarTabExternalSection.vue'
|
||||
import SidebarTabExternalSectionLegacy from '../components/SidebarTabExternal/SidebarTabExternalSectionLegacy.vue'
|
||||
|
||||
import ShareDetails from '../mixins/ShareDetails.js'
|
||||
import logger from '../services/logger.ts'
|
||||
|
|
@ -205,6 +215,8 @@ export default {
|
|||
SharingLinkList,
|
||||
SharingList,
|
||||
SharingDetailsTab,
|
||||
SidebarTabExternalSection,
|
||||
SidebarTabExternalSectionLegacy,
|
||||
},
|
||||
mixins: [ShareDetails],
|
||||
|
||||
|
|
@ -225,7 +237,9 @@ export default {
|
|||
linkShares: [],
|
||||
externalShares: [],
|
||||
|
||||
sections: OCA.Sharing.ShareTabSections.getSections(),
|
||||
legacySections: OCA.Sharing.ShareTabSections.getSections(),
|
||||
sections: getSidebarSections(),
|
||||
|
||||
projectsEnabled: loadState('core', 'projects_enabled', false),
|
||||
showSharingDetailsView: false,
|
||||
shareDetailsData: {},
|
||||
|
|
@ -238,6 +252,21 @@ export default {
|
|||
},
|
||||
|
||||
computed: {
|
||||
/**
|
||||
* Are any sections registered by other apps.
|
||||
*
|
||||
* @return {boolean}
|
||||
*/
|
||||
hasExternalSections() {
|
||||
return this.sections.length > 0 || this.legacySections.length > 0
|
||||
},
|
||||
|
||||
sortedExternalSections() {
|
||||
return this.sections
|
||||
.filter((section) => section.enabled(this.fileInfo.node))
|
||||
.sort((a, b) => a.order - b.order)
|
||||
},
|
||||
|
||||
/**
|
||||
* Is this share shared with me?
|
||||
*
|
||||
|
|
@ -287,10 +316,6 @@ export default {
|
|||
// TRANSLATORS: Type as in with a keyboard
|
||||
: t('files_sharing', 'Type an email or federated cloud ID')
|
||||
},
|
||||
|
||||
sectionComponents() {
|
||||
return this.sections.map((section) => section(undefined, this.fileInfo))
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
|
|
@ -618,7 +643,7 @@ export default {
|
|||
}
|
||||
|
||||
&__additionalContent {
|
||||
margin: 44px 0;
|
||||
margin: var(--default-clickable-area) 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue