@datagouv/components-next 0.0.7 → 0.0.9

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 (103) hide show
  1. package/README.md +34 -14
  2. package/assets/json/vector.json +2377 -0
  3. package/assets/main.css +3 -0
  4. package/assets/swagger-themes/newspaper.css +1669 -0
  5. package/assets/tailwind.config.js +1 -1
  6. package/dist/JsonPreview.client-BIz1_EiB.js +92 -0
  7. package/dist/MapContainer.client-ZDwr4Q_I.js +78276 -0
  8. package/dist/PdfPreview.client-BTTMM27i.js +112 -0
  9. package/dist/Pmtiles.client-4kOoUQcR.js +22377 -0
  10. package/dist/Swagger.client-Q7a5wb51.js +4 -0
  11. package/dist/XmlPreview.client-BYIIkDqf.js +84 -0
  12. package/dist/components-next.css +52 -1
  13. package/dist/components-next.js +42 -41
  14. package/dist/components.css +1 -1
  15. package/dist/main-CLUk9Jj7.js +105843 -0
  16. package/dist/pdf-vue3-BZh6kzke.js +273 -0
  17. package/dist/pdf.min-f72cfa08-DAetWL3M.js +9501 -0
  18. package/dist/{text-clamp.esm-DurZFOvT.js → text-clamp.esm-DP59tec5.js} +1 -1
  19. package/dist/vue3-json-viewer-DIQzFF6K.js +1089 -0
  20. package/dist/vue3-xml-viewer.common-BmKw6vER.js +5437 -0
  21. package/package.json +7 -5
  22. package/src/components/AvatarWithName.vue +6 -2
  23. package/src/components/BannerAction.vue +1 -1
  24. package/src/components/BrandedButton.vue +13 -8
  25. package/src/components/CopyButton.vue +7 -7
  26. package/src/components/DataserviceCard.vue +54 -23
  27. package/src/components/DatasetCard.vue +36 -24
  28. package/src/components/DatasetInformationPanel.vue +19 -18
  29. package/src/components/DatasetQuality.vue +21 -18
  30. package/src/components/DatasetQualityInline.vue +1 -1
  31. package/src/components/DatasetQualityItem.vue +3 -3
  32. package/src/components/DatasetQualityItemWarning.vue +2 -2
  33. package/src/components/DatasetQualityScore.vue +2 -2
  34. package/src/components/DatasetQualityTooltipContent.vue +29 -29
  35. package/src/components/DescriptionDetails.vue +2 -2
  36. package/src/components/ExtraAccordion.vue +10 -7
  37. package/src/components/OrganizationCard.vue +9 -4
  38. package/src/components/OrganizationNameWithCertificate.vue +25 -11
  39. package/src/components/Pagination.vue +26 -15
  40. package/src/components/ReadMore.vue +2 -2
  41. package/src/components/ResourceAccordion/DataStructure.vue +2 -2
  42. package/src/components/ResourceAccordion/EditButton.vue +10 -6
  43. package/src/components/ResourceAccordion/JsonPreview.client.vue +153 -0
  44. package/src/components/ResourceAccordion/MapContainer.client.vue +137 -0
  45. package/src/components/ResourceAccordion/Metadata.vue +33 -54
  46. package/src/components/ResourceAccordion/PdfPreview.client.vue +189 -0
  47. package/src/components/ResourceAccordion/Pmtiles.client.vue +166 -0
  48. package/src/components/ResourceAccordion/Preview.vue +39 -37
  49. package/src/components/ResourceAccordion/ResourceAccordion.vue +141 -63
  50. package/src/components/ResourceAccordion/ResourceIcon.vue +7 -1
  51. package/src/components/ResourceAccordion/SchemaBadge.vue +26 -26
  52. package/src/components/ResourceAccordion/{Swagger.vue → Swagger.client.vue} +1 -1
  53. package/src/components/ResourceAccordion/XmlPreview.client.vue +143 -0
  54. package/src/components/ReuseCard.vue +10 -7
  55. package/src/components/ReuseDetails.vue +3 -3
  56. package/src/components/SimpleBanner.vue +7 -4
  57. package/src/components/SmallChart.vue +23 -9
  58. package/src/components/StatBox.vue +92 -10
  59. package/src/config.ts +6 -2
  60. package/src/functions/api.ts +18 -18
  61. package/src/functions/dates.ts +81 -74
  62. package/src/functions/helpers.ts +5 -4
  63. package/src/functions/organizations.ts +5 -5
  64. package/src/functions/resources.ts +34 -5
  65. package/src/functions/schemas.ts +4 -3
  66. package/src/functions/tabularApi.ts +1 -1
  67. package/src/main.ts +10 -11
  68. package/src/types/badges.ts +3 -3
  69. package/src/types/contact_point.ts +5 -5
  70. package/src/types/dataservices.ts +16 -2
  71. package/src/types/datasets.ts +20 -2
  72. package/src/types/frequency.ts +5 -5
  73. package/src/types/granularity.ts +12 -4
  74. package/src/types/harvest.ts +2 -2
  75. package/src/types/licenses.ts +8 -8
  76. package/src/types/organizations.ts +6 -0
  77. package/src/types/resources.ts +3 -3
  78. package/src/types/reuses.ts +3 -1
  79. package/src/types/site.ts +8 -0
  80. package/src/types/ui.ts +2 -2
  81. package/src/types/users.ts +24 -8
  82. package/src/types/vue3-xml-viewer.d.ts +10 -0
  83. package/dist/Swagger-DjysB-OI.js +0 -67851
  84. package/dist/en-DCRve7vN.js +0 -613
  85. package/dist/fr-DCOnbL-p.js +0 -613
  86. package/dist/locales/de.js +0 -155
  87. package/dist/locales/en.js +0 -155
  88. package/dist/locales/es.js +0 -155
  89. package/dist/locales/fr.js +0 -155
  90. package/dist/locales/it.js +0 -155
  91. package/dist/locales/pt.js +0 -155
  92. package/dist/locales/sr.js +0 -155
  93. package/dist/main-CPW2vNLE.js +0 -32008
  94. package/src/components/DescriptionList/DescriptionDetails.stories.ts +0 -43
  95. package/src/components/DescriptionList/DescriptionList.stories.ts +0 -47
  96. package/src/components/DescriptionList/DescriptionTerm.stories.ts +0 -28
  97. package/src/locales/de.json +0 -154
  98. package/src/locales/en.json +0 -154
  99. package/src/locales/es.json +0 -154
  100. package/src/locales/fr.json +0 -154
  101. package/src/locales/it.json +0 -154
  102. package/src/locales/pt.json +0 -154
  103. package/src/locales/sr.json +0 -154
@@ -0,0 +1,143 @@
1
+ <template>
2
+ <div class="fr-text--xs">
3
+ <div v-if="xmlData">
4
+ <XmlViewer :xml="xmlData" />
5
+ </div>
6
+ <div
7
+ v-else-if="loading"
8
+ class="text-gray-medium"
9
+ >
10
+ {{ $t("Chargement de l'aperçu XML...") }}
11
+ </div>
12
+ <SimpleBanner
13
+ v-else-if="fileTooLarge"
14
+ type="warning"
15
+ class="flex items-center space-x-2"
16
+ >
17
+ <RiErrorWarningLine class="shink-0 size-6" />
18
+ <span>{{ fileSizeBytes
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
+ : $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.")
21
+ }}</span>
22
+ </SimpleBanner>
23
+ <SimpleBanner
24
+ v-else-if="error === 'network'"
25
+ type="warning"
26
+ class="flex items-center space-x-2"
27
+ >
28
+ <RiErrorWarningLine class="shink-0 size-6" />
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
+ </SimpleBanner>
31
+ <SimpleBanner
32
+ v-else-if="error"
33
+ type="warning"
34
+ class="flex items-center space-x-2"
35
+ >
36
+ <RiErrorWarningLine class="shink-0 size-6" />
37
+ <span>{{ $t("Erreur lors du chargement de l'aperçu XML.") }}</span>
38
+ </SimpleBanner>
39
+ </div>
40
+ </template>
41
+
42
+ <script setup lang="ts">
43
+ import { computed, defineAsyncComponent, onMounted, ref } from 'vue'
44
+ import { RiErrorWarningLine } from '@remixicon/vue'
45
+
46
+ import { useComponentsConfig } from '../../config'
47
+ import SimpleBanner from '../SimpleBanner.vue'
48
+ import type { Resource } from '../../types/resources'
49
+
50
+ const XmlViewer = defineAsyncComponent(() =>
51
+ import('vue3-xml-viewer').then((module) => {
52
+ return module.default || module.XmlViewer
53
+ }),
54
+ )
55
+
56
+ const props = defineProps<{
57
+ resource: Resource
58
+ }>()
59
+
60
+ const config = useComponentsConfig()
61
+
62
+ const xmlData = ref<string | null>(null)
63
+ const loading = ref(false)
64
+ const error = ref<string | null>(null)
65
+ const fileTooLarge = ref(false)
66
+
67
+ const fileSizeBytes = computed(() => {
68
+ // Check if resource has filesize
69
+ if (props.resource.filesize) {
70
+ return props.resource.filesize
71
+ }
72
+
73
+ // Check if resource has content-length in extras (from API metadata)
74
+ const contentLength = props.resource.extras?.['analysis:content-length']
75
+ if (contentLength && typeof contentLength === 'number') {
76
+ return contentLength
77
+ }
78
+
79
+ return null
80
+ })
81
+
82
+ const shouldLoadXml = computed(() => {
83
+ const size = fileSizeBytes.value
84
+ if (!size) {
85
+ // If we don't know the size, don't risk loading a potentially huge file
86
+ return false
87
+ }
88
+
89
+ // Check if maxXmlPreviewSize is configured
90
+ if (!config.maxXmlPreviewSize) {
91
+ // If no limit is set, don't load unknown files
92
+ return false
93
+ }
94
+
95
+ // Convert maxXmlPreviewSize from characters to bytes (rough estimate)
96
+ // Assuming average 1 byte per character for XML
97
+ const maxSizeBytes = config.maxXmlPreviewSize
98
+
99
+ return size <= maxSizeBytes
100
+ })
101
+
102
+ const fetchXmlData = async () => {
103
+ // Check if file is too large or size is unknown before making the request
104
+ if (!shouldLoadXml.value) {
105
+ fileTooLarge.value = true
106
+ return
107
+ }
108
+
109
+ loading.value = true
110
+ error.value = null
111
+
112
+ try {
113
+ const response = await fetch(props.resource.url)
114
+ // const response = await fetch('/test-data.xml') // For testing locally without CORS issues
115
+ if (!response.ok) {
116
+ throw new Error(`HTTP error! status: ${response.status}`)
117
+ }
118
+ const data = await response.text()
119
+
120
+ // Use the XML data as string - let the XML viewer handle large files
121
+ xmlData.value = data
122
+ }
123
+ catch (err) {
124
+ console.error('Error loading XML:', err)
125
+
126
+ if (err instanceof TypeError) {
127
+ error.value = 'network'
128
+ }
129
+ else {
130
+ error.value = 'generic'
131
+ }
132
+
133
+ xmlData.value = null
134
+ }
135
+ finally {
136
+ loading.value = false
137
+ }
138
+ }
139
+
140
+ onMounted(() => {
141
+ fetchXmlData()
142
+ })
143
+ </script>
@@ -4,7 +4,7 @@
4
4
  <div class="order-1 flex flex-col px-4 py-1 h-full -mx-8">
