summaryrefslogtreecommitdiff
path: root/src/client/app/common/views/pages
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/app/common/views/pages')
-rw-r--r--src/client/app/common/views/pages/explore.vue4
-rw-r--r--src/client/app/common/views/pages/follow-requests.vue68
-rw-r--r--src/client/app/common/views/pages/pages.vue5
-rw-r--r--src/client/app/common/views/pages/user-group-editor.vue180
-rw-r--r--src/client/app/common/views/pages/user-groups.vue63
-rw-r--r--src/client/app/common/views/pages/user-list-editor.vue180
-rw-r--r--src/client/app/common/views/pages/user-lists.vue63
7 files changed, 563 insertions, 0 deletions
diff --git a/src/client/app/common/views/pages/explore.vue b/src/client/app/common/views/pages/explore.vue
index d0e98035f8..bf0d7ab574 100644
--- a/src/client/app/common/views/pages/explore.vue
+++ b/src/client/app/common/views/pages/explore.vue
@@ -116,6 +116,10 @@ export default Vue.extend({
},
created() {
+ this.$emit('init', {
+ title: this.$t('@.explore'),
+ icon: faHashtag
+ });
this.$root.api('hashtags/list', {
sort: '+attachedLocalUsers',
attachedToLocalUserOnly: true,
diff --git a/src/client/app/common/views/pages/follow-requests.vue b/src/client/app/common/views/pages/follow-requests.vue
new file mode 100644
index 0000000000..860efefd93
--- /dev/null
+++ b/src/client/app/common/views/pages/follow-requests.vue
@@ -0,0 +1,68 @@
+<template>
+<div>
+ <ui-container :body-togglable="true">
+ <template #header>{{ $t('received-follow-requests') }}</template>
+ <div v-if="!fetching">
+ <sequential-entrance animation="entranceFromTop" delay="25" tag="div" class="mcbzkkaw">
+ <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>
+ </sequential-entrance>
+ </div>
+ </ui-container>
+</div>
+</template>
+
+<script lang="ts">
+import Vue from 'vue';
+import i18n from '../../../i18n';
+import Progress from '../../scripts/loading';
+
+export default Vue.extend({
+ i18n: i18n('common/views/pages/follow-requests.vue'),
+ data() {
+ return {
+ fetching: true,
+ requests: []
+ };
+ },
+ mounted() {
+ 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>
+.mcbzkkaw
+ > div
+ display flex
+ padding 16px
+ border solid 1px var(--faceDivider)
+ border-radius 4px
+
+ > span
+ margin 0 0 0 auto
+
+</style>
diff --git a/src/client/app/common/views/pages/pages.vue b/src/client/app/common/views/pages/pages.vue
index 751ea72374..d658728a19 100644
--- a/src/client/app/common/views/pages/pages.vue
+++ b/src/client/app/common/views/pages/pages.vue
@@ -50,6 +50,11 @@ export default Vue.extend({
},
created() {
this.fetch();
+
+ this.$emit('init', {
+ title: this.$t('@.pages'),
+ icon: faStickyNote
+ });
},
methods: {
async fetch() {
diff --git a/src/client/app/common/views/pages/user-group-editor.vue b/src/client/app/common/views/pages/user-group-editor.vue
new file mode 100644
index 0000000000..c658d0c6ff
--- /dev/null
+++ b/src/client/app/common/views/pages/user-group-editor.vue
@@ -0,0 +1,180 @@
+<template>
+<div class="ivrbakop">
+ <ui-container v-if="group">
+ <template #header><fa :icon="faUsers"/> {{ group.name }}</template>
+
+ <section>
+ <ui-margin>
+ <ui-button @click="rename"><fa :icon="faICursor"/> {{ $t('rename') }}</ui-button>
+ <ui-button @click="del"><fa :icon="faTrashAlt"/> {{ $t('delete') }}</ui-button>
+ </ui-margin>
+ </section>
+ </ui-container>
+
+ <ui-container>
+ <template #header><fa :icon="faUsers"/> {{ $t('users') }}</template>
+
+ <section>
+ <ui-margin>
+ <ui-button @click="add"><fa :icon="faPlus"/> {{ $t('add-user') }}</ui-button>
+ </ui-margin>
+ <sequential-entrance animation="entranceFromTop" delay="25">
+ <div class="kjlrfbes" v-for="user in users">
+ <div>
+ <a :href="user | userPage">
+ <mk-avatar class="avatar" :user="user" :disable-link="true"/>
+ </a>
+ </div>
+ <div>
+ <header>
+ <b><mk-user-name :user="user"/></b>
+ <span class="username">@{{ user | acct }}</span>
+ </header>
+ <div>
+ <a @click="remove(user)">{{ $t('remove-user') }}</a>
+ </div>
+ </div>
+ </div>
+ </sequential-entrance>
+ </section>
+ </ui-container>
+</div>
+</template>
+
+<script lang="ts">
+import Vue from 'vue';
+import i18n from '../../../i18n';
+import { faICursor, faUsers, faPlus } from '@fortawesome/free-solid-svg-icons';
+import { faTrashAlt } from '@fortawesome/free-regular-svg-icons';
+
+export default Vue.extend({
+ i18n: i18n('common/views/components/user-group-editor.vue'),
+
+ props: {
+ groupId: {
+ required: true
+ }
+ },
+
+ data() {
+ return {
+ group: null,
+ users: [],
+ faICursor, faTrashAlt, faUsers, faPlus
+ };
+ },
+
+ created() {
+ this.$root.api('users/groups/show', {
+ groupId: this.groupId
+ }).then(group => {
+ this.group = group;
+ this.fetchUsers();
+ this.$emit('init', {
+ title: this.group.name,
+ icon: faUsers
+ });
+ });
+ },
+
+ methods: {
+ fetchUsers() {
+ this.$root.api('users/show', {
+ userIds: this.group.userIds
+ }).then(users => {
+ this.users = users;
+ });
+ },
+
+ rename() {
+ this.$root.dialog({
+ title: this.$t('rename'),
+ input: {
+ default: this.group.name
+ }
+ }).then(({ canceled, result: name }) => {
+ if (canceled) return;
+ this.$root.api('users/groups/update', {
+ groupId: this.group.id,
+ name: name
+ });
+ });
+ },
+
+ del() {
+ this.$root.dialog({
+ type: 'warning',
+ text: this.$t('delete-are-you-sure').replace('$1', this.group.name),
+ showCancelButton: true
+ }).then(({ canceled }) => {
+ if (canceled) return;
+
+ this.$root.api('users/groups/delete', {
+ groupId: this.group.id
+ }).then(() => {
+ this.$root.dialog({
+ type: 'success',
+ text: this.$t('deleted')
+ });
+ }).catch(e => {
+ this.$root.dialog({
+ type: 'error',
+ text: e
+ });
+ });
+ });
+ },
+
+ remove(user: any) {
+ this.$root.api('users/groups/pull', {
+ groupId: this.group.id,
+ userId: user.id
+ }).then(() => {
+ this.fetchUsers();
+ });
+ },
+
+ async add() {
+ const { result: user } = await this.$root.dialog({
+ user: {
+ local: true
+ }
+ });
+ if (user == null) return;
+ this.$root.api('users/groups/push', {
+ groupId: this.group.id,
+ userId: user.id
+ }).then(() => {
+ this.fetchUsers();
+ });
+ }
+ }
+});
+</script>
+
+<style lang="stylus" scoped>
+.ivrbakop
+ .kjlrfbes
+ display flex
+ padding 16px
+ border-top solid 1px var(--faceDivider)
+
+ > div:first-child
+ > a
+ > .avatar
+ width 64px
+ height 64px
+
+ > div:last-child
+ flex 1
+ padding-left 16px
+
+ @media (max-width 500px)
+ font-size 14px
+
+ > header
+ > .username
+ margin-left 8px
+ opacity 0.7
+
+</style>
diff --git a/src/client/app/common/views/pages/user-groups.vue b/src/client/app/common/views/pages/user-groups.vue
new file mode 100644
index 0000000000..336772799b
--- /dev/null
+++ b/src/client/app/common/views/pages/user-groups.vue
@@ -0,0 +1,63 @@
+<template>
+<ui-container>
+ <template #header><fa :icon="faUsers"/> {{ $t('user-groups') }}</template>
+ <ui-margin>
+ <ui-button @click="add"><fa :icon="faPlus"/> {{ $t('create-group') }}</ui-button>
+ </ui-margin>
+ <div class="hwgkdrbl" v-for="group in groups" :key="group.id">
+ <ui-hr/>
+ <ui-margin>
+ <router-link :to="`/i/groups/${group.id}`">{{ group.name }}</router-link>
+ </ui-margin>
+ </div>
+</ui-container>
+</template>
+
+<script lang="ts">
+import Vue from 'vue';
+import i18n from '../../../i18n';
+import { faUsers, faPlus } from '@fortawesome/free-solid-svg-icons';
+
+export default Vue.extend({
+ i18n: i18n('common/views/components/user-groups.vue'),
+ data() {
+ return {
+ fetching: true,
+ groups: [],
+ faUsers, faPlus
+ };
+ },
+ mounted() {
+ this.$root.api('users/groups/owned').then(groups => {
+ this.fetching = false;
+ this.groups = groups;
+ });
+
+ this.$emit('init', {
+ title: this.$t('user-groups'),
+ icon: faUsers
+ });
+ },
+ methods: {
+ add() {
+ this.$root.dialog({
+ title: this.$t('group-name'),
+ input: true
+ }).then(async ({ canceled, result: name }) => {
+ if (canceled) return;
+ const list = await this.$root.api('users/groups/create', {
+ name
+ });
+
+ this.groups.push(list)
+ });
+ },
+ }
+});
+</script>
+
+<style lang="stylus" scoped>
+.hwgkdrbl
+ display block
+
+</style>
diff --git a/src/client/app/common/views/pages/user-list-editor.vue b/src/client/app/common/views/pages/user-list-editor.vue
new file mode 100644
index 0000000000..6b2fd75f85
--- /dev/null
+++ b/src/client/app/common/views/pages/user-list-editor.vue
@@ -0,0 +1,180 @@
+<template>
+<div class="cudqjmnl">
+ <ui-container v-if="list">
+ <template #header><fa :icon="faListUl"/> {{ list.name }}</template>
+
+ <section class="fwvevrks">
+ <ui-margin>
+ <ui-button @click="rename"><fa :icon="faICursor"/> {{ $t('rename') }}</ui-button>
+ <ui-button @click="del"><fa :icon="faTrashAlt"/> {{ $t('delete') }}</ui-button>
+ </ui-margin>
+ </section>
+ </ui-container>
+
+ <ui-container>
+ <template #header><fa :icon="faUsers"/> {{ $t('users') }}</template>
+
+ <section>
+ <ui-margin>
+ <ui-button @click="add"><fa :icon="faPlus"/> {{ $t('add-user') }}</ui-button>
+ </ui-margin>
+ <sequential-entrance animation="entranceFromTop" delay="25">
+ <div class="phcqulfl" v-for="user in users">
+ <div>
+ <a :href="user | userPage">
+ <mk-avatar class="avatar" :user="user" :disable-link="true"/>
+ </a>
+ </div>
+ <div>
+ <header>
+ <b><mk-user-name :user="user"/></b>
+ <span class="username">@{{ user | acct }}</span>
+ </header>
+ <div>
+ <a @click="remove(user)">{{ $t('remove-user') }}</a>
+ </div>
+ </div>
+ </div>
+ </sequential-entrance>
+ </section>
+ </ui-container>
+</div>
+</template>
+
+<script lang="ts">
+import Vue from 'vue';
+import i18n from '../../../i18n';
+import { faListUl, faICursor, faUsers, faPlus } from '@fortawesome/free-solid-svg-icons';
+import { faTrashAlt } from '@fortawesome/free-regular-svg-icons';
+
+export default Vue.extend({
+ i18n: i18n('common/views/components/user-list-editor.vue'),
+
+ props: {
+ listId: {
+ required: true
+ }
+ },
+
+ data() {
+ return {
+ list: null,
+ users: [],
+ faListUl, faICursor, faTrashAlt, faUsers, faPlus
+ };
+ },
+
+ created() {
+ this.$root.api('users/lists/show', {
+ listId: this.listId
+ }).then(list => {
+ this.list = list;
+ this.fetchUsers();
+ this.$emit('init', {
+ title: this.list.name,
+ icon: faListUl
+ });
+ });
+ },
+
+ methods: {
+ fetchUsers() {
+ this.$root.api('users/show', {
+ userIds: this.list.userIds
+ }).then(users => {
+ this.users = users;
+ });
+ },
+
+ rename() {
+ this.$root.dialog({
+ title: this.$t('rename'),
+ input: {
+ default: this.list.name
+ }
+ }).then(({ canceled, result: name }) => {
+ if (canceled) return;
+ this.$root.api('users/lists/update', {
+ listId: this.list.id,
+ name: name
+ });
+ });
+ },
+
+ del() {
+ this.$root.dialog({
+ type: 'warning',
+ text: this.$t('delete-are-you-sure').replace('$1', this.list.name),
+ showCancelButton: true
+ }).then(({ canceled }) => {
+ if (canceled) return;
+
+ this.$root.api('users/lists/delete', {
+ listId: this.list.id
+ }).then(() => {
+ this.$root.dialog({
+ type: 'success',
+ text: this.$t('deleted')
+ });
+ }).catch(e => {
+ this.$root.dialog({
+ type: 'error',
+ text: e
+ });
+ });
+ });
+ },
+
+ remove(user: any) {
+ this.$root.api('users/lists/pull', {
+ listId: this.list.id,
+ userId: user.id
+ }).then(() => {
+ this.fetchUsers();
+ });
+ },
+
+ async add() {
+ const { result: user } = await this.$root.dialog({
+ user: {
+ local: true
+ }
+ });
+ if (user == null) return;
+ this.$root.api('users/lists/push', {
+ listId: this.list.id,
+ userId: user.id
+ }).then(() => {
+ this.fetchUsers();
+ });
+ }
+ }
+});
+</script>
+
+<style lang="stylus" scoped>
+.cudqjmnl
+ .phcqulfl
+ display flex
+ padding 16px
+ border-top solid 1px var(--faceDivider)
+
+ > div:first-child
+ > a
+ > .avatar
+ width 64px
+ height 64px
+
+ > div:last-child
+ flex 1
+ padding-left 16px
+
+ @media (max-width 500px)
+ font-size 14px
+
+ > header
+ > .username
+ margin-left 8px
+ opacity 0.7
+
+</style>
diff --git a/src/client/app/common/views/pages/user-lists.vue b/src/client/app/common/views/pages/user-lists.vue
new file mode 100644
index 0000000000..4c09eca6ce
--- /dev/null
+++ b/src/client/app/common/views/pages/user-lists.vue
@@ -0,0 +1,63 @@
+<template>
+<ui-container>
+ <template #header><fa :icon="faListUl"/> {{ $t('user-lists') }}</template>
+ <ui-margin>
+ <ui-button @click="add"><fa :icon="faPlus"/> {{ $t('create-list') }}</ui-button>
+ </ui-margin>
+ <div class="cpqqyrst" v-for="list in lists" :key="list.id">
+ <ui-hr/>
+ <ui-margin>
+ <router-link :to="`/i/lists/${list.id}`">{{ list.name }}</router-link>
+ </ui-margin>
+ </div>
+</ui-container>
+</template>
+
+<script lang="ts">
+import Vue from 'vue';
+import i18n from '../../../i18n';
+import { faListUl, faPlus } from '@fortawesome/free-solid-svg-icons';
+
+export default Vue.extend({
+ i18n: i18n('common/views/components/user-lists.vue'),
+ data() {
+ return {
+ fetching: true,
+ lists: [],
+ faListUl, faPlus
+ };
+ },
+ mounted() {
+ this.$root.api('users/lists/list').then(lists => {
+ this.fetching = false;
+ this.lists = lists;
+ });
+
+ this.$emit('init', {
+ title: this.$t('user-lists'),
+ icon: faListUl
+ });
+ },
+ methods: {
+ add() {
+ this.$root.dialog({
+ title: this.$t('list-name'),
+ input: true
+ }).then(async ({ canceled, result: name }) => {
+ if (canceled) return;
+ const list = await this.$root.api('users/lists/create', {
+ name
+ });
+
+ this.lists.push(list)
+ });
+ },
+ }
+});
+</script>
+
+<style lang="stylus" scoped>
+.cpqqyrst
+ display block
+
+</style>