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:
authorMarcel Klehr <mklehr@gmx.net>2022-08-18 14:29:45 +0300
committerMarcel Klehr <mklehr@gmx.net>2022-08-23 15:30:18 +0300
commit706c560ddaa70ad27a8e992b23081de301a70ea9 (patch)
treebe07e9b57b6ab378af573c8bb6bedd94cb1b9fd8
parenteb081a40d7b834c8dce5f7a8db1d15f5ac36bf8a (diff)
Lots of design and UX fixes
Signed-off-by: Marcel Klehr <mklehr@gmx.net>
-rw-r--r--src/components/FaceCover.vue31
-rw-r--r--src/components/FaceMergeForm.vue32
-rw-r--r--src/mixins/FaceCoverMixin.js4
-rw-r--r--src/views/FaceContent.vue73
-rw-r--r--src/views/Faces.vue12
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;