wip
This commit is contained in:
		
							parent
							
								
									4705c935ab
								
							
						
					
					
						commit
						0c9a7cf643
					
				
					 8 changed files with 161 additions and 162 deletions
				
			
		
							
								
								
									
										17
									
								
								.eslintrc
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								.eslintrc
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,17 @@ | |||
| { | ||||
| 	"parserOptions": { | ||||
| 		"parser": "typescript-eslint-parser" | ||||
| 	}, | ||||
| 	"extends": [ | ||||
| 		"eslint:recommended", | ||||
| 		"plugin:vue/recommended" | ||||
| 	], | ||||
| 	"rules": { | ||||
| 		"vue/require-v-for-key": false, | ||||
| 		"vue/max-attributes-per-line": false, | ||||
| 		"vue/html-indent": false, | ||||
| 		"vue/html-self-closing": false, | ||||
| 		"vue/no-unused-vars": false, | ||||
| 		"no-console": 0 | ||||
| 	} | ||||
| } | ||||
|  | @ -99,6 +99,8 @@ | |||
| 		"diskusage": "0.2.4", | ||||
| 		"elasticsearch": "14.1.0", | ||||
| 		"escape-regexp": "0.0.1", | ||||
| 		"eslint": "^4.18.0", | ||||
| 		"eslint-plugin-vue": "^4.2.2", | ||||
| 		"eventemitter3": "3.0.0", | ||||
| 		"exif-js": "2.3.0", | ||||
| 		"express": "4.16.2", | ||||
|  | @ -174,6 +176,7 @@ | |||
| 		"ts-node": "4.1.0", | ||||
| 		"tslint": "5.9.1", | ||||
| 		"typescript": "2.7.1", | ||||
| 		"typescript-eslint-parser": "^13.0.0", | ||||
| 		"uglify-es": "3.3.9", | ||||
| 		"uglifyjs-webpack-plugin": "1.1.8", | ||||
| 		"uuid": "3.2.1", | ||||
|  |  | |||
|  | @ -1,23 +0,0 @@ | |||
| <mk-timemachine-home-widget> | ||||
| 	<mk-calendar-widget design={ data.design } warp={ warp }/> | ||||
| 	<style lang="stylus" scoped> | ||||
| 		:scope | ||||
| 			display block | ||||
| 	</style> | ||||
| 	<script lang="typescript"> | ||||
| 		this.data = { | ||||
| 			design: 0 | ||||
| 		}; | ||||
| 
 | ||||
| 		this.mixin('widget'); | ||||
| 
 | ||||
| 		this.warp = date => { | ||||
| 			this.opts.tl.warp(date); | ||||
| 		}; | ||||
| 
 | ||||
| 		this.func = () => { | ||||
| 			if (++this.data.design == 6) this.data.design = 0; | ||||
| 			this.save(); | ||||
| 		}; | ||||
| 	</script> | ||||
| </mk-timemachine-home-widget> | ||||
|  | @ -7,16 +7,15 @@ | |||
| 	</template> | ||||
| 
 | ||||
