@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
|
@@ -2,18 +2,25 @@
|
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useState, useEffect } from 'react';
|
|
4
4
|
import PropTypes from 'prop-types';
|
|
5
|
+
import { Modal } from '../../general/modal';
|
|
5
6
|
import { Tab } from '../../general/tab';
|
|
6
7
|
import { Accordion } from '../../general/accordion';
|
|
8
|
+
import { createGeminiApiService } from '../../utilities/gemini-api.client';
|
|
7
9
|
import { FormEngine } from '../form/formengine';
|
|
10
|
+
import { FormValidationProvider } from '../form/formvalidator';
|
|
11
|
+
import * as FC from '../form/formcomponents';
|
|
8
12
|
import siteInfoForm from './siteinfo-form.json';
|
|
9
13
|
import visualDesignForm from './visualdesignform.json';
|
|
14
|
+
import routesForm from './routes-form.json';
|
|
10
15
|
import defaultConfigData from '../../../data/routes.json';
|
|
11
16
|
import './ConfigBuilder.css';
|
|
12
17
|
const RoutePropTypes = {
|
|
18
|
+
name: PropTypes.string,
|
|
13
19
|
path: PropTypes.string.isRequired,
|
|
14
|
-
component: PropTypes.string.isRequired,
|
|
15
20
|
title: PropTypes.string,
|
|
16
21
|
description: PropTypes.string,
|
|
22
|
+
keywords: PropTypes.arrayOf(PropTypes.string),
|
|
23
|
+
hidden: PropTypes.bool,
|
|
17
24
|
};
|
|
18
25
|
const SiteInfoPropTypes = {
|
|
19
26
|
name: PropTypes.string.isRequired,
|
|
@@ -78,7 +85,7 @@ const SiteConfigPropTypes = {
|
|
|
78
85
|
routes: PropTypes.arrayOf(PropTypes.shape(RoutePropTypes).isRequired).isRequired,
|
|
79
86
|
visualdesign: PropTypes.shape(VisualDesignPropTypes).isRequired,
|
|
80
87
|
};
|
|
81
|
-
|
|
88
|
+
ConfigBuilder.propTypes = {
|
|
82
89
|
initialConfig: PropTypes.shape(SiteConfigPropTypes),
|
|
83
90
|
onSave: PropTypes.func,
|
|
84
91
|
};
|
|
@@ -98,18 +105,38 @@ export function ConfigBuilder(props) {
|
|
|
98
105
|
});
|
|
99
106
|
const [socialLinks, setSocialLinks] = useState(initialConfig?.siteInfo?.sameAs || ['']);
|
|
100
107
|
const [isFormValid, setIsFormValid] = useState(false);
|
|
108
|
+
// AI Recommendations state
|
|
109
|
+
const [aiModalOpen, setAiModalOpen] = useState(false);
|
|
110
|
+
const [currentRouteIndex, setCurrentRouteIndex] = useState(null);
|
|
111
|
+
const [aiRecommendations, setAiRecommendations] = useState(null);
|
|
112
|
+
const [aiLoading, setAiLoading] = useState(false);
|
|
113
|
+
const [acceptTitle, setAcceptTitle] = useState(false);
|
|
114
|
+
const [acceptKeywords, setAcceptKeywords] = useState(false);
|
|
115
|
+
const [acceptDescription, setAcceptDescription] = useState(false);
|
|
101
116
|
// Validate form whenever config changes
|
|
102
117
|
useEffect(() => {
|
|
103
118
|
const siteInfo = config.siteInfo || {};
|
|
104
|
-
const isValid = (siteInfo.name || '').trim() !== '' &&
|
|
105
|
-
(siteInfo.author || '').trim() !== '' &&
|
|
106
|
-
(siteInfo.description || '').trim() !== '' &&
|
|
107
|
-
(siteInfo.url || '').trim() !== '' &&
|
|
108
|
-
(siteInfo.email || '').trim() !== '' &&
|
|
119
|
+
const isValid = String(siteInfo.name || '').trim() !== '' &&
|
|
120
|
+
String(siteInfo.author || '').trim() !== '' &&
|
|
121
|
+
String(siteInfo.description || '').trim() !== '' &&
|
|
122
|
+
String(siteInfo.url || '').trim() !== '' &&
|
|
123
|
+
String(siteInfo.email || '').trim() !== '' &&
|
|
109
124
|
// Basic email validation
|
|
110
125
|
/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(siteInfo.email || '');
|
|
111
126
|
setIsFormValid(isValid);
|
|
112
127
|
}, [config]);
|
|
128
|
+
// Handle AI modal visibility - now handled by Modal component isOpen prop
|
|
129
|
+
// useEffect(() => {
|
|
130
|
+
// console.log('AI modal effect running, aiModalOpen:', aiModalOpen);
|
|
131
|
+
// if (aiModalOpen) {
|
|
132
|
+
// const modal = document.getElementById('myModalai-recommendations');
|
|
133
|
+
// console.log('Modal element found:', modal);
|
|
134
|
+
// if (modal) {
|
|
135
|
+
// modal.style.display = 'block';
|
|
136
|
+
// console.log('Set modal display to block');
|
|
137
|
+
// }
|
|
138
|
+
// }
|
|
139
|
+
// }, [aiModalOpen]);
|
|
113
140
|
const handleFileUpload = (event) => {
|
|
114
141
|
const file = event.target.files?.[0];
|
|
115
142
|
if (!file)
|
|
@@ -121,7 +148,19 @@ export function ConfigBuilder(props) {
|
|
|
121
148
|
const parsedConfig = JSON.parse(jsonContent);
|
|
122
149
|
// Validate the structure
|
|
123
150
|
if (parsedConfig.siteInfo && parsedConfig.routes) {
|
|
124
|
-
|
|
151
|
+
// Ensure keywords are arrays for all routes
|
|
152
|
+
const normalizedRoutes = parsedConfig.routes.map((route) => ({
|
|
153
|
+
...route,
|
|
154
|
+
keywords: Array.isArray(route.keywords)
|
|
155
|
+
? route.keywords
|
|
156
|
+
: (typeof route.keywords === 'string'
|
|
157
|
+
? route.keywords.split(',').map((k) => k.trim()).filter((k) => k.length > 0)
|
|
158
|
+
: [])
|
|
159
|
+
}));
|
|
160
|
+
setConfig({
|
|
161
|
+
...parsedConfig,
|
|
162
|
+
routes: normalizedRoutes
|
|
163
|
+
});
|
|
125
164
|
setSocialLinks(parsedConfig.siteInfo.sameAs || ['']);
|
|
126
165
|
}
|
|
127
166
|
else {
|
|
@@ -138,9 +177,18 @@ export function ConfigBuilder(props) {
|
|
|
138
177
|
};
|
|
139
178
|
useEffect(() => {
|
|
140
179
|
if (initialConfig) {
|
|
180
|
+
// Ensure keywords are arrays for all routes
|
|
181
|
+
const normalizedRoutes = (initialConfig.routes || []).map((route) => ({
|
|
182
|
+
...route,
|
|
183
|
+
keywords: Array.isArray(route.keywords)
|
|
184
|
+
? route.keywords
|
|
185
|
+
: (typeof route.keywords === 'string'
|
|
186
|
+
? route.keywords.split(',').map((k) => k.trim()).filter((k) => k.length > 0)
|
|
187
|
+
: [])
|
|
188
|
+
}));
|
|
141
189
|
setConfig((prev) => ({
|
|
142
190
|
siteInfo: { ...prev.siteInfo, ...initialConfig.siteInfo },
|
|
143
|
-
routes:
|
|
191
|
+
routes: normalizedRoutes,
|
|
144
192
|
visualdesign: initialConfig.visualdesign || prev.visualdesign || {}
|
|
145
193
|
}));
|
|
146
194
|
setSocialLinks(initialConfig.siteInfo?.sameAs || ['']);
|
|
@@ -155,11 +203,18 @@ export function ConfigBuilder(props) {
|
|
|
155
203
|
value: config.siteInfo[field.props.name] || '',
|
|
156
204
|
defaultValue: config.siteInfo[field.props.name] || field.props.defaultValue || '',
|
|
157
205
|
onChange: (value) => {
|
|
206
|
+
// Handle both direct values and event objects
|
|
207
|
+
let actualValue = value;
|
|
208
|
+
if (value && typeof value === 'object' && value.target) {
|
|
209
|
+
// It's an event object, extract the value
|
|
210
|
+
const target = value.target;
|
|
211
|
+
actualValue = target.type === 'checkbox' ? (target.checked ? target.value : '') : target.value;
|
|
212
|
+
}
|
|
158
213
|
setConfig((prev) => ({
|
|
159
214
|
...prev,
|
|
160
215
|
siteInfo: {
|
|
161
216
|
...prev.siteInfo,
|
|
162
|
-
[field.props.name]:
|
|
217
|
+
[field.props.name]: actualValue
|
|
163
218
|
}
|
|
164
219
|
}));
|
|
165
220
|
}
|
|
@@ -174,7 +229,8 @@ export function ConfigBuilder(props) {
|
|
|
174
229
|
...field.props,
|
|
175
230
|
value: (config.visualdesign && config.visualdesign[field.props.name]) ? (config.visualdesign[field.props.name].value ?? config.visualdesign[field.props.name]) : '',
|
|
176
231
|
defaultValue: (config.visualdesign && config.visualdesign[field.props.name]) ? (config.visualdesign[field.props.name].value ?? config.visualdesign[field.props.name]) : field.props.defaultValue || '',
|
|
177
|
-
onChange: (
|
|
232
|
+
onChange: (event) => {
|
|
233
|
+
const value = event.target.value;
|
|
178
234
|
setConfig((prev) => ({
|
|
179
235
|
...prev,
|
|
180
236
|
visualdesign: {
|
|
@@ -228,13 +284,18 @@ export function ConfigBuilder(props) {
|
|
|
228
284
|
const addRoute = () => {
|
|
229
285
|
setConfig(prev => ({
|
|
230
286
|
...prev,
|
|
231
|
-
routes: [...prev.routes, {
|
|
287
|
+
routes: [...prev.routes, { name: '', path: '', title: '', description: '', keywords: [], hidden: false }]
|
|
232
288
|
}));
|
|
233
289
|
};
|
|
234
290
|
const updateRoute = (index, field, value) => {
|
|
291
|
+
// Special handling for keywords field - convert comma-separated string to array
|
|
292
|
+
let processedValue = value;
|
|
293
|
+
if (field === 'keywords' && typeof value === 'string') {
|
|
294
|
+
processedValue = value.split(',').map((k) => k.trim()).filter((k) => k.length > 0);
|
|
295
|
+
}
|
|
235
296
|
setConfig(prev => ({
|
|
236
297
|
...prev,
|
|
237
|
-
routes: prev.routes.map((route, i) => i === index ? { ...route, [field]:
|
|
298
|
+
routes: prev.routes.map((route, i) => i === index ? { ...route, [field]: processedValue } : route)
|
|
238
299
|
}));
|
|
239
300
|
};
|
|
240
301
|
const removeRoute = (index) => {
|
|
@@ -250,6 +311,60 @@ export function ConfigBuilder(props) {
|
|
|
250
311
|
}
|
|
251
312
|
onSave?.(config);
|
|
252
313
|
};
|
|
314
|
+
const handleAiRecommendations = async (routeIndex) => {
|
|
315
|
+
console.log('handleAiRecommendations called with routeIndex:', routeIndex);
|
|
316
|
+
setCurrentRouteIndex(routeIndex);
|
|
317
|
+
setAiLoading(true);
|
|
318
|
+
setAiModalOpen(true);
|
|
319
|
+
setAcceptTitle(false);
|
|
320
|
+
setAcceptKeywords(false);
|
|
321
|
+
setAcceptDescription(false);
|
|
322
|
+
try {
|
|
323
|
+
const geminiService = createGeminiApiService('dummy-key'); // API key handled server-side
|
|
324
|
+
const route = config.routes[routeIndex];
|
|
325
|
+
const result = await geminiService.generateRouteRecommendations({
|
|
326
|
+
route,
|
|
327
|
+
siteInfo: config.siteInfo,
|
|
328
|
+
baseUrl: config.siteInfo.url
|
|
329
|
+
});
|
|
330
|
+
if (result.success && result.data) {
|
|
331
|
+
setAiRecommendations(result.data);
|
|
332
|
+
}
|
|
333
|
+
else {
|
|
334
|
+
setAiRecommendations({ error: result.error || 'Failed to generate recommendations' });
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
catch (error) {
|
|
338
|
+
console.error('AI recommendation error:', error);
|
|
339
|
+
setAiRecommendations({ error: 'Failed to generate AI recommendations' });
|
|
340
|
+
}
|
|
341
|
+
finally {
|
|
342
|
+
setAiLoading(false);
|
|
343
|
+
}
|
|
344
|
+
};
|
|
345
|
+
const handleAcceptAiRecommendations = () => {
|
|
346
|
+
if (currentRouteIndex === null || !aiRecommendations)
|
|
347
|
+
return;
|
|
348
|
+
const updates = {};
|
|
349
|
+
if (acceptTitle && aiRecommendations.title) {
|
|
350
|
+
updates.title = aiRecommendations.title;
|
|
351
|
+
}
|
|
352
|
+
if (acceptKeywords && aiRecommendations.keywords) {
|
|
353
|
+
updates.keywords = aiRecommendations.keywords;
|
|
354
|
+
}
|
|
355
|
+
if (acceptDescription && aiRecommendations.description) {
|
|
356
|
+
updates.description = aiRecommendations.description;
|
|
357
|
+
}
|
|
358
|
+
if (Object.keys(updates).length > 0) {
|
|
359
|
+
setConfig(prev => ({
|
|
360
|
+
...prev,
|
|
361
|
+
routes: prev.routes.map((route, i) => i === currentRouteIndex ? { ...route, ...updates } : route)
|
|
362
|
+
}));
|
|
363
|
+
}
|
|
364
|
+
setAiModalOpen(false);
|
|
365
|
+
setAiRecommendations(null);
|
|
366
|
+
setCurrentRouteIndex(null);
|
|
367
|
+
};
|
|
253
368
|
return (_jsxs("div", { className: "config-builder", children: [_jsx("h2", { children: "Config Builder" }), _jsxs("div", { className: "file-upload-section", children: [_jsx("label", { htmlFor: "config-file-upload", className: "file-upload-label", children: "Load Configuration File:" }), _jsx("input", { id: "config-file-upload", type: "file", accept: ".json", onChange: handleFileUpload, className: "file-upload-input" })] }), _jsx(Tab, { tabs: [
|
|
254
369
|
{
|
|
255
370
|
id: 'siteinfo',
|
|
@@ -259,7 +374,41 @@ export function ConfigBuilder(props) {
|
|
|
259
374
|
{
|
|
260
375
|
id: 'routes',
|
|
261
376
|
label: 'Routes',
|
|
262
|
-
content: (
|
|
377
|
+
content: (_jsx(FormValidationProvider, { children: _jsxs("div", { className: "routes-section", children: [_jsx("div", { className: "routes-list", children: config.routes.map((route, index) => (_jsxs("div", { className: "route-item", children: [routesForm.fields.map((field) => {
|
|
378
|
+
const Component = FC[field.component];
|
|
379
|
+
if (!Component)
|
|
380
|
+
return null;
|
|
381
|
+
let fieldValue = route[field.props.name];
|
|
382
|
+
if (field.props.name === 'keywords' && Array.isArray(fieldValue)) {
|
|
383
|
+
fieldValue = fieldValue.join(', ');
|
|
384
|
+
}
|
|
385
|
+
const fieldProps = {
|
|
386
|
+
...field.props,
|
|
387
|
+
id: `${field.props.id}-${index}`,
|
|
388
|
+
...(field.component === 'FormTextarea'
|
|
389
|
+
? { defaultValue: fieldValue || '' }
|
|
390
|
+
: field.props.type === 'checkbox'
|
|
391
|
+
? { checked: fieldValue || false }
|
|
392
|
+
: { value: fieldValue || '' }),
|
|
393
|
+
onChange: (e) => {
|
|
394
|
+
let value;
|
|
395
|
+
if (field.props.type === 'checkbox') {
|
|
396
|
+
value = e.target.checked;
|
|
397
|
+
}
|
|
398
|
+
else if (field.props.name === 'keywords') {
|
|
399
|
+
value = e.target.value.split(',').map((s) => s.trim()).filter((s) => s);
|
|
400
|
+
}
|
|
401
|
+
else {
|
|
402
|
+
value = e.target.value;
|
|
403
|
+
}
|
|
404
|
+
updateRoute(index, field.props.name, value);
|
|
405
|
+
}
|
|
406
|
+
};
|
|
407
|
+
return _jsx(Component, { ...fieldProps }, fieldProps.id);
|
|
408
|
+
}), _jsxs("div", { className: "route-buttons", children: [_jsxs("button", { onClick: () => {
|
|
409
|
+
console.log('AI Recommend button clicked for route:', index);
|
|
410
|
+
handleAiRecommendations(index);
|
|
411
|
+
}, className: "route-button ai-recommend", children: [_jsx("span", { className: "ai-icon", children: "\u2728" }), " Recommend"] }), _jsx("button", { onClick: () => removeRoute(index), className: "route-button remove", children: "Remove" })] })] }, index))) }), _jsx("button", { onClick: addRoute, children: "Add Route" })] }) }))
|
|
263
412
|
},
|
|
264
413
|
{
|
|
265
414
|
id: 'visualdesign',
|
|
@@ -269,8 +418,25 @@ export function ConfigBuilder(props) {
|
|
|
269
418
|
], orientation: "top" }), _jsx("button", { onClick: handleSave, disabled: !isFormValid, className: isFormValid ? 'save-button-valid' : 'save-button-invalid', children: "Save Config" }), !isFormValid && (_jsx("div", { className: "validation-message", children: "Please fill in all required fields (marked with *) before saving." })), _jsx(Accordion, { items: [
|
|
270
419
|
{
|
|
271
420
|
title: 'Configuration Preview',
|
|
272
|
-
content: _jsx("pre", { children:
|
|
421
|
+
content: _jsx("pre", { children: (() => {
|
|
422
|
+
try {
|
|
423
|
+
return JSON.stringify(config, null, 2);
|
|
424
|
+
}
|
|
425
|
+
catch (e) {
|
|
426
|
+
// Simple fallback that doesn't try to analyze the object deeply
|
|
427
|
+
const errorMessage = e instanceof Error ? e.message : String(e);
|
|
428
|
+
return `Configuration contains non-serializable data (functions, circular references, or DOM elements).\n\nError: ${errorMessage}\n\nTo debug, check the config object in browser dev tools for functions or complex objects.`;
|
|
429
|
+
}
|
|
430
|
+
})() })
|
|
273
431
|
}
|
|
274
|
-
] })] }))
|
|
432
|
+
] }), _jsx(Modal, { modalID: "ai-recommendations", isOpen: aiModalOpen, handleCloseEvent: () => setAiModalOpen(false), modalContent: _jsxs("div", { className: "ai-recommendations-modal", children: [_jsx("h3", { children: "AI SEO Recommendations" }), currentRouteIndex !== null && (_jsxs("p", { children: [_jsx("strong", { children: "Route:" }), " ", config.routes[currentRouteIndex].name || config.routes[currentRouteIndex].path] })), aiLoading ? (_jsxs("div", { className: "ai-loading", children: [_jsx("p", { children: "Generating AI recommendations..." }), _jsx("div", { className: "loading-spinner" })] })) : aiRecommendations?.error ? (_jsx("div", { className: "ai-error", children: _jsxs("p", { children: ["Error: ", aiRecommendations.error] }) })) : aiRecommendations ? (_jsxs("div", { className: "ai-recommendations", children: [_jsxs("div", { className: "recommendation-item", children: [_jsxs("label", { children: [_jsx("input", { type: "checkbox", checked: acceptTitle, onChange: (e) => setAcceptTitle(e.target.checked) }), _jsx("strong", { children: "Title:" })] }), _jsxs("div", { className: "recommendation-content", children: [_jsx("div", { className: "current-value", children: _jsxs("small", { children: ["Current: ", config.routes[currentRouteIndex]?.title || 'None'] }) }), _jsx("div", { className: "suggested-value", children: aiRecommendations.title })] })] }), _jsxs("div", { className: "recommendation-item", children: [_jsxs("label", { children: [_jsx("input", { type: "checkbox", checked: acceptKeywords, onChange: (e) => setAcceptKeywords(e.target.checked) }), _jsx("strong", { children: "Keywords:" })] }), _jsxs("div", { className: "recommendation-content", children: [_jsx("div", { className: "current-value", children: _jsxs("small", { children: ["Current: ", (() => {
|
|
433
|
+
const keywords = config.routes[currentRouteIndex]?.keywords;
|
|
434
|
+
if (Array.isArray(keywords)) {
|
|
435
|
+
return keywords.join(', ') || 'None';
|
|
436
|
+
}
|
|
437
|
+
else if (typeof keywords === 'string') {
|
|
438
|
+
return keywords || 'None';
|
|
439
|
+
}
|
|
440
|
+
return 'None';
|
|
441
|
+
})()] }) }), _jsx("div", { className: "suggested-value", children: aiRecommendations.keywords?.join(', ') })] })] }), _jsxs("div", { className: "recommendation-item", children: [_jsxs("label", { children: [_jsx("input", { type: "checkbox", checked: acceptDescription, onChange: (e) => setAcceptDescription(e.target.checked) }), _jsx("strong", { children: "Description:" })] }), _jsxs("div", { className: "recommendation-content", children: [_jsx("div", { className: "current-value", children: _jsxs("small", { children: ["Current: ", config.routes[currentRouteIndex]?.description || 'None'] }) }), _jsx("div", { className: "suggested-value", children: aiRecommendations.description })] })] })] })) : null, _jsxs("div", { className: "modal-actions", children: [_jsx("button", { onClick: () => setAiModalOpen(false), children: "Cancel" }), _jsx("button", { onClick: handleAcceptAiRecommendations, disabled: !acceptTitle && !acceptKeywords && !acceptDescription, className: "accept-button", children: "Accept Selected" })] })] }) })] }));
|
|
275
442
|
}
|
|
276
|
-
ConfigBuilder.propTypes = ConfigBuilderPropTypes;
|
|
@@ -4,7 +4,18 @@ import PropTypes from 'prop-types';
|
|
|
4
4
|
import { getFontOptions } from './google-fonts';
|
|
5
5
|
import { WEB_SAFE_FONTS, GENERIC_FAMILIES } from './fonts';
|
|
6
6
|
import './FontSelector.css';
|
|
7
|
-
|
|
7
|
+
FontSelector.propTypes = {
|
|
8
|
+
id: PropTypes.string.isRequired,
|
|
9
|
+
name: PropTypes.string.isRequired,
|
|
10
|
+
label: PropTypes.string.isRequired,
|
|
11
|
+
fontType: PropTypes.oneOf(['google', 'websafe', 'generic']).isRequired,
|
|
12
|
+
required: PropTypes.bool,
|
|
13
|
+
placeholder: PropTypes.string,
|
|
14
|
+
value: PropTypes.string,
|
|
15
|
+
onChange: PropTypes.func,
|
|
16
|
+
};
|
|
17
|
+
export function FontSelector(props) {
|
|
18
|
+
const { id, name, label, fontType, required = false, placeholder, value = '', onChange } = props;
|
|
8
19
|
const [inputValue, setInputValue] = useState(value);
|
|
9
20
|
const [googleFonts, setGoogleFonts] = useState([]);
|
|
10
21
|
const [isLoading, setIsLoading] = useState(false);
|
|
@@ -67,7 +78,7 @@ export function FontSelector({ id, name, label, fontType, required = false, plac
|
|
|
67
78
|
}
|
|
68
79
|
return null;
|
|
69
80
|
};
|
|
70
|
-
return (_jsxs("div", { className: "font-selector-container", children: [_jsxs("label", { htmlFor: id, className: "font-selector-label", children: [label, required && _jsx("span", { className: "font-selector-required", children: "*" }), getTooltip() && (_jsx("span", { className: "font-selector-tooltip", title: getTooltip().replace(/\[([^\]]+)\]\([^)]+\)/, '$1'), children: "\uD83D\uDC41\uFE0F" }))] }), _jsxs("div", { className: "font-selector-input-container", children: [_jsx("input", { type: "text", id: id, name: name, value: inputValue, onChange: handleInputChange, onFocus: handleFocus, onBlur: handleBlur, placeholder: placeholder, required: required, autoComplete: "off", className: "font-selector-input" }), showDropdown && filteredOptions.length > 0 && (_jsx("div", { className: "font-selector-dropdown", children: isLoading ? (_jsx("div", { className: "font-selector-loading", children: "Loading fonts..." })) : (filteredOptions.map((option) => (_jsxs("div", { className: "font-selector-option", onClick: () => handleOptionSelect(option), onKeyDown: (e) => {
|
|
81
|
+
return (_jsxs("div", { className: "font-selector-container", children: [_jsxs("label", { htmlFor: id, className: "font-selector-label", children: [label, required && _jsx("span", { className: "font-selector-required", children: "*" }), getTooltip() && (_jsx("span", { className: "font-selector-tooltip", title: getTooltip().replace(/\[([^\]]+)\]\([^)]+\)/, '$1'), children: "\uD83D\uDC41\uFE0F" }))] }), _jsxs("div", { className: "font-selector-input-container", children: [_jsx("input", { type: "text", id: id, name: name, value: inputValue ?? '', onChange: handleInputChange, onFocus: handleFocus, onBlur: handleBlur, placeholder: placeholder ?? undefined, required: required ?? false, autoComplete: "off", className: "font-selector-input" }), showDropdown && filteredOptions.length > 0 && (_jsx("div", { className: "font-selector-dropdown", children: isLoading ? (_jsx("div", { className: "font-selector-loading", children: "Loading fonts..." })) : (filteredOptions.map((option) => (_jsxs("div", { className: "font-selector-option", onClick: () => handleOptionSelect(option), onKeyDown: (e) => {
|
|
71
82
|
if (e.key === 'Enter' || e.key === ' ') {
|
|
72
83
|
e.preventDefault();
|
|
73
84
|
handleOptionSelect(option);
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
{
|
|
2
|
+
"fields": [
|
|
3
|
+
{
|
|
4
|
+
"component": "FormInput",
|
|
5
|
+
"props": {
|
|
6
|
+
"type": "text",
|
|
7
|
+
"id": "name",
|
|
8
|
+
"name": "name",
|
|
9
|
+
"label": "Route Name",
|
|
10
|
+
"required": true,
|
|
11
|
+
"placeholder": "e.g., Home Page",
|
|
12
|
+
"size": "40"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"component": "FormInput",
|
|
17
|
+
"props": {
|
|
18
|
+
"type": "text",
|
|
19
|
+
"id": "path",
|
|
20
|
+
"name": "path",
|
|
21
|
+
"label": "Path",
|
|
22
|
+
"required": true,
|
|
23
|
+
"placeholder": "e.g., /",
|
|
24
|
+
"size": "40"
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"component": "FormInput",
|
|
29
|
+
"props": {
|
|
30
|
+
"type": "text",
|
|
31
|
+
"id": "title",
|
|
32
|
+
"name": "title",
|
|
33
|
+
"label": "Title",
|
|
34
|
+
"placeholder": "Page title for SEO",
|
|
35
|
+
"size": "40"
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"component": "FormTextarea",
|
|
40
|
+
"props": {
|
|
41
|
+
"id": "description",
|
|
42
|
+
"name": "description",
|
|
43
|
+
"label": "Description",
|
|
44
|
+
"placeholder": "Meta description for SEO"
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"component": "FormTextarea",
|
|
49
|
+
"props": {
|
|
50
|
+
"id": "keywords",
|
|
51
|
+
"name": "keywords",
|
|
52
|
+
"label": "Keywords",
|
|
53
|
+
"placeholder": "Comma-separated keywords for SEO",
|
|
54
|
+
"cols": "40"
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
"component": "FormInput",
|
|
59
|
+
"props": {
|
|
60
|
+
"type": "checkbox",
|
|
61
|
+
"id": "hidden",
|
|
62
|
+
"name": "hidden",
|
|
63
|
+
"label": "Hidden Route"
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
]
|
|
67
|
+
}
|
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
"name": "name",
|
|
9
9
|
"label": "Site Name",
|
|
10
10
|
"required": true,
|
|
11
|
-
"placeholder": "Enter site name"
|
|
11
|
+
"placeholder": "Enter site name",
|
|
12
|
+
"size": "40"
|
|
12
13
|
}
|
|
13
14
|
},
|
|
14
15
|
{
|
|
@@ -19,7 +20,8 @@
|
|
|
19
20
|
"name": "author",
|
|
20
21
|
"label": "Author",
|
|
21
22
|
"required": true,
|
|
22
|
-
"placeholder": "Enter author name"
|
|
23
|
+
"placeholder": "Enter author name",
|
|
24
|
+
"size": "40"
|
|
23
25
|
}
|
|
24
26
|
},
|
|
25
27
|
{
|
|
@@ -41,7 +43,8 @@
|
|
|
41
43
|
"name": "url",
|
|
42
44
|
"label": "Site URL",
|
|
43
45
|
"required": true,
|
|
44
|
-
"placeholder": "https://example.com"
|
|
46
|
+
"placeholder": "https://example.com",
|
|
47
|
+
"size": "40"
|
|
45
48
|
}
|
|
46
49
|
},
|
|
47
50
|
{
|
|
@@ -52,7 +55,8 @@
|
|
|
52
55
|
"name": "email",
|
|
53
56
|
"label": "Email",
|
|
54
57
|
"required": true,
|
|
55
|
-
"placeholder": "contact@example.com"
|
|
58
|
+
"placeholder": "contact@example.com",
|
|
59
|
+
"size": "40"
|
|
56
60
|
}
|
|
57
61
|
},
|
|
58
62
|
{
|
|
@@ -63,7 +67,8 @@
|
|
|
63
67
|
"name": "favicon",
|
|
64
68
|
"label": "Favicon",
|
|
65
69
|
"required": true,
|
|
66
|
-
"placeholder": "/favicon.ico"
|
|
70
|
+
"placeholder": "/favicon.ico",
|
|
71
|
+
"size": "40"
|
|
67
72
|
}
|
|
68
73
|
},
|
|
69
74
|
{
|
|
@@ -74,7 +79,8 @@
|
|
|
74
79
|
"name": "favicon_sizes",
|
|
75
80
|
"label": "Favicon Sizes",
|
|
76
81
|
"required": true,
|
|
77
|
-
"placeholder": "64x64 32x32 24x24 16x16"
|
|
82
|
+
"placeholder": "64x64 32x32 24x24 16x16",
|
|
83
|
+
"size": "40"
|
|
78
84
|
}
|
|
79
85
|
},
|
|
80
86
|
{
|
|
@@ -85,7 +91,8 @@
|
|
|
85
91
|
"name": "favicon_type",
|
|
86
92
|
"label": "Favicon Type",
|
|
87
93
|
"required": true,
|
|
88
|
-
"placeholder": "image/x-icon"
|
|
94
|
+
"placeholder": "image/x-icon",
|
|
95
|
+
"size": "40"
|
|
89
96
|
}
|
|
90
97
|
},
|
|
91
98
|
{
|
|
@@ -118,7 +125,8 @@
|
|
|
118
125
|
"name": "default_locale",
|
|
119
126
|
"label": "Default Locale",
|
|
120
127
|
"required": true,
|
|
121
|
-
"placeholder": "en"
|
|
128
|
+
"placeholder": "en",
|
|
129
|
+
"size": "40"
|
|
122
130
|
}
|
|
123
131
|
},
|
|
124
132
|
{
|
|
@@ -143,7 +151,8 @@
|
|
|
143
151
|
"id": "image",
|
|
144
152
|
"name": "image",
|
|
145
153
|
"label": "Site Image",
|
|
146
|
-
"placeholder": "/images/site-image.jpg"
|
|
154
|
+
"placeholder": "/images/site-image.jpg",
|
|
155
|
+
"size": "40"
|
|
147
156
|
}
|
|
148
157
|
},
|
|
149
158
|
{
|
|
@@ -153,7 +162,8 @@
|
|
|
153
162
|
"id": "image_height",
|
|
154
163
|
"name": "image_height",
|
|
155
164
|
"label": "Image Height",
|
|
156
|
-
"placeholder": "512"
|
|
165
|
+
"placeholder": "512",
|
|
166
|
+
"size": "40"
|
|
157
167
|
}
|
|
158
168
|
},
|
|
159
169
|
{
|
|
@@ -163,7 +173,8 @@
|
|
|
163
173
|
"id": "image_width",
|
|
164
174
|
"name": "image_width",
|
|
165
175
|
"label": "Image Width",
|
|
166
|
-
"placeholder": "512"
|
|
176
|
+
"placeholder": "512",
|
|
177
|
+
"size": "40"
|
|
167
178
|
}
|
|
168
179
|
},
|
|
169
180
|
{
|
|
@@ -173,7 +184,8 @@
|
|
|
173
184
|
"id": "telephone",
|
|
174
185
|
"name": "telephone",
|
|
175
186
|
"label": "Telephone",
|
|
176
|
-
"placeholder": "+1-555-123-4567"
|
|
187
|
+
"placeholder": "+1-555-123-4567",
|
|
188
|
+
"size": "40"
|
|
177
189
|
}
|
|
178
190
|
},
|
|
179
191
|
{
|
|
@@ -183,7 +195,8 @@
|
|
|
183
195
|
"id": "priceRange",
|
|
184
196
|
"name": "priceRange",
|
|
185
197
|
"label": "Price Range",
|
|
186
|
-
"placeholder": "$$"
|
|
198
|
+
"placeholder": "$$",
|
|
199
|
+
"size": "40"
|
|
187
200
|
}
|
|
188
201
|
},
|
|
189
202
|
{
|
|
@@ -193,7 +206,8 @@
|
|
|
193
206
|
"id": "keywords",
|
|
194
207
|
"name": "keywords",
|
|
195
208
|
"label": "Keywords",
|
|
196
|
-
"placeholder": "web development, design, services"
|
|
209
|
+
"placeholder": "web development, design, services",
|
|
210
|
+
"size": "40"
|
|
197
211
|
}
|
|
198
212
|
}
|
|
199
213
|
]
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"name": "primary-color",
|
|
9
9
|
"label": "Primary color",
|
|
10
10
|
"required": true,
|
|
11
|
-
"placeholder": "#
|
|
11
|
+
"placeholder": "#336699"
|
|
12
12
|
}
|
|
13
13
|
},
|
|
14
14
|
{
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"name": "secondary-color",
|
|
20
20
|
"label": "Secondary color",
|
|
21
21
|
"required": true,
|
|
22
|
-
"placeholder": "#
|
|
22
|
+
"placeholder": "#BBCCDD"
|
|
23
23
|
}
|
|
24
24
|
},
|
|
25
25
|
{
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"name": "accent1-color",
|
|
31
31
|
"label": "Accent color 1",
|
|
32
32
|
"required": true,
|
|
33
|
-
"placeholder": "#
|
|
33
|
+
"placeholder": "#CCCCCC"
|
|
34
34
|
}
|
|
35
35
|
},
|
|
36
36
|
{
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"name": "accent2-color",
|
|
42
42
|
"label": "Accent color 2",
|
|
43
43
|
"required": true,
|
|
44
|
-
"placeholder": "#
|
|
44
|
+
"placeholder": "#EEEEEE"
|
|
45
45
|
}
|
|
46
46
|
},
|
|
47
47
|
{
|
|
@@ -8,6 +8,7 @@ import { FormEngine } from './formengine';
|
|
|
8
8
|
/* ===== FORM BUILDER =====
|
|
9
9
|
Display all the components for a Form Builder -
|
|
10
10
|
Element Buttons, Element Details, and the Form */
|
|
11
|
+
FormBuilder.propTypes = {};
|
|
11
12
|
export function FormBuilder() {
|
|
12
13
|
const [formData, setFormData] = useState({ fields: [] });
|
|
13
14
|
const [fieldFormData, setFieldFormData] = useState({ fields: [] });
|
|
@@ -53,7 +53,7 @@ const useFormComponent = (props) => {
|
|
|
53
53
|
const customOnChange = props.onChange || (props.parent && props.parent.onChange);
|
|
54
54
|
if (customOnChange) {
|
|
55
55
|
try {
|
|
56
|
-
customOnChange(
|
|
56
|
+
customOnChange(event);
|
|
57
57
|
}
|
|
58
58
|
catch {
|
|
59
59
|
// swallow handler errors to avoid breaking validation flow
|
|
@@ -293,7 +293,6 @@ FormRadioOption.propTypes = {
|
|
|
293
293
|
function FormRadioOption(props) {
|
|
294
294
|
const inputProps = setupInputProps(props);
|
|
295
295
|
const isChecked = props.parent.checked === props.value;
|
|
296
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
297
296
|
const handleChange = (e) => {
|
|
298
297
|
if (props.parent.onChange) {
|
|
299
298
|
props.parent.onChange(props.value);
|
|
@@ -374,7 +373,7 @@ export function FormDataList(props) {
|
|
|
374
373
|
return (_jsx("datalist", { id: props.id, children: options }));
|
|
375
374
|
}
|
|
376
375
|
FormFieldset.propTypes = {};
|
|
377
|
-
export function FormFieldset() {
|
|
376
|
+
export function FormFieldset(props) {
|
|
378
377
|
return (_jsx(_Fragment, {}));
|
|
379
378
|
}
|
|
380
379
|
// Re-export FontSelector for use in forms
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
"use client";
|
|
1
2
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
3
|
import React from 'react';
|
|
3
4
|
import PropTypes from 'prop-types';
|
|
@@ -14,14 +15,17 @@ FormEngine.propTypes = {
|
|
|
14
15
|
onSubmitHandler: PropTypes.func,
|
|
15
16
|
formData: PropTypes.object.isRequired
|
|
16
17
|
};
|
|
18
|
+
export function FormEngine(props) {
|
|
19
|
+
return (_jsx(FormValidationProvider, { children: _jsx(FormEngineInner, { ...props }) }));
|
|
20
|
+
}
|
|
17
21
|
function FormEngineInner(props) {
|
|
18
22
|
const { validateAllFields } = useFormValidation();
|
|
19
23
|
function generateFormProps(props) {
|
|
20
24
|
// GENERATE PROPS TO RENDER THE FORM CONTAINER, INTERNAL FUNCTION
|
|
21
25
|
if (debug)
|
|
22
26
|
console.log("Generating Form Props");
|
|
23
|
-
|
|
24
|
-
|
|
27
|
+
// Create a clean copy without non-serializable properties
|
|
28
|
+
const { formData, onSubmitHandler, ...formProps } = props;
|
|
25
29
|
return formProps;
|
|
26
30
|
}
|
|
27
31
|
generateNewFields.propTypes = {
|
|
@@ -77,6 +81,3 @@ function FormEngineInner(props) {
|
|
|
77
81
|
}
|
|
78
82
|
return (_jsx("form", { ...generateFormProps(props), onSubmit: (event) => { handleSubmit(event); }, suppressHydrationWarning: true, children: generateNewFields(props) }));
|
|
79
83
|
}
|
|
80
|
-
export function FormEngine(props) {
|
|
81
|
-
return (_jsx(FormValidationProvider, { children: _jsx(FormEngineInner, { ...props }) }));
|
|
82
|
-
}
|