shared-features 0.1.8 → 0.1.10

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.
@@ -1472,6 +1472,847 @@ function AdBanner({
1472
1472
  }
1473
1473
  );
1474
1474
  }
1475
+ const DISMISSED_TOPBAR_KEY = "sf_topbar_dismissed";
1476
+ function TopbarAdBanner({
1477
+ placement = "topbar_banner",
1478
+ rotationInterval = 2e4,
1479
+ maxCampaigns = 5,
1480
+ className,
1481
+ style
1482
+ }) {
1483
+ const [currentIndex, setCurrentIndex] = react.useState(0);
1484
+ const [isAnimating, setIsAnimating] = react.useState(false);
1485
+ const [isDismissed, setIsDismissed] = react.useState(false);
1486
+ const [progress, setProgress] = react.useState(0);
1487
+ const trackedImpressions = react.useRef(/* @__PURE__ */ new Set());
1488
+ const timerRef = react.useRef(null);
1489
+ react.useEffect(() => {
1490
+ try {
1491
+ const dismissed = sessionStorage.getItem(DISMISSED_TOPBAR_KEY);
1492
+ if (dismissed === "true") {
1493
+ setIsDismissed(true);
1494
+ }
1495
+ } catch {
1496
+ }
1497
+ }, []);
1498
+ const handleDismiss = react.useCallback(() => {
1499
+ setIsDismissed(true);
1500
+ try {
1501
+ sessionStorage.setItem(DISMISSED_TOPBAR_KEY, "true");
1502
+ } catch {
1503
+ }
1504
+ }, []);
1505
+ const {
1506
+ campaigns,
1507
+ loading,
1508
+ recordImpression,
1509
+ recordClick
1510
+ } = useCommonFeatures.useCampaigns({ placement, maxCampaigns });
1511
+ react.useEffect(() => {
1512
+ if (campaigns.length === 0) return;
1513
+ const campaign2 = campaigns[currentIndex];
1514
+ if (!campaign2 || trackedImpressions.current.has(campaign2.id)) return;
1515
+ trackedImpressions.current.add(campaign2.id);
1516
+ recordImpression(campaign2);
1517
+ }, [currentIndex, campaigns, recordImpression]);
1518
+ react.useEffect(() => {
1519
+ if (campaigns.length <= 1) return;
1520
+ setProgress(0);
1521
+ const progressInterval = 50;
1522
+ const steps = rotationInterval / progressInterval;
1523
+ let currentStep = 0;
1524
+ timerRef.current = setInterval(() => {
1525
+ currentStep++;
1526
+ setProgress(currentStep / steps * 100);
1527
+ if (currentStep >= steps) {
1528
+ setIsAnimating(true);
1529
+ setTimeout(() => {
1530
+ setCurrentIndex((prev) => (prev + 1) % campaigns.length);
1531
+ setProgress(0);
1532
+ currentStep = 0;
1533
+ setTimeout(() => setIsAnimating(false), 50);
1534
+ }, 200);
1535
+ }
1536
+ }, progressInterval);
1537
+ return () => {
1538
+ if (timerRef.current) clearInterval(timerRef.current);
1539
+ };
1540
+ }, [campaigns.length, rotationInterval, currentIndex]);
1541
+ const handleClick = react.useCallback(
1542
+ (campaign2) => {
1543
+ recordClick(campaign2);
1544
+ const targetUrl = campaign2.customCtaUrl || campaign2.product.url;
1545
+ window.open(targetUrl, "_blank");
1546
+ },
1547
+ [recordClick]
1548
+ );
1549
+ const resetTimer = react.useCallback(() => {
1550
+ if (timerRef.current) clearInterval(timerRef.current);
1551
+ setProgress(0);
1552
+ }, []);
1553
+ const goToPrev = react.useCallback(() => {
1554
+ resetTimer();
1555
+ setIsAnimating(true);
1556
+ setTimeout(() => {
1557
+ setCurrentIndex((prev) => (prev - 1 + campaigns.length) % campaigns.length);
1558
+ setTimeout(() => setIsAnimating(false), 50);
1559
+ }, 200);
1560
+ }, [campaigns.length, resetTimer]);
1561
+ const goToNext = react.useCallback(() => {
1562
+ resetTimer();
1563
+ setIsAnimating(true);
1564
+ setTimeout(() => {
1565
+ setCurrentIndex((prev) => (prev + 1) % campaigns.length);
1566
+ setTimeout(() => setIsAnimating(false), 50);
1567
+ }, 200);
1568
+ }, [campaigns.length, resetTimer]);
1569
+ if (loading || campaigns.length === 0 || isDismissed) return null;
1570
+ const campaign = campaigns[currentIndex];
1571
+ if (!campaign) return null;
1572
+ const { product } = campaign;
1573
+ const displayTitle = campaign.customTitle || product.name;
1574
+ const displayTagline = campaign.customTagline || product.tagline;
1575
+ const displayCta = campaign.customCta || "Learn More";
1576
+ const displayColor = campaign.customProductColor || product.color || "#3B82F6";
1577
+ const displayIcon = campaign.customIcon || product.icon64 || "";
1578
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1579
+ themes.Box,
1580
+ {
1581
+ className,
1582
+ style: {
1583
+ background: `linear-gradient(135deg, ${displayColor}12 0%, ${displayColor}08 50%, ${displayColor}12 100%)`,
1584
+ borderBottom: `1px solid ${displayColor}30`,
1585
+ position: "relative",
1586
+ height: 100,
1587
+ maxHeight: 100,
1588
+ overflow: "hidden",
1589
+ ...style
1590
+ },
1591
+ children: [
1592
+ /* @__PURE__ */ jsxRuntime.jsx(
1593
+ themes.Box,
1594
+ {
1595
+ style: {
1596
+ position: "absolute",
1597
+ inset: 0,
1598
+ background: `radial-gradient(ellipse at 50% 0%, ${displayColor}15 0%, transparent 70%)`,
1599
+ pointerEvents: "none"
1600
+ }
1601
+ }
1602
+ ),
1603
+ /* @__PURE__ */ jsxRuntime.jsx(themes.Box, { style: { height: 3, background: "var(--gray-a3)", position: "relative", zIndex: 1 }, children: /* @__PURE__ */ jsxRuntime.jsx(
1604
+ themes.Box,
1605
+ {
1606
+ style: {
1607
+ position: "absolute",
1608
+ top: 0,
1609
+ left: 0,
1610
+ height: "100%",
1611
+ width: `${progress}%`,
1612
+ background: `linear-gradient(90deg, ${displayColor}, ${displayColor}cc)`,
1613
+ transition: "width 50ms linear",
1614
+ boxShadow: `0 0 10px ${displayColor}60`
1615
+ }
1616
+ }
1617
+ ) }),
1618
+ /* @__PURE__ */ jsxRuntime.jsx(themes.Container, { size: "4", style: { height: "calc(100% - 3px)" }, children: /* @__PURE__ */ jsxRuntime.jsxs(
1619
+ themes.Flex,
1620
+ {
1621
+ align: "center",
1622
+ justify: "between",
1623
+ gap: { initial: "2", sm: "4" },
1624
+ style: {
1625
+ height: "100%",
1626
+ padding: "0 16px"
1627
+ },
1628
+ children: [
1629
+ /* @__PURE__ */ jsxRuntime.jsxs(themes.Flex, { gap: "2", align: "center", style: { flexShrink: 0 }, children: [
1630
+ /* @__PURE__ */ jsxRuntime.jsx(
1631
+ themes.Box,
1632
+ {
1633
+ style: {
1634
+ width: 28,
1635
+ height: 28,
1636
+ borderRadius: 6,
1637
+ background: `${displayColor}20`,
1638
+ display: "flex",
1639
+ alignItems: "center",
1640
+ justifyContent: "center"
1641
+ },
1642
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Sparkles, { size: 14, color: displayColor })
1643
+ }
1644
+ ),
1645
+ campaigns.length > 1 && /* @__PURE__ */ jsxRuntime.jsx(themes.Box, { display: { initial: "none", md: "block" }, children: /* @__PURE__ */ jsxRuntime.jsx(
1646
+ themes.IconButton,
1647
+ {
1648
+ size: "1",
1649
+ variant: "ghost",
1650
+ color: "gray",
1651
+ onClick: goToPrev,
1652
+ style: { cursor: "pointer" },
1653
+ "aria-label": "Previous ad",
1654
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronLeft, { size: 16 })
1655
+ }
1656
+ ) })
1657
+ ] }),
1658
+ /* @__PURE__ */ jsxRuntime.jsxs(
1659
+ themes.Flex,
1660
+ {
1661
+ align: "center",
1662
+ gap: { initial: "2", sm: "3" },
1663
+ style: {
1664
+ flex: 1,
1665
+ minWidth: 0,
1666
+ opacity: isAnimating ? 0 : 1,
1667
+ transform: isAnimating ? "translateY(-8px)" : "translateY(0)",
1668
+ transition: "all 0.25s cubic-bezier(0.4, 0, 0.2, 1)"
1669
+ },
1670
+ children: [
1671
+ /* @__PURE__ */ jsxRuntime.jsx(
1672
+ themes.Box,
1673
+ {
1674
+ style: {
1675
+ width: 48,
1676
+ height: 48,
1677
+ borderRadius: 10,
1678
+ background: `linear-gradient(135deg, ${displayColor}25 0%, ${displayColor}15 100%)`,
1679
+ border: `1.5px solid ${displayColor}35`,
1680
+ display: "flex",
1681
+ alignItems: "center",
1682
+ justifyContent: "center",
1683
+ flexShrink: 0,
1684
+ boxShadow: `0 2px 8px ${displayColor}20`
1685
+ },
1686
+ dangerouslySetInnerHTML: { __html: displayIcon }
1687
+ }
1688
+ ),
1689
+ /* @__PURE__ */ jsxRuntime.jsxs(themes.Flex, { direction: "column", gap: "0", style: { minWidth: 0, flex: 1 }, children: [
1690
+ /* @__PURE__ */ jsxRuntime.jsx(themes.Text, { size: "2", weight: "bold", style: { lineHeight: 1.3 }, children: displayTitle }),
1691
+ /* @__PURE__ */ jsxRuntime.jsx(
1692
+ themes.Text,
1693
+ {
1694
+ size: "1",
1695
+ color: "gray",
1696
+ style: {
1697
+ display: "-webkit-box",
1698
+ WebkitLineClamp: 1,
1699
+ WebkitBoxOrient: "vertical",
1700
+ overflow: "hidden",
1701
+ lineHeight: 1.4
1702
+ },
1703
+ children: displayTagline
1704
+ }
1705
+ )
1706
+ ] }),
1707
+ /* @__PURE__ */ jsxRuntime.jsx(
1708
+ themes.Button,
1709
+ {
1710
+ size: "2",
1711
+ onClick: () => handleClick(campaign),
1712
+ style: {
1713
+ background: `linear-gradient(135deg, ${displayColor} 0%, ${displayColor}dd 100%)`,
1714
+ color: "white",
1715
+ fontWeight: 600,
1716
+ fontSize: "13px",
1717
+ padding: "0 16px",
1718
+ height: 32,
1719
+ flexShrink: 0,
1720
+ boxShadow: `0 2px 8px ${displayColor}40`,
1721
+ border: "none"
1722
+ },
1723
+ children: /* @__PURE__ */ jsxRuntime.jsxs("span", { style: { display: "flex", alignItems: "center", gap: 6 }, children: [
1724
+ displayCta,
1725
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ExternalLink, { size: 13 })
1726
+ ] })
1727
+ }
1728
+ )
1729
+ ]
1730
+ }
1731
+ ),
1732
+ /* @__PURE__ */ jsxRuntime.jsxs(themes.Flex, { gap: "1", align: "center", style: { flexShrink: 0 }, children: [
1733
+ campaigns.length > 1 && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1734
+ /* @__PURE__ */ jsxRuntime.jsx(themes.Box, { display: { initial: "none", md: "block" }, children: /* @__PURE__ */ jsxRuntime.jsx(
1735
+ themes.IconButton,
1736
+ {
1737
+ size: "1",
1738
+ variant: "ghost",
1739
+ color: "gray",
1740
+ onClick: goToNext,
1741
+ style: { cursor: "pointer" },
1742
+ "aria-label": "Next ad",
1743
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { size: 16 })
1744
+ }
1745
+ ) }),
1746
+ /* @__PURE__ */ jsxRuntime.jsx(themes.Flex, { gap: "1", mx: "2", display: { initial: "none", sm: "flex" }, children: campaigns.map((_, i) => /* @__PURE__ */ jsxRuntime.jsx(
1747
+ themes.Box,
1748
+ {
1749
+ style: {
1750
+ width: i === currentIndex ? 16 : 6,
1751
+ height: 6,
1752
+ borderRadius: 3,
1753
+ background: i === currentIndex ? displayColor : "var(--gray-a5)",
1754
+ cursor: "pointer",
1755
+ transition: "all 0.2s ease"
1756
+ },
1757
+ onClick: () => {
1758
+ resetTimer();
1759
+ setCurrentIndex(i);
1760
+ }
1761
+ },
1762
+ i
1763
+ )) })
1764
+ ] }),
1765
+ /* @__PURE__ */ jsxRuntime.jsx(
1766
+ themes.IconButton,
1767
+ {
1768
+ size: "1",
1769
+ variant: "soft",
1770
+ color: "gray",
1771
+ onClick: handleDismiss,
1772
+ style: { cursor: "pointer", marginLeft: 4 },
1773
+ "aria-label": "Close banner",
1774
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { size: 14 })
1775
+ }
1776
+ )
1777
+ ] })
1778
+ ]
1779
+ }
1780
+ ) }),
1781
+ campaigns.length > 1 && /* @__PURE__ */ jsxRuntime.jsx(
1782
+ themes.Flex,
1783
+ {
1784
+ justify: "center",
1785
+ gap: "1",
1786
+ style: {
1787
+ position: "absolute",
1788
+ bottom: 6,
1789
+ left: 0,
1790
+ right: 0
1791
+ },
1792
+ display: { initial: "flex", sm: "none" },
1793
+ children: campaigns.map((_, i) => /* @__PURE__ */ jsxRuntime.jsx(
1794
+ themes.Box,
1795
+ {
1796
+ style: {
1797
+ width: 6,
1798
+ height: 6,
1799
+ borderRadius: "50%",
1800
+ background: i === currentIndex ? displayColor : "var(--gray-a5)",
1801
+ transition: "background 0.2s ease"
1802
+ }
1803
+ },
1804
+ i
1805
+ ))
1806
+ }
1807
+ )
1808
+ ]
1809
+ }
1810
+ );
1811
+ }
1812
+ function AdCarousel({
1813
+ placement = "home_banner",
1814
+ rotationInterval = 2e4,
1815
+ maxCampaigns = 5,
1816
+ className,
1817
+ style
1818
+ }) {
1819
+ const [currentIndex, setCurrentIndex] = react.useState(0);
1820
+ const [isAnimating, setIsAnimating] = react.useState(false);
1821
+ const [progress, setProgress] = react.useState(0);
1822
+ const trackedImpressions = react.useRef(/* @__PURE__ */ new Set());
1823
+ const timerRef = react.useRef(null);
1824
+ const {
1825
+ campaigns,
1826
+ loading,
1827
+ recordImpression,
1828
+ recordClick
1829
+ } = useCommonFeatures.useCampaigns({ placement, maxCampaigns });
1830
+ react.useEffect(() => {
1831
+ if (campaigns.length === 0) return;
1832
+ const campaign2 = campaigns[currentIndex];
1833
+ if (!campaign2 || trackedImpressions.current.has(campaign2.id)) return;
1834
+ trackedImpressions.current.add(campaign2.id);
1835
+ recordImpression(campaign2);
1836
+ }, [currentIndex, campaigns, recordImpression]);
1837
+ react.useEffect(() => {
1838
+ if (campaigns.length <= 1) return;
1839
+ setProgress(0);
1840
+ const progressInterval = 50;
1841
+ const steps = rotationInterval / progressInterval;
1842
+ let currentStep = 0;
1843
+ timerRef.current = setInterval(() => {
1844
+ currentStep++;
1845
+ setProgress(currentStep / steps * 100);
1846
+ if (currentStep >= steps) {
1847
+ setIsAnimating(true);
1848
+ setTimeout(() => {
1849
+ setCurrentIndex((prev) => (prev + 1) % campaigns.length);
1850
+ setProgress(0);
1851
+ currentStep = 0;
1852
+ setTimeout(() => setIsAnimating(false), 50);
1853
+ }, 250);
1854
+ }
1855
+ }, progressInterval);
1856
+ return () => {
1857
+ if (timerRef.current) clearInterval(timerRef.current);
1858
+ };
1859
+ }, [campaigns.length, rotationInterval, currentIndex]);
1860
+ const handleClick = react.useCallback(
1861
+ (campaign2) => {
1862
+ recordClick(campaign2);
1863
+ const targetUrl = campaign2.customCtaUrl || campaign2.product.url;
1864
+ window.open(targetUrl, "_blank");
1865
+ },
1866
+ [recordClick]
1867
+ );
1868
+ const resetTimer = react.useCallback(() => {
1869
+ if (timerRef.current) clearInterval(timerRef.current);
1870
+ setProgress(0);
1871
+ }, []);
1872
+ const goToPrev = react.useCallback(() => {
1873
+ resetTimer();
1874
+ setIsAnimating(true);
1875
+ setTimeout(() => {
1876
+ setCurrentIndex((prev) => (prev - 1 + campaigns.length) % campaigns.length);
1877
+ setTimeout(() => setIsAnimating(false), 50);
1878
+ }, 250);
1879
+ }, [campaigns.length, resetTimer]);
1880
+ const goToNext = react.useCallback(() => {
1881
+ resetTimer();
1882
+ setIsAnimating(true);
1883
+ setTimeout(() => {
1884
+ setCurrentIndex((prev) => (prev + 1) % campaigns.length);
1885
+ setTimeout(() => setIsAnimating(false), 50);
1886
+ }, 250);
1887
+ }, [campaigns.length, resetTimer]);
1888
+ const goToSlide = react.useCallback((index) => {
1889
+ if (index === currentIndex) return;
1890
+ resetTimer();
1891
+ setIsAnimating(true);
1892
+ setTimeout(() => {
1893
+ setCurrentIndex(index);
1894
+ setTimeout(() => setIsAnimating(false), 50);
1895
+ }, 250);
1896
+ }, [currentIndex, resetTimer]);
1897
+ if (loading || campaigns.length === 0) return null;
1898
+ const campaign = campaigns[currentIndex];
1899
+ if (!campaign) return null;
1900
+ const { product } = campaign;
1901
+ const displayTitle = campaign.customTitle || product.name;
1902
+ const displayTagline = campaign.customTagline || product.tagline;
1903
+ const displayCta = campaign.customCta || "Learn More";
1904
+ const displayColor = campaign.customProductColor || product.color || "#3B82F6";
1905
+ const displayIcon = campaign.customIcon || product.icon64 || "";
1906
+ const displayFeatures = campaign.customFeatures || product.features || [];
1907
+ const displayDescription = product.description || displayTagline;
1908
+ const getProductTypeLabel = () => {
1909
+ switch (product.type) {
1910
+ case "extension":
1911
+ return "Browser Extension";
1912
+ case "android":
1913
+ return "Android App";
1914
+ case "ios":
1915
+ return "iOS App";
1916
+ case "web":
1917
+ return "Web App";
1918
+ default:
1919
+ return "App";
1920
+ }
1921
+ };
1922
+ return /* @__PURE__ */ jsxRuntime.jsx(
1923
+ themes.Box,
1924
+ {
1925
+ className,
1926
+ style: {
1927
+ padding: "24px 0",
1928
+ ...style
1929
+ },
1930
+ children: /* @__PURE__ */ jsxRuntime.jsx(themes.Container, { size: "4", children: /* @__PURE__ */ jsxRuntime.jsxs(
1931
+ themes.Card,
1932
+ {
1933
+ style: {
1934
+ background: `linear-gradient(145deg, var(--color-background) 0%, ${displayColor}08 100%)`,
1935
+ border: `1px solid ${displayColor}20`,
1936
+ borderRadius: 16,
1937
+ overflow: "hidden",
1938
+ height: 350,
1939
+ position: "relative"
1940
+ },
1941
+ children: [
1942
+ /* @__PURE__ */ jsxRuntime.jsx(
1943
+ themes.Box,
1944
+ {
1945
+ style: {
1946
+ position: "absolute",
1947
+ top: -100,
1948
+ right: -100,
1949
+ width: 300,
1950
+ height: 300,
1951
+ borderRadius: "50%",
1952
+ background: `radial-gradient(circle, ${displayColor}12 0%, transparent 70%)`,
1953
+ pointerEvents: "none"
1954
+ }
1955
+ }
1956
+ ),
1957
+ /* @__PURE__ */ jsxRuntime.jsx(
1958
+ themes.Box,
1959
+ {
1960
+ style: {
1961
+ position: "absolute",
1962
+ bottom: -50,
1963
+ left: -50,
1964
+ width: 200,
1965
+ height: 200,
1966
+ borderRadius: "50%",
1967
+ background: `radial-gradient(circle, ${displayColor}08 0%, transparent 70%)`,
1968
+ pointerEvents: "none"
1969
+ }
1970
+ }
1971
+ ),
1972
+ campaigns.length > 1 && /* @__PURE__ */ jsxRuntime.jsx(themes.Box, { style: { height: 4, background: "var(--gray-a3)", position: "relative", zIndex: 2 }, children: /* @__PURE__ */ jsxRuntime.jsx(
1973
+ themes.Box,
1974
+ {
1975
+ style: {
1976
+ position: "absolute",
1977
+ top: 0,
1978
+ left: 0,
1979
+ height: "100%",
1980
+ width: `${progress}%`,
1981
+ background: `linear-gradient(90deg, ${displayColor} 0%, ${displayColor}cc 100%)`,
1982
+ transition: "width 50ms linear",
1983
+ boxShadow: `0 0 12px ${displayColor}50`
1984
+ }
1985
+ }
1986
+ ) }),
1987
+ /* @__PURE__ */ jsxRuntime.jsxs(themes.Box, { style: { height: "calc(100% - 4px)", position: "relative", zIndex: 1 }, children: [
1988
+ /* @__PURE__ */ jsxRuntime.jsxs(
1989
+ themes.Flex,
1990
+ {
1991
+ direction: { initial: "column", md: "row" },
1992
+ align: "stretch",
1993
+ style: { height: "100%" },
1994
+ children: [
1995
+ campaigns.length > 1 && /* @__PURE__ */ jsxRuntime.jsx(
1996
+ themes.Flex,
1997
+ {
1998
+ align: "center",
1999
+ justify: "center",
2000
+ style: { width: 60, flexShrink: 0 },
2001
+ display: { initial: "none", md: "flex" },
2002
+ children: /* @__PURE__ */ jsxRuntime.jsx(
2003
+ themes.IconButton,
2004
+ {
2005
+ size: "3",
2006
+ variant: "ghost",
2007
+ color: "gray",
2008
+ onClick: goToPrev,
2009
+ style: {
2010
+ cursor: "pointer",
2011
+ width: 44,
2012
+ height: 44,
2013
+ borderRadius: 12,
2014
+ background: "var(--gray-a3)"
2015
+ },
2016
+ "aria-label": "Previous",
2017
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronLeft, { size: 24 })
2018
+ }
2019
+ )
2020
+ }
2021
+ ),
2022
+ /* @__PURE__ */ jsxRuntime.jsxs(
2023
+ themes.Flex,
2024
+ {
2025
+ direction: { initial: "column", md: "row" },
2026
+ align: "center",
2027
+ gap: { initial: "4", md: "6" },
2028
+ p: { initial: "4", md: "5" },
2029
+ style: {
2030
+ flex: 1,
2031
+ opacity: isAnimating ? 0 : 1,
2032
+ transform: isAnimating ? "translateX(-20px) scale(0.98)" : "translateX(0) scale(1)",
2033
+ transition: "all 0.3s cubic-bezier(0.4, 0, 0.2, 1)"
2034
+ },
2035
+ children: [
2036
+ /* @__PURE__ */ jsxRuntime.jsxs(
2037
+ themes.Flex,
2038
+ {
2039
+ direction: "column",
2040
+ align: "center",
2041
+ gap: "3",
2042
+ style: { flexShrink: 0 },
2043
+ children: [
2044
+ /* @__PURE__ */ jsxRuntime.jsx(
2045
+ themes.Box,
2046
+ {
2047
+ style: {
2048
+ width: 100,
2049
+ height: 100,
2050
+ borderRadius: 20,
2051
+ background: `linear-gradient(145deg, ${displayColor}20 0%, ${displayColor}10 100%)`,
2052
+ border: `2px solid ${displayColor}30`,
2053
+ display: "flex",
2054
+ alignItems: "center",
2055
+ justifyContent: "center",
2056
+ boxShadow: `0 8px 32px ${displayColor}20, inset 0 1px 0 ${displayColor}20`
2057
+ },
2058
+ dangerouslySetInnerHTML: { __html: displayIcon }
2059
+ }
2060
+ ),
2061
+ /* @__PURE__ */ jsxRuntime.jsxs(
2062
+ themes.Badge,
2063
+ {
2064
+ size: "2",
2065
+ style: {
2066
+ background: `${displayColor}15`,
2067
+ color: displayColor,
2068
+ fontWeight: 600,
2069
+ padding: "4px 12px"
2070
+ },
2071
+ children: [
2072
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Zap, { size: 12, style: { marginRight: 4 } }),
2073
+ getProductTypeLabel()
2074
+ ]
2075
+ }
2076
+ )
2077
+ ]
2078
+ }
2079
+ ),
2080
+ /* @__PURE__ */ jsxRuntime.jsxs(
2081
+ themes.Flex,
2082
+ {
2083
+ direction: "column",
2084
+ gap: "3",
2085
+ style: { flex: 1, minWidth: 0, textAlign: "left" },
2086
+ children: [
2087
+ /* @__PURE__ */ jsxRuntime.jsxs(themes.Flex, { align: "center", gap: "2", wrap: "wrap", children: [
2088
+ /* @__PURE__ */ jsxRuntime.jsx(
2089
+ themes.Text,
2090
+ {
2091
+ size: { initial: "5", md: "6" },
2092
+ weight: "bold",
2093
+ style: { lineHeight: 1.2 },
2094
+ children: displayTitle
2095
+ }
2096
+ ),
2097
+ /* @__PURE__ */ jsxRuntime.jsxs(
2098
+ themes.Flex,
2099
+ {
2100
+ align: "center",
2101
+ gap: "1",
2102
+ style: {
2103
+ background: `${displayColor}15`,
2104
+ padding: "4px 8px",
2105
+ borderRadius: 6
2106
+ },
2107
+ children: [
2108
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Star, { size: 12, fill: displayColor, color: displayColor }),
2109
+ /* @__PURE__ */ jsxRuntime.jsx(themes.Text, { size: "1", weight: "medium", style: { color: displayColor }, children: "Featured" })
2110
+ ]
2111
+ }
2112
+ )
2113
+ ] }),
2114
+ /* @__PURE__ */ jsxRuntime.jsx(
2115
+ themes.Text,
2116
+ {
2117
+ size: { initial: "2", md: "3" },
2118
+ color: "gray",
2119
+ style: {
2120
+ lineHeight: 1.5,
2121
+ display: "-webkit-box",
2122
+ WebkitLineClamp: 2,
2123
+ WebkitBoxOrient: "vertical",
2124
+ overflow: "hidden"
2125
+ },
2126
+ children: displayDescription
2127
+ }
2128
+ ),
2129
+ displayFeatures.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
2130
+ themes.Flex,
2131
+ {
2132
+ gap: { initial: "2", md: "4" },
2133
+ wrap: "wrap",
2134
+ mt: "1",
2135
+ children: displayFeatures.slice(0, 4).map((feature, i) => /* @__PURE__ */ jsxRuntime.jsxs(
2136
+ themes.Flex,
2137
+ {
2138
+ align: "center",
2139
+ gap: "2",
2140
+ style: {
2141
+ background: "var(--gray-a3)",
2142
+ padding: "6px 12px",
2143
+ borderRadius: 8
2144
+ },
2145
+ children: [
2146
+ /* @__PURE__ */ jsxRuntime.jsx(
2147
+ themes.Box,
2148
+ {
2149
+ style: {
2150
+ width: 18,
2151
+ height: 18,
2152
+ borderRadius: 4,
2153
+ background: `${displayColor}20`,
2154
+ display: "flex",
2155
+ alignItems: "center",
2156
+ justifyContent: "center"
2157
+ },
2158
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { size: 12, color: displayColor, strokeWidth: 3 })
2159
+ }
2160
+ ),
2161
+ /* @__PURE__ */ jsxRuntime.jsx(themes.Text, { size: "1", weight: "medium", children: feature })
2162
+ ]
2163
+ },
2164
+ i
2165
+ ))
2166
+ }
2167
+ ),
2168
+ /* @__PURE__ */ jsxRuntime.jsxs(
2169
+ themes.Flex,
2170
+ {
2171
+ gap: "3",
2172
+ align: "center",
2173
+ mt: { initial: "2", md: "3" },
2174
+ wrap: "wrap",
2175
+ children: [
2176
+ /* @__PURE__ */ jsxRuntime.jsx(
2177
+ themes.Button,
2178
+ {
2179
+ size: { initial: "2", md: "3" },
2180
+ onClick: () => handleClick(campaign),
2181
+ style: {
2182
+ background: `linear-gradient(135deg, ${displayColor} 0%, ${displayColor}dd 100%)`,
2183
+ color: "white",
2184
+ fontWeight: 600,
2185
+ padding: "0 24px",
2186
+ height: 44,
2187
+ boxShadow: `0 4px 16px ${displayColor}40`,
2188
+ border: "none",
2189
+ cursor: "pointer"
2190
+ },
2191
+ children: /* @__PURE__ */ jsxRuntime.jsxs("span", { style: { display: "flex", alignItems: "center", gap: 8 }, children: [
2192
+ displayCta,
2193
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowRight, { size: 18 })
2194
+ ] })
2195
+ }
2196
+ ),
2197
+ /* @__PURE__ */ jsxRuntime.jsx(
2198
+ themes.Button,
2199
+ {
2200
+ size: { initial: "2", md: "3" },
2201
+ variant: "ghost",
2202
+ onClick: () => handleClick(campaign),
2203
+ style: {
2204
+ color: displayColor,
2205
+ fontWeight: 500,
2206
+ cursor: "pointer"
2207
+ },
2208
+ children: /* @__PURE__ */ jsxRuntime.jsxs("span", { style: { display: "flex", alignItems: "center", gap: 6 }, children: [
2209
+ "View Details",
2210
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ExternalLink, { size: 14 })
2211
+ ] })
2212
+ }
2213
+ )
2214
+ ]
2215
+ }
2216
+ )
2217
+ ]
2218
+ }
2219
+ )
2220
+ ]
2221
+ }
2222
+ ),
2223
+ campaigns.length > 1 && /* @__PURE__ */ jsxRuntime.jsx(
2224
+ themes.Flex,
2225
+ {
2226
+ align: "center",
2227
+ justify: "center",
2228
+ style: { width: 60, flexShrink: 0 },
2229
+ display: { initial: "none", md: "flex" },
2230
+ children: /* @__PURE__ */ jsxRuntime.jsx(
2231
+ themes.IconButton,
2232
+ {
2233
+ size: "3",
2234
+ variant: "ghost",
2235
+ color: "gray",
2236
+ onClick: goToNext,
2237
+ style: {
2238
+ cursor: "pointer",
2239
+ width: 44,
2240
+ height: 44,
2241
+ borderRadius: 12,
2242
+ background: "var(--gray-a3)"
2243
+ },
2244
+ "aria-label": "Next",
2245
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { size: 24 })
2246
+ }
2247
+ )
2248
+ }
2249
+ )
2250
+ ]
2251
+ }
2252
+ ),
2253
+ campaigns.length > 1 && /* @__PURE__ */ jsxRuntime.jsxs(
2254
+ themes.Flex,
2255
+ {
2256
+ justify: "center",
2257
+ align: "center",
2258
+ gap: "3",
2259
+ style: {
2260
+ position: "absolute",
2261
+ bottom: 16,
2262
+ left: 0,
2263
+ right: 0
2264
+ },
2265
+ children: [
2266
+ /* @__PURE__ */ jsxRuntime.jsx(themes.Box, { display: { initial: "block", md: "none" }, children: /* @__PURE__ */ jsxRuntime.jsx(
2267
+ themes.IconButton,
2268
+ {
2269
+ size: "1",
2270
+ variant: "soft",
2271
+ color: "gray",
2272
+ onClick: goToPrev,
2273
+ style: { cursor: "pointer" },
2274
+ "aria-label": "Previous",
2275
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronLeft, { size: 16 })
2276
+ }
2277
+ ) }),
2278
+ /* @__PURE__ */ jsxRuntime.jsx(themes.Flex, { gap: "2", children: campaigns.map((c, i) => /* @__PURE__ */ jsxRuntime.jsx(
2279
+ themes.Box,
2280
+ {
2281
+ onClick: () => goToSlide(i),
2282
+ style: {
2283
+ width: i === currentIndex ? 32 : 10,
2284
+ height: 10,
2285
+ borderRadius: 5,
2286
+ background: i === currentIndex ? `linear-gradient(90deg, ${c.product?.color || displayColor}, ${c.product?.color || displayColor}cc)` : "var(--gray-a4)",
2287
+ cursor: "pointer",
2288
+ transition: "all 0.3s cubic-bezier(0.4, 0, 0.2, 1)",
2289
+ boxShadow: i === currentIndex ? `0 2px 8px ${c.product?.color || displayColor}40` : "none"
2290
+ }
2291
+ },
2292
+ i
2293
+ )) }),
2294
+ /* @__PURE__ */ jsxRuntime.jsx(themes.Box, { display: { initial: "block", md: "none" }, children: /* @__PURE__ */ jsxRuntime.jsx(
2295
+ themes.IconButton,
2296
+ {
2297
+ size: "1",
2298
+ variant: "soft",
2299
+ color: "gray",
2300
+ onClick: goToNext,
2301
+ style: { cursor: "pointer" },
2302
+ "aria-label": "Next",
2303
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { size: 16 })
2304
+ }
2305
+ ) })
2306
+ ]
2307
+ }
2308
+ )
2309
+ ] })
2310
+ ]
2311
+ }
2312
+ ) })
2313
+ }
2314
+ );
2315
+ }
1475
2316
  const TYPE_STYLES = {
1476
2317
  info: {
1477
2318
  icon: lucideReact.Info,
@@ -2082,6 +2923,7 @@ function FooterSection({ showContact = true, showSocialLinks = true, showAddress
2082
2923
  ] });
2083
2924
  }
2084
2925
  exports.AdBanner = AdBanner;
2926
+ exports.AdCarousel = AdCarousel;
2085
2927
  exports.AdModal = AdModal;
2086
2928
  exports.AdPanel = AdPanel;
2087
2929
  exports.AdSlider = AdSlider;
@@ -2108,7 +2950,8 @@ exports.SocialLinksBar = SocialLinksBar;
2108
2950
  exports.TaglineVariant = TaglineVariant;
2109
2951
  exports.TestimonialVariant = TestimonialVariant;
2110
2952
  exports.TestimonialsGrid = TestimonialsGrid;
2953
+ exports.TopbarAdBanner = TopbarAdBanner;
2111
2954
  exports.VideoVariant = VideoVariant;
2112
2955
  exports.getLargePanelVariant = getLargePanelVariant;
2113
2956
  exports.getSmallPanelVariant = getSmallPanelVariant;
2114
- //# sourceMappingURL=index-CLd2pR09.cjs.map
2957
+ //# sourceMappingURL=index-CyHJYPl1.cjs.map