summaryrefslogtreecommitdiff
path: root/src/client
diff options
context:
space:
mode:
authorsyuilo <syuilotan@yahoo.co.jp>2018-04-29 17:17:15 +0900
committersyuilo <syuilotan@yahoo.co.jp>2018-04-29 17:17:15 +0900
commit372bfaceda5bf694bf33986b5a64a56e5787104c (patch)
treec498cd9fac2f79404e2d5b74549a5d759257ddcf /src/client
parentMerge pull request #1559 from syuilo/visibility (diff)
downloadsharkey-372bfaceda5bf694bf33986b5a64a56e5787104c.tar.gz
sharkey-372bfaceda5bf694bf33986b5a64a56e5787104c.tar.bz2
sharkey-372bfaceda5bf694bf33986b5a64a56e5787104c.zip
リファクタリングなど
Diffstat (limited to 'src/client')
-rw-r--r--src/client/app/common/define-widget.ts62
-rw-r--r--src/client/app/common/mios.ts56
-rw-r--r--src/client/app/common/scripts/streaming/home.ts23
-rw-r--r--src/client/app/common/views/components/avatar.vue38
-rw-r--r--src/client/app/common/views/components/index.ts2
-rw-r--r--src/client/app/common/views/components/messaging-room.message.vue24
-rw-r--r--src/client/app/common/views/components/messaging.vue4
-rw-r--r--src/client/app/common/views/components/welcome-timeline.vue15
-rw-r--r--src/client/app/common/views/widgets/access-log.vue1
-rw-r--r--src/client/app/common/views/widgets/broadcast.vue1
-rw-r--r--src/client/app/common/views/widgets/calendar.vue1
-rw-r--r--src/client/app/common/views/widgets/photo-stream.vue2
-rw-r--r--src/client/app/common/views/widgets/rss.vue1
-rw-r--r--src/client/app/common/views/widgets/server.vue2
-rw-r--r--src/client/app/common/views/widgets/slideshow.vue2
-rw-r--r--src/client/app/desktop/views/components/friends-maker.vue17
-rw-r--r--src/client/app/desktop/views/components/home.vue83
-rw-r--r--src/client/app/desktop/views/components/note-detail.sub.vue17
-rw-r--r--src/client/app/desktop/views/components/note-detail.vue37
-rw-r--r--src/client/app/desktop/views/components/note-preview.vue17
-rw-r--r--src/client/app/desktop/views/components/notes.note.sub.vue17
-rw-r--r--src/client/app/desktop/views/components/notes.note.vue38
-rw-r--r--src/client/app/desktop/views/components/notes.vue6
-rw-r--r--src/client/app/desktop/views/components/notifications.vue41
-rw-r--r--src/client/app/desktop/views/components/settings.vue59
-rw-r--r--src/client/app/desktop/views/components/timeline.core.vue8
-rw-r--r--src/client/app/desktop/views/components/ui.header.account.vue2
-rw-r--r--src/client/app/desktop/views/components/user-list-timeline.vue8
-rw-r--r--src/client/app/desktop/views/components/user-preview.vue16
-rw-r--r--src/client/app/desktop/views/components/users-list.item.vue17
-rw-r--r--src/client/app/desktop/views/components/widget-container.vue4
-rw-r--r--src/client/app/desktop/views/components/window.vue4
-rw-r--r--src/client/app/desktop/views/pages/user-list.users.vue17
-rw-r--r--src/client/app/desktop/views/pages/user/user.friends.vue17
-rw-r--r--src/client/app/desktop/views/pages/user/user.header.vue3
-rw-r--r--src/client/app/desktop/views/pages/welcome.vue4
-rw-r--r--src/client/app/desktop/views/widgets/activity.vue2
-rw-r--r--src/client/app/desktop/views/widgets/channel.vue1
-rw-r--r--src/client/app/desktop/views/widgets/messaging.vue1
-rw-r--r--src/client/app/desktop/views/widgets/notifications.vue1
-rw-r--r--src/client/app/desktop/views/widgets/polls.vue1
-rw-r--r--src/client/app/desktop/views/widgets/post-form.vue1
-rw-r--r--src/client/app/desktop/views/widgets/profile.vue1
-rw-r--r--src/client/app/desktop/views/widgets/timemachine.vue1
-rw-r--r--src/client/app/desktop/views/widgets/trends.vue1
-rw-r--r--src/client/app/desktop/views/widgets/users.vue18
-rw-r--r--src/client/app/init.ts28
-rw-r--r--src/client/app/mobile/views/components/note-detail.sub.vue17
-rw-r--r--src/client/app/mobile/views/components/note-detail.vue47
-rw-r--r--src/client/app/mobile/views/components/note-preview.vue17
-rw-r--r--src/client/app/mobile/views/components/note.sub.vue23
-rw-r--r--src/client/app/mobile/views/components/note.vue46
-rw-r--r--src/client/app/mobile/views/components/notes.vue6
-rw-r--r--src/client/app/mobile/views/components/notification.vue32
-rw-r--r--src/client/app/mobile/views/components/post-form.vue2
-rw-r--r--src/client/app/mobile/views/components/user-list-timeline.vue8
-rw-r--r--src/client/app/mobile/views/components/user-preview.vue25
-rw-r--r--src/client/app/mobile/views/pages/dashboard.vue20
-rw-r--r--src/client/app/mobile/views/pages/home.timeline.vue8
-rw-r--r--src/client/app/mobile/views/pages/welcome.vue4
-rw-r--r--src/client/app/mobile/views/widgets/activity.vue1
-rw-r--r--src/client/app/store.ts90
62 files changed, 512 insertions, 556 deletions
diff --git a/src/client/app/common/define-widget.ts b/src/client/app/common/define-widget.ts
index 7b98c0903f..0b2bc36566 100644
--- a/src/client/app/common/define-widget.ts
+++ b/src/client/app/common/define-widget.ts
@@ -18,61 +18,65 @@ export default function<T extends object>(data: {
default: false
}
},
+
computed: {
id(): string {
return this.widget.id;
+ },
+
+ props(): T {
+ return this.widget.data;
}
},
+
data() {
return {
- props: data.props ? data.props() : {} as T,
- bakedOldProps: null,
- preventSave: false
+ bakedOldProps: null
};
},
+
created() {
- if (this.props) {
- Object.keys(this.props).forEach(prop => {
- if (this.widget.data.hasOwnProperty(prop)) {
- this.props[prop] = this.widget.data[prop];
- }
- });
- }
+ this.mergeProps();
+
+ this.$watch('props', () => {
+ this.mergeProps();
+ });
this.bakeProps();
+ },
+
+ methods: {
+ bakeProps() {
+ this.bakedOldProps = JSON.stringify(this.props);
+ },
- this.$watch('props', newProps => {
- if (this.preventSave) {
- this.preventSave = false;
- this.bakeProps();
- return;
+ mergeProps() {
+ if (data.props) {
+ const defaultProps = data.props();
+ Object.keys(defaultProps).forEach(prop => {
+ if (!this.props.hasOwnProperty(prop)) {
+ Vue.set(this.props, prop, defaultProps[prop]);
+ }
+ });
}
- if (this.bakedOldProps == JSON.stringify(newProps)) return;
+ },
+
+ save() {
+ if (this.bakedOldProps == JSON.stringify(this.props)) return;
this.bakeProps();
if (this.isMobile) {
(this as any).api('i/update_mobile_home', {
id: this.id,
- data: newProps
- }).then(() => {
- (this as any).os.i.clientSettings.mobileHome.find(w => w.id == this.id).data = newProps;
+ data: this.props
});
} else {
(this as any).api('i/update_home', {
id: this.id,
- data: newProps
- }).then(() => {
- (this as any).os.i.clientSettings.home.find(w => w.id == this.id).data = newProps;
+ data: this.props
});
}
- }, {
- deep: true
- });
- },
- methods: {
- bakeProps() {
- this.bakedOldProps = JSON.stringify(this.props);
}
}
});
diff --git a/src/client/app/common/mios.ts b/src/client/app/common/mios.ts
index 4e471cf96f..7dcae47946 100644
--- a/src/client/app/common/mios.ts
+++ b/src/client/app/common/mios.ts
@@ -3,6 +3,7 @@ import { EventEmitter } from 'eventemitter3';
import * as merge from 'object-assign-deep';
import * as uuid from 'uuid';
+import initStore from '../store';
import { hostname, apiUrl, swPublickey, version, lang, googleMapsApiKey } from '../config';
import Progress from './scripts/loading';
import Connection from './scripts/streaming/stream';
@@ -16,16 +17,6 @@ import Err from '../common/views/components/connect-failed.vue';
import { LocalTimelineStreamManager } from './scripts/streaming/local-timeline';
import { GlobalTimelineStreamManager } from './scripts/streaming/global-timeline';
-const defaultSettings = {
- fetchOnScroll: true,
- showMaps: true,
- showPostFormOnTopOfTl: false,
- gradientWindowHeader: false,
- showReplyTarget: true,
- showMyRenotes: true,
- showRenotedMyNotes: true
-};
-
//#region api requests
let spinner = null;
let pending = 0;
@@ -117,6 +108,8 @@ export default class MiOS extends EventEmitter {
return localStorage.getItem('enableSounds') == 'true';
}
+ public store: ReturnType<typeof initStore>;
+
public apis: API;
/**
@@ -232,6 +225,11 @@ export default class MiOS extends EventEmitter {
console.error.apply(null, args);
}
+ public bakeMe() {
+ // ローカルストレージにキャッシュ
+ localStorage.setItem('me', JSON.stringify(this.i));
+ }
+
public signout() {
localStorage.removeItem('me');
document.cookie = `i=; domain=${hostname}; expires=Thu, 01 Jan 1970 00:00:01 GMT;`;
@@ -243,6 +241,8 @@ export default class MiOS extends EventEmitter {
* @param callback A function that call when initialized
*/
public async init(callback) {
+ this.store = initStore(this);
+
//#region Init stream managers
this.streams.serverStream = new ServerStreamManager(this);
@@ -307,16 +307,11 @@ export default class MiOS extends EventEmitter {
// フェッチが完了したとき
const fetched = me => {
- if (me) {
- // デフォルトの設定をマージ
- me.clientSettings = Object.assign(defaultSettings, me.clientSettings);
-
- // ローカルストレージにキャッシュ
- localStorage.setItem('me', JSON.stringify(me));
- }
-
this.i = me;
+ // ローカルストレージにキャッシュ
+ this.bakeMe();
+
this.emit('signedin');
// Finish init
@@ -333,6 +328,14 @@ export default class MiOS extends EventEmitter {
// Get cached account data
const cachedMe = JSON.parse(localStorage.getItem('me'));
+ //#region キャッシュされた設定を復元
+ const cachedSettings = JSON.parse(localStorage.getItem('settings'));
+
+ if (cachedSettings) {
+ this.store.commit('settings/init', cachedSettings);
+ }
+ //#endregion
+
// キャッシュがあったとき
if (cachedMe) {
if (cachedMe.token == null) {
@@ -346,12 +349,25 @@ export default class MiOS extends EventEmitter {
// 後から新鮮なデータをフェッチ
fetchme(cachedMe.token, freshData => {
merge(cachedMe, freshData);
+
+ this.store.commit('settings/init', freshData.clientSettings);
});
} else {
// Get token from cookie
const i = (document.cookie.match(/i=(!\w+)/) || [null, null])[1];
- fetchme(i, fetched);
+ fetchme(i, me => {
+ if (me) {
+ Object.entries(me.clientSettings).forEach(([key, value]) => {
+ this.store.commit('settings/set', { key, value });
+ });
+
+ fetched(me);
+ } else {
+ // Finish init
+ callback();
+ }
+ });
}
}
@@ -456,7 +472,7 @@ export default class MiOS extends EventEmitter {
};
const promise = new Promise((resolve, reject) => {
- const viaStream = this.stream.hasConnection &&
+ const viaStream = this.stream && this.stream.hasConnection &&
(localStorage.getItem('apiViaStream') ? localStorage.getItem('apiViaStream') == 'true' : true);
if (viaStream) {
diff --git a/src/client/app/common/scripts/streaming/home.ts b/src/client/app/common/scripts/streaming/home.ts
index 73f2c5302c..ddb0d4820e 100644
--- a/src/client/app/common/scripts/streaming/home.ts
+++ b/src/client/app/common/scripts/streaming/home.ts
@@ -25,10 +25,31 @@ export class HomeStream extends Stream {
console.log('I updated:', i);
}
merge(me, i);
+
+ // キャッシュ更新
+ os.bakeMe();
+ });
+
+ this.on('clientSettingUpdated', x => {
+ os.store.commit('settings/set', {
+ key: x.key,
+ value: x.value
+ });
+ });
+
+ this.on('home_updated', x => {
+ if (x.home) {
+ os.store.commit('settings/setHome', x.home);
+ } else {
+ os.store.commit('settings/setHomeWidget', {
+ id: x.id,
+ data: x.data
+ });
+ }
});
// トークンが再生成されたとき
- // このままではAPIが利用できないので強制的にサインアウトさせる
+ // このままではMisskeyが利用できないので強制的にサインアウトさせる
this.on('my_token_regenerated', () => {
alert('%i18n:!common.my-token-regenerated%');
os.signout();
diff --git a/src/client/app/common/views/components/avatar.vue b/src/client/app/common/views/components/avatar.vue
new file mode 100644
index 0000000000..5aac9c8ba1
--- /dev/null
+++ b/src/client/app/common/views/components/avatar.vue
@@ -0,0 +1,38 @@
+<template>
+ <router-link class="mk-avatar" :to="user | userPage" :title="user | acct" :target="target" :style="{ borderRadius: clientSettings.circleIcons ? '100%' : null }">
+ <img v-if="disablePreview" :src="`${user.avatarUrl}?thumbnail&size=128`" alt=""/>
+ <img v-else :src="`${user.avatarUrl}?thumbnail&size=128`" alt="" v-user-preview="user.id"/>
+ </router-link>
+</template>
+
+<script lang="ts">
+import Vue from 'vue';
+export default Vue.extend({
+ props: {
+ user: {
+ required: true
+ },
+ target: {
+ required: false,
+ default: null
+ },
+ disablePreview: {
+ required: false,
+ default: false
+ }
+ }
+});
+</script>
+
+<style lang="stylus" scoped>
+.mk-avatar
+ display block
+
+ > img
+ display inline-block
+ width 100%
+ height 100%
+ margin 0
+ border-radius inherit
+ vertical-align bottom
+</style>
diff --git a/src/client/app/common/views/components/index.ts b/src/client/app/common/views/components/index.ts
index 6bfe43a800..69fed00c74 100644
--- a/src/client/app/common/views/components/index.ts
+++ b/src/client/app/common/views/components/index.ts
@@ -3,6 +3,7 @@ import Vue from 'vue';
import signin from './signin.vue';
import signup from './signup.vue';
import forkit from './forkit.vue';
+import avatar from './avatar.vue';
import nav from './nav.vue';
import noteHtml from './note-html';
import poll from './poll.vue';
@@ -28,6 +29,7 @@ import welcomeTimeline from './welcome-timeline.vue';
Vue.component('mk-signin', signin);
Vue.component('mk-signup', signup);
Vue.component('mk-forkit', forkit);
+Vue.component('mk-avatar', avatar);
Vue.component('mk-nav', nav);
Vue.component('mk-note-html', noteHtml);
Vue.component('mk-poll', poll);
diff --git a/src/client/app/common/views/components/messaging-room.message.vue b/src/client/app/common/views/components/messaging-room.message.vue
index 70df899f5a..ba0ab3209f 100644
--- a/src/client/app/common/views/components/messaging-room.message.vue
+++ b/src/client/app/common/views/components/messaging-room.message.vue
@@ -1,8 +1,6 @@
<template>
<div class="message" :data-is-me="isMe">
- <router-link class="avatar-anchor" :to="message.user | userPage" :title="message.user | acct" target="_blank">
- <img class="avatar" :src="`${message.user.avatarUrl}?thumbnail&size=80`" alt=""/>
- </router-link>
+ <mk-avatar class="avatar" :user="message.user" target="_blank"/>
<div class="content">
<div class="balloon" :data-no-text="message.text == null">
<p class="read" v-if="isMe && message.isRead">%i18n:@is-read%</p>
@@ -67,20 +65,14 @@ export default Vue.extend({
padding 10px 12px 10px 12px
background-color transparent
- > .avatar-anchor
+ > .avatar
display block
position absolute
top 10px
-
- > .avatar
- display block
- min-width 54px
- min-height 54px
- max-width 54px
- max-height 54px
- margin 0
- border-radius 8px
- transition all 0.1s ease
+ width 54px
+ height 54px
+ border-radius 8px
+ transition all 0.1s ease
> .content
@@ -201,7 +193,7 @@ export default Vue.extend({
margin-left 4px
&:not([data-is-me])
- > .avatar-anchor
+ > .avatar
left 12px
> .content
@@ -225,7 +217,7 @@ export default Vue.extend({
text-align left
&[data-is-me]
- > .avatar-anchor
+ > .avatar
right 12px
> .content
diff --git a/src/client/app/common/views/components/messaging.vue b/src/client/app/common/views/components/messaging.vue
index 6f8fcb3a70..11f9c366d4 100644
--- a/src/client/app/common/views/components/messaging.vue
+++ b/src/client/app/common/views/components/messaging.vue
@@ -13,7 +13,7 @@
@click="navigate(user)"
tabindex="-1"
>
- <img class="avatar" :src="`${user.avatarUrl}?thumbnail&size=32`" alt=""/>
+ <mk-avatar class="avatar" :user="user"/>
<span class="name">{{ user | userName }}</span>
<span class="username">@{{ user | acct }}</span>
</li>
@@ -31,7 +31,7 @@
:key="message.id"
>
<div>
- <img class="avatar" :src="`${isMe(message) ? message.recipient.avatarUrl : message.user.avatarUrl}?thumbnail&size=64`" alt=""/>
+ <mk-avatar class="avatar" :user="isMe(message) ? message.recipient : message.user"/>
<header>
<span class="name">{{ isMe(message) ? message.recipient : message.user | userName }}</span>
<span class="username">@{{ isMe(message) ? message.recipient : message.user | acct }}</span>
diff --git a/src/client/app/common/views/components/welcome-timeline.vue b/src/client/app/common/views/components/welcome-timeline.vue
index 3497976901..6fadb030c3 100644
--- a/src/client/app/common/views/components/welcome-timeline.vue
+++ b/src/client/app/common/views/components/welcome-timeline.vue
@@ -1,9 +1,7 @@
<template>
<div class="mk-welcome-timeline">
<div v-for="note in notes">
- <router-link class="avatar-anchor" :to="note.user | userPage" v-user-preview="note.user.id">
- <img class="avatar" :src="`${note.user.avatarUrl}?thumbnail&size=96`" alt="avatar"/>
- </router-link>
+ <mk-avatar class="avatar" :user="note.user" target="_blank"/>
<div class="body">
<header>
<router-link class="name" :to="note.user | userPage" v-user-preview="note.user.id">{{ note.user | userName }}</router-link>
@@ -69,18 +67,15 @@ export default Vue.extend({
display block
clear both
- > .avatar-anchor
+ > .avatar
display block
float left
position -webkit-sticky
position sticky
top 16px
-
- > img
- display block
- width 42px
- height 42px
- border-radius 6px
+ width 42px
+ height 42px
+ border-radius 6px
> .body
float right
diff --git a/src/client/app/common/views/widgets/access-log.vue b/src/client/app/common/views/widgets/access-log.vue
index 0b1c7fe2dd..8652e35645 100644
--- a/src/client/app/common/views/widgets/access-log.vue
+++ b/src/client/app/common/views/widgets/access-log.vue
@@ -61,6 +61,7 @@ export default define({
} else {
this.props.design++;
}
+ this.save();
}
}
});
diff --git a/src/client/app/common/views/widgets/broadcast.vue b/src/client/app/common/views/widgets/broadcast.vue
index 96d1d0ef3a..75b1d60524 100644
--- a/src/client/app/common/views/widgets/broadcast.vue
+++ b/src/client/app/common/views/widgets/broadcast.vue
@@ -68,6 +68,7 @@ export default define({
} else {
this.props.design++;
}
+ this.save();
}
}
});
diff --git a/src/client/app/common/views/widgets/calendar.vue b/src/client/app/common/views/widgets/calendar.vue
index 0bb503759c..41e9253784 100644
--- a/src/client/app/common/views/widgets/calendar.vue
+++ b/src/client/app/common/views/widgets/calendar.vue
@@ -73,6 +73,7 @@ export default define({
} else {
this.props.design++;
}
+ this.save();
},
tick() {
const now = new Date();
diff --git a/src/client/app/common/views/widgets/photo-stream.vue b/src/client/app/common/views/widgets/photo-stream.vue
index c51d932bd1..ae5924bb10 100644
--- a/src/client/app/common/views/widgets/photo-stream.vue
+++ b/src/client/app/common/views/widgets/photo-stream.vue
@@ -59,6 +59,8 @@ export default define({
} else {
this.props.design++;
}
+
+ this.save();
}
}
});
diff --git a/src/client/app/common/views/widgets/rss.vue b/src/client/app/common/views/widgets/rss.vue
index f0ba11678e..b5339add0b 100644
--- a/src/client/app/common/views/widgets/rss.vue
+++ b/src/client/app/common/views/widgets/rss.vue
@@ -40,6 +40,7 @@ export default define({
methods: {
func() {
this.props.compact = !this.props.compact;
+ this.save();
},
fetch() {
fetch(`https://api.rss2json.com/v1/api.json?rss_url=${this.url}`, {
diff --git a/src/client/app/common/views/widgets/server.vue b/src/client/app/common/views/widgets/server.vue
index 2fbc07adf0..2fdd60499b 100644
--- a/src/client/app/common/views/widgets/server.vue
+++ b/src/client/app/common/views/widgets/server.vue
@@ -68,6 +68,7 @@ export default define({
} else {
this.props.view++;
}
+ this.save();
},
func() {
if (this.props.design == 2) {
@@ -75,6 +76,7 @@ export default define({
} else {
this.props.design++;
}
+ this.save();
}
}
});
diff --git a/src/client/app/common/views/widgets/slideshow.vue b/src/client/app/common/views/widgets/slideshow.vue
index 95be4b94fd..459b24a32f 100644
--- a/src/client/app/common/views/widgets/slideshow.vue
+++ b/src/client/app/common/views/widgets/slideshow.vue
@@ -64,6 +64,7 @@ export default define({
} else {
this.props.size++;
}
+ this.save();
this.applySize();
},
@@ -111,6 +112,7 @@ export default define({
choose() {
(this as any).apis.chooseDriveFolder().then(folder => {
this.props.folder = folder ? folder.id : null;
+ this.save();
this.fetch();
});
}
diff --git a/src/client/app/desktop/views/components/friends-maker.vue b/src/client/app/desktop/views/components/friends-maker.vue
index af5bde3ad5..3c1f8b8257 100644
--- a/src/client/app/desktop/views/components/friends-maker.vue
+++ b/src/client/app/desktop/views/components/friends-maker.vue
@@ -3,9 +3,7 @@
<p class="title">気になるユーザーをフォロー:</p>
<div class="users" v-if="!fetching && users.length > 0">
<div class="user" v-for="user in users" :key="user.id">
- <router-link class="avatar-anchor" :to="user | userPage">
- <img class="avatar" :src="`${user.avatarUrl}?thumbnail&size=42`" alt="" v-user-preview="user.id"/>
- </router-link>
+ <mk-avatar class="avatar" :user="user" target="_blank"/>
<div class="body">
<router-link class="name" :to="user | userPage" v-user-preview="user.id">{{ user | userName }}</router-link>
<p class="username">@{{ user | acct }}</p>
@@ -86,18 +84,13 @@ export default Vue.extend({
display block
clear both
- > .avatar-anchor
+ > .avatar
display block
float left
margin 0 12px 0 0
-
- > .avatar
- display block
- width 42px
- height 42px
- margin 0
- border-radius 8px
- vertical-align bottom
+ width 42px
+ height 42px
+ border-radius 8px
> .body
float left
diff --git a/src/client/app/desktop/views/components/home.vue b/src/client/app/desktop/views/components/home.vue
index 4343a7fb78..5337be61fd 100644
--- a/src/client/app/desktop/views/components/home.vue
+++ b/src/client/app/desktop/views/components/home.vue
@@ -53,7 +53,7 @@
<div class="main">
<a @click="hint">カスタマイズのヒント</a>
<div>
- <mk-post-form v-if="os.i.clientSettings.showPostFormOnTopOfTl"/>
+ <mk-post-form v-if="clientSettings.showPostFormOnTopOfTl"/>
<mk-timeline ref="tl" @loaded="onTlLoaded"/>
</div>
</div>
@@ -63,7 +63,7 @@
<component v-for="widget in widgets[place]" :is="`mkw-${widget.name}`" :key="widget.id" :ref="widget.id" :widget="widget" @chosen="warp"/>
</div>
<div class="main">
- <mk-post-form v-if="os.i.clientSettings.showPostFormOnTopOfTl"/>
+ <mk-post-form v-if="clientSettings.showPostFormOnTopOfTl"/>
<mk-timeline ref="tl" @loaded="onTlLoaded" v-if="mode == 'timeline'"/>
<mk-mentions @loaded="onTlLoaded" v-if="mode == 'mentions'"/>
</div>
@@ -81,6 +81,7 @@ export default Vue.extend({
components: {
XDraggable
},
+
props: {
customize: {
type: Boolean,
@@ -91,61 +92,43 @@ export default Vue.extend({
default: 'timeline'
}
},
+
data() {
return {
connection: null,
connectionId: null,
widgetAdderSelected: null,
- trash: [],
- widgets: {
- left: [],
- right: []
- }
+ trash: []
};
},
+
computed: {
- home: {
- get(): any[] {
- //#region 互換性のため
- (this as any).os.i.clientSettings.home.forEach(w => {
- if (w.name == 'rss-reader') w.name = 'rss';
- if (w.name == 'user-recommendation') w.name = 'users';
- if (w.name == 'recommended-polls') w.name = 'polls';
- });
- //#endregion
- return (this as any).os.i.clientSettings.home;
- },
- set(value) {
- (this as any).os.i.clientSettings.home = value;
- }
+ home(): any[] {
+ return this.$store.state.settings.data.home;
},
left(): any[] {
return this.home.filter(w => w.place == 'left');
},
right(): any[] {
return this.home.filter(w => w.place == 'right');
+ },
+ widgets(): any {
+ return {
+ left: this.left,
+ right: this.right
+ };
}
},
- created() {
- this.widgets.left = this.left;
- this.widgets.right = this.right;
- this.$watch('os.i.clientSettings', i => {
- this.widgets.left = this.left;
- this.widgets.right = this.right;
- }, {
- deep: true
- });
- },
+
mounted() {
this.connection = (this as any).os.stream.getConnection();
this.connectionId = (this as any).os.stream.use();
-
- this.connection.on('home_updated', this.onHomeUpdated);
},
+
beforeDestroy() {
- this.connection.off('home_updated', this.onHomeUpdated);
(this as any).os.stream.dispose(this.connectionId);
},
+
methods: {
hint() {
(this as any).apis.dialog({
@@ -159,56 +142,44 @@ export default Vue.extend({
}]
});
},
+
onTlLoaded() {
this.$emit('loaded');
},
- onHomeUpdated(data) {
- if (data.home) {
- (this as any).os.i.clientSettings.home = data.home;
- this.widgets.left = data.home.filter(w => w.place == 'left');
- this.widgets.right = data.home.filter(w => w.place == 'right');
- } else {
- const w = (this as any).os.i.clientSettings.home.find(w => w.id == data.id);
- if (w != null) {
- w.data = data.data;
- this.$refs[w.id][0].preventSave = true;
- this.$refs[w.id][0].props = w.data;
- this.widgets.left = (this as any).os.i.clientSettings.home.filter(w => w.place == 'left');
- this.widgets.right = (this as any).os.i.clientSettings.home.filter(w => w.place == 'right');
- }
- }
- },
+
onWidgetContextmenu(widgetId) {
const w = (this.$refs[widgetId] as any)[0];
if (w.func) w.func();
},
+
onWidgetSort() {
this.saveHome();
},
+
onTrash(evt) {
this.saveHome();
},
+
addWidget() {
- const widget = {
+ this.$store.dispatch('settings/addHomeWidget', {
name: this.widgetAdderSelected,
id: uuid(),
place: 'left',
data: {}
- };
-
- this.widgets.left.unshift(widget);
- this.saveHome();
+ });
},
+
saveHome() {
const left = this.widgets.left;
const right = this.widgets.right;
- this.home = left.concat(right);
+ this.$store.commit('settings/setHome', left.concat(right));
left.forEach(w => w.place = 'left');
right.forEach(w => w.place = 'right');
(this as any).api('i/update_home', {
home: this.home
});
},
+
warp(date) {
(this.$refs.tl as any).warp(date);
}
diff --git a/src/client/app/desktop/views/components/note-detail.sub.vue b/src/client/app/desktop/views/components/note-detail.sub.vue
index 5175c8bd45..24550c4e94 100644
--- a/src/client/app/desktop/views/components/note-detail.sub.vue
+++ b/src/client/app/desktop/views/components/note-detail.sub.vue
@@ -1,8 +1,6 @@
<template>
<div class="sub" :title="title">
- <router-link class="avatar-anchor" :to="note.user | userPage">
- <img class="avatar" :src="`${note.user.avatarUrl}?thumbnail&size=64`" alt="avatar" v-user-preview="note.userId"/>
- </router-link>
+ <mk-avatar class="avatar" :user="note.user"/>
<div class="main">
<header>
<div class="left">
@@ -57,18 +55,13 @@ root(isDark)
> .main > footer > button
color #888
- > .avatar-anchor
+ > .avatar
display block
float left
margin 0 16px 0 0
-
- > .avatar
- display block
- width 44px
- height 44px
- margin 0
- border-radius 4px
- vertical-align bottom
+ width 44px
+ height 44px
+ border-radius 4px
> .main
float left
diff --git a/src/client/app/desktop/views/components/note-detail.vue b/src/client/app/desktop/views/components/note-detail.vue
index 525023349e..5d07dc90d4 100644
--- a/src/client/app/desktop/views/components/note-detail.vue
+++ b/src/client/app/desktop/views/components/note-detail.vue
@@ -18,18 +18,14 @@
</div>
<div class="renote" v-if="isRenote">
<p>
- <router-link class="avatar-anchor" :to="note.user | userPage" v-user-preview="note.userId">
- <img class="avatar" :src="`${note.user.avatarUrl}?thumbnail&size=32`" alt="avatar"/>
- </router-link>
+ <mk-avatar class="avatar" :user="note.user"/>
%fa:retweet%
<router-link class="name" :href="note.user | userPage">{{ note.user | userName }}</router-link>
がRenote
</p>
</div>
<article>
- <router-link class="avatar-anchor" :to="p.user | userPage">
- <img class="avatar" :src="`${p.user.avatarUrl}?thumbnail&size=64`" alt="avatar" v-user-preview="p.user.id"/>
- </router-link>
+ <mk-avatar class="avatar" :user="p.user"/>
<header>
<router-link class="name" :to="p.user | userPage" v-user-preview="p.user.id">{{ p.user | userName }}</router-link>
<span class="username">@{{ p.user | acct }}</span>
@@ -159,7 +155,7 @@ export default Vue.extend({
// Draw map
if (this.p.geo) {
- const shouldShowMap = (this as any).os.isSignedIn ? (this as any).os.i.clientSettings.showMaps : true;
+ const shouldShowMap = (this as any).os.isSignedIn ? (this as any).clientSettings.showMaps : true;
if (shouldShowMap) {
(this as any).os.getGoogleMaps().then(maps => {
const uluru = new maps.LatLng(this.p.geo.coordinates[1], this.p.geo.coordinates[0]);
@@ -262,17 +258,12 @@ root(isDark)
margin 0
padding 16px 32px
- .avatar-anchor
+ .avatar
display inline-block
-
- .avatar
- vertical-align bottom
- min-width 28px
- min-height 28px
- max-width 28px
- max-height 28px
- margin 0 8px 0 0
- border-radius 6px
+ width 28px
+ height 28px
+ margin 0 8px 0 0
+ border-radius 6px
[data-fa]
margin-right 4px
@@ -298,18 +289,10 @@ root(isDark)
> footer > button
color isDark ? #707b97 : #888
- > .avatar-anchor
- display block
+ > .avatar
width 60px
height 60px
-
- > .avatar
- display block
- width 60px
- height 60px
- margin 0
- border-radius 8px
- vertical-align bottom
+ border-radius 8px
> header
position absolute
diff --git a/src/client/app/desktop/views/components/note-preview.vue b/src/client/app/desktop/views/components/note-preview.vue
index b45814e512..43eb159885 100644
--- a/src/client/app/desktop/views/components/note-preview.vue
+++ b/src/client/app/desktop/views/components/note-preview.vue
@@ -1,8 +1,6 @@
<template>
<div class="mk-note-preview" :title="title">
- <router-link class="avatar-anchor" :to="note.user | userPage">
- <img class="avatar" :src="`${note.user.avatarUrl}?thumbnail&size=64`" alt="avatar" v-user-preview="note.userId"/>
- </router-link>
+ <mk-avatar class="avatar" :user="note.user"/>
<div class="main">
<header>
<router-link class="name" :to="note.user | userPage" v-user-preview="note.userId">{{ note.user | userName }}</router-link>
@@ -41,18 +39,13 @@ root(isDark)
display block
clear both
- > .avatar-anchor
+ > .avatar
display block
float left
margin 0 16px 0 0
-
- > .avatar
- display block
- width 52px
- height 52px
- margin 0
- border-radius 8px
- vertical-align bottom
+ width 52px
+ height 52px
+ border-radius 8px
> .main
float left
diff --git a/src/client/app/desktop/views/components/notes.note.sub.vue b/src/client/app/desktop/views/components/notes.note.sub.vue
index 4472ddefb8..238fb03691 100644
--- a/src/client/app/desktop/views/components/notes.note.sub.vue
+++ b/src/client/app/desktop/views/components/notes.note.sub.vue
@@ -1,8 +1,6 @@
<template>
<div class="sub" :title="title">
- <router-link class="avatar-anchor" :to="note.user | userPage">
- <img class="avatar" :src="`${note.user.avatarUrl}?thumbnail&size=64`" alt="avatar" v-user-preview="note.userId"/>
- </router-link>
+ <mk-avatar class="avatar" :user="note.user"/>
<div class="main">
<header>
<router-link class="name" :to="note.user | userPage" v-user-preview="note.userId">{{ note.user | userName }}</router-link>
@@ -53,18 +51,13 @@ root(isDark)
display block
clear both
- > .avatar-anchor
+ > .avatar
display block
float left
margin 0 14px 0 0
-
- > .avatar
- display block
- width 52px
- height 52px
- margin 0
- border-radius 8px
- vertical-align bottom
+ width 52px
+ height 52px
+ border-radius 8px
> .main
float left
diff --git a/src/client/app/desktop/views/components/notes.note.vue b/src/client/app/desktop/views/components/notes.note.vue
index ee24543ebf..b512f78eca 100644
--- a/src/client/app/desktop/views/components/notes.note.vue
+++ b/src/client/app/desktop/views/components/notes.note.vue
@@ -1,12 +1,10 @@
<template>
<div class="note" tabindex="-1" :title="title" @keydown="onKeydown">
- <div class="reply-to" v-if="p.reply && (!os.isSignedIn || os.i.clientSettings.showReplyTarget)">
+ <div class="reply-to" v-if="p.reply && (!os.isSignedIn || clientSettings.showReplyTarget)">
<x-sub :note="p.reply"/>
</div>
<div class="renote" v-if="isRenote">
- <router-link class="avatar-anchor" :to="note.user | userPage" v-user-preview="note.userId">
- <img class="avatar" :src="`${note.user.avatarUrl}?thumbnail&size=32`" alt="avatar"/>
- </router-link>
+ <mk-avatar class="avatar" :user="note.user"/>
%fa:retweet%
<span>{{ '%i18n:!@reposted-by%'.substr(0, '%i18n:!@reposted-by%'.indexOf('{')) }}</span>
<a class="name" :href="note.user | userPage" v-user-preview="note.userId">{{ note.user | userName }}</a>
@@ -14,9 +12,7 @@
<mk-time :time="note.createdAt"/>
</div>
<article>
- <router-link class="avatar-anchor" :to="p.user | userPage">
- <img class="avatar" :src="`${p.user.avatarUrl}?thumbnail&size=64`" alt="avatar" v-user-preview="p.user.id"/>
- </router-link>
+ <mk-avatar class="avatar" :user="p.user"/>
<div class="main">
<header>
<router-link class="name" :to="p.user | userPage" v-user-preview="p.user.id">{{ p.user | userName }}</router-link>
@@ -182,7 +178,7 @@ export default Vue.extend({
// Draw map
if (this.p.geo) {
- const shouldShowMap = (this as any).os.isSignedIn ? (this as any).os.i.clientSettings.showMaps : true;
+ const shouldShowMap = (this as any).os.isSignedIn ? (this as any).clientSettings.showMaps : true;
if (shouldShowMap) {
(this as any).os.getGoogleMaps().then(maps => {
const uluru = new maps.LatLng(this.p.geo.coordinates[1], this.p.geo.coordinates[0]);
@@ -343,15 +339,12 @@ root(isDark)
color #9dbb00
background isDark ? linear-gradient(to bottom, #314027 0%, #282c37 100%) : linear-gradient(to bottom, #edfde2 0%, #fff 100%)
- .avatar-anchor
+ .avatar
display inline-block
-
- .avatar
- vertical-align bottom
- width 28px
- height 28px
- margin 0 8px 0 0
- border-radius 6px
+ width 28px
+ height 28px
+ margin 0 8px 0 0
+ border-radius 6px
[data-fa]
margin-right 4px
@@ -390,22 +383,17 @@ root(isDark)
> .main > footer > button
color isDark ? #707b97 : #888
- > .avatar-anchor
+ > .avatar
display block
float left
margin 0 16px 10px 0
+ width 58px
+ height 58px
+ border-radius 8px
//position -webkit-sticky
//position sticky
//top 74px
- > .avatar
- display block
- width 58px
- height 58px
- margin 0
- border-radius 8px
- vertical-align bottom
-
> .main
float left
width calc(100% - 74px)
diff --git a/src/client/app/desktop/views/components/notes.vue b/src/client/app/desktop/views/components/notes.vue
index c4824feeac..7e80e6f74a 100644
--- a/src/client/app/desktop/views/components/notes.vue
+++ b/src/client/app/desktop/views/components/notes.vue
@@ -121,13 +121,13 @@ export default Vue.extend({
const isMyNote = note.userId == (this as any).os.i.id;
const isPureRenote = note.renoteId != null && note.text == null && note.mediaIds.length == 0 && note.poll == null;
- if ((this as any).os.i.clientSettings.showMyRenotes === false) {
+ if ((this as any).clientSettings.showMyRenotes === false) {
if (isMyNote && isPureRenote) {
return;
}
}
- if ((this as any).os.i.clientSettings.showRenotedMyNotes === false) {
+ if ((this as any).clientSettings.showRenotedMyNotes === false) {
if (isPureRenote && (note.renote.userId == (this as any).os.i.id)) {
return;
}
@@ -199,7 +199,7 @@ export default Vue.extend({
this.clearNotification();
}
- if ((this as any).os.i.clientSettings.fetchOnScroll !== false) {
+ if ((this as any).clientSettings.fetchOnScroll !== false) {
const current = window.scrollY + window.innerHeight;
if (current > document.body.offsetHeight - 8) this.loadMore();
}
diff --git a/src/client/app/desktop/views/components/notifications.vue b/src/client/app/desktop/views/components/notifications.vue
index 36e9dce6af..7923d1a62d 100644
--- a/src/client/app/desktop/views/components/notifications.vue
+++ b/src/client/app/desktop/views/components/notifications.vue
@@ -6,9 +6,7 @@
<div class="notification" :class="notification.type" :key="notification.id">
<mk-time :time="notification.createdAt"/>
<template v-if="notification.type == 'reaction'">
- <router-link class="avatar-anchor" :to="notification.user | userPage" v-user-preview="notification.user.id">
- <img class="avatar" :src="`${notification.user.avatarUrl}?thumbnail&size=48`" alt="avatar"/>
- </router-link>
+ <mk-avatar class="avatar" :user="notification.user"/>
<div class="text">
<p>
<mk-reaction-icon :reaction="notification.reaction"/>
@@ -20,9 +18,7 @@
</div>
</template>
<template v-if="notification.type == 'renote'">
- <router-link class="avatar-anchor" :to="notification.note.user | userPage" v-user-preview="notification.note.userId">
- <img class="avatar" :src="`${notification.note.user.avatarUrl}?thumbnail&size=48`" alt="avatar"/>
- </router-link>
+ <mk-avatar class="avatar" :user="notification.note.user"/>
<div class="text">
<p>%fa:retweet%
<router-link :to="notification.note.user | userPage" v-user-preview="notification.note.userId">{{ notification.note.user | userName }}</router-link>
@@ -33,9 +29,7 @@
</div>
</template>
<template v-if="notification.type == 'quote'">
- <router-link class="avatar-anchor" :to="notification.note.user | userPage" v-user-preview="notification.note.userId">
- <img class="avatar" :src="`${notification.note.user.avatarUrl}?thumbnail&size=48`" alt="avatar"/>
- </router-link>
+ <mk-avatar class="avatar" :user="notification.note.user"/>
<div class="text">
<p>%fa:quote-left%
<router-link :to="notification.note.user | userPage" v-user-preview="notification.note.userId">{{ notification.note.user | userName }}</router-link>
@@ -44,9 +38,7 @@
</div>
</template>
<template v-if="notification.type == 'follow'">
- <router-link class="avatar-anchor" :to="notification.user | userPage" v-user-preview="notification.user.id">
- <img class="avatar" :src="`${notification.user.avatarUrl}?thumbnail&size=48`" alt="avatar"/>
- </router-link>
+ <mk-avatar class="avatar" :user="notification.user"/>
<div class="text">
<p>%fa:user-plus%
<router-link :to="notification.user | userPage" v-user-preview="notification.user.id">{{ notification.user | userName }}</router-link>
@@ -54,9 +46,7 @@
</div>
</template>
<template v-if="notification.type == 'reply'">
- <router-link class="avatar-anchor" :to="notification.note.user | userPage" v-user-preview="notification.note.userId">
- <img class="avatar" :src="`${notification.note.user.avatarUrl}?thumbnail&size=48`" alt="avatar"/>
- </router-link>
+ <mk-avatar class="avatar" :user="notification.note.user"/>
<div class="text">
<p>%fa:reply%
<router-link :to="notification.note.user | userPage" v-user-preview="notification.note.userId">{{ notification.note.user | userName }}</router-link>
@@ -65,9 +55,7 @@
</div>
</template>
<template v-if="notification.type == 'mention'">
- <router-link class="avatar-anchor" :to="notification.note.user | userPage" v-user-preview="notification.note.userId">
- <img class="avatar" :src="`${notification.note.user.avatarUrl}?thumbnail&size=48`" alt="avatar"/>
- </router-link>
+ <mk-avatar class="avatar" :user="notification.note.user"/>
<div class="text">
<p>%fa:at%
<router-link :to="notification.note.user | userPage" v-user-preview="notification.note.userId">{{ notification.note.user | userName }}</router-link>
@@ -76,9 +64,7 @@
</div>
</template>
<template v-if="notification.type == 'poll_vote'">
- <router-link class="avatar-anchor" :to="notification.user | userPage" v-user-preview="notification.user.id">
- <img class="avatar" :src="`${notification.user.avatarUrl}?thumbnail&size=48`" alt="avatar"/>
- </router-link>
+ <mk-avatar class="avatar" :user="notification.user"/>
<div class="text">
<p>%fa:chart-pie%<a :href="notification.user | userPage" v-user-preview="notification.user.id">{{ notification.user | userName }}</a></p>
<router-link class="note-ref" :to="notification.note | notePage">
@@ -223,20 +209,15 @@ root(isDark)
display block
clear both
- > .avatar-anchor
+ > .avatar
display block
float left
position -webkit-sticky
position sticky
top 16px
-
- > img
- display block
- min-width 36px
- min-height 36px
- max-width 36px
- max-height 36px
- border-radius 6px
+ width 36px
+ height 36px
+ border-radius 6px
> .text
float right
diff --git a/src/client/app/desktop/views/components/settings.vue b/src/client/app/desktop/views/components/settings.vue
index 9d56042ea7..af6ab12669 100644
--- a/src/client/app/desktop/views/components/settings.vue
+++ b/src/client/app/desktop/views/components/settings.vue
@@ -20,7 +20,7 @@
<section class="web" v-show="page == 'web'">
<h1>動作</h1>
- <mk-switch v-model="os.i.clientSettings.fetchOnScroll" @change="onChangeFetchOnScroll" text="スクロールで自動読み込み">
+ <mk-switch v-model="clientSettings.fetchOnScroll" @change="onChangeFetchOnScroll" text="スクロールで自動読み込み">
<span>ページを下までスクロールしたときに自動で追加のコンテンツを読み込みます。</span>
</mk-switch>
<mk-switch v-model="autoPopout" text="ウィンドウの自動ポップアウト">
@@ -41,13 +41,14 @@
</div>
<div class="div">
<mk-switch v-model="darkmode" text="ダークモード"/>
- <mk-switch v-model="os.i.clientSettings.gradientWindowHeader" @change="onChangeGradientWindowHeader" text="ウィンドウのタイトルバーにグラデーションを使用"/>
+ <mk-switch v-model="clientSettings.circleIcons" @change="onChangeCircleIcons" text="丸いアイコンを使用"/>
+ <mk-switch v-model="clientSettings.gradientWindowHeader" @change="onChangeGradientWindowHeader" text="ウィンドウのタイトルバーにグラデーションを使用"/>
</div>
- <mk-switch v-model="os.i.clientSettings.showPostFormOnTopOfTl" @change="onChangeShowPostFormOnTopOfTl" text="タイムライン上部に投稿フォームを表示する"/>
- <mk-switch v-model="os.i.clientSettings.showReplyTarget" @change="onChangeShowReplyTarget" text="リプライ先を表示する"/>
- <mk-switch v-model="os.i.clientSettings.showMyRenotes" @change="onChangeShowMyRenotes" text="自分の行ったRenoteをタイムラインに表示する"/>
- <mk-switch v-model="os.i.clientSettings.showRenotedMyNotes" @change="onChangeShowRenotedMyNotes" text="Renoteされた自分の投稿をタイムラインに表示する"/>
- <mk-switch v-model="os.i.clientSettings.showMaps" @change="onChangeShowMaps" text="マップの自動展開">
+ <mk-switch v-model="clientSettings.showPostFormOnTopOfTl" @change="onChangeShowPostFormOnTopOfTl" text="タイムライン上部に投稿フォームを表示する"/>
+ <mk-switch v-model="clientSettings.showReplyTarget" @change="onChangeShowReplyTarget" text="リプライ先を表示する"/>
+ <mk-switch v-model="clientSettings.showMyRenotes" @change="onChangeShowMyRenotes" text="自分の行ったRenoteをタイムラインに表示する"/>
+ <mk-switch v-model="clientSettings.showRenotedMyNotes" @change="onChangeShowRenotedMyNotes" text="Renoteされた自分の投稿をタイムラインに表示する"/>
+ <mk-switch v-model="clientSettings.showMaps" @change="onChangeShowMaps" text="マップの自動展開">
<span>位置情報が添付された投稿のマップを自動的に展開します。</span>
</mk-switch>
</section>
@@ -69,7 +70,7 @@
<section class="web" v-show="page == 'web'">
<h1>モバイル</h1>
- <mk-switch v-model="os.i.clientSettings.disableViaMobile" @change="onChangeDisableViaMobile" text="「モバイルからの投稿」フラグを付けない"/>
+ <mk-switch v-model="clientSettings.disableViaMobile" @change="onChangeDisableViaMobile" text="「モバイルからの投稿」フラグを付けない"/>
</section>
<section class="web" v-show="page == 'web'">
@@ -297,8 +298,8 @@ export default Vue.extend({
this.$emit('done');
},
onChangeFetchOnScroll(v) {
- (this as any).api('i/update_client_setting', {
- name: 'fetchOnScroll',
+ this.$store.dispatch('settings/set', {
+ key: 'fetchOnScroll',
value: v
});
},
@@ -308,50 +309,56 @@ export default Vue.extend({
});
},
onChangeDark(v) {
- (this as any).api('i/update_client_setting', {
- name: 'dark',
+ this.$store.dispatch('settings/set', {
+ key: 'dark',
value: v
});
},
onChangeShowPostFormOnTopOfTl(v) {
- (this as any).api('i/update_client_setting', {
- name: 'showPostFormOnTopOfTl',
+ this.$store.dispatch('settings/set', {
+ key: 'showPostFormOnTopOfTl',
value: v
});
},
onChangeShowReplyTarget(v) {
- (this as any).api('i/update_client_setting', {
- name: 'showReplyTarget',
+ this.$store.dispatch('settings/set', {
+ key: 'showReplyTarget',
value: v
});
},
onChangeShowMyRenotes(v) {
- (this as any).api('i/update_client_setting', {
- name: 'showMyRenotes',
+ this.$store.dispatch('settings/set', {
+ key: 'showMyRenotes',
value: v
});
},
onChangeShowRenotedMyNotes(v) {
- (this as any).api('i/update_client_setting', {
- name: 'showRenotedMyNotes',
+ this.$store.dispatch('settings/set', {
+ key: 'showRenotedMyNotes',
value: v
});
},
onChangeShowMaps(v) {
- (this as any).api('i/update_client_setting', {
- name: 'showMaps',
+ this.$store.dispatch('settings/set', {
+ key: 'showMaps',
+ value: v
+ });
+ },
+ onChangeCircleIcons(v) {
+ this.$store.dispatch('settings/set', {
+ key: 'circleIcons',
value: v
});
},
onChangeGradientWindowHeader(v) {
- (this as any).api('i/update_client_setting', {
- name: 'gradientWindowHeader',
+ this.$store.dispatch('settings/set', {
+ key: 'gradientWindowHeader',
value: v
});
},
onChangeDisableViaMobile(v) {
- (this as any).api('i/update_client_setting', {
- name: 'disableViaMobile',
+ this.$store.dispatch('settings/set', {
+ key: 'disableViaMobile',
value: v
});
},
diff --git a/src/client/app/desktop/views/components/timeline.core.vue b/src/client/app/desktop/views/components/timeline.core.vue
index a137a57070..254a5b9d63 100644
--- a/src/client/app/desktop/views/components/timeline.core.vue
+++ b/src/client/app/desktop/views/components/timeline.core.vue
@@ -101,8 +101,8 @@ export default Vue.extend({
(this as any).api(this.endpoint, {
limit: fetchLimit + 1,
untilDate: this.date ? this.date.getTime() : undefined,
- includeMyRenotes: (this as any).os.i.clientSettings.showMyRenotes,
- includeRenotedMyNotes: (this as any).os.i.clientSettings.showRenotedMyNotes
+ includeMyRenotes: (this as any).clientSettings.showMyRenotes,
+ includeRenotedMyNotes: (this as any).clientSettings.showRenotedMyNotes
}).then(notes => {
if (notes.length == fetchLimit + 1) {
notes.pop();
@@ -123,8 +123,8 @@ export default Vue.extend({
(this as any).api(this.endpoint, {
limit: fetchLimit + 1,
untilId: (this.$refs.timeline as any).tail().id,
- includeMyRenotes: (this as any).os.i.clientSettings.showMyRenotes,
- includeRenotedMyNotes: (this as any).os.i.clientSettings.showRenotedMyNotes
+ includeMyRenotes: (this as any).clientSettings.showMyRenotes,
+ includeRenotedMyNotes: (this as any).clientSettings.showRenotedMyNotes
}).then(notes => {
if (notes.length == fetchLimit + 1) {
notes.pop();
diff --git a/src/client/app/desktop/views/components/ui.header.account.vue b/src/client/app/desktop/views/components/ui.header.account.vue
index 145666b4bc..897d3de816 100644
--- a/src/client/app/desktop/views/components/ui.header.account.vue
+++ b/src/client/app/desktop/views/components/ui.header.account.vue
@@ -2,7 +2,7 @@
<div class="account">
<button class="header" :data-active="isOpen" @click="toggle">
<span class="username">{{ os.i.username }}<template v-if="!isOpen">%fa:angle-down%</template><template v-if="isOpen">%fa:angle-up%</template></span>
- <img class="avatar" :src="`${ os.i.avatarUrl }?thumbnail&size=64`" alt="avatar"/>
+ <mk-avatar class="avatar" :user="os.i"/>
</button>
<transition name="zoom-in-top">
<div class="menu" v-if="isOpen">
diff --git a/src/client/app/desktop/views/components/user-list-timeline.vue b/src/client/app/desktop/views/components/user-list-timeline.vue
index ee983a969c..ccdf8f64d2 100644
--- a/src/client/app/desktop/views/components/user-list-timeline.vue
+++ b/src/client/app/desktop/views/components/user-list-timeline.vue
@@ -46,8 +46,8 @@ export default Vue.extend({
(this as any).api('notes/user-list-timeline', {
listId: this.list.id,
limit: fetchLimit + 1,
- includeMyRenotes: (this as any).os.i.clientSettings.showMyRenotes,
- includeRenotedMyNotes: (this as any).os.i.clientSettings.showRenotedMyNotes
+ includeMyRenotes: (this as any).clientSettings.showMyRenotes,
+ includeRenotedMyNotes: (this as any).clientSettings.showRenotedMyNotes
}).then(notes => {
if (notes.length == fetchLimit + 1) {
notes.pop();
@@ -66,8 +66,8 @@ export default Vue.extend({
listId: this.list.id,
limit: fetchLimit + 1,
untilId: (this.$refs.timeline as any).tail().id,
- includeMyRenotes: (this as any).os.i.clientSettings.showMyRenotes,
- includeRenotedMyNotes: (this as any).os.i.clientSettings.showRenotedMyNotes
+ includeMyRenotes: (this as any).clientSettings.showMyRenotes,
+ includeRenotedMyNotes: (this as any).clientSettings.showRenotedMyNotes
}).then(notes => {
if (notes.length == fetchLimit + 1) {
notes.pop();
diff --git a/src/client/app/desktop/views/components/user-preview.vue b/src/client/app/desktop/views/components/user-preview.vue
index d0111d7dc5..cc5e021390 100644
--- a/src/client/app/desktop/views/components/user-preview.vue
+++ b/src/client/app/desktop/views/components/user-preview.vue
@@ -2,9 +2,7 @@
<div class="mk-user-preview">
<template v-if="u != null">
<div class="banner" :style="u.bannerUrl ? `background-image: url(${u.bannerUrl}?thumbnail&size=512)` : ''"></div>
- <router-link class="avatar" :to="u | userPage">
- <img :src="`${u.avatarUrl}?thumbnail&size=64`" alt="avatar"/>
- </router-link>
+ <mk-avatar class="avatar" :user="u" :disable-preview="true"/>
<div class="title">
<router-link class="name" :to="u | userPage">{{ u | userName }}</router-link>
<p class="username">@{{ u | acct }}</p>
@@ -111,14 +109,10 @@ root(isDark)
top 62px
left 13px
z-index 2
-
- > img
- display block
- width 58px
- height 58px
- margin 0
- border solid 3px isDark ? #282c37 : #fff
- border-radius 8px
+ width 58px
+ height 58px
+ border solid 3px isDark ? #282c37 : #fff
+ border-radius 8px
> .title
display block
diff --git a/src/client/app/desktop/views/components/users-list.item.vue b/src/client/app/desktop/views/components/users-list.item.vue
index 005c9cd6d3..dbad295178 100644
--- a/src/client/app/desktop/views/components/users-list.item.vue
+++ b/src/client/app/desktop/views/components/users-list.item.vue
@@ -1,8 +1,6 @@
<template>
<div class="root item">
- <router-link class="avatar-anchor" :to="user | userPage" v-user-preview="user.id">
- <img class="avatar" :src="`${user.avatarUrl}?thumbnail&size=64`" alt="avatar"/>
- </router-link>
+ <mk-avatar class="avatar" :user="user"/>
<div class="main">
<header>
<router-link class="name" :to="user | userPage" v-user-preview="user.id">{{ user | userName }}</router-link>
@@ -35,18 +33,13 @@ export default Vue.extend({
display block
clear both
- > .avatar-anchor
+ > .avatar
display block
float left
margin 0 16px 0 0
-
- > .avatar
- display block
- width 58px
- height 58px
- margin 0
- border-radius 8px
- vertical-align bottom
+ width 58px
+ height 58px
+ border-radius 8px
> .main
float left
diff --git a/src/client/app/desktop/views/components/widget-container.vue b/src/client/app/desktop/views/components/widget-container.vue
index 2edba5a230..ab8327d39e 100644
--- a/src/client/app/desktop/views/components/widget-container.vue
+++ b/src/client/app/desktop/views/components/widget-container.vue
@@ -24,8 +24,8 @@ export default Vue.extend({
computed: {
withGradient(): boolean {
return (this as any).os.isSignedIn
- ? (this as any).os.i.clientSettings.gradientWindowHeader != null
- ? (this as any).os.i.clientSettings.gradientWindowHeader
+ ? (this as any).clientSettings.gradientWindowHeader != null
+ ? (this as any).clientSettings.gradientWindowHeader
: false
: false;
}
diff --git a/src/client/app/desktop/views/components/window.vue b/src/client/app/desktop/views/components/window.vue
index c9820f8697..91d1a9c2bf 100644
--- a/src/client/app/desktop/views/components/window.vue
+++ b/src/client/app/desktop/views/components/window.vue
@@ -94,8 +94,8 @@ export default Vue.extend({
},
withGradient(): boolean {
return (this as any).os.isSignedIn
- ? (this as any).os.i.clientSettings.gradientWindowHeader != null
- ? (this as any).os.i.clientSettings.gradientWindowHeader
+ ? (this as any).clientSettings.gradientWindowHeader != null
+ ? (this as any).clientSettings.gradientWindowHeader
: false
: false;
}
diff --git a/src/client/app/desktop/views/pages/user-list.users.vue b/src/client/app/desktop/views/pages/user-list.users.vue
index 63070ed609..4236cdbb14 100644
--- a/src/client/app/desktop/views/pages/user-list.users.vue
+++ b/src/client/app/desktop/views/pages/user-list.users.vue
@@ -8,9 +8,7 @@
<p class="fetching" v-if="fetching">%fa:spinner .pulse .fw% %i18n:common.loading%<mk-ellipsis/></p>
<template v-else-if="users.length != 0">
<div class="user" v-for="_user in users">
- <router-link class="avatar-anchor" :to="_user | userPage">
- <img class="avatar" :src="`${_user.avatarUrl}?thumbnail&size=42`" alt="" v-user-preview="_user.id"/>
- </router-link>
+ <mk-avatar class="avatar" :user="_user"/>
<div class="body">
<router-link class="name" :to="_user | userPage" v-user-preview="_user.id">{{ _user | userName }}</router-link>
<p class="username">@{{ _user | acct }}</p>
@@ -80,18 +78,13 @@ root(isDark)
display block
clear both
- > .avatar-anchor
+ > .avatar
display block
float left
margin 0 12px 0 0
-
- > .avatar
- display block
- width 42px
- height 42px
- margin 0
- border-radius 8px
- vertical-align bottom
+ width 42px
+ height 42px
+ border-radius 8px
> .body
float left
diff --git a/src/client/app/desktop/views/pages/user/user.friends.vue b/src/client/app/desktop/views/pages/user/user.friends.vue
index 161b08d1de..4af0f0bca6 100644
--- a/src/client/app/desktop/views/pages/user/user.friends.vue
+++ b/src/client/app/desktop/views/pages/user/user.friends.vue
@@ -4,9 +4,7 @@
<p class="initializing" v-if="fetching">%fa:spinner .pulse .fw%%i18n:@loading%<mk-ellipsis/></p>
<template v-if="!fetching && users.length != 0">
<div class="user" v-for="friend in users">
- <router-link class="avatar-anchor" :to="friend | userPage">
- <img class="avatar" :src="`${friend.avatarUrl}?thumbnail&size=42`" alt="" v-user-preview="friend.id"/>
- </router-link>
+ <mk-avatar class="avatar" :user="friend"/>
<div class="body">
<router-link class="name" :to="friend | userPage" v-user-preview="friend.id">{{ friend.name }}</router-link>
<p class="username">@{{ friend | acct }}</p>
@@ -82,18 +80,13 @@ export default Vue.extend({
display block
clear both
- > .avatar-anchor
+ > .avatar
display block
float left
margin 0 12px 0 0
-
- > .avatar
- display block
- width 42px
- height 42px
- margin 0
- border-radius 8px
- vertical-align bottom
+ width 42px
+ height 42px
+ border-radius 8px
> .body
float left
diff --git a/src/client/app/desktop/views/pages/user/user.header.vue b/src/client/app/desktop/views/pages/user/user.header.vue
index 99fe0b18d0..629f6d87cf 100644
--- a/src/client/app/desktop/views/pages/user/user.header.vue
+++ b/src/client/app/desktop/views/pages/user/user.header.vue
@@ -7,7 +7,7 @@
<div class="fade"></div>
</div>
<div class="container">
- <img class="avatar" :src="`${user.avatarUrl}?thumbnail&size=150`" alt="avatar"/>
+ <mk-avatar class="avatar" :user="user" :disable-preview="true"/>
<div class="title">
<p class="name">{{ user | userName }}</p>
<p class="username">@{{ user | acct }}</p>
@@ -139,7 +139,6 @@ export default Vue.extend({
z-index 2
width 160px
height 160px
- margin 0
border solid 3px #fff
border-radius 8px
box-shadow 1px 1px 3px rgba(#000, 0.2)
diff --git a/src/client/app/desktop/views/pages/welcome.vue b/src/client/app/desktop/views/pages/welcome.vue
index 223be8301b..3d6765c97e 100644
--- a/src/client/app/desktop/views/pages/welcome.vue
+++ b/src/client/app/desktop/views/pages/welcome.vue
@@ -8,9 +8,7 @@
<p>ようこそ! <b>Misskey</b>はTwitter風ミニブログSNSです。思ったことや皆と共有したいことを投稿しましょう。タイムラインを見れば、皆の関心事をすぐにチェックすることもできます。<a :href="aboutUrl">詳しく...</a></p>
<p><button class="signup" @click="signup">はじめる</button><button class="signin" @click="signin">ログイン</button></p>
<div class="users">
- <router-link v-for="user in users" :key="user.id" class="avatar-anchor" :to="user | userPage" v-user-preview="user.id">
- <img class="avatar" :src="`${user.avatarUrl}?thumbnail&size=64`" alt="avatar"/>
- </router-link>
+ <mk-avatar class="avatar" :key="user.id" :user="user"/>
</div>
</div>
<div>
diff --git a/src/client/app/desktop/views/widgets/activity.vue b/src/client/app/desktop/views/widgets/activity.vue
index 0bdf4622af..1be87f590c 100644
--- a/src/client/app/desktop/views/widgets/activity.vue
+++ b/src/client/app/desktop/views/widgets/activity.vue
@@ -22,9 +22,11 @@ export default define({
} else {
this.props.design++;
}
+ this.save();
},
viewChanged(view) {
this.props.view = view;
+ this.save();
}
}
});
diff --git a/src/client/app/desktop/views/widgets/channel.vue b/src/client/app/desktop/views/widgets/channel.vue
index 600cdd5318..d21aed40fd 100644
--- a/src/client/app/desktop/views/widgets/channel.vue
+++ b/src/client/app/desktop/views/widgets/channel.vue
@@ -37,6 +37,7 @@ export default define({
methods: {
func() {
this.props.compact = !this.props.compact;
+ this.save();
},
settings() {
const id = window.prompt('チャンネルID');
diff --git a/src/client/app/desktop/views/widgets/messaging.vue b/src/client/app/desktop/views/widgets/messaging.vue
index b71db3e087..791d2ff1bb 100644
--- a/src/client/app/desktop/views/widgets/messaging.vue
+++ b/src/client/app/desktop/views/widgets/messaging.vue
@@ -35,6 +35,7 @@ export default define({
} else {
this.props.design++;
}
+ this.save();
}
}
});
diff --git a/src/client/app/desktop/views/widgets/notifications.vue b/src/client/app/desktop/views/widgets/notifications.vue
index 091b0d8b98..f75a091480 100644
--- a/src/client/app/desktop/views/widgets/notifications.vue
+++ b/src/client/app/desktop/views/widgets/notifications.vue
@@ -23,6 +23,7 @@ export default define({
},
func() {
this.props.compact = !this.props.compact;
+ this.save();
}
}
});
diff --git a/src/client/app/desktop/views/widgets/polls.vue b/src/client/app/desktop/views/widgets/polls.vue
index 852bf2e3a1..36fcc20636 100644
--- a/src/client/app/desktop/views/widgets/polls.vue
+++ b/src/client/app/desktop/views/widgets/polls.vue
@@ -39,6 +39,7 @@ export default define({
methods: {
func() {
this.props.compact = !this.props.compact;
+ this.save();
},
fetch() {
this.fetching = true;
diff --git a/src/client/app/desktop/views/widgets/post-form.vue b/src/client/app/desktop/views/widgets/post-form.vue
index 9c2d60f9b9..69b21ad37a 100644
--- a/src/client/app/desktop/views/widgets/post-form.vue
+++ b/src/client/app/desktop/views/widgets/post-form.vue
@@ -29,6 +29,7 @@ export default define({
} else {
this.props.design++;
}
+ this.save();
},
onKeydown(e) {
if ((e.which == 10 || e.which == 13) && (e.ctrlKey || e.metaKey)) this.post();
diff --git a/src/client/app/desktop/views/widgets/profile.vue b/src/client/app/desktop/views/widgets/profile.vue
index 7958b4829a..48e7747b40 100644
--- a/src/client/app/desktop/views/widgets/profile.vue
+++ b/src/client/app/desktop/views/widgets/profile.vue
@@ -36,6 +36,7 @@ export default define({
} else {
this.props.design++;
}
+ this.save();
}
}
});
diff --git a/src/client/app/desktop/views/widgets/timemachine.vue b/src/client/app/desktop/views/widgets/timemachine.vue
index 6db3b14c62..22a4120403 100644
--- a/src/client/app/desktop/views/widgets/timemachine.vue
+++ b/src/client/app/desktop/views/widgets/timemachine.vue
@@ -22,6 +22,7 @@ export default define({
} else {
this.props.design++;
}
+ this.save();
}
}
});
diff --git a/src/client/app/desktop/views/widgets/trends.vue b/src/client/app/desktop/views/widgets/trends.vue
index 08fa7f8027..c33bf2f2f2 100644
--- a/src/client/app/desktop/views/widgets/trends.vue
+++ b/src/client/app/desktop/views/widgets/trends.vue
@@ -38,6 +38,7 @@ export default define({
methods: {
func() {
this.props.compact = !this.props.compact;
+ this.save();
},
fetch() {
this.fetching = true;
diff --git a/src/client/app/desktop/views/widgets/users.vue b/src/client/app/desktop/views/widgets/users.vue
index 6e326115b0..328fa56697 100644
--- a/src/client/app/desktop/views/widgets/users.vue
+++ b/src/client/app/desktop/views/widgets/users.vue
@@ -8,9 +8,7 @@
<p class="fetching" v-if="fetching">%fa:spinner .pulse .fw%%i18n:common.loading%<mk-ellipsis/></p>
<template v-else-if="users.length != 0">
<div class="user" v-for="_user in users">
- <router-link class="avatar-anchor" :to="_user | userPage">
- <img class="avatar" :src="`${_user.avatarUrl}?thumbnail&size=42`" alt="" v-user-preview="_user.id"/>
- </router-link>
+ <mk-avatar class="avatar" :user="_user"/>
<div class="body">
<router-link class="name" :to="_user | userPage" v-user-preview="_user.id">{{ _user | userName }}</router-link>
<p class="username">@{{ _user | acct }}</p>
@@ -48,6 +46,7 @@ export default define({
methods: {
func() {
this.props.compact = !this.props.compact;
+ this.save();
},
fetch() {
this.fetching = true;
@@ -88,18 +87,13 @@ root(isDark)
display block
clear both
- > .avatar-anchor
+ > .avatar
display block
float left
margin 0 12px 0 0
-
- > .avatar
- display block
- width 42px
- height 42px
- margin 0
- border-radius 8px
- vertical-align bottom
+ width 42px
+ height 42px
+ border-radius 8px
> .body
float left
diff --git a/src/client/app/init.ts b/src/client/app/init.ts
index 26f5328d7d..6f7ce02607 100644
--- a/src/client/app/init.ts
+++ b/src/client/app/init.ts
@@ -3,7 +3,7 @@
*/
import Vue from 'vue';
-import Vuex from 'vuex';
+import Vuex, { mapState } from 'vuex';
import VueRouter from 'vue-router';
import VModal from 'vue-js-modal';
import * as TreeView from 'vue-json-tree-view';
@@ -41,17 +41,6 @@ require('./common/views/widgets');
// Register global filters
require('./common/views/filters');
-const store = new Vuex.Store({
- state: {
- uiHeaderHeight: 0
- },
- mutations: {
- setUiHeaderHeight(state, height) {
- state.uiHeaderHeight = height;
- }
- }
-});
-
Vue.mixin({
destroyed(this: any) {
if (this.$el.parentNode) {
@@ -159,20 +148,15 @@ export default (callback: (launch: (router: VueRouter, api?: (os: MiOS) => API)
api: os.api,
apis: os.apis
};
- }
+ },
+ computed: mapState({
+ clientSettings: state => state.settings.data
+ })
});
const app = new Vue({
- store,
+ store: os.store,
router,
- created() {
- this.$watch('os.i', i => {
- // キャッシュ更新
- localStorage.setItem('me', JSON.stringify(i));
- }, {
- deep: true
- });
- },
render: createEl => createEl(App)
});
diff --git a/src/client/app/mobile/views/components/note-detail.sub.vue b/src/client/app/mobile/views/components/note-detail.sub.vue
index 683b5ffd1b..34ff06db30 100644
--- a/src/client/app/mobile/views/components/note-detail.sub.vue
+++ b/src/client/app/mobile/views/components/note-detail.sub.vue
@@ -1,8 +1,6 @@
<template>
<div class="root sub">
- <router-link class="avatar-anchor" :to="note.user | userPage">
- <img class="avatar" :src="`${note.user.avatarUrl}?thumbnail&size=64`" alt="avatar"/>
- </router-link>
+ <mk-avatar class="avatar" :user="note.user"/>
<div class="main">
<header>
<router-link class="name" :to="note.user | userPage">{{ note.user | userName }}</router-link>
@@ -43,18 +41,13 @@ root(isDark)
display block
clear both
- > .avatar-anchor
+ > .avatar
display block
float left
margin 0 12px 0 0
-
- > .avatar
- display block
- width 48px
- height 48px
- margin 0
- border-radius 8px
- vertical-align bottom
+ width 48px
+ height 48px
+ border-radius 8px
> .main
float left
diff --git a/src/client/app/mobile/views/components/note-detail.vue b/src/client/app/mobile/views/components/note-detail.vue
index 36c3f30c62..b9bd9fe495 100644
--- a/src/client/app/mobile/views/components/note-detail.vue
+++ b/src/client/app/mobile/views/components/note-detail.vue
@@ -17,17 +17,12 @@
</div>
<div class="renote" v-if="isRenote">
<p>
- <router-link class="avatar-anchor" :to="note.user | userPage">
- <img class="avatar" :src="`${note.user.avatarUrl}?thumbnail&size=32`" alt="avatar"/>
- </router-link>
- %fa:retweet%<router-link class="name" :to="note.user | userPage">{{ note.user | userName }}</router-link>がRenote
+ <mk-avatar class="avatar" :user="note.user"/>%fa:retweet%<router-link class="name" :to="note.user | userPage">{{ note.user | userName }}</router-link>がRenote
</p>
</div>
<article>
<header>
- <router-link class="avatar-anchor" :to="p.user | userPage">
- <img class="avatar" :src="`${p.user.avatarUrl}?thumbnail&size=64`" alt="avatar"/>
- </router-link>
+ <mk-avatar class="avatar" :user="p.user"/>
<div>
<router-link class="name" :to="p.user | userPage">{{ p.user | userName }}</router-link>
<span class="username">@{{ p.user | acct }}</span>
@@ -152,7 +147,7 @@ export default Vue.extend({
// Draw map
if (this.p.geo) {
- const shouldShowMap = (this as any).os.isSignedIn ? (this as any).os.i.clientSettings.showMaps : true;
+ const shouldShowMap = (this as any).os.isSignedIn ? (this as any).clientSettings.showMaps : true;
if (shouldShowMap) {
(this as any).os.getGoogleMaps().then(maps => {
const uluru = new maps.LatLng(this.p.geo.coordinates[1], this.p.geo.coordinates[0]);
@@ -262,17 +257,12 @@ root(isDark)
margin 0
padding 16px 32px
- .avatar-anchor
+ .avatar
display inline-block
-
- .avatar
- vertical-align bottom
- min-width 28px
- min-height 28px
- max-width 28px
- max-height 28px
- margin 0 8px 0 0
- border-radius 6px
+ width 28px
+ height 28px
+ margin 0 8px 0 0
+ border-radius 6px
[data-fa]
margin-right 4px
@@ -301,21 +291,16 @@ root(isDark)
display flex
line-height 1.1em
- > .avatar-anchor
+ > .avatar
display block
- padding 0 12px 0 0
+ margin 0 12px 0 0
+ width 54px
+ height 54px
+ border-radius 8px
- > .avatar
- display block
- width 54px
- height 54px
- margin 0
- border-radius 8px
- vertical-align bottom
-
- @media (min-width 500px)
- width 60px
- height 60px
+ @media (min-width 500px)
+ width 60px
+ height 60px
> div
diff --git a/src/client/app/mobile/views/components/note-preview.vue b/src/client/app/mobile/views/components/note-preview.vue
index 41244cc759..e9fe9b1bdd 100644
--- a/src/client/app/mobile/views/components/note-preview.vue
+++ b/src/client/app/mobile/views/components/note-preview.vue
@@ -1,8 +1,6 @@
<template>
<div class="mk-note-preview">
- <router-link class="avatar-anchor" :to="note.user | userPage">
- <img class="avatar" :src="`${note.user.avatarUrl}?thumbnail&size=64`" alt="avatar"/>
- </router-link>
+ <mk-avatar class="avatar" :user="note.user"/>
<div class="main">
<header>
<router-link class="name" :to="note.user | userPage">{{ note.user | userName }}</router-link>
@@ -37,18 +35,13 @@ root(isDark)
display block
clear both
- > .avatar-anchor
+ > .avatar
display block
float left
margin 0 12px 0 0
-
- > .avatar
- display block
- width 48px
- height 48px
- margin 0
- border-radius 8px
- vertical-align bottom
+ width 48px
+ height 48px
+ border-radius 8px
> .main
float left
diff --git a/src/client/app/mobile/views/components/note.sub.vue b/src/client/app/mobile/views/components/note.sub.vue
index 01f02bdb56..251b377fb2 100644
--- a/src/client/app/mobile/views/components/note.sub.vue
+++ b/src/client/app/mobile/views/components/note.sub.vue
@@ -1,8 +1,6 @@
<template>
<div class="sub">
- <router-link class="avatar-anchor" :to="note.user | userPage">
- <img class="avatar" :src="`${note.user.avatarUrl}?thumbnail&size=96`" alt="avatar"/>
- </router-link>
+ <mk-avatar class="avatar" :user="note.user"/>
<div class="main">
<header>
<router-link class="name" :to="note.user | userPage">{{ note.user | userName }}</router-link>
@@ -49,25 +47,18 @@ root(isDark)
display block
clear both
- > .avatar-anchor
+ > .avatar
display block
float left
margin 0 10px 0 0
+ width 44px
+ height 44px
+ border-radius 8px
@media (min-width 500px)
margin-right 16px
-
- > .avatar
- display block
- width 44px
- height 44px
- margin 0
- border-radius 8px
- vertical-align bottom
-
- @media (min-width 500px)
- width 52px
- height 52px
+ width 52px
+ height 52px
> .main
float left
diff --git a/src/client/app/mobile/views/components/note.vue b/src/client/app/mobile/views/components/note.vue
index 07e18544dd..f3aab49bb0 100644
--- a/src/client/app/mobile/views/components/note.vue
+++ b/src/client/app/mobile/views/components/note.vue
@@ -1,12 +1,10 @@
<template>
<div class="note" :class="{ renote: isRenote }">
- <div class="reply-to" v-if="p.reply && (!os.isSignedIn || os.i.clientSettings.showReplyTarget)">
+ <div class="reply-to" v-if="p.reply && (!os.isSignedIn || clientSettings.showReplyTarget)">
<x-sub :note="p.reply"/>
</div>
<div class="renote" v-if="isRenote">
- <router-link class="avatar-anchor" :to="note.user | userPage">
- <img class="avatar" :src="`${note.user.avatarUrl}?thumbnail&size=64`" alt="avatar"/>
- </router-link>
+ <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>
@@ -14,9 +12,7 @@
<mk-time :time="note.createdAt"/>
</div>
<article>
- <router-link class="avatar-anchor" :to="p.user | userPage">
- <img class="avatar" :src="`${p.user.avatarUrl}?thumbnail&size=96`" alt="avatar"/>
- </router-link>
+ <mk-avatar class="avatar" :user="p.user"/>
<div class="main">
<header>
<router-link class="name" :to="p.user | userPage">{{ p.user | userName }}</router-link>
@@ -154,7 +150,7 @@ export default Vue.extend({
// Draw map
if (this.p.geo) {
- const shouldShowMap = (this as any).os.isSignedIn ? (this as any).os.i.clientSettings.showMaps : true;
+ const shouldShowMap = (this as any).os.isSignedIn ? (this as any).clientSettings.showMaps : true;
if (shouldShowMap) {
(this as any).os.getGoogleMaps().then(maps => {
const uluru = new maps.LatLng(this.p.geo.coordinates[1], this.p.geo.coordinates[0]);
@@ -268,15 +264,12 @@ root(isDark)
@media (min-width 600px)
padding 16px 32px
- .avatar-anchor
+ .avatar
display inline-block
-
- .avatar
- vertical-align bottom
- width 28px
- height 28px
- margin 0 8px 0 0
- border-radius 6px
+ width 28px
+ height 28px
+ margin 0 8px 0 0
+ border-radius 6px
[data-fa]
margin-right 4px
@@ -314,29 +307,22 @@ root(isDark)
display block
clear both
- > .avatar-anchor
+ > .avatar
display block
float left
margin 0 10px 8px 0
+ width 48px
+ height 48px
+ border-radius 6px
//position -webkit-sticky
//position sticky
//top 62px
@media (min-width 500px)
margin-right 16px
-
- > .avatar
- display block
- width 48px
- height 48px
- margin 0
- border-radius 6px
- vertical-align bottom
-
- @media (min-width 500px)
- width 58px
- height 58px
- border-radius 8px
+ width 58px
+ height 58px
+ border-radius 8px
> .main
float left
diff --git a/src/client/app/mobile/views/components/notes.vue b/src/client/app/mobile/views/components/notes.vue
index e12dc1d040..9461fe6fe9 100644
--- a/src/client/app/mobile/views/components/notes.vue
+++ b/src/client/app/mobile/views/components/notes.vue
@@ -116,13 +116,13 @@ export default Vue.extend({
const isMyNote = note.userId == (this as any).os.i.id;
const isPureRenote = note.renoteId != null && note.text == null && note.mediaIds.length == 0 && note.poll == null;
- if ((this as any).os.i.clientSettings.showMyRenotes === false) {
+ if ((this as any).clientSettings.showMyRenotes === false) {
if (isMyNote && isPureRenote) {
return;
}
}
- if ((this as any).os.i.clientSettings.showRenotedMyNotes === false) {
+ if ((this as any).clientSettings.showRenotedMyNotes === false) {
if (isPureRenote && (note.renote.userId == (this as any).os.i.id)) {
return;
}
@@ -187,7 +187,7 @@ export default Vue.extend({
this.clearNotification();
}
- if ((this as any).os.i.clientSettings.fetchOnScroll !== false) {
+ if ((this as any).clientSettings.fetchOnScroll !== false) {
const current = window.scrollY + window.innerHeight;
if (current > document.body.offsetHeight - 8) this.loadMore();
}
diff --git a/src/client/app/mobile/views/components/notification.vue b/src/client/app/mobile/views/components/notification.vue
index a4e6b027ed..13ca95075c 100644
--- a/src/client/app/mobile/views/components/notification.vue
+++ b/src/client/app/mobile/views/components/notification.vue
@@ -1,9 +1,7 @@
<template>
<div class="mk-notification">
<div class="notification reaction" v-if="notification.type == 'reaction'">
- <router-link class="avatar-anchor" :to="notification.user | userPage">
- <img class="avatar" :src="`${notification.user.avatarUrl}?thumbnail&size=64`" alt="avatar"/>
- </router-link>
+ <mk-avatar class="avatar" :user="notification.user"/>
<div>
<header>
<mk-reaction-icon :reaction="notification.reaction"/>
@@ -18,9 +16,7 @@
</div>
<div class="notification renote" v-if="notification.type == 'renote'">
- <router-link class="avatar-anchor" :to="notification.user | userPage">
- <img class="avatar" :src="`${notification.user.avatarUrl}?thumbnail&size=64`" alt="avatar"/>
- </router-link>
+ <mk-avatar class="avatar" :user="notification.user"/>
<div>
<header>
%fa:retweet%
@@ -34,9 +30,7 @@
</div>
<div class="notification follow" v-if="notification.type == 'follow'">
- <router-link class="avatar-anchor" :to="notification.user | userPage">
- <img class="avatar" :src="`${notification.user.avatarUrl}?thumbnail&size=64`" alt="avatar"/>
- </router-link>
+ <mk-avatar class="avatar" :user="notification.user"/>
<div>
<header>
%fa:user-plus%
@@ -47,9 +41,7 @@
</div>
<div class="notification poll_vote" v-if="notification.type == 'poll_vote'">
- <router-link class="avatar-anchor" :to="notification.user | userPage">
- <img class="avatar" :src="`${notification.user.avatarUrl}?thumbnail&size=64`" alt="avatar"/>
- </router-link>
+ <mk-avatar class="avatar" :user="notification.user"/>
<div>
<header>
%fa:chart-pie%
@@ -111,18 +103,16 @@ root(isDark)
display block
clear both
- > .avatar-anchor
+ > .avatar
display block
float left
+ width 36px
+ height 36px
+ border-radius 6px
- img
- width 36px
- height 36px
- border-radius 6px
-
- @media (min-width 500px)
- width 42px
- height 42px
+ @media (min-width 500px)
+ width 42px
+ height 42px
> div
float right
diff --git a/src/client/app/mobile/views/components/post-form.vue b/src/client/app/mobile/views/components/post-form.vue
index ec16119797..3f890223a3 100644
--- a/src/client/app/mobile/views/components/post-form.vue
+++ b/src/client/app/mobile/views/components/post-form.vue
@@ -166,7 +166,7 @@ export default Vue.extend({
post() {
this.posting = true;
- const viaMobile = (this as any).os.i.clientSettings.disableViaMobile !== true;
+ const viaMobile = (this as any).clientSettings.disableViaMobile !== true;
(this as any).api('notes/create', {
text: this.text == '' ? undefined : this.text,
mediaIds: this.files.length > 0 ? this.files.map(f => f.id) : undefined,
diff --git a/src/client/app/mobile/views/components/user-list-timeline.vue b/src/client/app/mobile/views/components/user-list-timeline.vue
index ee983a969c..ccdf8f64d2 100644
--- a/src/client/app/mobile/views/components/user-list-timeline.vue
+++ b/src/client/app/mobile/views/components/user-list-timeline.vue
@@ -46,8 +46,8 @@ export default Vue.extend({
(this as any).api('notes/user-list-timeline', {
listId: this.list.id,
limit: fetchLimit + 1,
- includeMyRenotes: (this as any).os.i.clientSettings.showMyRenotes,
- includeRenotedMyNotes: (this as any).os.i.clientSettings.showRenotedMyNotes
+ includeMyRenotes: (this as any).clientSettings.showMyRenotes,
+ includeRenotedMyNotes: (this as any).clientSettings.showRenotedMyNotes
}).then(notes => {
if (notes.length == fetchLimit + 1) {
notes.pop();
@@ -66,8 +66,8 @@ export default Vue.extend({
listId: this.list.id,
limit: fetchLimit + 1,
untilId: (this.$refs.timeline as any).tail().id,
- includeMyRenotes: (this as any).os.i.clientSettings.showMyRenotes,
- includeRenotedMyNotes: (this as any).os.i.clientSettings.showRenotedMyNotes
+ includeMyRenotes: (this as any).clientSettings.showMyRenotes,
+ includeRenotedMyNotes: (this as any).clientSettings.showRenotedMyNotes
}).then(notes => {
if (notes.length == fetchLimit + 1) {
notes.pop();
diff --git a/src/client/app/mobile/views/components/user-preview.vue b/src/client/app/mobile/views/components/user-preview.vue
index 23a83b5e3a..d258360911 100644
--- a/src/client/app/mobile/views/components/user-preview.vue
+++ b/src/client/app/mobile/views/components/user-preview.vue
@@ -1,8 +1,6 @@
<template>
<div class="mk-user-preview">
- <router-link class="avatar-anchor" :to="user | userPage">
- <img class="avatar" :src="`${user.avatarUrl}?thumbnail&size=64`" alt="avatar"/>
- </router-link>
+ <mk-avatar class="avatar" :user="user"/>
<div class="main">
<header>
<router-link class="name" :to="user | userPage">{{ user | userName }}</router-link>
@@ -40,26 +38,19 @@ export default Vue.extend({
display block
clear both
- > .avatar-anchor
+ > .avatar
display block
float left
margin 0 10px 0 0
+ width 48px
+ height 48px
+ border-radius 6px
@media (min-width 500px)
margin-right 16px
-
- > .avatar
- display block
- width 48px
- height 48px
- margin 0
- border-radius 6px
- vertical-align bottom
-
- @media (min-width 500px)
- width 58px
- height 58px
- border-radius 8px
+ width 58px
+ height 58px
+ border-radius 8px
> .main
float left
diff --git a/src/client/app/mobile/views/pages/dashboard.vue b/src/client/app/mobile/views/pages/dashboard.vue
index 53fe33ee8f..a5ca6cb4a2 100644
--- a/src/client/app/mobile/views/pages/dashboard.vue
+++ b/src/client/app/mobile/views/pages/dashboard.vue
@@ -64,8 +64,8 @@ export default Vue.extend({
};
},
created() {
- if ((this as any).os.i.clientSettings.mobileHome == null) {
- Vue.set((this as any).os.i.clientSettings, 'mobileHome', [{
+ if ((this as any).clientSettings.mobileHome == null) {
+ Vue.set((this as any).clientSettings, 'mobileHome', [{
name: 'calendar',
id: 'a', data: {}
}, {
@@ -87,14 +87,14 @@ export default Vue.extend({
name: 'version',
id: 'g', data: {}
}]);
- this.widgets = (this as any).os.i.clientSettings.mobileHome;
+ this.widgets = (this as any).clientSettings.mobileHome;
this.saveHome();
} else {
- this.widgets = (this as any).os.i.clientSettings.mobileHome;
+ this.widgets = (this as any).clientSettings.mobileHome;
}
- this.$watch('os.i.clientSettings', i => {
- this.widgets = (this as any).os.i.clientSettings.mobileHome;
+ this.$watch('clientSettings', i => {
+ this.widgets = (this as any).clientSettings.mobileHome;
}, {
deep: true
});
@@ -107,15 +107,15 @@ export default Vue.extend({
methods: {
onHomeUpdated(data) {
if (data.home) {
- (this as any).os.i.clientSettings.mobileHome = data.home;
+ (this as any).clientSettings.mobileHome = data.home;
this.widgets = data.home;
} else {
- const w = (this as any).os.i.clientSettings.mobileHome.find(w => w.id == data.id);
+ const w = (this as any).clientSettings.mobileHome.find(w => w.id == data.id);
if (w != null) {
w.data = data.data;
this.$refs[w.id][0].preventSave = true;
this.$refs[w.id][0].props = w.data;
- this.widgets = (this as any).os.i.clientSettings.mobileHome;
+ this.widgets = (this as any).clientSettings.mobileHome;
}
}
},
@@ -144,7 +144,7 @@ export default Vue.extend({
this.saveHome();
},
saveHome() {
- (this as any).os.i.clientSettings.mobileHome = this.widgets;
+ (this as any).clientSettings.mobileHome = this.widgets;
(this as any).api('i/update_mobile_home', {
home: this.widgets
});
diff --git a/src/client/app/mobile/views/pages/home.timeline.vue b/src/client/app/mobile/views/pages/home.timeline.vue
index 5f4bd6dcd8..4c1c344db1 100644
--- a/src/client/app/mobile/views/pages/home.timeline.vue
+++ b/src/client/app/mobile/views/pages/home.timeline.vue
@@ -92,8 +92,8 @@ export default Vue.extend({
(this as any).api(this.endpoint, {
limit: fetchLimit + 1,
untilDate: this.date ? this.date.getTime() : undefined,
- includeMyRenotes: (this as any).os.i.clientSettings.showMyRenotes,
- includeRenotedMyNotes: (this as any).os.i.clientSettings.showRenotedMyNotes
+ includeMyRenotes: (this as any).clientSettings.showMyRenotes,
+ includeRenotedMyNotes: (this as any).clientSettings.showRenotedMyNotes
}).then(notes => {
if (notes.length == fetchLimit + 1) {
notes.pop();
@@ -114,8 +114,8 @@ export default Vue.extend({
(this as any).api(this.endpoint, {
limit: fetchLimit + 1,
untilId: (this.$refs.timeline as any).tail().id,
- includeMyRenotes: (this as any).os.i.clientSettings.showMyRenotes,
- includeRenotedMyNotes: (this as any).os.i.clientSettings.showRenotedMyNotes
+ includeMyRenotes: (this as any).clientSettings.showMyRenotes,
+ includeRenotedMyNotes: (this as any).clientSettings.showRenotedMyNotes
}).then(notes => {
if (notes.length == fetchLimit + 1) {
notes.pop();
diff --git a/src/client/app/mobile/views/pages/welcome.vue b/src/client/app/mobile/views/pages/welcome.vue
index 485996870e..4d236d7aa5 100644
--- a/src/client/app/mobile/views/pages/welcome.vue
+++ b/src/client/app/mobile/views/pages/welcome.vue
@@ -22,9 +22,7 @@
<mk-welcome-timeline/>
</div>
<div class="users">
- <router-link v-for="user in users" :key="user.id" class="avatar-anchor" :to="`/@${user.username}`">
- <img class="avatar" :src="`${user.avatarUrl}?thumbnail&size=64`" alt="avatar"/>
- </router-link>
+ <mk-avatar class="avatar" :key="user.id" :user="user"/>
</div>
<footer>
<small>{{ copyright }}</small>
diff --git a/src/client/app/mobile/views/widgets/activity.vue b/src/client/app/mobile/views/widgets/activity.vue
index 48dcafb3ed..7763be41f5 100644
--- a/src/client/app/mobile/views/widgets/activity.vue
+++ b/src/client/app/mobile/views/widgets/activity.vue
@@ -21,6 +21,7 @@ export default define({
methods: {
func() {
this.props.compact = !this.props.compact;
+ this.save();
}
}
});
diff --git a/src/client/app/store.ts b/src/client/app/store.ts
new file mode 100644
index 0000000000..706fd65558
--- /dev/null
+++ b/src/client/app/store.ts
@@ -0,0 +1,90 @@
+import Vuex from 'vuex';
+import MiOS from './common/mios';
+
+const defaultSettings = {
+ home: [],
+ fetchOnScroll: true,
+ showMaps: true,
+ showPostFormOnTopOfTl: false,
+ circleIcons: true,
+ gradientWindowHeader: false,
+ showReplyTarget: true,
+ showMyRenotes: true,
+ showRenotedMyNotes: true
+};
+
+export default (os: MiOS) => new Vuex.Store({
+ plugins: [store => {
+ store.subscribe((mutation, state) => {
+ if (mutation.type.startsWith('settings/')) {
+ localStorage.setItem('settings', JSON.stringify(state.settings.data));
+ }
+ });
+ }],
+
+ state: {
+ uiHeaderHeight: 0
+ },
+
+ mutations: {
+ setUiHeaderHeight(state, height) {
+ state.uiHeaderHeight = height;
+ }
+ },
+
+ modules: {
+ settings: {
+ namespaced: true,
+
+ state: {
+ data: defaultSettings
+ },
+
+ mutations: {
+ init(state, settings) {
+ state.data = settings;
+ },
+
+ set(state, x: { key: string; value: any }) {
+ state.data[x.key] = x.value;
+ },
+
+ setHome(state, data) {
+ state.data.home = data;
+ },
+
+ setHomeWidget(state, x) {
+ const w = state.data.home.find(w => w.id == x.id);
+ if (w) {
+ w.data = x.data;
+ }
+ },
+
+ addHomeWidget(state, widget) {
+ state.data.home.unshift(widget);
+ }
+ },
+
+ actions: {
+ set(ctx, x) {
+ ctx.commit('set', x);
+
+ if (os.isSignedIn) {
+ os.api('i/update_client_setting', {
+ name: x.key,
+ value: x.value
+ });
+ }
+ },
+
+ addHomeWidget(ctx, widget) {
+ ctx.commit('addHomeWidget', widget);
+
+ os.api('i/update_home', {
+ home: ctx.state.data.home
+ });
+ }
+ }
+ }
+ }
+});