Add support for showing progress
Browse files- index.html +6 -0
- src/config.ts +4 -1
- src/driver.ts +8 -0
- src/popover.ts +36 -15
- src/style.css +8 -0
index.html
CHANGED
@@ -3,6 +3,8 @@
|
|
3 |
<head>
|
4 |
<meta charset="UTF-8" />
|
5 |
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
|
|
|
6 |
<title>Vite App</title>
|
7 |
|
8 |
<style>
|
@@ -410,6 +412,7 @@ npm install driver.js</pre
|
|
410 |
animate: false,
|
411 |
backdropColor: "blue",
|
412 |
opacity: 0.3,
|
|
|
413 |
steps: basicTourSteps,
|
414 |
});
|
415 |
|
@@ -438,6 +441,8 @@ npm install driver.js</pre
|
|
438 |
const driverObj = driver({
|
439 |
animate: true,
|
440 |
opacity: 0.3,
|
|
|
|
|
441 |
steps: [
|
442 |
{
|
443 |
element: ".page-header",
|
@@ -524,6 +529,7 @@ npm install driver.js</pre
|
|
524 |
|
525 |
document.getElementById("basic-tour").addEventListener("click", () => {
|
526 |
const driverObj = driver({
|
|
|
527 |
steps: basicTourSteps,
|
528 |
});
|
529 |
|
|
|
3 |
<head>
|
4 |
<meta charset="UTF-8" />
|
5 |
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
6 |
+
<!-- prefetch image -->
|
7 |
+
<link rel="preconnect" href="https://i.imgur.com/" />
|
8 |
<title>Vite App</title>
|
9 |
|
10 |
<style>
|
|
|
412 |
animate: false,
|
413 |
backdropColor: "blue",
|
414 |
opacity: 0.3,
|
415 |
+
showProgress: true,
|
416 |
steps: basicTourSteps,
|
417 |
});
|
418 |
|
|
|
441 |
const driverObj = driver({
|
442 |
animate: true,
|
443 |
opacity: 0.3,
|
444 |
+
showProgress: true,
|
445 |
+
progressText: "{{current}} / {{total}}",
|
446 |
steps: [
|
447 |
{
|
448 |
element: ".page-header",
|
|
|
529 |
|
530 |
document.getElementById("basic-tour").addEventListener("click", () => {
|
531 |
const driverObj = driver({
|
532 |
+
showProgress: true,
|
533 |
steps: basicTourSteps,
|
534 |
});
|
535 |
|
src/config.ts
CHANGED
@@ -1,5 +1,5 @@
|
|
1 |
import { DriveStep } from "./driver";
|
2 |
-
import {AllowedButtons, PopoverDOM} from "./popover";
|
3 |
|
4 |
export type Config = {
|
5 |
steps?: DriveStep[];
|
@@ -17,9 +17,11 @@ export type Config = {
|
|
17 |
popoverClass?: string;
|
18 |
popoverOffset?: number;
|
19 |
showButtons?: AllowedButtons[];
|
|
|
20 |
disableButtons?: AllowedButtons[];
|
21 |
|
22 |
// Button texts
|
|
|
23 |
nextBtnText?: string;
|
24 |
prevBtnText?: string;
|
25 |
doneBtnText?: string;
|
@@ -49,6 +51,7 @@ export function configure(config: Config = {}) {
|
|
49 |
allowClose: true,
|
50 |
opacity: 0.7,
|
51 |
smoothScroll: false,
|
|
|
52 |
stagePadding: 10,
|
53 |
stageRadius: 5,
|
54 |
popoverOffset: 10,
|
|
|
1 |
import { DriveStep } from "./driver";
|
2 |
+
import { AllowedButtons, PopoverDOM } from "./popover";
|
3 |
|
4 |
export type Config = {
|
5 |
steps?: DriveStep[];
|
|
|
17 |
popoverClass?: string;
|
18 |
popoverOffset?: number;
|
19 |
showButtons?: AllowedButtons[];
|
20 |
+
showProgress?: boolean;
|
21 |
disableButtons?: AllowedButtons[];
|
22 |
|
23 |
// Button texts
|
24 |
+
progressText?: string;
|
25 |
nextBtnText?: string;
|
26 |
prevBtnText?: string;
|
27 |
doneBtnText?: string;
|
|
|
51 |
allowClose: true,
|
52 |
opacity: 0.7,
|
53 |
smoothScroll: false,
|
54 |
+
showProgress: false,
|
55 |
stagePadding: 10,
|
56 |
stageRadius: 5,
|
57 |
popoverOffset: 10,
|
src/driver.ts
CHANGED
@@ -120,13 +120,19 @@ export function driver(options: Config = {}) {
|
|
120 |
|
121 |
const doneBtnText = currentStep.popover?.doneBtnText || getConfig("doneBtnText") || "Done";
|
122 |
const allowsClosing = getConfig("allowClose");
|
|
|
|
|
|
|
123 |
|
|
|
124 |
highlight({
|
125 |
...currentStep,
|
126 |
popover: {
|
127 |
showButtons: ["next", "previous", ...(allowsClosing ? ["close" as AllowedButtons] : [])],
|
128 |
nextBtnText: !hasNextStep ? doneBtnText : undefined,
|
129 |
disableButtons: [...(!hasPreviousStep ? ["previous" as AllowedButtons] : [])],
|
|
|
|
|
130 |
onNextClick: () => {
|
131 |
if (!hasNextStep) {
|
132 |
destroy();
|
@@ -211,6 +217,8 @@ export function driver(options: Config = {}) {
|
|
211 |
popover: step.popover
|
212 |
? {
|
213 |
showButtons: [],
|
|
|
|
|
214 |
...step.popover!,
|
215 |
}
|
216 |
: undefined,
|
|
|
120 |
|
121 |
const doneBtnText = currentStep.popover?.doneBtnText || getConfig("doneBtnText") || "Done";
|
122 |
const allowsClosing = getConfig("allowClose");
|
123 |
+
const showProgress = typeof currentStep.popover?.showProgress !== "undefined" ? currentStep.popover?.showProgress : getConfig("showProgress")
|
124 |
+
const progressText = currentStep.popover?.progressText || getConfig("progressText") || "{{current}} of {{total}}";
|
125 |
+
const progressTextReplaced = progressText.replace("{{current}}", `${stepIndex + 1}`).replace("{{total}}", `${steps.length}`);
|
126 |
|
127 |
+
console.log(showProgress);
|
128 |
highlight({
|
129 |
...currentStep,
|
130 |
popover: {
|
131 |
showButtons: ["next", "previous", ...(allowsClosing ? ["close" as AllowedButtons] : [])],
|
132 |
nextBtnText: !hasNextStep ? doneBtnText : undefined,
|
133 |
disableButtons: [...(!hasPreviousStep ? ["previous" as AllowedButtons] : [])],
|
134 |
+
showProgress: showProgress,
|
135 |
+
progressText: progressTextReplaced,
|
136 |
onNextClick: () => {
|
137 |
if (!hasNextStep) {
|
138 |
destroy();
|
|
|
217 |
popover: step.popover
|
218 |
? {
|
219 |
showButtons: [],
|
220 |
+
showProgress: false,
|
221 |
+
progressText: "",
|
222 |
...step.popover!,
|
223 |
}
|
224 |
: undefined,
|
src/popover.ts
CHANGED
@@ -16,11 +16,13 @@ export type Popover = {
|
|
16 |
align?: Alignment;
|
17 |
|
18 |
showButtons?: AllowedButtons[];
|
|
|
19 |
disableButtons?: AllowedButtons[];
|
20 |
|
21 |
popoverClass?: string;
|
22 |
|
23 |
// Button texts
|
|
|
24 |
doneBtnText?: string;
|
25 |
nextBtnText?: string;
|
26 |
prevBtnText?: string;
|
@@ -41,6 +43,7 @@ export type PopoverDOM = {
|
|
41 |
title: HTMLElement;
|
42 |
description: HTMLElement;
|
43 |
footer: HTMLElement;
|
|
|
44 |
previousButton: HTMLElement;
|
45 |
nextButton: HTMLElement;
|
46 |
closeButton: HTMLElement;
|
@@ -70,13 +73,16 @@ export function renderPopover(element: Element, step: DriveStep) {
|
|
70 |
description,
|
71 |
showButtons,
|
72 |
disableButtons,
|
|
|
73 |
|
74 |
nextBtnText = getConfig("nextBtnText") || "Next →",
|
75 |
prevBtnText = getConfig("prevBtnText") || "← Previous",
|
|
|
76 |
} = step.popover || {};
|
77 |
|
78 |
popover.nextButton.innerHTML = nextBtnText;
|
79 |
popover.previousButton.innerHTML = prevBtnText;
|
|
|
80 |
|
81 |
if (title) {
|
82 |
popover.title.innerText = title;
|
@@ -93,27 +99,36 @@ export function renderPopover(element: Element, step: DriveStep) {
|
|
93 |
}
|
94 |
|
95 |
const showButtonsConfig: AllowedButtons[] = showButtons || getConfig("showButtons")!;
|
|
|
|
|
|
|
|
|
|
|
|
|
96 |
|
97 |
-
popover.closeButton.style.display = showButtonsConfig.includes("close") ?
|
98 |
-
|
|
|
99 |
popover.footer.style.display = "flex";
|
100 |
-
|
101 |
-
popover.
|
|
|
|
|
102 |
} else {
|
103 |
popover.footer.style.display = "none";
|
104 |
}
|
105 |
|
106 |
-
const disabledButtonsConfig: AllowedButtons[] = disableButtons || getConfig(
|
107 |
-
if (disabledButtonsConfig?.includes(
|
108 |
-
|
109 |
}
|
110 |
|
111 |
-
if (disabledButtonsConfig?.includes(
|
112 |
-
|
113 |
}
|
114 |
|
115 |
-
if (disabledButtonsConfig?.includes(
|
116 |
-
|
117 |
}
|
118 |
|
119 |
// Reset the popover position
|
@@ -182,7 +197,7 @@ export function renderPopover(element: Element, step: DriveStep) {
|
|
182 |
repositionPopover(element, step);
|
183 |
bringInView(popoverWrapper);
|
184 |
|
185 |
-
const onPopoverRendered = step.popover?.onPopoverRendered || getConfig(
|
186 |
if (onPopoverRendered) {
|
187 |
onPopoverRendered(popover);
|
188 |
}
|
@@ -566,13 +581,17 @@ function createPopover(): PopoverDOM {
|
|
566 |
description.style.display = "none";
|
567 |
description.innerText = "Popover description is here";
|
568 |
|
569 |
-
const footer = document.createElement("div");
|
570 |
-
footer.classList.add("driver-popover-footer");
|
571 |
-
|
572 |
const closeButton = document.createElement("button");
|
573 |
closeButton.classList.add("driver-popover-close-btn");
|
574 |
closeButton.innerHTML = "×";
|
575 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
576 |
const footerButtons = document.createElement("span");
|
577 |
footerButtons.classList.add("driver-popover-navigation-btns");
|
578 |
|
@@ -586,6 +605,7 @@ function createPopover(): PopoverDOM {
|
|
586 |
|
587 |
footerButtons.appendChild(previousButton);
|
588 |
footerButtons.appendChild(nextButton);
|
|
|
589 |
footer.appendChild(footerButtons);
|
590 |
|
591 |
wrapper.appendChild(closeButton);
|
@@ -604,6 +624,7 @@ function createPopover(): PopoverDOM {
|
|
604 |
nextButton,
|
605 |
closeButton,
|
606 |
footerButtons,
|
|
|
607 |
};
|
608 |
}
|
609 |
|
|
|
16 |
align?: Alignment;
|
17 |
|
18 |
showButtons?: AllowedButtons[];
|
19 |
+
showProgress?: boolean;
|
20 |
disableButtons?: AllowedButtons[];
|
21 |
|
22 |
popoverClass?: string;
|
23 |
|
24 |
// Button texts
|
25 |
+
progressText?: string;
|
26 |
doneBtnText?: string;
|
27 |
nextBtnText?: string;
|
28 |
prevBtnText?: string;
|
|
|
43 |
title: HTMLElement;
|
44 |
description: HTMLElement;
|
45 |
footer: HTMLElement;
|
46 |
+
progress: HTMLElement;
|
47 |
previousButton: HTMLElement;
|
48 |
nextButton: HTMLElement;
|
49 |
closeButton: HTMLElement;
|
|
|
73 |
description,
|
74 |
showButtons,
|
75 |
disableButtons,
|
76 |
+
showProgress,
|
77 |
|
78 |
nextBtnText = getConfig("nextBtnText") || "Next →",
|
79 |
prevBtnText = getConfig("prevBtnText") || "← Previous",
|
80 |
+
progressText = getConfig("progressText") || "{current} of {total}",
|
81 |
} = step.popover || {};
|
82 |
|
83 |
popover.nextButton.innerHTML = nextBtnText;
|
84 |
popover.previousButton.innerHTML = prevBtnText;
|
85 |
+
popover.progress.innerHTML = progressText;
|
86 |
|
87 |
if (title) {
|
88 |
popover.title.innerText = title;
|
|
|
99 |
}
|
100 |
|
101 |
const showButtonsConfig: AllowedButtons[] = showButtons || getConfig("showButtons")!;
|
102 |
+
const showProgressConfig = showProgress || getConfig("showProgress") || false;
|
103 |
+
const showFooter =
|
104 |
+
showButtonsConfig?.includes("next") ||
|
105 |
+
showButtonsConfig?.includes("previous") ||
|
106 |
+
showButtonsConfig?.includes("close") ||
|
107 |
+
showProgressConfig;
|
108 |
|
109 |
+
popover.closeButton.style.display = showButtonsConfig.includes("close") ? "block" : "none";
|
110 |
+
|
111 |
+
if (showFooter) {
|
112 |
popover.footer.style.display = "flex";
|
113 |
+
|
114 |
+
popover.progress.style.display = showProgressConfig ? "block" : "none";
|
115 |
+
popover.nextButton.style.display = showButtonsConfig.includes("next") ? "block" : "none";
|
116 |
+
popover.previousButton.style.display = showButtonsConfig.includes("previous") ? "block" : "none";
|
117 |
} else {
|
118 |
popover.footer.style.display = "none";
|
119 |
}
|
120 |
|
121 |
+
const disabledButtonsConfig: AllowedButtons[] = disableButtons || getConfig("disableButtons")! || [];
|
122 |
+
if (disabledButtonsConfig?.includes("next")) {
|
123 |
+
popover.nextButton.classList.add("driver-popover-btn-disabled");
|
124 |
}
|
125 |
|
126 |
+
if (disabledButtonsConfig?.includes("previous")) {
|
127 |
+
popover.previousButton.classList.add("driver-popover-btn-disabled");
|
128 |
}
|
129 |
|
130 |
+
if (disabledButtonsConfig?.includes("close")) {
|
131 |
+
popover.closeButton.classList.add("driver-popover-btn-disabled");
|
132 |
}
|
133 |
|
134 |
// Reset the popover position
|
|
|
197 |
repositionPopover(element, step);
|
198 |
bringInView(popoverWrapper);
|
199 |
|
200 |
+
const onPopoverRendered = step.popover?.onPopoverRendered || getConfig("onPopoverRendered");
|
201 |
if (onPopoverRendered) {
|
202 |
onPopoverRendered(popover);
|
203 |
}
|
|
|
581 |
description.style.display = "none";
|
582 |
description.innerText = "Popover description is here";
|
583 |
|
|
|
|
|
|
|
584 |
const closeButton = document.createElement("button");
|
585 |
closeButton.classList.add("driver-popover-close-btn");
|
586 |
closeButton.innerHTML = "×";
|
587 |
|
588 |
+
const footer = document.createElement("div");
|
589 |
+
footer.classList.add("driver-popover-footer");
|
590 |
+
|
591 |
+
const progress = document.createElement("span");
|
592 |
+
progress.classList.add("driver-popover-progress-text");
|
593 |
+
progress.innerText = "";
|
594 |
+
|
595 |
const footerButtons = document.createElement("span");
|
596 |
footerButtons.classList.add("driver-popover-navigation-btns");
|
597 |
|
|
|
605 |
|
606 |
footerButtons.appendChild(previousButton);
|
607 |
footerButtons.appendChild(nextButton);
|
608 |
+
footer.appendChild(progress);
|
609 |
footer.appendChild(footerButtons);
|
610 |
|
611 |
wrapper.appendChild(closeButton);
|
|
|
624 |
nextButton,
|
625 |
closeButton,
|
626 |
footerButtons,
|
627 |
+
progress,
|
628 |
};
|
629 |
}
|
630 |
|
src/style.css
CHANGED
@@ -101,9 +101,17 @@
|
|
101 |
text-align: right;
|
102 |
zoom: 1;
|
103 |
display: flex;
|
|
|
104 |
justify-content: space-between;
|
105 |
}
|
106 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
107 |
.driver-popover-footer button {
|
108 |
all: unset;
|
109 |
display: inline-block;
|
|
|
101 |
text-align: right;
|
102 |
zoom: 1;
|
103 |
display: flex;
|
104 |
+
align-items: center;
|
105 |
justify-content: space-between;
|
106 |
}
|
107 |
|
108 |
+
.driver-popover-progress-text {
|
109 |
+
font-size: 13px;
|
110 |
+
font-weight: 400;
|
111 |
+
color: #a2a2a2;
|
112 |
+
zoom: 1;
|
113 |
+
}
|
114 |
+
|
115 |
.driver-popover-footer button {
|
116 |
all: unset;
|
117 |
display: inline-block;
|