datastake-daf 0.6.168 → 0.6.170
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/index.js +256 -130
- package/package.json +1 -1
- package/src/@daf/core/components/AvatarGroup/AvatarGroup.stories.jsx +1 -1
- package/src/@daf/core/components/Badge/Badge.stories.js +98 -94
- package/src/@daf/core/components/Dashboard/Widget/CarouselWidget/CarouselWidget.stories.js +42 -0
- package/src/@daf/core/components/Dashboard/Widget/CarouselWidget/index.jsx +72 -0
- package/src/@daf/core/components/Dashboard/Widget/ImageCarousel/ImageCarousel.stories.js +93 -0
- package/src/@daf/core/components/Dashboard/Widget/ImageCarousel/index.jsx +132 -0
- package/src/@daf/core/components/Dashboard/Widget/ProjectWidget/ProjectWidget.stories.jsx +0 -3
- package/src/@daf/core/components/Dashboard/Widget/ProjectWidget/components/SdgList.jsx +9 -77
- package/src/@daf/core/components/Dashboard/Widget/ProjectWidget/index.jsx +78 -80
- package/src/@daf/core/components/Dashboard/Widget/ProjectWidget/style.js +47 -74
- package/src/@daf/core/components/EditForm/_index.scss +3 -3
- package/src/@daf/core/components/Icon/CustomIcon.stories.js +177 -179
- package/src/@daf/core/components/ProgressBar/MultiBarProgress/MultibarProgress.stories.jsx +48 -41
- package/src/@daf/core/components/ProgressBar/Progress.stories.jsx +31 -31
- package/src/@daf/core/components/Segment/Segment.stories.js +70 -64
- package/src/@daf/core/components/UI/SDGIcon/SGDIcon.stories.jsx +55 -0
- package/src/@daf/core/components/UI/SDGIcon/index.jsx +100 -0
- package/src/@daf/core/components/UI/SDGIcon/styles.js +26 -0
- package/src/@daf/core/components/ViewForm/_index.scss +1 -1
- package/src/index.js +2 -0
- package/src/@daf/core/components/Icon/Icon.stories.js +0 -27
package/package.json
CHANGED
|
@@ -1,87 +1,85 @@
|
|
|
1
1
|
import Badge from "./index.jsx";
|
|
2
2
|
import ThemeLayout from "../ThemeLayout/index.jsx";
|
|
3
3
|
|
|
4
|
-
|
|
5
4
|
export default {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
5
|
+
title: "Components/Badge",
|
|
6
|
+
component: Badge,
|
|
7
|
+
tags: ["autodocs"],
|
|
8
|
+
args: {
|
|
9
|
+
children: "Badge Text",
|
|
10
|
+
variant: "success",
|
|
11
|
+
},
|
|
12
|
+
decorators: [
|
|
13
|
+
(Story) => (
|
|
14
|
+
<div style={{ margin: "3em" }}>
|
|
15
|
+
<ThemeLayout>
|
|
16
|
+
<Story />
|
|
17
|
+
</ThemeLayout>
|
|
18
|
+
</div>
|
|
19
|
+
),
|
|
20
|
+
],
|
|
22
21
|
};
|
|
23
22
|
|
|
24
23
|
export const Primary = {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
24
|
+
name: "Badge",
|
|
25
|
+
render: (args) => (
|
|
26
|
+
<div style={{ display: "flex", gap: "1em" }}>
|
|
27
|
+
<Badge {...args} />
|
|
28
|
+
</div>
|
|
29
|
+
),
|
|
29
30
|
};
|
|
30
31
|
|
|
31
32
|
export const Variants = {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
33
|
+
render: (args) => (
|
|
34
|
+
<div style={{ display: "flex", gap: "1em", flexDirection: "column" }}>
|
|
35
|
+
<Badge {...args} variant="default" />
|
|
36
|
+
<Badge {...args} variant="success" />
|
|
37
|
+
<Badge {...args} variant="danger" />
|
|
38
|
+
<Badge {...args} variant="warning" />
|
|
39
|
+
</div>
|
|
40
|
+
),
|
|
40
41
|
};
|
|
41
42
|
|
|
42
43
|
export const IconSize = {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
44
|
+
args: {
|
|
45
|
+
size: "icon",
|
|
46
|
+
},
|
|
47
|
+
render: (args) => (
|
|
48
|
+
<div style={{ display: "flex", gap: "1em" }}>
|
|
49
|
+
<Badge {...args} variant="default" />
|
|
50
|
+
<Badge {...args} />
|
|
51
|
+
<Badge {...args} variant="danger" />
|
|
52
|
+
<Badge {...args} variant="warning" />
|
|
53
|
+
</div>
|
|
54
|
+
),
|
|
54
55
|
};
|
|
55
56
|
|
|
56
57
|
export const CustomWidth = {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
58
|
+
render: (args) => (
|
|
59
|
+
<div style={{ display: "flex", gap: "1em", flexDirection: "column" }}>
|
|
60
|
+
<Badge {...args} size={600} />
|
|
61
|
+
<Badge {...args} size={50} />
|
|
62
|
+
<Badge {...args} size={500} />
|
|
63
|
+
<Badge {...args} size={300} />
|
|
64
|
+
</div>
|
|
65
|
+
),
|
|
65
66
|
};
|
|
66
67
|
|
|
67
68
|
export const BorderRadios = {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
),
|
|
69
|
+
render: (args) => (
|
|
70
|
+
<div style={{ display: "flex", gap: "1em" }}>
|
|
71
|
+
<Badge {...args} rounded="none" />
|
|
72
|
+
<Badge {...args} rounded="half" />
|
|
73
|
+
<Badge {...args} rounded="full" />
|
|
74
|
+
</div>
|
|
75
|
+
),
|
|
76
76
|
};
|
|
77
77
|
|
|
78
|
-
|
|
79
|
-
|
|
80
78
|
export const CustomBadge = {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
79
|
+
render: (args) => (
|
|
80
|
+
<>
|
|
81
|
+
<style>
|
|
82
|
+
{`
|
|
85
83
|
.test {
|
|
86
84
|
color: white !important;
|
|
87
85
|
}
|
|
@@ -94,38 +92,44 @@ export const CustomBadge = {
|
|
|
94
92
|
color: #ff169f;
|
|
95
93
|
border: 1px dashed #ff169f;
|
|
96
94
|
}`}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
95
|
+
</style>
|
|
96
|
+
<div style={{ display: "flex", gap: "1em" }} className="test">
|
|
97
|
+
<Badge
|
|
98
|
+
{...args}
|
|
99
|
+
rounded="half"
|
|
100
|
+
customIcon={"Delete"}
|
|
101
|
+
className="custom_badge_blue"
|
|
102
|
+
>
|
|
103
|
+
CUSTOMIZED
|
|
104
|
+
</Badge>
|
|
105
|
+
<Badge
|
|
106
|
+
{...args}
|
|
107
|
+
rounded="none"
|
|
108
|
+
size="icon"
|
|
109
|
+
customIcon={"Search"}
|
|
110
|
+
className="custom_badge_pink"
|
|
111
|
+
>
|
|
112
|
+
CUSTOMIZED
|
|
113
|
+
</Badge>
|
|
114
|
+
</div>
|
|
115
|
+
</>
|
|
116
|
+
),
|
|
114
117
|
};
|
|
115
118
|
|
|
116
119
|
export const WithTooltip = {
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
};
|
|
120
|
+
render: (args) => (
|
|
121
|
+
<div style={{ display: "flex", gap: "1em" }}>
|
|
122
|
+
<Badge {...args} size={144} tooltip>
|
|
123
|
+
lorem ipsum dolor sit amet consectetur adipiscing elit lorem ipsum dolor
|
|
124
|
+
sit amet consectetur adipiscing elit
|
|
125
|
+
</Badge>
|
|
126
|
+
<Badge {...args} tooltip="Yes this is a tooltip">
|
|
127
|
+
Tooltip with your text
|
|
128
|
+
</Badge>
|
|
129
|
+
<Badge {...args} variant="danger" tooltip size="icon">
|
|
130
|
+
Tooltip with danger
|
|
131
|
+
</Badge>
|
|
132
|
+
</div>
|
|
133
|
+
),
|
|
134
|
+
};
|
|
135
|
+
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import CarouselWidget from "./index";
|
|
2
|
+
import ThemeLayout from "../../../ThemeLayout";
|
|
3
|
+
import WidgetCard from "../WidgetCard";
|
|
4
|
+
|
|
5
|
+
export default {
|
|
6
|
+
title: "Dashboard/Widgets/CarouselWidget",
|
|
7
|
+
component: CarouselWidget,
|
|
8
|
+
tags: ["autodocs"],
|
|
9
|
+
decorators: [
|
|
10
|
+
(Story) => (
|
|
11
|
+
<ThemeLayout>
|
|
12
|
+
<Story />
|
|
13
|
+
</ThemeLayout>
|
|
14
|
+
),
|
|
15
|
+
],
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const contentStyle = {
|
|
19
|
+
margin: 0,
|
|
20
|
+
height: '160px',
|
|
21
|
+
color: '#fff',
|
|
22
|
+
lineHeight: '160px',
|
|
23
|
+
textAlign: 'center',
|
|
24
|
+
background: '#364d79',
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export const Primary = {
|
|
28
|
+
name: "CarouselWidget",
|
|
29
|
+
render: () => (
|
|
30
|
+
<CarouselWidget title="Carousel">
|
|
31
|
+
<div>
|
|
32
|
+
<h3 style={contentStyle}>1</h3>
|
|
33
|
+
</div>
|
|
34
|
+
<div>
|
|
35
|
+
<h3 style={contentStyle}>2</h3>
|
|
36
|
+
</div>
|
|
37
|
+
</CarouselWidget>
|
|
38
|
+
),
|
|
39
|
+
args: {
|
|
40
|
+
title: "Carousel",
|
|
41
|
+
},
|
|
42
|
+
};
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import Widget from '../index.jsx'
|
|
3
|
+
import { Carousel } from 'antd';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* CarouselWidget Component - A reusable widget wrapper for Ant Design Carousel with consistent styling
|
|
7
|
+
*
|
|
8
|
+
* @component
|
|
9
|
+
* @example
|
|
10
|
+
* // Basic usage
|
|
11
|
+
* <CarouselWidget title="My Content">
|
|
12
|
+
* <div>Slide 1</div>
|
|
13
|
+
* <div>Slide 2</div>
|
|
14
|
+
* </CarouselWidget>
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* // With additional carousel props
|
|
18
|
+
* <CarouselWidget
|
|
19
|
+
* title="Auto-play Carousel"
|
|
20
|
+
* autoplay
|
|
21
|
+
* dots={true}
|
|
22
|
+
* speed={500}
|
|
23
|
+
* >
|
|
24
|
+
* <div>Content 1</div>
|
|
25
|
+
* <div>Content 2</div>
|
|
26
|
+
* </CarouselWidget>
|
|
27
|
+
*
|
|
28
|
+
* @param {Object} props - Component props
|
|
29
|
+
* @param {string} props.title - The title displayed in the widget header
|
|
30
|
+
* @param {React.ReactNode} props.children - Child elements to be rendered as carousel slides
|
|
31
|
+
* @param {Object} [props.rest] - Additional props passed to the Ant Design Carousel component
|
|
32
|
+
* @param {boolean} [props.autoplay] - Whether to auto-play the carousel (passed via rest)
|
|
33
|
+
* @param {boolean} [props.dots=true] - Whether to show navigation dots (passed via rest)
|
|
34
|
+
* @param {number} [props.speed=500] - Animation speed in milliseconds (passed via rest)
|
|
35
|
+
* @param {boolean} [props.infinite=true] - Whether to enable infinite loop (passed via rest)
|
|
36
|
+
* @param {'horizontal'|'vertical'} [props.dotPosition='bottom'] - Position of navigation dots (passed via rest)
|
|
37
|
+
* @param {function} [props.beforeChange] - Callback before slide change (passed via rest)
|
|
38
|
+
* @param {function} [props.afterChange] - Callback after slide change (passed via rest)
|
|
39
|
+
*
|
|
40
|
+
* @features
|
|
41
|
+
* - ✅ Consistent widget styling with header and borders
|
|
42
|
+
* - ✅ Full Ant Design Carousel functionality support
|
|
43
|
+
* - ✅ Slide change event logging for debugging
|
|
44
|
+
* - ✅ Flexible content rendering via children
|
|
45
|
+
* - ✅ Responsive design integration
|
|
46
|
+
*
|
|
47
|
+
* @returns {JSX.Element} The rendered CarouselWidget component
|
|
48
|
+
*/
|
|
49
|
+
function CarouselWidget({title, children, ...rest}) {
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Handles carousel slide change events
|
|
53
|
+
* @param {number} currentSlide - The index of the current slide after change
|
|
54
|
+
* @private
|
|
55
|
+
*/
|
|
56
|
+
const onChange = (currentSlide) => {
|
|
57
|
+
console.log(currentSlide);
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
return (
|
|
61
|
+
<Widget
|
|
62
|
+
title={title}
|
|
63
|
+
className="with-border-header h-w-btn-header"
|
|
64
|
+
>
|
|
65
|
+
<Carousel afterChange={onChange} {...rest}>
|
|
66
|
+
{children}
|
|
67
|
+
</Carousel>
|
|
68
|
+
</Widget>
|
|
69
|
+
)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export default CarouselWidget;
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { Image } from "antd";
|
|
2
|
+
import ImageCarousel from "./index";
|
|
3
|
+
import ThemeLayout from "../../../ThemeLayout";
|
|
4
|
+
import WidgetCard from "../WidgetCard";
|
|
5
|
+
|
|
6
|
+
export default {
|
|
7
|
+
title: "Dashboard/Widgets/ImageCarousel",
|
|
8
|
+
component: ImageCarousel,
|
|
9
|
+
tags: ["autodocs"],
|
|
10
|
+
decorators: [
|
|
11
|
+
(Story) => (
|
|
12
|
+
<ThemeLayout>
|
|
13
|
+
<Story />
|
|
14
|
+
</ThemeLayout>
|
|
15
|
+
),
|
|
16
|
+
],
|
|
17
|
+
argTypes: {
|
|
18
|
+
height: {
|
|
19
|
+
control: { type: 'range', min: 200, max: 600, step: 50 },
|
|
20
|
+
description: 'Height of the carousel images'
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
// High quality sample images with proper alt text
|
|
26
|
+
const sampleImages = [
|
|
27
|
+
{
|
|
28
|
+
src: "https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=800&h=600&fit=crop",
|
|
29
|
+
alt: "Scenic mountain landscape with lake reflection"
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
src: "https://images.unsplash.com/photo-1441974231531-c6227db76b6e?w=800&h=600&fit=crop",
|
|
33
|
+
alt: "Dense forest path with sunlight filtering through trees"
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
src: "https://images.unsplash.com/photo-1448375240586-882707db888b?w=800&h=600&fit=crop",
|
|
37
|
+
alt: "Rolling green hills under a cloudy sky"
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
src: "https://images.unsplash.com/photo-1469474968028-56623f02e42e?w=800&h=600&fit=crop",
|
|
41
|
+
alt: "Serene forest landscape with tall pine trees"
|
|
42
|
+
}
|
|
43
|
+
];
|
|
44
|
+
|
|
45
|
+
const mixedQualityImages = [
|
|
46
|
+
{
|
|
47
|
+
src: "https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=800&h=600&fit=crop",
|
|
48
|
+
alt: "High quality mountain landscape"
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
src: "https://invalid-url-to-show-fallback.jpg",
|
|
52
|
+
alt: "Broken image to demonstrate fallback functionality"
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
src: "https://images.unsplash.com/photo-1441974231531-c6227db76b6e?w=400&h=300&fit=crop",
|
|
56
|
+
alt: "Lower resolution forest image"
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
src: "https://images.unsplash.com/photo-1448375240586-882707db888b?w=1200&h=800&fit=crop",
|
|
60
|
+
alt: "High resolution hills landscape"
|
|
61
|
+
}
|
|
62
|
+
];
|
|
63
|
+
|
|
64
|
+
export const Primary = {
|
|
65
|
+
name: "Basic ImageCarousel",
|
|
66
|
+
render: (args) => (
|
|
67
|
+
<div>
|
|
68
|
+
<p style={{ marginBottom: '16px', color: '#666' }}>
|
|
69
|
+
<strong>💡 Tip:</strong> Click any image to open preview, then use ← → arrow keys to navigate between images!
|
|
70
|
+
</p>
|
|
71
|
+
<ImageCarousel
|
|
72
|
+
title="Nature Gallery"
|
|
73
|
+
images={sampleImages}
|
|
74
|
+
{...args}
|
|
75
|
+
/>
|
|
76
|
+
</div>
|
|
77
|
+
),
|
|
78
|
+
args: {
|
|
79
|
+
title: "Nature Gallery",
|
|
80
|
+
height: 400,
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
export const WithFallbacks = {
|
|
85
|
+
name: "With Error Handling",
|
|
86
|
+
render: () => (
|
|
87
|
+
<ImageCarousel
|
|
88
|
+
title="Mixed Quality Images"
|
|
89
|
+
images={mixedQualityImages}
|
|
90
|
+
height={350}
|
|
91
|
+
/>
|
|
92
|
+
),
|
|
93
|
+
};
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import React, { useState, useRef } from "react";
|
|
2
|
+
import CarouselWidget from "../CarouselWidget/index.jsx";
|
|
3
|
+
import { Image, Carousel } from "antd";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @typedef {Object} ImageObject
|
|
7
|
+
* @property {string} src - The source URL of the image
|
|
8
|
+
* @property {string} alt - Alternative text for the image
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* ImageCarousel Component - A responsive image carousel with preview functionality and keyboard navigation
|
|
13
|
+
*
|
|
14
|
+
* @component
|
|
15
|
+
* @example
|
|
16
|
+
* // Basic usage with string URLs
|
|
17
|
+
* <ImageCarousel
|
|
18
|
+
* title="My Gallery"
|
|
19
|
+
* images={["image1.jpg", "image2.jpg"]}
|
|
20
|
+
* />
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* // Advanced usage with image objects and custom height
|
|
24
|
+
* <ImageCarousel
|
|
25
|
+
* title="Nature Gallery"
|
|
26
|
+
* images={[
|
|
27
|
+
* { src: "landscape.jpg", alt: "Beautiful mountain landscape" },
|
|
28
|
+
* { src: "forest.jpg", alt: "Dense forest path" }
|
|
29
|
+
* ]}
|
|
30
|
+
* height={300}
|
|
31
|
+
* fallback="/custom-fallback.svg"
|
|
32
|
+
* />
|
|
33
|
+
*
|
|
34
|
+
* @param {Object} props - Component props
|
|
35
|
+
* @param {string} props.title - The title displayed in the widget header
|
|
36
|
+
* @param {(string|ImageObject)[]} props.images - Array of image URLs (strings) or image objects with src and alt properties
|
|
37
|
+
* @param {number} [props.height=400] - Height of the carousel images in pixels
|
|
38
|
+
* @param {string} [props.fallback="/assets/images/empty-box.svg"] - Fallback image URL when original image fails to load
|
|
39
|
+
* @param {Object} [props.rest] - Additional props passed to the underlying CarouselWidget component
|
|
40
|
+
*
|
|
41
|
+
* @features
|
|
42
|
+
* - ✅ Responsive image display with lazy loading
|
|
43
|
+
* - ✅ Click-to-preview with full-screen image viewer
|
|
44
|
+
* - ✅ Keyboard navigation in preview mode (← → arrow keys)
|
|
45
|
+
* - ✅ Automatic fallback for broken images
|
|
46
|
+
* - ✅ Support for both string URLs and image objects with alt text
|
|
47
|
+
* - ✅ Synchronized carousel and preview navigation
|
|
48
|
+
* - ✅ Infinite scrolling in both carousel and preview modes
|
|
49
|
+
*
|
|
50
|
+
* @accessibility
|
|
51
|
+
* - Proper alt text support for screen readers
|
|
52
|
+
* - Keyboard navigation support
|
|
53
|
+
* - Focus management in preview mode
|
|
54
|
+
*
|
|
55
|
+
*/
|
|
56
|
+
function ImageCarousel({
|
|
57
|
+
title,
|
|
58
|
+
images,
|
|
59
|
+
height = 400,
|
|
60
|
+
fallback = "/assets/images/empty-box.svg",
|
|
61
|
+
...rest
|
|
62
|
+
}) {
|
|
63
|
+
const [previewVisible, setPreviewVisible] = useState(false);
|
|
64
|
+
const [current, setCurrent] = useState(0);
|
|
65
|
+
const carouselRef = useRef(null);
|
|
66
|
+
|
|
67
|
+
const handleCarouselChange = (index) => {
|
|
68
|
+
setCurrent(index);
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
return (
|
|
72
|
+
<>
|
|
73
|
+
<CarouselWidget title={title} {...rest} dots={false}>
|
|
74
|
+
<Carousel ref={carouselRef} afterChange={handleCarouselChange} infinite>
|
|
75
|
+
{images.map((image, index) => {
|
|
76
|
+
const imageSrc = typeof image === "string" ? image : image.src;
|
|
77
|
+
const imageAlt =
|
|
78
|
+
typeof image === "string"
|
|
79
|
+
? `${title} - Image ${index + 1}`
|
|
80
|
+
: image.alt;
|
|
81
|
+
|
|
82
|
+
return (
|
|
83
|
+
<div key={imageSrc}>
|
|
84
|
+
<Image
|
|
85
|
+
src={imageSrc}
|
|
86
|
+
alt={imageAlt}
|
|
87
|
+
height={height}
|
|
88
|
+
width="100%"
|
|
89
|
+
fallback={fallback}
|
|
90
|
+
loading="lazy"
|
|
91
|
+
preview={{
|
|
92
|
+
visible: false,
|
|
93
|
+
}}
|
|
94
|
+
onClick={() => {
|
|
95
|
+
setCurrent(index);
|
|
96
|
+
setPreviewVisible(true);
|
|
97
|
+
}}
|
|
98
|
+
/>
|
|
99
|
+
</div>
|
|
100
|
+
);
|
|
101
|
+
})}
|
|
102
|
+
</Carousel>
|
|
103
|
+
</CarouselWidget>
|
|
104
|
+
|
|
105
|
+
<div style={{ display: "none" }}>
|
|
106
|
+
<Image.PreviewGroup
|
|
107
|
+
preview={{
|
|
108
|
+
visible: previewVisible,
|
|
109
|
+
current,
|
|
110
|
+
onVisibleChange: (vis) => setPreviewVisible(vis),
|
|
111
|
+
onChange: (idx) => {
|
|
112
|
+
setCurrent(idx);
|
|
113
|
+
carouselRef.current?.goTo(idx);
|
|
114
|
+
},
|
|
115
|
+
}}
|
|
116
|
+
>
|
|
117
|
+
{images.map((image, index) => {
|
|
118
|
+
const imageSrc = typeof image === "string" ? image : image.src;
|
|
119
|
+
const imageAlt =
|
|
120
|
+
typeof image === "string"
|
|
121
|
+
? `${title} - Image ${index + 1}`
|
|
122
|
+
: image.alt;
|
|
123
|
+
|
|
124
|
+
return <Image key={imageSrc} src={imageSrc} alt={imageAlt} />;
|
|
125
|
+
})}
|
|
126
|
+
</Image.PreviewGroup>
|
|
127
|
+
</div>
|
|
128
|
+
</>
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export default ImageCarousel;
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import ProjectWidget from "./index.jsx";
|
|
2
2
|
import ThemeLayout from "../../../ThemeLayout/index.jsx";
|
|
3
3
|
import Widget from "../index.jsx";
|
|
4
|
-
|
|
5
4
|
import DashboardLayout from "../../DashboardLayout/index.jsx";
|
|
6
5
|
export default {
|
|
7
6
|
title: "Dashboard/Widgets/ProjectWidget",
|
|
@@ -21,8 +20,6 @@ export default {
|
|
|
21
20
|
export const Primary = {
|
|
22
21
|
name: "ProjectWidget",
|
|
23
22
|
args: {
|
|
24
|
-
image:
|
|
25
|
-
"https://images.steamusercontent.com/ugc/2064377508522269100/6E178CC9C29DDA679B4941E43DF799E93163804A/?imw=637&imh=358&ima=fit&impolicy=Letterbox&imcolor=%23000000&letterbox=true",
|
|
26
23
|
onLinkClick: () => {},
|
|
27
24
|
linkIcon: "Link",
|
|
28
25
|
sdgList: [
|