jean-react-utils 0.1.0 → 0.2.0

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 jean-w
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/dist/index.d.mts CHANGED
@@ -1,4 +1,5 @@
1
1
  import React, { ReactNode } from 'react';
2
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
3
 
3
4
  interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
4
5
  variant?: 'primary' | 'secondary' | 'outline';
@@ -11,10 +12,10 @@ interface HeadingProps {
11
12
  className?: string;
12
13
  title?: string;
13
14
  }
14
- declare function PageTitle({ children, title, className }: HeadingProps): JSX.Element;
15
- declare function SectionTitle({ children, title, className }: HeadingProps): JSX.Element;
16
- declare function CardTitle({ children, title, className }: HeadingProps): JSX.Element;
17
- declare function SubTitle({ children, title, className }: HeadingProps): JSX.Element;
15
+ declare function PageTitle({ children, title, className }: HeadingProps): react_jsx_runtime.JSX.Element;
16
+ declare function SectionTitle({ children, title, className }: HeadingProps): react_jsx_runtime.JSX.Element;
17
+ declare function CardTitle({ children, title, className }: HeadingProps): react_jsx_runtime.JSX.Element;
18
+ declare function SubTitle({ children, title, className }: HeadingProps): react_jsx_runtime.JSX.Element;
18
19
 
19
20
  interface NavItem {
20
21
  key: string;
@@ -69,4 +70,4 @@ declare const Footer: React.FC<FooterProps>;
69
70
 
70
71
  declare const useForceRerender: () => [number, () => void];
71
72
 
72
- export { Button, CardTitle, Footer, type FooterLink, type FooterProps, type FooterTexts, Header, PageTitle, SectionTitle, SubTitle, useForceRerender };
73
+ export { Button, CardTitle, Footer, Header, PageTitle, SectionTitle, SubTitle, useForceRerender };
package/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import React, { ReactNode } from 'react';
2
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
3
 
3
4
  interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
4
5
  variant?: 'primary' | 'secondary' | 'outline';
@@ -11,10 +12,10 @@ interface HeadingProps {
11
12
  className?: string;
12
13
  title?: string;
13
14
  }
14
- declare function PageTitle({ children, title, className }: HeadingProps): JSX.Element;
15
- declare function SectionTitle({ children, title, className }: HeadingProps): JSX.Element;
16
- declare function CardTitle({ children, title, className }: HeadingProps): JSX.Element;
17
- declare function SubTitle({ children, title, className }: HeadingProps): JSX.Element;
15
+ declare function PageTitle({ children, title, className }: HeadingProps): react_jsx_runtime.JSX.Element;
16
+ declare function SectionTitle({ children, title, className }: HeadingProps): react_jsx_runtime.JSX.Element;
17
+ declare function CardTitle({ children, title, className }: HeadingProps): react_jsx_runtime.JSX.Element;
18
+ declare function SubTitle({ children, title, className }: HeadingProps): react_jsx_runtime.JSX.Element;
18
19
 
19
20
  interface NavItem {
20
21
  key: string;
@@ -69,4 +70,4 @@ declare const Footer: React.FC<FooterProps>;
69
70
 
70
71
  declare const useForceRerender: () => [number, () => void];
71
72
 
72
- export { Button, CardTitle, Footer, type FooterLink, type FooterProps, type FooterTexts, Header, PageTitle, SectionTitle, SubTitle, useForceRerender };
73
+ export { Button, CardTitle, Footer, Header, PageTitle, SectionTitle, SubTitle, useForceRerender };
package/dist/index.js CHANGED
@@ -32,7 +32,7 @@ var index_exports = {};
32
32
  __export(index_exports, {
33
33
  Button: () => Button_default,
34
34
  CardTitle: () => CardTitle,
35
- Footer: () => Footer,
35
+ Footer: () => Footer_default,
36
36
  Header: () => Header_default,
37
37
  PageTitle: () => PageTitle,
38
38
  SectionTitle: () => SectionTitle,
@@ -120,16 +120,19 @@ function SubTitle({ children, title, className = "" }) {
120
120
 
121
121
  // src/layout/Header/index.tsx
122
122
  var import_react = require("react");
123
+ var import_classnames = __toESM(require("classnames"));
123
124
  var import_link = __toESM(require("next/link"));
124
125
  var import_framer_motion2 = require("framer-motion");
125
126
 
126
127
  // src/layout/Header/BreadIcon.tsx
127
128
  var import_jsx_runtime3 = require("react/jsx-runtime");
129
+ var spanDefaultCls = "w-full h-0.5 bg-black transition-transform duration-300";
130
+ var spanOpacityCls = "w-full h-0.5 bg-black transition-opacity duration-300";
128
131
  function BreadIcon({ isMenuOpen }) {
129
132
  return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "w-6 h-5 relative flex flex-col justify-between", children: [
130
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: `w-full h-0.5 bg-gray-800 transition-transform duration-300 ${isMenuOpen ? "rotate-45 translate-y-2" : ""}` }),
131
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: `w-full h-0.5 bg-gray-800 transition-opacity duration-300 ${isMenuOpen ? "opacity-0" : ""}` }),
132
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: `w-full h-0.5 bg-gray-800 transition-transform duration-300 ${isMenuOpen ? "-rotate-45 -translate-y-2" : ""}` })
133
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: `${spanDefaultCls} ${isMenuOpen ? "rotate-45 translate-y-2" : ""}` }),
134
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: `${spanOpacityCls} ${isMenuOpen ? "opacity-0" : ""}` }),
135
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: `${spanDefaultCls} ${isMenuOpen ? "-rotate-45 -translate-y-2" : ""}` })
133
136
  ] });
134
137
  }
135
138
 
@@ -140,7 +143,7 @@ var getActivedCls = (href, selectedKey) => {
140
143
  if (href.includes(selectedKey) || href === "/" && selectedKey === "home") {
141
144
  return "text-purple-600";
142
145
  }
143
- return "text-gray-600";
146
+ return "";
144
147
  };
145
148
  var Header = ({
146
149
  logo,
@@ -150,8 +153,7 @@ var Header = ({
150
153
  }) => {
151
154
  const [isMenuOpen, setIsMenuOpen] = (0, import_react.useState)(false);
152
155
  const selectedKey = (0, import_navigation.usePathname)().split("/")[2] || "home";
153
- console.log("selectedKey>>>", selectedKey);
154
- const baseNavClassName = `fixed top-0 left-0 right-0 z-50 bg-white/80 backdrop-blur-lg border-b border-purple-100 ${className}`;
156
+ const baseNavClassName = (0, import_classnames.default)(`fixed top-0 left-0 right-0 z-50 bg-white/80 backdrop-blur-lg border-b border-purple-100 text-gray-600`, className);
155
157
  const navVariants = {
156
158
  hidden: { y: -20, opacity: 0 },
157
159
  visible: {
@@ -163,6 +165,32 @@ var Header = ({
163
165
  }
164
166
  }
165
167
  };
168
+ const HeaderWrapper = enableAnimation ? import_framer_motion2.motion.header : "header";
169
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
170
+ HeaderWrapper,
171
+ {
172
+ className: baseNavClassName,
173
+ ...enableAnimation && {
174
+ initial: "hidden",
175
+ animate: "visible",
176
+ variants: navVariants
177
+ },
178
+ children: [
179
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "container flex items-center justify-between p-4", children: [
180
+ logo,
181
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(DesktopNav, { menuItems, selectedKey, enableAnimation }),
182
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(MobileMenuBtn, { menuItems, selectedKey, setIsMenuOpen, isMenuOpen })
183
+ ] }),
184
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_framer_motion2.AnimatePresence, { children: isMenuOpen && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(MobileNav, { menuItems, selectedKey, enableAnimation }) })
185
+ ]
186
+ }
187
+ );
188
+ };
189
+ var DesktopNav = ({ menuItems, selectedKey, enableAnimation }) => {
190
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("nav", { className: "hidden md:flex items-center space-x-8", children: menuItems.map((item) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(NavLink, { href: item.href, selectedKey, className: item.className?.pc, children: item.label }, item.key)) });
191
+ };
192
+ var MobileNav = ({ menuItems, selectedKey, enableAnimation }) => {
193
+ const MobileMenuComponent = enableAnimation ? import_framer_motion2.motion.div : "div";
166
194
  const mobileMenuVariants = {
167
195
  hidden: {
168
196
  height: 0,
@@ -181,74 +209,43 @@ var Header = ({
181
209
  }
182
210
  }
183
211
  };
184
- const NavComponent = enableAnimation ? import_framer_motion2.motion.nav : "nav";
185
- const MobileMenuComponent = enableAnimation ? import_framer_motion2.motion.div : "div";
186
- console.log("menuItems>>>", menuItems);
187
212
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
188
- NavComponent,
213
+ MobileMenuComponent,
189
214
  {
190
- className: baseNavClassName,
215
+ className: "md:hidden overflow-hidden",
191
216
  ...enableAnimation && {
192
217
  initial: "hidden",
193
218
  animate: "visible",
194
- variants: navVariants
219
+ exit: "hidden",
220
+ variants: mobileMenuVariants
195
221
  },
196
- children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "container mx-auto px-4", children: [
197
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex items-center justify-between h-20", children: [
198
- logo,
199
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("nav", { className: "hidden md:flex items-center space-x-8", children: menuItems.map((item) => (
200
- // <Link
201
- // key={item.key}
202
- // href="/"
203
- // className="flex items-center justify-center gap-2 text-lg font-bold tracking-wide transition-all duration-300 ease-in-out"
204
- // >
205
- // {item.label}
206
- // </Link>
207
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(NavLink, { href: item.href, className: item.className?.pc, selectedKey, children: item.label }, item.key)
208
- )) }),
209
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
210
- "button",
211
- {
212
- onClick: () => setIsMenuOpen(!isMenuOpen),
213
- className: "md:hidden p-2 hover:bg-purple-50 rounded-lg transition-colors",
214
- children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(BreadIcon, { isMenuOpen })
215
- }
216
- )
217
- ] }),
218
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_framer_motion2.AnimatePresence, { children: isMenuOpen && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
219
- MobileMenuComponent,
220
- {
221
- className: "md:hidden overflow-hidden",
222
- ...enableAnimation && {
223
- initial: "hidden",
224
- animate: "visible",
225
- exit: "hidden",
226
- variants: mobileMenuVariants
227
- },
228
- children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "flex flex-col space-y-4 py-4 items-center", children: menuItems.map((item) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
229
- import_framer_motion2.motion.div,
230
- {
231
- ...enableAnimation && {
232
- initial: { x: -20, opacity: 0 },
233
- animate: { x: 0, opacity: 1 },
234
- transition: { delay: 0.1 }
235
- },
236
- children: menuItems.map((item2) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(MobileNavLink, { href: item2.href, className: item2.className?.mobile, selectedKey, children: item2.label }, item2.key))
237
- },
238
- item.key
239
- )) })
240
- }
241
- ) })
242
- ] })
222
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("nav", { className: "flex flex-col space-y-4 py-4 items-center", children: menuItems.map((item) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(MobileMenuComponent, { ...enableAnimation && {
223
+ initial: { x: -20, opacity: 0 },
224
+ animate: { x: 0, opacity: 1 },
225
+ transition: { delay: 0.1 }
226
+ }, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(MobileNavLink, { href: item.href, selectedKey, className: item.className?.mobile, children: item.label }) }, item.key)) })
227
+ }
228
+ );
229
+ };
230
+ var MobileMenuBtn = ({ setIsMenuOpen, isMenuOpen }) => {
231
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
232
+ "button",
233
+ {
234
+ onClick: () => setIsMenuOpen(!isMenuOpen),
235
+ className: "md:hidden p-2 hover:bg-purple-50 rounded-lg transition-colors",
236
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(BreadIcon, { isMenuOpen })
243
237
  }
244
238
  );
245
239
  };
