replace clickable el-popover with Popover components

This commit is contained in:
pa
2026-01-07 19:59:33 +09:00
committed by Natsumi
parent 738d22461e
commit acbc0ca0fc
12 changed files with 517 additions and 395 deletions

View File

@@ -1,52 +1,56 @@
<template> <template>
<el-popover v-model:visible="visible" trigger="click" placement="bottom-start" :width="620"> <Popover v-model:open="visible">
<template #reference> <PopoverTrigger asChild>
<el-button class="icon-picker__trigger" plain> <el-button class="icon-picker__trigger" plain>
<i v-if="modelValue" :class="modelValue"></i> <i v-if="modelValue" :class="modelValue"></i>
<span>{{ t('nav_menu.icon_picker.pick_icon') }}</span> <span>{{ t('nav_menu.icon_picker.pick_icon') }}</span>
</el-button> </el-button>
</template> </PopoverTrigger>
<div class="icon-picker"> <PopoverContent side="bottom" align="start" class="w-[620px]">
<el-input <div class="icon-picker">
v-model="search" <el-input
clearable v-model="search"
class="icon-picker__search" clearable
:placeholder="t('nav_menu.icon_picker.search_placeholder')" /> class="icon-picker__search"
<el-scrollbar v-if="filteredCategories.length" height="600px" class="icon-picker__scroll"> :placeholder="t('nav_menu.icon_picker.search_placeholder')" />
<div v-for="category in filteredCategories" :key="category.name" class="icon-picker__category"> <el-scrollbar v-if="filteredCategories.length" height="600px" class="icon-picker__scroll">
<div class="icon-picker__category-title"> <div v-for="category in filteredCategories" :key="category.name" class="icon-picker__category">
{{ category.name }} <div class="icon-picker__category-title">
</div> {{ category.name }}
<div class="icon-picker__grid"> </div>
<div v-for="group in category.groups" :key="group.id" class="icon-picker__group"> <div class="icon-picker__grid">
<div class="icon-picker__group-label"> <div v-for="group in category.groups" :key="group.id" class="icon-picker__group">
{{ group.label }} <div class="icon-picker__group-label">
</div> {{ group.label }}
<div class="icon-picker__variants"> </div>
<button <div class="icon-picker__variants">
v-for="variant in group.variants" <button
:key="variant.className" v-for="variant in group.variants"
type="button" :key="variant.className"
class="icon-picker__variant" type="button"
:class="{ 'is-active': variant.className === modelValue }" class="icon-picker__variant"
:title="group.tooltip" :class="{ 'is-active': variant.className === modelValue }"
@click="handleSelect(variant.className)"> :title="group.tooltip"
<i :class="[variant.className, 'ri-2x']"></i> @click="handleSelect(variant.className)">
</button> <i :class="[variant.className, 'ri-2x']"></i>
</button>
</div>
</div> </div>
</div> </div>
</div> </div>
</div> </el-scrollbar>
</el-scrollbar> <div v-else class="icon-picker__empty">{{ t('nav_menu.icon_picker.no_icon_found') }}</div>
<div v-else class="icon-picker__empty">{{ t('nav_menu.icon_picker.no_icon_found') }}</div> </div>
</div> </PopoverContent>
</el-popover> </Popover>
</template> </template>
<script setup> <script setup>
import { computed, ref, watch } from 'vue'; import { computed, ref, watch } from 'vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { Popover, PopoverContent, PopoverTrigger } from './ui/popover';
import remixIconTags from '../shared/constants/remixIconTags.json'; import remixIconTags from '../shared/constants/remixIconTags.json';
const { t } = useI18n(); const { t } = useI18n();

View File

