@visns-studio/visns-components 5.6.7 → 5.6.9

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.
@@ -1,47 +1,176 @@
1
- // Use the Login styles to maintain consistency
2
- @use './Login.module.scss' as login;
1
+ .formItem {
2
+ width: 100%;
3
+ position: relative;
4
+ box-sizing: border-box;
5
+ margin-bottom: 1rem;
3
6
 
4
- // Additional styles specific to the 2FA component
5
- .instructions {
6
- text-align: center;
7
- margin: 0.5rem 0 1.5rem;
8
- color: var(--paragraph-color);
9
- font-size: 0.95rem;
10
- line-height: 1.4;
7
+ .fi__label {
8
+ position: relative;
9
+ display: flex;
10
+ align-items: center;
11
+ }
12
+
13
+ .fi__span {
14
+ position: absolute;
15
+ transition: all 200ms;
16
+ opacity: 0.7;
17
+ left: 0;
18
+ transform-origin: top left;
19
+ cursor: text;
20
+ padding: 0 1rem;
21
+ font-size: 0.9rem;
22
+ color: #6b7280;
23
+ }
24
+
25
+ input[name='verificationCode'] {
26
+ letter-spacing: 0.25rem;
27
+ font-size: 1.2rem;
28
+ text-align: center;
29
+ }
11
30
  }
12
31
 
13
- .login {
14
- // Instead of extending, copy the necessary properties
15
- width: 35rem;
32
+ .fwItem,
33
+ .fwBuilderItem {
34
+ grid-column: 1 / -1;
35
+ width: 100%;
36
+ }
37
+
38
+ .lastItem .btn {
39
+ width: 100%;
40
+ }
41
+
42
+ .loginlogo {
43
+ display: block;
44
+ width: 100%;
45
+ max-width: 150px;
46
+ height: auto;
47
+ margin: 0 auto;
48
+ padding-bottom: 1.5rem;
49
+ }
50
+
51
+ .logincontainer {
52
+ width: 100%;
53
+ min-height: 100vh;
54
+ display: grid;
55
+ place-items: center;
16
56
  padding: 1rem;
57
+ background-color: #f9fafb;
58
+ }
59
+
60
+ .login {
61
+ width: 28rem;
62
+ padding: 2rem;
17
63
  margin: 0;
18
64
  display: grid;
19
65
  grid-template-columns: 1fr;
20
- gap: 0.5rem;
66
+ gap: 1rem;
67
+ background-color: white;
68
+ border-radius: 0.75rem;
69
+ box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1),
70
+ 0 2px 4px -1px rgba(0, 0, 0, 0.06);
71
+
72
+ > .formItem {
73
+ padding: 0;
74
+
75
+ small {
76
+ position: absolute;
77
+ width: 18px;
78
+ height: 18px;
79
+ right: 14px;
80
+ top: 14px;
81
+ opacity: 0.4;
82
+ color: #6b7280;
83
+ }
84
+ }
21
85
 
22
86
  h2 {
23
87
  text-align: center;
24
- margin: 0;
25
- color: var(--heading-color);
88
+ margin-bottom: 0.5rem;
89
+ color: #111827;
90
+ font-weight: 600;
91
+ font-size: 1.5rem;
92
+ }
93
+ }
94
+
95
+ .instructions {
96
+ text-align: center;
97
+ margin: 0 0 1.5rem;
98
+ color: var(--paragraph-color, #6b7280);
99
+ font-size: 0.95rem;
100
+ line-height: 1.4;
101
+ }
102
+
103
+ .forgotten span {
104
+ display: block;
105
+ text-align: center;
106
+ color: #6b7280;
107
+ padding: 1rem 0;
108
+ font-size: 0.875rem;
109
+
110
+ a {
111
+ color: var(--primary-color, #4f46e5);
112
+ text-decoration: none;
26
113
  font-weight: 500;
114
+
115
+ &:hover {
116
+ text-decoration: underline;
117
+ }
27
118
  }
28
119
  }
29
120
 
30
- // Style for the verification code input
31
- .formItem {
32
- // Instead of extending, copy the necessary properties
33
- width: 50%;
121
+ .lcontainer {
122
+ min-height: 100vh;
123
+ display: flex;
124
+ align-items: center;
125
+ justify-content: center;
126
+ background-color: #f9fafb;
127
+ }
128
+
129
+ .lwrap {
130
+ display: grid;
131
+ grid-template-columns: 1fr;
132
+ }
133
+
134
+ .btn {
135
+ width: max-content;
136
+ display: inline-block;
34
137
  position: relative;
35
- box-sizing: border-box;
36
- margin-bottom: 0.5rem;
138
+ padding: 0.75rem 1rem;
139
+ cursor: pointer;
140
+ font-size: 0.875rem;
141
+ font-weight: 500;
142
+ color: white;
143
+ text-decoration: none;
144
+ overflow: hidden;
145
+ background: var(--primary-color, #4f46e5);
146
+ border: 1px solid var(--primary-color, #4f46e5);
147
+ border-radius: 0.5rem;
148
+ outline: none;
149
+ transition: all 0.2s ease;
150
+ box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
37
151
 
38
- input[name='verificationCode'] {
39
- letter-spacing: 0.25rem;
40
- font-size: 1.2rem;
41
- text-align: center;
152
+ &:hover {
153
+ background: #4338ca;
154
+ border-color: #4338ca;
155
+ }
156
+
157
+ &:focus {
158
+ box-shadow: 0 0 0 2px rgba(79, 70, 229, 0.25);
42
159
  }
43
160
  }
44
161
 
162
+ input:not(:placeholder-shown) + .fi__span,
163
+ textarea:not(:placeholder-shown) + .fi__span,
164
+ select:not(:placeholder-shown) + .fi__span {
165
+ transform: translateY(-135%) translateX(10px) scale(0.85);
166
+ opacity: 1;
167
+ padding: 0;
168
+ background: white;
169
+ font-weight: 500;
170
+ transition: all 0.3s ease;
171
+ color: var(--primary-color, #4f46e5) !important;
172
+ }
173
+
45
174
  .rememberMeIndicator {
46
175
  display: flex;
47
176
  align-items: center;
@@ -1,11 +1,15 @@
1
1
  .formItem {
2
- width: 50%;
2
+ width: 100%;
3
3
  position: relative;
4
4
  box-sizing: border-box;
5
+ margin-bottom: 1rem;
5
6
 
6
7
  h1 {
7
8
  text-align: center;
8
- font-size: 1.25rem;
9
+ font-size: 1.5rem;
10
+ font-weight: 600;
11
+ color: #111827;
12
+ margin-bottom: 1.5rem;
9
13
  }
10
14
 
11
15
  .fi__label {
@@ -17,11 +21,13 @@
17
21
  .fi__span {
18
22
  position: absolute;
19
23
  transition: all 200ms;
20
- opacity: 0.8;
24
+ opacity: 0.7;
21
25
  left: 0;
22
26
  transform-origin: top left;
23
27
  cursor: text;
24
28
  padding: 0 1rem;
29
+ font-size: 0.9rem;
30
+ color: #6b7280;
25
31
  }
26
32
 
27
33
  .fi__div {
@@ -29,8 +35,8 @@
29
35
  opacity: 0.8;
30
36
  left: 0;
31
37
  padding: 19px 13px;
32
- border-radius: var(--radius);
33
- border: 1px solid rgba(var(--paragraph-rgb), 0.15);
38
+ border-radius: 0.5rem;
39
+ border: 1px solid #e5e7eb;
34
40
  box-shadow: none;
35
41
  }
36
42
 
@@ -64,29 +70,10 @@
64
70
  .loginlogo {
65
71
  display: block;
66
72
  width: 100%;
67
- max-width: 140px;
73
+ max-width: 150px;
68
74
  height: auto;
69
75
  margin: 0 auto;
70
- padding-bottom: 1rem;
71
- }
72
-
73
- .logincontainer {
74
- min-height: 100vh;
75
- flex-grow: 1;
76
- display: flex;
77
- align-items: center;
78
- justify-content: center;
79
- align-content: center;
80
- flex-wrap: wrap;
81
- }
82
-
83
- .loginlogo {
84
- display: block;
85
- width: 100%;
86
- max-width: 200px;
87
- height: auto;
88
- margin: 0 auto;
89
- padding-bottom: 1rem;
76
+ padding-bottom: 1.5rem;
90
77
  }
91
78
 
92
79
  .logincontainer {
@@ -95,15 +82,20 @@
95
82
  display: grid;
96
83
  place-items: center;
97
84
  padding: 1rem;
85
+ background-color: #f9fafb;
98
86
  }
99
87
 
100
88
  .login {
101
- width: 35rem;
102
- padding: 1rem;
89
+ width: 28rem;
90
+ padding: 2rem;
103
91
  margin: 0;
104
92
  display: grid;
105
93
  grid-template-columns: 1fr;
106
- gap: 0.5rem;
94
+ gap: 1rem;
95
+ background-color: white;
96
+ border-radius: 0.75rem;
97
+ box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1),
98
+ 0 2px 4px -1px rgba(0, 0, 0, 0.06);
107
99
 
108
100
  > .formItem {
109
101
  padding: 0;
@@ -112,9 +104,10 @@
112
104
  position: absolute;
113
105
  width: 18px;
114
106
  height: 18px;
115
- right: 18px;
116
- top: 18px;
117
- opacity: 0.15;
107
+ right: 14px;
108
+ top: 14px;
109
+ opacity: 0.4;
110
+ color: #6b7280;
118
111
  }
119
112
  }
120
113
 
@@ -149,11 +142,12 @@
149
142
  display: flex;
150
143
  align-items: center;
151
144
  justify-content: center;
145
+ background-color: #f9fafb;
152
146
  }
153
147
 
154
148
  .lwrap {
155
149
  display: grid;
156
- grid-template-columns: var(--sidebar-width) 1fr;
150
+ grid-template-columns: 1fr;
157
151
  }
158
152
 
159
153
  .aside {
@@ -168,27 +162,38 @@
168
162
  width: max-content;
169
163
  display: inline-block;
170
164
  position: relative;
171
- padding: 0.65rem 1rem;
165
+ padding: 0.75rem 1rem;
172
166
  cursor: pointer;
173
- font-size: 1rem;
174
- color: var(--tertiary-color);
167
+ font-size: 0.875rem;
168
+ font-weight: 500;
169
+ color: white;
175
170
  text-decoration: none;
176
171
  overflow: hidden;
177
- background: var(--primary-color);
178
- border: 1px solid rgba(var(--primary-color--rgb), 1.1);
179
- border-radius: var(--br);
172
+ background: var(--primary-color, #4f46e5);
173
+ border: 1px solid var(--primary-color, #4f46e5);
174
+ border-radius: 0.5rem;
180
175
  outline: none;
181
- transition: all 0.2s cubic-bezier(0.85, 0, 0.15, 1) 0s;
182
- font-size: 1.25em;
176
+ transition: all 0.2s ease;
177
+ box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
178
+
179
+ &:hover {
180
+ background: #4338ca;
181
+ border-color: #4338ca;
182
+ }
183
+
184
+ &:focus {
185
+ box-shadow: 0 0 0 2px rgba(79, 70, 229, 0.25);
186
+ }
183
187
  }
184
188
 
185
189
  input:not(:placeholder-shown) + .fi__span,
186
190
  textarea:not(:placeholder-shown) + .fi__span,
187
191
  select:not(:placeholder-shown) + .fi__span {
188
- transform: translateY(-110%) translateX(10px) scale(0.75);
192
+ transform: translateY(-135%) translateX(10px) scale(0.85);
189
193
  opacity: 1;
190
194
  padding: 0;
191
- background: var(--bg-color);
192
- font-weight: 300;
193
- transition: all 0.5s cubic-bezier(0.5, 0.5, 0, 1);
194
- }
195
+ background: white;
196
+ font-weight: 500;
197
+ transition: all 0.3s ease;
198
+ color: var(--primary-color, #4f46e5) !important;
199
+ }
@@ -0,0 +1,207 @@
1
+ import React, { useState } from 'react';
2
+ import TableFilter from '../TableFilter';
3
+
4
+ const FilterExample = () => {
5
+ // Initial filter structure with parent-child relationships
6
+ const initialFilters = [
7
+ {
8
+ id: "personnelLicensesAndRecords",
9
+ label: "Personnel Licenses and Records",
10
+ isParent: true,
11
+ show: false,
12
+ class: "",
13
+ children: [
14
+ {
15
+ id: "completedSiteInduction",
16
+ show: false,
17
+ label: "Completed Site Induction",
18
+ class: ""
19
+ },
20
+ {
21
+ id: "unapprovedWhiteCard",
22
+ show: false,
23
+ label: "Unapproved White Card",
24
+ class: ""
25
+ },
26
+ {
27
+ id: "unapprovedLicense",
28
+ show: false,
29
+ label: "Unapproved License",
30
+ class: ""
31
+ },
32
+ {
33
+ id: "outstandingLicense",
34
+ show: false,
35
+ label: "Outstanding License",
36
+ class: ""
37
+ },
38
+ {
39
+ id: "unapprovedCovid",
40
+ show: false,
41
+ label: "Unapproved COVID",
42
+ class: ""
43
+ }
44
+ ]
45
+ },
46
+ {
47
+ id: "insurance",
48
+ label: "Insurance",
49
+ isParent: true,
50
+ show: false,
51
+ class: "",
52
+ children: [
53
+ {
54
+ id: "allInsurance",
55
+ show: false,
56
+ label: "All Insurance",
57
+ class: ""
58
+ },
59
+ {
60
+ id: "unapprovedInsurance",
61
+ show: false,
62
+ label: "Unapproved Insurance",
63
+ class: ""
64
+ },
65
+ {
66
+ id: "expiredInsurance",
67
+ show: false,
68
+ label: "Expired Insurance",
69
+ class: ""
70
+ },
71
+ {
72
+ id: "outstandingInsurance",
73
+ show: false,
74
+ label: "Outstanding Insurance",
75
+ class: ""
76
+ }
77
+ ]
78
+ },
79
+ {
80
+ id: "workingHours",
81
+ label: "Working Hours",
82
+ isParent: true,
83
+ show: false,
84
+ class: "",
85
+ children: [
86
+ {
87
+ id: "projectTotalHours",
88
+ show: false,
89
+ label: "Project Total Hours",
90
+ class: ""
91
+ },
92
+ {
93
+ id: "contractorTotalHours",
94
+ show: false,
95
+ label: "Contractor Total Hours",
96
+ class: ""
97
+ },
98
+ {
99
+ id: "sitePersonnelWorkHours",
100
+ show: false,
101
+ label: "Site Personnel Work Hours",
102
+ class: ""
103
+ },
104
+ {
105
+ id: "sitePersonnelRecords",
106
+ show: false,
107
+ label: "Site Personnel Records",
108
+ class: ""
109
+ }
110
+ ]
111
+ },
112
+ {
113
+ id: "prequalifications",
114
+ label: "Prequalifications",
115
+ isParent: true,
116
+ show: false,
117
+ class: "",
118
+ children: [
119
+ {
120
+ id: "prequalificationsUnapproved",
121
+ show: false,
122
+ label: "Unapproved Prequalifications",
123
+ class: ""
124
+ },
125
+ {
126
+ id: "prequalificationsExpiring",
127
+ show: false,
128
+ label: "Expiring Prequalifications",
129
+ class: ""
130
+ },
131
+ {
132
+ id: "prequalifiedContractors",
133
+ show: false,
134
+ label: "Prequalified Contractors",
135
+ class: ""
136
+ }
137
+ ]
138
+ }
139
+ ];
140
+
141
+ const [filters, setFilters] = useState(initialFilters);
142
+ const [settings, setSettings] = useState({
143
+ ajaxSetting: {
144
+ where: []
145
+ }
146
+ });
147
+
148
+ // Find the active filter to display content
149
+ const getActiveFilter = () => {
150
+ let activeFilter = null;
151
+
152
+ // Check each parent filter
153
+ filters.forEach(parent => {
154
+ if (parent.children) {
155
+ // Check if any child is active
156
+ parent.children.forEach(child => {
157
+ if (child.show) {
158
+ activeFilter = {
159
+ parent: parent.label,
160
+ child: child.label,
161
+ id: child.id
162
+ };
163
+ }
164
+ });
165
+ }
166
+ });
167
+
168
+ return activeFilter;
169
+ };
170
+
171
+ const activeFilter = getActiveFilter();
172
+
173
+ return (
174
+ <div style={{ maxWidth: '800px', margin: '0 auto', padding: '20px' }}>
175
+ <h1 style={{ marginBottom: '20px' }}>Reports</h1>
176
+
177
+ <div style={{ display: 'flex', gap: '20px' }}>
178
+ <div style={{ width: '300px' }}>
179
+ <TableFilter
180
+ filters={filters}
181
+ setFilters={setFilters}
182
+ setSettings={setSettings}
183
+ />
184
+ </div>
185
+
186
+ <div style={{ flex: 1, padding: '20px', backgroundColor: '#f9f9f9', borderRadius: '8px', minHeight: '300px' }}>
187
+ {activeFilter ? (
188
+ <div>
189
+ <h2>{activeFilter.child}</h2>
190
+ <p>Category: {activeFilter.parent}</p>
191
+ <p>Filter ID: {activeFilter.id}</p>
192
+ <div style={{ marginTop: '20px', padding: '15px', backgroundColor: '#fff', borderRadius: '4px' }}>
193
+ <p>This is the content area that would display data based on the selected filter.</p>
194
+ </div>
195
+ </div>
196
+ ) : (
197
+ <div style={{ textAlign: 'center', color: '#666' }}>
198
+ <p>Please select a filter option to view content</p>
199
+ </div>
200
+ )}
201
+ </div>
202
+ </div>
203
+ </div>
204
+ );
205
+ };
206
+
207
+ export default FilterExample;
@@ -0,0 +1,113 @@
1
+ # TableFilter Component with Parent-Child Structure
2
+
3
+ This document explains how to use the updated TableFilter component with parent-child relationships.
4
+
5
+ ## Structure of Filter Data
6
+
7
+ The TableFilter component now supports a hierarchical structure with parent categories and child filters. Here's how to structure your filter data:
8
+
9
+ ```javascript
10
+ const filters = [
11
+ {
12
+ id: "parentCategoryId",
13
+ label: "Parent Category Name",
14
+ isParent: true, // Important: mark as parent
15
+ show: false,
16
+ class: "",
17
+ children: [
18
+ {
19
+ id: "childFilter1",
20
+ show: false,
21
+ label: "Child Filter 1",
22
+ class: ""
23
+ },
24
+ {
25
+ id: "childFilter2",
26
+ show: false,
27
+ label: "Child Filter 2",
28
+ class: ""
29
+ }
30
+ ]
31
+ },
32
+ // More parent categories...
33
+ ];
34
+ ```
35
+
36
+ ## Key Features
37
+
38
+ 1. **Collapsible Parent Categories**: Click on a parent category to show/hide its children
39
+ 2. **Visual Indicators**: Arrow indicators show whether a parent category is expanded
40
+ 3. **Styling**: Distinct styling for parent categories and child filters
41
+ 4. **Active States**: Visual indication of active filters
42
+ 5. **Mobile Responsive**: Adapts to smaller screens with a toggle menu
43
+
44
+ ## Usage Example
45
+
46
+ ```jsx
47
+ import React, { useState } from 'react';
48
+ import TableFilter from '../TableFilter';
49
+
50
+ function MyComponent() {
51
+ const [filters, setFilters] = useState([
52
+ // Your filter structure here
53
+ ]);
54
+
55
+ const [settings, setSettings] = useState({
56
+ ajaxSetting: {
57
+ where: []
58
+ }
59
+ });
60
+
61
+ return (
62
+ <TableFilter
63
+ filters={filters}
64
+ setFilters={setFilters}
65
+ setSettings={setSettings}
66
+ />
67
+ );
68
+ }
69
+ ```
70
+
71
+ ## How It Works
72
+
73
+ 1. **Parent Categories**: When you click on a parent category, it toggles the visibility of its children
74
+ 2. **Child Filters**: When you click on a child filter:
75
+ - It becomes active (highlighted)
76
+ - The `show` property is set to `true`
77
+ - The `settings` object is updated with the filter's ID and value
78
+ - The content area should update based on the selected filter
79
+
80
+ ## Handling Filter Selection
81
+
82
+ To display content based on the selected filter, check which filter has `show: true`:
83
+
84
+ ```javascript
85
+ // Find the active filter
86
+ const getActiveFilter = () => {
87
+ let activeFilter = null;
88
+
89
+ filters.forEach(parent => {
90
+ if (parent.children) {
91
+ parent.children.forEach(child => {
92
+ if (child.show) {
93
+ activeFilter = {
94
+ parent: parent.label,
95
+ child: child.label,
96
+ id: child.id
97
+ };
98
+ }
99
+ });
100
+ }
101
+ });
102
+
103
+ return activeFilter;
104
+ };
105
+
106
+ // Use the active filter to display content
107
+ const activeFilter = getActiveFilter();
108
+ if (activeFilter) {
109
+ // Display content for the active filter
110
+ }
111
+ ```
112
+
113
+ See the `FilterExample.jsx` file for a complete working example.