| 	<div class="calendar"> | ||||
| 		<template v-if="design == 0 || design == 2 || design == 4"> | ||||
| 		<div class="weekday" | ||||
| 			v-if="design == 0 || design == 2 || design == 4" | ||||
| 			v-for="(day, i) in Array(7).fill(0)" | ||||
| 			:key="i" | ||||
| 			:data-today="year == today.getFullYear() && month == today.getMonth() + 1 && today.getDay() == i" | ||||
| 			:data-is-donichi="i == 0 || i == 6" | ||||
| 		>{{ weekdayText[i] }}</div> | ||||
| 		<div each={ day, i in Array(paddingDays).fill(0) }></div> | ||||
| 		<div class="day" v-for="(day, i) in Array(days).fill(0)" | ||||
| 			:key="i" | ||||
| 		</template> | ||||
| 		<div v-for="n in paddingDays"></div> | ||||
| 		<div class="day" v-for="(day, i) in days" | ||||
| 			:data-today="isToday(i + 1)" | ||||
| 			:data-selected="isSelected(i + 1)" | ||||
| 			:data-is-out-of-range="isOutOfRange(i + 1)" | ||||
|  |  | |||
|  | @ -37,43 +37,21 @@ | |||
| 		</div> | ||||
| 	</div> | ||||
| 	<div class="main"> | ||||
| 		<div class="left"> | ||||
| 			<div ref="left" data-place="left"> | ||||
| 				<template v-for="widget in leftWidgets"> | ||||
| 		<div v-for="place in ['left', 'main', 'right']" :class="place" :ref="place" :data-place="place"> | ||||
| 			<template v-if="place != 'main'"> | ||||
| 				<template v-for="widget in widgets[place]"> | ||||
| 					<div class="customize-container" v-if="customize" :key="widget.id" @contextmenu.stop.prevent="onWidgetContextmenu(widget.id)"> | ||||
| 						<component :is="'mkw-' + widget.name" :widget="widget" :ref="widget.id"/> | ||||
| 						<component :is="`mkw-${widget.name}`" :widget="widget" :ref="widget.id"/> | ||||
| 					</div> | ||||
| 					<template v-else> | ||||
| 						<component :is="'mkw-' + widget.name" :key="widget.id" :widget="widget" :ref="widget.id"/> | ||||
| 						<component :is="`mkw-${widget.name}`" :key="widget.id" :widget="widget" :ref="widget.id" @chosen="warp"/> | ||||
| 					</template> | ||||
| 				</template> | ||||
| 			</div> | ||||
| 		</div> | ||||
| 		<main ref="main"> | ||||
| 			<div class="maintop" ref="maintop" data-place="main" v-if="customize"> | ||||
| 				<template v-for="widget in centerWidgets"> | ||||
| 					<div class="customize-container" v-if="customize" :key="widget.id" @contextmenu.stop.prevent="onWidgetContextmenu(widget.id)"> | ||||
| 						<component :is="'mkw-' + widget.name" :widget="widget" :ref="widget.id"/> | ||||
| 					</div> | ||||
| 					<template v-else> | ||||
| 						<component :is="'mkw-' + widget.name" :key="widget.id" :widget="widget" :ref="widget.id"/> | ||||
| 					</template> | ||||
| 				</template> | ||||
| 			</div> | ||||
| 			<mk-timeline ref="tl" @loaded="onTlLoaded" v-if="mode == 'timeline'"/> | ||||
| 			<mk-mentions ref="tl" @loaded="onTlLoaded" v-if="mode == 'mentions'"/> | ||||
| 		</main> | ||||
| 		<div class="right"> | ||||
| 			<div ref="right" data-place="right"> | ||||
| 				<template v-for="widget in rightWidgets"> | ||||
| 					<div class="customize-container" v-if="customize" :key="widget.id" @contextmenu.stop.prevent="onWidgetContextmenu(widget.id)"> | ||||
| 						<component :is="'mkw-' + widget.name" :widget="widget" :ref="widget.id"/> | ||||
| 					</div> | ||||
| 					<template v-else> | ||||
| 						<component :is="'mkw-' + widget.name" :key="widget.id" :widget="widget" :ref="widget.id"/> | ||||
| 					</template> | ||||
| 				</template> | ||||
| 			</div> | ||||
| 			</template> | ||||
| 			<template v-else> | ||||
| 				<mk-timeline ref="tl" @loaded="onTlLoaded" v-if="place == 'main' && mode == 'timeline'"/> | ||||
| 				<mk-mentions @loaded="onTlLoaded" v-if="place == 'main' && mode == 'mentions'"/> | ||||
| 			</template> | ||||
| 		</div> | ||||
| 	</div> | ||||
| </div> | ||||
|  | @ -99,6 +77,85 @@ export default Vue.extend({ | |||
| 			widgetAdderSelected: null | ||||
| 		}; | ||||
| 	}, | ||||
| 	computed: { | ||||
| 		leftWidgets(): any { | ||||
| 			return (this as any).os.i.client_settings.home.filter(w => w.place == 'left'); | ||||
| 		}, | ||||
| 		rightWidgets(): any { | ||||
| 			return (this as any).os.i.client_settings.home.filter(w => w.place == 'right'); | ||||
| 		}, | ||||
| 		widgets(): any { | ||||
| 			return { | ||||
| 				left: this.leftWidgets, | ||||
| 				right: this.rightWidgets, | ||||
| 			}; | ||||
| 		}, | ||||
| 		leftEl(): Element { | ||||
| 			return (this.$refs.left as Element[])[0]; | ||||
| 		}, | ||||
| 		rightEl(): Element { | ||||
| 			return (this.$refs.right as Element[])[0]; | ||||
| 		} | ||||
| 	}, | ||||
| 	created() { | ||||
| 		this.bakedHomeData = this.bakeHomeData(); | ||||
| 	}, | ||||
| 	mounted() { | ||||
| 		(this as any).os.i.on('refreshed', this.onMeRefreshed); | ||||
| 
 | ||||
| 		this.home = (this as any).os.i.client_settings.home; | ||||
| 
 | ||||
| 		this.$nextTick(() => { | ||||
| 			if (!this.customize) { | ||||
| 				if (this.leftEl.children.length == 0) { | ||||
| 					this.leftEl.parentNode.removeChild(this.leftEl); | ||||
| 				} | ||||
| 				if (this.rightEl.children.length == 0) { | ||||
| 					this.rightEl.parentNode.removeChild(this.rightEl); | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			if (this.customize) { | ||||
| 				(this as any).apis.dialog({ | ||||
| 					title: '%fa:info-circle%カスタマイズのヒント', | ||||
| 					text: '<p>ホームのカスタマイズでは、ウィジェットを追加/削除したり、ドラッグ&ドロップして並べ替えたりすることができます。</p>' + | ||||
| 						'<p>一部のウィジェットは、<strong><strong>右</strong>クリック</strong>することで表示を変更することができます。</p>' + | ||||
| 						'<p>ウィジェットを削除するには、ヘッダーの<strong>「ゴミ箱」</strong>と書かれたエリアにウィジェットをドラッグ&ドロップします。</p>' + | ||||
| 						'<p>カスタマイズを終了するには、右上の「完了」をクリックします。</p>', | ||||
| 					actions: [{ | ||||
| 						text: 'Got it!' | ||||
| 					}] | ||||
| 				}); | ||||
| 
 | ||||
| 				const sortableOption = { | ||||
| 					group: 'kyoppie', | ||||
| 					animation: 150, | ||||
| 					onMove: evt => { | ||||
| 						const id = evt.dragged.getAttribute('data-widget-id'); | ||||
| 						this.home.find(tag => tag.id == id).widget.place = evt.to.getAttribute('data-place'); | ||||
| 					}, | ||||
| 					onSort: () => { | ||||
| 						this.saveHome(); | ||||
| 					} | ||||
| 				}; | ||||
| 
 | ||||
| 				new Sortable(this.leftEl, sortableOption); | ||||
| 				new Sortable(this.rightEl, sortableOption); | ||||
| 				new Sortable(this.$refs.trash, Object.assign({}, sortableOption, { | ||||
| 					onAdd: evt => { | ||||
| 						const el = evt.item; | ||||
| 						const id = el.getAttribute('data-widget-id'); | ||||
| 						el.parentNode.removeChild(el); | ||||
| 						(this as any).os.i.client_settings.home = (this as any).os.i.client_settings.home.filter(w => w.id != id); | ||||
| 						this.saveHome(); | ||||
| 					} | ||||
| 				})); | ||||
| 			} | ||||
| 		}); | ||||
| 	}, | ||||
| 	beforeDestroy() { | ||||
| 		(this as any).os.i.off('refreshed', this.onMeRefreshed); | ||||
| 	}, | ||||
| 	methods: { | ||||
| 		bakeHomeData() { | ||||
| 			return JSON.stringify((this as any).os.i.client_settings.home); | ||||
|  | @ -130,102 +187,27 @@ export default Vue.extend({ | |||
| 		saveHome() { | ||||
| 			const data = []; | ||||
| 
 | ||||
| 			Array.from((this.$refs.left as Element).children).forEach(el => { | ||||
| 			Array.from(this.leftEl.children).forEach(el => { | ||||
| 				const id = el.getAttribute('data-widget-id'); | ||||
| 				const widget = (this as any).os.i.client_settings.home.find(w => w.id == id); | ||||
| 				widget.place = 'left'; | ||||
| 				data.push(widget); | ||||
| 			}); | ||||
| 
 | ||||
| 			Array.from((this.$refs.right as Element).children).forEach(el => { | ||||
| 			Array.from(this.rightEl.children).forEach(el => { | ||||
| 				const id = el.getAttribute('data-widget-id'); | ||||
| 				const widget = (this as any).os.i.client_settings.home.find(w => w.id == id); | ||||
| 				widget.place = 'right'; | ||||
| 				data.push(widget); | ||||
| 			}); | ||||
| 
 | ||||
| 			Array.from((this.$refs.maintop as Element).children).forEach(el => { | ||||
| 				const id = el.getAttribute('data-widget-id'); | ||||
| 				const widget = (this as any).os.i.client_settings.home.find(w => w.id == id); | ||||
| 				widget.place = 'main'; | ||||
| 				data.push(widget); | ||||
| 			}); | ||||
| 
 | ||||
| 			(this as any).api('i/update_home', { | ||||
| 				home: data | ||||
| 			}); | ||||
| 		} | ||||
| 	}, | ||||
| 	computed: { | ||||
| 		leftWidgets(): any { | ||||
| 			return (this as any).os.i.client_settings.home.filter(w => w.place == 'left'); | ||||
| 		}, | ||||
| 		centerWidgets(): any { | ||||
| 			return (this as any).os.i.client_settings.home.filter(w => w.place == 'center'); | ||||
| 		}, | ||||
| 		rightWidgets(): any { | ||||
| 			return (this as any).os.i.client_settings.home.filter(w => w.place == 'right'); | ||||
| 		warp(date) { | ||||
| 			(this.$refs.tl as any)[0].warp(date); | ||||
| 		} | ||||
| 	}, | ||||
| 	created() { | ||||
| 		this.bakedHomeData = this.bakeHomeData(); | ||||
| 	}, | ||||
| 	mounted() { | ||||
| 		(this as any).os.i.on('refreshed', this.onMeRefreshed); | ||||
| 
 | ||||
| 		this.home = (this as any).os.i.client_settings.home; | ||||
| 
 | ||||
| 		if (!this.customize) { | ||||
| 			if ((this.$refs.left as Element).children.length == 0) { | ||||
| 				(this.$refs.left as Element).parentNode.removeChild((this.$refs.left as Element)); | ||||
| 			} | ||||
| 			if ((this.$refs.right as Element).children.length == 0) { | ||||
| 				(this.$refs.right as Element).parentNode.removeChild((this.$refs.right as Element)); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		if (this.customize) { | ||||
| 			/*dialog('%fa:info-circle%カスタマイズのヒント', | ||||
| 				'<p>ホームのカスタマイズでは、ウィジェットを追加/削除したり、ドラッグ&ドロップして並べ替えたりすることができます。</p>' + | ||||
| 				'<p>一部のウィジェットは、<strong><strong>右</strong>クリック</strong>することで表示を変更することができます。</p>' + | ||||
| 				'<p>ウィジェットを削除するには、ヘッダーの<strong>「ゴミ箱」</strong>と書かれたエリアにウィジェットをドラッグ&ドロップします。</p>' + | ||||
| 				'<p>カスタマイズを終了するには、右上の「完了」をクリックします。</p>', | ||||
| 			[{ | ||||
| 				text: 'Got it!' | ||||
| 			}]);*/ | ||||
| 
 | ||||
| 			const sortableOption = { | ||||
| 				group: 'kyoppie', | ||||
| 				animation: 150, | ||||
| 				onMove: evt => { | ||||
| 					const id = evt.dragged.getAttribute('data-widget-id'); | ||||
| 					this.home.find(tag => tag.id == id).update({ place: evt.to.getAttribute('data-place') }); | ||||
| 				}, | ||||
| 				onSort: () => { | ||||
| 					this.saveHome(); | ||||
| 				} | ||||
| 			}; | ||||
| 
 | ||||
| 			new Sortable(this.$refs.left, sortableOption); | ||||
| 			new Sortable(this.$refs.right, sortableOption); | ||||
| 			new Sortable(this.$refs.maintop, sortableOption); | ||||
| 			new Sortable(this.$refs.trash, Object.assign({}, sortableOption, { | ||||
| 				onAdd: evt => { | ||||
| 					const el = evt.item; | ||||
| 					const id = el.getAttribute('data-widget-id'); | ||||
| 					el.parentNode.removeChild(el); | ||||
| 					(this as any).os.i.client_settings.home = (this as any).os.i.client_settings.home.filter(w => w.id != id); | ||||
| 					this.saveHome(); | ||||
| 				} | ||||
| 			})); | ||||
| 		} | ||||
| 	}, | ||||
| 	beforeDestroy() { | ||||
| 		(this as any).os.i.off('refreshed', this.onMeRefreshed); | ||||
| 
 | ||||
| 		this.home.forEach(widget => { | ||||
| 			widget.unmount(); | ||||
| 		}); | ||||
| 	} | ||||
| }); | ||||
| </script> | ||||
|  | @ -324,26 +306,16 @@ export default Vue.extend({ | |||
| 				> * | ||||
| 					pointer-events none | ||||
| 
 | ||||
| 		> main | ||||
| 		> .main | ||||
| 			padding 16px | ||||
| 			width calc(100% - 275px * 2) | ||||
| 
 | ||||
| 			> *:not(.maintop):not(:last-child) | ||||
| 			> .maintop > *:not(:last-child) | ||||
| 				margin-bottom 16px | ||||
| 
 | ||||
| 			> .maintop | ||||
| 				min-height 64px | ||||
| 				margin-bottom 16px | ||||
| 
 | ||||
| 		> *:not(main) | ||||
| 			width 275px | ||||
| 			padding 16px 0 16px 0 | ||||
| 
 | ||||
| 			> * | ||||
| 				padding 16px 0 16px 0 | ||||
| 
 | ||||
| 				> *:not(:last-child) | ||||
| 					margin-bottom 16px | ||||
| 			> *:not(:last-child) | ||||
| 				margin-bottom 16px | ||||
| 
 | ||||
| 		> .left | ||||
| 			padding-left 16px | ||||
|  | @ -355,7 +327,7 @@ export default Vue.extend({ | |||
| 			> *:not(main) | ||||
| 				display none | ||||
| 
 | ||||
| 			> main | ||||
| 			> .main | ||||
| 				float none | ||||
| 				width 100% | ||||
| 				max-width 700px | ||||
|  |  | |||
|  | @ -33,6 +33,7 @@ import driveFolder from './drive-folder.vue'; | |||
| import driveNavFolder from './drive-nav-folder.vue'; | ||||
| import postDetail from './post-detail.vue'; | ||||
| import settings from './settings.vue'; | ||||
| import calendar from './calendar.vue'; | ||||
| import wNav from './widgets/nav.vue'; | ||||
| import wCalendar from './widgets/calendar.vue'; | ||||
| import wPhotoStream from './widgets/photo-stream.vue'; | ||||
|  | @ -41,6 +42,7 @@ import wTips from './widgets/tips.vue'; | |||
| import wDonation from './widgets/donation.vue'; | ||||
| import wNotifications from './widgets/notifications.vue'; | ||||
| import wBroadcast from './widgets/broadcast.vue'; | ||||
| import wTimemachine from './widgets/timemachine.vue'; | ||||
| 
 | ||||
| Vue.component('mk-ui', ui); | ||||
| Vue.component('mk-ui-header', uiHeader); | ||||
|  | @ -75,6 +77,7 @@ Vue.component('mk-drive-folder', driveFolder); | |||
| Vue.component('mk-drive-nav-folder', driveNavFolder); | ||||
| Vue.component('mk-post-detail', postDetail); | ||||
| Vue.component('mk-settings', settings); | ||||
| Vue.component('mk-calendar', calendar); | ||||
| Vue.component('mkw-nav', wNav); | ||||
| Vue.component('mkw-calendar', wCalendar); | ||||
| Vue.component('mkw-photo-stream', wPhotoStream); | ||||
|  | @ -83,3 +86,4 @@ Vue.component('mkw-tips', wTips); | |||
| Vue.component('mkw-donation', wDonation); | ||||
| Vue.component('mkw-notifications', wNotifications); | ||||
| Vue.component('mkw-broadcast', wBroadcast); | ||||
| Vue.component('mkw-timemachine', wTimemachine); | ||||
|  |  | |||
|  | @ -13,19 +13,14 @@ | |||
| import Vue from 'vue'; | ||||
| 
 | ||||
| export default Vue.extend({ | ||||
| 	props: { | ||||
| 		date: { | ||||
| 			type: Date, | ||||
| 			required: false | ||||
| 		} | ||||
| 	}, | ||||
| 	data() { | ||||
| 		return { | ||||
| 			fetching: true, | ||||
| 			moreFetching: false, | ||||
| 			posts: [], | ||||
| 			connection: null, | ||||
| 			connectionId: null | ||||
| 			connectionId: null, | ||||
| 			date: null | ||||
| 		}; | ||||
| 	}, | ||||
| 	computed: { | ||||
|  | @ -60,7 +55,7 @@ export default Vue.extend({ | |||
| 			this.fetching = true; | ||||
| 
 | ||||
| 			(this as any).api('posts/timeline', { | ||||
| 				until_date: this.date ? (this.date as any).getTime() : undefined | ||||
| 				until_date: this.date ? this.date.getTime() : undefined | ||||
| 			}).then(posts => { | ||||
| 				this.fetching = false; | ||||
| 				this.posts = posts; | ||||
|  | @ -93,6 +88,10 @@ export default Vue.extend({ | |||
| 					(this.$refs.timeline as any).focus(); | ||||
| 				} | ||||
| 			} | ||||
| 		}, | ||||
| 		warp(date) { | ||||
| 			this.date = date; | ||||
| 			this.fetch(); | ||||
| 		} | ||||
| 	} | ||||
| }); | ||||
|  |  | |||
							
								
								
									
										28
									
								
								src/web/app/desktop/views/components/widgets/timemachine.vue
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								src/web/app/desktop/views/components/widgets/timemachine.vue
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,28 @@ | |||
| <template> | ||||
| <div class="mkw-timemachine"> | ||||
| 	<mk-calendar :design="props.design" @chosen="chosen"/> | ||||
| </div> | ||||
| </template> | ||||
| 
 | ||||
| <script lang="ts"> | ||||
| import define from '../../../../common/define-widget'; | ||||
| export default define({ | ||||
| 	name: 'timemachine', | ||||
| 	props: { | ||||
| 		design: 0 | ||||
| 	} | ||||
| }).extend({ | ||||
| 	methods: { | ||||
| 		chosen(date) { | ||||
| 			this.$emit('chosen', date); | ||||
| 		}, | ||||
| 		func() { | ||||
| 			if (this.props.design == 5) { | ||||
| 				this.props.design = 0; | ||||
| 			} else { | ||||
| 				this.props.design++; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| }); | ||||
| </script> | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue