Merge branch 'develop' into math-block
This commit is contained in:
82
src/client/app/admin/views/users.user.vue
Normal file
82
src/client/app/admin/views/users.user.vue
Normal file
@ -0,0 +1,82 @@
|
||||
<template>
|
||||
<div class="kofvwchc">
|
||||
<div>
|
||||
<a :href="user | userPage(null, true)">
|
||||
<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>
|
||||
<span class="is-admin" v-if="user.isAdmin">admin</span>
|
||||
<span class="is-moderator" v-if="user.isModerator">moderator</span>
|
||||
<span class="is-verified" v-if="user.isVerified" :title="$t('@.verified-user')"><fa icon="star"/></span>
|
||||
<span class="is-suspended" v-if="user.isSuspended" :title="$t('@.suspended-user')"><fa :icon="faSnowflake"/></span>
|
||||
</header>
|
||||
<div>
|
||||
<span>{{ $t('users.updatedAt') }}: <mk-time :time="user.updatedAt" mode="detail"/></span>
|
||||
</div>
|
||||
<div>
|
||||
<span>{{ $t('users.createdAt') }}: <mk-time :time="user.createdAt" mode="detail"/></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import i18n from '../../i18n';
|
||||
import { faSnowflake } from '@fortawesome/free-regular-svg-icons';
|
||||
|
||||
export default Vue.extend({
|
||||
i18n: i18n('admin/views/users.vue'),
|
||||
props: ['user'],
|
||||
data() {
|
||||
return {
|
||||
faSnowflake
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.kofvwchc
|
||||
display flex
|
||||
padding 16px 0
|
||||
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
|
||||
|
||||
> .is-admin
|
||||
> .is-moderator
|
||||
flex-shrink 0
|
||||
align-self center
|
||||
margin 0 0 0 .5em
|
||||
padding 1px 6px
|
||||
font-size 80%
|
||||
border-radius 3px
|
||||
background var(--noteHeaderAdminBg)
|
||||
color var(--noteHeaderAdminFg)
|
||||
|
||||
> .is-verified
|
||||
> .is-suspended
|
||||
margin 0 0 0 .5em
|
||||
color #4dabf7
|
||||
</style>
|
@ -3,20 +3,27 @@
|
||||
<ui-card>
|
||||
<div slot="title"><fa :icon="faTerminal"/> {{ $t('operation') }}</div>
|
||||
<section class="fit-top">
|
||||
<ui-input v-model="target" type="text">
|
||||
<ui-input class="target" v-model="target" type="text">
|
||||
<span>{{ $t('username-or-userid') }}</span>
|
||||
</ui-input>
|
||||
<ui-button @click="resetPassword"><fa :icon="faKey"/> {{ $t('reset-password') }}</ui-button>
|
||||
<ui-horizon-group>
|
||||
<ui-button @click="verifyUser" :disabled="verifying"><fa :icon="faCertificate"/> {{ $t('verify') }}</ui-button>
|
||||
<ui-button @click="unverifyUser" :disabled="unverifying">{{ $t('unverify') }}</ui-button>
|
||||
</ui-horizon-group>
|
||||
<ui-horizon-group>
|
||||
<ui-button @click="suspendUser" :disabled="suspending"><fa :icon="faSnowflake"/> {{ $t('suspend') }}</ui-button>
|
||||
<ui-button @click="unsuspendUser" :disabled="unsuspending">{{ $t('unsuspend') }}</ui-button>
|
||||
</ui-horizon-group>
|
||||
<ui-button @click="showUser"><fa :icon="faSearch"/> {{ $t('lookup') }}</ui-button>
|
||||
<ui-textarea v-if="user" :value="user | json5" readonly tall style="margin-top:16px;"></ui-textarea>
|
||||
|
||||
<div class="user" v-if="user">
|
||||
<x-user :user='user'/>
|
||||
<div class="actions">
|
||||
<ui-button @click="resetPassword"><fa :icon="faKey"/> {{ $t('reset-password') }}</ui-button>
|
||||
<ui-horizon-group>
|
||||
<ui-button @click="verifyUser" :disabled="verifying"><fa :icon="faCertificate"/> {{ $t('verify') }}</ui-button>
|
||||
<ui-button @click="unverifyUser" :disabled="unverifying">{{ $t('unverify') }}</ui-button>
|
||||
</ui-horizon-group>
|
||||
<ui-horizon-group>
|
||||
<ui-button @click="suspendUser" :disabled="suspending"><fa :icon="faSnowflake"/> {{ $t('suspend') }}</ui-button>
|
||||
<ui-button @click="unsuspendUser" :disabled="unsuspending">{{ $t('unsuspend') }}</ui-button>
|
||||
</ui-horizon-group>
|
||||
<ui-button v-if="user.host != null" @click="updateRemoteUser"><fa :icon="faSync"/> {{ $t('update-remote-user') }}</ui-button>
|
||||
<ui-textarea v-if="user" :value="user | json5" readonly tall style="margin-top:16px;"></ui-textarea>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</ui-card>
|
||||
|
||||
@ -47,29 +54,7 @@
|
||||
</ui-select>
|
||||
</ui-horizon-group>
|
||||
<sequential-entrance animation="entranceFromTop" delay="25">
|
||||
<div class="kofvwchc" v-for="user in users" :key="user.id">
|
||||
<div>
|
||||
<a :href="user | userPage(null, true)">
|
||||
<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>
|
||||
<span class="is-admin" v-if="user.isAdmin">admin</span>
|
||||
<span class="is-moderator" v-if="user.isModerator">moderator</span>
|
||||
<span class="is-verified" v-if="user.isVerified" :title="$t('@.verified-user')"><fa icon="star"/></span>
|
||||
<span class="is-suspended" v-if="user.isSuspended" :title="$t('@.suspended-user')"><fa :icon="faSnowflake"/></span>
|
||||
</header>
|
||||
<div>
|
||||
<span>{{ $t('users.updatedAt') }}: <mk-time :time="user.updatedAt" mode="detail"/></span>
|
||||
</div>
|
||||
<div>
|
||||
<span>{{ $t('users.createdAt') }}: <mk-time :time="user.createdAt" mode="detail"/></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<x-user v-for="user in users" :user='user' :key="user.id"/>
|
||||
</sequential-entrance>
|
||||
<ui-button v-if="existMore" @click="fetchUsers">{{ $t('@.load-more') }}</ui-button>
|
||||
</section>
|
||||
@ -81,12 +66,15 @@
|
||||
import Vue from 'vue';
|
||||
import i18n from '../../i18n';
|
||||
import parseAcct from "../../../../misc/acct/parse";
|
||||
import { faCertificate, faUsers, faTerminal, faSearch, faKey } from '@fortawesome/free-solid-svg-icons';
|
||||
import { faCertificate, faUsers, faTerminal, faSearch, faKey, faSync } from '@fortawesome/free-solid-svg-icons';
|
||||
import { faSnowflake } from '@fortawesome/free-regular-svg-icons';
|
||||
import XUser from './users.user.vue';
|
||||
|
||||
export default Vue.extend({
|
||||
i18n: i18n('admin/views/users.vue'),
|
||||
|
||||
components: {
|
||||
XUser
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
user: null,
|
||||
@ -102,7 +90,7 @@ export default Vue.extend({
|
||||
offset: 0,
|
||||
users: [],
|
||||
existMore: false,
|
||||
faTerminal, faCertificate, faUsers, faSnowflake, faSearch, faKey
|
||||
faTerminal, faCertificate, faUsers, faSnowflake, faSearch, faKey, faSync
|
||||
};
|
||||
},
|
||||
|
||||
@ -131,6 +119,7 @@ export default Vue.extend({
|
||||
},
|
||||
|
||||
methods: {
|
||||
/** テキストエリアのユーザーを解決する */
|
||||
async fetchUser() {
|
||||
try {
|
||||
return await this.$root.api('users/show', this.target.startsWith('@') ? parseAcct(this.target) : { userId: this.target });
|
||||
@ -149,16 +138,27 @@ export default Vue.extend({
|
||||
}
|
||||
},
|
||||
|
||||
/** テキストエリアから処理対象ユーザーを設定する */
|
||||
async showUser() {
|
||||
this.user = null;
|
||||
const user = await this.fetchUser();
|
||||
this.$root.api('admin/show-user', { userId: user.id }).then(info => {
|
||||
this.user = info;
|
||||
});
|
||||
this.target = '';
|
||||
},
|
||||
|
||||
/** 処理対象ユーザーの情報を更新する */
|
||||
async refreshUser() {
|
||||
this.$root.api('admin/show-user', { userId: this.user._id }).then(info => {
|
||||
this.user = info;
|
||||
});
|
||||
},
|
||||
|
||||
async resetPassword() {
|
||||
const user = await this.fetchUser();
|
||||
this.$root.api('admin/reset-password', { userId: user.id }).then(res => {
|
||||
if (!await this.getConfirmed(this.$t('reset-password-confirm'))) return;
|
||||
|
||||
this.$root.api('admin/reset-password', { userId: this.user._id }).then(res => {
|
||||
this.$root.dialog({
|
||||
type: 'success',
|
||||
text: this.$t('password-updated', { password: res.password })
|
||||
@ -167,11 +167,12 @@ export default Vue.extend({
|
||||
},
|
||||
|
||||
async verifyUser() {
|
||||
if (!await this.getConfirmed(this.$t('verify-confirm'))) return;
|
||||
|
||||
this.verifying = true;
|
||||
|
||||
const process = async () => {
|
||||
const user = await this.fetchUser();
|
||||
await this.$root.api('admin/verify-user', { userId: user.id });
|
||||
await this.$root.api('admin/verify-user', { userId: this.user._id });
|
||||
this.$root.dialog({
|
||||
type: 'success',
|
||||
text: this.$t('verified')
|
||||
@ -186,14 +187,17 @@ export default Vue.extend({
|
||||
});
|
||||
|
||||
this.verifying = false;
|
||||
|
||||
this.refreshUser();
|
||||
},
|
||||
|
||||
async unverifyUser() {
|
||||
if (!await this.getConfirmed(this.$t('unverify-confirm'))) return;
|
||||
|
||||
this.unverifying = true;
|
||||
|
||||
const process = async () => {
|
||||
const user = await this.fetchUser();
|
||||
await this.$root.api('admin/unverify-user', { userId: user.id });
|
||||
await this.$root.api('admin/unverify-user', { userId: this.user._id });
|
||||
this.$root.dialog({
|
||||
type: 'success',
|
||||
text: this.$t('unverified')
|
||||
@ -208,14 +212,17 @@ export default Vue.extend({
|
||||
});
|
||||
|
||||
this.unverifying = false;
|
||||
|
||||
this.refreshUser();
|
||||
},
|
||||
|
||||
async suspendUser() {
|
||||
if (!await this.getConfirmed(this.$t('suspend-confirm'))) return;
|
||||
|
||||
this.suspending = true;
|
||||
|
||||
const process = async () => {
|
||||
const user = await this.fetchUser();
|
||||
await this.$root.api('admin/suspend-user', { userId: user.id });
|
||||
await this.$root.api('admin/suspend-user', { userId: this.user._id });
|
||||
this.$root.dialog({
|
||||
type: 'success',
|
||||
text: this.$t('suspended')
|
||||
@ -230,14 +237,17 @@ export default Vue.extend({
|
||||
});
|
||||
|
||||
this.suspending = false;
|
||||
|
||||
this.refreshUser();
|
||||
},
|
||||
|
||||
async unsuspendUser() {
|
||||
if (!await this.getConfirmed(this.$t('unsuspend-confirm'))) return;
|
||||
|
||||
this.unsuspending = true;
|
||||
|
||||
const process = async () => {
|
||||
const user = await this.fetchUser();
|
||||
await this.$root.api('admin/unsuspend-user', { userId: user.id });
|
||||
await this.$root.api('admin/unsuspend-user', { userId: this.user._id });
|
||||
this.$root.dialog({
|
||||
type: 'success',
|
||||
text: this.$t('unsuspended')
|
||||
@ -252,8 +262,32 @@ export default Vue.extend({
|
||||
});
|
||||
|
||||
this.unsuspending = false;
|
||||
|
||||
this.refreshUser();
|
||||
},
|
||||
|
||||
async updateRemoteUser() {
|
||||
this.$root.api('admin/update-remote-user', { userId: this.user._id }).then(res => {
|
||||
this.$root.dialog({
|
||||
type: 'success',
|
||||
text: this.$t('remote-user-updated')
|
||||
});
|
||||
});
|
||||
|
||||
this.refreshUser();
|
||||
},
|
||||
|
||||
async getConfirmed(text: string): Promise<Boolean> {
|
||||
const confirm = await this.$root.dialog({
|
||||
type: 'warning',
|
||||
showCancelButton: true,
|
||||
title: 'confirm',
|
||||
text,
|
||||
});
|
||||
|
||||
return !confirm.canceled;
|
||||
}
|
||||
|
||||
fetchUsers() {
|
||||
this.$root.api('admin/show-users', {
|
||||
state: this.state,
|
||||
@ -277,42 +311,12 @@ export default Vue.extend({
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.kofvwchc
|
||||
display flex
|
||||
padding 16px 0
|
||||
border-top solid 1px var(--faceDivider)
|
||||
.target
|
||||
margin-bottom 16px !important
|
||||
|
||||
> div:first-child
|
||||
> a
|
||||
> .avatar
|
||||
width 64px
|
||||
height 64px
|
||||
.user
|
||||
margin-top 32px
|
||||
|
||||
> div:last-child
|
||||
flex 1
|
||||
padding-left 16px
|
||||
|
||||
@media (max-width 500px)
|
||||
font-size 14px
|
||||
|
||||
> header
|
||||
> .username
|
||||
margin-left 8px
|
||||
opacity 0.7
|
||||
|
||||
> .is-admin
|
||||
> .is-moderator
|
||||
flex-shrink 0
|
||||
align-self center
|
||||
margin 0 0 0 .5em
|
||||
padding 1px 6px
|
||||
font-size 80%
|
||||
border-radius 3px
|
||||
background var(--noteHeaderAdminBg)
|
||||
color var(--noteHeaderAdminFg)
|
||||
|
||||
> .is-verified
|
||||
> .is-suspended
|
||||
margin 0 0 0 .5em
|
||||
color #4dabf7
|
||||
> .actions
|
||||
margin-left 80px
|
||||
</style>
|
||||
|
@ -26,3 +26,8 @@
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); }
|
||||
}
|
||||
|
@ -72,47 +72,6 @@ body
|
||||
code
|
||||
font-family Consolas, 'Courier New', Courier, Monaco, monospace
|
||||
|
||||
.comment
|
||||
opacity 0.5
|
||||
|
||||
.string
|
||||
color #e96900
|
||||
|
||||
.regexp
|
||||
color #e9003f
|
||||
|
||||
.keyword
|
||||
color #2973b7
|
||||
|
||||
&.true
|
||||
&.false
|
||||
&.null
|
||||
&.nil
|
||||
&.undefined
|
||||
color #ae81ff
|
||||
|
||||
.symbol
|
||||
color #42b983
|
||||
|
||||
.number
|
||||
.nan
|
||||
color #ae81ff
|
||||
|
||||
.var:not(.keyword)
|
||||
font-weight bold
|
||||
font-style italic
|
||||
//text-decoration underline
|
||||
|
||||
.method
|
||||
font-style italic
|
||||
color #8964c1
|
||||
|
||||
.property
|
||||
color #a71d5d
|
||||
|
||||
.label
|
||||
color #e9003f
|
||||
|
||||
pre
|
||||
display block
|
||||
|
||||
|
@ -133,6 +133,7 @@ export default prop => ({
|
||||
|
||||
case 'deleted': {
|
||||
Vue.set(this.$_ns_target, 'deletedAt', body.deletedAt);
|
||||
Vue.set(this.$_ns_target, 'renote', null);
|
||||
this.$_ns_target.text = null;
|
||||
this.$_ns_target.tags = [];
|
||||
this.$_ns_target.fileIds = [];
|
||||
|
30
src/client/app/common/views/components/code-core.vue
Normal file
30
src/client/app/common/views/components/code-core.vue
Normal file
@ -0,0 +1,30 @@
|
||||
<template>
|
||||
<prism :inline="inline" :language="lang">{{ code }}</prism>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import 'prismjs';
|
||||
import 'prismjs/themes/prism.css';
|
||||
import Prism from 'vue-prism-component';
|
||||
|
||||
export default Vue.extend({
|
||||
components: {
|
||||
Prism
|
||||
},
|
||||
props: {
|
||||
code: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
lang: {
|
||||
type: String,
|
||||
required: false
|
||||
},
|
||||
inline: {
|
||||
type: Boolean,
|
||||
required: false
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
28
src/client/app/common/views/components/code.vue
Normal file
28
src/client/app/common/views/components/code.vue
Normal file
@ -0,0 +1,28 @@
|
||||
<template>
|
||||
<x-code :code="code" :lang="lang" :inline="inline"/>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
|
||||
export default Vue.extend({
|
||||
components: {
|
||||
XCode: () => import('./code-core.vue').then(m => m.default)
|
||||
},
|
||||
|
||||
props: {
|
||||
code: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
lang: {
|
||||
type: String,
|
||||
required: false
|
||||
},
|
||||
inline: {
|
||||
type: Boolean,
|
||||
required: false
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
@ -5,16 +5,21 @@
|
||||
<span>{{ $t('click-to-show') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<a class="gqnyydlzavusgskkfvwvjiattxdzsqlf" v-else :href="image.url" target="_blank" :style="style" :title="image.name" @click.prevent="onClick"></a>
|
||||
<a class="gqnyydlzavusgskkfvwvjiattxdzsqlf" v-else
|
||||
:href="image.url"
|
||||
:style="style"
|
||||
:title="image.name"
|
||||
@click.prevent="onClick"
|
||||
></a>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import i18n from '../../../i18n';
|
||||
import ImageViewer from '../../../common/views/components/image-viewer.vue';
|
||||
import ImageViewer from './image-viewer.vue';
|
||||
|
||||
export default Vue.extend({
|
||||
i18n: i18n('mobile/views/components/media-image.vue'),
|
||||
i18n: i18n('common/views/components/media-image.vue'),
|
||||
props: {
|
||||
image: {
|
||||
type: Object,
|
||||
@ -58,6 +63,7 @@ export default Vue.extend({
|
||||
<style lang="stylus" scoped>
|
||||
.gqnyydlzavusgskkfvwvjiattxdzsqlf
|
||||
display block
|
||||
cursor zoom-in
|
||||
overflow hidden
|
||||
width 100%
|
||||
height 100%
|
@ -7,7 +7,7 @@
|
||||
<div :data-count="mediaList.filter(media => previewable(media)).length" ref="grid">
|
||||
<template v-for="media in mediaList">
|
||||
<mk-media-video :video="media" :key="media.id" v-if="media.type.startsWith('video')"/>
|
||||
<mk-media-image :image="media" :key="media.id" v-else-if="media.type.startsWith('image')" :raw="raw"/>
|
||||
<x-image :image="media" :key="media.id" v-else-if="media.type.startsWith('image')" :raw="raw"/>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
@ -17,10 +17,12 @@
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import XBanner from './media-banner.vue';
|
||||
import XImage from './media-image.vue';
|
||||
|
||||
export default Vue.extend({
|
||||
components: {
|
||||
XBanner
|
||||
XBanner,
|
||||
XImage
|
||||
},
|
||||
props: {
|
||||
mediaList: {
|
||||
|
@ -6,8 +6,8 @@ import MkUrl from './url.vue';
|
||||
import MkMention from './mention.vue';
|
||||
import { concat, sum } from '../../../../../prelude/array';
|
||||
import MkFormula from './formula.vue';
|
||||
import MkCode from './code.vue';
|
||||
import MkGoogle from './google.vue';
|
||||
import syntaxHighlight from '../../../../../mfm/syntax-highlight';
|
||||
import { host } from '../../../config';
|
||||
import { preorderF, countNodesF } from '../../../../../prelude/tree';
|
||||
|
||||
@ -124,6 +124,25 @@ export default Vue.component('misskey-flavored-markdown', {
|
||||
}, genEl(token.children));
|
||||
}
|
||||
|
||||
case 'spin': {
|
||||
motionCount++;
|
||||
const isLong = sumTextsLength(token.children) > 5 || countNodesF(token.children) > 3;
|
||||
const isMany = motionCount > 3;
|
||||
return (createElement as any)('span', {
|
||||
attrs: {
|
||||
style: (this.$store.state.settings.disableAnimatedMfm || isLong || isMany) ? 'display: inline-block;' : 'display: inline-block; animation: spin 1.5s linear infinite;'
|
||||
},
|
||||
}, genEl(token.children));
|
||||
}
|
||||
|
||||
case 'flip': {
|
||||
return (createElement as any)('span', {
|
||||
attrs: {
|
||||
style: 'display: inline-block; transform: scaleX(-1);'
|
||||
},
|
||||
}, genEl(token.children));
|
||||
}
|
||||
|
||||
case 'url': {
|
||||
return [createElement(MkUrl, {
|
||||
key: Math.random(),
|
||||
@ -170,21 +189,22 @@ export default Vue.component('misskey-flavored-markdown', {
|
||||
}
|
||||
|
||||
case 'blockCode': {
|
||||
return [createElement('pre', {
|
||||
class: 'code'
|
||||
}, [
|
||||
createElement('code', {
|
||||
domProps: {
|
||||
innerHTML: syntaxHighlight(token.node.props.code)
|
||||
}
|
||||
})
|
||||
])];
|
||||
return [createElement(MkCode, {
|
||||
key: Math.random(),
|
||||
props: {
|
||||
code: token.node.props.code,
|
||||
lang: token.node.props.lang,
|
||||
}
|
||||
})];
|
||||
}
|
||||
|
||||
case 'inlineCode': {
|
||||
return [createElement('code', {
|
||||
domProps: {
|
||||
innerHTML: syntaxHighlight(token.node.props.code)
|
||||
return [createElement(MkCode, {
|
||||
key: Math.random(),
|
||||
props: {
|
||||
code: token.node.props.code,
|
||||
lang: token.node.props.lang,
|
||||
inline: true
|
||||
}
|
||||
})];
|
||||
}
|
||||
|
@ -24,34 +24,10 @@ export default Vue.extend({
|
||||
background var(--mfmTitleBg)
|
||||
border-radius 4px
|
||||
|
||||
>>> .code
|
||||
margin 8px 0
|
||||
|
||||
>>> .quote
|
||||
margin 8px
|
||||
padding 6px 0 6px 12px
|
||||
color var(--mfmQuote)
|
||||
border-left solid 3px var(--mfmQuoteLine)
|
||||
|
||||
>>> code
|
||||
padding 4px 8px
|
||||
margin 0 0.5em
|
||||
font-size 80%
|
||||
color #525252
|
||||
background rgba(0, 0, 0, 0.05)
|
||||
border-radius 2px
|
||||
|
||||
>>> pre > code
|
||||
padding 16px
|
||||
margin 0
|
||||
|
||||
>>> [data-is-me]:after
|
||||
content "you"
|
||||
padding 0 4px
|
||||
margin-left 4px
|
||||
font-size 80%
|
||||
color var(--primaryForeground)
|
||||
background var(--primary)
|
||||
border-radius 4px
|
||||
|
||||
</style>
|
||||
|
@ -1,21 +1,23 @@
|
||||
<template>
|
||||
<mk-window ref="window" is-modal width="800px" height="500px" @closed="destroyDom">
|
||||
<span slot="header">
|
||||
<span :class="$style.title">{{ $t('choose-prompt') }}</span>
|
||||
<span :class="$style.count" v-if="multiple && files.length > 0">({{ $t('chosen-files', { count: files.length }) }})</span>
|
||||
<span slot="header" class="jqiaciqv">
|
||||
<span class="title">{{ $t('choose-prompt') }}</span>
|
||||
<span class="count" v-if="multiple && files.length > 0">({{ $t('chosen-files', { count: files.length }) }})</span>
|
||||
</span>
|
||||
|
||||
<x-drive
|
||||
ref="browser"
|
||||
:class="$style.browser"
|
||||
:multiple="multiple"
|
||||
@selected="onSelected"
|
||||
@change-selection="onChangeSelection"
|
||||
/>
|
||||
<div :class="$style.footer">
|
||||
<button :class="$style.upload" :title="$t('title')" @click="upload"><fa icon="upload"/></button>
|
||||
<button :class="$style.cancel" @click="cancel">{{ $t('cancel') }}</button>
|
||||
<button :class="$style.ok" :disabled="multiple && files.length == 0" @click="ok">{{ $t('ok') }}</button>
|
||||
<div class="rqsvbumu">
|
||||
<x-drive
|
||||
ref="browser"
|
||||
class="browser"
|
||||
:multiple="multiple"
|
||||
@selected="onSelected"
|
||||
@change-selection="onChangeSelection"
|
||||
/>
|
||||
<div class="footer">
|
||||
<button class="upload" :title="$t('title')" @click="upload"><fa icon="upload"/></button>
|
||||
<ui-button inline @click="cancel" style="margin-right:16px;">{{ $t('cancel') }}</ui-button>
|
||||
<ui-button inline primary :disabled="multiple && files.length == 0" @click="ok">{{ $t('ok') }}</ui-button>
|
||||
</div>
|
||||
</div>
|
||||
</mk-window>
|
||||
</template>
|
||||
@ -60,120 +62,67 @@ export default Vue.extend({
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="stylus" module>
|
||||
.title
|
||||
> [data-icon]
|
||||
margin-right 4px
|
||||
<style lang="stylus" scoped>
|
||||
.jqiaciqv
|
||||
.title
|
||||
> [data-icon]
|
||||
margin-right 4px
|
||||
|
||||
.count
|
||||
margin-left 8px
|
||||
opacity 0.7
|
||||
|
||||
.browser
|
||||
height calc(100% - 72px)
|
||||
|
||||
.footer
|
||||
height 72px
|
||||
background var(--primaryLighten95)
|
||||
|
||||
.upload
|
||||
display inline-block
|
||||
position absolute
|
||||
top 8px
|
||||
left 16px
|
||||
cursor pointer
|
||||
padding 0
|
||||
margin 8px 4px 0 0
|
||||
width 40px
|
||||
height 40px
|
||||
font-size 1em
|
||||
color var(--primaryAlpha05)
|
||||
background transparent
|
||||
outline none
|
||||
border solid 1px transparent
|
||||
border-radius 4px
|
||||
|
||||
&:hover
|
||||
background transparent
|
||||
border-color var(--primaryAlpha03)
|
||||
|
||||
&:active
|
||||
color var(--primaryAlpha06)
|
||||
background transparent
|
||||
border-color var(--primaryAlpha05)
|
||||
//box-shadow 0 2px 4px rgba(var(--primaryDarken50), 0.15) inset
|
||||
|
||||
&:focus
|
||||
&:after
|
||||
content ""
|
||||
pointer-events none
|
||||
position absolute
|
||||
top -5px
|
||||
right -5px
|
||||
bottom -5px
|
||||
left -5px
|
||||
border 2px solid var(--primaryAlpha03)
|
||||
border-radius 8px
|
||||
|
||||
.ok
|
||||
.cancel
|
||||
display block
|
||||
position absolute
|
||||
bottom 16px
|
||||
cursor pointer
|
||||
padding 0
|
||||
margin 0
|
||||
width 120px
|
||||
height 40px
|
||||
font-size 1em
|
||||
outline none
|
||||
border-radius 4px
|
||||
|
||||
&:focus
|
||||
&:after
|
||||
content ""
|
||||
pointer-events none
|
||||
position absolute
|
||||
top -5px
|
||||
right -5px
|
||||
bottom -5px
|
||||
left -5px
|
||||
border 2px solid var(--primaryAlpha03)
|
||||
border-radius 8px
|
||||
|
||||
&:disabled
|
||||
.count
|
||||
margin-left 8px
|
||||
opacity 0.7
|
||||
cursor default
|
||||
|
||||
.ok
|
||||
right 16px
|
||||
color var(--primaryForeground)
|
||||
background linear-gradient(to bottom, var(--primaryLighten25) 0%, var(--primaryLighten10) 100%)
|
||||
border solid 1px var(--primaryLighten15)
|
||||
.rqsvbumu
|
||||
display flex
|
||||
flex-direction column
|
||||
height 100%
|
||||
|
||||
&:not(:disabled)
|
||||
font-weight bold
|
||||
.browser
|
||||
flex 1
|
||||
overflow auto
|
||||
|
||||
&:hover:not(:disabled)
|
||||
background linear-gradient(to bottom, var(--primaryLighten8) 0%, var(--primaryDarken8) 100%)
|
||||
border-color var(--primary)
|
||||
.footer
|
||||
padding 16px
|
||||
background var(--desktopPostFormBg)
|
||||
text-align right
|
||||
|
||||
&:active:not(:disabled)
|
||||
background var(--primary)
|
||||
border-color var(--primary)
|
||||
.upload
|
||||
display inline-block
|
||||
position absolute
|
||||
top 8px
|
||||
left 16px
|
||||
cursor pointer
|
||||
padding 0
|
||||
margin 8px 4px 0 0
|
||||
width 40px
|
||||
height 40px
|
||||
font-size 1em
|
||||
color var(--primaryAlpha05)
|
||||
background transparent
|
||||
outline none
|
||||
border solid 1px transparent
|
||||
border-radius 4px
|
||||
|
||||
.cancel
|
||||
right 148px
|
||||
color #888
|
||||
background linear-gradient(to bottom, #ffffff 0%, #f5f5f5 100%)
|
||||
border solid 1px #e2e2e2
|
||||
&:hover
|
||||
background transparent
|
||||
border-color var(--primaryAlpha03)
|
||||
|
||||
&:hover
|
||||
background linear-gradient(to bottom, #f9f9f9 0%, #ececec 100%)
|
||||
border-color #dcdcdc
|
||||
&:active
|
||||
color var(--primaryAlpha06)
|
||||
background transparent
|
||||
border-color var(--primaryAlpha05)
|
||||
//box-shadow 0 2px 4px rgba(var(--primaryDarken50), 0.15) inset
|
||||
|
||||
&:active
|
||||
background #ececec
|
||||
border-color #dcdcdc
|
||||
&:focus
|
||||
&:after
|
||||
content ""
|
||||
pointer-events none
|
||||
position absolute
|
||||
top -5px
|
||||
right -5px
|
||||
bottom -5px
|
||||
left -5px
|
||||
border 2px solid var(--primaryAlpha03)
|
||||
border-radius 8px
|
||||
|
||||
</style>
|
||||
|
@ -1,17 +1,19 @@
|
||||
<template>
|
||||
<mk-window ref="window" is-modal width="800px" height="500px" @closed="destroyDom">
|
||||
<span slot="header">
|
||||
<span :class="$style.title">{{ $t('choose-prompt') }}</span>
|
||||
<span>{{ $t('choose-prompt') }}</span>
|
||||
</span>
|
||||
|
||||
<x-drive
|
||||
ref="browser"
|
||||
:class="$style.browser"
|
||||
:multiple="false"
|
||||
/>
|
||||
<div :class="$style.footer">
|
||||
<button :class="$style.cancel" @click="cancel">{{ $t('cancel') }}</button>
|
||||
<button :class="$style.ok" @click="ok">{{ $t('ok') }}</button>
|
||||
<div class="hllkpxxu">
|
||||
<x-drive
|
||||
ref="browser"
|
||||
class="browser"
|
||||
:multiple="false"
|
||||
/>
|
||||
<div class="footer">
|
||||
<ui-button inline @click="cancel" style="margin-right:16px;">{{ $t('cancel') }}</ui-button>
|
||||
<ui-button inline @click="ok" primary>{{ $t('ok') }}</ui-button>
|
||||
</div>
|
||||
</div>
|
||||
</mk-window>
|
||||
</template>
|
||||
@ -36,79 +38,19 @@ export default Vue.extend({
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="stylus" module>
|
||||
<style lang="stylus" scoped>
|
||||
.hllkpxxu
|
||||
display flex
|
||||
flex-direction column
|
||||
height 100%
|
||||
|
||||
.browser
|
||||
flex 1
|
||||
overflow auto
|
||||
|
||||
.title
|
||||
> [data-icon]
|
||||
margin-right 4px
|
||||
|
||||
.browser
|
||||
height calc(100% - 72px)
|
||||
|
||||
.footer
|
||||
height 72px
|
||||
background var(--primaryLighten95)
|
||||
|
||||
.ok
|
||||
.cancel
|
||||
display block
|
||||
position absolute
|
||||
bottom 16px
|
||||
cursor pointer
|
||||
padding 0
|
||||
margin 0
|
||||
width 120px
|
||||
height 40px
|
||||
font-size 1em
|
||||
outline none
|
||||
border-radius 4px
|
||||
|
||||
&:focus
|
||||
&:after
|
||||
content ""
|
||||
pointer-events none
|
||||
position absolute
|
||||
top -5px
|
||||
right -5px
|
||||
bottom -5px
|
||||
left -5px
|
||||
border 2px solid var(--primaryAlpha03)
|
||||
border-radius 8px
|
||||
|
||||
&:disabled
|
||||
opacity 0.7
|
||||
cursor default
|
||||
|
||||
.ok
|
||||
right 16px
|
||||
color var(--primaryForeground)
|
||||
background linear-gradient(to bottom, var(--primaryLighten25) 0%, var(--primaryLighten10) 100%)
|
||||
border solid 1px var(--primaryLighten15)
|
||||
|
||||
&:not(:disabled)
|
||||
font-weight bold
|
||||
|
||||
&:hover:not(:disabled)
|
||||
background linear-gradient(to bottom, var(--primaryLighten8) 0%, var(--primaryDarken8) 100%)
|
||||
border-color var(--primary)
|
||||
|
||||
&:active:not(:disabled)
|
||||
background var(--primary)
|
||||
border-color var(--primary)
|
||||
|
||||
.cancel
|
||||
right 148px
|
||||
color #888
|
||||
background linear-gradient(to bottom, #ffffff 0%, #f5f5f5 100%)
|
||||
border solid 1px #e2e2e2
|
||||
|
||||
&:hover
|
||||
background linear-gradient(to bottom, #f9f9f9 0%, #ececec 100%)
|
||||
border-color #dcdcdc
|
||||
|
||||
&:active
|
||||
background #ececec
|
||||
border-color #dcdcdc
|
||||
.footer
|
||||
padding 16px
|
||||
background var(--desktopPostFormBg)
|
||||
text-align right
|
||||
|
||||
</style>
|
||||
|
@ -9,7 +9,6 @@ import subNoteContent from './sub-note-content.vue';
|
||||
import window from './window.vue';
|
||||
import noteFormWindow from './post-form-window.vue';
|
||||
import renoteFormWindow from './renote-form-window.vue';
|
||||
import mediaImage from './media-image.vue';
|
||||
import mediaVideo from './media-video.vue';
|
||||
import notifications from './notifications.vue';
|
||||
import noteForm from './post-form.vue';
|
||||
@ -32,7 +31,6 @@ Vue.component('mk-sub-note-content', subNoteContent);
|
||||
Vue.component('mk-window', window);
|
||||
Vue.component('mk-post-form-window', noteFormWindow);
|
||||
Vue.component('mk-renote-form-window', renoteFormWindow);
|
||||
Vue.component('mk-media-image', mediaImage);
|
||||
Vue.component('mk-media-video', mediaVideo);
|
||||
Vue.component('mk-notifications', notifications);
|
||||
Vue.component('mk-post-form', noteForm);
|
||||
|
@ -1,81 +0,0 @@
|
||||
<template>
|
||||
<div class="ldwbgwstjsdgcjruamauqdrffetqudry" v-if="image.isSensitive && hide && !$store.state.device.alwaysShowNsfw" @click="hide = false">
|
||||
<div>
|
||||
<b><fa icon="exclamation-triangle"/> {{ $t('sensitive') }}</b>
|
||||
<span>{{ $t('click-to-show') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<a class="lcjomzwbohoelkxsnuqjiaccdbdfiazy" v-else
|
||||
:href="image.url"
|
||||
@click.prevent="onClick"
|
||||
:style="style"
|
||||
:title="image.name"
|
||||
></a>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import i18n from '../../../i18n';
|
||||
import ImageViewer from '../../../common/views/components/image-viewer.vue';
|
||||
|
||||
export default Vue.extend({
|
||||
i18n: i18n('desktop/views/components/media-image.vue'),
|
||||
props: {
|
||||
image: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
raw: {
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
hide: true
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
style(): any {
|
||||
return {
|
||||
'background-color': this.image.properties.avgColor && this.image.properties.avgColor.length == 3 ? `rgb(${this.image.properties.avgColor.join(',')})` : 'transparent',
|
||||
'background-image': this.raw ? `url(${this.image.url})` : `url(${this.image.thumbnailUrl})`
|
||||
};
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onClick() {
|
||||
this.$root.new(ImageViewer, {
|
||||
image: this.image
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.lcjomzwbohoelkxsnuqjiaccdbdfiazy
|
||||
display block
|
||||
cursor zoom-in
|
||||
overflow hidden
|
||||
width 100%
|
||||
height 100%
|
||||
background-position center
|
||||
background-size contain
|
||||
background-repeat no-repeat
|
||||
|
||||
.ldwbgwstjsdgcjruamauqdrffetqudry
|
||||
display flex
|
||||
justify-content center
|
||||
align-items center
|
||||
background #111
|
||||
color #fff
|
||||
|
||||
> div
|
||||
display table-cell
|
||||
text-align center
|
||||
font-size 12px
|
||||
|
||||
> *
|
||||
display block
|
||||
|
||||
</style>
|
@ -3,7 +3,6 @@ import Vue from 'vue';
|
||||
import ui from './ui.vue';
|
||||
import note from './note.vue';
|
||||
import notes from './notes.vue';
|
||||
import mediaImage from './media-image.vue';
|
||||
import mediaVideo from './media-video.vue';
|
||||
import notePreview from './note-preview.vue';
|
||||
import subNoteContent from './sub-note-content.vue';
|
||||
@ -24,7 +23,6 @@ import postForm from './post-form.vue';
|
||||
Vue.component('mk-ui', ui);
|
||||
Vue.component('mk-note', note);
|
||||
Vue.component('mk-notes', notes);
|
||||
Vue.component('mk-media-image', mediaImage);
|
||||
Vue.component('mk-media-video', mediaVideo);
|
||||
Vue.component('mk-note-preview', notePreview);
|
||||
Vue.component('mk-sub-note-content', subNoteContent);
|
||||
|
Reference in New Issue
Block a user