@pixelated-tech/components 3.2.1 → 3.2.4

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 (161) hide show
  1. package/dist/components/carousel/carousel.css +5 -0
  2. package/dist/components/cms/contentful.items.components.js +1 -1
  3. package/dist/components/cms/google.reviews.components.js +7 -0
  4. package/dist/components/cms/hubspot.components.js +33 -1
  5. package/dist/components/cms/wordpress.functions.js +52 -0
  6. package/dist/components/general/loading.js +16 -15
  7. package/dist/components/menu/menu-accordion.js +9 -14
  8. package/dist/components/menu/menu-expando.css +97 -90
  9. package/dist/components/menu/menu-expando.js +115 -17
  10. package/dist/components/menu/menu-simple.css +4 -0
  11. package/dist/components/menu/menu-simple.js +8 -3
  12. package/dist/components/pagebuilder/components/SaveLoadSection.js +1 -1
  13. package/dist/components/seo/404.js +1 -1
  14. package/dist/components/seo/sitemap.js +16 -4
  15. package/dist/components/shoppingcart/shoppingcart.components.js +1 -1
  16. package/dist/components/structured/buzzwordbingo.js +1 -1
  17. package/dist/components/structured/recipe.js +1 -1
  18. package/dist/components/structured/socialcard.js +1 -1
  19. package/dist/index.js +1 -2
  20. package/dist/index.server.js +0 -1
  21. package/dist/types/components/cms/google.reviews.components.d.ts +10 -0
  22. package/dist/types/components/cms/google.reviews.components.d.ts.map +1 -1
  23. package/dist/types/components/cms/hubspot.components.d.ts +16 -0
  24. package/dist/types/components/cms/hubspot.components.d.ts.map +1 -1
  25. package/dist/types/components/cms/wordpress.functions.d.ts +31 -0
  26. package/dist/types/components/cms/wordpress.functions.d.ts.map +1 -1
  27. package/dist/types/components/general/loading.d.ts.map +1 -1
  28. package/dist/types/components/menu/menu-accordion.d.ts.map +1 -1
  29. package/dist/types/components/menu/menu-expando.d.ts.map +1 -1
  30. package/dist/types/components/menu/menu-simple.d.ts +1 -1
  31. package/dist/types/components/menu/menu-simple.d.ts.map +1 -1
  32. package/dist/types/components/seo/sitemap.d.ts +2 -0
  33. package/dist/types/components/seo/sitemap.d.ts.map +1 -1
  34. package/dist/types/index.d.ts +1 -1
  35. package/dist/types/index.server.d.ts +0 -1
  36. package/dist/types/stories/menu/menu-expando.stories.d.ts +8 -0
  37. package/dist/types/stories/menu/menu-expando.stories.d.ts.map +1 -0
  38. package/dist/types/tests/api.test.d.ts +2 -0
  39. package/dist/types/tests/api.test.d.ts.map +1 -0
  40. package/dist/types/tests/buzzwordbingo.test.d.ts +2 -0
  41. package/dist/types/tests/buzzwordbingo.test.d.ts.map +1 -0
  42. package/dist/types/tests/calendly.test.d.ts +2 -0
  43. package/dist/types/tests/calendly.test.d.ts.map +1 -0
  44. package/dist/types/tests/callout.test.d.ts +2 -0
  45. package/dist/types/tests/callout.test.d.ts.map +1 -0
  46. package/dist/types/tests/carousel-drag.test.d.ts +2 -0
  47. package/dist/types/tests/carousel-drag.test.d.ts.map +1 -0
  48. package/dist/types/tests/carousel.test.d.ts +2 -0
  49. package/dist/types/tests/carousel.test.d.ts.map +1 -0
  50. package/dist/types/tests/cloudinary-image.test.d.ts +2 -0
  51. package/dist/types/tests/cloudinary-image.test.d.ts.map +1 -0
  52. package/dist/types/tests/cloudinary.test.d.ts +2 -0
  53. package/dist/types/tests/cloudinary.test.d.ts.map +1 -0
  54. package/dist/types/tests/config.client.test.d.ts +2 -0
  55. package/dist/types/tests/config.client.test.d.ts.map +1 -0
  56. package/dist/types/tests/config.server.test.d.ts +2 -0
  57. package/dist/types/tests/config.server.test.d.ts.map +1 -0
  58. package/dist/types/tests/contentful-items.test.d.ts +2 -0
  59. package/dist/types/tests/contentful-items.test.d.ts.map +1 -0
  60. package/dist/types/tests/contentful.delivery.test.d.ts +2 -0
  61. package/dist/types/tests/contentful.delivery.test.d.ts.map +1 -0
  62. package/dist/types/tests/css.test.d.ts +2 -0
  63. package/dist/types/tests/css.test.d.ts.map +1 -0
  64. package/dist/types/tests/ebay.test.d.ts +2 -0
  65. package/dist/types/tests/ebay.test.d.ts.map +1 -0
  66. package/dist/types/tests/form.test.d.ts +2 -0
  67. package/dist/types/tests/form.test.d.ts.map +1 -0
  68. package/dist/types/tests/formcomponents.test.d.ts +2 -0
  69. package/dist/types/tests/formcomponents.test.d.ts.map +1 -0
  70. package/dist/types/tests/formvalidations.test.d.ts +2 -0
  71. package/dist/types/tests/formvalidations.test.d.ts.map +1 -0
  72. package/dist/types/tests/functions.test.d.ts +2 -0
  73. package/dist/types/tests/functions.test.d.ts.map +1 -0
  74. package/dist/types/tests/google-analytics.test.d.ts +2 -0
  75. package/dist/types/tests/google-analytics.test.d.ts.map +1 -0
  76. package/dist/types/tests/google-map.test.d.ts +2 -0
  77. package/dist/types/tests/google-map.test.d.ts.map +1 -0
  78. package/dist/types/tests/google-reviews.test.d.ts +2 -0
  79. package/dist/types/tests/google-reviews.test.d.ts.map +1 -0
  80. package/dist/types/tests/googlesearch.test.d.ts +2 -0
  81. package/dist/types/tests/googlesearch.test.d.ts.map +1 -0
  82. package/dist/types/tests/gravatar.test.d.ts +2 -0
  83. package/dist/types/tests/gravatar.test.d.ts.map +1 -0
  84. package/dist/types/tests/hubspot.test.d.ts +2 -0
  85. package/dist/types/tests/hubspot.test.d.ts.map +1 -0
  86. package/dist/types/tests/image.test.d.ts +2 -0
  87. package/dist/types/tests/image.test.d.ts.map +1 -0
  88. package/dist/types/tests/instagram.test.d.ts +2 -0
  89. package/dist/types/tests/instagram.test.d.ts.map +1 -0
  90. package/dist/types/tests/loading.test.d.ts +2 -0
  91. package/dist/types/tests/loading.test.d.ts.map +1 -0
  92. package/dist/types/tests/markdown.test.d.ts +2 -0
  93. package/dist/types/tests/markdown.test.d.ts.map +1 -0
  94. package/dist/types/tests/menu-accordion.test.d.ts +2 -0
  95. package/dist/types/tests/menu-accordion.test.d.ts.map +1 -0
  96. package/dist/types/tests/menu-expando.test.d.ts +2 -0
  97. package/dist/types/tests/menu-expando.test.d.ts.map +1 -0
  98. package/dist/types/tests/menu-simple.test.d.ts +2 -0
  99. package/dist/types/tests/menu-simple.test.d.ts.map +1 -0
  100. package/dist/types/tests/metadata.components.test.d.ts +2 -0
  101. package/dist/types/tests/metadata.components.test.d.ts.map +1 -0
  102. package/dist/types/tests/microinteractions.test.d.ts +2 -0
  103. package/dist/types/tests/microinteractions.test.d.ts.map +1 -0
  104. package/dist/types/tests/modal.test.d.ts +2 -0
  105. package/dist/types/tests/modal.test.d.ts.map +1 -0
  106. package/dist/types/tests/nerdjoke.test.d.ts +2 -0
  107. package/dist/types/tests/nerdjoke.test.d.ts.map +1 -0
  108. package/dist/types/tests/paypal.test.d.ts +2 -0
  109. package/dist/types/tests/paypal.test.d.ts.map +1 -0
  110. package/dist/types/tests/pixelated.menu-expando.test.d.ts +2 -0
  111. package/dist/types/tests/pixelated.menu-expando.test.d.ts.map +1 -0
  112. package/dist/types/tests/recipe.test.d.ts +2 -0
  113. package/dist/types/tests/recipe.test.d.ts.map +1 -0
  114. package/dist/types/tests/resume.test.d.ts +2 -0
  115. package/dist/types/tests/resume.test.d.ts.map +1 -0
  116. package/dist/types/tests/semantic.test.d.ts +2 -0
  117. package/dist/types/tests/semantic.test.d.ts.map +1 -0
  118. package/dist/types/tests/setup.d.ts +2 -0
  119. package/dist/types/tests/setup.d.ts.map +1 -0
  120. package/dist/types/tests/shopping-cart.test.d.ts +2 -0
  121. package/dist/types/tests/shopping-cart.test.d.ts.map +1 -0
  122. package/dist/types/tests/shoppingcart.components.test.d.ts +2 -0
  123. package/dist/types/tests/shoppingcart.components.test.d.ts.map +1 -0
  124. package/dist/types/tests/shoppingcart.functions.test.d.ts +2 -0
  125. package/dist/types/tests/shoppingcart.functions.test.d.ts.map +1 -0
  126. package/dist/types/tests/sidepanel.test.d.ts +2 -0
  127. package/dist/types/tests/sidepanel.test.d.ts.map +1 -0
  128. package/dist/types/tests/socialcard.test.d.ts +2 -0
  129. package/dist/types/tests/socialcard.test.d.ts.map +1 -0
  130. package/dist/types/tests/table.test.d.ts +2 -0
  131. package/dist/types/tests/table.test.d.ts.map +1 -0
  132. package/dist/types/tests/tiles.test.d.ts +2 -0
  133. package/dist/types/tests/tiles.test.d.ts.map +1 -0
  134. package/dist/types/tests/timeline.test.d.ts +2 -0
  135. package/dist/types/tests/timeline.test.d.ts.map +1 -0
  136. package/dist/types/tests/wordpress.test.d.ts +2 -0
  137. package/dist/types/tests/wordpress.test.d.ts.map +1 -0
  138. package/dist/types/tests/yelp.test.d.ts +2 -0
  139. package/dist/types/tests/yelp.test.d.ts.map +1 -0
  140. package/package.json +20 -7
  141. package/dist/components/cms/hubspot.js +0 -34
  142. package/dist/types/components/cms/hubspot.d.ts +0 -18
  143. package/dist/types/components/cms/hubspot.d.ts.map +0 -1
  144. package/dist/types/tests/pixelated.api.test.d.ts +0 -2
  145. package/dist/types/tests/pixelated.api.test.d.ts.map +0 -1
  146. package/dist/types/tests/pixelated.callout.test.d.ts +0 -2
  147. package/dist/types/tests/pixelated.callout.test.d.ts.map +0 -1
  148. package/dist/types/tests/pixelated.carousel.test.d.ts +0 -2
  149. package/dist/types/tests/pixelated.carousel.test.d.ts.map +0 -1
  150. package/dist/types/tests/pixelated.menu-accordion.test.d.ts +0 -2
  151. package/dist/types/tests/pixelated.menu-accordion.test.d.ts.map +0 -1
  152. package/dist/types/tests/pixelated.menu-simple.test.d.ts +0 -2
  153. package/dist/types/tests/pixelated.menu-simple.test.d.ts.map +0 -1
  154. package/dist/types/tests/pixelated.nerdjoke.test.d.ts +0 -2
  155. package/dist/types/tests/pixelated.nerdjoke.test.d.ts.map +0 -1
  156. package/dist/types/tests/pixelated.recipe.test.d.ts +0 -2
  157. package/dist/types/tests/pixelated.recipe.test.d.ts.map +0 -1
  158. package/dist/types/tests/pixelated.resume.test.d.ts +0 -2
  159. package/dist/types/tests/pixelated.resume.test.d.ts.map +0 -1
  160. package/dist/types/tests/pixelated.socialcard.test.d.ts +0 -2
  161. package/dist/types/tests/pixelated.socialcard.test.d.ts.map +0 -1
