diff --git a/components/Common/AvatarGroup/index.module.css b/components/Common/AvatarGroup/index.module.css index b0934bf25cb30..38efcc06d07db 100644 --- a/components/Common/AvatarGroup/index.module.css +++ b/components/Common/AvatarGroup/index.module.css @@ -1,4 +1,5 @@ .avatarGroup { @apply flex + h-8 items-center; } diff --git a/components/Common/MetaBar/index.module.css b/components/Common/MetaBar/index.module.css new file mode 100644 index 0000000000000..e0b794ba604cb --- /dev/null +++ b/components/Common/MetaBar/index.module.css @@ -0,0 +1,67 @@ +.wrapper { + @apply flex + w-80 + flex-col + items-start + gap-8 + border-l + border-neutral-200 + p-6 + dark:border-neutral-900; + + dt { + @apply mb-2 + text-sm + font-medium + text-neutral-800 + dark:text-neutral-200; + } + + dd { + @apply mb-8 + flex + items-center + gap-2 + text-sm + text-neutral-900 + dark:text-white; + + a { + @apply font-semibold + text-neutral-900 + underline + hover:text-neutral-800 + dark:text-white + dark:hover:text-neutral-200; + } + + ol { + @apply flex + list-none + flex-col + gap-1.5 + p-0; + } + + svg { + @apply h-4 + w-4 + text-neutral-600 + dark:text-neutral-400; + } + + &:last-child { + @apply mb-0; + } + } + + [data-on-dark] { + @apply hidden + dark:block; + } + + [data-on-light] { + @apply block + dark:hidden; + } +} diff --git a/components/Common/MetaBar/index.stories.tsx b/components/Common/MetaBar/index.stories.tsx new file mode 100644 index 0000000000000..81a8569cf21e3 --- /dev/null +++ b/components/Common/MetaBar/index.stories.tsx @@ -0,0 +1,99 @@ +import { CodeBracketIcon } from '@heroicons/react/24/outline'; +import type { Meta as MetaObj, StoryObj } from '@storybook/react'; +import Image from 'next/image'; +import { FormattedMessage } from 'react-intl'; + +import AvatarGroup from '@/components/Common/AvatarGroup'; +import LocalizedLink from '@/components/LocalizedLink'; + +import MetaBar from './index'; + +type Story = StoryObj; +type Meta = MetaObj; + +export const Default: Story = { + args: { + items: { + 'components.metabar.lastUpdated': new Date().toLocaleDateString(), + 'components.metabar.readingTime': '15 minutes', + 'components.metabar.addedIn': 'v1.0.0', + 'components.metabar.author': 'The Node.js Project', + 'components.metabar.authors': ( + + ), + 'components.metabar.contribute': ( + <> + GitHub Logo + GitHub Logo + + + + + ), + 'components.metabar.viewAs': ( + <> + + JSON + + ), + }, + headings: { + items: [ + { + value: 'OpenSSL update assessment, and Node.js project plans', + depth: 1, + data: { id: 'heading-1' }, + }, + { + value: 'Summary', + depth: 2, + data: { id: 'summary' }, + }, + { + value: 'Analysis', + depth: 2, + data: { id: 'analysis' }, + }, + { + value: 'The c_rehash script allows command injection (CVE-2022-2068)', + depth: 3, + data: { id: 'the_c_rehash' }, + }, + { + value: 'Contact and future updates', + depth: 3, + data: { id: 'contact_and_future_updates' }, + }, + ], + }, + }, +}; + +export default { component: MetaBar } as Meta; diff --git a/components/Common/MetaBar/index.tsx b/components/Common/MetaBar/index.tsx new file mode 100644 index 0000000000000..3d8422e9c6cc9 --- /dev/null +++ b/components/Common/MetaBar/index.tsx @@ -0,0 +1,61 @@ +import type { Heading } from '@vcarl/remark-headings'; +import { Fragment, useMemo } from 'react'; +import type { FC } from 'react'; +import { FormattedMessage } from 'react-intl'; + +import LocalizedLink from '@/components/LocalizedLink'; + +import styles from './index.module.css'; + +type MetaBarProps = { + items: Record; + headings?: { + items: Heading[]; + depth?: number; + }; +}; + +const MetaBar: FC = ({ items, headings }) => { + // The default depth of headings to display in the table of contents. + const { depth = 2, items: headingItems = [] } = headings || {}; + + const heading = useMemo( + () => headingItems.filter(head => head.depth === depth), + [depth, headingItems] + ); + + return ( +
+
+ {Object.entries(items).map(([key, value]) => ( + +
+ +
+
{value}
+
+ ))} + {heading.length > 0 && ( + +
+ +
+
+
    + {heading.map(head => ( +
  1. + + {head.value} + +
  2. + ))} +
+
+
+ )} +
+
+ ); +}; + +export default MetaBar; diff --git a/i18n/locales/en.json b/i18n/locales/en.json index b6136e52ddbbc..d711b29920b5d 100644 --- a/i18n/locales/en.json +++ b/i18n/locales/en.json @@ -43,6 +43,15 @@ "components.common.crossLink.previous": "Prev", "components.common.crossLink.next": "Next", "components.common.codebox.copied": "Copied to clipboard!", + "components.metabar.lastUpdated": "Last Updated", + "components.metabar.readingTime": "Reading Time", + "components.metabar.addedIn": "Added In", + "components.metabar.author": "Author", + "components.metabar.authors": "Authors", + "components.metabar.contribute": "Contribute", + "components.metabar.contributeText": "Edit this page", + "components.metabar.viewAs": "View as", + "components.metabar.tableOfContents": "Table of Contents", "layouts.blogPost.author.byLine": "{author, select, null {} other {By {author}, }}", "layouts.blogIndex.currentYear": "News from {year}", "components.api.jsonLink.title": "View as JSON",