@startinblox/boilerplate 3.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.
- package/.gitlab-ci.yml +57 -0
- package/.storybook/main.ts +15 -0
- package/.storybook/preview-head.html +8 -0
- package/.storybook/preview.ts +22 -0
- package/LICENSE +21 -0
- package/README.md +85 -0
- package/biome.json +39 -0
- package/cypress/component/solid-boilerplate.cy.ts +9 -0
- package/cypress/cypress.d.ts +1 -0
- package/cypress/support/component-index.html +12 -0
- package/cypress/support/component.ts +17 -0
- package/cypress.config.ts +11 -0
- package/dist/boilerplate.css +1 -0
- package/dist/index.js +1213 -0
- package/lit-localize.json +15 -0
- package/locales/en.xlf +13 -0
- package/package.json +92 -0
- package/postcss.config.js +8 -0
- package/src/component.d.ts +161 -0
- package/src/components/solid-boilerplate.ts +79 -0
- package/src/components/ui/sample-object.ts +37 -0
- package/src/components/ui/sample-objects.ts +40 -0
- package/src/context.json +1 -0
- package/src/helpers/components/componentObjectHandler.ts +100 -0
- package/src/helpers/components/componentObjectsHandler.ts +44 -0
- package/src/helpers/components/orbitComponent.ts +241 -0
- package/src/helpers/components/setupCacheInvalidation.ts +37 -0
- package/src/helpers/components/setupCacheOnResourceReady.ts +32 -0
- package/src/helpers/components/setupComponentSubscriptions.ts +73 -0
- package/src/helpers/components/setupOnSaveReset.ts +20 -0
- package/src/helpers/datas/dataBuilder.ts +43 -0
- package/src/helpers/datas/filterGenerator.ts +29 -0
- package/src/helpers/datas/filterObjectByDateAfter.ts +80 -0
- package/src/helpers/datas/filterObjectById.ts +54 -0
- package/src/helpers/datas/filterObjectByInterval.ts +133 -0
- package/src/helpers/datas/filterObjectByNamedValue.ts +103 -0
- package/src/helpers/datas/filterObjectByType.ts +30 -0
- package/src/helpers/datas/filterObjectByValue.ts +81 -0
- package/src/helpers/datas/sort.ts +40 -0
- package/src/helpers/i18n/configureLocalization.ts +17 -0
- package/src/helpers/index.ts +41 -0
- package/src/helpers/ui/formatDate.ts +18 -0
- package/src/helpers/ui/lipsum.ts +12 -0
- package/src/helpers/utils/requestNavigation.ts +12 -0
- package/src/helpers/utils/uniq.ts +6 -0
- package/src/index.ts +7 -0
- package/src/initializer.ts +11 -0
- package/src/mocks/orbit.mock.ts +33 -0
- package/src/mocks/user.mock.ts +67 -0
- package/src/styles/component-sample.scss +4 -0
- package/src/styles/index.scss +16 -0
- package/stories/sample-objects.stories.ts +47 -0
- package/tsconfig.json +36 -0
- package/vite.config.ts +44 -0
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import type { Resource } from "@src/component";
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
function isValidDateValue(value: unknown): value is string | number | Date {
|
|
5
|
+
if (
|
|
6
|
+
typeof value !== "string" &&
|
|
7
|
+
typeof value !== "number" &&
|
|
8
|
+
!(value instanceof Date)
|
|
9
|
+
) {
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
return !Number.isNaN(new Date(value).getTime());
|
|
14
|
+
}
|
|
15
|
+
const checkValueInIntervalRecursive = (
|
|
16
|
+
data: any,
|
|
17
|
+
propName: string,
|
|
18
|
+
startValue: number | Date,
|
|
19
|
+
endValue: number | Date
|
|
20
|
+
): boolean => {
|
|
21
|
+
if (data === null || data === undefined) {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const propPath = propName.split(".");
|
|
26
|
+
let current = data;
|
|
27
|
+
|
|
28
|
+
for (const segment of propPath) {
|
|
29
|
+
if (current && typeof current === "object" && segment in current) {
|
|
30
|
+
current = current[segment];
|
|
31
|
+
} else {
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (typeof current === "number") {
|
|
37
|
+
if (typeof startValue === "number" && typeof endValue === "number") {
|
|
38
|
+
if (startValue <= current && current <= endValue) {
|
|
39
|
+
return true;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
} else if (isValidDateValue(current)) {
|
|
43
|
+
const date = new Date(current);
|
|
44
|
+
if (startValue instanceof Date && endValue instanceof Date) {
|
|
45
|
+
if (startValue <= date && date <= endValue) {
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
} else {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (Array.isArray(data)) {
|
|
54
|
+
return data.some((item) =>
|
|
55
|
+
checkValueInIntervalRecursive(item, propName, startValue, endValue)
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (typeof data === "object") {
|
|
60
|
+
return Object.entries(data).some(([key, value]) =>
|
|
61
|
+
checkValueInIntervalRecursive(value, propName, startValue, endValue)
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return false;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Filters an array of Resource objects based on whether a specific date/number property
|
|
70
|
+
* falls within a given interval string (e.g., "2023-01-01/2023-01-31" or "3/6").
|
|
71
|
+
* Checks the property recursively within nested objects and arrays.
|
|
72
|
+
*/
|
|
73
|
+
const filterObjectByDateInterval = (
|
|
74
|
+
array: Resource[],
|
|
75
|
+
propName: string,
|
|
76
|
+
interval: string
|
|
77
|
+
): Resource[] => {
|
|
78
|
+
if (!propName || !interval || typeof interval !== "string") {
|
|
79
|
+
return array;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const [startStr, endStr] = interval.split("/");
|
|
83
|
+
if (!startStr) {
|
|
84
|
+
return array;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const startDate = new Date(startStr);
|
|
88
|
+
|
|
89
|
+
const endDate = new Date(endStr ?? startStr);
|
|
90
|
+
|
|
91
|
+
if (Number.isNaN(startDate.getTime()) || Number.isNaN(endDate.getTime())) {
|
|
92
|
+
console.warn(`Invalid date interval provided: ${interval}`);
|
|
93
|
+
return array;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
endDate.setHours(23, 59, 59, 999);
|
|
97
|
+
|
|
98
|
+
if (startDate > endDate) {
|
|
99
|
+
console.warn(`Start date is after end date in interval: ${interval}`);
|
|
100
|
+
return array;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return array.filter((obj) =>
|
|
104
|
+
checkValueInIntervalRecursive(obj, propName, startDate, endDate)
|
|
105
|
+
);
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
const filterObjectByInterval = (
|
|
109
|
+
array: Resource[],
|
|
110
|
+
propName: string,
|
|
111
|
+
interval: string
|
|
112
|
+
): Resource[] => {
|
|
113
|
+
if (!propName || !interval || typeof interval !== "string") {
|
|
114
|
+
return array;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const [startStr, endStr] = interval.split("/").map(Number);
|
|
118
|
+
|
|
119
|
+
if (Number.isNaN(startStr) || Number.isNaN(endStr)) {
|
|
120
|
+
return array;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (startStr > endStr) {
|
|
124
|
+
console.warn(`Start number is after end number in interval: ${interval}`);
|
|
125
|
+
return array;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return array.filter((obj) =>
|
|
129
|
+
checkValueInIntervalRecursive(obj, propName, startStr, endStr)
|
|
130
|
+
);
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
export default filterObjectByInterval;
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import type { Resource } from "@src/component";
|
|
2
|
+
|
|
3
|
+
const calculatePertinenceScoreRecursive = (
|
|
4
|
+
data: any,
|
|
5
|
+
lowerCaseString: string,
|
|
6
|
+
isTargetProperty: boolean
|
|
7
|
+
): number => {
|
|
8
|
+
if (data === null || data === undefined) {
|
|
9
|
+
return 0;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
if (typeof data !== "object") {
|
|
13
|
+
if (!isTargetProperty) {
|
|
14
|
+
return 0;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const valueString = String(data).toLowerCase();
|
|
18
|
+
|
|
19
|
+
const escapedString = lowerCaseString.replace(
|
|
20
|
+
/[.*+?^${}()|[\]\\]/g,
|
|
21
|
+
"\\$&"
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
const wholeWordRegex = new RegExp(`\\b${escapedString}\\b`);
|
|
25
|
+
|
|
26
|
+
let score = 0;
|
|
27
|
+
if (wholeWordRegex.test(valueString)) {
|
|
28
|
+
score = 2;
|
|
29
|
+
} else if (valueString.includes(lowerCaseString)) {
|
|
30
|
+
score = 1;
|
|
31
|
+
}
|
|
32
|
+
return score;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (Array.isArray(data)) {
|
|
36
|
+
let maxScore = 0;
|
|
37
|
+
for (const item of data) {
|
|
38
|
+
maxScore = Math.max(
|
|
39
|
+
maxScore,
|
|
40
|
+
calculatePertinenceScoreRecursive(
|
|
41
|
+
item,
|
|
42
|
+
lowerCaseString,
|
|
43
|
+
isTargetProperty
|
|
44
|
+
)
|
|
45
|
+
);
|
|
46
|
+
if (maxScore === 2) break;
|
|
47
|
+
}
|
|
48
|
+
return maxScore;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
let maxScore = 0;
|
|
52
|
+
for (const value of Object.values(data)) {
|
|
53
|
+
maxScore = Math.max(
|
|
54
|
+
maxScore,
|
|
55
|
+
calculatePertinenceScoreRecursive(
|
|
56
|
+
value,
|
|
57
|
+
lowerCaseString,
|
|
58
|
+
isTargetProperty
|
|
59
|
+
)
|
|
60
|
+
);
|
|
61
|
+
if (maxScore === 2) break;
|
|
62
|
+
}
|
|
63
|
+
return maxScore;
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
const filterObjectByNamedValue = (
|
|
67
|
+
array: Resource[],
|
|
68
|
+
propName: string,
|
|
69
|
+
searchString: string
|
|
70
|
+
): Resource[] => {
|
|
71
|
+
if (!propName || !searchString || searchString.trim() === "") {
|
|
72
|
+
return array;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const lowerCaseString = searchString.toLowerCase();
|
|
76
|
+
|
|
77
|
+
const scoredObjects = array.map((obj) => {
|
|
78
|
+
let current: any = obj;
|
|
79
|
+
const propPath = propName.split(".");
|
|
80
|
+
for (const segment of propPath) {
|
|
81
|
+
if (current && typeof current === "object" && segment in current) {
|
|
82
|
+
current = current[segment];
|
|
83
|
+
} else {
|
|
84
|
+
current = null;
|
|
85
|
+
break;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
let score = 0;
|
|
90
|
+
if (current) {
|
|
91
|
+
score = calculatePertinenceScoreRecursive(current, lowerCaseString, true);
|
|
92
|
+
}
|
|
93
|
+
return { obj, score };
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
const filteredObjects = scoredObjects.filter((item) => item.score > 0);
|
|
97
|
+
|
|
98
|
+
filteredObjects.sort((a, b) => b.score - a.score);
|
|
99
|
+
|
|
100
|
+
return filteredObjects.map((item) => item.obj);
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
export default filterObjectByNamedValue;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { Resource } from "@src/component";
|
|
2
|
+
|
|
3
|
+
const filterObjectByType = (
|
|
4
|
+
array: Resource[],
|
|
5
|
+
targetType: string
|
|
6
|
+
): Resource[] => {
|
|
7
|
+
if (!targetType) {
|
|
8
|
+
return array;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
return array.filter((obj) => {
|
|
12
|
+
const type = obj["@type"];
|
|
13
|
+
|
|
14
|
+
if (!type) {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
if (typeof type === "string") {
|
|
19
|
+
return type === targetType;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (Array.isArray(type)) {
|
|
23
|
+
return type.some((t) => t === targetType);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return false;
|
|
27
|
+
});
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export default filterObjectByType;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import type { Resource } from "@src/component";
|
|
2
|
+
|
|
3
|
+
const calculatePertinenceScore = (
|
|
4
|
+
data: any,
|
|
5
|
+
lowerCaseString: string,
|
|
6
|
+
key?: string
|
|
7
|
+
): number => {
|
|
8
|
+
if (data === null || data === undefined) {
|
|
9
|
+
return 0;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
if (typeof data !== "object") {
|
|
13
|
+
const valueString = String(data).toLowerCase();
|
|
14
|
+
|
|
15
|
+
const escapedString = lowerCaseString.replace(
|
|
16
|
+
/[.*+?^${}()|[\]\\]/g,
|
|
17
|
+
"\\$&"
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
const wholeWordRegex = new RegExp(`\\b${escapedString}\\b`);
|
|
21
|
+
|
|
22
|
+
let score = 0;
|
|
23
|
+
if (wholeWordRegex.test(valueString)) {
|
|
24
|
+
if (key === "name" || key === "title") {
|
|
25
|
+
score = 4;
|
|
26
|
+
} else {
|
|
27
|
+
score = 3;
|
|
28
|
+
}
|
|
29
|
+
} else if (valueString.includes(lowerCaseString)) {
|
|
30
|
+
if (key === "name" || key === "title") {
|
|
31
|
+
score = 2;
|
|
32
|
+
} else {
|
|
33
|
+
score = 1;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return score;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (Array.isArray(data)) {
|
|
40
|
+
let maxScore = 0;
|
|
41
|
+
for (const item of data) {
|
|
42
|
+
maxScore = Math.max(
|
|
43
|
+
maxScore,
|
|
44
|
+
calculatePertinenceScore(item, lowerCaseString)
|
|
45
|
+
);
|
|
46
|
+
if (maxScore === 4) break;
|
|
47
|
+
}
|
|
48
|
+
return maxScore;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
let maxScore = 0;
|
|
52
|
+
for (const [currentKey, value] of Object.entries(data)) {
|
|
53
|
+
maxScore = Math.max(
|
|
54
|
+
maxScore,
|
|
55
|
+
calculatePertinenceScore(value, lowerCaseString, currentKey)
|
|
56
|
+
);
|
|
57
|
+
if (maxScore === 4) break;
|
|
58
|
+
}
|
|
59
|
+
return maxScore;
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
const filterObjectByValue = (array: Resource[], searchString: string): any[] => {
|
|
63
|
+
if (!searchString || searchString.trim() === "") {
|
|
64
|
+
return array;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const lowerCaseString = searchString.toLowerCase();
|
|
68
|
+
|
|
69
|
+
const scoredObjects = array.map((obj) => ({
|
|
70
|
+
obj,
|
|
71
|
+
score: calculatePertinenceScore(obj, lowerCaseString),
|
|
72
|
+
}));
|
|
73
|
+
|
|
74
|
+
const filteredObjects = scoredObjects.filter((item) => item.score > 0);
|
|
75
|
+
|
|
76
|
+
filteredObjects.sort((a, b) => b.score - a.score);
|
|
77
|
+
|
|
78
|
+
return filteredObjects.map((item) => item.obj);
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
export default filterObjectByValue;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
const getValueFromAnyKey = (obj: any, keys: string[]): any => {
|
|
2
|
+
let value = obj;
|
|
3
|
+
for (let i = 0; i < keys.length; i++) {
|
|
4
|
+
if (value && keys[i] in value) {
|
|
5
|
+
value = value[keys[i]];
|
|
6
|
+
} else {
|
|
7
|
+
break;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
return value;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
type Sort = (arr: any[], k: string | string[], order?: "asc" | "desc") => any[];
|
|
14
|
+
|
|
15
|
+
const sort: Sort = (arr, k, order = "asc") => {
|
|
16
|
+
return arr.sort((a, b) => {
|
|
17
|
+
let aN = a;
|
|
18
|
+
let bN = b;
|
|
19
|
+
if (Array.isArray(k)) {
|
|
20
|
+
aN = getValueFromAnyKey(a, k);
|
|
21
|
+
bN = getValueFromAnyKey(b, k);
|
|
22
|
+
} else {
|
|
23
|
+
aN = a[k];
|
|
24
|
+
bN = b[k];
|
|
25
|
+
}
|
|
26
|
+
let c = 0;
|
|
27
|
+
if (typeof aN === "number" && typeof bN === "number") {
|
|
28
|
+
c = aN - bN;
|
|
29
|
+
} else if (typeof aN === "string" && typeof bN === "string") {
|
|
30
|
+
c = aN.localeCompare(bN);
|
|
31
|
+
} else if (aN instanceof Date && bN instanceof Date) {
|
|
32
|
+
c = aN.getTime() - bN.getTime();
|
|
33
|
+
} else {
|
|
34
|
+
throw new TypeError(`Unsupported data type for key "${k}"`);
|
|
35
|
+
}
|
|
36
|
+
return order === "asc" ? c : -c;
|
|
37
|
+
});
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export default sort;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { configureLocalization } from "@lit/localize";
|
|
2
|
+
import { sourceLocale, targetLocales } from "@src/generated/locale-codes.js";
|
|
3
|
+
|
|
4
|
+
const langs = import.meta.glob("../generated/locales/**/*.ts", { eager: true });
|
|
5
|
+
|
|
6
|
+
const localizedTemplates: Map<string, any> = new Map(
|
|
7
|
+
targetLocales.map((locale) => [
|
|
8
|
+
locale,
|
|
9
|
+
langs[`../generated/locales/${locale}.ts`],
|
|
10
|
+
]),
|
|
11
|
+
);
|
|
12
|
+
|
|
13
|
+
export const { getLocale, setLocale } = configureLocalization({
|
|
14
|
+
sourceLocale,
|
|
15
|
+
targetLocales,
|
|
16
|
+
loadLocale: async (locale) => localizedTemplates.get(locale),
|
|
17
|
+
});
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import OrbitComponent from "@helpers/components/orbitComponent";
|
|
2
|
+
import setupCacheInvalidation from "@helpers/components/setupCacheInvalidation";
|
|
3
|
+
import setupCacheOnResourceReady from "@helpers/components/setupCacheOnResourceReady";
|
|
4
|
+
import setupComponentSubscriptions from "@helpers/components/setupComponentSubscriptions";
|
|
5
|
+
import setupOnSaveReset from "@helpers/components/setupOnSaveReset";
|
|
6
|
+
import { ComponentObjectHandler } from "@helpers/components/componentObjectHandler";
|
|
7
|
+
import { ComponentObjectsHandler } from "@helpers/components/componentObjectsHandler";
|
|
8
|
+
import filterGenerator from "@helpers/datas/filterGenerator";
|
|
9
|
+
import filterObjectByDateAfter from "@helpers/datas/filterObjectByDateAfter";
|
|
10
|
+
import filterObjectById from "@helpers/datas/filterObjectById";
|
|
11
|
+
import filterObjectByInterval from "@helpers/datas/filterObjectByInterval";
|
|
12
|
+
import filterObjectByNamedValue from "@helpers/datas/filterObjectByNamedValue";
|
|
13
|
+
import filterObjectByValue from "@helpers/datas/filterObjectByValue";
|
|
14
|
+
import filterObjectByType from "@helpers/datas/filterObjectByType";
|
|
15
|
+
import formatDate from "@helpers/ui/formatDate";
|
|
16
|
+
import sort from "@helpers/datas/sort";
|
|
17
|
+
import requestNavigation from "@helpers/utils/requestNavigation";
|
|
18
|
+
import uniq from "@helpers/utils/uniq";
|
|
19
|
+
import CLIENT_CONTEXT from "@src/context.json";
|
|
20
|
+
|
|
21
|
+
export {
|
|
22
|
+
CLIENT_CONTEXT,
|
|
23
|
+
filterGenerator,
|
|
24
|
+
filterObjectByDateAfter,
|
|
25
|
+
filterObjectById,
|
|
26
|
+
filterObjectByInterval,
|
|
27
|
+
filterObjectByNamedValue,
|
|
28
|
+
filterObjectByValue,
|
|
29
|
+
filterObjectByType,
|
|
30
|
+
formatDate,
|
|
31
|
+
ComponentObjectHandler,
|
|
32
|
+
ComponentObjectsHandler,
|
|
33
|
+
OrbitComponent,
|
|
34
|
+
requestNavigation,
|
|
35
|
+
setupCacheInvalidation,
|
|
36
|
+
setupCacheOnResourceReady,
|
|
37
|
+
setupComponentSubscriptions,
|
|
38
|
+
setupOnSaveReset,
|
|
39
|
+
sort,
|
|
40
|
+
uniq,
|
|
41
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
const formatDate = (
|
|
2
|
+
originalDate: string | Date | undefined,
|
|
3
|
+
format: Intl.DateTimeFormatOptions = {
|
|
4
|
+
day: "2-digit",
|
|
5
|
+
month: "2-digit",
|
|
6
|
+
year: "2-digit",
|
|
7
|
+
}
|
|
8
|
+
): string => {
|
|
9
|
+
if (!originalDate) return "";
|
|
10
|
+
const date =
|
|
11
|
+
typeof originalDate === "string" ? new Date(originalDate) : originalDate;
|
|
12
|
+
const formattedDate = date.toLocaleString(undefined, format);
|
|
13
|
+
if (typeof originalDate === "string" && formattedDate === "Invalid Date")
|
|
14
|
+
return originalDate;
|
|
15
|
+
return formattedDate;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export default formatDate;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
const requestNavigation = (route: string, resource: string | boolean = false) => {
|
|
2
|
+
window.dispatchEvent(
|
|
3
|
+
new CustomEvent("requestNavigation", {
|
|
4
|
+
detail: {
|
|
5
|
+
route: route,
|
|
6
|
+
resource: typeof resource === "string" ? { "@id": resource } : resource,
|
|
7
|
+
},
|
|
8
|
+
}),
|
|
9
|
+
);
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export default requestNavigation;
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { getLocale, setLocale } from "@helpers/i18n/configureLocalization";
|
|
2
|
+
import "@styles/index.scss";
|
|
3
|
+
import.meta.glob("./components/**/*.ts", { eager: true });
|
|
4
|
+
import.meta.glob("./components/**/*.js", { eager: true });
|
|
5
|
+
|
|
6
|
+
window.getLocale = window.getLocale ? window.getLocale.push(getLocale) : [getLocale];
|
|
7
|
+
window.setLocale = window.setLocale ? window.setLocale.push(setLocale) : [setLocale];
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { LiveOrbit } from "@src/component";
|
|
2
|
+
|
|
3
|
+
export const orbit: LiveOrbit = {
|
|
4
|
+
client: {
|
|
5
|
+
name: "Orbit",
|
|
6
|
+
logo: "https://cdn.startinblox.com/logos/ACME.svg",
|
|
7
|
+
},
|
|
8
|
+
components: [],
|
|
9
|
+
getRoute: (route: string) => route,
|
|
10
|
+
getDefaultRoute: () => "",
|
|
11
|
+
getComponent: () => undefined,
|
|
12
|
+
getComponentFromRoute: () => undefined,
|
|
13
|
+
Swal: () => {},
|
|
14
|
+
defaultRoute: "",
|
|
15
|
+
federations: {},
|
|
16
|
+
componentSet: new Set(["routing", "menu", "menu-top", "autoLogin"]),
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
window.orbit = orbit;
|
|
20
|
+
|
|
21
|
+
export const sibStore = {
|
|
22
|
+
getData: (id: any, _context: any) => {
|
|
23
|
+
return id;
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
window.sibStore = sibStore;
|
|
28
|
+
|
|
29
|
+
export const sibRouter = {
|
|
30
|
+
currentResource: "",
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
window.sibRouter = sibRouter;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { dataBuilder } from "@helpers/datas/dataBuilder";
|
|
2
|
+
import { lorem } from "@helpers/ui/lipsum";
|
|
3
|
+
import type { User } from "@src/component";
|
|
4
|
+
|
|
5
|
+
export const user: User = {
|
|
6
|
+
"@id": "_:b1",
|
|
7
|
+
first_name: "John",
|
|
8
|
+
last_name: "Doe",
|
|
9
|
+
username: "johndoe42",
|
|
10
|
+
email: "john@doe.com",
|
|
11
|
+
account: {
|
|
12
|
+
"@id": "_:b2",
|
|
13
|
+
picture: "https://placehold.co/30x30",
|
|
14
|
+
user: {
|
|
15
|
+
"@id": "_b:1",
|
|
16
|
+
"@type": "foaf:user",
|
|
17
|
+
"@context": { get_full_name: "rdfs:label" },
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
name: "John Doe",
|
|
21
|
+
inbox: { "@id": "_:b3" },
|
|
22
|
+
"@type": "foaf:user",
|
|
23
|
+
"@context": [
|
|
24
|
+
"https://cdn.startinblox.com/owl/context.jsonld",
|
|
25
|
+
{ get_full_name: "rdfs:label" },
|
|
26
|
+
],
|
|
27
|
+
permissions: ["view", "add", "control", "delete", "change"],
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export const userWithoutPicture = dataBuilder(user, ["account.picture"]);
|
|
31
|
+
|
|
32
|
+
export const userWithoutEmail = dataBuilder(user, ["email"]);
|
|
33
|
+
|
|
34
|
+
export const minimalUser = dataBuilder(user, [
|
|
35
|
+
"first_name",
|
|
36
|
+
"last_name",
|
|
37
|
+
"email",
|
|
38
|
+
"account.picture",
|
|
39
|
+
"name",
|
|
40
|
+
]);
|
|
41
|
+
|
|
42
|
+
export const get_random_user = (): User => {
|
|
43
|
+
const removables: string[] = [];
|
|
44
|
+
const replacements: User = {
|
|
45
|
+
"@id": `store://local.sample-object/${Math.floor(Math.random() * 1000)}/`,
|
|
46
|
+
first_name: lorem.generateWords(1),
|
|
47
|
+
last_name: lorem.generateWords(1),
|
|
48
|
+
username: lorem.generateWords(1).toLocaleLowerCase(),
|
|
49
|
+
email: `${lorem.generateWords(1).toLocaleLowerCase()}@example.com`,
|
|
50
|
+
name: "",
|
|
51
|
+
};
|
|
52
|
+
replacements.name = `${replacements.first_name} ${replacements.last_name}`;
|
|
53
|
+
const removableGenerator = (key: string) => {
|
|
54
|
+
// Between 0 and 25% chance
|
|
55
|
+
if (Math.random() < Math.random() * 0.25) {
|
|
56
|
+
removables.push(key);
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
removableGenerator("account");
|
|
60
|
+
removableGenerator("first_name");
|
|
61
|
+
removableGenerator("last_name");
|
|
62
|
+
removableGenerator("name");
|
|
63
|
+
removableGenerator("email");
|
|
64
|
+
removableGenerator("username");
|
|
65
|
+
|
|
66
|
+
return dataBuilder(user, removables, replacements, true) as User;
|
|
67
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
@charset "UTF-8";
|
|
2
|
+
@use "sass:meta";
|
|
3
|
+
|
|
4
|
+
// This is a sample file, replace me.
|
|
5
|
+
|
|
6
|
+
@import url("https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&family=Montserrat:ital,wght@0,100..900;1,100..900&display=swap");
|
|
7
|
+
|
|
8
|
+
:root {
|
|
9
|
+
--font-family: "Inter", sans-serif;
|
|
10
|
+
--color-text: #181d27;
|
|
11
|
+
--color-primary: #001aff;
|
|
12
|
+
--color-secondary: #001aff;
|
|
13
|
+
--color-third: #e4f0ff;
|
|
14
|
+
--color-heading: #181d27;
|
|
15
|
+
font-family: var(--font-family);
|
|
16
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { html } from "lit";
|
|
2
|
+
|
|
3
|
+
import type { Meta, StoryObj } from "@storybook/web-components";
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
SampleObjects,
|
|
7
|
+
type ComponentProps,
|
|
8
|
+
} from "@components/ui/sample-objects";
|
|
9
|
+
|
|
10
|
+
import "@components/ui/sample-object";
|
|
11
|
+
|
|
12
|
+
const meta: Meta<{ objects: ComponentProps[] }> = {
|
|
13
|
+
title: "components/sample-objects",
|
|
14
|
+
tags: ["autodocs", "!dev", "Some", "Tags"],
|
|
15
|
+
render: (args) => {
|
|
16
|
+
new SampleObjects();
|
|
17
|
+
|
|
18
|
+
return html`<sample-objects .objects=${args.objects}></sample-objects>`;
|
|
19
|
+
},
|
|
20
|
+
args: {
|
|
21
|
+
objects: [
|
|
22
|
+
{
|
|
23
|
+
"@id": "urn:uuid:1",
|
|
24
|
+
name: "Foo",
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"@id": "urn:uuid:2",
|
|
28
|
+
name: "Bar",
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"@id": "urn:uuid:3",
|
|
32
|
+
name: "Baz",
|
|
33
|
+
},
|
|
34
|
+
],
|
|
35
|
+
},
|
|
36
|
+
argTypes: {
|
|
37
|
+
objects: {
|
|
38
|
+
control: "object",
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export default meta;
|
|
44
|
+
|
|
45
|
+
export type SampleObjectsStory = StoryObj<{ objects: { name: string }[] }>;
|
|
46
|
+
|
|
47
|
+
export const Default: SampleObjectsStory = {};
|