goobs-frontend 0.9.33 → 0.9.35

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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "goobs-frontend",
3
- "version": "0.9.33",
3
+ "version": "0.9.35",
4
4
  "type": "module",
5
5
  "description": "A comprehensive React-based libary that extends the functionality of Material-UI",
6
6
  "license": "MIT",
@@ -37,10 +37,10 @@
37
37
  "next": "15",
38
38
  "otplib": "^12",
39
39
  "react-qr-code": "^2",
40
- "slate": "^0.115",
41
- "slate-dom": "^0.114",
40
+ "slate": "^0.117",
41
+ "slate-dom": "^0.116",
42
42
  "slate-history": "^0.113",
43
- "slate-react": "^0.114",
43
+ "slate-react": "^0.117",
44
44
  "storybook": "^9",
45
45
  "zod": "^3",
46
46
  "zod-formik-adapter": "^1"
@@ -55,7 +55,7 @@
55
55
  "@types/react-dom": "^19",
56
56
  "@typescript-eslint/eslint-plugin": "^8",
57
57
  "@typescript-eslint/parser": "^8",
58
- "chromatic": "^12",
58
+ "chromatic": "^13",
59
59
  "eslint": "^9",
60
60
  "eslint-config-next": "^15",
61
61
  "eslint-config-prettier": "^10",
