geonetwork-ui 2.2.0-dev.5b8d393f → 2.2.0-dev.6332307a

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 (232) hide show
  1. package/esm2022/libs/api/metadata-converter/src/lib/gn4/atomic-operations.mjs +27 -1
  2. package/esm2022/libs/api/metadata-converter/src/lib/gn4/gn4.field.mapper.mjs +64 -61
  3. package/esm2022/libs/api/metadata-converter/src/lib/gn4/gn4.metadata.mapper.mjs +7 -4
  4. package/esm2022/libs/api/metadata-converter/src/lib/gn4/types/metadata.model.mjs +1 -1
  5. package/esm2022/libs/api/metadata-converter/src/lib/iso19139/codelists/keyword.mapper.mjs +14 -0
  6. package/esm2022/libs/api/metadata-converter/src/lib/iso19139/converter.mjs +25 -17
  7. package/esm2022/libs/api/metadata-converter/src/lib/iso19139/read-parts.mjs +55 -23
  8. package/esm2022/libs/api/metadata-converter/src/lib/iso19139/write-parts.mjs +52 -32
  9. package/esm2022/libs/api/repository/src/lib/gn4/elasticsearch/elasticsearch.service.mjs +2 -2
  10. package/esm2022/libs/api/repository/src/lib/gn4/organizations/organizations-from-metadata.service.mjs +10 -3
  11. package/esm2022/libs/api/repository/src/lib/gn4/platform/gn4-platform.mapper.mjs +14 -5
  12. package/esm2022/libs/api/repository/src/lib/gn4/platform/gn4-platform.service.mjs +33 -8
  13. package/esm2022/libs/common/domain/src/lib/model/record/metadata.model.mjs +1 -1
  14. package/esm2022/libs/common/domain/src/lib/model/search/aggregation.model.mjs +1 -1
  15. package/esm2022/libs/common/domain/src/lib/model/search/field.model.mjs +2 -0
  16. package/esm2022/libs/common/domain/src/lib/model/search/filter.model.mjs +1 -1
  17. package/esm2022/libs/common/domain/src/lib/model/search/index.mjs +2 -1
  18. package/esm2022/libs/common/domain/src/lib/model/search/search.model.mjs +1 -1
  19. package/esm2022/libs/common/domain/src/lib/model/thesaurus/thesaurus.model.mjs +1 -1
  20. package/esm2022/libs/common/domain/src/lib/platform.service.interface.mjs +1 -1
  21. package/esm2022/libs/feature/map/src/lib/map-context/map-context.service.mjs +9 -1
  22. package/esm2022/libs/feature/record/src/lib/state/mdview.reducer.mjs +2 -2
  23. package/esm2022/libs/feature/search/src/index.mjs +3 -1
  24. package/esm2022/libs/feature/search/src/lib/favorites/favorite-star/favorite-star.component.mjs +3 -3
  25. package/esm2022/libs/feature/search/src/lib/feature-search.module.mjs +2 -6
  26. package/esm2022/libs/feature/search/src/lib/filter-geometry.token.mjs +4 -0
  27. package/esm2022/libs/feature/search/src/lib/fuzzy-search/fuzzy-search.component.mjs +7 -3
  28. package/esm2022/libs/feature/search/src/lib/record-url.token.mjs +4 -0
  29. package/esm2022/libs/feature/search/src/lib/results-list/results-list.container.component.mjs +2 -2
  30. package/esm2022/libs/feature/search/src/lib/results-table/results-table.component.mjs +3 -4
  31. package/esm2022/libs/feature/search/src/lib/state/effects.mjs +2 -2
  32. package/esm2022/libs/feature/search/src/lib/state/search.facade.mjs +3 -2
  33. package/esm2022/libs/feature/search/src/lib/utils/service/fields.mjs +41 -26
  34. package/esm2022/libs/feature/search/src/lib/utils/service/fields.service.mjs +11 -9
  35. package/esm2022/libs/ui/catalog/src/lib/language-switcher/language-switcher.component.mjs +3 -3
  36. package/esm2022/libs/ui/elements/src/lib/markdown-parser/markdown-parser.component.mjs +3 -3
  37. package/esm2022/libs/ui/elements/src/lib/max-lines/max-lines.component.mjs +5 -3
  38. package/esm2022/libs/ui/elements/src/lib/metadata-contact/metadata-contact.component.mjs +3 -3
  39. package/esm2022/libs/ui/elements/src/lib/metadata-info/metadata-info.component.mjs +47 -22
  40. package/esm2022/libs/ui/elements/src/lib/metadata-quality/metadata-quality.component.mjs +3 -4
  41. package/esm2022/libs/ui/elements/src/lib/record-api-form/record-api-form.component.mjs +9 -6
  42. package/esm2022/libs/ui/elements/src/lib/thumbnail/thumbnail.component.mjs +3 -3
  43. package/esm2022/libs/ui/elements/src/lib/ui-elements.module.mjs +4 -4
  44. package/esm2022/libs/ui/inputs/src/lib/button/button.component.mjs +3 -3
  45. package/esm2022/libs/ui/inputs/src/lib/dropdown-multiselect/dropdown-multiselect.component.mjs +3 -3
  46. package/esm2022/libs/ui/inputs/src/lib/dropdown-selector/dropdown-selector.component.mjs +3 -3
  47. package/esm2022/libs/ui/inputs/src/lib/navigation-button/navigation-button.component.mjs +3 -3
  48. package/esm2022/libs/ui/inputs/src/lib/text-area/text-area.component.mjs +3 -3
  49. package/esm2022/libs/ui/inputs/src/lib/ui-inputs.module.mjs +6 -6
  50. package/esm2022/libs/ui/layout/src/lib/carousel/carousel.component.mjs +3 -3
  51. package/esm2022/libs/util/i18n/src/index.mjs +1 -2
  52. package/esm2022/libs/util/i18n/src/lib/i18n.constants.mjs +18 -1
  53. package/esm2022/libs/util/shared/src/lib/utils/index.mjs +2 -1
  54. package/esm2022/libs/util/shared/src/lib/utils/temporal-extent-union.mjs +32 -0
  55. package/esm2022/translations/de.json +35 -26
  56. package/esm2022/translations/en.json +35 -26
  57. package/esm2022/translations/es.json +29 -20
  58. package/esm2022/translations/fr.json +48 -39
  59. package/esm2022/translations/it.json +42 -33
  60. package/esm2022/translations/nl.json +30 -21
  61. package/esm2022/translations/pt.json +29 -20
  62. package/fesm2022/geonetwork-ui.mjs +744 -560
  63. package/fesm2022/geonetwork-ui.mjs.map +1 -1
  64. package/libs/api/metadata-converter/src/lib/gn4/atomic-operations.d.ts +2 -0
  65. package/libs/api/metadata-converter/src/lib/gn4/atomic-operations.d.ts.map +1 -1
  66. package/libs/api/metadata-converter/src/lib/gn4/gn4.field.mapper.d.ts +0 -1
  67. package/libs/api/metadata-converter/src/lib/gn4/gn4.field.mapper.d.ts.map +1 -1
  68. package/libs/api/metadata-converter/src/lib/gn4/gn4.metadata.mapper.d.ts.map +1 -1
  69. package/libs/api/metadata-converter/src/lib/gn4/types/metadata.model.d.ts +4 -5
  70. package/libs/api/metadata-converter/src/lib/gn4/types/metadata.model.d.ts.map +1 -1
  71. package/libs/api/metadata-converter/src/lib/iso19139/codelists/keyword.mapper.d.ts +3 -0
  72. package/libs/api/metadata-converter/src/lib/iso19139/codelists/keyword.mapper.d.ts.map +1 -0
  73. package/libs/api/metadata-converter/src/lib/iso19139/converter.d.ts.map +1 -1
  74. package/libs/api/metadata-converter/src/lib/iso19139/read-parts.d.ts +7 -6
  75. package/libs/api/metadata-converter/src/lib/iso19139/read-parts.d.ts.map +1 -1
  76. package/libs/api/metadata-converter/src/lib/iso19139/write-parts.d.ts +4 -3
  77. package/libs/api/metadata-converter/src/lib/iso19139/write-parts.d.ts.map +1 -1
  78. package/libs/api/repository/src/lib/gn4/elasticsearch/elasticsearch.service.d.ts.map +1 -1
  79. package/libs/api/repository/src/lib/gn4/organizations/organizations-from-metadata.service.d.ts.map +1 -1
  80. package/libs/api/repository/src/lib/gn4/platform/gn4-platform.mapper.d.ts +1 -1
  81. package/libs/api/repository/src/lib/gn4/platform/gn4-platform.mapper.d.ts.map +1 -1
  82. package/libs/api/repository/src/lib/gn4/platform/gn4-platform.service.d.ts +9 -2
  83. package/libs/api/repository/src/lib/gn4/platform/gn4-platform.service.d.ts.map +1 -1
  84. package/libs/common/domain/src/lib/model/record/metadata.model.d.ts +21 -12
  85. package/libs/common/domain/src/lib/model/record/metadata.model.d.ts.map +1 -1
  86. package/libs/common/domain/src/lib/model/search/aggregation.model.d.ts +1 -1
  87. package/libs/common/domain/src/lib/model/search/aggregation.model.d.ts.map +1 -1
  88. package/libs/common/domain/src/lib/model/search/field.model.d.ts +2 -0
  89. package/libs/common/domain/src/lib/model/search/field.model.d.ts.map +1 -0
  90. package/libs/common/domain/src/lib/model/search/filter.model.d.ts +1 -1
  91. package/libs/common/domain/src/lib/model/search/filter.model.d.ts.map +1 -1
  92. package/libs/common/domain/src/lib/model/search/index.d.ts +1 -0
  93. package/libs/common/domain/src/lib/model/search/index.d.ts.map +1 -1
  94. package/libs/common/domain/src/lib/model/search/search.model.d.ts +1 -1
  95. package/libs/common/domain/src/lib/model/search/search.model.d.ts.map +1 -1
  96. package/libs/common/domain/src/lib/model/thesaurus/thesaurus.model.d.ts +1 -0
  97. package/libs/common/domain/src/lib/model/thesaurus/thesaurus.model.d.ts.map +1 -1
  98. package/libs/common/domain/src/lib/platform.service.interface.d.ts +1 -1
  99. package/libs/common/domain/src/lib/platform.service.interface.d.ts.map +1 -1
  100. package/libs/feature/map/src/lib/map-context/map-context.service.d.ts +1 -0
  101. package/libs/feature/map/src/lib/map-context/map-context.service.d.ts.map +1 -1
  102. package/libs/feature/search/src/index.d.ts +2 -0
  103. package/libs/feature/search/src/index.d.ts.map +1 -1
  104. package/libs/feature/search/src/lib/feature-search.module.d.ts +0 -4
  105. package/libs/feature/search/src/lib/feature-search.module.d.ts.map +1 -1
  106. package/libs/feature/search/src/lib/filter-geometry.token.d.ts +4 -0
  107. package/libs/feature/search/src/lib/filter-geometry.token.d.ts.map +1 -0
  108. package/libs/feature/search/src/lib/fuzzy-search/fuzzy-search.component.d.ts +1 -1
  109. package/libs/feature/search/src/lib/fuzzy-search/fuzzy-search.component.d.ts.map +1 -1
  110. package/libs/feature/search/src/lib/record-url.token.d.ts +3 -0
  111. package/libs/feature/search/src/lib/record-url.token.d.ts.map +1 -0
  112. package/libs/feature/search/src/lib/results-table/results-table.component.d.ts +0 -1
  113. package/libs/feature/search/src/lib/results-table/results-table.component.d.ts.map +1 -1
  114. package/libs/feature/search/src/lib/state/search.facade.d.ts +1 -1
  115. package/libs/feature/search/src/lib/state/search.facade.d.ts.map +1 -1
  116. package/libs/feature/search/src/lib/utils/service/fields.d.ts +21 -8
  117. package/libs/feature/search/src/lib/utils/service/fields.d.ts.map +1 -1
  118. package/libs/feature/search/src/lib/utils/service/fields.service.d.ts.map +1 -1
  119. package/libs/ui/elements/src/lib/markdown-parser/markdown-parser.component.d.ts +1 -1
  120. package/libs/ui/elements/src/lib/markdown-parser/markdown-parser.component.d.ts.map +1 -1
  121. package/libs/ui/elements/src/lib/max-lines/max-lines.component.d.ts.map +1 -1
  122. package/libs/ui/elements/src/lib/metadata-info/metadata-info.component.d.ts +16 -6
  123. package/libs/ui/elements/src/lib/metadata-info/metadata-info.component.d.ts.map +1 -1
  124. package/libs/ui/elements/src/lib/metadata-quality/metadata-quality.component.d.ts.map +1 -1
  125. package/libs/ui/elements/src/lib/record-api-form/record-api-form.component.d.ts +3 -1
  126. package/libs/ui/elements/src/lib/record-api-form/record-api-form.component.d.ts.map +1 -1
  127. package/libs/ui/elements/src/lib/ui-elements.module.d.ts +13 -13
  128. package/libs/ui/inputs/src/lib/button/button.component.d.ts +1 -1
  129. package/libs/ui/inputs/src/lib/button/button.component.d.ts.map +1 -1
  130. package/libs/ui/inputs/src/lib/text-area/text-area.component.d.ts +1 -1
  131. package/libs/ui/inputs/src/lib/text-area/text-area.component.d.ts.map +1 -1
  132. package/libs/ui/inputs/src/lib/ui-inputs.module.d.ts +40 -40
  133. package/libs/ui/layout/src/lib/interactive-table/interactive-table-column/interactive-table-column.component.d.ts +1 -1
  134. package/libs/util/i18n/src/index.d.ts +0 -1
  135. package/libs/util/i18n/src/index.d.ts.map +1 -1
  136. package/libs/util/i18n/src/lib/i18n.constants.d.ts +17 -0
  137. package/libs/util/i18n/src/lib/i18n.constants.d.ts.map +1 -1
  138. package/libs/util/shared/src/lib/utils/index.d.ts +1 -0
  139. package/libs/util/shared/src/lib/utils/index.d.ts.map +1 -1
  140. package/libs/util/shared/src/lib/utils/temporal-extent-union.d.ts +5 -0
  141. package/libs/util/shared/src/lib/utils/temporal-extent-union.d.ts.map +1 -0
  142. package/package.json +2 -2
  143. package/src/libs/api/metadata-converter/src/lib/fixtures/generic.records.ts +63 -8
  144. package/src/libs/api/metadata-converter/src/lib/fixtures/geo2france.records.ts +57 -9
  145. package/src/libs/api/metadata-converter/src/lib/fixtures/geocat-ch.records.ts +229 -24
  146. package/src/libs/api/metadata-converter/src/lib/gn4/atomic-operations.ts +29 -0
  147. package/src/libs/api/metadata-converter/src/lib/gn4/gn4.field.mapper.ts +99 -76
  148. package/src/libs/api/metadata-converter/src/lib/gn4/gn4.metadata.mapper.ts +6 -3
  149. package/src/libs/api/metadata-converter/src/lib/gn4/types/metadata.model.ts +4 -5
  150. package/src/libs/api/metadata-converter/src/lib/iso19139/codelists/keyword.mapper.ts +16 -0
  151. package/src/libs/api/metadata-converter/src/lib/iso19139/converter.ts +30 -21
  152. package/src/libs/api/metadata-converter/src/lib/iso19139/read-parts.ts +120 -63
  153. package/src/libs/api/metadata-converter/src/lib/iso19139/write-parts.ts +177 -97
  154. package/src/libs/api/repository/src/lib/gn4/elasticsearch/elasticsearch.service.ts +1 -1
  155. package/src/libs/api/repository/src/lib/gn4/organizations/organizations-from-metadata.service.ts +22 -2
  156. package/src/libs/api/repository/src/lib/gn4/platform/gn4-platform.mapper.ts +15 -4
  157. package/src/libs/api/repository/src/lib/gn4/platform/gn4-platform.service.ts +47 -8
  158. package/src/libs/common/domain/src/lib/model/record/metadata.model.ts +25 -14
  159. package/src/libs/common/domain/src/lib/model/search/aggregation.model.ts +1 -1
  160. package/src/libs/common/domain/src/lib/model/search/field.model.ts +1 -0
  161. package/src/libs/common/domain/src/lib/model/search/filter.model.ts +1 -1
  162. package/src/libs/common/domain/src/lib/model/search/index.ts +1 -0
  163. package/src/libs/common/domain/src/lib/model/search/search.model.ts +1 -1
  164. package/src/libs/common/domain/src/lib/model/thesaurus/thesaurus.model.ts +1 -0
  165. package/src/libs/common/domain/src/lib/platform.service.interface.ts +1 -4
  166. package/src/libs/common/fixtures/src/lib/elasticsearch/full-response.ts +1 -1
  167. package/src/libs/common/fixtures/src/lib/gn4/groups.fixtures.ts +1 -1
  168. package/src/libs/common/fixtures/src/lib/records.fixtures.ts +52 -10
  169. package/src/libs/feature/map/src/lib/map-context/map-context.service.ts +10 -0
  170. package/src/libs/feature/record/src/lib/state/mdview.reducer.ts +1 -1
  171. package/src/libs/feature/search/src/index.ts +2 -0
  172. package/src/libs/feature/search/src/lib/favorites/favorite-star/favorite-star.component.html +3 -4
  173. package/src/libs/feature/search/src/lib/feature-search.module.ts +1 -10
  174. package/src/libs/feature/search/src/lib/filter-geometry.token.ts +7 -0
  175. package/src/libs/feature/search/src/lib/fuzzy-search/fuzzy-search.component.ts +9 -3
  176. package/src/libs/feature/search/src/lib/record-url.token.ts +4 -0
  177. package/src/libs/feature/search/src/lib/results-list/results-list.container.component.ts +1 -1
  178. package/src/libs/feature/search/src/lib/results-table/results-table.component.html +104 -127
  179. package/src/libs/feature/search/src/lib/results-table/results-table.component.ts +0 -1
  180. package/src/libs/feature/search/src/lib/state/effects.ts +1 -1
  181. package/src/libs/feature/search/src/lib/state/search.facade.ts +2 -1
  182. package/src/libs/feature/search/src/lib/utils/service/fields.service.ts +21 -16
  183. package/src/libs/feature/search/src/lib/utils/service/fields.ts +43 -34
  184. package/src/libs/ui/catalog/src/lib/language-switcher/language-switcher.component.html +1 -1
  185. package/src/libs/ui/elements/src/lib/markdown-editor/markdown-editor.component.css +5 -0
  186. package/src/libs/ui/elements/src/lib/markdown-editor/markdown-editor.component.html +39 -0
  187. package/src/libs/ui/elements/src/lib/markdown-editor/markdown-editor.component.ts +58 -0
  188. package/src/libs/ui/elements/src/lib/markdown-parser/markdown-parser.component.css +2 -2
  189. package/src/libs/ui/elements/src/lib/markdown-parser/markdown-parser.component.ts +1 -0
  190. package/src/libs/ui/elements/src/lib/max-lines/max-lines.component.html +5 -1
  191. package/src/libs/ui/elements/src/lib/max-lines/max-lines.component.ts +1 -0
  192. package/src/libs/ui/elements/src/lib/metadata-contact/metadata-contact.component.html +1 -1
  193. package/src/libs/ui/elements/src/lib/metadata-info/metadata-info.component.html +157 -42
  194. package/src/libs/ui/elements/src/lib/metadata-info/metadata-info.component.ts +51 -15
  195. package/src/libs/ui/elements/src/lib/metadata-quality/metadata-quality.component.ts +2 -3
  196. package/src/libs/ui/elements/src/lib/record-api-form/record-api-form.component.html +5 -5
  197. package/src/libs/ui/elements/src/lib/record-api-form/record-api-form.component.ts +12 -4
  198. package/src/libs/ui/elements/src/lib/thumbnail/thumbnail.component.html +2 -2
  199. package/src/libs/ui/elements/src/lib/ui-elements.module.ts +1 -1
  200. package/src/libs/ui/inputs/src/lib/button/button.component.ts +1 -0
  201. package/src/libs/ui/inputs/src/lib/dropdown-multiselect/dropdown-multiselect.component.html +1 -1
  202. package/src/libs/ui/inputs/src/lib/dropdown-selector/dropdown-selector.component.html +3 -1
  203. package/src/libs/ui/inputs/src/lib/navigation-button/navigation-button.component.css +3 -0
  204. package/src/libs/ui/inputs/src/lib/navigation-button/navigation-button.component.html +1 -1
  205. package/src/libs/ui/inputs/src/lib/text-area/text-area.component.ts +1 -0
  206. package/src/libs/ui/inputs/src/lib/ui-inputs.module.ts +2 -2
  207. package/src/libs/ui/layout/src/lib/carousel/carousel.component.html +1 -0
  208. package/src/libs/util/i18n/src/index.ts +0 -1
  209. package/src/libs/util/i18n/src/lib/i18n.constants.ts +18 -0
  210. package/src/libs/util/shared/src/lib/utils/index.ts +1 -0
  211. package/src/libs/util/shared/src/lib/utils/temporal-extent-union.ts +32 -0
  212. package/tailwind.base.css +2 -2
  213. package/translations/de.json +35 -26
  214. package/translations/en.json +35 -26
  215. package/translations/es.json +29 -20
  216. package/translations/fr.json +48 -39
  217. package/translations/it.json +42 -33
  218. package/translations/nl.json +30 -21
  219. package/translations/pt.json +29 -20
  220. package/translations/sk.json +30 -21
  221. package/esm2022/libs/util/i18n/src/lib/testing/test.translate.loader.mjs +0 -24
  222. package/esm2022/libs/util/i18n/src/lib/testing/test.translate.module.mjs +0 -109
  223. package/esm2022/libs/util/i18n/src/lib/testing/translations.model.mjs +0 -6
  224. package/libs/util/i18n/src/lib/testing/test.translate.loader.d.ts +0 -17
  225. package/libs/util/i18n/src/lib/testing/test.translate.loader.d.ts.map +0 -1
  226. package/libs/util/i18n/src/lib/testing/test.translate.module.d.ts +0 -131
  227. package/libs/util/i18n/src/lib/testing/test.translate.module.d.ts.map +0 -1
  228. package/libs/util/i18n/src/lib/testing/translations.model.d.ts +0 -21
  229. package/libs/util/i18n/src/lib/testing/translations.model.d.ts.map +0 -1
  230. package/src/libs/util/i18n/src/lib/testing/test.translate.loader.ts +0 -26
  231. package/src/libs/util/i18n/src/lib/testing/test.translate.module.ts +0 -235
  232. package/src/libs/util/i18n/src/lib/testing/translations.model.ts +0 -28
