@c-rex/components 0.1.25 → 0.1.28
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 +23 -11
- package/src/autocomplete.tsx +3 -1
- package/src/breadcrumb.tsx +6 -26
- package/src/directoryNodes/tree-of-content.tsx +45 -27
- package/src/documents/result-list.tsx +137 -0
- package/src/favorites/bookmark-button.tsx +17 -14
- package/src/generated/create-client-request.tsx +1 -2
- package/src/generated/create-server-request.tsx +2 -2
- package/src/icons/loading.tsx +2 -2
- package/src/info/info-table.tsx +3 -2
- package/src/results/generic/table-result-list.tsx +96 -0
- package/src/results/table-with-images.tsx +17 -16
- package/src/search-input.tsx +9 -4
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@c-rex/components",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.28",
|
|
4
4
|
"files": [
|
|
5
5
|
"src"
|
|
6
6
|
],
|
|
@@ -46,8 +46,8 @@
|
|
|
46
46
|
"import": "./src/icons/flag-icon.tsx"
|
|
47
47
|
},
|
|
48
48
|
"./loading": {
|
|
49
|
-
"types": "./src/loading.tsx",
|
|
50
|
-
"import": "./src/loading.tsx"
|
|
49
|
+
"types": "./src/icons/loading.tsx",
|
|
50
|
+
"import": "./src/icons/loading.tsx"
|
|
51
51
|
},
|
|
52
52
|
"./info-table": {
|
|
53
53
|
"types": "./src/info/info-table.tsx",
|
|
@@ -81,14 +81,6 @@
|
|
|
81
81
|
"types": "./src/result-container.tsx",
|
|
82
82
|
"import": "./src/result-container.tsx"
|
|
83
83
|
},
|
|
84
|
-
"./table": {
|
|
85
|
-
"types": "./src/results/table.tsx",
|
|
86
|
-
"import": "./src/results/table.tsx"
|
|
87
|
-
},
|
|
88
|
-
"./table-with-images": {
|
|
89
|
-
"types": "./src/results/table-with-images.tsx",
|
|
90
|
-
"import": "./src/results/table-with-images.tsx"
|
|
91
|
-
},
|
|
92
84
|
"./dialog-filter": {
|
|
93
85
|
"types": "./src/results/dialog-filter.tsx",
|
|
94
86
|
"import": "./src/results/dialog-filter.tsx"
|
|
@@ -144,6 +136,26 @@
|
|
|
144
136
|
"./image-container": {
|
|
145
137
|
"types": "./src/renditions/image/container.tsx",
|
|
146
138
|
"import": "./src/renditions/image/container.tsx"
|
|
139
|
+
},
|
|
140
|
+
"./image-rendition": {
|
|
141
|
+
"types": "./src/renditions/image/rendition.tsx",
|
|
142
|
+
"import": "./src/renditions/image/rendition.tsx"
|
|
143
|
+
},
|
|
144
|
+
"./server-image-rendition": {
|
|
145
|
+
"types": "./src/renditions/image/server-image-rendition.tsx",
|
|
146
|
+
"import": "./src/renditions/image/server-image-rendition.tsx"
|
|
147
|
+
},
|
|
148
|
+
"./article-skeleton": {
|
|
149
|
+
"types": "./src/article/article-skeleton.tsx",
|
|
150
|
+
"import": "./src/article/article-skeleton.tsx"
|
|
151
|
+
},
|
|
152
|
+
"./documents-result-list": {
|
|
153
|
+
"types": "./src/documents/result-list.tsx",
|
|
154
|
+
"import": "./src/documents/result-list.tsx"
|
|
155
|
+
},
|
|
156
|
+
"./generic-table-result-list": {
|
|
157
|
+
"types": "./src/results/generic/table-result-list.tsx",
|
|
158
|
+
"import": "./src/results/generic/table-result-list.tsx"
|
|
147
159
|
}
|
|
148
160
|
},
|
|
149
161
|
"scripts": {
|
package/src/autocomplete.tsx
CHANGED
|
@@ -16,6 +16,7 @@ export type AutoCompleteProps = {
|
|
|
16
16
|
endpoint: string;
|
|
17
17
|
queryParams?: SuggestionQueryParams
|
|
18
18
|
onSelectParams?: { key: string, value: string }[];
|
|
19
|
+
onSelectPath: string
|
|
19
20
|
};
|
|
20
21
|
|
|
21
22
|
export const AutoComplete = ({
|
|
@@ -24,6 +25,7 @@ export const AutoComplete = ({
|
|
|
24
25
|
endpoint,
|
|
25
26
|
queryParams,
|
|
26
27
|
onSelectParams,
|
|
28
|
+
onSelectPath = "/"
|
|
27
29
|
}: AutoCompleteProps) => {
|
|
28
30
|
const t = useTranslations();
|
|
29
31
|
const containerRef = useRef<HTMLDivElement>(null);
|
|
@@ -62,7 +64,7 @@ export const AutoComplete = ({
|
|
|
62
64
|
params.set(param.key, param.value);
|
|
63
65
|
});
|
|
64
66
|
|
|
65
|
-
router.push(
|
|
67
|
+
router.push(`${onSelectPath}?${params.toString()}`);
|
|
66
68
|
};
|
|
67
69
|
|
|
68
70
|
useEffect(() => {
|
package/src/breadcrumb.tsx
CHANGED
|
@@ -12,21 +12,21 @@ import {
|
|
|
12
12
|
} from "@c-rex/ui/breadcrumb";
|
|
13
13
|
import { Button } from "@c-rex/ui/button";
|
|
14
14
|
import { Drawer, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerTitle, DrawerTrigger } from "@c-rex/ui/drawer";
|
|
15
|
-
import { Skeleton } from "@c-rex/ui/skeleton";
|
|
16
15
|
import { TreeOfContent } from "@c-rex/interfaces";
|
|
17
16
|
import { useTranslations } from 'next-intl';
|
|
18
17
|
import Link from "next/link"
|
|
19
18
|
import { useBreakpoint } from "@c-rex/ui/hooks"
|
|
20
19
|
import { DEVICE_OPTIONS } from "@c-rex/constants";
|
|
20
|
+
import { generateBreadcrumbItems } from "@c-rex/utils";
|
|
21
21
|
|
|
22
22
|
interface BreadcrumbProps {
|
|
23
|
-
|
|
23
|
+
tree: TreeOfContent[];
|
|
24
24
|
lang: string;
|
|
25
|
-
loading?: boolean;
|
|
26
25
|
}
|
|
27
26
|
|
|
28
|
-
export const Breadcrumb: FC<BreadcrumbProps> = ({
|
|
27
|
+
export const Breadcrumb: FC<BreadcrumbProps> = ({ tree, lang }) => {
|
|
29
28
|
const t = useTranslations("breadcrumbs");
|
|
29
|
+
const items = generateBreadcrumbItems(tree);
|
|
30
30
|
const device = useBreakpoint();
|
|
31
31
|
const isMobile = device !== null && (device === DEVICE_OPTIONS.MOBILE || device === DEVICE_OPTIONS.TABLET);
|
|
32
32
|
|
|
@@ -34,26 +34,6 @@ export const Breadcrumb: FC<BreadcrumbProps> = ({ items, loading, lang }) => {
|
|
|
34
34
|
|
|
35
35
|
const lastItem = items[items.length - 1] as TreeOfContent;
|
|
36
36
|
|
|
37
|
-
if (loading) {
|
|
38
|
-
return (
|
|
39
|
-
<BreadcrumbComponent>
|
|
40
|
-
<BreadcrumbList>
|
|
41
|
-
<BreadcrumbItem>
|
|
42
|
-
<BreadcrumbPage>{t("home")}</BreadcrumbPage>
|
|
43
|
-
</BreadcrumbItem>
|
|
44
|
-
<BreadcrumbSeparator />
|
|
45
|
-
<BreadcrumbItem>
|
|
46
|
-
<Skeleton className="w-40 h-6" />
|
|
47
|
-
</BreadcrumbItem>
|
|
48
|
-
<BreadcrumbSeparator />
|
|
49
|
-
<BreadcrumbItem>
|
|
50
|
-
<Skeleton className="w-40 h-6" />
|
|
51
|
-
</BreadcrumbItem>
|
|
52
|
-
</BreadcrumbList>
|
|
53
|
-
</BreadcrumbComponent>
|
|
54
|
-
);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
37
|
const renderDrawer = () => {
|
|
58
38
|
if (items.length < 2) return null
|
|
59
39
|
|
|
@@ -76,7 +56,7 @@ export const Breadcrumb: FC<BreadcrumbProps> = ({ items, loading, lang }) => {
|
|
|
76
56
|
{items.slice(0, -1).map((item, index) => (
|
|
77
57
|
<Link
|
|
78
58
|
key={index}
|
|
79
|
-
href={item.
|
|
59
|
+
href={`/topics/${item.linkId}/content`}
|
|
80
60
|
className="py-1 text-sm"
|
|
81
61
|
>
|
|
82
62
|
{item.label}
|
|
@@ -100,7 +80,7 @@ export const Breadcrumb: FC<BreadcrumbProps> = ({ items, loading, lang }) => {
|
|
|
100
80
|
|
|
101
81
|
const renderLink = (showLink: boolean, item: TreeOfContent): ReactNode => {
|
|
102
82
|
if (showLink) {
|
|
103
|
-
return <BreadcrumbLink href={item.
|
|
83
|
+
return <BreadcrumbLink href={`/topics/${item.linkId}/content`}>{item.label}</BreadcrumbLink>;
|
|
104
84
|
}
|
|
105
85
|
|
|
106
86
|
return <BreadcrumbPage>{item.label}</BreadcrumbPage>;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
+
SidebarGroup,
|
|
2
3
|
SidebarMenu,
|
|
3
4
|
SidebarMenuButton,
|
|
4
5
|
SidebarMenuItem,
|
|
@@ -8,6 +9,9 @@ import {
|
|
|
8
9
|
} from "@c-rex/ui/sidebar";
|
|
9
10
|
import { DirectoryNodeModel } from "@c-rex/interfaces";
|
|
10
11
|
import { generateTreeOfContent } from "@c-rex/utils/directoryNodes";
|
|
12
|
+
import Link from "next/link";
|
|
13
|
+
import { Suspense } from "react";
|
|
14
|
+
import { Skeleton } from "@c-rex/ui/skeleton";
|
|
11
15
|
|
|
12
16
|
interface SidebarProps {
|
|
13
17
|
directoryNodes: DirectoryNodeModel[];
|
|
@@ -17,33 +21,47 @@ export async function TreeOfContent({ directoryNodes }: SidebarProps) {
|
|
|
17
21
|
const tree = await generateTreeOfContent(directoryNodes);
|
|
18
22
|
|
|
19
23
|
return (
|
|
20
|
-
<
|
|
21
|
-
{
|
|
22
|
-
<
|
|
23
|
-
<
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
24
|
+
<Suspense
|
|
25
|
+
fallback={
|
|
26
|
+
<SidebarGroup className="pt-4">
|
|
27
|
+
<Skeleton className="w-auto h-10 mb-2" />
|
|
28
|
+
<Skeleton className="w-auto h-10 mb-2" />
|
|
29
|
+
<Skeleton className="w-auto h-10 mb-2 ml-8" />
|
|
30
|
+
<Skeleton className="w-auto h-10 mb-2 ml-8" />
|
|
31
|
+
<Skeleton className="w-auto h-10 mb-2 ml-8" />
|
|
32
|
+
<Skeleton className="w-auto h-10 mb-2 ml-8" />
|
|
33
|
+
<Skeleton className="w-auto h-10 mb-2" />
|
|
34
|
+
</SidebarGroup>
|
|
35
|
+
}
|
|
36
|
+
>
|
|
37
|
+
<SidebarMenu>
|
|
38
|
+
{tree.map((item) => (
|
|
39
|
+
<SidebarMenuItem key={item.id}>
|
|
40
|
+
<SidebarMenuButton asChild isActive={item.active}>
|
|
41
|
+
<Link href={`/topics/${item.linkId}/content`} title={item.label}>
|
|
42
|
+
{item.label}
|
|
43
|
+
</Link>
|
|
44
|
+
</SidebarMenuButton>
|
|
28
45
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
46
|
+
{item.children?.length ? (
|
|
47
|
+
<SidebarMenuSub>
|
|
48
|
+
{item.children.map((item) => (
|
|
49
|
+
<SidebarMenuSubItem key={item.label}>
|
|
50
|
+
<SidebarMenuSubButton
|
|
51
|
+
asChild
|
|
52
|
+
isActive={item.active}
|
|
53
|
+
>
|
|
54
|
+
<Link href={`/topics/${item.linkId}/content`} title={item.label}>
|
|
55
|
+
{item.label}
|
|
56
|
+
</Link>
|
|
57
|
+
</SidebarMenuSubButton>
|
|
58
|
+
</SidebarMenuSubItem>
|
|
59
|
+
))}
|
|
60
|
+
</SidebarMenuSub>
|
|
61
|
+
) : null}
|
|
62
|
+
</SidebarMenuItem>
|
|
63
|
+
))}
|
|
64
|
+
</SidebarMenu>
|
|
65
|
+
</Suspense>
|
|
48
66
|
);
|
|
49
67
|
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { FC } from "react";
|
|
2
|
+
import {
|
|
3
|
+
DocumentModel,
|
|
4
|
+
ExternalProductGraphicModel,
|
|
5
|
+
FragmentModel,
|
|
6
|
+
InformationUnitModel,
|
|
7
|
+
PackageModel,
|
|
8
|
+
TopicModel
|
|
9
|
+
} from "@c-rex/interfaces";
|
|
10
|
+
import { FileStack } from "lucide-react";
|
|
11
|
+
import { cn, getType, getTitle, getVersions } from "@c-rex/utils";
|
|
12
|
+
import { Button } from "@c-rex/ui/button";
|
|
13
|
+
import { Tooltip, TooltipContent, TooltipTrigger } from "@c-rex/ui/tooltip";
|
|
14
|
+
import { ResultTypes } from "@c-rex/types";
|
|
15
|
+
import { RESULT_TYPES } from "@c-rex/constants";
|
|
16
|
+
import { FileDownloadDropdown } from "@c-rex/components/file-download";
|
|
17
|
+
import { FavoriteButton } from "@c-rex/components/favorite-button";
|
|
18
|
+
|
|
19
|
+
import { ImageRenditionContainer } from "../renditions/image/container";
|
|
20
|
+
import { BookmarkButton } from "../favorites/bookmark-button";
|
|
21
|
+
import { HtmlRendition } from "../renditions/html";
|
|
22
|
+
|
|
23
|
+
interface Props {
|
|
24
|
+
items: (
|
|
25
|
+
DocumentModel |
|
|
26
|
+
ExternalProductGraphicModel |
|
|
27
|
+
FragmentModel |
|
|
28
|
+
InformationUnitModel |
|
|
29
|
+
PackageModel |
|
|
30
|
+
TopicModel
|
|
31
|
+
)[];
|
|
32
|
+
query?: string;
|
|
33
|
+
disabledResults?: ResultTypes[];
|
|
34
|
+
imageRestrictions?: string[];
|
|
35
|
+
showActions?: boolean;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
export const DocumentsResultList: FC<Props> = ({
|
|
40
|
+
items,
|
|
41
|
+
query = "",
|
|
42
|
+
disabledResults = [],
|
|
43
|
+
imageRestrictions = [],
|
|
44
|
+
showActions = true,
|
|
45
|
+
}) => {
|
|
46
|
+
return (
|
|
47
|
+
<div className="flex-1">
|
|
48
|
+
{items.map((item, index) => {
|
|
49
|
+
const title = getTitle(item.titles, item.labels);
|
|
50
|
+
const itemType = getType(item.class);
|
|
51
|
+
const disabled = disabledResults.includes(itemType);
|
|
52
|
+
const isDocument = itemType === RESULT_TYPES.DOCUMENT;
|
|
53
|
+
const multipleVersions = getVersions(item.versionOf);
|
|
54
|
+
const packageId = item.packages && item.packages.length > 0 ? item.packages[0]?.shortId : null;
|
|
55
|
+
|
|
56
|
+
let itemLink = `/documents/${item.shortId}?q=${query}`
|
|
57
|
+
|
|
58
|
+
if (packageId) {
|
|
59
|
+
itemLink += `&package=${packageId}`
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return (
|
|
63
|
+
<div
|
|
64
|
+
key={index}
|
|
65
|
+
className={cn(
|
|
66
|
+
"min-h-12 flex flex-wrap items-center border px-4 py-2 gap-2 rounded",
|
|
67
|
+
index == items.length - 1 ? "" : "mb-4",
|
|
68
|
+
`c-rex-result-item c-rex-result-${itemType}`,
|
|
69
|
+
disabled && "c-rex-result-item-disabled",
|
|
70
|
+
)}
|
|
71
|
+
>
|
|
72
|
+
<div className="h-16 w-16 flex items-start">
|
|
73
|
+
<ImageRenditionContainer
|
|
74
|
+
itemShortId={item.shortId!}
|
|
75
|
+
imageRestrictions={imageRestrictions}
|
|
76
|
+
emptyImageStyle="h-16 w-16"
|
|
77
|
+
/>
|
|
78
|
+
</div>
|
|
79
|
+
|
|
80
|
+
<div className="flex-1 p-2 flex flex-col">
|
|
81
|
+
<span className="text-sm text-muted-foreground">
|
|
82
|
+
{item.revision}
|
|
83
|
+
</span>
|
|
84
|
+
|
|
85
|
+
<span className="text-lg font-medium">
|
|
86
|
+
{disabled ? (
|
|
87
|
+
title
|
|
88
|
+
) : (
|
|
89
|
+
<a className="hover:underline" href={itemLink}>{title}</a>
|
|
90
|
+
)}
|
|
91
|
+
</span>
|
|
92
|
+
|
|
93
|
+
<span className="text-sm">
|
|
94
|
+
{itemType}
|
|
95
|
+
</span>
|
|
96
|
+
<span className="text-sm">
|
|
97
|
+
<HtmlRendition shortId={item.shortId!} />
|
|
98
|
+
</span>
|
|
99
|
+
</div>
|
|
100
|
+
|
|
101
|
+
<div className="flex flex-col p-2 ml-auto justify-center">
|
|
102
|
+
<div className="flex gap-2">
|
|
103
|
+
<FileDownloadDropdown renditions={item.renditions} />
|
|
104
|
+
|
|
105
|
+
<FavoriteButton
|
|
106
|
+
id={item.shortId!}
|
|
107
|
+
type={itemType}
|
|
108
|
+
label={title}
|
|
109
|
+
/>
|
|
110
|
+
|
|
111
|
+
{multipleVersions.length > 1 && (
|
|
112
|
+
<Tooltip>
|
|
113
|
+
<TooltipTrigger asChild>
|
|
114
|
+
<Button variant="ghost" size="icon">
|
|
115
|
+
<FileStack />
|
|
116
|
+
</Button>
|
|
117
|
+
</TooltipTrigger>
|
|
118
|
+
<TooltipContent>
|
|
119
|
+
Available in: {multipleVersions.join(", ")}
|
|
120
|
+
</TooltipContent>
|
|
121
|
+
</Tooltip>
|
|
122
|
+
)}
|
|
123
|
+
|
|
124
|
+
{isDocument && (
|
|
125
|
+
<BookmarkButton
|
|
126
|
+
shortId={item.shortId!}
|
|
127
|
+
triggerVariant="ghost"
|
|
128
|
+
/>
|
|
129
|
+
)}
|
|
130
|
+
</div>
|
|
131
|
+
</div>
|
|
132
|
+
</div>
|
|
133
|
+
);
|
|
134
|
+
})}
|
|
135
|
+
</div>
|
|
136
|
+
);
|
|
137
|
+
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
import { FC, ReactNode, useEffect, useState } from "react";
|
|
4
|
-
import { Button } from "@c-rex/ui/button";
|
|
3
|
+
import { ComponentProps, FC, ReactNode, useEffect, useState } from "react";
|
|
4
|
+
import { Button, ButtonProps } from "@c-rex/ui/button";
|
|
5
5
|
import { Trash } from "lucide-react";
|
|
6
6
|
import { cn } from "@c-rex/utils";
|
|
7
7
|
import Link from "next/link";
|
|
@@ -15,32 +15,35 @@ import {
|
|
|
15
15
|
} from "@c-rex/ui/table"
|
|
16
16
|
import { FaRegBookmark } from "react-icons/fa6";
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
type BookmarkProps = {
|
|
19
|
+
shortId: string;
|
|
20
|
+
triggerVariant?: ComponentProps<typeof Button>["variant"];
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export const BookmarkButton: FC<BookmarkProps> = ({
|
|
24
|
+
shortId,
|
|
25
|
+
triggerVariant = "outline"
|
|
26
|
+
}) => {
|
|
19
27
|
const [markersList, setMarkersList] = useState<Array<{ id: string; label: string; color: string }>>([]);
|
|
20
28
|
|
|
21
29
|
useEffect(() => {
|
|
22
30
|
setMarkersList(useFavoritesStore.getState().documents[shortId]?.topics || []);
|
|
23
31
|
}, [shortId]);
|
|
24
|
-
|
|
25
|
-
useEffect(() => {
|
|
26
|
-
console.log(shortId, markersList);
|
|
27
|
-
}, [markersList]);
|
|
28
|
-
|
|
29
32
|
return (
|
|
30
33
|
<Dialog>
|
|
31
34
|
<DialogTrigger asChild>
|
|
35
|
+
<Button variant={triggerVariant} size="icon" className="relative">
|
|
36
|
+
<FaRegBookmark className="text-primary" />
|
|
32
37
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
<Button variant="outline" size="icon" className="relative">
|
|
36
|
-
<FaRegBookmark className="text-primary" />
|
|
38
|
+
{markersList.length > 0 && (
|
|
37
39
|
<span
|
|
38
40
|
className="absolute -top-[10px] -right-[10px] min-w-5 min-h-5 bg-primary text-white rounded-full"
|
|
39
41
|
>
|
|
40
42
|
{markersList.length}
|
|
41
43
|
</span>
|
|
42
|
-
|
|
43
|
-
|
|
44
|
+
)}
|
|
45
|
+
</Button>
|
|
46
|
+
|
|
44
47
|
</DialogTrigger>
|
|
45
48
|
<DialogContent>
|
|
46
49
|
<DialogHeader>
|
|
@@ -37,13 +37,12 @@ export function createClientDataRequest<T, PathParams, QueryParams>(
|
|
|
37
37
|
const [state, setState] = useState<DataRequestRenderProps<T>>({
|
|
38
38
|
data: null,
|
|
39
39
|
error: null,
|
|
40
|
-
isLoading:
|
|
40
|
+
isLoading: true,
|
|
41
41
|
});
|
|
42
42
|
|
|
43
43
|
const fetchData = useCallback(async () => {
|
|
44
44
|
setState({
|
|
45
45
|
...state,
|
|
46
|
-
isLoading: !state.data,
|
|
47
46
|
error: null,
|
|
48
47
|
});
|
|
49
48
|
|
|
@@ -14,7 +14,7 @@ export type DataRequestRenderProps<T> = {
|
|
|
14
14
|
type DataRequestProps<T, PathParams, QueryParams> = {
|
|
15
15
|
pathParams?: PathParams;
|
|
16
16
|
queryParams?: QueryParams;
|
|
17
|
-
render: (data: T, error?: SerializedError) =>
|
|
17
|
+
render: (data: T, error?: SerializedError) => any; // any because it can return JSX, async functions, etc.
|
|
18
18
|
};
|
|
19
19
|
|
|
20
20
|
|
|
@@ -25,7 +25,7 @@ export function createDataRequestWithParams<T, PathParams, QueryParams>(
|
|
|
25
25
|
pathParams,
|
|
26
26
|
queryParams = {} as QueryParams,
|
|
27
27
|
render,
|
|
28
|
-
}: DataRequestProps<T, PathParams, QueryParams>) {
|
|
28
|
+
}: DataRequestProps<T, PathParams, QueryParams>): Promise<any> {
|
|
29
29
|
let endpoint = endpointTemplate;
|
|
30
30
|
if (pathParams) {
|
|
31
31
|
endpoint = Object.entries(pathParams as Record<string, string>).reduce(
|
package/src/icons/loading.tsx
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import React, { FC } from "react";
|
|
2
2
|
|
|
3
3
|
type LoadingProps = {
|
|
4
|
-
opacity
|
|
4
|
+
opacity?: boolean;
|
|
5
5
|
}
|
|
6
|
-
export const Loading: FC<LoadingProps> = ({ opacity }) => {
|
|
6
|
+
export const Loading: FC<LoadingProps> = ({ opacity = false }) => {
|
|
7
7
|
return (
|
|
8
8
|
<div className={`fixed inset-0 z-[100000] w-full h-full flex justify-center items-center bg-white ${opacity ? "opacity-50" : ""}`}>
|
|
9
9
|
<div className="animate-spin rounded-full h-12 w-12 border-2 border-gray-300 border-t-gray-950"></div>
|
package/src/info/info-table.tsx
CHANGED
|
@@ -24,6 +24,7 @@ import { InformationUnitsGetAll } from "../generated/server-components";
|
|
|
24
24
|
import { getTranslations } from "next-intl/server";
|
|
25
25
|
import { EN_LANG } from "@c-rex/constants";
|
|
26
26
|
import { getFileRenditions } from "../results/utils";
|
|
27
|
+
import Link from "next/link";
|
|
27
28
|
|
|
28
29
|
type Props = {
|
|
29
30
|
title: string;
|
|
@@ -155,9 +156,9 @@ export const InfoTable: FC<Props> = async ({
|
|
|
155
156
|
const country = language.split("-")[1]!;
|
|
156
157
|
return (
|
|
157
158
|
<span className="w-8 block border" key={item.shortId}>
|
|
158
|
-
<
|
|
159
|
+
<Link href={`/${linkPath}/${item.shortId}/content`} title={language}>
|
|
159
160
|
<Flag countryCode={country} />
|
|
160
|
-
</
|
|
161
|
+
</Link>
|
|
161
162
|
</span>
|
|
162
163
|
)
|
|
163
164
|
})}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { FC } from "react";
|
|
2
|
+
import {
|
|
3
|
+
DocumentModel,
|
|
4
|
+
ExternalProductGraphicModel,
|
|
5
|
+
FragmentModel,
|
|
6
|
+
InformationUnitModel,
|
|
7
|
+
PackageModel,
|
|
8
|
+
TopicModel
|
|
9
|
+
} from "@c-rex/interfaces";
|
|
10
|
+
import { cn, getLanguage, getTitle, getType, getVersions } from "@c-rex/utils";
|
|
11
|
+
import { Flag } from "@c-rex/components/flag";
|
|
12
|
+
import { Badge } from "@c-rex/ui/badge";
|
|
13
|
+
import { RESULT_TYPES } from "@c-rex/constants";
|
|
14
|
+
import Link from "next/link";
|
|
15
|
+
import { FileDownloadDropdown } from "@c-rex/components/file-download";
|
|
16
|
+
import { getTranslations } from "next-intl/server";
|
|
17
|
+
|
|
18
|
+
interface Props {
|
|
19
|
+
items: (
|
|
20
|
+
DocumentModel |
|
|
21
|
+
ExternalProductGraphicModel |
|
|
22
|
+
FragmentModel |
|
|
23
|
+
InformationUnitModel |
|
|
24
|
+
PackageModel |
|
|
25
|
+
TopicModel
|
|
26
|
+
)[];
|
|
27
|
+
query: string;
|
|
28
|
+
linkPath: string;
|
|
29
|
+
showFilesColumn?: boolean;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export const GenericTableResultList: FC<Props> = async ({ items, query, linkPath, showFilesColumn = true }) => {
|
|
33
|
+
const t = await getTranslations("results");
|
|
34
|
+
|
|
35
|
+
return (
|
|
36
|
+
<div className="rounded-md border mb-6 last:border-b-0">
|
|
37
|
+
<div className="font-bold text-sm p-2 border-b items-center flex-wrap hidden md:flex">
|
|
38
|
+
<div className="flex-1 p-2">{t("title")}</div>
|
|
39
|
+
<div className="w-1/2 md:w-1/5 p-2 flex justify-center">{t("language")}</div>
|
|
40
|
+
<div className="w-1/2 md:w-1/5 p-2 flex justify-center">{t("type")}</div>
|
|
41
|
+
{showFilesColumn &&
|
|
42
|
+
<div className="w-1/2 md:w-1/5 p-2 flex justify-center">{t("files")}</div>
|
|
43
|
+
}
|
|
44
|
+
</div>
|
|
45
|
+
|
|
46
|
+
{items.map((item, index) => {
|
|
47
|
+
const title = getTitle(item.titles, item.labels);
|
|
48
|
+
const itemType = getType(item.class);
|
|
49
|
+
const language = getLanguage(item.languages);
|
|
50
|
+
const packageId = item.packages && item.packages.length > 0 ? item.packages[0]?.shortId : null;
|
|
51
|
+
|
|
52
|
+
const isDocument = itemType === RESULT_TYPES.DOCUMENT;
|
|
53
|
+
const multipleVersions = getVersions(item.versionOf);
|
|
54
|
+
|
|
55
|
+
let itemLink = `${linkPath}/${item.shortId}?q=${query}`
|
|
56
|
+
|
|
57
|
+
if (packageId) {
|
|
58
|
+
itemLink += `&package=${packageId}`
|
|
59
|
+
}
|
|
60
|
+
return (
|
|
61
|
+
<div
|
|
62
|
+
className={cn(
|
|
63
|
+
"min-h-12 c-rex-result-item flex flex-wrap items-center border-b",
|
|
64
|
+
`c-rex-result-${itemType.toLowerCase()}`,
|
|
65
|
+
)}
|
|
66
|
+
key={index}
|
|
67
|
+
>
|
|
68
|
+
<div className="flex-1 p-2">
|
|
69
|
+
<Link href={itemLink} className="hover:underline">{title}</Link>
|
|
70
|
+
</div>
|
|
71
|
+
|
|
72
|
+
<div className="w-1/5 md:w-1/5 flex justify-center p-2">
|
|
73
|
+
<span className="w-8 inline-block">
|
|
74
|
+
{language.split("-").length > 1 && (
|
|
75
|
+
<Flag countryCode={language.split("-")[1] as string} />
|
|
76
|
+
)}
|
|
77
|
+
</span>
|
|
78
|
+
</div>
|
|
79
|
+
|
|
80
|
+
<div className="w-4/5 md:w-1/5 p-2 flex justify-center">
|
|
81
|
+
<Badge variant="secondary">
|
|
82
|
+
{itemType}
|
|
83
|
+
</Badge>
|
|
84
|
+
</div>
|
|
85
|
+
|
|
86
|
+
{showFilesColumn &&
|
|
87
|
+
<div className="w-1/5 flex justify-center p-2">
|
|
88
|
+
<FileDownloadDropdown renditions={item.renditions} />
|
|
89
|
+
</div>
|
|
90
|
+
}
|
|
91
|
+
</div>
|
|
92
|
+
)
|
|
93
|
+
})}
|
|
94
|
+
</div>
|
|
95
|
+
);
|
|
96
|
+
};
|
|
@@ -9,11 +9,10 @@ import {
|
|
|
9
9
|
} from "@c-rex/interfaces";
|
|
10
10
|
import { FileStack } from "lucide-react";
|
|
11
11
|
import { FileDownloadDropdown } from "../renditions/file-download";
|
|
12
|
-
import { cn, getType, getTitle,
|
|
12
|
+
import { cn, getType, getTitle, getVersions } from "@c-rex/utils";
|
|
13
13
|
import { Button } from "@c-rex/ui/button";
|
|
14
14
|
import { Tooltip, TooltipContent, TooltipTrigger } from "@c-rex/ui/tooltip";
|
|
15
15
|
import { Favorite, ResultTypes } from "@c-rex/types";
|
|
16
|
-
import { getVersions } from "./utils";
|
|
17
16
|
import { RESULT_TYPES } from "@c-rex/constants";
|
|
18
17
|
import { FavoriteButton } from "../favorites/favorite-button";
|
|
19
18
|
import { ImageRenditionContainer } from "../renditions/image/container";
|
|
@@ -33,15 +32,21 @@ interface TableWithImageProps {
|
|
|
33
32
|
markersList?: Favorite[];
|
|
34
33
|
disabledResults?: ResultTypes[];
|
|
35
34
|
imageRestrictions?: string[];
|
|
35
|
+
showActions?: boolean;
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
|
|
39
|
-
export const TableWithImage: FC<TableWithImageProps> = ({
|
|
39
|
+
export const TableWithImage: FC<TableWithImageProps> = ({
|
|
40
|
+
items,
|
|
41
|
+
query = "",
|
|
42
|
+
disabledResults = [],
|
|
43
|
+
imageRestrictions = [],
|
|
44
|
+
showActions = true,
|
|
45
|
+
}) => {
|
|
40
46
|
return (
|
|
41
47
|
<div className="flex-1">
|
|
42
48
|
{items.map((item, index) => {
|
|
43
49
|
const title = getTitle(item.titles, item.labels);
|
|
44
|
-
const language = getLanguage(item.languages);
|
|
45
50
|
const itemType = getType(item.class);
|
|
46
51
|
const disabled = disabledResults.includes(itemType);
|
|
47
52
|
const isDocument = itemType === RESULT_TYPES.DOCUMENT;
|
|
@@ -58,7 +63,6 @@ export const TableWithImage: FC<TableWithImageProps> = ({ items, query = "", dis
|
|
|
58
63
|
itemLink += `&package=${packageId}`
|
|
59
64
|
}
|
|
60
65
|
|
|
61
|
-
|
|
62
66
|
return (
|
|
63
67
|
<div
|
|
64
68
|
key={index}
|
|
@@ -79,7 +83,7 @@ export const TableWithImage: FC<TableWithImageProps> = ({ items, query = "", dis
|
|
|
79
83
|
|
|
80
84
|
<div className="flex-1 p-2 flex flex-col">
|
|
81
85
|
<span className="text-sm text-muted-foreground">
|
|
82
|
-
{
|
|
86
|
+
{item.revision}
|
|
83
87
|
</span>
|
|
84
88
|
|
|
85
89
|
<span className="text-lg font-medium">
|
|
@@ -99,19 +103,9 @@ export const TableWithImage: FC<TableWithImageProps> = ({ items, query = "", dis
|
|
|
99
103
|
</div>
|
|
100
104
|
|
|
101
105
|
<div className="flex flex-col p-2 ml-auto justify-center">
|
|
102
|
-
<span className="text-end text-sm text-muted-foreground mb-2">
|
|
103
|
-
{item.revision}
|
|
104
|
-
</span>
|
|
105
106
|
<div className="flex gap-2">
|
|
106
107
|
<FileDownloadDropdown renditions={item.renditions} />
|
|
107
108
|
|
|
108
|
-
{isDocument && (
|
|
109
|
-
<BookmarkButton
|
|
110
|
-
shortId={item.shortId!}
|
|
111
|
-
|
|
112
|
-
/>
|
|
113
|
-
)}
|
|
114
|
-
|
|
115
109
|
<FavoriteButton
|
|
116
110
|
id={item.shortId!}
|
|
117
111
|
type={itemType}
|
|
@@ -130,6 +124,13 @@ export const TableWithImage: FC<TableWithImageProps> = ({ items, query = "", dis
|
|
|
130
124
|
</TooltipContent>
|
|
131
125
|
</Tooltip>
|
|
132
126
|
)}
|
|
127
|
+
|
|
128
|
+
{isDocument && (
|
|
129
|
+
<BookmarkButton
|
|
130
|
+
shortId={item.shortId!}
|
|
131
|
+
triggerVariant="ghost"
|
|
132
|
+
/>
|
|
133
|
+
)}
|
|
133
134
|
</div>
|
|
134
135
|
</div>
|
|
135
136
|
</div>
|
package/src/search-input.tsx
CHANGED
|
@@ -29,10 +29,15 @@ export const SearchInput: FC<Props> = ({ showInput, showPkgFilter, placedOn = "N
|
|
|
29
29
|
|
|
30
30
|
{/*
|
|
31
31
|
Add scope=pkgID if checked is true
|
|
32
|
-
|
|
33
|
-
<InformationUnitsSuggestions
|
|
34
|
-
|
|
35
|
-
|
|
32
|
+
*/}
|
|
33
|
+
<InformationUnitsSuggestions
|
|
34
|
+
onSelectParams={
|
|
35
|
+
(pkg && checked) ? [{ key: "packages", value: pkg }] : []
|
|
36
|
+
|
|
37
|
+
}
|
|
38
|
+
onSelectPath="/information-units"
|
|
39
|
+
embedded
|
|
40
|
+
/>
|
|
36
41
|
|
|
37
42
|
{showPkgFilter && <>
|
|
38
43
|
<TooltipProvider>
|