@datagouv/components-next 1.0.2-dev.192 → 1.0.2-dev.194

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/dist/{Datafair.client-fxOwwaND.js → Datafair.client-Drn-ygd-.js} +1 -1
  2. package/dist/{ImagePreview.client-XSR9THWR.js → ImagePreview.client-DCzPQ-xK.js} +1 -1
  3. package/dist/{JsonPreview.client-CU1FWFIy.js → JsonPreview.client-Dqioe7mC.js} +2 -2
  4. package/dist/{MapContainer.client-D0-Dn7jq.js → MapContainer.client-CV5ZRvvr.js} +2 -2
  5. package/dist/{PdfPreview.client-B7eDgq8y.js → PdfPreview.client-XFmjFK8r.js} +2 -2
  6. package/dist/{Pmtiles.client-CCpvggkZ.js → Pmtiles.client-DAp930rV.js} +1 -1
  7. package/dist/{PreviewWrapper.vue_vue_type_script_setup_true_lang-BzhNjYoY.js → PreviewWrapper.vue_vue_type_script_setup_true_lang-BkPS3zke.js} +1 -1
  8. package/dist/{XmlPreview.client-CyjpNh5i.js → XmlPreview.client-zetBGS4F.js} +3 -3
  9. package/dist/components-next.css +1 -1
  10. package/dist/components-next.js +164 -163
  11. package/dist/{index-BBnxH-Nj.js → index-DWuJwKzS.js} +1 -1
  12. package/dist/{leaflet-src-Be0Ohp2k.js → leaflet-src-DiG78UoJ.js} +1 -1
  13. package/dist/{main-C2kCZkPD.js → main-dOC1WJIR.js} +12194 -12006
  14. package/dist/{vue3-xml-viewer.common-__BZsi8i.js → vue3-xml-viewer.common-D1KbuT3v.js} +1 -1
  15. package/package.json +1 -1
  16. package/src/components/ActivityList/ActivityList.vue +21 -12
  17. package/src/components/DataserviceCard.vue +15 -5
  18. package/src/components/DatasetCard.vue +15 -5
  19. package/src/components/DatasetInformation/DatasetTemporalitySection.vue +7 -4
  20. package/src/components/DiscussionMessageCard.vue +14 -15
  21. package/src/components/FormattedDate.vue +81 -0
  22. package/src/components/PostCard.vue +13 -15
  23. package/src/components/ResourceAccordion/Downloads.vue +19 -7
  24. package/src/components/ResourceAccordion/Metadata.vue +3 -4
  25. package/src/components/ResourceAccordion/Preview.vue +8 -4
  26. package/src/components/ResourceAccordion/ResourceAccordion.vue +13 -3
  27. package/src/components/ResourceExplorer/ResourceExplorerHeader.vue +10 -5
  28. package/src/components/ResourceExplorer/ResourceViewerHeader.vue +10 -3
  29. package/src/components/ResourceListItem.vue +10 -3
  30. package/src/components/ReuseCard.vue +14 -3
  31. package/src/components/SmallChart.vue +11 -10
  32. package/src/components/StatBox.vue +13 -5
  33. package/src/components/TabularExplorer/types.ts +15 -12
  34. package/src/components/TabularExplorer/useColumnMetadata.ts +1 -1
  35. package/src/components/TopicCard.vue +13 -14
  36. package/src/functions/charts.ts +2 -2
  37. package/src/functions/dates.ts +3 -5
  38. package/src/main.ts +2 -0
@@ -59,7 +59,14 @@
59
59
  >
60
60
  <span class="block whitespace-nowrap text-[13px] font-medium leading-5 text-gray-title">{{ resource.title || t('Fichier sans nom') }}</span>
61
61
  <div class="mt-1 flex items-center gap-1 text-[12px] leading-4 text-gray-medium">