@@ -78,6 +78,7 @@ export class MaxLinesComponent implements AfterViewInit, OnDestroy {
78
78
  }
79
79
 
80
80
  ngOnDestroy(): void {
81
+ if (!this.observer) return
81
82
  this.observer.unobserve(this.container.nativeElement.children[0])
82
83
  }
83
84
  }
@@ -1,5 +1,5 @@
1
1
  <div class="py-5 px-5 rounded bg-gray-100 text-black mb-6">
2
- <div class="grid gap-3">
2
+ <div class="grid gap-3 overflow-hidden">
3
3
  <div>
4
4
  <p class="text-sm font-medium" translate>record.metadata.contact</p>
5
5
  </div>
@@ -10,30 +10,127 @@
10
10
  </gn-ui-content-ghost>
11
11
  </div>
12
12
 
13
+ <gn-ui-expandable-panel [title]="'record.metadata.usage' | translate">
14
+ <div class="flex flex-col gap-[10px] mr-4 py-[12px] rounded text-gray-900">
15
+ <ng-container *ngFor="let license of licenses">
16
+ <div *ngIf="license.url; else noUrl" class="text-primary">
17
+ <a
18
+ [href]="license.url"
19
+ target="_blank"
20
+ class="cursor-pointer hover:underline transition-all"
21
+ >
22
+ {{ license.text }}
23
+ <mat-icon
24
+ class="material-symbols-outlined !w-[12px] !h-[12px] !text-[12px] opacity-75 shrink-0"
25
+ >open_in_new</mat-icon
26
+ >
27
+ </a>
28
+ </div>
29
+ <ng-template #noUrl>
30
+ <div class="text-primary" gnUiLinkify>
31
+ {{ license.text }}
32
+ </div>
33
+ </ng-template>
34
+ </ng-container>
35
+ <ng-container *ngIf="legalConstraints.length">
36
+ <gn-ui-markdown-parser
37
+ *ngFor="let constraint of legalConstraints"
38
+ [textContent]="constraint"
39
+ >
40
+ </gn-ui-markdown-parser>
41
+ </ng-container>
42
+ <ng-container *ngIf="otherConstraints.length">
43
+ <div gnUiLinkify *ngFor="let constraint of otherConstraints">
44
+ <h5 translate class="font-medium text-black text-sm mb-[2px] mt-[16px]">
45
+ record.metadata.otherConstraints
46
+ </h5>
47
+ <gn-ui-markdown-parser [textContent]="constraint">
48
+ </gn-ui-markdown-parser>
49
+ </div>
50
+ </ng-container>
51
+
52
+ <span class="noUsage" *ngIf="!hasUsage">
53
+ {{ 'record.metadata.noUsage' | translate }}
54
+ </span>
55
+ </div>
56
+ </gn-ui-expandable-panel>
13
57
  <gn-ui-expandable-panel
