aboutsummaryrefslogtreecommitdiffstats
path: root/apps/dashboard/src
diff options
context:
space:
mode:
authorFerdinand Thiessen <opensource@fthiessen.de>2025-01-14 17:55:10 +0100
committerFerdinand Thiessen <opensource@fthiessen.de>2025-01-14 21:51:39 +0100
commitbbde7681520ded0dee0b999d69e5b50789a7ac15 (patch)
treef9354c96781b72f42e55b3d63f40b15b6d5d81e5 /apps/dashboard/src
parent91f568e01b1b91e08874a087ba2e17a9312f11ef (diff)
downloadnextcloud-server-bbde7681520ded0dee0b999d69e5b50789a7ac15.tar.gz
nextcloud-server-bbde7681520ded0dee0b999d69e5b50789a7ac15.zip
fix(dashboard): Correctly handle non-rounded icons for dashboard widgets
Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
Diffstat (limited to 'apps/dashboard/src')
-rw-r--r--apps/dashboard/src/DashboardApp.vue4
-rw-r--r--apps/dashboard/src/components/ApiDashboardWidget.vue29
-rw-r--r--apps/dashboard/src/components/ApiDashboardWidgetItem.vue68
3 files changed, 84 insertions, 17 deletions
diff --git a/apps/dashboard/src/DashboardApp.vue b/apps/dashboard/src/DashboardApp.vue
index 864571842cc..055f1e68cb6 100644
--- a/apps/dashboard/src/DashboardApp.vue
+++ b/apps/dashboard/src/DashboardApp.vue
@@ -461,8 +461,8 @@ export default {
}
},
async fetchApiWidgets() {
- const response = await axios.get(generateOcsUrl('/apps/dashboard/api/v1/widgets'))
- this.apiWidgets = response.data.ocs.data
+ const { data } = await axios.get(generateOcsUrl('/apps/dashboard/api/v1/widgets'))
+ this.apiWidgets = data.ocs.data
},
async fetchApiWidgetItems(widgetIds, merge = false) {
try {
diff --git a/apps/dashboard/src/components/ApiDashboardWidget.vue b/apps/dashboard/src/components/ApiDashboardWidget.vue
index e82b977b041..22834abadd5 100644
--- a/apps/dashboard/src/components/ApiDashboardWidget.vue
+++ b/apps/dashboard/src/components/ApiDashboardWidget.vue
@@ -10,16 +10,7 @@
:show-items-and-empty-content="!!halfEmptyContentMessage"
:half-empty-content-message="halfEmptyContentMessage">
<template #default="{ item }">
- <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 :size="44" :url="item.iconUrl" />
- </template>
- </template>
- </NcDashboardWidgetItem>
+ <ApiDashboardWidgetItem :item="item" :icon-size="iconSize" :rounded-icons="widget.item_icons_round" />
</template>
<template #empty-content>
<NcEmptyContent v-if="items.length === 0"
@@ -39,23 +30,21 @@
<script>
import {
- NcAvatar,
NcDashboardWidget,
- NcDashboardWidgetItem,
NcEmptyContent,
NcButton,
} from '@nextcloud/vue'
import CheckIcon from 'vue-material-design-icons/Check.vue'
+import ApiDashboardWidgetItem from './ApiDashboardWidgetItem.vue'
export default {
name: 'ApiDashboardWidget',
components: {
- NcAvatar,
+ ApiDashboardWidgetItem,
+ CheckIcon,
NcDashboardWidget,
- NcDashboardWidgetItem,
NcEmptyContent,
NcButton,
- CheckIcon,
},
props: {
widget: {
@@ -71,6 +60,11 @@ export default {
required: true,
},
},
+ data() {
+ return {
+ iconSize: 44,
+ }
+ },
computed: {
/** @return {object[]} */
items() {
@@ -115,5 +109,10 @@ export default {
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..e38f745f82a
--- /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/dist/Components/NcAvatar.js'
+import NcDashboardWidgetItem from '@nextcloud/vue/dist/Components/NcDashboardWidgetItem.js'
+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>