@c-rex/components 0.1.8 → 0.1.9

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@c-rex/components",
3
- "version": "0.1.8",
3
+ "version": "0.1.9",
4
4
  "files": [
5
5
  "src"
6
6
  ],
@@ -25,6 +25,14 @@
25
25
  "types": "./src/breadcrumb.tsx",
26
26
  "import": "./src/breadcrumb.tsx"
27
27
  },
28
+ "./pagination": {
29
+ "types": "./src/pagination.tsx",
30
+ "import": "./src/pagination.tsx"
31
+ },
32
+ "./info-card": {
33
+ "types": "./src/info-card.tsx",
34
+ "import": "./src/info-card.tsx"
35
+ },
28
36
  "./empty": {
29
37
  "types": "./src/empty.tsx",
30
38
  "import": "./src/empty.tsx"
@@ -1,4 +1,4 @@
1
- import React, { FC, use, useEffect, useState } from "react"
1
+ import React, { FC, useEffect, useState } from "react"
2
2
  import { Button } from "@c-rex/ui/button"
3
3
  import {
4
4
  Dialog,
@@ -18,10 +18,10 @@ import { useAppConfig } from "@c-rex/contexts/config-provider"
18
18
  import { LanguageAndCountries } from "@c-rex/interfaces"
19
19
  import { WILD_CARD_OPTIONS, OPERATOR_OPTIONS } from "@c-rex/constants"
20
20
  import { Switch } from "@c-rex/ui/switch"
21
+ import { useSearchContext } from "@c-rex/contexts/search"
21
22
 
22
23
  interface DialogFilterProps {
23
24
  trigger: React.ReactNode;
24
- setLoading: (loading: boolean) => void;
25
25
  }
26
26
  interface Languages {
27
27
  lang: string;
@@ -29,8 +29,9 @@ interface Languages {
29
29
  checked: boolean;
30
30
  }
31
31
 
32
- export const DialogFilter: FC<DialogFilterProps> = ({ trigger, setLoading }) => {
32
+ export const DialogFilter: FC<DialogFilterProps> = ({ trigger }) => {
33
33
  const t = useTranslations("filter");
34
+ const { setLoading } = useSearchContext();
34
35
  const { availableLanguagesAndCountries } = useAppConfig()
35
36
  const [params, setParams] = useQueryStates({
36
37
  language: parseAsString,
@@ -0,0 +1,38 @@
1
+ import { Card, CardContent, CardHeader, CardTitle } from "@c-rex/ui/card";
2
+ import { useTranslations } from "next-intl";
3
+ import React, { FC } from "react";
4
+
5
+ type Props = {
6
+ title: string;
7
+ items: {
8
+ label: string;
9
+ value: string;
10
+ link?: string;
11
+ }[]
12
+ }
13
+ export const InfoCard: FC<Props> = ({ title, items }) => {
14
+ const t = useTranslations();
15
+
16
+ return (
17
+ <Card>
18
+ <CardHeader>
19
+ <CardTitle className="text-lg">{title}</CardTitle>
20
+ </CardHeader>
21
+ <CardContent className="space-y-3">
22
+ {items.map((item, index) => (
23
+ <div key={index} className="border-b border-blog-divider last:border-0 pb-3 last:pb-0">
24
+ {item.link ? (
25
+ <a href={item.link}>
26
+ <h4 className="text-sm font-medium mb-1">{t(item.label)}</h4>
27
+ </a>
28
+ ) : (
29
+ <h4 className="text-sm font-medium mb-1">{t(item.label)}</h4>
30
+ )}
31
+
32
+ <span className="text-xs text-muted-foreground">{item.value}</span>
33
+ </div>
34
+ ))}
35
+ </CardContent>
36
+ </Card>
37
+ );
38
+ }
@@ -3,7 +3,7 @@
3
3
  import { startTransition } from "react";
4
4
  import { SharedLanguageSwitch } from "./shared";
5
5
  import { getFromCookieString, setCookie } from "@c-rex/utils";
6
- import { CONTENT_LANG_KEY } from "@c-rex/constants";
6
+ import { BLOG_TYPE_AND_LINK, CONTENT_LANG_KEY, DOCUMENTS_TYPE_AND_LINK, TOPICS_TYPE_AND_LINK } from "@c-rex/constants";
7
7
  import { useQueryState } from "nuqs"
8
8
  import { useAppConfig } from "@c-rex/contexts/config-provider";
9
9
  import { useTranslations } from "next-intl";
@@ -12,8 +12,22 @@ import { toast } from "sonner"
12
12
  export const ContentLanguageSwitch = () => {
13
13
  const t = useTranslations();
14
14
  const contentLang = getFromCookieString(document.cookie, CONTENT_LANG_KEY)
15
- const { availableLanguagesAndCountries, setContentLang, availableVersions } = useAppConfig()
15
+ const { availableLanguagesAndCountries: aux, setContentLang, availableVersions } = useAppConfig()
16
16
 
17
+ const availableLanguagesAndCountries = () => {
18
+ let result = aux.map(item => ({ ...item, link: "#" }))
19
+ if (availableVersions == null) return result
20
+
21
+ result = aux.map(item => {
22
+ const availableVersion = availableVersions.find(version => version.lang === item.value)
23
+ return {
24
+ ...item,
25
+ link: availableVersion?.link ?? "#"
26
+ }
27
+ })
28
+
29
+ return result;
30
+ }
17
31
  const [queryLanguage, setContentLanguage] = useQueryState('language', {
18
32
  history: 'push',
19
33
  shallow: false,
@@ -23,10 +37,19 @@ export const ContentLanguageSwitch = () => {
23
37
  startTransition(() => {
24
38
  setCookie(CONTENT_LANG_KEY, locale)
25
39
  setContentLang(locale)
40
+
26
41
  if (queryLanguage != null) {
27
42
  setContentLanguage(locale)
28
43
  }
29
44
 
45
+ const currentPath = window.location.pathname;
46
+ const isTopicOrBlogOrDocument = currentPath.includes(TOPICS_TYPE_AND_LINK) || currentPath.includes(BLOG_TYPE_AND_LINK) || currentPath.includes(DOCUMENTS_TYPE_AND_LINK)
47
+
48
+ if (!isTopicOrBlogOrDocument) {
49
+ window.location.reload();
50
+ return;
51
+ }
52
+
30
53
  if (availableVersions !== null) {
31
54
  const filteredList = availableVersions.filter((item) => item.lang === locale)
32
55
 
@@ -48,7 +71,7 @@ export const ContentLanguageSwitch = () => {
48
71
 
49
72
  return (
50
73
  <SharedLanguageSwitch
51
- availableLanguagesAndCountries={availableLanguagesAndCountries}
74
+ availableLanguagesAndCountries={availableLanguagesAndCountries()}
52
75
  changeLanguage={changeContentLanguage}
53
76
  selected={contentLang}
54
77
  />
@@ -4,7 +4,7 @@ import { LanguageAndCountries } from "@c-rex/interfaces";
4
4
  import { DropdownMenuRadioGroup, DropdownMenuRadioItem } from "@c-rex/ui/dropdown-menu";
5
5
 
6
6
  interface SharedLanguageSwitchProps {
7
- availableLanguagesAndCountries: LanguageAndCountries[];
7
+ availableLanguagesAndCountries: (LanguageAndCountries & { link?: string })[];
8
8
  selected: string;
9
9
  changeLanguage: (locale: string) => void;
10
10
  }
@@ -19,10 +19,18 @@ export const SharedLanguageSwitch: FC<SharedLanguageSwitchProps> = ({ availableL
19
19
  };
20
20
 
21
21
  return (
22
- <DropdownMenuRadioGroup value={selected} onValueChange={changeLanguage}>
22
+ <DropdownMenuRadioGroup value={selected}>
23
23
  {availableLanguagesAndCountries.map(item => {
24
24
  return (
25
- <DropdownMenuRadioItem key={item.value} value={item.value}>
25
+ <DropdownMenuRadioItem
26
+ key={item.value}
27
+ value={item.value}
28
+ link={item?.link}
29
+ onClick={(e) => {
30
+ e.preventDefault();
31
+ changeLanguage(item.value)
32
+ }}
33
+ >
26
34
  {getFlagIcon(item.country)}
27
35
  <span>{item.lang.toUpperCase()}</span>
28
36
  </DropdownMenuRadioItem>
@@ -8,6 +8,7 @@ import {
8
8
  PaginationPrevious,
9
9
  } from "@c-rex/ui/pagination"
10
10
  import { parseAsInteger, useQueryState } from "nuqs";
11
+ import { useSearchContext } from "@c-rex/contexts/search";
11
12
 
12
13
  interface PaginationProps {
13
14
  totalPages: number;
@@ -16,6 +17,7 @@ interface PaginationProps {
16
17
 
17
18
  export const Pagination: FC<PaginationProps> = ({ totalPages, currentPage }) => {
18
19
  const disabledClass = "opacity-50 pointer-events-none";
20
+ const { setLoading } = useSearchContext();
19
21
 
20
22
  const [_, setPage] = useQueryState('page',
21
23
  parseAsInteger.withOptions({
@@ -24,6 +26,11 @@ export const Pagination: FC<PaginationProps> = ({ totalPages, currentPage }) =>
24
26
  })
25
27
  )
26
28
 
29
+ const onChangePage = (pageNumber: number) => {
30
+ setLoading(true);
31
+ setPage(pageNumber);
32
+ }
33
+
27
34
  return (
28
35
  <PaginationUI className="py-4">
29
36
  <PaginationContent>
@@ -31,7 +38,7 @@ export const Pagination: FC<PaginationProps> = ({ totalPages, currentPage }) =>
31
38
  <PaginationPrevious
32
39
  href="#"
33
40
  className={currentPage === 1 ? disabledClass : ""}
34
- onClick={() => setPage(currentPage - 1)}
41
+ onClick={() => onChangePage(currentPage - 1)}
35
42
  />
36
43
  </PaginationItem>
37
44
 
@@ -40,7 +47,7 @@ export const Pagination: FC<PaginationProps> = ({ totalPages, currentPage }) =>
40
47
  <PaginationLink
41
48
  href="#"
42
49
  isActive={page === currentPage}
43
- onClick={() => setPage(page)}
50
+ onClick={() => onChangePage(page)}
44
51
  >
45
52
  {page}
46
53
  </PaginationLink>
@@ -55,7 +62,7 @@ export const Pagination: FC<PaginationProps> = ({ totalPages, currentPage }) =>
55
62
  <PaginationItem>
56
63
  <PaginationNext
57
64
  href="#"
58
- onClick={() => setPage(currentPage + 1)}
65
+ onClick={() => onChangePage(currentPage + 1)}
59
66
  className={currentPage === totalPages ? disabledClass : ""}
60
67
  />
61
68
  </PaginationItem>
@@ -1,17 +1,19 @@
1
1
  import React, { FC } from "react";
2
- import { ConfigInterface, DefaultPageInfo, informationUnitsResponseItem, } from "@c-rex/interfaces";
2
+ import { DefaultPageInfo, informationUnitsResponseItem, } from "@c-rex/interfaces";
3
3
  import { Empty } from "./empty";
4
4
  import BlogView from './result-view/blog';
5
5
  import TableView from './result-view/table';
6
6
  import { Pagination } from "./pagination";
7
+ import { useAppConfig } from "@c-rex/contexts/config-provider";
7
8
 
8
9
  interface ResultListProps {
9
10
  items: informationUnitsResponseItem[];
10
- configs: ConfigInterface;
11
11
  pagination: DefaultPageInfo;
12
12
  }
13
13
 
14
- export const ResultList: FC<ResultListProps> = ({ items, configs, pagination }: ResultListProps) => {
14
+ export const ResultList: FC<ResultListProps> = ({ items, pagination }: ResultListProps) => {
15
+ const { configs } = useAppConfig()
16
+
15
17
  const ViewComponent = configs.results.resultViewStyle == "table" ? TableView : BlogView;
16
18
 
17
19
  return (
@@ -1,20 +1,93 @@
1
- import React, { FC } from "react";
2
- import { BlogCard } from "../blog-card";
3
- import { informationUnitsResponseItem } from "@c-rex/interfaces";
1
+ "use client"
2
+
3
+ import React, { FC, useState } from "react";
4
+
5
+ import Link from "next/link";
6
+ import { cn } from "@c-rex/utils";
7
+ import { Badge } from "@c-rex/ui/badge";
8
+ import { useTranslations } from "next-intl";
9
+ import { TopicsResponseItem } from "@c-rex/interfaces";
10
+ import { Card } from "@c-rex/ui/card";
4
11
 
5
12
  interface BlogViewProps {
6
- items: informationUnitsResponseItem[];
13
+ items: TopicsResponseItem[];
7
14
  }
8
15
 
9
16
  const BlogView: FC<BlogViewProps> = ({ items }) => {
17
+ const t = useTranslations("results")
18
+ const [isLoading, setLoading] = useState(true);
10
19
  return (
11
- <div className="grid gap-8 md:grid-cols-2 md:gap-x-6 md:gap-y-10 xl:grid-cols-3">
12
- {items.map((item, index) => {
20
+ <div className="grid gap-6 grid-cols-2 ">
21
+ {items.map((item, index) => (
22
+
23
+ <Card
24
+ key={item.shortId}
25
+ className={cn(
26
+ `blog-card relative p-0 c-rex_result_${item.type.toLowerCase()}`,
27
+ index == 0
28
+ ? "col-span-2 grid grid-cols-1 gap-3 md:grid-cols-2 md:gap-6"
29
+ : "flex flex-col space-y-2",
30
+ item.disabled ? "c-rex_result_item_disabled" : ""
31
+ )}
32
+ >
33
+
34
+ <div className={
35
+ cn(
36
+ "w-full overflow-hidden",
37
+ index == 0 ? "rounded-tl-xl rounded-bl-xl" : "rounded-t-xl"
38
+ )}>
39
+ {item.image && (
40
+ <img
41
+ src={item.image}
42
+ alt={item.title}
43
+ className={cn(
44
+ "size-full object-cover object-center",
45
+ isLoading ? "bg-gray-300 animate-pulse" : "",
46
+ )}
47
+ style={{
48
+ width: "100%", height: index == 0 ? "auto" : "190px"
49
+ }}
50
+ onLoad={() => setLoading(false)}
51
+ onError={() => setLoading(false)}
52
+ />
53
+ )}
54
+
55
+ </div>
56
+
57
+ <div
58
+ className={cn(
59
+ "flex flex-1 flex-col p-4",
60
+ index == 0 ? "justify-around" : "justify-between",
61
+ )}
62
+ >
63
+ <div className="w-full">
64
+ <h2 className="my-1.5 line-clamp-2 font-heading text-2xl">
65
+ {item.title}
66
+ </h2>
67
+
68
+ {item.type && (
69
+ <Badge variant="secondary">
70
+ {item.type}
71
+ </Badge>
72
+ )}
73
+ </div>
74
+ <div className="mt-4 flex items-end flex-row gap-2">
75
+ <p className="m-0 flex-1 text-sm text-muted-foreground">{item.description?.substring(0, 100)}...</p>
76
+
77
+ {item.created && (
78
+ <p className="m-0 text-sm text-muted-foreground">{item.created}</p>
79
+ )}
80
+
81
+ </div>
82
+ </div>
13
83
 
14
- return (
15
- <BlogCard key={index} item={item} />
16
- );
17
- })}
84
+ {!item.disabled && (
85
+ <Link href={item.link} className="absolute inset-0">
86
+ <span className="sr-only">{t("viewArticle")}</span>
87
+ </Link>
88
+ )}
89
+ </Card>
90
+ ))}
18
91
  </div>
19
92
  );
20
93
  };
package/src/blog-card.tsx DELETED
@@ -1,88 +0,0 @@
1
- import Link from "next/link";
2
- import { cn } from "@c-rex/utils";
3
- import { BlurImage } from "./blur-image";
4
- import { useTranslations } from "next-intl";
5
- import { informationUnitsResponseItem } from "@c-rex/interfaces";
6
-
7
- interface BlogCardProp {
8
- item: informationUnitsResponseItem;
9
- priority?: boolean;
10
- horizontal?: boolean;
11
- }
12
-
13
- export const BlogCard = ({
14
- item,
15
- priority,
16
- horizontal = false,
17
- }: BlogCardProp) => {
18
- const t = useTranslations("results")
19
- const image = "/img/blog-post-1.webp"
20
- const blurDataURL = "/img/blog-post-1.webp"
21
-
22
- return (
23
- <article
24
- className={cn(
25
- "group relative", `c-rex_result_${item.type.toLowerCase()}`,
26
- horizontal
27
- ? "grid grid-cols-1 gap-3 md:grid-cols-2 md:gap-6"
28
- : "flex flex-col space-y-2",
29
- item.disabled ? "c-rex_result_item_disabled" : ""
30
- )}
31
- >
32
-
33
- <div className="w-full overflow-hidden rounded-xl border">
34
- <BlurImage
35
- alt={item.title}
36
- blurDataURL={blurDataURL}
37
- className={cn(
38
- "size-full object-cover object-center",
39
- horizontal ? "lg:h-72" : null,
40
- )}
41
- width={800}
42
- height={400}
43
- priority={priority}
44
- placeholder="blur"
45
- src={image}
46
- sizes="(max-width: 768px) 750px, 600px"
47
- />
48
- </div>
49
-
50
- <div
51
- className={cn(
52
- "flex flex-1 flex-col",
53
- horizontal ? "justify-center" : "justify-between",
54
- )}
55
- >
56
- <div className="w-full">
57
- <h2 className="my-1.5 line-clamp-2 font-heading text-2xl">
58
- {item.title}
59
- </h2>
60
- {item.type && (
61
- <p className="line-clamp-2 text-muted-foreground">
62
- {item.type}
63
- </p>
64
- )}
65
- </div>
66
- {/*
67
- <div className="mt-4 flex items-center space-x-3">
68
- <div className="flex items-center -space-x-2">
69
- {item.authors && (
70
- <p className="text-sm text-muted-foreground">{item.authors}</p>
71
- )}
72
- </div>
73
-
74
- {item.date && (
75
- <p className="text-sm text-muted-foreground">{item.date}</p>
76
- )}
77
- </div>
78
- */}
79
- </div>
80
-
81
- {!item.disabled && (
82
- <Link href={item.link} className="absolute inset-0">
83
- <span className="sr-only">{t("viewArticle")}</span>
84
- </Link>
85
- )}
86
- </article>
87
- );
88
- };
@@ -1,46 +0,0 @@
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
- };