geonetwork-ui 2.6.0-dev.7be6567ef → 2.6.0-dev.b306f1194

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 (38) hide show
  1. package/esm2022/libs/feature/search/src/lib/favorites/favorite-star/favorite-star.component.mjs +3 -3
  2. package/esm2022/libs/ui/elements/src/index.mjs +2 -1
  3. package/esm2022/libs/ui/elements/src/lib/internal-link-card/internal-link-card.component.mjs +163 -0
  4. package/esm2022/libs/ui/elements/src/lib/metadata-quality/metadata-quality.component.mjs +3 -3
  5. package/esm2022/libs/ui/elements/src/lib/ui-elements.module.mjs +10 -4
  6. package/esm2022/libs/ui/widgets/src/lib/progress-bar/progress-bar.component.mjs +3 -3
  7. package/esm2022/translations/de.json +5 -0
  8. package/esm2022/translations/en.json +5 -0
  9. package/esm2022/translations/es.json +5 -0
  10. package/esm2022/translations/fr.json +5 -0
  11. package/esm2022/translations/it.json +5 -0
  12. package/esm2022/translations/nl.json +5 -0
  13. package/esm2022/translations/pt.json +5 -0
  14. package/fesm2022/geonetwork-ui.mjs +202 -14
  15. package/fesm2022/geonetwork-ui.mjs.map +1 -1
  16. package/libs/ui/elements/src/index.d.ts +1 -0
  17. package/libs/ui/elements/src/index.d.ts.map +1 -1
  18. package/libs/ui/elements/src/lib/internal-link-card/internal-link-card.component.d.ts +43 -0
  19. package/libs/ui/elements/src/lib/internal-link-card/internal-link-card.component.d.ts.map +1 -0
  20. package/libs/ui/elements/src/lib/ui-elements.module.d.ts +2 -1
  21. package/libs/ui/elements/src/lib/ui-elements.module.d.ts.map +1 -1
  22. package/package.json +1 -1
  23. package/src/libs/feature/search/src/lib/favorites/favorite-star/favorite-star.component.html +1 -1
  24. package/src/libs/ui/elements/src/index.ts +1 -0
  25. package/src/libs/ui/elements/src/lib/internal-link-card/internal-link-card.component.css +0 -0
  26. package/src/libs/ui/elements/src/lib/internal-link-card/internal-link-card.component.html +156 -0
  27. package/src/libs/ui/elements/src/lib/internal-link-card/internal-link-card.component.ts +190 -0
  28. package/src/libs/ui/elements/src/lib/metadata-quality/metadata-quality.component.html +4 -2
  29. package/src/libs/ui/elements/src/lib/ui-elements.module.ts +3 -0
  30. package/src/libs/ui/widgets/src/lib/progress-bar/progress-bar.component.html +2 -2
  31. package/translations/de.json +5 -0
  32. package/translations/en.json +5 -0
  33. package/translations/es.json +5 -0
  34. package/translations/fr.json +5 -0
  35. package/translations/it.json +5 -0
  36. package/translations/nl.json +5 -0
  37. package/translations/pt.json +5 -0
  38. package/translations/sk.json +5 -0
@@ -23,4 +23,5 @@ export * from './lib/ui-elements.module';
23
23
  export * from './lib/user-feedback-item/user-feedback-item.component';
24
24
  export * from './lib/user-preview/user-preview.component';
25
25
  export * from './lib/application-banner/application-banner.component';
26
+ export * from './lib/internal-link-card/internal-link-card.component';
26
27
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/libs/ui/elements/src/index.ts"],"names":[],"mappings":"AAAA,cAAc,mCAAmC,CAAA;AACjD,cAAc,+BAA+B,CAAA;AAC7C,cAAc,yDAAyD,CAAA;AACvE,cAAc,6CAA6C,CAAA;AAC3D,cAAc,6CAA6C,CAAA;AAC3D,cAAc,+CAA+C,CAAA;AAC7D,cAAc,6BAA6B,CAAA;AAC3C,cAAc,yCAAyC,CAAA;AACvD,cAAc,6DAA6D,CAAA;AAC3E,cAAc,qCAAqC,CAAA;AACnD,cAAc,iDAAiD,CAAA;AAC/D,cAAc,iDAAiD,CAAA;AAC/D,cAAc,mDAAmD,CAAA;AACjE,cAAc,mDAAmD,CAAA;AACjE,cAAc,6CAA6C,CAAA;AAC3D,cAAc,6DAA6D,CAAA;AAC3E,cAAc,mDAAmD,CAAA;AACjE,cAAc,2CAA2C,CAAA;AACzD,cAAc,iDAAiD,CAAA;AAC/D,cAAc,yDAAyD,CAAA;AACvE,cAAc,qCAAqC,CAAA;AACnD,cAAc,0BAA0B,CAAA;AACxC,cAAc,uDAAuD,CAAA;AACrE,cAAc,2CAA2C,CAAA;AACzD,cAAc,uDAAuD,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/libs/ui/elements/src/index.ts"],"names":[],"mappings":"AAAA,cAAc,mCAAmC,CAAA;AACjD,cAAc,+BAA+B,CAAA;AAC7C,cAAc,yDAAyD,CAAA;AACvE,cAAc,6CAA6C,CAAA;AAC3D,cAAc,6CAA6C,CAAA;AAC3D,cAAc,+CAA+C,CAAA;AAC7D,cAAc,6BAA6B,CAAA;AAC3C,cAAc,yCAAyC,CAAA;AACvD,cAAc,6DAA6D,CAAA;AAC3E,cAAc,qCAAqC,CAAA;AACnD,cAAc,iDAAiD,CAAA;AAC/D,cAAc,iDAAiD,CAAA;AAC/D,cAAc,mDAAmD,CAAA;AACjE,cAAc,mDAAmD,CAAA;AACjE,cAAc,6CAA6C,CAAA;AAC3D,cAAc,6DAA6D,CAAA;AAC3E,cAAc,mDAAmD,CAAA;AACjE,cAAc,2CAA2C,CAAA;AACzD,cAAc,iDAAiD,CAAA;AAC/D,cAAc,yDAAyD,CAAA;AACvE,cAAc,qCAAqC,CAAA;AACnD,cAAc,0BAA0B,CAAA;AACxC,cAAc,uDAAuD,CAAA;AACrE,cAAc,2CAA2C,CAAA;AACzD,cAAc,uDAAuD,CAAA;AACrE,cAAc,uDAAuD,CAAA"}
@@ -0,0 +1,43 @@
1
+ import { TemplateRef, OnInit, EventEmitter, ElementRef } from '@angular/core';
2
+ import { CatalogRecord, Organization } from '../../../../../../libs/common/domain/src/lib/model/record';
3
+ import { Subscription } from 'rxjs';
4
+ import * as i0 from "@angular/core";
5
+ type CardSize = 'L' | 'M' | 'S' | 'XS';
6
+ export declare class InternalLinkCardComponent implements OnInit {
7
+ protected elementRef: ElementRef;
8
+ record: CatalogRecord;
9
+ metadataQualityDisplay: boolean;
10
+ favoriteTemplate: TemplateRef<{
11
+ $implicit: CatalogRecord;
12
+ }>;
13
+ linkHref: string;
14
+ isGeodata: boolean;
15
+ set size(value: CardSize);
16
+ get size(): CardSize;
17
+ mdSelect: EventEmitter<CatalogRecord>;
18
+ subscription: Subscription;
19
+ abstract: string;
20
+ cardClass: string;
21
+ thumbnailContainerClass: string;
22
+ private _size;
23
+ private readonly sizeClassMap;
24
+ private readonly thumbnailSizeClassMap;
25
+ private readonly titleClassMap;
26
+ constructor(elementRef: ElementRef);
27
+ ngOnInit(): void;
28
+ get organization(): Organization;
29
+ get contacts(): import("../../../../../common/domain/src/lib/model/record/contact.model").Individual[];
30
+ getTitleClass(): string;
31
+ openExternalUrl(event: Event, url: URL): void;
32
+ openMailto(event: Event, email: string): void;
33
+ copyToClipboard(event: Event, text: string): void;
34
+ get shouldShowThumbnail(): boolean;
35
+ getKindInfo(): {
36
+ text: string;
37
+ icon: string;
38
+ };
39
+ static ɵfac: i0.ɵɵFactoryDeclaration<InternalLinkCardComponent, never>;
40
+ static ɵcmp: i0.ɵɵComponentDeclaration<InternalLinkCardComponent, "gn-ui-internal-link-card", never, { "record": { "alias": "record"; "required": false; }; "metadataQualityDisplay": { "alias": "metadataQualityDisplay"; "required": false; }; "favoriteTemplate": { "alias": "favoriteTemplate"; "required": false; }; "linkHref": { "alias": "linkHref"; "required": false; }; "isGeodata": { "alias": "isGeodata"; "required": false; }; "size": { "alias": "size"; "required": false; }; }, { "mdSelect": "mdSelect"; }, never, never, true, never>;
41
+ }
42
+ export {};
43
+ //# sourceMappingURL=internal-link-card.component.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"internal-link-card.component.d.ts","sourceRoot":"","sources":["../../../../../../src/libs/ui/elements/src/lib/internal-link-card/internal-link-card.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,WAAW,EACX,MAAM,EAEN,YAAY,EACZ,UAAU,EACX,MAAM,eAAe,CAAA;AACtB,OAAO,EACL,aAAa,EACb,YAAY,EACb,MAAM,2DAA2D,CAAA;AAyBlE,OAAO,EAAa,YAAY,EAAE,MAAM,MAAM,CAAA;;AAM9C,KAAK,QAAQ,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,IAAI,CAAA;AAEtC,qBA+Ba,yBAA0B,YAAW,MAAM;IA6C1C,SAAS,CAAC,UAAU,EAAE,UAAU;IA5CnC,MAAM,EAAE,aAAa,CAAA;IACrB,sBAAsB,EAAE,OAAO,CAAA;IAC/B,gBAAgB,EAAE,WAAW,CAAC;QAAE,SAAS,EAAE,aAAa,CAAA;KAAE,CAAC,CAAA;IAC3D,QAAQ,EAAE,MAAM,CAAO;IACvB,SAAS,EAAE,OAAO,CAAA;IAC3B,IAAa,IAAI,CAAC,KAAK,EAAE,QAAQ,EAIhC;IACD,IAAI,IAAI,IAAI,QAAQ,CAEnB;IACS,QAAQ,8BAAoC;IACtD,YAAY,eAAqB;IAEjC,QAAQ,EAAE,MAAM,CAAA;IAEhB,SAAS,SAAK;IACd,uBAAuB,SAAK;IAE5B,OAAO,CAAC,KAAK,CAAgB;IAE7B,OAAO,CAAC,QAAQ,CAAC,YAAY,CAK5B;IAED,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAKrC;IAED,OAAO,CAAC,QAAQ,CAAC,aAAa,CAK7B;gBAEqB,UAAU,EAAE,UAAU;IAE5C,QAAQ,IAAI,IAAI;IAahB,IAAI,YAAY,IAAI,YAAY,CAE/B;IAED,IAAI,QAAQ,2FAMX;IAED,aAAa;IAQb,eAAe,CAAC,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,GAAG,IAAI;IAK7C,UAAU,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAK7C,eAAe,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAKjD,IAAI,mBAAmB,IAAI,OAAO,CAEjC;IAED,WAAW,IAAI;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE;yCAnGlC,yBAAyB;2CAAzB,yBAAyB;CAiHrC"}
@@ -19,9 +19,10 @@ import * as i17 from "../../../layout/src/lib/max-lines/max-lines.component";
19
19
  import * as i18 from "../../../inputs/src/lib/text-input/text-input.component";
