@meridian-ui/meridian 1.0.0

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 (61) hide show
  1. package/README.md +63 -0
  2. package/package.json +52 -0
  3. package/postcss.config.mjs +5 -0
  4. package/rollup.config.js +51 -0
  5. package/src/assets/add-tab.svg +4 -0
  6. package/src/assets/chevron-right.svg +4 -0
  7. package/src/assets/delete-tab.svg +3 -0
  8. package/src/assets/dummy-data/skeleton.json +42 -0
  9. package/src/assets/dummy-data/skeleton.ts +28 -0
  10. package/src/assets/meridian-toggle.svg +4 -0
  11. package/src/components/attributes/attribute-price.tsx +17 -0
  12. package/src/components/detail-views/detail-basic.tsx +121 -0
  13. package/src/components/detail-views/detail-view.scss +187 -0
  14. package/src/components/item-views/item-compact.tsx +72 -0
  15. package/src/components/item-views/item-pin.tsx +131 -0
  16. package/src/components/item-views/item-profile.tsx +140 -0
  17. package/src/components/item-views/item-vertical.tsx +145 -0
  18. package/src/components/item-views/item-view.scss +277 -0
  19. package/src/components/malleability/console/console-setting.tsx +184 -0
  20. package/src/components/malleability/console/console-view.tsx +47 -0
  21. package/src/components/malleability/console/detail-view-component.tsx +262 -0
  22. package/src/components/malleability/console/malleability-component.tsx +104 -0
  23. package/src/components/malleability/console/malleability-console.scss +285 -0
  24. package/src/components/malleability/console/overview-component.tsx +174 -0
  25. package/src/components/malleability/malleability-content-toggle.tsx +32 -0
  26. package/src/components/malleability/malleability-overview-tabs.tsx +212 -0
  27. package/src/components/malleability/malleability-toolbar.tsx +15 -0
  28. package/src/components/malleability/malleability.scss +199 -0
  29. package/src/components/overviews/overivew-basic-table.tsx +127 -0
  30. package/src/components/overviews/overview-basic-grid.tsx +27 -0
  31. package/src/components/overviews/overview-basic-list.tsx +61 -0
  32. package/src/components/overviews/overview-basic-map.tsx +358 -0
  33. package/src/components/overviews/overview-basic.scss +88 -0
  34. package/src/components/ui/dropdown-menu.tsx +61 -0
  35. package/src/helpers/attribute-set.helper.ts +4 -0
  36. package/src/helpers/attribute.helper.ts +334 -0
  37. package/src/helpers/spec.helper.ts +92 -0
  38. package/src/helpers/utils.helper.ts +22 -0
  39. package/src/helpers/view.helper.ts +184 -0
  40. package/src/index.css +149 -0
  41. package/src/index.ts +1 -0
  42. package/src/renderer/attribute.scss +59 -0
  43. package/src/renderer/attribute.tsx +305 -0
  44. package/src/renderer/renderer.data-bind.ts +573 -0
  45. package/src/renderer/renderer.defaults.ts +194 -0
  46. package/src/renderer/renderer.denormalize.ts +273 -0
  47. package/src/renderer/renderer.filter.ts +211 -0
  48. package/src/renderer/renderer.props.ts +21 -0
  49. package/src/renderer/renderer.scss +72 -0
  50. package/src/renderer/renderer.tsx +450 -0
  51. package/src/renderer/wrapper.tsx +225 -0
  52. package/src/spec/spec.internal.ts +76 -0
  53. package/src/spec/spec.ts +195 -0
  54. package/src/store/odi-malleability.store.ts +337 -0
  55. package/src/store/odi-navigation.store.ts +44 -0
  56. package/src/store/odi.store.ts +210 -0
  57. package/tailwind.config.js +31 -0
  58. package/tsconfig.json +24 -0
  59. package/types/svg.d.ts +6 -0
  60. package/vercel.json +5 -0
  61. package/webpack.config.js +18 -0
