@datagouv/components-next 1.0.2-dev.192 → 1.0.2-dev.193
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{Datafair.client-fxOwwaND.js → Datafair.client-w30urimy.js} +1 -1
- package/dist/{ImagePreview.client-XSR9THWR.js → ImagePreview.client-DVAf75eI.js} +1 -1
- package/dist/{JsonPreview.client-CU1FWFIy.js → JsonPreview.client-BO4FYlVq.js} +2 -2
- package/dist/{MapContainer.client-D0-Dn7jq.js → MapContainer.client-D5ZOWzlJ.js} +2 -2
- package/dist/{PdfPreview.client-B7eDgq8y.js → PdfPreview.client-Cal_OaFX.js} +2 -2
- package/dist/{Pmtiles.client-CCpvggkZ.js → Pmtiles.client-DWfTeeOk.js} +1 -1
- package/dist/{PreviewWrapper.vue_vue_type_script_setup_true_lang-BzhNjYoY.js → PreviewWrapper.vue_vue_type_script_setup_true_lang-CNDEB-3x.js} +1 -1
- package/dist/{XmlPreview.client-CyjpNh5i.js → XmlPreview.client-C8GN6y1u.js} +3 -3
- package/dist/components-next.css +1 -1
- package/dist/components-next.js +164 -163
- package/dist/{index-BBnxH-Nj.js → index-WRb99DNu.js} +1 -1
- package/dist/{leaflet-src-Be0Ohp2k.js → leaflet-src-DJeNmzLc.js} +1 -1
- package/dist/{main-C2kCZkPD.js → main-B3IzELg_.js} +12194 -12006
- package/dist/{vue3-xml-viewer.common-__BZsi8i.js → vue3-xml-viewer.common-AEbzQxXP.js} +1 -1
- package/package.json +1 -1
- package/src/components/ActivityList/ActivityList.vue +21 -12
- package/src/components/DataserviceCard.vue +15 -5
- package/src/components/DatasetCard.vue +15 -5
- package/src/components/DatasetInformation/DatasetTemporalitySection.vue +7 -4
- package/src/components/DiscussionMessageCard.vue +14 -15
- package/src/components/FormattedDate.vue +81 -0
- package/src/components/PostCard.vue +13 -15
- package/src/components/ResourceAccordion/Downloads.vue +19 -7
- package/src/components/ResourceAccordion/Metadata.vue +3 -4
- package/src/components/ResourceAccordion/Preview.vue +8 -4
- package/src/components/ResourceAccordion/ResourceAccordion.vue +13 -3
- package/src/components/ResourceExplorer/ResourceExplorerHeader.vue +10 -5
- package/src/components/ResourceExplorer/ResourceViewerHeader.vue +10 -3
- package/src/components/ResourceListItem.vue +10 -3
- package/src/components/ReuseCard.vue +14 -3
- package/src/components/SmallChart.vue +11 -10
- package/src/components/StatBox.vue +13 -5
- package/src/components/TopicCard.vue +13 -14
- package/src/functions/dates.ts +3 -5
- package/src/main.ts +2 -0
package/package.json
CHANGED
|
@@ -12,7 +12,10 @@
|
|
|
12
12
|
class="my-1"
|
|
13
13
|
>
|
|
14
14
|
<p class="pl-3 mb-1 text-xs text-gray-medium">
|
|
15
|
-
|
|
15
|
+
<FormattedDate
|
|
16
|
+
:date="month"
|
|
17
|
+
:options="{ dateStyle: undefined, year: 'numeric', month: 'long', day: undefined }"
|
|
18
|
+
/>
|
|
16
19
|
</p>
|
|
17
20
|
<ul
|
|
18
21
|
class="space-y-2 p-0 m-0"
|
|
@@ -82,9 +85,15 @@
|
|
|
82
85
|
</template>
|
|
83
86
|
</slot>
|
|
84
87
|
</p>
|
|
85
|
-
<
|
|
86
|
-
|
|
87
|
-
|
|
88
|
+
<TranslationT
|
|
89
|
+
tag="p"
|
|
90
|
+
class="m-0 flex-none text-xs text-gray-medium"
|
|
91
|
+
keypath="le {date}"
|
|
92
|
+
>
|
|
93
|
+
<template #date>
|
|
94
|
+
<FormattedDate :date="activity.created_at" />
|
|
95
|
+
</template>
|
|
96
|
+
</TranslationT>
|
|
88
97
|
</div>
|
|
89
98
|
</li>
|
|
90
99
|
</ul>
|
|
@@ -118,13 +127,14 @@ import { useRoute } from 'vue-router'
|
|
|
118
127
|
import { useTranslation } from '../../composables/useTranslation'
|
|
119
128
|
import { getActivityTranslation } from '../../functions/activities'
|
|
120
129
|
import { useFetch } from '../../functions/api'
|
|
121
|
-
import { useFormatDate } from '../../functions/dates'
|
|
122
130
|
import type { PaginatedArray } from '../../types/api'
|
|
123
131
|
import type { Activity } from '../../types/activity'
|
|
124
132
|
import Avatar from '../Avatar.vue'
|
|
125
133
|
import LoadingBlock from '../LoadingBlock.vue'
|
|
126
134
|
import Pagination from '../Pagination.vue'
|
|
127
135
|
import PaddedContainer from '../PaddedContainer.vue'
|
|
136
|
+
import FormattedDate from '../FormattedDate.vue'
|
|
137
|
+
import TranslationT from '../TranslationT.vue'
|
|
128
138
|
import listSrc from '../../../assets/illustrations/list.svg?url'
|
|
129
139
|
|
|
130
140
|
const props = defineProps<{
|
|
@@ -133,7 +143,6 @@ const props = defineProps<{
|
|
|
133
143
|
}>()
|
|
134
144
|
|
|
135
145
|
const route = useRoute()
|
|
136
|
-
const { formatDate } = useFormatDate()
|
|
137
146
|
const { t } = useTranslation()
|
|
138
147
|
|
|
139
148
|
const page = ref(parseInt(route.query.page as string | undefined ?? '1', 10))
|
|
@@ -146,13 +155,13 @@ const { data: activities, status } = await useFetch<PaginatedArray<Activity>>('/
|
|
|
146
155
|
},
|
|
147
156
|
})
|
|
148
157
|
|
|
158
|
+
// Grouping on a month read in the reader's timezone would change both the number of
|
|
159
|
+
// groups and their keys between the server render and the browser's — a mismatch on
|
|
160
|
+
// the children themselves, which no `data-allow-mismatch` covers. The `YYYY-MM` the
|
|
161
|
+
// timestamp starts with is the same string for everyone; the month is worded from it
|
|
162
|
+
// at render time.
|
|
149
163
|
const groupedActivities = computed(() => activities.value?.data.reduce((grouped, activity) => {
|
|
150
|
-
const activityMonth =
|
|
151
|
-
dateStyle: undefined,
|
|
152
|
-
day: undefined,
|
|
153
|
-
month: 'long',
|
|
154
|
-
year: 'numeric',
|
|
155
|
-
})
|
|
164
|
+
const activityMonth = activity.created_at.slice(0, 7)
|
|
156
165
|
if (!grouped[activityMonth]) {
|
|
157
166
|
grouped[activityMonth] = []
|
|
158
167
|
}
|
|
@@ -71,9 +71,19 @@
|
|
|
71
71
|
class="size-4 flex-none fill-gray-medium"
|
|
72
72
|
/>
|
|
73
73
|
<!-- https://github.com/datagouv/cdata/issues/653 -->
|
|
74
|
-
<
|
|
75
|
-
|
|
76
|
-
|
|
74
|
+
<TranslationT
|
|
75
|
+
tag="p"
|
|
76
|
+
class="text-sm whitespace-nowrap mb-0 text-gray-medium"
|
|
77
|
+
keypath="Mis à jour {date}"
|
|
78
|
+
>
|
|
79
|
+
<template #date>
|
|
80
|
+
<FormattedDate
|
|
81
|
+
:date="dataservice.metadata_modified_at"
|
|
82
|
+
format="relative"
|
|
83
|
+
:options="{ dateStyle: 'medium' }"
|
|
84
|
+
/>
|
|
85
|
+
</template>
|
|
86
|
+
</TranslationT>
|
|
77
87
|
<RiSubtractLine
|
|
78
88
|
aria-hidden="true"
|
|
79
89
|
class="size-4 flex-none fill-gray-medium"
|
|
@@ -118,7 +128,6 @@ import { computed } from 'vue'
|
|
|
118
128
|
import type { RouteLocationRaw } from 'vue-router'
|
|
119
129
|
import { RiArchiveLine, RiEyeLine, RiLockLine, RiPassValidLine, RiSparklingLine, RiStarLine, RiSubtractLine, RiTerminalLine } from '@remixicon/vue'
|
|
120
130
|
import { useComponentsConfig } from '../config'
|
|
121
|
-
import { useFormatDate } from '../functions/dates'
|
|
122
131
|
import { summarize } from '../functions/helpers'
|
|
123
132
|
import type { Dataservice } from '../types/dataservices'
|
|
124
133
|
import type { TitleTag } from '../types/ui'
|
|
@@ -132,6 +141,8 @@ import ObjectCardHeader from './ObjectCardHeader.vue'
|
|
|
132
141
|
import ObjectCardOwner from './ObjectCardOwner.vue'
|
|
133
142
|
import ObjectCardShortDescription from './ObjectCardShortDescription.vue'
|
|
134
143
|
import DataserviceQualityInline from './DataserviceQualityInline.vue'
|
|
144
|
+
import FormattedDate from './FormattedDate.vue'
|
|
145
|
+
import TranslationT from './TranslationT.vue'
|
|
135
146
|
|
|
136
147
|
type Props = {
|
|
137
148
|
dataservice: Dataservice
|
|
@@ -146,7 +157,6 @@ const props = withDefaults(defineProps<Props>(), {
|
|
|
146
157
|
})
|
|
147
158
|
|
|
148
159
|
const { t } = useTranslation()
|
|
149
|
-
const { formatRelativeIfRecentDate } = useFormatDate()
|
|
150
160
|
|
|
151
161
|
const config = useComponentsConfig()
|
|
152
162
|
const isTabularApi = computed(() => {
|
|
@@ -56,9 +56,19 @@
|
|
|
56
56
|
:organization-url="organizationUrl"
|
|
57
57
|
/>
|
|
58
58
|
<RiSubtractLine class="hidden md:block size-4 flex-none fill-gray-medium" />
|
|
59
|
-
<
|
|
60
|
-
|
|
61
|
-
|
|
59
|
+
<TranslationT
|
|
60
|
+
tag="div"
|
|
61
|
+
class="w-full md:w-auto text-gray-medium whitespace-nowrap"
|
|
62
|
+
keypath="Mis à jour {date}"
|
|
63
|
+
>
|
|
64
|
+
<template #date>
|
|
65
|
+
<FormattedDate
|
|
66
|
+
:date="dataset.last_update"
|
|
67
|
+
format="relative"
|
|
68
|
+
:options="{ dateStyle: 'medium' }"
|
|
69
|
+
/>
|
|
70
|
+
</template>
|
|
71
|
+
</TranslationT>
|
|
62
72
|
</div>
|
|
63
73
|
<div class="mx-0 -mb-1 flex flex-wrap items-center text-sm text-gray-medium">
|
|
64
74
|
<div class="hidden sm:flex text-gray-medium">
|
|
@@ -122,7 +132,6 @@ import { RiArchiveLine, RiDatabase2Line, RiDownloadLine, RiEyeLine, RiLineChartL
|
|
|
122
132
|
import type { Dataset, DatasetV2 } from '../types/datasets'
|
|
123
133
|
import type { TitleTag } from '../types/ui'
|
|
124
134
|
import { summarize } from '../functions/helpers'
|
|
125
|
-
import { useFormatDate } from '../functions/dates'
|
|
126
135
|
import { getDescriptionShort } from '../functions/description'
|
|
127
136
|
import { useTranslation } from '../composables/useTranslation'
|
|
128
137
|
import DatasetQualityInline from './DatasetQualityInline.vue'
|
|
@@ -134,6 +143,8 @@ import ObjectCard from './ObjectCard.vue'
|
|
|
134
143
|
import ObjectCardBadge from './ObjectCardBadge.vue'
|
|
135
144
|
import ObjectCardHeader from './ObjectCardHeader.vue'
|
|
136
145
|
import ObjectCardShortDescription from './ObjectCardShortDescription.vue'
|
|
146
|
+
import FormattedDate from './FormattedDate.vue'
|
|
147
|
+
import TranslationT from './TranslationT.vue'
|
|
137
148
|
|
|
138
149
|
type Props = {
|
|
139
150
|
dataset: Dataset | DatasetV2
|
|
@@ -149,5 +160,4 @@ const props = withDefaults(defineProps<Props>(), {
|
|
|
149
160
|
})
|
|
150
161
|
|
|
151
162
|
const { t } = useTranslation()
|
|
152
|
-
const { formatRelativeIfRecentDate } = useFormatDate()
|
|
153
163
|
</script>
|
|
@@ -6,7 +6,9 @@
|
|
|
6
6
|
<DescriptionList>
|
|
7
7
|
<div>
|
|
8
8
|
<DescriptionListTerm>{{ t('Création') }}</DescriptionListTerm>
|
|
9
|
-
<DescriptionListDetails>
|
|
9
|
+
<DescriptionListDetails>
|
|
10
|
+
<FormattedDate :date="dataset.created_at" />
|
|
11
|
+
</DescriptionListDetails>
|
|
10
12
|
</div>
|
|
11
13
|
<div v-if="dataset.frequency">
|
|
12
14
|
<DescriptionListTerm>{{ t('Fréquence') }}</DescriptionListTerm>
|
|
@@ -20,7 +22,9 @@
|
|
|
20
22
|
</div>
|
|
21
23
|
<div>
|
|
22
24
|
<DescriptionListTerm>{{ t('Dernière mise à jour') }}</DescriptionListTerm>
|
|
23
|
-
<DescriptionListDetails>
|
|
25
|
+
<DescriptionListDetails>
|
|
26
|
+
<FormattedDate :date="dataset.last_update" />
|
|
27
|
+
</DescriptionListDetails>
|
|
24
28
|
</div>
|
|
25
29
|
<slot />
|
|
26
30
|
</DescriptionList>
|
|
@@ -29,17 +33,16 @@
|
|
|
29
33
|
|
|
30
34
|
<script setup lang="ts">
|
|
31
35
|
import { useTranslation } from '../../composables/useTranslation'
|
|
32
|
-
import { useFormatDate } from '../../functions/dates'
|
|
33
36
|
import type { DatasetV2WithFullObject } from '../../types/datasets'
|
|
34
37
|
import DescriptionList from '../DescriptionList.vue'
|
|
35
38
|
import DescriptionListTerm from '../DescriptionListTerm.vue'
|
|
36
39
|
import DescriptionListDetails from '../DescriptionListDetails.vue'
|
|
37
40
|
import DateRangeDetails from '../DateRangeDetails.vue'
|
|
41
|
+
import FormattedDate from '../FormattedDate.vue'
|
|
38
42
|
|
|
39
43
|
defineProps<{
|
|
40
44
|
dataset: DatasetV2WithFullObject
|
|
41
45
|
}>()
|
|
42
46
|
|
|
43
47
|
const { t } = useTranslation()
|
|
44
|
-
const { formatDate } = useFormatDate()
|
|
45
48
|
</script>
|
|
@@ -20,9 +20,18 @@
|
|
|
20
20
|
aria-hidden="true"
|
|
21
21
|
class="size-4 flex-none fill-gray-medium"
|
|
22
22
|
/>
|
|
23
|
-
<
|
|
24
|
-
|
|
25
|
-
|
|
23
|
+
<TranslationT
|
|
24
|
+
class="text-gray-medium whitespace-nowrap"
|
|
25
|
+
keypath="Posté {date}"
|
|
26
|
+
>
|
|
27
|
+
<template #date>
|
|
28
|
+
<FormattedDate
|
|
29
|
+
:date="discussion.created"
|
|
30
|
+
format="relative"
|
|
31
|
+
:options="{ dateStyle: 'long', timeStyle: 'short' }"
|
|
32
|
+
/>
|
|
33
|
+
</template>
|
|
34
|
+
</TranslationT>
|
|
26
35
|
</div>
|
|
27
36
|
|
|
28
37
|
<ObjectCardShortDescription :text="firstMessageContent" />
|
|
@@ -35,13 +44,13 @@
|
|
|
35
44
|
import { RiChat3Line, RiSubtractLine } from '@remixicon/vue'
|
|
36
45
|
import { computed } from 'vue'
|
|
37
46
|
import type { RouteLocationRaw } from 'vue-router'
|
|
38
|
-
import { useFormatDate } from '../functions/dates'
|
|
39
|
-
import { useTranslation } from '../composables/useTranslation'
|
|
40
47
|
import type { Thread } from '../types/discussions'
|
|
41
48
|
import ObjectCard from './ObjectCard.vue'
|
|
42
49
|
import ObjectCardHeader from './ObjectCardHeader.vue'
|
|
43
50
|
import ObjectCardOwner from './ObjectCardOwner.vue'
|
|
44
51
|
import ObjectCardShortDescription from './ObjectCardShortDescription.vue'
|
|
52
|
+
import FormattedDate from './FormattedDate.vue'
|
|
53
|
+
import TranslationT from './TranslationT.vue'
|
|
45
54
|
|
|
46
55
|
const props = defineProps<{
|
|
47
56
|
discussion: Thread
|
|
@@ -49,15 +58,5 @@ const props = defineProps<{
|
|
|
49
58
|
organizationUrl?: RouteLocationRaw
|
|
50
59
|
}>()
|
|
51
60
|
|
|
52
|
-
const { t } = useTranslation()
|
|
53
|
-
const { formatRelativeIfRecentDate } = useFormatDate()
|
|
54
|
-
|
|
55
61
|
const firstMessageContent = computed(() => props.discussion.discussion?.[0]?.content)
|
|
56
|
-
|
|
57
|
-
const formatDate = (dateString: string) => {
|
|
58
|
-
return formatRelativeIfRecentDate(dateString, {
|
|
59
|
-
dateStyle: 'long',
|
|
60
|
-
timeStyle: 'short',
|
|
61
|
-
})
|
|
62
|
-
}
|
|
63
62
|
</script>
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<!-- An instant is formatted in the server's timezone at render time and in the
|
|
3
|
+
reader's at read time, so its text and `title` legitimately differ and Vue is
|
|
4
|
+
told to accept it. A plain date carries no time, so nothing about it varies —
|
|
5
|
+
exempting it would hide a real bug instead of a legitimate difference. Vue only
|
|
6
|
+
honours `data-allow-mismatch` on an element whose children are plain text,
|
|
7
|
+
never on a text node coming from a slot: hence two static elements instead of a
|
|
8
|
+
`<component :is>`, which would pass the text through a slot. -->
|
|
9
|
+
<time
|
|
10
|
+
v-if="datetime"
|
|
11
|
+
:datetime
|
|
12
|
+
:title
|
|
13
|
+
:data-allow-mismatch="allowMismatch"
|
|
14
|
+
>{{ formatted }}</time>
|
|
15
|
+
<!-- No date to format: nothing here depends on the timezone or on "now". -->
|
|
16
|
+
<span v-else>{{ formatted }}</span>
|
|
17
|
+
</template>
|
|
18
|
+
|
|
19
|
+
<script setup lang="ts">
|
|
20
|
+
import { computed } from 'vue'
|
|
21
|
+
import { useFormatDate } from '../functions/dates'
|
|
22
|
+
|
|
23
|
+
const props = withDefaults(defineProps<{
|
|
24
|
+
date: Date | string | null | undefined
|
|
25
|
+
/**
|
|
26
|
+
* `date`: the full date. `relative`: "3 days ago" while the date is less than a
|
|
27
|
+
* month old, the full date beyond. `from-now`: always relative, however old.
|
|
28
|
+
*/
|
|
29
|
+
format?: 'date' | 'relative' | 'from-now'
|
|
30
|
+
options?: Intl.DateTimeFormatOptions
|
|
31
|
+
}>(), {
|
|
32
|
+
format: 'date',
|
|
33
|
+
options: () => ({}),
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
const { formatDate, formatFromNow, formatRelativeIfRecentDate } = useFormatDate()
|
|
37
|
+
|
|
38
|
+
// `2026`, `2026-04` and `2026-04-24` carry no time of day. `new Date()` reads them as
|
|
39
|
+
// midnight UTC, an instant they never claimed, and then converts it: a reader west of
|
|
40
|
+
// UTC gets the day before — and with it the month, and sometimes the year.
|
|
41
|
+
const PLAIN_DATE = /^(\d{4})(?:-(\d{2}))?(?:-(\d{2}))?$/
|
|
42
|
+
|
|
43
|
+
const plainDate = computed(() => typeof props.date === 'string' ? props.date.match(PLAIN_DATE) : null)
|
|
44
|
+
|
|
45
|
+
const parsed = computed(() => {
|
|
46
|
+
if (!props.date) return null
|
|
47
|
+
const plain = plainDate.value
|
|
48
|
+
const date = plain
|
|
49
|
+
? new Date(Number(plain[1]), Number(plain[2] ?? 1) - 1, Number(plain[3] ?? 1))
|
|
50
|
+
: new Date(props.date)
|
|
51
|
+
return isNaN(date.getTime()) ? null : date
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
// Announce the precision the value carries, never more: a month stays a month.
|
|
55
|
+
const datetime = computed(() => {
|
|
56
|
+
if (!parsed.value) return undefined
|
|
57
|
+
return plainDate.value ? plainDate.value[0] : parsed.value.toISOString()
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
// Only what genuinely differs between server and browser is exempted: an instant, and
|
|
61
|
+
// the relative forms, which are measured against "now".
|
|
62
|
+
const allowMismatch = computed(() => !plainDate.value || props.format !== 'date'
|
|
63
|
+
? 'text,attribute'
|
|
64
|
+
: undefined)
|
|
65
|
+
|
|
66
|
+
const formatted = computed(() => {
|
|
67
|
+
if (props.format === 'relative') return formatRelativeIfRecentDate(parsed.value, props.options)
|
|
68
|
+
if (props.format === 'from-now') return formatFromNow(parsed.value)
|
|
69
|
+
return formatDate(parsed.value, props.options)
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
// Hovering an instant gives the exact moment, which the displayed form usually omits:
|
|
73
|
+
// the relative forms drop it entirely, and most styles drop the time. A plain date has
|
|
74
|
+
// no moment to reveal — a `title` there would be one we made up, and a form that already
|
|
75
|
+
// spells the moment out needs no tooltip repeating it word for word.
|
|
76
|
+
const title = computed(() => {
|
|
77
|
+
if (!parsed.value || plainDate.value) return undefined
|
|
78
|
+
const exact = formatDate(parsed.value, { dateStyle: 'long', timeStyle: 'short' })
|
|
79
|
+
return exact === formatted.value ? undefined : exact
|
|
80
|
+
})
|
|
81
|
+
</script>
|
|
@@ -23,12 +23,20 @@
|
|
|
23
23
|
|
|
24
24
|
<ObjectCardShortDescription :text="post.headline || post.content" />
|
|
25
25
|
|
|
26
|
-
<
|
|
26
|
+
<TranslationT
|
|
27
27
|
v-if="post.published || post.created_at"
|
|
28
|
+
tag="div"
|
|
28
29
|
class="text-sm text-gray-medium mt-1"
|
|
30
|
+
keypath="Publié {date}"
|
|
29
31
|
>
|
|
30
|
-
|
|
31
|
-
|
|
32
|
+
<template #date>
|
|
33
|
+
<FormattedDate
|
|
34
|
+
:date="post.published || post.created_at"
|
|
35
|
+
format="relative"
|
|
36
|
+
:options="{ dateStyle: 'long', timeStyle: 'short' }"
|
|
37
|
+
/>
|
|
38
|
+
</template>
|
|
39
|
+
</TranslationT>
|
|
32
40
|
|
|
33
41
|
<slot />
|
|
34
42
|
</ObjectCard>
|
|
@@ -37,26 +45,16 @@
|
|
|
37
45
|
<script setup lang="ts">
|
|
38
46
|
import { RiArticleLine } from '@remixicon/vue'
|
|
39
47
|
import type { RouteLocationRaw } from 'vue-router'
|
|
40
|
-
import { useFormatDate } from '../functions/dates'
|
|
41
|
-
import { useTranslation } from '../composables/useTranslation'
|
|
42
48
|
import type { Post } from '../types/posts'
|
|
43
49
|
import Placeholder from './Placeholder.vue'
|
|
44
50
|
import ObjectCard from './ObjectCard.vue'
|
|
45
51
|
import ObjectCardHeader from './ObjectCardHeader.vue'
|
|
46
52
|
import ObjectCardShortDescription from './ObjectCardShortDescription.vue'
|
|
53
|
+
import FormattedDate from './FormattedDate.vue'
|
|
54
|
+
import TranslationT from './TranslationT.vue'
|
|
47
55
|
|
|
48
56
|
defineProps<{
|
|
49
57
|
post: Post
|
|
50
58
|
postUrl?: RouteLocationRaw
|
|
51
59
|
}>()
|
|
52
|
-
|
|
53
|
-
const { t } = useTranslation()
|
|
54
|
-
const { formatRelativeIfRecentDate } = useFormatDate()
|
|
55
|
-
|
|
56
|
-
const formatDate = (dateString: string) => {
|
|
57
|
-
return formatRelativeIfRecentDate(dateString, {
|
|
58
|
-
dateStyle: 'long',
|
|
59
|
-
timeStyle: 'short',
|
|
60
|
-
})
|
|
61
|
-
}
|
|
62
60
|
</script>
|
|
@@ -47,9 +47,21 @@
|
|
|
47
47
|
/>
|
|
48
48
|
</dd>
|
|
49
49
|
<template v-if="generatedFormats.length">
|
|
50
|
-
<
|
|
51
|
-
|
|
52
|
-
|
|
50
|
+
<TranslationT
|
|
51
|
+
tag="dt"
|
|
52
|
+
class="font-bold fr-text--sm fr-mb-0"
|
|
53
|
+
keypath="Formats générés automatiquement par {platform} (dernière mise à jour {date})"
|
|
54
|
+
>
|
|
55
|
+
<template #platform>
|
|
56
|
+
{{ config.name }}
|
|
57
|
+
</template>
|
|
58
|
+
<template #date>
|
|
59
|
+
<FormattedDate
|
|
60
|
+
:date="conversionsFinishedAt"
|
|
61
|
+
format="relative"
|
|
62
|
+
/>
|
|
63
|
+
</template>
|
|
64
|
+
</TranslationT>
|
|
53
65
|
<dd
|
|
54
66
|
v-for="generatedFormat in generatedFormats"
|
|
55
67
|
:key="generatedFormat.format"
|
|
@@ -132,7 +144,8 @@ import { filesize } from '../../functions/helpers'
|
|
|
132
144
|
import { getResourceFilesize } from '../../functions/resources'
|
|
133
145
|
import { trackEvent } from '../../functions/matomo'
|
|
134
146
|
import { useComponentsConfig } from '../../config'
|
|
135
|
-
import
|
|
147
|
+
import FormattedDate from '../FormattedDate.vue'
|
|
148
|
+
import TranslationT from '../TranslationT.vue'
|
|
136
149
|
import { useTranslation } from '../../composables/useTranslation'
|
|
137
150
|
import { useResourceCapabilities } from '../../composables/useResourceCapabilities'
|
|
138
151
|
import type { Resource } from '../../types/resources'
|
|
@@ -145,7 +158,6 @@ const props = defineProps<{
|
|
|
145
158
|
|
|
146
159
|
const { t } = useTranslation()
|
|
147
160
|
const config = useComponentsConfig()
|
|
148
|
-
const { formatRelativeIfRecentDate } = useFormatDate()
|
|
149
161
|
|
|
150
162
|
const { generatedFormats, wfsFormats, defaultWfsProjection } = useResourceCapabilities(
|
|
151
163
|
() => props.resource,
|
|
@@ -154,7 +166,7 @@ const { generatedFormats, wfsFormats, defaultWfsProjection } = useResourceCapabi
|
|
|
154
166
|
|
|
155
167
|
const resourceFilesize = computed(() => getResourceFilesize(props.resource))
|
|
156
168
|
|
|
157
|
-
const
|
|
158
|
-
|
|
169
|
+
const conversionsFinishedAt = computed(() =>
|
|
170
|
+
props.resource.extras['analysis:parsing:finished_at'] as string | undefined,
|
|
159
171
|
)
|
|
160
172
|
</script>
|
|
@@ -4,7 +4,7 @@ import type { Resource } from '../../types/resources'
|
|
|
4
4
|
import CopyButton from '../CopyButton.vue'
|
|
5
5
|
import DescriptionDetails from '../DescriptionDetails.vue'
|
|
6
6
|
import DescriptionTerm from '../DescriptionTerm.vue'
|
|
7
|
-
import
|
|
7
|
+
import FormattedDate from '../FormattedDate.vue'
|
|
8
8
|
import { filesize } from '../../functions/helpers'
|
|
9
9
|
import ExtraAccordion from '../ExtraAccordion.vue'
|
|
10
10
|
import { getResourceTitleId, getResourceLabel, getResourceFilesize } from '../../functions/resources'
|
|
@@ -19,7 +19,6 @@ const resourceTitleId = computed(() => getResourceTitleId(props.resource))
|
|
|
19
19
|
const resourceFilesize = computed(() => getResourceFilesize(props.resource))
|
|
20
20
|
|
|
21
21
|
const { t } = useTranslation()
|
|
22
|
-
const { formatDate } = useFormatDate()
|
|
23
22
|
</script>
|
|
24
23
|
|
|
25
24
|
<template>
|
|
@@ -94,11 +93,11 @@ const { formatDate } = useFormatDate()
|
|
|
94
93
|
>
|
|
95
94
|
<DescriptionTerm>{{ t('Créée le') }}</DescriptionTerm>
|
|
96
95
|
<DescriptionDetails>
|
|
97
|
-
|
|
96
|
+
<FormattedDate :date="resource.created_at" />
|
|
98
97
|
</DescriptionDetails>
|
|
99
98
|
<DescriptionTerm>{{ t('Modifiée le') }}</DescriptionTerm>
|
|
100
99
|
<DescriptionDetails>
|
|
101
|
-
|
|
100
|
+
<FormattedDate :date="resource.last_modified" />
|
|
102
101
|
</DescriptionDetails>
|
|
103
102
|
</dl>
|
|
104
103
|
<dl
|
|
@@ -90,7 +90,11 @@
|
|
|
90
90
|
@change="changePage"
|
|
91
91
|
/>
|
|
92
92
|
<div class="fr-px-5v">
|
|
93
|
-
|
|
93
|
+
<TranslationT keypath="Dernière mise à jour de la prévisualisation : {date}">
|
|
94
|
+
<template #date>
|
|
95
|
+
<FormattedDate :date="parsingFinishedAt" />
|
|
96
|
+
</template>
|
|
97
|
+
</TranslationT> —
|
|
94
98
|
{{ t('{count} colonnes', columns.length) }} —
|
|
95
99
|
{{ t('Lignes {count}', rowCount) }}
|
|
96
100
|
</div>
|
|
@@ -103,7 +107,8 @@ import { computed, onMounted, ref } from 'vue'
|
|
|
103
107
|
import { RiArrowDownLine, RiArrowUpLine, RiExternalLinkFill } from '@remixicon/vue'
|
|
104
108
|
import Pagination from '../Pagination.vue'
|
|
105
109
|
import { getData, type SortConfig } from '../../functions/tabularApi'
|
|
106
|
-
import
|
|
110
|
+
import FormattedDate from '../FormattedDate.vue'
|
|
111
|
+
import TranslationT from '../TranslationT.vue'
|
|
107
112
|
import { trackEvent } from '../../functions/matomo'
|
|
108
113
|
import type { Resource } from '../../types/resources'
|
|
109
114
|
import { useComponentsConfig } from '../../config'
|
|
@@ -116,7 +121,6 @@ import PreviewLoader from './PreviewLoader.vue'
|
|
|
116
121
|
const props = defineProps<{ resource: Resource }>()
|
|
117
122
|
|
|
118
123
|
const { t } = useTranslation()
|
|
119
|
-
const { formatDate } = useFormatDate()
|
|
120
124
|
|
|
121
125
|
const rows = ref<Array<Record<string, unknown>>>([])
|
|
122
126
|
const columns = ref<Array<string>>([])
|
|
@@ -196,7 +200,7 @@ function sortByField(col: string) {
|
|
|
196
200
|
getTableInfos(currentPage.value, sortConfig.value)
|
|
197
201
|
};
|
|
198
202
|
|
|
199
|
-
const
|
|
203
|
+
const parsingFinishedAt = computed(() => props.resource.extras['analysis:parsing:finished_at'] as string | undefined)
|
|
200
204
|
|
|
201
205
|
onMounted(() => {
|
|
202
206
|
getTableInfos(currentPage.value)
|
|
@@ -60,7 +60,17 @@
|
|
|
60
60
|
aria-hidden="true"
|
|
61
61
|
class="size-3 fill-gray-medium"
|
|
62
62
|
/>
|
|
63
|
-
<
|
|
63
|
+
<TranslationT
|
|
64
|
+
class="text-xs mb-0"
|
|
65
|
+
keypath="Mis à jour {date}"
|
|
66
|
+
>
|
|
67
|
+
<template #date>
|
|
68
|
+
<FormattedDate
|
|
69
|
+
:date="lastUpdate"
|
|
70
|
+
format="relative"
|
|
71
|
+
/>
|
|
72
|
+
</template>
|
|
73
|
+
</TranslationT>
|
|
64
74
|
<RiSubtractLine
|
|
65
75
|
aria-hidden="true"
|
|
66
76
|
class="size-3 fill-gray-medium"
|
|
@@ -303,7 +313,8 @@ import { ref, computed, defineAsyncComponent } from 'vue'
|
|
|
303
313
|
import { RiDownloadLine, RiFileCopyLine, RiFileWarningLine, RiSubtractLine } from '@remixicon/vue'
|
|
304
314
|
import OrganizationNameWithCertificate from '../OrganizationNameWithCertificate.vue'
|
|
305
315
|
import { filesize, summarize } from '../../functions/helpers'
|
|
306
|
-
import
|
|
316
|
+
import FormattedDate from '../FormattedDate.vue'
|
|
317
|
+
import TranslationT from '../TranslationT.vue'
|
|
307
318
|
import MarkdownViewer from '../MarkdownViewer.vue'
|
|
308
319
|
import type { CommunityResource, Resource } from '../../types/resources'
|
|
309
320
|
import type { Dataset, DatasetV2 } from '../../types/datasets'
|
|
@@ -355,7 +366,6 @@ const ImagePreview = defineAsyncComponent(() => import('./ImagePreview.client.vu
|
|
|
355
366
|
const DatafairPreview = defineAsyncComponent(() => import('./Datafair.client.vue'))
|
|
356
367
|
|
|
357
368
|
const { t } = useTranslation()
|
|
358
|
-
const { formatRelativeIfRecentDate } = useFormatDate()
|
|
359
369
|
const checkTabularData = useHasTabularData()
|
|
360
370
|
|
|
361
371
|
const hasPreview = computed(() => {
|
|
@@ -18,9 +18,14 @@
|
|
|
18
18
|
<span class="min-w-0 truncate font-bold text-gray-title">{{ dataset.title }}</span>
|
|
19
19
|
<template v-if="dataset.last_update">
|
|
20
20
|
<span class="hidden shrink-0 text-gray-medium sm:inline">·</span>
|
|
21
|
-
<
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
<TranslationT
|
|
22
|
+
class="hidden truncate text-gray-medium sm:inline"
|
|
23
|
+
keypath="mis à jour le {date}"
|
|
24
|
+
>
|
|
25
|
+
<template #date>
|
|
26
|
+
<FormattedDate :date="dataset.last_update" />
|
|
27
|
+
</template>
|
|
28
|
+
</TranslationT>
|
|
24
29
|
</template>
|
|
25
30
|
</div>
|
|
26
31
|
</div>
|
|
@@ -53,9 +58,10 @@ import Avatar from '../Avatar.vue'
|
|
|
53
58
|
import BrandedButton from '../BrandedButton.vue'
|
|
54
59
|
import OrganizationLogo from '../OrganizationLogo.vue'
|
|
55
60
|
import ResourceMainAction from './ResourceMainAction.vue'
|
|
61
|
+
import FormattedDate from '../FormattedDate.vue'
|
|
62
|
+
import TranslationT from '../TranslationT.vue'
|
|
56
63
|
import { getOwnerName } from '../../functions/owned'
|
|
57
64
|
import { useTranslation } from '../../composables/useTranslation'
|
|
58
|
-
import { useFormatDate } from '../../functions/dates'
|
|
59
65
|
import type { Dataset, DatasetV2 } from '../../types/datasets'
|
|
60
66
|
import type { Resource } from '../../types/resources'
|
|
61
67
|
|
|
@@ -66,7 +72,6 @@ const props = defineProps<{
|
|
|
66
72
|
}>()
|
|
67
73
|
|
|
68
74
|
const { t } = useTranslation()
|
|
69
|
-
const { formatDate } = useFormatDate()
|
|
70
75
|
|
|
71
76
|
// Plain producer name, matching the prototype: dark text, no link, no certificate
|
|
72
77
|
// badge — unlike ObjectCardOwner which renders a styled link.
|
|
@@ -24,7 +24,14 @@
|
|
|
24
24
|
carried by the separators' margins. -->
|
|
25
25
|
<div class="min-w-0 truncate [flex-shrink:9999]">
|
|
26
26
|
<span class="mr-1.5">·</span>
|
|
27
|
-
<
|
|
27
|
+
<TranslationT keypath="mis à jour {date}">
|
|
28
|
+
<template #date>
|
|
29
|
+
<FormattedDate
|
|
30
|
+
:date="resource.last_modified"
|
|
31
|
+
format="relative"
|
|
32
|
+
/>
|
|
33
|
+
</template>
|
|
34
|
+
</TranslationT>
|
|
28
35
|
<template v-if="resourceFilesize">
|
|
29
36
|
<span class="mx-1.5">·</span>
|
|
30
37
|
<span>{{ filesize(resourceFilesize) }}</span>
|
|
@@ -84,10 +91,11 @@ import ResourceIcon from '../ResourceAccordion/ResourceIcon.vue'
|
|
|
84
91
|
import SchemaBadge from '../ResourceAccordion/SchemaBadge.vue'
|
|
85
92
|
import ResourceSelector from './ResourceSelector.vue'
|
|
86
93
|
import ResourceMainAction from './ResourceMainAction.vue'
|
|
94
|
+
import FormattedDate from '../FormattedDate.vue'
|
|
95
|
+
import TranslationT from '../TranslationT.vue'
|
|
87
96
|
import { filesize, summarize } from '../../functions/helpers'
|
|
88
97
|
import { getResourceExternalUrl, getResourceFilesize } from '../../functions/resources'
|
|
89
98
|
import { trackEvent } from '../../functions/matomo'
|
|
90
|
-
import { useFormatDate } from '../../functions/dates'
|
|
91
99
|
import { useTranslation } from '../../composables/useTranslation'
|
|
92
100
|
import type { RouteLocationRaw } from 'vue-router'
|
|
93
101
|
import type { Resource } from '../../types/resources'
|
|
@@ -108,7 +116,6 @@ const props = defineProps<{
|
|
|
108
116
|
}>()
|
|
109
117
|
|
|
110
118
|
const { t } = useTranslation()
|
|
111
|
-
const { formatRelativeIfRecentDate, formatDate } = useFormatDate()
|
|
112
119
|
|
|
113
120
|
const resourceFilesize = computed(() => getResourceFilesize(props.resource))
|
|
114
121
|
const resourceExternalUrl = computed(() => getResourceExternalUrl(props.dataset, props.resource))
|