wip
This commit is contained in:
		
							parent
							
								
									0d8c83f27c
								
							
						
					
					
						commit
						69b5de3346
					
				|  | @ -1,6 +1,7 @@ | |||
| import Vue from 'vue'; | ||||
| 
 | ||||
| import analogClock from './analog-clock.vue'; | ||||
| import menu from './menu.vue'; | ||||
| import signin from './signin.vue'; | ||||
| import signup from './signup.vue'; | ||||
| import forkit from './forkit.vue'; | ||||
|  | @ -29,6 +30,7 @@ import Othello from './othello.vue'; | |||
| import welcomeTimeline from './welcome-timeline.vue'; | ||||
| 
 | ||||
| Vue.component('mk-analog-clock', analogClock); | ||||
| Vue.component('mk-menu', menu); | ||||
| Vue.component('mk-signin', signin); | ||||
| Vue.component('mk-signup', signup); | ||||
| Vue.component('mk-forkit', forkit); | ||||
|  |  | |||
|  | @ -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> | ||||
| <div class="mk-note-menu"> | ||||
| 	<div class="backdrop" ref="backdrop" @click="close"></div> | ||||
| 	<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 class="mk-note-menu" style="position:initial"> | ||||
| 	<mk-menu ref="menu" :source="source" :compact="compact" :items="items" @closed="$destroy"/> | ||||
| </div> | ||||
| </template> | ||||
| 
 | ||||
| <script lang="ts"> | ||||
| import Vue from 'vue'; | ||||
| import * as anime from 'animejs'; | ||||
| 
 | ||||
| export default Vue.extend({ | ||||
| 	props: ['note', 'source', 'compact'], | ||||
| 	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'; | ||||
| 	computed: { | ||||
| 		items() { | ||||
| 			const items = []; | ||||
| 			items.push({ | ||||
| 				content: '%i18n:@favorite%', | ||||
| 				onClick: this.favorite | ||||
| 			}); | ||||
| 			if (this.note.userId == this.$store.state.i.id) { | ||||
| 				items.push({ | ||||
| 					content: '%i18n:@pin%', | ||||
| 					onClick: this.pin | ||||
| 				}); | ||||
| 				items.push({ | ||||
| 					content: '%i18n:@delete%', | ||||
| 					onClick: this.del | ||||
| 				}); | ||||
| 			} | ||||
| 
 | ||||
| 			anime({ | ||||
| 				targets: this.$refs.backdrop, | ||||
| 				opacity: 1, | ||||
| 				duration: 100, | ||||
| 				easing: 'linear' | ||||
| 			}); | ||||
| 
 | ||||
| 			anime({ | ||||
| 				targets: this.$refs.popover, | ||||
| 				opacity: 1, | ||||
| 				scale: [0.5, 1], | ||||
| 				duration: 500 | ||||
| 			}); | ||||
| 		}); | ||||
| 			if (this.note.uri) { | ||||
| 				items.push({ | ||||
| 					content: '%i18n:@remote%', | ||||
| 					onClick: () => { | ||||
| 						window.open(this.note.uri, '_blank'); | ||||
| 					} | ||||
| 				}); | ||||
| 			} | ||||
| 			return items; | ||||
| 		} | ||||
| 	}, | ||||
| 	methods: { | ||||
| 		pin() { | ||||
|  | @ -78,98 +64,8 @@ export default Vue.extend({ | |||
| 		}, | ||||
| 
 | ||||
| 		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.$destroy() | ||||
| 			}); | ||||
| 			this.$refs.menu.close(); | ||||
| 		} | ||||
| 	} | ||||
| }); | ||||
| </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"> | ||||
| 	<header :class="{ indicate }"> | ||||
| 		<slot name="header"></slot> | ||||
| 		<button ref="menu" @click="menu">%fa:caret-down%</button> | ||||
| 	</header> | ||||
| 	<div ref="body"> | ||||
| 		<slot></slot> | ||||
|  | @ -11,8 +12,16 @@ | |||
| 
 | ||||