14
- class="metadata-origin"
15
58
  *ngIf="
16
59
  metadata.lineage ||
17
60
  metadata.recordUpdated ||
18
61
  metadata.updateFrequency ||
19
62
  metadata.status
20
63
  "
21
- [title]="'record.metadata.origin' | translate"
64
+ [title]="'record.metadata.details' | translate"
22
65
  >
23
- <p
24
- *ngIf="metadata.lineage"
25
- class="mb-5 pt-4 whitespace-pre-line break-words"
26
- gnUiLinkify
27
- >
28
- {{ metadata.lineage }}
29
- </p>
66
+ <div *ngIf="metadata.lineage" class="text-gray-900 flex flex-col mt-4 gap-2">
67
+ <p class="whitespace-pre-line break-words text-gray-900" gnUiLinkify>
68
+ {{ metadata.lineage }}
69
+ </p>
70
+ </div>
71
+ <div class="flex flex-row gap-6 mt-5 mb-8" *ngIf="resourceContact">
72
+ <div
73
+ *ngIf="resourceContact.organization?.logoUrl?.href"
74
+ class="flex items-center justify-center border-solid border border-gray-300 rounded-md bg-white h-32 overflow-hidden"
75
+ >
76
+ <gn-ui-thumbnail
77
+ class="relative h-full w-full"
78
+ [thumbnailUrl]="resourceContact.organization.logoUrl.href"
79
+ fit="contain"
80
+ ></gn-ui-thumbnail>
81
+ </div>
82
+ <div class="flex flex-col gap-1">
83
+ <p class="text-sm font-medium" translate>record.metadata.producer</p>
84
+ <div
85
+ class="text-primary font-title text-21 mr-2 cursor-pointer hover:underline"
86
+ data-cy="organization-name"
87
+ >
88
+ {{ resourceContact.organization?.name }}
89
+ </div>
90
+ <div *ngIf="resourceContact.organization?.website">
91
+ <a
92
+ [href]="resourceContact.organization.website"
93
+ target="_blank"
94
+ class="contact-website text-primary text-sm cursor-pointer hover:underline transition-all"
95
+ >{{ resourceContact.organization.website }}
96
+ <mat-icon
97
+ class="material-symbols-outlined !w-[12px] !h-[12px] !text-[12px] opacity-75 shrink-0"
98
+ >open_in_new</mat-icon
99
+ >
100
+ </a>
101
+ </div>
102
+ <div class="mt-4" *ngIf="resourceContact.email">
103
+ <div class="flex">
104
+ <mat-icon
105
+ class="material-symbols-outlined !w-5 !h-5 !text-[20px] opacity-75 shrink-0"
106
+ >
107
+ mail_outline</mat-icon
108
+ >
109
+ <a
110
+ *ngIf="resourceContact.email"
111
+ [href]="'mailto:' + resourceContact.email"
112
+ class="text-sm hover:underline ml-2"
113
+ target="_blank"
114
+ data-cy="contact-email"
115
+ >{{ resourceContact?.email }}</a
116
+ >
117
+ </div>
118
+ </div>
119
+ </div>
120
+ </div>
30
121
  <div
