@onexapis/cli 1.1.36 → 1.1.37
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/dist/cli.js +5 -1
- package/dist/cli.js.map +1 -1
- package/dist/cli.mjs +5 -1
- package/dist/cli.mjs.map +1 -1
- package/dist/preview/preview-app.tsx +13 -5
- package/package.json +1 -1
- package/templates/default/AUTH_AND_PROFILE.md +167 -0
- package/templates/default/LAYOUT.md +195 -0
- package/templates/default/bundle-entry.ts +5 -0
- package/templates/default/hooks/index.ts +26 -0
- package/templates/default/hooks/use-forgot-password-form.ts +90 -0
- package/templates/default/hooks/use-login-form.ts +102 -0
- package/templates/default/hooks/use-profile-form.ts +255 -0
- package/templates/default/hooks/use-register-form.ts +154 -0
- package/templates/default/hooks/use-verify-code-form.ts +224 -0
- package/templates/default/index.ts +21 -1
- package/templates/default/pages/forgot-password.ts +41 -0
- package/templates/default/pages/login.ts +41 -0
- package/templates/default/pages/profile.ts +39 -0
- package/templates/default/pages/register.ts +41 -0
- package/templates/default/pages/verify-code.ts +41 -0
- package/templates/default/sections/auth-forgot-password/auth-forgot-password-default.tsx +192 -0
- package/templates/default/sections/auth-forgot-password/auth-forgot-password.schema.ts +150 -0
- package/templates/default/sections/auth-forgot-password/index.ts +14 -0
- package/templates/default/sections/auth-login/auth-login-default.tsx +238 -0
- package/templates/default/sections/auth-login/auth-login.schema.ts +171 -0
- package/templates/default/sections/auth-login/index.ts +14 -0
- package/templates/default/sections/auth-register/auth-register-default.tsx +327 -0
- package/templates/default/sections/auth-register/auth-register.schema.ts +188 -0
- package/templates/default/sections/auth-register/index.ts +14 -0
- package/templates/default/sections/auth-verify-code/auth-verify-code-default.tsx +209 -0
- package/templates/default/sections/auth-verify-code/auth-verify-code.schema.ts +150 -0
- package/templates/default/sections/auth-verify-code/index.ts +14 -0
- package/templates/default/sections/footer/footer-default.tsx +214 -0
- package/templates/default/sections/footer/footer.schema.ts +170 -0
- package/templates/default/sections/footer/index.ts +14 -0
- package/templates/default/sections/header/header-default.tsx +322 -0
- package/templates/default/sections/header/header.schema.ts +168 -0
- package/templates/default/sections/header/index.ts +14 -0
- package/templates/default/sections/profile/index.ts +14 -0
- package/templates/default/sections/profile/profile-default.tsx +522 -0
- package/templates/default/sections/profile/profile.schema.ts +228 -0
- package/templates/default/sections-registry.ts +28 -0
- package/templates/default/theme.layout.ts +53 -2
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Footer Section Schema
|
|
3
|
+
* Responsive footer with company info, links, and copyright
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { SectionSchema, FieldDefinition } from "@onexapis/core/types";
|
|
7
|
+
|
|
8
|
+
const commonSettings: FieldDefinition[] = [
|
|
9
|
+
{
|
|
10
|
+
id: "companyName",
|
|
11
|
+
type: "text",
|
|
12
|
+
label: "Company Name",
|
|
13
|
+
default: "My Site",
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
id: "description",
|
|
17
|
+
type: "textarea",
|
|
18
|
+
label: "Description",
|
|
19
|
+
default: "A clean and minimal theme for your website.",
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
id: "showAboutColumn",
|
|
23
|
+
type: "checkbox",
|
|
24
|
+
label: "Show About Column",
|
|
25
|
+
default: true,
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
id: "aboutColumnTitle",
|
|
29
|
+
type: "text",
|
|
30
|
+
label: "About Column Title",
|
|
31
|
+
default: "About",
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
id: "aboutLinks",
|
|
35
|
+
type: "array",
|
|
36
|
+
label: "About Links",
|
|
37
|
+
default: [
|
|
38
|
+
{ label: "About Us", href: "/about" },
|
|
39
|
+
{ label: "Contact", href: "#contact" },
|
|
40
|
+
],
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
id: "showLinksColumn",
|
|
44
|
+
type: "checkbox",
|
|
45
|
+
label: "Show Links Column",
|
|
46
|
+
default: true,
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
id: "linksColumnTitle",
|
|
50
|
+
type: "text",
|
|
51
|
+
label: "Links Column Title",
|
|
52
|
+
default: "Quick Links",
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
id: "quickLinks",
|
|
56
|
+
type: "array",
|
|
57
|
+
label: "Quick Links",
|
|
58
|
+
default: [
|
|
59
|
+
{ label: "Home", href: "/" },
|
|
60
|
+
{ label: "Showcase", href: "/showcase" },
|
|
61
|
+
],
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
id: "copyrightText",
|
|
65
|
+
type: "text",
|
|
66
|
+
label: "Copyright Text",
|
|
67
|
+
default: "My Site. All rights reserved.",
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
id: "backgroundColor",
|
|
71
|
+
type: "color",
|
|
72
|
+
label: "Background Color",
|
|
73
|
+
default: "#111827",
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
id: "textColor",
|
|
77
|
+
type: "color",
|
|
78
|
+
label: "Text Color",
|
|
79
|
+
default: "#9CA3AF",
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
id: "primaryColor",
|
|
83
|
+
type: "color",
|
|
84
|
+
label: "Heading Color",
|
|
85
|
+
default: "#FFFFFF",
|
|
86
|
+
},
|
|
87
|
+
];
|
|
88
|
+
|
|
89
|
+
export const footerSchema: SectionSchema = {
|
|
90
|
+
type: "my-simple-footer",
|
|
91
|
+
name: "Footer",
|
|
92
|
+
description: "Responsive footer with company info, links, and copyright",
|
|
93
|
+
category: "footer",
|
|
94
|
+
icon: "layout",
|
|
95
|
+
settings: commonSettings,
|
|
96
|
+
templates: [
|
|
97
|
+
{
|
|
98
|
+
id: "default",
|
|
99
|
+
name: "Default Footer",
|
|
100
|
+
description: "3-column footer with company info and links",
|
|
101
|
+
isDefault: true,
|
|
102
|
+
},
|
|
103
|
+
],
|
|
104
|
+
defaults: {
|
|
105
|
+
settings: {
|
|
106
|
+
companyName: "My Site",
|
|
107
|
+
description: "A clean and minimal theme for your website.",
|
|
108
|
+
showAboutColumn: true,
|
|
109
|
+
aboutColumnTitle: "About",
|
|
110
|
+
aboutLinks: [
|
|
111
|
+
{ label: "About Us", href: "/about" },
|
|
112
|
+
{ label: "Contact", href: "#contact" },
|
|
113
|
+
],
|
|
114
|
+
showLinksColumn: true,
|
|
115
|
+
linksColumnTitle: "Quick Links",
|
|
116
|
+
quickLinks: [
|
|
117
|
+
{ label: "Home", href: "/" },
|
|
118
|
+
{ label: "Showcase", href: "/showcase" },
|
|
119
|
+
],
|
|
120
|
+
copyrightText: "My Site. All rights reserved.",
|
|
121
|
+
backgroundColor: "#111827",
|
|
122
|
+
textColor: "#9CA3AF",
|
|
123
|
+
primaryColor: "#FFFFFF",
|
|
124
|
+
},
|
|
125
|
+
components: [
|
|
126
|
+
{
|
|
127
|
+
id: "footer-company-name",
|
|
128
|
+
type: "heading",
|
|
129
|
+
slot: "company-name",
|
|
130
|
+
order: 0,
|
|
131
|
+
content: { text: "My Site", tag: "h3" },
|
|
132
|
+
style: {
|
|
133
|
+
fontSize: "xl",
|
|
134
|
+
fontWeight: "bold",
|
|
135
|
+
color: "#FFFFFF",
|
|
136
|
+
},
|
|
137
|
+
styleMode: "advanced",
|
|
138
|
+
enabled: true,
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
id: "footer-description",
|
|
142
|
+
type: "paragraph",
|
|
143
|
+
slot: "description",
|
|
144
|
+
order: 1,
|
|
145
|
+
content: { text: "A clean and minimal theme for your website." },
|
|
146
|
+
style: {
|
|
147
|
+
fontSize: "sm",
|
|
148
|
+
color: "#9CA3AF",
|
|
149
|
+
lineHeight: "1.625",
|
|
150
|
+
},
|
|
151
|
+
styleMode: "advanced",
|
|
152
|
+
enabled: true,
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
id: "footer-copyright",
|
|
156
|
+
type: "paragraph",
|
|
157
|
+
slot: "copyright",
|
|
158
|
+
order: 2,
|
|
159
|
+
content: { text: "My Site. All rights reserved." },
|
|
160
|
+
style: {
|
|
161
|
+
fontSize: "sm",
|
|
162
|
+
color: "#6B7280",
|
|
163
|
+
},
|
|
164
|
+
styleMode: "advanced",
|
|
165
|
+
enabled: true,
|
|
166
|
+
},
|
|
167
|
+
],
|
|
168
|
+
},
|
|
169
|
+
tags: ["footer", "layout"],
|
|
170
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Footer Section
|
|
3
|
+
* Exports schema and component templates
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { SectionComponentProps } from "@onexapis/core/types";
|
|
7
|
+
import { FooterDefault } from "./footer-default";
|
|
8
|
+
|
|
9
|
+
export const footerComponents: Record<
|
|
10
|
+
string,
|
|
11
|
+
React.ComponentType<SectionComponentProps>
|
|
12
|
+
> = { default: FooterDefault };
|
|
13
|
+
|
|
14
|
+
export { footerSchema } from "./footer.schema";
|
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Header - Default Template
|
|
3
|
+
* Smart responsive header with auto-hide on scroll, sticky, and customizable behavior
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
"use client";
|
|
7
|
+
|
|
8
|
+
import React, { useState, useEffect, useRef, useCallback } from "react";
|
|
9
|
+
import type { SectionComponentProps } from "@onexapis/core/types";
|
|
10
|
+
import coreRenderers from "@onexapis/core/renderers";
|
|
11
|
+
import coreUtils from "@onexapis/core/utils";
|
|
12
|
+
|
|
13
|
+
const { ComponentRenderer } = coreRenderers;
|
|
14
|
+
const { toComponentInstance, getSectionValues, filterEnabledComponents } =
|
|
15
|
+
coreUtils;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Hook for smart header scroll behavior
|
|
19
|
+
* - Hides header on scroll down, shows on scroll up
|
|
20
|
+
* - Tracks whether page is scrolled (for shadow/transparent effects)
|
|
21
|
+
*/
|
|
22
|
+
function useHeaderScroll(options: {
|
|
23
|
+
enabled: boolean;
|
|
24
|
+
threshold: number;
|
|
25
|
+
isEditing: boolean;
|
|
26
|
+
}) {
|
|
27
|
+
const [isVisible, setIsVisible] = useState(true);
|
|
28
|
+
const [isScrolled, setIsScrolled] = useState(false);
|
|
29
|
+
const lastScrollY = useRef(0);
|
|
30
|
+
const ticking = useRef(false);
|
|
31
|
+
|
|
32
|
+
const handleScroll = useCallback(() => {
|
|
33
|
+
if (!ticking.current) {
|
|
34
|
+
requestAnimationFrame(() => {
|
|
35
|
+
const currentScrollY = window.scrollY;
|
|
36
|
+
const scrollDelta = currentScrollY - lastScrollY.current;
|
|
37
|
+
|
|
38
|
+
// Track if page is scrolled past top
|
|
39
|
+
setIsScrolled(currentScrollY > 0);
|
|
40
|
+
|
|
41
|
+
if (options.enabled && !options.isEditing) {
|
|
42
|
+
// Scrolling down past threshold → hide
|
|
43
|
+
if (scrollDelta > options.threshold && currentScrollY > 80) {
|
|
44
|
+
setIsVisible(false);
|
|
45
|
+
}
|
|
46
|
+
// Scrolling up past threshold → show
|
|
47
|
+
else if (scrollDelta < -options.threshold) {
|
|
48
|
+
setIsVisible(true);
|
|
49
|
+
}
|
|
50
|
+
// At the very top → always show
|
|
51
|
+
if (currentScrollY <= 0) {
|
|
52
|
+
setIsVisible(true);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
lastScrollY.current = currentScrollY;
|
|
57
|
+
ticking.current = false;
|
|
58
|
+
});
|
|
59
|
+
ticking.current = true;
|
|
60
|
+
}
|
|
61
|
+
}, [options.enabled, options.threshold, options.isEditing]);
|
|
62
|
+
|
|
63
|
+
useEffect(() => {
|
|
64
|
+
if (typeof window === "undefined") return;
|
|
65
|
+
window.addEventListener("scroll", handleScroll, { passive: true });
|
|
66
|
+
return () => window.removeEventListener("scroll", handleScroll);
|
|
67
|
+
}, [handleScroll]);
|
|
68
|
+
|
|
69
|
+
return { isVisible, isScrolled };
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function HeaderDefault({
|
|
73
|
+
section,
|
|
74
|
+
schema,
|
|
75
|
+
isEditing,
|
|
76
|
+
}: SectionComponentProps) {
|
|
77
|
+
const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
|
|
78
|
+
|
|
79
|
+
const { settings } = getSectionValues(section, schema);
|
|
80
|
+
const {
|
|
81
|
+
logoText,
|
|
82
|
+
sticky,
|
|
83
|
+
autoHide,
|
|
84
|
+
scrollThreshold,
|
|
85
|
+
showShadowOnScroll,
|
|
86
|
+
transparentOnTop,
|
|
87
|
+
headerHeight,
|
|
88
|
+
ctaText,
|
|
89
|
+
ctaLink,
|
|
90
|
+
backgroundColor,
|
|
91
|
+
textColor,
|
|
92
|
+
primaryColor,
|
|
93
|
+
} = settings;
|
|
94
|
+
|
|
95
|
+
const bgColor = String(backgroundColor || "#FFFFFF");
|
|
96
|
+
const txtColor = String(textColor || "#111827");
|
|
97
|
+
const btnColor = String(primaryColor || "#2563EB");
|
|
98
|
+
const height = String(headerHeight || "16");
|
|
99
|
+
const heightClass = `h-${height}`;
|
|
100
|
+
|
|
101
|
+
// Smart scroll behavior
|
|
102
|
+
const { isVisible, isScrolled } = useHeaderScroll({
|
|
103
|
+
enabled: Boolean(autoHide),
|
|
104
|
+
threshold: Number(scrollThreshold) || 10,
|
|
105
|
+
isEditing: !!isEditing,
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
// Build dynamic classes and styles
|
|
109
|
+
const isSticky = Boolean(sticky);
|
|
110
|
+
const shouldShowShadow = Boolean(showShadowOnScroll) && isScrolled;
|
|
111
|
+
const isTransparentOnTop = Boolean(transparentOnTop) && !isScrolled;
|
|
112
|
+
|
|
113
|
+
// Find components from schema defaults
|
|
114
|
+
const components = filterEnabledComponents(section.components || []);
|
|
115
|
+
const logoComp = components.find(
|
|
116
|
+
(c) => c.slot === "logo" || c.id === "header-logo"
|
|
117
|
+
);
|
|
118
|
+
const ctaComp = components.find(
|
|
119
|
+
(c) => c.slot === "cta" || c.id === "header-cta"
|
|
120
|
+
);
|
|
121
|
+
|
|
122
|
+
// Parse navigation items from settings
|
|
123
|
+
let navItems: Array<{ label: string; href: string }> = [];
|
|
124
|
+
try {
|
|
125
|
+
const raw = settings.navigationItems;
|
|
126
|
+
if (typeof raw === "string") {
|
|
127
|
+
navItems = JSON.parse(raw);
|
|
128
|
+
} else if (Array.isArray(raw)) {
|
|
129
|
+
navItems = raw as Array<{ label: string; href: string }>;
|
|
130
|
+
}
|
|
131
|
+
} catch {
|
|
132
|
+
navItems = [
|
|
133
|
+
{ label: "Home", href: "/" },
|
|
134
|
+
{ label: "About", href: "/about" },
|
|
135
|
+
{ label: "Showcase", href: "/showcase" },
|
|
136
|
+
];
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
return (
|
|
140
|
+
<header
|
|
141
|
+
className={`w-full transition-all duration-300 ease-in-out ${
|
|
142
|
+
isSticky ? "sticky top-0 z-50" : ""
|
|
143
|
+
}`}
|
|
144
|
+
style={{
|
|
145
|
+
backgroundColor: isTransparentOnTop ? "transparent" : bgColor,
|
|
146
|
+
boxShadow: shouldShowShadow
|
|
147
|
+
? "0 1px 3px 0 rgba(0,0,0,0.1), 0 1px 2px -1px rgba(0,0,0,0.1)"
|
|
148
|
+
: "none",
|
|
149
|
+
transform:
|
|
150
|
+
isSticky && !isVisible && !isEditing
|
|
151
|
+
? "translateY(-100%)"
|
|
152
|
+
: "translateY(0)",
|
|
153
|
+
}}
|
|
154
|
+
data-section-id={section.id}
|
|
155
|
+
data-section-type={section.type}
|
|
156
|
+
data-section-template="default"
|
|
157
|
+
>
|
|
158
|
+
<div className="container mx-auto px-4">
|
|
159
|
+
<div className={`flex ${heightClass} items-center justify-between`}>
|
|
160
|
+
{/* Logo */}
|
|
161
|
+
{isEditing ? (
|
|
162
|
+
<span className="flex items-center">
|
|
163
|
+
{logoComp ? (
|
|
164
|
+
<ComponentRenderer
|
|
165
|
+
instance={toComponentInstance(logoComp)}
|
|
166
|
+
sectionId={section.id}
|
|
167
|
+
isEditing={isEditing}
|
|
168
|
+
/>
|
|
169
|
+
) : (
|
|
170
|
+
<span className="text-xl font-bold" style={{ color: txtColor }}>
|
|
171
|
+
{String(logoText)}
|
|
172
|
+
</span>
|
|
173
|
+
)}
|
|
174
|
+
</span>
|
|
175
|
+
) : (
|
|
176
|
+
<a href="/" className="flex items-center">
|
|
177
|
+
{logoComp ? (
|
|
178
|
+
<ComponentRenderer
|
|
179
|
+
instance={toComponentInstance(logoComp)}
|
|
180
|
+
sectionId={section.id}
|
|
181
|
+
isEditing={isEditing}
|
|
182
|
+
/>
|
|
183
|
+
) : (
|
|
184
|
+
<span className="text-xl font-bold" style={{ color: txtColor }}>
|
|
185
|
+
{String(logoText)}
|
|
186
|
+
</span>
|
|
187
|
+
)}
|
|
188
|
+
</a>
|
|
189
|
+
)}
|
|
190
|
+
|
|
191
|
+
{/* Desktop Navigation */}
|
|
192
|
+
<nav className="hidden md:flex items-center gap-6">
|
|
193
|
+
{navItems.map((item, i) =>
|
|
194
|
+
isEditing ? (
|
|
195
|
+
<span
|
|
196
|
+
key={i}
|
|
197
|
+
className="text-sm font-medium opacity-70"
|
|
198
|
+
style={{ color: txtColor }}
|
|
199
|
+
>
|
|
200
|
+
{item.label}
|
|
201
|
+
</span>
|
|
202
|
+
) : (
|
|
203
|
+
<a
|
|
204
|
+
key={i}
|
|
205
|
+
href={item.href}
|
|
206
|
+
className="text-sm font-medium hover:opacity-70 transition-opacity"
|
|
207
|
+
style={{ color: txtColor }}
|
|
208
|
+
>
|
|
209
|
+
{item.label}
|
|
210
|
+
</a>
|
|
211
|
+
)
|
|
212
|
+
)}
|
|
213
|
+
|
|
214
|
+
{/* CTA Button */}
|
|
215
|
+
{ctaComp ? (
|
|
216
|
+
<ComponentRenderer
|
|
217
|
+
instance={toComponentInstance(ctaComp)}
|
|
218
|
+
sectionId={section.id}
|
|
219
|
+
isEditing={isEditing}
|
|
220
|
+
/>
|
|
221
|
+
) : ctaText ? (
|
|
222
|
+
isEditing ? (
|
|
223
|
+
<span
|
|
224
|
+
className="px-4 py-2 text-sm font-medium text-white rounded-lg"
|
|
225
|
+
style={{ backgroundColor: btnColor }}
|
|
226
|
+
>
|
|
227
|
+
{String(ctaText)}
|
|
228
|
+
</span>
|
|
229
|
+
) : (
|
|
230
|
+
<a
|
|
231
|
+
href={String(ctaLink || "#")}
|
|
232
|
+
className="px-4 py-2 text-sm font-medium text-white rounded-lg hover:opacity-90 transition-opacity"
|
|
233
|
+
style={{ backgroundColor: btnColor }}
|
|
234
|
+
>
|
|
235
|
+
{String(ctaText)}
|
|
236
|
+
</a>
|
|
237
|
+
)
|
|
238
|
+
) : null}
|
|
239
|
+
</nav>
|
|
240
|
+
|
|
241
|
+
{/* Mobile Menu Button */}
|
|
242
|
+
<button
|
|
243
|
+
className="md:hidden"
|
|
244
|
+
style={{ color: txtColor }}
|
|
245
|
+
onClick={() => setMobileMenuOpen(!mobileMenuOpen)}
|
|
246
|
+
aria-label="Toggle menu"
|
|
247
|
+
>
|
|
248
|
+
<svg
|
|
249
|
+
className="w-6 h-6"
|
|
250
|
+
fill="none"
|
|
251
|
+
stroke="currentColor"
|
|
252
|
+
viewBox="0 0 24 24"
|
|
253
|
+
>
|
|
254
|
+
{mobileMenuOpen ? (
|
|
255
|
+
<path
|
|
256
|
+
strokeLinecap="round"
|
|
257
|
+
strokeLinejoin="round"
|
|
258
|
+
strokeWidth={2}
|
|
259
|
+
d="M6 18L18 6M6 6l12 12"
|
|
260
|
+
/>
|
|
261
|
+
) : (
|
|
262
|
+
<path
|
|
263
|
+
strokeLinecap="round"
|
|
264
|
+
strokeLinejoin="round"
|
|
265
|
+
strokeWidth={2}
|
|
266
|
+
d="M4 6h16M4 12h16M4 18h16"
|
|
267
|
+
/>
|
|
268
|
+
)}
|
|
269
|
+
</svg>
|
|
270
|
+
</button>
|
|
271
|
+
</div>
|
|
272
|
+
|
|
273
|
+
{/* Mobile Menu */}
|
|
274
|
+
{mobileMenuOpen && (
|
|
275
|
+
<nav className="md:hidden border-t py-4 space-y-3">
|
|
276
|
+
{navItems.map((item, i) =>
|
|
277
|
+
isEditing ? (
|
|
278
|
+
<span
|
|
279
|
+
key={i}
|
|
280
|
+
className="block text-sm font-medium opacity-70"
|
|
281
|
+
style={{ color: txtColor }}
|
|
282
|
+
>
|
|
283
|
+
{item.label}
|
|
284
|
+
</span>
|
|
285
|
+
) : (
|
|
286
|
+
<a
|
|
287
|
+
key={i}
|
|
288
|
+
href={item.href}
|
|
289
|
+
className="block text-sm font-medium hover:opacity-70 transition-opacity"
|
|
290
|
+
style={{ color: txtColor }}
|
|
291
|
+
onClick={() => setMobileMenuOpen(false)}
|
|
292
|
+
>
|
|
293
|
+
{item.label}
|
|
294
|
+
</a>
|
|
295
|
+
)
|
|
296
|
+
)}
|
|
297
|
+
{ctaText &&
|
|
298
|
+
(isEditing ? (
|
|
299
|
+
<span
|
|
300
|
+
className="block text-center px-4 py-2 text-sm font-medium text-white rounded-lg"
|
|
301
|
+
style={{ backgroundColor: btnColor }}
|
|
302
|
+
>
|
|
303
|
+
{String(ctaText)}
|
|
304
|
+
</span>
|
|
305
|
+
) : (
|
|
306
|
+
<a
|
|
307
|
+
href={String(ctaLink || "#")}
|
|
308
|
+
className="block text-center px-4 py-2 text-sm font-medium text-white rounded-lg hover:opacity-90 transition-opacity"
|
|
309
|
+
style={{ backgroundColor: btnColor }}
|
|
310
|
+
onClick={() => setMobileMenuOpen(false)}
|
|
311
|
+
>
|
|
312
|
+
{String(ctaText)}
|
|
313
|
+
</a>
|
|
314
|
+
))}
|
|
315
|
+
</nav>
|
|
316
|
+
)}
|
|
317
|
+
</div>
|
|
318
|
+
</header>
|
|
319
|
+
);
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
export default HeaderDefault;
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Header Section Schema
|
|
3
|
+
* Responsive header with logo, navigation, and CTA
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { SectionSchema, FieldDefinition } from "@onexapis/core/types";
|
|
7
|
+
|
|
8
|
+
const commonSettings: FieldDefinition[] = [
|
|
9
|
+
{
|
|
10
|
+
id: "logoText",
|
|
11
|
+
type: "text",
|
|
12
|
+
label: "Logo Text",
|
|
13
|
+
default: "My Site",
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
id: "sticky",
|
|
17
|
+
type: "checkbox",
|
|
18
|
+
label: "Sticky Header",
|
|
19
|
+
default: true,
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
id: "autoHide",
|
|
23
|
+
type: "checkbox",
|
|
24
|
+
label: "Auto-hide on Scroll Down",
|
|
25
|
+
default: true,
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
id: "scrollThreshold",
|
|
29
|
+
type: "number",
|
|
30
|
+
label: "Scroll Threshold (px)",
|
|
31
|
+
default: 10,
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
id: "showShadowOnScroll",
|
|
35
|
+
type: "checkbox",
|
|
36
|
+
label: "Show Shadow When Scrolled",
|
|
37
|
+
default: true,
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
id: "transparentOnTop",
|
|
41
|
+
type: "checkbox",
|
|
42
|
+
label: "Transparent When at Top",
|
|
43
|
+
default: false,
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
id: "headerHeight",
|
|
47
|
+
type: "select",
|
|
48
|
+
label: "Header Height",
|
|
49
|
+
default: "16",
|
|
50
|
+
options: [
|
|
51
|
+
{ label: "Compact (48px)", value: "12" },
|
|
52
|
+
{ label: "Default (64px)", value: "16" },
|
|
53
|
+
{ label: "Tall (80px)", value: "20" },
|
|
54
|
+
],
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
id: "navigationItems",
|
|
58
|
+
type: "array",
|
|
59
|
+
label: "Navigation Items",
|
|
60
|
+
default: [
|
|
61
|
+
{ label: "Home", href: "/" },
|
|
62
|
+
{ label: "About", href: "/about" },
|
|
63
|
+
{ label: "Showcase", href: "/showcase" },
|
|
64
|
+
],
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
id: "ctaText",
|
|
68
|
+
type: "text",
|
|
69
|
+
label: "CTA Button Text",
|
|
70
|
+
default: "Contact",
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
id: "ctaLink",
|
|
74
|
+
type: "url",
|
|
75
|
+
label: "CTA Button Link",
|
|
76
|
+
default: "#contact",
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
id: "backgroundColor",
|
|
80
|
+
type: "color",
|
|
81
|
+
label: "Background Color",
|
|
82
|
+
default: "#FFFFFF",
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
id: "textColor",
|
|
86
|
+
type: "color",
|
|
87
|
+
label: "Text Color",
|
|
88
|
+
default: "#111827",
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
id: "primaryColor",
|
|
92
|
+
type: "color",
|
|
93
|
+
label: "CTA Button Color",
|
|
94
|
+
default: "#2563EB",
|
|
95
|
+
},
|
|
96
|
+
];
|
|
97
|
+
|
|
98
|
+
export const headerSchema: SectionSchema = {
|
|
99
|
+
type: "my-simple-header",
|
|
100
|
+
name: "Header",
|
|
101
|
+
description: "Responsive header with logo, navigation, and CTA button",
|
|
102
|
+
category: "header",
|
|
103
|
+
icon: "layout",
|
|
104
|
+
settings: commonSettings,
|
|
105
|
+
templates: [
|
|
106
|
+
{
|
|
107
|
+
id: "default",
|
|
108
|
+
name: "Default Header",
|
|
109
|
+
description: "Clean header with horizontal navigation",
|
|
110
|
+
isDefault: true,
|
|
111
|
+
},
|
|
112
|
+
],
|
|
113
|
+
defaults: {
|
|
114
|
+
settings: {
|
|
115
|
+
logoText: "My Site",
|
|
116
|
+
sticky: true,
|
|
117
|
+
autoHide: true,
|
|
118
|
+
scrollThreshold: 10,
|
|
119
|
+
showShadowOnScroll: true,
|
|
120
|
+
transparentOnTop: false,
|
|
121
|
+
headerHeight: "16",
|
|
122
|
+
navigationItems: [
|
|
123
|
+
{ label: "Home", href: "/" },
|
|
124
|
+
{ label: "About", href: "/about" },
|
|
125
|
+
{ label: "Showcase", href: "/showcase" },
|
|
126
|
+
],
|
|
127
|
+
ctaText: "Contact",
|
|
128
|
+
ctaLink: "#contact",
|
|
129
|
+
backgroundColor: "#FFFFFF",
|
|
130
|
+
textColor: "#111827",
|
|
131
|
+
primaryColor: "#2563EB",
|
|
132
|
+
},
|
|
133
|
+
components: [
|
|
134
|
+
{
|
|
135
|
+
id: "header-logo",
|
|
136
|
+
type: "heading",
|
|
137
|
+
slot: "logo",
|
|
138
|
+
order: 0,
|
|
139
|
+
content: { text: "My Site", tag: "span" },
|
|
140
|
+
style: {
|
|
141
|
+
fontSize: "xl",
|
|
142
|
+
fontWeight: "bold",
|
|
143
|
+
color: "#111827",
|
|
144
|
+
},
|
|
145
|
+
styleMode: "advanced",
|
|
146
|
+
enabled: true,
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
id: "header-cta",
|
|
150
|
+
type: "button",
|
|
151
|
+
slot: "cta",
|
|
152
|
+
order: 1,
|
|
153
|
+
content: { text: "Contact", href: "#contact" },
|
|
154
|
+
style: {
|
|
155
|
+
fontSize: "sm",
|
|
156
|
+
fontWeight: "medium",
|
|
157
|
+
color: "#FFFFFF",
|
|
158
|
+
backgroundColor: "#2563EB",
|
|
159
|
+
padding: "0.5rem 1rem",
|
|
160
|
+
borderRadius: "0.5rem",
|
|
161
|
+
},
|
|
162
|
+
styleMode: "advanced",
|
|
163
|
+
enabled: true,
|
|
164
|
+
},
|
|
165
|
+
],
|
|
166
|
+
},
|
|
167
|
+
tags: ["header", "navigation", "layout"],
|
|
168
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Header Section
|
|
3
|
+
* Exports schema and component templates
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { SectionComponentProps } from "@onexapis/core/types";
|
|
7
|
+
import { HeaderDefault } from "./header-default";
|
|
8
|
+
|
|
9
|
+
export const headerComponents: Record<
|
|
10
|
+
string,
|
|
11
|
+
React.ComponentType<SectionComponentProps>
|
|
12
|
+
> = { default: HeaderDefault };
|
|
13
|
+
|
|
14
|
+
export { headerSchema } from "./header.schema";
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Profile Section
|
|
3
|
+
* Exports schema and component templates
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { SectionComponentProps } from "@onexapis/core/types";
|
|
7
|
+
import { ProfileDefault } from "./profile-default";
|
|
8
|
+
|
|
9
|
+
export const profileComponents: Record<
|
|
10
|
+
string,
|
|
11
|
+
React.ComponentType<SectionComponentProps>
|
|
12
|
+
> = { default: ProfileDefault };
|
|
13
|
+
|
|
14
|
+
export { profileSchema } from "./profile.schema";
|