@pixelated-tech/components 3.4.3 → 3.5.0
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 +12 -191
- package/dist/components/admin/componentusage/componentAnalysis.js +12 -4
- package/dist/components/admin/componentusage/componentDiscovery.js +20 -6
- package/dist/components/admin/site-health/site-health-accessibility.js +5 -1
- package/dist/components/admin/site-health/site-health-axe-core.js +4 -0
- package/dist/components/admin/site-health/site-health-cloudwatch.integration.js +0 -5
- package/dist/components/admin/site-health/site-health-cloudwatch.js +7 -1
- package/dist/components/admin/site-health/site-health-dependency-vulnerabilities.js +4 -0
- package/dist/components/admin/site-health/site-health-github.js +6 -0
- package/dist/components/admin/site-health/site-health-google-analytics.js +6 -0
- package/dist/components/admin/site-health/site-health-google-search-console.js +6 -0
- package/dist/components/admin/site-health/site-health-on-site-seo.integration.js +128 -55
- package/dist/components/admin/site-health/site-health-on-site-seo.js +4 -0
- package/dist/components/admin/site-health/site-health-overview.js +11 -4
- package/dist/components/admin/site-health/site-health-performance.js +4 -0
- package/dist/components/admin/site-health/site-health-security.js +5 -1
- package/dist/components/admin/site-health/site-health-seo.js +5 -1
- package/dist/components/admin/site-health/site-health-template.js +19 -9
- package/dist/components/admin/site-health/site-health-uptime.js +4 -0
- package/dist/components/callout/callout.js +0 -10
- package/dist/components/carousel/carousel.js +15 -4
- package/dist/components/carousel/tiles.js +1 -1
- package/dist/components/cms/contentful.items.components.js +3 -4
- package/dist/components/cms/flickr.js +1 -1
- package/dist/components/cms/google.reviews.components.js +3 -3
- package/dist/components/cms/instagram.components.js +15 -5
- package/dist/components/cms/smartimage.js +2 -2
- package/dist/components/cms/wordpress.components.js +32 -6
- package/dist/components/cms/yelp.js +5 -0
- package/dist/components/config/config.server.js +7 -1
- package/dist/components/general/css.js +0 -1
- package/dist/components/general/image.js +0 -1
- package/dist/components/general/loading.js +2 -1
- package/dist/components/general/microinteractions.js +0 -1
- package/dist/components/general/modal.css +2 -4
- package/dist/components/general/modal.js +72 -30
- package/dist/components/general/sidepanel.js +16 -0
- package/dist/components/general/tab.js +1 -0
- package/dist/components/menu/menu-accordion.css +1 -1
- package/dist/components/menu/menu-accordion.js +15 -4
- package/dist/components/menu/menu-expando.js +21 -19
- package/dist/components/menu/menu-simple.js +14 -14
- package/dist/components/nerdjoke/nerdjoke.js +1 -1
- package/dist/components/seo/googlesearch.js +0 -1
- package/dist/components/seo/schema-blogposting.js +6 -1
- package/dist/components/seo/schema-recipe.js +34 -1
- package/dist/components/seo/schema-services.js +20 -2
- package/dist/components/shoppingcart/ebay.components.js +3 -3
- package/dist/components/shoppingcart/shoppingcart.components.js +76 -28
- package/dist/components/shoppingcart/shoppingcart.functions.js +4 -4
- package/dist/components/sitebuilder/config/CompoundFontSelector.js +13 -4
- package/dist/components/sitebuilder/config/ConfigBuilder.css +194 -5
- package/dist/components/sitebuilder/config/ConfigBuilder.js +183 -17
- package/dist/components/sitebuilder/config/FontSelector.js +13 -2
- package/dist/components/sitebuilder/config/routes-form.json +67 -0
- package/dist/components/sitebuilder/config/siteinfo-form.json +28 -14
- package/dist/components/sitebuilder/config/visualdesignform.json +4 -4
- package/dist/components/sitebuilder/form/formbuilder.js +1 -0
- package/dist/components/sitebuilder/form/formcomponents.js +2 -3
- package/dist/components/sitebuilder/form/formengine.js +6 -5
- package/dist/components/sitebuilder/form/formvalidator.js +5 -0
- package/dist/components/sitebuilder/page/components/PageBuilderUI.js +5 -1
- package/dist/components/structured/buzzwordbingo.css +0 -1
- package/dist/components/structured/recipe.js +1 -1
- package/dist/components/structured/socialcard.js +2 -2
- package/dist/components/utilities/functions.js +82 -1
- package/dist/components/utilities/gemini-api.client.js +76 -0
- package/dist/components/utilities/gemini-api.server.js +185 -0
- package/dist/data/routes.json +5 -5
- package/dist/index.adminclient.js +30 -0
- package/dist/index.adminserver.js +21 -0
- package/dist/index.js +4 -18
- package/dist/index.server.js +15 -28
- package/dist/types/components/admin/componentusage/componentAnalysis.d.ts.map +1 -1
- package/dist/types/components/admin/componentusage/componentDiscovery.d.ts +1 -1
- package/dist/types/components/admin/componentusage/componentDiscovery.d.ts.map +1 -1
- package/dist/types/components/admin/site-health/site-health-accessibility.d.ts +7 -4
- package/dist/types/components/admin/site-health/site-health-accessibility.d.ts.map +1 -1
- package/dist/types/components/admin/site-health/site-health-axe-core.d.ts +7 -4
- package/dist/types/components/admin/site-health/site-health-axe-core.d.ts.map +1 -1
- package/dist/types/components/admin/site-health/site-health-cloudwatch.d.ts +9 -6
- package/dist/types/components/admin/site-health/site-health-cloudwatch.d.ts.map +1 -1
- package/dist/types/components/admin/site-health/site-health-cloudwatch.integration.d.ts.map +1 -1
- package/dist/types/components/admin/site-health/site-health-dependency-vulnerabilities.d.ts +7 -4
- package/dist/types/components/admin/site-health/site-health-dependency-vulnerabilities.d.ts.map +1 -1
- package/dist/types/components/admin/site-health/site-health-github.d.ts +9 -6
- package/dist/types/components/admin/site-health/site-health-github.d.ts.map +1 -1
- package/dist/types/components/admin/site-health/site-health-google-analytics.d.ts +9 -6
- package/dist/types/components/admin/site-health/site-health-google-analytics.d.ts.map +1 -1
- package/dist/types/components/admin/site-health/site-health-google-search-console.d.ts +9 -6
- package/dist/types/components/admin/site-health/site-health-google-search-console.d.ts.map +1 -1
- package/dist/types/components/admin/site-health/site-health-on-site-seo.d.ts +8 -3
- package/dist/types/components/admin/site-health/site-health-on-site-seo.d.ts.map +1 -1
- package/dist/types/components/admin/site-health/site-health-on-site-seo.integration.d.ts.map +1 -1
- package/dist/types/components/admin/site-health/site-health-overview.d.ts +7 -4
- package/dist/types/components/admin/site-health/site-health-overview.d.ts.map +1 -1
- package/dist/types/components/admin/site-health/site-health-performance.d.ts +7 -4
- package/dist/types/components/admin/site-health/site-health-performance.d.ts.map +1 -1
- package/dist/types/components/admin/site-health/site-health-security.d.ts +7 -4
- package/dist/types/components/admin/site-health/site-health-security.d.ts.map +1 -1
- package/dist/types/components/admin/site-health/site-health-seo.d.ts +7 -4
- package/dist/types/components/admin/site-health/site-health-seo.d.ts.map +1 -1
- package/dist/types/components/admin/site-health/site-health-template.d.ts +12 -10
- package/dist/types/components/admin/site-health/site-health-template.d.ts.map +1 -1
- package/dist/types/components/admin/site-health/site-health-uptime.d.ts +7 -4
- package/dist/types/components/admin/site-health/site-health-uptime.d.ts.map +1 -1
- package/dist/types/components/callout/callout.d.ts +3 -3
- package/dist/types/components/callout/callout.d.ts.map +1 -1
- package/dist/types/components/carousel/carousel.d.ts +16 -7
- package/dist/types/components/carousel/carousel.d.ts.map +1 -1
- package/dist/types/components/carousel/tiles.d.ts +3 -6
- package/dist/types/components/carousel/tiles.d.ts.map +1 -1
- package/dist/types/components/cms/flickr.d.ts +3 -6
- package/dist/types/components/cms/flickr.d.ts.map +1 -1
- package/dist/types/components/cms/google.reviews.components.d.ts +1 -7
- package/dist/types/components/cms/google.reviews.components.d.ts.map +1 -1
- package/dist/types/components/cms/hubspot.components.d.ts +1 -2
- package/dist/types/components/cms/hubspot.components.d.ts.map +1 -1
- package/dist/types/components/cms/instagram.components.d.ts +14 -9
- package/dist/types/components/cms/instagram.components.d.ts.map +1 -1
- package/dist/types/components/cms/smartimage.d.ts +2 -28
- package/dist/types/components/cms/smartimage.d.ts.map +1 -1
- package/dist/types/components/cms/wordpress.components.d.ts +33 -14
- package/dist/types/components/cms/wordpress.components.d.ts.map +1 -1
- package/dist/types/components/cms/yelp.d.ts +9 -4
- package/dist/types/components/cms/yelp.d.ts.map +1 -1
- package/dist/types/components/config/config.server.d.ts +9 -6
- package/dist/types/components/config/config.server.d.ts.map +1 -1
- package/dist/types/components/general/loading.d.ts +5 -1
- package/dist/types/components/general/loading.d.ts.map +1 -1
- package/dist/types/components/general/microinteractions.d.ts +1 -3
- package/dist/types/components/general/microinteractions.d.ts.map +1 -1
- package/dist/types/components/general/modal.d.ts +11 -5
- package/dist/types/components/general/modal.d.ts.map +1 -1
- package/dist/types/components/general/semantic.d.ts +3 -3
- package/dist/types/components/general/sidepanel.d.ts +20 -13
- package/dist/types/components/general/sidepanel.d.ts.map +1 -1
- package/dist/types/components/general/tab.d.ts +1 -2
- package/dist/types/components/general/tab.d.ts.map +1 -1
- package/dist/types/components/menu/menu-accordion.d.ts +22 -9
- package/dist/types/components/menu/menu-accordion.d.ts.map +1 -1
- package/dist/types/components/menu/menu-expando.d.ts +14 -5
- package/dist/types/components/menu/menu-expando.d.ts.map +1 -1
- package/dist/types/components/menu/menu-simple.d.ts +4 -5
- package/dist/types/components/menu/menu-simple.d.ts.map +1 -1
- package/dist/types/components/nerdjoke/nerdjoke.d.ts +1 -1
- package/dist/types/components/nerdjoke/nerdjoke.d.ts.map +1 -1
- package/dist/types/components/seo/googleanalytics.d.ts.map +1 -1
- package/dist/types/components/seo/metadata.components.d.ts +2 -2
- package/dist/types/components/seo/metadata.components.d.ts.map +1 -1
- package/dist/types/components/seo/schema-blogposting.d.ts +7 -4
- package/dist/types/components/seo/schema-blogposting.d.ts.map +1 -1
- package/dist/types/components/seo/schema-recipe.d.ts +29 -30
- package/dist/types/components/seo/schema-recipe.d.ts.map +1 -1
- package/dist/types/components/seo/schema-services.d.ts +19 -9
- package/dist/types/components/seo/schema-services.d.ts.map +1 -1
- package/dist/types/components/shoppingcart/paypal.d.ts +1 -1
- package/dist/types/components/shoppingcart/paypal.d.ts.map +1 -1
- package/dist/types/components/shoppingcart/shoppingcart.components.d.ts +77 -28
- package/dist/types/components/shoppingcart/shoppingcart.components.d.ts.map +1 -1
- package/dist/types/components/shoppingcart/shoppingcart.functions.d.ts +4 -23
- package/dist/types/components/shoppingcart/shoppingcart.functions.d.ts.map +1 -1
- package/dist/types/components/sitebuilder/config/CompoundFontSelector.d.ts +10 -11
- package/dist/types/components/sitebuilder/config/CompoundFontSelector.d.ts.map +1 -1
- package/dist/types/components/sitebuilder/config/ConfigBuilder.d.ts +41 -174
- package/dist/types/components/sitebuilder/config/ConfigBuilder.d.ts.map +1 -1
- package/dist/types/components/sitebuilder/config/FontSelector.d.ts +12 -13
- package/dist/types/components/sitebuilder/config/FontSelector.d.ts.map +1 -1
- package/dist/types/components/sitebuilder/form/formbuilder.d.ts +7 -3
- package/dist/types/components/sitebuilder/form/formbuilder.d.ts.map +1 -1
- package/dist/types/components/sitebuilder/form/formcomponents.d.ts +1 -1
- package/dist/types/components/sitebuilder/form/formcomponents.d.ts.map +1 -1
- package/dist/types/components/sitebuilder/form/formengine.d.ts +1 -2
- package/dist/types/components/sitebuilder/form/formengine.d.ts.map +1 -1
- package/dist/types/components/sitebuilder/form/formextractor.d.ts +5 -4
- package/dist/types/components/sitebuilder/form/formextractor.d.ts.map +1 -1
- package/dist/types/components/sitebuilder/form/formtypes.d.ts +3 -3
- package/dist/types/components/sitebuilder/form/formtypes.d.ts.map +1 -1
- package/dist/types/components/sitebuilder/form/formvalidator.d.ts +8 -3
- package/dist/types/components/sitebuilder/form/formvalidator.d.ts.map +1 -1
- package/dist/types/components/sitebuilder/page/components/ComponentPropertiesForm.d.ts +2 -3
- package/dist/types/components/sitebuilder/page/components/ComponentPropertiesForm.d.ts.map +1 -1
- package/dist/types/components/sitebuilder/page/components/ComponentSelector.d.ts +2 -3
- package/dist/types/components/sitebuilder/page/components/ComponentSelector.d.ts.map +1 -1
- package/dist/types/components/sitebuilder/page/components/ComponentTree.d.ts +2 -3
- package/dist/types/components/sitebuilder/page/components/ComponentTree.d.ts.map +1 -1
- package/dist/types/components/sitebuilder/page/components/PageBuilderUI.d.ts +8 -7
- package/dist/types/components/sitebuilder/page/components/PageBuilderUI.d.ts.map +1 -1
- package/dist/types/components/sitebuilder/page/components/PageEngine.d.ts.map +1 -1
- package/dist/types/components/sitebuilder/page/components/SaveLoadSection.d.ts +2 -3
- package/dist/types/components/sitebuilder/page/components/SaveLoadSection.d.ts.map +1 -1
- package/dist/types/components/sitebuilder/page/lib/componentMap.d.ts +1 -1
- package/dist/types/components/structured/markdown.d.ts +1 -3
- package/dist/types/components/structured/markdown.d.ts.map +1 -1
- package/dist/types/components/structured/recipe.d.ts +5 -32
- package/dist/types/components/structured/recipe.d.ts.map +1 -1
- package/dist/types/components/structured/socialcard.d.ts +4 -0
- package/dist/types/components/structured/socialcard.d.ts.map +1 -1
- package/dist/types/components/structured/timeline.d.ts +1 -3
- package/dist/types/components/structured/timeline.d.ts.map +1 -1
- package/dist/types/components/utilities/functions.d.ts +20 -0
- package/dist/types/components/utilities/functions.d.ts.map +1 -1
- package/dist/types/components/utilities/gemini-api.client.d.ts +38 -0
- package/dist/types/components/utilities/gemini-api.client.d.ts.map +1 -0
- package/dist/types/components/utilities/gemini-api.server.d.ts +17 -0
- package/dist/types/components/utilities/gemini-api.server.d.ts.map +1 -0
- package/dist/types/index.adminclient.d.ts +27 -0
- package/dist/types/index.adminclient.d.ts.map +1 -0
- package/dist/types/index.adminserver.d.ts +19 -0
- package/dist/types/index.adminserver.d.ts.map +1 -0
- package/dist/types/index.d.ts +4 -18
- package/dist/types/index.server.d.ts +5 -28
- package/dist/types/stories/general/sidepanel.stories.d.ts.map +1 -1
- package/dist/types/stories/general/smartimage.stories.d.ts +74 -2
- package/dist/types/stories/general/smartimage.stories.d.ts.map +1 -1
- package/package.json +19 -9
- package/README.COMPONENTS.md +0 -2310
- package/dist/components/cms/pixelated.linkedin.js +0 -180
- package/dist/components/cms/pixelated.linkedin1.js +0 -84
- package/dist/components/cms/pixelated.linkedin2.js +0 -92
- package/dist/types/components/cms/pixelated.linkedin.d.ts +0 -2
- package/dist/types/components/cms/pixelated.linkedin.d.ts.map +0 -1
- package/dist/types/components/cms/pixelated.linkedin1.d.ts +0 -2
- package/dist/types/components/cms/pixelated.linkedin1.d.ts.map +0 -1
- package/dist/types/components/cms/pixelated.linkedin2.d.ts +0 -2
- package/dist/types/components/cms/pixelated.linkedin2.d.ts.map +0 -1
- package/dist/types/tests/pixelated.menu-expando.test.d.ts +0 -2
- package/dist/types/tests/pixelated.menu-expando.test.d.ts.map +0 -1
|
@@ -1,8 +1,18 @@
|
|
|
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 { getInstagramTiles } from './instagram.functions';
|
|
5
6
|
import { Tiles } from '../carousel/tiles';
|
|
7
|
+
InstagramTiles.propTypes = {
|
|
8
|
+
accessToken: PropTypes.string,
|
|
9
|
+
userId: PropTypes.string,
|
|
10
|
+
limit: PropTypes.number,
|
|
11
|
+
rowCount: PropTypes.number,
|
|
12
|
+
useThumbnails: PropTypes.bool,
|
|
13
|
+
includeVideos: PropTypes.bool,
|
|
14
|
+
includeCaptions: PropTypes.bool,
|
|
15
|
+
};
|
|
6
16
|
export function InstagramTiles(props) {
|
|
7
17
|
const [tiles, setTiles] = useState([]);
|
|
8
18
|
const [loading, setLoading] = useState(true);
|
|
@@ -11,12 +21,12 @@ export function InstagramTiles(props) {
|
|
|
11
21
|
(async () => {
|
|
12
22
|
try {
|
|
13
23
|
const result = await getInstagramTiles({
|
|
14
|
-
accessToken: props.accessToken,
|
|
15
|
-
userId: props.userId,
|
|
24
|
+
accessToken: props.accessToken ?? undefined,
|
|
25
|
+
userId: props.userId ?? undefined,
|
|
16
26
|
limit: props.limit ?? 12,
|
|
17
|
-
useThumbnails: props.useThumbnails,
|
|
18
|
-
includeVideos: props.includeVideos,
|
|
19
|
-
includeCaptions: props.includeCaptions,
|
|
27
|
+
useThumbnails: props.useThumbnails ?? undefined,
|
|
28
|
+
includeVideos: props.includeVideos ?? undefined,
|
|
29
|
+
includeCaptions: props.includeCaptions ?? undefined,
|
|
20
30
|
});
|
|
21
31
|
setTiles(result);
|
|
22
32
|
setLoading(false);
|
|
@@ -80,8 +80,8 @@ export function SmartImage(props) {
|
|
|
80
80
|
newProps.name = safeString(name);
|
|
81
81
|
newProps.title = safeString(title);
|
|
82
82
|
newProps.alt = safeString(alt) ?? '';
|
|
83
|
-
newProps.width = parseNumber(width)
|
|
84
|
-
newProps.height = parseNumber(height)
|
|
83
|
+
newProps.width = parseNumber(width ?? undefined) ?? 500;
|
|
84
|
+
newProps.height = parseNumber(height ?? undefined) ?? 500;
|
|
85
85
|
const filename = (newProps.src).split('/').pop()?.split('?')[0] || '';
|
|
86
86
|
const imageName = filename.replace(/\.[^.]+$/, '');
|
|
87
87
|
newProps.id = newProps.id || newProps.name || sanitizeString(newProps.title) || sanitizeString(newProps.alt) || sanitizeString(imageName);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useEffect, useState } from 'react';
|
|
4
|
+
import PropTypes from 'prop-types';
|
|
4
5
|
import { usePixelatedConfig } from "../config/config.client";
|
|
5
6
|
import { SmartImage } from './smartimage';
|
|
6
7
|
import { PageGridItem } from '../general/semantic';
|
|
@@ -13,6 +14,13 @@ function decodeString(str) {
|
|
|
13
14
|
textarea.innerHTML = str;
|
|
14
15
|
return textarea.value;
|
|
15
16
|
}
|
|
17
|
+
BlogPostList.propTypes = {
|
|
18
|
+
site: PropTypes.string,
|
|
19
|
+
baseURL: PropTypes.string,
|
|
20
|
+
count: PropTypes.number,
|
|
21
|
+
posts: PropTypes.array,
|
|
22
|
+
showCategories: PropTypes.bool,
|
|
23
|
+
};
|
|
16
24
|
export function BlogPostList(props) {
|
|
17
25
|
const { site: propSite, baseURL: propBaseURL, count, posts: cachedPosts, showCategories = true } = props;
|
|
18
26
|
const config = usePixelatedConfig();
|
|
@@ -34,7 +42,12 @@ export function BlogPostList(props) {
|
|
|
34
42
|
// Otherwise, fetch from WordPress
|
|
35
43
|
ToggleLoading({ show: true });
|
|
36
44
|
(async () => {
|
|
37
|
-
const
|
|
45
|
+
const params = { site };
|
|
46
|
+
if (count !== null && count !== undefined)
|
|
47
|
+
params.count = count;
|
|
48
|
+
if (baseURL !== null && baseURL !== undefined)
|
|
49
|
+
params.baseURL = baseURL;
|
|
50
|
+
const data = (await getWordPressItems(params)) ?? [];
|
|
38
51
|
const sorted = data.sort((a, b) => ((a.date ?? '') < (b.date ?? '')) ? 1 : -1);
|
|
39
52
|
setPosts(sorted);
|
|
40
53
|
ToggleLoading({ show: false });
|
|
@@ -42,20 +55,33 @@ export function BlogPostList(props) {
|
|
|
42
55
|
}, [site, baseURL, count, cachedPosts]);
|
|
43
56
|
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, showCategories: showCategories }) }, post.ID)))] }));
|
|
44
57
|
}
|
|
58
|
+
BlogPostSummary.propTypes = {
|
|
59
|
+
ID: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
|
60
|
+
title: PropTypes.string,
|
|
61
|
+
date: PropTypes.string,
|
|
62
|
+
excerpt: PropTypes.string,
|
|
63
|
+
URL: PropTypes.string,
|
|
64
|
+
categories: PropTypes.object,
|
|
65
|
+
featured_image: PropTypes.string,
|
|
66
|
+
showCategories: PropTypes.bool,
|
|
67
|
+
};
|
|
45
68
|
export function BlogPostSummary(props) {
|
|
46
|
-
const myCategoryImages = Object.entries(props.categories).map(([category, index]) => [category
|
|
69
|
+
const myCategoryImages = props.categories ? Object.entries(props.categories).map(([category, index]) => [category?.trim().toLowerCase().replace(/[ /]+/g, '-'), index]).sort() : [];
|
|
47
70
|
const config = usePixelatedConfig();
|
|
48
|
-
const myExcerpt = decodeString(props.excerpt).replace(/\[…\]/g, '<a href="' + props.URL + '" target="_blank" rel="noopener noreferrer">[…]</a>');
|
|
49
|
-
return (_jsx("div", { className: "blog-post-summary", children: _jsxs("article", { className: "h-entry", children: [_jsx("h2", { className: "p-name", children: _jsx("a", { className: "u-url blog-post-url", href: props.URL, target: "_blank", rel: "noopener noreferrer", children: decodeString(props.title) }) }), _jsxs("div", { className: "dt-published", children: ["Published: ", new Date(props.date).toLocaleDateString()] }), props.featured_image ? (_jsxs("div", { className: "article-body row-12col", children: [_jsx("div", { className: "article-featured-image grid-s1-e4", children: _jsx(SmartImage, { className: "u-photo", src: props.featured_image, alt: decodeString(props.title), title: decodeString(props.title), style: {}, cloudinaryEnv: config?.cloudinary?.product_env ?? undefined, cloudinaryDomain: config?.cloudinary?.baseUrl ?? undefined, cloudinaryTransforms: config?.cloudinary?.transforms ?? undefined }) }), _jsx("div", { className: "article-excerpt grid-s4-e13", children: _jsx("div", { className: "p-summary", dangerouslySetInnerHTML: { __html: myExcerpt } }) })] })) :
|
|
71
|
+
const myExcerpt = props.excerpt ? decodeString(props.excerpt).replace(/\[…\]/g, '<a href="' + (props.URL || '') + '" target="_blank" rel="noopener noreferrer">[…]</a>') : '';
|
|
72
|
+
return (_jsx("div", { className: "blog-post-summary", children: _jsxs("article", { className: "h-entry", children: [_jsx("h2", { className: "p-name", children: _jsx("a", { className: "u-url blog-post-url", href: props.URL || '', target: "_blank", rel: "noopener noreferrer", children: props.title ? decodeString(props.title) : '' }) }), _jsxs("div", { className: "dt-published", children: ["Published: ", props.date ? new Date(props.date).toLocaleDateString() : ''] }), props.featured_image ? (_jsxs("div", { className: "article-body row-12col", children: [_jsx("div", { className: "article-featured-image grid-s1-e4", children: _jsx(SmartImage, { className: "u-photo", src: props.featured_image, alt: props.title ? decodeString(props.title) : '', title: props.title ? decodeString(props.title) : '', style: {}, cloudinaryEnv: config?.cloudinary?.product_env ?? undefined, cloudinaryDomain: config?.cloudinary?.baseUrl ?? undefined, cloudinaryTransforms: config?.cloudinary?.transforms ?? undefined }) }), _jsx("div", { className: "article-excerpt grid-s4-e13", children: _jsx("div", { className: "p-summary", dangerouslySetInnerHTML: { __html: myExcerpt } }) })] })) :
|
|
50
73
|
_jsx("div", { className: "article-excerpt grid-s1-e13", children: _jsx("div", { className: "p-summary", dangerouslySetInnerHTML: { __html: myExcerpt } }) }), props.showCategories !== false && (_jsxs("div", { children: ["Categories:", myCategoryImages.map(([categoryImg, index]) => (_jsx("span", { className: "p-category", children: _jsx(SmartImage, { src: `/images/icons/${categoryImg}.png`, title: String(categoryImg), alt: String(categoryImg), cloudinaryEnv: config?.cloudinary?.product_env ?? undefined, cloudinaryDomain: config?.cloudinary?.baseUrl ?? undefined, cloudinaryTransforms: config?.cloudinary?.transforms ?? undefined }) }, categoryImg + "-" + index)))] }))] }) }, props.ID));
|
|
51
74
|
}
|
|
75
|
+
BlogPostCategories.propTypes = {
|
|
76
|
+
categories: PropTypes.arrayOf(PropTypes.string),
|
|
77
|
+
};
|
|
52
78
|
export function BlogPostCategories(props) {
|
|
53
79
|
if (!props.categories || props.categories.length === 0) {
|
|
54
80
|
return null;
|
|
55
81
|
}
|
|
56
|
-
const myCategoryImages = props.categories.map((category) => (category !== "Uncategorized")
|
|
82
|
+
const myCategoryImages = props.categories.map((category) => (category && category !== "Uncategorized")
|
|
57
83
|
? category.trim().toLowerCase().replace(/[ /]+/g, '-')
|
|
58
|
-
: undefined).sort();
|
|
84
|
+
: undefined).filter(Boolean).sort();
|
|
59
85
|
const config = usePixelatedConfig();
|
|
60
86
|
return (_jsxs("div", { className: "blogPostCategories", children: [_jsx("div", { children: "Categories: " }), myCategoryImages.map((categoryImg, index) => categoryImg ? (_jsx("span", { className: "p-category", children: _jsx(SmartImage, { className: "u-photo", src: `/images/icons/${categoryImg}.png`, title: String(categoryImg), alt: String(categoryImg), cloudinaryEnv: config?.cloudinary?.product_env ?? undefined, cloudinaryDomain: config?.cloudinary?.baseUrl ?? undefined, cloudinaryTransforms: config?.cloudinary?.transforms ?? undefined }) }, categoryImg + "-" + index)) : null)] }));
|
|
61
87
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
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
|
/*
|
|
5
6
|
NOTE : development has stopped for this component
|
|
6
7
|
as Yelp Base API Access costs $229 per month.
|
|
@@ -12,6 +13,10 @@ https://www.google.com/search?q=yelp+reviews+react+component&oq=yelp+reviews+rea
|
|
|
12
13
|
https://www.reddit.com/r/nextjs/comments/16smhqa/next_js_fetching_data_from_yelp_api/
|
|
13
14
|
https://helloputnam.medium.com/easiest-way-to-include-business-reviews-on-a-web-app-google-facebook-yelp-etc-de3e243bbe75
|
|
14
15
|
*/
|
|
16
|
+
YelpReviews.propTypes = {
|
|
17
|
+
businessID: PropTypes.string.isRequired,
|
|
18
|
+
key: PropTypes.string,
|
|
19
|
+
};
|
|
15
20
|
export function YelpReviews(props) {
|
|
16
21
|
const [reviews, setReviews] = useState([]);
|
|
17
22
|
const [loading, setLoading] = useState(true);
|
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
2
3
|
import { getClientOnlyPixelatedConfig } from './config';
|
|
3
4
|
// Server wrapper: reads server env blob and sanitizes it, then mounts the client provider.
|
|
4
5
|
// Important: do NOT import client components at module scope — dynamically import
|
|
5
6
|
// the client provider inside the function so this module remains server-safe.
|
|
6
|
-
|
|
7
|
+
PixelatedServerConfigProvider.propTypes = {
|
|
8
|
+
config: PropTypes.object,
|
|
9
|
+
children: PropTypes.node.isRequired,
|
|
10
|
+
};
|
|
11
|
+
export async function PixelatedServerConfigProvider(props) {
|
|
12
|
+
const { config, children } = props;
|
|
7
13
|
const cfg = config ?? getClientOnlyPixelatedConfig();
|
|
8
14
|
const mod = await import('./config.client');
|
|
9
15
|
const Provider = mod.PixelatedClientConfigProvider;
|
|
@@ -7,7 +7,8 @@ https://signalvnoise.com/posts/2577-loading-spinner-animation-using-css-and-webk
|
|
|
7
7
|
https://www.andreaverlicchi.eu/blog/css-3-only-spinning-loading-animation/
|
|
8
8
|
*/
|
|
9
9
|
/* ========== MARKDOWN ========== */
|
|
10
|
-
|
|
10
|
+
Loading.propTypes = {};
|
|
11
|
+
export function Loading(props) {
|
|
11
12
|
return (_jsx(_Fragment, { children: _jsx("div", { id: "loadingSpinner", className: "loading", children: _jsxs("div", { className: "spinner", children: [_jsx("div", { className: "bar1" }), _jsx("div", { className: "bar2" }), _jsx("div", { className: "bar3" }), _jsx("div", { className: "bar4" }), _jsx("div", { className: "bar5" }), _jsx("div", { className: "bar6" }), _jsx("div", { className: "bar7" }), _jsx("div", { className: "bar8" }), _jsx("div", { className: "bar9" }), _jsx("div", { className: "bar10" }), _jsx("div", { className: "bar11" }), _jsx("div", { className: "bar12" })] }) }) }));
|
|
12
13
|
}
|
|
13
14
|
ToggleLoading.propTypes = {
|
|
@@ -29,7 +29,6 @@ export function MicroInteractions(props) {
|
|
|
29
29
|
if (props.scrollfadeElements)
|
|
30
30
|
ScrollFade(props.scrollfadeElements);
|
|
31
31
|
}
|
|
32
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
33
32
|
function isElementInViewport(el) {
|
|
34
33
|
const rect = el.getBoundingClientRect();
|
|
35
34
|
return (rect.top >= 0 &&
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
|
|
2
2
|
.modal {
|
|
3
|
-
|
|
4
3
|
position: fixed; /* Stay in place */
|
|
5
4
|
z-index: 1000; /* Sit on top */
|
|
6
|
-
top:
|
|
7
|
-
left:
|
|
8
|
-
transform: translate(-50%, -50%);
|
|
5
|
+
top: 0;
|
|
6
|
+
left: 0;
|
|
9
7
|
width: 100%; /* Full width */
|
|
10
8
|
height: 100%; /* Full height */
|
|
11
9
|
overflow: auto; /* Enable scroll if needed */
|
|
@@ -1,45 +1,87 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { useEffect } from 'react';
|
|
3
|
+
import { useEffect, useRef } from 'react';
|
|
4
|
+
import PropTypes from 'prop-types';
|
|
4
5
|
import './modal.css';
|
|
5
6
|
/*
|
|
6
7
|
https://www.w3schools.com/howto/howto_css_modals.asp
|
|
7
8
|
*/
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
Modal.propTypes = {
|
|
10
|
+
modalContent: PropTypes.node.isRequired,
|
|
11
|
+
modalID: PropTypes.string,
|
|
12
|
+
isOpen: PropTypes.bool,
|
|
13
|
+
handleCloseEvent: PropTypes.func,
|
|
14
|
+
};
|
|
15
|
+
export function Modal({ modalContent, modalID, isOpen = false, handleCloseEvent }) {
|
|
16
|
+
const myModalID = "myModal" + (modalID ?? '');
|
|
17
|
+
const myModalCloseID = "myModalClose" + (modalID ?? '');
|
|
18
|
+
const modalRef = useRef(null);
|
|
11
19
|
useEffect(() => {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
myModal
|
|
17
|
-
}
|
|
18
|
-
};
|
|
19
|
-
const myModalClose = document.getElementById(myModalCloseID);
|
|
20
|
-
if (myModalClose) {
|
|
21
|
-
myModalClose.addEventListener('click', handleModalClose);
|
|
22
|
-
}
|
|
23
|
-
;
|
|
24
|
-
const handleWindowOnClick = (event) => {
|
|
25
|
-
const myModal = document.getElementById(myModalID);
|
|
26
|
-
if (event.target == myModal) {
|
|
20
|
+
// Only use DOM event listeners for backward compatibility when handleCloseEvent is not provided
|
|
21
|
+
if (!handleCloseEvent) {
|
|
22
|
+
const handleModalClose = (event) => {
|
|
23
|
+
event.preventDefault();
|
|
24
|
+
const myModal = document.getElementById(myModalID);
|
|
27
25
|
if (myModal) {
|
|
28
|
-
myModal.style.display =
|
|
26
|
+
myModal.style.display = 'none';
|
|
29
27
|
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
};
|
|
33
|
-
window.addEventListener('click', handleWindowOnClick);
|
|
34
|
-
return () => {
|
|
35
|
-
window.removeEventListener('click', handleWindowOnClick);
|
|
28
|
+
};
|
|
29
|
+
const myModalClose = document.getElementById(myModalCloseID);
|
|
36
30
|
if (myModalClose) {
|
|
37
|
-
myModalClose.
|
|
31
|
+
myModalClose.addEventListener('click', handleModalClose);
|
|
38
32
|
}
|
|
39
33
|
;
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
34
|
+
const handleWindowOnClick = (event) => {
|
|
35
|
+
const myModal = document.getElementById(myModalID);
|
|
36
|
+
if (event.target == myModal) {
|
|
37
|
+
if (myModal) {
|
|
38
|
+
myModal.style.display = 'none';
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
window.addEventListener('click', handleWindowOnClick);
|
|
43
|
+
return () => {
|
|
44
|
+
window.removeEventListener('click', handleWindowOnClick);
|
|
45
|
+
if (myModalClose) {
|
|
46
|
+
myModalClose.removeEventListener('click', handleModalClose);
|
|
47
|
+
}
|
|
48
|
+
;
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
// For React approach, add escape key listener
|
|
53
|
+
const handleEscape = (event) => {
|
|
54
|
+
if (event.key === 'Escape') {
|
|
55
|
+
handleCloseEvent();
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
document.addEventListener('keydown', handleEscape);
|
|
59
|
+
return () => {
|
|
60
|
+
document.removeEventListener('keydown', handleEscape);
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
}, [myModalID, myModalCloseID, handleCloseEvent]);
|
|
64
|
+
const handleCloseClick = handleCloseEvent ? (event) => {
|
|
65
|
+
event.preventDefault();
|
|
66
|
+
handleCloseEvent();
|
|
67
|
+
} : undefined;
|
|
68
|
+
const handleCloseKeyDown = handleCloseEvent ? (event) => {
|
|
69
|
+
if (event.key === 'Enter' || event.key === ' ') {
|
|
70
|
+
event.preventDefault();
|
|
71
|
+
handleCloseEvent();
|
|
72
|
+
}
|
|
73
|
+
} : undefined;
|
|
74
|
+
const handleModalClick = handleCloseEvent ? (event) => {
|
|
75
|
+
if (event.target === modalRef.current) {
|
|
76
|
+
handleCloseEvent();
|
|
77
|
+
}
|
|
78
|
+
} : undefined;
|
|
79
|
+
const handleModalKeyDown = handleCloseEvent ? (event) => {
|
|
80
|
+
if (event.key === 'Escape' && event.target === modalRef.current) {
|
|
81
|
+
handleCloseEvent();
|
|
82
|
+
}
|
|
83
|
+
} : undefined;
|
|
84
|
+
return (_jsx("div", { id: myModalID, className: "modal", style: { display: isOpen ? 'block' : 'none' }, ref: modalRef, onClick: handleModalClick, children: _jsxs("div", { className: "modal-content", role: "dialog", "aria-modal": "true", children: [_jsx("button", { id: myModalCloseID, className: "modal-close", "aria-label": "Close modal", onClick: handleCloseClick, onKeyDown: handleCloseKeyDown, type: "button", children: "\u00D7" }), modalContent] }) }));
|
|
43
85
|
}
|
|
44
86
|
export const handleModalOpen = (event, modalID) => {
|
|
45
87
|
const myModalID = "myModal" + (modalID ?? '');
|
|
@@ -3,7 +3,23 @@
|
|
|
3
3
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
4
4
|
import { useEffect, useRef, useState } from 'react';
|
|
5
5
|
import { createPortal } from 'react-dom';
|
|
6
|
+
import PropTypes from 'prop-types';
|
|
6
7
|
import './sidepanel.css';
|
|
8
|
+
// Define const arrays for options - used by both PropTypes and form generation
|
|
9
|
+
export const positions = ['left', 'right'];
|
|
10
|
+
SidePanel.propTypes = {
|
|
11
|
+
isOpen: PropTypes.bool.isRequired,
|
|
12
|
+
onClose: PropTypes.func.isRequired,
|
|
13
|
+
onToggle: PropTypes.func,
|
|
14
|
+
position: PropTypes.oneOf([...positions]),
|
|
15
|
+
width: PropTypes.string,
|
|
16
|
+
showOverlay: PropTypes.bool,
|
|
17
|
+
showTab: PropTypes.bool,
|
|
18
|
+
tabIcon: PropTypes.node,
|
|
19
|
+
tabLabel: PropTypes.string,
|
|
20
|
+
children: PropTypes.node,
|
|
21
|
+
className: PropTypes.string,
|
|
22
|
+
};
|
|
7
23
|
export default function SidePanel({ isOpen, onClose, onToggle, position = 'left', width = '300px', showOverlay = true, showTab = false, tabIcon /* = "≡" */, tabLabel, children, className = '' }) {
|
|
8
24
|
const portalRootRef = useRef(null);
|
|
9
25
|
const wrapperRef = useRef(null);
|
|
@@ -4,6 +4,15 @@ import { useEffect, useRef } from 'react';
|
|
|
4
4
|
import PropTypes from 'prop-types';
|
|
5
5
|
import './menu-accordion.css';
|
|
6
6
|
const hamburgerIcon = "≡"; /* (U+2261) */ /* ||| */
|
|
7
|
+
const menuItemShape = PropTypes.shape({
|
|
8
|
+
name: PropTypes.string.isRequired,
|
|
9
|
+
path: PropTypes.string,
|
|
10
|
+
target: PropTypes.string,
|
|
11
|
+
routes: PropTypes.array, // Will be refined after function declaration
|
|
12
|
+
hidden: PropTypes.bool,
|
|
13
|
+
});
|
|
14
|
+
// Update the recursive reference after the shape is defined
|
|
15
|
+
menuItemShape.routes = PropTypes.arrayOf(menuItemShape);
|
|
7
16
|
function generateMenuItems({ menuData, state = "hide" }) {
|
|
8
17
|
const myItems = [];
|
|
9
18
|
let index = 0;
|
|
@@ -27,9 +36,8 @@ function generateMenuItems({ menuData, state = "hide" }) {
|
|
|
27
36
|
}
|
|
28
37
|
return myItems;
|
|
29
38
|
}
|
|
30
|
-
/* ========== MENU ========== */
|
|
31
39
|
MenuAccordion.propTypes = {
|
|
32
|
-
menuItems: PropTypes.
|
|
40
|
+
menuItems: PropTypes.arrayOf(menuItemShape).isRequired,
|
|
33
41
|
showHidden: PropTypes.bool,
|
|
34
42
|
};
|
|
35
43
|
export function MenuAccordion(props) {
|
|
@@ -145,7 +153,10 @@ export function MenuAccordion(props) {
|
|
|
145
153
|
}
|
|
146
154
|
/* ========== MENU GROUP ========== */
|
|
147
155
|
MenuAccordionGroup.propTypes = {
|
|
148
|
-
menuItems: PropTypes.
|
|
156
|
+
menuItems: PropTypes.oneOfType([
|
|
157
|
+
menuItemShape,
|
|
158
|
+
PropTypes.arrayOf(menuItemShape)
|
|
159
|
+
]).isRequired,
|
|
149
160
|
state: PropTypes.string,
|
|
150
161
|
};
|
|
151
162
|
export function MenuAccordionGroup(props) {
|
|
@@ -168,7 +179,7 @@ export function MenuAccordionItem(props) {
|
|
|
168
179
|
https://www.unclebigbay.com/blog/building-the-world-simplest-hamburger-with-html-and-css
|
|
169
180
|
*/
|
|
170
181
|
MenuAccordionButton.propTypes = {};
|
|
171
|
-
export function MenuAccordionButton() {
|
|
182
|
+
export function MenuAccordionButton(props) {
|
|
172
183
|
function slideMobilePanel() {
|
|
173
184
|
if (typeof window !== 'undefined' && window.moveMenu) {
|
|
174
185
|
window.moveMenu();
|
|
@@ -1,9 +1,18 @@
|
|
|
1
|
-
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
2
1
|
'use client';
|
|
3
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
4
3
|
import { useEffect, useRef } from 'react';
|
|
5
4
|
import PropTypes from 'prop-types';
|
|
6
5
|
import './menu-expando.css';
|
|
6
|
+
MenuExpando.propTypes = {
|
|
7
|
+
menuItems: PropTypes.oneOfType([
|
|
8
|
+
PropTypes.objectOf(PropTypes.string),
|
|
9
|
+
PropTypes.arrayOf(PropTypes.shape({
|
|
10
|
+
name: PropTypes.string.isRequired,
|
|
11
|
+
path: PropTypes.string.isRequired,
|
|
12
|
+
routes: PropTypes.array,
|
|
13
|
+
}))
|
|
14
|
+
]).isRequired
|
|
15
|
+
};
|
|
7
16
|
export function MenuExpando(props) {
|
|
8
17
|
const detailsRef = useRef(null);
|
|
9
18
|
const ulRef = useRef(null);
|
|
@@ -91,11 +100,11 @@ export function MenuExpando(props) {
|
|
|
91
100
|
if (Array.isArray(props.menuItems)) {
|
|
92
101
|
// Array format like MenuAccordion
|
|
93
102
|
for (const item of props.menuItems) {
|
|
94
|
-
if (item.routes && item.routes.length > 0) {
|
|
103
|
+
if (item && item.routes && item.routes.length > 0) {
|
|
95
104
|
// Item has nested routes - create expandable submenu
|
|
96
105
|
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));
|
|
97
106
|
}
|
|
98
|
-
else {
|
|
107
|
+
else if (item) {
|
|
99
108
|
// Regular item without nested routes
|
|
100
109
|
myItems.push(_jsx(MenuExpandoItem, { name: item.name, href: item.path }, item.name));
|
|
101
110
|
}
|
|
@@ -104,31 +113,25 @@ export function MenuExpando(props) {
|
|
|
104
113
|
else {
|
|
105
114
|
// Object format
|
|
106
115
|
for (const itemKey in props.menuItems) {
|
|
107
|
-
|
|
116
|
+
const href = props.menuItems[itemKey];
|
|
117
|
+
if (typeof href === 'string') {
|
|
118
|
+
myItems.push(_jsx(MenuExpandoItem, { name: itemKey, href: href }, itemKey));
|
|
119
|
+
}
|
|
108
120
|
}
|
|
109
121
|
}
|
|
110
122
|
return myItems;
|
|
111
123
|
}
|
|
112
124
|
return (_jsx("div", { className: "menuExpando", id: "menuExpando", children: _jsxs("details", { className: "menu-expando-wrapper", id: "menu-expando-wrapper", ref: detailsRef, children: [_jsx("summary", {}), _jsx("ul", { ref: ulRef, children: generateMenuItems() })] }) }));
|
|
113
125
|
}
|
|
114
|
-
MenuExpando.propTypes = {
|
|
115
|
-
menuItems: PropTypes.oneOfType([
|
|
116
|
-
PropTypes.object,
|
|
117
|
-
PropTypes.arrayOf(PropTypes.shape({
|
|
118
|
-
name: PropTypes.string.isRequired,
|
|
119
|
-
path: PropTypes.string.isRequired,
|
|
120
|
-
routes: PropTypes.array,
|
|
121
|
-
}))
|
|
122
|
-
]).isRequired
|
|
123
|
-
};
|
|
124
|
-
export function MenuExpandoItem(props) {
|
|
125
|
-
return (_jsx("li", { children: _jsx("a", { href: props.href, children: props.name }) }));
|
|
126
|
-
}
|
|
127
126
|
MenuExpandoItem.propTypes = {
|
|
128
127
|
name: PropTypes.string.isRequired,
|
|
129
128
|
href: PropTypes.string.isRequired
|
|
130
129
|
};
|
|
131
|
-
export function
|
|
130
|
+
export function MenuExpandoItem(props) {
|
|
131
|
+
return (_jsx("li", { children: _jsx("a", { href: props.href, children: props.name }) }));
|
|
132
|
+
}
|
|
133
|
+
MenuExpandoButton.propTypes = {};
|
|
134
|
+
export function MenuExpandoButton(props) {
|
|
132
135
|
function handleMenuExpandoButtonClick(event) {
|
|
133
136
|
event.preventDefault();
|
|
134
137
|
event.stopPropagation();
|
|
@@ -144,4 +147,3 @@ export function MenuExpandoButton() {
|
|
|
144
147
|
}
|
|
145
148
|
return (_jsx("div", { className: "menuExpandoButton", id: "menuExpandoButton", onClick: handleMenuExpandoButtonClick, onKeyDown: handleKeyDown, tabIndex: 0, role: "button", "aria-label": "Toggle mobile menu", children: _jsx("img", { src: "/images/icons/mobile-menu2.png", title: "Mobile Menu", alt: "Mobile Menu" }) }));
|
|
146
149
|
}
|
|
147
|
-
MenuExpandoButton.propTypes = {};
|
|
@@ -3,26 +3,26 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
3
3
|
import { useEffect } from 'react';
|
|
4
4
|
import PropTypes from "prop-types";
|
|
5
5
|
import './menu-simple.css';
|
|
6
|
-
|
|
6
|
+
const menuItemShape = PropTypes.shape({
|
|
7
|
+
name: PropTypes.string.isRequired,
|
|
8
|
+
path: PropTypes.string,
|
|
9
|
+
target: PropTypes.string,
|
|
10
|
+
hidden: PropTypes.bool,
|
|
11
|
+
routes: PropTypes.array,
|
|
12
|
+
});
|
|
7
13
|
MenuSimple.propTypes = {
|
|
8
|
-
|
|
9
|
-
menuItems: PropTypes.arrayOf(PropTypes.shape({
|
|
10
|
-
name: PropTypes.string.isRequired,
|
|
11
|
-
path: PropTypes.string.isRequired,
|
|
12
|
-
target: PropTypes.string,
|
|
13
|
-
hidden: PropTypes.bool,
|
|
14
|
-
routes: PropTypes.array,
|
|
15
|
-
})).isRequired,
|
|
14
|
+
menuItems: PropTypes.arrayOf(menuItemShape).isRequired,
|
|
16
15
|
};
|
|
17
16
|
export function MenuSimple(props) {
|
|
18
17
|
function generateMenuItems() {
|
|
19
18
|
const myItems = [];
|
|
20
19
|
for (const itemKey in props.menuItems) {
|
|
21
20
|
const myItem = props.menuItems[itemKey];
|
|
22
|
-
if (myItem
|
|
23
|
-
continue;
|
|
24
|
-
|
|
25
|
-
|
|
21
|
+
if (!myItem)
|
|
22
|
+
continue; // Skip null/undefined items
|
|
23
|
+
if (myItem.routes)
|
|
24
|
+
continue; // Skip nested routes
|
|
25
|
+
myItems.push(_jsx(MenuSimpleItem, { name: myItem.name, path: myItem.path || '', target: myItem.target || undefined, hidden: myItem.hidden || undefined }, itemKey));
|
|
26
26
|
}
|
|
27
27
|
return myItems;
|
|
28
28
|
}
|
|
@@ -45,7 +45,7 @@ export function MenuSimple(props) {
|
|
|
45
45
|
/* ========== MENU ITEM ========== */
|
|
46
46
|
MenuSimpleItem.propTypes = {
|
|
47
47
|
name: PropTypes.string.isRequired,
|
|
48
|
-
path: PropTypes.string,
|
|
48
|
+
path: PropTypes.string.isRequired,
|
|
49
49
|
target: PropTypes.string,
|
|
50
50
|
hidden: PropTypes.bool,
|
|
51
51
|
routes: PropTypes.array,
|
|
@@ -7,7 +7,7 @@ import "./nerdjoke.css";
|
|
|
7
7
|
const debug = false;
|
|
8
8
|
const TIME_LIMIT = 15;
|
|
9
9
|
NerdJoke.propTypes = {};
|
|
10
|
-
export function NerdJoke(
|
|
10
|
+
export function NerdJoke(props) {
|
|
11
11
|
const [joke, setJoke] = useState({ question: "", answer: "" });
|
|
12
12
|
const timerIntervalRef = useRef(null);
|
|
13
13
|
const jokeIntervalRef = useRef(null);
|
|
@@ -23,7 +23,6 @@ GoogleSearch.propTypes = {
|
|
|
23
23
|
};
|
|
24
24
|
export function GoogleSearch(props) {
|
|
25
25
|
if (typeof document !== 'undefined') {
|
|
26
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
27
26
|
const gsearch = (function () {
|
|
28
27
|
const gcse = document.createElement("script");
|
|
29
28
|
gcse.type = "text/javascript";
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
SchemaBlogPosting.propTypes = {
|
|
4
|
+
post: PropTypes.object.isRequired,
|
|
5
|
+
};
|
|
6
|
+
export function SchemaBlogPosting(props) {
|
|
7
|
+
const { post } = props;
|
|
3
8
|
return (_jsx("script", { type: "application/ld+json", dangerouslySetInnerHTML: {
|
|
4
9
|
__html: JSON.stringify(post),
|
|
5
10
|
} }));
|
|
@@ -1,5 +1,38 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
/**
|
|
4
|
+
* Recipe Schema Component
|
|
5
|
+
* Generates JSON-LD structured data for recipes
|
|
6
|
+
* https://schema.org/Recipe
|
|
7
|
+
*/
|
|
8
|
+
RecipeSchema.propTypes = {
|
|
9
|
+
recipe: PropTypes.shape({
|
|
10
|
+
'@context': PropTypes.string.isRequired,
|
|
11
|
+
'@type': PropTypes.string.isRequired,
|
|
12
|
+
name: PropTypes.string.isRequired,
|
|
13
|
+
description: PropTypes.string,
|
|
14
|
+
author: PropTypes.shape({
|
|
15
|
+
'@type': PropTypes.string.isRequired,
|
|
16
|
+
name: PropTypes.string.isRequired,
|
|
17
|
+
}),
|
|
18
|
+
datePublished: PropTypes.string,
|
|
19
|
+
image: PropTypes.string,
|
|
20
|
+
recipeYield: PropTypes.string,
|
|
21
|
+
prepTime: PropTypes.string,
|
|
22
|
+
cookTime: PropTypes.string,
|
|
23
|
+
totalTime: PropTypes.string,
|
|
24
|
+
recipeCategory: PropTypes.string,
|
|
25
|
+
recipeCuisine: PropTypes.string,
|
|
26
|
+
recipeIngredient: PropTypes.arrayOf(PropTypes.string),
|
|
27
|
+
recipeInstructions: PropTypes.arrayOf(PropTypes.shape({
|
|
28
|
+
'@type': PropTypes.string.isRequired,
|
|
29
|
+
text: PropTypes.string.isRequired,
|
|
30
|
+
})),
|
|
31
|
+
license: PropTypes.string,
|
|
32
|
+
}).isRequired,
|
|
33
|
+
};
|
|
34
|
+
export function RecipeSchema(props) {
|
|
35
|
+
const { recipe } = props;
|
|
3
36
|
return (_jsx("script", { type: "application/ld+json", dangerouslySetInnerHTML: { __html: JSON.stringify(recipe) } }));
|
|
4
37
|
}
|
|
5
38
|
export default RecipeSchema;
|