package/src/index.css ADDED
@@ -0,0 +1,149 @@
1
+ @import "tailwindcss";
2
+
3
+ :root {
4
+ font-optical-sizing: auto;
5
+ font-style: normal;
6
+
7
+ --max-width: 1100px;
8
+ --border-radius: 12px;
9
+ --font-mono: ui-monospace, Menlo, Monaco, 'Cascadia Mono', 'Segoe UI Mono',
10
+ 'Roboto Mono', 'Oxygen Mono', 'Ubuntu Monospace', 'Source Code Pro',
11
+ 'Fira Mono', 'Droid Sans Mono', 'Courier New', monospace;
12
+
13
+ --foreground-rgb: 0, 0, 0;
14
+ --background-start-rgb: 214, 219, 220;
15
+ --background-end-rgb: 255, 255, 255;
16
+
17
+ --primaryPoints-glow: conic-gradient(
18
+ from 180deg at 50% 50%,
19
+ #16abff33 0deg,
20
+ #0885ff33 55deg,
21
+ #54d6ff33 120deg,
22
+ #0071ff33 160deg,
23
+ transparent 360deg
24
+ );
25
+ --secondaryPoints-glow: radial-gradient(
26
+ rgba(255, 255, 255, 1),
27
+ rgba(255, 255, 255, 0)
28
+ );
29
+
30
+ --tile-start-rgb: 239, 245, 249;
31
+ --tile-end-rgb: 228, 232, 233;
32
+ --tile-border: conic-gradient(
33
+ #00000080,
34
+ #00000040,
35
+ #00000030,
36
+ #00000020,
37
+ #00000010,
38
+ #00000010,
39
+ #00000080
40
+ );
41
+
42
+ --callout-rgb: 238, 240, 241;
43
+ --callout-border-rgb: 172, 175, 176;
44
+ --card-rgb: 180, 185, 188;
45
+ --card-border-rgb: 131, 134, 135;
46
+ }
47
+
48
+ /* * {
49
+ box-sizing: border-box;
50
+ padding: 0;
51
+ margin: 0;
52
+ } */
53
+
54
+ html,
55
+ body {
56
+ max-width: 100vw;
57
+ overflow-x: hidden;
58
+ }
59
+
60
+ .gm-style iframe + div {
61
+ border: none !important;
62
+ }
63
+
64
+ h1 {
65
+ font-weight: 700;
66
+ }
67
+
68
+ body {
69
+ color: rgb(var(--foreground-rgb));
70
+ }
71
+
72
+ a {
73
+ color: inherit;
74
+ /* color: red; */
75
+ /* text-decoration: underline; */
76
+ }
77
+
78
+ a:hover {
79
+ color: rgb(0, 64, 255);
80
+ cursor: pointer;
81
+ }
82
+
83
+ input {
84
+ font-style: italic;
85
+ background-color: white;
86
+ }
87
+
88
+ input::placeholder {
89
+ transition: ease;
90
+ }
91
+
92
+ .white-input {
93
+ }
94
+
95
+ .white-input::placeholder {
96
+ font-style: italic;
97
+ color: #9ca3af; /* Tailwind gray: md-gray-400 */
98
+ }
99
+
100
+ hr {
101
+ border: none; /* Remove default border */
102
+ border-top: 1px solid #d1d5db; /* Top border with 1px thickness and gray color */
103
+ margin: 0; /* Optional: Remove margin if needed */
104
+ padding: 0; /* Optional: Remove padding if needed */
105
+ padding-left: 0.5rem;
106
+ padding-right: 0.5rem;
107
+ }
108
+
109
+ /* button {
110
+ background-color: #ececec;
111
+ border-radius: 6px;
112
+ padding: 3px 10px;
113
+ transition: 0.2s ease;
114
+ outline: none;
115
+ }
116
+
117
+ button:hover {
118
+ background-color: #d2d2d2;
119
+ }
120
+
121
+ button:active {
122
+ background-color: #bfbfbf;
123
+ } */
124
+
125
+ @media (prefers-color-scheme: dark) {
126
+ html {
127
+ color-scheme: dark;
128
+ }
129
+ }
130
+
131
+ .loader {
132
+ border: 2px solid transparent; /* Light grey */
133
+ border-top: 2px solid #6b7280; /* Blue */
134
+ border-left: 2px solid #6b7280; /* Blue */
135
+ border-right: 2px solid #6b7280; /* Blue */
136
+ border-radius: 50%;
137
+ width: 12px;
138
+ height: 12px;
139
+ animation: spin 2s linear infinite;
140
+ }
141
+
142
+ @keyframes spin {
143
+ 0% {
144
+ transform: rotate(0deg);
145
+ }
146
+ 100% {
147
+ transform: rotate(360deg);
148
+ }
149
+ }
package/src/index.ts ADDED
@@ -0,0 +1 @@
1
+ import 'index.css'
@@ -0,0 +1,59 @@
1
+ .attribute {
2
+ // display: flex;
3
+ // flex-direction: column;
4
+ // border: 1px solid red;
5
+ // // flex-direction: row;
6
+ // // flex-wrap: wrap;
7
+ // gap: 8px;
8
+
9
+ img {
10
+ width: 100%;
11
+ height: 100%;
12
+ object-fit: cover;
13
+ border-radius: 8px;
14
+ }
15
+ }
16
+
17
+ .attribute-item {
18
+ display: flex;
19
+ }
20
+ .attribute-label {
21
+ font-weight: 300;
22
+ }
23
+
24
+ .attribute-render {
25
+ // flex: 1;
26
+ z-index: 0;
27
+ }
28
+
29
+ .attribute-list {
30
+ display: flex;
31
+ flex-wrap: wrap;
32
+ gap: 8px;
33
+ width: 100%;
34
+ }
35
+
36
+ .highlight-attributes {
37
+ background: #00000020;
38
+ border-radius: 2px;
39
+ opacity: 0.6;
40
+ }
41
+
42
+ .highlight-attributes:hover {
43
+ background: #00000030;
44
+ opacity: 0.8;
45
+ }
46
+
47
+ .highlight-attributes:active {
48
+ background: #00000050;
49
+ opacity: 1;
50
+ }
51
+
52
+ .attribute-selected {
53
+ outline: 2px solid #446f49b0;
54
+ /* outline-offset: 2px; */
55
+ background: #446f4950;
56
+ /* background: none; */
57
+ opacity: 1;
58
+ /* background: red; */
59
+ }
@@ -0,0 +1,305 @@
1
+ import './attribute.scss';
2
+ import { CSSProperties, ReactElement } from 'react';
3
+ import { useODI } from '../store/odi.store';
4
+ import React from 'react';
5
+ import { attributeInScope } from '../helpers/attribute.helper';
6
+ import { getFirstDetail, getFirstOverview } from '../renderer/renderer.filter';
7
+ import {
8
+ FetchedAttributeType,
9
+ FetchedAttributeGroupType,
10
+ FetchedODI,
11
+ ViewOptions,
12
+ } from '../spec/spec.internal';
13
+ import { isAttributeType } from '../helpers/spec.helper';
14
+ import { attributeTypesMap } from './renderer.defaults';
15
+ import { DetailView } from '../spec/spec';
16
+ import { findDetailViewToOpen } from '../helpers/view.helper';
17
+ import { MeridianOverview } from './renderer';
18
+
19
+ // export const AttributeOver
20
+
21
+ export const Attribute = ({
22
+ attribute,
23
+ children,
24
+ options,
25
+ // itemIndex,
26
+ onAction,
27
+ showLabel,
28
+ className,
29
+ style,
30
+ }: {
31
+ attribute: FetchedAttributeType | FetchedAttributeType[] | undefined;
32
+ children?: ReactElement;
33
+ showLabel?: boolean;
34
+ options: ViewOptions;
35
+ // itemIndex: number;
36
+ onAction?: React.MouseEventHandler<HTMLButtonElement>;
37
+ className?: string;
38
+ style?: CSSProperties;
39
+ }) => {
40
+ const {
41
+ odi,
42
+ selectedItemEntity,
43
+ setSelectedItemEntity,
44
+ highlightAttributes,
45
+ toggleSelectedAttribute,
46
+ attributeIsSelected,
47
+ setLastSelected,
48
+ } = useODI();
49
+
50
+ const viewId =
51
+ (options.viewType === 'overview'
52
+ ? options.overview.id ?? (odi ? getFirstOverview(odi).id : '')
53
+ : selectedItemEntity?.detail.id ?? (odi ? getFirstDetail(odi).id : '')) ??
54
+ '';
55
+
56
+ if (!attribute) return <></>;
57
+
58
+ // const classNameString = `${children.className} ${className}`;
59
+ const classNameString = `${className}`; //${attribute?.className}`;
60
+ const styleObject = { ...style }; //...attribute?.style };
61
+
62
+ const AttributeItem = ({
63
+ attribute,
64
+ children,
65
+ }: {
66
+ attribute: FetchedAttributeType;
67
+ children?: ReactElement;
68
+ }) => {
69
+ if (!attribute) return <></>;
70
+
71
+ if (children) {
72
+ return children;
73
+ }
74
+
75
+ // console.log(
76
+ // 'attribute',
77
+ // attribute.type,
78
+ // attribute.type && attributeTypesMap[attribute.type]
79
+ // );
80
+
81
+ // Check if the attribute type has a custom renderer in attributeTypesMap
82
+ if (attribute.type && attributeTypesMap[attribute.type]) {
83
+ const AttributeComponent = attributeTypesMap[attribute.type].view;
84
+ return (
85
+ <AttributeComponent
86
+ attribute={attribute}
87
+ options={options}
88
+ item={options.items[attribute.itemIndex ?? 0]}
89
+ />
90
+ );
91
+ }
92
+
93
+ // If the attribute is an overview, return the overview component
94
+ if (attribute.type === 'overview') {
95
+ // console.log('overview', attribute);
96
+ return (
97
+ <MeridianOverview
98
+ overviewIdToShow={attribute.id}
99
+ attribute={attribute as FetchedAttributeGroupType}
100
+ />
101
+ );
102
+ }
103
+
104
+ // Default fallback types
105
+ if (!isAttributeType(attribute)) {
106
+ return (
107
+ <div
108
+ // ${attribute?.direction === 'row' ? 'flex-row flex-wrap' : 'flex-col'}
109
+ className={`attribute ${classNameString}`}
110
+ // style={attribute?.style}
111
+ >
112
+ {attribute.attributes
113
+ .filter(
114
+ (a) =>
115
+ a &&
116
+ ((isAttributeType(a) && a.value) ||
117
+ (!isAttributeType(a) && a.attributes))
118
+ )
119
+ .map((attributeSet, index) => (
120
+ <Attribute
121
+ className={classNameString}
122
+ // style={attributeSet?.style}
123
+ key={index}
124
+ options={options}
125
+ attribute={attributeSet}
126
+ >
127
+ {children}
128
+ </Attribute>
129
+ ))}
130
+ </div>
131
+ );
132
+ } else if (
133
+ attribute.type === 'element' ||
134
+ React.isValidElement(attribute.value)
135
+ ) {
136
+ return (
137
+ <div className={classNameString} style={styleObject}>
138
+ {attribute.value as ReactElement}
139
+ </div>
140
+ );
141
+ } else if (attribute.type === 'image') {
142
+ return (
143
+ <div
144
+ className={`attribute ${classNameString}`}
145
+ style={{
146
+ ...styleObject,
147
+ overflow: 'hidden',
148
+ width: options.overview.type === 'table' ? '200px' : 'auto',
149
+ padding: options.overview.type === 'table' ? '6px' : '0px',
150
+ }}
151
+ >
152
+ <img src={attribute.value?.toString()} />
153
+ </div>
154
+ );
155
+ } else if (attribute.type === 'link') {
156
+ return (
157
+ <a
158
+ className={classNameString}
159
+ style={styleObject}
160
+ href={attribute.value?.toString()}
161
+ >
162
+ {attribute.label ?? attribute.value?.toString()}
163
+ </a>
164
+ );
165
+ } else if (attribute.type === 'button') {
166
+ return (
167
+ <button
168
+ className={classNameString}
169
+ style={styleObject}
170
+ onClick={onAction}
171
+ >
172
+ {attribute.value?.toString()}
173
+ </button>
174
+ );
175
+ } else {
176
+ return (
177
+ <div className={`${classNameString}`} style={styleObject}>
178
+ {/* {attribute.value?.toString()}: {attribute.id} */}
179
+ {/* {showLabel ? (
180
+ <>
181
+ <div className="attribute-label">{attribute.label}</div>
182
+ <div className="attribute-value">{attribute.value?.toString()}</div>
183
+ </>
184
+ ) : (
185
+ <div className="attribute-value">{attribute.value?.toString()}</div>
186
+ )} */}
187
+ {/* {classNameString} */}
188
+ {attribute.value?.toString()}
189
+ </div>
190
+ );
191
+ }
192
+ };
193
+
194
+ const RenderAttribute = ({
195
+ attribute,
196
+ children,
197
+ }: {
198
+ attribute: FetchedAttributeType;
199
+ children?: ReactElement;
200
+ }) => {
201
+ if (!attribute) return <></>;
202
+
203
+ const detailToOpen = findDetailViewToOpen(options, odi, attribute);
204
+
205
+ // console.log('detailToOpen', detailToOpen);
206
+
207
+ const toHighlight =
208
+ highlightAttributes &&
209
+ isAttributeType(attribute) &&
210
+ attribute.type !== 'overview';
211
+
212
+ return (
213
+ <div
214
+ key={`${attribute.itemIndex}-${attribute.index}-${attribute.id}-render`}
215
+ className={`attribute-render ${
216
+ attributeIsSelected(attribute) ? 'attribute-selected' : ''
217
+ } ${toHighlight ? 'highlight-attributes' : ''}`}
218
+ style={{
219
+ cursor: detailToOpen || toHighlight ? 'pointer' : 'auto',
220
+ transition: 'opacity ease 0.15s, background ease 0.15s',
221
+ }}
222
+ onClick={(e) => {
223
+ if (toHighlight) {
224
+ e.preventDefault();
225
+ e.stopPropagation();
226
+
227
+ // console.log('aa', attribute);
228
+ toggleSelectedAttribute(attribute);
229
+ setLastSelected(
230
+ e.clientX + 20,
231
+ e.clientY + 20,
232
+ options.viewType,
233
+ viewId
234
+ );
235
+ } else if (detailToOpen) {
236
+ const generalItem = options.items.at(attribute.itemIndex ?? 0);
237
+ if (generalItem && !('value' in generalItem)) {
238
+ e.stopPropagation();
239
+ // console.log('test', detailToOpen, options, attribute.itemIndex);
240
+ setSelectedItemEntity(
241
+ detailToOpen,
242
+ generalItem.overviewIndex ?? 0,
243
+ generalItem.itemId,
244
+ {
245
+ ...options,
246
+ viewType: 'detail',
247
+ overview: {
248
+ ...options.overview,
249
+ detailViews: options.overview.detailViews,
250
+ },
251
+ },
252
+ { x: e.clientX, y: e.clientY }
253
+ );
254
+ }
255
+ if (detailToOpen.openIn === 'new-page') {
256
+ e.stopPropagation();
257
+ // If open in new page, run callback function to route.
258
+ options.onOpenDetailNewPage(
259
+ options.items[attribute.itemIndex ?? 0]
260
+ );
261
+ }
262
+ }
263
+ }}
264
+ >
265
+ {/* {overviewOptions.items.at(0)?.index} */}
266
+ {showLabel &&
267
+ isAttributeType(attribute) &&
268
+ attribute.value !== undefined &&
269
+ attribute.value !== null ? (
270
+ <span
271
+ className={`attribute-item ${classNameString}`}
272
+ style={{
273
+ ...styleObject,
274
+ fontWeight: '300',
275
+ }}
276
+ >
277
+ {attribute.label}:&nbsp;
278
+ <AttributeItem attribute={attribute} children={children} />
279
+ </span>
280
+ ) : (
281
+ <AttributeItem attribute={attribute} children={children} />
282
+ )}
283
+ </div>
284
+ );
285
+ };
286
+
287
+ if (Array.isArray(attribute) && attribute.length > 0) {
288
+ return attribute.map((attr, idx) => {
289
+ return (
290
+ <RenderAttribute
291
+ key={`${attr?.itemIndex}-${attr?.index}-${attr?.id}-${idx}`}
292
+ attribute={attr as FetchedAttributeType}
293
+ >
294
+ {children}
295
+ </RenderAttribute>
296
+ );
297
+ });
298
+ } else {
299
+ return (
300
+ <RenderAttribute attribute={attribute as FetchedAttributeType}>
301
+ {children}
302
+ </RenderAttribute>
303
+ );
304
+ }
305
+ };