Skip to content

Commit 85ee8a1

Browse files
modernize TourStep component
1 parent 21ece4b commit 85ee8a1

2 files changed

Lines changed: 107 additions & 108 deletions

File tree

client/src/components/Tour/TourStep.vue

Lines changed: 107 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -1,110 +1,119 @@
1+
<script setup lang="ts">
2+
import { faArrowRight, faCheck, faPlay, faSpinner, faSquare, faTimes } from "@fortawesome/free-solid-svg-icons";
3+
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
4+
import { createPopper } from "@popperjs/core";
5+
import { computed, ref, watch } from "vue";
6+
7+
import type { TourStep } from "@/api/tours";
8+
9+
import GButton from "../BaseComponents/GButton.vue";
10+
11+
const props = defineProps<{
12+
step: TourStep;
13+
isPlaying: boolean;
14+
isLast: boolean;
15+
waitingOnElement?: string | null;
16+
}>();
17+
18+
const emit = defineEmits<{
19+
(e: "end"): void;
20+
(e: "next"): void;
21+
(e: "play", value: boolean): void;
22+
}>();
23+
24+
const targetElement = computed(() => {
25+
if (props.step.element) {
26+
return document.querySelector(props.step.element);
27+
}
28+
return null;
29+
});
30+
31+
const targetElementVisible = computed(() => {
32+
const el = targetElement.value;
33+
if (el) {
34+
const rect = el.getBoundingClientRect();
35+
return rect && rect.width > 0 && rect.height > 0;
36+
}
37+
return false;
38+
});
39+
40+
const tourElement = ref<HTMLElement | null>(null);
41+
watch(
42+
() => tourElement.value,
43+
() => {
44+
if (tourElement.value) {
45+
createStep();
46+
}
47+
},
48+
{ immediate: true }
49+
);
50+
51+
function createStep() {
52+
if (targetElement.value && targetElementVisible.value && tourElement.value) {
53+
createPopper(targetElement.value, tourElement.value, {
54+
modifiers: [
55+
{
56+
name: "preventOverflow",
57+
options: {
58+
altAxis: true,
59+
tether: false,
60+
padding: 20,
61+
},
62+
},
63+
],
64+
strategy: "absolute",
65+
placement: "auto",
66+
});
67+
}
68+
}
69+
</script>
70+
171
<template>
272
<div
3-
ref="tour-element"
73+
ref="tourElement"
474
class="tour-element"
575
:class="{ 'tour-element-sticky': !targetElementVisible, 'tour-has-title': !!step.title }">
676
<div v-if="step.title" class="tour-header">
77+
<!-- eslint-disable-next-line vue/no-v-html -->
778
<div class="tour-title" v-html="step.title"></div>
879
</div>
80+
<!-- eslint-disable-next-line vue/no-v-html -->
981
<div v-if="step.content" class="tour-content" v-html="step.content" />
10-
<div class="tour-buttons">
11-
<div v-if="isLast">
12-
<button class="tour-button tour-end" @click.prevent="$emit('end')">Close</button>
13-
</div>
14-
<div v-else-if="isPlaying">
15-
<button
16-
v-if="waitingOnElement"
17-
v-b-tooltip.hover
18-
:title="`Waiting for ${waitingOnElement}`"
19-
class="btn btn-link btn-sm">
20-
<FontAwesomeIcon :icon="faSpinner" spin />
21-
</button>
22-
<button class="tour-button tour-stop" @click.prevent="$emit('play', false)">Stop</button>
23-
</div>
24-
<div v-else>
25-
<button
26-
v-if="waitingOnElement"
27-
v-b-tooltip.hover
28-
:title="`Waiting for ${waitingOnElement}`"
29-
class="btn btn-link btn-sm">
30-
<FontAwesomeIcon :icon="faSpinner" spin />
31-
</button>
32-
<button class="tour-button tour-end" @click.prevent="$emit('end')">End Tour</button>
33-
<button class="tour-button tour-play" @click.prevent="$emit('play', true)">Play</button>
34-
<button class="tour-button tour-next" @click.prevent="$emit('next')">Continue</button>
82+
<div class="float-right p-2">
83+
<div>
84+
<template v-if="waitingOnElement && (isPlaying || !isLast)">
85+
<GButton tooltip icon-only transparent :title="`Waiting for ${waitingOnElement}`">
86+
<FontAwesomeIcon :icon="faSpinner" spin />
87+
</GButton>
88+
</template>
89+
<template v-if="isLast">
90+
<GButton class="tour-end" size="small" color="blue" @click.prevent="emit('end')">
91+
<FontAwesomeIcon :icon="faCheck" />
92+
Close
93+
</GButton>
94+
</template>
95+
<template v-else-if="isPlaying">
96+
<GButton class="tour-stop" size="small" color="blue" @click.prevent="emit('play', false)">
97+
<FontAwesomeIcon :icon="faSquare" />
98+
Stop Auto-Playing
99+
</GButton>
100+
</template>
101+
<template v-else>
102+
<GButton class="tour-end" size="small" color="blue" @click.prevent="emit('end')">
103+
<FontAwesomeIcon :icon="faTimes" />
104+
End Tour
105+
</GButton>
106+
<GButton class="tour-play" size="small" color="blue" @click.prevent="emit('play', true)">
107+
<FontAwesomeIcon :icon="faPlay" />
108+
Auto-Play Tour
109+
</GButton>
110+
<GButton class="tour-next" size="small" color="blue" @click.prevent="emit('next')">
111+
<FontAwesomeIcon :icon="faArrowRight" />
112+
Continue
113+
</GButton>
114+
</template>
35115
</div>
36116
</div>
37-
<div v-if="targetElement" class="tour-arrow" data-popper-arrow />
117+
<div v-if="targetElementVisible" class="tour-arrow" data-popper-arrow />
38118
</div>
39119
</template>
40-
41-
<script>
42-
import { faSpinner } from "@fortawesome/free-solid-svg-icons";
43-
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
44-
import { createPopper } from "@popperjs/core";
45-
46-
export default {
47-
components: {
48-
FontAwesomeIcon,
49-
},
50-
props: {
51-
step: {
52-
type: Object,
53-
},
54-
isPlaying: {
55-
type: Boolean,
56-
},
57-
isLast: {
58-
type: Boolean,
59-
},
60-
waitingOnElement: {
61-
type: String,
62-
default: null,
63-
},
64-
},
65-
data() {
66-
return {
67-
faSpinner,
68-
};
69-
},
70-
computed: {
71-
targetElement() {
72-
if (this.step.element) {
73-
return document.querySelector(this.step.element);
74-
}
75-
return null;
76-
},
77-
targetElementVisible() {
78-
const el = this.targetElement;
79-
if (el) {
80-
const rect = el.getBoundingClientRect();
81-
return rect && rect.width > 0 && rect.height > 0;
82-
}
83-
return false;
84-
},
85-
},
86-
mounted() {
87-
this.createStep();
88-
},
89-
methods: {
90-
createStep() {
91-
if (this.targetElement && this.targetElementVisible) {
92-
createPopper(this.targetElement, this.$refs["tour-element"], {
93-
modifiers: [
94-
{
95-
name: "preventOverflow",
96-
options: {
97-
altAxis: true,
98-
tether: false,
99-
padding: 20,
100-
},
101-
},
102-
],
103-
strategy: "absolute",
104-
placement: "auto",
105-
});
106-
}
107-
},
108-
},
109-
};
110-
</script>

client/src/style/scss/tour.scss

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -29,16 +29,6 @@
2929
border-radius: $border-radius-base;
3030
color: $text-color;
3131
}
32-
.tour-buttons {
33-
@extend .float-right;
34-
@extend .p-2;
35-
.tour-button {
36-
@extend .ml-1;
37-
@extend .btn;
38-
@extend .btn-sm;
39-
@extend .btn-info;
40-
}
41-
}
4232
}
4333

4434
.tour-element,

0 commit comments

Comments
 (0)