@datagouv/components-next 0.2.0 → 1.0.1

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 (155) hide show
  1. package/README.md +1 -1
  2. package/assets/main.css +49 -22
  3. package/dist/Control-BNCDn-8E.js +148 -0
  4. package/dist/{Datafair.client-x39O4yfF.js → Datafair.client-B5lBpOl8.js} +2 -2
  5. package/dist/Event-BOgJUhNR.js +738 -0
  6. package/dist/Image-BN-4XkIn.js +247 -0
  7. package/dist/{JsonPreview.client-BMsC5JcY.js → JsonPreview.client-Doz1Z0BS.js} +23 -23
  8. package/dist/Map-BdT3i2C4.js +7609 -0
  9. package/dist/MapContainer.client-oiieO8H-.js +105 -0
  10. package/dist/OSM-CamriM9b.js +71 -0
  11. package/dist/PdfPreview.client-CdAhkDFJ.js +14513 -0
  12. package/dist/{Pmtiles.client-BaiIo4VZ.js → Pmtiles.client-B0v8tGJQ.js} +3 -3
  13. package/dist/ScaleLine-BiesrgOv.js +165 -0
  14. package/dist/Swagger.client-CsK65JnG.js +4 -0
  15. package/dist/Tile-DCuqwNOI.js +1206 -0
  16. package/dist/TileImage-CmZf8EdU.js +1067 -0
  17. package/dist/View-DcDc7N2K.js +2858 -0
  18. package/dist/{XmlPreview.client-CAdN0w_Y.js → XmlPreview.client-CrjHf74q.js} +17 -17
  19. package/dist/common-C4rDcQpp.js +243 -0
  20. package/dist/components-next.css +1 -1
  21. package/dist/components-next.js +158 -117
  22. package/dist/components.css +1 -1
  23. package/dist/{MapContainer.client-DeSo8EvG.js → index-Bbu9rOHt.js} +4975 -21416
  24. package/dist/leaflet-src-7m1mB8LI.js +6338 -0
  25. package/dist/{main-Dgri3TQL.js → main-CiH8ZmBI.js} +56973 -51462
  26. package/dist/proj-CKwYjU38.js +1569 -0
  27. package/dist/tilecoord-YW3qEH_j.js +884 -0
  28. package/dist/{vue3-xml-viewer.common-D6skc_Ai.js → vue3-xml-viewer.common-Bi_bsV6C.js} +1 -1
  29. package/package.json +6 -2
  30. package/src/components/ActivityList/ActivityList.vue +6 -2
  31. package/src/components/AppLink.vue +4 -1
  32. package/src/components/Avatar.vue +2 -2
  33. package/src/components/AvatarWithName.vue +8 -4
  34. package/src/components/BouncingDots.vue +21 -0
  35. package/src/components/BrandedButton.vue +2 -0
  36. package/src/components/CopyButton.vue +19 -7
  37. package/src/components/DataserviceCard.vue +85 -120
  38. package/src/components/DatasetCard.vue +110 -171
  39. package/src/components/DatasetInformation/DatasetEmbedSection.vue +43 -0
  40. package/src/components/DatasetInformation/DatasetInformationSection.vue +73 -0
  41. package/src/components/DatasetInformation/DatasetSchemaSection.vue +74 -0
  42. package/src/components/DatasetInformation/DatasetSpatialSection.vue +59 -0
  43. package/src/components/DatasetInformation/DatasetTemporalitySection.vue +45 -0
  44. package/src/components/DatasetInformation/index.ts +5 -0
  45. package/src/components/DatasetQuality.vue +23 -16
  46. package/src/components/DatasetQualityInline.vue +13 -17
  47. package/src/components/DatasetQualityScore.vue +12 -15
  48. package/src/components/DatasetQualityTooltipContent.vue +3 -3
  49. package/src/components/DescriptionList.vue +1 -4
  50. package/src/components/DescriptionListDetails.vue +5 -0
  51. package/src/components/DescriptionListTerm.vue +5 -0
  52. package/src/components/DiscussionMessageCard.vue +63 -0
  53. package/src/components/ExtraAccordion.vue +4 -4
  54. package/src/components/Form/BadgeSelect.vue +35 -0
  55. package/src/components/Form/FormatSelect.vue +28 -0
  56. package/src/components/Form/GeozoneSelect.vue +52 -0
  57. package/src/components/Form/GranularitySelect.vue +29 -0
  58. package/src/components/Form/LicenseSelect.vue +30 -0
  59. package/src/components/Form/OrganizationSelect.vue +62 -0
  60. package/src/components/Form/OrganizationTypeSelect.vue +34 -0
  61. package/src/components/Form/ReuseTopicSelect.vue +29 -0
  62. package/src/components/Form/SchemaSelect.vue +30 -0
  63. package/src/components/Form/SearchableSelect.vue +334 -0
  64. package/src/components/Form/SelectGroup.vue +132 -0
  65. package/src/components/Form/TagSelect.vue +38 -0
  66. package/src/components/LeafletMap.vue +31 -0
  67. package/src/components/LicenseBadge.vue +24 -0
  68. package/src/components/LoadingBlock.vue +23 -2
  69. package/src/components/MarkdownViewer.vue +3 -1
  70. package/src/components/ObjectCard.vue +42 -0
  71. package/src/components/ObjectCardBadge.vue +22 -0
  72. package/src/components/ObjectCardHeader.vue +35 -0
  73. package/src/components/ObjectCardOwner.vue +43 -0
  74. package/src/components/ObjectCardShortDescription.vue +28 -0
  75. package/src/components/OrganizationCard.vue +35 -20
  76. package/src/components/OrganizationHorizontalCard.vue +87 -0
  77. package/src/components/OrganizationLogo.vue +1 -1
  78. package/src/components/OrganizationNameWithCertificate.vue +12 -6
  79. package/src/components/OwnerTypeIcon.vue +1 -0
  80. package/src/components/Pagination.vue +1 -1
  81. package/src/components/Placeholder.vue +5 -2
  82. package/src/components/PostCard.vue +62 -0
  83. package/src/components/ProgressBar.vue +31 -0
  84. package/src/components/RadioGroup.vue +32 -0
  85. package/src/components/RadioInput.vue +64 -0
  86. package/src/components/ResourceAccordion/Datafair.client.vue +1 -1
  87. package/src/components/ResourceAccordion/EditButton.vue +2 -3
  88. package/src/components/ResourceAccordion/JsonPreview.client.vue +3 -3
  89. package/src/components/ResourceAccordion/MapContainer.client.vue +21 -17
  90. package/src/components/ResourceAccordion/Metadata.vue +11 -24
  91. package/src/components/ResourceAccordion/PdfPreview.client.vue +70 -74
  92. package/src/components/ResourceAccordion/Pmtiles.client.vue +2 -2
  93. package/src/components/ResourceAccordion/Preview.vue +2 -2
  94. package/src/components/ResourceAccordion/ResourceAccordion.vue +35 -28
  95. package/src/components/ResourceAccordion/ResourceIcon.vue +1 -0
  96. package/src/components/ResourceAccordion/SchemaBadge.vue +2 -2
  97. package/src/components/ResourceAccordion/XmlPreview.client.vue +3 -3
  98. package/src/components/ResourceExplorer/ResourceExplorer.vue +243 -0
  99. package/src/components/ResourceExplorer/ResourceExplorerSidebar.vue +116 -0
  100. package/src/components/ResourceExplorer/ResourceExplorerViewer.vue +410 -0
  101. package/src/components/ReuseCard.vue +8 -28
  102. package/src/components/ReuseHorizontalCard.vue +80 -0
  103. package/src/components/Search/BasicAndAdvancedFilters.vue +49 -0
  104. package/src/components/Search/Filter/AccessTypeFilter.vue +37 -0
  105. package/src/components/Search/Filter/DatasetBadgeFilter.vue +40 -0
  106. package/src/components/Search/Filter/FilterButtonGroup.vue +78 -0
  107. package/src/components/Search/Filter/FormatFamilyFilter.vue +39 -0
  108. package/src/components/Search/Filter/LastUpdateRangeFilter.vue +37 -0
  109. package/src/components/Search/Filter/ProducerTypeFilter.vue +49 -0
  110. package/src/components/Search/Filter/ReuseTypeFilter.vue +42 -0
  111. package/src/components/Search/GlobalSearch.vue +707 -0
  112. package/src/components/Search/SearchInput.vue +63 -0
  113. package/src/components/Search/Sidemenu.vue +38 -0
  114. package/src/components/StatBox.vue +5 -5
  115. package/src/components/Tag.vue +30 -0
  116. package/src/components/Toggletip.vue +11 -4
  117. package/src/components/Tooltip.vue +2 -3
  118. package/src/components/TopicCard.vue +134 -0
  119. package/src/components/radioGroupContext.ts +9 -0
  120. package/src/composables/useDebouncedRef.ts +31 -0
  121. package/src/composables/useHasTabularData.ts +15 -0
  122. package/src/composables/useMetrics.ts +4 -3
  123. package/src/composables/useResourceCapabilities.ts +131 -0
  124. package/src/composables/useRouteQueryBoolean.ts +10 -0
  125. package/src/composables/useSelectModelSync.ts +89 -0
  126. package/src/composables/useStableQueryParams.ts +84 -0
  127. package/src/composables/useTranslation.ts +2 -1
  128. package/src/config.ts +4 -0
  129. package/src/functions/api.ts +25 -6
  130. package/src/functions/api.types.ts +5 -3
  131. package/src/functions/datasets.ts +1 -29
  132. package/src/functions/description.ts +33 -0
  133. package/src/functions/helpers.ts +11 -0
  134. package/src/functions/markdown.ts +60 -16
  135. package/src/functions/metrics.ts +33 -0
  136. package/src/functions/organizations.ts +5 -5
  137. package/src/functions/resourceCapabilities.ts +55 -0
  138. package/src/main.ts +96 -7
  139. package/src/types/dataservices.ts +14 -12
  140. package/src/types/datasets.ts +20 -7
  141. package/src/types/discussions.ts +20 -0
  142. package/src/types/licenses.ts +3 -3
  143. package/src/types/organizations.ts +13 -1
  144. package/src/types/owned.ts +4 -2
  145. package/src/types/pages.ts +70 -0
  146. package/src/types/posts.ts +27 -0
  147. package/src/types/resources.ts +16 -0
  148. package/src/types/reuses.ts +14 -5
  149. package/src/types/search.ts +407 -0
  150. package/src/types/users.ts +12 -3
  151. package/dist/PdfPreview.client-COOkEkRA.js +0 -107
  152. package/dist/Swagger.client-CpLgaLg6.js +0 -4
  153. package/dist/pdf-vue3-IkJO65RH.js +0 -273
  154. package/dist/pdf.min-f72cfa08-CdgJTooZ.js +0 -9501
  155. package/src/components/DatasetInformationPanel.vue +0 -211
