Add group page and card components.
This commit is contained in:
parent
7a3e608455
commit
55925383b7
8 changed files with 327 additions and 1 deletions
228
src/components/group_card_content/group_card_content.vue
Normal file
228
src/components/group_card_content/group_card_content.vue
Normal file
|
@ -0,0 +1,228 @@
|
|||
<template>
|
||||
<div id="heading" class="group-panel-background" :style="headingStyle">
|
||||
<div class="panel-heading text-center">
|
||||
<div class='group-info'>
|
||||
<div class='container'>
|
||||
<router-link :to="{ name: 'group-page', params: { name: group.nickname } }">
|
||||
<img v-if="!!group.original_logo" :src="group.original_logo">
|
||||
<img v-else src="https://placehold.it/48x48">
|
||||
</router-link>
|
||||
<span class="glyphicon glyphicon-user"></span>
|
||||
<div class="name-and-screen-name">
|
||||
<div class='group-name'>{{group.nickname}}</div>
|
||||
<router-link :to="{ name: 'group-page', params: { name: group.nickname } }">
|
||||
<div class='group-full-name'>{{group.fullname}}</div>
|
||||
</router-link>
|
||||
</div>
|
||||
</div>
|
||||
<div class="group-interactions">
|
||||
<div class="member" v-if="loggedIn">
|
||||
<span v-if="isMember">
|
||||
<button @click="leaveGroup" class="base04 base00-background pressed">
|
||||
{{ $t('group_card.leave') }}
|
||||
</button>
|
||||
</span>
|
||||
<span v-if="!isMember">
|
||||
<button @click="joinGroup" class="base05 base02-background">
|
||||
{{ $t('group_card.join') }}
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel-body group-panel-body">
|
||||
<div class="member-counts">
|
||||
<div class="member-count">
|
||||
<a href="#" v-on:click.prevent="setGroupView('statuses')"><h5 class="base05">{{ $t('user_card.statuses') }}</h5></a>
|
||||
</div>
|
||||
<div class="member-count">
|
||||
<a href="#" v-on:click.prevent="setGroupView('members')"><h5 class="base05">{{ $t('group_card.members') }}</h5></a>
|
||||
<span class="base05">{{group.member_count}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<p>{{group.description}}</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: [ 'groupName' ],
|
||||
computed: {
|
||||
group () {
|
||||
return this.$store.state.groups.groupsObject[this.groupName]
|
||||
},
|
||||
headingStyle () {
|
||||
let color = this.$store.state.config.colors['base00']
|
||||
if (color) {
|
||||
let rgb = this.$store.state.config.colors['base00'].match(/\d+/g)
|
||||
return {
|
||||
backgroundColor: `rgb(${Math.floor(rgb[0] * 0.53)}, ${Math.floor(rgb[1] * 0.56)}, ${Math.floor(rgb[2] * 0.59)})`,
|
||||
backgroundImage: `url(${this.group.cover_photo})`
|
||||
}
|
||||
}
|
||||
},
|
||||
loggedIn () {
|
||||
return !!this.$store.state.users.currentUser
|
||||
},
|
||||
isMember () {
|
||||
return this.$store.state.groups.groupMemberships[this.groupName]
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
setMember (value) {
|
||||
this.$store.state.groups.groupMemberships[this.groupName] = value
|
||||
},
|
||||
joinGroup () {
|
||||
const store = this.$store
|
||||
store.state.api.backendInteractor.joinGroup({'groupName': this.group.nickname})
|
||||
.then((joinedGroup) => {
|
||||
store.commit('addNewGroup', joinedGroup)
|
||||
this.setMember(true)
|
||||
})
|
||||
},
|
||||
leaveGroup () {
|
||||
const store = this.$store
|
||||
store.state.api.backendInteractor.leaveGroup({'groupName': this.group.nickname})
|
||||
.then((leftGroup) => {
|
||||
store.commit('addNewGroup', leftGroup)
|
||||
this.setMember(false)
|
||||
})
|
||||
},
|
||||
setGroupView (v) {
|
||||
const store = this.$store
|
||||
store.commit('setGroupView', { v })
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import '../../_variables.scss';
|
||||
|
||||
.group-panel-background {
|
||||
background-size: cover;
|
||||
border-radius: 10px;
|
||||
|
||||
.panel-heading {
|
||||
padding: 0.6em 0em;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.group-panel-body {
|
||||
top: -0em;
|
||||
padding-top: 4em;
|
||||
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
.group-info {
|
||||
color: white;
|
||||
padding: 0 16px 16px 16px;
|
||||
margin-bottom: -4em;
|
||||
|
||||
.container{
|
||||
padding: 16px 10px 4px 10px;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
flex-direction: column;
|
||||
align-content: flex-start;
|
||||
justify-content: center;
|
||||
max-height: 56px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
img {
|
||||
border-radius: 5px;
|
||||
flex: 1 0 100%;
|
||||
width: 56px;
|
||||
height: 56px;
|
||||
box-shadow: 0px 1px 8px rgba(0,0,0,0.75);
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
text-shadow: 0px 1px 1.5px rgba(0, 0, 0, 1.0);
|
||||
|
||||
.name-and-screen-name {
|
||||
display: block;
|
||||
margin-left: 0.6em;
|
||||
text-align: left;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.group-name{
|
||||
color: white;
|
||||
}
|
||||
|
||||
.group-full-name {
|
||||
color: white;
|
||||
font-weight: lighter;
|
||||
font-size: 15px;
|
||||
padding-right: 0.1em;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.group-interactions {
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
justify-content: space-between;
|
||||
|
||||
div {
|
||||
flex: 1;
|
||||
}
|
||||
margin-top: 0.7em;
|
||||
margin-bottom: -1.0em;
|
||||
|
||||
.following {
|
||||
color: white;
|
||||
font-size: 14px;
|
||||
flex: 0 0 100%;
|
||||
margin: -0.7em 0.0em 0.3em 0.0em;
|
||||
padding-left: 16px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.mute {
|
||||
max-width: 220px;
|
||||
min-height: 28px;
|
||||
}
|
||||
|
||||
.follow {
|
||||
max-width: 220px;
|
||||
min-height: 28px;
|
||||
}
|
||||
|
||||
button {
|
||||
width: 92%;
|
||||
height: 100%;
|
||||
}
|
||||
.pressed {
|
||||
border-bottom-color: rgba(255, 255, 255, 0.2);
|
||||
border-top-color: rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.member-counts {
|
||||
display: flex;
|
||||
line-height:16px;
|
||||
padding: 1em 1.5em 0em 1em;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.member-count {
|
||||
flex: 1;
|
||||
|
||||
h5 {
|
||||
font-size:1em;
|
||||
font-weight: bolder;
|
||||
margin: 0 0 0.25em;
|
||||
}
|
||||
a {
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
</style>
|
38
src/components/group_page/group_page.js
Normal file
38
src/components/group_page/group_page.js
Normal file
|
@ -0,0 +1,38 @@
|
|||
import GroupCardContent from '../group_card_content/group_card_content.vue'
|
||||
import Timeline from '../timeline/timeline.vue'
|
||||
|
||||
const GroupPage = {
|
||||
created () {
|
||||
const name = this.$route.params.name
|
||||
this.$store.commit('clearTimeline', { timeline: 'group' })
|
||||
this.$store.dispatch('startFetching', { 'identifier': name })
|
||||
this.$store.dispatch('fetchGroup', { 'groupName': name })
|
||||
this.$store.dispatch('fetchIsMember', { 'groupName': name, 'id': this.$store.state.users.currentUser.id })
|
||||
},
|
||||
destroyed () {
|
||||
this.$store.dispatch('stopFetching', 'group')
|
||||
},
|
||||
computed: {
|
||||
timeline () { return this.$store.state.statuses.timelines.group },
|
||||
groupName () {
|
||||
return this.$route.params.name
|
||||
},
|
||||
group () {
|
||||
return this.$store.state.groups.groupsObject[this.groupName] || false
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
groupName () {
|
||||
this.$store.dispatch('fetchGroup', { 'groupName': this.groupName })
|
||||
this.$store.dispatch('fetchIsMember', { 'groupName': this.groupName, 'id': this.$store.state.users.currentUser.id })
|
||||
this.$store.commit('clearTimeline', { timeline: 'group' })
|
||||
// this.$store.dispatch('startFetching', { 'identifier': this.groupName })
|
||||
}
|
||||
},
|
||||
components: {
|
||||
GroupCardContent,
|
||||
Timeline
|
||||
}
|
||||
}
|
||||
|
||||
export default GroupPage
|
21
src/components/group_page/group_page.vue
Normal file
21
src/components/group_page/group_page.vue
Normal file
|
@ -0,0 +1,21 @@
|
|||
<template>
|
||||
<div>
|
||||
<div v-if="group" class="group-page panel panel-default base00-background">
|
||||
<group-card-content :groupName="groupName"></group-card-content>
|
||||
</div>
|
||||
<Timeline :title="'Group Timeline'" v-bind:timeline="timeline" v-bind:timeline-name="'group'" :groupName="groupName" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script src="./group_page.js"></script>
|
||||
|
||||
<style lang="scss">
|
||||
|
||||
.group-page {
|
||||
flex: 2;
|
||||
flex-basis: 500px;
|
||||
padding-bottom: 10px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
</style>
|
|
@ -158,6 +158,11 @@ const en = {
|
|||
followees: 'Following',
|
||||
per_day: 'per day'
|
||||
},
|
||||
group_card: {
|
||||
members: 'Members',
|
||||
join: 'Join group',
|
||||
leave: 'Leave group'
|
||||
},
|
||||
timeline: {
|
||||
show_new: 'Show new',
|
||||
error_fetching: 'Error fetching updates',
|
||||
|
|
|
@ -9,6 +9,7 @@ import TagTimeline from './components/tag_timeline/tag_timeline.vue'
|
|||
import ConversationPage from './components/conversation-page/conversation-page.vue'
|
||||
import Mentions from './components/mentions/mentions.vue'
|
||||
import UserProfile from './components/user_profile/user_profile.vue'
|
||||
import GroupPage from './components/group_page/group_page.vue'
|
||||
import Settings from './components/settings/settings.vue'
|
||||
import Registration from './components/registration/registration.vue'
|
||||
import UserSettings from './components/user_settings/user_settings.vue'
|
||||
|
@ -72,6 +73,7 @@ const routes = [
|
|||
{ path: '/tag/:tag', component: TagTimeline },
|
||||
{ name: 'conversation', path: '/notice/:id', component: ConversationPage, meta: { dontScroll: true } },
|
||||
{ name: 'user-profile', path: '/users/:id', component: UserProfile },
|
||||
{ name: 'group-page', path: '/groups/:name', component: GroupPage },
|
||||
{ name: 'mentions', path: '/:username/mentions', component: Mentions },
|
||||
{ name: 'settings', path: '/settings', component: Settings },
|
||||
{ name: 'registration', path: '/registration', component: Registration },
|
||||
|
|
|
@ -17,7 +17,8 @@ export const mergeOrAdd = (arr, obj, item) => {
|
|||
|
||||
export const defaultState = {
|
||||
groups: [],
|
||||
groupsObject: {}
|
||||
groupsObject: {},
|
||||
groupMemberships: {}
|
||||
}
|
||||
|
||||
const groups = {
|
||||
|
@ -27,9 +28,23 @@ const groups = {
|
|||
each(statuses, (groups) => {
|
||||
each(groups, (group) => mergeOrAdd(state.groups, state.groupsObject, group))
|
||||
})
|
||||
},
|
||||
addNewGroup (state, group) {
|
||||
mergeOrAdd(state.groups, state.groupsObject, group)
|
||||
},
|
||||
addMembership (state, {groupName, membership}) {
|
||||
state.groupMemberships[groupName] = membership
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
fetchGroup (store, { groupName }) {
|
||||
store.rootState.api.backendInteractor.fetchGroup({ groupName })
|
||||
.then((group) => store.commit('addNewGroup', group))
|
||||
},
|
||||
fetchIsMember (store, { groupName, id }) {
|
||||
store.rootState.api.backendInteractor.fetchIsMember({id, groupName})
|
||||
.then((membership) => store.commit('addMembership', {groupName, 'membership': membership.is_member}))
|
||||
},
|
||||
addNewStatuses (store, { statuses }) {
|
||||
const groups = compact(map(statuses, 'statusnet_in_groups'))
|
||||
store.commit('addNewGroups', groups)
|
||||
|
|
|
@ -93,6 +93,21 @@ export const defaultState = {
|
|||
followers: [],
|
||||
friends: [],
|
||||
viewing: 'statuses'
|
||||
},
|
||||
group: {
|
||||
statuses: [],
|
||||
statusesObject: {},
|
||||
faves: [],
|
||||
visibleStatuses: [],
|
||||
visibleStatusesObject: {},
|
||||
newStatusCount: 0,
|
||||
maxId: 0,
|
||||
minVisibleId: 0,
|
||||
loading: false,
|
||||
members: [],
|
||||
followers: [],
|
||||
friends: [],
|
||||
viewing: 'statuses'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,12 +29,14 @@ const QVITTER_USER_TIMELINE_URL = '/api/qvitter/statuses/user_timeline.json'
|
|||
const BLOCKING_URL = '/api/blocks/create.json'
|
||||
const UNBLOCKING_URL = '/api/blocks/destroy.json'
|
||||
const USER_URL = '/api/users/show.json'
|
||||
const GROUP_URL = '/api/statusnet/groups/show'
|
||||
const GROUP_TIMELINE_URL = '/api/statusnet/groups/timeline'
|
||||
const GROUP_JOINING_URL = '/api/statusnet/groups/join'
|
||||
const GROUP_LEAVING_URL = '/api/statusnet/groups/leave'
|
||||
const GROUP_CREATE_URL = '/api/statusnet/groups/create.json'
|
||||
const USER_MEMBERSHIPS_URL = '/api/statusnet/groups/list.json'
|
||||
const GROUP_MEMBERS_URL = '/api/statusnet/groups/membership'
|
||||
const GROUP_IS_MEMBER_URL = '/api/statusnet/groups/is_member.json'
|
||||
|
||||
import { each, map } from 'lodash'
|
||||
import 'whatwg-fetch'
|
||||
|
|
Loading…
Add table
Reference in a new issue