20
20
  import * as i19 from "./image-input/image-input.component";
21
21
  import * as i20 from "./application-banner/application-banner.component";
22
+ import * as i21 from "./internal-link-card/internal-link-card.component";
22
23
  export declare class UiElementsModule {
23
24
  static ɵfac: i0.ɵɵFactoryDeclaration<UiElementsModule, never>;
24
- static ɵmod: i0.ɵɵNgModuleDeclaration<UiElementsModule, [typeof i1.AvatarComponent, typeof i2.UserPreviewComponent], [typeof i3.CommonModule, typeof i4.MatTooltipModule, typeof i5.UiWidgetsModule, typeof i6.UiLayoutModule, typeof i7.TranslateModule, typeof i8.UtilSharedModule, typeof i9.RouterModule, typeof i10.UiInputsModule, typeof i11.FormsModule, typeof i3.NgOptimizedImage, typeof i12.PopoverComponent, typeof i13.MarkdownParserComponent, typeof i14.ThumbnailComponent, typeof i15.TimeSincePipe, typeof i16.BadgeComponent, typeof i17.MaxLinesComponent, typeof i18.TextInputComponent, typeof i19.ImageInputComponent, typeof i20.ApplicationBannerComponent], [typeof i14.ThumbnailComponent, typeof i1.AvatarComponent, typeof i2.UserPreviewComponent, typeof i13.MarkdownParserComponent, typeof i19.ImageInputComponent, typeof i20.ApplicationBannerComponent]>;
25
+ static ɵmod: i0.ɵɵNgModuleDeclaration<UiElementsModule, [typeof i1.AvatarComponent, typeof i2.UserPreviewComponent], [typeof i3.CommonModule, typeof i4.MatTooltipModule, typeof i5.UiWidgetsModule, typeof i6.UiLayoutModule, typeof i7.TranslateModule, typeof i8.UtilSharedModule, typeof i9.RouterModule, typeof i10.UiInputsModule, typeof i11.FormsModule, typeof i3.NgOptimizedImage, typeof i12.PopoverComponent, typeof i13.MarkdownParserComponent, typeof i14.ThumbnailComponent, typeof i15.TimeSincePipe, typeof i16.BadgeComponent, typeof i17.MaxLinesComponent, typeof i18.TextInputComponent, typeof i19.ImageInputComponent, typeof i20.ApplicationBannerComponent, typeof i21.InternalLinkCardComponent], [typeof i14.ThumbnailComponent, typeof i1.AvatarComponent, typeof i2.UserPreviewComponent, typeof i13.MarkdownParserComponent, typeof i19.ImageInputComponent, typeof i20.ApplicationBannerComponent, typeof i21.InternalLinkCardComponent]>;
25
26
  static ɵinj: i0.ɵɵInjectorDeclaration<UiElementsModule>;
26
27
  }
27
28
  //# sourceMappingURL=ui-elements.module.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ui-elements.module.d.ts","sourceRoot":"","sources":["../../../../../src/libs/ui/elements/src/lib/ui-elements.module.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;AAuBA,qBAqCa,gBAAgB;yCAAhB,gBAAgB;0CAAhB,gBAAgB;0CAAhB,gBAAgB;CAAG"}