@@ -0,0 +1,257 @@
1
+ 'use client'
2
+
3
+ import React from 'react'
4
+ import { Box, Grid, useMediaQuery, keyframes, alpha } from '@mui/material'
5
+ import SearchableDropdown from '../../Field/Dropdown/Searchable'
6
+ import DateField from '../../Field/Date/DateField'
7
+ import DateRange from '../../Field/Date/DateRange'
8
+ import { DataGridFilter } from '../types'
9
+
10
+ // Sacred theming animations
11
+ const sacredGlow = keyframes`
12
+ 0% { box-shadow: 0 0 10px rgba(255, 215, 0, 0.3); }
13
+ 50% { box-shadow: 0 0 20px rgba(255, 215, 0, 0.5); }
14
+ 100% { box-shadow: 0 0 10px rgba(255, 215, 0, 0.3); }
15
+ `
16
+
17
+ const sacredFloat = keyframes`
18
+ 0% { transform: translateY(0px); }
19
+ 50% { transform: translateY(-2px); }
20
+ 100% { transform: translateY(0px); }
21
+ `
22
+
23
+ const rotateGlyph = keyframes`
24
+ from { transform: rotate(0deg); }
25
+ to { transform: rotate(360deg); }
26
+ `
27
+
28
+ // Sacred hieroglyphs for decoration
29
+ const SACRED_GLYPHS = [
30
+ '𓁟',
31
+ '𓂀',
32
+ '𓃀',
33
+ '𓄿',
34
+ '𓊖',
35
+ '𓊗',
36
+ '𓋴',
37
+ '𓏏',
38
+ '𓊨',
39
+ '𓁦',
40
+ '𓅓',
41
+ '𓆄',
42
+ '𓇳',
43
+ '𓈖',
44
+ '𓊹',
45
+ '𓊺',
46
+ '𓊻',
47
+ '𓋹',
48
+ '𓌻',
49
+ '𓍿',
50
+ '𓅨',
51
+ '𓂋',
52
+ '𓏭',
53
+ '𓊵',
54
+ ]
55
+
56
+ export interface FilterSectionProps {
57
+ filters: DataGridFilter[]
58
+ sacredtheme?: boolean
59
+ }
60
+
61
+ const FilterSection: React.FC<FilterSectionProps> = ({
62
+ filters,
63
+ sacredtheme = false,
64
+ }) => {
65
+ const isMobile = useMediaQuery('(max-width:600px)')
66
+ const isTablet = useMediaQuery('(max-width:900px)')
67
+
68
+ if (!filters || filters.length === 0) {
69
+ return null
70
+ }
71
+
72
+ // Determine grid size based on screen size and number of filters
73
+ const getGridSize = () => {
74
+ if (isMobile) {
75
+ return 12 // Full width on mobile
76
+ }
77
+ if (isTablet) {
78
+ return filters.length === 1 ? 6 : 12 / Math.min(filters.length, 2) // Max 2 per row on tablet
79
+ }
80
+ // Desktop - up to 4 filters per row, but scale based on count
81
+ if (filters.length === 1) return 3
82
+ if (filters.length === 2) return 6
83
+ if (filters.length === 3) return 4
84
+ return 3 // 4 filters per row max
85
+ }
86
+
87
+ const gridSize = getGridSize()
88
+
89
+ // Helper function to render the appropriate filter component
90
+ const renderFilterComponent = (filter: DataGridFilter) => {
91
+ // Check if this is a date range filter
92
+ if (filter.type === 'daterange') {
93
+ return (
94
+ <DateRange
95
+ startLabel="From Date"
96
+ endLabel="To Date"
97
+ value={filter.value as { start: Date | null; end: Date | null }}
98
+ onChange={
99
+ filter.onChange as (value: {
100
+ start: Date | null
101
+ end: Date | null
102
+ }) => void
103
+ }
104
+ sacredtheme={sacredtheme}
105
+ style={{
106
+ marginBottom: '8px',
107
+ width: filter.width || '100%',
108
+ }}
109
+ />
110
+ )
111
+ }
112
+
113
+ // Check if this is a date filter
114
+ if (filter.type === 'date') {
115
+ return (
116
+ <DateField
117
+ label={filter.label}
118
+ value={
119
+ (filter.value as string) ? new Date(filter.value as string) : null
120
+ }
121
+ onChange={filter.onChange as (date: Date | null) => void}
122
+ placeholder={filter.placeholder}
123
+ sacredtheme={sacredtheme}
124
+ disableFutureDateValidation={true}
125
+ style={{
126
+ marginBottom: '8px',
127
+ width: filter.width || '100%',
128
+ }}
129
+ />
130
+ )
131
+ }
132
+
133
+ // Default to SearchableDropdown for regular filters
134
+ return (
135
+ <SearchableDropdown
136
+ label={filter.label}
137
+ options={filter.options || []}
138
+ defaultValue={filter.value === 'all' ? '' : (filter.value as string)}
139
+ onChange={filter.onChange as (value: { value: string } | null) => void}
140
+ placeholder={filter.placeholder}
141
+ width={filter.width || '100%'}
142
+ variant="simple"
143
+ sacredtheme={sacredtheme}
144
+ sacredTitle={sacredtheme ? 'Divine Filtering' : ''}
145
+ sacredSubtitle={sacredtheme ? 'Channel cosmic data streams' : ''}
146
+ style={{
147
+ marginBottom: '8px',
148
+ }}
149
+ />
150
+ )
151
+ }
152
+
153
+ return (
154
+ <Box
155
+ sx={{
156
+ width: '100%',
157
+ position: 'relative',
158
+ p: sacredtheme ? 1 : 0.5,
159
+ ...(sacredtheme && {
160
+ backgroundColor: alpha('#000000', 0.6),
161
+ borderRadius: '8px',
162
+ border: `1px solid ${alpha('#FFD700', 0.3)}`,
163
+ backgroundImage: `
164
+ linear-gradient(rgba(255, 215, 0, 0.02), rgba(255, 215, 0, 0.02)),
165
+ radial-gradient(circle at top left, rgba(255, 215, 0, 0.08) 0%, transparent 50%)
166
+ `,
167
+ animation: `${sacredGlow} 3s ease-in-out infinite`,
168
+ '&::before': {
169
+ content: '"𓊹"',
170
+ position: 'absolute',
171
+ top: '8px',
172
+ right: '12px',
173
+ fontSize: '14px',
174
+ color: alpha('#FFD700', 0.4),
175
+ animation: `${rotateGlyph} 15s linear infinite`,
176
+ zIndex: 1,
177
+ },
178
+ }),
179
+ }}
180
+ >
181
+ {/* Sacred decorative glyphs */}
182
+ {sacredtheme && (
183
+ <>
184
+ <Box
185
+ sx={{
186
+ position: 'absolute',
187
+ top: '8px',
188
+ left: '8px',
189
+ color: alpha('#FFD700', 0.3),
190
+ fontSize: '12px',
191
+ animation: `${sacredFloat} 4s ease-in-out infinite`,
192
+ zIndex: 1,
193
+ }}
194
+ >
195
+ {SACRED_GLYPHS[15]} {/* Filter/sieve symbol */}
196
+ </Box>
197
+ <Box
198
+ sx={{
199
+ position: 'absolute',
200
+ bottom: '8px',
201
+ right: '8px',
202
+ color: alpha('#FFD700', 0.3),
203
+ fontSize: '12px',
204
+ animation: `${sacredFloat} 3s ease-in-out infinite reverse`,
205
+ zIndex: 1,
206
+ }}
207
+ >
208
+ {SACRED_GLYPHS[16]} {/* Filter/refine symbol */}
209
+ </Box>
210
+ </>
211
+ )}
212
+
213
+ <Grid container spacing={1}>
214
+ {filters.map((filter, index) => (
215
+ <Grid
216
+ key={`${filter.label}-${index}`}
217
+ size={{
218
+ xs: isMobile ? 12 : filter.type === 'daterange' ? 6 : gridSize,
219
+ }}
220
+ >
221
+ {renderFilterComponent(filter)}
222
+ </Grid>
223
+ ))}
224
+ </Grid>
225
+
226
+ {/* Bottom sacred decoration */}
227
+ {sacredtheme && (
228
+ <Box
229
+ sx={{
230
+ position: 'absolute',
231
+ bottom: '4px',
232
+ left: '50%',
233
+ transform: 'translateX(-50%)',
234
+ display: 'flex',
235
+ gap: 0.5,
236
+ opacity: 0.5,
237
+ }}
238
+ >
239
+ {['𓊖', '𓊗', '𓊖'].map((glyph, i) => (
240
+ <Box
241
+ key={i}
242
+ sx={{
243
+ color: alpha('#FFD700', 0.4),
244
+ fontSize: 8,
245
+ animation: `${sacredFloat} ${2 + i * 0.3}s ease-in-out infinite`,
246
+ }}
247
+ >
248
+ {glyph}
249
+ </Box>
250
+ ))}
251
+ </Box>
252
+ )}
253
+ </Box>
254
+ )
255
+ }
256
+
257
+ export default FilterSection
@@ -178,161 +178,162 @@ function ManageRow({
178
178
  sx={{ '& > div:not(:last-child)': { marginRight: '2px' } }}
179
179
  >
180
180
  {/* If exactly 1 item selected, show Manage / Show / Duplicate */}
181
- {selectedRows.length === 1 && (
182
- <Box
183
- display="flex"
184
- flexDirection="row"
185
- alignItems="center"
186
- sx={{
187
- borderRight: sacredtheme
188
- ? `1px solid ${alpha(egyptianStyles.goldColor, 0.3)}`
189
- : '1px solid #e0e0e0',
190
- paddingRight: '8px',
191
- marginRight: '8px',
192
- }}
193
- >
194
- {onManage && (
195
- <Box
196
- onClick={e => {
197
- e.stopPropagation()
198
- handleActionSelection('manage')
199
- }}
200
- display="flex"
201
- flexDirection="column"
202
- alignItems="center"
203
- sx={{
204
- padding: '8px',
205
- cursor: 'pointer',
206
- '&:hover': {
207
- backgroundColor: sacredtheme
208
- ? alpha(egyptianStyles.goldColor, 0.1)
209
- : 'rgba(0, 0, 0, 0.04)',
210
- },
211
- borderRadius: '4px',
212
- transition: 'background-color 0.2s',
213
- userSelect: 'none',
214
- }}
215
- >
181
+ {selectedRows.length === 1 &&
182
+ (onManage || onShow || (onDuplicate && !isMobile)) && (
183
+ <Box
184
+ display="flex"
185
+ flexDirection="row"
186
+ alignItems="center"
187
+ sx={{
188
+ borderRight: sacredtheme
189
+ ? `1px solid ${alpha(egyptianStyles.goldColor, 0.3)}`
190
+ : '1px solid #e0e0e0',
191
+ paddingRight: '8px',
192
+ marginRight: '8px',
193
+ }}
194
+ >
195
+ {onManage && (
216
196
  <Box
197
+ onClick={e => {
198
+ e.stopPropagation()
199
+ handleActionSelection('manage')
200
+ }}
201
+ display="flex"
202
+ flexDirection="column"
203
+ alignItems="center"
217
204
  sx={{
218
- display: 'flex',
219
- flexDirection: 'column',
220
- alignItems: 'center',
221
- color: sacredtheme ? egyptianStyles.goldColor : 'black',
205
+ padding: '8px',
206
+ cursor: 'pointer',
207
+ '&:hover': {
208
+ backgroundColor: sacredtheme
209
+ ? alpha(egyptianStyles.goldColor, 0.1)
210
+ : 'rgba(0, 0, 0, 0.04)',
211
+ },
212
+ borderRadius: '4px',
213
+ transition: 'background-color 0.2s',
214
+ userSelect: 'none',
222
215
  }}
223
216
  >
224
- <EditIcon />
225
- <Typography
226
- fontvariant="merriparagraph"
227
- text="Manage"
228
- fontcolor={
229
- sacredtheme ? egyptianStyles.goldColor : undefined
230
- }
231
- sx={
232
- sacredtheme
233
- ? { fontFamily: '"Crimson Text", serif' }
234
- : {}
235
- }
236
- />
217
+ <Box
218
+ sx={{
219
+ display: 'flex',
220
+ flexDirection: 'column',
221
+ alignItems: 'center',
222
+ color: sacredtheme ? egyptianStyles.goldColor : 'black',
223
+ }}
224
+ >
225
+ <EditIcon />
226
+ <Typography
227
+ fontvariant="merriparagraph"
228
+ text="Manage"
229
+ fontcolor={
230
+ sacredtheme ? egyptianStyles.goldColor : undefined
231
+ }
232
+ sx={
233
+ sacredtheme
234
+ ? { fontFamily: '"Crimson Text", serif' }
235
+ : {}
236
+ }
237
+ />
238
+ </Box>
237
239
  </Box>
238
- </Box>
239
- )}
240
+ )}
240
241
 
241
- {onShow && (
242
- <Box
243
- onClick={e => {
244
- e.stopPropagation()
245
- handleActionSelection('show')
246
- }}
247
- display="flex"
248
- flexDirection="column"
249
- alignItems="center"
250
- sx={{
251
- padding: '8px',
252
- cursor: 'pointer',
253
- '&:hover': {
254
- backgroundColor: sacredtheme
255
- ? alpha(egyptianStyles.goldColor, 0.1)
256
- : 'rgba(0, 0, 0, 0.04)',
257
- },
258
- borderRadius: '4px',
259
- transition: 'background-color 0.2s',
260
- userSelect: 'none',
261
- }}
262
- >
242
+ {onShow && (
263
243
  <Box
244
+ onClick={e => {
245
+ e.stopPropagation()
246
+ handleActionSelection('show')
247
+ }}
248
+ display="flex"
249
+ flexDirection="column"
250
+ alignItems="center"
264
251
  sx={{
265
- display: 'flex',
266
- flexDirection: 'column',
267
- alignItems: 'center',
268
- color: sacredtheme ? egyptianStyles.goldColor : 'black',
252
+ padding: '8px',
253
+ cursor: 'pointer',
254
+ '&:hover': {
255
+ backgroundColor: sacredtheme
256
+ ? alpha(egyptianStyles.goldColor, 0.1)
257
+ : 'rgba(0, 0, 0, 0.04)',
258
+ },
259
+ borderRadius: '4px',
260
+ transition: 'background-color 0.2s',
261
+ userSelect: 'none',
269
262
  }}
270
263
  >
271
- <VisibilityIcon />
272
- <Typography
273
- fontvariant="merriparagraph"
274
- text="Show"
275
- fontcolor={
276
- sacredtheme ? egyptianStyles.goldColor : undefined
277
- }
278
- sx={
279
- sacredtheme
280
- ? { fontFamily: '"Crimson Text", serif' }
281
- : {}
282
- }
283
- />
264
+ <Box
265
+ sx={{
266
+ display: 'flex',
267
+ flexDirection: 'column',
268
+ alignItems: 'center',
269
+ color: sacredtheme ? egyptianStyles.goldColor : 'black',
270
+ }}
271
+ >
272
+ <VisibilityIcon />
273
+ <Typography
274
+ fontvariant="merriparagraph"
275
+ text="Show"
276
+ fontcolor={
277
+ sacredtheme ? egyptianStyles.goldColor : undefined
278
+ }
279
+ sx={
280
+ sacredtheme
281
+ ? { fontFamily: '"Crimson Text", serif' }
282
+ : {}
283
+ }
284
+ />
285
+ </Box>
284
286
  </Box>
285
- </Box>
286
- )}
287
+ )}
287
288
 
288
- {onDuplicate && !isMobile && (
289
- <Box
290
- onClick={e => {
291
- e.stopPropagation()
292
- handleActionSelection('duplicate')
293
- }}
294
- display="flex"
295
- flexDirection="column"
296
- alignItems="center"
297
- sx={{
298
- padding: '8px',
299
- cursor: 'pointer',
300
- '&:hover': {
301
- backgroundColor: sacredtheme
302
- ? alpha(egyptianStyles.goldColor, 0.1)
303
- : 'rgba(0, 0, 0, 0.04)',
304
- },
305
- borderRadius: '4px',
306
- transition: 'background-color 0.2s',
307
- userSelect: 'none',
308
- }}
309
- >
289
+ {onDuplicate && !isMobile && (
310
290
  <Box
291
+ onClick={e => {
292
+ e.stopPropagation()
293
+ handleActionSelection('duplicate')
294
+ }}
295
+ display="flex"
296
+ flexDirection="column"
297
+ alignItems="center"
311
298
  sx={{
312
- display: 'flex',
313
- flexDirection: 'column',
314
- alignItems: 'center',
315
- color: sacredtheme ? egyptianStyles.goldColor : 'black',
299
+ padding: '8px',
300
+ cursor: 'pointer',
301
+ '&:hover': {
302
+ backgroundColor: sacredtheme
303
+ ? alpha(egyptianStyles.goldColor, 0.1)
304
+ : 'rgba(0, 0, 0, 0.04)',
305
+ },
306
+ borderRadius: '4px',
307
+ transition: 'background-color 0.2s',
308
+ userSelect: 'none',
316
309
  }}
317
310
  >
318
- <DuplicateIcon />
319
- <Typography
320
- fontvariant="merriparagraph"
321
- text="Duplicate"
322
- fontcolor={
323
- sacredtheme ? egyptianStyles.goldColor : undefined
324
- }
325
- sx={
326
- sacredtheme
327
- ? { fontFamily: '"Crimson Text", serif' }
328
- : {}
329
- }
330
- />
311
+ <Box
312
+ sx={{
313
+ display: 'flex',
314
+ flexDirection: 'column',
315
+ alignItems: 'center',
316
+ color: sacredtheme ? egyptianStyles.goldColor : 'black',
317
+ }}
318
+ >
319
+ <DuplicateIcon />
320
+ <Typography
321
+ fontvariant="merriparagraph"
322
+ text="Duplicate"
323
+ fontcolor={
324
+ sacredtheme ? egyptianStyles.goldColor : undefined
325
+ }
326
+ sx={
327
+ sacredtheme
328
+ ? { fontFamily: '"Crimson Text", serif' }
329
+ : {}
330
+ }
331
+ />
332
+ </Box>
331
333
  </Box>
332
- </Box>
333
- )}
334
- </Box>
335
- )}
334
+ )}
335
+ </Box>
336
+ )}
336
337
 
337
338
  {/* Delete and Export - shown for any number of selected rows */}
338
339
  <Box display="flex" flexDirection="row" alignItems="center">