mirror of
https://github.com/Ocelot-Social-Community/Ocelot-Social.git
synced 2025-12-13 07:46:06 +00:00
Move important parts of 'FollowList' to sub component 'ProfileList'
This commit is contained in:
parent
a9376cb979
commit
b7be7018e8
@ -1,64 +1,28 @@
|
|||||||
<template>
|
<template>
|
||||||
<base-card class="follow-list">
|
<profile-list
|
||||||
<template v-if="connections && connections.length">
|
:uniqueName="`${type}Filter`"
|
||||||
<h5 class="title spacer-x-small">
|
:title="$filters.truncate(userName, 15) + ' ' + $t(`profile.network.${type}`)"
|
||||||
{{ userName | truncate(15) }} {{ $t(`profile.network.${type}`) }}
|
:titleNobody="$filters.truncate(userName, 15) + ' ' + $t(`profile.network.${type}Nobody`)"
|
||||||
</h5>
|
:allConnectionsCount="allConnectionsCount"
|
||||||
<ul :class="connectionsClass">
|
:connections="connections"
|
||||||
<li
|
:loading="loading"
|
||||||
v-for="connection in filteredConnections"
|
@fetchAllConnections="$emit('fetchAllConnections', type)"
|
||||||
:key="connection.id"
|
/>
|
||||||
class="connections__item"
|
|
||||||
>
|
|
||||||
<user-teaser :user="connection" />
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<base-button
|
|
||||||
v-if="hasMore"
|
|
||||||
:loading="loading"
|
|
||||||
class="spacer-x-small"
|
|
||||||
size="small"
|
|
||||||
@click="$emit('fetchAllConnections', type)"
|
|
||||||
>
|
|
||||||
{{
|
|
||||||
$t('profile.network.andMore', {
|
|
||||||
number: allConnectionsCount - connections.length,
|
|
||||||
})
|
|
||||||
}}
|
|
||||||
</base-button>
|
|
||||||
<ds-input
|
|
||||||
v-if="!hasMore"
|
|
||||||
:name="`${type}Filter`"
|
|
||||||
:placeholder="filter"
|
|
||||||
class="spacer-x-small"
|
|
||||||
icon="filter"
|
|
||||||
size="small"
|
|
||||||
@input.native="setFilter"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
<p v-else class="nobody-message">{{ userName }} {{ $t(`profile.network.${type}Nobody`) }}</p>
|
|
||||||
</base-card>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { escape } from 'xregexp/xregexp-all.js'
|
import ProfileList from '~/components/features/ProfileList/ProfileList'
|
||||||
import UserTeaser from '~/components/UserTeaser/UserTeaser'
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'FollowerList',
|
name: 'FollowerList',
|
||||||
components: {
|
components: {
|
||||||
UserTeaser,
|
ProfileList,
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
user: { type: Object, default: null },
|
user: { type: Object, default: null },
|
||||||
type: { type: String, default: 'following' },
|
type: { type: String, default: 'following' },
|
||||||
loading: { type: Boolean, default: false },
|
loading: { type: Boolean, default: false },
|
||||||
},
|
},
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
filter: null,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
computed: {
|
computed: {
|
||||||
userName() {
|
userName() {
|
||||||
const { name } = this.user || {}
|
const { name } = this.user || {}
|
||||||
@ -70,95 +34,6 @@ export default {
|
|||||||
connections() {
|
connections() {
|
||||||
return this.user[this.type]
|
return this.user[this.type]
|
||||||
},
|
},
|
||||||
hasMore() {
|
|
||||||
return this.allConnectionsCount > this.connections.length
|
|
||||||
},
|
|
||||||
connectionsClass() {
|
|
||||||
return `connections${this.hasMore ? '' : ' --overflow'}`
|
|
||||||
},
|
|
||||||
filteredConnections() {
|
|
||||||
if (!this.filter) {
|
|
||||||
return this.connections
|
|
||||||
}
|
|
||||||
|
|
||||||
// @example
|
|
||||||
// this.filter = 'foo';
|
|
||||||
// fuzzyExpression = /([^f]*f)([^o]*o)([^o]*o)/i
|
|
||||||
const fuzzyExpression = new RegExp(
|
|
||||||
`${this.filter.split('').reduce((expr, c) => `${expr}([^${escape(c)}]*${escape(c)})`, '')}`,
|
|
||||||
'i',
|
|
||||||
)
|
|
||||||
|
|
||||||
const fuzzyScores = this.connections
|
|
||||||
.map((user) => {
|
|
||||||
const match = user.name.match(fuzzyExpression)
|
|
||||||
|
|
||||||
if (!match) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
let score = 1
|
|
||||||
for (let i = 1; i <= this.filter.length; i++) {
|
|
||||||
score *= match[i].length
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
user,
|
|
||||||
score,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.filter(Boolean)
|
|
||||||
.sort((a, b) => a.score - b.score)
|
|
||||||
|
|
||||||
return fuzzyScores.map((score) => score.user)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
setFilter(evt) {
|
|
||||||
this.filter = evt.target.value
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
.follow-list {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
position: relative;
|
|
||||||
width: auto;
|
|
||||||
|
|
||||||
> .title {
|
|
||||||
color: $text-color-soft;
|
|
||||||
font-size: $font-size-base;
|
|
||||||
}
|
|
||||||
|
|
||||||
.connections {
|
|
||||||
height: $size-height-connections;
|
|
||||||
padding: $space-none;
|
|
||||||
list-style-type: none;
|
|
||||||
|
|
||||||
&.--overflow {
|
|
||||||
overflow-y: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
> .connections__item {
|
|
||||||
padding: $space-xx-small;
|
|
||||||
|
|
||||||
&.is-selected,
|
|
||||||
&:hover {
|
|
||||||
background-color: $background-color-primary-inverse;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.nobody-message {
|
|
||||||
text-align: center;
|
|
||||||
color: $text-color-soft;
|
|
||||||
}
|
|
||||||
|
|
||||||
> :nth-child(n):not(:last-child) {
|
|
||||||
margin-bottom: $space-small;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|||||||
158
webapp/components/features/ProfileList/ProfileList.vue
Normal file
158
webapp/components/features/ProfileList/ProfileList.vue
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
<template>
|
||||||
|
<base-card class="follow-list">
|
||||||
|
<template v-if="connections && connections.length">
|
||||||
|
<h5 class="title spacer-x-small">
|
||||||
|
{{ title }}
|
||||||
|
</h5>
|
||||||
|
<ul :class="connectionsClass">
|
||||||
|
<li
|
||||||
|
v-for="connection in filteredConnections"
|
||||||
|
:key="connection.id"
|
||||||
|
class="connections__item"
|
||||||
|
>
|
||||||
|
<user-teaser :user="connection" />
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<base-button
|
||||||
|
v-if="hasMore"
|
||||||
|
:loading="loading"
|
||||||
|
class="spacer-x-small"
|
||||||
|
size="small"
|
||||||
|
@click="$emit('fetchAllConnections')"
|
||||||
|
>
|
||||||
|
{{
|
||||||
|
$t('profile.network.andMore', {
|
||||||
|
number: allConnectionsCount - connections.length,
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
</base-button>
|
||||||
|
<ds-input
|
||||||
|
v-if="!hasMore"
|
||||||
|
:name="uniqueName"
|
||||||
|
:placeholder="filter"
|
||||||
|
class="spacer-x-small"
|
||||||
|
icon="filter"
|
||||||
|
size="small"
|
||||||
|
@input.native="setFilter"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
<p v-else class="nobody-message">{{ titleNobody }}</p>
|
||||||
|
</base-card>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { escape } from 'xregexp/xregexp-all.js'
|
||||||
|
import UserTeaser from '~/components/UserTeaser/UserTeaser'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'ProfileList',
|
||||||
|
components: {
|
||||||
|
UserTeaser,
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
uniqueName: { type: String, required: true },
|
||||||
|
title: { type: String, required: true },
|
||||||
|
titleNobody: { type: String, required: true },
|
||||||
|
allConnectionsCount: { type: Number, required: true },
|
||||||
|
connections: { type: Array, required: true },
|
||||||
|
type: { type: String, default: 'following' },
|
||||||
|
loading: { type: Boolean, default: false },
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
filter: null,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
hasMore() {
|
||||||
|
return this.allConnectionsCount > this.connections.length
|
||||||
|
},
|
||||||
|
connectionsClass() {
|
||||||
|
return `connections${this.hasMore ? '' : ' --overflow'}`
|
||||||
|
},
|
||||||
|
filteredConnections() {
|
||||||
|
if (!this.filter) {
|
||||||
|
return this.connections
|
||||||
|
}
|
||||||
|
|
||||||
|
// @example
|
||||||
|
// this.filter = 'foo';
|
||||||
|
// fuzzyExpression = /([^f]*f)([^o]*o)([^o]*o)/i
|
||||||
|
const fuzzyExpression = new RegExp(
|
||||||
|
`${this.filter.split('').reduce((expr, c) => `${expr}([^${escape(c)}]*${escape(c)})`, '')}`,
|
||||||
|
'i',
|
||||||
|
)
|
||||||
|
|
||||||
|
const fuzzyScores = this.connections
|
||||||
|
.map((user) => {
|
||||||
|
const match = user.name.match(fuzzyExpression)
|
||||||
|
|
||||||
|
if (!match) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
let score = 1
|
||||||
|
for (let i = 1; i <= this.filter.length; i++) {
|
||||||
|
score *= match[i].length
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
user,
|
||||||
|
score,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.filter(Boolean)
|
||||||
|
.sort((a, b) => a.score - b.score)
|
||||||
|
|
||||||
|
return fuzzyScores.map((score) => score.user)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
setFilter(evt) {
|
||||||
|
this.filter = evt.target.value
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.follow-list {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
position: relative;
|
||||||
|
width: auto;
|
||||||
|
|
||||||
|
> .title {
|
||||||
|
color: $text-color-soft;
|
||||||
|
font-size: $font-size-base;
|
||||||
|
}
|
||||||
|
|
||||||
|
.connections {
|
||||||
|
height: $size-height-connections;
|
||||||
|
padding: $space-none;
|
||||||
|
list-style-type: none;
|
||||||
|
|
||||||
|
&.--overflow {
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
> .connections__item {
|
||||||
|
padding: $space-xx-small;
|
||||||
|
|
||||||
|
&.is-selected,
|
||||||
|
&:hover {
|
||||||
|
background-color: $background-color-primary-inverse;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.nobody-message {
|
||||||
|
text-align: center;
|
||||||
|
color: $text-color-soft;
|
||||||
|
}
|
||||||
|
|
||||||
|
> :nth-child(n):not(:last-child) {
|
||||||
|
margin-bottom: $space-small;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Loading…
x
Reference in New Issue
Block a user