ab-nextjs-components 0.1.1 → 0.1.3
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/CHANGELOG.md +40 -0
- package/LICENSE +1 -1
- package/README.md +91 -15
- package/ab-avatar/index.tsx +90 -0
- package/ab-avatar/styles.module.css +62 -0
- package/ab-balloon/index.tsx +55 -0
- package/ab-balloon/styles.module.css +12 -0
- package/ab-brand/index.tsx +88 -0
- package/ab-brand/styles.module.css +54 -0
- package/ab-button/index.tsx +164 -0
- package/ab-button/styles.module.css +63 -0
- package/ab-collapsible/index.tsx +188 -0
- package/ab-collapsible/styles.module.css +98 -0
- package/ab-color/index.tsx +84 -0
- package/ab-color/styles.module.css +51 -0
- package/ab-demo-box/index.tsx +38 -0
- package/ab-demo-box/styles.module.css +13 -0
- package/ab-demo-code/index.tsx +62 -0
- package/ab-demo-code/styles.module.css +41 -0
- package/ab-icon/index.tsx +63 -0
- package/ab-icon/styles.module.css +27 -0
- package/ab-icon-button/index.tsx +107 -0
- package/ab-icon-button/styles.module.css +64 -0
- package/ab-image/index.tsx +83 -0
- package/ab-image/styles.module.css +27 -0
- package/ab-info/index.tsx +89 -0
- package/ab-info/styles.module.css +87 -0
- package/ab-input/index.tsx +277 -0
- package/ab-input/styles.module.css +101 -0
- package/ab-key-feature/index.tsx +60 -0
- package/ab-key-feature/styles.module.css +47 -0
- package/ab-like-button/index.tsx +116 -0
- package/ab-like-button/styles.module.css +60 -0
- package/ab-logo/index.tsx +94 -0
- package/ab-logo/styles.module.css +30 -0
- package/ab-main-headline/index.tsx +57 -0
- package/ab-main-headline/styles.module.css +24 -0
- package/ab-menu/index.tsx +119 -0
- package/ab-menu/styles.module.css +99 -0
- package/ab-name/index.tsx +49 -0
- package/ab-name/styles.module.css +14 -0
- package/ab-navbar/index.tsx +68 -0
- package/ab-navbar/styles.module.css +35 -0
- package/ab-page-paginator/index.tsx +130 -0
- package/ab-page-paginator/styles.module.css +47 -0
- package/ab-page-switcher/index.tsx +121 -0
- package/ab-page-switcher/styles.module.css +37 -0
- package/ab-preview/index.tsx +78 -0
- package/ab-preview/styles.module.css +26 -0
- package/ab-price/index.tsx +109 -0
- package/ab-price/styles.module.css +36 -0
- package/ab-price-tag/index.tsx +70 -0
- package/ab-price-tag/styles.module.css +81 -0
- package/ab-product/index.tsx +128 -0
- package/ab-product/styles.module.css +44 -0
- package/ab-product-item/index.tsx +78 -0
- package/ab-product-item/styles.module.css +21 -0
- package/ab-progress-chips/index.tsx +105 -0
- package/ab-progress-chips/styles.module.css +43 -0
- package/ab-search-result/index.tsx +79 -0
- package/ab-search-result/styles.module.css +48 -0
- package/ab-searchbar/index.tsx +150 -0
- package/ab-searchbar/styles.module.css +77 -0
- package/ab-sidebar/index.tsx +72 -0
- package/ab-sidebar/styles.module.css +41 -0
- package/ab-switch-back/index.tsx +72 -0
- package/ab-switch-back/styles.module.css +45 -0
- package/ab-tab/index.tsx +101 -0
- package/ab-tab/styles.module.css +65 -0
- package/ab-tabs/index.tsx +45 -0
- package/ab-tabs/styles.module.css +17 -0
- package/ab-test-hello/index.tsx +37 -0
- package/ab-test-hello/styles.module.css +25 -0
- package/ab-text/index.tsx +36 -0
- package/ab-text/styles.module.css +3 -0
- package/index.ts +117 -0
- package/package.json +152 -7
- package/server/ab-avatar/index.tsx +85 -0
- package/server/ab-avatar/styles.module.css +62 -0
- package/server/ab-badge/index.tsx +66 -0
- package/server/ab-badge/styles.module.css +39 -0
- package/server/ab-brand/index.tsx +87 -0
- package/server/ab-brand/styles.module.css +54 -0
- package/server/ab-button/index.tsx +144 -0
- package/server/ab-button/styles.module.css +63 -0
- package/server/ab-icon/index.tsx +61 -0
- package/server/ab-icon/styles.module.css +27 -0
- package/server/ab-key-feature/index.tsx +59 -0
- package/server/ab-key-feature/styles.module.css +47 -0
- package/server/ab-logo/index.tsx +93 -0
- package/server/ab-logo/styles.module.css +30 -0
- package/server/ab-name/index.tsx +48 -0
- package/server/ab-name/styles.module.css +14 -0
- package/server/ab-nav-link/index.tsx +60 -0
- package/server/ab-nav-link/styles.module.css +32 -0
- package/server/ab-navbar/index.tsx +64 -0
- package/server/ab-navbar/styles.module.css +35 -0
- package/server/ab-polygon/index.tsx +45 -0
- package/server/ab-polygon/styles.module.css +11 -0
- package/server/ab-sidebar/index.tsx +68 -0
- package/server/ab-sidebar/styles.module.css +41 -0
- package/server/ab-switch-back/index.tsx +71 -0
- package/server/ab-switch-back/styles.module.css +45 -0
- package/server/ab-test-hello/index.tsx +35 -0
- package/server/ab-test-hello/styles.module.css +22 -0
- package/server/ab-text/index.tsx +33 -0
- package/server/ab-text/styles.module.css +3 -0
- package/server/index.ts +27 -0
- package/types/index.d.ts +54 -0
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @license MIT
|
|
3
|
+
* ~~~~~~~~~~~~
|
|
4
|
+
* ab-nextjs-components
|
|
5
|
+
* ~~~~~~~~~~~~
|
|
6
|
+
* Copyright (c) 2026 Abraham Ukachi. The abElements Project.
|
|
7
|
+
*
|
|
8
|
+
* @project: ab-nextjs-components
|
|
9
|
+
* @name: AbName - Server (port of lyd-name)
|
|
10
|
+
* @file: server/ab-name/index.tsx
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
import type { ReactElement } from 'react';
|
|
15
|
+
import clsx from 'clsx';
|
|
16
|
+
import styles from './styles.module.css';
|
|
17
|
+
|
|
18
|
+
export interface AbNameProps {
|
|
19
|
+
type?: 'light' | 'regular' | 'bold' | 'black';
|
|
20
|
+
className?: string;
|
|
21
|
+
label?: string;
|
|
22
|
+
onClick?: () => void;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const AbName = ({
|
|
26
|
+
type = 'regular',
|
|
27
|
+
className,
|
|
28
|
+
label = 'abElements',
|
|
29
|
+
onClick,
|
|
30
|
+
}: AbNameProps): ReactElement => {
|
|
31
|
+
const first = label.slice(0, 2);
|
|
32
|
+
const rest = label.slice(2);
|
|
33
|
+
return (
|
|
34
|
+
<span
|
|
35
|
+
data-type={type}
|
|
36
|
+
className={clsx('AbName', styles.abName, className)}
|
|
37
|
+
onClick={onClick}
|
|
38
|
+
role={onClick ? 'button' : undefined}
|
|
39
|
+
tabIndex={onClick ? 0 : undefined}
|
|
40
|
+
>
|
|
41
|
+
<span className={styles.abNameAb}>{first}</span>
|
|
42
|
+
<span className={styles.abNameRest}>{rest}</span>
|
|
43
|
+
</span>
|
|
44
|
+
);
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export default AbName;
|
|
48
|
+
export { AbName };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
.abName {
|
|
2
|
+
display: inline-flex;
|
|
3
|
+
align-items: baseline;
|
|
4
|
+
font-family: ui-serif, Georgia, serif;
|
|
5
|
+
letter-spacing: -0.02em;
|
|
6
|
+
cursor: default;
|
|
7
|
+
user-select: none;
|
|
8
|
+
}
|
|
9
|
+
.abName[data-type='light'] { font-weight: 300; }
|
|
10
|
+
.abName[data-type='regular'] { font-weight: 400; }
|
|
11
|
+
.abName[data-type='bold'] { font-weight: 700; }
|
|
12
|
+
.abName[data-type='black'] { font-weight: 900; }
|
|
13
|
+
.abNameAb { color: var(--ab-primary, #6750a4); }
|
|
14
|
+
.abNameRest { opacity: 0.85; }
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @license MIT
|
|
3
|
+
* ~~~~~~~~~~~~
|
|
4
|
+
* ab-nextjs-components
|
|
5
|
+
* ~~~~~~~~~~~~
|
|
6
|
+
* Copyright (c) 2026 Abraham Ukachi. The abElements Project.
|
|
7
|
+
*
|
|
8
|
+
* @project: ab-nextjs-components
|
|
9
|
+
* @name: AbNavLink - Server (port of lyd-nav-link)
|
|
10
|
+
* @file: server/ab-nav-link/index.tsx
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import type { ReactElement } from 'react';
|
|
14
|
+
import Link from 'next/link';
|
|
15
|
+
import clsx from 'clsx';
|
|
16
|
+
import styles from './styles.module.css';
|
|
17
|
+
|
|
18
|
+
export interface AbNavLinkProps {
|
|
19
|
+
className?: string;
|
|
20
|
+
title?: string;
|
|
21
|
+
href: string;
|
|
22
|
+
icon: string;
|
|
23
|
+
label: string;
|
|
24
|
+
active?: boolean;
|
|
25
|
+
noBadge?: boolean;
|
|
26
|
+
badgeCount?: number;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const AbNavLink = ({
|
|
30
|
+
className,
|
|
31
|
+
title,
|
|
32
|
+
href,
|
|
33
|
+
icon,
|
|
34
|
+
label,
|
|
35
|
+
active = false,
|
|
36
|
+
noBadge = true,
|
|
37
|
+
badgeCount = 0,
|
|
38
|
+
}: AbNavLinkProps): ReactElement => {
|
|
39
|
+
return (
|
|
40
|
+
<Link
|
|
41
|
+
href={href}
|
|
42
|
+
title={title ?? label}
|
|
43
|
+
data-active={active ? 'true' : 'false'}
|
|
44
|
+
className={clsx('AbNavLink', styles.abNavLink, className)}
|
|
45
|
+
>
|
|
46
|
+
<span className={clsx('material-symbols-rounded', styles.abNavLinkIcon)} aria-hidden>
|
|
47
|
+
{icon}
|
|
48
|
+
</span>
|
|
49
|
+
<span className={styles.abNavLinkLabel}>{label}</span>
|
|
50
|
+
{!noBadge && badgeCount > 0 ? (
|
|
51
|
+
<span className={styles.abNavLinkBadge} aria-label={`${badgeCount} notifications`}>
|
|
52
|
+
{badgeCount}
|
|
53
|
+
</span>
|
|
54
|
+
) : null}
|
|
55
|
+
</Link>
|
|
56
|
+
);
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
export default AbNavLink;
|
|
60
|
+
export { AbNavLink };
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
.abNavLink {
|
|
2
|
+
display: inline-flex;
|
|
3
|
+
align-items: center;
|
|
4
|
+
gap: 0.5rem;
|
|
5
|
+
text-decoration: none;
|
|
6
|
+
color: inherit;
|
|
7
|
+
opacity: 0.7;
|
|
8
|
+
padding: 0.5rem 0.75rem;
|
|
9
|
+
border-radius: 9999px;
|
|
10
|
+
position: relative;
|
|
11
|
+
}
|
|
12
|
+
.abNavLink[data-active='true'] {
|
|
13
|
+
opacity: 1;
|
|
14
|
+
background: color-mix(in srgb, var(--ab-primary, #6750a4) 12%, transparent);
|
|
15
|
+
}
|
|
16
|
+
.abNavLinkIcon { font-size: 1.25rem; }
|
|
17
|
+
.abNavLinkLabel { font-size: 0.875rem; font-weight: 600; }
|
|
18
|
+
.abNavLinkBadge {
|
|
19
|
+
position: absolute;
|
|
20
|
+
top: 0.15rem;
|
|
21
|
+
right: 0.15rem;
|
|
22
|
+
min-width: 1.1rem;
|
|
23
|
+
height: 1.1rem;
|
|
24
|
+
padding: 0 0.25rem;
|
|
25
|
+
border-radius: 9999px;
|
|
26
|
+
background: var(--ab-error, #b3261e);
|
|
27
|
+
color: #fff;
|
|
28
|
+
font-size: 0.65rem;
|
|
29
|
+
display: inline-flex;
|
|
30
|
+
align-items: center;
|
|
31
|
+
justify-content: center;
|
|
32
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @license MIT
|
|
3
|
+
* ~~~~~~~~~~~~
|
|
4
|
+
* ab-nextjs-components
|
|
5
|
+
* ~~~~~~~~~~~~
|
|
6
|
+
* Copyright (c) 2026 Abraham Ukachi. The abElements Project.
|
|
7
|
+
*
|
|
8
|
+
* @project: ab-nextjs-components
|
|
9
|
+
* @name: AbNavbar - Server (port of lyd-navbar)
|
|
10
|
+
* @file: server/ab-navbar/index.tsx
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import type { ReactElement } from 'react';
|
|
14
|
+
import Link from 'next/link';
|
|
15
|
+
import clsx from 'clsx';
|
|
16
|
+
import styles from './styles.module.css';
|
|
17
|
+
|
|
18
|
+
export type AbNavbarLink = {
|
|
19
|
+
href: string;
|
|
20
|
+
icon: string;
|
|
21
|
+
value: string;
|
|
22
|
+
label: string;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export interface AbNavbarProps {
|
|
26
|
+
className?: string;
|
|
27
|
+
type?: 'customer' | 'admin';
|
|
28
|
+
page?: string;
|
|
29
|
+
links?: AbNavbarLink[];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const AbNavbar = ({
|
|
33
|
+
className,
|
|
34
|
+
type = 'customer',
|
|
35
|
+
page,
|
|
36
|
+
links = [],
|
|
37
|
+
}: AbNavbarProps): ReactElement => {
|
|
38
|
+
return (
|
|
39
|
+
<nav data-type={type} className={clsx('AbNavbar', styles.abNavbar, className)} aria-label="Primary">
|
|
40
|
+
<ul className={styles.abNavbarList}>
|
|
41
|
+
{links.map((link) => {
|
|
42
|
+
const active = page === link.value;
|
|
43
|
+
return (
|
|
44
|
+
<li key={link.value}>
|
|
45
|
+
<Link
|
|
46
|
+
href={link.href}
|
|
47
|
+
data-active={active ? 'true' : 'false'}
|
|
48
|
+
className={styles.abNavbarLink}
|
|
49
|
+
>
|
|
50
|
+
<span className={clsx('material-symbols-rounded', styles.abNavbarIcon)} aria-hidden>
|
|
51
|
+
{link.icon}
|
|
52
|
+
</span>
|
|
53
|
+
<span>{link.label}</span>
|
|
54
|
+
</Link>
|
|
55
|
+
</li>
|
|
56
|
+
);
|
|
57
|
+
})}
|
|
58
|
+
</ul>
|
|
59
|
+
</nav>
|
|
60
|
+
);
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
export default AbNavbar;
|
|
64
|
+
export { AbNavbar };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
.abNavbar {
|
|
2
|
+
display: flex;
|
|
3
|
+
align-items: center;
|
|
4
|
+
gap: 0.5rem;
|
|
5
|
+
width: 100%;
|
|
6
|
+
padding: 0.5rem 0.75rem;
|
|
7
|
+
box-sizing: border-box;
|
|
8
|
+
}
|
|
9
|
+
.abNavbarList {
|
|
10
|
+
display: flex;
|
|
11
|
+
align-items: center;
|
|
12
|
+
gap: 0.25rem;
|
|
13
|
+
list-style: none;
|
|
14
|
+
margin: 0;
|
|
15
|
+
padding: 0;
|
|
16
|
+
overflow-x: auto;
|
|
17
|
+
}
|
|
18
|
+
.abNavbarLink {
|
|
19
|
+
display: inline-flex;
|
|
20
|
+
align-items: center;
|
|
21
|
+
gap: 0.35rem;
|
|
22
|
+
padding: 0.45rem 0.75rem;
|
|
23
|
+
border-radius: 9999px;
|
|
24
|
+
text-decoration: none;
|
|
25
|
+
color: inherit;
|
|
26
|
+
opacity: 0.7;
|
|
27
|
+
white-space: nowrap;
|
|
28
|
+
font-size: 0.875rem;
|
|
29
|
+
font-weight: 600;
|
|
30
|
+
}
|
|
31
|
+
.abNavbarLink[data-active='true'] {
|
|
32
|
+
opacity: 1;
|
|
33
|
+
background: color-mix(in srgb, var(--ab-primary, #6750a4) 14%, transparent);
|
|
34
|
+
}
|
|
35
|
+
.abNavbarIcon { font-size: 1.15rem; }
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @license MIT
|
|
3
|
+
* ~~~~~~~~~~~~
|
|
4
|
+
* ab-nextjs-components
|
|
5
|
+
* ~~~~~~~~~~~~
|
|
6
|
+
* Copyright (c) 2026 Abraham Ukachi. The abElements Project.
|
|
7
|
+
*
|
|
8
|
+
* @project: ab-nextjs-components
|
|
9
|
+
* @name: AbPolygon - Server (port of lyd-polygon)
|
|
10
|
+
* @file: server/ab-polygon/index.tsx
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import type { ReactElement } from 'react';
|
|
14
|
+
import clsx from 'clsx';
|
|
15
|
+
import styles from './styles.module.css';
|
|
16
|
+
|
|
17
|
+
export interface AbPolygonProps {
|
|
18
|
+
className?: string;
|
|
19
|
+
hidden?: boolean;
|
|
20
|
+
fill?: string;
|
|
21
|
+
opacity?: number;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const AbPolygon = ({
|
|
25
|
+
className,
|
|
26
|
+
hidden = false,
|
|
27
|
+
fill = '#778D79',
|
|
28
|
+
opacity = 0.36,
|
|
29
|
+
}: AbPolygonProps): ReactElement => {
|
|
30
|
+
return (
|
|
31
|
+
<div hidden={hidden} className={clsx('AbPolygon', styles.abPolygon, className)} aria-hidden>
|
|
32
|
+
<svg width="761" height="603" viewBox="0 0 761 603" fill="none" role="presentation">
|
|
33
|
+
<path
|
|
34
|
+
opacity={opacity}
|
|
35
|
+
d="M647.5 -242.933C708.264 -265.049 770.182 -213.093 758.954 -149.412L638.552 533.421C627.323 597.102 551.369 624.747 501.834 583.183L-29.316 137.495C-78.8509 95.9301 -64.8151 16.3291 -4.05151 -5.78704L647.5 -242.933Z"
|
|
36
|
+
fill={fill}
|
|
37
|
+
/>
|
|
38
|
+
</svg>
|
|
39
|
+
</div>
|
|
40
|
+
);
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export default AbPolygon;
|
|
44
|
+
export { AbPolygon };
|
|
45
|
+
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @license MIT
|
|
3
|
+
* ~~~~~~~~~~~~
|
|
4
|
+
* ab-nextjs-components
|
|
5
|
+
* ~~~~~~~~~~~~
|
|
6
|
+
* Copyright (c) 2026 Abraham Ukachi. The abElements Project.
|
|
7
|
+
*
|
|
8
|
+
* @project: ab-nextjs-components
|
|
9
|
+
* @name: AbSidebar - Server (port of lyd-sidebar)
|
|
10
|
+
* @file: server/ab-sidebar/index.tsx
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import type { ReactElement } from 'react';
|
|
14
|
+
import Link from 'next/link';
|
|
15
|
+
import clsx from 'clsx';
|
|
16
|
+
import styles from './styles.module.css';
|
|
17
|
+
|
|
18
|
+
export type AbSidebarLink = {
|
|
19
|
+
href: string;
|
|
20
|
+
icon: string;
|
|
21
|
+
value: string;
|
|
22
|
+
label: string;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export interface AbSidebarProps {
|
|
26
|
+
className?: string;
|
|
27
|
+
type?: 'customer' | 'admin';
|
|
28
|
+
page?: string;
|
|
29
|
+
links?: AbSidebarLink[];
|
|
30
|
+
brandHref?: string;
|
|
31
|
+
brandLabel?: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const AbSidebar = ({
|
|
35
|
+
className,
|
|
36
|
+
type = 'customer',
|
|
37
|
+
page,
|
|
38
|
+
links = [],
|
|
39
|
+
brandHref = '/',
|
|
40
|
+
brandLabel = 'abElements',
|
|
41
|
+
}: AbSidebarProps): ReactElement => {
|
|
42
|
+
return (
|
|
43
|
+
<aside data-type={type} className={clsx('AbSidebar', styles.abSidebar, className)} aria-label="Sidebar">
|
|
44
|
+
<Link href={brandHref} className={styles.abSidebarBrand}>
|
|
45
|
+
<span className="material-symbols-rounded" aria-hidden>apps</span>
|
|
46
|
+
<span>{brandLabel}</span>
|
|
47
|
+
</Link>
|
|
48
|
+
<ul className={styles.abSidebarList}>
|
|
49
|
+
{links.map((link) => {
|
|
50
|
+
const active = page === link.value;
|
|
51
|
+
return (
|
|
52
|
+
<li key={link.value}>
|
|
53
|
+
<Link href={link.href} data-active={active ? 'true' : 'false'} className={styles.abSidebarLink}>
|
|
54
|
+
<span className={clsx('material-symbols-rounded', styles.abSidebarIcon)} aria-hidden>
|
|
55
|
+
{link.icon}
|
|
56
|
+
</span>
|
|
57
|
+
<span>{link.label}</span>
|
|
58
|
+
</Link>
|
|
59
|
+
</li>
|
|
60
|
+
);
|
|
61
|
+
})}
|
|
62
|
+
</ul>
|
|
63
|
+
</aside>
|
|
64
|
+
);
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
export default AbSidebar;
|
|
68
|
+
export { AbSidebar };
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
.abSidebar {
|
|
2
|
+
display: flex;
|
|
3
|
+
flex-direction: column;
|
|
4
|
+
gap: 1rem;
|
|
5
|
+
width: 100%;
|
|
6
|
+
max-width: 16rem;
|
|
7
|
+
padding: 1rem 0.75rem;
|
|
8
|
+
box-sizing: border-box;
|
|
9
|
+
}
|
|
10
|
+
.abSidebarBrand {
|
|
11
|
+
display: flex;
|
|
12
|
+
align-items: center;
|
|
13
|
+
gap: 0.5rem;
|
|
14
|
+
font-weight: 700;
|
|
15
|
+
text-decoration: none;
|
|
16
|
+
color: inherit;
|
|
17
|
+
}
|
|
18
|
+
.abSidebarList {
|
|
19
|
+
display: flex;
|
|
20
|
+
flex-direction: column;
|
|
21
|
+
gap: 0.25rem;
|
|
22
|
+
list-style: none;
|
|
23
|
+
margin: 0;
|
|
24
|
+
padding: 0;
|
|
25
|
+
}
|
|
26
|
+
.abSidebarLink {
|
|
27
|
+
display: flex;
|
|
28
|
+
align-items: center;
|
|
29
|
+
gap: 0.6rem;
|
|
30
|
+
padding: 0.55rem 0.75rem;
|
|
31
|
+
border-radius: 0.75rem;
|
|
32
|
+
text-decoration: none;
|
|
33
|
+
color: inherit;
|
|
34
|
+
opacity: 0.75;
|
|
35
|
+
font-weight: 600;
|
|
36
|
+
}
|
|
37
|
+
.abSidebarLink[data-active='true'] {
|
|
38
|
+
opacity: 1;
|
|
39
|
+
background: color-mix(in srgb, var(--ab-primary, #6750a4) 14%, transparent);
|
|
40
|
+
}
|
|
41
|
+
.abSidebarIcon { font-size: 1.25rem; }
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @license MIT
|
|
3
|
+
* ~~~~~~~~~~~~
|
|
4
|
+
* ab-nextjs-components
|
|
5
|
+
* ~~~~~~~~~~~~
|
|
6
|
+
* Copyright (c) 2026 Abraham Ukachi. The abElements Project.
|
|
7
|
+
*
|
|
8
|
+
* @project: ab-nextjs-components
|
|
9
|
+
* @name: AbSwitchBack - Server (port of lyd-switch-back)
|
|
10
|
+
* @file: server/ab-switch-back/index.tsx
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
import type { ReactElement, ReactNode } from 'react';
|
|
15
|
+
import Link from 'next/link';
|
|
16
|
+
import Image from 'next/image';
|
|
17
|
+
import clsx from 'clsx';
|
|
18
|
+
import styles from './styles.module.css';
|
|
19
|
+
|
|
20
|
+
export interface AbSwitchBackProps {
|
|
21
|
+
className?: string;
|
|
22
|
+
hidden?: boolean;
|
|
23
|
+
switched?: boolean;
|
|
24
|
+
image: string;
|
|
25
|
+
imageAlt: string;
|
|
26
|
+
title?: ReactNode;
|
|
27
|
+
description?: ReactNode;
|
|
28
|
+
cta1Label: string;
|
|
29
|
+
cta1Link: string;
|
|
30
|
+
cta2Label: string;
|
|
31
|
+
cta2Link: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const AbSwitchBack = ({
|
|
35
|
+
className,
|
|
36
|
+
hidden = false,
|
|
37
|
+
switched = false,
|
|
38
|
+
image,
|
|
39
|
+
imageAlt,
|
|
40
|
+
title,
|
|
41
|
+
description,
|
|
42
|
+
cta1Label,
|
|
43
|
+
cta1Link,
|
|
44
|
+
cta2Label,
|
|
45
|
+
cta2Link,
|
|
46
|
+
}: AbSwitchBackProps): ReactElement => {
|
|
47
|
+
return (
|
|
48
|
+
<section
|
|
49
|
+
hidden={hidden}
|
|
50
|
+
data-switched={switched ? 'true' : 'false'}
|
|
51
|
+
className={clsx('AbSwitchBack', styles.abSwitchBack, className)}
|
|
52
|
+
>
|
|
53
|
+
<div className={styles.abSwitchBackMedia}>
|
|
54
|
+
<Image className={styles.abSwitchBackImage} src={image} alt={imageAlt} width={800} height={600} unoptimized />
|
|
55
|
+
</div>
|
|
56
|
+
<div className={styles.abSwitchBackCopy}>
|
|
57
|
+
{title ? <h2 className={styles.abSwitchBackTitle}>{title}</h2> : null}
|
|
58
|
+
{description ? <div className={styles.abSwitchBackDesc}>{description}</div> : null}
|
|
59
|
+
<div className={styles.abSwitchBackActions}>
|
|
60
|
+
<Link href={cta1Link} className={styles.abSwitchBackCta}>{cta1Label}</Link>
|
|
61
|
+
<Link href={cta2Link} className={clsx(styles.abSwitchBackCta, styles.abSwitchBackCtaSecondary)}>
|
|
62
|
+
{cta2Label}
|
|
63
|
+
</Link>
|
|
64
|
+
</div>
|
|
65
|
+
</div>
|
|
66
|
+
</section>
|
|
67
|
+
);
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
export default AbSwitchBack;
|
|
71
|
+
export { AbSwitchBack };
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
.abSwitchBack {
|
|
2
|
+
display: grid;
|
|
3
|
+
grid-template-columns: 1fr;
|
|
4
|
+
gap: 1.25rem;
|
|
5
|
+
align-items: center;
|
|
6
|
+
}
|
|
7
|
+
@media (min-width: 768px) {
|
|
8
|
+
.abSwitchBack {
|
|
9
|
+
grid-template-columns: 1fr 1fr;
|
|
10
|
+
}
|
|
11
|
+
.abSwitchBack[data-switched='true'] .abSwitchBackMedia { order: 2; }
|
|
12
|
+
.abSwitchBack[data-switched='true'] .abSwitchBackCopy { order: 1; }
|
|
13
|
+
}
|
|
14
|
+
.abSwitchBackMedia {
|
|
15
|
+
position: relative;
|
|
16
|
+
width: 100%;
|
|
17
|
+
aspect-ratio: 4 / 3;
|
|
18
|
+
border-radius: 1rem;
|
|
19
|
+
overflow: hidden;
|
|
20
|
+
background: #ddd;
|
|
21
|
+
}
|
|
22
|
+
.abSwitchBackImage {
|
|
23
|
+
object-fit: cover;
|
|
24
|
+
width: 100%;
|
|
25
|
+
height: 100%;
|
|
26
|
+
}
|
|
27
|
+
.abSwitchBackCopy { display: flex; flex-direction: column; gap: 0.75rem; }
|
|
28
|
+
.abSwitchBackTitle { margin: 0; font-size: 1.5rem; font-weight: 700; }
|
|
29
|
+
.abSwitchBackDesc { margin: 0; opacity: 0.8; }
|
|
30
|
+
.abSwitchBackActions { display: flex; flex-wrap: wrap; gap: 0.5rem; }
|
|
31
|
+
.abSwitchBackCta {
|
|
32
|
+
display: inline-flex;
|
|
33
|
+
align-items: center;
|
|
34
|
+
padding: 0.5rem 1rem;
|
|
35
|
+
border-radius: 9999px;
|
|
36
|
+
text-decoration: none;
|
|
37
|
+
font-weight: 600;
|
|
38
|
+
background: var(--ab-primary, #6750a4);
|
|
39
|
+
color: #fff;
|
|
40
|
+
}
|
|
41
|
+
.abSwitchBackCtaSecondary {
|
|
42
|
+
background: transparent;
|
|
43
|
+
color: var(--ab-primary, #6750a4);
|
|
44
|
+
border: 1px solid color-mix(in srgb, var(--ab-primary, #6750a4) 40%, transparent);
|
|
45
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @license MIT
|
|
3
|
+
* ~~~~~~~~~~~~
|
|
4
|
+
* ab-nextjs-components
|
|
5
|
+
* ~~~~~~~~~~~~
|
|
6
|
+
* Copyright (c) 2026 Abraham Ukachi. The abElements Project.
|
|
7
|
+
*
|
|
8
|
+
* @project: ab-nextjs-components
|
|
9
|
+
* @name: AbTestHello - Server (port of lyd-test-hello)
|
|
10
|
+
* @file: server/ab-test-hello/index.tsx
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import type { ReactElement } from 'react';
|
|
14
|
+
import clsx from 'clsx';
|
|
15
|
+
import styles from './styles.module.css';
|
|
16
|
+
|
|
17
|
+
export interface AbTestHelloProps {
|
|
18
|
+
name: string;
|
|
19
|
+
src?: string;
|
|
20
|
+
className?: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const AbTestHello = ({ name, src, className }: AbTestHelloProps): ReactElement => {
|
|
24
|
+
return (
|
|
25
|
+
<div id="abTestHello" className={clsx('AbTestHello', styles.abTestHello, className)}>
|
|
26
|
+
<h2 className={styles.abTestHelloTitle}>
|
|
27
|
+
Hello from <span className={styles.abTestHelloName}>{name}</span>
|
|
28
|
+
</h2>
|
|
29
|
+
{src ? <span className={styles.abTestHelloSrc}>{src}</span> : null}
|
|
30
|
+
</div>
|
|
31
|
+
);
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export default AbTestHello;
|
|
35
|
+
export { AbTestHello };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
.abTestHello {
|
|
2
|
+
display: flex;
|
|
3
|
+
flex-direction: column;
|
|
4
|
+
align-items: flex-start;
|
|
5
|
+
text-align: left;
|
|
6
|
+
padding: 1.5rem;
|
|
7
|
+
}
|
|
8
|
+
.abTestHelloTitle {
|
|
9
|
+
margin: 0;
|
|
10
|
+
padding: 0.75rem 0 0.25rem;
|
|
11
|
+
font-size: 1rem;
|
|
12
|
+
}
|
|
13
|
+
.abTestHelloName {
|
|
14
|
+
font-family: ui-serif, Georgia, serif;
|
|
15
|
+
font-weight: 700;
|
|
16
|
+
color: var(--ab-primary, #6750a4);
|
|
17
|
+
}
|
|
18
|
+
.abTestHelloSrc {
|
|
19
|
+
font-family: ui-monospace, monospace;
|
|
20
|
+
font-size: 0.875rem;
|
|
21
|
+
opacity: 0.5;
|
|
22
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @license MIT
|
|
3
|
+
* ~~~~~~~~~~~~
|
|
4
|
+
* ab-nextjs-components
|
|
5
|
+
* ~~~~~~~~~~~~
|
|
6
|
+
* Copyright (c) 2026 Abraham Ukachi. The abElements Project.
|
|
7
|
+
*
|
|
8
|
+
* @project: ab-nextjs-components
|
|
9
|
+
* @name: AbText - Server (port of lyd-text; i18n stripped)
|
|
10
|
+
* @file: server/ab-text/index.tsx
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import type { ReactElement } from 'react';
|
|
14
|
+
import clsx from 'clsx';
|
|
15
|
+
import styles from './styles.module.css';
|
|
16
|
+
|
|
17
|
+
export interface AbTextProps {
|
|
18
|
+
className?: string;
|
|
19
|
+
id?: string;
|
|
20
|
+
value?: string;
|
|
21
|
+
origin?: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const AbText = ({ className, id, value }: AbTextProps): ReactElement => {
|
|
25
|
+
return (
|
|
26
|
+
<span id={id} className={clsx('AbText', styles.abText, className)}>
|
|
27
|
+
{value ?? id ?? ''}
|
|
28
|
+
</span>
|
|
29
|
+
);
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export default AbText;
|
|
33
|
+
export { AbText };
|
package/server/index.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @license MIT
|
|
3
|
+
* ~~~~~~~~~~~~
|
|
4
|
+
* ab-nextjs-components
|
|
5
|
+
* ~~~~~~~~~~~~
|
|
6
|
+
* Copyright (c) 2026 Abraham Ukachi. The abElements Project.
|
|
7
|
+
*
|
|
8
|
+
* @project: ab-nextjs-components
|
|
9
|
+
* @name: Server Components - Barrel
|
|
10
|
+
* @file: server/index.ts
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
export { default as AbIcon } from './ab-icon/index.tsx'
|
|
14
|
+
export { default as AbLogo } from './ab-logo/index.tsx'
|
|
15
|
+
export { default as AbButton } from './ab-button/index.tsx'
|
|
16
|
+
export { default as AbAvatar } from './ab-avatar/index.tsx'
|
|
17
|
+
export { default as AbBadge } from './ab-badge/index.tsx'
|
|
18
|
+
export { default as AbPolygon } from './ab-polygon/index.tsx'
|
|
19
|
+
export { default as AbBrand } from './ab-brand/index.tsx'
|
|
20
|
+
export { default as AbName } from './ab-name/index.tsx'
|
|
21
|
+
export { default as AbNavbar } from './ab-navbar/index.tsx'
|
|
22
|
+
export { default as AbSidebar } from './ab-sidebar/index.tsx'
|
|
23
|
+
export { default as AbNavLink } from './ab-nav-link/index.tsx'
|
|
24
|
+
export { default as AbText } from './ab-text/index.tsx'
|
|
25
|
+
export { default as AbTestHello } from './ab-test-hello/index.tsx'
|
|
26
|
+
export { default as AbKeyFeature } from './ab-key-feature/index.tsx'
|
|
27
|
+
export { default as AbSwitchBack } from './ab-switch-back/index.tsx'
|