@frontlit/page-builder 0.1.0-alpha.4 → 0.1.0-alpha.6

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 (46) hide show
  1. package/dist/blocks/index.d.ts +18 -3
  2. package/dist/blocks/index.js +3 -3
  3. package/dist/builder/index.d.ts +4 -1
  4. package/dist/builder/index.js +6 -6
  5. package/dist/{chunk-BBI7UHOA.js → chunk-BWOGREWJ.js} +3 -3
  6. package/dist/{chunk-BBI7UHOA.js.map → chunk-BWOGREWJ.js.map} +1 -1
  7. package/dist/{chunk-K4WCLHMS.js → chunk-FZBLE44D.js} +317 -66
  8. package/dist/chunk-FZBLE44D.js.map +1 -0
  9. package/dist/{chunk-J7Z4UW45.js → chunk-OEQJQ4OA.js} +112 -5
  10. package/dist/chunk-OEQJQ4OA.js.map +1 -0
  11. package/dist/{chunk-GIKTOAQS.js → chunk-PQTDUFKU.js} +9 -9
  12. package/dist/chunk-PQTDUFKU.js.map +1 -0
  13. package/dist/{chunk-36QHCIPM.js → chunk-QMUIISN3.js} +5 -93
  14. package/dist/chunk-QMUIISN3.js.map +1 -0
  15. package/dist/{chunk-IU4KATI2.js → chunk-YXLOVEQZ.js} +6 -6
  16. package/dist/{chunk-IU4KATI2.js.map → chunk-YXLOVEQZ.js.map} +1 -1
  17. package/dist/components/index.d.ts +1 -1
  18. package/dist/components/index.js +3 -3
  19. package/dist/{image-Bk8kPXwP.d.ts → image-Cv0aSUHD.d.ts} +3 -1
  20. package/dist/index.d.ts +1 -1
  21. package/dist/index.js +6 -6
  22. package/dist/primitives/index.d.ts +2 -0
  23. package/dist/primitives/index.js +1 -1
  24. package/dist/renderer/index.js +5 -5
  25. package/dist/server/index.js +151 -53
  26. package/dist/server/index.js.map +1 -1
  27. package/dist/server/islands/header-github-stars.d.ts +12 -0
  28. package/dist/server/islands/header-github-stars.js +31 -0
  29. package/dist/server/islands/header-github-stars.js.map +1 -0
  30. package/dist/server/islands/pricing-period-switch.d.ts +20 -0
  31. package/dist/server/islands/pricing-period-switch.js +151 -0
  32. package/dist/server/islands/pricing-period-switch.js.map +1 -0
  33. package/dist/server/primitives.d.ts +2 -0
  34. package/dist/server/primitives.js +53 -30
  35. package/dist/server/primitives.js.map +1 -1
  36. package/dist/server/schema.d.ts +38 -0
  37. package/dist/server/schema.js +17 -2
  38. package/dist/server/schema.js.map +1 -1
  39. package/dist/styles.css +12 -0
  40. package/package.json +1 -1
  41. package/schema/page.v1.json +29 -1
  42. package/schema/site.v1.json +8 -0
  43. package/dist/chunk-36QHCIPM.js.map +0 -1
  44. package/dist/chunk-GIKTOAQS.js.map +0 -1
  45. package/dist/chunk-J7Z4UW45.js.map +0 -1
  46. package/dist/chunk-K4WCLHMS.js.map +0 -1
@@ -89,12 +89,16 @@ function cn(...inputs) {
89
89
 
90
90
  // src/blocks/header/widget.tsx
91
91
  import clsx2 from "clsx";
92
+ import { Github } from "lucide-react";
92
93
 
93
94
  // src/components/image.tsx
94
95
  import { jsx } from "react/jsx-runtime";
95
- var imageAttributesResolver = null;
96
+ var registry = globalThis;
96
97
  function setImageAttributesResolver(resolver) {
97
- imageAttributesResolver = resolver;
98
+ registry.__frontlitImageResolver = resolver;
99
+ }
100
+ function resolveImageAttributes(input) {
101
+ return registry.__frontlitImageResolver?.(input) ?? null;
98
102
  }
99
103
  var roundedMap = {
100
104
  0: "rounded-none",
@@ -148,7 +152,7 @@ var Image = (props) => {
148
152
  }
149
153
  );
150
154
  }