62
- <span>{{ t('mis à jour {date}', { date: formatRelativeIfRecentDate(resource.last_modified) }) }}</span>
62
+ <TranslationT keypath="mis à jour {date}">
63
+ <template #date>
64
+ <FormattedDate
65
+ :date="resource.last_modified"
66
+ format="relative"
67
+ />
68
+ </template>
69
+ </TranslationT>
63
70
  <template v-if="humanFilesize">
64
71
  <span>·</span>
65
72
  <span>{{ humanFilesize }}</span>
@@ -91,9 +98,10 @@ import { RiDownloadLine } from '@remixicon/vue'
91
98
  import AppLink from './AppLink.vue'
92
99
  import ClientOnly from './ClientOnly.vue'
93
100
  import File from './Icons/File.vue'
101
+ import FormattedDate from './FormattedDate.vue'
102
+ import TranslationT from './TranslationT.vue'
94
103
  import { getResourceFormatIcon, getResourceIconColor, getResourceFilesize } from '../functions/resources'
95
104
  import { filesize, summarize } from '../functions/helpers'
96
- import { useFormatDate } from '../functions/dates'
97
105
  import { useTranslation } from '../composables/useTranslation'
98
106
  import type { Resource } from '../types/resources'
99
107
 
@@ -116,7 +124,6 @@ const props = withDefaults(defineProps<{
116
124
  })
117
125
 
118
126
  const { t } = useTranslation()
119
- const { formatRelativeIfRecentDate } = useFormatDate()
120
127
 
121
128
  // Render the icon directly (not via ResourceIcon which forces a gray color) so the
122
129
  // colored badge can tint it through currentColor + [&_svg]:fill-current.
@@ -21,7 +21,18 @@
21
21
  :organization-url="organizationUrl"
22
22
  />
23
23
  <RiSubtractLine class="size-4 flex-none fill-gray-medium" />
24
- <span class="block flex-none">{{ t('publié {date}', { date: formatRelativeIfRecentDate(reuse.created_at, { dateStyle: 'medium' }) }) }}</span>
24
+ <TranslationT
25
+ class="block flex-none"
26
+ keypath="publié {date}"
27
+ >
28
+ <template #date>
29
+ <FormattedDate
30
+ :date="reuse.created_at"
31
+ format="relative"
32
+ :options="{ dateStyle: 'medium' }"
33
+ />
34
+ </template>
35
+ </TranslationT>
25
36
  </div>
26
37
  <ReuseDetails :reuse />
27
38
  </div>
@@ -67,7 +78,6 @@
67
78
  import { RiLockLine, RiSubtractLine } from '@remixicon/vue'
68
79
  import { computed } from 'vue'
69
80
  import type { RouteLocationRaw } from 'vue-router'
70
- import { useFormatDate } from '../functions/dates'
71
81
  import type { Reuse, ReuseV2 } from '../types/reuses'
72
82
  import type { TitleTag } from '../types/ui'
73
83
  import { useTranslation } from '../composables/useTranslation'
@@ -75,6 +85,8 @@ import AppLink from './AppLink.vue'
75
85
  import ObjectCardOwner from './ObjectCardOwner.vue'
76
86
  import ReuseDetails from './ReuseDetails.vue'
77
87
  import Placeholder from './Placeholder.vue'
88
+ import FormattedDate from './FormattedDate.vue'
89
+ import TranslationT from './TranslationT.vue'
78
90
 
