@visns-studio/visns-components 5.1.23 → 5.1.25
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/package.json
CHANGED
|
@@ -77,7 +77,7 @@
|
|
|
77
77
|
"react-dom": "^17.0.0 || ^18.0.0"
|
|
78
78
|
},
|
|
79
79
|
"name": "@visns-studio/visns-components",
|
|
80
|
-
"version": "5.1.
|
|
80
|
+
"version": "5.1.25",
|
|
81
81
|
"description": "Various packages to assist in the development of our Custom Applications.",
|
|
82
82
|
"main": "src/index.js",
|
|
83
83
|
"files": [
|
|
@@ -15,7 +15,6 @@ import styles from './styles/GenericEditableTable.module.scss';
|
|
|
15
15
|
// Updated ColourPicker with an expanded pastel palette and a refined Akar icon
|
|
16
16
|
const ColourPicker = ({ value, columnId, keyCounter, onChange }) => {
|
|
17
17
|
const [colorPickerShow, setColorPickerShow] = useState(false);
|
|
18
|
-
const colorPickerRef = useRef(null);
|
|
19
18
|
const buttonRef = useRef(null);
|
|
20
19
|
const popoverRef = useRef(null);
|
|
21
20
|
|
|
@@ -54,20 +53,23 @@ const ColourPicker = ({ value, columnId, keyCounter, onChange }) => {
|
|
|
54
53
|
? buttonRef.current.getBoundingClientRect()
|
|
55
54
|
: {};
|
|
56
55
|
|
|
56
|
+
const handleClear = () => {
|
|
57
|
+
// Passing an empty string to represent "no colour selected"
|
|
58
|
+
onChange('', columnId, keyCounter);
|
|
59
|
+
setColorPickerShow(false);
|
|
60
|
+
};
|
|
61
|
+
|
|
57
62
|
return (
|
|
58
63
|
<div className={styles.cpicker}>
|
|
59
|
-
<div className={styles.cpicker__btn}
|
|
64
|
+
<div className={styles.cpicker__btn}>
|
|
60
65
|
<button
|
|
61
66
|
ref={buttonRef}
|
|
62
|
-
style={
|
|
63
|
-
value && value !== 'null' ? { background: value } : {}
|
|
64
|
-
}
|
|
67
|
+
style={value ? { background: value } : {}}
|
|
65
68
|
onClick={(e) => {
|
|
66
69
|
e.preventDefault();
|
|
67
70
|
setColorPickerShow(!colorPickerShow);
|
|
68
71
|
}}
|
|
69
72
|
>
|
|
70
|
-
{/* Using the Akar Water icon with increased size and some margin */}
|
|
71
73
|
<Water size={20} style={{ color: 'black' }} />
|
|
72
74
|
</button>
|
|
73
75
|
|
|
@@ -87,14 +89,29 @@ const ColourPicker = ({ value, columnId, keyCounter, onChange }) => {
|
|
|
87
89
|
className={styles.colour_cover}
|
|
88
90
|
onClick={() => setColorPickerShow(false)}
|
|
89
91
|
/>
|
|
90
|
-
<
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
92
|
+
<div className={styles.pickerContainer}>
|
|
93
|
+
<CompactPicker
|
|
94
|
+
color={value || ''}
|
|
95
|
+
colors={pastelColors}
|
|
96
|
+
onChangeComplete={(color) => {
|
|
97
|
+
onChange(
|
|
98
|
+
color.hex,
|
|
99
|
+
columnId,
|
|
100
|
+
keyCounter
|
|
101
|
+
);
|
|
102
|
+
setColorPickerShow(false);
|
|
103
|
+
}}
|
|
104
|
+
/>
|
|
105
|
+
{/* Extra clear button added below the CompactPicker */}
|
|
106
|
+
<div className={styles.clearContainer}>
|
|
107
|
+
<button
|
|
108
|
+
onClick={handleClear}
|
|
109
|
+
className={styles.clearButton}
|
|
110
|
+
>
|
|
111
|
+
Clear
|
|
112
|
+
</button>
|
|
113
|
+
</div>
|
|
114
|
+
</div>
|
|
98
115
|
</div>,
|
|
99
116
|
document.body
|
|
100
117
|
)}
|
|
@@ -107,14 +124,16 @@ const GenericEditableTable = ({
|
|
|
107
124
|
schedulingConfig,
|
|
108
125
|
data,
|
|
109
126
|
dataId,
|
|
110
|
-
modalOpen,
|
|
111
127
|
preloadedOptions,
|
|
112
128
|
setData,
|
|
113
129
|
}) => {
|
|
114
|
-
const { columns, rows, form } = schedulingConfig;
|
|
130
|
+
const { columns, rows, form, title } = schedulingConfig;
|
|
115
131
|
const hasCategory = rows && rows.categoryKey; // Only group if defined
|
|
116
132
|
|
|
117
133
|
const [localData, setLocalData] = useState([]);
|
|
134
|
+
// For new (unsaved) entries: if grouped, store per group; if not, a single object.
|
|
135
|
+
const [newEntries, setNewEntries] = useState({});
|
|
136
|
+
const [newEntry, setNewEntry] = useState({});
|
|
118
137
|
|
|
119
138
|
// Determine if a total column exists and its index.
|
|
120
139
|
const totalColumnIndex = columns.findIndex((col) => col.type === 'total');
|
|
@@ -135,7 +154,6 @@ const GenericEditableTable = ({
|
|
|
135
154
|
const calculateTotal = (entry, keys) => {
|
|
136
155
|
let total = 0;
|
|
137
156
|
if (Array.isArray(keys)) {
|
|
138
|
-
// Legacy format: simply sum up the values.
|
|
139
157
|
total = keys.reduce(
|
|
140
158
|
(sum, key) => sum + (parseFloat(entry[key]) || 0),
|
|
141
159
|
0
|
|
@@ -148,7 +166,6 @@ const GenericEditableTable = ({
|
|
|
148
166
|
) {
|
|
149
167
|
const priceKeys = keys.price;
|
|
150
168
|
const unitKeys = keys.unit;
|
|
151
|
-
// If there's one unit key, use its value for all price keys.
|
|
152
169
|
if (unitKeys.length === 1) {
|
|
153
170
|
const unitValue = parseFloat(entry[unitKeys[0]]) || 0;
|
|
154
171
|
total = priceKeys.reduce(
|
|
@@ -156,9 +173,7 @@ const GenericEditableTable = ({
|
|
|
156
173
|
sum + (parseFloat(entry[key]) || 0) * unitValue,
|
|
157
174
|
0
|
|
158
175
|
);
|
|
159
|
-
}
|
|
160
|
-
// Otherwise, if both arrays have the same length, multiply pair‑wise.
|
|
161
|
-
else if (priceKeys.length === unitKeys.length) {
|
|
176
|
+
} else if (priceKeys.length === unitKeys.length) {
|
|
162
177
|
total = priceKeys.reduce(
|
|
163
178
|
(sum, key, index) =>
|
|
164
179
|
sum +
|
|
@@ -219,8 +234,10 @@ const GenericEditableTable = ({
|
|
|
219
234
|
|
|
220
235
|
if (!grouped[groupKey]) {
|
|
221
236
|
grouped[groupKey] = {
|
|
222
|
-
id:
|
|
223
|
-
category:
|
|
237
|
+
id: groupKey,
|
|
238
|
+
category:
|
|
239
|
+
categoryType ||
|
|
240
|
+
(groupKey === 'no_category' ? 'No Category' : ''),
|
|
224
241
|
entries: [],
|
|
225
242
|
};
|
|
226
243
|
}
|
|
@@ -276,7 +293,7 @@ const GenericEditableTable = ({
|
|
|
276
293
|
.catch(() => toast.error('Failed to copy to clipboard'));
|
|
277
294
|
};
|
|
278
295
|
|
|
279
|
-
// Update
|
|
296
|
+
// Update an existing field’s value
|
|
280
297
|
const handleFieldChange = (value, fieldId, keyCounter) => {
|
|
281
298
|
setLocalData((prev) => {
|
|
282
299
|
const updatedDetail = [...prev];
|
|
@@ -383,6 +400,7 @@ const GenericEditableTable = ({
|
|
|
383
400
|
});
|
|
384
401
|
};
|
|
385
402
|
|
|
403
|
+
// Render existing row field (same as before)
|
|
386
404
|
const renderScheduledTableField = (entry, column, keyCounter) => {
|
|
387
405
|
if (!entry || !column) return null;
|
|
388
406
|
|
|
@@ -507,6 +525,222 @@ const GenericEditableTable = ({
|
|
|
507
525
|
}
|
|
508
526
|
};
|
|
509
527
|
|
|
528
|
+
// --- New row functions for inline creation ---
|
|
529
|
+
|
|
530
|
+
// Update new entry fields (for grouped or ungrouped)
|
|
531
|
+
const handleNewFieldChange = (value, fieldId, groupId = null) => {
|
|
532
|
+
if (hasCategory) {
|
|
533
|
+
setNewEntries((prev) => ({
|
|
534
|
+
...prev,
|
|
535
|
+
[groupId]: {
|
|
536
|
+
...prev[groupId],
|
|
537
|
+
[fieldId]: value,
|
|
538
|
+
},
|
|
539
|
+
}));
|
|
540
|
+
} else {
|
|
541
|
+
setNewEntry((prev) => ({
|
|
542
|
+
...prev,
|
|
543
|
+
[fieldId]: value,
|
|
544
|
+
}));
|
|
545
|
+
}
|
|
546
|
+
};
|
|
547
|
+
|
|
548
|
+
// Add the new row to localData and update the backend
|
|
549
|
+
const handleAddNewEntry = (groupId = null) => {
|
|
550
|
+
const newRowData = hasCategory ? newEntries[groupId] || {} : newEntry;
|
|
551
|
+
if (!newRowData || Object.keys(newRowData).length === 0) {
|
|
552
|
+
toast.error('Please fill in some data before adding.');
|
|
553
|
+
return;
|
|
554
|
+
}
|
|
555
|
+
// Determine a new sort_order
|
|
556
|
+
const maxSortOrder = localData.reduce(
|
|
557
|
+
(max, row) => Math.max(max, row.sort_order || 0),
|
|
558
|
+
0
|
|
559
|
+
);
|
|
560
|
+
const newRow = {
|
|
561
|
+
...newRowData,
|
|
562
|
+
id: `new-${Date.now()}`, // temporary ID; adjust as needed
|
|
563
|
+
sort_order: maxSortOrder + 1,
|
|
564
|
+
};
|
|
565
|
+
|
|
566
|
+
// For grouped data, prepopulate the category field if needed
|
|
567
|
+
if (hasCategory && groupId !== 'no_category') {
|
|
568
|
+
newRow[rows.categoryKey.id] = {
|
|
569
|
+
id: groupId,
|
|
570
|
+
[rows.categoryKey.label]: groupId,
|
|
571
|
+
};
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
setLocalData((prev) => {
|
|
575
|
+
const updated = [...prev, newRow];
|
|
576
|
+
debouncedUpdate({ [rows.key]: updated });
|
|
577
|
+
return updated;
|
|
578
|
+
});
|
|
579
|
+
// Reset the new entry state for the corresponding group or overall
|
|
580
|
+
if (hasCategory) {
|
|
581
|
+
setNewEntries((prev) => ({ ...prev, [groupId]: {} }));
|
|
582
|
+
} else {
|
|
583
|
+
setNewEntry({});
|
|
584
|
+
}
|
|
585
|
+
toast.success('Row added');
|
|
586
|
+
};
|
|
587
|
+
|
|
588
|
+
// Render a new row field (similar to renderScheduledTableField)
|
|
589
|
+
const renderNewRowField = (newRowData, column, groupId = null) => {
|
|
590
|
+
const value = newRowData ? newRowData[column.id] : '';
|
|
591
|
+
switch (column.type) {
|
|
592
|
+
case 'colour':
|
|
593
|
+
return (
|
|
594
|
+
<ColourPicker
|
|
595
|
+
value={value}
|
|
596
|
+
columnId={column.id}
|
|
597
|
+
keyCounter={0}
|
|
598
|
+
onChange={(val) =>
|
|
599
|
+
handleNewFieldChange(val, column.id, groupId)
|
|
600
|
+
}
|
|
601
|
+
/>
|
|
602
|
+
);
|
|
603
|
+
case 'currency':
|
|
604
|
+
case 'number':
|
|
605
|
+
return (
|
|
606
|
+
<input
|
|
607
|
+
type="text"
|
|
608
|
+
value={value || ''}
|
|
609
|
+
onChange={(e) =>
|
|
610
|
+
handleNewFieldChange(
|
|
611
|
+
e.target.value,
|
|
612
|
+
column.id,
|
|
613
|
+
groupId
|
|
614
|
+
)
|
|
615
|
+
}
|
|
616
|
+
style={{ textAlign: 'right' }}
|
|
617
|
+
/>
|
|
618
|
+
);
|
|
619
|
+
case 'date':
|
|
620
|
+
return (
|
|
621
|
+
<input
|
|
622
|
+
type="date"
|
|
623
|
+
value={value || ''}
|
|
624
|
+
onChange={(e) =>
|
|
625
|
+
handleNewFieldChange(
|
|
626
|
+
e.target.value,
|
|
627
|
+
column.id,
|
|
628
|
+
groupId
|
|
629
|
+
)
|
|
630
|
+
}
|
|
631
|
+
style={{ textAlign: 'right' }}
|
|
632
|
+
/>
|
|
633
|
+
);
|
|
634
|
+
case 'dropdown':
|
|
635
|
+
return (
|
|
636
|
+
<select
|
|
637
|
+
value={value || ''}
|
|
638
|
+
onChange={(e) =>
|
|
639
|
+
handleNewFieldChange(
|
|
640
|
+
e.target.value,
|
|
641
|
+
column.id,
|
|
642
|
+
groupId
|
|
643
|
+
)
|
|
644
|
+
}
|
|
645
|
+
>
|
|
646
|
+
{column.options.map((option) => (
|
|
647
|
+
<option key={option.id} value={option.id}>
|
|
648
|
+
{option.label}
|
|
649
|
+
</option>
|
|
650
|
+
))}
|
|
651
|
+
</select>
|
|
652
|
+
);
|
|
653
|
+
case 'dropdown-ajax': {
|
|
654
|
+
const options = preloadedOptions[column.id] || [];
|
|
655
|
+
return (
|
|
656
|
+
<select
|
|
657
|
+
value={value || ''}
|
|
658
|
+
onChange={(e) =>
|
|
659
|
+
handleNewFieldChange(
|
|
660
|
+
e.target.value,
|
|
661
|
+
column.id,
|
|
662
|
+
groupId
|
|
663
|
+
)
|
|
664
|
+
}
|
|
665
|
+
>
|
|
666
|
+
<option>Select an Option</option>
|
|
667
|
+
{options.map((option) => (
|
|
668
|
+
<option key={option.id} value={option.id}>
|
|
669
|
+
{option.label}
|
|
670
|
+
</option>
|
|
671
|
+
))}
|
|
672
|
+
</select>
|
|
673
|
+
);
|
|
674
|
+
}
|
|
675
|
+
case 'multi-dropdown-ajax': {
|
|
676
|
+
const multiOptions = preloadedOptions[column.id] || [];
|
|
677
|
+
return (
|
|
678
|
+
<MultiSelect
|
|
679
|
+
settings={{ id: column.id, compact: true }}
|
|
680
|
+
className={styles.selectFullWidth}
|
|
681
|
+
multi={false}
|
|
682
|
+
onChange={(value) =>
|
|
683
|
+
handleNewFieldChange(value, column.id, groupId)
|
|
684
|
+
}
|
|
685
|
+
inputValue={value || ''}
|
|
686
|
+
options={multiOptions}
|
|
687
|
+
/>
|
|
688
|
+
);
|
|
689
|
+
}
|
|
690
|
+
case 'total': {
|
|
691
|
+
const subtotal = calculateTotal(newRowData || {}, column.keys);
|
|
692
|
+
return new Intl.NumberFormat('en-AU', {
|
|
693
|
+
style: 'currency',
|
|
694
|
+
currency: 'AUD',
|
|
695
|
+
}).format(subtotal);
|
|
696
|
+
}
|
|
697
|
+
default:
|
|
698
|
+
return (
|
|
699
|
+
<input
|
|
700
|
+
type="text"
|
|
701
|
+
value={value || ''}
|
|
702
|
+
onChange={(e) =>
|
|
703
|
+
handleNewFieldChange(
|
|
704
|
+
e.target.value,
|
|
705
|
+
column.id,
|
|
706
|
+
groupId
|
|
707
|
+
)
|
|
708
|
+
}
|
|
709
|
+
/>
|
|
710
|
+
);
|
|
711
|
+
}
|
|
712
|
+
};
|
|
713
|
+
|
|
714
|
+
// Render the new row form (for grouped or ungrouped data)
|
|
715
|
+
const renderNewRowForm = (groupId = null) => {
|
|
716
|
+
const newRowData = hasCategory ? newEntries[groupId] || {} : newEntry;
|
|
717
|
+
return (
|
|
718
|
+
<tr className={styles.newRow}>
|
|
719
|
+
{columns.map((column) => (
|
|
720
|
+
<td
|
|
721
|
+
key={column.id}
|
|
722
|
+
style={{
|
|
723
|
+
textAlign:
|
|
724
|
+
column.type === 'currency' ? 'right' : 'left',
|
|
725
|
+
}}
|
|
726
|
+
>
|
|
727
|
+
{renderNewRowField(newRowData, column, groupId)}
|
|
728
|
+
</td>
|
|
729
|
+
))}
|
|
730
|
+
<td>
|
|
731
|
+
<div className={styles.tdactions}>
|
|
732
|
+
<button
|
|
733
|
+
className={styles.btn_compact}
|
|
734
|
+
onClick={() => handleAddNewEntry(groupId)}
|
|
735
|
+
>
|
|
736
|
+
Add
|
|
737
|
+
</button>
|
|
738
|
+
</div>
|
|
739
|
+
</td>
|
|
740
|
+
</tr>
|
|
741
|
+
);
|
|
742
|
+
};
|
|
743
|
+
|
|
510
744
|
// Render header cell with a label and copy icon
|
|
511
745
|
const renderHeaderCell = (column, group = null) => (
|
|
512
746
|
<th
|
|
@@ -539,7 +773,7 @@ const GenericEditableTable = ({
|
|
|
539
773
|
return (
|
|
540
774
|
<div className={styles.gridtxt}>
|
|
541
775
|
<div className={styles.gridtxt__header}>
|
|
542
|
-
<span>{
|
|
776
|
+
<span>{title || 'Estimation Schedule'}</span>
|
|
543
777
|
</div>
|
|
544
778
|
{hasCategory ? (
|
|
545
779
|
groupedCategories.length > 0 ? (
|
|
@@ -635,6 +869,8 @@ const GenericEditableTable = ({
|
|
|
635
869
|
</td>
|
|
636
870
|
</tr>
|
|
637
871
|
))}
|
|
872
|
+
{/* Render the inline new row for this category */}
|
|
873
|
+
{renderNewRowForm(group.id)}
|
|
638
874
|
{/* Render subtotal row for group only if a total column exists */}
|
|
639
875
|
{totalColumnIndex !== -1 && (
|
|
640
876
|
<tr className={styles.subtotalRow}>
|
|
@@ -764,6 +1000,8 @@ const GenericEditableTable = ({
|
|
|
764
1000
|
</td>
|
|
765
1001
|
</tr>
|
|
766
1002
|
))}
|
|
1003
|
+
{/* Render the inline new row at the bottom */}
|
|
1004
|
+
{renderNewRowForm()}
|
|
767
1005
|
{/* Render overall subtotal row only if a total column exists */}
|
|
768
1006
|
{totalColumnIndex !== -1 && (
|
|
769
1007
|
<tr className={styles.subtotalRow}>
|
|
@@ -812,17 +1050,6 @@ const GenericEditableTable = ({
|
|
|
812
1050
|
reloading the data.
|
|
813
1051
|
</div>
|
|
814
1052
|
)}
|
|
815
|
-
|
|
816
|
-
<div className={styles.polActions}>
|
|
817
|
-
<button
|
|
818
|
-
className={styles.btn}
|
|
819
|
-
onClick={() => {
|
|
820
|
-
modalOpen('create', 0);
|
|
821
|
-
}}
|
|
822
|
-
>
|
|
823
|
-
Add
|
|
824
|
-
</button>
|
|
825
|
-
</div>
|
|
826
1053
|
</div>
|
|
827
1054
|
);
|
|
828
1055
|
};
|
|
@@ -144,12 +144,35 @@
|
|
|
144
144
|
outline: none;
|
|
145
145
|
transition: all 0.2s cubic-bezier(0.85, 0, 0.15, 1) 0s;
|
|
146
146
|
font-size: 1.25em;
|
|
147
|
+
|
|
148
|
+
&:hover {
|
|
149
|
+
color: var(--primary-color);
|
|
150
|
+
background: var(--highlight-color);
|
|
151
|
+
border: 1px solid rgba(var(--highlight-rgb), 1.05);
|
|
152
|
+
}
|
|
147
153
|
}
|
|
148
154
|
|
|
149
|
-
.
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
155
|
+
.btn_compact {
|
|
156
|
+
width: max-content;
|
|
157
|
+
display: inline-block;
|
|
158
|
+
position: relative;
|
|
159
|
+
padding: 0.4rem 0.75rem; /* Reduced padding for a compact look */
|
|
160
|
+
cursor: pointer;
|
|
161
|
+
font-size: 1rem; /* Slightly smaller font size */
|
|
162
|
+
color: var(--tertiary-color);
|
|
163
|
+
text-decoration: none;
|
|
164
|
+
overflow: hidden;
|
|
165
|
+
background: var(--primary-color);
|
|
166
|
+
border: 1px solid rgba(var(--primary-color--rgb), 1.1);
|
|
167
|
+
border-radius: var(--br);
|
|
168
|
+
outline: none;
|
|
169
|
+
transition: all 0.2s cubic-bezier(0.85, 0, 0.15, 1) 0s;
|
|
170
|
+
|
|
171
|
+
&:hover {
|
|
172
|
+
color: var(--primary-color);
|
|
173
|
+
background: var(--highlight-color);
|
|
174
|
+
border: 1px solid rgba(var(--highlight-rgb), 1.05);
|
|
175
|
+
}
|
|
153
176
|
}
|
|
154
177
|
|
|
155
178
|
.tdactions {
|
|
@@ -223,40 +246,79 @@
|
|
|
223
246
|
}
|
|
224
247
|
|
|
225
248
|
.cpicker {
|
|
226
|
-
|
|
249
|
+
position: relative;
|
|
227
250
|
display: flex;
|
|
228
|
-
flex-wrap: nowrap;
|
|
229
251
|
align-items: center;
|
|
230
252
|
|
|
231
253
|
&__btn {
|
|
232
|
-
flex: 1;
|
|
233
|
-
|
|
234
254
|
button {
|
|
235
|
-
width:
|
|
236
|
-
height:
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
255
|
+
width: 28px;
|
|
256
|
+
height: 28px;
|
|
257
|
+
background-color: #f0f0f0;
|
|
258
|
+
border: 1px solid #ccc;
|
|
259
|
+
border-radius: 6px;
|
|
260
|
+
display: flex;
|
|
261
|
+
align-items: center;
|
|
262
|
+
justify-content: center;
|
|
243
263
|
cursor: pointer;
|
|
244
|
-
transition:
|
|
264
|
+
transition: background 0.2s;
|
|
245
265
|
|
|
246
266
|
&:hover {
|
|
247
|
-
background-color: #
|
|
248
|
-
border-color: #666;
|
|
267
|
+
background-color: #e0e0e0;
|
|
249
268
|
}
|
|
250
269
|
|
|
251
270
|
&:focus {
|
|
252
271
|
outline: none;
|
|
253
|
-
box-shadow: 0 0
|
|
272
|
+
box-shadow: 0 0 3px rgba(0, 0, 0, 0.2);
|
|
254
273
|
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
}
|
|
255
277
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
278
|
+
.colour_popover {
|
|
279
|
+
position: absolute;
|
|
280
|
+
background: white;
|
|
281
|
+
border-radius: 8px;
|
|
282
|
+
box-shadow: 0px 4px 12px rgba(0, 0, 0, 0.15);
|
|
283
|
+
padding: 10px;
|
|
284
|
+
min-width: 200px;
|
|
285
|
+
display: flex;
|
|
286
|
+
flex-direction: column;
|
|
287
|
+
align-items: center;
|
|
288
|
+
z-index: 1000;
|
|
289
|
+
|
|
290
|
+
.clearContainer {
|
|
291
|
+
width: 100%;
|
|
292
|
+
display: flex;
|
|
293
|
+
justify-content: center;
|
|
294
|
+
margin-top: 8px;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
.clearButton {
|
|
298
|
+
width: 100%; /* Make button span the entire width */
|
|
299
|
+
background: rgba(
|
|
300
|
+
var(--primary-rgb),
|
|
301
|
+
0.1
|
|
302
|
+
); /* Soft transparent background */
|
|
303
|
+
color: var(--primary-color);
|
|
304
|
+
border: none;
|
|
305
|
+
border-top: 1px solid rgba(var(--primary-rgb), 0.2); /* Subtle separator */
|
|
306
|
+
border-radius: 0 0 8px 8px; /* Match colour picker's bottom corners */
|
|
307
|
+
font-size: 13px;
|
|
308
|
+
padding: 8px;
|
|
309
|
+
cursor: pointer;
|
|
310
|
+
transition: background 0.2s, border 0.2s, box-shadow 0.2s;
|
|
311
|
+
font-weight: 500;
|
|
312
|
+
text-align: center;
|
|
313
|
+
box-shadow: inset 0px 1px 3px rgba(0, 0, 0, 0.05);
|
|
314
|
+
|
|
315
|
+
&:hover {
|
|
316
|
+
background: rgba(var(--primary-rgb), 0.15);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
&:active {
|
|
320
|
+
background: rgba(var(--primary-rgb), 0.25);
|
|
321
|
+
box-shadow: inset 0px 1px 3px rgba(0, 0, 0, 0.15);
|
|
260
322
|
}
|
|
261
323
|
}
|
|
262
324
|
}
|
|
@@ -287,3 +349,12 @@
|
|
|
287
349
|
.react-select__indicators {
|
|
288
350
|
padding: 0 0.25rem;
|
|
289
351
|
}
|
|
352
|
+
|
|
353
|
+
.newRow {
|
|
354
|
+
background-color: rgba(
|
|
355
|
+
var(--primary-rgb),
|
|
356
|
+
0.15
|
|
357
|
+
); /* Slightly lighter background */
|
|
358
|
+
border-top: 1px dashed rgba(var(--primary-rgb), 0.3);
|
|
359
|
+
border-bottom: 1px dashed rgba(var(--primary-rgb), 0.3);
|
|
360
|
+
}
|