summaryrefslogtreecommitdiff
path: root/src/client
diff options
context:
space:
mode:
authorsyuilo <Syuilotan@yahoo.co.jp>2020-02-08 15:11:12 +0900
committersyuilo <Syuilotan@yahoo.co.jp>2020-02-08 15:11:12 +0900
commit860a7d1eeb6a8c14dff812f65fc5901d292213b0 (patch)
tree46089be8ce10b3867f5c774171fc05e0742876ce /src/client
parent:art: (diff)
downloadmisskey-860a7d1eeb6a8c14dff812f65fc5901d292213b0.tar.gz
misskey-860a7d1eeb6a8c14dff812f65fc5901d292213b0.tar.bz2
misskey-860a7d1eeb6a8c14dff812f65fc5901d292213b0.zip
wip
Diffstat (limited to 'src/client')
-rw-r--r--src/client/app.vue5
-rw-r--r--src/client/pages/my-groups/group.vue194
-rw-r--r--src/client/pages/my-groups/index.vue99
-rw-r--r--src/client/pages/my-lists/index.vue2
-rw-r--r--src/client/pages/my-lists/list.vue50
-rw-r--r--src/client/router.ts2
6 files changed, 342 insertions, 10 deletions
diff --git a/src/client/app.vue b/src/client/app.vue
index e260d3070c..081f4f22d3 100644
--- a/src/client/app.vue
+++ b/src/client/app.vue
@@ -411,6 +411,11 @@ export default Vue.extend({
icon: faListUl,
}, {
type: 'link',
+ text: this.$t('groups'),
+ to: '/my/groups',
+ icon: faUsers,
+ }, {
+ type: 'link',
text: this.$t('antennas'),
to: '/my/antennas',
icon: faSatellite,
diff --git a/src/client/pages/my-groups/group.vue b/src/client/pages/my-groups/group.vue
new file mode 100644
index 0000000000..67f5f9754f
--- /dev/null
+++ b/src/client/pages/my-groups/group.vue
@@ -0,0 +1,194 @@
+<template>
+<div class="mk-group-page">
+ <portal to="icon"><fa :icon="faUsers"/></portal>
+ <portal to="title">{{ group.name }}</portal>
+
+ <transition name="zoom" mode="out-in">
+ <div v-if="group" class="_card">
+ <div class="_content">
+ <mk-button inline @click="renameGroup()">{{ $t('rename') }}</mk-button>
+ <mk-button inline @click="deleteGroup()">{{ $t('delete') }}</mk-button>
+ </div>
+ </div>
+ </transition>
+
+ <transition name="zoom" mode="out-in">
+ <div v-if="group" class="_card members">
+ <div class="_title">{{ $t('members') }}</div>
+ <div class="_content">
+ <div class="users">
+ <div class="user" v-for="user in users" :key="user.id">
+ <mk-avatar :user="user" class="avatar"/>
+ <div class="body">
+ <mk-user-name :user="user" class="name"/>
+ <mk-acct :user="user" class="acct"/>
+ </div>
+ <div class="action">
+ <button class="_button" @click="removeUser(user)"><fa :icon="faTimes"/></button>
+ </div>
+ </div>
+ </div>
+ </div>
+ <div class="_footer">
+ <mk-button inline @click="invite()">{{ $t('invite') }}</mk-button>
+ </div>
+ </div>
+ </transition>
+</div>
+</template>
+
+<script lang="ts">
+import Vue from 'vue';
+import { faTimes, faUsers } from '@fortawesome/free-solid-svg-icons';
+import i18n from '../../i18n';
+import Progress from '../../scripts/loading';
+import MkButton from '../../components/ui/button.vue';
+import MkUserSelect from '../../components/user-select.vue';
+
+export default Vue.extend({
+ i18n,
+
+ metaInfo() {
+ return {
+ title: this.group ? `${this.group.name} | ${this.$t('manageGroups')}` : this.$t('manageGroups')
+ };
+ },
+
+ components: {
+ MkButton
+ },
+
+ data() {
+ return {
+ group: null,
+ users: [],
+ faTimes, faUsers
+ };
+ },
+
+ watch: {
+ $route: 'fetch'
+ },
+
+ created() {
+ this.fetch();
+ },
+
+ methods: {
+ fetch() {
+ Progress.start();
+ this.$root.api('users/groups/show', {
+ groupId: this.$route.params.group
+ }).then(group => {
+ this.group = group;
+ this.$root.api('users/show', {
+ userIds: this.group.userIds
+ }).then(users => {
+ this.users = users;
+ Progress.done();
+ });
+ });
+ },
+
+ invite() {
+ this.$root.new(MkUserSelect, {}).$once('selected', user => {
+ this.$root.api('users/groups/invite', {
+ groupId: this.group.id,
+ userId: user.id
+ }).then(() => {
+ this.$root.dialog({
+ type: 'success',
+ iconOnly: true, autoClose: true
+ });
+ }).catch(e => {
+ this.$root.dialog({
+ type: 'error',
+ text: e
+ });
+ });
+ });
+ },
+
+ removeUser(user) {
+ this.$root.api('users/groups/pull', {
+ groupId: this.group.id,
+ userId: user.id
+ }).then(() => {
+ this.users = this.users.filter(x => x.id !== user.id);
+ });
+ },
+
+ async renameGroup() {
+ const { canceled, result: name } = await this.$root.dialog({
+ title: this.$t('groupName'),
+ input: {
+ default: this.group.name
+ }
+ });
+ if (canceled) return;
+
+ await this.$root.api('users/groups/update', {
+ groupId: this.group.id,
+ name: name
+ });
+
+ this.group.name = name;
+ },
+
+ async deleteGroup() {
+ const { canceled } = await this.$root.dialog({
+ type: 'warning',
+ text: this.$t('removeAreYouSure', { x: this.group.name }),
+ showCancelButton: true
+ });
+ if (canceled) return;
+
+ await this.$root.api('users/groups/delete', {
+ groupId: this.group.id
+ });
+ this.$root.dialog({
+ type: 'success',
+ iconOnly: true, autoClose: true
+ });
+ this.$router.push('/my/groups');
+ }
+ }
+});
+</script>
+
+<style lang="scss" scoped>
+.mk-group-page {
+ > .members {
+ > ._content {
+ max-height: 400px;
+ overflow: auto;
+
+ > .users {
+ > .user {
+ display: flex;
+ align-items: center;
+
+ > .avatar {
+ width: 50px;
+ height: 50px;
+ }
+
+ > .body {
+ flex: 1;
+ padding: 8px;
+
+ > .name {
+ display: block;
+ font-weight: bold;
+ }
+
+ > .acct {
+ opacity: 0.5;
+ }
+ }
+ }
+ }
+ }
+ }
+}
+</style>
diff --git a/src/client/pages/my-groups/index.vue b/src/client/pages/my-groups/index.vue
new file mode 100644
index 0000000000..733c481aa6
--- /dev/null
+++ b/src/client/pages/my-groups/index.vue
@@ -0,0 +1,99 @@
+<template>
+<div class="">
+ <portal to="icon"><fa :icon="faUsers"/></portal>
+ <portal to="title">{{ $t('groups') }}</portal>
+
+ <mk-button @click="create" primary style="margin: 0 auto var(--margin) auto;"><fa :icon="faPlus"/> {{ $t('createGroup') }}</mk-button>
+
+ <mk-container :body-togglable="true">
+ <template #header><fa :icon="faUsers"/> {{ $t('ownedGroups') }}</template>
+ <mk-pagination :pagination="ownedPagination" #default="{items}" ref="owned">
+ <div class="" v-for="group in items" :key="group.id">
+ <router-link :to="`/my/groups/${ group.id }`">{{ group.name }}</router-link>
+ </div>
+ </mk-pagination>
+ </mk-container>
+
+ <mk-container :body-togglable="true">
+ <template #header><fa :icon="faEnvelopeOpenText"/> {{ $t('invites') }}</template>
+ <mk-pagination :pagination="invitePagination" #default="{items}">
+ <div class="" v-for="invite in items" :key="invite.id">
+ <div class="name">{{ invite.group.name }}</div>
+ <x-avatars :user-ids="invite.group.userIds" style="margin-top:8px;"/>
+ <ui-horizon-group>
+ <ui-button @click="acceptInvite(invite)"><fa :icon="faCheck"/> {{ $t('accept') }}</ui-button>
+ <ui-button @click="rejectInvite(invite)"><fa :icon="faBan"/> {{ $t('reject') }}</ui-button>
+ </ui-horizon-group>
+ </div>
+ </mk-pagination>
+ </mk-container>
+
+ <mk-container :body-togglable="true">
+ <template #header><fa :icon="faUsers"/> {{ $t('joinedGroups') }}</template>
+ <mk-pagination :pagination="joinedPagination" #default="{items}">
+ <div class="" v-for="group in items" :key="group.id">
+ <div>{{ group.name }}</div>
+ </div>
+ </mk-pagination>
+ </mk-container>
+</div>
+</template>
+
+<script lang="ts">
+import Vue from 'vue';
+import { faUsers, faPlus, faEnvelopeOpenText } from '@fortawesome/free-solid-svg-icons';
+import MkPagination from '../../components/ui/pagination.vue';
+import MkButton from '../../components/ui/button.vue';
+import MkContainer from '../../components/ui/container.vue';
+
+export default Vue.extend({
+ metaInfo() {
+ return {
+ title: this.$t('groups') as string,
+ };
+ },
+
+ components: {
+ MkPagination,
+ MkButton,
+ MkContainer,
+ },
+
+ data() {
+ return {
+ ownedPagination: {
+ endpoint: 'users/groups/owned',
+ limit: 10,
+ },
+ joinedPagination: {
+ endpoint: 'users/groups/joined',
+ limit: 10,
+ },
+ invitePagination: {
+ endpoint: 'i/user-group-invites',
+ limit: 10,
+ },
+ faUsers, faPlus, faEnvelopeOpenText
+ };
+ },
+
+ methods: {
+ async create() {
+ const { canceled, result: name } = await this.$root.dialog({
+ title: this.$t('groupName'),
+ input: true
+ });
+ if (canceled) return;
+ await this.$root.api('users/groups/create', { name: name });
+ this.$refs.owned.reload();
+ this.$root.dialog({
+ type: 'success',
+ iconOnly: true, autoClose: true
+ });
+ },
+ }
+});
+</script>
+
+<style lang="scss" scoped>
+</style>
diff --git a/src/client/pages/my-lists/index.vue b/src/client/pages/my-lists/index.vue
index 505998209e..c3f6d9c774 100644
--- a/src/client/pages/my-lists/index.vue
+++ b/src/client/pages/my-lists/index.vue
@@ -62,7 +62,7 @@ export default Vue.extend({
<style lang="scss" scoped>
.qkcjvfiv {
> .add {
- margin: 0 auto 16px auto;
+ margin: 0 auto var(--margin) auto;
}
> .lists {
diff --git a/src/client/pages/my-lists/list.vue b/src/client/pages/my-lists/list.vue
index ded79b89c7..cf85a80ccb 100644
--- a/src/client/pages/my-lists/list.vue
+++ b/src/client/pages/my-lists/list.vue
@@ -1,11 +1,23 @@
<template>
<div class="mk-list-page">
+ <portal to="icon"><fa :icon="faListUl"/></portal>
+ <portal to="title">{{ list.name }}</portal>
+
<transition name="zoom" mode="out-in">
- <div v-if="list" :key="list.id" class="_card list">
- <div class="_title">{{ list.name }}</div>
+ <div v-if="list" class="_card">
+ <div class="_content">
+ <mk-button inline @click="renameList()">{{ $t('rename') }}</mk-button>
+ <mk-button inline @click="deleteList()">{{ $t('delete') }}</mk-button>
+ </div>
+ </div>
+ </transition>
+
+ <transition name="zoom" mode="out-in">
+ <div v-if="list" class="_card members">
+ <div class="_title">{{ $t('members') }}</div>
<div class="_content">
<div class="users">
- <div class="user" v-for="(user, i) in users" :key="user.id">
+ <div class="user" v-for="user in users" :key="user.id">
<mk-avatar :user="user" class="avatar"/>
<div class="body">
<mk-user-name :user="user" class="name"/>
@@ -18,8 +30,7 @@
</div>
</div>
<div class="_footer">
- <mk-button inline @click="renameList()">{{ $t('renameList') }}</mk-button>
- <mk-button inline @click="deleteList()">{{ $t('deleteList') }}</mk-button>
+ <mk-button inline @click="addUser()">{{ $t('addUser') }}</mk-button>
</div>
</div>
</transition>
@@ -28,10 +39,11 @@
<script lang="ts">
import Vue from 'vue';
-import { faTimes } from '@fortawesome/free-solid-svg-icons';
+import { faTimes, faListUl } from '@fortawesome/free-solid-svg-icons';
import i18n from '../../i18n';
import Progress from '../../scripts/loading';
import MkButton from '../../components/ui/button.vue';
+import MkUserSelect from '../../components/user-select.vue';
export default Vue.extend({
i18n,
@@ -50,7 +62,7 @@ export default Vue.extend({
return {
list: null,
users: [],
- faTimes
+ faTimes, faListUl
};
},
@@ -78,6 +90,26 @@ export default Vue.extend({
});
},
+ addUser() {
+ this.$root.new(MkUserSelect, {}).$once('selected', user => {
+ this.$root.api('users/lists/push', {
+ listId: this.list.id,
+ userId: user.id
+ }).then(() => {
+ this.users.push(user);
+ this.$root.dialog({
+ type: 'success',
+ iconOnly: true, autoClose: true
+ });
+ }).catch(e => {
+ this.$root.dialog({
+ type: 'error',
+ text: e
+ });
+ });
+ });
+ },
+
removeUser(user) {
this.$root.api('users/lists/pull', {
listId: this.list.id,
@@ -107,7 +139,7 @@ export default Vue.extend({
async deleteList() {
const { canceled } = await this.$root.dialog({
type: 'warning',
- text: this.$t('deleteListConfirm', { list: this.list.name }),
+ text: this.$t('removeAreYouSure', { x: this.list.name }),
showCancelButton: true
});
if (canceled) return;
@@ -127,7 +159,7 @@ export default Vue.extend({
<style lang="scss" scoped>
.mk-list-page {
- > .list {
+ > .members {
> ._content {
max-height: 400px;
overflow: auto;
diff --git a/src/client/router.ts b/src/client/router.ts
index f32673f432..949eb1ccbd 100644
--- a/src/client/router.ts
+++ b/src/client/router.ts
@@ -40,6 +40,8 @@ export const router = new VueRouter({
{ path: '/my/follow-requests', component: page('follow-requests') },
{ path: '/my/lists', component: page('my-lists/index') },
{ path: '/my/lists/:list', component: page('my-lists/list') },
+ { path: '/my/groups', component: page('my-groups/index') },
+ { path: '/my/groups/:group', component: page('my-groups/group') },
{ path: '/my/antennas', component: page('my-antennas/index') },
{ path: '/instance', component: page('instance/index') },
{ path: '/instance/emojis', component: page('instance/emojis') },