@nextworks/blocks-templates 0.2.0-alpha.7 → 0.2.0-alpha.8

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.
Files changed (62) hide show
  1. package/dist/templates/digitalagency/components/About.jsx +43 -0
  2. package/dist/templates/digitalagency/components/CTA.jsx +31 -0
  3. package/dist/templates/digitalagency/components/Contact.d.ts.map +1 -1
  4. package/dist/templates/digitalagency/components/Contact.jsx +89 -0
  5. package/dist/templates/digitalagency/components/Footer.d.ts +8 -0
  6. package/dist/templates/digitalagency/components/Footer.jsx +58 -0
  7. package/dist/templates/digitalagency/components/Hero.d.ts +7 -0
  8. package/dist/templates/digitalagency/components/Hero.jsx +71 -0
  9. package/dist/templates/digitalagency/components/Navbar.d.ts +20 -0
  10. package/dist/templates/digitalagency/components/Navbar.d.ts.map +1 -1
  11. package/dist/templates/digitalagency/components/Navbar.jsx +1 -1
  12. package/dist/templates/digitalagency/components/NetworkPattern.d.ts +7 -0
  13. package/dist/templates/digitalagency/components/NetworkPattern.d.ts.map +1 -0
  14. package/dist/templates/digitalagency/components/NetworkPattern.jsx +125 -0
  15. package/dist/templates/digitalagency/components/Portfolio.jsx +104 -0
  16. package/dist/templates/gallery/PresetThemeVars.d.ts +15 -0
  17. package/dist/templates/gallery/PresetThemeVars.jsx +2 -2
  18. package/dist/templates/gallery/page.d.ts.map +1 -1
  19. package/dist/templates/gallery/page.jsx +1 -2
  20. package/dist/templates/productlaunch/components/About.d.ts.map +1 -1
  21. package/dist/templates/productlaunch/components/About.jsx +55 -0
  22. package/dist/templates/productlaunch/components/CTA.jsx +37 -0
  23. package/dist/templates/productlaunch/components/Contact.d.ts.map +1 -1
  24. package/dist/templates/productlaunch/components/Contact.jsx +91 -0
  25. package/dist/templates/productlaunch/components/FAQ.d.ts +5 -0
  26. package/dist/templates/productlaunch/components/FAQ.d.ts.map +1 -1
  27. package/dist/templates/productlaunch/components/FAQ.jsx +55 -0
  28. package/dist/templates/productlaunch/components/Features.d.ts +5 -0
  29. package/dist/templates/productlaunch/components/Features.d.ts.map +1 -1
  30. package/dist/templates/productlaunch/components/Features.jsx +50 -0
  31. package/dist/templates/productlaunch/components/Footer.d.ts +5 -0
  32. package/dist/templates/productlaunch/components/Footer.jsx +102 -0
  33. package/dist/templates/productlaunch/components/Hero.d.ts +5 -0
  34. package/dist/templates/productlaunch/components/Hero.d.ts.map +1 -1
  35. package/dist/templates/productlaunch/components/Hero.jsx +68 -0
  36. package/dist/templates/productlaunch/components/Navbar.d.ts +25 -0
  37. package/dist/templates/productlaunch/components/Navbar.jsx +81 -0
  38. package/dist/templates/productlaunch/components/Pricing.d.ts +5 -0
  39. package/dist/templates/productlaunch/components/Pricing.jsx +76 -0
  40. package/dist/templates/productlaunch/components/ProcessTimeline.d.ts +5 -0
  41. package/dist/templates/productlaunch/components/ProcessTimeline.jsx +62 -0
  42. package/dist/templates/productlaunch/components/ServicesGrid.d.ts +5 -0
  43. package/dist/templates/productlaunch/components/ServicesGrid.jsx +40 -0
  44. package/dist/templates/productlaunch/components/Team.d.ts +5 -0
  45. package/dist/templates/productlaunch/components/Team.jsx +71 -0
  46. package/dist/templates/productlaunch/components/Testimonials.d.ts +5 -0
  47. package/dist/templates/productlaunch/components/Testimonials.jsx +54 -0
  48. package/dist/templates/productlaunch/components/TrustBadges.d.ts +5 -0
  49. package/dist/templates/productlaunch/components/TrustBadges.jsx +49 -0
  50. package/dist/templates/saasdashboard/components/Contact.jsx +89 -0
  51. package/dist/templates/saasdashboard/components/Dashboard.d.ts.map +1 -0
  52. package/dist/templates/saasdashboard/components/Dashboard.jsx +168 -0
  53. package/dist/templates/saasdashboard/components/Hero.d.ts.map +1 -1
  54. package/dist/templates/saasdashboard/components/Hero.jsx +0 -1
  55. package/dist/templates/saasdashboard/components/Hero_mask.d.ts.map +1 -1
  56. package/dist/templates/saasdashboard/components/Hero_mask.jsx +0 -1
  57. package/dist/templates/saasdashboard/components/Navbar.d.ts +25 -0
  58. package/dist/templates/saasdashboard/components/Navbar.d.ts.map +1 -1
  59. package/dist/templates/saasdashboard/components/Navbar.jsx +83 -0
  60. package/dist/templates/saasdashboard/components/SmoothScroll.d.ts.map +1 -0
  61. package/dist/templates/saasdashboard/components/SmoothScroll.jsx +86 -0
  62. package/package.json +34 -34
