@node-core/ui-components 0.0.1 → 1.0.1-1d5a7f279720e5e4da66f43d06a6a9a14cb7c2d2

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 (190) hide show
  1. package/Common/AlertBox/index.module.css +76 -0
  2. package/Common/AlertBox/index.stories.tsx +73 -0
  3. package/Common/AlertBox/index.tsx +24 -0
  4. package/Common/AvatarGroup/Avatar/index.module.css +40 -0
  5. package/Common/AvatarGroup/Avatar/index.stories.tsx +22 -0
  6. package/Common/AvatarGroup/Avatar/index.tsx +67 -0
  7. package/Common/AvatarGroup/Overlay/index.module.css +31 -0
  8. package/Common/AvatarGroup/Overlay/index.stories.tsx +33 -0
  9. package/Common/AvatarGroup/Overlay/index.tsx +37 -0
  10. package/Common/AvatarGroup/__tests__/index.test.jsx +55 -0
  11. package/Common/AvatarGroup/index.module.css +25 -0
  12. package/Common/AvatarGroup/index.stories.tsx +56 -0
  13. package/Common/AvatarGroup/index.tsx +87 -0
  14. package/Common/Badge/index.module.css +38 -0
  15. package/Common/Badge/index.stories.tsx +38 -0
  16. package/Common/Badge/index.tsx +35 -0
  17. package/Common/BadgeGroup/index.module.css +77 -0
  18. package/Common/BadgeGroup/index.stories.tsx +35 -0
  19. package/Common/BadgeGroup/index.tsx +35 -0
  20. package/Common/Banner/index.module.css +42 -0
  21. package/Common/Banner/index.stories.tsx +29 -0
  22. package/Common/Banner/index.tsx +18 -0
  23. package/Common/BaseActiveLink/__tests__/index.test.jsx +52 -0
  24. package/Common/BaseActiveLink/index.tsx +34 -0
  25. package/Common/BaseButton/index.module.css +142 -0
  26. package/Common/BaseButton/index.stories.tsx +67 -0
  27. package/Common/BaseButton/index.tsx +59 -0
  28. package/Common/BaseCodeBox/index.module.css +78 -0
  29. package/Common/BaseCodeBox/index.stories.tsx +39 -0
  30. package/Common/BaseCodeBox/index.tsx +122 -0
  31. package/Common/BaseCrossLink/index.module.css +51 -0
  32. package/Common/BaseCrossLink/index.stories.tsx +38 -0
  33. package/Common/BaseCrossLink/index.tsx +46 -0
  34. package/Common/BaseLinkTabs/index.module.css +43 -0
  35. package/Common/BaseLinkTabs/index.stories.tsx +34 -0
  36. package/Common/BaseLinkTabs/index.tsx +53 -0
  37. package/Common/BasePagination/Ellipsis/index.module.css +10 -0
  38. package/Common/BasePagination/Ellipsis/index.stories.tsx +10 -0
  39. package/Common/BasePagination/Ellipsis/index.tsx +11 -0
  40. package/Common/BasePagination/PaginationListItem/__tests__/index.test.jsx +58 -0
  41. package/Common/BasePagination/PaginationListItem/index.module.css +27 -0
  42. package/Common/BasePagination/PaginationListItem/index.stories.tsx +40 -0
  43. package/Common/BasePagination/PaginationListItem/index.tsx +39 -0
  44. package/Common/BasePagination/PrevNextArrow.tsx +15 -0
  45. package/Common/BasePagination/__tests__/index.test.jsx +180 -0
  46. package/Common/BasePagination/index.module.css +39 -0
  47. package/Common/BasePagination/index.stories.tsx +67 -0
  48. package/Common/BasePagination/index.tsx +77 -0
  49. package/Common/BasePagination/useGetPageElements.tsx +132 -0
  50. package/Common/Blockquote/index.module.css +29 -0
  51. package/Common/Blockquote/index.stories.tsx +45 -0
  52. package/Common/Blockquote/index.tsx +11 -0
  53. package/Common/Breadcrumbs/BreadcrumbHomeLink/index.module.css +5 -0
  54. package/Common/Breadcrumbs/BreadcrumbHomeLink/index.tsx +30 -0
  55. package/Common/Breadcrumbs/BreadcrumbItem/index.module.css +41 -0
  56. package/Common/Breadcrumbs/BreadcrumbItem/index.tsx +42 -0
  57. package/Common/Breadcrumbs/BreadcrumbLink/index.module.css +22 -0
  58. package/Common/Breadcrumbs/BreadcrumbLink/index.tsx +37 -0
  59. package/Common/Breadcrumbs/BreadcrumbRoot/index.module.css +9 -0
  60. package/Common/Breadcrumbs/BreadcrumbRoot/index.tsx +20 -0
  61. package/Common/Breadcrumbs/BreadcrumbTruncatedItem/index.tsx +9 -0
  62. package/Common/Breadcrumbs/index.stories.tsx +94 -0
  63. package/Common/Breadcrumbs/index.tsx +81 -0
  64. package/Common/CodeTabs/index.module.css +56 -0
  65. package/Common/CodeTabs/index.stories.tsx +73 -0
  66. package/Common/CodeTabs/index.tsx +16 -0
  67. package/Common/DataTag/index.module.css +56 -0
  68. package/Common/DataTag/index.stories.tsx +40 -0
  69. package/Common/DataTag/index.tsx +39 -0
  70. package/Common/GlowingBackdrop/index.module.css +32 -0
  71. package/Common/GlowingBackdrop/index.stories.tsx +10 -0
  72. package/Common/GlowingBackdrop/index.tsx +13 -0
  73. package/Common/LanguageDropDown/index.module.css +53 -0
  74. package/Common/LanguageDropDown/index.stories.tsx +19 -0
  75. package/Common/LanguageDropDown/index.tsx +56 -0
  76. package/Common/Modal/index.module.css +79 -0
  77. package/Common/Modal/index.stories.tsx +32 -0
  78. package/Common/Modal/index.tsx +48 -0
  79. package/Common/NodejsLogo/index.module.css +6 -0
  80. package/Common/NodejsLogo/index.stories.tsx +14 -0
  81. package/Common/NodejsLogo/index.tsx +26 -0
  82. package/Common/Notification/index.module.css +20 -0
  83. package/Common/Notification/index.stories.tsx +36 -0
  84. package/Common/Notification/index.tsx +34 -0
  85. package/Common/Preview/index.module.css +79 -0
  86. package/Common/Preview/index.stories.tsx +44 -0
  87. package/Common/Preview/index.tsx +25 -0
  88. package/Common/ProgressionSidebar/ProgressionSidebarGroup/index.module.css +47 -0
  89. package/Common/ProgressionSidebar/ProgressionSidebarGroup/index.tsx +35 -0
  90. package/Common/ProgressionSidebar/ProgressionSidebarIcon/index.tsx +16 -0
  91. package/Common/ProgressionSidebar/ProgressionSidebarItem/index.module.css +39 -0
  92. package/Common/ProgressionSidebar/ProgressionSidebarItem/index.tsx +32 -0
  93. package/Common/ProgressionSidebar/index.module.css +30 -0
  94. package/Common/ProgressionSidebar/index.stories.tsx +79 -0
  95. package/Common/ProgressionSidebar/index.tsx +59 -0
  96. package/Common/Select/__tests__/index.test.jsx +67 -0
  97. package/Common/Select/index.module.css +161 -0
  98. package/Common/Select/index.stories.tsx +111 -0
  99. package/Common/Select/index.tsx +187 -0
  100. package/Common/Separator/index.module.css +16 -0
  101. package/Common/Separator/index.stories.tsx +32 -0
  102. package/Common/Separator/index.tsx +27 -0
  103. package/Common/Skeleton/index.module.css +30 -0
  104. package/Common/Skeleton/index.tsx +39 -0
  105. package/Common/Tabs/__tests__/index.test.jsx +52 -0
  106. package/Common/Tabs/index.module.css +54 -0
  107. package/Common/Tabs/index.stories.tsx +50 -0
  108. package/Common/Tabs/index.tsx +54 -0
  109. package/Common/ThemeToggle/__tests__/index.test.jsx +35 -0
  110. package/Common/ThemeToggle/index.module.css +15 -0
  111. package/Common/ThemeToggle/index.stories.tsx +10 -0
  112. package/Common/ThemeToggle/index.tsx +15 -0
  113. package/Common/Tooltip/index.module.css +43 -0
  114. package/Common/Tooltip/index.stories.tsx +73 -0
  115. package/Common/Tooltip/index.tsx +48 -0
  116. package/Containers/Article/index.module.css +70 -0
  117. package/Containers/Article/index.stories.tsx +39 -0
  118. package/Containers/Article/index.tsx +9 -0
  119. package/Containers/Footer/index.module.css +46 -0
  120. package/Containers/Footer/index.stories.tsx +27 -0
  121. package/Containers/Footer/index.tsx +95 -0
  122. package/Containers/MetaBar/__tests__/index.test.jsx +63 -0
  123. package/Containers/MetaBar/index.module.css +91 -0
  124. package/Containers/MetaBar/index.stories.tsx +80 -0
  125. package/Containers/MetaBar/index.tsx +72 -0
  126. package/Containers/NavBar/NavItem/index.module.css +60 -0
  127. package/Containers/NavBar/NavItem/index.stories.tsx +38 -0
  128. package/Containers/NavBar/NavItem/index.tsx +44 -0
  129. package/Containers/NavBar/index.module.css +125 -0
  130. package/Containers/NavBar/index.stories.tsx +45 -0
  131. package/Containers/NavBar/index.tsx +94 -0
  132. package/Containers/Sidebar/SidebarGroup/index.module.css +26 -0
  133. package/Containers/Sidebar/SidebarGroup/index.stories.tsx +36 -0
  134. package/Containers/Sidebar/SidebarGroup/index.tsx +30 -0
  135. package/Containers/Sidebar/SidebarItem/index.module.css +35 -0
  136. package/Containers/Sidebar/SidebarItem/index.stories.tsx +15 -0
  137. package/Containers/Sidebar/SidebarItem/index.tsx +26 -0
  138. package/Containers/Sidebar/index.module.css +31 -0
  139. package/Containers/Sidebar/index.stories.tsx +84 -0
  140. package/Containers/Sidebar/index.tsx +58 -0
  141. package/Icons/HexagonGrid.stories.tsx +10 -0
  142. package/Icons/HexagonGrid.tsx +1434 -0
  143. package/Icons/InstallationMethod/Choco.tsx +78 -0
  144. package/Icons/InstallationMethod/Devbox.tsx +21 -0
  145. package/Icons/InstallationMethod/Docker.tsx +20 -0
  146. package/Icons/InstallationMethod/FNM.tsx +132 -0
  147. package/Icons/InstallationMethod/Homebrew.tsx +69 -0
  148. package/Icons/InstallationMethod/N.tsx +32 -0
  149. package/Icons/InstallationMethod/NVM.tsx +63 -0
  150. package/Icons/InstallationMethod/Volta.tsx +34 -0
  151. package/Icons/InstallationMethod/index.ts +10 -0
  152. package/Icons/Logos/JsGreen.tsx +24 -0
  153. package/Icons/Logos/JsWhite.tsx +37 -0
  154. package/Icons/Logos/Nodejs.tsx +188 -0
  155. package/Icons/Logos/NodejsStackedBlack.tsx +98 -0
  156. package/Icons/Logos/NodejsStackedDark.tsx +124 -0
  157. package/Icons/Logos/NodejsStackedLight.tsx +123 -0
  158. package/Icons/Logos/NodejsStackedWhite.tsx +98 -0
  159. package/Icons/Logos/index.ts +17 -0
  160. package/Icons/OperatingSystem/AIX.tsx +46 -0
  161. package/Icons/OperatingSystem/Apple.tsx +23 -0
  162. package/Icons/OperatingSystem/Linux.tsx +969 -0
  163. package/Icons/OperatingSystem/Microsoft.tsx +19 -0
  164. package/Icons/OperatingSystem/index.ts +6 -0
  165. package/Icons/PackageManager/Npm.tsx +21 -0
  166. package/Icons/PackageManager/Pnpm.tsx +22 -0
  167. package/Icons/PackageManager/Yarn.tsx +22 -0
  168. package/Icons/PackageManager/index.ts +5 -0
  169. package/Icons/Social/Bluesky.tsx +19 -0
  170. package/Icons/Social/Discord.tsx +20 -0
  171. package/Icons/Social/GitHub.tsx +16 -0
  172. package/Icons/Social/LinkedIn.tsx +16 -0
  173. package/Icons/Social/Mastodon.tsx +36 -0
  174. package/Icons/Social/Slack.tsx +31 -0
  175. package/Icons/Social/X.tsx +16 -0
  176. package/Icons/Social/index.ts +9 -0
  177. package/LICENSE +21 -0
  178. package/MDX/CodeTabs.tsx +47 -0
  179. package/package.json +87 -5
  180. package/stylelint/__tests__/index.test.mjs +80 -0
  181. package/stylelint/one-utility-class-per-line.mjs +64 -0
  182. package/stylelint/utils.mjs +53 -0
  183. package/styles/animations.css +47 -0
  184. package/styles/base.css +17 -0
  185. package/styles/effects.css +12 -0
  186. package/styles/index.css +38 -0
  187. package/styles/markdown.css +173 -0
  188. package/styles/theme.css +175 -0
  189. package/types.ts +25 -0
  190. package/README.md +0 -1
