@node-core/ui-components 0.0.1 → 1.0.1-f948ce8a25da149fc61135f90a43e189c4909f5d
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/Common/AlertBox/index.module.css +76 -0
- package/Common/AlertBox/index.stories.tsx +73 -0
- package/Common/AlertBox/index.tsx +24 -0
- package/Common/AvatarGroup/Avatar/index.module.css +40 -0
- package/Common/AvatarGroup/Avatar/index.stories.tsx +22 -0
- package/Common/AvatarGroup/Avatar/index.tsx +67 -0
- package/Common/AvatarGroup/Overlay/index.module.css +31 -0
- package/Common/AvatarGroup/Overlay/index.stories.tsx +33 -0
- package/Common/AvatarGroup/Overlay/index.tsx +37 -0
- package/Common/AvatarGroup/__tests__/index.test.jsx +55 -0
- package/Common/AvatarGroup/index.module.css +25 -0
- package/Common/AvatarGroup/index.stories.tsx +56 -0
- package/Common/AvatarGroup/index.tsx +87 -0
- package/Common/Badge/index.module.css +38 -0
- package/Common/Badge/index.stories.tsx +38 -0
- package/Common/Badge/index.tsx +35 -0
- package/Common/BadgeGroup/index.module.css +77 -0
- package/Common/BadgeGroup/index.stories.tsx +35 -0
- package/Common/BadgeGroup/index.tsx +35 -0
- package/Common/Banner/index.module.css +42 -0
- package/Common/Banner/index.stories.tsx +29 -0
- package/Common/Banner/index.tsx +18 -0
- package/Common/BaseActiveLink/__tests__/index.test.jsx +52 -0
- package/Common/BaseActiveLink/index.tsx +34 -0
- package/Common/BaseButton/index.module.css +142 -0
- package/Common/BaseButton/index.stories.tsx +67 -0
- package/Common/BaseButton/index.tsx +59 -0
- package/Common/BaseCodeBox/index.module.css +84 -0
- package/Common/BaseCodeBox/index.stories.tsx +39 -0
- package/Common/BaseCodeBox/index.tsx +133 -0
- package/Common/BaseCrossLink/index.module.css +51 -0
- package/Common/BaseCrossLink/index.stories.tsx +38 -0
- package/Common/BaseCrossLink/index.tsx +46 -0
- package/Common/BaseLinkTabs/index.module.css +43 -0
- package/Common/BaseLinkTabs/index.stories.tsx +34 -0
- package/Common/BaseLinkTabs/index.tsx +53 -0
- package/Common/BasePagination/Ellipsis/index.module.css +10 -0
- package/Common/BasePagination/Ellipsis/index.stories.tsx +10 -0
- package/Common/BasePagination/Ellipsis/index.tsx +11 -0
- package/Common/BasePagination/PaginationListItem/__tests__/index.test.jsx +58 -0
- package/Common/BasePagination/PaginationListItem/index.module.css +27 -0
- package/Common/BasePagination/PaginationListItem/index.stories.tsx +40 -0
- package/Common/BasePagination/PaginationListItem/index.tsx +39 -0
- package/Common/BasePagination/PrevNextArrow.tsx +15 -0
- package/Common/BasePagination/__tests__/index.test.jsx +180 -0
- package/Common/BasePagination/index.module.css +39 -0
- package/Common/BasePagination/index.stories.tsx +67 -0
- package/Common/BasePagination/index.tsx +77 -0
- package/Common/BasePagination/useGetPageElements.tsx +132 -0
- package/Common/Blockquote/index.module.css +29 -0
- package/Common/Blockquote/index.stories.tsx +45 -0
- package/Common/Blockquote/index.tsx +11 -0
- package/Common/Breadcrumbs/BreadcrumbHomeLink/index.module.css +5 -0
- package/Common/Breadcrumbs/BreadcrumbHomeLink/index.tsx +30 -0
- package/Common/Breadcrumbs/BreadcrumbItem/index.module.css +41 -0
- package/Common/Breadcrumbs/BreadcrumbItem/index.tsx +42 -0
- package/Common/Breadcrumbs/BreadcrumbLink/index.module.css +22 -0
- package/Common/Breadcrumbs/BreadcrumbLink/index.tsx +37 -0
- package/Common/Breadcrumbs/BreadcrumbRoot/index.module.css +9 -0
- package/Common/Breadcrumbs/BreadcrumbRoot/index.tsx +20 -0
- package/Common/Breadcrumbs/BreadcrumbTruncatedItem/index.tsx +9 -0
- package/Common/Breadcrumbs/index.stories.tsx +94 -0
- package/Common/Breadcrumbs/index.tsx +81 -0
- package/Common/CodeTabs/index.module.css +56 -0
- package/Common/CodeTabs/index.stories.tsx +74 -0
- package/Common/CodeTabs/index.tsx +16 -0
- package/Common/GlowingBackdrop/index.module.css +32 -0
- package/Common/GlowingBackdrop/index.stories.tsx +10 -0
- package/Common/GlowingBackdrop/index.tsx +13 -0
- package/Common/LanguageDropDown/index.module.css +53 -0
- package/Common/LanguageDropDown/index.stories.tsx +19 -0
- package/Common/LanguageDropDown/index.tsx +56 -0
- package/Common/Modal/index.module.css +79 -0
- package/Common/Modal/index.stories.tsx +32 -0
- package/Common/Modal/index.tsx +48 -0
- package/Common/NodejsLogo/index.module.css +6 -0
- package/Common/NodejsLogo/index.stories.tsx +14 -0
- package/Common/NodejsLogo/index.tsx +26 -0
- package/Common/Notification/index.module.css +20 -0
- package/Common/Notification/index.stories.tsx +36 -0
- package/Common/Notification/index.tsx +34 -0
- package/Common/Preview/index.module.css +79 -0
- package/Common/Preview/index.stories.tsx +44 -0
- package/Common/Preview/index.tsx +25 -0
- package/Common/ProgressionSidebar/ProgressionSidebarGroup/index.module.css +47 -0
- package/Common/ProgressionSidebar/ProgressionSidebarGroup/index.tsx +35 -0
- package/Common/ProgressionSidebar/ProgressionSidebarIcon/index.tsx +16 -0
- package/Common/ProgressionSidebar/ProgressionSidebarItem/index.module.css +39 -0
- package/Common/ProgressionSidebar/ProgressionSidebarItem/index.tsx +32 -0
- package/Common/ProgressionSidebar/index.module.css +30 -0
- package/Common/ProgressionSidebar/index.stories.tsx +79 -0
- package/Common/ProgressionSidebar/index.tsx +59 -0
- package/Common/Select/__tests__/index.test.jsx +67 -0
- package/Common/Select/index.module.css +161 -0
- package/Common/Select/index.stories.tsx +111 -0
- package/Common/Select/index.tsx +187 -0
- package/Common/Separator/index.module.css +16 -0
- package/Common/Separator/index.stories.tsx +32 -0
- package/Common/Separator/index.tsx +27 -0
- package/Common/Skeleton/index.module.css +29 -0
- package/Common/Skeleton/index.tsx +39 -0
- package/Common/Tabs/__tests__/index.test.jsx +52 -0
- package/Common/Tabs/index.module.css +53 -0
- package/Common/Tabs/index.stories.tsx +50 -0
- package/Common/Tabs/index.tsx +54 -0
- package/Common/ThemeToggle/__tests__/index.test.jsx +35 -0
- package/Common/ThemeToggle/index.module.css +15 -0
- package/Common/ThemeToggle/index.stories.tsx +10 -0
- package/Common/ThemeToggle/index.tsx +15 -0
- package/Common/Tooltip/index.module.css +43 -0
- package/Common/Tooltip/index.stories.tsx +73 -0
- package/Common/Tooltip/index.tsx +48 -0
- package/Containers/Article/index.module.css +70 -0
- package/Containers/Article/index.stories.tsx +39 -0
- package/Containers/Article/index.tsx +9 -0
- package/Containers/Footer/index.module.css +46 -0
- package/Containers/Footer/index.stories.tsx +27 -0
- package/Containers/Footer/index.tsx +95 -0
- package/Containers/MetaBar/__tests__/index.test.jsx +63 -0
- package/Containers/MetaBar/index.module.css +84 -0
- package/Containers/MetaBar/index.stories.tsx +80 -0
- package/Containers/MetaBar/index.tsx +72 -0
- package/Containers/NavBar/NavItem/index.module.css +60 -0
- package/Containers/NavBar/NavItem/index.stories.tsx +38 -0
- package/Containers/NavBar/NavItem/index.tsx +44 -0
- package/Containers/NavBar/index.module.css +125 -0
- package/Containers/NavBar/index.stories.tsx +45 -0
- package/Containers/NavBar/index.tsx +94 -0
- package/Containers/Sidebar/SidebarGroup/index.module.css +26 -0
- package/Containers/Sidebar/SidebarGroup/index.stories.tsx +36 -0
- package/Containers/Sidebar/SidebarGroup/index.tsx +30 -0
- package/Containers/Sidebar/SidebarItem/index.module.css +35 -0
- package/Containers/Sidebar/SidebarItem/index.stories.tsx +15 -0
- package/Containers/Sidebar/SidebarItem/index.tsx +26 -0
- package/Containers/Sidebar/index.module.css +31 -0
- package/Containers/Sidebar/index.stories.tsx +84 -0
- package/Containers/Sidebar/index.tsx +58 -0
- package/Icons/HexagonGrid.stories.tsx +10 -0
- package/Icons/HexagonGrid.tsx +1434 -0
- package/Icons/InstallationMethod/Choco.tsx +78 -0
- package/Icons/InstallationMethod/Devbox.tsx +21 -0
- package/Icons/InstallationMethod/Docker.tsx +20 -0
- package/Icons/InstallationMethod/FNM.tsx +132 -0
- package/Icons/InstallationMethod/Homebrew.tsx +69 -0
- package/Icons/InstallationMethod/N.tsx +32 -0
- package/Icons/InstallationMethod/NVM.tsx +63 -0
- package/Icons/InstallationMethod/Volta.tsx +34 -0
- package/Icons/InstallationMethod/index.ts +10 -0
- package/Icons/Logos/JsGreen.tsx +24 -0
- package/Icons/Logos/JsWhite.tsx +37 -0
- package/Icons/Logos/Nodejs.tsx +188 -0
- package/Icons/Logos/NodejsStackedBlack.tsx +98 -0
- package/Icons/Logos/NodejsStackedDark.tsx +124 -0
- package/Icons/Logos/NodejsStackedLight.tsx +123 -0
- package/Icons/Logos/NodejsStackedWhite.tsx +98 -0
- package/Icons/Logos/index.ts +17 -0
- package/Icons/OperatingSystem/AIX.tsx +46 -0
- package/Icons/OperatingSystem/Apple.tsx +23 -0
- package/Icons/OperatingSystem/Linux.tsx +969 -0
- package/Icons/OperatingSystem/Microsoft.tsx +19 -0
- package/Icons/OperatingSystem/index.ts +6 -0
- package/Icons/PackageManager/Npm.tsx +21 -0
- package/Icons/PackageManager/Pnpm.tsx +22 -0
- package/Icons/PackageManager/Yarn.tsx +22 -0
- package/Icons/PackageManager/index.ts +5 -0
- package/Icons/Social/Bluesky.tsx +19 -0
- package/Icons/Social/Discord.tsx +20 -0
- package/Icons/Social/GitHub.tsx +16 -0
- package/Icons/Social/LinkedIn.tsx +16 -0
- package/Icons/Social/Mastodon.tsx +36 -0
- package/Icons/Social/Slack.tsx +31 -0
- package/Icons/Social/X.tsx +16 -0
- package/Icons/Social/index.ts +9 -0
- package/LICENSE +21 -0
- package/package.json +89 -5
- package/stylelint/__tests__/index.test.mjs +80 -0
- package/stylelint/one-utility-class-per-line.mjs +64 -0
- package/stylelint/utils.mjs +53 -0
- package/styles/animations.css +47 -0
- package/styles/base.css +17 -0
- package/styles/effects.css +12 -0
- package/styles/index.css +34 -0
- package/styles/markdown.css +173 -0
- package/styles/theme.css +175 -0
- package/types.ts +25 -0
- package/README.md +0 -1
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { Meta as MetaObj, StoryObj } from '@storybook/react';
|
|
2
|
+
|
|
3
|
+
import Badge from '#ui/Common/Badge';
|
|
4
|
+
|
|
5
|
+
type Story = StoryObj<typeof Badge>;
|
|
6
|
+
type Meta = MetaObj<typeof Badge>;
|
|
7
|
+
|
|
8
|
+
export const Default: Story = {
|
|
9
|
+
args: {
|
|
10
|
+
kind: 'default',
|
|
11
|
+
},
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export const Error: Story = {
|
|
15
|
+
args: {
|
|
16
|
+
kind: 'error',
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export const Warning: Story = {
|
|
21
|
+
args: {
|
|
22
|
+
kind: 'warning',
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export const Small: Story = {
|
|
27
|
+
args: {
|
|
28
|
+
size: 'small',
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export const Medium: Story = {
|
|
33
|
+
args: {
|
|
34
|
+
size: 'medium',
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export default { component: Badge, args: { children: 'Badge' } } as Meta;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import classNames from 'classnames';
|
|
2
|
+
import type { FC, HTMLAttributes, PropsWithChildren } from 'react';
|
|
3
|
+
|
|
4
|
+
import styles from './index.module.css';
|
|
5
|
+
|
|
6
|
+
type BadgeKind = 'default' | 'warning' | 'error';
|
|
7
|
+
|
|
8
|
+
type BadgeProps = HTMLAttributes<HTMLSpanElement> & {
|
|
9
|
+
size?: 'small' | 'medium';
|
|
10
|
+
kind?: BadgeKind;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const Badge: FC<PropsWithChildren<BadgeProps>> = ({
|
|
14
|
+
kind = 'default',
|
|
15
|
+
size = 'medium',
|
|
16
|
+
className,
|
|
17
|
+
children,
|
|
18
|
+
...props
|
|
19
|
+
}) => {
|
|
20
|
+
return (
|
|
21
|
+
<span
|
|
22
|
+
className={classNames(
|
|
23
|
+
styles.badge,
|
|
24
|
+
styles[kind],
|
|
25
|
+
styles[size],
|
|
26
|
+
className
|
|
27
|
+
)}
|
|
28
|
+
{...props}
|
|
29
|
+
>
|
|
30
|
+
{children}
|
|
31
|
+
</span>
|
|
32
|
+
);
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export default Badge;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
@reference "../../styles/index.css";
|
|
2
|
+
|
|
3
|
+
.wrapper {
|
|
4
|
+
@apply flex
|
|
5
|
+
w-fit
|
|
6
|
+
items-center
|
|
7
|
+
rounded-full
|
|
8
|
+
border
|
|
9
|
+
py-1
|
|
10
|
+
pl-1
|
|
11
|
+
pr-2.5
|
|
12
|
+
text-sm
|
|
13
|
+
font-medium;
|
|
14
|
+
|
|
15
|
+
.icon {
|
|
16
|
+
@apply size-4;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.badge {
|
|
20
|
+
@apply mr-2;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.message {
|
|
24
|
+
@apply mr-1;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
&.default {
|
|
28
|
+
@apply border-green-200
|
|
29
|
+
bg-green-100
|
|
30
|
+
dark:border-green-700
|
|
31
|
+
dark:bg-neutral-900;
|
|
32
|
+
|
|
33
|
+
.icon {
|
|
34
|
+
@apply text-green-500
|
|
35
|
+
dark:text-green-300;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.message {
|
|
39
|
+
@apply text-green-700
|
|
40
|
+
dark:text-green-300;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
&.error {
|
|
45
|
+
@apply border-danger-200
|
|
46
|
+
bg-danger-100
|
|
47
|
+
dark:border-danger-700
|
|
48
|
+
dark:bg-neutral-900;
|
|
49
|
+
|
|
50
|
+
.icon {
|
|
51
|
+
@apply text-danger-500
|
|
52
|
+
dark:text-danger-300;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.message {
|
|
56
|
+
@apply text-danger-700
|
|
57
|
+
dark:text-danger-300;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
&.warning {
|
|
62
|
+
@apply border-warning-200
|
|
63
|
+
bg-warning-100
|
|
64
|
+
dark:border-warning-700
|
|
65
|
+
dark:bg-neutral-900;
|
|
66
|
+
|
|
67
|
+
.icon {
|
|
68
|
+
@apply text-warning-500
|
|
69
|
+
dark:text-warning-300;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.message {
|
|
73
|
+
@apply text-warning-700
|
|
74
|
+
dark:text-warning-300;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { Meta as MetaObj, StoryObj } from '@storybook/react';
|
|
2
|
+
|
|
3
|
+
import BadgeGroup from '#ui/Common/BadgeGroup';
|
|
4
|
+
|
|
5
|
+
type Story = StoryObj<typeof BadgeGroup>;
|
|
6
|
+
type Meta = MetaObj<typeof BadgeGroup>;
|
|
7
|
+
|
|
8
|
+
export const Default: Story = {
|
|
9
|
+
args: {
|
|
10
|
+
href: '/',
|
|
11
|
+
children: 'OpenJS Foundation Certification 2023',
|
|
12
|
+
kind: 'default',
|
|
13
|
+
badgeText: 'New',
|
|
14
|
+
},
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export const Error: Story = {
|
|
18
|
+
args: {
|
|
19
|
+
href: '/',
|
|
20
|
+
children: 'OpenJS Foundation Certification 2023',
|
|
21
|
+
kind: 'error',
|
|
22
|
+
badgeText: 'New',
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export const Warning: Story = {
|
|
27
|
+
args: {
|
|
28
|
+
href: '/',
|
|
29
|
+
children: 'OpenJS Foundation Certification 2023',
|
|
30
|
+
kind: 'warning',
|
|
31
|
+
badgeText: 'New',
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export default { component: BadgeGroup } as Meta;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import ArrowRightIcon from '@heroicons/react/24/solid/ArrowRightIcon';
|
|
2
|
+
import type { ComponentProps, FC, PropsWithChildren } from 'react';
|
|
3
|
+
|
|
4
|
+
import Badge from '#ui/Common/Badge';
|
|
5
|
+
import type { LinkLike } from '#ui/types';
|
|
6
|
+
|
|
7
|
+
import styles from './index.module.css';
|
|
8
|
+
|
|
9
|
+
type BadgeGroupKind = 'default' | 'warning' | 'error';
|
|
10
|
+
|
|
11
|
+
type BadgeGroupProps = {
|
|
12
|
+
kind?: BadgeGroupKind;
|
|
13
|
+
badgeText?: string;
|
|
14
|
+
as: LinkLike;
|
|
15
|
+
} & ComponentProps<LinkLike>;
|
|
16
|
+
|
|
17
|
+
const BadgeGroup: FC<PropsWithChildren<BadgeGroupProps>> = ({
|
|
18
|
+
kind = 'default',
|
|
19
|
+
badgeText,
|
|
20
|
+
children,
|
|
21
|
+
as: Component = 'a',
|
|
22
|
+
...args
|
|
23
|
+
}) => (
|
|
24
|
+
<Component className={`${styles.wrapper} ${styles[kind]}`} {...args}>
|
|
25
|
+
{badgeText && (
|
|
26
|
+
<Badge kind={kind} className={styles.badge}>
|
|
27
|
+
{badgeText}
|
|
28
|
+
</Badge>
|
|
29
|
+
)}
|
|
30
|
+
<span className={styles.message}>{children}</span>
|
|
31
|
+
{args.href && <ArrowRightIcon className={styles.icon} />}
|
|
32
|
+
</Component>
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
export default BadgeGroup;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
@reference "../../styles/index.css";
|
|
2
|
+
|
|
3
|
+
.banner {
|
|
4
|
+
@apply flex
|
|
5
|
+
w-full
|
|
6
|
+
flex-row
|
|
7
|
+
items-center
|
|
8
|
+
justify-center
|
|
9
|
+
gap-2
|
|
10
|
+
px-8
|
|
11
|
+
py-3
|
|
12
|
+
text-sm;
|
|
13
|
+
|
|
14
|
+
&,
|
|
15
|
+
a {
|
|
16
|
+
@apply text-white
|
|
17
|
+
dark:text-white;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
a {
|
|
21
|
+
@apply w-fit
|
|
22
|
+
underline
|
|
23
|
+
decoration-white/50;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
svg {
|
|
27
|
+
@apply size-4
|
|
28
|
+
text-white/50;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.default {
|
|
33
|
+
@apply bg-green-600;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.error {
|
|
37
|
+
@apply bg-danger-600;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.warning {
|
|
41
|
+
@apply bg-warning-600;
|
|
42
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { Meta as MetaObj, StoryObj } from '@storybook/react';
|
|
2
|
+
|
|
3
|
+
import Banner from '#ui/Common/Banner';
|
|
4
|
+
|
|
5
|
+
type Story = StoryObj<typeof Banner>;
|
|
6
|
+
type Meta = MetaObj<typeof Banner>;
|
|
7
|
+
|
|
8
|
+
export const Default: Story = {
|
|
9
|
+
args: {
|
|
10
|
+
children: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
|
|
11
|
+
type: 'default',
|
|
12
|
+
},
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export const Error: Story = {
|
|
16
|
+
args: {
|
|
17
|
+
children: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
|
|
18
|
+
type: 'error',
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export const Warning: Story = {
|
|
23
|
+
args: {
|
|
24
|
+
children: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
|
|
25
|
+
type: 'warning',
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export default { component: Banner } as Meta;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { FC, PropsWithChildren } from 'react';
|
|
2
|
+
|
|
3
|
+
import styles from './index.module.css';
|
|
4
|
+
|
|
5
|
+
export type BannerProps = {
|
|
6
|
+
type?: 'default' | 'warning' | 'error';
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
const Banner: FC<PropsWithChildren<BannerProps>> = ({
|
|
10
|
+
type = 'default',
|
|
11
|
+
children,
|
|
12
|
+
}) => (
|
|
13
|
+
<div className={`${styles.banner} ${styles[type] || styles.default}`}>
|
|
14
|
+
{children}
|
|
15
|
+
</div>
|
|
16
|
+
);
|
|
17
|
+
|
|
18
|
+
export default Banner;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { describe, it } from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
|
|
4
|
+
import { render, screen } from '@testing-library/react';
|
|
5
|
+
|
|
6
|
+
import ActiveLink from '..';
|
|
7
|
+
|
|
8
|
+
describe('ActiveLink', () => {
|
|
9
|
+
it('renders as localized link', async () => {
|
|
10
|
+
render(
|
|
11
|
+
<ActiveLink className="link" activeClassName="active" href="/link">
|
|
12
|
+
Link
|
|
13
|
+
</ActiveLink>
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
assert.equal(
|
|
17
|
+
(await screen.findByText('Link')).getAttribute('href'),
|
|
18
|
+
'/link'
|
|
19
|
+
);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('ignores active class when href not matches location.href', async () => {
|
|
23
|
+
render(
|
|
24
|
+
<ActiveLink className="link" activeClassName="active" href="/not-link">
|
|
25
|
+
Link
|
|
26
|
+
</ActiveLink>
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
assert.equal(
|
|
30
|
+
(await screen.findByText('Link')).getAttribute('class'),
|
|
31
|
+
'link'
|
|
32
|
+
);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('sets active class when href matches location.href', async () => {
|
|
36
|
+
render(
|
|
37
|
+
<ActiveLink
|
|
38
|
+
className="link"
|
|
39
|
+
activeClassName="active"
|
|
40
|
+
href="/link"
|
|
41
|
+
pathname="/link"
|
|
42
|
+
>
|
|
43
|
+
Link
|
|
44
|
+
</ActiveLink>
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
assert.equal(
|
|
48
|
+
(await screen.findByText('Link')).getAttribute('class'),
|
|
49
|
+
'link active'
|
|
50
|
+
);
|
|
51
|
+
});
|
|
52
|
+
});
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import classNames from 'classnames';
|
|
2
|
+
import type { ComponentProps, FC } from 'react';
|
|
3
|
+
|
|
4
|
+
import type { LinkLike } from '#ui/types';
|
|
5
|
+
|
|
6
|
+
export type ActiveLocalizedLinkProps = ComponentProps<LinkLike> & {
|
|
7
|
+
activeClassName?: string;
|
|
8
|
+
allowSubPath?: boolean;
|
|
9
|
+
pathname?: string;
|
|
10
|
+
as?: LinkLike;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const BaseActiveLink: FC<ActiveLocalizedLinkProps> = ({
|
|
14
|
+
activeClassName = 'active',
|
|
15
|
+
allowSubPath = false,
|
|
16
|
+
className,
|
|
17
|
+
href = '',
|
|
18
|
+
pathname = '/',
|
|
19
|
+
as: Component = 'a',
|
|
20
|
+
...props
|
|
21
|
+
}) => {
|
|
22
|
+
const finalClassName = classNames(className, {
|
|
23
|
+
[activeClassName]: allowSubPath
|
|
24
|
+
? // When using allowSubPath we want only to check if
|
|
25
|
+
// the current pathname starts with the utmost upper level
|
|
26
|
+
// of an href (e.g. /docs/...)
|
|
27
|
+
pathname.startsWith(`/${href.toString().split('/')[1]}`)
|
|
28
|
+
: href.toString() === pathname,
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
return <Component className={finalClassName} href={href} {...props} />;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export default BaseActiveLink;
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
@reference "../../styles/index.css";
|
|
2
|
+
|
|
3
|
+
.button {
|
|
4
|
+
@apply px-4.5
|
|
5
|
+
relative
|
|
6
|
+
inline-flex
|
|
7
|
+
items-center
|
|
8
|
+
justify-center
|
|
9
|
+
gap-2
|
|
10
|
+
py-2.5
|
|
11
|
+
text-center
|
|
12
|
+
font-semibold
|
|
13
|
+
motion-safe:transition-colors;
|
|
14
|
+
|
|
15
|
+
svg {
|
|
16
|
+
@apply size-5;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
&[aria-disabled='true'] {
|
|
20
|
+
@apply cursor-not-allowed;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
&.small {
|
|
24
|
+
@apply px-3
|
|
25
|
+
py-2
|
|
26
|
+
text-sm;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
&.neutral {
|
|
30
|
+
@apply rounded-sm
|
|
31
|
+
bg-neutral-900
|
|
32
|
+
text-white
|
|
33
|
+
dark:text-neutral-200;
|
|
34
|
+
|
|
35
|
+
&:hover:not([aria-disabled='true']) {
|
|
36
|
+
@apply bg-neutral-800;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
&[aria-disabled='true'] {
|
|
40
|
+
@apply bg-neutral-900
|
|
41
|
+
opacity-50;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
&:focus {
|
|
45
|
+
@apply bg-neutral-800;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
&.primary {
|
|
50
|
+
@apply shadow-xs
|
|
51
|
+
rounded-sm
|
|
52
|
+
border
|
|
53
|
+
border-green-600
|
|
54
|
+
bg-green-600
|
|
55
|
+
text-white;
|
|
56
|
+
|
|
57
|
+
&:hover:not([aria-disabled='true']) {
|
|
58
|
+
@apply border-green-700
|
|
59
|
+
bg-green-700
|
|
60
|
+
text-white;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
&:focus {
|
|
64
|
+
@apply border-green-700
|
|
65
|
+
bg-green-700;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
&[aria-disabled='true'] {
|
|
69
|
+
@apply bg-green-600
|
|
70
|
+
opacity-50;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
&.secondary {
|
|
75
|
+
@apply rounded-lg
|
|
76
|
+
text-neutral-800
|
|
77
|
+
dark:text-neutral-200;
|
|
78
|
+
|
|
79
|
+
&:hover:not([aria-disabled='true']) {
|
|
80
|
+
@apply bg-neutral-100
|
|
81
|
+
text-neutral-800
|
|
82
|
+
dark:bg-neutral-900
|
|
83
|
+
dark:text-neutral-200;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
&[aria-disabled='true'] {
|
|
87
|
+
@apply bg-transparent
|
|
88
|
+
opacity-50;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
&:focus {
|
|
92
|
+
@apply bg-neutral-100
|
|
93
|
+
text-neutral-800
|
|
94
|
+
dark:bg-neutral-900
|
|
95
|
+
dark:text-neutral-200;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
&.special {
|
|
100
|
+
@apply before:bg-gradient-glow-backdrop
|
|
101
|
+
shadow-xs
|
|
102
|
+
rounded-lg
|
|
103
|
+
border
|
|
104
|
+
border-green-600/30
|
|
105
|
+
bg-green-600/10
|
|
106
|
+
text-white
|
|
107
|
+
before:absolute
|
|
108
|
+
before:left-0
|
|
109
|
+
before:right-0
|
|
110
|
+
before:top-0
|
|
111
|
+
before:-z-10
|
|
112
|
+
before:mx-auto
|
|
113
|
+
before:h-full
|
|
114
|
+
before:w-full
|
|
115
|
+
before:opacity-30
|
|
116
|
+
before:content-['']
|
|
117
|
+
after:absolute
|
|
118
|
+
after:-top-px
|
|
119
|
+
after:left-0
|
|
120
|
+
after:right-0
|
|
121
|
+
after:mx-auto
|
|
122
|
+
after:h-px
|
|
123
|
+
after:w-2/5
|
|
124
|
+
after:bg-gradient-to-r
|
|
125
|
+
after:from-green-600/0
|
|
126
|
+
after:via-green-600
|
|
127
|
+
after:to-green-600/0
|
|
128
|
+
after:content-[''];
|
|
129
|
+
|
|
130
|
+
&[aria-disabled='true'] {
|
|
131
|
+
@apply opacity-50;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
&:hover:not([aria-disabled='true']) {
|
|
135
|
+
@apply bg-green-600/20;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
&:focus {
|
|
139
|
+
@apply bg-green-600/20;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { ArrowRightIcon } from '@heroicons/react/24/solid';
|
|
2
|
+
import type { Meta as MetaObj, StoryObj } from '@storybook/react';
|
|
3
|
+
|
|
4
|
+
import BaseButton from '#ui/Common/BaseButton';
|
|
5
|
+
|
|
6
|
+
type Story = StoryObj<typeof BaseButton>;
|
|
7
|
+
type Meta = MetaObj<typeof BaseButton>;
|
|
8
|
+
|
|
9
|
+
export const Neutral: Story = {
|
|
10
|
+
args: {
|
|
11
|
+
kind: 'neutral',
|
|
12
|
+
children: 'Download Node (LTS)',
|
|
13
|
+
disabled: false,
|
|
14
|
+
size: 'default',
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export const Primary: Story = {
|
|
19
|
+
args: {
|
|
20
|
+
kind: 'primary',
|
|
21
|
+
children: 'Download Node (LTS)',
|
|
22
|
+
disabled: false,
|
|
23
|
+
size: 'default',
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export const Secondary: Story = {
|
|
28
|
+
args: {
|
|
29
|
+
kind: 'secondary',
|
|
30
|
+
children: 'Download Node (LTS)',
|
|
31
|
+
disabled: false,
|
|
32
|
+
size: 'default',
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export const Special: Story = {
|
|
37
|
+
args: {
|
|
38
|
+
kind: 'special',
|
|
39
|
+
children: 'Download Node (LTS)',
|
|
40
|
+
disabled: false,
|
|
41
|
+
size: 'default',
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export const WithIcon: Story = {
|
|
46
|
+
args: {
|
|
47
|
+
kind: 'primary',
|
|
48
|
+
children: (
|
|
49
|
+
<>
|
|
50
|
+
Back to Home
|
|
51
|
+
<ArrowRightIcon />
|
|
52
|
+
</>
|
|
53
|
+
),
|
|
54
|
+
disabled: false,
|
|
55
|
+
size: 'default',
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
export default {
|
|
60
|
+
component: BaseButton,
|
|
61
|
+
argTypes: {
|
|
62
|
+
size: {
|
|
63
|
+
options: ['default', 'small'],
|
|
64
|
+
control: { type: 'radio' },
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
} as Meta;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import classNames from 'classnames';
|
|
2
|
+
import type { FC, AnchorHTMLAttributes, ButtonHTMLAttributes } from 'react';
|
|
3
|
+
|
|
4
|
+
import type { LinkLike } from '#ui/types';
|
|
5
|
+
|
|
6
|
+
import styles from './index.module.css';
|
|
7
|
+
|
|
8
|
+
export type ButtonProps = (
|
|
9
|
+
| AnchorHTMLAttributes<HTMLAnchorElement>
|
|
10
|
+
| ButtonHTMLAttributes<HTMLButtonElement>
|
|
11
|
+
) & {
|
|
12
|
+
kind?: 'neutral' | 'primary' | 'secondary' | 'special';
|
|
13
|
+
size?: 'default' | 'small';
|
|
14
|
+
disabled?: boolean;
|
|
15
|
+
as?: LinkLike;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const BaseButton: FC<ButtonProps> = ({
|
|
19
|
+
kind = 'primary',
|
|
20
|
+
size = 'default',
|
|
21
|
+
disabled = false,
|
|
22
|
+
className,
|
|
23
|
+
as: Component = 'a',
|
|
24
|
+
...props
|
|
25
|
+
}) => {
|
|
26
|
+
if ('href' in props && Component) {
|
|
27
|
+
return (
|
|
28
|
+
<Component
|
|
29
|
+
role="button"
|
|
30
|
+
href={disabled ? undefined : props.href}
|
|
31
|
+
aria-disabled={disabled}
|
|
32
|
+
className={classNames(
|
|
33
|
+
styles.button,
|
|
34
|
+
styles[kind],
|
|
35
|
+
styles[size],
|
|
36
|
+
className
|
|
37
|
+
)}
|
|
38
|
+
tabIndex={disabled ? -1 : 0}
|
|
39
|
+
{...props}
|
|
40
|
+
/>
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return (
|
|
45
|
+
<button
|
|
46
|
+
disabled={disabled}
|
|
47
|
+
className={classNames(
|
|
48
|
+
styles.button,
|
|
49
|
+
styles[kind],
|
|
50
|
+
styles[size],
|
|
51
|
+
className
|
|
52
|
+
)}
|
|
53
|
+
type="button"
|
|
54
|
+
{...(props as ButtonHTMLAttributes<HTMLButtonElement>)}
|
|
55
|
+
/>
|
|
56
|
+
);
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
export default BaseButton;
|