@@ -182,8 +182,8 @@
<span v-if="badge.hidden">&nbsp;(Hidden)</span> <span v-if="badge.hidden">&nbsp;(Hidden)</span>
</template> </template>
<div style="display: inline-block"> <div style="display: inline-block">
<el-popover placement="bottom" :width="300" trigger="click"> <Popover>
<template #reference> <PopoverTrigger asChild>
<img <img
class="x-link x-user-badge" class="x-link x-user-badge"
:src="badge.badgeImageUrl" :src="badge.badgeImageUrl"
@@ -198,40 +198,44 @@
" "
:class="{ 'x-user-badge-hidden': badge.hidden }" :class="{ 'x-user-badge-hidden': badge.hidden }"
loading="lazy" /> loading="lazy" />
</template> </PopoverTrigger>
<img <PopoverContent side="bottom" class="w-[300px]">
:src="badge.badgeImageUrl" <img
:class="['x-link', 'x-popover-image']" :src="badge.badgeImageUrl"
@click="showFullscreenImageDialog(badge.badgeImageUrl)" :class="['x-link', 'x-popover-image']"
loading="lazy" /> @click="showFullscreenImageDialog(badge.badgeImageUrl)"
<br /> loading="lazy" />
<div style="display: block; width: 275px; word-break: normal">
<span>{{ badge.badgeName }}</span>
<br /> <br />
<span class="x-grey" style="font-size: 12px">{{ badge.badgeDescription }}</span> <div style="display: block; width: 275px; word-break: normal">
<br /> <span>{{ badge.badgeName }}</span>
<span
v-if="badge.assignedAt"
class="x-grey"
style="font-family: monospace; font-size: 12px">
{{ t('dialog.user.badges.assigned') }}:
{{ formatDateFilter(badge.assignedAt, 'long') }}
</span>
<template v-if="userDialog.id === currentUser.id">
<br /> <br />
<el-checkbox <span class="x-grey" style="font-size: 12px">{{ badge.badgeDescription }}</span>
v-model="badge.hidden"
style="margin-top: 5px"
@change="toggleBadgeVisibility(badge)">
{{ t('dialog.user.badges.hidden') }}
</el-checkbox>
<br /> <br />
<el-checkbox v-model="badge.showcased" @change="toggleBadgeShowcased(badge)"> <span
{{ t('dialog.user.badges.showcased') }} v-if="badge.assignedAt"
</el-checkbox> class="x-grey"
</template> style="font-family: monospace; font-size: 12px">
</div> {{ t('dialog.user.badges.assigned') }}:
</el-popover> {{ formatDateFilter(badge.assignedAt, 'long') }}
</span>
<template v-if="userDialog.id === currentUser.id">
<br />
<el-checkbox
v-model="badge.hidden"
style="margin-top: 5px"
@change="toggleBadgeVisibility(badge)">
{{ t('dialog.user.badges.hidden') }}
</el-checkbox>
<br />
<el-checkbox
v-model="badge.showcased"
@change="toggleBadgeShowcased(badge)">
{{ t('dialog.user.badges.showcased') }}
</el-checkbox>
</template>
</div>
</PopoverContent>
</Popover>
</div> </div>
</TooltipWrapper> </TooltipWrapper>
</div> </div>
@@ -260,6 +264,7 @@
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { formatDateFilter, languageClass, userImage, userStatusClass } from '../../../shared/utils'; import { formatDateFilter, languageClass, userImage, userStatusClass } from '../../../shared/utils';
import { Popover, PopoverContent, PopoverTrigger } from '../../ui/popover';
import { useGalleryStore, useUserStore } from '../../../stores'; import { useGalleryStore, useUserStore } from '../../../stores';
import { Badge } from '../../ui/badge'; import { Badge } from '../../ui/badge';

View File

@@ -0,0 +1,18 @@
<script setup>
import { PopoverRoot, useForwardPropsEmits } from 'reka-ui';
const props = defineProps({
defaultOpen: { type: Boolean, required: false },
open: { type: Boolean, required: false },
modal: { type: Boolean, required: false }
});
const emits = defineEmits(['update:open']);
const forwarded = useForwardPropsEmits(props, emits);
</script>
<template>
<PopoverRoot v-slot="slotProps" data-slot="popover" v-bind="forwarded">
<slot v-bind="slotProps" />
</PopoverRoot>
</template>

View File

@@ -0,0 +1,15 @@
<script setup>
import { PopoverAnchor } from 'reka-ui';
const props = defineProps({
reference: { type: null, required: false },
asChild: { type: Boolean, required: false },
as: { type: null, required: false }
});
</script>
<template>
<PopoverAnchor data-slot="popover-anchor" v-bind="props">
<slot />
</PopoverAnchor>
</template>

View File

@@ -0,0 +1,62 @@
<script setup>
import { PopoverContent, PopoverPortal, useForwardPropsEmits } from 'reka-ui';
import { cn } from '@/lib/utils';
import { reactiveOmit } from '@vueuse/core';
defineOptions({
inheritAttrs: false
});
const props = defineProps({
forceMount: { type: Boolean, required: false },
side: { type: null, required: false },
sideOffset: { type: Number, required: false, default: 4 },
sideFlip: { type: Boolean, required: false },
align: { type: null, required: false, default: 'center' },
alignOffset: { type: Number, required: false },
alignFlip: { type: Boolean, required: false },
avoidCollisions: { type: Boolean, required: false },
collisionBoundary: { type: null, required: false },
collisionPadding: { type: [Number, Object], required: false },
arrowPadding: { type: Number, required: false },
sticky: { type: String, required: false },
hideWhenDetached: { type: Boolean, required: false },
positionStrategy: { type: String, required: false },
updatePositionStrategy: { type: String, required: false },
disableUpdateOnLayoutShift: { type: Boolean, required: false },
prioritizePosition: { type: Boolean, required: false },
reference: { type: null, required: false },
asChild: { type: Boolean, required: false },
as: { type: null, required: false },
disableOutsidePointerEvents: { type: Boolean, required: false },
class: { type: null, required: false }
});
const emits = defineEmits([
'escapeKeyDown',
'pointerDownOutside',
'focusOutside',
'interactOutside',
'openAutoFocus',
'closeAutoFocus'
]);
const delegatedProps = reactiveOmit(props, 'class');
const forwarded = useForwardPropsEmits(delegatedProps, emits);
</script>
<template>
<PopoverPortal>
<PopoverContent
data-slot="popover-content"
v-bind="{ ...$attrs, ...forwarded }"
:class="
cn(
'bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-72 rounded-md border p-4 shadow-md origin-(--reka-popover-content-transform-origin) outline-hidden',
props.class
)
">
<slot />
</PopoverContent>
</PopoverPortal>
</template>