151
- const optimized = imageAttributesResolver?.({ src: source, alt, sizes, priority });
155
+ const optimized = resolveImageAttributes({ src: source, alt, sizes, priority });
152
156
  return /* @__PURE__ */ jsx(
153
157
  "div",
154
158
  {
@@ -866,6 +870,15 @@ function HeaderLink({
866
870
 
867
871
  // src/blocks/header/widget.tsx
868
872
  import { HeaderMobileMenu } from "./islands/header-mobile-menu.js";
873
+ import { GithubStars } from "./islands/header-github-stars.js";
874
+
875
+ // src/blocks/header/github.ts
876
+ function parseGithubRepo(value) {
877
+ const match = value?.trim().match(/^(?:https?:\/\/(?:www\.)?github\.com\/)?([\w.-]+\/[\w.-]+?)(?:\.git)?\/?$/);
878
+ return match?.[1];
879
+ }
880
+
881
+ // src/blocks/header/widget.tsx
869
882
  import { jsx as jsx16, jsxs as jsxs2 } from "react/jsx-runtime";
870
883
  function HeaderWidget({
871
884
  settings: {
@@ -876,6 +889,8 @@ function HeaderWidget({
876
889
  linkAlignment = "left",
877
890
  layout = "fixed",
878
891
  backdropBlur = false,
892
+ githubRepo,
893
+ showGithubStars,
879
894
  cssId,
880
895
  maxWidth,
881
896
  verticalPadding,
@@ -896,6 +911,8 @@ function HeaderWidget({
896
911
  const resolvedLogoText = pageData.siteTitle;
897
912
  const resolvedLogoAlt = pageData.siteLogoAlt || resolvedLogoText || "";
898
913
  const effectiveLogoCorners = logoCorners ?? 2;
914
+ const hasCta = Boolean(ctaLabel && ctaHref);
915
+ const repo = parseGithubRepo(githubRepo);
899
916
  const logo = /* @__PURE__ */ jsx16(NavLink2, { href: "/", className: "no-underline", children: /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-2", children: [
900
917
  resolvedLogoImage && /* @__PURE__ */ jsx16(
901
918
  Image,
@@ -912,9 +929,22 @@ function HeaderWidget({
912
929
  resolvedLogoText && /* @__PURE__ */ jsx16(Header4, { theme: overriddenTheme, as: "span", children: resolvedLogoText })
913
930
  ] }) });
914
931
  const ctaAndMenu = /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-3", children: [
932
+ repo && /* @__PURE__ */ jsx16(
933
+ "a",
934
+ {
935
+ href: `https://github.com/${repo}`,
936
+ target: "_blank",
937
+ rel: "noopener noreferrer",
938
+ children: /* @__PURE__ */ jsxs2(Button2, { theme: overriddenTheme, variant: "ghost", size: "sm", className: "gap-1.5", children: [
939
+ /* @__PURE__ */ jsx16(Github, { className: "h-4 w-4", "aria-hidden": true }),
940
+ /* @__PURE__ */ jsx16("span", { className: "sr-only", children: "GitHub repository" }),
941
+ showGithubStars && /* @__PURE__ */ jsx16(GithubStars, { repo })
942
+ ] })
943
+ }
944
+ ),
915
945
  buttonLinks.map((link) => /* @__PURE__ */ jsx16("div", { className: "hidden lg:!block", children: /* @__PURE__ */ jsx16(HeaderLink, { link, theme: overriddenTheme }) }, link.id)),
916
- ctaLabel && ctaHref && /* @__PURE__ */ jsx16("div", { className: "hidden lg:!block", children: /* @__PURE__ */ jsx16(NavLink2, { href: ctaHref, children: /* @__PURE__ */ jsx16(Button2, { theme: overriddenTheme, size: "sm", children: ctaLabel }) }) }),
917
- /* @__PURE__ */ jsx16("div", { className: "lg:hidden", children: /* @__PURE__ */ jsx16(
946
+ hasCta && /* @__PURE__ */ jsx16("div", { className: "hidden lg:!block", children: /* @__PURE__ */ jsx16(NavLink2, { href: ctaHref, children: /* @__PURE__ */ jsx16(Button2, { theme: overriddenTheme, size: "sm", children: ctaLabel }) }) }),
947
+ (links.length > 0 || hasCta) && /* @__PURE__ */ jsx16("div", { className: "lg:hidden", children: /* @__PURE__ */ jsx16(
918
948
  HeaderMobileMenu,
919
949
  {
920
950
  links,
@@ -1567,8 +1597,17 @@ var faqDefaults = {
1567
1597
 
1568
1598
  // src/blocks/pricing/widget.tsx
1569
1599
  import clsx7 from "clsx";
1600
+ import { PricingPeriodSwitch } from "./islands/pricing-period-switch.js";
1570
1601
  import { NavLink as NavLink4 } from "./islands/nav-link.js";
1571
- import { jsx as jsx21, jsxs as jsxs7 } from "react/jsx-runtime";
1602
+ import { Fragment as Fragment2, jsx as jsx21, jsxs as jsxs7 } from "react/jsx-runtime";
1603
+ var lgColumns = {
1604
+ 1: "lg:grid-cols-1",
1605
+ 2: "lg:grid-cols-2",
1606
+ 3: "lg:grid-cols-3",
1607
+ 4: "lg:grid-cols-4"
1608
+ };
1609
+ var monthlyOnly = "group-data-[period=yearly]/pricing:hidden";
1610
+ var yearlyOnly = "hidden group-data-[period=yearly]/pricing:block";
1572
1611
  function PricingWidget({
1573
1612
  settings: {
1574
1613
  title,
@@ -1578,6 +1617,10 @@ function PricingWidget({
1578
1617
  headerAlignment = "center",
1579
1618
  tiers,
1580
1619
  layout = "grid",
1620
+ pricingSwitcher,
1621
+ monthlyPriceCaption,
1622
+ yearlyPriceCaption,
1623
+ defaultPeriod = "yearly",
1581
1624
  cssId,
1582
1625
  maxWidth,
1583
1626
  verticalPadding,
@@ -1588,6 +1631,76 @@ function PricingWidget({
1588
1631
  const overriddenTheme = JSON.parse(JSON.stringify(theme.theme));
1589
1632
  overriddenTheme.structure.page.width = maxWidth || theme.theme.structure.page.width;
1590
1633
  overriddenTheme.structure.section.padding.y = verticalPadding || theme.theme.structure.section.padding.y;
1634
+ const plans = tiers && tiers.length > 0 && /* @__PURE__ */ jsx21(
1635
+ "div",
1636
+ {
1637
+ className: clsx7(
1638
+ layout === "stacked" ? "mx-auto flex w-full max-w-xl flex-col gap-6" : [
1639
+ "grid grid-cols-1 gap-6 items-stretch",
1640
+ tiers.length === 1 && "mx-auto w-full max-w-xl",
1641
+ tiers.length >= 2 && "md:grid-cols-2",
1642
+ lgColumns[Math.min(tiers.length, 4)]
1643
+ ]
1644
+ ),
1645
+ children: tiers.map((tier, index) => /* @__PURE__ */ jsx21(
1646
+ PageCard,
1647
+ {
1648
+ theme: overriddenTheme,
1649
+ className: clsx7(
1650
+ tier.highlighted && "ring-2 ring-primary",
1651
+ layout === "highlight" && tier.highlighted && "relative z-10 shadow-xl md:-translate-y-3"
1652
+ ),
1653
+ children: /* @__PURE__ */ jsxs7(
1654
+ PageCardContent,
1655
+ {
1656
+ theme: overriddenTheme,
1657
+ className: "h-full flex flex-col gap-4",
1658
+ children: [
1659
+ /* @__PURE__ */ jsxs7("div", { className: "flex items-center justify-between gap-2", children: [
1660
+ /* @__PURE__ */ jsx21(Preheader, { theme: overriddenTheme, children: tier.name }),
1661
+ tier.highlighted && /* @__PURE__ */ jsx21(Badge2, { theme: overriddenTheme, children: "Most popular" })
1662
+ ] }),
1663
+ /* @__PURE__ */ jsx21(PageCardHeader, { theme: overriddenTheme, children: pricingSwitcher ? /* @__PURE__ */ jsxs7(Fragment2, { children: [
1664
+ /* @__PURE__ */ jsx21("span", { className: monthlyOnly, children: tier.price }),
1665
+ /* @__PURE__ */ jsx21("span", { className: yearlyOnly, children: tier.priceYearly || tier.price })
1666
+ ] }) : tier.price }),
1667
+ tier.description && /* @__PURE__ */ jsx21(Text1, { theme: overriddenTheme, children: tier.description }),
1668
+ tier.features && tier.features.length > 0 && /* @__PURE__ */ jsx21("div", { className: "grow flex flex-col gap-2", children: tier.features.map((feature, i) => /* @__PURE__ */ jsx21(Text2, { theme: overriddenTheme, children: feature }, i)) }),
1669
+ pricingSwitcher && tier.buttonActionYearly && tier.buttonActionYearly !== tier.buttonAction ? /* @__PURE__ */ jsxs7(Fragment2, { children: [
1670
+ /* @__PURE__ */ jsx21(
1671
+ TierButton,
1672
+ {
1673
+ tier,
1674
+ href: tier.buttonAction,
1675
+ className: monthlyOnly,
1676
+ theme: overriddenTheme
1677
+ }
1678
+ ),
1679
+ /* @__PURE__ */ jsx21(
1680
+ TierButton,
1681
+ {
1682
+ tier,
1683
+ href: tier.buttonActionYearly,
1684
+ className: yearlyOnly,
1685
+ theme: overriddenTheme
1686
+ }
1687
+ )
1688
+ ] }) : /* @__PURE__ */ jsx21(
1689
+ TierButton,
1690
+ {
1691
+ tier,
1692
+ href: tier.buttonAction,
1693
+ theme: overriddenTheme
1694
+ }
1695
+ )
1696
+ ]
1697
+ }
1698
+ )
1699
+ },
1700
+ index
1701
+ ))
1702
+ }
1703
+ );
1591
1704
  return /* @__PURE__ */ jsx21(Section, { theme: overriddenTheme, id: cssId, background, children: /* @__PURE__ */ jsxs7("div", { className: "flex flex-col gap-8", children: [
1592
1705
  /* @__PURE__ */ jsxs7(
1593
1706
  "div",
@@ -1602,50 +1715,35 @@ function PricingWidget({
1602
1715
  ]
1603
1716
  }
1604
1717
  ),
1605
- tiers && tiers.length > 0 && /* @__PURE__ */ jsx21(
1606
- "div",
1718
+ tiers && tiers.length > 0 && (pricingSwitcher ? /* @__PURE__ */ jsx21(
1719
+ PricingPeriodSwitch,
1607
1720
  {
1608
- className: layout === "stacked" ? "mx-auto flex w-full max-w-xl flex-col gap-6" : "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 items-stretch",
1609
- children: tiers.map((tier, index) => /* @__PURE__ */ jsx21(
1610
- PageCard,
1611
- {
1612
- theme: overriddenTheme,
1613
- className: clsx7(
1614
- tier.highlighted && "ring-2 ring-primary",
1615
- layout === "highlight" && tier.highlighted && "relative z-10 shadow-xl md:-translate-y-3"
1616
- ),
1617
- children: /* @__PURE__ */ jsxs7(
1618
- PageCardContent,
1619
- {
1620
- theme: overriddenTheme,
1621
- className: "h-full flex flex-col gap-4",
1622
- children: [
1623
- /* @__PURE__ */ jsxs7("div", { className: "flex items-center justify-between gap-2", children: [
1624
- /* @__PURE__ */ jsx21(Preheader, { theme: overriddenTheme, children: tier.name }),
1625
- tier.highlighted && /* @__PURE__ */ jsx21(Badge2, { theme: overriddenTheme, children: "Most popular" })
1626
- ] }),
1627
- /* @__PURE__ */ jsx21(PageCardHeader, { theme: overriddenTheme, children: tier.price }),
1628
- tier.description && /* @__PURE__ */ jsx21(Text1, { theme: overriddenTheme, children: tier.description }),
1629
- tier.features && tier.features.length > 0 && /* @__PURE__ */ jsx21("div", { className: "grow flex flex-col gap-2", children: tier.features.map((feature, i) => /* @__PURE__ */ jsx21(Text2, { theme: overriddenTheme, children: feature }, i)) }),
1630
- tier.buttonAction && tier.buttonCaption && /* @__PURE__ */ jsx21(NavLink4, { href: tier.buttonAction, className: "w-full mt-auto", children: /* @__PURE__ */ jsx21(
1631
- Button2,
1632
- {
1633
- theme: overriddenTheme,
1634
- variant: tier.highlighted ? "default" : "secondary",
1635
- className: "w-full",
1636
- children: tier.buttonCaption
1637
- }
1638
- ) })
1639
- ]
1640
- }
1641
- )
1642
- },
1643
- index
1644
- ))
1721
+ defaultPeriod,
1722
+ monthlyCaption: monthlyPriceCaption || "Monthly",
1723
+ yearlyCaption: yearlyPriceCaption || "Yearly",
1724
+ theme: overriddenTheme,
1725
+ children: plans
1645
1726
  }
1646
- )
1727
+ ) : plans)
1647
1728
  ] }) });
1648
1729
  }
1730
+ function TierButton({
1731
+ tier,
1732
+ href,
1733
+ className,
1734
+ theme
1735
+ }) {
1736
+ if (!href || !tier.buttonCaption) return null;
1737
+ return /* @__PURE__ */ jsx21(NavLink4, { href, className: clsx7("w-full mt-auto", className), children: /* @__PURE__ */ jsx21(
1738
+ Button2,
1739
+ {
1740
+ theme,
1741
+ variant: tier.highlighted ? "default" : "secondary",
1742
+ className: "w-full",
1743
+ children: tier.buttonCaption
1744
+ }
1745
+ ) });
1746
+ }
1649
1747
 
1650
1748
  // src/blocks/pricing/defaults.ts
1651
1749
  var pricingDefaults = {
@@ -1688,7 +1786,7 @@ var pricingDefaults = {
1688
1786
  // src/blocks/banner/widget.tsx
1689
1787
  import clsx8 from "clsx";
1690
1788
  import { NavLink as NavLink5 } from "./islands/nav-link.js";
1691
- import { Fragment as Fragment2, jsx as jsx22, jsxs as jsxs8 } from "react/jsx-runtime";
1789
+ import { Fragment as Fragment3, jsx as jsx22, jsxs as jsxs8 } from "react/jsx-runtime";
1692
1790
  function BannerWidget({
1693
1791
  settings: {
1694
1792
  title,
@@ -1714,7 +1812,7 @@ function BannerWidget({
1714
1812
  const isCentered = contentAlignment === "center";
1715
1813
  const isSplit = layout === "split";
1716
1814
  const isBoxed = layout === "boxed";
1717
- const heading = /* @__PURE__ */ jsxs8(Fragment2, { children: [
1815
+ const heading = /* @__PURE__ */ jsxs8(Fragment3, { children: [
1718
1816
  /* @__PURE__ */ jsx22(Header1, { theme: overriddenTheme, ...titleProps({ titleLevel, titleSize }), children: renderTitle(title, overriddenTheme) }),
1719
1817
  description && /* @__PURE__ */ jsx22(Subheader1, { theme: overriddenTheme, component: "span", children: /* @__PURE__ */ jsx22(TextRenderer, { json: description, theme: overriddenTheme }) })
1720
1818
  ] });
@@ -2088,7 +2186,7 @@ var richTextDefaults = {
2088
2186
  import clsx11 from "clsx";
2089
2187
  import * as Icons2 from "lucide-react";
2090
2188
  import { NavLink as NavLink7 } from "./islands/nav-link.js";
2091
- import { Fragment as Fragment3, jsx as jsx27, jsxs as jsxs12 } from "react/jsx-runtime";
2189
+ import { Fragment as Fragment4, jsx as jsx27, jsxs as jsxs12 } from "react/jsx-runtime";
2092
2190
  function resolveIcon2(name) {
2093
2191
  if (!name) return null;
2094
2192
  return Icons2[name] ?? null;
@@ -2125,10 +2223,10 @@ function GridItemCard({ item, theme }) {
2125
2223
  item.description && /* @__PURE__ */ jsx27(Text2, { theme, children: item.description }),
2126
2224
  item.buttonAction && item.buttonCaption && /* @__PURE__ */ jsx27(NavLink7, { href: item.buttonAction, className: "mt-2", children: /* @__PURE__ */ jsx27(Button2, { theme, variant: "secondary", size: "sm", children: item.buttonCaption }) })
2127
2225
  ] });
2128
- return /* @__PURE__ */ jsx27(PageCard, { theme, children: /* @__PURE__ */ jsx27(PageCardContent, { theme, className: "flex h-full flex-col gap-3", children: mediaFirst ? /* @__PURE__ */ jsxs12(Fragment3, { children: [
2226
+ return /* @__PURE__ */ jsx27(PageCard, { theme, children: /* @__PURE__ */ jsx27(PageCardContent, { theme, className: "flex h-full flex-col gap-3", children: mediaFirst ? /* @__PURE__ */ jsxs12(Fragment4, { children: [
2129
2227
  media,
2130
2228
  text
2131
- ] }) : /* @__PURE__ */ jsxs12(Fragment3, { children: [
2229
+ ] }) : /* @__PURE__ */ jsxs12(Fragment4, { children: [
2132
2230
  text,
2133
2231
  media
2134
2232
  ] }) }) });
@@ -2293,7 +2391,7 @@ import React5 from "react";
2293
2391
  import * as Icons3 from "lucide-react";
2294
2392
  import { NavLink as NavLink8 } from "./islands/nav-link.js";
2295
2393
  import { MarqueeTrack } from "./islands/marquee-track.js";
2296
- import { Fragment as Fragment4, jsx as jsx29, jsxs as jsxs13 } from "react/jsx-runtime";
2394
+ import { Fragment as Fragment5, jsx as jsx29, jsxs as jsxs13 } from "react/jsx-runtime";
2297
2395
  function resolveIcon3(name) {
2298
2396
  if (!name) return null;
2299
2397
  return Icons3[name] ?? null;
@@ -2344,7 +2442,7 @@ function MarqueeWidget({
2344
2442
  };
2345
2443
  return /* @__PURE__ */ jsx29(Section, { theme: overriddenTheme, id: cssId, background, children: /* @__PURE__ */ jsxs13("div", { className: "relative", "aria-hidden": "true", children: [
2346
2444
  /* @__PURE__ */ jsx29(MarqueeTrack, { speed, direction, pauseOnHover, children: items.map(renderItem) }),
2347
- fadeWidth > 0 && /* @__PURE__ */ jsxs13(Fragment4, { children: [
2445
+ fadeWidth > 0 && /* @__PURE__ */ jsxs13(Fragment5, { children: [
2348
2446
  /* @__PURE__ */ jsx29(
2349
2447
  "div",
2350
2448
  {