31
- class="py-4 px-6 rounded bg-gray-100 grid grid-cols-2 gap-y-[10px] gap-x-[20px] text-gray-700 info-grid"
122
+ class="py-6 px-6 rounded bg-gray-100 grid grid-cols-2 gap-y-6 gap-x-[20px] text-gray-700"
32
123
  >
33
- <div *ngIf="metadata.recordUpdated">
34
- <p class="text-sm" translate>record.metadata.updatedOn</p>
124
+ <div *ngIf="metadata.recordCreated">
125
+ <p class="text-sm" translate>record.metadata.creation</p>
35
126
  <p class="text-primary font-medium mt-1">
36
- {{ metadata.recordUpdated && metadata.recordUpdated.toLocaleString() }}
127
+ {{ metadata.recordCreated.toLocaleDateString() }}
128
+ </p>
129
+ </div>
130
+ <div *ngIf="metadata.recordPublished">
131
+ <p class="text-sm" translate>record.metadata.publication</p>
132
+ <p class="text-primary font-medium mt-1">
133
+ {{ metadata.recordPublished.toLocaleDateString() }}
37
134
  </p>
38
135
  </div>
39
136
  <div *ngIf="updateFrequency">
@@ -46,34 +143,52 @@
46
143
  {{ updateFrequency }}