@@ -4,7 +4,7 @@
4
4
  type="warning"
5
5
  class="flex items-center space-x-2"
6
6
  >
7
- <RiErrorWarningLine class="shink-0 size-6" />
7
+ <RiErrorWarningLine class="shrink-0 size-6" />
8
8
  <span>{{ t("L'aperçu cartographique de ce fichier n'a pas pu être chargé.") }}</span>
9
9
  </SimpleBanner>
10
10
  <div
@@ -18,22 +18,6 @@
18
18
  import { onMounted, ref, useTemplateRef } from 'vue'
19
19
  import { RiErrorWarningLine } from '@remixicon/vue'
20
20
 
21
- import View from 'ol/View'
22
- import Map from 'ol/Map'
23
- import ScaleLine from 'ol/control/ScaleLine'
24
- import TileLayer from 'ol/layer/Tile'
25
- import OSM from 'ol/source/OSM'
26
-
27
- import {
28
- CRS,
29
- GeoportalAttribution,
30
- GeoportalFullScreen,
31
- GeoportalZoom,
32
- LayerImport,
33
- LayerSwitcher,
34
- // @ts-expect-error no types provided
35
- } from 'geopf-extensions-openlayers'
36
-
37
21
  import SimpleBanner from '../SimpleBanner.vue'
