wip
This commit is contained in:
		
							parent
							
								
									80eefa92ce
								
							
						
					
					
						commit
						0336d640ec
					
				
					 7 changed files with 155 additions and 56 deletions
				
			
		|  | @ -1,6 +1,6 @@ | |||
| <template> | ||||
| <div | ||||
| 	class="note _panel" | ||||
| 	class="tkcbzcuz _panel" | ||||
| 	v-if="!muted" | ||||
| 	v-show="!isDeleted" | ||||
| 	:tabindex="!isDeleted ? '-1' : null" | ||||
|  | @ -858,7 +858,7 @@ export default defineComponent({ | |||
| </script> | ||||
| 
 | ||||
| <style lang="scss" scoped> | ||||
| .note { | ||||
| .tkcbzcuz { | ||||
| 	position: relative; | ||||
| 	transition: box-shadow 0.1s ease; | ||||
| 	overflow: hidden; | ||||
|  |  | |||
|  | @ -13,12 +13,10 @@ export default { | |||
| 			const viewHeight = container.clientHeight; | ||||
| 			const height = container.scrollHeight; | ||||
| 			isBottom = (pos + viewHeight > height - 32); | ||||
| 			console.log(isBottom); | ||||
| 		}, { passive: true }); | ||||
| 		container.scrollTop = container.scrollHeight; | ||||
| 
 | ||||
| 		const ro = new ResizeObserver((entries, observer) => { | ||||
| 			console.log(isBottom); | ||||
| 			if (isBottom) { | ||||
| 				const height = container.scrollHeight; | ||||
| 				container.scrollTop = height; | ||||
|  |  | |||
|  | @ -120,6 +120,20 @@ export default defineComponent({ | |||
| .hmjzthxl { | ||||
| 	> .separator { | ||||
| 		text-align: center; | ||||
| 		position: relative; | ||||
| 
 | ||||
| 		&:before { | ||||
| 			content: ""; | ||||
| 			display: block; | ||||
| 			position: absolute; | ||||
| 			top: 50%; | ||||
| 			left: 0; | ||||
| 			right: 0; | ||||
| 			margin: auto; | ||||
| 			width: calc(100% - 32px); | ||||
| 			height: 1px; | ||||
| 			background: var(--divider); | ||||
| 		} | ||||
| 
 | ||||
| 		> .date { | ||||
| 			display: inline-block; | ||||
|  | @ -130,6 +144,7 @@ export default defineComponent({ | |||
| 			text-align: center; | ||||
| 			font-size: 12px; | ||||
| 			color: var(--dateLabelFg); | ||||
| 			background: var(--panel); | ||||
| 
 | ||||
| 			> span { | ||||
| 				&:first-child { | ||||
|  |  | |||
							
								
								
									
										44
									
								
								src/client/ui/chat/header-clock.vue
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								src/client/ui/chat/header-clock.vue
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,44 @@ | |||
| <template> | ||||
| <div class="_monospace"> | ||||
| 	<span> | ||||
| 		<span v-text="hh"></span> | ||||
| 		<span :style="{ visibility: showColon ? 'visible' : 'hidden' }">:</span> | ||||
| 		<span v-text="mm"></span> | ||||
| 		<span :style="{ visibility: showColon ? 'visible' : 'hidden' }">:</span> | ||||
| 		<span v-text="ss"></span> | ||||
| 	</span> | ||||
| </div> | ||||
| </template> | ||||
| 
 | ||||
| <script lang="ts"> | ||||
| import { defineComponent } from 'vue'; | ||||
| import * as os from '@/os'; | ||||
| 
 | ||||
| export default defineComponent({ | ||||
| 	data() { | ||||
| 		return { | ||||
| 			clock: null, | ||||
| 			hh: null, | ||||
| 			mm: null, | ||||
| 			ss: null, | ||||
| 			showColon: true, | ||||
| 		}; | ||||
| 	}, | ||||
| 	created() { | ||||
| 		this.tick(); | ||||
| 		this.clock = setInterval(this.tick, 1000); | ||||
| 	}, | ||||
| 	beforeUnmount() { | ||||
| 		clearInterval(this.clock); | ||||
| 	}, | ||||
| 	methods: { | ||||
| 		tick() { | ||||
| 			const now = new Date(); | ||||
| 			this.hh = now.getHours().toString().padStart(2, '0'); | ||||
| 			this.mm = now.getMinutes().toString().padStart(2, '0'); | ||||
| 			this.ss = now.getSeconds().toString().padStart(2, '0'); | ||||
| 			this.showColon = now.getSeconds() % 2 === 0; | ||||
| 		} | ||||
| 	} | ||||
| }); | ||||
| </script> | ||||
|  | @ -62,21 +62,27 @@ | |||
| 
 | ||||
| 	<main class="main" @contextmenu.stop="onContextmenu"> | ||||
| 		<header class="header" ref="header" @click="onHeaderClick"> | ||||
| 			<div v-if="tl === 'home'"> | ||||
| 				<Fa :icon="faHome" class="icon"/> | ||||
| 				<div class="title">{{ $ts._timelines.home }}</div> | ||||
| 			<div class="left"> | ||||
| 				<template v-if="tl === 'home'"> | ||||
| 					<Fa :icon="faHome" class="icon"/> | ||||
| 					<div class="title">{{ $ts._timelines.home }}</div> | ||||
| 				</template> | ||||
| 				<template v-else-if="tl === 'local'"> | ||||
| 					<Fa :icon="faShareAlt" class="icon"/> | ||||
| 					<div class="title">{{ $ts._timelines.local }}</div> | ||||
| 				</template> | ||||
| 				<template v-else-if="tl === 'social'"> | ||||
| 					<Fa :icon="faShareAlt" class="icon"/> | ||||
| 					<div class="title">{{ $ts._timelines.social }}</div> | ||||
| 				</template> | ||||
| 				<template v-else-if="tl === 'global'"> | ||||
| 					<Fa :icon="faShareAlt" class="icon"/> | ||||
| 					<div class="title">{{ $ts._timelines.global }}</div> | ||||
| 				</template> | ||||
| 			</div> | ||||
| 			<div v-else-if="tl === 'local'"> | ||||
| 				<Fa :icon="faShareAlt" class="icon"/> | ||||
| 				<div class="title">{{ $ts._timelines.local }}</div> | ||||
| 			</div> | ||||
| 			<div v-else-if="tl === 'social'"> | ||||
| 				<Fa :icon="faShareAlt" class="icon"/> | ||||
| 				<div class="title">{{ $ts._timelines.social }}</div> | ||||
| 			</div> | ||||
| 			<div v-else-if="tl === 'global'"> | ||||
| 				<Fa :icon="faShareAlt" class="icon"/> | ||||
| 				<div class="title">{{ $ts._timelines.global }}</div> | ||||
| 
 | ||||
| 			<div class="right"> | ||||
| 				<XHeaderClock/> | ||||
| 			</div> | ||||
| 		</header> | ||||
| 		<div class="body"> | ||||
|  | @ -105,6 +111,7 @@ import XCommon from '../_common_/common.vue'; | |||
| import XSide from './side.vue'; | ||||
| import XTimeline from './timeline.vue'; | ||||
| import XPostForm from './post-form.vue'; | ||||
| import XHeaderClock from './header-clock.vue'; | ||||
| import * as os from '@/os'; | ||||
| import { sidebarDef } from '@/sidebar'; | ||||
| 
 | ||||
|  | @ -115,6 +122,7 @@ export default defineComponent({ | |||
| 		XSide, // NOTE: dynamic importするとAsyncComponentWrapperが間に入るせいでref取得できなくて面倒になる | ||||
| 		XTimeline, | ||||
| 		XPostForm, | ||||
| 		XHeaderClock, | ||||
| 	}, | ||||
| 
 | ||||
| 	provide() { | ||||
|  | @ -260,6 +268,29 @@ export default defineComponent({ | |||
| 				border-top: solid 1px var(--divider); | ||||
| 			} | ||||
| 
 | ||||
| 			> .left, > .right { | ||||
| 				> .item, > .menu { | ||||
| 					height: ($header-height - ($padding * 2)); | ||||
| 					width: ($header-height - ($padding * 2)); | ||||
| 					padding: 10px; | ||||
| 					box-sizing: border-box; | ||||
| 					margin-right: 4px; | ||||
| 					//opacity: 0.6; | ||||
| 					position: relative; | ||||
| 					line-height: initial; | ||||
| 
 | ||||
| 					> i { | ||||
| 						position: absolute; | ||||
| 						top: 8px; | ||||
| 						right: 8px; | ||||
| 						color: var(--indicator); | ||||
| 						font-size: 8px; | ||||
| 						line-height: 8px; | ||||
| 						animation: blink 1s infinite; | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			> .left { | ||||
| 				> .account { | ||||
| 					display: flex; | ||||
|  | @ -276,26 +307,6 @@ export default defineComponent({ | |||
| 
 | ||||
| 			> .right { | ||||
| 				margin-left: auto; | ||||
| 
 | ||||
| 				> .item { | ||||
| 					height: ($header-height - ($padding * 2)); | ||||
| 					width: ($header-height - ($padding * 2)); | ||||
| 					padding: 10px; | ||||
| 					box-sizing: border-box; | ||||
| 					margin-right: 4px; | ||||
| 					//opacity: 0.6; | ||||
| 					position: relative; | ||||
| 
 | ||||
| 					> i { | ||||
| 						position: absolute; | ||||
| 						top: 8px; | ||||
| 						right: 8px; | ||||
| 						color: var(--indicator); | ||||
| 						font-size: 8px; | ||||
| 						line-height: 8px; | ||||
| 						animation: blink 1s infinite; | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
|  | @ -358,18 +369,19 @@ export default defineComponent({ | |||
| 
 | ||||
| 		> .header { | ||||
| 			$padding: 8px; | ||||
| 			display: flex; | ||||
| 			z-index: 1000; | ||||
| 			height: $header-height; | ||||
| 			padding: $padding; | ||||
| 			box-sizing: border-box; | ||||
| 			line-height: ($header-height - ($padding * 2)); | ||||
| 			font-weight: bold; | ||||
| 			background-color: var(--panel); | ||||
| 			border-bottom: solid 1px var(--divider); | ||||
| 			user-select: none; | ||||
| 
 | ||||
| 			> div { | ||||
| 			> .left { | ||||
| 				display: flex; | ||||
| 				font-weight: bold; | ||||
| 
 | ||||
| 				> .icon { | ||||
| 					height: ($header-height - ($padding * 2)); | ||||
|  | @ -380,10 +392,15 @@ export default defineComponent({ | |||
| 					opacity: 0.6; | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			> .right { | ||||
| 				margin-left: auto; | ||||
| 				padding: 0 8px; | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		> .footer { | ||||
| 			padding: 16px; | ||||
| 			padding: 0 16px 16px 16px; | ||||
| 		} | ||||
| 
 | ||||
| 		> .body { | ||||
|  |  | |||
|  | @ -1,10 +1,10 @@ | |||
| <template> | ||||
| <div | ||||
| 	class="note" | ||||
| 	class="vfzoeqcg" | ||||
| 	v-if="!muted" | ||||
| 	v-show="!isDeleted" | ||||
| 	:tabindex="!isDeleted ? '-1' : null" | ||||
| 	:class="{ renote: isRenote }" | ||||
| 	:class="{ renote: isRenote, operating }" | ||||
| 	v-hotkey="keymap" | ||||
| > | ||||
| 	<XSub :note="appearNote.reply" class="reply-to" v-if="appearNote.reply"/> | ||||
|  | @ -171,6 +171,7 @@ export default defineComponent({ | |||
| 			collapsed: false, | ||||
| 			isDeleted: false, | ||||
| 			muted: false, | ||||
| 			operating: false, | ||||
| 			faEdit, faBolt, faTimes, faBullhorn, faPlus, faMinus, faRetweet, faReply, faReplyAll, faEllipsisH, faHome, faUnlock, faEnvelope, faThumbtack, faBan, faBiohazard, faPlug, faSatelliteDish | ||||
| 		}; | ||||
| 	}, | ||||
|  | @ -439,16 +440,19 @@ export default defineComponent({ | |||
| 
 | ||||
| 		reply(viaKeyboard = false) { | ||||
| 			pleaseLogin(); | ||||
| 			this.operating = true; | ||||
| 			os.post({ | ||||
| 				reply: this.appearNote, | ||||
| 				animation: !viaKeyboard, | ||||
| 			}, () => { | ||||
| 				this.operating = false; | ||||
| 				this.focus(); | ||||
| 			}); | ||||
| 		}, | ||||
| 
 | ||||
| 		renote(viaKeyboard = false) { | ||||
| 			pleaseLogin(); | ||||
| 			this.operating = true; | ||||
| 			this.blur(); | ||||
| 			os.modalMenu([{ | ||||
| 				text: this.$ts.renote, | ||||
|  | @ -468,6 +472,8 @@ export default defineComponent({ | |||
| 				} | ||||
| 			}], this.$refs.renoteButton, { | ||||
| 				viaKeyboard | ||||
| 			}).then(() => { | ||||
| 				this.operating = false; | ||||
| 			}); | ||||
| 		}, | ||||
| 
 | ||||
|  | @ -494,10 +500,11 @@ export default defineComponent({ | |||
| 			}); | ||||
| 		}, | ||||
| 
 | ||||
| 		react(viaKeyboard = false) { | ||||
| 		async react(viaKeyboard = false) { | ||||
| 			pleaseLogin(); | ||||
| 			this.operating = true; | ||||
| 			this.blur(); | ||||
| 			os.popup(import('@/components/emoji-picker.vue'), { | ||||
| 			const { dispose } = await os.popup(import('@/components/emoji-picker.vue'), { | ||||
| 				src: this.$refs.reactButton, | ||||
| 				asReactionPicker: true | ||||
| 			}, { | ||||
|  | @ -508,9 +515,13 @@ export default defineComponent({ | |||
| 							reaction: reaction | ||||
| 						}); | ||||
| 					} | ||||
| 					this.focus(); | ||||
| 				}, | ||||
| 			}, 'closed'); | ||||
| 				closed: () => { | ||||
| 					this.operating = false; | ||||
| 					this.focus(); | ||||
| 					dispose(); | ||||
| 				} | ||||
| 			}); | ||||
| 		}, | ||||
| 
 | ||||
| 		reactDirectly(reaction) { | ||||
|  | @ -734,9 +745,13 @@ export default defineComponent({ | |||
| 		}, | ||||
| 
 | ||||
| 		menu(viaKeyboard = false) { | ||||
| 			this.operating = true; | ||||
| 			os.modalMenu(this.getMenu(), this.$refs.menuButton, { | ||||
| 				viaKeyboard | ||||
| 			}).then(this.focus); | ||||
| 			}).then(() => { | ||||
| 				this.operating = false; | ||||
| 				this.focus(); | ||||
| 			}); | ||||
| 		}, | ||||
| 
 | ||||
| 		showRenoteMenu(viaKeyboard = false) { | ||||
|  | @ -857,10 +872,8 @@ export default defineComponent({ | |||
| </script> | ||||
| 
 | ||||
| <style lang="scss" scoped> | ||||
| .note { | ||||
| .vfzoeqcg { | ||||
| 	position: relative; | ||||
| 	transition: box-shadow 0.1s ease; | ||||
| 	overflow: hidden; | ||||
| 	contain: content; | ||||
| 
 | ||||
| 	// これらの指定はパフォーマンス向上には有効だが、ノートの高さは一定でないため、 | ||||
|  | @ -879,8 +892,10 @@ export default defineComponent({ | |||
| 		background: rgba(0, 0, 0, 0.05); | ||||
| 	} | ||||
| 
 | ||||
| 	&:hover > .article > .main > .footer { | ||||
| 		display: block; | ||||
| 	&:hover, &.operating { | ||||
| 		> .article > .main > .footer { | ||||
| 			display: block; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	&.renote { | ||||
|  | @ -983,8 +998,8 @@ export default defineComponent({ | |||
| 		> .avatar { | ||||
| 			flex-shrink: 0; | ||||
| 			display: block; | ||||
| 			//position: sticky; | ||||
| 			//top: 72px; | ||||
| 			position: sticky; | ||||
| 			top: 12px; | ||||
| 			margin: 0 14px 0 0; | ||||
| 			width: 46px; | ||||
| 			height: 46px; | ||||
|  | @ -1122,5 +1137,9 @@ export default defineComponent({ | |||
| .muted { | ||||
| 	padding: 8px 16px; | ||||
| 	opacity: 0.7; | ||||
| 
 | ||||
| 	&:hover { | ||||
| 		background: rgba(0, 0, 0, 0.05); | ||||
| 	} | ||||
| } | ||||
| </style> | ||||
|  |  | |||
|  | @ -1,5 +1,5 @@ | |||
| <template> | ||||
| <XNotes ref="tl" :pagination="pagination" @queue="$emit('queue', $event)" v-follow="pagination.reversed"/> | ||||
| <XNotes class="dbiokgaf" ref="tl" :pagination="pagination" @queue="$emit('queue', $event)" v-follow="pagination.reversed"/> | ||||
| </template> | ||||
| 
 | ||||
| <script lang="ts"> | ||||
|  | @ -188,3 +188,9 @@ export default defineComponent({ | |||
| 	} | ||||
| }); | ||||
| </script> | ||||
| 
 | ||||
| <style lang="scss" scoped> | ||||
| .dbiokgaf { | ||||
| 	padding: 16px 0; | ||||
| } | ||||
| </style> | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue