@elogroup-sereduc/portal-aluno-tour 1.0.1 → 1.0.3
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/Tour.d.ts.map +1 -1
- package/dist/components/Tour.js +70 -11
- package/package.json +1 -1
- package/src/components/Tour.tsx +80 -19
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Tour.d.ts","sourceRoot":"","sources":["../../src/components/Tour.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAY,MAAM,UAAU,CAAC;AAG/C;;GAEG;AACH,wBAAgB,IAAI,CAAC,EACnB,OAAO,EACP,KAAK,EACL,WAAe,EACf,OAAY,EACZ,MAAM,EACN,UAAU,GACX,EAAE,SAAS,
|
|
1
|
+
{"version":3,"file":"Tour.d.ts","sourceRoot":"","sources":["../../src/components/Tour.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAY,MAAM,UAAU,CAAC;AAG/C;;GAEG;AACH,wBAAgB,IAAI,CAAC,EACnB,OAAO,EACP,KAAK,EACL,WAAe,EACf,OAAY,EACZ,MAAM,EACN,UAAU,GACX,EAAE,SAAS,kDA0YX"}
|
package/dist/components/Tour.js
CHANGED
|
@@ -7,10 +7,12 @@ import { HiXMark, HiChevronLeft, HiChevronRight } from "react-icons/hi2";
|
|
|
7
7
|
*/
|
|
8
8
|
export function Tour({ enabled, steps, initialStep = 0, options = {}, onExit, onComplete, }) {
|
|
9
9
|
const [currentStep, setCurrentStep] = useState(initialStep);
|
|
10
|
+
const [isVisible, setIsVisible] = useState(false);
|
|
10
11
|
const [highlightedElement, setHighlightedElement] = useState(null);
|
|
11
12
|
const [tooltipPosition, setTooltipPosition] = useState(null);
|
|
12
13
|
const overlayRef = useRef(null);
|
|
13
14
|
const tooltipRef = useRef(null);
|
|
15
|
+
const isConfiguredRef = useRef(false);
|
|
14
16
|
const { nextLabel = "Próximo", prevLabel = "Anterior", skipLabel = "Pular", doneLabel = "Concluir", showProgress = true, showBullets = true, exitOnOverlayClick = false, exitOnEsc = true, } = options;
|
|
15
17
|
// Calcula a posição da tooltip baseado no elemento destacado
|
|
16
18
|
const calculateTooltipPosition = useCallback((element, position = "bottom") => {
|
|
@@ -42,9 +44,26 @@ export function Tour({ enabled, steps, initialStep = 0, options = {}, onExit, on
|
|
|
42
44
|
}
|
|
43
45
|
return { top, left };
|
|
44
46
|
}, []);
|
|
47
|
+
// Configura o tour quando steps ou options mudam
|
|
48
|
+
const configureTour = useCallback(() => {
|
|
49
|
+
isConfiguredRef.current = true;
|
|
50
|
+
}, []);
|
|
51
|
+
// Renderiza os steps (mostra/esconde o tour)
|
|
52
|
+
const renderSteps = useCallback(() => {
|
|
53
|
+
if (enabled && steps.length > 0 && !isVisible) {
|
|
54
|
+
setIsVisible(true);
|
|
55
|
+
setCurrentStep(initialStep);
|
|
56
|
+
}
|
|
57
|
+
else if (!enabled && isVisible) {
|
|
58
|
+
setIsVisible(false);
|
|
59
|
+
setCurrentStep(initialStep);
|
|
60
|
+
setHighlightedElement(null);
|
|
61
|
+
setTooltipPosition(null);
|
|
62
|
+
}
|
|
63
|
+
}, [enabled, steps.length, isVisible, initialStep]);
|
|
45
64
|
// Destaca o elemento atual
|
|
46
65
|
useEffect(() => {
|
|
47
|
-
if (!
|
|
66
|
+
if (!isVisible || currentStep < 0 || currentStep >= steps.length) {
|
|
48
67
|
setHighlightedElement(null);
|
|
49
68
|
setTooltipPosition(null);
|
|
50
69
|
return;
|
|
@@ -63,25 +82,40 @@ export function Tour({ enabled, steps, initialStep = 0, options = {}, onExit, on
|
|
|
63
82
|
const position = calculateTooltipPosition(element, step.position);
|
|
64
83
|
setTooltipPosition(position);
|
|
65
84
|
}, 300);
|
|
66
|
-
}, [
|
|
85
|
+
}, [isVisible, currentStep, steps, calculateTooltipPosition]);
|
|
67
86
|
// Adiciona overlay e highlight ao elemento
|
|
68
87
|
useEffect(() => {
|
|
69
88
|
if (!highlightedElement) {
|
|
70
89
|
// Remove highlights anteriores
|
|
71
90
|
document.querySelectorAll(".tour-highlight").forEach((el) => {
|
|
72
91
|
el.classList.remove("tour-highlight");
|
|
92
|
+
el.style.zIndex = "";
|
|
73
93
|
});
|
|
74
94
|
return;
|
|
75
95
|
}
|
|
76
|
-
// Adiciona classe de highlight
|
|
96
|
+
// Adiciona classe de highlight e z-index alto
|
|
77
97
|
highlightedElement.classList.add("tour-highlight");
|
|
98
|
+
const originalZIndex = highlightedElement.style.zIndex;
|
|
99
|
+
highlightedElement.style.zIndex = "10000";
|
|
78
100
|
return () => {
|
|
79
101
|
highlightedElement.classList.remove("tour-highlight");
|
|
102
|
+
highlightedElement.style.zIndex = originalZIndex;
|
|
80
103
|
};
|
|
81
104
|
}, [highlightedElement]);
|
|
82
|
-
//
|
|
105
|
+
// Configura o tour quando necessário
|
|
106
|
+
useEffect(() => {
|
|
107
|
+
if (!isConfiguredRef.current || steps.length > 0) {
|
|
108
|
+
configureTour();
|
|
109
|
+
renderSteps();
|
|
110
|
+
}
|
|
111
|
+
}, [steps, configureTour, renderSteps]);
|
|
112
|
+
// Atualiza quando enabled muda
|
|
83
113
|
useEffect(() => {
|
|
84
|
-
|
|
114
|
+
renderSteps();
|
|
115
|
+
}, [enabled, renderSteps]);
|
|
116
|
+
// Handler de teclado (ESC e setas)
|
|
117
|
+
useEffect(() => {
|
|
118
|
+
if (!isVisible || !exitOnEsc)
|
|
85
119
|
return;
|
|
86
120
|
const handleKeyDown = (e) => {
|
|
87
121
|
if (e.key === "Escape") {
|
|
@@ -96,7 +130,19 @@ export function Tour({ enabled, steps, initialStep = 0, options = {}, onExit, on
|
|
|
96
130
|
};
|
|
97
131
|
window.addEventListener("keydown", handleKeyDown);
|
|
98
132
|
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
99
|
-
}, [
|
|
133
|
+
}, [isVisible, exitOnEsc, currentStep, steps.length]);
|
|
134
|
+
// Controla overflow do body
|
|
135
|
+
useEffect(() => {
|
|
136
|
+
if (isVisible) {
|
|
137
|
+
document.body.style.overflow = "hidden";
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
document.body.style.overflow = "";
|
|
141
|
+
}
|
|
142
|
+
return () => {
|
|
143
|
+
document.body.style.overflow = "";
|
|
144
|
+
};
|
|
145
|
+
}, [isVisible]);
|
|
100
146
|
const handleNext = useCallback(() => {
|
|
101
147
|
if (currentStep < steps.length - 1) {
|
|
102
148
|
setCurrentStep(currentStep + 1);
|
|
@@ -118,6 +164,7 @@ export function Tour({ enabled, steps, initialStep = 0, options = {}, onExit, on
|
|
|
118
164
|
handleExit();
|
|
119
165
|
}, [onComplete]);
|
|
120
166
|
const handleExit = useCallback(() => {
|
|
167
|
+
setIsVisible(false);
|
|
121
168
|
setCurrentStep(initialStep);
|
|
122
169
|
setHighlightedElement(null);
|
|
123
170
|
setTooltipPosition(null);
|
|
@@ -128,14 +175,24 @@ export function Tour({ enabled, steps, initialStep = 0, options = {}, onExit, on
|
|
|
128
175
|
handleExit();
|
|
129
176
|
}
|
|
130
177
|
}, [exitOnOverlayClick, handleExit]);
|
|
131
|
-
if (!
|
|
178
|
+
if (!isVisible) {
|
|
132
179
|
return null;
|
|
133
180
|
}
|
|
134
181
|
const currentStepData = steps[currentStep];
|
|
135
182
|
const isFirstStep = currentStep === 0;
|
|
136
183
|
const isLastStep = currentStep === steps.length - 1;
|
|
137
184
|
const progress = ((currentStep + 1) / steps.length) * 100;
|
|
138
|
-
return (_jsxs(_Fragment, { children: [_jsx("div", { ref: overlayRef,
|
|
185
|
+
return (_jsxs(_Fragment, { children: [_jsx("div", { ref: overlayRef, onClick: handleOverlayClick, style: {
|
|
186
|
+
position: "fixed",
|
|
187
|
+
top: 0,
|
|
188
|
+
left: 0,
|
|
189
|
+
right: 0,
|
|
190
|
+
bottom: 0,
|
|
191
|
+
backgroundColor: "rgba(0, 0, 0, 0.6)",
|
|
192
|
+
zIndex: 9998,
|
|
193
|
+
pointerEvents: exitOnOverlayClick ? "auto" : "none",
|
|
194
|
+
} }), tooltipPosition && currentStepData && highlightedElement && (_jsxs("div", { ref: tooltipRef, className: "max-w-sm", style: {
|
|
195
|
+
position: "fixed",
|
|
139
196
|
top: currentStepData.position === "bottom" ? `${tooltipPosition.top}px` : undefined,
|
|
140
197
|
bottom: currentStepData.position === "top" ? `${window.innerHeight - tooltipPosition.top}px` : undefined,
|
|
141
198
|
left: currentStepData.position === "left" || currentStepData.position === "right"
|
|
@@ -144,7 +201,8 @@ export function Tour({ enabled, steps, initialStep = 0, options = {}, onExit, on
|
|
|
144
201
|
transform: currentStepData.position === "left" || currentStepData.position === "right"
|
|
145
202
|
? "translate(0, -50%)"
|
|
146
203
|
: "translate(-50%, 0)",
|
|
147
|
-
|
|
204
|
+
zIndex: 10001,
|
|
205
|
+
}, children: [_jsxs("div", { className: "bg-white rounded-lg shadow-xl p-6 relative", children: [_jsx("button", { onClick: handleExit, className: "absolute top-2 right-2 p-1 rounded-full hover:bg-gray-100 transition-colors z-10", "aria-label": "Fechar tour", children: _jsx(HiXMark, { className: "w-5 h-5 text-gray-500" }) }), currentStepData.title && (_jsx("h3", { className: "text-lg font-semibold text-gray-900 mb-2 pr-6", children: currentStepData.title })), _jsx("p", { className: "text-gray-700 mb-4", children: currentStepData.intro }), showProgress && (_jsxs("div", { className: "mb-4", children: [_jsx("div", { className: "w-full bg-gray-200 rounded-full h-2", children: _jsx("div", { className: "bg-brand-primary h-2 rounded-full transition-all duration-300", style: { width: `${progress}%` } }) }), _jsxs("p", { className: "text-xs text-gray-500 mt-1 text-center", children: [currentStep + 1, " de ", steps.length] })] })), showBullets && (_jsx("div", { className: "flex justify-center gap-1 mb-4", children: steps.map((_, index) => (_jsx("button", { onClick: () => setCurrentStep(index), className: `w-2 h-2 rounded-full transition-all ${index === currentStep
|
|
148
206
|
? "bg-brand-primary w-6"
|
|
149
207
|
: "bg-gray-300 hover:bg-gray-400"}`, "aria-label": `Ir para passo ${index + 1}` }, index))) })), _jsxs("div", { className: "flex justify-between items-center gap-2", children: [_jsx("div", { className: "flex gap-2", children: !isFirstStep && (_jsx(Button, { variant: "bordered", onPress: handlePrev, startContent: _jsx(HiChevronLeft, { className: "w-4 h-4" }), children: prevLabel })) }), _jsxs("div", { className: "flex gap-2", children: [_jsx(Button, { variant: "light", onPress: handleSkip, children: skipLabel }), _jsx(Button, { color: "primary", onPress: isLastStep ? handleComplete : handleNext, endContent: !isLastStep ? _jsx(HiChevronRight, { className: "w-4 h-4" }) : undefined, children: isLastStep ? doneLabel : nextLabel })] })] })] }), currentStepData.position === "bottom" && (_jsx("div", { className: "absolute w-0 h-0 border-8 border-transparent", style: {
|
|
150
208
|
top: "-16px",
|
|
@@ -168,11 +226,12 @@ export function Tour({ enabled, steps, initialStep = 0, options = {}, onExit, on
|
|
|
168
226
|
borderColor: "transparent transparent transparent white",
|
|
169
227
|
} }))] })), _jsx("style", { children: `
|
|
170
228
|
.tour-highlight {
|
|
171
|
-
position: relative;
|
|
172
|
-
z-index:
|
|
229
|
+
position: relative !important;
|
|
230
|
+
z-index: 10000 !important;
|
|
173
231
|
outline: 3px solid var(--brand-primary, #0056b0) !important;
|
|
174
232
|
outline-offset: 2px;
|
|
175
233
|
border-radius: 4px;
|
|
234
|
+
box-shadow: 0 0 0 9999px rgba(0, 0, 0, 0.6) !important;
|
|
176
235
|
}
|
|
177
236
|
` })] }));
|
|
178
237
|
}
|
package/package.json
CHANGED
package/src/components/Tour.tsx
CHANGED
|
@@ -15,10 +15,12 @@ export function Tour({
|
|
|
15
15
|
onComplete,
|
|
16
16
|
}: TourProps) {
|
|
17
17
|
const [currentStep, setCurrentStep] = useState(initialStep);
|
|
18
|
+
const [isVisible, setIsVisible] = useState(false);
|
|
18
19
|
const [highlightedElement, setHighlightedElement] = useState<HTMLElement | null>(null);
|
|
19
20
|
const [tooltipPosition, setTooltipPosition] = useState<{ top: number; left: number } | null>(null);
|
|
20
21
|
const overlayRef = useRef<HTMLDivElement>(null);
|
|
21
22
|
const tooltipRef = useRef<HTMLDivElement>(null);
|
|
23
|
+
const isConfiguredRef = useRef(false);
|
|
22
24
|
|
|
23
25
|
const {
|
|
24
26
|
nextLabel = "Próximo",
|
|
@@ -65,9 +67,27 @@ export function Tour({
|
|
|
65
67
|
return { top, left };
|
|
66
68
|
}, []);
|
|
67
69
|
|
|
70
|
+
// Configura o tour quando steps ou options mudam
|
|
71
|
+
const configureTour = useCallback(() => {
|
|
72
|
+
isConfiguredRef.current = true;
|
|
73
|
+
}, []);
|
|
74
|
+
|
|
75
|
+
// Renderiza os steps (mostra/esconde o tour)
|
|
76
|
+
const renderSteps = useCallback(() => {
|
|
77
|
+
if (enabled && steps.length > 0 && !isVisible) {
|
|
78
|
+
setIsVisible(true);
|
|
79
|
+
setCurrentStep(initialStep);
|
|
80
|
+
} else if (!enabled && isVisible) {
|
|
81
|
+
setIsVisible(false);
|
|
82
|
+
setCurrentStep(initialStep);
|
|
83
|
+
setHighlightedElement(null);
|
|
84
|
+
setTooltipPosition(null);
|
|
85
|
+
}
|
|
86
|
+
}, [enabled, steps.length, isVisible, initialStep]);
|
|
87
|
+
|
|
68
88
|
// Destaca o elemento atual
|
|
69
89
|
useEffect(() => {
|
|
70
|
-
if (!
|
|
90
|
+
if (!isVisible || currentStep < 0 || currentStep >= steps.length) {
|
|
71
91
|
setHighlightedElement(null);
|
|
72
92
|
setTooltipPosition(null);
|
|
73
93
|
return;
|
|
@@ -91,7 +111,7 @@ export function Tour({
|
|
|
91
111
|
const position = calculateTooltipPosition(element, step.position);
|
|
92
112
|
setTooltipPosition(position);
|
|
93
113
|
}, 300);
|
|
94
|
-
}, [
|
|
114
|
+
}, [isVisible, currentStep, steps, calculateTooltipPosition]);
|
|
95
115
|
|
|
96
116
|
// Adiciona overlay e highlight ao elemento
|
|
97
117
|
useEffect(() => {
|
|
@@ -99,21 +119,38 @@ export function Tour({
|
|
|
99
119
|
// Remove highlights anteriores
|
|
100
120
|
document.querySelectorAll(".tour-highlight").forEach((el) => {
|
|
101
121
|
el.classList.remove("tour-highlight");
|
|
122
|
+
(el as HTMLElement).style.zIndex = "";
|
|
102
123
|
});
|
|
103
124
|
return;
|
|
104
125
|
}
|
|
105
126
|
|
|
106
|
-
// Adiciona classe de highlight
|
|
127
|
+
// Adiciona classe de highlight e z-index alto
|
|
107
128
|
highlightedElement.classList.add("tour-highlight");
|
|
129
|
+
const originalZIndex = highlightedElement.style.zIndex;
|
|
130
|
+
highlightedElement.style.zIndex = "10000";
|
|
108
131
|
|
|
109
132
|
return () => {
|
|
110
133
|
highlightedElement.classList.remove("tour-highlight");
|
|
134
|
+
highlightedElement.style.zIndex = originalZIndex;
|
|
111
135
|
};
|
|
112
136
|
}, [highlightedElement]);
|
|
113
137
|
|
|
114
|
-
//
|
|
138
|
+
// Configura o tour quando necessário
|
|
139
|
+
useEffect(() => {
|
|
140
|
+
if (!isConfiguredRef.current || steps.length > 0) {
|
|
141
|
+
configureTour();
|
|
142
|
+
renderSteps();
|
|
143
|
+
}
|
|
144
|
+
}, [steps, configureTour, renderSteps]);
|
|
145
|
+
|
|
146
|
+
// Atualiza quando enabled muda
|
|
115
147
|
useEffect(() => {
|
|
116
|
-
|
|
148
|
+
renderSteps();
|
|
149
|
+
}, [enabled, renderSteps]);
|
|
150
|
+
|
|
151
|
+
// Handler de teclado (ESC e setas)
|
|
152
|
+
useEffect(() => {
|
|
153
|
+
if (!isVisible || !exitOnEsc) return;
|
|
117
154
|
|
|
118
155
|
const handleKeyDown = (e: KeyboardEvent) => {
|
|
119
156
|
if (e.key === "Escape") {
|
|
@@ -127,7 +164,19 @@ export function Tour({
|
|
|
127
164
|
|
|
128
165
|
window.addEventListener("keydown", handleKeyDown);
|
|
129
166
|
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
130
|
-
}, [
|
|
167
|
+
}, [isVisible, exitOnEsc, currentStep, steps.length]);
|
|
168
|
+
|
|
169
|
+
// Controla overflow do body
|
|
170
|
+
useEffect(() => {
|
|
171
|
+
if (isVisible) {
|
|
172
|
+
document.body.style.overflow = "hidden";
|
|
173
|
+
} else {
|
|
174
|
+
document.body.style.overflow = "";
|
|
175
|
+
}
|
|
176
|
+
return () => {
|
|
177
|
+
document.body.style.overflow = "";
|
|
178
|
+
};
|
|
179
|
+
}, [isVisible]);
|
|
131
180
|
|
|
132
181
|
const handleNext = useCallback(() => {
|
|
133
182
|
if (currentStep < steps.length - 1) {
|
|
@@ -153,6 +202,7 @@ export function Tour({
|
|
|
153
202
|
}, [onComplete]);
|
|
154
203
|
|
|
155
204
|
const handleExit = useCallback(() => {
|
|
205
|
+
setIsVisible(false);
|
|
156
206
|
setCurrentStep(initialStep);
|
|
157
207
|
setHighlightedElement(null);
|
|
158
208
|
setTooltipPosition(null);
|
|
@@ -168,7 +218,7 @@ export function Tour({
|
|
|
168
218
|
[exitOnOverlayClick, handleExit]
|
|
169
219
|
);
|
|
170
220
|
|
|
171
|
-
if (!
|
|
221
|
+
if (!isVisible) {
|
|
172
222
|
return null;
|
|
173
223
|
}
|
|
174
224
|
|
|
@@ -182,32 +232,43 @@ export function Tour({
|
|
|
182
232
|
{/* Overlay escuro */}
|
|
183
233
|
<div
|
|
184
234
|
ref={overlayRef}
|
|
185
|
-
className="fixed inset-0 bg-black/60 z-[9998]"
|
|
186
235
|
onClick={handleOverlayClick}
|
|
187
|
-
style={{
|
|
236
|
+
style={{
|
|
237
|
+
position: "fixed",
|
|
238
|
+
top: 0,
|
|
239
|
+
left: 0,
|
|
240
|
+
right: 0,
|
|
241
|
+
bottom: 0,
|
|
242
|
+
backgroundColor: "rgba(0, 0, 0, 0.6)",
|
|
243
|
+
zIndex: 9998,
|
|
244
|
+
pointerEvents: exitOnOverlayClick ? "auto" : "none",
|
|
245
|
+
}}
|
|
188
246
|
/>
|
|
189
247
|
|
|
190
248
|
{/* Tooltip */}
|
|
191
249
|
{tooltipPosition && currentStepData && highlightedElement && (
|
|
192
250
|
<div
|
|
193
251
|
ref={tooltipRef}
|
|
194
|
-
className="
|
|
252
|
+
className="max-w-sm"
|
|
195
253
|
style={{
|
|
254
|
+
position: "fixed",
|
|
196
255
|
top: currentStepData.position === "bottom" ? `${tooltipPosition.top}px` : undefined,
|
|
197
256
|
bottom: currentStepData.position === "top" ? `${window.innerHeight - tooltipPosition.top}px` : undefined,
|
|
198
|
-
left: currentStepData.position === "left" || currentStepData.position === "right"
|
|
199
|
-
? `${tooltipPosition.left}px`
|
|
257
|
+
left: currentStepData.position === "left" || currentStepData.position === "right"
|
|
258
|
+
? `${tooltipPosition.left}px`
|
|
200
259
|
: `${tooltipPosition.left}px`,
|
|
201
|
-
transform:
|
|
202
|
-
|
|
203
|
-
|
|
260
|
+
transform:
|
|
261
|
+
currentStepData.position === "left" || currentStepData.position === "right"
|
|
262
|
+
? "translate(0, -50%)"
|
|
263
|
+
: "translate(-50%, 0)",
|
|
264
|
+
zIndex: 10001,
|
|
204
265
|
}}
|
|
205
266
|
>
|
|
206
267
|
<div className="bg-white rounded-lg shadow-xl p-6 relative">
|
|
207
268
|
{/* Botão fechar */}
|
|
208
269
|
<button
|
|
209
270
|
onClick={handleExit}
|
|
210
|
-
className="absolute top-2 right-2 p-1 rounded-full hover:bg-gray-100 transition-colors"
|
|
271
|
+
className="absolute top-2 right-2 p-1 rounded-full hover:bg-gray-100 transition-colors z-10"
|
|
211
272
|
aria-label="Fechar tour"
|
|
212
273
|
>
|
|
213
274
|
<HiXMark className="w-5 h-5 text-gray-500" />
|
|
@@ -336,14 +397,14 @@ export function Tour({
|
|
|
336
397
|
{/* Estilos inline para highlight */}
|
|
337
398
|
<style>{`
|
|
338
399
|
.tour-highlight {
|
|
339
|
-
position: relative;
|
|
340
|
-
z-index:
|
|
400
|
+
position: relative !important;
|
|
401
|
+
z-index: 10000 !important;
|
|
341
402
|
outline: 3px solid var(--brand-primary, #0056b0) !important;
|
|
342
403
|
outline-offset: 2px;
|
|
343
404
|
border-radius: 4px;
|
|
405
|
+
box-shadow: 0 0 0 9999px rgba(0, 0, 0, 0.6) !important;
|
|
344
406
|
}
|
|
345
407
|
`}</style>
|
|
346
408
|
</>
|
|
347
409
|
);
|
|
348
410
|
}
|
|
349
|
-
|