Skip to content

Commit 6cc0701

Browse files
committed
Popover migration to popper js
Signed-off-by: Gašper Grom <[email protected]>
1 parent 8b64fed commit 6cc0701

File tree

7 files changed

+150
-181
lines changed

7 files changed

+150
-181
lines changed
Lines changed: 28 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,28 @@
1-
html {
2-
-ms-text-size-adjust: 100%;
3-
-webkit-text-size-adjust: 100%;
4-
-webkit-font-smoothing: antialiased;
5-
-moz-osx-font-smoothing: grayscale;
6-
-webkit-tap-highlight-color: transparent;
7-
height: 100%;
8-
overflow-y: hidden;
9-
scroll-behavior: smooth;
10-
-webkit-overflow-scrolling: touch;
11-
position: relative;
12-
}
13-
14-
body {
15-
margin: 0;
16-
height: 100%;
17-
overflow: auto;
18-
position: relative;
19-
color: var(--lfx-color-text);
20-
background: var(--lfx-color-background);
21-
-webkit-overflow-scrolling: touch;
22-
// Base font size used for rem
23-
font-size: 16px;
24-
}
25-
26-
*{
27-
font-family: var(--lfx-font-primary), sans-serif;
28-
}
1+
//html {
2+
// -ms-text-size-adjust: 100%;
3+
// -webkit-text-size-adjust: 100%;
4+
// -webkit-font-smoothing: antialiased;
5+
// -moz-osx-font-smoothing: grayscale;
6+
// -webkit-tap-highlight-color: transparent;
7+
// height: 100%;
8+
// overflow-y: hidden;
9+
// scroll-behavior: smooth;
10+
// -webkit-overflow-scrolling: touch;
11+
// position: relative;
12+
//}
13+
//
14+
//body {
15+
// margin: 0;
16+
// height: 100%;
17+
// overflow: auto;
18+
// position: relative;
19+
// color: var(--lfx-color-text);
20+
// background: var(--lfx-color-background);
21+
// -webkit-overflow-scrolling: touch;
22+
// // Base font size used for rem
23+
// font-size: 16px;
24+
//}
25+
//
26+
//*{
27+
// font-family: var(--lfx-font-primary), sans-serif;
28+
//}

frontend/app/components/modules/project/components/shared/header.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
class="font-bold mr-3 ease-linear transition-all font-secondary duration-200 text-heading-4"
2828
:class="[
2929
scrollTop > 50 ? 'md:text-heading-3' : 'md:text-heading-2',
30-
repoName ? 'w-[25ch] truncate' : ''
30+
repoName ? 'max-w-[25ch] truncate' : ''
3131
]"
3232
>
3333
{{ props.project.name }}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
export const getRepoNameFromUrl = (url: string): string => {
2+
try {
3+
const urlObj = new URL(url);
4+
const pathParts = urlObj.pathname.split('/').filter(Boolean);
5+
6+
if (url.includes('gerrit')) {
7+
if (url.includes('/c/')) {
8+
return pathParts.slice(2, 4).join('/');
9+
}
10+
if (url.includes('/q/project:')) {
11+
const last = pathParts.at(-1) as string;
12+
if(last.includes('project:')) {
13+
return last.split(':').at(-1) as string;
14+
}
15+
return pathParts.at(-1) as string;
16+
}
17+
} else if (url.includes('github.com')) {
18+
return pathParts.slice(0, 2).join('/');
19+
}
20+
21+
return url;
22+
} catch {
23+
return url;
24+
}
25+
}
Lines changed: 2 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,78 +1,15 @@
11
.c-popover {
2-
@apply relative w-fit flex;
3-
42
&__trigger {
53
@apply w-fit;
64
}
75

86
&__content {
9-
@apply absolute z-50 w-max transition overflow-visible;
7+
@apply z-50 w-max transition overflow-visible;
108
@apply bg-white shadow-lg rounded-lg border border-neutral-200;
9+
@apply outline-1 outline-transparent;
1110

1211
&.is-hidden {
1312
@apply invisible opacity-0 pointer-events-none;
1413
}
15-
16-
&.is-placed {
17-
&-bottom-start {
18-
left: var(--lfx-popover-trigger-left);
19-
top: calc(var(--lfx-popover-trigger-bottom) + var(--lfx-popover-spacing));
20-
}
21-
22-
&-bottom-end {
23-
left: calc(var(--lfx-popover-trigger-right) - var(--lfx-popover-content-width));
24-
top: calc(var(--lfx-popover-trigger-top) + var(--lfx-popover-trigger-height) + var(--lfx-popover-spacing));
25-
}
26-
27-
&-bottom {
28-
left: calc(var(--lfx-popover-trigger-left) + var(--lfx-popover-trigger-width) / 2 - var(--lfx-popover-content-width) / 2);
29-
top: calc(var(--lfx-popover-trigger-bottom) + var(--lfx-popover-spacing));
30-
}
31-
32-
&-top-start {
33-
left: var(--lfx-popover-trigger-left);
34-
top: calc(var(--lfx-popover-trigger-top) - var(--lfx-popover-content-height) - var(--lfx-popover-spacing));
35-
}
36-
37-
&-top-end {
38-
left: calc(var(--lfx-popover-trigger-right) - var(--lfx-popover-content-width));
39-
top: calc(var(--lfx-popover-trigger-top) - var(--lfx-popover-content-height) - var(--lfx-popover-spacing));
40-
}
41-
42-
&-top {
43-
left: calc(var(--lfx-popover-trigger-left) + var(--lfx-popover-trigger-width) / 2 - var(--lfx-popover-content-width) / 2);
44-
top: calc(var(--lfx-popover-trigger-top) - var(--lfx-popover-content-height) - var(--lfx-popover-spacing));
45-
}
46-
47-
&-left {
48-
left: calc(var(--lfx-popover-trigger-left) - var(--lfx-popover-content-width) - var(--lfx-popover-spacing));
49-
top: calc(var(--lfx-popover-trigger-top) + var(--lfx-popover-trigger-height) / 2 - var(--lfx-popover-content-height) / 2);
50-
}
51-
52-
&-left-start {
53-
left: calc(var(--lfx-popover-trigger-left) - var(--lfx-popover-content-width) - var(--lfx-popover-spacing));
54-
top: var(--lfx-popover-trigger-top);
55-
}
56-
57-
&-left-end {
58-
left: calc(var(--lfx-popover-trigger-left) - var(--lfx-popover-content-width) - var(--lfx-popover-spacing));
59-
top: calc(var(--lfx-popover-trigger-bottom) - var(--lfx-popover-content-height));
60-
}
61-
62-
&-right {
63-
left: calc(var(--lfx-popover-trigger-right) + var(--lfx-popover-spacing));
64-
top: calc(var(--lfx-popover-trigger-top) + var(--lfx-popover-trigger-height) / 2 - var(--lfx-popover-content-height) / 2);
65-
}
66-
67-
&-right-start {
68-
left: calc(var(--lfx-popover-trigger-right) + var(--lfx-popover-spacing));
69-
top: var(--lfx-popover-trigger-top);
70-
}
71-
72-
&-right-end {
73-
left: calc(var(--lfx-popover-trigger-right) + var(--lfx-popover-spacing));
74-
top: calc(var(--lfx-popover-trigger-bottom) - var(--lfx-popover-content-height));
75-
}
76-
}
7714
}
7815
}

frontend/app/components/uikit/popover/popover.vue