47
144
  </p>
48
145
  </div>
49
- <div *ngIf="metadata.status">
50
- <p class="text-sm" translate>record.metadata.updateStatus</p>
51
- <p class="text-primary font-medium mt-1" translate>
52
- domain.record.status.{{ metadata.status }}
53
- </p>
146
+ <div *ngIf="metadata.languages">
147
+ <p class="text-sm mb-1" translate>record.metadata.languages</p>
148
+ <div class="flex flex-row gap-1 flex-wrap">
149
+ <p
150
+ class="text-primary font-medium"
151
+ translate
152
+ *ngFor="let language of metadata.languages"
153
+ >
154
+ language.{{ language }}
155
+ </p>
156
+ </div>
157
+ </div>
158
+ <div *ngIf="temporalExtent">
159
+ <p class="text-sm" translate>record.metadata.temporalExtent</p>
160
+ <div class="flex flex-row gap-1 mb-1 text-primary font-medium">
161
+ <p
162
+ *ngIf="temporalExtent.start && temporalExtent.end"
163
+ translate
164
+ [translateParams]="{
165
+ start: temporalExtent.start,
166
+ end: temporalExtent.end
167
+ }"
168
+ >
169
+ record.metadata.temporalExtent.fromDateToDate
170
+ </p>
171
+ <p
172
+ *ngIf="temporalExtent.start && !temporalExtent.end"
173
+ translate
174
+ [translateParams]="{ start: temporalExtent.start }"
175
+ >
176
+ record.metadata.temporalExtent.sinceDate
177
+ </p>
178
+ <p
179
+ *ngIf="!temporalExtent.start && temporalExtent.end"
180
+ translate
181
+ [translateParams]="{ end: temporalExtent.end }"
182
+ >
183
+ record.metadata.temporalExtent.untilDate
184
+ </p>
185
+ </div>
54
186
  </div>
