Skip to content

Commit

Permalink
Merge pull request #44328 from nextcloud/feat/app-discover-showcase-type
Browse files Browse the repository at this point in the history
feat(settings): Implement `showcase` type for App Discover section
  • Loading branch information
AndyScherzinger authored Mar 19, 2024
2 parents 83746f7 + d58f3e3 commit 400c3b3
Show file tree
Hide file tree
Showing 20 changed files with 320 additions and 52 deletions.
16 changes: 13 additions & 3 deletions apps/settings/src/components/AppList/AppItem.vue
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
-->

<template>
<component :is="listView ? `tr` : `li`"
<component :is="listView ? 'tr' : (inline ? 'article' : 'li')"
class="app-item"
:class="{
'app-item--list-view': listView,
Expand Down Expand Up @@ -82,7 +82,10 @@
<AppLevelBadge :level="app.level" />
<AppScore v-if="hasRating && !listView" :score="app.score" />
</component>
<component :is="dataItemTag" :headers="getDataItemHeaders(`app-table-col-actions`)" class="app-actions">
<component :is="dataItemTag"
v-if="!inline"
:headers="getDataItemHeaders(`app-table-col-actions`)"
class="app-actions">
<div v-if="app.error" class="warning">
{{ app.error }}
</div>
Expand Down Expand Up @@ -145,7 +148,10 @@ export default {
type: Object,
required: true,
},
category: {},
category: {
type: String,
required: true,
},
listView: {
type: Boolean,
default: true,
Expand All @@ -158,6 +164,10 @@ export default {
type: String,
default: null,
},
inline: {
type: Boolean,
default: false,
},
},
data() {
return {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import { parseApiResponse, filterElements } from '../../utils/appDiscoverParser.
const PostType = defineAsyncComponent(() => import('./PostType.vue'))
const CarouselType = defineAsyncComponent(() => import('./CarouselType.vue'))
const ShowcaseType = defineAsyncComponent(() => import('./ShowcaseType.vue'))
const hasError = ref(false)
const elements = ref<IAppDiscoverElements[]>([])
Expand Down Expand Up @@ -89,6 +90,8 @@ const getComponent = (type) => {
return PostType
} else if (type === 'carousel') {
return CarouselType
} else if (type === 'showcase') {
return ShowcaseType
}
return defineComponent({
mounted: () => logger.error('Unknown component requested ', type),
Expand Down
117 changes: 117 additions & 0 deletions apps/settings/src/components/AppStoreDiscover/AppType.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
<!--
- @copyright Copyright (c) 2024 Ferdinand Thiessen <[email protected]>
-
- @author Ferdinand Thiessen <[email protected]>
-
- @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>
<AppItem v-if="app"
:app="app"
category="discover"
class="app-discover-app"
inline
:list-view="false" />
<a v-else
class="app-discover-app app-discover-app__skeleton"
:href="appStoreLink"
target="_blank"
:title="modelValue.appId"
rel="noopener noreferrer">
<!-- This is a fallback skeleton -->
<span class="skeleton-element" />
<span class="skeleton-element" />
<span class="skeleton-element" />
<span class="skeleton-element" />
<span class="skeleton-element" />
</a>
</template>

<script setup lang="ts">
import type { IAppDiscoverApp } from '../../constants/AppDiscoverTypes'
import { computed } from 'vue'
import { useAppsStore } from '../../store/apps-store.ts'
import AppItem from '../AppList/AppItem.vue'
const props = defineProps<{
modelValue: IAppDiscoverApp
}>()
const store = useAppsStore()
const app = computed(() => store.getAppById(props.modelValue.appId))
const appStoreLink = computed(() => props.modelValue.appId ? `https://apps.nextcloud.com/apps/${props.modelValue.appId}` : '#')
</script>

<style scoped lang="scss">
.app-discover-app {
width: 100% !important; // full with of the showcase item
&:hover {
background: var(--color-background-hover);
border-radius: var(--border-radius-rounded);
}
&__skeleton {
display: flex;
flex-direction: column;
gap: 8px;
padding: 30px; // Same as AppItem
> :first-child {
height: 50%;
min-height: 130px;
}
> :nth-child(2) {
width: 50px;
}
> :nth-child(5) {
height: 20px;
width: 100px;
}
> :not(:first-child) {
border-radius: 4px;
}
}
}
.skeleton-element {
min-height: var(--default-font-size, 15px);
background: linear-gradient(90deg, var(--color-background-dark), var(--color-background-darker), var(--color-background-dark));
background-size: 400% 400%;
animation: gradient 6s ease infinite;
}
@keyframes gradient {
0% {
background-position: 0% 50%;
}
50% {
background-position: 100% 50%;
}
100% {
background-position: 0% 50%;
}
}
</style>
28 changes: 23 additions & 5 deletions apps/settings/src/components/AppStoreDiscover/PostType.vue
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,12 @@
-->
<template>
<article :id="domId"
ref="container"
class="app-discover-post"
:class="{ 'app-discover-post--reverse': media && media.alignment === 'start' }">
:class="{
'app-discover-post--reverse': media && media.alignment === 'start',
'app-discover-post--small': isSmallWidth
}">
<component :is="link ? 'AppLink' : 'div'"
v-if="headline || text"
:href="link"
Expand Down Expand Up @@ -73,7 +77,7 @@ import type { PropType } from 'vue'
import { mdiPlayCircleOutline } from '@mdi/js'
import { generateUrl } from '@nextcloud/router'
import { useElementVisibility } from '@vueuse/core'
import { useElementSize, useElementVisibility } from '@vueuse/core'
import { computed, defineComponent, ref, watchEffect } from 'vue'
import { commonAppDiscoverProps } from './common'
import { useLocalizedValue } from '../../composables/useGetLocalizedValue'
Expand Down Expand Up @@ -138,6 +142,14 @@ export default defineComponent({
const hasPlaybackEnded = ref(false)
const showPlayVideo = computed(() => localizedMedia.value?.link && hasPlaybackEnded.value)
/**
* The content is sized / styles are applied based on the container width
* To make it responsive even for inline usage and when opening / closing the sidebar / navigation
*/
const container = ref<HTMLElement>()
const { width: containerWidth } = useElementSize(container)
const isSmallWidth = computed(() => containerWidth.value < 600)
/**
* Generate URL for cached media to prevent user can be tracked
* @param url The URL to resolve
Expand Down Expand Up @@ -171,6 +183,8 @@ export default defineComponent({
return {
mdiPlayCircleOutline,
container,
translatedText,
translatedHeadline,
mediaElement,
Expand All @@ -182,6 +196,7 @@ export default defineComponent({
showPlayVideo,
isFullWidth,
isSmallWidth,
isImage,
generatePrivacyUrl,
Expand All @@ -199,6 +214,8 @@ export default defineComponent({
display: flex;
flex-direction: row;
justify-content: start;
&--reverse {
flex-direction: row-reverse;
}
Expand Down Expand Up @@ -264,16 +281,17 @@ export default defineComponent({
}
}
// Ensure section works on mobile devices
@media only screen and (max-width: 699px) {
.app-discover-post {
.app-discover-post--small {
&.app-discover-post {
flex-direction: column;
max-height: 500px;
&--reverse {
flex-direction: column-reverse;
}
}
.app-discover-post {
&__text {
flex: 1 1 50%;
}
Expand Down
Loading

0 comments on commit 400c3b3

Please sign in to comment.