Skip to content

Commit

Permalink
Merge pull request #656 from codeworks-projects/feat/replace-tooltip-…
Browse files Browse the repository at this point in the history
…with-popover

Feat/replace tooltip with popover
  • Loading branch information
RudiThoeni authored Jan 16, 2025
2 parents 4fa94f1 + 2205163 commit 1a9aae7
Show file tree
Hide file tree
Showing 10 changed files with 246 additions and 164 deletions.
28 changes: 19 additions & 9 deletions databrowser/src/components/list/ListWithMore.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,34 @@ SPDX-License-Identifier: AGPL-3.0-or-later
<template>
<div class="flex">
{{ dataset.sources[0] }}
<TooltipCustom v-if="dataset.sources.length > 0">
<template #default>
<button v-if="dataset.sources.length > 1" class="ml-1 text-green-700">
<PopoverCustom v-if="dataset.sources.length > 0" has-arrow>
<template #trigger>
<PopoverCustomButton
v-if="dataset.sources.length > 1"
class="ml-1 text-green-700"
>
+{{ dataset.sources.length - 1 }} others
</button>
</PopoverCustomButton>
</template>
<template #container>
<span class="text-sm text-dialog">
{{ dataset.sources.slice(1).join(', ') }}
</span>
<PopoverCustomPanel>
<PopoverContent class="text-sm text-dialog">
<span>
{{ dataset.sources.slice(1).join(', ') }}
</span>
</PopoverContent>
</PopoverCustomPanel>
</template>
</TooltipCustom>
</PopoverCustom>
</div>
</template>

<script setup lang="ts">
import { TourismMetaData } from '../../domain/metaDataConfig/tourism/types';
import TooltipCustom from '../tooltip/TooltipCustom.vue';
import PopoverCustom from '../popover/PopoverCustom.vue';
import PopoverCustomPanel from '../popover/PopoverCustomPanel.vue';
import PopoverContent from '../popover/PopoverContent.vue';
import PopoverCustomButton from '../popover/PopoverCustomButton.vue';

defineProps<{ dataset: TourismMetaData }>();
</script>
47 changes: 41 additions & 6 deletions databrowser/src/components/popover/PopoverCustom.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-or-later

<template>
<PopoverGroup>
<Popover>
<Popover v-slot="{ open }">
<span ref="trigger">
<slot name="trigger"></slot>
</span>
Expand All @@ -21,6 +21,15 @@ SPDX-License-Identifier: AGPL-3.0-or-later
}"
>
<slot name="container"></slot>

<PopoverTransition v-if="hasArrow">
<div
v-show="open"
ref="arrow"
class="absolute size-4 rotate-45 border-gray-400 bg-white"
:class="arrowClasses"
></div>
</PopoverTransition>
</div>
</Teleport>
</Popover>
Expand All @@ -30,14 +39,40 @@ SPDX-License-Identifier: AGPL-3.0-or-later
<script setup lang="ts">
import { Popover, PopoverGroup } from '@headlessui/vue';
import { useFloatingUi } from '../utils/useFloatingUi';
import { computed, ref } from 'vue';
import PopoverTransition from './PopoverTransition.vue';

withDefaults(defineProps<{ fullScreenWidth?: boolean; zIndex?: number }>(), {
fullScreenWidth: true,
zIndex: undefined,
});
const props = withDefaults(
defineProps<{
fullScreenWidth?: boolean;
zIndex?: number;
hasArrow?: boolean;
leftOffset?: number;
}>(),
{
fullScreenWidth: true,
zIndex: undefined,
hasArrow: false,
leftOffset: undefined,
}
);

const [trigger, container] = useFloatingUi({
const arrow = ref();

const [trigger, container, placement] = useFloatingUi({
placement: 'bottom-start',
offset: 8,
arrow,
leftOffset: props.leftOffset,
});

const arrowClasses = computed(() =>
placement.value.startsWith(`bottom`)
? `border-t border-l`
: placement.value.startsWith(`top`)
? `border-b border-r`
: placement.value.startsWith(`left`)
? `border-t border-r`
: `border-b border-l`
);
</script>
56 changes: 54 additions & 2 deletions databrowser/src/components/popover/PopoverCustomButton.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,65 @@ SPDX-License-Identifier: AGPL-3.0-or-later
-->

<template>
<PopoverButton v-slot="{ open, close }" :disabled="disabled">
<PopoverButton
ref="popoverButtonRef"
v-slot="{ open, close }"
:disabled="disabled"
:class="{
relative: triggerOnHover,
}"
>
<slot :open="open" :close="close"></slot>
<span
v-if="triggerOnHover"
ref="triggerHoverRef"
class="absolute left-0 top-0 h-full w-full"
@click.stop="onTriggerHoverClick()"
@mouseover="onTriggerMouseHover(open)"
@mouseleave="onTriggerMouseLeave(close)"
>
</span>
</PopoverButton>
</template>

<script setup lang="ts">
import { ref } from 'vue';
import { PopoverButton } from '@headlessui/vue';
import { useTimeoutFn } from '@vueuse/core';

defineProps<{ disabled?: boolean }>();
defineProps<{ disabled?: boolean; triggerOnHover?: boolean }>();

const emit = defineEmits(['triggerClick']);

const popoverButtonRef = ref();
const triggerHoverRef = ref();

const onTriggerMouseHover = (isOpen: boolean) => {
if (isOpen || isPopoverButtonClickPending.value) return;

startPopoverButtonClick();
};

const onTriggerMouseLeave = (isClose: boolean) => {
if (isClose) return;

stopPopoverButtonClick();
startPopoverButtonClick();
};

const onTriggerHoverClick = () => {
emit('triggerClick');
};

const {
isPending: isPopoverButtonClickPending,
start: startPopoverButtonClick,
stop: stopPopoverButtonClick,
} = useTimeoutFn(
() => {
popoverButtonRef.value.$el.click();
},
100,
{ immediate: false }
);
</script>
12 changes: 3 additions & 9 deletions databrowser/src/components/popover/PopoverCustomPanel.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-or-later
-->

<template>
<transition
enter-active-class="transition duration-100 ease-out"
enter-from-class="transform scale-95 opacity-0"
enter-to-class="transform scale-100 opacity-100"
leave-active-class="transition duration-75 ease-out"
leave-from-class="transform scale-100 opacity-100"
leave-to-class="transform scale-95 opacity-0"
>
<PopoverTransition>
<PopoverPanel v-slot="{ open, close }" class="z-20">
<div class="rounded bg-white shadow-md ring-1 ring-gray-400">
<ButtonCustom
Expand All @@ -28,14 +21,15 @@ SPDX-License-Identifier: AGPL-3.0-or-later
<slot :open="open" :close="close"></slot>
</div>
</PopoverPanel>
</transition>
</PopoverTransition>
</template>

<script setup lang="ts">
import { PopoverPanel } from '@headlessui/vue';
import IconClose from '../svg/IconClose.vue';
import ButtonCustom from '../button/ButtonCustom.vue';
import { Size, Variant } from '../button/types';
import PopoverTransition from './PopoverTransition.vue';

withDefaults(defineProps<{ hasCloseButton?: boolean }>(), {
hasCloseButton: true,
Expand Down
18 changes: 18 additions & 0 deletions databrowser/src/components/popover/PopoverTransition.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<!--
SPDX-FileCopyrightText: NOI Techpark <digital@noi.bz.it>

SPDX-License-Identifier: AGPL-3.0-or-later
-->

<template>
<transition
enter-active-class="transition duration-100 ease-out"
enter-from-class="transform scale-95 opacity-0"
enter-to-class="transform scale-100 opacity-100"
leave-active-class="transition duration-75 ease-out"
leave-from-class="transform scale-100 opacity-100"
leave-to-class="transform scale-95 opacity-0"
>
<slot />
</transition>
</template>
82 changes: 0 additions & 82 deletions databrowser/src/components/tooltip/TooltipCustom.vue

This file was deleted.

18 changes: 13 additions & 5 deletions databrowser/src/components/utils/useFloatingUi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ export interface UseFloatingUi {
placement: Placement;
matchReferenceWidth?: boolean;
offset?: number;
leftOffset?: number;
arrow?: Ref<HTMLElement>;

}

export const useFloatingUi = (
Expand Down Expand Up @@ -50,8 +52,14 @@ export const useFloatingUi = (
middleware,
}).then(({ x, y, placement: currentPlacement, middlewareData }) => {
// Position tooltip
const [staticPlacement, dynamicPlacement] =
currentPlacement.split('-');

const leftOffset =
(options.leftOffset || 0) * (dynamicPlacement === 'end' ? 1 : -1);

Object.assign(tooltipEl.style, {
left: `${x}px`,
left: `${x + leftOffset}px`,
top: `${y}px`,
});

Expand All @@ -61,24 +69,24 @@ export const useFloatingUi = (
// If arrow element is provided, handle its positioning
if (middlewareData.arrow != null) {
const { x: arrowX, y: arrowY } = middlewareData.arrow;
const splittedPlacement = currentPlacement.split('-')[0];

const staticSide = {
top: 'bottom',
right: 'left',
bottom: 'top',
left: 'right',
}[splittedPlacement]!;
}[staticPlacement]!;

if (arrowEl != null) {
if(arrowEl){
Object.assign(arrowEl.style, {
left: arrowX != null ? `${arrowX}px` : '',
left: arrowX != null ? `${arrowX - leftOffset}px` : '',
top: arrowY != null ? `${arrowY}px` : '',
right: '',
bottom: '',
[staticSide]: '-8px',
});
}

}
});
});
Expand Down
Loading

0 comments on commit 1a9aae7

Please sign in to comment.