ユーザーグループ

Resolve #3218
This commit is contained in:
syuilo
2019-05-18 20:36:33 +09:00
parent 61f54f8f74
commit c7cc3dcdfd
65 changed files with 1797 additions and 638 deletions

View File

@ -18,17 +18,16 @@ import MkDrive from './views/pages/drive.vue';
import MkWidgets from './views/pages/widgets.vue';
import MkMessaging from './views/pages/messaging.vue';
import MkMessagingRoom from './views/pages/messaging-room.vue';
import MkReceivedFollowRequests from './views/pages/received-follow-requests.vue';
import MkNote from './views/pages/note.vue';
import MkSearch from './views/pages/search.vue';
import MkFavorites from './views/pages/favorites.vue';
import MkUserLists from './views/pages/user-lists.vue';
import MkUserList from './views/pages/user-list.vue';
import UI from './views/pages/ui.vue';
import MkReversi from './views/pages/games/reversi.vue';
import MkTag from './views/pages/tag.vue';
import MkShare from '../common/views/pages/share.vue';
import MkFollow from '../common/views/pages/follow.vue';
import MkNotFound from '../common/views/pages/not-found.vue';
import DeckColumn from '../common/views/deck/deck.column-template.vue';
import PostForm from './views/components/post-form-dialog.vue';
import FileChooser from './views/components/drive-file-chooser.vue';
@ -125,9 +124,14 @@ init((launch, os) => {
{ path: '/search', component: () => import('../common/views/deck/deck.search-column.vue').then(m => m.default) },
{ path: '/tags/:tag', name: 'tag', component: () => import('../common/views/deck/deck.hashtag-column.vue').then(m => m.default) },
{ path: '/featured', name: 'featured', component: () => import('../common/views/deck/deck.featured-column.vue').then(m => m.default) },
{ path: '/explore', name: 'explore', component: () => import('../common/views/deck/deck.explore-column.vue').then(m => m.default) },
{ path: '/explore/tags/:tag', name: 'explore-tag', props: true, component: () => import('../common/views/deck/deck.explore-column.vue').then(m => m.default) },
{ path: '/i/favorites', component: () => import('../common/views/deck/deck.favorites-column.vue').then(m => m.default) }
{ path: '/explore', name: 'explore', component: DeckColumn, props: route => ({ component: () => import('../common/views/pages/explore.vue').then(m => m.default) }) },
{ path: '/explore/tags/:tag', name: 'explore-tag', component: DeckColumn, props: route => ({ component: () => import('../common/views/pages/explore.vue').then(m => m.default), tag: route.params.tag }) },
{ path: '/i/favorites', component: () => import('../common/views/deck/deck.favorites-column.vue').then(m => m.default) },
{ path: '/i/pages', component: DeckColumn, props: route => ({ component: () => import('../common/views/pages/pages.vue').then(m => m.default) }) },
{ path: '/i/lists', component: DeckColumn, props: route => ({ component: () => import('../common/views/pages/user-lists.vue').then(m => m.default) }) },
{ path: '/i/lists/:listId', component: DeckColumn, props: route => ({ component: () => import('../common/views/pages/user-list-editor.vue').then(m => m.default), listId: route.params.listId }) },
{ path: '/i/groups', component: DeckColumn, props: route => ({ component: () => import('../common/views/pages/user-groups.vue').then(m => m.default) }) },
{ path: '/i/groups/:groupId', component: DeckColumn, props: route => ({ component: () => import('../common/views/pages/user-group-editor.vue').then(m => m.default), groupId: route.params.groupId }) },
]}]
: [
{ path: '/', name: 'index', component: MkIndex },
@ -135,12 +139,15 @@ init((launch, os) => {
{ path: '/signup', name: 'signup', component: MkSignup },
{ path: '/i/settings', name: 'settings', component: () => import('./views/pages/settings.vue').then(m => m.default) },
{ path: '/i/favorites', name: 'favorites', component: MkFavorites },
{ path: '/i/pages', name: 'pages', component: () => import('./views/pages/pages.vue').then(m => m.default) },
{ path: '/i/lists', name: 'user-lists', component: MkUserLists },
{ path: '/i/lists/:list', name: 'user-list', component: MkUserList },
{ path: '/i/received-follow-requests', name: 'received-follow-requests', component: MkReceivedFollowRequests },
{ path: '/i/pages', name: 'pages', component: UI, props: route => ({ component: () => import('../common/views/pages/pages.vue').then(m => m.default) }) },
{ path: '/i/lists', name: 'user-lists', component: UI, props: route => ({ component: () => import('../common/views/pages/user-lists.vue').then(m => m.default) }) },
{ path: '/i/lists/:list', component: UI, props: route => ({ component: () => import('../common/views/pages/user-list-editor.vue').then(m => m.default), listId: route.params.list }) },
{ path: '/i/groups', name: 'user-groups', component: UI, props: route => ({ component: () => import('../common/views/pages/user-groups.vue').then(m => m.default) }) },
{ path: '/i/groups/:group', component: UI, props: route => ({ component: () => import('../common/views/pages/user-group-editor.vue').then(m => m.default), groupId: route.params.group }) },
{ path: '/i/follow-requests', name: 'follow-requests', component: UI, props: route => ({ component: () => import('../common/views/pages/follow-requests.vue').then(m => m.default) }) },
{ path: '/i/widgets', name: 'widgets', component: MkWidgets },
{ path: '/i/messaging', name: 'messaging', component: MkMessaging },
{ path: '/i/messaging/group/:group', component: MkMessagingRoom },
{ path: '/i/messaging/:user', component: MkMessagingRoom },
{ path: '/i/drive', name: 'drive', component: MkDrive },
{ path: '/i/drive/folder/:folder', component: MkDrive },
@ -151,8 +158,8 @@ init((launch, os) => {
{ path: '/search', component: MkSearch },
{ path: '/tags/:tag', component: MkTag },
{ path: '/featured', name: 'featured', component: () => import('./views/pages/featured.vue').then(m => m.default) },
{ path: '/explore', name: 'explore', component: () => import('./views/pages/explore.vue').then(m => m.default) },
{ path: '/explore/tags/:tag', name: 'explore-tag', props: true, component: () => import('./views/pages/explore.vue').then(m => m.default) },
{ path: '/explore', name: 'explore', component: UI, props: route => ({ component: () => import('../common/views/pages/explore.vue').then(m => m.default) }) },
{ path: '/explore/tags/:tag', name: 'explore-tag', component: UI, props: route => ({ component: () => import('../common/views/pages/explore.vue').then(m => m.default), tag: route.params.tag }) },
{ path: '/share', component: MkShare },
{ path: '/games/reversi/:game?', name: 'reversi', component: MkReversi },
{ path: '/@:user', name: 'user', component: () => import('./views/pages/user/index.vue').then(m => m.default), children: [

View File

@ -19,7 +19,7 @@
<li><router-link to="/" :data-active="$route.name == 'index'"><i><fa icon="home" fixed-width/></i>{{ $t('timeline') }}<i><fa icon="angle-right"/></i></router-link></li>
<li><p @click="showNotifications = true"><i><fa :icon="['far', 'bell']" fixed-width/></i>{{ $t('notifications') }}<i v-if="hasUnreadNotification" class="circle"><fa icon="circle"/></i><i><fa icon="angle-right"/></i></p></li>
<li><router-link to="/i/messaging" :data-active="$route.name == 'messaging'"><i><fa :icon="['far', 'comments']" fixed-width/></i>{{ $t('@.messaging') }}<i v-if="hasUnreadMessagingMessage" class="circle"><fa icon="circle"/></i><i><fa icon="angle-right"/></i></router-link></li>
<li v-if="$store.getters.isSignedIn && ($store.state.i.isLocked || $store.state.i.carefulBot)"><router-link to="/i/received-follow-requests" :data-active="$route.name == 'received-follow-requests'"><i><fa :icon="['far', 'envelope']" fixed-width/></i>{{ $t('follow-requests') }}<i v-if="$store.getters.isSignedIn && $store.state.i.pendingReceivedFollowRequestsCount" class="circle"><fa icon="circle"/></i><i><fa icon="angle-right"/></i></router-link></li>
<li v-if="$store.getters.isSignedIn && ($store.state.i.isLocked || $store.state.i.carefulBot)"><router-link to="/i/follow-requests" :data-active="$route.name == 'follow-requests'"><i><fa :icon="['far', 'envelope']" fixed-width/></i>{{ $t('follow-requests') }}<i v-if="$store.getters.isSignedIn && $store.state.i.pendingReceivedFollowRequestsCount" class="circle"><fa icon="circle"/></i><i><fa icon="angle-right"/></i></router-link></li>
<li><router-link to="/featured" :data-active="$route.name == 'featured'"><i><fa :icon="faNewspaper" fixed-width/></i>{{ $t('@.featured-notes') }}<i><fa icon="angle-right"/></i></router-link></li>
<li><router-link to="/explore" :data-active="$route.name == 'explore' || $route.name == 'explore-tag'"><i><fa :icon="faHashtag" fixed-width/></i>{{ $t('@.explore') }}<i><fa icon="angle-right"/></i></router-link></li>
<li><router-link to="/games/reversi" :data-active="$route.name == 'reversi'"><i><fa icon="gamepad" fixed-width/></i>{{ $t('game') }}<i v-if="hasGameInvitation" class="circle"><fa icon="circle"/></i><i><fa icon="angle-right"/></i></router-link></li>

View File

@ -1,28 +0,0 @@
<template>
<mk-ui>
<template #header><span style="margin-right:4px;"><fa :icon="faHashtag"/></span>{{ $t('@.explore') }}</template>
<main>
<x-explore v-bind="$attrs"/>
</main>
</mk-ui>
</template>
<script lang="ts">
import Vue from 'vue';
import i18n from '../../../i18n';
import { faHashtag } from '@fortawesome/free-solid-svg-icons';
import XExplore from '../../../common/views/pages/explore.vue';
export default Vue.extend({
i18n: i18n(''),
components: {
XExplore
},
data() {
return {
faHashtag
};
},
});
</script>

View File

@ -2,9 +2,10 @@
<mk-ui>
<template #header>
<template v-if="user"><span style="margin-right:4px;"><fa :icon="['far', 'comments']"/></span><mk-user-name :user="user"/></template>
<template v-else-if="group"><span style="margin-right:4px;"><fa :icon="['far', 'comments']"/></span>{{ group.name }}</template>
<template v-else><mk-ellipsis/></template>
</template>
<x-messaging-room v-if="!fetching" :user="user" :is-naked="true"/>
<x-messaging-room v-if="!fetching" :user="user" :group="group" :is-naked="true"/>
</mk-ui>
</template>
@ -22,6 +23,7 @@ export default Vue.extend({
return {
fetching: true,
user: null,
group: null,
unwatchDarkmode: null
};
},
@ -48,12 +50,21 @@ export default Vue.extend({
methods: {
fetch() {
this.fetching = true;
this.$root.api('users/show', parseAcct(this.$route.params.user)).then(user => {
this.user = user;
this.fetching = false;
if (this.$route.params.user) {
this.$root.api('users/show', parseAcct(this.$route.params.user)).then(user => {
this.user = user;
this.fetching = false;
document.title = `${this.$t('@.messaging')}: ${Vue.filter('userName')(this.user)} | ${this.$root.instanceName}`;
});
document.title = `${this.$t('@.messaging')}: ${Vue.filter('userName')(this.user)} | ${this.$root.instanceName}`;
});
} else {
this.$root.api('users/groups/show', { groupId: this.$route.params.group }).then(group => {
this.group = group;
this.fetching = false;
document.title = this.$t('@.messaging') + ': ' + this.group.name;
});
}
}
}
});

View File

@ -1,7 +1,7 @@
<template>
<mk-ui>
<template #header><span style="margin-right:4px;"><fa :icon="['far', 'comments']"/></span>{{ $t('@.messaging') }}</template>
<x-messaging @navigate="navigate" :header-top="48"/>
<x-messaging @navigate="navigate" @navigateGroup="navigateGroup" :header-top="48"/>
</mk-ui>
</template>
@ -21,6 +21,9 @@ export default Vue.extend({
methods: {
navigate(user) {
(this as any).$router.push(`/i/messaging/${getAcct(user)}`);
},
navigateGroup(group) {
(this as any).$router.push(`/i/messaging/group/${group.id}`);
}
}
});

View File

@ -1,29 +0,0 @@
<template>
<mk-ui>
<template #header><span style="margin-right:4px;"><fa :icon="faStickyNote"/></span>{{ $t('@.pages') }}</template>
<main>
<x-pages v-bind="$attrs"/>
</main>
</mk-ui>
</template>
<script lang="ts">
import Vue from 'vue';
import i18n from '../../../i18n';
import { faHashtag } from '@fortawesome/free-solid-svg-icons';
import XPages from '../../../common/views/pages/pages.vue';
export default Vue.extend({
i18n: i18n(''),
components: {
XPages
},
data() {
return {
faHashtag
};
},
});
</script>

View File

@ -1,69 +0,0 @@
<template>
<mk-ui>
<template #header><fa :icon="['far', 'envelope']"/>{{ $t('title') }}</template>
<main>
<div v-for="req in requests">
<router-link :key="req.id" :to="req.follower | userPage">
<mk-user-name :user="req.follower"/>
</router-link>
<span>
<a @click="accept(req.follower)">{{ $t('accept') }}</a>|<a @click="reject(req.follower)">{{ $t('reject') }}</a>
</span>
</div>
</main>
</mk-ui>
</template>
<script lang="ts">
import Vue from 'vue';
import i18n from '../../../i18n';
import Progress from '../../../common/scripts/loading';
export default Vue.extend({
i18n: i18n('mobile/views/pages/received-follow-requests.vue'),
data() {
return {
fetching: true,
requests: []
};
},
mounted() {
document.title = this.$t('title');
Progress.start();
this.$root.api('following/requests/list').then(requests => {
this.fetching = false;
this.requests = requests;
Progress.done();
});
},
methods: {
accept(user) {
this.$root.api('following/requests/accept', { userId: user.id }).then(() => {
this.requests = this.requests.filter(r => r.follower.id != user.id);
});
},
reject(user) {
this.$root.api('following/requests/reject', { userId: user.id }).then(() => {
this.requests = this.requests.filter(r => r.follower.id != user.id);
});
}
}
});
</script>
<style lang="stylus" scoped>
main
> div
display flex
padding 16px
border solid 1px var(--faceDivider)
border-radius 4px
> span
margin 0 0 0 auto
</style>

View File

@ -0,0 +1,38 @@
<template>
<mk-ui>
<template #header><span style="margin-right:4px;" v-if="icon"><fa :icon="icon"/></span>{{ title }}</template>
<main>
<component :is="component" @init="init" v-bind="$attrs"/>
</main>
</mk-ui>
</template>
<script lang="ts">
import Vue from 'vue';
export default Vue.extend({
props: {
component: {
required: true
}
},
data() {
return {
title: null,
icon: null,
};
},
mounted() {
},
methods: {
init(v) {
this.title = v.title;
this.icon = v.icon;
}
}
});
</script>

View File

@ -1,48 +0,0 @@
<template>
<mk-ui>
<template #header v-if="!fetching"><fa icon="list"/>{{ list.name }}</template>
<main v-if="!fetching">
<x-editor :list="list"/>
</main>
</mk-ui>
</template>
<script lang="ts">
import Vue from 'vue';
import Progress from '../../../common/scripts/loading';
import XEditor from '../../../common/views/components/user-list-editor.vue';
export default Vue.extend({
components: {
XEditor
},
data() {
return {
fetching: true,
list: null
};
},
watch: {
$route: 'fetch'
},
created() {
this.fetch();
},
methods: {
fetch() {
Progress.start();
this.fetching = true;
this.$root.api('users/lists/show', {
listId: this.$route.params.list
}).then(list => {
this.list = list;
this.fetching = false;
Progress.done();
});
}
}
});
</script>

View File

@ -1,35 +0,0 @@
<template>
<mk-ui>
<template #header><fa icon="list"/>{{ $t('title') }}</template>
<template #func><button @click="$refs.lists.add()"><fa icon="plus"/></button></template>
<x-lists ref="lists" @choosen="choosen"/>
</mk-ui>
</template>
<script lang="ts">
import Vue from 'vue';
import i18n from '../../../i18n';
export default Vue.extend({
i18n: i18n('mobile/views/pages/user-lists.vue'),
data() {
return {
fetching: true,
lists: []
};
},
components: {
XLists: () => import('../../../common/views/components/user-lists.vue').then(m => m.default)
},
mounted() {
document.title = this.$t('title');
},
methods: {
choosen(list) {
if (!list) return;
this.$router.push(`/i/lists/${list.id}`);
}
}
});
</script>