tee3apps-cms-sdk-react 0.0.1

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.
Files changed (43) hide show
  1. package/.env +11 -0
  2. package/README.md +255 -0
  3. package/dist/index.d.ts +5 -0
  4. package/dist/index.js +13 -0
  5. package/dist/index.js.map +1 -0
  6. package/dist/index.mjs +13 -0
  7. package/dist/index.mjs.map +1 -0
  8. package/package.json +33 -0
  9. package/rollup.config.js +43 -0
  10. package/src/Components/BoxRenderer.tsx +108 -0
  11. package/src/Components/ComponentRenderer.tsx +29 -0
  12. package/src/Components/ImageComponent.tsx +68 -0
  13. package/src/Components/RowComponent.tsx +66 -0
  14. package/src/Components/TextComponent.tsx +47 -0
  15. package/src/ErrorBoundary.tsx +35 -0
  16. package/src/Page.tsx +124 -0
  17. package/src/PageComponents/BoxComponent.tsx +397 -0
  18. package/src/PageComponents/RowComponent.tsx +113 -0
  19. package/src/PageComponents/Visual-Components/CarouselComponent.tsx +366 -0
  20. package/src/PageComponents/Visual-Components/GroupBrandComponent.tsx +391 -0
  21. package/src/PageComponents/Visual-Components/GroupCategoryComponent.tsx +425 -0
  22. package/src/PageComponents/Visual-Components/GroupImageList.tsx +669 -0
  23. package/src/PageComponents/Visual-Components/GroupProductComponent.tsx +671 -0
  24. package/src/PageComponents/Visual-Components/GroupVideoList.tsx +590 -0
  25. package/src/PageComponents/Visual-Components/ImageComponent.tsx +163 -0
  26. package/src/PageComponents/Visual-Components/LinkComponent.tsx +68 -0
  27. package/src/PageComponents/Visual-Components/LottieComponent.tsx +213 -0
  28. package/src/PageComponents/Visual-Components/NavigationComponent.tsx +178 -0
  29. package/src/PageComponents/Visual-Components/Styles/ProductListViewOne.tsx +102 -0
  30. package/src/PageComponents/Visual-Components/Styles/ProductListViewTwo.tsx +104 -0
  31. package/src/PageComponents/Visual-Components/Styles/product-list-view-one.css +166 -0
  32. package/src/PageComponents/Visual-Components/Styles/product-list-view-two.css +182 -0
  33. package/src/PageComponents/Visual-Components/TabComponent.tsx +1169 -0
  34. package/src/PageComponents/Visual-Components/TextComponent.tsx +114 -0
  35. package/src/PageComponents/Visual-Components/VideoComponent.tsx +191 -0
  36. package/src/PageComponents/Visual-Components/tab.css +697 -0
  37. package/src/common.interface.ts +216 -0
  38. package/src/const.ts +6 -0
  39. package/src/env.d.ts +15 -0
  40. package/src/index.css +82 -0
  41. package/src/index.ts +2 -0
  42. package/src/types.ts +234 -0
  43. package/tsconfig.json +20 -0
@@ -0,0 +1,163 @@
1
+ import '../../../src/index.css';
2
+ import React from 'react';
3
+ import { Linodeurl } from '../../const';
4
+
5
+ interface ImageData {
6
+ isDynamic: boolean;
7
+ shape: string;
8
+ url: string;
9
+ alt: string;
10
+ }
11
+
12
+ interface ImageModeProps {
13
+ borderRadius: number;
14
+ width: string;
15
+ height: string;
16
+ }
17
+
18
+ interface ImageComponentProps {
19
+ images: any;
20
+ mode: {
21
+ web: ImageModeProps;
22
+ mobileweb: ImageModeProps;
23
+ mobileapp: ImageModeProps;
24
+ tablet: ImageModeProps;
25
+ };
26
+ linktype: string;
27
+ link: {
28
+ url: string;
29
+ target: string;
30
+ };
31
+ product: {
32
+ _id: string;
33
+ code: string;
34
+ name: object;
35
+ pd_type: string;
36
+ };
37
+ page: {
38
+ _id: string;
39
+ code: string;
40
+ name: object;
41
+ pg_type: string;
42
+ facet_params: any[];
43
+ track_params: any[];
44
+ };
45
+ tag: {
46
+ _id: string;
47
+ code: string;
48
+ name: object;
49
+ tagtype: string;
50
+ };
51
+ type: any[];
52
+ }
53
+
54
+ interface ImageComponentMainProps {
55
+ props: ImageComponentProps;
56
+ deviceMode?: string;
57
+ boxHeight?: string; // Add this prop to receive box height
58
+ }
59
+
60
+ const ImageComponent: React.FC<ImageComponentMainProps> = ({
61
+ props,
62
+ deviceMode = 'web',
63
+ boxHeight = '280px',
64
+ }) => {
65
+
66
+ const bannerLink = (element: any): string | null => {
67
+ if (!element || !element.linktype) return null;
68
+
69
+ switch (element.linktype) {
70
+ case 'NONE':
71
+ return null;
72
+
73
+ case 'EXTERNAL':
74
+ case 'EXTERNAL_LINK':
75
+ return element.link?.url || null;
76
+
77
+ case 'PRODUCT': {
78
+ const pdType = element.product?.pd_type;
79
+ const code =
80
+ element.product?.pd_id?.code ||
81
+ element.product?.code ||
82
+ element.product?.product_data?.code;
83
+
84
+ if (!code) return null;
85
+
86
+ return pdType === 'VARIANT'
87
+ ? `/variant/${code}`
88
+ : `model/${code}`;
89
+ }
90
+
91
+ case 'TAG': {
92
+ const tagCode = element.tag?.code;
93
+ if (!tagCode) return null;
94
+ // return `/${tagCode}/s?type=tag`;
95
+ return `/tag/${tagCode}`;
96
+ }
97
+
98
+ case 'PAGE': {
99
+ const pageId = element.page?._id || element.page?.code;
100
+ const pgType = element.page?.pg_type;
101
+ if (!pageId || !pgType) return null;
102
+ return `/page/${pageId}?type=${pgType}`;
103
+ }
104
+
105
+ default:
106
+ return element.slug || null;
107
+ }
108
+ };
109
+
110
+ const getCurrentMode = () => {
111
+ switch (deviceMode) {
112
+ case 'mobileweb':
113
+ return props.mode.mobileweb;
114
+ case 'mobileapp':
115
+ return props.mode.mobileapp;
116
+ case 'tablet':
117
+ return props.mode.tablet;
118
+ case 'web':
119
+ default:
120
+ return props.mode.web;
121
+ }
122
+ };
123
+
124
+ const currentMode = getCurrentMode();
125
+ const containerHeight = boxHeight === 'auto' ? 'auto' : boxHeight;
126
+ const link = bannerLink(props);
127
+ const imageUrl = `${Linodeurl}${props.images?.url || props.images?.all?.url}`;
128
+ const altText = props.images.alt || '';
129
+
130
+ const imageElement = (
131
+ <img
132
+ src={imageUrl}
133
+ alt={altText}
134
+ className="fitted-image"
135
+ style={{ cursor: link ? 'pointer' : 'default' }}
136
+ />
137
+ );
138
+
139
+ return (
140
+ <div
141
+ className="image-box"
142
+ style={{
143
+ borderRadius: `${currentMode.borderRadius}px`,
144
+ height: containerHeight,
145
+ overflow: 'hidden',
146
+ }}
147
+ >
148
+ {link ? (
149
+ <a
150
+ href={link}
151
+ target={props?.linktype=='EXTERNAL' ? props?.link?.target :'_self'}
152
+ style={{ display: 'block', width: '100%', height: '100%' }}
153
+ >
154
+ {imageElement}
155
+ </a>
156
+ ) : (
157
+ imageElement
158
+ )}
159
+ </div>
160
+ );
161
+ };
162
+
163
+ export default ImageComponent;
@@ -0,0 +1,68 @@
1
+ import React from 'react';
2
+
3
+ interface LinkProps {
4
+ text: any;
5
+ url: string;
6
+ target: string;
7
+ framename: string;
8
+ style?: {
9
+ fontSize?: number;
10
+ fontStyle?: {
11
+ isBold?: boolean;
12
+ isItalic?: boolean;
13
+ isUnderLine?: boolean;
14
+ isStrikeThrough?: boolean;
15
+ };
16
+ fontColor?: string;
17
+ textAlign?: React.CSSProperties['textAlign'];
18
+ fontFamily?: string;
19
+ };
20
+ }
21
+
22
+ interface LinkComponentProps {
23
+ props: LinkProps;
24
+ }
25
+
26
+ const LinkComponent: React.FC<LinkComponentProps> = ({ props }) => {
27
+ const { text, url, target, style } = props;
28
+
29
+ const linkStyle: React.CSSProperties = {
30
+ fontSize: style?.fontSize ? `${style.fontSize}px` : '16px',
31
+ fontWeight: style?.fontStyle?.isBold ? 'bold' : 'normal',
32
+ fontStyle: style?.fontStyle?.isItalic ? 'italic' : 'normal',
33
+ textDecoration: style?.fontStyle?.isUnderLine ? 'underline' : 'none',
34
+ textDecorationLine: style?.fontStyle?.isStrikeThrough ? 'line-through' : 'none',
35
+ color: style?.fontColor || '#000000ff',
36
+ textAlign: (style?.textAlign as React.CSSProperties['textAlign']) || 'left',
37
+ fontFamily: style?.fontFamily || 'inherit',
38
+ margin: 5,
39
+ wordWrap: "break-word" as const,
40
+ overflowWrap: "break-word" as const,
41
+ maxWidth: "100%",
42
+ whiteSpace: "normal" as const,
43
+ width: "100%",
44
+ boxSizing: "border-box" as const,
45
+ wordBreak: "break-word" as const,
46
+ };
47
+
48
+ return (
49
+ <div style={{
50
+ display: "block" as const,
51
+ width: "100%",
52
+ maxWidth: "100%",
53
+ wordWrap: "break-word" as const,
54
+ overflowWrap: "break-word" as const,
55
+ boxSizing: "border-box" as const,
56
+ }}>
57
+ <a
58
+ href={url}
59
+ target={target}
60
+ style={linkStyle}
61
+ >
62
+ {text}
63
+ </a>
64
+ </div>
65
+ );
66
+ };
67
+
68
+ export default LinkComponent;
@@ -0,0 +1,213 @@
1
+ import React from 'react'
2
+ import Lottie from 'lottie-react'
3
+ import { Linodeurl } from '../../const'
4
+
5
+ // No custom JSX intrinsic elements needed when using lottie-react
6
+
7
+ interface LottieModeProps {
8
+ autoplay: boolean
9
+ loop: boolean
10
+ height: string
11
+ width: string
12
+ }
13
+
14
+ export interface LottieComponentProps {
15
+ lottieurl: string
16
+ linktype: string
17
+ link: {
18
+ url: string
19
+ target: string
20
+ }
21
+ product: {
22
+ _id: string
23
+ code: string
24
+ name: object
25
+ pd_type: string
26
+ }
27
+ page: {
28
+ _id: string
29
+ code: string
30
+ name: object
31
+ pg_type: string
32
+ facet_params: any[]
33
+ track_params: any[]
34
+ }
35
+ tag: {
36
+ _id: string
37
+ code: string
38
+ name: object
39
+ tagtype: string
40
+ }
41
+ mode: {
42
+ web: LottieModeProps
43
+ mobileweb: LottieModeProps
44
+ mobileapp: LottieModeProps
45
+ tablet: LottieModeProps
46
+ }
47
+ }
48
+
49
+ interface LottieComponentMainProps {
50
+ props: LottieComponentProps
51
+ deviceMode?: 'web' | 'mobileweb' | 'mobileapp' | 'tablet'
52
+ }
53
+
54
+ const LottieComponent: React.FC<LottieComponentMainProps> = ({ props, deviceMode = 'web' }) => {
55
+ const bannerLink = (element: any): string | null => {
56
+ if (!element || !element.linktype) return null;
57
+
58
+ switch (element.linktype) {
59
+ case 'NONE':
60
+ return null;
61
+
62
+ case 'EXTERNAL':
63
+ case 'EXTERNAL_LINK':
64
+ return element.link?.url || null;
65
+
66
+ case 'PRODUCT': {
67
+ const pdType = element.product?.pd_type;
68
+ const code =
69
+ element.product?.pd_id?.code ||
70
+ element.product?.code ||
71
+ element.product?.product_data?.code;
72
+
73
+ if (!code) return null;
74
+
75
+ return pdType === 'VARIANT'
76
+ ? `/${code}/s?type=variant`
77
+ : `/${code}/s?type=model`;
78
+ }
79
+
80
+ case 'TAG': {
81
+ const tagCode = element.tag?.code;
82
+ if (!tagCode) return null;
83
+ return `/${tagCode}/s?type=tag`;
84
+ }
85
+
86
+ case 'PAGE': {
87
+ const pageId = element.page?._id || element.page?.code;
88
+ const pgType = element.page?.pg_type?.toLowerCase();
89
+ if (!pageId || !pgType) return null;
90
+ return `/page/${pageId}?type=${pgType}`;
91
+ }
92
+
93
+ default:
94
+ return element.slug || null;
95
+ }
96
+ };
97
+
98
+
99
+ const link = bannerLink(props)
100
+
101
+
102
+ const getCurrentMode = (): LottieModeProps => {
103
+ switch (deviceMode) {
104
+ case 'mobileweb':
105
+ return props.mode.mobileweb
106
+ case 'mobileapp':
107
+ return props.mode.mobileapp
108
+ case 'tablet':
109
+ return props.mode.tablet
110
+ case 'web':
111
+ default:
112
+ return props.mode.web
113
+ }
114
+ }
115
+
116
+ const currentMode = getCurrentMode()
117
+
118
+ const src = props.lottieurl?.startsWith('http')
119
+ ? props.lottieurl
120
+ : `${Linodeurl}${props.lottieurl}`
121
+
122
+ const isClickable = bannerLink(props) !== null
123
+
124
+ const [animationData, setAnimationData] = React.useState<any | null>(null)
125
+ const [error, setError] = React.useState<string | null>(null)
126
+
127
+ React.useEffect(() => {
128
+ let isMounted = true
129
+ const controller = new AbortController()
130
+ setAnimationData(null)
131
+ setError(null)
132
+ fetch(src, { signal: controller.signal })
133
+ .then(async (res) => {
134
+ if (!res.ok) throw new Error(`Failed to load lottie json: ${res.status}`)
135
+ return res.json()
136
+ })
137
+ .then((json) => {
138
+ if (isMounted) setAnimationData(json)
139
+ })
140
+ .catch((e) => {
141
+ if (isMounted && e.name !== 'AbortError') setError(e.message || 'Failed to load animation')
142
+ })
143
+ return () => {
144
+ isMounted = false
145
+ controller.abort()
146
+ }
147
+ }, [src])
148
+
149
+ return (
150
+ <>
151
+ {link?(
152
+ <a
153
+ href={link}
154
+ target={props?.linktype=='EXTERNAL' ? props?.link?.target :'_self'}
155
+ >
156
+ <div
157
+ style={{
158
+ width: '100%',
159
+ height: '100%',
160
+ display: 'inline-block',
161
+ backgroundColor: 'white',
162
+ cursor: isClickable ? 'pointer' : 'default',
163
+ }}
164
+
165
+ >
166
+ {animationData && (
167
+ <Lottie
168
+ animationData={animationData}
169
+ loop={currentMode.loop}
170
+ autoplay={currentMode.autoplay}
171
+ style={{ width: '100%', height: '100%' }}
172
+ />
173
+ )}
174
+ {!animationData && !error && (
175
+ <div style={{ width: '100%', height: '100%' }} />
176
+ )}
177
+ {error && (
178
+ <div style={{ fontSize: '12px', color: '#999' }}>Failed to load animation</div>
179
+ )}
180
+ </div>
181
+ </a>
182
+ ):(
183
+ <div
184
+ style={{
185
+ width: '100%',
186
+ height: '100%',
187
+ display: 'inline-block',
188
+ backgroundColor: 'white',
189
+ cursor: isClickable ? 'pointer' : 'default',
190
+ }}
191
+
192
+ >
193
+ {animationData && (
194
+ <Lottie
195
+ animationData={animationData}
196
+ loop={currentMode.loop}
197
+ autoplay={currentMode.autoplay}
198
+ style={{ width: '100%', height: '100%' }}
199
+ />
200
+ )}
201
+ {!animationData && !error && (
202
+ <div style={{ width: '100%', height: '100%' }} />
203
+ )}
204
+ {error && (
205
+ <div style={{ fontSize: '12px', color: '#999' }}>Failed to load animation</div>
206
+ )}
207
+ </div>
208
+ )}
209
+ </>
210
+ )
211
+ }
212
+
213
+ export default LottieComponent
@@ -0,0 +1,178 @@
1
+ import React from 'react'
2
+
3
+ interface NavTitle {
4
+ all: string
5
+ }
6
+
7
+ interface NavItem {
8
+ nl_id?: string
9
+ id?: string
10
+ title: any
11
+ url?: string
12
+ target?: string
13
+ framename?: string
14
+ children?: NavItem[]
15
+ collapsed?: boolean
16
+ }
17
+
18
+ interface ColorPair {
19
+ background: string
20
+ text: string
21
+ arrow?: string
22
+ separator?: string
23
+ }
24
+
25
+ interface LayerStyle {
26
+ isSeparator: boolean
27
+ color: ColorPair
28
+ colorHover: ColorPair
29
+ }
30
+
31
+ interface NavigationStyles {
32
+ primary: LayerStyle
33
+ secondary: LayerStyle
34
+ }
35
+
36
+ export interface NavigationProps {
37
+ navData: NavItem[]
38
+ shape: 'simple' | string
39
+ styles: NavigationStyles
40
+ }
41
+
42
+ interface NavigationComponentMainProps {
43
+ props: NavigationProps
44
+ boxHeight: string
45
+ }
46
+
47
+ const NavigationComponent: React.FC<NavigationComponentMainProps> = ({ props, boxHeight }) => {
48
+ const root = props.navData?.[0]
49
+ const topItems: NavItem[] = root?.children || []
50
+
51
+ const [openId, setOpenId] = React.useState<string | null>(null)
52
+
53
+ const buildHref = (item: NavItem) => item.url || '#'
54
+
55
+ const Item = ({ item, depth = 0, isRoot = false }: { item: NavItem; depth?: number; isRoot?: boolean }) => {
56
+ const hasChildren = Array.isArray(item.children) && item.children.length > 0
57
+ const isTop = depth === 0 && !isRoot
58
+ const layer = isRoot ? props.styles.primary : (isTop ? props.styles.primary : props.styles.secondary)
59
+
60
+ const baseStyles: React.CSSProperties = {
61
+ display: 'flex',
62
+ alignItems: 'center',
63
+ justifyContent: 'space-between',
64
+ gap: '8px',
65
+ padding: isRoot ? '12px 16px' : (isTop ? '10px 14px' : '8px 12px'),
66
+ color: layer.color.text,
67
+ background: layer.color.background,
68
+ textDecoration: 'none',
69
+ whiteSpace: 'nowrap',
70
+ fontSize: isRoot ? 16 : (isTop ? 14 : 13),
71
+ borderBottom: layer.isSeparator && !isTop && !isRoot ? `1px solid ${layer.color.separator}` : 'none',
72
+ borderRadius: isRoot ? 8 : (isTop ? 6 : 4),
73
+ cursor: 'pointer',
74
+ fontWeight: isRoot ? 'bold' : 'normal'
75
+ }
76
+
77
+ const [hover, setHover] = React.useState(false)
78
+
79
+ return (
80
+ <div
81
+ style={{ position: 'relative' }}
82
+ onMouseEnter={() => { setHover(true); if (isTop || isRoot) setOpenId(item.id || item.nl_id || null) }}
83
+ onMouseLeave={() => { setHover(false); if (isTop || isRoot) setOpenId((prev) => (prev === (item.id || item.nl_id) ? null : prev)) }}
84
+ >
85
+ {isRoot ? (
86
+ <div
87
+ style={{
88
+ ...baseStyles,
89
+ background: hover ? layer.colorHover.background : layer.color.background,
90
+ color: hover ? layer.colorHover.text : layer.color.text,
91
+ cursor: 'default'
92
+ }}
93
+ >
94
+ <span>{item?.title}</span>
95
+ {hasChildren && (
96
+ <span style={{ color: layer.color.arrow || layer.color.text }}>{'▾'}</span>
97
+ )}
98
+ </div>
99
+ ) : (
100
+ <a
101
+ href={buildHref(item)}
102
+ target={item.target || '_self'}
103
+ rel={item.target === '_blank' ? 'noopener noreferrer' : undefined}
104
+ style={{
105
+ ...baseStyles,
106
+ background: hover ? layer.colorHover.background : layer.color.background,
107
+ color: hover ? layer.colorHover.text : layer.color.text
108
+ }}
109
+ >
110
+ <span>{item?.title}</span>
111
+ {hasChildren && (
112
+ <span style={{ color: layer.color.arrow || layer.color.text }}>{isTop ? '▾' : '›'}</span>
113
+ )}
114
+ </a>
115
+ )}
116
+
117
+
118
+ {/* Dropdown */}
119
+ {hasChildren && ((isTop || isRoot) ? openId === (item.id || item.nl_id) : hover) && (
120
+ <div
121
+ style={{
122
+ position: 'absolute',
123
+ top: (isTop || isRoot) ? '100%' : 0,
124
+ left: (isTop || isRoot) ? 0 : '100%',
125
+ background: props.styles.secondary.color.background,
126
+ color: props.styles.secondary.color.text,
127
+ border: `1px solid ${props.styles.secondary.color.separator || 'transparent'}`,
128
+ borderRadius: 8,
129
+ minWidth: 220,
130
+ padding: 6,
131
+ boxShadow: '0 6px 24px rgba(0,0,0,0.12)',
132
+ zIndex: 1000
133
+ }}
134
+ >
135
+ <div style={{ display: 'flex', flexDirection: 'column' }}>
136
+ {item.children!.map((child) => (
137
+ <Item key={child.id || child.nl_id} item={child} depth={depth + 1} />
138
+ ))}
139
+ </div>
140
+ </div>
141
+ )}
142
+ </div>
143
+ )
144
+ }
145
+
146
+ if (!root) {
147
+ return (
148
+ <div style={{ padding: 12, color: '#666' }}>No navigation items</div>
149
+ )
150
+ }
151
+
152
+ return (
153
+ <nav
154
+ style={{
155
+ width: '100%',
156
+ display: 'flex',
157
+ alignItems: 'start',
158
+ paddingTop: '5px',
159
+ paddingLeft:'10px',
160
+ margin: '0px',
161
+ background: props.styles.primary.color.background,
162
+ borderRadius: 8,
163
+ overflow: 'visible',
164
+ height: boxHeight
165
+ }}
166
+ >
167
+ {/* Render root node first */}
168
+ <Item key={root.id || root.nl_id} item={root} depth={0} isRoot={true} />
169
+
170
+
171
+ </nav>
172
+ )
173
+ }
174
+
175
+ export default NavigationComponent
176
+
177
+
178
+