@c-rex/components 0.0.11 → 0.1.0
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 +12 -3
- package/src/autocomplete.tsx +1 -1
- package/src/breadcrumb.tsx +7 -5
- package/src/dialog-filter.tsx +102 -0
- package/src/empty.tsx +6 -3
- package/src/navbar/language-switcher/content-language-switch.tsx +35 -0
- package/src/navbar/language-switcher/shared.tsx +33 -0
- package/src/navbar/language-switcher/ui-language-switch.tsx +38 -0
- package/src/navbar/navbar.tsx +88 -33
- package/src/navbar/sign-in-out-btns.tsx +36 -0
- package/src/result-view/blog.tsx +4 -2
- package/src/sidebar.tsx +39 -5
- package/src/navbar/sing-in-out-btns.tsx +0 -29
- package/src/providers/search-state-wrapper.tsx +0 -21
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@c-rex/components",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.1.0",
|
|
4
4
|
"files": [
|
|
5
5
|
"src"
|
|
6
6
|
],
|
|
7
7
|
"publishConfig": {
|
|
8
8
|
"access": "public"
|
|
9
|
-
},
|
|
9
|
+
},
|
|
10
10
|
"sideEffects": false,
|
|
11
11
|
"exports": {
|
|
12
12
|
"./autocomplete": {
|
|
@@ -52,6 +52,10 @@
|
|
|
52
52
|
"./sidebar": {
|
|
53
53
|
"types": "./src/sidebar.tsx",
|
|
54
54
|
"import": "./src/sidebar.tsx"
|
|
55
|
+
},
|
|
56
|
+
"./dialog-filter": {
|
|
57
|
+
"types": "./src/dialog-filter.tsx",
|
|
58
|
+
"import": "./src/dialog-filter.tsx"
|
|
55
59
|
}
|
|
56
60
|
},
|
|
57
61
|
"scripts": {
|
|
@@ -82,13 +86,18 @@
|
|
|
82
86
|
"typescript": "latest"
|
|
83
87
|
},
|
|
84
88
|
"dependencies": {
|
|
89
|
+
"@c-rex/config": "*",
|
|
90
|
+
"@c-rex/constants": "*",
|
|
85
91
|
"@c-rex/contexts": "*",
|
|
86
92
|
"@c-rex/interfaces": "*",
|
|
87
93
|
"@c-rex/services": "*",
|
|
88
94
|
"@c-rex/ui": "*",
|
|
89
95
|
"@c-rex/utils": "*",
|
|
90
|
-
"
|
|
96
|
+
"country-flag-icons": "^1.5.19",
|
|
97
|
+
"lucide-react": "^0.511.0",
|
|
91
98
|
"next": "^14",
|
|
99
|
+
"next-intl": "^4.1.0",
|
|
100
|
+
"nuqs": "^2.4.3",
|
|
92
101
|
"react": "^18",
|
|
93
102
|
"react-dom": "^18",
|
|
94
103
|
"tailwindcss-animate": "^1.0.7"
|
package/src/autocomplete.tsx
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import React from "react";
|
|
1
2
|
import { Command as CommandPrimitive } from "cmdk";
|
|
2
3
|
import { Check } from "lucide-react";
|
|
3
4
|
import { useEffect, useState } from "react";
|
|
@@ -28,7 +29,6 @@ export const AutoComplete = ({
|
|
|
28
29
|
}: Props) => {
|
|
29
30
|
const [query, setQuery] = useState(initialValue);
|
|
30
31
|
const [suggestions, setSuggestions] = useState<string[]>([]);
|
|
31
|
-
|
|
32
32
|
const [open, setOpen] = useState(false);
|
|
33
33
|
|
|
34
34
|
useEffect(() => {
|
package/src/breadcrumb.tsx
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { FC, ReactNode } from "react";
|
|
1
|
+
import React, { FC, Fragment, ReactNode } from "react";
|
|
2
2
|
import {
|
|
3
3
|
Breadcrumb as BreadcrumbComponent,
|
|
4
4
|
BreadcrumbItem,
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
} from "@c-rex/ui/breadcrumb";
|
|
10
10
|
import { Skeleton } from "@c-rex/ui/skeleton";
|
|
11
11
|
import { TreeOfContent } from "@c-rex/interfaces";
|
|
12
|
+
import { useTranslations } from 'next-intl';
|
|
12
13
|
|
|
13
14
|
interface BreadcrumbProps {
|
|
14
15
|
items: TreeOfContent[];
|
|
@@ -16,6 +17,7 @@ interface BreadcrumbProps {
|
|
|
16
17
|
}
|
|
17
18
|
|
|
18
19
|
export const Breadcrumb: FC<BreadcrumbProps> = ({ items, loading }) => {
|
|
20
|
+
const t = useTranslations("breadcrumbs");
|
|
19
21
|
if (!items) {
|
|
20
22
|
return null;
|
|
21
23
|
}
|
|
@@ -25,7 +27,7 @@ export const Breadcrumb: FC<BreadcrumbProps> = ({ items, loading }) => {
|
|
|
25
27
|
<BreadcrumbComponent>
|
|
26
28
|
<BreadcrumbList>
|
|
27
29
|
<BreadcrumbItem>
|
|
28
|
-
<BreadcrumbPage>
|
|
30
|
+
<BreadcrumbPage>{t("home")}</BreadcrumbPage>
|
|
29
31
|
</BreadcrumbItem>
|
|
30
32
|
<BreadcrumbSeparator />
|
|
31
33
|
<BreadcrumbItem>
|
|
@@ -42,7 +44,7 @@ export const Breadcrumb: FC<BreadcrumbProps> = ({ items, loading }) => {
|
|
|
42
44
|
|
|
43
45
|
const homeItem: TreeOfContent = {
|
|
44
46
|
link: "/",
|
|
45
|
-
label: "
|
|
47
|
+
label: t("home"),
|
|
46
48
|
id: "home",
|
|
47
49
|
active: false,
|
|
48
50
|
children: [],
|
|
@@ -65,14 +67,14 @@ export const Breadcrumb: FC<BreadcrumbProps> = ({ items, loading }) => {
|
|
|
65
67
|
const isLast = index === newItemList.length - 1;
|
|
66
68
|
|
|
67
69
|
return (
|
|
68
|
-
|
|
70
|
+
<Fragment key={`${item.label}-fragment`}>
|
|
69
71
|
<BreadcrumbItem key={`${item.label}-item`}>
|
|
70
72
|
{renderLink(!isLast, item)}
|
|
71
73
|
</BreadcrumbItem>
|
|
72
74
|
{!isLast && (
|
|
73
75
|
<BreadcrumbSeparator key={`${item.label}-separator`} />
|
|
74
76
|
)}
|
|
75
|
-
|
|
77
|
+
</Fragment>
|
|
76
78
|
);
|
|
77
79
|
})}
|
|
78
80
|
</BreadcrumbList>
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import React, { FC, useState } from "react"
|
|
2
|
+
import { Button } from "@c-rex/ui/button"
|
|
3
|
+
import {
|
|
4
|
+
Dialog,
|
|
5
|
+
DialogClose,
|
|
6
|
+
DialogContent,
|
|
7
|
+
DialogFooter,
|
|
8
|
+
DialogHeader,
|
|
9
|
+
DialogTitle,
|
|
10
|
+
DialogTrigger,
|
|
11
|
+
} from "@c-rex/ui/dialog"
|
|
12
|
+
import { Checkbox } from "@c-rex/ui/checkbox"
|
|
13
|
+
import { Label } from "@c-rex/ui/label"
|
|
14
|
+
import { useQueryState } from "nuqs"
|
|
15
|
+
import { useTranslations } from "next-intl"
|
|
16
|
+
|
|
17
|
+
interface DialogFilterProps {
|
|
18
|
+
trigger: React.ReactNode;
|
|
19
|
+
startSelectedLanguages: string[];
|
|
20
|
+
availableLanguages: any;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export const DialogFilter: FC<DialogFilterProps> = ({
|
|
24
|
+
trigger,
|
|
25
|
+
startSelectedLanguages,
|
|
26
|
+
availableLanguages,
|
|
27
|
+
}) => {
|
|
28
|
+
const t = useTranslations();
|
|
29
|
+
|
|
30
|
+
const [_, setContentLanguage] = useQueryState('language', {
|
|
31
|
+
history: 'push',
|
|
32
|
+
shallow: false,
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
const [languages, setLanguages] = useState(availableLanguages.map((item: any) => {
|
|
36
|
+
const checked = startSelectedLanguages.includes(item.value)
|
|
37
|
+
return {
|
|
38
|
+
lang: item.lang,
|
|
39
|
+
value: item.value,
|
|
40
|
+
checked,
|
|
41
|
+
}
|
|
42
|
+
}));
|
|
43
|
+
|
|
44
|
+
const onChange = (item: any) => {
|
|
45
|
+
const newLang = languages.filter((lang: any) => lang.lang !== item.lang)
|
|
46
|
+
setLanguages([...newLang, item].sort((a, b) => {
|
|
47
|
+
return a.value.localeCompare(b.value)
|
|
48
|
+
}))
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const apply = () => {
|
|
52
|
+
const selectedLanguages = languages.filter((item: any) => item.checked).map((item: any) => item.value).join(',')
|
|
53
|
+
setContentLanguage(selectedLanguages)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return (
|
|
57
|
+
<Dialog>
|
|
58
|
+
<DialogTrigger asChild>
|
|
59
|
+
{trigger}
|
|
60
|
+
</DialogTrigger>
|
|
61
|
+
<DialogContent>
|
|
62
|
+
<DialogHeader>
|
|
63
|
+
<DialogTitle>{t("filters")}</DialogTitle>
|
|
64
|
+
</DialogHeader>
|
|
65
|
+
<div className="grid grid-cols-2 items-center py-4">
|
|
66
|
+
<Label className="text-right">
|
|
67
|
+
{t("languages")}:
|
|
68
|
+
</Label>
|
|
69
|
+
<div className="flex items-center">
|
|
70
|
+
{languages?.map((item: any, index: any) => {
|
|
71
|
+
return (
|
|
72
|
+
<div key={index} className="mr-4">
|
|
73
|
+
<Checkbox
|
|
74
|
+
id={`available-languages${item.lang}`}
|
|
75
|
+
className="mr-2"
|
|
76
|
+
{...({ checked: item.checked })}
|
|
77
|
+
onCheckedChange={(checked: boolean) => onChange({
|
|
78
|
+
...item,
|
|
79
|
+
checked: checked,
|
|
80
|
+
})}
|
|
81
|
+
/>
|
|
82
|
+
<label
|
|
83
|
+
htmlFor={`available-languages${item.lang}`}
|
|
84
|
+
className="text-sm font-medium "
|
|
85
|
+
>
|
|
86
|
+
{item.lang.toUpperCase()}
|
|
87
|
+
</label>
|
|
88
|
+
</div>
|
|
89
|
+
)
|
|
90
|
+
})}
|
|
91
|
+
</div>
|
|
92
|
+
|
|
93
|
+
</div>
|
|
94
|
+
<DialogFooter>
|
|
95
|
+
<DialogClose asChild>
|
|
96
|
+
<Button onClick={apply}>{t("applyFilters")}</Button>
|
|
97
|
+
</DialogClose>
|
|
98
|
+
</DialogFooter>
|
|
99
|
+
</DialogContent>
|
|
100
|
+
</Dialog>
|
|
101
|
+
)
|
|
102
|
+
}
|
package/src/empty.tsx
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
|
-
import { FC } from "react";
|
|
1
|
+
import React, { FC } from "react";
|
|
2
2
|
import { Alert, AlertDescription, AlertTitle } from "@c-rex/ui/alert";
|
|
3
|
+
import { useTranslations } from "next-intl";
|
|
3
4
|
|
|
4
5
|
export const Empty: FC = () => {
|
|
6
|
+
const t = useTranslations("results")
|
|
7
|
+
|
|
5
8
|
return (
|
|
6
9
|
<Alert className="my-2">
|
|
7
|
-
<AlertTitle>
|
|
10
|
+
<AlertTitle>{t("noResultsTitle")}</AlertTitle>
|
|
8
11
|
<AlertDescription>
|
|
9
|
-
|
|
12
|
+
{t("noResultsDescription")}
|
|
10
13
|
</AlertDescription>
|
|
11
14
|
</Alert>
|
|
12
15
|
);
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import React, { FC, startTransition } from "react";
|
|
4
|
+
import { LanguageAndCountries } from "@c-rex/interfaces";
|
|
5
|
+
import { SharedLanguageSwitch } from "./shared";
|
|
6
|
+
import { setCookie } from "@c-rex/utils/next-cookies";
|
|
7
|
+
import { CONTENT_LANG_KEY, DEFAULT_UI_LANG } from "@c-rex/constants";
|
|
8
|
+
import { useQueryState } from "nuqs"
|
|
9
|
+
|
|
10
|
+
interface ContentLanguageSwitchProps {
|
|
11
|
+
availableLanguagesAndCountries: LanguageAndCountries[];
|
|
12
|
+
}
|
|
13
|
+
export const ContentLanguageSwitch: FC<ContentLanguageSwitchProps> = ({ availableLanguagesAndCountries }) => {
|
|
14
|
+
|
|
15
|
+
const [contentLanguage, setContentLanguage] = useQueryState('language', {
|
|
16
|
+
history: 'push',
|
|
17
|
+
shallow: false,
|
|
18
|
+
defaultValue: DEFAULT_UI_LANG
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
const changeContentLanguage = (locale: string) => {
|
|
22
|
+
startTransition(() => {
|
|
23
|
+
setCookie(CONTENT_LANG_KEY, locale)
|
|
24
|
+
setContentLanguage(locale)
|
|
25
|
+
});
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
return (
|
|
29
|
+
<SharedLanguageSwitch
|
|
30
|
+
availableLanguagesAndCountries={availableLanguagesAndCountries}
|
|
31
|
+
changeLanguage={changeContentLanguage}
|
|
32
|
+
selected={contentLanguage}
|
|
33
|
+
/>
|
|
34
|
+
);
|
|
35
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import React, { FC, JSX } from "react";
|
|
2
|
+
import * as Flags from 'country-flag-icons/react/3x2';
|
|
3
|
+
import { LanguageAndCountries } from "@c-rex/interfaces";
|
|
4
|
+
import { DropdownMenuRadioGroup, DropdownMenuRadioItem } from "@c-rex/ui/dropdown-menu";
|
|
5
|
+
|
|
6
|
+
interface SharedLanguageSwitchProps {
|
|
7
|
+
availableLanguagesAndCountries: LanguageAndCountries[];
|
|
8
|
+
selected: string;
|
|
9
|
+
changeLanguage: (locale: string) => void;
|
|
10
|
+
}
|
|
11
|
+
export const SharedLanguageSwitch: FC<SharedLanguageSwitchProps> = ({ availableLanguagesAndCountries, changeLanguage, selected }) => {
|
|
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
|
+
return (
|
|
22
|
+
<DropdownMenuRadioGroup value={selected} onValueChange={changeLanguage}>
|
|
23
|
+
{availableLanguagesAndCountries.map(item => {
|
|
24
|
+
return (
|
|
25
|
+
<DropdownMenuRadioItem key={item.value} value={item.value}>
|
|
26
|
+
<span>{item.lang.toUpperCase()}</span>
|
|
27
|
+
{getFlagIcon(item.country)}
|
|
28
|
+
</DropdownMenuRadioItem>
|
|
29
|
+
)
|
|
30
|
+
})}
|
|
31
|
+
</DropdownMenuRadioGroup>
|
|
32
|
+
);
|
|
33
|
+
};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import React, { FC, startTransition, useEffect, useState } from "react";
|
|
4
|
+
import { LanguageAndCountries } from "@c-rex/interfaces";
|
|
5
|
+
import { SharedLanguageSwitch } from "./shared";
|
|
6
|
+
import { setCookie } from "@c-rex/utils/next-cookies";
|
|
7
|
+
import { DEFAULT_UI_LANG, UI_LANG_KEY } from "@c-rex/constants";
|
|
8
|
+
|
|
9
|
+
interface UILanguageSwitchProps {
|
|
10
|
+
availableLanguagesAndCountries: LanguageAndCountries[];
|
|
11
|
+
}
|
|
12
|
+
export const UILanguageSwitch: FC<UILanguageSwitchProps> = ({ availableLanguagesAndCountries }) => {
|
|
13
|
+
const [selected, setSelected] = useState(DEFAULT_UI_LANG);
|
|
14
|
+
|
|
15
|
+
useEffect(() => {
|
|
16
|
+
const allCookies = document.cookie
|
|
17
|
+
const uiLang = allCookies
|
|
18
|
+
.split('; ')
|
|
19
|
+
.find(row => row.startsWith(`${UI_LANG_KEY}=`))
|
|
20
|
+
?.split('=')[1]
|
|
21
|
+
setSelected(uiLang as string)
|
|
22
|
+
}, [])
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
const setUILanguage = (locale: string) => {
|
|
26
|
+
startTransition(() => {
|
|
27
|
+
setCookie(UI_LANG_KEY, locale)
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return (
|
|
32
|
+
<SharedLanguageSwitch
|
|
33
|
+
availableLanguagesAndCountries={availableLanguagesAndCountries}
|
|
34
|
+
changeLanguage={setUILanguage}
|
|
35
|
+
selected={selected}
|
|
36
|
+
/>
|
|
37
|
+
);
|
|
38
|
+
};
|
package/src/navbar/navbar.tsx
CHANGED
|
@@ -1,9 +1,28 @@
|
|
|
1
1
|
import React, { FC } from "react";
|
|
2
2
|
import Link from "next/link";
|
|
3
3
|
import Image from "next/image";
|
|
4
|
-
import {
|
|
4
|
+
import { SignOut, SignInBtn } from "./sign-in-out-btns";
|
|
5
5
|
import { getServerSession } from "next-auth";
|
|
6
|
-
|
|
6
|
+
import { getCookie } from '@c-rex/utils/next-cookies';
|
|
7
|
+
import { ConfigInterface } from "@c-rex/interfaces";
|
|
8
|
+
import {
|
|
9
|
+
DropdownMenu,
|
|
10
|
+
DropdownMenuContent,
|
|
11
|
+
DropdownMenuLabel,
|
|
12
|
+
DropdownMenuPortal,
|
|
13
|
+
DropdownMenuSeparator,
|
|
14
|
+
DropdownMenuSub,
|
|
15
|
+
DropdownMenuSubContent,
|
|
16
|
+
DropdownMenuSubTrigger,
|
|
17
|
+
DropdownMenuTrigger,
|
|
18
|
+
} from "@c-rex/ui/dropdown-menu"
|
|
19
|
+
import { SDK_CONFIG_KEY, UI_LANG_OPTIONS } from "@c-rex/constants";
|
|
20
|
+
import { LanguageService } from "@c-rex/services";
|
|
21
|
+
import { Settings } from "lucide-react";
|
|
22
|
+
import { ContentLanguageSwitch } from "./language-switcher/content-language-switch";
|
|
23
|
+
import { getTranslations } from "next-intl/server";
|
|
24
|
+
import { getCountryCodeByLang } from "@c-rex/utils";
|
|
25
|
+
import { UILanguageSwitch } from "./language-switcher/ui-language-switch";
|
|
7
26
|
|
|
8
27
|
interface NavBarProps {
|
|
9
28
|
scroll?: boolean;
|
|
@@ -11,8 +30,25 @@ interface NavBarProps {
|
|
|
11
30
|
}
|
|
12
31
|
|
|
13
32
|
export const NavBar: FC<NavBarProps> = async () => {
|
|
33
|
+
const t = await getTranslations();
|
|
14
34
|
const session = await getServerSession()
|
|
15
35
|
|
|
36
|
+
const jsonConfigs = await getCookie(SDK_CONFIG_KEY);
|
|
37
|
+
if (!jsonConfigs) {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const configs: ConfigInterface = JSON.parse(jsonConfigs);
|
|
42
|
+
const service = new LanguageService(configs.languageSwitcher.endpoint);
|
|
43
|
+
const contentLanguages = await service.getLanguagesAndCountries();
|
|
44
|
+
|
|
45
|
+
const UILanguages = UI_LANG_OPTIONS.map((lang) => ({
|
|
46
|
+
value: lang,
|
|
47
|
+
lang: lang,
|
|
48
|
+
country: getCountryCodeByLang(lang)
|
|
49
|
+
}));
|
|
50
|
+
|
|
51
|
+
|
|
16
52
|
return (
|
|
17
53
|
<header className="sticky top-0 z-40 flex w-full bg-background/60 backdrop-blur-xl transition-all bg-transparent border-b justify-center py-4">
|
|
18
54
|
<div className="container flex justify-between">
|
|
@@ -25,42 +61,61 @@ export const NavBar: FC<NavBarProps> = async () => {
|
|
|
25
61
|
height={50}
|
|
26
62
|
/>
|
|
27
63
|
</Link>
|
|
28
|
-
|
|
29
|
-
<nav className="hidden gap-6 md:flex">
|
|
30
|
-
{/*
|
|
31
|
-
TODO: add map to load links
|
|
32
|
-
TODO: add function to validate active item
|
|
33
|
-
*/}
|
|
34
|
-
<Link
|
|
35
|
-
href={"/blog"}
|
|
36
|
-
prefetch={true}
|
|
37
|
-
className={
|
|
38
|
-
"flex items-center text-lg font-medium transition-colors hover:text-foreground/80 sm:text-sm"
|
|
39
|
-
}
|
|
40
|
-
>
|
|
41
|
-
Blog
|
|
42
|
-
</Link>
|
|
43
|
-
|
|
44
|
-
<Link
|
|
45
|
-
href={"#"}
|
|
46
|
-
prefetch={true}
|
|
47
|
-
className={
|
|
48
|
-
"flex items-center text-lg font-medium transition-colors hover:text-foreground/80 sm:text-sm"
|
|
49
|
-
}
|
|
50
|
-
>
|
|
51
|
-
Documentation
|
|
52
|
-
</Link>
|
|
53
|
-
</nav>
|
|
54
64
|
</div>
|
|
55
65
|
|
|
56
66
|
<div className="flex items-center space-x-3">
|
|
57
|
-
{
|
|
67
|
+
{configs.OIDC.user.enabled && (
|
|
58
68
|
<>
|
|
59
|
-
|
|
60
|
-
|
|
69
|
+
{session ? (
|
|
70
|
+
<>
|
|
71
|
+
<span>{t("user.welcome", { userName: session.user?.name as string })}</span>
|
|
72
|
+
<SignOut />
|
|
73
|
+
</>
|
|
74
|
+
) : (
|
|
75
|
+
<SignInBtn />
|
|
76
|
+
)}
|
|
61
77
|
</>
|
|
62
|
-
)
|
|
63
|
-
|
|
78
|
+
)}
|
|
79
|
+
|
|
80
|
+
{configs.languageSwitcher.enabled && (
|
|
81
|
+
<DropdownMenu>
|
|
82
|
+
<DropdownMenuTrigger>
|
|
83
|
+
<Settings />
|
|
84
|
+
</DropdownMenuTrigger>
|
|
85
|
+
<DropdownMenuContent>
|
|
86
|
+
<DropdownMenuLabel>{t("accountSettings.accountSettings")}</DropdownMenuLabel>
|
|
87
|
+
<DropdownMenuSeparator />
|
|
88
|
+
|
|
89
|
+
<DropdownMenuSub>
|
|
90
|
+
<DropdownMenuSubTrigger>
|
|
91
|
+
<span>{t("accountSettings.contentLanguage")}</span>
|
|
92
|
+
</DropdownMenuSubTrigger>
|
|
93
|
+
|
|
94
|
+
<DropdownMenuPortal>
|
|
95
|
+
<DropdownMenuSubContent>
|
|
96
|
+
<ContentLanguageSwitch
|
|
97
|
+
availableLanguagesAndCountries={contentLanguages}
|
|
98
|
+
/>
|
|
99
|
+
</DropdownMenuSubContent>
|
|
100
|
+
</DropdownMenuPortal>
|
|
101
|
+
</DropdownMenuSub>
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
<DropdownMenuSub>
|
|
105
|
+
<DropdownMenuSubTrigger>
|
|
106
|
+
<span>{t("accountSettings.uiLanguage")}</span>
|
|
107
|
+
</DropdownMenuSubTrigger>
|
|
108
|
+
|
|
109
|
+
<DropdownMenuPortal>
|
|
110
|
+
<DropdownMenuSubContent>
|
|
111
|
+
<UILanguageSwitch
|
|
112
|
+
availableLanguagesAndCountries={UILanguages}
|
|
113
|
+
/>
|
|
114
|
+
</DropdownMenuSubContent>
|
|
115
|
+
</DropdownMenuPortal>
|
|
116
|
+
</DropdownMenuSub>
|
|
117
|
+
</DropdownMenuContent>
|
|
118
|
+
</DropdownMenu>
|
|
64
119
|
)}
|
|
65
120
|
</div>
|
|
66
121
|
</div>
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import React from "react";
|
|
4
|
+
import { signOut, signIn } from "next-auth/react";
|
|
5
|
+
import { Button } from "@c-rex/ui/button";
|
|
6
|
+
import { useTranslations } from "next-intl";
|
|
7
|
+
|
|
8
|
+
export const SignInBtn = () => {
|
|
9
|
+
const t = useTranslations("user")
|
|
10
|
+
return (
|
|
11
|
+
<Button
|
|
12
|
+
className="gap-2 px-5 md:flex"
|
|
13
|
+
variant="default"
|
|
14
|
+
size="sm"
|
|
15
|
+
rounded="full"
|
|
16
|
+
onClick={() => signIn("crex", { callbackUrl: "/" })}
|
|
17
|
+
>
|
|
18
|
+
<span>{t("signIn")}</span>
|
|
19
|
+
</Button>
|
|
20
|
+
);
|
|
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/result-view/blog.tsx
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { FC } from "react";
|
|
2
|
-
|
|
1
|
+
import React, { FC } from "react";
|
|
3
2
|
import { BlogCard } from "../blog-card";
|
|
4
3
|
import { informationUnitsItems, Labels } from "@c-rex/interfaces";
|
|
5
4
|
|
|
@@ -9,6 +8,9 @@ interface BlogViewProps {
|
|
|
9
8
|
|
|
10
9
|
const BlogView: FC<BlogViewProps> = ({ items }) => {
|
|
11
10
|
const getTitle = (labels: Labels[]): string => {
|
|
11
|
+
if (labels === undefined) {
|
|
12
|
+
return "";
|
|
13
|
+
}
|
|
12
14
|
return labels.map((item) => item.value).join();
|
|
13
15
|
};
|
|
14
16
|
|
package/src/sidebar.tsx
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
import { ComponentProps } from "react";
|
|
3
|
+
import React, { ComponentProps, JSX } from "react";
|
|
4
4
|
import {
|
|
5
5
|
Sidebar,
|
|
6
6
|
SidebarContent,
|
|
7
7
|
SidebarGroup,
|
|
8
|
+
SidebarGroupLabel,
|
|
8
9
|
SidebarMenu,
|
|
9
10
|
SidebarMenuButton,
|
|
10
11
|
SidebarMenuItem,
|
|
@@ -15,18 +16,32 @@ import {
|
|
|
15
16
|
} from "@c-rex/ui/sidebar";
|
|
16
17
|
import { Skeleton } from "@c-rex/ui/skeleton";
|
|
17
18
|
import { TreeOfContent } from "@c-rex/interfaces";
|
|
19
|
+
import * as Flags from 'country-flag-icons/react/3x2';
|
|
20
|
+
import { useTranslations } from "next-intl";
|
|
18
21
|
|
|
19
22
|
interface SidebarProps extends ComponentProps<typeof Sidebar> {
|
|
20
23
|
data: TreeOfContent[];
|
|
21
24
|
loading?: boolean;
|
|
25
|
+
availableVersions: any
|
|
22
26
|
}
|
|
23
27
|
|
|
24
|
-
export function AppSidebar({ data, loading, ...props }: SidebarProps) {
|
|
28
|
+
export function AppSidebar({ data, availableVersions, loading, ...props }: SidebarProps) {
|
|
29
|
+
const t = useTranslations();
|
|
30
|
+
|
|
31
|
+
const getFlagIcon = (countryCode: string): JSX.Element | null => {
|
|
32
|
+
type CountryCode = keyof typeof Flags;
|
|
33
|
+
const FlagComponent = Flags[countryCode as CountryCode];
|
|
34
|
+
if (!FlagComponent) return null;
|
|
35
|
+
|
|
36
|
+
return <FlagComponent />;
|
|
37
|
+
};
|
|
38
|
+
|
|
25
39
|
return (
|
|
26
|
-
<Sidebar collapsible="icon" {...props}
|
|
40
|
+
<Sidebar collapsible="icon" {...props}>
|
|
27
41
|
<SidebarContent>
|
|
28
|
-
<SidebarGroup>
|
|
29
|
-
<
|
|
42
|
+
<SidebarGroup className="my-4">
|
|
43
|
+
<SidebarGroupLabel>{t("tableOfContent")}:</SidebarGroupLabel>
|
|
44
|
+
<SidebarMenu>
|
|
30
45
|
{loading ? (
|
|
31
46
|
<>
|
|
32
47
|
<Skeleton className="w-auto h-10 mb-2" />
|
|
@@ -69,6 +84,25 @@ export function AppSidebar({ data, loading, ...props }: SidebarProps) {
|
|
|
69
84
|
)}
|
|
70
85
|
</SidebarMenu>
|
|
71
86
|
</SidebarGroup>
|
|
87
|
+
|
|
88
|
+
<SidebarGroup>
|
|
89
|
+
<SidebarGroupLabel>{t("availableIn")}:</SidebarGroupLabel>
|
|
90
|
+
<SidebarMenu>
|
|
91
|
+
|
|
92
|
+
{availableVersions.map((item: any) => {
|
|
93
|
+
return (
|
|
94
|
+
|
|
95
|
+
<SidebarMenuItem key={item.shortId}>
|
|
96
|
+
<SidebarMenuButton asChild isActive={item.active}>
|
|
97
|
+
<a href={`../info/${item.shortId}`} title={item.lang}>
|
|
98
|
+
{getFlagIcon(item.country)} {item.lang}
|
|
99
|
+
</a>
|
|
100
|
+
</SidebarMenuButton>
|
|
101
|
+
</SidebarMenuItem>
|
|
102
|
+
)
|
|
103
|
+
})}
|
|
104
|
+
</SidebarMenu>
|
|
105
|
+
</SidebarGroup>
|
|
72
106
|
</SidebarContent>
|
|
73
107
|
<SidebarRail />
|
|
74
108
|
</Sidebar>
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
"use client"
|
|
2
|
-
|
|
3
|
-
import React from "react";
|
|
4
|
-
import { signOut, signIn } from "next-auth/react";
|
|
5
|
-
import { Button } from "@c-rex/ui/button";
|
|
6
|
-
|
|
7
|
-
export const SingInBtn = () => (
|
|
8
|
-
<Button
|
|
9
|
-
className="hidden gap-2 px-5 md:flex"
|
|
10
|
-
variant="default"
|
|
11
|
-
size="sm"
|
|
12
|
-
rounded="full"
|
|
13
|
-
onClick={() => signIn("crex", { callbackUrl: "/" })}
|
|
14
|
-
>
|
|
15
|
-
<span>Sign In</span>
|
|
16
|
-
</Button>
|
|
17
|
-
);
|
|
18
|
-
|
|
19
|
-
export const SingOut = () => (
|
|
20
|
-
<Button
|
|
21
|
-
className="hidden gap-2 px-5 md:flex"
|
|
22
|
-
variant="default"
|
|
23
|
-
size="sm"
|
|
24
|
-
rounded="full"
|
|
25
|
-
onClick={() => signOut()}
|
|
26
|
-
>
|
|
27
|
-
<span>Sign out</span>
|
|
28
|
-
</Button>
|
|
29
|
-
);
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
|
|
3
|
-
import { SearchProvider } from "@c-rex/contexts";
|
|
4
|
-
import { FC, ReactNode } from "react";
|
|
5
|
-
|
|
6
|
-
interface SearchStateWrapperProps {
|
|
7
|
-
children: ReactNode;
|
|
8
|
-
filters: {
|
|
9
|
-
searchValue: string;
|
|
10
|
-
page: number;
|
|
11
|
-
selectedLanguage: string[];
|
|
12
|
-
availableLanguages: string[];
|
|
13
|
-
};
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export const SearchStateWrapper: FC<SearchStateWrapperProps> = ({
|
|
17
|
-
children,
|
|
18
|
-
filters,
|
|
19
|
-
}) => {
|
|
20
|
-
return <SearchProvider value={{ ...filters }}>{children}</SearchProvider>;
|
|
21
|
-
};
|