| <script lang="ts"> | ||||
| import Vue from 'vue'; | ||||
| import Menu from '../../../../common/views/components/menu.vue'; | ||||
| 
 | ||||
| export default Vue.extend({ | ||||
| 	props: { | ||||
| 		id: { | ||||
| 			type: String, | ||||
| 			required: false | ||||
| 		} | ||||
| 	}, | ||||
| 
 | ||||
| 	data() { | ||||
| 		return { | ||||
| 			indicate: false | ||||
|  | @ -48,6 +57,29 @@ export default Vue.extend({ | |||
| 				const current = this.$refs.body.scrollTop + this.$refs.body.clientHeight; | ||||
| 				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' | ||||
| 
 | ||||
| root(isDark) | ||||
| 	$header-height = 42px | ||||
| 
 | ||||
| 	flex 1 | ||||
| 	min-width 330px | ||||
| 	max-width 330px | ||||
|  | @ -68,7 +102,7 @@ root(isDark) | |||
| 
 | ||||
| 	> header | ||||
| 		z-index 1 | ||||
| 		line-height 42px | ||||
| 		line-height $header-height | ||||
| 		padding 0 16px | ||||
| 		color isDark ? #e3e5e8 : #888 | ||||
| 		background isDark ? #313543 : #fff | ||||
|  | @ -77,8 +111,26 @@ root(isDark) | |||
| 		&.indicate | ||||
| 			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 | ||||
| 		height calc(100% - 42px) | ||||
| 		height calc(100% - $header-height) | ||||
| 		overflow auto | ||||
| 		overflow-x hidden | ||||
| 
 | ||||
|  |  | |||
|  | @ -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> | ||||
| <div> | ||||
| 	<x-column> | ||||
| 	<x-column :id="id"> | ||||
| 		<span slot="header">%fa:bell R% %i18n:@notifications%</span> | ||||
| 
 | ||||
| 		<x-notifications/> | ||||
|  | @ -17,6 +17,13 @@ export default Vue.extend({ | |||
| 	components: { | ||||
| 		XColumn, | ||||
| 		XNotifications | ||||
| 	}, | ||||
| 
 | ||||
| 	props: { | ||||
| 		id: { | ||||
| 			type: String, | ||||
| 			required: true | ||||
| 		} | ||||
| 	} | ||||
| }); | ||||
| </script> | ||||
|  |  | |||
|  | @ -1,13 +1,15 @@ | |||
| <template> | ||||
| <div> | ||||
| 	<x-column> | ||||
| 	<x-column :id="column.id"> | ||||
| 		<span slot="header"> | ||||
| 			<template v-if="src == 'home'">%fa:home% %i18n:@home%</template> | ||||
| 			<template v-if="src == 'local'">%fa:R comments% %i18n:@local%</template> | ||||
| 			<template v-if="src == 'global'">%fa:globe% %i18n:@global%</template> | ||||
| 			<template v-if="src == 'list'">%fa:list% {{ list.title }}</template> | ||||
| 			<template v-if="column.type == 'home'">%fa:home%%i18n:@home%</template> | ||||
| 			<template v-if="column.type == 'local'">%fa:R comments%%i18n:@local%</template> | ||||
| 			<template v-if="column.type == 'global'">%fa:globe%%i18n:@global%</template> | ||||
| 			<template v-if="column.type == 'list'">%fa:list%{{ column.list.title }}</template> | ||||
| 		</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> | ||||
| </div> | ||||
| </template> | ||||
|  | @ -16,18 +18,20 @@ | |||
| import Vue from 'vue'; | ||||
| import XColumn from './deck.column.vue'; | ||||
| import XTl from './deck.tl.vue'; | ||||
| import XListTl from './deck.list-tl.vue'; | ||||
| 
 | ||||
| export default Vue.extend({ | ||||
| 	components: { | ||||
| 		XColumn, | ||||
| 		XTl | ||||
| 		XTl, | ||||
| 		XListTl | ||||
| 	}, | ||||
| 
 | ||||
| 	props: { | ||||
| 		src: { | ||||
| 			type: String, | ||||
| 			required: false | ||||
| 		column: { | ||||
| 			type: Object, | ||||
| 			required: true | ||||
| 		} | ||||
| 	}, | ||||
| 	} | ||||
| }); | ||||
| </script> | ||||
|  |  | |||
|  | @ -27,9 +27,7 @@ export default Vue.extend({ | |||
| 			moreFetching: false, | ||||
| 			existMore: false, | ||||
| 			connection: null, | ||||
| 			connectionId: null, | ||||
| 			unreadCount: 0, | ||||
| 			date: null | ||||
| 			connectionId: null | ||||
| 		}; | ||||
| 	}, | ||||
| 
 | ||||
|  | @ -74,17 +72,12 @@ export default Vue.extend({ | |||
| 	}, | ||||
| 
 | ||||
| 	methods: { | ||||
| 		mount(root) { | ||||
| 			this.$refs.timeline.mount(root); | ||||
| 		}, | ||||
| 
 | ||||
| 		fetch() { | ||||
| 			this.fetching = true; | ||||
| 
 | ||||
| 			(this.$refs.timeline as any).init(() => new Promise((res, rej) => { | ||||
| 				(this as any).api(this.endpoint, { | ||||
| 					limit: fetchLimit + 1, | ||||
| 					untilDate: this.date ? this.date.getTime() : undefined, | ||||
| 					includeMyRenotes: this.$store.state.settings.showMyRenotes, | ||||
| 					includeRenotedMyNotes: this.$store.state.settings.showRenotedMyNotes | ||||
| 				}).then(notes => { | ||||
|  |  | |||
|  | @ -2,12 +2,13 @@ | |||
| <mk-ui :class="$style.root"> | ||||
| 	<div class="qlvquzbjribqcaozciifydkngcwtyzje" :data-darkmode="$store.state.device.darkmode"> | ||||
| 		<template v-for="column in columns"> | ||||
| 			<x-notifications-column v-if="column.type == 'notifications'" :key="column.id"/> | ||||
| 			<x-tl-column v-if="column.type == 'home'" :key="column.id" src="home"/> | ||||
| 			<x-tl-column v-if="column.type == 'local'" :key="column.id" src="local"/> | ||||
| 			<x-tl-column v-if="column.type == 'global'" :key="column.id" src="global"/> | ||||
| 			<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" :column="column"/> | ||||
| 			<x-tl-column v-if="column.type == 'local'" :key="column.id" :column="column"/> | ||||
| 			<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> | ||||
| 		<button>%fa:plus%</button> | ||||
| 		<button ref="add" @click="add">%fa:plus%</button> | ||||
| 	</div> | ||||
| </mk-ui> | ||||
| </template> | ||||
|  | @ -16,6 +17,8 @@ | |||
| import Vue from 'vue'; | ||||
| import XTlColumn from './deck.tl-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'; | ||||
| 
 | ||||
| export default Vue.extend({ | ||||
|  | @ -55,6 +58,61 @@ export default Vue.extend({ | |||
| 				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> | ||||
|  |  | |||
|  | @ -73,12 +73,12 @@ export default class MiOS extends EventEmitter { | |||
| 	public app: Vue; | ||||
| 
 | ||||
| 	public new(vm, props) { | ||||
| 		const w = new vm({ | ||||
| 		const x = new vm({ | ||||
| 			parent: this.app, | ||||
| 			propsData: props | ||||
| 		}).$mount(); | ||||
| 		document.body.appendChild(w.$el); | ||||
| 		return w; | ||||
| 		document.body.appendChild(x.$el); | ||||
| 		return x; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
|  |  | |||
|  | @ -152,6 +152,44 @@ export default (os: MiOS) => new Vuex.Store({ | |||
| 
 | ||||
| 				removeMobileHomeWidget(state, widget) { | ||||
| 					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) { | ||||
| 					ctx.commit('addHomeWidget', widget); | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue