✌️
This commit is contained in:
		
							parent
							
								
									0da0ae14d2
								
							
						
					
					
						commit
						3ae824c354
					
				
					 8 changed files with 227 additions and 44 deletions
				
			
		| 
						 | 
					@ -31,6 +31,10 @@ module.exports = (params, user: IUser, app) => new Promise(async (res, rej) => {
 | 
				
			||||||
	const [text, textErr] = $(params.text).optional.string().pipe(isValidText).$;
 | 
						const [text, textErr] = $(params.text).optional.string().pipe(isValidText).$;
 | 
				
			||||||
	if (textErr) return rej('invalid text');
 | 
						if (textErr) return rej('invalid text');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Get 'tags' parameter
 | 
				
			||||||
 | 
						const [tags = [], tagsErr] = $(params.tags).optional.array('string').unique().eachQ(t => t.range(1, 32)).$;
 | 
				
			||||||
 | 
						if (tagsErr) return rej('invalid tags');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Get 'media_ids' parameter
 | 
						// Get 'media_ids' parameter
 | 
				
			||||||
	const [mediaIds, mediaIdsErr] = $(params.media_ids).optional.array('id').unique().range(1, 4).$;
 | 
						const [mediaIds, mediaIdsErr] = $(params.media_ids).optional.array('id').unique().range(1, 4).$;
 | 
				
			||||||
	if (mediaIdsErr) return rej('invalid media_ids');
 | 
						if (mediaIdsErr) return rej('invalid media_ids');
 | 
				
			||||||
| 
						 | 
					@ -205,6 +209,23 @@ module.exports = (params, user: IUser, app) => new Promise(async (res, rej) => {
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						let tokens = null;
 | 
				
			||||||
 | 
						if (text) {
 | 
				
			||||||
 | 
							// Analyze
 | 
				
			||||||
 | 
							tokens = parse(text);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Extract hashtags
 | 
				
			||||||
 | 
							const hashtags = tokens
 | 
				
			||||||
 | 
								.filter(t => t.type == 'hashtag')
 | 
				
			||||||
 | 
								.map(t => t.hashtag);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							hashtags.forEach(tag => {
 | 
				
			||||||
 | 
								if (tags.indexOf(tag) == -1) {
 | 
				
			||||||
 | 
									tags.push(tag);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							});
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// 投稿を作成
 | 
						// 投稿を作成
 | 
				
			||||||
	const post = await Post.insert({
 | 
						const post = await Post.insert({
 | 
				
			||||||
		created_at: new Date(),
 | 
							created_at: new Date(),
 | 
				
			||||||
| 
						 | 
					@ -215,6 +236,7 @@ module.exports = (params, user: IUser, app) => new Promise(async (res, rej) => {
 | 
				
			||||||
		repost_id: repost ? repost._id : undefined,
 | 
							repost_id: repost ? repost._id : undefined,
 | 
				
			||||||
		poll: poll,
 | 
							poll: poll,
 | 
				
			||||||
		text: text,
 | 
							text: text,
 | 
				
			||||||
 | 
							tags: tags,
 | 
				
			||||||
		user_id: user._id,
 | 
							user_id: user._id,
 | 
				
			||||||
		app_id: app ? app._id : null,
 | 
							app_id: app ? app._id : null,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -423,8 +445,6 @@ module.exports = (params, user: IUser, app) => new Promise(async (res, rej) => {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// If has text content
 | 
						// If has text content
 | 
				
			||||||
	if (text) {
 | 
						if (text) {
 | 
				
			||||||
		// Analyze
 | 
					 | 
				
			||||||
		const tokens = parse(text);
 | 
					 | 
				
			||||||
		/*
 | 
							/*
 | 
				
			||||||
				// Extract a hashtags
 | 
									// Extract a hashtags
 | 
				
			||||||
				const hashtags = tokens
 | 
									const hashtags = tokens
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -44,6 +44,9 @@
 | 
				
			||||||
				<mk-images :images="p.media"/>
 | 
									<mk-images :images="p.media"/>
 | 
				
			||||||
			</div>
 | 
								</div>
 | 
				
			||||||
			<mk-poll v-if="p.poll" :post="p"/>
 | 
								<mk-poll v-if="p.poll" :post="p"/>
 | 
				
			||||||
 | 
								<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>
 | 
							</div>
 | 
				
			||||||
		<footer>
 | 
							<footer>
 | 
				
			||||||
			<mk-reactions-viewer :post="p"/>
 | 
								<mk-reactions-viewer :post="p"/>
 | 
				
			||||||
| 
						 | 
					@ -306,6 +309,32 @@ export default Vue.extend({
 | 
				
			||||||
			> .mk-url-preview
 | 
								> .mk-url-preview
 | 
				
			||||||
				margin-top 8px
 | 
									margin-top 8px
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								> .tags
 | 
				
			||||||
 | 
									> *
 | 
				
			||||||
 | 
										margin 0 8px 0 0
 | 
				
			||||||
 | 
										padding 0 8px 0 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
 | 
							> footer
 | 
				
			||||||
			font-size 1.2em
 | 
								font-size 1.2em
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -38,6 +38,9 @@
 | 
				
			||||||
					</p>
 | 
										</p>
 | 
				
			||||||
					<a class="reply" v-if="p.reply">%fa:reply%</a>
 | 
										<a class="reply" v-if="p.reply">%fa:reply%</a>
 | 
				
			||||||
					<mk-post-html v-if="p.ast" :ast="p.ast" :i="os.i" :class="$style.text"/>
 | 
										<mk-post-html v-if="p.ast" :ast="p.ast" :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>
 | 
				
			||||||
					<a class="quote" v-if="p.repost">RP:</a>
 | 
										<a class="quote" v-if="p.repost">RP:</a>
 | 
				
			||||||
					<mk-url-preview v-for="url in urls" :url="url" :key="url"/>
 | 
										<mk-url-preview v-for="url in urls" :url="url" :key="url"/>
 | 
				
			||||||
				</div>
 | 
									</div>
 | 
				
			||||||
| 
						 | 
					@ -342,9 +345,9 @@ export default Vue.extend({
 | 
				
			||||||
			display block
 | 
								display block
 | 
				
			||||||
			float left
 | 
								float left
 | 
				
			||||||
			margin 0 16px 10px 0
 | 
								margin 0 16px 10px 0
 | 
				
			||||||
			position -webkit-sticky
 | 
								//position -webkit-sticky
 | 
				
			||||||
			position sticky
 | 
								//position sticky
 | 
				
			||||||
			top 74px
 | 
								//top 74px
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			> .avatar
 | 
								> .avatar
 | 
				
			||||||
				display block
 | 
									display block
 | 
				
			||||||
| 
						 | 
					@ -428,6 +431,32 @@ export default Vue.extend({
 | 
				
			||||||
						font-style oblique
 | 
											font-style oblique
 | 
				
			||||||
						color #a0bf46
 | 
											color #a0bf46
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										> .tags
 | 
				
			||||||
 | 
											> *
 | 
				
			||||||
 | 
												margin 0 8px 0 0
 | 
				
			||||||
 | 
												padding 0 8px 0 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-poll
 | 
									> .mk-poll
 | 
				
			||||||
					font-size 80%
 | 
										font-size 80%
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -24,6 +24,7 @@ export default Vue.extend({
 | 
				
			||||||
		return {
 | 
							return {
 | 
				
			||||||
			fetching: true,
 | 
								fetching: true,
 | 
				
			||||||
			moreFetching: false,
 | 
								moreFetching: false,
 | 
				
			||||||
 | 
								existMore: false,
 | 
				
			||||||
			posts: [],
 | 
								posts: [],
 | 
				
			||||||
			connection: null,
 | 
								connection: null,
 | 
				
			||||||
			connectionId: null,
 | 
								connectionId: null,
 | 
				
			||||||
| 
						 | 
					@ -62,8 +63,13 @@ export default Vue.extend({
 | 
				
			||||||
			this.fetching = true;
 | 
								this.fetching = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			(this as any).api('posts/timeline', {
 | 
								(this as any).api('posts/timeline', {
 | 
				
			||||||
 | 
									limit: 11,
 | 
				
			||||||
				until_date: this.date ? this.date.getTime() : undefined
 | 
									until_date: this.date ? this.date.getTime() : undefined
 | 
				
			||||||
			}).then(posts => {
 | 
								}).then(posts => {
 | 
				
			||||||
 | 
									if (posts.length == 11) {
 | 
				
			||||||
 | 
										posts.pop();
 | 
				
			||||||
 | 
										this.existMore = true;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
				this.posts = posts;
 | 
									this.posts = posts;
 | 
				
			||||||
				this.fetching = false;
 | 
									this.fetching = false;
 | 
				
			||||||
				this.$emit('loaded');
 | 
									this.$emit('loaded');
 | 
				
			||||||
| 
						 | 
					@ -71,11 +77,17 @@ export default Vue.extend({
 | 
				
			||||||
			});
 | 
								});
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		more() {
 | 
							more() {
 | 
				
			||||||
			if (this.moreFetching || this.fetching || this.posts.length == 0) return;
 | 
								if (this.moreFetching || this.fetching || this.posts.length == 0 || !this.existMore) return;
 | 
				
			||||||
			this.moreFetching = true;
 | 
								this.moreFetching = true;
 | 
				
			||||||
			(this as any).api('posts/timeline', {
 | 
								(this as any).api('posts/timeline', {
 | 
				
			||||||
 | 
									limit: 11,
 | 
				
			||||||
				until_id: this.posts[this.posts.length - 1].id
 | 
									until_id: this.posts[this.posts.length - 1].id
 | 
				
			||||||
			}).then(posts => {
 | 
								}).then(posts => {
 | 
				
			||||||
 | 
									if (posts.length == 11) {
 | 
				
			||||||
 | 
										posts.pop();
 | 
				
			||||||
 | 
									} else {
 | 
				
			||||||
 | 
										this.existMore = false;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
				this.posts = this.posts.concat(posts);
 | 
									this.posts = this.posts.concat(posts);
 | 
				
			||||||
				this.moreFetching = false;
 | 
									this.moreFetching = false;
 | 
				
			||||||
			});
 | 
								});
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,13 +1,13 @@
 | 
				
			||||||
<template>
 | 
					<template>
 | 
				
			||||||
<mk-ui>
 | 
					<mk-ui>
 | 
				
			||||||
	<header :class="$style.header">
 | 
						<header :class="$style.header">
 | 
				
			||||||
		<h1>{{ query }}</h1>
 | 
							<h1>{{ q }}</h1>
 | 
				
			||||||
	</header>
 | 
						</header>
 | 
				
			||||||
	<div :class="$style.loading" v-if="fetching">
 | 
						<div :class="$style.loading" v-if="fetching">
 | 
				
			||||||
		<mk-ellipsis-icon/>
 | 
							<mk-ellipsis-icon/>
 | 
				
			||||||
	</div>
 | 
						</div>
 | 
				
			||||||
	<p :class="$style.empty" v-if="empty">%fa:search%「{{ query }}」に関する投稿は見つかりませんでした。</p>
 | 
						<p :class="$style.empty" v-if="!fetching && empty">%fa:search%「{{ q }}」に関する投稿は見つかりませんでした。</p>
 | 
				
			||||||
	<mk-posts ref="timeline" :class="$style.posts">
 | 
						<mk-posts ref="timeline" :class="$style.posts" :posts="posts">
 | 
				
			||||||
		<div slot="footer">
 | 
							<div slot="footer">
 | 
				
			||||||
			<template v-if="!moreFetching">%fa:search%</template>
 | 
								<template v-if="!moreFetching">%fa:search%</template>
 | 
				
			||||||
			<template v-if="moreFetching">%fa:spinner .pulse .fw%</template>
 | 
								<template v-if="moreFetching">%fa:spinner .pulse .fw%</template>
 | 
				
			||||||
| 
						 | 
					@ -21,33 +21,34 @@ import Vue from 'vue';
 | 
				
			||||||
import Progress from '../../../common/scripts/loading';
 | 
					import Progress from '../../../common/scripts/loading';
 | 
				
			||||||
import parse from '../../../common/scripts/parse-search-query';
 | 
					import parse from '../../../common/scripts/parse-search-query';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const limit = 30;
 | 
					const limit = 20;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default Vue.extend({
 | 
					export default Vue.extend({
 | 
				
			||||||
	props: ['query'],
 | 
					 | 
				
			||||||
	data() {
 | 
						data() {
 | 
				
			||||||
		return {
 | 
							return {
 | 
				
			||||||
			fetching: true,
 | 
								fetching: true,
 | 
				
			||||||
			moreFetching: false,
 | 
								moreFetching: false,
 | 
				
			||||||
 | 
								existMore: false,
 | 
				
			||||||
			offset: 0,
 | 
								offset: 0,
 | 
				
			||||||
			posts: []
 | 
								posts: []
 | 
				
			||||||
		};
 | 
							};
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
 | 
						watch: {
 | 
				
			||||||
 | 
							$route: 'fetch'
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
	computed: {
 | 
						computed: {
 | 
				
			||||||
		empty(): boolean {
 | 
							empty(): boolean {
 | 
				
			||||||
			return this.posts.length == 0;
 | 
								return this.posts.length == 0;
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							q(): string {
 | 
				
			||||||
 | 
								return this.$route.query.q;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
	mounted() {
 | 
						mounted() {
 | 
				
			||||||
		Progress.start();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		document.addEventListener('keydown', this.onDocumentKeydown);
 | 
							document.addEventListener('keydown', this.onDocumentKeydown);
 | 
				
			||||||
		window.addEventListener('scroll', this.onScroll);
 | 
							window.addEventListener('scroll', this.onScroll);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		(this as any).api('posts/search', parse(this.query)).then(posts => {
 | 
							this.fetch();
 | 
				
			||||||
			this.posts = posts;
 | 
					 | 
				
			||||||
			this.fetching = false;
 | 
					 | 
				
			||||||
		});
 | 
					 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
	beforeDestroy() {
 | 
						beforeDestroy() {
 | 
				
			||||||
		document.removeEventListener('keydown', this.onDocumentKeydown);
 | 
							document.removeEventListener('keydown', this.onDocumentKeydown);
 | 
				
			||||||
| 
						 | 
					@ -61,16 +62,38 @@ export default Vue.extend({
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
 | 
							fetch() {
 | 
				
			||||||
 | 
								this.fetching = true;
 | 
				
			||||||
 | 
								Progress.start();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								(this as any).api('posts/search', Object.assign({
 | 
				
			||||||
 | 
									limit: limit + 1,
 | 
				
			||||||
 | 
									offset: this.offset
 | 
				
			||||||
 | 
								}, parse(this.q))).then(posts => {
 | 
				
			||||||
 | 
									if (posts.length == limit + 1) {
 | 
				
			||||||
 | 
										posts.pop();
 | 
				
			||||||
 | 
										this.existMore = true;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									this.posts = posts;
 | 
				
			||||||
 | 
									this.fetching = false;
 | 
				
			||||||
 | 
									Progress.done();
 | 
				
			||||||
 | 
								});
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
		more() {
 | 
							more() {
 | 
				
			||||||
			if (this.moreFetching || this.fetching || this.posts.length == 0) return;
 | 
								if (this.moreFetching || this.fetching || this.posts.length == 0 || !this.existMore) return;
 | 
				
			||||||
			this.offset += limit;
 | 
								this.offset += limit;
 | 
				
			||||||
			this.moreFetching = true;
 | 
								this.moreFetching = true;
 | 
				
			||||||
			return (this as any).api('posts/search', Object.assign({}, parse(this.query), {
 | 
								return (this as any).api('posts/search', Object.assign({
 | 
				
			||||||
				limit: limit,
 | 
									limit: limit + 1,
 | 
				
			||||||
				offset: this.offset
 | 
									offset: this.offset
 | 
				
			||||||
			})).then(posts => {
 | 
								}, parse(this.q))).then(posts => {
 | 
				
			||||||
				this.moreFetching = false;
 | 
									if (posts.length == limit + 1) {
 | 
				
			||||||
 | 
										posts.pop();
 | 
				
			||||||
 | 
									} else {
 | 
				
			||||||
 | 
										this.existMore = false;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
				this.posts = this.posts.concat(posts);
 | 
									this.posts = this.posts.concat(posts);
 | 
				
			||||||
 | 
									this.moreFetching = false;
 | 
				
			||||||
			});
 | 
								});
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		onScroll() {
 | 
							onScroll() {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -39,6 +39,9 @@
 | 
				
			||||||
		</header>
 | 
							</header>
 | 
				
			||||||
		<div class="body">
 | 
							<div class="body">
 | 
				
			||||||
			<mk-post-html v-if="p.ast" :ast="p.ast" :i="os.i" :class="$style.text"/>
 | 
								<mk-post-html v-if="p.ast" :ast="p.ast" :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>
 | 
				
			||||||
			<mk-url-preview v-for="url in urls" :url="url" :key="url"/>
 | 
								<mk-url-preview v-for="url in urls" :url="url" :key="url"/>
 | 
				
			||||||
			<div class="media" v-if="p.media">
 | 
								<div class="media" v-if="p.media">
 | 
				
			||||||
				<mk-images :images="p.media"/>
 | 
									<mk-images :images="p.media"/>
 | 
				
			||||||
| 
						 | 
					@ -312,6 +315,28 @@ export default Vue.extend({
 | 
				
			||||||
					display block
 | 
										display block
 | 
				
			||||||
					max-width 100%
 | 
										max-width 100%
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								> .tags
 | 
				
			||||||
 | 
									> *
 | 
				
			||||||
 | 
										margin 0 8px 0 0
 | 
				
			||||||
 | 
										padding 0 8px 0 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
 | 
							> .time
 | 
				
			||||||
			font-size 16px
 | 
								font-size 16px
 | 
				
			||||||
			color #c0c0c0
 | 
								color #c0c0c0
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -35,6 +35,9 @@
 | 
				
			||||||
						%fa:reply%
 | 
											%fa:reply%
 | 
				
			||||||
					</a>
 | 
										</a>
 | 
				
			||||||
					<mk-post-html v-if="p.ast" :ast="p.ast" :i="os.i" :class="$style.text"/>
 | 
										<mk-post-html v-if="p.ast" :ast="p.ast" :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>
 | 
				
			||||||
					<mk-url-preview v-for="url in urls" :url="url" :key="url"/>
 | 
										<mk-url-preview v-for="url in urls" :url="url" :key="url"/>
 | 
				
			||||||
					<a class="quote" v-if="p.repost != null">RP:</a>
 | 
										<a class="quote" v-if="p.repost != null">RP:</a>
 | 
				
			||||||
				</div>
 | 
									</div>
 | 
				
			||||||
| 
						 | 
					@ -346,10 +349,7 @@ export default Vue.extend({
 | 
				
			||||||
					font-size 1.1em
 | 
										font-size 1.1em
 | 
				
			||||||
					color #717171
 | 
										color #717171
 | 
				
			||||||
 | 
					
 | 
				
			||||||
					> .dummy
 | 
										.mk-url-preview
 | 
				
			||||||
						display none
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
					mk-url-preview
 | 
					 | 
				
			||||||
						margin-top 8px
 | 
											margin-top 8px
 | 
				
			||||||
 | 
					
 | 
				
			||||||
					> .channel
 | 
										> .channel
 | 
				
			||||||
| 
						 | 
					@ -364,6 +364,28 @@ export default Vue.extend({
 | 
				
			||||||
						font-style oblique
 | 
											font-style oblique
 | 
				
			||||||
						color #a0bf46
 | 
											color #a0bf46
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										> .tags
 | 
				
			||||||
 | 
											> *
 | 
				
			||||||
 | 
												margin 0 8px 0 0
 | 
				
			||||||
 | 
												padding 0 8px 0 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%
 | 
				
			||||||
 | 
					
 | 
				
			||||||
					[data-is-me]:after
 | 
										[data-is-me]:after
 | 
				
			||||||
						content "you"
 | 
											content "you"
 | 
				
			||||||
						padding 0 4px
 | 
											padding 0 4px
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,10 +1,10 @@
 | 
				
			||||||
<template>
 | 
					<template>
 | 
				
			||||||
<mk-ui>
 | 
					<mk-ui>
 | 
				
			||||||
	<span slot="header">%fa:search% {{ query }}</span>
 | 
						<span slot="header">%fa:search% {{ q }}</span>
 | 
				
			||||||
	<main v-if="!fetching">
 | 
						<main v-if="!fetching">
 | 
				
			||||||
		<mk-posts :class="$style.posts" :posts="posts">
 | 
							<mk-posts :class="$style.posts" :posts="posts">
 | 
				
			||||||
			<span v-if="posts.length == 0">{{ '%i18n:mobile.tags.mk-search-posts.empty%'.replace('{}', query) }}</span>
 | 
								<span v-if="posts.length == 0">{{ '%i18n:mobile.tags.mk-search-posts.empty%'.replace('{}', q) }}</span>
 | 
				
			||||||
			<button v-if="canFetchMore" @click="more" :disabled="fetching" slot="tail">
 | 
								<button v-if="existMore" @click="more" :disabled="fetching" slot="tail">
 | 
				
			||||||
				<span v-if="!fetching">%i18n:mobile.tags.mk-timeline.load-more%</span>
 | 
									<span v-if="!fetching">%i18n:mobile.tags.mk-timeline.load-more%</span>
 | 
				
			||||||
				<span v-if="fetching">%i18n:common.loading%<mk-ellipsis/></span>
 | 
									<span v-if="fetching">%i18n:common.loading%<mk-ellipsis/></span>
 | 
				
			||||||
			</button>
 | 
								</button>
 | 
				
			||||||
| 
						 | 
					@ -18,38 +18,61 @@ import Vue from 'vue';
 | 
				
			||||||
import Progress from '../../../common/scripts/loading';
 | 
					import Progress from '../../../common/scripts/loading';
 | 
				
			||||||
import parse from '../../../common/scripts/parse-search-query';
 | 
					import parse from '../../../common/scripts/parse-search-query';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const limit = 30;
 | 
					const limit = 20;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default Vue.extend({
 | 
					export default Vue.extend({
 | 
				
			||||||
	props: ['query'],
 | 
					 | 
				
			||||||
	data() {
 | 
						data() {
 | 
				
			||||||
		return {
 | 
							return {
 | 
				
			||||||
			fetching: true,
 | 
								fetching: true,
 | 
				
			||||||
 | 
								existMore: false,
 | 
				
			||||||
			posts: [],
 | 
								posts: [],
 | 
				
			||||||
			offset: 0
 | 
								offset: 0
 | 
				
			||||||
		};
 | 
							};
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
 | 
						watch: {
 | 
				
			||||||
 | 
							$route: 'fetch'
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						computed: {
 | 
				
			||||||
 | 
							q(): string {
 | 
				
			||||||
 | 
								return this.$route.query.q;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
	mounted() {
 | 
						mounted() {
 | 
				
			||||||
		document.title = `%i18n:mobile.tags.mk-search-page.search%: ${this.query} | Misskey`;
 | 
							document.title = `%i18n:mobile.tags.mk-search-page.search%: ${this.q} | Misskey`;
 | 
				
			||||||
		document.documentElement.style.background = '#313a42';
 | 
							document.documentElement.style.background = '#313a42';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		Progress.start();
 | 
							this.fetch();
 | 
				
			||||||
 | 
					 | 
				
			||||||
		(this as any).api('posts/search', Object.assign({}, parse(this.query), {
 | 
					 | 
				
			||||||
			limit: limit
 | 
					 | 
				
			||||||
		})).then(posts => {
 | 
					 | 
				
			||||||
			this.posts = posts;
 | 
					 | 
				
			||||||
			this.fetching = false;
 | 
					 | 
				
			||||||
			Progress.done();
 | 
					 | 
				
			||||||
		});
 | 
					 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
	methods: {
 | 
						methods: {
 | 
				
			||||||
 | 
							fetch() {
 | 
				
			||||||
 | 
								this.fetching = true;
 | 
				
			||||||
 | 
								Progress.start();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								(this as any).api('posts/search', Object.assign({
 | 
				
			||||||
 | 
									limit: limit + 1
 | 
				
			||||||
 | 
								}, parse(this.q))).then(posts => {
 | 
				
			||||||
 | 
									if (posts.length == limit + 1) {
 | 
				
			||||||
 | 
										posts.pop();
 | 
				
			||||||
 | 
										this.existMore = true;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									this.posts = posts;
 | 
				
			||||||
 | 
									this.fetching = false;
 | 
				
			||||||
 | 
									Progress.done();
 | 
				
			||||||
 | 
								});
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
		more() {
 | 
							more() {
 | 
				
			||||||
			this.offset += limit;
 | 
								this.offset += limit;
 | 
				
			||||||
			return (this as any).api('posts/search', Object.assign({}, parse(this.query), {
 | 
								(this as any).api('posts/search', Object.assign({
 | 
				
			||||||
				limit: limit,
 | 
									limit: limit + 1,
 | 
				
			||||||
				offset: this.offset
 | 
									offset: this.offset
 | 
				
			||||||
			}));
 | 
								}, parse(this.q))).then(posts => {
 | 
				
			||||||
 | 
									if (posts.length == limit + 1) {
 | 
				
			||||||
 | 
										posts.pop();
 | 
				
			||||||
 | 
									} else {
 | 
				
			||||||
 | 
										this.existMore = false;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									this.posts = this.posts.concat(posts);
 | 
				
			||||||
 | 
								});
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue