From 5eb944ecdeb0d65ec82b89522dfdf37d980bdb51 Mon Sep 17 00:00:00 2001
From: ikasoba <57828948+ikasoba@users.noreply.github.com>
Date: Fri, 22 Dec 2023 20:41:42 +0900
Subject: enhance: チャンネルに新規の投稿がある場合にバッジを表示させる
 (#12690)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* 多分できたかも

* 不要なpropsを削除

* 不要なimportを削除

* 縁を付けた

* 枠線の位置を端に寄せた

* やっぱり内側へ寄せることにした

* できたかも

* 修正

* 修正

* クラスにまとめた

* 微調整

* 直せたかも

* importを付け足し

* 多分できたかも

* Update channel.vue

* Update MkMenu.vue

* Update channel.vue

* Update CHANGELOG.md

---------

Co-authored-by: syuilo <Syuilotan@yahoo.co.jp>
---
 .../frontend/src/components/MkChannelPreview.vue   | 98 +++++++++++++++-------
 1 file changed, 66 insertions(+), 32 deletions(-)

(limited to 'packages/frontend/src/components/MkChannelPreview.vue')

diff --git a/packages/frontend/src/components/MkChannelPreview.vue b/packages/frontend/src/components/MkChannelPreview.vue
index 4512f2dd60..bf6504d6bf 100644
--- a/packages/frontend/src/components/MkChannelPreview.vue
+++ b/packages/frontend/src/components/MkChannelPreview.vue
@@ -4,49 +4,70 @@ SPDX-License-Identifier: AGPL-3.0-only
 -->
 
 <template>
-<MkA :to="`/channels/${channel.id}`" class="eftoefju _panel" tabindex="-1">
-	<div class="banner" :style="bannerStyle">
-		<div class="fade"></div>
-		<div class="name"><i class="ti ti-device-tv"></i> {{ channel.name }}</div>
-		<div v-if="channel.isSensitive" class="sensitiveIndicator">{{ i18n.ts.sensitive }}</div>
-		<div class="status">
-			<div>
-				<i class="ti ti-users ti-fw"></i>
-				<I18n :src="i18n.ts._channel.usersCount" tag="span" style="margin-left: 4px;">
-					<template #n>
-						<b>{{ channel.usersCount }}</b>
-					</template>
-				</I18n>
-			</div>
-			<div>
-				<i class="ti ti-pencil ti-fw"></i>
-				<I18n :src="i18n.ts._channel.notesCount" tag="span" style="margin-left: 4px;">
-					<template #n>
-						<b>{{ channel.notesCount }}</b>
-					</template>
-				</I18n>
+<div style="position: relative;">
+	<MkA :to="`/channels/${channel.id}`" class="eftoefju _panel" tabindex="-1" @click="updateLastReadedAt">
+		<div class="banner" :style="bannerStyle">
+			<div class="fade"></div>
+			<div class="name"><i class="ti ti-device-tv"></i> {{ channel.name }}</div>
+			<div v-if="channel.isSensitive" class="sensitiveIndicator">{{ i18n.ts.sensitive }}</div>
+			<div class="status">
+				<div>
+					<i class="ti ti-users ti-fw"></i>
+					<I18n :src="i18n.ts._channel.usersCount" tag="span" style="margin-left: 4px;">
+						<template #n>
+							<b>{{ channel.usersCount }}</b>
+						</template>
+					</I18n>
+				</div>
+				<div>
+					<i class="ti ti-pencil ti-fw"></i>
+					<I18n :src="i18n.ts._channel.notesCount" tag="span" style="margin-left: 4px;">
+						<template #n>
+							<b>{{ channel.notesCount }}</b>
+						</template>
+					</I18n>
+				</div>
 			</div>
 		</div>
-	</div>
-	<article v-if="channel.description">
-		<p :title="channel.description">{{ channel.description.length > 85 ? channel.description.slice(0, 85) + '…' : channel.description }}</p>
-	</article>
-	<footer>
-		<span v-if="channel.lastNotedAt">
-			{{ i18n.ts.updatedAt }}: <MkTime :time="channel.lastNotedAt"/>
-		</span>
-	</footer>
-</MkA>
+		<article v-if="channel.description">
+			<p :title="channel.description">{{ channel.description.length > 85 ? channel.description.slice(0, 85) + '…' : channel.description }}</p>
+		</article>
+		<footer>
+			<span v-if="channel.lastNotedAt">
+				{{ i18n.ts.updatedAt }}: <MkTime :time="channel.lastNotedAt"/>
+			</span>
+		</footer>
+	</MkA>
+	<div
+		v-if="channel.lastNotedAt && (channel.isFavorited || channel.isFollowing) && (!lastReadedAt || Date.parse(channel.lastNotedAt) > lastReadedAt)"
+		class="indicator"
+	></div>
+</div>
 </template>
 
 <script lang="ts" setup>
-import { computed } from 'vue';
+import { computed, ref, watch } from 'vue';
 import { i18n } from '@/i18n.js';
+import { miLocalStorage } from '@/local-storage.js';
 
 const props = defineProps<{
 	channel: Record<string, any>;
 }>();
 
+const getLastReadedAt = (): number | null => {
+	return miLocalStorage.getItemAsJson(`channelLastReadedAt:${props.channel.id}`) ?? null;
+};
+
+const lastReadedAt = ref(getLastReadedAt());
+
+watch(() => props.channel.id, () => {
+	lastReadedAt.value = getLastReadedAt();
+});
+
+const updateLastReadedAt = () => {
+	lastReadedAt.value = props.channel.lastNotedAt ? Date.parse(props.channel.lastNotedAt) : Date.now();
+};
+
 const bannerStyle = computed(() => {
 	if (props.channel.bannerUrl) {
 		return { backgroundImage: `url(${props.channel.bannerUrl})` };
@@ -170,4 +191,17 @@ const bannerStyle = computed(() => {
 	}
 }
 
+.indicator {
+	position: absolute;
+	top: 0;
+	right: 0;
+	transform: translate(25%, -25%);
+	background-color: var(--accent);
+	border: solid var(--bg) 4px;
+	border-radius: 100%;
+	width: 1.5rem;
+	height: 1.5rem;
+	aspect-ratio: 1 / 1;
+}
+
 </style>
-- 
cgit v1.2.3-freya