@@ -0,0 +1,73 @@
1
+ import type { Meta as MetaObj, StoryObj } from '@storybook/react';
2
+
3
+ import Tooltip from '#ui/Common/Tooltip';
4
+
5
+ type Story = StoryObj<typeof Tooltip>;
6
+ type Meta = MetaObj<typeof Tooltip>;
7
+
8
+ const defaultProps = {
9
+ children: <a>Rocket Turtle</a>,
10
+ content: <div className="p-3">🚀 🐢</div>,
11
+ };
12
+
13
+ export const Default: Story = {
14
+ args: defaultProps,
15
+ };
16
+
17
+ export const Warning: Story = {
18
+ args: {
19
+ ...defaultProps,
20
+ kind: 'warning',
21
+ },
22
+ };
23
+
24
+ export const Error: Story = {
25
+ args: {
26
+ ...defaultProps,
27
+ kind: 'error',
28
+ },
29
+ };
30
+
31
+ export const LeftSide: Story = {
32
+ args: {
33
+ ...defaultProps,
34
+ side: 'left',
35
+ },
36
+ decorators: [
37
+ Story => (
38
+ <div className="flex w-72 justify-end">
39
+ <Story />
40
+ </div>
41
+ ),
42
+ ],
43
+ };
44
+
45
+ export const RightSide: Story = {
46
+ args: {
47
+ ...defaultProps,
48
+ side: 'left',
49
+ },
50
+ decorators: [
51
+ Story => (
52
+ <div className="flex w-72 justify-start">
53
+ <Story />
54
+ </div>
55
+ ),
56
+ ],
57
+ };
58
+
59
+ export const TopSide: Story = {
60
+ args: {
61
+ ...defaultProps,
62
+ side: 'top',
63
+ },
64
+ decorators: [
65
+ Story => (
66
+ <div className="flex h-72 items-end">
67
+ <Story />
68
+ </div>
69
+ ),
70
+ ],
71
+ };
72
+
73
+ export default { component: Tooltip } as Meta;
@@ -0,0 +1,48 @@
1
+ import * as TooltipPrimitive from '@radix-ui/react-tooltip';
2
+ import classNames from 'classnames';
3
+ import type { FC, PropsWithChildren, ReactNode } from 'react';
4
+
5
+ import styles from './index.module.css';
6
+
7
+ type TooltipProps = {
8
+ asChild?: boolean;
9
+ content: ReactNode;
10
+ kind?: 'default' | 'warning' | 'error';
11
+ side?: TooltipPrimitive.TooltipContentProps['side'];
12
+ container?: HTMLElement | null;
13
+ };
14
+
15
+ const Tooltip: FC<PropsWithChildren<TooltipProps>> = ({
16
+ kind = 'default',
17
+ children,
18
+ content,
19
+ asChild = false,
20
+ side = 'bottom',
21
+ container,
22
+ }) => (
23
+ <TooltipPrimitive.Provider delayDuration={200}>
24
+ <TooltipPrimitive.Root>
25
+ <TooltipPrimitive.Trigger asChild={asChild}>
26
+ {children}
27
+ </TooltipPrimitive.Trigger>
28
+ <TooltipPrimitive.Portal container={container}>
29
+ <TooltipPrimitive.Content
30
+ side={side}
31
+ sideOffset={4}
32
+ className={classNames(styles[kind], styles.content, {
33
+ 'mx-1.5': side === 'top' || side === 'bottom',
34
+ })}
35
+ >
36
+ {content}
37
+ <TooltipPrimitive.Arrow
38
+ className={styles.arrow}
39
+ width={14}
40
+ height={6}
41
+ />
42
+ </TooltipPrimitive.Content>
43
+ </TooltipPrimitive.Portal>
44
+ </TooltipPrimitive.Root>
45
+ </TooltipPrimitive.Provider>
46
+ );
47
+
48
+ export default Tooltip;
@@ -0,0 +1,70 @@
1
+ @reference "../../styles/index.css";
2
+
3
+ .articleLayout {
4
+ @apply max-w-8xl
5
+ mx-auto
6
+ block
7
+ w-full
8
+ sm:grid
9
+ sm:grid-cols-[theme(spacing.52)_1fr]
10
+ sm:grid-rows-[1fr]
11
+ sm:overflow-visible
12
+ sm:[grid-template-areas:'sidebar_main''sidebar_footer']
13
+ md:grid-cols-[theme(spacing.64)_1fr]
14
+ lg:grid-cols-[theme(spacing.52)_1fr_theme(spacing.52)]
15
+ lg:[grid-template-areas:'sidebar_main_metabar''sidebar_footer_metabar']
16
+ xl:grid-cols-[theme(spacing.80)_1fr_theme(spacing.80)];
17
+
18
+ > *:nth-child(1) {
19
+ @apply [grid-area:sidebar]
20
+ lg:sticky
21
+ lg:top-0
22
+ lg:h-[100vh]
23
+ lg:overflow-y-auto;
24
+ }
25
+
26
+ > *:nth-child(2) {
27
+ @apply contents
28
+ sm:max-lg:block;
29
+
30
+ > *:first-child {
31
+ @apply sm:bg-gradient-subtle
32
+ sm:dark:bg-gradient-subtle-dark
33
+ xl:px-18
34
+ p-4
35
+ [grid-area:main]
36
+ motion-safe:scroll-smooth
37
+ sm:bg-fixed
38
+ sm:p-12;
39
+ }
40
+
41
+ > *:last-child {
42
+ @apply mt-8
43
+ border-t
44
+ [grid-area:metabar]
45
+ sm:mt-0
46
+ lg:sticky
47
+ lg:top-0
48
+ lg:max-w-xs
49
+ lg:border-l
50
+ lg:border-t-0;
51
+ }
52
+ }
53
+
54
+ > *:nth-child(3) {
55
+ @apply sticky
56
+ bottom-0
57
+ flex
58
+ w-full
59
+ flex-col
60
+ items-center
61
+ self-stretch
62
+ border-t
63
+ border-t-neutral-200
64
+ bg-white
65
+ py-4
66
+ [grid-area:footer]
67
+ dark:border-t-neutral-900
68
+ dark:bg-neutral-950;
69
+ }
70
+ }
@@ -0,0 +1,39 @@
1
+ import type { Meta as MetaObj, StoryObj } from '@storybook/react';
2
+
3
+ import Article from '.';
4
+
5
+ type Story = StoryObj<typeof Article>;
6
+ type Meta = MetaObj<typeof Article>;
7
+
8
+ const Sidebar = () => (
9
+ <div className="text-center">
10
+ <h3>Sidebar</h3>
11
+ <ul>
12
+ <li>Navigation Item 1</li>
13
+ <li>Navigation Item 2</li>
14
+ <li>Navigation Item 3</li>
15
+ <li>Navigation Item 4</li>
16
+ </ul>
17
+ </div>
18
+ );
19
+
20
+ export const Default: Story = {
21
+ args: {
22
+ children: (
23
+ <>
24
+ <Sidebar />
25
+ <div>
26
+ <main>
27
+ <p>
28
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
29
+ eiusmod tempor incididunt ut labore et dolore magna aliqua.
30
+ </p>
31
+ </main>
32
+ <Sidebar />
33
+ </div>
34
+ </>
35
+ ),
36
+ },
37
+ };
38
+
39
+ export default { component: Article } as Meta;
@@ -0,0 +1,9 @@
1
+ import type { FC, PropsWithChildren } from 'react';
2
+
3
+ import styles from './index.module.css';
4
+
5
+ const ArticleLayout: FC<PropsWithChildren> = ({ children }) => (
6
+ <div className={styles.articleLayout}>{children}</div>
7
+ );
8
+
9
+ export default ArticleLayout;
@@ -0,0 +1,46 @@
1
+ @reference "../../styles/index.css";
2
+
3
+ .footer {
4
+ @apply flex
5
+ flex-col
6
+ items-center
7
+ gap-6
8
+ border-t
9
+ border-neutral-200
10
+ bg-white
11
+ py-4
12
+ sm:px-8
13
+ md:flex-row
14
+ md:justify-between
15
+ md:py-5
16
+ dark:border-neutral-900
17
+ dark:bg-neutral-950;
18
+
19
+ .sectionPrimary {
20
+ @apply flex
21
+ flex-wrap
22
+ content-start
23
+ items-center
24
+ justify-center
25
+ gap-1
26
+ self-stretch;
27
+
28
+ a {
29
+ @apply whitespace-nowrap;
30
+ }
31
+ }
32
+
33
+ .sectionSecondary {
34
+ @apply flex
35
+ flex-col
36
+ items-center
37
+ gap-1
38
+ md:flex-row;
39
+
40
+ .social {
41
+ @apply flex
42
+ items-center
43
+ gap-1;
44
+ }
45
+ }
46
+ }
@@ -0,0 +1,27 @@
1
+ import type { Meta as MetaObj, StoryObj } from '@storybook/react';
2
+
3
+ import Footer from '#ui/Containers/Footer';
4
+
5
+ type Story = StoryObj<typeof Footer>;
6
+ type Meta = MetaObj<typeof Footer>;
7
+
8
+ export const Default: Story = {
9
+ args: {
10
+ navigation: {
11
+ footerLinks: [
12
+ { link: '/', text: 'Home' },
13
+ { link: 'https://openjsf.org', text: 'OpenJS Foundation' },
14
+ ],
15
+ socialLinks: [
16
+ { icon: 'github', link: 'https://github.com' },
17
+ { icon: 'mastodon', link: 'https://mastodon.social' },
18
+ { icon: 'twitter', link: 'https://twitter.com' },
19
+ { icon: 'slack', link: 'https://slack.com' },
20
+ { icon: 'linkedin', link: 'https://linkedin.com' },
21
+ { icon: 'bluesky', link: 'https://bsky.app' },
22
+ ],
23
+ },
24
+ },
25
+ };
26
+
27
+ export default { component: Footer } as Meta;
@@ -0,0 +1,95 @@
1
+ 'use client';
2
+
3
+ import type { FC, SVGProps } from 'react';
4
+
5
+ import NavItem from '#ui/Containers/NavBar/NavItem';
6
+ import {
7
+ Bluesky,
8
+ Discord,
9
+ GitHub,
10
+ LinkedIn,
11
+ Mastodon,
12
+ Slack,
13
+ X,
14
+ } from '#ui/Icons/Social';
15
+ import type { LinkLike } from '#ui/types';
16
+
17
+ import styles from './index.module.css';
18
+
19
+ const footerSocialIcons: Record<string, React.FC<SVGProps<SVGSVGElement>>> = {
20
+ github: GitHub,
21
+ mastodon: Mastodon,
22
+ twitter: X,
23
+ slack: Slack,
24
+ linkedin: LinkedIn,
25
+ bluesky: Bluesky,
26
+ discord: Discord,
27
+ };
28
+
29
+ type Navigation = {
30
+ socialLinks: Array<{
31
+ icon: string;
32
+ link: string;
33
+ }>;
34
+ footerLinks: Array<{
35
+ text: string;
36
+ link: string;
37
+ }>;
38
+ };
39
+
40
+ const Footer: FC<{
41
+ pathname: string;
42
+ as: LinkLike;
43
+ navigation: Navigation;
44
+ }> = ({ pathname = '/', as = 'a', navigation }) => {
45
+ const openJSlink = navigation.footerLinks.at(-1)!;
46
+
47
+ return (
48
+ <footer className={styles.footer}>
49
+ <div className={styles.sectionPrimary}>
50
+ {navigation.footerLinks.slice(0, -1).map(item => (
51
+ <NavItem
52
+ key={item.link}
53
+ type="footer"
54
+ href={item.link}
55
+ as={as}
56
+ pathname={pathname}
57
+ >
58
+ {item.text}
59
+ </NavItem>
60
+ ))}
61
+ </div>
62
+
63
+ <div className={styles.sectionSecondary}>
64
+ <NavItem
65
+ type="footer"
66
+ href={openJSlink.link}
67
+ as={as}
68
+ pathname={pathname}
69
+ >
70
+ &copy; {openJSlink.text}
71
+ </NavItem>
72
+
73
+ <div className={styles.social}>
74
+ {navigation.socialLinks.map(link => {
75
+ const SocialIcon = footerSocialIcons[link.icon];
76
+
77
+ return (
78
+ <NavItem
79
+ key={link.icon}
80
+ href={link.link}
81
+ type="footer"
82
+ as={as}
83
+ pathname={pathname}
84
+ >
85
+ <SocialIcon width={20} height={20} aria-label={link.link} />
86
+ </NavItem>
87
+ );
88
+ })}
89
+ </div>
90
+ </div>
91
+ </footer>
92
+ );
93
+ };
94
+
95
+ export default Footer;
@@ -0,0 +1,63 @@
1
+ import { describe, it } from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+
4
+ import { render } from '@testing-library/react';
5
+
6
+ import MetaBar from '..';
7
+
8
+ describe('MetaBar', () => {
9
+ it('does not render h5s in the table of contents', () => {
10
+ const { queryByText, getByText } = render(
11
+ <MetaBar
12
+ items={{}}
13
+ headings={{
14
+ items: [
15
+ {
16
+ value: 'Heading Level 1',
17
+ depth: 1,
18
+ data: { id: 'heading-1' },
19
+ },
20
+ {
21
+ value: 'Heading Level 2',
22
+ depth: 2,
23
+ data: { id: 'heading-2' },
24
+ },
25
+ {
26
+ value: 'Heading Level 3',
27
+ depth: 3,
28
+ data: { id: 'heading-3' },
29
+ },
30
+ {
31
+ value: 'Heading Level 4',
32
+ depth: 4,
33
+ data: { id: 'heading-4' },
34
+ },
35
+ {
36
+ value: 'Heading Level 5',
37
+ depth: 5,
38
+ data: { id: 'heading-5' },
39
+ },
40
+ {
41
+ value: 'Heading Level 6',
42
+ depth: 6,
43
+ data: { id: 'heading-6' },
44
+ },
45
+ ],
46
+ }}
47
+ />
48
+ );
49
+
50
+ const h1Element = queryByText('Heading Level 1');
51
+ assert.ok(!h1Element?.ownerDocument);
52
+
53
+ getByText('Heading Level 2');
54
+ getByText('Heading Level 3');
55
+ getByText('Heading Level 4');
56
+
57
+ const h5Element = queryByText('Heading Level 5');
58
+ assert.ok(!h5Element?.ownerDocument);
59
+
60
+ const h6Element = queryByText('Heading Level 6');
61
+ assert.ok(!h6Element?.ownerDocument);
62
+ });
63
+ });
@@ -0,0 +1,91 @@
1
+ @reference "../../styles/index.css";
2
+
3
+ .wrapper {
4
+ @apply flex
5
+ w-full
6
+ flex-col
7
+ items-start
8
+ gap-8
9
+ border-neutral-200
10
+ px-4
11
+ py-6
12
+ [overflow-wrap:anywhere]
13
+ lg:sticky
14
+ lg:top-0
15
+ lg:max-h-screen
16
+ lg:px-6
17
+ dark:border-neutral-900;
18
+
19
+ dl {
20
+ @apply flex
21
+ w-full
22
+ flex-col
23
+ gap-1.5
24
+ pb-12
25
+ [scrollbar-width:none]
26
+ lg:max-h-[calc(100vh-var(--header-height))]
27
+ lg:overflow-y-auto
28
+ [&::-webkit-scrollbar]:hidden;
29
+ }
30
+
31
+ dt {
32
+ @apply mb-2
33
+ text-sm
34
+ font-medium
35
+ text-neutral-800
36
+ dark:text-neutral-200;
37
+ }
38
+
39
+ dd {
40
+ @apply mb-8
41
+ flex
42
+ items-center
43
+ gap-2
44
+ text-sm
45
+ text-neutral-900
46
+ dark:text-white;
47
+
48
+ a {
49
+ @apply max-xs:inline-block
50
+ max-xs:py-1
51
+ font-semibold
52
+ text-neutral-900
53
+ underline
54
+ dark:text-white;
55
+
56
+ &:hover {
57
+ @apply text-neutral-800
58
+ dark:text-neutral-200;
59
+ }
60
+ }
61
+
62
+ ol {
63
+ @apply flex
64
+ w-full
65
+ list-none
66
+ flex-col
67
+ gap-1.5
68
+ p-0;
69
+ }
70
+
71
+ svg {
72
+ @apply size-4
73
+ text-neutral-600
74
+ dark:text-neutral-400;
75
+ }
76
+
77
+ &:last-child {
78
+ @apply mb-0;
79
+ }
80
+ }
81
+
82
+ [data-on-dark] {
83
+ @apply hidden
84
+ dark:block;
85
+ }
86
+
87
+ [data-on-light] {
88
+ @apply block
89
+ dark:hidden;
90
+ }
91
+ }
@@ -0,0 +1,80 @@
1
+ import { CodeBracketIcon } from '@heroicons/react/24/outline';
2
+ import type { Meta as MetaObj, StoryObj } from '@storybook/react';
3
+
4
+ import MetaBar from '#ui/Containers/MetaBar';
5
+ import GitHubIcon from '#ui/Icons/Social/GitHub';
6
+
7
+ type Story = StoryObj<typeof MetaBar>;
8
+ type Meta = MetaObj<typeof MetaBar>;
9
+
10
+ export const Default: Story = {
11
+ args: {
12
+ items: {
13
+ 'components.metabar.lastUpdated': new Date(
14
+ '17 October 2023'
15
+ ).toLocaleDateString(),
16
+ 'components.metabar.readingTime': '15 minutes',
17
+ 'components.metabar.addedIn': 'v1.0.0',
18
+ 'components.metabar.author': 'The Node.js Project',
19
+ 'components.metabar.authors': <p>...</p>,
20
+ 'components.metabar.contribute': (
21
+ <>
22
+ <GitHubIcon className="fill-neutral-700 dark:fill-neutral-100" />
23
+ <a href="/contribute">Edit this page</a>
24
+ </>
25
+ ),
26
+ 'components.metabar.viewAs': (
27
+ <>
28
+ <CodeBracketIcon />
29
+ <a href="/json">JSON</a>
30
+ </>
31
+ ),
32
+ },
33
+ headings: {
34
+ items: [
35
+ {
36
+ value: 'OpenSSL update assessment, and Node.js project plans',
37
+ depth: 1,
38
+ data: { id: 'heading-1' },
39
+ },
40
+ {
41
+ value: 'Summary',
42
+ depth: 2,
43
+ data: { id: 'summary' },
44
+ },
45
+ {
46
+ value: 'Analysis',
47
+ depth: 2,
48
+ data: { id: 'analysis' },
49
+ },
50
+ {
51
+ value: 'The c_rehash script allows command injection (CVE-2022-2068)',
52
+ depth: 3,
53
+ data: { id: 'the_c_rehash' },
54
+ },
55
+ {
56
+ value: 'Contact and future updates',
57
+ depth: 3,
58
+ data: { id: 'contact_and_future_updates' },
59
+ },
60
+ {
61
+ value: 'Email',
62
+ depth: 4,
63
+ data: { id: 'email' },
64
+ },
65
+ {
66
+ value: 'Slack',
67
+ depth: 4,
68
+ data: { id: 'slack' },
69
+ },
70
+ {
71
+ value: '#node-website',
72
+ depth: 5, // h5s do not get shown
73
+ data: { id: 'node-website' },
74
+ },
75
+ ],
76
+ },
77
+ },
78
+ };
79
+
80
+ export default { component: MetaBar } as Meta;