55
- </div>
56
- </gn-ui-expandable-panel>
57
- <gn-ui-expandable-panel [title]="'record.metadata.usage' | translate">
58
- <div class="py-4 px-6 rounded bg-gray-100 text-gray-700 flex flex-wrap gap-2">
59
- <gn-ui-badge *ngIf="metadata.extras?.isOpenData">
60
- <span translate>record.metadata.isOpenData</span>
61
- </gn-ui-badge>
62
- <span
63
- class="text-primary font-medium"
64
- *ngFor="let usage of usages"
65
- gnUiLinkify
66
- >
67
- {{ usage }}
68
- </span>
69
- <span class="text-primary font-medium noUsage" *ngIf="!hasUsage">
70
- {{ 'record.metadata.noUsage' | translate }}
71
- </span>
72
187
  </div>
73
188
  </gn-ui-expandable-panel>
74
189
  <gn-ui-expandable-panel
75
190
  *ngIf="metadata.landingPage"
76
- [title]="'record.metadata.details' | translate"
191
+ [title]="'record.metadata.technical' | translate"
77
192
  >
78
193
  <div class="flex flex-col gap-4 mr-4 py-5 rounded text-gray-700">
79
194
  <div *ngIf="metadata.recordUpdated">
@@ -109,13 +224,13 @@
109
224
  </p>
110
225
  </div>
111
226
  </div>
112
- <div *ngIf="metadata.themes?.length">
113
- <p class="text-sm mb-1" translate>record.metadata.themes</p>
227
+ <div *ngIf="metadata.topics?.length">
228
+ <p class="text-sm mb-1" translate>record.metadata.topics</p>
114
229
  <div class="sm:pb-4 sm:pr-16">
115
230
  <gn-ui-badge
116
- class="inline-block mr-2 lowercase"
117
- *ngFor="let theme of metadata.themes"
118
- >{{ theme }}</gn-ui-badge
231
+ class="inline-block mr-2 mb-2 lowercase"
232
+ *ngFor="let topic of metadata.topics"
233
+ >{{ topic }}</gn-ui-badge
119
234
  >
120
235
  </div>
121
236
  </div>
@@ -127,7 +242,7 @@
127
242
  (click)="onKeywordClick(keyword)"
128
243
  [clickable]="true"
129
244
  *ngFor="let keyword of metadata.keywords"
130
- >{{ keyword }}</gn-ui-badge
245
+ >{{ keyword.label }}</gn-ui-badge
131
246
  >
132
247
  </div>
133
248
  </div>
@@ -5,7 +5,11 @@ import {
5
5
  Input,
6
6
  Output,
7
7
  } from '@angular/core'
8
- import { DatasetRecord } from '../../../../../../libs/common/domain/src/lib/model/record'
8
+ import {
9
+ DatasetRecord,
10
+ Keyword,
11
+ } from '../../../../../../libs/common/domain/src/lib/model/record'
12
+ import { getTemporalRangeUnion } from '../../../../../../libs/util/shared/src'
9
13
 
