@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,12 +1,12 @@
1
- import React, { FC } from "react";
2
-
3
- type LoadingProps = {
4
- opacity?: boolean;
5
- }
6
- export const Loading: FC<LoadingProps> = ({ opacity = false }) => {
7
- return (
8
- <div className={`fixed inset-0 z-[100000] w-full h-full flex justify-center items-center bg-white ${opacity ? "opacity-50" : ""}`}>
9
- <div className="animate-spin rounded-full h-12 w-12 border-2 border-gray-300 border-t-gray-950"></div>
10
- </div>
11
- );
1
+ import React, { FC } from "react";
2
+
3
+ type LoadingProps = {
4
+ opacity?: boolean;
5
+ }
6
+ export const Loading: FC<LoadingProps> = ({ opacity = false }) => {
7
+ return (
8
+ <div className={`fixed inset-0 z-[100000] w-full h-full flex justify-center items-center bg-white ${opacity ? "opacity-50" : ""}`}>
9
+ <div className="animate-spin rounded-full h-12 w-12 border-2 border-gray-300 border-t-gray-950"></div>
10
+ </div>
11
+ );
12
12
  };
@@ -0,0 +1,24 @@
1
+ import * as FaIcons from "react-icons/fa6";
2
+
3
+ type SocialIconProps = {
4
+ label: string;
5
+ className?: string;
6
+ };
7
+
8
+ const supportedIcons: Partial<Record<string, keyof typeof FaIcons>> = {
9
+ xing: "FaSquareXing",
10
+ linkedin: "FaLinkedin",
11
+ twitter: "FaSquareXTwitter",
12
+ instagram: "FaInstagram",
13
+ youtube: "FaYoutube",
14
+ facebook: "FaSquareFacebook",
15
+ };
16
+
17
+ export const SocialIcon = ({ label, className }: SocialIconProps) => {
18
+ const iconName = supportedIcons[label.toLowerCase()];
19
+ const Icon = iconName ? FaIcons[iconName] : null;
20
+
21
+ if (!Icon) return <>{label}</>;
22
+
23
+ return <Icon className={className} aria-hidden="true" />;
24
+ };
@@ -0,0 +1,43 @@
1
+ import Link from "next/link";
2
+ import { Card, CardContent, CardHeader, CardTitle } from "@c-rex/ui/card";
3
+
4
+ type InfoCardItem = {
5
+ label: string;
6
+ value?: string | null;
7
+ link?: string | null;
8
+ };
9
+
10
+ type InfoCardProps = {
11
+ title: string;
12
+ items: InfoCardItem[];
13
+ };
14
+
15
+ export const InfoCard = ({ title, items }: InfoCardProps) => {
16
+ return (
17
+ <Card>
18
+ <CardHeader>
19
+ <CardTitle className="text-lg">{title}</CardTitle>
20
+ </CardHeader>
21
+ <CardContent className="space-y-3">
22
+ {items.map((item) => {
23
+ const content = (
24
+ <>
25
+ <div className="line-clamp-2 text-sm font-medium">{item.label}</div>
26
+ {item.value ? <div className="text-xs text-muted-foreground">{item.value}</div> : null}
27
+ </>
28
+ );
29
+
30
+ if (item.link) {
31
+ return (
32
+ <Link key={`${item.link}-${item.label}`} href={item.link} className="block rounded-md hover:opacity-90">
33
+ {content}
34
+ </Link>
35
+ );
36
+ }
37
+
38
+ return <div key={item.label}>{content}</div>;
39
+ })}
40
+ </CardContent>
41
+ </Card>
42
+ );
43
+ };
@@ -1,146 +1,157 @@
1
- import React, { FC } from "react";
2
- import { Card, CardContent, CardHeader, CardTitle } from "@c-rex/ui/card";
3
- import {
4
- Table,
5
- TableBody,
6
- TableCell,
7
- TableRow,
8
- } from "@c-rex/ui/table"
9
-
10
- import { renderValue } from "./shared";
11
- import {
12
- DropdownMenu,
13
- DropdownMenuContent,
14
- DropdownMenuItem,
15
- DropdownMenuTrigger,
16
- } from "@c-rex/ui/dropdown-menu";
17
- import { CloudDownload, Eye } from "lucide-react";
18
- import { InformationUnitModel } from "@c-rex/interfaces";
19
- import { Flag } from "../icons/flag-icon";
20
- import { Button } from "@c-rex/ui/button";
21
- import { FileIcon } from "../icons/file-icon";
22
- import { BookmarkButton } from "../favorites/bookmark-button";
23
- import { InformationUnitsGetAll } from "../generated/server-components";
24
- import { getTranslations } from "next-intl/server";
25
- import { EN_LANG } from "@c-rex/constants";
26
- import { getFileRenditions } from "../results/utils";
27
- import Link from "next/link";
28
- import { processDataToLabelValuePairs } from "@c-rex/utils";
29
-
30
- type Props = {
31
- title: string;
32
- linkPath: "topics" | "documents";
33
- data: InformationUnitModel;
34
- excludeKeys?: string[];
35
- showBookmarkButton?: boolean;
36
- }
37
-
38
- export const InfoTable: FC<Props> = async ({
39
- title,
40
- data,
41
- linkPath = "topics",
42
- showBookmarkButton = false,
43
- }) => {
44
- const t = await getTranslations();
45
- const files = getFileRenditions({ renditions: data.renditions! });
46
-
47
- return (
48
- <Card className="p-0 !pt-4">
49
- <CardHeader>
50
- <CardTitle className="text-lg flex justify-between items-end">
51
- {title}
52
-
53
- {showBookmarkButton && <BookmarkButton shortId={data.shortId!} />}
54
- </CardTitle>
55
- </CardHeader>
56
- <CardContent className="space-y-3 !p-0">
57
- <Table>
58
- <TableBody>
59
- {processDataToLabelValuePairs(data).map((item) => (
60
- <TableRow key={item.label} className="min-h-12">
61
- <TableCell className="font-medium w-28 pl-4">
62
- <h4 className="text-sm font-medium capitalize">{t(item.label)}</h4>
63
- </TableCell>
64
- <TableCell className="text-xs text-muted-foreground flex items-center gap-2 min-h-12">
65
- {renderValue(item, EN_LANG)}
66
- </TableCell>
67
- </TableRow>
68
- ))}
69
-
70
- {/*check if has versionOF */}
71
- <InformationUnitsGetAll
72
- queryParams={{
73
- Restrict: [`versionOf.shortId=${data.versionOf?.shortId}`],
74
- Fields: ["renditions", "class", "languages", "labels"]
75
- }}
76
- render={(data, error) => {
77
- if (error) {
78
- return JSON.stringify(error);
79
- }
80
-
81
- return (
82
- <TableRow className="min-h-12">
83
- <TableCell className="font-medium w-28 pl-4">
84
- <h4 className="text-sm font-medium">{t("availableIn")}</h4>
85
- </TableCell>
86
- <TableCell className="text-xs text-muted-foreground flex items-center gap-2 min-h-12">
87
- {data.items.map((item) => {
88
- const language = item.languages?.[0] ?? "NO LANGUAGE";
89
- const country = language.split("-")[1]!;
90
- return (
91
- <span className="w-8 block border" key={item.shortId}>
92
- <Link href={`/${linkPath}/${item.shortId}/content`} title={language}>
93
- <Flag countryCode={country} />
94
- </Link>
95
- </span>
96
- )
97
- })}
98
- </TableCell>
99
- </TableRow>
100
- )
101
- }}
102
- />
103
-
104
- {Object.keys(files).length > 0 && (
105
- <TableRow className="min-h-12">
106
- <TableCell className="font-medium w-28 pl-4">
107
- <h4 className="text-sm font-medium">{t("files")}</h4>
108
- </TableCell>
109
- <TableCell className="text-xs text-muted-foreground flex items-center gap-2 min-h-12">
110
-
111
- {Object.keys(files).map((fileKey) => {
112
- if (!files[fileKey]) return null
113
-
114
- return (
115
- <DropdownMenu key={fileKey}>
116
- <DropdownMenuTrigger className="mr-2" asChild >
117
- <Button variant="outline" size="icon" >
118
- <FileIcon extension={fileKey} />
119
- </Button>
120
- </DropdownMenuTrigger>
121
- <DropdownMenuContent>
122
- <DropdownMenuItem>
123
- <a href={files[fileKey].view} target="_blank" rel="noreferrer" className="flex items-center">
124
- <Eye className="mr-2" /> Open
125
- </a>
126
- </DropdownMenuItem>
127
- <DropdownMenuItem>
128
- <a href={files[fileKey].download} target="_blank" rel="noreferrer" className="flex items-center">
129
- <CloudDownload className="mr-2" /> Download
130
- </a>
131
- </DropdownMenuItem>
132
-
133
- </DropdownMenuContent>
134
- </DropdownMenu>
135
- )
136
- })}
137
-
138
- </TableCell>
139
- </TableRow>
140
- )}
141
- </TableBody>
142
- </Table>
143
- </CardContent>
144
- </Card >
145
- );
146
- }
1
+ import React, { FC } from "react";
2
+ import { Card, CardContent, CardHeader, CardTitle } from "@c-rex/ui/card";
3
+ import {
4
+ Table,
5
+ TableBody,
6
+ TableCell,
7
+ TableRow,
8
+ } from "@c-rex/ui/table"
9
+
10
+ import { renderMetadataDisplayValues } from "./shared";
11
+ import {
12
+ DropdownMenu,
13
+ DropdownMenuContent,
14
+ DropdownMenuItem,
15
+ DropdownMenuTrigger,
16
+ } from "@c-rex/ui/dropdown-menu";
17
+ import { CloudDownload, Eye } from "lucide-react";
18
+ import { InformationUnitModel } from "@c-rex/interfaces";
19
+ import { Flag } from "../icons/flag-icon";
20
+ import { Button } from "@c-rex/ui/button";
21
+ import { FileIcon } from "../icons/file-icon";
22
+ import { BookmarkButton } from "../favorites/bookmark-button";
23
+ import { getLocale, getTranslations } from "next-intl/server";
24
+ import { getFileRenditions } from "../results/utils";
25
+ import Link from "next/link";
26
+ import { extractCountryCodeFromLanguage } from "@c-rex/utils";
27
+ import {
28
+ getAvailableLanguagesByVersionOf,
29
+ getMetadataDisplayRows,
30
+ resolveMetadataDisplayProperties,
31
+ } from "@c-rex/services/read-models";
32
+
33
+ type Props = {
34
+ title: string;
35
+ linkPattern: string;
36
+ data: InformationUnitModel;
37
+ metadataIncludeProperties?: Array<keyof InformationUnitModel>;
38
+ metadataExcludeProperties?: Array<keyof InformationUnitModel>;
39
+ showBookmarkButton?: boolean;
40
+ showFileRenditions?: boolean;
41
+ }
42
+
43
+ export const InformationUnitMetadataGrid: FC<Props> = async ({
44
+ title,
45
+ data,
46
+ linkPattern,
47
+ metadataIncludeProperties,
48
+ metadataExcludeProperties,
49
+ showBookmarkButton = false,
50
+ showFileRenditions = true,
51
+ }) => {
52
+ const [t, locale] = await Promise.all([
53
+ getTranslations(),
54
+ getLocale(),
55
+ ]);
56
+ const files = showFileRenditions ? getFileRenditions({ renditions: data.renditions! }) : {};
57
+
58
+ const availableVersions = await getAvailableLanguagesByVersionOf(data.versionOf?.shortId);
59
+ const displayVersions = availableVersions.filter((item) => item.shortId !== data.shortId);
60
+ const metadataRows = await getMetadataDisplayRows(data, {
61
+ uiLanguage: locale,
62
+ includeProperties: resolveMetadataDisplayProperties({
63
+ includeProperties: metadataIncludeProperties,
64
+ excludeProperties: metadataExcludeProperties,
65
+ }),
66
+ });
67
+ const resolveDetailsPath = (shortId: string): string =>
68
+ linkPattern.replace("{shortId}", shortId);
69
+
70
+ return (
71
+ <Card className="p-0 !pt-4">
72
+ <CardHeader>
73
+ <CardTitle className="text-lg flex justify-between items-end">
74
+ {title}
75
+
76
+ {showBookmarkButton && <BookmarkButton shortId={data.shortId!} />}
77
+ </CardTitle>
78
+ </CardHeader>
79
+ <CardContent className="space-y-3 !p-0">
80
+ <Table>
81
+ <TableBody>
82
+ {metadataRows.map((row) => (
83
+ <TableRow key={`${row.key}:${row.label}`} className="min-h-12">
84
+ <TableCell className="font-medium w-28 pl-4">
85
+ <h4 className="text-sm font-medium capitalize">
86
+ {row.labelSource === "translationKey" ? t(row.label) : row.label}
87
+ </h4>
88
+ </TableCell>
89
+ <TableCell className="text-xs text-muted-foreground flex items-center gap-2 min-h-12">
90
+ {renderMetadataDisplayValues(row, locale)}
91
+ </TableCell>
92
+ </TableRow>
93
+ ))}
94
+
95
+ {displayVersions.length > 0 && (
96
+ <TableRow className="min-h-12">
97
+ <TableCell className="font-medium w-28 pl-4">
98
+ <h4 className="text-sm font-medium">{t("availableIn")}</h4>
99
+ </TableCell>
100
+ <TableCell className="text-xs text-muted-foreground flex items-center gap-2 min-h-12">
101
+ {displayVersions.map((item) => {
102
+ const country = extractCountryCodeFromLanguage(item.language);
103
+ return (
104
+ <span className="w-8 block border" key={item.shortId}>
105
+ <Link href={resolveDetailsPath(item.shortId)} title={item.language}>
106
+ <Flag countryCode={country} />
107
+ </Link>
108
+ </span>
109
+ );
110
+ })}
111
+ </TableCell>
112
+ </TableRow>
113
+ )}
114
+
115
+ {Object.keys(files).length > 0 && (
116
+ <TableRow className="min-h-12">
117
+ <TableCell className="font-medium w-28 pl-4">
118
+ <h4 className="text-sm font-medium">{t("files")}</h4>
119
+ </TableCell>
120
+ <TableCell className="text-xs text-muted-foreground flex items-center gap-2 min-h-12">
121
+
122
+ {Object.keys(files).map((fileKey) => {
123
+ if (!files[fileKey]) return null
124
+
125
+ return (
126
+ <DropdownMenu key={fileKey}>
127
+ <DropdownMenuTrigger className="mr-2" asChild >
128
+ <Button variant="outline" size="icon" >
129
+ <FileIcon extension={fileKey} />
130
+ </Button>
131
+ </DropdownMenuTrigger>
132
+ <DropdownMenuContent>
133
+ <DropdownMenuItem>
134
+ <a href={files[fileKey].view} target="_blank" rel="noreferrer" className="flex items-center">
135
+ <Eye className="mr-2" /> Open
136
+ </a>
137
+ </DropdownMenuItem>
138
+ <DropdownMenuItem>
139
+ <a href={files[fileKey].download} target="_blank" rel="noreferrer" className="flex items-center">
140
+ <CloudDownload className="mr-2" /> Download
141
+ </a>
142
+ </DropdownMenuItem>
143
+
144
+ </DropdownMenuContent>
145
+ </DropdownMenu>
146
+ )
147
+ })}
148
+
149
+ </TableCell>
150
+ </TableRow>
151
+ )}
152
+ </TableBody>
153
+ </Table>
154
+ </CardContent>
155
+ </Card >
156
+ );
157
+ }
@@ -1,25 +1,49 @@
1
- import { ReactNode } from "react";
2
- import { articleInfoItemType } from "@c-rex/types";
3
- import { formatDateToLocale, isDate, isLanguage } from "@c-rex/utils";
4
- import { Flag } from "../icons/flag-icon";
5
-
6
-
7
- export const renderValue = (item: articleInfoItemType, uiLang: string): ReactNode => {
8
- if (isDate(item.value)) return formatDateToLocale(item.value, uiLang);
9
-
10
- if (isLanguage(item.label)) {
11
- const countryCode = item.value.split("-")[1] || item.value;
12
- return (
13
- <span className="w-8 block">
14
- <Flag countryCode={countryCode} />
15
- </span>
16
- );
17
- }
18
-
19
- return item.value;
20
- }
21
-
22
- export const filteredItems = (items: articleInfoItemType[]): articleInfoItemType[] => {
23
- const hasTitle = items.some(item => item.label === "titles");
24
- return items.filter(item => (hasTitle ? !(item.label == "labels") : true));
25
- }
1
+ import { ReactNode } from "react";
2
+ import { articleInfoItemType } from "@c-rex/types";
3
+ import { extractCountryCodeFromLanguage, formatDateToLocale, isDate, isLanguage } from "@c-rex/utils";
4
+ import { Flag } from "../icons/flag-icon";
5
+
6
+ type MetadataDisplayRow = {
7
+ values: string[];
8
+ valueType?: string;
9
+ };
10
+
11
+ export const renderValue = (item: articleInfoItemType, uiLang: string): ReactNode => {
12
+ if (isDate(item.value)) return formatDateToLocale(item.value, uiLang);
13
+
14
+ if (isLanguage(item.label)) {
15
+ const countryCode = item.value.split("-")[1] || item.value;
16
+ return (
17
+ <span className="w-8 block">
18
+ <Flag countryCode={countryCode} />
19
+ </span>
20
+ );
21
+ }
22
+
23
+ return item.value;
24
+ }
25
+
26
+ export const renderMetadataDisplayValues = (row: MetadataDisplayRow, uiLang: string): ReactNode => {
27
+ if (row.valueType === "language") {
28
+ return (
29
+ <span className="flex items-center gap-2">
30
+ {row.values.map((language) => (
31
+ <span className="w-8 block" key={language} title={language}>
32
+ <Flag countryCode={extractCountryCodeFromLanguage(language)} />
33
+ </span>
34
+ ))}
35
+ </span>
36
+ );
37
+ }
38
+
39
+ if (row.values.length === 1 && isDate(row.values[0])) {
40
+ return formatDateToLocale(row.values[0], uiLang);
41
+ }
42
+
43
+ return row.values.join(", ");
44
+ };
45
+
46
+ export const filteredItems = (items: articleInfoItemType[]): articleInfoItemType[] => {
47
+ const hasTitle = items.some(item => item.label === "titles");
48
+ return items.filter(item => (hasTitle ? !(item.label == "labels") : true));
49
+ }