246
240
  var NavLink = ({ href, children, className, selectedKey }) => {
247
- const combinedClassName = `${className || "text-gray-600 hover:text-black transition-colors"} ${getActivedCls(href, selectedKey)}`;
241
+ const combinedClassName = (0, import_classnames.default)(
242
+ className || "hover:text-black transition-colors",
243
+ getActivedCls(href, selectedKey)
244
+ );
248
245
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_link.default, { href, legacyBehavior: true, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("a", { className: combinedClassName, children }) });
249
246
  };
250
247
  var MobileNavLink = ({ href, children, className, selectedKey }) => {
251
- const combinedClassName = `${className || "text-lg font-medium text-center text-gray-600 hover:text-purple-600 transition-colors"} ${getActivedCls(href, selectedKey)}`;
248
+ const combinedClassName = `${className || "text-lg font-medium text-center hover:text-purple-600 transition-colors"} ${getActivedCls(href, selectedKey)}`;
252
249
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_link.default, { href, legacyBehavior: true, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("a", { className: combinedClassName, children }) });
253
250
  };
254
251
  var Header_default = Header;
@@ -308,6 +305,7 @@ var Footer = ({
308
305
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "absolute top-0 left-0 right-0 h-1 bg-gradient-to-r from-purple-600 via-pink-500 to-purple-600" })
309
306
  ] });
310
307
  };
308
+ var Footer_default = Footer;
311
309
 
312
310
  // src/hooks/useForceRerender.ts