38
22
  import type { Resource } from '../../types/resources'
39
23
  import { useTranslation } from '../../composables/useTranslation'
@@ -47,6 +31,26 @@ const mapRef = useTemplateRef('mapRef')
47
31
  const hasError = ref(false)
48
32
 
49
33
  async function displayMap() {
34
+ // Dynamic imports for client-only libraries
35
+ const [
36
+ { default: View },
37
+ { default: Map },
38
+ { default: ScaleLine },
39
+ { default: TileLayer },
40
+ { default: OSM },
41
+ geopf,
42
+ ] = await Promise.all([
43
+ import('ol/View'),
44
+ import('ol/Map'),
45
+ import('ol/control/ScaleLine'),
46
+ import('ol/layer/Tile'),
47
+ import('ol/source/OSM'),
48
+ // @ts-expect-error no types provided
49
+ import('geopf-extensions-openlayers'),
50
+ ])
51
+
52
+ const { CRS, GeoportalAttribution, GeoportalFullScreen, GeoportalZoom, LayerImport, LayerSwitcher } = geopf
53
+
50
54
  await import('ol/ol.css')
51
55
  await import('@gouvfr/dsfr/dist/dsfr.css')
52
56
  await import('@gouvfr/dsfr/dist/utility/icons/icons.css')
@@ -3,7 +3,6 @@ import { computed } from 'vue'
3
3
  import type { Resource } from '../../types/resources'
4
4
  import CopyButton from '../CopyButton.vue'
5
5
  import DescriptionDetails from '../DescriptionDetails.vue'
6
- import DescriptionList from '../DescriptionList.vue'
7
6
  import DescriptionTerm from '../DescriptionTerm.vue'
8
7
  import { useFormatDate } from '../../functions/dates'
9
8
  import { filesize } from '../../functions/helpers'
@@ -27,7 +26,7 @@ const { formatDate } = useFormatDate()
27
26
  <template>
28
27
  <div>
29
28
  <div class="flex flex-wrap gap-12 flex-col md:flex-row overflow-hidden">
30
- <DescriptionList class="flex-1 max-w-full">
29
+ <dl class="flex-1 max-w-full p-0 m-0">
31
30
  <DescriptionTerm>
32
31
  {{ t('URL') }}
33
32
  <CopyButton
@@ -90,8 +89,10 @@ const { formatDate } = useFormatDate()
90
89
  </code>
91
90
  </DescriptionDetails>
92
91
  </template>
93
- </DescriptionList>
94
- <DescriptionList style="flex-shrink: 0;">
92
+ </dl>
93
+ <dl
94
+ class="p-0 m-0 shrink-0"
95
+ >
95
96
  <DescriptionTerm>{{ t('Créée le') }}</DescriptionTerm>
96
97
  <DescriptionDetails>
97
98
  {{ formatDate(resource.created_at) }}
@@ -100,8 +101,10 @@ const { formatDate } = useFormatDate()
100
101
  <DescriptionDetails>
101
102
  {{ formatDate(resource.last_modified) }}
102
103
  </DescriptionDetails>
103
- </DescriptionList>
104
- <DescriptionList style="flex-shrink: 0;">
104
+ </dl>
105
+ <dl
106
+ class="p-0 m-0 shrink-0"
107
+ >
105
108
  <template v-if="resourceFilesize">
106
109
  <DescriptionTerm>{{ t('Taille') }}</DescriptionTerm>
107
110
  <DescriptionDetails>
@@ -120,12 +123,12 @@ const { formatDate } = useFormatDate()
120
123
  <code class="code truncate">{{ resource.mime }}</code>
121
124
  </DescriptionDetails>
122
125
  </template>
123
- </DescriptionList>
126
+ </dl>
124
127
  </div>
125
128
  <div>
126
129
  <ExtraAccordion
127
130
  v-if="hasExtras"
128
- class="pt-6 mt-6 border-top border-gray-default"
131
+ class="pt-6 mt-6 border-t border-gray-default"
129
132
  :button-text="t('Voir les extras')"
130
133
  :title-text="t('Extras de la ressource')"
131
134
  title-level="h5"
@@ -134,19 +137,3 @@ const { formatDate } = useFormatDate()
134
137
  </div>
135
138
  </div>
136
139
  </template>
137
-
138
- <style scoped>
139
- .gap-3rem {
140
- gap: 3rem;
141
- }
142
-
143
- .gap-3rem dl {
144
- padding-inline-start: 0;
145
- }
146
-
147
- @container (max-width: 600px) {
148
- .flex-col-on-small {
149
- flex-direction: column
150
- }
151
- }
152
- </style>
@@ -1,30 +1,15 @@
1
1
  <template>
2
2
  <div class="text-xs">
3
- <div v-if="pdfData">
4
- <!--
5
- We use props.resource.url instead of props.resource.latest
6
- because the PDF component raises an error otherwise.
7
- See https://github.com/datagouv/cdata/pull/611
8
- -->
9
- <PDF
10
- :src="props.resource.url"
11
- :show-progress="true"
12
- progress-color="#0063cb"
13
- :show-page-tooltip="true"
14
- :show-back-to-top-btn="true"
15
- :scroll-threshold="300"
16
- pdf-width="100%"
17
- :row-gap="12"
18
- :use-system-fonts="true"
19
- :disable-range="false"
20
- :disable-stream="false"
21
- :disable-auto-fetch="false"
3
+ <div
4
+ v-if="pdfReady"
5
+ ref="containerRef"
6
+ class="w-full overflow-y-auto max-h-[80vh] space-y-3"
7
+ >
8
+ <canvas
9
+ v-for="page in totalPages"
10
+ :key="page"
11
+ :ref="(el) => setCanvasRef(el as HTMLCanvasElement, page)"
22
12
  class="w-full"
23
- @on-progress="handleProgress"
24
- @on-complete="handleComplete"
25
- @on-page-change="handlePageChange"
26
- @on-pdf-init="handlePdfInit"
27
- @on-error="handleError"
28
13
  />
29
14
  </div>
30
15
  <div
@@ -64,19 +49,18 @@
64
49
  </template>
65
50
 
66
51
  <script setup lang="ts">
67
- import { computed, defineAsyncComponent, onMounted, ref } from 'vue'
52
+ import { computed, nextTick, onBeforeUnmount, onMounted, ref } from 'vue'
68
53
  import { RiErrorWarningLine } from '@remixicon/vue'
54
+ import * as pdfjsLib from 'pdfjs-dist'
55
+ import pdfjsWorker from 'pdfjs-dist/build/pdf.worker.min.mjs?url'
56
+ import type { PDFDocumentProxy } from 'pdfjs-dist'
69
57
  import SimpleBanner from '../SimpleBanner.vue'
70
58
  import { useComponentsConfig } from '../../config'
71
59
  import type { Resource } from '../../types/resources'
72
60
  import { useTranslation } from '../../composables/useTranslation'
73
61
  import { getResourceFilesize } from '../../functions/datasets'
74
62
 
75
- const PDF = defineAsyncComponent(() =>
76
- import('pdf-vue3').then((module) => {
77
- return module.default
78
- }),
79
- )
63
+ pdfjsLib.GlobalWorkerOptions.workerSrc = pdfjsWorker
80
64
 
81
65
  const props = defineProps<{
82
66
  resource: Resource
@@ -85,10 +69,47 @@ const props = defineProps<{
85
69
  const config = useComponentsConfig()
86
70
  const { t } = useTranslation()
87
71
 
88
- const pdfData = ref<boolean>(false)
72
+ const containerRef = ref<HTMLElement | null>(null)
73
+ const pdfReady = ref(false)
89
74
  const loading = ref(false)
90
75
  const error = ref<string | null>(null)
91
76
  const fileTooLarge = ref(false)
77
+ const totalPages = ref(0)
78
+
79
+ let pdfDoc: PDFDocumentProxy | null = null
80
+ const canvasRefs = new Map<number, HTMLCanvasElement>()
81
+
82
+ function setCanvasRef(el: HTMLCanvasElement | null, pageNum: number) {
83
+ if (el) canvasRefs.set(pageNum, el)
84
+ }
85
+
86
+ async function renderPage(pageNum: number) {
87
+ if (!pdfDoc) return
88
+
89
+ const canvas = canvasRefs.get(pageNum)
90
+ if (!canvas) return
91
+
92
+ const page = await pdfDoc.getPage(pageNum)
93
+
94
+ const containerWidth = containerRef.value?.clientWidth ?? 800
95
+ const unscaledViewport = page.getViewport({ scale: 1 })
96
+ const scale = containerWidth / unscaledViewport.width
97
+ const viewport = page.getViewport({ scale })
98
+
99
+ const dpr = window.devicePixelRatio || 1
100
+ canvas.width = viewport.width * dpr
101
+ canvas.height = viewport.height * dpr
102
+ canvas.style.width = `${viewport.width}px`
103
+ canvas.style.height = `${viewport.height}px`
104
+
105
+ const context = canvas.getContext('2d')!
106
+ context.scale(dpr, dpr)
107
+
108
+ await page.render({
109
+ canvasContext: context,
110
+ viewport,
111
+ }).promise
112
+ }
92
113
 
93
114
  const fileSizeBytes = computed(() => getResourceFilesize(props.resource))
94
115
 
@@ -105,7 +126,6 @@ const shouldLoadPdf = computed(() => {
105
126
  })
106
127
 
107
128
  const loadPdf = async () => {
108
- // Check if file is too large or size is unknown before loading
109
129
  if (!shouldLoadPdf.value) {
110
130
  fileTooLarge.value = true
111
131
  return
@@ -115,19 +135,23 @@ const loadPdf = async () => {
115
135
  error.value = null
116
136
 
117
137
  try {
118
- // Test if the PDF URL is accessible
119
- const response = await fetch(props.resource.url, { method: 'HEAD' })
120
- // const response = await fetch('/test-data.pdf') // For testing locally without CORS issues
121
- if (!response.ok) {
122
- throw new Error(`HTTP error! status: ${response.status}`)
123
- }
138
+ const loadingTask = pdfjsLib.getDocument({
139
+ url: props.resource.url,
140
+ isEvalSupported: false,
141
+ })
142
+
143
+ pdfDoc = await loadingTask.promise
144
+ totalPages.value = pdfDoc.numPages
145
+ pdfReady.value = true
124
146
 
125
- // If the URL is accessible, set pdfData to true
126
- // The PDF component will handle the actual loading
127
- pdfData.value = true
147
+ await nextTick()
148
+
149
+ for (let i = 1; i <= pdfDoc.numPages; i++) {
150
+ await renderPage(i)
151
+ }
128
152
  }
129
153
  catch (err) {
130
- console.error('Error testing PDF URL:', err)
154
+ console.error('Error loading PDF:', err)
131
155
 
132
156
  if (err instanceof TypeError) {
133
157
  error.value = 'network'
@@ -135,45 +159,17 @@ const loadPdf = async () => {
135
159
  else {
136
160
  error.value = 'generic'
137
161
  }
138
-
139
- pdfData.value = false
140
162
  }
141
163
  finally {
142
164
  loading.value = false
143
165
  }
144
166
  }
145
167
 
146
- // Event handlers for PDF component
147
- const handleProgress = (loadRatio: number) => {
148
- console.log(`PDF loading progress: ${loadRatio}%`)
149
- }
150
-
151
- const handleComplete = () => {
152
- console.log('PDF download completed')
153
- }
154
-
155
- const handlePageChange = (page: number) => {
156
- console.log(`PDF page changed to: ${page}`)
157
- }
158
-
159
- const handlePdfInit = (pdf: unknown) => {
160
- console.log('PDF initialized:', pdf)
161
- }
162
-
163
- const handleError = (err: unknown) => {
164
- console.error('PDF loading error:', err)
165
-
166
- if (err instanceof TypeError) {
167
- error.value = 'network'
168
- }
169
- else {
170
- error.value = 'generic'
171
- }
172
-
173
- pdfData.value = false
174
- }
175
-
176
168
  onMounted(() => {
177
169
  loadPdf()
178
170
  })
171
+
172
+ onBeforeUnmount(() => {
173
+ pdfDoc?.destroy()
174
+ })
179
175
  </script>
@@ -5,7 +5,7 @@
5
5
  type="warning"
6
6
  class="flex items-center space-x-2"
7
7
  >
8
- <RiErrorWarningLine class="shink-0 size-6" />
8
+ <RiErrorWarningLine class="shrink-0 size-6" />
9
9
  <span>{{ t("L'aperçu cartographique de ce fichier n'a pas pu être chargé.") }}</span>
10
10
  </SimpleBanner>
11
11
  <div
@@ -25,7 +25,7 @@
25
25
  <p class="fr-text--bold fr-m-0">
26
26
  {{ t("Explorer les données en détail") }}
27
27
  </p>
28
- <p class="fr-text--sm fr-m-0 f-italic">
28
+ <p class="fr-text--sm fr-m-0 italic">
29
29
  {{ t("Utiliser un visualisateur PMTiles pour obtenir un aperçu des données.") }}
30
30
  </p>
31
31
  </div>
@@ -5,7 +5,7 @@
5
5
  type="warning"
6
6
  class="flex items-center space-x-2"
7
7
  >
8
- <RiErrorWarningLine class="shink-0 size-6" />
8
+ <RiErrorWarningLine class="shrink-0 size-6" />
9
9
  <span>{{ t("L'aperçu de ce fichier n'a pas pu être chargé.") }}</span>
10
10
  </SimpleBanner>
11
11
  <PreviewLoader v-else-if="loading" />
@@ -23,7 +23,7 @@
23
23
  <p class="fr-text--bold fr-m-0">
24
24
  {{ t("Explorer les données en détail") }}
25
25
  </p>
26
- <p class="fr-text--sm fr-m-0 f-italic">
26
+ <p class="fr-text--sm fr-m-0 italic">
27
27
  {{ t("Utiliser notre outil pour obtenir un aperçu des données, en savoir plus sur les différentes colonnes ou réaliser des filtres et des tris.") }}
28
28
  </p>
29
29
  </div>
@@ -9,7 +9,7 @@
9
9
  >
10
10
  <div>
11
11
  <div class="flex items-center fr-mb-1v">
12
- <h4
12
+ <h3
13
13
  :id="resourceTitleId"
14
14
  class="fr-m-0"
15
15
  >
@@ -43,7 +43,7 @@
43
43
  /></span>
44
44
  <span class="absolute inset-0 z-1" />
45
45
  </button>
46
- </h4>
46
+ </h3>
47
47
  <CopyButton
48
48
  :label="t('Copier le lien')"
49
49
  :copied-label="t('Lien copié !')"
@@ -51,22 +51,33 @@
51
51
  class="z-2"
52
52
  />
53
53
  </div>
54
- <div class="text-gray-medium subheaders-infos">
54
+ <div class="text-gray-medium subheaders-infos flex items-center gap-1">
55
55
  <SchemaBadge
56
56
  :resource
57
- class="dash-after"
58
57
  />
59
- <span class="fr-text--xs fr-mb-0 dash-after">{{ t('Mis à jour {date}', { date: formatRelativeIfRecentDate(lastUpdate) }) }}</span>
60
- <span
61
- v-if="resource.format"
62
- class="fr-text--xs fr-mb-0 dash-after"
63
- >
64
- <span class="hidden show-on-small">{{ t("Format") }}</span>
65
- {{ resource.format.trim().toLowerCase() }}
66
- <span v-if="resourceFilesize">({{ filesize(resourceFilesize) }})</span>
67
- </span>
58
+ <RiSubtractLine
59
+ v-if="resource.schema"
60
+ aria-hidden="true"
61
+ class="size-3 fill-gray-medium"
62
+ />
63
+ <span class="text-xs mb-0">{{ t('Mis à jour {date}', { date: formatRelativeIfRecentDate(lastUpdate) }) }}</span>
64
+ <RiSubtractLine
65
+ aria-hidden="true"
66
+ class="size-3 fill-gray-medium"
67
+ />
68
+ <template v-if="resource.format">
69
+ <span class="text-xs mb-0">
70
+ <span class="hidden sm:inline">{{ t("Format") }}</span>
71
+ {{ resource.format.trim().toLowerCase() }}
72
+ <span v-if="resourceFilesize">({{ filesize(resourceFilesize) }})</span>
73
+ </span>
74
+ <RiSubtractLine
75
+ aria-hidden="true"
76
+ class="size-3 fill-gray-medium"
77
+ />
78
+ </template>
68
79
  <span
69
- class="inline-flex items-center fr-text--xs fr-mb-0"
80
+ class="inline-flex items-center text-xs mb-0"
70
81
  :aria-label="t('{n} téléchargements', resource.metrics.views)"
71
82
  >
72
83
  <span class="fr-icon-download-line fr-icon--xs fr-mr-1v" />
@@ -102,6 +113,7 @@
102
113
  rel="ugc nofollow noopener"
103
114
  new-tab
104
115
  size="xs"
116
+ color="secondary"
105
117
  external
106
118
  @click="trackEvent('Jeux de données', 'Télécharger un fichier', 'Bouton : télécharger un fichier')"
107
119
  >
@@ -116,7 +128,7 @@
116
128
  :id="resource.id + '-copy'"
117
129
  :data-clipboard-text="resource.url"
118
130
  :aria-describedby="resourceTitleId"
119
- color="primary"
131
+ color="secondary"
120
132
  size="xs"
121
133
  :icon="RiFileCopyLine"
122
134
  >
@@ -132,14 +144,15 @@
132
144
  rel="ugc nofollow noopener"
133
145
  :title="downloadButtonTitle"
134
146
  download
135
- class="relative text-transform-uppercase matomo_download z-2"
147
+ class="relative matomo_download z-2"
136
148
  :icon="unavailable ? RiFileWarningLine : RiDownloadLine"
137
149
  size="xs"
150
+ color="secondary"
138
151
  :aria-describedby="resourceTitleId"
139
152
  external
140
153
  @click="trackEvent('Jeux de données', 'Télécharger un fichier', 'Bouton : télécharger un fichier')"
141
154
  >
142
- <span class="sr-only">{{ t('Télécharger le fichier au format ') }}</span>{{ format }}
155
+ {{ t('Télécharger') }}
143
156
  </BrandedButton>
144
157
  </p>
145
158
  <p
@@ -358,7 +371,7 @@
358
371
 
359
372
  <script setup lang="ts">
360
373
  import { ref, computed, defineAsyncComponent } from 'vue'
361
- import { RiDownloadLine, RiFileCopyLine, RiFileWarningLine } from '@remixicon/vue'
374
+ import { RiDownloadLine, RiFileCopyLine, RiFileWarningLine, RiSubtractLine } from '@remixicon/vue'
362
375
  import OrganizationNameWithCertificate from '../OrganizationNameWithCertificate.vue'
363
376
  import { filesize, summarize } from '../../functions/helpers'
364
377
  import { useFormatDate } from '../../functions/dates'
@@ -378,6 +391,7 @@ import { getResourceFormatIcon, getResourceTitleId, detectOgcService } from '../
378
391
  import BrandedButton from '../BrandedButton.vue'
379
392
  import { getResourceExternalUrl, getResourceFilesize } from '../../functions/datasets'
380
393
  import { useTranslation } from '../../composables/useTranslation'
394
+ import { useHasTabularData } from '../../composables/useHasTabularData'
381
395
  import Metadata from './Metadata.vue'
382
396
  import SchemaBadge from './SchemaBadge.vue'
383
397
  import ResourceIcon from './ResourceIcon.vue'
@@ -414,6 +428,7 @@ const DatafairPreview = defineAsyncComponent(() => import('./Datafair.client.vue
414
428
 
415
429
  const { t } = useTranslation()
416
430
  const { formatRelativeIfRecentDate } = useFormatDate()
431
+ const checkTabularData = useHasTabularData()
417
432
 
418
433
  const hasPreview = computed(() => {
419
434
  // For JSON, PDF, and XML files, show preview.
@@ -423,13 +438,7 @@ const hasPreview = computed(() => {
423
438
  return format === 'json' || format === 'pdf' || format === 'xml'
424
439
  })
425
440
 
426
- const hasTabularData = computed(() => {
427
- // Determines if we should show the "Données" tab for tabular files AND the "Structure des données" tab (for tabular data structure)
428
- return config.tabularApiUrl
429
- && props.resource.extras['analysis:parsing:parsing_table']
430
- && !props.resource.extras['analysis:parsing:error']
431
- && (config.tabularAllowRemote || props.resource.filetype === 'file')
432
- })
441
+ const hasTabularData = computed(() => checkTabularData(props.resource))
433
442
 
434
443
  const hasPmtiles = computed(() => {
435
444
  return props.resource.extras['analysis:parsing:pmtiles_url'] || props.resource.format === 'pmtiles'
@@ -595,9 +604,7 @@ article {
595
604
  article header .subheaders-infos .hidden.show-on-small {
596
605
  display: inline !important;
597
606
  }
598
- article header .dash-after::after {
599
- content: ''
600
- } */
607
+ */
601
608
 
602
609
  /* article .fr-pl-4v fr-pr-4v {
603
610
  padding: 0.75rem !important;
@@ -2,6 +2,7 @@
2
2
  <component
3
3
  :is="(resource.format ? getResourceFormatIcon(resource.format) : null) || File"
4
4
  class="text-gray-800 shrink-0"
5
+ aria-hidden="true"
5
6
  />
6
7
  </template>
7
8
 
@@ -9,12 +9,12 @@
9
9
  >
10
10
  <RiInformationLine class="size-4" />
11
11
  <template #toggletip="{ close }">
12
- <div class="flex justify-between border-bottom">
12
+ <div class="flex justify-between border-b">
13
13
  <h5 class="fr-text--sm fr-my-0 fr-p-2v">{{ t("Schéma de données") }}</h5>
14
14
  <button
15
15
  type="button"
16
16
  :title="t('Fermer')"
17
- class="border-left close-button flex items-center justify-center"
17
+ class="border-l close-button flex items-center justify-center"
18
18
  @click="close"
19
19
  >&times;</button>
20
20
  </div>
@@ -14,7 +14,7 @@
14
14
  type="warning"
15
15
  class="flex items-center space-x-2"
16
16
  >
17
- <RiErrorWarningLine class="shink-0 size-6" />
17
+ <RiErrorWarningLine class="shrink-0 size-6" />
18
18
  <span>{{ fileSizeBytes
19
19
  ? t("Fichier XML trop volumineux pour l'aperçu. Pour consulter le fichier complet, téléchargez-le en cliquant sur le bouton bleu ou depuis l'onglet Téléchargements.")
20
20
  : t("L'aperçu n'est pas disponible car la taille du fichier est inconnue. Pour consulter le fichier complet, téléchargez-le en cliquant sur le bouton bleu ou depuis l'onglet Téléchargements.")
@@ -25,7 +25,7 @@
25
25
  type="warning"
26
26
  class="flex items-center space-x-2"
27
27
  >
28
- <RiErrorWarningLine class="shink-0 size-6" />
28
+ <RiErrorWarningLine class="shrink-0 size-6" />
29
29
  <span>{{ t("Ce fichier XML ne peut pas être prévisualisé, peut-être parce qu'il est hébergé sur un autre site qui ne l'autorise pas. Pour le consulter, téléchargez-le en cliquant sur le bouton bleu ou depuis l'onglet Téléchargements.") }}</span>
30
30
  </SimpleBanner>
31
31
  <SimpleBanner
@@ -33,7 +33,7 @@
33
33
  type="warning"
34
34
  class="flex items-center space-x-2"
35
35
  >
36
- <RiErrorWarningLine class="shink-0 size-6" />
36
+ <RiErrorWarningLine class="shrink-0 size-6" />
37
37
  <span>{{ t("Erreur lors du chargement de l'aperçu XML.") }}</span>
38
38
  </SimpleBanner>
39
39
  </div>