@@ -0,0 +1,168 @@
1
+ "use client";
2
+ import React, { useEffect, useRef, useState } from "react";
3
+ export function Dashboard({ stats, projects, floatingCards, activeTab = "Analytics", navItems = ["Analytics", "Projects", "Team"], }) {
4
+ return (<div className="relative isolate">
5
+ <DashboardMockup stats={stats} projects={projects} activeTab={activeTab} navItems={navItems}/>
6
+
7
+ {floatingCards.map(({ position, icon, text }) => (<FloatingCard key={position} position={position} icon={icon} text={text}/>))}
8
+
9
+ <style>{`
10
+ .dashboard-mockup {
11
+ transform: perspective(1000px) rotateY(-5deg) rotateX(5deg);
12
+ transition: transform 0.3s ease;
13
+ box-shadow: 0 25px 50px rgba(0, 0, 0, 0.3);
14
+ }
15
+ .dashboard-mockup:hover {
16
+ transform: perspective(1000px) rotateY(-2deg) rotateX(2deg);
17
+ }
18
+ .trend-line {
19
+ clip-path: polygon(
20
+ 0 100%,
21
+ 20% 80%,
22
+ 40% 85%,
23
+ 60% 60%,
24
+ 80% 50%,
25
+ 100% 20%
26
+ );
27
+ }
28
+ @keyframes growUp {
29
+ 0% {
30
+ height: 0;
31
+ opacity: 0;
32
+ }
33
+ 100% {
34
+ opacity: 1;
35
+ }
36
+ }
37
+ @keyframes floatAnim {
38
+ 0%,
39
+ 100% {
40
+ transform: translateY(0px);
41
+ }
42
+ 50% {
43
+ transform: translateY(-20px);
44
+ }
45
+ }
46
+ `}</style>
47
+ </div>);
48
+ }
49
+ function DashboardMockup({ stats, projects, activeTab, navItems, }) {
50
+ const [tilt, setTilt] = useState({ rx: 0, ry: 0 });
51
+ const targetTilt = useRef({ rx: 0, ry: 0 });
52
+ const rafId = useRef(null);
53
+ const animate = () => {
54
+ setTilt((prev) => {
55
+ const smoothing = 0.15;
56
+ const nextRx = prev.rx + (targetTilt.current.rx - prev.rx) * smoothing;
57
+ const nextRy = prev.ry + (targetTilt.current.ry - prev.ry) * smoothing;
58
+ return { rx: nextRx, ry: nextRy };
59
+ });
60
+ rafId.current = requestAnimationFrame(animate);
61
+ };
62
+ const handleMove = (e) => {
63
+ const rect = e.currentTarget.getBoundingClientRect();
64
+ const x = e.clientX - rect.left;
65
+ const y = e.clientY - rect.top;
66
+ const rx = (y / rect.height - 0.5) * -6;
67
+ const ry = (x / rect.width - 0.5) * 6;
68
+ targetTilt.current = { rx, ry };
69
+ if (rafId.current == null)
70
+ rafId.current = requestAnimationFrame(animate);
71
+ };
72
+ const handleLeave = () => {
73
+ targetTilt.current = { rx: 0, ry: 0 };
74
+ };
75
+ useEffect(() => {
76
+ return () => {
77
+ if (rafId.current != null)
78
+ cancelAnimationFrame(rafId.current);
79
+ };
80
+ }, []);
81
+ return (<div className={"dashboard-mockup transform-gpu rounded-2xl border border-blue-500/20 p-6 shadow-2xl ring-1 ring-blue-500/10 backdrop-blur transition-transform duration-150 ease-out motion-reduce:transition-none " +
82
+ "bg-slate-900/80 dark:bg-slate-900/80"} style={{
83
+ willChange: "transform",
84
+ transform: `perspective(1000px) rotateX(${tilt.rx}deg) rotateY(${tilt.ry}deg)`,
85
+ }} onMouseMove={handleMove} onMouseLeave={handleLeave}>
86
+ <DashboardHeader activeTab={activeTab} navItems={navItems}/>
87
+ <DashboardGrid stats={stats} projects={projects}/>
88
+ </div>);
89
+ }
90
+ function DashboardHeader({ activeTab = "Analytics", navItems = ["Analytics", "Projects", "Team"], }) {
91
+ return (<div className="mb-6 flex items-center justify-between border-b border-blue-500/10 pb-4">
92
+ <div className="text-[1.1rem] font-semibold text-slate-200">
93
+ Business Overview
94
+ </div>
95
+ <div className="hidden gap-3 md:flex">
96
+ {navItems.map((item) => (<div key={item} className={"rounded-md px-3 py-2 text-sm " +
97
+ (item === activeTab
98
+ ? "bg-gradient-to-br from-blue-500 to-purple-500 text-white"
99
+ : "bg-blue-500/10 text-blue-400")}>
100
+ {item}
101
+ </div>))}
102
+ </div>
103
+ </div>);
104
+ }
105
+ function DashboardGrid({ stats, projects, }) {
106
+ return (<div className="mb-4 grid grid-cols-[2fr_1fr] gap-4">
107
+ <ChartArea />
108
+ <StatsPanel stats={stats}/>
109
+ <ProjectList projects={projects}/>
110
+ </div>);
111
+ }
112
+ function ChartArea() {
113
+ const barHeights = [30, 45, 35, 60, 55, 75, 70, 85, 90, 100];
114
+ return (<div className="relative overflow-hidden rounded-lg border border-blue-500/10 bg-slate-900/50 p-4">
115
+ <div className="mb-2 text-sm text-slate-300">Revenue Growth</div>
116
+ <div className="relative h-32 overflow-hidden rounded-md" style={{
117
+ background: "linear-gradient(45deg, transparent 20%, rgba(59,130,246,0.1) 20%, rgba(59,130,246,0.1) 40%, transparent 40%, transparent 60%, rgba(139,92,246,0.1) 60%, rgba(139,92,246,0.1) 80%, transparent 80%)",
118
+ }}>
119
+ <div className="absolute inset-[10px] flex items-end gap-[3px]">
120
+ {barHeights.map((h, i) => (<div key={i} className="flex-1 rounded-t bg-gradient-to-b from-blue-500 to-purple-500" style={{
121
+ minHeight: "20px",
122
+ height: `${h}%`,
123
+ animation: "growUp 2s ease-out both",
124
+ animationDelay: `${(i + 1) * 0.1}s`,
125
+ }}/>))}
126
+ </div>
127
+ <div className="trend-line absolute top-5 right-[5%] left-[5%] h-[2px] rounded bg-gradient-to-r from-emerald-500 to-blue-500 opacity-80"/>
128
+ </div>
129
+ </div>);
130
+ }
131
+ function StatsPanel({ stats }) {
132
+ return (<div className="flex flex-col gap-2">
133
+ {stats.map((s, i) => (<div key={i} className="rounded-lg border border-blue-500/10 bg-slate-900/50 p-3">
134
+ <div className="text-lg font-bold text-blue-500">{s.value}</div>
135
+ <div className="text-[0.7rem] text-slate-400 uppercase">
136
+ {s.label}
137
+ </div>
138
+ </div>))}
139
+ </div>);
140
+ }
141
+ function ProjectList({ projects }) {
142
+ return (<div className="col-span-2 rounded-lg border border-blue-500/10 bg-slate-900/50 p-4">
143
+ <div className="mb-2 text-sm text-slate-300">Active Projects</div>
144
+ <div className="flex flex-wrap gap-2">
145
+ {projects.map((p, i) => (<div key={i} className="rounded border border-blue-500/30 bg-gradient-to-br from-blue-500/20 to-purple-500/10 px-2 py-2 text-[0.8rem] text-slate-200">
146
+ {p}
147
+ </div>))}
148
+ </div>
149
+ </div>);
150
+ }
151
+ function FloatingCard({ position, icon, text }) {
152
+ const positionClasses = position === "card-1"
153
+ ? "top-[10%] right-[6%]"
154
+ : position === "card-2"
155
+ ? "bottom-[20%] left-[2%]"
156
+ : "top-0 left-0";
157
+ return (<div className={[
158
+ "absolute z-10 transform-gpu rounded-lg border border-blue-500/20 p-4 shadow-lg",
159
+ "animate-[floatAnim_6s_ease-in-out_infinite]",
160
+ "bg-slate-800 dark:bg-slate-900",
161
+ positionClasses,
162
+ ].join(" ")} style={{ willChange: "transform" }}>
163
+ <div className="mb-2 flex h-[30px] w-[30px] items-center justify-center rounded-md bg-gradient-to-br from-blue-500 to-purple-500 text-sm text-white">
164
+ {icon}
165
+ </div>
166
+ <div className="text-sm text-slate-300">{text}</div>
167
+ </div>);
168
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"Hero.d.ts","sourceRoot":"","sources":["../../../../src/templates/saasdashboard/components/Hero.tsx"],"names":[],"mappings":"AAsBA,wBAAgB,IAAI,gCAkFnB"}
1
+ {"version":3,"file":"Hero.d.ts","sourceRoot":"","sources":["../../../../src/templates/saasdashboard/components/Hero.tsx"],"names":[],"mappings":"AAsBA,wBAAgB,IAAI,gCAiFnB"}
@@ -58,7 +58,6 @@ export function Hero() {
58
58
  </div>
59
59
  </div>} imageContainer={{
60
60
  className: "pl-0 relative self-start md:self-start md:flex-none md:shrink-0 w-full h-[24rem] sm:h-[32rem] md:h-[34rem] lg:h-[33rem] md:w-1/2 mb-0 md:mb-0 lg:mb-0 opacity-100",
61
- // "relative self-start md:self-start md:flex-none md:shrink-0 w-full h-[24rem] sm:h-[26rem] md:h-[28rem] md:w-1/2 mb-6 md:mb-0",
62
61
  }} textContainer={{ className: "flex-1 p-5 lg:p-8" }} buttonsContainer={{
63
62
  className: [
64
63
  "flex flex-col sm:flex-row gap-4 mt-8 justify-center lg:justify-start",
@@ -1 +1 @@
1
- {"version":3,"file":"Hero_mask.d.ts","sourceRoot":"","sources":["../../../../src/templates/saasdashboard/components/Hero_mask.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,OAAO,CAAC;AAqB1B,wBAAgB,IAAI,sBAuGnB"}
1
+ {"version":3,"file":"Hero_mask.d.ts","sourceRoot":"","sources":["../../../../src/templates/saasdashboard/components/Hero_mask.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,OAAO,CAAC;AAqB1B,wBAAgB,IAAI,sBAsGnB"}
@@ -76,7 +76,6 @@ export function Hero() {
76
76
  </div>
77
77
  </div>} imageContainer={{
78
78
  className: "relative self-start md:self-start md:flex-none md:shrink-0 w-full h-[24rem] sm:h-[26rem] md:h-[31rem] md:w-1/2 mb-6 md:mb-0",
79
- // "relative self-start md:self-start md:flex-none md:shrink-0 w-full h-[24rem] sm:h-[26rem] md:h-[28rem] md:w-1/2 mb-6 md:mb-0",
80
79
  }} textContainer={{ className: "flex-1 p-5 lg:p-8" }} buttonsContainer={{
81
80
  className: "flex flex-col sm:flex-row gap-4 mt-8 justify-center lg:justify-start",
82
81
  }} textAlign="center" ariaLabel="DashFlow hero section"/>
@@ -0,0 +1,25 @@
1
+ import type { ComponentProps } from "react";
2
+ import { Navbar as SharedNavbar } from "@nextworks/blocks-sections";
3
+ /**
4
+ * SaaS Dashboard preset Navbar
5
+ *
6
+ * - DashFlow branding with blue/purple gradient logo square (brandNode)
7
+ * - Inter font for brand and links
8
+ * - No CTA button (ctaButton = null)
9
+ * - Blue hover states for links and theme toggle
10
+ * - Glassy background with backdrop blur (light/dark)
11
+ *
12
+ * This preset exposes the Shared Navbar API so any prop/slot can be overridden.
13
+ *
14
+ * Example:
15
+ * <Navbar
16
+ * brand="My SaaS"
17
+ * links={{ className: "hover:text-emerald-600" }}
18
+ * container={{ className: "max-w-6xl mx-auto" }}
19
+ * />
20
+ */
21
+ type SharedNavbarProps = ComponentProps<typeof SharedNavbar>;
22
+ type PresetOverrides = Partial<SharedNavbarProps>;
23
+ export declare function Navbar(overrides?: PresetOverrides): import("react").JSX.Element;
24
+ export {};
25
+ //# sourceMappingURL=Navbar.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Navbar.d.ts","sourceRoot":"","sources":["../../../../src/templates/saasdashboard/components/Navbar.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,OAAO,CAAC;AAC5C,OAAO,EAAE,MAAM,IAAI,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAEpE;;;;;;;;;;;;;;;;;GAiBG;AACH,KAAK,iBAAiB,GAAG,cAAc,CAAC,OAAO,YAAY,CAAC,CAAC;AAC7D,KAAK,eAAe,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;AAsFlD,wBAAgB,MAAM,CAAC,SAAS,GAAE,eAAoB,+BAQrD"}
1
+ {"version":3,"file":"Navbar.d.ts","sourceRoot":"","sources":["../../../../src/templates/saasdashboard/components/Navbar.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,OAAO,CAAC;AAC5C,OAAO,EAAE,MAAM,IAAI,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAEpE;;;;;;;;;;;;;;;;;GAiBG;AACH,KAAK,iBAAiB,GAAG,cAAc,CAAC,OAAO,YAAY,CAAC,CAAC;AAC7D,KAAK,eAAe,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;AAqFlD,wBAAgB,MAAM,CAAC,SAAS,GAAE,eAAoB,+BAQrD"}
@@ -0,0 +1,83 @@
1
+ "use client";
2
+ import { Navbar as SharedNavbar } from "@nextworks/blocks-sections";
3
+ const defaultProps = {
4
+ brand: "DashFlow",
5
+ // Preserve custom gradient logo block
6
+ brandNode: (<div className="flex h-8 w-8 items-center justify-center rounded-md bg-gradient-to-br from-blue-600 to-purple-600 font-bold text-white shadow-sm ring-1 ring-white/40">
7
+ DF
8
+ </div>),
9
+ menuItems: [
10
+ { label: "Home", href: "#home" },
11
+ { label: "Features", href: "#features" },
12
+ { label: "Pricing", href: "#pricing" },
13
+ { label: "Contact", href: "#contact" },
14
+ ],
15
+ ctaButton: null,
16
+ showColorModeToggle: true,
17
+ navHeight: "h-16",
18
+ sticky: true,
19
+ ariaLabel: "DashFlow main navigation",
20
+ // Allow layout constraints to be added at page-level
21
+ className: "",
22
+ // Style slots tuned for the blue SaaS theme
23
+ nav: {
24
+ className: "bg-white/60 dark:bg-gray-900/60 backdrop-blur supports-[backdrop-filter]:bg-white/60 supports-[backdrop-filter]:dark:bg-gray-900/60 text-gray-800 dark:text-white " +
25
+ // Accent variables for this preset (read by toggle, links, mobile links)
26
+ "[--navbar-accent:theme(colors.blue.700)] dark:[--navbar-accent:theme(colors.blue.400)] " +
27
+ "[--navbar-toggle-bg:theme(colors.white)] dark:[--navbar-toggle-bg:theme(colors.gray.900)] " +
28
+ "[--navbar-hover-bg:theme(colors.blue.50)] dark:[--navbar-hover-bg:color-mix(in oklab,oklch(0.23 0.05 264) 20%, transparent)] " +
29
+ "[--navbar-ring:theme(colors.blue.500)] dark:[--navbar-ring:theme(colors.blue.400)] " +
30
+ "[--navbar-border:theme(colors.gray.200)] dark:[--navbar-border:theme(colors.gray.800)]",
31
+ },
32
+ brandText: {
33
+ className: "text-xl font-bold font-inter text-blue-700 dark:text-blue-500",
34
+ },
35
+ links: {
36
+ className: "text-sm font-medium font-inter text-gray-800 dark:text-white hover:text-blue-700 dark:hover:text-blue-400 " +
37
+ "focus:ring-[var(--navbar-ring)]",
38
+ },
39
+ // Preset keeps CTA hidden; if enabled, provide subtle interactive defaults
40
+ ctaButtonStyle: {
41
+ variant: "default",
42
+ size: "default",
43
+ className: "shadow-lg hover:shadow-xl transition-all duration-200 hover:-translate-y-0.5",
44
+ },
45
+ mobileMenu: {
46
+ className: "border-t border-gray-200/80 dark:border-gray-800/80",
47
+ },
48
+ container: {
49
+ className: "max-w-7xl mx-auto",
50
+ },
51
+ brandWrapper: {
52
+ className: "",
53
+ },
54
+ desktopMenu: {
55
+ className: "hidden items-center space-x-1 md:flex lg:space-x-6",
56
+ },
57
+ toggleButton: {
58
+ className: "md:hidden flex items-center justify-center rounded-md p-2 transition-colors " +
59
+ "hover:bg-blue-50 dark:hover:bg-blue-900/20 " +
60
+ "focus:outline-none focus:ring-2 focus:ring-blue-500 dark:focus:ring-blue-400",
61
+ },
62
+ colorModeWrapper: {
63
+ className: "ml-2",
64
+ },
65
+ // With variables above, ThemeToggle can rely on them; explicit override optional
66
+ // themeToggle: { ... }
67
+ ctaButtonWrapper: {
68
+ className: "ml-2",
69
+ },
70
+ mobileMenuInner: {
71
+ className: "space-y-2 px-4 pt-2 pb-4",
72
+ },
73
+ // Mobile links will read --navbar-hover-bg; explicit class optional
74
+ mobileLinks: {
75
+ className: "hover:bg-[var(--navbar-hover-bg)]",
76
+ },
77
+ };
78
+ export function Navbar(overrides = {}) {
79
+ // Shallow-merge: passing a style-slot object (e.g., links, nav, etc.)
80
+ // replaces the default for that slot.
81
+ const props = Object.assign(Object.assign({}, defaultProps), overrides);
82
+ return <SharedNavbar {...props}/>;
83
+ }
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SmoothScroll.d.ts","sourceRoot":"","sources":["../../../../src/templates/saasdashboard/components/SmoothScroll.tsx"],"names":[],"mappings":"AAKA,wBAAgB,YAAY,SA0F3B"}
@@ -0,0 +1,86 @@
1
+ "use client";
2
+ import { useEffect } from "react";
3
+ // Smoothly scrolls to section links with a faster duration
4
+ export function SmoothScroll() {
5
+ useEffect(() => {
6
+ let suppressClick = false;
7
+ const animateTo = (href) => {
8
+ const el = document.querySelector(href);
9
+ if (!el)
10
+ return;
11
+ const navbarOffsetPx = 64;
12
+ const start = window.scrollY;
13
+ const targetTop = el.getBoundingClientRect().top + window.scrollY - navbarOffsetPx;
14
+ const distance = targetTop - start;
15
+ const duration = 300;
16
+ const startTime = performance.now();
17
+ const easeOutQuart = (t) => 1 - Math.pow(1 - t, 4);
18
+ const step = (now) => {
19
+ const elapsed = now - startTime;
20
+ const t = Math.min(1, elapsed / duration);
21
+ const eased = easeOutQuart(t);
22
+ window.scrollTo(0, start + distance * eased);
23
+ if (t < 1)
24
+ requestAnimationFrame(step);
25
+ else
26
+ history.replaceState(null, "", href);
27
+ };
28
+ requestAnimationFrame(step);
29
+ };
30
+ const onPointerDown = (e) => {
31
+ const ev = e;
32
+ const target = e.currentTarget;
33
+ const href = target.getAttribute("href");
34
+ if (!href || !href.startsWith("#"))
35
+ return;
36
+ // Only primary button, no modifiers
37
+ if (ev.button !== 0 ||
38
+ ev.metaKey ||
39
+ ev.ctrlKey ||
40
+ ev.altKey ||
41
+ ev.shiftKey)
42
+ return;
43
+ e.preventDefault();
44
+ suppressClick = true;
45
+ animateTo(href);
46
+ };
47
+ const onClick = (e) => {
48
+ const target = e.currentTarget;
49
+ const href = target.getAttribute("href");
50
+ if (!href || !href.startsWith("#"))
51
+ return;
52
+ if (suppressClick) {
53
+ e.preventDefault();
54
+ suppressClick = false;
55
+ return;
56
+ }
57
+ e.preventDefault();
58
+ animateTo(href);
59
+ };
60
+ const onKeyDown = (e) => {
61
+ const ev = e;
62
+ if (ev.key !== "Enter" && ev.key !== " ")
63
+ return;
64
+ const target = e.currentTarget;
65
+ const href = target.getAttribute("href");
66
+ if (!href || !href.startsWith("#"))
67
+ return;
68
+ e.preventDefault();
69
+ animateTo(href);
70
+ };
71
+ const links = Array.from(document.querySelectorAll('a[href^="#"]'));
72
+ links.forEach((a) => {
73
+ a.addEventListener("pointerdown", onPointerDown);
74
+ a.addEventListener("click", onClick);
75
+ a.addEventListener("keydown", onKeyDown);
76
+ });
77
+ return () => {
78
+ links.forEach((a) => {
79
+ a.removeEventListener("pointerdown", onPointerDown);
80
+ a.removeEventListener("click", onClick);
81
+ a.removeEventListener("keydown", onKeyDown);
82
+ });
83
+ };
84
+ }, []);
85
+ return null;
86
+ }
package/package.json CHANGED
@@ -1,34 +1,34 @@
1
- {
2
- "name": "@nextworks/blocks-templates",
3
- "version": "0.2.0-alpha.7",
4
- "private": false,
5
- "main": "dist/index.js",
6
- "types": "dist/index.d.ts",
7
- "files": [
8
- "dist",
9
- "package.json",
10
- "README.md"
11
- ],
12
- "repository": "github:jblh/nextworks-cli",
13
- "bugs": "https://github.com/jblh/nextworks-cli/issues",
14
- "homepage": "https://github.com/jblh/nextworks-cli#readme",
15
- "scripts": {
16
- "build": "npx tsc -p tsconfig.json"
17
- },
18
- "dependencies": {
19
- "@nextworks/blocks-core": "0.2.0-alpha.7",
20
- "@nextworks/blocks-sections": "0.2.0-alpha.7",
21
- "lucide-react": "^0.542.0"
22
- },
23
- "devDependencies": {
24
- "typescript": "^5.9.3",
25
- "@types/node": "^20",
26
- "@types/react": "^19",
27
- "@types/react-dom": "^19"
28
- },
29
- "peerDependencies": {
30
- "react": "^19.0.0",
31
- "react-dom": "^19.0.0",
32
- "next": "^15.0.0 || ^16.0.0"
33
- }
34
- }
1
+ {
2
+ "name": "@nextworks/blocks-templates",
3
+ "version": "0.2.0-alpha.8",
4
+ "private": false,
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "files": [
8
+ "dist",
9
+ "package.json",
10
+ "README.md"
11
+ ],
12
+ "repository": "github:jblh/nextworks-cli",
13
+ "bugs": "https://github.com/jblh/nextworks-cli/issues",
14
+ "homepage": "https://github.com/jblh/nextworks-cli#readme",
15
+ "scripts": {
16
+ "build": "npx tsc -p tsconfig.json"
17
+ },
18
+ "dependencies": {
19
+ "@nextworks/blocks-core": "0.2.0-alpha.8",
20
+ "@nextworks/blocks-sections": "0.2.0-alpha.8",
21
+ "lucide-react": "^0.542.0"
22
+ },
23
+ "devDependencies": {
24
+ "typescript": "^5.9.3",
25
+ "@types/node": "^20",
26
+ "@types/react": "^19",
27
+ "@types/react-dom": "^19"
28
+ },
29
+ "peerDependencies": {
30
+ "react": "^19.0.0",
31
+ "react-dom": "^19.0.0",
32
+ "next": "^15.0.0 || ^16.0.0"
33
+ }
34
+ }