10
14
  @Component({
11
15
  selector: 'gn-ui-metadata-info',
@@ -16,24 +20,48 @@ import { DatasetRecord } from '../../../../../../libs/common/domain/src/lib/mode
16
20
  export class MetadataInfoComponent {
17
21
  @Input() metadata: Partial<DatasetRecord>
18
22
  @Input() incomplete: boolean
19
- @Output() keyword = new EventEmitter<string>()
23
+ @Output() keyword = new EventEmitter<Keyword>()
20
24
  updatedTimes: number
21
25
 
22
26
  get hasUsage() {
23
27
  return (
24
28
  this.metadata.extras?.isOpenData === true ||
25
- this.metadata.useLimitations?.length ||
26
- this.metadata.accessConstraints?.length
29
+ (this.metadata.legalConstraints?.length > 0 &&
30
+ this.legalConstraints.length > 0) ||
31
+ (this.metadata.otherConstraints?.length > 0 &&
32
+ this.otherConstraints.length > 0) ||
33
+ (this.metadata.licenses?.length > 0 && this.licenses.length > 0)
27
34
  )
28
35
  }
29
36
 
30
- get usages(): string[] {
37
+ get legalConstraints() {
31
38
  let array = []
32
- if (this.metadata.useLimitations?.length) {
33
- array = array.concat(this.metadata.useLimitations)
39
+ if (this.metadata.legalConstraints?.length) {
40
+ array = array.concat(
41
+ this.metadata.legalConstraints.filter((c) => c.text).map((c) => c.text)
42
+ )
34
43
  }
35
- if (this.metadata.accessConstraints?.length) {
36
- array = array.concat(this.metadata.accessConstraints.map((c) => c.text))
44
+ return array
45
+ }
46
+
47
+ get otherConstraints() {
48
+ let array = []
49
+ if (this.metadata.otherConstraints?.length) {
50
+ array = array.concat(
51
+ this.metadata.otherConstraints.filter((c) => c.text).map((c) => c.text)
52
+ )
53
+ }
54
+ return array
55
+ }
56
+
57
+ get licenses(): { text: string; url: string }[] {
58
+ let array = []
59
+ if (this.metadata.licenses?.length) {
60
+ array = array.concat(
61
+ this.metadata.licenses
62
+ .filter((c) => c.text)
63
+ .map((c) => ({ text: c.text, url: c.url }))
64
+ )
37
65
  }
38
66
  return array
39
67
  }
@@ -49,16 +77,24 @@ export class MetadataInfoComponent {
49
77
  }
50
78
  }
51
79
 
80
+ get temporalExtent(): { start: string; end: string } {
81
+ const temporalExtents = this.metadata.temporalExtents
82
+ return getTemporalRangeUnion(temporalExtents)
83
+ }
84
+
85
+ get shownOrganization() {
86
+ return this.metadata.ownerOrganization
87
+ }
88
+
89
+ get resourceContact() {
90
+ return this.metadata.contactsForResource?.[0]
91
+ }
92
+
52
93
  fieldReady(propName: string) {
53
94
  return !this.incomplete || propName in this.metadata
54
95
  }
55
96
 
56
- onKeywordClick(keyword: string) {
97
+ onKeywordClick(keyword: Keyword) {
57
98
  this.keyword.emit(keyword)
58
99
  }
59
-
60
- copyText() {
61
- navigator.clipboard.writeText(this.metadata.uniqueIdentifier)
62
- ;(event.target as HTMLElement).blur()
63
- }
64
100
  }
@@ -32,8 +32,7 @@ export class MetadataQualityComponent implements OnChanges {
32
32
 
33
33
  get calculatedQualityScore(): number {
34
34
  return Math.round(
35
- (this.items.filter(({ value }) => value === true).length * 100) /
36
- this.items.length
35
+ (this.items.filter(({ value }) => value).length * 100) / this.items.length
37
36
  )
38
37
  }
39
38
 
@@ -56,7 +55,7 @@ export class MetadataQualityComponent implements OnChanges {
56
55
  this.items = []
57
56
  this.add('title', !!this.metadata?.title)
58
57
  this.add('description', !!this.metadata?.abstract)
59
- this.add('topic', this.metadata?.themes?.length > 0)
58
+ this.add('topic', this.metadata?.topics?.length > 0)
60
59
  this.add('keywords', this.metadata?.keywords?.length > 0)
61
60
  this.add('legalConstraints', this.metadata?.legalConstraints?.length > 0)
62
61
  this.add('organisation', !!contact?.organization)
@@ -19,8 +19,8 @@
19
19
  <div class="flex flex-row items-center gap-2">
20
20
  <gn-ui-text-input
21
21
  class="mr-2 w-20"
22
- (input)="setLimit($event.target.value)"
23
- [value]="limit$ | async"
22
+ (valueChange)="setLimit($event)"
23
+ [value]="displayLimit$ | async"
24
24
  hint=""
25
25
  >
26
26
  </gn-ui-text-input>
@@ -28,8 +28,8 @@
28
28
  <input
29
29
  class="mr-2 cursor-pointer"
30
30
  type="checkbox"
31
- [checked]="(limit$ | async) === ''"
32
- (change)="setLimit('')"
31
+ [checked]="noLimitChecked$ | async"
32
+ (change)="setLimit('-1')"
33
33
  />
34
34
  <span class="text-sm" translate
35
35
  >record.metadata.api.form.limit.all</span
@@ -42,7 +42,7 @@
42
42
  <gn-ui-text-input
43
43
  class="w-20"
44
44
  [value]="offset$ | async"
45
- (input)="setOffset($event.target.value)"
45
+ (valueChange)="setOffset($event)"
46
46
  hint=""
47
47
  >
48
48
  </gn-ui-text-input>
@@ -4,7 +4,7 @@ import { BehaviorSubject, combineLatest, map } from 'rxjs'
4
4
 
5
5
  const DEFAULT_PARAMS = {
6
6
  OFFSET: '',
7
- LIMIT: '',
7
+ LIMIT: '-1',
8
8
  FORMAT: 'json',
9
9
  }
10
10
  @Component({
@@ -44,17 +44,25 @@ export class RecordApiFormComponent {
44
44
  return outputUrl
45
45
  })
46
46
  )
47
+ noLimitChecked$ = this.limit$.pipe(
48
+ map((limit) => limit === '-1' || limit === '')
49
+ )
50
+
51
+ displayLimit$ = this.limit$.pipe(
52
+ map((limit) => (limit !== '-1' ? limit : ''))
53
+ )
47
54
 
48
55
  setOffset(value: string) {
49
56
  this.offset$.next(value)
50
57
  }
51
58
 
52
59
  setLimit(value: string) {
53
- this.limit$.next(value)
60
+ const newLimit = value === '' ? '-1' : value
61
+ this.limit$.next(newLimit)
54
62
  }
55
63
 
56
- setFormat(value: string) {
57
- this.format$.next(value)
64
+ setFormat(value: string | unknown) {
65
+ this.format$.next(String(value))
58
66
  }
59
67
 
60
68
  resetUrl() {
@@ -1,13 +1,13 @@
1
1
  <div
2
2
  #containerElement
3
- class="h-full w-full relative shrink-0 overflow-hidden flex items-center"
3
+ class="h-full w-full relative shrink-0 overflow-hidden flex items-center justify-center"
4
4
  [ngClass]="isPlaceholder ? 'bg-gray-100' : 'bg-white'"
5
5
  [attr.data-cy-is-placeholder]="isPlaceholder.toString()"
6
6
  >
7
7
  <img
8
8
  #imageElement
9
9
  class="relative w-full object-center"
10
- [ngClass]="imgFit === 'contain' ? 'h-4/5' : 'h-full'"
10
+ [ngClass]="imgFit === 'contain' ? 'h-4/5 w-4/5' : 'h-full'"
11
11
  [ngStyle]="{ objectFit: imgFit }"
12
12
  alt="thumbnail"
13
13
  loading="lazy"
@@ -45,6 +45,7 @@ import { ImageOverlayPreviewComponent } from './image-overlay-preview/image-over
45
45
  UiInputsModule,
46
46
  FormsModule,
47
47
  NgOptimizedImage,
48
+ MarkdownParserComponent,
48
49
  ],
49
50
  declarations: [
50
51
  MetadataInfoComponent,
@@ -67,7 +68,6 @@ import { ImageOverlayPreviewComponent } from './image-overlay-preview/image-over
67
68
  PaginationButtonsComponent,
68
69
  MaxLinesComponent,
69
70
  RecordApiFormComponent,
70
- MarkdownParserComponent,
71
71
  ImageOverlayPreviewComponent,
72
72
  ],
73
73
  exports: [
@@ -12,6 +12,7 @@ import { propagateToDocumentOnly } from '../../../../../../libs/util/shared/src'
12
12
  templateUrl: './button.component.html',
13
13
  styleUrls: ['./button.component.css'],
14
14
  changeDetection: ChangeDetectionStrategy.OnPush,
15
+ standalone: true,
15
16
  })
16
17
  export class ButtonComponent {
17
18
  private btnClass: string
@@ -1,6 +1,6 @@
1
1
  <gn-ui-button
2
2
  type="outline"
3
- extraClass="w-full !p-[8px] !pl-[16px]"
3
+ extraClass="bg-background w-full !p-[8px] !pl-[16px]"
4
4
  [title]="title"
5
5
  [attr.aria-owns]="id"
6
6
  (buttonClick)="openOverlay()"
@@ -9,7 +9,9 @@
9
9
  <gn-ui-button
10
10
  type="outline"
11
11
  class="grow min-w-0"
12
- extraClass="!p-[8px] !pl-[16px] flex flex-row w-full {{ extraBtnClass }}"
12
+ extraClass="bg-background !p-[8px] !pl-[16px] flex flex-row w-full {{
13
+ extraBtnClass
14
+ }}"
13
15
  [title]="title"
14
16
  [attr.aria-owns]="id"
15
17
  (buttonClick)="openOverlay()"
@@ -0,0 +1,3 @@
1
+ button {
2
+ color: var(--navigation-button-color, --color-background);
3
+ }
@@ -1,5 +1,5 @@
1
1
  <button
2
- class="group flex items-center justify-center gap-1 backdrop-blur p-1 bg-primary-opacity-30 text-white rounded content-center"
2
+ class="group flex items-center justify-center gap-1 backdrop-blur p-1 bg-primary-opacity-30 rounded content-center"
3
3
  >
4
4
  <mat-icon class="material-symbols-outlined align-middle w-[18px]">{{
5
5
  icon
@@ -12,6 +12,7 @@ import { distinctUntilChanged } from 'rxjs/operators'
12
12
  selector: 'gn-ui-text-area',
13
13
  templateUrl: './text-area.component.html',
14
14
  styleUrls: ['./text-area.component.css'],
15
+ standalone: true,
15
16
  })
16
17
  export class TextAreaComponent implements AfterViewInit {
17
18
  @Input() value = ''
@@ -47,10 +47,8 @@ import { EditableLabelDirective } from './editable-label/editable-label.directiv
47
47
  declarations: [
48
48
  DropdownSelectorComponent,
49
49
  AutocompleteComponent,
50
- ButtonComponent,
51
50
  TextInputComponent,
52
51
  DragAndDropFileInputComponent,
53
- TextAreaComponent,
54
52
  ChipsInputComponent,
55
53
  NavigationButtonComponent,
56
54
  StarToggleComponent,
@@ -89,6 +87,8 @@ import { EditableLabelDirective } from './editable-label/editable-label.directiv
89
87
  MatDatepickerModule,
90
88
  MatNativeDateModule,
91
89
  EditableLabelDirective,
90
+ TextAreaComponent,
91
+ ButtonComponent,
92
92
  ],
93
93
  exports: [
94
94
  DropdownSelectorComponent,
@@ -4,6 +4,7 @@
4
4
  </div>
5
5
  </div>
6
6
  <div
7
+ *ngIf="steps.length > 1"
7
8
  class="absolute right-0 top-0 flex flex-row justify-center gap-[10px] p-1"
8
9
  [ngClass]="stepsContainerClass"
9
10
  >
@@ -3,6 +3,5 @@ export * from './lib/i18n.constants'
3
3
  export * from './lib/i18n.interceptor'
4
4
  export * from './lib/lang.service'
5
5
  export * from './lib/file.translate.loader'
6
- export * from './lib/testing/test.translate.module'
7
6
  export * from './lib/embedded.translate.loader'
8
7
  export * from './lib/translate.loader.utils'
@@ -40,6 +40,24 @@ export const LANG_3_TO_2_MAPPER = {
40
40
  slo: 'sk',
41
41
  }
42
42
 
43
+ export const LANGUAGE_NAMES = {
44
+ en: 'English',
45
+ nl: 'Nederlands',
46
+ fr: 'Français',
47
+ de: 'Deutsch',
48
+ ko: '한국어',
49
+ es: 'Español',
50
+ cs: 'Čeština',
51
+ ca: 'Català',
52
+ fi: 'Suomi',
53
+ is: 'Íslenska',
54
+ it: 'Italiano',
55
+ pt: 'Português',
56
+ ru: 'Русский',
57
+ zh: '中文',
58
+ sk: 'Slovenčina',
59
+ }
60
+
43
61
  // Caution: changing this can break language selection from third parties!
44
62
  export const LANGUAGE_STORAGE_KEY = 'geonetwork-ui-language'
45
63
 
@@ -6,3 +6,4 @@ export * from './sort-by'
6
6
  export * from './url'
7
7
  export * from './event'
8
8
  export * from './fuzzy-filter'
9
+ export * from './temporal-extent-union'
@@ -0,0 +1,32 @@
1
+ export function getTemporalRangeUnion(ranges) {
2
+ let earliestStartDate = Infinity
3
+ let latestEndDate = -Infinity
4
+ if (ranges.length) {
5
+ for (let i = 0; i < ranges.length; i++) {
6
+ const rangeStart = ranges[i].start
7
+ ? new Date(ranges[i].start).getTime()
8
+ : -Infinity
9
+ const rangeEnd = ranges[i].end
10
+ ? new Date(ranges[i].end).getTime()
11
+ : Infinity
12
+ if (rangeStart < earliestStartDate) {
13
+ earliestStartDate = rangeStart
14
+ }
15
+ if (rangeEnd > latestEndDate) {
16
+ latestEndDate = rangeEnd
17
+ }
18
+ }
19
+ return {
20
+ start:
21
+ earliestStartDate !== -Infinity
22
+ ? new Date(earliestStartDate).toLocaleDateString()
23
+ : undefined,
24
+ end:
25
+ latestEndDate !== Infinity
26
+ ? new Date(latestEndDate).toLocaleDateString()
27
+ : undefined,
28
+ }
29
+ } else {
30
+ return undefined
31
+ }
32
+ }
package/tailwind.base.css CHANGED
@@ -31,8 +31,8 @@
31
31
 
32
32
  .btn-outline {
33
33
  @apply btn text-main
34
- bg-white hover:text-primary-darker focus:text-primary-darker active:text-primary-black
35
- border border-gray-300 hover:border-primary-lighter focus:border-primary-lighter focus:ring-4 focus:ring-primary-lightest active:border-primary-darker;
34
+ bg-transparent hover:text-primary-darker focus:text-primary-darker active:text-primary-black
35
+ border border-gray-300 hover:border-primary-lighter focus:border-primary-lighter focus:ring-4 focus:ring-primary-lightest active:border-primary-darker;
36
36
  }
37
37
 
38
38
  .btn-light {