@c-rex/components 0.0.4 → 0.0.6
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/dist/src/autocomplete.d.ts +8 -0
- package/dist/src/autocomplete.d.ts.map +1 -0
- package/dist/src/blog-card.d.ts +17 -0
- package/dist/src/blog-card.d.ts.map +1 -0
- package/dist/src/blur-image.d.ts +4 -0
- package/dist/src/blur-image.d.ts.map +1 -0
- package/dist/src/breadcrumb.d.ts +9 -0
- package/dist/src/breadcrumb.d.ts.map +1 -0
- package/dist/src/empty.d.ts +3 -0
- package/dist/src/empty.d.ts.map +1 -0
- package/dist/src/navbar.d.ts +8 -0
- package/dist/src/navbar.d.ts.map +1 -0
- package/dist/src/providers/search-state-wrapper.d.ts +13 -0
- package/dist/src/providers/search-state-wrapper.d.ts.map +1 -0
- package/dist/src/result-list.d.ts +8 -0
- package/dist/src/result-list.d.ts.map +1 -0
- package/dist/src/result-view/blog.d.ts +8 -0
- package/dist/src/result-view/blog.d.ts.map +1 -0
- package/dist/src/result-view/table.d.ts +8 -0
- package/dist/src/result-view/table.d.ts.map +1 -0
- package/dist/src/sidebar.d.ts +10 -0
- package/dist/src/sidebar.d.ts.map +1 -0
- package/dist/tailwind.config.d.ts +2 -0
- package/dist/tailwind.config.d.ts.map +1 -0
- package/package.json +14 -13
- package/src/autocomplete.tsx +113 -0
- package/src/blog-card.tsx +87 -0
- package/src/blur-image.tsx +23 -0
- package/src/breadcrumb.tsx +81 -0
- package/src/empty.tsx +13 -0
- package/src/navbar.tsx +66 -0
- package/src/providers/search-state-wrapper.tsx +21 -0
- package/src/result-list.tsx +16 -0
- package/src/result-view/blog-view.stories.tsx +58 -0
- package/src/result-view/blog.tsx +38 -0
- package/src/result-view/table-view.stories.tsx +55 -0
- package/src/result-view/table.tsx +65 -0
- package/src/sidebar.tsx +76 -0
- package/src/stories/blog-card.stories.tsx +46 -0
- package/src/stories/blur-image.stories.tsx +51 -0
- package/src/stories/breadcrumb.stories.tsx +52 -0
- package/src/stories/empty.stories.tsx +14 -0
- package/src/stories/navbar.stories.tsx +16 -0
- package/src/stories/sidebar.stories.tsx +94 -0
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
type Props = {
|
|
2
|
+
initialValue: string;
|
|
3
|
+
onSelect: (value: string) => void;
|
|
4
|
+
onSearch: (value: string) => Promise<string[]>;
|
|
5
|
+
};
|
|
6
|
+
export declare const AutoComplete: ({ initialValue, onSearch, onSelect, }: Props) => import("react/jsx-runtime").JSX.Element;
|
|
7
|
+
export {};
|
|
8
|
+
//# sourceMappingURL=autocomplete.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"autocomplete.d.ts","sourceRoot":"","sources":["../../src/autocomplete.tsx"],"names":[],"mappings":"AAiBA,KAAK,KAAK,GAAG;IACT,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;CAClD,CAAC;AAEF,eAAO,MAAM,YAAY,GAAI,uCAI1B,KAAK,4CAqFP,CAAA"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
interface BlogCardProp {
|
|
2
|
+
data: {
|
|
3
|
+
title: string;
|
|
4
|
+
blurDataURL: string;
|
|
5
|
+
image: string;
|
|
6
|
+
description: string;
|
|
7
|
+
authors: string;
|
|
8
|
+
_id: string;
|
|
9
|
+
date: string;
|
|
10
|
+
slug: string;
|
|
11
|
+
};
|
|
12
|
+
priority?: boolean;
|
|
13
|
+
horizontal?: boolean;
|
|
14
|
+
}
|
|
15
|
+
export declare const BlogCard: ({ data, priority, horizontal, }: BlogCardProp) => import("react/jsx-runtime").JSX.Element;
|
|
16
|
+
export {};
|
|
17
|
+
//# sourceMappingURL=blog-card.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"blog-card.d.ts","sourceRoot":"","sources":["../../src/blog-card.tsx"],"names":[],"mappings":"AAMA,UAAU,YAAY;IAClB,IAAI,EAAE;QACF,KAAK,EAAE,MAAM,CAAC;QACd,WAAW,EAAE,MAAM,CAAC;QACpB,KAAK,EAAE,MAAM,CAAC;QACd,WAAW,EAAE,MAAM,CAAC;QACpB,OAAO,EAAE,MAAM,CAAC;QAChB,GAAG,EAAE,MAAM,CAAC;QACZ,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,UAAU,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,eAAO,MAAM,QAAQ,GAAI,iCAItB,YAAY,4CA6Dd,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"blur-image.d.ts","sourceRoot":"","sources":["../../src/blur-image.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,OAAO,CAAC;AAC5C,OAAO,KAAK,MAAM,YAAY,CAAC;AAG/B,eAAO,MAAM,SAAS,GAAI,OAAO,cAAc,CAAC,OAAO,KAAK,CAAC,4CAe5D,CAAA"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { FC } from "react";
|
|
2
|
+
import { TreeOfContent } from "@c-rex/interfaces";
|
|
3
|
+
interface BreadcrumbProps {
|
|
4
|
+
items: TreeOfContent[];
|
|
5
|
+
loading?: boolean;
|
|
6
|
+
}
|
|
7
|
+
export declare const Breadcrumb: FC<BreadcrumbProps>;
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=breadcrumb.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"breadcrumb.d.ts","sourceRoot":"","sources":["../../src/breadcrumb.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAa,MAAM,OAAO,CAAC;AAUtC,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAElD,UAAU,eAAe;IACrB,KAAK,EAAE,aAAa,EAAE,CAAC;IACvB,OAAO,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,eAAO,MAAM,UAAU,EAAE,EAAE,CAAC,eAAe,CA+D1C,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"empty.d.ts","sourceRoot":"","sources":["../../src/empty.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAG3B,eAAO,MAAM,KAAK,EAAE,EASnB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"navbar.d.ts","sourceRoot":"","sources":["../../src/navbar.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAM3B,UAAU,WAAW;IACjB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,eAAO,MAAM,MAAM,EAAE,EAAE,CAAC,WAAW,CAsDlC,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { FC, ReactNode } from "react";
|
|
2
|
+
interface SearchStateWrapperProps {
|
|
3
|
+
children: ReactNode;
|
|
4
|
+
filters: {
|
|
5
|
+
searchValue: string;
|
|
6
|
+
page: number;
|
|
7
|
+
selectedLanguage: string[];
|
|
8
|
+
availableLanguages: string[];
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
export declare const SearchStateWrapper: FC<SearchStateWrapperProps>;
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=search-state-wrapper.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search-state-wrapper.d.ts","sourceRoot":"","sources":["../../../src/providers/search-state-wrapper.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEtC,UAAU,uBAAuB;IAC7B,QAAQ,EAAE,SAAS,CAAC;IACpB,OAAO,EAAE;QACL,WAAW,EAAE,MAAM,CAAC;QACpB,IAAI,EAAE,MAAM,CAAC;QACb,gBAAgB,EAAE,MAAM,EAAE,CAAC;QAC3B,kBAAkB,EAAE,MAAM,EAAE,CAAC;KAChC,CAAC;CACL;AAED,eAAO,MAAM,kBAAkB,EAAE,EAAE,CAAC,uBAAuB,CAK1D,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { FC } from "react";
|
|
2
|
+
import { informationUnitsItems } from "@c-rex/interfaces";
|
|
3
|
+
interface ResultListProps {
|
|
4
|
+
items: informationUnitsItems[];
|
|
5
|
+
}
|
|
6
|
+
export declare const ResultList: FC<ResultListProps>;
|
|
7
|
+
export {};
|
|
8
|
+
//# sourceMappingURL=result-list.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"result-list.d.ts","sourceRoot":"","sources":["../../src/result-list.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAC3B,OAAO,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAQ1D,UAAU,eAAe;IACrB,KAAK,EAAE,qBAAqB,EAAE,CAAC;CAClC;AAED,eAAO,MAAM,UAAU,EAAE,EAAE,CAAC,eAAe,CAE1C,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"blog.d.ts","sourceRoot":"","sources":["../../../src/result-view/blog.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAG3B,OAAO,EAAE,qBAAqB,EAAU,MAAM,mBAAmB,CAAC;AAElE,UAAU,aAAa;IACnB,KAAK,EAAE,qBAAqB,EAAE,CAAC;CAClC;AAED,QAAA,MAAM,QAAQ,EAAE,EAAE,CAAC,aAAa,CA0B/B,CAAC;AAEF,eAAe,QAAQ,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { FC } from "react";
|
|
2
|
+
import { informationUnitsItems } from "@c-rex/interfaces";
|
|
3
|
+
interface TableViewProps {
|
|
4
|
+
items: informationUnitsItems[];
|
|
5
|
+
}
|
|
6
|
+
declare const TableView: FC<TableViewProps>;
|
|
7
|
+
export default TableView;
|
|
8
|
+
//# sourceMappingURL=table.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"table.d.ts","sourceRoot":"","sources":["../../../src/result-view/table.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAa,MAAM,OAAO,CAAC;AAStC,OAAO,EAAE,qBAAqB,EAAU,MAAM,mBAAmB,CAAC;AAGlE,UAAU,cAAc;IACpB,KAAK,EAAE,qBAAqB,EAAE,CAAC;CAClC;AAED,QAAA,MAAM,SAAS,EAAE,EAAE,CAAC,cAAc,CA8CjC,CAAC;AAEF,eAAe,SAAS,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { ComponentProps } from "react";
|
|
2
|
+
import { Sidebar } from "@c-rex/ui/sidebar";
|
|
3
|
+
import { TreeOfContent } from "@c-rex/interfaces";
|
|
4
|
+
interface SidebarProps extends ComponentProps<typeof Sidebar> {
|
|
5
|
+
data: TreeOfContent[];
|
|
6
|
+
loading?: boolean;
|
|
7
|
+
}
|
|
8
|
+
export declare function AppSidebar({ data, loading, ...props }: SidebarProps): import("react/jsx-runtime").JSX.Element;
|
|
9
|
+
export {};
|
|
10
|
+
//# sourceMappingURL=sidebar.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sidebar.d.ts","sourceRoot":"","sources":["../../src/sidebar.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,EACH,OAAO,EAUV,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAElD,UAAU,YAAa,SAAQ,cAAc,CAAC,OAAO,OAAO,CAAC;IACzD,IAAI,EAAE,aAAa,EAAE,CAAC;IACtB,OAAO,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,wBAAgB,UAAU,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,KAAK,EAAE,EAAE,YAAY,2CAoDnE"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tailwind.config.d.ts","sourceRoot":"","sources":["../tailwind.config.ts"],"names":[],"mappings":""}
|
package/package.json
CHANGED
|
@@ -1,55 +1,56 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@c-rex/components",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.6",
|
|
4
4
|
"files": [
|
|
5
|
-
"dist"
|
|
5
|
+
"dist",
|
|
6
|
+
"src"
|
|
6
7
|
],
|
|
7
8
|
"publishConfig": {
|
|
8
9
|
"access": "public"
|
|
9
10
|
},
|
|
10
11
|
"exports": {
|
|
11
12
|
"./autocomplete": {
|
|
12
|
-
"types": "./
|
|
13
|
+
"types": "./dist/autocomplete.d.ts",
|
|
13
14
|
"import": "./src/autocomplete.tsx"
|
|
14
15
|
},
|
|
15
16
|
"./blog-card": {
|
|
16
|
-
"types": "./
|
|
17
|
+
"types": "./dist/blog-card.d.ts",
|
|
17
18
|
"import": "./src/blog-card.tsx"
|
|
18
19
|
},
|
|
19
20
|
"./blur-image": {
|
|
20
|
-
"types": "./
|
|
21
|
+
"types": "./dist/blur-image.d.ts",
|
|
21
22
|
"import": "./src/blur-image.tsx"
|
|
22
23
|
},
|
|
23
24
|
"./breadcrumb": {
|
|
24
|
-
"types": "./
|
|
25
|
+
"types": "./dist/breadcrumb.d.ts",
|
|
25
26
|
"import": "./src/breadcrumb.tsx"
|
|
26
27
|
},
|
|
27
28
|
"./empty": {
|
|
28
|
-
"types": "./
|
|
29
|
+
"types": "./dist/empty.d.ts",
|
|
29
30
|
"import": "./src/empty.tsx"
|
|
30
31
|
},
|
|
31
32
|
"./navbar": {
|
|
32
|
-
"types": "./
|
|
33
|
+
"types": "./dist/navbar.d.ts",
|
|
33
34
|
"import": "./src/navbar.tsx"
|
|
34
35
|
},
|
|
35
36
|
"./providers/search-state-wrapper": {
|
|
36
|
-
"types": "./
|
|
37
|
+
"types": "./dist/providers/search-state-wrapper.d.ts",
|
|
37
38
|
"import": "./src/providers/search-state-wrapper.tsx"
|
|
38
39
|
},
|
|
39
40
|
"./result-list": {
|
|
40
|
-
"types": "./
|
|
41
|
+
"types": "./dist/result-list.d.ts",
|
|
41
42
|
"import": "./src/result-list.tsx"
|
|
42
43
|
},
|
|
43
44
|
"./result-view/blog": {
|
|
44
|
-
"types": "./
|
|
45
|
+
"types": "./dist/result-view/blog.d.ts",
|
|
45
46
|
"import": "./src/result-view/blog.tsx"
|
|
46
47
|
},
|
|
47
48
|
"./result-view/table": {
|
|
48
|
-
"types": "./
|
|
49
|
+
"types": "./dist/result-view/table.d.ts",
|
|
49
50
|
"import": "./src/result-view/table.tsx"
|
|
50
51
|
},
|
|
51
52
|
"./sidebar": {
|
|
52
|
-
"types": "./
|
|
53
|
+
"types": "./dist/sidebar.d.ts",
|
|
53
54
|
"import": "./src/sidebar.tsx"
|
|
54
55
|
},
|
|
55
56
|
"./package.json": "./package.json"
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { Command as CommandPrimitive } from "cmdk";
|
|
2
|
+
import { Check } from "lucide-react";
|
|
3
|
+
import { useEffect, useState } from "react";
|
|
4
|
+
import { Input } from "@c-rex/ui/input";
|
|
5
|
+
import {
|
|
6
|
+
Command,
|
|
7
|
+
CommandEmpty,
|
|
8
|
+
CommandGroup,
|
|
9
|
+
CommandItem,
|
|
10
|
+
CommandList
|
|
11
|
+
} from "@c-rex/ui/command";
|
|
12
|
+
import {
|
|
13
|
+
Popover,
|
|
14
|
+
PopoverAnchor,
|
|
15
|
+
PopoverContent
|
|
16
|
+
} from "@c-rex/ui/popover";
|
|
17
|
+
|
|
18
|
+
type Props = {
|
|
19
|
+
initialValue: string;
|
|
20
|
+
onSelect: (value: string) => void;
|
|
21
|
+
onSearch: (value: string) => Promise<string[]>;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export const AutoComplete = ({
|
|
25
|
+
initialValue,
|
|
26
|
+
onSearch,
|
|
27
|
+
onSelect,
|
|
28
|
+
}: Props) => {
|
|
29
|
+
const [query, setQuery] = useState(initialValue);
|
|
30
|
+
const [suggestions, setSuggestions] = useState<string[]>([]);
|
|
31
|
+
|
|
32
|
+
const [open, setOpen] = useState(false);
|
|
33
|
+
|
|
34
|
+
useEffect(() => {
|
|
35
|
+
const debounceFetch = setTimeout(() => {
|
|
36
|
+
if (query) {
|
|
37
|
+
onSearch(query).then(setSuggestions);
|
|
38
|
+
} else {
|
|
39
|
+
setSuggestions([]);
|
|
40
|
+
}
|
|
41
|
+
}, 300);
|
|
42
|
+
|
|
43
|
+
return () => clearTimeout(debounceFetch);
|
|
44
|
+
}, [onSearch, query]);
|
|
45
|
+
|
|
46
|
+
return (
|
|
47
|
+
<div className="flex items-center">
|
|
48
|
+
<Popover open={open} onOpenChange={setOpen}>
|
|
49
|
+
<Command shouldFilter={false}>
|
|
50
|
+
<PopoverAnchor asChild>
|
|
51
|
+
<CommandPrimitive.Input
|
|
52
|
+
asChild
|
|
53
|
+
value={query}
|
|
54
|
+
onValueChange={setQuery}
|
|
55
|
+
onKeyDown={(e) => setOpen(e.key !== "Escape")}
|
|
56
|
+
onMouseDown={() => setOpen(false)}
|
|
57
|
+
onFocus={() => setOpen(true)}
|
|
58
|
+
>
|
|
59
|
+
<Input />
|
|
60
|
+
</CommandPrimitive.Input>
|
|
61
|
+
</PopoverAnchor>
|
|
62
|
+
|
|
63
|
+
{!open && <CommandList aria-hidden="true" className="hidden" />}
|
|
64
|
+
|
|
65
|
+
<PopoverContent
|
|
66
|
+
asChild
|
|
67
|
+
onOpenAutoFocus={(e) => e.preventDefault()}
|
|
68
|
+
onInteractOutside={(e) => {
|
|
69
|
+
if (
|
|
70
|
+
e.target instanceof Element &&
|
|
71
|
+
e.target.hasAttribute("cmdk-input")
|
|
72
|
+
) {
|
|
73
|
+
e.preventDefault();
|
|
74
|
+
}
|
|
75
|
+
}}
|
|
76
|
+
className="w-[--radix-popover-trigger-width] p-0"
|
|
77
|
+
>
|
|
78
|
+
<CommandList>
|
|
79
|
+
{/*isLoading && (
|
|
80
|
+
<CommandPrimitive.Loading>
|
|
81
|
+
<div className="p-1">
|
|
82
|
+
<Skeleton className="h-6 w-full" />
|
|
83
|
+
</div>
|
|
84
|
+
</CommandPrimitive.Loading>
|
|
85
|
+
)*/}
|
|
86
|
+
|
|
87
|
+
{suggestions.length > 0 ? (
|
|
88
|
+
<CommandGroup>
|
|
89
|
+
{suggestions.map((option) => (
|
|
90
|
+
<CommandItem
|
|
91
|
+
key={option}
|
|
92
|
+
value={option}
|
|
93
|
+
onMouseDown={(e) => e.preventDefault()}
|
|
94
|
+
onSelect={(inputValue) => {
|
|
95
|
+
setOpen(false);
|
|
96
|
+
onSelect(inputValue ?? "");
|
|
97
|
+
}}
|
|
98
|
+
>
|
|
99
|
+
<Check className="mr-2 h-4 w-4 opacity-0" />
|
|
100
|
+
{option}
|
|
101
|
+
</CommandItem>
|
|
102
|
+
))}
|
|
103
|
+
</CommandGroup>
|
|
104
|
+
) : (
|
|
105
|
+
<CommandEmpty>No suggestions.</CommandEmpty>
|
|
106
|
+
)}
|
|
107
|
+
</CommandList>
|
|
108
|
+
</PopoverContent>
|
|
109
|
+
</Command>
|
|
110
|
+
</Popover>
|
|
111
|
+
</div>
|
|
112
|
+
);
|
|
113
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import Link from "next/link";
|
|
2
|
+
import { cn } from "@c-rex/utils";
|
|
3
|
+
import { BlurImage } from "./blur-image";
|
|
4
|
+
|
|
5
|
+
//import Author from "./author";
|
|
6
|
+
|
|
7
|
+
interface BlogCardProp {
|
|
8
|
+
data: {
|
|
9
|
+
title: string;
|
|
10
|
+
blurDataURL: string;
|
|
11
|
+
image: string;
|
|
12
|
+
description: string;
|
|
13
|
+
authors: string;
|
|
14
|
+
_id: string;
|
|
15
|
+
date: string;
|
|
16
|
+
slug: string;
|
|
17
|
+
};
|
|
18
|
+
priority?: boolean;
|
|
19
|
+
horizontal?: boolean;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export const BlogCard = ({
|
|
23
|
+
data,
|
|
24
|
+
priority,
|
|
25
|
+
horizontal = false,
|
|
26
|
+
}: BlogCardProp) => {
|
|
27
|
+
return (
|
|
28
|
+
<article
|
|
29
|
+
className={cn(
|
|
30
|
+
"group relative",
|
|
31
|
+
horizontal
|
|
32
|
+
? "grid grid-cols-1 gap-3 md:grid-cols-2 md:gap-6"
|
|
33
|
+
: "flex flex-col space-y-2",
|
|
34
|
+
)}
|
|
35
|
+
>
|
|
36
|
+
{data.image && (
|
|
37
|
+
<div className="w-full overflow-hidden rounded-xl border">
|
|
38
|
+
<BlurImage
|
|
39
|
+
alt={data.title}
|
|
40
|
+
blurDataURL={data.blurDataURL}
|
|
41
|
+
className={cn(
|
|
42
|
+
"size-full object-cover object-center",
|
|
43
|
+
horizontal ? "lg:h-72" : null,
|
|
44
|
+
)}
|
|
45
|
+
width={800}
|
|
46
|
+
height={400}
|
|
47
|
+
priority={priority}
|
|
48
|
+
placeholder="blur"
|
|
49
|
+
src={data.image}
|
|
50
|
+
sizes="(max-width: 768px) 750px, 600px"
|
|
51
|
+
/>
|
|
52
|
+
</div>
|
|
53
|
+
)}
|
|
54
|
+
<div
|
|
55
|
+
className={cn(
|
|
56
|
+
"flex flex-1 flex-col",
|
|
57
|
+
horizontal ? "justify-center" : "justify-between",
|
|
58
|
+
)}
|
|
59
|
+
>
|
|
60
|
+
<div className="w-full">
|
|
61
|
+
<h2 className="my-1.5 line-clamp-2 font-heading text-2xl">
|
|
62
|
+
{data.title}
|
|
63
|
+
</h2>
|
|
64
|
+
{data.description && (
|
|
65
|
+
<p className="line-clamp-2 text-muted-foreground">
|
|
66
|
+
{data.description}
|
|
67
|
+
</p>
|
|
68
|
+
)}
|
|
69
|
+
</div>
|
|
70
|
+
<div className="mt-4 flex items-center space-x-3">
|
|
71
|
+
<div className="flex items-center -space-x-2">
|
|
72
|
+
{data.authors && (
|
|
73
|
+
<p className="text-sm text-muted-foreground">{data.authors}</p>
|
|
74
|
+
)}
|
|
75
|
+
</div>
|
|
76
|
+
|
|
77
|
+
{data.date && (
|
|
78
|
+
<p className="text-sm text-muted-foreground">{data.date}</p>
|
|
79
|
+
)}
|
|
80
|
+
</div>
|
|
81
|
+
</div>
|
|
82
|
+
<Link href={data.slug} className="absolute inset-0" target="_blank">
|
|
83
|
+
<span className="sr-only">View Article</span>
|
|
84
|
+
</Link>
|
|
85
|
+
</article>
|
|
86
|
+
);
|
|
87
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useState } from "react";
|
|
4
|
+
import type { ComponentProps } from "react";
|
|
5
|
+
import Image from "next/image";
|
|
6
|
+
import { cn } from "@c-rex/utils";
|
|
7
|
+
|
|
8
|
+
export const BlurImage = (props: ComponentProps<typeof Image>) => {
|
|
9
|
+
const [isLoading, setLoading] = useState(true);
|
|
10
|
+
|
|
11
|
+
return (
|
|
12
|
+
<Image
|
|
13
|
+
{...props}
|
|
14
|
+
alt={props.alt}
|
|
15
|
+
className={cn(
|
|
16
|
+
props.className,
|
|
17
|
+
"duration-500 ease-in-out",
|
|
18
|
+
isLoading ? "blur-sm" : "blur-0",
|
|
19
|
+
)}
|
|
20
|
+
onLoad={() => setLoading(false)}
|
|
21
|
+
/>
|
|
22
|
+
);
|
|
23
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { FC, ReactNode } from "react";
|
|
2
|
+
import {
|
|
3
|
+
Breadcrumb as BreadcrumbComponent,
|
|
4
|
+
BreadcrumbItem,
|
|
5
|
+
BreadcrumbLink,
|
|
6
|
+
BreadcrumbList,
|
|
7
|
+
BreadcrumbPage,
|
|
8
|
+
BreadcrumbSeparator
|
|
9
|
+
} from "@c-rex/ui/breadcrumb";
|
|
10
|
+
import { Skeleton } from "@c-rex/ui/skeleton";
|
|
11
|
+
import { TreeOfContent } from "@c-rex/interfaces";
|
|
12
|
+
|
|
13
|
+
interface BreadcrumbProps {
|
|
14
|
+
items: TreeOfContent[];
|
|
15
|
+
loading?: boolean;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export const Breadcrumb: FC<BreadcrumbProps> = ({ items, loading }) => {
|
|
19
|
+
if (!items) {
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (loading) {
|
|
24
|
+
return (
|
|
25
|
+
<BreadcrumbComponent>
|
|
26
|
+
<BreadcrumbList>
|
|
27
|
+
<BreadcrumbItem>
|
|
28
|
+
<BreadcrumbPage>Home</BreadcrumbPage>
|
|
29
|
+
</BreadcrumbItem>
|
|
30
|
+
<BreadcrumbSeparator />
|
|
31
|
+
<BreadcrumbItem>
|
|
32
|
+
<Skeleton className="w-40 h-6" />
|
|
33
|
+
</BreadcrumbItem>
|
|
34
|
+
<BreadcrumbSeparator />
|
|
35
|
+
<BreadcrumbItem>
|
|
36
|
+
<Skeleton className="w-40 h-6" />
|
|
37
|
+
</BreadcrumbItem>
|
|
38
|
+
</BreadcrumbList>
|
|
39
|
+
</BreadcrumbComponent>
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const homeItem: TreeOfContent = {
|
|
44
|
+
link: "/",
|
|
45
|
+
label: "Home",
|
|
46
|
+
id: "home",
|
|
47
|
+
active: false,
|
|
48
|
+
children: [],
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const newItemList: TreeOfContent[] = [homeItem, ...items];
|
|
52
|
+
|
|
53
|
+
const renderLink = (showLink: boolean, item: TreeOfContent): ReactNode => {
|
|
54
|
+
if (showLink) {
|
|
55
|
+
return <BreadcrumbLink href={item.link}>{item.label}</BreadcrumbLink>;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return <BreadcrumbPage>{item.label}</BreadcrumbPage>;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
return (
|
|
62
|
+
<BreadcrumbComponent>
|
|
63
|
+
<BreadcrumbList>
|
|
64
|
+
{newItemList.map((item, index) => {
|
|
65
|
+
const isLast = index === newItemList.length - 1;
|
|
66
|
+
|
|
67
|
+
return (
|
|
68
|
+
<>
|
|
69
|
+
<BreadcrumbItem key={`${item.label}-item`}>
|
|
70
|
+
{renderLink(!isLast, item)}
|
|
71
|
+
</BreadcrumbItem>
|
|
72
|
+
{!isLast && (
|
|
73
|
+
<BreadcrumbSeparator key={`${item.label}-separator`} />
|
|
74
|
+
)}
|
|
75
|
+
</>
|
|
76
|
+
);
|
|
77
|
+
})}
|
|
78
|
+
</BreadcrumbList>
|
|
79
|
+
</BreadcrumbComponent>
|
|
80
|
+
);
|
|
81
|
+
};
|
package/src/empty.tsx
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { FC } from "react";
|
|
2
|
+
import { Alert, AlertDescription, AlertTitle } from "@c-rex/ui/alert";
|
|
3
|
+
|
|
4
|
+
export const Empty: FC = () => {
|
|
5
|
+
return (
|
|
6
|
+
<Alert className="my-2">
|
|
7
|
+
<AlertTitle>No results</AlertTitle>
|
|
8
|
+
<AlertDescription>
|
|
9
|
+
No data available. Please try adjusting your search or filter criteria.
|
|
10
|
+
</AlertDescription>
|
|
11
|
+
</Alert>
|
|
12
|
+
);
|
|
13
|
+
};
|
package/src/navbar.tsx
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { FC } from "react";
|
|
2
|
+
|
|
3
|
+
import Link from "next/link";
|
|
4
|
+
import { Button } from "@c-rex/ui/button";
|
|
5
|
+
import Image from "next/image";
|
|
6
|
+
|
|
7
|
+
interface NavBarProps {
|
|
8
|
+
scroll?: boolean;
|
|
9
|
+
large?: boolean;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const NavBar: FC<NavBarProps> = () => {
|
|
13
|
+
return (
|
|
14
|
+
<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">
|
|
15
|
+
<div className="container flex justify-between">
|
|
16
|
+
<div className="flex gap-6 md:gap-10">
|
|
17
|
+
<Link href="/" className="flex items-center space-x-1.5">
|
|
18
|
+
<Image
|
|
19
|
+
src="/img/logo.png"
|
|
20
|
+
alt="C-rex Logo"
|
|
21
|
+
width={88}
|
|
22
|
+
height={50}
|
|
23
|
+
/>
|
|
24
|
+
</Link>
|
|
25
|
+
|
|
26
|
+
<nav className="hidden gap-6 md:flex">
|
|
27
|
+
{/*
|
|
28
|
+
TODO: add map to load links
|
|
29
|
+
TODO: add function to validate active item
|
|
30
|
+
*/}
|
|
31
|
+
<Link
|
|
32
|
+
href={"/blog"}
|
|
33
|
+
prefetch={true}
|
|
34
|
+
className={
|
|
35
|
+
"flex items-center text-lg font-medium transition-colors hover:text-foreground/80 sm:text-sm"
|
|
36
|
+
}
|
|
37
|
+
>
|
|
38
|
+
Blog
|
|
39
|
+
</Link>
|
|
40
|
+
|
|
41
|
+
<Link
|
|
42
|
+
href={"#"}
|
|
43
|
+
prefetch={true}
|
|
44
|
+
className={
|
|
45
|
+
"flex items-center text-lg font-medium transition-colors hover:text-foreground/80 sm:text-sm"
|
|
46
|
+
}
|
|
47
|
+
>
|
|
48
|
+
Documentation
|
|
49
|
+
</Link>
|
|
50
|
+
</nav>
|
|
51
|
+
</div>
|
|
52
|
+
|
|
53
|
+
<div className="flex items-center space-x-3">
|
|
54
|
+
<Button
|
|
55
|
+
className="hidden gap-2 px-5 md:flex"
|
|
56
|
+
variant="default"
|
|
57
|
+
size="sm"
|
|
58
|
+
rounded="full"
|
|
59
|
+
>
|
|
60
|
+
<span>Sign In</span>
|
|
61
|
+
</Button>
|
|
62
|
+
</div>
|
|
63
|
+
</div>
|
|
64
|
+
</header>
|
|
65
|
+
);
|
|
66
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
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
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { FC } from "react";
|
|
2
|
+
import { informationUnitsItems } from "@c-rex/interfaces";
|
|
3
|
+
import { Empty } from "./empty";
|
|
4
|
+
//import { CUSTOMER_CONFIG } from '@/config/customerConfig';
|
|
5
|
+
//import { RESULT_VIEW_OPTIONS } from '@/constants/components';
|
|
6
|
+
import BlogView from './result-view/blog';
|
|
7
|
+
|
|
8
|
+
const ViewComponent = BlogView;
|
|
9
|
+
|
|
10
|
+
interface ResultListProps {
|
|
11
|
+
items: informationUnitsItems[];
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export const ResultList: FC<ResultListProps> = ({ items }) => {
|
|
15
|
+
return <>{items.length == 0 ? <Empty /> : <ViewComponent items={items} />}</>;
|
|
16
|
+
};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import BlogView from '../result-view/blog';
|
|
3
|
+
|
|
4
|
+
const meta: Meta<typeof BlogView> = {
|
|
5
|
+
title: 'Components/ResultView/Blog',
|
|
6
|
+
component: BlogView,
|
|
7
|
+
parameters: {
|
|
8
|
+
layout: 'centered',
|
|
9
|
+
},
|
|
10
|
+
tags: ['autodocs'],
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export default meta;
|
|
14
|
+
type Story = StoryObj<typeof BlogView>;
|
|
15
|
+
|
|
16
|
+
const mockItems = [
|
|
17
|
+
{
|
|
18
|
+
id: '1',
|
|
19
|
+
shortId: 'doc-1',
|
|
20
|
+
labels: [
|
|
21
|
+
{ value: 'Getting Started with C-Rex', language: 'en-US' },
|
|
22
|
+
{ value: 'Começando com C-Rex', language: 'pt-BR' }
|
|
23
|
+
],
|
|
24
|
+
languages: ['pt-BR'],
|
|
25
|
+
type: 'document',
|
|
26
|
+
renditions: [],
|
|
27
|
+
directoryNodes: []
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
id: '2',
|
|
31
|
+
shortId: 'doc-2',
|
|
32
|
+
labels: [
|
|
33
|
+
{ value: 'Advanced Configuration Guide', language: 'en-US' }
|
|
34
|
+
],
|
|
35
|
+
languages: ['en-US'],
|
|
36
|
+
type: 'document',
|
|
37
|
+
renditions: [],
|
|
38
|
+
directoryNodes: []
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
id: '3',
|
|
42
|
+
shortId: 'doc-3',
|
|
43
|
+
labels: [
|
|
44
|
+
{ value: 'API Documentation', language: 'en-US' },
|
|
45
|
+
{ value: 'Documentation API', language: 'fr-FR' }
|
|
46
|
+
],
|
|
47
|
+
languages: ['fr-FR'],
|
|
48
|
+
type: 'document',
|
|
49
|
+
renditions: [],
|
|
50
|
+
directoryNodes: []
|
|
51
|
+
}
|
|
52
|
+
];
|
|
53
|
+
|
|
54
|
+
export const Default: Story = {
|
|
55
|
+
args: {
|
|
56
|
+
items: mockItems as any
|
|
57
|
+
}
|
|
58
|
+
};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { FC } from "react";
|
|
2
|
+
|
|
3
|
+
import { BlogCard } from "../blog-card";
|
|
4
|
+
import { informationUnitsItems, Labels } from "@c-rex/interfaces";
|
|
5
|
+
|
|
6
|
+
interface BlogViewProps {
|
|
7
|
+
items: informationUnitsItems[];
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const BlogView: FC<BlogViewProps> = ({ items }) => {
|
|
11
|
+
const getTitle = (labels: Labels[]): string => {
|
|
12
|
+
return labels.map((item) => item.value).join();
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
return (
|
|
16
|
+
<div className="grid gap-8 md:grid-cols-2 md:gap-x-6 md:gap-y-10 xl:grid-cols-3">
|
|
17
|
+
{items.map((item, index) => {
|
|
18
|
+
return (
|
|
19
|
+
<BlogCard
|
|
20
|
+
key={index}
|
|
21
|
+
data={{
|
|
22
|
+
title: getTitle(item.labels),
|
|
23
|
+
blurDataURL: "/img/blog-post-1.webp",
|
|
24
|
+
image: "/img/blog-post-1.webp",
|
|
25
|
+
description: "item.shortDescription",
|
|
26
|
+
authors: "item.authors",
|
|
27
|
+
_id: "item._id",
|
|
28
|
+
date: "item.date",
|
|
29
|
+
slug: `info/${item.shortId}`,
|
|
30
|
+
}}
|
|
31
|
+
/>
|
|
32
|
+
);
|
|
33
|
+
})}
|
|
34
|
+
</div>
|
|
35
|
+
);
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export default BlogView;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import TableView from '../result-view/table';
|
|
3
|
+
|
|
4
|
+
const meta: Meta<typeof TableView> = {
|
|
5
|
+
title: 'Components/ResultView/Table',
|
|
6
|
+
component: TableView,
|
|
7
|
+
parameters: {
|
|
8
|
+
layout: 'centered',
|
|
9
|
+
},
|
|
10
|
+
tags: ['autodocs'],
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export default meta;
|
|
14
|
+
type Story = StoryObj<typeof TableView>;
|
|
15
|
+
|
|
16
|
+
const mockItems = [
|
|
17
|
+
{
|
|
18
|
+
id: '1',
|
|
19
|
+
labels: [
|
|
20
|
+
{ value: 'Installation Guide', language: 'en-US' },
|
|
21
|
+
{ value: 'Guide d\'installation', language: 'fr-FR' }
|
|
22
|
+
],
|
|
23
|
+
languages: ['fr-FR'],
|
|
24
|
+
type: 'document',
|
|
25
|
+
renditions: [],
|
|
26
|
+
directoryNodes: []
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
id: '2',
|
|
30
|
+
labels: [
|
|
31
|
+
{ value: 'User Manual', language: 'en-US' },
|
|
32
|
+
{ value: 'Manual del Usuario', language: 'es-ES' }
|
|
33
|
+
],
|
|
34
|
+
languages: ['es-ES'],
|
|
35
|
+
type: 'document',
|
|
36
|
+
renditions: [],
|
|
37
|
+
directoryNodes: []
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
id: '3',
|
|
41
|
+
labels: [
|
|
42
|
+
{ value: 'Technical Specifications', language: 'en-US' }
|
|
43
|
+
],
|
|
44
|
+
languages: ['en-US'],
|
|
45
|
+
type: 'document',
|
|
46
|
+
renditions: [],
|
|
47
|
+
directoryNodes: []
|
|
48
|
+
}
|
|
49
|
+
];
|
|
50
|
+
|
|
51
|
+
export const Default: Story = {
|
|
52
|
+
args: {
|
|
53
|
+
items: mockItems as any
|
|
54
|
+
}
|
|
55
|
+
};
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { FC, ReactNode } from "react";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
Table,
|
|
5
|
+
TableBody,
|
|
6
|
+
TableCell,
|
|
7
|
+
TableHeader,
|
|
8
|
+
TableRow,
|
|
9
|
+
} from "@c-rex/ui/table";
|
|
10
|
+
import { informationUnitsItems, Labels } from "@c-rex/interfaces";
|
|
11
|
+
//import { getFlagIcon } from '@c-rex/utils/index';
|
|
12
|
+
|
|
13
|
+
interface TableViewProps {
|
|
14
|
+
items: informationUnitsItems[];
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const TableView: FC<TableViewProps> = ({ items }) => {
|
|
18
|
+
const getTitle = (labels: Labels[]): string => {
|
|
19
|
+
return labels.map((item) => item.value).join();
|
|
20
|
+
};
|
|
21
|
+
const getIcons = (languages: string[]): ReactNode[] => {
|
|
22
|
+
return languages.map((lang, index) => {
|
|
23
|
+
const aux = lang.split("-")[1];
|
|
24
|
+
|
|
25
|
+
/*
|
|
26
|
+
const FlagIcon = getFlagIcon(aux);
|
|
27
|
+
|
|
28
|
+
return FlagIcon && (
|
|
29
|
+
<div key={index} style={{ width: 36 }} className="border me-3">
|
|
30
|
+
<FlagIcon />
|
|
31
|
+
</div>
|
|
32
|
+
)
|
|
33
|
+
*/
|
|
34
|
+
|
|
35
|
+
return (
|
|
36
|
+
<div key={index} style={{ width: 36 }} className="border me-3">
|
|
37
|
+
{aux}
|
|
38
|
+
</div>
|
|
39
|
+
);
|
|
40
|
+
});
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
return (
|
|
44
|
+
<div className="rounded-md border">
|
|
45
|
+
<Table>
|
|
46
|
+
<TableHeader>
|
|
47
|
+
<TableRow>
|
|
48
|
+
<TableCell>Title</TableCell>
|
|
49
|
+
<TableCell>Country</TableCell>
|
|
50
|
+
</TableRow>
|
|
51
|
+
</TableHeader>
|
|
52
|
+
<TableBody>
|
|
53
|
+
{items.map((item, index) => (
|
|
54
|
+
<TableRow key={index}>
|
|
55
|
+
<TableCell>{getTitle(item.labels)}</TableCell>
|
|
56
|
+
<TableCell>{getIcons(item.languages)}</TableCell>
|
|
57
|
+
</TableRow>
|
|
58
|
+
))}
|
|
59
|
+
</TableBody>
|
|
60
|
+
</Table>
|
|
61
|
+
</div>
|
|
62
|
+
);
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export default TableView;
|
package/src/sidebar.tsx
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { ComponentProps } from "react";
|
|
4
|
+
import {
|
|
5
|
+
Sidebar,
|
|
6
|
+
SidebarContent,
|
|
7
|
+
SidebarGroup,
|
|
8
|
+
SidebarMenu,
|
|
9
|
+
SidebarMenuButton,
|
|
10
|
+
SidebarMenuItem,
|
|
11
|
+
SidebarMenuSub,
|
|
12
|
+
SidebarMenuSubButton,
|
|
13
|
+
SidebarMenuSubItem,
|
|
14
|
+
SidebarRail
|
|
15
|
+
} from "@c-rex/ui/sidebar";
|
|
16
|
+
import { Skeleton } from "@c-rex/ui/skeleton";
|
|
17
|
+
import { TreeOfContent } from "@c-rex/interfaces";
|
|
18
|
+
|
|
19
|
+
interface SidebarProps extends ComponentProps<typeof Sidebar> {
|
|
20
|
+
data: TreeOfContent[];
|
|
21
|
+
loading?: boolean;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function AppSidebar({ data, loading, ...props }: SidebarProps) {
|
|
25
|
+
return (
|
|
26
|
+
<Sidebar collapsible="icon" {...props} className="top-20">
|
|
27
|
+
<SidebarContent>
|
|
28
|
+
<SidebarGroup>
|
|
29
|
+
<SidebarMenu className="pt-4">
|
|
30
|
+
{loading ? (
|
|
31
|
+
<>
|
|
32
|
+
<Skeleton className="w-auto h-10 mb-2" />
|
|
33
|
+
<Skeleton className="w-auto h-10 mb-2" />
|
|
34
|
+
<Skeleton className="w-auto h-10 mb-2 ml-8" />
|
|
35
|
+
<Skeleton className="w-auto h-10 mb-2 ml-8" />
|
|
36
|
+
<Skeleton className="w-auto h-10 mb-2 ml-8" />
|
|
37
|
+
<Skeleton className="w-auto h-10 mb-2 ml-8" />
|
|
38
|
+
<Skeleton className="w-auto h-10 mb-2" />
|
|
39
|
+
</>
|
|
40
|
+
) : (
|
|
41
|
+
<>
|
|
42
|
+
{data.map((item) => (
|
|
43
|
+
<SidebarMenuItem key={item.id}>
|
|
44
|
+
<SidebarMenuButton asChild isActive={item.active}>
|
|
45
|
+
<a href={item.link} title={item.label}>
|
|
46
|
+
{item.label}
|
|
47
|
+
</a>
|
|
48
|
+
</SidebarMenuButton>
|
|
49
|
+
|
|
50
|
+
{item.children?.length ? (
|
|
51
|
+
<SidebarMenuSub>
|
|
52
|
+
{item.children.map((item) => (
|
|
53
|
+
<SidebarMenuSubItem key={item.label}>
|
|
54
|
+
<SidebarMenuSubButton
|
|
55
|
+
asChild
|
|
56
|
+
isActive={item.active}
|
|
57
|
+
>
|
|
58
|
+
<a href={item.link} title={item.label}>
|
|
59
|
+
{item.label}
|
|
60
|
+
</a>
|
|
61
|
+
</SidebarMenuSubButton>
|
|
62
|
+
</SidebarMenuSubItem>
|
|
63
|
+
))}
|
|
64
|
+
</SidebarMenuSub>
|
|
65
|
+
) : null}
|
|
66
|
+
</SidebarMenuItem>
|
|
67
|
+
))}
|
|
68
|
+
</>
|
|
69
|
+
)}
|
|
70
|
+
</SidebarMenu>
|
|
71
|
+
</SidebarGroup>
|
|
72
|
+
</SidebarContent>
|
|
73
|
+
<SidebarRail />
|
|
74
|
+
</Sidebar>
|
|
75
|
+
);
|
|
76
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import { BlogCard } from '../blog-card';
|
|
3
|
+
|
|
4
|
+
const meta: Meta = {
|
|
5
|
+
title: 'Components/BlogCard',
|
|
6
|
+
component: BlogCard,
|
|
7
|
+
tags: ['autodocs',],
|
|
8
|
+
parameters: {
|
|
9
|
+
layout: 'centered',
|
|
10
|
+
},
|
|
11
|
+
argTypes: {
|
|
12
|
+
data: { control: 'object', description: 'The data to be displayed in the card' },
|
|
13
|
+
priority: { control: 'boolean', description: 'Whether the image should be prioritized', type: 'boolean' },
|
|
14
|
+
horizontal: { control: 'boolean' },
|
|
15
|
+
},
|
|
16
|
+
} satisfies Meta<typeof BlogCard>;
|
|
17
|
+
|
|
18
|
+
export default meta;
|
|
19
|
+
type Story = StoryObj<typeof meta>;
|
|
20
|
+
|
|
21
|
+
const mockBlogData = {
|
|
22
|
+
title: 'Getting Started with C-Rex Components',
|
|
23
|
+
blurDataURL: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg==',
|
|
24
|
+
image: 'https://images.pexels.com/photos/31712301/pexels-photo-31712301/free-photo-of-scenic-cycling-tour-in-andernach-fields.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1',
|
|
25
|
+
description: 'Learn how to use C-Rex components to build modern web applications with React and Next.js.',
|
|
26
|
+
authors: 'John Doe',
|
|
27
|
+
_id: '1',
|
|
28
|
+
date: '2023-05-15',
|
|
29
|
+
slug: 'getting-started-with-c-rex-components',
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export const Horizontal: Story = {
|
|
33
|
+
args: {
|
|
34
|
+
data: mockBlogData,
|
|
35
|
+
priority: false,
|
|
36
|
+
horizontal: true,
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export const WithPriority: Story = {
|
|
41
|
+
args: {
|
|
42
|
+
data: mockBlogData,
|
|
43
|
+
priority: true,
|
|
44
|
+
horizontal: false,
|
|
45
|
+
},
|
|
46
|
+
};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import { BlurImage } from '../blur-image';
|
|
3
|
+
|
|
4
|
+
const meta = {
|
|
5
|
+
title: 'Components/BlurImage',
|
|
6
|
+
component: BlurImage,
|
|
7
|
+
tags: ['autodocs'],
|
|
8
|
+
parameters: {
|
|
9
|
+
layout: 'centered',
|
|
10
|
+
},
|
|
11
|
+
argTypes: {
|
|
12
|
+
src: { control: 'text' },
|
|
13
|
+
alt: { control: 'text' },
|
|
14
|
+
width: { control: 'number' },
|
|
15
|
+
height: { control: 'number' },
|
|
16
|
+
className: { control: 'text' },
|
|
17
|
+
},
|
|
18
|
+
} satisfies Meta<typeof BlurImage>;
|
|
19
|
+
|
|
20
|
+
export default meta;
|
|
21
|
+
type Story = StoryObj<typeof meta>;
|
|
22
|
+
|
|
23
|
+
export const Default: Story = {
|
|
24
|
+
args: {
|
|
25
|
+
src: 'https://images.pexels.com/photos/31712301/pexels-photo-31712301/free-photo-of-scenic-cycling-tour-in-andernach-fields.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1',
|
|
26
|
+
alt: 'Sample image with blur effect',
|
|
27
|
+
width: 400,
|
|
28
|
+
height: 300,
|
|
29
|
+
className: 'rounded-lg',
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export const SmallImage: Story = {
|
|
34
|
+
args: {
|
|
35
|
+
src: 'https://images.pexels.com/photos/31712301/pexels-photo-31712301/free-photo-of-scenic-cycling-tour-in-andernach-fields.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1',
|
|
36
|
+
alt: 'Small sample image with blur effect',
|
|
37
|
+
width: 200,
|
|
38
|
+
height: 150,
|
|
39
|
+
className: 'rounded-lg',
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export const RoundedImage: Story = {
|
|
44
|
+
args: {
|
|
45
|
+
src: 'https://images.pexels.com/photos/31712301/pexels-photo-31712301/free-photo-of-scenic-cycling-tour-in-andernach-fields.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1',
|
|
46
|
+
alt: 'Rounded sample image with blur effect',
|
|
47
|
+
width: 300,
|
|
48
|
+
height: 300,
|
|
49
|
+
className: 'rounded-full',
|
|
50
|
+
},
|
|
51
|
+
};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import { Breadcrumb } from '../breadcrumb';
|
|
3
|
+
|
|
4
|
+
const meta: Meta = {
|
|
5
|
+
title: 'Components/Breadcrumb',
|
|
6
|
+
component: Breadcrumb,
|
|
7
|
+
tags: ['autodocs'],
|
|
8
|
+
parameters: {
|
|
9
|
+
layout: 'centered',
|
|
10
|
+
}
|
|
11
|
+
} satisfies Meta;
|
|
12
|
+
|
|
13
|
+
export default meta;
|
|
14
|
+
type Story = StoryObj<typeof meta>;
|
|
15
|
+
|
|
16
|
+
const mockItems = [
|
|
17
|
+
{
|
|
18
|
+
id: 'docs',
|
|
19
|
+
label: 'Documentation',
|
|
20
|
+
link: '/docs',
|
|
21
|
+
active: false,
|
|
22
|
+
children: [],
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
id: 'components',
|
|
26
|
+
label: 'Components',
|
|
27
|
+
link: '/docs/components',
|
|
28
|
+
active: false,
|
|
29
|
+
children: [],
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
id: 'breadcrumb',
|
|
33
|
+
label: 'Breadcrumb',
|
|
34
|
+
link: '/docs/components/breadcrumb',
|
|
35
|
+
active: true,
|
|
36
|
+
children: [],
|
|
37
|
+
},
|
|
38
|
+
];
|
|
39
|
+
|
|
40
|
+
export const Default: Story = {
|
|
41
|
+
args: {
|
|
42
|
+
items: mockItems,
|
|
43
|
+
loading: false,
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export const Loading: Story = {
|
|
48
|
+
args: {
|
|
49
|
+
items: [],
|
|
50
|
+
loading: true,
|
|
51
|
+
},
|
|
52
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import { Empty } from '../empty';
|
|
3
|
+
|
|
4
|
+
const meta = {
|
|
5
|
+
title: 'Components/Empty',
|
|
6
|
+
component: Empty,
|
|
7
|
+
tags: ['autodocs'],
|
|
8
|
+
} satisfies Meta<typeof Empty>;
|
|
9
|
+
|
|
10
|
+
export default meta;
|
|
11
|
+
type Story = StoryObj<typeof meta>;
|
|
12
|
+
|
|
13
|
+
export const Default: Story = {
|
|
14
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import { NavBar } from '../navbar';
|
|
3
|
+
|
|
4
|
+
const meta: Meta = {
|
|
5
|
+
title: 'Components/NavBar',
|
|
6
|
+
component: NavBar,
|
|
7
|
+
tags: ['autodocs'],
|
|
8
|
+
parameters: {
|
|
9
|
+
layout: 'padded',
|
|
10
|
+
},
|
|
11
|
+
} satisfies Meta<typeof NavBar>;
|
|
12
|
+
|
|
13
|
+
export default meta;
|
|
14
|
+
type Story = StoryObj<typeof meta>;
|
|
15
|
+
|
|
16
|
+
export const Default: Story = {}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import { AppSidebar } from '../sidebar';
|
|
3
|
+
import { SidebarInset, SidebarProvider, SidebarTrigger } from "@c-rex/ui/sidebar";
|
|
4
|
+
|
|
5
|
+
const meta = {
|
|
6
|
+
title: 'Components/Sidebar',
|
|
7
|
+
component: AppSidebar,
|
|
8
|
+
tags: ['autodocs'],
|
|
9
|
+
parameters: {
|
|
10
|
+
layout: 'centered',
|
|
11
|
+
},
|
|
12
|
+
argTypes: {
|
|
13
|
+
data: { control: 'object' },
|
|
14
|
+
loading: { control: 'boolean' },
|
|
15
|
+
},
|
|
16
|
+
decorators: [
|
|
17
|
+
(Story: any) => (
|
|
18
|
+
<SidebarProvider>
|
|
19
|
+
<SidebarTrigger />
|
|
20
|
+
|
|
21
|
+
<div className="flex">
|
|
22
|
+
<SidebarInset>
|
|
23
|
+
<Story />
|
|
24
|
+
</SidebarInset>
|
|
25
|
+
</div>
|
|
26
|
+
</SidebarProvider>
|
|
27
|
+
|
|
28
|
+
),
|
|
29
|
+
]
|
|
30
|
+
} satisfies Meta<typeof AppSidebar>;
|
|
31
|
+
|
|
32
|
+
export default meta;
|
|
33
|
+
type Story = StoryObj<typeof meta>;
|
|
34
|
+
|
|
35
|
+
const mockData = [
|
|
36
|
+
{
|
|
37
|
+
id: '1',
|
|
38
|
+
label: 'Getting Started',
|
|
39
|
+
link: '/docs/getting-started',
|
|
40
|
+
active: true,
|
|
41
|
+
children: [
|
|
42
|
+
{
|
|
43
|
+
id: '1-1',
|
|
44
|
+
label: 'Installation',
|
|
45
|
+
link: '/docs/getting-started/installation',
|
|
46
|
+
active: false,
|
|
47
|
+
children: [],
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
id: '1-2',
|
|
51
|
+
label: 'Configuration',
|
|
52
|
+
link: '/docs/getting-started/configuration',
|
|
53
|
+
active: false,
|
|
54
|
+
children: [],
|
|
55
|
+
},
|
|
56
|
+
],
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
id: '2',
|
|
60
|
+
label: 'Components',
|
|
61
|
+
link: '/docs/components',
|
|
62
|
+
active: false,
|
|
63
|
+
children: [
|
|
64
|
+
{
|
|
65
|
+
id: '2-1',
|
|
66
|
+
label: 'Sidebar',
|
|
67
|
+
link: '/docs/components/sidebar',
|
|
68
|
+
active: false,
|
|
69
|
+
children: [],
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
id: '2-2',
|
|
73
|
+
label: 'Navbar',
|
|
74
|
+
link: '/docs/components/navbar',
|
|
75
|
+
active: false,
|
|
76
|
+
children: [],
|
|
77
|
+
},
|
|
78
|
+
],
|
|
79
|
+
},
|
|
80
|
+
];
|
|
81
|
+
|
|
82
|
+
export const Default: Story = {
|
|
83
|
+
args: {
|
|
84
|
+
data: mockData,
|
|
85
|
+
loading: false,
|
|
86
|
+
},
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
export const Loading: Story = {
|
|
90
|
+
args: {
|
|
91
|
+
data: [],
|
|
92
|
+
loading: true,
|
|
93
|
+
},
|
|
94
|
+
};
|