View File

@@ -0,0 +1,20 @@
<script setup>
import { PopoverTrigger } from 'reka-ui';
import { computed } from 'vue';
const props = defineProps({
asChild: { type: Boolean, required: false },
as: { type: null, required: false }
});
const forwarded = computed(() => ({
...props,
as: props.as ?? (props.asChild ? 'span' : 'button')
}));
</script>
<template>
<PopoverTrigger data-slot="popover-trigger" v-bind="forwarded">
<slot />
</PopoverTrigger>
</template>

View File

@@ -0,0 +1,4 @@
export { default as Popover } from './Popover.vue';
export { default as PopoverAnchor } from './PopoverAnchor.vue';
export { default as PopoverContent } from './PopoverContent.vue';
export { default as PopoverTrigger } from './PopoverTrigger.vue';

View File

@@ -25,53 +25,58 @@
><el-button :icon="Refresh" circle style="margin-right: 5px" @click="reloadData"></el-button ><el-button :icon="Refresh" circle style="margin-right: 5px" @click="reloadData"></el-button
></TooltipWrapper> ></TooltipWrapper>
<el-popover placement="bottom" trigger="click" :width="250"> <Popover>
<div class="settings"> <PopoverTrigger asChild>
<div>
<span>{{ t('view.charts.instance_activity.settings.bar_width') }}</span>
<div>
<el-slider
v-model.lazy="barWidth"
:max="50"
:min="1"
@change="
(value) => changeBarWidth(value, () => handleEchartsRerender())
"></el-slider>
</div>
</div>
<div>
<span>{{ t('view.charts.instance_activity.settings.show_detail') }}</span>
<el-switch
v-model="isDetailVisible"
@change="(value) => changeIsDetailInstanceVisible(value, () => handleSettingsChange())">
</el-switch>
</div>
<div v-if="isDetailVisible">
<span>{{ t('view.charts.instance_activity.settings.show_solo_instance') }}</span>
<el-switch
v-model="isSoloInstanceVisible"
@change="(value) => changeIsSoloInstanceVisible(value, () => handleSettingsChange())">
</el-switch>
</div>
<div v-if="isDetailVisible">
<span>{{ t('view.charts.instance_activity.settings.show_no_friend_instance') }}</span>
<el-switch
v-model="isNoFriendInstanceVisible"
@change="
(value) => changeIsNoFriendInstanceVisible(value, () => handleSettingsChange())
">
</el-switch>
</div>
</div>
<template #reference>
<div> <div>
<TooltipWrapper :content="t('view.charts.instance_activity.settings.header')" side="top"> <TooltipWrapper :content="t('view.charts.instance_activity.settings.header')" side="top">
<el-button :icon="Setting" style="margin-right: 5px" circle></el-button> <el-button :icon="Setting" style="margin-right: 5px" circle></el-button>
</TooltipWrapper> </TooltipWrapper>
</div> </div>
</template> </PopoverTrigger>
</el-popover> <PopoverContent side="bottom" class="w-[250px]">
<div class="settings">
<div>
<span>{{ t('view.charts.instance_activity.settings.bar_width') }}</span>
<div>
<el-slider
v-model.lazy="barWidth"
:max="50"
:min="1"
@change="
(value) => changeBarWidth(value, () => handleEchartsRerender())
"></el-slider>
</div>
</div>
<div>
<span>{{ t('view.charts.instance_activity.settings.show_detail') }}</span>
<el-switch
v-model="isDetailVisible"
@change="
(value) => changeIsDetailInstanceVisible(value, () => handleSettingsChange())
">
</el-switch>
</div>
<div v-if="isDetailVisible">
<span>{{ t('view.charts.instance_activity.settings.show_solo_instance') }}</span>
<el-switch
v-model="isSoloInstanceVisible"
@change="
(value) => changeIsSoloInstanceVisible(value, () => handleSettingsChange())
">
</el-switch>
</div>
<div v-if="isDetailVisible">
<span>{{ t('view.charts.instance_activity.settings.show_no_friend_instance') }}</span>
<el-switch
v-model="isNoFriendInstanceVisible"
@change="
(value) => changeIsNoFriendInstanceVisible(value, () => handleSettingsChange())
">
</el-switch>
</div>
</div>
</PopoverContent>
</Popover>
<el-button-group style="margin-right: 5px"> <el-button-group style="margin-right: 5px">
<TooltipWrapper :content="t('view.charts.instance_activity.previous_day')" side="top"> <TooltipWrapper :content="t('view.charts.instance_activity.previous_day')" side="top">
<el-button <el-button
@@ -124,13 +129,14 @@
</template> </template>
<script setup> <script setup>
import { nextTick, onActivated, onBeforeMount, onBeforeUnmount, onDeactivated, onMounted, ref, watch } from 'vue';
import { ArrowLeft, ArrowRight, InfoFilled, Refresh, Setting, WarningFilled } from '@element-plus/icons-vue'; import { ArrowLeft, ArrowRight, InfoFilled, Refresh, Setting, WarningFilled } from '@element-plus/icons-vue';
import { nextTick, onBeforeMount, onBeforeUnmount, onMounted, ref, watch } from 'vue';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import { Popover, PopoverContent, PopoverTrigger } from '../../../components/ui/popover';
import { useAppearanceSettingsStore, useFriendStore, useUserStore } from '../../../stores'; import { useAppearanceSettingsStore, useFriendStore, useUserStore } from '../../../stores';
import { parseLocation, timeToText } from '../../../shared/utils'; import { parseLocation, timeToText } from '../../../shared/utils';
import { useActivityDataProcessor } from '../composables/useActivityDataProcessor'; import { useActivityDataProcessor } from '../composables/useActivityDataProcessor';

