@c-rex/components 0.1.37 → 0.1.39

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 (146) hide show
  1. package/README.md +73 -73
  2. package/package.json +250 -235
  3. package/src/article/article-action-bar.tsx +110 -110
  4. package/src/article/article-content.tsx +18 -46
  5. package/src/autocomplete.tsx +201 -201
  6. package/src/breadcrumb.tsx +124 -124
  7. package/src/carousel/carousel.tsx +353 -352
  8. package/src/check-article-lang.tsx +47 -43
  9. package/src/directoryNodes/directory-tree-context.tsx +388 -0
  10. package/src/directoryNodes/tree-of-content.tsx +68 -67
  11. package/src/documents/result-list.tsx +124 -127
  12. package/src/favorites/bookmark-button.tsx +97 -79
  13. package/src/favorites/favorite-button.tsx +137 -74
  14. package/src/footer/footer-shell.tsx +52 -0
  15. package/src/footer/footer.tsx +7 -0
  16. package/src/footer/legal-links-block.tsx +25 -0
  17. package/src/footer/organization-contact-block.tsx +94 -0
  18. package/src/footer/social-links-block.tsx +38 -0
  19. package/src/footer/types.ts +10 -0
  20. package/src/footer/vcard-footer.tsx +72 -0
  21. package/src/generated/client-components.tsx +1366 -1350
  22. package/src/generated/create-client-request.tsx +116 -113
  23. package/src/generated/create-server-request.tsx +70 -61
  24. package/src/generated/create-suggestions-request.tsx +55 -55
  25. package/src/generated/server-components.tsx +1056 -1056
  26. package/src/generated/suggestions.tsx +302 -299
  27. package/src/icons/file-icon.tsx +8 -8
  28. package/src/icons/flag-icon.tsx +15 -15
  29. package/src/icons/loading.tsx +11 -11
  30. package/src/icons/social-icon.tsx +24 -0
  31. package/src/info/info-card.tsx +43 -0
  32. package/src/info/{info-table.tsx → information-unit-metadata-grid.tsx} +157 -146
  33. package/src/info/shared.tsx +49 -25
  34. package/src/navbar/language-switcher/content-language-switch.tsx +92 -92
  35. package/src/navbar/language-switcher/shared.tsx +33 -33
  36. package/src/navbar/language-switcher/ui-language-switch.tsx +37 -38
  37. package/src/navbar/navbar.tsx +157 -148
  38. package/src/navbar/settings.tsx +62 -62
  39. package/src/navbar/sign-in-out-btns.tsx +35 -35
  40. package/src/navbar/user-menu.tsx +60 -60
  41. package/src/page-wrapper.tsx +54 -31
  42. package/src/render-article.module.css +155 -0
  43. package/src/render-article.tsx +75 -68
  44. package/src/renditions/file-download.tsx +83 -83
  45. package/src/renditions/html.tsx +64 -64
  46. package/src/renditions/image/container.tsx +54 -54
  47. package/src/renditions/image/rendition.tsx +55 -55
  48. package/src/restriction-menu/restriction-menu-container.tsx +117 -53
  49. package/src/restriction-menu/restriction-menu-item.tsx +155 -147
  50. package/src/restriction-menu/restriction-menu.tsx +341 -157
  51. package/src/results/dialog-filter.tsx +166 -166
  52. package/src/results/empty.tsx +15 -15
  53. package/src/results/filter-navbar.tsx +294 -261
  54. package/src/results/filter-sidebar/__tests__/utils.test.ts +129 -0
  55. package/src/results/filter-sidebar/index.tsx +270 -126
  56. package/src/results/filter-sidebar/utils.ts +196 -164
  57. package/src/results/generic/table-result-list.tsx +97 -99
  58. package/src/results/{table-with-images.tsx → information-unit-search-results-card-list.tsx} +125 -127
  59. package/src/results/{cards.tsx → information-unit-search-results-cards.tsx} +99 -99
  60. package/src/results/{table.tsx → information-unit-search-results-table.tsx} +104 -104
  61. package/src/results/pagination.tsx +81 -81
  62. package/src/results/summary.ts +30 -0
  63. package/src/results/utils.ts +54 -47
  64. package/src/search-input.tsx +70 -70
  65. package/src/share-button.tsx +49 -49
  66. package/src/stores/favorites-store.ts +88 -88
  67. package/src/stores/highlight-store.ts +15 -15
  68. package/src/stores/language-store.ts +14 -43
  69. package/src/stores/restriction-store.ts +11 -11
  70. package/src/stores/search-settings-store.ts +68 -64
  71. package/src/article/article-action-bar.analysis.md +0 -15
  72. package/src/article/article-action-bar.stories.tsx +0 -15
  73. package/src/article/article-content.analysis.md +0 -15
  74. package/src/article/article-content.stories.tsx +0 -21
  75. package/src/autocomplete.analysis.md +0 -17
  76. package/src/breadcrumb.analysis.md +0 -15
  77. package/src/carousel/carousel.analysis.md +0 -17
  78. package/src/check-article-lang.analysis.md +0 -15
  79. package/src/directoryNodes/tree-of-content.analysis.md +0 -14
  80. package/src/directoryNodes/tree-of-content.stories.tsx +0 -22
  81. package/src/documents/result-list.analysis.md +0 -14
  82. package/src/documents/result-list.stories.tsx +0 -19
  83. package/src/favorites/bookmark-button.analysis.md +0 -17
  84. package/src/favorites/bookmark-button.stories.tsx +0 -19
  85. package/src/favorites/favorite-button.analysis.md +0 -18
  86. package/src/favorites/favorite-button.stories.tsx +0 -22
  87. package/src/icons/file-icon.analysis.md +0 -14
  88. package/src/icons/file-icon.stories.tsx +0 -19
  89. package/src/icons/flag-icon.analysis.md +0 -14
  90. package/src/icons/flag-icon.stories.tsx +0 -25
  91. package/src/icons/loading.analysis.md +0 -14
  92. package/src/icons/loading.stories.tsx +0 -21
  93. package/src/info/info-table.analysis.md +0 -15
  94. package/src/info/shared.analysis.md +0 -14
  95. package/src/info/stories/info-table.stories.tsx +0 -31
  96. package/src/info/stories/shared.stories.tsx +0 -24
  97. package/src/navbar/language-switcher/content-language-switch.analysis.md +0 -15
  98. package/src/navbar/language-switcher/shared.analysis.md +0 -14
  99. package/src/navbar/language-switcher/ui-language-switch.analysis.md +0 -15
  100. package/src/navbar/navbar.analysis.md +0 -14
  101. package/src/navbar/settings.analysis.md +0 -14
  102. package/src/navbar/sign-in-out-btns.analysis.md +0 -14
  103. package/src/navbar/stories/navbar.stories.tsx +0 -31
  104. package/src/navbar/stories/settings.stories.tsx +0 -15
  105. package/src/navbar/stories/sign-in-out-btns.stories.tsx +0 -15
  106. package/src/navbar/stories/user-menu.stories.tsx +0 -20
  107. package/src/navbar/user-menu.analysis.md +0 -14
  108. package/src/page-wrapper.analysis.md +0 -14
  109. package/src/render-article.analysis.md +0 -15
  110. package/src/renditions/file-download.analysis.md +0 -14
  111. package/src/renditions/file-download.stories.tsx +0 -19
  112. package/src/renditions/html.analysis.md +0 -17
  113. package/src/renditions/html.stories.tsx +0 -19
  114. package/src/renditions/image/container.analysis.md +0 -15
  115. package/src/renditions/image/container.stories.tsx +0 -19
  116. package/src/renditions/image/rendition.analysis.md +0 -14
  117. package/src/renditions/image/rendition.stories.tsx +0 -19
  118. package/src/restriction-menu/restriction-menu-container.analysis.md +0 -14
  119. package/src/restriction-menu/restriction-menu-item.analysis.md +0 -14
  120. package/src/restriction-menu/restriction-menu.analysis.md +0 -17
  121. package/src/results/analysis/cards.analysis.md +0 -14
  122. package/src/results/analysis/dialog-filter.analysis.md +0 -17
  123. package/src/results/analysis/empty.analysis.md +0 -14
  124. package/src/results/analysis/filter-navbar.analysis.md +0 -16
  125. package/src/results/analysis/pagination.analysis.md +0 -14
  126. package/src/results/analysis/table-with-images.analysis.md +0 -15
  127. package/src/results/analysis/table.analysis.md +0 -15
  128. package/src/results/filter-sidebar/index.analysis.md +0 -14
  129. package/src/results/generic/table-result-list.analysis.md +0 -15
  130. package/src/results/generic/table-result-list.stories.tsx +0 -21
  131. package/src/results/stories/cards.stories.tsx +0 -66
  132. package/src/results/stories/dialog-filter.stories.tsx +0 -20
  133. package/src/results/stories/empty.stories.tsx +0 -25
  134. package/src/results/stories/filter-navbar.stories.tsx +0 -19
  135. package/src/results/stories/filter-sidebar.stories.tsx +0 -20
  136. package/src/results/stories/pagination.stories.tsx +0 -24
  137. package/src/results/stories/table-with-images.stories.tsx +0 -19
  138. package/src/results/stories/table.stories.tsx +0 -78
  139. package/src/search-input.analysis.md +0 -15
  140. package/src/share-button.analysis.md +0 -19
  141. package/src/stories/autocomplete.stories.tsx +0 -20
  142. package/src/stories/breadcrumb.stories.tsx +0 -93
  143. package/src/stories/check-article-lang.stories.tsx +0 -22
  144. package/src/stories/render-article.stories.tsx +0 -19
  145. package/src/stories/search-input.stories.tsx +0 -21
  146. package/src/stories/share-button.stories.tsx +0 -15
@@ -1,261 +1,294 @@
1
- "use client"
2
- import { FC, useMemo } from "react";
3
- import { useTranslations } from "next-intl";
4
- import { parseAsBoolean, parseAsInteger, parseAsString, useQueryStates } from "nuqs";
5
- import { Button } from "@c-rex/ui/button";
6
- import { Funnel, X } from "lucide-react";
7
- import { Badge } from "@c-rex/ui/badge";
8
- import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@c-rex/ui/tooltip";
9
- import { OPERATOR_OPTIONS } from "@c-rex/constants";
10
- import { Tags } from "@c-rex/interfaces";
11
- import { memoizeFilteredTags } from "./filter-sidebar/utils";
12
- import { useSearchSettingsStore } from "../stores/search-settings-store";
13
- import { useRestrictionStore } from "../stores/restriction-store";
14
-
15
- type filterModel = {
16
- key: string
17
- name?: string
18
- value: string
19
- default?: string | boolean | null
20
- removable: boolean
21
- }
22
-
23
- type FilterNavbarProps = {
24
- tags?: Tags
25
- }
26
-
27
- export const FilterNavbar: FC<FilterNavbarProps> = ({ tags }) => {
28
- const t = useTranslations()
29
- const restrictionList = useRestrictionStore((state) => state.restrictionList);
30
- const [params, setParams] = useQueryStates({
31
- language: parseAsString.withDefault(useSearchSettingsStore.getState().language || ''),
32
- page: parseAsInteger.withDefault(1),
33
- wildcard: parseAsString.withDefault(useSearchSettingsStore.getState().wildcard),
34
- operator: parseAsString.withDefault(useSearchSettingsStore.getState().operator),
35
- packages: parseAsString,
36
- filter: parseAsString,
37
- restrict: parseAsString,
38
- like: parseAsBoolean.withDefault(useSearchSettingsStore.getState().like),
39
- search: {
40
- defaultValue: "",
41
- parse(value) {
42
- return value
43
- },
44
- },
45
- }, {
46
- history: 'push',
47
- shallow: false,
48
- });
49
- const isMobile = false
50
-
51
-
52
- const filteredTags = useMemo(() => {
53
- return memoizeFilteredTags(tags, params.filter, params.packages);
54
- }, [tags, params.filter, params.packages]);
55
-
56
- const filters = useMemo(() => {
57
- const filters: filterModel[] = [{
58
- key: "operator",
59
- name: t("filter.operator"),
60
- value: `${params?.operator !== OPERATOR_OPTIONS.OR}`,
61
- removable: false
62
- }, {
63
- key: "like",
64
- name: t("filter.like"),
65
- value: `${params.like}`,
66
- removable: false
67
- }, {
68
- key: "wildcard",
69
- name: t("filter.wildcard"),
70
- value: params.wildcard as string,
71
- removable: false,
72
- }]
73
-
74
- if (params.language !== null) {
75
- filters.push({
76
- key: "language",
77
- name: t(`language`),
78
- value: params.language.toUpperCase(),
79
- removable: false,
80
- })
81
- }
82
-
83
- if (params.filter !== null) {
84
- const splittedParam = params.filter.split(",")
85
-
86
- splittedParam.forEach((item, index) => {
87
- const aux = item.split(".shortId=")
88
- const name = aux[0] as string
89
- const shortId = aux[1] as string
90
-
91
- const defaultValue = [...splittedParam]
92
- defaultValue.splice(index, 1)
93
-
94
- if (!Object.keys(filteredTags).includes(name) || !filteredTags[name]) return;
95
-
96
- const tag = filteredTags[name].find(el => el.shortId === shortId)
97
- if (!tag) return;
98
-
99
- const value = defaultValue.length == 0 ? null : defaultValue.join(",")
100
-
101
- filters.push({
102
- key: "filter",
103
- name: t(`filter.tags.${name}`),
104
- value: tag.label,
105
- removable: true,
106
- default: value
107
- })
108
- })
109
- }
110
-
111
- if (params.restrict !== null) {
112
- const splittedParam = params.restrict.split("=")
113
- const key = splittedParam[0]
114
- const shortIdList = splittedParam[1]?.split(",") || []
115
-
116
- shortIdList.forEach((item, index) => {
117
- const defaultValue = [...shortIdList]
118
- defaultValue.splice(index, 1)
119
-
120
- const value = defaultValue.length == 0 ? null : `${key}=${defaultValue.join(",")}`
121
-
122
- filters.push({
123
- key: "restrict",
124
- name: t(`filter.tags.${key}`),
125
- value: restrictionList.get(item) || item,
126
- removable: true,
127
- default: value
128
- })
129
- })
130
- }
131
-
132
- if (params.packages !== null) {
133
- let label = params.packages
134
-
135
- if (filteredTags["packages"]) {
136
- const aux = filteredTags["packages"].find(el => el.shortId === params.packages)
137
-
138
- if (aux) {
139
- label = aux.label
140
- }
141
- }
142
-
143
- filters.push({
144
- key: "packages",
145
- name: t("filter.tags.packages"),
146
- value: label,
147
- removable: true,
148
- default: null
149
- })
150
- }
151
-
152
- Object.keys(params)
153
- .filter(item => !["page", "search", "language", "operator", "like", "wildcard", "filter", "restrict", "packages"].includes(item))
154
- .forEach(item => {
155
- if (params[item as keyof typeof params] === null || params[item as keyof typeof params] === undefined) return;
156
- const value = params[item as keyof typeof params] as string
157
- filters.push({ key: item, value: value, removable: true, default: null })
158
- })
159
-
160
- return filters
161
- }, [filteredTags, params]);
162
-
163
- if (filters == null || filters.length === 0) {
164
- return null;
165
- }
166
-
167
- return (
168
- <div className="pb-4 flex justify-between">
169
-
170
- <div className="flex flex-wrap gap-2">
171
- <Button
172
- size="sm"
173
- variant="secondary"
174
- //onClick={() => setOpen(true)}
175
- className="md:hidden"
176
- >
177
- <Funnel className="h-2" />
178
- </Button>
179
-
180
- {filters.length > 0 && (
181
- <>
182
- {filters.slice(0, 1).map((item) => (
183
- <Badge
184
- key={`${item.key}-${item?.value}`}
185
- variant="outline"
186
- className="h-8"
187
- >
188
- {item?.name ? item.name : item.key}: {item.value}
189
-
190
- {item.removable && (
191
- <Button size="xs" variant="ghost" onClick={() => {
192
- setParams({ [item.key]: item?.default })
193
- }}>
194
- <X className="h-2" />
195
- </Button>
196
- )}
197
- </Badge>
198
- ))}
199
-
200
-
201
- {isMobile ? (
202
- <TooltipProvider>
203
- <Tooltip delayDuration={100}>
204
- <TooltipTrigger>
205
- <Badge
206
- key={`grouped-filters`}
207
- variant="outline"
208
- className="h-8"
209
- >
210
- +{filters.length - 1} {t("filter.filters")}
211
- </Badge>
212
-
213
- </TooltipTrigger>
214
-
215
- <TooltipContent>
216
- {filters.slice(1).map((item) => {
217
- const label = item?.name ? item.name : item.key
218
- const returnString = `${label}: ${item.value}`;
219
- return <div className="capitalize" key={returnString}>{returnString}</div>;
220
- })}
221
- </TooltipContent>
222
- </Tooltip>
223
- </TooltipProvider>
224
- ) : (
225
- <>
226
- {filters.slice(1).map((item) => (
227
- <Badge
228
- key={`${item.key}-${item?.value}`}
229
- variant="outline"
230
- className="h-8"
231
- >
232
- {item?.name ? item.name : item.key}: {item.value}
233
-
234
- {item.removable && (
235
- <Button size="xs" variant="ghost" onClick={() => {
236
- setParams({ [item.key]: item?.default })
237
- }}>
238
- <X className="h-2" />
239
- </Button>
240
- )}
241
- </Badge>
242
- ))}
243
- </>
244
- )}
245
- </>
246
- )}
247
- </div>
248
-
249
- <Button
250
- size="sm"
251
- variant="secondary"
252
- onClick={() => {
253
- setParams({ filter: null, packages: null })
254
- }}
255
- >
256
- {t("reset")}
257
- </Button>
258
-
259
- </div>
260
- );
261
- };
1
+ "use client"
2
+ import { FC, useMemo } from "react";
3
+ import { useLocale, useTranslations } from "next-intl";
4
+ import { parseAsBoolean, parseAsInteger, parseAsString, useQueryStates } from "nuqs";
5
+ import { Button } from "@c-rex/ui/button";
6
+ import { Funnel, X } from "lucide-react";
7
+ import { Badge } from "@c-rex/ui/badge";
8
+ import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@c-rex/ui/tooltip";
9
+ import { OPERATOR_OPTIONS } from "@c-rex/constants";
10
+ import { Tags } from "@c-rex/interfaces";
11
+ import { applyFacetPropertyVisibility, FacetLabelOverrides, memoizeFilteredTags } from "./filter-sidebar/utils";
12
+ import { useSearchSettingsStore } from "../stores/search-settings-store";
13
+ import { useRestrictionStore } from "../stores/restriction-store";
14
+
15
+ type filterModel = {
16
+ key: string
17
+ name?: string
18
+ value: string
19
+ default?: string | boolean | null
20
+ removable: boolean
21
+ }
22
+
23
+ type FilterNavbarProps = {
24
+ tags?: Tags
25
+ facetLabelOverrides?: FacetLabelOverrides
26
+ includeZeroHits?: boolean
27
+ includeProperties?: string[]
28
+ excludeProperties?: string[]
29
+ }
30
+
31
+ export const FilterNavbar: FC<FilterNavbarProps> = ({
32
+ tags,
33
+ facetLabelOverrides,
34
+ includeZeroHits = true,
35
+ includeProperties,
36
+ excludeProperties,
37
+ }) => {
38
+ const t = useTranslations()
39
+ const locale = useLocale()
40
+ const restrictionList = useRestrictionStore((state) => state.restrictionList);
41
+ const [params, setParams] = useQueryStates({
42
+ language: parseAsString.withDefault(useSearchSettingsStore.getState().language || ''),
43
+ page: parseAsInteger.withDefault(1),
44
+ wildcard: parseAsString.withDefault(useSearchSettingsStore.getState().wildcard),
45
+ operator: parseAsString.withDefault(useSearchSettingsStore.getState().operator),
46
+ packages: parseAsString,
47
+ filter: parseAsString,
48
+ restrict: parseAsString,
49
+ like: parseAsBoolean.withDefault(useSearchSettingsStore.getState().like),
50
+ search: {
51
+ defaultValue: "",
52
+ parse(value) {
53
+ return value
54
+ },
55
+ },
56
+ }, {
57
+ history: 'push',
58
+ shallow: false,
59
+ });
60
+ const isMobile = false
61
+
62
+
63
+ const filteredTags = useMemo(() => {
64
+ const resolved = memoizeFilteredTags(tags, params.filter, params.packages, {
65
+ uiLanguage: locale,
66
+ labelOverrides: facetLabelOverrides,
67
+ includeZeroHits,
68
+ });
69
+ return applyFacetPropertyVisibility(resolved, includeProperties, excludeProperties);
70
+ }, [tags, params.filter, params.packages, locale, facetLabelOverrides, includeZeroHits, includeProperties, excludeProperties]);
71
+
72
+ const humanizeMetadataKey = (key: string): string =>
73
+ key
74
+ .replace(/([a-z0-9])([A-Z])/g, "$1 $2")
75
+ .replace(/[-_]/g, " ")
76
+ .replace(/\s+/g, " ")
77
+ .trim()
78
+ .replace(/^./, (char) => char.toUpperCase());
79
+
80
+ const resolveSectionLabelByKey = (key: string): string => {
81
+ const candidates = filteredTags[key] || [];
82
+ const sectionLabel = candidates.find((item) => item.sectionLabel)?.sectionLabel;
83
+ if (sectionLabel) return sectionLabel;
84
+ const groupLabel = candidates.find((item) => item.groupLabel)?.groupLabel;
85
+ if (groupLabel) return groupLabel;
86
+ return humanizeMetadataKey(key);
87
+ };
88
+
89
+ const filters = useMemo(() => {
90
+ const filters: filterModel[] = [{
91
+ key: "operator",
92
+ name: t("filter.operator"),
93
+ value: `${params?.operator !== OPERATOR_OPTIONS.OR}`,
94
+ removable: false
95
+ }, {
96
+ key: "like",
97
+ name: t("filter.like"),
98
+ value: `${params.like}`,
99
+ removable: false
100
+ }, {
101
+ key: "wildcard",
102
+ name: t("filter.wildcard"),
103
+ value: params.wildcard as string,
104
+ removable: false,
105
+ }]
106
+
107
+ if (params.language !== null) {
108
+ filters.push({
109
+ key: "language",
110
+ name: t(`language`),
111
+ value: params.language.toUpperCase(),
112
+ removable: false,
113
+ })
114
+ }
115
+
116
+ if (params.filter !== null) {
117
+ const splittedParam = params.filter.split(",")
118
+
119
+ splittedParam.forEach((item, index) => {
120
+ const aux = item.split(".shortId=")
121
+ const name = aux[0] as string
122
+ const shortId = aux[1] as string
123
+
124
+ const defaultValue = [...splittedParam]
125
+ defaultValue.splice(index, 1)
126
+
127
+ if (!Object.keys(filteredTags).includes(name) || !filteredTags[name]) return;
128
+
129
+ const tag = filteredTags[name].find(el => el.shortId === shortId)
130
+ if (!tag) return;
131
+
132
+ const value = defaultValue.length == 0 ? null : defaultValue.join(",")
133
+
134
+ filters.push({
135
+ key: "filter",
136
+ name: (tag as { sectionLabel?: string }).sectionLabel || resolveSectionLabelByKey(name),
137
+ value: tag.label,
138
+ removable: true,
139
+ default: value
140
+ })
141
+ })
142
+ }
143
+
144
+ if (params.restrict !== null) {
145
+ const splittedParam = params.restrict.split("=")
146
+ const key = splittedParam[0]
147
+ const shortIdList = splittedParam[1]?.split(",") || []
148
+
149
+ shortIdList.forEach((item, index) => {
150
+ const defaultValue = [...shortIdList]
151
+ defaultValue.splice(index, 1)
152
+
153
+ const value = defaultValue.length == 0 ? null : `${key}=${defaultValue.join(",")}`
154
+
155
+ filters.push({
156
+ key: "restrict",
157
+ name: resolveSectionLabelByKey(key),
158
+ value: restrictionList.get(item) || item,
159
+ removable: true,
160
+ default: value
161
+ })
162
+ })
163
+ }
164
+
165
+ if (params.packages !== null) {
166
+ let label = params.packages
167
+
168
+ if (filteredTags["packages"]) {
169
+ const aux = filteredTags["packages"].find(el => el.shortId === params.packages)
170
+
171
+ if (aux) {
172
+ label = aux.label
173
+ }
174
+ }
175
+
176
+ filters.push({
177
+ key: "packages",
178
+ name: resolveSectionLabelByKey("packages"),
179
+ value: label,
180
+ removable: true,
181
+ default: null
182
+ })
183
+ }
184
+
185
+ Object.keys(params)
186
+ .filter(item => !["page", "search", "language", "operator", "like", "wildcard", "filter", "restrict", "packages"].includes(item))
187
+ .forEach(item => {
188
+ if (params[item as keyof typeof params] === null || params[item as keyof typeof params] === undefined) return;
189
+ const value = params[item as keyof typeof params] as string
190
+ filters.push({ key: item, value: value, removable: true, default: null })
191
+ })
192
+
193
+ return filters
194
+ }, [filteredTags, params]);
195
+
196
+ if (filters == null || filters.length === 0) {
197
+ return null;
198
+ }
199
+
200
+ return (
201
+ <div className="pb-4 flex justify-between">
202
+
203
+ <div className="flex flex-wrap gap-2">
204
+ <Button
205
+ size="sm"
206
+ variant="secondary"
207
+ //onClick={() => setOpen(true)}
208
+ className="md:hidden"
209
+ >
210
+ <Funnel className="h-2" />
211
+ </Button>
212
+
213
+ {filters.length > 0 && (
214
+ <>
215
+ {filters.slice(0, 1).map((item) => (
216
+ <Badge
217
+ key={`${item.key}-${item?.value}`}
218
+ variant="outline"
219
+ className="h-8"
220
+ >
221
+ {item?.name ? item.name : item.key}: {item.value}
222
+
223
+ {item.removable && (
224
+ <Button size="xs" variant="ghost" onClick={() => {
225
+ setParams({ [item.key]: item?.default })
226
+ }}>
227
+ <X className="h-2" />
228
+ </Button>
229
+ )}
230
+ </Badge>
231
+ ))}
232
+
233
+
234
+ {isMobile ? (
235
+ <TooltipProvider>
236
+ <Tooltip delayDuration={100}>
237
+ <TooltipTrigger>
238
+ <Badge
239
+ key={`grouped-filters`}
240
+ variant="outline"
241
+ className="h-8"
242
+ >
243
+ +{filters.length - 1} {t("filter.filters")}
244
+ </Badge>
245
+
246
+ </TooltipTrigger>
247
+
248
+ <TooltipContent>
249
+ {filters.slice(1).map((item) => {
250
+ const label = item?.name ? item.name : item.key
251
+ const returnString = `${label}: ${item.value}`;
252
+ return <div className="capitalize" key={returnString}>{returnString}</div>;
253
+ })}
254
+ </TooltipContent>
255
+ </Tooltip>
256
+ </TooltipProvider>
257
+ ) : (
258
+ <>
259
+ {filters.slice(1).map((item) => (
260
+ <Badge
261
+ key={`${item.key}-${item?.value}`}
262
+ variant="outline"
263
+ className="h-8"
264
+ >
265
+ {item?.name ? item.name : item.key}: {item.value}
266
+
267
+ {item.removable && (
268
+ <Button size="xs" variant="ghost" onClick={() => {
269
+ setParams({ [item.key]: item?.default })
270
+ }}>
271
+ <X className="h-2" />
272
+ </Button>
273
+ )}
274
+ </Badge>
275
+ ))}
276
+ </>
277
+ )}
278
+ </>
279
+ )}
280
+ </div>
281
+
282
+ <Button
283
+ size="sm"
284
+ variant="secondary"
285
+ onClick={() => {
286
+ setParams({ filter: null, packages: null })
287
+ }}
288
+ >
289
+ {t("reset")}
290
+ </Button>
291
+
292
+ </div>
293
+ );
294
+ };