Skip to content

Commit

Permalink
Merge pull request #47 from miyaoka/multi-select
Browse files Browse the repository at this point in the history
複数選択モードを追加し、選択した動画をマルチビュー画面で表示できるようにする
  • Loading branch information
miyaoka authored Oct 6, 2024
2 parents 70f5244 + 2a5dcf0 commit 21a818e
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 7 deletions.
60 changes: 54 additions & 6 deletions src/components/menu/FooterMenu.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,66 @@ import BookmarkedEventButton from "./bookmarkedEvent/BookmarkedEventButton.vue";
import FilteringButton from "./FilteringButton.vue";
import KeywordListButton from "./keywordList/KeywordListButton.vue";
import LiveFilterButton from "./LiveFilterButton.vue";
import MultiSelectButton from "./MultiSelectButton.vue";
import ScrollButton from "./ScrollButton.vue";
import { getYouTubeVideoId } from "@/lib/youtube";
import { useEventListStore } from "@/store/eventListStore";
import { useFocusStore } from "@/store/focusStore";
const focusStore = useFocusStore();
const eventListStore = useEventListStore();
const multiplayerUrl = "https://multi-player.vercel.app/";
function openInMultiPlayer() {
const idList = Array.from(focusStore.multiSelectEventIdSet);
if (idList.length === 0) return;
const eventList = idList.flatMap((id) => eventListStore.liverEventMap.get(id) ?? []);
const vidList = eventList.flatMap((event) => {
const videoId = getYouTubeVideoId(event.url);
return videoId ?? [];
});
const url = new URL(multiplayerUrl);
url.search = new URLSearchParams(vidList.map((vid) => ["v", vid])).toString();
window.open(url.href, "_blank");
}
</script>

<template>
<footer class="relative z-30">
<FilteringButton />
<div class="fixed bottom-4 right-4 flex flex-row items-end gap-2">
<KeywordListButton />
<BookmarkedEventButton />
<AddedEventButton />
<LiveFilterButton />
<ScrollButton />

<div class="fixed bottom-4 right-4 flex flex-col items-end gap-4">
<div
v-if="focusStore.isMultiSelectMode"
class="flex items-center justify-center gap-4 rounded-xl bg-green-700 px-4 py-2 text-white"
>
<div class="flex flex-col">
<p class="text-lg font-bold">複数選択モード</p>
<p>選択した動画をマルチビュー画面で表示</p>
<p>({{ focusStore.multiSelectEventIdSet.size }}個選択中)</p>
</div>
<div>
<button
:disabled="focusStore.multiSelectEventIdSet.size === 0"
class="flex size-11 items-center justify-center rounded-full bg-white px-2 py-1 text-black disabled:opacity-20"
title="マルチビュー画面で開く"
@click="openInMultiPlayer"
>
<i class="i-mdi-open-in-new size-8" />
</button>
</div>
</div>
<div class="flex flex-row items-end gap-2">
<MultiSelectButton />
<KeywordListButton />
<BookmarkedEventButton />
<AddedEventButton />
<LiveFilterButton />
<ScrollButton />
</div>
</div>
</footer>
</template>
19 changes: 19 additions & 0 deletions src/components/menu/MultiSelectButton.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<script setup lang="ts">
import { useFocusStore } from "@/store/focusStore";
const focusStore = useFocusStore();
</script>

<template>
<button
class="relative flex size-11 items-center justify-center rounded-full border shadow-md"
:class="`${focusStore.isMultiSelectMode ? 'bg-green-600 text-white' : 'bg-white text-black'}`"
title="multiple select"
@click="focusStore.toggleMultiSelectMode"
>
<i
class="size-8"
:class="`${focusStore.isMultiSelectMode ? 'i-mdi-checkbox-multiple-marked-outline' : ' i-mdi-checkbox-multiple-outline'}`"
/>
</button>
</template>
17 changes: 17 additions & 0 deletions src/components/streams/LiverEventCard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,12 @@ const hasHoveredHash = computed(() => {
function onClickCard(evt: MouseEvent) {
evt.preventDefault();
// マルチセレクトモードの場合はトグルして終了
if (focusStore.isMultiSelectMode) {
focusStore.toggleMultiSelectEvent(liverEvent.value.id);
return;
}
// idからpopover要素を取得
const popover = document.getElementById(props.liverEvent.id);
if (!popover) return;
Expand Down Expand Up @@ -191,6 +197,17 @@ function setSearchString(str: string) {
>
<span class="whitespace-nowrap text-xs">#{{ firstHash }}</span>
</div>

<div
v-if="focusStore.isMultiSelectMode && focusStore.multiSelectEventIdSet.has(liverEvent.id)"
class="absolute flex size-full items-center justify-end"
>
<div class="absolute inset-0 rounded-xl bg-green-500/30" />

<div class="absolute right-2 z-10 flex rounded-full bg-white">
<i class="i-mdi-checkbox-marked-circle size-12 text-green-600" />
</div>
</div>
</div>
</a>
</div>
Expand Down
21 changes: 20 additions & 1 deletion src/store/focusStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ import type { LiverEvent } from "@/services/api";
export const useFocusStore = defineStore("focusStore", () => {
const hoveredTalent = ref<string | null>(null);
const hoveredCollaboTalentSet = ref<Set<string>>(new Set());

const hoveredHashSet = ref<Set<string>>(new Set());
const isMultiSelectMode = ref(false);
const multiSelectEventIdSet = ref<Set<string>>(new Set());

function setHoveredTalents(talent: string, collaboTalents: string[] = []) {
hoveredTalent.value = talent;
Expand Down Expand Up @@ -39,16 +40,34 @@ export const useFocusStore = defineStore("focusStore", () => {
clearHoveredHashtagSet();
}

function toggleMultiSelectMode() {
isMultiSelectMode.value = !isMultiSelectMode.value;
if (!isMultiSelectMode.value) {
multiSelectEventIdSet.value.clear();
}
}
function toggleMultiSelectEvent(id: string) {
if (multiSelectEventIdSet.value.has(id)) {
multiSelectEventIdSet.value.delete(id);
} else {
multiSelectEventIdSet.value.add(id);
}
}

return {
hoveredTalent,
hoveredCollaboTalentSet,
hoveredHashSet,
isMultiSelectMode,
multiSelectEventIdSet,
setHoveredTalents,
clearHoveredTalents,
setHoveredHashtagSet,
clearHoveredHashtagSet,
hoverEvent,
unhoverEvent,
toggleMultiSelectMode,
toggleMultiSelectEvent,
};
});

Expand Down

0 comments on commit 21a818e

Please sign in to comment.