@c-rex/components 0.3.0-build.34 → 0.3.0-build.36
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 +28 -36
- package/src/article/article-action-bar.tsx +4 -1
- package/src/{check-article-lang.tsx → article/check-article-lang.tsx} +1 -1
- package/src/article/render-article-highlight.tsx +108 -0
- package/src/article/render-article.tsx +28 -0
- package/src/autocomplete.tsx +2 -2
- package/src/carousel/carousel.tsx +5 -2
- package/src/carousel/information-unit-carousel-item.tsx +1 -1
- package/src/content-unavailable.tsx +20 -0
- package/src/directoryNodes/directory-tree-context.tsx +9 -4
- package/src/documents/description-preview.tsx +14 -4
- package/src/documents/result-list-item.tsx +35 -46
- package/src/favorites/__tests__/favorites-hydration.test.tsx +245 -0
- package/src/favorites/bookmark-button.tsx +38 -20
- package/src/favorites/favorite-button.tsx +23 -24
- package/src/favorites/favorites-context.tsx +287 -0
- package/src/icons/file-icon.tsx +9 -26
- package/src/info/information-unit-metadata-grid-client.tsx +21 -21
- package/src/page-wrapper.tsx +1 -1
- package/src/renditions/html-client.tsx +8 -6
- package/src/renditions/html.tsx +3 -1
- package/src/restriction-menu/restriction-menu-item.tsx +48 -58
- package/src/restriction-menu/restriction-selection-command-menu.tsx +444 -0
- package/src/restriction-menu/restriction-selection-menu.tsx +3 -5
- package/src/restriction-menu/taxonomy-restriction-command-menu.tsx +111 -0
- package/src/restriction-menu/taxonomy-restriction-menu.tsx +1 -7
- package/src/results/filter-navbar.tsx +81 -76
- package/src/results/filter-sidebar/context.tsx +32 -0
- package/src/results/filter-sidebar/index.tsx +44 -35
- package/src/results/generic/search-results-client.tsx +5 -4
- package/src/results/generic/table-result-list.tsx +16 -16
- package/src/results/information-unit-search-results-card-list.tsx +4 -1
- package/src/results/pagination.tsx +43 -40
- package/src/search-input.tsx +4 -2
- package/src/toc/toc-browse-controls.tsx +2 -2
- package/src/toc/toc-tree-panel.tsx +19 -16
- package/src/article/article-content.tsx +0 -19
- package/src/breadcrumb.tsx +0 -124
- package/src/directoryNodes/tree-of-content.tsx +0 -68
- package/src/render-article.tsx +0 -75
- package/src/restriction-menu/restriction-menu-container.tsx +0 -4
- package/src/restriction-menu/restriction-menu.tsx +0 -4
- package/src/stores/__tests__/favorites-store.test.ts +0 -54
- package/src/stores/favorites-store.ts +0 -163
- /package/src/{render-article.module.css → article/render-article.module.css} +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@c-rex/components",
|
|
3
|
-
"version": "0.3.0-build.
|
|
3
|
+
"version": "0.3.0-build.36",
|
|
4
4
|
"files": [
|
|
5
5
|
"src"
|
|
6
6
|
],
|
|
@@ -21,10 +21,6 @@
|
|
|
21
21
|
"types": "./src/generated/suggestions.tsx",
|
|
22
22
|
"import": "./src/generated/suggestions.tsx"
|
|
23
23
|
},
|
|
24
|
-
"./breadcrumb": {
|
|
25
|
-
"types": "./src/breadcrumb.tsx",
|
|
26
|
-
"import": "./src/breadcrumb.tsx"
|
|
27
|
-
},
|
|
28
24
|
"./navbar": {
|
|
29
25
|
"types": "./src/navbar/navbar.tsx",
|
|
30
26
|
"import": "./src/navbar/navbar.tsx"
|
|
@@ -62,12 +58,12 @@
|
|
|
62
58
|
"import": "./src/info/info-card.tsx"
|
|
63
59
|
},
|
|
64
60
|
"./check-article-lang": {
|
|
65
|
-
"types": "./src/check-article-lang.tsx",
|
|
66
|
-
"import": "./src/check-article-lang.tsx"
|
|
61
|
+
"types": "./src/article/check-article-lang.tsx",
|
|
62
|
+
"import": "./src/article/check-article-lang.tsx"
|
|
67
63
|
},
|
|
68
64
|
"./render-article": {
|
|
69
|
-
"types": "./src/render-article.tsx",
|
|
70
|
-
"import": "./src/render-article.tsx"
|
|
65
|
+
"types": "./src/article/render-article.tsx",
|
|
66
|
+
"import": "./src/article/render-article.tsx"
|
|
71
67
|
},
|
|
72
68
|
"./article-action-bar": {
|
|
73
69
|
"types": "./src/article/article-action-bar.tsx",
|
|
@@ -98,17 +94,13 @@
|
|
|
98
94
|
"import": "./src/renditions/html-client.tsx"
|
|
99
95
|
},
|
|
100
96
|
"./image-rendition-container": {
|
|
101
|
-
"types": "./src/renditions/container.
|
|
102
|
-
"import": "./src/renditions/container.
|
|
97
|
+
"types": "./src/renditions/image/container.tsx",
|
|
98
|
+
"import": "./src/renditions/image/container.tsx"
|
|
103
99
|
},
|
|
104
100
|
"./autocomplete": {
|
|
105
101
|
"types": "./src/autocomplete.tsx",
|
|
106
102
|
"import": "./src/autocomplete.tsx"
|
|
107
103
|
},
|
|
108
|
-
"./result-container": {
|
|
109
|
-
"types": "./src/result-container.tsx",
|
|
110
|
-
"import": "./src/result-container.tsx"
|
|
111
|
-
},
|
|
112
104
|
"./dialog-filter": {
|
|
113
105
|
"types": "./src/results/dialog-filter.tsx",
|
|
114
106
|
"import": "./src/results/dialog-filter.tsx"
|
|
@@ -117,6 +109,10 @@
|
|
|
117
109
|
"types": "./src/results/pagination.tsx",
|
|
118
110
|
"import": "./src/results/pagination.tsx"
|
|
119
111
|
},
|
|
112
|
+
"./information-unit-search-results-card-list": {
|
|
113
|
+
"types": "./src/results/information-unit-search-results-card-list.tsx",
|
|
114
|
+
"import": "./src/results/information-unit-search-results-card-list.tsx"
|
|
115
|
+
},
|
|
120
116
|
"./information-unit-search-results-cards": {
|
|
121
117
|
"types": "./src/results/information-unit-search-results-cards.tsx",
|
|
122
118
|
"import": "./src/results/information-unit-search-results-cards.tsx"
|
|
@@ -141,10 +137,10 @@
|
|
|
141
137
|
"types": "./src/stores/highlight-store.ts",
|
|
142
138
|
"import": "./src/stores/highlight-store.ts"
|
|
143
139
|
},
|
|
144
|
-
"./favorites-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
140
|
+
"./favorites-context": {
|
|
141
|
+
"types": "./src/favorites/favorites-context.tsx",
|
|
142
|
+
"import": "./src/favorites/favorites-context.tsx"
|
|
143
|
+
},
|
|
148
144
|
"./search-settings-store": {
|
|
149
145
|
"types": "./src/stores/search-settings-store.ts",
|
|
150
146
|
"import": "./src/stores/search-settings-store.ts"
|
|
@@ -177,14 +173,6 @@
|
|
|
177
173
|
"types": "./src/renditions/image/rendition.tsx",
|
|
178
174
|
"import": "./src/renditions/image/rendition.tsx"
|
|
179
175
|
},
|
|
180
|
-
"./server-image-rendition": {
|
|
181
|
-
"types": "./src/renditions/image/server-image-rendition.tsx",
|
|
182
|
-
"import": "./src/renditions/image/server-image-rendition.tsx"
|
|
183
|
-
},
|
|
184
|
-
"./article-skeleton": {
|
|
185
|
-
"types": "./src/article/article-skeleton.tsx",
|
|
186
|
-
"import": "./src/article/article-skeleton.tsx"
|
|
187
|
-
},
|
|
188
176
|
"./documents-result-list": {
|
|
189
177
|
"types": "./src/documents/result-list.tsx",
|
|
190
178
|
"import": "./src/documents/result-list.tsx"
|
|
@@ -201,14 +189,6 @@
|
|
|
201
189
|
"types": "./src/carousel/carousel.tsx",
|
|
202
190
|
"import": "./src/carousel/carousel.tsx"
|
|
203
191
|
},
|
|
204
|
-
"./restriction-menu": {
|
|
205
|
-
"types": "./src/restriction-menu/restriction-menu.tsx",
|
|
206
|
-
"import": "./src/restriction-menu/restriction-menu.tsx"
|
|
207
|
-
},
|
|
208
|
-
"./restriction-menu-container": {
|
|
209
|
-
"types": "./src/restriction-menu/restriction-menu-container.tsx",
|
|
210
|
-
"import": "./src/restriction-menu/restriction-menu-container.tsx"
|
|
211
|
-
},
|
|
212
192
|
"./restriction-menu-item": {
|
|
213
193
|
"types": "./src/restriction-menu/restriction-menu-item.tsx",
|
|
214
194
|
"import": "./src/restriction-menu/restriction-menu-item.tsx"
|
|
@@ -217,6 +197,10 @@
|
|
|
217
197
|
"types": "./src/search-input.tsx",
|
|
218
198
|
"import": "./src/search-input.tsx"
|
|
219
199
|
},
|
|
200
|
+
"./content-unavailable": {
|
|
201
|
+
"types": "./src/content-unavailable.tsx",
|
|
202
|
+
"import": "./src/content-unavailable.tsx"
|
|
203
|
+
},
|
|
220
204
|
"./footer": {
|
|
221
205
|
"types": "./src/footer/footer.tsx",
|
|
222
206
|
"import": "./src/footer/footer.tsx"
|
|
@@ -240,7 +224,15 @@
|
|
|
240
224
|
"./taxonomy-restriction-menu": {
|
|
241
225
|
"types": "./src/restriction-menu/taxonomy-restriction-menu.tsx",
|
|
242
226
|
"import": "./src/restriction-menu/taxonomy-restriction-menu.tsx"
|
|
243
|
-
}
|
|
227
|
+
},
|
|
228
|
+
"./restriction-selection-command-menu": {
|
|
229
|
+
"types": "./src/restriction-menu/restriction-selection-command-menu.tsx",
|
|
230
|
+
"import": "./src/restriction-menu/restriction-selection-command-menu.tsx"
|
|
231
|
+
},
|
|
232
|
+
"./taxonomy-restriction-command-menu": {
|
|
233
|
+
"types": "./src/restriction-menu/taxonomy-restriction-command-menu.tsx",
|
|
234
|
+
"import": "./src/restriction-menu/taxonomy-restriction-command-menu.tsx"
|
|
235
|
+
}
|
|
244
236
|
},
|
|
245
237
|
"scripts": {
|
|
246
238
|
"storybook": "storybook dev -p 6006",
|
|
@@ -10,6 +10,7 @@ import { cn } from "@c-rex/utils";
|
|
|
10
10
|
import { useTranslations } from "next-intl";
|
|
11
11
|
import { FavoriteButton } from "../favorites/favorite-button";
|
|
12
12
|
import { ResultTypes } from "@c-rex/types";
|
|
13
|
+
import { ShareButton } from "../share-button";
|
|
13
14
|
type Props = {
|
|
14
15
|
id: string;
|
|
15
16
|
articleType: ResultTypes;
|
|
@@ -31,7 +32,7 @@ export const ArticleActionBar: FC<Props> = ({ id, articleType, favoriteLabel })
|
|
|
31
32
|
}, [open]);
|
|
32
33
|
|
|
33
34
|
return (
|
|
34
|
-
<div className="w-9 flex gap-2 transition-all duration-300
|
|
35
|
+
<div className="w-9 flex gap-2 transition-all duration-300 z-20 items-end flex-col sticky top-40 md:top-24 self-start">
|
|
35
36
|
|
|
36
37
|
<SidebarTrigger side="right" />
|
|
37
38
|
|
|
@@ -41,6 +42,8 @@ export const ArticleActionBar: FC<Props> = ({ id, articleType, favoriteLabel })
|
|
|
41
42
|
label={favoriteLabel}
|
|
42
43
|
/>
|
|
43
44
|
|
|
45
|
+
<ShareButton />
|
|
46
|
+
|
|
44
47
|
<Button
|
|
45
48
|
variant="ghost"
|
|
46
49
|
size="icon"
|
|
@@ -5,7 +5,7 @@ import { useAppConfig } from "@c-rex/contexts/config-provider";
|
|
|
5
5
|
import { AvailableVersionsInterface } from "@c-rex/interfaces";
|
|
6
6
|
import { toast } from "sonner"
|
|
7
7
|
import { useTranslations } from "next-intl"
|
|
8
|
-
import { useSearchSettingsStore } from "
|
|
8
|
+
import { useSearchSettingsStore } from "../stores/search-settings-store";
|
|
9
9
|
|
|
10
10
|
interface Props {
|
|
11
11
|
availableVersions: AvailableVersionsInterface[]
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useEffect } from "react";
|
|
4
|
+
import { useQueryState } from "nuqs";
|
|
5
|
+
import { useHighlight } from "@c-rex/contexts/highlight-provider";
|
|
6
|
+
import { useHighlightStore } from "../stores/highlight-store";
|
|
7
|
+
|
|
8
|
+
const EXCLUDED_TAGS = new Set(["MARK", "SCRIPT", "STYLE", "NOSCRIPT", "TEXTAREA"]);
|
|
9
|
+
|
|
10
|
+
export const extractHighlightTerms = (query: string | null): string[] => {
|
|
11
|
+
if (!query) return [];
|
|
12
|
+
|
|
13
|
+
return query
|
|
14
|
+
.split(/[+ ]/)
|
|
15
|
+
.map((term) => term.trim())
|
|
16
|
+
.filter(Boolean);
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const applyHighlightToElement = (container: HTMLElement, terms: string[]) => {
|
|
20
|
+
if (terms.length === 0) return;
|
|
21
|
+
|
|
22
|
+
const escapedTerms = terms.map((term) =>
|
|
23
|
+
term.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")
|
|
24
|
+
);
|
|
25
|
+
const regex = new RegExp(`(${escapedTerms.join("|")})`, "gi");
|
|
26
|
+
const walker = document.createTreeWalker(container, NodeFilter.SHOW_TEXT);
|
|
27
|
+
const textNodes: Text[] = [];
|
|
28
|
+
|
|
29
|
+
let currentNode = walker.nextNode();
|
|
30
|
+
while (currentNode) {
|
|
31
|
+
const parent = currentNode.parentElement;
|
|
32
|
+
const textContent = currentNode.textContent ?? "";
|
|
33
|
+
|
|
34
|
+
if (
|
|
35
|
+
parent &&
|
|
36
|
+
!EXCLUDED_TAGS.has(parent.tagName) &&
|
|
37
|
+
textContent.trim().length > 0
|
|
38
|
+
) {
|
|
39
|
+
const hasMatch = regex.test(textContent);
|
|
40
|
+
regex.lastIndex = 0;
|
|
41
|
+
|
|
42
|
+
if (hasMatch) {
|
|
43
|
+
textNodes.push(currentNode as Text);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
currentNode = walker.nextNode();
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
textNodes.forEach((textNode) => {
|
|
51
|
+
const textContent = textNode.textContent ?? "";
|
|
52
|
+
const parts = textContent.split(regex);
|
|
53
|
+
|
|
54
|
+
if (parts.length <= 1) return;
|
|
55
|
+
|
|
56
|
+
const fragment = document.createDocumentFragment();
|
|
57
|
+
|
|
58
|
+
parts.forEach((part) => {
|
|
59
|
+
if (!part) return;
|
|
60
|
+
|
|
61
|
+
const isMatch = regex.test(part);
|
|
62
|
+
regex.lastIndex = 0;
|
|
63
|
+
|
|
64
|
+
if (isMatch) {
|
|
65
|
+
const mark = document.createElement("mark");
|
|
66
|
+
mark.className = "bg-yellow-200";
|
|
67
|
+
mark.textContent = part;
|
|
68
|
+
fragment.appendChild(mark);
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
fragment.appendChild(document.createTextNode(part));
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
textNode.parentNode?.replaceChild(fragment, textNode);
|
|
76
|
+
});
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
type RenderArticleHighlightProps = {
|
|
80
|
+
containerId: string
|
|
81
|
+
htmlContent: string
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
export const RenderArticleHighlight = ({
|
|
85
|
+
containerId,
|
|
86
|
+
htmlContent,
|
|
87
|
+
}: RenderArticleHighlightProps) => {
|
|
88
|
+
const [query] = useQueryState("q");
|
|
89
|
+
const enableHighlight = useHighlightStore((state) => state.enable);
|
|
90
|
+
const { registerContainer, refreshMarks } = useHighlight();
|
|
91
|
+
|
|
92
|
+
useEffect(() => {
|
|
93
|
+
const container = document.getElementById(containerId) as HTMLElement | null;
|
|
94
|
+
if (!container) return;
|
|
95
|
+
|
|
96
|
+
registerContainer(container);
|
|
97
|
+
container.innerHTML = htmlContent;
|
|
98
|
+
|
|
99
|
+
if (enableHighlight) {
|
|
100
|
+
const terms = extractHighlightTerms(query);
|
|
101
|
+
applyHighlightToElement(container, terms);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
refreshMarks();
|
|
105
|
+
}, [containerId, enableHighlight, htmlContent, query, refreshMarks, registerContainer]);
|
|
106
|
+
|
|
107
|
+
return null;
|
|
108
|
+
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { useId } from "react";
|
|
2
|
+
import styles from "./render-article.module.css";
|
|
3
|
+
import { RenderArticleHighlight } from "./render-article-highlight";
|
|
4
|
+
|
|
5
|
+
type Props = {
|
|
6
|
+
htmlContent: string;
|
|
7
|
+
contentLang?: string;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export const RenderArticle = ({ htmlContent, contentLang }: Props) => {
|
|
11
|
+
const containerId = useId().replace(/:/g, "");
|
|
12
|
+
|
|
13
|
+
return (
|
|
14
|
+
<>
|
|
15
|
+
<main
|
|
16
|
+
id={containerId}
|
|
17
|
+
data-content-scope="dita"
|
|
18
|
+
lang={contentLang}
|
|
19
|
+
className={`ids-content ids-content--dita-ot ${styles.idsContent}`}
|
|
20
|
+
dangerouslySetInnerHTML={{ __html: htmlContent }}
|
|
21
|
+
/>
|
|
22
|
+
<RenderArticleHighlight
|
|
23
|
+
containerId={containerId}
|
|
24
|
+
htmlContent={htmlContent}
|
|
25
|
+
/>
|
|
26
|
+
</>
|
|
27
|
+
);
|
|
28
|
+
};
|
package/src/autocomplete.tsx
CHANGED
|
@@ -209,7 +209,7 @@ export const AutoComplete = ({
|
|
|
209
209
|
<InputGroupButton
|
|
210
210
|
size="icon-xs"
|
|
211
211
|
variant="ghost"
|
|
212
|
-
aria-label="
|
|
212
|
+
aria-label={t("clearSearch")}
|
|
213
213
|
onClick={clearSearch}
|
|
214
214
|
>
|
|
215
215
|
<X className="size-3" />
|
|
@@ -246,7 +246,7 @@ export const AutoComplete = ({
|
|
|
246
246
|
))}
|
|
247
247
|
</>
|
|
248
248
|
) : (
|
|
249
|
-
<li className="px-4 py-2">
|
|
249
|
+
<li className="px-4 py-2">{t("noSuggestions")}</li>
|
|
250
250
|
)}
|
|
251
251
|
</>
|
|
252
252
|
)}
|
|
@@ -298,6 +298,7 @@ export const Carousel: FC<Props> = ({
|
|
|
298
298
|
<div ref={containerRef} className={cn("w-full flex items-center")}>
|
|
299
299
|
{(arrows && data && data.length > 0) && <CarouselPrev />}
|
|
300
300
|
<div className={cn("flex-1 overflow-hidden relative flex items-center")}>
|
|
301
|
+
{/*TODO: update loading position*/}
|
|
301
302
|
{loadByPages && loading && data && data.length > 0 && (
|
|
302
303
|
<div className="absolute right-3 top-3 z-20 rounded-full bg-background/95 p-2 text-muted-foreground shadow-sm">
|
|
303
304
|
<LoaderCircle className="h-3.5 w-3.5 animate-spin" />
|
|
@@ -327,7 +328,10 @@ export const Carousel: FC<Props> = ({
|
|
|
327
328
|
data.map((item: CommonItemsModel, index: number) => (
|
|
328
329
|
<div
|
|
329
330
|
key={item.shortId}
|
|
330
|
-
className={
|
|
331
|
+
className={cn(
|
|
332
|
+
'flex-shrink-0 flex-grow-0 flex justify-center',
|
|
333
|
+
loading && "opacity-40"
|
|
334
|
+
)}
|
|
331
335
|
style={{ width: `${100 / slidesToShow}%` }}
|
|
332
336
|
>
|
|
333
337
|
<RenderComponent
|
|
@@ -454,7 +458,6 @@ const CarouselIndicators: FC<{ className?: string }> = ({ className }) => {
|
|
|
454
458
|
);
|
|
455
459
|
})}
|
|
456
460
|
</ol>
|
|
457
|
-
{pagedMode && loading && <LoaderCircle className="h-3.5 w-3.5 animate-spin text-muted-foreground" />}
|
|
458
461
|
</div>
|
|
459
462
|
);
|
|
460
463
|
};
|
|
@@ -65,7 +65,7 @@ export const InformationUnitCarouselItem: FC<Props> = ({
|
|
|
65
65
|
<Tooltip>
|
|
66
66
|
<TooltipTrigger asChild>
|
|
67
67
|
<div className="h-44 overflow-hidden">
|
|
68
|
-
<span className="line-clamp-5 text-lg font-semibold group-hover:underline">
|
|
68
|
+
<span className="line-clamp-5 text-lg font-semibold group-hover:underline max-w-full overflow-ellipsis [overflow-wrap:anywhere] hyphens-auto">
|
|
69
69
|
{title}
|
|
70
70
|
</span>
|
|
71
71
|
</div>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { ComponentProps, FC } from "react";
|
|
2
|
+
import { PageWrapper } from "@c-rex/components/page-wrapper";
|
|
3
|
+
import { getTranslations } from "next-intl/server";
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
type Props = Omit<ComponentProps<typeof PageWrapper>, "children">;
|
|
7
|
+
|
|
8
|
+
export const ContentUnavailable: FC<Props> = async ({ ...props }) => {
|
|
9
|
+
const t = await getTranslations();
|
|
10
|
+
|
|
11
|
+
return (
|
|
12
|
+
<PageWrapper {...props}>
|
|
13
|
+
<div className="flex flex-1 justify-center items-center p-4">
|
|
14
|
+
<div className="rounded-md border p-4 text-sm text-muted-foreground">
|
|
15
|
+
{t("contentTemporarilyUnavailableRetry")}
|
|
16
|
+
</div>
|
|
17
|
+
</div>
|
|
18
|
+
</PageWrapper>
|
|
19
|
+
)
|
|
20
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
import { createContext, useContext, useEffect, useMemo, useState, type FC, type PropsWithChildren } from "react";
|
|
4
|
+
import { useTranslations } from "next-intl";
|
|
4
5
|
import { useRouter } from "next/navigation";
|
|
5
6
|
import type { TreeOfContent } from "@c-rex/interfaces";
|
|
6
7
|
import {
|
|
@@ -232,6 +233,7 @@ type DirectoryTreeSidebarMenuProps = {
|
|
|
232
233
|
export const DirectoryTreeSidebarMenu: FC<DirectoryTreeSidebarMenuProps> = ({
|
|
233
234
|
onNavigateNode,
|
|
234
235
|
}) => {
|
|
236
|
+
const t = useTranslations();
|
|
235
237
|
const { tree, isLoading, expandActivePathOnLoad } = useDirectoryTree();
|
|
236
238
|
const [expandedNodeIds, setExpandedNodeIds] = useState<Set<string>>(new Set());
|
|
237
239
|
|
|
@@ -266,7 +268,8 @@ export const DirectoryTreeSidebarMenu: FC<DirectoryTreeSidebarMenuProps> = ({
|
|
|
266
268
|
<Skeleton className="w-auto h-10 mb-2 ml-8" />
|
|
267
269
|
<Skeleton className="w-auto h-10 mb-2 ml-8" />
|
|
268
270
|
<Skeleton className="w-auto h-10 mb-2" />
|
|
269
|
-
|
|
271
|
+
{/*TODO: need this?*/}
|
|
272
|
+
<div className="px-2 pt-1 text-xs text-muted-foreground">{t("loadingTableOfContents")}</div>
|
|
270
273
|
</div>
|
|
271
274
|
);
|
|
272
275
|
}
|
|
@@ -302,7 +305,7 @@ export const DirectoryTreeSidebarMenu: FC<DirectoryTreeSidebarMenuProps> = ({
|
|
|
302
305
|
{node.children?.length ? (
|
|
303
306
|
<button
|
|
304
307
|
type="button"
|
|
305
|
-
aria-label={expandedNodeIds.has(node.id) ? "
|
|
308
|
+
aria-label={expandedNodeIds.has(node.id) ? t("collapseSection") : t("expandSection")}
|
|
306
309
|
className="h-8 w-8 inline-flex items-center justify-center text-muted-foreground hover:text-foreground"
|
|
307
310
|
onClick={() => toggleNode(node.id)}
|
|
308
311
|
>
|
|
@@ -335,11 +338,13 @@ type DirectoryTreeBreadcrumbProps = {
|
|
|
335
338
|
|
|
336
339
|
export const DirectoryTreeBreadcrumb: FC<DirectoryTreeBreadcrumbProps> = ({
|
|
337
340
|
lang,
|
|
338
|
-
homeLabel
|
|
341
|
+
homeLabel,
|
|
339
342
|
onNavigateHome,
|
|
340
343
|
onNavigateNodeId,
|
|
341
344
|
}) => {
|
|
345
|
+
const t = useTranslations();
|
|
342
346
|
const { tree, isLoading } = useDirectoryTree();
|
|
347
|
+
const resolvedHomeLabel = homeLabel ?? t("home");
|
|
343
348
|
const router = useRouter();
|
|
344
349
|
const items = generateBreadcrumbItems(tree);
|
|
345
350
|
|
|
@@ -362,7 +367,7 @@ export const DirectoryTreeBreadcrumb: FC<DirectoryTreeBreadcrumbProps> = ({
|
|
|
362
367
|
<BreadcrumbList>
|
|
363
368
|
<BreadcrumbItem>
|
|
364
369
|
<button type="button" onClick={navigateHome}>
|
|
365
|
-
{
|
|
370
|
+
{resolvedHomeLabel}
|
|
366
371
|
</button>
|
|
367
372
|
</BreadcrumbItem>
|
|
368
373
|
<BreadcrumbSeparator />
|
|
@@ -2,8 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
import { FC, useEffect, useState } from "react";
|
|
4
4
|
import { FragmentsGetByIdClient } from "../generated/client-components";
|
|
5
|
+
import { Skeleton } from "@c-rex/ui/skeleton";
|
|
5
6
|
import { ExpandableSummary } from "./expandable-summary";
|
|
6
7
|
import type { RenditionModel } from "@c-rex/interfaces";
|
|
8
|
+
import { useTranslations } from "next-intl";
|
|
7
9
|
|
|
8
10
|
interface Props {
|
|
9
11
|
fragmentShortId?: string;
|
|
@@ -48,6 +50,7 @@ const DocumentDescriptionPreviewContent: FC<{
|
|
|
48
50
|
isLoading,
|
|
49
51
|
hasError,
|
|
50
52
|
}) => {
|
|
53
|
+
const t = useTranslations();
|
|
51
54
|
const [text, setText] = useState<string | null>(null);
|
|
52
55
|
const [loadingText, setLoadingText] = useState(false);
|
|
53
56
|
|
|
@@ -84,15 +87,20 @@ const DocumentDescriptionPreviewContent: FC<{
|
|
|
84
87
|
}, [title, viewHref]);
|
|
85
88
|
|
|
86
89
|
if (hasError) {
|
|
87
|
-
return <span className="text-muted-foreground">
|
|
90
|
+
return <span className="text-muted-foreground">{t("noRenditionAvailable")}</span>;
|
|
88
91
|
}
|
|
89
92
|
|
|
90
93
|
if (isLoading || loadingText) {
|
|
91
|
-
return
|
|
94
|
+
return (
|
|
95
|
+
<div className="flex flex-col gap-1 pt-1">
|
|
96
|
+
<Skeleton className="h-4 w-full" />
|
|
97
|
+
<Skeleton className="h-4 w-5/6" />
|
|
98
|
+
</div>
|
|
99
|
+
);
|
|
92
100
|
}
|
|
93
101
|
|
|
94
102
|
if (!text) {
|
|
95
|
-
return <span className="text-muted-foreground">
|
|
103
|
+
return <span className="text-muted-foreground">{t("noRenditionAvailable")}</span>;
|
|
96
104
|
}
|
|
97
105
|
|
|
98
106
|
return <ExpandableSummary text={text} />;
|
|
@@ -102,8 +110,10 @@ export const DocumentDescriptionPreview: FC<Props> = ({
|
|
|
102
110
|
fragmentShortId,
|
|
103
111
|
title,
|
|
104
112
|
}) => {
|
|
113
|
+
const t = useTranslations();
|
|
114
|
+
|
|
105
115
|
if (!fragmentShortId) {
|
|
106
|
-
return <span className="text-muted-foreground">
|
|
116
|
+
return <span className="text-muted-foreground">{t("noRenditionAvailable")}</span>;
|
|
107
117
|
}
|
|
108
118
|
|
|
109
119
|
return (
|