create-template-html-css 2.1.0 → 2.2.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/CHANGELOG.md +131 -0
- package/CODE-SPLITTING-GUIDE.md +274 -0
- package/COMPONENTS-GALLERY.html +143 -8
- package/README.md +71 -3
- package/bin/cli.js +2 -0
- package/bin/commands/create.js +16 -0
- package/package.json +1 -1
- package/src/react-component-choices.js +53 -1
- package/src/react-component-templates.js +182 -0
- package/src/react-generator.js +15 -4
- package/src/react-templates.js +192 -124
- package/src/templates/basic-components-templates.js +157 -0
- package/src/templates/form-components-templates.js +194 -0
- package/src/templates/interactive-components-templates.js +139 -0
- package/templates-react/alert/Alert.css +158 -0
- package/templates-react/alert/Alert.example.jsx +106 -0
- package/templates-react/alert/Alert.jsx +61 -0
- package/templates-react/badge/Badge.css +196 -0
- package/templates-react/badge/Badge.example.jsx +182 -0
- package/templates-react/badge/Badge.jsx +44 -0
- package/templates-react/button/Button.example.jsx +1 -1
- package/templates-react/button/Button.jsx +1 -1
- package/templates-react/card/Card.example.jsx +1 -1
- package/templates-react/card/Card.jsx +1 -1
- package/templates-react/checkbox/Checkbox.css +217 -0
- package/templates-react/checkbox/Checkbox.example.jsx +141 -0
- package/templates-react/checkbox/Checkbox.jsx +82 -0
- package/templates-react/counter/Counter.example.jsx +1 -1
- package/templates-react/counter/Counter.jsx +1 -1
- package/templates-react/dropdown/Dropdown.css +237 -0
- package/templates-react/dropdown/Dropdown.example.jsx +98 -0
- package/templates-react/dropdown/Dropdown.jsx +154 -0
- package/templates-react/form/Form.example.jsx +0 -1
- package/templates-react/form/Form.jsx +1 -1
- package/templates-react/input/Input.css +113 -0
- package/templates-react/input/Input.example.jsx +82 -0
- package/templates-react/input/Input.jsx +87 -0
- package/templates-react/modal/Modal.example.jsx +1 -1
- package/templates-react/modal/Modal.jsx +1 -1
- package/templates-react/navbar/Navbar.css +139 -0
- package/templates-react/navbar/Navbar.example.jsx +37 -0
- package/templates-react/navbar/Navbar.jsx +62 -0
- package/templates-react/progress/Progress.css +247 -0
- package/templates-react/progress/Progress.example.jsx +244 -0
- package/templates-react/progress/Progress.jsx +79 -0
- package/templates-react/switch/Switch.css +244 -0
- package/templates-react/switch/Switch.example.jsx +221 -0
- package/templates-react/switch/Switch.jsx +98 -0
- package/templates-react/todo-list/TodoList.example.jsx +1 -1
- package/templates-react/todo-list/TodoList.jsx +1 -1
- package/templates-react/tooltip/Tooltip.css +165 -0
- package/templates-react/tooltip/Tooltip.example.jsx +166 -0
- package/templates-react/tooltip/Tooltip.jsx +176 -0
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Form Component Templates
|
|
3
|
+
* Form-related components with input fields and state management
|
|
4
|
+
*
|
|
5
|
+
* @module templates/form-components-templates
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export const FORM_TEMPLATES = {
|
|
9
|
+
form: ` return (
|
|
10
|
+
<div className="App" style={{ padding: '40px' }}>
|
|
11
|
+
<{ComponentName}
|
|
12
|
+
title="Contact Form"
|
|
13
|
+
fields={[
|
|
14
|
+
{ name: 'name', label: 'Name', type: 'text', required: true },
|
|
15
|
+
{ name: 'email', label: 'Email', type: 'email', required: true },
|
|
16
|
+
]}
|
|
17
|
+
onSubmit={(data) => console.log('Form data:', data)}
|
|
18
|
+
/>
|
|
19
|
+
</div>
|
|
20
|
+
);`,
|
|
21
|
+
|
|
22
|
+
input: ` const [value, setValue] = useState('');
|
|
23
|
+
|
|
24
|
+
return (
|
|
25
|
+
<div className="App" style={{ padding: '40px', maxWidth: '400px', margin: '0 auto' }}>
|
|
26
|
+
<h1 style={{ marginBottom: '30px' }}>Input Component Examples</h1>
|
|
27
|
+
|
|
28
|
+
<{ComponentName}
|
|
29
|
+
label="Name"
|
|
30
|
+
placeholder="Enter your name"
|
|
31
|
+
required
|
|
32
|
+
/>
|
|
33
|
+
|
|
34
|
+
<{ComponentName}
|
|
35
|
+
type="email"
|
|
36
|
+
label="Email"
|
|
37
|
+
placeholder="your@email.com"
|
|
38
|
+
value={value}
|
|
39
|
+
onChange={(e) => setValue(e.target.value)}
|
|
40
|
+
required
|
|
41
|
+
/>
|
|
42
|
+
|
|
43
|
+
<{ComponentName}
|
|
44
|
+
label="Search"
|
|
45
|
+
placeholder="Search..."
|
|
46
|
+
icon="🔍"
|
|
47
|
+
/>
|
|
48
|
+
</div>
|
|
49
|
+
);`,
|
|
50
|
+
|
|
51
|
+
checkbox: ` const [isChecked, setIsChecked] = useState(false);
|
|
52
|
+
|
|
53
|
+
return (
|
|
54
|
+
<div className="App" style={{ padding: '40px', maxWidth: '600px', margin: '0 auto' }}>
|
|
55
|
+
<h1 style={{ marginBottom: '30px' }}>Checkbox Component Examples</h1>
|
|
56
|
+
|
|
57
|
+
<div style={{ marginBottom: '30px' }}>
|
|
58
|
+
<h2>Basic Checkbox</h2>
|
|
59
|
+
<{ComponentName}
|
|
60
|
+
label="I agree to the terms and conditions"
|
|
61
|
+
checked={isChecked}
|
|
62
|
+
onChange={setIsChecked}
|
|
63
|
+
/>
|
|
64
|
+
<p>Status: {isChecked ? 'Checked' : 'Unchecked'}</p>
|
|
65
|
+
</div>
|
|
66
|
+
|
|
67
|
+
<div style={{ marginBottom: '30px' }}>
|
|
68
|
+
<h2>Different Sizes</h2>
|
|
69
|
+
<{ComponentName} label="Small" size="small" />
|
|
70
|
+
<{ComponentName} label="Medium (default)" size="medium" />
|
|
71
|
+
<{ComponentName} label="Large" size="large" />
|
|
72
|
+
</div>
|
|
73
|
+
|
|
74
|
+
<div style={{ marginBottom: '30px' }}>
|
|
75
|
+
<h2>Different Colors</h2>
|
|
76
|
+
<{ComponentName} label="Primary" checked color="primary" />
|
|
77
|
+
<{ComponentName} label="Success" checked color="success" />
|
|
78
|
+
<{ComponentName} label="Error" checked color="error" />
|
|
79
|
+
</div>
|
|
80
|
+
|
|
81
|
+
<div style={{ marginBottom: '30px' }}>
|
|
82
|
+
<h2>Disabled State</h2>
|
|
83
|
+
<{ComponentName} label="Disabled unchecked" disabled />
|
|
84
|
+
<{ComponentName} label="Disabled checked" checked disabled />
|
|
85
|
+
</div>
|
|
86
|
+
</div>
|
|
87
|
+
);`,
|
|
88
|
+
|
|
89
|
+
dropdown: ` const [selected, setSelected] = useState('');
|
|
90
|
+
|
|
91
|
+
const options = [
|
|
92
|
+
{ value: 'apple', label: 'Apple' },
|
|
93
|
+
{ value: 'banana', label: 'Banana' },
|
|
94
|
+
{ value: 'cherry', label: 'Cherry' },
|
|
95
|
+
{ value: 'date', label: 'Date' },
|
|
96
|
+
{ value: 'elderberry', label: 'Elderberry' }
|
|
97
|
+
];
|
|
98
|
+
|
|
99
|
+
return (
|
|
100
|
+
<div className="App" style={{ padding: '40px', maxWidth: '600px', margin: '0 auto' }}>
|
|
101
|
+
<h1 style={{ marginBottom: '30px' }}>Dropdown Component Examples</h1>
|
|
102
|
+
|
|
103
|
+
<div style={{ marginBottom: '30px' }}>
|
|
104
|
+
<{ComponentName}
|
|
105
|
+
label="Choose a fruit"
|
|
106
|
+
options={options}
|
|
107
|
+
value={selected}
|
|
108
|
+
onChange={setSelected}
|
|
109
|
+
placeholder="Select a fruit"
|
|
110
|
+
/>
|
|
111
|
+
<p>Selected: {selected || 'None'}</p>
|
|
112
|
+
</div>
|
|
113
|
+
|
|
114
|
+
<div style={{ marginBottom: '30px' }}>
|
|
115
|
+
<{ComponentName}
|
|
116
|
+
label="Searchable Dropdown"
|
|
117
|
+
options={options}
|
|
118
|
+
placeholder="Search and select..."
|
|
119
|
+
searchable
|
|
120
|
+
/>
|
|
121
|
+
</div>
|
|
122
|
+
|
|
123
|
+
<div style={{ marginBottom: '30px' }}>
|
|
124
|
+
<{ComponentName}
|
|
125
|
+
label="Disabled"
|
|
126
|
+
options={options}
|
|
127
|
+
placeholder="Cannot select"
|
|
128
|
+
disabled
|
|
129
|
+
/>
|
|
130
|
+
</div>
|
|
131
|
+
</div>
|
|
132
|
+
);`,
|
|
133
|
+
|
|
134
|
+
switch: ` const [enabled, setEnabled] = useState(false);
|
|
135
|
+
const [darkMode, setDarkMode] = useState(false);
|
|
136
|
+
|
|
137
|
+
return (
|
|
138
|
+
<div className="App" style={{ padding: '40px', maxWidth: '800px', margin: '0 auto' }}>
|
|
139
|
+
<h1 style={{ marginBottom: '30px' }}>Switch Component Examples</h1>
|
|
140
|
+
|
|
141
|
+
<div style={{ marginBottom: '30px' }}>
|
|
142
|
+
<h2>Basic Switch</h2>
|
|
143
|
+
<{ComponentName}
|
|
144
|
+
checked={enabled}
|
|
145
|
+
onChange={setEnabled}
|
|
146
|
+
label="Enable notifications"
|
|
147
|
+
/>
|
|
148
|
+
<p style={{ marginTop: '0.5rem' }}>Status: {enabled ? 'ON' : 'OFF'}</p>
|
|
149
|
+
</div>
|
|
150
|
+
|
|
151
|
+
<div style={{ marginBottom: '30px' }}>
|
|
152
|
+
<h2>Sizes</h2>
|
|
153
|
+
<div style={{ display: 'flex', flexDirection: 'column', gap: '1rem' }}>
|
|
154
|
+
<{ComponentName} size="small" label="Small" />
|
|
155
|
+
<{ComponentName} size="medium" label="Medium (default)" />
|
|
156
|
+
<{ComponentName} size="large" label="Large" />
|
|
157
|
+
</div>
|
|
158
|
+
</div>
|
|
159
|
+
|
|
160
|
+
<div style={{ marginBottom: '30px' }}>
|
|
161
|
+
<h2>Colors</h2>
|
|
162
|
+
<div style={{ display: 'flex', flexDirection: 'column', gap: '1rem' }}>
|
|
163
|
+
<{ComponentName} checked color="primary" label="Primary" />
|
|
164
|
+
<{ComponentName} checked color="success" label="Success" />
|
|
165
|
+
<{ComponentName} checked color="error" label="Error" />
|
|
166
|
+
</div>
|
|
167
|
+
</div>
|
|
168
|
+
|
|
169
|
+
<div style={{ marginBottom: '30px' }}>
|
|
170
|
+
<h2>With Icons</h2>
|
|
171
|
+
<{ComponentName}
|
|
172
|
+
checked={darkMode}
|
|
173
|
+
onChange={setDarkMode}
|
|
174
|
+
label="Dark mode"
|
|
175
|
+
color="secondary"
|
|
176
|
+
icons={{
|
|
177
|
+
checked: '🌙',
|
|
178
|
+
unchecked: '☀️'
|
|
179
|
+
}}
|
|
180
|
+
/>
|
|
181
|
+
</div>
|
|
182
|
+
|
|
183
|
+
<div style={{ marginBottom: '30px' }}>
|
|
184
|
+
<h2>States</h2>
|
|
185
|
+
<div style={{ display: 'flex', flexDirection: 'column', gap: '1rem' }}>
|
|
186
|
+
<{ComponentName} label="Normal" />
|
|
187
|
+
<{ComponentName} checked label="Checked" />
|
|
188
|
+
<{ComponentName} disabled label="Disabled" />
|
|
189
|
+
<{ComponentName} loading label="Loading" />
|
|
190
|
+
</div>
|
|
191
|
+
</div>
|
|
192
|
+
</div>
|
|
193
|
+
);`,
|
|
194
|
+
};
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interactive Component Templates
|
|
3
|
+
* Complex interactive components with navigation, modals, and animations
|
|
4
|
+
*
|
|
5
|
+
* @module templates/interactive-components-templates
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export const INTERACTIVE_TEMPLATES = {
|
|
9
|
+
modal: ` const [isOpen, setIsOpen] = useState(false);
|
|
10
|
+
|
|
11
|
+
return (
|
|
12
|
+
<div className="App" style={{ padding: '40px' }}>
|
|
13
|
+
<button onClick={() => setIsOpen(true)}>Open Modal</button>
|
|
14
|
+
<{ComponentName}
|
|
15
|
+
isOpen={isOpen}
|
|
16
|
+
onClose={() => setIsOpen(false)}
|
|
17
|
+
title="Example Modal"
|
|
18
|
+
>
|
|
19
|
+
<p>This is the modal content</p>
|
|
20
|
+
</{ComponentName}>
|
|
21
|
+
</div>
|
|
22
|
+
);`,
|
|
23
|
+
|
|
24
|
+
navbar: ` const links = [
|
|
25
|
+
{ label: 'Home', href: '#home' },
|
|
26
|
+
{ label: 'Features', href: '#features' },
|
|
27
|
+
{ label: 'Pricing', href: '#pricing' },
|
|
28
|
+
{ label: 'Contact', href: '#contact' }
|
|
29
|
+
];
|
|
30
|
+
|
|
31
|
+
return (
|
|
32
|
+
<div>
|
|
33
|
+
<{ComponentName}
|
|
34
|
+
logo="MyApp"
|
|
35
|
+
links={links}
|
|
36
|
+
onLinkClick={(link) => console.log('Clicked:', link.label)}
|
|
37
|
+
/>
|
|
38
|
+
<div style={{ padding: '40px' }}>
|
|
39
|
+
<h1>Scroll down to see sticky navbar</h1>
|
|
40
|
+
<div style={{ height: '2000px' }}>
|
|
41
|
+
<p>Content goes here...</p>
|
|
42
|
+
</div>
|
|
43
|
+
</div>
|
|
44
|
+
</div>
|
|
45
|
+
);`,
|
|
46
|
+
|
|
47
|
+
tooltip: ` return (
|
|
48
|
+
<div className="App" style={{ padding: '80px', maxWidth: '800px', margin: '0 auto', textAlign: 'center' }}>
|
|
49
|
+
<h1 style={{ marginBottom: '50px' }}>Tooltip Component Examples</h1>
|
|
50
|
+
|
|
51
|
+
<div style={{ marginBottom: '50px', display: 'flex', gap: '40px', justifyContent: 'center', flexWrap: 'wrap' }}>
|
|
52
|
+
<{ComponentName} content="This is a top tooltip" position="top">
|
|
53
|
+
<button style={buttonStyle}>Top</button>
|
|
54
|
+
</{ComponentName}>
|
|
55
|
+
|
|
56
|
+
<{ComponentName} content="This is a bottom tooltip" position="bottom">
|
|
57
|
+
<button style={buttonStyle}>Bottom</button>
|
|
58
|
+
</{ComponentName}>
|
|
59
|
+
|
|
60
|
+
<{ComponentName} content="This is a left tooltip" position="left">
|
|
61
|
+
<button style={buttonStyle}>Left</button>
|
|
62
|
+
</{ComponentName}>
|
|
63
|
+
|
|
64
|
+
<{ComponentName} content="This is a right tooltip" position="right">
|
|
65
|
+
<button style={buttonStyle}>Right</button>
|
|
66
|
+
</{ComponentName}>
|
|
67
|
+
</div>
|
|
68
|
+
|
|
69
|
+
<div style={{ marginBottom: '50px' }}>
|
|
70
|
+
<{ComponentName} content="Click me to toggle!" trigger="click">
|
|
71
|
+
<button style={buttonStyle}>Click Trigger</button>
|
|
72
|
+
</{ComponentName}>
|
|
73
|
+
</div>
|
|
74
|
+
|
|
75
|
+
<div>
|
|
76
|
+
<{ComponentName}
|
|
77
|
+
content="This is a longer tooltip that demonstrates how it handles more text content."
|
|
78
|
+
maxWidth="300px"
|
|
79
|
+
>
|
|
80
|
+
<button style={buttonStyle}>Long Content</button>
|
|
81
|
+
</{ComponentName}>
|
|
82
|
+
</div>
|
|
83
|
+
</div>
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
const buttonStyle = {
|
|
87
|
+
padding: '0.5rem 1rem',
|
|
88
|
+
backgroundColor: '#3b82f6',
|
|
89
|
+
color: 'white',
|
|
90
|
+
border: 'none',
|
|
91
|
+
borderRadius: '0.375rem',
|
|
92
|
+
cursor: 'pointer'
|
|
93
|
+
};`,
|
|
94
|
+
|
|
95
|
+
progress: ` const [progress, setProgress] = useState(0);
|
|
96
|
+
|
|
97
|
+
useEffect(() => {
|
|
98
|
+
const timer = setInterval(() => {
|
|
99
|
+
setProgress((prev) => (prev >= 100 ? 0 : prev + 1));
|
|
100
|
+
}, 100);
|
|
101
|
+
return () => clearInterval(timer);
|
|
102
|
+
}, []);
|
|
103
|
+
|
|
104
|
+
return (
|
|
105
|
+
<div className="App" style={{ padding: '40px', maxWidth: '800px', margin: '0 auto' }}>
|
|
106
|
+
<h1 style={{ marginBottom: '30px' }}>Progress Component Examples</h1>
|
|
107
|
+
|
|
108
|
+
<div style={{ marginBottom: '30px' }}>
|
|
109
|
+
<h2>Basic Progress</h2>
|
|
110
|
+
<{ComponentName} value={25} variant="primary" />
|
|
111
|
+
<{ComponentName} value={50} variant="success" />
|
|
112
|
+
<{ComponentName} value={75} variant="warning" />
|
|
113
|
+
</div>
|
|
114
|
+
|
|
115
|
+
<div style={{ marginBottom: '30px' }}>
|
|
116
|
+
<h2>With Percentage</h2>
|
|
117
|
+
<{ComponentName} value={60} variant="primary" showPercentage size="large" />
|
|
118
|
+
</div>
|
|
119
|
+
|
|
120
|
+
<div style={{ marginBottom: '30px' }}>
|
|
121
|
+
<h2>Animated Progress</h2>
|
|
122
|
+
<div style={{ marginBottom: '0.5rem' }}>Uploading: {progress}%</div>
|
|
123
|
+
<{ComponentName} value={progress} variant="info" striped animated />
|
|
124
|
+
</div>
|
|
125
|
+
|
|
126
|
+
<div style={{ marginBottom: '30px' }}>
|
|
127
|
+
<h2>Indeterminate (Loading)</h2>
|
|
128
|
+
<{ComponentName} indeterminate variant="primary" />
|
|
129
|
+
</div>
|
|
130
|
+
</div>
|
|
131
|
+
);`,
|
|
132
|
+
|
|
133
|
+
'todo-list': ` return (
|
|
134
|
+
<div className="App" style={{ padding: '40px' }}>
|
|
135
|
+
<h1>Todo List</h1>
|
|
136
|
+
<{ComponentName} />
|
|
137
|
+
</div>
|
|
138
|
+
);`,
|
|
139
|
+
};
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
.alert {
|
|
2
|
+
display: flex;
|
|
3
|
+
align-items: flex-start;
|
|
4
|
+
justify-content: space-between;
|
|
5
|
+
padding: 1rem 1.25rem;
|
|
6
|
+
border-radius: 0.5rem;
|
|
7
|
+
margin-bottom: 1rem;
|
|
8
|
+
border: 1px solid;
|
|
9
|
+
animation: slideIn 0.3s ease;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
@keyframes slideIn {
|
|
13
|
+
from {
|
|
14
|
+
opacity: 0;
|
|
15
|
+
transform: translateY(-10px);
|
|
16
|
+
}
|
|
17
|
+
to {
|
|
18
|
+
opacity: 1;
|
|
19
|
+
transform: translateY(0);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.alert-content {
|
|
24
|
+
display: flex;
|
|
25
|
+
align-items: flex-start;
|
|
26
|
+
flex: 1;
|
|
27
|
+
gap: 0.75rem;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.alert-icon {
|
|
31
|
+
font-size: 1.25rem;
|
|
32
|
+
font-weight: bold;
|
|
33
|
+
flex-shrink: 0;
|
|
34
|
+
width: 24px;
|
|
35
|
+
height: 24px;
|
|
36
|
+
display: flex;
|
|
37
|
+
align-items: center;
|
|
38
|
+
justify-content: center;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.alert-text {
|
|
42
|
+
flex: 1;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.alert-title {
|
|
46
|
+
font-weight: 600;
|
|
47
|
+
font-size: 1rem;
|
|
48
|
+
margin-bottom: 0.25rem;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.alert-message {
|
|
52
|
+
font-size: 0.875rem;
|
|
53
|
+
line-height: 1.5;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.alert-close {
|
|
57
|
+
background: none;
|
|
58
|
+
border: none;
|
|
59
|
+
font-size: 1.5rem;
|
|
60
|
+
line-height: 1;
|
|
61
|
+
cursor: pointer;
|
|
62
|
+
padding: 0;
|
|
63
|
+
margin-left: 1rem;
|
|
64
|
+
opacity: 0.6;
|
|
65
|
+
transition: opacity 0.2s ease;
|
|
66
|
+
flex-shrink: 0;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.alert-close:hover {
|
|
70
|
+
opacity: 1;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/* Success Alert */
|
|
74
|
+
.alert-success {
|
|
75
|
+
background: #ecfdf5;
|
|
76
|
+
border-color: #10b981;
|
|
77
|
+
color: #065f46;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.alert-success .alert-icon {
|
|
81
|
+
color: #10b981;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.alert-success .alert-close {
|
|
85
|
+
color: #065f46;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/* Error Alert */
|
|
89
|
+
.alert-error {
|
|
90
|
+
background: #fef2f2;
|
|
91
|
+
border-color: #ef4444;
|
|
92
|
+
color: #991b1b;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.alert-error .alert-icon {
|
|
96
|
+
color: #ef4444;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.alert-error .alert-close {
|
|
100
|
+
color: #991b1b;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/* Warning Alert */
|
|
104
|
+
.alert-warning {
|
|
105
|
+
background: #fffbeb;
|
|
106
|
+
border-color: #f59e0b;
|
|
107
|
+
color: #92400e;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.alert-warning .alert-icon {
|
|
111
|
+
color: #f59e0b;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
.alert-warning .alert-close {
|
|
115
|
+
color: #92400e;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/* Info Alert */
|
|
119
|
+
.alert-info {
|
|
120
|
+
background: #eff6ff;
|
|
121
|
+
border-color: ##PRIMARY_COLOR##;
|
|
122
|
+
color: #1e40af;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
.alert-info .alert-icon {
|
|
126
|
+
color: ##PRIMARY_COLOR##;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
.alert-info .alert-close {
|
|
130
|
+
color: #1e40af;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/* Dark mode support */
|
|
134
|
+
@media (prefers-color-scheme: dark) {
|
|
135
|
+
.alert-success {
|
|
136
|
+
background: #064e3b;
|
|
137
|
+
color: #d1fae5;
|
|
138
|
+
border-color: #059669;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
.alert-error {
|
|
142
|
+
background: #7f1d1d;
|
|
143
|
+
color: #fecaca;
|
|
144
|
+
border-color: #dc2626;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
.alert-warning {
|
|
148
|
+
background: #78350f;
|
|
149
|
+
color: #fef3c7;
|
|
150
|
+
border-color: #d97706;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
.alert-info {
|
|
154
|
+
background: #1e3a8a;
|
|
155
|
+
color: #dbeafe;
|
|
156
|
+
border-color: ##PRIMARY_COLOR##;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { useState } from 'react';
|
|
2
|
+
import Alert from './Alert';
|
|
3
|
+
|
|
4
|
+
function AlertExample() {
|
|
5
|
+
const [alerts, setAlerts] = useState({
|
|
6
|
+
success: true,
|
|
7
|
+
error: true,
|
|
8
|
+
warning: true,
|
|
9
|
+
info: true
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
const handleClose = (type) => {
|
|
13
|
+
set Alerts({ ...alerts, [type]: false });
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const resetAlerts = () => {
|
|
17
|
+
setAlerts({
|
|
18
|
+
success: true,
|
|
19
|
+
error: true,
|
|
20
|
+
warning: true,
|
|
21
|
+
info: true
|
|
22
|
+
});
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
return (
|
|
26
|
+
<div style={{ maxWidth: '600px', padding: '2rem' }}>
|
|
27
|
+
<h2>Alert Component Examples</h2>
|
|
28
|
+
|
|
29
|
+
<button
|
|
30
|
+
onClick={resetAlerts}
|
|
31
|
+
style={{
|
|
32
|
+
padding: '0.5rem 1rem',
|
|
33
|
+
marginBottom: '1.5rem',
|
|
34
|
+
background: '#667eea',
|
|
35
|
+
color: 'white',
|
|
36
|
+
border: 'none',
|
|
37
|
+
borderRadius: '0.5rem',
|
|
38
|
+
cursor: 'pointer'
|
|
39
|
+
}}
|
|
40
|
+
>
|
|
41
|
+
Reset Alerts
|
|
42
|
+
</button>
|
|
43
|
+
|
|
44
|
+
{/* Success Alert */}
|
|
45
|
+
{alerts.success && (
|
|
46
|
+
<Alert
|
|
47
|
+
type="success"
|
|
48
|
+
title="Success!"
|
|
49
|
+
onClose={() => handleClose('success')}
|
|
50
|
+
>
|
|
51
|
+
Your changes have been saved successfully.
|
|
52
|
+
</Alert>
|
|
53
|
+
)}
|
|
54
|
+
|
|
55
|
+
{/* Error Alert */}
|
|
56
|
+
{alerts.error && (
|
|
57
|
+
<Alert
|
|
58
|
+
type="error"
|
|
59
|
+
title="Error"
|
|
60
|
+
onClose={() => handleClose('error')}
|
|
61
|
+
>
|
|
62
|
+
Something went wrong. Please try again.
|
|
63
|
+
</Alert>
|
|
64
|
+
)}
|
|
65
|
+
|
|
66
|
+
{/* Warning Alert */}
|
|
67
|
+
{alerts.warning && (
|
|
68
|
+
<Alert
|
|
69
|
+
type="warning"
|
|
70
|
+
title="Warning"
|
|
71
|
+
onClose={() => handleClose('warning')}
|
|
72
|
+
>
|
|
73
|
+
This action cannot be undone. Please proceed with caution.
|
|
74
|
+
</Alert>
|
|
75
|
+
)}
|
|
76
|
+
|
|
77
|
+
{/* Info Alert */}
|
|
78
|
+
{alerts.info && (
|
|
79
|
+
<Alert
|
|
80
|
+
type="info"
|
|
81
|
+
title="Information"
|
|
82
|
+
onClose={() => handleClose('info')}
|
|
83
|
+
>
|
|
84
|
+
Check out our new features in the latest update!
|
|
85
|
+
</Alert>
|
|
86
|
+
)}
|
|
87
|
+
|
|
88
|
+
{/* Alert without title */}
|
|
89
|
+
<Alert type="success">
|
|
90
|
+
Quick success message without a title.
|
|
91
|
+
</Alert>
|
|
92
|
+
|
|
93
|
+
{/* Non-dismissible Alert */}
|
|
94
|
+
<Alert type="info" dismissible={false}>
|
|
95
|
+
This alert cannot be closed.
|
|
96
|
+
</Alert>
|
|
97
|
+
|
|
98
|
+
{/* Alert with custom icon */}
|
|
99
|
+
<Alert type="success" icon="🎉" title="Celebration!">
|
|
100
|
+
You've reached a new milestone!
|
|
101
|
+
</Alert>
|
|
102
|
+
</div>
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export default AlertExample;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
|
|
2
|
+
import { useState } from 'react';
|
|
3
|
+
|
|
4
|
+
function Alert({
|
|
5
|
+
type = 'info',
|
|
6
|
+
title,
|
|
7
|
+
children,
|
|
8
|
+
onClose,
|
|
9
|
+
dismissible = true,
|
|
10
|
+
icon: customIcon,
|
|
11
|
+
className = ''
|
|
12
|
+
}) {
|
|
13
|
+
const [isVisible, setIsVisible] = useState(true);
|
|
14
|
+
|
|
15
|
+
const icons = {
|
|
16
|
+
success: '✓',
|
|
17
|
+
error: '✕',
|
|
18
|
+
warning: '⚠',
|
|
19
|
+
info: 'ℹ'
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const handleClose = () => {
|
|
23
|
+
setIsVisible(false);
|
|
24
|
+
if (onClose) {
|
|
25
|
+
onClose();
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
if (!isVisible) {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const icon = customIcon !== undefined ? customIcon : icons[type];
|
|
34
|
+
|
|
35
|
+
return (
|
|
36
|
+
<div className={`alert alert-${type} ${className}`} role="alert">
|
|
37
|
+
<div className="alert-content">
|
|
38
|
+
{icon && (
|
|
39
|
+
<span className="alert-icon">{icon}</span>
|
|
40
|
+
)}
|
|
41
|
+
|
|
42
|
+
<div className="alert-text">
|
|
43
|
+
{title && <div className="alert-title">{title}</div>}
|
|
44
|
+
{children && <div className="alert-message">{children}</div>}
|
|
45
|
+
</div>
|
|
46
|
+
</div>
|
|
47
|
+
|
|
48
|
+
{dismissible && (
|
|
49
|
+
<button
|
|
50
|
+
className="alert-close"
|
|
51
|
+
onClick={handleClose}
|
|
52
|
+
aria-label="Close alert"
|
|
53
|
+
>
|
|
54
|
+
×
|
|
55
|
+
</button>
|
|
56
|
+
)}
|
|
57
|
+
</div>
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export default Alert;
|