diff options
Diffstat (limited to 'apps/dashboard/src/components')
-rw-r--r-- | apps/dashboard/src/components/ApiDashboardWidget.vue | 116 | ||||
-rw-r--r-- | apps/dashboard/src/components/ApiDashboardWidgetItem.vue | 68 |
2 files changed, 184 insertions, 0 deletions
diff --git a/apps/dashboard/src/components/ApiDashboardWidget.vue b/apps/dashboard/src/components/ApiDashboardWidget.vue new file mode 100644 index 00000000000..4aa8628fac8 --- /dev/null +++ b/apps/dashboard/src/components/ApiDashboardWidget.vue @@ -0,0 +1,116 @@ +<!-- + - SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors + - SPDX-License-Identifier: AGPL-3.0-or-later + --> +<template> + <NcDashboardWidget :items="items" + :show-more-label="showMoreLabel" + :show-more-url="showMoreUrl" + :loading="loading" + :show-items-and-empty-content="!!halfEmptyContentMessage" + :half-empty-content-message="halfEmptyContentMessage"> + <template #default="{ item }"> + <ApiDashboardWidgetItem :item="item" :icon-size="iconSize" :rounded-icons="widget.item_icons_round" /> + </template> + <template #empty-content> + <NcEmptyContent v-if="items.length === 0" + :description="emptyContentMessage"> + <template #icon> + <CheckIcon v-if="emptyContentMessage" :size="65" /> + </template> + <template #action> + <NcButton v-if="setupButton" :href="setupButton.link"> + {{ setupButton.text }} + </NcButton> + </template> + </NcEmptyContent> + </template> + </NcDashboardWidget> +</template> + +<script> +import NcButton from '@nextcloud/vue/components/NcButton' +import NcDashboardWidget from '@nextcloud/vue/components/NcDashboardWidget' +import NcEmptyContent from '@nextcloud/vue/components/NcEmptyContent' +import CheckIcon from 'vue-material-design-icons/Check.vue' +import ApiDashboardWidgetItem from './ApiDashboardWidgetItem.vue' + +export default { + name: 'ApiDashboardWidget', + components: { + ApiDashboardWidgetItem, + CheckIcon, + NcDashboardWidget, + NcEmptyContent, + NcButton, + }, + props: { + widget: { + type: [Object, undefined], + default: undefined, + }, + data: { + type: [Object, undefined], + default: undefined, + }, + loading: { + type: Boolean, + required: true, + }, + }, + data() { + return { + iconSize: 44, + } + }, + computed: { + /** @return {object[]} */ + items() { + return this.data?.items ?? [] + }, + + /** @return {string} */ + emptyContentMessage() { + return this.data?.emptyContentMessage ?? '' + }, + + /** @return {string} */ + halfEmptyContentMessage() { + return this.data?.halfEmptyContentMessage ?? '' + }, + + /** @return {object|undefined} */ + newButton() { + // TODO: Render new button in the template + // I couldn't find a widget that makes use of the button. Furthermore, there is no convenient + // way to render such a button using the official widget component. + return this.widget?.buttons?.find(button => button.type === 'new') + }, + + /** @return {object|undefined} */ + moreButton() { + return this.widget?.buttons?.find(button => button.type === 'more') + }, + + /** @return {object|undefined} */ + setupButton() { + return this.widget?.buttons?.find(button => button.type === 'setup') + }, + + /** @return {string|undefined} */ + showMoreLabel() { + return this.moreButton?.text + }, + + /** @return {string|undefined} */ + showMoreUrl() { + return this.moreButton?.link + }, + }, + mounted() { + const size = window.getComputedStyle(document.body).getPropertyValue('--default-clickable-area') + const numeric = Number.parseFloat(size) + this.iconSize = Number.isNaN(numeric) ? 44 : numeric + }, +} +</script> diff --git a/apps/dashboard/src/components/ApiDashboardWidgetItem.vue b/apps/dashboard/src/components/ApiDashboardWidgetItem.vue new file mode 100644 index 00000000000..2caa7868fb3 --- /dev/null +++ b/apps/dashboard/src/components/ApiDashboardWidgetItem.vue @@ -0,0 +1,68 @@ +<!-- + - SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors + - SPDX-License-Identifier: AGPL-3.0-or-later + --> +<script setup lang="ts"> +import { ref } from 'vue' +import NcAvatar from '@nextcloud/vue/components/NcAvatar' +import NcDashboardWidgetItem from '@nextcloud/vue/components/NcDashboardWidgetItem' +import IconFile from 'vue-material-design-icons/File.vue' + +defineProps({ + item: { + type: Object, + required: true, + }, + iconSize: { + type: Number, + required: true, + }, + roundedIcons: { + type: Boolean, + default: true, + }, +}) + +/** + * True as soon as the image is loaded + */ +const imageLoaded = ref(false) +/** + * True if the image failed to load and we should show a fallback + */ +const loadingImageFailed = ref(false) +</script> + +<template> + <NcDashboardWidgetItem :target-url="item.link" + :overlay-icon-url="item.overlayIconUrl ? item.overlayIconUrl : ''" + :main-text="item.title" + :sub-text="item.subtitle"> + <template #avatar> + <template v-if="item.iconUrl"> + <NcAvatar v-if="roundedIcons" + :size="iconSize" + :url="item.iconUrl" /> + <template v-else> + <img v-show="!loadingImageFailed" + alt="" + class="api-dashboard-widget-item__icon" + :class="{'hidden-visually': !imageLoaded }" + :src="item.iconUrl" + @error="loadingImageFailed = true" + @load="imageLoaded = true"> + <!-- Placeholder while the image is loaded and also the fallback if the URL is broken --> + <IconFile v-if="!imageLoaded" + :size="iconSize" /> + </template> + </template> + </template> + </NcDashboardWidgetItem> +</template> + +<style scoped> +.api-dashboard-widget-item__icon { + height: var(--default-clickable-area); + width: var(--default-clickable-area); +} +</style> |