@plusscommunities/pluss-feature-builder-web-a 1.0.2-beta.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/.babelrc +4 -0
- package/dist/index.cjs.js +7792 -0
- package/package.json +54 -0
- package/rollup.config.js +68 -0
- package/src/actions/featureBuilderStringsActions.js +88 -0
- package/src/actions/featureDefinitionsIndex.js +258 -0
- package/src/actions/formActions.js +311 -0
- package/src/actions/index.js +12 -0
- package/src/actions/listingActions.js +350 -0
- package/src/actions/wizardActions.js +240 -0
- package/src/components/ActivityCardExample.jsx +86 -0
- package/src/components/ActivityCardExample.module.css +130 -0
- package/src/components/BackgroundLoader.jsx +33 -0
- package/src/components/BackgroundLoader.module.css +46 -0
- package/src/components/BaseFieldConfig.jsx +305 -0
- package/src/components/BaseFieldConfig.module.css +42 -0
- package/src/components/CenteredContainer.jsx +29 -0
- package/src/components/CenteredContainer.module.css +171 -0
- package/src/components/DeleteConfirmationPopup.jsx +95 -0
- package/src/components/DeleteConfirmationPopup.module.css +12 -0
- package/src/components/ErrorBoundary.jsx +134 -0
- package/src/components/ErrorBoundary.module.css +77 -0
- package/src/components/ErrorMessage.jsx +85 -0
- package/src/components/ErrorMessage.module.css +116 -0
- package/src/components/ExampleDisplay.jsx +26 -0
- package/src/components/ExampleDisplay.module.css +3 -0
- package/src/components/FeatureBuilderSidebar.jsx +84 -0
- package/src/components/FeatureBuilderSuccessPopup.jsx +55 -0
- package/src/components/FeatureBuilderSuccessPopup.module.css +43 -0
- package/src/components/FeatureBuilderWelcomePopup.jsx +51 -0
- package/src/components/FeatureBuilderWelcomePopup.module.css +21 -0
- package/src/components/FeatureListingCard.jsx +104 -0
- package/src/components/FeatureListingCard.module.css +62 -0
- package/src/components/Fields.jsx +460 -0
- package/src/components/Fields.module.css +159 -0
- package/src/components/IconLoader.jsx +153 -0
- package/src/components/IconLoader.module.css +92 -0
- package/src/components/IconSelector.jsx +112 -0
- package/src/components/IconSelector.module.css +197 -0
- package/src/components/ListingEditor.jsx +406 -0
- package/src/components/ListingEditor.module.css +14 -0
- package/src/components/ListingSuccessPopup.jsx +52 -0
- package/src/components/LoadingScreen.jsx +54 -0
- package/src/components/LoadingScreen.module.css +103 -0
- package/src/components/LoadingState.jsx +40 -0
- package/src/components/LoadingState.module.css +18 -0
- package/src/components/PreviewFull.js +24 -0
- package/src/components/PreviewFull.module.css +11 -0
- package/src/components/PreviewGrid.js +14 -0
- package/src/components/PreviewWidget.js +27 -0
- package/src/components/PreviewWidget.module.css +15 -0
- package/src/components/SidebarLayout.jsx +292 -0
- package/src/components/SidebarLayout.module.css +145 -0
- package/src/components/SkeletonLoader.jsx +128 -0
- package/src/components/SkeletonLoader.module.css +295 -0
- package/src/components/SortButtonGroup.jsx +34 -0
- package/src/components/SortButtonGroup.module.css +51 -0
- package/src/components/ToastContainer.jsx +98 -0
- package/src/components/ToastContainer.module.css +156 -0
- package/src/components/ToggleSwitch.js +40 -0
- package/src/components/ToggleSwitch.module.css +48 -0
- package/src/components/TwoColumnInput.jsx +29 -0
- package/src/components/TwoColumnInput.module.css +32 -0
- package/src/components/ViewFull.js +139 -0
- package/src/components/ViewFull.module.css +71 -0
- package/src/components/ViewWidget.js +62 -0
- package/src/components/ViewWidget.module.css +28 -0
- package/src/components/iconCategories.js +135 -0
- package/src/components/iconImports.js +409 -0
- package/src/components/index.js +61 -0
- package/src/components/listing/FileListItem.jsx +86 -0
- package/src/components/listing/GalleryDisplay.jsx +331 -0
- package/src/components/listing/GalleryDisplay.module.css +309 -0
- package/src/components/listing/ListingCTAInput.jsx +82 -0
- package/src/components/listing/ListingDescriptionInput.jsx +73 -0
- package/src/components/listing/ListingField.jsx +101 -0
- package/src/components/listing/ListingField.module.css +106 -0
- package/src/components/listing/ListingFileInput.jsx +255 -0
- package/src/components/listing/ListingFileInput.module.css +192 -0
- package/src/components/listing/ListingForm.jsx +90 -0
- package/src/components/listing/ListingForm.module.css +38 -0
- package/src/components/listing/ListingGalleryInput.jsx +236 -0
- package/src/components/listing/ListingGalleryInput.module.css +131 -0
- package/src/components/listing/ListingImageInput.jsx +153 -0
- package/src/components/listing/ListingTextInput.jsx +72 -0
- package/src/feature.config.js +130 -0
- package/src/helper/index.js +135 -0
- package/src/hooks/useFeatureDefinitionLoader.js +62 -0
- package/src/images/full.png +0 -0
- package/src/images/fullNoTitle.png +0 -0
- package/src/images/previewWidget.png +0 -0
- package/src/images/widget.png +0 -0
- package/src/index.js +38 -0
- package/src/pages/CreateListingPage.jsx +49 -0
- package/src/pages/EditListingPage.jsx +58 -0
- package/src/reducers/featureBuilderReducer.js +744 -0
- package/src/screens/CreateListing.module.css +45 -0
- package/src/screens/Form.module.css +734 -0
- package/src/screens/FormFieldsStep.jsx +689 -0
- package/src/screens/FormLayoutStep.jsx +445 -0
- package/src/screens/FormOverviewStep.jsx +396 -0
- package/src/screens/ListingScreen.jsx +478 -0
- package/src/screens/ListingScreen.module.css +333 -0
- package/src/selectors/featureBuilderSelectors.js +529 -0
- package/src/types/index.js +91 -0
- package/src/utils/textUtils.js +89 -0
- package/src/validators/galleryValidators.js +345 -0
- package/src/values.config.a.js +49 -0
- package/src/values.config.b.js +49 -0
- package/src/values.config.c.js +49 -0
- package/src/values.config.d.js +49 -0
- package/src/values.config.js +49 -0
- package/src/webapi/featureDefinitionActions.js +0 -0
- package/src/webapi/featuresActions.js +90 -0
- package/src/webapi/helper.js +4 -0
- package/src/webapi/index.js +12 -0
- package/src/webapi/listingActions.js +176 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import styles from "./TwoColumnInput.module.css";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Two Column Input layout component
|
|
6
|
+
* Renders form inputs in a side-by-side layout with proper spacing and styling
|
|
7
|
+
* Commonly used for label/placeholder pairs or related input fields
|
|
8
|
+
*
|
|
9
|
+
* @param {Object} props - Component props
|
|
10
|
+
* @param {React.ReactNode} props.left - Content for the left column (typically a form input)
|
|
11
|
+
* @param {React.ReactNode} props.right - Content for the right column (typically a form input)
|
|
12
|
+
* @param {boolean} [props.leftRequired=false] - Whether left column content is required
|
|
13
|
+
* @returns {React.ReactElement} Two-column layout wrapper
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* <TwoColumnInput
|
|
17
|
+
* left={<GenericInput label="First Name" />}
|
|
18
|
+
* right={<GenericInput label="Last Name" />}
|
|
19
|
+
* leftRequired={true}
|
|
20
|
+
* />
|
|
21
|
+
*/
|
|
22
|
+
export const TwoColumnInput = ({ left, right, leftRequired = false }) => {
|
|
23
|
+
return (
|
|
24
|
+
<div className={styles.twoColumnInput}>
|
|
25
|
+
<div className={`${styles.column} ${styles.leftColumn}`}>{left}</div>
|
|
26
|
+
<div className={`${styles.column} ${styles.rightColumn}`}>{right}</div>
|
|
27
|
+
</div>
|
|
28
|
+
);
|
|
29
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/* TwoColumnInput BEM CSS Module */
|
|
2
|
+
|
|
3
|
+
.twoColumnInput {
|
|
4
|
+
display: flex;
|
|
5
|
+
gap: 20px;
|
|
6
|
+
align-items: center;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
.column {
|
|
10
|
+
flex: 1;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.leftColumn {
|
|
14
|
+
flex: 1.2; /* Slightly wider for required label */
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.rightColumn {
|
|
18
|
+
flex: 1;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/* Responsive adjustments */
|
|
22
|
+
@media (max-width: 768px) {
|
|
23
|
+
.twoColumnInput {
|
|
24
|
+
flex-direction: column;
|
|
25
|
+
gap: 12px;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.leftColumn,
|
|
29
|
+
.rightColumn {
|
|
30
|
+
flex: 1;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { PlussCore } from "../feature.config";
|
|
3
|
+
const { Text, Button } = PlussCore.Components;
|
|
4
|
+
import full from "../images/full.png";
|
|
5
|
+
import styles from "./ViewFull.module.css";
|
|
6
|
+
|
|
7
|
+
const ViewFull = ({ listing }) => {
|
|
8
|
+
// If no listing data provided, show placeholder
|
|
9
|
+
if (!listing || !listing.fields) {
|
|
10
|
+
return <img className={styles.viewFull__image} src={full} alt="full" />;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// Get the title field
|
|
14
|
+
const title = listing.fields["mandatory-title"] || "Untitled";
|
|
15
|
+
|
|
16
|
+
// Find all CTA fields
|
|
17
|
+
const ctaFields = Object.keys(listing.fields).filter((fieldId) => {
|
|
18
|
+
const fieldValue = listing.fields[fieldId];
|
|
19
|
+
return (
|
|
20
|
+
fieldValue &&
|
|
21
|
+
typeof fieldValue === "object" &&
|
|
22
|
+
fieldValue.label &&
|
|
23
|
+
fieldValue.url
|
|
24
|
+
);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
// Find all text fields
|
|
28
|
+
const textFields = Object.keys(listing.fields)
|
|
29
|
+
.filter((fieldId) => {
|
|
30
|
+
const fieldValue = listing.fields[fieldId];
|
|
31
|
+
return typeof fieldValue === "string" && fieldValue.length > 0;
|
|
32
|
+
})
|
|
33
|
+
.filter((fieldId) => fieldId !== "mandatory-title"); // Exclude title field
|
|
34
|
+
|
|
35
|
+
// Find all image fields
|
|
36
|
+
const imageFields = Object.keys(listing.fields).filter((fieldId) => {
|
|
37
|
+
const fieldValue = listing.fields[fieldId];
|
|
38
|
+
return typeof fieldValue === "string" && fieldValue.startsWith("https://");
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
// Find all file fields
|
|
42
|
+
const fileFields = Object.keys(listing.fields).filter((fieldId) => {
|
|
43
|
+
const fieldValue = listing.fields[fieldId];
|
|
44
|
+
// Handle both single file object and array of files
|
|
45
|
+
if (Array.isArray(fieldValue)) {
|
|
46
|
+
return fieldValue.length > 0 && fieldValue.some((f) => f.url && !f.label);
|
|
47
|
+
} else if (fieldValue && typeof fieldValue === "object") {
|
|
48
|
+
return fieldValue.url && !fieldValue.label; // Not a CTA field (CTA has both url and label)
|
|
49
|
+
}
|
|
50
|
+
return false;
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
// Helper function to normalize file data
|
|
54
|
+
const normalizeFiles = (fileData) => {
|
|
55
|
+
if (Array.isArray(fileData)) {
|
|
56
|
+
return fileData.filter((f) => f && f.url && !f.label);
|
|
57
|
+
} else if (
|
|
58
|
+
fileData &&
|
|
59
|
+
typeof fileData === "object" &&
|
|
60
|
+
fileData.url &&
|
|
61
|
+
!fileData.label
|
|
62
|
+
) {
|
|
63
|
+
return [fileData];
|
|
64
|
+
}
|
|
65
|
+
return [];
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
return (
|
|
69
|
+
<div className={styles.viewFull}>
|
|
70
|
+
{/* Title */}
|
|
71
|
+
<Text type="h2" className={styles.viewFull__title}>
|
|
72
|
+
{title}
|
|
73
|
+
</Text>
|
|
74
|
+
|
|
75
|
+
{/* Image fields */}
|
|
76
|
+
{imageFields.map((fieldId) => (
|
|
77
|
+
<div key={fieldId} className={styles.viewFull__imageContainer}>
|
|
78
|
+
<img
|
|
79
|
+
src={listing.fields[fieldId]}
|
|
80
|
+
alt={fieldId}
|
|
81
|
+
className={styles.viewFull__imageField}
|
|
82
|
+
/>
|
|
83
|
+
</div>
|
|
84
|
+
))}
|
|
85
|
+
|
|
86
|
+
{/* Text fields */}
|
|
87
|
+
{textFields.map((fieldId) => (
|
|
88
|
+
<Text key={fieldId} type="body" className={styles.viewFull__textField}>
|
|
89
|
+
{listing.fields[fieldId]}
|
|
90
|
+
</Text>
|
|
91
|
+
))}
|
|
92
|
+
|
|
93
|
+
{/* File fields */}
|
|
94
|
+
{fileFields.map((fieldId) => {
|
|
95
|
+
const files = normalizeFiles(listing.fields[fieldId]);
|
|
96
|
+
return (
|
|
97
|
+
<div key={fieldId} className={styles.viewFull__fileSection}>
|
|
98
|
+
{files.map((file, index) => (
|
|
99
|
+
<div
|
|
100
|
+
key={`${fieldId}-${index}`}
|
|
101
|
+
className={styles.viewFull__fileItem}
|
|
102
|
+
>
|
|
103
|
+
<a
|
|
104
|
+
href={file.url}
|
|
105
|
+
target="_blank"
|
|
106
|
+
rel="noopener noreferrer"
|
|
107
|
+
className={styles.viewFull__fileLink}
|
|
108
|
+
>
|
|
109
|
+
<Text type="body" className={styles.viewFull__fileName}>
|
|
110
|
+
{file.name || file.originalName}
|
|
111
|
+
</Text>
|
|
112
|
+
</a>
|
|
113
|
+
</div>
|
|
114
|
+
))}
|
|
115
|
+
</div>
|
|
116
|
+
);
|
|
117
|
+
})}
|
|
118
|
+
|
|
119
|
+
{/* CTA fields */}
|
|
120
|
+
{ctaFields.map((fieldId) => {
|
|
121
|
+
const ctaField = listing.fields[fieldId];
|
|
122
|
+
return (
|
|
123
|
+
<Button
|
|
124
|
+
key={fieldId}
|
|
125
|
+
buttonType="primary"
|
|
126
|
+
onClick={() => {
|
|
127
|
+
window.open(ctaField.url, "_blank", "noopener,noreferrer");
|
|
128
|
+
}}
|
|
129
|
+
className={styles.viewFull__ctaButton}
|
|
130
|
+
>
|
|
131
|
+
{ctaField.label}
|
|
132
|
+
</Button>
|
|
133
|
+
);
|
|
134
|
+
})}
|
|
135
|
+
</div>
|
|
136
|
+
);
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
export default ViewFull;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/* ViewFull BEM CSS Module */
|
|
2
|
+
|
|
3
|
+
/* Block */
|
|
4
|
+
.viewFull {
|
|
5
|
+
padding: 20px;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/* Elements */
|
|
9
|
+
.viewFull__image {
|
|
10
|
+
width: 100%;
|
|
11
|
+
height: 100%;
|
|
12
|
+
object-fit: contain;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.viewFull__title {
|
|
16
|
+
margin-bottom: 20px;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.viewFull__imageContainer {
|
|
20
|
+
margin-bottom: 20px;
|
|
21
|
+
text-align: center;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.viewFull__imageField {
|
|
25
|
+
max-width: 100%;
|
|
26
|
+
max-height: 300px;
|
|
27
|
+
object-fit: contain;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.viewFull__textField {
|
|
31
|
+
margin-bottom: 12px;
|
|
32
|
+
line-height: 1.4;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.viewFull__fileSection {
|
|
36
|
+
margin-bottom: 20px;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.viewFull__fileItem {
|
|
40
|
+
margin-bottom: 8px;
|
|
41
|
+
padding: 12px;
|
|
42
|
+
border: 1px solid var(--border-line-grey);
|
|
43
|
+
border-radius: 4px;
|
|
44
|
+
background-color: #fff;
|
|
45
|
+
transition: all 0.2s ease-in-out;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.viewFull__fileItem:hover {
|
|
49
|
+
border-color: var(--colour-branding-action);
|
|
50
|
+
box-shadow: 0 0 4px var(--colour-branding-action-alpha20);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.viewFull__fileLink {
|
|
54
|
+
text-decoration: none;
|
|
55
|
+
color: var(--text-dark);
|
|
56
|
+
display: flex;
|
|
57
|
+
align-items: center;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.viewFull__fileLink:hover {
|
|
61
|
+
color: var(--colour-branding-action);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.viewFull__fileName {
|
|
65
|
+
font-weight: 500;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.viewFull__ctaButton {
|
|
69
|
+
margin-top: 20px;
|
|
70
|
+
margin-right: 10px;
|
|
71
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { PlussCore } from "../feature.config";
|
|
3
|
+
const { Text, Button } = PlussCore.Components;
|
|
4
|
+
import widget from "../images/widget.png";
|
|
5
|
+
import styles from "./ViewWidget.module.css";
|
|
6
|
+
|
|
7
|
+
const ViewWidget = ({ listing }) => {
|
|
8
|
+
// If no listing data provided, show placeholder
|
|
9
|
+
if (!listing || !listing.fields) {
|
|
10
|
+
return <img className={styles.image} src={widget} alt="widget" />;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// Get the title field
|
|
14
|
+
const title = listing.fields["mandatory-title"] || "Untitled";
|
|
15
|
+
|
|
16
|
+
// Find all CTA fields and render the first one
|
|
17
|
+
const ctaFields = Object.keys(listing.fields).filter((fieldId) => {
|
|
18
|
+
// Check if field value has label and url (CTA structure)
|
|
19
|
+
const fieldValue = listing.fields[fieldId];
|
|
20
|
+
return (
|
|
21
|
+
fieldValue &&
|
|
22
|
+
typeof fieldValue === "object" &&
|
|
23
|
+
fieldValue.label &&
|
|
24
|
+
fieldValue.url
|
|
25
|
+
);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
// If no CTA fields, just show title
|
|
29
|
+
if (ctaFields.length === 0) {
|
|
30
|
+
return (
|
|
31
|
+
<div className={styles.root}>
|
|
32
|
+
<Text type="body" className={styles.title}>
|
|
33
|
+
{title}
|
|
34
|
+
</Text>
|
|
35
|
+
</div>
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Render CTA button
|
|
40
|
+
const ctaFieldId = ctaFields[0];
|
|
41
|
+
const ctaField = listing.fields[ctaFieldId];
|
|
42
|
+
|
|
43
|
+
return (
|
|
44
|
+
<div className={styles.root}>
|
|
45
|
+
<Text type="body" className={styles.title}>
|
|
46
|
+
{title}
|
|
47
|
+
</Text>
|
|
48
|
+
<Button
|
|
49
|
+
buttonType="primary"
|
|
50
|
+
onClick={() => {
|
|
51
|
+
// Open URL in new window
|
|
52
|
+
window.open(ctaField.url, "_blank", "noopener,noreferrer");
|
|
53
|
+
}}
|
|
54
|
+
className={styles.ctaButton}
|
|
55
|
+
>
|
|
56
|
+
{ctaField.label}
|
|
57
|
+
</Button>
|
|
58
|
+
</div>
|
|
59
|
+
);
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
export default ViewWidget;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/* ViewWidget CSS Module */
|
|
2
|
+
|
|
3
|
+
/* Block */
|
|
4
|
+
.root {
|
|
5
|
+
padding: 8px;
|
|
6
|
+
text-align: center;
|
|
7
|
+
min-height: 80px;
|
|
8
|
+
display: flex;
|
|
9
|
+
flex-direction: column;
|
|
10
|
+
justify-content: center;
|
|
11
|
+
align-items: center;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/* Elements */
|
|
15
|
+
.image {
|
|
16
|
+
width: 80px;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.title {
|
|
20
|
+
font-size: 12px;
|
|
21
|
+
margin-bottom: 8px;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.ctaButton {
|
|
25
|
+
font-size: 11px;
|
|
26
|
+
padding: 4px 8px;
|
|
27
|
+
min-width: auto;
|
|
28
|
+
}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Icon categories and definitions for the feature builder
|
|
3
|
+
* Curated for retirement village community management
|
|
4
|
+
* All icons are compatible with Font Awesome 6.4.0 (plugin) and 4.7.0 (main app)
|
|
5
|
+
*/
|
|
6
|
+
export const iconCategories = [
|
|
7
|
+
{
|
|
8
|
+
name: "Community & Living",
|
|
9
|
+
icons: [
|
|
10
|
+
"home",
|
|
11
|
+
"users",
|
|
12
|
+
"user",
|
|
13
|
+
"heart",
|
|
14
|
+
"star",
|
|
15
|
+
"flag",
|
|
16
|
+
"hands-helping",
|
|
17
|
+
"handshake",
|
|
18
|
+
"people-carry",
|
|
19
|
+
"child",
|
|
20
|
+
],
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
name: "Household & Comfort",
|
|
24
|
+
icons: [
|
|
25
|
+
"couch",
|
|
26
|
+
"bed",
|
|
27
|
+
"tv",
|
|
28
|
+
"bath",
|
|
29
|
+
"shower",
|
|
30
|
+
"toilet",
|
|
31
|
+
"sink",
|
|
32
|
+
"chair",
|
|
33
|
+
"table",
|
|
34
|
+
"fire",
|
|
35
|
+
"fan",
|
|
36
|
+
"temperature-high",
|
|
37
|
+
],
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
name: "Health & Wellness",
|
|
41
|
+
icons: [
|
|
42
|
+
"shield",
|
|
43
|
+
"heart",
|
|
44
|
+
"user-nurse",
|
|
45
|
+
"stethoscope",
|
|
46
|
+
"heart-pulse",
|
|
47
|
+
"wheelchair",
|
|
48
|
+
"crutch",
|
|
49
|
+
"prescription-bottle",
|
|
50
|
+
"pills",
|
|
51
|
+
"syringe",
|
|
52
|
+
"thermometer",
|
|
53
|
+
],
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
name: "Activities & Events",
|
|
57
|
+
icons: [
|
|
58
|
+
"calendar",
|
|
59
|
+
"clock",
|
|
60
|
+
"bell",
|
|
61
|
+
"music",
|
|
62
|
+
"book",
|
|
63
|
+
"image",
|
|
64
|
+
"camera",
|
|
65
|
+
"chess",
|
|
66
|
+
"dice",
|
|
67
|
+
"theater-masks",
|
|
68
|
+
"palette",
|
|
69
|
+
"graduation-cap",
|
|
70
|
+
"trophy",
|
|
71
|
+
],
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
name: "Sports & Recreation",
|
|
75
|
+
icons: [
|
|
76
|
+
"basketball-ball",
|
|
77
|
+
"football-ball",
|
|
78
|
+
"volleyball-ball",
|
|
79
|
+
"table-tennis",
|
|
80
|
+
"bowling-ball",
|
|
81
|
+
"swimming-pool",
|
|
82
|
+
"bicycle",
|
|
83
|
+
"walking",
|
|
84
|
+
"hiking",
|
|
85
|
+
"umbrella-beach",
|
|
86
|
+
],
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
name: "Dining & Food",
|
|
90
|
+
icons: [
|
|
91
|
+
"utensils",
|
|
92
|
+
"coffee",
|
|
93
|
+
"wine-glass",
|
|
94
|
+
"glass-water",
|
|
95
|
+
"pizza-slice",
|
|
96
|
+
"apple-alt",
|
|
97
|
+
"carrot",
|
|
98
|
+
"bread-slice",
|
|
99
|
+
"ice-cream",
|
|
100
|
+
"cocktail",
|
|
101
|
+
],
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
name: "Transportation",
|
|
105
|
+
icons: ["car", "bus", "train", "bicycle", "truck"],
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
name: "Files & Information",
|
|
109
|
+
icons: ["file", "file-lines", "folder", "book-open", "clipboard"],
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
name: "Communication",
|
|
113
|
+
icons: ["phone", "envelope", "map-marker", "location-dot"],
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
name: "Garden & Outdoor",
|
|
117
|
+
icons: ["tree", "leaf", "seedling", "sun", "cloud-sun", "bug"],
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
name: "Maintenance & Safety",
|
|
121
|
+
icons: ["wrench", "hammer", "tools", "lock"],
|
|
122
|
+
},
|
|
123
|
+
];
|
|
124
|
+
|
|
125
|
+
// Flatten all icons for easy iteration, removing duplicates
|
|
126
|
+
export const allIcons = [
|
|
127
|
+
...new Set(
|
|
128
|
+
iconCategories.reduce((acc, category) => {
|
|
129
|
+
return [...acc, ...category.icons];
|
|
130
|
+
}, []),
|
|
131
|
+
),
|
|
132
|
+
];
|
|
133
|
+
|
|
134
|
+
// Default icons for current selection
|
|
135
|
+
export const defaultIcon = "star";
|