@c-rex/components 0.1.21 → 0.1.23

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.
Files changed (53) hide show
  1. package/package.json +78 -62
  2. package/src/article/article-action-bar.tsx +89 -0
  3. package/src/article/article-content.tsx +55 -0
  4. package/src/autocomplete.tsx +55 -50
  5. package/src/breadcrumb.tsx +3 -1
  6. package/src/directoryNodes/tree-of-content.tsx +49 -0
  7. package/src/{bookmark-button.tsx → favorites/bookmark-button.tsx} +12 -3
  8. package/src/{favorite-button.tsx → favorites/favorite-button.tsx} +1 -1
  9. package/src/generated/client-components.tsx +1350 -0
  10. package/src/generated/create-client-request.tsx +105 -0
  11. package/src/generated/create-server-request.tsx +61 -0
  12. package/src/generated/create-suggestions-request.tsx +56 -0
  13. package/src/generated/server-components.tsx +1056 -0
  14. package/src/generated/suggestions.tsx +299 -0
  15. package/src/info/bookmark.tsx +51 -0
  16. package/src/info/info-table.tsx +127 -60
  17. package/src/info/shared.tsx +1 -1
  18. package/src/navbar/language-switcher/shared.tsx +1 -1
  19. package/src/navbar/navbar.tsx +1 -1
  20. package/src/{stories → navbar/stories}/navbar.stories.tsx +1 -1
  21. package/src/page-wrapper.tsx +1 -1
  22. package/src/renditions/file-download.tsx +84 -0
  23. package/src/renditions/html.tsx +55 -0
  24. package/src/renditions/image/container.tsx +52 -0
  25. package/src/renditions/image/rendition.tsx +61 -0
  26. package/src/{dialog-filter.tsx → results/dialog-filter.tsx} +22 -23
  27. package/src/results/filter-navbar.tsx +241 -0
  28. package/src/results/filter-sidebar/index.tsx +125 -0
  29. package/src/results/filter-sidebar/utils.ts +164 -0
  30. package/src/{pagination.tsx → results/pagination.tsx} +12 -10
  31. package/src/results/result-container.tsx +70 -0
  32. package/src/{stories/blog-view.stories.tsx → results/stories/cards.stories.tsx} +1 -1
  33. package/src/{stories/table-view.stories.tsx → results/stories/table.stories.tsx} +1 -1
  34. package/src/results/table-with-images.tsx +140 -0
  35. package/src/{result-view → results}/table.tsx +1 -2
  36. package/src/results/utils.ts +67 -0
  37. package/src/{navbar/search-input.tsx → search-input.tsx} +9 -6
  38. package/src/share-button.tsx +49 -0
  39. package/src/stores/search-settings-store.ts +1 -1
  40. package/src/blur-image.tsx +0 -23
  41. package/src/left-sidebar.tsx +0 -90
  42. package/src/result-list.tsx +0 -43
  43. package/src/result-view/table-with-images.tsx +0 -199
  44. package/src/right-sidebar.tsx +0 -70
  45. package/src/search-modal.tsx +0 -140
  46. package/src/stories/blur-image.stories.tsx +0 -51
  47. package/src/stories/sidebar.stories.tsx +0 -94
  48. /package/src/{file-icon.tsx → icons/file-icon.tsx} +0 -0
  49. /package/src/{flag.tsx → icons/flag-icon.tsx} +0 -0
  50. /package/src/{loading.tsx → icons/loading.tsx} +0 -0
  51. /package/src/{result-view/blog.tsx → results/cards.tsx} +0 -0
  52. /package/src/{empty.tsx → results/empty.tsx} +0 -0
  53. /package/src/{stories → results/stories}/empty.stories.tsx +0 -0
