@visns-studio/visns-components 5.1.17 → 5.1.19

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.17",
80
+ "version": "5.1.19",
81
81
  "description": "Various packages to assist in the development of our Custom Applications.",
82
82
  "main": "src/index.js",
83
83
  "files": [
@@ -11,7 +11,19 @@ import { BlockPicker } from 'react-color';
11
11
  import { CopyToClipboard } from 'react-copy-to-clipboard';
12
12
  import { NumericFormat, PatternFormat } from 'react-number-format';
13
13
  import { Editor } from '@tinymce/tinymce-react';
14
- import { CirclePlus, CloudDownload, Copy, TrashCan } from 'akar-icons';
14
+ import {
15
+ Edit,
16
+ ChevronRight,
17
+ Circle,
18
+ CircleFill,
19
+ CirclePlus,
20
+ CloudDownload,
21
+ Copy,
22
+ Minus,
23
+ ArrowBack,
24
+ TrashCan,
25
+ CircleX,
26
+ } from 'akar-icons';
15
27
  import { toast } from 'react-toastify';
16
28
  import styles from './styles/Field.module.scss';
17
29
 
@@ -19,6 +31,9 @@ import CustomFetch from './Fetch';
19
31
  import Form from './Form';
20
32
  import MultiSelect from './MultiSelect';
21
33
  import Select from './Select';
34
+ import SketchConfig from './sketch/json/config.json';
35
+ import SketchField from './sketch/SketchField';
36
+ import Tools from './sketch/tools';
22
37
  import VisnsAsyncSelect from './AsyncSelect';
23
38
  import VisnsAutocomplete from './Autocomplete';
24
39
  import VisnsDropZone from '../cms/DropZone';
@@ -63,6 +78,30 @@ function Field({
63
78
  const [formItemClass, setFormItemClass] = useState('');
64
79
  const [options, setOptions] = useState([]);
65
80
 
81
+ /** Canvas States */
82
+ const [canvasPopupOpen, setCanvasPopupOpen] = useState(false);
83
+ const [canvasUrl, setCanvasUrl] = useState('');
84
+ const [sketchTool, setSketchTool] = useState(Tools.Pencil);
85
+ const [toolClass, setToolClass] = useState('pencil');
86
+ const [lineWidth, setLineWidth] = useState(2);
87
+ const [lineColor, setLineColor] = useState('rgba(0, 0, 0, 1)');
88
+ const sketchRef = useRef(null);
89
+
90
+ /** Canvas Functions */
91
+ const handleCanvasSave = async () => {
92
+ // Save the current canvas state
93
+ const canvasState = sketchRef.current.saveCanvasState();
94
+
95
+ // Export the canvas image data as a Base64 string
96
+ const imageData = await sketchRef.current.exportCanvasImage(); // Use await here
97
+
98
+ // Call the onChangeCanvas function with both values
99
+ onChangeCanvas(settings, canvasState, imageData);
100
+
101
+ // Close the canvas popup
102
+ setCanvasPopupOpen(false);
103
+ };
104
+
66
105
  const cover = {
67
106
  position: 'fixed',
68
107
  top: '0px',
@@ -203,6 +242,7 @@ function Field({
203
242
  }
204
243
  });
205
244
  } else {
245
+ console.info(s);
206
246
  filter = {
207
247
  where: [
208
248
  {
@@ -212,20 +252,22 @@ function Field({
212
252
  ],
213
253
  };
214
254
 
215
- if (s.fields) {
216
- filter.fields = s.fields;
255
+ if (s?.child?.fields) {
256
+ filter.fields = s.child.fields;
217
257
  }
218
258
 
219
- if (s.orderBy) {
220
- filter.orderBy = s.orderBy;
259
+ if (s?.child?.orderBy) {
260
+ filter.orderBy = s.child.orderBy;
221
261
  }
222
262
 
223
- if (s.where) {
224
- forEach(s.where, (w) => {
263
+ if (s?.child?.where) {
264
+ forEach(s.child.where, (w) => {
225
265
  filter.where.push(w);
226
266
  });
227
267
  }
228
268
 
269
+ console.info(filter, s.fields);
270
+
229
271
  CustomFetch(s.child.url, 'POST', filter, function (result) {
230
272
  childDropdownCallback({
231
273
  id: s.child.id,
@@ -280,8 +322,6 @@ function Field({
280
322
  'checkbox',
281
323
  'colour',
282
324
  'copytoclipboard',
283
- 'date',
284
- 'datetime',
285
325
  'dropdown',
286
326
  'dropdown-ajax',
287
327
  'dynamicdata',
@@ -307,6 +347,14 @@ function Field({
307
347
  {settings.label} {settings.required ? '*' : ''}
308
348
  </span>
309
349
  );
350
+ } else if (['date', 'datetime', 'time'].includes(settings.type)) {
351
+ return (
352
+ <span
353
+ className={`${styles.fi__span} ${styles.prefocusdate}`}
354
+ >
355
+ {settings.label} {settings.required ? '*' : ''}
356
+ </span>
357
+ );
310
358
  } else if (['plaintext'].includes(settings.type)) {
311
359
  if (settings.description) {
312
360
  return (
@@ -687,7 +735,7 @@ function Field({
687
735
  settings.multiple === true
688
736
  ) {
689
737
  return (
690
- <>
738
+ <div className={styles['file-upload-container']}>
691
739
  <input
692
740
  type="file"
693
741
  multiple
@@ -695,51 +743,53 @@ function Field({
695
743
  className={inputClass[settings.id]}
696
744
  onChange={onChange}
697
745
  />
746
+
698
747
  {inputValue && inputValue.length > 0 && (
699
- <ul className="file-list">
748
+ <ul className={styles['file-list']}>
700
749
  {inputValue.map((file, index) => (
701
750
  <li
702
751
  key={`file-${settings.id}-${index}`}
703
752
  >
704
- {file.name
705
- ? file.name
706
- : file.file_name
707
- ? file.file_name
708
- : ''}
753
+ <span
754
+ className={styles['file-name']}
755
+ >
756
+ {file.name ||
757
+ file.file_name ||
758
+ ''}
759
+ </span>
709
760
  <button
710
- className="trash-button"
761
+ className={
762
+ styles['trash-button']
763
+ }
711
764
  onClick={(e) => {
712
765
  e.preventDefault();
713
766
  e.stopPropagation();
714
-
715
- const updatedFiles =
716
- inputValue.filter(
717
- (_, fileIndex) =>
718
- fileIndex !==
719
- index
720
- );
721
-
722
767
  setFormData(
723
768
  (prevFormData) => ({
724
769
  ...prevFormData,
725
770
  [settings.id]:
726
- updatedFiles,
771
+ inputValue.filter(
772
+ (
773
+ _,
774
+ fileIndex
775
+ ) =>
776
+ fileIndex !==
777
+ index
778
+ ),
727
779
  })
728
780
  );
729
781
  }}
730
782
  >
731
783
  <TrashCan
732
- data-tooltip-id="system-tooltip"
733
- data-tooltip-content="Remove File"
734
784
  strokeWidth={2}
735
- size={24}
785
+ size={20}
736
786
  />
737
787
  </button>
738
788
  </li>
739
789
  ))}
740
790
  </ul>
741
791
  )}
742
- </>
792
+ </div>
743
793
  );
744
794
  } else {
745
795
  return (
@@ -1922,6 +1972,126 @@ function Field({
1922
1972
  updateForm={setChildForm}
1923
1973
  />
1924
1974
  </Popup>
1975
+ <Popup
1976
+ open={canvasPopupOpen}
1977
+ onClose={() => setCanvasPopupOpen(false)}
1978
+ closeOnDocumentClick={false}
1979
+ >
1980
+ <div className={`${styles.modalwrap} ${styles['top--modal']}`}>
1981
+ <div className={styles.modal}>
1982
+ <div className={styles.modal__header}>
1983
+ <h1>Edit Canvas</h1>
1984
+ <button
1985
+ className={styles.modal__close}
1986
+ onClick={() => setCanvasPopupOpen(false)}
1987
+ >
1988
+ <CircleX size={24} color="#FFF" />
1989
+ </button>
1990
+ </div>
1991
+ <div
1992
+ className={`${styles.modal__content} ${styles.drawDiv}`}
1993
+ >
1994
+ {/* Sketch Tools */}
1995
+ <ul className={styles.drawactions}>
1996
+ <li>
1997
+ <button
1998
+ onClick={() => {
1999
+ handleCanvasSave();
2000
+ }}
2001
+ className={styles['drawactions--save']}
2002
+ >
2003
+ <CloudDownload size={16} /> Save
2004
+ </button>
2005
+ </li>
2006
+ <li>
2007
+ <button
2008
+ onClick={() => {
2009
+ setSketchTool(Tools.Pencil);
2010
+ setToolClass('pencil');
2011
+ }}
2012
+ className={`${
2013
+ styles['drawaction-pencil']
2014
+ } ${
2015
+ toolClass === 'pencil'
2016
+ ? styles['drawactive']
2017
+ : ''
2018
+ }`}
2019
+ >
2020
+ <Edit size={16} /> Pencil
2021
+ </button>
2022
+ </li>
2023
+ <li>
2024
+ <button
2025
+ onClick={() => {
2026
+ setSketchTool(Tools.Line);
2027
+
2028
+ setToolClass('line');
2029
+ }}
2030
+ className={`${
2031
+ styles['drawaction-line']
2032
+ } ${
2033
+ toolClass === 'line'
2034
+ ? styles['drawactive']
2035
+ : ''
2036
+ }`}
2037
+ >
2038
+ <Minus size={16} /> Line
2039
+ </button>
2040
+ </li>
2041
+ <li>
2042
+ <button
2043
+ onClick={() => {
2044
+ setSketchTool(Tools.Circle);
2045
+
2046
+ setToolClass('circle');
2047
+ }}
2048
+ className={`${
2049
+ styles['drawaction-circle']
2050
+ } ${
2051
+ toolClass === 'circle'
2052
+ ? styles['drawactive']
2053
+ : ''
2054
+ }`}
2055
+ >
2056
+ <Circle size={16} /> Circle
2057
+ </button>
2058
+ </li>
2059
+ <li>
2060
+ <button
2061
+ onClick={() => sketchRef.current.undo()}
2062
+ className={styles['drawaction-undo']}
2063
+ >
2064
+ <ArrowBack size={16} /> Undo
2065
+ </button>
2066
+ </li>
2067
+ <li>
2068
+ <button
2069
+ onClick={() =>
2070
+ sketchRef.current.clearCanvas()
2071
+ }
2072
+ className={styles['drawactions--clear']}
2073
+ >
2074
+ <TrashCan size={16} /> Clear
2075
+ </button>
2076
+ </li>
2077
+ </ul>
2078
+ {(canvasUrl || inputValue?.state) && (
2079
+ <SketchField
2080
+ ref={sketchRef}
2081
+ width={740}
2082
+ height={800}
2083
+ tool={sketchTool}
2084
+ lineColor={lineColor}
2085
+ lineWidth={lineWidth}
2086
+ className={styles.drawcontainer}
2087
+ backgroundImage={canvasUrl}
2088
+ defaultValue={inputValue?.state || null}
2089
+ />
2090
+ )}
2091
+ </div>
2092
+ </div>
2093
+ </div>
2094
+ </Popup>
1925
2095
  </div>
1926
2096
  );
1927
2097
  }
@@ -1,12 +1,13 @@
1
1
  import '../../styles/global.css';
2
2
 
3
3
  import React, { useState, useEffect } from 'react';
4
- import { Link } from 'react-router-dom';
4
+ import { Link, useNavigate } from 'react-router-dom';
5
5
  import { ResponsiveBar } from '@nivo/bar';
6
6
  import { ResponsiveLine } from '@nivo/line';
7
7
  import { ResponsivePie } from '@nivo/pie';
8
8
  import Popup from 'reactjs-popup';
9
9
  import dayjs from 'dayjs';
10
+ import parse from 'html-react-parser';
10
11
  import { CircleX } from 'akar-icons';
11
12
 
12
13
  import CustomFetch from '../../crm/Fetch';
@@ -17,6 +18,7 @@ import styles from './styles/GenericDashboard.module.scss';
17
18
  const toSnakeCase = (str) => str.replace(/[\s-]+/g, '_').toLowerCase();
18
19
 
19
20
  function GenericDashboard({ setting }) {
21
+ const navigate = useNavigate();
20
22
  const [data, setData] = useState({});
21
23
  const [dropdowns, setDropdowns] = useState({});
22
24
  const [filters, setFilters] = useState({}); // Track filter values for each widget
@@ -25,44 +27,69 @@ function GenericDashboard({ setting }) {
25
27
 
26
28
  const fetchData = async (appliedFilters = {}) => {
27
29
  try {
28
- const promises = setting.widgets.map(async (widget) => {
30
+ // Flatten the nested widgets array into a single array
31
+ const flattenedWidgets = setting.widgets.reduce(
32
+ (acc, row) => [...acc, ...row],
33
+ []
34
+ );
35
+
36
+ // Map through the flattened array of widgets
37
+ const promises = flattenedWidgets.map(async (widget) => {
29
38
  const widgetFilters = appliedFilters[widget.id] || {};
30
39
 
31
40
  // Fetch dropdown data if required
32
41
  if (widget.filters) {
33
42
  for (const filter of widget.filters) {
34
43
  if (filter.url) {
35
- const initialFilterData = await CustomFetch(
36
- filter.url,
37
- 'POST',
38
- filter.params || {}
39
- );
40
- setDropdowns((prevFilters) => ({
41
- ...prevFilters,
42
- [widget.id]: {
43
- ...prevFilters[widget.id],
44
- [filter.id]:
45
- initialFilterData?.data?.data || [],
46
- },
47
- }));
44
+ try {
45
+ const initialFilterData = await CustomFetch(
46
+ filter.url,
47
+ 'POST',
48
+ filter.params || {}
49
+ );
50
+ setDropdowns((prevFilters) => ({
51
+ ...prevFilters,
52
+ [widget.id]: {
53
+ ...prevFilters[widget.id],
54
+ [filter.id]:
55
+ initialFilterData?.data?.data || [],
56
+ },
57
+ }));
58
+ } catch (error) {
59
+ console.error(
60
+ `Error fetching dropdown for widget ${widget.id}:`,
61
+ error
62
+ );
63
+ }
48
64
  }
49
65
  }
50
66
  }
51
67
 
52
- // Fetch widget data with filters
53
- return CustomFetch(
54
- widget.api.url,
55
- widget.api.method,
56
- widgetFilters
57
- );
68
+ // Check if widget.api exists before making a request
69
+ if (widget.api?.url && widget.api?.method) {
70
+ return CustomFetch(
71
+ widget.api.url,
72
+ widget.api.method,
73
+ widgetFilters
74
+ );
75
+ }
76
+
77
+ return null; // Return null if no API request is needed
58
78
  });
59
79
 
80
+ // Execute all API requests
60
81
  const results = await Promise.all(promises);
61
82
 
62
- const fetchedData = setting.widgets.reduce((acc, widget, index) => {
63
- acc[widget.id] = results[index]?.data;
64
- return acc;
65
- }, {});
83
+ // Build a data object keyed by widget id
84
+ const fetchedData = flattenedWidgets.reduce(
85
+ (acc, widget, index) => {
86
+ if (results[index]) {
87
+ acc[widget.id] = results[index]?.data;
88
+ }
89
+ return acc;
90
+ },
91
+ {}
92
+ );
66
93
 
67
94
  setData(fetchedData);
68
95
  } catch (error) {
@@ -136,20 +163,28 @@ function GenericDashboard({ setting }) {
136
163
  const initializeFilters = () => {
137
164
  const initialFilters = {};
138
165
 
139
- setting.widgets.forEach((widget) => {
140
- if (widget.filters) {
141
- initialFilters[widget.id] = widget.filters.reduce(
142
- (acc, filter) => {
143
- if (filter.type === 'date' && filter.default) {
144
- acc[filter.id] = getDefaultDate(filter.default);
145
- } else if (filter.type === 'multi-dropdown-ajax') {
146
- acc[filter.id] = [];
147
- }
148
- return acc;
149
- },
150
- {}
151
- );
152
- }
166
+ setting.widgets.forEach((row) => {
167
+ row.forEach((widget) => {
168
+ if (widget.filters) {
169
+ initialFilters[widget.id] = widget.filters.reduce(
170
+ (acc, filter) => {
171
+ if (filter.type === 'date' && filter.default) {
172
+ acc[filter.id] = getDefaultDate(
173
+ filter.default
174
+ );
175
+ } else if (
176
+ filter.type === 'multi-dropdown-ajax'
177
+ ) {
178
+ acc[filter.id] = [];
179
+ } else if (filter.type === 'years') {
180
+ acc[filter.id] = dayjs().year();
181
+ }
182
+ return acc;
183
+ },
184
+ {}
185
+ );
186
+ }
187
+ });
153
188
  });
154
189
 
155
190
  setFilters(initialFilters);
@@ -176,7 +211,13 @@ function GenericDashboard({ setting }) {
176
211
  case 'date':
177
212
  return (
178
213
  <div
179
- className={styles['filter-field']}
214
+ className={
215
+ widget.highlight
216
+ ? styles[
217
+ 'filter-field-highlight'
218
+ ]
219
+ : styles['filter-field']
220
+ }
180
221
  key={filter.id}
181
222
  >
182
223
  <label htmlFor={filter.id}>
@@ -204,7 +245,13 @@ function GenericDashboard({ setting }) {
204
245
  case 'multi-dropdown-ajax':
205
246
  return (
206
247
  <div
207
- className={styles['filter-field']}
248
+ className={
249
+ widget.highlight
250
+ ? styles[
251
+ 'filter-field-highlight'
252
+ ]
253
+ : styles['filter-field']
254
+ }
208
255
  key={filter.id}
209
256
  >
210
257
  <label htmlFor={filter.id}>
@@ -232,6 +279,60 @@ function GenericDashboard({ setting }) {
232
279
  />
233
280
  </div>
234
281
  );
282
+ case 'years':
283
+ return (
284
+ <div
285
+ className={
286
+ widget.highlight
287
+ ? styles[
288
+ 'filter-field-highlight'
289
+ ]
290
+ : styles['filter-field']
291
+ }
292
+ key={filter.id}
293
+ >
294
+ <label htmlFor={filter.id}>
295
+ {filter.label}
296
+ </label>
297
+ <select
298
+ name="year"
299
+ style={{ height: '51px' }}
300
+ value={
301
+ filters[widget.id]?.[
302
+ filter.id
303
+ ] || ''
304
+ }
305
+ onChange={(e) => {
306
+ handleFilterChange(
307
+ widget.id,
308
+ filter.id,
309
+ e.target.value
310
+ );
311
+ e.target.blur(); // Closes the picker
312
+ }}
313
+ >
314
+ {Array.from(
315
+ {
316
+ length:
317
+ new Date().getFullYear() -
318
+ 2021 +
319
+ 3,
320
+ },
321
+ (_, i) => {
322
+ const yearOption = 2022 + i;
323
+ return (
324
+ <option
325
+ key={yearOption}
326
+ value={yearOption}
327
+ >
328
+ {yearOption}
329
+ </option>
330
+ );
331
+ }
332
+ )}
333
+ </select>
334
+ </div>
335
+ );
235
336
  default:
236
337
  return null;
237
338
  }
@@ -269,22 +370,32 @@ function GenericDashboard({ setting }) {
269
370
  return (
270
371
  <>
271
372
  <div className={styles.widgetNo}>
272
- <span>0</span>
273
- </div>
274
- <div className={styles.widgetLink}>
275
- <button
276
- className={
277
- widget.highlight
278
- ? styles['btn-alt']
279
- : styles.btn
280
- }
281
- onClick={() => {
282
- navigate('/leads/follow-ups');
283
- }}
284
- >
285
- View All
286
- </button>
373
+ <span>
374
+ {(Array.isArray(widgetData) &&
375
+ widgetData.length === 0) ||
376
+ widgetData == null
377
+ ? parse(`&nbsp;`)
378
+ : widgetData}
379
+ </span>
287
380
  </div>
381
+ {widget.button && (
382
+ <div className={styles.widgetLink}>
383
+ <button
384
+ className={
385
+ widget.highlight
386
+ ? styles['btn-alt']
387
+ : styles.btn
388
+ }
389
+ onClick={() => {
390
+ if (widget.button.url) {
391
+ navigate(widget.button.url);
392
+ }
393
+ }}
394
+ >
395
+ {widget.button.title}
396
+ </button>
397
+ </div>
398
+ )}
288
399
  </>
289
400
  );
290
401
  case 'pie':
@@ -299,15 +410,25 @@ function GenericDashboard({ setting }) {
299
410
  const barData =
300
411
  widgetData.bar?.data || widgetData.data || widgetData;
301
412
 
302
- return (
303
- <div style={{ height: widget.height || '600px' }}>
304
- <ResponsiveBar data={barData} {...widget.props} />
305
- </div>
306
- );
413
+ if (barData?.length > 0) {
414
+ return (
415
+ <div style={{ height: widget.height || '600px' }}>
416
+ <ResponsiveBar
417
+ data={barData}
418
+ {...widget.props}
419
+ />
420
+ </div>
421
+ );
422
+ }
307
423
  case 'line':
308
- return (
309
- <ResponsiveLine data={widgetData} {...widget.props} />
310
- );
424
+ if (widgetData.length > 0) {
425
+ return (
426
+ <ResponsiveLine
427
+ data={widgetData}
428
+ {...widget.props}
429
+ />
430
+ );
431
+ }
311
432
  case 'list':
312
433
  return (
313
434
  <ul className={styles.dashList}>
@@ -588,48 +709,54 @@ function GenericDashboard({ setting }) {
588
709
  };
589
710
 
590
711
  const renderRows = () => {
591
- const columns = setting.columns || 3; // Default to 3 columns if not specified
592
- const widgetChunks = [];
593
-
594
- for (let i = 0; i < setting.widgets.length; i += columns) {
595
- widgetChunks.push(setting.widgets.slice(i, i + columns));
596
- }
597
-
598
- return widgetChunks.map((row, rowIndex) => (
599
- <div className={styles.grid__row} key={`row-${rowIndex}`}>
600
- {row.map((widget) => (
601
- <div
602
- key={widget.id}
603
- className={`${styles.grid__full} ${
604
- widget.type !== 'list'
605
- ? widget.highlight
606
- ? styles['dashwidget--highlight']
607
- : styles.dashwidget
608
- : null
609
- }`}
610
- >
611
- <div className={styles.widgetTitle}>
612
- <h2>{widget.title}</h2>
613
- </div>
614
- {renderFilters(widget)}
615
- <div>{renderWidget(widget)}</div>
616
- {widget.modal && (
617
- <div className={styles.widgetAction}>
618
- <button
619
- className={`${styles.btn} ${styles.dmore}`}
620
- onClick={() => openModal(widget.id)}
621
- >
622
- View all{' '}
623
- <span>
624
- ({data[widget.id]?.length || 0})
625
- </span>
626
- </button>
712
+ return setting.widgets.map((row, rowIndex) => {
713
+ // Use the number of widgets in the row to determine the grid class
714
+ const columns = row.length;
715
+ const gridClass =
716
+ columns === 1
717
+ ? styles.grid__full
718
+ : columns === 2
719
+ ? styles.grid__half
720
+ : columns === 3
721
+ ? styles.grid__three
722
+ : styles.grid__three; // fallback if more than 3 columns
723
+
724
+ return (
725
+ <div className={styles.grid__row} key={`row-${rowIndex}`}>
726
+ {row.map((widget) => (
727
+ <div
728
+ key={widget.id}
729
+ className={`${gridClass} ${
730
+ widget.type !== 'list'
731
+ ? widget.highlight
732
+ ? styles['dashwidget--highlight']
733
+ : styles.dashwidget
734
+ : ''
735
+ }`}
736
+ >
737
+ <div className={styles.widgetTitle}>
738
+ <h2>{widget.title}</h2>
627
739
  </div>
628
- )}
629
- </div>
630
- ))}
631
- </div>
632
- ));
740
+ {renderFilters(widget)}
741
+ <div>{renderWidget(widget)}</div>
742
+ {widget.modal && (
743
+ <div className={styles.widgetAction}>
744
+ <button
745
+ className={`${styles.btn} ${styles.dmore}`}
746
+ onClick={() => openModal(widget.id)}
747
+ >
748
+ View all{' '}
749
+ <span>
750
+ ({data[widget.id]?.length || 0})
751
+ </span>
752
+ </button>
753
+ </div>
754
+ )}
755
+ </div>
756
+ ))}
757
+ </div>
758
+ );
759
+ });
633
760
  };
634
761
 
635
762
  return (
@@ -182,7 +182,7 @@
182
182
 
183
183
  .widgetTitle {
184
184
  padding-bottom: 10px;
185
- border-bottom: 2px solid rgba(var(--tertiary-rgb), 0.5);
185
+ border-bottom: 2px solid rgba(var(--tertiary-color-rgb), 0.5);
186
186
  }
187
187
  }
188
188
 
@@ -261,6 +261,7 @@
261
261
  gap: 1rem; // Gap between fields
262
262
  align-items: flex-end; // Align fields vertically
263
263
  }
264
+
264
265
  .filter-field {
265
266
  flex: 1; // Ensures equal spacing for each field
266
267
  display: flex;
@@ -292,6 +293,37 @@
292
293
  }
293
294
  }
294
295
 
296
+ .filter-field-highlight {
297
+ flex: 1; // Ensures equal spacing for each field
298
+ display: flex;
299
+ flex-direction: column;
300
+ min-width: 200px; // Sets a minimum width for smaller screens
301
+
302
+ label {
303
+ font-size: 0.875rem;
304
+ font-weight: 600;
305
+ margin-bottom: 0.5rem;
306
+ color: var(--tertiary-color);
307
+ }
308
+
309
+ input,
310
+ select {
311
+ border: 1px solid #dadce0;
312
+ border-radius: 5px;
313
+ padding: 0.5rem 0.75rem;
314
+ font-size: 0.875rem;
315
+ color: #333;
316
+ outline: none;
317
+ background-color: #f9f9f9;
318
+ width: 100%; // Ensures full width within the container
319
+
320
+ &:focus {
321
+ border-color: #007bff;
322
+ box-shadow: 0 0 0 2px rgba(0, 123, 255, 0.25); // Focus effect
323
+ }
324
+ }
325
+ }
326
+
295
327
  .filter-actions {
296
328
  display: flex;
297
329
  gap: 0.75rem; // Gap between buttons
@@ -152,6 +152,17 @@ select:not(:placeholder-shown) + .fi__span {
152
152
  color: rgba(var(--paragraph-rgb), 0.65) !important;
153
153
  }
154
154
 
155
+ .prefocusdate {
156
+ transform: translateX(10px) scale(0.9) !important;
157
+ opacity: 1 !important;
158
+ padding: 0 0.25rem !important;
159
+ background: var(--tertiary-color) !important;
160
+ font-weight: 400 !important;
161
+ transition: all 0.5s cubic-bezier(0.5, 0.5, 0, 1) !important;
162
+ z-index: 1 !important;
163
+ color: rgba(var(--paragraph-rgb), 0.65) !important;
164
+ }
165
+
155
166
  .qtrItem {
156
167
  flex-basis: 25%;
157
168
  }
@@ -417,3 +428,228 @@ input[type='file']:hover {
417
428
  color: var(--secondary-color);
418
429
  }
419
430
  }
431
+
432
+ .modalwrap {
433
+ background: var(--tertiary-color);
434
+ border-radius: 3px;
435
+ overflow: visible;
436
+ border-top-left-radius: var(--br);
437
+ border-top-right-radius: var(--br);
438
+
439
+ .modal {
440
+ width: 100%;
441
+ position: relative;
442
+
443
+ &__header {
444
+ width: 100%;
445
+ background: var(--primary-color);
446
+ border: 2px solid rgba(var(--primary-color), 1.05);
447
+ border-top-left-radius: var(--br);
448
+ border-top-right-radius: var(--br);
449
+ box-sizing: border-box;
450
+
451
+ h1 {
452
+ color: var(--secondary-color);
453
+ margin: 0;
454
+ padding: 0.75em 0.75em;
455
+ font-size: 1.15em;
456
+ }
457
+
458
+ .modal__close {
459
+ width: max-content;
460
+ position: absolute;
461
+ right: 5px;
462
+ top: 5px;
463
+ box-sizing: border-box;
464
+ background: rgba(var(--primary-color), 1.08);
465
+ cursor: pointer;
466
+ padding: 8px 8px;
467
+ margin: 0;
468
+ outline: none;
469
+ border: none;
470
+ border-radius: var(--br);
471
+ display: block;
472
+ line-height: 1;
473
+
474
+ svg {
475
+ color: var(--secondary-color);
476
+ display: block;
477
+ }
478
+ }
479
+ }
480
+
481
+ &__content {
482
+ width: 100%;
483
+ position: relative;
484
+ padding: 0.25rem;
485
+ box-sizing: border-box;
486
+ border-top-left-radius: var(--br);
487
+ border-top-right-radius: var(--br);
488
+
489
+ .btn {
490
+ background: var(--primary-color);
491
+ border: 1px solid rgba(var(--primary-color), 1.05);
492
+
493
+ &:hover {
494
+ background: var(--secondary-color);
495
+ color: var(--tertiary-color);
496
+ }
497
+ }
498
+ }
499
+ }
500
+ }
501
+
502
+ .top--modal {
503
+ width: 100%;
504
+ max-width: 1000px !important;
505
+ height: auto;
506
+ // display: none;
507
+ padding: 0 !important;
508
+ }
509
+
510
+ // Canvas
511
+
512
+ .drawDiv {
513
+ width: 100%;
514
+ display: flex;
515
+ justify-content: space-between;
516
+
517
+ img {
518
+ width: 100%;
519
+ max-width: 470px;
520
+ display: block;
521
+ margin: 0 auto;
522
+ }
523
+ }
524
+
525
+ .drawactions {
526
+ width: 100%;
527
+ height: auto;
528
+ list-style: none;
529
+ padding: 0 1em 0 0;
530
+ margin: 0;
531
+ flex: 1;
532
+ box-sizing: border-box;
533
+
534
+ li {
535
+ width: 100%;
536
+ margin: 0 0 2px 0;
537
+
538
+ button {
539
+ width: 100%;
540
+ color: var(--paragraph-color);
541
+ border: 1px solid transparent;
542
+ padding: 0.5em 1em;
543
+ border-radius: 6px;
544
+ text-align: left;
545
+ font-size: 0.875em;
546
+
547
+ .octicon {
548
+ margin-right: 8px;
549
+ transform: scale(0.8) translateY(-1px);
550
+ }
551
+ }
552
+
553
+ .drawactions--save {
554
+ background: #4ff1ba;
555
+ color: var(--paragraph-color);
556
+ }
557
+
558
+ .drawactions--clear {
559
+ background: #ff6a6a;
560
+ color: var(--paragraph-color);
561
+ }
562
+
563
+ .drawactive {
564
+ border: 1px solid rgba(var(--paragraph-color-rgb), 1.4);
565
+ background: rgba(var(--paragraph-color-rgb), 0.2);
566
+ color: rgba(var(--paragraph-color-rgb), 1.05);
567
+ }
568
+ }
569
+ }
570
+
571
+ .drawcontainer {
572
+ display: block;
573
+ flex: 0 1 80%;
574
+ margin: 0;
575
+ border: 1px dashed rgba(var(--primary-color-rgb), 1.2);
576
+ padding: 5px;
577
+ overflow: hidden;
578
+ box-sizing: border-box;
579
+ }
580
+
581
+ .canvasWrap {
582
+ display: block;
583
+ margin: 0 auto;
584
+ }
585
+
586
+ .canvas-container {
587
+ display: block;
588
+ margin: 0 auto;
589
+ }
590
+
591
+ /* File List Styling */
592
+ .file-upload-container {
593
+ display: flex;
594
+ flex-direction: column;
595
+ gap: 0.5em;
596
+ width: 100%;
597
+ }
598
+
599
+ .file-upload-container input[type='file'] {
600
+ padding: 8px;
601
+ border: 1px solid var(--border-color);
602
+ border-radius: var(--br);
603
+ width: auto;
604
+ background: var(--tertiary-color);
605
+ }
606
+
607
+ .file-list {
608
+ width: 100%;
609
+ border: 1px solid var(--border-color);
610
+ border-radius: var(--br);
611
+ background: var(--tertiary-color);
612
+ max-height: 200px;
613
+ overflow-y: auto;
614
+ padding: 0.5em;
615
+ }
616
+
617
+ .file-list li {
618
+ display: flex;
619
+ justify-content: space-between;
620
+ align-items: center;
621
+ padding: 0.75em 1em;
622
+ border-bottom: 1px solid var(--border-color);
623
+ font-size: 0.9rem;
624
+ background: white;
625
+ border-radius: 5px;
626
+ transition: background 0.3s;
627
+ margin-bottom: 5px;
628
+ }
629
+
630
+ .file-list li:last-child {
631
+ border-bottom: none;
632
+ }
633
+
634
+ .file-list li:hover {
635
+ background: rgba(var(--paragraph-color-rgb), 0.1);
636
+ }
637
+
638
+ .trash-button {
639
+ background: transparent;
640
+ border: none;
641
+ cursor: pointer;
642
+ color: var(--primary-color);
643
+ display: flex;
644
+ align-items: center;
645
+ transition: color 0.3s;
646
+ }
647
+
648
+ .trash-button:hover {
649
+ color: var(--secondary-color);
650
+ }
651
+
652
+ .trash-button svg {
653
+ width: 1.2em;
654
+ height: 1.2em;
655
+ }