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.
Files changed (109) hide show
  1. package/dist/components/puck-base/article-card.js +1 -1
  2. package/dist/components/puck-base/button.d.ts +1 -0
  3. package/dist/components/puck-base/button.js +1 -0
  4. package/dist/components/puck-base/container.d.ts +7 -1
  5. package/dist/components/puck-base/container.js +2 -1
  6. package/dist/components/puck-base/content.d.ts +1 -4
  7. package/dist/components/puck-base/content.js +15 -17
  8. package/dist/components/puck-base/core/types.d.ts +2 -2
  9. package/dist/components/puck-base/editor-context.d.ts +12 -0
  10. package/dist/components/puck-base/fields/auto-field.d.ts +1 -0
  11. package/dist/components/puck-base/fields/auto-field.js +131 -49
  12. package/dist/components/puck-base/gradient-text.js +12 -3
  13. package/dist/components/puck-block/banner-sections/announcement-banner-1/announcement-banner.js +1 -1
  14. package/dist/components/puck-block/contact-sections/api/form-leads.d.ts +16 -0
  15. package/dist/components/puck-block/contact-sections/api/form-leads.js +25 -0
  16. package/dist/components/puck-block/contact-sections/contact-us-1/contact-us.js +27 -11
  17. package/dist/components/puck-block/contact-sections/contact-us-2/contact-us-2.d.ts +26 -0
  18. package/dist/components/puck-block/contact-sections/contact-us-2/contact-us-2.js +229 -0
  19. package/dist/components/puck-block/contact-sections/contact-us-2/index.d.ts +5 -0
  20. package/dist/components/puck-block/contact-sections/contact-us-2/index.js +72 -0
  21. package/dist/components/puck-block/contact-sections/contact-us-3/contact-us-3.d.ts +29 -0
  22. package/dist/components/puck-block/contact-sections/contact-us-3/contact-us-3.js +245 -0
  23. package/dist/components/puck-block/contact-sections/contact-us-3/index.d.ts +5 -0
  24. package/dist/components/puck-block/contact-sections/contact-us-3/index.js +101 -0
  25. package/dist/components/puck-block/cta-sections/banner-cta-1/banner-cta.js +9 -8
  26. package/dist/components/puck-block/cta-sections/gradient-cta-1/gradient-cta.js +3 -3
  27. package/dist/components/puck-block/cta-sections/gradient-cta-1/index.js +4 -4
  28. package/dist/components/puck-block/cta-sections/newsletter-signup-1/newsletter-signup.js +5 -4
  29. package/dist/components/puck-block/cta-sections/promo-section-1/promo-section.js +6 -5
  30. package/dist/components/puck-block/faq-sections/faq-2/faq-2.d.ts +16 -0
  31. package/dist/components/puck-block/faq-sections/faq-2/faq-2.js +56 -0
  32. package/dist/components/puck-block/faq-sections/faq-2/index.d.ts +5 -0
  33. package/dist/components/puck-block/faq-sections/faq-2/index.js +62 -0
  34. package/dist/components/puck-block/feature-sections/feature-cards-1/feature-cards.d.ts +3 -4
  35. package/dist/components/puck-block/feature-sections/feature-cards-1/feature-cards.js +13 -3
  36. package/dist/components/puck-block/feature-sections/feature-cards-1/index.js +34 -14
  37. package/dist/components/puck-block/feature-sections/feature-showcase-1/feature-showcase.js +2 -8
  38. package/dist/components/puck-block/feature-sections/product-features-1/product-features.js +5 -25
  39. package/dist/components/puck-block/gallery-sections/gallery-1/gallery.js +3 -2
  40. package/dist/components/puck-block/gallery-sections/gallery-2/gallery-2.d.ts +14 -0
  41. package/dist/components/puck-block/gallery-sections/gallery-2/gallery-2.js +88 -0
  42. package/dist/components/puck-block/gallery-sections/gallery-2/index.d.ts +5 -0
  43. package/dist/components/puck-block/gallery-sections/gallery-2/index.js +44 -0
  44. package/dist/components/puck-block/gallery-sections/gallery-3/gallery-3.d.ts +17 -0
  45. package/dist/components/puck-block/gallery-sections/gallery-3/gallery-3.js +121 -0
  46. package/dist/components/puck-block/gallery-sections/gallery-3/index.d.ts +5 -0
  47. package/dist/components/puck-block/gallery-sections/gallery-3/index.js +60 -0
  48. package/dist/components/puck-block/hero-sections/fullscreen-hero-1/fullscreen-hero.d.ts +6 -1
  49. package/dist/components/puck-block/hero-sections/fullscreen-hero-1/fullscreen-hero.js +56 -20
  50. package/dist/components/puck-block/hero-sections/fullscreen-hero-1/index.js +12 -1
  51. package/dist/components/puck-block/hero-sections/gradient-hero-1/gradient-hero.d.ts +1 -1
  52. package/dist/components/puck-block/hero-sections/gradient-hero-1/gradient-hero.js +9 -6
  53. package/dist/components/puck-block/hero-sections/gradient-hero-1/index.js +4 -4
  54. package/dist/components/puck-block/hero-sections/image-hero-1/image-hero.d.ts +4 -1
  55. package/dist/components/puck-block/hero-sections/image-hero-1/image-hero.js +60 -62
  56. package/dist/components/puck-block/index.d.ts +15 -0
  57. package/dist/components/puck-block/location-sections/location-1/index.d.ts +5 -0
  58. package/dist/components/puck-block/location-sections/location-1/index.js +103 -0
  59. package/dist/components/puck-block/location-sections/location-1/location.d.ts +27 -0
  60. package/dist/components/puck-block/location-sections/location-1/location.js +143 -0
  61. package/dist/components/puck-block/location-sections/location-2/index.d.ts +5 -0
  62. package/dist/components/puck-block/location-sections/location-2/index.js +111 -0
  63. package/dist/components/puck-block/location-sections/location-2/location.d.ts +25 -0
  64. package/dist/components/puck-block/location-sections/location-2/location.js +136 -0
  65. package/dist/components/puck-block/location-sections/location-3/index.d.ts +5 -0
  66. package/dist/components/puck-block/location-sections/location-3/index.js +83 -0
  67. package/dist/components/puck-block/location-sections/location-3/location.d.ts +22 -0
  68. package/dist/components/puck-block/location-sections/location-3/location.js +129 -0
  69. package/dist/components/puck-block/metrics-sections/stats-2/index.d.ts +5 -0
  70. package/dist/components/puck-block/metrics-sections/stats-2/index.js +77 -0
  71. package/dist/components/puck-block/metrics-sections/stats-2/stats-2.d.ts +16 -0
  72. package/dist/components/puck-block/metrics-sections/stats-2/stats-2.js +59 -0
  73. package/dist/components/puck-block/metrics-sections/stats-3/index.d.ts +5 -0
  74. package/dist/components/puck-block/metrics-sections/stats-3/index.js +94 -0
  75. package/dist/components/puck-block/metrics-sections/stats-3/stats-3.d.ts +17 -0
  76. package/dist/components/puck-block/metrics-sections/stats-3/stats-3.js +60 -0
  77. package/dist/components/puck-block/pricing-sections/pricing-2/index.d.ts +5 -0
  78. package/dist/components/puck-block/pricing-sections/pricing-2/index.js +152 -0
  79. package/dist/components/puck-block/pricing-sections/pricing-2/pricing-2.d.ts +24 -0
  80. package/dist/components/puck-block/pricing-sections/pricing-2/pricing-2.js +68 -0
  81. package/dist/components/puck-block/showcase-sections/before-after-1/before-after.d.ts +20 -0
  82. package/dist/components/puck-block/showcase-sections/before-after-1/before-after.js +73 -0
  83. package/dist/components/puck-block/showcase-sections/before-after-1/index.d.ts +5 -0
  84. package/dist/components/puck-block/showcase-sections/before-after-1/index.js +74 -0
  85. package/dist/components/puck-block/showcase-sections/case-study-1/case-study.js +2 -8
  86. package/dist/components/puck-block/team-sections/team-grid-1/team-grid.js +4 -24
  87. package/dist/components/puck-block/team-sections/team-grid-2/index.d.ts +5 -0
  88. package/dist/components/puck-block/team-sections/team-grid-2/index.js +63 -0
  89. package/dist/components/puck-block/team-sections/team-grid-2/team-grid-2.d.ts +21 -0
  90. package/dist/components/puck-block/team-sections/team-grid-2/team-grid-2.js +46 -0
  91. package/dist/components/puck-block/team-sections/team-profiles-1/index.d.ts +5 -0
  92. package/dist/components/puck-block/team-sections/team-profiles-1/index.js +54 -0
  93. package/dist/components/puck-block/team-sections/team-profiles-1/team-profiles.d.ts +21 -0
  94. package/dist/components/puck-block/team-sections/team-profiles-1/team-profiles.js +107 -0
  95. package/dist/components/puck-block/testimonial-sections/logo-marquee-1/logo-marquee.js +2 -1
  96. package/dist/components/puck-block/testimonial-sections/logo-wall-1/index.d.ts +5 -0
  97. package/dist/components/puck-block/testimonial-sections/logo-wall-1/index.js +50 -0
  98. package/dist/components/puck-block/testimonial-sections/logo-wall-1/logo-wall.d.ts +15 -0
  99. package/dist/components/puck-block/testimonial-sections/logo-wall-1/logo-wall.js +57 -0
  100. package/dist/components/puck-block/testimonial-sections/review-section-1/review-section.js +3 -2
  101. package/dist/components/puck-block/text-sections/articles-1/articles.d.ts +1 -0
  102. package/dist/components/puck-block/text-sections/articles-1/articles.js +19 -6
  103. package/dist/components/puck-block/text-sections/articles-1/index.js +16 -4
  104. package/dist/components/puck-block/text-sections/content-section-1/content-section.js +5 -4
  105. package/dist/components/puck-block/text-sections/tab-section-1/tab-section.js +3 -2
  106. package/dist/components/shadcn/navigation-menu.d.ts +1 -1
  107. package/dist/components/shadcn/navigation-menu.js +33 -0
  108. package/dist/index.js +104 -74
  109. 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 rounded-md aspect-video mb-2 overflow-hidden", children: (image == null ? void 0 : image.src) ? /* @__PURE__ */ jsx(CompoundImage, { src: image.src, alt: image.alt }) : null }),
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;
@@ -72,6 +72,7 @@ function CompoundButtonBase(props) {
72
72
  size: props.size,
73
73
  className: cn("gap-4", props.className),
74
74
  type: props.type ?? "button",
75
+ disabled: props.disabled,
75
76
  children: content
76
77
  }