79
91
  const props = withDefaults(defineProps<{
80
92
  reuse: Reuse | ReuseV2
@@ -97,7 +109,6 @@ const props = withDefaults(defineProps<{
97
109
  })
98
110
 
99
111
  const { t } = useTranslation()
100
- const { formatRelativeIfRecentDate } = useFormatDate()
101
112
 
102
113
  const reuseUrl = computed(() => props.reuseUrl || props.reuse.page)
103
114
  </script>
@@ -11,10 +11,16 @@
11
11
  class="flex flex-wrap justify-between"
12
12
  >
13
13
  <p class="text-[0.625rem] m-0 text-gray-medium">
14
- {{ startDate }}
14
+ <FormattedDate
15
+ :date="startDate"
16
+ :options="{ dateStyle: undefined, year: '2-digit', month: '2-digit' }"
17
+ />
15
18
  </p>
16
19
  <p class="text-[0.625rem] m-0 text-gray-medium">
17
- {{ endDate }}
20
+ <FormattedDate
21
+ :date="endDate"
22
+ :options="{ dateStyle: undefined, year: '2-digit', month: '2-digit' }"
23
+ />
18
24
  </p>
19
25
  </div>
20
26
  </div>
@@ -24,6 +30,7 @@
24
30
  import type { ChartOptions, ScriptableLineSegmentContext } from 'chart.js'
25
31
  import Chart from 'chart.js/auto'
26
32
  import { computed, onMounted, ref, useTemplateRef, watchEffect } from 'vue'
33
+ import FormattedDate from './FormattedDate.vue'
27
34
 
28
35
  const LIGHT_COLOR = '#B6CFFB'
29
36
  const COLOR = '#3558A2'
@@ -107,14 +114,8 @@ const additionalDatasetConfig = computed<{
107
114
  return {}
108
115
  })
109
116
 
110
- const getMonthYear = (dateAsString: string): string => {
111
- const date = new Date(dateAsString)
112
-
113
- return `${(date.getMonth() + 1).toString().padStart(2, '0')}/${date.getFullYear().toString().slice(-2)}`
114
- }
115
-
116
- const startDate = computed(() => months.value.length ? getMonthYear(months.value[0]!) : null)
117
- const endDate = computed(() => months.value.length ? getMonthYear(months.value[months.value.length - 1]!) : null)
117
+ const startDate = computed(() => months.value[0] ?? null)
118
+ const endDate = computed(() => months.value[months.value.length - 1] ?? null)
118
119
 
119
120
  const OPTIONS = {
120
121
  // @ts-expect-error animation can be `true` but the typing is not expecting it
@@ -65,14 +65,20 @@
65
65
  class="mt-1 mb-0 text-xs"
66
66
  >
67
67
  {{ t("depuis ") }}
68
- {{ formatDate(since, { dateStyle: undefined, year: 'numeric', month: 'short', day: undefined }) }}
68
+ <FormattedDate
69
+ :date="since"
70
+ :options="{ dateStyle: undefined, year: 'numeric', month: 'short', day: undefined }"
71
+ />
69
72
  </p>
70
73
  <p class="mt-1 mb-0 text-xs text-success-darkest">
71
74
  <strong>
72
75
  + {{ summarize(lastValue, 2) }}
73
76
  </strong>
74
77
  {{ t(" en ") }}
75
- {{ formatDate(lastMonth, { dateStyle: undefined, year: 'numeric', month: 'short', day: undefined }) }}
78
+ <FormattedDate
79
+ :date="lastMonth"
80
+ :options="{ dateStyle: undefined, year: 'numeric', month: 'short', day: undefined }"
81
+ />
76
82
  </p>
77
83
  </template>
78
84
  </div>
@@ -146,7 +152,10 @@
146
152
  + {{ summarize(lastValue, 2) }}
147
153
  </strong>
148
154
  {{ t(" en ") }}
149
- {{ formatDate(lastMonth, { dateStyle: undefined, year: 'numeric', month: 'short', day: undefined }) }}
155
+ <FormattedDate
156
+ :date="lastMonth"
157
+ :options="{ dateStyle: undefined, year: 'numeric', month: 'short', day: undefined }"
158
+ />
150
159
  </p>
151
160
  </div>
152
161
  </template>
@@ -154,7 +163,7 @@
154
163
  <script setup lang="ts">
155
164
  import { computed } from 'vue'
156
165
  import { ContentLoader } from 'vue-content-loader'
157
- import { useFormatDate } from '../functions/dates'
166
+ import FormattedDate from './FormattedDate.vue'
158
167
  import { summarize } from '../functions/helpers'
159
168
  import { useTranslation } from '../composables/useTranslation'
160
169
  import SmallChart from './SmallChart.vue'
@@ -169,7 +178,6 @@ const props = defineProps<{
169
178
  }>()
170
179
 
171
180
  const { t } = useTranslation()
172
- const { formatDate } = useFormatDate()
173
181
 
174
182
  const months = computed(() => props.data ? Object.keys(props.data) : [])
175
183
  const values = computed(() => props.data ? Object.values(props.data) : [])
@@ -24,25 +24,28 @@ export type TabularProfileResponse = {
24
24
  indexes: null
25
25
  }
26
26
 
27
+ // Only CSV resources go through csv-detective: for the other formats the API
28
+ // indexes (parquet…), the profile is reduced to the column names, their types
29
+ // and the row count. Everything csv-detective produces is therefore optional.
27
30
  export type TabularProfile = {
28
31
  header: string[]
29
32
  columns: Record<string, TabularColumnInfo>
30
- formats: Record<string, string[]>
31
- profile: Record<string, TabularColumnProfile>
32
- encoding: string
33
- separator: string
34
- categorical: string[]
35
33
  total_lines: number
36
- nb_duplicates: number
37
- columns_fields: Record<string, TabularColumnInfo>
38
- columns_labels: Record<string, TabularColumnInfo>
39
- header_row_idx: number
40
- heading_columns: number
41
- trailing_columns: number
34
+ formats?: Record<string, string[]>
35
+ profile?: Record<string, TabularColumnProfile>
36
+ encoding?: string
37
+ separator?: string
38
+ categorical?: string[]
39
+ nb_duplicates?: number
40
+ columns_fields?: Record<string, TabularColumnInfo>
41
+ columns_labels?: Record<string, TabularColumnInfo>
42
+ header_row_idx?: number
43
+ heading_columns?: number
44
+ trailing_columns?: number
42
45
  }
43
46
 
44
47
  export type TabularColumnInfo = {
45
- score: number
48
+ score?: number
46
49
  format: string
47
50
  python_type: string
48
51
  }
@@ -38,7 +38,7 @@ export function useColumnMetadata(
38
38
  if (!profile) return 'text'
39
39
  const colInfo = profile.columns[col]
40
40
  if (!colInfo) return 'text'
41
- return resolveColumnType(colInfo, profile.categorical.includes(col))
41
+ return resolveColumnType(colInfo, profile.categorical?.includes(col) ?? false)
42
42
  }
43
43
 
44
44
  const columnTypesMap = computed<Record<string, ColumnType>>(() => {
@@ -41,12 +41,20 @@
41
41
  aria-hidden="true"
42
42
  class="hidden md:block size-4 flex-none fill-gray-medium"
43
43
  />
44
- <div
44
+ <TranslationT
45
45
  v-if="topic.last_modified"
46
+ tag="div"
46
47
  class="w-full md:w-auto text-gray-medium whitespace-nowrap"
48
+ keypath="Mis à jour {date}"
47
49
  >
48
- {{ t('Mis à jour {date}', { date: formatDate(topic.last_modified) }) }}
49
- </div>
50
+ <template #date>
51
+ <FormattedDate
52
+ :date="topic.last_modified"
53
+ format="relative"
54
+ :options="{ dateStyle: 'long' }"
55
+ />
56
+ </template>
57
+ </TranslationT>
50
58
  </div>
51
59
 
52
60
  <ObjectCardShortDescription :text="topic.description" />
@@ -97,8 +105,6 @@
97
105
  import { RiBookShelfLine, RiDatabase2Line, RiLineChartLine, RiSubtractLine, RiTerminalLine } from '@remixicon/vue'
98
106
  import type { RouteLocationRaw } from 'vue-router'
99
107
  import type { TopicV2 } from '../types/topics'
100
- import { useFormatDate } from '../functions/dates'
101
- import { useTranslation } from '../composables/useTranslation'
102
108
  import ObjectCardHeader from './ObjectCardHeader.vue'
103
109
  import ObjectCardOwner from './ObjectCardOwner.vue'
104
110
  import ObjectCardShortDescription from './ObjectCardShortDescription.vue'
@@ -106,6 +112,8 @@ import OrganizationLogo from './OrganizationLogo.vue'
106
112
  import Avatar from './Avatar.vue'
107
113
  import Placeholder from './Placeholder.vue'
108
114
  import ObjectCard from './ObjectCard.vue'
115
+ import FormattedDate from './FormattedDate.vue'
116
+ import TranslationT from './TranslationT.vue'
109
117
 
110
118
  type TopicWithStats = TopicV2 & {
111
119
  nb_datasets?: number
@@ -122,13 +130,4 @@ withDefaults(defineProps<{
122
130
  showLogo: true,
123
131
  showStats: true,
124
132
  })
125
-
126
- const { t } = useTranslation()
127
- const { formatRelativeIfRecentDate } = useFormatDate()
128
-
129
- const formatDate = (dateString: string) => {
130
- return formatRelativeIfRecentDate(dateString, {
131
- dateStyle: 'long',
132
- })
133
- }
134
133
  </script>
@@ -72,13 +72,13 @@ export function toChartApi(chartForm: ChartForm): ChartForApi {
72
72
  export function buildColumnsFromProfile(profile: { profile: TabularProfile }): Array<ColumnDefinition> {
73
73
  return profile.profile.header.map((name) => {
74
74
  const colInfo = profile.profile.columns[name]
75
- const isCategorical = profile.profile.categorical.includes(name)
75
+ const isCategorical = profile.profile.categorical?.includes(name) ?? false
76
76
  // The chart stack only branches on 'number' and 'date' (continuous axis,
77
77
  // aggregatable series, time formatting): it has no notion of a year column,
78
78
  // and on an axis a year is a number.
79
79
  const resolvedType = resolveColumnType(colInfo ?? { python_type: 'unknown', format: undefined }, isCategorical)
80
80
  const colType = resolvedType === 'year' ? 'number' : resolvedType
81
- const colProfile = profile.profile.profile[name]
81
+ const colProfile = profile.profile.profile?.[name]
82
82
  return {
83
83
  name,
84
84
  type: colType,
@@ -9,11 +9,9 @@ export function useFormatDate() {
9
9
  if (!date) {
10
10
  return ''
11
11
  }
12
- date = new Date(date)
13
- if (!('dateStyle' in options)) {
14
- options.dateStyle = 'long'
15
- }
16
- return new Intl.DateTimeFormat(locale, options).format(date)
12
+ // An explicit `dateStyle: undefined` overrides the default, which is how callers ask
13
+ // for `year`/`month` components — `dateStyle` and those cannot be combined.
14
+ return new Intl.DateTimeFormat(locale, { dateStyle: 'long', ...options }).format(new Date(date))
17
15
  }
18
16
 
19
17
  /**
package/src/main.ts CHANGED
@@ -51,6 +51,7 @@ import DescriptionListTerm from './components/DescriptionListTerm.vue'
51
51
  import DescriptionListDetails from './components/DescriptionListDetails.vue'
52
52
  import DiscussionMessageCard from './components/DiscussionMessageCard.vue'
53
53
  import DateRangeDetails from './components/DateRangeDetails.vue'
54
+ import FormattedDate from './components/FormattedDate.vue'
54
55
  import { DatasetInformationSection, DatasetTemporalitySection, DatasetSpatialSection, DatasetSchemaSection, DatasetEmbedSection } from './components/DatasetInformation'
55
56
  import LeafletMap from './components/LeafletMap.vue'
56
57
  import LicenseBadge from './components/LicenseBadge.vue'
@@ -366,6 +367,7 @@ export {
366
367
  QualityScore,
367
368
  DatasetQualityTooltipContent,
368
369
  DateRangeDetails,
370
+ FormattedDate,
369
371
  ExtraAccordion,
370
372
  LabelTag,
371
373
  LeafletMap,