summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJonas <jonas@freesources.org>2024-08-05 16:09:13 +0200
committerGitHub <noreply@github.com>2024-08-05 16:09:13 +0200
commit5edd2d82921ab99e67990d4384a3c82ab79b1ad3 (patch)
treee69eafa203d44e072216bd81eedf7d65af88ac45
parent5d5a231f5e5cc9f67896300ecd06b3bc90b8d725 (diff)
parent05be5e320697d45371c7a91ae07e31196e931830 (diff)
Merge pull request #4073 from nextcloud/fix/members_list
fix(CircleDetails): Improve calculation of member list
-rw-r--r--src/components/CircleDetails.vue79
1 files changed, 54 insertions, 25 deletions
diff --git a/src/components/CircleDetails.vue b/src/components/CircleDetails.vue
index b5acfeb9..021c45c9 100644
--- a/src/components/CircleDetails.vue
+++ b/src/components/CircleDetails.vue
@@ -76,14 +76,22 @@
<ContentHeading>
{{ t('contacts', 'Members') }}
</ContentHeading>
- <div ref="avatarList" class="avatar-list">
- <Avatar v-for="member in membersLimited"
- :key="member.singleId"
- :user="member.userId"
- :display-name="member.displayName"
- :is-no-user="!member.isUser"
- :size="44" />
- <Button @click="showMembersModal = true">
+ <div class="avatar-box">
+ <div ref="avatarList" class="avatar-list">
+ <Avatar v-for="member in membersLimited"
+ :key="member.singleId"
+ :user="member.userId"
+ :display-name="member.displayName"
+ :is-no-user="!member.isUser"
+ :icon-class="member.isUser ? null : 'icon-group-white'"
+ :size="avatarSize" />
+ <Avatar v-if="hasExtraMembers">
+ <template #icon>
+ <DotsHorizontal :size="16" />
+ </template>
+ </Avatar>
+ </div>
+ <Button class="members-button" @click="showMembersModal = true">
<template #icon>
<AccountMultiplePlus :size="20" />
</template>
@@ -188,9 +196,12 @@
</template>
<script>
-import { showError } from '@nextcloud/dialogs'
+import { ref } from 'vue'
+import { useElementSize } from '@vueuse/core'
import debounce from 'debounce'
-import { useResizeObserver } from '@vueuse/core'
+import { generateOcsUrl } from '@nextcloud/router'
+import { showError } from '@nextcloud/dialogs'
+import axios from '@nextcloud/axios'
import {
NcAppContentDetails as AppContentDetails,
@@ -206,6 +217,7 @@ import Login from 'vue-material-design-icons/Login.vue'
import Logout from 'vue-material-design-icons/Logout.vue'
import IconDelete from 'vue-material-design-icons/Delete.vue'
import AccountMultiplePlus from 'vue-material-design-icons/AccountMultiplePlus.vue'
+import DotsHorizontal from 'vue-material-design-icons/DotsHorizontal.vue'
import { CircleEdit, editCircle } from '../services/circles.ts'
import CircleActionsMixin from '../mixins/CircleActionsMixin.js'
@@ -214,8 +226,6 @@ import CircleConfigs from './CircleDetails/CircleConfigs.vue'
import MemberList from './MemberList.vue'
import ContentHeading from './CircleDetails/ContentHeading.vue'
import CirclePasswordSettings from './CircleDetails/CirclePasswordSettings.vue'
-import axios from '@nextcloud/axios'
-import { generateOcsUrl } from '@nextcloud/router'
export default {
name: 'CircleDetails',
@@ -229,6 +239,7 @@ export default {
CirclePasswordSettings,
ContentHeading,
DetailsHeader,
+ DotsHorizontal,
ListItem,
Cog,
Login,
@@ -241,6 +252,12 @@ export default {
mixins: [CircleActionsMixin],
+ setup() {
+ const avatarList = ref()
+ const { width } = useElementSize(avatarList)
+ return { avatarList, width }
+ },
+
data() {
return {
loadingDescription: false,
@@ -248,7 +265,6 @@ export default {
showSettingsModal: false,
showMembersModal: false,
resources: null,
- memberLimit: 1,
}
},
@@ -275,10 +291,27 @@ export default {
return Object.values(this.$store.getters.getCircle(this.circle.id)?.members || [])
},
+ maxMembers() {
+ // How many avatars (default-clickable-area + 12px gap) fit?
+ const avatarWidth = parseInt(window.getComputedStyle(document.body).getPropertyValue('--default-clickable-area')) + 12
+ const maxMembers = Math.floor(this.width / avatarWidth)
+ return (this.members.length > maxMembers)
+ ? maxMembers - 1
+ : maxMembers
+ },
+
+ memberLimit() {
+ return Math.min(this.members.length, this.maxMembers)
+ },
+
membersLimited() {
return this.members.slice(0, this.memberLimit)
},
+ hasExtraMembers() {
+ return this.members.length > this.maxMembers
+ },
+
resourceProviders() {
return this.resources?.reduce((acc, res) => {
if (!acc.find(p => p.id === res.provider.id)) {
@@ -304,13 +337,6 @@ export default {
},
},
- mounted() {
- this.updateMemberLimit()
- useResizeObserver(this.$refs.avatarList, () => {
- this.updateMemberLimit()
- })
- },
-
methods: {
async fetchTeamResources() {
const response = await axios.get(generateOcsUrl(`/teams/${this.circle.id}/resources`))
@@ -357,10 +383,6 @@ export default {
this.loadingName = false
}
},
- updateMemberLimit() {
- this.memberLimit = Math.floor((this.$refs.avatarList.clientWidth - 44) / 44)
- console.error(this.memberLimit)
- },
},
}
</script>
@@ -410,10 +432,17 @@ export default {
}
}
+.avatar-box {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+}
+
.avatar-list {
display: flex;
flex-wrap: wrap;
- gap: 8px;
+ flex-grow: 1;
+ gap: 12px;
}
.members-modal {