geonetwork-ui 2.6.0-dev.502fa026d → 2.6.0-dev.582b4530a
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/esm2022/libs/api/metadata-converter/src/lib/gn4/gn4.field.mapper.mjs +6 -1
- package/esm2022/libs/common/domain/src/lib/model/record/metadata.model.mjs +1 -1
- package/esm2022/libs/feature/dataviz/src/lib/chart-view/chart-view.component.mjs +5 -1
- package/esm2022/libs/feature/dataviz/src/lib/table-view/table-view.component.mjs +5 -1
- package/esm2022/libs/feature/record/src/lib/map-view/map-view.component.mjs +6 -1
- package/esm2022/libs/feature/search/src/lib/favorites/favorite-star/favorite-star.component.mjs +3 -3
- package/esm2022/libs/ui/elements/src/index.mjs +2 -1
- package/esm2022/libs/ui/elements/src/lib/api-card/api-card.component.mjs +27 -6
- package/esm2022/libs/ui/elements/src/lib/download-item/download-item.component.mjs +22 -6
- package/esm2022/libs/ui/elements/src/lib/downloads-list/downloads-list.component.mjs +3 -3
- package/esm2022/libs/ui/elements/src/lib/internal-link-card/internal-link-card.component.mjs +163 -0
- package/esm2022/libs/ui/elements/src/lib/link-card/link-card.component.mjs +29 -7
- package/esm2022/libs/ui/elements/src/lib/metadata-catalog/metadata-catalog.component.mjs +3 -3
- package/esm2022/libs/ui/elements/src/lib/metadata-quality/metadata-quality.component.mjs +3 -3
- package/esm2022/libs/ui/elements/src/lib/record-api-form/record-api-form.component.mjs +3 -2
- package/esm2022/libs/ui/elements/src/lib/ui-elements.module.mjs +10 -4
- package/esm2022/libs/ui/layout/src/lib/carousel/carousel.component.mjs +3 -3
- package/esm2022/libs/ui/widgets/src/lib/progress-bar/progress-bar.component.mjs +3 -3
- package/esm2022/libs/util/shared/src/lib/links/link-utils.mjs +21 -19
- package/esm2022/translations/de.json +8 -0
- package/esm2022/translations/en.json +9 -1
- package/esm2022/translations/es.json +8 -0
- package/esm2022/translations/fr.json +8 -0
- package/esm2022/translations/it.json +8 -1
- package/esm2022/translations/nl.json +8 -0
- package/esm2022/translations/pt.json +8 -0
- package/fesm2022/geonetwork-ui.mjs +340 -55
- package/fesm2022/geonetwork-ui.mjs.map +1 -1
- package/libs/api/metadata-converter/src/lib/gn4/gn4.field.mapper.d.ts.map +1 -1
- package/libs/common/domain/src/lib/model/record/metadata.model.d.ts +4 -0
- package/libs/common/domain/src/lib/model/record/metadata.model.d.ts.map +1 -1
- package/libs/feature/dataviz/src/lib/chart-view/chart-view.component.d.ts.map +1 -1
- package/libs/feature/dataviz/src/lib/table-view/table-view.component.d.ts +1 -1
- package/libs/feature/dataviz/src/lib/table-view/table-view.component.d.ts.map +1 -1
- package/libs/feature/record/src/lib/map-view/map-view.component.d.ts.map +1 -1
- package/libs/ui/elements/src/index.d.ts +1 -0
- package/libs/ui/elements/src/index.d.ts.map +1 -1
- package/libs/ui/elements/src/lib/api-card/api-card.component.d.ts +9 -1
- package/libs/ui/elements/src/lib/api-card/api-card.component.d.ts.map +1 -1
- package/libs/ui/elements/src/lib/download-item/download-item.component.d.ts +8 -1
- package/libs/ui/elements/src/lib/download-item/download-item.component.d.ts.map +1 -1
- package/libs/ui/elements/src/lib/internal-link-card/internal-link-card.component.d.ts +43 -0
- package/libs/ui/elements/src/lib/internal-link-card/internal-link-card.component.d.ts.map +1 -0
- package/libs/ui/elements/src/lib/link-card/link-card.component.d.ts +10 -2
- package/libs/ui/elements/src/lib/link-card/link-card.component.d.ts.map +1 -1
- package/libs/ui/elements/src/lib/record-api-form/record-api-form.component.d.ts.map +1 -1
- package/libs/ui/elements/src/lib/ui-elements.module.d.ts +2 -1
- package/libs/ui/elements/src/lib/ui-elements.module.d.ts.map +1 -1
- package/libs/util/shared/src/lib/links/link-utils.d.ts +16 -16
- package/libs/util/shared/src/lib/links/link-utils.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/libs/api/metadata-converter/src/lib/gn4/gn4.field.mapper.ts +6 -0
- package/src/libs/common/domain/src/lib/model/record/metadata.model.ts +4 -0
- package/src/libs/feature/dataviz/src/lib/chart-view/chart-view.component.ts +4 -0
- package/src/libs/feature/dataviz/src/lib/table-view/table-view.component.ts +4 -0
- package/src/libs/feature/record/src/lib/map-view/map-view.component.ts +5 -0
- package/src/libs/feature/search/src/lib/favorites/favorite-star/favorite-star.component.html +1 -1
- package/src/libs/ui/elements/src/index.ts +1 -0
- package/src/libs/ui/elements/src/lib/api-card/api-card.component.html +64 -38
- package/src/libs/ui/elements/src/lib/api-card/api-card.component.ts +26 -2
- package/src/libs/ui/elements/src/lib/download-item/download-item.component.html +17 -17
- package/src/libs/ui/elements/src/lib/download-item/download-item.component.ts +20 -2
- package/src/libs/ui/elements/src/lib/downloads-list/downloads-list.component.html +7 -6
- package/src/libs/ui/elements/src/lib/internal-link-card/internal-link-card.component.css +0 -0
- package/src/libs/ui/elements/src/lib/internal-link-card/internal-link-card.component.html +156 -0
- package/src/libs/ui/elements/src/lib/internal-link-card/internal-link-card.component.ts +190 -0
- package/src/libs/ui/elements/src/lib/link-card/link-card.component.html +27 -29
- package/src/libs/ui/elements/src/lib/link-card/link-card.component.ts +33 -3
- package/src/libs/ui/elements/src/lib/metadata-catalog/metadata-catalog.component.html +1 -1
- package/src/libs/ui/elements/src/lib/metadata-quality/metadata-quality.component.html +4 -2
- package/src/libs/ui/elements/src/lib/record-api-form/record-api-form.component.ts +2 -1
- package/src/libs/ui/elements/src/lib/ui-elements.module.ts +3 -0
- package/src/libs/ui/layout/src/lib/carousel/carousel.component.css +0 -4
- package/src/libs/ui/widgets/src/lib/progress-bar/progress-bar.component.html +2 -2
- package/src/libs/util/shared/src/lib/links/link-utils.ts +20 -18
- package/tailwind.base.css +34 -1
- package/translations/de.json +8 -0
- package/translations/en.json +9 -1
- package/translations/es.json +8 -0
- package/translations/fr.json +8 -0
- package/translations/it.json +8 -1
- package/translations/nl.json +8 -0
- package/translations/pt.json +8 -0
- package/translations/sk.json +8 -0
|
@@ -1,13 +1,66 @@
|
|
|
1
1
|
<div
|
|
2
|
-
class="group flex
|
|
2
|
+
class="group flex justify-between rounded filter overflow-hidden"
|
|
3
|
+
[ngClass]="cardClass"
|
|
3
4
|
>
|
|
4
|
-
<
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
<ng-container *ngIf="size !== 'S'">
|
|
6
|
+
<div>
|
|
7
|
+
<ng-container *ngTemplateOutlet="content"></ng-container>
|
|
8
|
+
</div>
|
|
9
|
+
<div class="flex items-center">
|
|
10
|
+
<ng-container *ngTemplateOutlet="buttons"></ng-container>
|
|
11
|
+
</div>
|
|
12
|
+
</ng-container>
|
|
13
|
+
<ng-container *ngIf="size === 'S'">
|
|
14
|
+
<ng-container *ngTemplateOutlet="content"></ng-container>
|
|
15
|
+
</ng-container>
|
|
16
|
+
</div>
|
|
17
|
+
|
|
18
|
+
<ng-template #buttons>
|
|
19
|
+
<div class="flex flex-row gap-2">
|
|
20
|
+
<gn-ui-copy-text-button
|
|
21
|
+
[text]="link.url"
|
|
22
|
+
[tooltipText]="'tooltip.url.copy' | translate"
|
|
23
|
+
[displayText]="false"
|
|
24
|
+
class="border border-gray-300 rounded-lg pt-1 px-2 h-[34px]"
|
|
25
|
+
></gn-ui-copy-text-button>
|
|
26
|
+
<button
|
|
27
|
+
*ngIf="displayApiFormButton"
|
|
28
|
+
type="button"
|
|
29
|
+
class="gn-ui-card-icon"
|
|
30
|
+
[ngClass]="{
|
|
31
|
+
'py-2 px-4 rounded-r-md bg-gray-400 hover:bg-gray-600 focus:bg-gray-800 text-white':
|
|
32
|
+
displayText,
|
|
33
|
+
}"
|
|
34
|
+
[matTooltip]="
|
|
35
|
+
!currentlyActive
|
|
36
|
+
? ('record.metadata.api.form.openForm' | translate)
|
|
37
|
+
: ('record.metadata.api.form.closeForm' | translate)
|
|
38
|
+
"
|
|
39
|
+
matTooltipPosition="above"
|
|
40
|
+
(click)="openRecordApiFormPanel()"
|
|
41
|
+
>
|
|
42
|
+
<ng-icon
|
|
43
|
+
class="pointer-events-none align-middle card-icon"
|
|
44
|
+
name="iconoirSettings"
|
|
45
|
+
[ngClass]="{
|
|
46
|
+
'text-secondary opacity-100': currentlyActive,
|
|
47
|
+
}"
|
|
48
|
+
></ng-icon>
|
|
49
|
+
</button>
|
|
8
50
|
</div>
|
|
9
|
-
|
|
10
|
-
|
|
51
|
+
</ng-template>
|
|
52
|
+
|
|
53
|
+
<ng-template #content>
|
|
54
|
+
<div>
|
|
55
|
+
<div class="gn-ui-card-title">
|
|
56
|
+
{{ link.description || link.name }}
|
|
57
|
+
</div>
|
|
58
|
+
<div class="gn-ui-card-detail">
|
|
59
|
+
{{ link.name }}
|
|
60
|
+
</div>
|
|
61
|
+
</div>
|
|
62
|
+
<div class="flex flex-row justify-between">
|
|
63
|
+
<div class="flex flex-row gap-2.5 items-center pt-1">
|
|
11
64
|
<span
|
|
12
65
|
*ngIf="link.accessServiceProtocol !== 'GPFDL'"
|
|
13
66
|
class="bg-primary-opacity-50 uppercase inline-flex items-center justify-center px-2 py-1 text-13 font-medium leading-none text-white rounded text-primary-lightest group-hover:bg-primary transition-colors"
|
|
@@ -26,36 +79,9 @@
|
|
|
26
79
|
>
|
|
27
80
|
record.metadata.api.gpfdl</span
|
|
28
81
|
>
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
[tooltipText]="'tooltip.url.copy' | translate"
|
|
33
|
-
[displayText]="false"
|
|
34
|
-
></gn-ui-copy-text-button>
|
|
35
|
-
<button
|
|
36
|
-
*ngIf="displayApiFormButton"
|
|
37
|
-
type="button"
|
|
38
|
-
[ngClass]="{
|
|
39
|
-
'py-2 px-4 rounded-r-md bg-gray-400 hover:bg-gray-600 focus:bg-gray-800 text-white':
|
|
40
|
-
displayText,
|
|
41
|
-
}"
|
|
42
|
-
[matTooltip]="
|
|
43
|
-
!currentlyActive
|
|
44
|
-
? ('record.metadata.api.form.openForm' | translate)
|
|
45
|
-
: ('record.metadata.api.form.closeForm' | translate)
|
|
46
|
-
"
|
|
47
|
-
matTooltipPosition="above"
|
|
48
|
-
(click)="openRecordApiFormPanel()"
|
|
49
|
-
>
|
|
50
|
-
<ng-icon
|
|
51
|
-
class="pointer-events-none align-middle card-icon"
|
|
52
|
-
name="matMoreHoriz"
|
|
53
|
-
[ngClass]="{
|
|
54
|
-
'text-secondary opacity-100': currentlyActive,
|
|
55
|
-
}"
|
|
56
|
-
></ng-icon>
|
|
57
|
-
</button>
|
|
58
|
-
</div>
|
|
82
|
+
</div>
|
|
83
|
+
<div *ngIf="size === 'S'">
|
|
84
|
+
<ng-container *ngTemplateOutlet="buttons"></ng-container>
|
|
59
85
|
</div>
|
|
60
86
|
</div>
|
|
61
|
-
</
|
|
87
|
+
</ng-template>
|
|
@@ -14,7 +14,9 @@ import { CopyTextButtonComponent } from '../../../../../../libs/ui/inputs/src'
|
|
|
14
14
|
import { TranslateModule } from '@ngx-translate/core'
|
|
15
15
|
import { MatTooltipModule } from '@angular/material/tooltip'
|
|
16
16
|
import { NgIcon, provideIcons } from '@ng-icons/core'
|
|
17
|
-
import {
|
|
17
|
+
import { iconoirSettings } from '@ng-icons/iconoir'
|
|
18
|
+
|
|
19
|
+
type CardSize = 'L' | 'M' | 'S' | 'XS'
|
|
18
20
|
|
|
19
21
|
@Component({
|
|
20
22
|
selector: 'gn-ui-api-card',
|
|
@@ -31,18 +33,40 @@ import { matMoreHoriz } from '@ng-icons/material-icons/baseline'
|
|
|
31
33
|
],
|
|
32
34
|
viewProviders: [
|
|
33
35
|
provideIcons({
|
|
34
|
-
|
|
36
|
+
iconoirSettings,
|
|
35
37
|
}),
|
|
36
38
|
],
|
|
37
39
|
})
|
|
38
40
|
export class ApiCardComponent implements OnInit, OnChanges {
|
|
41
|
+
private _size: 'L' | 'M' | 'S' | 'XS'
|
|
39
42
|
@Input() link: DatasetServiceDistribution
|
|
40
43
|
@Input() currentLink: DatasetServiceDistribution
|
|
44
|
+
private readonly sizeClassMap: Record<CardSize, string> = {
|
|
45
|
+
L: 'gn-ui-card-l py-2 px-5 flex-row',
|
|
46
|
+
M: 'gn-ui-card-m py-2 px-5 flex-row',
|
|
47
|
+
S: 'gn-ui-card-s p-4 flex-col',
|
|
48
|
+
XS: 'gn-ui-card-xs py-2 px-5 flex-row',
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
@Input() set size(value: CardSize) {
|
|
52
|
+
this._size = value
|
|
53
|
+
this.cardClass = this.sizeClassMap[value]
|
|
54
|
+
}
|
|
55
|
+
get size(): 'L' | 'M' | 'S' | 'XS' {
|
|
56
|
+
return this._size
|
|
57
|
+
}
|
|
58
|
+
cardClass = ''
|
|
41
59
|
displayApiFormButton: boolean
|
|
42
60
|
currentlyActive = false
|
|
43
61
|
@Output() openRecordApiForm: EventEmitter<DatasetServiceDistribution> =
|
|
44
62
|
new EventEmitter<DatasetServiceDistribution>()
|
|
45
63
|
|
|
64
|
+
get generatedText() {
|
|
65
|
+
return this.link.accessServiceProtocol === 'wfs'
|
|
66
|
+
? 'datahub.search.filter.generatedByWfs'
|
|
67
|
+
: 'datahub.search.filter.generatedByAPI'
|
|
68
|
+
}
|
|
69
|
+
|
|
46
70
|
ngOnInit() {
|
|
47
71
|
this.displayApiFormButton =
|
|
48
72
|
this.link.accessServiceProtocol === 'ogcFeatures' ||
|
|
@@ -1,36 +1,36 @@
|
|
|
1
1
|
<a
|
|
2
2
|
href="{{ link.url }}"
|
|
3
3
|
target="_blank"
|
|
4
|
-
class="group flex justify-between card-shadow
|
|
4
|
+
class="group flex flex-row justify-between card-shadow cursor-pointer rounded overflow-hidden"
|
|
5
5
|
rel="noopener"
|
|
6
|
+
[ngClass]="cardClass"
|
|
6
7
|
>
|
|
7
|
-
<div class="
|
|
8
|
-
<div
|
|
9
|
-
class="text-21 text-black truncate font-title w-11/12"
|
|
10
|
-
[title]="link.description || link.name"
|
|
11
|
-
>
|
|
8
|
+
<div class="flex flex-col justify-between">
|
|
9
|
+
<div class="gn-ui-card-title" [title]="link.description || link.name">
|
|
12
10
|
{{ link.description || link.name }}
|
|
13
11
|
</div>
|
|
14
|
-
<div class="
|
|
12
|
+
<div class="gn-ui-card-detail">
|
|
13
|
+
{{ link.name }}
|
|
14
|
+
</div>
|
|
15
|
+
<div class="flex flex-row gap-2 items-center pt-1">
|
|
15
16
|
<span
|
|
16
17
|
class="inline-flex items-center justify-center px-2 py-1 text-13 font-medium leading-none text-white rounded transition-opacity opacity-70 group-hover:opacity-100"
|
|
17
18
|
[style.background-color]="color"
|
|
18
19
|
data-cy="download-format"
|
|
19
20
|
>{{ format || ('downloads.format.unknown' | translate) }}</span
|
|
20
21
|
>
|
|
21
|
-
<span
|
|
22
|
-
class="pl-2 inline-flex items-center text-gray-800 text-sm"
|
|
23
|
-
*ngIf="isFromApi"
|
|
24
|
-
translate=""
|
|
22
|
+
<span class="text-gray-800 text-xs" *ngIf="isFromApi" translate=""
|
|
25
23
|
>datahub.search.filter.generatedByAPI</span
|
|
26
24
|
>
|
|
27
25
|
</div>
|
|
28
26
|
</div>
|
|
29
|
-
<div class="
|
|
30
|
-
<
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
27
|
+
<div class="flex" [ngClass]="size === 'S' ? 'items-end' : 'items-center'">
|
|
28
|
+
<div class="gn-ui-card-icon">
|
|
29
|
+
<ng-icon
|
|
30
|
+
class="inline-block card-icon align-middle"
|
|
31
|
+
name="iconoirDownload"
|
|
32
|
+
>
|
|
33
|
+
</ng-icon>
|
|
34
|
+
</div>
|
|
35
35
|
</div>
|
|
36
36
|
</a>
|
|
@@ -9,7 +9,9 @@ import { DatasetOnlineResource } from '../../../../../../libs/common/domain/src/
|
|
|
9
9
|
import { TranslateModule } from '@ngx-translate/core'
|
|
10
10
|
import { CommonModule } from '@angular/common'
|
|
11
11
|
import { NgIcon, provideIcons } from '@ng-icons/core'
|
|
12
|
-
import {
|
|
12
|
+
import { iconoirDownload } from '@ng-icons/iconoir'
|
|
13
|
+
|
|
14
|
+
type CardSize = 'L' | 'M' | 'S' | 'XS'
|
|
13
15
|
|
|
14
16
|
@Component({
|
|
15
17
|
selector: 'gn-ui-download-item',
|
|
@@ -20,15 +22,31 @@ import { matCloudDownloadOutline } from '@ng-icons/material-icons/outline'
|
|
|
20
22
|
standalone: true,
|
|
21
23
|
viewProviders: [
|
|
22
24
|
provideIcons({
|
|
23
|
-
|
|
25
|
+
iconoirDownload,
|
|
24
26
|
}),
|
|
25
27
|
],
|
|
26
28
|
})
|
|
27
29
|
export class DownloadItemComponent {
|
|
30
|
+
private _size: 'L' | 'M' | 'S' | 'XS'
|
|
28
31
|
@Input() link: DatasetOnlineResource
|
|
29
32
|
@Input() color: string
|
|
30
33
|
@Input() format: string
|
|
31
34
|
@Input() isFromApi: boolean
|
|
35
|
+
private readonly sizeClassMap: Record<CardSize, string> = {
|
|
36
|
+
L: 'gn-ui-card-l py-2 px-5',
|
|
37
|
+
M: 'gn-ui-card-m py-2 px-5',
|
|
38
|
+
S: 'gn-ui-card-s p-4',
|
|
39
|
+
XS: 'gn-ui-card-xs py-2 px-5',
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
@Input() set size(value: CardSize) {
|
|
43
|
+
this._size = value
|
|
44
|
+
this.cardClass = this.sizeClassMap[value]
|
|
45
|
+
}
|
|
46
|
+
get size(): 'L' | 'M' | 'S' | 'XS' {
|
|
47
|
+
return this._size
|
|
48
|
+
}
|
|
49
|
+
cardClass = ''
|
|
32
50
|
@Output() exportUrl = new EventEmitter<string>()
|
|
33
51
|
|
|
34
52
|
openUrl() {
|
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
<div
|
|
2
|
-
class="flex flex-wrap justify-between
|
|
2
|
+
class="flex flex-wrap justify-between items-center pb-4"
|
|
3
3
|
*ngIf="links && links.length > 0"
|
|
4
4
|
>
|
|
5
|
-
<
|
|
6
|
-
class="font-title text-
|
|
5
|
+
<div
|
|
6
|
+
class="font-title text-xl text-title font-medium mr-4 text-center sm:text-left"
|
|
7
7
|
translate
|
|
8
8
|
>
|
|
9
9
|
record.metadata.download
|
|
10
|
-
</
|
|
10
|
+
</div>
|
|
11
11
|
<div
|
|
12
|
-
class="flex flex-wrap justify-start sm:justify-end
|
|
12
|
+
class="flex flex-wrap justify-start sm:justify-end"
|
|
13
13
|
data-cy="download-format-filters"
|
|
14
14
|
>
|
|
15
15
|
<gn-ui-button
|
|
16
16
|
class="m-1 format-filter"
|
|
17
17
|
[extraClass]="
|
|
18
18
|
'!px-[12px] !py-[8px] !text-[15px]' +
|
|
19
|
-
(isFilterActive(format) ? ' opacity-100' : ' opacity-
|
|
19
|
+
(isFilterActive(format) ? ' opacity-100' : ' opacity-60')
|
|
20
20
|
"
|
|
21
21
|
(buttonClick)="toggleFilterFormat(format)"
|
|
22
22
|
[attr.data-format]="format"
|
|
@@ -28,6 +28,7 @@
|
|
|
28
28
|
</div>
|
|
29
29
|
<div class="mb-2 sm:mb-3" *ngFor="let link of filteredLinks">
|
|
30
30
|
<gn-ui-download-item
|
|
31
|
+
size="L"
|
|
31
32
|
[link]="link"
|
|
32
33
|
[color]="getLinkColor(link)"
|
|
33
34
|
[format]="getLinkFormat(link)"
|
|
File without changes
|
|
@@ -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
|
+
}
|