@@ -3,8 +3,9 @@
3
3
  import React, { FC, 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
- import { AutoComplete } from "../autocomplete";
7
6
  import { cn } from "@c-rex/utils";
7
+ import { InformationUnitsSuggestions } from "./generated/suggestions";
8
+ import { useQueryState } from "nuqs";
8
9
 
9
10
  type PlacedOn = "NAVBAR" | "BODY"
10
11
  type Props = {
@@ -14,6 +15,7 @@ type Props = {
14
15
  }
15
16
 
16
17
  export const SearchInput: FC<Props> = ({ showInput, showPkgFilter, placedOn = "NAVBAR" }) => {
18
+ const [pkg, setPkg] = useQueryState("package");
17
19
  const [checked, setChecked] = useState<boolean>(true);
18
20
 
19
21
  if (!showInput) return null
@@ -25,11 +27,12 @@ export const SearchInput: FC<Props> = ({ showInput, showPkgFilter, placedOn = "N
25
27
  )}>
26
28
  <Search className="shrink-0 opacity-50" />
27
29
 
28
- <AutoComplete
29
- initialValue=""
30
- embedded={true}
31
- searchByPackage={checked}
32
- />
30
+ {/*
31
+ Add scope=pkgID if checked is true
32
+ */}
33
+ <InformationUnitsSuggestions embedded onSelectParams={
34
+ (pkg && checked) ? [{ key: "packages", value: pkg }] : []
35
+ } />
33
36
 
34
37
  {showPkgFilter && <>
35
38
  <TooltipProvider>
@@ -0,0 +1,49 @@
1
+ "use client";
2
+
3
+ import { useEffect, useState } from "react";
4
+ import { Button } from "@c-rex/ui/button";
5
+ import { Share2 } from "lucide-react"
6
+
7
+ export const ShareButton = () => {
8
+ const [copied, setCopied] = useState(false);
9
+ const [shareData, setShareData] = useState({
10
+ title: '',
11
+ url: '',
12
+ });
13
+
14
+ useEffect(() => {
15
+ setShareData({
16
+ title: document.title,
17
+ url: window.location.href,
18
+ });
19
+ }, []);
20
+
21
+ const handleShare = async () => {
22
+ if (navigator.share) {
23
+ try {
24
+ await navigator.share(shareData);
25
+ console.log('Compartilhado com sucesso');
26
+ } catch (err) {
27
+ console.log('Erro ao compartilhar:', err);
28
+ }
29
+ } else {
30
+ navigator.clipboard.writeText(shareData.url);
31
+ setCopied(true);
32
+ setTimeout(() => setCopied(false), 2000);
33
+ }
34
+ };
35
+
36
+ return (
37
+ <div style={{ fontFamily: 'sans-serif' }}>
38
+ <Button
39
+ variant="ghost"
40
+ size="icon"
41
+ onClick={handleShare}
42
+ >
43
+ <Share2 />
44
+ </Button>
45
+ </div>
46
+ );
47
+ }
48
+
49
+
@@ -12,7 +12,7 @@ type SearchSettingsStore = {
12
12
 
13
13
  export const useSearchSettingsStore = create<SearchSettingsStore>()(
14
14
  persist((set) => ({
15
- language: [] as string[],
15
+ language: [],
16
16
  wildcard: "BOTH",
17
17
  operator: "OR",
18
18
  like: false,
@@ -1,23 +0,0 @@
1
- "use client";
2
-
3
- import React, { 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
- }
@@ -1,90 +0,0 @@
1
- "use client";
2
-
3
- import React, { ComponentProps, JSX } from "react";
4
- import {
5
- Sidebar,
6
- SidebarContent,
7
- SidebarGroup,
8
- SidebarMenu,
9
- SidebarMenuButton,
10
- SidebarMenuItem,
11
- SidebarMenuSub,
12
- SidebarMenuSubButton,
13
- SidebarMenuSubItem,
14
- } from "@c-rex/ui/sidebar";
15
- import { Skeleton } from "@c-rex/ui/skeleton";
16
- import { TreeOfContent } from "@c-rex/interfaces";
17
- import { cn } from "@c-rex/utils";
18
-
19
- interface SidebarProps extends ComponentProps<typeof Sidebar> {
20
- data: TreeOfContent[];
21
- loading?: boolean;
22
- }
23
-
24
- export function LeftSidebar({ data, loading, className, lang, ...props }: SidebarProps) {
25
-
26
- const tableOfContentGroup = (): JSX.Element | null => {
27
- if (loading) {
28
- return (
29
- <SidebarGroup className="pt-4">
30
- <Skeleton className="w-auto h-10 mb-2" />
31
- <Skeleton className="w-auto h-10 mb-2" />
32
- <Skeleton className="w-auto h-10 mb-2 ml-8" />
33
- <Skeleton className="w-auto h-10 mb-2 ml-8" />
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" />
37
- </SidebarGroup>
38
- )
39
- }
40
-
41
- if (data.length == 0) return null;
42
-
43
- const langProp = {} as any
44
-
45
- if (lang) {
46
- langProp.lang = lang
47
- }
48
-
49
- return (
50
- <SidebarGroup {...langProp}>
51
- <SidebarMenu>
52
- {data.map((item) => (
53
- <SidebarMenuItem key={item.id}>
54
- <SidebarMenuButton asChild isActive={item.active}>
55
- <a href={item.link} title={item.label}>
56
- {item.label}
57
- </a>
58
- </SidebarMenuButton>
59
-
60
- {item.children?.length ? (
61
- <SidebarMenuSub>
62
- {item.children.map((item) => (
63
- <SidebarMenuSubItem key={item.label}>
64
- <SidebarMenuSubButton
65
- asChild
66
- isActive={item.active}
67
- >
68
- <a href={item.link} title={item.label}>
69
- {item.label}
70
- </a>
71
- </SidebarMenuSubButton>
72
- </SidebarMenuSubItem>
73
- ))}
74
- </SidebarMenuSub>
75
- ) : null}
76
- </SidebarMenuItem>
77
- ))}
78
- </SidebarMenu>
79
- </SidebarGroup>
80
- );
81
- }
82
-
83
- return (
84
- <Sidebar className={cn(className)} {...props}>
85
- <SidebarContent>
86
- {tableOfContentGroup()}
87
- </SidebarContent>
88
- </Sidebar>
89
- );
90
- }
@@ -1,43 +0,0 @@
1
- import React, { FC, ReactNode } from "react";
2
- import { DefaultPageInfo, informationUnitsResponseItem, TopicsResponseItem, } from "@c-rex/interfaces";
3
- import { Empty } from "./empty";
4
- import BlogView from './result-view/blog';
5
- import TableView from './result-view/table';
6
- import { Pagination } from "./pagination";
7
- import { useAppConfig } from "@c-rex/contexts/config-provider";
8
- import { ResultViewStyles } from "@c-rex/types";
9
- import TableWithImageView from "./result-view/table-with-images";
10
-
11
- interface ResultListProps {
12
- items: informationUnitsResponseItem[] | TopicsResponseItem[];
13
- pagination: DefaultPageInfo;
14
- }
15
-
16
- export const ResultList: FC<ResultListProps> = ({ items, pagination }: ResultListProps) => {
17
- const { configs } = useAppConfig()
18
-
19
- const listComponent: Record<ResultViewStyles, ReactNode> = {
20
- "cards": <BlogView items={items as TopicsResponseItem[]} />,
21
- "table": <TableView items={items as informationUnitsResponseItem[]} />,
22
- "table-with-images": <TableWithImageView items={items as informationUnitsResponseItem[]} />,
23
- }
24
-
25
- if (!(configs.results.resultViewStyle in listComponent)) {
26
- throw new Error(`Unsupported result view style: ${configs.results.resultViewStyle}`);
27
- }
28
-
29
- if (items.length === 0) {
30
- return <Empty />;
31
- }
32
-
33
- return (
34
- <>
35
- {listComponent[configs.results.resultViewStyle as ResultViewStyles]}
36
-
37
- <Pagination
38
- totalPages={pagination.pageCount}
39
- currentPage={pagination.pageNumber}
40
- />
41
- </>
42
- );
43
- };
@@ -1,199 +0,0 @@
1
- import { FC, useEffect, useState } from "react";
2
- import { informationUnitsResponseItem } from "@c-rex/interfaces";
3
- import { CloudDownload, Eye, FileStack, ImageOff } from "lucide-react";
4
- import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@c-rex/ui/dropdown-menu";
5
- import { cn } from "@c-rex/utils";
6
- import { useQueryState } from "nuqs";
7
- import { Skeleton } from "@c-rex/ui/skeleton";
8
- import { FavoriteButton } from "../favorite-button";
9
- import { Button } from "@c-rex/ui/button";
10
- import { Tooltip, TooltipContent, TooltipTrigger } from "@c-rex/ui/tooltip";
11
- import { Favorite, ResultTypes } from "@c-rex/types";
12
- import { FileIcon } from "../file-icon";
13
- import { useFavoritesStore } from "../stores/favorites-store";
14
- import { BookmarkButton } from "../bookmark-button";
15
- import { FaRegBookmark } from "react-icons/fa6";
16
-
17
- interface TableWithImageViewProps {
18
- items: informationUnitsResponseItem[];
19
- }
20
-
21
- const Image: FC<{ id: string }> = ({ id }) => {
22
- const [imageUrl, setImageUrl] = useState("");
23
- const [loading, setLoading] = useState(true);
24
- const [error, setError] = useState(false);
25
-
26
- useEffect(() => {
27
- let ignore = false;
28
-
29
- async function fetchImage() {
30
- try {
31
- const res = await fetch(`https://picsum.photos/v2/list?limit=1`);
32
-
33
- {/*
34
- TODO: talvez vamos receber mais de uma imagem, mas por enquanto pegamos apenas a primeira na lista
35
- */}
36
-
37
-
38
- const data = await res.json();
39
- if (!ignore) {
40
- setImageUrl(data[0].download_url);
41
- setLoading(false);
42
- }
43
- } catch (err) {
44
- setError(true);
45
- console.error("Error loading image", err);
46
- }
47
- }
48
-
49
- fetchImage();
50
- return () => {
51
- ignore = true
52
- };
53
- }, [id]);
54
-
55
- if (error) {
56
- return <ImageOff className="h-16 w-16 text-muted" />;
57
- }
58
-
59
- return (
60
- <div className="h-16 w-16 flex items-center">
61
- {loading ? (
62
- <Skeleton className="h-16 w-16" />
63
- ) : (
64
- <img
65
- src={imageUrl}
66
- loading="lazy"
67
- onLoad={() => setLoading(false)}
68
- />
69
- )}
70
- </div>
71
- );
72
- }
73
-
74
- const TableWithImageView: FC<TableWithImageViewProps> = ({ items }) => {
75
- const [query] = useQueryState("search");
76
-
77
- const favoritesDocuments = useFavoritesStore((state) => state.documents);
78
-
79
- return (
80
- <div className="mb-6">
81
- {items.map((item, index) => {
82
- const isFavoriteDocument = Object.keys(favoritesDocuments).some((docId) => docId === item.shortId);
83
- let topicList: Favorite[] = []
84
-
85
- if (isFavoriteDocument && favoritesDocuments[item.shortId]) {
86
- topicList = favoritesDocuments[item.shortId]?.topics || []
87
- }
88
- return (
89
- <div
90
- key={index}
91
- className={cn(
92
- "min-h-12 flex flex-wrap items-center border px-4 py-2 gap-2 rounded mb-2",
93
- `c-rex-result-item c-rex-result-${item.type.toLowerCase()}`,
94
- item.disabled && "c-rex-result-item-disabled",
95
- )}
96
- >
97
-
98
- <div className="h-16 w-16 flex items-center">
99
- <Image id={item.shortId} />
100
- </div>
101
-
102
- <div className="flex-1 p-2 flex flex-col">
103
- <span className=" text-sm text-muted-foreground">
104
- {item.language.split("-")[0]?.toUpperCase()}
105
- </span>
106
-
107
- <span className="text-lg font-medium">
108
- {item.disabled ? (
109
- item.title
110
- ) : (
111
- <a className="hover:underline" href={`${item.link}?q=${query}`}>{item.title}</a>
112
- )}
113
- </span>
114
-
115
- <span className="text-sm">
116
- {item.type}
117
- </span>
118
- <span className="text-sm">
119
- short description here {/*
120
- TODO: get abstract if has the value key on it. Same behavior on class props
121
-
122
- abstract and description are not being returned by the API yet
123
- */}
124
- </span>
125
- </div>
126
-
127
- <div className="flex flex-col p-2 ml-auto justify-center">
128
- <span className="text-end text-sm text-muted-foreground mb-2">
129
- {item.revision}
130
- </span>
131
- <div className="flex gap-2">
132
- {Object.keys(item.files).map((fileKey, index) => {
133
- if (!item.files[fileKey]) return null
134
-
135
- return (
136
- <DropdownMenu key={index}>
137
- <DropdownMenuTrigger>
138
- <Button variant="ghost" size="icon">
139
- <FileIcon extension={fileKey} />
140
- </Button>
141
- </DropdownMenuTrigger>
142
- <DropdownMenuContent>
143
- <DropdownMenuItem>
144
- <a href={item.files[fileKey].view} target="_blank" rel="noreferrer" className="flex items-center">
145
- <Eye className="mr-2" /> Open {/*TODO: use i18n functions*/}
146
- </a>
147
- </DropdownMenuItem>
148
- <DropdownMenuItem>
149
- <a href={item.files[fileKey].download} target="_blank" rel="noreferrer" className="flex items-center">
150
- <CloudDownload className="mr-2" /> Download {/*TODO: use i18n functions*/}
151
- </a>
152
- </DropdownMenuItem>
153
- </DropdownMenuContent>
154
- </DropdownMenu>
155
- )
156
- })}
157
-
158
- {(topicList && topicList.length > 0) && (
159
- <BookmarkButton
160
- markersList={topicList.filter(item => item.label.length > 0)}
161
- trigger={
162
- <Button variant="ghost" size="icon" className="relative">
163
- <FaRegBookmark className="!w-5 color-primary" />
164
- <span
165
- className="absolute -top-[10px] -right-[10px] min-w-5 min-h-5 bg-primary text-white rounded-full"
166
- >
167
- {topicList.length}
168
- </span>
169
- </Button>
170
- }
171
- />
172
- )}
173
-
174
- <FavoriteButton id={item.shortId} type={item.type as ResultTypes} label={item.title} />
175
-
176
- {item.multipleVersions.length > 1 && (
177
- <Tooltip>
178
- <TooltipTrigger asChild>
179
- <Button variant="ghost" size="icon">
180
- <FileStack />
181
- </Button>
182
- </TooltipTrigger>
183
- <TooltipContent>
184
-
185
- Available in: {item.multipleVersions.join(", ")}
186
- </TooltipContent>
187
- </Tooltip>
188
- )}
189
- </div>
190
-
191
- </div>
192
- </div>
193
- )
194
- })}
195
- </div>
196
- );
197
- };
198
-
199
- export default TableWithImageView;
@@ -1,70 +0,0 @@
1
- "use client";
2
-
3
- import React, { ComponentProps } from "react";
4
- import {
5
- Sidebar,
6
- SidebarContent,
7
- } from "@c-rex/ui/sidebar";
8
- import { useTranslations } from "next-intl";
9
- import { articleInfoItemType, DocumentsType, Favorite } from "@c-rex/types";
10
- import { InfoTable } from "./info/info-table";
11
- import { AvailableVersionsInterface } from "@c-rex/interfaces";
12
- import { useFavoritesStore } from "./stores/favorites-store";
13
-
14
- interface SidebarProps extends ComponentProps<typeof Sidebar> {
15
- articleInfo: articleInfoItemType[],
16
- documentInfo: articleInfoItemType[],
17
- files: DocumentsType,
18
- articleAvailableVersions: AvailableVersionsInterface[],
19
- documentAvailableVersions: AvailableVersionsInterface[]
20
- documentId: string
21
- }
22
-
23
- export function RightSidebar({
24
- articleInfo,
25
- documentInfo,
26
- files,
27
- articleAvailableVersions,
28
- documentAvailableVersions,
29
- documentId,
30
- ...props
31
- }: SidebarProps) {
32
- const t = useTranslations();
33
- const favoritesDocuments = useFavoritesStore((state) => state.documents);
34
- const isFavoriteDocument = Object.keys(favoritesDocuments).some((docId) => docId === documentId);
35
- let favoritesList: Favorite[] = []
36
-
37
- if (Object.keys(favoritesDocuments).some(docId => docId === documentId)) {
38
- favoritesList = favoritesDocuments[documentId]?.topics || []
39
- }
40
-
41
- return (
42
- <Sidebar {...props}>
43
- <SidebarContent className="pt-4 pr-4 pb-10">
44
- {(articleInfo.length > 0 || documentInfo.length > 0) && (
45
- <>
46
-
47
- {documentInfo.length > 0 && (
48
- <InfoTable
49
- title={t("aboutDocument")}
50
- items={documentInfo}
51
- files={files}
52
- availableVersions={documentAvailableVersions}
53
- markersList={isFavoriteDocument ? favoritesList : []}
54
- />
55
- )}
56
-
57
- {articleInfo.length > 0 && (
58
- <InfoTable
59
- title={t("aboutArticle")}
60
- items={articleInfo}
61
- availableVersions={articleAvailableVersions}
62
- />
63
- )}
64
-
65
- </>
66
- )}
67
- </SidebarContent>
68
- </Sidebar>
69
- );
70
- }
@@ -1,140 +0,0 @@
1
- "use client"
2
-
3
- import React, { FC, useEffect, useState } from "react"
4
- import { Button } from "@c-rex/ui/button"
5
- import {
6
- Dialog,
7
- DialogClose,
8
- DialogContent,
9
- DialogFooter,
10
- DialogHeader,
11
- DialogTitle,
12
- DialogTrigger,
13
- } from "@c-rex/ui/dialog"
14
- import { parseAsBoolean, parseAsInteger, parseAsString, useQueryStates } from "nuqs"
15
- import { useTranslations } from "next-intl"
16
- import { WILD_CARD_OPTIONS } from "@c-rex/constants"
17
- import { call } from "@c-rex/utils"
18
- import { Input } from "@c-rex/ui/input"
19
- import { Label } from "@c-rex/ui/label"
20
- import { Checkbox } from "@c-rex/ui/checkbox"
21
- import { Toggle } from "@c-rex/ui/toggle"
22
- import { useLanguageStore } from "./stores/language-store"
23
-
24
- interface SearchModalProps {
25
- trigger: React.ReactNode;
26
- }
27
-
28
- export const SearchModal: FC<SearchModalProps> = ({ trigger }) => {
29
- const t = useTranslations("filter");
30
- const contentLang = useLanguageStore(state => state.contentLang);
31
- const [value, setValue] = useState<string>("");
32
- const [loading, setLoading] = useState<boolean>(false);
33
- const [suggestions, setSuggestions] = useState<string[]>([]);
34
-
35
- const [params, setParams] = useQueryStates({
36
- language: parseAsString,
37
- page: parseAsInteger,
38
- wildcard: parseAsString,
39
- operator: parseAsString,
40
- search: parseAsString,
41
- packages: parseAsString,
42
- tags: parseAsBoolean,
43
- like: parseAsBoolean,
44
- }, {
45
- history: 'push',
46
- shallow: false,
47
- });
48
-
49
-
50
- const onSearch = (value: string): Promise<string[]> => {
51
- return call<string[]>("InformationUnitsService.getSuggestions", { query: value, language: contentLang });
52
- }
53
-
54
-
55
- useEffect(() => {
56
- const debounceFetch = setTimeout(() => {
57
- if (value) {
58
- setLoading(true)
59
- onSearch(value).then(suggestions => {
60
- setSuggestions(suggestions)
61
- setLoading(false)
62
- });
63
- } else {
64
- setSuggestions([]);
65
- }
66
- }, 300);
67
-
68
- return () => clearTimeout(debounceFetch);
69
- }, [value]);
70
-
71
-
72
- const apply = () => {
73
- setParams({
74
- search: value,
75
- operator: "OR",
76
- page: 1,
77
- language: contentLang,
78
- wildcard: WILD_CARD_OPTIONS.BOTH,
79
- tags: false,
80
- like: false,
81
- });
82
- }
83
-
84
- return (
85
- <Dialog>
86
- <DialogTrigger asChild>
87
- {trigger}
88
- </DialogTrigger>
89
- <DialogContent>
90
- <DialogHeader>
91
- <DialogTitle>Search</DialogTitle>
92
- </DialogHeader>
93
- <Input value={value} autoFocus onChange={(e) => setValue(e.target.value)} />
94
-
95
- {loading ? (
96
- <div className="flex items-center justify-center py-4">
97
- <div className="animate-spin rounded-full h-6 w-6 border-2 border-gray-300 border-t-gray-950" />
98
- </div>
99
- ) : (
100
- <div>
101
- {suggestions.map((option) => (
102
- <Toggle
103
- key={option}
104
- value={option}
105
- className="m-0"
106
- onClick={(inputValue) => {
107
- setValue(`"${inputValue}"`);
108
- }}
109
- >
110
- {option}
111
- </Toggle>
112
- ))}
113
- </div>
114
- )}
115
-
116
- <Label className="hover:bg-accent/50 flex items-start gap-3 rounded-lg border p-3">
117
- <Checkbox
118
- id="toggle-2"
119
- defaultChecked
120
- className="data-[state=checked]:border-blue-600 data-[state=checked]:bg-blue-600 data-[state=checked]:text-white dark:data-[state=checked]:border-blue-700 dark:data-[state=checked]:bg-blue-700"
121
- />
122
- <div className="font-normal">
123
- <span className="text-sm leading-none font-medium">
124
- Search only on this document
125
- </span>
126
- <p className="text-muted-foreground text-sm">
127
- You can enable or disable notifications at any time.
128
- </p>
129
- </div>
130
- </Label>
131
-
132
- <DialogFooter className="pt-2">
133
- <DialogClose asChild>
134
- <Button onClick={apply}>{t("apply")}</Button>
135
- </DialogClose>
136
- </DialogFooter>
137
- </DialogContent>
138
- </Dialog >
139
- )
140
- }