@@ -146,6 +146,11 @@
146
146
  background-color: transparent;
147
147
  }
148
148
 
149
+ .carousel-container .carousel-buttons button.carousel-button {
150
+ /* fix for buttonring microinteraction */
151
+ outline: none !important;
152
+ }
153
+
149
154
  .carousel-arrow,
150
155
  .carousel-arrow-left,
151
156
  .carousel-arrow-right {
@@ -215,7 +215,7 @@ export function ContentfulItemDetail(props) {
215
215
  }
216
216
  }
217
217
  fetchStuff();
218
- }, []);
218
+ }, [props.entry_id, apiProps]);
219
219
  if (item && Object.keys(item) && Object.keys(item).length > 0) {
220
220
  const thisItem = { ...item };
221
221
  if (debug)
@@ -1,7 +1,14 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { useState, useEffect } from 'react';
4
+ import PropTypes from 'prop-types';
4
5
  import { getGoogleReviewsByPlaceId } from './google.reviews.functions';
6
+ GoogleReviewsCard.propTypes = {
7
+ placeID: PropTypes.string.isRequired,
8
+ language: PropTypes.string,
9
+ maxReviews: PropTypes.number,
10
+ proxyBase: PropTypes.string,
11
+ };
5
12
  export function GoogleReviewsCard(props) {
6
13
  const [place, setPlace] = useState();
7
14
  const [reviews, setReviews] = useState([]);
@@ -1,5 +1,5 @@
1
1
  'use client';
2
- import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
3
3
  import { useEffect } from 'react';
4
4
  import PropTypes from 'prop-types';
5
5
  export function initializeHubSpotScript(region, portalId) {
@@ -43,3 +43,35 @@ export function HubSpotForm({ region, portalId, formId, target, containerId = 'h
43
43
  }, [region, portalId, formId, formTarget]);
44
44
  return _jsx("div", { className: "hs-form-frame", "data-region": region, "data-form-id": formId, "data-portal-id": portalId });
45
45
  }
46
+ HubspotTrackingCode.propTypes = {
47
+ hubID: PropTypes.string.isRequired,
48
+ };
49
+ export function HubspotTrackingCode(props) {
50
+ return (_jsx(_Fragment, { children: _jsx("script", { type: "text/javascript", id: "hs-script-loader", async: true, defer: true, src: `//js-na2.hs-scripts.com/${props.hubID}.js` }) }));
51
+ }
52
+ getHubspotFormSubmissions.propTypes = {
53
+ proxyURL: PropTypes.string.isRequired,
54
+ formGUID: PropTypes.string.isRequired,
55
+ apiToken: PropTypes.string.isRequired,
56
+ };
57
+ export async function getHubspotFormSubmissions(props) {
58
+ const url = `${props.proxyURL}https://api.hubapi.com/form-integrations/v1/submissions/forms/${props.formGUID}`;
59
+ const headers = {
60
+ Authorization: "Bearer " + props.apiToken,
61
+ };
62
+ try {
63
+ const response = await fetch(url, {
64
+ method: 'GET',
65
+ headers: headers,
66
+ });
67
+ if (!response.ok) {
68
+ throw new Error(`HTTP error! status: ${response.status}`);
69
+ }
70
+ const data = await response.json();
71
+ return data;
72
+ }
73
+ catch (error) {
74
+ console.error('Error fetching HubSpot form submissions:', error);
75
+ return null;
76
+ }
77
+ }
@@ -1,8 +1,13 @@
1
+ import PropTypes from "prop-types";
1
2
  // const wpSite = "pixelatedviews.wordpress.com";
2
3
  // const wpSite = "19824045";
3
4
  // const wpSite = "blog.pixelated.tech";
4
5
  const wpApiURL = "https://public-api.wordpress.com/rest/v1/sites/";
5
6
  const wpCategoriesPath = "/categories";
7
+ getWordPressItems.propTypes = {
8
+ site: PropTypes.string.isRequired,
9
+ count: PropTypes.number,
10
+ };
6
11
  export async function getWordPressItems(props) {
7
12
  const requested = props.count; // undefined means fetch all available
8
13
  const posts = [];
@@ -31,6 +36,53 @@ export async function getWordPressItems(props) {
31
36
  }
32
37
  return posts;
33
38
  }
39
+ getWordPressItemImages.propTypes = {
40
+ item: PropTypes.object.isRequired,
41
+ };
42
+ export function getWordPressItemImages(item) {
43
+ const images = [];
44
+ const seen = new Set();
45
+ // Helper to swap image origin with post origin
46
+ const swapOrigin = (url) => {
47
+ try {
48
+ const postOrigin = new URL(item.URL).origin;
49
+ const urlObj = new URL(url);
50
+ return `${postOrigin}${urlObj.pathname}`;
51
+ }
52
+ catch (error) {
53
+ console.log("Error: ", error);
54
+ return url;
55
+ }
56
+ };
57
+ // Featured image
58
+ if (item.featured_image && !seen.has(item.featured_image)) {
59
+ seen.add(item.featured_image);
60
+ images.push({
61
+ url: swapOrigin(item.featured_image),
62
+ title: item.title,
63
+ caption: item.excerpt,
64
+ thumbnail_loc: item.post_thumbnail?.URL,
65
+ });
66
+ }
67
+ // Attachments
68
+ if (item.attachments) {
69
+ for (const key in item.attachments) {
70
+ const att = item.attachments[key];
71
+ if (att.URL && !seen.has(att.URL)) {
72
+ seen.add(att.URL);
73
+ images.push({
74
+ url: swapOrigin(att.URL),
75
+ title: att.title,
76
+ caption: att.caption || att.description,
77
+ });
78
+ }
79
+ }
80
+ }
81
+ return images;
82
+ }
83
+ getWordPressCategories.propTypes = {
84
+ site: PropTypes.string.isRequired,
85
+ };
34
86
  export async function getWordPressCategories(props) {
35
87
  const wpCategoriesURL = wpApiURL + props.site + wpCategoriesPath;
36
88
  const categories = [];
@@ -1,3 +1,4 @@
1
+ 'use client';
1
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
3
  import PropTypes from "prop-types";
3
4
  import "./loading.scss";
@@ -13,24 +14,24 @@ ToggleLoading.propTypes = {
13
14
  show: PropTypes.bool,
14
15
  };
15
16
  export function ToggleLoading(props) {
16
- if (typeof window !== "undefined" && typeof document !== "undefined") {
17
- const loadingElem = document.getElementById("loadingSpinner");
18
- if (!loadingElem)
19
- return;
20
- if (props.show && props.show === true) {
17
+ if (typeof window === 'undefined' || typeof document === 'undefined')
18
+ return;
19
+ const loadingElem = document.getElementById("loadingSpinner");
20
+ if (!loadingElem)
21
+ return;
22
+ if (props.show === true) {
23
+ loadingElem.style.display = "inline-block";
24
+ }
25
+ else if (props.show === false) {
26
+ loadingElem.style.display = "none";
27
+ }
28
+ else {
29
+ // Toggle behavior
30
+ if (loadingElem.style.display === "none" || !loadingElem.style.display) {
21
31
  loadingElem.style.display = "inline-block";
22
- return;
23
- } // Show content
24
- if (props.show && props.show === false) {
25
- loadingElem.style.display = "none";
26
- return;
27
- } // Hide content
28
- if (loadingElem && loadingElem.style.display === "none") {
29
- loadingElem.style.display = "inline-block"; // Show content
30
32
  }
31
33
  else {
32
- if (loadingElem)
33
- loadingElem.style.display = "none"; // Hide content
34
+ loadingElem.style.display = "none";
34
35
  }
35
36
  }
36
37
  }
@@ -140,7 +140,7 @@ export function MenuAccordion(props) {
140
140
  document.removeEventListener('click', handleMenuClick);
141
141
  };
142
142
  }, []);
143
- return (_jsx("div", { className: "accordionMenuWrapper accordionUp", children: _jsx("div", { className: "accordionMenu", id: "accordionMenu", children: _jsx(MenuAccordionGroup, { menuItems: menuItems, state: undefined }, "accordionRoot") }) }));
143
+ return (_jsx("div", { className: "accordionMenuWrapper accordionUp", suppressHydrationWarning: true, children: _jsx("div", { className: "accordionMenu", id: "accordionMenu", children: _jsx(MenuAccordionGroup, { menuItems: menuItems, state: undefined }, "accordionRoot") }) }));
144
144
  }
145
145
  /* ========== MENU GROUP ========== */
146
146
  MenuAccordionGroup.propTypes = {
@@ -158,17 +158,9 @@ MenuAccordionItem.propTypes = {
158
158
  target: PropTypes.string,
159
159
  };
160
160
  export function MenuAccordionItem(props) {
161
- if (props.href && props.href.length > 0) {
162
- if (props.target && props.target.length > 0) {
163
- return (_jsx("li", { children: _jsx("a", { href: props.href, target: props.target, children: props.name }) }, "menu-item-" + props.name));
164
- }
165
- else {
166
- return (_jsx("li", { children: _jsx("a", { href: props.href, children: props.name }) }, "menu-item-" + props.name));
167
- }
168
- }
169
- else {
170
- return (_jsx("li", { children: _jsx("a", { children: props.name }) }, "menu-item-" + props.name));
171
- }
161
+ // Always render the same JSX structure to avoid hydration mismatch
162
+ // href will be undefined or an empty string, target might be undefined
163
+ return (_jsx("li", { children: _jsx("a", { href: props.href || undefined, target: props.target || undefined, children: props.name }) }, "menu-item-" + props.name));
172
164
  }
173
165
  /* ========== MENU BUTTON ========== */
174
166
  /*
@@ -177,7 +169,10 @@ https://www.unclebigbay.com/blog/building-the-world-simplest-hamburger-with-html
177
169
  MenuAccordionButton.propTypes = {};
178
170
  export function MenuAccordionButton() {
179
171
  function slideMobilePanel() {
180
- window.moveMenu();
172
+ if (typeof window !== 'undefined' && window.moveMenu) {
173
+ window.moveMenu();
174
+ }
181
175
  }
182
- return (_jsx("button", { className: "panelMenuButton", id: "panelMenuButton", onClick: slideMobilePanel, children: _jsx("span", { className: "hamburger text-outline", children: "|||" }) }));
176
+ // suppressHydrationWarning suppresses hydration mismatch warnings for this button
177
+ return (_jsx("button", { className: "panelMenuButton", id: "panelMenuButton", onClick: slideMobilePanel, suppressHydrationWarning: true, children: _jsx("span", { className: "hamburger text-outline", children: "|||" }) }));
183
178
  }
@@ -1,127 +1,134 @@
1
1
 
2
+
2
3
  /* ========================================
3
- ===== SLIDING PANEL MENU =====
4
+ ===== MENU EXPANDO COMPONENT =====
4
5
  ======================================== */
5
6
 
6
- .menuExpandoButton {
7
- /* background-color: rgba(255,255,255,0.7); */
8
- /* display: none; */
9
- /* display: inline; */
10
- margin: 0px 10px 0px 0px;
11
- padding: 5px;
12
- text-align: center;
13
- width: 35px;
7
+ .menuExpando {
8
+ display: inline-block;
9
+ }
14
10
 
15
- /* .rounded; */
16
- -moz-border-radius: 5px;
17
- -webkit-border-radius: 5px;
18
- border-radius: 5px;
11
+ details.menuExpandoWrapper {
12
+ display: inline-block;
19
13
  }
20
14
 
21
- @media screen and (max-width: 480px) {
22
- .menuExpandoButton {
23
- display: inline;
24
- }
15
+ details.menuExpandoWrapper > summary {
16
+ cursor: pointer;
17
+ user-select: none;
18
+ background: #336699;
19
+ color: white;
20
+ padding: 10px 15px;
21
+ border-radius: 4px;
22
+ font-weight: bold;
23
+ display: inline-block;
24
+ transition: background 0.3s ease;
25
25
  }
26
26
 
27
- .menuExpandoButtonHeader {
28
- background-color: #336699;
29
- /* background-image: url(/images/pix/pix-bg.gif); */
30
- color: #FFFFFF;
31
- padding: 15px;
27
+ details.menuExpandoWrapper > summary:hover {
28
+ background: #2d5a8a;
29
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
30
+ }
32
31
 
33
- /* .rounded; */
34
- -moz-border-radius: 5px;
35
- -webkit-border-radius: 5px;
36
- border-radius: 5px;
32
+ details.menuExpandoWrapper > summary::marker,
33
+ details.menuExpandoWrapper > summary::-webkit-details-marker {
34
+ display: none;
37
35
  }
38
36
 
37
+ details.menuExpandoWrapper > summary::before {
38
+ content: '▼';
39
+ display: inline-block;
40
+ }
39
41
 
40
- /* ========================================
41
- ============ ACCORDION MENU ============
42
- ======================================== */
42
+ details.menuExpandoWrapper[open] > summary::before {
43
+ content: '▲';
44
+ }
43
45
 
44
- details.menuExpandoWrapper {
45
- /* background: #FFF; */
46
- background: rgba(150, 190, 250, 0.7);
47
- border-right: 1px solid #ccc;
48
- /* height: auto; */
49
- position: fixed;
50
- left: 0px;
51
- top: 60px;
52
- /* height: 100%; */
53
- width: 220px;
54
- z-index: 1000;
55
- /* padding: 5px; */
46
+ details.menuExpandoWrapper ul {
47
+ margin-top: 10px;
48
+ padding-left: 20px;
49
+ list-style: none;
50
+ overflow: visible;
51
+ max-height: 1000px;
56
52
  }
57
53
 
58
- details.menuExpandoWrapper > summary {
59
- /* display: none; */
60
- list-style: none;
61
- height: 0px;
62
- width: 0px;
54
+ details.menuExpandoWrapper li {
55
+ margin: 5px 0;
63
56
  }
64
57
 
65
- details.menuExpandoWrapper[open] > summary {
66
- --do-nothing: true;
58
+ details.menuExpandoWrapper a {
59
+ color: #333;
60
+ text-decoration: none;
61
+ transition: color 0.2s ease;
67
62
  }
68
63
 
69
- details.menuExpandoWrapper:not([open]) {
70
- --do-nothing: true;
64
+ details.menuExpandoWrapper a:hover {
65
+ color: #336699;
66
+ text-decoration: underline;
71
67
  }
72
68
 
73
- details.menuExpandoWrapper > *,
74
- details.menuExpandoWrapper[open] > *,
75
- details.menuExpandoWrapper:not([open]) > * {
76
- animation: sweep 1s ease-out;
69
+ /* ========== NESTED MENU STYLING ========== */
70
+ details.menuExpandoNested {
71
+ display: block;
77
72
  }
78
73
 
79
- @keyframes sweep {
80
- 0% { opacity: 0; margin-left: -220px }
81
- 100% { opacity: 1; margin-left: 0px }
74
+ details.menuExpandoNested > summary {
75
+ cursor: pointer;
76
+ user-select: none;
77
+ padding: 5px 0;
78
+ font-weight: 500;
79
+ display: list-item;
80
+ color: #333;
81
+ transition: color 0.2s ease;
82
82
  }
83
83
 
84
- details.menuExpandoWrapper > summary::marker,
85
- details.menuExpandoWrapper > summary::-webkit-details-marker {
86
- display:none;
84
+ details.menuExpandoNested > summary:hover {
85
+ color: #336699;
87
86
  }
88
87
 
89
- .menuExpando,
90
- .menuExpando ul {
91
- /* ALL LIST LEVELS */
92
- display: inline-block;
93
- list-style-type: none;
94
- padding: 0;
95
- width: 200px;
96
- margin: 10px;
88
+ details.menuExpandoNested > summary a {
89
+ color: inherit;
90
+ text-decoration: none;
97
91
  }
98
92
 
99
- .menuExpando ul > li {
100
- /* ALL LIST ITEM LEVELS */
101
- border-bottom: 1px solid #FFF;
93
+ details.menuExpandoNested > summary a:hover {
94
+ text-decoration: underline;
102
95
  }
103
96
 
104
- .menuExpando ul > li:first-child {
105
- /* ALL LIST ITEM LEVELS */
106
- border-top: 1px solid #FFF;
97
+ details.menuExpandoNested > summary::marker,
98
+ details.menuExpandoNested > summary::-webkit-details-marker {
99
+ color: #666;
107
100
  }
108
101
 
109
- .menuExpando ul > li > a {
110
- /* this is the button */
111
- color: black;
112
- background: #CCC;
113
- /* background-image: url(/images/pix/pix-bg-lite.jpg); */
114
- display: block;
115
- font-weight: bold;
116
- height: 30px;
117
- line-height:30px;
118
- text-decoration: none;
119
- text-indent: 10px;
102
+ details.menuExpandoNested > ul {
103
+ margin: 0px;
104
+ padding-left: 20px;
105
+ list-style: none;
106
+ max-height: 0px;
107
+ opacity: 0;
108
+ overflow: hidden;
109
+ }
110
+
111
+ details.menuExpandoNested li {
112
+ margin: 3px 0;
120
113
  }
121
114
 
122
- .menuExpando ul > li > a:hover {
123
- background: #EDD;
124
- /* background-image: url(/images/pix/pix-bg-sm-bw.gif); */
125
- text-indent: 5px;
126
- border-left: 5px #000 solid;
115
+ /* ========== ANIMATIONS ========== */
116
+ @keyframes menuExpandoSlideDown {
117
+ from {
118
+ opacity: 0;
119
+ }
120
+ to {
121
+ opacity: 1;
122
+ }
127
123
  }
124
+
125
+ @keyframes menuExpandoSlideUp {
126
+ from {
127
+ opacity: 1;
128
+ }
129
+ to {
130
+ opacity: 0;
131
+ }
132
+ }
133
+
134
+
@@ -1,28 +1,131 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useEffect, useRef } from 'react';
3
4
  import PropTypes from 'prop-types';
4
5
  import './menu-expando.css';
5
- /*
6
- NOTE :
7
- Stopped development on details / summary for now.
8
- Not enough css control for animation.
9
- */
10
- /* ========== MENU ========== */
11
6
  export function MenuExpando(props) {
12
- // const debug = false;
7
+ const detailsRef = useRef(null);
8
+ const ulRef = useRef(null);
9
+ useEffect(() => {
10
+ const details = detailsRef.current;
11
+ const ul = ulRef.current;
12
+ if (!details || !ul)
13
+ return;
14
+ const summary = details.querySelector('summary');
15
+ if (!summary)
16
+ return;
17
+ // Initialize nested menus to be closed
18
+ const nestedDetails = details.querySelectorAll('details.menuExpandoNested');
19
+ nestedDetails.forEach((nested) => {
20
+ const nestedUl = nested.querySelector('ul');
21
+ if (nestedUl) {
22
+ nestedUl.style.maxHeight = '0px';
23
+ nestedUl.style.opacity = '0';
24
+ nestedUl.style.overflow = 'hidden';
25
+ }
26
+ });
27
+ let isAnimating = false;
28
+ summary.addEventListener('click', (e) => {
29
+ if (isAnimating) {
30
+ e.preventDefault();
31
+ return;
32
+ }
33
+ e.preventDefault();
34
+ isAnimating = true;
35
+ if (details.open) {
36
+ // Closing animation
37
+ ul.style.animation = 'menuExpandoSlideUp 0.3s ease-out forwards';
38
+ setTimeout(() => {
39
+ details.open = false;
40
+ ul.style.animation = '';
41
+ isAnimating = false;
42
+ }, 300);
43
+ }
44
+ else {
45
+ // Opening animation
46
+ details.open = true;
47
+ ul.style.animation = 'menuExpandoSlideDown 0.3s ease-out forwards';
48
+ setTimeout(() => {
49
+ ul.style.animation = '';
50
+ isAnimating = false;
51
+ }, 300);
52
+ }
53
+ });
54
+ // Handle nested menu animations
55
+ const nestedDetailsForAnimation = details.querySelectorAll('details.menuExpandoNested');
56
+ nestedDetailsForAnimation.forEach((nested) => {
57
+ nested.addEventListener('toggle', (e) => {
58
+ const nestedUl = nested.querySelector('ul');
59
+ if (nestedUl) {
60
+ if (nested.open) {
61
+ nestedUl.style.maxHeight = '0px';
62
+ nestedUl.style.opacity = '0';
63
+ nestedUl.style.overflow = 'hidden';
64
+ // Force reflow
65
+ void nestedUl.offsetHeight;
66
+ nestedUl.style.transition = 'max-height 0.3s ease-out, opacity 0.3s ease-out';
67
+ nestedUl.style.maxHeight = '500px';
68
+ nestedUl.style.opacity = '1';
69
+ setTimeout(() => {
70
+ nestedUl.style.overflow = 'visible';
71
+ nestedUl.style.transition = '';
72
+ }, 300);
73
+ }
74
+ else {
75
+ nestedUl.style.overflow = 'hidden';
76
+ nestedUl.style.transition = 'max-height 0.3s ease-out, opacity 0.3s ease-out';
77
+ nestedUl.style.maxHeight = '0px';
78
+ nestedUl.style.opacity = '0';
79
+ setTimeout(() => {
80
+ nestedUl.style.transition = '';
81
+ }, 300);
82
+ }
83
+ }
84
+ });
85
+ });
86
+ }, []);
13
87
  function generateMenuItems() {
14
88
  const myItems = [];
15
- for (const itemKey in props.menuItems) {
16
- myItems.push(_jsx(MenuExpandoItem, { name: itemKey, href: props.menuItems[itemKey] }, itemKey));
89
+ console.log('MenuExpando props.menuItems:', props.menuItems);
90
+ console.log('Is array?', Array.isArray(props.menuItems));
91
+ // Handle both object format (name: href) and array format (with name/path properties)
92
+ if (Array.isArray(props.menuItems)) {
93
+ // Array format like MenuAccordion
94
+ console.log('Processing as array, length:', props.menuItems.length);
95
+ for (const item of props.menuItems) {
96
+ console.log('Item:', item);
97
+ if (item.routes && item.routes.length > 0) {
98
+ // Item has nested routes - create expandable submenu
99
+ myItems.push(_jsx("li", { children: _jsxs("details", { className: "menuExpandoNested", children: [_jsx("summary", { children: _jsx("a", { href: item.path, children: item.name }) }), _jsx("ul", { children: item.routes.map((route) => (_jsx(MenuExpandoItem, { name: route.name, href: route.path }, route.name))) })] }) }, item.name));
100
+ }
101
+ else {
102
+ // Regular item without nested routes
103
+ myItems.push(_jsx(MenuExpandoItem, { name: item.name, href: item.path }, item.name));
104
+ }
105
+ }
17
106
  }
107
+ else {
108
+ // Object format
109
+ console.log('Processing as object');
110
+ for (const itemKey in props.menuItems) {
111
+ myItems.push(_jsx(MenuExpandoItem, { name: itemKey, href: props.menuItems[itemKey] }, itemKey));
112
+ }
113
+ }
114
+ console.log('Generated items count:', myItems.length);
18
115
  return myItems;
19
116
  }
20
- return (_jsx("div", { className: "menuExpando", id: "menuExpando", children: _jsxs("details", { className: "menuExpandoWrapper", id: "menuExpandoWrapper", children: [_jsx("summary", {}), _jsx("ul", { children: generateMenuItems() })] }) }));
117
+ return (_jsx("div", { className: "menuExpando", id: "menuExpando", children: _jsxs("details", { className: "menuExpandoWrapper", id: "menuExpandoWrapper", ref: detailsRef, children: [_jsx("summary", {}), _jsx("ul", { ref: ulRef, children: generateMenuItems() })] }) }));
21
118
  }
22
119
  MenuExpando.propTypes = {
23
- menuItems: PropTypes.object.isRequired
120
+ menuItems: PropTypes.oneOfType([
121
+ PropTypes.object,
122
+ PropTypes.arrayOf(PropTypes.shape({
123
+ name: PropTypes.string.isRequired,
124
+ path: PropTypes.string.isRequired,
125
+ routes: PropTypes.array,
126
+ }))
127
+ ]).isRequired
24
128
  };
25
- /* ========== MENU ITEM ========== */
26
129
  export function MenuExpandoItem(props) {
27
130
  return (_jsx("li", { children: _jsx("a", { href: props.href, children: props.name }) }));
28
131
  }
@@ -30,15 +133,10 @@ MenuExpandoItem.propTypes = {
30
133
  name: PropTypes.string.isRequired,
31
134
  href: PropTypes.string.isRequired
32
135
  };
33
- /* ========== MENU BUTTON ========== */
34
136
  export function MenuExpandoButton() {
35
137
  function handleMenuExpandoButtonClick(event) {
36
- const debug = false;
37
- if (debug)
38
- console.log("MenuExpandoButton clicked");
39
138
  event.preventDefault();
40
139
  event.stopPropagation();
41
- // const button = document.getElementById('menuExpandoButton');
42
140
  const details = document.getElementById('menuExpandoWrapper');
43
141
  if (details)
44
142
  details.open = !details.open;
@@ -50,6 +50,10 @@
50
50
  flex-basis: content; /* each item is its own size instead of auto */
51
51
  }
52
52
 
53
+ .menu-item-hidden {
54
+ display: none;
55
+ }
56
+
53
57
  .menu-item:hover {
54
58
  background-color: var(--accent1-color);
55
59
  }
@@ -1,3 +1,4 @@
1
+ 'use client';
1
2
  import { jsx as _jsx } from "react/jsx-runtime";
2
3
  import { useEffect } from 'react';
3
4
  import PropTypes from "prop-types";
@@ -26,6 +27,8 @@ export function MenuSimple(props) {
26
27
  return myItems;
27
28
  }
28
29
  function styleSelectedMenuItem() {
30
+ if (typeof window === 'undefined')
31
+ return;
29
32
  const menuitems = document.querySelectorAll('.menu-item a');
30
33
  const currentURL = window.location.href;
31
34
  menuitems.forEach((menuitem) => {
@@ -48,9 +51,11 @@ MenuSimpleItem.propTypes = {
48
51
  routes: PropTypes.array,
49
52
  };
50
53
  export function MenuSimpleItem(props) {
51
- if (props.hidden)
52
- return null;
53
- return (_jsx("li", { className: 'menu-item', children: props.target
54
+ const classNames = ['menu-item'];
55
+ if (props.hidden) {
56
+ classNames.push('menu-item-hidden');
57
+ }
58
+ return (_jsx("li", { className: classNames.join(' '), children: props.target
54
59
  ? _jsx("a", { href: props.path || undefined, target: props.target, children: props.name })
55
60
  : _jsx("a", { href: props.path || undefined, children: props.name }) }));
56
61
  }