@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,164 +1,196 @@
1
- import { FilterItem, Tags } from "@c-rex/interfaces";
2
- import { EN_LANG } from "@c-rex/constants";
3
-
4
- export const updateFilterParam = (key: string, item: FilterItem, filter: string | null): Record<string, string | null> => {
5
-
6
- if (key === "packages") {
7
- return { packages: item.shortId }
8
- }
9
-
10
- const value = `${key}.shortId=${item.shortId}`
11
- let aux = value
12
-
13
- if (filter != null) {
14
- const splittedParam = filter.split(",")
15
- const finalValue = [...splittedParam]
16
-
17
- const hasParams = filter.includes(key)
18
-
19
- if (hasParams) {
20
- let mainIndex = -1
21
-
22
- splittedParam.forEach((el, index) => {
23
- if (el.includes(key)) {
24
- mainIndex = index
25
- }
26
- })
27
- finalValue[mainIndex] = value
28
- } else {
29
- finalValue.push(value)
30
- }
31
-
32
- aux = finalValue.join(",")
33
- }
34
-
35
- return { filter: aux }
36
- };
37
-
38
- export const removeFilterItem = (key: string, item: FilterItem, filter: string | null): Record<string, string | null> => {
39
- if (key === "packages") {
40
- return { packages: null }
41
- }
42
-
43
- if (filter !== null) {
44
- const value = `${key}.shortId=${item.shortId}`
45
- const newValue = filter.split(",").filter(item => item !== value).join(",")
46
- return { filter: newValue.length === 0 ? null : newValue }
47
- }
48
-
49
- return {}
50
- }
51
-
52
- export const clearData = (tags: Tags): Record<string, FilterItem[]> => {
53
- const contentLang = EN_LANG.toLowerCase()
54
- const splittedContentLang = contentLang.split("-")[0];
55
- const filteredTags: Record<string, FilterItem[]> = {}
56
-
57
- for (const [key, value] of Object.entries(tags)) {
58
- if (!value || !value.items || value.items.length === 0) {
59
- continue;
60
- }
61
-
62
- const aux = value.items.map(item => {
63
- if (item?.shortId === undefined) return null
64
- if (Number(item.hits) === 0) return null
65
- if (item?.labels === undefined || item?.labels.length === 0) {
66
- /*
67
- logger.log({
68
- level: "warning",
69
- message: `No labels on item with id ${item.shortId} from category ${key}`
70
- })
71
- */
72
-
73
- return null;
74
- }
75
-
76
- let label = ""
77
-
78
- for (const labelItem of item.labels) {
79
- if (labelItem.language === undefined) {
80
- /*
81
- logger.log({
82
- level: "info",
83
- message: `No language on label ${labelItem.value} from category ${key}`
84
- })
85
- */
86
- label = labelItem.value
87
- break;
88
- }
89
-
90
- if (labelItem.language.toLowerCase() === contentLang || labelItem.language.toLowerCase() === splittedContentLang) {
91
- label = labelItem.value
92
- break;
93
- }
94
-
95
- label = labelItem.value
96
-
97
- // todo: fallback in english
98
- }
99
-
100
- return {
101
- hits: item.hits,
102
- total: item.total,
103
- label: label,
104
- active: false,
105
- shortId: item.shortId,
106
- }
107
- }).filter((item) => item !== null)
108
-
109
- if (aux.length === 0) {
110
- continue;
111
- }
112
-
113
- filteredTags[key] = aux;
114
- }
115
-
116
- return filteredTags;
117
- }
118
-
119
- export const memoizeFilteredTags = (tags: Tags | undefined, filter: string | null, packages: string | null) => {
120
-
121
- if (!tags) return {};
122
-
123
- const newTags: Record<string, FilterItem[]> = clearData(tags);
124
-
125
- if (filter !== null) {
126
- const splittedParam = filter.split(",")
127
-
128
- splittedParam.forEach((item) => {
129
- const aux = item.split(".shortId=")
130
- const name = aux[0] as string
131
- const shortId = aux[1] as string
132
-
133
- if (!Object.keys(newTags).includes(name)) {
134
- newTags[name] = []
135
- }
136
-
137
- newTags[name]?.forEach((el) => {
138
- if (el.shortId == shortId) {
139
- el.active = true
140
- } else {
141
- el.active = false
142
- }
143
- })
144
- })
145
- } else {
146
- Object.keys(newTags).forEach((key) => {
147
- newTags[key]?.forEach((el) => {
148
- el.active = false
149
- })
150
- })
151
- }
152
-
153
- if (packages !== null && newTags["packages"]) {
154
- newTags["packages"].forEach((el) => {
155
- if (el.shortId == packages) {
156
- el.active = true
157
- } else {
158
- el.active = false
159
- }
160
- })
161
- }
162
-
163
- return newTags
164
- }
1
+ import { FilterItem, Tags } from "@c-rex/interfaces";
2
+ import { EN_LANG } from "@c-rex/constants";
3
+
4
+ export type FacetLabelOverride = {
5
+ label: string;
6
+ groupLabel?: string;
7
+ sectionLabel?: string;
8
+ };
9
+
10
+ export type FacetLabelOverrides = Partial<Record<string, Record<string, FacetLabelOverride>>>;
11
+
12
+ export type ResolvedFilterItem = FilterItem & {
13
+ groupLabel?: string;
14
+ sectionLabel?: string;
15
+ taxonomyId?: string;
16
+ };
17
+
18
+ export const updateFilterParam = (key: string, item: FilterItem, filter: string | null): Record<string, string | null> => {
19
+
20
+ if (key === "packages") {
21
+ return { packages: item.shortId }
22
+ }
23
+
24
+ const value = `${key}.shortId=${item.shortId}`
25
+ let aux = value
26
+
27
+ if (filter != null) {
28
+ const splittedParam = filter.split(",")
29
+ const finalValue = [...splittedParam]
30
+
31
+ const hasParams = filter.includes(key)
32
+
33
+ if (hasParams) {
34
+ let mainIndex = -1
35
+
36
+ splittedParam.forEach((el, index) => {
37
+ if (el.includes(key)) {
38
+ mainIndex = index
39
+ }
40
+ })
41
+ finalValue[mainIndex] = value
42
+ } else {
43
+ finalValue.push(value)
44
+ }
45
+
46
+ aux = finalValue.join(",")
47
+ }
48
+
49
+ return { filter: aux }
50
+ };
51
+
52
+ export const removeFilterItem = (key: string, item: FilterItem, filter: string | null): Record<string, string | null> => {
53
+ if (key === "packages") {
54
+ return { packages: null }
55
+ }
56
+
57
+ if (filter !== null) {
58
+ const value = `${key}.shortId=${item.shortId}`
59
+ const newValue = filter.split(",").filter(item => item !== value).join(",")
60
+ return { filter: newValue.length === 0 ? null : newValue }
61
+ }
62
+
63
+ return {}
64
+ }
65
+
66
+ export const resolveLabelByLanguage = (
67
+ labels: { language?: string; value: string }[],
68
+ uiLanguage?: string
69
+ ): string | undefined => {
70
+ if (!labels || labels.length === 0) return undefined;
71
+
72
+ const normalizedLanguage = (uiLanguage || EN_LANG).toLowerCase();
73
+ const baseLanguage = normalizedLanguage.split("-")[0];
74
+
75
+ const exact = labels.find((item) => item.language?.toLowerCase() === normalizedLanguage)?.value;
76
+ if (exact) return exact;
77
+
78
+ const base = labels.find((item) => item.language?.toLowerCase() === baseLanguage)?.value;
79
+ if (base) return base;
80
+
81
+ const withoutLanguage = labels.find((item) => !item.language)?.value;
82
+ if (withoutLanguage) return withoutLanguage;
83
+
84
+ return labels[0]?.value;
85
+ };
86
+
87
+ export const clearData = (
88
+ tags: Tags,
89
+ options?: { uiLanguage?: string; labelOverrides?: FacetLabelOverrides; includeZeroHits?: boolean }
90
+ ): Record<string, ResolvedFilterItem[]> => {
91
+ const includeZeroHits = options?.includeZeroHits ?? true;
92
+ const filteredTags: Record<string, ResolvedFilterItem[]> = {}
93
+
94
+ for (const [key, value] of Object.entries(tags)) {
95
+ if (!value || !value.items || value.items.length === 0) {
96
+ continue;
97
+ }
98
+
99
+ const aux = value.items.map(item => {
100
+ if (item?.shortId === undefined) return null
101
+ if (!includeZeroHits && Number(item.hits) === 0) return null
102
+
103
+ const override = options?.labelOverrides?.[key]?.[item.shortId];
104
+ const label = override?.label || resolveLabelByLanguage(item.labels || [], options?.uiLanguage);
105
+ if (!label) return null;
106
+ const taxonomyId = (item as { id?: string }).id;
107
+
108
+ return {
109
+ hits: item.hits,
110
+ total: item.total,
111
+ label,
112
+ active: false,
113
+ shortId: item.shortId,
114
+ groupLabel: override?.groupLabel,
115
+ sectionLabel: override?.sectionLabel,
116
+ taxonomyId,
117
+ }
118
+ }).filter((item) => item !== null)
119
+
120
+ if (aux.length === 0) {
121
+ continue;
122
+ }
123
+
124
+ filteredTags[key] = aux;
125
+ }
126
+
127
+ return filteredTags;
128
+ }
129
+
130
+ export const memoizeFilteredTags = (
131
+ tags: Tags | undefined,
132
+ filter: string | null,
133
+ packages: string | null,
134
+ options?: { uiLanguage?: string; labelOverrides?: FacetLabelOverrides; includeZeroHits?: boolean }
135
+ ) => {
136
+
137
+ if (!tags) return {};
138
+
139
+ const newTags: Record<string, ResolvedFilterItem[]> = clearData(tags, options);
140
+
141
+ if (filter !== null) {
142
+ const splittedParam = filter.split(",")
143
+
144
+ splittedParam.forEach((item) => {
145
+ const aux = item.split(".shortId=")
146
+ const name = aux[0] as string
147
+ const shortId = aux[1] as string
148
+
149
+ if (!Object.keys(newTags).includes(name)) {
150
+ newTags[name] = []
151
+ }
152
+
153
+ newTags[name]?.forEach((el) => {
154
+ if (el.shortId == shortId) {
155
+ el.active = true
156
+ } else {
157
+ el.active = false
158
+ }
159
+ })
160
+ })
161
+ } else {
162
+ Object.keys(newTags).forEach((key) => {
163
+ newTags[key]?.forEach((el) => {
164
+ el.active = false
165
+ })
166
+ })
167
+ }
168
+
169
+ if (packages !== null && newTags["packages"]) {
170
+ newTags["packages"].forEach((el) => {
171
+ if (el.shortId == packages) {
172
+ el.active = true
173
+ } else {
174
+ el.active = false
175
+ }
176
+ })
177
+ }
178
+
179
+ return newTags
180
+ }
181
+
182
+ export const applyFacetPropertyVisibility = (
183
+ tags: Record<string, ResolvedFilterItem[]>,
184
+ includeProperties?: string[],
185
+ excludeProperties?: string[]
186
+ ): Record<string, ResolvedFilterItem[]> => {
187
+ const includeSet = new Set((includeProperties || []).filter(Boolean));
188
+ const excludeSet = new Set((excludeProperties || []).filter(Boolean));
189
+
190
+ return Object.entries(tags).reduce<Record<string, ResolvedFilterItem[]>>((acc, [key, value]) => {
191
+ if (includeSet.size > 0 && !includeSet.has(key)) return acc;
192
+ if (excludeSet.has(key)) return acc;
193
+ acc[key] = value;
194
+ return acc;
195
+ }, {});
196
+ }
@@ -1,99 +1,97 @@
1
- import { FC } from "react";
2
- import { CommonItemsModel } from "@c-rex/interfaces";
3
- import { cn, generateQueryParams, getLanguage, getTitle, getType } from "@c-rex/utils";
4
- import { Flag } from "@c-rex/components/flag";
5
- import { Badge } from "@c-rex/ui/badge";
6
- import Link from "next/link";
7
- import { FileDownloadDropdown } from "@c-rex/components/file-download";
8
- import { getTranslations } from "next-intl/server";
9
- import { QueryParams } from "@c-rex/types";
10
-
11
- interface Props {
12
- items: CommonItemsModel[];
13
- linkPattern: string;
14
- addPackageId: boolean
15
- showFilesColumn?: boolean;
16
- query?: string
17
- }
18
-
19
- export const GenericTableResultList: FC<Props> = async ({
20
- items,
21
- linkPattern,
22
- addPackageId,
23
- query,
24
- showFilesColumn = true,
25
- }) => {
26
- const t = await getTranslations("results");
27
-
28
- return (
29
- <div className="rounded-md border mb-6 last:border-b-0">
30
- <div className="font-bold text-sm p-2 border-b items-center flex-wrap hidden md:flex">
31
- <div className="flex-1 p-2">{t("title")}</div>
32
- <div className="w-1/2 md:w-1/5 p-2 flex justify-center">{t("language")}</div>
33
- <div className="w-1/2 md:w-1/5 p-2 flex justify-center">{t("type")}</div>
34
- {showFilesColumn &&
35
- <div className="w-1/2 md:w-1/5 p-2 flex justify-center">{t("files")}</div>
36
- }
37
- </div>
38
-
39
- {items.map((item) => {
40
- const title = getTitle(item.titles, item.labels);
41
- const itemType = getType(item.class);
42
- const language = getLanguage(item.languages);
43
- const packageId = item.packages && item.packages.length > 0 ? item.packages[0]?.shortId : null;
44
- const queryParams: QueryParams[] = []
45
-
46
- if (addPackageId && packageId) {
47
- queryParams.push({
48
- key: "package",
49
- value: packageId,
50
- })
51
- }
52
-
53
- if (query != undefined) {
54
- queryParams.push({
55
- key: "q",
56
- value: query,
57
- })
58
- }
59
-
60
- const params = generateQueryParams(queryParams)
61
- const link = linkPattern.replace("{id}", item.shortId!) + (params.length > 0 ? `?${params}` : "")
62
-
63
- return (
64
- <div
65
- className={cn(
66
- "min-h-12 c-rex-result-item flex flex-wrap items-center border-b",
67
- `c-rex-result-${itemType.toLowerCase()}`,
68
- )}
69
- key={item.shortId}
70
- >
71
- <div className="flex-1 p-2">
72
- <Link href={link} className="hover:underline">{title}</Link>
73
- </div>
74
-
75
- <div className="w-1/5 md:w-1/5 flex justify-center p-2">
76
- <span className="w-8 inline-block">
77
- {language.split("-").length > 1 && (
78
- <Flag countryCode={language.split("-")[1] as string} />
79
- )}
80
- </span>
81
- </div>
82
-
83
- <div className="w-4/5 md:w-1/5 p-2 flex justify-center">
84
- <Badge variant="secondary">
85
- {itemType}
86
- </Badge>
87
- </div>
88
-
89
- {showFilesColumn &&
90
- <div className="w-1/5 flex justify-center p-2">
91
- <FileDownloadDropdown renditions={item.renditions} />
92
- </div>
93
- }
94
- </div>
95
- )
96
- })}
97
- </div>
98
- );
99
- };
1
+ import { FC } from "react";
2
+ import { CommonItemsModel } from "@c-rex/interfaces";
3
+ import { cn, generateQueryParams } from "@c-rex/utils";
4
+ import { Flag } from "@c-rex/components/flag";
5
+ import { Badge } from "@c-rex/ui/badge";
6
+ import Link from "next/link";
7
+ import { FileDownloadDropdown } from "@c-rex/components/file-download";
8
+ import { getTranslations } from "next-intl/server";
9
+ import { QueryParams } from "@c-rex/types";
10
+ import { getResultItemSummary } from "../summary";
11
+
12
+ interface Props {
13
+ items: CommonItemsModel[];
14
+ linkPattern: string;
15
+ addPackageId: boolean
16
+ showFilesColumn?: boolean;
17
+ query?: string
18
+ }
19
+
20
+ export const GenericTableResultList: FC<Props> = async ({
21
+ items,
22
+ linkPattern,
23
+ addPackageId,
24
+ query,
25
+ showFilesColumn = true,
26
+ }) => {
27
+ const t = await getTranslations("results");
28
+
29
+ return (
30
+ <div className="rounded-md border mb-6 last:border-b-0">
31
+ <div className="font-bold text-sm p-2 border-b items-center flex-wrap hidden md:flex">
32
+ <div className="flex-1 p-2">{t("title")}</div>
33
+ <div className="w-1/2 md:w-1/5 p-2 flex justify-center">{t("language")}</div>
34
+ <div className="w-1/2 md:w-1/5 p-2 flex justify-center">{t("type")}</div>
35
+ {showFilesColumn &&
36
+ <div className="w-1/2 md:w-1/5 p-2 flex justify-center">{t("files")}</div>
37
+ }
38
+ </div>
39
+
40
+ {items.map((item) => {
41
+ const { title, itemType, language, countryCode, packageId } = getResultItemSummary(item);
42
+ const queryParams: QueryParams[] = []
43
+
44
+ if (addPackageId && packageId) {
45
+ queryParams.push({
46
+ key: "package",
47
+ value: packageId,
48
+ })
49
+ }
50
+
51
+ if (query != undefined) {
52
+ queryParams.push({
53
+ key: "q",
54
+ value: query,
55
+ })
56
+ }
57
+
58
+ const params = generateQueryParams(queryParams)
59
+ const link = linkPattern.replace("{shortId}", item.shortId!) + (params.length > 0 ? `?${params}` : "")
60
+
61
+ return (
62
+ <div
63
+ className={cn(
64
+ "min-h-12 c-rex-result-item flex flex-wrap items-center border-b",
65
+ `c-rex-result-${itemType.toLowerCase()}`,
66
+ )}
67
+ key={item.shortId}
68
+ >
69
+ <div className="flex-1 p-2">
70
+ <Link href={link} className="hover:underline">{title}</Link>
71
+ </div>
72
+
73
+ <div className="w-1/5 md:w-1/5 flex justify-center p-2">
74
+ <span className="w-8 inline-block">
75
+ {countryCode.length > 0 && (
76
+ <Flag countryCode={countryCode} />
77
+ )}
78
+ </span>
79
+ </div>
80
+
81
+ <div className="w-4/5 md:w-1/5 p-2 flex justify-center">
82
+ <Badge variant="secondary">
83
+ {itemType}
84
+ </Badge>
85
+ </div>
86
+
87
+ {showFilesColumn &&
88
+ <div className="w-1/5 flex justify-center p-2">
89
+ <FileDownloadDropdown renditions={item.renditions} />
90
+ </div>
91
+ }
92
+ </div>
93
+ )
94
+ })}
95
+ </div>
96
+ );
97
+ };