@rpg-engine/long-bow 0.6.37 → 0.6.39
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/Image/ZoomableImage.d.ts +5 -0
- package/dist/components/Stepper.d.ts +3 -0
- package/dist/long-bow.cjs.development.js +76 -23
- package/dist/long-bow.cjs.development.js.map +1 -1
- package/dist/long-bow.cjs.production.min.js +1 -1
- package/dist/long-bow.cjs.production.min.js.map +1 -1
- package/dist/long-bow.esm.js +76 -23
- package/dist/long-bow.esm.js.map +1 -1
- package/package.json +1 -1
- package/src/components/Image/ZoomableImage.tsx +41 -0
- package/src/components/Stepper.tsx +11 -3
- package/src/components/Tutorial/TutorialStepper.tsx +48 -42
package/package.json
CHANGED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
|
|
3
|
+
export const ZoomableImage: React.FC<{ src: string; alt: string }> = ({
|
|
4
|
+
src,
|
|
5
|
+
alt,
|
|
6
|
+
}) => {
|
|
7
|
+
const [isHovered, setIsHovered] = useState(false);
|
|
8
|
+
const [zoomPosition, setZoomPosition] = useState({ x: 50, y: 50 });
|
|
9
|
+
|
|
10
|
+
const handleMouseMove = (
|
|
11
|
+
e: React.MouseEvent<HTMLImageElement, MouseEvent>
|
|
12
|
+
) => {
|
|
13
|
+
const {
|
|
14
|
+
left,
|
|
15
|
+
top,
|
|
16
|
+
width,
|
|
17
|
+
height,
|
|
18
|
+
} = e.currentTarget.getBoundingClientRect();
|
|
19
|
+
const x = ((e.clientX - left) / width) * 100;
|
|
20
|
+
const y = ((e.clientY - top) / height) * 100;
|
|
21
|
+
setZoomPosition({ x, y });
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
return (
|
|
25
|
+
<img
|
|
26
|
+
src={src}
|
|
27
|
+
alt={alt}
|
|
28
|
+
onMouseMove={handleMouseMove}
|
|
29
|
+
onMouseEnter={() => setIsHovered(true)}
|
|
30
|
+
onMouseLeave={() => setIsHovered(false)}
|
|
31
|
+
style={{
|
|
32
|
+
width: '100%',
|
|
33
|
+
height: '100%',
|
|
34
|
+
objectFit: 'cover',
|
|
35
|
+
transform: isHovered ? 'scale(1.5)' : 'scale(1)',
|
|
36
|
+
transformOrigin: `${zoomPosition.x}% ${zoomPosition.y}%`,
|
|
37
|
+
transition: 'transform 0.3s ease',
|
|
38
|
+
}}
|
|
39
|
+
/>
|
|
40
|
+
);
|
|
41
|
+
};
|
|
@@ -19,6 +19,9 @@ interface IStepperProps {
|
|
|
19
19
|
};
|
|
20
20
|
onError?: (message: string) => void;
|
|
21
21
|
useSideArrows?: boolean; // New prop to control arrow position
|
|
22
|
+
styles?: {
|
|
23
|
+
stepperProgressColor?: string;
|
|
24
|
+
};
|
|
22
25
|
}
|
|
23
26
|
|
|
24
27
|
export const Stepper: React.FC<IStepperProps> = ({
|
|
@@ -26,6 +29,7 @@ export const Stepper: React.FC<IStepperProps> = ({
|
|
|
26
29
|
finalCTAButton,
|
|
27
30
|
onError,
|
|
28
31
|
useSideArrows = false, // Default to false for backwards compatibility
|
|
32
|
+
styles,
|
|
29
33
|
}) => {
|
|
30
34
|
const [currentStep, setCurrentStep] = useState(0);
|
|
31
35
|
|
|
@@ -101,6 +105,7 @@ export const Stepper: React.FC<IStepperProps> = ({
|
|
|
101
105
|
<ProgressIndicator
|
|
102
106
|
key={i}
|
|
103
107
|
isActive={i <= currentStep}
|
|
108
|
+
stepperProgressColor={styles?.stepperProgressColor}
|
|
104
109
|
onClick={() => onStepChange(i)}
|
|
105
110
|
/>
|
|
106
111
|
))}
|
|
@@ -174,11 +179,14 @@ const StepperFooter = styled.div`
|
|
|
174
179
|
align-items: center;
|
|
175
180
|
`;
|
|
176
181
|
|
|
177
|
-
const ProgressIndicator = styled.div<{
|
|
182
|
+
const ProgressIndicator = styled.div<{
|
|
183
|
+
isActive: boolean;
|
|
184
|
+
stepperProgressColor?: string;
|
|
185
|
+
}>`
|
|
178
186
|
width: 20px;
|
|
179
187
|
height: 20px;
|
|
180
|
-
background-color: ${({ isActive }) =>
|
|
181
|
-
isActive ? uiColors.orange : uiColors.lightGray};
|
|
188
|
+
background-color: ${({ isActive, stepperProgressColor }) =>
|
|
189
|
+
isActive ? stepperProgressColor || uiColors.orange : uiColors.lightGray};
|
|
182
190
|
margin: 0 5px;
|
|
183
191
|
transition: background-color 0.3s;
|
|
184
192
|
opacity: ${({ isActive }) => (isActive ? 1 : 0.25)};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React, { useMemo } from 'react';
|
|
2
2
|
import styled, { CSSProperties } from 'styled-components';
|
|
3
3
|
import { uiColors } from '../../constants/uiColors';
|
|
4
|
+
import { ZoomableImage } from '../Image/ZoomableImage';
|
|
4
5
|
import { Stepper } from '../Stepper';
|
|
5
6
|
import { DynamicText } from '../typography/DynamicText';
|
|
6
7
|
|
|
@@ -27,27 +28,27 @@ export const TutorialStepper = React.memo(
|
|
|
27
28
|
<LessonContainer key={index} className="lesson-container">
|
|
28
29
|
<LessonTitle className="lesson-title">{lesson.title}</LessonTitle>
|
|
29
30
|
{lesson.image && (
|
|
30
|
-
<
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
31
|
+
<LessonImageWrapper className="lesson-image-wrapper">
|
|
32
|
+
<LessonImage className="lesson-image" style={imageStyle}>
|
|
33
|
+
{lesson.imageUrl ? (
|
|
34
|
+
<a
|
|
35
|
+
href={lesson.imageUrl}
|
|
36
|
+
target="_blank"
|
|
37
|
+
rel="noopener noreferrer"
|
|
38
|
+
>
|
|
39
|
+
<ZoomableImage
|
|
40
|
+
src={lesson.image}
|
|
41
|
+
alt={lesson.title || 'Tutorial image'}
|
|
42
|
+
/>
|
|
43
|
+
</a>
|
|
44
|
+
) : (
|
|
45
|
+
<ZoomableImage
|
|
38
46
|
src={lesson.image}
|
|
39
47
|
alt={lesson.title || 'Tutorial image'}
|
|
40
|
-
loading="lazy"
|
|
41
48
|
/>
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
src={lesson.image}
|
|
46
|
-
alt={lesson.title || 'Tutorial image'}
|
|
47
|
-
loading="lazy"
|
|
48
|
-
/>
|
|
49
|
-
)}
|
|
50
|
-
</LessonImage>
|
|
49
|
+
)}
|
|
50
|
+
</LessonImage>
|
|
51
|
+
</LessonImageWrapper>
|
|
51
52
|
)}
|
|
52
53
|
<LessonFooter className="lesson-footer">
|
|
53
54
|
{lesson.body && (
|
|
@@ -80,6 +81,35 @@ export const TutorialStepper = React.memo(
|
|
|
80
81
|
}
|
|
81
82
|
);
|
|
82
83
|
|
|
84
|
+
const LessonImageWrapper = styled.div`
|
|
85
|
+
width: 100%;
|
|
86
|
+
max-width: 500px;
|
|
87
|
+
margin: 1rem auto;
|
|
88
|
+
aspect-ratio: 16 / 9;
|
|
89
|
+
overflow: hidden;
|
|
90
|
+
border-radius: 10px;
|
|
91
|
+
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
|
92
|
+
`;
|
|
93
|
+
|
|
94
|
+
const LessonImage = styled.div`
|
|
95
|
+
width: 100%;
|
|
96
|
+
height: 100%;
|
|
97
|
+
position: relative;
|
|
98
|
+
`;
|
|
99
|
+
|
|
100
|
+
const LessonContainer = styled.div`
|
|
101
|
+
display: flex;
|
|
102
|
+
flex-direction: column;
|
|
103
|
+
justify-content: flex-start;
|
|
104
|
+
min-height: 200px;
|
|
105
|
+
padding: 1rem;
|
|
106
|
+
padding-top: 0;
|
|
107
|
+
|
|
108
|
+
p {
|
|
109
|
+
font-size: 0.7rem !important;
|
|
110
|
+
}
|
|
111
|
+
`;
|
|
112
|
+
|
|
83
113
|
const LessonBody = styled.div``;
|
|
84
114
|
|
|
85
115
|
const Container = styled.div`
|
|
@@ -95,31 +125,7 @@ const LessonFooter = styled.div`
|
|
|
95
125
|
margin-top: 1rem;
|
|
96
126
|
`;
|
|
97
127
|
|
|
98
|
-
const LessonImage = styled.div`
|
|
99
|
-
display: flex;
|
|
100
|
-
justify-content: center;
|
|
101
|
-
align-items: center;
|
|
102
|
-
width: 100%;
|
|
103
|
-
height: auto;
|
|
104
|
-
max-width: 500px;
|
|
105
|
-
margin: auto;
|
|
106
|
-
|
|
107
|
-
img {
|
|
108
|
-
max-width: 100%;
|
|
109
|
-
max-height: 100%;
|
|
110
|
-
object-fit: contain;
|
|
111
|
-
border-radius: 10px;
|
|
112
|
-
}
|
|
113
|
-
`;
|
|
114
|
-
|
|
115
128
|
const LessonTitle = styled.h1`
|
|
116
129
|
color: ${uiColors.yellow} !important;
|
|
117
130
|
font-size: 0.8rem !important;
|
|
118
131
|
`;
|
|
119
|
-
|
|
120
|
-
const LessonContainer = styled.div`
|
|
121
|
-
display: flex;
|
|
122
|
-
flex-direction: column;
|
|
123
|
-
justify-content: space-between;
|
|
124
|
-
min-height: 200px; /* Match with StepperBody for consistent height */
|
|
125
|
-
`;
|