@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.
- package/README.md +1 -1
- package/assets/main.css +49 -22
- package/dist/Control-BNCDn-8E.js +148 -0
- package/dist/{Datafair.client-x39O4yfF.js → Datafair.client-B5lBpOl8.js} +2 -2
- package/dist/Event-BOgJUhNR.js +738 -0
- package/dist/Image-BN-4XkIn.js +247 -0
- package/dist/{JsonPreview.client-BMsC5JcY.js → JsonPreview.client-Doz1Z0BS.js} +23 -23
- package/dist/Map-BdT3i2C4.js +7609 -0
- package/dist/MapContainer.client-oiieO8H-.js +105 -0
- package/dist/OSM-CamriM9b.js +71 -0
- package/dist/PdfPreview.client-CdAhkDFJ.js +14513 -0
- package/dist/{Pmtiles.client-BaiIo4VZ.js → Pmtiles.client-B0v8tGJQ.js} +3 -3
- package/dist/ScaleLine-BiesrgOv.js +165 -0
- package/dist/Swagger.client-CsK65JnG.js +4 -0
- package/dist/Tile-DCuqwNOI.js +1206 -0
- package/dist/TileImage-CmZf8EdU.js +1067 -0
- package/dist/View-DcDc7N2K.js +2858 -0
- package/dist/{XmlPreview.client-CAdN0w_Y.js → XmlPreview.client-CrjHf74q.js} +17 -17
- package/dist/common-C4rDcQpp.js +243 -0
- package/dist/components-next.css +1 -1
- package/dist/components-next.js +158 -117
- package/dist/components.css +1 -1
- package/dist/{MapContainer.client-DeSo8EvG.js → index-Bbu9rOHt.js} +4975 -21416
- package/dist/leaflet-src-7m1mB8LI.js +6338 -0
- package/dist/{main-Dgri3TQL.js → main-CiH8ZmBI.js} +56973 -51462
- package/dist/proj-CKwYjU38.js +1569 -0
- package/dist/tilecoord-YW3qEH_j.js +884 -0
- package/dist/{vue3-xml-viewer.common-D6skc_Ai.js → vue3-xml-viewer.common-Bi_bsV6C.js} +1 -1
- package/package.json +6 -2
- package/src/components/ActivityList/ActivityList.vue +6 -2
- package/src/components/AppLink.vue +4 -1
- package/src/components/Avatar.vue +2 -2
- package/src/components/AvatarWithName.vue +8 -4
- package/src/components/BouncingDots.vue +21 -0
- package/src/components/BrandedButton.vue +2 -0
- package/src/components/CopyButton.vue +19 -7
- package/src/components/DataserviceCard.vue +85 -120
- package/src/components/DatasetCard.vue +110 -171
- package/src/components/DatasetInformation/DatasetEmbedSection.vue +43 -0
- package/src/components/DatasetInformation/DatasetInformationSection.vue +73 -0
- package/src/components/DatasetInformation/DatasetSchemaSection.vue +74 -0
- package/src/components/DatasetInformation/DatasetSpatialSection.vue +59 -0
- package/src/components/DatasetInformation/DatasetTemporalitySection.vue +45 -0
- package/src/components/DatasetInformation/index.ts +5 -0
- package/src/components/DatasetQuality.vue +23 -16
- package/src/components/DatasetQualityInline.vue +13 -17
- package/src/components/DatasetQualityScore.vue +12 -15
- package/src/components/DatasetQualityTooltipContent.vue +3 -3
- package/src/components/DescriptionList.vue +1 -4
- package/src/components/DescriptionListDetails.vue +5 -0
- package/src/components/DescriptionListTerm.vue +5 -0
- package/src/components/DiscussionMessageCard.vue +63 -0
- package/src/components/ExtraAccordion.vue +4 -4
- package/src/components/Form/BadgeSelect.vue +35 -0
- package/src/components/Form/FormatSelect.vue +28 -0
- package/src/components/Form/GeozoneSelect.vue +52 -0
- package/src/components/Form/GranularitySelect.vue +29 -0
- package/src/components/Form/LicenseSelect.vue +30 -0
- package/src/components/Form/OrganizationSelect.vue +62 -0
- package/src/components/Form/OrganizationTypeSelect.vue +34 -0
- package/src/components/Form/ReuseTopicSelect.vue +29 -0
- package/src/components/Form/SchemaSelect.vue +30 -0
- package/src/components/Form/SearchableSelect.vue +334 -0
- package/src/components/Form/SelectGroup.vue +132 -0
- package/src/components/Form/TagSelect.vue +38 -0
- package/src/components/LeafletMap.vue +31 -0
- package/src/components/LicenseBadge.vue +24 -0
- package/src/components/LoadingBlock.vue +23 -2
- package/src/components/MarkdownViewer.vue +3 -1
- package/src/components/ObjectCard.vue +42 -0
- package/src/components/ObjectCardBadge.vue +22 -0
- package/src/components/ObjectCardHeader.vue +35 -0
- package/src/components/ObjectCardOwner.vue +43 -0
- package/src/components/ObjectCardShortDescription.vue +28 -0
- package/src/components/OrganizationCard.vue +35 -20
- package/src/components/OrganizationHorizontalCard.vue +87 -0
- package/src/components/OrganizationLogo.vue +1 -1
- package/src/components/OrganizationNameWithCertificate.vue +12 -6
- package/src/components/OwnerTypeIcon.vue +1 -0
- package/src/components/Pagination.vue +1 -1
- package/src/components/Placeholder.vue +5 -2
- package/src/components/PostCard.vue +62 -0
- package/src/components/ProgressBar.vue +31 -0
- package/src/components/RadioGroup.vue +32 -0
- package/src/components/RadioInput.vue +64 -0
- package/src/components/ResourceAccordion/Datafair.client.vue +1 -1
- package/src/components/ResourceAccordion/EditButton.vue +2 -3
- package/src/components/ResourceAccordion/JsonPreview.client.vue +3 -3
- package/src/components/ResourceAccordion/MapContainer.client.vue +21 -17
- package/src/components/ResourceAccordion/Metadata.vue +11 -24
- package/src/components/ResourceAccordion/PdfPreview.client.vue +70 -74
- package/src/components/ResourceAccordion/Pmtiles.client.vue +2 -2
- package/src/components/ResourceAccordion/Preview.vue +2 -2
- package/src/components/ResourceAccordion/ResourceAccordion.vue +35 -28
- package/src/components/ResourceAccordion/ResourceIcon.vue +1 -0
- package/src/components/ResourceAccordion/SchemaBadge.vue +2 -2
- package/src/components/ResourceAccordion/XmlPreview.client.vue +3 -3
- package/src/components/ResourceExplorer/ResourceExplorer.vue +243 -0
- package/src/components/ResourceExplorer/ResourceExplorerSidebar.vue +116 -0
- package/src/components/ResourceExplorer/ResourceExplorerViewer.vue +410 -0
- package/src/components/ReuseCard.vue +8 -28
- package/src/components/ReuseHorizontalCard.vue +80 -0
- package/src/components/Search/BasicAndAdvancedFilters.vue +49 -0
- package/src/components/Search/Filter/AccessTypeFilter.vue +37 -0
- package/src/components/Search/Filter/DatasetBadgeFilter.vue +40 -0
- package/src/components/Search/Filter/FilterButtonGroup.vue +78 -0
- package/src/components/Search/Filter/FormatFamilyFilter.vue +39 -0
- package/src/components/Search/Filter/LastUpdateRangeFilter.vue +37 -0
- package/src/components/Search/Filter/ProducerTypeFilter.vue +49 -0
- package/src/components/Search/Filter/ReuseTypeFilter.vue +42 -0
- package/src/components/Search/GlobalSearch.vue +707 -0
- package/src/components/Search/SearchInput.vue +63 -0
- package/src/components/Search/Sidemenu.vue +38 -0
- package/src/components/StatBox.vue +5 -5
- package/src/components/Tag.vue +30 -0
- package/src/components/Toggletip.vue +11 -4
- package/src/components/Tooltip.vue +2 -3
- package/src/components/TopicCard.vue +134 -0
- package/src/components/radioGroupContext.ts +9 -0
- package/src/composables/useDebouncedRef.ts +31 -0
- package/src/composables/useHasTabularData.ts +15 -0
- package/src/composables/useMetrics.ts +4 -3
- package/src/composables/useResourceCapabilities.ts +131 -0
- package/src/composables/useRouteQueryBoolean.ts +10 -0
- package/src/composables/useSelectModelSync.ts +89 -0
- package/src/composables/useStableQueryParams.ts +84 -0
- package/src/composables/useTranslation.ts +2 -1
- package/src/config.ts +4 -0
- package/src/functions/api.ts +25 -6
- package/src/functions/api.types.ts +5 -3
- package/src/functions/datasets.ts +1 -29
- package/src/functions/description.ts +33 -0
- package/src/functions/helpers.ts +11 -0
- package/src/functions/markdown.ts +60 -16
- package/src/functions/metrics.ts +33 -0
- package/src/functions/organizations.ts +5 -5
- package/src/functions/resourceCapabilities.ts +55 -0
- package/src/main.ts +96 -7
- package/src/types/dataservices.ts +14 -12
- package/src/types/datasets.ts +20 -7
- package/src/types/discussions.ts +20 -0
- package/src/types/licenses.ts +3 -3
- package/src/types/organizations.ts +13 -1
- package/src/types/owned.ts +4 -2
- package/src/types/pages.ts +70 -0
- package/src/types/posts.ts +27 -0
- package/src/types/resources.ts +16 -0
- package/src/types/reuses.ts +14 -5
- package/src/types/search.ts +407 -0
- package/src/types/users.ts +12 -3
- package/dist/PdfPreview.client-COOkEkRA.js +0 -107
- package/dist/Swagger.client-CpLgaLg6.js +0 -4
- package/dist/pdf-vue3-IkJO65RH.js +0 -273
- package/dist/pdf.min-f72cfa08-CdgJTooZ.js +0 -9501
- package/src/components/DatasetInformationPanel.vue +0 -211
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<h3 class="w-full text-base flex">
|
|
3
|
+
<AppLink
|
|
4
|
+
:to="url"
|
|
5
|
+
class="text-gray-title text-base bg-none flex items-center w-full truncate gap-1"
|
|
6
|
+
:target="target"
|
|
7
|
+
>
|
|
8
|
+
<component
|
|
9
|
+
:is="icon"
|
|
10
|
+
aria-hidden="true"
|
|
11
|
+
class="size-4 flex-none"
|
|
12
|
+
/>
|
|
13
|
+
<span
|
|
14
|
+
class="block truncate"
|
|
15
|
+
:class="$slots.extra ? 'flex-initial' : 'flex-1'"
|
|
16
|
+
>
|
|
17
|
+
<slot />
|
|
18
|
+
</span>
|
|
19
|
+
<slot name="extra" />
|
|
20
|
+
<span class="absolute inset-0" />
|
|
21
|
+
</AppLink>
|
|
22
|
+
</h3>
|
|
23
|
+
</template>
|
|
24
|
+
|
|
25
|
+
<script setup lang="ts">
|
|
26
|
+
import type { Component } from 'vue'
|
|
27
|
+
import type { RouteLocationRaw } from 'vue-router'
|
|
28
|
+
import AppLink from './AppLink.vue'
|
|
29
|
+
|
|
30
|
+
defineProps<{
|
|
31
|
+
icon: Component
|
|
32
|
+
url: RouteLocationRaw
|
|
33
|
+
target?: string
|
|
34
|
+
}>()
|
|
35
|
+
</script>
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div
|
|
3
|
+
v-if="organization"
|
|
4
|
+
class="-mr-0.5 flex-initial truncate"
|
|
5
|
+
>
|
|
6
|
+
<AppLink
|
|
7
|
+
class="link text-sm overflow-hidden flex items-center relative z-[2] truncate"
|
|
8
|
+
:to="organizationUrl || organization.page"
|
|
9
|
+
>
|
|
10
|
+
<OrganizationNameWithCertificate
|
|
11
|
+
:organization
|
|
12
|
+
size="sm"
|
|
13
|
+
/>
|
|
14
|
+
</AppLink>
|
|
15
|
+
</div>
|
|
16
|
+
<div
|
|
17
|
+
v-else-if="ownerName"
|
|
18
|
+
class="mr-1 truncate"
|
|
19
|
+
>
|
|
20
|
+
{{ ownerName }}
|
|
21
|
+
</div>
|
|
22
|
+
</template>
|
|
23
|
+
|
|
24
|
+
<script setup lang="ts">
|
|
25
|
+
import { computed } from 'vue'
|
|
26
|
+
import type { RouteLocationRaw } from 'vue-router'
|
|
27
|
+
import { getOwnerName } from '../functions/owned'
|
|
28
|
+
import type { OrganizationReference } from '../types/organizations'
|
|
29
|
+
import type { UserReference } from '../types/users'
|
|
30
|
+
import AppLink from './AppLink.vue'
|
|
31
|
+
import OrganizationNameWithCertificate from './OrganizationNameWithCertificate.vue'
|
|
32
|
+
|
|
33
|
+
const props = defineProps<{
|
|
34
|
+
organization?: OrganizationReference | null
|
|
35
|
+
owner?: UserReference | null
|
|
36
|
+
organizationUrl?: RouteLocationRaw
|
|
37
|
+
}>()
|
|
38
|
+
|
|
39
|
+
const ownerName = computed(() => {
|
|
40
|
+
if (!props.owner) return ''
|
|
41
|
+
return getOwnerName({ organization: null, owner: props.owner })
|
|
42
|
+
})
|
|
43
|
+
</script>
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<p
|
|
3
|
+
v-if="shortDescription"
|
|
4
|
+
class="fr-text--sm fr-mt-1w fr-mb-0 overflow-wrap-anywhere hidden sm:line-clamp-2"
|
|
5
|
+
>
|
|
6
|
+
{{ shortDescription }}
|
|
7
|
+
</p>
|
|
8
|
+
</template>
|
|
9
|
+
|
|
10
|
+
<script setup lang="ts">
|
|
11
|
+
import { computed } from 'vue'
|
|
12
|
+
import { removeMarkdownSync } from '../functions/markdown'
|
|
13
|
+
|
|
14
|
+
const props = withDefaults(defineProps<{
|
|
15
|
+
text?: string | null
|
|
16
|
+
maxLength?: number
|
|
17
|
+
}>(), {
|
|
18
|
+
maxLength: 300,
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
// Truncate in JS to avoid sending very long markdown-cleaned text to the DOM.
|
|
22
|
+
// The visual clamp is handled by CSS line-clamp-2.
|
|
23
|
+
const shortDescription = computed(() => {
|
|
24
|
+
if (!props.text) return ''
|
|
25
|
+
const cleaned = removeMarkdownSync(props.text)
|
|
26
|
+
return cleaned.length > props.maxLength ? cleaned.substring(0, props.maxLength) + '…' : cleaned
|
|
27
|
+
})
|
|
28
|
+
</script>
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
loading="lazy"
|
|
12
12
|
>
|
|
13
13
|
</div>
|
|
14
|
-
<
|
|
14
|
+
<div class="mb-0.5 font-bold">
|
|
15
15
|
<AppLink
|
|
16
16
|
:to="organization.page"
|
|
17
17
|
class="overflow-hidden"
|
|
@@ -21,55 +21,70 @@
|
|
|
21
21
|
:organization
|
|
22
22
|
/>
|
|
23
23
|
</AppLink>
|
|
24
|
-
</
|
|
24
|
+
</div>
|
|
25
25
|
<div class="mb-2 flex flex-wrap gap-1 items-center">
|
|
26
26
|
<template v-if="type !== 'other'">
|
|
27
27
|
<OwnerType
|
|
28
28
|
class="mb-0 text-sm"
|
|
29
29
|
:type
|
|
30
30
|
/>
|
|
31
|
-
<RiSubtractLine
|
|
31
|
+
<RiSubtractLine
|
|
32
|
+
aria-hidden="true"
|
|
33
|
+
class="size-4 fill-gray-medium"
|
|
34
|
+
/>
|
|
32
35
|
</template>
|
|
33
36
|
<div>
|
|
34
37
|
<div
|
|
35
|
-
v-if="organization
|
|
38
|
+
v-if="'metrics' in organization"
|
|
36
39
|
class="text-gray-medium flex items-center text-sm gap-0.5"
|
|
40
|
+
:aria-label="t('{datasets} jeux de données, {dataservices} API et {reuses} réutilisations', {
|
|
41
|
+
datasets: organization.metrics.datasets,
|
|
42
|
+
dataservices: organization.metrics.dataservices,
|
|
43
|
+
reuses: organization.metrics.reuses,
|
|
44
|
+
})"
|
|
37
45
|
>
|
|
38
|
-
<RiDatabase2Line
|
|
39
|
-
|
|
40
|
-
|
|
46
|
+
<RiDatabase2Line
|
|
47
|
+
aria-hidden="true"
|
|
48
|
+
class="size-4 -mt-1"
|
|
49
|
+
/> {{ organization.metrics.datasets }}
|
|
50
|
+
<RiTerminalLine
|
|
51
|
+
aria-hidden="true"
|
|
52
|
+
class="size-4 -mt-1 ml-1"
|
|
53
|
+
/> {{ organization.metrics.dataservices }}
|
|
54
|
+
<RiLineChartLine
|
|
55
|
+
aria-hidden="true"
|
|
56
|
+
class="size-4 -mt-1 ml-1"
|
|
57
|
+
/> {{ organization.metrics.reuses }}
|
|
41
58
|
</div>
|
|
42
59
|
</div>
|
|
43
60
|
</div>
|
|
44
|
-
<
|
|
61
|
+
<div class="mt-1 mb-0">
|
|
45
62
|
<TextClamp
|
|
46
|
-
v-if="description"
|
|
47
|
-
:text="description"
|
|
63
|
+
v-if="'description' in organization"
|
|
64
|
+
:text="removeMarkdownSync(organization.description)"
|
|
48
65
|
:max-lines="3"
|
|
49
66
|
/>
|
|
50
|
-
</
|
|
67
|
+
</div>
|
|
51
68
|
</div>
|
|
52
69
|
</div>
|
|
53
70
|
</template>
|
|
54
71
|
|
|
55
72
|
<script setup lang="ts">
|
|
56
73
|
import { RiLineChartLine, RiDatabase2Line, RiTerminalLine, RiSubtractLine } from '@remixicon/vue'
|
|
57
|
-
import { computed
|
|
58
|
-
import {
|
|
74
|
+
import { computed } from 'vue'
|
|
75
|
+
import { removeMarkdownSync } from '../functions/markdown'
|
|
59
76
|
import { getOrganizationType } from '../functions/organizations'
|
|
60
|
-
import type { Organization } from '../types/organizations'
|
|
77
|
+
import type { Organization, OrganizationReference } from '../types/organizations'
|
|
61
78
|
import OwnerType from './OwnerType.vue'
|
|
62
79
|
import OrganizationNameWithCertificate from './OrganizationNameWithCertificate.vue'
|
|
63
80
|
import AppLink from './AppLink.vue'
|
|
81
|
+
import { useTranslation } from '../composables/useTranslation'
|
|
64
82
|
|
|
65
83
|
const props = defineProps<{
|
|
66
|
-
organization: Organization
|
|
84
|
+
organization: Organization | OrganizationReference
|
|
67
85
|
}>()
|
|
68
86
|
|
|
69
|
-
const
|
|
87
|
+
const { t } = useTranslation()
|
|
70
88
|
|
|
71
|
-
const
|
|
72
|
-
watchEffect(async () => {
|
|
73
|
-
description.value = await removeMarkdown(props.organization.description)
|
|
74
|
-
})
|
|
89
|
+
const type = computed(() => getOrganizationType(props.organization))
|
|
75
90
|
</script>
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<ObjectCard>
|
|
3
|
+
<template #media>
|
|
4
|
+
<OrganizationLogo
|
|
5
|
+
:organization="organization"
|
|
6
|
+
size-class="size-12"
|
|
7
|
+
/>
|
|
8
|
+
</template>
|
|
9
|
+
<ObjectCardHeader
|
|
10
|
+
:icon="RiBuilding2Line"
|
|
11
|
+
:url="organization.page"
|
|
12
|
+
>
|
|
13
|
+
<OrganizationNameWithCertificate
|
|
14
|
+
:show-type="false"
|
|
15
|
+
:organization
|
|
16
|
+
size="sm"
|
|
17
|
+
color-class="text-gray-title"
|
|
18
|
+
/>
|
|
19
|
+
</ObjectCardHeader>
|
|
20
|
+
<div class="text-sm flex flex-wrap md:flex-nowrap gap-y-1 items-center truncate">
|
|
21
|
+
<template v-if="type !== 'other'">
|
|
22
|
+
<OwnerType
|
|
23
|
+
class="mb-0"
|
|
24
|
+
:type
|
|
25
|
+
/>
|
|
26
|
+
<RiSubtractLine
|
|
27
|
+
v-if="'metrics' in organization"
|
|
28
|
+
aria-hidden="true"
|
|
29
|
+
class="hidden md:block size-4 flex-none fill-gray-medium"
|
|
30
|
+
/>
|
|
31
|
+
</template>
|
|
32
|
+
<div
|
|
33
|
+
v-if="'metrics' in organization"
|
|
34
|
+
class="text-gray-medium flex items-center text-sm gap-0.5"
|
|
35
|
+
:aria-label="t('{datasets} jeux de donn\u00e9es, {dataservices} API et {reuses} r\u00e9utilisations', {
|
|
36
|
+
datasets: organization.metrics.datasets,
|
|
37
|
+
dataservices: organization.metrics.dataservices,
|
|
38
|
+
reuses: organization.metrics.reuses,
|
|
39
|
+
})"
|
|
40
|
+
>
|
|
41
|
+
<RiDatabase2Line
|
|
42
|
+
aria-hidden="true"
|
|
43
|
+
class="size-3.5"
|
|
44
|
+
/> {{ summarize(organization.metrics.datasets) }}
|
|
45
|
+
<RiTerminalLine
|
|
46
|
+
aria-hidden="true"
|
|
47
|
+
class="size-3.5 ml-1"
|
|
48
|
+
/> {{ summarize(organization.metrics.dataservices) }}
|
|
49
|
+
<RiLineChartLine
|
|
50
|
+
aria-hidden="true"
|
|
51
|
+
class="size-3.5 ml-1"
|
|
52
|
+
/> {{ summarize(organization.metrics.reuses) }}
|
|
53
|
+
<RiStarLine
|
|
54
|
+
aria-hidden="true"
|
|
55
|
+
class="size-3.5 ml-1"
|
|
56
|
+
/> {{ summarize(organization.metrics.followers) }}
|
|
57
|
+
</div>
|
|
58
|
+
</div>
|
|
59
|
+
<ObjectCardShortDescription
|
|
60
|
+
v-if="'description' in organization"
|
|
61
|
+
:text="organization.description"
|
|
62
|
+
/>
|
|
63
|
+
</ObjectCard>
|
|
64
|
+
</template>
|
|
65
|
+
|
|
66
|
+
<script setup lang="ts">
|
|
67
|
+
import { RiBuilding2Line, RiDatabase2Line, RiLineChartLine, RiStarLine, RiSubtractLine, RiTerminalLine } from '@remixicon/vue'
|
|
68
|
+
import { computed } from 'vue'
|
|
69
|
+
import { getOrganizationType } from '../functions/organizations'
|
|
70
|
+
import { summarize } from '../functions/helpers'
|
|
71
|
+
import { useTranslation } from '../composables/useTranslation'
|
|
72
|
+
import type { Organization, OrganizationReference } from '../types/organizations'
|
|
73
|
+
import OrganizationLogo from './OrganizationLogo.vue'
|
|
74
|
+
import OrganizationNameWithCertificate from './OrganizationNameWithCertificate.vue'
|
|
75
|
+
import OwnerType from './OwnerType.vue'
|
|
76
|
+
import ObjectCard from './ObjectCard.vue'
|
|
77
|
+
import ObjectCardHeader from './ObjectCardHeader.vue'
|
|
78
|
+
import ObjectCardShortDescription from './ObjectCardShortDescription.vue'
|
|
79
|
+
|
|
80
|
+
const props = defineProps<{
|
|
81
|
+
organization: Organization | OrganizationReference
|
|
82
|
+
}>()
|
|
83
|
+
|
|
84
|
+
const { t } = useTranslation()
|
|
85
|
+
|
|
86
|
+
const type = computed(() => getOrganizationType(props.organization))
|
|
87
|
+
</script>
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
<script setup lang="ts">
|
|
17
17
|
import { computed } from 'vue'
|
|
18
18
|
import type { OrganizationOrSuggest } from '../types/organizations'
|
|
19
|
-
import { throwOnNever } from '../
|
|
19
|
+
import { throwOnNever } from '../functions/never'
|
|
20
20
|
import Placeholder from './Placeholder.vue'
|
|
21
21
|
|
|
22
22
|
const props = defineProps<{
|
|
@@ -4,9 +4,10 @@
|
|
|
4
4
|
v-if="showType"
|
|
5
5
|
:type="getOrganizationType(organization)"
|
|
6
6
|
/>
|
|
7
|
-
<
|
|
7
|
+
<component
|
|
8
|
+
:is="as"
|
|
8
9
|
class="mb-0 truncate flex-initial"
|
|
9
|
-
:class="{ 'text-sm': size === 'sm' }"
|
|
10
|
+
:class="[colorClass, { 'text-xs': size === 'xs', 'text-sm': size === 'sm', 'text-base': size === 'base' }]"
|
|
10
11
|
>
|
|
11
12
|
{{ organization.name }}
|
|
12
13
|
<small
|
|
@@ -15,11 +16,12 @@
|
|
|
15
16
|
>
|
|
16
17
|
{{ organization.acronym }}
|
|
17
18
|
</small>
|
|
18
|
-
</
|
|
19
|
+
</component>
|
|
19
20
|
<Tooltip v-if="isOrganizationCertified(organization)">
|
|
20
21
|
<RiCheckboxCircleLine
|
|
21
22
|
class="flex-none"
|
|
22
23
|
:class="{
|
|
24
|
+
'size-3': size === 'xs',
|
|
23
25
|
'size-4': size === 'sm',
|
|
24
26
|
'size-5': size === 'base',
|
|
25
27
|
}"
|
|
@@ -38,7 +40,7 @@
|
|
|
38
40
|
<script setup lang="ts">
|
|
39
41
|
import { RiCheckboxCircleLine } from '@remixicon/vue'
|
|
40
42
|
import { getOrganizationType, isOrganizationCertified } from '../functions/organizations'
|
|
41
|
-
import type { OrganizationReference } from '../types/organizations'
|
|
43
|
+
import type { Organization, OrganizationReference } from '../types/organizations'
|
|
42
44
|
import { useComponentsConfig } from '../config'
|
|
43
45
|
import { useTranslation } from '../composables/useTranslation'
|
|
44
46
|
import OwnerTypeIcon from './OwnerTypeIcon.vue'
|
|
@@ -48,13 +50,17 @@ const config = useComponentsConfig()
|
|
|
48
50
|
|
|
49
51
|
const { t } = useTranslation()
|
|
50
52
|
withDefaults(defineProps<{
|
|
51
|
-
organization: OrganizationReference
|
|
53
|
+
organization: Organization | OrganizationReference
|
|
52
54
|
showAcronym?: boolean
|
|
53
55
|
showType?: boolean
|
|
54
|
-
size?: 'base' | 'sm'
|
|
56
|
+
size?: 'base' | 'sm' | 'xs'
|
|
57
|
+
colorClass?: string
|
|
58
|
+
as?: string
|
|
55
59
|
}>(), {
|
|
56
60
|
showAcronym: false,
|
|
57
61
|
showType: true,
|
|
58
62
|
size: 'base',
|
|
63
|
+
colorClass: 'text-new-primary',
|
|
64
|
+
as: 'div',
|
|
59
65
|
})
|
|
60
66
|
</script>
|
|
@@ -3,23 +3,26 @@
|
|
|
3
3
|
<component
|
|
4
4
|
:is="icon"
|
|
5
5
|
class="size-1/2 text-gray-plain"
|
|
6
|
+
aria-hidden="true"
|
|
6
7
|
/>
|
|
7
8
|
</div>
|
|
8
9
|
</template>
|
|
9
10
|
|
|
10
11
|
<script setup lang="ts">
|
|
11
12
|
import { computed } from 'vue'
|
|
12
|
-
import { RiBuilding2Line, RiDatabase2Line, RiLineChartLine } from '@remixicon/vue'
|
|
13
|
+
import { RiBookShelfLine, RiBuilding2Line, RiDatabase2Line, RiLineChartLine, RiTerminalLine } from '@remixicon/vue'
|
|
13
14
|
|
|
14
15
|
const props = defineProps<{
|
|
15
|
-
type: 'Dataset' | 'Reuse' | 'Organization'
|
|
16
|
+
type: 'Dataset' | 'Dataservice' | 'Reuse' | 'Organization' | 'Topic'
|
|
16
17
|
}>()
|
|
17
18
|
|
|
18
19
|
const icon = computed(() => {
|
|
19
20
|
return {
|
|
20
21
|
Dataset: RiDatabase2Line,
|
|
22
|
+
Dataservice: RiTerminalLine,
|
|
21
23
|
Reuse: RiLineChartLine,
|
|
22
24
|
Organization: RiBuilding2Line,
|
|
25
|
+
Topic: RiBookShelfLine,
|
|
23
26
|
}[props.type]
|
|
24
27
|
})
|
|
25
28
|
</script>
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<ObjectCard media-size="lg">
|
|
3
|
+
<template #media>
|
|
4
|
+
<img
|
|
5
|
+
v-if="post.image"
|
|
6
|
+
:src="post.image"
|
|
7
|
+
class="w-full h-full object-cover"
|
|
8
|
+
:alt="post.name"
|
|
9
|
+
>
|
|
10
|
+
<Placeholder
|
|
11
|
+
v-else
|
|
12
|
+
type="Dataset"
|
|
13
|
+
class="w-full h-full"
|
|
14
|
+
/>
|
|
15
|
+
</template>
|
|
16
|
+
|
|
17
|
+
<ObjectCardHeader
|
|
18
|
+
:icon="RiArticleLine"
|
|
19
|
+
:url="postUrl || post.page || '#'"
|
|
20
|
+
>
|
|
21
|
+
{{ post.name }}
|
|
22
|
+
</ObjectCardHeader>
|
|
23
|
+
|
|
24
|
+
<ObjectCardShortDescription :text="post.headline || post.content" />
|
|
25
|
+
|
|
26
|
+
<div
|
|
27
|
+
v-if="post.published || post.created_at"
|
|
28
|
+
class="text-sm text-gray-medium mt-1"
|
|
29
|
+
>
|
|
30
|
+
{{ t('Publié {date}', { date: formatDate(post.published || post.created_at) }) }}
|
|
31
|
+
</div>
|
|
32
|
+
|
|
33
|
+
<slot />
|
|
34
|
+
</ObjectCard>
|
|
35
|
+
</template>
|
|
36
|
+
|
|
37
|
+
<script setup lang="ts">
|
|
38
|
+
import { RiArticleLine } from '@remixicon/vue'
|
|
39
|
+
import type { RouteLocationRaw } from 'vue-router'
|
|
40
|
+
import { useFormatDate } from '../functions/dates'
|
|
41
|
+
import { useTranslation } from '../composables/useTranslation'
|
|
42
|
+
import type { Post } from '../types/posts'
|
|
43
|
+
import Placeholder from './Placeholder.vue'
|
|
44
|
+
import ObjectCard from './ObjectCard.vue'
|
|
45
|
+
import ObjectCardHeader from './ObjectCardHeader.vue'
|
|
46
|
+
import ObjectCardShortDescription from './ObjectCardShortDescription.vue'
|
|
47
|
+
|
|
48
|
+
defineProps<{
|
|
49
|
+
post: Post
|
|
50
|
+
postUrl?: RouteLocationRaw
|
|
51
|
+
}>()
|
|
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
|
+
</script>
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div
|
|
3
|
+
role="meter"
|
|
4
|
+
:aria-valuenow="value"
|
|
5
|
+
aria-valuemin="0"
|
|
6
|
+
:aria-valuemax="max"
|
|
7
|
+
class="min-w-20 h-2.5 rounded-lg border border-gray-default bg-[#f5f5f5] overflow-hidden"
|
|
8
|
+
>
|
|
9
|
+
<div
|
|
10
|
+
class="h-full rounded-lg"
|
|
11
|
+
:class="barClass"
|
|
12
|
+
:style="{ width: percentage + '%' }"
|
|
13
|
+
/>
|
|
14
|
+
<slot />
|
|
15
|
+
</div>
|
|
16
|
+
</template>
|
|
17
|
+
|
|
18
|
+
<script setup lang="ts">
|
|
19
|
+
import { computed } from 'vue'
|
|
20
|
+
|
|
21
|
+
const props = withDefaults(defineProps<{
|
|
22
|
+
value: number
|
|
23
|
+
max?: number
|
|
24
|
+
barClass?: string
|
|
25
|
+
}>(), {
|
|
26
|
+
max: 1,
|
|
27
|
+
barClass: '',
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
const percentage = computed(() => Math.min(100, Math.max(0, (props.value / props.max) * 100)))
|
|
31
|
+
</script>
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<fieldset class="flex flex-col gap-2 min-w-0">
|
|
3
|
+
<legend
|
|
4
|
+
v-if="legend"
|
|
5
|
+
class="fr-label mb-2"
|
|
6
|
+
>
|
|
7
|
+
{{ legend }}
|
|
8
|
+
</legend>
|
|
9
|
+
<slot />
|
|
10
|
+
</fieldset>
|
|
11
|
+
</template>
|
|
12
|
+
|
|
13
|
+
<script setup lang="ts">
|
|
14
|
+
import { provide, toRef } from 'vue'
|
|
15
|
+
import { radioGroupInjectionKey } from './radioGroupContext'
|
|
16
|
+
|
|
17
|
+
const props = defineProps<{
|
|
18
|
+
modelValue: string
|
|
19
|
+
name: string
|
|
20
|
+
legend?: string
|
|
21
|
+
}>()
|
|
22
|
+
|
|
23
|
+
const emit = defineEmits<{
|
|
24
|
+
(event: 'update:modelValue', value: string): void
|
|
25
|
+
}>()
|
|
26
|
+
|
|
27
|
+
provide(radioGroupInjectionKey, {
|
|
28
|
+
name: toRef(() => props.name),
|
|
29
|
+
modelValue: toRef(() => props.modelValue),
|
|
30
|
+
select: (value: string) => emit('update:modelValue', value),
|
|
31
|
+
})
|
|
32
|
+
</script>
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<label
|
|
3
|
+
class="flex items-center gap-2 p-1 rounded cursor-pointer transition has-[:focus-visible]:ring-2 has-[:focus-visible]:ring-blue-500"
|
|
4
|
+
:class="selectedClass"
|
|
5
|
+
>
|
|
6
|
+
<input
|
|
7
|
+
type="radio"
|
|
8
|
+
:name="group?.name.value"
|
|
9
|
+
:value="value"
|
|
10
|
+
:checked="isSelected"
|
|
11
|
+
class="sr-only"
|
|
12
|
+
@change="group?.select(value)"
|
|
13
|
+
>
|
|
14
|
+
<component
|
|
15
|
+
:is="icon"
|
|
16
|
+
v-if="icon"
|
|
17
|
+
class="w-4 h-4"
|
|
18
|
+
/>
|
|
19
|
+
<span class="text-sm flex-1 min-w-0">
|
|
20
|
+
<slot />
|
|
21
|
+
</span>
|
|
22
|
+
<span
|
|
23
|
+
v-if="loading || count !== undefined"
|
|
24
|
+
class="text-xs font-bold px-1 py-0.5 rounded"
|
|
25
|
+
:class="isSelected && highlighted ? 'bg-white/20 text-white' : 'bg-gray-200 text-gray-600'"
|
|
26
|
+
>
|
|
27
|
+
<BouncingDots v-if="loading" />
|
|
28
|
+
<template v-else>{{ formattedCount }}</template>
|
|
29
|
+
</span>
|
|
30
|
+
</label>
|
|
31
|
+
</template>
|
|
32
|
+
|
|
33
|
+
<script setup lang="ts">
|
|
34
|
+
import { computed, inject, type Component } from 'vue'
|
|
35
|
+
import { radioGroupInjectionKey } from './radioGroupContext'
|
|
36
|
+
import { useTranslation } from '../composables/useTranslation'
|
|
37
|
+
import BouncingDots from './BouncingDots.vue'
|
|
38
|
+
|
|
39
|
+
type Props = {
|
|
40
|
+
value: string
|
|
41
|
+
count?: number
|
|
42
|
+
loading?: boolean
|
|
43
|
+
icon?: Component
|
|
44
|
+
highlighted?: boolean
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const props = defineProps<Props>()
|
|
48
|
+
|
|
49
|
+
const group = inject(radioGroupInjectionKey)
|
|
50
|
+
const { locale } = useTranslation()
|
|
51
|
+
|
|
52
|
+
const isSelected = computed(() => group?.modelValue.value === props.value)
|
|
53
|
+
|
|
54
|
+
const selectedClass = computed(() => {
|
|
55
|
+
if (!isSelected.value) return 'hover:bg-gray-100'
|
|
56
|
+
if (props.highlighted) return 'bg-blue-800 text-white'
|
|
57
|
+
return 'bg-gray-200'
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
const formattedCount = computed(() => {
|
|
61
|
+
if (props.count === undefined) return ''
|
|
62
|
+
return new Intl.NumberFormat(locale, { notation: 'compact' }).format(props.count)
|
|
63
|
+
})
|
|
64
|
+
</script>
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
type="warning"
|
|
23
23
|
class="flex items-center space-x-2"
|
|
24
24
|
>
|
|
25
|
-
<RiErrorWarningLine class="
|
|
25
|
+
<RiErrorWarningLine class="shrink-0 size-6" />
|
|
26
26
|
<span>{{ fileSizeBytes
|
|
27
27
|
? t("Fichier JSON 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.")
|
|
28
28
|
: 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.")
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
type="warning"
|
|
34
34
|
class="flex items-center space-x-2"
|
|
35
35
|
>
|
|
36
|
-
<RiErrorWarningLine class="
|
|
36
|
+
<RiErrorWarningLine class="shrink-0 size-6" />
|
|
37
37
|
<span>{{ t("Ce fichier JSON 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>
|
|
38
38
|
</SimpleBanner>
|
|
39
39
|
<SimpleBanner
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
type="warning"
|
|
42
42
|
class="flex items-center space-x-2"
|
|
43
43
|
>
|
|
44
|
-
<RiErrorWarningLine class="
|
|
44
|
+
<RiErrorWarningLine class="shrink-0 size-6" />
|
|
45
45
|
<span>{{ t("Erreur lors du chargement de l'aperçu JSON.") }}</span>
|
|
46
46
|
</SimpleBanner>
|
|
47
47
|
</div>
|