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
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
### Unreleased (chore/upgrade-next-16 — Skip-override / Phase 5 components)
|
|
2
|
+
|
|
3
|
+
* **Port (client):** AbBrand, AbName, AbNavbar, AbSidebar, AbText, AbTestHello, AbKeyFeature, AbMainHeadline, AbPreview, AbProduct, AbProductItem, AbSwitchBack, AbDemoBox, AbDemoCode
|
|
4
|
+
* **Port (server):** AbBrand, AbName, AbNavbar, AbSidebar, AbNavLink, AbText, AbTestHello, AbKeyFeature, AbSwitchBack
|
|
5
|
+
* Select/MenuItem skipped — empty on Projects (GitHub-only historically)
|
|
6
|
+
* Product/Preview adapted (Dexie/providers/i18n stripped); usable props API kept
|
|
7
|
+
* Catalog **51 Done** (36 client / 15 server). Local only — no push.
|
|
8
|
+
|
|
9
|
+
# Changelog
|
|
10
|
+
|
|
11
|
+
### Unreleased (chore/upgrade-next-16 — Phase 4 Port)
|
|
12
|
+
|
|
13
|
+
* **Port:** AbSearchbar, AbSearchResult, AbPagePaginator, AbPageSwitcher, AbProgressChips, AbPrice, AbPriceTag
|
|
14
|
+
* **Adapt:** AbImage (Dexie / offline / background-removal stripped; next/image + optional fallback)
|
|
15
|
+
* **Port (server):** AbPolygon
|
|
16
|
+
* Catalog 28 Done (22 client / 6 server). Plain CSS modules. Local only — no push.
|
|
17
|
+
|
|
18
|
+
### Unreleased (chore/upgrade-next-16 — Phase 2 Adapt + Phase 3 Port)
|
|
19
|
+
|
|
20
|
+
* **Adapt:** **AbBalloon** (`title=` locked) — Input now uses real AbBalloon
|
|
21
|
+
* **Port:** AbAvatar (client + server), AbBadge (server), AbTab, AbTabs, AbMenu, AbCollapsible, AbColor, AbInfo, AbLikeButton
|
|
22
|
+
* Plain CSS modules; LYD brand/nav/i18n stripped; Select/MenuItem skipped (not on Projects)
|
|
23
|
+
|
|
24
|
+
### Unreleased (chore/upgrade-next-16 — Phase 2)
|
|
25
|
+
|
|
26
|
+
* Ported **AbIcon** (client + server) — Material Symbols ligatures
|
|
27
|
+
* Ported **AbLogo** (client + server) — contained | outlined | hollow | naked; defaults from `ab-nextjs-icons` logos (`#a67c52`), optional `src` / `mask`
|
|
28
|
+
* Ported **AbButton** client from lyd-button; invented server (href → `<a>`, else submit/button; no onClick)
|
|
29
|
+
* Added minimal **AbIconButton** (Input dependency)
|
|
30
|
+
* Ported **AbInput** client — `useAbToggle` from `ab-nextjs-hooks/helpers/useAbToggle`; Balloon stub via `title=`; no console.logs
|
|
31
|
+
* Hard peers: next 16.3.4, react^19, clsx; soft optional peers: theme / icons / hooks / animations
|
|
32
|
+
* Plain CSS modules (no `@apply`); theme `data-*` attrs preserved on buttons
|
|
33
|
+
|
|
34
|
+
### Unreleased (Phase 1)
|
|
35
|
+
|
|
36
|
+
* Next.js **16.3.4** / React 19 tooling scaffold + Pending catalog
|
|
37
|
+
|
|
38
|
+
### 0.1.2
|
|
39
|
+
|
|
40
|
+
* Stub package version bump
|
package/LICENSE
CHANGED
|
@@ -2,7 +2,7 @@ MIT License
|
|
|
2
2
|
~~~~~~~~~~~
|
|
3
3
|
ab-nextjs-components
|
|
4
4
|
~~~~~~~~~~~
|
|
5
|
-
Copyright (c) 2024 Abraham Ukachi.
|
|
5
|
+
Copyright (c) 2024 Abraham Ukachi. The abElements Project.
|
|
6
6
|
|
|
7
7
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
8
8
|
of this software and associated documentation files (the "Software"), to deal
|
package/README.md
CHANGED
|
@@ -1,10 +1,49 @@
|
|
|
1
|
-
|
|
1
|
+
<p align="center">
|
|
2
|
+
<!-- Ab - Logo - Light Mode -->
|
|
3
|
+
<a href="https://abraham-ukachi.vercel.app/#gh-light-mode-only" target="_blank">
|
|
4
|
+
<img src="./.github/ab-logo-light.svg" alt="Ab Logo on Light" width="64" height="64" />
|
|
5
|
+
</a>
|
|
6
|
+
|
|
7
|
+
<!-- Ab - Logo - Dark Mode -->
|
|
8
|
+
<a href="https://abraham-ukachi.vercel.app/#gh-dark-mode-only" target="_blank">
|
|
9
|
+
<img src="./.github/ab-logo-dark.svg" alt="Ab Logo on Dark" width="64" height="64" />
|
|
10
|
+
</a>
|
|
11
|
+
|
|
12
|
+
<!-- Next.js - Logo Name - Light Mode -->
|
|
13
|
+
<a href="https://nextjs.org/#gh-light-mode-only" target="_blank">
|
|
14
|
+
<img src="./.github/nextjs-logoname-light.svg" alt="Next.js LogoName on Light" width="192" height="64" />
|
|
15
|
+
</a>
|
|
16
|
+
|
|
17
|
+
<!-- Next.js - Logo Name - Dark Mode -->
|
|
18
|
+
<a href="https://nextjs.org/#gh-dark-mode-only" target="_blank">
|
|
19
|
+
<img src="./.github/nextjs-logoname-dark.svg" alt="Next.js LogoName on Dark" width="192" height="64" />
|
|
20
|
+
</a>
|
|
21
|
+
|
|
22
|
+
</p>
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
<p align="center">
|
|
26
|
+
<a href="https://ab-elements.vercel.app" target="_blank"><b>Checkout abElements →</b></a>
|
|
27
|
+
</p>
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
# `ab-nextjs-components`
|
|
2
31
|
|
|
3
32
|
> IMPORTANT: This is a work in progress and subject to major changes until version 1.0.
|
|
4
33
|
|
|
34
|
+
|
|
5
35
|
🚀 This is a lightweight collection of server & client React components created by [Abraham Ukachi](https://github.com/abraham-ukachi), and optimized for [Next.js](https://nextjs.org/docs) applications 😎.
|
|
6
36
|
|
|
7
37
|
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
## Tooling (Phase 1)
|
|
41
|
+
|
|
42
|
+
- Next.js **16.3.4** / React **19** hard peers
|
|
43
|
+
- ESLint 9 flat + Vitest
|
|
44
|
+
- Package ships as TypeScript (`type: module`) with a `supportedComponents` catalog
|
|
45
|
+
- Phase 2 Adapt complete; Phase 4 + Skip-override (Phase 5 components) complete (local)
|
|
46
|
+
|
|
8
47
|
## Getting Started
|
|
9
48
|
|
|
10
49
|
### Installation
|
|
@@ -39,14 +78,42 @@ A list of all the **client components** and their current status:
|
|
|
39
78
|
|
|
40
79
|
| No. | Name | File | Status |
|
|
41
80
|
|:----|:-----|:-----|:-------|
|
|
42
|
-
| 1 | *`
|
|
43
|
-
| 2 | *`
|
|
44
|
-
| 3 | *`AbButton`* | **ab-button/index.tsx** |
|
|
45
|
-
| 4 | *`
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
81
|
+
| 1 | *`AbIcon`* | **ab-icon/index.tsx** | Done |
|
|
82
|
+
| 2 | *`AbLogo`* | **ab-logo/index.tsx** | Done |
|
|
83
|
+
| 3 | *`AbButton`* | **ab-button/index.tsx** | Done |
|
|
84
|
+
| 4 | *`AbIconButton`* | **ab-icon-button/index.tsx** | Done |
|
|
85
|
+
| 5 | *`AbInput`* | **ab-input/index.tsx** | Done |
|
|
86
|
+
| 6 | *`AbBalloon`* | **ab-balloon/index.tsx** | Done |
|
|
87
|
+
| 7 | *`AbAvatar`* | **ab-avatar/index.tsx** | Done |
|
|
88
|
+
| 8 | *`AbTab`* | **ab-tab/index.tsx** | Done |
|
|
89
|
+
| 9 | *`AbTabs`* | **ab-tabs/index.tsx** | Done |
|
|
90
|
+
| 10 | *`AbMenu`* | **ab-menu/index.tsx** | Done |
|
|
91
|
+
| 11 | *`AbCollapsible`* | **ab-collapsible/index.tsx** | Done |
|
|
92
|
+
| 12 | *`AbColor`* | **ab-color/index.tsx** | Done |
|
|
93
|
+
| 13 | *`AbInfo`* | **ab-info/index.tsx** | Done |
|
|
94
|
+
| 14 | *`AbLikeButton`* | **ab-like-button/index.tsx** | Done |
|
|
95
|
+
| 15 | *`AbSearchbar`* | **ab-searchbar/index.tsx** | Done |
|
|
96
|
+
| 16 | *`AbSearchResult`* | **ab-search-result/index.tsx** | Done |
|
|
97
|
+
| 17 | *`AbPagePaginator`* | **ab-page-paginator/index.tsx** | Done |
|
|
98
|
+
| 18 | *`AbPageSwitcher`* | **ab-page-switcher/index.tsx** | Done |
|
|
99
|
+
| 19 | *`AbProgressChips`* | **ab-progress-chips/index.tsx** | Done |
|
|
100
|
+
| 20 | *`AbPrice`* | **ab-price/index.tsx** | Done |
|
|
101
|
+
| 21 | *`AbPriceTag`* | **ab-price-tag/index.tsx** | Done |
|
|
102
|
+
| 22 | *`AbImage`* | **ab-image/index.tsx** | Done |
|
|
103
|
+
| 23 | *`AbBrand`* | **ab-brand/index.tsx** | Done |
|
|
104
|
+
| 24 | *`AbName`* | **ab-name/index.tsx** | Done |
|
|
105
|
+
| 25 | *`AbNavbar`* | **ab-navbar/index.tsx** | Done |
|
|
106
|
+
| 26 | *`AbSidebar`* | **ab-sidebar/index.tsx** | Done |
|
|
107
|
+
| 27 | *`AbText`* | **ab-text/index.tsx** | Done |
|
|
108
|
+
| 28 | *`AbTestHello`* | **ab-test-hello/index.tsx** | Done |
|
|
109
|
+
| 29 | *`AbKeyFeature`* | **ab-key-feature/index.tsx** | Done |
|
|
110
|
+
| 30 | *`AbMainHeadline`* | **ab-main-headline/index.tsx** | Done |
|
|
111
|
+
| 31 | *`AbPreview`* | **ab-preview/index.tsx** | Done |
|
|
112
|
+
| 32 | *`AbProduct`* | **ab-product/index.tsx** | Done |
|
|
113
|
+
| 33 | *`AbProductItem`* | **ab-product-item/index.tsx** | Done |
|
|
114
|
+
| 34 | *`AbSwitchBack`* | **ab-switch-back/index.tsx** | Done |
|
|
115
|
+
| 35 | *`AbDemoBox`* | **ab-demo-box/index.tsx** | Done |
|
|
116
|
+
| 36 | *`AbDemoCode`* | **ab-demo-code/index.tsx** | Done |
|
|
50
117
|
|
|
51
118
|
## Server Components
|
|
52
119
|
|
|
@@ -54,12 +121,21 @@ A list of all the **server components** and their current status:
|
|
|
54
121
|
|
|
55
122
|
| No. | Name | File | Status |
|
|
56
123
|
|:----|:-----|:-----|:-------|
|
|
57
|
-
| 1 | *`
|
|
58
|
-
| 2 | *`
|
|
59
|
-
| 3 | *`AbButton`* | **server/ab-button/index.tsx** |
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
124
|
+
| 1 | *`AbIcon`* | **server/ab-icon/index.tsx** | Done |
|
|
125
|
+
| 2 | *`AbLogo`* | **server/ab-logo/index.tsx** | Done |
|
|
126
|
+
| 3 | *`AbButton`* | **server/ab-button/index.tsx** | Done |
|
|
127
|
+
| 4 | *`AbAvatar`* | **server/ab-avatar/index.tsx** | Done |
|
|
128
|
+
| 5 | *`AbBadge`* | **server/ab-badge/index.tsx** | Done |
|
|
129
|
+
| 6 | *`AbPolygon`* | **server/ab-polygon/index.tsx** | Done |
|
|
130
|
+
| 7 | *`AbBrand`* | **server/ab-brand/index.tsx** | Done |
|
|
131
|
+
| 8 | *`AbName`* | **server/ab-name/index.tsx** | Done |
|
|
132
|
+
| 9 | *`AbNavbar`* | **server/ab-navbar/index.tsx** | Done |
|
|
133
|
+
| 10 | *`AbSidebar`* | **server/ab-sidebar/index.tsx** | Done |
|
|
134
|
+
| 11 | *`AbNavLink`* | **server/ab-nav-link/index.tsx** | Done |
|
|
135
|
+
| 12 | *`AbText`* | **server/ab-text/index.tsx** | Done |
|
|
136
|
+
| 13 | *`AbTestHello`* | **server/ab-test-hello/index.tsx** | Done |
|
|
137
|
+
| 14 | *`AbKeyFeature`* | **server/ab-key-feature/index.tsx** | Done |
|
|
138
|
+
| 15 | *`AbSwitchBack`* | **server/ab-switch-back/index.tsx** | Done |
|
|
63
139
|
|
|
64
140
|
|
|
65
141
|
## Learn More abElements
|
|
@@ -0,0 +1,90 @@
|
|
|
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: AbAvatar - Client (port of lyd-avatar)
|
|
10
|
+
* @file: ab-avatar/index.tsx
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
'use client';
|
|
14
|
+
|
|
15
|
+
import type { ReactElement } from 'react';
|
|
16
|
+
import Image from 'next/image';
|
|
17
|
+
import Link from 'next/link';
|
|
18
|
+
import clsx from 'clsx';
|
|
19
|
+
import styles from './styles.module.css';
|
|
20
|
+
|
|
21
|
+
export interface AbAvatarProps {
|
|
22
|
+
isConnected: boolean;
|
|
23
|
+
isOnline: boolean;
|
|
24
|
+
icon?: 'person' | 'group';
|
|
25
|
+
version?: number;
|
|
26
|
+
image?: string;
|
|
27
|
+
label?: string;
|
|
28
|
+
className?: string;
|
|
29
|
+
width?: number;
|
|
30
|
+
height?: number;
|
|
31
|
+
/** Connected href (default `/`). Offline href (default `/`). No app-brand routes. */
|
|
32
|
+
href?: string;
|
|
33
|
+
offlineHref?: string;
|
|
34
|
+
isActive?: boolean;
|
|
35
|
+
noIndicator?: boolean;
|
|
36
|
+
onClick?: () => void;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const AbAvatar = ({
|
|
40
|
+
isConnected,
|
|
41
|
+
isOnline,
|
|
42
|
+
icon = 'person',
|
|
43
|
+
version = 1,
|
|
44
|
+
image,
|
|
45
|
+
label = 'Avatar',
|
|
46
|
+
className,
|
|
47
|
+
width = 48,
|
|
48
|
+
height = 48,
|
|
49
|
+
href = '/',
|
|
50
|
+
offlineHref = '/',
|
|
51
|
+
isActive = false,
|
|
52
|
+
noIndicator = false,
|
|
53
|
+
onClick,
|
|
54
|
+
}: AbAvatarProps): ReactElement => {
|
|
55
|
+
const src = image ?? `/assets/images/avatars/avatar_${version}.png`;
|
|
56
|
+
|
|
57
|
+
return (
|
|
58
|
+
<div className={clsx('AbAvatar', styles.abAvatar, className)} onClick={onClick}>
|
|
59
|
+
{isConnected ? (
|
|
60
|
+
<Link href={href} className={clsx(styles.abAvatarLink, isActive && styles.isActive)}>
|
|
61
|
+
<span className={styles.abAvatarImageWrap}>
|
|
62
|
+
<Image
|
|
63
|
+
src={src}
|
|
64
|
+
className={styles.abAvatarImage}
|
|
65
|
+
width={width}
|
|
66
|
+
height={height}
|
|
67
|
+
alt={label}
|
|
68
|
+
/>
|
|
69
|
+
{!noIndicator ? (
|
|
70
|
+
<span
|
|
71
|
+
className={clsx(styles.abAvatarIndicator, !isOnline && styles.isOffline)}
|
|
72
|
+
aria-hidden
|
|
73
|
+
/>
|
|
74
|
+
) : null}
|
|
75
|
+
</span>
|
|
76
|
+
</Link>
|
|
77
|
+
) : (
|
|
78
|
+
<Link href={offlineHref} className={styles.abAvatarOffline}>
|
|
79
|
+
<span className={clsx('material-symbols-rounded', styles.abAvatarIcon)} aria-hidden>
|
|
80
|
+
{icon}
|
|
81
|
+
</span>
|
|
82
|
+
{label ? <span className={styles.abAvatarLabel}>{label}</span> : null}
|
|
83
|
+
</Link>
|
|
84
|
+
)}
|
|
85
|
+
</div>
|
|
86
|
+
);
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
export default AbAvatar;
|
|
90
|
+
export { AbAvatar };
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/* AbAvatar — plain CSS (no Tailwind apply) */
|
|
2
|
+
.abAvatar {
|
|
3
|
+
display: flex;
|
|
4
|
+
flex-direction: column;
|
|
5
|
+
width: auto;
|
|
6
|
+
height: auto;
|
|
7
|
+
pointer-events: auto;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
.abAvatarLink {
|
|
11
|
+
position: relative;
|
|
12
|
+
display: inline-flex;
|
|
13
|
+
text-decoration: none;
|
|
14
|
+
opacity: 1;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.isActive {
|
|
18
|
+
opacity: 0.9;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.abAvatarImageWrap {
|
|
22
|
+
position: relative;
|
|
23
|
+
display: inline-flex;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.abAvatarImage {
|
|
27
|
+
border-radius: 9999px;
|
|
28
|
+
object-fit: cover;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.abAvatarIndicator {
|
|
32
|
+
position: absolute;
|
|
33
|
+
right: 0;
|
|
34
|
+
bottom: 0;
|
|
35
|
+
width: 1rem;
|
|
36
|
+
height: 1rem;
|
|
37
|
+
border-radius: 9999px;
|
|
38
|
+
border: 2px solid var(--ab-surface, #fff);
|
|
39
|
+
background: #22c55e;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.abAvatarIndicator.isOffline {
|
|
43
|
+
background: #ef4444;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.abAvatarOffline {
|
|
47
|
+
display: inline-flex;
|
|
48
|
+
flex-direction: column;
|
|
49
|
+
align-items: center;
|
|
50
|
+
gap: 0.25rem;
|
|
51
|
+
text-decoration: none;
|
|
52
|
+
color: inherit;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.abAvatarIcon {
|
|
56
|
+
font-size: 1.75rem;
|
|
57
|
+
line-height: 1;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.abAvatarLabel {
|
|
61
|
+
font-size: 0.75rem;
|
|
62
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
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: AbBalloon - Client (Adapt — title= locked)
|
|
10
|
+
* @file: ab-balloon/index.tsx
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
'use client';
|
|
14
|
+
|
|
15
|
+
import type { ReactElement, ReactNode } from 'react';
|
|
16
|
+
import clsx from 'clsx';
|
|
17
|
+
import styles from './styles.module.css';
|
|
18
|
+
|
|
19
|
+
export interface AbBalloonProps {
|
|
20
|
+
/** Native tooltip text — locked API (`title=`). */
|
|
21
|
+
title?: string;
|
|
22
|
+
className?: string;
|
|
23
|
+
hidden?: boolean;
|
|
24
|
+
disabled?: boolean;
|
|
25
|
+
children: ReactNode;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* AbBalloon — Phase 2 Adapt.
|
|
30
|
+
* Uses the native `title=` tooltip (locked). Not a port of the LYD hover balloon.
|
|
31
|
+
*/
|
|
32
|
+
const AbBalloon = ({
|
|
33
|
+
title,
|
|
34
|
+
className,
|
|
35
|
+
hidden = false,
|
|
36
|
+
disabled = false,
|
|
37
|
+
children,
|
|
38
|
+
}: AbBalloonProps): ReactElement => {
|
|
39
|
+
if (hidden) {
|
|
40
|
+
return <>{children}</>;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return (
|
|
44
|
+
<span
|
|
45
|
+
className={clsx('AbBalloon', styles.abBalloon, className)}
|
|
46
|
+
title={disabled ? undefined : title}
|
|
47
|
+
data-disabled={disabled ? 'true' : 'false'}
|
|
48
|
+
>
|
|
49
|
+
{children}
|
|
50
|
+
</span>
|
|
51
|
+
);
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export default AbBalloon;
|
|
55
|
+
export { AbBalloon };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/* AbBalloon — title= Adapt (no hover chrome; native tooltip only) */
|
|
2
|
+
.abBalloon {
|
|
3
|
+
display: inline-flex;
|
|
4
|
+
align-items: center;
|
|
5
|
+
justify-content: center;
|
|
6
|
+
box-sizing: border-box;
|
|
7
|
+
max-width: 100%;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
.abBalloon[data-disabled='true'] {
|
|
11
|
+
pointer-events: none;
|
|
12
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
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: AbBrand - Client (port of lyd-brand)
|
|
10
|
+
* @file: ab-brand/index.tsx
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
'use client';
|
|
14
|
+
|
|
15
|
+
import type { CSSProperties, ReactElement } from 'react';
|
|
16
|
+
import Link from 'next/link';
|
|
17
|
+
import Image from 'next/image';
|
|
18
|
+
import clsx from 'clsx';
|
|
19
|
+
import styles from './styles.module.css';
|
|
20
|
+
|
|
21
|
+
export interface AbBrandProps {
|
|
22
|
+
className?: string;
|
|
23
|
+
type?: 'default' | 'blurred';
|
|
24
|
+
effect?: 'normal' | 'zoom';
|
|
25
|
+
hidden?: boolean;
|
|
26
|
+
image: string;
|
|
27
|
+
imageAlt?: string;
|
|
28
|
+
logo: string;
|
|
29
|
+
logoAlt?: string;
|
|
30
|
+
name: string;
|
|
31
|
+
shortName: string;
|
|
32
|
+
description: string;
|
|
33
|
+
autohideDescription?: boolean;
|
|
34
|
+
color?: string;
|
|
35
|
+
accentColor?: string;
|
|
36
|
+
link: string;
|
|
37
|
+
ctaLabel: string;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const AbBrand = ({
|
|
41
|
+
className,
|
|
42
|
+
type = 'default',
|
|
43
|
+
effect = 'normal',
|
|
44
|
+
hidden = false,
|
|
45
|
+
image,
|
|
46
|
+
imageAlt,
|
|
47
|
+
logo,
|
|
48
|
+
logoAlt,
|
|
49
|
+
name,
|
|
50
|
+
shortName,
|
|
51
|
+
description,
|
|
52
|
+
autohideDescription = false,
|
|
53
|
+
color,
|
|
54
|
+
accentColor,
|
|
55
|
+
link,
|
|
56
|
+
ctaLabel,
|
|
57
|
+
}: AbBrandProps): ReactElement => {
|
|
58
|
+
const style = {
|
|
59
|
+
'--ab-brand-color': color,
|
|
60
|
+
'--ab-brand-accent': accentColor,
|
|
61
|
+
} as CSSProperties;
|
|
62
|
+
|
|
63
|
+
return (
|
|
64
|
+
<Link
|
|
65
|
+
href={link}
|
|
66
|
+
hidden={hidden}
|
|
67
|
+
data-type={type}
|
|
68
|
+
data-effect={effect}
|
|
69
|
+
data-autohide-desc={autohideDescription ? 'true' : 'false'}
|
|
70
|
+
className={clsx('AbBrand', styles.abBrand, className)}
|
|
71
|
+
style={style}
|
|
72
|
+
>
|
|
73
|
+
<div className={styles.abBrandImageWrap}>
|
|
74
|
+
<Image className={styles.abBrandImage} src={image} alt={imageAlt ?? name} width={640} height={360} unoptimized />
|
|
75
|
+
</div>
|
|
76
|
+
<div className={styles.abBrandMeta}>
|
|
77
|
+
<Image className={styles.abBrandLogo} src={logo} alt={logoAlt ?? shortName} width={40} height={40} unoptimized />
|
|
78
|
+
<span className={styles.abBrandShort}>{shortName}</span>
|
|
79
|
+
<h3 className={styles.abBrandName}>{name}</h3>
|
|
80
|
+
<p className={styles.abBrandDesc}>{description}</p>
|
|
81
|
+
<span className={styles.abBrandCta}>{ctaLabel}</span>
|
|
82
|
+
</div>
|
|
83
|
+
</Link>
|
|
84
|
+
);
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
export default AbBrand;
|
|
88
|
+
export { AbBrand };
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
.abBrand {
|
|
2
|
+
position: relative;
|
|
3
|
+
display: flex;
|
|
4
|
+
flex-direction: column;
|
|
5
|
+
gap: 0.75rem;
|
|
6
|
+
padding: 1rem;
|
|
7
|
+
border-radius: 1rem;
|
|
8
|
+
overflow: hidden;
|
|
9
|
+
text-decoration: none;
|
|
10
|
+
color: inherit;
|
|
11
|
+
background: color-mix(in srgb, var(--ab-surface-container, #f3edf7) 90%, transparent);
|
|
12
|
+
}
|
|
13
|
+
.abBrand[data-type='blurred'] {
|
|
14
|
+
backdrop-filter: blur(12px);
|
|
15
|
+
}
|
|
16
|
+
.abBrand[data-effect='zoom']:hover .abBrandImage {
|
|
17
|
+
transform: scale(1.05);
|
|
18
|
+
}
|
|
19
|
+
.abBrandImageWrap {
|
|
20
|
+
position: relative;
|
|
21
|
+
width: 100%;
|
|
22
|
+
aspect-ratio: 16 / 9;
|
|
23
|
+
border-radius: 0.75rem;
|
|
24
|
+
overflow: hidden;
|
|
25
|
+
background: #ddd;
|
|
26
|
+
}
|
|
27
|
+
.abBrandImage {
|
|
28
|
+
object-fit: cover;
|
|
29
|
+
width: 100%;
|
|
30
|
+
height: 100%;
|
|
31
|
+
transition: transform 0.35s ease;
|
|
32
|
+
}
|
|
33
|
+
.abBrandLogo {
|
|
34
|
+
width: 2.5rem;
|
|
35
|
+
height: 2.5rem;
|
|
36
|
+
object-fit: contain;
|
|
37
|
+
}
|
|
38
|
+
.abBrandMeta { display: flex; flex-direction: column; gap: 0.25rem; }
|
|
39
|
+
.abBrandName { margin: 0; font-size: 1.125rem; font-weight: 700; }
|
|
40
|
+
.abBrandShort { font-size: 0.75rem; font-weight: 600; opacity: 0.7; text-transform: uppercase; }
|
|
41
|
+
.abBrandDesc { margin: 0; font-size: 0.875rem; opacity: 0.8; }
|
|
42
|
+
.abBrand[data-autohide-desc='true'] .abBrandDesc { display: none; }
|
|
43
|
+
.abBrandCta {
|
|
44
|
+
align-self: flex-start;
|
|
45
|
+
border: none;
|
|
46
|
+
border-radius: 9999px;
|
|
47
|
+
padding: 0.4rem 0.9rem;
|
|
48
|
+
background: var(--ab-brand-accent, var(--ab-primary, #6750a4));
|
|
49
|
+
color: #fff;
|
|
50
|
+
font: inherit;
|
|
51
|
+
font-weight: 600;
|
|
52
|
+
cursor: pointer;
|
|
53
|
+
text-decoration: none;
|
|
54
|
+
}
|