@startinblox/components-ds4go 3.3.7 → 4.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.
@@ -19,197 +19,54 @@ article {
19
19
  width: 100%;
20
20
  display: flex;
21
21
  font-family: var(--font-family-body);
22
- &.vertical {
23
- min-width: 295px;
24
- .card-content {
25
- max-height: 180px;
26
- tems-division {
27
- max-height: 180px;
28
- }
29
- }
30
- }
31
- &.horizontal,
32
- &.billImage {
33
- header {
34
- width: auto;
35
- border-radius: var(--border-radius-lg) 0 0 var(--border-radius-lg);
36
- }
37
- header.image {
38
- flex-shrink: 0;
39
- width: 33%;
40
- height: 100%;
41
- }
42
- main {
43
- flex-grow: 1;
44
- .card-content {
45
- max-height: 78px;
46
- tems-division {
47
- max-height: 78px;
48
- }
49
- }
50
- }
51
- }
52
- &.billImage {
53
- header.image {
54
- width: 50%;
55
- }
56
- .card-content {
57
- max-height: 206px;
58
- tems-division {
59
- max-height: 206px;
60
- }
61
- }
62
- }
22
+ min-width: 295px;
23
+ flex-direction: column;
24
+
63
25
  header {
64
26
  display: flex;
65
27
  background-repeat: no-repeat;
66
- background-size: cover;
28
+ background-size: contain;
67
29
  background-position: center center;
68
30
  box-sizing: border-box;
31
+ padding: var(--scale-400);
69
32
  width: 100%;
70
- padding: 16px;
33
+ border-bottom: var(--border-width-sm) solid var(--color-border-primary);
34
+ border-radius: var(--border-radius-lg) var(--border-radius-lg) 0 0;
35
+ height: 167px;
36
+ }
37
+
38
+ .card-content {
39
+ max-height: 180px;
40
+ tems-division {
41
+ max-height: 180px;
42
+ }
71
43
  }
44
+
72
45
  main {
73
46
  display: flex;
74
47
  flex-direction: column;
75
48
  gap: var(--scale-400);
76
49
  flex: 1;
50
+ padding: var(--scale-600);
51
+ padding-bottom: var(--scale-800);
52
+
77
53
  .content {
78
54
  flex: 1;
79
55
  }
80
- .orgLogo {
81
- background-repeat: no-repeat;
82
- background-size: contain;
83
- background-position: center center;
84
- width: 48px;
85
- height: 48px;
86
- }
56
+
87
57
  .card-content {
88
58
  flex-grow: 1;
89
59
  overflow: hidden;
90
60
  text-overflow: ellipsis;
91
61
  width: 100%;
92
62
  }
93
- .address-line {
94
- display: flex;
95
- flex-direction: row;
96
- justify-content: space-between;
97
- align-items: end;
98
- width: 100%;
99
- > div:first-child {
100
- flex: 1;
101
- display: flex;
102
- gap: 16px;
103
- flex-direction: column;
104
- }
105
- }
106
- .lang-date {
107
- width: fit-content;
108
- display: flex;
109
- gap: 24px;
110
- flex-direction: row;
111
- color: var(--color-text-disabled-on);
112
- font-size: var(--typography-size-body-sm);
113
-
114
- font-weight: var(--font-weight-regular);
115
- line-height: var(--line-height-body-sm);
116
- text-transform: uppercase;
117
- }
118
- .address,
119
- .source-logo {
120
- display: flex;
121
- flex-direction: row;
122
- align-items: center;
123
- gap: var(--scale-200);
124
- color: var(--color-text-information);
125
- font-size: var(--typography-size-body-sm);
126
- font-style: normal;
127
- font-weight: var(--font-weight-regular);
128
- line-height: var(--line-height-body-sm);
129
- text-decoration: underline;
130
- a {
131
- color: var(--color-text-information);
132
- }
133
- svg {
134
- color: var(--color-text-information);
135
- width: var(--icon-size-sm);
136
- height: var(--icon-size-sm);
137
- display: flex;
138
- }
139
- .source,
140
- .logo {
141
- display: flex;
142
- flex-direction: row;
143
- align-items: center;
144
- gap: var(--scale-200);
145
- }
146
- // logo image in source block
147
- .logo {
148
- margin-left: auto;
149
- background-repeat: no-repeat;
150
- background-size: contain;
151
- background-position: center center;
152
- width: 76px;
153
- height: 24px;
154
- }
155
- }
156
63
  }
157
- .tags,
158
- .action {
64
+
65
+ .tags {
159
66
  display: flex;
160
67
  flex-direction: row;
161
68
  flex-wrap: wrap;
162
69
  align-items: flex-start;
163
70
  gap: var(--scale-200);
164
71
  }
165
- .action ::slotted(*) {
166
- width: 100%;
167
- padding: var(--scale-400);
168
- border-top: var(--border-width-sm) solid var(--color-border-primary);
169
- }
170
- .action slot:not(:has-slotted) {
171
- display: none;
172
- }
173
-
174
- &.vertical {
175
- flex-direction: column;
176
- header {
177
- width: 100%;
178
- border-bottom: var(--border-width-sm) solid var(--color-border-primary);
179
- border-radius: var(--border-radius-lg) var(--border-radius-lg) 0 0;
180
- &.image {
181
- height: 167px;
182
- }
183
- }
184
- main {
185
- padding: var(--scale-600);
186
- padding-bottom: var(--scale-800);
187
- }
188
-
189
- }
190
-
191
- &.vertical,
192
- &.billImage {
193
- .lang-date {
194
- width: 100%;
195
- justify-content: space-between;
196
- }
197
- }
198
-
199
- &.horizontal,
200
- &.billImage {
201
-
202
- main {
203
- padding: var(--scale-600);
204
- padding-bottom: var(--scale-800);
205
-
206
-
207
- .source-logo .logo {
208
- margin-left: 0px;
209
- }
210
- }
211
- }
212
- div:has(slot:not(:has-slotted)) {
213
- display: none;
214
- }
215
72
  }
@@ -38,7 +38,7 @@ svg {
38
38
  flex-direction: row;
39
39
  gap: var(--scale-400);
40
40
 
41
- tems-button:nth-child(2) {
41
+ catalog-modal-negotiation-button {
42
42
  margin-left: auto;
43
43
  }
44
44
  }
@@ -1,349 +0,0 @@
1
- import type { Ds4goCardCatalogProps } from "@components/cards/ds4go-card-dataspace-catalog";
2
- import {
3
- filterObjectByDateAfter,
4
- filterObjectById,
5
- filterObjectByInterval,
6
- filterObjectByNamedValue,
7
- filterObjectByType,
8
- filterObjectByValue,
9
- } from "@helpers";
10
- import { msg } from "@lit/localize";
11
- import type { Resource } from "@src/component";
12
- import {
13
- rdf,
14
- TemsObjectsHandler,
15
- type TemsSearchObject,
16
- } from "@startinblox/solid-tems-shared";
17
- import { css, html, nothing, type PropertyValues } from "lit";
18
- import { customElement, state } from "lit/decorators.js";
19
-
20
- @customElement("ds4go-catalog-data-holder")
21
- export class Ds4goCatalogDataHolder extends TemsObjectsHandler {
22
- static styles = css`
23
- .card-grid {
24
- display: flex;
25
- flex-direction: row;
26
- flex-wrap: wrap;
27
- gap: 20px;
28
- }
29
- .card-grid-vertical {
30
- justify-content: stretch;
31
- }
32
- .card-grid-vertical ds4go-card-dataspace-catalog {
33
- width: 354px;
34
- height: auto;
35
- }
36
- ds4go-card-dataspace-catalog {
37
- cursor: pointer;
38
- }
39
- `;
40
-
41
- @state()
42
- view: "card" | "list" | "table" | "map" = "card";
43
-
44
- @state()
45
- search: TemsSearchObject[] = [];
46
-
47
- objects: (
48
- | rdf.Object_3DObject
49
- | rdf.Object_MediaObject_CivilSociety
50
- | rdf.Object_MediaObject_FactChecking
51
- | rdf.Object_MediaObject_InteractiveInfographics
52
- | rdf.Object_MediaObject_Stories
53
- | rdf.Provider
54
- | rdf.Service
55
- | rdf.DataOffer
56
- )[] = [];
57
-
58
- @state()
59
- protected _displayObjects: (Ds4goCardCatalogProps & { original: Resource })[] =
60
- [];
61
-
62
- protected filter(objects: any[], filters: TemsSearchObject[] = []) {
63
- if (!filters || filters.length === 0 || !objects || objects.length === 0) {
64
- return objects;
65
- }
66
-
67
- const groupedFilters = new Map<string, TemsSearchObject[]>();
68
- for (const filter of filters) {
69
- const groupKey = filter.name;
70
- const group = groupedFilters.get(groupKey) || [];
71
- group.push(filter);
72
- groupedFilters.set(groupKey, group);
73
- }
74
-
75
- let currentFilteredObjects = [...objects];
76
-
77
- for (const filterGroup of groupedFilters.values()) {
78
- if (currentFilteredObjects.length === 0) {
79
- break;
80
- }
81
-
82
- const tempResults = [];
83
- for (const filter of filterGroup) {
84
- switch (filter.type) {
85
- case "interval":
86
- tempResults.push(
87
- filterObjectByInterval(
88
- currentFilteredObjects,
89
- filter.name,
90
- filter.value,
91
- ),
92
- );
93
- break;
94
- case "dateAfter":
95
- tempResults.push(
96
- filterObjectByDateAfter(
97
- currentFilteredObjects,
98
- filter.name,
99
- filter.value,
100
- ),
101
- );
102
- break;
103
- case "matchId":
104
- tempResults.push(
105
- filterObjectById(
106
- currentFilteredObjects,
107
- filter.name,
108
- filter.value,
109
- ),
110
- );
111
- break;
112
- case "matchType":
113
- tempResults.push(
114
- filterObjectByType(currentFilteredObjects, filter.value),
115
- );
116
- break;
117
- case "exact":
118
- tempResults.push(
119
- filterObjectByNamedValue(
120
- currentFilteredObjects,
121
- filter.name,
122
- filter.value,
123
- ),
124
- );
125
- break;
126
- default:
127
- tempResults.push(
128
- filterObjectByValue(currentFilteredObjects, filter.value),
129
- );
130
- }
131
- }
132
- currentFilteredObjects = [...tempResults.flat()];
133
- }
134
-
135
- return currentFilteredObjects;
136
- }
137
-
138
- protected _getProp(obj: Resource, ...names: string[]) {
139
- if (!obj) return undefined;
140
- for (const name of names) {
141
- if (name in obj) {
142
- return obj[name];
143
- }
144
- }
145
- return undefined;
146
- }
147
-
148
- protected _areSameType(objects: Resource[] = this.objects): boolean {
149
- if (!objects || objects.length === 0) {
150
- return true;
151
- }
152
-
153
- const firstType = objects[0]["@type"];
154
- for (const obj of objects) {
155
- const objType = obj["@type"];
156
-
157
- if (Array.isArray(firstType) && Array.isArray(objType)) {
158
- if (
159
- firstType.length !== objType.length ||
160
- !firstType.every((val, index) => val === objType[index])
161
- ) {
162
- return false;
163
- }
164
- } else if (Array.isArray(firstType) && !Array.isArray(objType)) {
165
- return false;
166
- } else if (!Array.isArray(firstType) && Array.isArray(objType)) {
167
- return false;
168
- } else if (objType !== firstType) {
169
- return false;
170
- }
171
- }
172
-
173
- return true;
174
- }
175
-
176
- protected _typeToString(types: string[]) {
177
- return types
178
- .map((type) => rdf.typeMap[type])
179
- .filter(String)
180
- .join("");
181
- }
182
-
183
- protected _handleClickEvent(originalObj: Resource) {
184
- this.dispatchEvent(new CustomEvent("clicked", { detail: originalObj }));
185
- }
186
-
187
- willUpdate(changedProperties: PropertyValues) {
188
- if (changedProperties.has("objects") || changedProperties.has("search")) {
189
- const filteredObjects = this.filter(this.objects, this.search);
190
- this.dispatchEvent(
191
- new CustomEvent("result-count", { detail: filteredObjects.length }),
192
- );
193
- const objectsAreSameType = this._areSameType(filteredObjects);
194
-
195
- this._displayObjects = filteredObjects.map((obj) => {
196
- const getter = (propName: string, ...fallbackNames: string[]) =>
197
- this._getProp(obj, propName, ...fallbackNames);
198
-
199
- const tags: (
200
- | string
201
- | { name: string; type?: string; color?: string }
202
- )[] = [];
203
-
204
- // Add provider badge for DSP datasets (provider discrimination)
205
- const providerName = getter("_provider");
206
- const providerColor = getter("_providerColor");
207
- if (providerName) {
208
- tags.push({
209
- name: providerName,
210
- type: "provider",
211
- color: providerColor,
212
- });
213
- }
214
-
215
- let categories = getter("categories", "keywords");
216
- let firstCategory = "";
217
- if (categories) {
218
- if (!Array.isArray(categories)) categories = [categories];
219
-
220
- if (
221
- !(!objectsAreSameType && this.hasType(rdf.RDFTYPE_OBJECT, [obj])) &&
222
- categories.length > 0 &&
223
- !this.hasType(rdf.RDFTYPE_PROVIDER, [obj]) &&
224
- !this.hasType(rdf.RDFTYPE_DATAOFFER, [obj])
225
- ) {
226
- firstCategory = categories[0]?.name;
227
- tags.push(
228
- ...categories.slice(1).map((c: rdf.NamedResource) => c.name),
229
- );
230
- } else {
231
- tags.push(...categories.map((c: rdf.NamedResource) => c.name));
232
- }
233
- }
234
-
235
- let location = "";
236
- if (this.hasType(rdf.RDFTYPE_3D_OBJECT, [obj])) {
237
- if (getter("is_low_polygons")) {
238
- tags.push(msg("Low-poly (<10k polygones)"));
239
- }
240
- if (getter("ai")) {
241
- tags.push(msg("AI-generated"));
242
- }
243
- if (getter("texture")) {
244
- tags.push(getter("texture"));
245
- }
246
- location = getter("location")?.country;
247
- }
248
-
249
- let images = getter("images", "image");
250
- if (!Array.isArray(images)) images = [images];
251
- images = images.filter((p: rdf.Image) => p?.url && !p?.iframe);
252
-
253
- let language = getter("language", "original_languages", "prices");
254
- if (typeof language !== "string") {
255
- language = language?.name || "";
256
- }
257
-
258
- // Get endpoint URL and content type for DSP assets
259
- const endpointUrl = getter("endpointUrl", "url");
260
- const contentType = getter("contentType", "contenttype");
261
-
262
- // Add content type as tag if available
263
- if (
264
- contentType &&
265
- !tags.some((t) =>
266
- typeof t === "string" ? t === contentType : t.name === contentType,
267
- )
268
- ) {
269
- tags.push({
270
- name: contentType,
271
- type: "contentType",
272
- color: "#607d8b",
273
- });
274
- }
275
-
276
- // Build description with endpoint URL for DSP assets
277
- let description = getter("description") || "";
278
- if (endpointUrl && !description) {
279
- description = endpointUrl;
280
- }
281
-
282
- const cardProps: Ds4goCardCatalogProps = {
283
- backgroundImg: this.hasType(rdf.RDFTYPE_PROVIDER, [obj])
284
- ? false
285
- : images?.filter((p: rdf.Image) => p?.url && !p?.iframe)?.[0]?.url,
286
- orgLogo: this.hasType(rdf.RDFTYPE_PROVIDER, [obj])
287
- ? images?.filter((p: rdf.Image) => p?.url && !p?.iframe)?.[0]?.url
288
- : getter("providers")?.filter(
289
- (p: rdf.Provider) => p.image?.url && !p.image?.iframe,
290
- )?.[0]?.image?.url,
291
- logoOnTop: !this.hasType(rdf.RDFTYPE_OBJECT, [obj]),
292
- badge:
293
- !objectsAreSameType && this.hasType(rdf.RDFTYPE_OBJECT, [obj])
294
- ? this._typeToString([getter("@type")].flat())
295
- : firstCategory,
296
- tags: tags.filter((t) => t) as string[],
297
- header: getter("name", "title"),
298
- content: description,
299
- isFullSize: true,
300
- date: this.hasType(rdf.RDFTYPE_3D_OBJECT, [obj])
301
- ? getter("licences")
302
- ?.map((l: rdf.Licence) => l.name)
303
- .join(", ")
304
- : getter("publication_date", "release_date", "creation_date"),
305
- language: language,
306
- address: endpointUrl || location,
307
- source: this.hasType(rdf.RDFTYPE_OBJECT, [obj])
308
- ? getter("affiliation")?.name ||
309
- getter("providers")
310
- ?.map((p: rdf.Provider) => p.name)
311
- .join(", ")
312
- : "",
313
- };
314
-
315
- return { ...cardProps, original: obj };
316
- });
317
- }
318
- }
319
-
320
- render() {
321
- if (!this._displayObjects || this._displayObjects.length === 0) {
322
- return nothing;
323
- }
324
-
325
- return html`<div
326
- class="card-grid${this.view === "card" ? " card-grid-vertical" : ""}"
327
- >
328
- ${this._displayObjects.map((displayObj) => {
329
- return html`<ds4go-card-dataspace-catalog
330
- .object=${import.meta.env.DEV ? displayObj.original : nothing}
331
- type=${this.view === "card" ? "card" : "horizontal"}
332
- background-img=${displayObj.backgroundImg || nothing}
333
- org-logo=${displayObj.orgLogo || nothing}
334
- .logoOnTop=${displayObj.logoOnTop || nothing}
335
- .badge=${displayObj.badge || nothing}
336
- .tags=${displayObj.tags || nothing}
337
- .header=${displayObj.header || nothing}
338
- .content=${displayObj.content || nothing}
339
- .isFullSize=${displayObj.isFullSize || nothing}
340
- date=${displayObj.date || nothing}
341
- language=${displayObj.language || nothing}
342
- address=${displayObj.address || nothing}
343
- source=${displayObj.source || nothing}
344
- @click=${() => this._handleClickEvent(displayObj.original)}
345
- ></ds4go-card-dataspace-catalog>`;
346
- })}
347
- </div>`;
348
- }
349
- }