dune-react 0.0.7 → 0.0.9
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/components/puck-base/article-card.js +1 -1
- package/dist/components/puck-base/button.d.ts +1 -0
- package/dist/components/puck-base/button.js +1 -0
- package/dist/components/puck-base/container.d.ts +7 -1
- package/dist/components/puck-base/container.js +2 -1
- package/dist/components/puck-base/content.d.ts +1 -4
- package/dist/components/puck-base/content.js +15 -17
- package/dist/components/puck-base/core/types.d.ts +2 -2
- package/dist/components/puck-base/editor-context.d.ts +12 -0
- package/dist/components/puck-base/fields/auto-field.d.ts +1 -0
- package/dist/components/puck-base/fields/auto-field.js +131 -49
- package/dist/components/puck-base/gradient-text.js +12 -3
- package/dist/components/puck-block/banner-sections/announcement-banner-1/announcement-banner.js +1 -1
- package/dist/components/puck-block/contact-sections/api/form-leads.d.ts +16 -0
- package/dist/components/puck-block/contact-sections/api/form-leads.js +25 -0
- package/dist/components/puck-block/contact-sections/contact-us-1/contact-us.js +27 -11
- package/dist/components/puck-block/contact-sections/contact-us-2/contact-us-2.d.ts +26 -0
- package/dist/components/puck-block/contact-sections/contact-us-2/contact-us-2.js +229 -0
- package/dist/components/puck-block/contact-sections/contact-us-2/index.d.ts +5 -0
- package/dist/components/puck-block/contact-sections/contact-us-2/index.js +72 -0
- package/dist/components/puck-block/contact-sections/contact-us-3/contact-us-3.d.ts +29 -0
- package/dist/components/puck-block/contact-sections/contact-us-3/contact-us-3.js +245 -0
- package/dist/components/puck-block/contact-sections/contact-us-3/index.d.ts +5 -0
- package/dist/components/puck-block/contact-sections/contact-us-3/index.js +101 -0
- package/dist/components/puck-block/cta-sections/banner-cta-1/banner-cta.js +9 -8
- package/dist/components/puck-block/cta-sections/gradient-cta-1/gradient-cta.js +3 -3
- package/dist/components/puck-block/cta-sections/gradient-cta-1/index.js +4 -4
- package/dist/components/puck-block/cta-sections/newsletter-signup-1/newsletter-signup.js +5 -4
- package/dist/components/puck-block/cta-sections/promo-section-1/promo-section.js +6 -5
- package/dist/components/puck-block/faq-sections/faq-2/faq-2.d.ts +16 -0
- package/dist/components/puck-block/faq-sections/faq-2/faq-2.js +56 -0
- package/dist/components/puck-block/faq-sections/faq-2/index.d.ts +5 -0
- package/dist/components/puck-block/faq-sections/faq-2/index.js +62 -0
- package/dist/components/puck-block/feature-sections/feature-cards-1/feature-cards.d.ts +3 -4
- package/dist/components/puck-block/feature-sections/feature-cards-1/feature-cards.js +13 -3
- package/dist/components/puck-block/feature-sections/feature-cards-1/index.js +34 -14
- package/dist/components/puck-block/feature-sections/feature-showcase-1/feature-showcase.js +2 -8
- package/dist/components/puck-block/feature-sections/product-features-1/product-features.js +5 -25
- package/dist/components/puck-block/gallery-sections/gallery-1/gallery.js +3 -2
- package/dist/components/puck-block/gallery-sections/gallery-2/gallery-2.d.ts +14 -0
- package/dist/components/puck-block/gallery-sections/gallery-2/gallery-2.js +88 -0
- package/dist/components/puck-block/gallery-sections/gallery-2/index.d.ts +5 -0
- package/dist/components/puck-block/gallery-sections/gallery-2/index.js +44 -0
- package/dist/components/puck-block/gallery-sections/gallery-3/gallery-3.d.ts +17 -0
- package/dist/components/puck-block/gallery-sections/gallery-3/gallery-3.js +121 -0
- package/dist/components/puck-block/gallery-sections/gallery-3/index.d.ts +5 -0
- package/dist/components/puck-block/gallery-sections/gallery-3/index.js +60 -0
- package/dist/components/puck-block/hero-sections/fullscreen-hero-1/fullscreen-hero.d.ts +6 -1
- package/dist/components/puck-block/hero-sections/fullscreen-hero-1/fullscreen-hero.js +56 -20
- package/dist/components/puck-block/hero-sections/fullscreen-hero-1/index.js +12 -1
- package/dist/components/puck-block/hero-sections/gradient-hero-1/gradient-hero.d.ts +1 -1
- package/dist/components/puck-block/hero-sections/gradient-hero-1/gradient-hero.js +9 -6
- package/dist/components/puck-block/hero-sections/gradient-hero-1/index.js +4 -4
- package/dist/components/puck-block/hero-sections/image-hero-1/image-hero.d.ts +4 -1
- package/dist/components/puck-block/hero-sections/image-hero-1/image-hero.js +60 -62
- package/dist/components/puck-block/index.d.ts +15 -0
- package/dist/components/puck-block/location-sections/location-1/index.d.ts +5 -0
- package/dist/components/puck-block/location-sections/location-1/index.js +103 -0
- package/dist/components/puck-block/location-sections/location-1/location.d.ts +27 -0
- package/dist/components/puck-block/location-sections/location-1/location.js +143 -0
- package/dist/components/puck-block/location-sections/location-2/index.d.ts +5 -0
- package/dist/components/puck-block/location-sections/location-2/index.js +111 -0
- package/dist/components/puck-block/location-sections/location-2/location.d.ts +25 -0
- package/dist/components/puck-block/location-sections/location-2/location.js +136 -0
- package/dist/components/puck-block/location-sections/location-3/index.d.ts +5 -0
- package/dist/components/puck-block/location-sections/location-3/index.js +83 -0
- package/dist/components/puck-block/location-sections/location-3/location.d.ts +22 -0
- package/dist/components/puck-block/location-sections/location-3/location.js +129 -0
- package/dist/components/puck-block/metrics-sections/stats-2/index.d.ts +5 -0
- package/dist/components/puck-block/metrics-sections/stats-2/index.js +77 -0
- package/dist/components/puck-block/metrics-sections/stats-2/stats-2.d.ts +16 -0
- package/dist/components/puck-block/metrics-sections/stats-2/stats-2.js +59 -0
- package/dist/components/puck-block/metrics-sections/stats-3/index.d.ts +5 -0
- package/dist/components/puck-block/metrics-sections/stats-3/index.js +94 -0
- package/dist/components/puck-block/metrics-sections/stats-3/stats-3.d.ts +17 -0
- package/dist/components/puck-block/metrics-sections/stats-3/stats-3.js +60 -0
- package/dist/components/puck-block/pricing-sections/pricing-2/index.d.ts +5 -0
- package/dist/components/puck-block/pricing-sections/pricing-2/index.js +152 -0
- package/dist/components/puck-block/pricing-sections/pricing-2/pricing-2.d.ts +24 -0
- package/dist/components/puck-block/pricing-sections/pricing-2/pricing-2.js +68 -0
- package/dist/components/puck-block/showcase-sections/before-after-1/before-after.d.ts +20 -0
- package/dist/components/puck-block/showcase-sections/before-after-1/before-after.js +73 -0
- package/dist/components/puck-block/showcase-sections/before-after-1/index.d.ts +5 -0
- package/dist/components/puck-block/showcase-sections/before-after-1/index.js +74 -0
- package/dist/components/puck-block/showcase-sections/case-study-1/case-study.js +2 -8
- package/dist/components/puck-block/team-sections/team-grid-1/team-grid.js +4 -24
- package/dist/components/puck-block/team-sections/team-grid-2/index.d.ts +5 -0
- package/dist/components/puck-block/team-sections/team-grid-2/index.js +63 -0
- package/dist/components/puck-block/team-sections/team-grid-2/team-grid-2.d.ts +21 -0
- package/dist/components/puck-block/team-sections/team-grid-2/team-grid-2.js +46 -0
- package/dist/components/puck-block/team-sections/team-profiles-1/index.d.ts +5 -0
- package/dist/components/puck-block/team-sections/team-profiles-1/index.js +54 -0
- package/dist/components/puck-block/team-sections/team-profiles-1/team-profiles.d.ts +21 -0
- package/dist/components/puck-block/team-sections/team-profiles-1/team-profiles.js +107 -0
- package/dist/components/puck-block/testimonial-sections/logo-marquee-1/logo-marquee.js +2 -1
- package/dist/components/puck-block/testimonial-sections/logo-wall-1/index.d.ts +5 -0
- package/dist/components/puck-block/testimonial-sections/logo-wall-1/index.js +50 -0
- package/dist/components/puck-block/testimonial-sections/logo-wall-1/logo-wall.d.ts +15 -0
- package/dist/components/puck-block/testimonial-sections/logo-wall-1/logo-wall.js +57 -0
- package/dist/components/puck-block/testimonial-sections/review-section-1/review-section.js +3 -2
- package/dist/components/puck-block/text-sections/articles-1/articles.d.ts +1 -0
- package/dist/components/puck-block/text-sections/articles-1/articles.js +19 -6
- package/dist/components/puck-block/text-sections/articles-1/index.js +16 -4
- package/dist/components/puck-block/text-sections/content-section-1/content-section.js +5 -4
- package/dist/components/puck-block/text-sections/tab-section-1/tab-section.js +3 -2
- package/dist/components/shadcn/navigation-menu.d.ts +1 -1
- package/dist/components/shadcn/navigation-menu.js +33 -0
- package/dist/index.js +104 -74
- package/package.json +1 -1
|
@@ -10,7 +10,7 @@ const CompoundArticleCard = ({
|
|
|
10
10
|
className
|
|
11
11
|
}) => {
|
|
12
12
|
return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-4", className), children: [
|
|
13
|
-
/* @__PURE__ */ jsx("div", { className: "bg-muted
|
|
13
|
+
image && /* @__PURE__ */ jsx("div", { className: "bg-muted mb-2 aspect-video overflow-hidden rounded-md [&>span]:h-full [&>span]:w-full", children: /* @__PURE__ */ jsx(CompoundImage, { src: image.src || "", alt: image.alt, className: "h-full w-full object-cover" }) }),
|
|
14
14
|
!!heading || !!description || !!button ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
|
|
15
15
|
heading ? /* @__PURE__ */ jsx("h3", { className: "text-xl tracking-tight", children: heading }) : null,
|
|
16
16
|
description ? /* @__PURE__ */ jsx("p", { className: "text-muted-foreground max-w-xs text-base", children: description }) : null,
|
|
@@ -8,6 +8,7 @@ export interface CompoundButtonProps {
|
|
|
8
8
|
size?: ButtonProps["size"];
|
|
9
9
|
icon?: IconName;
|
|
10
10
|
type?: "button" | "submit" | "reset";
|
|
11
|
+
disabled?: boolean;
|
|
11
12
|
className?: string;
|
|
12
13
|
}
|
|
13
14
|
export declare const CompoundButton: (props: CompoundButtonProps) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ReactNode } from "react";
|
|
1
|
+
import { CSSProperties, ReactNode } from "react";
|
|
2
2
|
type PaddingLevel = "none" | "small" | "medium" | "large";
|
|
3
3
|
export type SectionStyle = "default" | "dark" | "muted" | "inverted" | "custom";
|
|
4
4
|
export type OverlayStyle = "none" | "gradient-top" | "gradient-bottom" | "noise";
|
|
@@ -14,5 +14,11 @@ export interface CompoundContainerProps {
|
|
|
14
14
|
overlay?: OverlayStyle;
|
|
15
15
|
className?: string;
|
|
16
16
|
}
|
|
17
|
+
/**
|
|
18
|
+
* Section-scoped CSS variable presets.
|
|
19
|
+
* These override the root-level CSS variables so child components
|
|
20
|
+
* using `bg-background`, `text-foreground` etc. automatically adapt.
|
|
21
|
+
*/
|
|
22
|
+
export declare const SECTION_STYLE_VARS: Record<string, CSSProperties>;
|
|
17
23
|
export declare const CompoundContainer: ({ children, padding, sectionStyle, backgroundColor, backgroundImage, overlay, className, }: CompoundContainerProps) => import("react/jsx-runtime").JSX.Element;
|
|
18
24
|
export {};
|
|
@@ -9,9 +9,6 @@ export interface CompoundContentProps {
|
|
|
9
9
|
buttons?: CompoundButtonProps[];
|
|
10
10
|
alignContent?: "start" | "center" | "end";
|
|
11
11
|
className?: string;
|
|
12
|
-
}
|
|
13
|
-
interface CompoundContentPropsWithSpacing extends CompoundContentProps {
|
|
14
12
|
spacing?: "normal" | "tight";
|
|
15
13
|
}
|
|
16
|
-
export declare const CompoundContent: ({ badge, heading, description, features, buttons, alignContent, className, spacing, }:
|
|
17
|
-
export {};
|
|
14
|
+
export declare const CompoundContent: ({ badge, heading, description, features, buttons, alignContent, className, spacing, }: CompoundContentProps) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -61,7 +61,7 @@ const CompoundContent = ({
|
|
|
61
61
|
"h2",
|
|
62
62
|
{
|
|
63
63
|
className: cn(
|
|
64
|
-
"text-3xl md:text-5xl
|
|
64
|
+
"font-serif font-regular text-3xl tracking-tighter md:text-5xl lg:max-w-xl",
|
|
65
65
|
textAlignClassnames
|
|
66
66
|
),
|
|
67
67
|
children: heading
|
|
@@ -71,7 +71,7 @@ const CompoundContent = ({
|
|
|
71
71
|
"p",
|
|
72
72
|
{
|
|
73
73
|
className: cn(
|
|
74
|
-
"text-lg leading-relaxed tracking-tight
|
|
74
|
+
"text-muted-foreground text-lg leading-relaxed tracking-tight",
|
|
75
75
|
{
|
|
76
76
|
"lg:max-w-sm": alignContent === "start" || alignContent === "end",
|
|
77
77
|
"lg:max-w-xl": alignContent === "center"
|
|
@@ -86,7 +86,7 @@ const CompoundContent = ({
|
|
|
86
86
|
DynamicIcon,
|
|
87
87
|
{
|
|
88
88
|
name: feature.icon,
|
|
89
|
-
className: "
|
|
89
|
+
className: "h-6 w-6 shrink-0"
|
|
90
90
|
}
|
|
91
91
|
) : null,
|
|
92
92
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
|
|
@@ -98,20 +98,18 @@ const CompoundContent = ({
|
|
|
98
98
|
}
|
|
99
99
|
)
|
|
100
100
|
] }) : null,
|
|
101
|
-
Array.isArray(buttons) && buttons.length > 0 ? /* @__PURE__ */ jsx("div", { className: cn("gap-4
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
) : null
|
|
114
|
-
) }) : null
|
|
101
|
+
Array.isArray(buttons) && buttons.length > 0 ? /* @__PURE__ */ jsx("div", { className: cn("flex-wrap gap-4", rowPositionClassNames), children: buttons.filter((button) => !!button.label).map((button, index) => /* @__PURE__ */ jsx(
|
|
102
|
+
CompoundButton,
|
|
103
|
+
{
|
|
104
|
+
label: button.label,
|
|
105
|
+
url: button.url,
|
|
106
|
+
action: button.action,
|
|
107
|
+
variant: button.variant,
|
|
108
|
+
size: button.size,
|
|
109
|
+
icon: button.icon
|
|
110
|
+
},
|
|
111
|
+
index
|
|
112
|
+
)) }) : null
|
|
115
113
|
]
|
|
116
114
|
}
|
|
117
115
|
);
|
|
@@ -5,12 +5,12 @@ export type Feature = {
|
|
|
5
5
|
name: string;
|
|
6
6
|
description?: string;
|
|
7
7
|
};
|
|
8
|
-
export type ActionType = "page" | "external" | "email" | "phone" | "section" | "download" | "none";
|
|
8
|
+
export type ActionType = "page" | "external" | "scroll" | "email" | "phone" | "section" | "download" | "none";
|
|
9
9
|
export type Action = {
|
|
10
10
|
type: ActionType;
|
|
11
11
|
pageUrl?: string;
|
|
12
12
|
externalUrl?: string;
|
|
13
|
-
openInNewTab?:
|
|
13
|
+
openInNewTab?: string;
|
|
14
14
|
email?: string;
|
|
15
15
|
subject?: string;
|
|
16
16
|
phone?: string;
|
|
@@ -1,10 +1,22 @@
|
|
|
1
1
|
import { type RefObject } from "react";
|
|
2
|
+
export type SitePage = {
|
|
3
|
+
/** 页面 slug,如 "about"、"pricing",用作路由值 */
|
|
4
|
+
slug: string;
|
|
5
|
+
/** 页面显示名,如 "关于我们"、"定价" */
|
|
6
|
+
label: string;
|
|
7
|
+
};
|
|
2
8
|
type EditorContextValue = {
|
|
3
9
|
openFieldsPanel: (componentId: string, componentType: string) => void;
|
|
4
10
|
openAddSection: (index: number, zone: string) => void;
|
|
5
11
|
isEditor: boolean;
|
|
6
12
|
toolbarPortalRef: RefObject<HTMLDivElement | null> | null;
|
|
7
13
|
fetchLibraryImages?: () => Promise<string[]>;
|
|
14
|
+
/** 站点 ID,用于表单提交等业务接口 */
|
|
15
|
+
siteId?: string;
|
|
16
|
+
/** 后台 API 域名,如 https://api.example.com */
|
|
17
|
+
domain?: string;
|
|
18
|
+
/** 站内可选页面列表,用于 url 字段快捷选择 */
|
|
19
|
+
sitePages?: SitePage[];
|
|
8
20
|
};
|
|
9
21
|
export declare const EditorContextProvider: import("react").Provider<EditorContextValue>;
|
|
10
22
|
export declare const useEditorContext: () => EditorContextValue;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { memo, useState, useRef, useMemo,
|
|
2
|
+
import { memo, useCallback, useState, useRef, useMemo, useEffect } from "react";
|
|
3
3
|
import { Input } from "../../shadcn/input.js";
|
|
4
4
|
import { Textarea } from "../../shadcn/textarea.js";
|
|
5
5
|
import { Label } from "../../shadcn/label.js";
|
|
@@ -8,7 +8,8 @@ import { Button } from "../../shadcn/button.js";
|
|
|
8
8
|
import { Select, SelectTrigger, SelectValue, SelectContent, SelectItem } from "../../shadcn/select.js";
|
|
9
9
|
import { Popover, PopoverTrigger, PopoverContent } from "../../shadcn/popover.js";
|
|
10
10
|
import { ToggleGroup, ToggleGroupItem } from "../../shadcn/toggle-group.js";
|
|
11
|
-
import { ChevronDownIcon, CheckIcon } from "lucide-react";
|
|
11
|
+
import { LinkIcon, XIcon, ClipboardIcon, GlobeIcon, ChevronDownIcon, CheckIcon } from "lucide-react";
|
|
12
|
+
import { useEditorContext } from "../editor-context.js";
|
|
12
13
|
const LARGE_SELECT_THRESHOLD = 200;
|
|
13
14
|
const VIRTUAL_ITEM_HEIGHT = 32;
|
|
14
15
|
const VIRTUAL_VIEWPORT_HEIGHT = 256;
|
|
@@ -159,62 +160,131 @@ const VirtualizedSelectField = memo(function VirtualizedSelectField2({
|
|
|
159
160
|
]
|
|
160
161
|
}
|
|
161
162
|
) }),
|
|
162
|
-
/* @__PURE__ */ jsxs(
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
163
|
+
/* @__PURE__ */ jsxs(PopoverContent, { className: "w-(--radix-popover-trigger-width) p-2", children: [
|
|
164
|
+
/* @__PURE__ */ jsx(
|
|
165
|
+
Input,
|
|
166
|
+
{
|
|
167
|
+
value: search,
|
|
168
|
+
onChange: (e) => setSearch(e.target.value),
|
|
169
|
+
placeholder: "Search options...",
|
|
170
|
+
className: "mb-2"
|
|
171
|
+
}
|
|
172
|
+
),
|
|
173
|
+
/* @__PURE__ */ jsx(
|
|
174
|
+
"div",
|
|
175
|
+
{
|
|
176
|
+
ref: viewportRef,
|
|
177
|
+
className: "relative touch-pan-y overflow-y-auto overscroll-contain rounded-md border",
|
|
178
|
+
style: {
|
|
179
|
+
height: VIRTUAL_VIEWPORT_HEIGHT,
|
|
180
|
+
WebkitOverflowScrolling: "touch"
|
|
181
|
+
},
|
|
182
|
+
onScroll: (e) => setScrollTop(e.currentTarget.scrollTop),
|
|
183
|
+
children: filteredOptions.length === 0 ? /* @__PURE__ */ jsx("div", { className: "text-muted-foreground p-3 text-sm", children: "No options found." }) : /* @__PURE__ */ jsx("div", { style: { height: totalHeight, position: "relative" }, children: /* @__PURE__ */ jsx(
|
|
177
184
|
"div",
|
|
178
185
|
{
|
|
179
|
-
ref: viewportRef,
|
|
180
|
-
className: "relative touch-pan-y overflow-y-auto overscroll-contain rounded-md border",
|
|
181
186
|
style: {
|
|
182
|
-
|
|
183
|
-
|
|
187
|
+
position: "absolute",
|
|
188
|
+
top: startIndex * VIRTUAL_ITEM_HEIGHT,
|
|
189
|
+
left: 0,
|
|
190
|
+
right: 0
|
|
184
191
|
},
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
192
|
+
children: visibleOptions.map((opt) => {
|
|
193
|
+
const isSelected = opt.stringValue === selectedString;
|
|
194
|
+
return /* @__PURE__ */ jsxs(
|
|
195
|
+
"button",
|
|
196
|
+
{
|
|
197
|
+
type: "button",
|
|
198
|
+
className: "hover:bg-accent hover:text-accent-foreground flex h-8 w-full items-center justify-between px-2 text-left text-sm",
|
|
199
|
+
onClick: () => handleSelect(opt.stringValue),
|
|
200
|
+
children: [
|
|
201
|
+
/* @__PURE__ */ jsx("span", { className: "truncate", children: opt.label }),
|
|
202
|
+
isSelected ? /* @__PURE__ */ jsx(CheckIcon, { className: "text-primary ml-2 size-4 shrink-0" }) : null
|
|
203
|
+
]
|
|
194
204
|
},
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
"button",
|
|
199
|
-
{
|
|
200
|
-
type: "button",
|
|
201
|
-
className: "hover:bg-accent hover:text-accent-foreground flex h-8 w-full items-center justify-between px-2 text-left text-sm",
|
|
202
|
-
onClick: () => handleSelect(opt.stringValue),
|
|
203
|
-
children: [
|
|
204
|
-
/* @__PURE__ */ jsx("span", { className: "truncate", children: opt.label }),
|
|
205
|
-
isSelected ? /* @__PURE__ */ jsx(CheckIcon, { className: "text-primary ml-2 size-4 shrink-0" }) : null
|
|
206
|
-
]
|
|
207
|
-
},
|
|
208
|
-
opt.stringValue
|
|
209
|
-
);
|
|
210
|
-
})
|
|
211
|
-
}
|
|
212
|
-
) })
|
|
205
|
+
opt.stringValue
|
|
206
|
+
);
|
|
207
|
+
})
|
|
213
208
|
}
|
|
214
|
-
)
|
|
209
|
+
) })
|
|
210
|
+
}
|
|
211
|
+
)
|
|
212
|
+
] })
|
|
213
|
+
] })
|
|
214
|
+
] });
|
|
215
|
+
});
|
|
216
|
+
const UrlField = memo(function UrlField2({
|
|
217
|
+
label,
|
|
218
|
+
value,
|
|
219
|
+
onChange,
|
|
220
|
+
sitePages
|
|
221
|
+
}) {
|
|
222
|
+
const currentValue = value ?? "";
|
|
223
|
+
const selectedSlug = currentValue.startsWith("/") ? currentValue.slice(1) : null;
|
|
224
|
+
const handlePaste = useCallback(async () => {
|
|
225
|
+
try {
|
|
226
|
+
const text = await navigator.clipboard.readText();
|
|
227
|
+
if (text) onChange(text.trim());
|
|
228
|
+
} catch {
|
|
229
|
+
}
|
|
230
|
+
}, [onChange]);
|
|
231
|
+
return /* @__PURE__ */ jsxs("div", { className: "mb-4 space-y-3", children: [
|
|
232
|
+
/* @__PURE__ */ jsx(Label, { children: label }),
|
|
233
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
234
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-1 items-center gap-2 rounded-lg border px-3 py-2", children: [
|
|
235
|
+
/* @__PURE__ */ jsx(LinkIcon, { className: "text-muted-foreground size-4 shrink-0" }),
|
|
236
|
+
/* @__PURE__ */ jsx(
|
|
237
|
+
"input",
|
|
238
|
+
{
|
|
239
|
+
className: "w-full bg-transparent text-sm outline-none placeholder:text-muted-foreground",
|
|
240
|
+
placeholder: "https:// or /page-slug",
|
|
241
|
+
value: currentValue,
|
|
242
|
+
onChange: (e) => onChange(e.target.value)
|
|
243
|
+
}
|
|
244
|
+
),
|
|
245
|
+
currentValue && /* @__PURE__ */ jsx(
|
|
246
|
+
"button",
|
|
247
|
+
{
|
|
248
|
+
type: "button",
|
|
249
|
+
className: "text-muted-foreground hover:text-foreground shrink-0",
|
|
250
|
+
onClick: () => onChange(""),
|
|
251
|
+
children: /* @__PURE__ */ jsx(XIcon, { className: "size-3.5" })
|
|
252
|
+
}
|
|
253
|
+
)
|
|
254
|
+
] }),
|
|
255
|
+
/* @__PURE__ */ jsxs(
|
|
256
|
+
Button,
|
|
257
|
+
{
|
|
258
|
+
type: "button",
|
|
259
|
+
variant: "outline",
|
|
260
|
+
size: "sm",
|
|
261
|
+
className: "shrink-0 gap-1.5",
|
|
262
|
+
onClick: handlePaste,
|
|
263
|
+
children: [
|
|
264
|
+
/* @__PURE__ */ jsx(ClipboardIcon, { className: "size-3.5" }),
|
|
265
|
+
"Paste"
|
|
215
266
|
]
|
|
216
267
|
}
|
|
217
268
|
)
|
|
269
|
+
] }),
|
|
270
|
+
sitePages.length > 0 && /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
271
|
+
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground text-xs font-medium", children: "Site pages" }),
|
|
272
|
+
/* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-2", children: sitePages.map((page) => {
|
|
273
|
+
const isSelected = selectedSlug === page.slug;
|
|
274
|
+
return /* @__PURE__ */ jsxs(
|
|
275
|
+
"button",
|
|
276
|
+
{
|
|
277
|
+
type: "button",
|
|
278
|
+
className: `inline-flex items-center gap-1.5 rounded-full border px-3 py-1 text-xs font-medium transition-colors ${isSelected ? "border-primary bg-primary text-primary-foreground" : "border-border bg-background text-foreground hover:bg-accent"}`,
|
|
279
|
+
onClick: () => onChange(isSelected ? "" : `${page.slug}`),
|
|
280
|
+
children: [
|
|
281
|
+
/* @__PURE__ */ jsx(GlobeIcon, { className: "size-3" }),
|
|
282
|
+
page.label
|
|
283
|
+
]
|
|
284
|
+
},
|
|
285
|
+
page.slug
|
|
286
|
+
);
|
|
287
|
+
}) })
|
|
218
288
|
] })
|
|
219
289
|
] });
|
|
220
290
|
});
|
|
@@ -226,6 +296,18 @@ const AutoField = memo(function AutoField2({
|
|
|
226
296
|
}) {
|
|
227
297
|
var _a, _b;
|
|
228
298
|
const label = field.label || name;
|
|
299
|
+
const { sitePages } = useEditorContext();
|
|
300
|
+
if (name === "url" && field.type === "text") {
|
|
301
|
+
return /* @__PURE__ */ jsx(
|
|
302
|
+
UrlField,
|
|
303
|
+
{
|
|
304
|
+
label,
|
|
305
|
+
value,
|
|
306
|
+
onChange,
|
|
307
|
+
sitePages: sitePages ?? []
|
|
308
|
+
}
|
|
309
|
+
);
|
|
310
|
+
}
|
|
229
311
|
switch (field.type) {
|
|
230
312
|
case "text":
|
|
231
313
|
return /* @__PURE__ */ jsxs("div", { className: "mb-4 space-y-1.5", children: [
|
|
@@ -8,17 +8,26 @@ const TAG_STYLES = {
|
|
|
8
8
|
p: "text-base md:text-lg",
|
|
9
9
|
span: ""
|
|
10
10
|
};
|
|
11
|
+
const DIRECTION_MAP = {
|
|
12
|
+
"to-r": "to right",
|
|
13
|
+
"to-l": "to left",
|
|
14
|
+
"to-t": "to top",
|
|
15
|
+
"to-b": "to bottom",
|
|
16
|
+
"to-br": "to bottom right",
|
|
17
|
+
"to-bl": "to bottom left"
|
|
18
|
+
};
|
|
11
19
|
const GradientText = ({
|
|
12
20
|
text,
|
|
13
21
|
as: Tag = "h2",
|
|
14
|
-
gradientFrom = "
|
|
15
|
-
gradientTo = "
|
|
22
|
+
gradientFrom = "var(--primary)",
|
|
23
|
+
gradientTo = "var(--chart-2)",
|
|
16
24
|
gradientVia,
|
|
17
25
|
direction = "to-r",
|
|
18
26
|
className
|
|
19
27
|
}) => {
|
|
28
|
+
const cssDirection = DIRECTION_MAP[direction] ?? "to right";
|
|
20
29
|
const gradientStyle = {
|
|
21
|
-
backgroundImage: gradientVia ? `linear-gradient(${
|
|
30
|
+
backgroundImage: gradientVia ? `linear-gradient(${cssDirection}, ${gradientFrom}, ${gradientVia}, ${gradientTo})` : `linear-gradient(${cssDirection}, ${gradientFrom}, ${gradientTo})`
|
|
22
31
|
};
|
|
23
32
|
return /* @__PURE__ */ jsx(
|
|
24
33
|
Tag,
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 联系表单线索:POST 到 `{domain}/api/form-leads`,与站点后端约定一致。
|
|
3
|
+
*/
|
|
4
|
+
export interface SubmitFormLeadBody {
|
|
5
|
+
site_id?: string | null;
|
|
6
|
+
name: string;
|
|
7
|
+
email: string;
|
|
8
|
+
phone: string;
|
|
9
|
+
message: string;
|
|
10
|
+
/** 当前页路径,用于归因 */
|
|
11
|
+
source_page: string;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* 提交表单线索。成功 resolve;HTTP 非 2xx 或业务 success !== true 时 throw Error(message 为 errMsg 或 HTTP 状态)。
|
|
15
|
+
*/
|
|
16
|
+
export declare function submitFormLead(domain: string | undefined | null, body: SubmitFormLeadBody): Promise<void>;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
function normalizeBaseUrl(domain) {
|
|
2
|
+
return (domain ?? "").replace(/\/$/, "");
|
|
3
|
+
}
|
|
4
|
+
async function submitFormLead(domain, body) {
|
|
5
|
+
const baseUrl = normalizeBaseUrl(domain);
|
|
6
|
+
const res = await fetch(`${baseUrl}/api/form-leads`, {
|
|
7
|
+
method: "POST",
|
|
8
|
+
headers: { "Content-Type": "application/json" },
|
|
9
|
+
body: JSON.stringify({
|
|
10
|
+
site_id: body.site_id,
|
|
11
|
+
name: body.name || "",
|
|
12
|
+
email: body.email || "",
|
|
13
|
+
phone: body.phone || "",
|
|
14
|
+
message: body.message || "",
|
|
15
|
+
source_page: body.source_page
|
|
16
|
+
})
|
|
17
|
+
});
|
|
18
|
+
const data = await res.json().catch(() => null);
|
|
19
|
+
if (!res.ok || !(data == null ? void 0 : data.success)) {
|
|
20
|
+
throw new Error((data == null ? void 0 : data.errMsg) || `HTTP ${res.status}`);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
export {
|
|
24
|
+
submitFormLead
|
|
25
|
+
};
|
|
@@ -9,6 +9,7 @@ import { Input } from "../../../shadcn/input.js";
|
|
|
9
9
|
import { Label } from "../../../shadcn/label.js";
|
|
10
10
|
import { Textarea } from "../../../shadcn/textarea.js";
|
|
11
11
|
import { useEditorContext } from "../../../puck-base/editor-context.js";
|
|
12
|
+
import { submitFormLead } from "../api/form-leads.js";
|
|
12
13
|
const DEFAULT_FIELDS = [
|
|
13
14
|
{ label: "Name", name: "name", type: "text", required: true },
|
|
14
15
|
{ label: "Email", name: "email", type: "email", required: true },
|
|
@@ -17,17 +18,33 @@ const DEFAULT_FIELDS = [
|
|
|
17
18
|
{ label: "Message", name: "message", type: "textarea", required: true }
|
|
18
19
|
];
|
|
19
20
|
const ContactUs = (props) => {
|
|
20
|
-
var _a, _b, _c, _d, _e, _f
|
|
21
|
-
const { isEditor: isEditorMode } = useEditorContext();
|
|
21
|
+
var _a, _b, _c, _d, _e, _f;
|
|
22
|
+
const { isEditor: isEditorMode, siteId, domain } = useEditorContext();
|
|
22
23
|
const formFields = ((_b = (_a = props.form) == null ? void 0 : _a.fields) == null ? void 0 : _b.length) ? props.form.fields : DEFAULT_FIELDS;
|
|
23
24
|
const [values, setValues] = useState({});
|
|
25
|
+
const [submitting, setSubmitting] = useState(false);
|
|
24
26
|
const setValue = (name, value) => setValues((prev) => ({ ...prev, [name]: value }));
|
|
25
|
-
const handleSubmit = (e) => {
|
|
27
|
+
const handleSubmit = async (e) => {
|
|
26
28
|
e.preventDefault();
|
|
27
29
|
if (isEditorMode) return;
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
30
|
+
setSubmitting(true);
|
|
31
|
+
try {
|
|
32
|
+
await submitFormLead(domain, {
|
|
33
|
+
site_id: siteId,
|
|
34
|
+
name: values.name || "",
|
|
35
|
+
email: values.email || "",
|
|
36
|
+
phone: values.phone || "",
|
|
37
|
+
message: values.message || "",
|
|
38
|
+
source_page: typeof window !== "undefined" ? window.location.pathname : ""
|
|
39
|
+
});
|
|
40
|
+
toast.success("Message sent successfully!");
|
|
41
|
+
setValues({});
|
|
42
|
+
} catch (err) {
|
|
43
|
+
const msg = err instanceof Error ? err.message : "Failed to send message";
|
|
44
|
+
toast.error(msg);
|
|
45
|
+
} finally {
|
|
46
|
+
setSubmitting(false);
|
|
47
|
+
}
|
|
31
48
|
};
|
|
32
49
|
const submitLabel = ((_d = (_c = props.form) == null ? void 0 : _c.button) == null ? void 0 : _d.label) ?? "Send Message";
|
|
33
50
|
const submitIcon = ((_f = (_e = props.form) == null ? void 0 : _e.button) == null ? void 0 : _f.icon) ?? "send";
|
|
@@ -49,8 +66,6 @@ const ContactUs = (props) => {
|
|
|
49
66
|
{
|
|
50
67
|
className: "rounded-md max-w-md w-full flex flex-col border p-8 gap-4",
|
|
51
68
|
onSubmit: handleSubmit,
|
|
52
|
-
action: (_g = props.form) == null ? void 0 : _g.action,
|
|
53
|
-
method: (_h = props.form) == null ? void 0 : _h.method,
|
|
54
69
|
children: [
|
|
55
70
|
formFields.reduce((rows, field, i) => {
|
|
56
71
|
var _a2, _b2, _c2;
|
|
@@ -127,11 +142,12 @@ const ContactUs = (props) => {
|
|
|
127
142
|
/* @__PURE__ */ jsx(
|
|
128
143
|
CompoundButton,
|
|
129
144
|
{
|
|
130
|
-
label: submitLabel,
|
|
145
|
+
label: submitting ? "Sending..." : submitLabel,
|
|
131
146
|
variant: "default",
|
|
132
147
|
size: "default",
|
|
133
|
-
icon: submitIcon,
|
|
134
|
-
type: "submit"
|
|
148
|
+
icon: submitting ? "loader" : submitIcon,
|
|
149
|
+
type: "submit",
|
|
150
|
+
disabled: submitting
|
|
135
151
|
}
|
|
136
152
|
)
|
|
137
153
|
]
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { CompoundContainerProps } from "@/components/puck-base/container";
|
|
2
|
+
export interface ContactUs2Button {
|
|
3
|
+
label: string;
|
|
4
|
+
variant?: string;
|
|
5
|
+
size?: string;
|
|
6
|
+
icon?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface ContactUs2Props {
|
|
9
|
+
heading?: string;
|
|
10
|
+
description?: string;
|
|
11
|
+
nameLabel?: string;
|
|
12
|
+
emailLabel?: string;
|
|
13
|
+
phoneLabel?: string;
|
|
14
|
+
companyLabel?: string;
|
|
15
|
+
messageLabel?: string;
|
|
16
|
+
button?: ContactUs2Button;
|
|
17
|
+
image?: {
|
|
18
|
+
src: string;
|
|
19
|
+
alt: string;
|
|
20
|
+
};
|
|
21
|
+
imagePosition?: "start" | "end";
|
|
22
|
+
padding?: CompoundContainerProps["padding"];
|
|
23
|
+
sectionStyle?: CompoundContainerProps["sectionStyle"];
|
|
24
|
+
backgroundColor?: string;
|
|
25
|
+
}
|
|
26
|
+
export declare const ContactUs2: ({ heading, description, nameLabel, emailLabel, phoneLabel, companyLabel, messageLabel, button, image, imagePosition, padding, sectionStyle, backgroundColor, }: ContactUs2Props) => import("react/jsx-runtime").JSX.Element;
|