@pixelated-tech/components 3.2.14 → 3.3.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.COMPONENTS.md +289 -30
- package/README.md +36 -28
- package/dist/components/general/tab.css +105 -0
- package/dist/components/general/tab.js +26 -0
- package/dist/components/seo/metadata.components.js +0 -19
- package/dist/components/seo/metadata.functions.js +111 -0
- package/dist/components/seo/schema-blogposting.functions.js +42 -0
- package/dist/components/seo/schema-blogposting.js +0 -46
- package/dist/components/seo/sitemap.js +1 -1
- package/dist/components/shoppingcart/shoppingcart.components.js +4 -4
- package/dist/components/sitebuilder/config/ConfigBuilder.css +266 -0
- package/dist/components/sitebuilder/config/ConfigBuilder.js +221 -0
- package/dist/components/{pagebuilder → sitebuilder}/form/form.css +55 -34
- package/dist/components/sitebuilder/form/formbuilder.js +106 -0
- package/dist/components/sitebuilder/form/formcomponents.js +356 -0
- package/dist/components/sitebuilder/form/formengine.js +82 -0
- package/dist/components/{pagebuilder/form/form.js → sitebuilder/form/formextractor.js} +10 -211
- package/dist/components/sitebuilder/form/formutils.js +206 -0
- package/dist/components/sitebuilder/form/formvalidator.js +123 -0
- package/dist/components/{pagebuilder → sitebuilder/page}/components/ComponentPropertiesForm.js +1 -1
- package/dist/components/{pagebuilder → sitebuilder/page}/components/PageBuilderUI.js +2 -2
- package/dist/components/{pagebuilder → sitebuilder/page}/components/PageEngine.js +1 -1
- package/dist/components/sitebuilder/page/documentation/api-examples/save-route-example.js +37 -0
- package/dist/components/{pagebuilder → sitebuilder/page}/lib/componentMap.js +3 -3
- package/dist/components/{pagebuilder → sitebuilder/page}/lib/componentMetadata.js +2 -2
- package/dist/components/{pagebuilder → sitebuilder/page}/lib/pageStorageContentful.js +2 -2
- package/dist/components/sitebuilder/page/lib/pageStorageTypes.js +1 -0
- package/dist/data/form.json +18 -18
- package/dist/data/shipping.to.json +9 -9
- package/dist/data/siteinfo-form.json +200 -0
- package/dist/index.js +29 -21
- package/dist/index.server.js +24 -17
- package/dist/types/components/general/semantic.d.ts +3 -3
- package/dist/types/components/general/tab.d.ts +18 -0
- package/dist/types/components/general/tab.d.ts.map +1 -0
- package/dist/types/components/seo/metadata.components.d.ts +0 -17
- package/dist/types/components/seo/metadata.components.d.ts.map +1 -1
- package/dist/types/components/seo/{metadata.d.ts → metadata.functions.d.ts} +15 -1
- package/dist/types/components/seo/metadata.functions.d.ts.map +1 -0
- package/dist/types/components/seo/schema-blogposting.d.ts +1 -25
- package/dist/types/components/seo/schema-blogposting.d.ts.map +1 -1
- package/dist/types/components/seo/schema-blogposting.functions.d.ts +26 -0
- package/dist/types/components/seo/schema-blogposting.functions.d.ts.map +1 -0
- package/dist/types/components/seo/sitemap.d.ts.map +1 -1
- package/dist/types/components/shoppingcart/shoppingcart.components.d.ts +1 -1
- package/dist/types/components/sitebuilder/config/ConfigBuilder.d.ts +86 -0
- package/dist/types/components/sitebuilder/config/ConfigBuilder.d.ts.map +1 -0
- package/dist/types/components/sitebuilder/form/formbuilder.d.ts +11 -0
- package/dist/types/components/sitebuilder/form/formbuilder.d.ts.map +1 -0
- package/dist/types/components/{pagebuilder → sitebuilder}/form/formcomponents.d.ts +12 -16
- package/dist/types/components/sitebuilder/form/formcomponents.d.ts.map +1 -0
- package/dist/types/components/{pagebuilder/form/form.submit.d.ts → sitebuilder/form/formemailer.d.ts} +1 -1
- package/dist/types/components/sitebuilder/form/formemailer.d.ts.map +1 -0
- package/dist/types/components/sitebuilder/form/formengine.d.ts +14 -0
- package/dist/types/components/sitebuilder/form/formengine.d.ts.map +1 -0
- package/dist/types/components/sitebuilder/form/formextractor.d.ts +25 -0
- package/dist/types/components/sitebuilder/form/formextractor.d.ts.map +1 -0
- package/dist/types/components/{pagebuilder/form/formvalidations.d.ts → sitebuilder/form/formfieldvalidations.d.ts} +1 -1
- package/dist/types/components/sitebuilder/form/formfieldvalidations.d.ts.map +1 -0
- package/dist/types/components/sitebuilder/form/formtypes.d.ts +66 -0
- package/dist/types/components/sitebuilder/form/formtypes.d.ts.map +1 -0
- package/dist/types/components/sitebuilder/form/formutils.d.ts +20 -0
- package/dist/types/components/sitebuilder/form/formutils.d.ts.map +1 -0
- package/dist/types/components/sitebuilder/form/formvalidator.d.ts +20 -0
- package/dist/types/components/sitebuilder/form/formvalidator.d.ts.map +1 -0
- package/dist/types/components/sitebuilder/page/components/ComponentPropertiesForm.d.ts.map +1 -0
- package/dist/types/components/sitebuilder/page/components/ComponentSelector.d.ts.map +1 -0
- package/dist/types/components/sitebuilder/page/components/ComponentTree.d.ts.map +1 -0
- package/dist/types/components/{pagebuilder → sitebuilder/page}/components/PageBuilderUI.d.ts +1 -1
- package/dist/types/components/sitebuilder/page/components/PageBuilderUI.d.ts.map +1 -0
- package/dist/types/components/sitebuilder/page/components/PageEngine.d.ts.map +1 -0
- package/dist/types/components/sitebuilder/page/components/SaveLoadSection.d.ts.map +1 -0
- package/dist/types/components/sitebuilder/page/documentation/api-examples/save-route-example.d.ts +6 -0
- package/dist/types/components/sitebuilder/page/documentation/api-examples/save-route-example.d.ts.map +1 -0
- package/dist/types/components/sitebuilder/page/lib/componentGeneration.d.ts.map +1 -0
- package/dist/types/components/{pagebuilder → sitebuilder/page}/lib/componentMap.d.ts +3 -3
- package/dist/types/components/sitebuilder/page/lib/componentMap.d.ts.map +1 -0
- package/dist/types/components/sitebuilder/page/lib/componentMetadata.d.ts.map +1 -0
- package/dist/types/components/{pagebuilder → sitebuilder/page}/lib/pageStorageContentful.d.ts +1 -1
- package/dist/types/components/sitebuilder/page/lib/pageStorageContentful.d.ts.map +1 -0
- package/dist/types/components/sitebuilder/page/lib/pageStorageLocal.d.ts.map +1 -0
- package/dist/types/components/sitebuilder/page/lib/pageStorageTypes.d.ts.map +1 -0
- package/dist/types/components/sitebuilder/page/lib/propTypeIntrospection.d.ts.map +1 -0
- package/dist/types/components/sitebuilder/page/lib/types.d.ts.map +1 -0
- package/dist/types/components/sitebuilder/page/lib/usePageBuilder.d.ts.map +1 -0
- package/dist/types/index.d.ts +29 -20
- package/dist/types/index.server.d.ts +23 -16
- package/dist/types/stories/general/tab.stories.d.ts +45 -0
- package/dist/types/stories/general/tab.stories.d.ts.map +1 -0
- package/dist/types/stories/seo/seo.metadata.stories.d.ts +1 -1
- package/dist/types/stories/seo/seo.metadata.stories.d.ts.map +1 -1
- package/dist/types/stories/sitebuilder/configbuilder.stories.d.ts +48 -0
- package/dist/types/stories/sitebuilder/configbuilder.stories.d.ts.map +1 -0
- package/dist/types/stories/{pagebuilder → sitebuilder}/form-builder.stories.d.ts +1 -1
- package/dist/types/stories/sitebuilder/form-builder.stories.d.ts.map +1 -0
- package/dist/types/stories/{pagebuilder → sitebuilder}/form-engine.stories.d.ts +1 -1
- package/dist/types/stories/sitebuilder/form-engine.stories.d.ts.map +1 -0
- package/dist/types/stories/{pagebuilder → sitebuilder}/form-extractor.stories.d.ts +1 -1
- package/dist/types/stories/sitebuilder/form-extractor.stories.d.ts.map +1 -0
- package/dist/types/stories/{pagebuilder → sitebuilder}/pagebuilder.stories.d.ts +1 -1
- package/dist/types/stories/{pagebuilder → sitebuilder}/pagebuilder.stories.d.ts.map +1 -1
- package/dist/types/stories/{pagebuilder → sitebuilder}/pagebuilder.usageguide.stories.d.ts +1 -1
- package/dist/types/stories/{pagebuilder → sitebuilder}/pagebuilder.usageguide.stories.d.ts.map +1 -1
- package/dist/types/stories/{pagebuilder → sitebuilder}/pageengine.stories.d.ts +1 -1
- package/dist/types/stories/{pagebuilder → sitebuilder}/pageengine.stories.d.ts.map +1 -1
- package/dist/types/tests/configbuilder.test.d.ts +2 -0
- package/dist/types/tests/configbuilder.test.d.ts.map +1 -0
- package/dist/types/tests/tab.test.d.ts +2 -0
- package/dist/types/tests/tab.test.d.ts.map +1 -0
- package/package.json +5 -4
- package/dist/components/pagebuilder/form/formcomponents.js +0 -359
- package/dist/components/seo/metadata.js +0 -108
- package/dist/types/components/pagebuilder/components/ComponentPropertiesForm.d.ts.map +0 -1
- package/dist/types/components/pagebuilder/components/ComponentSelector.d.ts.map +0 -1
- package/dist/types/components/pagebuilder/components/ComponentTree.d.ts.map +0 -1
- package/dist/types/components/pagebuilder/components/PageBuilderUI.d.ts.map +0 -1
- package/dist/types/components/pagebuilder/components/PageEngine.d.ts.map +0 -1
- package/dist/types/components/pagebuilder/components/SaveLoadSection.d.ts.map +0 -1
- package/dist/types/components/pagebuilder/form/form.d.ts +0 -46
- package/dist/types/components/pagebuilder/form/form.d.ts.map +0 -1
- package/dist/types/components/pagebuilder/form/form.submit.d.ts.map +0 -1
- package/dist/types/components/pagebuilder/form/formcomponents.d.ts.map +0 -1
- package/dist/types/components/pagebuilder/form/formvalidations.d.ts.map +0 -1
- package/dist/types/components/pagebuilder/lib/componentGeneration.d.ts.map +0 -1
- package/dist/types/components/pagebuilder/lib/componentMap.d.ts.map +0 -1
- package/dist/types/components/pagebuilder/lib/componentMetadata.d.ts.map +0 -1
- package/dist/types/components/pagebuilder/lib/pageStorageContentful.d.ts.map +0 -1
- package/dist/types/components/pagebuilder/lib/pageStorageLocal.d.ts.map +0 -1
- package/dist/types/components/pagebuilder/lib/pageStorageTypes.d.ts.map +0 -1
- package/dist/types/components/pagebuilder/lib/propTypeIntrospection.d.ts.map +0 -1
- package/dist/types/components/pagebuilder/lib/types.d.ts.map +0 -1
- package/dist/types/components/pagebuilder/lib/usePageBuilder.d.ts.map +0 -1
- package/dist/types/components/seo/metadata.d.ts.map +0 -1
- package/dist/types/stories/pagebuilder/form-builder.stories.d.ts.map +0 -1
- package/dist/types/stories/pagebuilder/form-engine.stories.d.ts.map +0 -1
- package/dist/types/stories/pagebuilder/form-extractor.stories.d.ts.map +0 -1
- /package/dist/components/{pagebuilder/form/form.submit.js → sitebuilder/form/formemailer.js} +0 -0
- /package/dist/components/{pagebuilder/form/formvalidations.js → sitebuilder/form/formfieldvalidations.js} +0 -0
- /package/dist/components/{pagebuilder/lib/pageStorageTypes.js → sitebuilder/form/formtypes.js} +0 -0
- /package/dist/components/{pagebuilder → sitebuilder/page}/components/ComponentSelector.js +0 -0
- /package/dist/components/{pagebuilder → sitebuilder/page}/components/ComponentTree.js +0 -0
- /package/dist/components/{pagebuilder → sitebuilder/page}/components/SaveLoadSection.js +0 -0
- /package/dist/components/{pagebuilder → sitebuilder/page}/components/pagebuilder.scss +0 -0
- /package/dist/components/{pagebuilder → sitebuilder/page}/lib/componentGeneration.js +0 -0
- /package/dist/components/{pagebuilder → sitebuilder/page}/lib/pageStorageLocal.js +0 -0
- /package/dist/components/{pagebuilder → sitebuilder/page}/lib/propTypeIntrospection.js +0 -0
- /package/dist/components/{pagebuilder → sitebuilder/page}/lib/types.js +0 -0
- /package/dist/components/{pagebuilder → sitebuilder/page}/lib/usePageBuilder.js +0 -0
- /package/dist/types/components/{pagebuilder → sitebuilder/page}/components/ComponentPropertiesForm.d.ts +0 -0
- /package/dist/types/components/{pagebuilder → sitebuilder/page}/components/ComponentSelector.d.ts +0 -0
- /package/dist/types/components/{pagebuilder → sitebuilder/page}/components/ComponentTree.d.ts +0 -0
- /package/dist/types/components/{pagebuilder → sitebuilder/page}/components/PageEngine.d.ts +0 -0
- /package/dist/types/components/{pagebuilder → sitebuilder/page}/components/SaveLoadSection.d.ts +0 -0
- /package/dist/types/components/{pagebuilder → sitebuilder/page}/lib/componentGeneration.d.ts +0 -0
- /package/dist/types/components/{pagebuilder → sitebuilder/page}/lib/componentMetadata.d.ts +0 -0
- /package/dist/types/components/{pagebuilder → sitebuilder/page}/lib/pageStorageLocal.d.ts +0 -0
- /package/dist/types/components/{pagebuilder → sitebuilder/page}/lib/pageStorageTypes.d.ts +0 -0
- /package/dist/types/components/{pagebuilder → sitebuilder/page}/lib/propTypeIntrospection.d.ts +0 -0
- /package/dist/types/components/{pagebuilder → sitebuilder/page}/lib/types.d.ts +0 -0
- /package/dist/types/components/{pagebuilder → sitebuilder/page}/lib/usePageBuilder.d.ts +0 -0
package/README.COMPONENTS.md
CHANGED
|
@@ -11,6 +11,7 @@ This guide provides detailed API documentation and usage examples for all Pixela
|
|
|
11
11
|
- [Modal](#modal)
|
|
12
12
|
- [SidePanel](#sidepanel)
|
|
13
13
|
- [SmartImage](#smartimage)
|
|
14
|
+
- [Tab](#tab)
|
|
14
15
|
- [Table](#table)
|
|
15
16
|
|
|
16
17
|
### CMS Integration
|
|
@@ -34,6 +35,7 @@ This guide provides detailed API documentation and usage examples for all Pixela
|
|
|
34
35
|
- [ComponentPropertiesForm](#componentpropertiesform)
|
|
35
36
|
- [ComponentSelector](#componentselector)
|
|
36
37
|
- [ComponentTree](#componenttree)
|
|
38
|
+
- [ConfigBuilder](#configbuilder)
|
|
37
39
|
- [PageBuilderUI](#pagebuilderui)
|
|
38
40
|
- [PageEngine](#pageengine)
|
|
39
41
|
- [SaveLoadSection](#saveloadsection)
|
|
@@ -554,7 +556,7 @@ const reviews = [
|
|
|
554
556
|
|
|
555
557
|
### Forms
|
|
556
558
|
|
|
557
|
-
Dynamic form builder that generates forms from JSON configuration.
|
|
559
|
+
Dynamic form builder that generates forms from JSON configuration with comprehensive validation and event handling.
|
|
558
560
|
|
|
559
561
|
#### FormEngine
|
|
560
562
|
|
|
@@ -566,21 +568,39 @@ import { FormEngine } from '@pixelated-tech/components';
|
|
|
566
568
|
const formConfig = {
|
|
567
569
|
fields: [
|
|
568
570
|
{
|
|
569
|
-
|
|
571
|
+
component: 'FormInput',
|
|
570
572
|
props: {
|
|
573
|
+
type: 'text',
|
|
574
|
+
id: 'email',
|
|
571
575
|
name: 'email',
|
|
572
576
|
label: 'Email Address',
|
|
573
577
|
placeholder: 'Enter your email',
|
|
574
|
-
required:
|
|
578
|
+
required: 'required',
|
|
579
|
+
validate: 'email'
|
|
575
580
|
}
|
|
576
581
|
},
|
|
577
582
|
{
|
|
578
|
-
|
|
583
|
+
component: 'FormTextarea',
|
|
579
584
|
props: {
|
|
585
|
+
id: 'message',
|
|
580
586
|
name: 'message',
|
|
581
587
|
label: 'Message',
|
|
582
588
|
placeholder: 'Enter your message',
|
|
583
|
-
rows: 4
|
|
589
|
+
rows: '4',
|
|
590
|
+
required: 'required'
|
|
591
|
+
}
|
|
592
|
+
},
|
|
593
|
+
{
|
|
594
|
+
component: 'FormSelect',
|
|
595
|
+
props: {
|
|
596
|
+
id: 'category',
|
|
597
|
+
name: 'category',
|
|
598
|
+
label: 'Category',
|
|
599
|
+
options: [
|
|
600
|
+
{ text: 'General', value: 'general' },
|
|
601
|
+
{ text: 'Support', value: 'support' },
|
|
602
|
+
{ text: 'Sales', value: 'sales' }
|
|
603
|
+
]
|
|
584
604
|
}
|
|
585
605
|
}
|
|
586
606
|
]
|
|
@@ -595,36 +615,171 @@ const formConfig = {
|
|
|
595
615
|
|
|
596
616
|
#### Form Components
|
|
597
617
|
|
|
598
|
-
Individual form field components
|
|
618
|
+
Individual form field components with unified event handling and validation.
|
|
619
|
+
|
|
620
|
+
##### FormInput
|
|
621
|
+
Text input field with validation and accessibility features.
|
|
599
622
|
|
|
600
623
|
```tsx
|
|
601
|
-
import
|
|
624
|
+
import { FormInput } from '@pixelated-tech/components';
|
|
625
|
+
|
|
626
|
+
<FormInput
|
|
627
|
+
type="email"
|
|
628
|
+
id="email"
|
|
629
|
+
name="email"
|
|
630
|
+
label="Email Address"
|
|
631
|
+
placeholder="Enter your email"
|
|
632
|
+
required="required"
|
|
633
|
+
validate="email"
|
|
634
|
+
display="vertical"
|
|
635
|
+
/>
|
|
636
|
+
```
|
|
602
637
|
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
638
|
+
**Props:**
|
|
639
|
+
- `type`: Input type (text, email, password, etc.)
|
|
640
|
+
- `id`: Unique identifier
|
|
641
|
+
- `name`: Form field name
|
|
642
|
+
- `label`: Display label
|
|
643
|
+
- `placeholder`: Input placeholder text
|
|
644
|
+
- `required`: Makes field required
|
|
645
|
+
- `validate`: Validation rule name
|
|
646
|
+
- `display`: Layout mode (vertical/horizontal)
|
|
647
|
+
|
|
648
|
+
##### FormTextarea
|
|
649
|
+
Multi-line text input with validation.
|
|
650
|
+
|
|
651
|
+
```tsx
|
|
652
|
+
import { FormTextarea } from '@pixelated-tech/components';
|
|
653
|
+
|
|
654
|
+
<FormTextarea
|
|
655
|
+
id="description"
|
|
656
|
+
name="description"
|
|
657
|
+
label="Description"
|
|
658
|
+
placeholder="Enter description"
|
|
659
|
+
rows="4"
|
|
660
|
+
required="required"
|
|
661
|
+
display="vertical"
|
|
662
|
+
/>
|
|
663
|
+
```
|
|
664
|
+
|
|
665
|
+
##### FormSelect
|
|
666
|
+
Dropdown selection with option validation.
|
|
667
|
+
|
|
668
|
+
```tsx
|
|
669
|
+
import { FormSelect } from '@pixelated-tech/components';
|
|
670
|
+
|
|
671
|
+
<FormSelect
|
|
672
|
+
id="category"
|
|
673
|
+
name="category"
|
|
674
|
+
label="Category"
|
|
675
|
+
options={[
|
|
676
|
+
{ text: 'Option 1', value: 'opt1' },
|
|
677
|
+
{ text: 'Option 2', value: 'opt2' }
|
|
678
|
+
]}
|
|
679
|
+
required="required"
|
|
680
|
+
/>
|
|
626
681
|
```
|
|
627
682
|
|
|
683
|
+
##### FormRadio
|
|
684
|
+
Radio button group with validation.
|
|
685
|
+
|
|
686
|
+
```tsx
|
|
687
|
+
import { FormRadio } from '@pixelated-tech/components';
|
|
688
|
+
|
|
689
|
+
<FormRadio
|
|
690
|
+
id="choice"
|
|
691
|
+
name="choice"
|
|
692
|
+
label="Choose an option"
|
|
693
|
+
options={[
|
|
694
|
+
{ text: 'Option A', value: 'a' },
|
|
695
|
+
{ text: 'Option B', value: 'b' }
|
|
696
|
+
]}
|
|
697
|
+
required="required"
|
|
698
|
+
/>
|
|
699
|
+
```
|
|
700
|
+
|
|
701
|
+
##### FormCheckbox
|
|
702
|
+
Checkbox group with validation.
|
|
703
|
+
|
|
704
|
+
```tsx
|
|
705
|
+
import { FormCheckbox } from '@pixelated-tech/components';
|
|
706
|
+
|
|
707
|
+
<FormCheckbox
|
|
708
|
+
id="preferences"
|
|
709
|
+
name="preferences"
|
|
710
|
+
label="Preferences"
|
|
711
|
+
options={[
|
|
712
|
+
{ text: 'Email updates', value: 'email' },
|
|
713
|
+
{ text: 'SMS updates', value: 'sms' }
|
|
714
|
+
]}
|
|
715
|
+
/>
|
|
716
|
+
```
|
|
717
|
+
|
|
718
|
+
##### FormButton
|
|
719
|
+
Action button for form submission.
|
|
720
|
+
|
|
721
|
+
```tsx
|
|
722
|
+
import { FormButton } from '@pixelated-tech/components';
|
|
723
|
+
|
|
724
|
+
<FormButton
|
|
725
|
+
type="submit"
|
|
726
|
+
id="submit-btn"
|
|
727
|
+
text="Submit Form"
|
|
728
|
+
onClick={handleSubmit}
|
|
729
|
+
/>
|
|
730
|
+
```
|
|
731
|
+
|
|
732
|
+
##### FormTooltip
|
|
733
|
+
Unified tooltip and validation message component with mouseover behavior and conditional styling.
|
|
734
|
+
|
|
735
|
+
```tsx
|
|
736
|
+
import { FormTooltip } from '@pixelated-tech/components';
|
|
737
|
+
|
|
738
|
+
// Tooltip mode - displays information with black ⓘ icon
|
|
739
|
+
<FormTooltip
|
|
740
|
+
mode="tooltip"
|
|
741
|
+
text={['This field is required', 'Please enter a valid email address']}
|
|
742
|
+
/>
|
|
743
|
+
|
|
744
|
+
// Validation mode - displays errors with red ❌ icon
|
|
745
|
+
<FormTooltip
|
|
746
|
+
mode="validate"
|
|
747
|
+
text={['Email format is invalid', 'Please check your input']}
|
|
748
|
+
/>
|
|
749
|
+
```
|
|
750
|
+
|
|
751
|
+
**Props:**
|
|
752
|
+
- `mode`: Display mode ('tooltip' for info, 'validate' for errors)
|
|
753
|
+
- `text`: Array of strings to display (always use array format)
|
|
754
|
+
|
|
755
|
+
**Features:**
|
|
756
|
+
- **Conditional Icons**: ⓘ (black) for tooltips, ❌ (red) for validation errors
|
|
757
|
+
- **Mouseover Behavior**: Shows/hides content on hover for both modes
|
|
758
|
+
- **Unified Styling**: Consistent appearance with mode-based color variations
|
|
759
|
+
- **Array-Based Text**: Always accepts text as string array for consistency
|
|
760
|
+
|
|
761
|
+
#### Form Validation
|
|
762
|
+
|
|
763
|
+
Built-in validation rules available via the `validate` prop:
|
|
764
|
+
|
|
765
|
+
- `email`: Email format validation
|
|
766
|
+
- `url`: URL format validation
|
|
767
|
+
- `phone`: Phone number format
|
|
768
|
+
- `zipcode`: US zip code validation
|
|
769
|
+
- `required`: Required field validation
|
|
770
|
+
- Custom validation functions can be added to `formvalidations.tsx`
|
|
771
|
+
|
|
772
|
+
#### Recent Improvements
|
|
773
|
+
|
|
774
|
+
**Version 3.2.14+** includes major refactoring for better performance and maintainability:
|
|
775
|
+
|
|
776
|
+
- **FormTooltip Unification**: Merged FormTooltip and FormValidate into single component with mode-based rendering
|
|
777
|
+
- **Unified Event Handling**: All form components now use consistent `onChange` and `onInput` handlers for better test compatibility
|
|
778
|
+
- **Performance Optimization**: Replaced inefficient `JSON.parse/stringify` with direct object destructuring
|
|
779
|
+
- **Code Deduplication**: Custom `useFormComponent` hook eliminates repetitive validation logic
|
|
780
|
+
- **Circular Reference Prevention**: Fixed memory leaks in option generation for radio/checkbox components
|
|
781
|
+
- **Enhanced Test Coverage**: 2,244 tests passing across 67 test files with comprehensive form component coverage
|
|
782
|
+
|
|
628
783
|
### Menu
|
|
629
784
|
|
|
630
785
|
Navigation components with multiple interaction patterns.
|
|
@@ -691,6 +846,29 @@ const menuItems = [
|
|
|
691
846
|
<MenuExpando menuItems={menuItems} />
|
|
692
847
|
```
|
|
693
848
|
|
|
849
|
+
### Tab
|
|
850
|
+
|
|
851
|
+
Configurable tab component with multiple orientations and content areas.
|
|
852
|
+
|
|
853
|
+
```tsx
|
|
854
|
+
import { Tab } from '@pixelated-tech/components';
|
|
855
|
+
|
|
856
|
+
const tabs = [
|
|
857
|
+
{ id: 'tab1', label: 'Tab 1', content: <div>Content for Tab 1</div> },
|
|
858
|
+
{ id: 'tab2', label: 'Tab 2', content: <div>Content for Tab 2</div> },
|
|
859
|
+
{ id: 'tab3', label: 'Tab 3', content: <div>Content for Tab 3</div> },
|
|
860
|
+
];
|
|
861
|
+
|
|
862
|
+
<Tab tabs={tabs} orientation="top" defaultActiveTab="tab1" />
|
|
863
|
+
```
|
|
864
|
+
|
|
865
|
+
#### Props
|
|
866
|
+
|
|
867
|
+
- `tabs`: Array of tab objects with `id`, `label`, and `content`
|
|
868
|
+
- `orientation`: 'top' | 'bottom' | 'left' | 'right' (default: 'top')
|
|
869
|
+
- `defaultActiveTab`: ID of the initially active tab
|
|
870
|
+
- `onTabChange`: Callback function called when tab changes
|
|
871
|
+
|
|
694
872
|
### Tables
|
|
695
873
|
|
|
696
874
|
Data display component with sorting and image support.
|
|
@@ -874,6 +1052,87 @@ import { SaveLoadSection } from '@pixelated-tech/components';
|
|
|
874
1052
|
| `onLoad` | `function` | - | Load handler |
|
|
875
1053
|
| `onNew` | `function` | - | New page handler |
|
|
876
1054
|
|
|
1055
|
+
### ConfigBuilder
|
|
1056
|
+
|
|
1057
|
+
Tabbed interface for managing site metadata and routes configuration.
|
|
1058
|
+
|
|
1059
|
+
```tsx
|
|
1060
|
+
import { ConfigBuilder } from '@pixelated-tech/components';
|
|
1061
|
+
|
|
1062
|
+
<ConfigBuilder
|
|
1063
|
+
initialConfig={{
|
|
1064
|
+
siteInfo: { name: 'My Site', description: 'Site description' },
|
|
1065
|
+
routes: [
|
|
1066
|
+
{ path: '/home', component: 'Home', title: 'Home Page' }
|
|
1067
|
+
]
|
|
1068
|
+
}}
|
|
1069
|
+
onSave={(config) => console.log('Config saved:', config)}
|
|
1070
|
+
/>
|
|
1071
|
+
```
|
|
1072
|
+
|
|
1073
|
+
#### Props
|
|
1074
|
+
| Prop | Type | Default | Description |
|
|
1075
|
+
|------|------|---------|-------------|
|
|
1076
|
+
| `initialConfig` | `SiteConfig` | - | Initial site configuration |
|
|
1077
|
+
| `onSave` | `function` | - | Configuration save handler |
|
|
1078
|
+
|
|
1079
|
+
#### SiteConfig Type
|
|
1080
|
+
```tsx
|
|
1081
|
+
interface SiteConfig {
|
|
1082
|
+
siteInfo: {
|
|
1083
|
+
name: string;
|
|
1084
|
+
author: string;
|
|
1085
|
+
description: string;
|
|
1086
|
+
url: string;
|
|
1087
|
+
email: string;
|
|
1088
|
+
favicon: string;
|
|
1089
|
+
favicon_sizes: string;
|
|
1090
|
+
favicon_type: string;
|
|
1091
|
+
theme_color: string;
|
|
1092
|
+
background_color: string;
|
|
1093
|
+
default_locale: string;
|
|
1094
|
+
display: string;
|
|
1095
|
+
image?: string;
|
|
1096
|
+
image_height?: string;
|
|
1097
|
+
image_width?: string;
|
|
1098
|
+
telephone?: string;
|
|
1099
|
+
address?: {
|
|
1100
|
+
streetAddress: string;
|
|
1101
|
+
addressLocality: string;
|
|
1102
|
+
addressRegion: string;
|
|
1103
|
+
postalCode: string;
|
|
1104
|
+
addressCountry: string;
|
|
1105
|
+
};
|
|
1106
|
+
priceRange?: string;
|
|
1107
|
+
sameAs?: string[];
|
|
1108
|
+
keywords?: string;
|
|
1109
|
+
};
|
|
1110
|
+
routes: Array<{
|
|
1111
|
+
path: string;
|
|
1112
|
+
component: string;
|
|
1113
|
+
title?: string;
|
|
1114
|
+
description?: string;
|
|
1115
|
+
}>;
|
|
1116
|
+
}
|
|
1117
|
+
```
|
|
1118
|
+
|
|
1119
|
+
#### Features
|
|
1120
|
+
- **Tabbed Interface**: Organized into "Site Info" and "Routes" tabs
|
|
1121
|
+
- **Comprehensive Site Info Management**: Edit all standard site metadata fields including PWA settings, contact info, and address
|
|
1122
|
+
- **Route Management**: Add, edit, and remove page routes with component mapping
|
|
1123
|
+
- **Real-time Preview**: JSON preview of current configuration
|
|
1124
|
+
- **Save Functionality**: Callback-based configuration persistence with form validation enforcement
|
|
1125
|
+
- **Form Validation**: Required field validation for essential site information with visual feedback
|
|
1126
|
+
|
|
1127
|
+
#### Validation Behavior
|
|
1128
|
+
|
|
1129
|
+
The "Save Config" button enforces form validation before allowing configuration saves:
|
|
1130
|
+
|
|
1131
|
+
- **Required Fields**: Site name, author, description, URL, and email are mandatory
|
|
1132
|
+
- **Visual Feedback**: Invalid fields show validation errors with ❌ indicators
|
|
1133
|
+
- **Save Prevention**: Save action is blocked until all required validations pass
|
|
1134
|
+
- **Real-time Validation**: Form validates as you type with immediate feedback
|
|
1135
|
+
|
|
877
1136
|
---
|
|
878
1137
|
|
|
879
1138
|
## SEO & Schema
|
package/README.md
CHANGED
|
@@ -270,16 +270,16 @@ Project Link: [https://github.com/brianwhaley/pixelated-components](https://gith
|
|
|
270
270
|
|
|
271
271
|
### Overview
|
|
272
272
|
|
|
273
|
-
**Current Status**: ✅ 2,
|
|
273
|
+
**Current Status**: ✅ 2,244 tests passing across 67 test files
|
|
274
274
|
|
|
275
275
|
| Metric | Value |
|
|
276
276
|
|--------|-------|
|
|
277
|
-
| Test Files |
|
|
278
|
-
| Total Tests | 2,
|
|
279
|
-
| Coverage (Statements) |
|
|
280
|
-
| Coverage (Lines) |
|
|
281
|
-
| Coverage (Functions) |
|
|
282
|
-
| Coverage (Branches) |
|
|
277
|
+
| Test Files | 67 |
|
|
278
|
+
| Total Tests | 2,244 |
|
|
279
|
+
| Coverage (Statements) | 76.59% |
|
|
280
|
+
| Coverage (Lines) | 79.45% |
|
|
281
|
+
| Coverage (Functions) | 78.33% |
|
|
282
|
+
| Coverage (Branches) | 66.79% |
|
|
283
283
|
| Test Framework | Vitest 4.x |
|
|
284
284
|
| Testing Library | @testing-library/react + jsdom |
|
|
285
285
|
|
|
@@ -297,52 +297,60 @@ npm run test:run # Single run (for CI)
|
|
|
297
297
|
**Component Coverage Summary**
|
|
298
298
|
|
|
299
299
|
#### Component Coverage (Sorted by Statement Coverage)
|
|
300
|
+
- **tiles.tsx**: 100% statements
|
|
301
|
+
- **google.reviews.functions.ts**: 100% statements
|
|
300
302
|
- **config.server.tsx**: 100% statements
|
|
301
|
-
- **modal.tsx**: 100% statements
|
|
302
303
|
- **accordion.tsx**: 100% statements
|
|
303
|
-
- **
|
|
304
|
-
- **
|
|
305
|
-
- **formvalidations.tsx**: 100% statements
|
|
306
|
-
- **buzzwordbingo.tsx**: 100% statements
|
|
307
|
-
- **timeline.tsx**: 100% statements
|
|
308
|
-
- **markdown.tsx**: 100% statements
|
|
304
|
+
- **modal.tsx**: 100% statements
|
|
305
|
+
- **tab.tsx**: 100% statements
|
|
309
306
|
- **ComponentPropertiesForm.tsx**: 100% statements
|
|
310
307
|
- **ComponentSelector.tsx**: 100% statements
|
|
311
308
|
- **ComponentTree.tsx**: 100% statements
|
|
309
|
+
- **formvalidations.tsx**: 100% statements
|
|
310
|
+
- **componentMetadata.tsx**: 100% statements
|
|
311
|
+
- **googlesearch.tsx**: 100% statements
|
|
312
312
|
- **schema-localbusiness.tsx**: 100% statements
|
|
313
313
|
- **schema-recipe.tsx**: 100% statements
|
|
314
314
|
- **schema-services.tsx**: 100% statements
|
|
315
315
|
- **schema-website.tsx**: 100% statements
|
|
316
|
-
- **
|
|
316
|
+
- **buzzwordbingo.tsx**: 100% statements
|
|
317
|
+
- **markdown.tsx**: 100% statements
|
|
318
|
+
- **timeline.tsx**: 100% statements
|
|
317
319
|
- **sidepanel.tsx**: 97.5% statements
|
|
318
320
|
- **config.ts**: 96.55% statements
|
|
319
321
|
- **google.reviews.components.tsx**: 95.83% statements
|
|
320
|
-
- **schema-blogposting.tsx**: 95.
|
|
322
|
+
- **schema-blogposting.tsx**: 95.24% statements
|
|
321
323
|
- **recipe.tsx**: 94.59% statements
|
|
322
324
|
- **resume.tsx**: 94.38% statements
|
|
323
325
|
- **contentful.delivery.ts**: 92.5% statements
|
|
324
|
-
- **css.tsx**: 91.
|
|
325
|
-
- **functions.ts**: 90.
|
|
326
|
-
- **config.client.tsx**: 90% statements
|
|
326
|
+
- **css.tsx**: 91.43% statements
|
|
327
|
+
- **functions.ts**: 90.91% statements
|
|
327
328
|
- **menu-expando.tsx**: 90.12% statements
|
|
329
|
+
- **config.client.tsx**: 90% statements
|
|
330
|
+
- **loading.tsx**: 85.71% statements
|
|
331
|
+
- **SaveLoadSection.tsx**: 84.85% statements
|
|
332
|
+
- **table.tsx**: 84.48% statements
|
|
333
|
+
- **ConfigBuilder.tsx**: 83.52% statements
|
|
328
334
|
- **cloudinary.ts**: 83.33% statements
|
|
335
|
+
- **formcomponents.tsx**: 83.33% statements
|
|
329
336
|
- **form.tsx**: 83.2% statements
|
|
330
|
-
- **shoppingcart.functions.ts**: 81.
|
|
337
|
+
- **shoppingcart.functions.ts**: 81.7% statements
|
|
331
338
|
- **callout.tsx**: 80% statements
|
|
332
339
|
- **microinteractions.tsx**: 80% statements
|
|
333
|
-
- **
|
|
340
|
+
- **cloudinary.image.tsx**: 78.57% statements
|
|
341
|
+
- **sitemap.ts**: 76.06% statements
|
|
334
342
|
- **manifest.tsx**: 75% statements
|
|
335
|
-
- **carousel.tsx**: 71.
|
|
343
|
+
- **carousel.tsx**: 71.7% statements
|
|
336
344
|
- **nerdjoke.tsx**: 69.44% statements
|
|
337
345
|
- **menu-accordion.tsx**: 68.13% statements
|
|
338
346
|
- **semantic.tsx**: 63.51% statements
|
|
339
|
-
- **
|
|
347
|
+
- **componentMap.tsx**: 60% statements
|
|
348
|
+
- **propTypeIntrospection.tsx**: 60% statements
|
|
349
|
+
- **wordpress.functions.ts**: 51.43% statements
|
|
340
350
|
- **PageEngine.tsx**: 48% statements
|
|
341
|
-
- **
|
|
342
|
-
- **
|
|
343
|
-
- **
|
|
344
|
-
- **socialcard.tsx**: 29.5% statements
|
|
345
|
-
- **PageBuilderUI.tsx**: 26.66% statements
|
|
351
|
+
- **componentGeneration.tsx**: 38.89% statements
|
|
352
|
+
- **socialcard.tsx**: 29.51% statements
|
|
353
|
+
- **PageBuilderUI.tsx**: 26.67% statements
|
|
346
354
|
|
|
347
355
|
### Testing Next Steps
|
|
348
356
|
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/* Tab Component Styles */
|
|
2
|
+
|
|
3
|
+
.tab-container {
|
|
4
|
+
display: flex;
|
|
5
|
+
border: 1px solid #ddd;
|
|
6
|
+
border-radius: 4px;
|
|
7
|
+
overflow: hidden;
|
|
8
|
+
height: 100%;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
.tab-top {
|
|
12
|
+
flex-direction: column;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.tab-bottom {
|
|
16
|
+
flex-direction: column-reverse;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.tab-left {
|
|
20
|
+
flex-direction: row;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.tab-right {
|
|
24
|
+
flex-direction: row-reverse;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.tab-headers {
|
|
28
|
+
display: flex;
|
|
29
|
+
background-color: #f5f5f5;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.tab-top .tab-headers,
|
|
33
|
+
.tab-bottom .tab-headers {
|
|
34
|
+
flex-direction: row;
|
|
35
|
+
width: 100%;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.tab-left .tab-headers,
|
|
39
|
+
.tab-right .tab-headers {
|
|
40
|
+
flex-direction: column;
|
|
41
|
+
height: 100%;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.tab-header {
|
|
45
|
+
padding: 10px 20px;
|
|
46
|
+
border: none;
|
|
47
|
+
background: none;
|
|
48
|
+
cursor: pointer;
|
|
49
|
+
transition: background-color 0.3s;
|
|
50
|
+
white-space: nowrap;
|
|
51
|
+
flex-shrink: 0;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.tab-top .tab-header,
|
|
55
|
+
.tab-bottom .tab-header {
|
|
56
|
+
border-right: 1px solid #ddd;
|
|
57
|
+
border-bottom: none;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.tab-left .tab-header,
|
|
61
|
+
.tab-right .tab-header {
|
|
62
|
+
border-right: none;
|
|
63
|
+
border-bottom: 1px solid #ddd;
|
|
64
|
+
height: auto;
|
|
65
|
+
padding: 20px 10px;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.tab-left .tab-header {
|
|
69
|
+
transform: rotate(-90deg);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.tab-right .tab-header {
|
|
73
|
+
transform: rotate(90deg);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.tab-header:last-child {
|
|
77
|
+
border-right: none;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.tab-top .tab-header:last-child,
|
|
81
|
+
.tab-bottom .tab-header:last-child {
|
|
82
|
+
border-right: none;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.tab-left .tab-header:last-child,
|
|
86
|
+
.tab-right .tab-header:last-child {
|
|
87
|
+
border-bottom: none;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.tab-header:hover {
|
|
91
|
+
background-color: #e0e0e0;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.tab-header.active {
|
|
95
|
+
background-color: #fff;
|
|
96
|
+
font-weight: bold;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.tab-content {
|
|
100
|
+
flex: 1;
|
|
101
|
+
padding: 20px;
|
|
102
|
+
background-color: #fff;
|
|
103
|
+
min-height: 200px;
|
|
104
|
+
overflow: auto;
|
|
105
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from 'react';
|
|
3
|
+
import PropTypes from 'prop-types';
|
|
4
|
+
import './tab.css';
|
|
5
|
+
const TabItemPropTypes = {
|
|
6
|
+
id: PropTypes.string.isRequired,
|
|
7
|
+
label: PropTypes.string.isRequired, //
|
|
8
|
+
content: PropTypes.node.isRequired,
|
|
9
|
+
};
|
|
10
|
+
// type TabItemType = InferProps<typeof TabItemPropTypes>;
|
|
11
|
+
Tab.propTypes = {
|
|
12
|
+
tabs: PropTypes.arrayOf(PropTypes.shape(TabItemPropTypes).isRequired).isRequired,
|
|
13
|
+
orientation: PropTypes.oneOf(['top', 'bottom', 'left', 'right']),
|
|
14
|
+
defaultActiveTab: PropTypes.string,
|
|
15
|
+
onTabChange: PropTypes.func,
|
|
16
|
+
};
|
|
17
|
+
export function Tab({ tabs, orientation = 'top', defaultActiveTab, onTabChange }) {
|
|
18
|
+
const [activeTab, setActiveTab] = useState(defaultActiveTab || tabs[0]?.id || '');
|
|
19
|
+
const handleTabClick = (tabId) => {
|
|
20
|
+
setActiveTab(tabId);
|
|
21
|
+
onTabChange?.(tabId);
|
|
22
|
+
};
|
|
23
|
+
const activeContent = tabs.find(tab => tab.id === activeTab)?.content;
|
|
24
|
+
const tabClass = `tab-container tab-${orientation}`;
|
|
25
|
+
return (_jsxs("div", { className: tabClass, children: [_jsx("div", { className: "tab-headers", children: tabs.map(tab => (_jsx("button", { className: `tab-header ${activeTab === tab.id ? 'active' : ''}`, onClick: () => handleTabClick(tab.id), children: tab.label }, tab.id))) }), _jsx("div", { className: "tab-content", children: activeContent })] }));
|
|
26
|
+
}
|
|
@@ -1,23 +1,4 @@
|
|
|
1
|
-
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
1
|
import PropTypes from "prop-types";
|
|
3
|
-
// https://gist.github.com/whitingx/3840905
|
|
4
|
-
generateMetaTags.propTypes = {
|
|
5
|
-
title: PropTypes.string.isRequired,
|
|
6
|
-
description: PropTypes.string.isRequired,
|
|
7
|
-
keywords: PropTypes.string.isRequired,
|
|
8
|
-
site_name: PropTypes.string.isRequired,
|
|
9
|
-
email: PropTypes.string.isRequired,
|
|
10
|
-
origin: PropTypes.string.isRequired,
|
|
11
|
-
url: PropTypes.string.isRequired,
|
|
12
|
-
image: PropTypes.string.isRequired,
|
|
13
|
-
image_height: PropTypes.string.isRequired,
|
|
14
|
-
image_width: PropTypes.string.isRequired,
|
|
15
|
-
favicon: PropTypes.string.isRequired,
|
|
16
|
-
};
|
|
17
|
-
export function generateMetaTags(props) {
|
|
18
|
-
const { title, description, keywords, site_name, email, origin, url, image, image_height, image_width, favicon } = props;
|
|
19
|
-
return (_jsxs(_Fragment, { children: [_jsx("title", { children: title }), _jsx("meta", { charSet: "UTF-8" }), _jsx("meta", { httpEquiv: "content-type", content: "text/html; charset=UTF-8" }), _jsx("meta", { httpEquiv: 'Expires', content: '0' }), _jsx("meta", { httpEquiv: 'Pragma', content: 'no-cache' }), _jsx("meta", { httpEquiv: 'Cache-Control', content: 'no-cache' }), _jsx("meta", { name: "application-name", content: site_name }), _jsx("meta", { name: "author", content: site_name + ", " + email }), _jsx("meta", { name: 'copyright', content: site_name }), _jsx("meta", { name: "creator", content: site_name }), _jsx("meta", { name: "description", content: description }), _jsx("meta", { name: "keywords", content: keywords }), _jsx("meta", { name: 'language', content: 'EN' }), _jsx("meta", { name: 'owner', content: site_name }), _jsx("meta", { name: "publisher", content: site_name }), _jsx("meta", { name: 'rating', content: 'General' }), _jsx("meta", { name: 'reply-to', content: email }), _jsx("meta", { name: "robots", content: "index, follow" }), _jsx("meta", { name: 'url', content: url }), _jsx("meta", { name: "viewport", content: "width=device-width, initial-scale=1.0, shrink-to-fit=no" }), _jsx("meta", { property: "og:description", content: description }), _jsx("meta", { property: 'og:email', content: email }), _jsx("meta", { property: "og:image", content: image }), _jsx("meta", { property: "og:image:height", content: image_height }), _jsx("meta", { property: "og:image:width", content: image_width }), _jsx("meta", { property: "og:locale", content: "en_US" }), _jsx("meta", { property: "og:site_name", content: site_name }), _jsx("meta", { property: "og:title", content: title }), _jsx("meta", { property: "og:type", content: "website" }), _jsx("meta", { property: "og:url", content: url }), _jsx("meta", { itemProp: "name", content: site_name }), _jsx("meta", { itemProp: "url", content: url }), _jsx("meta", { itemProp: "description", content: description }), _jsx("meta", { itemProp: "thumbnailUrl", content: image }), _jsx("meta", { property: "twitter:domain", content: new URL(origin).hostname }), _jsx("meta", { property: "twitter:url", content: url }), _jsx("meta", { name: "twitter:card", content: "summary_large_image" }), _jsx("meta", { name: "twitter:creator", content: site_name }), _jsx("meta", { name: "twitter:description", content: description }), _jsx("meta", { name: "twitter:image", content: image }), _jsx("meta", { name: "twitter:image:height", content: image_height }), _jsx("meta", { name: "twitter:image:width", content: image_width }), _jsx("meta", { name: "twitter:title", content: title }), _jsx("link", { rel: "author", href: origin }), _jsx("link", { rel: "canonical", href: url }), _jsx("link", { rel: "icon", type: "image/x-icon", href: favicon }), _jsx("link", { rel: "shortcut icon", type: "image/x-icon", href: favicon }), _jsx("link", { rel: "manifest", href: "/manifest.webmanifest" }), _jsx("link", { rel: "preconnect", href: "https://images.ctfassets.net/" }), _jsx("link", { rel: "preconnect", href: "https://res.cloudinary.com/" }), _jsx("link", { rel: "preconnect", href: "https://farm2.static.flickr.com" }), _jsx("link", { rel: "preconnect", href: "https://farm6.static.flickr.com" }), _jsx("link", { rel: "preconnect", href: "https://farm8.static.flickr.com" }), _jsx("link", { rel: "preconnect", href: "https://farm66.static.flickr.com" })] }));
|
|
20
|
-
}
|
|
21
2
|
setClientMetadata.propTypes = {
|
|
22
3
|
title: PropTypes.string.isRequired,
|
|
23
4
|
description: PropTypes.string.isRequired,
|