diff options
author | Marcel Klehr <mklehr@gmx.net> | 2022-08-18 14:29:45 +0300 |
---|---|---|
committer | Marcel Klehr <mklehr@gmx.net> | 2022-08-23 15:30:18 +0300 |
commit | 706c560ddaa70ad27a8e992b23081de301a70ea9 (patch) | |
tree | be07e9b57b6ab378af573c8bb6bedd94cb1b9fd8 | |
parent | eb081a40d7b834c8dce5f7a8db1d15f5ac36bf8a (diff) |
Lots of design and UX fixes
Signed-off-by: Marcel Klehr <mklehr@gmx.net>
-rw-r--r-- | src/components/FaceCover.vue | 31 | ||||
-rw-r--r-- | src/components/FaceMergeForm.vue | 32 | ||||
-rw-r--r-- | src/mixins/FaceCoverMixin.js | 4 | ||||
-rw-r--r-- | src/views/FaceContent.vue | 73 | ||||
-rw-r--r-- | src/views/Faces.vue | 12 |
5 files changed, 98 insertions, 54 deletions
diff --git a/src/components/FaceCover.vue b/src/components/FaceCover.vue index 4354daa0..3bc3d836 100644 --- a/src/components/FaceCover.vue +++ b/src/components/FaceCover.vue @@ -30,12 +30,12 @@ </div> <div class="face-cover__details"> <div class="face-cover__details__first-line"> - <h2 class="face-cover__details__name"> + <h2 :class="{'face-cover__details__name': true, 'hidden-visually': baseName.match(/^[0-9]+$/)}"> {{ baseName }} </h2> </div> - <div v-if="facesFiles[baseName]" class="album-cover__details__second-line"> - {{ n('photos', '%n item', '%n items', facesFiles[baseName].length,) }} + <div v-if="facesFiles[baseName]" class="face-cover__details__second-line"> + {{ n('photos', '%n photos', '%n photos', facesFiles[baseName].length,) }} </div> </div> </router-link> @@ -93,7 +93,7 @@ export default { coverDimensions() { if (!this.cover) return {} - return this.getCoverStyle(this.face.basename, 250) + return this.getCoverStyle(this.face.basename) }, }, @@ -118,7 +118,7 @@ export default { display: flex; flex-direction: column; padding: 10px; - border-radius: var(--border-radius); + border-radius: var(--border-radius-large); &__crop-container { overflow: hidden; @@ -127,29 +127,44 @@ export default { border-radius: 250px; position: relative; background: var(--color-background-darker); + --photos-face-width: 250px; + + @media only screen and (max-width: 1020px) { + width: 95px; + height: 95px; + --photos-face-width: 95px; + } } - &:hover { + &:hover, &:focus { background: var(--color-background-hover); } &__details { display: flex; flex-direction: column; + width: 250px; + margin-top: 4px; + + @media only screen and (max-width: 1020px) { + width: 95px; + } &__first-line { display: flex; + height: 2em; + overflow: hidden; + text-overflow: ellipsis; } &__second-line { display: flex; - color: var(--color-text-lighter); + color: var(--color-text-maxcontrast); } &__name { flex-grow: 1; margin: 0; - font-weight: normal; } } } diff --git a/src/components/FaceMergeForm.vue b/src/components/FaceMergeForm.vue index 8f3aa48d..71f19116 100644 --- a/src/components/FaceMergeForm.vue +++ b/src/components/FaceMergeForm.vue @@ -11,10 +11,10 @@ <div class="face-list__item__crop-container"> <img class="face-list__item__image" :src="getCoverUrl(face.basename)" - :style="getCoverStyle(face.basename, 50)"> + :style="getCoverStyle(face.basename)"> </div> <div class="face-list__item__details"> - {{ face.basename }} + <span :class="{'hidden-visually': face.basename.match(/^[0-9]+$/)}">{{ face.basename }}</span> </div> </div> </template> @@ -54,7 +54,12 @@ export default { ]), filteredFaces() { - return Object.values(this.faces).filter(face => face.basename !== this.firstFace) + return Object.values(this.faces).filter(face => face.basename !== this.firstFace).sort((a, b) => { + if (!this.facesFiles[b.basename] || !this.facesFiles[a.basename]) { + return 0 + } + return this.facesFiles[b.basename].length - this.facesFiles[a.basename].length + }) }, }, methods: { @@ -78,16 +83,19 @@ export default { <style scoped lang="scss"> .face-list { display: flex; - flex-direction: column; + flex-direction: row; height: 350px; + flex-wrap: wrap; + padding: 12px; &__item { display: flex; - flex-direction: row; + flex-direction: column; padding: 10px; border-radius: var(--border-radius); align-items: center; cursor: pointer; + width: 120px; * { cursor: pointer; @@ -95,19 +103,25 @@ export default { &__crop-container { overflow: hidden; - width: 50px; - height: 50px; - border-radius: 50px; + width: 60px; + height: 60px; + border-radius: 60px; position: relative; background: var(--color-background-darker); + --photos-face-width: 60px; } - &:hover { + &:hover, &:focus { background: var(--color-background-hover); } &__details { padding: 10px; + height: 1em; + overflow: hidden; + text-overflow: ellipsis; + width: 100%; + text-align: center; } } } diff --git a/src/mixins/FaceCoverMixin.js b/src/mixins/FaceCoverMixin.js index a2b0f7c1..18218159 100644 --- a/src/mixins/FaceCoverMixin.js +++ b/src/mixins/FaceCoverMixin.js @@ -52,7 +52,7 @@ export default { )[0] }, - getCoverStyle(faceName, baseWidth) { + getCoverStyle(faceName) { const cover = this.getFaceCover(faceName) if (!cover) { return {} @@ -64,7 +64,7 @@ export default { return { width: '100%', - transform: `translate(calc( ${baseWidth / 2}px - ${(detection.x + detection.width / 2) * 100}% ), calc( ${baseWidth / 2}px - ${(detection.y + detection.height / 2) * 100}% )) scale(${zoom})`, + transform: `translate(calc( var(--photos-face-width)/2 - ${(detection.x + detection.width / 2) * 100}% ), calc( var(--photos-face-width)/2 - ${(detection.y + detection.height / 2) * 100}% )) scale(${zoom})`, transformOrigin: `${(detection.x + detection.width / 2) * 100}% ${(detection.y + detection.height / 2) * 100}%`, } }, diff --git a/src/views/FaceContent.vue b/src/views/FaceContent.vue index b37876f6..a63a7875 100644 --- a/src/views/FaceContent.vue +++ b/src/views/FaceContent.vue @@ -38,68 +38,77 @@ <div v-else class="album"> <div class="album__header"> <div class="album__header__left"> + <Actions> + <ActionButton @click="$router.push('/faces/')"> + <template #icon> + <ArrowLeft /> + </template>{{ t('photos', 'Back') }} + </ActionButton> + </Actions> <div class="album__header__title"> - <b v-if="face !== undefined" class="album-name"> + <h2 v-if="face !== undefined" :class="{'album-name': true, 'hidden-visually': face.basename.match(/^[0-9]+$/)}"> {{ face.basename }} - </b> + </h2> </div> <Loader v-if="loadingCount > 0 || loadingFaces" /> </div> <div v-if="face !== undefined" class="album__header__actions"> - <Actions :force-menu="true"> + <Actions> <ActionButton :close-after-click="true" :aria-label="t('photos', 'Rename person')" - :title="t('photos', 'Rename person')" @click="showRenameModal = true"> <template #icon> <Pencil /> </template> + {{ t('photos', 'Rename person') }} </ActionButton> + </Actions> + <Actions :force-menu="true"> <ActionButton v-if="Object.keys(faces).length > 1" :close-after-click="true" - :aria-label="t('photos', 'Unify with different person')" - :title="t('photos', 'Unify with different person')" + :aria-label="t('photos', 'Merge with different person')" @click="showMergeModal = true"> <template #icon> <Merge /> </template> + {{ t('photos', 'Merge with different person') }} </ActionButton> <template v-if="selectedFileIds.length"> <ActionButton :close-after-click="true" :aria-label="t('photos', 'Download selected files')" - :title="t('photos', 'Download selected files')" @click="downloadSelection"> - <DownloadOutline slot="icon" /> + <Download slot="icon" /> + {{ t('photos', 'Download selected photos') }} </ActionButton> <ActionButton v-if="shouldFavoriteSelection" :close-after-click="true" :aria-label="t('photos', 'Mark selection as favorite')" - :title="t('photos', 'Favorite')" @click="favoriteSelection"> <Star slot="icon" /> + {{ t('photos', 'Favorite') }} </ActionButton> <ActionButton v-else :close-after-click="true" :aria-label="t('photos', 'Remove selection from favorites')" - :title="t('photos', 'Remove from favorites')" @click="unFavoriteSelection"> <Star slot="icon" /> + {{ t('photos', 'Remove from favorites') }} </ActionButton> <ActionButton :close-after-click="true" - :title="n('photos', 'Remove file from person', 'Remove files from person', selectedFileIds.length)" @click="handleRemoveFilesFromFace(selectedFileIds)"> <template #icon> - <CloseBoxMultiple /> + <Close /> </template> + {{ n('photos', 'Remove photo from person', 'Remove photos from person', selectedFileIds.length) }} </ActionButton> </template> <ActionButton :close-after-click="true" - :title="t('photos', 'Delete person')" @click="handleDeleteFace"> <template #icon> - <TrashCan /> + <Close /> </template> + {{ t('photos', 'Remove person') }} </ActionButton> </Actions> </div> @@ -146,7 +155,7 @@ </Modal> <Modal v-if="showMergeModal" - :title="t('photos', 'Unify person')" + :title="t('photos', 'Merge person')" @close="showMergeModal = false"> <FaceMergeForm :first-face="faceName" @select="handleMerge($event)" /> </Modal> @@ -156,13 +165,13 @@ <script> import { mapActions, mapGetters } from 'vuex' import Pencil from 'vue-material-design-icons/Pencil' -import TrashCan from 'vue-material-design-icons/TrashCan' -import CloseBoxMultiple from 'vue-material-design-icons/CloseBoxMultiple' +import Close from 'vue-material-design-icons/Close' import AlertCircle from 'vue-material-design-icons/AlertCircle' import Star from 'vue-material-design-icons/Star' -import DownloadOutline from 'vue-material-design-icons/DownloadOutline' +import Download from 'vue-material-design-icons/Download' import Send from 'vue-material-design-icons/Send' import Merge from 'vue-material-design-icons/Merge' +import ArrowLeft from 'vue-material-design-icons/ArrowLeft' import { Actions, ActionButton, Modal, EmptyContent, Button } from '@nextcloud/vue' @@ -183,8 +192,8 @@ export default { FaceMergeForm, Pencil, Star, - DownloadOutline, - TrashCan, + Download, + Close, AlertCircle, FilesListViewer, File, @@ -195,8 +204,8 @@ export default { Modal, Send, Button, - CloseBoxMultiple, Merge, + ArrowLeft, }, directives: { @@ -312,8 +321,9 @@ export default { async handleRenameFace(faceName) { try { this.loadingCount++ - await this.renameFace({ oldName: this.faceName, faceName }) this.showRenameModal = false + const oldName = this.faceName + await this.renameFace({ oldName, faceName }) this.$router.push({ name: 'facecontent', params: { faceName } }) } catch (error) { logger.error(error) @@ -375,7 +385,6 @@ export default { .album { display: flex; flex-direction: column; - padding: 8px 64px; &__empty { display: flex; @@ -397,6 +406,12 @@ export default { top: var(--header-height); z-index: 3; background: var(--color-main-background); + padding: 0 64px; + + @media only screen and (max-width: 1020px) { + padding: 0; + padding-left: 64px; + } &__left { height: 100%; @@ -405,10 +420,9 @@ export default { } &__title { - .album-location { - margin-left: -4px; - display: flex; - color: var(--color-text-lighter); + margin-left: 10px; + h2 { + margin-bottom: 0; } } @@ -430,6 +444,11 @@ export default { margin-top: 16px; height: 100%; min-height: 0; // Prevent it from overflowing in a flex context. + padding: 0 64px; + + @media only screen and (max-width: 1020px) { + padding: 0; + } } } diff --git a/src/views/Faces.vue b/src/views/Faces.vue index 010d6089..018ef7dc 100644 --- a/src/views/Faces.vue +++ b/src/views/Faces.vue @@ -27,9 +27,7 @@ <!-- Album list --> <div v-else class="albums"> - <div class="albums__header"> - <Loader v-if="loadingFaces" /> - </div> + <Loader v-if="loadingFaces" /> <!-- No albums --> <div v-if="noFaces && !loadingFaces" class="albums__empty"> @@ -104,14 +102,13 @@ export default { </script> <style lang="scss" scoped> .albums { - height: 100%; display: flex; flex-direction: column; height: calc(100vh - var(--header-height)); - padding: 4px 64px; + padding-left: 64px; - @media only screen and (max-width: 1200px) { - padding: 4px 32px; + @media only screen and (max-width: 1020px) { + padding: 0; } &__header { @@ -125,7 +122,6 @@ export default { } &__list { - margin-top: 8px; padding-top: 24px; padding-bottom: 32px; flex-grow: 1; |