diff options
| author | syuilo <syuilotan@yahoo.co.jp> | 2017-11-14 08:21:19 +0900 |
|---|---|---|
| committer | syuilo <syuilotan@yahoo.co.jp> | 2017-11-14 08:21:19 +0900 |
| commit | 107ecfb07fe81dc5b89d9ef57a7be77657463d31 (patch) | |
| tree | 65e1f0416b88304a760a853cbb010d2423c0a435 /src | |
| parent | Clean up (diff) | |
| download | sharkey-107ecfb07fe81dc5b89d9ef57a7be77657463d31.tar.gz sharkey-107ecfb07fe81dc5b89d9ef57a7be77657463d31.tar.bz2 sharkey-107ecfb07fe81dc5b89d9ef57a7be77657463d31.zip | |
なんか
Diffstat (limited to 'src')
| -rw-r--r-- | src/api/endpoints/users/posts.ts | 28 | ||||
| -rw-r--r-- | src/web/app/desktop/tags/calendar.tag | 241 | ||||
| -rw-r--r-- | src/web/app/desktop/tags/home-widgets/timemachine.tag | 231 | ||||
| -rw-r--r-- | src/web/app/desktop/tags/index.ts | 6 | ||||
| -rw-r--r-- | src/web/app/desktop/tags/user-graphs.tag | 41 | ||||
| -rw-r--r-- | src/web/app/desktop/tags/user-header.tag | 147 | ||||
| -rw-r--r-- | src/web/app/desktop/tags/user-home.tag | 46 | ||||
| -rw-r--r-- | src/web/app/desktop/tags/user-photos.tag | 91 | ||||
| -rw-r--r-- | src/web/app/desktop/tags/user-profile.tag | 102 | ||||
| -rw-r--r-- | src/web/app/desktop/tags/user-timeline.tag | 9 | ||||
| -rw-r--r-- | src/web/app/desktop/tags/user.tag | 457 |
11 files changed, 727 insertions, 672 deletions
diff --git a/src/api/endpoints/users/posts.ts b/src/api/endpoints/users/posts.ts index d8204b8b80..fe821cf17a 100644 --- a/src/api/endpoints/users/posts.ts +++ b/src/api/endpoints/users/posts.ts @@ -46,9 +46,17 @@ module.exports = (params, me) => new Promise(async (res, rej) => { const [maxId, maxIdErr] = $(params.max_id).optional.id().$; if (maxIdErr) return rej('invalid max_id param'); - // Check if both of since_id and max_id is specified - if (sinceId && maxId) { - return rej('cannot set since_id and max_id'); + // Get 'since_date' parameter + const [sinceDate, sinceDateErr] = $(params.since_date).optional.number().$; + if (sinceDateErr) throw 'invalid since_date param'; + + // Get 'max_date' parameter + const [maxDate, maxDateErr] = $(params.max_date).optional.number().$; + if (maxDateErr) throw 'invalid max_date param'; + + // Check if only one of since_id, max_id, since_date, max_date specified + if ([sinceId, maxId, sinceDate, maxDate].filter(x => x != null).length > 1) { + throw 'only one of since_id, max_id, since_date, max_date can be specified'; } const q = userId !== undefined @@ -66,13 +74,15 @@ module.exports = (params, me) => new Promise(async (res, rej) => { return rej('user not found'); } - // Construct query + //#region Construct query const sort = { _id: -1 }; + const query = { user_id: user._id } as any; + if (sinceId) { sort._id = 1; query._id = { @@ -82,6 +92,15 @@ module.exports = (params, me) => new Promise(async (res, rej) => { query._id = { $lt: maxId }; + } else if (sinceDate) { + sort._id = 1; + query.created_at = { + $gt: new Date(sinceDate) + }; + } else if (maxDate) { + query.created_at = { + $lt: new Date(maxDate) + }; } if (!includeReplies) { @@ -94,6 +113,7 @@ module.exports = (params, me) => new Promise(async (res, rej) => { $ne: null }; } + //#endregion // Issue query const posts = await Post diff --git a/src/web/app/desktop/tags/calendar.tag b/src/web/app/desktop/tags/calendar.tag new file mode 100644 index 0000000000..3535e81901 --- /dev/null +++ b/src/web/app/desktop/tags/calendar.tag @@ -0,0 +1,241 @@ +<mk-calendar data-melt={ opts.design == 4 || opts.design == 5 }> + <virtual if={ opts.design == 0 || opts.design == 1 }> + <button onclick={ prev } title="%i18n:desktop.tags.mk-calendar.prev%"><i class="fa fa-chevron-circle-left"></i></button> + <p class="title">{ '%i18n:desktop.tags.mk-calendar.title%'.replace('{1}', year).replace('{2}', month) }</p> + <button onclick={ next } title="%i18n:desktop.tags.mk-calendar.next%"><i class="fa fa-chevron-circle-right"></i></button> + </virtual> + + <div class="calendar"> + <div class="weekday" if={ opts.design == 0 || opts.design == 2 || opts.design == 4} each={ day, i in Array(7).fill(0) } + data-today={ year == today.getFullYear() && month == today.getMonth() + 1 && today.getDay() == i } + data-is-donichi={ i == 0 || i == 6 }>{ weekdayText[i] }</div> + <div each={ day, i in Array(paddingDays).fill(0) }></div> + <div class="day" each={ day, i in Array(days).fill(0) } + data-today={ isToday(i + 1) } + data-selected={ isSelected(i + 1) } + data-is-out-of-range={ isOutOfRange(i + 1) } + data-is-donichi={ isDonichi(i + 1) } + onclick={ go.bind(null, i + 1) } + title={ isOutOfRange(i + 1) ? null : '%i18n:desktop.tags.mk-calendar.go%' }><div>{ i + 1 }</div></div> + </div> + <style> + :scope + display block + color #777 + 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 + text-align center + line-height 42px + font-size 0.9em + font-weight bold + color #888 + box-shadow 0 1px rgba(0, 0, 0, 0.07) + + > i + margin-right 4px + + > button + position absolute + z-index 2 + top 0 + padding 0 + width 42px + font-size 0.9em + line-height 42px + color #ccc + + &:hover + color #aaa + + &:active + color #999 + + &:first-of-type + left 0 + + &:last-of-type + right 0 + + > .calendar + display flex + flex-wrap wrap + padding 16px + + * + user-select none + + > div + width calc(100% * (1/7)) + text-align center + line-height 32px + font-size 14px + + &.weekday + color #19a2a9 + + &[data-is-donichi] + color #ef95a0 + + &[data-today] + box-shadow 0 0 0 1px #19a2a9 inset + border-radius 6px + + &[data-is-donichi] + box-shadow 0 0 0 1px #ef95a0 inset + + &.day + cursor pointer + color #777 + + > div + border-radius 6px + + &:hover > div + background rgba(0, 0, 0, 0.025) + + &:active > div + background rgba(0, 0, 0, 0.05) + + &[data-is-donichi] + color #ef95a0 + + &[data-is-out-of-range] + cursor default + color rgba(#777, 0.5) + + &[data-is-donichi] + color rgba(#ef95a0, 0.5) + + &[data-selected] + font-weight bold + + > div + background rgba(0, 0, 0, 0.025) + + &:active > div + background rgba(0, 0, 0, 0.05) + + &[data-today] + > div + color $theme-color-foreground + background $theme-color + + &:hover > div + background lighten($theme-color, 10%) + + &:active > div + background darken($theme-color, 10%) + + </style> + <script> + if (this.opts.design == null) this.opts.design = 0; + + const eachMonthDays = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; + + function isLeapYear(year) { + return (year % 400 == 0) ? true : + (year % 100 == 0) ? false : + (year % 4 == 0) ? true : + false; + } + + this.today = new Date(); + this.year = this.today.getFullYear(); + this.month = this.today.getMonth() + 1; + this.selected = this.today; + this.weekdayText = [ + '%i18n:common.weekday-short.sunday%', + '%i18n:common.weekday-short.monday%', + '%i18n:common.weekday-short.tuesday%', + '%i18n:common.weekday-short.wednesday%', + '%i18n:common.weekday-short.thursday%', + '%i18n:common.weekday-short.friday%', + '%i18n:common.weekday-short.satruday%' + ]; + + this.on('mount', () => { + this.calc(); + }); + + this.isToday = day => { + return this.year == this.today.getFullYear() && this.month == this.today.getMonth() + 1 && day == this.today.getDate(); + }; + + this.isSelected = day => { + return this.year == this.selected.getFullYear() && this.month == this.selected.getMonth() + 1 && day == this.selected.getDate(); + }; + + this.isOutOfRange = day => { + const test = (new Date(this.year, this.month - 1, day)).getTime(); + return test > this.today.getTime() || + (this.opts.start ? test < this.opts.start.getTime() : false); + }; + + this.isDonichi = day => { + const weekday = (new Date(this.year, this.month - 1, day)).getDay(); + return weekday == 0 || weekday == 6; + }; + + this.calc = () => { + let days = eachMonthDays[this.month - 1]; + + // うるう年なら+1日 + if (this.month == 2 && isLeapYear(this.year)) days++; + + const date = new Date(this.year, this.month - 1, 1); + const weekday = date.getDay(); + + this.update({ + paddingDays: weekday, + days: days + }); + }; + + this.prev = () => { + if (this.month == 1) { + this.update({ + year: this.year - 1, + month: 12 + }); + } else { + this.update({ + month: this.month - 1 + }); + } + this.calc(); + }; + + this.next = () => { + if (this.month == 12) { + this.update({ + year: this.year + 1, + month: 1 + }); + } else { + this.update({ + month: this.month + 1 + }); + } + this.calc(); + }; + + this.go = day => { + if (this.isOutOfRange(day)) return; + const date = new Date(this.year, this.month - 1, day, 23, 59, 59, 999); + this.update({ + selected: date + }); + this.opts.warp(date); + }; +</script> +</mk-calendar> diff --git a/src/web/app/desktop/tags/home-widgets/timemachine.tag b/src/web/app/desktop/tags/home-widgets/timemachine.tag index 984258d2ba..2199cf4c67 100644 --- a/src/web/app/desktop/tags/home-widgets/timemachine.tag +++ b/src/web/app/desktop/tags/home-widgets/timemachine.tag @@ -1,139 +1,10 @@ -<mk-timemachine-home-widget data-melt={ data.design == 4 || data.design == 5 }> - <virtual if={ data.design == 0 || data.design == 1 }> - <button onclick={ prev } title="%i18n:desktop.tags.mk-timemachine-home-widget.prev%"><i class="fa fa-chevron-circle-left"></i></button> - <p class="title">{ '%i18n:desktop.tags.mk-timemachine-home-widget.title%'.replace('{1}', year).replace('{2}', month) }</p> - <button onclick={ next } title="%i18n:desktop.tags.mk-timemachine-home-widget.next%"><i class="fa fa-chevron-circle-right"></i></button> - </virtual> - - <div class="calendar"> - <div class="weekday" if={ data.design == 0 || data.design == 2 || data.design == 4} each={ day, i in Array(7).fill(0) } - data-today={ year == today.getFullYear() && month == today.getMonth() + 1 && today.getDay() == i } - data-is-donichi={ i == 0 || i == 6 }>{ weekdayText[i] }</div> - <div each={ day, i in Array(paddingDays).fill(0) }></div> - <div class="day" each={ day, i in Array(days).fill(0) } - data-today={ isToday(i + 1) } - data-selected={ isSelected(i + 1) } - data-is-future={ isFuture(i + 1) } - data-is-donichi={ isDonichi(i + 1) } - onclick={ go.bind(null, i + 1) } - title={ isFuture(i + 1) ? null : '%i18n:desktop.tags.mk-timemachine-home-widget.go%' }><div>{ i + 1 }</div></div> - </div> +<mk-timemachine-home-widget> + <mk-calendar design={ data.design } warp={ warp }/> <style> :scope display block - color #777 - background #fff - - &[data-melt] - background transparent !important - border none !important - - > .title - z-index 1 - margin 0 - padding 0 16px - text-align center - line-height 42px - font-size 0.9em - font-weight bold - color #888 - box-shadow 0 1px rgba(0, 0, 0, 0.07) - - > i - margin-right 4px - - > button - position absolute - z-index 2 - top 0 - padding 0 - width 42px - font-size 0.9em - line-height 42px - color #ccc - - &:hover - color #aaa - - &:active - color #999 - - &:first-of-type - left 0 - - &:last-of-type - right 0 - - > .calendar - display flex - flex-wrap wrap - padding 16px - - * - user-select none - - > div - width calc(100% * (1/7)) - text-align center - line-height 32px - font-size 14px - - &.weekday - color #19a2a9 - - &[data-is-donichi] - color #ef95a0 - - &[data-today] - box-shadow 0 0 0 1px #19a2a9 inset - border-radius 6px - - &[data-is-donichi] - box-shadow 0 0 0 1px #ef95a0 inset - - &.day - cursor pointer - color #777 - - > div - border-radius 6px - - &:hover > div - background rgba(0, 0, 0, 0.025) - - &:active > div - background rgba(0, 0, 0, 0.05) - - &[data-is-donichi] - color #ef95a0 - - &[data-is-future] - cursor default - color rgba(#777, 0.5) - - &[data-is-donichi] - color rgba(#ef95a0, 0.5) - - &[data-selected] - font-weight bold - - > div - background rgba(0, 0, 0, 0.025) - - &:active > div - background rgba(0, 0, 0, 0.05) - - &[data-today] - > div - color $theme-color-foreground - background $theme-color - - &:hover > div - background lighten($theme-color, 10%) - - &:active > div - background darken($theme-color, 10%) - + background transparent !important + border none !important </style> <script> this.data = { @@ -142,99 +13,7 @@ this.mixin('widget'); - const eachMonthDays = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; - - function isLeapYear(year) { - return (year % 400 == 0) ? true : - (year % 100 == 0) ? false : - (year % 4 == 0) ? true : - false; - } - - this.today = new Date(); - this.year = this.today.getFullYear(); - this.month = this.today.getMonth() + 1; - this.selected = this.today; - this.weekdayText = [ - '%i18n:common.weekday-short.sunday%', - '%i18n:common.weekday-short.monday%', - '%i18n:common.weekday-short.tuesday%', - '%i18n:common.weekday-short.wednesday%', - '%i18n:common.weekday-short.thursday%', - '%i18n:common.weekday-short.friday%', - '%i18n:common.weekday-short.satruday%' - ]; - - this.on('mount', () => { - this.calc(); - }); - - this.isToday = day => { - return this.year == this.today.getFullYear() && this.month == this.today.getMonth() + 1 && day == this.today.getDate(); - }; - - this.isSelected = day => { - return this.year == this.selected.getFullYear() && this.month == this.selected.getMonth() + 1 && day == this.selected.getDate(); - }; - - this.isFuture = day => { - return (new Date(this.year, this.month - 1, day)).getTime() > this.today.getTime(); - }; - - this.isDonichi = day => { - const weekday = (new Date(this.year, this.month - 1, day)).getDay(); - return weekday == 0 || weekday == 6; - }; - - this.calc = () => { - let days = eachMonthDays[this.month - 1]; - - // うるう年なら+1日 - if (this.month == 2 && isLeapYear(this.year)) days++; - - const date = new Date(this.year, this.month - 1, 1); - const weekday = date.getDay(); - - this.update({ - paddingDays: weekday, - days: days - }); - }; - - this.prev = () => { - if (this.month == 1) { - this.update({ - year: this.year - 1, - month: 12 - }); - } else { - this.update({ - month: this.month - 1 - }); - } - this.calc(); - }; - - this.next = () => { - if (this.month == 12) { - this.update({ - year: this.year + 1, - month: 1 - }); - } else { - this.update({ - month: this.month + 1 - }); - } - this.calc(); - }; - - this.go = day => { - if (this.isFuture(day)) return; - const date = new Date(this.year, this.month - 1, day, 23, 59, 59, 999); - this.update({ - selected: date - }); + this.warp = date => { this.opts.tl.warp(date); }; diff --git a/src/web/app/desktop/tags/index.ts b/src/web/app/desktop/tags/index.ts index cd22dde352..f9df091bdc 100644 --- a/src/web/app/desktop/tags/index.ts +++ b/src/web/app/desktop/tags/index.ts @@ -52,13 +52,8 @@ require('./following-setuper.tag'); require('./ellipsis-icon.tag'); require('./ui.tag'); require('./home.tag'); -require('./user-header.tag'); -require('./user-profile.tag'); require('./user-timeline.tag'); require('./user.tag'); -require('./user-home.tag'); -require('./user-graphs.tag'); -require('./user-photos.tag'); require('./big-follow-button.tag'); require('./pages/entrance.tag'); require('./pages/entrance/signin.tag'); @@ -93,3 +88,4 @@ require('./user-following-window.tag'); require('./user-followers-window.tag'); require('./list-user.tag'); require('./detailed-post-window.tag'); +require('./calendar.tag'); diff --git a/src/web/app/desktop/tags/user-graphs.tag b/src/web/app/desktop/tags/user-graphs.tag deleted file mode 100644 index 0677d8c187..0000000000 --- a/src/web/app/desktop/tags/user-graphs.tag +++ /dev/null @@ -1,41 +0,0 @@ -<mk-user-graphs> - <section> - <h1>投稿</h1> - <mk-user-posts-graph user={ opts.user }/> - </section> - <section> - <h1>フォロー/フォロワー</h1> - <mk-user-friends-graph user={ opts.user }/> - </section> - <section> - <h1>いいね</h1> - <mk-user-likes-graph user={ opts.user }/> - </section> - <style> - :scope - display block - - > section - margin 16px 0 - background #fff - border solid 1px rgba(0, 0, 0, 0.1) - border-radius 4px - - > h1 - margin 0 0 8px 0 - padding 0 16px - line-height 40px - font-size 1em - color #666 - border-bottom solid 1px #eee - - > *:not(h1) - margin 0 auto 16px auto - - </style> - <script> - this.on('mount', () => { - this.trigger('loaded'); - }); - </script> -</mk-user-graphs> diff --git a/src/web/app/desktop/tags/user-header.tag b/src/web/app/desktop/tags/user-header.tag deleted file mode 100644 index ea7ea6bb37..0000000000 --- a/src/web/app/desktop/tags/user-header.tag +++ /dev/null @@ -1,147 +0,0 @@ -<mk-user-header data-is-dark-background={ user.banner_url != null }> - <div class="banner" ref="banner" style={ user.banner_url ? 'background-image: url(' + user.banner_url + '?thumbnail&size=1024)' : '' } onclick={ onUpdateBanner }></div><img class="avatar" src={ user.avatar_url + '?thumbnail&size=150' } alt="avatar"/> - <div class="title"> - <p class="name" href={ '/' + user.username }>{ user.name }</p> - <p class="username">@{ user.username }</p> - <p class="location" if={ user.profile.location }><i class="fa fa-map-marker"></i>{ user.profile.location }</p> - </div> - <footer> - <a href={ '/' + user.username }>投稿</a> - <a href={ '/' + user.username + '/media' }>メディア</a> - <a href={ '/' + user.username + '/graphs' }>グラフ</a> - </footer> - <style> - :scope - $footer-height = 58px - - display block - background #fff - - &[data-is-dark-background] - > .banner - background-color #383838 - - > .title - color #fff - background linear-gradient(transparent, rgba(0, 0, 0, 0.7)) - - > .name - text-shadow 0 0 8px #000 - - > .banner - height 280px - background-color #f5f5f5 - background-size cover - background-position center - - > .avatar - display block - position absolute - bottom 16px - left 16px - z-index 2 - width 150px - height 150px - margin 0 - border solid 3px #fff - border-radius 8px - box-shadow 1px 1px 3px rgba(0, 0, 0, 0.2) - - > .title - position absolute - bottom $footer-height - left 0 - width 100% - padding 0 0 8px 195px - color #656565 - font-family '游ゴシック', 'YuGothic', 'ヒラギノ角ゴ ProN W3', 'Hiragino Kaku Gothic ProN', 'Meiryo', 'メイリオ', sans-serif - - > .name - display block - margin 0 - line-height 40px - font-weight bold - font-size 2em - - > .username - > .location - display inline-block - margin 0 16px 0 0 - line-height 20px - opacity 0.8 - - > i - margin-right 4px - - > footer - z-index 1 - height $footer-height - padding-left 195px - background #fff - - > a - display inline-block - margin 0 - width 100px - line-height $footer-height - color #555 - - > button - display block - position absolute - top 0 - right 0 - margin 8px - padding 0 - width $footer-height - 16px - line-height $footer-height - 16px - 2px - font-size 1.2em - color #777 - border solid 1px #eee - border-radius 4px - - &:hover - color #555 - border solid 1px #ddd - - </style> - <script> - import updateBanner from '../scripts/update-banner'; - - this.mixin('i'); - - this.user = this.opts.user; - - this.on('mount', () => { - window.addEventListener('load', this.scroll); - window.addEventListener('scroll', this.scroll); - window.addEventListener('resize', this.scroll); - }); - - this.on('unmount', () => { - window.removeEventListener('load', this.scroll); - window.removeEventListener('scroll', this.scroll); - window.removeEventListener('resize', this.scroll); - }); - - this.scroll = () => { - const top = window.scrollY; - const height = 280/*px*/; - - const pos = 50 - ((top / height) * 50); - this.refs.banner.style.backgroundPosition = `center ${pos}%`; - - const blur = top / 32 - if (blur <= 10) this.refs.banner.style.filter = `blur(${blur}px)`; - }; - - this.onUpdateBanner = () => { - if (!this.SIGNIN || this.I.id != this.user.id) return; - - updateBanner(this.I, i => { - this.user.banner_url = i.banner_url; - this.update(); - }); - }; - </script> -</mk-user-header> diff --git a/src/web/app/desktop/tags/user-home.tag b/src/web/app/desktop/tags/user-home.tag deleted file mode 100644 index a879db5bb6..0000000000 --- a/src/web/app/desktop/tags/user-home.tag +++ /dev/null @@ -1,46 +0,0 @@ -<mk-user-home> - <div class="side"> - <mk-user-profile user={ user }/> - <mk-user-photos user={ user }/> - </div> - <main> - <mk-user-timeline ref="tl" user={ user }/> - </main> - <style> - :scope - display flex - justify-content center - - > * - > * - display block - //border solid 1px #eaeaea - border solid 1px rgba(0, 0, 0, 0.075) - border-radius 6px - - &:not(:last-child) - margin-bottom 16px - - > main - flex 1 1 560px - max-width 560px - margin 0 - padding 16px 0 16px 16px - - > .side - flex 1 1 270px - max-width 270px - margin 0 - padding 16px 0 16px 0 - - </style> - <script> - this.user = this.opts.user; - - this.on('mount', () => { - this.refs.tl.on('loaded', () => { - this.trigger('loaded'); - }); - }); - </script> -</mk-user-home> diff --git a/src/web/app/desktop/tags/user-photos.tag b/src/web/app/desktop/tags/user-photos.tag deleted file mode 100644 index dce1e50add..0000000000 --- a/src/web/app/desktop/tags/user-photos.tag +++ /dev/null @@ -1,91 +0,0 @@ -<mk-user-photos> - <p class="title"><i class="fa fa-camera"></i>フォト</p> - <p class="initializing" if={ initializing }><i class="fa fa-spinner fa-pulse fa-fw"></i>読み込んでいます<mk-ellipsis/></p> - <div class="stream" if={ !initializing && images.length > 0 }> - <virtual each={ image in images }> - <div class="img" style={ 'background-image: url(' + image.url + '?thumbnail&size=256)' }></div> - </virtual> - </div> - <p class="empty" if={ !initializing && images.length == 0 }>写真はありません</p> - <style> - :scope - display block - background #fff - - > .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) - - > i - margin-right 4px - - > .stream - display -webkit-flex - display -moz-flex - display -ms-flex - display flex - justify-content center - flex-wrap wrap - padding 8px - - > .img - flex 1 1 33% - width 33% - height 80px - background-position center center - background-size cover - background-clip content-box - border solid 2px transparent - - > .initializing - > .empty - margin 0 - padding 16px - text-align center - color #aaa - - > i - margin-right 4px - - </style> - <script> - import isPromise from '../../common/scripts/is-promise'; - - this.mixin('api'); - - this.images = []; - this.initializing = true; - this.user = null; - this.userPromise = isPromise(this.opts.user) - ? this.opts.user - : Promise.resolve(this.opts.user); - - this.on('mount', () => { - this.userPromise.then(user => { - this.update({ - user: user - }); - - this.api('users/posts', { - user_id: this.user.id, - with_media: true, - limit: 9 - }).then(posts => { - this.initializing = false; - posts.forEach(post => { - post.media.forEach(media => { - if (this.images.length < 9) this.images.push(media); - }); - }); - this.update(); - }); - }); - }); - </script> -</mk-user-photos> diff --git a/src/web/app/desktop/tags/user-profile.tag b/src/web/app/desktop/tags/user-profile.tag deleted file mode 100644 index 7472a47801..0000000000 --- a/src/web/app/desktop/tags/user-profile.tag +++ /dev/null @@ -1,102 +0,0 @@ -<mk-user-profile> - <div class="friend-form" if={ SIGNIN && I.id != user.id }> - <mk-big-follow-button user={ user }/> - <p class="followed" if={ user.is_followed }>フォローされています</p> - </div> - <div class="description" if={ user.description }>{ user.description }</div> - <div class="birthday" if={ user.profile.birthday }> - <p><i class="fa fa-birthday-cake"></i>{ user.profile.birthday.replace('-', '年').replace('-', '月') + '日' } ({ age(user.profile.birthday) }歳)</p> - </div> - <div class="twitter" if={ user.twitter }> - <p><i class="fa fa-twitter"></i><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"><i class="fa fa-angle-right"></i><a>{ user.posts_count }</a><b>ポスト</b></p> - <p class="following"><i class="fa fa-angle-right"></i><a onclick={ showFollowing }>{ user.following_count }</a>人を<b>フォロー</b></p> - <p class="followers"><i class="fa fa-angle-right"></i><a onclick={ showFollowers }>{ user.followers_count }</a>人の<b>フォロワー</b></p> - </div> - <style> - :scope - display block - background #fff - - > *:first-child - border-top none !important - - > .friend-form - padding 16px - border-top solid 1px #eee - - > mk-big-follow-button - width 100% - - > .followed - margin 12px 0 0 0 - padding 0 - text-align center - line-height 24px - font-size 0.8em - color #71afc7 - background #eefaff - border-radius 4px - - > .description - padding 16px - color #555 - border-top solid 1px #eee - - > .birthday - padding 16px - color #555 - border-top solid 1px #eee - - > p - margin 0 - - > i - margin-right 8px - - > .twitter - padding 16px - color #555 - border-top solid 1px #eee - - > p - margin 0 - - > i - margin-right 8px - - > .status - padding 16px - color #555 - border-top solid 1px #eee - - > p - margin 8px 0 - - > i - margin-left 8px - margin-right 8px - - </style> - <script> - this.age = require('s-age'); - - this.mixin('i'); - - this.user = this.opts.user; - - this.showFollowing = () => { - riot.mount(document.body.appendChild(document.createElement('mk-user-following-window')), { - user: this.user - }); - }; - - this.showFollowers = () => { - riot.mount(document.body.appendChild(document.createElement('mk-user-followers-window')), { - user: this.user - }); - }; - </script> -</mk-user-profile> diff --git a/src/web/app/desktop/tags/user-timeline.tag b/src/web/app/desktop/tags/user-timeline.tag index 08ab47b160..5df13c436c 100644 --- a/src/web/app/desktop/tags/user-timeline.tag +++ b/src/web/app/desktop/tags/user-timeline.tag @@ -91,6 +91,7 @@ this.fetch = cb => { this.api('users/posts', { user_id: this.user.id, + max_date: this.date ? this.date.getTime() : undefined, with_replies: this.mode == 'with-replies' }).then(posts => { this.update({ @@ -132,5 +133,13 @@ }); this.fetch(); }; + + this.warp = date => { + this.update({ + date: date + }); + + this.fetch(); + }; </script> </mk-user-timeline> diff --git a/src/web/app/desktop/tags/user.tag b/src/web/app/desktop/tags/user.tag index 2e69872b78..c9bb53fedd 100644 --- a/src/web/app/desktop/tags/user.tag +++ b/src/web/app/desktop/tags/user.tag @@ -3,10 +3,8 @@ <header> <mk-user-header user={ user }/> </header> - <div class="body"> - <mk-user-home if={ page == 'home' } user={ user }/> - <mk-user-graphs if={ page == 'graphs' } user={ user }/> - </div> + <mk-user-home if={ page == 'home' } user={ user }/> + <mk-user-graphs if={ page == 'graphs' } user={ user }/> </div> <style> :scope @@ -14,7 +12,7 @@ > .user > header - max-width 560px + 270px + max-width 1200px margin 0 auto padding 0 16px @@ -24,11 +22,6 @@ border-radius 0 0 6px 6px overflow hidden - > .body - max-width 560px + 270px - margin 0 auto - padding 0 16px - </style> <script> this.mixin('api'); @@ -51,3 +44,447 @@ }); </script> </mk-user> + +<mk-user-header data-is-dark-background={ user.banner_url != null }> + <div class="banner" ref="banner" style={ user.banner_url ? 'background-image: url(' + user.banner_url + '?thumbnail&size=1024)' : '' } onclick={ onUpdateBanner }></div> + <img class="avatar" src={ user.avatar_url + '?thumbnail&size=150' } alt="avatar"/> + <div class="title"> + <p class="name" href={ '/' + user.username }>{ user.name }</p> + <p class="username">@{ user.username }</p> + <p class="location" if={ user.profile.location }><i class="fa fa-map-marker"></i>{ user.profile.location }</p> + </div> + <footer> + <a href={ '/' + user.username }>投稿</a> + <a href={ '/' + user.username + '/media' }>メディア</a> + <a href={ '/' + user.username + '/graphs' }>グラフ</a> + </footer> + <style> + :scope + $footer-height = 58px + + display block + background #fff + + &[data-is-dark-background] + > .banner + background-color #383838 + + > .title + color #fff + background linear-gradient(transparent, rgba(0, 0, 0, 0.7)) + + > .name + text-shadow 0 0 8px #000 + + > .banner + height 280px + background-color #f5f5f5 + background-size cover + background-position center + + > .avatar + display block + position absolute + bottom 16px + left 16px + z-index 2 + width 150px + height 150px + margin 0 + border solid 3px #fff + border-radius 8px + box-shadow 1px 1px 3px rgba(0, 0, 0, 0.2) + + > .title + position absolute + bottom $footer-height + left 0 + width 100% + padding 0 0 8px 195px + color #656565 + font-family '游ゴシック', 'YuGothic', 'ヒラギノ角ゴ ProN W3', 'Hiragino Kaku Gothic ProN', 'Meiryo', 'メイリオ', sans-serif + + > .name + display block + margin 0 + line-height 40px + font-weight bold + font-size 2em + + > .username + > .location + display inline-block + margin 0 16px 0 0 + line-height 20px + opacity 0.8 + + > i + margin-right 4px + + > footer + z-index 1 + height $footer-height + padding-left 195px + background #fff + + > a + display inline-block + margin 0 + width 100px + line-height $footer-height + color #555 + + > button + display block + position absolute + top 0 + right 0 + margin 8px + padding 0 + width $footer-height - 16px + line-height $footer-height - 16px - 2px + font-size 1.2em + color #777 + border solid 1px #eee + border-radius 4px + + &:hover + color #555 + border solid 1px #ddd + + </style> + <script> + import updateBanner from '../scripts/update-banner'; + + this.mixin('i'); + + this.user = this.opts.user; + + this.on('mount', () => { + window.addEventListener('load', this.scroll); + window.addEventListener('scroll', this.scroll); + window.addEventListener('resize', this.scroll); + }); + + this.on('unmount', () => { + window.removeEventListener('load', this.scroll); + window.removeEventListener('scroll', this.scroll); + window.removeEventListener('resize', this.scroll); + }); + + this.scroll = () => { + const top = window.scrollY; + const height = 280/*px*/; + + const pos = 50 - ((top / height) * 50); + this.refs.banner.style.backgroundPosition = `center ${pos}%`; + + const blur = top / 32 + if (blur <= 10) this.refs.banner.style.filter = `blur(${blur}px)`; + }; + + this.onUpdateBanner = () => { + if (!this.SIGNIN || this.I.id != this.user.id) return; + + updateBanner(this.I, i => { + this.user.banner_url = i.banner_url; + this.update(); + }); + }; + </script> +</mk-user-header> + +<mk-user-profile> + <div class="friend-form" if={ SIGNIN && I.id != user.id }> + <mk-big-follow-button user={ user }/> + <p class="followed" if={ user.is_followed }>フォローされています</p> + </div> + <div class="description" if={ user.description }>{ user.description }</div> + <div class="birthday" if={ user.profile.birthday }> + <p><i class="fa fa-birthday-cake"></i>{ user.profile.birthday.replace('-', '年').replace('-', '月') + '日' } ({ age(user.profile.birthday) }歳)</p> + </div> + <div class="twitter" if={ user.twitter }> + <p><i class="fa fa-twitter"></i><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"><i class="fa fa-angle-right"></i><a>{ user.posts_count }</a><b>ポスト</b></p> + <p class="following"><i class="fa fa-angle-right"></i><a onclick={ showFollowing }>{ user.following_count }</a>人を<b>フォロー</b></p> + <p class="followers"><i class="fa fa-angle-right"></i><a onclick={ showFollowers }>{ user.followers_count }</a>人の<b>フォロワー</b></p> + </div> + <style> + :scope + display block + background #fff + + > *:first-child + border-top none !important + + > .friend-form + padding 16px + border-top solid 1px #eee + + > mk-big-follow-button + width 100% + + > .followed + margin 12px 0 0 0 + padding 0 + text-align center + line-height 24px + font-size 0.8em + color #71afc7 + background #eefaff + border-radius 4px + + > .description + padding 16px + color #555 + border-top solid 1px #eee + + > .birthday + padding 16px + color #555 + border-top solid 1px #eee + + > p + margin 0 + + > i + margin-right 8px + + > .twitter + padding 16px + color #555 + border-top solid 1px #eee + + > p + margin 0 + + > i + margin-right 8px + + > .status + padding 16px + color #555 + border-top solid 1px #eee + + > p + margin 8px 0 + + > i + margin-left 8px + margin-right 8px + + </style> + <script> + this.age = require('s-age'); + + this.mixin('i'); + + this.user = this.opts.user; + + this.showFollowing = () => { + riot.mount(document.body.appendChild(document.createElement('mk-user-following-window')), { + user: this.user + }); + }; + + this.showFollowers = () => { + riot.mount(document.body.appendChild(document.createElement('mk-user-followers-window')), { + user: this.user + }); + }; + </script> +</mk-user-profile> + +<mk-user-photos> + <p class="title"><i class="fa fa-camera"></i>フォト</p> + <p class="initializing" if={ initializing }><i class="fa fa-spinner fa-pulse fa-fw"></i>読み込んでいます<mk-ellipsis/></p> + <div class="stream" if={ !initializing && images.length > 0 }> + <virtual each={ image in images }> + <div class="img" style={ 'background-image: url(' + image.url + '?thumbnail&size=256)' }></div> + </virtual> + </div> + <p class="empty" if={ !initializing && images.length == 0 }>写真はありません</p> + <style> + :scope + display block + background #fff + + > .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) + + > i + margin-right 4px + + > .stream + display -webkit-flex + display -moz-flex + display -ms-flex + display flex + justify-content center + flex-wrap wrap + padding 8px + + > .img + flex 1 1 33% + width 33% + height 80px + background-position center center + background-size cover + background-clip content-box + border solid 2px transparent + + > .initializing + > .empty + margin 0 + padding 16px + text-align center + color #aaa + + > i + margin-right 4px + + </style> + <script> + import isPromise from '../../common/scripts/is-promise'; + + this.mixin('api'); + + this.images = []; + this.initializing = true; + this.user = null; + this.userPromise = isPromise(this.opts.user) + ? this.opts.user + : Promise.resolve(this.opts.user); + + this.on('mount', () => { + this.userPromise.then(user => { + this.update({ + user: user + }); + + this.api('users/posts', { + user_id: this.user.id, + with_media: true, + limit: 9 + }).then(posts => { + this.initializing = false; + posts.forEach(post => { + post.media.forEach(media => { + if (this.images.length < 9) this.images.push(media); + }); + }); + this.update(); + }); + }); + }); + </script> +</mk-user-photos> + +<mk-user-home> + <div> + <mk-user-profile user={ user }/> + <mk-user-photos user={ user }/> + </div> + <main> + <mk-user-timeline ref="tl" user={ user }/> + </main> + <div> + <mk-calendar warp={ warp } start={ new Date(user.created_at) }/> + </div> + <style> + :scope + display flex + justify-content center + margin 0 auto + max-width 1200px + + > * + > * + display block + //border solid 1px #eaeaea + border solid 1px rgba(0, 0, 0, 0.075) + border-radius 6px + + &:not(:last-child) + margin-bottom 16px + + > main + padding 16px + width calc(100% - 275px * 2) + + > div + width 275px + margin 0 + + &:first-child + padding 16px 0 16px 16px + + &:last-child + padding 16px 16px 16px 0 + + </style> + <script> + this.user = this.opts.user; + + this.on('mount', () => { + this.refs.tl.on('loaded', () => { + this.trigger('loaded'); + }); + }); + + this.warp = date => { + this.refs.tl.warp(date); + }; + </script> +</mk-user-home> + +<mk-user-graphs> + <section> + <h1>投稿</h1> + <mk-user-posts-graph user={ opts.user }/> + </section> + <section> + <h1>フォロー/フォロワー</h1> + <mk-user-friends-graph user={ opts.user }/> + </section> + <section> + <h1>いいね</h1> + <mk-user-likes-graph user={ opts.user }/> + </section> + <style> + :scope + display block + + > section + margin 16px 0 + background #fff + border solid 1px rgba(0, 0, 0, 0.1) + border-radius 4px + + > h1 + margin 0 0 8px 0 + padding 0 16px + line-height 40px + font-size 1em + color #666 + border-bottom solid 1px #eee + + > *:not(h1) + margin 0 auto 16px auto + + </style> + <script> + this.on('mount', () => { + this.trigger('loaded'); + }); + </script> +</mk-user-graphs> |