-
Notifications
You must be signed in to change notification settings - Fork 43
リアクションをホバーしたときに拡大して表示 #4434
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
リアクションをホバーしたときに拡大して表示 #4434
Changes from 13 commits
c1c88b5
8d05380
acd6832
0101b00
ec87df5
e50a748
6bbdefe
7c3878d
dfe59a5
2544496
862f88f
5ee9bac
108c4c1
b5850d4
3a771c4
646c014
f19b322
5087384
e379fa0
b84cbfa
2b99e5e
cbc515e
995cfd7
6e8dce7
167ff71
534fe15
672c119
8ec935b
ae54378
974d348
02c6f74
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,11 @@ | ||
<template> | ||
<div | ||
:class="$style.body" | ||
:title="tooltip" | ||
:aria-label="tooltip" | ||
:data-include-me="$boolAttr(includeMe)" | ||
@click="onClick" | ||
@mouseenter="onMouseEnter" | ||
@mouseleave="onMouseLeave" | ||
> | ||
<transition name="stamp-pressed" mode="out-in"> | ||
<a-stamp | ||
|
@@ -15,6 +17,11 @@ | |
</transition> | ||
<spin-number :value="stamp.sum" :class="$style.count" /> | ||
</div> | ||
<stamp-scaled-element | ||
:class="$style.scaleReaction" | ||
:show="isHovered && isLongHovered && !isDetailShown && !isMobile" | ||
:stamp="stamp" | ||
/> | ||
</template> | ||
|
||
<script lang="ts" setup> | ||
|
@@ -23,17 +30,22 @@ import AStamp from '/@/components/UI/AStamp.vue' | |
import { ref, computed, watch, onMounted } from 'vue' | ||
import { useStampsStore } from '/@/store/entities/stamps' | ||
import { useUsersStore } from '/@/store/entities/users' | ||
import { useResponsiveStore } from '/@/store/ui/responsive' | ||
import type { MessageStampById } from '/@/lib/messageStampList' | ||
import StampScaledElement from './StampScaledElement.vue' | ||
import useHover from '/@/composables/dom/useHover' | ||
|
||
const props = defineProps<{ | ||
stamp: MessageStampById | ||
isDetailShown: boolean | ||
}>() | ||
|
||
const emit = defineEmits<{ | ||
(e: 'addStamp', _stampId: string): void | ||
(e: 'removeStamp', _stampId: string): void | ||
}>() | ||
|
||
const { isMobile } = useResponsiveStore() | ||
const { stampsMap } = useStampsStore() | ||
const { usersMap } = useUsersStore() | ||
|
||
|
@@ -43,10 +55,7 @@ const stampName = computed( | |
|
||
const tooltip = computed(() => | ||
[ | ||
`:${stampName.value}:`, | ||
...props.stamp.users.map( | ||
u => `${usersMap.value.get(u.id)?.displayName ?? ''}(${u.count})` | ||
) | ||
`${stampName.value}, ${props.stamp.sum}件のリアクション, クリック/タップでリアクションを削除` | ||
].join(' ') | ||
) | ||
|
||
|
@@ -85,6 +94,24 @@ watch( | |
isProgress.value = false | ||
} | ||
) | ||
|
||
const { isHovered, onMouseEnter, onMouseLeave } = useHover() | ||
const hoverTimeout = ref<ReturnType<typeof setTimeout> | null>(null) | ||
const isLongHovered = ref(false) | ||
|
||
watch(isHovered, beginHover => { | ||
UnABC marked this conversation as resolved.
Show resolved
Hide resolved
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. このあたりの処理、useHoverを使おうと使おうとしたのは自然な判断だと思います! |
||
if (beginHover) { | ||
hoverTimeout.value = setTimeout(() => { | ||
isLongHovered.value = true | ||
}, 500) | ||
} else { | ||
if (hoverTimeout.value) { | ||
clearTimeout(hoverTimeout.value) | ||
hoverTimeout.value = null | ||
} | ||
isLongHovered.value = false | ||
} | ||
}) | ||
</script> | ||
|
||
<style lang="scss" module> | ||
|
@@ -103,6 +130,7 @@ watch( | |
user-select: none; | ||
overflow: hidden; | ||
contain: content; | ||
position: relative; | ||
} | ||
|
||
.count { | ||
|
@@ -118,4 +146,19 @@ watch( | |
right: 4px; | ||
} | ||
} | ||
|
||
.scaleReaction { | ||
@include background-tertiary; | ||
display: flex; | ||
height: 3.5rem; | ||
UnABC marked this conversation as resolved.
Show resolved
Hide resolved
|
||
align-items: flex-start; | ||
UnABC marked this conversation as resolved.
Show resolved
Hide resolved
|
||
padding: 0.125rem 0.25rem; | ||
border-radius: 0.25rem; | ||
user-select: none; | ||
overflow: visible; | ||
contain: content; | ||
position: absolute; | ||
bottom: 105%; | ||
z-index: $z-index-message-element-scaled-stamp; | ||
} | ||
</style> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
<template> | ||
<div :class="$style.container"> | ||
<div> | ||
{{ ':' + stampName + ': が ' }} | ||
</div> | ||
<div v-for="user in limitedUsers" :key="user.id" :class="$style.contents"> | ||
<stamp-detail-element-content | ||
:user-id="user.id" | ||
:count="user.count" | ||
:class="$style.content" | ||
/> | ||
<span | ||
v-if=" | ||
(!isLastUser(user) && !isSecondLastUser(user)) || | ||
isOverLimitSecondUser(user) | ||
" | ||
:class="$style.contents" | ||
> | ||
、 | ||
</span> | ||
<span | ||
v-if="isSecondLastUser(user) && !isOverLimitSecondUser(user)" | ||
:class="$style.contents" | ||
>と</span | ||
> | ||
<span v-if="isOverLimitUser(user)" :class="$style.contents" | ||
>と他{{ props.stamp.users.length - 3 }}人</span | ||
> | ||
<span v-if="isLastUser(user)" :class="$style.contents"> | ||
にリアクションされました | ||
</span> | ||
UnABC marked this conversation as resolved.
Show resolved
Hide resolved
|
||
</div> | ||
</div> | ||
</template> | ||
|
||
<script lang="ts" setup> | ||
import StampDetailElementContent from './StampDetailElementContent.vue' | ||
import { computed } from 'vue' | ||
import { useStampsStore } from '/@/store/entities/stamps' | ||
import type { StampUser, MessageStampById } from '/@/lib/messageStampList' | ||
|
||
const props = defineProps<{ | ||
stamp: MessageStampById | ||
}>() | ||
|
||
const { stampsMap } = useStampsStore() | ||
|
||
const limitedUsers = computed(() => props.stamp.users.slice(0, 3)) | ||
|
||
const stampName = computed( | ||
() => stampsMap.value.get(props.stamp.id)?.name ?? '' | ||
) | ||
|
||
const isLastUser = (user: StampUser) => | ||
user === props.stamp.users[Math.min(props.stamp.users.length - 1, 2)] | ||
|
||
const isSecondLastUser = (user: StampUser) => | ||
user === props.stamp.users[Math.min(props.stamp.users.length - 2, 1)] | ||
|
||
const isOverLimitUser = (user: StampUser) => | ||
user === props.stamp.users[2] && props.stamp.users.length > 3 | ||
|
||
const isOverLimitSecondUser = (user: StampUser) => | ||
user === props.stamp.users[1] && props.stamp.users.length > 3 | ||
</script> | ||
|
||
<style lang="scss" module> | ||
.container { | ||
display: flex; | ||
flex-wrap: wrap; | ||
} | ||
.contents { | ||
display: flex; | ||
} | ||
.content { | ||
padding: 0 0.2rem; | ||
} | ||
</style> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
<template> | ||
<div v-show="show" :class="$style.scaleReaction"> | ||
<transition name="scale-reaction"> | ||
<!-- sizeを46より大きくすると見切れる --> | ||
<a-stamp | ||
:key="stamp.id" | ||
:stamp-id="stamp.id" | ||
:size="46" | ||
:class="$style.stamp" | ||
without-title | ||
/> | ||
</transition> | ||
<stamp-detail-element :class="$style.detail" :stamp="stamp" /> | ||
</div> | ||
</template> | ||
|
||
<script lang="ts" setup> | ||
import AStamp from '/@/components/UI/AStamp.vue' | ||
import type { MessageStampById } from '/@/lib/messageStampList' | ||
import StampDetailElement from './StampScaledDetailElement.vue' | ||
|
||
const props = defineProps<{ | ||
stamp: MessageStampById | ||
show: boolean | ||
}>() | ||
</script> | ||
|
||
<style lang="scss" module> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ここ、grid の中の item で margin を入れてて margin が 2 つ分できてしまってるので、 flex box にして gap 指定する形で margin 重複を回避できるならしたいかも |
||
.scaleReaction { | ||
@include color-ui-tertiary; | ||
@include background-primary; | ||
display: flex; | ||
border-radius: 4px; | ||
contain: none; | ||
flex-wrap: wrap; | ||
border: solid 2px $theme-ui-tertiary-default; | ||
} | ||
.stamp { | ||
margin: { | ||
right: 0.2rem; | ||
bottom: 0.2rem; | ||
} | ||
display: flex; | ||
} | ||
|
||
.detail { | ||
color: var(--specific-count-text); | ||
@include color-ui-primary; | ||
flex: 1 1 0; | ||
min-width: 0; | ||
overflow: hidden; | ||
overflow: clip; | ||
margin: { | ||
left: 6px; | ||
right: 4px; | ||
} | ||
} | ||
</style> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ここ、stamp-scaled-elementの中でv-show使って制御してると思うんですけど、v-ifでコンポーネントごと表示させないほうが大量にスタンプが付いたときに軽くなると思います。
https://ja.vuejs.org/guide/essentials/conditional#v-if-vs-v-show