@datagouv/components-next 1.0.2-dev.6 → 1.0.2-dev.61

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 (78) hide show
  1. package/assets/main.css +4 -0
  2. package/dist/Datafair.client-CZBhcl2N.js +30 -0
  3. package/dist/JsonPreview.client-BFXc8Yds.js +40 -0
  4. package/dist/{MapContainer.client-DRkAmdOc.js → MapContainer.client-DXvpJcmy.js} +35 -38
  5. package/dist/{PdfPreview.client-C-w6-w44.js → PdfPreview.client-C4rWJaSZ.js} +822 -865
  6. package/dist/{Pmtiles.client-BR7_ldHY.js → Pmtiles.client-ByvF0n7m.js} +574 -579
  7. package/dist/PreviewWrapper.vue_vue_type_script_setup_true_lang-B6mL96Bm.js +61 -0
  8. package/dist/XmlPreview.client-aAATX5FP.js +34 -0
  9. package/dist/components-next.css +3 -3
  10. package/dist/components-next.js +140 -131
  11. package/dist/components.css +1 -1
  12. package/dist/{index-SrYZwgCT.js → index-9wBlcysa.js} +1 -1
  13. package/dist/main-DSV-Ai-o.js +73008 -0
  14. package/dist/{vue3-xml-viewer.common-BRxsqI9j.js → vue3-xml-viewer.common-EQMYhxMa.js} +1 -1
  15. package/package.json +14 -9
  16. package/src/components/ActivityList/ActivityList.vue +0 -2
  17. package/src/components/Form/SearchableSelect.vue +2 -1
  18. package/src/components/InfiniteLoader.vue +53 -0
  19. package/src/components/OpenApiViewer/ContentTypeSelect.vue +48 -0
  20. package/src/components/OpenApiViewer/EndpointRequest.vue +164 -0
  21. package/src/components/OpenApiViewer/EndpointResponses.vue +149 -0
  22. package/src/components/OpenApiViewer/OpenApiViewer.vue +308 -0
  23. package/src/components/OpenApiViewer/SchemaPanel.vue +53 -0
  24. package/src/components/OpenApiViewer/SchemaTree.vue +77 -0
  25. package/src/components/OpenApiViewer/openapi.ts +150 -0
  26. package/src/components/OrganizationNameWithCertificate.vue +3 -2
  27. package/src/components/Pagination.vue +8 -5
  28. package/src/components/ReadMore.vue +1 -1
  29. package/src/components/ResourceAccordion/Datafair.client.vue +4 -10
  30. package/src/components/ResourceAccordion/JsonPreview.client.vue +23 -121
  31. package/src/components/ResourceAccordion/MapContainer.client.vue +7 -11
  32. package/src/components/ResourceAccordion/Metadata.vue +1 -2
  33. package/src/components/ResourceAccordion/PdfPreview.client.vue +24 -103
  34. package/src/components/ResourceAccordion/Pmtiles.client.vue +5 -10
  35. package/src/components/ResourceAccordion/Preview.vue +15 -20
  36. package/src/components/ResourceAccordion/PreviewLoader.vue +1 -2
  37. package/src/components/ResourceAccordion/PreviewUnavailable.vue +22 -0
  38. package/src/components/ResourceAccordion/PreviewWrapper.vue +82 -0
  39. package/src/components/ResourceAccordion/ResourceAccordion.vue +5 -7
  40. package/src/components/ResourceAccordion/XmlPreview.client.vue +16 -115
  41. package/src/components/ResourceExplorer/ResourceExplorer.vue +81 -13
  42. package/src/components/ResourceExplorer/ResourceExplorerSidebar.vue +2 -2
  43. package/src/components/ResourceExplorer/ResourceExplorerViewer.vue +30 -11
  44. package/src/components/Search/GlobalSearch.vue +174 -108
  45. package/src/components/Search/SearchInput.vue +3 -3
  46. package/src/components/TabularExplorer/TabularCell.vue +51 -0
  47. package/src/components/TabularExplorer/TabularCellPopover.vue +170 -0
  48. package/src/components/TabularExplorer/TabularExplorer.vue +870 -0
  49. package/src/components/TabularExplorer/TabularFilterContent.vue +351 -0
  50. package/src/components/TabularExplorer/TabularFilterPopover.vue +111 -0
  51. package/src/components/TabularExplorer/types.ts +83 -0
  52. package/src/composables/useResourceCapabilities.ts +1 -1
  53. package/src/composables/useSearchFilter.ts +90 -0
  54. package/src/composables/useStableQueryParams.ts +28 -3
  55. package/src/config.ts +2 -0
  56. package/src/functions/api.ts +34 -33
  57. package/src/functions/api.types.ts +1 -0
  58. package/src/functions/datasets.ts +0 -17
  59. package/src/functions/resources.ts +56 -1
  60. package/src/functions/tabular.ts +60 -0
  61. package/src/functions/tabularApi.ts +4 -6
  62. package/src/main.ts +14 -6
  63. package/src/types/dataservices.ts +2 -0
  64. package/src/types/pages.ts +0 -5
  65. package/src/types/posts.ts +2 -2
  66. package/src/types/reports.ts +3 -0
  67. package/src/types/search.ts +50 -1
  68. package/src/types/site.ts +5 -3
  69. package/src/types/users.ts +0 -1
  70. package/assets/swagger-themes/newspaper.css +0 -1670
  71. package/dist/Datafair.client-E5D6ePRC.js +0 -35
  72. package/dist/JsonPreview.client-C-6eBbPw.js +0 -87
  73. package/dist/Swagger.client-D4-F6yEf.js +0 -4
  74. package/dist/XmlPreview.client-Dl2VCgXF.js +0 -79
  75. package/dist/main-B2kXxWRG.js +0 -105833
  76. package/src/components/ResourceAccordion/Swagger.client.vue +0 -48
  77. package/src/functions/pagination.ts +0 -9
  78. /package/assets/illustrations/{_microscope.svg → microscope.svg} +0 -0
@@ -0,0 +1,170 @@
1
+ <template>
2
+ <ClientOnly>
3
+ <Teleport to="#tooltips">
4
+ <div
5
+ v-if="cell"
6
+ ref="panel"
7
+ class="bg-white border border-black/10 rounded-lg shadow-md w-80 absolute z-[800]"
8
+ :style="floatingStyles"
9
+ >
10
+ <!-- Value -->
11
+ <div class="px-3 pt-3 pb-2 border-b border-gray-default">
12
+ <p class="text-[10px] text-gray-plain mb-0">
13
+ {{ t('Valeur brute') }}
14
+ </p>
15
+ <p class="text-xs text-gray-title mb-0">
16
+ {{ displayValue }}
17
+ </p>
18
+ </div>
19
+
20
+ <!-- Type -->
21
+ <div class="flex items-center gap-2 px-3 py-2 border-b border-gray-default">
22
+ <span class="text-[10px] text-gray-plain">{{ t('Type') }}</span>
23
+ <span class="inline-flex items-center gap-1 bg-gray-some rounded px-1.5 py-0.5 text-xs text-gray-plain">
24
+ <component
25
+ :is="typeIcon"
26
+ class="size-3"
27
+ aria-hidden="true"
28
+ />
29
+ {{ typeLabel }}
30
+ </span>
31
+ <span class="text-[10px] text-gray-plain shrink-0">·</span>
32
+ <span class="text-[10px] text-gray-plain truncate min-w-0">{{ cell.column }}</span>
33
+ </div>
34
+
35
+ <!-- Actions -->
36
+ <div class="p-1">
37
+ <button
38
+ class="flex items-center gap-2.5 w-full px-3 py-2 rounded-md text-xs font-medium hover:bg-gray-50"
39
+ @click="filterByValue"
40
+ >
41
+ <RiFilter2Line
42
+ class="size-4"
43
+ aria-hidden="true"
44
+ />
45
+ {{ t('Filtrer par cette valeur') }}
46
+ </button>
47
+ <button
48
+ class="flex items-center gap-2.5 w-full px-3 py-2 rounded-md text-xs font-medium hover:bg-gray-50"
49
+ @click="copyValue"
50
+ >
51
+ <RiCheckLine
52
+ v-if="copied"
53
+ class="size-4 text-green-500"
54
+ aria-hidden="true"
55
+ />
56
+ <RiFileCopyLine
57
+ v-else
58
+ class="size-4 text-gray-plain"
59
+ aria-hidden="true"
60
+ />
61
+ {{ copied ? t('Copié !') : t('Copier la valeur') }}
62
+ </button>
63
+ </div>
64
+ </div>
65
+ </Teleport>
66
+ </ClientOnly>
67
+ </template>
68
+
69
+ <script setup lang="ts">
70
+ import { computed, ref, useTemplateRef, watch } from 'vue'
71
+ import { flip, shift, autoUpdate, useFloating } from '@floating-ui/vue'
72
+ import { onClickOutside } from '@vueuse/core'
73
+ import {
74
+ RiFilter2Line,
75
+ RiFileCopyLine,
76
+ RiCheckLine,
77
+ } from '@remixicon/vue'
78
+ import { toast } from 'vue-sonner'
79
+ import { useTranslation } from '../../composables/useTranslation'
80
+ import { buildTypeConfig } from '../../functions/tabular'
81
+ import ClientOnly from '../ClientOnly.vue'
82
+ import type { ColumnType, ColumnFilters } from './types'
83
+
84
+ export interface CellInfo {
85
+ column: string
86
+ columnType: ColumnType
87
+ value: unknown
88
+ element: HTMLElement
89
+ }
90
+
91
+ const cell = defineModel<CellInfo | null>('cell', { default: null })
92
+ const filters = defineModel<Record<string, ColumnFilters>>('filters', { default: () => ({}) })
93
+
94
+ const { t } = useTranslation()
95
+
96
+ const panelRef = useTemplateRef<HTMLElement>('panel')
97
+ const anchorRef = ref<HTMLElement | null>(null)
98
+
99
+ watch(cell, (c) => {
100
+ anchorRef.value = c?.element ?? null
101
+ })
102
+
103
+ const { floatingStyles } = useFloating(anchorRef, panelRef, {
104
+ placement: 'bottom-start',
105
+ middleware: [flip(), shift()],
106
+ whileElementsMounted: autoUpdate,
107
+ })
108
+
109
+ const displayValue = computed(() => {
110
+ if (!cell.value) return ''
111
+ const v = cell.value.value
112
+ if (v == null || v === '') return '–'
113
+ if (typeof v === 'object') return JSON.stringify(v)
114
+ return String(v)
115
+ })
116
+
117
+ const typeConfig = buildTypeConfig(t)
118
+
119
+ const typeIcon = computed(() => cell.value ? typeConfig[cell.value.columnType].icon : typeConfig.text.icon)
120
+ const typeLabel = computed(() => cell.value ? typeConfig[cell.value.columnType].label : '')
121
+
122
+ function close() {
123
+ cell.value = null
124
+ }
125
+
126
+ function filterByValue() {
127
+ if (!cell.value) return
128
+ const val = String(cell.value.value ?? '')
129
+ const col = cell.value.column
130
+ const existing = filters.value[col] ?? {}
131
+ if (cell.value.columnType === 'categorical' || cell.value.columnType === 'text' || cell.value.columnType === 'date') {
132
+ const current = existing.in ?? []
133
+ if (!current.includes(val)) {
134
+ filters.value = { ...filters.value, [col]: { ...existing, in: [...current, val] } }
135
+ }
136
+ }
137
+ else if (cell.value.columnType === 'number') {
138
+ const num = Number(cell.value.value)
139
+ if (Number.isFinite(num)) {
140
+ filters.value = { ...filters.value, [col]: { ...existing, min: num, max: num } }
141
+ }
142
+ }
143
+ else if (cell.value.columnType === 'boolean') {
144
+ filters.value = { ...filters.value, [col]: { ...existing, exact: val } }
145
+ }
146
+ close()
147
+ }
148
+
149
+ const copied = ref(false)
150
+
151
+ async function copyValue() {
152
+ try {
153
+ await navigator.clipboard.writeText(displayValue.value)
154
+ copied.value = true
155
+ setTimeout(() => {
156
+ copied.value = false
157
+ }, 1500)
158
+ }
159
+ catch {
160
+ toast.error(t('Impossible de copier dans le presse-papier'))
161
+ }
162
+ }
163
+
164
+ onClickOutside(panelRef, (e) => {
165
+ if (!cell.value) return
166
+ const clickedCell = (e.target as HTMLElement).closest('[data-cell]')
167
+ if (clickedCell && clickedCell === cell.value.element) return
168
+ close()
169
+ })
170
+ </script>