summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorsyuilo <syuilotan@yahoo.co.jp>2018-02-15 18:33:34 +0900
committersyuilo <syuilotan@yahoo.co.jp>2018-02-15 18:33:34 +0900
commit4980b86d640ca795442255e4746c01bb38e0b5f8 (patch)
tree772f0e80bd4fb1b2ef1dd2949c97fcf59b61877f /src
parentwip (diff)
downloadmisskey-4980b86d640ca795442255e4746c01bb38e0b5f8.tar.gz
misskey-4980b86d640ca795442255e4746c01bb38e0b5f8.tar.bz2
misskey-4980b86d640ca795442255e4746c01bb38e0b5f8.zip
wip
Diffstat (limited to 'src')
-rw-r--r--src/web/app/auth/tags/index.tag6
-rw-r--r--src/web/app/ch/tags/channel.tag8
-rw-r--r--src/web/app/ch/tags/header.tag4
-rw-r--r--src/web/app/desktop/-tags/user-preview.tag2
-rw-r--r--src/web/app/desktop/-tags/users-list.tag2
-rw-r--r--src/web/app/mobile/tags/home.tag23
-rw-r--r--src/web/app/mobile/tags/user.tag735
-rw-r--r--src/web/app/mobile/tags/users-list.tag2
-rw-r--r--src/web/app/mobile/views/components/home.vue29
-rw-r--r--src/web/app/mobile/views/components/post-card.vue85
-rw-r--r--src/web/app/mobile/views/components/ui-nav.vue2
-rw-r--r--src/web/app/mobile/views/pages/user.vue226
-rw-r--r--src/web/app/mobile/views/pages/user/followers-you-know.vue62
-rw-r--r--src/web/app/mobile/views/pages/user/home-activity.vue62
-rw-r--r--src/web/app/mobile/views/pages/user/home-friends.vue54
-rw-r--r--src/web/app/mobile/views/pages/user/home-photos.vue78
-rw-r--r--src/web/app/mobile/views/pages/user/home-posts.vue57
-rw-r--r--src/web/app/mobile/views/pages/user/home.vue95
18 files changed, 761 insertions, 771 deletions
diff --git a/src/web/app/auth/tags/index.tag b/src/web/app/auth/tags/index.tag
index 3a24c2d6be..56fbbb7da2 100644
--- a/src/web/app/auth/tags/index.tag
+++ b/src/web/app/auth/tags/index.tag
@@ -1,5 +1,5 @@
<mk-index>
- <main v-if="SIGNIN">
+ <main v-if="$root.$data.os.isSignedIn">
<p class="fetching" v-if="fetching">読み込み中<mk-ellipsis/></p>
<mk-form ref="form" v-if="state == 'waiting'" session={ session }/>
<div class="denied" v-if="state == 'denied'">
@@ -15,7 +15,7 @@
<p>セッションが存在しません。</p>
</div>
</main>
- <main class="signin" v-if="!SIGNIN">
+ <main class="signin" v-if="!$root.$data.os.isSignedIn">
<h1>サインインしてください</h1>
<mk-signin/>
</main>
@@ -93,7 +93,7 @@
this.token = window.location.href.split('/').pop();
this.on('mount', () => {
- if (!this.SIGNIN) return;
+ if (!this.$root.$data.os.isSignedIn) return;
// Fetch session
this.$root.$data.os.api('auth/session/show', {
diff --git a/src/web/app/ch/tags/channel.tag b/src/web/app/ch/tags/channel.tag
index d95de97376..b5c6ce1e69 100644
--- a/src/web/app/ch/tags/channel.tag
+++ b/src/web/app/ch/tags/channel.tag
@@ -4,7 +4,7 @@
<main v-if="!fetching">
<h1>{ channel.title }</h1>
- <div v-if="SIGNIN">
+ <div v-if="$root.$data.os.isSignedIn">
<p v-if="channel.is_watching">このチャンネルをウォッチしています <a @click="unwatch">ウォッチ解除</a></p>
<p v-if="!channel.is_watching"><a @click="watch">このチャンネルをウォッチする</a></p>
</div>
@@ -24,8 +24,8 @@
</div>
</div>
<hr>
- <mk-channel-form v-if="SIGNIN" channel={ channel } ref="form"/>
- <div v-if="!SIGNIN">
+ <mk-channel-form v-if="$root.$data.os.isSignedIn" channel={ channel } ref="form"/>
+ <div v-if="!$root.$data.os.isSignedIn">
<p>参加するには<a href={ _URL_ }>ログインまたは新規登録</a>してください</p>
</div>
<hr>
@@ -125,7 +125,7 @@
this.posts.unshift(post);
this.update();
- if (document.hidden && this.SIGNIN && post.user_id !== this.$root.$data.os.i.id) {
+ if (document.hidden && this.$root.$data.os.isSignedIn && post.user_id !== this.$root.$data.os.i.id) {
this.unreadCount++;
document.title = `(${this.unreadCount}) ${this.channel.title} | Misskey`;
}
diff --git a/src/web/app/ch/tags/header.tag b/src/web/app/ch/tags/header.tag
index 47a1e3e76a..747bec357b 100644
--- a/src/web/app/ch/tags/header.tag
+++ b/src/web/app/ch/tags/header.tag
@@ -3,8 +3,8 @@
<a href={ _CH_URL_ }>Index</a> | <a href={ _URL_ }>Misskey</a>
</div>
<div>
- <a v-if="!SIGNIN" href={ _URL_ }>ログイン(新規登録)</a>
- <a v-if="SIGNIN" href={ _URL_ + '/' + I.username }>{ I.username }</a>
+ <a v-if="!$root.$data.os.isSignedIn" href={ _URL_ }>ログイン(新規登録)</a>
+ <a v-if="$root.$data.os.isSignedIn" href={ _URL_ + '/' + I.username }>{ I.username }</a>
</div>
<style lang="stylus" scoped>
:scope
diff --git a/src/web/app/desktop/-tags/user-preview.tag b/src/web/app/desktop/-tags/user-preview.tag
index 3a65fb79b9..8503e9aeb0 100644
--- a/src/web/app/desktop/-tags/user-preview.tag
+++ b/src/web/app/desktop/-tags/user-preview.tag
@@ -17,7 +17,7 @@
<p>フォロワー</p><a>{ user.followers_count }</a>
</div>
</div>
- <mk-follow-button v-if="SIGNIN && user.id != I.id" user={ userPromise }/>
+ <mk-follow-button v-if="$root.$data.os.isSignedIn && user.id != I.id" user={ userPromise }/>
</template>
<style lang="stylus" scoped>
:scope
diff --git a/src/web/app/desktop/-tags/users-list.tag b/src/web/app/desktop/-tags/users-list.tag
index bf002ae552..03c527109b 100644
--- a/src/web/app/desktop/-tags/users-list.tag
+++ b/src/web/app/desktop/-tags/users-list.tag
@@ -2,7 +2,7 @@
<nav>
<div>
<span data-is-active={ mode == 'all' } @click="setMode.bind(this, 'all')">すべて<span>{ opts.count }</span></span>
- <span v-if="SIGNIN && opts.youKnowCount" data-is-active={ mode == 'iknow' } @click="setMode.bind(this, 'iknow')">知り合い<span>{ opts.youKnowCount }</span></span>
+ <span v-if="$root.$data.os.isSignedIn && opts.youKnowCount" data-is-active={ mode == 'iknow' } @click="setMode.bind(this, 'iknow')">知り合い<span>{ opts.youKnowCount }</span></span>
</div>
</nav>
<div class="users" v-if="!fetching && users.length != 0">
diff --git a/src/web/app/mobile/tags/home.tag b/src/web/app/mobile/tags/home.tag
deleted file mode 100644
index 038322b633..0000000000
--- a/src/web/app/mobile/tags/home.tag
+++ /dev/null
@@ -1,23 +0,0 @@
-<mk-home>
- <mk-home-timeline ref="tl"/>
- <style lang="stylus" scoped>
- :scope
- display block
-
- > mk-home-timeline
- max-width 600px
- margin 0 auto
- padding 8px
-
- @media (min-width 500px)
- padding 16px
-
- </style>
- <script lang="typescript">
- this.on('mount', () => {
- this.$refs.tl.on('loaded', () => {
- this.$emit('loaded');
- });
- });
- </script>
-</mk-home>
diff --git a/src/web/app/mobile/tags/user.tag b/src/web/app/mobile/tags/user.tag
deleted file mode 100644
index b9bb4e17a4..0000000000
--- a/src/web/app/mobile/tags/user.tag
+++ /dev/null
@@ -1,735 +0,0 @@
-<mk-user>
- <div class="user" v-if="!fetching">
- <header>
- <div class="banner" style={ user.banner_url ? 'background-image: url(' + user.banner_url + '?thumbnail&size=1024)' : '' }></div>
- <div class="body">
- <div class="top">
- <a class="avatar">
- <img src={ user.avatar_url + '?thumbnail&size=200' } alt="avatar"/>
- </a>
- <mk-follow-button v-if="SIGNIN && I.id != user.id" user={ user }/>
- </div>
- <div class="title">
- <h1>{ user.name }</h1>
- <span class="username">@{ user.username }</span>
- <span class="followed" v-if="user.is_followed">%i18n:mobile.tags.mk-user.follows-you%</span>
- </div>
- <div class="description">{ user.description }</div>
- <div class="info">
- <p class="location" v-if="user.profile.location">
- %fa:map-marker%{ user.profile.location }
- </p>
- <p class="birthday" v-if="user.profile.birthday">
- %fa:birthday-cake%{ user.profile.birthday.replace('-', '年').replace('-', '月') + '日' } ({ age(user.profile.birthday) }歳)
- </p>
- </div>
- <div class="status">
- <a>
- <b>{ user.posts_count }</b>
- <i>%i18n:mobile.tags.mk-user.posts%</i>
- </a>
- <a href="{ user.username }/following">
- <b>{ user.following_count }</b>
- <i>%i18n:mobile.tags.mk-user.following%</i>
- </a>
- <a href="{ user.username }/followers">
- <b>{ user.followers_count }</b>
- <i>%i18n:mobile.tags.mk-user.followers%</i>
- </a>
- </div>
- </div>
- <nav>
- <a data-is-active={ page == 'overview' } @click="go.bind(null, 'overview')">%i18n:mobile.tags.mk-user.overview%</a>
- <a data-is-active={ page == 'posts' } @click="go.bind(null, 'posts')">%i18n:mobile.tags.mk-user.timeline%</a>
- <a data-is-active={ page == 'media' } @click="go.bind(null, 'media')">%i18n:mobile.tags.mk-user.media%</a>
- </nav>
- </header>
- <div class="body">
- <mk-user-overview v-if="page == 'overview'" user={ user }/>
- <mk-user-timeline v-if="page == 'posts'" user={ user }/>
- <mk-user-timeline v-if="page == 'media'" user={ user } with-media={ true }/>
- </div>
- </div>
- <style lang="stylus" scoped>
- :scope
- display block
-
- > .user
- > header
- box-shadow 0 4px 4px rgba(0, 0, 0, 0.3)
-
- > .banner
- padding-bottom 33.3%
- background-color #1b1b1b
- background-size cover
- background-position center
-
- > .body
- padding 12px
- margin 0 auto
- max-width 600px
-
- > .top
- &:after
- content ''
- display block
- clear both
-
- > .avatar
- display block
- float left
- width 25%
- height 40px
-
- > img
- display block
- position absolute
- left -2px
- bottom -2px
- width 100%
- border 2px solid #313a42
- border-radius 6px
-
- @media (min-width 500px)
- left -4px
- bottom -4px
- border 4px solid #313a42
- border-radius 12px
-
- > mk-follow-button
- float right
- height 40px
-
- > .title
- margin 8px 0
-
- > h1
- margin 0
- line-height 22px
- font-size 20px
- color #fff
-
- > .username
- display inline-block
- line-height 20px
- font-size 16px
- font-weight bold
- color #657786
-
- > .followed
- margin-left 8px
- padding 2px 4px
- font-size 12px
- color #657786
- background #f8f8f8
- border-radius 4px
-
- > .description
- margin 8px 0
- color #fff
-
- > .info
- margin 8px 0
-
- > p
- display inline
- margin 0 16px 0 0
- color #a9b9c1
-
- > i
- margin-right 4px
-
- > .status
- > a
- color #657786
-
- &:not(:last-child)
- margin-right 16px
-
- > b
- margin-right 4px
- font-size 16px
- color #fff
-
- > i
- font-size 14px
-
- > mk-activity-table
- margin 12px 0 0 0
-
- > nav
- display flex
- justify-content center
- margin 0 auto
- max-width 600px
-
- > a
- display block
- flex 1 1
- text-align center
- line-height 52px
- font-size 14px
- text-decoration none
- color #657786
- border-bottom solid 2px transparent
-
- &[data-is-active]
- font-weight bold
- color $theme-color
- border-color $theme-color
-
- > .body
- padding 8px
-
- @media (min-width 500px)
- padding 16px
-
- </style>
- <script lang="typescript">
- this.age = require('s-age');
-
- this.mixin('i');
- this.mixin('api');
-
- this.username = this.opts.user;
- this.page = this.opts.page ? this.opts.page : 'overview';
- this.fetching = true;
-
- this.on('mount', () => {
- this.$root.$data.os.api('users/show', {
- username: this.username
- }).then(user => {
- this.fetching = false;
- this.user = user;
- this.$emit('loaded', user);
- this.update();
- });
- });
-
- this.go = page => {
- this.update({
- page: page
- });
- };
- </script>
-</mk-user>
-
-<mk-user-overview>
- <mk-post-detail v-if="user.pinned_post" post={ user.pinned_post } compact={ true }/>
- <section class="recent-posts">
- <h2>%fa:R comments%%i18n:mobile.tags.mk-user-overview.recent-posts%</h2>
- <div>
- <mk-user-overview-posts user={ user }/>
- </div>
- </section>
- <section class="images">
- <h2>%fa:image%%i18n:mobile.tags.mk-user-overview.images%</h2>
- <div>
- <mk-user-overview-photos user={ user }/>
- </div>
- </section>
- <section class="activity">
- <h2>%fa:chart-bar%%i18n:mobile.tags.mk-user-overview.activity%</h2>
- <div>
- <mk-user-overview-activity-chart user={ user }/>
- </div>
- </section>
- <section class="keywords">
- <h2>%fa:R comment%%i18n:mobile.tags.mk-user-overview.keywords%</h2>
- <div>
- <mk-user-overview-keywords user={ user }/>
- </div>
- </section>
- <section class="domains">
- <h2>%fa:globe%%i18n:mobile.tags.mk-user-overview.domains%</h2>
- <div>
- <mk-user-overview-domains user={ user }/>
- </div>
- </section>
- <section class="frequently-replied-users">
- <h2>%fa:users%%i18n:mobile.tags.mk-user-overview.frequently-replied-users%</h2>
- <div>
- <mk-user-overview-frequently-replied-users user={ user }/>
- </div>
- </section>
- <section class="followers-you-know" v-if="SIGNIN && I.id !== user.id">
- <h2>%fa:users%%i18n:mobile.tags.mk-user-overview.followers-you-know%</h2>
- <div>
- <mk-user-overview-followers-you-know user={ user }/>
- </div>
- </section>
- <p>%i18n:mobile.tags.mk-user-overview.last-used-at%: <b><mk-time time={ user.last_used_at }/></b></p>
- <style lang="stylus" scoped>
- :scope
- display block
- max-width 600px
- margin 0 auto
-
- > mk-post-detail
- margin 0 0 8px 0
-
- > section
- background #eee
- border-radius 8px
- box-shadow 0 0 0 1px rgba(0, 0, 0, 0.2)
-
- &:not(:last-child)
- margin-bottom 8px
-
- > h2
- margin 0
- padding 8px 10px
- font-size 15px
- font-weight normal
- color #465258
- background #fff
- border-radius 8px 8px 0 0
-
- > i
- margin-right 6px
-
- > .activity
- > div
- padding 8px
-
- > p
- display block
- margin 16px
- text-align center
- color #cad2da
-
- </style>
- <script lang="typescript">
- this.mixin('i');
-
- this.user = this.opts.user;
- </script>
-</mk-user-overview>
-
-<mk-user-overview-posts>
- <p class="initializing" v-if="initializing">%fa:spinner .pulse .fw%%i18n:mobile.tags.mk-user-overview-posts.loading%<mk-ellipsis/></p>
- <div v-if="!initializing && posts.length > 0">
- <template each={ posts }>
- <mk-user-overview-posts-post-card post={ this }/>
- </template>
- </div>
- <p class="empty" v-if="!initializing && posts.length == 0">%i18n:mobile.tags.mk-user-overview-posts.no-posts%</p>
- <style lang="stylus" scoped>
- :scope
- display block
-
- > div
- overflow-x scroll
- -webkit-overflow-scrolling touch
- white-space nowrap
- padding 8px
-
- > *
- vertical-align top
-
- &:not(:last-child)
- margin-right 8px
-
- > .initializing
- > .empty
- margin 0
- padding 16px
- text-align center
- color #aaa
-
- > i
- margin-right 4px
-
- </style>
- <script lang="typescript">
- this.mixin('api');
-
- this.user = this.opts.user;
- this.initializing = true;
-
- this.on('mount', () => {
- this.$root.$data.os.api('users/posts', {
- user_id: this.user.id
- }).then(posts => {
- this.update({
- posts: posts,
- initializing: false
- });
- });
- });
- </script>
-</mk-user-overview-posts>
-
-<mk-user-overview-posts-post-card>
- <a href={ '/' + post.user.username + '/' + post.id }>
- <header>
- <img src={ post.user.avatar_url + '?thumbnail&size=64' } alt="avatar"/><h3>{ post.user.name }</h3>
- </header>
- <div>
- { text }
- </div>
- <mk-time time={ post.created_at }/>
- </a>
- <style lang="stylus" scoped>
- :scope
- display inline-block
- width 150px
- //height 120px
- font-size 12px
- background #fff
- border-radius 4px
-
- > a
- display block
- color #2c3940
-
- &:hover
- text-decoration none
-
- > header
- > img
- position absolute
- top 8px
- left 8px
- width 28px
- height 28px
- border-radius 6px
-
- > h3
- display inline-block
- overflow hidden
- width calc(100% - 45px)
- margin 8px 0 0 42px
- line-height 28px
- white-space nowrap
- text-overflow ellipsis
- font-size 12px
-
- > div
- padding 2px 8px 8px 8px
- height 60px
- overflow hidden
- white-space normal
-
- &:after
- content ""
- display block
- position absolute
- top 40px
- left 0
- width 100%
- height 20px
- background linear-gradient(to bottom, rgba(255, 255, 255, 0) 0%, #fff 100%)
-
- > mk-time
- display inline-block
- padding 8px
- color #aaa
-
- </style>
- <script lang="typescript">
- import summary from '../../../../common/get-post-summary.ts';
-
- this.post = this.opts.post;
- this.text = summary(this.post);
- </script>
-</mk-user-overview-posts-post-card>
-
-<mk-user-overview-photos>
- <p class="initializing" v-if="initializing">%fa:spinner .pulse .fw%%i18n:mobile.tags.mk-user-overview-photos.loading%<mk-ellipsis/></p>
- <div class="stream" v-if="!initializing && images.length > 0">
- <template each={ image in images }>
- <a class="img" style={ 'background-image: url(' + image.media.url + '?thumbnail&size=256)' } href={ '/' + image.post.user.username + '/' + image.post.id }></a>
- </template>
- </div>
- <p class="empty" v-if="!initializing && images.length == 0">%i18n:mobile.tags.mk-user-overview-photos.no-photos%</p>
- <style lang="stylus" scoped>
- :scope
- display block
-
- > .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
- border-radius 4px
-
- > .initializing
- > .empty
- margin 0
- padding 16px
- text-align center
- color #aaa
-
- > i
- margin-right 4px
-
- </style>
- <script lang="typescript">
- this.mixin('api');
-
- this.images = [];
- this.initializing = true;
- this.user = this.opts.user;
-
- this.on('mount', () => {
- this.$root.$data.os.api('users/posts', {
- user_id: this.user.id,
- with_media: true,
- limit: 6
- }).then(posts => {
- this.initializing = false;
- posts.forEach(post => {
- post.media.forEach(media => {
- if (this.images.length < 9) this.images.push({
- post,
- media
- });
- });
- });
- this.update();
- });
- });
- </script>
-</mk-user-overview-photos>
-
-<mk-user-overview-activity-chart>
- <svg v-if="data" ref="canvas" viewBox="0 0 30 1" preserveAspectRatio="none">
- <g each={ d, i in data.reverse() }>
- <rect width="0.8" riot-height={ d.postsH }
- riot-x={ i + 0.1 } riot-y={ 1 - d.postsH - d.repliesH - d.repostsH }
- fill="#41ddde"/>
- <rect width="0.8" riot-height={ d.repliesH }
- riot-x={ i + 0.1 } riot-y={ 1 - d.repliesH - d.repostsH }
- fill="#f7796c"/>
- <rect width="0.8" riot-height={ d.repostsH }
- riot-x={ i + 0.1 } riot-y={ 1 - d.repostsH }
- fill="#a1de41"/>
- </g>
- </svg>
- <style lang="stylus" scoped>
- :scope
- display block
- max-width 600px
- margin 0 auto
-
- > svg
- display block
- width 100%
- height 80px
-
- > rect
- transform-origin center
-
- </style>
- <script lang="typescript">
- this.mixin('api');
-
- this.user = this.opts.user;
-
- this.on('mount', () => {
- this.$root.$data.os.api('aggregation/users/activity', {
- user_id: this.user.id,
- limit: 30
- }).then(data => {
- data.forEach(d => d.total = d.posts + d.replies + d.reposts);
- this.peak = Math.max.apply(null, data.map(d => d.total));
- data.forEach(d => {
- d.postsH = d.posts / this.peak;
- d.repliesH = d.replies / this.peak;
- d.repostsH = d.reposts / this.peak;
- });
- this.update({ data });
- });
- });
- </script>
-</mk-user-overview-activity-chart>
-
-<mk-user-overview-keywords>
- <div v-if="user.keywords != null && user.keywords.length > 1">
- <template each={ keyword in user.keywords }>
- <a>{ keyword }</a>
- </template>
- </div>
- <p class="empty" v-if="user.keywords == null || user.keywords.length == 0">%i18n:mobile.tags.mk-user-overview-keywords.no-keywords%</p>
- <style lang="stylus" scoped>
- :scope
- display block
-
- > div
- padding 4px
-
- > a
- display inline-block
- margin 4px
- color #555
-
- > .empty
- margin 0
- padding 16px
- text-align center
- color #aaa
-
- > i
- margin-right 4px
-
- </style>
- <script lang="typescript">
- this.user = this.opts.user;
- </script>
-</mk-user-overview-keywords>
-
-<mk-user-overview-domains>
- <div v-if="user.domains != null && user.domains.length > 1">
- <template each={ domain in user.domains }>
- <a style="opacity: { 0.5 + (domain.weight / 2) }">{ domain.domain }</a>
- </template>
- </div>
- <p class="empty" v-if="user.domains == null || user.domains.length == 0">%i18n:mobile.tags.mk-user-overview-domains.no-domains%</p>
- <style lang="stylus" scoped>
- :scope
- display block
-
- > div
- padding 4px
-
- > a
- display inline-block
- margin 4px
- color #555
-
- > .empty
- margin 0
- padding 16px
- text-align center
- color #aaa
-
- > i
- margin-right 4px
-
- </style>
- <script lang="typescript">
- this.user = this.opts.user;
- </script>
-</mk-user-overview-domains>
-
-<mk-user-overview-frequently-replied-users>
- <p class="initializing" v-if="initializing">%fa:spinner .pulse .fw%%i18n:mobile.tags.mk-user-overview-frequently-replied-users.loading%<mk-ellipsis/></p>
- <div v-if="!initializing && users.length > 0">
- <template each={ users }>
- <mk-user-card user={ this.user }/>
- </template>
- </div>
- <p class="empty" v-if="!initializing && users.length == 0">%i18n:mobile.tags.mk-user-overview-frequently-replied-users.no-users%</p>
- <style lang="stylus" scoped>
- :scope
- display block
-
- > div
- overflow-x scroll
- -webkit-overflow-scrolling touch
- white-space nowrap
- padding 8px
-
- > mk-user-card
- &:not(:last-child)
- margin-right 8px
-
- > .initializing
- > .empty
- margin 0
- padding 16px
- text-align center
- color #aaa
-
- > i
- margin-right 4px
-
- </style>
- <script lang="typescript">
- this.mixin('api');
-
- this.user = this.opts.user;
- this.initializing = true;
-
- this.on('mount', () => {
- this.$root.$data.os.api('users/get_frequently_replied_users', {
- user_id: this.user.id
- }).then(x => {
- this.update({
- users: x,
- initializing: false
- });
- });
- });
- </script>
-</mk-user-overview-frequently-replied-users>
-
-<mk-user-overview-followers-you-know>
- <p class="initializing" v-if="initializing">%fa:spinner .pulse .fw%%i18n:mobile.tags.mk-user-overview-followers-you-know.loading%<mk-ellipsis/></p>
- <div v-if="!initializing && users.length > 0">
- <template each={ user in users }>
- <a href={ '/' + user.username }><img src={ user.avatar_url + '?thumbnail&size=64' } alt={ user.name }/></a>
- </template>
- </div>
- <p class="empty" v-if="!initializing && users.length == 0">%i18n:mobile.tags.mk-user-overview-followers-you-know.no-users%</p>
- <style lang="stylus" scoped>
- :scope
- display block
-
- > div
- padding 4px
-
- > a
- display inline-block
- margin 4px
-
- > img
- width 48px
- height 48px
- vertical-align bottom
- border-radius 100%
-
- > .initializing
- > .empty
- margin 0
- padding 16px
- text-align center
- color #aaa
-
- > i
- margin-right 4px
-
- </style>
- <script lang="typescript">
- this.mixin('api');
-
- this.user = this.opts.user;
- this.initializing = true;
-
- this.on('mount', () => {
- this.$root.$data.os.api('users/followers', {
- user_id: this.user.id,
- iknow: true,
- limit: 30
- }).then(x => {
- this.update({
- users: x.users,
- initializing: false
- });
- });
- });
- </script>
-</mk-user-overview-followers-you-know>
diff --git a/src/web/app/mobile/tags/users-list.tag b/src/web/app/mobile/tags/users-list.tag
index 2bc0c6e939..84427a18e2 100644
--- a/src/web/app/mobile/tags/users-list.tag
+++ b/src/web/app/mobile/tags/users-list.tag
@@ -1,7 +1,7 @@
<mk-users-list>
<nav>
<span data-is-active={ mode == 'all' } @click="setMode.bind(this, 'all')">%i18n:mobile.tags.mk-users-list.all%<span>{ opts.count }</span></span>
- <span v-if="SIGNIN && opts.youKnowCount" data-is-active={ mode == 'iknow' } @click="setMode.bind(this, 'iknow')">%i18n:mobile.tags.mk-users-list.known%<span>{ opts.youKnowCount }</span></span>
+ <span v-if="$root.$data.os.isSignedIn && opts.youKnowCount" data-is-active={ mode == 'iknow' } @click="setMode.bind(this, 'iknow')">%i18n:mobile.tags.mk-users-list.known%<span>{ opts.youKnowCount }</span></span>
</nav>
<div class="users" v-if="!fetching && users.length != 0">
<mk-user-preview each={ users } user={ this }/>
diff --git a/src/web/app/mobile/views/components/home.vue b/src/web/app/mobile/views/components/home.vue
new file mode 100644
index 0000000000..3feab581d2
--- /dev/null
+++ b/src/web/app/mobile/views/components/home.vue
@@ -0,0 +1,29 @@
+<template>
+<div class="mk-home">
+ <mk-timeline @loaded="onTlLoaded"/>
+</div>
+</template>
+
+<script lang="ts">
+import Vue from 'vue';
+export default Vue.extend({
+ methods: {
+ onTlLoaded() {
+ this.$emit('loaded');
+ }
+ }
+});
+</script>
+
+<style lang="stylus" scoped>
+.mk-home
+
+ > .mk-timeline
+ max-width 600px
+ margin 0 auto
+ padding 8px
+
+ @media (min-width 500px)
+ padding 16px
+
+</style>
diff --git a/src/web/app/mobile/views/components/post-card.vue b/src/web/app/mobile/views/components/post-card.vue
new file mode 100644
index 0000000000..4dd6ceb282
--- /dev/null
+++ b/src/web/app/mobile/views/components/post-card.vue
@@ -0,0 +1,85 @@
+<template>
+<div class="mk-post-card">
+ <a :href="`/${post.user.username}/${post.id}`">
+ <header>
+ <img :src="`${post.user.avatar_url}?thumbnail&size=64`" alt="avatar"/><h3>{{ post.user.name }}</h3>
+ </header>
+ <div>
+ {{ text }}
+ </div>
+ <mk-time :time="post.created_at"/>
+ </a>
+</div>
+</template>
+
+<script lang="ts">
+import Vue from 'vue';
+import summary from '../../../../../common/get-post-summary';
+
+export default Vue.extend({
+ props: ['post'],
+ computed: {
+ text(): string {
+ return summary(this.post);
+ }
+ }
+});
+</script>
+
+<style lang="stylus" scoped>
+.mk-post-card
+ display inline-block
+ width 150px
+ //height 120px
+ font-size 12px
+ background #fff
+ border-radius 4px
+
+ > a
+ display block
+ color #2c3940
+
+ &:hover
+ text-decoration none
+
+ > header
+ > img
+ position absolute
+ top 8px
+ left 8px
+ width 28px
+ height 28px
+ border-radius 6px
+
+ > h3
+ display inline-block
+ overflow hidden
+ width calc(100% - 45px)
+ margin 8px 0 0 42px
+ line-height 28px
+ white-space nowrap
+ text-overflow ellipsis
+ font-size 12px
+
+ > div
+ padding 2px 8px 8px 8px
+ height 60px
+ overflow hidden
+ white-space normal
+
+ &:after
+ content ""
+ display block
+ position absolute
+ top 40px
+ left 0
+ width 100%
+ height 20px
+ background linear-gradient(to bottom, rgba(255, 255, 255, 0) 0%, #fff 100%)
+
+ > mk-time
+ display inline-block
+ padding 8px
+ color #aaa
+
+</style>
diff --git a/src/web/app/mobile/views/components/ui-nav.vue b/src/web/app/mobile/views/components/ui-nav.vue
index 3765ce8870..cab24787d1 100644
--- a/src/web/app/mobile/views/components/ui-nav.vue
+++ b/src/web/app/mobile/views/components/ui-nav.vue
@@ -2,7 +2,7 @@
<div class="mk-ui-nav" :style="{ display: isOpen ? 'block' : 'none' }">
<div class="backdrop" @click="parent.toggleDrawer"></div>
<div class="body">
- <a class="me" v-if="SIGNIN" href={ '/' + I.username }>
+ <a class="me" v-if="$root.$data.os.isSignedIn" href={ '/' + I.username }>
<img class="avatar" src={ I.avatar_url + '?thumbnail&size=128' } alt="avatar"/>
<p class="name">{ I.name }</p>
</a>
diff --git a/src/web/app/mobile/views/pages/user.vue b/src/web/app/mobile/views/pages/user.vue
new file mode 100644
index 0000000000..d92f3bbe65
--- /dev/null
+++ b/src/web/app/mobile/views/pages/user.vue
@@ -0,0 +1,226 @@
+<template>
+<mk-ui :func="fn" func-icon="%fa:pencil-alt%">
+ <span slot="header">%fa:user% {{user.name}}</span>
+ <div v-if="!fetching" :class="$style.user">
+ <header>
+ <div class="banner" :style="user.banner_url ? `background-image: url(${user.banner_url}?thumbnail&size=1024)` : ''"></div>
+ <div class="body">
+ <div class="top">
+ <a class="avatar">
+ <img :src="`${user.avatar_url}?thumbnail&size=200`" alt="avatar"/>
+ </a>
+ <mk-follow-button v-if="$root.$data.os.isSignedIn && $root.$data.os.i.id != user.id" :user="user"/>
+ </div>
+ <div class="title">
+ <h1>{{ user.name }}</h1>
+ <span class="username">@{{ user.username }}</span>
+ <span class="followed" v-if="user.is_followed">%i18n:mobile.tags.mk-user.follows-you%</span>
+ </div>
+ <div class="description">{{ user.description }}</div>
+ <div class="info">
+ <p class="location" v-if="user.profile.location">
+ %fa:map-marker%{{ user.profile.location }}
+ </p>
+ <p class="birthday" v-if="user.profile.birthday">
+ %fa:birthday-cake%{{ user.profile.birthday.replace('-', '年').replace('-', '月') + '日' }} ({{ age }}歳)
+ </p>
+ </div>
+ <div class="status">
+ <a>
+ <b>{{ user.posts_count }}</b>
+ <i>%i18n:mobile.tags.mk-user.posts%</i>
+ </a>
+ <a :href="`${user.username}/following`">
+ <b>{{ user.following_count }}</b>
+ <i>%i18n:mobile.tags.mk-user.following%</i>
+ </a>
+ <a :href="`${user.username}/followers`">
+ <b>{{ user.followers_count }}</b>
+ <i>%i18n:mobile.tags.mk-user.followers%</i>
+ </a>
+ </div>
+ </div>
+ <nav>
+ <a :data-is-active=" page == 'home' " @click="page = 'home'">%i18n:mobile.tags.mk-user.overview%</a>
+ <a :data-is-active=" page == 'posts' " @click="page = 'posts'">%i18n:mobile.tags.mk-user.timeline%</a>
+ <a :data-is-active=" page == 'media' " @click="page = 'media'">%i18n:mobile.tags.mk-user.media%</a>
+ </nav>
+ </header>
+ <div class="body">
+ <mk-user-home v-if="page == 'home'" :user="user"/>
+ <mk-user-timeline v-if="page == 'posts'" :user="user"/>
+ <mk-user-timeline v-if="page == 'media'" :user="user" with-media/>
+ </div>
+ </div>
+</mk-ui>
+</template>
+
+<script lang="ts">
+import Vue from 'vue';
+const age = require('s-age');
+
+export default Vue.extend({
+ props: {
+ username: {
+ type: String,
+ required: true
+ },
+ page: {
+ default: 'home'
+ }
+ },
+ data() {
+ return {
+ fetching: true,
+ user: null
+ };
+ },
+ computed: {
+ age(): number {
+ return age(this.user.profile.birthday);
+ }
+ },
+ mounted() {
+ this.$root.$data.os.api('users/show', {
+ username: this.username
+ }).then(user => {
+ this.fetching = false;
+ this.user = user;
+ this.$emit('loaded', user);
+ });
+ }
+});
+</script>
+
+<style lang="stylus" module>
+.user
+ > header
+ box-shadow 0 4px 4px rgba(0, 0, 0, 0.3)
+
+ > .banner
+ padding-bottom 33.3%
+ background-color #1b1b1b
+ background-size cover
+ background-position center
+
+ > .body
+ padding 12px
+ margin 0 auto
+ max-width 600px
+
+ > .top
+ &:after
+ content ''
+ display block
+ clear both
+
+ > .avatar
+ display block
+ float left
+ width 25%
+ height 40px
+
+ > img
+ display block
+ position absolute
+ left -2px
+ bottom -2px
+ width 100%
+ border 2px solid #313a42
+ border-radius 6px
+
+ @media (min-width 500px)
+ left -4px
+ bottom -4px
+ border 4px solid #313a42
+ border-radius 12px
+
+ > mk-follow-button
+ float right
+ height 40px
+
+ > .title
+ margin 8px 0
+
+ > h1
+ margin 0
+ line-height 22px
+ font-size 20px
+ color #fff
+
+ > .username
+ display inline-block
+ line-height 20px
+ font-size 16px
+ font-weight bold
+ color #657786
+
+ > .followed
+ margin-left 8px
+ padding 2px 4px
+ font-size 12px
+ color #657786
+ background #f8f8f8
+ border-radius 4px
+
+ > .description
+ margin 8px 0
+ color #fff
+
+ > .info
+ margin 8px 0
+
+ > p
+ display inline
+ margin 0 16px 0 0
+ color #a9b9c1
+
+ > i
+ margin-right 4px
+
+ > .status
+ > a
+ color #657786
+
+ &:not(:last-child)
+ margin-right 16px
+
+ > b
+ margin-right 4px
+ font-size 16px
+ color #fff
+
+ > i
+ font-size 14px
+
+ > mk-activity-table
+ margin 12px 0 0 0
+
+ > nav
+ display flex
+ justify-content center
+ margin 0 auto
+ max-width 600px
+
+ > a
+ display block
+ flex 1 1
+ text-align center
+ line-height 52px
+ font-size 14px
+ text-decoration none
+ color #657786
+ border-bottom solid 2px transparent
+
+ &[data-is-active]
+ font-weight bold
+ color $theme-color
+ border-color $theme-color
+
+ > .body
+ padding 8px
+
+ @media (min-width 500px)
+ padding 16px
+
+</style>
diff --git a/src/web/app/mobile/views/pages/user/followers-you-know.vue b/src/web/app/mobile/views/pages/user/followers-you-know.vue
new file mode 100644
index 0000000000..a4358f5d90
--- /dev/null
+++ b/src/web/app/mobile/views/pages/user/followers-you-know.vue
@@ -0,0 +1,62 @@
+<template>
+<div class="mk-user-home-followers-you-know">
+ <p class="initializing" v-if="fetching">%fa:spinner .pulse .fw%%i18n:mobile.tags.mk-user-overview-followers-you-know.loading%<mk-ellipsis/></p>
+ <div v-if="!fetching && users.length > 0">
+ <a v-for="user in users" :key="user.id" :href="`/${user.username}`">
+ <img :src="`${user.avatar_url}?thumbnail&size=64`" :alt="user.name"/>
+ </a>
+ </div>
+ <p class="empty" v-if="!fetching && users.length == 0">%i18n:mobile.tags.mk-user-overview-followers-you-know.no-users%</p>
+</div>
+</template>
+
+<script lang="ts">
+import Vue from 'vue';
+export default Vue.extend({
+ props: ['user'],
+ data() {
+ return {
+ fetching: true,
+ users: []
+ };
+ },
+ mounted() {
+ this.$root.$data.os.api('users/followers', {
+ user_id: this.user.id,
+ iknow: true,
+ limit: 30
+ }).then(res => {
+ this.fetching = false;
+ this.users = res.users;
+ });
+ }
+});
+</script>
+
+<style lang="stylus" scoped>
+.mk-user-home-followers-you-know
+
+ > div
+ padding 4px
+
+ > a
+ display inline-block
+ margin 4px
+
+ > img
+ width 48px
+ height 48px
+ vertical-align bottom
+ border-radius 100%
+
+ > .initializing
+ > .empty
+ margin 0
+ padding 16px
+ text-align center
+ color #aaa
+
+ > i
+ margin-right 4px
+
+</style>
diff --git a/src/web/app/mobile/views/pages/user/home-activity.vue b/src/web/app/mobile/views/pages/user/home-activity.vue
new file mode 100644
index 0000000000..00a2dafc12
--- /dev/null
+++ b/src/web/app/mobile/views/pages/user/home-activity.vue
@@ -0,0 +1,62 @@
+<template>
+<div class="mk-user-home-activity">
+ <svg v-if="data" ref="canvas" viewBox="0 0 30 1" preserveAspectRatio="none">
+ <g v-for="(d, i) in data.reverse()" :key="i">
+ <rect width="0.8" :height="d.postsH"
+ :x="i + 0.1" :y="1 - d.postsH - d.repliesH - d.repostsH"
+ fill="#41ddde"/>
+ <rect width="0.8" :height="d.repliesH"
+ :x="i + 0.1" :y="1 - d.repliesH - d.repostsH"
+ fill="#f7796c"/>
+ <rect width="0.8" :height="d.repostsH"
+ :x="i + 0.1" :y="1 - d.repostsH"
+ fill="#a1de41"/>
+ </g>
+ </svg>
+</div>
+</template>
+
+<script lang="ts">
+import Vue from 'vue';
+export default Vue.extend({
+ props: ['user'],
+ data() {
+ return {
+ fetching: true,
+ data: [],
+ peak: null
+ };
+ },
+ mounted() {
+ this.$root.$data.os.api('aggregation/users/activity', {
+ user_id: this.user.id,
+ limit: 30
+ }).then(data => {
+ data.forEach(d => d.total = d.posts + d.replies + d.reposts);
+ this.peak = Math.max.apply(null, data.map(d => d.total));
+ data.forEach(d => {
+ d.postsH = d.posts / this.peak;
+ d.repliesH = d.replies / this.peak;
+ d.repostsH = d.reposts / this.peak;
+ });
+ this.data = data;
+ });
+ }
+});
+</script>
+
+<style lang="stylus" scoped>
+.mk-user-home-activity
+ display block
+ max-width 600px
+ margin 0 auto
+
+ > svg
+ display block
+ width 100%
+ height 80px
+
+ > rect
+ transform-origin center
+
+</style>
diff --git a/src/web/app/mobile/views/pages/user/home-friends.vue b/src/web/app/mobile/views/pages/user/home-friends.vue
new file mode 100644
index 0000000000..2a7e8b9617
--- /dev/null
+++ b/src/web/app/mobile/views/pages/user/home-friends.vue
@@ -0,0 +1,54 @@
+<template>
+<div class="mk-user-home-friends">
+ <p class="initializing" v-if="fetching">%fa:spinner .pulse .fw%%i18n:mobile.tags.mk-user-overview-frequently-replied-users.loading%<mk-ellipsis/></p>
+ <div v-if="!fetching && users.length > 0">
+ <mk-user-card v-for="user in users" :key="user.id" :user="user"/>
+ </div>
+ <p class="empty" v-if="!fetching && users.length == 0">%i18n:mobile.tags.mk-user-overview-frequently-replied-users.no-users%</p>
+</div>
+</template>
+
+<script lang="ts">
+import Vue from 'vue';
+export default Vue.extend({
+ props: ['user'],
+ data() {
+ return {
+ fetching: true,
+ users: []
+ };
+ },
+ mounted() {
+ this.$root.$data.os.api('users/get_frequently_replied_users', {
+ user_id: this.user.id
+ }).then(res => {
+ this.fetching = false;
+ this.users = res.map(x => x.user);
+ });
+ }
+});
+</script>
+
+<style lang="stylus" scoped>
+.mk-user-home-friends
+ > div
+ overflow-x scroll
+ -webkit-overflow-scrolling touch
+ white-space nowrap
+ padding 8px
+
+ > mk-user-card
+ &:not(:last-child)
+ margin-right 8px
+
+ > .initializing
+ > .empty
+ margin 0
+ padding 16px
+ text-align center
+ color #aaa
+
+ > i
+ margin-right 4px
+
+</style>
diff --git a/src/web/app/mobile/views/pages/user/home-photos.vue b/src/web/app/mobile/views/pages/user/home-photos.vue
new file mode 100644
index 0000000000..fc2d0e139a
--- /dev/null
+++ b/src/web/app/mobile/views/pages/user/home-photos.vue
@@ -0,0 +1,78 @@
+<template>
+<div class="mk-user-home-photos">
+ <p class="initializing" v-if="fetching">%fa:spinner .pulse .fw%%i18n:mobile.tags.mk-user-overview-photos.loading%<mk-ellipsis/></p>
+ <div class="stream" v-if="!fetching && images.length > 0">
+ <a v-for="image in images" :key="image.id"
+ class="img"
+ :style="`background-image: url(${image.media.url}?thumbnail&size=256)`"
+ :href="`/${image.post.user.username}/${image.post.id}`"
+ ></a>
+ </div>
+ <p class="empty" v-if="!fetching && images.length == 0">%i18n:mobile.tags.mk-user-overview-photos.no-photos%</p>
+</div>
+</template>
+
+<script lang="ts">
+import Vue from 'vue';
+export default Vue.extend({
+ props: ['user'],
+ data() {
+ return {
+ fetching: true,
+ images: []
+ };
+ },
+ mounted() {
+ this.$root.$data.os.api('users/posts', {
+ user_id: this.user.id,
+ 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({
+ post,
+ media
+ });
+ });
+ });
+ });
+ }
+});
+</script>
+
+<style lang="stylus" scoped>
+.mk-user-home-photos
+
+ > .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
+ border-radius 4px
+
+ > .initializing
+ > .empty
+ margin 0
+ padding 16px
+ text-align center
+ color #aaa
+
+ > i
+ margin-right 4px
+
+</style>
+
diff --git a/src/web/app/mobile/views/pages/user/home-posts.vue b/src/web/app/mobile/views/pages/user/home-posts.vue
new file mode 100644
index 0000000000..b1451b0887
--- /dev/null
+++ b/src/web/app/mobile/views/pages/user/home-posts.vue
@@ -0,0 +1,57 @@
+<template>
+<div class="mk-user-home-posts">
+ <p class="initializing" v-if="initializing">%fa:spinner .pulse .fw%%i18n:mobile.tags.mk-user-overview-posts.loading%<mk-ellipsis/></p>
+ <div v-if="!initializing && posts.length > 0">
+ <mk-post-card v-for="post in posts" :key="post.id" :post="post"/>
+ </div>
+ <p class="empty" v-if="!initializing && posts.length == 0">%i18n:mobile.tags.mk-user-overview-posts.no-posts%</p>
+</div>
+</template>
+
+<script lang="ts">
+import Vue from 'vue';
+export default Vue.extend({
+ props: ['user'],
+ data() {
+ return {
+ fetching: true,
+ posts: []
+ };
+ },
+ mounted() {
+ this.$root.$data.os.api('users/posts', {
+ user_id: this.user.id
+ }).then(posts => {
+ this.fetching = false;
+ this.posts = posts;
+ });
+ }
+});
+</script>
+
+<style lang="stylus" scoped>
+.mk-user-home-posts
+
+ > div
+ overflow-x scroll
+ -webkit-overflow-scrolling touch
+ white-space nowrap
+ padding 8px
+
+ > *
+ vertical-align top
+
+ &:not(:last-child)
+ margin-right 8px
+
+ > .initializing
+ > .empty
+ margin 0
+ padding 16px
+ text-align center
+ color #aaa
+
+ > i
+ margin-right 4px
+
+</style>
diff --git a/src/web/app/mobile/views/pages/user/home.vue b/src/web/app/mobile/views/pages/user/home.vue
new file mode 100644
index 0000000000..56b9285591
--- /dev/null
+++ b/src/web/app/mobile/views/pages/user/home.vue
@@ -0,0 +1,95 @@
+<template>
+<div class="mk-user-home">
+ <mk-post-detail v-if="user.pinned_post" :post="user.pinned_post" compact/>
+ <section class="recent-posts">
+ <h2>%fa:R comments%%i18n:mobile.tags.mk-user-overview.recent-posts%</h2>
+ <div>
+ <mk-user-home-posts :user="user"/>
+ </div>
+ </section>
+ <section class="images">
+ <h2>%fa:image%%i18n:mobile.tags.mk-user-overview.images%</h2>
+ <div>
+ <mk-user-home-photos :user="user"/>
+ </div>
+ </section>
+ <section class="activity">
+ <h2>%fa:chart-bar%%i18n:mobile.tags.mk-user-overview.activity%</h2>
+ <div>
+ <mk-user-home-activity-chart :user="user"/>
+ </div>
+ </section>
+ <section class="keywords">
+ <h2>%fa:R comment%%i18n:mobile.tags.mk-user-overview.keywords%</h2>
+ <div>
+ <mk-user-home-keywords :user="user"/>
+ </div>
+ </section>
+ <section class="domains">
+ <h2>%fa:globe%%i18n:mobile.tags.mk-user-overview.domains%</h2>
+ <div>
+ <mk-user-home-domains :user="user"/>
+ </div>
+ </section>
+ <section class="frequently-replied-users">
+ <h2>%fa:users%%i18n:mobile.tags.mk-user-overview.frequently-replied-users%</h2>
+ <div>
+ <mk-user-home-frequently-replied-users :user="user"/>
+ </div>
+ </section>
+ <section class="followers-you-know" v-if="$root.$data.os.isSignedIn && $root.$data.os.i.id !== user.id">
+ <h2>%fa:users%%i18n:mobile.tags.mk-user-overview.followers-you-know%</h2>
+ <div>
+ <mk-user-home-followers-you-know :user="user"/>
+ </div>
+ </section>
+ <p>%i18n:mobile.tags.mk-user-overview.last-used-at%: <b><mk-time :time="user.last_used_at"/></b></p>
+</div>
+</template>
+
+<script lang="ts">
+import Vue from 'vue';
+export default Vue.extend({
+ props: ['user']
+});
+</script>
+
+<style lang="stylus" scoped>
+.mk-user-home
+ max-width 600px
+ margin 0 auto
+
+ > mk-post-detail
+ margin 0 0 8px 0
+
+ > section
+ background #eee
+ border-radius 8px
+ box-shadow 0 0 0 1px rgba(0, 0, 0, 0.2)
+
+ &:not(:last-child)
+ margin-bottom 8px
+
+ > h2
+ margin 0
+ padding 8px 10px
+ font-size 15px
+ font-weight normal
+ color #465258
+ background #fff
+ border-radius 8px 8px 0 0
+
+ > i
+ margin-right 6px
+
+ > .activity
+ > div
+ padding 8px
+
+ > p
+ display block
+ margin 16px
+ text-align center
+ color #cad2da
+
+</style>