View File

@@ -93,71 +93,68 @@
<Badge variant="outline"> <Badge variant="outline">
{{ formatVisibility(group.visibility) }} {{ formatVisibility(group.visibility) }}
</Badge> </Badge>
<el-popover <Popover
:visible="activeGroupMenu === remoteGroupMenuKey(group.key)" :open="activeGroupMenu === remoteGroupMenuKey(group.key)"
@update:visible=" @update:open="
handleGroupMenuVisible(remoteGroupMenuKey(group.key), $event) handleGroupMenuVisible(remoteGroupMenuKey(group.key), $event)
" ">
placement="right" <PopoverTrigger asChild>
trigger="click"
:hide-after="0"
:width="220"
popper-style="padding: 4px; border-radius: 8px;">
<template #reference>
<el-button <el-button
text text
size="small" size="small"
:icon="MoreFilled" :icon="MoreFilled"
circle circle
@click.stop></el-button> @click.stop></el-button>
</template> </PopoverTrigger>
<div class="favorites-group-menu"> <PopoverContent side="right" class="w-[220px] p-1 rounded-lg">
<button <div class="favorites-group-menu">
type="button" <button
class="favorites-group-menu__item" type="button"
@click="handleRemoteRename(group)"> class="favorites-group-menu__item"
<span>{{ t('view.favorite.rename_tooltip') }}</span> @click="handleRemoteRename(group)">
</button> <span>{{ t('view.favorite.rename_tooltip') }}</span>
<el-popover </button>
placement="right" <el-popover
trigger="hover" placement="right"
:width="180" trigger="hover"
popper-style="padding: 4px; border-radius: 8px;"> :width="180"
<div class="group-visibility-menu"> popper-style="padding: 4px; border-radius: 8px;">
<button <div class="group-visibility-menu">
v-for="visibility in avatarGroupVisibilityOptions" <button
:key="visibility" v-for="visibility in avatarGroupVisibilityOptions"
type="button" :key="visibility"
:class="[ type="button"
'group-visibility-menu__item', :class="[
{ 'is-active': group.visibility === visibility } 'group-visibility-menu__item',
]" { 'is-active': group.visibility === visibility }
@click="handleVisibilitySelection(group, visibility)"> ]"
<span>{{ formatVisibility(visibility) }}</span> @click="handleVisibilitySelection(group, visibility)">
<span <span>{{ formatVisibility(visibility) }}</span>
v-if="group.visibility === visibility" <span
class="group-visibility-menu__check"> v-if="group.visibility === visibility"
<i class="ri-check-line"></i> class="group-visibility-menu__check">
</span> <i class="ri-check-line"></i>
</button> </span>
</div> </button>
<template #reference> </div>
<button <template #reference>
type="button" <button
class="favorites-group-menu__item favorites-group-menu__item--submenu"> type="button"
<span>{{ t('view.favorite.visibility_tooltip') }}</span> class="favorites-group-menu__item favorites-group-menu__item--submenu">
<span class="favorites-group-menu__arrow"></span> <span>{{ t('view.favorite.visibility_tooltip') }}</span>
</button> <span class="favorites-group-menu__arrow"></span>
</template> </button>
</el-popover> </template>
<button </el-popover>
type="button" <button
class="favorites-group-menu__item favorites-group-menu__item--danger" type="button"
@click="handleRemoteClear(group)"> class="favorites-group-menu__item favorites-group-menu__item--danger"
<span>{{ t('view.favorite.clear') }}</span> @click="handleRemoteClear(group)">
</button> <span>{{ t('view.favorite.clear') }}</span>
</div> </button>
</el-popover> </div>
</PopoverContent>
</Popover>
</div> </div>
</div> </div>
</template> </template>
@@ -212,45 +209,40 @@
<span class="group-item__count">{{ <span class="group-item__count">{{
localAvatarFavGroupLength(group) localAvatarFavGroupLength(group)
}}</span> }}</span>
<el-popover <Popover
:visible="activeGroupMenu === localGroupMenuKey(group)" :open="activeGroupMenu === localGroupMenuKey(group)"
@update:visible=" @update:open="handleGroupMenuVisible(localGroupMenuKey(group), $event)">
handleGroupMenuVisible(localGroupMenuKey(group), $event) <PopoverTrigger asChild>
"
placement="right"
trigger="click"
:hide-after="0"
:width="200"
popper-style="padding: 4px; border-radius: 8px;">
<template #reference>
<el-button <el-button
text text
size="small" size="small"
:icon="MoreFilled" :icon="MoreFilled"
circle circle
@click.stop></el-button> @click.stop></el-button>
</template> </PopoverTrigger>
<div class="favorites-group-menu"> <PopoverContent side="right" class="w-[200px] p-1 rounded-lg">
<button <div class="favorites-group-menu">
type="button" <button
class="favorites-group-menu__item" type="button"
@click="handleLocalRename(group)"> class="favorites-group-menu__item"
<span>{{ t('view.favorite.rename_tooltip') }}</span> @click="handleLocalRename(group)">
</button> <span>{{ t('view.favorite.rename_tooltip') }}</span>
<button </button>
type="button" <button
class="favorites-group-menu__item" type="button"
@click="handleCheckInvalidAvatars(group)"> class="favorites-group-menu__item"
<span>{{ t('view.favorite.avatars.check_invalid') }}</span> @click="handleCheckInvalidAvatars(group)">
</button> <span>{{ t('view.favorite.avatars.check_invalid') }}</span>
<button </button>
type="button" <button
class="favorites-group-menu__item favorites-group-menu__item--danger" type="button"
@click="handleLocalDelete(group)"> class="favorites-group-menu__item favorites-group-menu__item--danger"
<span>{{ t('view.favorite.delete_tooltip') }}</span> @click="handleLocalDelete(group)">
</button> <span>{{ t('view.favorite.delete_tooltip') }}</span>
</div> </button>
</el-popover> </div>
</PopoverContent>
</Popover>
</div> </div>
</div> </div>
</div> </div>
@@ -286,26 +278,23 @@
<div class="group-section"> <div class="group-section">
<div class="group-section__header"> <div class="group-section__header">
<span>Local History</span> <span>Local History</span>
<el-popover <Popover
:visible="activeGroupMenu === historyGroupMenuKey" :open="activeGroupMenu === historyGroupMenuKey"
@update:visible="handleGroupMenuVisible(historyGroupMenuKey, $event)" @update:open="handleGroupMenuVisible(historyGroupMenuKey, $event)">
placement="right" <PopoverTrigger asChild>
trigger="click"
:hide-after="0"
:width="180"
popper-style="padding: 4px; border-radius: 8px;">
<template #reference>
<el-button text size="small" :icon="MoreFilled" circle @click.stop></el-button> <el-button text size="small" :icon="MoreFilled" circle @click.stop></el-button>
</template> </PopoverTrigger>
<div class="favorites-group-menu"> <PopoverContent side="right" class="w-[180px] p-1 rounded-lg">
<button <div class="favorites-group-menu">
type="button" <button
class="favorites-group-menu__item favorites-group-menu__item--danger" type="button"
@click="handleHistoryClear"> class="favorites-group-menu__item favorites-group-menu__item--danger"
<span>{{ t('view.favorite.clear_tooltip') }}</span> @click="handleHistoryClear">
</button> <span>{{ t('view.favorite.clear_tooltip') }}</span>
</div> </button>
</el-popover> </div>
</PopoverContent>
</Popover>
</div> </div>
<div class="group-section__list"> <div class="group-section__list">
<div <div
@@ -504,6 +493,7 @@
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { useAppearanceSettingsStore, useAvatarStore, useFavoriteStore, useUserStore } from '../../stores'; import { useAppearanceSettingsStore, useAvatarStore, useFavoriteStore, useUserStore } from '../../stores';
import { Popover, PopoverContent, PopoverTrigger } from '../../components/ui/popover';
import { avatarRequest, favoriteRequest } from '../../api'; import { avatarRequest, favoriteRequest } from '../../api';
import { Badge } from '../../components/ui/badge'; import { Badge } from '../../components/ui/badge';
import { useFavoritesCardScaling } from './composables/useFavoritesCardScaling.js'; import { useFavoritesCardScaling } from './composables/useFavoritesCardScaling.js';

