Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nextcloud/photos.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'src/components/Collection')
-rw-r--r--src/components/Collection/CollectionContent.vue154
-rw-r--r--src/components/Collection/CollectionCover.vue141
-rw-r--r--src/components/Collection/CollectionsList.vue104
3 files changed, 399 insertions, 0 deletions
diff --git a/src/components/Collection/CollectionContent.vue b/src/components/Collection/CollectionContent.vue
new file mode 100644
index 00000000..5e483317
--- /dev/null
+++ b/src/components/Collection/CollectionContent.vue
@@ -0,0 +1,154 @@
+<!--
+ - @copyright Copyright (c) 2022 Louis Chemineau <louis@chmn.me>
+ -
+ - @author Louis Chemineau <louis@chmn.me>
+ -
+ - @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>
+ <!-- Errors handlers-->
+ <NcEmptyContent v-if="collection === undefined && !loading"
+ class="empty-content-with-illustration"
+ :title="t('photos', 'This collection does not exist')">
+ <FolderMultipleImage />
+ </NcEmptyContent>
+ <NcEmptyContent v-else-if="error" :title="t('photos', 'An error occurred')">
+ <AlertCircle slot="icon" />
+ </NcEmptyContent>
+
+ <div v-else class="collection">
+ <!-- Header -->
+ <slot class="collection__header" name="header" :selected-file-ids="selectedFileIds" />
+
+ <!-- No content -->
+ <slot v-if="collectionFileIds.length === 0 && !loading" name="empty-content" />
+
+ <!-- Media list -->
+ <FilesListViewer v-if="collection !== undefined"
+ :container-element="appContent"
+ class="collection__media"
+ :file-ids="collectionFileIds"
+ :base-height="isMobile ? 120 : 200"
+ :loading="loading">
+ <File slot-scope="{file, visibility}"
+ :file="files[file.id]"
+ :allow-selection="true"
+ :selected="selection[file.id] === true"
+ :visibility="visibility"
+ :semaphore="semaphore"
+ @click="openViewer"
+ @select-toggled="onFileSelectToggle" />
+ </FilesListViewer>
+ </div>
+</template>
+
+<script>
+import { mapGetters } from 'vuex'
+import AlertCircle from 'vue-material-design-icons/AlertCircle'
+import FolderMultipleImage from 'vue-material-design-icons/FolderMultipleImage'
+
+import { NcEmptyContent, isMobile } from '@nextcloud/vue'
+
+import FilesSelectionMixin from '../../mixins/FilesSelectionMixin.js'
+import FilesListViewer from '.././FilesListViewer.vue'
+import File from '.././File.vue'
+import FolderIllustration from '../../assets/Illustrations/folder.svg'
+import SemaphoreWithPriority from '../../utils/semaphoreWithPriority.js'
+
+export default {
+ name: 'CollectionContent',
+
+ components: {
+ AlertCircle,
+ FolderMultipleImage,
+ NcEmptyContent,
+ FilesListViewer,
+ File,
+ },
+
+ mixins: [
+ FilesSelectionMixin,
+ isMobile,
+ ],
+
+ props: {
+ collection: {
+ type: Object,
+ default: () => undefined,
+ },
+
+ collectionFileIds: {
+ type: Array,
+ required: true,
+ },
+
+ loading: {
+ type: Boolean,
+ default: false,
+ },
+
+ error: {
+ type: [Error],
+ default: '',
+ },
+
+ semaphore: {
+ type: SemaphoreWithPriority,
+ required: true,
+ },
+ },
+
+ data() {
+ return {
+ FolderIllustration,
+ appContent: document.getElementById('app-content-vue'),
+ }
+ },
+
+ computed: {
+ ...mapGetters([
+ 'files',
+ ]),
+ },
+
+ methods: {
+ openViewer(fileId) {
+ const file = this.files[fileId]
+ OCA.Viewer.open({
+ fileInfo: file,
+ list: this.collectionFileIds.map(fileId => this.files[fileId]).filter(file => !file.sectionHeader),
+ loadMore: file.loadMore ? async () => await file.loadMore(true) : () => [],
+ canLoop: file.canLoop,
+ })
+ },
+ },
+}
+</script>
+<style lang="scss" scoped>
+.collection {
+ display: flex;
+ flex-direction: column;
+
+ &__media {
+ padding: 0 64px;
+
+ @media only screen and (max-width: 1200px) {
+ padding: 0 4px;
+ }
+ }
+}
+</style>
diff --git a/src/components/Collection/CollectionCover.vue b/src/components/Collection/CollectionCover.vue
new file mode 100644
index 00000000..2d35365e
--- /dev/null
+++ b/src/components/Collection/CollectionCover.vue
@@ -0,0 +1,141 @@
+<!--
+ - @copyright Copyright (c) 2022 Louis Chemineau <louis@chmn.me>
+ -
+ - @author Louis Chemineau <louis@chmn.me>
+ -
+ - @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>
+ <li>
+ <router-link class="collection-cover" :to="link">
+ <img v-if="coverUrl !== ''"
+ class="collection-cover__image"
+ :src="coverUrl"
+ :alt="altImg">
+
+ <div v-else class="collection-cover__image collection-cover__image--placeholder">
+ <ImageMultiple :size="128" />
+ </div>
+ <div class="collection-cover__details">
+ <div class="collection-cover__details__title">
+ <slot name="default" />
+ </div>
+ <div class="collection-cover__details__subtitle">
+ <slot name="subtitle" />
+ </div>
+ </div>
+ </router-link>
+ </li>
+</template>
+
+<script>
+
+import { mapGetters } from 'vuex'
+// import ShareVariant from 'vue-material-design-icons/ShareVariant'
+// import AccountMultiple from 'vue-material-design-icons/AccountMultiple'
+import ImageMultiple from 'vue-material-design-icons/ImageMultiple'
+
+export default {
+ name: 'CollectionCover',
+
+ components: {
+ ImageMultiple,
+ },
+
+ props: {
+ coverUrl: {
+ type: String,
+ required: true,
+ },
+ altImg: {
+ type: String,
+ required: true,
+ },
+ link: {
+ type: String,
+ required: true,
+ },
+ },
+
+ computed: {
+ ...mapGetters([
+ 'files',
+ 'albums',
+ ]),
+ },
+}
+</script>
+
+<style lang="scss" scoped>
+.collection-cover {
+ display: flex;
+ flex-direction: column;
+ padding: 16px;
+ border-radius: var(--border-radius-large);
+
+ &:hover, &:focus {
+ background: var(--color-background-dark);
+ }
+
+ &__image {
+ width: 350px;
+ height: 350px;
+ object-fit: none;
+ border-radius: var(--border-radius-large);
+
+ @media only screen and (max-width: 1200px) {
+ width: 250px;
+ height: 250px;
+ }
+
+ &--placeholder {
+ background: var(--color-primary-light);
+
+ ::v-deep .material-design-icon {
+ width: 100%;
+ height: 100%;
+
+ .material-design-icon__svg {
+ fill: var(--color-primary);
+ }
+ }
+ }
+ }
+
+ &__details {
+ display: flex;
+ flex-direction: column;
+ margin-top: 16px;
+ width: 350px;
+
+ @media only screen and (max-width: 1200px) {
+ width: 250px;
+ }
+
+ &__title {
+ display: flex;
+ }
+
+ &__subtitle {
+ display: flex;
+ color: var(--color-text-lighter);
+ }
+ }
+
+}
+</style>
diff --git a/src/components/Collection/CollectionsList.vue b/src/components/Collection/CollectionsList.vue
new file mode 100644
index 00000000..c9256ac0
--- /dev/null
+++ b/src/components/Collection/CollectionsList.vue
@@ -0,0 +1,104 @@
+<!--
+ - @copyright Copyright (c) 2022 Louis Chemineau <louis@chmn.me>
+ -
+ - @author Louis Chemineau <louis@chmn.me>
+ -
+ - @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>
+ <!-- Errors handlers-->
+ <NcEmptyContent v-if="error" :title="t('photos', 'An error occurred') ">
+ <AlertCircle slot="icon" />
+ </NcEmptyContent>
+
+ <div v-else class="collections">
+ <!-- Collection header -->
+ <slot name="header" />
+
+ <!-- No collections -->
+ <slot v-if="noCollection && !loading" name="empty-collections-list" class="collections__empty" />
+
+ <!-- List -->
+ <ul v-else-if="!noCollection" class="collections__list">
+ <slot v-for="collection in collections"
+ :collection="collection"
+ class="collection" />
+ </ul>
+ </div>
+</template>
+
+<script>
+import AlertCircle from 'vue-material-design-icons/AlertCircle'
+
+import { NcEmptyContent } from '@nextcloud/vue'
+
+export default {
+ name: 'CollectionsList',
+
+ components: {
+ AlertCircle,
+ NcEmptyContent,
+ },
+
+ props: {
+ collections: {
+ type: Object,
+ required: true,
+ },
+ loading: {
+ type: Boolean,
+ default: false,
+ },
+ error: {
+ type: Error,
+ default: null,
+ },
+ },
+
+ computed: {
+ /**
+ * @return {boolean} Whether the list of collections is empty or not.
+ */
+ noCollection() {
+ return Object.keys(this.collections).length === 0
+ },
+ },
+}
+</script>
+<style lang="scss" scoped>
+.collections {
+ display: flex;
+ flex-direction: column;
+ height: 100%;
+
+ &__list {
+ padding: 32px 48px;
+ flex-grow: 1;
+ display: flex;
+ flex-wrap: wrap;
+ gap: 16px;
+ align-items: flex-start;
+ height: calc(100% - 60px);
+ overflow-x: scroll;
+
+ @media only screen and (max-width: 1200px) {
+ padding: 32px 12px;
+ justify-content: center;
+ }
+ }
+}
+</style>