mirror of
https://activitypub.software/TransFem-org/Sharkey.git
synced 2024-12-14 10:05:46 +01:00
wip
This commit is contained in:
parent
43d9d81b53
commit
4980b86d64
18 changed files with 761 additions and 771 deletions
|
@ -1,5 +1,5 @@
|
||||||
<mk-index>
|
<mk-index>
|
||||||
<main v-if="SIGNIN">
|
<main v-if="$root.$data.os.isSignedIn">
|
||||||
<p class="fetching" v-if="fetching">読み込み中<mk-ellipsis/></p>
|
<p class="fetching" v-if="fetching">読み込み中<mk-ellipsis/></p>
|
||||||
<mk-form ref="form" v-if="state == 'waiting'" session={ session }/>
|
<mk-form ref="form" v-if="state == 'waiting'" session={ session }/>
|
||||||
<div class="denied" v-if="state == 'denied'">
|
<div class="denied" v-if="state == 'denied'">
|
||||||
|
@ -15,7 +15,7 @@
|
||||||
<p>セッションが存在しません。</p>
|
<p>セッションが存在しません。</p>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
<main class="signin" v-if="!SIGNIN">
|
<main class="signin" v-if="!$root.$data.os.isSignedIn">
|
||||||
<h1>サインインしてください</h1>
|
<h1>サインインしてください</h1>
|
||||||
<mk-signin/>
|
<mk-signin/>
|
||||||
</main>
|
</main>
|
||||||
|
@ -93,7 +93,7 @@
|
||||||
this.token = window.location.href.split('/').pop();
|
this.token = window.location.href.split('/').pop();
|
||||||
|
|
||||||
this.on('mount', () => {
|
this.on('mount', () => {
|
||||||
if (!this.SIGNIN) return;
|
if (!this.$root.$data.os.isSignedIn) return;
|
||||||
|
|
||||||
// Fetch session
|
// Fetch session
|
||||||
this.$root.$data.os.api('auth/session/show', {
|
this.$root.$data.os.api('auth/session/show', {
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
<main v-if="!fetching">
|
<main v-if="!fetching">
|
||||||
<h1>{ channel.title }</h1>
|
<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="unwatch">ウォッチ解除</a></p>
|
||||||
<p v-if="!channel.is_watching"><a @click="watch">このチャンネルをウォッチする</a></p>
|
<p v-if="!channel.is_watching"><a @click="watch">このチャンネルをウォッチする</a></p>
|
||||||
</div>
|
</div>
|
||||||
|
@ -24,8 +24,8 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<hr>
|
<hr>
|
||||||
<mk-channel-form v-if="SIGNIN" channel={ channel } ref="form"/>
|
<mk-channel-form v-if="$root.$data.os.isSignedIn" channel={ channel } ref="form"/>
|
||||||
<div v-if="!SIGNIN">
|
<div v-if="!$root.$data.os.isSignedIn">
|
||||||
<p>参加するには<a href={ _URL_ }>ログインまたは新規登録</a>してください</p>
|
<p>参加するには<a href={ _URL_ }>ログインまたは新規登録</a>してください</p>
|
||||||
</div>
|
</div>
|
||||||
<hr>
|
<hr>
|
||||||
|
@ -125,7 +125,7 @@
|
||||||
this.posts.unshift(post);
|
this.posts.unshift(post);
|
||||||
this.update();
|
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++;
|
this.unreadCount++;
|
||||||
document.title = `(${this.unreadCount}) ${this.channel.title} | Misskey`;
|
document.title = `(${this.unreadCount}) ${this.channel.title} | Misskey`;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,8 +3,8 @@
|
||||||
<a href={ _CH_URL_ }>Index</a> | <a href={ _URL_ }>Misskey</a>
|
<a href={ _CH_URL_ }>Index</a> | <a href={ _URL_ }>Misskey</a>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<a v-if="!SIGNIN" href={ _URL_ }>ログイン(新規登録)</a>
|
<a v-if="!$root.$data.os.isSignedIn" href={ _URL_ }>ログイン(新規登録)</a>
|
||||||
<a v-if="SIGNIN" href={ _URL_ + '/' + I.username }>{ I.username }</a>
|
<a v-if="$root.$data.os.isSignedIn" href={ _URL_ + '/' + I.username }>{ I.username }</a>
|
||||||
</div>
|
</div>
|
||||||
<style lang="stylus" scoped>
|
<style lang="stylus" scoped>
|
||||||
:scope
|
:scope
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
<p>フォロワー</p><a>{ user.followers_count }</a>
|
<p>フォロワー</p><a>{ user.followers_count }</a>
|
||||||
</div>
|
</div>
|
||||||
</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>
|
</template>
|
||||||
<style lang="stylus" scoped>
|
<style lang="stylus" scoped>
|
||||||
:scope
|
:scope
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<nav>
|
<nav>
|
||||||
<div>
|
<div>
|
||||||
<span data-is-active={ mode == 'all' } @click="setMode.bind(this, 'all')">すべて<span>{ opts.count }</span></span>
|
<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>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
<div class="users" v-if="!fetching && users.length != 0">
|
<div class="users" v-if="!fetching && users.length != 0">
|
||||||
|
|
|
@ -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>
|
|
|
@ -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>
|
|
|
@ -1,7 +1,7 @@
|
||||||
<mk-users-list>
|
<mk-users-list>
|
||||||
<nav>
|
<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 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>
|
</nav>
|
||||||
<div class="users" v-if="!fetching && users.length != 0">
|
<div class="users" v-if="!fetching && users.length != 0">
|
||||||
<mk-user-preview each={ users } user={ this }/>
|
<mk-user-preview each={ users } user={ this }/>
|
||||||
|
|
29
src/web/app/mobile/views/components/home.vue
Normal file
29
src/web/app/mobile/views/components/home.vue
Normal file
|
@ -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>
|
85
src/web/app/mobile/views/components/post-card.vue
Normal file
85
src/web/app/mobile/views/components/post-card.vue
Normal file
|
@ -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>
|
|
@ -2,7 +2,7 @@
|
||||||
<div class="mk-ui-nav" :style="{ display: isOpen ? 'block' : 'none' }">
|
<div class="mk-ui-nav" :style="{ display: isOpen ? 'block' : 'none' }">
|
||||||
<div class="backdrop" @click="parent.toggleDrawer"></div>
|
<div class="backdrop" @click="parent.toggleDrawer"></div>
|
||||||
<div class="body">
|
<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"/>
|
<img class="avatar" src={ I.avatar_url + '?thumbnail&size=128' } alt="avatar"/>
|
||||||
<p class="name">{ I.name }</p>
|
<p class="name">{ I.name }</p>
|
||||||
</a>
|
</a>
|
||||||
|
|
226
src/web/app/mobile/views/pages/user.vue
Normal file
226
src/web/app/mobile/views/pages/user.vue
Normal file
|
@ -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>
|
62
src/web/app/mobile/views/pages/user/followers-you-know.vue
Normal file
62
src/web/app/mobile/views/pages/user/followers-you-know.vue
Normal file
|
@ -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>
|
62
src/web/app/mobile/views/pages/user/home-activity.vue
Normal file
62
src/web/app/mobile/views/pages/user/home-activity.vue
Normal file
|
@ -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>
|
54
src/web/app/mobile/views/pages/user/home-friends.vue
Normal file
54
src/web/app/mobile/views/pages/user/home-friends.vue
Normal file
|
@ -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>
|
78
src/web/app/mobile/views/pages/user/home-photos.vue
Normal file
78
src/web/app/mobile/views/pages/user/home-photos.vue
Normal file
|
@ -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>
|
||||||
|
|
57
src/web/app/mobile/views/pages/user/home-posts.vue
Normal file
57
src/web/app/mobile/views/pages/user/home-posts.vue
Normal file
|
@ -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>
|
95
src/web/app/mobile/views/pages/user/home.vue
Normal file
95
src/web/app/mobile/views/pages/user/home.vue
Normal file
|
@ -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>
|
Loading…
Reference in a new issue