mirror of
https://github.com/Ocelot-Social-Community/Ocelot-Social.git
synced 2025-12-13 07:46:06 +00:00
Merge pull request #3293 from Human-Connection/1741-follow-lists
feat: FollowerList [1741]
This commit is contained in:
commit
9aacb22a58
@ -928,7 +928,15 @@ const languages = ['de', 'en', 'es', 'fr', 'it', 'pt', 'pl']
|
||||
trollingComment.update({ disabled: true, updatedAt: new Date().toISOString(), closed: true }),
|
||||
])
|
||||
|
||||
await Promise.all([...Array(30).keys()].map(() => Factory.build('user')))
|
||||
const additionalUsers = await Promise.all(
|
||||
[...Array(30).keys()].map(() => Factory.build('user')),
|
||||
)
|
||||
await Promise.all(
|
||||
additionalUsers.map(async (user) => {
|
||||
await jennyRostock.relateTo(user, 'following')
|
||||
await user.relateTo(jennyRostock, 'following')
|
||||
}),
|
||||
)
|
||||
|
||||
await Promise.all(
|
||||
[...Array(30).keys()].map(() =>
|
||||
|
||||
@ -230,6 +230,7 @@ $space-small: 16px;
|
||||
$space-x-small: 8px;
|
||||
$space-xx-small: 4px;
|
||||
$space-xxx-small: 2px;
|
||||
$space-none: 0;
|
||||
|
||||
/**
|
||||
* @tokens Size Height
|
||||
@ -240,6 +241,7 @@ $size-height-base: 42px;
|
||||
$size-height-large: 50px;
|
||||
$size-height-xlarge: 60px;
|
||||
$size-height-footer: 64px;
|
||||
$size-height-connections: 315px;
|
||||
$size-tappable-square: 44px;
|
||||
$size-ribbon: 6px;
|
||||
|
||||
|
||||
@ -3,9 +3,11 @@
|
||||
<span class="initials">{{ userInitials }}</span>
|
||||
<base-icon v-if="isAnonymous" name="eye-slash" />
|
||||
<img
|
||||
v-else
|
||||
v-if="user && user.avatar"
|
||||
:src="user.avatar | proxyApiUrl"
|
||||
class="image"
|
||||
:alt="user.name"
|
||||
:title="user.name"
|
||||
@error="$event.target.style.display = 'none'"
|
||||
/>
|
||||
</div>
|
||||
|
||||
150
webapp/components/features/FollowList/FollowList.spec.js
Normal file
150
webapp/components/features/FollowList/FollowList.spec.js
Normal file
@ -0,0 +1,150 @@
|
||||
import { config, mount } from '@vue/test-utils'
|
||||
import Vuex from 'vuex'
|
||||
|
||||
import helpers from '~/storybook/helpers'
|
||||
import FollowList from './FollowList.vue'
|
||||
|
||||
const localVue = global.localVue
|
||||
|
||||
config.stubs['client-only'] = '<span><slot /></span>'
|
||||
config.stubs['ds-space'] = '<span><slot /></span>'
|
||||
config.stubs['nuxt-link'] = '<span><slot /></span>'
|
||||
|
||||
const user = {
|
||||
...helpers.fakeUser()[0],
|
||||
followedByCount: 12,
|
||||
followingCount: 15,
|
||||
followedBy: helpers.fakeUser(7),
|
||||
following: helpers.fakeUser(7),
|
||||
}
|
||||
|
||||
const allConnectionsUser = {
|
||||
...user,
|
||||
followedBy: [
|
||||
...user.followedBy,
|
||||
...helpers.fakeUser(user.followedByCount - user.followedBy.length),
|
||||
],
|
||||
following: [...user.following, ...helpers.fakeUser(user.followingCount - user.following.length)],
|
||||
}
|
||||
|
||||
const noConnectionsUser = {
|
||||
...user,
|
||||
followedByCount: 0,
|
||||
followingCount: 0,
|
||||
followedBy: [],
|
||||
following: [],
|
||||
}
|
||||
|
||||
describe('FollowList.vue', () => {
|
||||
let store, getters
|
||||
const Wrapper = (customProps) =>
|
||||
mount(FollowList, {
|
||||
store,
|
||||
propsData: { user, ...customProps },
|
||||
mocks: {
|
||||
$t: jest.fn((str) => str),
|
||||
},
|
||||
localVue,
|
||||
})
|
||||
|
||||
beforeAll(() => {
|
||||
getters = {
|
||||
'auth/user': () => {
|
||||
return {}
|
||||
},
|
||||
'auth/isModerator': () => false,
|
||||
}
|
||||
})
|
||||
|
||||
describe('mount', () => {
|
||||
beforeAll(() => {
|
||||
store = new Vuex.Store({
|
||||
getters,
|
||||
})
|
||||
})
|
||||
|
||||
describe('given a type', () => {
|
||||
describe('of `following`', () => {
|
||||
it('uses the `following` data on :user', () => {
|
||||
const wrapper = Wrapper({ user, type: 'following' })
|
||||
wrapper.find('.base-button').trigger('click')
|
||||
|
||||
expect(wrapper.vm.allConnectionsCount).toBe(user.followingCount)
|
||||
expect(wrapper.findAll('.user-teaser')).toHaveLength(user.following.length)
|
||||
expect(wrapper.emitted('fetchAllConnections')).toEqual([['following']])
|
||||
})
|
||||
})
|
||||
|
||||
describe('of `followedBy`', () => {
|
||||
it('uses the `followedBy` data on :user', () => {
|
||||
const wrapper = Wrapper({ type: 'followedBy' })
|
||||
wrapper.find('.base-button').trigger('click')
|
||||
|
||||
expect(wrapper.vm.allConnectionsCount).toBe(user.followedByCount)
|
||||
expect(wrapper.findAll('.user-teaser')).toHaveLength(user.followedBy.length)
|
||||
expect(wrapper.emitted('fetchAllConnections')).toEqual([['followedBy']])
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('given no type', () => {
|
||||
it('defaults type to `following`', () => {
|
||||
const wrapper = Wrapper()
|
||||
expect(wrapper.text()).toContain('profile.network.following')
|
||||
})
|
||||
})
|
||||
|
||||
describe('given a user', () => {
|
||||
describe('without connections', () => {
|
||||
it('displays the followingNobody message', () => {
|
||||
const wrapper = Wrapper({ user: noConnectionsUser })
|
||||
expect(wrapper.find('.nobody-message').text()).toContain(
|
||||
'profile.network.followingNobody',
|
||||
)
|
||||
})
|
||||
|
||||
it('displays the followedByNobody message', () => {
|
||||
const wrapper = Wrapper({ user: noConnectionsUser, type: 'followedBy' })
|
||||
expect(wrapper.find('.nobody-message').text()).toContain(
|
||||
'profile.network.followedByNobody',
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('with up to 7 loaded connections', () => {
|
||||
let wrapper
|
||||
beforeAll(() => {
|
||||
wrapper = Wrapper()
|
||||
})
|
||||
|
||||
it(`renders the connections`, () => {
|
||||
expect(wrapper.findAll('.user-teaser')).toHaveLength(user.following.length)
|
||||
})
|
||||
|
||||
it(`has a button to load all remaining connections`, async () => {
|
||||
wrapper.find('.base-button').trigger('click')
|
||||
expect(wrapper.emitted('fetchAllConnections')).toBeTruthy()
|
||||
})
|
||||
})
|
||||
|
||||
describe('with more than 7 loaded connections', () => {
|
||||
let wrapper
|
||||
beforeAll(() => {
|
||||
wrapper = Wrapper({ user: allConnectionsUser })
|
||||
})
|
||||
|
||||
it('renders the connections', () => {
|
||||
expect(wrapper.findAll('.user-teaser')).toHaveLength(allConnectionsUser.followingCount)
|
||||
})
|
||||
|
||||
it('renders the user-teasers as an overflowing list', () => {
|
||||
expect(wrapper.find('.--overflow').is('ul')).toBe(true)
|
||||
})
|
||||
|
||||
it('renders a filter text input', () => {
|
||||
expect(wrapper.find('[name="followingFilter"]').is('input')).toBe(true)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
111
webapp/components/features/FollowList/FollowList.story.js
Normal file
111
webapp/components/features/FollowList/FollowList.story.js
Normal file
@ -0,0 +1,111 @@
|
||||
import { storiesOf } from '@storybook/vue'
|
||||
import { withA11y } from '@storybook/addon-a11y'
|
||||
import { action } from '@storybook/addon-actions'
|
||||
|
||||
import helpers from '~/storybook/helpers'
|
||||
import FollowList from './FollowList.vue'
|
||||
|
||||
import fuzzyFilterUser from './FollowList.story.json'
|
||||
|
||||
helpers.init()
|
||||
|
||||
const user = {
|
||||
name: 'Jenny Rostock',
|
||||
id: 'u3',
|
||||
followedByCount: 12,
|
||||
followedBy: helpers.fakeUser(7),
|
||||
followingCount: 28,
|
||||
following: helpers.fakeUser(7),
|
||||
}
|
||||
|
||||
const lessThanSevenUser = {
|
||||
...user,
|
||||
followedByCount: 3,
|
||||
followedBy: user.followedBy.slice(0, 3),
|
||||
followingCount: 3,
|
||||
following: user.following.slice(0, 3),
|
||||
}
|
||||
|
||||
const allConnectionsUser = {
|
||||
...user,
|
||||
followedBy: [...user.followedBy, ...helpers.fakeUser(5)],
|
||||
following: [...user.following, ...helpers.fakeUser(21)],
|
||||
}
|
||||
|
||||
const noConnectionsUser = {
|
||||
...user,
|
||||
followedBy: [],
|
||||
followedByCount: 0,
|
||||
following: [],
|
||||
followingCount: 0,
|
||||
}
|
||||
|
||||
storiesOf('FollowList', module)
|
||||
.addDecorator(withA11y)
|
||||
.addDecorator(helpers.layout)
|
||||
.add('without connections', () => {
|
||||
return {
|
||||
components: { FollowList },
|
||||
store: helpers.store,
|
||||
data() {
|
||||
return { user: noConnectionsUser }
|
||||
},
|
||||
template: '<follow-list :user="user" type="following" />',
|
||||
}
|
||||
})
|
||||
.add('with all connections loaded', () => {
|
||||
return {
|
||||
components: { FollowList },
|
||||
store: helpers.store,
|
||||
data() {
|
||||
return { user: lessThanSevenUser }
|
||||
},
|
||||
|
||||
template: '<follow-list :user="user"/>',
|
||||
}
|
||||
})
|
||||
|
||||
.add('with more connections loadable', () => {
|
||||
return {
|
||||
components: { FollowList },
|
||||
store: helpers.store,
|
||||
data() {
|
||||
return { user: { ...user } }
|
||||
},
|
||||
methods: {
|
||||
fetchAllConnections(type) {
|
||||
this.user[type] = allConnectionsUser[type]
|
||||
action('fetchAllConnections')(type, this.user)
|
||||
},
|
||||
},
|
||||
template: '<follow-list :user="user" @fetchAllConnections="fetchAllConnections"/>',
|
||||
}
|
||||
})
|
||||
.add('with 1000 connections loaded', () => {
|
||||
return {
|
||||
components: { FollowList },
|
||||
store: helpers.store,
|
||||
data() {
|
||||
return {
|
||||
user: {
|
||||
...user,
|
||||
followedByCount: 1000,
|
||||
followingCount: 1000,
|
||||
followedBy: helpers.fakeUser(1000),
|
||||
following: helpers.fakeUser(1000),
|
||||
},
|
||||
}
|
||||
},
|
||||
template: '<follow-list :user="user" />',
|
||||
}
|
||||
})
|
||||
.add('Fuzzy Filter', () => {
|
||||
return {
|
||||
components: { FollowList },
|
||||
store: helpers.store,
|
||||
data() {
|
||||
return { user: fuzzyFilterUser }
|
||||
},
|
||||
template: '<follow-list :user="user" />',
|
||||
}
|
||||
})
|
||||
519
webapp/components/features/FollowList/FollowList.story.json
Normal file
519
webapp/components/features/FollowList/FollowList.story.json
Normal file
@ -0,0 +1,519 @@
|
||||
{
|
||||
"id": "u3",
|
||||
"slug": "jenny-rostock",
|
||||
"name": "Jenny Rostock",
|
||||
"avatar": {
|
||||
"url": "https://s3.amazonaws.com/uifaces/faces/twitter/nessoila/128.jpg?random=16aba55f-48c6-4ef5-966a-af0e31693e6a"
|
||||
},
|
||||
"followedByCount": 32,
|
||||
"followingCount": 31,
|
||||
"following": [
|
||||
{
|
||||
"id": "8c0b0191-454a-4806-b0c3-1ed1d9dc5416",
|
||||
"slug": "wanda-stanton-sr",
|
||||
"name": "Wanda Stanton Sr.",
|
||||
"avatar": {
|
||||
"url": "https://s3.amazonaws.com/uifaces/faces/twitter/nicolasfolliot/128.jpg?random=be2e59fb-f038-44d5-9e21-28fb123e8c7c"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "6f4fdb51-fe93-4373-bf44-c36ea17f6535",
|
||||
"slug": "walter-ohara",
|
||||
"name": "Walter O'Hara",
|
||||
"avatar": {
|
||||
"url": "https://s3.amazonaws.com/uifaces/faces/twitter/mutlu82/128.jpg?random=0866e1b7-8285-4eaf-a4c8-8509bd99f172"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "20f5080b-1fc2-4c70-94c7-badbe2aa2370",
|
||||
"slug": "hannah-bradtke",
|
||||
"name": "Hannah Bradtke",
|
||||
"avatar": {
|
||||
"url": "https://s3.amazonaws.com/uifaces/faces/twitter/Skyhartman/128.jpg?random=c02415a6-1e7e-488a-acb6-47587399ff07"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "c5d2c492-5b8c-41a5-a9a2-26f8c866a885",
|
||||
"slug": "georgia-koss-dvm",
|
||||
"name": "Georgia Koss DVM",
|
||||
"avatar": {
|
||||
"url": "https://s3.amazonaws.com/uifaces/faces/twitter/lvovenok/128.jpg?random=8e1e75b9-5dad-4fc8-9c52-38b89a3e0484"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "f4c10451-f367-4afb-97fe-e48f60236655",
|
||||
"slug": "genevieve-aufderhar-v",
|
||||
"name": "Genevieve Aufderhar V",
|
||||
"avatar": {
|
||||
"url": "https://s3.amazonaws.com/uifaces/faces/twitter/dss49/128.jpg?random=fc59a664-d2b4-4677-81e9-26ed5d4bc37e"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "df65a474-b661-4fd8-b49f-2d609bfc4089",
|
||||
"slug": "wanda-gerlach",
|
||||
"name": "Wanda Gerlach",
|
||||
"avatar": {
|
||||
"url": "https://s3.amazonaws.com/uifaces/faces/twitter/lewisainslie/128.jpg?random=5f0976d5-7871-4606-a416-6b67b0e67c15"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "5f2b3c14-07fc-4dfa-978e-9bf21d8586d0",
|
||||
"slug": "roland-kohler",
|
||||
"name": "Roland Kohler",
|
||||
"avatar": {
|
||||
"url": "https://s3.amazonaws.com/uifaces/faces/twitter/bcrad/128.jpg?random=4f77c5b2-0214-4342-a18e-424787f04896"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "a2c49c22-940a-4598-8285-b8ebb34bd045",
|
||||
"slug": "krista-hammes-dvm",
|
||||
"name": "Krista Hammes DVM",
|
||||
"avatar": {
|
||||
"url": "https://s3.amazonaws.com/uifaces/faces/twitter/sterlingrules/128.jpg?random=28167137-eee4-42e6-98a3-ec9a7d4b9509"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "da70bae8-daf2-4481-b2db-506d00b73210",
|
||||
"slug": "miss-lester-kovacek",
|
||||
"name": "Miss Lester Kovacek",
|
||||
"avatar": {
|
||||
"url": "https://s3.amazonaws.com/uifaces/faces/twitter/stefvdham/128.jpg?random=7de26019-8114-4caa-9aea-2172ae3c537c"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "868952d8-c5df-4415-a0bb-930acd26749c",
|
||||
"slug": "teri-stamm-iii",
|
||||
"name": "Teri Stamm III",
|
||||
"avatar": {
|
||||
"url": "https://s3.amazonaws.com/uifaces/faces/twitter/salimianoff/128.jpg?random=d2305511-39b2-4207-bee6-90799557546e"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "7a569786-fbb1-4e27-8f2c-38d2a0963b9d",
|
||||
"slug": "gerardo-batz",
|
||||
"name": "Gerardo Batz",
|
||||
"avatar": {
|
||||
"url": "https://s3.amazonaws.com/uifaces/faces/twitter/colirpixoil/128.jpg?random=8536b980-103e-4e5e-8141-31142e3c6330"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "dca673f2-89b8-46cc-a836-2515f319c02f",
|
||||
"slug": "carlton-botsford",
|
||||
"name": "Carlton Botsford",
|
||||
"avatar": {
|
||||
"url": "https://s3.amazonaws.com/uifaces/faces/twitter/cocolero/128.jpg?random=3ef57800-7694-4ec4-a9eb-39abca8d59e4"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "58ba4ab0-990e-4f44-a7a8-42d10962f8b7",
|
||||
"slug": "edward-boehm",
|
||||
"name": "Edward Boehm",
|
||||
"avatar": {
|
||||
"url": "https://s3.amazonaws.com/uifaces/faces/twitter/d_nny_m_cher/128.jpg?random=cf3ba671-4564-4dc1-bf94-a5fc3ea4fafa"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "u4",
|
||||
"slug": "huey",
|
||||
"name": "Huey",
|
||||
"avatar": {
|
||||
"url": "https://s3.amazonaws.com/uifaces/faces/twitter/hellofeverrrr/128.jpg?random=46fef3a9-44a0-4784-9854-03be6b3f37e1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "40cf7e21-a4dc-4055-a49d-3137c53dd815",
|
||||
"slug": "ms-laurie-bergnaum",
|
||||
"name": "Ms. Laurie Bergnaum",
|
||||
"avatar": {
|
||||
"url": "https://s3.amazonaws.com/uifaces/faces/twitter/kohette/128.jpg?random=45516cde-9073-4ceb-8b42-2bdf66a26c67"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "4c377f54-72c3-4e13-9532-6d0f2278a794",
|
||||
"slug": "jeffery-waelchi",
|
||||
"name": "Jeffery Waelchi",
|
||||
"avatar": {
|
||||
"url": "https://s3.amazonaws.com/uifaces/faces/twitter/andresenfredrik/128.jpg?random=b643d8ba-5e49-4854-b2a6-2ff609ffcba0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "d861e775-2344-40d5-b6e4-8479e7dbe97f",
|
||||
"slug": "marvin-gutkowski-iii",
|
||||
"name": "Marvin Gutkowski III",
|
||||
"avatar": {
|
||||
"url": "https://s3.amazonaws.com/uifaces/faces/twitter/kiwiupover/128.jpg?random=d38c1508-0342-46e0-9ef9-e0fd14b33072"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "3102346c-ea94-41d3-8474-5241e5e473a6",
|
||||
"slug": "edmund-rolfson-jr",
|
||||
"name": "Edmund Rolfson Jr.",
|
||||
"avatar": {
|
||||
"url": "https://s3.amazonaws.com/uifaces/faces/twitter/nerrsoft/128.jpg?random=d6f0804c-f38f-4c8b-821d-27a02373c74e"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "0290fd5e-7ce8-4d70-8c29-f5ed96bfaa1f",
|
||||
"slug": "bert-oconner",
|
||||
"name": "Bert O'Conner",
|
||||
"avatar": {
|
||||
"url": "https://s3.amazonaws.com/uifaces/faces/twitter/mangosango/128.jpg?random=03807c6c-c2f6-4ed3-8433-7a1823079eb0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "9fe670ff-1968-4b15-ab80-7adee8173dd8",
|
||||
"slug": "angela-schiller",
|
||||
"name": "Angela Schiller",
|
||||
"avatar": {
|
||||
"url": "https://s3.amazonaws.com/uifaces/faces/twitter/dudestein/128.jpg?random=0b511fa4-8603-419a-acf0-2a89bc41a71b"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "63798c79-2476-4eb8-a09c-167420bd05d7",
|
||||
"slug": "peggy-carter",
|
||||
"name": "Peggy Carter",
|
||||
"avatar": {
|
||||
"url": "https://s3.amazonaws.com/uifaces/faces/twitter/uxpiper/128.jpg?random=c4dc0de5-99d7-410d-8088-6a2be8358fe9"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "4d3fbb67-7ddc-4aa9-96d0-57bb20f95f59",
|
||||
"slug": "krystal-braun",
|
||||
"name": "Krystal Braun",
|
||||
"avatar": {
|
||||
"url": "https://s3.amazonaws.com/uifaces/faces/twitter/salvafc/128.jpg?random=1dbd4549-a525-4fa3-be41-15db84ceb41a"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "bcd5f271-bca5-492e-a6b6-7fd490ac37aa",
|
||||
"slug": "janet-bruen",
|
||||
"name": "Janet Bruen",
|
||||
"avatar": {
|
||||
"url": "https://s3.amazonaws.com/uifaces/faces/twitter/yigitpinarbasi/128.jpg?random=3c7ab2c0-8e53-4edb-8c74-fd8cdfae5f8e"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "38ccbf58-305a-4400-a1e4-785661604d5f",
|
||||
"slug": "ebony-corwin",
|
||||
"name": "Ebony Corwin",
|
||||
"avatar": {
|
||||
"url": "https://s3.amazonaws.com/uifaces/faces/twitter/thibaut_re/128.jpg?random=f2137643-6f58-45b8-8266-d1fb893d0528"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "5137e045-aef0-4ce1-8327-b516a72fffd6",
|
||||
"slug": "terrell-gorczany",
|
||||
"name": "Terrell Gorczany",
|
||||
"avatar": {
|
||||
"url": "https://s3.amazonaws.com/uifaces/faces/twitter/jimmuirhead/128.jpg?random=5e61976f-529e-47f2-b4f0-b5e4550942ea"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "b224eb01-5a71-4126-b811-51b7b35afd51",
|
||||
"slug": "dr-jamie-romaguera",
|
||||
"name": "Dr. Jamie Romaguera",
|
||||
"avatar": {
|
||||
"url": "https://s3.amazonaws.com/uifaces/faces/twitter/leonfedotov/128.jpg?random=9179538d-58be-4707-8ad6-485f703bea26"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "fdbb3e7f-f211-4685-831e-9d7e394b95a1",
|
||||
"slug": "shannon-schuster",
|
||||
"name": "Shannon Schuster",
|
||||
"avatar": {
|
||||
"url": "https://s3.amazonaws.com/uifaces/faces/twitter/markretzloff/128.jpg?random=f8a223ff-d49f-499f-a161-350e8078c353"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "d7ee00ea-5d22-4a1c-8670-7e4d4bd4ebfa",
|
||||
"slug": "guadalupe-kessler",
|
||||
"name": "Guadalupe Kessler",
|
||||
"avatar": {
|
||||
"url": "https://s3.amazonaws.com/uifaces/faces/twitter/linux29/128.jpg?random=a87d13e1-ff0e-4a39-a018-e89a04d72572"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "49b868e3-dba5-48ed-8b6c-e686c70dfcfb",
|
||||
"slug": "lonnie-rogahn",
|
||||
"name": "Lonnie Rogahn",
|
||||
"avatar": {
|
||||
"url": "https://s3.amazonaws.com/uifaces/faces/twitter/herbigt/128.jpg?random=fde8a699-624d-4052-96ef-0aaacf217184"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "fa70eecb-fbae-4133-b447-6c80b335fc01",
|
||||
"slug": "marcella-ledner",
|
||||
"name": "Marcella Ledner",
|
||||
"avatar": {
|
||||
"url": "https://s3.amazonaws.com/uifaces/faces/twitter/dawidwu/128.jpg?random=03869abc-1a6b-4f26-8d73-7ba508c148d0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "ef4cc540-c784-407f-b646-cff4d8fe666e",
|
||||
"slug": "darrell-runolfsson",
|
||||
"name": "Darrell Runolfsson",
|
||||
"avatar": {
|
||||
"url": "https://s3.amazonaws.com/uifaces/faces/twitter/andrewofficer/128.jpg?random=e6c24db9-f1c9-45b5-8507-609fca960e92"
|
||||
}
|
||||
}
|
||||
],
|
||||
"followedBy": [
|
||||
{
|
||||
"id": "8c0b0191-454a-4806-b0c3-1ed1d9dc5416",
|
||||
"slug": "wanda-stanton-sr",
|
||||
"name": "Wanda Stanton Sr.",
|
||||
"avatar": {
|
||||
"url": "https://s3.amazonaws.com/uifaces/faces/twitter/nicolasfolliot/128.jpg?random=be2e59fb-f038-44d5-9e21-28fb123e8c7c"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "c5d2c492-5b8c-41a5-a9a2-26f8c866a885",
|
||||
"slug": "georgia-koss-dvm",
|
||||
"name": "Georgia Koss DVM",
|
||||
"avatar": {
|
||||
"url": "https://s3.amazonaws.com/uifaces/faces/twitter/lvovenok/128.jpg?random=8e1e75b9-5dad-4fc8-9c52-38b89a3e0484"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "5f2b3c14-07fc-4dfa-978e-9bf21d8586d0",
|
||||
"slug": "roland-kohler",
|
||||
"name": "Roland Kohler",
|
||||
"avatar": {
|
||||
"url": "https://s3.amazonaws.com/uifaces/faces/twitter/bcrad/128.jpg?random=4f77c5b2-0214-4342-a18e-424787f04896"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "6f4fdb51-fe93-4373-bf44-c36ea17f6535",
|
||||
"slug": "walter-ohara",
|
||||
"name": "Walter O'Hara",
|
||||
"avatar": {
|
||||
"url": "https://s3.amazonaws.com/uifaces/faces/twitter/mutlu82/128.jpg?random=0866e1b7-8285-4eaf-a4c8-8509bd99f172"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "20f5080b-1fc2-4c70-94c7-badbe2aa2370",
|
||||
"slug": "hannah-bradtke",
|
||||
"name": "Hannah Bradtke",
|
||||
"avatar": {
|
||||
"url": "https://s3.amazonaws.com/uifaces/faces/twitter/Skyhartman/128.jpg?random=c02415a6-1e7e-488a-acb6-47587399ff07"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "df65a474-b661-4fd8-b49f-2d609bfc4089",
|
||||
"slug": "wanda-gerlach",
|
||||
"name": "Wanda Gerlach",
|
||||
"avatar": {
|
||||
"url": "https://s3.amazonaws.com/uifaces/faces/twitter/lewisainslie/128.jpg?random=5f0976d5-7871-4606-a416-6b67b0e67c15"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "f4c10451-f367-4afb-97fe-e48f60236655",
|
||||
"slug": "genevieve-aufderhar-v",
|
||||
"name": "Genevieve Aufderhar V",
|
||||
"avatar": {
|
||||
"url": "https://s3.amazonaws.com/uifaces/faces/twitter/dss49/128.jpg?random=fc59a664-d2b4-4677-81e9-26ed5d4bc37e"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "7a569786-fbb1-4e27-8f2c-38d2a0963b9d",
|
||||
"slug": "gerardo-batz",
|
||||
"name": "Gerardo Batz",
|
||||
"avatar": {
|
||||
"url": "https://s3.amazonaws.com/uifaces/faces/twitter/colirpixoil/128.jpg?random=8536b980-103e-4e5e-8141-31142e3c6330"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "da70bae8-daf2-4481-b2db-506d00b73210",
|
||||
"slug": "miss-lester-kovacek",
|
||||
"name": "Miss Lester Kovacek",
|
||||
"avatar": {
|
||||
"url": "https://s3.amazonaws.com/uifaces/faces/twitter/stefvdham/128.jpg?random=7de26019-8114-4caa-9aea-2172ae3c537c"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "a2c49c22-940a-4598-8285-b8ebb34bd045",
|
||||
"slug": "krista-hammes-dvm",
|
||||
"name": "Krista Hammes DVM",
|
||||
"avatar": {
|
||||
"url": "https://s3.amazonaws.com/uifaces/faces/twitter/sterlingrules/128.jpg?random=28167137-eee4-42e6-98a3-ec9a7d4b9509"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "bcd5f271-bca5-492e-a6b6-7fd490ac37aa",
|
||||
"slug": "janet-bruen",
|
||||
"name": "Janet Bruen",
|
||||
"avatar": {
|
||||
"url": "https://s3.amazonaws.com/uifaces/faces/twitter/yigitpinarbasi/128.jpg?random=3c7ab2c0-8e53-4edb-8c74-fd8cdfae5f8e"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "38ccbf58-305a-4400-a1e4-785661604d5f",
|
||||
"slug": "ebony-corwin",
|
||||
"name": "Ebony Corwin",
|
||||
"avatar": {
|
||||
"url": "https://s3.amazonaws.com/uifaces/faces/twitter/thibaut_re/128.jpg?random=f2137643-6f58-45b8-8266-d1fb893d0528"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "d7ee00ea-5d22-4a1c-8670-7e4d4bd4ebfa",
|
||||
"slug": "guadalupe-kessler",
|
||||
"name": "Guadalupe Kessler",
|
||||
"avatar": {
|
||||
"url": "https://s3.amazonaws.com/uifaces/faces/twitter/linux29/128.jpg?random=a87d13e1-ff0e-4a39-a018-e89a04d72572"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "dca673f2-89b8-46cc-a836-2515f319c02f",
|
||||
"slug": "carlton-botsford",
|
||||
"name": "Carlton Botsford",
|
||||
"avatar": {
|
||||
"url": "https://s3.amazonaws.com/uifaces/faces/twitter/cocolero/128.jpg?random=3ef57800-7694-4ec4-a9eb-39abca8d59e4"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "49b868e3-dba5-48ed-8b6c-e686c70dfcfb",
|
||||
"slug": "lonnie-rogahn",
|
||||
"name": "Lonnie Rogahn",
|
||||
"avatar": {
|
||||
"url": "https://s3.amazonaws.com/uifaces/faces/twitter/herbigt/128.jpg?random=fde8a699-624d-4052-96ef-0aaacf217184"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "4d3fbb67-7ddc-4aa9-96d0-57bb20f95f59",
|
||||
"slug": "krystal-braun",
|
||||
"name": "Krystal Braun",
|
||||
"avatar": {
|
||||
"url": "https://s3.amazonaws.com/uifaces/faces/twitter/salvafc/128.jpg?random=1dbd4549-a525-4fa3-be41-15db84ceb41a"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "58ba4ab0-990e-4f44-a7a8-42d10962f8b7",
|
||||
"slug": "edward-boehm",
|
||||
"name": "Edward Boehm",
|
||||
"avatar": {
|
||||
"url": "https://s3.amazonaws.com/uifaces/faces/twitter/d_nny_m_cher/128.jpg?random=cf3ba671-4564-4dc1-bf94-a5fc3ea4fafa"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "868952d8-c5df-4415-a0bb-930acd26749c",
|
||||
"slug": "teri-stamm-iii",
|
||||
"name": "Teri Stamm III",
|
||||
"avatar": {
|
||||
"url": "https://s3.amazonaws.com/uifaces/faces/twitter/salimianoff/128.jpg?random=d2305511-39b2-4207-bee6-90799557546e"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "fa70eecb-fbae-4133-b447-6c80b335fc01",
|
||||
"slug": "marcella-ledner",
|
||||
"name": "Marcella Ledner",
|
||||
"avatar": {
|
||||
"url": "https://s3.amazonaws.com/uifaces/faces/twitter/dawidwu/128.jpg?random=03869abc-1a6b-4f26-8d73-7ba508c148d0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "63798c79-2476-4eb8-a09c-167420bd05d7",
|
||||
"slug": "peggy-carter",
|
||||
"name": "Peggy Carter",
|
||||
"avatar": {
|
||||
"url": "https://s3.amazonaws.com/uifaces/faces/twitter/uxpiper/128.jpg?random=c4dc0de5-99d7-410d-8088-6a2be8358fe9"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "9fe670ff-1968-4b15-ab80-7adee8173dd8",
|
||||
"slug": "angela-schiller",
|
||||
"name": "Angela Schiller",
|
||||
"avatar": {
|
||||
"url": "https://s3.amazonaws.com/uifaces/faces/twitter/dudestein/128.jpg?random=0b511fa4-8603-419a-acf0-2a89bc41a71b"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "fdbb3e7f-f211-4685-831e-9d7e394b95a1",
|
||||
"slug": "shannon-schuster",
|
||||
"name": "Shannon Schuster",
|
||||
"avatar": {
|
||||
"url": "https://s3.amazonaws.com/uifaces/faces/twitter/markretzloff/128.jpg?random=f8a223ff-d49f-499f-a161-350e8078c353"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "5137e045-aef0-4ce1-8327-b516a72fffd6",
|
||||
"slug": "terrell-gorczany",
|
||||
"name": "Terrell Gorczany",
|
||||
"avatar": {
|
||||
"url": "https://s3.amazonaws.com/uifaces/faces/twitter/jimmuirhead/128.jpg?random=5e61976f-529e-47f2-b4f0-b5e4550942ea"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "ef4cc540-c784-407f-b646-cff4d8fe666e",
|
||||
"slug": "darrell-runolfsson",
|
||||
"name": "Darrell Runolfsson",
|
||||
"avatar": {
|
||||
"url": "https://s3.amazonaws.com/uifaces/faces/twitter/andrewofficer/128.jpg?random=e6c24db9-f1c9-45b5-8507-609fca960e92"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "b224eb01-5a71-4126-b811-51b7b35afd51",
|
||||
"slug": "dr-jamie-romaguera",
|
||||
"name": "Dr. Jamie Romaguera",
|
||||
"avatar": {
|
||||
"url": "https://s3.amazonaws.com/uifaces/faces/twitter/leonfedotov/128.jpg?random=9179538d-58be-4707-8ad6-485f703bea26"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "u1",
|
||||
"slug": "peter-lustig",
|
||||
"name": "Peter Lustig",
|
||||
"avatar": {
|
||||
"url": "https://s3.amazonaws.com/uifaces/faces/twitter/timgthomas/128.jpg?random=189d17f8-02d1-4b01-a000-af7121ae6897"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "u6",
|
||||
"slug": "louie",
|
||||
"name": "Louie",
|
||||
"avatar": {
|
||||
"url": "https://s3.amazonaws.com/uifaces/faces/twitter/yayteejay/128.jpg?random=eefe597c-d49a-494f-b311-d6f2645d2264"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "3102346c-ea94-41d3-8474-5241e5e473a6",
|
||||
"slug": "edmund-rolfson-jr",
|
||||
"name": "Edmund Rolfson Jr.",
|
||||
"avatar": {
|
||||
"url": "https://s3.amazonaws.com/uifaces/faces/twitter/nerrsoft/128.jpg?random=d6f0804c-f38f-4c8b-821d-27a02373c74e"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "40cf7e21-a4dc-4055-a49d-3137c53dd815",
|
||||
"slug": "ms-laurie-bergnaum",
|
||||
"name": "Ms. Laurie Bergnaum",
|
||||
"avatar": {
|
||||
"url": "https://s3.amazonaws.com/uifaces/faces/twitter/kohette/128.jpg?random=45516cde-9073-4ceb-8b42-2bdf66a26c67"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "d861e775-2344-40d5-b6e4-8479e7dbe97f",
|
||||
"slug": "marvin-gutkowski-iii",
|
||||
"name": "Marvin Gutkowski III",
|
||||
"avatar": {
|
||||
"url": "https://s3.amazonaws.com/uifaces/faces/twitter/kiwiupover/128.jpg?random=d38c1508-0342-46e0-9ef9-e0fd14b33072"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "4c377f54-72c3-4e13-9532-6d0f2278a794",
|
||||
"slug": "jeffery-waelchi",
|
||||
"name": "Jeffery Waelchi",
|
||||
"avatar": {
|
||||
"url": "https://s3.amazonaws.com/uifaces/faces/twitter/andresenfredrik/128.jpg?random=b643d8ba-5e49-4854-b2a6-2ff609ffcba0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "0290fd5e-7ce8-4d70-8c29-f5ed96bfaa1f",
|
||||
"slug": "bert-oconner",
|
||||
"name": "Bert O'Conner",
|
||||
"avatar": {
|
||||
"url": "https://s3.amazonaws.com/uifaces/faces/twitter/mangosango/128.jpg?random=03807c6c-c2f6-4ed3-8433-7a1823079eb0"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
165
webapp/components/features/FollowList/FollowList.vue
Normal file
165
webapp/components/features/FollowList/FollowList.vue
Normal file
@ -0,0 +1,165 @@
|
||||
<template>
|
||||
<base-card class="follow-list">
|
||||
<template v-if="connections && connections.length">
|
||||
<h5 class="title spacer-x-small">
|
||||
{{ userName | truncate(15) }} {{ $t(`profile.network.${type}`) }}
|
||||
</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', type)"
|
||||
>
|
||||
{{
|
||||
$t('profile.network.andMore', {
|
||||
number: allConnectionsCount - connections.length,
|
||||
})
|
||||
}}
|
||||
</base-button>
|
||||
<ds-input
|
||||
v-if="!hasMore"
|
||||
v-focus="true"
|
||||
: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>
|
||||
|
||||
<script>
|
||||
import { escape } from 'xregexp/xregexp-all.js'
|
||||
import UserTeaser from '~/components/UserTeaser/UserTeaser'
|
||||
|
||||
export default {
|
||||
name: 'FollowerList',
|
||||
components: {
|
||||
UserTeaser,
|
||||
},
|
||||
props: {
|
||||
user: { type: Object, default: null },
|
||||
type: { type: String, default: 'following' },
|
||||
loading: { type: Boolean, default: false },
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
filter: null,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
userName() {
|
||||
const { name } = this.user || {}
|
||||
return name || this.$t('profile.userAnonym')
|
||||
},
|
||||
allConnectionsCount() {
|
||||
return this.user[`${this.type}Count`]
|
||||
},
|
||||
connections() {
|
||||
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>
|
||||
|
||||
<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>
|
||||
@ -14,7 +14,7 @@ export default (i18n) => {
|
||||
${userCountsFragment}
|
||||
${locationAndBadgesFragment(lang)}
|
||||
|
||||
query User($id: ID!) {
|
||||
query User($id: ID!, $followedByCount: Int, $followingCount: Int) {
|
||||
User(id: $id) {
|
||||
...user
|
||||
...userCounts
|
||||
@ -26,12 +26,12 @@ export default (i18n) => {
|
||||
isMuted
|
||||
isBlocked
|
||||
blocked
|
||||
following(first: 7) {
|
||||
following(first: $followingCount) {
|
||||
...user
|
||||
...userCounts
|
||||
...locationAndBadges
|
||||
}
|
||||
followedBy(first: 7) {
|
||||
followedBy(first: $followedByCount) {
|
||||
...user
|
||||
...userCounts
|
||||
...locationAndBadges
|
||||
|
||||
@ -9,6 +9,7 @@ config.stubs['client-only'] = '<span><slot /></span>'
|
||||
config.stubs['v-popover'] = '<span><slot /></span>'
|
||||
config.stubs['nuxt-link'] = '<span><slot /></span>'
|
||||
config.stubs['infinite-loading'] = '<span><slot /></span>'
|
||||
config.stubs['follow-list'] = '<span><slot /></span>'
|
||||
|
||||
describe('ProfileSlug', () => {
|
||||
let wrapper
|
||||
|
||||
@ -89,65 +89,19 @@
|
||||
<ds-heading tag="h3" soft style="text-align: center; margin-bottom: 10px;">
|
||||
{{ $t('profile.network.title') }}
|
||||
</ds-heading>
|
||||
<base-card style="position: relative; height: auto;">
|
||||
<ds-space v-if="user.following && user.following.length" margin="x-small">
|
||||
<ds-text tag="h5" color="soft">
|
||||
{{ userName | truncate(15) }} {{ $t('profile.network.following') }}
|
||||
</ds-text>
|
||||
</ds-space>
|
||||
<template v-if="user.following && user.following.length">
|
||||
<ds-space v-for="follow in uniq(user.following)" :key="follow.id" margin="x-small">
|
||||
<!-- TODO: find better solution for rendering errors -->
|
||||
<client-only>
|
||||
<user-teaser :user="follow" />
|
||||
</client-only>
|
||||
</ds-space>
|
||||
<ds-space v-if="user.followingCount - user.following.length" margin="small">
|
||||
<ds-text size="small" color="softer">
|
||||
{{
|
||||
$t('profile.network.andMore', {
|
||||
number: user.followingCount - user.following.length,
|
||||
})
|
||||
}}
|
||||
</ds-text>
|
||||
</ds-space>
|
||||
</template>
|
||||
<template v-else>
|
||||
<p style="text-align: center; opacity: 0.5;">
|
||||
{{ userName }} {{ $t('profile.network.followingNobody') }}
|
||||
</p>
|
||||
</template>
|
||||
</base-card>
|
||||
<follow-list
|
||||
:loading="$apollo.loading"
|
||||
:user="user"
|
||||
type="followedBy"
|
||||
@fetchAllConnections="fetchAllConnections"
|
||||
/>
|
||||
<ds-space />
|
||||
<base-card style="position: relative; height: auto;">
|
||||
<ds-space v-if="user.followedBy && user.followedBy.length" margin="x-small">
|
||||
<ds-text tag="h5" color="soft">
|
||||
{{ userName | truncate(15) }} {{ $t('profile.network.followedBy') }}
|
||||
</ds-text>
|
||||
</ds-space>
|
||||
<template v-if="user.followedBy && user.followedBy.length">
|
||||
<ds-space v-for="follow in uniq(user.followedBy)" :key="follow.id" margin="x-small">
|
||||
<!-- TODO: find better solution for rendering errors -->
|
||||
<client-only>
|
||||
<user-teaser :user="follow" />
|
||||
</client-only>
|
||||
</ds-space>
|
||||
<ds-space v-if="user.followedByCount - user.followedBy.length" margin="small">
|
||||
<ds-text size="small" color="softer">
|
||||
{{
|
||||
$t('profile.network.andMore', {
|
||||
number: user.followedByCount - user.followedBy.length,
|
||||
})
|
||||
}}
|
||||
</ds-text>
|
||||
</ds-space>
|
||||
</template>
|
||||
<template v-else>
|
||||
<p style="text-align: center; opacity: 0.5;">
|
||||
{{ userName }} {{ $t('profile.network.followedByNobody') }}
|
||||
</p>
|
||||
</template>
|
||||
</base-card>
|
||||
<follow-list
|
||||
:loading="$apollo.loading"
|
||||
:user="user"
|
||||
type="following"
|
||||
@fetchAllConnections="fetchAllConnections"
|
||||
/>
|
||||
<ds-space v-if="user.socialMedia && user.socialMedia.length" margin="large">
|
||||
<base-card style="position: relative; height: auto;">
|
||||
<ds-space margin="x-small">
|
||||
@ -271,11 +225,11 @@
|
||||
|
||||
<script>
|
||||
import uniqBy from 'lodash/uniqBy'
|
||||
import UserTeaser from '~/components/UserTeaser/UserTeaser'
|
||||
import PostTeaser from '~/components/PostTeaser/PostTeaser.vue'
|
||||
import HcFollowButton from '~/components/FollowButton.vue'
|
||||
import HcCountTo from '~/components/CountTo.vue'
|
||||
import HcBadges from '~/components/Badges.vue'
|
||||
import FollowList from '~/components/features/FollowList/FollowList'
|
||||
import HcEmpty from '~/components/Empty/Empty'
|
||||
import ContentMenu from '~/components/ContentMenu/ContentMenu'
|
||||
import HcUpload from '~/components/Upload'
|
||||
@ -299,7 +253,6 @@ const tabToFilterMapping = ({ tab, id }) => {
|
||||
|
||||
export default {
|
||||
components: {
|
||||
UserTeaser,
|
||||
PostTeaser,
|
||||
HcFollowButton,
|
||||
HcCountTo,
|
||||
@ -310,6 +263,7 @@ export default {
|
||||
HcUpload,
|
||||
MasonryGrid,
|
||||
MasonryGridItem,
|
||||
FollowList,
|
||||
},
|
||||
transition: {
|
||||
name: 'slide-up',
|
||||
@ -326,6 +280,8 @@ export default {
|
||||
tabActive: 'post',
|
||||
filter,
|
||||
followedByCountStartValue: 0,
|
||||
followedByCount: 7,
|
||||
followingCount: 7,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@ -355,13 +311,6 @@ export default {
|
||||
return slug && `@${slug}`
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
User(val) {
|
||||
if (!val || !val.length) {
|
||||
throw new Error('User not found!')
|
||||
}
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
removePostFromList(deletedPost) {
|
||||
this.posts = this.posts.filter((post) => {
|
||||
@ -483,6 +432,10 @@ export default {
|
||||
this.user.followedByCurrentUser = followedByCurrentUser
|
||||
this.user.followedBy = followedBy
|
||||
},
|
||||
fetchAllConnections(type) {
|
||||
if (type === 'following') this.followingCount = Infinity
|
||||
if (type === 'followedBy') this.followedByCount = Infinity
|
||||
},
|
||||
},
|
||||
apollo: {
|
||||
profilePagePosts: {
|
||||
@ -507,7 +460,11 @@ export default {
|
||||
return UserQuery(this.$i18n)
|
||||
},
|
||||
variables() {
|
||||
return { id: this.$route.params.id }
|
||||
return {
|
||||
id: this.$route.params.id,
|
||||
followedByCount: this.followedByCount,
|
||||
followingCount: this.followingCount,
|
||||
}
|
||||
},
|
||||
fetchPolicy: 'cache-and-network',
|
||||
},
|
||||
|
||||
@ -7,7 +7,10 @@ export default ({ app }) => {
|
||||
// Focus the element
|
||||
Vue.nextTick(() => {
|
||||
if (binding.value !== false) {
|
||||
el.focus()
|
||||
const target = el instanceof HTMLInputElement ? el : el.querySelector('input')
|
||||
if (target) {
|
||||
target.focus()
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
@ -1,8 +1,10 @@
|
||||
import Vue from 'vue'
|
||||
import Vuex from 'vuex'
|
||||
import faker from 'faker'
|
||||
import vuexI18n from 'vuex-i18n/dist/vuex-i18n.umd.js'
|
||||
import Styleguide from '@human-connection/styleguide'
|
||||
import Filters from '~/plugins/vue-filters'
|
||||
import Directives from '~/plugins/vue-directives'
|
||||
import IziToast from '~/plugins/izi-toast'
|
||||
import layout from './layout.vue'
|
||||
import locales from '~/locales/index.js'
|
||||
@ -15,6 +17,7 @@ const helpers = {
|
||||
Vue.use(Styleguide)
|
||||
Vue.use(Filters)
|
||||
Vue.use(IziToast)
|
||||
Vue.use(Directives)
|
||||
|
||||
Vue.use(vuexI18n.plugin, helpers.store)
|
||||
locales.forEach(({ code }) => {
|
||||
@ -38,7 +41,7 @@ const helpers = {
|
||||
isAdmin() {
|
||||
return true
|
||||
},
|
||||
user(state) {
|
||||
user() {
|
||||
return { id: '1', name: 'admin', slug: 'admin' }
|
||||
},
|
||||
},
|
||||
@ -57,6 +60,16 @@ const helpers = {
|
||||
</layout>`,
|
||||
}
|
||||
},
|
||||
fakeUser(n) {
|
||||
return new Array(n || 1).fill(0).map(() => {
|
||||
const name = faker.name.findName()
|
||||
return {
|
||||
id: faker.random.uuid(),
|
||||
name,
|
||||
slug: faker.helpers.slugify(name),
|
||||
}
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
export default helpers
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<ds-container class="container">
|
||||
<div class="container">
|
||||
<slot />
|
||||
</ds-container>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
@ -10,5 +10,7 @@
|
||||
|
||||
.container {
|
||||
padding: 5rem;
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -5,6 +5,7 @@ import Styleguide from '@human-connection/styleguide'
|
||||
import BaseComponents from '~/plugins/base-components'
|
||||
import Filters from '~/plugins/vue-filters'
|
||||
import InfiniteLoading from '~/plugins/vue-infinite-loading'
|
||||
import Directives from '~/plugins/vue-directives'
|
||||
|
||||
global.localVue = createLocalVue()
|
||||
|
||||
@ -13,4 +14,5 @@ global.localVue.use(VTooltip)
|
||||
global.localVue.use(Styleguide)
|
||||
global.localVue.use(BaseComponents)
|
||||
global.localVue.use(Filters)
|
||||
global.localVue.use(Directives)
|
||||
global.localVue.use(InfiniteLoading)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user