Skip to content
Snippets Groups Projects
Commit e0aba492 authored by こぴなたみぽ's avatar こぴなたみぽ
Browse files

wip

parent 7b733143
No related branches found
No related tags found
No related merge requests found
<mk-post-detail title={ title }>
<div class="main">
<button class="read-more" v-if="p.reply && p.reply.reply_id && context == null" title="会話をもっと読み込む" @click="loadContext" disabled={ contextFetching }>
<template v-if="!contextFetching">%fa:ellipsis-v%</template>
<template v-if="contextFetching">%fa:spinner .pulse%</template>
</button>
<div class="context">
<template each={ post in context }>
<mk-post-detail-sub post={ post }/>
</template>
</div>
<div class="reply-to" v-if="p.reply">
<mk-post-detail-sub post={ p.reply }/>
</div>
<div class="repost" v-if="isRepost">
<p>
<a class="avatar-anchor" href={ '/' + post.user.username } data-user-preview={ post.user_id }>
<img class="avatar" src={ post.user.avatar_url + '?thumbnail&size=32' } alt="avatar"/>
</a>
%fa:retweet%<a class="name" href={ '/' + post.user.username }>
{ post.user.name }
</a>
がRepost
</p>
</div>
<article>
<a class="avatar-anchor" href={ '/' + p.user.username }>
<img class="avatar" src={ p.user.avatar_url + '?thumbnail&size=64' } alt="avatar" data-user-preview={ p.user.id }/>
</a>
<header>
<a class="name" href={ '/' + p.user.username } data-user-preview={ p.user.id }>{ p.user.name }</a>
<span class="username">@{ p.user.username }</span>
<a class="time" href={ '/' + p.user.username + '/' + p.id }>
<mk-time time={ p.created_at }/>
</a>
</header>
<div class="body">
<div class="text" ref="text"></div>
<div class="media" v-if="p.media">
<mk-images images={ p.media }/>
</div>
<mk-poll v-if="p.poll" post={ p }/>
</div>
<footer>
<mk-reactions-viewer post={ p }/>
<button @click="reply" title="返信">
%fa:reply%<p class="count" v-if="p.replies_count > 0">{ p.replies_count }</p>
</button>
<button @click="repost" title="Repost">
%fa:retweet%<p class="count" v-if="p.repost_count > 0">{ p.repost_count }</p>
</button>
<button :class="{ reacted: p.my_reaction != null }" @click="react" ref="reactButton" title="リアクション">
%fa:plus%<p class="count" v-if="p.reactions_count > 0">{ p.reactions_count }</p>
</button>
<button @click="menu" ref="menuButton">
%fa:ellipsis-h%
</button>
</footer>
</article>
<div class="replies" v-if="!compact">
<template each={ post in replies }>
<mk-post-detail-sub post={ post }/>
</template>
</div>
</div>
<style lang="stylus" scoped>
:scope
display block
margin 0
padding 0
overflow hidden
text-align left
background #fff
border solid 1px rgba(0, 0, 0, 0.1)
border-radius 8px
> .main
> .read-more
display block
margin 0
padding 10px 0
width 100%
font-size 1em
text-align center
color #999
cursor pointer
background #fafafa
outline none
border none
border-bottom solid 1px #eef0f2
border-radius 6px 6px 0 0
&:hover
background #f6f6f6
&:active
background #f0f0f0
&:disabled
color #ccc
> .context
> *
border-bottom 1px solid #eef0f2
> .repost
color #9dbb00
background linear-gradient(to bottom, #edfde2 0%, #fff 100%)
> p
margin 0
padding 16px 32px
.avatar-anchor
display inline-block
.avatar
vertical-align bottom
min-width 28px
min-height 28px
max-width 28px
max-height 28px
margin 0 8px 0 0
border-radius 6px
[data-fa]
margin-right 4px
.name
font-weight bold
& + article
padding-top 8px
> .reply-to
border-bottom 1px solid #eef0f2
> article
padding 28px 32px 18px 32px
&:after
content ""
display block
clear both
&:hover
> .main > footer > button
color #888
> .avatar-anchor
display block
width 60px
height 60px
> .avatar
display block
width 60px
height 60px
margin 0
border-radius 8px
vertical-align bottom
> header
position absolute
top 28px
left 108px
width calc(100% - 108px)
> .name
display inline-block
margin 0
line-height 24px
color #777
font-size 18px
font-weight 700
text-align left
text-decoration none
&:hover
text-decoration underline
> .username
display block
text-align left
margin 0
color #ccc
> .time
position absolute
top 0
right 32px
font-size 1em
color #c0c0c0
> .body
padding 8px 0
> .text
cursor default
display block
margin 0
padding 0
overflow-wrap break-word
font-size 1.5em
color #717171
> mk-url-preview
margin-top 8px
> footer
font-size 1.2em
> button
margin 0 28px 0 0
padding 8px
background transparent
border none
font-size 1em
color #ddd
cursor pointer
&:hover
color #666
> .count
display inline
margin 0 0 0 8px
color #999
&.reacted
color $theme-color
> .replies
> *
border-top 1px solid #eef0f2
</style>
<script lang="typescript">
import compile from '../../common/scripts/text-compiler';
import dateStringify from '../../common/scripts/date-stringify';
this.mixin('api');
this.mixin('user-preview');
this.compact = this.opts.compact;
this.contextFetching = false;
this.context = null;
this.post = this.opts.post;
this.isRepost = this.post.repost != null;
this.p = this.isRepost ? this.post.repost : this.post;
this.p.reactions_count = this.p.reaction_counts ? Object.keys(this.p.reaction_counts).map(key => this.p.reaction_counts[key]).reduce((a, b) => a + b) : 0;
this.title = dateStringify(this.p.created_at);
this.on('mount', () => {
if (this.p.text) {
const tokens = this.p.ast;
this.$refs.text.innerHTML = compile(tokens);
Array.from(this.$refs.text.children).forEach(e => {
if (e.tagName == 'MK-URL') riot.mount(e);
});
// URLをプレビュー
tokens
.filter(t => (t.type == 'url' || t.type == 'link') && !t.silent)
.map(t => {
riot.mount(this.$refs.text.appendChild(document.createElement('mk-url-preview')), {
url: t.url
});
});
}
// Get replies
if (!this.compact) {
this.api('posts/replies', {
post_id: this.p.id,
limit: 8
}).then(replies => {
this.update({
replies: replies
});
});
}
});
this.reply = () => {
riot.mount(document.body.appendChild(document.createElement('mk-post-form-window')), {
reply: this.p
});
};
this.repost = () => {
riot.mount(document.body.appendChild(document.createElement('mk-repost-form-window')), {
post: this.p
});
};
this.react = () => {
riot.mount(document.body.appendChild(document.createElement('mk-reaction-picker')), {
source: this.$refs.reactButton,
post: this.p
});
};
this.menu = () => {
riot.mount(document.body.appendChild(document.createElement('mk-post-menu')), {
source: this.$refs.menuButton,
post: this.p
});
};
this.loadContext = () => {
this.contextFetching = true;
// Fetch context
this.api('posts/context', {
post_id: this.p.reply_id
}).then(context => {
this.update({
contextFetching: false,
context: context.reverse()
});
});
};
</script>
</mk-post-detail>
<template>
<div class="mk-post-detail" :title="title">
<button class="read-more" v-if="p.reply && p.reply.reply_id && context == null" title="会話をもっと読み込む" @click="loadContext" disabled={ contextFetching }>
<template v-if="!contextFetching">%fa:ellipsis-v%</template>
<template v-if="contextFetching">%fa:spinner .pulse%</template>
</button>
<div class="context">
<template each={ post in context }>
<mk-post-detail-sub post={ post }/>
</template>
</div>
<div class="reply-to" v-if="p.reply">
<mk-post-detail-sub post={ p.reply }/>
</div>
<div class="repost" v-if="isRepost">
<p>
<a class="avatar-anchor" href={ '/' + post.user.username } data-user-preview={ post.user_id }>
<img class="avatar" src={ post.user.avatar_url + '?thumbnail&size=32' } alt="avatar"/>
</a>
%fa:retweet%<a class="name" href={ '/' + post.user.username }>
{ post.user.name }
</a>
がRepost
</p>
</div>
<article>
<a class="avatar-anchor" href={ '/' + p.user.username }>
<img class="avatar" src={ p.user.avatar_url + '?thumbnail&size=64' } alt="avatar" data-user-preview={ p.user.id }/>
</a>
<header>
<a class="name" href={ '/' + p.user.username } data-user-preview={ p.user.id }>{ p.user.name }</a>
<span class="username">@{ p.user.username }</span>
<a class="time" href={ '/' + p.user.username + '/' + p.id }>
<mk-time time={ p.created_at }/>
</a>
</header>
<div class="body">
<mk-post-html v-if="p.ast" :ast="p.ast" :i="$root.$data.os.i"/>
<mk-url-preview v-for="url in urls" :url="url" :key="url"/>
<div class="media" v-if="p.media">
<mk-images images={ p.media }/>
</div>
<mk-poll v-if="p.poll" post={ p }/>
</div>
<footer>
<mk-reactions-viewer post={ p }/>
<button @click="reply" title="返信">
%fa:reply%<p class="count" v-if="p.replies_count > 0">{ p.replies_count }</p>
</button>
<button @click="repost" title="Repost">
%fa:retweet%<p class="count" v-if="p.repost_count > 0">{ p.repost_count }</p>
</button>
<button :class="{ reacted: p.my_reaction != null }" @click="react" ref="reactButton" title="リアクション">
%fa:plus%<p class="count" v-if="p.reactions_count > 0">{ p.reactions_count }</p>
</button>
<button @click="menu" ref="menuButton">
%fa:ellipsis-h%
</button>
</footer>
</article>
<div class="replies" v-if="!compact">
<template each={ post in replies }>
<mk-post-detail-sub post={ post }/>
</template>
</div>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
import dateStringify from '../../common/scripts/date-stringify';
export default Vue.extend({
props: {
post: {
type: Object,
required: true
},
compact: {
default: false
}
},
data() {
return {
context: [],
contextFetching: false,
replies: [],
};
},
computed: {
isRepost(): boolean {
return this.post.repost != null;
},
p(): any {
return this.isRepost ? this.post.repost : this.post;
},
reactionsCount(): number {
return this.p.reaction_counts
? Object.keys(this.p.reaction_counts)
.map(key => this.p.reaction_counts[key])
.reduce((a, b) => a + b)
: 0;
},
title(): string {
return dateStringify(this.p.created_at);
},
urls(): string[] {
if (this.p.ast) {
return this.p.ast
.filter(t => (t.type == 'url' || t.type == 'link') && !t.silent)
.map(t => t.url);
} else {
return null;
}
}
},
mounted() {
// Get replies
if (!this.compact) {
this.$root.$data.os.api('posts/replies', {
post_id: this.p.id,
limit: 8
}).then(replies => {
this.replies = replies;
});
}
},
methods: {
fetchContext() {
this.contextFetching = true;
// Fetch context
this.$root.$data.os.api('posts/context', {
post_id: this.p.reply_id
}).then(context => {
this.contextFetching = false;
this.context = context.reverse();
});
}
}
});
</script>
<style lang="stylus" scoped>
.mk-post-detail
margin 0
padding 0
overflow hidden
text-align left
background #fff
border solid 1px rgba(0, 0, 0, 0.1)
border-radius 8px
> .read-more
display block
margin 0
padding 10px 0
width 100%
font-size 1em
text-align center
color #999
cursor pointer
background #fafafa
outline none
border none
border-bottom solid 1px #eef0f2
border-radius 6px 6px 0 0
&:hover
background #f6f6f6
&:active
background #f0f0f0
&:disabled
color #ccc
> .context
> *
border-bottom 1px solid #eef0f2
> .repost
color #9dbb00
background linear-gradient(to bottom, #edfde2 0%, #fff 100%)
> p
margin 0
padding 16px 32px
.avatar-anchor
display inline-block
.avatar
vertical-align bottom
min-width 28px
min-height 28px
max-width 28px
max-height 28px
margin 0 8px 0 0
border-radius 6px
[data-fa]
margin-right 4px
.name
font-weight bold
& + article
padding-top 8px
> .reply-to
border-bottom 1px solid #eef0f2
> article
padding 28px 32px 18px 32px
&:after
content ""
display block
clear both
&:hover
> .main > footer > button
color #888
> .avatar-anchor
display block
width 60px
height 60px
> .avatar
display block
width 60px
height 60px
margin 0
border-radius 8px
vertical-align bottom
> header
position absolute
top 28px
left 108px
width calc(100% - 108px)
> .name
display inline-block
margin 0
line-height 24px
color #777
font-size 18px
font-weight 700
text-align left
text-decoration none
&:hover
text-decoration underline
> .username
display block
text-align left
margin 0
color #ccc
> .time
position absolute
top 0
right 32px
font-size 1em
color #c0c0c0
> .body
padding 8px 0
> .text
cursor default
display block
margin 0
padding 0
overflow-wrap break-word
font-size 1.5em
color #717171
> mk-url-preview
margin-top 8px
> footer
font-size 1.2em
> button
margin 0 28px 0 0
padding 8px
background transparent
border none
font-size 1em
color #ddd
cursor pointer
&:hover
color #666
> .count
display inline
margin 0 0 0 8px
color #999
&.reacted
color $theme-color
> .replies
> *
border-top 1px solid #eef0f2
</style>
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment