wip
This commit is contained in:
		| @@ -1,6 +1,7 @@ | |||||||
| import Vue from 'vue'; | import Vue from 'vue'; | ||||||
|  |  | ||||||
| import analogClock from './analog-clock.vue'; | import analogClock from './analog-clock.vue'; | ||||||
|  | import menu from './menu.vue'; | ||||||
| import signin from './signin.vue'; | import signin from './signin.vue'; | ||||||
| import signup from './signup.vue'; | import signup from './signup.vue'; | ||||||
| import forkit from './forkit.vue'; | import forkit from './forkit.vue'; | ||||||
| @@ -29,6 +30,7 @@ import Othello from './othello.vue'; | |||||||
| import welcomeTimeline from './welcome-timeline.vue'; | import welcomeTimeline from './welcome-timeline.vue'; | ||||||
|  |  | ||||||
| Vue.component('mk-analog-clock', analogClock); | Vue.component('mk-analog-clock', analogClock); | ||||||
|  | Vue.component('mk-menu', menu); | ||||||
| Vue.component('mk-signin', signin); | Vue.component('mk-signin', signin); | ||||||
| Vue.component('mk-signup', signup); | Vue.component('mk-signup', signup); | ||||||
| Vue.component('mk-forkit', forkit); | Vue.component('mk-forkit', forkit); | ||||||
|   | |||||||
							
								
								
									
										153
									
								
								src/client/app/common/views/components/menu.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										153
									
								
								src/client/app/common/views/components/menu.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,153 @@ | |||||||
|  | <template> | ||||||
|  | <div class="mk-menu"> | ||||||
|  | 	<div class="backdrop" ref="backdrop" @click="close"></div> | ||||||
|  | 	<div class="popover" :class="{ compact }" ref="popover"> | ||||||
|  | 		<button v-for="item in items" @click="clicked(item.onClick)" v-html="item.content"></button> | ||||||
|  | 	</div> | ||||||
|  | </div> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script lang="ts"> | ||||||
|  | import Vue from 'vue'; | ||||||
|  | import * as anime from 'animejs'; | ||||||
|  |  | ||||||
|  | export default Vue.extend({ | ||||||
|  | 	props: ['source', 'compact', 'items'], | ||||||
|  | 	mounted() { | ||||||
|  | 		this.$nextTick(() => { | ||||||
|  | 			const popover = this.$refs.popover as any; | ||||||
|  |  | ||||||
|  | 			const rect = this.source.getBoundingClientRect(); | ||||||
|  | 			const width = popover.offsetWidth; | ||||||
|  | 			const height = popover.offsetHeight; | ||||||
|  |  | ||||||
|  | 			if (this.compact) { | ||||||
|  | 				const x = rect.left + window.pageXOffset + (this.source.offsetWidth / 2); | ||||||
|  | 				const y = rect.top + window.pageYOffset + (this.source.offsetHeight / 2); | ||||||
|  | 				popover.style.left = (x - (width / 2)) + 'px'; | ||||||
|  | 				popover.style.top = (y - (height / 2)) + 'px'; | ||||||
|  | 			} else { | ||||||
|  | 				const x = rect.left + window.pageXOffset + (this.source.offsetWidth / 2); | ||||||
|  | 				const y = rect.top + window.pageYOffset + this.source.offsetHeight; | ||||||
|  | 				popover.style.left = (x - (width / 2)) + 'px'; | ||||||
|  | 				popover.style.top = y + 'px'; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			anime({ | ||||||
|  | 				targets: this.$refs.backdrop, | ||||||
|  | 				opacity: 1, | ||||||
|  | 				duration: 100, | ||||||
|  | 				easing: 'linear' | ||||||
|  | 			}); | ||||||
|  |  | ||||||
|  | 			anime({ | ||||||
|  | 				targets: this.$refs.popover, | ||||||
|  | 				opacity: 1, | ||||||
|  | 				scale: [0.5, 1], | ||||||
|  | 				duration: 500 | ||||||
|  | 			}); | ||||||
|  | 		}); | ||||||
|  | 	}, | ||||||
|  | 	methods: { | ||||||
|  | 		clicked(fn) { | ||||||
|  | 			fn(); | ||||||
|  | 			this.close(); | ||||||
|  | 		}, | ||||||
|  | 		close() { | ||||||
|  | 			(this.$refs.backdrop as any).style.pointerEvents = 'none'; | ||||||
|  | 			anime({ | ||||||
|  | 				targets: this.$refs.backdrop, | ||||||
|  | 				opacity: 0, | ||||||
|  | 				duration: 200, | ||||||
|  | 				easing: 'linear' | ||||||
|  | 			}); | ||||||
|  |  | ||||||
|  | 			(this.$refs.popover as any).style.pointerEvents = 'none'; | ||||||
|  | 			anime({ | ||||||
|  | 				targets: this.$refs.popover, | ||||||
|  | 				opacity: 0, | ||||||
|  | 				scale: 0.5, | ||||||
|  | 				duration: 200, | ||||||
|  | 				easing: 'easeInBack', | ||||||
|  | 				complete: () => { | ||||||
|  | 					this.$emit('closed'); | ||||||
|  | 					this.$destroy(); | ||||||
|  | 				} | ||||||
|  | 			}); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | }); | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style lang="stylus" scoped> | ||||||
|  | @import '~const.styl' | ||||||
|  |  | ||||||
|  | $border-color = rgba(27, 31, 35, 0.15) | ||||||
|  |  | ||||||
|  | .mk-menu | ||||||
|  | 	position initial | ||||||
|  |  | ||||||
|  | 	> .backdrop | ||||||
|  | 		position fixed | ||||||
|  | 		top 0 | ||||||
|  | 		left 0 | ||||||
|  | 		z-index 10000 | ||||||
|  | 		width 100% | ||||||
|  | 		height 100% | ||||||
|  | 		background rgba(#000, 0.1) | ||||||
|  | 		opacity 0 | ||||||
|  |  | ||||||
|  | 	> .popover | ||||||
|  | 		position absolute | ||||||
|  | 		z-index 10001 | ||||||
|  | 		padding 8px 0 | ||||||
|  | 		background #fff | ||||||
|  | 		border 1px solid $border-color | ||||||
|  | 		border-radius 4px | ||||||
|  | 		box-shadow 0 3px 12px rgba(27, 31, 35, 0.15) | ||||||
|  | 		transform scale(0.5) | ||||||
|  | 		opacity 0 | ||||||
|  |  | ||||||
|  | 		$balloon-size = 16px | ||||||
|  |  | ||||||
|  | 		&:not(.compact) | ||||||
|  | 			margin-top $balloon-size | ||||||
|  | 			transform-origin center -($balloon-size) | ||||||
|  |  | ||||||
|  | 			&:before | ||||||
|  | 				content "" | ||||||
|  | 				display block | ||||||
|  | 				position absolute | ||||||
|  | 				top -($balloon-size * 2) | ||||||
|  | 				left s('calc(50% - %s)', $balloon-size) | ||||||
|  | 				border-top solid $balloon-size transparent | ||||||
|  | 				border-left solid $balloon-size transparent | ||||||
|  | 				border-right solid $balloon-size transparent | ||||||
|  | 				border-bottom solid $balloon-size $border-color | ||||||
|  |  | ||||||
|  | 			&:after | ||||||
|  | 				content "" | ||||||
|  | 				display block | ||||||
|  | 				position absolute | ||||||
|  | 				top -($balloon-size * 2) + 1.5px | ||||||
|  | 				left s('calc(50% - %s)', $balloon-size) | ||||||
|  | 				border-top solid $balloon-size transparent | ||||||
|  | 				border-left solid $balloon-size transparent | ||||||
|  | 				border-right solid $balloon-size transparent | ||||||
|  | 				border-bottom solid $balloon-size #fff | ||||||
|  |  | ||||||
|  | 		> button | ||||||
|  | 			display block | ||||||
|  | 			padding 8px 16px | ||||||
|  | 			width 100% | ||||||
|  |  | ||||||
|  | 			&:hover | ||||||
|  | 				color $theme-color-foreground | ||||||
|  | 				background $theme-color | ||||||
|  | 				text-decoration none | ||||||
|  |  | ||||||
|  | 			&:active | ||||||
|  | 				color $theme-color-foreground | ||||||
|  | 				background darken($theme-color, 10%) | ||||||
|  |  | ||||||
|  | </style> | ||||||
| @@ -1,55 +1,41 @@ | |||||||
| <template> | <template> | ||||||
| <div class="mk-note-menu"> | <div class="mk-note-menu" style="position:initial"> | ||||||
| 	<div class="backdrop" ref="backdrop" @click="close"></div> | 	<mk-menu ref="menu" :source="source" :compact="compact" :items="items" @closed="$destroy"/> | ||||||
| 	<div class="popover" :class="{ compact }" ref="popover"> |  | ||||||
| 		<button @click="favorite">%i18n:@favorite%</button> |  | ||||||
| 		<button v-if="note.userId == $store.state.i.id" @click="pin">%i18n:@pin%</button> |  | ||||||
| 		<button v-if="note.userId == $store.state.i.id" @click="del">%i18n:@delete%</button> |  | ||||||
| 		<a v-if="note.uri" :href="note.uri" target="_blank">%i18n:@remote%</a> |  | ||||||
| 	</div> |  | ||||||
| </div> | </div> | ||||||
| </template> | </template> | ||||||
|  |  | ||||||
| <script lang="ts"> | <script lang="ts"> | ||||||
| import Vue from 'vue'; | import Vue from 'vue'; | ||||||
| import * as anime from 'animejs'; |  | ||||||
|  |  | ||||||
| export default Vue.extend({ | export default Vue.extend({ | ||||||
| 	props: ['note', 'source', 'compact'], | 	props: ['note', 'source', 'compact'], | ||||||
| 	mounted() { | 	computed: { | ||||||
| 		this.$nextTick(() => { | 		items() { | ||||||
| 			const popover = this.$refs.popover as any; | 			const items = []; | ||||||
|  | 			items.push({ | ||||||
| 			const rect = this.source.getBoundingClientRect(); | 				content: '%i18n:@favorite%', | ||||||
| 			const width = popover.offsetWidth; | 				onClick: this.favorite | ||||||
| 			const height = popover.offsetHeight; | 			}); | ||||||
|  | 			if (this.note.userId == this.$store.state.i.id) { | ||||||
| 			if (this.compact) { | 				items.push({ | ||||||
| 				const x = rect.left + window.pageXOffset + (this.source.offsetWidth / 2); | 					content: '%i18n:@pin%', | ||||||
| 				const y = rect.top + window.pageYOffset + (this.source.offsetHeight / 2); | 					onClick: this.pin | ||||||
| 				popover.style.left = (x - (width / 2)) + 'px'; | 				}); | ||||||
| 				popover.style.top = (y - (height / 2)) + 'px'; | 				items.push({ | ||||||
| 			} else { | 					content: '%i18n:@delete%', | ||||||
| 				const x = rect.left + window.pageXOffset + (this.source.offsetWidth / 2); | 					onClick: this.del | ||||||
| 				const y = rect.top + window.pageYOffset + this.source.offsetHeight; | 				}); | ||||||
| 				popover.style.left = (x - (width / 2)) + 'px'; |  | ||||||
| 				popover.style.top = y + 'px'; |  | ||||||
| 			} | 			} | ||||||
|  | 			if (this.note.uri) { | ||||||
| 			anime({ | 				items.push({ | ||||||
| 				targets: this.$refs.backdrop, | 					content: '%i18n:@remote%', | ||||||
| 				opacity: 1, | 					onClick: () => { | ||||||
| 				duration: 100, | 						window.open(this.note.uri, '_blank'); | ||||||
| 				easing: 'linear' | 					} | ||||||
| 			}); | 				}); | ||||||
|  | 			} | ||||||
| 			anime({ | 			return items; | ||||||
| 				targets: this.$refs.popover, | 		} | ||||||
| 				opacity: 1, |  | ||||||
| 				scale: [0.5, 1], |  | ||||||
| 				duration: 500 |  | ||||||
| 			}); |  | ||||||
| 		}); |  | ||||||
| 	}, | 	}, | ||||||
| 	methods: { | 	methods: { | ||||||
| 		pin() { | 		pin() { | ||||||
| @@ -78,98 +64,8 @@ export default Vue.extend({ | |||||||
| 		}, | 		}, | ||||||
|  |  | ||||||
| 		close() { | 		close() { | ||||||
| 			(this.$refs.backdrop as any).style.pointerEvents = 'none'; | 			this.$refs.menu.close(); | ||||||
| 			anime({ |  | ||||||
| 				targets: this.$refs.backdrop, |  | ||||||
| 				opacity: 0, |  | ||||||
| 				duration: 200, |  | ||||||
| 				easing: 'linear' |  | ||||||
| 			}); |  | ||||||
|  |  | ||||||
| 			(this.$refs.popover as any).style.pointerEvents = 'none'; |  | ||||||
| 			anime({ |  | ||||||
| 				targets: this.$refs.popover, |  | ||||||
| 				opacity: 0, |  | ||||||
| 				scale: 0.5, |  | ||||||
| 				duration: 200, |  | ||||||
| 				easing: 'easeInBack', |  | ||||||
| 				complete: () => this.$destroy() |  | ||||||
| 			}); |  | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| }); | }); | ||||||
| </script> | </script> | ||||||
|  |  | ||||||
| <style lang="stylus" scoped> |  | ||||||
| @import '~const.styl' |  | ||||||
|  |  | ||||||
| $border-color = rgba(27, 31, 35, 0.15) |  | ||||||
|  |  | ||||||
| .mk-note-menu |  | ||||||
| 	position initial |  | ||||||
|  |  | ||||||
| 	> .backdrop |  | ||||||
| 		position fixed |  | ||||||
| 		top 0 |  | ||||||
| 		left 0 |  | ||||||
| 		z-index 10000 |  | ||||||
| 		width 100% |  | ||||||
| 		height 100% |  | ||||||
| 		background rgba(#000, 0.1) |  | ||||||
| 		opacity 0 |  | ||||||
|  |  | ||||||
| 	> .popover |  | ||||||
| 		position absolute |  | ||||||
| 		z-index 10001 |  | ||||||
| 		padding 8px 0 |  | ||||||
| 		background #fff |  | ||||||
| 		border 1px solid $border-color |  | ||||||
| 		border-radius 4px |  | ||||||
| 		box-shadow 0 3px 12px rgba(27, 31, 35, 0.15) |  | ||||||
| 		transform scale(0.5) |  | ||||||
| 		opacity 0 |  | ||||||
|  |  | ||||||
| 		$balloon-size = 16px |  | ||||||
|  |  | ||||||
| 		&:not(.compact) |  | ||||||
| 			margin-top $balloon-size |  | ||||||
| 			transform-origin center -($balloon-size) |  | ||||||
|  |  | ||||||
| 			&:before |  | ||||||
| 				content "" |  | ||||||
| 				display block |  | ||||||
| 				position absolute |  | ||||||
| 				top -($balloon-size * 2) |  | ||||||
| 				left s('calc(50% - %s)', $balloon-size) |  | ||||||
| 				border-top solid $balloon-size transparent |  | ||||||
| 				border-left solid $balloon-size transparent |  | ||||||
| 				border-right solid $balloon-size transparent |  | ||||||
| 				border-bottom solid $balloon-size $border-color |  | ||||||
|  |  | ||||||
| 			&:after |  | ||||||
| 				content "" |  | ||||||
| 				display block |  | ||||||
| 				position absolute |  | ||||||
| 				top -($balloon-size * 2) + 1.5px |  | ||||||
| 				left s('calc(50% - %s)', $balloon-size) |  | ||||||
| 				border-top solid $balloon-size transparent |  | ||||||
| 				border-left solid $balloon-size transparent |  | ||||||
| 				border-right solid $balloon-size transparent |  | ||||||
| 				border-bottom solid $balloon-size #fff |  | ||||||
|  |  | ||||||
| 		> button |  | ||||||
| 		> a |  | ||||||
| 			display block |  | ||||||
| 			padding 8px 16px |  | ||||||
| 			width 100% |  | ||||||
|  |  | ||||||
| 			&:hover |  | ||||||
| 				color $theme-color-foreground |  | ||||||
| 				background $theme-color |  | ||||||
| 				text-decoration none |  | ||||||
|  |  | ||||||
| 			&:active |  | ||||||
| 				color $theme-color-foreground |  | ||||||
| 				background darken($theme-color, 10%) |  | ||||||
|  |  | ||||||
| </style> |  | ||||||
|   | |||||||
| @@ -2,6 +2,7 @@ | |||||||
| <div class="dnpfarvgbnfmyzbdquhhzyxcmstpdqzs"> | <div class="dnpfarvgbnfmyzbdquhhzyxcmstpdqzs"> | ||||||
| 	<header :class="{ indicate }"> | 	<header :class="{ indicate }"> | ||||||
| 		<slot name="header"></slot> | 		<slot name="header"></slot> | ||||||
|  | 		<button ref="menu" @click="menu">%fa:caret-down%</button> | ||||||
| 	</header> | 	</header> | ||||||
| 	<div ref="body"> | 	<div ref="body"> | ||||||
| 		<slot></slot> | 		<slot></slot> | ||||||
| @@ -11,8 +12,16 @@ | |||||||
|  |  | ||||||
| <script lang="ts"> | <script lang="ts"> | ||||||
| import Vue from 'vue'; | import Vue from 'vue'; | ||||||
|  | import Menu from '../../../../common/views/components/menu.vue'; | ||||||
|  |  | ||||||
| export default Vue.extend({ | export default Vue.extend({ | ||||||
|  | 	props: { | ||||||
|  | 		id: { | ||||||
|  | 			type: String, | ||||||
|  | 			required: false | ||||||
|  | 		} | ||||||
|  | 	}, | ||||||
|  |  | ||||||
| 	data() { | 	data() { | ||||||
| 		return { | 		return { | ||||||
| 			indicate: false | 			indicate: false | ||||||
| @@ -48,6 +57,29 @@ export default Vue.extend({ | |||||||
| 				const current = this.$refs.body.scrollTop + this.$refs.body.clientHeight; | 				const current = this.$refs.body.scrollTop + this.$refs.body.clientHeight; | ||||||
| 				if (current > this.$refs.body.scrollHeight - 1) this.$emit('bottom'); | 				if (current > this.$refs.body.scrollHeight - 1) this.$emit('bottom'); | ||||||
| 			} | 			} | ||||||
|  | 		}, | ||||||
|  |  | ||||||
|  | 		menu() { | ||||||
|  | 			this.os.new(Menu, { | ||||||
|  | 				source: this.$refs.menu, | ||||||
|  | 				compact: false, | ||||||
|  | 				items: [{ | ||||||
|  | 					content: '%fa:arrow-left% %i18n:@swap-left%', | ||||||
|  | 					onClick: () => { | ||||||
|  | 						this.$store.dispatch('settings/swapLeftDeckColumn', this.id); | ||||||
|  | 					} | ||||||
|  | 				}, { | ||||||
|  | 					content: '%fa:arrow-right% %i18n:@swap-right%', | ||||||
|  | 					onClick: () => { | ||||||
|  | 						this.$store.dispatch('settings/swapRightDeckColumn', this.id); | ||||||
|  | 					} | ||||||
|  | 				}, { | ||||||
|  | 					content: '%fa:trash-alt R% %i18n:@remove%', | ||||||
|  | 					onClick: () => { | ||||||
|  | 						this.$store.dispatch('settings/removeDeckColumn', this.id); | ||||||
|  | 					} | ||||||
|  | 				}] | ||||||
|  | 			}); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| }); | }); | ||||||
| @@ -57,6 +89,8 @@ export default Vue.extend({ | |||||||
| @import '~const.styl' | @import '~const.styl' | ||||||
|  |  | ||||||
| root(isDark) | root(isDark) | ||||||
|  | 	$header-height = 42px | ||||||
|  |  | ||||||
| 	flex 1 | 	flex 1 | ||||||
| 	min-width 330px | 	min-width 330px | ||||||
| 	max-width 330px | 	max-width 330px | ||||||
| @@ -68,7 +102,7 @@ root(isDark) | |||||||
|  |  | ||||||
| 	> header | 	> header | ||||||
| 		z-index 1 | 		z-index 1 | ||||||
| 		line-height 42px | 		line-height $header-height | ||||||
| 		padding 0 16px | 		padding 0 16px | ||||||
| 		color isDark ? #e3e5e8 : #888 | 		color isDark ? #e3e5e8 : #888 | ||||||
| 		background isDark ? #313543 : #fff | 		background isDark ? #313543 : #fff | ||||||
| @@ -77,8 +111,26 @@ root(isDark) | |||||||
| 		&.indicate | 		&.indicate | ||||||
| 			box-shadow 0 3px 0 0 $theme-color | 			box-shadow 0 3px 0 0 $theme-color | ||||||
|  |  | ||||||
|  | 		> span | ||||||
|  | 			[data-fa] | ||||||
|  | 				margin-right 8px | ||||||
|  |  | ||||||
|  | 		> button | ||||||
|  | 			position absolute | ||||||
|  | 			top 0 | ||||||
|  | 			right 0 | ||||||
|  | 			width $header-height | ||||||
|  | 			line-height $header-height | ||||||
|  | 			color isDark ? #9baec8 : #ccc | ||||||
|  |  | ||||||
|  | 			&:hover | ||||||
|  | 				color isDark ? #b2c1d5 : #aaa | ||||||
|  |  | ||||||
|  | 			&:active | ||||||
|  | 				color isDark ? #b2c1d5 : #999 | ||||||
|  |  | ||||||
| 	> div | 	> div | ||||||
| 		height calc(100% - 42px) | 		height calc(100% - $header-height) | ||||||
| 		overflow auto | 		overflow auto | ||||||
| 		overflow-x hidden | 		overflow-x hidden | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										103
									
								
								src/client/app/desktop/views/pages/deck/deck.list-tl.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								src/client/app/desktop/views/pages/deck/deck.list-tl.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,103 @@ | |||||||
|  | <template> | ||||||
|  | 	<x-notes ref="timeline" :more="existMore ? more : null"/> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script lang="ts"> | ||||||
|  | import Vue from 'vue'; | ||||||
|  | import XNotes from './deck.notes.vue'; | ||||||
|  | import { UserListStream } from '../../../../common/scripts/streaming/user-list'; | ||||||
|  |  | ||||||
|  | const fetchLimit = 10; | ||||||
|  |  | ||||||
|  | export default Vue.extend({ | ||||||
|  | 	components: { | ||||||
|  | 		XNotes | ||||||
|  | 	}, | ||||||
|  |  | ||||||
|  | 	props: { | ||||||
|  | 		list: { | ||||||
|  | 			type: Object, | ||||||
|  | 			required: true | ||||||
|  | 		} | ||||||
|  | 	}, | ||||||
|  |  | ||||||
|  | 	data() { | ||||||
|  | 		return { | ||||||
|  | 			fetching: true, | ||||||
|  | 			moreFetching: false, | ||||||
|  | 			existMore: false, | ||||||
|  | 			connection: null | ||||||
|  | 		}; | ||||||
|  | 	}, | ||||||
|  |  | ||||||
|  | 	mounted() { | ||||||
|  | 		if (this.connection) this.connection.close(); | ||||||
|  | 		this.connection = new UserListStream((this as any).os, this.$store.state.i, this.list.id); | ||||||
|  | 		this.connection.on('note', this.onNote); | ||||||
|  | 		this.connection.on('userAdded', this.onUserAdded); | ||||||
|  | 		this.connection.on('userRemoved', this.onUserRemoved); | ||||||
|  |  | ||||||
|  | 		this.fetch(); | ||||||
|  | 	}, | ||||||
|  |  | ||||||
|  | 	beforeDestroy() { | ||||||
|  | 		this.connection.close(); | ||||||
|  | 	}, | ||||||
|  |  | ||||||
|  | 	methods: { | ||||||
|  | 		fetch() { | ||||||
|  | 			this.fetching = true; | ||||||
|  |  | ||||||
|  | 			(this.$refs.timeline as any).init(() => new Promise((res, rej) => { | ||||||
|  | 				(this as any).api('notes/user-list-timeline', { | ||||||
|  | 					listId: this.list.id, | ||||||
|  | 					limit: fetchLimit + 1, | ||||||
|  | 					includeMyRenotes: this.$store.state.settings.showMyRenotes, | ||||||
|  | 					includeRenotedMyNotes: this.$store.state.settings.showRenotedMyNotes | ||||||
|  | 				}).then(notes => { | ||||||
|  | 					if (notes.length == fetchLimit + 1) { | ||||||
|  | 						notes.pop(); | ||||||
|  | 						this.existMore = true; | ||||||
|  | 					} | ||||||
|  | 					res(notes); | ||||||
|  | 					this.fetching = false; | ||||||
|  | 					this.$emit('loaded'); | ||||||
|  | 				}, rej); | ||||||
|  | 			})); | ||||||
|  | 		}, | ||||||
|  | 		more() { | ||||||
|  | 			this.moreFetching = true; | ||||||
|  |  | ||||||
|  | 			const promise = (this as any).api('notes/user-list-timeline', { | ||||||
|  | 				listId: this.list.id, | ||||||
|  | 				limit: fetchLimit + 1, | ||||||
|  | 				untilId: (this.$refs.timeline as any).tail().id, | ||||||
|  | 				includeMyRenotes: this.$store.state.settings.showMyRenotes, | ||||||
|  | 				includeRenotedMyNotes: this.$store.state.settings.showRenotedMyNotes | ||||||
|  | 			}); | ||||||
|  |  | ||||||
|  | 			promise.then(notes => { | ||||||
|  | 				if (notes.length == fetchLimit + 1) { | ||||||
|  | 					notes.pop(); | ||||||
|  | 				} else { | ||||||
|  | 					this.existMore = false; | ||||||
|  | 				} | ||||||
|  | 				notes.forEach(n => (this.$refs.timeline as any).append(n)); | ||||||
|  | 				this.moreFetching = false; | ||||||
|  | 			}); | ||||||
|  |  | ||||||
|  | 			return promise; | ||||||
|  | 		}, | ||||||
|  | 		onNote(note) { | ||||||
|  | 			// Prepend a note | ||||||
|  | 			(this.$refs.timeline as any).prepend(note); | ||||||
|  | 		}, | ||||||
|  | 		onUserAdded() { | ||||||
|  | 			this.fetch(); | ||||||
|  | 		}, | ||||||
|  | 		onUserRemoved() { | ||||||
|  | 			this.fetch(); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | }); | ||||||
|  | </script> | ||||||
| @@ -1,6 +1,6 @@ | |||||||
| <template> | <template> | ||||||
| <div> | <div> | ||||||
| 	<x-column> | 	<x-column :id="id"> | ||||||
| 		<span slot="header">%fa:bell R% %i18n:@notifications%</span> | 		<span slot="header">%fa:bell R% %i18n:@notifications%</span> | ||||||
|  |  | ||||||
| 		<x-notifications/> | 		<x-notifications/> | ||||||
| @@ -17,6 +17,13 @@ export default Vue.extend({ | |||||||
| 	components: { | 	components: { | ||||||
| 		XColumn, | 		XColumn, | ||||||
| 		XNotifications | 		XNotifications | ||||||
|  | 	}, | ||||||
|  |  | ||||||
|  | 	props: { | ||||||
|  | 		id: { | ||||||
|  | 			type: String, | ||||||
|  | 			required: true | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
| }); | }); | ||||||
| </script> | </script> | ||||||
|   | |||||||
| @@ -1,13 +1,15 @@ | |||||||
| <template> | <template> | ||||||
| <div> | <div> | ||||||
| 	<x-column> | 	<x-column :id="column.id"> | ||||||
| 		<span slot="header"> | 		<span slot="header"> | ||||||
| 			<template v-if="src == 'home'">%fa:home% %i18n:@home%</template> | 			<template v-if="column.type == 'home'">%fa:home%%i18n:@home%</template> | ||||||
| 			<template v-if="src == 'local'">%fa:R comments% %i18n:@local%</template> | 			<template v-if="column.type == 'local'">%fa:R comments%%i18n:@local%</template> | ||||||
| 			<template v-if="src == 'global'">%fa:globe% %i18n:@global%</template> | 			<template v-if="column.type == 'global'">%fa:globe%%i18n:@global%</template> | ||||||
| 			<template v-if="src == 'list'">%fa:list% {{ list.title }}</template> | 			<template v-if="column.type == 'list'">%fa:list%{{ column.list.title }}</template> | ||||||
| 		</span> | 		</span> | ||||||
| 		<x-tl :src="src"/> |  | ||||||
|  | 		<x-list-tl v-if="column.type == 'list'" :list="column.list"/> | ||||||
|  | 		<x-tl v-else :src="column.type"/> | ||||||
| 	</x-column> | 	</x-column> | ||||||
| </div> | </div> | ||||||
| </template> | </template> | ||||||
| @@ -16,18 +18,20 @@ | |||||||
| import Vue from 'vue'; | import Vue from 'vue'; | ||||||
| import XColumn from './deck.column.vue'; | import XColumn from './deck.column.vue'; | ||||||
| import XTl from './deck.tl.vue'; | import XTl from './deck.tl.vue'; | ||||||
|  | import XListTl from './deck.list-tl.vue'; | ||||||
|  |  | ||||||
| export default Vue.extend({ | export default Vue.extend({ | ||||||
| 	components: { | 	components: { | ||||||
| 		XColumn, | 		XColumn, | ||||||
| 		XTl | 		XTl, | ||||||
|  | 		XListTl | ||||||
| 	}, | 	}, | ||||||
|  |  | ||||||
| 	props: { | 	props: { | ||||||
| 		src: { | 		column: { | ||||||
| 			type: String, | 			type: Object, | ||||||
| 			required: false | 			required: true | ||||||
| 		} | 		} | ||||||
| 	}, | 	} | ||||||
| }); | }); | ||||||
| </script> | </script> | ||||||
|   | |||||||
| @@ -27,9 +27,7 @@ export default Vue.extend({ | |||||||
| 			moreFetching: false, | 			moreFetching: false, | ||||||
| 			existMore: false, | 			existMore: false, | ||||||
| 			connection: null, | 			connection: null, | ||||||
| 			connectionId: null, | 			connectionId: null | ||||||
| 			unreadCount: 0, |  | ||||||
| 			date: null |  | ||||||
| 		}; | 		}; | ||||||
| 	}, | 	}, | ||||||
|  |  | ||||||
| @@ -74,17 +72,12 @@ export default Vue.extend({ | |||||||
| 	}, | 	}, | ||||||
|  |  | ||||||
| 	methods: { | 	methods: { | ||||||
| 		mount(root) { |  | ||||||
| 			this.$refs.timeline.mount(root); |  | ||||||
| 		}, |  | ||||||
|  |  | ||||||
| 		fetch() { | 		fetch() { | ||||||
| 			this.fetching = true; | 			this.fetching = true; | ||||||
|  |  | ||||||
| 			(this.$refs.timeline as any).init(() => new Promise((res, rej) => { | 			(this.$refs.timeline as any).init(() => new Promise((res, rej) => { | ||||||
| 				(this as any).api(this.endpoint, { | 				(this as any).api(this.endpoint, { | ||||||
| 					limit: fetchLimit + 1, | 					limit: fetchLimit + 1, | ||||||
| 					untilDate: this.date ? this.date.getTime() : undefined, |  | ||||||
| 					includeMyRenotes: this.$store.state.settings.showMyRenotes, | 					includeMyRenotes: this.$store.state.settings.showMyRenotes, | ||||||
| 					includeRenotedMyNotes: this.$store.state.settings.showRenotedMyNotes | 					includeRenotedMyNotes: this.$store.state.settings.showRenotedMyNotes | ||||||
| 				}).then(notes => { | 				}).then(notes => { | ||||||
|   | |||||||
| @@ -2,12 +2,13 @@ | |||||||
| <mk-ui :class="$style.root"> | <mk-ui :class="$style.root"> | ||||||
| 	<div class="qlvquzbjribqcaozciifydkngcwtyzje" :data-darkmode="$store.state.device.darkmode"> | 	<div class="qlvquzbjribqcaozciifydkngcwtyzje" :data-darkmode="$store.state.device.darkmode"> | ||||||
| 		<template v-for="column in columns"> | 		<template v-for="column in columns"> | ||||||
| 			<x-notifications-column v-if="column.type == 'notifications'" :key="column.id"/> | 			<x-notifications-column v-if="column.type == 'notifications'" :key="column.id" :id="column.id"/> | ||||||
| 			<x-tl-column v-if="column.type == 'home'" :key="column.id" src="home"/> | 			<x-tl-column v-if="column.type == 'home'" :key="column.id" :column="column"/> | ||||||
| 			<x-tl-column v-if="column.type == 'local'" :key="column.id" src="local"/> | 			<x-tl-column v-if="column.type == 'local'" :key="column.id" :column="column"/> | ||||||
| 			<x-tl-column v-if="column.type == 'global'" :key="column.id" src="global"/> | 			<x-tl-column v-if="column.type == 'global'" :key="column.id" :column="column"/> | ||||||
|  | 			<x-tl-column v-if="column.type == 'list'" :key="column.id" :column="column"/> | ||||||
| 		</template> | 		</template> | ||||||
| 		<button>%fa:plus%</button> | 		<button ref="add" @click="add">%fa:plus%</button> | ||||||
| 	</div> | 	</div> | ||||||
| </mk-ui> | </mk-ui> | ||||||
| </template> | </template> | ||||||
| @@ -16,6 +17,8 @@ | |||||||
| import Vue from 'vue'; | import Vue from 'vue'; | ||||||
| import XTlColumn from './deck.tl-column.vue'; | import XTlColumn from './deck.tl-column.vue'; | ||||||
| import XNotificationsColumn from './deck.notifications-column.vue'; | import XNotificationsColumn from './deck.notifications-column.vue'; | ||||||
|  | import Menu from '../../../../common/views/components/menu.vue'; | ||||||
|  | import MkUserListsWindow from '../../components/user-lists-window.vue'; | ||||||
| import * as uuid from 'uuid'; | import * as uuid from 'uuid'; | ||||||
|  |  | ||||||
| export default Vue.extend({ | export default Vue.extend({ | ||||||
| @@ -55,6 +58,61 @@ export default Vue.extend({ | |||||||
| 				value: deck | 				value: deck | ||||||
| 			}); | 			}); | ||||||
| 		} | 		} | ||||||
|  | 	}, | ||||||
|  |  | ||||||
|  | 	methods: { | ||||||
|  | 		add() { | ||||||
|  | 			this.os.new(Menu, { | ||||||
|  | 				source: this.$refs.add, | ||||||
|  | 				compact: true, | ||||||
|  | 				items: [{ | ||||||
|  | 					content: '%i18n:@home%', | ||||||
|  | 					onClick: () => { | ||||||
|  | 						this.$store.dispatch('settings/addDeckColumn', { | ||||||
|  | 							id: uuid(), | ||||||
|  | 							type: 'home' | ||||||
|  | 						}); | ||||||
|  | 					} | ||||||
|  | 				}, { | ||||||
|  | 					content: '%i18n:@local%', | ||||||
|  | 					onClick: () => { | ||||||
|  | 						this.$store.dispatch('settings/addDeckColumn', { | ||||||
|  | 							id: uuid(), | ||||||
|  | 							type: 'local' | ||||||
|  | 						}); | ||||||
|  | 					} | ||||||
|  | 				}, { | ||||||
|  | 					content: '%i18n:@global%', | ||||||
|  | 					onClick: () => { | ||||||
|  | 						this.$store.dispatch('settings/addDeckColumn', { | ||||||
|  | 							id: uuid(), | ||||||
|  | 							type: 'global' | ||||||
|  | 						}); | ||||||
|  | 					} | ||||||
|  | 				}, { | ||||||
|  | 					content: '%i18n:@list%', | ||||||
|  | 					onClick: () => { | ||||||
|  | 						const w = (this as any).os.new(MkUserListsWindow); | ||||||
|  | 						w.$once('choosen', list => { | ||||||
|  | 							this.$store.dispatch('settings/addDeckColumn', { | ||||||
|  | 								id: uuid(), | ||||||
|  | 								type: 'list', | ||||||
|  | 								list: list | ||||||
|  | 							}); | ||||||
|  | 							w.close(); | ||||||
|  | 						}); | ||||||
|  | 					} | ||||||
|  | 				}, { | ||||||
|  | 					content: '%i18n:@notifications%', | ||||||
|  | 					onClick: () => { | ||||||
|  | 						this.$store.dispatch('settings/addDeckColumn', { | ||||||
|  | 							id: uuid(), | ||||||
|  | 							type: 'notifications' | ||||||
|  | 						}); | ||||||
|  | 					} | ||||||
|  | 				}] | ||||||
|  | 			}); | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
| }); | }); | ||||||
| </script> | </script> | ||||||
|   | |||||||
| @@ -73,12 +73,12 @@ export default class MiOS extends EventEmitter { | |||||||
| 	public app: Vue; | 	public app: Vue; | ||||||
|  |  | ||||||
| 	public new(vm, props) { | 	public new(vm, props) { | ||||||
| 		const w = new vm({ | 		const x = new vm({ | ||||||
| 			parent: this.app, | 			parent: this.app, | ||||||
| 			propsData: props | 			propsData: props | ||||||
| 		}).$mount(); | 		}).$mount(); | ||||||
| 		document.body.appendChild(w.$el); | 		document.body.appendChild(x.$el); | ||||||
| 		return w; | 		return x; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
|   | |||||||
| @@ -152,6 +152,44 @@ export default (os: MiOS) => new Vuex.Store({ | |||||||
|  |  | ||||||
| 				removeMobileHomeWidget(state, widget) { | 				removeMobileHomeWidget(state, widget) { | ||||||
| 					state.mobileHome = state.mobileHome.filter(w => w.id != widget.id); | 					state.mobileHome = state.mobileHome.filter(w => w.id != widget.id); | ||||||
|  | 				}, | ||||||
|  |  | ||||||
|  | 				addDeckColumn(state, column) { | ||||||
|  | 					if (state.deck.columns == null) state.deck.columns = []; | ||||||
|  | 					state.deck.columns.push(column); | ||||||
|  | 				}, | ||||||
|  |  | ||||||
|  | 				removeDeckColumn(state, id) { | ||||||
|  | 					if (state.deck.columns == null) return; | ||||||
|  | 					state.deck.columns = state.deck.columns.filter(c => c.id != id); | ||||||
|  | 				}, | ||||||
|  |  | ||||||
|  | 				swapLeftDeckColumn(state, id) { | ||||||
|  | 					if (state.deck.columns == null) return; | ||||||
|  | 					state.deck.columns.some((c, i) => { | ||||||
|  | 						if (c.id == id) { | ||||||
|  | 							const left = state.deck.columns[i - 1]; | ||||||
|  | 							if (left) { | ||||||
|  | 								state.deck.columns[i - 1] = state.deck.columns[i]; | ||||||
|  | 								state.deck.columns[i] = left; | ||||||
|  | 							} | ||||||
|  | 							return true; | ||||||
|  | 						} | ||||||
|  | 					}); | ||||||
|  | 				}, | ||||||
|  |  | ||||||
|  | 				swapRightDeckColumn(state, id) { | ||||||
|  | 					if (state.deck.columns == null) return; | ||||||
|  | 					state.deck.columns.some((c, i) => { | ||||||
|  | 						if (c.id == id) { | ||||||
|  | 							const right = state.deck.columns[i + 1]; | ||||||
|  | 							if (right) { | ||||||
|  | 								state.deck.columns[i + 1] = state.deck.columns[i]; | ||||||
|  | 								state.deck.columns[i] = right; | ||||||
|  | 							} | ||||||
|  | 							return true; | ||||||
|  | 						} | ||||||
|  | 					}); | ||||||
| 				} | 				} | ||||||
| 			}, | 			}, | ||||||
|  |  | ||||||
| @@ -174,6 +212,42 @@ export default (os: MiOS) => new Vuex.Store({ | |||||||
| 					} | 					} | ||||||
| 				}, | 				}, | ||||||
|  |  | ||||||
|  | 				addDeckColumn(ctx, column) { | ||||||
|  | 					ctx.commit('addDeckColumn', column); | ||||||
|  |  | ||||||
|  | 					os.api('i/update_client_setting', { | ||||||
|  | 						name: 'deck', | ||||||
|  | 						value: ctx.state.deck | ||||||
|  | 					}); | ||||||
|  | 				}, | ||||||
|  |  | ||||||
|  | 				removeDeckColumn(ctx, id) { | ||||||
|  | 					ctx.commit('removeDeckColumn', id); | ||||||
|  |  | ||||||
|  | 					os.api('i/update_client_setting', { | ||||||
|  | 						name: 'deck', | ||||||
|  | 						value: ctx.state.deck | ||||||
|  | 					}); | ||||||
|  | 				}, | ||||||
|  |  | ||||||
|  | 				swapLeftDeckColumn(ctx, id) { | ||||||
|  | 					ctx.commit('swapLeftDeckColumn', id); | ||||||
|  |  | ||||||
|  | 					os.api('i/update_client_setting', { | ||||||
|  | 						name: 'deck', | ||||||
|  | 						value: ctx.state.deck | ||||||
|  | 					}); | ||||||
|  | 				}, | ||||||
|  |  | ||||||
|  | 				swapRightDeckColumn(ctx, id) { | ||||||
|  | 					ctx.commit('swapRightDeckColumn', id); | ||||||
|  |  | ||||||
|  | 					os.api('i/update_client_setting', { | ||||||
|  | 						name: 'deck', | ||||||
|  | 						value: ctx.state.deck | ||||||
|  | 					}); | ||||||
|  | 				}, | ||||||
|  |  | ||||||
| 				addHomeWidget(ctx, widget) { | 				addHomeWidget(ctx, widget) { | ||||||
| 					ctx.commit('addHomeWidget', widget); | 					ctx.commit('addHomeWidget', widget); | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 syuilo
					syuilo