リファクタリングなど
This commit is contained in:
parent
1625b37b44
commit
372bfaceda
|
@ -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();
|
||||
},
|
||||
|
||||
this.$watch('props', newProps => {
|
||||
if (this.preventSave) {
|
||||
this.preventSave = false;
|
||||
this.bakeProps();
|
||||
return;
|
||||
methods: {
|
||||
bakeProps() {
|
||||
this.bakedOldProps = JSON.stringify(this.props);
|
||||
},
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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();
|
||||
|
|
38
src/client/app/common/views/components/avatar.vue
Normal file
38
src/client/app/common/views/components/avatar.vue
Normal file
|
@ -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>
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -61,6 +61,7 @@ export default define({
|
|||
} else {
|
||||
this.props.design++;
|
||||
}
|
||||
this.save();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -68,6 +68,7 @@ export default define({
|
|||
} else {
|
||||
this.props.design++;
|
||||
}
|
||||
this.save();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -73,6 +73,7 @@ export default define({
|
|||
} else {
|
||||
this.props.design++;
|
||||
}
|
||||
this.save();
|
||||
},
|
||||
tick() {
|
||||
const now = new Date();
|
||||
|
|
|
@ -59,6 +59,8 @@ export default define({
|
|||
} else {
|
||||
this.props.design++;
|
||||
}
|
||||
|
||||
this.save();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -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}`, {
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -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();
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
});
|
||||
},
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -22,9 +22,11 @@ export default define({
|
|||
} else {
|
||||
this.props.design++;
|
||||
}
|
||||
this.save();
|
||||
},
|
||||
viewChanged(view) {
|
||||
this.props.view = view;
|
||||
this.save();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -37,6 +37,7 @@ export default define({
|
|||
methods: {
|
||||
func() {
|
||||
this.props.compact = !this.props.compact;
|
||||
this.save();
|
||||
},
|
||||
settings() {
|
||||
const id = window.prompt('チャンネルID');
|
||||
|
|
|
@ -35,6 +35,7 @@ export default define({
|
|||
} else {
|
||||
this.props.design++;
|
||||
}
|
||||
this.save();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -23,6 +23,7 @@ export default define({
|
|||
},
|
||||
func() {
|
||||
this.props.compact = !this.props.compact;
|
||||
this.save();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -39,6 +39,7 @@ export default define({
|
|||
methods: {
|
||||
func() {
|
||||
this.props.compact = !this.props.compact;
|
||||
this.save();
|
||||
},
|
||||
fetch() {
|
||||
this.fetching = true;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -36,6 +36,7 @@ export default define({
|
|||
} else {
|
||||
this.props.design++;
|
||||
}
|
||||
this.save();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -22,6 +22,7 @@ export default define({
|
|||
} else {
|
||||
this.props.design++;
|
||||
}
|
||||
this.save();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -38,6 +38,7 @@ export default define({
|
|||
methods: {
|
||||
func() {
|
||||
this.props.compact = !this.props.compact;
|
||||
this.save();
|
||||
},
|
||||
fetch() {
|
||||
this.fetching = true;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
});
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
});
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -21,6 +21,7 @@ export default define({
|
|||
methods: {
|
||||
func() {
|
||||
this.props.compact = !this.props.compact;
|
||||
this.save();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
90
src/client/app/store.ts
Normal file
90
src/client/app/store.ts
Normal file
|
@ -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
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
|
@ -24,16 +24,11 @@ module.exports = async (params, user) => new Promise(async (res, rej) => {
|
|||
$set: x
|
||||
});
|
||||
|
||||
// Serialize
|
||||
user.clientSettings[name] = value;
|
||||
const iObj = await pack(user, user, {
|
||||
detail: true,
|
||||
includeSecrets: true
|
||||
res();
|
||||
|
||||
// Publish event
|
||||
event(user._id, 'clientSettingUpdated', {
|
||||
key: name,
|
||||
value
|
||||
});
|
||||
|
||||
// Send response
|
||||
res(iObj);
|
||||
|
||||
// Publish i updated event
|
||||
event(user._id, 'i_updated', iObj);
|
||||
});
|
||||
|
|
|
@ -26,9 +26,9 @@ if (process.env.NODE_ENV != 'production') {
|
|||
app.use(logger());
|
||||
|
||||
// Delay
|
||||
app.use(slow({
|
||||
delay: 1000
|
||||
}));
|
||||
//app.use(slow({
|
||||
// delay: 1000
|
||||
//}));
|
||||
}
|
||||
|
||||
// Compress response
|
||||
|
|
Loading…
Reference in a new issue