aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFerdinand Thiessen <opensource@fthiessen.de>2024-02-22 16:45:07 +0100
committerFerdinand Thiessen <opensource@fthiessen.de>2024-03-11 16:02:34 +0100
commit5f19acec9bcff664f4e1516f2a58e1d1de1b7a3b (patch)
tree5a431d96a6f03dcc870a09392065088425a6a887
parent84cb04f7c068defef353db8823ca8666d85874af (diff)
downloadnextcloud-server-5f19acec9bcff664f4e1516f2a58e1d1de1b7a3b.tar.gz
nextcloud-server-5f19acec9bcff664f4e1516f2a58e1d1de1b7a3b.zip
feat: Add composable to fetch app icon as SVG for inline use
Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
-rw-r--r--apps/settings/src/composables/useAppIcon.ts52
1 files changed, 52 insertions, 0 deletions
diff --git a/apps/settings/src/composables/useAppIcon.ts b/apps/settings/src/composables/useAppIcon.ts
new file mode 100644
index 00000000000..719836433e8
--- /dev/null
+++ b/apps/settings/src/composables/useAppIcon.ts
@@ -0,0 +1,52 @@
+import type { Ref } from 'vue'
+import type { IAppstoreApp } from '../app-types.ts'
+
+import { mdiCog } from '@mdi/js'
+import { computed, ref, watchEffect } from 'vue'
+import AppstoreCategoryIcons from '../constants/AppstoreCategoryIcons.ts'
+import logger from '../logger.ts'
+
+/**
+ * Get the app icon raw SVG for use with `NcIconSvgWrapper` (do never use without sanitizing)
+ * It has a fallback to the categroy icon.
+ *
+ * @param app The app to get the icon for
+ */
+export function useAppIcon(app: Ref<IAppstoreApp>) {
+ const appIcon = ref<string|null>(null)
+
+ /**
+ * Fallback value if no app icon available
+ */
+ const categoryIcon = computed(() => {
+ const path = [app.value?.category ?? []].flat()
+ .map((name) => AppstoreCategoryIcons[name])
+ .filter((icon) => !!icon)
+ .at(0)
+ ?? mdiCog
+ return path ? `<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="${path}" /></svg>` : null
+ })
+
+ watchEffect(async () => {
+ // Note: Only variables until the first `await` will be watched!
+ if (!app.value?.preview) {
+ appIcon.value = categoryIcon.value
+ } else {
+ appIcon.value = null
+ // Now try to load the real app icon
+ try {
+ const response = await window.fetch(app.value.preview)
+ const blob = await response.blob()
+ const rawSvg = await blob.text()
+ appIcon.value = rawSvg.replaceAll(/fill="#(fff|ffffff)([a-z0-9]{1,2})?"/ig, 'fill="currentColor"')
+ } catch (error) {
+ appIcon.value = categoryIcon.value
+ logger.error('Could not load app icon', { error })
+ }
+ }
+ })
+
+ return {
+ appIcon,
+ }
+}