View File

@@ -95,71 +95,68 @@
<Badge variant="outline"> <Badge variant="outline">
{{ formatVisibility(group.visibility) }} {{ formatVisibility(group.visibility) }}
</Badge> </Badge>
<el-popover <Popover
:visible="activeGroupMenu === remoteGroupMenuKey(group.key)" :open="activeGroupMenu === remoteGroupMenuKey(group.key)"
@update:visible=" @update:open="
handleGroupMenuVisible(remoteGroupMenuKey(group.key), $event) handleGroupMenuVisible(remoteGroupMenuKey(group.key), $event)
" ">
placement="right" <PopoverTrigger asChild>
trigger="click"
:hide-after="0"
:width="220"
popper-style="padding: 4px; border-radius: 8px;">
<template #reference>
<el-button <el-button
text text
size="small" size="small"
:icon="MoreFilled" :icon="MoreFilled"
circle circle
@click.stop></el-button> @click.stop></el-button>
</template> </PopoverTrigger>
<div class="favorites-group-menu"> <PopoverContent side="right" class="w-[220px] p-1 rounded-lg">
<button <div class="favorites-group-menu">
type="button" <button
class="favorites-group-menu__item" type="button"
@click="handleRemoteRename(group)"> class="favorites-group-menu__item"
<span>{{ t('view.favorite.rename_tooltip') }}</span> @click="handleRemoteRename(group)">
</button> <span>{{ t('view.favorite.rename_tooltip') }}</span>
<el-popover </button>
placement="right" <el-popover
trigger="hover" placement="right"
:width="180" trigger="hover"
popper-style="padding: 4px; border-radius: 8px;"> :width="180"
<div class="group-visibility-menu"> popper-style="padding: 4px; border-radius: 8px;">
<button <div class="group-visibility-menu">
v-for="visibility in friendGroupVisibilityOptions" <button
:key="visibility" v-for="visibility in friendGroupVisibilityOptions"
type="button" :key="visibility"
:class="[ type="button"
'group-visibility-menu__item', :class="[
{ 'is-active': group.visibility === visibility } 'group-visibility-menu__item',
]" { 'is-active': group.visibility === visibility }
@click="handleVisibilitySelection(group, visibility)"> ]"
<span>{{ formatVisibility(visibility) }}</span> @click="handleVisibilitySelection(group, visibility)">
<span <span>{{ formatVisibility(visibility) }}</span>
v-if="group.visibility === visibility" <span
class="group-visibility-menu__check"> v-if="group.visibility === visibility"
<i class="ri-check-line"></i> class="group-visibility-menu__check">
</span> <i class="ri-check-line"></i>
</button> </span>
</div> </button>
<template #reference> </div>
<button <template #reference>
type="button" <button
class="favorites-group-menu__item favorites-group-menu__item--submenu"> type="button"
<span>{{ t('view.favorite.visibility_tooltip') }}</span> class="favorites-group-menu__item favorites-group-menu__item--submenu">
<span class="favorites-group-menu__arrow"></span> <span>{{ t('view.favorite.visibility_tooltip') }}</span>
</button> <span class="favorites-group-menu__arrow"></span>
</template> </button>
</el-popover> </template>
<button </el-popover>
type="button" <button
class="favorites-group-menu__item favorites-group-menu__item--danger" type="button"
@click="handleRemoteClear(group)"> class="favorites-group-menu__item favorites-group-menu__item--danger"
<span>{{ t('view.favorite.clear') }}</span> @click="handleRemoteClear(group)">
</button> <span>{{ t('view.favorite.clear') }}</span>
</div> </button>
</el-popover> </div>
</PopoverContent>
</Popover>
</div> </div>
</div> </div>
</template> </template>
@@ -287,6 +284,7 @@
import { toast } from 'vue-sonner'; import { toast } from 'vue-sonner';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { Popover, PopoverContent, PopoverTrigger } from '../../components/ui/popover';
import { useAppearanceSettingsStore, useFavoriteStore, useUserStore } from '../../stores'; import { useAppearanceSettingsStore, useFavoriteStore, useUserStore } from '../../stores';
import { Badge } from '../../components/ui/badge'; import { Badge } from '../../components/ui/badge';
import { favoriteRequest } from '../../api'; import { favoriteRequest } from '../../api';

