@c-rex/components 0.1.28 → 0.1.30
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 +9 -1
- package/src/article/article-action-bar.stories.tsx +15 -0
- package/src/article/article-content.stories.tsx +21 -0
- package/src/autocomplete.tsx +8 -5
- package/src/carousel/carousel.tsx +344 -0
- package/src/check-article-lang.tsx +5 -5
- package/src/directoryNodes/tree-of-content.stories.tsx +22 -0
- package/src/directoryNodes/tree-of-content.tsx +2 -2
- package/src/documents/result-list.stories.tsx +19 -0
- package/src/documents/result-list.tsx +23 -33
- package/src/favorites/bookmark-button.stories.tsx +19 -0
- package/src/favorites/favorite-button.stories.tsx +22 -0
- package/src/icons/file-icon.stories.tsx +19 -0
- package/src/icons/flag-icon.stories.tsx +25 -0
- package/src/icons/loading.stories.tsx +21 -0
- package/src/info/info-table.tsx +2 -69
- package/src/info/stories/info-table.stories.tsx +31 -0
- package/src/info/stories/shared.stories.tsx +24 -0
- package/src/navbar/language-switcher/content-language-switch.tsx +3 -7
- package/src/navbar/language-switcher/ui-language-switch.tsx +2 -2
- package/src/navbar/navbar.tsx +76 -35
- package/src/navbar/stories/navbar.stories.tsx +21 -6
- package/src/navbar/stories/settings.stories.tsx +15 -0
- package/src/navbar/stories/sign-in-out-btns.stories.tsx +15 -0
- package/src/navbar/stories/user-menu.stories.tsx +20 -0
- package/src/page-wrapper.tsx +10 -14
- package/src/renditions/file-download.stories.tsx +19 -0
- package/src/renditions/html.stories.tsx +19 -0
- package/src/renditions/html.tsx +12 -9
- package/src/renditions/image/container.stories.tsx +19 -0
- package/src/renditions/image/container.tsx +6 -3
- package/src/renditions/image/rendition.stories.tsx +19 -0
- package/src/renditions/image/rendition.tsx +9 -14
- package/src/restriction-menu/restriction-menu-item.tsx +89 -0
- package/src/restriction-menu/restriction-menu.tsx +157 -0
- package/src/results/cards.tsx +1 -1
- package/src/results/dialog-filter.tsx +30 -67
- package/src/results/filter-navbar.tsx +12 -15
- package/src/results/generic/table-result-list.stories.tsx +21 -0
- package/src/results/generic/table-result-list.tsx +31 -28
- package/src/results/stories/cards.stories.tsx +16 -8
- package/src/results/stories/dialog-filter.stories.tsx +20 -0
- package/src/results/stories/empty.stories.tsx +12 -1
- package/src/results/stories/filter-navbar.stories.tsx +19 -0
- package/src/results/stories/filter-sidebar.stories.tsx +20 -0
- package/src/results/stories/pagination.stories.tsx +24 -0
- package/src/results/stories/table-with-images.stories.tsx +19 -0
- package/src/results/stories/table.stories.tsx +32 -9
- package/src/results/table-with-images.tsx +2 -16
- package/src/search-input.tsx +33 -12
- package/src/stores/language-store.ts +33 -16
- package/src/stores/search-settings-store.ts +49 -8
- package/src/stories/autocomplete.stories.tsx +20 -0
- package/src/stories/breadcrumb.stories.tsx +72 -31
- package/src/stories/check-article-lang.stories.tsx +22 -0
- package/src/stories/render-article.stories.tsx +19 -0
- package/src/stories/search-input.stories.tsx +21 -0
- package/src/stories/share-button.stories.tsx +15 -0
- package/src/results/result-container.tsx +0 -70
|
@@ -1,35 +1,28 @@
|
|
|
1
1
|
import { FC } from "react";
|
|
2
|
-
import {
|
|
3
|
-
|
|
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";
|
|
2
|
+
import { CommonItemsModel } from "@c-rex/interfaces";
|
|
3
|
+
import { cn, generateQueryParams, getLanguage, getTitle, getType } from "@c-rex/utils";
|
|
11
4
|
import { Flag } from "@c-rex/components/flag";
|
|
12
5
|
import { Badge } from "@c-rex/ui/badge";
|
|
13
|
-
import { RESULT_TYPES } from "@c-rex/constants";
|
|
14
6
|
import Link from "next/link";
|
|
15
7
|
import { FileDownloadDropdown } from "@c-rex/components/file-download";
|
|
16
8
|
import { getTranslations } from "next-intl/server";
|
|
9
|
+
import { QueryParams } from "@c-rex/types";
|
|
17
10
|
|
|
18
11
|
interface Props {
|
|
19
|
-
items:
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
FragmentModel |
|
|
23
|
-
InformationUnitModel |
|
|
24
|
-
PackageModel |
|
|
25
|
-
TopicModel
|
|
26
|
-
)[];
|
|
27
|
-
query: string;
|
|
28
|
-
linkPath: string;
|
|
12
|
+
items: CommonItemsModel[];
|
|
13
|
+
linkPattern: string;
|
|
14
|
+
addPackageId: boolean
|
|
29
15
|
showFilesColumn?: boolean;
|
|
16
|
+
query?: string
|
|
30
17
|
}
|
|
31
18
|
|
|
32
|
-
export const GenericTableResultList: FC<Props> = async ({
|
|
19
|
+
export const GenericTableResultList: FC<Props> = async ({
|
|
20
|
+
items,
|
|
21
|
+
linkPattern,
|
|
22
|
+
addPackageId,
|
|
23
|
+
query,
|
|
24
|
+
showFilesColumn = true,
|
|
25
|
+
}) => {
|
|
33
26
|
const t = await getTranslations("results");
|
|
34
27
|
|
|
35
28
|
return (
|
|
@@ -48,15 +41,25 @@ export const GenericTableResultList: FC<Props> = async ({ items, query, linkPath
|
|
|
48
41
|
const itemType = getType(item.class);
|
|
49
42
|
const language = getLanguage(item.languages);
|
|
50
43
|
const packageId = item.packages && item.packages.length > 0 ? item.packages[0]?.shortId : null;
|
|
44
|
+
const queryParams: QueryParams[] = []
|
|
51
45
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
46
|
+
if (addPackageId && packageId) {
|
|
47
|
+
queryParams.push({
|
|
48
|
+
key: "package",
|
|
49
|
+
value: packageId,
|
|
50
|
+
})
|
|
51
|
+
}
|
|
56
52
|
|
|
57
|
-
if (
|
|
58
|
-
|
|
53
|
+
if (query != undefined) {
|
|
54
|
+
queryParams.push({
|
|
55
|
+
key: "q",
|
|
56
|
+
value: query,
|
|
57
|
+
})
|
|
59
58
|
}
|
|
59
|
+
|
|
60
|
+
const params = generateQueryParams(queryParams)
|
|
61
|
+
const link = linkPattern.replace("{id}", item.shortId!) + (params.length > 0 ? `?${params}` : "")
|
|
62
|
+
|
|
60
63
|
return (
|
|
61
64
|
<div
|
|
62
65
|
className={cn(
|
|
@@ -66,7 +69,7 @@ export const GenericTableResultList: FC<Props> = async ({ items, query, linkPath
|
|
|
66
69
|
key={index}
|
|
67
70
|
>
|
|
68
71
|
<div className="flex-1 p-2">
|
|
69
|
-
<Link href={
|
|
72
|
+
<Link href={link} className="hover:underline">{title}</Link>
|
|
70
73
|
</div>
|
|
71
74
|
|
|
72
75
|
<div className="w-1/5 md:w-1/5 flex justify-center p-2">
|
|
@@ -9,11 +9,10 @@ const meta: Meta<typeof BlogView> = {
|
|
|
9
9
|
},
|
|
10
10
|
tags: ['autodocs'],
|
|
11
11
|
};
|
|
12
|
-
|
|
13
12
|
export default meta;
|
|
14
13
|
type Story = StoryObj<typeof BlogView>;
|
|
15
14
|
|
|
16
|
-
const
|
|
15
|
+
const items = [
|
|
17
16
|
{
|
|
18
17
|
id: '1',
|
|
19
18
|
shortId: 'doc-1',
|
|
@@ -24,7 +23,8 @@ const mockItems = [
|
|
|
24
23
|
languages: ['pt-BR'],
|
|
25
24
|
type: 'document',
|
|
26
25
|
renditions: [],
|
|
27
|
-
directoryNodes: []
|
|
26
|
+
directoryNodes: [],
|
|
27
|
+
disabled: false,
|
|
28
28
|
},
|
|
29
29
|
{
|
|
30
30
|
id: '2',
|
|
@@ -35,7 +35,8 @@ const mockItems = [
|
|
|
35
35
|
languages: ['en-US'],
|
|
36
36
|
type: 'document',
|
|
37
37
|
renditions: [],
|
|
38
|
-
directoryNodes: []
|
|
38
|
+
directoryNodes: [],
|
|
39
|
+
disabled: false,
|
|
39
40
|
},
|
|
40
41
|
{
|
|
41
42
|
id: '3',
|
|
@@ -47,12 +48,19 @@ const mockItems = [
|
|
|
47
48
|
languages: ['fr-FR'],
|
|
48
49
|
type: 'document',
|
|
49
50
|
renditions: [],
|
|
50
|
-
directoryNodes: []
|
|
51
|
+
directoryNodes: [],
|
|
52
|
+
disabled: true,
|
|
51
53
|
}
|
|
52
54
|
];
|
|
53
55
|
|
|
54
|
-
export const
|
|
56
|
+
export const Basic: Story = {
|
|
55
57
|
args: {
|
|
56
|
-
items
|
|
57
|
-
}
|
|
58
|
+
items,
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
export const WithDisabled: Story = {
|
|
63
|
+
args: {
|
|
64
|
+
items: items.map((item, i) => ({ ...item, disabled: i === 2 })),
|
|
65
|
+
},
|
|
58
66
|
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import { DialogFilter } from '../dialog-filter';
|
|
3
|
+
import { Button } from '@c-rex/ui/button';
|
|
4
|
+
|
|
5
|
+
const meta: Meta<typeof DialogFilter> = {
|
|
6
|
+
title: 'Components/Results/DialogFilter',
|
|
7
|
+
component: DialogFilter,
|
|
8
|
+
parameters: {
|
|
9
|
+
layout: 'centered',
|
|
10
|
+
},
|
|
11
|
+
tags: ['autodocs'],
|
|
12
|
+
};
|
|
13
|
+
export default meta;
|
|
14
|
+
type Story = StoryObj<typeof DialogFilter>;
|
|
15
|
+
|
|
16
|
+
export const Basic: Story = {
|
|
17
|
+
args: {
|
|
18
|
+
trigger: <Button>Open Filter</Button>,
|
|
19
|
+
},
|
|
20
|
+
};
|
|
@@ -10,5 +10,16 @@ const meta = {
|
|
|
10
10
|
export default meta;
|
|
11
11
|
type Story = StoryObj<typeof meta>;
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
|
|
14
|
+
export const Basic: Story = {};
|
|
15
|
+
|
|
16
|
+
export const CustomMessage: Story = {
|
|
17
|
+
render: () => (
|
|
18
|
+
<div style={{ maxWidth: 400 }}>
|
|
19
|
+
<Empty />
|
|
20
|
+
<div style={{ marginTop: 16, color: '#888' }}>
|
|
21
|
+
Nenhum resultado encontrado para sua busca personalizada.
|
|
22
|
+
</div>
|
|
23
|
+
</div>
|
|
24
|
+
),
|
|
14
25
|
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import { FilterNavbar } from '../filter-navbar';
|
|
3
|
+
|
|
4
|
+
const meta: Meta<typeof FilterNavbar> = {
|
|
5
|
+
title: 'Components/Results/FilterNavbar',
|
|
6
|
+
component: FilterNavbar,
|
|
7
|
+
parameters: {
|
|
8
|
+
layout: 'centered',
|
|
9
|
+
},
|
|
10
|
+
tags: ['autodocs'],
|
|
11
|
+
};
|
|
12
|
+
export default meta;
|
|
13
|
+
type Story = StoryObj<typeof FilterNavbar>;
|
|
14
|
+
|
|
15
|
+
export const Basic: Story = {
|
|
16
|
+
args: {
|
|
17
|
+
tags: {},
|
|
18
|
+
},
|
|
19
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import { FilterSidebar } from './index';
|
|
3
|
+
|
|
4
|
+
const meta: Meta<typeof FilterSidebar> = {
|
|
5
|
+
title: 'Components/Results/FilterSidebar',
|
|
6
|
+
component: FilterSidebar,
|
|
7
|
+
parameters: {
|
|
8
|
+
layout: 'centered',
|
|
9
|
+
},
|
|
10
|
+
tags: ['autodocs'],
|
|
11
|
+
};
|
|
12
|
+
export default meta;
|
|
13
|
+
type Story = StoryObj<typeof FilterSidebar>;
|
|
14
|
+
|
|
15
|
+
export const Basic: Story = {
|
|
16
|
+
args: {
|
|
17
|
+
tags: {},
|
|
18
|
+
totalItemCount: 0,
|
|
19
|
+
},
|
|
20
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import { Pagination } from '../pagination';
|
|
3
|
+
|
|
4
|
+
const meta: Meta<typeof Pagination> = {
|
|
5
|
+
title: 'Components/Results/Pagination',
|
|
6
|
+
component: Pagination,
|
|
7
|
+
parameters: {
|
|
8
|
+
layout: 'centered',
|
|
9
|
+
},
|
|
10
|
+
tags: ['autodocs'],
|
|
11
|
+
};
|
|
12
|
+
export default meta;
|
|
13
|
+
type Story = StoryObj<typeof Pagination>;
|
|
14
|
+
|
|
15
|
+
export const Basic: Story = {
|
|
16
|
+
args: {
|
|
17
|
+
pageInfo: {
|
|
18
|
+
pageNumber: 1,
|
|
19
|
+
pageSize: 10,
|
|
20
|
+
totalPages: 5,
|
|
21
|
+
totalItems: 50,
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import { TableWithImage } from '../table-with-images';
|
|
3
|
+
|
|
4
|
+
const meta: Meta<typeof TableWithImage> = {
|
|
5
|
+
title: 'Components/Results/TableWithImage',
|
|
6
|
+
component: TableWithImage,
|
|
7
|
+
parameters: {
|
|
8
|
+
layout: 'centered',
|
|
9
|
+
},
|
|
10
|
+
tags: ['autodocs'],
|
|
11
|
+
};
|
|
12
|
+
export default meta;
|
|
13
|
+
type Story = StoryObj<typeof TableWithImage>;
|
|
14
|
+
|
|
15
|
+
export const Basic: Story = {
|
|
16
|
+
args: {
|
|
17
|
+
items: [],
|
|
18
|
+
},
|
|
19
|
+
};
|
|
@@ -13,17 +13,26 @@ const meta: Meta<typeof TableView> = {
|
|
|
13
13
|
export default meta;
|
|
14
14
|
type Story = StoryObj<typeof TableView>;
|
|
15
15
|
|
|
16
|
-
const
|
|
16
|
+
const items = [
|
|
17
17
|
{
|
|
18
18
|
id: '1',
|
|
19
19
|
labels: [
|
|
20
20
|
{ value: 'Installation Guide', language: 'en-US' },
|
|
21
|
-
{ value:
|
|
21
|
+
{ value: "Guide d'installation", language: 'fr-FR' }
|
|
22
22
|
],
|
|
23
23
|
languages: ['fr-FR'],
|
|
24
24
|
type: 'document',
|
|
25
25
|
renditions: [],
|
|
26
|
-
directoryNodes: []
|
|
26
|
+
directoryNodes: [],
|
|
27
|
+
disabled: false,
|
|
28
|
+
link: '/docs/1',
|
|
29
|
+
language: 'fr-FR',
|
|
30
|
+
files: {
|
|
31
|
+
'application/pdf': {
|
|
32
|
+
view: '/docs/1/view',
|
|
33
|
+
download: '/docs/1/download',
|
|
34
|
+
},
|
|
35
|
+
},
|
|
27
36
|
},
|
|
28
37
|
{
|
|
29
38
|
id: '2',
|
|
@@ -34,7 +43,11 @@ const mockItems = [
|
|
|
34
43
|
languages: ['es-ES'],
|
|
35
44
|
type: 'document',
|
|
36
45
|
renditions: [],
|
|
37
|
-
directoryNodes: []
|
|
46
|
+
directoryNodes: [],
|
|
47
|
+
disabled: false,
|
|
48
|
+
link: '/docs/2',
|
|
49
|
+
language: 'es-ES',
|
|
50
|
+
files: {},
|
|
38
51
|
},
|
|
39
52
|
{
|
|
40
53
|
id: '3',
|
|
@@ -44,12 +57,22 @@ const mockItems = [
|
|
|
44
57
|
languages: ['en-US'],
|
|
45
58
|
type: 'document',
|
|
46
59
|
renditions: [],
|
|
47
|
-
directoryNodes: []
|
|
48
|
-
|
|
60
|
+
directoryNodes: [],
|
|
61
|
+
disabled: true,
|
|
62
|
+
link: '/docs/3',
|
|
63
|
+
language: 'en-US',
|
|
64
|
+
files: {},
|
|
65
|
+
},
|
|
49
66
|
];
|
|
50
67
|
|
|
51
|
-
export const
|
|
68
|
+
export const Basic: Story = {
|
|
69
|
+
args: {
|
|
70
|
+
items,
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
export const WithFilesAndDisabled: Story = {
|
|
52
75
|
args: {
|
|
53
|
-
items
|
|
54
|
-
}
|
|
76
|
+
items,
|
|
77
|
+
},
|
|
55
78
|
};
|
|
@@ -1,12 +1,5 @@
|
|
|
1
1
|
import { FC } from "react";
|
|
2
|
-
import {
|
|
3
|
-
DocumentModel,
|
|
4
|
-
ExternalProductGraphicModel,
|
|
5
|
-
FragmentModel,
|
|
6
|
-
InformationUnitModel,
|
|
7
|
-
PackageModel,
|
|
8
|
-
TopicModel
|
|
9
|
-
} from "@c-rex/interfaces";
|
|
2
|
+
import { CommonItemsModel } from "@c-rex/interfaces";
|
|
10
3
|
import { FileStack } from "lucide-react";
|
|
11
4
|
import { FileDownloadDropdown } from "../renditions/file-download";
|
|
12
5
|
import { cn, getType, getTitle, getVersions } from "@c-rex/utils";
|
|
@@ -20,14 +13,7 @@ import { BookmarkButton } from "../favorites/bookmark-button";
|
|
|
20
13
|
import { HtmlRendition } from "../renditions/html";
|
|
21
14
|
|
|
22
15
|
interface TableWithImageProps {
|
|
23
|
-
items:
|
|
24
|
-
DocumentModel |
|
|
25
|
-
ExternalProductGraphicModel |
|
|
26
|
-
FragmentModel |
|
|
27
|
-
InformationUnitModel |
|
|
28
|
-
PackageModel |
|
|
29
|
-
TopicModel
|
|
30
|
-
)[];
|
|
16
|
+
items: CommonItemsModel[];
|
|
31
17
|
query?: string;
|
|
32
18
|
markersList?: Favorite[];
|
|
33
19
|
disabledResults?: ResultTypes[];
|
package/src/search-input.tsx
CHANGED
|
@@ -1,24 +1,48 @@
|
|
|
1
1
|
"use client"
|
|
2
2
|
|
|
3
|
-
import React, { FC, useState } from "react";
|
|
3
|
+
import React, { FC, useEffect, 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 { cn } from "@c-rex/utils";
|
|
7
|
-
import
|
|
7
|
+
import * as AutocompleteOptions from "./generated/suggestions";
|
|
8
8
|
import { useQueryState } from "nuqs";
|
|
9
9
|
|
|
10
10
|
type PlacedOn = "NAVBAR" | "BODY"
|
|
11
11
|
type Props = {
|
|
12
|
-
showInput: boolean
|
|
13
12
|
showPkgFilter: boolean
|
|
14
13
|
placedOn?: PlacedOn
|
|
14
|
+
onSelectPath: string;
|
|
15
|
+
autocompleteType: keyof typeof AutocompleteOptions;
|
|
16
|
+
//these two props are only used when showPkgFilter is false and has some values to override the default behavior
|
|
17
|
+
alternativeAutocompleteType?: keyof typeof AutocompleteOptions;
|
|
18
|
+
alternativeOnSelectPath?: string;
|
|
15
19
|
}
|
|
16
20
|
|
|
17
|
-
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
export const SearchInput: FC<Props> = ({
|
|
24
|
+
showPkgFilter,
|
|
25
|
+
autocompleteType,
|
|
26
|
+
onSelectPath,
|
|
27
|
+
placedOn = "NAVBAR",
|
|
28
|
+
alternativeAutocompleteType,
|
|
29
|
+
alternativeOnSelectPath
|
|
30
|
+
}) => {
|
|
18
31
|
const [pkg, setPkg] = useQueryState("package");
|
|
19
32
|
const [checked, setChecked] = useState<boolean>(true);
|
|
33
|
+
const [autocompleteComponentName, setAutocompleteComponentName] = useState<keyof typeof AutocompleteOptions>(autocompleteType);
|
|
34
|
+
|
|
35
|
+
const AutocompleteComponent = AutocompleteOptions[autocompleteComponentName] as FC<any>;
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
useEffect(() => {
|
|
39
|
+
if (checked) {
|
|
40
|
+
setAutocompleteComponentName(autocompleteType);
|
|
41
|
+
} else if (alternativeAutocompleteType) {
|
|
42
|
+
setAutocompleteComponentName(alternativeAutocompleteType);
|
|
43
|
+
}
|
|
44
|
+
}, [checked]);
|
|
20
45
|
|
|
21
|
-
if (!showInput) return null
|
|
22
46
|
|
|
23
47
|
return (
|
|
24
48
|
<div className={cn(
|
|
@@ -27,15 +51,12 @@ export const SearchInput: FC<Props> = ({ showInput, showPkgFilter, placedOn = "N
|
|
|
27
51
|
)}>
|
|
28
52
|
<Search className="shrink-0 opacity-50" />
|
|
29
53
|
|
|
30
|
-
{/*
|
|
31
|
-
|
|
32
|
-
*/}
|
|
33
|
-
<InformationUnitsSuggestions
|
|
54
|
+
{/* Add scope=pkgID if checked is true */}
|
|
55
|
+
<AutocompleteComponent
|
|
34
56
|
onSelectParams={
|
|
35
|
-
(pkg && checked) ? [{ key: "packages", value: pkg }] : []
|
|
36
|
-
|
|
57
|
+
(pkg && checked && showPkgFilter) ? [{ key: "packages", value: pkg }] : []
|
|
37
58
|
}
|
|
38
|
-
onSelectPath=
|
|
59
|
+
onSelectPath={checked ? onSelectPath : alternativeOnSelectPath}
|
|
39
60
|
embedded
|
|
40
61
|
/>
|
|
41
62
|
|
|
@@ -1,26 +1,43 @@
|
|
|
1
1
|
import { LanguageAndCountries } from "@c-rex/interfaces";
|
|
2
2
|
import { create } from "zustand";
|
|
3
|
+
import { persist, createJSONStorage, StateStorage } from "zustand/middleware";
|
|
4
|
+
|
|
5
|
+
const cookieStorage: StateStorage = {
|
|
6
|
+
getItem: (name: string): string | null => {
|
|
7
|
+
if (typeof document === "undefined") return null;
|
|
8
|
+
const match = document.cookie.match(new RegExp(`(^| )${name}=([^;]+)`));
|
|
9
|
+
return match ? decodeURIComponent(match[2] as string) : null;
|
|
10
|
+
},
|
|
11
|
+
setItem: (name: string, value: string): void => {
|
|
12
|
+
if (typeof document === "undefined") return;
|
|
13
|
+
const maxAge = 60 * 60 * 24 * 365; // 1 year
|
|
14
|
+
document.cookie = `${name}=${encodeURIComponent(value)};path=/;max-age=${maxAge};SameSite=Lax`;
|
|
15
|
+
},
|
|
16
|
+
removeItem: (name: string): void => {
|
|
17
|
+
if (typeof document === "undefined") return;
|
|
18
|
+
document.cookie = `${name}=;path=/;max-age=0`;
|
|
19
|
+
},
|
|
20
|
+
};
|
|
3
21
|
|
|
4
22
|
type LanguageStoreType = {
|
|
5
|
-
contentLang: string;
|
|
6
23
|
uiLang: string;
|
|
7
24
|
availableLanguages: LanguageAndCountries[];
|
|
8
|
-
setContentLang: (v: string) => void;
|
|
9
25
|
setUiLang: (v: string) => void;
|
|
10
26
|
setAvailableLanguages: (list: LanguageAndCountries[]) => void;
|
|
11
27
|
};
|
|
12
28
|
|
|
13
|
-
export const useLanguageStore = create<LanguageStoreType>(
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
})
|
|
29
|
+
export const useLanguageStore = create<LanguageStoreType>()(
|
|
30
|
+
persist((set) => ({
|
|
31
|
+
uiLang: "",
|
|
32
|
+
availableLanguages: [],
|
|
33
|
+
setUiLang: (v) => {
|
|
34
|
+
set({ uiLang: v });
|
|
35
|
+
},
|
|
36
|
+
setAvailableLanguages: (list) => {
|
|
37
|
+
set({ availableLanguages: list });
|
|
38
|
+
},
|
|
39
|
+
}), {
|
|
40
|
+
name: "c-rex-language-store",
|
|
41
|
+
storage: createJSONStorage(() => cookieStorage),
|
|
42
|
+
})
|
|
43
|
+
);
|
|
@@ -1,23 +1,64 @@
|
|
|
1
|
+
import { EN_LANG, OPERATOR_OPTIONS, WILD_CARD_OPTIONS } from "@c-rex/constants";
|
|
1
2
|
import { OperatorType, WildCardType } from "@c-rex/types";
|
|
2
3
|
import { create } from "zustand";
|
|
3
|
-
import { persist } from "zustand/middleware";
|
|
4
|
+
import { persist, createJSONStorage, StateStorage } from "zustand/middleware";
|
|
4
5
|
|
|
5
|
-
|
|
6
|
-
|
|
6
|
+
const cookieStorage: StateStorage = {
|
|
7
|
+
getItem: (name: string): string | null => {
|
|
8
|
+
if (typeof document === "undefined") return null;
|
|
9
|
+
const match = document.cookie.match(new RegExp(`(^| )${name}=([^;]+)`));
|
|
10
|
+
return match ? decodeURIComponent(match[2] as string) : null;
|
|
11
|
+
},
|
|
12
|
+
setItem: (name: string, value: string): void => {
|
|
13
|
+
if (typeof document === "undefined") return;
|
|
14
|
+
const maxAge = 60 * 60 * 24 * 365; // 1 year
|
|
15
|
+
document.cookie = `${name}=${encodeURIComponent(value)};path=/;max-age=${maxAge};SameSite=Lax`;
|
|
16
|
+
},
|
|
17
|
+
removeItem: (name: string): void => {
|
|
18
|
+
if (typeof document === "undefined") return;
|
|
19
|
+
document.cookie = `${name}=;path=/;max-age=0`;
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export type SearchSettingsState = {
|
|
24
|
+
language: string,
|
|
7
25
|
wildcard: WildCardType,
|
|
8
26
|
operator: OperatorType,
|
|
9
27
|
like: boolean,
|
|
10
|
-
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export type SearchSettingsStore = SearchSettingsState & {
|
|
31
|
+
updatePreferences: (settings: Partial<SearchSettingsState>) => void,
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export const defaultSearchSettings: SearchSettingsState = {
|
|
35
|
+
language: EN_LANG,
|
|
36
|
+
wildcard: WILD_CARD_OPTIONS.BOTH,
|
|
37
|
+
operator: OPERATOR_OPTIONS.OR,
|
|
38
|
+
like: false,
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Helper function to read search settings from cookie on the server.
|
|
43
|
+
* Use this in Server Components with Next.js cookies() function.
|
|
44
|
+
* @param cookieValue - The raw cookie value from cookies().get("c-rex-search-settings")?.value
|
|
45
|
+
*/
|
|
46
|
+
export function getSearchSettingsFromCookie(cookieValue: string | undefined): SearchSettingsState {
|
|
47
|
+
if (!cookieValue) return defaultSearchSettings;
|
|
48
|
+
try {
|
|
49
|
+
const parsed = JSON.parse(cookieValue);
|
|
50
|
+
return { ...defaultSearchSettings, ...parsed.state };
|
|
51
|
+
} catch {
|
|
52
|
+
return defaultSearchSettings;
|
|
53
|
+
}
|
|
11
54
|
}
|
|
12
55
|
|
|
13
56
|
export const useSearchSettingsStore = create<SearchSettingsStore>()(
|
|
14
57
|
persist((set) => ({
|
|
15
|
-
|
|
16
|
-
wildcard: "BOTH",
|
|
17
|
-
operator: "OR",
|
|
18
|
-
like: false,
|
|
58
|
+
...defaultSearchSettings,
|
|
19
59
|
updatePreferences: (settings) => set((state) => ({ ...state, ...settings })),
|
|
20
60
|
}), {
|
|
21
61
|
name: "c-rex-search-settings",
|
|
62
|
+
storage: createJSONStorage(() => cookieStorage),
|
|
22
63
|
})
|
|
23
64
|
);
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import { AutoComplete } from '../autocomplete';
|
|
3
|
+
|
|
4
|
+
const meta: Meta<typeof AutoComplete> = {
|
|
5
|
+
title: 'Components/AutoComplete',
|
|
6
|
+
component: AutoComplete,
|
|
7
|
+
parameters: {
|
|
8
|
+
layout: 'centered',
|
|
9
|
+
},
|
|
10
|
+
tags: ['autodocs'],
|
|
11
|
+
};
|
|
12
|
+
export default meta;
|
|
13
|
+
type Story = StoryObj<typeof AutoComplete>;
|
|
14
|
+
|
|
15
|
+
export const Basic: Story = {
|
|
16
|
+
args: {
|
|
17
|
+
endpoint: '/api/suggestions',
|
|
18
|
+
onSelectPath: '/',
|
|
19
|
+
},
|
|
20
|
+
};
|