1
+ {"version":3,"file":"ui-elements.module.d.ts","sourceRoot":"","sources":["../../../../../src/libs/ui/elements/src/lib/ui-elements.module.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAwBA,qBAuCa,gBAAgB;yCAAhB,gBAAgB;0CAAhB,gBAAgB;0CAAhB,gBAAgB;CAAG"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "geonetwork-ui",
3
- "version": "2.6.0-dev.7be6567ef",
3
+ "version": "2.6.0-dev.b306f1194",
4
4
  "engines": {
5
5
  "node": ">=20"
6
6
  },
@@ -1,6 +1,6 @@
1
1
  <div class="flex flex-row items-center">
2
2
  <span
3
- class="align-text-top mr-1.5"
3
+ class="align-text-top mr-1.5 mt-0.5"
4
4
  data-test="favorite-count"
5
5
  *ngIf="hasFavoriteCount && displayCount"
6
6
  >{{ favoriteCount }}</span
@@ -23,3 +23,4 @@ export * from './lib/ui-elements.module'
23
23
  export * from './lib/user-feedback-item/user-feedback-item.component'
24
24
  export * from './lib/user-preview/user-preview.component'
25
25
  export * from './lib/application-banner/application-banner.component'
26
+ export * from './lib/internal-link-card/internal-link-card.component'
@@ -0,0 +1,156 @@
1
+ <div
2
+ class="rounded-lg group card-shadow cursor-pointer overflow-hidden hover:bg-gray-50"
3
+ [ngClass]="cardClass"
4
+ >
5
+ <div class="flex flex-row justify-between w-full">
6
+ <div
7
+ *ngIf="shouldShowThumbnail"
8
+ [ngClass]="thumbnailContainerClass"
9
+ class="mr-4 flex flex-col"
10
+ >
11
+ <gn-ui-thumbnail
12
+ class="w-full h-full object-cover"
13
+ [thumbnailUrl]="record.overviews?.[0]?.url?.toString() || ''"
14
+ [fit]="'cover'"
15
+ ></gn-ui-thumbnail>
16
+ </div>
17
+ <div
18
+ class="flex flex-col flex-1 relative"
19
+ [ngClass]="{
20
+ 'justify-between': record.ownerOrganization?.name && size !== 'XS',
21
+ }"
22
+ >
23
+ <div class="flex items-center space-x-2">
24
+ <span
25
+ *ngIf="getKindInfo().text"
26
+ class="badge-btn text-white text-xs px-2 py-0.5 font-bold shrink-0 bg-primary leading-tight flex items-center justify-evenly h-6 min-h-6"
27
+ >
28
+ <ng-icon
29
+ class="text-[0.9em] text-white mr-1"
30
+ [name]="getKindInfo().icon"
31
+ ></ng-icon>
32
+ <span class="font-medium text-white text-xs" translate>
33
+ {{ getKindInfo().text }}
34
+ </span>
35
+ </span>
36
+ <span
37
+ *ngIf="isGeodata"
38
+ class="badge-btn text-black text-xs px-2 py-0.5 font-bold shrink-0 bg-primary-white leading-tight flex items-center justify-evenly h-6 min-h-6"
39
+ [ngClass]="size === 'L' ? 'w-[164px]' : 'w-8'"
40
+ >
41
+ <ng-icon
42
+ class="text-[0.9em] text-primary-darkest"
43
+ name="matLocationSearchingOutline"
44
+ ></ng-icon>
45
+ <ng-container *ngIf="size === 'L'">
46
+ <span
47
+ class="font-medium text-primary-darkest text-xs ml-1"
48
+ translate
49
+ >
50
+ record.metadata.type
51
+ </span>
52
+ </ng-container>
53
+ </span>
54
+ <div class="flex items-center">
55
+ <gn-ui-metadata-quality
56
+ [smaller]="true"
57
+ [metadata]="record"
58
+ [metadataQualityDisplay]="metadataQualityDisplay"
59
+ ></gn-ui-metadata-quality>
60
+ </div>
61
+ <div class="absolute top-0 right-0 items-center">
62
+ <ng-container
63
+ *ngIf="size !== 'XS'"
64
+ [ngTemplateOutlet]="favoriteTemplate"
65
+ [ngTemplateOutletContext]="{ $implicit: record }"
66
+ ></ng-container>
67
+ </div>
68
+ </div>
69
+ <div
70
+ class="font-medium text-title group-hover:text-primary overflow-hidden break-words"
71
+ [ngClass]="getTitleClass()"
72
+ >
73
+ {{ record.title }}
74
+ </div>
75
+ <div
76
+ *ngIf="size === 'L'"
77
+ class="mt-1 mb-2 font-normal text-xs text-gray-900 line-clamp-2 overflow-hidden"
78
+ >
79
+ <gn-ui-markdown-parser
80
+ [textContent]="abstract"
81
+ [whitoutStyles]="true"
82
+ ></gn-ui-markdown-parser>
83
+ </div>
84
+ <div
85
+ *ngIf="size !== 'XS' && record.ownerOrganization?.name"
86
+ class="flex items-center justify-evenly bg-gray-50 rounded-lg h-[53px] px-2"
87
+ >
88
+ <div class="flex items-center flex-1 min-w-0">
89
+ <div
90
+ class="w-[45px] h-[45px] rounded-lg overflow-hidden shrink-0 mr-3"
91
+ >
92
+ <gn-ui-thumbnail
93
+ [thumbnailUrl]="
94
+ record.ownerOrganization?.logoUrl?.toString() || ''
95
+ "
96
+ [fit]="'contain'"
97
+ class="w-full h-full rounded-lg"
98
+ ></gn-ui-thumbnail>
99
+ </div>
100
+ <div *ngIf="organization?.name" class="flex-1 w-0 overflow-hidden">
101
+ <div
102
+ class="text-xs text-black font-normal leading-tight truncate"
103
+ translate
104
+ >
105
+ record.card.metadata.contact
106
+ </div>
107
+ <div class="text-xl text-primary-black font-medium truncate">
108
+ {{ organization.name }}
109
+ </div>
110
+ </div>
111
+ </div>
112
+ <div *ngIf="size === 'L'" class="ml-2 flex space-x-2">
113
+ <div *ngIf="organization?.website" class="flex">
114
+ <button
115
+ [title]="organization.website"
116
+ class="w-[40px] h-[32px] flex items-center justify-center rounded-lg border border-[#D4D3D7] px-[8px] py-[4px] hover:bg-primary-lightest"
117
+ (click)="openExternalUrl($event, organization.website)"
118
+ >
119
+ <ng-icon name="iconoirInternet"></ng-icon>
120
+ </button>
121
+ </div>
122
+ <div *ngIf="contacts[0]?.email" class="flex">
123
+ <button
124
+ [title]="contacts[0].email"
125
+ class="w-[40px] h-[32px] flex items-center justify-center rounded-lg border border-[#D4D3D7] px-[8px] py-[4px] hover:bg-primary-lightest"
126
+ data-cy="contact-email"
127
+ (click)="openMailto($event, contacts[0].email)"
128
+ >
129
+ <ng-icon name="matEmailOutline"></ng-icon>
130
+ </button>
131
+ </div>
132
+ <div *ngIf="contacts[0]?.phone" class="flex">
133
+ <button
134
+ [title]="'Copy to clipboard'"
135
+ class="w-[40px] h-[32px] flex items-center justify-center rounded-lg border border-[#D4D3D7] px-[8px] py-[4px] hover:bg-primary-lightest relative group"
136
+ data-cy="contact-phone"
137
+ (click)="copyToClipboard($event, contacts[0].phone)"
138
+ >
139
+ <ng-icon name="matPhoneOutline"></ng-icon>
140
+ </button>
141
+ </div>
142
+ <div *ngIf="contacts[0]?.address" class="flex">
143
+ <button
144
+ [title]="'Copy to clipboard'"
145
+ class="w-[40px] h-[32px] flex items-center justify-center rounded-lg border border-[#D4D3D7] px-[8px] py-[4px] hover:bg-primary-lightest relative group"
146
+ data-cy="contact-phone"
147
+ (click)="copyToClipboard($event, contacts[0].address)"
148
+ >
149
+ <ng-icon name="matLocationOnOutline"></ng-icon>
150
+ </button>
151
+ </div>
152
+ </div>
153
+ </div>
154
+ </div>
155
+ </div>
156
+ </div>
@@ -0,0 +1,190 @@
1
+ import {
2
+ Component,
3
+ Input,
4
+ TemplateRef,
5
+ OnInit,
6
+ Output,
7
+ EventEmitter,
8
+ ElementRef,
9
+ } from '@angular/core'
10
+ import {
11
+ CatalogRecord,
12
+ Organization,
13
+ } from '../../../../../../libs/common/domain/src/lib/model/record'
14
+ import { NgClass, NgIf, NgTemplateOutlet } from '@angular/common'
15
+ import { MarkdownParserComponent } from '../markdown-parser/markdown-parser.component'
16
+ import { MetadataQualityComponent } from '../metadata-quality/metadata-quality.component'
17
+ import { ThumbnailComponent } from '../thumbnail/thumbnail.component'
18
+ import {
19
+ propagateToDocumentOnly,
20
+ removeWhitespace,
21
+ stripHtml,
22
+ } from '../../../../../../libs/util/shared/src'
23
+ import {
24
+ NgIconComponent,
25
+ provideIcons,
26
+ provideNgIconsConfig,
27
+ } from '@ng-icons/core'
28
+ import {
29
+ matLocationSearchingOutline,
30
+ matEmailOutline,
31
+ matPhoneOutline,
32
+ matLocationOnOutline,
33
+ } from '@ng-icons/material-icons/outline'
34
+ import { matCode } from '@ng-icons/material-icons/baseline'
35
+ import { iconoirDatabase, iconoirMap, iconoirInternet } from '@ng-icons/iconoir'
36
+ import { TranslateModule } from '@ngx-translate/core'
37
+ import { marker } from '@biesbjerg/ngx-translate-extract-marker'
38
+ import { fromEvent, Subscription } from 'rxjs'
39
+
40
+ marker('record.kind.dataset')
41
+ marker('record.kind.reuse')
42
+ marker('record.kind.service')
43
+
44
+ type CardSize = 'L' | 'M' | 'S' | 'XS'
45
+
46
+ @Component({
47
+ selector: 'gn-ui-internal-link-card',
48
+ standalone: true,
49
+ imports: [
50
+ NgClass,
51
+ NgIf,
52
+ ThumbnailComponent,
53
+ MetadataQualityComponent,
54
+ NgTemplateOutlet,
55
+ NgIconComponent,
56
+ TranslateModule,
57
+ MarkdownParserComponent,
58
+ ],
59
+ providers: [
60
+ provideIcons({
61
+ matLocationSearchingOutline,
62
+ matCode,
63
+ iconoirDatabase,
64
+ iconoirMap,
65
+ iconoirInternet,
66
+ matEmailOutline,
67
+ matPhoneOutline,
68
+ matLocationOnOutline,
69
+ }),
70
+ provideNgIconsConfig({
71
+ size: '1.2em',
72
+ }),
73
+ ],
74
+ templateUrl: './internal-link-card.component.html',
75
+ styleUrls: ['./internal-link-card.component.css'],
76
+ })
77
+ export class InternalLinkCardComponent implements OnInit {
78
+ @Input() record: CatalogRecord
79
+ @Input() metadataQualityDisplay: boolean
80
+ @Input() favoriteTemplate: TemplateRef<{ $implicit: CatalogRecord }>
81
+ @Input() linkHref: string = null
82
+ @Input() isGeodata: boolean
83
+ @Input() set size(value: CardSize) {
84
+ this._size = value
85
+ this.cardClass = this.sizeClassMap[value] || ''
86
+ this.thumbnailContainerClass = this.thumbnailSizeClassMap[value] || 'hidden'
87
+ }
88
+ get size(): CardSize {
89
+ return this._size
90
+ }
91
+ @Output() mdSelect = new EventEmitter<CatalogRecord>()
92
+ subscription = new Subscription()
93
+
94
+ abstract: string
95
+
96
+ cardClass = ''
97
+ thumbnailContainerClass = ''
98
+
99
+ private _size: CardSize = 'M'
100
+
101
+ private readonly sizeClassMap: Record<CardSize, string> = {
102
+ L: 'min-h-[190px] md:w-[992px] py-3 px-3 flex items-start gap-5',
103
+ M: 'min-h-[140px] md:w-[570px] py-3 px-3 flex items-start gap-4',
104
+ S: 'min-h-[220px] md:w-[370px] py-3 px-3 flex gap-4',
105
+ XS: 'min-h-[108px] md:w-[570px] py-3 px-3 flex gap-4',
106
+ }
107
+
108
+ private readonly thumbnailSizeClassMap: Record<CardSize, string> = {
109
+ L: 'w-[190px] h-[180px] rounded-lg overflow-hidden shrink-0',
110
+ M: 'w-[110px] h-[140px] rounded-lg overflow-hidden shrink-0',
111
+ S: 'hidden',
112
+ XS: 'hidden',
113
+ }
114
+
115
+ private readonly titleClassMap: Record<CardSize, string> = {
116
+ L: 'text-xl line-clamp-2',
117
+ M: 'text-base line-clamp-2',
118
+ S: 'text-base line-clamp-3',
119
+ XS: 'text-base mt-3 line-clamp-2',
120
+ }
121
+
122
+ constructor(protected elementRef: ElementRef) {}
123
+
124
+ ngOnInit(): void {
125
+ this.abstract = removeWhitespace(stripHtml(this.record?.abstract))
126
+ this.subscription.add(
127
+ fromEvent(this.elementRef.nativeElement, 'click').subscribe(
128
+ (event: Event) => {
129
+ event.preventDefault()
130
+ propagateToDocumentOnly(event)
131
+ this.mdSelect.emit(this.record)
132
+ }
133
+ )
134
+ )
135
+ }
136
+
137
+ get organization(): Organization {
138
+ return this.record.ownerOrganization
139
+ }
140
+
141
+ get contacts() {
142
+ return (
143
+ (this.record.kind === 'dataset'
144
+ ? this.record.contactsForResource
145
+ : this.record.contacts) || []
146
+ )
147
+ }
148
+
149
+ getTitleClass() {
150
+ return (
151
+ this.titleClassMap[this._size] +
152
+ ' ' +
153
+ (this.record.ownerOrganization?.name ? '' : 'mt-3') || ''
154
+ )
155
+ }
156
+
157
+ openExternalUrl(event: Event, url: URL): void {
158
+ event.stopPropagation()
159
+ window.open(url, '_blank')
160
+ }
161
+
162
+ openMailto(event: Event, email: string): void {
163
+ event.stopPropagation()
164
+ window.open(`mailto:${email}`, '_blank')
165
+ }
166
+
167
+ copyToClipboard(event: Event, text: string): void {
168
+ event.stopPropagation()
169
+ navigator.clipboard.writeText(text)
170
+ }
171
+
172
+ get shouldShowThumbnail(): boolean {
173
+ return this.size === 'L' || this.size === 'M'
174
+ }
175
+
176
+ getKindInfo(): { text: string; icon: string } {
177
+ if (!this.record?.kind) return { text: '', icon: '' }
178
+
179
+ switch (this.record.kind.toLowerCase()) {
180
+ case 'dataset':
181
+ return { text: 'record.kind.dataset', icon: 'iconoirDatabase' }
182
+ case 'reuse':
183
+ return { text: 'record.kind.reuse', icon: 'iconoirMap' }
184
+ case 'service':
185
+ return { text: 'record.kind.service', icon: 'matCode' }
186
+ default:
187
+ return { text: '', icon: '' }
188
+ }
189
+ }
190
+ }
@@ -1,7 +1,9 @@
1
- <div *ngIf="metadataQualityDisplay" class="mb-6 metadata-quality">
1
+ <div *ngIf="metadataQualityDisplay" class="metadata-quality">
2
2
  <div
3
3
  class="flex items-center"
4
- [class]="smaller ? 'leading-[8px] min-w-[120px]' : 'min-w-[200px]'"
4
+ [class]="
5
+ smaller ? 'leading-[8px] min-w-[120px] m-h-[120px]' : 'min-w-[200px]'
6
+ "
5
7
  >
6
8
  <gn-ui-progress-bar
7
9
  tabindex="0"
@@ -20,6 +20,7 @@ import { ThumbnailComponent } from './thumbnail/thumbnail.component'
20
20
  import { TimeSincePipe } from './user-feedback-item/time-since.pipe'
21
21
  import { UserPreviewComponent } from './user-preview/user-preview.component'
22
22
  import { ApplicationBannerComponent } from './application-banner/application-banner.component'
23
+ import { InternalLinkCardComponent } from './internal-link-card/internal-link-card.component'
23
24
 
24
25
  @NgModule({
25
26
  imports: [
@@ -42,6 +43,7 @@ import { ApplicationBannerComponent } from './application-banner/application-ban
42
43
  TextInputComponent,
43
44
  ImageInputComponent,
44
45
  ApplicationBannerComponent,
46
+ InternalLinkCardComponent,
45
47
  ],
46
48
  providers: [
47
49
  provideNgIconsConfig({
@@ -56,6 +58,7 @@ import { ApplicationBannerComponent } from './application-banner/application-ban
56
58
  MarkdownParserComponent,
57
59
  ImageInputComponent,
58
60
  ApplicationBannerComponent,
61
+ InternalLinkCardComponent,
59
62
  ],
60
63
  })
61
64
  export class UiElementsModule {}
@@ -8,11 +8,11 @@
8
8
  >
9
9
  {{ progress }}%
10
10
  </div>
11
- <div class="flex-grow h-[6px] w-full {{ color.outerBar }} rounded-full">
11
+ <div class="flex-grow h-[4px] w-[52px] {{ color.outerBar }} rounded-full">
12
12
  <div
13
13
  [style.width.%]="progress"
14
14
  class="{{ color.innerBar }} transition-width duration-500
15
- ease-in-out rounded-full shadow-sm h-full"
15
+ ease-in-out rounded-full shadow-sm w-[52px] h-[4px]"
16
16
  ></div>
17
17
  </div>
18
18
  </div>
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "": "",
3
3
  "Add Layer As": "",
4
+ "Enter to search": "",
4
5
  "button.login": "",
5
6
  "catalog.figures.datasets": "{count, plural, =0{Datensätze} one{Datensatz} other{Datensätze}}",
6
7
  "catalog.figures.organizations": "{count, plural, =0{Organisationen} one{Organisation} other{Organisationen}}",
@@ -354,8 +355,12 @@
354
355
  "record.action.duplicating": "",
355
356
  "record.action.rollback": "",
356
357
  "record.action.view": "Anzeigen",
358
+ "record.card.metadata.contact": "",
357
359
  "record.externalViewer.open": "In externem Kartenviewer öffnen",
358
360
  "record.feature.limit": "Die Vorschau wurde aufgrund zu vieler Elemente deaktiviert",
361
+ "record.kind.dataset": "",
362
+ "record.kind.reuse": "",
363
+ "record.kind.service": "",
359
364
  "record.metadata.about": "Beschreibung",
360
365
  "record.metadata.api": "API",
361
366
  "record.metadata.api.form.closeButton": "Schließen",
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "": "",
3
3
  "Add Layer As": "",
4
+ "Enter to search": "",
4
5
  "button.login": "Log in",
5
6
  "catalog.figures.datasets": "{count, plural, =0{datasets} one{dataset} other{datasets}}",
6
7
  "catalog.figures.organizations": "{count, plural, =0{organizations} one{organization} other{organizations}}",
@@ -354,8 +355,12 @@
354
355
  "record.action.duplicating": "Duplicating...",
355
356
  "record.action.rollback": "Rollback",
356
357
  "record.action.view": "View",
358
+ "record.card.metadata.contact": "Metadata Contact",
357
359
  "record.externalViewer.open": "Open in the external map viewer",
358
360
  "record.feature.limit": "Preview disabled due to too many elements",
361
+ "record.kind.dataset": "Data",
362
+ "record.kind.reuse": "Reuse",
363
+ "record.kind.service": "Service",
359
364
  "record.metadata.about": "Description",
360
365
  "record.metadata.api": "API",
361
366
  "record.metadata.api.form.closeButton": "Close",
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "": "",
3
3
  "Add Layer As": "",
4
+ "Enter to search": "",
4
5
  "button.login": "",
5
6
  "catalog.figures.datasets": "conjuntos de datos",
6
7
  "catalog.figures.organizations": "organizaciones",
@@ -354,8 +355,12 @@
354
355
  "record.action.duplicating": "",
355
356
  "record.action.rollback": "",
356
357
  "record.action.view": "",
358
+ "record.card.metadata.contact": "",
357
359
  "record.externalViewer.open": "",
358
360
  "record.feature.limit": "",
361
+ "record.kind.dataset": "",
362
+ "record.kind.reuse": "",
363
+ "record.kind.service": "",
359
364
  "record.metadata.about": "",
360
365
  "record.metadata.api": "",
361
366
  "record.metadata.api.form.closeButton": "",
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "": "",
3
3
  "Add Layer As": "",
4
+ "Enter to search": "",
4
5
  "button.login": "Se connecter",
5
6
  "catalog.figures.datasets": "{count, plural, =0{données} one{donnée} other{données}}",
6
7
  "catalog.figures.organizations": "{count, plural, =0{organisations} one{organisation} other{organisations}}",
@@ -354,8 +355,12 @@
354
355
  "record.action.duplicating": "Duplication...",
355
356
  "record.action.rollback": "Restaurer",
356
357
  "record.action.view": "Voir",
358
+ "record.card.metadata.contact": "Contact de la métadonnée ",
357
359
  "record.externalViewer.open": "Ouvrir dans le visualiseur externe",
358
360
  "record.feature.limit": "L’aperçu a été désactivé en raison d’un trop grand nombre d'éléments",
361
+ "record.kind.dataset": "Donnée",
362
+ "record.kind.reuse": "Réutilisation",
363
+ "record.kind.service": "Service",
359
364
  "record.metadata.about": "Description",
360
365
  "record.metadata.api": "API",
361
366
  "record.metadata.api.form.closeButton": "Fermer",
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "": "",
3
3
  "Add Layer As": "",
4
+ "Enter to search": "",
4
5
  "button.login": "Login",
5
6
  "catalog.figures.datasets": "{count, plural, =0{datasets} one{dataset} other{datasets}}",
6
7
  "catalog.figures.organizations": "{count, plural, =0{organizzazioni} one{organizzazione} other{organizzazioni}}",
@@ -354,8 +355,12 @@
354
355
  "record.action.duplicating": "Duplicazione",
355
356
  "record.action.rollback": "Annulla",
356
357
  "record.action.view": "Visualizza",
358
+ "record.card.metadata.contact": "",
357
359
  "record.externalViewer.open": "Aprire nel visualizzatore esterno",
358
360
  "record.feature.limit": "La visualizzazione è stata disabilitata a causa di troppi elementi ",
361
+ "record.kind.dataset": "",
362
+ "record.kind.reuse": "",
363
+ "record.kind.service": "",
359
364
  "record.metadata.about": "Descrizione",
360
365
  "record.metadata.api": "API",
361
366
  "record.metadata.api.form.closeButton": "Chiude",
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "": "",
3
3
  "Add Layer As": "",
4
+ "Enter to search": "",
4
5
  "button.login": "",
5
6
  "catalog.figures.datasets": "datasets",
6
7
  "catalog.figures.organizations": "organisaties",
@@ -354,8 +355,12 @@
354
355
  "record.action.duplicating": "",
355
356
  "record.action.rollback": "",
356
357
  "record.action.view": "",
358
+ "record.card.metadata.contact": "",
357
359
  "record.externalViewer.open": "",
358
360
  "record.feature.limit": "",
361
+ "record.kind.dataset": "",
362
+ "record.kind.reuse": "",
363
+ "record.kind.service": "",
359
364
  "record.metadata.about": "",
360
365
  "record.metadata.api": "",
361
366
  "record.metadata.api.form.closeButton": "",
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "": "",
3
3
  "Add Layer As": "",
4
+ "Enter to search": "",
4
5
  "button.login": "",
5
6
  "catalog.figures.datasets": "conjuntos de dados",
6
7
  "catalog.figures.organizations": "organizações",
@@ -354,8 +355,12 @@
354
355
  "record.action.duplicating": "",
355
356
  "record.action.rollback": "",
356
357
  "record.action.view": "",
358
+ "record.card.metadata.contact": "",
357
359
  "record.externalViewer.open": "",
358
360
  "record.feature.limit": "",
361
+ "record.kind.dataset": "",
362
+ "record.kind.reuse": "",
363
+ "record.kind.service": "",
359
364
  "record.metadata.about": "",
360
365
  "record.metadata.api": "",
361
366
  "record.metadata.api.form.closeButton": "",