View File

@@ -95,69 +95,68 @@
<Badge variant="outline"> <Badge variant="outline">
{{ formatVisibility(group.visibility) }} {{ formatVisibility(group.visibility) }}
</Badge> </Badge>
<el-popover <Popover
:visible="activeGroupMenu === remoteGroupMenuKey(group.key)" :open="activeGroupMenu === remoteGroupMenuKey(group.key)"
@update:visible=" @update:open="
handleGroupMenuVisible(remoteGroupMenuKey(group.key), $event) handleGroupMenuVisible(remoteGroupMenuKey(group.key), $event)
" ">
placement="right" <PopoverTrigger asChild>
trigger="click"
:hide-after="0"
:width="200"
popper-style="padding: 4px; border-radius: 8px;">
<template #reference>
<el-button <el-button
text text
size="small" size="small"
:icon="MoreFilled" :icon="MoreFilled"
circle circle
@click.stop></el-button> @click.stop></el-button>
</template> </PopoverTrigger>
<div class="favorites-group-menu"> <PopoverContent side="right" class="w-[200px] p-1 rounded-lg">
<button <div class="favorites-group-menu">
type="button" <button
class="favorites-group-menu__item" type="button"
@click="handleRemoteRename(group)"> class="favorites-group-menu__item"
<span>{{ t('view.favorite.rename_tooltip') }}</span> @click="handleRemoteRename(group)">
</button> <span>{{ t('view.favorite.rename_tooltip') }}</span>
<el-popover </button>
placement="right-start" <el-popover
trigger="hover" placement="right-start"
:width="200" trigger="hover"
popper-style="padding: 4px; border-radius: 8px;"> :width="200"
<div class="group-visibility-menu"> popper-style="padding: 4px; border-radius: 8px;">
<button <div class="group-visibility-menu">
v-for="visibility in worldGroupVisibilityOptions" <button
:key="visibility" v-for="visibility in worldGroupVisibilityOptions"
type="button" :key="visibility"
class="group-visibility-menu__item" type="button"
:class="{ 'is-active': group.visibility === visibility }" class="group-visibility-menu__item"
@click="handleVisibilitySelection(group, visibility)"> :class="{
<span>{{ formatVisibility(visibility) }}</span> 'is-active': group.visibility === visibility
<span }"
v-if="group.visibility === visibility" @click="handleVisibilitySelection(group, visibility)">
class="group-visibility-menu__check" <span>{{ formatVisibility(visibility) }}</span>
></span <span
> v-if="group.visibility === visibility"
</button> class="group-visibility-menu__check"
</div> ></span
<template #reference> >
<button </button>
type="button" </div>
class="favorites-group-menu__item favorites-group-menu__item--submenu"> <template #reference>
<span>{{ t('view.favorite.visibility_tooltip') }}</span> <button
<span class="favorites-group-menu__arrow"></span> type="button"
</button> class="favorites-group-menu__item favorites-group-menu__item--submenu">
</template> <span>{{ t('view.favorite.visibility_tooltip') }}</span>
</el-popover> <span class="favorites-group-menu__arrow"></span>
<button </button>
type="button" </template>
class="favorites-group-menu__item favorites-group-menu__item--danger" </el-popover>
@click="handleRemoteClear(group)"> <button
<span>{{ t('view.favorite.clear') }}</span> type="button"
</button> class="favorites-group-menu__item favorites-group-menu__item--danger"
</div> @click="handleRemoteClear(group)">
</el-popover> <span>{{ t('view.favorite.clear') }}</span>
</button>
</div>
</PopoverContent>
</Popover>
</div> </div>
</div> </div>
</template> </template>
@@ -210,39 +209,36 @@
<div class="group-item__right"> <div class="group-item__right">
<span class="group-item__count">{{ localWorldFavGroupLength(group) }}</span> <span class="group-item__count">{{ localWorldFavGroupLength(group) }}</span>
<div class="group-item__bottom"> <div class="group-item__bottom">
<el-popover <Popover
:visible="activeGroupMenu === localGroupMenuKey(group)" :open="activeGroupMenu === localGroupMenuKey(group)"
@update:visible=" @update:open="
handleGroupMenuVisible(localGroupMenuKey(group), $event) handleGroupMenuVisible(localGroupMenuKey(group), $event)
" ">
placement="right" <PopoverTrigger asChild>
trigger="click"
:hide-after="0"
:width="200"
popper-style="padding: 4px; border-radius: 8px;">
<template #reference>
<el-button <el-button
text text
size="small" size="small"
:icon="MoreFilled" :icon="MoreFilled"
circle circle
@click.stop></el-button> @click.stop></el-button>
</template> </PopoverTrigger>
<div class="favorites-group-menu"> <PopoverContent side="right" class="w-[200px] p-1 rounded-lg">
<button <div class="favorites-group-menu">
type="button" <button
class="favorites-group-menu__item" type="button"
@click="handleLocalRename(group)"> class="favorites-group-menu__item"
<span>{{ t('view.favorite.rename_tooltip') }}</span> @click="handleLocalRename(group)">
</button> <span>{{ t('view.favorite.rename_tooltip') }}</span>
<button </button>
type="button" <button
class="favorites-group-menu__item favorites-group-menu__item--danger" type="button"
@click="handleLocalDelete(group)"> class="favorites-group-menu__item favorites-group-menu__item--danger"
<span>{{ t('view.favorite.delete_tooltip') }}</span> @click="handleLocalDelete(group)">
</button> <span>{{ t('view.favorite.delete_tooltip') }}</span>
</div> </button>
</el-popover> </div>
</PopoverContent>
</Popover>
</div> </div>
</div> </div>
</div> </div>
@@ -412,6 +408,7 @@
import { toast } from 'vue-sonner'; import { toast } from 'vue-sonner';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { Popover, PopoverContent, PopoverTrigger } from '../../components/ui/popover';
import { useAppearanceSettingsStore, useFavoriteStore, useWorldStore } from '../../stores'; import { useAppearanceSettingsStore, useFavoriteStore, useWorldStore } from '../../stores';
import { favoriteRequest, worldRequest } from '../../api'; import { favoriteRequest, worldRequest } from '../../api';
import { Badge } from '../../components/ui/badge'; import { Badge } from '../../components/ui/badge';

