@opensite/ui 0.9.9 → 1.0.1

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.
@@ -885,6 +885,160 @@ var NavbarLogo = ({
885
885
  }
886
886
  );
887
887
  };
888
+ var svgCache = /* @__PURE__ */ new Map();
889
+ function DynamicIcon({
890
+ name,
891
+ size = 28,
892
+ color,
893
+ className,
894
+ alt
895
+ }) {
896
+ const [svgContent, setSvgContent] = React__namespace.useState(null);
897
+ const [isLoading, setIsLoading] = React__namespace.useState(true);
898
+ const [error, setError] = React__namespace.useState(null);
899
+ const { url, iconName } = React__namespace.useMemo(() => {
900
+ const separator = name.includes("/") ? "/" : ":";
901
+ const [prefix, iconName2] = name.split(separator);
902
+ const baseUrl = `https://icons.opensite.ai/api/icon/${prefix}/${iconName2}?format=svg&width=${size}&height=${size}`;
903
+ return {
904
+ url: baseUrl,
905
+ iconName: iconName2
906
+ };
907
+ }, [name, size]);
908
+ React__namespace.useEffect(() => {
909
+ let isMounted = true;
910
+ const fetchSvg = async () => {
911
+ const cached = svgCache.get(url);
912
+ if (cached) {
913
+ if (isMounted) {
914
+ setSvgContent(cached);
915
+ setIsLoading(false);
916
+ }
917
+ return;
918
+ }
919
+ try {
920
+ setIsLoading(true);
921
+ setError(null);
922
+ const response = await fetch(url);
923
+ if (!response.ok) {
924
+ throw new Error(`Failed to fetch icon: ${response.status}`);
925
+ }
926
+ let svg = await response.text();
927
+ svg = processSvgForCurrentColor(svg);
928
+ svgCache.set(url, svg);
929
+ if (isMounted) {
930
+ setSvgContent(svg);
931
+ setIsLoading(false);
932
+ }
933
+ } catch (err) {
934
+ if (isMounted) {
935
+ setError(err instanceof Error ? err.message : "Failed to load icon");
936
+ setIsLoading(false);
937
+ }
938
+ }
939
+ };
940
+ fetchSvg();
941
+ return () => {
942
+ isMounted = false;
943
+ };
944
+ }, [url]);
945
+ if (isLoading) {
946
+ return /* @__PURE__ */ jsxRuntime.jsx(
947
+ "span",
948
+ {
949
+ className: cn("inline-block", className),
950
+ style: { width: size, height: size },
951
+ "aria-hidden": "true"
952
+ }
953
+ );
954
+ }
955
+ if (error || !svgContent) {
956
+ return /* @__PURE__ */ jsxRuntime.jsx(
957
+ "span",
958
+ {
959
+ className: cn("inline-block", className),
960
+ style: { width: size, height: size },
961
+ role: "img",
962
+ "aria-label": alt || iconName
963
+ }
964
+ );
965
+ }
966
+ return /* @__PURE__ */ jsxRuntime.jsx(
967
+ "span",
968
+ {
969
+ className: cn("inline-flex items-center justify-center", className),
970
+ style: {
971
+ width: size,
972
+ height: size,
973
+ color: color || "inherit"
974
+ },
975
+ role: "img",
976
+ "aria-label": alt || iconName,
977
+ dangerouslySetInnerHTML: { __html: svgContent }
978
+ }
979
+ );
980
+ }
981
+ function processSvgForCurrentColor(svg) {
982
+ let processed = svg;
983
+ processed = processed.replace(
984
+ /stroke=["'](#000000|#000|black)["']/gi,
985
+ 'stroke="currentColor"'
986
+ );
987
+ processed = processed.replace(
988
+ /fill=["'](#000000|#000|black)["']/gi,
989
+ 'fill="currentColor"'
990
+ );
991
+ return processed;
992
+ }
993
+ var platformIconMap = {
994
+ instagram: "cib/instagram",
995
+ linkedin: "cib/linkedin",
996
+ google: "cib/google",
997
+ facebook: "cib/facebook",
998
+ tiktok: "cib/tiktok",
999
+ youtube: "cib/youtube",
1000
+ yelp: "cib/yelp",
1001
+ spotify: "cib/spotify",
1002
+ apple: "cib/apple",
1003
+ x: "line-md/twitter-x"
1004
+ };
1005
+ var SocialLinkIcon = React__namespace.forwardRef(
1006
+ ({
1007
+ platformName,
1008
+ label,
1009
+ iconSize = 20,
1010
+ iconColor,
1011
+ iconClassName,
1012
+ className,
1013
+ ...pressableProps
1014
+ }, ref) => {
1015
+ const iconName = platformIconMap[platformName];
1016
+ const accessibleLabel = label || platformName;
1017
+ return /* @__PURE__ */ jsxRuntime.jsx(
1018
+ Pressable,
1019
+ {
1020
+ ref,
1021
+ "aria-label": accessibleLabel,
1022
+ className: cn(
1023
+ "inline-flex items-center justify-center transition-colors",
1024
+ className
1025
+ ),
1026
+ ...pressableProps,
1027
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1028
+ DynamicIcon,
1029
+ {
1030
+ name: iconName,
1031
+ size: iconSize,
1032
+ color: iconColor,
1033
+ className: iconClassName,
1034
+ alt: accessibleLabel
1035
+ }
1036
+ )
1037
+ }
1038
+ );
1039
+ }
1040
+ );
1041
+ SocialLinkIcon.displayName = "SocialLinkIcon";
888
1042
 
889
1043
  // lib/mediaPlaceholders.ts
890
1044
  var logoPlaceholders = {
@@ -954,36 +1108,35 @@ var NavbarFullscreenMenu = ({
954
1108
  const renderMenuItems = React.useMemo(() => {
955
1109
  if (menuSlot) return menuSlot;
956
1110
  if (!menuItems || menuItems.length === 0) return null;
957
- return menuItems.map((item, index) => /* @__PURE__ */ jsxRuntime.jsx(
1111
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "group/menu-container", children: menuItems.map((item, index) => /* @__PURE__ */ jsxRuntime.jsx(
958
1112
  "div",
959
1113
  {
960
- className: "mb-5 animate-in slide-in-from-bottom-4 fade-in",
1114
+ className: "group/menu-item mb-5 animate-in slide-in-from-bottom-4 fade-in",
961
1115
  style: {
962
1116
  animationDelay: `${0.2 + index * 0.1}s`,
963
1117
  animationFillMode: "both"
964
1118
  },
965
- children: /* @__PURE__ */ jsxRuntime.jsxs(Pressable, { href: item.href, className: "group relative inline-block", children: [
966
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "relative z-10 text-4xl font-black text-foreground uppercase transition-all duration-300 md:text-6xl group-hover:opacity-80 group-hover:blur-[6px]", children: item.label }),
967
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute bottom-0 left-0 h-1 w-0 bg-primary transition-all duration-300 group-hover:w-full" })
1119
+ children: /* @__PURE__ */ jsxRuntime.jsxs(Pressable, { href: item.href, className: "relative inline-block", children: [
1120
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "relative z-10 text-4xl font-black text-foreground uppercase transition-all duration-300 md:text-6xl group-hover/menu-container:opacity-50 group-hover/menu-container:blur-[4px] group-hover/menu-item:!opacity-100 group-hover/menu-item:!blur-none", children: item.label }),
1121
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute bottom-0 left-0 h-1 w-0 bg-primary transition-all duration-300 group-hover/menu-item:w-full" })
968
1122
  ] })
969
1123
  },
970
1124
  item.label
971
- ));
1125
+ )) });
972
1126
  }, [menuSlot, menuItems]);
973
1127
  const renderSocialLinks = React.useMemo(() => {
974
1128
  if (socialLinksSlot) return socialLinksSlot;
975
1129
  if (!socialLinks || socialLinks.length === 0) return null;
976
- return socialLinks.map((link, index) => /* @__PURE__ */ jsxRuntime.jsx(
977
- Pressable,
1130
+ return socialLinks.map((link) => /* @__PURE__ */ jsxRuntime.jsx(
1131
+ SocialLinkIcon,
978
1132
  {
1133
+ platformName: link.platformName,
979
1134
  href: link.href,
980
- target: "_blank",
981
- rel: "noopener noreferrer",
982
- className: "group flex items-center gap-2 font-mono text-sm tracking-wider text-muted-foreground transition-colors hover:text-foreground hover:translate-x-1",
983
- style: { animationDelay: `${0.8 + index * 0.1}s` },
984
- children: /* @__PURE__ */ jsxRuntime.jsx("span", { children: link.label })
1135
+ label: link.label,
1136
+ iconSize: 24,
1137
+ className: "text-muted-foreground transition-all duration-300 hover:text-foreground hover:scale-110"
985
1138
  },
986
- link.label
1139
+ link.platformName
987
1140
  ));
988
1141
  }, [socialLinksSlot, socialLinks]);
989
1142
  const {
@@ -995,18 +1148,18 @@ var NavbarFullscreenMenu = ({
995
1148
  sectionContainerMaxWidth,
996
1149
  spacingOverride
997
1150
  } = getNavbarLayoutClasses(layoutVariant, { className, containerClassName });
998
- return /* @__PURE__ */ jsxRuntime.jsx(
999
- Section,
1000
- {
1001
- background,
1002
- spacing: spacingOverride ?? spacing,
1003
- className: sectionClasses,
1004
- pattern,
1005
- patternOpacity,
1006
- containerClassName: sectionContainerClassName,
1007
- containerMaxWidth: sectionContainerMaxWidth,
1008
- children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: containerWrapperClasses, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: navWrapperClasses, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: innerContainerClasses, children: [
1009
- /* @__PURE__ */ jsxRuntime.jsxs(
1151
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1152
+ /* @__PURE__ */ jsxRuntime.jsx(
1153
+ Section,
1154
+ {
1155
+ background,
1156
+ spacing: spacingOverride ?? spacing,
1157
+ className: sectionClasses,
1158
+ pattern,
1159
+ patternOpacity,
1160
+ containerClassName: sectionContainerClassName,
1161
+ containerMaxWidth: sectionContainerMaxWidth,
1162
+ children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: containerWrapperClasses, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: navWrapperClasses, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: innerContainerClasses, children: /* @__PURE__ */ jsxRuntime.jsxs(
1010
1163
  "nav",
1011
1164
  {
1012
1165
  className: cn(
@@ -1023,60 +1176,75 @@ var NavbarFullscreenMenu = ({
1023
1176
  optixFlowConfig
1024
1177
  }
1025
1178
  ) }),
1026
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "z-50", children: /* @__PURE__ */ jsxRuntime.jsxs(
1179
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "z-50", children: /* @__PURE__ */ jsxRuntime.jsx(
1027
1180
  "button",
1028
1181
  {
1029
1182
  onClick: toggleMenu,
1030
- className: "text-lg tracking-wider text-foreground transition-colors hover:text-muted-foreground",
1031
- children: [
1032
- /* @__PURE__ */ jsxRuntime.jsx(
1033
- "span",
1034
- {
1035
- className: `inline-block transition-all duration-200 ${isOpen ? "opacity-0 -translate-y-2" : "opacity-100 translate-y-0"}`,
1036
- style: { display: isOpen ? "none" : "inline-block" },
1037
- children: isOpen ? "" : "\u2630"
1038
- }
1039
- ),
1040
- /* @__PURE__ */ jsxRuntime.jsx(
1041
- "span",
1042
- {
1043
- className: `inline-block transition-all duration-200 ${isOpen ? "opacity-100 translate-y-0" : "opacity-0 translate-y-2"}`,
1044
- style: { display: isOpen ? "inline-block" : "none" },
1045
- children: isOpen ? "\u2715" : ""
1046
- }
1047
- )
1048
- ]
1183
+ className: "text-2xl tracking-wider text-foreground transition-colors hover:text-muted-foreground",
1184
+ "aria-label": isOpen ? "Close menu" : "Open menu",
1185
+ children: "\u2630"
1049
1186
  }
1050
1187
  ) })
1051
1188
  ]
1052
1189
  }
1190
+ ) }) }) })
1191
+ }
1192
+ ),
1193
+ isOpen && /* @__PURE__ */ jsxRuntime.jsxs(
1194
+ "div",
1195
+ {
1196
+ className: cn(
1197
+ "fixed inset-0 z-50 flex flex-col bg-background animate-in fade-in duration-300",
1198
+ overlayClassName
1053
1199
  ),
1054
- isOpen && /* @__PURE__ */ jsxRuntime.jsx(
1055
- "div",
1056
- {
1057
- className: cn(
1058
- "fixed inset-0 z-40 overflow-hidden bg-background animate-in fade-in duration-300",
1059
- overlayClassName
1200
+ children: [
1201
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-6 py-6", children: [
1202
+ /* @__PURE__ */ jsxRuntime.jsx(
1203
+ NavbarLogo,
1204
+ {
1205
+ logo,
1206
+ logoSlot,
1207
+ logoClassName,
1208
+ optixFlowConfig
1209
+ }
1060
1210
  ),
1061
- children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex h-full flex-col items-center justify-center px-6", children: [
1062
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("mb-16 text-center", menuItemsClassName), children: renderMenuItems }),
1063
- /* @__PURE__ */ jsxRuntime.jsx(
1064
- "div",
1065
- {
1066
- className: cn(
1067
- "flex flex-col gap-8 sm:flex-row sm:gap-12 animate-in slide-in-from-bottom-4 fade-in",
1068
- socialLinksClassName
1069
- ),
1070
- style: { animationDelay: "0.7s", animationFillMode: "both" },
1071
- children: renderSocialLinks
1072
- }
1073
- )
1074
- ] })
1075
- }
1076
- )
1077
- ] }) }) })
1078
- }
1079
- );
1211
+ /* @__PURE__ */ jsxRuntime.jsx(
1212
+ "button",
1213
+ {
1214
+ onClick: toggleMenu,
1215
+ className: "text-2xl text-foreground transition-colors hover:text-muted-foreground",
1216
+ "aria-label": "Close menu",
1217
+ children: "\u2715"
1218
+ }
1219
+ )
1220
+ ] }),
1221
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-1 flex-col items-center justify-center overflow-y-auto px-6 py-8", children: [
1222
+ /* @__PURE__ */ jsxRuntime.jsx(
1223
+ "div",
1224
+ {
1225
+ className: cn(
1226
+ "mb-12 max-h-[60vh] overflow-y-auto text-center md:max-h-none",
1227
+ menuItemsClassName
1228
+ ),
1229
+ children: renderMenuItems
1230
+ }
1231
+ ),
1232
+ /* @__PURE__ */ jsxRuntime.jsx(
1233
+ "div",
1234
+ {
1235
+ className: cn(
1236
+ "flex flex-row flex-wrap items-center justify-center gap-6 animate-in slide-in-from-bottom-4 fade-in",
1237
+ socialLinksClassName
1238
+ ),
1239
+ style: { animationDelay: "0.7s", animationFillMode: "both" },
1240
+ children: renderSocialLinks
1241
+ }
1242
+ )
1243
+ ] })
1244
+ ]
1245
+ }
1246
+ )
1247
+ ] });
1080
1248
  };