5
5
  <h3 class="font-bold text-base mt-1 mb-0 truncate">
6
6
  <AppLink
7
- class="text-gray-title"
7
+ class="text-gray-title overflow-hidden"
8
8
  :to="reuseUrl"
9
9
  >
10
10
  {{ reuse.title }}
@@ -18,7 +18,7 @@
18
18
  >
19
19
  <AppLink
20
20
  v-if="organizationUrl"
21
- class="fr-link block"
21
+ class="link overflow-hidden"
22
22
  :to="organizationUrl"
23
23
  >
24
24
  <OrganizationNameWithCertificate
@@ -35,7 +35,7 @@
35
35
  class="mr-1 truncate"
36
36
  >{{ ownerName }}</span>
37
37
  <RiSubtractLine class="size-4 flex-none fill-gray-medium" />
38
- <span class="block flex-none">{{ t('published {date}', { date: formatRelativeIfRecentDate(reuse.created_at, { dateStyle: 'medium' }) }) }}</span>
38
+ <span class="block flex-none">{{ t('publié {date}', { date: formatRelativeIfRecentDate(reuse.created_at, { dateStyle: 'medium' }) }) }}</span>
39
39
  </p>
40
40
  <ReuseDetails :reuse />
41
41
  </div>
@@ -58,13 +58,13 @@
58
58
  <li v-if="reuse.private">