View File

@@ -9,8 +9,8 @@
:prefix-icon="Search" :prefix-icon="Search"
clearable clearable
placeholder="Search Friend"></el-input> placeholder="Search Friend"></el-input>
<el-popover placement="bottom" trigger="click" :width="350"> <Popover>
<template #reference> <PopoverTrigger asChild>
<div> <div>
<TooltipWrapper :content="t('view.charts.instance_activity.settings.header')" side="top"> <TooltipWrapper :content="t('view.charts.instance_activity.settings.header')" side="top">
<el-button style="margin-right: 5px" circle <el-button style="margin-right: 5px" circle
@@ -18,40 +18,42 @@
></el-button> ></el-button>
</TooltipWrapper> </TooltipWrapper>
</div> </div>
</template> </PopoverTrigger>
<div style="display: flex; justify-content: space-between; align-items: center"> <PopoverContent side="bottom" class="w-[350px]">
<span class="friend-view__settings-label">{{ <div style="display: flex; justify-content: space-between; align-items: center">
t('view.friends_locations.separate_same_instance_friends') <span class="friend-view__settings-label">{{
}}</span> t('view.friends_locations.separate_same_instance_friends')
<el-switch v-model="showSameInstance" /> }}</span>
</div> <el-switch v-model="showSameInstance" />
<div class="friend-view__settings-row">
<span class="friend-view__settings-label">{{ t('view.friends_locations.scale') }}</span>
<div class="friend-view__scale-control">
<span class="friend-view__scale-value">{{ cardScalePercentLabel }}&nbsp;</span>
<el-slider
v-model="cardScale"
class="friend-view__slider"
:min="0.5"
:max="1.0"
:step="0.01"
:show-tooltip="false" />
</div> </div>
</div> <div class="friend-view__settings-row">
<div class="friend-view__settings-row"> <span class="friend-view__settings-label">{{ t('view.friends_locations.scale') }}</span>
<span class="friend-view__settings-label">{{ t('view.friends_locations.spacing') }}</span> <div class="friend-view__scale-control">
<div class="friend-view__scale-control"> <span class="friend-view__scale-value">{{ cardScalePercentLabel }}&nbsp;</span>
<span class="friend-view__scale-value">{{ cardSpacingPercentLabel }}&nbsp;</span> <el-slider
<el-slider v-model="cardScale"
v-model="cardSpacing" class="friend-view__slider"
class="friend-view__slider" :min="0.5"
:min="0.25" :max="1.0"
:max="1.0" :step="0.01"
:step="0.05" :show-tooltip="false" />
:show-tooltip="false" /> </div>
</div> </div>
</div> <div class="friend-view__settings-row">
</el-popover> <span class="friend-view__settings-label">{{ t('view.friends_locations.spacing') }}</span>
<div class="friend-view__scale-control">
<span class="friend-view__scale-value">{{ cardSpacingPercentLabel }}&nbsp;</span>
<el-slider
v-model="cardSpacing"
class="friend-view__slider"
:min="0.25"
:max="1.0"
:step="0.05"
:show-tooltip="false" />
</div>
</div>
</PopoverContent>
</Popover>
</div> </div>
</div> </div>
<div v-else class="friend-view__toolbar friend-view__toolbar--loading"> <div v-else class="friend-view__toolbar friend-view__toolbar--loading">
@@ -167,6 +169,7 @@
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { Popover, PopoverContent, PopoverTrigger } from '../../components/ui/popover';
import { getFriendsLocations } from '../../shared/utils/location.js'; import { getFriendsLocations } from '../../shared/utils/location.js';
import { useFriendStore } from '../../stores'; import { useFriendStore } from '../../stores';