Press n or j to go to the next uncovered block, b, p or k for the previous block.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 | 33x 33x 33x 33x 33x 16x 16x 4x 4x 10x 10x 3x 3x 33x 33x 33x | import { ReactNode } from "react"; import type { Step } from "../listing/types"; type Props = { steps: Step[]; currentStepIndex: number; mask: { top: number; bottom: number; left: number; right: number; }; onFinishClick: () => void; onSkipClick: () => void; onNextClick: () => void; onPrevClick: () => void; }; export default function TourStepCard({ steps, currentStepIndex, mask, onFinishClick, onSkipClick, onNextClick, onPrevClick, }: Props): ReactNode { const step = steps[currentStepIndex]; let tooltipStyle = {}; // for positioning relative to right/bottom of the screen const overlayHeight = document.body.clientHeight; const overlayWidth = document.body.clientWidth; switch (step.position) { // TODO: support for all available tooltip positions case "bottom-left": tooltipStyle = { top: mask.bottom, left: mask.left, }; break; case "bottom-right": tooltipStyle = { top: mask.bottom, right: overlayWidth - mask.right, }; break; case "top-left": tooltipStyle = { bottom: overlayHeight - mask.top, left: mask.left, }; break; case "top-right": tooltipStyle = { bottom: overlayHeight - mask.top, right: overlayWidth - mask.right, }; break; } // step content is controlled by us and passed as data to component directly // so it should be safe to set it via dangerouslySetInnerHTML const content = { __html: step.content }; const isLastStep = currentStepIndex === steps.length - 1; return ( <div className={`p-card--tour is-tooltip--${step.position}`} style={tooltipStyle} > <h4>{step.title}</h4> <div className="p-card--tour__content" dangerouslySetInnerHTML={content} /> <p className="p-tour-controls"> {!isLastStep && ( <span> Done? <a onClick={onSkipClick}>Skip tour</a>. </span> )} <small className="p-tour-controls__step"> {currentStepIndex + 1}/{steps.length} </small> <span className="p-tour-controls__buttons"> <button disabled={currentStepIndex === 0} onClick={onPrevClick} className="p-button has-icon u-no-margin--bottom" > <i className="p-icon--chevron-up is-prev">Previous step</i> </button> <button onClick={isLastStep ? onFinishClick : onNextClick} className="p-button--positive has-icon u-no-margin--bottom u-no-margin--right" > {isLastStep ? ( "Finish tour" ) : ( <i className="p-icon--chevron-up is-light is-next">Next step</i> )} </button> </span> </p> </div> ); } |