aboutsummaryrefslogtreecommitdiffstats
path: root/apps
diff options
context:
space:
mode:
Diffstat (limited to 'apps')
-rw-r--r--apps/settings/src/components/AppStoreDiscover/AppLink.vue117
-rw-r--r--apps/settings/src/components/AppStoreDiscover/PostType.vue14
2 files changed, 125 insertions, 6 deletions
diff --git a/apps/settings/src/components/AppStoreDiscover/AppLink.vue b/apps/settings/src/components/AppStoreDiscover/AppLink.vue
new file mode 100644
index 00000000000..88006b1d39b
--- /dev/null
+++ b/apps/settings/src/components/AppStoreDiscover/AppLink.vue
@@ -0,0 +1,117 @@
+<!--
+ - @copyright Copyright (c) 2024 Ferdinand Thiessen <opensource@fthiessen.de>
+ -
+ - @author Ferdinand Thiessen <opensource@fthiessen.de>
+ -
+ - @license AGPL-3.0-or-later
+ -
+ - This program is free software: you can redistribute it and/or modify
+ - it under the terms of the GNU Affero General Public License as
+ - published by the Free Software Foundation, either version 3 of the
+ - License, or (at your option) any later version.
+ -
+ - This program is distributed in the hope that it will be useful,
+ - but WITHOUT ANY WARRANTY; without even the implied warranty of
+ - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ - GNU Affero General Public License for more details.
+ -
+ - You should have received a copy of the GNU Affero General Public License
+ - along with this program. If not, see <http://www.gnu.org/licenses/>.
+ -
+ -->
+<template>
+ <a v-if="linkProps" v-bind="linkProps">
+ <slot />
+ </a>
+ <RouterLink v-else-if="routerProps" v-bind="routerProps">
+ <slot />
+ </RouterLink>
+</template>
+
+<script lang="ts">
+import type { RouterLinkProps } from 'vue-router/types/router.js'
+
+import { loadState } from '@nextcloud/initial-state'
+import { generateUrl } from '@nextcloud/router'
+import { defineComponent } from 'vue'
+import { RouterLink } from 'vue-router'
+
+const knownRoutes = Object.fromEntries(
+ Object.entries(
+ loadState<Record<string, { app?: string, href: string }>>('core', 'apps'),
+ ).map(([k, v]) => [v.app ?? k, v.href]),
+)
+
+/**
+ * This component either shows a native link to the installed app or external size - or a router link to the appstore page of the app if not installed
+ */
+export default defineComponent({
+ name: 'AppLink',
+
+ components: { RouterLink },
+
+ props: {
+ href: {
+ type: String,
+ required: true,
+ },
+ },
+
+ data() {
+ return {
+ routerProps: undefined as RouterLinkProps|undefined,
+ linkProps: undefined as Record<string, string>|undefined,
+ }
+ },
+
+ watch: {
+ href: {
+ immediate: true,
+ handler() {
+ const match = this.href.match(/^app:\/\/([^/]+)(\/.+)?$/)
+ this.routerProps = undefined
+ this.linkProps = undefined
+
+ // not an app url
+ if (match === null) {
+ this.linkProps = {
+ href: this.href,
+ target: '_blank',
+ rel: 'noreferrer noopener',
+ }
+ return
+ }
+
+ const appId = match[1]
+ // Check if specific route was requested
+ if (match[2]) {
+ // we do no know anything about app internal path so we only allow generic app paths
+ this.linkProps = {
+ href: generateUrl(`/apps/${appId}${match[2]}`),
+ }
+ return
+ }
+
+ // If we know any route for that app we open it
+ if (appId in knownRoutes) {
+ this.linkProps = {
+ href: knownRoutes[appId],
+ }
+ return
+ }
+
+ // Fallback to show the app store entry
+ this.routerProps = {
+ to: {
+ name: 'apps-details',
+ params: {
+ category: 'installed',
+ id: appId,
+ },
+ },
+ }
+ },
+ },
+ },
+})
+</script>
diff --git a/apps/settings/src/components/AppStoreDiscover/PostType.vue b/apps/settings/src/components/AppStoreDiscover/PostType.vue
index 443daa6287f..df4755483f8 100644
--- a/apps/settings/src/components/AppStoreDiscover/PostType.vue
+++ b/apps/settings/src/components/AppStoreDiscover/PostType.vue
@@ -23,18 +23,18 @@
<article :id="domId"
class="app-discover-post"
:class="{ 'app-discover-post--reverse': media && media.alignment === 'start' }">
- <component :is="link ? 'a' : 'div'"
+ <component :is="link ? 'AppLink' : 'div'"
v-if="headline || text"
:href="link"
- :target="link ? '_blank' : undefined"
class="app-discover-post__text">
- <component :is="inline ? 'h4' : 'h3'">{{ translatedHeadline }}</component>
+ <component :is="inline ? 'h4' : 'h3'">
+ {{ translatedHeadline }}
+ </component>
<p>{{ translatedText }}</p>
</component>
- <component :is="mediaLink ? 'a' : 'div'"
+ <component :is="mediaLink ? 'AppLink' : 'div'"
v-if="mediaSources"
:href="mediaLink"
- :target="mediaLink ? '_blank' : undefined"
class="app-discover-post__media"
:class="{
'app-discover-post__media--fullwidth': isFullWidth,
@@ -79,9 +79,11 @@ import { commonAppDiscoverProps } from './common'
import { useLocalizedValue } from '../../composables/useGetLocalizedValue'
import NcIconSvgWrapper from '@nextcloud/vue/dist/Components/NcIconSvgWrapper.js'
+import AppLink from './AppLink.vue'
export default defineComponent({
components: {
+ AppLink,
NcIconSvgWrapper,
},
@@ -116,8 +118,8 @@ export default defineComponent({
setup(props) {
const translatedHeadline = useLocalizedValue(computed(() => props.headline))
const translatedText = useLocalizedValue(computed(() => props.text))
-
const localizedMedia = useLocalizedValue(computed(() => props.media?.content))
+
const mediaSources = computed(() => localizedMedia.value !== null ? [localizedMedia.value.src].flat() : undefined)
const mediaAlt = computed(() => localizedMedia.value?.alt ?? '')