aboutsummaryrefslogtreecommitdiffstats
path: root/apps/settings/src/composables/useAppIcon.ts
blob: 60c3ee6e3ea40a2b5f0185f422a1ea79ea7392df (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
/**
 * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
 * SPDX-License-Identifier: AGPL-3.0-or-later
 */
import type { Ref } from 'vue'
import type { IAppstoreApp } from '../app-types.ts'

import { mdiCog, mdiCogOutline } 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(() => {
		let path: string
		if (app.value?.app_api) {
			// Use different default icon for ExApps (AppAPI)
			path = mdiCogOutline
		} else {
			path = [app.value?.category ?? []].flat()
					.map((name) => AppstoreCategoryIcons[name])
					.filter((icon) => !!icon)
					.at(0)
				?? (!app.value?.app_api ? mdiCog : mdiCogOutline)
		}
		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,
	}
}