diff options
author | Ferdinand Thiessen <opensource@fthiessen.de> | 2024-03-19 16:34:36 +0100 |
---|---|---|
committer | Ferdinand Thiessen <opensource@fthiessen.de> | 2024-03-19 20:10:20 +0100 |
commit | a735e7dea3e5c9f37ec6e6440cfdcc331a8c5478 (patch) | |
tree | 566e2bf0039270298f19290d0d1a4a2e9d38d54d /apps/settings | |
parent | e245c3df12e956d10004ae62db5f7a60c08d6a3b (diff) | |
download | nextcloud-server-a735e7dea3e5c9f37ec6e6440cfdcc331a8c5478.tar.gz nextcloud-server-a735e7dea3e5c9f37ec6e6440cfdcc331a8c5478.zip |
feat(settings): Implement `showcase` type for App Discover section
Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
Diffstat (limited to 'apps/settings')
3 files changed, 144 insertions, 0 deletions
diff --git a/apps/settings/src/components/AppStoreDiscover/AppStoreDiscoverSection.vue b/apps/settings/src/components/AppStoreDiscover/AppStoreDiscoverSection.vue index 5c167c22abd..4e20a55bcde 100644 --- a/apps/settings/src/components/AppStoreDiscover/AppStoreDiscoverSection.vue +++ b/apps/settings/src/components/AppStoreDiscover/AppStoreDiscoverSection.vue @@ -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[]>([]) @@ -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), diff --git a/apps/settings/src/components/AppStoreDiscover/PostType.vue b/apps/settings/src/components/AppStoreDiscover/PostType.vue index c5b5d1cfc03..c03cac4feaf 100644 --- a/apps/settings/src/components/AppStoreDiscover/PostType.vue +++ b/apps/settings/src/components/AppStoreDiscover/PostType.vue @@ -214,6 +214,8 @@ export default defineComponent({ display: flex; flex-direction: row; + justify-content: start; + &--reverse { flex-direction: row-reverse; } diff --git a/apps/settings/src/components/AppStoreDiscover/ShowcaseType.vue b/apps/settings/src/components/AppStoreDiscover/ShowcaseType.vue new file mode 100644 index 00000000000..cb4d118dd83 --- /dev/null +++ b/apps/settings/src/components/AppStoreDiscover/ShowcaseType.vue @@ -0,0 +1,139 @@ +<!-- + - @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> + <section ref="container" + class="app-discover-showcase" + :class="{ + 'app-discover-showcase--small': isSmallWidth, + 'app-discover-showcase--extra-small': isExtraSmallWidth, + }"> + <h3 v-if="translatedHeadline"> + {{ translatedHeadline }} + </h3> + <ul class="app-discover-showcase__list"> + <li v-for="(item, index) of content" + :key="item.id ?? index" + class="app-discover-showcase__item"> + <PostType v-if="item.type === 'post'" + v-bind="item" + inline /> + <AppType v-else-if="item.type === 'app'" :model-value="item" /> + </li> + </ul> + </section> +</template> + +<script lang="ts"> +import type { PropType } from 'vue' +import type { IAppDiscoverShowcase } from '../../constants/AppDiscoverTypes.ts' + +import { translate as t } from '@nextcloud/l10n' +import { useElementSize } from '@vueuse/core' +import { computed, defineComponent, ref } from 'vue' +import { commonAppDiscoverProps } from './common.ts' +import { useLocalizedValue } from '../../composables/useGetLocalizedValue.ts' + +import AppType from './AppType.vue' +import PostType from './PostType.vue' + +export default defineComponent({ + name: 'ShowcaseType', + + components: { + AppType, + PostType, + }, + + props: { + ...commonAppDiscoverProps, + + /** + * The content of the carousel + */ + content: { + type: Array as PropType<IAppDiscoverShowcase['content']>, + required: true, + }, + }, + + setup(props) { + const translatedHeadline = useLocalizedValue(computed(() => props.headline)) + + /** + * Make the element responsive based on the container width to also handle open navigation or sidebar + */ + const container = ref<HTMLElement>() + const { width: containerWidth } = useElementSize(container) + const isSmallWidth = computed(() => containerWidth.value < 768) + const isExtraSmallWidth = computed(() => containerWidth.value < 512) + + return { + t, + + container, + isSmallWidth, + isExtraSmallWidth, + translatedHeadline, + } + }, +}) +</script> + +<style scoped lang="scss"> +$item-gap: calc(var(--default-clickable-area, 44px) / 2); + +h3 { + font-size: 24px; + font-weight: 600; + margin-block: 0 1em; +} + +.app-discover-showcase { + &__list { + list-style: none; + + display: flex; + flex-wrap: wrap; + gap: $item-gap; + } + + &__item { + display: flex; + align-items: stretch; + + position: relative; + width: calc(33% - $item-gap); + } +} + +.app-discover-showcase--small { + .app-discover-showcase__item { + width: calc(50% - $item-gap); + } +} + +.app-discover-showcase--extra-small { + .app-discover-showcase__item { + width: 100%; + } +} +</style> |