@canmingir/link 1.2.3 → 1.2.5

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.
@@ -0,0 +1,78 @@
1
+ import AnimatedNode from "./AnimatedNode";
2
+ import { Iconify } from "@canmingir/link/platform/components";
3
+ import LoadingNode from "./LoadingNode";
4
+ import React from "react";
5
+
6
+ import { Card, Tooltip, Typography } from "@mui/material";
7
+
8
+ const ActionNode = ({
9
+ visible,
10
+ delay,
11
+ isLoading,
12
+ action,
13
+ status,
14
+ tooltip,
15
+ icon,
16
+ }) => {
17
+ if (isLoading) {
18
+ return <LoadingNode visible={visible} delay={delay} />;
19
+ }
20
+
21
+ const card = (
22
+ <AnimatedNode visible={visible} delay={delay}>
23
+ <Card
24
+ sx={{
25
+ p: 2,
26
+ width: 180,
27
+ height: 100,
28
+ display: "flex",
29
+ flexDirection: "column",
30
+ alignItems: "center",
31
+ justifyContent: "center",
32
+ gap: 1,
33
+ borderRadius: 1,
34
+ bgcolor: "background.paper",
35
+ transition: "background-color 0.3s ease",
36
+ "&:hover": {
37
+ bgcolor: "grey.600",
38
+ cursor: "pointer",
39
+ },
40
+ }}
41
+ >
42
+ <Iconify icon={icon} width={24} height={24} />
43
+ <Typography
44
+ variant="caption"
45
+ sx={{
46
+ textAlign: "center",
47
+ fontSize: "0.5rem",
48
+ color: "text.secondary",
49
+ }}
50
+ >
51
+ {action}
52
+ </Typography>
53
+ {status && (
54
+ <Typography
55
+ variant="caption"
56
+ sx={{
57
+ textAlign: "center",
58
+ fontSize: "0.5rem",
59
+ color: "text.secondary",
60
+ }}
61
+ >
62
+ {status}
63
+ </Typography>
64
+ )}
65
+ </Card>
66
+ </AnimatedNode>
67
+ );
68
+
69
+ if (!tooltip) return card;
70
+
71
+ return (
72
+ <Tooltip title={tooltip} placement="right">
73
+ {card}
74
+ </Tooltip>
75
+ );
76
+ };
77
+
78
+ export default ActionNode;
@@ -0,0 +1,22 @@
1
+ import styled from "styled-components";
2
+
3
+ const AnimatedNode = styled.div`
4
+ opacity: 0;
5
+ transform: translateY(20px);
6
+ animation: ${({ visible }) =>
7
+ visible ? "nodeAppear 0.5s ease forwards" : "none"};
8
+ animation-delay: ${({ delay = 0 }) => `${delay}ms`};
9
+
10
+ @keyframes nodeAppear {
11
+ from {
12
+ opacity: 0;
13
+ transform: translateY(20px);
14
+ }
15
+ to {
16
+ opacity: 1;
17
+ transform: translateY(0);
18
+ }
19
+ }
20
+ `;
21
+
22
+ export default AnimatedNode;
@@ -0,0 +1,313 @@
1
+ import React from "react";
2
+
3
+ import { Box, Card, Stack } from "@mui/material";
4
+ import { alpha, useTheme } from "@mui/material/styles";
5
+
6
+ export function MediaAvatarCard({
7
+ sx,
8
+ leftContent,
9
+ rightContent,
10
+ background,
11
+ overlayColor,
12
+ backgroundClassName = "animated-background-image",
13
+ }) {
14
+ const theme = useTheme();
15
+
16
+ return (
17
+ <Card
18
+ sx={{
19
+ p: 0,
20
+ minWidth: 350,
21
+ maxWidth: 450,
22
+ height: 120,
23
+ borderRadius: 1.5,
24
+ textAlign: "left",
25
+ position: "relative",
26
+ display: "flex",
27
+ flexDirection: "row",
28
+ boxShadow: (theme) => theme.shadows[3],
29
+ "&:hover": {
30
+ boxShadow: (theme) => theme.shadows[6],
31
+ },
32
+ overflow: "hidden",
33
+ [`&:hover .${backgroundClassName}`]: {
34
+ width: "100%",
35
+ },
36
+ ...sx,
37
+ }}
38
+ >
39
+ {background && (
40
+ <Box
41
+ className={backgroundClassName}
42
+ sx={{
43
+ width: 100,
44
+ height: "100%",
45
+ position: "absolute",
46
+ top: 0,
47
+ left: 0,
48
+ zIndex: 0,
49
+ backgroundImage: `url(${background})`,
50
+ backgroundSize: "cover",
51
+ backgroundPosition: "center",
52
+ transition: theme.transitions.create("width", {
53
+ duration: theme.transitions.duration.standard,
54
+ easing: theme.transitions.easing.easeInOut,
55
+ }),
56
+ "&::after": {
57
+ content: '""',
58
+ position: "absolute",
59
+ inset: 0,
60
+ backgroundColor:
61
+ overlayColor || alpha(theme.palette.grey[900], 0.48),
62
+ },
63
+ }}
64
+ />
65
+ )}
66
+
67
+ <Stack
68
+ direction="column"
69
+ spacing={1}
70
+ sx={{
71
+ width: 100,
72
+ height: "100%",
73
+ justifyContent: "center",
74
+ alignItems: "center",
75
+ borderRadius: "8px 0 0 8px",
76
+ position: "relative",
77
+ zIndex: 1,
78
+ }}
79
+ >
80
+ {leftContent}
81
+ </Stack>
82
+
83
+ <Stack
84
+ direction="column"
85
+ spacing={1}
86
+ sx={{
87
+ flex: 1,
88
+ padding: 2,
89
+ zIndex: 1,
90
+ position: "relative",
91
+ }}
92
+ >
93
+ {rightContent}
94
+ </Stack>
95
+ </Card>
96
+ );
97
+ }
98
+
99
+ export function HeaderCard({
100
+ sx,
101
+ header,
102
+ children,
103
+ height = 140,
104
+ padding = 2,
105
+ }) {
106
+ const theme = useTheme();
107
+
108
+ return (
109
+ <Card
110
+ sx={{
111
+ p: padding,
112
+ minWidth: 200,
113
+ maxWidth: 420,
114
+ height,
115
+ borderRadius: 3,
116
+ position: "relative",
117
+ overflow: "hidden",
118
+ backgroundColor: theme.palette.background.paper,
119
+ transition: "all 0.3s ease-in-out",
120
+ "&:hover": {
121
+ transform: "translateY(-4px)",
122
+ boxShadow: theme.shadows[8],
123
+ "&:before": {
124
+ height: "100%",
125
+ },
126
+ },
127
+ "&:before": {
128
+ content: '""',
129
+ width: "100%",
130
+ height: "40%",
131
+ position: "absolute",
132
+ top: 0,
133
+ left: 0,
134
+ background: `linear-gradient(135deg, ${alpha(
135
+ theme.palette.secondary.light,
136
+ 0.2
137
+ )}, ${alpha(theme.palette.primary.main, 0.3)})`,
138
+ borderRadius: "8px 8px 0 0",
139
+ transition: "height 0.3s ease-in-out",
140
+ },
141
+ ...sx,
142
+ }}
143
+ >
144
+ <Stack
145
+ spacing={2}
146
+ sx={{
147
+ height: "100%",
148
+ position: "relative",
149
+ zIndex: 1,
150
+ }}
151
+ >
152
+ {header}
153
+ {children}
154
+ </Stack>
155
+ </Card>
156
+ );
157
+ }
158
+
159
+ export function SideStripeCard({
160
+ sx,
161
+ stripeContent,
162
+ mainContent,
163
+ minWidth = 200,
164
+ maxWidth = 290,
165
+ height = 100,
166
+ stripeWidth = 65,
167
+ }) {
168
+ const theme = useTheme();
169
+
170
+ return (
171
+ <Box
172
+ sx={{
173
+ cursor: "pointer",
174
+ }}
175
+ >
176
+ <Card
177
+ sx={{
178
+ display: "flex",
179
+ flexDirection: "row",
180
+ alignItems: "center",
181
+ minWidth,
182
+ maxWidth,
183
+ height,
184
+ borderRadius: 1.5,
185
+ boxShadow: 3,
186
+ position: "relative",
187
+ overflow: "hidden",
188
+ "&:hover": {
189
+ boxShadow: 6,
190
+ "& .animated-background-selector": {
191
+ width: "100%",
192
+ borderRadius: 1.5,
193
+ },
194
+ "& .responsibility-title, & .responsibility-description": {
195
+ color: theme.palette.getContrastText(theme.palette.primary.light),
196
+ },
197
+ },
198
+ ...sx,
199
+ }}
200
+ >
201
+ <Box
202
+ className="animated-background-selector"
203
+ sx={{
204
+ position: "absolute",
205
+ top: 0,
206
+ left: 0,
207
+ bottom: 0,
208
+ width: stripeWidth,
209
+ backgroundColor: theme.palette.primary.light,
210
+ borderRadius: "8px 0 0 8px",
211
+ transition: theme.transitions.create(["width", "border-radius"], {
212
+ duration: theme.transitions.duration.short,
213
+ }),
214
+ zIndex: 0,
215
+ }}
216
+ />
217
+ <Stack
218
+ direction="column"
219
+ spacing={1}
220
+ sx={{
221
+ position: "relative",
222
+ zIndex: 1,
223
+ width: stripeWidth,
224
+ height: "100%",
225
+ display: "flex",
226
+ justifyContent: "center",
227
+ alignItems: "center",
228
+ padding: 1,
229
+ }}
230
+ >
231
+ {stripeContent}
232
+ </Stack>
233
+
234
+ <Stack
235
+ direction="column"
236
+ spacing={1}
237
+ sx={{
238
+ padding: 2,
239
+ position: "relative",
240
+ zIndex: 1,
241
+ }}
242
+ >
243
+ {mainContent}
244
+ </Stack>
245
+ </Card>
246
+ </Box>
247
+ );
248
+ }
249
+
250
+ export function AvatarRoleCard({
251
+ sx,
252
+ leftContent,
253
+ topRightContent,
254
+ bottomContent,
255
+ }) {
256
+ const theme = useTheme();
257
+
258
+ return (
259
+ <Card
260
+ sx={{
261
+ p: 2.5,
262
+ width: 230,
263
+ height: 120,
264
+ borderRadius: 2,
265
+ position: "relative",
266
+ backgroundColor: theme.palette.background.paper,
267
+ transition: "all 0.3s ease-in-out",
268
+ "&:hover": {
269
+ transform: "translateY(-4px)",
270
+ boxShadow: theme.shadows[8],
271
+ "&:before": {
272
+ height: "100%",
273
+ },
274
+ },
275
+ "&:before": {
276
+ content: '""',
277
+ width: "100%",
278
+ height: "40%",
279
+ position: "absolute",
280
+ top: 0,
281
+ left: 0,
282
+ background: `linear-gradient(135deg, ${alpha(
283
+ theme.palette.secondary.light,
284
+ 0.2
285
+ )}, ${alpha(theme.palette.primary.main, 0.3)})`,
286
+ borderRadius: "8px 8px 0 0",
287
+ transition: "height 0.3s ease-in-out",
288
+ },
289
+ ...sx,
290
+ }}
291
+ >
292
+ <Stack
293
+ spacing={1}
294
+ sx={{
295
+ height: "100%",
296
+ position: "relative",
297
+ zIndex: 1,
298
+ }}
299
+ >
300
+ <Stack
301
+ direction="row"
302
+ justifyContent="space-between"
303
+ alignItems="flex-start"
304
+ >
305
+ {leftContent}
306
+ {topRightContent}
307
+ </Stack>
308
+
309
+ {bottomContent && <Stack spacing={0.5}>{bottomContent}</Stack>}
310
+ </Stack>
311
+ </Card>
312
+ );
313
+ }
@@ -0,0 +1,196 @@
1
+ import { Iconify } from "@canmingir/link/platform/components";
2
+
3
+ import React, { useEffect, useState } from "react";
4
+ import { alpha, styled } from "@mui/material/styles";
5
+
6
+ const ANIMATION_DELAY_MS = 200;
7
+
8
+ const MainContainer = styled("div", {
9
+ shouldForwardProp: (prop) => prop !== "$style",
10
+ })(({ theme, $style = {} }) => {
11
+ const {
12
+ minWidth = 120,
13
+ minHeight = 120,
14
+ maxWidth = 160,
15
+ maxHeight = 160,
16
+ borderRadius = 16,
17
+ borderColor = "rgba(255, 255, 255, 0.2)",
18
+ bgFrom,
19
+ bgTo,
20
+ } = $style;
21
+
22
+ const defaultFrom = alpha(theme.palette.secondary.light, 0.2);
23
+ const defaultTo = alpha(theme.palette.primary.main, 0.3);
24
+
25
+ const hoveredFrom = alpha(theme.palette.primary.main, 0.3);
26
+ const hoveredTo = alpha(theme.palette.secondary.light, 0.2);
27
+
28
+ return {
29
+ display: "flex",
30
+ flexDirection: "column",
31
+ alignItems: "center",
32
+ color: "#ffffff",
33
+ borderRadius,
34
+ padding: "16px 20px",
35
+ border: `1px solid ${borderColor}`,
36
+ backdropFilter: "blur(10px)",
37
+ transition: "all 0.4s cubic-bezier(0.4, 0, 0.2, 1)",
38
+ cursor: "pointer",
39
+ position: "relative",
40
+ overflow: "hidden",
41
+ minWidth,
42
+ minHeight,
43
+ maxWidth,
44
+ maxHeight,
45
+ background: `linear-gradient(135deg, ${bgFrom || defaultFrom}, ${
46
+ bgTo || defaultTo
47
+ })`,
48
+ boxShadow: "0 2px 10px rgba(0, 0, 0, 0.2)",
49
+
50
+ '&[data-hovered="true"]': {
51
+ background: `linear-gradient(135deg, ${bgTo || hoveredFrom}, ${
52
+ bgFrom || hoveredTo
53
+ })`,
54
+ boxShadow: "0 4px 20px rgba(0, 0, 0, 0.3)",
55
+ },
56
+ };
57
+ });
58
+
59
+ const IconContainer = styled("div", {
60
+ shouldForwardProp: (prop) => prop !== "$style",
61
+ })(({ $style = {} }) => {
62
+ const {
63
+ bg = "rgba(255, 255, 255, 0.1)",
64
+ hoverBg = "rgba(255, 255, 255, 0.15)",
65
+ borderRadius = 12,
66
+ padding = 8,
67
+ borderColor = "rgba(255, 255, 255, 0.3)",
68
+ marginBottom = 12,
69
+ } = $style;
70
+
71
+ return {
72
+ backgroundColor: bg,
73
+ borderRadius,
74
+ padding,
75
+ marginBottom,
76
+ transition: "all 0.4s ease",
77
+ backdropFilter: "blur(5px)",
78
+ border: `1px solid ${borderColor}`,
79
+
80
+ '[data-hovered="true"] &': {
81
+ backgroundColor: hoverBg,
82
+ },
83
+ };
84
+ });
85
+
86
+ const LabelText = styled("div", {
87
+ shouldForwardProp: (prop) => prop !== "$style",
88
+ })(({ $style = {} }) => {
89
+ const {
90
+ color = "#ffffff",
91
+ fontWeight = 600,
92
+ fontSize = 13,
93
+ letterSpacing = 0.5,
94
+ } = $style;
95
+
96
+ return {
97
+ fontWeight,
98
+ fontSize,
99
+ letterSpacing: `${letterSpacing}px`,
100
+ textAlign: "center",
101
+ transition: "all 0.5s cubic-bezier(0.4, 0, 0.2, 1)",
102
+ textShadow: "none",
103
+ lineHeight: "1.4",
104
+ opacity: 0,
105
+ transform: "translateY(10px)",
106
+ color,
107
+
108
+ '&[data-animated="true"]': {
109
+ opacity: 1,
110
+ transform: "translateY(0)",
111
+ },
112
+ };
113
+ });
114
+
115
+ const getIcon = (node) => {
116
+ if (node.icon) return node.icon;
117
+ if (node.type === "CONDITION" || node.type === "decision")
118
+ return "mdi:help-circle-outline";
119
+ if (node.type === "NORMAL") return "mdi:checkbox-blank-circle-outline";
120
+ return "mdi:cube-outline";
121
+ };
122
+
123
+ const InfoNode = ({ node, nodeStyle = {} }) => {
124
+ const [animated, setAnimated] = useState(false);
125
+ const [isHovered, setIsHovered] = useState(false);
126
+
127
+ const label =
128
+ node.label || node.title || node.name || node.id || "Responsibility";
129
+
130
+ useEffect(() => {
131
+ const timer = setTimeout(() => setAnimated(true), ANIMATION_DELAY_MS);
132
+ return () => clearTimeout(timer);
133
+ }, []);
134
+
135
+ const layoutStyle = {
136
+ minWidth: nodeStyle.cardWidth || nodeStyle.minWidth || 120,
137
+ minHeight: nodeStyle.minHeight || 120,
138
+ maxWidth: nodeStyle.maxWidth || 160,
139
+ maxHeight: nodeStyle.maxHeight || 160,
140
+ borderRadius: typeof nodeStyle.shape === "number" ? nodeStyle.shape : 16,
141
+ borderColor: nodeStyle.borderColor || "rgba(255, 255, 255, 0.2)",
142
+ bgFrom: nodeStyle.bgFrom,
143
+ bgTo: nodeStyle.bgTo,
144
+ };
145
+
146
+ const iconContainerStyle = {
147
+ iconBg: nodeStyle.iconBg,
148
+ iconHoverBg: nodeStyle.iconHoverBg,
149
+ iconBorderRadius: nodeStyle.iconRadius,
150
+ iconPadding: nodeStyle.iconPadding,
151
+ iconBorderColor: nodeStyle.iconBorderColor,
152
+ iconMarginBottom: nodeStyle.iconMarginBottom,
153
+ };
154
+
155
+ const labelStyle = {
156
+ labelColor: nodeStyle.labelColor,
157
+ labelFontSize: nodeStyle.labelFontSize,
158
+ labelFontWeight: nodeStyle.labelFontWeight,
159
+ labelLetterSpacing: nodeStyle.labelLetterSpacing,
160
+ };
161
+
162
+ const icon = getIcon(node);
163
+
164
+ return (
165
+ <MainContainer
166
+ $style={layoutStyle}
167
+ data-hovered={isHovered}
168
+ onMouseEnter={() => setIsHovered(true)}
169
+ onMouseLeave={() => setIsHovered(false)}
170
+ >
171
+ <IconContainer $style={iconContainerStyle}>
172
+ <Iconify
173
+ icon={icon}
174
+ width={28}
175
+ height={28}
176
+ sx={{
177
+ transition: "all 0.6s cubic-bezier(0.4, 0, 0.2, 1)",
178
+ transform: animated
179
+ ? isHovered
180
+ ? "rotate(360deg) scale(1.1)"
181
+ : "rotate(0deg) scale(1)"
182
+ : "rotate(-90deg) scale(0.8)",
183
+ filter: "none",
184
+ color: nodeStyle.iconColor || "#ffffff",
185
+ }}
186
+ />
187
+ </IconContainer>
188
+
189
+ <LabelText data-animated={animated} $style={labelStyle}>
190
+ {label}
191
+ </LabelText>
192
+ </MainContainer>
193
+ );
194
+ };
195
+
196
+ export default InfoNode;
@@ -0,0 +1,37 @@
1
+ import AnimatedNode from "./AnimatedNode";
2
+ import React from "react";
3
+
4
+ import { Card, CircularProgress, Typography } from "@mui/material";
5
+
6
+ const LoadingNode = ({ visible, delay }) => (
7
+ <AnimatedNode visible={visible} delay={delay}>
8
+ <Card
9
+ sx={{
10
+ p: 2,
11
+ width: 180,
12
+ height: 100,
13
+ display: "flex",
14
+ flexDirection: "column",
15
+ alignItems: "center",
16
+ justifyContent: "center",
17
+ gap: 1,
18
+ borderRadius: 1,
19
+ bgcolor: "background.paper",
20
+ }}
21
+ >
22
+ <CircularProgress size={24} />
23
+ <Typography
24
+ variant="caption"
25
+ sx={{
26
+ textAlign: "center",
27
+ fontSize: "0.5rem",
28
+ color: "text.secondary",
29
+ }}
30
+ >
31
+ Loading...
32
+ </Typography>
33
+ </Card>
34
+ </AnimatedNode>
35
+ );
36
+
37
+ export default LoadingNode;