Lines changed: 85 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -1,126 +1,124 @@
11
<template>
2-
<div class="c-popover">
3-
<div
4-
ref="trigger"
5-
class="c-popover__trigger"
6-
@click.stop="props.triggerEvent === 'click' ? togglePopover() : null"
7-
@mouseenter="props.triggerEvent === 'hover' ? showPopover() : null"
8-
@mouseleave="props.triggerEvent === 'hover' ? hidePopover() : null"
9-
>
10-
<slot :close="hidePopover" />
11-
</div>
12-
<Teleport
13-
v-if="!props.disabled && (props.persistent || isVisible)"
14-
to="body"
15-
>
16-
<div
17-
ref="popover"
18-
:style="popoverStyle"
19-
class="c-popover__content"
20-
:class="[`is-placed-${props.placement}`, { 'is-hidden': props.persistent && !isVisible }]"
21-
>
22-
<slot
23-
name="content"
24-
:close="hidePopover"
25-
/>
26-
</div>
27-
</Teleport>
2+
<div
3+
ref="trigger"
4+
class="c-popover__trigger"
5+
@click="handleClick"
6+
>
7+
<slot />
8+
</div>
9+
10+
<div
11+
v-show="isVisible"
12+
ref="popover"
13+
class="c-popover__content"
14+
:class="placement"
15+
>
16+
<slot
17+
name="content"
18+
:close="closePopover"
19+
/>
2820
</div>
2921
</template>
3022

3123
<script lang="ts" setup>
3224
import {
33-
computed, onBeforeUnmount, ref, watch,
25+
ref, watch, onMounted, onBeforeUnmount
3426
} from 'vue';
35-
import type { PopoverPlacement } from '@/ui-kit/popover/types/PopoverPlacement';
36-
import type { PopoverTrigger } from '@/ui-kit/popover/types/PopoverTrigger';
37-
import useScroll from "~/components/shared/utils/scroll";
27+
import type { Instance, Placement } from '@popperjs/core';
28+
import { createPopper } from '@popperjs/core';
3829
3930
const props = withDefaults(defineProps<{
40-
placement?: PopoverPlacement,
41-
disabled?: boolean,
42-
spacing?: number,
31+
placement?: Placement,
32+
triggerEvent?: 'click' | 'hover',
4333
visibility?: boolean,
44-
triggerEvent?: PopoverTrigger,
45-
persistent?: boolean;
34+
spacing?: number,
35+
disabled?: boolean,
4636
}>(), {
4737
placement: 'bottom-start',
48-
disabled: false,
49-
spacing: 4,
50-
visibility: false,
5138
triggerEvent: 'click',
52-
persistent: false,
39+
visibility: false,
40+
spacing: 4,
41+
disabled: false,
5342
});
5443
55-
const emit = defineEmits<{(e: 'update:visibility', value: boolean): void }>();
56-
57-
const {scrollTop} = useScroll();
44+
const emit = defineEmits(['update:visibility']);
5845
59-
const trigger = ref(null);
60-
const popover = ref(null);
46+
const trigger = ref<HTMLElement | null>(null);
47+
const popover = ref<HTMLElement | null>(null);
48+
const popperInstance = ref<Instance | null>(null);
6149
const isVisible = ref(props.visibility);
6250
63-
watch(() => props.visibility, (newValue) => {
64-
isVisible.value = newValue;
65-
}, { immediate: true });
66-
67-
watch(isVisible, (newValue) => {
68-
emit('update:visibility', newValue);
51+
watch(() => props.visibility, (val) => {
52+
isVisible.value = val;
6953
});
54+
watch(isVisible, (val) => emit('update:visibility', val));
55+
56+
const createPopperInstance = () => {
57+
if (trigger.value && popover.value) {
58+
popperInstance.value = createPopper(trigger.value, popover.value, {
59+
strategy: 'fixed',
60+
placement: props.placement,
61+
modifiers: [
62+
{
63+
name: 'offset',
64+
options: {
65+
offset: [0, props.spacing],
66+
},
67+
},
68+
],
69+
});
70+
}
71+
};
7072
71-
const togglePopover = () => {
72-
isVisible.value = !isVisible.value;
73-
if (isVisible.value) addOutsideClickListener();
74-
else removeOutsideClickListener();
73+
const destroyPopperInstance = () => {
74+
popperInstance.value?.destroy();
75+
popperInstance.value = null;
7576
};
7677
77-
const showPopover = () => {
78+
const openPopover = async () => {
7879
isVisible.value = true;
79-
addOutsideClickListener();
8080
};
8181
82-
const hidePopover = () => {
82+
const closePopover = () => {
8383
isVisible.value = false;
84-
removeOutsideClickListener();
84+
document.removeEventListener('click', handleClickOutside);
8585
};
8686
87-
const handleClickOutside = (event: Event) => {
88-
if (
89-
!trigger.value?.contains(event.target)
90-
&& !popover.value?.contains(event.target)
91-
) {
92-
isVisible.value = false;
93-
removeOutsideClickListener();
87+
const handleClick = (e: Event) => {
88+
e.stopPropagation();
89+
if (props.triggerEvent === 'click') {
90+
if (isVisible.value) {
91+
closePopover();
92+
} else {
93+
openPopover();
94+
}
9495
}
9596
};
9697
97-
const addOutsideClickListener = () => {
98-
document.addEventListener('click', handleClickOutside);
99-
};
100-
101-
const removeOutsideClickListener = () => {
102-
document.removeEventListener('click', handleClickOutside);
98+
const handleClickOutside = (e: Event) => {
99+
if (
100+
popover.value
101+
&& !popover.value.contains(e.target as Node)
102+
&& !trigger.value?.contains(e.target as Node)
103+
) {
104+
closePopover();
105+
}
103106
};
104107
105-
const popoverStyle = computed(() => {
106-
if (!trigger.value || !popover.value) return {};
107-
108-
const triggerRect = trigger.value.getBoundingClientRect();
109-
return {
110-
'--lfx-popover-trigger-top': `${(triggerRect.top + scrollTop.value) / 16}rem`,
111-
'--lfx-popover-trigger-left': `${triggerRect.left / 16}rem`,
112-
'--lfx-popover-trigger-right': `${triggerRect.right / 16}rem`,
113-
'--lfx-popover-trigger-bottom': `${triggerRect.bottom / 16}rem`,
114-
'--lfx-popover-trigger-width': `${trigger.value.offsetWidth / 16}rem`,
115-
'--lfx-popover-trigger-height': `${trigger.value.offsetHeight / 16}rem`,
116-
'--lfx-popover-content-width': `${popover.value.offsetWidth / 16}rem`,
117-
'--lfx-popover-content-height': `${popover.value.offsetHeight / 16}rem`,
118-
'--lfx-popover-spacing': `${props.spacing / 16}rem`,
119-
};
108+
onMounted(() => {
109+
createPopperInstance();
110+
if (props.triggerEvent === 'hover') {
111+
trigger.value?.addEventListener('mouseenter', openPopover);
112+
trigger.value?.addEventListener('mouseleave', closePopover);
113+
}
120114
});
121115
122116
onBeforeUnmount(() => {
123-
removeOutsideClickListener();
117+
destroyPopperInstance();
118+
if (props.triggerEvent === 'hover') {
119+
trigger.value?.removeEventListener('mouseenter', openPopover);
120+
trigger.value?.removeEventListener('mouseleave', closePopover);
121+
}
124122
});
125123
</script>
126124

frontend/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
"@linuxfoundation/lfx-ui-core": "^0.0.14",
2020
"@nuxt/eslint": "^0.7.5",
2121
"@pinia/nuxt": "0.9.0",
22+
"@popperjs/core": "^2.11.8",
2223
"@primevue/themes": "^4.2.5",
2324
"echarts": "^5.6.0",
2425
"eslint": "^9.18.0",

0 commit comments

Comments
 (0)