diff --git a/src/web/app/common/-tags/authorized-apps.tag b/src/web/app/common/-tags/authorized-apps.tag index 288c2fcc2d..ed1570650a 100644 --- a/src/web/app/common/-tags/authorized-apps.tag +++ b/src/web/app/common/-tags/authorized-apps.tag @@ -28,7 +28,6 @@ this.$root.$data.os.api('i/authorized_apps').then(apps => { this.apps = apps; this.fetching = false; - this.update(); }); }); </script> diff --git a/src/web/app/common/views/components/messaging.vue b/src/web/app/common/views/components/messaging.vue index c0b3a1924b..c1d5418944 100644 --- a/src/web/app/common/views/components/messaging.vue +++ b/src/web/app/common/views/components/messaging.vue @@ -78,8 +78,8 @@ export default Vue.extend({ this.connection.on('read', this.onRead); (this as any).api('messaging/history').then(messages => { - this.fetching = false; this.messages = messages; + this.fetching = false; }); }, beforeDestroy() { diff --git a/src/web/app/desktop/-tags/widgets/activity.tag b/src/web/app/desktop/-tags/widgets/activity.tag deleted file mode 100644 index 1f9bee5ed5..0000000000 --- a/src/web/app/desktop/-tags/widgets/activity.tag +++ /dev/null @@ -1,246 +0,0 @@ -<mk-activity-widget data-melt={ design == 2 }> - <template v-if="design == 0"> - <p class="title">%fa:chart-bar%%i18n:desktop.tags.mk-activity-widget.title%</p> - <button @click="toggle" title="%i18n:desktop.tags.mk-activity-widget.toggle%">%fa:sort%</button> - </template> - <p class="initializing" v-if="initializing">%fa:spinner .pulse .fw%%i18n:common.loading%<mk-ellipsis/></p> - <mk-activity-widget-calender v-if="!initializing && view == 0" data={ [].concat(activity) }/> - <mk-activity-widget-chart v-if="!initializing && view == 1" data={ [].concat(activity) }/> - <style lang="stylus" scoped> - :scope - display block - background #fff - border solid 1px rgba(0, 0, 0, 0.075) - border-radius 6px - - &[data-melt] - background transparent !important - border none !important - - > .title - z-index 1 - margin 0 - padding 0 16px - line-height 42px - font-size 0.9em - font-weight bold - color #888 - box-shadow 0 1px rgba(0, 0, 0, 0.07) - - > [data-fa] - margin-right 4px - - > button - position absolute - z-index 2 - top 0 - right 0 - padding 0 - width 42px - font-size 0.9em - line-height 42px - color #ccc - - &:hover - color #aaa - - &:active - color #999 - - > .initializing - margin 0 - padding 16px - text-align center - color #aaa - - > [data-fa] - margin-right 4px - - </style> - <script lang="typescript"> - this.mixin('api'); - - this.design = this.opts.design || 0; - this.view = this.opts.view || 0; - - this.user = this.opts.user; - this.initializing = true; - - this.on('mount', () => { - this.$root.$data.os.api('aggregation/users/activity', { - user_id: this.user.id, - limit: 20 * 7 - }).then(activity => { - this.update({ - initializing: false, - activity - }); - }); - }); - - this.toggle = () => { - this.view++; - if (this.view == 2) this.view = 0; - this.update(); - this.$emit('view-changed', this.view); - }; - </script> -</mk-activity-widget> - -<mk-activity-widget-calender> - <svg viewBox="0 0 21 7" preserveAspectRatio="none"> - <rect each={ data } class="day" - width="1" height="1" - riot-x={ x } riot-y={ date.weekday } - rx="1" ry="1" - fill="transparent"> - <title>{ date.year }/{ date.month }/{ date.day }<br/>Post: { posts }, Reply: { replies }, Repost: { reposts }</title> - </rect> - <rect each={ data } - riot-width={ v } riot-height={ v } - riot-x={ x + ((1 - v) / 2) } riot-y={ date.weekday + ((1 - v) / 2) } - rx="1" ry="1" - fill={ color } - style="pointer-events: none;"/> - <rect class="today" - width="1" height="1" - riot-x={ data[data.length - 1].x } riot-y={ data[data.length - 1].date.weekday } - rx="1" ry="1" - fill="none" - stroke-width="0.1" - stroke="#f73520"/> - </svg> - <style lang="stylus" scoped> - :scope - display block - - > svg - display block - padding 10px - width 100% - - > rect - transform-origin center - - &.day - &:hover - fill rgba(0, 0, 0, 0.05) - - </style> - <script lang="typescript"> - this.data = this.opts.data; - this.data.forEach(d => d.total = d.posts + d.replies + d.reposts); - const peak = Math.max.apply(null, this.data.map(d => d.total)); - - let x = 0; - this.data.reverse().forEach(d => { - d.x = x; - d.date.weekday = (new Date(d.date.year, d.date.month - 1, d.date.day)).getDay(); - - d.v = d.total / (peak / 2); - if (d.v > 1) d.v = 1; - const ch = d.date.weekday == 0 || d.date.weekday == 6 ? 275 : 170; - const cs = d.v * 100; - const cl = 15 + ((1 - d.v) * 80); - d.color = `hsl(${ch}, ${cs}%, ${cl}%)`; - - if (d.date.weekday == 6) x++; - }); - </script> -</mk-activity-widget-calender> - -<mk-activity-widget-chart> - <svg riot-viewBox="0 0 { viewBoxX } { viewBoxY }" preserveAspectRatio="none" onmousedown={ onMousedown }> - <title>Black ... Total<br/>Blue ... Posts<br/>Red ... Replies<br/>Green ... Reposts</title> - <polyline - riot-points={ pointsPost } - fill="none" - stroke-width="1" - stroke="#41ddde"/> - <polyline - riot-points={ pointsReply } - fill="none" - stroke-width="1" - stroke="#f7796c"/> - <polyline - riot-points={ pointsRepost } - fill="none" - stroke-width="1" - stroke="#a1de41"/> - <polyline - riot-points={ pointsTotal } - fill="none" - stroke-width="1" - stroke="#555" - stroke-dasharray="2 2"/> - </svg> - <style lang="stylus" scoped> - :scope - display block - - > svg - display block - padding 10px - width 100% - cursor all-scroll - </style> - <script lang="typescript"> - this.viewBoxX = 140; - this.viewBoxY = 60; - this.zoom = 1; - this.pos = 0; - - this.data = this.opts.data.reverse(); - this.data.forEach(d => d.total = d.posts + d.replies + d.reposts); - const peak = Math.max.apply(null, this.data.map(d => d.total)); - - this.on('mount', () => { - this.render(); - }); - - this.render = () => { - this.update({ - pointsPost: this.data.map((d, i) => `${(i * this.zoom) + this.pos},${(1 - (d.posts / peak)) * this.viewBoxY}`).join(' '), - pointsReply: this.data.map((d, i) => `${(i * this.zoom) + this.pos},${(1 - (d.replies / peak)) * this.viewBoxY}`).join(' '), - pointsRepost: this.data.map((d, i) => `${(i * this.zoom) + this.pos},${(1 - (d.reposts / peak)) * this.viewBoxY}`).join(' '), - pointsTotal: this.data.map((d, i) => `${(i * this.zoom) + this.pos},${(1 - (d.total / peak)) * this.viewBoxY}`).join(' ') - }); - }; - - this.onMousedown = e => { - e.preventDefault(); - - const clickX = e.clientX; - const clickY = e.clientY; - const baseZoom = this.zoom; - const basePos = this.pos; - - // 動かした時 - dragListen(me => { - let moveLeft = me.clientX - clickX; - let moveTop = me.clientY - clickY; - - this.zoom = baseZoom + (-moveTop / 20); - this.pos = basePos + moveLeft; - if (this.zoom < 1) this.zoom = 1; - if (this.pos > 0) this.pos = 0; - if (this.pos < -(((this.data.length - 1) * this.zoom) - this.viewBoxX)) this.pos = -(((this.data.length - 1) * this.zoom) - this.viewBoxX); - - this.render(); - }); - }; - - function dragListen(fn) { - window.addEventListener('mousemove', fn); - window.addEventListener('mouseleave', dragClear.bind(null, fn)); - window.addEventListener('mouseup', dragClear.bind(null, fn)); - } - - function dragClear(fn) { - window.removeEventListener('mousemove', fn); - window.removeEventListener('mouseleave', dragClear); - window.removeEventListener('mouseup', dragClear); - } - </script> -</mk-activity-widget-chart> - diff --git a/src/web/app/desktop/views/components/activity.calendar.vue b/src/web/app/desktop/views/components/activity.calendar.vue new file mode 100644 index 0000000000..d9b8523152 --- /dev/null +++ b/src/web/app/desktop/views/components/activity.calendar.vue @@ -0,0 +1,66 @@ +<template> +<svg viewBox="0 0 21 7" preserveAspectRatio="none"> + <rect v-for="record in data" class="day" + width="1" height="1" + :x="record.x" :y="record.date.weekday" + rx="1" ry="1" + fill="transparent"> + <title>{{ record.date.year }}/{{ record.date.month }}/{{ record.date.day }}</title> + </rect> + <rect v-for="record in data" class="day" + :width="record.v" :height="record.v" + :x="record.x + ((1 - record.v) / 2)" :y="record.date.weekday + ((1 - record.v) / 2)" + rx="1" ry="1" + :fill="record.color" + style="pointer-events: none;"/> + <rect class="today" + width="1" height="1" + :x="data[data.length - 1].x" :y="data[data.length - 1].date.weekday" + rx="1" ry="1" + fill="none" + stroke-width="0.1" + stroke="#f73520"/> +</svg> +</template> + +<script lang="ts"> +import Vue from 'vue'; + +export default Vue.extend({ + props: ['data'], + created() { + this.data.forEach(d => d.total = d.posts + d.replies + d.reposts); + const peak = Math.max.apply(null, this.data.map(d => d.total)); + + let x = 0; + this.data.reverse().forEach(d => { + d.x = x; + d.date.weekday = (new Date(d.date.year, d.date.month - 1, d.date.day)).getDay(); + + d.v = d.total / (peak / 2); + if (d.v > 1) d.v = 1; + const ch = d.date.weekday == 0 || d.date.weekday == 6 ? 275 : 170; + const cs = d.v * 100; + const cl = 15 + ((1 - d.v) * 80); + d.color = `hsl(${ch}, ${cs}%, ${cl}%)`; + + if (d.date.weekday == 6) x++; + }); + } +}); +</script> + +<style lang="stylus" scoped> +svg + display block + padding 10px + width 100% + + > rect + transform-origin center + + &.day + &:hover + fill rgba(0, 0, 0, 0.05) + +</style> diff --git a/src/web/app/desktop/views/components/activity.chart.vue b/src/web/app/desktop/views/components/activity.chart.vue new file mode 100644 index 0000000000..e64b181ba1 --- /dev/null +++ b/src/web/app/desktop/views/components/activity.chart.vue @@ -0,0 +1,101 @@ +<template> +<svg :viewBox="`0 0 ${ viewBoxX } ${ viewBoxY }`" preserveAspectRatio="none" @mousedown.prevent="onMousedown"> + <title>Black ... Total<br/>Blue ... Posts<br/>Red ... Replies<br/>Green ... Reposts</title> + <polyline + :points="pointsPost" + fill="none" + stroke-width="1" + stroke="#41ddde"/> + <polyline + :points="pointsReply" + fill="none" + stroke-width="1" + stroke="#f7796c"/> + <polyline + :points="pointsRepost" + fill="none" + stroke-width="1" + stroke="#a1de41"/> + <polyline + :points="pointsTotal" + fill="none" + stroke-width="1" + stroke="#555" + stroke-dasharray="2 2"/> +</svg> +</template> + +<script lang="ts"> +import Vue from 'vue'; + +function dragListen(fn) { + window.addEventListener('mousemove', fn); + window.addEventListener('mouseleave', dragClear.bind(null, fn)); + window.addEventListener('mouseup', dragClear.bind(null, fn)); +} + +function dragClear(fn) { + window.removeEventListener('mousemove', fn); + window.removeEventListener('mouseleave', dragClear); + window.removeEventListener('mouseup', dragClear); +} + +export default Vue.extend({ + props: ['data'], + data() { + return { + viewBoxX: 140, + viewBoxY: 60, + zoom: 1, + pos: 0, + pointsPost: null, + pointsReply: null, + pointsRepost: null, + pointsTotal: null + }; + }, + created() { + this.data.reverse(); + this.data.forEach(d => d.total = d.posts + d.replies + d.reposts); + this.render(); + }, + methods: { + render() { + const peak = Math.max.apply(null, this.data.map(d => d.total)); + this.pointsPost = this.data.map((d, i) => `${(i * this.zoom) + this.pos},${(1 - (d.posts / peak)) * this.viewBoxY}`).join(' '); + this.pointsReply = this.data.map((d, i) => `${(i * this.zoom) + this.pos},${(1 - (d.replies / peak)) * this.viewBoxY}`).join(' '); + this.pointsRepost = this.data.map((d, i) => `${(i * this.zoom) + this.pos},${(1 - (d.reposts / peak)) * this.viewBoxY}`).join(' '); + this.pointsTotal = this.data.map((d, i) => `${(i * this.zoom) + this.pos},${(1 - (d.total / peak)) * this.viewBoxY}`).join(' '); + }, + onMousedown(e) { + const clickX = e.clientX; + const clickY = e.clientY; + const baseZoom = this.zoom; + const basePos = this.pos; + + // 動かした時 + dragListen(me => { + let moveLeft = me.clientX - clickX; + let moveTop = me.clientY - clickY; + + this.zoom = baseZoom + (-moveTop / 20); + this.pos = basePos + moveLeft; + if (this.zoom < 1) this.zoom = 1; + if (this.pos > 0) this.pos = 0; + if (this.pos < -(((this.data.length - 1) * this.zoom) - this.viewBoxX)) this.pos = -(((this.data.length - 1) * this.zoom) - this.viewBoxX); + + this.render(); + }); + } + } +}); +</script> + +<style lang="stylus" scoped> +svg + display block + padding 10px + width 100% + cursor all-scroll + +</style> diff --git a/src/web/app/desktop/views/components/activity.vue b/src/web/app/desktop/views/components/activity.vue new file mode 100644 index 0000000000..d1c44f0f5d --- /dev/null +++ b/src/web/app/desktop/views/components/activity.vue @@ -0,0 +1,116 @@ +<template> +<div class="mk-activity"> + <template v-if="design == 0"> + <p class="title">%fa:chart-bar%%i18n:desktop.tags.mk-activity-widget.title%</p> + <button @click="toggle" title="%i18n:desktop.tags.mk-activity-widget.toggle%">%fa:sort%</button> + </template> + <p class="fetching" v-if="fetching">%fa:spinner .pulse .fw%%i18n:common.loading%<mk-ellipsis/></p> + <template v-else> + <mk-activity-widget-calender v-show="view == 0" :data="[].concat(activity)"/> + <mk-activity-widget-chart v-show="view == 1" :data="[].concat(activity)"/> + </template> +</div> +</template> + +<script lang="ts"> +import Vue from 'vue'; +import Calendar from './activity.calendar.vue'; +import Chart from './activity.chart.vue'; + +export default Vue.extend({ + components: { + 'mk-activity-widget-calender': Calendar, + 'mk-activity-widget-chart': Chart + }, + props: { + design: { + default: 0 + }, + initView: { + default: 0 + }, + user: { + type: Object, + required: true + } + }, + data() { + return { + fetching: true, + activity: null, + view: this.initView + }; + }, + mounted() { + (this as any).api('aggregation/users/activity', { + user_id: this.user.id, + limit: 20 * 7 + }).then(activity => { + this.activity = activity; + this.fetching = false; + }); + }, + methods: { + toggle() { + if (this.view == 1) { + this.view = 0; + this.$emit('viewChanged', this.view); + } else { + this.view++; + this.$emit('viewChanged', this.view); + } + } + } +}); +</script> + +<style lang="stylus" scoped> +.mk-activity + background #fff + border solid 1px rgba(0, 0, 0, 0.075) + border-radius 6px + + &[data-melt] + background transparent !important + border none !important + + > .title + z-index 1 + margin 0 + padding 0 16px + line-height 42px + font-size 0.9em + font-weight bold + color #888 + box-shadow 0 1px rgba(0, 0, 0, 0.07) + + > [data-fa] + margin-right 4px + + > button + position absolute + z-index 2 + top 0 + right 0 + padding 0 + width 42px + font-size 0.9em + line-height 42px + color #ccc + + &:hover + color #aaa + + &:active + color #999 + + > .fetching + margin 0 + padding 16px + text-align center + color #aaa + + > [data-fa] + margin-right 4px + +</style> diff --git a/src/web/app/desktop/views/components/calendar.vue b/src/web/app/desktop/views/components/calendar.vue index e548a82c57..a21d3e6148 100644 --- a/src/web/app/desktop/views/components/calendar.vue +++ b/src/web/app/desktop/views/components/calendar.vue @@ -47,7 +47,7 @@ export default Vue.extend({ default: 0 }, start: { - type: Object, + type: Date, required: false } }, @@ -94,7 +94,7 @@ export default Vue.extend({ isOutOfRange(day) { const test = (new Date(this.year, this.month - 1, day)).getTime(); return test > this.today.getTime() || - (this.start ? test < this.start.getTime() : false); + (this.start ? test < (this.start as any).getTime() : false); }, isDonichi(day) { diff --git a/src/web/app/desktop/views/components/followers-window.vue b/src/web/app/desktop/views/components/followers-window.vue index e56545cccb..ed439114c3 100644 --- a/src/web/app/desktop/views/components/followers-window.vue +++ b/src/web/app/desktop/views/components/followers-window.vue @@ -1,9 +1,9 @@ <template> -<mk-window width='400px' height='550px' @closed="$destroy"> +<mk-window width="400px" height="550px" @closed="$destroy"> <span slot="header" :class="$style.header"> <img :src="`${user.avatar_url}?thumbnail&size=64`" alt=""/>{{ user.name }}のフォロワー </span> - <mk-user-followers :user="user"/> + <mk-followers-list :user="user"/> </mk-window> </template> diff --git a/src/web/app/desktop/views/components/following-window.vue b/src/web/app/desktop/views/components/following-window.vue index fa2edfa473..4e1fb0306f 100644 --- a/src/web/app/desktop/views/components/following-window.vue +++ b/src/web/app/desktop/views/components/following-window.vue @@ -1,9 +1,9 @@ <template> -<mk-window width='400px' height='550px' @closed="$destroy"> +<mk-window width="400px" height="550px" @closed="$destroy"> <span slot="header" :class="$style.header"> <img :src="`${user.avatar_url}?thumbnail&size=64`" alt=""/>{{ user.name }}のフォロー </span> - <mk-user-following :user="user"/> + <mk-following-list :user="user"/> </mk-window> </template> diff --git a/src/web/app/desktop/views/components/friends-maker.vue b/src/web/app/desktop/views/components/friends-maker.vue index b23373421d..61015b979f 100644 --- a/src/web/app/desktop/views/components/friends-maker.vue +++ b/src/web/app/desktop/views/components/friends-maker.vue @@ -43,8 +43,8 @@ export default Vue.extend({ limit: this.limit, offset: this.limit * this.page }).then(users => { - this.fetching = false; this.users = users; + this.fetching = false; }); }, refresh() { diff --git a/src/web/app/desktop/views/components/index.ts b/src/web/app/desktop/views/components/index.ts index 9a27369547..8e48d67b98 100644 --- a/src/web/app/desktop/views/components/index.ts +++ b/src/web/app/desktop/views/components/index.ts @@ -34,6 +34,7 @@ import driveNavFolder from './drive-nav-folder.vue'; import postDetail from './post-detail.vue'; import settings from './settings.vue'; import calendar from './calendar.vue'; +import activity from './activity.vue'; import wNav from './widgets/nav.vue'; import wCalendar from './widgets/calendar.vue'; import wPhotoStream from './widgets/photo-stream.vue'; @@ -78,6 +79,7 @@ Vue.component('mk-drive-nav-folder', driveNavFolder); Vue.component('mk-post-detail', postDetail); Vue.component('mk-settings', settings); Vue.component('mk-calendar', calendar); +Vue.component('mk-activity', activity); Vue.component('mkw-nav', wNav); Vue.component('mkw-calendar', wCalendar); Vue.component('mkw-photo-stream', wPhotoStream); diff --git a/src/web/app/desktop/views/components/mute-setting.vue b/src/web/app/desktop/views/components/mute-setting.vue index 3fcc34c9e6..fe78401af9 100644 --- a/src/web/app/desktop/views/components/mute-setting.vue +++ b/src/web/app/desktop/views/components/mute-setting.vue @@ -23,8 +23,8 @@ export default Vue.extend({ }, mounted() { (this as any).api('mute/list').then(x => { - this.fetching = false; this.users = x.users; + this.fetching = false; }); } }); diff --git a/src/web/app/desktop/views/components/post-detail.vue b/src/web/app/desktop/views/components/post-detail.vue index c2c2559f63..429b3549b9 100644 --- a/src/web/app/desktop/views/components/post-detail.vue +++ b/src/web/app/desktop/views/components/post-detail.vue @@ -4,7 +4,7 @@ class="read-more" v-if="p.reply && p.reply.reply_id && context == null" title="会話をもっと読み込む" - @click="loadContext" + @click="fetchContext" :disabled="contextFetching" > <template v-if="!contextFetching">%fa:ellipsis-v%</template> diff --git a/src/web/app/desktop/views/components/timeline.vue b/src/web/app/desktop/views/components/timeline.vue index c638013380..3e06774753 100644 --- a/src/web/app/desktop/views/components/timeline.vue +++ b/src/web/app/desktop/views/components/timeline.vue @@ -57,8 +57,8 @@ export default Vue.extend({ (this as any).api('posts/timeline', { until_date: this.date ? this.date.getTime() : undefined }).then(posts => { - this.fetching = false; this.posts = posts; + this.fetching = false; if (cb) cb(); }); }, diff --git a/src/web/app/desktop/views/components/users-list.vue b/src/web/app/desktop/views/components/users-list.vue index 12abb372e7..b93a81630c 100644 --- a/src/web/app/desktop/views/components/users-list.vue +++ b/src/web/app/desktop/views/components/users-list.vue @@ -45,9 +45,9 @@ export default Vue.extend({ _fetch(cb) { this.fetching = true; this.fetch(this.mode == 'iknow', this.limit, null, obj => { - this.fetching = false; this.users = obj.users; this.next = obj.next; + this.fetching = false; if (cb) cb(); }); }, diff --git a/src/web/app/desktop/views/components/widgets/broadcast.vue b/src/web/app/desktop/views/components/widgets/broadcast.vue index cdc65a2a7b..1a0fd9280c 100644 --- a/src/web/app/desktop/views/components/widgets/broadcast.vue +++ b/src/web/app/desktop/views/components/widgets/broadcast.vue @@ -46,8 +46,8 @@ export default define({ } }); } - this.fetching = false; this.broadcasts = broadcasts; + this.fetching = false; }); }, methods: { diff --git a/src/web/app/desktop/views/components/widgets/photo-stream.vue b/src/web/app/desktop/views/components/widgets/photo-stream.vue index a3f37e8c7e..6ad7d2f064 100644 --- a/src/web/app/desktop/views/components/widgets/photo-stream.vue +++ b/src/web/app/desktop/views/components/widgets/photo-stream.vue @@ -35,8 +35,8 @@ export default define({ type: 'image/*', limit: 9 }).then(images => { - this.fetching = false; this.images = images; + this.fetching = false; }); }, beforeDestroy() { diff --git a/src/web/app/desktop/views/components/widgets/slideshow.vue b/src/web/app/desktop/views/components/widgets/slideshow.vue index beda350666..3c2ef6da4f 100644 --- a/src/web/app/desktop/views/components/widgets/slideshow.vue +++ b/src/web/app/desktop/views/components/widgets/slideshow.vue @@ -93,8 +93,8 @@ export default define({ type: 'image/*', limit: 100 }).then(images => { - this.fetching = false; this.images = images; + this.fetching = false; (this.$refs.slideA as any).style.backgroundImage = ''; (this.$refs.slideB as any).style.backgroundImage = ''; this.change(); diff --git a/src/web/app/desktop/views/pages/messaging-room.vue b/src/web/app/desktop/views/pages/messaging-room.vue index 3e4fb256ac..ace9e1607b 100644 --- a/src/web/app/desktop/views/pages/messaging-room.vue +++ b/src/web/app/desktop/views/pages/messaging-room.vue @@ -24,8 +24,8 @@ export default Vue.extend({ (this as any).api('users/show', { username: this.username }).then(user => { - this.fetching = false; this.user = user; + this.fetching = false; document.title = 'メッセージ: ' + this.user.name; diff --git a/src/web/app/desktop/views/pages/post.vue b/src/web/app/desktop/views/pages/post.vue index 186ee332f6..8b9f30f108 100644 --- a/src/web/app/desktop/views/pages/post.vue +++ b/src/web/app/desktop/views/pages/post.vue @@ -26,8 +26,8 @@ export default Vue.extend({ (this as any).api('posts/show', { post_id: this.postId }).then(post => { - this.fetching = false; this.post = post; + this.fetching = false; Progress.done(); }); diff --git a/src/web/app/desktop/views/pages/search.vue b/src/web/app/desktop/views/pages/search.vue index 828aac8fe1..b8e8db2e79 100644 --- a/src/web/app/desktop/views/pages/search.vue +++ b/src/web/app/desktop/views/pages/search.vue @@ -45,8 +45,8 @@ export default Vue.extend({ window.addEventListener('scroll', this.onScroll); (this as any).api('posts/search', parse(this.query)).then(posts => { - this.fetching = false; this.posts = posts; + this.fetching = false; }); }, beforeDestroy() { diff --git a/src/web/app/desktop/views/pages/user/user-followers-you-know.vue b/src/web/app/desktop/views/pages/user/user-followers-you-know.vue index 246ff865d1..c58eb75bcf 100644 --- a/src/web/app/desktop/views/pages/user/user-followers-you-know.vue +++ b/src/web/app/desktop/views/pages/user/user-followers-you-know.vue @@ -27,8 +27,8 @@ export default Vue.extend({ iknow: true, limit: 16 }).then(x => { - this.fetching = false; this.users = x.users; + this.fetching = false; }); } }); diff --git a/src/web/app/desktop/views/pages/user/user-friends.vue b/src/web/app/desktop/views/pages/user/user-friends.vue index 9f324cfc08..a144ca2ad1 100644 --- a/src/web/app/desktop/views/pages/user/user-friends.vue +++ b/src/web/app/desktop/views/pages/user/user-friends.vue @@ -2,16 +2,18 @@ <div class="mk-user-friends"> <p class="title">%fa:users%%i18n:desktop.tags.mk-user.frequently-replied-users.title%</p> <p class="initializing" v-if="fetching">%fa:spinner .pulse .fw%%i18n:desktop.tags.mk-user.frequently-replied-users.loading%<mk-ellipsis/></p> - <div class="user" v-if="!fetching && users.length != 0" each={ _user in users }> - <a class="avatar-anchor" href={ '/' + _user.username }> - <img class="avatar" src={ _user.avatar_url + '?thumbnail&size=42' } alt="" v-user-preview={ _user.id }/> - </a> - <div class="body"> - <a class="name" href={ '/' + _user.username } v-user-preview={ _user.id }>{ _user.name }</a> - <p class="username">@{ _user.username }</p> + <template v-if="!fetching && users.length != 0"> + <div class="user" v-for="friend in users"> + <router-link class="avatar-anchor" to="`/${friend.username}`"> + <img class="avatar" :src="`${friend.avatar_url}?thumbnail&size=42`" alt="" v-user-preview="friend.id"/> + </router-link> + <div class="body"> + <router-link class="name" to="`/${friend.username}`" v-user-preview="friend.id">{{ friend.name }}</router-link> + <p class="username">@{{ friend.username }}</p> + </div> + <mk-follow-button :user="friend"/> </div> - <mk-follow-button user={ _user }/> - </div> + </template> <p class="empty" v-if="!fetching && users.length == 0">%i18n:desktop.tags.mk-user.frequently-replied-users.no-users%</p> </div> </template> @@ -31,8 +33,8 @@ export default Vue.extend({ user_id: this.user.id, limit: 4 }).then(docs => { - this.fetching = false; this.users = docs.map(doc => doc.user); + this.fetching = false; }); } }); diff --git a/src/web/app/desktop/views/pages/user/user-home.vue b/src/web/app/desktop/views/pages/user/user-home.vue index ca2c68840c..5ed901579e 100644 --- a/src/web/app/desktop/views/pages/user/user-home.vue +++ b/src/web/app/desktop/views/pages/user/user-home.vue @@ -14,8 +14,8 @@ </main> <div> <div ref="right"> - <mk-calendar-widget @warp="warp" :start="new Date(user.created_at)"/> - <mk-activity-widget :user="user"/> + <mk-calendar @chosen="warp" :start="new Date(user.created_at)"/> + <mk-activity :user="user"/> <mk-user-friends :user="user"/> <div class="nav"><mk-nav/></div> </div> @@ -25,7 +25,20 @@ <script lang="ts"> import Vue from 'vue'; +import MkUserTimeline from './user-timeline.vue'; +import MkUserProfile from './user-profile.vue'; +import MkUserPhotos from './user-photos.vue'; +import MkUserFollowersYouKnow from './user-followers-you-know.vue'; +import MkUserFriends from './user-friends.vue'; + export default Vue.extend({ + components: { + 'mk-user-timeline': MkUserTimeline, + 'mk-user-profile': MkUserProfile, + 'mk-user-photos': MkUserPhotos, + 'mk-user-followers-you-know': MkUserFollowersYouKnow, + 'mk-user-friends': MkUserFriends + }, props: ['user'], methods: { warp(date) { diff --git a/src/web/app/desktop/views/pages/user/user-photos.vue b/src/web/app/desktop/views/pages/user/user-photos.vue index 789d9af85f..4029a95cc8 100644 --- a/src/web/app/desktop/views/pages/user/user-photos.vue +++ b/src/web/app/desktop/views/pages/user/user-photos.vue @@ -3,8 +3,7 @@ <p class="title">%fa:camera%%i18n:desktop.tags.mk-user.photos.title%</p> <p class="initializing" v-if="fetching">%fa:spinner .pulse .fw%%i18n:desktop.tags.mk-user.photos.loading%<mk-ellipsis/></p> <div class="stream" v-if="!fetching && images.length > 0"> - <div v-for="image in images" :key="image.id" - class="img" + <div v-for="image in images" class="img" :style="`background-image: url(${image.url}?thumbnail&size=256)`" ></div> </div> @@ -28,12 +27,12 @@ export default Vue.extend({ with_media: true, limit: 9 }).then(posts => { - this.fetching = false; posts.forEach(post => { post.media.forEach(media => { if (this.images.length < 9) this.images.push(media); }); }); + this.fetching = false; }); } }); diff --git a/src/web/app/desktop/views/pages/user/user-profile.vue b/src/web/app/desktop/views/pages/user/user-profile.vue index d389e01c19..32c28595e9 100644 --- a/src/web/app/desktop/views/pages/user/user-profile.vue +++ b/src/web/app/desktop/views/pages/user/user-profile.vue @@ -14,7 +14,7 @@ <p>%fa:B twitter%<a :href="`https://twitter.com/${user.twitter.screen_name}`" target="_blank">@{{ user.twitter.screen_name }}</a></p> </div> <div class="status"> - <p class="posts-count">%fa:angle-right%<a>{{ user.posts_count }}</a><b>投稿</b></p> + <p class="posts-count">%fa:angle-right%<a>{{ user.posts_count }}</a><b>投稿</b></p> <p class="following">%fa:angle-right%<a @click="showFollowing">{{ user.following_count }}</a>人を<b>フォロー</b></p> <p class="followers">%fa:angle-right%<a @click="showFollowers">{{ user.followers_count }}</a>人の<b>フォロワー</b></p> </div> @@ -23,7 +23,9 @@ <script lang="ts"> import Vue from 'vue'; -const age = require('s-age'); +import age from 's-age'; +import MkFollowingWindow from '../../components/following-window.vue'; +import MkFollowersWindow from '../../components/followers-window.vue'; export default Vue.extend({ props: ['user'], @@ -34,8 +36,7 @@ export default Vue.extend({ }, methods: { showFollowing() { - document.body.appendChild(new MkUserFollowingWindow({ - + document.body.appendChild(new MkFollowingWindow({ propsData: { user: this.user } @@ -43,8 +44,7 @@ export default Vue.extend({ }, showFollowers() { - document.body.appendChild(new MkUserFollowersWindow({ - + document.body.appendChild(new MkFollowersWindow({ propsData: { user: this.user } @@ -56,7 +56,7 @@ export default Vue.extend({ user_id: this.user.id }).then(() => { this.user.is_muted = true; - }, e => { + }, () => { alert('error'); }); }, @@ -66,7 +66,7 @@ export default Vue.extend({ user_id: this.user.id }).then(() => { this.user.is_muted = false; - }, e => { + }, () => { alert('error'); }); } diff --git a/src/web/app/desktop/views/components/user-timeline.vue b/src/web/app/desktop/views/pages/user/user-timeline.vue similarity index 100% rename from src/web/app/desktop/views/components/user-timeline.vue rename to src/web/app/desktop/views/pages/user/user-timeline.vue index fa5b32f225..9dd07653c4 100644 --- a/src/web/app/desktop/views/components/user-timeline.vue +++ b/src/web/app/desktop/views/pages/user/user-timeline.vue @@ -65,8 +65,8 @@ export default Vue.extend({ until_date: this.date ? this.date.getTime() : undefined, with_replies: this.mode == 'with-replies' }).then(posts => { - this.fetching = false; this.posts = posts; + this.fetching = false; if (cb) cb(); }); }, diff --git a/src/web/app/desktop/views/pages/user/user.vue b/src/web/app/desktop/views/pages/user/user.vue index 765057e651..def9ced362 100644 --- a/src/web/app/desktop/views/pages/user/user.vue +++ b/src/web/app/desktop/views/pages/user/user.vue @@ -35,8 +35,8 @@ export default Vue.extend({ (this as any).api('users/show', { username: this.$route.params.user }).then(user => { - this.fetching = false; this.user = user; + this.fetching = false; Progress.done(); document.title = user.name + ' | Misskey'; }); diff --git a/src/web/app/mobile/views/components/drive.vue b/src/web/app/mobile/views/components/drive.vue index e581d3f053..0e54563323 100644 --- a/src/web/app/mobile/views/components/drive.vue +++ b/src/web/app/mobile/views/components/drive.vue @@ -351,13 +351,14 @@ export default Vue.extend({ (this as any).api('drive/files/show', { file_id: file }).then(file => { - this.fetching = false; this.file = file; this.folder = null; this.hierarchyFolders = []; if (file.folder) this.dive(file.folder); + this.fetching = false; + this.$emit('open-file', this.file, silent); }); }, diff --git a/src/web/app/mobile/views/components/friends-maker.vue b/src/web/app/mobile/views/components/friends-maker.vue index b069b988cc..8e7bf2d632 100644 --- a/src/web/app/mobile/views/components/friends-maker.vue +++ b/src/web/app/mobile/views/components/friends-maker.vue @@ -36,8 +36,8 @@ export default Vue.extend({ limit: this.limit, offset: this.limit * this.page }).then(users => { - this.fetching = false; this.users = users; + this.fetching = false; }); }, refresh() { diff --git a/src/web/app/mobile/views/components/timeline.vue b/src/web/app/mobile/views/components/timeline.vue index a04780e94d..80fda75605 100644 --- a/src/web/app/mobile/views/components/timeline.vue +++ b/src/web/app/mobile/views/components/timeline.vue @@ -63,8 +63,8 @@ export default Vue.extend({ (this as any).api('posts/timeline', { until_date: this.date ? (this.date as any).getTime() : undefined }).then(posts => { - this.fetching = false; this.posts = posts; + this.fetching = false; if (cb) cb(); }); }, diff --git a/src/web/app/mobile/views/components/user-timeline.vue b/src/web/app/mobile/views/components/user-timeline.vue index fb2a214198..ffd6288381 100644 --- a/src/web/app/mobile/views/components/user-timeline.vue +++ b/src/web/app/mobile/views/components/user-timeline.vue @@ -31,8 +31,8 @@ export default Vue.extend({ user_id: this.user.id, with_media: this.withMedia }).then(posts => { - this.fetching = false; this.posts = posts; + this.fetching = false; this.$emit('loaded'); }); } diff --git a/src/web/app/mobile/views/components/users-list.vue b/src/web/app/mobile/views/components/users-list.vue index 45629c5586..24c96aec79 100644 --- a/src/web/app/mobile/views/components/users-list.vue +++ b/src/web/app/mobile/views/components/users-list.vue @@ -41,9 +41,9 @@ export default Vue.extend({ _fetch(cb) { this.fetching = true; this.fetch(this.mode == 'iknow', this.limit, null, obj => { - this.fetching = false; this.users = obj.users; this.next = obj.next; + this.fetching = false; if (cb) cb(); }); }, diff --git a/src/web/app/mobile/views/pages/followers.vue b/src/web/app/mobile/views/pages/followers.vue index e9696dbd3c..2f102bd68f 100644 --- a/src/web/app/mobile/views/pages/followers.vue +++ b/src/web/app/mobile/views/pages/followers.vue @@ -26,8 +26,8 @@ export default Vue.extend({ (this as any).api('users/show', { username: this.username }).then(user => { - this.fetching = false; this.user = user; + this.fetching = false; document.title = '%i18n:mobile.tags.mk-user-followers-page.followers-of%'.replace('{}', user.name) + ' | Misskey'; document.documentElement.style.background = '#313a42'; diff --git a/src/web/app/mobile/views/pages/following.vue b/src/web/app/mobile/views/pages/following.vue index c278abfd25..20f085a9f1 100644 --- a/src/web/app/mobile/views/pages/following.vue +++ b/src/web/app/mobile/views/pages/following.vue @@ -26,8 +26,8 @@ export default Vue.extend({ (this as any).api('users/show', { username: this.username }).then(user => { - this.fetching = false; this.user = user; + this.fetching = false; document.title = '%i18n:mobile.tags.mk-user-followers-page.followers-of%'.replace('{}', user.name) + ' | Misskey'; document.documentElement.style.background = '#313a42'; diff --git a/src/web/app/mobile/views/pages/post.vue b/src/web/app/mobile/views/pages/post.vue index c5b6750afa..03e9972a44 100644 --- a/src/web/app/mobile/views/pages/post.vue +++ b/src/web/app/mobile/views/pages/post.vue @@ -32,8 +32,8 @@ export default Vue.extend({ (this as any).api('posts/show', { post_id: this.postId }).then(post => { - this.fetching = false; this.post = post; + this.fetching = false; Progress.done(); }); diff --git a/src/web/app/mobile/views/pages/user.vue b/src/web/app/mobile/views/pages/user.vue index f5babbd67f..53cde1fb68 100644 --- a/src/web/app/mobile/views/pages/user.vue +++ b/src/web/app/mobile/views/pages/user.vue @@ -88,8 +88,8 @@ export default Vue.extend({ (this as any).api('users/show', { username: this.username }).then(user => { - this.fetching = false; this.user = user; + this.fetching = false; Progress.done(); document.title = user.name + ' | Misskey'; diff --git a/src/web/app/mobile/views/pages/user/home-friends.vue b/src/web/app/mobile/views/pages/user/home-friends.vue index 4f2f12a642..543ed9b30d 100644 --- a/src/web/app/mobile/views/pages/user/home-friends.vue +++ b/src/web/app/mobile/views/pages/user/home-friends.vue @@ -22,8 +22,8 @@ export default Vue.extend({ (this as any).api('users/get_frequently_replied_users', { user_id: this.user.id }).then(res => { - this.fetching = false; this.users = res.map(x => x.user); + this.fetching = false; }); } }); diff --git a/src/web/app/mobile/views/pages/user/home-photos.vue b/src/web/app/mobile/views/pages/user/home-photos.vue index eb53eb89a9..dbb2a410aa 100644 --- a/src/web/app/mobile/views/pages/user/home-photos.vue +++ b/src/web/app/mobile/views/pages/user/home-photos.vue @@ -28,7 +28,6 @@ export default Vue.extend({ with_media: true, limit: 6 }).then(posts => { - this.fetching = false; posts.forEach(post => { post.media.forEach(media => { if (this.images.length < 9) this.images.push({ @@ -37,6 +36,7 @@ export default Vue.extend({ }); }); }); + this.fetching = false; }); } }); diff --git a/src/web/app/mobile/views/pages/user/home-posts.vue b/src/web/app/mobile/views/pages/user/home-posts.vue index c60f114b88..8b1ea2de54 100644 --- a/src/web/app/mobile/views/pages/user/home-posts.vue +++ b/src/web/app/mobile/views/pages/user/home-posts.vue @@ -22,8 +22,8 @@ export default Vue.extend({ (this as any).api('users/posts', { user_id: this.user.id }).then(posts => { - this.fetching = false; this.posts = posts; + this.fetching = false; }); } });