@ -18,6 +18,7 @@
|
||||
<fa icon="spinner" pulse v-if="type === 'waiting'"/>
|
||||
</div>
|
||||
<header v-if="title" v-html="title"></header>
|
||||
<header v-if="title == null && user">{{ $t('@.enter-username') }}</header>
|
||||
<div class="body" v-if="text" v-html="text"></div>
|
||||
<ui-input v-if="input" v-model="inputValue" autofocus :type="input.type || 'text'" :placeholder="input.placeholder" @keydown="onInputKeydown"></ui-input>
|
||||
<ui-input v-if="user" v-model="userInputValue" autofocus @keydown="onInputKeydown"><template #prefix>@</template></ui-input>
|
||||
|
@ -44,6 +44,8 @@ import uiSwitch from './ui/switch.vue';
|
||||
import uiRadio from './ui/radio.vue';
|
||||
import uiSelect from './ui/select.vue';
|
||||
import uiInfo from './ui/info.vue';
|
||||
import uiMargin from './ui/margin.vue';
|
||||
import uiHr from './ui/hr.vue';
|
||||
import formButton from './ui/form/button.vue';
|
||||
import formRadio from './ui/form/radio.vue';
|
||||
|
||||
@ -91,5 +93,7 @@ Vue.component('ui-switch', uiSwitch);
|
||||
Vue.component('ui-radio', uiRadio);
|
||||
Vue.component('ui-select', uiSelect);
|
||||
Vue.component('ui-info', uiInfo);
|
||||
Vue.component('ui-margin', uiMargin);
|
||||
Vue.component('ui-hr', uiHr);
|
||||
Vue.component('form-button', formButton);
|
||||
Vue.component('form-radio', formRadio);
|
||||
|
@ -33,7 +33,16 @@ import * as autosize from 'autosize';
|
||||
|
||||
export default Vue.extend({
|
||||
i18n: i18n('common/views/components/messaging-room.form.vue'),
|
||||
props: ['user'],
|
||||
props: {
|
||||
user: {
|
||||
type: Object,
|
||||
requird: false,
|
||||
},
|
||||
group: {
|
||||
type: Object,
|
||||
requird: false,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
text: null,
|
||||
@ -43,7 +52,7 @@ export default Vue.extend({
|
||||
},
|
||||
computed: {
|
||||
draftId(): string {
|
||||
return this.user.id;
|
||||
return this.user ? 'user:' + this.user.id : 'group:' + this.group.id;
|
||||
},
|
||||
canSend(): boolean {
|
||||
return (this.text != null && this.text != '') || this.file != null;
|
||||
@ -159,7 +168,8 @@ export default Vue.extend({
|
||||
send() {
|
||||
this.sending = true;
|
||||
this.$root.api('messaging/messages/create', {
|
||||
userId: this.user.id,
|
||||
userId: this.user ? this.user.id : undefined,
|
||||
groupId: this.group ? this.group.id : undefined,
|
||||
text: this.text ? this.text : undefined,
|
||||
fileId: this.file ? this.file.id : undefined
|
||||
}).then(message => {
|
||||
|
@ -23,7 +23,12 @@
|
||||
<div></div>
|
||||
<mk-url-preview v-for="url in urls" :url="url" :key="url"/>
|
||||
<footer>
|
||||
<span class="read" v-if="isMe && message.isRead">{{ $t('is-read') }}</span>
|
||||
<template v-if="isGroup">
|
||||
<span class="read" v-if="message.reads.length > 0">{{ $t('is-read') }} {{ message.reads.length }}</span>
|
||||
</template>
|
||||
<template v-else>
|
||||
<span class="read" v-if="isMe && message.isRead">{{ $t('is-read') }}</span>
|
||||
</template>
|
||||
<mk-time :time="message.createdAt"/>
|
||||
<template v-if="message.is_edited"><fa icon="pencil-alt"/></template>
|
||||
</footer>
|
||||
@ -42,6 +47,9 @@ export default Vue.extend({
|
||||
props: {
|
||||
message: {
|
||||
required: true
|
||||
},
|
||||
isGroup: {
|
||||
required: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
@ -4,14 +4,14 @@
|
||||
@drop.prevent.stop="onDrop"
|
||||
>
|
||||
<div class="body">
|
||||
<p class="init" v-if="init"><fa icon="spinner .spin"/>{{ $t('@.loading') }}</p>
|
||||
<p class="empty" v-if="!init && messages.length == 0"><fa icon="info-circle"/>{{ $t('empty') }}</p>
|
||||
<p class="init" v-if="init"><fa icon="spinner" pulse fixed-width/>{{ $t('@.loading') }}</p>
|
||||
<p class="empty" v-if="!init && messages.length == 0"><fa icon="info-circle"/>{{ user ? $t('not-talked-user') : $t('not-talked-group') }}</p>
|
||||
<p class="no-history" v-if="!init && messages.length > 0 && !existMoreMessages"><fa :icon="faFlag"/>{{ $t('no-history') }}</p>
|
||||
<button class="more" :class="{ fetching: fetchingMoreMessages }" v-if="existMoreMessages" @click="fetchMoreMessages" :disabled="fetchingMoreMessages">
|
||||
<template v-if="fetchingMoreMessages"><fa icon="spinner" pulse fixed-width/></template>{{ fetchingMoreMessages ? $t('@.loading') : $t('@.load-more') }}
|
||||
</button>
|
||||
<template v-for="(message, i) in _messages">
|
||||
<x-message :message="message" :key="message.id"/>
|
||||
<x-message :message="message" :key="message.id" :is-group="group != null"/>
|
||||
<p class="date" v-if="i != messages.length - 1 && message._date != _messages[i + 1]._date">
|
||||
<span>{{ _messages[i + 1]._datetext }}</span>
|
||||
</p>
|
||||
@ -23,7 +23,7 @@
|
||||
<button @click="onIndicatorClick"><i><fa :icon="faArrowCircleDown"/></i>{{ $t('new-message') }}</button>
|
||||
</div>
|
||||
</transition>
|
||||
<x-form :user="user" ref="form"/>
|
||||
<x-form :user="user" :group="group" ref="form"/>
|
||||
</footer>
|
||||
</div>
|
||||
</template>
|
||||
@ -34,17 +34,30 @@ import i18n from '../../../i18n';
|
||||
import XMessage from './messaging-room.message.vue';
|
||||
import XForm from './messaging-room.form.vue';
|
||||
import { url } from '../../../config';
|
||||
import { faArrowCircleDown } from '@fortawesome/free-solid-svg-icons';
|
||||
import { faFlag } from '@fortawesome/free-regular-svg-icons';
|
||||
import { faArrowCircleDown, faFlag } from '@fortawesome/free-solid-svg-icons';
|
||||
|
||||
export default Vue.extend({
|
||||
i18n: i18n('common/views/components/messaging-room.vue'),
|
||||
|
||||
components: {
|
||||
XMessage,
|
||||
XForm
|
||||
},
|
||||
|
||||
props: ['user', 'isNaked'],
|
||||
props: {
|
||||
user: {
|
||||
type: Object,
|
||||
requird: false,
|
||||
},
|
||||
group: {
|
||||
type: Object,
|
||||
requird: false,
|
||||
},
|
||||
isNaked: {
|
||||
type: Boolean,
|
||||
requird: false,
|
||||
},
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
@ -76,7 +89,10 @@ export default Vue.extend({
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.connection = this.$root.stream.connectToChannel('messaging', { otherparty: this.user.id });
|
||||
this.connection = this.$root.stream.connectToChannel('messaging', {
|
||||
otherparty: this.user ? this.user.id : undefined,
|
||||
group: this.group ? this.group.id : undefined,
|
||||
});
|
||||
|
||||
this.connection.on('message', this.onMessage);
|
||||
this.connection.on('read', this.onRead);
|
||||
@ -147,7 +163,8 @@ export default Vue.extend({
|
||||
const max = this.existMoreMessages ? 20 : 10;
|
||||
|
||||
this.$root.api('messaging/messages', {
|
||||
userId: this.user.id,
|
||||
userId: this.user ? this.user.id : undefined,
|
||||
groupId: this.group ? this.group.id : undefined,
|
||||
limit: max + 1,
|
||||
untilId: this.existMoreMessages ? this.messages[0].id : undefined
|
||||
}).then(messages => {
|
||||
@ -199,12 +216,21 @@ export default Vue.extend({
|
||||
}
|
||||
},
|
||||
|
||||
onRead(ids) {
|
||||
if (!Array.isArray(ids)) ids = [ids];
|
||||
for (const id of ids) {
|
||||
if (this.messages.some(x => x.id == id)) {
|
||||
const exist = this.messages.map(x => x.id).indexOf(id);
|
||||
this.messages[exist].isRead = true;
|
||||
onRead(x) {
|
||||
if (this.user) {
|
||||
if (!Array.isArray(x)) x = [x];
|
||||
for (const id of x) {
|
||||
if (this.messages.some(x => x.id == id)) {
|
||||
const exist = this.messages.map(x => x.id).indexOf(id);
|
||||
this.messages[exist].isRead = true;
|
||||
}
|
||||
}
|
||||
} else if (this.group) {
|
||||
for (const id of x.ids) {
|
||||
if (this.messages.some(x => x.id == id)) {
|
||||
const exist = this.messages.map(x => x.id).indexOf(id);
|
||||
this.messages[exist].reads.push(x.userId);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -21,36 +21,62 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="history" v-if="messages.length > 0">
|
||||
<template>
|
||||
<a v-for="message in messages"
|
||||
class="user"
|
||||
:href="`/i/messaging/${getAcct(isMe(message) ? message.recipient : message.user)}`"
|
||||
:data-is-me="isMe(message)"
|
||||
:data-is-read="message.isRead"
|
||||
@click.prevent="navigate(isMe(message) ? message.recipient : message.user)"
|
||||
:key="message.id"
|
||||
>
|
||||
<div>
|
||||
<mk-avatar class="avatar" :user="isMe(message) ? message.recipient : message.user"/>
|
||||
<header>
|
||||
<span class="name"><mk-user-name :user="isMe(message) ? message.recipient : message.user"/></span>
|
||||
<span class="username">@{{ isMe(message) ? message.recipient : message.user | acct }}</span>
|
||||
<mk-time :time="message.createdAt"/>
|
||||
</header>
|
||||
<div class="body">
|
||||
<p class="text"><span class="me" v-if="isMe(message)">{{ $t('you') }}:</span>{{ message.text }}</p>
|
||||
</div>
|
||||
<div class="title">{{ $t('user') }}</div>
|
||||
<a v-for="message in messages"
|
||||
class="user"
|
||||
:href="`/i/messaging/${getAcct(isMe(message) ? message.recipient : message.user)}`"
|
||||
:data-is-me="isMe(message)"
|
||||
:data-is-read="message.isRead"
|
||||
@click.prevent="navigate(isMe(message) ? message.recipient : message.user)"
|
||||
:key="message.id"
|
||||
>
|
||||
<div>
|
||||
<mk-avatar class="avatar" :user="isMe(message) ? message.recipient : message.user"/>
|
||||
<header>
|
||||
<span class="name"><mk-user-name :user="isMe(message) ? message.recipient : message.user"/></span>
|
||||
<span class="username">@{{ isMe(message) ? message.recipient : message.user | acct }}</span>
|
||||
<mk-time :time="message.createdAt"/>
|
||||
</header>
|
||||
<div class="body">
|
||||
<p class="text"><span class="me" v-if="isMe(message)">{{ $t('you') }}:</span>{{ message.text }}</p>
|
||||
</div>
|
||||
</a>
|
||||
</template>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<p class="no-history" v-if="!fetching && messages.length == 0">{{ $t('no-history') }}</p>
|
||||
<div class="history" v-if="groupMessages.length > 0">
|
||||
<div class="title">{{ $t('group') }}</div>
|
||||
<a v-for="message in groupMessages"
|
||||
class="user"
|
||||
:href="`/i/messaging/group/${message.groupId}`"
|
||||
:data-is-me="isMe(message)"
|
||||
:data-is-read="message.reads.includes($store.state.i.id)"
|
||||
@click.prevent="navigateGroup(message.group)"
|
||||
:key="message.id"
|
||||
>
|
||||
<div>
|
||||
<mk-avatar class="avatar" :user="message.user"/>
|
||||
<header>
|
||||
<span class="name">{{ message.group.name }}</span>
|
||||
<mk-time :time="message.createdAt"/>
|
||||
</header>
|
||||
<div class="body">
|
||||
<p class="text"><span class="me" v-if="isMe(message)">{{ $t('you') }}:</span>{{ message.text }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<p class="no-history" v-if="!fetching && (messages.length == 0 && groupMessages.length == 0)">{{ $t('no-history') }}</p>
|
||||
<p class="fetching" v-if="fetching"><fa icon="spinner" pulse fixed-width/>{{ $t('@.loading') }}<mk-ellipsis/></p>
|
||||
<ui-margin>
|
||||
<ui-button @click="startUser()"><fa :icon="faUser"/> {{ $t('start-with-user') }}</ui-button>
|
||||
<ui-button @click="startGroup()"><fa :icon="faUsers"/> {{ $t('start-with-group') }}</ui-button>
|
||||
</ui-margin>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import { faUser, faUsers } from '@fortawesome/free-solid-svg-icons';
|
||||
import i18n from '../../../i18n';
|
||||
import getAcct from '../../../../../misc/acct/render';
|
||||
|
||||
@ -71,9 +97,11 @@ export default Vue.extend({
|
||||
fetching: true,
|
||||
moreFetching: false,
|
||||
messages: [],
|
||||
groupMessages: [],
|
||||
q: null,
|
||||
result: [],
|
||||
connection: null
|
||||
connection: null,
|
||||
faUser, faUsers
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
@ -82,9 +110,12 @@ export default Vue.extend({
|
||||
this.connection.on('message', this.onMessage);
|
||||
this.connection.on('read', this.onRead);
|
||||
|
||||
this.$root.api('messaging/history').then(messages => {
|
||||
this.messages = messages;
|
||||
this.fetching = false;
|
||||
this.$root.api('messaging/history', { group: false }).then(messages => {
|
||||
this.$root.api('messaging/history', { group: true }).then(groupMessages => {
|
||||
this.messages = messages;
|
||||
this.groupMessages = groupMessages;
|
||||
this.fetching = false;
|
||||
});
|
||||
});
|
||||
},
|
||||
beforeDestroy() {
|
||||
@ -96,16 +127,27 @@ export default Vue.extend({
|
||||
return message.userId == this.$store.state.i.id;
|
||||
},
|
||||
onMessage(message) {
|
||||
this.messages = this.messages.filter(m => !(
|
||||
(m.recipientId == message.recipientId && m.userId == message.userId) ||
|
||||
(m.recipientId == message.userId && m.userId == message.recipientId)));
|
||||
if (message.recipientId) {
|
||||
this.messages = this.messages.filter(m => !(
|
||||
(m.recipientId == message.recipientId && m.userId == message.userId) ||
|
||||
(m.recipientId == message.userId && m.userId == message.recipientId)));
|
||||
|
||||
this.messages.unshift(message);
|
||||
this.messages.unshift(message);
|
||||
} else if (message.groupId) {
|
||||
this.groupMessages = this.groupMessages.filter(m => m.groupId !== message.groupId);
|
||||
this.groupMessages.unshift(message);
|
||||
}
|
||||
},
|
||||
onRead(ids) {
|
||||
for (const id of ids) {
|
||||
const found = this.messages.find(m => m.id == id);
|
||||
if (found) found.isRead = true;
|
||||
if (found) {
|
||||
if (found.recipientId) {
|
||||
found.isRead = true;
|
||||
} else if (found.groupId) {
|
||||
found.reads.push(this.$store.state.i.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
search() {
|
||||
@ -125,6 +167,9 @@ export default Vue.extend({
|
||||
navigate(user) {
|
||||
this.$emit('navigate', user);
|
||||
},
|
||||
navigateGroup(group) {
|
||||
this.$emit('navigateGroup', group);
|
||||
},
|
||||
onSearchKeydown(e) {
|
||||
switch (e.which) {
|
||||
case 9: // [TAB]
|
||||
@ -161,6 +206,30 @@ export default Vue.extend({
|
||||
(list.childNodes[i].nextElementSibling || list.childNodes[0]).focus();
|
||||
break;
|
||||
}
|
||||
},
|
||||
async startUser() {
|
||||
const { result: user } = await this.$root.dialog({
|
||||
user: {
|
||||
local: true
|
||||
}
|
||||
});
|
||||
if (user == null) return;
|
||||
this.navigate(user);
|
||||
},
|
||||
async startGroup() {
|
||||
const groups = await this.$root.api('users/groups/joined');
|
||||
const { canceled, result: group } = await this.$root.dialog({
|
||||
type: null,
|
||||
title: this.$t('select-group'),
|
||||
select: {
|
||||
items: groups.map(group => ({
|
||||
value: group, text: group.name
|
||||
}))
|
||||
},
|
||||
showCancelButton: true
|
||||
});
|
||||
if (canceled) return;
|
||||
this.navigateGroup(group);
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -173,6 +242,9 @@ export default Vue.extend({
|
||||
font-size 0.8em
|
||||
|
||||
> .history
|
||||
> .title
|
||||
padding 8px
|
||||
|
||||
> a
|
||||
&:last-child
|
||||
border-bottom none
|
||||
@ -311,6 +383,13 @@ export default Vue.extend({
|
||||
color rgba(#000, 0.3)
|
||||
|
||||
> .history
|
||||
> .title
|
||||
padding 6px 16px
|
||||
margin 0 auto
|
||||
max-width 500px
|
||||
background rgba(0, 0, 0, 0.05)
|
||||
color var(--text)
|
||||
font-size 85%
|
||||
|
||||
> a
|
||||
display block
|
||||
|
15
src/client/app/common/views/components/ui/hr.vue
Normal file
15
src/client/app/common/views/components/ui/hr.vue
Normal file
@ -0,0 +1,15 @@
|
||||
<template>
|
||||
<div class="evrzpitu"></div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
export default Vue.extend({});
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.evrzpitu
|
||||
margin 16px 0
|
||||
border-bottom solid var(--lineWidth) var(--faceDivider)
|
||||
|
||||
</style>
|
16
src/client/app/common/views/components/ui/margin.vue
Normal file
16
src/client/app/common/views/components/ui/margin.vue
Normal file
@ -0,0 +1,16 @@
|
||||
<template>
|
||||
<div class="zdcrxcne">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
export default Vue.extend({});
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.zdcrxcne
|
||||
margin 16px
|
||||
|
||||
</style>
|
@ -1,95 +0,0 @@
|
||||
<template>
|
||||
<div class="xkxvokkjlptzyewouewmceqcxhpgzprp">
|
||||
<button class="ui" @click="add">{{ $t('create-list') }}</button>
|
||||
<a v-for="list in lists" :key="list.id" @click="choice(list)">{{ list.name }}</a>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import i18n from '../../../i18n';
|
||||
|
||||
export default Vue.extend({
|
||||
i18n: i18n('common/views/components/user-lists.vue'),
|
||||
data() {
|
||||
return {
|
||||
fetching: true,
|
||||
lists: []
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.$root.api('users/lists/list').then(lists => {
|
||||
this.fetching = false;
|
||||
this.lists = lists;
|
||||
});
|
||||
},
|
||||
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)
|
||||
this.$emit('choosen', list);
|
||||
});
|
||||
},
|
||||
choice(list) {
|
||||
this.$emit('choosen', list);
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.xkxvokkjlptzyewouewmceqcxhpgzprp
|
||||
padding 16px
|
||||
background: var(--bg)
|
||||
|
||||
> button
|
||||
display block
|
||||
margin-bottom 16px
|
||||
color var(--primaryForeground)
|
||||
background var(--primary)
|
||||
width 100%
|
||||
border-radius 38px
|
||||
user-select none
|
||||
cursor pointer
|
||||
padding 0 16px
|
||||
min-width 100px
|
||||
line-height 38px
|
||||
font-size 14px
|
||||
font-weight 700
|
||||
|
||||
&:hover
|
||||
background var(--primaryLighten10)
|
||||
|
||||
&:active
|
||||
background var(--primaryDarken10)
|
||||
|
||||
a
|
||||
display block
|
||||
margin 8px 0
|
||||
padding 8px
|
||||
color var(--text)
|
||||
background var(--face)
|
||||
box-shadow 0 2px 16px var(--reversiListItemShadow)
|
||||
border-radius 6px
|
||||
cursor pointer
|
||||
line-height 32px
|
||||
|
||||
*
|
||||
pointer-events none
|
||||
user-select none
|
||||
|
||||
&:hover
|
||||
box-shadow 0 0 0 100px inset rgba(0, 0, 0, 0.05)
|
||||
|
||||
&:active
|
||||
box-shadow 0 0 0 100px inset rgba(0, 0, 0, 0.1)
|
||||
|
||||
</style>
|
@ -27,7 +27,7 @@ export default Vue.extend({
|
||||
text: this.$t('push-to-list'),
|
||||
action: this.pushList
|
||||
}] as any;
|
||||
|
||||
|
||||
if (this.$store.getters.isSignedIn && this.$store.state.i.id != this.user.id) {
|
||||
menu = menu.concat([null, {
|
||||
icon: this.user.isMuted ? ['fas', 'eye'] : ['far', 'eye-slash'],
|
||||
|
@ -1,34 +1,45 @@
|
||||
<template>
|
||||
<x-column>
|
||||
<template #header>
|
||||
<fa :icon="faHashtag"/>{{ $t('@.explore') }}
|
||||
<fa :icon="icon"/>{{ title }}
|
||||
</template>
|
||||
|
||||
<div>
|
||||
<x-explore v-bind="$attrs"/>
|
||||
<component :is="component" @init="init" v-bind="$attrs"/>
|
||||
</div>
|
||||
</x-column>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import i18n from '../../../i18n';
|
||||
import XColumn from './deck.column.vue';
|
||||
import XExplore from '../../../common/views/pages/explore.vue';
|
||||
import { faHashtag } from '@fortawesome/free-solid-svg-icons';
|
||||
|
||||
export default Vue.extend({
|
||||
i18n: i18n(),
|
||||
|
||||
components: {
|
||||
XColumn,
|
||||
XExplore,
|
||||
},
|
||||
|
||||
props: {
|
||||
component: {
|
||||
required: true
|
||||
}
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
faHashtag
|
||||
title: null,
|
||||
icon: null,
|
||||
};
|
||||
},
|
||||
|
||||
mounted() {
|
||||
},
|
||||
|
||||
methods: {
|
||||
init(v) {
|
||||
this.title = v.title;
|
||||
this.icon = v.icon;
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
@ -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,
|
||||
|
@ -1,27 +1,30 @@
|
||||
<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>
|
||||
<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>
|
||||
</main>
|
||||
</mk-ui>
|
||||
</ui-container>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import i18n from '../../../i18n';
|
||||
import Progress from '../../../common/scripts/loading';
|
||||
import Progress from '../../scripts/loading';
|
||||
|
||||
export default Vue.extend({
|
||||
i18n: i18n('mobile/views/pages/received-follow-requests.vue'),
|
||||
i18n: i18n('common/views/pages/follow-requests.vue'),
|
||||
data() {
|
||||
return {
|
||||
fetching: true,
|
||||
@ -29,14 +32,10 @@ export default Vue.extend({
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
document.title = this.$t('title');
|
||||
|
||||
Progress.start();
|
||||
|
||||
this.$root.api('following/requests/list').then(requests => {
|
||||
this.fetching = false;
|
||||
this.requests = requests;
|
||||
|
||||
Progress.done();
|
||||
});
|
||||
},
|
||||
@ -56,7 +55,7 @@ export default Vue.extend({
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
main
|
||||
.mcbzkkaw
|
||||
> div
|
||||
display flex
|
||||
padding 16px
|
@ -50,6 +50,11 @@ export default Vue.extend({
|
||||
},
|
||||
created() {
|
||||
this.fetch();
|
||||
|
||||
this.$emit('init', {
|
||||
title: this.$t('@.pages'),
|
||||
icon: faStickyNote
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
async fetch() {
|
||||
|
180
src/client/app/common/views/pages/user-group-editor.vue
Normal file
180
src/client/app/common/views/pages/user-group-editor.vue
Normal file
@ -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>
|
63
src/client/app/common/views/pages/user-groups.vue
Normal file
63
src/client/app/common/views/pages/user-groups.vue
Normal file
@ -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>
|
@ -1,18 +1,23 @@
|
||||
<template>
|
||||
<div class="cudqjmnl">
|
||||
<ui-card>
|
||||
<template #title><fa :icon="faList"/> {{ list.name }}</template>
|
||||
<ui-container v-if="list">
|
||||
<template #header><fa :icon="faListUl"/> {{ list.name }}</template>
|
||||
|
||||
<section>
|
||||
<ui-button @click="rename"><fa :icon="faICursor"/> {{ $t('rename') }}</ui-button>
|
||||
<ui-button @click="del"><fa :icon="faTrashAlt"/> {{ $t('delete') }}</ui-button>
|
||||
<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-card>
|
||||
</ui-container>
|
||||
|
||||
<ui-card>
|
||||
<template #title><fa :icon="faUsers"/> {{ $t('users') }}</template>
|
||||
<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>
|
||||
@ -32,34 +37,44 @@
|
||||
</div>
|
||||
</sequential-entrance>
|
||||
</section>
|
||||
</ui-card>
|
||||
</ui-container>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import i18n from '../../../i18n';
|
||||
import { faList, faICursor, faUsers } from '@fortawesome/free-solid-svg-icons';
|
||||
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: {
|
||||
list: {
|
||||
listId: {
|
||||
required: true
|
||||
}
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
list: null,
|
||||
users: [],
|
||||
faList, faICursor, faTrashAlt, faUsers
|
||||
faListUl, faICursor, faTrashAlt, faUsers, faPlus
|
||||
};
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.fetchUsers();
|
||||
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: {
|
||||
@ -117,6 +132,21 @@ export default Vue.extend({
|
||||
}).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();
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -126,7 +156,7 @@ export default Vue.extend({
|
||||
.cudqjmnl
|
||||
.phcqulfl
|
||||
display flex
|
||||
padding 16px 0
|
||||
padding 16px
|
||||
border-top solid 1px var(--faceDivider)
|
||||
|
||||
> div:first-child
|
63
src/client/app/common/views/pages/user-lists.vue
Normal file
63
src/client/app/common/views/pages/user-lists.vue
Normal file
@ -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>
|
@ -22,6 +22,7 @@ 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 MkSettings from './views/pages/settings.vue';
|
||||
import DeckColumn from '../common/views/deck/deck.column-template.vue';
|
||||
|
||||
import Ctx from './views/components/context-menu.vue';
|
||||
import PostFormWindow from './views/components/post-form-window.vue';
|
||||
@ -138,9 +139,14 @@ init(async (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: '/', component: MkHome, children: [
|
||||
{ path: '', name: 'index', component: MkHomeTimeline },
|
||||
@ -157,11 +163,17 @@ init(async (launch, os) => {
|
||||
{ path: '/explore/tags/:tag', name: 'explore-tag', props: true, component: () => import('../common/views/pages/explore.vue').then(m => m.default) },
|
||||
{ path: '/i/favorites', component: () => import('./views/home/favorites.vue').then(m => m.default) },
|
||||
{ path: '/i/pages', component: () => import('../common/views/pages/pages.vue').then(m => m.default) },
|
||||
{ path: '/i/lists', component: () => import('../common/views/pages/user-lists.vue').then(m => m.default) },
|
||||
{ path: '/i/lists/:listId', props: true, component: () => import('../common/views/pages/user-list-editor.vue').then(m => m.default) },
|
||||
{ path: '/i/groups', component: () => import('../common/views/pages/user-groups.vue').then(m => m.default) },
|
||||
{ path: '/i/groups/:groupId', props: true, component: () => import('../common/views/pages/user-group-editor.vue').then(m => m.default) },
|
||||
{ path: '/i/follow-requests', component: () => import('../common/views/pages/follow-requests.vue').then(m => m.default) },
|
||||
]},
|
||||
{ path: '/@:user/pages/:page', props: true, component: () => import('./views/pages/page.vue').then(m => m.default) },
|
||||
{ path: '/@:user/pages/:pageName/view-source', props: true, component: () => import('./views/pages/page-editor.vue').then(m => m.default) },
|
||||
{ path: '/i/pages/new', component: () => import('./views/pages/page-editor.vue').then(m => m.default) },
|
||||
{ path: '/i/pages/edit/:pageId', props: true, component: () => import('./views/pages/page-editor.vue').then(m => m.default) },
|
||||
{ path: '/i/messaging/group/:group', component: MkMessagingRoom },
|
||||
{ path: '/i/messaging/:user', component: MkMessagingRoom },
|
||||
{ path: '/i/drive', component: MkDrive },
|
||||
{ path: '/i/drive/folder/:folder', component: MkDrive },
|
||||
|
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<mk-window ref="window" width="500px" height="560px" :popout-url="popout" @closed="destroyDom">
|
||||
<template #header><fa icon="comments"/> {{ $t('@.messaging') }}: <mk-user-name :user="user"/></template>
|
||||
<x-messaging-room :user="user" :class="$style.content"/>
|
||||
<template #header><fa icon="comments"/> {{ $t('@.messaging') }}: <mk-user-name v-if="user" :user="user"/><span v-else>{{ group.name }}</span></template>
|
||||
<x-messaging-room :user="user" :group="group" :class="$style.content"/>
|
||||
</mk-window>
|
||||
</template>
|
||||
|
||||
@ -16,10 +16,14 @@ export default Vue.extend({
|
||||
components: {
|
||||
XMessagingRoom: () => import('../../../common/views/components/messaging-room.vue').then(m => m.default)
|
||||
},
|
||||
props: ['user'],
|
||||
props: ['user', 'group'],
|
||||
computed: {
|
||||
popout(): string {
|
||||
return `${url}/i/messaging/${getAcct(this.user)}`;
|
||||
if (this.user) {
|
||||
return `${url}/i/messaging/${getAcct(this.user)}`;
|
||||
} else if (this.group) {
|
||||
return `${url}/i/messaging/group/${this.group.id}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<mk-window ref="window" width="500px" height="560px" @closed="destroyDom">
|
||||
<template #header :class="$style.header"><fa icon="comments"/>{{ $t('@.messaging') }}</template>
|
||||
<x-messaging :class="$style.content" @navigate="navigate"/>
|
||||
<x-messaging :class="$style.content" @navigate="navigate" @navigateGroup="navigateGroup"/>
|
||||
</mk-window>
|
||||
</template>
|
||||
|
||||
@ -20,6 +20,11 @@ export default Vue.extend({
|
||||
this.$root.new(MkMessagingRoomWindow, {
|
||||
user: user
|
||||
});
|
||||
},
|
||||
navigateGroup(group) {
|
||||
this.$root.new(MkMessagingRoomWindow, {
|
||||
group: group
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -1,70 +0,0 @@
|
||||
<template>
|
||||
<mk-window ref="window" is-modal width="450px" height="500px" @closed="destroyDom">
|
||||
<template #header><fa :icon="['far', 'envelope']"/> {{ $t('title') }}</template>
|
||||
|
||||
<div class="slpqaxdoxhvglersgjukmvizkqbmbokc">
|
||||
<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>
|
||||
</div>
|
||||
</mk-window>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import i18n from '../../../i18n';
|
||||
|
||||
export default Vue.extend({
|
||||
i18n: i18n('desktop/views/components/received-follow-requests-window.vue'),
|
||||
data() {
|
||||
return {
|
||||
fetching: true,
|
||||
requests: []
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.$root.api('following/requests/list').then(requests => {
|
||||
this.fetching = false;
|
||||
this.requests = requests;
|
||||
});
|
||||
},
|
||||
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);
|
||||
});
|
||||
},
|
||||
close() {
|
||||
(this as any).$refs.window.close();
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.slpqaxdoxhvglersgjukmvizkqbmbokc
|
||||
padding 16px
|
||||
|
||||
> button
|
||||
margin-bottom 16px
|
||||
|
||||
> div
|
||||
display flex
|
||||
padding 16px
|
||||
border solid 1px var(--faceDivider)
|
||||
border-radius 4px
|
||||
|
||||
> span
|
||||
margin 0 0 0 auto
|
||||
|
||||
</style>
|
@ -28,12 +28,19 @@
|
||||
<i><fa icon="angle-right"/></i>
|
||||
</router-link>
|
||||
</li>
|
||||
<li @click="list">
|
||||
<p>
|
||||
<li>
|
||||
<router-link to="/i/lists">
|
||||
<i><fa icon="list" fixed-width/></i>
|
||||
<span>{{ $t('lists') }}</span>
|
||||
<i><fa icon="angle-right"/></i>
|
||||
</p>
|
||||
</router-link>
|
||||
</li>
|
||||
<li>
|
||||
<router-link to="/i/groups">
|
||||
<i><fa :icon="faUsers" fixed-width/></i>
|
||||
<span>{{ $t('groups') }}</span>
|
||||
<i><fa icon="angle-right"/></i>
|
||||
</router-link>
|
||||
</li>
|
||||
<li>
|
||||
<router-link to="/i/pages">
|
||||
@ -42,12 +49,12 @@
|
||||
<i><fa icon="angle-right"/></i>
|
||||
</router-link>
|
||||
</li>
|
||||
<li @click="followRequests" v-if="($store.state.i.isLocked || $store.state.i.carefulBot)">
|
||||
<p>
|
||||
<li v-if="($store.state.i.isLocked || $store.state.i.carefulBot)">
|
||||
<router-link to="/i/follow-requests">
|
||||
<i><fa :icon="['far', 'envelope']" fixed-width/></i>
|
||||
<span>{{ $t('follow-requests') }}<i v-if="$store.state.i.pendingReceivedFollowRequestsCount">{{ $store.state.i.pendingReceivedFollowRequestsCount }}</i></span>
|
||||
<i><fa icon="angle-right"/></i>
|
||||
</p>
|
||||
</router-link>
|
||||
</li>
|
||||
</ul>
|
||||
<ul>
|
||||
@ -96,12 +103,10 @@
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import i18n from '../../../i18n';
|
||||
import MkUserListsWindow from './user-lists-window.vue';
|
||||
import MkFollowRequestsWindow from './received-follow-requests-window.vue';
|
||||
// import MkSettingsWindow from './settings-window.vue';
|
||||
import MkDriveWindow from './drive-window.vue';
|
||||
import contains from '../../../common/scripts/contains';
|
||||
import { faHome, faColumns } from '@fortawesome/free-solid-svg-icons';
|
||||
import { faHome, faColumns, faUsers } from '@fortawesome/free-solid-svg-icons';
|
||||
import { faMoon, faSun, faStickyNote } from '@fortawesome/free-regular-svg-icons';
|
||||
|
||||
export default Vue.extend({
|
||||
@ -109,7 +114,7 @@ export default Vue.extend({
|
||||
data() {
|
||||
return {
|
||||
isOpen: false,
|
||||
faHome, faColumns, faMoon, faSun, faStickyNote
|
||||
faHome, faColumns, faMoon, faSun, faStickyNote, faUsers
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@ -147,14 +152,6 @@ export default Vue.extend({
|
||||
this.close();
|
||||
this.$root.new(MkDriveWindow);
|
||||
},
|
||||
list() {
|
||||
this.close();
|
||||
this.$root.new(MkUserListsWindow);
|
||||
},
|
||||
followRequests() {
|
||||
this.close();
|
||||
this.$root.new(MkFollowRequestsWindow);
|
||||
},
|
||||
signout() {
|
||||
this.$root.signout();
|
||||
},
|
||||
|
@ -72,8 +72,6 @@
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import i18n from '../../../i18n';
|
||||
import MkUserListsWindow from './user-lists-window.vue';
|
||||
import MkFollowRequestsWindow from './received-follow-requests-window.vue';
|
||||
import MkSettingsWindow from './settings-window.vue';
|
||||
import MkDriveWindow from './drive-window.vue';
|
||||
import MkMessagingWindow from './messaging-window.vue';
|
||||
|
@ -1,24 +0,0 @@
|
||||
<template>
|
||||
<mk-window ref="window" width="450px" height="500px" @closed="destroyDom">
|
||||
<template #header><fa icon="list"/> {{ list.name }}</template>
|
||||
|
||||
<x-editor :list="list"/>
|
||||
</mk-window>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import XEditor from '../../../common/views/components/user-list-editor.vue';
|
||||
|
||||
export default Vue.extend({
|
||||
components: {
|
||||
XEditor
|
||||
},
|
||||
|
||||
props: {
|
||||
list: {
|
||||
required: true
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
@ -1,36 +0,0 @@
|
||||
<template>
|
||||
<mk-window ref="window" width="450px" height="500px" @closed="destroyDom">
|
||||
<template #header><fa icon="list"/> {{ $t('title') }}</template>
|
||||
<x-lists :class="$style.content" @choosen="choosen"/>
|
||||
</mk-window>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import i18n from '../../../i18n';
|
||||
import MkUserListWindow from './user-list-window.vue';
|
||||
|
||||
export default Vue.extend({
|
||||
i18n: i18n('desktop/views/components/user-lists-window.vue'),
|
||||
components: {
|
||||
XLists: () => import('../../../common/views/components/user-lists.vue').then(m => m.default)
|
||||
},
|
||||
methods: {
|
||||
close() {
|
||||
(this as any).$refs.window.close();
|
||||
},
|
||||
choosen(list) {
|
||||
this.$root.new(MkUserListWindow, {
|
||||
list
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="stylus" module>
|
||||
.content
|
||||
height 100%
|
||||
overflow auto
|
||||
|
||||
</style>
|
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="mk-messaging-room-page">
|
||||
<x-messaging-room v-if="user" :user="user" :is-naked="true"/>
|
||||
<x-messaging-room v-if="user || group" :user="user" :group="group" :is-naked="true"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -19,7 +19,8 @@ export default Vue.extend({
|
||||
data() {
|
||||
return {
|
||||
fetching: true,
|
||||
user: null
|
||||
user: null,
|
||||
group: null
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
@ -47,14 +48,25 @@ export default Vue.extend({
|
||||
Progress.start();
|
||||
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') + ': ' + getUserName(this.user);
|
||||
document.title = this.$t('@.messaging') + ': ' + getUserName(this.user);
|
||||
|
||||
Progress.done();
|
||||
});
|
||||
Progress.done();
|
||||
});
|
||||
} 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;
|
||||
|
||||
Progress.done();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -4,7 +4,7 @@
|
||||
<template #header><fa icon="comments"/>{{ $t('@.messaging') }}</template>
|
||||
<template #func><button @click="add"><fa icon="plus"/></button></template>
|
||||
|
||||
<x-messaging ref="index" compact @navigate="navigate"/>
|
||||
<x-messaging ref="index" compact @navigate="navigate" @navigateGroup="navigateGroup"/>
|
||||
</ui-container>
|
||||
</div>
|
||||
</template>
|
||||
@ -31,6 +31,11 @@ export default define({
|
||||
user: user
|
||||
});
|
||||
},
|
||||
navigateGroup(group) {
|
||||
this.$root.new(MkMessagingRoomWindow, {
|
||||
group: group
|
||||
});
|
||||
},
|
||||
add() {
|
||||
this.$root.new(MkMessagingWindow);
|
||||
},
|
||||
|
@ -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: [
|
||||
|
@ -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>
|
||||
|
@ -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>
|
@ -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;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -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}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -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>
|
38
src/client/app/mobile/views/pages/ui.vue
Normal file
38
src/client/app/mobile/views/pages/ui.vue
Normal 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>
|
@ -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>
|
@ -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>
|
Reference in New Issue
Block a user