59
59
  <p class="fr-badge fr-badge--sm fr-badge--mention-grey text-gray-medium">
60
60
  <RiLockLine class="size-3.5 mr-0.5" />
61
- {{ t('Draft') }}
61
+ {{ t('Brouillon') }}
62
62
  </p>
63
63
  </li>
64
64
  <li v-if="reuse.archived">
65
65
  <p class="fr-badge fr-badge--sm fr-badge--mention-grey text-gray-medium">
66
66
  <RiLockLine class="size-3.5 mr-0.5" />
67
- {{ t('Archived') }}
67
+ {{ t('Archivé') }}
68
68
  </p>
69
69
  </li>
70
70
  </ul>
@@ -77,7 +77,7 @@ import { RiLockLine, RiSubtractLine } from '@remixicon/vue'
77
77
  import { computed } from 'vue'
78
78
  import { useI18n } from 'vue-i18n'
79
79
  import type { RouteLocationRaw } from 'vue-router'
80
- import { formatRelativeIfRecentDate } from '../functions/dates'
80
+ import { useFormatDate } from '../functions/dates'
81
81
  import { getOwnerName } from '../functions/owned'
82
82
  import type { Reuse } from '../types/reuses'
83
83
  import AppLink from './AppLink.vue'
@@ -91,7 +91,7 @@ const props = defineProps<{
91
91
  * The reuseUrl is a route location object to allow Vue Router to navigate to the details of a reuse.
92
92
  * It is used as a separate prop to allow other sites using the package to define their own reuse pages.
93
93
  */
94
- reuseUrl: RouteLocationRaw
94
+ reuseUrl?: RouteLocationRaw
95
95
 
96
96
  /**
97
97
  * The organizationUrl is an optional route location object to allow Vue Router to navigate to the details of the organization linked to tha reuse.
@@ -101,6 +101,9 @@ const props = defineProps<{
101
101
  }>()
102
102
 
103
103
  const { t } = useI18n()
104
+ const { formatRelativeIfRecentDate } = useFormatDate()
104
105
 
105
106
  const ownerName = computed(() => getOwnerName(props.reuse))
107
+
108
+ const reuseUrl = computed(() => props.reuseUrl || props.reuse.page)
106
109
  </script>
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div class="flex flex-wrap items-center gap-0.5">
2
+ <div class="flex flex-wrap items-center gap-1">
3
3
  <p class="text-sm mb-0">
4
4
  {{ reuseType }}
5
5
  </p>
@@ -9,7 +9,7 @@
9
9
  />
10
10
  <p
11
11
  class="text-sm mb-0 flex items-center gap-0.5"
12
- :aria-label="t('{n} views', reuse.metrics.views)"
12
+ :aria-label="t('{n} vues | {n} vue | {n} vues', reuse.metrics.views)"
13
13
  >
14
14
  <RiEyeLine
15
15
  aria-hidden="true"
@@ -18,7 +18,7 @@
18
18
  </p>
19
19
  <p
20
20
  class="text-sm mb-0 flex items-center gap-0.5"
21
- :aria-label="t('{n} followers', reuse.metrics.followers)"
21
+ :aria-label="t('{n} abonnés | {n} abonné | {n} abonnés', reuse.metrics.followers)"
22
22
  >
23
23
  <RiStarLine
24
24
  aria-hidden="true"
@@ -11,14 +11,17 @@
11
11
  import { computed } from 'vue'
12
12
 
13
13
  const props = defineProps<{
14
- type: 'primary' | 'warning' | 'gray'
14
+ type: 'primary' | 'primary-frame' | 'warning' | 'gray' | 'danger' | 'success'
15
15
  }>()
16
16
 
17
17
  const classes = computed(() => {
18
18
  return {
19
- primary: 'bg-datagouv-lightest text-datagouv-dark',
20
- warning: 'bg-warning3-lightest text-warning3-dark',
21
- gray: 'bg-gray-some text-gray-plain',
19
+ 'primary': 'bg-datagouv-lightest text-datagouv-dark',
20
+ 'primary-frame': 'bg-gray-50 border border-datagouv',
21
+ 'warning': 'bg-warning3-lightest text-warning3-dark',
22
+ 'gray': 'bg-gray-some text-gray-plain',
23
+ 'success': 'bg-success-lightest text-success-dark',
24
+ 'danger': 'bg-danger-lightest text-danger-dark',
22
25
  }[props.type]
23
26
  })
24
27
  </script>
@@ -2,14 +2,18 @@
2
2
  <div>
3
3
  <canvas
4
4
  ref="canvasRef"
5
- width="120"
6
- height="30"
5
+ :width="width*2"
6
+ :height="height*2"
7
+ :style="{ width: width + 'px', height: height + 'px' }"
7
8
  />
8
- <div class="fr-grid-row justify-between">
9
- <p class="text-xxs fr-m-0 text-mention-grey">
9
+ <div
10
+ v-if="showAxisLabel"
11
+ class="flex flex-wrap justify-between"
12
+ >
13
+ <p class="text-[0.625rem] m-0 text-gray-medium">
10
14
  {{ startDate }}
11
15
  </p>
12
- <p class="text-xxs fr-m-0 text-mention-grey">
16
+ <p class="text-[0.625rem] m-0 text-gray-medium">
13
17
  {{ endDate }}
14
18
  </p>
15
19
  </div>
@@ -27,10 +31,16 @@ const LIGHT_COLOR_WITH_OPACITY = 'rgba(182, 207, 251, 0.7)'
27
31
 
28
32
  const props = withDefaults(defineProps<{
29
33
  data: Record<string, number>
30
- type: 'line' | 'bar'
34
+ height?: number
31
35
  lastWithLowEmphasis?: boolean
36
+ showAxisLabel?: boolean
37
+ type: 'line' | 'bar'
38
+ width?: number
32
39
  }>(), {
40
+ height: 30,
33
41
  lastWithLowEmphasis: false,
42
+ showAxisLabel: true,
43
+ width: 120,
34
44
  })
35
45
 
36
46
  const last = (ctx, value) => {
@@ -85,8 +95,10 @@ const startDate = computed(() => months.value.length ? getMonthYear(months.value
85
95
  const endDate = computed(() => months.value.length ? getMonthYear(months.value[months.value.length - 1]) : null)
86
96
 
87
97
  const OPTIONS = {
88
- animation: false,
89
- responsive: true,
98
+ animation: true,
99
+ devicePixelRatio: 1,
100
+ responsive: false,
101
+ clip: false,
90
102
  plugins: {
91
103
  legend: {
92
104
  display: false,
@@ -105,6 +117,7 @@ const OPTIONS = {
105
117
  backgroundColor: COLOR,
106
118
  borderColor: COLOR,
107
119
  borderJoinStyle: 'round',
120
+ borderWidth: 3,
108
121
  tension: 0.35,
109
122
  },
110
123
  point: {
@@ -125,7 +138,8 @@ const OPTIONS = {
125
138
  },
126
139
  layout: {
127
140
  padding: {
128
- top: 1.5, // half border width
141
+ top: 2, // half border width
142
+ bottom: 2,
129
143
  },
130
144
  },
131
145
  } satisfies ChartOptions
@@ -1,13 +1,87 @@
1
1
  <template>
2
+ <div v-if="size === 'sm'">
3
+ <h3 class="text-sm font-bold m-0">
4
+ {{ title }}
5
+ </h3>
6
+ <div class="flex flex-wrap items-center">
7
+ <ContentLoader
8
+ v-if="summary === null"
9
+ :width="39"
10
+ :height="24"
11
+ :speed="2"
12
+ primary-color="#f3f3f3"
13
+ secondary-color="#ecebeb"
14
+ >
15
+ <rect
16
+ x="0"
17
+ y="0"
18
+ rx="3"
19
+ ry="3"
20
+ width="39"
21
+ height="24"
22
+ />
23
+ </ContentLoader>
24
+ <p
25
+ v-else
26
+ class="font-extrabold leading-none m-0"
27
+ >
28
+ {{ summarize(summary, 2) }}
29
+ </p>
30
+ <ContentLoader
31
+ v-if="data === null"
32
+ :width="77"
33
+ :height="19"
34
+ :speed="2"
35
+ primary-color="#f3f3f3"
36
+ secondary-color="#ecebeb"
37
+ class="ml-2"
38
+ >
39
+ <rect
40
+ x="0"
41
+ y="0"
42
+ rx="3"
43
+ ry="3"
44
+ width="77"
45
+ height="19"
46
+ />
47
+ </ContentLoader>
48
+ <div
49
+ v-else-if="changesThisYear"
50
+ class="ml-2"
51
+ >
52
+ <SmallChart
53
+ :type
54
+ :data
55
+ :last-with-low-emphasis="true"
56
+ :show-axis-label="false"
57
+ :height="19"
58
+ :width="77"
59
+ />
60
+ </div>
61
+ </div>
62
+ <template v-if="lastValue && lastMonth">
63
+ <p class="mt-1 mb-0 text-xs">
64
+ {{ $t('depuis juillet 2022') }}
65
+ </p>
66
+ <p class="mt-1 mb-0 text-xs text-success-darkest">
67
+ <strong>
68
+ + {{ summarize(lastValue, 2) }}
69
+ </strong>
70
+ {{ t(" en ") }}
71
+ {{ formatDate(lastMonth, { dateStyle: undefined, year: 'numeric', month: 'short', day: undefined }) }}
72
+ </p>
73
+ </template>
74
+ </div>
2
75
  <div
76
+ v-else
3
77
  :class="{
4
78
  'text-gray-medium': !changesThisYear && !summary,
5
79
  }"
6
80
  >
7
- <h3 class="fr-text--sm fr-m-0">
81
+ <h3 class="text-sm m-0">
8
82
  {{ title }}
9
83
  </h3>
10
- <div class="fr-grid-row fr-grid-row--middle">
84
+ <div class="flex flex-wrap items-center">
11
85
  <ContentLoader
12
86
  v-if="summary === null"
13
87
  :width="92"
@@ -27,7 +101,7 @@
27
101
  </ContentLoader>
28
102
  <p
29
103
  v-else
30
- class="h1 line-height-1 fr-m-0"
104
+ class="font-extrabold text-[2rem] leading-none m-0"
31
105
  >
32
106
  {{ summarize(summary, 2) }}
33
107
  </p>
@@ -38,7 +112,7 @@
38
112
  :speed="2"
39
113
  primary-color="#f3f3f3"
40
114
  secondary-color="#ecebeb"
41
- class="fr-ml-1w"
115
+ class="ml-2"
42
116
  >
43
117
  <rect
44
118
  x="0"
@@ -51,7 +125,7 @@
51
125
  </ContentLoader>
52
126
  <div
53
127
  v-else-if="changesThisYear"
54
- class="fr-ml-1w"
128
+ class="ml-2"
55
129
  >
56
130
  <SmallChart
57
131
  :type
@@ -62,12 +136,12 @@
62
136
  </div>
63
137
  <p
64
138
  v-if="lastValue && lastMonth"
65
- class="fr-mt-1w fr-text--regular text-transform-none fr-badge fr-badge--no-icon fr-badge--success"
139
+ class="mt-2 font-normal text-transform-none fr-badge fr-badge--no-icon fr-badge--success"
66
140
  >
67
- <strong class="fr-mr-1v">
141
+ <strong class="mr-1">
68
142
  + {{ summarize(lastValue, 2) }}
69
143
  </strong>
70
- {{ t(" in ") }}
144
+ {{ t(" en ") }}
71
145
  {{ formatDate(lastMonth, { dateStyle: undefined, year: 'numeric', month: 'short', day: undefined }) }}
72
146
  </p>
73
147
  </div>
@@ -77,7 +151,7 @@
77
151
  import { computed } from 'vue'
78
152
  import { useI18n } from 'vue-i18n'
79
153
  import { ContentLoader } from 'vue-content-loader'
80
- import { formatDate } from '../functions/dates'
154
+ import { useFormatDate } from '../functions/dates'
81
155
  import { summarize } from '../functions/helpers'
82
156
  import SmallChart from './SmallChart.vue'
83
157
 
@@ -85,10 +159,12 @@ const props = defineProps<{
85
159
  title: string
86
160
  data: Record<string, number> | null
87
161
  type: 'line' | 'bar'
88
- summary: number | null
162
+ size?: 'sm'
163
+ summary?: number | null
89
164
  }>()
90
165
 
91
166
  const { t } = useI18n()
167
+ const { formatDate } = useFormatDate()
92
168
 
93
169
  const months = computed(() => props.data ? Object.keys(props.data) : [])
94
170
  const values = computed(() => props.data ? Object.values(props.data) : [])
@@ -97,4 +173,10 @@ const lastMonthIndex = computed(() => lastMonth.value ? months.value.indexOf(las
97
173
  const lastValue = computed(() => lastMonthIndex.value !== null ? values.value[lastMonthIndex.value] : null)
98
174
 
99
175
  const changesThisYear = computed(() => Math.max(...values.value) > 0)
176
+ const summary = computed(() => {
177
+ if (props.summary !== undefined) return props.summary
178
+ if (!props.data) return null
179
+
180
+ return Object.values(props.data).reduce((a, b) => a + b, 0)
181
+ })
100
182
  </script>
package/src/config.ts CHANGED
@@ -8,15 +8,19 @@ export type PluginConfig = {
8
8
  devApiKey?: string | null
9
9
  staticUrl: string
10
10
  datasetQualityGuideUrl?: string
11
- schemaValidataUrl: string
12
- schemaDocumentationUrl: string
11
+ schemaValidataUrl?: string
12
+ schemaDocumentationUrl?: string
13
13
  tabularApiUrl?: string
14
14
  tabularApiPageSize?: number
15
15
  tabularAllowRemote?: boolean
16
16
  tabularApiDataserviceId?: string
17
+ pmtilesViewerBaseUrl?: string | null // Base URL of a pmtiles viewer (ex: https://pmtiles.io/#url=)
17
18
  customUseFetch?: UseFetchFunction | null
18
19
  textClamp?: string | Component | null
19
20
  appLink?: Component | null
21
+ maxJsonPreviewSize?: number // Maximum size of JSON to preview in characters
22
+ maxPdfPreviewSize?: number // Maximum size of PDF to preview in bytes
23
+ maxXmlPreviewSize?: number // Maximum size of XML to preview in characters
20
24
  i18n?: {
21
25
  global: {
22
26
  mergeLocaleMessage: (locale: string, messages: unknown) => void
@@ -10,7 +10,7 @@ export async function useFetch<DataT, ErrorT = never>(
10
10
  ): Promise<AsyncData<DataT, ErrorT>> {
11
11
  const config = useComponentsConfig()
12
12
 
13
- const { t, locale } = useI18n()
13
+ const { locale } = useI18n()
14
14
 
15
15
  if (config.customUseFetch) {
16
16
  return await config.customUseFetch(url, options)
@@ -20,7 +20,7 @@ export async function useFetch<DataT, ErrorT = never>(
20
20
  const error: Ref<ErrorT | null> = ref(null)
21
21
  const status = ref<AsyncDataRequestStatus>('idle')
22
22
 
23
- const execute = async (opts?: AsyncDataExecuteOptions) => {
23
+ const execute = async (_opts?: AsyncDataExecuteOptions) => {
24
24
  const urlValue = toValue(url)
25
25
  if (!urlValue) return
26
26
  status.value = 'pending'
@@ -42,26 +42,26 @@ export async function useFetch<DataT, ErrorT = never>(
42
42
  options.params['lang'] = locale.value
43
43
  }
44
44
  },
45
- async onResponseError({ response }) {
45
+ async onResponseError() {
46
46
  // TODO redirect to login outside Nuxt?
47
47
  // if (response.status === 401) {
48
48
  // await nuxtApp.runWithContext(() => navigateTo(localePath('/login')))
49
49
  // }
50
50
 
51
- let message
52
- try {
53
- if ('error' in response._data) {
54
- message = response._data.error
55
- }
56
- else if ('message' in response._data) {
57
- message = response._data.message
58
- }
59
- }
60
- catch (e) {
61
- console.error(e)
62
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
63
- message = t('The API returned an unexpected error')
64
- }
51
+ // let message
52
+ // try {
53
+ // if ('error' in response._data) {
54
+ // message = response._data.error
55
+ // }
56
+ // else if ('message' in response._data) {
57
+ // message = response._data.message
58
+ // }
59
+ // }
60
+ // catch (e) {
61
+ // console.error(e)
62
+ // // eslint-disable-next-line @typescript-eslint/no-unused-vars
63
+ // message = t(`L'API a retourné une erreur inattendue`)
64
+ // }
65
65
 
66
66
  // TODO Toast outside Nuxt
67
67
  // toast.error(message)
@@ -82,7 +82,7 @@ export async function useFetch<DataT, ErrorT = never>(
82
82
 
83
83
  return {
84
84
  data,
85
- refresh: async (opts?: AsyncDataExecuteOptions) => {
85
+ refresh: async (_opts?: AsyncDataExecuteOptions) => {
86
86
  execute()
87
87
  },
88
88
  execute,