@visns-studio/visns-components 5.11.5 → 5.11.7

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.
@@ -0,0 +1,158 @@
1
+ import React from 'react';
2
+ import { X, FileText, List, Eye, CheckSquare, DollarSign, CreditCard, PenTool, FileCheck } from 'lucide-react';
3
+ import './SectionTypeSelector.css';
4
+
5
+ const sectionTypes = [
6
+ {
7
+ id: 'cover_page',
8
+ name: 'Cover Page',
9
+ description: 'Title page with company branding and proposal information',
10
+ icon: FileText,
11
+ category: 'header'
12
+ },
13
+ {
14
+ id: 'toc',
15
+ name: 'Table of Contents',
16
+ description: 'Automatically generated table of contents',
17
+ icon: List,
18
+ category: 'header'
19
+ },
20
+ {
21
+ id: 'overview',
22
+ name: 'Overview',
23
+ description: 'Executive summary and project overview section',
24
+ icon: Eye,
25
+ category: 'content'
26
+ },
27
+ {
28
+ id: 'acceptance',
29
+ name: 'Acceptance Criteria',
30
+ description: 'Project acceptance and success criteria',
31
+ icon: CheckSquare,
32
+ category: 'content'
33
+ },
34
+ {
35
+ id: 'quote_items',
36
+ name: 'Quote Items',
37
+ description: 'Dynamic pricing table with quote line items',
38
+ icon: DollarSign,
39
+ category: 'pricing',
40
+ isDynamic: true
41
+ },
42
+ {
43
+ id: 'payment_terms',
44
+ name: 'Payment Terms',
45
+ description: 'Payment schedule and terms section',
46
+ icon: CreditCard,
47
+ category: 'pricing'
48
+ },
49
+ {
50
+ id: 'agreement_signature',
51
+ name: 'Signatures',
52
+ description: 'Signature blocks for agreement acceptance',
53
+ icon: PenTool,
54
+ category: 'footer'
55
+ },
56
+ {
57
+ id: 'terms_conditions',
58
+ name: 'Terms & Conditions',
59
+ description: 'Legal terms and conditions',
60
+ icon: FileCheck,
61
+ category: 'footer'
62
+ }
63
+ ];
64
+
65
+ const categoryNames = {
66
+ header: 'Header Sections',
67
+ content: 'Content Sections',
68
+ pricing: 'Pricing Sections',
69
+ footer: 'Footer Sections'
70
+ };
71
+
72
+ const categoryColors = {
73
+ header: 'header-category',
74
+ content: 'content-category',
75
+ pricing: 'pricing-category',
76
+ footer: 'footer-category'
77
+ };
78
+
79
+ const SectionTypeSelector = ({ onSelect, onCancel }) => {
80
+ const groupedSections = sectionTypes.reduce((acc, section) => {
81
+ if (!acc[section.category]) {
82
+ acc[section.category] = [];
83
+ }
84
+ acc[section.category].push(section);
85
+ return acc;
86
+ }, {});
87
+
88
+ return (
89
+ <div className="section-type-modal">
90
+ <div className="section-type-modal-content">
91
+ <div className="section-type-modal-header">
92
+ <div>
93
+ <h2 className="section-type-modal-title">Add Template Section</h2>
94
+ <p className="section-type-modal-subtitle">Choose a section type to add to your proposal template</p>
95
+ </div>
96
+ <button
97
+ onClick={onCancel}
98
+ className="section-type-close-btn"
99
+ >
100
+ <X size={20} />
101
+ </button>
102
+ </div>
103
+
104
+ <div className="section-type-modal-body">
105
+ {Object.entries(groupedSections).map(([category, sections]) => (
106
+ <div key={category} className="section-category">
107
+ <h3 className="section-category-title">
108
+ {categoryNames[category]}
109
+ </h3>
110
+ <div className="section-types-grid">
111
+ {sections.map((section) => {
112
+ const IconComponent = section.icon;
113
+ return (
114
+ <button
115
+ key={section.id}
116
+ onClick={() => onSelect(section.id)}
117
+ className={`section-type-card ${categoryColors[category]}`}
118
+ >
119
+ <div className="section-type-card-header">
120
+ <div className="section-type-icon">
121
+ <IconComponent size={20} />
122
+ </div>
123
+ <div className="section-type-card-content">
124
+ <h4 className="section-type-name">
125
+ {section.name}
126
+ {section.isDynamic && (
127
+ <span className="dynamic-badge">
128
+ Dynamic
129
+ </span>
130
+ )}
131
+ </h4>
132
+ <p className="section-type-description">
133
+ {section.description}
134
+ </p>
135
+ </div>
136
+ </div>
137
+ </button>
138
+ );
139
+ })}
140
+ </div>
141
+ </div>
142
+ ))}
143
+ </div>
144
+
145
+ <div className="section-type-modal-footer">
146
+ <button
147
+ onClick={onCancel}
148
+ className="section-type-cancel-btn"
149
+ >
150
+ Cancel
151
+ </button>
152
+ </div>
153
+ </div>
154
+ </div>
155
+ );
156
+ };
157
+
158
+ export default SectionTypeSelector;
@@ -0,0 +1,392 @@
1
+ /* Variable Inserter Modal Styles */
2
+ .variable-inserter-overlay {
3
+ position: fixed;
4
+ inset: 0;
5
+ background-color: rgba(0, 0, 0, 0.5);
6
+ backdrop-filter: blur(4px);
7
+ display: flex;
8
+ align-items: center;
9
+ justify-content: center;
10
+ z-index: 1000;
11
+ animation: fadeIn 0.2s ease-out;
12
+ }
13
+
14
+ @keyframes fadeIn {
15
+ from { opacity: 0; }
16
+ to { opacity: 1; }
17
+ }
18
+
19
+ .variable-inserter-modal {
20
+ background: white;
21
+ border-radius: 12px;
22
+ box-shadow: 0 25px 50px rgba(0, 0, 0, 0.15);
23
+ max-width: 1000px;
24
+ width: 95%;
25
+ margin: 1rem;
26
+ max-height: 85vh;
27
+ overflow: hidden;
28
+ animation: slideUp 0.3s ease-out;
29
+ }
30
+
31
+ @keyframes slideUp {
32
+ from {
33
+ opacity: 0;
34
+ transform: translateY(20px) scale(0.98);
35
+ }
36
+ to {
37
+ opacity: 1;
38
+ transform: translateY(0) scale(1);
39
+ }
40
+ }
41
+
42
+ .variable-inserter-header {
43
+ display: flex;
44
+ align-items: flex-start;
45
+ justify-content: space-between;
46
+ padding: 1.5rem;
47
+ border-bottom: 1px solid #e2e8f0;
48
+ background: linear-gradient(135deg, #0f172a 0%, #1e293b 100%);
49
+ color: white;
50
+ border-radius: 12px 12px 0 0;
51
+ }
52
+
53
+ .variable-inserter-header-actions {
54
+ display: flex;
55
+ align-items: center;
56
+ gap: 0.5rem;
57
+ }
58
+
59
+ .variable-inserter-title {
60
+ font-size: 1.25rem;
61
+ font-weight: 700;
62
+ margin: 0;
63
+ color: #ffffff !important;
64
+ text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
65
+ }
66
+
67
+ .variable-inserter-subtitle {
68
+ font-size: 0.875rem;
69
+ margin: 0.25rem 0 0 0;
70
+ color: rgba(255, 255, 255, 0.95) !important;
71
+ text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
72
+ }
73
+
74
+ .variable-inserter-close-btn {
75
+ padding: 0.5rem;
76
+ color: rgba(255, 255, 255, 0.8);
77
+ background: rgba(255, 255, 255, 0.1);
78
+ border: none;
79
+ border-radius: 6px;
80
+ cursor: pointer;
81
+ transition: all 0.2s;
82
+ display: flex;
83
+ align-items: center;
84
+ justify-content: center;
85
+ }
86
+
87
+ .variable-inserter-close-btn:hover {
88
+ background: #3cbf7d;
89
+ color: white;
90
+ }
91
+
92
+ .variable-inserter-toggle-btn {
93
+ padding: 0.5rem 0.75rem;
94
+ font-size: 0.75rem;
95
+ font-weight: 600;
96
+ color: rgba(255, 255, 255, 0.9);
97
+ background: rgba(60, 191, 125, 0.2);
98
+ border: 1px solid rgba(60, 191, 125, 0.3);
99
+ border-radius: 6px;
100
+ cursor: pointer;
101
+ transition: all 0.2s;
102
+ text-transform: uppercase;
103
+ letter-spacing: 0.025em;
104
+ }
105
+
106
+ .variable-inserter-toggle-btn:hover {
107
+ background: rgba(60, 191, 125, 0.3);
108
+ border-color: rgba(60, 191, 125, 0.5);
109
+ color: white;
110
+ }
111
+
112
+ .variable-inserter-intelligent-indicator {
113
+ color: #3cbf7d;
114
+ font-weight: 600;
115
+ margin-left: 0.5rem;
116
+ }
117
+
118
+ .variable-inserter-loading {
119
+ font-size: 0.8rem;
120
+ color: rgba(255, 255, 255, 0.7);
121
+ margin-top: 0.25rem;
122
+ animation: pulse 1.5s ease-in-out infinite;
123
+ }
124
+
125
+ @keyframes pulse {
126
+ 0%, 100% { opacity: 0.7; }
127
+ 50% { opacity: 1; }
128
+ }
129
+
130
+ .variable-inserter-search-section {
131
+ padding: 1.5rem;
132
+ border-bottom: 1px solid #e2e8f0;
133
+ background: #f8fafc;
134
+ }
135
+
136
+ .variable-inserter-search-container {
137
+ display: flex;
138
+ flex-direction: column;
139
+ gap: 1rem;
140
+ }
141
+
142
+ @media (min-width: 640px) {
143
+ .variable-inserter-search-container {
144
+ flex-direction: row;
145
+ gap: 1rem;
146
+ }
147
+ }
148
+
149
+ .variable-inserter-search-input-wrapper {
150
+ flex: 1;
151
+ position: relative;
152
+ }
153
+
154
+ .variable-inserter-search-icon {
155
+ position: absolute;
156
+ left: 0.875rem;
157
+ top: 50%;
158
+ transform: translateY(-50%);
159
+ color: #9ca3af;
160
+ pointer-events: none;
161
+ z-index: 1;
162
+ }
163
+
164
+ .variable-inserter-search-input {
165
+ width: 100%;
166
+ padding: 0.75rem 1rem 0.75rem 3rem;
167
+ border: 1px solid #d1d5db;
168
+ border-radius: 8px;
169
+ font-size: 0.875rem;
170
+ transition: all 0.2s;
171
+ background: white;
172
+ }
173
+
174
+ .variable-inserter-search-input:focus {
175
+ outline: none;
176
+ border-color: #3cbf7d;
177
+ box-shadow: 0 0 0 3px rgba(60, 191, 125, 0.1);
178
+ }
179
+
180
+ .variable-inserter-category-select {
181
+ width: 100%;
182
+ padding: 0.75rem;
183
+ border: 1px solid #d1d5db;
184
+ border-radius: 8px;
185
+ font-size: 0.875rem;
186
+ background: white;
187
+ transition: all 0.2s;
188
+ }
189
+
190
+ @media (min-width: 640px) {
191
+ .variable-inserter-category-select {
192
+ width: 12rem;
193
+ }
194
+ }
195
+
196
+ .variable-inserter-category-select:focus {
197
+ outline: none;
198
+ border-color: #3cbf7d;
199
+ box-shadow: 0 0 0 3px rgba(60, 191, 125, 0.1);
200
+ }
201
+
202
+ .variable-inserter-content {
203
+ overflow-y: auto;
204
+ max-height: 24rem;
205
+ padding: 1.5rem;
206
+ }
207
+
208
+ .variable-inserter-empty {
209
+ text-align: center;
210
+ padding: 3rem 1rem;
211
+ }
212
+
213
+ .variable-inserter-empty-icon {
214
+ margin: 0 auto 1rem auto;
215
+ color: #d1d5db;
216
+ }
217
+
218
+ .variable-inserter-empty-title {
219
+ font-size: 1.125rem;
220
+ font-weight: 500;
221
+ color: #6b7280;
222
+ margin: 0 0 0.5rem 0;
223
+ }
224
+
225
+ .variable-inserter-empty-text {
226
+ color: #9ca3af;
227
+ margin: 0;
228
+ }
229
+
230
+ .variable-inserter-categories {
231
+ display: flex;
232
+ flex-direction: column;
233
+ gap: 2rem;
234
+ }
235
+
236
+ .variable-inserter-category {
237
+ margin: 0;
238
+ }
239
+
240
+ .variable-inserter-category-header {
241
+ display: flex;
242
+ align-items: center;
243
+ gap: 0.5rem;
244
+ margin-bottom: 1rem;
245
+ }
246
+
247
+ .variable-inserter-category-icon {
248
+ color: #1b3933;
249
+ flex-shrink: 0;
250
+ }
251
+
252
+ .variable-inserter-category-title {
253
+ font-size: 1.125rem;
254
+ font-weight: 600;
255
+ color: #1f2937;
256
+ margin: 0;
257
+ }
258
+
259
+ .variable-inserter-variables-grid {
260
+ display: grid;
261
+ grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
262
+ gap: 0.75rem;
263
+ }
264
+
265
+ .variable-inserter-variable-button {
266
+ text-align: left;
267
+ padding: 1rem;
268
+ border: 1px solid #e5e7eb;
269
+ border-radius: 8px;
270
+ background: white;
271
+ cursor: pointer;
272
+ transition: all 0.2s ease-in-out;
273
+ position: relative;
274
+ overflow: hidden;
275
+ }
276
+
277
+ .variable-inserter-variable-button:hover {
278
+ border-color: #3cbf7d;
279
+ background: #f0fdf4;
280
+ box-shadow: 0 4px 6px rgba(60, 191, 125, 0.1);
281
+ transform: translateY(-1px);
282
+ }
283
+
284
+ .variable-inserter-variable-button:active {
285
+ transform: translateY(0);
286
+ }
287
+
288
+ .variable-inserter-variable-content {
289
+ display: flex;
290
+ align-items: flex-start;
291
+ justify-content: space-between;
292
+ gap: 0.75rem;
293
+ }
294
+
295
+ .variable-inserter-variable-info {
296
+ flex: 1;
297
+ min-width: 0;
298
+ }
299
+
300
+ .variable-inserter-variable-name {
301
+ font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
302
+ font-size: 0.875rem;
303
+ font-weight: 600;
304
+ color: #1b3933;
305
+ margin: 0 0 0.25rem 0;
306
+ word-break: break-all;
307
+ }
308
+
309
+ .variable-inserter-variable-button:hover .variable-inserter-variable-name {
310
+ color: #3cbf7d;
311
+ }
312
+
313
+ .variable-inserter-variable-description {
314
+ font-size: 0.8rem;
315
+ color: #6b7280;
316
+ line-height: 1.4;
317
+ margin: 0;
318
+ }
319
+
320
+ .variable-inserter-variable-icon {
321
+ color: #9ca3af;
322
+ flex-shrink: 0;
323
+ transition: all 0.2s;
324
+ }
325
+
326
+ .variable-inserter-variable-button:hover .variable-inserter-variable-icon {
327
+ color: #3cbf7d;
328
+ }
329
+
330
+ .variable-inserter-footer {
331
+ display: flex;
332
+ align-items: center;
333
+ justify-content: flex-end;
334
+ gap: 0.75rem;
335
+ padding: 1rem 1.5rem;
336
+ border-top: 1px solid #e2e8f0;
337
+ background: #f8fafc;
338
+ border-radius: 0 0 12px 12px;
339
+ }
340
+
341
+ .variable-inserter-cancel-btn {
342
+ padding: 0.625rem 1.25rem;
343
+ font-size: 0.875rem;
344
+ font-weight: 600;
345
+ border-radius: 6px;
346
+ cursor: pointer;
347
+ transition: all 0.2s;
348
+ display: inline-flex;
349
+ align-items: center;
350
+ gap: 0.5rem;
351
+ border: 1px solid #d1d5db;
352
+ background: white;
353
+ color: #6b7280;
354
+ }
355
+
356
+ .variable-inserter-cancel-btn:hover {
357
+ background: #f9fafb;
358
+ border-color: #9ca3af;
359
+ }
360
+
361
+ /* Responsive Design */
362
+ @media (max-width: 768px) {
363
+ .variable-inserter-modal {
364
+ width: 98%;
365
+ margin: 0.5rem;
366
+ max-height: 95vh;
367
+ border-radius: 8px;
368
+ }
369
+
370
+ .variable-inserter-header {
371
+ padding: 1rem;
372
+ border-radius: 8px 8px 0 0;
373
+ }
374
+
375
+ .variable-inserter-search-section,
376
+ .variable-inserter-content,
377
+ .variable-inserter-footer {
378
+ padding: 1rem;
379
+ }
380
+
381
+ .variable-inserter-variables-grid {
382
+ grid-template-columns: 1fr;
383
+ }
384
+
385
+ .variable-inserter-search-container {
386
+ flex-direction: column;
387
+ }
388
+
389
+ .variable-inserter-category-select {
390
+ width: 100%;
391
+ }
392
+ }