313
311
  var import_react2 = require("react");
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/components/Button/index.tsx","../src/components/Heading/index.tsx","../src/layout/Header/index.tsx","../src/layout/Header/BreadIcon.tsx","../src/layout/Footer/index.tsx","../src/hooks/useForceRerender.ts"],"sourcesContent":["export * from './components'\nexport * from './layout'\nexport { default as useForceRerender } from './hooks/useForceRerender'\n// export * from './hooks'\n// export * from './layout'\n// export * from './theme'\n// export * from './i18n'","import React from 'react';\n\nexport interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n variant?: 'primary' | 'secondary' | 'outline';\n size?: 'sm' | 'md' | 'lg';\n}\n\nexport const Button: React.FC<ButtonProps> = ({\n variant = 'primary',\n size = 'md',\n className = '',\n children,\n ...props\n}) => {\n const baseStyles = 'rounded-full font-medium transition-colors';\n \n const variants = {\n primary: 'bg-purple-600 text-white hover:bg-purple-700 shadow-lg shadow-purple-500/20',\n secondary: 'bg-purple-50 text-purple-700 hover:bg-purple-100',\n outline: 'border-2 border-purple-600 text-purple-600 hover:bg-purple-50'\n };\n\n const sizes = {\n sm: 'px-4 py-1.5 text-sm',\n md: 'px-6 py-2 text-sm',\n lg: 'px-8 py-3 text-base'\n };\n\n const classes = `${baseStyles} ${variants[variant]} ${sizes[size]} ${className}`;\n\n return (\n <button className={classes} {...props}>\n {children}\n </button>\n );\n}; \n\nexport default Button;","'use client';\n\nimport { motion } from 'framer-motion';\nimport { ReactNode } from 'react';\n\nexport interface HeadingProps {\n children?: ReactNode;\n className?: string;\n title?: string;\n}\n\n// 頁面主標題:大標題,帶漸變色\nexport function PageTitle({ children, title, className = '' }: HeadingProps) {\n return (\n <motion.h1\n initial={{ opacity: 0, y: 20 }}\n animate={{ opacity: 1, y: 0 }}\n transition={{ duration: 0.8 }}\n className={`text-4xl md:text-5xl font-bold mb-6 bg-gradient-to-r from-purple-600 to-pink-500 bg-clip-text text-transparent ${className}`}\n >\n {title || children}\n </motion.h1>\n );\n}\n\n// 區塊標題:中等大小,帶漸變色\nexport function SectionTitle({ children, title, className = '' }: HeadingProps) {\n return (\n <motion.h2\n initial={{ opacity: 0, y: 20 }}\n animate={{ opacity: 1, y: 0 }}\n transition={{ duration: 0.8, delay: 0.2 }}\n className={`text-3xl font-bold text-center mb-16 bg-gradient-to-r from-purple-600 to-pink-500 bg-clip-text text-transparent ${className}`}\n >\n {title || children}\n </motion.h2>\n );\n}\n\n// 卡片標題:較小,深灰色\nexport function CardTitle({ children, title,className = '' }: HeadingProps) {\n return (\n <motion.h3\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n transition={{ duration: 0.5 }}\n className={`text-2xl font-bold text-gray-800 ${className}`}\n >\n {title || children}\n </motion.h3>\n );\n}\n\n// 區塊子標題:最小,帶圖標位置\nexport function SubTitle({ children, title, className = '' }: HeadingProps) {\n return (\n <motion.h4\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n transition={{ duration: 0.5 }}\n className={`text-lg font-semibold text-gray-800 ${className}`}\n >\n {title || children}\n </motion.h4>\n );\n} \n\nexport default {\n PageTitle,\n SectionTitle,\n CardTitle,\n SubTitle,\n}","'use client';\nimport React, { useState } from 'react';\nimport Link from 'next/link';\nimport { motion, AnimatePresence } from 'framer-motion';\nimport BreadIcon from './BreadIcon';\nimport { usePathname } from 'next/navigation';\nexport interface NavItem {\n key: string;\n href: string;\n label: string;\n className?: {\n pc?: string;\n mobile?: string;\n };\n}\n\nexport interface HeaderProps {\n logo: React.ReactNode;\n menuItems: NavItem[];\n className?: string;\n /** 是否啟用動畫效果 */\n enableAnimation?: boolean;\n}\nconst getActivedCls = (href: string, selectedKey: string) => {\n if(href.includes(selectedKey) || (href === '/' && selectedKey === 'home')) {\n return 'text-purple-600';\n }\n return 'text-gray-600';\n}\nexport const Header: React.FC<HeaderProps> = ({\n logo,\n menuItems,\n className = '',\n enableAnimation = true,\n}) => {\n const [isMenuOpen, setIsMenuOpen] = useState(false);\n const selectedKey = usePathname().split('/')[2] || 'home'; // todo support home\n console.log('selectedKey>>>',selectedKey);\n // 基礎樣式\n const baseNavClassName = `fixed top-0 left-0 right-0 z-50 bg-white/80 backdrop-blur-lg border-b border-purple-100 ${className}`;\n // 動畫配置\n const navVariants = {\n hidden: { y: -20, opacity: 0 },\n visible: { \n y: 0, \n opacity: 1,\n transition: {\n duration: 0.5,\n ease: \"easeOut\"\n }\n }\n };\n\n const mobileMenuVariants = {\n hidden: { \n height: 0,\n opacity: 0,\n transition: {\n duration: 0.3,\n ease: \"easeInOut\"\n }\n },\n visible: { \n height: \"auto\",\n opacity: 1,\n transition: {\n duration: 0.3,\n ease: \"easeInOut\"\n }\n }\n };\n\n // 根據是否啟用動畫返回不同的組件\n const NavComponent = enableAnimation ? motion.nav : 'nav';\n const MobileMenuComponent = enableAnimation ? motion.div : 'div';\nconsole.log('menuItems>>>',menuItems);\n return (\n <NavComponent \n className={baseNavClassName}\n {...(enableAnimation && {\n initial: \"hidden\",\n animate: \"visible\",\n variants: navVariants\n })}\n >\n <div className=\"container mx-auto px-4\">\n <div className=\"flex items-center justify-between h-20\">\n {/* Logo */}\n {logo}\n\n {/* Desktop Navigation */}\n <nav className=\"hidden md:flex items-center space-x-8\">\n {menuItems.map((item) => (\n // <Link\n // key={item.key}\n // href=\"/\"\n // className=\"flex items-center justify-center gap-2 text-lg font-bold tracking-wide transition-all duration-300 ease-in-out\"\n // >\n // {item.label}\n // </Link>\n <NavLink key={item.key} href={item.href} className={item.className?.pc} selectedKey={selectedKey}>\n {item.label}\n </NavLink>\n ))}\n </nav>\n\n {/* Mobile Menu Button */}\n <button \n onClick={() => setIsMenuOpen(!isMenuOpen)}\n className=\"md:hidden p-2 hover:bg-purple-50 rounded-lg transition-colors\"\n >\n <BreadIcon isMenuOpen={isMenuOpen}/>\n </button>\n </div>\n\n {/* Mobile Menu */}\n <AnimatePresence>\n {isMenuOpen && (\n <MobileMenuComponent\n className=\"md:hidden overflow-hidden\"\n {...(enableAnimation && {\n initial: \"hidden\",\n animate: \"visible\",\n exit: \"hidden\",\n variants: mobileMenuVariants\n })}\n >\n <div className=\"flex flex-col space-y-4 py-4 items-center\">\n {menuItems.map((item) => (\n <motion.div\n key={item.key}\n {...(enableAnimation && {\n initial: { x: -20, opacity: 0 },\n animate: { x: 0, opacity: 1 },\n transition: { delay: 0.1 }\n })}\n >\n {\n menuItems.map((item) => (\n <MobileNavLink key={item.key} href={item.href} className={item.className?.mobile} selectedKey={selectedKey}>{item.label}</MobileNavLink>\n ))\n }\n </motion.div>\n ))}\n </div>\n </MobileMenuComponent>\n )}\n </AnimatePresence>\n </div>\n </NavComponent>\n );\n}; \n\n\nconst NavLink = ({ href, children, className, selectedKey }: { href: string; children: React.ReactNode, className?: string, selectedKey: string }) => {\n const combinedClassName = `${className || 'text-gray-600 hover:text-black transition-colors'} ${getActivedCls(href, selectedKey)}`;\n return (\n <Link href={href} legacyBehavior>\n <a className={combinedClassName}>{children}</a>\n </Link>\n );\n};\n\nconst MobileNavLink = ({ href, children, className, selectedKey }: { href: string; children: React.ReactNode, className?: string, selectedKey: string }) => {\n const combinedClassName = `${className || 'text-lg font-medium text-center text-gray-600 hover:text-purple-600 transition-colors'} ${getActivedCls(href, selectedKey)}`;\n return (\n <Link href={href} legacyBehavior>\n <a className={combinedClassName}>{children}</a>\n </Link>\n );\n};\n\nexport default Header;","export default function BreadIcon({isMenuOpen}: {isMenuOpen: boolean}) {\n return (\n <div className=\"w-6 h-5 relative flex flex-col justify-between\">\n <span className={`w-full h-0.5 bg-gray-800 transition-transform duration-300 ${isMenuOpen ? 'rotate-45 translate-y-2' : ''}`} />\n <span className={`w-full h-0.5 bg-gray-800 transition-opacity duration-300 ${isMenuOpen ? 'opacity-0' : ''}`} />\n <span className={`w-full h-0.5 bg-gray-800 transition-transform duration-300 ${isMenuOpen ? '-rotate-45 -translate-y-2' : ''}`} />\n </div>\n )\n}","'use client';\nimport React from 'react';\nimport Link from 'next/link';\n\nexport interface FooterLink {\n href: string;\n title: string;\n}\n\nexport interface FooterTexts {\n copyright: string;\n privacy: string;\n terms: string;\n social: string;\n}\n\nexport interface FooterProps {\n /** 網站基本信息 */\n site: {\n name: string;\n description: string;\n };\n /** 導航鏈接 */\n navigation: {\n /** 快速鏈接區塊 */\n quickLinks: {\n title: string;\n items: FooterLink[];\n };\n /** 社交媒體鏈接 */\n socialLinks: FooterLink[];\n };\n /** 頁腳文本 */\n texts: FooterTexts;\n /** 自定義類名 */\n className?: string;\n}\n\nexport const Footer: React.FC<FooterProps> = ({\n site,\n navigation,\n texts,\n className = '',\n}) => {\n return (\n <footer className={`relative bg-gradient-to-b from-gray-50 to-gray-100 pt-16 pb-6 ${className}`}>\n <div className=\"absolute inset-0 bg-grid-gray-200/25 [mask-image:linear-gradient(0deg,white,rgba(255,255,255,0.6))]\" />\n \n <div className=\"container mx-auto p-4 relative\">\n <div className=\"grid grid-cols-1 md:grid-cols-3 gap-8 mb-12\">\n {/* Brand Section */}\n <div className=\"space-y-4\">\n <h3 className=\"text-xl font-bold bg-gradient-to-r from-purple-600 to-pink-500 bg-clip-text text-transparent\">\n {site.name}\n </h3>\n <p className=\"text-gray-600 max-w-xs\">\n {site.description}\n </p>\n </div>\n\n {/* Quick Links */}\n <div className=\"space-y-4\">\n <h4 className=\"text-sm font-semibold text-gray-900 uppercase\">\n {navigation.quickLinks.title}\n </h4>\n <nav className=\"flex flex-col space-y-2\">\n {navigation.quickLinks.items.map((item) => (\n <Link\n key={item.href}\n href={item.href}\n className=\"text-gray-600 hover:text-purple-600 transition-colors\"\n >\n {item.title}\n </Link>\n ))}\n </nav>\n </div>\n\n {/* Social Links */}\n <div className=\"space-y-4\">\n <h4 className=\"text-sm font-semibold text-gray-900 uppercase\">\n {texts.social}\n </h4>\n <div className=\"flex space-x-4\">\n {navigation.socialLinks.map((link) => (\n <a\n key={link.href}\n href={link.href}\n className=\"text-gray-600 hover:text-purple-600 transition-colors\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n {link.title}\n </a>\n ))}\n </div>\n </div>\n </div>\n\n {/* Bottom Bar */}\n <div className=\"border-t border-gray-200 pt-6\">\n <div className=\"flex flex-col md:flex-row justify-between items-center space-y-4 md:space-y-0\">\n <p className=\"text-sm text-gray-600\">\n {texts.copyright}\n </p>\n <div className=\"flex space-x-6\">\n <Link href=\"/privacy\" className=\"text-sm text-gray-600 hover:text-purple-600 transition-colors\">\n {texts.privacy}\n </Link>\n <Link href=\"/terms\" className=\"text-sm text-gray-600 hover:text-purple-600 transition-colors\">\n {texts.terms}\n </Link>\n </div>\n </div>\n </div>\n </div>\n\n {/* Decorative gradient line */}\n <div className=\"absolute top-0 left-0 right-0 h-1 bg-gradient-to-r from-purple-600 via-pink-500 to-purple-600\" />\n </footer>\n );\n}; ","import { useState, useCallback } from 'react';\n\nconst useForceRerender = (): [number, () => void] => {\n const [key, setKey] = useState(0);\n\n const forceRerender = useCallback(() => {\n setKey(prevKey => prevKey + 1);\n }, []);\n\n return [key, forceRerender];\n};\n\nexport default useForceRerender;"],"mappings":"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","names":["import_jsx_runtime","import_framer_motion","import_jsx_runtime","import_jsx_runtime","item","Link","import_link","import_jsx_runtime","Link","import_react"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/components/Button/index.tsx","../src/components/Heading/index.tsx","../src/layout/Header/index.tsx","../src/layout/Header/BreadIcon.tsx","../src/layout/Footer/index.tsx","../src/hooks/useForceRerender.ts"],"sourcesContent":["export * from './components'\nexport * from './layout'\nexport { default as useForceRerender } from './hooks/useForceRerender'\n// export * from './hooks'\n// export * from './layout'\n// export * from './theme'\n// export * from './i18n'","import React from 'react';\n\nexport interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n variant?: 'primary' | 'secondary' | 'outline';\n size?: 'sm' | 'md' | 'lg';\n}\n\nexport const Button: React.FC<ButtonProps> = ({\n variant = 'primary',\n size = 'md',\n className = '',\n children,\n ...props\n}) => {\n const baseStyles = 'rounded-full font-medium transition-colors';\n \n const variants = {\n primary: 'bg-purple-600 text-white hover:bg-purple-700 shadow-lg shadow-purple-500/20',\n secondary: 'bg-purple-50 text-purple-700 hover:bg-purple-100',\n outline: 'border-2 border-purple-600 text-purple-600 hover:bg-purple-50'\n };\n\n const sizes = {\n sm: 'px-4 py-1.5 text-sm',\n md: 'px-6 py-2 text-sm',\n lg: 'px-8 py-3 text-base'\n };\n\n const classes = `${baseStyles} ${variants[variant]} ${sizes[size]} ${className}`;\n\n return (\n <button className={classes} {...props}>\n {children}\n </button>\n );\n}; \n\nexport default Button;","'use client';\n\nimport { motion } from 'framer-motion';\nimport { ReactNode } from 'react';\n\nexport interface HeadingProps {\n children?: ReactNode;\n className?: string;\n title?: string;\n}\n\n// 頁面主標題:大標題,帶漸變色\nexport function PageTitle({ children, title, className = '' }: HeadingProps) {\n return (\n <motion.h1\n initial={{ opacity: 0, y: 20 }}\n animate={{ opacity: 1, y: 0 }}\n transition={{ duration: 0.8 }}\n className={`text-4xl md:text-5xl font-bold mb-6 bg-gradient-to-r from-purple-600 to-pink-500 bg-clip-text text-transparent ${className}`}\n >\n {title || children}\n </motion.h1>\n );\n}\n\n// 區塊標題:中等大小,帶漸變色\nexport function SectionTitle({ children, title, className = '' }: HeadingProps) {\n return (\n <motion.h2\n initial={{ opacity: 0, y: 20 }}\n animate={{ opacity: 1, y: 0 }}\n transition={{ duration: 0.8, delay: 0.2 }}\n className={`text-3xl font-bold text-center mb-16 bg-gradient-to-r from-purple-600 to-pink-500 bg-clip-text text-transparent ${className}`}\n >\n {title || children}\n </motion.h2>\n );\n}\n\n// 卡片標題:較小,深灰色\nexport function CardTitle({ children, title,className = '' }: HeadingProps) {\n return (\n <motion.h3\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n transition={{ duration: 0.5 }}\n className={`text-2xl font-bold text-gray-800 ${className}`}\n >\n {title || children}\n </motion.h3>\n );\n}\n\n// 區塊子標題:最小,帶圖標位置\nexport function SubTitle({ children, title, className = '' }: HeadingProps) {\n return (\n <motion.h4\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n transition={{ duration: 0.5 }}\n className={`text-lg font-semibold text-gray-800 ${className}`}\n >\n {title || children}\n </motion.h4>\n );\n} \n\nexport default {\n PageTitle,\n SectionTitle,\n CardTitle,\n SubTitle,\n}","'use client';\nimport React, { useState } from 'react';\nimport classNames from 'classnames';\nimport Link from 'next/link';\nimport { motion, AnimatePresence } from 'framer-motion';\nimport BreadIcon from './BreadIcon';\nimport { usePathname } from 'next/navigation';\nexport interface NavItem {\n key: string;\n href: string;\n label: string;\n className?: {\n pc?: string;\n mobile?: string;\n };\n}\n\nexport interface HeaderProps {\n logo: React.ReactNode;\n menuItems: NavItem[];\n className?: string;\n /** 是否啟用動畫效果 */\n enableAnimation?: boolean;\n}\nconst getActivedCls = (href: string, selectedKey: string) => {\n if(href.includes(selectedKey) || (href === '/' && selectedKey === 'home')) {\n return 'text-purple-600';\n }\n return '';\n}\nexport const Header: React.FC<HeaderProps> = ({\n logo,\n menuItems,\n className = '',\n enableAnimation = true,\n}) => {\n const [isMenuOpen, setIsMenuOpen] = useState(false);\n const selectedKey = usePathname().split('/')[2] || 'home';\n // 如何解决className 重复的问题,传入值与默认值有重复\n const baseNavClassName = classNames(`fixed top-0 left-0 right-0 z-50 bg-white/80 backdrop-blur-lg border-b border-purple-100 text-gray-600`, className);\n\n // 動畫配置\n const navVariants = {\n hidden: { y: -20, opacity: 0 },\n visible: { \n y: 0, \n opacity: 1,\n transition: {\n duration: 0.5,\n ease: \"easeOut\"\n }\n }\n };\n\n // 根據是否啟用動畫返回不同的組件\n const HeaderWrapper = enableAnimation ? motion.header : 'header';\n return (\n <HeaderWrapper \n className={baseNavClassName}\n {...(enableAnimation && {\n initial: \"hidden\",\n animate: \"visible\",\n variants: navVariants\n })}\n >\n <div className='container flex items-center justify-between p-4'>\n {logo}\n {/* Desktop Navigation */}\n <DesktopNav menuItems={menuItems} selectedKey={selectedKey} enableAnimation={enableAnimation} />\n <MobileMenuBtn menuItems={menuItems} selectedKey={selectedKey} setIsMenuOpen={setIsMenuOpen} isMenuOpen={isMenuOpen} />\n </div>\n {/* Mobile Menu */}\n <AnimatePresence>\n {isMenuOpen && (\n <MobileNav menuItems={menuItems} selectedKey={selectedKey} enableAnimation={enableAnimation} />\n )}\n </AnimatePresence>\n </HeaderWrapper>\n );\n}; \nconst DesktopNav = ({ menuItems, selectedKey, enableAnimation }: { menuItems: NavItem[], selectedKey: string, enableAnimation: boolean }) => {\n return (\n <nav className='hidden md:flex items-center space-x-8'>\n {menuItems.map((item) => (\n <NavLink key={item.key} href={item.href} selectedKey={selectedKey} className={item.className?.pc}>{item.label}</NavLink>\n ))}\n </nav>\n )\n}\n\nconst MobileNav = ({ menuItems, selectedKey, enableAnimation }: { menuItems: NavItem[], selectedKey: string, enableAnimation: boolean }) => {\n const MobileMenuComponent = enableAnimation ? motion.div : 'div';\n const mobileMenuVariants = {\n hidden: { \n height: 0,\n opacity: 0,\n transition: {\n duration: 0.3,\n ease: \"easeInOut\"\n }\n },\n visible: { \n height: \"auto\",\n opacity: 1,\n transition: {\n duration: 0.3,\n ease: \"easeInOut\"\n }\n }\n };\n return (\n <MobileMenuComponent className='md:hidden overflow-hidden'\n {\n ...(enableAnimation && {\n initial: \"hidden\",\n animate: \"visible\",\n exit: \"hidden\",\n variants: mobileMenuVariants\n })\n }>\n <nav className='flex flex-col space-y-4 py-4 items-center'>\n {menuItems.map((item) => (\n <MobileMenuComponent key={item.key} {...(enableAnimation && {\n initial: { x: -20, opacity: 0 },\n animate: { x: 0, opacity: 1 },\n transition: { delay: 0.1 }\n })}>\n <MobileNavLink href={item.href} selectedKey={selectedKey} className={item.className?.mobile}>{item.label}</MobileNavLink>\n </MobileMenuComponent>\n ))}\n </nav>\n </MobileMenuComponent>\n )\n}\n\nconst MobileMenuBtn = ({ setIsMenuOpen, isMenuOpen }: { menuItems: NavItem[], selectedKey: string, setIsMenuOpen: (isMenuOpen: boolean) => void, isMenuOpen: boolean }) => {\n return (\n <button \n onClick={() => setIsMenuOpen(!isMenuOpen)}\n className=\"md:hidden p-2 hover:bg-purple-50 rounded-lg transition-colors\"\n >\n <BreadIcon isMenuOpen={isMenuOpen}/>\n </button>\n )\n}\n\nconst NavLink = ({ href, children, className, selectedKey }: { href: string; children: React.ReactNode, className?: string, selectedKey: string }) => {\n const combinedClassName = classNames(\n className || 'hover:text-black transition-colors',\n getActivedCls(href, selectedKey)\n );\n return (\n <Link href={href} legacyBehavior>\n <a className={combinedClassName}>{children}</a>\n </Link>\n );\n};\n\nconst MobileNavLink = ({ href, children, className, selectedKey }: { href: string; children: React.ReactNode, className?: string, selectedKey: string }) => {\n const combinedClassName = `${className || 'text-lg font-medium text-center hover:text-purple-600 transition-colors'} ${getActivedCls(href, selectedKey)}`;\n return (\n <Link href={href} legacyBehavior>\n <a className={combinedClassName}>{children}</a>\n </Link>\n );\n};\n\nexport default Header;","const spanDefaultCls= 'w-full h-0.5 bg-black transition-transform duration-300'\nconst spanOpacityCls= 'w-full h-0.5 bg-black transition-opacity duration-300'\n\nexport default function BreadIcon({isMenuOpen}: {isMenuOpen: boolean}) {\n return (\n <div className=\"w-6 h-5 relative flex flex-col justify-between\">\n <span className={`${spanDefaultCls} ${isMenuOpen ? 'rotate-45 translate-y-2' : ''}`} />\n <span className={`${spanOpacityCls} ${isMenuOpen ? 'opacity-0' : ''}`} />\n <span className={`${spanDefaultCls} ${isMenuOpen ? '-rotate-45 -translate-y-2' : ''}`} />\n </div>\n )\n}","'use client';\nimport React from 'react';\nimport Link from 'next/link';\n\nexport interface FooterLink {\n href: string;\n title: string;\n}\n\nexport interface FooterTexts {\n copyright: string;\n privacy: string;\n terms: string;\n social: string;\n}\n\nexport interface FooterProps {\n /** 網站基本信息 */\n site: {\n name: string;\n description: string;\n };\n /** 導航鏈接 */\n navigation: {\n /** 快速鏈接區塊 */\n quickLinks: {\n title: string;\n items: FooterLink[];\n };\n /** 社交媒體鏈接 */\n socialLinks: FooterLink[];\n };\n /** 頁腳文本 */\n texts: FooterTexts;\n /** 自定義類名 */\n className?: string;\n}\n\nexport const Footer: React.FC<FooterProps> = ({\n site,\n navigation,\n texts,\n className = '',\n}) => {\n return (\n <footer className={`relative bg-gradient-to-b from-gray-50 to-gray-100 pt-16 pb-6 ${className}`}>\n <div className=\"absolute inset-0 bg-grid-gray-200/25 [mask-image:linear-gradient(0deg,white,rgba(255,255,255,0.6))]\" />\n \n <div className=\"container mx-auto p-4 relative\">\n <div className=\"grid grid-cols-1 md:grid-cols-3 gap-8 mb-12\">\n {/* Brand Section */}\n <div className=\"space-y-4\">\n <h3 className=\"text-xl font-bold bg-gradient-to-r from-purple-600 to-pink-500 bg-clip-text text-transparent\">\n {site.name}\n </h3>\n <p className=\"text-gray-600 max-w-xs\">\n {site.description}\n </p>\n </div>\n\n {/* Quick Links */}\n <div className=\"space-y-4\">\n <h4 className=\"text-sm font-semibold text-gray-900 uppercase\">\n {navigation.quickLinks.title}\n </h4>\n <nav className=\"flex flex-col space-y-2\">\n {navigation.quickLinks.items.map((item) => (\n <Link\n key={item.href}\n href={item.href}\n className=\"text-gray-600 hover:text-purple-600 transition-colors\"\n >\n {item.title}\n </Link>\n ))}\n </nav>\n </div>\n\n {/* Social Links */}\n <div className=\"space-y-4\">\n <h4 className=\"text-sm font-semibold text-gray-900 uppercase\">\n {texts.social}\n </h4>\n <div className=\"flex space-x-4\">\n {navigation.socialLinks.map((link) => (\n <a\n key={link.href}\n href={link.href}\n className=\"text-gray-600 hover:text-purple-600 transition-colors\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n {link.title}\n </a>\n ))}\n </div>\n </div>\n </div>\n\n {/* Bottom Bar */}\n <div className=\"border-t border-gray-200 pt-6\">\n <div className=\"flex flex-col md:flex-row justify-between items-center space-y-4 md:space-y-0\">\n <p className=\"text-sm text-gray-600\">\n {texts.copyright}\n </p>\n <div className=\"flex space-x-6\">\n <Link href=\"/privacy\" className=\"text-sm text-gray-600 hover:text-purple-600 transition-colors\">\n {texts.privacy}\n </Link>\n <Link href=\"/terms\" className=\"text-sm text-gray-600 hover:text-purple-600 transition-colors\">\n {texts.terms}\n </Link>\n </div>\n </div>\n </div>\n </div>\n\n {/* Decorative gradient line */}\n <div className=\"absolute top-0 left-0 right-0 h-1 bg-gradient-to-r from-purple-600 via-pink-500 to-purple-600\" />\n </footer>\n );\n}; \n\nexport default Footer;","import { useState, useCallback } from 'react';\n\nconst useForceRerender = (): [number, () => void] => {\n const [key, setKey] = useState(0);\n\n const forceRerender = useCallback(() => {\n setKey(prevKey => prevKey + 1);\n }, []);\n\n return [key, forceRerender];\n};\n\nexport default useForceRerender;"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;AC+BI;AAxBG,IAAM,SAAgC,CAAC;AAAA,EAC5C,UAAU;AAAA,EACV,OAAO;AAAA,EACP,YAAY;AAAA,EACZ;AAAA,EACA,GAAG;AACL,MAAM;AACJ,QAAM,aAAa;AAEnB,QAAM,WAAW;AAAA,IACf,SAAS;AAAA,IACT,WAAW;AAAA,IACX,SAAS;AAAA,EACX;AAEA,QAAM,QAAQ;AAAA,IACZ,IAAI;AAAA,IACJ,IAAI;AAAA,IACJ,IAAI;AAAA,EACN;AAEA,QAAM,UAAU,GAAG,UAAU,IAAI,SAAS,OAAO,CAAC,IAAI,MAAM,IAAI,CAAC,IAAI,SAAS;AAE9E,SACE,4CAAC,YAAO,WAAW,SAAU,GAAG,OAC7B,UACH;AAEJ;AAEA,IAAO,iBAAQ;;;ACnCf,2BAAuB;AAYnB,IAAAA,sBAAA;AAFG,SAAS,UAAU,EAAE,UAAU,OAAO,YAAY,GAAG,GAAiB;AAC3E,SACE;AAAA,IAAC,4BAAO;AAAA,IAAP;AAAA,MACC,SAAS,EAAE,SAAS,GAAG,GAAG,GAAG;AAAA,MAC7B,SAAS,EAAE,SAAS,GAAG,GAAG,EAAE;AAAA,MAC5B,YAAY,EAAE,UAAU,IAAI;AAAA,MAC5B,WAAW,kHAAkH,SAAS;AAAA,MAErI,mBAAS;AAAA;AAAA,EACZ;AAEJ;AAGO,SAAS,aAAa,EAAE,UAAU,OAAO,YAAY,GAAG,GAAiB;AAC9E,SACE;AAAA,IAAC,4BAAO;AAAA,IAAP;AAAA,MACC,SAAS,EAAE,SAAS,GAAG,GAAG,GAAG;AAAA,MAC7B,SAAS,EAAE,SAAS,GAAG,GAAG,EAAE;AAAA,MAC5B,YAAY,EAAE,UAAU,KAAK,OAAO,IAAI;AAAA,MACxC,WAAW,mHAAmH,SAAS;AAAA,MAEtI,mBAAS;AAAA;AAAA,EACZ;AAEJ;AAGO,SAAS,UAAU,EAAE,UAAU,OAAM,YAAY,GAAG,GAAiB;AAC1E,SACE;AAAA,IAAC,4BAAO;AAAA,IAAP;AAAA,MACC,SAAS,EAAE,SAAS,EAAE;AAAA,MACtB,SAAS,EAAE,SAAS,EAAE;AAAA,MACtB,YAAY,EAAE,UAAU,IAAI;AAAA,MAC5B,WAAW,oCAAoC,SAAS;AAAA,MAEvD,mBAAS;AAAA;AAAA,EACZ;AAEJ;AAGO,SAAS,SAAS,EAAE,UAAU,OAAO,YAAY,GAAG,GAAiB;AAC1E,SACE;AAAA,IAAC,4BAAO;AAAA,IAAP;AAAA,MACC,SAAS,EAAE,SAAS,EAAE;AAAA,MACtB,SAAS,EAAE,SAAS,EAAE;AAAA,MACtB,YAAY,EAAE,UAAU,IAAI;AAAA,MAC5B,WAAW,uCAAuC,SAAS;AAAA,MAE1D,mBAAS;AAAA;AAAA,EACZ;AAEJ;;;AChEA,mBAAgC;AAChC,wBAAuB;AACvB,kBAAiB;AACjB,IAAAC,wBAAwC;;;ACChC,IAAAC,sBAAA;AALR,IAAM,iBAAgB;AACtB,IAAM,iBAAgB;AAEP,SAAR,UAA2B,EAAC,WAAU,GAA0B;AACnE,SACI,8CAAC,SAAI,WAAU,kDACT;AAAA,iDAAC,UAAK,WAAW,GAAG,cAAc,IAAI,aAAa,4BAA4B,EAAE,IAAI;AAAA,IACrF,6CAAC,UAAK,WAAW,GAAG,cAAc,IAAI,aAAa,cAAc,EAAE,IAAI;AAAA,IACvE,6CAAC,UAAK,WAAW,GAAG,cAAc,IAAI,aAAa,8BAA8B,EAAE,IAAI;AAAA,KAC7F;AAER;;;ADLA,wBAA4B;AA2DtB,IAAAC,sBAAA;AAzCN,IAAM,gBAAgB,CAAC,MAAc,gBAAwB;AAC3D,MAAG,KAAK,SAAS,WAAW,KAAM,SAAS,OAAO,gBAAgB,QAAS;AACzE,WAAO;AAAA,EACT;AACA,SAAO;AACT;AACO,IAAM,SAAgC,CAAC;AAAA,EAC5C;AAAA,EACA;AAAA,EACA,YAAY;AAAA,EACZ,kBAAkB;AACpB,MAAM;AACJ,QAAM,CAAC,YAAY,aAAa,QAAI,uBAAS,KAAK;AAClD,QAAM,kBAAc,+BAAY,EAAE,MAAM,GAAG,EAAE,CAAC,KAAK;AAEnD,QAAM,uBAAmB,kBAAAC,SAAW,yGAAyG,SAAS;AAGtJ,QAAM,cAAc;AAAA,IAClB,QAAQ,EAAE,GAAG,KAAK,SAAS,EAAE;AAAA,IAC7B,SAAS;AAAA,MACP,GAAG;AAAA,MACH,SAAS;AAAA,MACT,YAAY;AAAA,QACV,UAAU;AAAA,QACV,MAAM;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAGA,QAAM,gBAAgB,kBAAkB,6BAAO,SAAS;AACxD,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW;AAAA,MACV,GAAI,mBAAmB;AAAA,QACtB,SAAS;AAAA,QACT,SAAS;AAAA,QACT,UAAU;AAAA,MACZ;AAAA,MAEA;AAAA,sDAAC,SAAI,WAAU,mDACZ;AAAA;AAAA,UAED,6CAAC,cAAW,WAAsB,aAA0B,iBAAkC;AAAA,UAC9F,6CAAC,iBAAc,WAAsB,aAA0B,eAA8B,YAAwB;AAAA,WACvH;AAAA,QAEA,6CAAC,yCACE,wBACC,6CAAC,aAAU,WAAsB,aAA0B,iBAAkC,GAEjG;AAAA;AAAA;AAAA,EACF;AAEJ;AACA,IAAM,aAAa,CAAC,EAAE,WAAW,aAAa,gBAAgB,MAA+E;AAC3I,SACE,6CAAC,SAAI,WAAU,yCACZ,oBAAU,IAAI,CAAC,SACd,6CAAC,WAAuB,MAAM,KAAK,MAAM,aAA0B,WAAW,KAAK,WAAW,IAAK,eAAK,SAA1F,KAAK,GAA2F,CAC/G,GACH;AAEJ;AAEA,IAAM,YAAY,CAAC,EAAE,WAAW,aAAa,gBAAgB,MAA+E;AAC1I,QAAM,sBAAsB,kBAAkB,6BAAO,MAAM;AAC3D,QAAM,qBAAqB;AAAA,IACzB,QAAQ;AAAA,MACN,QAAQ;AAAA,MACR,SAAS;AAAA,MACT,YAAY;AAAA,QACV,UAAU;AAAA,QACV,MAAM;AAAA,MACR;AAAA,IACF;AAAA,IACA,SAAS;AAAA,MACP,QAAQ;AAAA,MACR,SAAS;AAAA,MACT,YAAY;AAAA,QACV,UAAU;AAAA,QACV,MAAM;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,SACE;AAAA,IAAC;AAAA;AAAA,MAAoB,WAAU;AAAA,MAE7B,GAAI,mBAAmB;AAAA,QACrB,SAAS;AAAA,QACT,SAAS;AAAA,QACT,MAAM;AAAA,QACN,UAAU;AAAA,MACZ;AAAA,MAEA,uDAAC,SAAI,WAAU,6CACZ,oBAAU,IAAI,CAAC,SACd,6CAAC,uBAAoC,GAAI,mBAAmB;AAAA,QACxD,SAAS,EAAE,GAAG,KAAK,SAAS,EAAE;AAAA,QAC9B,SAAS,EAAE,GAAG,GAAG,SAAS,EAAE;AAAA,QAC5B,YAAY,EAAE,OAAO,IAAI;AAAA,MAC3B,GACA,uDAAC,iBAAc,MAAM,KAAK,MAAM,aAA0B,WAAW,KAAK,WAAW,QAAS,eAAK,OAAM,KALjF,KAAK,GAM/B,CACD,GACH;AAAA;AAAA,EACF;AAEJ;AAEA,IAAM,gBAAgB,CAAC,EAAE,eAAe,WAAW,MAAwH;AACzK,SACI;AAAA,IAAC;AAAA;AAAA,MACG,SAAS,MAAM,cAAc,CAAC,UAAU;AAAA,MACxC,WAAU;AAAA,MAEZ,uDAAC,aAAU,YAAuB;AAAA;AAAA,EACtC;AAEJ;AAEA,IAAM,UAAU,CAAC,EAAE,MAAM,UAAU,WAAW,YAAY,MAA4F;AACpJ,QAAM,wBAAoB,kBAAAA;AAAA,IACxB,aAAa;AAAA,IACb,cAAc,MAAM,WAAW;AAAA,EACjC;AACA,SACE,6CAAC,YAAAC,SAAA,EAAK,MAAY,gBAAc,MAC9B,uDAAC,OAAE,WAAW,mBAAoB,UAAS,GAC7C;AAEJ;AAEA,IAAM,gBAAgB,CAAC,EAAE,MAAM,UAAU,WAAW,YAAY,MAA4F;AAC1J,QAAM,oBAAoB,GAAG,aAAa,yEAAyE,IAAI,cAAc,MAAM,WAAW,CAAC;AACvJ,SACE,6CAAC,YAAAA,SAAA,EAAK,MAAY,gBAAc,MAC9B,uDAAC,OAAE,WAAW,mBAAoB,UAAS,GAC7C;AAEJ;AAEA,IAAO,iBAAQ;;;AErKf,IAAAC,eAAiB;AA4CX,IAAAC,sBAAA;AARC,IAAM,SAAgC,CAAC;AAAA,EAC5C;AAAA,EACA;AAAA,EACA;AAAA,EACA,YAAY;AACd,MAAM;AACJ,SACE,8CAAC,YAAO,WAAW,iEAAiE,SAAS,IAC3F;AAAA,iDAAC,SAAI,WAAU,uGAAsG;AAAA,IAErH,8CAAC,SAAI,WAAU,kCACb;AAAA,oDAAC,SAAI,WAAU,+CAEb;AAAA,sDAAC,SAAI,WAAU,aACb;AAAA,uDAAC,QAAG,WAAU,gGACX,eAAK,MACR;AAAA,UACA,6CAAC,OAAE,WAAU,0BACV,eAAK,aACR;AAAA,WACF;AAAA,QAGA,8CAAC,SAAI,WAAU,aACb;AAAA,uDAAC,QAAG,WAAU,iDACX,qBAAW,WAAW,OACzB;AAAA,UACA,6CAAC,SAAI,WAAU,2BACZ,qBAAW,WAAW,MAAM,IAAI,CAAC,SAChC;AAAA,YAAC,aAAAC;AAAA,YAAA;AAAA,cAEC,MAAM,KAAK;AAAA,cACX,WAAU;AAAA,cAET,eAAK;AAAA;AAAA,YAJD,KAAK;AAAA,UAKZ,CACD,GACH;AAAA,WACF;AAAA,QAGA,8CAAC,SAAI,WAAU,aACb;AAAA,uDAAC,QAAG,WAAU,iDACX,gBAAM,QACT;AAAA,UACA,6CAAC,SAAI,WAAU,kBACZ,qBAAW,YAAY,IAAI,CAAC,SAC3B;AAAA,YAAC;AAAA;AAAA,cAEC,MAAM,KAAK;AAAA,cACX,WAAU;AAAA,cACV,QAAO;AAAA,cACP,KAAI;AAAA,cAEH,eAAK;AAAA;AAAA,YAND,KAAK;AAAA,UAOZ,CACD,GACH;AAAA,WACF;AAAA,SACF;AAAA,MAGA,6CAAC,SAAI,WAAU,iCACb,wDAAC,SAAI,WAAU,iFACb;AAAA,qDAAC,OAAE,WAAU,yBACV,gBAAM,WACT;AAAA,QACA,8CAAC,SAAI,WAAU,kBACb;AAAA,uDAAC,aAAAA,SAAA,EAAK,MAAK,YAAW,WAAU,iEAC7B,gBAAM,SACT;AAAA,UACA,6CAAC,aAAAA,SAAA,EAAK,MAAK,UAAS,WAAU,iEAC3B,gBAAM,OACT;AAAA,WACF;AAAA,SACF,GACF;AAAA,OACF;AAAA,IAGA,6CAAC,SAAI,WAAU,iGAAgG;AAAA,KACjH;AAEJ;AAEA,IAAO,iBAAQ;;;AC3Hf,IAAAC,gBAAsC;AAEtC,IAAM,mBAAmB,MAA4B;AACnD,QAAM,CAAC,KAAK,MAAM,QAAI,wBAAS,CAAC;AAEhC,QAAM,oBAAgB,2BAAY,MAAM;AACtC,WAAO,aAAW,UAAU,CAAC;AAAA,EAC/B,GAAG,CAAC,CAAC;AAEL,SAAO,CAAC,KAAK,aAAa;AAC5B;AAEA,IAAO,2BAAQ;","names":["import_jsx_runtime","import_framer_motion","import_jsx_runtime","import_jsx_runtime","classNames","Link","import_link","import_jsx_runtime","Link","import_react"]}
package/dist/index.mjs CHANGED
@@ -77,16 +77,19 @@ function SubTitle({ children, title, className = "" }) {
77
77
 
78
78
  // src/layout/Header/index.tsx
79
79
  import { useState } from "react";
80
+ import classNames from "classnames";
80
81
  import Link from "next/link";
81
82
  import { motion as motion2, AnimatePresence } from "framer-motion";
82
83
 
83
84
  // src/layout/Header/BreadIcon.tsx
84
85
  import { jsx as jsx3, jsxs } from "react/jsx-runtime";
86
+ var spanDefaultCls = "w-full h-0.5 bg-black transition-transform duration-300";
87
+ var spanOpacityCls = "w-full h-0.5 bg-black transition-opacity duration-300";
85
88
  function BreadIcon({ isMenuOpen }) {
86
89
  return /* @__PURE__ */ jsxs("div", { className: "w-6 h-5 relative flex flex-col justify-between", children: [
87
- /* @__PURE__ */ jsx3("span", { className: `w-full h-0.5 bg-gray-800 transition-transform duration-300 ${isMenuOpen ? "rotate-45 translate-y-2" : ""}` }),
88
- /* @__PURE__ */ jsx3("span", { className: `w-full h-0.5 bg-gray-800 transition-opacity duration-300 ${isMenuOpen ? "opacity-0" : ""}` }),
89
- /* @__PURE__ */ jsx3("span", { className: `w-full h-0.5 bg-gray-800 transition-transform duration-300 ${isMenuOpen ? "-rotate-45 -translate-y-2" : ""}` })
90
+ /* @__PURE__ */ jsx3("span", { className: `${spanDefaultCls} ${isMenuOpen ? "rotate-45 translate-y-2" : ""}` }),
91
+ /* @__PURE__ */ jsx3("span", { className: `${spanOpacityCls} ${isMenuOpen ? "opacity-0" : ""}` }),
92
+ /* @__PURE__ */ jsx3("span", { className: `${spanDefaultCls} ${isMenuOpen ? "-rotate-45 -translate-y-2" : ""}` })
90
93
  ] });
91
94
  }
92
95
 
@@ -97,7 +100,7 @@ var getActivedCls = (href, selectedKey) => {
97
100
  if (href.includes(selectedKey) || href === "/" && selectedKey === "home") {
98
101
  return "text-purple-600";
99
102
  }
100
- return "text-gray-600";
103
+ return "";
101
104
  };
102
105
  var Header = ({
103
106
  logo,
@@ -107,8 +110,7 @@ var Header = ({
107
110
  }) => {
108
111
  const [isMenuOpen, setIsMenuOpen] = useState(false);
109
112
  const selectedKey = usePathname().split("/")[2] || "home";
110
- console.log("selectedKey>>>", selectedKey);
111
- const baseNavClassName = `fixed top-0 left-0 right-0 z-50 bg-white/80 backdrop-blur-lg border-b border-purple-100 ${className}`;
113
+ const baseNavClassName = classNames(`fixed top-0 left-0 right-0 z-50 bg-white/80 backdrop-blur-lg border-b border-purple-100 text-gray-600`, className);
112
114
  const navVariants = {
113
115
  hidden: { y: -20, opacity: 0 },
114
116
  visible: {
@@ -120,6 +122,32 @@ var Header = ({
120
122
  }
121
123
  }
122
124
  };
125
+ const HeaderWrapper = enableAnimation ? motion2.header : "header";
126
+ return /* @__PURE__ */ jsxs2(
127
+ HeaderWrapper,
128
+ {
129
+ className: baseNavClassName,
130
+ ...enableAnimation && {
131
+ initial: "hidden",
132
+ animate: "visible",
133
+ variants: navVariants
134
+ },
135
+ children: [
136
+ /* @__PURE__ */ jsxs2("div", { className: "container flex items-center justify-between p-4", children: [
137
+ logo,
138
+ /* @__PURE__ */ jsx4(DesktopNav, { menuItems, selectedKey, enableAnimation }),
139
+ /* @__PURE__ */ jsx4(MobileMenuBtn, { menuItems, selectedKey, setIsMenuOpen, isMenuOpen })
140
+ ] }),
141
+ /* @__PURE__ */ jsx4(AnimatePresence, { children: isMenuOpen && /* @__PURE__ */ jsx4(MobileNav, { menuItems, selectedKey, enableAnimation }) })
142
+ ]
143
+ }
144
+ );
145
+ };
146
+ var DesktopNav = ({ menuItems, selectedKey, enableAnimation }) => {
147
+ return /* @__PURE__ */ jsx4("nav", { className: "hidden md:flex items-center space-x-8", children: menuItems.map((item) => /* @__PURE__ */ jsx4(NavLink, { href: item.href, selectedKey, className: item.className?.pc, children: item.label }, item.key)) });
148
+ };
149
+ var MobileNav = ({ menuItems, selectedKey, enableAnimation }) => {
150
+ const MobileMenuComponent = enableAnimation ? motion2.div : "div";
123
151
  const mobileMenuVariants = {
124
152
  hidden: {
125
153
  height: 0,
@@ -138,74 +166,43 @@ var Header = ({
138
166
  }
139
167
  }
140
168
  };
141
- const NavComponent = enableAnimation ? motion2.nav : "nav";
142
- const MobileMenuComponent = enableAnimation ? motion2.div : "div";
143
- console.log("menuItems>>>", menuItems);
144
169
  return /* @__PURE__ */ jsx4(
145
- NavComponent,
170
+ MobileMenuComponent,
146
171
  {
147
- className: baseNavClassName,
172
+ className: "md:hidden overflow-hidden",
148
173
  ...enableAnimation && {
149
174
  initial: "hidden",
150
175
  animate: "visible",
151
- variants: navVariants
176
+ exit: "hidden",
177
+ variants: mobileMenuVariants
152
178
  },
153
- children: /* @__PURE__ */ jsxs2("div", { className: "container mx-auto px-4", children: [
154
- /* @__PURE__ */ jsxs2("div", { className: "flex items-center justify-between h-20", children: [
155
- logo,
156
- /* @__PURE__ */ jsx4("nav", { className: "hidden md:flex items-center space-x-8", children: menuItems.map((item) => (
157
- // <Link
158
- // key={item.key}
159
- // href="/"
160
- // className="flex items-center justify-center gap-2 text-lg font-bold tracking-wide transition-all duration-300 ease-in-out"
161
- // >
162
- // {item.label}
163
- // </Link>
164
- /* @__PURE__ */ jsx4(NavLink, { href: item.href, className: item.className?.pc, selectedKey, children: item.label }, item.key)
165
- )) }),
166
- /* @__PURE__ */ jsx4(
167
- "button",
168
- {
169
- onClick: () => setIsMenuOpen(!isMenuOpen),
170
- className: "md:hidden p-2 hover:bg-purple-50 rounded-lg transition-colors",
171
- children: /* @__PURE__ */ jsx4(BreadIcon, { isMenuOpen })
172
- }
173
- )
174
- ] }),
175
- /* @__PURE__ */ jsx4(AnimatePresence, { children: isMenuOpen && /* @__PURE__ */ jsx4(
176
- MobileMenuComponent,
177
- {
178
- className: "md:hidden overflow-hidden",
179
- ...enableAnimation && {
180
- initial: "hidden",
181
- animate: "visible",
182
- exit: "hidden",
183
- variants: mobileMenuVariants
184
- },
185
- children: /* @__PURE__ */ jsx4("div", { className: "flex flex-col space-y-4 py-4 items-center", children: menuItems.map((item) => /* @__PURE__ */ jsx4(
186
- motion2.div,
187
- {
188
- ...enableAnimation && {
189
- initial: { x: -20, opacity: 0 },
190
- animate: { x: 0, opacity: 1 },
191
- transition: { delay: 0.1 }
192
- },
193
- children: menuItems.map((item2) => /* @__PURE__ */ jsx4(MobileNavLink, { href: item2.href, className: item2.className?.mobile, selectedKey, children: item2.label }, item2.key))
194
- },
195
- item.key
196
- )) })
197
- }
198
- ) })
199
- ] })
179
+ children: /* @__PURE__ */ jsx4("nav", { className: "flex flex-col space-y-4 py-4 items-center", children: menuItems.map((item) => /* @__PURE__ */ jsx4(MobileMenuComponent, { ...enableAnimation && {
180
+ initial: { x: -20, opacity: 0 },
181
+ animate: { x: 0, opacity: 1 },
182
+ transition: { delay: 0.1 }
183
+ }, children: /* @__PURE__ */ jsx4(MobileNavLink, { href: item.href, selectedKey, className: item.className?.mobile, children: item.label }) }, item.key)) })
184
+ }
185
+ );
186
+ };
187
+ var MobileMenuBtn = ({ setIsMenuOpen, isMenuOpen }) => {
188
+ return /* @__PURE__ */ jsx4(
189
+ "button",
190
+ {
191
+ onClick: () => setIsMenuOpen(!isMenuOpen),
192
+ className: "md:hidden p-2 hover:bg-purple-50 rounded-lg transition-colors",
193
+ children: /* @__PURE__ */ jsx4(BreadIcon, { isMenuOpen })
200
194
  }
201
195
  );
202
196
  };
203
197
  var NavLink = ({ href, children, className, selectedKey }) => {
204
- const combinedClassName = `${className || "text-gray-600 hover:text-black transition-colors"} ${getActivedCls(href, selectedKey)}`;
198
+ const combinedClassName = classNames(
199
+ className || "hover:text-black transition-colors",
200
+ getActivedCls(href, selectedKey)
201
+ );
205
202
  return /* @__PURE__ */ jsx4(Link, { href, legacyBehavior: true, children: /* @__PURE__ */ jsx4("a", { className: combinedClassName, children }) });
206
203
  };
207
204
  var MobileNavLink = ({ href, children, className, selectedKey }) => {
208
- const combinedClassName = `${className || "text-lg font-medium text-center text-gray-600 hover:text-purple-600 transition-colors"} ${getActivedCls(href, selectedKey)}`;
205
+ const combinedClassName = `${className || "text-lg font-medium text-center hover:text-purple-600 transition-colors"} ${getActivedCls(href, selectedKey)}`;
209
206
  return /* @__PURE__ */ jsx4(Link, { href, legacyBehavior: true, children: /* @__PURE__ */ jsx4("a", { className: combinedClassName, children }) });
210
207
  };
211
208
  var Header_default = Header;
@@ -265,6 +262,7 @@ var Footer = ({
265
262
  /* @__PURE__ */ jsx5("div", { className: "absolute top-0 left-0 right-0 h-1 bg-gradient-to-r from-purple-600 via-pink-500 to-purple-600" })
266
263
  ] });
267
264
  };
265
+ var Footer_default = Footer;
268
266
 
269
267
  // src/hooks/useForceRerender.ts
270
268
  import { useState as useState2, useCallback } from "react";
@@ -279,7 +277,7 @@ var useForceRerender_default = useForceRerender;
279
277
  export {
280
278
  Button_default as Button,
281
279
  CardTitle,
282
- Footer,
280
+ Footer_default as Footer,
283
281
  Header_default as Header,
284
282
  PageTitle,
285
283
  SectionTitle,
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/components/Button/index.tsx","../src/components/Heading/index.tsx","../src/layout/Header/index.tsx","../src/layout/Header/BreadIcon.tsx","../src/layout/Footer/index.tsx","../src/hooks/useForceRerender.ts"],"sourcesContent":["import React from 'react';\n\nexport interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n variant?: 'primary' | 'secondary' | 'outline';\n size?: 'sm' | 'md' | 'lg';\n}\n\nexport const Button: React.FC<ButtonProps> = ({\n variant = 'primary',\n size = 'md',\n className = '',\n children,\n ...props\n}) => {\n const baseStyles = 'rounded-full font-medium transition-colors';\n \n const variants = {\n primary: 'bg-purple-600 text-white hover:bg-purple-700 shadow-lg shadow-purple-500/20',\n secondary: 'bg-purple-50 text-purple-700 hover:bg-purple-100',\n outline: 'border-2 border-purple-600 text-purple-600 hover:bg-purple-50'\n };\n\n const sizes = {\n sm: 'px-4 py-1.5 text-sm',\n md: 'px-6 py-2 text-sm',\n lg: 'px-8 py-3 text-base'\n };\n\n const classes = `${baseStyles} ${variants[variant]} ${sizes[size]} ${className}`;\n\n return (\n <button className={classes} {...props}>\n {children}\n </button>\n );\n}; \n\nexport default Button;","'use client';\n\nimport { motion } from 'framer-motion';\nimport { ReactNode } from 'react';\n\nexport interface HeadingProps {\n children?: ReactNode;\n className?: string;\n title?: string;\n}\n\n// 頁面主標題:大標題,帶漸變色\nexport function PageTitle({ children, title, className = '' }: HeadingProps) {\n return (\n <motion.h1\n initial={{ opacity: 0, y: 20 }}\n animate={{ opacity: 1, y: 0 }}\n transition={{ duration: 0.8 }}\n className={`text-4xl md:text-5xl font-bold mb-6 bg-gradient-to-r from-purple-600 to-pink-500 bg-clip-text text-transparent ${className}`}\n >\n {title || children}\n </motion.h1>\n );\n}\n\n// 區塊標題:中等大小,帶漸變色\nexport function SectionTitle({ children, title, className = '' }: HeadingProps) {\n return (\n <motion.h2\n initial={{ opacity: 0, y: 20 }}\n animate={{ opacity: 1, y: 0 }}\n transition={{ duration: 0.8, delay: 0.2 }}\n className={`text-3xl font-bold text-center mb-16 bg-gradient-to-r from-purple-600 to-pink-500 bg-clip-text text-transparent ${className}`}\n >\n {title || children}\n </motion.h2>\n );\n}\n\n// 卡片標題:較小,深灰色\nexport function CardTitle({ children, title,className = '' }: HeadingProps) {\n return (\n <motion.h3\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n transition={{ duration: 0.5 }}\n className={`text-2xl font-bold text-gray-800 ${className}`}\n >\n {title || children}\n </motion.h3>\n );\n}\n\n// 區塊子標題:最小,帶圖標位置\nexport function SubTitle({ children, title, className = '' }: HeadingProps) {\n return (\n <motion.h4\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n transition={{ duration: 0.5 }}\n className={`text-lg font-semibold text-gray-800 ${className}`}\n >\n {title || children}\n </motion.h4>\n );\n} \n\nexport default {\n PageTitle,\n SectionTitle,\n CardTitle,\n SubTitle,\n}","'use client';\nimport React, { useState } from 'react';\nimport Link from 'next/link';\nimport { motion, AnimatePresence } from 'framer-motion';\nimport BreadIcon from './BreadIcon';\nimport { usePathname } from 'next/navigation';\nexport interface NavItem {\n key: string;\n href: string;\n label: string;\n className?: {\n pc?: string;\n mobile?: string;\n };\n}\n\nexport interface HeaderProps {\n logo: React.ReactNode;\n menuItems: NavItem[];\n className?: string;\n /** 是否啟用動畫效果 */\n enableAnimation?: boolean;\n}\nconst getActivedCls = (href: string, selectedKey: string) => {\n if(href.includes(selectedKey) || (href === '/' && selectedKey === 'home')) {\n return 'text-purple-600';\n }\n return 'text-gray-600';\n}\nexport const Header: React.FC<HeaderProps> = ({\n logo,\n menuItems,\n className = '',\n enableAnimation = true,\n}) => {\n const [isMenuOpen, setIsMenuOpen] = useState(false);\n const selectedKey = usePathname().split('/')[2] || 'home'; // todo support home\n console.log('selectedKey>>>',selectedKey);\n // 基礎樣式\n const baseNavClassName = `fixed top-0 left-0 right-0 z-50 bg-white/80 backdrop-blur-lg border-b border-purple-100 ${className}`;\n // 動畫配置\n const navVariants = {\n hidden: { y: -20, opacity: 0 },\n visible: { \n y: 0, \n opacity: 1,\n transition: {\n duration: 0.5,\n ease: \"easeOut\"\n }\n }\n };\n\n const mobileMenuVariants = {\n hidden: { \n height: 0,\n opacity: 0,\n transition: {\n duration: 0.3,\n ease: \"easeInOut\"\n }\n },\n visible: { \n height: \"auto\",\n opacity: 1,\n transition: {\n duration: 0.3,\n ease: \"easeInOut\"\n }\n }\n };\n\n // 根據是否啟用動畫返回不同的組件\n const NavComponent = enableAnimation ? motion.nav : 'nav';\n const MobileMenuComponent = enableAnimation ? motion.div : 'div';\nconsole.log('menuItems>>>',menuItems);\n return (\n <NavComponent \n className={baseNavClassName}\n {...(enableAnimation && {\n initial: \"hidden\",\n animate: \"visible\",\n variants: navVariants\n })}\n >\n <div className=\"container mx-auto px-4\">\n <div className=\"flex items-center justify-between h-20\">\n {/* Logo */}\n {logo}\n\n {/* Desktop Navigation */}\n <nav className=\"hidden md:flex items-center space-x-8\">\n {menuItems.map((item) => (\n // <Link\n // key={item.key}\n // href=\"/\"\n // className=\"flex items-center justify-center gap-2 text-lg font-bold tracking-wide transition-all duration-300 ease-in-out\"\n // >\n // {item.label}\n // </Link>\n <NavLink key={item.key} href={item.href} className={item.className?.pc} selectedKey={selectedKey}>\n {item.label}\n </NavLink>\n ))}\n </nav>\n\n {/* Mobile Menu Button */}\n <button \n onClick={() => setIsMenuOpen(!isMenuOpen)}\n className=\"md:hidden p-2 hover:bg-purple-50 rounded-lg transition-colors\"\n >\n <BreadIcon isMenuOpen={isMenuOpen}/>\n </button>\n </div>\n\n {/* Mobile Menu */}\n <AnimatePresence>\n {isMenuOpen && (\n <MobileMenuComponent\n className=\"md:hidden overflow-hidden\"\n {...(enableAnimation && {\n initial: \"hidden\",\n animate: \"visible\",\n exit: \"hidden\",\n variants: mobileMenuVariants\n })}\n >\n <div className=\"flex flex-col space-y-4 py-4 items-center\">\n {menuItems.map((item) => (\n <motion.div\n key={item.key}\n {...(enableAnimation && {\n initial: { x: -20, opacity: 0 },\n animate: { x: 0, opacity: 1 },\n transition: { delay: 0.1 }\n })}\n >\n {\n menuItems.map((item) => (\n <MobileNavLink key={item.key} href={item.href} className={item.className?.mobile} selectedKey={selectedKey}>{item.label}</MobileNavLink>\n ))\n }\n </motion.div>\n ))}\n </div>\n </MobileMenuComponent>\n )}\n </AnimatePresence>\n </div>\n </NavComponent>\n );\n}; \n\n\nconst NavLink = ({ href, children, className, selectedKey }: { href: string; children: React.ReactNode, className?: string, selectedKey: string }) => {\n const combinedClassName = `${className || 'text-gray-600 hover:text-black transition-colors'} ${getActivedCls(href, selectedKey)}`;\n return (\n <Link href={href} legacyBehavior>\n <a className={combinedClassName}>{children}</a>\n </Link>\n );\n};\n\nconst MobileNavLink = ({ href, children, className, selectedKey }: { href: string; children: React.ReactNode, className?: string, selectedKey: string }) => {\n const combinedClassName = `${className || 'text-lg font-medium text-center text-gray-600 hover:text-purple-600 transition-colors'} ${getActivedCls(href, selectedKey)}`;\n return (\n <Link href={href} legacyBehavior>\n <a className={combinedClassName}>{children}</a>\n </Link>\n );\n};\n\nexport default Header;","export default function BreadIcon({isMenuOpen}: {isMenuOpen: boolean}) {\n return (\n <div className=\"w-6 h-5 relative flex flex-col justify-between\">\n <span className={`w-full h-0.5 bg-gray-800 transition-transform duration-300 ${isMenuOpen ? 'rotate-45 translate-y-2' : ''}`} />\n <span className={`w-full h-0.5 bg-gray-800 transition-opacity duration-300 ${isMenuOpen ? 'opacity-0' : ''}`} />\n <span className={`w-full h-0.5 bg-gray-800 transition-transform duration-300 ${isMenuOpen ? '-rotate-45 -translate-y-2' : ''}`} />\n </div>\n )\n}","'use client';\nimport React from 'react';\nimport Link from 'next/link';\n\nexport interface FooterLink {\n href: string;\n title: string;\n}\n\nexport interface FooterTexts {\n copyright: string;\n privacy: string;\n terms: string;\n social: string;\n}\n\nexport interface FooterProps {\n /** 網站基本信息 */\n site: {\n name: string;\n description: string;\n };\n /** 導航鏈接 */\n navigation: {\n /** 快速鏈接區塊 */\n quickLinks: {\n title: string;\n items: FooterLink[];\n };\n /** 社交媒體鏈接 */\n socialLinks: FooterLink[];\n };\n /** 頁腳文本 */\n texts: FooterTexts;\n /** 自定義類名 */\n className?: string;\n}\n\nexport const Footer: React.FC<FooterProps> = ({\n site,\n navigation,\n texts,\n className = '',\n}) => {\n return (\n <footer className={`relative bg-gradient-to-b from-gray-50 to-gray-100 pt-16 pb-6 ${className}`}>\n <div className=\"absolute inset-0 bg-grid-gray-200/25 [mask-image:linear-gradient(0deg,white,rgba(255,255,255,0.6))]\" />\n \n <div className=\"container mx-auto p-4 relative\">\n <div className=\"grid grid-cols-1 md:grid-cols-3 gap-8 mb-12\">\n {/* Brand Section */}\n <div className=\"space-y-4\">\n <h3 className=\"text-xl font-bold bg-gradient-to-r from-purple-600 to-pink-500 bg-clip-text text-transparent\">\n {site.name}\n </h3>\n <p className=\"text-gray-600 max-w-xs\">\n {site.description}\n </p>\n </div>\n\n {/* Quick Links */}\n <div className=\"space-y-4\">\n <h4 className=\"text-sm font-semibold text-gray-900 uppercase\">\n {navigation.quickLinks.title}\n </h4>\n <nav className=\"flex flex-col space-y-2\">\n {navigation.quickLinks.items.map((item) => (\n <Link\n key={item.href}\n href={item.href}\n className=\"text-gray-600 hover:text-purple-600 transition-colors\"\n >\n {item.title}\n </Link>\n ))}\n </nav>\n </div>\n\n {/* Social Links */}\n <div className=\"space-y-4\">\n <h4 className=\"text-sm font-semibold text-gray-900 uppercase\">\n {texts.social}\n </h4>\n <div className=\"flex space-x-4\">\n {navigation.socialLinks.map((link) => (\n <a\n key={link.href}\n href={link.href}\n className=\"text-gray-600 hover:text-purple-600 transition-colors\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n {link.title}\n </a>\n ))}\n </div>\n </div>\n </div>\n\n {/* Bottom Bar */}\n <div className=\"border-t border-gray-200 pt-6\">\n <div className=\"flex flex-col md:flex-row justify-between items-center space-y-4 md:space-y-0\">\n <p className=\"text-sm text-gray-600\">\n {texts.copyright}\n </p>\n <div className=\"flex space-x-6\">\n <Link href=\"/privacy\" className=\"text-sm text-gray-600 hover:text-purple-600 transition-colors\">\n {texts.privacy}\n </Link>\n <Link href=\"/terms\" className=\"text-sm text-gray-600 hover:text-purple-600 transition-colors\">\n {texts.terms}\n </Link>\n </div>\n </div>\n </div>\n </div>\n\n {/* Decorative gradient line */}\n <div className=\"absolute top-0 left-0 right-0 h-1 bg-gradient-to-r from-purple-600 via-pink-500 to-purple-600\" />\n </footer>\n );\n}; ","import { useState, useCallback } from 'react';\n\nconst useForceRerender = (): [number, () => void] => {\n const [key, setKey] = useState(0);\n\n const forceRerender = useCallback(() => {\n setKey(prevKey => prevKey + 1);\n }, []);\n\n return [key, forceRerender];\n};\n\nexport default useForceRerender;"],"mappings":"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","names":["jsx","motion","jsx","jsx","jsxs","motion","item","Link","jsx","jsxs","useState"]}
1
+ {"version":3,"sources":["../src/components/Button/index.tsx","../src/components/Heading/index.tsx","../src/layout/Header/index.tsx","../src/layout/Header/BreadIcon.tsx","../src/layout/Footer/index.tsx","../src/hooks/useForceRerender.ts"],"sourcesContent":["import React from 'react';\n\nexport interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n variant?: 'primary' | 'secondary' | 'outline';\n size?: 'sm' | 'md' | 'lg';\n}\n\nexport const Button: React.FC<ButtonProps> = ({\n variant = 'primary',\n size = 'md',\n className = '',\n children,\n ...props\n}) => {\n const baseStyles = 'rounded-full font-medium transition-colors';\n \n const variants = {\n primary: 'bg-purple-600 text-white hover:bg-purple-700 shadow-lg shadow-purple-500/20',\n secondary: 'bg-purple-50 text-purple-700 hover:bg-purple-100',\n outline: 'border-2 border-purple-600 text-purple-600 hover:bg-purple-50'\n };\n\n const sizes = {\n sm: 'px-4 py-1.5 text-sm',\n md: 'px-6 py-2 text-sm',\n lg: 'px-8 py-3 text-base'\n };\n\n const classes = `${baseStyles} ${variants[variant]} ${sizes[size]} ${className}`;\n\n return (\n <button className={classes} {...props}>\n {children}\n </button>\n );\n}; \n\nexport default Button;","'use client';\n\nimport { motion } from 'framer-motion';\nimport { ReactNode } from 'react';\n\nexport interface HeadingProps {\n children?: ReactNode;\n className?: string;\n title?: string;\n}\n\n// 頁面主標題:大標題,帶漸變色\nexport function PageTitle({ children, title, className = '' }: HeadingProps) {\n return (\n <motion.h1\n initial={{ opacity: 0, y: 20 }}\n animate={{ opacity: 1, y: 0 }}\n transition={{ duration: 0.8 }}\n className={`text-4xl md:text-5xl font-bold mb-6 bg-gradient-to-r from-purple-600 to-pink-500 bg-clip-text text-transparent ${className}`}\n >\n {title || children}\n </motion.h1>\n );\n}\n\n// 區塊標題:中等大小,帶漸變色\nexport function SectionTitle({ children, title, className = '' }: HeadingProps) {\n return (\n <motion.h2\n initial={{ opacity: 0, y: 20 }}\n animate={{ opacity: 1, y: 0 }}\n transition={{ duration: 0.8, delay: 0.2 }}\n className={`text-3xl font-bold text-center mb-16 bg-gradient-to-r from-purple-600 to-pink-500 bg-clip-text text-transparent ${className}`}\n >\n {title || children}\n </motion.h2>\n );\n}\n\n// 卡片標題:較小,深灰色\nexport function CardTitle({ children, title,className = '' }: HeadingProps) {\n return (\n <motion.h3\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n transition={{ duration: 0.5 }}\n className={`text-2xl font-bold text-gray-800 ${className}`}\n >\n {title || children}\n </motion.h3>\n );\n}\n\n// 區塊子標題:最小,帶圖標位置\nexport function SubTitle({ children, title, className = '' }: HeadingProps) {\n return (\n <motion.h4\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n transition={{ duration: 0.5 }}\n className={`text-lg font-semibold text-gray-800 ${className}`}\n >\n {title || children}\n </motion.h4>\n );\n} \n\nexport default {\n PageTitle,\n SectionTitle,\n CardTitle,\n SubTitle,\n}","'use client';\nimport React, { useState } from 'react';\nimport classNames from 'classnames';\nimport Link from 'next/link';\nimport { motion, AnimatePresence } from 'framer-motion';\nimport BreadIcon from './BreadIcon';\nimport { usePathname } from 'next/navigation';\nexport interface NavItem {\n key: string;\n href: string;\n label: string;\n className?: {\n pc?: string;\n mobile?: string;\n };\n}\n\nexport interface HeaderProps {\n logo: React.ReactNode;\n menuItems: NavItem[];\n className?: string;\n /** 是否啟用動畫效果 */\n enableAnimation?: boolean;\n}\nconst getActivedCls = (href: string, selectedKey: string) => {\n if(href.includes(selectedKey) || (href === '/' && selectedKey === 'home')) {\n return 'text-purple-600';\n }\n return '';\n}\nexport const Header: React.FC<HeaderProps> = ({\n logo,\n menuItems,\n className = '',\n enableAnimation = true,\n}) => {\n const [isMenuOpen, setIsMenuOpen] = useState(false);\n const selectedKey = usePathname().split('/')[2] || 'home';\n // 如何解决className 重复的问题,传入值与默认值有重复\n const baseNavClassName = classNames(`fixed top-0 left-0 right-0 z-50 bg-white/80 backdrop-blur-lg border-b border-purple-100 text-gray-600`, className);\n\n // 動畫配置\n const navVariants = {\n hidden: { y: -20, opacity: 0 },\n visible: { \n y: 0, \n opacity: 1,\n transition: {\n duration: 0.5,\n ease: \"easeOut\"\n }\n }\n };\n\n // 根據是否啟用動畫返回不同的組件\n const HeaderWrapper = enableAnimation ? motion.header : 'header';\n return (\n <HeaderWrapper \n className={baseNavClassName}\n {...(enableAnimation && {\n initial: \"hidden\",\n animate: \"visible\",\n variants: navVariants\n })}\n >\n <div className='container flex items-center justify-between p-4'>\n {logo}\n {/* Desktop Navigation */}\n <DesktopNav menuItems={menuItems} selectedKey={selectedKey} enableAnimation={enableAnimation} />\n <MobileMenuBtn menuItems={menuItems} selectedKey={selectedKey} setIsMenuOpen={setIsMenuOpen} isMenuOpen={isMenuOpen} />\n </div>\n {/* Mobile Menu */}\n <AnimatePresence>\n {isMenuOpen && (\n <MobileNav menuItems={menuItems} selectedKey={selectedKey} enableAnimation={enableAnimation} />\n )}\n </AnimatePresence>\n </HeaderWrapper>\n );\n}; \nconst DesktopNav = ({ menuItems, selectedKey, enableAnimation }: { menuItems: NavItem[], selectedKey: string, enableAnimation: boolean }) => {\n return (\n <nav className='hidden md:flex items-center space-x-8'>\n {menuItems.map((item) => (\n <NavLink key={item.key} href={item.href} selectedKey={selectedKey} className={item.className?.pc}>{item.label}</NavLink>\n ))}\n </nav>\n )\n}\n\nconst MobileNav = ({ menuItems, selectedKey, enableAnimation }: { menuItems: NavItem[], selectedKey: string, enableAnimation: boolean }) => {\n const MobileMenuComponent = enableAnimation ? motion.div : 'div';\n const mobileMenuVariants = {\n hidden: { \n height: 0,\n opacity: 0,\n transition: {\n duration: 0.3,\n ease: \"easeInOut\"\n }\n },\n visible: { \n height: \"auto\",\n opacity: 1,\n transition: {\n duration: 0.3,\n ease: \"easeInOut\"\n }\n }\n };\n return (\n <MobileMenuComponent className='md:hidden overflow-hidden'\n {\n ...(enableAnimation && {\n initial: \"hidden\",\n animate: \"visible\",\n exit: \"hidden\",\n variants: mobileMenuVariants\n })\n }>\n <nav className='flex flex-col space-y-4 py-4 items-center'>\n {menuItems.map((item) => (\n <MobileMenuComponent key={item.key} {...(enableAnimation && {\n initial: { x: -20, opacity: 0 },\n animate: { x: 0, opacity: 1 },\n transition: { delay: 0.1 }\n })}>\n <MobileNavLink href={item.href} selectedKey={selectedKey} className={item.className?.mobile}>{item.label}</MobileNavLink>\n </MobileMenuComponent>\n ))}\n </nav>\n </MobileMenuComponent>\n )\n}\n\nconst MobileMenuBtn = ({ setIsMenuOpen, isMenuOpen }: { menuItems: NavItem[], selectedKey: string, setIsMenuOpen: (isMenuOpen: boolean) => void, isMenuOpen: boolean }) => {\n return (\n <button \n onClick={() => setIsMenuOpen(!isMenuOpen)}\n className=\"md:hidden p-2 hover:bg-purple-50 rounded-lg transition-colors\"\n >\n <BreadIcon isMenuOpen={isMenuOpen}/>\n </button>\n )\n}\n\nconst NavLink = ({ href, children, className, selectedKey }: { href: string; children: React.ReactNode, className?: string, selectedKey: string }) => {\n const combinedClassName = classNames(\n className || 'hover:text-black transition-colors',\n getActivedCls(href, selectedKey)\n );\n return (\n <Link href={href} legacyBehavior>\n <a className={combinedClassName}>{children}</a>\n </Link>\n );\n};\n\nconst MobileNavLink = ({ href, children, className, selectedKey }: { href: string; children: React.ReactNode, className?: string, selectedKey: string }) => {\n const combinedClassName = `${className || 'text-lg font-medium text-center hover:text-purple-600 transition-colors'} ${getActivedCls(href, selectedKey)}`;\n return (\n <Link href={href} legacyBehavior>\n <a className={combinedClassName}>{children}</a>\n </Link>\n );\n};\n\nexport default Header;","const spanDefaultCls= 'w-full h-0.5 bg-black transition-transform duration-300'\nconst spanOpacityCls= 'w-full h-0.5 bg-black transition-opacity duration-300'\n\nexport default function BreadIcon({isMenuOpen}: {isMenuOpen: boolean}) {\n return (\n <div className=\"w-6 h-5 relative flex flex-col justify-between\">\n <span className={`${spanDefaultCls} ${isMenuOpen ? 'rotate-45 translate-y-2' : ''}`} />\n <span className={`${spanOpacityCls} ${isMenuOpen ? 'opacity-0' : ''}`} />\n <span className={`${spanDefaultCls} ${isMenuOpen ? '-rotate-45 -translate-y-2' : ''}`} />\n </div>\n )\n}","'use client';\nimport React from 'react';\nimport Link from 'next/link';\n\nexport interface FooterLink {\n href: string;\n title: string;\n}\n\nexport interface FooterTexts {\n copyright: string;\n privacy: string;\n terms: string;\n social: string;\n}\n\nexport interface FooterProps {\n /** 網站基本信息 */\n site: {\n name: string;\n description: string;\n };\n /** 導航鏈接 */\n navigation: {\n /** 快速鏈接區塊 */\n quickLinks: {\n title: string;\n items: FooterLink[];\n };\n /** 社交媒體鏈接 */\n socialLinks: FooterLink[];\n };\n /** 頁腳文本 */\n texts: FooterTexts;\n /** 自定義類名 */\n className?: string;\n}\n\nexport const Footer: React.FC<FooterProps> = ({\n site,\n navigation,\n texts,\n className = '',\n}) => {\n return (\n <footer className={`relative bg-gradient-to-b from-gray-50 to-gray-100 pt-16 pb-6 ${className}`}>\n <div className=\"absolute inset-0 bg-grid-gray-200/25 [mask-image:linear-gradient(0deg,white,rgba(255,255,255,0.6))]\" />\n \n <div className=\"container mx-auto p-4 relative\">\n <div className=\"grid grid-cols-1 md:grid-cols-3 gap-8 mb-12\">\n {/* Brand Section */}\n <div className=\"space-y-4\">\n <h3 className=\"text-xl font-bold bg-gradient-to-r from-purple-600 to-pink-500 bg-clip-text text-transparent\">\n {site.name}\n </h3>\n <p className=\"text-gray-600 max-w-xs\">\n {site.description}\n </p>\n </div>\n\n {/* Quick Links */}\n <div className=\"space-y-4\">\n <h4 className=\"text-sm font-semibold text-gray-900 uppercase\">\n {navigation.quickLinks.title}\n </h4>\n <nav className=\"flex flex-col space-y-2\">\n {navigation.quickLinks.items.map((item) => (\n <Link\n key={item.href}\n href={item.href}\n className=\"text-gray-600 hover:text-purple-600 transition-colors\"\n >\n {item.title}\n </Link>\n ))}\n </nav>\n </div>\n\n {/* Social Links */}\n <div className=\"space-y-4\">\n <h4 className=\"text-sm font-semibold text-gray-900 uppercase\">\n {texts.social}\n </h4>\n <div className=\"flex space-x-4\">\n {navigation.socialLinks.map((link) => (\n <a\n key={link.href}\n href={link.href}\n className=\"text-gray-600 hover:text-purple-600 transition-colors\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n {link.title}\n </a>\n ))}\n </div>\n </div>\n </div>\n\n {/* Bottom Bar */}\n <div className=\"border-t border-gray-200 pt-6\">\n <div className=\"flex flex-col md:flex-row justify-between items-center space-y-4 md:space-y-0\">\n <p className=\"text-sm text-gray-600\">\n {texts.copyright}\n </p>\n <div className=\"flex space-x-6\">\n <Link href=\"/privacy\" className=\"text-sm text-gray-600 hover:text-purple-600 transition-colors\">\n {texts.privacy}\n </Link>\n <Link href=\"/terms\" className=\"text-sm text-gray-600 hover:text-purple-600 transition-colors\">\n {texts.terms}\n </Link>\n </div>\n </div>\n </div>\n </div>\n\n {/* Decorative gradient line */}\n <div className=\"absolute top-0 left-0 right-0 h-1 bg-gradient-to-r from-purple-600 via-pink-500 to-purple-600\" />\n </footer>\n );\n}; \n\nexport default Footer;","import { useState, useCallback } from 'react';\n\nconst useForceRerender = (): [number, () => void] => {\n const [key, setKey] = useState(0);\n\n const forceRerender = useCallback(() => {\n setKey(prevKey => prevKey + 1);\n }, []);\n\n return [key, forceRerender];\n};\n\nexport default useForceRerender;"],"mappings":"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","names":["jsx","motion","jsx","jsx","jsxs","motion","Link","jsx","jsxs","useState"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jean-react-utils",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Jean's personal reusable components, hooks, theme and i18n utils for Next.js projects",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -8,8 +8,7 @@
8
8
  "exports": {
9
9
  ".": {
10
10
  "import": "./dist/index.js",
11
- "require": "./dist/index.cjs",
12
- "types": "./dist/index.d.ts"
11
+ "require": "./dist/index.cjs"
13
12
  }
14
13
  },
15
14
  "files": [
@@ -17,16 +16,6 @@
17
16
  "README.md",
18
17
  "LICENSE"
19
18
  ],
20
- "scripts": {
21
- "dev": "tsup src/index.ts --format esm,cjs --watch --dts --external react",
22
- "build": "tsup src/index.ts",
23
- "test": "vitest",
24
- "lint": "eslint . --ext .ts,.tsx",
25
- "typecheck": "tsc --noEmit",
26
- "clean": "rm -rf .turbo && rm -rf node_modules && rm -rf dist",
27
- "test:watch": "vitest",
28
- "test:coverage": "vitest run --coverage"
29
- },
30
19
  "dependencies": {
31
20
  "classnames": "^2.5.1"
32
21
  },
@@ -35,10 +24,7 @@
35
24
  "@testing-library/user-event": "^14.5.2",
36
25
  "@vitejs/plugin-react": "^4.2.1",
37
26
  "@vitest/coverage-v8": "^1.6.1",
38
- "autoprefixer": "^10.4.21",
39
27
  "happy-dom": "^13.3.8",
40
- "postcss": "^8.5.4",
41
- "tailwindcss": "^4.1.8",
42
28
  "tsup": "^8.0.2",
43
29
  "vitest": "^1.6.1"
44
30
  },
@@ -62,5 +48,15 @@
62
48
  "publishConfig": {
63
49
  "access": "public"
64
50
  },
65
- "license": "MIT"
66
- }
51
+ "license": "MIT",
52
+ "scripts": {
53
+ "dev": "tsup src/index.ts --format esm,cjs --watch --dts --external react",
54
+ "build": "tsup src/index.ts",
55
+ "test": "vitest",
56
+ "lint": "eslint . --ext .ts,.tsx",
57
+ "typecheck": "tsc --noEmit",
58
+ "clean": "rm -rf .turbo && rm -rf node_modules && rm -rf dist",
59
+ "test:watch": "vitest",
60
+ "test:coverage": "vitest run --coverage"
61
+ }
62
+ }