@pixelated-tech/components 3.2.3 → 3.2.5
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.
- package/README.md +5 -0
- package/dist/components/carousel/carousel.css +5 -0
- package/dist/components/cms/contentful.items.components.js +1 -1
- package/dist/components/cms/wordpress.components.js +14 -9
- package/dist/components/general/loading.js +16 -15
- package/dist/components/menu/menu-accordion.js +9 -14
- package/dist/components/menu/menu-simple.css +4 -0
- package/dist/components/menu/menu-simple.js +8 -3
- package/dist/components/pagebuilder/components/SaveLoadSection.js +1 -1
- package/dist/components/seo/404.js +1 -1
- package/dist/components/seo/schema-blogposting.js +53 -0
- package/dist/components/seo/schema-localbusiness.js +27 -0
- package/dist/components/seo/schema-recipe.js +5 -0
- package/dist/components/seo/schema-services.js +24 -0
- package/dist/components/seo/schema-website.js +13 -0
- package/dist/components/shoppingcart/shoppingcart.components.js +1 -1
- package/dist/components/structured/buzzwordbingo.js +1 -1
- package/dist/components/structured/recipe.css +1 -1
- package/dist/components/structured/recipe.js +59 -9
- package/dist/components/structured/socialcard.js +1 -1
- package/dist/data/recipes.json +3157 -1821
- package/dist/index.js +5 -0
- package/dist/types/components/cms/wordpress.components.d.ts +1 -0
- package/dist/types/components/cms/wordpress.components.d.ts.map +1 -1
- package/dist/types/components/general/loading.d.ts.map +1 -1
- package/dist/types/components/menu/menu-accordion.d.ts.map +1 -1
- package/dist/types/components/menu/menu-simple.d.ts +1 -1
- package/dist/types/components/menu/menu-simple.d.ts.map +1 -1
- package/dist/types/components/seo/schema-blogposting.d.ts +31 -0
- package/dist/types/components/seo/schema-blogposting.d.ts.map +1 -0
- package/dist/types/components/seo/schema-localbusiness.d.ts +25 -0
- package/dist/types/components/seo/schema-localbusiness.d.ts.map +1 -0
- package/dist/types/components/seo/schema-recipe.d.ts +34 -0
- package/dist/types/components/seo/schema-recipe.d.ts.map +1 -0
- package/dist/types/components/seo/schema-services.d.ts +25 -0
- package/dist/types/components/seo/schema-services.d.ts.map +1 -0
- package/dist/types/components/seo/schema-website.d.ts +21 -0
- package/dist/types/components/seo/schema-website.d.ts.map +1 -0
- package/dist/types/components/structured/recipe.d.ts +34 -13
- package/dist/types/components/structured/recipe.d.ts.map +1 -1
- package/dist/types/index.d.ts +5 -0
- package/dist/types/tests/api.test.d.ts +2 -0
- package/dist/types/tests/api.test.d.ts.map +1 -0
- package/dist/types/tests/buzzwordbingo.test.d.ts +2 -0
- package/dist/types/tests/buzzwordbingo.test.d.ts.map +1 -0
- package/dist/types/tests/calendly.test.d.ts +2 -0
- package/dist/types/tests/calendly.test.d.ts.map +1 -0
- package/dist/types/tests/callout.test.d.ts +2 -0
- package/dist/types/tests/callout.test.d.ts.map +1 -0
- package/dist/types/tests/carousel-drag.test.d.ts +2 -0
- package/dist/types/tests/carousel-drag.test.d.ts.map +1 -0
- package/dist/types/tests/carousel.test.d.ts +2 -0
- package/dist/types/tests/carousel.test.d.ts.map +1 -0
- package/dist/types/tests/cloudinary-image.test.d.ts +2 -0
- package/dist/types/tests/cloudinary-image.test.d.ts.map +1 -0
- package/dist/types/tests/cloudinary.test.d.ts +2 -0
- package/dist/types/tests/cloudinary.test.d.ts.map +1 -0
- package/dist/types/tests/config.client.test.d.ts +2 -0
- package/dist/types/tests/config.client.test.d.ts.map +1 -0
- package/dist/types/tests/config.server.test.d.ts +2 -0
- package/dist/types/tests/config.server.test.d.ts.map +1 -0
- package/dist/types/tests/contentful-items.test.d.ts +2 -0
- package/dist/types/tests/contentful-items.test.d.ts.map +1 -0
- package/dist/types/tests/contentful.delivery.test.d.ts +2 -0
- package/dist/types/tests/contentful.delivery.test.d.ts.map +1 -0
- package/dist/types/tests/css.test.d.ts +2 -0
- package/dist/types/tests/css.test.d.ts.map +1 -0
- package/dist/types/tests/ebay.test.d.ts +2 -0
- package/dist/types/tests/ebay.test.d.ts.map +1 -0
- package/dist/types/tests/form.test.d.ts +2 -0
- package/dist/types/tests/form.test.d.ts.map +1 -0
- package/dist/types/tests/formcomponents.test.d.ts +2 -0
- package/dist/types/tests/formcomponents.test.d.ts.map +1 -0
- package/dist/types/tests/formvalidations.test.d.ts +2 -0
- package/dist/types/tests/formvalidations.test.d.ts.map +1 -0
- package/dist/types/tests/functions.test.d.ts +2 -0
- package/dist/types/tests/functions.test.d.ts.map +1 -0
- package/dist/types/tests/google-analytics.test.d.ts +2 -0
- package/dist/types/tests/google-analytics.test.d.ts.map +1 -0
- package/dist/types/tests/google-map.test.d.ts +2 -0
- package/dist/types/tests/google-map.test.d.ts.map +1 -0
- package/dist/types/tests/google-reviews.test.d.ts +2 -0
- package/dist/types/tests/google-reviews.test.d.ts.map +1 -0
- package/dist/types/tests/googlesearch.test.d.ts +2 -0
- package/dist/types/tests/googlesearch.test.d.ts.map +1 -0
- package/dist/types/tests/gravatar.test.d.ts +2 -0
- package/dist/types/tests/gravatar.test.d.ts.map +1 -0
- package/dist/types/tests/hubspot.test.d.ts +2 -0
- package/dist/types/tests/hubspot.test.d.ts.map +1 -0
- package/dist/types/tests/image.test.d.ts +2 -0
- package/dist/types/tests/image.test.d.ts.map +1 -0
- package/dist/types/tests/instagram.test.d.ts +2 -0
- package/dist/types/tests/instagram.test.d.ts.map +1 -0
- package/dist/types/tests/loading.test.d.ts +2 -0
- package/dist/types/tests/loading.test.d.ts.map +1 -0
- package/dist/types/tests/markdown.test.d.ts +2 -0
- package/dist/types/tests/markdown.test.d.ts.map +1 -0
- package/dist/types/tests/menu-accordion.test.d.ts +2 -0
- package/dist/types/tests/menu-accordion.test.d.ts.map +1 -0
- package/dist/types/tests/menu-expando.test.d.ts +2 -0
- package/dist/types/tests/menu-expando.test.d.ts.map +1 -0
- package/dist/types/tests/menu-simple.test.d.ts +2 -0
- package/dist/types/tests/menu-simple.test.d.ts.map +1 -0
- package/dist/types/tests/metadata.components.test.d.ts +2 -0
- package/dist/types/tests/metadata.components.test.d.ts.map +1 -0
- package/dist/types/tests/microinteractions.test.d.ts +2 -0
- package/dist/types/tests/microinteractions.test.d.ts.map +1 -0
- package/dist/types/tests/modal.test.d.ts +2 -0
- package/dist/types/tests/modal.test.d.ts.map +1 -0
- package/dist/types/tests/nerdjoke.test.d.ts +2 -0
- package/dist/types/tests/nerdjoke.test.d.ts.map +1 -0
- package/dist/types/tests/paypal.test.d.ts +2 -0
- package/dist/types/tests/paypal.test.d.ts.map +1 -0
- package/dist/types/tests/pixelated.menu-expando.test.d.ts +2 -0
- package/dist/types/tests/pixelated.menu-expando.test.d.ts.map +1 -0
- package/dist/types/tests/recipe.test.d.ts +2 -0
- package/dist/types/tests/recipe.test.d.ts.map +1 -0
- package/dist/types/tests/resume.test.d.ts +2 -0
- package/dist/types/tests/resume.test.d.ts.map +1 -0
- package/dist/types/tests/schema-blogposting.test.d.ts +2 -0
- package/dist/types/tests/schema-blogposting.test.d.ts.map +1 -0
- package/dist/types/tests/schema-localbusiness.test.d.ts +2 -0
- package/dist/types/tests/schema-localbusiness.test.d.ts.map +1 -0
- package/dist/types/tests/schema-recipe.test.d.ts +2 -0
- package/dist/types/tests/schema-recipe.test.d.ts.map +1 -0
- package/dist/types/tests/schema-services.test.d.ts +2 -0
- package/dist/types/tests/schema-services.test.d.ts.map +1 -0
- package/dist/types/tests/schema-website.test.d.ts +2 -0
- package/dist/types/tests/schema-website.test.d.ts.map +1 -0
- package/dist/types/tests/semantic.test.d.ts +2 -0
- package/dist/types/tests/semantic.test.d.ts.map +1 -0
- package/dist/types/tests/setup.d.ts +2 -0
- package/dist/types/tests/setup.d.ts.map +1 -0
- package/dist/types/tests/shopping-cart.test.d.ts +2 -0
- package/dist/types/tests/shopping-cart.test.d.ts.map +1 -0
- package/dist/types/tests/shoppingcart.components.test.d.ts +2 -0
- package/dist/types/tests/shoppingcart.components.test.d.ts.map +1 -0
- package/dist/types/tests/shoppingcart.functions.test.d.ts +2 -0
- package/dist/types/tests/shoppingcart.functions.test.d.ts.map +1 -0
- package/dist/types/tests/sidepanel.test.d.ts +2 -0
- package/dist/types/tests/sidepanel.test.d.ts.map +1 -0
- package/dist/types/tests/socialcard.test.d.ts +2 -0
- package/dist/types/tests/socialcard.test.d.ts.map +1 -0
- package/dist/types/tests/table.test.d.ts +2 -0
- package/dist/types/tests/table.test.d.ts.map +1 -0
- package/dist/types/tests/tiles.test.d.ts +2 -0
- package/dist/types/tests/tiles.test.d.ts.map +1 -0
- package/dist/types/tests/timeline.test.d.ts +2 -0
- package/dist/types/tests/timeline.test.d.ts.map +1 -0
- package/dist/types/tests/wordpress.test.d.ts +2 -0
- package/dist/types/tests/wordpress.test.d.ts.map +1 -0
- package/dist/types/tests/yelp.test.d.ts +2 -0
- package/dist/types/tests/yelp.test.d.ts.map +1 -0
- package/package.json +23 -10
- package/dist/types/tests/pixelated.api.test.d.ts +0 -2
- package/dist/types/tests/pixelated.api.test.d.ts.map +0 -1
- package/dist/types/tests/pixelated.callout.test.d.ts +0 -2
- package/dist/types/tests/pixelated.callout.test.d.ts.map +0 -1
- package/dist/types/tests/pixelated.carousel.test.d.ts +0 -2
- package/dist/types/tests/pixelated.carousel.test.d.ts.map +0 -1
- package/dist/types/tests/pixelated.menu-accordion.test.d.ts +0 -2
- package/dist/types/tests/pixelated.menu-accordion.test.d.ts.map +0 -1
- package/dist/types/tests/pixelated.menu-simple.test.d.ts +0 -2
- package/dist/types/tests/pixelated.menu-simple.test.d.ts.map +0 -1
- package/dist/types/tests/pixelated.nerdjoke.test.d.ts +0 -2
- package/dist/types/tests/pixelated.nerdjoke.test.d.ts.map +0 -1
- package/dist/types/tests/pixelated.recipe.test.d.ts +0 -2
- package/dist/types/tests/pixelated.recipe.test.d.ts.map +0 -1
- package/dist/types/tests/pixelated.resume.test.d.ts +0 -2
- package/dist/types/tests/pixelated.resume.test.d.ts.map +0 -1
- package/dist/types/tests/pixelated.socialcard.test.d.ts +0 -2
- package/dist/types/tests/pixelated.socialcard.test.d.ts.map +0 -1
package/README.md
CHANGED
|
@@ -96,6 +96,11 @@ Components to help build websites quicker:
|
|
|
96
96
|
1. Form Components and Form Builder
|
|
97
97
|
1. Google Analytics, Map, and Search Integration
|
|
98
98
|
1. Gravatar Card Integration
|
|
99
|
+
1. Local Business JSON-LD Schema for SEO
|
|
100
|
+
1. Website JSON-LD Schema for SEO
|
|
101
|
+
1. Services JSON-LD Schema for SEO
|
|
102
|
+
1. Recipe JSON-LD Schema for SEO
|
|
103
|
+
1. BlogPosting JSON-LD Schema for SEO
|
|
99
104
|
1. Page and Page Section Header Components
|
|
100
105
|
1. Hubspot Calendar and Form Integration
|
|
101
106
|
1. Instagram Image Fetch Integration
|
|
@@ -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 {
|
|
@@ -7,17 +7,22 @@ import { getWordPressItems } from './wordpress.functions';
|
|
|
7
7
|
import { Loading, ToggleLoading } from '../general/loading';
|
|
8
8
|
import "./wordpress.css";
|
|
9
9
|
// https://microformats.org/wiki/h-entry
|
|
10
|
-
function decodeString(
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
temp = null;
|
|
15
|
-
return str;
|
|
10
|
+
function decodeString(str) {
|
|
11
|
+
const textarea = { value: '' };
|
|
12
|
+
textarea.innerHTML = str;
|
|
13
|
+
return textarea.value || str;
|
|
16
14
|
}
|
|
17
15
|
export function BlogPostList(props) {
|
|
18
|
-
const { site, count } = props;
|
|
19
|
-
const [posts, setPosts] = useState([]);
|
|
16
|
+
const { site, count, posts: cachedPosts } = props;
|
|
17
|
+
const [posts, setPosts] = useState(cachedPosts ?? []);
|
|
20
18
|
useEffect(() => {
|
|
19
|
+
// If posts are provided, use them directly without fetching
|
|
20
|
+
if (cachedPosts && cachedPosts.length > 0) {
|
|
21
|
+
const sorted = cachedPosts.sort((a, b) => ((a.date ?? '') < (b.date ?? '')) ? 1 : -1);
|
|
22
|
+
setPosts(sorted);
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
// Otherwise, fetch from WordPress
|
|
21
26
|
ToggleLoading({ show: true });
|
|
22
27
|
(async () => {
|
|
23
28
|
const data = (await getWordPressItems({ site, count })) ?? [];
|
|
@@ -25,7 +30,7 @@ export function BlogPostList(props) {
|
|
|
25
30
|
setPosts(sorted);
|
|
26
31
|
ToggleLoading({ show: false });
|
|
27
32
|
})();
|
|
28
|
-
}, [site, count]);
|
|
33
|
+
}, [site, count, cachedPosts]);
|
|
29
34
|
return (_jsxs(_Fragment, { children: [_jsx(Loading, {}), posts.map((post) => (_jsx(PageGridItem, { children: _jsx(BlogPostSummary, { ID: post.ID, title: post.title, date: post.date, excerpt: post.excerpt, URL: post.URL, categories: post.categories, featured_image: post.featured_image }) }, post.ID)))] }));
|
|
30
35
|
}
|
|
31
36
|
export function BlogPostSummary(props) {
|
|
@@ -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
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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
|
-
|
|
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
|
-
|
|
162
|
-
|
|
163
|
-
|
|
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
|
-
|
|
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,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
|
-
|
|
52
|
-
|
|
53
|
-
|
|
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
|
}
|
|
@@ -16,7 +16,7 @@ export function SaveLoadSection({ pageData, onLoad, apiEndpoint = '/api/pagebuil
|
|
|
16
16
|
// Fetch list of saved pages on mount
|
|
17
17
|
useEffect(() => {
|
|
18
18
|
fetchPages();
|
|
19
|
-
}, []);
|
|
19
|
+
}, [apiEndpoint]);
|
|
20
20
|
async function fetchPages() {
|
|
21
21
|
try {
|
|
22
22
|
const response = await fetch(`${apiEndpoint}/list`);
|
|
@@ -19,7 +19,7 @@ export function FourOhFour(props) {
|
|
|
19
19
|
// const cloudinaryURL = getCloudinaryRemoteFetchURL({ url: images[randomIndex].img, product_env:"dlbon7tpq" });
|
|
20
20
|
// setCloudinaryURL(cloudinaryURL);
|
|
21
21
|
setImageURL(images[randomIndex].img);
|
|
22
|
-
}, []);
|
|
22
|
+
}, [images]);
|
|
23
23
|
const config = usePixelatedConfig();
|
|
24
24
|
if (randomIndex !== null && imageURL /* cloudinaryURL */ !== '') {
|
|
25
25
|
return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "fof-body-container", children: [_jsxs("h1", { className: "centered text-outline", children: ["404 - ", images[randomIndex].text] }), _jsx("div", { className: "centered-button", children: _jsx("a", { href: "/", target: "_self", rel: "noopener noreferrer", children: "Go Home" }) })] }), _jsx("div", { className: "fof-image-container", children: _jsx("div", { className: "fof-image-wrapper", children: _jsx(SmartImage, { src: imageURL,
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* Converts WordPress REST API blog post to schema.org BlogPosting format
|
|
4
|
+
* @param post WordPress blog post
|
|
5
|
+
* @param includeFullContent Whether to include articleBody (true) or just description (false)
|
|
6
|
+
*/
|
|
7
|
+
export function mapWordPressToBlogPosting(post, includeFullContent = false) {
|
|
8
|
+
const decodeString = (s) => {
|
|
9
|
+
if (typeof document === 'undefined')
|
|
10
|
+
return s;
|
|
11
|
+
const temp = document.createElement('p');
|
|
12
|
+
temp.innerHTML = s;
|
|
13
|
+
return temp.textContent || temp.innerText || s;
|
|
14
|
+
};
|
|
15
|
+
const cleanContent = (content) => {
|
|
16
|
+
if (!content)
|
|
17
|
+
return '';
|
|
18
|
+
return decodeString(content).replace(/\[…\]/g, '').trim();
|
|
19
|
+
};
|
|
20
|
+
const description = cleanContent(post.excerpt);
|
|
21
|
+
const articleBody = includeFullContent ? cleanContent(post.content || '') : undefined;
|
|
22
|
+
const schema = {
|
|
23
|
+
'@context': 'https://schema.org',
|
|
24
|
+
'@type': 'BlogPosting',
|
|
25
|
+
headline: decodeString(post.title),
|
|
26
|
+
description: description || decodeString(post.title),
|
|
27
|
+
datePublished: post.date,
|
|
28
|
+
image: post.featured_image || post.post_thumbnail?.URL,
|
|
29
|
+
articleSection: Array.isArray(post.categories) && post.categories.length > 0
|
|
30
|
+
? post.categories[0]
|
|
31
|
+
: 'Blog',
|
|
32
|
+
keywords: Array.isArray(post.categories) ? post.categories : [],
|
|
33
|
+
};
|
|
34
|
+
if (articleBody) {
|
|
35
|
+
schema.articleBody = articleBody;
|
|
36
|
+
}
|
|
37
|
+
if (post.modified) {
|
|
38
|
+
schema.dateModified = post.modified;
|
|
39
|
+
}
|
|
40
|
+
if (post.author) {
|
|
41
|
+
schema.author = {
|
|
42
|
+
'@type': 'Person',
|
|
43
|
+
name: post.author,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
return schema;
|
|
47
|
+
}
|
|
48
|
+
export function SchemaBlogPosting({ post }) {
|
|
49
|
+
return (_jsx("script", { type: "application/ld+json", dangerouslySetInnerHTML: {
|
|
50
|
+
__html: JSON.stringify(post),
|
|
51
|
+
} }));
|
|
52
|
+
}
|
|
53
|
+
export default SchemaBlogPosting;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
export function LocalBusinessSchema({ name, streetAddress, addressLocality, addressRegion, postalCode, addressCountry = 'United States', telephone, url, logo, image, openingHours, description, email, priceRange, sameAs }) {
|
|
3
|
+
const schemaData = {
|
|
4
|
+
'@context': 'https://schema.org',
|
|
5
|
+
'@type': 'LocalBusiness',
|
|
6
|
+
name,
|
|
7
|
+
address: {
|
|
8
|
+
'@type': 'PostalAddress',
|
|
9
|
+
streetAddress,
|
|
10
|
+
addressLocality,
|
|
11
|
+
addressRegion,
|
|
12
|
+
postalCode,
|
|
13
|
+
addressCountry
|
|
14
|
+
},
|
|
15
|
+
telephone,
|
|
16
|
+
url,
|
|
17
|
+
...(logo && { logo }),
|
|
18
|
+
...(image && { image }),
|
|
19
|
+
...(openingHours && { openingHours }),
|
|
20
|
+
...(description && { description }),
|
|
21
|
+
...(email && { email }),
|
|
22
|
+
...(priceRange && { priceRange }),
|
|
23
|
+
...(sameAs && sameAs.length > 0 && { sameAs })
|
|
24
|
+
};
|
|
25
|
+
return (_jsx("script", { type: "application/ld+json", dangerouslySetInnerHTML: { __html: JSON.stringify(schemaData) } }));
|
|
26
|
+
}
|
|
27
|
+
export default LocalBusinessSchema;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
export function ServicesSchema({ provider, services }) {
|
|
3
|
+
const serviceObjects = services.map(service => ({
|
|
4
|
+
'@type': 'Service',
|
|
5
|
+
name: service.name,
|
|
6
|
+
description: service.description,
|
|
7
|
+
...(service.url && { url: service.url }),
|
|
8
|
+
...(service.image && { image: service.image }),
|
|
9
|
+
...(service.areaServed && { areaServed: service.areaServed }),
|
|
10
|
+
provider: {
|
|
11
|
+
'@type': 'LocalBusiness',
|
|
12
|
+
name: provider.name,
|
|
13
|
+
url: provider.url,
|
|
14
|
+
...(provider.logo && { logo: provider.logo }),
|
|
15
|
+
...(provider.telephone && { telephone: provider.telephone }),
|
|
16
|
+
...(provider.email && { email: provider.email })
|
|
17
|
+
}
|
|
18
|
+
}));
|
|
19
|
+
return (_jsx(_Fragment, { children: serviceObjects.map((service, idx) => (_jsx("script", { type: "application/ld+json", dangerouslySetInnerHTML: { __html: JSON.stringify({
|
|
20
|
+
'@context': 'https://schema.org',
|
|
21
|
+
...service
|
|
22
|
+
}) } }, idx))) }));
|
|
23
|
+
}
|
|
24
|
+
export default ServicesSchema;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
export function WebsiteSchema({ name, url, description, potentialAction }) {
|
|
3
|
+
const schemaData = {
|
|
4
|
+
'@context': 'https://schema.org',
|
|
5
|
+
'@type': 'WebSite',
|
|
6
|
+
name,
|
|
7
|
+
url,
|
|
8
|
+
...(description && { description }),
|
|
9
|
+
...(potentialAction && { potentialAction })
|
|
10
|
+
};
|
|
11
|
+
return (_jsx("script", { type: "application/ld+json", dangerouslySetInnerHTML: { __html: JSON.stringify(schemaData) } }));
|
|
12
|
+
}
|
|
13
|
+
export default WebsiteSchema;
|
|
@@ -245,7 +245,7 @@ export function AddToCartButton(props) {
|
|
|
245
245
|
useEffect(() => {
|
|
246
246
|
const myContent = _jsxs("div", { className: "centered", children: [_jsx("br", {}), _jsx("br", {}), "Item ", props.itemID, " has been added to your cart.", _jsx("br", {}), _jsx("br", {}), GoToCartButton({ href: "/cart", itemID: props.itemID }), _jsx("br", {}), _jsx("br", {})] });
|
|
247
247
|
setModalContent(myContent);
|
|
248
|
-
}, []);
|
|
248
|
+
}, [props.itemID]);
|
|
249
249
|
function handleClick(e) {
|
|
250
250
|
props.handler(props.item);
|
|
251
251
|
handleModalOpen(e.nativeEvent, "-" + props.itemID);
|
|
@@ -18,7 +18,7 @@ export function BuzzwordBingo(props) {
|
|
|
18
18
|
const [bingoWords, setBingoWords] = useState([]);
|
|
19
19
|
useEffect(() => {
|
|
20
20
|
setBingoWords(getBingoWords(buzzwords, 24));
|
|
21
|
-
}, []);
|
|
21
|
+
}, [buzzwords]);
|
|
22
22
|
return (_jsxs("div", { className: "bingoCard rowfix-5col", children: [myBingoHeaders.map((word) => (_jsx(BingoHeader, { word: word }, word))), bingoWords.map((word) => (_jsx(BingoBox, { word: word }, word)))] }));
|
|
23
23
|
}
|
|
24
24
|
BingoHeader.propTypes = {
|
|
@@ -4,6 +4,55 @@ import PropTypes from 'prop-types';
|
|
|
4
4
|
import { SmartImage } from '../cms/cloudinary.image';
|
|
5
5
|
import { usePixelatedConfig } from '../config/config.client';
|
|
6
6
|
import './recipe.css';
|
|
7
|
+
export function mapSchemaRecipeToDisplay(schemaRecipe) {
|
|
8
|
+
// Parse ISO 8601 duration and convert to readable format
|
|
9
|
+
function parseDuration(iso8601) {
|
|
10
|
+
if (!iso8601 || iso8601 === 'PT0M')
|
|
11
|
+
return '';
|
|
12
|
+
const regex = /PT(?:(\d+)H)?(?:(\d+)M)?/;
|
|
13
|
+
const match = iso8601.match(regex);
|
|
14
|
+
if (!match)
|
|
15
|
+
return iso8601;
|
|
16
|
+
const hours = match[1] ? parseInt(match[1]) : 0;
|
|
17
|
+
const minutes = match[2] ? parseInt(match[2]) : 0;
|
|
18
|
+
if (hours > 0 && minutes > 0) {
|
|
19
|
+
return `${hours} hour${hours > 1 ? 's' : ''} ${minutes} minutes`;
|
|
20
|
+
}
|
|
21
|
+
else if (hours > 0) {
|
|
22
|
+
return `${hours} hour${hours > 1 ? 's' : ''}`;
|
|
23
|
+
}
|
|
24
|
+
else if (minutes > 0) {
|
|
25
|
+
return `${minutes} minutes`;
|
|
26
|
+
}
|
|
27
|
+
return '';
|
|
28
|
+
}
|
|
29
|
+
// Extract author name
|
|
30
|
+
const authorName = typeof schemaRecipe.author === 'string'
|
|
31
|
+
? schemaRecipe.author
|
|
32
|
+
: schemaRecipe.author?.name || '';
|
|
33
|
+
// Convert instructions from HowToStep format to plain text
|
|
34
|
+
const instructions = Array.isArray(schemaRecipe.recipeInstructions)
|
|
35
|
+
? schemaRecipe.recipeInstructions.map((instruction) => typeof instruction === 'string' ? instruction : instruction.text || '')
|
|
36
|
+
: [];
|
|
37
|
+
// Combine cook and prep times for display
|
|
38
|
+
let displayDuration = '';
|
|
39
|
+
if (schemaRecipe.totalTime) {
|
|
40
|
+
displayDuration = parseDuration(schemaRecipe.totalTime);
|
|
41
|
+
}
|
|
42
|
+
return {
|
|
43
|
+
name: schemaRecipe.name || '',
|
|
44
|
+
photo: schemaRecipe.image || '',
|
|
45
|
+
summary: schemaRecipe.description || '',
|
|
46
|
+
author: authorName,
|
|
47
|
+
published: schemaRecipe.datePublished || '',
|
|
48
|
+
duration: displayDuration,
|
|
49
|
+
yield: schemaRecipe.recipeYield || '',
|
|
50
|
+
ingredients: schemaRecipe.recipeIngredient || [],
|
|
51
|
+
instructions,
|
|
52
|
+
category: schemaRecipe.recipeCategory ? [schemaRecipe.recipeCategory] : [],
|
|
53
|
+
license: schemaRecipe.license || ''
|
|
54
|
+
};
|
|
55
|
+
}
|
|
7
56
|
/* ========== RECIPE BOOK ========== */
|
|
8
57
|
RecipeBook.propTypes = {
|
|
9
58
|
recipeData: PropTypes.shape({
|
|
@@ -25,9 +74,10 @@ export function RecipeBook(props) {
|
|
|
25
74
|
myElems[category] = [];
|
|
26
75
|
for (const recipeKey in recipeBookItems) {
|
|
27
76
|
const recipe = recipeBookItems[recipeKey];
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
77
|
+
const outputRecipe = mapSchemaRecipeToDisplay(recipe);
|
|
78
|
+
const recipeCat = outputRecipe.category;
|
|
79
|
+
if (recipeCat.includes(category)) {
|
|
80
|
+
myElems[category].push(outputRecipe);
|
|
31
81
|
}
|
|
32
82
|
}
|
|
33
83
|
}
|
|
@@ -41,7 +91,7 @@ export function RecipeBook(props) {
|
|
|
41
91
|
myElems.push(_jsx(RecipeCategory, { id: cID, className: 'h-recipe-category', category: category, showOnly: showOnlyCat }, cID));
|
|
42
92
|
for (const recipeKey in recipeElems[category]) {
|
|
43
93
|
const recipe = recipeElems[category][recipeKey];
|
|
44
|
-
const cats = recipe.
|
|
94
|
+
const cats = recipe.category;
|
|
45
95
|
const rID = cID + '-r' + (parseInt(recipeKey, 10) + 1);
|
|
46
96
|
if (cats.includes(category)) {
|
|
47
97
|
myElems.push(_jsx(RecipeBookItem, { id: rID, recipeData: recipe, showOnly: showOnlyRecipe }, rID));
|
|
@@ -92,8 +142,7 @@ RecipeBookItem.propTypes = {
|
|
|
92
142
|
};
|
|
93
143
|
export function RecipeBookItem(props) {
|
|
94
144
|
const config = usePixelatedConfig();
|
|
95
|
-
const
|
|
96
|
-
const recipe = recipeData.properties;
|
|
145
|
+
const recipe = props.recipeData;
|
|
97
146
|
const ingredients = recipe.ingredients.map((ingredient, iKey) => _jsx("li", { className: "p-ingredient", children: ingredient }, iKey));
|
|
98
147
|
const instructions = recipe.instructions.map((instruction, iKey) => _jsx("li", { className: "p-instruction", children: instruction }, iKey));
|
|
99
148
|
/* ? <img className='u-photo' src={recipe.photo} title={recipe.name} alt={recipe.name} /> */
|
|
@@ -124,9 +173,10 @@ export function RecipePickList(props) {
|
|
|
124
173
|
const recipeDataItems = recipeData.items;
|
|
125
174
|
for (const recipeKey in recipeDataItems) {
|
|
126
175
|
const recipe = recipeDataItems[recipeKey];
|
|
127
|
-
const
|
|
176
|
+
const outputRecipe = mapSchemaRecipeToDisplay(recipe);
|
|
177
|
+
const cats = outputRecipe.category;
|
|
128
178
|
if (cats.includes(category)) {
|
|
129
|
-
myOpts.push(_jsx("option", { value: cID + '-r' + rID, children:
|
|
179
|
+
myOpts.push(_jsx("option", { value: cID + '-r' + rID, children: outputRecipe.name }, cID + '-r' + rID));
|
|
130
180
|
rID += 1;
|
|
131
181
|
}
|
|
132
182
|
}
|
|
@@ -143,7 +193,7 @@ export function RecipePickList(props) {
|
|
|
143
193
|
}
|
|
144
194
|
useEffect(() => {
|
|
145
195
|
setRecipeOptions(generateMyOptions());
|
|
146
|
-
}, []);
|
|
196
|
+
}, [props.recipeData, props.recipeCategories]);
|
|
147
197
|
return (_jsx("form", { children: _jsx("select", { id: "recipe-list", name: "recipe-list", onChange: recipeListChanged, children: recipeOptions }) }));
|
|
148
198
|
}
|
|
149
199
|
/* ========== RECIPE BACK TO TOP ========== */
|