@farihatang/react-ui 0.1.0-beta.1
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/README.md +82 -0
- package/dist/index.d.mts +49 -0
- package/dist/index.d.ts +49 -0
- package/dist/index.js +272 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +264 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +65 -0
package/README.md
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# @farihatang/react-ui โ React Component Library
|
|
2
|
+
|
|
3
|
+
> A React component library to help you build your own GitHub projects more easily. Built with React 18, TypeScript (strict), and Tailwind CSS. Documented in Storybook.
|
|
4
|
+
|
|
5
|
+
๐ **Storybook**: _https://react-component-library-farihatang.vercel.app_
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Components
|
|
10
|
+
|
|
11
|
+
| Component | Description |
|
|
12
|
+
| --------- | ----------------------------------------------------------------------------------------------------------------------------- |
|
|
13
|
+
| `Button` | 4 variants, 3 sizes, loading state, leading/trailing icons |
|
|
14
|
+
| `NavBar` | 2 themes (light/dark), scroll-triggered background effect, configurable links, CTA button, responsive mobile menu with toggle |
|
|
15
|
+
|
|
16
|
+
## Getting Started
|
|
17
|
+
|
|
18
|
+
### Prerequisites
|
|
19
|
+
|
|
20
|
+
- Node.js 18+
|
|
21
|
+
- npm / pnpm
|
|
22
|
+
|
|
23
|
+
### Run Storybook locally
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
git clone git@github.com:FarihaTang/react-component-library.git
|
|
27
|
+
cd react-component-library
|
|
28
|
+
npm install
|
|
29
|
+
npm run dev # opens Storybook at http://localhost:6006
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### Use in a project
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
npm install @farihatang/react-ui
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
```tsx
|
|
39
|
+
import { Button } from '@farihatang/react-ui';
|
|
40
|
+
// Import Tailwind styles in your app root
|
|
41
|
+
import '@farihatang/react-ui/dist/styles.css';
|
|
42
|
+
|
|
43
|
+
export function PaymentButton() {
|
|
44
|
+
return (
|
|
45
|
+
<Button variant="primary" size="lg">
|
|
46
|
+
To Pay
|
|
47
|
+
</Button>
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Project Structure
|
|
53
|
+
|
|
54
|
+
```
|
|
55
|
+
src/
|
|
56
|
+
โโโ components/
|
|
57
|
+
โ โโโ Button/
|
|
58
|
+
โ โ โโโ Button.tsx
|
|
59
|
+
โ โ โโโ Button.stories.tsx
|
|
60
|
+
โ โโโ NavBar/
|
|
61
|
+
โ โ โโโ NavBar.tsx
|
|
62
|
+
โ โ โโโ NavBar.stories.tsx
|
|
63
|
+
โโโ lib/
|
|
64
|
+
โ โโโ cn.ts
|
|
65
|
+
โโโ styles/
|
|
66
|
+
โ โโโ globals.css
|
|
67
|
+
โโโ index.ts โ public API
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Scripts
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
npm run dev # Storybook dev server (port 6006)
|
|
74
|
+
npm run build # Build library (CJS + ESM + .d.ts)
|
|
75
|
+
npm run build-storybook # Static Storybook for deployment
|
|
76
|
+
npm run type-check # TypeScript strict check
|
|
77
|
+
npm run lint # ESLint
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Author
|
|
81
|
+
|
|
82
|
+
**FarihaTang** โ [yourwebsite.com](https://yourwebsite.com) ยท [LinkedIn](https://www.linkedin.com/in/farihatang) ยท [GitHub](https://github.com/FarihaTang)
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
3
|
+
import { ClassValue } from 'clsx';
|
|
4
|
+
|
|
5
|
+
type ButtonVariant = 'primary' | 'secondary' | 'ghost' | 'danger';
|
|
6
|
+
type ButtonSize = 'sm' | 'md' | 'lg';
|
|
7
|
+
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
|
8
|
+
/** Visual style variant */
|
|
9
|
+
variant?: ButtonVariant;
|
|
10
|
+
/** Size preset */
|
|
11
|
+
size?: ButtonSize;
|
|
12
|
+
/** Show loading spinner and disable interaction */
|
|
13
|
+
loading?: boolean;
|
|
14
|
+
/** Icon rendered before label */
|
|
15
|
+
leadingIcon?: React.ReactNode;
|
|
16
|
+
/** Icon rendered after label */
|
|
17
|
+
trailingIcon?: React.ReactNode;
|
|
18
|
+
/** Stretch to fill container width */
|
|
19
|
+
fullWidth?: boolean;
|
|
20
|
+
}
|
|
21
|
+
declare const Button: React.ForwardRefExoticComponent<ButtonProps & React.RefAttributes<HTMLButtonElement>>;
|
|
22
|
+
|
|
23
|
+
interface NavLink {
|
|
24
|
+
label: string;
|
|
25
|
+
href: string;
|
|
26
|
+
}
|
|
27
|
+
interface NavBarProps {
|
|
28
|
+
/** Visual theme. "dark" = glass/blur on dark bg. "light" = white/shadow on light bg. */
|
|
29
|
+
theme?: 'dark' | 'light';
|
|
30
|
+
/** Logo text displayed on the left. */
|
|
31
|
+
logo?: string;
|
|
32
|
+
/** Accent character appended to the logo (e.g. "."). */
|
|
33
|
+
logoAccent?: string;
|
|
34
|
+
/** Navigation links rendered in the centre. */
|
|
35
|
+
links?: NavLink[];
|
|
36
|
+
/** Label for the CTA button on the right. */
|
|
37
|
+
ctaLabel?: string;
|
|
38
|
+
/** href for the CTA button. */
|
|
39
|
+
ctaHref?: string;
|
|
40
|
+
/** Whether the nav background changes on scroll. */
|
|
41
|
+
scrollEffect?: boolean;
|
|
42
|
+
/** Scroll threshold in px before the effect triggers. Default 50. */
|
|
43
|
+
scrollThreshold?: number;
|
|
44
|
+
}
|
|
45
|
+
declare function NavBar({ theme, logo, logoAccent, links, ctaLabel, ctaHref, scrollEffect, scrollThreshold, }: NavBarProps): react_jsx_runtime.JSX.Element;
|
|
46
|
+
|
|
47
|
+
declare function cn(...inputs: ClassValue[]): string;
|
|
48
|
+
|
|
49
|
+
export { Button, type ButtonProps, type ButtonSize, type ButtonVariant, NavBar, type NavBarProps, type NavLink, cn };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
3
|
+
import { ClassValue } from 'clsx';
|
|
4
|
+
|
|
5
|
+
type ButtonVariant = 'primary' | 'secondary' | 'ghost' | 'danger';
|
|
6
|
+
type ButtonSize = 'sm' | 'md' | 'lg';
|
|
7
|
+
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
|
8
|
+
/** Visual style variant */
|
|
9
|
+
variant?: ButtonVariant;
|
|
10
|
+
/** Size preset */
|
|
11
|
+
size?: ButtonSize;
|
|
12
|
+
/** Show loading spinner and disable interaction */
|
|
13
|
+
loading?: boolean;
|
|
14
|
+
/** Icon rendered before label */
|
|
15
|
+
leadingIcon?: React.ReactNode;
|
|
16
|
+
/** Icon rendered after label */
|
|
17
|
+
trailingIcon?: React.ReactNode;
|
|
18
|
+
/** Stretch to fill container width */
|
|
19
|
+
fullWidth?: boolean;
|
|
20
|
+
}
|
|
21
|
+
declare const Button: React.ForwardRefExoticComponent<ButtonProps & React.RefAttributes<HTMLButtonElement>>;
|
|
22
|
+
|
|
23
|
+
interface NavLink {
|
|
24
|
+
label: string;
|
|
25
|
+
href: string;
|
|
26
|
+
}
|
|
27
|
+
interface NavBarProps {
|
|
28
|
+
/** Visual theme. "dark" = glass/blur on dark bg. "light" = white/shadow on light bg. */
|
|
29
|
+
theme?: 'dark' | 'light';
|
|
30
|
+
/** Logo text displayed on the left. */
|
|
31
|
+
logo?: string;
|
|
32
|
+
/** Accent character appended to the logo (e.g. "."). */
|
|
33
|
+
logoAccent?: string;
|
|
34
|
+
/** Navigation links rendered in the centre. */
|
|
35
|
+
links?: NavLink[];
|
|
36
|
+
/** Label for the CTA button on the right. */
|
|
37
|
+
ctaLabel?: string;
|
|
38
|
+
/** href for the CTA button. */
|
|
39
|
+
ctaHref?: string;
|
|
40
|
+
/** Whether the nav background changes on scroll. */
|
|
41
|
+
scrollEffect?: boolean;
|
|
42
|
+
/** Scroll threshold in px before the effect triggers. Default 50. */
|
|
43
|
+
scrollThreshold?: number;
|
|
44
|
+
}
|
|
45
|
+
declare function NavBar({ theme, logo, logoAccent, links, ctaLabel, ctaHref, scrollEffect, scrollThreshold, }: NavBarProps): react_jsx_runtime.JSX.Element;
|
|
46
|
+
|
|
47
|
+
declare function cn(...inputs: ClassValue[]): string;
|
|
48
|
+
|
|
49
|
+
export { Button, type ButtonProps, type ButtonSize, type ButtonVariant, NavBar, type NavBarProps, type NavLink, cn };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var React = require('react');
|
|
4
|
+
var clsx = require('clsx');
|
|
5
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
6
|
+
|
|
7
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
8
|
+
|
|
9
|
+
var React__default = /*#__PURE__*/_interopDefault(React);
|
|
10
|
+
|
|
11
|
+
var __defProp = Object.defineProperty;
|
|
12
|
+
var __defProps = Object.defineProperties;
|
|
13
|
+
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
14
|
+
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
15
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
16
|
+
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
17
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
18
|
+
var __spreadValues = (a, b) => {
|
|
19
|
+
for (var prop in b || (b = {}))
|
|
20
|
+
if (__hasOwnProp.call(b, prop))
|
|
21
|
+
__defNormalProp(a, prop, b[prop]);
|
|
22
|
+
if (__getOwnPropSymbols)
|
|
23
|
+
for (var prop of __getOwnPropSymbols(b)) {
|
|
24
|
+
if (__propIsEnum.call(b, prop))
|
|
25
|
+
__defNormalProp(a, prop, b[prop]);
|
|
26
|
+
}
|
|
27
|
+
return a;
|
|
28
|
+
};
|
|
29
|
+
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
30
|
+
var __objRest = (source, exclude) => {
|
|
31
|
+
var target = {};
|
|
32
|
+
for (var prop in source)
|
|
33
|
+
if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
|
|
34
|
+
target[prop] = source[prop];
|
|
35
|
+
if (source != null && __getOwnPropSymbols)
|
|
36
|
+
for (var prop of __getOwnPropSymbols(source)) {
|
|
37
|
+
if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
|
|
38
|
+
target[prop] = source[prop];
|
|
39
|
+
}
|
|
40
|
+
return target;
|
|
41
|
+
};
|
|
42
|
+
function cn(...inputs) {
|
|
43
|
+
return clsx.clsx(inputs);
|
|
44
|
+
}
|
|
45
|
+
var variantStyles = {
|
|
46
|
+
primary: "bg-brand text-white hover:bg-brand-600 active:bg-brand-700 shadow-sm",
|
|
47
|
+
secondary: "bg-surface-2 text-ink border border-surface-3 hover:bg-surface-3 active:bg-surface-3",
|
|
48
|
+
ghost: "bg-transparent text-ink-secondary hover:bg-surface-2 active:bg-surface-3",
|
|
49
|
+
danger: "bg-danger text-white hover:bg-red-600 active:bg-red-700 shadow-sm"
|
|
50
|
+
};
|
|
51
|
+
var sizeStyles = {
|
|
52
|
+
sm: "h-8 px-3 text-xs gap-1.5 rounded",
|
|
53
|
+
md: "h-9 px-4 text-sm gap-2 rounded-md",
|
|
54
|
+
lg: "h-11 px-6 text-sm gap-2.5 rounded-lg"
|
|
55
|
+
};
|
|
56
|
+
function Spinner({ className }) {
|
|
57
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
58
|
+
"svg",
|
|
59
|
+
{
|
|
60
|
+
className: cn("animate-spin", className),
|
|
61
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
62
|
+
fill: "none",
|
|
63
|
+
viewBox: "0 0 24 24",
|
|
64
|
+
"aria-hidden": "true",
|
|
65
|
+
children: [
|
|
66
|
+
/* @__PURE__ */ jsxRuntime.jsx("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }),
|
|
67
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
68
|
+
"path",
|
|
69
|
+
{
|
|
70
|
+
className: "opacity-75",
|
|
71
|
+
fill: "currentColor",
|
|
72
|
+
d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"
|
|
73
|
+
}
|
|
74
|
+
)
|
|
75
|
+
]
|
|
76
|
+
}
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
var Button = React__default.default.forwardRef(
|
|
80
|
+
(_a, ref) => {
|
|
81
|
+
var _b = _a, {
|
|
82
|
+
variant = "primary",
|
|
83
|
+
size = "md",
|
|
84
|
+
loading = false,
|
|
85
|
+
leadingIcon,
|
|
86
|
+
trailingIcon,
|
|
87
|
+
fullWidth = false,
|
|
88
|
+
disabled,
|
|
89
|
+
children,
|
|
90
|
+
className
|
|
91
|
+
} = _b, props = __objRest(_b, [
|
|
92
|
+
"variant",
|
|
93
|
+
"size",
|
|
94
|
+
"loading",
|
|
95
|
+
"leadingIcon",
|
|
96
|
+
"trailingIcon",
|
|
97
|
+
"fullWidth",
|
|
98
|
+
"disabled",
|
|
99
|
+
"children",
|
|
100
|
+
"className"
|
|
101
|
+
]);
|
|
102
|
+
const isDisabled = disabled || loading;
|
|
103
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
104
|
+
"button",
|
|
105
|
+
__spreadProps(__spreadValues({
|
|
106
|
+
ref,
|
|
107
|
+
disabled: isDisabled,
|
|
108
|
+
"aria-busy": loading,
|
|
109
|
+
className: cn(
|
|
110
|
+
"inline-flex items-center justify-center font-sans font-medium",
|
|
111
|
+
"transition-all duration-150 ease-in-out",
|
|
112
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand focus-visible:ring-offset-1",
|
|
113
|
+
"disabled:opacity-50 disabled:pointer-events-none",
|
|
114
|
+
"select-none whitespace-nowrap",
|
|
115
|
+
variantStyles[variant],
|
|
116
|
+
sizeStyles[size],
|
|
117
|
+
fullWidth && "w-full",
|
|
118
|
+
className
|
|
119
|
+
)
|
|
120
|
+
}, props), {
|
|
121
|
+
children: [
|
|
122
|
+
loading ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
123
|
+
Spinner,
|
|
124
|
+
{
|
|
125
|
+
className: cn(size === "sm" ? "h-3 w-3" : size === "lg" ? "h-4 w-4" : "h-3.5 w-3.5")
|
|
126
|
+
}
|
|
127
|
+
) : leadingIcon && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0", "aria-hidden": "true", children: leadingIcon }),
|
|
128
|
+
children && /* @__PURE__ */ jsxRuntime.jsx("span", { children }),
|
|
129
|
+
!loading && trailingIcon && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0", "aria-hidden": "true", children: trailingIcon })
|
|
130
|
+
]
|
|
131
|
+
})
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
);
|
|
135
|
+
Button.displayName = "Button";
|
|
136
|
+
var DEFAULT_LINKS = [
|
|
137
|
+
{ label: "About", href: "#about" },
|
|
138
|
+
{ label: "Experience", href: "#experience" },
|
|
139
|
+
{ label: "Projects", href: "#projects" },
|
|
140
|
+
{ label: "Contact", href: "#contact" }
|
|
141
|
+
];
|
|
142
|
+
var tokens = {
|
|
143
|
+
dark: {
|
|
144
|
+
nav: {
|
|
145
|
+
base: "bg-transparent",
|
|
146
|
+
scrolled: "bg-[#060912]/80 backdrop-blur-md border-b border-white/5"
|
|
147
|
+
},
|
|
148
|
+
logo: "text-[#6366f1]",
|
|
149
|
+
logoAccent: "text-white/20",
|
|
150
|
+
link: "text-[#64748b] hover:text-[#e2e8f0]",
|
|
151
|
+
cta: "bg-[#6366f1]/10 border border-[#6366f1]/30 text-[#6366f1] hover:bg-[#6366f1] hover:text-white hover:border-[#6366f1]",
|
|
152
|
+
menuToggle: "text-[#64748b] hover:text-[#e2e8f0]",
|
|
153
|
+
mobileMenu: "bg-[#060912]/95 backdrop-blur-md border-t border-white/5",
|
|
154
|
+
mobileLink: "text-[#64748b] hover:text-[#e2e8f0]",
|
|
155
|
+
mobileCta: "bg-[#6366f1]/10 border border-[#6366f1]/30 text-[#6366f1]"
|
|
156
|
+
},
|
|
157
|
+
light: {
|
|
158
|
+
nav: {
|
|
159
|
+
base: "bg-transparent",
|
|
160
|
+
scrolled: "bg-[#f8f7f4]/90 backdrop-blur-md shadow-sm"
|
|
161
|
+
},
|
|
162
|
+
logo: "text-[#0f0f0f]",
|
|
163
|
+
logoAccent: "text-[#5b50f0]",
|
|
164
|
+
link: "text-[#6b7280] hover:bg-black/5 hover:text-[#0f0f0f]",
|
|
165
|
+
cta: "[background:linear-gradient(135deg,#5b50f0,#7c3aed)] text-white shadow-lg shadow-[#5b50f0]/25 hover:shadow-[#5b50f0]/40 hover:scale-[1.03]",
|
|
166
|
+
menuToggle: "text-[#6b7280] hover:text-[#0f0f0f]",
|
|
167
|
+
mobileMenu: "bg-[#f8f7f4]/95 backdrop-blur-md border-t border-black/5",
|
|
168
|
+
mobileLink: "text-[#6b7280] hover:text-[#0f0f0f]",
|
|
169
|
+
mobileCta: "[background:linear-gradient(135deg,#5b50f0,#7c3aed)] text-white"
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
function NavBar({
|
|
173
|
+
theme = "light",
|
|
174
|
+
logo = "Fariha",
|
|
175
|
+
logoAccent = ".",
|
|
176
|
+
links = DEFAULT_LINKS,
|
|
177
|
+
ctaLabel = "Hire me",
|
|
178
|
+
ctaHref = "#contact",
|
|
179
|
+
scrollEffect = true,
|
|
180
|
+
scrollThreshold = 50
|
|
181
|
+
}) {
|
|
182
|
+
const [scrolled, setScrolled] = React.useState(false);
|
|
183
|
+
const [menuOpen, setMenuOpen] = React.useState(false);
|
|
184
|
+
const t = tokens[theme];
|
|
185
|
+
React.useEffect(() => {
|
|
186
|
+
if (!scrollEffect) return;
|
|
187
|
+
const handler = () => setScrolled(window.scrollY > scrollThreshold);
|
|
188
|
+
window.addEventListener("scroll", handler, { passive: true });
|
|
189
|
+
return () => window.removeEventListener("scroll", handler);
|
|
190
|
+
}, [scrollEffect, scrollThreshold]);
|
|
191
|
+
const navPy = scrolled ? "py-3" : "py-5";
|
|
192
|
+
const navBg = scrolled ? t.nav.scrolled : t.nav.base;
|
|
193
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
194
|
+
"nav",
|
|
195
|
+
{
|
|
196
|
+
role: "navigation",
|
|
197
|
+
"aria-label": "Main navigation",
|
|
198
|
+
className: `fixed top-0 inset-x-0 z-50 transition-all duration-500 ${navPy} ${navBg}`,
|
|
199
|
+
children: [
|
|
200
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "max-w-6xl mx-auto px-6 flex items-center justify-between", children: [
|
|
201
|
+
/* @__PURE__ */ jsxRuntime.jsxs("a", { href: "#", className: `font-sans font-extrabold text-lg tracking-tight ${t.logo}`, children: [
|
|
202
|
+
logo,
|
|
203
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: t.logoAccent, children: logoAccent })
|
|
204
|
+
] }),
|
|
205
|
+
/* @__PURE__ */ jsxRuntime.jsx("ul", { className: "hidden md:flex items-center gap-1", role: "list", children: links.map((link) => /* @__PURE__ */ jsxRuntime.jsx("li", { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
206
|
+
"a",
|
|
207
|
+
{
|
|
208
|
+
href: link.href,
|
|
209
|
+
className: `font-sans font-medium text-sm px-4 py-2 rounded-full transition-all duration-200 ${t.link}`,
|
|
210
|
+
children: link.label
|
|
211
|
+
}
|
|
212
|
+
) }, link.label)) }),
|
|
213
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
214
|
+
"a",
|
|
215
|
+
{
|
|
216
|
+
href: ctaHref,
|
|
217
|
+
className: `hidden md:inline-flex items-center px-5 py-2.5 rounded-full font-sans font-bold text-sm transition-all duration-200 ${t.cta}`,
|
|
218
|
+
children: ctaLabel
|
|
219
|
+
}
|
|
220
|
+
),
|
|
221
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
222
|
+
"button",
|
|
223
|
+
{
|
|
224
|
+
className: `md:hidden transition-colors ${t.menuToggle}`,
|
|
225
|
+
onClick: () => setMenuOpen((prev) => !prev),
|
|
226
|
+
"aria-expanded": menuOpen,
|
|
227
|
+
"aria-label": menuOpen ? "Close menu" : "Open menu",
|
|
228
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
229
|
+
"svg",
|
|
230
|
+
{
|
|
231
|
+
width: "22",
|
|
232
|
+
height: "22",
|
|
233
|
+
viewBox: "0 0 24 24",
|
|
234
|
+
fill: "none",
|
|
235
|
+
stroke: "currentColor",
|
|
236
|
+
strokeWidth: "2",
|
|
237
|
+
children: menuOpen ? /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M18 6L6 18M6 6l12 12" }) : /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M3 12h18M3 6h18M3 18h18" })
|
|
238
|
+
}
|
|
239
|
+
)
|
|
240
|
+
}
|
|
241
|
+
)
|
|
242
|
+
] }),
|
|
243
|
+
menuOpen && /* @__PURE__ */ jsxRuntime.jsx("div", { className: `md:hidden mt-3 ${t.mobileMenu}`, children: /* @__PURE__ */ jsxRuntime.jsxs("ul", { className: "max-w-6xl mx-auto px-6 py-5 flex flex-col gap-4", role: "list", children: [
|
|
244
|
+
links.map((link) => /* @__PURE__ */ jsxRuntime.jsx("li", { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
245
|
+
"a",
|
|
246
|
+
{
|
|
247
|
+
href: link.href,
|
|
248
|
+
onClick: () => setMenuOpen(false),
|
|
249
|
+
className: `font-sans font-medium text-base transition-colors ${t.mobileLink}`,
|
|
250
|
+
children: link.label
|
|
251
|
+
}
|
|
252
|
+
) }, link.label)),
|
|
253
|
+
/* @__PURE__ */ jsxRuntime.jsx("li", { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
254
|
+
"a",
|
|
255
|
+
{
|
|
256
|
+
href: ctaHref,
|
|
257
|
+
onClick: () => setMenuOpen(false),
|
|
258
|
+
className: `inline-block px-5 py-2.5 rounded-full font-sans font-bold text-sm ${t.mobileCta}`,
|
|
259
|
+
children: ctaLabel
|
|
260
|
+
}
|
|
261
|
+
) })
|
|
262
|
+
] }) })
|
|
263
|
+
]
|
|
264
|
+
}
|
|
265
|
+
);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
exports.Button = Button;
|
|
269
|
+
exports.NavBar = NavBar;
|
|
270
|
+
exports.cn = cn;
|
|
271
|
+
//# sourceMappingURL=index.js.map
|
|
272
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/cn.ts","../src/components/Button/Button.tsx","../src/components/NavBar/NavBar.tsx"],"names":["clsx","jsxs","jsx","React","useState","useEffect"],"mappings":"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","file":"index.js","sourcesContent":["import { clsx, type ClassValue } from \"clsx\";\n\nexport function cn(...inputs: ClassValue[]): string {\n return clsx(inputs);\n}\n","import React from 'react';\nimport { cn } from '@/lib/cn';\n\nexport type ButtonVariant = 'primary' | 'secondary' | 'ghost' | 'danger';\nexport type ButtonSize = 'sm' | 'md' | 'lg';\n\nexport interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n /** Visual style variant */\n variant?: ButtonVariant;\n /** Size preset */\n size?: ButtonSize;\n /** Show loading spinner and disable interaction */\n loading?: boolean;\n /** Icon rendered before label */\n leadingIcon?: React.ReactNode;\n /** Icon rendered after label */\n trailingIcon?: React.ReactNode;\n /** Stretch to fill container width */\n fullWidth?: boolean;\n}\n\nconst variantStyles: Record<ButtonVariant, string> = {\n primary: 'bg-brand text-white hover:bg-brand-600 active:bg-brand-700 shadow-sm',\n secondary: 'bg-surface-2 text-ink border border-surface-3 hover:bg-surface-3 active:bg-surface-3',\n ghost: 'bg-transparent text-ink-secondary hover:bg-surface-2 active:bg-surface-3',\n danger: 'bg-danger text-white hover:bg-red-600 active:bg-red-700 shadow-sm',\n};\n\nconst sizeStyles: Record<ButtonSize, string> = {\n sm: 'h-8 px-3 text-xs gap-1.5 rounded',\n md: 'h-9 px-4 text-sm gap-2 rounded-md',\n lg: 'h-11 px-6 text-sm gap-2.5 rounded-lg',\n};\n\nfunction Spinner({ className }: { className?: string }) {\n return (\n <svg\n className={cn('animate-spin', className)}\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n aria-hidden=\"true\"\n >\n <circle className=\"opacity-25\" cx=\"12\" cy=\"12\" r=\"10\" stroke=\"currentColor\" strokeWidth=\"4\" />\n <path\n className=\"opacity-75\"\n fill=\"currentColor\"\n d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z\"\n />\n </svg>\n );\n}\n\nexport const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(\n (\n {\n variant = 'primary',\n size = 'md',\n loading = false,\n leadingIcon,\n trailingIcon,\n fullWidth = false,\n disabled,\n children,\n className,\n ...props\n },\n ref\n ) => {\n const isDisabled = disabled || loading;\n\n return (\n <button\n ref={ref}\n disabled={isDisabled}\n aria-busy={loading}\n className={cn(\n 'inline-flex items-center justify-center font-sans font-medium',\n 'transition-all duration-150 ease-in-out',\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand focus-visible:ring-offset-1',\n 'disabled:opacity-50 disabled:pointer-events-none',\n 'select-none whitespace-nowrap',\n variantStyles[variant],\n sizeStyles[size],\n fullWidth && 'w-full',\n className\n )}\n {...props}\n >\n {loading ? (\n <Spinner\n className={cn(size === 'sm' ? 'h-3 w-3' : size === 'lg' ? 'h-4 w-4' : 'h-3.5 w-3.5')}\n />\n ) : (\n leadingIcon && (\n <span className=\"shrink-0\" aria-hidden=\"true\">\n {leadingIcon}\n </span>\n )\n )}\n {children && <span>{children}</span>}\n {!loading && trailingIcon && (\n <span className=\"shrink-0\" aria-hidden=\"true\">\n {trailingIcon}\n </span>\n )}\n </button>\n );\n }\n);\n\nButton.displayName = 'Button';\n","'use client';\n\nimport { useState, useEffect } from 'react';\n\n// โโโ Types โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n\nexport interface NavLink {\n label: string;\n href: string;\n}\n\nexport interface NavBarProps {\n /** Visual theme. \"dark\" = glass/blur on dark bg. \"light\" = white/shadow on light bg. */\n theme?: 'dark' | 'light';\n /** Logo text displayed on the left. */\n logo?: string;\n /** Accent character appended to the logo (e.g. \".\"). */\n logoAccent?: string;\n /** Navigation links rendered in the centre. */\n links?: NavLink[];\n /** Label for the CTA button on the right. */\n ctaLabel?: string;\n /** href for the CTA button. */\n ctaHref?: string;\n /** Whether the nav background changes on scroll. */\n scrollEffect?: boolean;\n /** Scroll threshold in px before the effect triggers. Default 50. */\n scrollThreshold?: number;\n}\n\n// โโโ Constants โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n\nconst DEFAULT_LINKS: NavLink[] = [\n { label: 'About', href: '#about' },\n { label: 'Experience', href: '#experience' },\n { label: 'Projects', href: '#projects' },\n { label: 'Contact', href: '#contact' },\n];\n\n// โโโ Theme tokens โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n\nconst tokens = {\n dark: {\n nav: {\n base: 'bg-transparent',\n scrolled: 'bg-[#060912]/80 backdrop-blur-md border-b border-white/5',\n },\n logo: 'text-[#6366f1]',\n logoAccent: 'text-white/20',\n link: 'text-[#64748b] hover:text-[#e2e8f0]',\n cta: 'bg-[#6366f1]/10 border border-[#6366f1]/30 text-[#6366f1] hover:bg-[#6366f1] hover:text-white hover:border-[#6366f1]',\n menuToggle: 'text-[#64748b] hover:text-[#e2e8f0]',\n mobileMenu: 'bg-[#060912]/95 backdrop-blur-md border-t border-white/5',\n mobileLink: 'text-[#64748b] hover:text-[#e2e8f0]',\n mobileCta: 'bg-[#6366f1]/10 border border-[#6366f1]/30 text-[#6366f1]',\n },\n light: {\n nav: {\n base: 'bg-transparent',\n scrolled: 'bg-[#f8f7f4]/90 backdrop-blur-md shadow-sm',\n },\n logo: 'text-[#0f0f0f]',\n logoAccent: 'text-[#5b50f0]',\n link: 'text-[#6b7280] hover:bg-black/5 hover:text-[#0f0f0f]',\n cta: '[background:linear-gradient(135deg,#5b50f0,#7c3aed)] text-white shadow-lg shadow-[#5b50f0]/25 hover:shadow-[#5b50f0]/40 hover:scale-[1.03]',\n menuToggle: 'text-[#6b7280] hover:text-[#0f0f0f]',\n mobileMenu: 'bg-[#f8f7f4]/95 backdrop-blur-md border-t border-black/5',\n mobileLink: 'text-[#6b7280] hover:text-[#0f0f0f]',\n mobileCta: '[background:linear-gradient(135deg,#5b50f0,#7c3aed)] text-white',\n },\n} as const;\n\n// โโโ Component โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n\nexport function NavBar({\n theme = 'light',\n logo = 'Fariha',\n logoAccent = '.',\n links = DEFAULT_LINKS,\n ctaLabel = 'Hire me',\n ctaHref = '#contact',\n scrollEffect = true,\n scrollThreshold = 50,\n}: NavBarProps) {\n const [scrolled, setScrolled] = useState(false);\n const [menuOpen, setMenuOpen] = useState(false);\n const t = tokens[theme];\n\n useEffect(() => {\n if (!scrollEffect) return;\n const handler = () => setScrolled(window.scrollY > scrollThreshold);\n window.addEventListener('scroll', handler, { passive: true });\n return () => window.removeEventListener('scroll', handler);\n }, [scrollEffect, scrollThreshold]);\n\n const navPy = scrolled ? 'py-3' : 'py-5';\n const navBg = scrolled ? t.nav.scrolled : t.nav.base;\n\n return (\n <nav\n role=\"navigation\"\n aria-label=\"Main navigation\"\n className={`fixed top-0 inset-x-0 z-50 transition-all duration-500 ${navPy} ${navBg}`}\n >\n <div className=\"max-w-6xl mx-auto px-6 flex items-center justify-between\">\n {/* Logo */}\n <a href=\"#\" className={`font-sans font-extrabold text-lg tracking-tight ${t.logo}`}>\n {logo}\n <span className={t.logoAccent}>{logoAccent}</span>\n </a>\n\n {/* Desktop links */}\n <ul className=\"hidden md:flex items-center gap-1\" role=\"list\">\n {links.map(link => (\n <li key={link.label}>\n <a\n href={link.href}\n className={`font-sans font-medium text-sm px-4 py-2 rounded-full transition-all duration-200 ${t.link}`}\n >\n {link.label}\n </a>\n </li>\n ))}\n </ul>\n\n {/* Desktop CTA */}\n <a\n href={ctaHref}\n className={`hidden md:inline-flex items-center px-5 py-2.5 rounded-full font-sans font-bold text-sm transition-all duration-200 ${t.cta}`}\n >\n {ctaLabel}\n </a>\n\n {/* Mobile toggle */}\n <button\n className={`md:hidden transition-colors ${t.menuToggle}`}\n onClick={() => setMenuOpen(prev => !prev)}\n aria-expanded={menuOpen}\n aria-label={menuOpen ? 'Close menu' : 'Open menu'}\n >\n <svg\n width=\"22\"\n height=\"22\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n >\n {menuOpen ? <path d=\"M18 6L6 18M6 6l12 12\" /> : <path d=\"M3 12h18M3 6h18M3 18h18\" />}\n </svg>\n </button>\n </div>\n\n {/* Mobile menu */}\n {menuOpen && (\n <div className={`md:hidden mt-3 ${t.mobileMenu}`}>\n <ul className=\"max-w-6xl mx-auto px-6 py-5 flex flex-col gap-4\" role=\"list\">\n {links.map(link => (\n <li key={link.label}>\n <a\n href={link.href}\n onClick={() => setMenuOpen(false)}\n className={`font-sans font-medium text-base transition-colors ${t.mobileLink}`}\n >\n {link.label}\n </a>\n </li>\n ))}\n <li>\n <a\n href={ctaHref}\n onClick={() => setMenuOpen(false)}\n className={`inline-block px-5 py-2.5 rounded-full font-sans font-bold text-sm ${t.mobileCta}`}\n >\n {ctaLabel}\n </a>\n </li>\n </ul>\n </div>\n )}\n </nav>\n );\n}\n\nexport default NavBar;\n"]}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
import React, { useState, useEffect } from 'react';
|
|
2
|
+
import { clsx } from 'clsx';
|
|
3
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
4
|
+
|
|
5
|
+
var __defProp = Object.defineProperty;
|
|
6
|
+
var __defProps = Object.defineProperties;
|
|
7
|
+
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
8
|
+
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
9
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
10
|
+
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
11
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
12
|
+
var __spreadValues = (a, b) => {
|
|
13
|
+
for (var prop in b || (b = {}))
|
|
14
|
+
if (__hasOwnProp.call(b, prop))
|
|
15
|
+
__defNormalProp(a, prop, b[prop]);
|
|
16
|
+
if (__getOwnPropSymbols)
|
|
17
|
+
for (var prop of __getOwnPropSymbols(b)) {
|
|
18
|
+
if (__propIsEnum.call(b, prop))
|
|
19
|
+
__defNormalProp(a, prop, b[prop]);
|
|
20
|
+
}
|
|
21
|
+
return a;
|
|
22
|
+
};
|
|
23
|
+
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
24
|
+
var __objRest = (source, exclude) => {
|
|
25
|
+
var target = {};
|
|
26
|
+
for (var prop in source)
|
|
27
|
+
if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
|
|
28
|
+
target[prop] = source[prop];
|
|
29
|
+
if (source != null && __getOwnPropSymbols)
|
|
30
|
+
for (var prop of __getOwnPropSymbols(source)) {
|
|
31
|
+
if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
|
|
32
|
+
target[prop] = source[prop];
|
|
33
|
+
}
|
|
34
|
+
return target;
|
|
35
|
+
};
|
|
36
|
+
function cn(...inputs) {
|
|
37
|
+
return clsx(inputs);
|
|
38
|
+
}
|
|
39
|
+
var variantStyles = {
|
|
40
|
+
primary: "bg-brand text-white hover:bg-brand-600 active:bg-brand-700 shadow-sm",
|
|
41
|
+
secondary: "bg-surface-2 text-ink border border-surface-3 hover:bg-surface-3 active:bg-surface-3",
|
|
42
|
+
ghost: "bg-transparent text-ink-secondary hover:bg-surface-2 active:bg-surface-3",
|
|
43
|
+
danger: "bg-danger text-white hover:bg-red-600 active:bg-red-700 shadow-sm"
|
|
44
|
+
};
|
|
45
|
+
var sizeStyles = {
|
|
46
|
+
sm: "h-8 px-3 text-xs gap-1.5 rounded",
|
|
47
|
+
md: "h-9 px-4 text-sm gap-2 rounded-md",
|
|
48
|
+
lg: "h-11 px-6 text-sm gap-2.5 rounded-lg"
|
|
49
|
+
};
|
|
50
|
+
function Spinner({ className }) {
|
|
51
|
+
return /* @__PURE__ */ jsxs(
|
|
52
|
+
"svg",
|
|
53
|
+
{
|
|
54
|
+
className: cn("animate-spin", className),
|
|
55
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
56
|
+
fill: "none",
|
|
57
|
+
viewBox: "0 0 24 24",
|
|
58
|
+
"aria-hidden": "true",
|
|
59
|
+
children: [
|
|
60
|
+
/* @__PURE__ */ jsx("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }),
|
|
61
|
+
/* @__PURE__ */ jsx(
|
|
62
|
+
"path",
|
|
63
|
+
{
|
|
64
|
+
className: "opacity-75",
|
|
65
|
+
fill: "currentColor",
|
|
66
|
+
d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"
|
|
67
|
+
}
|
|
68
|
+
)
|
|
69
|
+
]
|
|
70
|
+
}
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
var Button = React.forwardRef(
|
|
74
|
+
(_a, ref) => {
|
|
75
|
+
var _b = _a, {
|
|
76
|
+
variant = "primary",
|
|
77
|
+
size = "md",
|
|
78
|
+
loading = false,
|
|
79
|
+
leadingIcon,
|
|
80
|
+
trailingIcon,
|
|
81
|
+
fullWidth = false,
|
|
82
|
+
disabled,
|
|
83
|
+
children,
|
|
84
|
+
className
|
|
85
|
+
} = _b, props = __objRest(_b, [
|
|
86
|
+
"variant",
|
|
87
|
+
"size",
|
|
88
|
+
"loading",
|
|
89
|
+
"leadingIcon",
|
|
90
|
+
"trailingIcon",
|
|
91
|
+
"fullWidth",
|
|
92
|
+
"disabled",
|
|
93
|
+
"children",
|
|
94
|
+
"className"
|
|
95
|
+
]);
|
|
96
|
+
const isDisabled = disabled || loading;
|
|
97
|
+
return /* @__PURE__ */ jsxs(
|
|
98
|
+
"button",
|
|
99
|
+
__spreadProps(__spreadValues({
|
|
100
|
+
ref,
|
|
101
|
+
disabled: isDisabled,
|
|
102
|
+
"aria-busy": loading,
|
|
103
|
+
className: cn(
|
|
104
|
+
"inline-flex items-center justify-center font-sans font-medium",
|
|
105
|
+
"transition-all duration-150 ease-in-out",
|
|
106
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand focus-visible:ring-offset-1",
|
|
107
|
+
"disabled:opacity-50 disabled:pointer-events-none",
|
|
108
|
+
"select-none whitespace-nowrap",
|
|
109
|
+
variantStyles[variant],
|
|
110
|
+
sizeStyles[size],
|
|
111
|
+
fullWidth && "w-full",
|
|
112
|
+
className
|
|
113
|
+
)
|
|
114
|
+
}, props), {
|
|
115
|
+
children: [
|
|
116
|
+
loading ? /* @__PURE__ */ jsx(
|
|
117
|
+
Spinner,
|
|
118
|
+
{
|
|
119
|
+
className: cn(size === "sm" ? "h-3 w-3" : size === "lg" ? "h-4 w-4" : "h-3.5 w-3.5")
|
|
120
|
+
}
|
|
121
|
+
) : leadingIcon && /* @__PURE__ */ jsx("span", { className: "shrink-0", "aria-hidden": "true", children: leadingIcon }),
|
|
122
|
+
children && /* @__PURE__ */ jsx("span", { children }),
|
|
123
|
+
!loading && trailingIcon && /* @__PURE__ */ jsx("span", { className: "shrink-0", "aria-hidden": "true", children: trailingIcon })
|
|
124
|
+
]
|
|
125
|
+
})
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
);
|
|
129
|
+
Button.displayName = "Button";
|
|
130
|
+
var DEFAULT_LINKS = [
|
|
131
|
+
{ label: "About", href: "#about" },
|
|
132
|
+
{ label: "Experience", href: "#experience" },
|
|
133
|
+
{ label: "Projects", href: "#projects" },
|
|
134
|
+
{ label: "Contact", href: "#contact" }
|
|
135
|
+
];
|
|
136
|
+
var tokens = {
|
|
137
|
+
dark: {
|
|
138
|
+
nav: {
|
|
139
|
+
base: "bg-transparent",
|
|
140
|
+
scrolled: "bg-[#060912]/80 backdrop-blur-md border-b border-white/5"
|
|
141
|
+
},
|
|
142
|
+
logo: "text-[#6366f1]",
|
|
143
|
+
logoAccent: "text-white/20",
|
|
144
|
+
link: "text-[#64748b] hover:text-[#e2e8f0]",
|
|
145
|
+
cta: "bg-[#6366f1]/10 border border-[#6366f1]/30 text-[#6366f1] hover:bg-[#6366f1] hover:text-white hover:border-[#6366f1]",
|
|
146
|
+
menuToggle: "text-[#64748b] hover:text-[#e2e8f0]",
|
|
147
|
+
mobileMenu: "bg-[#060912]/95 backdrop-blur-md border-t border-white/5",
|
|
148
|
+
mobileLink: "text-[#64748b] hover:text-[#e2e8f0]",
|
|
149
|
+
mobileCta: "bg-[#6366f1]/10 border border-[#6366f1]/30 text-[#6366f1]"
|
|
150
|
+
},
|
|
151
|
+
light: {
|
|
152
|
+
nav: {
|
|
153
|
+
base: "bg-transparent",
|
|
154
|
+
scrolled: "bg-[#f8f7f4]/90 backdrop-blur-md shadow-sm"
|
|
155
|
+
},
|
|
156
|
+
logo: "text-[#0f0f0f]",
|
|
157
|
+
logoAccent: "text-[#5b50f0]",
|
|
158
|
+
link: "text-[#6b7280] hover:bg-black/5 hover:text-[#0f0f0f]",
|
|
159
|
+
cta: "[background:linear-gradient(135deg,#5b50f0,#7c3aed)] text-white shadow-lg shadow-[#5b50f0]/25 hover:shadow-[#5b50f0]/40 hover:scale-[1.03]",
|
|
160
|
+
menuToggle: "text-[#6b7280] hover:text-[#0f0f0f]",
|
|
161
|
+
mobileMenu: "bg-[#f8f7f4]/95 backdrop-blur-md border-t border-black/5",
|
|
162
|
+
mobileLink: "text-[#6b7280] hover:text-[#0f0f0f]",
|
|
163
|
+
mobileCta: "[background:linear-gradient(135deg,#5b50f0,#7c3aed)] text-white"
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
function NavBar({
|
|
167
|
+
theme = "light",
|
|
168
|
+
logo = "Fariha",
|
|
169
|
+
logoAccent = ".",
|
|
170
|
+
links = DEFAULT_LINKS,
|
|
171
|
+
ctaLabel = "Hire me",
|
|
172
|
+
ctaHref = "#contact",
|
|
173
|
+
scrollEffect = true,
|
|
174
|
+
scrollThreshold = 50
|
|
175
|
+
}) {
|
|
176
|
+
const [scrolled, setScrolled] = useState(false);
|
|
177
|
+
const [menuOpen, setMenuOpen] = useState(false);
|
|
178
|
+
const t = tokens[theme];
|
|
179
|
+
useEffect(() => {
|
|
180
|
+
if (!scrollEffect) return;
|
|
181
|
+
const handler = () => setScrolled(window.scrollY > scrollThreshold);
|
|
182
|
+
window.addEventListener("scroll", handler, { passive: true });
|
|
183
|
+
return () => window.removeEventListener("scroll", handler);
|
|
184
|
+
}, [scrollEffect, scrollThreshold]);
|
|
185
|
+
const navPy = scrolled ? "py-3" : "py-5";
|
|
186
|
+
const navBg = scrolled ? t.nav.scrolled : t.nav.base;
|
|
187
|
+
return /* @__PURE__ */ jsxs(
|
|
188
|
+
"nav",
|
|
189
|
+
{
|
|
190
|
+
role: "navigation",
|
|
191
|
+
"aria-label": "Main navigation",
|
|
192
|
+
className: `fixed top-0 inset-x-0 z-50 transition-all duration-500 ${navPy} ${navBg}`,
|
|
193
|
+
children: [
|
|
194
|
+
/* @__PURE__ */ jsxs("div", { className: "max-w-6xl mx-auto px-6 flex items-center justify-between", children: [
|
|
195
|
+
/* @__PURE__ */ jsxs("a", { href: "#", className: `font-sans font-extrabold text-lg tracking-tight ${t.logo}`, children: [
|
|
196
|
+
logo,
|
|
197
|
+
/* @__PURE__ */ jsx("span", { className: t.logoAccent, children: logoAccent })
|
|
198
|
+
] }),
|
|
199
|
+
/* @__PURE__ */ jsx("ul", { className: "hidden md:flex items-center gap-1", role: "list", children: links.map((link) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(
|
|
200
|
+
"a",
|
|
201
|
+
{
|
|
202
|
+
href: link.href,
|
|
203
|
+
className: `font-sans font-medium text-sm px-4 py-2 rounded-full transition-all duration-200 ${t.link}`,
|
|
204
|
+
children: link.label
|
|
205
|
+
}
|
|
206
|
+
) }, link.label)) }),
|
|
207
|
+
/* @__PURE__ */ jsx(
|
|
208
|
+
"a",
|
|
209
|
+
{
|
|
210
|
+
href: ctaHref,
|
|
211
|
+
className: `hidden md:inline-flex items-center px-5 py-2.5 rounded-full font-sans font-bold text-sm transition-all duration-200 ${t.cta}`,
|
|
212
|
+
children: ctaLabel
|
|
213
|
+
}
|
|
214
|
+
),
|
|
215
|
+
/* @__PURE__ */ jsx(
|
|
216
|
+
"button",
|
|
217
|
+
{
|
|
218
|
+
className: `md:hidden transition-colors ${t.menuToggle}`,
|
|
219
|
+
onClick: () => setMenuOpen((prev) => !prev),
|
|
220
|
+
"aria-expanded": menuOpen,
|
|
221
|
+
"aria-label": menuOpen ? "Close menu" : "Open menu",
|
|
222
|
+
children: /* @__PURE__ */ jsx(
|
|
223
|
+
"svg",
|
|
224
|
+
{
|
|
225
|
+
width: "22",
|
|
226
|
+
height: "22",
|
|
227
|
+
viewBox: "0 0 24 24",
|
|
228
|
+
fill: "none",
|
|
229
|
+
stroke: "currentColor",
|
|
230
|
+
strokeWidth: "2",
|
|
231
|
+
children: menuOpen ? /* @__PURE__ */ jsx("path", { d: "M18 6L6 18M6 6l12 12" }) : /* @__PURE__ */ jsx("path", { d: "M3 12h18M3 6h18M3 18h18" })
|
|
232
|
+
}
|
|
233
|
+
)
|
|
234
|
+
}
|
|
235
|
+
)
|
|
236
|
+
] }),
|
|
237
|
+
menuOpen && /* @__PURE__ */ jsx("div", { className: `md:hidden mt-3 ${t.mobileMenu}`, children: /* @__PURE__ */ jsxs("ul", { className: "max-w-6xl mx-auto px-6 py-5 flex flex-col gap-4", role: "list", children: [
|
|
238
|
+
links.map((link) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(
|
|
239
|
+
"a",
|
|
240
|
+
{
|
|
241
|
+
href: link.href,
|
|
242
|
+
onClick: () => setMenuOpen(false),
|
|
243
|
+
className: `font-sans font-medium text-base transition-colors ${t.mobileLink}`,
|
|
244
|
+
children: link.label
|
|
245
|
+
}
|
|
246
|
+
) }, link.label)),
|
|
247
|
+
/* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(
|
|
248
|
+
"a",
|
|
249
|
+
{
|
|
250
|
+
href: ctaHref,
|
|
251
|
+
onClick: () => setMenuOpen(false),
|
|
252
|
+
className: `inline-block px-5 py-2.5 rounded-full font-sans font-bold text-sm ${t.mobileCta}`,
|
|
253
|
+
children: ctaLabel
|
|
254
|
+
}
|
|
255
|
+
) })
|
|
256
|
+
] }) })
|
|
257
|
+
]
|
|
258
|
+
}
|
|
259
|
+
);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
export { Button, NavBar, cn };
|
|
263
|
+
//# sourceMappingURL=index.mjs.map
|
|
264
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/cn.ts","../src/components/Button/Button.tsx","../src/components/NavBar/NavBar.tsx"],"names":["jsxs","jsx"],"mappings":"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","file":"index.mjs","sourcesContent":["import { clsx, type ClassValue } from \"clsx\";\n\nexport function cn(...inputs: ClassValue[]): string {\n return clsx(inputs);\n}\n","import React from 'react';\nimport { cn } from '@/lib/cn';\n\nexport type ButtonVariant = 'primary' | 'secondary' | 'ghost' | 'danger';\nexport type ButtonSize = 'sm' | 'md' | 'lg';\n\nexport interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n /** Visual style variant */\n variant?: ButtonVariant;\n /** Size preset */\n size?: ButtonSize;\n /** Show loading spinner and disable interaction */\n loading?: boolean;\n /** Icon rendered before label */\n leadingIcon?: React.ReactNode;\n /** Icon rendered after label */\n trailingIcon?: React.ReactNode;\n /** Stretch to fill container width */\n fullWidth?: boolean;\n}\n\nconst variantStyles: Record<ButtonVariant, string> = {\n primary: 'bg-brand text-white hover:bg-brand-600 active:bg-brand-700 shadow-sm',\n secondary: 'bg-surface-2 text-ink border border-surface-3 hover:bg-surface-3 active:bg-surface-3',\n ghost: 'bg-transparent text-ink-secondary hover:bg-surface-2 active:bg-surface-3',\n danger: 'bg-danger text-white hover:bg-red-600 active:bg-red-700 shadow-sm',\n};\n\nconst sizeStyles: Record<ButtonSize, string> = {\n sm: 'h-8 px-3 text-xs gap-1.5 rounded',\n md: 'h-9 px-4 text-sm gap-2 rounded-md',\n lg: 'h-11 px-6 text-sm gap-2.5 rounded-lg',\n};\n\nfunction Spinner({ className }: { className?: string }) {\n return (\n <svg\n className={cn('animate-spin', className)}\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n aria-hidden=\"true\"\n >\n <circle className=\"opacity-25\" cx=\"12\" cy=\"12\" r=\"10\" stroke=\"currentColor\" strokeWidth=\"4\" />\n <path\n className=\"opacity-75\"\n fill=\"currentColor\"\n d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z\"\n />\n </svg>\n );\n}\n\nexport const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(\n (\n {\n variant = 'primary',\n size = 'md',\n loading = false,\n leadingIcon,\n trailingIcon,\n fullWidth = false,\n disabled,\n children,\n className,\n ...props\n },\n ref\n ) => {\n const isDisabled = disabled || loading;\n\n return (\n <button\n ref={ref}\n disabled={isDisabled}\n aria-busy={loading}\n className={cn(\n 'inline-flex items-center justify-center font-sans font-medium',\n 'transition-all duration-150 ease-in-out',\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand focus-visible:ring-offset-1',\n 'disabled:opacity-50 disabled:pointer-events-none',\n 'select-none whitespace-nowrap',\n variantStyles[variant],\n sizeStyles[size],\n fullWidth && 'w-full',\n className\n )}\n {...props}\n >\n {loading ? (\n <Spinner\n className={cn(size === 'sm' ? 'h-3 w-3' : size === 'lg' ? 'h-4 w-4' : 'h-3.5 w-3.5')}\n />\n ) : (\n leadingIcon && (\n <span className=\"shrink-0\" aria-hidden=\"true\">\n {leadingIcon}\n </span>\n )\n )}\n {children && <span>{children}</span>}\n {!loading && trailingIcon && (\n <span className=\"shrink-0\" aria-hidden=\"true\">\n {trailingIcon}\n </span>\n )}\n </button>\n );\n }\n);\n\nButton.displayName = 'Button';\n","'use client';\n\nimport { useState, useEffect } from 'react';\n\n// โโโ Types โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n\nexport interface NavLink {\n label: string;\n href: string;\n}\n\nexport interface NavBarProps {\n /** Visual theme. \"dark\" = glass/blur on dark bg. \"light\" = white/shadow on light bg. */\n theme?: 'dark' | 'light';\n /** Logo text displayed on the left. */\n logo?: string;\n /** Accent character appended to the logo (e.g. \".\"). */\n logoAccent?: string;\n /** Navigation links rendered in the centre. */\n links?: NavLink[];\n /** Label for the CTA button on the right. */\n ctaLabel?: string;\n /** href for the CTA button. */\n ctaHref?: string;\n /** Whether the nav background changes on scroll. */\n scrollEffect?: boolean;\n /** Scroll threshold in px before the effect triggers. Default 50. */\n scrollThreshold?: number;\n}\n\n// โโโ Constants โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n\nconst DEFAULT_LINKS: NavLink[] = [\n { label: 'About', href: '#about' },\n { label: 'Experience', href: '#experience' },\n { label: 'Projects', href: '#projects' },\n { label: 'Contact', href: '#contact' },\n];\n\n// โโโ Theme tokens โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n\nconst tokens = {\n dark: {\n nav: {\n base: 'bg-transparent',\n scrolled: 'bg-[#060912]/80 backdrop-blur-md border-b border-white/5',\n },\n logo: 'text-[#6366f1]',\n logoAccent: 'text-white/20',\n link: 'text-[#64748b] hover:text-[#e2e8f0]',\n cta: 'bg-[#6366f1]/10 border border-[#6366f1]/30 text-[#6366f1] hover:bg-[#6366f1] hover:text-white hover:border-[#6366f1]',\n menuToggle: 'text-[#64748b] hover:text-[#e2e8f0]',\n mobileMenu: 'bg-[#060912]/95 backdrop-blur-md border-t border-white/5',\n mobileLink: 'text-[#64748b] hover:text-[#e2e8f0]',\n mobileCta: 'bg-[#6366f1]/10 border border-[#6366f1]/30 text-[#6366f1]',\n },\n light: {\n nav: {\n base: 'bg-transparent',\n scrolled: 'bg-[#f8f7f4]/90 backdrop-blur-md shadow-sm',\n },\n logo: 'text-[#0f0f0f]',\n logoAccent: 'text-[#5b50f0]',\n link: 'text-[#6b7280] hover:bg-black/5 hover:text-[#0f0f0f]',\n cta: '[background:linear-gradient(135deg,#5b50f0,#7c3aed)] text-white shadow-lg shadow-[#5b50f0]/25 hover:shadow-[#5b50f0]/40 hover:scale-[1.03]',\n menuToggle: 'text-[#6b7280] hover:text-[#0f0f0f]',\n mobileMenu: 'bg-[#f8f7f4]/95 backdrop-blur-md border-t border-black/5',\n mobileLink: 'text-[#6b7280] hover:text-[#0f0f0f]',\n mobileCta: '[background:linear-gradient(135deg,#5b50f0,#7c3aed)] text-white',\n },\n} as const;\n\n// โโโ Component โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n\nexport function NavBar({\n theme = 'light',\n logo = 'Fariha',\n logoAccent = '.',\n links = DEFAULT_LINKS,\n ctaLabel = 'Hire me',\n ctaHref = '#contact',\n scrollEffect = true,\n scrollThreshold = 50,\n}: NavBarProps) {\n const [scrolled, setScrolled] = useState(false);\n const [menuOpen, setMenuOpen] = useState(false);\n const t = tokens[theme];\n\n useEffect(() => {\n if (!scrollEffect) return;\n const handler = () => setScrolled(window.scrollY > scrollThreshold);\n window.addEventListener('scroll', handler, { passive: true });\n return () => window.removeEventListener('scroll', handler);\n }, [scrollEffect, scrollThreshold]);\n\n const navPy = scrolled ? 'py-3' : 'py-5';\n const navBg = scrolled ? t.nav.scrolled : t.nav.base;\n\n return (\n <nav\n role=\"navigation\"\n aria-label=\"Main navigation\"\n className={`fixed top-0 inset-x-0 z-50 transition-all duration-500 ${navPy} ${navBg}`}\n >\n <div className=\"max-w-6xl mx-auto px-6 flex items-center justify-between\">\n {/* Logo */}\n <a href=\"#\" className={`font-sans font-extrabold text-lg tracking-tight ${t.logo}`}>\n {logo}\n <span className={t.logoAccent}>{logoAccent}</span>\n </a>\n\n {/* Desktop links */}\n <ul className=\"hidden md:flex items-center gap-1\" role=\"list\">\n {links.map(link => (\n <li key={link.label}>\n <a\n href={link.href}\n className={`font-sans font-medium text-sm px-4 py-2 rounded-full transition-all duration-200 ${t.link}`}\n >\n {link.label}\n </a>\n </li>\n ))}\n </ul>\n\n {/* Desktop CTA */}\n <a\n href={ctaHref}\n className={`hidden md:inline-flex items-center px-5 py-2.5 rounded-full font-sans font-bold text-sm transition-all duration-200 ${t.cta}`}\n >\n {ctaLabel}\n </a>\n\n {/* Mobile toggle */}\n <button\n className={`md:hidden transition-colors ${t.menuToggle}`}\n onClick={() => setMenuOpen(prev => !prev)}\n aria-expanded={menuOpen}\n aria-label={menuOpen ? 'Close menu' : 'Open menu'}\n >\n <svg\n width=\"22\"\n height=\"22\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n >\n {menuOpen ? <path d=\"M18 6L6 18M6 6l12 12\" /> : <path d=\"M3 12h18M3 6h18M3 18h18\" />}\n </svg>\n </button>\n </div>\n\n {/* Mobile menu */}\n {menuOpen && (\n <div className={`md:hidden mt-3 ${t.mobileMenu}`}>\n <ul className=\"max-w-6xl mx-auto px-6 py-5 flex flex-col gap-4\" role=\"list\">\n {links.map(link => (\n <li key={link.label}>\n <a\n href={link.href}\n onClick={() => setMenuOpen(false)}\n className={`font-sans font-medium text-base transition-colors ${t.mobileLink}`}\n >\n {link.label}\n </a>\n </li>\n ))}\n <li>\n <a\n href={ctaHref}\n onClick={() => setMenuOpen(false)}\n className={`inline-block px-5 py-2.5 rounded-full font-sans font-bold text-sm ${t.mobileCta}`}\n >\n {ctaLabel}\n </a>\n </li>\n </ul>\n </div>\n )}\n </nav>\n );\n}\n\nexport default NavBar;\n"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@farihatang/react-ui",
|
|
3
|
+
"version": "0.1.0-beta.1",
|
|
4
|
+
"description": "A React component library to help you build your own GitHub projects more easily.",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"import": "./dist/index.mjs",
|
|
10
|
+
"require": "./dist/index.js",
|
|
11
|
+
"types": "./dist/index.d.ts"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist"
|
|
16
|
+
],
|
|
17
|
+
"license": "MIT",
|
|
18
|
+
"keywords": [
|
|
19
|
+
"react",
|
|
20
|
+
"component-library",
|
|
21
|
+
"ui",
|
|
22
|
+
"navbar"
|
|
23
|
+
],
|
|
24
|
+
"repository": {
|
|
25
|
+
"type": "git",
|
|
26
|
+
"url": "https://github.com/FarihaTang/react-component-library"
|
|
27
|
+
},
|
|
28
|
+
"homepage": "https://react-component-library-farihatang.vercel.app/",
|
|
29
|
+
"bugs": {
|
|
30
|
+
"url": "https://github.com/FarihaTang/react-component-library/issues"
|
|
31
|
+
},
|
|
32
|
+
"scripts": {
|
|
33
|
+
"dev": "storybook dev -p 6006",
|
|
34
|
+
"build": "tsup src/index.ts --format cjs,esm --dts --clean",
|
|
35
|
+
"build-storybook": "storybook build",
|
|
36
|
+
"lint": "eslint src --ext .ts,.tsx",
|
|
37
|
+
"type-check": "tsc --noEmit"
|
|
38
|
+
},
|
|
39
|
+
"peerDependencies": {
|
|
40
|
+
"react": ">=18.0.0",
|
|
41
|
+
"react-dom": ">=18.0.0"
|
|
42
|
+
},
|
|
43
|
+
"dependencies": {
|
|
44
|
+
"clsx": "^2.1.1"
|
|
45
|
+
},
|
|
46
|
+
"devDependencies": {
|
|
47
|
+
"@storybook/addon-essentials": "^8.1.9",
|
|
48
|
+
"@storybook/addon-interactions": "^8.1.9",
|
|
49
|
+
"@storybook/addon-links": "^8.1.9",
|
|
50
|
+
"@storybook/blocks": "^8.1.9",
|
|
51
|
+
"@storybook/react": "^8.1.9",
|
|
52
|
+
"@storybook/react-vite": "^8.1.9",
|
|
53
|
+
"@storybook/test": "^8.1.9",
|
|
54
|
+
"@types/node": "^25.5.2",
|
|
55
|
+
"@types/react": "^18.3.3",
|
|
56
|
+
"@types/react-dom": "^18.3.0",
|
|
57
|
+
"autoprefixer": "^10.4.19",
|
|
58
|
+
"postcss": "^8.4.38",
|
|
59
|
+
"storybook": "^8.1.9",
|
|
60
|
+
"tailwindcss": "^3.4.4",
|
|
61
|
+
"tsup": "^8.1.0",
|
|
62
|
+
"typescript": "^5.4.5",
|
|
63
|
+
"vite": "^5.2.13"
|
|
64
|
+
}
|
|
65
|
+
}
|