77
78
  );
@@ -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 {};
@@ -86,5 +86,6 @@ const CompoundContainer = ({
86
86
  ) });
87
87
  };
88
88
  export {
89
- CompoundContainer
89
+ CompoundContainer,
90
+ SECTION_STYLE_VARS
90
91
  };
@@ -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, }: CompoundContentPropsWithSpacing) => import("react/jsx-runtime").JSX.Element;
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 tracking-tighter lg:max-w-xl font-regular",
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 text-muted-foreground",
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: "w-6 h-6 shrink-0"
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 flex-wrap", rowPositionClassNames), children: buttons.map(
102
- (button, index) => button.label ? /* @__PURE__ */ jsx(
103
- CompoundButton,
104
- {
105
- label: button.label,
106
- url: button.url,
107
- action: button.action,
108
- variant: button.variant,
109
- size: button.size,
110
- icon: button.icon
111
- },
112
- index
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?: "true" | "false";
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,2 +1,3 @@
1
1
  import type { AutoFieldProps } from "./types";
2
+ /** 按 field.type 分发控件;名为 url 且类型为 text 时固定使用 UrlField(链接 + 站内路由) */
2
3
  export declare const AutoField: import("react").NamedExoticComponent<AutoFieldProps>;
@@ -1,5 +1,5 @@
1
1
  import { jsx, jsxs } from "react/jsx-runtime";
2
- import { memo, useState, useRef, useMemo, useCallback, useEffect } from "react";
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
- PopoverContent,
164
- {
165
- className: "w-(--radix-popover-trigger-width) p-2",
166
- children: [
167
- /* @__PURE__ */ jsx(
168
- Input,
169
- {
170
- value: search,
171
- onChange: (e) => setSearch(e.target.value),
172
- placeholder: "Search options...",
173
- className: "mb-2"
174
- }
175
- ),
176
- /* @__PURE__ */ jsx(
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
- height: VIRTUAL_VIEWPORT_HEIGHT,
183
- WebkitOverflowScrolling: "touch"
187
+ position: "absolute",
188
+ top: startIndex * VIRTUAL_ITEM_HEIGHT,
189
+ left: 0,
190
+ right: 0
184
191
  },
185
- onScroll: (e) => setScrollTop(e.currentTarget.scrollTop),
186
- 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(
187
- "div",
188
- {
189
- style: {
190
- position: "absolute",
191
- top: startIndex * VIRTUAL_ITEM_HEIGHT,
192
- left: 0,
193
- right: 0
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
- children: visibleOptions.map((opt) => {
196
- const isSelected = opt.stringValue === selectedString;
197
- return /* @__PURE__ */ jsxs(
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 = "oklch(0.7 0.25 260)",
15
- gradientTo = "oklch(0.7 0.25 330)",
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(${direction.replace("to-", "to ")}, ${gradientFrom}, ${gradientVia}, ${gradientTo})` : `linear-gradient(${direction.replace("to-", "to ")}, ${gradientFrom}, ${gradientTo})`
30
+ backgroundImage: gradientVia ? `linear-gradient(${cssDirection}, ${gradientFrom}, ${gradientVia}, ${gradientTo})` : `linear-gradient(${cssDirection}, ${gradientFrom}, ${gradientTo})`
22
31
  };
23
32
  return /* @__PURE__ */ jsx(
24
33
  Tag,
@@ -4,7 +4,7 @@ const AnnouncementBanner = ({
4
4
  text,
5
5
  linkText,
6
6
  linkUrl,
7
- backgroundColor = "oklch(0.85 0.15 85)",
7
+ backgroundColor = "var(--primary)",
8
8
  textColor,
9
9
  align = "center",
10
10
  size = "default"
@@ -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, _g, _h;
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
- console.log({ ...values });
29
- toast.success("Message sent successfully!");
30
- setValues({});
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;