2727 </template >
2828 </NcEmptyContent >
2929
30- <div v-else class =" member-grid" >
31- <MemberGridItem v-for =" member in flatList"
32- :key =" `member-grid-item-${member.id}`"
33- :member =" member"
34- :is-team =" !member.isUser" />
35- </div >
30+ <template v-else >
31+ <NcTextField
32+ v-if =" flatList.length > 20"
33+ v-model =" searchQuery"
34+ :label =" t('contacts', 'Search among current members')"
35+ trailing-button-icon =" close"
36+ :show-trailing-button =" searchQuery !== ''"
37+ @trailing-button-click =" clearSearchField" >
38+ <IconSearch :size =" 20" />
39+ </NcTextField >
40+ <RecycleScroller
41+ ref =" scroller"
42+ class =" member-scroller"
43+ :items =" filteredList"
44+ :item-size =" 56"
45+ :grid-items =" gridItems"
46+ :item-secondary-size =" itemSecondarySize" >
47+ <template #default =" { item } " >
48+ <MemberGridItem
49+ :key =" `member-grid-item-${item.id}`"
50+ :member =" item"
51+ :is-team =" !item.isUser" />
52+ </template >
53+ <template #empty v-if =" ! filteredList .length " >
54+ <div style =" margin-top : 2rem ;" >
55+ <NcEmptyContent :name =" t('contacts', 'No results found')" >
56+ <template #icon >
57+ <IconSearch :size =" 20" />
58+ </template >
59+ </NcEmptyContent >
60+ </div >
61+ </template >
62+ </RecycleScroller >
63+ </template >
3664
3765 <!-- member picker -->
3866 <EntityPicker v-if =" showPicker"
5381import {
5482 NcEmptyContent ,
5583 isMobile ,
84+ NcLoadingIcon as IconLoading ,
85+ NcTextField
5686} from ' @nextcloud/vue'
87+ import { RecycleScroller } from ' vue-virtual-scroller'
88+ import ' vue-virtual-scroller/dist/vue-virtual-scroller.css'
5789
5890import MemberGridItem from ' ./MemberGridItem.vue'
5991import EntityPicker from ' ../EntityPicker/EntityPicker.vue'
6092import IconContact from ' vue-material-design-icons/AccountMultipleOutline.vue'
93+ import IconSearch from ' vue-material-design-icons/Magnify.vue'
6194
6295import RouterMixin from ' ../../mixins/RouterMixin.js'
6396
@@ -74,8 +107,12 @@ export default defineComponent({
74107 components: {
75108 EntityPicker ,
76109 IconContact ,
110+ IconLoading ,
111+ IconSearch ,
77112 MemberGridItem ,
78113 NcEmptyContent ,
114+ RecycleScroller ,
115+ NcTextField ,
79116 },
80117
81118 mixins: [isMobile , RouterMixin ],
@@ -103,6 +140,8 @@ export default defineComponent({
103140 pickerData: [],
104141 pickerSelection: {},
105142 pickerTypes: CIRCLES_MEMBER_GROUPING ,
143+ windowWidth: window .innerWidth ,
144+ searchQuery: ' ' ,
106145 }
107146 },
108147
@@ -134,17 +173,59 @@ export default defineComponent({
134173 return [... teams , ... users ]
135174 },
136175
176+ filteredList() {
177+ const query = this .searchQuery .toLowerCase ()
178+
179+ return this .flatList .filter (member =>
180+ ! this .searchQuery || member .displayName .toLowerCase ().includes (query )
181+ );
182+ },
183+
137184 hasMembers() {
138185 return this .flatList .length > 0
139186 },
187+
188+ gridItems() {
189+ if (this .windowWidth < 768 ) {
190+ // undefined means that the grid will be rendered as a list
191+ return undefined
192+ }
193+
194+ return 2
195+ },
196+
197+ itemSecondarySize() {
198+ if (this .windowWidth < 768 ) {
199+ // undefined means that the grid will be rendered as a list
200+ return undefined
201+ }
202+
203+ // The maximum width of the member list is 500px,
204+ // so with two columns, each column is 242px wide (with scroll)
205+ return 242
206+ },
140207 },
141208
142209 mounted() {
143210 subscribe (' contacts:circles:append' , this .onShowPicker )
144211 subscribe (' guests:user:created' , this .onGuestCreated )
212+
213+ window .addEventListener (' resize' , this .onResize )
214+ },
215+
216+ beforeDestroy() {
217+ window .removeEventListener (' resize' , this .onResize )
145218 },
146219
147220 methods: {
221+ onResize() {
222+ this .windowWidth = window .innerWidth
223+ },
224+
225+ clearSearchField() {
226+ this .searchQuery = ' '
227+ },
228+
148229 /**
149230 * Show picker and fetch for recommendations
150231 * Cache the circleId in case the url change or something
@@ -260,18 +341,9 @@ export default defineComponent({
260341 }
261342}
262343
263- .member-grid {
264- display : grid ;
265- grid-template-columns : repeat (2 , 1fr );
266- gap : 8px ;
267-
268- @media (max-width : 768px ) {
269- grid-template-columns : 1fr ;
270- }
271-
272- @media (min-width : 1200px ) {
273- grid-template-columns : repeat (3 , 1fr );
274- }
344+ .member-scroller {
345+ height : 100% ;
346+ max-height : 200px ;
275347}
276348
277349.empty-content {
0 commit comments