1081
1249
 
1082
1250
  exports.NavbarFullscreenMenu = NavbarFullscreenMenu;
@@ -1,8 +1,10 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import * as React from 'react';
3
+ import { SocialPlatformName } from './social-link-icon.cjs';
3
4
  import { f as SectionBackground, g as SectionSpacing, t as PatternName } from './community-initiatives-CPyEa7IX.cjs';
4
5
  import { L as LogoConfig, N as NavbarLayoutVariant } from './types-COVDidbn.cjs';
5
6
  import { O as OptixFlowConfig } from './blocks-tmd_MRJv.cjs';
7
+ import './pressable.cjs';
6
8
  import 'class-variance-authority';
7
9
  import './button-variants-8mtEHxev.cjs';
8
10
  import 'class-variance-authority/types';
@@ -11,9 +13,16 @@ interface MenuItem {
11
13
  label: string;
12
14
  href: string;
13
15
  }
14
- interface SocialLink {
15
- label: string;
16
+ /**
17
+ * Social link configuration for fullscreen menu
18
+ */
19
+ interface NavbarFullscreenMenuSocialLink {
20
+ /** Social platform name - determines which icon to display */
21
+ platformName: SocialPlatformName;
22
+ /** URL to the social profile */
16
23
  href: string;
24
+ /** Optional label for accessibility (defaults to platform name) */
25
+ label?: string;
17
26
  }
18
27
  /**
19
28
  * Props for the NavbarFullscreenMenu component
@@ -66,7 +75,7 @@ interface NavbarFullscreenMenuProps {
66
75
  /**
67
76
  * Social links displayed at bottom of fullscreen menu
68
77
  */
69
- socialLinks?: SocialLink[];
78
+ socialLinks?: NavbarFullscreenMenuSocialLink[];
70
79
  /**
71
80
  * Custom slot for social links (overrides socialLinks array)
72
81
  */
@@ -1,8 +1,10 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import * as React from 'react';
3
+ import { SocialPlatformName } from './social-link-icon.js';
3
4
  import { f as SectionBackground, g as SectionSpacing, t as PatternName } from './community-initiatives-hxnFe3w6.js';
4
5
  import { L as LogoConfig, N as NavbarLayoutVariant } from './types-COVDidbn.js';
5
6
  import { O as OptixFlowConfig } from './blocks-DRE-f6cS.js';
7
+ import './pressable.js';
6
8
  import 'class-variance-authority';
7
9
  import './button-variants-8mtEHxev.js';
8
10
  import 'class-variance-authority/types';
@@ -11,9 +13,16 @@ interface MenuItem {
11
13
  label: string;
12
14
  href: string;
13
15
  }
14
- interface SocialLink {
15
- label: string;
16
+ /**
17
+ * Social link configuration for fullscreen menu
18
+ */
19
+ interface NavbarFullscreenMenuSocialLink {
20
+ /** Social platform name - determines which icon to display */
21
+ platformName: SocialPlatformName;
22
+ /** URL to the social profile */
16
23
  href: string;
24
+ /** Optional label for accessibility (defaults to platform name) */
25
+ label?: string;
17
26
  }
18
27
  /**
19
28
  * Props for the NavbarFullscreenMenu component
@@ -66,7 +75,7 @@ interface NavbarFullscreenMenuProps {
66
75
  /**
67
76
  * Social links displayed at bottom of fullscreen menu
68
77
  */
69
- socialLinks?: SocialLink[];
78
+ socialLinks?: NavbarFullscreenMenuSocialLink[];
70
79
  /**
71
80
  * Custom slot for social links (overrides socialLinks array)
72
81
  */