@c-rex/components 0.1.9 → 0.1.11
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/package.json +20 -8
- package/src/autocomplete.tsx +1 -1
- package/src/breadcrumb.tsx +84 -26
- package/src/check-article-lang.tsx +2 -2
- package/src/dialog-filter.tsx +1 -1
- package/src/flag.tsx +15 -0
- package/src/{info-card.tsx → info/info-card.tsx} +7 -2
- package/src/info/info-table.tsx +127 -0
- package/src/info/shared.tsx +32 -0
- package/src/{sidebar.tsx → left-sidebar.tsx} +3 -43
- package/src/navbar/language-switcher/shared.tsx +3 -11
- package/src/navbar/navbar.tsx +35 -33
- package/src/navbar/search-input.tsx +10 -5
- package/src/navbar/settings.tsx +1 -1
- package/src/navbar/sign-in-out-btns.tsx +1 -16
- package/src/page-wrapper.tsx +3 -2
- package/src/result-list.tsx +13 -7
- package/src/result-view/table.tsx +84 -64
- package/src/right-sidebar.tsx +52 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@c-rex/components",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.11",
|
|
4
4
|
"files": [
|
|
5
5
|
"src"
|
|
6
6
|
],
|
|
@@ -25,13 +25,21 @@
|
|
|
25
25
|
"types": "./src/breadcrumb.tsx",
|
|
26
26
|
"import": "./src/breadcrumb.tsx"
|
|
27
27
|
},
|
|
28
|
+
"./flag": {
|
|
29
|
+
"types": "./src/flag.tsx",
|
|
30
|
+
"import": "./src/flag.tsx"
|
|
31
|
+
},
|
|
28
32
|
"./pagination": {
|
|
29
33
|
"types": "./src/pagination.tsx",
|
|
30
34
|
"import": "./src/pagination.tsx"
|
|
31
35
|
},
|
|
36
|
+
"./info-table": {
|
|
37
|
+
"types": "./src/info/info-table.tsx",
|
|
38
|
+
"import": "./src/info/info-table.tsx"
|
|
39
|
+
},
|
|
32
40
|
"./info-card": {
|
|
33
|
-
"types": "./src/info-card.tsx",
|
|
34
|
-
"import": "./src/info-card.tsx"
|
|
41
|
+
"types": "./src/info/info-card.tsx",
|
|
42
|
+
"import": "./src/info/info-card.tsx"
|
|
35
43
|
},
|
|
36
44
|
"./empty": {
|
|
37
45
|
"types": "./src/empty.tsx",
|
|
@@ -61,9 +69,13 @@
|
|
|
61
69
|
"types": "./src/result-view/dropdown-menu.tsx",
|
|
62
70
|
"import": "./src/result-view/dropdown-menu.tsx"
|
|
63
71
|
},
|
|
64
|
-
"./sidebar": {
|
|
65
|
-
"types": "./src/sidebar.tsx",
|
|
66
|
-
"import": "./src/sidebar.tsx"
|
|
72
|
+
"./left-sidebar": {
|
|
73
|
+
"types": "./src/left-sidebar.tsx",
|
|
74
|
+
"import": "./src/left-sidebar.tsx"
|
|
75
|
+
},
|
|
76
|
+
"./right-sidebar": {
|
|
77
|
+
"types": "./src/right-sidebar.tsx",
|
|
78
|
+
"import": "./src/right-sidebar.tsx"
|
|
67
79
|
},
|
|
68
80
|
"./dialog-filter": {
|
|
69
81
|
"types": "./src/dialog-filter.tsx",
|
|
@@ -132,8 +144,8 @@
|
|
|
132
144
|
"next": "^14",
|
|
133
145
|
"next-intl": "^4.1.0",
|
|
134
146
|
"nuqs": "^2.4.3",
|
|
135
|
-
"react": "^18",
|
|
136
|
-
"react-dom": "^18",
|
|
147
|
+
"react": "^18.3.1",
|
|
148
|
+
"react-dom": "^18.3.1",
|
|
137
149
|
"react-icons": "^5.5.0",
|
|
138
150
|
"tailwindcss-animate": "^1.0.7"
|
|
139
151
|
},
|
package/src/autocomplete.tsx
CHANGED
|
@@ -81,7 +81,7 @@ export const AutoComplete = ({ initialValue, embedded, searchByPackage }: Props)
|
|
|
81
81
|
}, [query]);
|
|
82
82
|
|
|
83
83
|
return (
|
|
84
|
-
<div className="relative" ref={containerRef}>
|
|
84
|
+
<div className="relative flex-1" ref={containerRef}>
|
|
85
85
|
<Input
|
|
86
86
|
variant={embedded ? "embedded" : undefined}
|
|
87
87
|
type="text"
|
package/src/breadcrumb.tsx
CHANGED
|
@@ -1,15 +1,21 @@
|
|
|
1
1
|
import React, { FC, Fragment, ReactNode } from "react";
|
|
2
2
|
import {
|
|
3
3
|
Breadcrumb as BreadcrumbComponent,
|
|
4
|
+
BreadcrumbEllipsis,
|
|
4
5
|
BreadcrumbItem,
|
|
5
6
|
BreadcrumbLink,
|
|
6
7
|
BreadcrumbList,
|
|
7
8
|
BreadcrumbPage,
|
|
8
9
|
BreadcrumbSeparator
|
|
9
10
|
} from "@c-rex/ui/breadcrumb";
|
|
11
|
+
import { Button } from "@c-rex/ui/button";
|
|
12
|
+
import { Drawer, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerTitle, DrawerTrigger } from "@c-rex/ui/drawer";
|
|
10
13
|
import { Skeleton } from "@c-rex/ui/skeleton";
|
|
11
14
|
import { TreeOfContent } from "@c-rex/interfaces";
|
|
12
15
|
import { useTranslations } from 'next-intl';
|
|
16
|
+
import Link from "next/link"
|
|
17
|
+
import { useBreakpoint } from "@c-rex/ui/hooks"
|
|
18
|
+
import { DEVICE_OPTIONS } from "@c-rex/constants";
|
|
13
19
|
|
|
14
20
|
interface BreadcrumbProps {
|
|
15
21
|
items: TreeOfContent[];
|
|
@@ -19,9 +25,12 @@ interface BreadcrumbProps {
|
|
|
19
25
|
|
|
20
26
|
export const Breadcrumb: FC<BreadcrumbProps> = ({ items, loading, lang }) => {
|
|
21
27
|
const t = useTranslations("breadcrumbs");
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
28
|
+
const device = useBreakpoint();
|
|
29
|
+
const isMobile = (device === DEVICE_OPTIONS.MOBILE || device === DEVICE_OPTIONS.TABLET);
|
|
30
|
+
|
|
31
|
+
if (!items) return null
|
|
32
|
+
|
|
33
|
+
const lastItem = items[items.length - 1] as TreeOfContent;
|
|
25
34
|
|
|
26
35
|
if (loading) {
|
|
27
36
|
return (
|
|
@@ -43,15 +52,49 @@ export const Breadcrumb: FC<BreadcrumbProps> = ({ items, loading, lang }) => {
|
|
|
43
52
|
);
|
|
44
53
|
}
|
|
45
54
|
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
55
|
+
const renderDrawer = () => {
|
|
56
|
+
if (items.length < 2) return null
|
|
57
|
+
|
|
58
|
+
return (
|
|
59
|
+
<>
|
|
60
|
+
<BreadcrumbItem>
|
|
61
|
+
<Drawer>
|
|
62
|
+
<DrawerTrigger asChild>
|
|
63
|
+
<BreadcrumbEllipsis className="h-4 w-4" />
|
|
64
|
+
</DrawerTrigger>
|
|
65
|
+
<DrawerContent>
|
|
66
|
+
<DrawerHeader className="text-left">
|
|
67
|
+
<DrawerTitle>Navigate to</DrawerTitle>
|
|
68
|
+
<DrawerDescription>
|
|
69
|
+
Select a page to navigate to.
|
|
70
|
+
</DrawerDescription>
|
|
71
|
+
</DrawerHeader>
|
|
72
|
+
|
|
73
|
+
<div className="grid gap-1 px-4">
|
|
74
|
+
{items.slice(0, -1).map((item, index) => (
|
|
75
|
+
<Link
|
|
76
|
+
key={index}
|
|
77
|
+
href={item.link}
|
|
78
|
+
className="py-1 text-sm"
|
|
79
|
+
>
|
|
80
|
+
{item.label}
|
|
81
|
+
</Link>
|
|
82
|
+
))}
|
|
83
|
+
</div>
|
|
53
84
|
|
|
54
|
-
|
|
85
|
+
<DrawerFooter className="pt-4">
|
|
86
|
+
<DrawerClose asChild>
|
|
87
|
+
<Button variant="outline">Close</Button>
|
|
88
|
+
</DrawerClose>
|
|
89
|
+
</DrawerFooter>
|
|
90
|
+
</DrawerContent>
|
|
91
|
+
</Drawer>
|
|
92
|
+
</BreadcrumbItem>
|
|
93
|
+
<BreadcrumbSeparator />
|
|
94
|
+
</>
|
|
95
|
+
|
|
96
|
+
);
|
|
97
|
+
};
|
|
55
98
|
|
|
56
99
|
const renderLink = (showLink: boolean, item: TreeOfContent): ReactNode => {
|
|
57
100
|
if (showLink) {
|
|
@@ -62,22 +105,37 @@ export const Breadcrumb: FC<BreadcrumbProps> = ({ items, loading, lang }) => {
|
|
|
62
105
|
};
|
|
63
106
|
|
|
64
107
|
return (
|
|
65
|
-
<BreadcrumbComponent lang={lang}>
|
|
108
|
+
<BreadcrumbComponent lang={lang} className="hidden sm:block">
|
|
66
109
|
<BreadcrumbList>
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
110
|
+
<BreadcrumbItem>
|
|
111
|
+
<BreadcrumbLink asChild>
|
|
112
|
+
<BreadcrumbLink href="/">{t("home")}</BreadcrumbLink>
|
|
113
|
+
</BreadcrumbLink>
|
|
114
|
+
</BreadcrumbItem>
|
|
115
|
+
<BreadcrumbSeparator />
|
|
116
|
+
|
|
117
|
+
{isMobile ? renderDrawer() : (
|
|
118
|
+
<>
|
|
119
|
+
{items.slice(0, -1).map((item, index) => {
|
|
120
|
+
const isLast = index === items.length - 1;
|
|
121
|
+
|
|
122
|
+
return (
|
|
123
|
+
<Fragment key={`${item.label}-fragment`}>
|
|
124
|
+
<BreadcrumbItem key={`${item.label}-item`} className={index.toString()}>
|
|
125
|
+
{renderLink(!isLast, item)}
|
|
126
|
+
</BreadcrumbItem>
|
|
127
|
+
{!isLast && (
|
|
128
|
+
<BreadcrumbSeparator key={`${item.label}-separator`} />
|
|
129
|
+
)}
|
|
130
|
+
</Fragment>
|
|
131
|
+
);
|
|
132
|
+
})}
|
|
133
|
+
</>
|
|
134
|
+
)}
|
|
135
|
+
|
|
136
|
+
<BreadcrumbPage>
|
|
137
|
+
{renderLink(false, lastItem)}
|
|
138
|
+
</BreadcrumbPage>
|
|
81
139
|
</BreadcrumbList>
|
|
82
140
|
</BreadcrumbComponent>
|
|
83
141
|
);
|
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
import { FC, useEffect } from "react";
|
|
4
4
|
import { useAppConfig } from "@c-rex/contexts/config-provider";
|
|
5
|
-
import {
|
|
5
|
+
import { AvailableVersionsInterface } from "@c-rex/interfaces";
|
|
6
6
|
import { toast } from "sonner"
|
|
7
7
|
import { useTranslations } from "next-intl"
|
|
8
8
|
|
|
9
9
|
interface Props {
|
|
10
|
-
availableVersions:
|
|
10
|
+
availableVersions: AvailableVersionsInterface[]
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
export const CheckArticleLangToast: FC<Props> = ({ availableVersions }) => {
|
package/src/dialog-filter.tsx
CHANGED
|
@@ -113,7 +113,7 @@ export const DialogFilter: FC<DialogFilterProps> = ({ trigger }) => {
|
|
|
113
113
|
</DialogTrigger>
|
|
114
114
|
<DialogContent>
|
|
115
115
|
<DialogHeader>
|
|
116
|
-
<DialogTitle>{t("
|
|
116
|
+
<DialogTitle>{t("searchSettings")}</DialogTitle>
|
|
117
117
|
</DialogHeader>
|
|
118
118
|
|
|
119
119
|
<div className="grid grid-cols-2 items-center pt-2">
|
package/src/flag.tsx
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import React, { FC } from "react";
|
|
2
|
+
import * as Flags from 'country-flag-icons/react/3x2';
|
|
3
|
+
|
|
4
|
+
interface FlagProps {
|
|
5
|
+
countryCode: string;
|
|
6
|
+
}
|
|
7
|
+
export const Flag: FC<FlagProps> = ({ countryCode }) => {
|
|
8
|
+
|
|
9
|
+
type CountryCode = keyof typeof Flags;
|
|
10
|
+
const FlagComponent = Flags[countryCode as CountryCode];
|
|
11
|
+
|
|
12
|
+
if (!FlagComponent) return null;
|
|
13
|
+
|
|
14
|
+
return <FlagComponent />;
|
|
15
|
+
};
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { Card, CardContent, CardHeader, CardTitle } from "@c-rex/ui/card";
|
|
2
|
+
import { getFromCookieString } from "@c-rex/utils";
|
|
2
3
|
import { useTranslations } from "next-intl";
|
|
3
4
|
import React, { FC } from "react";
|
|
5
|
+
import { filteredItems, renderValue } from "./shared";
|
|
6
|
+
import { UI_LANG_KEY } from "@c-rex/constants";
|
|
4
7
|
|
|
5
8
|
type Props = {
|
|
6
9
|
title: string;
|
|
@@ -12,6 +15,8 @@ type Props = {
|
|
|
12
15
|
}
|
|
13
16
|
export const InfoCard: FC<Props> = ({ title, items }) => {
|
|
14
17
|
const t = useTranslations();
|
|
18
|
+
const uiLang = getFromCookieString(document.cookie, UI_LANG_KEY)
|
|
19
|
+
const newItems = filteredItems(items)
|
|
15
20
|
|
|
16
21
|
return (
|
|
17
22
|
<Card>
|
|
@@ -19,7 +24,7 @@ export const InfoCard: FC<Props> = ({ title, items }) => {
|
|
|
19
24
|
<CardTitle className="text-lg">{title}</CardTitle>
|
|
20
25
|
</CardHeader>
|
|
21
26
|
<CardContent className="space-y-3">
|
|
22
|
-
{
|
|
27
|
+
{newItems.map((item, index) => (
|
|
23
28
|
<div key={index} className="border-b border-blog-divider last:border-0 pb-3 last:pb-0">
|
|
24
29
|
{item.link ? (
|
|
25
30
|
<a href={item.link}>
|
|
@@ -29,7 +34,7 @@ export const InfoCard: FC<Props> = ({ title, items }) => {
|
|
|
29
34
|
<h4 className="text-sm font-medium mb-1">{t(item.label)}</h4>
|
|
30
35
|
)}
|
|
31
36
|
|
|
32
|
-
<span className="text-xs text-muted-foreground">{item
|
|
37
|
+
<span className="text-xs text-muted-foreground">{renderValue(item, uiLang)}</span>
|
|
33
38
|
</div>
|
|
34
39
|
))}
|
|
35
40
|
</CardContent>
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import React, { FC } from "react";
|
|
2
|
+
import { articleInfoItemType, DocumentsType } from "@c-rex/types";
|
|
3
|
+
import { Card, CardContent, CardHeader, CardTitle } from "@c-rex/ui/card";
|
|
4
|
+
import {
|
|
5
|
+
Table,
|
|
6
|
+
TableBody,
|
|
7
|
+
TableCell,
|
|
8
|
+
TableRow,
|
|
9
|
+
} from "@c-rex/ui/table"
|
|
10
|
+
import { useTranslations } from "next-intl";
|
|
11
|
+
import { getFromCookieString } from "@c-rex/utils";
|
|
12
|
+
import { UI_LANG_KEY } from "@c-rex/constants";
|
|
13
|
+
import { filteredItems, renderValue } from "./shared";
|
|
14
|
+
import {
|
|
15
|
+
DropdownMenu,
|
|
16
|
+
DropdownMenuContent,
|
|
17
|
+
DropdownMenuItem,
|
|
18
|
+
DropdownMenuTrigger,
|
|
19
|
+
} from "@c-rex/ui/dropdown-menu";
|
|
20
|
+
import { CloudDownload, Eye } from "lucide-react";
|
|
21
|
+
|
|
22
|
+
import { FaFilePdf } from "react-icons/fa6";
|
|
23
|
+
import { AvailableVersionsInterface } from "@c-rex/interfaces";
|
|
24
|
+
import { Flag } from "../flag";
|
|
25
|
+
|
|
26
|
+
type Props = {
|
|
27
|
+
title: string;
|
|
28
|
+
files?: DocumentsType
|
|
29
|
+
items: articleInfoItemType[]
|
|
30
|
+
availableVersions?: AvailableVersionsInterface[]
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const IconsToFileExtension: Record<string, React.ReactNode> = {
|
|
34
|
+
"application/pdf": <FaFilePdf className="h-6 w-6" />,
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export const InfoTable: FC<Props> = ({ title, items, files, availableVersions }) => {
|
|
38
|
+
const t = useTranslations();
|
|
39
|
+
const uiLang = getFromCookieString(document.cookie, UI_LANG_KEY)
|
|
40
|
+
const newItems = filteredItems(items)
|
|
41
|
+
|
|
42
|
+
return (
|
|
43
|
+
<Card className="p-0 !pt-4">
|
|
44
|
+
<CardHeader>
|
|
45
|
+
<CardTitle className="text-lg">{title}</CardTitle>
|
|
46
|
+
</CardHeader>
|
|
47
|
+
<CardContent className="space-y-3 !p-0">
|
|
48
|
+
<Table>
|
|
49
|
+
<TableBody>
|
|
50
|
+
{newItems.map((item, index) => (
|
|
51
|
+
<TableRow key={index} className="h-12">
|
|
52
|
+
<TableCell className="font-medium w-28 pl-4">
|
|
53
|
+
{item.link ? (
|
|
54
|
+
<a href={item.link} className="underline">
|
|
55
|
+
<h4 className="text-sm font-medium">{t(item.label)}</h4>
|
|
56
|
+
</a>
|
|
57
|
+
) : (
|
|
58
|
+
<h4 className="text-sm font-medium">{t(item.label)}</h4>
|
|
59
|
+
)}
|
|
60
|
+
</TableCell>
|
|
61
|
+
<TableCell className="text-xs text-muted-foreground flex items-center gap-2 h-12">
|
|
62
|
+
{renderValue(item, uiLang)}
|
|
63
|
+
</TableCell>
|
|
64
|
+
</TableRow>
|
|
65
|
+
))}
|
|
66
|
+
|
|
67
|
+
{files && (
|
|
68
|
+
<TableRow className="h-12">
|
|
69
|
+
<TableCell className="font-medium w-28 pl-4">
|
|
70
|
+
<h4 className="text-sm font-medium">{t("files")}</h4>
|
|
71
|
+
</TableCell>
|
|
72
|
+
<TableCell className="text-xs text-muted-foreground flex items-center gap-2 h-12">
|
|
73
|
+
|
|
74
|
+
{Object.keys(files).map((item, index) => {
|
|
75
|
+
if (!files[item]) return null
|
|
76
|
+
|
|
77
|
+
return (
|
|
78
|
+
<DropdownMenu key={index}>
|
|
79
|
+
<DropdownMenuTrigger className="mx-2">
|
|
80
|
+
{IconsToFileExtension[item]}
|
|
81
|
+
</DropdownMenuTrigger>
|
|
82
|
+
<DropdownMenuContent>
|
|
83
|
+
<DropdownMenuItem>
|
|
84
|
+
<a href={files[item].view} target="_blank" rel="noreferrer" className="flex items-center">
|
|
85
|
+
<Eye className="mr-2 " /> Open
|
|
86
|
+
</a>
|
|
87
|
+
</DropdownMenuItem>
|
|
88
|
+
<DropdownMenuItem>
|
|
89
|
+
<a href={files[item].download} target="_blank" rel="noreferrer" className="flex items-center">
|
|
90
|
+
<CloudDownload className="mr-2 " /> Download
|
|
91
|
+
</a>
|
|
92
|
+
</DropdownMenuItem>
|
|
93
|
+
|
|
94
|
+
</DropdownMenuContent>
|
|
95
|
+
</DropdownMenu>
|
|
96
|
+
)
|
|
97
|
+
})}
|
|
98
|
+
|
|
99
|
+
</TableCell>
|
|
100
|
+
</TableRow>
|
|
101
|
+
)}
|
|
102
|
+
|
|
103
|
+
{availableVersions && (
|
|
104
|
+
<TableRow className="h-12">
|
|
105
|
+
<TableCell className="font-medium w-28 pl-4">
|
|
106
|
+
<h4 className="text-sm font-medium">{t("availableIn")}</h4>
|
|
107
|
+
</TableCell>
|
|
108
|
+
<TableCell className="text-xs text-muted-foreground flex items-center gap-2 h-12">
|
|
109
|
+
{availableVersions.map((item) => {
|
|
110
|
+
return (
|
|
111
|
+
<span className="w-8 block border" key={item.shortId}>
|
|
112
|
+
<a href={item.link} title={item.lang}>
|
|
113
|
+
<Flag countryCode={item.country} />
|
|
114
|
+
</a>
|
|
115
|
+
</span>
|
|
116
|
+
)
|
|
117
|
+
})}
|
|
118
|
+
</TableCell>
|
|
119
|
+
</TableRow>
|
|
120
|
+
)}
|
|
121
|
+
|
|
122
|
+
</TableBody>
|
|
123
|
+
</Table>
|
|
124
|
+
</CardContent>
|
|
125
|
+
</Card>
|
|
126
|
+
);
|
|
127
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import React, { ReactNode } from "react";
|
|
2
|
+
import { articleInfoItemType } from "@c-rex/types";
|
|
3
|
+
import { formatDateToLocale } from "@c-rex/utils";
|
|
4
|
+
import { Flag } from "../flag";
|
|
5
|
+
|
|
6
|
+
const isDate = (value: string): boolean => {
|
|
7
|
+
return (/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})$/.test(value))
|
|
8
|
+
}
|
|
9
|
+
const isLanguage = (label: string): boolean => {
|
|
10
|
+
return label === "language" || label === "languages";
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export const renderValue = (item: articleInfoItemType, uiLang: string): ReactNode => {
|
|
14
|
+
if (isDate(item.value)) return formatDateToLocale(item.value, uiLang);
|
|
15
|
+
|
|
16
|
+
if (isLanguage(item.label)) {
|
|
17
|
+
const countryCode = item.value.split("-")[1] || item.value;
|
|
18
|
+
return (
|
|
19
|
+
<span className="w-8 block">
|
|
20
|
+
<Flag countryCode={countryCode} />
|
|
21
|
+
</span>
|
|
22
|
+
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return item.value;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export const filteredItems = (items: articleInfoItemType[]): articleInfoItemType[] => {
|
|
30
|
+
const hasTitle = items.some(item => item.label === "titles");
|
|
31
|
+
return items.filter(item => (hasTitle ? !(item.label == "labels") : true));
|
|
32
|
+
}
|
|
@@ -4,9 +4,7 @@ import React, { ComponentProps, JSX } from "react";
|
|
|
4
4
|
import {
|
|
5
5
|
Sidebar,
|
|
6
6
|
SidebarContent,
|
|
7
|
-
SidebarFooter,
|
|
8
7
|
SidebarGroup,
|
|
9
|
-
SidebarGroupLabel,
|
|
10
8
|
SidebarMenu,
|
|
11
9
|
SidebarMenuButton,
|
|
12
10
|
SidebarMenuItem,
|
|
@@ -15,28 +13,18 @@ import {
|
|
|
15
13
|
SidebarMenuSubItem,
|
|
16
14
|
} from "@c-rex/ui/sidebar";
|
|
17
15
|
import { Skeleton } from "@c-rex/ui/skeleton";
|
|
18
|
-
import {
|
|
19
|
-
import * as Flags from 'country-flag-icons/react/3x2';
|
|
16
|
+
import { TreeOfContent } from "@c-rex/interfaces";
|
|
20
17
|
import { useTranslations } from "next-intl";
|
|
21
18
|
import { cn } from "@c-rex/utils";
|
|
22
19
|
|
|
23
20
|
interface SidebarProps extends ComponentProps<typeof Sidebar> {
|
|
24
21
|
data: TreeOfContent[];
|
|
25
22
|
loading?: boolean;
|
|
26
|
-
availableVersions: SidebarAvailableVersionsInterface[]
|
|
27
23
|
}
|
|
28
24
|
|
|
29
|
-
export function
|
|
25
|
+
export function LeftSidebar({ data, loading, className, lang, ...props }: SidebarProps) {
|
|
30
26
|
const t = useTranslations();
|
|
31
27
|
|
|
32
|
-
const getFlagIcon = (countryCode: string): JSX.Element | null => {
|
|
33
|
-
type CountryCode = keyof typeof Flags;
|
|
34
|
-
const FlagComponent = Flags[countryCode as CountryCode];
|
|
35
|
-
if (!FlagComponent) return null;
|
|
36
|
-
|
|
37
|
-
return <FlagComponent />;
|
|
38
|
-
};
|
|
39
|
-
|
|
40
28
|
const tableOfContentGroup = (): JSX.Element | null => {
|
|
41
29
|
if (loading) {
|
|
42
30
|
return (
|
|
@@ -94,39 +82,11 @@ export function AppSidebar({ data, availableVersions, loading, className, lang,
|
|
|
94
82
|
);
|
|
95
83
|
}
|
|
96
84
|
|
|
97
|
-
const availableVersionsGroup = (): JSX.Element | null => {
|
|
98
|
-
|
|
99
|
-
if (availableVersions.length == 0) return null;
|
|
100
|
-
|
|
101
|
-
return (
|
|
102
|
-
<>
|
|
103
|
-
<SidebarGroupLabel>{t("availableIn")}:</SidebarGroupLabel>
|
|
104
|
-
<SidebarMenu>
|
|
105
|
-
{availableVersions.map((item) => {
|
|
106
|
-
return (
|
|
107
|
-
<SidebarMenuItem key={item.shortId}>
|
|
108
|
-
<SidebarMenuButton asChild isActive={item.active}>
|
|
109
|
-
<a href={item.link} title={item.lang}>
|
|
110
|
-
{getFlagIcon(item.country)} {item.lang}
|
|
111
|
-
</a>
|
|
112
|
-
</SidebarMenuButton>
|
|
113
|
-
</SidebarMenuItem>
|
|
114
|
-
)
|
|
115
|
-
})}
|
|
116
|
-
</SidebarMenu>
|
|
117
|
-
</>
|
|
118
|
-
)
|
|
119
|
-
|
|
120
|
-
}
|
|
121
|
-
|
|
122
85
|
return (
|
|
123
|
-
<Sidebar className={cn(className
|
|
86
|
+
<Sidebar className={cn(className)} {...props}>
|
|
124
87
|
<SidebarContent>
|
|
125
88
|
{tableOfContentGroup()}
|
|
126
89
|
</SidebarContent>
|
|
127
|
-
<SidebarFooter>
|
|
128
|
-
{availableVersionsGroup()}
|
|
129
|
-
</SidebarFooter>
|
|
130
90
|
</Sidebar>
|
|
131
91
|
);
|
|
132
92
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import React, { FC
|
|
2
|
-
import * as Flags from 'country-flag-icons/react/3x2';
|
|
1
|
+
import React, { FC } from "react";
|
|
3
2
|
import { LanguageAndCountries } from "@c-rex/interfaces";
|
|
4
3
|
import { DropdownMenuRadioGroup, DropdownMenuRadioItem } from "@c-rex/ui/dropdown-menu";
|
|
4
|
+
import { Flag } from "../../flag";
|
|
5
5
|
|
|
6
6
|
interface SharedLanguageSwitchProps {
|
|
7
7
|
availableLanguagesAndCountries: (LanguageAndCountries & { link?: string })[];
|
|
@@ -10,14 +10,6 @@ interface SharedLanguageSwitchProps {
|
|
|
10
10
|
}
|
|
11
11
|
export const SharedLanguageSwitch: FC<SharedLanguageSwitchProps> = ({ availableLanguagesAndCountries, changeLanguage, selected }) => {
|
|
12
12
|
|
|
13
|
-
const getFlagIcon = (countryCode: string): JSX.Element | null => {
|
|
14
|
-
type CountryCode = keyof typeof Flags;
|
|
15
|
-
const FlagComponent = Flags[countryCode as CountryCode];
|
|
16
|
-
if (!FlagComponent) return null;
|
|
17
|
-
|
|
18
|
-
return <FlagComponent />;
|
|
19
|
-
};
|
|
20
|
-
|
|
21
13
|
return (
|
|
22
14
|
<DropdownMenuRadioGroup value={selected}>
|
|
23
15
|
{availableLanguagesAndCountries.map(item => {
|
|
@@ -31,7 +23,7 @@ export const SharedLanguageSwitch: FC<SharedLanguageSwitchProps> = ({ availableL
|
|
|
31
23
|
changeLanguage(item.value)
|
|
32
24
|
}}
|
|
33
25
|
>
|
|
34
|
-
{
|
|
26
|
+
<Flag countryCode={item.country} />
|
|
35
27
|
<span>{item.lang.toUpperCase()}</span>
|
|
36
28
|
</DropdownMenuRadioItem>
|
|
37
29
|
)
|
package/src/navbar/navbar.tsx
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { FC } from "react";
|
|
2
2
|
import Link from "next/link";
|
|
3
|
-
import Image from "next/image";
|
|
4
3
|
import { SignInBtn } from "./sign-in-out-btns";
|
|
5
4
|
import { getServerSession } from "next-auth";
|
|
6
5
|
import { getConfigs } from "@c-rex/utils/next-cookies";
|
|
@@ -23,43 +22,46 @@ export const NavBar: FC<NavBarProps> = async ({ title, showInput, showPkgFilter
|
|
|
23
22
|
}
|
|
24
23
|
|
|
25
24
|
return (
|
|
26
|
-
<header className="sticky top-0 z-40
|
|
27
|
-
<div className="
|
|
28
|
-
<
|
|
29
|
-
<
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
/>
|
|
36
|
-
</Link>
|
|
25
|
+
<header className="sticky flex flex-wrap sm:flex-nowrap justify-between sm:items-center top-0 z-40 w-full p-4 backdrop-blur-xl transition-all bg-transparent border-b">
|
|
26
|
+
<div className="flex gap-2">
|
|
27
|
+
<Link href="/" className="flex items-center w-24 lg:w-60">
|
|
28
|
+
<img
|
|
29
|
+
src="/img/logo.png"
|
|
30
|
+
alt="C-rex Logo"
|
|
31
|
+
className="max-h-14"
|
|
32
|
+
/>
|
|
33
|
+
</Link>
|
|
37
34
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
35
|
+
{title.length > 0 && (
|
|
36
|
+
<div className="hidden sm:flex items-center">
|
|
37
|
+
<h1 className="mt-4 sm:mt-0 sm:px-4 lg:px-0 text-xl sm:text-2xl md:text-3xl font-bold tracking-tight text-balance">{title}</h1>
|
|
38
|
+
</div>
|
|
39
|
+
)}
|
|
40
|
+
</div>
|
|
44
41
|
|
|
45
|
-
|
|
46
|
-
|
|
42
|
+
<div className="flex items-center gap-2 absolute sm:static top-4 h-14 sm:h-min right-4">
|
|
43
|
+
<SearchInput showInput={showInput} showPkgFilter={showPkgFilter} placedOn="NAVBAR" />
|
|
47
44
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
45
|
+
{configs.OIDC.user.enabled && (
|
|
46
|
+
<>
|
|
47
|
+
{session ? (
|
|
48
|
+
<UserMenu session={session} />
|
|
49
|
+
) : (
|
|
50
|
+
<SignInBtn />
|
|
51
|
+
)}
|
|
52
|
+
</>
|
|
53
|
+
)}
|
|
57
54
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
</div>
|
|
55
|
+
{configs.languageSwitcher.enabled && (
|
|
56
|
+
<SettingsMenu />
|
|
57
|
+
)}
|
|
62
58
|
</div>
|
|
59
|
+
|
|
60
|
+
{title.length > 0 && (
|
|
61
|
+
<div className="flex w-full sm:hidden items-center">
|
|
62
|
+
<h1 className="mt-4 sm:mt-0 sm:px-4 text-xl sm:text-2xl md:text-3xl font-bold tracking-tight text-balance">{title}</h1>
|
|
63
|
+
</div>
|
|
64
|
+
)}
|
|
63
65
|
</header>
|
|
64
66
|
);
|
|
65
67
|
};
|
|
@@ -4,20 +4,25 @@ import React, { FC, useState } from "react";
|
|
|
4
4
|
import { FileCheck, FileX, Search } from "lucide-react";
|
|
5
5
|
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@c-rex/ui/tooltip";
|
|
6
6
|
import { AutoComplete } from "../autocomplete";
|
|
7
|
+
import { cn } from "@c-rex/utils";
|
|
7
8
|
|
|
9
|
+
type PlacedOn = "NAVBAR" | "BODY"
|
|
8
10
|
type Props = {
|
|
9
11
|
showInput: boolean
|
|
10
12
|
showPkgFilter: boolean
|
|
13
|
+
placedOn?: PlacedOn
|
|
11
14
|
}
|
|
12
|
-
|
|
15
|
+
|
|
16
|
+
export const SearchInput: FC<Props> = ({ showInput, showPkgFilter, placedOn = "NAVBAR" }) => {
|
|
13
17
|
const [checked, setChecked] = useState<boolean>(true);
|
|
14
18
|
|
|
15
|
-
if (!showInput)
|
|
16
|
-
return null;
|
|
17
|
-
}
|
|
19
|
+
if (!showInput) return null
|
|
18
20
|
|
|
19
21
|
return (
|
|
20
|
-
<div className=
|
|
22
|
+
<div className={cn(
|
|
23
|
+
placedOn === "NAVBAR" ? "hidden lg:flex" : "sm:flex-none sm:w-60 md:w-72 lg:w-full lg:hidden flex",
|
|
24
|
+
"flex-1 items-center px-3 border rounded-full h-8"
|
|
25
|
+
)}>
|
|
21
26
|
<Search className="h-4 w-4 shrink-0 opacity-50" />
|
|
22
27
|
|
|
23
28
|
<AutoComplete
|
package/src/navbar/settings.tsx
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client"
|
|
2
2
|
|
|
3
3
|
import React from "react";
|
|
4
|
-
import {
|
|
4
|
+
import { signIn } from "next-auth/react";
|
|
5
5
|
import { Button } from "@c-rex/ui/button";
|
|
6
6
|
import { useTranslations } from "next-intl";
|
|
7
7
|
|
|
@@ -19,18 +19,3 @@ export const SignInBtn = () => {
|
|
|
19
19
|
</Button>
|
|
20
20
|
);
|
|
21
21
|
}
|
|
22
|
-
|
|
23
|
-
export const SignOut = () => {
|
|
24
|
-
const t = useTranslations("user")
|
|
25
|
-
return (
|
|
26
|
-
<Button
|
|
27
|
-
className="gap-2 px-5 md:flex"
|
|
28
|
-
variant="default"
|
|
29
|
-
size="sm"
|
|
30
|
-
rounded="full"
|
|
31
|
-
onClick={() => signOut()}
|
|
32
|
-
>
|
|
33
|
-
<span>{t("signOut")}</span>
|
|
34
|
-
</Button>
|
|
35
|
-
);
|
|
36
|
-
}
|
package/src/page-wrapper.tsx
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { NavBar } from './navbar/navbar';
|
|
3
|
+
import { MultiSidebarProvider } from "@c-rex/ui/sidebar";
|
|
3
4
|
|
|
4
5
|
type Props = {
|
|
5
6
|
children: React.ReactNode;
|
|
@@ -12,13 +13,13 @@ export const PageWrapper = ({ children, title, pageType }: Props) => {
|
|
|
12
13
|
const showPkgFilter = pageType === "DOC"
|
|
13
14
|
|
|
14
15
|
return (
|
|
15
|
-
|
|
16
|
+
<MultiSidebarProvider>
|
|
16
17
|
<NavBar
|
|
17
18
|
title={title}
|
|
18
19
|
showInput={showInput}
|
|
19
20
|
showPkgFilter={showPkgFilter}
|
|
20
21
|
/>
|
|
21
22
|
{children}
|
|
22
|
-
|
|
23
|
+
</MultiSidebarProvider>
|
|
23
24
|
);
|
|
24
25
|
}
|
package/src/result-list.tsx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { FC } from "react";
|
|
2
|
-
import { DefaultPageInfo, informationUnitsResponseItem, } from "@c-rex/interfaces";
|
|
2
|
+
import { DefaultPageInfo, informationUnitsResponseItem, TopicsResponseItem, } from "@c-rex/interfaces";
|
|
3
3
|
import { Empty } from "./empty";
|
|
4
4
|
import BlogView from './result-view/blog';
|
|
5
5
|
import TableView from './result-view/table';
|
|
@@ -7,25 +7,31 @@ import { Pagination } from "./pagination";
|
|
|
7
7
|
import { useAppConfig } from "@c-rex/contexts/config-provider";
|
|
8
8
|
|
|
9
9
|
interface ResultListProps {
|
|
10
|
-
items: informationUnitsResponseItem[];
|
|
10
|
+
items: informationUnitsResponseItem[] | TopicsResponseItem[];
|
|
11
11
|
pagination: DefaultPageInfo;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
export const ResultList: FC<ResultListProps> = ({ items, pagination }: ResultListProps) => {
|
|
15
15
|
const { configs } = useAppConfig()
|
|
16
16
|
|
|
17
|
-
const
|
|
17
|
+
const isTableView = configs.results.resultViewStyle === "table";
|
|
18
18
|
|
|
19
19
|
return (
|
|
20
20
|
<>
|
|
21
21
|
{
|
|
22
|
-
items.length
|
|
22
|
+
items.length === 0 ? (
|
|
23
23
|
<Empty />
|
|
24
24
|
) : (
|
|
25
25
|
<>
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
{isTableView ? (
|
|
27
|
+
<TableView
|
|
28
|
+
items={items as informationUnitsResponseItem[]}
|
|
29
|
+
/>
|
|
30
|
+
) : (
|
|
31
|
+
<BlogView
|
|
32
|
+
items={items as TopicsResponseItem[]}
|
|
33
|
+
/>
|
|
34
|
+
)}
|
|
29
35
|
|
|
30
36
|
<Pagination
|
|
31
37
|
totalPages={pagination.pageCount}
|
|
@@ -1,80 +1,100 @@
|
|
|
1
1
|
import { FC } from "react";
|
|
2
|
-
import {
|
|
3
|
-
Table,
|
|
4
|
-
TableBody,
|
|
5
|
-
TableCell,
|
|
6
|
-
TableHeader,
|
|
7
|
-
TableRow,
|
|
8
|
-
} from "@c-rex/ui/table";
|
|
9
2
|
import { informationUnitsResponseItem } from "@c-rex/interfaces";
|
|
10
3
|
import { useTranslations } from "next-intl";
|
|
11
|
-
import { Ban, CloudDownload,
|
|
12
|
-
import {
|
|
4
|
+
import { Ban, CloudDownload, Eye } from "lucide-react";
|
|
5
|
+
import { FaFilePdf } from "react-icons/fa6";
|
|
6
|
+
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@c-rex/ui/dropdown-menu";
|
|
7
|
+
import { cn } from "@c-rex/utils";
|
|
8
|
+
import { Flag } from "../flag";
|
|
9
|
+
import { Badge } from "@c-rex/ui/badge";
|
|
13
10
|
|
|
14
11
|
interface TableViewProps {
|
|
15
12
|
items: informationUnitsResponseItem[];
|
|
16
13
|
}
|
|
17
14
|
|
|
15
|
+
|
|
16
|
+
const IconsToFileExtension: Record<string, React.ReactNode> = {
|
|
17
|
+
"application/pdf": <FaFilePdf className="h-6 w-6" />,
|
|
18
|
+
};
|
|
19
|
+
|
|
18
20
|
const TableView: FC<TableViewProps> = ({ items }) => {
|
|
19
21
|
const t = useTranslations("results")
|
|
22
|
+
|
|
20
23
|
return (
|
|
21
|
-
<div className="rounded-md border">
|
|
22
|
-
<
|
|
23
|
-
<
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
24
|
+
<div className="rounded-md border mb-6 last:border-b-0">
|
|
25
|
+
<div className="font-bold text-sm p-2 border-b items-center flex-wrap hidden md:flex">
|
|
26
|
+
<div className="w-1/2 md:w-2/5 p-2">{t("title")}</div>
|
|
27
|
+
<div className="w-1/2 md:w-1/5 p-2 flex justify-center">{t("language")}</div>
|
|
28
|
+
<div className="w-1/2 md:w-1/5 p-2">{t("type")}</div>
|
|
29
|
+
<div className="w-1/2 md:w-1/5 p-2 flex justify-center">{t("files")}</div>
|
|
30
|
+
</div>
|
|
31
|
+
|
|
32
|
+
{items.map((item, index) => (
|
|
33
|
+
<div
|
|
34
|
+
className={cn(
|
|
35
|
+
"min-h-12 c-rex_result_row flex flex-wrap items-center",
|
|
36
|
+
`c-rex_result_${item.type.toLowerCase()}`,
|
|
37
|
+
item.disabled && "c-rex_result_item_disabled",
|
|
38
|
+
"border-b"
|
|
39
|
+
)}
|
|
40
|
+
key={index}
|
|
41
|
+
>
|
|
42
|
+
<div className="w-4/5 md:w-2/5 p-2">
|
|
43
|
+
{item.disabled ? (item.title) : (<a href={item.link}>{item.title}</a>)}
|
|
44
|
+
</div>
|
|
45
|
+
|
|
46
|
+
<div className="w-1/5 md:w-1/5 flex justify-center p-2">
|
|
47
|
+
<span className="w-8 inline-block">
|
|
48
|
+
{item.language.split("-").length > 1 && (
|
|
49
|
+
<Flag countryCode={item.language.split("-")[1] as string} />
|
|
50
|
+
)}
|
|
51
|
+
</span>
|
|
52
|
+
</div>
|
|
53
|
+
|
|
54
|
+
<div className="w-4/5 md:w-1/5 p-2">
|
|
55
|
+
<Badge variant="secondary">
|
|
56
|
+
{item.type}
|
|
57
|
+
</Badge>
|
|
58
|
+
</div>
|
|
59
|
+
|
|
60
|
+
<div className="w-1/5 flex justify-center p-2">
|
|
61
|
+
{(item.disabled || (Object.keys(item.files).length === 0)) ? (
|
|
62
|
+
<Ban />
|
|
63
|
+
) : (
|
|
64
|
+
<>
|
|
65
|
+
{Object.keys(item.files).map((fileKey, index) => {
|
|
66
|
+
|
|
67
|
+
if (!item.files[fileKey]) {
|
|
68
|
+
return null
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return (
|
|
72
|
+
<DropdownMenu key={index}>
|
|
73
|
+
<DropdownMenuTrigger className="mx-2">
|
|
74
|
+
{IconsToFileExtension[fileKey]}
|
|
75
|
+
</DropdownMenuTrigger>
|
|
76
|
+
<DropdownMenuContent>
|
|
77
|
+
<DropdownMenuItem>
|
|
78
|
+
<a href={item.files[fileKey].view} target="_blank" rel="noreferrer" className="flex items-center">
|
|
79
|
+
<Eye className="mr-2 " /> Open
|
|
80
|
+
</a>
|
|
81
|
+
</DropdownMenuItem>
|
|
82
|
+
<DropdownMenuItem>
|
|
83
|
+
<a href={item.files[fileKey].download} target="_blank" rel="noreferrer" className="flex items-center">
|
|
84
|
+
<CloudDownload className="mr-2 " /> Download
|
|
85
|
+
</a>
|
|
86
|
+
</DropdownMenuItem>
|
|
87
|
+
</DropdownMenuContent>
|
|
88
|
+
</DropdownMenu>
|
|
89
|
+
)
|
|
90
|
+
})}
|
|
91
|
+
</>
|
|
92
|
+
)}
|
|
34
93
|
|
|
35
|
-
|
|
36
|
-
<TableRow key={index} className={clazz}>
|
|
37
|
-
<TableCell className="h-12 c-rex_result_cell">
|
|
38
|
-
{item.disabled ? (item.title) : (<a href={item.link}>{item.title}</a>)}
|
|
39
|
-
</TableCell>
|
|
40
|
-
<TableCell>{item.type}</TableCell>
|
|
41
|
-
<TableCell>{item.language}</TableCell>
|
|
42
|
-
<TableCell>
|
|
43
|
-
{(item.disabled || (item.filesToDownload.length == 0 && item.filesToOpen.length == 0)) ? (
|
|
44
|
-
<button disabled className="mx-2">
|
|
45
|
-
<Ban />
|
|
46
|
-
</button>
|
|
47
|
-
) : (
|
|
48
|
-
<>
|
|
49
|
-
{item.filesToDownload.length == 0 ? (
|
|
50
|
-
<button disabled className="mx-2">
|
|
51
|
-
<CloudOff />
|
|
52
|
-
</button>
|
|
53
|
-
) : (
|
|
54
|
-
<DropdownMenu
|
|
55
|
-
items={item.filesToDownload}
|
|
56
|
-
icon={<CloudDownload />}
|
|
57
|
-
/>
|
|
58
|
-
)}
|
|
94
|
+
</div>
|
|
59
95
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
<EyeOff />
|
|
63
|
-
</button>
|
|
64
|
-
) : (
|
|
65
|
-
<DropdownMenu
|
|
66
|
-
items={item.filesToOpen}
|
|
67
|
-
icon={<Eye />}
|
|
68
|
-
/>
|
|
69
|
-
)}
|
|
70
|
-
</>
|
|
71
|
-
)}
|
|
72
|
-
</TableCell>
|
|
73
|
-
</TableRow>
|
|
74
|
-
)
|
|
75
|
-
})}
|
|
76
|
-
</TableBody>
|
|
77
|
-
</Table>
|
|
96
|
+
</div>
|
|
97
|
+
))}
|
|
78
98
|
</div>
|
|
79
99
|
);
|
|
80
100
|
};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import React, { ComponentProps } from "react";
|
|
4
|
+
import {
|
|
5
|
+
Sidebar,
|
|
6
|
+
SidebarContent,
|
|
7
|
+
} from "@c-rex/ui/sidebar";
|
|
8
|
+
import { useTranslations } from "next-intl";
|
|
9
|
+
import { cn } from "@c-rex/utils";
|
|
10
|
+
import { articleInfoItemType, DocumentsType } from "@c-rex/types";
|
|
11
|
+
import { InfoTable } from "./info/info-table";
|
|
12
|
+
import { AvailableVersionsInterface } from "@c-rex/interfaces";
|
|
13
|
+
|
|
14
|
+
interface SidebarProps extends ComponentProps<typeof Sidebar> {
|
|
15
|
+
articleInfo: articleInfoItemType[],
|
|
16
|
+
documentInfo: articleInfoItemType[],
|
|
17
|
+
files: DocumentsType,
|
|
18
|
+
availableVersions?: AvailableVersionsInterface[]
|
|
19
|
+
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function RightSidebar({ articleInfo, documentInfo, className, files, availableVersions, ...props }: SidebarProps) {
|
|
23
|
+
const t = useTranslations();
|
|
24
|
+
|
|
25
|
+
return (
|
|
26
|
+
<Sidebar className={cn(className)} {...props} side="right">
|
|
27
|
+
<SidebarContent className="p-2">
|
|
28
|
+
{(articleInfo.length > 0 || documentInfo.length > 0) && (
|
|
29
|
+
<div className=" gap-4 flex flex-col">
|
|
30
|
+
|
|
31
|
+
{documentInfo.length > 0 && (
|
|
32
|
+
<InfoTable
|
|
33
|
+
title={t("aboutDocument")}
|
|
34
|
+
items={documentInfo}
|
|
35
|
+
files={files}
|
|
36
|
+
/>
|
|
37
|
+
)}
|
|
38
|
+
|
|
39
|
+
{articleInfo.length > 0 && (
|
|
40
|
+
<InfoTable
|
|
41
|
+
title={t("aboutArticle")}
|
|
42
|
+
items={articleInfo}
|
|
43
|
+
availableVersions={availableVersions}
|
|
44
|
+
/>
|
|
45
|
+
)}
|
|
46
|
+
|
|
47
|
+
</div>
|
|
48
|
+
)}
|
|
49
|
+
</SidebarContent>
|
|
50
|
+
</Sidebar>
|
|
51
|
+
);
|
|
52
|
+
}
|