oops
This commit is contained in:
		| @@ -1,122 +0,0 @@ | |||||||
| <template> |  | ||||||
| <div class="sub" :title="title"> |  | ||||||
| 	<router-link class="avatar-anchor" :to="note.user | userPage"> |  | ||||||
| 		<img class="avatar" :src="`${note.user.avatarUrl}?thumbnail&size=64`" alt="avatar" v-user-preview="note.userId"/> |  | ||||||
| 	</router-link> |  | ||||||
| 	<div class="main"> |  | ||||||
| 		<header> |  | ||||||
| 			<div class="left"> |  | ||||||
| 				<router-link class="name" :to="note.user | userPage" v-user-preview="note.userId">{{ note.user | userName }}</router-link> |  | ||||||
| 				<span class="username">@{{ note.user | acct }}</span> |  | ||||||
| 			</div> |  | ||||||
| 			<div class="right"> |  | ||||||
| 				<router-link class="time" :to="note | notePage"> |  | ||||||
| 					<mk-time :time="note.createdAt"/> |  | ||||||
| 				</router-link> |  | ||||||
| 			</div> |  | ||||||
| 		</header> |  | ||||||
| 		<div class="body"> |  | ||||||
| 			<mk-note-html v-if="note.text" :text="note.text" :i="os.i" :class="$style.text"/> |  | ||||||
| 			<div class="media" v-if="note.media > 0"> |  | ||||||
| 				<mk-media-list :media-list="note.media"/> |  | ||||||
| 			</div> |  | ||||||
| 		</div> |  | ||||||
| 	</div> |  | ||||||
| </div> |  | ||||||
| </template> |  | ||||||
|  |  | ||||||
| <script lang="ts"> |  | ||||||
| import Vue from 'vue'; |  | ||||||
| import dateStringify from '../../../common/scripts/date-stringify'; |  | ||||||
|  |  | ||||||
| export default Vue.extend({ |  | ||||||
| 	props: ['note'], |  | ||||||
| 	computed: { |  | ||||||
| 		title(): string { |  | ||||||
| 			return dateStringify(this.note.createdAt); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| }); |  | ||||||
| </script> |  | ||||||
|  |  | ||||||
| <style lang="stylus" scoped> |  | ||||||
| .sub |  | ||||||
| 	margin 0 |  | ||||||
| 	padding 20px 32px |  | ||||||
| 	background #fdfdfd |  | ||||||
|  |  | ||||||
| 	&:after |  | ||||||
| 		content "" |  | ||||||
| 		display block |  | ||||||
| 		clear both |  | ||||||
|  |  | ||||||
| 	&:hover |  | ||||||
| 		> .main > footer > button |  | ||||||
| 			color #888 |  | ||||||
|  |  | ||||||
| 	> .avatar-anchor |  | ||||||
| 		display block |  | ||||||
| 		float left |  | ||||||
| 		margin 0 16px 0 0 |  | ||||||
|  |  | ||||||
| 		> .avatar |  | ||||||
| 			display block |  | ||||||
| 			width 44px |  | ||||||
| 			height 44px |  | ||||||
| 			margin 0 |  | ||||||
| 			border-radius 4px |  | ||||||
| 			vertical-align bottom |  | ||||||
|  |  | ||||||
| 	> .main |  | ||||||
| 		float left |  | ||||||
| 		width calc(100% - 60px) |  | ||||||
|  |  | ||||||
| 		> header |  | ||||||
| 			margin-bottom 4px |  | ||||||
| 			white-space nowrap |  | ||||||
|  |  | ||||||
| 			&:after |  | ||||||
| 				content "" |  | ||||||
| 				display block |  | ||||||
| 				clear both |  | ||||||
|  |  | ||||||
| 			> .left |  | ||||||
| 				float left |  | ||||||
|  |  | ||||||
| 				> .name |  | ||||||
| 					display inline |  | ||||||
| 					margin 0 |  | ||||||
| 					padding 0 |  | ||||||
| 					color #777 |  | ||||||
| 					font-size 1em |  | ||||||
| 					font-weight 700 |  | ||||||
| 					text-align left |  | ||||||
| 					text-decoration none |  | ||||||
|  |  | ||||||
| 					&:hover |  | ||||||
| 						text-decoration underline |  | ||||||
|  |  | ||||||
| 				> .username |  | ||||||
| 					text-align left |  | ||||||
| 					margin 0 0 0 8px |  | ||||||
| 					color #ccc |  | ||||||
|  |  | ||||||
| 			> .right |  | ||||||
| 				float right |  | ||||||
|  |  | ||||||
| 				> .time |  | ||||||
| 					font-size 0.9em |  | ||||||
| 					color #c0c0c0 |  | ||||||
|  |  | ||||||
| </style> |  | ||||||
|  |  | ||||||
| <style lang="stylus" module> |  | ||||||
| .text |  | ||||||
| 	cursor default |  | ||||||
| 	display block |  | ||||||
| 	margin 0 |  | ||||||
| 	padding 0 |  | ||||||
| 	overflow-wrap break-word |  | ||||||
| 	font-size 1em |  | ||||||
| 	color #717171 |  | ||||||
| </style> |  | ||||||
| @@ -1,434 +0,0 @@ | |||||||
| <template> |  | ||||||
| <div class="mk-note-detail" :title="title"> |  | ||||||
| 	<button |  | ||||||
| 		class="read-more" |  | ||||||
| 		v-if="p.reply && p.reply.replyId && context == null" |  | ||||||
| 		title="会話をもっと読み込む" |  | ||||||
| 		@click="fetchContext" |  | ||||||
| 		:disabled="contextFetching" |  | ||||||
| 	> |  | ||||||
| 		<template v-if="!contextFetching">%fa:ellipsis-v%</template> |  | ||||||
| 		<template v-if="contextFetching">%fa:spinner .pulse%</template> |  | ||||||
| 	</button> |  | ||||||
| 	<div class="context"> |  | ||||||
| 		<x-sub v-for="note in context" :key="note.id" :note="note"/> |  | ||||||
| 	</div> |  | ||||||
| 	<div class="reply-to" v-if="p.reply"> |  | ||||||
| 		<x-sub :note="p.reply"/> |  | ||||||
| 	</div> |  | ||||||
| 	<div class="renote" v-if="isRenote"> |  | ||||||
| 		<p> |  | ||||||
| 			<router-link class="avatar-anchor" :to="note.user | userPage" v-user-preview="note.userId"> |  | ||||||
| 				<img class="avatar" :src="`${note.user.avatarUrl}?thumbnail&size=32`" alt="avatar"/> |  | ||||||
| 			</router-link> |  | ||||||
| 			%fa:retweet% |  | ||||||
| 			<router-link class="name" :href="note.user | userPage">{{ note.user | userName }}</router-link> |  | ||||||
| 			がRenote |  | ||||||
| 		</p> |  | ||||||
| 	</div> |  | ||||||
| 	<article> |  | ||||||
| 		<router-link class="avatar-anchor" :to="p.user | userPage"> |  | ||||||
| 			<img class="avatar" :src="`${p.user.avatarUrl}?thumbnail&size=64`" alt="avatar" v-user-preview="p.user.id"/> |  | ||||||
| 		</router-link> |  | ||||||
| 		<header> |  | ||||||
| 			<router-link class="name" :to="p.user | userPage" v-user-preview="p.user.id">{{ p.user | userName }}</router-link> |  | ||||||
| 			<span class="username">@{{ p.user | acct }}</span> |  | ||||||
| 			<router-link class="time" :to="p | notePage"> |  | ||||||
| 				<mk-time :time="p.createdAt"/> |  | ||||||
| 			</router-link> |  | ||||||
| 		</header> |  | ||||||
| 		<div class="body"> |  | ||||||
| 			<mk-note-html :class="$style.text" v-if="p.text" :text="p.text" :i="os.i"/> |  | ||||||
| 			<div class="media" v-if="p.media.length > 0"> |  | ||||||
| 				<mk-media-list :media-list="p.media"/> |  | ||||||
| 			</div> |  | ||||||
| 			<mk-poll v-if="p.poll" :note="p"/> |  | ||||||
| 			<mk-url-preview v-for="url in urls" :url="url" :key="url"/> |  | ||||||
| 			<div class="tags" v-if="p.tags && p.tags.length > 0"> |  | ||||||
| 				<router-link v-for="tag in p.tags" :key="tag" :to="`/search?q=#${tag}`">{{ tag }}</router-link> |  | ||||||
| 			</div> |  | ||||||
| 			<a class="location" v-if="p.geo" :href="`http://maps.google.com/maps?q=${p.geo.coordinates[1]},${p.geo.coordinates[0]}`" target="_blank">%fa:map-marker-alt% 位置情報</a> |  | ||||||
| 			<div class="map" v-if="p.geo" ref="map"></div> |  | ||||||
| 			<div class="renote" v-if="p.renote"> |  | ||||||
| 				<mk-note-preview :note="p.renote"/> |  | ||||||
| 			</div> |  | ||||||
| 		</div> |  | ||||||
| 		<footer> |  | ||||||
| 			<mk-reactions-viewer :note="p"/> |  | ||||||
| 			<button @click="reply" title="返信"> |  | ||||||
| 				%fa:reply%<p class="count" v-if="p.repliesCount > 0">{{ p.repliesCount }}</p> |  | ||||||
| 			</button> |  | ||||||
| 			<button @click="renote" title="Renote"> |  | ||||||
| 				%fa:retweet%<p class="count" v-if="p.renoteCount > 0">{{ p.renoteCount }}</p> |  | ||||||
| 			</button> |  | ||||||
| 			<button :class="{ reacted: p.myReaction != 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"> |  | ||||||
| 		<x-sub v-for="note in replies" :key="note.id" :note="note"/> |  | ||||||
| 	</div> |  | ||||||
| </div> |  | ||||||
| </template> |  | ||||||
|  |  | ||||||
| <script lang="ts"> |  | ||||||
| import Vue from 'vue'; |  | ||||||
| import dateStringify from '../../../common/scripts/date-stringify'; |  | ||||||
| import parse from '../../../../../text/parse'; |  | ||||||
|  |  | ||||||
| import MkPostFormWindow from './post-form-window.vue'; |  | ||||||
| import MkRenoteFormWindow from './renote-form-window.vue'; |  | ||||||
| import MkNoteMenu from '../../../common/views/components/note-menu.vue'; |  | ||||||
| import MkReactionPicker from '../../../common/views/components/reaction-picker.vue'; |  | ||||||
| import XSub from './note-detail.sub.vue'; |  | ||||||
|  |  | ||||||
| export default Vue.extend({ |  | ||||||
| 	components: { |  | ||||||
| 		XSub |  | ||||||
| 	}, |  | ||||||
|  |  | ||||||
| 	props: { |  | ||||||
| 		note: { |  | ||||||
| 			type: Object, |  | ||||||
| 			required: true |  | ||||||
| 		}, |  | ||||||
| 		compact: { |  | ||||||
| 			default: false |  | ||||||
| 		} |  | ||||||
| 	}, |  | ||||||
|  |  | ||||||
| 	data() { |  | ||||||
| 		return { |  | ||||||
| 			context: [], |  | ||||||
| 			contextFetching: false, |  | ||||||
| 			replies: [] |  | ||||||
| 		}; |  | ||||||
| 	}, |  | ||||||
|  |  | ||||||
| 	computed: { |  | ||||||
| 		isRenote(): boolean { |  | ||||||
| 			return (this.note.renote && |  | ||||||
| 				this.note.text == null && |  | ||||||
| 				this.note.mediaIds.length == 0 && |  | ||||||
| 				this.note.poll == null); |  | ||||||
| 		}, |  | ||||||
| 		p(): any { |  | ||||||
| 			return this.isRenote ? this.note.renote : this.note; |  | ||||||
| 		}, |  | ||||||
| 		reactionsCount(): number { |  | ||||||
| 			return this.p.reactionCounts |  | ||||||
| 				? Object.keys(this.p.reactionCounts) |  | ||||||
| 					.map(key => this.p.reactionCounts[key]) |  | ||||||
| 					.reduce((a, b) => a + b) |  | ||||||
| 				: 0; |  | ||||||
| 		}, |  | ||||||
| 		title(): string { |  | ||||||
| 			return dateStringify(this.p.createdAt); |  | ||||||
| 		}, |  | ||||||
| 		urls(): string[] { |  | ||||||
| 			if (this.p.text) { |  | ||||||
| 				const ast = parse(this.p.text); |  | ||||||
| 				return 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 as any).api('notes/replies', { |  | ||||||
| 				noteId: this.p.id, |  | ||||||
| 				limit: 8 |  | ||||||
| 			}).then(replies => { |  | ||||||
| 				this.replies = replies; |  | ||||||
| 			}); |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		// Draw map |  | ||||||
| 		if (this.p.geo) { |  | ||||||
| 			const shouldShowMap = (this as any).os.isSignedIn ? (this as any).os.i.clientSettings.showMaps : true; |  | ||||||
| 			if (shouldShowMap) { |  | ||||||
| 				(this as any).os.getGoogleMaps().then(maps => { |  | ||||||
| 					const uluru = new maps.LatLng(this.p.geo.coordinates[1], this.p.geo.coordinates[0]); |  | ||||||
| 					const map = new maps.Map(this.$refs.map, { |  | ||||||
| 						center: uluru, |  | ||||||
| 						zoom: 15 |  | ||||||
| 					}); |  | ||||||
| 					new maps.Marker({ |  | ||||||
| 						position: uluru, |  | ||||||
| 						map: map |  | ||||||
| 					}); |  | ||||||
| 				}); |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 	}, |  | ||||||
|  |  | ||||||
| 	methods: { |  | ||||||
| 		fetchContext() { |  | ||||||
| 			this.contextFetching = true; |  | ||||||
|  |  | ||||||
| 			// Fetch context |  | ||||||
| 			(this as any).api('notes/context', { |  | ||||||
| 				noteId: this.p.replyId |  | ||||||
| 			}).then(context => { |  | ||||||
| 				this.contextFetching = false; |  | ||||||
| 				this.context = context.reverse(); |  | ||||||
| 			}); |  | ||||||
| 		}, |  | ||||||
| 		reply() { |  | ||||||
| 			(this as any).os.new(MkPostFormWindow, { |  | ||||||
| 				reply: this.p |  | ||||||
| 			}); |  | ||||||
| 		}, |  | ||||||
| 		renote() { |  | ||||||
| 			(this as any).os.new(MkRenoteFormWindow, { |  | ||||||
| 				note: this.p |  | ||||||
| 			}); |  | ||||||
| 		}, |  | ||||||
| 		react() { |  | ||||||
| 			(this as any).os.new(MkReactionPicker, { |  | ||||||
| 				source: this.$refs.reactButton, |  | ||||||
| 				note: this.p |  | ||||||
| 			}); |  | ||||||
| 		}, |  | ||||||
| 		menu() { |  | ||||||
| 			(this as any).os.new(MkNoteMenu, { |  | ||||||
| 				source: this.$refs.menuButton, |  | ||||||
| 				note: this.p |  | ||||||
| 			}); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| }); |  | ||||||
| </script> |  | ||||||
|  |  | ||||||
| <style lang="stylus" scoped> |  | ||||||
| @import '~const.styl' |  | ||||||
|  |  | ||||||
| .mk-note-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 |  | ||||||
|  |  | ||||||
| 	> .renote |  | ||||||
| 		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 |  | ||||||
|  |  | ||||||
| 			> .renote |  | ||||||
| 				margin 8px 0 |  | ||||||
|  |  | ||||||
| 				> .mk-note-preview |  | ||||||
| 					padding 16px |  | ||||||
| 					border dashed 1px #c0dac6 |  | ||||||
| 					border-radius 8px |  | ||||||
|  |  | ||||||
| 			> .location |  | ||||||
| 				margin 4px 0 |  | ||||||
| 				font-size 12px |  | ||||||
| 				color #ccc |  | ||||||
|  |  | ||||||
| 			> .map |  | ||||||
| 				width 100% |  | ||||||
| 				height 300px |  | ||||||
|  |  | ||||||
| 				&:empty |  | ||||||
| 					display none |  | ||||||
|  |  | ||||||
| 			> .mk-url-preview |  | ||||||
| 				margin-top 8px |  | ||||||
|  |  | ||||||
| 			> .tags |  | ||||||
| 				margin 4px 0 0 0 |  | ||||||
|  |  | ||||||
| 				> * |  | ||||||
| 					display inline-block |  | ||||||
| 					margin 0 8px 0 0 |  | ||||||
| 					padding 2px 8px 2px 16px |  | ||||||
| 					font-size 90% |  | ||||||
| 					color #8d969e |  | ||||||
| 					background #edf0f3 |  | ||||||
| 					border-radius 4px |  | ||||||
|  |  | ||||||
| 					&:before |  | ||||||
| 						content "" |  | ||||||
| 						display block |  | ||||||
| 						position absolute |  | ||||||
| 						top 0 |  | ||||||
| 						bottom 0 |  | ||||||
| 						left 4px |  | ||||||
| 						width 8px |  | ||||||
| 						height 8px |  | ||||||
| 						margin auto 0 |  | ||||||
| 						background #fff |  | ||||||
| 						border-radius 100% |  | ||||||
|  |  | ||||||
| 					&:hover |  | ||||||
| 						text-decoration none |  | ||||||
| 						background #e2e7ec |  | ||||||
|  |  | ||||||
| 		> 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> |  | ||||||
|  |  | ||||||
| <style lang="stylus" module> |  | ||||||
| .text |  | ||||||
| 	cursor default |  | ||||||
| 	display block |  | ||||||
| 	margin 0 |  | ||||||
| 	padding 0 |  | ||||||
| 	overflow-wrap break-word |  | ||||||
| 	font-size 1.5em |  | ||||||
| 	color #717171 |  | ||||||
| </style> |  | ||||||
| @@ -1,99 +0,0 @@ | |||||||
| <template> |  | ||||||
| <div class="mk-note-preview" :title="title"> |  | ||||||
| 	<router-link class="avatar-anchor" :to="note.user | userPage"> |  | ||||||
| 		<img class="avatar" :src="`${note.user.avatarUrl}?thumbnail&size=64`" alt="avatar" v-user-preview="note.userId"/> |  | ||||||
| 	</router-link> |  | ||||||
| 	<div class="main"> |  | ||||||
| 		<header> |  | ||||||
| 			<router-link class="name" :to="note.user | userPage" v-user-preview="note.userId">{{ note.user | userName }}</router-link> |  | ||||||
| 			<span class="username">@{{ note.user | acct }}</span> |  | ||||||
| 			<router-link class="time" :to="note | notePage"> |  | ||||||
| 				<mk-time :time="note.createdAt"/> |  | ||||||
| 			</router-link> |  | ||||||
| 		</header> |  | ||||||
| 		<div class="body"> |  | ||||||
| 			<mk-sub-note-content class="text" :note="note"/> |  | ||||||
| 		</div> |  | ||||||
| 	</div> |  | ||||||
| </div> |  | ||||||
| </template> |  | ||||||
|  |  | ||||||
| <script lang="ts"> |  | ||||||
| import Vue from 'vue'; |  | ||||||
| import dateStringify from '../../../common/scripts/date-stringify'; |  | ||||||
|  |  | ||||||
| export default Vue.extend({ |  | ||||||
| 	props: ['note'], |  | ||||||
| 	computed: { |  | ||||||
| 		title(): string { |  | ||||||
| 			return dateStringify(this.note.createdAt); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| }); |  | ||||||
| </script> |  | ||||||
|  |  | ||||||
| <style lang="stylus" scoped> |  | ||||||
| .mk-note-preview |  | ||||||
| 	font-size 0.9em |  | ||||||
| 	background #fff |  | ||||||
|  |  | ||||||
| 	&:after |  | ||||||
| 		content "" |  | ||||||
| 		display block |  | ||||||
| 		clear both |  | ||||||
|  |  | ||||||
| 	&:hover |  | ||||||
| 		> .main > footer > button |  | ||||||
| 			color #888 |  | ||||||
|  |  | ||||||
| 	> .avatar-anchor |  | ||||||
| 		display block |  | ||||||
| 		float left |  | ||||||
| 		margin 0 16px 0 0 |  | ||||||
|  |  | ||||||
| 		> .avatar |  | ||||||
| 			display block |  | ||||||
| 			width 52px |  | ||||||
| 			height 52px |  | ||||||
| 			margin 0 |  | ||||||
| 			border-radius 8px |  | ||||||
| 			vertical-align bottom |  | ||||||
|  |  | ||||||
| 	> .main |  | ||||||
| 		float left |  | ||||||
| 		width calc(100% - 68px) |  | ||||||
|  |  | ||||||
| 		> header |  | ||||||
| 			display flex |  | ||||||
| 			white-space nowrap |  | ||||||
|  |  | ||||||
| 			> .name |  | ||||||
| 				margin 0 .5em 0 0 |  | ||||||
| 				padding 0 |  | ||||||
| 				color #607073 |  | ||||||
| 				font-size 1em |  | ||||||
| 				font-weight bold |  | ||||||
| 				text-decoration none |  | ||||||
| 				white-space normal |  | ||||||
|  |  | ||||||
| 				&:hover |  | ||||||
| 					text-decoration underline |  | ||||||
|  |  | ||||||
| 			> .username |  | ||||||
| 				margin 0 .5em 0 0 |  | ||||||
| 				color #d1d8da |  | ||||||
|  |  | ||||||
| 			> .time |  | ||||||
| 				margin-left auto |  | ||||||
| 				color #b2b8bb |  | ||||||
|  |  | ||||||
| 		> .body |  | ||||||
|  |  | ||||||
| 			> .text |  | ||||||
| 				cursor default |  | ||||||
| 				margin 0 |  | ||||||
| 				padding 0 |  | ||||||
| 				font-size 1.1em |  | ||||||
| 				color #717171 |  | ||||||
|  |  | ||||||
| </style> |  | ||||||
| @@ -1,108 +0,0 @@ | |||||||
| <template> |  | ||||||
| <div class="sub" :title="title"> |  | ||||||
| 	<router-link class="avatar-anchor" :to="note.user | userPage"> |  | ||||||
| 		<img class="avatar" :src="`${note.user.avatarUrl}?thumbnail&size=64`" alt="avatar" v-user-preview="note.userId"/> |  | ||||||
| 	</router-link> |  | ||||||
| 	<div class="main"> |  | ||||||
| 		<header> |  | ||||||
| 			<router-link class="name" :to="note.user | userPage" v-user-preview="note.userId">{{ note.user | userName }}</router-link> |  | ||||||
| 			<span class="username">@{{ note.user | acct }}</span> |  | ||||||
| 			<router-link class="created-at" :to="note | notePage"> |  | ||||||
| 				<mk-time :time="note.createdAt"/> |  | ||||||
| 			</router-link> |  | ||||||
| 		</header> |  | ||||||
| 		<div class="body"> |  | ||||||
| 			<mk-sub-note-content class="text" :note="note"/> |  | ||||||
| 		</div> |  | ||||||
| 	</div> |  | ||||||
| </div> |  | ||||||
| </template> |  | ||||||
|  |  | ||||||
| <script lang="ts"> |  | ||||||
| import Vue from 'vue'; |  | ||||||
| import dateStringify from '../../../common/scripts/date-stringify'; |  | ||||||
|  |  | ||||||
| export default Vue.extend({ |  | ||||||
| 	props: ['note'], |  | ||||||
| 	computed: { |  | ||||||
| 		title(): string { |  | ||||||
| 			return dateStringify(this.note.createdAt); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| }); |  | ||||||
| </script> |  | ||||||
|  |  | ||||||
| <style lang="stylus" scoped> |  | ||||||
| .sub |  | ||||||
| 	margin 0 |  | ||||||
| 	padding 16px |  | ||||||
| 	font-size 0.9em |  | ||||||
|  |  | ||||||
| 	&:after |  | ||||||
| 		content "" |  | ||||||
| 		display block |  | ||||||
| 		clear both |  | ||||||
|  |  | ||||||
| 	&:hover |  | ||||||
| 		> .main > footer > button |  | ||||||
| 			color #888 |  | ||||||
|  |  | ||||||
| 	> .avatar-anchor |  | ||||||
| 		display block |  | ||||||
| 		float left |  | ||||||
| 		margin 0 14px 0 0 |  | ||||||
|  |  | ||||||
| 		> .avatar |  | ||||||
| 			display block |  | ||||||
| 			width 52px |  | ||||||
| 			height 52px |  | ||||||
| 			margin 0 |  | ||||||
| 			border-radius 8px |  | ||||||
| 			vertical-align bottom |  | ||||||
|  |  | ||||||
| 	> .main |  | ||||||
| 		float left |  | ||||||
| 		width calc(100% - 66px) |  | ||||||
|  |  | ||||||
| 		> header |  | ||||||
| 			display flex |  | ||||||
| 			margin-bottom 2px |  | ||||||
| 			white-space nowrap |  | ||||||
| 			line-height 21px |  | ||||||
|  |  | ||||||
| 			> .name |  | ||||||
| 				display block |  | ||||||
| 				margin 0 .5em 0 0 |  | ||||||
| 				padding 0 |  | ||||||
| 				overflow hidden |  | ||||||
| 				color #607073 |  | ||||||
| 				font-size 1em |  | ||||||
| 				font-weight bold |  | ||||||
| 				text-decoration none |  | ||||||
| 				text-overflow ellipsis |  | ||||||
|  |  | ||||||
| 				&:hover |  | ||||||
| 					text-decoration underline |  | ||||||
|  |  | ||||||
| 			> .username |  | ||||||
| 				margin 0 .5em 0 0 |  | ||||||
| 				color #d1d8da |  | ||||||
|  |  | ||||||
| 			> .created-at |  | ||||||
| 				margin-left auto |  | ||||||
| 				color #b2b8bb |  | ||||||
|  |  | ||||||
| 		> .body |  | ||||||
|  |  | ||||||
| 			> .text |  | ||||||
| 				cursor default |  | ||||||
| 				margin 0 |  | ||||||
| 				padding 0 |  | ||||||
| 				font-size 1.1em |  | ||||||
| 				color #717171 |  | ||||||
|  |  | ||||||
| 				pre |  | ||||||
| 					max-height 120px |  | ||||||
| 					font-size 80% |  | ||||||
|  |  | ||||||
| </style> |  | ||||||
| @@ -1,585 +0,0 @@ | |||||||
| <template> |  | ||||||
| <div class="note" tabindex="-1" :title="title" @keydown="onKeydown"> |  | ||||||
| 	<div class="reply-to" v-if="p.reply"> |  | ||||||
| 		<x-sub :note="p.reply"/> |  | ||||||
| 	</div> |  | ||||||
| 	<div class="renote" v-if="isRenote"> |  | ||||||
| 		<p> |  | ||||||
| 			<router-link class="avatar-anchor" :to="note.user | userPage" v-user-preview="note.userId"> |  | ||||||
| 				<img class="avatar" :src="`${note.user.avatarUrl}?thumbnail&size=32`" alt="avatar"/> |  | ||||||
| 			</router-link> |  | ||||||
| 			%fa:retweet% |  | ||||||
| 			<span>{{ '%i18n:desktop.tags.mk-timeline-note.reposted-by%'.substr(0, '%i18n:desktop.tags.mk-timeline-note.reposted-by%'.indexOf('{')) }}</span> |  | ||||||
| 			<a class="name" :href="note.user | userPage" v-user-preview="note.userId">{{ note.user | userName }}</a> |  | ||||||
| 			<span>{{ '%i18n:desktop.tags.mk-timeline-note.reposted-by%'.substr('%i18n:desktop.tags.mk-timeline-note.reposted-by%'.indexOf('}') + 1) }}</span> |  | ||||||
| 		</p> |  | ||||||
| 		<mk-time :time="note.createdAt"/> |  | ||||||
| 	</div> |  | ||||||
| 	<article> |  | ||||||
| 		<router-link class="avatar-anchor" :to="p.user | userPage"> |  | ||||||
| 			<img class="avatar" :src="`${p.user.avatarUrl}?thumbnail&size=64`" alt="avatar" v-user-preview="p.user.id"/> |  | ||||||
| 		</router-link> |  | ||||||
| 		<div class="main"> |  | ||||||
| 			<header> |  | ||||||
| 				<router-link class="name" :to="p.user | userPage" v-user-preview="p.user.id">{{ p.user | userName }}</router-link> |  | ||||||
| 				<span class="is-bot" v-if="p.user.host === null && p.user.isBot">bot</span> |  | ||||||
| 				<span class="username">@{{ p.user | acct }}</span> |  | ||||||
| 				<div class="info"> |  | ||||||
| 					<span class="app" v-if="p.app">via <b>{{ p.app.name }}</b></span> |  | ||||||
| 					<span class="mobile" v-if="p.viaMobile">%fa:mobile-alt%</span> |  | ||||||
| 					<router-link class="created-at" :to="url"> |  | ||||||
| 						<mk-time :time="p.createdAt"/> |  | ||||||
| 					</router-link> |  | ||||||
| 				</div> |  | ||||||
| 			</header> |  | ||||||
| 			<div class="body"> |  | ||||||
| 				<p class="channel" v-if="p.channel"> |  | ||||||
| 					<a :href="`${_CH_URL_}/${p.channel.id}`" target="_blank">{{ p.channel.title }}</a>: |  | ||||||
| 				</p> |  | ||||||
| 				<div class="text"> |  | ||||||
| 					<a class="reply" v-if="p.reply">%fa:reply%</a> |  | ||||||
| 					<mk-note-html v-if="p.textHtml" :text="p.text" :i="os.i" :class="$style.text"/> |  | ||||||
| 					<a class="rp" v-if="p.renote">RP:</a> |  | ||||||
| 				</div> |  | ||||||
| 				<div class="media" v-if="p.media.length > 0"> |  | ||||||
| 					<mk-media-list :media-list="p.media"/> |  | ||||||
| 				</div> |  | ||||||
| 				<mk-poll v-if="p.poll" :note="p" ref="pollViewer"/> |  | ||||||
| 				<div class="tags" v-if="p.tags && p.tags.length > 0"> |  | ||||||
| 					<router-link v-for="tag in p.tags" :key="tag" :to="`/search?q=#${tag}`">{{ tag }}</router-link> |  | ||||||
| 				</div> |  | ||||||
| 				<a class="location" v-if="p.geo" :href="`http://maps.google.com/maps?q=${p.geo.coordinates[1]},${p.geo.coordinates[0]}`" target="_blank">%fa:map-marker-alt% 位置情報</a> |  | ||||||
| 				<div class="map" v-if="p.geo" ref="map"></div> |  | ||||||
| 				<div class="renote" v-if="p.renote"> |  | ||||||
| 					<mk-note-preview :note="p.renote"/> |  | ||||||
| 				</div> |  | ||||||
| 				<mk-url-preview v-for="url in urls" :url="url" :key="url"/> |  | ||||||
| 			</div> |  | ||||||
| 			<footer> |  | ||||||
| 				<mk-reactions-viewer :note="p" ref="reactionsViewer"/> |  | ||||||
| 				<button @click="reply" title="%i18n:desktop.tags.mk-timeline-note.reply%"> |  | ||||||
| 					%fa:reply%<p class="count" v-if="p.repliesCount > 0">{{ p.repliesCount }}</p> |  | ||||||
| 				</button> |  | ||||||
| 				<button @click="renote" title="%i18n:desktop.tags.mk-timeline-note.renote%"> |  | ||||||
| 					%fa:retweet%<p class="count" v-if="p.renoteCount > 0">{{ p.renoteCount }}</p> |  | ||||||
| 				</button> |  | ||||||
| 				<button :class="{ reacted: p.myReaction != null }" @click="react" ref="reactButton" title="%i18n:desktop.tags.mk-timeline-note.add-reaction%"> |  | ||||||
| 					%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> |  | ||||||
| 				<button title="%i18n:desktop.tags.mk-timeline-note.detail"> |  | ||||||
| 					<template v-if="!isDetailOpened">%fa:caret-down%</template> |  | ||||||
| 					<template v-if="isDetailOpened">%fa:caret-up%</template> |  | ||||||
| 				</button> |  | ||||||
| 			</footer> |  | ||||||
| 		</div> |  | ||||||
| 	</article> |  | ||||||
| 	<div class="detail" v-if="isDetailOpened"> |  | ||||||
| 		<mk-note-status-graph width="462" height="130" :note="p"/> |  | ||||||
| 	</div> |  | ||||||
| </div> |  | ||||||
| </template> |  | ||||||
|  |  | ||||||
| <script lang="ts"> |  | ||||||
| import Vue from 'vue'; |  | ||||||
| import dateStringify from '../../../common/scripts/date-stringify'; |  | ||||||
| import parse from '../../../../../text/parse'; |  | ||||||
|  |  | ||||||
| import MkPostFormWindow from './post-form-window.vue'; |  | ||||||
| import MkRenoteFormWindow from './renote-form-window.vue'; |  | ||||||
| import MkNoteMenu from '../../../common/views/components/note-menu.vue'; |  | ||||||
| import MkReactionPicker from '../../../common/views/components/reaction-picker.vue'; |  | ||||||
| import XSub from './notes.note.sub.vue'; |  | ||||||
|  |  | ||||||
| function focus(el, fn) { |  | ||||||
| 	const target = fn(el); |  | ||||||
| 	if (target) { |  | ||||||
| 		if (target.hasAttribute('tabindex')) { |  | ||||||
| 			target.focus(); |  | ||||||
| 		} else { |  | ||||||
| 			focus(target, fn); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export default Vue.extend({ |  | ||||||
| 	components: { |  | ||||||
| 		XSub |  | ||||||
| 	}, |  | ||||||
|  |  | ||||||
| 	props: ['note'], |  | ||||||
|  |  | ||||||
| 	data() { |  | ||||||
| 		return { |  | ||||||
| 			isDetailOpened: false, |  | ||||||
| 			connection: null, |  | ||||||
| 			connectionId: null |  | ||||||
| 		}; |  | ||||||
| 	}, |  | ||||||
|  |  | ||||||
| 	computed: { |  | ||||||
| 		isRenote(): boolean { |  | ||||||
| 			return (this.note.renote && |  | ||||||
| 				this.note.text == null && |  | ||||||
| 				this.note.mediaIds.length == 0 && |  | ||||||
| 				this.note.poll == null); |  | ||||||
| 		}, |  | ||||||
| 		p(): any { |  | ||||||
| 			return this.isRenote ? this.note.renote : this.note; |  | ||||||
| 		}, |  | ||||||
| 		reactionsCount(): number { |  | ||||||
| 			return this.p.reactionCounts |  | ||||||
| 				? Object.keys(this.p.reactionCounts) |  | ||||||
| 					.map(key => this.p.reactionCounts[key]) |  | ||||||
| 					.reduce((a, b) => a + b) |  | ||||||
| 				: 0; |  | ||||||
| 		}, |  | ||||||
| 		title(): string { |  | ||||||
| 			return dateStringify(this.p.createdAt); |  | ||||||
| 		}, |  | ||||||
| 		urls(): string[] { |  | ||||||
| 			if (this.p.text) { |  | ||||||
| 				const ast = parse(this.p.text); |  | ||||||
| 				return ast |  | ||||||
| 					.filter(t => (t.type == 'url' || t.type == 'link') && !t.silent) |  | ||||||
| 					.map(t => t.url); |  | ||||||
| 			} else { |  | ||||||
| 				return null; |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 	}, |  | ||||||
|  |  | ||||||
| 	created() { |  | ||||||
| 		if ((this as any).os.isSignedIn) { |  | ||||||
| 			this.connection = (this as any).os.stream.getConnection(); |  | ||||||
| 			this.connectionId = (this as any).os.stream.use(); |  | ||||||
| 		} |  | ||||||
| 	}, |  | ||||||
|  |  | ||||||
| 	mounted() { |  | ||||||
| 		this.capture(true); |  | ||||||
|  |  | ||||||
| 		if ((this as any).os.isSignedIn) { |  | ||||||
| 			this.connection.on('_connected_', this.onStreamConnected); |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		// Draw map |  | ||||||
| 		if (this.p.geo) { |  | ||||||
| 			const shouldShowMap = (this as any).os.isSignedIn ? (this as any).os.i.clientSettings.showMaps : true; |  | ||||||
| 			if (shouldShowMap) { |  | ||||||
| 				(this as any).os.getGoogleMaps().then(maps => { |  | ||||||
| 					const uluru = new maps.LatLng(this.p.geo.coordinates[1], this.p.geo.coordinates[0]); |  | ||||||
| 					const map = new maps.Map(this.$refs.map, { |  | ||||||
| 						center: uluru, |  | ||||||
| 						zoom: 15 |  | ||||||
| 					}); |  | ||||||
| 					new maps.Marker({ |  | ||||||
| 						position: uluru, |  | ||||||
| 						map: map |  | ||||||
| 					}); |  | ||||||
| 				}); |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 	}, |  | ||||||
|  |  | ||||||
| 	beforeDestroy() { |  | ||||||
| 		this.decapture(true); |  | ||||||
|  |  | ||||||
| 		if ((this as any).os.isSignedIn) { |  | ||||||
| 			this.connection.off('_connected_', this.onStreamConnected); |  | ||||||
| 			(this as any).os.stream.dispose(this.connectionId); |  | ||||||
| 		} |  | ||||||
| 	}, |  | ||||||
|  |  | ||||||
| 	methods: { |  | ||||||
| 		capture(withHandler = false) { |  | ||||||
| 			if ((this as any).os.isSignedIn) { |  | ||||||
| 				this.connection.send({ |  | ||||||
| 					type: 'capture', |  | ||||||
| 					id: this.p.id |  | ||||||
| 				}); |  | ||||||
| 				if (withHandler) this.connection.on('note-updated', this.onStreamNoteUpdated); |  | ||||||
| 			} |  | ||||||
| 		}, |  | ||||||
| 		decapture(withHandler = false) { |  | ||||||
| 			if ((this as any).os.isSignedIn) { |  | ||||||
| 				this.connection.send({ |  | ||||||
| 					type: 'decapture', |  | ||||||
| 					id: this.p.id |  | ||||||
| 				}); |  | ||||||
| 				if (withHandler) this.connection.off('note-updated', this.onStreamNoteUpdated); |  | ||||||
| 			} |  | ||||||
| 		}, |  | ||||||
| 		onStreamConnected() { |  | ||||||
| 			this.capture(); |  | ||||||
| 		}, |  | ||||||
| 		onStreamNoteUpdated(data) { |  | ||||||
| 			const note = data.note; |  | ||||||
| 			if (note.id == this.note.id) { |  | ||||||
| 				this.$emit('update:note', note); |  | ||||||
| 			} else if (note.id == this.note.renoteId) { |  | ||||||
| 				this.note.renote = note; |  | ||||||
| 			} |  | ||||||
| 		}, |  | ||||||
| 		reply() { |  | ||||||
| 			(this as any).os.new(MkPostFormWindow, { |  | ||||||
| 				reply: this.p |  | ||||||
| 			}); |  | ||||||
| 		}, |  | ||||||
| 		renote() { |  | ||||||
| 			(this as any).os.new(MkRenoteFormWindow, { |  | ||||||
| 				note: this.p |  | ||||||
| 			}); |  | ||||||
| 		}, |  | ||||||
| 		react() { |  | ||||||
| 			(this as any).os.new(MkReactionPicker, { |  | ||||||
| 				source: this.$refs.reactButton, |  | ||||||
| 				note: this.p |  | ||||||
| 			}); |  | ||||||
| 		}, |  | ||||||
| 		menu() { |  | ||||||
| 			(this as any).os.new(MkNoteMenu, { |  | ||||||
| 				source: this.$refs.menuButton, |  | ||||||
| 				note: this.p |  | ||||||
| 			}); |  | ||||||
| 		}, |  | ||||||
| 		onKeydown(e) { |  | ||||||
| 			let shouldBeCancel = true; |  | ||||||
|  |  | ||||||
| 			switch (true) { |  | ||||||
| 				case e.which == 38: // [↑] |  | ||||||
| 				case e.which == 74: // [j] |  | ||||||
| 				case e.which == 9 && e.shiftKey: // [Shift] + [Tab] |  | ||||||
| 					focus(this.$el, e => e.previousElementSibling); |  | ||||||
| 					break; |  | ||||||
|  |  | ||||||
| 				case e.which == 40: // [↓] |  | ||||||
| 				case e.which == 75: // [k] |  | ||||||
| 				case e.which == 9: // [Tab] |  | ||||||
| 					focus(this.$el, e => e.nextElementSibling); |  | ||||||
| 					break; |  | ||||||
|  |  | ||||||
| 				case e.which == 81: // [q] |  | ||||||
| 				case e.which == 69: // [e] |  | ||||||
| 					this.renote(); |  | ||||||
| 					break; |  | ||||||
|  |  | ||||||
| 				case e.which == 70: // [f] |  | ||||||
| 				case e.which == 76: // [l] |  | ||||||
| 					//this.like(); |  | ||||||
| 					break; |  | ||||||
|  |  | ||||||
| 				case e.which == 82: // [r] |  | ||||||
| 					this.reply(); |  | ||||||
| 					break; |  | ||||||
|  |  | ||||||
| 				default: |  | ||||||
| 					shouldBeCancel = false; |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			if (shouldBeCancel) e.preventDefault(); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| }); |  | ||||||
| </script> |  | ||||||
|  |  | ||||||
| <style lang="stylus" scoped> |  | ||||||
| @import '~const.styl' |  | ||||||
|  |  | ||||||
| .note |  | ||||||
| 	margin 0 |  | ||||||
| 	padding 0 |  | ||||||
| 	background #fff |  | ||||||
| 	border-bottom solid 1px #eaeaea |  | ||||||
|  |  | ||||||
| 	&:first-child |  | ||||||
| 		border-top-left-radius 6px |  | ||||||
| 		border-top-right-radius 6px |  | ||||||
|  |  | ||||||
| 		> .renote |  | ||||||
| 			border-top-left-radius 6px |  | ||||||
| 			border-top-right-radius 6px |  | ||||||
|  |  | ||||||
| 	&:last-of-type |  | ||||||
| 		border-bottom none |  | ||||||
|  |  | ||||||
| 	&:focus |  | ||||||
| 		z-index 1 |  | ||||||
|  |  | ||||||
| 		&:after |  | ||||||
| 			content "" |  | ||||||
| 			pointer-events none |  | ||||||
| 			position absolute |  | ||||||
| 			top 2px |  | ||||||
| 			right 2px |  | ||||||
| 			bottom 2px |  | ||||||
| 			left 2px |  | ||||||
| 			border 2px solid rgba($theme-color, 0.3) |  | ||||||
| 			border-radius 4px |  | ||||||
|  |  | ||||||
| 	> .renote |  | ||||||
| 		color #9dbb00 |  | ||||||
| 		background linear-gradient(to bottom, #edfde2 0%, #fff 100%) |  | ||||||
|  |  | ||||||
| 		> p |  | ||||||
| 			margin 0 |  | ||||||
| 			padding 16px 32px |  | ||||||
| 			line-height 28px |  | ||||||
|  |  | ||||||
| 			.avatar-anchor |  | ||||||
| 				display inline-block |  | ||||||
|  |  | ||||||
| 				.avatar |  | ||||||
| 					vertical-align bottom |  | ||||||
| 					width 28px |  | ||||||
| 					height 28px |  | ||||||
| 					margin 0 8px 0 0 |  | ||||||
| 					border-radius 6px |  | ||||||
|  |  | ||||||
| 			[data-fa] |  | ||||||
| 				margin-right 4px |  | ||||||
|  |  | ||||||
| 			.name |  | ||||||
| 				font-weight bold |  | ||||||
|  |  | ||||||
| 		> .mk-time |  | ||||||
| 			position absolute |  | ||||||
| 			top 16px |  | ||||||
| 			right 32px |  | ||||||
| 			font-size 0.9em |  | ||||||
| 			line-height 28px |  | ||||||
|  |  | ||||||
| 		& + article |  | ||||||
| 			padding-top 8px |  | ||||||
|  |  | ||||||
| 	> .reply-to |  | ||||||
| 		padding 0 16px |  | ||||||
| 		background rgba(0, 0, 0, 0.0125) |  | ||||||
|  |  | ||||||
| 		> .mk-note-preview |  | ||||||
| 			background transparent |  | ||||||
|  |  | ||||||
| 	> article |  | ||||||
| 		padding 28px 32px 18px 32px |  | ||||||
|  |  | ||||||
| 		&:after |  | ||||||
| 			content "" |  | ||||||
| 			display block |  | ||||||
| 			clear both |  | ||||||
|  |  | ||||||
| 		&:hover |  | ||||||
| 			> .main > footer > button |  | ||||||
| 				color #888 |  | ||||||
|  |  | ||||||
| 		> .avatar-anchor |  | ||||||
| 			display block |  | ||||||
| 			float left |  | ||||||
| 			margin 0 16px 10px 0 |  | ||||||
| 			//position -webkit-sticky |  | ||||||
| 			//position sticky |  | ||||||
| 			//top 74px |  | ||||||
|  |  | ||||||
| 			> .avatar |  | ||||||
| 				display block |  | ||||||
| 				width 58px |  | ||||||
| 				height 58px |  | ||||||
| 				margin 0 |  | ||||||
| 				border-radius 8px |  | ||||||
| 				vertical-align bottom |  | ||||||
|  |  | ||||||
| 		> .main |  | ||||||
| 			float left |  | ||||||
| 			width calc(100% - 74px) |  | ||||||
|  |  | ||||||
| 			> header |  | ||||||
| 				display flex |  | ||||||
| 				align-items center |  | ||||||
| 				margin-bottom 4px |  | ||||||
| 				white-space nowrap |  | ||||||
|  |  | ||||||
| 				> .name |  | ||||||
| 					display block |  | ||||||
| 					margin 0 .5em 0 0 |  | ||||||
| 					padding 0 |  | ||||||
| 					overflow hidden |  | ||||||
| 					color #627079 |  | ||||||
| 					font-size 1em |  | ||||||
| 					font-weight bold |  | ||||||
| 					text-decoration none |  | ||||||
| 					text-overflow ellipsis |  | ||||||
|  |  | ||||||
| 					&:hover |  | ||||||
| 						text-decoration underline |  | ||||||
|  |  | ||||||
| 				> .is-bot |  | ||||||
| 					margin 0 .5em 0 0 |  | ||||||
| 					padding 1px 6px |  | ||||||
| 					font-size 12px |  | ||||||
| 					color #aaa |  | ||||||
| 					border solid 1px #ddd |  | ||||||
| 					border-radius 3px |  | ||||||
|  |  | ||||||
| 				> .username |  | ||||||
| 					margin 0 .5em 0 0 |  | ||||||
| 					color #ccc |  | ||||||
|  |  | ||||||
| 				> .info |  | ||||||
| 					margin-left auto |  | ||||||
| 					font-size 0.9em |  | ||||||
|  |  | ||||||
| 					> .mobile |  | ||||||
| 						margin-right 8px |  | ||||||
| 						color #ccc |  | ||||||
|  |  | ||||||
| 					> .app |  | ||||||
| 						margin-right 8px |  | ||||||
| 						padding-right 8px |  | ||||||
| 						color #ccc |  | ||||||
| 						border-right solid 1px #eaeaea |  | ||||||
|  |  | ||||||
| 					> .created-at |  | ||||||
| 						color #c0c0c0 |  | ||||||
|  |  | ||||||
| 			> .body |  | ||||||
|  |  | ||||||
| 				> .text |  | ||||||
| 					cursor default |  | ||||||
| 					display block |  | ||||||
| 					margin 0 |  | ||||||
| 					padding 0 |  | ||||||
| 					overflow-wrap break-word |  | ||||||
| 					font-size 1.1em |  | ||||||
| 					color #717171 |  | ||||||
|  |  | ||||||
| 					>>> .quote |  | ||||||
| 						margin 8px |  | ||||||
| 						padding 6px 12px |  | ||||||
| 						color #aaa |  | ||||||
| 						border-left solid 3px #eee |  | ||||||
|  |  | ||||||
| 					> .reply |  | ||||||
| 						margin-right 8px |  | ||||||
| 						color #717171 |  | ||||||
|  |  | ||||||
| 					> .rp |  | ||||||
| 						margin-left 4px |  | ||||||
| 						font-style oblique |  | ||||||
| 						color #a0bf46 |  | ||||||
|  |  | ||||||
| 				> .location |  | ||||||
| 					margin 4px 0 |  | ||||||
| 					font-size 12px |  | ||||||
| 					color #ccc |  | ||||||
|  |  | ||||||
| 				> .map |  | ||||||
| 					width 100% |  | ||||||
| 					height 300px |  | ||||||
|  |  | ||||||
| 					&:empty |  | ||||||
| 						display none |  | ||||||
|  |  | ||||||
| 				> .tags |  | ||||||
| 					margin 4px 0 0 0 |  | ||||||
|  |  | ||||||
| 					> * |  | ||||||
| 						display inline-block |  | ||||||
| 						margin 0 8px 0 0 |  | ||||||
| 						padding 2px 8px 2px 16px |  | ||||||
| 						font-size 90% |  | ||||||
| 						color #8d969e |  | ||||||
| 						background #edf0f3 |  | ||||||
| 						border-radius 4px |  | ||||||
|  |  | ||||||
| 						&:before |  | ||||||
| 							content "" |  | ||||||
| 							display block |  | ||||||
| 							position absolute |  | ||||||
| 							top 0 |  | ||||||
| 							bottom 0 |  | ||||||
| 							left 4px |  | ||||||
| 							width 8px |  | ||||||
| 							height 8px |  | ||||||
| 							margin auto 0 |  | ||||||
| 							background #fff |  | ||||||
| 							border-radius 100% |  | ||||||
|  |  | ||||||
| 						&:hover |  | ||||||
| 							text-decoration none |  | ||||||
| 							background #e2e7ec |  | ||||||
|  |  | ||||||
| 				.mk-url-preview |  | ||||||
| 					margin-top 8px |  | ||||||
|  |  | ||||||
| 				> .channel |  | ||||||
| 					margin 0 |  | ||||||
|  |  | ||||||
| 				> .mk-poll |  | ||||||
| 					font-size 80% |  | ||||||
|  |  | ||||||
| 				> .renote |  | ||||||
| 					margin 8px 0 |  | ||||||
|  |  | ||||||
| 					> .mk-note-preview |  | ||||||
| 						padding 16px |  | ||||||
| 						border dashed 1px #c0dac6 |  | ||||||
| 						border-radius 8px |  | ||||||
|  |  | ||||||
| 			> footer |  | ||||||
| 				> button |  | ||||||
| 					margin 0 28px 0 0 |  | ||||||
| 					padding 0 8px |  | ||||||
| 					line-height 32px |  | ||||||
| 					font-size 1em |  | ||||||
| 					color #ddd |  | ||||||
| 					background transparent |  | ||||||
| 					border none |  | ||||||
| 					cursor pointer |  | ||||||
|  |  | ||||||
| 					&:hover |  | ||||||
| 						color #666 |  | ||||||
|  |  | ||||||
| 					> .count |  | ||||||
| 						display inline |  | ||||||
| 						margin 0 0 0 8px |  | ||||||
| 						color #999 |  | ||||||
|  |  | ||||||
| 					&.reacted |  | ||||||
| 						color $theme-color |  | ||||||
|  |  | ||||||
| 					&:last-child |  | ||||||
| 						position absolute |  | ||||||
| 						right 0 |  | ||||||
| 						margin 0 |  | ||||||
|  |  | ||||||
| 	> .detail |  | ||||||
| 		padding-top 4px |  | ||||||
| 		background rgba(0, 0, 0, 0.0125) |  | ||||||
|  |  | ||||||
| </style> |  | ||||||
|  |  | ||||||
| <style lang="stylus" module> |  | ||||||
| .text |  | ||||||
|  |  | ||||||
| 	code |  | ||||||
| 		padding 4px 8px |  | ||||||
| 		margin 0 0.5em |  | ||||||
| 		font-size 80% |  | ||||||
| 		color #525252 |  | ||||||
| 		background #f8f8f8 |  | ||||||
| 		border-radius 2px |  | ||||||
|  |  | ||||||
| 	pre > code |  | ||||||
| 		padding 16px |  | ||||||
| 		margin 0 |  | ||||||
|  |  | ||||||
| 	[data-is-me]:after |  | ||||||
| 		content "you" |  | ||||||
| 		padding 0 4px |  | ||||||
| 		margin-left 4px |  | ||||||
| 		font-size 80% |  | ||||||
| 		color $theme-color-foreground |  | ||||||
| 		background $theme-color |  | ||||||
| 		border-radius 4px |  | ||||||
| </style> |  | ||||||
| @@ -1,65 +0,0 @@ | |||||||
| <template> |  | ||||||
| <div class="note"> |  | ||||||
| 	<header> |  | ||||||
| 		<a class="index" @click="reply">{{ note.index }}:</a> |  | ||||||
| 		<router-link class="name" :to="note.user | userPage" v-user-preview="note.user.id"><b>{{ note.user | userName }}</b></router-link> |  | ||||||
| 		<span>ID:<i>{{ note.user | acct }}</i></span> |  | ||||||
| 	</header> |  | ||||||
| 	<div> |  | ||||||
| 		<a v-if="note.reply">>>{{ note.reply.index }}</a> |  | ||||||
| 		{{ note.text }} |  | ||||||
| 		<div class="media" v-if="note.media"> |  | ||||||
| 			<a v-for="file in note.media" :href="file.url" target="_blank"> |  | ||||||
| 				<img :src="`${file.url}?thumbnail&size=512`" :alt="file.name" :title="file.name"/> |  | ||||||
| 			</a> |  | ||||||
| 		</div> |  | ||||||
| 	</div> |  | ||||||
| </div> |  | ||||||
| </template> |  | ||||||
|  |  | ||||||
| <script lang="ts"> |  | ||||||
| import Vue from 'vue'; |  | ||||||
|  |  | ||||||
| export default Vue.extend({ |  | ||||||
| 	props: ['note'], |  | ||||||
| 	methods: { |  | ||||||
| 		reply() { |  | ||||||
| 			this.$emit('reply', this.note); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| }); |  | ||||||
| </script> |  | ||||||
|  |  | ||||||
| <style lang="stylus" scoped> |  | ||||||
| .note |  | ||||||
| 	margin 0 |  | ||||||
| 	padding 0 |  | ||||||
| 	color #444 |  | ||||||
|  |  | ||||||
| 	> header |  | ||||||
| 		position -webkit-sticky |  | ||||||
| 		position sticky |  | ||||||
| 		z-index 1 |  | ||||||
| 		top 0 |  | ||||||
| 		padding 8px 4px 4px 16px |  | ||||||
| 		background rgba(255, 255, 255, 0.9) |  | ||||||
|  |  | ||||||
| 		> .index |  | ||||||
| 			margin-right 0.25em |  | ||||||
|  |  | ||||||
| 		> .name |  | ||||||
| 			margin-right 0.5em |  | ||||||
| 			color #008000 |  | ||||||
|  |  | ||||||
| 	> div |  | ||||||
| 		padding 0 16px 16px 16px |  | ||||||
|  |  | ||||||
| 		> .media |  | ||||||
| 			> a |  | ||||||
| 				display inline-block |  | ||||||
|  |  | ||||||
| 				> img |  | ||||||
| 					max-width 100% |  | ||||||
| 					vertical-align bottom |  | ||||||
|  |  | ||||||
| </style> |  | ||||||
| @@ -1,85 +0,0 @@ | |||||||
| <template> |  | ||||||
| <div class="mk-note-card"> |  | ||||||
| 	<a :href="note | notePage"> |  | ||||||
| 		<header> |  | ||||||
| 			<img :src="`${note.user.avatarUrl}?thumbnail&size=64`" alt="avatar"/><h3>{{ note.user | userName }}</h3> |  | ||||||
| 		</header> |  | ||||||
| 		<div> |  | ||||||
| 			{{ text }} |  | ||||||
| 		</div> |  | ||||||
| 		<mk-time :time="note.createdAt"/> |  | ||||||
| 	</a> |  | ||||||
| </div> |  | ||||||
| </template> |  | ||||||
|  |  | ||||||
| <script lang="ts"> |  | ||||||
| import Vue from 'vue'; |  | ||||||
| import summary from '../../../../../renderers/get-note-summary'; |  | ||||||
|  |  | ||||||
| export default Vue.extend({ |  | ||||||
| 	props: ['note'], |  | ||||||
| 	computed: { |  | ||||||
| 		text(): string { |  | ||||||
| 			return summary(this.note); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| }); |  | ||||||
| </script> |  | ||||||
|  |  | ||||||
| <style lang="stylus" scoped> |  | ||||||
| .mk-note-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> |  | ||||||
| @@ -1,103 +0,0 @@ | |||||||
| <template> |  | ||||||
| <div class="root sub"> |  | ||||||
| 	<router-link class="avatar-anchor" :to="note.user | userPage"> |  | ||||||
| 		<img class="avatar" :src="`${note.user.avatarUrl}?thumbnail&size=64`" alt="avatar"/> |  | ||||||
| 	</router-link> |  | ||||||
| 	<div class="main"> |  | ||||||
| 		<header> |  | ||||||
| 			<router-link class="name" :to="note.user | userPage">{{ note.user | userName }}</router-link> |  | ||||||
| 			<span class="username">@{{ note.user | acct }}</span> |  | ||||||
| 			<router-link class="time" :to="note | notePage"> |  | ||||||
| 				<mk-time :time="note.createdAt"/> |  | ||||||
| 			</router-link> |  | ||||||
| 		</header> |  | ||||||
| 		<div class="body"> |  | ||||||
| 			<mk-sub-note-content class="text" :note="note"/> |  | ||||||
| 		</div> |  | ||||||
| 	</div> |  | ||||||
| </div> |  | ||||||
| </template> |  | ||||||
|  |  | ||||||
| <script lang="ts"> |  | ||||||
| import Vue from 'vue'; |  | ||||||
|  |  | ||||||
| export default Vue.extend({ |  | ||||||
| 	props: ['note'] |  | ||||||
| }); |  | ||||||
| </script> |  | ||||||
|  |  | ||||||
| <style lang="stylus" scoped> |  | ||||||
| .root.sub |  | ||||||
| 	padding 8px |  | ||||||
| 	font-size 0.9em |  | ||||||
| 	background #fdfdfd |  | ||||||
|  |  | ||||||
| 	@media (min-width 500px) |  | ||||||
| 		padding 12px |  | ||||||
|  |  | ||||||
| 	&:after |  | ||||||
| 		content "" |  | ||||||
| 		display block |  | ||||||
| 		clear both |  | ||||||
|  |  | ||||||
| 	&:hover |  | ||||||
| 		> .main > footer > button |  | ||||||
| 			color #888 |  | ||||||
|  |  | ||||||
| 	> .avatar-anchor |  | ||||||
| 		display block |  | ||||||
| 		float left |  | ||||||
| 		margin 0 12px 0 0 |  | ||||||
|  |  | ||||||
| 		> .avatar |  | ||||||
| 			display block |  | ||||||
| 			width 48px |  | ||||||
| 			height 48px |  | ||||||
| 			margin 0 |  | ||||||
| 			border-radius 8px |  | ||||||
| 			vertical-align bottom |  | ||||||
|  |  | ||||||
| 	> .main |  | ||||||
| 		float left |  | ||||||
| 		width calc(100% - 60px) |  | ||||||
|  |  | ||||||
| 		> header |  | ||||||
| 			display flex |  | ||||||
| 			margin-bottom 4px |  | ||||||
| 			white-space nowrap |  | ||||||
|  |  | ||||||
| 			> .name |  | ||||||
| 				display block |  | ||||||
| 				margin 0 .5em 0 0 |  | ||||||
| 				padding 0 |  | ||||||
| 				overflow hidden |  | ||||||
| 				color #607073 |  | ||||||
| 				font-size 1em |  | ||||||
| 				font-weight 700 |  | ||||||
| 				text-align left |  | ||||||
| 				text-decoration none |  | ||||||
| 				text-overflow ellipsis |  | ||||||
|  |  | ||||||
| 				&:hover |  | ||||||
| 					text-decoration underline |  | ||||||
|  |  | ||||||
| 			> .username |  | ||||||
| 				text-align left |  | ||||||
| 				margin 0 .5em 0 0 |  | ||||||
| 				color #d1d8da |  | ||||||
|  |  | ||||||
| 			> .time |  | ||||||
| 				margin-left auto |  | ||||||
| 				color #b2b8bb |  | ||||||
|  |  | ||||||
| 		> .body |  | ||||||
|  |  | ||||||
| 			> .text |  | ||||||
| 				cursor default |  | ||||||
| 				margin 0 |  | ||||||
| 				padding 0 |  | ||||||
| 				font-size 1.1em |  | ||||||
| 				color #717171 |  | ||||||
|  |  | ||||||
| </style> |  | ||||||
|  |  | ||||||
| @@ -1,444 +0,0 @@ | |||||||
| <template> |  | ||||||
| <div class="mk-note-detail"> |  | ||||||
| 	<button |  | ||||||
| 		class="more" |  | ||||||
| 		v-if="p.reply && p.reply.replyId && context == null" |  | ||||||
| 		@click="fetchContext" |  | ||||||
| 		:disabled="fetchingContext" |  | ||||||
| 	> |  | ||||||
| 		<template v-if="!contextFetching">%fa:ellipsis-v%</template> |  | ||||||
| 		<template v-if="contextFetching">%fa:spinner .pulse%</template> |  | ||||||
| 	</button> |  | ||||||
| 	<div class="context"> |  | ||||||
| 		<x-sub v-for="note in context" :key="note.id" :note="note"/> |  | ||||||
| 	</div> |  | ||||||
| 	<div class="reply-to" v-if="p.reply"> |  | ||||||
| 		<x-sub :note="p.reply"/> |  | ||||||
| 	</div> |  | ||||||
| 	<div class="renote" v-if="isRenote"> |  | ||||||
| 		<p> |  | ||||||
| 			<router-link class="avatar-anchor" :to="note.user | userPage"> |  | ||||||
| 				<img class="avatar" :src="`${note.user.avatarUrl}?thumbnail&size=32`" alt="avatar"/> |  | ||||||
| 			</router-link> |  | ||||||
| 			%fa:retweet%<router-link class="name" :to="note.user | userPage">{{ note.user | userName }}</router-link>がRenote |  | ||||||
| 		</p> |  | ||||||
| 	</div> |  | ||||||
| 	<article> |  | ||||||
| 		<header> |  | ||||||
| 			<router-link class="avatar-anchor" :to="p.user | userPage"> |  | ||||||
| 				<img class="avatar" :src="`${p.user.avatarUrl}?thumbnail&size=64`" alt="avatar"/> |  | ||||||
| 			</router-link> |  | ||||||
| 			<div> |  | ||||||
| 				<router-link class="name" :to="p.user | userPage">{{ p.user | userName }}</router-link> |  | ||||||
| 				<span class="username">@{{ p.user | acct }}</span> |  | ||||||
| 			</div> |  | ||||||
| 		</header> |  | ||||||
| 		<div class="body"> |  | ||||||
| 			<mk-note-html v-if="p.text" :ast="p.text" :i="os.i" :class="$style.text"/> |  | ||||||
| 			<div class="tags" v-if="p.tags && p.tags.length > 0"> |  | ||||||
| 				<router-link v-for="tag in p.tags" :key="tag" :to="`/search?q=#${tag}`">{{ tag }}</router-link> |  | ||||||
| 			</div> |  | ||||||
| 			<div class="media" v-if="p.media.length > 0"> |  | ||||||
| 				<mk-media-list :media-list="p.media"/> |  | ||||||
| 			</div> |  | ||||||
| 			<mk-poll v-if="p.poll" :note="p"/> |  | ||||||
| 			<mk-url-preview v-for="url in urls" :url="url" :key="url"/> |  | ||||||
| 			<a class="location" v-if="p.geo" :href="`http://maps.google.com/maps?q=${p.geo.coordinates[1]},${p.geo.coordinates[0]}`" target="_blank">%fa:map-marker-alt% 位置情報</a> |  | ||||||
| 			<div class="map" v-if="p.geo" ref="map"></div> |  | ||||||
| 			<div class="renote" v-if="p.renote"> |  | ||||||
| 				<mk-note-preview :note="p.renote"/> |  | ||||||
| 			</div> |  | ||||||
| 		</div> |  | ||||||
| 		<router-link class="time" :to="`/@${pAcct}/${p.id}`"> |  | ||||||
| 			<mk-time :time="p.createdAt" mode="detail"/> |  | ||||||
| 		</router-link> |  | ||||||
| 		<footer> |  | ||||||
| 			<mk-reactions-viewer :note="p"/> |  | ||||||
| 			<button @click="reply" title="%i18n:mobile.tags.mk-note-detail.reply%"> |  | ||||||
| 				%fa:reply%<p class="count" v-if="p.repliesCount > 0">{{ p.repliesCount }}</p> |  | ||||||
| 			</button> |  | ||||||
| 			<button @click="renote" title="Renote"> |  | ||||||
| 				%fa:retweet%<p class="count" v-if="p.renoteCount > 0">{{ p.renoteCount }}</p> |  | ||||||
| 			</button> |  | ||||||
| 			<button :class="{ reacted: p.myReaction != null }" @click="react" ref="reactButton" title="%i18n:mobile.tags.mk-note-detail.reaction%"> |  | ||||||
| 				%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"> |  | ||||||
| 		<x-sub v-for="note in replies" :key="note.id" :note="note"/> |  | ||||||
| 	</div> |  | ||||||
| </div> |  | ||||||
| </template> |  | ||||||
|  |  | ||||||
| <script lang="ts"> |  | ||||||
| import Vue from 'vue'; |  | ||||||
| import parse from '../../../../../text/parse'; |  | ||||||
|  |  | ||||||
| import MkNoteMenu from '../../../common/views/components/note-menu.vue'; |  | ||||||
| import MkReactionPicker from '../../../common/views/components/reaction-picker.vue'; |  | ||||||
| import XSub from './note-detail.sub.vue'; |  | ||||||
|  |  | ||||||
| export default Vue.extend({ |  | ||||||
| 	components: { |  | ||||||
| 		XSub |  | ||||||
| 	}, |  | ||||||
|  |  | ||||||
| 	props: { |  | ||||||
| 		note: { |  | ||||||
| 			type: Object, |  | ||||||
| 			required: true |  | ||||||
| 		}, |  | ||||||
| 		compact: { |  | ||||||
| 			default: false |  | ||||||
| 		} |  | ||||||
| 	}, |  | ||||||
|  |  | ||||||
| 	data() { |  | ||||||
| 		return { |  | ||||||
| 			context: [], |  | ||||||
| 			contextFetching: false, |  | ||||||
| 			replies: [] |  | ||||||
| 		}; |  | ||||||
| 	}, |  | ||||||
|  |  | ||||||
| 	computed: { |  | ||||||
| 		isRenote(): boolean { |  | ||||||
| 			return (this.note.renote && |  | ||||||
| 				this.note.text == null && |  | ||||||
| 				this.note.mediaIds.length == 0 && |  | ||||||
| 				this.note.poll == null); |  | ||||||
| 		}, |  | ||||||
| 		p(): any { |  | ||||||
| 			return this.isRenote ? this.note.renote : this.note; |  | ||||||
| 		}, |  | ||||||
| 		reactionsCount(): number { |  | ||||||
| 			return this.p.reactionCounts |  | ||||||
| 				? Object.keys(this.p.reactionCounts) |  | ||||||
| 					.map(key => this.p.reactionCounts[key]) |  | ||||||
| 					.reduce((a, b) => a + b) |  | ||||||
| 				: 0; |  | ||||||
| 		}, |  | ||||||
| 		urls(): string[] { |  | ||||||
| 			if (this.p.text) { |  | ||||||
| 				const ast = parse(this.p.text); |  | ||||||
| 				return 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 as any).api('notes/replies', { |  | ||||||
| 				noteId: this.p.id, |  | ||||||
| 				limit: 8 |  | ||||||
| 			}).then(replies => { |  | ||||||
| 				this.replies = replies; |  | ||||||
| 			}); |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		// Draw map |  | ||||||
| 		if (this.p.geo) { |  | ||||||
| 			const shouldShowMap = (this as any).os.isSignedIn ? (this as any).os.i.clientSettings.showMaps : true; |  | ||||||
| 			if (shouldShowMap) { |  | ||||||
| 				(this as any).os.getGoogleMaps().then(maps => { |  | ||||||
| 					const uluru = new maps.LatLng(this.p.geo.coordinates[1], this.p.geo.coordinates[0]); |  | ||||||
| 					const map = new maps.Map(this.$refs.map, { |  | ||||||
| 						center: uluru, |  | ||||||
| 						zoom: 15 |  | ||||||
| 					}); |  | ||||||
| 					new maps.Marker({ |  | ||||||
| 						position: uluru, |  | ||||||
| 						map: map |  | ||||||
| 					}); |  | ||||||
| 				}); |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 	}, |  | ||||||
|  |  | ||||||
| 	methods: { |  | ||||||
| 		fetchContext() { |  | ||||||
| 			this.contextFetching = true; |  | ||||||
|  |  | ||||||
| 			// Fetch context |  | ||||||
| 			(this as any).api('notes/context', { |  | ||||||
| 				noteId: this.p.replyId |  | ||||||
| 			}).then(context => { |  | ||||||
| 				this.contextFetching = false; |  | ||||||
| 				this.context = context.reverse(); |  | ||||||
| 			}); |  | ||||||
| 		}, |  | ||||||
| 		reply() { |  | ||||||
| 			(this as any).apis.post({ |  | ||||||
| 				reply: this.p |  | ||||||
| 			}); |  | ||||||
| 		}, |  | ||||||
| 		renote() { |  | ||||||
| 			(this as any).apis.post({ |  | ||||||
| 				renote: this.p |  | ||||||
| 			}); |  | ||||||
| 		}, |  | ||||||
| 		react() { |  | ||||||
| 			(this as any).os.new(MkReactionPicker, { |  | ||||||
| 				source: this.$refs.reactButton, |  | ||||||
| 				note: this.p, |  | ||||||
| 				compact: true |  | ||||||
| 			}); |  | ||||||
| 		}, |  | ||||||
| 		menu() { |  | ||||||
| 			(this as any).os.new(MkNoteMenu, { |  | ||||||
| 				source: this.$refs.menuButton, |  | ||||||
| 				note: this.p, |  | ||||||
| 				compact: true |  | ||||||
| 			}); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| }); |  | ||||||
| </script> |  | ||||||
|  |  | ||||||
| <style lang="stylus" scoped> |  | ||||||
| @import '~const.styl' |  | ||||||
|  |  | ||||||
| .mk-note-detail |  | ||||||
| 	overflow hidden |  | ||||||
| 	margin 0 auto |  | ||||||
| 	padding 0 |  | ||||||
| 	width 100% |  | ||||||
| 	text-align left |  | ||||||
| 	background #fff |  | ||||||
| 	border-radius 8px |  | ||||||
| 	box-shadow 0 0 0 1px rgba(0, 0, 0, 0.2) |  | ||||||
|  |  | ||||||
| 	> .fetching |  | ||||||
| 		padding 64px 0 |  | ||||||
|  |  | ||||||
| 	> .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 |  | ||||||
| 		box-shadow none |  | ||||||
|  |  | ||||||
| 		&:hover |  | ||||||
| 			background #f6f6f6 |  | ||||||
|  |  | ||||||
| 		&:active |  | ||||||
| 			background #f0f0f0 |  | ||||||
|  |  | ||||||
| 		&:disabled |  | ||||||
| 			color #ccc |  | ||||||
|  |  | ||||||
| 	> .context |  | ||||||
| 		> * |  | ||||||
| 			border-bottom 1px solid #eef0f2 |  | ||||||
|  |  | ||||||
| 	> .renote |  | ||||||
| 		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 14px 16px 9px 16px |  | ||||||
|  |  | ||||||
| 		@media (min-width 500px) |  | ||||||
| 			padding 28px 32px 18px 32px |  | ||||||
|  |  | ||||||
| 		&:after |  | ||||||
| 			content "" |  | ||||||
| 			display block |  | ||||||
| 			clear both |  | ||||||
|  |  | ||||||
| 		&:hover |  | ||||||
| 			> .main > footer > button |  | ||||||
| 				color #888 |  | ||||||
|  |  | ||||||
| 		> header |  | ||||||
| 			display flex |  | ||||||
| 			line-height 1.1 |  | ||||||
|  |  | ||||||
| 			> .avatar-anchor |  | ||||||
| 				display block |  | ||||||
| 				padding 0 .5em 0 0 |  | ||||||
|  |  | ||||||
| 				> .avatar |  | ||||||
| 					display block |  | ||||||
| 					width 54px |  | ||||||
| 					height 54px |  | ||||||
| 					margin 0 |  | ||||||
| 					border-radius 8px |  | ||||||
| 					vertical-align bottom |  | ||||||
|  |  | ||||||
| 					@media (min-width 500px) |  | ||||||
| 						width 60px |  | ||||||
| 						height 60px |  | ||||||
|  |  | ||||||
| 			> div |  | ||||||
|  |  | ||||||
| 				> .name |  | ||||||
| 					display inline-block |  | ||||||
| 					margin .4em 0 |  | ||||||
| 					color #777 |  | ||||||
| 					font-size 16px |  | ||||||
| 					font-weight bold |  | ||||||
| 					text-align left |  | ||||||
| 					text-decoration none |  | ||||||
|  |  | ||||||
| 					&:hover |  | ||||||
| 						text-decoration underline |  | ||||||
|  |  | ||||||
| 				> .username |  | ||||||
| 					display block |  | ||||||
| 					text-align left |  | ||||||
| 					margin 0 |  | ||||||
| 					color #ccc |  | ||||||
|  |  | ||||||
| 		> .body |  | ||||||
| 			padding 8px 0 |  | ||||||
|  |  | ||||||
| 			> .renote |  | ||||||
| 				margin 8px 0 |  | ||||||
|  |  | ||||||
| 				> .mk-note-preview |  | ||||||
| 					padding 16px |  | ||||||
| 					border dashed 1px #c0dac6 |  | ||||||
| 					border-radius 8px |  | ||||||
|  |  | ||||||
| 			> .location |  | ||||||
| 				margin 4px 0 |  | ||||||
| 				font-size 12px |  | ||||||
| 				color #ccc |  | ||||||
|  |  | ||||||
| 			> .map |  | ||||||
| 				width 100% |  | ||||||
| 				height 200px |  | ||||||
|  |  | ||||||
| 				&:empty |  | ||||||
| 					display none |  | ||||||
|  |  | ||||||
| 			> .mk-url-preview |  | ||||||
| 				margin-top 8px |  | ||||||
|  |  | ||||||
| 			> .media |  | ||||||
| 				> img |  | ||||||
| 					display block |  | ||||||
| 					max-width 100% |  | ||||||
|  |  | ||||||
| 			> .tags |  | ||||||
| 				margin 4px 0 0 0 |  | ||||||
|  |  | ||||||
| 				> * |  | ||||||
| 					display inline-block |  | ||||||
| 					margin 0 8px 0 0 |  | ||||||
| 					padding 2px 8px 2px 16px |  | ||||||
| 					font-size 90% |  | ||||||
| 					color #8d969e |  | ||||||
| 					background #edf0f3 |  | ||||||
| 					border-radius 4px |  | ||||||
|  |  | ||||||
| 					&:before |  | ||||||
| 						content "" |  | ||||||
| 						display block |  | ||||||
| 						position absolute |  | ||||||
| 						top 0 |  | ||||||
| 						bottom 0 |  | ||||||
| 						left 4px |  | ||||||
| 						width 8px |  | ||||||
| 						height 8px |  | ||||||
| 						margin auto 0 |  | ||||||
| 						background #fff |  | ||||||
| 						border-radius 100% |  | ||||||
|  |  | ||||||
| 		> .time |  | ||||||
| 			font-size 16px |  | ||||||
| 			color #c0c0c0 |  | ||||||
|  |  | ||||||
| 		> footer |  | ||||||
| 			font-size 1.2em |  | ||||||
|  |  | ||||||
| 			> button |  | ||||||
| 				margin 0 |  | ||||||
| 				padding 8px |  | ||||||
| 				background transparent |  | ||||||
| 				border none |  | ||||||
| 				box-shadow none |  | ||||||
| 				font-size 1em |  | ||||||
| 				color #ddd |  | ||||||
| 				cursor pointer |  | ||||||
|  |  | ||||||
| 				&:not(:last-child) |  | ||||||
| 					margin-right 28px |  | ||||||
|  |  | ||||||
| 				&:hover |  | ||||||
| 					color #666 |  | ||||||
|  |  | ||||||
| 				> .count |  | ||||||
| 					display inline |  | ||||||
| 					margin 0 0 0 8px |  | ||||||
| 					color #999 |  | ||||||
|  |  | ||||||
| 				&.reacted |  | ||||||
| 					color $theme-color |  | ||||||
|  |  | ||||||
| 	> .replies |  | ||||||
| 		> * |  | ||||||
| 			border-top 1px solid #eef0f2 |  | ||||||
|  |  | ||||||
| </style> |  | ||||||
|  |  | ||||||
| <style lang="stylus" module> |  | ||||||
| .text |  | ||||||
| 	display block |  | ||||||
| 	margin 0 |  | ||||||
| 	padding 0 |  | ||||||
| 	overflow-wrap break-word |  | ||||||
| 	font-size 16px |  | ||||||
| 	color #717171 |  | ||||||
|  |  | ||||||
| 	@media (min-width 500px) |  | ||||||
| 		font-size 24px |  | ||||||
|  |  | ||||||
| </style> |  | ||||||
| @@ -1,100 +0,0 @@ | |||||||
| <template> |  | ||||||
| <div class="mk-note-preview"> |  | ||||||
| 	<router-link class="avatar-anchor" :to="note.user | userPage"> |  | ||||||
| 		<img class="avatar" :src="`${note.user.avatarUrl}?thumbnail&size=64`" alt="avatar"/> |  | ||||||
| 	</router-link> |  | ||||||
| 	<div class="main"> |  | ||||||
| 		<header> |  | ||||||
| 			<router-link class="name" :to="note.user | userPage">{{ note.user | userName }}</router-link> |  | ||||||
| 			<span class="username">@{{ note.user | acct }}</span> |  | ||||||
| 			<router-link class="time" :to="note | notePage"> |  | ||||||
| 				<mk-time :time="note.createdAt"/> |  | ||||||
| 			</router-link> |  | ||||||
| 		</header> |  | ||||||
| 		<div class="body"> |  | ||||||
| 			<mk-sub-note-content class="text" :note="note"/> |  | ||||||
| 		</div> |  | ||||||
| 	</div> |  | ||||||
| </div> |  | ||||||
| </template> |  | ||||||
|  |  | ||||||
| <script lang="ts"> |  | ||||||
| import Vue from 'vue'; |  | ||||||
|  |  | ||||||
| export default Vue.extend({ |  | ||||||
| 	props: ['note'] |  | ||||||
| }); |  | ||||||
| </script> |  | ||||||
|  |  | ||||||
| <style lang="stylus" scoped> |  | ||||||
| .mk-note-preview |  | ||||||
| 	margin 0 |  | ||||||
| 	padding 0 |  | ||||||
| 	font-size 0.9em |  | ||||||
| 	background #fff |  | ||||||
|  |  | ||||||
| 	&:after |  | ||||||
| 		content "" |  | ||||||
| 		display block |  | ||||||
| 		clear both |  | ||||||
|  |  | ||||||
| 	&:hover |  | ||||||
| 		> .main > footer > button |  | ||||||
| 			color #888 |  | ||||||
|  |  | ||||||
| 	> .avatar-anchor |  | ||||||
| 		display block |  | ||||||
| 		float left |  | ||||||
| 		margin 0 12px 0 0 |  | ||||||
|  |  | ||||||
| 		> .avatar |  | ||||||
| 			display block |  | ||||||
| 			width 48px |  | ||||||
| 			height 48px |  | ||||||
| 			margin 0 |  | ||||||
| 			border-radius 8px |  | ||||||
| 			vertical-align bottom |  | ||||||
|  |  | ||||||
| 	> .main |  | ||||||
| 		float left |  | ||||||
| 		width calc(100% - 60px) |  | ||||||
|  |  | ||||||
| 		> header |  | ||||||
| 			display flex |  | ||||||
| 			margin-bottom 4px |  | ||||||
| 			white-space nowrap |  | ||||||
|  |  | ||||||
| 			> .name |  | ||||||
| 				display block |  | ||||||
| 				margin 0 .5em 0 0 |  | ||||||
| 				padding 0 |  | ||||||
| 				overflow hidden |  | ||||||
| 				color #607073 |  | ||||||
| 				font-size 1em |  | ||||||
| 				font-weight 700 |  | ||||||
| 				text-align left |  | ||||||
| 				text-decoration none |  | ||||||
| 				text-overflow ellipsis |  | ||||||
|  |  | ||||||
| 				&:hover |  | ||||||
| 					text-decoration underline |  | ||||||
|  |  | ||||||
| 			> .username |  | ||||||
| 				text-align left |  | ||||||
| 				margin 0 .5em 0 0 |  | ||||||
| 				color #d1d8da |  | ||||||
|  |  | ||||||
| 			> .time |  | ||||||
| 				margin-left auto |  | ||||||
| 				color #b2b8bb |  | ||||||
|  |  | ||||||
| 		> .body |  | ||||||
|  |  | ||||||
| 			> .text |  | ||||||
| 				cursor default |  | ||||||
| 				margin 0 |  | ||||||
| 				padding 0 |  | ||||||
| 				font-size 1.1em |  | ||||||
| 				color #717171 |  | ||||||
|  |  | ||||||
| </style> |  | ||||||
| @@ -1,523 +0,0 @@ | |||||||
| <template> |  | ||||||
| <div class="note" :class="{ renote: isRenote }"> |  | ||||||
| 	<div class="reply-to" v-if="p.reply"> |  | ||||||
| 		<x-sub :note="p.reply"/> |  | ||||||
| 	</div> |  | ||||||
| 	<div class="renote" v-if="isRenote"> |  | ||||||
| 		<p> |  | ||||||
| 			<router-link class="avatar-anchor" :to="note.user | userPage"> |  | ||||||
| 				<img class="avatar" :src="`${note.user.avatarUrl}?thumbnail&size=64`" alt="avatar"/> |  | ||||||
| 			</router-link> |  | ||||||
| 			%fa:retweet% |  | ||||||
| 			<span>{{ '%i18n:mobile.tags.mk-timeline-note.reposted-by%'.substr(0, '%i18n:mobile.tags.mk-timeline-note.reposted-by%'.indexOf('{')) }}</span> |  | ||||||
| 			<router-link class="name" :to="note.user | userPage">{{ note.user | userName }}</router-link> |  | ||||||
| 			<span>{{ '%i18n:mobile.tags.mk-timeline-note.reposted-by%'.substr('%i18n:mobile.tags.mk-timeline-note.reposted-by%'.indexOf('}') + 1) }}</span> |  | ||||||
| 		</p> |  | ||||||
| 		<mk-time :time="note.createdAt"/> |  | ||||||
| 	</div> |  | ||||||
| 	<article> |  | ||||||
| 		<router-link class="avatar-anchor" :to="p.user | userPage"> |  | ||||||
| 			<img class="avatar" :src="`${p.user.avatarUrl}?thumbnail&size=96`" alt="avatar"/> |  | ||||||
| 		</router-link> |  | ||||||
| 		<div class="main"> |  | ||||||
| 			<header> |  | ||||||
| 				<router-link class="name" :to="p.user | userPage">{{ p.user | userName }}</router-link> |  | ||||||
| 				<span class="is-bot" v-if="p.user.host === null && p.user.isBot">bot</span> |  | ||||||
| 				<span class="username">@{{ p.user | acct }}</span> |  | ||||||
| 				<div class="info"> |  | ||||||
| 					<span class="mobile" v-if="p.viaMobile">%fa:mobile-alt%</span> |  | ||||||
| 					<router-link class="created-at" :to="p | notePage"> |  | ||||||
| 						<mk-time :time="p.createdAt"/> |  | ||||||
| 					</router-link> |  | ||||||
| 				</div> |  | ||||||
| 			</header> |  | ||||||
| 			<div class="body"> |  | ||||||
| 				<p class="channel" v-if="p.channel != null"><a target="_blank">{{ p.channel.title }}</a>:</p> |  | ||||||
| 				<div class="text"> |  | ||||||
| 					<a class="reply" v-if="p.reply"> |  | ||||||
| 						%fa:reply% |  | ||||||
| 					</a> |  | ||||||
| 					<mk-note-html v-if="p.text" :text="p.text" :i="os.i" :class="$style.text"/> |  | ||||||
| 					<a class="rp" v-if="p.renote != null">RP:</a> |  | ||||||
| 				</div> |  | ||||||
| 				<div class="media" v-if="p.media.length > 0"> |  | ||||||
| 					<mk-media-list :media-list="p.media"/> |  | ||||||
| 				</div> |  | ||||||
| 				<mk-poll v-if="p.poll" :note="p" ref="pollViewer"/> |  | ||||||
| 				<div class="tags" v-if="p.tags && p.tags.length > 0"> |  | ||||||
| 					<router-link v-for="tag in p.tags" :key="tag" :to="`/search?q=#${tag}`">{{ tag }}</router-link> |  | ||||||
| 				</div> |  | ||||||
| 				<mk-url-preview v-for="url in urls" :url="url" :key="url"/> |  | ||||||
| 				<a class="location" v-if="p.geo" :href="`http://maps.google.com/maps?q=${p.geo.coordinates[1]},${p.geo.coordinates[0]}`" target="_blank">%fa:map-marker-alt% 位置情報</a> |  | ||||||
| 				<div class="map" v-if="p.geo" ref="map"></div> |  | ||||||
| 				<span class="app" v-if="p.app">via <b>{{ p.app.name }}</b></span> |  | ||||||
| 				<div class="renote" v-if="p.renote"> |  | ||||||
| 					<mk-note-preview :note="p.renote"/> |  | ||||||
| 				</div> |  | ||||||
| 			</div> |  | ||||||
| 			<footer> |  | ||||||
| 				<mk-reactions-viewer :note="p" ref="reactionsViewer"/> |  | ||||||
| 				<button @click="reply"> |  | ||||||
| 					%fa:reply%<p class="count" v-if="p.repliesCount > 0">{{ p.repliesCount }}</p> |  | ||||||
| 				</button> |  | ||||||
| 				<button @click="renote" title="Renote"> |  | ||||||
| 					%fa:retweet%<p class="count" v-if="p.renoteCount > 0">{{ p.renoteCount }}</p> |  | ||||||
| 				</button> |  | ||||||
| 				<button :class="{ reacted: p.myReaction != null }" @click="react" ref="reactButton"> |  | ||||||
| 					%fa:plus%<p class="count" v-if="p.reactions_count > 0">{{ p.reactions_count }}</p> |  | ||||||
| 				</button> |  | ||||||
| 				<button class="menu" @click="menu" ref="menuButton"> |  | ||||||
| 					%fa:ellipsis-h% |  | ||||||
| 				</button> |  | ||||||
| 			</footer> |  | ||||||
| 		</div> |  | ||||||
| 	</article> |  | ||||||
| </div> |  | ||||||
| </template> |  | ||||||
|  |  | ||||||
| <script lang="ts"> |  | ||||||
| import Vue from 'vue'; |  | ||||||
| import parse from '../../../../../text/parse'; |  | ||||||
|  |  | ||||||
| import MkNoteMenu from '../../../common/views/components/note-menu.vue'; |  | ||||||
| import MkReactionPicker from '../../../common/views/components/reaction-picker.vue'; |  | ||||||
| import XSub from './note.sub.vue'; |  | ||||||
|  |  | ||||||
| export default Vue.extend({ |  | ||||||
| 	components: { |  | ||||||
| 		XSub |  | ||||||
| 	}, |  | ||||||
|  |  | ||||||
| 	props: ['note'], |  | ||||||
|  |  | ||||||
| 	data() { |  | ||||||
| 		return { |  | ||||||
| 			connection: null, |  | ||||||
| 			connectionId: null |  | ||||||
| 		}; |  | ||||||
| 	}, |  | ||||||
|  |  | ||||||
| 	computed: { |  | ||||||
| 		isRenote(): boolean { |  | ||||||
| 			return (this.note.renote && |  | ||||||
| 				this.note.text == null && |  | ||||||
| 				this.note.mediaIds.length == 0 && |  | ||||||
| 				this.note.poll == null); |  | ||||||
| 		}, |  | ||||||
| 		p(): any { |  | ||||||
| 			return this.isRenote ? this.note.renote : this.note; |  | ||||||
| 		}, |  | ||||||
| 		reactionsCount(): number { |  | ||||||
| 			return this.p.reactionCounts |  | ||||||
| 				? Object.keys(this.p.reactionCounts) |  | ||||||
| 					.map(key => this.p.reactionCounts[key]) |  | ||||||
| 					.reduce((a, b) => a + b) |  | ||||||
| 				: 0; |  | ||||||
| 		}, |  | ||||||
| 		urls(): string[] { |  | ||||||
| 			if (this.p.text) { |  | ||||||
| 				const ast = parse(this.p.text); |  | ||||||
| 				return ast |  | ||||||
| 					.filter(t => (t.type == 'url' || t.type == 'link') && !t.silent) |  | ||||||
| 					.map(t => t.url); |  | ||||||
| 			} else { |  | ||||||
| 				return null; |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 	}, |  | ||||||
|  |  | ||||||
| 	created() { |  | ||||||
| 		if ((this as any).os.isSignedIn) { |  | ||||||
| 			this.connection = (this as any).os.stream.getConnection(); |  | ||||||
| 			this.connectionId = (this as any).os.stream.use(); |  | ||||||
| 		} |  | ||||||
| 	}, |  | ||||||
|  |  | ||||||
| 	mounted() { |  | ||||||
| 		this.capture(true); |  | ||||||
|  |  | ||||||
| 		if ((this as any).os.isSignedIn) { |  | ||||||
| 			this.connection.on('_connected_', this.onStreamConnected); |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		// Draw map |  | ||||||
| 		if (this.p.geo) { |  | ||||||
| 			const shouldShowMap = (this as any).os.isSignedIn ? (this as any).os.i.clientSettings.showMaps : true; |  | ||||||
| 			if (shouldShowMap) { |  | ||||||
| 				(this as any).os.getGoogleMaps().then(maps => { |  | ||||||
| 					const uluru = new maps.LatLng(this.p.geo.coordinates[1], this.p.geo.coordinates[0]); |  | ||||||
| 					const map = new maps.Map(this.$refs.map, { |  | ||||||
| 						center: uluru, |  | ||||||
| 						zoom: 15 |  | ||||||
| 					}); |  | ||||||
| 					new maps.Marker({ |  | ||||||
| 						position: uluru, |  | ||||||
| 						map: map |  | ||||||
| 					}); |  | ||||||
| 				}); |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 	}, |  | ||||||
|  |  | ||||||
| 	beforeDestroy() { |  | ||||||
| 		this.decapture(true); |  | ||||||
|  |  | ||||||
| 		if ((this as any).os.isSignedIn) { |  | ||||||
| 			this.connection.off('_connected_', this.onStreamConnected); |  | ||||||
| 			(this as any).os.stream.dispose(this.connectionId); |  | ||||||
| 		} |  | ||||||
| 	}, |  | ||||||
|  |  | ||||||
| 	methods: { |  | ||||||
| 		capture(withHandler = false) { |  | ||||||
| 			if ((this as any).os.isSignedIn) { |  | ||||||
| 				this.connection.send({ |  | ||||||
| 					type: 'capture', |  | ||||||
| 					id: this.p.id |  | ||||||
| 				}); |  | ||||||
| 				if (withHandler) this.connection.on('note-updated', this.onStreamNoteUpdated); |  | ||||||
| 			} |  | ||||||
| 		}, |  | ||||||
| 		decapture(withHandler = false) { |  | ||||||
| 			if ((this as any).os.isSignedIn) { |  | ||||||
| 				this.connection.send({ |  | ||||||
| 					type: 'decapture', |  | ||||||
| 					id: this.p.id |  | ||||||
| 				}); |  | ||||||
| 				if (withHandler) this.connection.off('note-updated', this.onStreamNoteUpdated); |  | ||||||
| 			} |  | ||||||
| 		}, |  | ||||||
| 		onStreamConnected() { |  | ||||||
| 			this.capture(); |  | ||||||
| 		}, |  | ||||||
| 		onStreamNoteUpdated(data) { |  | ||||||
| 			const note = data.note; |  | ||||||
| 			if (note.id == this.note.id) { |  | ||||||
| 				this.$emit('update:note', note); |  | ||||||
| 			} else if (note.id == this.note.renoteId) { |  | ||||||
| 				this.note.renote = note; |  | ||||||
| 			} |  | ||||||
| 		}, |  | ||||||
| 		reply() { |  | ||||||
| 			(this as any).apis.post({ |  | ||||||
| 				reply: this.p |  | ||||||
| 			}); |  | ||||||
| 		}, |  | ||||||
| 		renote() { |  | ||||||
| 			(this as any).apis.post({ |  | ||||||
| 				renote: this.p |  | ||||||
| 			}); |  | ||||||
| 		}, |  | ||||||
| 		react() { |  | ||||||
| 			(this as any).os.new(MkReactionPicker, { |  | ||||||
| 				source: this.$refs.reactButton, |  | ||||||
| 				note: this.p, |  | ||||||
| 				compact: true |  | ||||||
| 			}); |  | ||||||
| 		}, |  | ||||||
| 		menu() { |  | ||||||
| 			(this as any).os.new(MkNoteMenu, { |  | ||||||
| 				source: this.$refs.menuButton, |  | ||||||
| 				note: this.p, |  | ||||||
| 				compact: true |  | ||||||
| 			}); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| }); |  | ||||||
| </script> |  | ||||||
|  |  | ||||||
| <style lang="stylus" scoped> |  | ||||||
| @import '~const.styl' |  | ||||||
|  |  | ||||||
| .note |  | ||||||
| 	font-size 12px |  | ||||||
| 	border-bottom solid 1px #eaeaea |  | ||||||
|  |  | ||||||
| 	&:first-child |  | ||||||
| 		border-radius 8px 8px 0 0 |  | ||||||
|  |  | ||||||
| 		> .renote |  | ||||||
| 			border-radius 8px 8px 0 0 |  | ||||||
|  |  | ||||||
| 	&:last-of-type |  | ||||||
| 		border-bottom none |  | ||||||
|  |  | ||||||
| 	@media (min-width 350px) |  | ||||||
| 		font-size 14px |  | ||||||
|  |  | ||||||
| 	@media (min-width 500px) |  | ||||||
| 		font-size 16px |  | ||||||
|  |  | ||||||
| 	> .renote |  | ||||||
| 		color #9dbb00 |  | ||||||
| 		background linear-gradient(to bottom, #edfde2 0%, #fff 100%) |  | ||||||
|  |  | ||||||
| 		> p |  | ||||||
| 			margin 0 |  | ||||||
| 			padding 8px 16px |  | ||||||
| 			line-height 28px |  | ||||||
|  |  | ||||||
| 			@media (min-width 500px) |  | ||||||
| 				padding 16px |  | ||||||
|  |  | ||||||
| 			.avatar-anchor |  | ||||||
| 				display inline-block |  | ||||||
|  |  | ||||||
| 				.avatar |  | ||||||
| 					vertical-align bottom |  | ||||||
| 					width 28px |  | ||||||
| 					height 28px |  | ||||||
| 					margin 0 8px 0 0 |  | ||||||
| 					border-radius 6px |  | ||||||
|  |  | ||||||
| 			[data-fa] |  | ||||||
| 				margin-right 4px |  | ||||||
|  |  | ||||||
| 			.name |  | ||||||
| 				font-weight bold |  | ||||||
|  |  | ||||||
| 		> .mk-time |  | ||||||
| 			position absolute |  | ||||||
| 			top 8px |  | ||||||
| 			right 16px |  | ||||||
| 			font-size 0.9em |  | ||||||
| 			line-height 28px |  | ||||||
|  |  | ||||||
| 			@media (min-width 500px) |  | ||||||
| 				top 16px |  | ||||||
|  |  | ||||||
| 		& + article |  | ||||||
| 			padding-top 8px |  | ||||||
|  |  | ||||||
| 	> .reply-to |  | ||||||
| 		background rgba(0, 0, 0, 0.0125) |  | ||||||
|  |  | ||||||
| 		> .mk-note-preview |  | ||||||
| 			background transparent |  | ||||||
|  |  | ||||||
| 	> article |  | ||||||
| 		padding 14px 16px 9px 16px |  | ||||||
|  |  | ||||||
| 		&:after |  | ||||||
| 			content "" |  | ||||||
| 			display block |  | ||||||
| 			clear both |  | ||||||
|  |  | ||||||
| 		> .avatar-anchor |  | ||||||
| 			display block |  | ||||||
| 			float left |  | ||||||
| 			margin 0 10px 8px 0 |  | ||||||
| 			position -webkit-sticky |  | ||||||
| 			position sticky |  | ||||||
| 			top 62px |  | ||||||
|  |  | ||||||
| 			@media (min-width 500px) |  | ||||||
| 				margin-right 16px |  | ||||||
|  |  | ||||||
| 			> .avatar |  | ||||||
| 				display block |  | ||||||
| 				width 48px |  | ||||||
| 				height 48px |  | ||||||
| 				margin 0 |  | ||||||
| 				border-radius 6px |  | ||||||
| 				vertical-align bottom |  | ||||||
|  |  | ||||||
| 				@media (min-width 500px) |  | ||||||
| 					width 58px |  | ||||||
| 					height 58px |  | ||||||
| 					border-radius 8px |  | ||||||
|  |  | ||||||
| 		> .main |  | ||||||
| 			float left |  | ||||||
| 			width calc(100% - 58px) |  | ||||||
|  |  | ||||||
| 			@media (min-width 500px) |  | ||||||
| 				width calc(100% - 74px) |  | ||||||
|  |  | ||||||
| 			> header |  | ||||||
| 				display flex |  | ||||||
| 				align-items center |  | ||||||
| 				white-space nowrap |  | ||||||
|  |  | ||||||
| 				@media (min-width 500px) |  | ||||||
| 					margin-bottom 2px |  | ||||||
|  |  | ||||||
| 				> .name |  | ||||||
| 					display block |  | ||||||
| 					margin 0 0.5em 0 0 |  | ||||||
| 					padding 0 |  | ||||||
| 					overflow hidden |  | ||||||
| 					color #627079 |  | ||||||
| 					font-size 1em |  | ||||||
| 					font-weight bold |  | ||||||
| 					text-decoration none |  | ||||||
| 					text-overflow ellipsis |  | ||||||
|  |  | ||||||
| 					&:hover |  | ||||||
| 						text-decoration underline |  | ||||||
|  |  | ||||||
| 				> .is-bot |  | ||||||
| 					margin 0 0.5em 0 0 |  | ||||||
| 					padding 1px 6px |  | ||||||
| 					font-size 12px |  | ||||||
| 					color #aaa |  | ||||||
| 					border solid 1px #ddd |  | ||||||
| 					border-radius 3px |  | ||||||
|  |  | ||||||
| 				> .username |  | ||||||
| 					margin 0 0.5em 0 0 |  | ||||||
| 					color #ccc |  | ||||||
|  |  | ||||||
| 				> .info |  | ||||||
| 					margin-left auto |  | ||||||
| 					font-size 0.9em |  | ||||||
|  |  | ||||||
| 					> .mobile |  | ||||||
| 						margin-right 6px |  | ||||||
| 						color #c0c0c0 |  | ||||||
|  |  | ||||||
| 					> .created-at |  | ||||||
| 						color #c0c0c0 |  | ||||||
|  |  | ||||||
| 			> .body |  | ||||||
|  |  | ||||||
| 				> .text |  | ||||||
| 					display block |  | ||||||
| 					margin 0 |  | ||||||
| 					padding 0 |  | ||||||
| 					overflow-wrap break-word |  | ||||||
| 					font-size 1.1em |  | ||||||
| 					color #717171 |  | ||||||
|  |  | ||||||
| 					>>> .quote |  | ||||||
| 						margin 8px |  | ||||||
| 						padding 6px 12px |  | ||||||
| 						color #aaa |  | ||||||
| 						border-left solid 3px #eee |  | ||||||
|  |  | ||||||
| 					> .reply |  | ||||||
| 						margin-right 8px |  | ||||||
| 						color #717171 |  | ||||||
|  |  | ||||||
| 					> .rp |  | ||||||
| 						margin-left 4px |  | ||||||
| 						font-style oblique |  | ||||||
| 						color #a0bf46 |  | ||||||
|  |  | ||||||
| 					[data-is-me]:after |  | ||||||
| 						content "you" |  | ||||||
| 						padding 0 4px |  | ||||||
| 						margin-left 4px |  | ||||||
| 						font-size 80% |  | ||||||
| 						color $theme-color-foreground |  | ||||||
| 						background $theme-color |  | ||||||
| 						border-radius 4px |  | ||||||
|  |  | ||||||
| 				.mk-url-preview |  | ||||||
| 					margin-top 8px |  | ||||||
|  |  | ||||||
| 				> .channel |  | ||||||
| 					margin 0 |  | ||||||
|  |  | ||||||
| 				> .tags |  | ||||||
| 					margin 4px 0 0 0 |  | ||||||
|  |  | ||||||
| 					> * |  | ||||||
| 						display inline-block |  | ||||||
| 						margin 0 8px 0 0 |  | ||||||
| 						padding 2px 8px 2px 16px |  | ||||||
| 						font-size 90% |  | ||||||
| 						color #8d969e |  | ||||||
| 						background #edf0f3 |  | ||||||
| 						border-radius 4px |  | ||||||
|  |  | ||||||
| 						&:before |  | ||||||
| 							content "" |  | ||||||
| 							display block |  | ||||||
| 							position absolute |  | ||||||
| 							top 0 |  | ||||||
| 							bottom 0 |  | ||||||
| 							left 4px |  | ||||||
| 							width 8px |  | ||||||
| 							height 8px |  | ||||||
| 							margin auto 0 |  | ||||||
| 							background #fff |  | ||||||
| 							border-radius 100% |  | ||||||
|  |  | ||||||
| 				> .media |  | ||||||
| 					> img |  | ||||||
| 						display block |  | ||||||
| 						max-width 100% |  | ||||||
|  |  | ||||||
| 				> .location |  | ||||||
| 					margin 4px 0 |  | ||||||
| 					font-size 12px |  | ||||||
| 					color #ccc |  | ||||||
|  |  | ||||||
| 				> .map |  | ||||||
| 					width 100% |  | ||||||
| 					height 200px |  | ||||||
|  |  | ||||||
| 					&:empty |  | ||||||
| 						display none |  | ||||||
|  |  | ||||||
| 				> .app |  | ||||||
| 					font-size 12px |  | ||||||
| 					color #ccc |  | ||||||
|  |  | ||||||
| 				> .mk-poll |  | ||||||
| 					font-size 80% |  | ||||||
|  |  | ||||||
| 				> .renote |  | ||||||
| 					margin 8px 0 |  | ||||||
|  |  | ||||||
| 					> .mk-note-preview |  | ||||||
| 						padding 16px |  | ||||||
| 						border dashed 1px #c0dac6 |  | ||||||
| 						border-radius 8px |  | ||||||
|  |  | ||||||
| 			> footer |  | ||||||
| 				> button |  | ||||||
| 					margin 0 |  | ||||||
| 					padding 8px |  | ||||||
| 					background transparent |  | ||||||
| 					border none |  | ||||||
| 					box-shadow none |  | ||||||
| 					font-size 1em |  | ||||||
| 					color #ddd |  | ||||||
| 					cursor pointer |  | ||||||
|  |  | ||||||
| 					&:not(:last-child) |  | ||||||
| 						margin-right 28px |  | ||||||
|  |  | ||||||
| 					&:hover |  | ||||||
| 						color #666 |  | ||||||
|  |  | ||||||
| 					> .count |  | ||||||
| 						display inline |  | ||||||
| 						margin 0 0 0 8px |  | ||||||
| 						color #999 |  | ||||||
|  |  | ||||||
| 					&.reacted |  | ||||||
| 						color $theme-color |  | ||||||
|  |  | ||||||
| 					&.menu |  | ||||||
| 						@media (max-width 350px) |  | ||||||
| 							display none |  | ||||||
|  |  | ||||||
| </style> |  | ||||||
|  |  | ||||||
| <style lang="stylus" module> |  | ||||||
| .text |  | ||||||
| 	code |  | ||||||
| 		padding 4px 8px |  | ||||||
| 		margin 0 0.5em |  | ||||||
| 		font-size 80% |  | ||||||
| 		color #525252 |  | ||||||
| 		background #f8f8f8 |  | ||||||
| 		border-radius 2px |  | ||||||
|  |  | ||||||
| 	pre > code |  | ||||||
| 		padding 16px |  | ||||||
| 		margin 0 |  | ||||||
| </style> |  | ||||||
		Reference in New Issue
	
	Block a user
	 syuilo
					syuilo