summaryrefslogtreecommitdiff
path: root/src/web
diff options
context:
space:
mode:
authorこぴなたみぽ <syuilotan@yahoo.co.jp>2018-02-14 22:20:09 +0900
committerこぴなたみぽ <syuilotan@yahoo.co.jp>2018-02-14 22:20:09 +0900
commite0aba492ddfeb35a1905868f68abe526b3943b4e (patch)
treec0d5d0acdd452cfdc1b9cf00fd081079e5d1fed9 /src/web
parentwip (diff)
downloadmisskey-e0aba492ddfeb35a1905868f68abe526b3943b4e.tar.gz
misskey-e0aba492ddfeb35a1905868f68abe526b3943b4e.tar.bz2
misskey-e0aba492ddfeb35a1905868f68abe526b3943b4e.zip
wip
Diffstat (limited to 'src/web')
-rw-r--r--src/web/app/desktop/-tags/post-detail.tag328
-rw-r--r--src/web/app/desktop/views/components/post-detail.vue313
2 files changed, 313 insertions, 328 deletions
diff --git a/src/web/app/desktop/-tags/post-detail.tag b/src/web/app/desktop/-tags/post-detail.tag
deleted file mode 100644
index 5f35ce6afa..0000000000
--- a/src/web/app/desktop/-tags/post-detail.tag
+++ /dev/null
@@ -1,328 +0,0 @@
-<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>
diff --git a/src/web/app/desktop/views/components/post-detail.vue b/src/web/app/desktop/views/components/post-detail.vue
new file mode 100644
index 0000000000..090a5bef6f
--- /dev/null
+++ b/src/web/app/desktop/views/components/post-detail.vue
@@ -0,0 +1,313 @@
+<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>