diff --git a/components/Blog/BlogHeader/__tests__/index.test.mjs b/components/Blog/BlogHeader/__tests__/index.test.mjs new file mode 100644 index 0000000000000..ec47f6c1f043b --- /dev/null +++ b/components/Blog/BlogHeader/__tests__/index.test.mjs @@ -0,0 +1,29 @@ +import { render, screen } from '@testing-library/react'; + +import BlogHeader from '@/components/Blog/BlogHeader'; + +describe('BlogHeader', () => { + it('should have correct href when category is all', () => { + render(); + const link = screen.getByRole('link'); + expect(link).toHaveAttribute('href', '/feed/blog.xml'); + }); + + it('should have correct href when category is release', () => { + render(); + const link = screen.getByRole('link'); + expect(link).toHaveAttribute('href', '/feed/releases.xml'); + }); + + it('should have correct href when category is vulnerability', () => { + render(); + const link = screen.getByRole('link'); + expect(link).toHaveAttribute('href', '/feed/vulnerability.xml'); + }); + + it('should have correct href when category is random', () => { + render(); + const link = screen.getByRole('link'); + expect(link).toHaveAttribute('href', '/feed/blog.xml'); + }); +}); diff --git a/components/Blog/BlogHeader/index.module.css b/components/Blog/BlogHeader/index.module.css new file mode 100644 index 0000000000000..b7a0764768f5f --- /dev/null +++ b/components/Blog/BlogHeader/index.module.css @@ -0,0 +1,34 @@ +.blogHeader { + h1 { + @apply inline-flex + w-full + items-center + justify-between; + + a { + @apply inline-flex + size-9 + items-center + justify-center + rounded-md + p-2; + + &:hover { + @apply bg-neutral-100 + dark:bg-neutral-900; + } + } + + svg { + @apply size-6 + text-neutral-500; + } + } + + p { + @apply text-lg + font-medium + text-neutral-800 + dark:text-neutral-200; + } +} diff --git a/components/Blog/BlogHeader/index.stories.tsx b/components/Blog/BlogHeader/index.stories.tsx new file mode 100644 index 0000000000000..0e29b475119bc --- /dev/null +++ b/components/Blog/BlogHeader/index.stories.tsx @@ -0,0 +1,23 @@ +import type { Meta as MetaObj, StoryObj } from '@storybook/react'; + +import BlogHeader from '@/components/Blog/BlogHeader'; + +type Story = StoryObj; +type Meta = MetaObj; + +export const Default: Story = { + args: { + // See `@/site.json` for the `rssFeeds` object + category: 'all', + }, + decorators: [ + // We need to wrap to allow global styles to be applied (markdown styles) + Story => ( +
+ +
+ ), + ], +}; + +export default { component: BlogHeader } as Meta; diff --git a/components/Blog/BlogHeader/index.tsx b/components/Blog/BlogHeader/index.tsx new file mode 100644 index 0000000000000..487ad642f8751 --- /dev/null +++ b/components/Blog/BlogHeader/index.tsx @@ -0,0 +1,35 @@ +'use client'; + +import { RssIcon } from '@heroicons/react/24/solid'; +import { useTranslations } from 'next-intl'; +import type { FC } from 'react'; + +import Link from '@/components/Link'; +import { siteConfig } from '@/next.json.mjs'; + +import styles from './index.module.css'; + +type BlogHeaderProps = { + category: string; +}; + +const BlogHeader: FC = ({ category }) => { + const t = useTranslations(); + const currentFile = + siteConfig.rssFeeds.find(item => item.category === category)?.file ?? + 'blog.xml'; + + return ( +
+

+ {t('layouts.blog.title')} + + + +

+

{t('layouts.blog.subtitle')}

+
+ ); +}; + +export default BlogHeader; diff --git a/layouts/New/Blog.tsx b/layouts/New/Blog.tsx index 27f1d3c92d750..1b3e1084e8191 100644 --- a/layouts/New/Blog.tsx +++ b/layouts/New/Blog.tsx @@ -2,6 +2,7 @@ import { getTranslations } from 'next-intl/server'; import type { FC } from 'react'; import { getClientContext } from '@/client-context'; +import BlogHeader from '@/components/Blog/BlogHeader'; import WithBlogCategories from '@/components/withBlogCategories'; import WithFooter from '@/components/withFooter'; import WithNavBar from '@/components/withNavBar'; @@ -41,9 +42,7 @@ const BlogLayout: FC = async () => {
-

{t('layouts.blog.title')}

- -

{t('layouts.blog.subtitle')}

+