diff --git a/src/assets/styles/Main.sass b/src/assets/styles/Main.sass
index 96ce392eb..2a975c639 100644
--- a/src/assets/styles/Main.sass
+++ b/src/assets/styles/Main.sass
@@ -279,10 +279,6 @@ a
@extend .text-color-base
.main-options-dropdown-container
@extend .visibility-visible
- &.main-playlist-item, &.main-profile-item
- & > .content
- & > .description
- @extend .no-margin
.main-message-item, .main-profile-item
& > .image
diff --git a/src/components/buttons/community/BaseCommunityCreateButton.vue b/src/components/buttons/community/BaseCommunityCreateButton.vue
new file mode 100644
index 000000000..6b3e00053
--- /dev/null
+++ b/src/components/buttons/community/BaseCommunityCreateButton.vue
@@ -0,0 +1,18 @@
+
+ button
+
+
+
+
+
diff --git a/src/components/buttons/playlist/BasePlaylistCreateButton.vue b/src/components/buttons/playlist/BasePlaylistCreateButton.vue
new file mode 100644
index 000000000..c821d467f
--- /dev/null
+++ b/src/components/buttons/playlist/BasePlaylistCreateButton.vue
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
diff --git a/src/components/containers/pages/communities/BaseCommunitiesPageContainer.vue b/src/components/containers/pages/communities/BaseCommunitiesPageContainer.vue
new file mode 100644
index 000000000..8d57e3748
--- /dev/null
+++ b/src/components/containers/pages/communities/BaseCommunitiesPageContainer.vue
@@ -0,0 +1,81 @@
+
+
+
+
+
+
+
+
+
diff --git a/src/components/containers/pages/community/BaseCommunityPageContainer.vue b/src/components/containers/pages/community/BaseCommunityPageContainer.vue
new file mode 100644
index 000000000..7ac21ecf5
--- /dev/null
+++ b/src/components/containers/pages/community/BaseCommunityPageContainer.vue
@@ -0,0 +1,101 @@
+
+
+
+
+
+
+
+
+
diff --git a/src/components/containers/pages/profile/BaseProfilePageContainer.vue b/src/components/containers/pages/profile/BaseProfilePageContainer.vue
index af946c39c..ff3fef552 100644
--- a/src/components/containers/pages/profile/BaseProfilePageContainer.vue
+++ b/src/components/containers/pages/profile/BaseProfilePageContainer.vue
@@ -32,6 +32,8 @@ import formatProfileFavoritesPageTab
import formatProfilePlaylistsPageTab
from '*/helpers/formatters/tabs/profile/playlists'
import formatProfilePostsPageTab from '*/helpers/formatters/tabs/profile/posts'
+import formatProfileCommunitiesPageTab
+ from '*/helpers/formatters/tabs/profile/communities'
import getProfile from '*/helpers/actions/api/profile/get'
export default {
@@ -108,6 +110,10 @@ export default {
return formatProfilePostsPageTab(
this.navigationData
)
+ case 'communities':
+ return formatProfileCommunitiesPageTab(
+ this.navigationData
+ )
default:
return formatProfilePageTab(
this.navigationData
diff --git a/src/components/images/BaseImage.vue b/src/components/images/BaseImage.vue
index 83997dc5f..ef3ceb6d3 100644
--- a/src/components/images/BaseImage.vue
+++ b/src/components/images/BaseImage.vue
@@ -28,6 +28,7 @@ export default {
track: 'https://lastfm.freetls.fastly.net/i/u/300x300/4128a6eb29f94943c9d206c08e625904.png',
playlist: 'https://lastfm.freetls.fastly.net/i/u/300x300/4128a6eb29f94943c9d206c08e625904.png',
profile: 'https://lastfm.freetls.fastly.net/i/u/300x300/818148bf682d429dc215c1705eb27b98.png',
+ community: 'https://lastfm.freetls.fastly.net/i/u/300x300/818148bf682d429dc215c1705eb27b98.png',
video: 'https://i.ytimg.com'
}
}
diff --git a/src/components/layout/panels/TheSidebarPanel.vue b/src/components/layout/panels/TheSidebarPanel.vue
index ea29a21fa..695cba31d 100644
--- a/src/components/layout/panels/TheSidebarPanel.vue
+++ b/src/components/layout/panels/TheSidebarPanel.vue
@@ -15,6 +15,7 @@
+
@@ -37,6 +38,7 @@ import FavoritesItem from './TheSidebarPanel/FavoritesItem.vue'
import BookmarksItem from './TheSidebarPanel/BookmarksItem.vue'
import TopItem from './TheSidebarPanel/TopItem.vue'
import RadioItem from './TheSidebarPanel/RadioItem.vue'
+import CommunitiesItem from './TheSidebarPanel/CommunitiesItem.vue'
import SettingsItem from './TheSidebarPanel/SettingsItem.vue'
import LogoutItem from './TheSidebarPanel/LogoutItem.vue'
@@ -53,6 +55,7 @@ export default {
BookmarksItem,
TopItem,
RadioItem,
+ CommunitiesItem,
SettingsItem,
LogoutItem
},
diff --git a/src/components/layout/panels/TheSidebarPanel/CommunitiesItem.vue b/src/components/layout/panels/TheSidebarPanel/CommunitiesItem.vue
new file mode 100644
index 000000000..2ca0c0f5a
--- /dev/null
+++ b/src/components/layout/panels/TheSidebarPanel/CommunitiesItem.vue
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+
diff --git a/src/components/lists/communities/BaseCommunitiesSimpleList.vue b/src/components/lists/communities/BaseCommunitiesSimpleList.vue
new file mode 100644
index 000000000..aeb49e8c6
--- /dev/null
+++ b/src/components/lists/communities/BaseCommunitiesSimpleList.vue
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+
+
+
diff --git a/src/components/lists/communities/BaseCommunitiesSimpleList/CommunityItem.vue b/src/components/lists/communities/BaseCommunitiesSimpleList/CommunityItem.vue
new file mode 100644
index 000000000..891e558ef
--- /dev/null
+++ b/src/components/lists/communities/BaseCommunitiesSimpleList/CommunityItem.vue
@@ -0,0 +1,93 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/lists/playlists/BasePlaylistsSimpleList/PlaylistItem.vue b/src/components/lists/playlists/BasePlaylistsSimpleList/PlaylistItem.vue
index f2f1a969f..131a3fc60 100644
--- a/src/components/lists/playlists/BasePlaylistsSimpleList/PlaylistItem.vue
+++ b/src/components/lists/playlists/BasePlaylistsSimpleList/PlaylistItem.vue
@@ -1,6 +1,6 @@
@@ -28,7 +28,7 @@
@mouseleave="handleProfileNicknameMouseLeave"
>
diff --git a/src/components/lists/playlists/BasePlaylistsSimpleSelectableList/PlaylistItem.vue b/src/components/lists/playlists/BasePlaylistsSimpleSelectableList/PlaylistItem.vue
index 9821e6d38..6eba209fb 100644
--- a/src/components/lists/playlists/BasePlaylistsSimpleSelectableList/PlaylistItem.vue
+++ b/src/components/lists/playlists/BasePlaylistsSimpleSelectableList/PlaylistItem.vue
@@ -1,6 +1,6 @@
@@ -30,12 +31,20 @@ export default {
}
}
},
+ emits: [
+ 'linkClick'
+ ],
computed: {
profilesCollection () {
return formatCollection(
this.profiles
)
}
+ },
+ methods: {
+ handleLinkClick () {
+ this.$emit('linkClick')
+ }
}
}
diff --git a/src/components/lists/profiles/BaseProfilesSimpleList/ProfileItem.vue b/src/components/lists/profiles/BaseProfilesSimpleList/ProfileItem.vue
index 0ebc2a6b9..be175ac0c 100644
--- a/src/components/lists/profiles/BaseProfilesSimpleList/ProfileItem.vue
+++ b/src/components/lists/profiles/BaseProfilesSimpleList/ProfileItem.vue
@@ -2,6 +2,7 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/models/profile/BaseProfileFollowingCount.vue b/src/components/models/profile/BaseProfileFollowingCount.vue
index dd0769beb..f1bbfd56d 100644
--- a/src/components/models/profile/BaseProfileFollowingCount.vue
+++ b/src/components/models/profile/BaseProfileFollowingCount.vue
@@ -24,6 +24,7 @@ import {
followers as formatProfileFollowersLink,
following as formatProfileFollowingLink
} from '*/helpers/formatters/links/profile'
+import { number as formatNumber } from '*/helpers/formatters'
export default {
name: 'BaseProfileFollowingCount',
@@ -55,7 +56,12 @@ export default {
)
},
followersCountStrong () {
- return `
${this.followersCount}`
+ return `
${this.followersCountFormatted}`
+ },
+ followersCountFormatted () {
+ return formatNumber(
+ this.followersCount
+ )
},
followersCount () {
return this.profileData.follower_profiles_count
diff --git a/src/helpers/actions/api/communities/get.js b/src/helpers/actions/api/communities/get.js
new file mode 100644
index 000000000..72366579b
--- /dev/null
+++ b/src/helpers/actions/api/communities/get.js
@@ -0,0 +1,36 @@
+import axios from 'axios'
+
+export default function ({ page, limit }) {
+ this.error = null
+ this.isLoading = true
+
+ const url = '/communities'
+
+ const params = {
+ ...(page && { page }),
+ ...(limit && { limit })
+ }
+
+ const handleSuccess = response => {
+ this.communitiesData =
+ response.data.communities
+ }
+
+ const handleError = error => {
+ this.error = error
+ }
+
+ const handleFinish = () => {
+ this.isLoading = false
+ }
+
+ axios.get(
+ url, { params }
+ ).then(
+ handleSuccess
+ ).catch(
+ handleError
+ ).finally(
+ handleFinish
+ )
+}
diff --git a/src/helpers/actions/api/community/get.js b/src/helpers/actions/api/community/get.js
new file mode 100644
index 000000000..200ab193e
--- /dev/null
+++ b/src/helpers/actions/api/community/get.js
@@ -0,0 +1,43 @@
+import axios from 'axios'
+import store from '*/plugins/store'
+
+export default function ({ communityId, scope = '', page, limit }) {
+ this.error = null
+ this.isLoading = true
+
+ const url = `/communities/${communityId}/${scope}`
+
+ const otherProfileId =
+ store.state.profile.info.id
+
+ const params = {
+ ...(scope === 'members' && {
+ other_profile_id: otherProfileId
+ }),
+ ...(page && { page }),
+ ...(limit && { limit })
+ }
+
+ const handleSuccess = response => {
+ this.communityData =
+ response.data.community
+ }
+
+ const handleError = error => {
+ this.error = error
+ }
+
+ const handleFinish = () => {
+ this.isLoading = false
+ }
+
+ axios.get(
+ url, { params }
+ ).then(
+ handleSuccess
+ ).catch(
+ handleError
+ ).finally(
+ handleFinish
+ )
+}
diff --git a/src/helpers/data/plugins/i18n/locales/en.json b/src/helpers/data/plugins/i18n/locales/en.json
index 640f44413..70affb613 100644
--- a/src/helpers/data/plugins/i18n/locales/en.json
+++ b/src/helpers/data/plugins/i18n/locales/en.json
@@ -25,6 +25,7 @@
"playlists": "Playlists",
"favorites": "Favorites",
"bookmarks": "Bookmarks",
+ "communities": "Communities",
"settings": "Settings",
"model": {
"artists": "{modelName} artists",
@@ -40,7 +41,8 @@
"following": "{modelName} following",
"library": "{modelName} library",
"playlists": "{modelName} playlists",
- "favorites": "{modelName} favorites"
+ "favorites": "{modelName} favorites",
+ "communities": "{modelName} communities"
},
"top": {
"artists": "Top artists",
@@ -134,6 +136,10 @@
"listened": "Delete from listened"
}
},
+ "links": {
+ "playlists": "All playlists",
+ "communities": "All communities"
+ },
"inputs": {
"search": "Search...",
"content": "Write something..."
@@ -244,7 +250,8 @@
"albums": "{count} albums",
"tracks": "{count} tracks",
"followers": "{count} followers",
- "following": "{count} following"
+ "following": "{count} following",
+ "members": "{count} members"
},
"sources": {
"select": {
diff --git a/src/helpers/data/plugins/i18n/locales/ru.json b/src/helpers/data/plugins/i18n/locales/ru.json
index 664d6e3c6..51f688a8d 100644
--- a/src/helpers/data/plugins/i18n/locales/ru.json
+++ b/src/helpers/data/plugins/i18n/locales/ru.json
@@ -25,6 +25,7 @@
"playlists": "Списки",
"favorites": "Избранное",
"bookmarks": "Закладки",
+ "communities": "Сообщества",
"settings": "Настройки",
"model": {
"artists": "Исполнители {modelName}",
@@ -40,7 +41,8 @@
"following": "Подписки {modelName}",
"library": "Библиотека {modelName}",
"playlists": "Списки {modelName}",
- "favorites": "Избранное {modelName}"
+ "favorites": "Избранное {modelName}",
+ "communities": "Сообщества {modelName}"
},
"top": {
"artists": "Популярные исполнители",
@@ -134,6 +136,10 @@
"listened": "Удалить из прослушанного"
}
},
+ "links": {
+ "playlists": "Все списки",
+ "communities": "Все сообщества"
+ },
"inputs": {
"search": "Поиск...",
"content": "Напишите что-нибудь..."
@@ -244,7 +250,8 @@
"albums": "{count} альбомов",
"tracks": "{count} композиций",
"followers": "{count} подписчиков",
- "following": "{count} подписок"
+ "following": "{count} подписок",
+ "members": "{count} участников"
},
"sources": {
"select": {
diff --git a/src/helpers/data/plugins/router/routes.js b/src/helpers/data/plugins/router/routes.js
index b3ed5e1c4..5596276d2 100644
--- a/src/helpers/data/plugins/router/routes.js
+++ b/src/helpers/data/plugins/router/routes.js
@@ -142,6 +142,15 @@ const ProfileFollowingPage = () => import(
const PlaylistsPage = () => import(
'*/views/PlaylistsPage.vue'
)
+const ProfileCommunitiesPage = () => import(
+ '*/views/profile/CommunitiesPage.vue'
+)
+const CommunitiesPage = () => import(
+ '*/views/communities/MainPage.vue'
+)
+const CommunityPage = () => import(
+ '*/views/communities/CommunityPage.vue'
+)
export default [
{
@@ -479,5 +488,26 @@ export default [
name: 'PlaylistsPage',
component: PlaylistsPage,
props: true
+ },
+ {
+ path: '/profiles/:profileId/communities',
+ exact: true,
+ name: 'ProfileCommunitiesPage',
+ component: ProfileCommunitiesPage,
+ props: true
+ },
+ {
+ path: '/communities',
+ exact: true,
+ name: 'CommunitiesPage',
+ component: CommunitiesPage,
+ props: true
+ },
+ {
+ path: '/communities/:communityId',
+ exact: true,
+ name: 'CommunityPage',
+ component: CommunityPage,
+ props: true
}
]
diff --git a/src/helpers/formatters/links/communities.js b/src/helpers/formatters/links/communities.js
new file mode 100644
index 000000000..ac205daf0
--- /dev/null
+++ b/src/helpers/formatters/links/communities.js
@@ -0,0 +1,15 @@
+export const main = () => {
+ return {
+ name: 'CommunitiesPage',
+ params: {},
+ path: 'communities'
+ }
+}
+
+export const community = ({ communityId }) => {
+ return {
+ name: 'CommunityPage',
+ params: { communityId },
+ path: `communities/${communityId}`
+ }
+}
diff --git a/src/helpers/formatters/links/profile.js b/src/helpers/formatters/links/profile.js
index eb80ded27..519bf5009 100644
--- a/src/helpers/formatters/links/profile.js
+++ b/src/helpers/formatters/links/profile.js
@@ -53,3 +53,11 @@ export const following = ({ profileId }) => {
path: `profiles/${profileId}/following`
}
}
+
+export const communities = ({ profileId }) => {
+ return {
+ name: 'ProfileCommunitiesPage',
+ params: { profileId },
+ path: `profiles/${profileId}/communities`
+ }
+}
diff --git a/src/helpers/formatters/navigation.js b/src/helpers/formatters/navigation.js
index e48550469..dbd0311a0 100644
--- a/src/helpers/formatters/navigation.js
+++ b/src/helpers/formatters/navigation.js
@@ -65,3 +65,14 @@ export const playlists = () => {
}
]
}
+
+export const communities = () => {
+ return [
+ {
+ name: i18n.global.t(
+ 'navigation.communities'
+ ),
+ isActive: true
+ }
+ ]
+}
diff --git a/src/helpers/formatters/navigation/community.js b/src/helpers/formatters/navigation/community.js
new file mode 100644
index 000000000..802296aa2
--- /dev/null
+++ b/src/helpers/formatters/navigation/community.js
@@ -0,0 +1,41 @@
+import i18n from '*/plugins/i18n'
+import {
+ main as formatCommunitiesLink,
+ community as formatCommunityLink
+} from '*/helpers/formatters/links/communities'
+
+export default function ({ communityTitle, pageNameKey }) {
+ const formatLink = () => {
+ if (pageNameKey) {
+ return formatCommunityLink({
+ communityTitle
+ })
+ }
+ }
+
+ const formatSubpageSection = () => {
+ if (pageNameKey) {
+ return {
+ name: i18n.global.t(
+ `navigation.${pageNameKey}`
+ ),
+ isActive: true
+ }
+ }
+ }
+
+ return [
+ {
+ name: i18n.global.t(
+ 'navigation.communities'
+ ),
+ link: formatCommunitiesLink()
+ },
+ {
+ name: communityTitle,
+ isActive: !pageNameKey,
+ link: formatLink()
+ },
+ formatSubpageSection()
+ ].filter(e => e)
+}
diff --git a/src/helpers/formatters/navigation/conversations.js b/src/helpers/formatters/navigation/conversations.js
index 59ebf6470..55f52550a 100644
--- a/src/helpers/formatters/navigation/conversations.js
+++ b/src/helpers/formatters/navigation/conversations.js
@@ -3,7 +3,7 @@ import {
main as formatConversationsLink
} from '*/helpers/formatters/links/conversations'
-export default function ({ conversationId, profileNickname } = {}) {
+export default function ({ profileNickname } = {}) {
const formatLink = () => {
if (profileNickname) {
return formatConversationsLink()
diff --git a/src/helpers/formatters/tabs/communities.js b/src/helpers/formatters/tabs/communities.js
new file mode 100644
index 000000000..e12e66a03
--- /dev/null
+++ b/src/helpers/formatters/tabs/communities.js
@@ -0,0 +1,18 @@
+import i18n from '*/plugins/i18n'
+import {
+ main as formatCommunitiesLink
+} from '*/helpers/formatters/links/communities'
+
+export default function () {
+ const title = i18n.global.t(
+ 'navigation.communities'
+ )
+
+ const { path } = formatCommunitiesLink()
+
+ return {
+ icon: 'users',
+ title,
+ path
+ }
+}
diff --git a/src/helpers/formatters/tabs/community.js b/src/helpers/formatters/tabs/community.js
new file mode 100644
index 000000000..707469a29
--- /dev/null
+++ b/src/helpers/formatters/tabs/community.js
@@ -0,0 +1,32 @@
+import i18n from '*/plugins/i18n'
+import {
+ community as formatCommunityLink
+} from '*/helpers/formatters/links/communities'
+
+export default function ({ communityId, communityTitle, pageNameKey }) {
+ const formatTitle = () => {
+ if (pageNameKey) {
+ return i18n.global.t(
+ `navigation.model.${pageNameKey}`,
+ { modelName: communityTitle }
+ )
+ } else {
+ return communityTitle
+ }
+ }
+
+ const formatPath = () => {
+ switch (pageNameKey) {
+ default:
+ return formatCommunityLink({
+ communityId
+ }).path
+ }
+ }
+
+ return {
+ icon: 'users',
+ title: formatTitle(),
+ path: formatPath()
+ }
+}
diff --git a/src/helpers/formatters/tabs/profile/communities.js b/src/helpers/formatters/tabs/profile/communities.js
new file mode 100644
index 000000000..02e7ffeef
--- /dev/null
+++ b/src/helpers/formatters/tabs/profile/communities.js
@@ -0,0 +1,25 @@
+import i18n from '*/plugins/i18n'
+import {
+ communities as formatProfileCommunitiesLink
+} from '*/helpers/formatters/links/profile'
+
+export default function ({ profileId, profileNickname }) {
+ const formatTitle = () => {
+ return i18n.global.t(
+ 'navigation.model.communities',
+ { modelName: profileNickname }
+ )
+ }
+
+ const formatPath = () => {
+ return formatProfileCommunitiesLink({
+ profileId
+ }).path
+ }
+
+ return {
+ icon: 'users',
+ title: formatTitle(),
+ path: formatPath()
+ }
+}
diff --git a/src/views/PlaylistsPage.vue b/src/views/PlaylistsPage.vue
index d84c370e9..a400a259d 100644
--- a/src/views/PlaylistsPage.vue
+++ b/src/views/PlaylistsPage.vue
@@ -3,35 +3,42 @@
:responsePageLimit="limit"
>
-
-
+
+
+
+
-
-
-
-
-
+
+
+
+
+
+
+
@@ -41,6 +48,8 @@ import BasePlaylistsPageContainer
from '*/components/containers/pages/playlists/BasePlaylistsPageContainer.vue'
import BaseSegmentContainer
from '*/components/containers/segments/BaseSegmentContainer.vue'
+import BasePlaylistCreateButton
+ from '*/components/buttons/playlist/BasePlaylistCreateButton.vue'
import BasePaginatedListContainer
from '*/components/containers/lists/BasePaginatedListContainer.vue'
import BasePlaylistsSimpleList
@@ -51,6 +60,7 @@ export default {
components: {
BasePlaylistsPageContainer,
BaseSegmentContainer,
+ BasePlaylistCreateButton,
BasePaginatedListContainer,
BasePlaylistsSimpleList
},
diff --git a/src/views/communities/CommunityPage.vue b/src/views/communities/CommunityPage.vue
new file mode 100644
index 000000000..42cb80914
--- /dev/null
+++ b/src/views/communities/CommunityPage.vue
@@ -0,0 +1,35 @@
+