nitro-web 0.0.103 → 0.0.104
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/client/index.ts
CHANGED
|
@@ -34,6 +34,7 @@ export { Modal } from '../components/partials/element/modal'
|
|
|
34
34
|
export { Sidebar, type SidebarProps } from '../components/partials/element/sidebar'
|
|
35
35
|
export { Tooltip } from '../components/partials/element/tooltip'
|
|
36
36
|
export { Topbar } from '../components/partials/element/topbar'
|
|
37
|
+
export { Table, type TableColumn, type TableProps, type TableRow } from '../components/partials/element/table'
|
|
37
38
|
|
|
38
39
|
// Component Form Elements
|
|
39
40
|
export { Checkbox } from '../components/partials/form/checkbox'
|
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
import { JSX, useState, useCallback } from 'react'
|
|
2
|
+
import { ChevronDownIcon, ChevronUpIcon } from 'lucide-react'
|
|
3
|
+
import { Checkbox, queryObject, queryString, twMerge } from 'nitro-web'
|
|
4
|
+
|
|
5
|
+
export interface TableColumn {
|
|
6
|
+
label: string
|
|
7
|
+
value: string
|
|
8
|
+
className?: string
|
|
9
|
+
disableSort?: boolean
|
|
10
|
+
innerClassName?: string
|
|
11
|
+
minWidth?: number
|
|
12
|
+
overflow?: boolean
|
|
13
|
+
rowLinesMax?: number
|
|
14
|
+
/** Use if the value is different from the sortBy */
|
|
15
|
+
sortByValue?: string
|
|
16
|
+
align?: 'left' | 'center' | 'right'
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export type TableRow = {
|
|
20
|
+
_id?: string
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export type TableProps<T> = {
|
|
24
|
+
columns: TableColumn[]
|
|
25
|
+
rows: T[]
|
|
26
|
+
generateTd: (col: TableColumn, row: T, i: number, isLast: boolean) => JSX.Element | null
|
|
27
|
+
generateCheckboxActions?: (selectedRowIds: string[]) => JSX.Element | null
|
|
28
|
+
headerHeightMin?: number
|
|
29
|
+
rowHeightMin?: number
|
|
30
|
+
rowContentHeightMax?: number
|
|
31
|
+
rowLinesMax?: number
|
|
32
|
+
rowSideColor?: (row?: T) => { className: string, width: number }
|
|
33
|
+
rowSpacing?: number
|
|
34
|
+
// columnSpacing?: number
|
|
35
|
+
className?: string
|
|
36
|
+
tableClassName?: string
|
|
37
|
+
columnClassName?: string
|
|
38
|
+
columnHeaderClassName?: string
|
|
39
|
+
checkboxClassName?: string
|
|
40
|
+
checkboxSize?: number
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function Table<T extends TableRow>({
|
|
44
|
+
rows,
|
|
45
|
+
columns: columnsProp,
|
|
46
|
+
generateTd,
|
|
47
|
+
generateCheckboxActions,
|
|
48
|
+
headerHeightMin=40,
|
|
49
|
+
rowHeightMin=48,
|
|
50
|
+
rowContentHeightMax,
|
|
51
|
+
rowLinesMax,
|
|
52
|
+
rowSideColor,
|
|
53
|
+
rowSpacing=0,
|
|
54
|
+
// columnSpacing=15,
|
|
55
|
+
className,
|
|
56
|
+
tableClassName,
|
|
57
|
+
columnClassName,
|
|
58
|
+
columnHeaderClassName,
|
|
59
|
+
checkboxClassName,
|
|
60
|
+
checkboxSize=16,
|
|
61
|
+
}: TableProps<T>) {
|
|
62
|
+
const location = useLocation()
|
|
63
|
+
const [selectedRowIds, setSelectedRowIds] = useState<string[]>([])
|
|
64
|
+
const _columnClassName = 'table-cell px-3 py-1 align-middle text-sm border-y border-border ' +
|
|
65
|
+
'first:border-l last:border-r border-t-0 box-border'
|
|
66
|
+
|
|
67
|
+
const columns = useMemo(() => {
|
|
68
|
+
const checkboxCol: TableColumn = { value: 'checkbox', label: '', disableSort: true }
|
|
69
|
+
const cols = (generateCheckboxActions ? [checkboxCol, ...columnsProp] : columnsProp).map((col, _i) => ({
|
|
70
|
+
...col,
|
|
71
|
+
rowLinesMax: typeof col.rowLinesMax != 'undefined' ? col.rowLinesMax : rowLinesMax,
|
|
72
|
+
sortByValue: col.sortByValue || col.value,
|
|
73
|
+
align: col.align || 'left',
|
|
74
|
+
}))
|
|
75
|
+
return cols
|
|
76
|
+
}, [columnsProp])
|
|
77
|
+
|
|
78
|
+
const onSelect = useCallback((idOrAll: string, checked: boolean) => {
|
|
79
|
+
setSelectedRowIds((o) => {
|
|
80
|
+
if (idOrAll == 'all' && checked) return rows.map(row => row?._id||'')
|
|
81
|
+
else if (idOrAll == 'all' && !checked) return []
|
|
82
|
+
else if (o.includes(idOrAll) && !checked) return o.filter(id => id != idOrAll)
|
|
83
|
+
else if (!o.includes(idOrAll) && checked) return [...o, idOrAll]
|
|
84
|
+
else return o
|
|
85
|
+
})
|
|
86
|
+
}, [selectedRowIds, rows])
|
|
87
|
+
|
|
88
|
+
const getAlignClass = useCallback((align: TableColumn['align'], _returnJustify?: boolean) => {
|
|
89
|
+
if (_returnJustify) return align == 'left' ? '' : align == 'center' ? 'justify-center' : 'justify-end'
|
|
90
|
+
else return align == 'left' ? '' : align == 'center' ? 'text-center' : 'text-right'
|
|
91
|
+
}, [])
|
|
92
|
+
|
|
93
|
+
// Reset selected rows when the location changes
|
|
94
|
+
useEffect(() => setSelectedRowIds([]), [location.key])
|
|
95
|
+
|
|
96
|
+
// --- Sorting ---
|
|
97
|
+
|
|
98
|
+
const navigate = useNavigate()
|
|
99
|
+
const query = useMemo(() => ({ ...queryObject(location.search) }), [location.search])
|
|
100
|
+
const sortBy = useMemo(() => query.sortBy || 'createdAt', [query.sortBy])
|
|
101
|
+
const sort = useMemo(() => !query.sort && query.sortBy == 'createdAt' ? '-1' : (query.sort || '1'), [query.sort])
|
|
102
|
+
|
|
103
|
+
const onSort = useCallback((item: TableColumn) => {
|
|
104
|
+
const queryStr = queryString({
|
|
105
|
+
...query,
|
|
106
|
+
sort: sortBy == item.sortByValue ? (sort == '1' ? '-1' : '1') : '1',
|
|
107
|
+
sortBy: item.sortByValue,
|
|
108
|
+
})
|
|
109
|
+
navigate(location.pathname + queryStr, { replace: true })
|
|
110
|
+
}, [location.pathname, query, sort, sortBy])
|
|
111
|
+
|
|
112
|
+
return (
|
|
113
|
+
<div
|
|
114
|
+
style={{ marginTop: -rowSpacing }}
|
|
115
|
+
className={twMerge('overflow-x-auto thin-scrollbar', className)}
|
|
116
|
+
>
|
|
117
|
+
<div
|
|
118
|
+
style={{ borderSpacing: `0 ${rowSpacing}px` }}
|
|
119
|
+
className={twMerge('table w-full border-separate', tableClassName)}
|
|
120
|
+
>
|
|
121
|
+
{/* Thead row */}
|
|
122
|
+
<div className="table-row relative">
|
|
123
|
+
{
|
|
124
|
+
columns.map((col, j) => {
|
|
125
|
+
const disableSort = col.disableSort || selectedRowIds.length
|
|
126
|
+
const sideColor = j == 0 && rowSideColor ? rowSideColor(undefined) : undefined
|
|
127
|
+
return (
|
|
128
|
+
<div
|
|
129
|
+
key={j}
|
|
130
|
+
onClick={disableSort ? undefined : () => onSort(col)}
|
|
131
|
+
style={{ height: headerHeightMin, minWidth: col.minWidth }}
|
|
132
|
+
className={twMerge(
|
|
133
|
+
_columnClassName,
|
|
134
|
+
'h-auto text-sm font-medium border-t-1',
|
|
135
|
+
disableSort ? '' : 'cursor-pointer select-none',
|
|
136
|
+
getAlignClass(col.align),
|
|
137
|
+
columnClassName,
|
|
138
|
+
columnHeaderClassName,
|
|
139
|
+
col.className
|
|
140
|
+
)}
|
|
141
|
+
>
|
|
142
|
+
<div
|
|
143
|
+
style={{
|
|
144
|
+
maxHeight: rowContentHeightMax,
|
|
145
|
+
paddingLeft: sideColor && rows.length > 0 ? sideColor.width + 5 : 0,
|
|
146
|
+
}}
|
|
147
|
+
className={twMerge(
|
|
148
|
+
rowContentHeightMax ? 'overflow-hidden' : '',
|
|
149
|
+
getLineClampClassName(col.rowLinesMax),
|
|
150
|
+
col.overflow ? 'overflow-visible' : '',
|
|
151
|
+
col.innerClassName
|
|
152
|
+
)}
|
|
153
|
+
>
|
|
154
|
+
{
|
|
155
|
+
col.value == 'checkbox'
|
|
156
|
+
? <>
|
|
157
|
+
<Checkbox
|
|
158
|
+
size={checkboxSize}
|
|
159
|
+
name="checkbox-all"
|
|
160
|
+
className='!m-0'
|
|
161
|
+
checkboxClassName={twMerge('border-foreground shadow-[0_1px_2px_0px_#0000001c]', checkboxClassName)}
|
|
162
|
+
onChange={(e) => onSelect('all', e.target.checked)}
|
|
163
|
+
/>
|
|
164
|
+
<div
|
|
165
|
+
className={`${selectedRowIds.length ? 'block' : 'hidden'} [&>*]:absolute [&>*]:inset-y-0 [&>*]:left-[68px] [&>*]:z-10`}
|
|
166
|
+
>
|
|
167
|
+
{generateCheckboxActions && generateCheckboxActions(selectedRowIds)}
|
|
168
|
+
</div>
|
|
169
|
+
</>
|
|
170
|
+
: <span className={twMerge(
|
|
171
|
+
'flex items-center gap-x-2 transition-opacity',
|
|
172
|
+
selectedRowIds.length ? 'opacity-0' : '',
|
|
173
|
+
getAlignClass(col.align, true)
|
|
174
|
+
)}>
|
|
175
|
+
<span>{col.label}</span>
|
|
176
|
+
{
|
|
177
|
+
(!col.disableSort && sortBy == col.sortByValue)
|
|
178
|
+
? (sort == '1'
|
|
179
|
+
? <ChevronDownIcon class='shrink-0 size-[16px]' />
|
|
180
|
+
: <ChevronUpIcon class='shrink-0 size-[16px]' />
|
|
181
|
+
)
|
|
182
|
+
: col.align == 'left' && <div class='size-[16px] shrink-0' /> // prevent layout shift on sort
|
|
183
|
+
}
|
|
184
|
+
</span>
|
|
185
|
+
}
|
|
186
|
+
</div>
|
|
187
|
+
</div>
|
|
188
|
+
)
|
|
189
|
+
})
|
|
190
|
+
}
|
|
191
|
+
</div>
|
|
192
|
+
{/* Tbody rows */}
|
|
193
|
+
{
|
|
194
|
+
rows.map((row: T, i: number) => {
|
|
195
|
+
return (
|
|
196
|
+
<div
|
|
197
|
+
key={`${row._id}-${i}`}
|
|
198
|
+
className={`table-row relative ${selectedRowIds.includes(row?._id||'') ? 'bg-gray-50' : 'bg-white'}`}
|
|
199
|
+
>
|
|
200
|
+
{
|
|
201
|
+
columns.map((col, j) => {
|
|
202
|
+
const sideColor = j == 0 && rowSideColor ? rowSideColor(row) : undefined
|
|
203
|
+
return (
|
|
204
|
+
<div
|
|
205
|
+
key={j}
|
|
206
|
+
style={{ height: rowHeightMin }}
|
|
207
|
+
className={twMerge(
|
|
208
|
+
_columnClassName,
|
|
209
|
+
getAlignClass(col.align),
|
|
210
|
+
columnClassName,
|
|
211
|
+
col.className
|
|
212
|
+
)}
|
|
213
|
+
>
|
|
214
|
+
<div
|
|
215
|
+
style={{
|
|
216
|
+
maxHeight: rowContentHeightMax,
|
|
217
|
+
paddingLeft: sideColor ? sideColor.width + 5 : 0,
|
|
218
|
+
}}
|
|
219
|
+
className={twMerge(
|
|
220
|
+
rowContentHeightMax ? 'overflow-hidden' : '',
|
|
221
|
+
getLineClampClassName(col.rowLinesMax),
|
|
222
|
+
col.overflow ? 'overflow-visible' : '',
|
|
223
|
+
col.innerClassName
|
|
224
|
+
)}
|
|
225
|
+
>
|
|
226
|
+
{
|
|
227
|
+
// Side color
|
|
228
|
+
sideColor &&
|
|
229
|
+
<div
|
|
230
|
+
className={`absolute top-0 left-0 h-full ${sideColor?.className||''}`}
|
|
231
|
+
style={{ width: sideColor.width }}
|
|
232
|
+
/>
|
|
233
|
+
}
|
|
234
|
+
{
|
|
235
|
+
col.value == 'checkbox'
|
|
236
|
+
? <Checkbox
|
|
237
|
+
size={checkboxSize}
|
|
238
|
+
name={`checkbox-${row._id}`}
|
|
239
|
+
onChange={(e) => onSelect(row?._id || '', e.target.checked)}
|
|
240
|
+
checked={selectedRowIds.includes(row?._id || '')}
|
|
241
|
+
className='!m-0'
|
|
242
|
+
checkboxClassName={twMerge('border-foreground shadow-[0_1px_2px_0px_#0000001c]', checkboxClassName)}
|
|
243
|
+
/>
|
|
244
|
+
: generateTd(col, row, i, i == rows.length - 1)
|
|
245
|
+
}
|
|
246
|
+
</div>
|
|
247
|
+
</div>
|
|
248
|
+
)
|
|
249
|
+
})
|
|
250
|
+
}
|
|
251
|
+
</div>
|
|
252
|
+
)
|
|
253
|
+
})
|
|
254
|
+
}
|
|
255
|
+
{
|
|
256
|
+
rows.length == 0 &&
|
|
257
|
+
<div className='table-row relative'>
|
|
258
|
+
{
|
|
259
|
+
columns.map((col, j) => (
|
|
260
|
+
<div
|
|
261
|
+
key={j}
|
|
262
|
+
style={{ height: rowHeightMin }}
|
|
263
|
+
className={twMerge(_columnClassName, columnClassName, col.className)}
|
|
264
|
+
>
|
|
265
|
+
<div
|
|
266
|
+
className={twMerge(
|
|
267
|
+
'absolute top-0 h-full flex items-center justify-center text-sm text-gray-500',
|
|
268
|
+
col.innerClassName
|
|
269
|
+
)}
|
|
270
|
+
>
|
|
271
|
+
{ j == 0 && 'No records found.' }
|
|
272
|
+
</div>
|
|
273
|
+
</div>
|
|
274
|
+
))
|
|
275
|
+
}
|
|
276
|
+
</div>
|
|
277
|
+
}
|
|
278
|
+
</div>
|
|
279
|
+
</div>
|
|
280
|
+
)
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
function getLineClampClassName(num?: number) {
|
|
284
|
+
// Splayed out for tailwind to pick up we are using the classNames below
|
|
285
|
+
if (num == 1) return 'line-clamp-1'
|
|
286
|
+
else if (num == 2) return 'line-clamp-2'
|
|
287
|
+
else if (num == 3) return 'line-clamp-3'
|
|
288
|
+
else if (num == 4) return 'line-clamp-4'
|
|
289
|
+
else if (num == 5) return 'line-clamp-5'
|
|
290
|
+
else if (num == 6) return 'line-clamp-6'
|
|
291
|
+
}
|
|
@@ -1,19 +1,36 @@
|
|
|
1
1
|
import {
|
|
2
2
|
Drop, Dropdown, Field, Select, Button as ButtonNitro, Checkbox, GithubLink, Modal, Calendar, injectedConfig,
|
|
3
|
-
Filters, FiltersHandleType, FilterType,
|
|
3
|
+
Filters, FiltersHandleType, FilterType, Table, TableColumn,
|
|
4
4
|
} from 'nitro-web'
|
|
5
|
-
import { getCountryOptions, getCurrencyOptions, onChange, ucFirst } from 'nitro-web/util'
|
|
6
|
-
import { Check, FileEditIcon } from 'lucide-react'
|
|
5
|
+
import { date, getCountryOptions, getCurrencyOptions, onChange, ucFirst } from 'nitro-web/util'
|
|
6
|
+
import { Check, EllipsisVerticalIcon, FileEditIcon } from 'lucide-react'
|
|
7
|
+
|
|
8
|
+
const perPage = 10
|
|
9
|
+
const statusColors = function(status: string) {
|
|
10
|
+
return {
|
|
11
|
+
pending: 'bg-yellow-400',
|
|
12
|
+
approved: 'bg-green-400',
|
|
13
|
+
rejected: 'bg-red-400',
|
|
14
|
+
}[status]
|
|
15
|
+
}
|
|
7
16
|
|
|
8
17
|
type StyleguideProps = {
|
|
9
18
|
className?: string
|
|
10
|
-
elements?: {
|
|
11
|
-
Button?: typeof ButtonNitro
|
|
12
|
-
}
|
|
19
|
+
elements?: { Button?: typeof ButtonNitro }
|
|
13
20
|
children?: React.ReactNode
|
|
14
21
|
}
|
|
15
22
|
|
|
23
|
+
type QuoteExample = {
|
|
24
|
+
_id?: string
|
|
25
|
+
freightType: string
|
|
26
|
+
destination: { code: string }
|
|
27
|
+
date: number
|
|
28
|
+
weight: number
|
|
29
|
+
status: string
|
|
30
|
+
}
|
|
31
|
+
|
|
16
32
|
export function Styleguide({ className, elements, children }: StyleguideProps) {
|
|
33
|
+
const Button = elements?.Button || ButtonNitro
|
|
17
34
|
const [customerSearch, setCustomerSearch] = useState('')
|
|
18
35
|
const [showModal1, setShowModal1] = useState(false)
|
|
19
36
|
const [state, setState] = useState({
|
|
@@ -28,10 +45,12 @@ export function Styleguide({ className, elements, children }: StyleguideProps) {
|
|
|
28
45
|
'date-time': Date.now(),
|
|
29
46
|
calendar: [Date.now(), Date.now() + 1000 * 60 * 60 * 24 * 8],
|
|
30
47
|
firstName: 'Bruce',
|
|
48
|
+
tableFilter: '',
|
|
31
49
|
errors: [
|
|
32
50
|
{ title: 'address', detail: 'Address is required' },
|
|
33
51
|
],
|
|
34
52
|
})
|
|
53
|
+
|
|
35
54
|
const [filterState, setFilterState] = useState({})
|
|
36
55
|
const filtersRef = useRef<FiltersHandleType>(null)
|
|
37
56
|
const filters = useMemo(() => {
|
|
@@ -79,9 +98,23 @@ export function Styleguide({ className, elements, children }: StyleguideProps) {
|
|
|
79
98
|
{ label: 'Delete' },
|
|
80
99
|
], [])
|
|
81
100
|
|
|
82
|
-
const
|
|
101
|
+
const thead: TableColumn[] = useMemo(() => [
|
|
102
|
+
{ value: 'freightType', label: 'Freight Type' },
|
|
103
|
+
{ value: 'destination.code', label: 'Destination Code' },
|
|
104
|
+
{ value: 'date', label: 'Date' },
|
|
105
|
+
{ value: 'weight', label: 'Weight', align: 'center' },
|
|
106
|
+
{ value: 'status', label: 'Status' },
|
|
107
|
+
{ value: 'actions', label: 'Actions', disableSort: true, overflow: true, minWidth: 100, align: 'right' },
|
|
108
|
+
], [])
|
|
109
|
+
|
|
110
|
+
const rows: QuoteExample[] = useMemo(() => [
|
|
111
|
+
{ _id: '1', freightType: 'air', destination: { code: 'nz' }, date: new Date().getTime(), weight: 100, status: 'pending' },
|
|
112
|
+
{ _id: '2', freightType: 'sea', destination: { code: 'nz' }, date: new Date().getTime(), weight: 200, status: 'approved' },
|
|
113
|
+
{ _id: '3', freightType: 'road', destination: { code: 'au' }, date: new Date().getTime(), weight: 300, status: 'rejected' },
|
|
114
|
+
// normally you should filter the rows on the api using the query string
|
|
115
|
+
].filter((row) => row.freightType.match(new RegExp(state.tableFilter, 'i'))), [state.tableFilter])
|
|
83
116
|
|
|
84
|
-
|
|
117
|
+
const onCustomerInputChange = (e: { target: { name: string, value: unknown } }) => {
|
|
85
118
|
if (e.target.name == 'customer' && e.target.value == '0') {
|
|
86
119
|
setCustomerSearch('')
|
|
87
120
|
e.target.value = null // clear the select's selected value
|
|
@@ -90,10 +123,45 @@ export function Styleguide({ className, elements, children }: StyleguideProps) {
|
|
|
90
123
|
onChange(setState, e)
|
|
91
124
|
}
|
|
92
125
|
|
|
93
|
-
|
|
126
|
+
const onCustomerSearch = (search: string) => {
|
|
94
127
|
setCustomerSearch(search || '')
|
|
95
128
|
}
|
|
96
129
|
|
|
130
|
+
const generateCheckboxActions = useCallback((selectedRowIds: string[]) => {
|
|
131
|
+
return <div class='flex items-center gap-x-2'>
|
|
132
|
+
<Button size='xs' color='dark' onClick={() => { console.log('set', selectedRowIds) }}>Set Status</Button>
|
|
133
|
+
<Button size='xs' color='dark' onClick={() => { console.log('remove', selectedRowIds) }}>Delete</Button>
|
|
134
|
+
</div>
|
|
135
|
+
}, [])
|
|
136
|
+
|
|
137
|
+
const generateTd = useCallback((col: TableColumn, row: QuoteExample, i: number) => {
|
|
138
|
+
switch (col.value) {
|
|
139
|
+
case 'freightType':
|
|
140
|
+
return <div>{ucFirst(row.freightType)}</div>
|
|
141
|
+
case 'destination.code':
|
|
142
|
+
return <div>{row.destination.code.toUpperCase()}</div>
|
|
143
|
+
case 'date':
|
|
144
|
+
return <div>{date(row.date, 'dd mmm, yyyy')}</div>
|
|
145
|
+
case 'weight':
|
|
146
|
+
return <div>{row.weight}</div>
|
|
147
|
+
case 'status':
|
|
148
|
+
return <div>{ucFirst(row.status)}</div>
|
|
149
|
+
case 'actions':
|
|
150
|
+
return (
|
|
151
|
+
<Dropdown
|
|
152
|
+
options={[{ label: 'Set Status' }, { label: 'Delete' }]}
|
|
153
|
+
dir={rows.slice(0, perPage).length - 3 < i ? 'top-right' : 'bottom-right'}
|
|
154
|
+
minWidth={100}
|
|
155
|
+
>
|
|
156
|
+
<Button color='clear' className='ring-0' size='sm' IconCenter={<EllipsisVerticalIcon size={18} strokeWidth={1.5} />} />
|
|
157
|
+
</Dropdown>
|
|
158
|
+
)
|
|
159
|
+
default:
|
|
160
|
+
console.error(`Error: unexpected thead value: ${col.value}`)
|
|
161
|
+
return null
|
|
162
|
+
}
|
|
163
|
+
}, [rows.length])
|
|
164
|
+
|
|
97
165
|
// Example of updating state
|
|
98
166
|
// useEffect(() => {
|
|
99
167
|
// setTimeout(() => {
|
|
@@ -103,6 +171,24 @@ export function Styleguide({ className, elements, children }: StyleguideProps) {
|
|
|
103
171
|
|
|
104
172
|
return (
|
|
105
173
|
<div class={`text-left max-w-[1100px] ${className}`}>
|
|
174
|
+
<Modal show={showModal1} setShow={setShowModal1}>
|
|
175
|
+
<h3 class="h3">Edit Profile</h3>
|
|
176
|
+
<p class="mb-5">An example modal containing a basic form for editing profiles.</p>
|
|
177
|
+
<form class="mb-8 text-left">
|
|
178
|
+
<div>
|
|
179
|
+
<label for="firstName2">First Name</label>
|
|
180
|
+
<Field name="firstName2" state={state} onChange={(e) => onChange(setState, e)} />
|
|
181
|
+
</div>
|
|
182
|
+
<div>
|
|
183
|
+
<label for="email2">Email Address</label>
|
|
184
|
+
<Field name="email2" type="email" placeholder="Your email address..."/>
|
|
185
|
+
</div>
|
|
186
|
+
</form>
|
|
187
|
+
<div class="flex justify-end">
|
|
188
|
+
<Button color="primary" onClick={() => setShowModal1(false)}>Save</Button>
|
|
189
|
+
</div>
|
|
190
|
+
</Modal>
|
|
191
|
+
|
|
106
192
|
<GithubLink filename={__filename} />
|
|
107
193
|
<div class="mb-7">
|
|
108
194
|
<h1 class="h1">{injectedConfig.isDemo ? 'Design System' : 'Style Guide'}</h1>
|
|
@@ -367,26 +453,8 @@ export function Styleguide({ className, elements, children }: StyleguideProps) {
|
|
|
367
453
|
</div>
|
|
368
454
|
</div>
|
|
369
455
|
|
|
370
|
-
<Modal show={showModal1} setShow={setShowModal1}>
|
|
371
|
-
<h3 class="h3">Edit Profile</h3>
|
|
372
|
-
<p class="mb-5">An example modal containing a basic form for editing profiles.</p>
|
|
373
|
-
<form class="mb-8 text-left">
|
|
374
|
-
<div>
|
|
375
|
-
<label for="firstName2">First Name</label>
|
|
376
|
-
<Field name="firstName2" state={state} onChange={(e) => onChange(setState, e)} />
|
|
377
|
-
</div>
|
|
378
|
-
<div>
|
|
379
|
-
<label for="email2">Email Address</label>
|
|
380
|
-
<Field name="email2" type="email" placeholder="Your email address..."/>
|
|
381
|
-
</div>
|
|
382
|
-
</form>
|
|
383
|
-
<div class="flex justify-end">
|
|
384
|
-
<Button color="primary" onClick={() => setShowModal1(false)}>Save</Button>
|
|
385
|
-
</div>
|
|
386
|
-
</Modal>
|
|
387
|
-
|
|
388
456
|
<h2 class="h3">File Inputs & Calendar</h2>
|
|
389
|
-
<div class="grid grid-cols-3 gap-x-6 mb-4
|
|
457
|
+
<div class="grid grid-cols-3 gap-x-6 mb-4">
|
|
390
458
|
<div>
|
|
391
459
|
<label for="avatar">Avatar</label>
|
|
392
460
|
<Drop class="is-small" name="avatar" state={state} onChange={(e) => onChange(setState, e)} awsUrl={injectedConfig.awsUrl} />
|
|
@@ -401,6 +469,44 @@ export function Styleguide({ className, elements, children }: StyleguideProps) {
|
|
|
401
469
|
</div>
|
|
402
470
|
</div>
|
|
403
471
|
|
|
472
|
+
<div class="flex justify-between items-start">
|
|
473
|
+
<h2 class="h3">Tables</h2>
|
|
474
|
+
<Field
|
|
475
|
+
name="tableFilter"
|
|
476
|
+
type="search"
|
|
477
|
+
state={state}
|
|
478
|
+
placeholder="Basic table filter..."
|
|
479
|
+
onChange={(e) => onChange(setState, e)}
|
|
480
|
+
className="!my-0 [&>input]:font-normal [&>input]:text-xs [&>input]:py-1.5" /////todo: need to allow twmerge here
|
|
481
|
+
/>
|
|
482
|
+
</div>
|
|
483
|
+
<div class="grid mb-4 last:mb-0">
|
|
484
|
+
<Table
|
|
485
|
+
rows={rows.slice(0, perPage)}
|
|
486
|
+
columns={thead}
|
|
487
|
+
rowSideColor={(row) => ({ className: row?.status == 'pending' ? 'bg-yellow-400' : '', width: 5 })}
|
|
488
|
+
generateCheckboxActions={generateCheckboxActions}
|
|
489
|
+
generateTd={generateTd}
|
|
490
|
+
className="mb-6"
|
|
491
|
+
/>
|
|
492
|
+
<Table
|
|
493
|
+
rows={rows.slice(0, 2)}
|
|
494
|
+
columns={thead}
|
|
495
|
+
rowLinesMax={1}
|
|
496
|
+
headerHeightMin={35}
|
|
497
|
+
rowSpacing={8}
|
|
498
|
+
rowHeightMin={52}
|
|
499
|
+
rowSideColor={(row) => ({ className: `rounded-l-xl ${statusColors(row?.status as string)}`, width: 10 })}
|
|
500
|
+
generateCheckboxActions={generateCheckboxActions}
|
|
501
|
+
generateTd={generateTd}
|
|
502
|
+
tableClassName="rounded-3px"
|
|
503
|
+
columnClassName="border-t-1 first:rounded-l-xl last:rounded-r-xl"
|
|
504
|
+
columnHeaderClassName="text-gray-500 text-2xs uppercase border-none"
|
|
505
|
+
checkboxClassName="rounded-[2px] shadow-none"
|
|
506
|
+
className="mb-5"
|
|
507
|
+
/>
|
|
508
|
+
</div>
|
|
509
|
+
|
|
404
510
|
{children}
|
|
405
511
|
</div>
|
|
406
512
|
)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nitro-web",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.104",
|
|
4
4
|
"repository": "github:boycce/nitro-web",
|
|
5
5
|
"homepage": "https://boycce.github.io/nitro-web/",
|
|
6
6
|
"description": "Nitro is a battle-tested, modular base project to turbocharge your projects, styled using Tailwind 🚀",
|