mirror of
https://github.com/misskey-dev/misskey.git
synced 2024-12-01 10:11:57 +01:00
* wip
* wip
* Clean up
* wip
* wip
* wip
* wip
* wip
* wip
* wip
* wip
* 🎨
* wip
* wip
This commit is contained in:
parent
c1a929022f
commit
fef4f7fce8
29 changed files with 824 additions and 833 deletions
|
@ -456,6 +456,26 @@ common/views/components/trends.vue:
|
|||
count: "{}人が投稿"
|
||||
empty: "トレンドなし"
|
||||
|
||||
common/views/components/profile-editor.vue:
|
||||
title: "プロフィール"
|
||||
name: "名前"
|
||||
account: "アカウント"
|
||||
location: "場所"
|
||||
description: "自己紹介"
|
||||
birthday: "誕生日"
|
||||
avatar: "アイコン"
|
||||
banner: "バナー"
|
||||
is-cat: "このアカウントはCatです"
|
||||
is-bot: "このアカウントはBotです"
|
||||
is-locked: "フォローを承認制にする"
|
||||
careful-bot: "Botからのフォローだけ承認制にする"
|
||||
advanced: "その他"
|
||||
privacy: "プライバシー"
|
||||
save: "保存"
|
||||
saved: "プロフィールを保存しました"
|
||||
uploading: "アップロード中"
|
||||
upload-failed: "アップロードに失敗しました"
|
||||
|
||||
common/views/widgets/broadcast.vue:
|
||||
fetching: "確認中"
|
||||
no-broadcasts: "お知らせはありません"
|
||||
|
@ -814,9 +834,12 @@ desktop/views/components/settings.vue:
|
|||
advanced: "詳細設定"
|
||||
api-via-stream: "ストリームを経由したAPIリクエスト"
|
||||
api-via-stream-desc: "この設定をオンにすると、websocket接続を経由してAPIリクエストが行われます(パフォーマンス向上が期待できます)。オフにすると、ネイティブの fetch APIが利用されます。この設定はこのデバイスのみ有効です。"
|
||||
deck-nav: "デッキ内ナビゲーション"
|
||||
deck-nav-desc: "デッキを使用しているとき、ナビゲーションが発生する際にページ遷移を行わずに一時的なカラムで受けるようにします。"
|
||||
|
||||
display: "デザインと表示"
|
||||
customize: "ホームをカスタマイズ"
|
||||
wallpaper: "壁紙"
|
||||
choose-wallpaper: "壁紙を選択"
|
||||
delete-wallpaper: "壁紙を削除"
|
||||
dark-mode: "ダークモード"
|
||||
|
@ -839,9 +862,6 @@ desktop/views/components/settings.vue:
|
|||
volume: "ボリューム"
|
||||
test: "テスト"
|
||||
|
||||
mobile: "モバイル"
|
||||
disable-via-mobile: "「モバイルからの投稿」フラグを付けない"
|
||||
|
||||
language: "言語"
|
||||
pick-language: "言語を選択"
|
||||
recommended: "推奨"
|
||||
|
@ -933,22 +953,6 @@ desktop/views/components/settings.password.vue:
|
|||
not-match: "新しいパスワードが一致しません"
|
||||
changed: "パスワードを変更しました"
|
||||
|
||||
desktop/views/components/settings.profile.vue:
|
||||
avatar: "アイコン"
|
||||
choice-avatar: "画像を選択"
|
||||
name: "名前"
|
||||
location: "場所"
|
||||
description: "自己紹介"
|
||||
birthday: "誕生日"
|
||||
save: "保存"
|
||||
locked-account: "アカウントの保護"
|
||||
is-locked: "フォローを承認制にする"
|
||||
careful-bot: "Botからのフォローだけ承認制にする"
|
||||
other: "その他"
|
||||
is-bot: "このアカウントはBotです"
|
||||
is-cat: "このアカウントはCatです"
|
||||
profile-updated: "プロフィールを更新しました"
|
||||
|
||||
desktop/views/components/sub-note-content.vue:
|
||||
private: "この投稿は非公開です"
|
||||
deleted: "この投稿は削除されました"
|
||||
|
@ -1069,11 +1073,6 @@ desktop/views/pages/deck/deck.tl-column.vue:
|
|||
is-media-view: "メディアビュー"
|
||||
edit: "オプション"
|
||||
|
||||
desktop/views/pages/deck/deck.note.vue:
|
||||
reposted-by: "{}がRenote"
|
||||
private: "この投稿は非公開です"
|
||||
deleted: "この投稿は削除されました"
|
||||
|
||||
desktop/views/pages/stats/stats.vue:
|
||||
all-users: "全てのユーザー"
|
||||
original-users: "このインスタンスのユーザー"
|
||||
|
@ -1417,25 +1416,6 @@ mobile/views/pages/notifications.vue:
|
|||
mobile/views/pages/games/reversi.vue:
|
||||
reversi: "リバーシ"
|
||||
|
||||
mobile/views/pages/settings/settings.profile.vue:
|
||||
title: "プロフィール"
|
||||
name: "名前"
|
||||
account: "アカウント"
|
||||
location: "場所"
|
||||
description: "自己紹介"
|
||||
birthday: "誕生日"
|
||||
avatar: "アイコン"
|
||||
banner: "バナー"
|
||||
is-cat: "このアカウントはCatです"
|
||||
is-locked: "フォローを承認制にする"
|
||||
careful-bot: "Botからのフォローだけ承認制にする"
|
||||
advanced: "その他"
|
||||
privacy: "プライバシー"
|
||||
save: "保存"
|
||||
saved: "プロフィールを保存しました"
|
||||
uploading: "アップロード中"
|
||||
upload-failed: "アップロードに失敗しました"
|
||||
|
||||
mobile/views/pages/search.vue:
|
||||
search: "検索"
|
||||
empty: "「{}」に関する投稿は見つかりませんでした。"
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import Vue from 'vue';
|
||||
|
||||
import profileEditor from './profile-editor.vue';
|
||||
import noteSkeleton from './note-skeleton.vue';
|
||||
import theme from './theme.vue';
|
||||
import instance from './instance.vue';
|
||||
|
@ -45,6 +46,7 @@ import uiSelect from './ui/select.vue';
|
|||
import formButton from './ui/form/button.vue';
|
||||
import formRadio from './ui/form/radio.vue';
|
||||
|
||||
Vue.component('mk-profile-editor', profileEditor);
|
||||
Vue.component('mk-note-skeleton', noteSkeleton);
|
||||
Vue.component('mk-theme', theme);
|
||||
Vue.component('mk-instance', instance);
|
||||
|
|
|
@ -49,6 +49,7 @@
|
|||
|
||||
<div>
|
||||
<ui-switch v-model="isCat" @change="save(false)">%i18n:@is-cat%</ui-switch>
|
||||
<ui-switch v-model="isBot" @change="save(false)">%i18n:@is-bot%</ui-switch>
|
||||
<ui-switch v-model="alwaysMarkNsfw">%i18n:common.always-mark-nsfw%</ui-switch>
|
||||
</div>
|
||||
</section>
|
||||
|
@ -66,7 +67,7 @@
|
|||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import { apiUrl, host } from '../../../../config';
|
||||
import { apiUrl, host } from '../../../config';
|
||||
|
||||
export default Vue.extend({
|
||||
data() {
|
||||
|
@ -80,6 +81,7 @@ export default Vue.extend({
|
|||
avatarId: null,
|
||||
bannerId: null,
|
||||
isCat: false,
|
||||
isBot: false,
|
||||
isLocked: false,
|
||||
carefulBot: false,
|
||||
saving: false,
|
||||
|
@ -104,6 +106,7 @@ export default Vue.extend({
|
|||
this.avatarId = this.$store.state.i.avatarId;
|
||||
this.bannerId = this.$store.state.i.bannerId;
|
||||
this.isCat = this.$store.state.i.isCat;
|
||||
this.isBot = this.$store.state.i.isBot;
|
||||
this.isLocked = this.$store.state.i.isLocked;
|
||||
this.carefulBot = this.$store.state.i.carefulBot;
|
||||
},
|
||||
|
@ -164,6 +167,7 @@ export default Vue.extend({
|
|||
avatarId: this.avatarId,
|
||||
bannerId: this.bannerId,
|
||||
isCat: this.isCat,
|
||||
isBot: this.isBot,
|
||||
isLocked: this.isLocked,
|
||||
carefulBot: this.carefulBot
|
||||
}).then(i => {
|
|
@ -122,17 +122,19 @@ export default Vue.extend({
|
|||
}
|
||||
},
|
||||
mounted() {
|
||||
if (this.$refs.prefix) {
|
||||
this.$refs.label.style.left = (this.$refs.prefix.offsetLeft + this.$refs.prefix.offsetWidth) + 'px';
|
||||
if (this.$refs.prefix.offsetWidth) {
|
||||
this.$refs.input.style.paddingLeft = this.$refs.prefix.offsetWidth + 'px';
|
||||
this.$nextTick(() => {
|
||||
if (this.$refs.prefix) {
|
||||
this.$refs.label.style.left = (this.$refs.prefix.offsetLeft + this.$refs.prefix.offsetWidth) + 'px';
|
||||
if (this.$refs.prefix.offsetWidth) {
|
||||
this.$refs.input.style.paddingLeft = this.$refs.prefix.offsetWidth + 'px';
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.$refs.suffix) {
|
||||
if (this.$refs.suffix.offsetWidth) {
|
||||
this.$refs.input.style.paddingRight = this.$refs.suffix.offsetWidth + 'px';
|
||||
if (this.$refs.suffix) {
|
||||
if (this.$refs.suffix.offsetWidth) {
|
||||
this.$refs.input.style.paddingRight = this.$refs.suffix.offsetWidth + 'px';
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
focus() {
|
||||
|
|
|
@ -73,9 +73,6 @@ export default define({
|
|||
border-radius 8px
|
||||
|
||||
.stream
|
||||
display -webkit-flex
|
||||
display -moz-flex
|
||||
display -ms-flex
|
||||
display flex
|
||||
justify-content center
|
||||
flex-wrap wrap
|
||||
|
|
|
@ -67,8 +67,8 @@ init(async (launch) => {
|
|||
{ path: '/tags/:tag', component: MkTag },
|
||||
{ path: '/share', component: MkShare },
|
||||
{ path: '/reversi/:game?', component: MkReversi },
|
||||
{ path: '/@:user', component: MkUser },
|
||||
{ path: '/notes/:note', component: MkNote },
|
||||
{ path: '/@:user', name: 'user', component: MkUser },
|
||||
{ path: '/notes/:note', name: 'note', component: MkNote },
|
||||
{ path: '/authorize-follow', component: MkFollow }
|
||||
]
|
||||
});
|
||||
|
|
|
@ -91,7 +91,7 @@ import MkPostFormWindow from './post-form-window.vue';
|
|||
import MkRenoteFormWindow from './renote-form-window.vue';
|
||||
import MkNoteMenu from '../../../common/views/components/note-menu.vue';
|
||||
import MkReactionPicker from '../../../common/views/components/reaction-picker.vue';
|
||||
import XSub from './notes.note.sub.vue';
|
||||
import XSub from './note.sub.vue';
|
||||
import { sum } from '../../../../../prelude/array';
|
||||
import noteSubscriber from '../../../common/scripts/note-subscriber';
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<div class="tkfdzaxtkdeianobciwadajxzbddorql" :title="title">
|
||||
<div class="tkfdzaxtkdeianobciwadajxzbddorql" :class="{ mini }" :title="title">
|
||||
<mk-avatar class="avatar" :user="note.user"/>
|
||||
<div class="main">
|
||||
<mk-note-header class="header" :note="note"/>
|
||||
|
@ -24,6 +24,11 @@ export default Vue.extend({
|
|||
note: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
mini: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -44,11 +49,19 @@ export default Vue.extend({
|
|||
<style lang="stylus" scoped>
|
||||
.tkfdzaxtkdeianobciwadajxzbddorql
|
||||
display flex
|
||||
margin 0
|
||||
padding 16px 32px
|
||||
font-size 0.9em
|
||||
background var(--subNoteBg)
|
||||
|
||||
&.mini
|
||||
padding 16px
|
||||
font-size 10px
|
||||
|
||||
> .avatar
|
||||
margin 0 8px 0 0
|
||||
width 38px
|
||||
height 38px
|
||||
|
||||
> .avatar
|
||||
flex-shrink 0
|
||||
display block
|
|
@ -1,7 +1,17 @@
|
|||
<template>
|
||||
<div class="note" v-show="appearNote.deletedAt == null" :tabindex="appearNote.deletedAt == null ? '-1' : null" v-hotkey="keymap" :title="title">
|
||||
<div
|
||||
class="note"
|
||||
:class="{ mini }"
|
||||
v-show="appearNote.deletedAt == null"
|
||||
:tabindex="appearNote.deletedAt == null ? '-1' : null"
|
||||
v-hotkey="keymap"
|
||||
:title="title"
|
||||
>
|
||||
<div class="conversation" v-if="detail && conversation.length > 0">
|
||||
<x-sub v-for="note in conversation" :key="note.id" :note="note" :mini="mini"/>
|
||||
</div>
|
||||
<div class="reply-to" v-if="appearNote.reply && (!$store.getters.isSignedIn || $store.state.settings.showReplyTarget)">
|
||||
<x-sub :note="appearNote.reply"/>
|
||||
<x-sub :note="appearNote.reply" :mini="mini"/>
|
||||
</div>
|
||||
<div class="renote" v-if="isRenote">
|
||||
<mk-avatar class="avatar" :user="note.user"/>
|
||||
|
@ -32,8 +42,8 @@
|
|||
</div>
|
||||
<mk-poll v-if="appearNote.poll" :note="appearNote" ref="pollViewer"/>
|
||||
<a class="location" v-if="appearNote.geo" :href="`https://maps.google.com/maps?q=${appearNote.geo.coordinates[1]},${appearNote.geo.coordinates[0]}`" target="_blank">%fa:map-marker-alt% 位置情報</a>
|
||||
<div class="renote" v-if="appearNote.renote"><mk-note-preview :note="appearNote.renote"/></div>
|
||||
<mk-url-preview v-for="url in urls" :url="url" :key="url"/>
|
||||
<div class="renote" v-if="appearNote.renote"><mk-note-preview :note="appearNote.renote" :mini="mini"/></div>
|
||||
<mk-url-preview v-for="url in urls" :url="url" :key="url" :mini="mini"/>
|
||||
</div>
|
||||
</div>
|
||||
<footer>
|
||||
|
@ -55,15 +65,16 @@
|
|||
</footer>
|
||||
</div>
|
||||
</article>
|
||||
<div class="replies" v-if="detail && replies.length > 0">
|
||||
<x-sub v-for="note in replies" :key="note.id" :note="note" :mini="mini"/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
|
||||
import MkPostFormWindow from './post-form-window.vue';
|
||||
import MkRenoteFormWindow from './renote-form-window.vue';
|
||||
import XSub from './notes.note.sub.vue';
|
||||
import XSub from './note.sub.vue';
|
||||
import noteMixin from '../../../common/scripts/note-mixin';
|
||||
import noteSubscriber from '../../../common/scripts/note-subscriber';
|
||||
|
||||
|
@ -81,6 +92,40 @@ export default Vue.extend({
|
|||
note: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
detail: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false
|
||||
},
|
||||
mini: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
conversation: [],
|
||||
replies: []
|
||||
};
|
||||
},
|
||||
|
||||
created() {
|
||||
if (this.detail) {
|
||||
(this as any).api('notes/replies', {
|
||||
noteId: this.appearNote.id,
|
||||
limit: 8
|
||||
}).then(replies => {
|
||||
this.replies = replies;
|
||||
});
|
||||
|
||||
(this as any).api('notes/conversation', {
|
||||
noteId: this.appearNote.replyId
|
||||
}).then(conversation => {
|
||||
this.conversation = conversation.reverse();
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -93,14 +138,23 @@ export default Vue.extend({
|
|||
background var(--face)
|
||||
border-bottom solid 1px var(--faceDivider)
|
||||
|
||||
&[data-round]
|
||||
&:first-child
|
||||
border-top-left-radius 6px
|
||||
border-top-right-radius 6px
|
||||
&.mini
|
||||
font-size 13px
|
||||
|
||||
> .renote
|
||||
border-top-left-radius 6px
|
||||
border-top-right-radius 6px
|
||||
> .renote
|
||||
padding 8px 16px 0 16px
|
||||
|
||||
.avatar
|
||||
width 20px
|
||||
height 20px
|
||||
|
||||
> article
|
||||
padding 16px 16px 4px
|
||||
|
||||
> .avatar
|
||||
margin 0 10px 8px 0
|
||||
width 42px
|
||||
height 42px
|
||||
|
||||
&:last-of-type
|
||||
border-bottom none
|
||||
|
@ -129,6 +183,7 @@ export default Vue.extend({
|
|||
background linear-gradient(to bottom, var(--renoteGradient) 0%, var(--face) 100%)
|
||||
|
||||
.avatar
|
||||
flex-shrink 0
|
||||
display inline-block
|
||||
width 28px
|
||||
height 28px
|
||||
|
@ -273,6 +328,9 @@ export default Vue.extend({
|
|||
border none
|
||||
cursor pointer
|
||||
|
||||
&:last-child
|
||||
margin-right 0
|
||||
|
||||
&:hover
|
||||
color var(--noteActionsHover)
|
||||
|
|
@ -40,7 +40,7 @@ import Vue from 'vue';
|
|||
import * as config from '../../../config';
|
||||
import getNoteSummary from '../../../../../misc/get-note-summary';
|
||||
|
||||
import XNote from './notes.note.vue';
|
||||
import XNote from './note.vue';
|
||||
|
||||
const displayLimit = 30;
|
||||
|
||||
|
|
|
@ -2,10 +2,10 @@
|
|||
<div class="2fa">
|
||||
<p>%i18n:@intro%<a href="%i18n:@url%" target="_blank">%i18n:@detail%</a></p>
|
||||
<div class="ui info warn"><p>%fa:exclamation-triangle%%i18n:@caution%</p></div>
|
||||
<p v-if="!data && !$store.state.i.twoFactorEnabled"><button @click="register" class="ui primary">%i18n:@register%</button></p>
|
||||
<p v-if="!data && !$store.state.i.twoFactorEnabled"><ui-button @click="register">%i18n:@register%</ui-button></p>
|
||||
<template v-if="$store.state.i.twoFactorEnabled">
|
||||
<p>%i18n:@already-registered%</p>
|
||||
<button @click="unregister" class="ui">%i18n:@unregister%</button>
|
||||
<ui-button @click="unregister">%i18n:@unregister%</ui-button>
|
||||
</template>
|
||||
<div v-if="data">
|
||||
<ol>
|
||||
|
@ -13,7 +13,7 @@
|
|||
<li>%i18n:@scan%<br><img :src="data.qr"></li>
|
||||
<li>%i18n:@done%<br>
|
||||
<input type="number" v-model="token" class="ui">
|
||||
<button @click="submit" class="ui primary">%i18n:@submit%</button>
|
||||
<ui-button primary @click="submit">%i18n:@submit%</ui-button>
|
||||
</li>
|
||||
</ol>
|
||||
<div class="ui info"><p>%fa:info-circle%%i18n:@info%</p></div>
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
<template>
|
||||
<div class="root api">
|
||||
<p>%i18n:@token% <code>{{ $store.state.i.token }}</code></p>
|
||||
<ui-input :value="$store.state.i.token" readonly>
|
||||
<span>%i18n:@token%</span>
|
||||
</ui-input>
|
||||
<p>%i18n:@intro%</p>
|
||||
<div class="ui info warn"><p>%fa:exclamation-triangle%%i18n:@caution%</p></div>
|
||||
<p>%i18n:@regeneration-of-token%</p>
|
||||
<button class="ui" @click="regenerateToken">%i18n:@regenerate-token%</button>
|
||||
<ui-button @click="regenerateToken">%i18n:@regenerate-token%</ui-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<div>
|
||||
<button @click="reset" class="ui primary">%i18n:@reset%</button>
|
||||
<ui-button @click="reset">%i18n:@reset%</ui-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
|
@ -1,106 +0,0 @@
|
|||
<template>
|
||||
<div class="profile">
|
||||
<label class="avatar ui from group">
|
||||
<p>%i18n:@avatar%</p>
|
||||
<img class="avatar" :src="$store.state.i.avatarUrl" alt="avatar"/>
|
||||
<button class="ui" @click="updateAvatar">%i18n:@choice-avatar%</button>
|
||||
</label>
|
||||
<label class="ui from group">
|
||||
<ui-input v-model="name" type="text">%i18n:@name%</ui-input>
|
||||
</label>
|
||||
<label class="ui from group">
|
||||
<ui-input v-model="location" type="text">%i18n:@location%</ui-input>
|
||||
</label>
|
||||
<label class="ui from group">
|
||||
<ui-textarea v-model="description">%i18n:@description%</ui-textarea>
|
||||
</label>
|
||||
<label class="ui from group">
|
||||
<p>%i18n:@birthday%</p>
|
||||
<input type="date" v-model="birthday"/>
|
||||
</label>
|
||||
<ui-button primary @click="save">%i18n:@save%</ui-button>
|
||||
<section>
|
||||
<h2>%i18n:@locked-account%</h2>
|
||||
<ui-switch v-model="isLocked" @change="save(false)">%i18n:@is-locked%</ui-switch>
|
||||
<ui-switch v-model="carefulBot" @change="save(false)">%i18n:@careful-bot%</ui-switch>
|
||||
</section>
|
||||
<section>
|
||||
<h2>%i18n:@other%</h2>
|
||||
<ui-switch v-model="isBot" @change="save(false)">%i18n:@is-bot%</ui-switch>
|
||||
<ui-switch v-model="isCat" @change="save(false)">%i18n:@is-cat%</ui-switch>
|
||||
<ui-switch v-model="alwaysMarkNsfw">%i18n:common.always-mark-nsfw%</ui-switch>
|
||||
</section>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
|
||||
export default Vue.extend({
|
||||
data() {
|
||||
return {
|
||||
name: null,
|
||||
location: null,
|
||||
description: null,
|
||||
birthday: null,
|
||||
isBot: false,
|
||||
isCat: false,
|
||||
isLocked: false,
|
||||
carefulBot: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
alwaysMarkNsfw: {
|
||||
get() { return this.$store.state.i.settings.alwaysMarkNsfw; },
|
||||
set(value) { (this as any).api('i/update', { alwaysMarkNsfw: value }); }
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.name = this.$store.state.i.name || '';
|
||||
this.location = this.$store.state.i.profile.location;
|
||||
this.description = this.$store.state.i.description;
|
||||
this.birthday = this.$store.state.i.profile.birthday;
|
||||
this.isCat = this.$store.state.i.isCat;
|
||||
this.isBot = this.$store.state.i.isBot;
|
||||
this.isLocked = this.$store.state.i.isLocked;
|
||||
this.carefulBot = this.$store.state.i.carefulBot;
|
||||
},
|
||||
methods: {
|
||||
updateAvatar() {
|
||||
(this as any).apis.updateAvatar();
|
||||
},
|
||||
save(notify) {
|
||||
(this as any).api('i/update', {
|
||||
name: this.name || null,
|
||||
location: this.location || null,
|
||||
description: this.description || null,
|
||||
birthday: this.birthday || null,
|
||||
isCat: this.isCat,
|
||||
isBot: this.isBot,
|
||||
isLocked: this.isLocked,
|
||||
carefulBot: this.carefulBot
|
||||
}).then(() => {
|
||||
if (notify) {
|
||||
(this as any).apis.notify('%i18n:@profile-updated%');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.profile
|
||||
> .avatar
|
||||
> img
|
||||
display inline-block
|
||||
vertical-align top
|
||||
width 64px
|
||||
height 64px
|
||||
border-radius 4px
|
||||
|
||||
> button
|
||||
margin-left 8px
|
||||
|
||||
</style>
|
||||
|
|
@ -2,38 +2,59 @@
|
|||
<div class="mk-settings">
|
||||
<div class="nav">
|
||||
<p :class="{ active: page == 'profile' }" @mousedown="page = 'profile'">%fa:user .fw%%i18n:@profile%</p>
|
||||
<p :class="{ active: page == 'theme' }" @mousedown="page = 'theme'">%fa:palette .fw%%i18n:@theme%</p>
|
||||
<p :class="{ active: page == 'web' }" @mousedown="page = 'web'">%fa:desktop .fw%Web</p>
|
||||
<p :class="{ active: page == 'notification' }" @mousedown="page = 'notification'">%fa:R bell .fw%%i18n:@notification%</p>
|
||||
<p :class="{ active: page == 'drive' }" @mousedown="page = 'drive'">%fa:cloud .fw%%i18n:@drive%</p>
|
||||
<p :class="{ active: page == 'hashtags' }" @mousedown="page = 'hashtags'">%fa:hashtag .fw%%i18n:@tags%</p>
|
||||
<p :class="{ active: page == 'mute' }" @mousedown="page = 'mute'">%fa:ban .fw%%i18n:@mute%</p>
|
||||
<p :class="{ active: page == 'apps' }" @mousedown="page = 'apps'">%fa:puzzle-piece .fw%%i18n:@apps%</p>
|
||||
<p :class="{ active: page == 'twitter' }" @mousedown="page = 'twitter'">%fa:B twitter .fw%Twitter</p>
|
||||
<p :class="{ active: page == 'security' }" @mousedown="page = 'security'">%fa:unlock-alt .fw%%i18n:@security%</p>
|
||||
<p :class="{ active: page == 'api' }" @mousedown="page = 'api'">%fa:key .fw%API</p>
|
||||
<p :class="{ active: page == 'other' }" @mousedown="page = 'other'">%fa:cogs .fw%%i18n:@other%</p>
|
||||
</div>
|
||||
<div class="pages">
|
||||
<section class="profile" v-show="page == 'profile'">
|
||||
<h1>%i18n:@profile%</h1>
|
||||
<x-profile/>
|
||||
</section>
|
||||
<div class="profile" v-show="page == 'profile'">
|
||||
<mk-profile-editor/>
|
||||
|
||||
<section class="web" v-show="page == 'web'">
|
||||
<h1>%i18n:@theme%</h1>
|
||||
<mk-theme/>
|
||||
</section>
|
||||
<ui-card>
|
||||
<div slot="title">%fa:B twitter% %i18n:@twitter%</div>
|
||||
<section>
|
||||
<mk-twitter-setting/>
|
||||
</section>
|
||||
</ui-card>
|
||||
</div>
|
||||
|
||||
<section class="web" v-show="page == 'web'">
|
||||
<h1>%i18n:@behaviour%</h1>
|
||||
<ui-switch v-model="fetchOnScroll">
|
||||
%i18n:@fetch-on-scroll%
|
||||
<span slot="desc">%i18n:@fetch-on-scroll-desc%</span>
|
||||
</ui-switch>
|
||||
<ui-switch v-model="autoPopout">
|
||||
%i18n:@auto-popout%
|
||||
<span slot="desc">%i18n:@auto-popout-desc%</span>
|
||||
</ui-switch>
|
||||
<ui-card class="theme" v-show="page == 'theme'">
|
||||
<div slot="title">%fa:palette% %i18n:@theme%</div>
|
||||
|
||||
<section>
|
||||
<mk-theme/>
|
||||
</section>
|
||||
</ui-card>
|
||||
|
||||
<ui-card class="web" v-show="page == 'web'">
|
||||
<div slot="title">%fa:sliders-h% %i18n:@behaviour%</div>
|
||||
|
||||
<section>
|
||||
<ui-switch v-model="fetchOnScroll">
|
||||
%i18n:@fetch-on-scroll%
|
||||
<span slot="desc">%i18n:@fetch-on-scroll-desc%</span>
|
||||
</ui-switch>
|
||||
<ui-switch v-model="autoPopout">
|
||||
%i18n:@auto-popout%
|
||||
<span slot="desc">%i18n:@auto-popout-desc%</span>
|
||||
</ui-switch>
|
||||
<ui-switch v-model="deckNav">%i18n:@deck-nav%<span slot="desc">%i18n:@deck-nav-desc%</span></ui-switch>
|
||||
|
||||
<details>
|
||||
<summary>%i18n:@advanced%</summary>
|
||||
<ui-switch v-model="apiViaStream">
|
||||
%i18n:@api-via-stream%
|
||||
<span slot="desc">%i18n:@api-via-stream-desc%</span>
|
||||
</ui-switch>
|
||||
</details>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<header>%i18n:@note-visibility%</header>
|
||||
|
@ -49,24 +70,26 @@
|
|||
</ui-select>
|
||||
</section>
|
||||
</section>
|
||||
</ui-card>
|
||||
|
||||
<details>
|
||||
<summary>%i18n:@advanced%</summary>
|
||||
<ui-switch v-model="apiViaStream">
|
||||
%i18n:@api-via-stream%
|
||||
<span slot="desc">%i18n:@api-via-stream-desc%</span>
|
||||
</ui-switch>
|
||||
</details>
|
||||
</section>
|
||||
<ui-card class="web" v-show="page == 'web'">
|
||||
<div slot="title">%fa:desktop% %i18n:@display%</div>
|
||||
|
||||
<section class="web" v-show="page == 'web'">
|
||||
<h1>%i18n:@display%</h1>
|
||||
<div class="div">
|
||||
<button class="ui button" @click="customizeHome" style="margin-bottom: 16px">%i18n:@customize%</button>
|
||||
</div>
|
||||
<div class="div">
|
||||
<button class="ui" @click="updateWallpaper">%i18n:@choose-wallpaper%</button>
|
||||
<button class="ui" @click="deleteWallpaper">%i18n:@delete-wallpaper%</button>
|
||||
<section>
|
||||
<ui-button @click="customizeHome">%i18n:@customize%</ui-button>
|
||||
</section>
|
||||
<section>
|
||||
<header>%i18n:@wallpaper%</header>
|
||||
<ui-button @click="updateWallpaper">%i18n:@choose-wallpaper%</ui-button>
|
||||
<ui-button @click="deleteWallpaper">%i18n:@delete-wallpaper%</ui-button>
|
||||
</section>
|
||||
<section>
|
||||
<header>%i18n:@navbar-position%</header>
|
||||
<ui-radio v-model="navbar" value="top">%i18n:@navbar-position-top%</ui-radio>
|
||||
<ui-radio v-model="navbar" value="left">%i18n:@navbar-position-left%</ui-radio>
|
||||
<ui-radio v-model="navbar" value="right">%i18n:@navbar-position-right%</ui-radio>
|
||||
</section>
|
||||
<section>
|
||||
<ui-switch v-model="darkmode">%i18n:@dark-mode%</ui-switch>
|
||||
<ui-switch v-model="useShadow">%i18n:@use-shadow%</ui-switch>
|
||||
<ui-switch v-model="roundedCorners">%i18n:@rounded-corners%</ui-switch>
|
||||
|
@ -75,171 +98,186 @@
|
|||
<ui-switch v-model="contrastedAcct">%i18n:@contrasted-acct%</ui-switch>
|
||||
<ui-switch v-model="showFullAcct">%i18n:common.show-full-acct%</ui-switch>
|
||||
<ui-switch v-model="iLikeSushi">%i18n:common.i-like-sushi%</ui-switch>
|
||||
</div>
|
||||
<ui-switch v-model="showPostFormOnTopOfTl">%i18n:@post-form-on-timeline%</ui-switch>
|
||||
<ui-switch v-model="suggestRecentHashtags">%i18n:@suggest-recent-hashtags%</ui-switch>
|
||||
<ui-switch v-model="showClockOnHeader">%i18n:@show-clock-on-header%</ui-switch>
|
||||
<ui-switch v-model="alwaysShowNsfw">%i18n:common.always-show-nsfw%</ui-switch>
|
||||
<ui-switch v-model="showReplyTarget">%i18n:@show-reply-target%</ui-switch>
|
||||
<ui-switch v-model="showMyRenotes">%i18n:@show-my-renotes%</ui-switch>
|
||||
<ui-switch v-model="showRenotedMyNotes">%i18n:@show-renoted-my-notes%</ui-switch>
|
||||
<ui-switch v-model="showLocalRenotes">%i18n:@show-local-renotes%</ui-switch>
|
||||
<ui-switch v-model="showMaps">%i18n:@show-maps%</ui-switch>
|
||||
<ui-switch v-model="disableAnimatedMfm">%i18n:common.disable-animated-mfm%</ui-switch>
|
||||
<ui-switch v-model="games_reversi_showBoardLabels">%i18n:common.show-reversi-board-labels%</ui-switch>
|
||||
<ui-switch v-model="games_reversi_useContrastStones">%i18n:common.use-contrast-reversi-stones%</ui-switch>
|
||||
</section>
|
||||
<section>
|
||||
<ui-switch v-model="showPostFormOnTopOfTl">%i18n:@post-form-on-timeline%</ui-switch>
|
||||
<ui-switch v-model="suggestRecentHashtags">%i18n:@suggest-recent-hashtags%</ui-switch>
|
||||
<ui-switch v-model="showClockOnHeader">%i18n:@show-clock-on-header%</ui-switch>
|
||||
<ui-switch v-model="alwaysShowNsfw">%i18n:common.always-show-nsfw%</ui-switch>
|
||||
<ui-switch v-model="showReplyTarget">%i18n:@show-reply-target%</ui-switch>
|
||||
<ui-switch v-model="showMyRenotes">%i18n:@show-my-renotes%</ui-switch>
|
||||
<ui-switch v-model="showRenotedMyNotes">%i18n:@show-renoted-my-notes%</ui-switch>
|
||||
<ui-switch v-model="showLocalRenotes">%i18n:@show-local-renotes%</ui-switch>
|
||||
<ui-switch v-model="showMaps">%i18n:@show-maps%</ui-switch>
|
||||
<ui-switch v-model="disableAnimatedMfm">%i18n:common.disable-animated-mfm%</ui-switch>
|
||||
<ui-switch v-model="games_reversi_showBoardLabels">%i18n:common.show-reversi-board-labels%</ui-switch>
|
||||
<ui-switch v-model="games_reversi_useContrastStones">%i18n:common.use-contrast-reversi-stones%</ui-switch>
|
||||
</section>
|
||||
</ui-card>
|
||||
|
||||
<ui-card class="web" v-show="page == 'web'">
|
||||
<div slot="title">%fa:volume-up% %i18n:@sound%</div>
|
||||
|
||||
<section>
|
||||
<header>%i18n:@navbar-position%</header>
|
||||
<ui-radio v-model="navbar" value="top">%i18n:@navbar-position-top%</ui-radio>
|
||||
<ui-radio v-model="navbar" value="left">%i18n:@navbar-position-left%</ui-radio>
|
||||
<ui-radio v-model="navbar" value="right">%i18n:@navbar-position-right%</ui-radio>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section class="web" v-show="page == 'web'">
|
||||
<h1>%i18n:@sound%</h1>
|
||||
<ui-switch v-model="enableSounds">
|
||||
%i18n:@enable-sounds%
|
||||
<span slot="desc">%i18n:@enable-sounds-desc%</span>
|
||||
</ui-switch>
|
||||
<label>%i18n:@volume%</label>
|
||||
<input type="range"
|
||||
v-model="soundVolume"
|
||||
:disabled="!enableSounds"
|
||||
max="1"
|
||||
step="0.1"
|
||||
/>
|
||||
<button class="ui button" @click="soundTest">%fa:volume-up% %i18n:@test%</button>
|
||||
</section>
|
||||
|
||||
<section class="web" v-show="page == 'web'">
|
||||
<h1>%i18n:@mobile%</h1>
|
||||
<ui-switch v-model="disableViaMobile">%i18n:@disable-via-mobile%</ui-switch>
|
||||
</section>
|
||||
|
||||
<section class="web" v-show="page == 'web'">
|
||||
<h1>%i18n:@language%</h1>
|
||||
<select v-model="lang" placeholder="%i18n:@pick-language%">
|
||||
<optgroup label="%i18n:@recommended%">
|
||||
<option value="">%i18n:@auto%</option>
|
||||
</optgroup>
|
||||
|
||||
<optgroup label="%i18n:@specify-language%">
|
||||
<option v-for="x in langs" :value="x[0]" :key="x[0]">{{ x[1] }}</option>
|
||||
</optgroup>
|
||||
</select>
|
||||
<div class="none ui info">
|
||||
<p>%fa:info-circle%%i18n:@language-desc%</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="web" v-show="page == 'web'">
|
||||
<h1>%i18n:@cache%</h1>
|
||||
<button class="ui button" @click="clean">%i18n:@clean-cache%</button>
|
||||
<div class="none ui info warn">
|
||||
<p>%fa:exclamation-triangle%%i18n:@cache-warn%</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="notification" v-show="page == 'notification'">
|
||||
<h1>%i18n:@notification%</h1>
|
||||
<ui-switch v-model="$store.state.i.settings.autoWatch" @change="onChangeAutoWatch">
|
||||
%i18n:@auto-watch%
|
||||
<span slot="desc">%i18n:@auto-watch-desc%</span>
|
||||
</ui-switch>
|
||||
</section>
|
||||
|
||||
<section class="drive" v-show="page == 'drive'">
|
||||
<h1>%i18n:@drive%</h1>
|
||||
<x-drive/>
|
||||
</section>
|
||||
|
||||
<section class="hashtags" v-show="page == 'hashtags'">
|
||||
<h1>%i18n:@tags%</h1>
|
||||
<x-tags/>
|
||||
</section>
|
||||
|
||||
<section class="mute" v-show="page == 'mute'">
|
||||
<h1>%i18n:@mute%</h1>
|
||||
<x-mute/>
|
||||
</section>
|
||||
|
||||
<section class="apps" v-show="page == 'apps'">
|
||||
<h1>%i18n:@apps%</h1>
|
||||
<x-apps/>
|
||||
</section>
|
||||
|
||||
<section class="twitter" v-show="page == 'twitter'">
|
||||
<h1>Twitter</h1>
|
||||
<mk-twitter-setting/>
|
||||
</section>
|
||||
|
||||
<section class="password" v-show="page == 'security'">
|
||||
<h1>%i18n:@password%</h1>
|
||||
<x-password/>
|
||||
</section>
|
||||
|
||||
<section class="2fa" v-show="page == 'security'">
|
||||
<h1>%i18n:@2fa%</h1>
|
||||
<x-2fa/>
|
||||
</section>
|
||||
|
||||
<section class="signin" v-show="page == 'security'">
|
||||
<h1>%i18n:@signin%</h1>
|
||||
<x-signins/>
|
||||
</section>
|
||||
|
||||
<section class="api" v-show="page == 'api'">
|
||||
<h1>API</h1>
|
||||
<x-api/>
|
||||
</section>
|
||||
|
||||
<section class="other" v-show="page == 'other'">
|
||||
<h1>%i18n:@about%</h1>
|
||||
<p v-if="meta">%i18n:@operator%: <i><a :href="meta.maintainer.url" target="_blank">{{ meta.maintainer.name }}</a></i></p>
|
||||
</section>
|
||||
|
||||
<section class="other" v-show="page == 'other'">
|
||||
<h1>%i18n:@update%</h1>
|
||||
<p>
|
||||
<span>%i18n:@version% <i>{{ version }}</i></span>
|
||||
<template v-if="latestVersion !== undefined">
|
||||
<br>
|
||||
<span>%i18n:@latest-version% <i>{{ latestVersion ? latestVersion : version }}</i></span>
|
||||
</template>
|
||||
</p>
|
||||
<button class="ui button block" @click="checkForUpdate" :disabled="checkingForUpdate">
|
||||
<template v-if="checkingForUpdate">%i18n:@update-checking%<mk-ellipsis/></template>
|
||||
<template v-else>%i18n:@do-update%</template>
|
||||
</button>
|
||||
<details>
|
||||
<summary>%i18n:@update-settings%</summary>
|
||||
<ui-switch v-model="preventUpdate">
|
||||
%i18n:@prevent-update%
|
||||
<span slot="desc">%i18n:@prevent-update-desc%</span>
|
||||
<ui-switch v-model="enableSounds">
|
||||
%i18n:@enable-sounds%
|
||||
<span slot="desc">%i18n:@enable-sounds-desc%</span>
|
||||
</ui-switch>
|
||||
</details>
|
||||
</section>
|
||||
<label>%i18n:@volume%</label>
|
||||
<input type="range"
|
||||
v-model="soundVolume"
|
||||
:disabled="!enableSounds"
|
||||
max="1"
|
||||
step="0.1"
|
||||
/>
|
||||
<ui-button @click="soundTest">%fa:volume-up% %i18n:@test%</ui-button>
|
||||
</section>
|
||||
</ui-card>
|
||||
|
||||
<section class="other" v-show="page == 'other'">
|
||||
<h1>%i18n:@advanced-settings%</h1>
|
||||
<ui-switch v-model="debug">
|
||||
%i18n:@debug-mode%
|
||||
<span slot="desc">%i18n:@debug-mode-desc%</span>
|
||||
</ui-switch>
|
||||
<ui-switch v-model="enableExperimentalFeatures">
|
||||
%i18n:@experimental%
|
||||
<span slot="desc">%i18n:@experimental-desc%</span>
|
||||
</ui-switch>
|
||||
</section>
|
||||
<ui-card class="web" v-show="page == 'web'">
|
||||
<div slot="title">%fa:language% %i18n:@language%</div>
|
||||
<section class="fit-top">
|
||||
<ui-select v-model="lang" placeholder="%i18n:@pick-language%">
|
||||
<optgroup label="%i18n:@recommended%">
|
||||
<option value="">%i18n:@auto%</option>
|
||||
</optgroup>
|
||||
|
||||
<optgroup label="%i18n:@specify-language%">
|
||||
<option v-for="x in langs" :value="x[0]" :key="x[0]">{{ x[1] }}</option>
|
||||
</optgroup>
|
||||
</ui-select>
|
||||
<div class="none ui info">
|
||||
<p>%fa:info-circle%%i18n:@language-desc%</p>
|
||||
</div>
|
||||
</section>
|
||||
</ui-card>
|
||||
|
||||
<ui-card class="web" v-show="page == 'web'">
|
||||
<div slot="title">%fa:trash-alt R% %i18n:@cache%</div>
|
||||
<section>
|
||||
<ui-button @click="clean">%i18n:@clean-cache%</ui-button>
|
||||
<div class="none ui info warn">
|
||||
<p>%fa:exclamation-triangle%%i18n:@cache-warn%</p>
|
||||
</div>
|
||||
</section>
|
||||
</ui-card>
|
||||
|
||||
<ui-card class="notification" v-show="page == 'notification'">
|
||||
<div slot="title">%fa:bell R% %i18n:@notification%</div>
|
||||
<section>
|
||||
<ui-switch v-model="$store.state.i.settings.autoWatch" @change="onChangeAutoWatch">
|
||||
%i18n:@auto-watch%
|
||||
<span slot="desc">%i18n:@auto-watch-desc%</span>
|
||||
</ui-switch>
|
||||
</section>
|
||||
</ui-card>
|
||||
|
||||
<ui-card class="drive" v-show="page == 'drive'">
|
||||
<div slot="title">%fa:cloud% %i18n:@drive%</div>
|
||||
<section>
|
||||
<x-drive/>
|
||||
</section>
|
||||
</ui-card>
|
||||
|
||||
<ui-card class="hashtags" v-show="page == 'hashtags'">
|
||||
<div slot="title">%fa:hashtag% %i18n:@tags%</div>
|
||||
<section>
|
||||
<x-tags/>
|
||||
</section>
|
||||
</ui-card>
|
||||
|
||||
<ui-card class="mute" v-show="page == 'mute'">
|
||||
<div slot="title">%fa:ban% %i18n:@mute%</div>
|
||||
<section>
|
||||
<x-mute/>
|
||||
</section>
|
||||
</ui-card>
|
||||
|
||||
<ui-card class="apps" v-show="page == 'apps'">
|
||||
<div slot="title">%fa:puzzle-piece% %i18n:@apps%</div>
|
||||
<section>
|
||||
<x-apps/>
|
||||
</section>
|
||||
</ui-card>
|
||||
|
||||
<ui-card class="password" v-show="page == 'security'">
|
||||
<div slot="title">%fa:unlock-alt% %i18n:@password%</div>
|
||||
<section>
|
||||
<x-password/>
|
||||
</section>
|
||||
</ui-card>
|
||||
|
||||
<ui-card class="2fa" v-show="page == 'security'">
|
||||
<div slot="title">%fa:mobile-alt% %i18n:@2fa%</div>
|
||||
<section>
|
||||
<x-2fa/>
|
||||
</section>
|
||||
</ui-card>
|
||||
|
||||
<ui-card class="signin" v-show="page == 'security'">
|
||||
<div slot="title">%fa:sign-in-alt% %i18n:@signin%</div>
|
||||
<section>
|
||||
<x-signins/>
|
||||
</section>
|
||||
</ui-card>
|
||||
|
||||
<ui-card class="api" v-show="page == 'api'">
|
||||
<div slot="title">%fa:key% API</div>
|
||||
<section class="fit-top">
|
||||
<x-api/>
|
||||
</section>
|
||||
</ui-card>
|
||||
|
||||
<ui-card class="other" v-show="page == 'other'">
|
||||
<div slot="title">%fa:info-circle% %i18n:@about%</div>
|
||||
<section>
|
||||
<p v-if="meta">%i18n:@operator%: <i><a :href="meta.maintainer.url" target="_blank">{{ meta.maintainer.name }}</a></i></p>
|
||||
</section>
|
||||
</ui-card>
|
||||
|
||||
<ui-card class="other" v-show="page == 'other'">
|
||||
<div slot="title">%fa:sync-alt% %i18n:@update%</div>
|
||||
<section>
|
||||
<p>
|
||||
<span>%i18n:@version% <i>{{ version }}</i></span>
|
||||
<template v-if="latestVersion !== undefined">
|
||||
<br>
|
||||
<span>%i18n:@latest-version% <i>{{ latestVersion ? latestVersion : version }}</i></span>
|
||||
</template>
|
||||
</p>
|
||||
<button class="ui button block" @click="checkForUpdate" :disabled="checkingForUpdate">
|
||||
<template v-if="checkingForUpdate">%i18n:@update-checking%<mk-ellipsis/></template>
|
||||
<template v-else>%i18n:@do-update%</template>
|
||||
</button>
|
||||
<details>
|
||||
<summary>%i18n:@update-settings%</summary>
|
||||
<ui-switch v-model="preventUpdate">
|
||||
%i18n:@prevent-update%
|
||||
<span slot="desc">%i18n:@prevent-update-desc%</span>
|
||||
</ui-switch>
|
||||
</details>
|
||||
</section>
|
||||
</ui-card>
|
||||
|
||||
<ui-card class="other" v-show="page == 'other'">
|
||||
<div slot="title">%fa:cogs% %i18n:@advanced-settings%</div>
|
||||
<section>
|
||||
<ui-switch v-model="debug">
|
||||
%i18n:@debug-mode%
|
||||
<span slot="desc">%i18n:@debug-mode-desc%</span>
|
||||
</ui-switch>
|
||||
<ui-switch v-model="enableExperimentalFeatures">
|
||||
%i18n:@experimental%
|
||||
<span slot="desc">%i18n:@experimental-desc%</span>
|
||||
</ui-switch>
|
||||
</section>
|
||||
</ui-card>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import XProfile from './settings.profile.vue';
|
||||
import XMute from './settings.mute.vue';
|
||||
import XPassword from './settings.password.vue';
|
||||
import X2fa from './settings.2fa.vue';
|
||||
|
@ -253,7 +291,6 @@ import checkForUpdate from '../../../common/scripts/check-for-update';
|
|||
|
||||
export default Vue.extend({
|
||||
components: {
|
||||
XProfile,
|
||||
XMute,
|
||||
XPassword,
|
||||
X2fa,
|
||||
|
@ -295,6 +332,11 @@ export default Vue.extend({
|
|||
set(value) { this.$store.commit('device/set', { key: 'autoPopout', value }); }
|
||||
},
|
||||
|
||||
deckNav: {
|
||||
get() { return this.$store.state.settings.deckNav; },
|
||||
set(value) { this.$store.commit('settings/set', { key: 'deckNav', value }); }
|
||||
},
|
||||
|
||||
darkmode: {
|
||||
get() { return this.$store.state.device.darkmode; },
|
||||
set(value) { this.$store.commit('device/set', { key: 'darkmode', value }); }
|
||||
|
@ -438,11 +480,6 @@ export default Vue.extend({
|
|||
disableAnimatedMfm: {
|
||||
get() { return this.$store.state.settings.disableAnimatedMfm; },
|
||||
set(value) { this.$store.dispatch('settings/set', { key: 'disableAnimatedMfm', value }); }
|
||||
},
|
||||
|
||||
disableViaMobile: {
|
||||
get() { return this.$store.state.settings.disableViaMobile; },
|
||||
set(value) { this.$store.dispatch('settings/set', { key: 'disableViaMobile', value }); }
|
||||
}
|
||||
},
|
||||
created() {
|
||||
|
@ -546,34 +583,10 @@ export default Vue.extend({
|
|||
height 100%
|
||||
flex auto
|
||||
overflow auto
|
||||
background var(--bg)
|
||||
|
||||
> section
|
||||
margin 32px
|
||||
color var(--text)
|
||||
|
||||
> h1
|
||||
margin 0 0 1em 0
|
||||
padding 0 0 8px 0
|
||||
font-size 1em
|
||||
border-bottom solid 1px var(--faceDivider)
|
||||
|
||||
&, >>> *
|
||||
.ui.button.block
|
||||
margin 16px 0
|
||||
|
||||
> section
|
||||
margin 32px 0
|
||||
|
||||
> h2
|
||||
margin 0 0 1em 0
|
||||
padding 0 0 8px 0
|
||||
font-size 1em
|
||||
color var(--text)
|
||||
border-bottom solid 1px var(--faceDivider)
|
||||
|
||||
> .web
|
||||
> .div
|
||||
border-bottom solid 1px var(--faceDivider)
|
||||
margin 16px 0
|
||||
|
||||
</style>
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
<template>
|
||||
<div class="dnpfarvgbnfmyzbdquhhzyxcmstpdqzs" :class="{ naked, narrow, active, isStacked, draghover, dragging, dropready }"
|
||||
@dragover.prevent.stop="onDragover"
|
||||
@dragenter.prevent="onDragenter"
|
||||
@dragleave="onDragleave"
|
||||
@drop.prevent.stop="onDrop">
|
||||
<header :class="{ indicate: count > 0 }"
|
||||
|
@ -16,7 +15,8 @@
|
|||
</button>
|
||||
<slot name="header"></slot>
|
||||
<span class="count" v-if="count > 0">({{ count }})</span>
|
||||
<button class="menu" ref="menu" @click.stop="showMenu">%fa:caret-down%</button>
|
||||
<button v-if="!isTemporaryColumn" class="menu" ref="menu" @click.stop="showMenu">%fa:caret-down%</button>
|
||||
<button v-else class="close" @click.stop="close">%fa:times%</button>
|
||||
</header>
|
||||
<div ref="body" v-show="active">
|
||||
<slot></slot>
|
||||
|
@ -34,11 +34,13 @@ export default Vue.extend({
|
|||
props: {
|
||||
column: {
|
||||
type: Object,
|
||||
required: true
|
||||
required: false,
|
||||
default: null
|
||||
},
|
||||
isStacked: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
required: false,
|
||||
default: false
|
||||
},
|
||||
name: {
|
||||
type: String,
|
||||
|
@ -61,6 +63,12 @@ export default Vue.extend({
|
|||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
isTemporaryColumn(): boolean {
|
||||
return this.column == null;
|
||||
}
|
||||
},
|
||||
|
||||
inject: {
|
||||
getColumnVm: { from: 'getColumnVm' }
|
||||
},
|
||||
|
@ -96,14 +104,20 @@ export default Vue.extend({
|
|||
|
||||
mounted() {
|
||||
this.$refs.body.addEventListener('scroll', this.onScroll, { passive: true });
|
||||
this.$root.$on('deck.column.dragStart', this.onOtherDragStart);
|
||||
this.$root.$on('deck.column.dragEnd', this.onOtherDragEnd);
|
||||
|
||||
if (!this.isTemporaryColumn) {
|
||||
this.$root.$on('deck.column.dragStart', this.onOtherDragStart);
|
||||
this.$root.$on('deck.column.dragEnd', this.onOtherDragEnd);
|
||||
}
|
||||
},
|
||||
|
||||
beforeDestroy() {
|
||||
this.$refs.body.removeEventListener('scroll', this.onScroll);
|
||||
this.$root.$off('deck.column.dragStart', this.onOtherDragStart);
|
||||
this.$root.$off('deck.column.dragEnd', this.onOtherDragEnd);
|
||||
|
||||
if (!this.isTemporaryColumn) {
|
||||
this.$root.$off('deck.column.dragStart', this.onOtherDragStart);
|
||||
this.$root.$off('deck.column.dragEnd', this.onOtherDragEnd);
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
|
@ -203,6 +217,7 @@ export default Vue.extend({
|
|||
},
|
||||
|
||||
onContextmenu(e) {
|
||||
if (this.isTemporaryColumn) return;
|
||||
contextmenu((this as any).os)(e, this.getMenu());
|
||||
},
|
||||
|
||||
|
@ -214,6 +229,13 @@ export default Vue.extend({
|
|||
});
|
||||
},
|
||||
|
||||
close() {
|
||||
this.$store.commit('device/set', {
|
||||
key: 'deckTemporaryColumn',
|
||||
value: null
|
||||
});
|
||||
},
|
||||
|
||||
goTop() {
|
||||
this.$refs.body.scrollTo({
|
||||
top: 0,
|
||||
|
@ -222,6 +244,12 @@ export default Vue.extend({
|
|||
},
|
||||
|
||||
onDragstart(e) {
|
||||
// テンポラリカラムはドラッグさせない
|
||||
if (this.isTemporaryColumn) {
|
||||
e.preventDefault();
|
||||
return;
|
||||
}
|
||||
|
||||
e.dataTransfer.effectAllowed = 'move';
|
||||
e.dataTransfer.setData('mk-deck-column', this.column.id);
|
||||
this.dragging = true;
|
||||
|
@ -232,6 +260,12 @@ export default Vue.extend({
|
|||
},
|
||||
|
||||
onDragover(e) {
|
||||
// テンポラリカラムにはドロップさせない
|
||||
if (this.isTemporaryColumn) {
|
||||
e.dataTransfer.dropEffect = 'none';
|
||||
return;
|
||||
}
|
||||
|
||||
// 自分自身がドラッグされている場合
|
||||
if (this.dragging) {
|
||||
// 自分自身にはドロップさせない
|
||||
|
@ -242,9 +276,7 @@ export default Vue.extend({
|
|||
const isDeckColumn = e.dataTransfer.types[0] == 'mk-deck-column';
|
||||
|
||||
e.dataTransfer.dropEffect = isDeckColumn ? 'move' : 'none';
|
||||
},
|
||||
|
||||
onDragenter() {
|
||||
if (!this.dragging) this.draghover = true;
|
||||
},
|
||||
|
||||
|
@ -349,6 +381,7 @@ export default Vue.extend({
|
|||
|
||||
> .toggleActive
|
||||
> .menu
|
||||
> .close
|
||||
padding 0
|
||||
width $header-height
|
||||
line-height $header-height
|
||||
|
@ -365,6 +398,7 @@ export default Vue.extend({
|
|||
margin-left -16px
|
||||
|
||||
> .menu
|
||||
> .close
|
||||
margin-left auto
|
||||
margin-right -16px
|
||||
|
||||
|
|
69
src/client/app/desktop/views/pages/deck/deck.note-column.vue
Normal file
69
src/client/app/desktop/views/pages/deck/deck.note-column.vue
Normal file
|
@ -0,0 +1,69 @@
|
|||
<template>
|
||||
<x-column>
|
||||
<span slot="header">
|
||||
%fa:comment-alt R%<span>{{ title }}</span>
|
||||
</span>
|
||||
|
||||
<div class="rvtscbadixhhbsczoorqoaygovdeecsx" v-if="note">
|
||||
<div class="is-remote" v-if="note.user.host != null">%fa:exclamation-triangle% %i18n:@is-remote%<a :href="note.url || note.uri" target="_blank">%i18n:@view-remote%</a></div>
|
||||
<x-note :note="note" :detail="true" :mini="true"/>
|
||||
</div>
|
||||
</x-column>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import XColumn from './deck.column.vue';
|
||||
import XNotes from './deck.notes.vue';
|
||||
import XNote from '../../components/note.vue';
|
||||
|
||||
export default Vue.extend({
|
||||
components: {
|
||||
XColumn,
|
||||
XNotes,
|
||||
XNote
|
||||
},
|
||||
|
||||
props: {
|
||||
noteId: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
note: null,
|
||||
fetching: true
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
title(): string {
|
||||
return this.note ? Vue.filter('userName')(this.note.user) : '';
|
||||
}
|
||||
},
|
||||
|
||||
created() {
|
||||
(this as any).api('notes/show', { noteId: this.noteId }).then(note => {
|
||||
this.note = note;
|
||||
this.fetching = false;
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.rvtscbadixhhbsczoorqoaygovdeecsx
|
||||
> .is-remote
|
||||
padding 8px 16px
|
||||
font-size 12px
|
||||
|
||||
&.is-remote
|
||||
color var(--remoteInfoFg)
|
||||
background var(--remoteInfoBg)
|
||||
|
||||
> a
|
||||
font-weight bold
|
||||
|
||||
</style>
|
|
@ -1,71 +0,0 @@
|
|||
<template>
|
||||
<div class="fnlfosztlhtptnongximhlbykxblytcq">
|
||||
<mk-avatar class="avatar" :user="note.user"/>
|
||||
<div class="main">
|
||||
<mk-note-header class="header" :note="note" :mini="true"/>
|
||||
<div class="body">
|
||||
<mk-sub-note-content class="text" :note="note"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
|
||||
export default Vue.extend({
|
||||
props: {
|
||||
note: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
// TODO
|
||||
truncate: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.fnlfosztlhtptnongximhlbykxblytcq
|
||||
display flex
|
||||
padding 16px
|
||||
font-size 10px
|
||||
background var(--subNoteBg)
|
||||
|
||||
&.smart
|
||||
> .main
|
||||
width 100%
|
||||
|
||||
> header
|
||||
align-items center
|
||||
|
||||
> .avatar
|
||||
flex-shrink 0
|
||||
display block
|
||||
margin 0 8px 0 0
|
||||
width 38px
|
||||
height 38px
|
||||
border-radius 8px
|
||||
|
||||
> .main
|
||||
flex 1
|
||||
min-width 0
|
||||
|
||||
> .header
|
||||
margin-bottom 2px
|
||||
|
||||
> .body
|
||||
|
||||
> .text
|
||||
margin 0
|
||||
padding 0
|
||||
color var(--subNoteText)
|
||||
|
||||
pre
|
||||
max-height 120px
|
||||
font-size 80%
|
||||
|
||||
</style>
|
|
@ -1,323 +0,0 @@
|
|||
<template>
|
||||
<div
|
||||
v-if="!mediaView"
|
||||
v-show="appearNote.deletedAt == null"
|
||||
:tabindex="appearNote.deletedAt == null ? '-1' : null"
|
||||
class="zyjjkidcqjnlegkqebitfviomuqmseqk"
|
||||
:class="{ renote: isRenote }"
|
||||
v-hotkey="keymap"
|
||||
:title="title"
|
||||
>
|
||||
<div class="reply-to" v-if="appearNote.reply && (!$store.getters.isSignedIn || $store.state.settings.showReplyTarget)">
|
||||
<x-sub :note="appearNote.reply"/>
|
||||
</div>
|
||||
<div class="renote" v-if="isRenote">
|
||||
<mk-avatar class="avatar" :user="note.user"/>
|
||||
%fa:retweet%
|
||||
<span>{{ '%i18n:@reposted-by%'.substr(0, '%i18n:@reposted-by%'.indexOf('{')) }}</span>
|
||||
<router-link class="name" :to="note.user | userPage">{{ note.user | userName }}</router-link>
|
||||
<span>{{ '%i18n:@reposted-by%'.substr('%i18n:@reposted-by%'.indexOf('}') + 1) }}</span>
|
||||
<mk-time :time="note.createdAt"/>
|
||||
</div>
|
||||
<article>
|
||||
<mk-avatar class="avatar" :user="appearNote.user"/>
|
||||
<div class="main">
|
||||
<mk-note-header class="header" :note="appearNote" :mini="true"/>
|
||||
<div class="body">
|
||||
<p v-if="appearNote.cw != null" class="cw">
|
||||
<span class="text" v-if="appearNote.cw != ''">{{ appearNote.cw }}</span>
|
||||
<mk-cw-button v-model="showContent"/>
|
||||
</p>
|
||||
<div class="content" v-show="appearNote.cw == null || showContent">
|
||||
<div class="text">
|
||||
<span v-if="appearNote.isHidden" style="opacity: 0.5">(%i18n:@private%)</span>
|
||||
<a class="reply" v-if="appearNote.reply">%fa:reply%</a>
|
||||
<misskey-flavored-markdown v-if="appearNote.text" :text="appearNote.text" :i="$store.state.i"/>
|
||||
<a class="rp" v-if="appearNote.renote != null">RP:</a>
|
||||
</div>
|
||||
<div class="files" v-if="appearNote.files.length > 0">
|
||||
<mk-media-list :media-list="appearNote.files"/>
|
||||
</div>
|
||||
<mk-poll v-if="appearNote.poll" :note="appearNote" ref="pollViewer"/>
|
||||
<a class="location" v-if="appearNote.geo" :href="`https://maps.google.com/maps?q=${appearNote.geo.coordinates[1]},${appearNote.geo.coordinates[0]}`" target="_blank">%fa:map-marker-alt% %i18n:@location%</a>
|
||||
<div class="renote" v-if="appearNote.renote">
|
||||
<mk-note-preview :note="appearNote.renote" :mini="true"/>
|
||||
</div>
|
||||
<mk-url-preview v-for="url in urls" :url="url" :key="url" :detail="false" :mini="true"/>
|
||||
</div>
|
||||
<span class="app" v-if="appearNote.app">via <b>{{ appearNote.app.name }}</b></span>
|
||||
</div>
|
||||
<footer>
|
||||
<mk-reactions-viewer :note="appearNote" ref="reactionsViewer"/>
|
||||
<button @click="reply()">
|
||||
<template v-if="appearNote.reply">%fa:reply-all%</template>
|
||||
<template v-else>%fa:reply%</template>
|
||||
</button>
|
||||
<button @click="renote()" title="Renote">%fa:retweet%</button>
|
||||
<button :class="{ reacted: appearNote.myReaction != null }" @click="react()" ref="reactButton">%fa:plus%</button>
|
||||
<button class="menu" @click="menu()" ref="menuButton">%fa:ellipsis-h%</button>
|
||||
</footer>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
<div v-else class="srwrkujossgfuhrbnvqkybtzxpblgchi">
|
||||
<div v-if="note.files.length > 0">
|
||||
<mk-media-list :media-list="note.files"/>
|
||||
</div>
|
||||
<div v-if="note.renote && note.renote.files.length > 0">
|
||||
<mk-media-list :media-list="note.renote.files"/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import MkPostFormWindow from '../../components/post-form-window.vue';
|
||||
import MkRenoteFormWindow from '../../components/renote-form-window.vue';
|
||||
import XSub from './deck.note.sub.vue';
|
||||
import noteMixin from '../../../../common/scripts/note-mixin';
|
||||
import noteSubscriber from '../../../../common/scripts/note-subscriber';
|
||||
|
||||
export default Vue.extend({
|
||||
components: {
|
||||
XSub
|
||||
},
|
||||
|
||||
mixins: [
|
||||
noteMixin(),
|
||||
noteSubscriber('note')
|
||||
],
|
||||
|
||||
props: {
|
||||
note: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
mediaView: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.srwrkujossgfuhrbnvqkybtzxpblgchi
|
||||
font-size 13px
|
||||
margin 4px 12px
|
||||
|
||||
&:first-child
|
||||
margin-top 12px
|
||||
|
||||
&:last-child
|
||||
margin-bottom 12px
|
||||
|
||||
.zyjjkidcqjnlegkqebitfviomuqmseqk
|
||||
font-size 13px
|
||||
border-bottom solid 1px var(--faceDivider)
|
||||
|
||||
&:focus
|
||||
z-index 1
|
||||
|
||||
&:after
|
||||
content ""
|
||||
pointer-events none
|
||||
position absolute
|
||||
top 2px
|
||||
right 2px
|
||||
bottom 2px
|
||||
left 2px
|
||||
border 2px solid var(--primaryAlpha03)
|
||||
border-radius 4px
|
||||
|
||||
&:last-of-type
|
||||
border-bottom none
|
||||
|
||||
&.smart
|
||||
> article
|
||||
> .main
|
||||
> header
|
||||
align-items center
|
||||
margin-bottom 4px
|
||||
|
||||
> .renote
|
||||
display flex
|
||||
align-items center
|
||||
padding 8px 16px 0 16px
|
||||
line-height 28px
|
||||
white-space pre
|
||||
color var(--renoteText)
|
||||
background linear-gradient(to bottom, var(--renoteGradient) 0%, var(--face) 100%)
|
||||
|
||||
.avatar
|
||||
flex-shrink 0
|
||||
display inline-block
|
||||
width 20px
|
||||
height 20px
|
||||
margin 0 8px 0 0
|
||||
border-radius 6px
|
||||
|
||||
[data-fa]
|
||||
margin-right 4px
|
||||
|
||||
> span
|
||||
flex-shrink 0
|
||||
|
||||
&:last-of-type
|
||||
margin-right 8px
|
||||
|
||||
.name
|
||||
overflow hidden
|
||||
flex-shrink 1
|
||||
text-overflow ellipsis
|
||||
white-space nowrap
|
||||
font-weight bold
|
||||
|
||||
> .mk-time
|
||||
display block
|
||||
margin-left auto
|
||||
flex-shrink 0
|
||||
font-size 0.9em
|
||||
|
||||
& + article
|
||||
padding-top 8px
|
||||
|
||||
> article
|
||||
display flex
|
||||
padding 16px 16px 4px
|
||||
|
||||
> .avatar
|
||||
flex-shrink 0
|
||||
display block
|
||||
margin 0 10px 8px 0
|
||||
width 42px
|
||||
height 42px
|
||||
border-radius 6px
|
||||
//position -webkit-sticky
|
||||
//position sticky
|
||||
//top 62px
|
||||
|
||||
> .main
|
||||
flex 1
|
||||
min-width 0
|
||||
|
||||
> .body
|
||||
|
||||
> .cw
|
||||
cursor default
|
||||
display block
|
||||
margin 0
|
||||
padding 0
|
||||
overflow-wrap break-word
|
||||
color var(--noteText)
|
||||
|
||||
> .text
|
||||
margin-right 8px
|
||||
|
||||
> .content
|
||||
|
||||
> .text
|
||||
display block
|
||||
margin 0
|
||||
padding 0
|
||||
overflow-wrap break-word
|
||||
color var(--noteText)
|
||||
|
||||
>>> .title
|
||||
display block
|
||||
margin-bottom 4px
|
||||
padding 4px
|
||||
font-size 90%
|
||||
text-align center
|
||||
background var(--mfmTitleBg)
|
||||
border-radius 4px
|
||||
|
||||
>>> .code
|
||||
margin 8px 0
|
||||
|
||||
>>> .quote
|
||||
margin 8px
|
||||
padding 6px 12px
|
||||
color var(--mfmQuote)
|
||||
border-left solid 3px var(--mfmQuoteLine)
|
||||
|
||||
> .reply
|
||||
margin-right 8px
|
||||
color var(--noteText)
|
||||
|
||||
> .rp
|
||||
margin-left 4px
|
||||
font-style oblique
|
||||
color var(--renoteText)
|
||||
|
||||
[data-is-me]:after
|
||||
content "you"
|
||||
padding 0 4px
|
||||
margin-left 4px
|
||||
font-size 80%
|
||||
color var(--primaryForeground)
|
||||
background var(--primary)
|
||||
border-radius 4px
|
||||
|
||||
.mk-url-preview
|
||||
margin-top 8px
|
||||
|
||||
> .files
|
||||
> img
|
||||
display block
|
||||
max-width 100%
|
||||
|
||||
> .location
|
||||
margin 4px 0
|
||||
font-size 12px
|
||||
color #ccc
|
||||
|
||||
> .map
|
||||
width 100%
|
||||
height 200px
|
||||
|
||||
&:empty
|
||||
display none
|
||||
|
||||
> .mk-poll
|
||||
font-size 80%
|
||||
|
||||
> .renote
|
||||
margin 8px 0
|
||||
|
||||
> *
|
||||
padding 16px
|
||||
border dashed 1px var(--quoteBorder)
|
||||
border-radius 8px
|
||||
|
||||
> .app
|
||||
font-size 12px
|
||||
color #ccc
|
||||
|
||||
> footer
|
||||
> button
|
||||
margin 0
|
||||
padding 4px 8px 8px 8px
|
||||
background transparent
|
||||
border none
|
||||
box-shadow none
|
||||
font-size 1em
|
||||
color var(--noteActions)
|
||||
cursor pointer
|
||||
|
||||
&:not(:last-child)
|
||||
margin-right 28px
|
||||
|
||||
&:hover
|
||||
color var(--noteActionsHover)
|
||||
|
||||
> .count
|
||||
display inline
|
||||
margin 0 0 0 8px
|
||||
color #999
|
||||
|
||||
&.reacted
|
||||
color var(--primary)
|
||||
|
||||
</style>
|
|
@ -17,7 +17,7 @@
|
|||
<!--<transition-group name="mk-notes" class="transition">-->
|
||||
<div class="notes">
|
||||
<template v-for="(note, i) in _notes">
|
||||
<x-note :note="note" :key="note.id" @update:note="onNoteUpdated(i, $event)" :media-view="mediaView"/>
|
||||
<x-note :note="note" :key="note.id" @update:note="onNoteUpdated(i, $event)" :media-view="mediaView" :mini="true"/>
|
||||
<p class="date" :key="note.id + '_date'" v-if="i != notes.length - 1 && note._date != _notes[i + 1]._date">
|
||||
<span>%fa:angle-up%{{ note._datetext }}</span>
|
||||
<span>%fa:angle-down%{{ _notes[i + 1]._datetext }}</span>
|
||||
|
@ -38,7 +38,7 @@
|
|||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
|
||||
import XNote from './deck.note.vue';
|
||||
import XNote from '../../components/note.vue';
|
||||
|
||||
const displayLimit = 20;
|
||||
|
||||
|
@ -220,7 +220,7 @@ export default Vue.extend({
|
|||
display block
|
||||
margin 0
|
||||
line-height 32px
|
||||
font-size 14px
|
||||
font-size 12px
|
||||
text-align center
|
||||
color var(--dateDividerFg)
|
||||
background var(--dateDividerBg)
|
||||
|
|
|
@ -66,15 +66,15 @@
|
|||
</div>
|
||||
|
||||
<template v-if="notification.type == 'quote'">
|
||||
<x-note :note="notification.note" @update:note="onNoteUpdated"/>
|
||||
<x-note :note="notification.note" @update:note="onNoteUpdated" :mini="true"/>
|
||||
</template>
|
||||
|
||||
<template v-if="notification.type == 'reply'">
|
||||
<x-note :note="notification.note" @update:note="onNoteUpdated"/>
|
||||
<x-note :note="notification.note" @update:note="onNoteUpdated" :mini="true"/>
|
||||
</template>
|
||||
|
||||
<template v-if="notification.type == 'mention'">
|
||||
<x-note :note="notification.note" @update:note="onNoteUpdated"/>
|
||||
<x-note :note="notification.note" @update:note="onNoteUpdated" :mini="true"/>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -82,7 +82,7 @@
|
|||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import getNoteSummary from '../../../../../../misc/get-note-summary';
|
||||
import XNote from './deck.note.vue';
|
||||
import XNote from '../../components/note.vue';
|
||||
|
||||
export default Vue.extend({
|
||||
components: {
|
||||
|
|
261
src/client/app/desktop/views/pages/deck/deck.user-column.vue
Normal file
261
src/client/app/desktop/views/pages/deck/deck.user-column.vue
Normal file
|
@ -0,0 +1,261 @@
|
|||
<template>
|
||||
<x-column>
|
||||
<span slot="header">
|
||||
%fa:user%<span>{{ title }}</span>
|
||||
</span>
|
||||
|
||||
<div class="zubukjlciycdsyynicqrnlsmdwmymzqu" v-if="user">
|
||||
<div class="is-remote" v-if="user.host != null">%fa:exclamation-triangle% %i18n:@is-remote%<a :href="user.url || user.uri" target="_blank">%i18n:@view-remote%</a></div>
|
||||
<header :style="bannerStyle">
|
||||
<div>
|
||||
<mk-follow-button v-if="$store.getters.isSignedIn && user.id != $store.state.i.id" :user="user" class="follow"/>
|
||||
<mk-avatar class="avatar" :user="user" :disable-preview="true"/>
|
||||
<span class="name">{{ user | userName }}</span>
|
||||
<span class="acct">@{{ user | acct }}</span>
|
||||
</div>
|
||||
</header>
|
||||
<div class="info">
|
||||
<div class="description">
|
||||
<misskey-flavored-markdown v-if="user.description" :text="user.description" :i="$store.state.i"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pinned" v-if="user.pinnedNotes && user.pinnedNotes.length > 0">
|
||||
<p>%fa:thumbtack% %i18n:@pinned-notes%</p>
|
||||
<div class="notes">
|
||||
<x-note v-for="n in user.pinnedNotes" :key="n.id" :note="n" :mini="true"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="images" v-if="images.length > 0">
|
||||
<router-link v-for="image in images" :style="`background-image: url(${image.thumbnailUrl})`" :key="`${image.id}:${image._note.id}`" :to="image._note | notePage"></router-link>
|
||||
</div>
|
||||
<div class="tl">
|
||||
<x-notes ref="timeline" :more="existMore ? fetchMoreNotes : null"/>
|
||||
</div>
|
||||
</div>
|
||||
</x-column>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import parseAcct from '../../../../../../misc/acct/parse';
|
||||
import XColumn from './deck.column.vue';
|
||||
import XNotes from './deck.notes.vue';
|
||||
import XNote from '../../components/note.vue';
|
||||
|
||||
const fetchLimit = 10;
|
||||
|
||||
export default Vue.extend({
|
||||
components: {
|
||||
XColumn,
|
||||
XNotes,
|
||||
XNote
|
||||
},
|
||||
|
||||
props: {
|
||||
acct: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
user: null,
|
||||
fetching: true,
|
||||
existMore: false,
|
||||
moreFetching: false,
|
||||
withFiles: false,
|
||||
images: []
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
title(): string {
|
||||
return this.user ? Vue.filter('userName')(this.user) : '';
|
||||
},
|
||||
|
||||
bannerStyle(): any {
|
||||
if (this.user == null) return {};
|
||||
if (this.user.bannerUrl == null) return {};
|
||||
return {
|
||||
backgroundColor: this.user.bannerColor && this.user.bannerColor.length == 3 ? `rgb(${ this.user.bannerColor.join(',') })` : null,
|
||||
backgroundImage: `url(${ this.user.bannerUrl })`
|
||||
};
|
||||
},
|
||||
},
|
||||
|
||||
created() {
|
||||
(this as any).api('users/show', parseAcct(this.acct)).then(user => {
|
||||
this.user = user;
|
||||
this.fetching = false;
|
||||
|
||||
this.$nextTick(() => {
|
||||
(this.$refs.timeline as any).init(() => this.initTl());
|
||||
});
|
||||
|
||||
(this as any).api('users/notes', {
|
||||
userId: this.user.id,
|
||||
withFiles: true,
|
||||
limit: 9
|
||||
}).then(notes => {
|
||||
notes.forEach(note => {
|
||||
note.files.forEach(file => {
|
||||
file._note = note;
|
||||
if (this.images.length < 9) this.images.push(file);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
methods: {
|
||||
initTl() {
|
||||
return new Promise((res, rej) => {
|
||||
(this as any).api('users/notes', {
|
||||
userId: this.user.id,
|
||||
limit: fetchLimit + 1,
|
||||
withFiles: this.withFiles,
|
||||
includeMyRenotes: this.$store.state.settings.showMyRenotes,
|
||||
includeRenotedMyNotes: this.$store.state.settings.showRenotedMyNotes,
|
||||
includeLocalRenotes: this.$store.state.settings.showLocalRenotes
|
||||
}).then(notes => {
|
||||
if (notes.length == fetchLimit + 1) {
|
||||
notes.pop();
|
||||
this.existMore = true;
|
||||
}
|
||||
res(notes);
|
||||
}, rej);
|
||||
});
|
||||
},
|
||||
|
||||
fetchMoreNotes() {
|
||||
this.moreFetching = true;
|
||||
|
||||
const promise = (this as any).api('users/notes', {
|
||||
userId: this.user.id,
|
||||
limit: fetchLimit + 1,
|
||||
untilId: (this.$refs.timeline as any).tail().id,
|
||||
withFiles: this.withFiles,
|
||||
includeMyRenotes: this.$store.state.settings.showMyRenotes,
|
||||
includeRenotedMyNotes: this.$store.state.settings.showRenotedMyNotes,
|
||||
includeLocalRenotes: this.$store.state.settings.showLocalRenotes
|
||||
});
|
||||
|
||||
promise.then(notes => {
|
||||
if (notes.length == fetchLimit + 1) {
|
||||
notes.pop();
|
||||
} else {
|
||||
this.existMore = false;
|
||||
}
|
||||
notes.forEach(n => (this.$refs.timeline as any).append(n));
|
||||
this.moreFetching = false;
|
||||
});
|
||||
|
||||
return promise;
|
||||
},
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.zubukjlciycdsyynicqrnlsmdwmymzqu
|
||||
background var(--deckUserColumnBg)
|
||||
|
||||
> .is-remote
|
||||
padding 8px 16px
|
||||
font-size 12px
|
||||
|
||||
&.is-remote
|
||||
color var(--remoteInfoFg)
|
||||
background var(--remoteInfoBg)
|
||||
|
||||
> a
|
||||
font-weight bold
|
||||
|
||||
> header
|
||||
overflow hidden
|
||||
background-size cover
|
||||
background-position center
|
||||
|
||||
> div
|
||||
padding 32px
|
||||
background rgba(#000, 0.5)
|
||||
color #fff
|
||||
text-align center
|
||||
|
||||
> .follow
|
||||
position absolute
|
||||
top 16px
|
||||
right 16px
|
||||
|
||||
> .avatar
|
||||
display block
|
||||
width 64px
|
||||
height 64px
|
||||
margin 0 auto
|
||||
|
||||
> .name
|
||||
display block
|
||||
margin-top 8px
|
||||
font-weight bold
|
||||
text-shadow 0 0 8px #000
|
||||
|
||||
> .acct
|
||||
font-size 14px
|
||||
opacity 0.7
|
||||
text-shadow 0 0 8px #000
|
||||
|
||||
> .info
|
||||
padding 16px
|
||||
font-size 14px
|
||||
color var(--text)
|
||||
text-align center
|
||||
background var(--face)
|
||||
border-bottom solid 1px var(--faceDivider)
|
||||
|
||||
&:before
|
||||
content ""
|
||||
display blcok
|
||||
position absolute
|
||||
top -32px
|
||||
left 0
|
||||
right 0
|
||||
width 0px
|
||||
margin 0 auto
|
||||
border-top solid 16px transparent
|
||||
border-left solid 16px transparent
|
||||
border-right solid 16px transparent
|
||||
border-bottom solid 16px var(--face)
|
||||
|
||||
> .pinned
|
||||
padding-bottom 16px
|
||||
background var(--deckUserColumnBg)
|
||||
|
||||
> p
|
||||
margin 0
|
||||
padding 8px 16px
|
||||
font-size 14px
|
||||
color var(--text)
|
||||
|
||||
> .notes
|
||||
background var(--face)
|
||||
|
||||
> .images
|
||||
display grid
|
||||
grid-template-rows 1fr 1fr 1fr
|
||||
grid-template-columns 1fr 1fr 1fr
|
||||
gap 4px
|
||||
height 250px
|
||||
padding 16px
|
||||
margin-bottom 16px
|
||||
background var(--face)
|
||||
|
||||
> *
|
||||
background-position center center
|
||||
background-size cover
|
||||
background-clip content-box
|
||||
|
||||
> .tl
|
||||
background var(--face)
|
||||
|
||||
</style>
|
|
@ -9,6 +9,10 @@
|
|||
</div>
|
||||
<x-column-core v-else :ref="ids[0]" :key="ids[0]" :column="columns.find(c => c.id == ids[0])"/>
|
||||
</template>
|
||||
<template v-if="temporaryColumn">
|
||||
<x-user-column v-if="temporaryColumn.type == 'user'" :acct="temporaryColumn.acct" :key="temporaryColumn.acct"/>
|
||||
<x-note-column v-else-if="temporaryColumn.type == 'note'" :note-id="temporaryColumn.noteId" :key="temporaryColumn.noteId"/>
|
||||
</template>
|
||||
<button ref="add" @click="add" title="%i18n:common.deck.add-column%">%fa:plus%</button>
|
||||
</div>
|
||||
</mk-ui>
|
||||
|
@ -19,11 +23,16 @@ import Vue from 'vue';
|
|||
import XColumnCore from './deck.column-core.vue';
|
||||
import Menu from '../../../../common/views/components/menu.vue';
|
||||
import MkUserListsWindow from '../../components/user-lists-window.vue';
|
||||
import XUserColumn from './deck.user-column.vue';
|
||||
import XNoteColumn from './deck.note-column.vue';
|
||||
|
||||
import * as uuid from 'uuid';
|
||||
|
||||
export default Vue.extend({
|
||||
components: {
|
||||
XColumnCore
|
||||
XColumnCore,
|
||||
XUserColumn,
|
||||
XNoteColumn
|
||||
},
|
||||
|
||||
computed: {
|
||||
|
@ -31,15 +40,21 @@ export default Vue.extend({
|
|||
if (this.$store.state.settings.deck == null) return [];
|
||||
return this.$store.state.settings.deck.columns;
|
||||
},
|
||||
|
||||
layout(): any[] {
|
||||
if (this.$store.state.settings.deck == null) return [];
|
||||
if (this.$store.state.settings.deck.layout == null) return this.$store.state.settings.deck.columns.map(c => [c.id]);
|
||||
return this.$store.state.settings.deck.layout;
|
||||
},
|
||||
|
||||
style(): any {
|
||||
return {
|
||||
height: `calc(100vh - ${this.$store.state.uiHeaderHeight}px)`
|
||||
};
|
||||
},
|
||||
|
||||
temporaryColumn(): any {
|
||||
return this.$store.state.device.deckTemporaryColumn;
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -50,6 +65,8 @@ export default Vue.extend({
|
|||
},
|
||||
|
||||
created() {
|
||||
this.$store.commit('navHook', this.onNav);
|
||||
|
||||
if (this.$store.state.settings.deck == null) {
|
||||
const deck = {
|
||||
columns: [/*{
|
||||
|
@ -95,6 +112,8 @@ export default Vue.extend({
|
|||
},
|
||||
|
||||
beforeDestroy() {
|
||||
this.$store.commit('navHook', null);
|
||||
|
||||
document.documentElement.style.overflow = 'auto';
|
||||
},
|
||||
|
||||
|
@ -103,6 +122,30 @@ export default Vue.extend({
|
|||
return this.$refs[id][0];
|
||||
},
|
||||
|
||||
onNav(to) {
|
||||
if (!this.$store.state.settings.deckNav) return false;
|
||||
|
||||
if (to.name == 'user') {
|
||||
this.$store.commit('device/set', {
|
||||
key: 'deckTemporaryColumn',
|
||||
value: {
|
||||
type: 'user',
|
||||
acct: to.params.user
|
||||
}
|
||||
});
|
||||
return true;
|
||||
} else if (to.name == 'note') {
|
||||
this.$store.commit('device/set', {
|
||||
key: 'deckTemporaryColumn',
|
||||
value: {
|
||||
type: 'note',
|
||||
noteId: to.params.note
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
},
|
||||
|
||||
add() {
|
||||
this.os.new(Menu, {
|
||||
source: this.$refs.add,
|
||||
|
|
|
@ -60,9 +60,6 @@ export default Vue.extend({
|
|||
margin-right 4px
|
||||
|
||||
> .stream
|
||||
display -webkit-flex
|
||||
display -moz-flex
|
||||
display -ms-flex
|
||||
display flex
|
||||
justify-content center
|
||||
flex-wrap wrap
|
||||
|
|
|
@ -148,6 +148,19 @@ export default (callback: (launch: (router: VueRouter, api?: (os: MiOS) => API)
|
|||
});
|
||||
//#endregion
|
||||
|
||||
// Navigation hook
|
||||
router.beforeEach((to, from, next) => {
|
||||
if (os.store.state.navHook) {
|
||||
if (os.store.state.navHook(to)) {
|
||||
next(false);
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
});
|
||||
|
||||
Vue.mixin({
|
||||
data() {
|
||||
return {
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<div class="signin-as" v-html="'%i18n:@signed-in-as%'.replace('{}', `<b>${name}</b>`)"></div>
|
||||
|
||||
<div>
|
||||
<x-profile/>
|
||||
<mk-profile-editor/>
|
||||
|
||||
<ui-card>
|
||||
<div slot="title">%fa:palette% %i18n:@theme%</div>
|
||||
|
@ -148,13 +148,7 @@ import Vue from 'vue';
|
|||
import { apiUrl, version, codename, langs } from '../../../config';
|
||||
import checkForUpdate from '../../../common/scripts/check-for-update';
|
||||
|
||||
import XProfile from './settings/settings.profile.vue';
|
||||
|
||||
export default Vue.extend({
|
||||
components: {
|
||||
XProfile
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
apiUrl,
|
||||
|
|
|
@ -10,6 +10,7 @@ const defaultSettings = {
|
|||
home: null,
|
||||
mobileHome: [],
|
||||
deck: null,
|
||||
deckNav: true,
|
||||
tagTimelines: [],
|
||||
fetchOnScroll: true,
|
||||
showMaps: true,
|
||||
|
@ -57,7 +58,8 @@ const defaultDeviceSettings = {
|
|||
alwaysShowNsfw: false,
|
||||
postStyle: 'standard',
|
||||
navbar: 'top',
|
||||
mobileNotificationPosition: 'bottom'
|
||||
mobileNotificationPosition: 'bottom',
|
||||
deckTemporaryColumn: null
|
||||
};
|
||||
|
||||
export default (os: MiOS) => new Vuex.Store({
|
||||
|
@ -68,7 +70,8 @@ export default (os: MiOS) => new Vuex.Store({
|
|||
state: {
|
||||
i: null,
|
||||
indicate: false,
|
||||
uiHeaderHeight: 0
|
||||
uiHeaderHeight: 0,
|
||||
navHook: null
|
||||
},
|
||||
|
||||
getters: {
|
||||
|
@ -90,6 +93,10 @@ export default (os: MiOS) => new Vuex.Store({
|
|||
|
||||
setUiHeaderHeight(state, height) {
|
||||
state.uiHeaderHeight = height;
|
||||
},
|
||||
|
||||
navHook(state, callback) {
|
||||
state.navHook = callback;
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
@ -174,6 +174,7 @@
|
|||
desktopSettingsNavItemHover: ':lighten<10<$text',
|
||||
|
||||
deckAcrylicColumnBg: 'rgba(0, 0, 0, 0.25)',
|
||||
deckUserColumnBg: ':darken<3<@face',
|
||||
|
||||
mobileHeaderBg: ':lighten<5<$secondary',
|
||||
mobileHeaderFg: '$text',
|
||||
|
|
|
@ -174,6 +174,7 @@
|
|||
desktopSettingsNavItemHover: ':darken<10<$text',
|
||||
|
||||
deckAcrylicColumnBg: 'rgba(0, 0, 0, 0.1)',
|
||||
deckUserColumnBg: ':darken<4<@face',
|
||||
|
||||
mobileHeaderBg: ':lighten<5<$secondary',
|
||||
mobileHeaderFg: '$text',
|
||||
|
|
Loading…
Reference in a new issue