From 0336d640ecf223e179bc18e02f66dfc7b5c9ea19 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Mon, 15 Feb 2021 17:17:19 +0900
Subject: [PATCH] wip

---
 src/client/components/note.vue             |  4 +-
 src/client/directives/follow-append.ts     |  2 -
 src/client/ui/chat/date-separated-list.vue | 15 ++++
 src/client/ui/chat/header-clock.vue        | 44 +++++++++++
 src/client/ui/chat/index.vue               | 91 +++++++++++++---------
 src/client/ui/chat/note.vue                | 47 +++++++----
 src/client/ui/chat/timeline.vue            |  8 +-
 7 files changed, 155 insertions(+), 56 deletions(-)
 create mode 100644 src/client/ui/chat/header-clock.vue

diff --git a/src/client/components/note.vue b/src/client/components/note.vue
index b839ab3e8f..d532289857 100644
--- a/src/client/components/note.vue
+++ b/src/client/components/note.vue
@@ -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;
diff --git a/src/client/directives/follow-append.ts b/src/client/directives/follow-append.ts
index 9490dcf786..b0e99628b0 100644
--- a/src/client/directives/follow-append.ts
+++ b/src/client/directives/follow-append.ts
@@ -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;
diff --git a/src/client/ui/chat/date-separated-list.vue b/src/client/ui/chat/date-separated-list.vue
index eb671510af..0120bf33f7 100644
--- a/src/client/ui/chat/date-separated-list.vue
+++ b/src/client/ui/chat/date-separated-list.vue
@@ -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 {
diff --git a/src/client/ui/chat/header-clock.vue b/src/client/ui/chat/header-clock.vue
new file mode 100644
index 0000000000..65573d460b
--- /dev/null
+++ b/src/client/ui/chat/header-clock.vue
@@ -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>
diff --git a/src/client/ui/chat/index.vue b/src/client/ui/chat/index.vue
index 56a1364f16..678ba2c7a8 100644
--- a/src/client/ui/chat/index.vue
+++ b/src/client/ui/chat/index.vue
@@ -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 {
diff --git a/src/client/ui/chat/note.vue b/src/client/ui/chat/note.vue
index f17f459625..cfc385bdf0 100644
--- a/src/client/ui/chat/note.vue
+++ b/src/client/ui/chat/note.vue
@@ -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>
diff --git a/src/client/ui/chat/timeline.vue b/src/client/ui/chat/timeline.vue
index 3a32b9faee..d73a40dab5 100644
--- a/src/client/ui/chat/timeline.vue
+++ b/src/client/ui/chat/timeline.vue
@@ -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>