@instantdb/components 0.0.1
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/.env +2 -0
- package/.turbo/turbo-build.log +18 -0
- package/README.md +78 -0
- package/app/App.css +38 -0
- package/app/App.tsx +61 -0
- package/app/index.css +18 -0
- package/app/main.tsx +10 -0
- package/dist/components/StyleMe.d.ts +15 -0
- package/dist/components/StyleMe.d.ts.map +1 -0
- package/dist/components/error-boundary.d.ts +17 -0
- package/dist/components/error-boundary.d.ts.map +1 -0
- package/dist/components/explorer/edit-namespace-dialog.d.ts +14 -0
- package/dist/components/explorer/edit-namespace-dialog.d.ts.map +1 -0
- package/dist/components/explorer/edit-row-dialog.d.ts +10 -0
- package/dist/components/explorer/edit-row-dialog.d.ts.map +1 -0
- package/dist/components/explorer/expandable-deleted-attr.d.ts +15 -0
- package/dist/components/explorer/expandable-deleted-attr.d.ts.map +1 -0
- package/dist/components/explorer/explorer-layout.d.ts +8 -0
- package/dist/components/explorer/explorer-layout.d.ts.map +1 -0
- package/dist/components/explorer/index.d.ts +44 -0
- package/dist/components/explorer/index.d.ts.map +1 -0
- package/dist/components/explorer/inner-explorer.d.ts +16 -0
- package/dist/components/explorer/inner-explorer.d.ts.map +1 -0
- package/dist/components/explorer/new-namespace-dialog.d.ts +10 -0
- package/dist/components/explorer/new-namespace-dialog.d.ts.map +1 -0
- package/dist/components/explorer/query-inspector.d.ts +11 -0
- package/dist/components/explorer/query-inspector.d.ts.map +1 -0
- package/dist/components/explorer/recently-deleted.d.ts +36 -0
- package/dist/components/explorer/recently-deleted.d.ts.map +1 -0
- package/dist/components/explorer/search-input.d.ts +9 -0
- package/dist/components/explorer/search-input.d.ts.map +1 -0
- package/dist/components/explorer/table-components.d.ts +16 -0
- package/dist/components/explorer/table-components.d.ts.map +1 -0
- package/dist/components/explorer/view-settings.d.ts +10 -0
- package/dist/components/explorer/view-settings.d.ts.map +1 -0
- package/dist/components/rosePineDawnTheme.d.ts +13 -0
- package/dist/components/rosePineDawnTheme.d.ts.map +1 -0
- package/dist/components/select.d.ts +16 -0
- package/dist/components/select.d.ts.map +1 -0
- package/dist/components/toast.d.ts +4 -0
- package/dist/components/toast.d.ts.map +1 -0
- package/dist/components/ui.d.ts +336 -0
- package/dist/components/ui.d.ts.map +1 -0
- package/dist/config.d.ts +14 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/hooks/explorer.d.ts +29 -0
- package/dist/hooks/explorer.d.ts.map +1 -0
- package/dist/hooks/useAttrNotes.d.ts +10 -0
- package/dist/hooks/useAttrNotes.d.ts.map +1 -0
- package/dist/hooks/useClickOutside.d.ts +3 -0
- package/dist/hooks/useClickOutside.d.ts.map +1 -0
- package/dist/hooks/useColumnVisibility.d.ts +12 -0
- package/dist/hooks/useColumnVisibility.d.ts.map +1 -0
- package/dist/hooks/useEditBlobConstraints.d.ts +32 -0
- package/dist/hooks/useEditBlobConstraints.d.ts.map +1 -0
- package/dist/hooks/useExplorerHistory.d.ts +1 -0
- package/dist/hooks/useExplorerHistory.d.ts.map +1 -0
- package/dist/hooks/useIsOverflow.d.ts +6 -0
- package/dist/hooks/useIsOverflow.d.ts.map +1 -0
- package/dist/hooks/useLocalStorage.d.ts +2 -0
- package/dist/hooks/useLocalStorage.d.ts.map +1 -0
- package/dist/hooks/useMonacoJSONSchema.d.ts +3 -0
- package/dist/hooks/useMonacoJSONSchema.d.ts.map +1 -0
- package/dist/hooks/useStableDB.d.ts +7 -0
- package/dist/hooks/useStableDB.d.ts.map +1 -0
- package/dist/index.cjs +15 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9270 -0
- package/dist/schema.d.ts +5 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/style.css +1 -0
- package/dist/types.d.ts +241 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/utils/format.d.ts +2 -0
- package/dist/utils/format.d.ts.map +1 -0
- package/dist/utils/indexingJobs.d.ts +24 -0
- package/dist/utils/indexingJobs.d.ts.map +1 -0
- package/dist/utils/parsePermsJSON.d.ts +11 -0
- package/dist/utils/parsePermsJSON.d.ts.map +1 -0
- package/dist/utils/renames.d.ts +3 -0
- package/dist/utils/renames.d.ts.map +1 -0
- package/dist/utils/tableWidthSize.d.ts +9 -0
- package/dist/utils/tableWidthSize.d.ts.map +1 -0
- package/index.html +13 -0
- package/package.json +109 -0
- package/src/components/StyleMe.tsx +97 -0
- package/src/components/error-boundary.tsx +76 -0
- package/src/components/explorer/edit-namespace-dialog.tsx +1886 -0
- package/src/components/explorer/edit-row-dialog.tsx +1151 -0
- package/src/components/explorer/expandable-deleted-attr.tsx +170 -0
- package/src/components/explorer/explorer-layout.tsx +156 -0
- package/src/components/explorer/index.tsx +217 -0
- package/src/components/explorer/inner-explorer.tsx +1341 -0
- package/src/components/explorer/new-namespace-dialog.tsx +54 -0
- package/src/components/explorer/query-inspector.tsx +394 -0
- package/src/components/explorer/recently-deleted.tsx +344 -0
- package/src/components/explorer/search-input.tsx +358 -0
- package/src/components/explorer/table-components.tsx +341 -0
- package/src/components/explorer/view-settings.tsx +75 -0
- package/src/components/rosePineDawnTheme.ts +45 -0
- package/src/components/select.tsx +198 -0
- package/src/components/toast.tsx +18 -0
- package/src/components/ui.tsx +1561 -0
- package/src/config.ts +61 -0
- package/src/hooks/explorer.tsx +125 -0
- package/src/hooks/useAttrNotes.ts +27 -0
- package/src/hooks/useClickOutside.ts +23 -0
- package/src/hooks/useColumnVisibility.ts +39 -0
- package/src/hooks/useEditBlobConstraints.ts +185 -0
- package/src/hooks/useExplorerHistory.ts +0 -0
- package/src/hooks/useIsOverflow.ts +24 -0
- package/src/hooks/useLocalStorage.ts +51 -0
- package/src/hooks/useMonacoJSONSchema.ts +41 -0
- package/src/hooks/useStableDB.ts +30 -0
- package/src/index.tsx +8 -0
- package/src/schema.ts +285 -0
- package/src/style.css +5 -0
- package/src/types.ts +359 -0
- package/src/utils/format.ts +13 -0
- package/src/utils/indexingJobs.ts +126 -0
- package/src/utils/parsePermsJSON.ts +35 -0
- package/src/utils/renames.ts +42 -0
- package/src/utils/tableWidthSize.ts +62 -0
- package/tailwind.config.cjs +42 -0
- package/tsconfig.json +22 -0
- package/vite-env.d.ts +1 -0
- package/vite.config.ts +49 -0
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import {
|
|
3
|
+
cn,
|
|
4
|
+
Fence,
|
|
5
|
+
Tooltip,
|
|
6
|
+
TooltipContent,
|
|
7
|
+
TooltipTrigger,
|
|
8
|
+
} from '@lib/components/ui';
|
|
9
|
+
import {
|
|
10
|
+
Cell,
|
|
11
|
+
flexRender,
|
|
12
|
+
Header,
|
|
13
|
+
HeaderGroup,
|
|
14
|
+
Table,
|
|
15
|
+
} from '@tanstack/react-table';
|
|
16
|
+
import { useSortable } from '@dnd-kit/sortable';
|
|
17
|
+
import { CSS } from '@dnd-kit/utilities';
|
|
18
|
+
|
|
19
|
+
import clsx from 'clsx';
|
|
20
|
+
import { CSSProperties, useEffect, useState } from 'react';
|
|
21
|
+
import {
|
|
22
|
+
ArrowDownIcon,
|
|
23
|
+
ArrowsUpDownIcon,
|
|
24
|
+
ArrowUpIcon,
|
|
25
|
+
} from '@heroicons/react/24/outline';
|
|
26
|
+
import { useIsOverflow } from '@lib/hooks/useIsOverflow';
|
|
27
|
+
import { isObject } from 'lodash';
|
|
28
|
+
import copy from 'copy-to-clipboard';
|
|
29
|
+
import { useExplorerProps, useExplorerState } from '.';
|
|
30
|
+
import { TableColMeta } from './inner-explorer';
|
|
31
|
+
|
|
32
|
+
export const TableHeader = ({
|
|
33
|
+
header,
|
|
34
|
+
table,
|
|
35
|
+
headerGroup,
|
|
36
|
+
index,
|
|
37
|
+
setMinViableColWidth,
|
|
38
|
+
onSort,
|
|
39
|
+
currentSortAttr,
|
|
40
|
+
currentSortAsc,
|
|
41
|
+
}: {
|
|
42
|
+
header: Header<any, any>;
|
|
43
|
+
table: Table<any>;
|
|
44
|
+
headerGroup: HeaderGroup<any>;
|
|
45
|
+
index: number;
|
|
46
|
+
setMinViableColWidth: (columnId: string) => void;
|
|
47
|
+
onSort?: (
|
|
48
|
+
attrName: string,
|
|
49
|
+
currentAttr: string | undefined,
|
|
50
|
+
currentAsc?: boolean,
|
|
51
|
+
) => void;
|
|
52
|
+
currentSortAttr?: string;
|
|
53
|
+
currentSortAsc?: boolean;
|
|
54
|
+
}) => {
|
|
55
|
+
const {
|
|
56
|
+
attributes,
|
|
57
|
+
setActivatorNodeRef,
|
|
58
|
+
isDragging,
|
|
59
|
+
listeners,
|
|
60
|
+
setNodeRef,
|
|
61
|
+
transform,
|
|
62
|
+
} = useSortable({
|
|
63
|
+
id: header.column.id,
|
|
64
|
+
disabled: header.id === 'select-col',
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
const style: CSSProperties = {
|
|
68
|
+
opacity: isDragging ? 0.8 : 1,
|
|
69
|
+
position: 'relative',
|
|
70
|
+
transform:
|
|
71
|
+
header.id === 'select-col'
|
|
72
|
+
? undefined
|
|
73
|
+
: CSS.Translate.toString(transform), // translate instead of transform to avoid squishing
|
|
74
|
+
transition: 'width transform 0.2s ease-in-out',
|
|
75
|
+
whiteSpace: 'nowrap',
|
|
76
|
+
width: header.column.getSize(),
|
|
77
|
+
zIndex: isDragging ? 1 : 0,
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
const meta = header.column.columnDef?.meta as TableColMeta | null;
|
|
81
|
+
|
|
82
|
+
const isSortable = !!meta?.sortable;
|
|
83
|
+
|
|
84
|
+
const headerText =
|
|
85
|
+
typeof header.column.columnDef.header === 'string'
|
|
86
|
+
? header.column.columnDef.header
|
|
87
|
+
: '';
|
|
88
|
+
|
|
89
|
+
// Check if this column is currently sorted
|
|
90
|
+
const isCurrentSort =
|
|
91
|
+
currentSortAttr === headerText ||
|
|
92
|
+
(currentSortAttr === 'serverCreatedAt' && headerText === 'id');
|
|
93
|
+
|
|
94
|
+
return (
|
|
95
|
+
<div
|
|
96
|
+
key={header.id}
|
|
97
|
+
ref={setNodeRef}
|
|
98
|
+
className={clsx(
|
|
99
|
+
'group relative z-10 h-8 w-full whitespace-nowrap select-none',
|
|
100
|
+
)}
|
|
101
|
+
style={{
|
|
102
|
+
...style,
|
|
103
|
+
width: header.getSize() !== 0 ? header.getSize() : undefined,
|
|
104
|
+
}}
|
|
105
|
+
>
|
|
106
|
+
{header.id !== 'select-col' && (
|
|
107
|
+
<button
|
|
108
|
+
className="absolute inset-0 z-0 hover:cursor-grab active:cursor-grabbing"
|
|
109
|
+
{...attributes}
|
|
110
|
+
{...listeners}
|
|
111
|
+
ref={setActivatorNodeRef}
|
|
112
|
+
style={{ pointerEvents: 'auto' }}
|
|
113
|
+
/>
|
|
114
|
+
)}
|
|
115
|
+
<div className="flex h-full items-stretch justify-between overflow-hidden">
|
|
116
|
+
<div
|
|
117
|
+
className={`flex shrink items-center gap-1 truncate px-2 py-1 font-semibold th-${header.column.id}`}
|
|
118
|
+
>
|
|
119
|
+
{isSortable ? (
|
|
120
|
+
<button
|
|
121
|
+
className="relative z-50 flex items-center gap-1 py-2 pr-5"
|
|
122
|
+
onClick={() => {
|
|
123
|
+
if (onSort) {
|
|
124
|
+
let thisAttrName =
|
|
125
|
+
headerText === 'id' ? 'serverCreatedAt' : headerText;
|
|
126
|
+
onSort(thisAttrName, currentSortAttr, currentSortAsc);
|
|
127
|
+
}
|
|
128
|
+
}}
|
|
129
|
+
>
|
|
130
|
+
<span className={cn(isCurrentSort && 'underline')}>
|
|
131
|
+
{header.isPlaceholder
|
|
132
|
+
? null
|
|
133
|
+
: flexRender(
|
|
134
|
+
header.column.columnDef.header,
|
|
135
|
+
header.getContext(),
|
|
136
|
+
)}
|
|
137
|
+
</span>
|
|
138
|
+
<span
|
|
139
|
+
className="opacity-50 transition-opacity group-hover:opacity-70"
|
|
140
|
+
style={{
|
|
141
|
+
opacity: isCurrentSort ? 1 : undefined,
|
|
142
|
+
fontWeight: isCurrentSort ? 'bold' : 'normal',
|
|
143
|
+
}}
|
|
144
|
+
>
|
|
145
|
+
{isCurrentSort ? (
|
|
146
|
+
currentSortAsc ? (
|
|
147
|
+
<ArrowUpIcon strokeWidth={3} width={10} />
|
|
148
|
+
) : (
|
|
149
|
+
<ArrowDownIcon strokeWidth={3} width={10} />
|
|
150
|
+
)
|
|
151
|
+
) : (
|
|
152
|
+
<ArrowsUpDownIcon strokeWidth={3} width={10} />
|
|
153
|
+
)}
|
|
154
|
+
</span>
|
|
155
|
+
</button>
|
|
156
|
+
) : (
|
|
157
|
+
<>
|
|
158
|
+
{header.isPlaceholder
|
|
159
|
+
? null
|
|
160
|
+
: flexRender(
|
|
161
|
+
header.column.columnDef.header,
|
|
162
|
+
header.getContext(),
|
|
163
|
+
)}
|
|
164
|
+
</>
|
|
165
|
+
)}
|
|
166
|
+
</div>
|
|
167
|
+
|
|
168
|
+
<div className="flex h-full items-center justify-between">
|
|
169
|
+
<div
|
|
170
|
+
{...{
|
|
171
|
+
onDoubleClick: () => setMinViableColWidth(header.column.id),
|
|
172
|
+
onMouseDown: (e) => {
|
|
173
|
+
e.stopPropagation();
|
|
174
|
+
return header.getResizeHandler()(e);
|
|
175
|
+
},
|
|
176
|
+
onTouchStart: header.getResizeHandler(),
|
|
177
|
+
className: cn(
|
|
178
|
+
`resizer h-full flex justify-center z-50 ${
|
|
179
|
+
table.options.columnResizeDirection
|
|
180
|
+
} ${header.column.getIsResizing() ? 'isResizing' : ''}`,
|
|
181
|
+
headerGroup.headers.length - 1 == index && 'justify-end',
|
|
182
|
+
header.id !== 'select-col' && 'hover:cursor-col-resize',
|
|
183
|
+
),
|
|
184
|
+
style: {
|
|
185
|
+
width: 8,
|
|
186
|
+
pointerEvents: 'auto',
|
|
187
|
+
},
|
|
188
|
+
}}
|
|
189
|
+
>
|
|
190
|
+
{headerGroup.headers.length - 1 !== index && (
|
|
191
|
+
<div className="h-full w-0.5 bg-neutral-200 dark:bg-neutral-700"></div>
|
|
192
|
+
)}
|
|
193
|
+
</div>
|
|
194
|
+
</div>
|
|
195
|
+
</div>
|
|
196
|
+
</div>
|
|
197
|
+
);
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
export const TableCell = ({ cell }: { cell: Cell<any, unknown> }) => {
|
|
201
|
+
const resizing = cell.column.getIsResizing();
|
|
202
|
+
|
|
203
|
+
const { history } = useExplorerState();
|
|
204
|
+
|
|
205
|
+
const meta = cell.column.columnDef.meta as TableColMeta | null;
|
|
206
|
+
const { isDragging, setNodeRef, transform } = useSortable({
|
|
207
|
+
id: cell.column.id,
|
|
208
|
+
disabled: cell.column.id === 'select-col',
|
|
209
|
+
});
|
|
210
|
+
const [showCopy, setShowCopy] = useState(false);
|
|
211
|
+
const { ref: overflowRef, isOverflow, setIsOverflow } = useIsOverflow();
|
|
212
|
+
const shouldShowTooltip =
|
|
213
|
+
(isOverflow || isObject(cell.getValue())) && !meta?.isLink;
|
|
214
|
+
|
|
215
|
+
useEffect(() => {
|
|
216
|
+
const observer = new ResizeObserver(() => {
|
|
217
|
+
const hasOverflow =
|
|
218
|
+
overflowRef.current.scrollWidth > overflowRef.current.clientWidth ||
|
|
219
|
+
overflowRef.current.scrollHeight > overflowRef.current.clientHeight;
|
|
220
|
+
|
|
221
|
+
setIsOverflow(hasOverflow);
|
|
222
|
+
});
|
|
223
|
+
observer.observe(overflowRef.current!);
|
|
224
|
+
|
|
225
|
+
return () => {
|
|
226
|
+
observer.disconnect();
|
|
227
|
+
};
|
|
228
|
+
}, [overflowRef.current]);
|
|
229
|
+
|
|
230
|
+
const style: CSSProperties = {
|
|
231
|
+
opacity: isDragging ? 0.8 : 1,
|
|
232
|
+
position: 'relative',
|
|
233
|
+
transform:
|
|
234
|
+
cell.column.id === 'select-col'
|
|
235
|
+
? undefined
|
|
236
|
+
: CSS.Translate.toString(transform), // translate instead of transform to avoid squishing
|
|
237
|
+
transition: 'width transform 0.2s ease-in-out',
|
|
238
|
+
width: cell.column.getSize(),
|
|
239
|
+
zIndex: isDragging ? 1 : 0,
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
const disablePadding = meta?.disablePadding ?? false;
|
|
243
|
+
|
|
244
|
+
const realValue = cell.getValue();
|
|
245
|
+
|
|
246
|
+
return (
|
|
247
|
+
<Tooltip>
|
|
248
|
+
{' '}
|
|
249
|
+
<TooltipTrigger className="text-left">
|
|
250
|
+
<div
|
|
251
|
+
ref={(el) => {
|
|
252
|
+
setNodeRef(el);
|
|
253
|
+
overflowRef.current = el;
|
|
254
|
+
}}
|
|
255
|
+
style={{
|
|
256
|
+
...style,
|
|
257
|
+
padding: disablePadding ? 0 : '0.5rem',
|
|
258
|
+
}}
|
|
259
|
+
className={cn(`cursor-default truncate whitespace-nowrap`)}
|
|
260
|
+
key={cell.id}
|
|
261
|
+
>
|
|
262
|
+
<span
|
|
263
|
+
className={cn(
|
|
264
|
+
`h-full min-h-full cursor-pointer td-${cell.column.id}`,
|
|
265
|
+
disablePadding ? '' : 'pr-2',
|
|
266
|
+
)}
|
|
267
|
+
onClick={() => {
|
|
268
|
+
if (
|
|
269
|
+
meta?.isLink &&
|
|
270
|
+
meta.attr &&
|
|
271
|
+
Array.isArray(realValue) &&
|
|
272
|
+
realValue.length > 0
|
|
273
|
+
) {
|
|
274
|
+
const attr = meta.attr;
|
|
275
|
+
const linkConfigDir =
|
|
276
|
+
attr.linkConfig[!attr.isForward ? 'forward' : 'reverse'];
|
|
277
|
+
|
|
278
|
+
if (linkConfigDir) {
|
|
279
|
+
history.push({
|
|
280
|
+
namespace: linkConfigDir.namespace,
|
|
281
|
+
where: [`${linkConfigDir.attr}.id`, cell.row.original.id],
|
|
282
|
+
});
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
if (meta?.copyable) {
|
|
287
|
+
if (copy(formatVal(realValue))) {
|
|
288
|
+
setShowCopy(true);
|
|
289
|
+
setTimeout(() => setShowCopy(false), 1000);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}}
|
|
293
|
+
>
|
|
294
|
+
{showCopy ? (
|
|
295
|
+
<div className="h-1">Copied!</div>
|
|
296
|
+
) : (
|
|
297
|
+
flexRender(cell.column.columnDef.cell, cell.getContext())
|
|
298
|
+
)}
|
|
299
|
+
</span>
|
|
300
|
+
</div>
|
|
301
|
+
</TooltipTrigger>
|
|
302
|
+
{shouldShowTooltip && !resizing && (
|
|
303
|
+
<TooltipContent
|
|
304
|
+
className={cn(isObject(realValue) && 'p-0')}
|
|
305
|
+
side="bottom"
|
|
306
|
+
>
|
|
307
|
+
{typeof realValue === 'string' ? (
|
|
308
|
+
flexRender(cell.column.columnDef.cell, cell.getContext())
|
|
309
|
+
) : (
|
|
310
|
+
<Val pretty data={realValue} />
|
|
311
|
+
)}
|
|
312
|
+
</TooltipContent>
|
|
313
|
+
)}
|
|
314
|
+
</Tooltip>
|
|
315
|
+
);
|
|
316
|
+
};
|
|
317
|
+
|
|
318
|
+
function formatVal(data: any, pretty?: boolean): string {
|
|
319
|
+
if (isObject(data)) {
|
|
320
|
+
return JSON.stringify(data, null, pretty ? 2 : undefined);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
return String(data);
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
function Val({ data, pretty }: { data: any; pretty?: boolean }) {
|
|
327
|
+
const sanitized = formatVal(data, pretty);
|
|
328
|
+
const explorerProps = useExplorerProps();
|
|
329
|
+
|
|
330
|
+
if (pretty && isObject(data)) {
|
|
331
|
+
return (
|
|
332
|
+
<Fence
|
|
333
|
+
darkMode={explorerProps.darkMode}
|
|
334
|
+
code={sanitized}
|
|
335
|
+
language="json"
|
|
336
|
+
/>
|
|
337
|
+
);
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
return <>{sanitized}</>;
|
|
341
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Switch } from '@lib/components/ui';
|
|
3
|
+
import { Checkbox, Dialog, Divider, IconButton } from '@lib/components/ui';
|
|
4
|
+
import { useColumnVisibility } from '@lib/hooks/useColumnVisibility';
|
|
5
|
+
import { Cog6ToothIcon, XMarkIcon } from '@heroicons/react/24/outline';
|
|
6
|
+
import { useState } from 'react';
|
|
7
|
+
|
|
8
|
+
interface ViewSettingsProps {
|
|
9
|
+
visiblity: ReturnType<typeof useColumnVisibility>;
|
|
10
|
+
localDates: boolean;
|
|
11
|
+
setLocalDates: (v: boolean | undefined) => void;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export const ViewSettings = ({
|
|
15
|
+
visiblity,
|
|
16
|
+
localDates,
|
|
17
|
+
setLocalDates,
|
|
18
|
+
}: ViewSettingsProps) => {
|
|
19
|
+
const [dialogOpen, setDialogOpen] = useState(false);
|
|
20
|
+
return (
|
|
21
|
+
<>
|
|
22
|
+
<IconButton
|
|
23
|
+
icon={<Cog6ToothIcon width={16} />}
|
|
24
|
+
label="View Settings"
|
|
25
|
+
onClick={() => setDialogOpen(true)}
|
|
26
|
+
/>
|
|
27
|
+
<Dialog
|
|
28
|
+
hideCloseButton={true}
|
|
29
|
+
onClose={() => setDialogOpen(false)}
|
|
30
|
+
open={dialogOpen}
|
|
31
|
+
>
|
|
32
|
+
<div className="flex items-center justify-between">
|
|
33
|
+
<div className="text-lg">Explorer View Settings</div>
|
|
34
|
+
<button onClick={() => setDialogOpen(false)}>
|
|
35
|
+
<XMarkIcon className="h-4 w-4 cursor-pointer" />
|
|
36
|
+
</button>
|
|
37
|
+
</div>
|
|
38
|
+
|
|
39
|
+
<div className="py-2">
|
|
40
|
+
<div>Visible Columns</div>
|
|
41
|
+
<div className="py-1">
|
|
42
|
+
{visiblity.attrs?.map((attr) => (
|
|
43
|
+
<div key={attr.id + attr.name} className="flex gap-2">
|
|
44
|
+
<Checkbox
|
|
45
|
+
label={attr.name}
|
|
46
|
+
checked={visiblity.visibility[attr.id + attr.name] !== false}
|
|
47
|
+
onChange={(checked) =>
|
|
48
|
+
visiblity.setVisibility((prev) => ({
|
|
49
|
+
...prev,
|
|
50
|
+
[attr.id + attr.name]: checked,
|
|
51
|
+
}))
|
|
52
|
+
}
|
|
53
|
+
></Checkbox>
|
|
54
|
+
</div>
|
|
55
|
+
))}
|
|
56
|
+
</div>
|
|
57
|
+
</div>
|
|
58
|
+
<Divider className="py-2" />
|
|
59
|
+
|
|
60
|
+
<div className="flex items-center gap-2">
|
|
61
|
+
<div>Show Dates in Local Time</div>
|
|
62
|
+
<Switch
|
|
63
|
+
onClick={(e) => {
|
|
64
|
+
setLocalDates(!localDates);
|
|
65
|
+
}}
|
|
66
|
+
checked={localDates}
|
|
67
|
+
></Switch>
|
|
68
|
+
</div>
|
|
69
|
+
<div className="text-xs opacity-40">
|
|
70
|
+
Copy to clipboard will still use the original value.
|
|
71
|
+
</div>
|
|
72
|
+
</Dialog>
|
|
73
|
+
</>
|
|
74
|
+
);
|
|
75
|
+
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// Rosé Pine Dawn theme (matching prism.css)
|
|
2
|
+
export const rosePineDawnTheme = {
|
|
3
|
+
plain: {
|
|
4
|
+
backgroundColor: '#fff',
|
|
5
|
+
color: '#575279',
|
|
6
|
+
},
|
|
7
|
+
styles: [
|
|
8
|
+
{
|
|
9
|
+
types: ['comment', 'prolog', 'cdata', 'punctuation'],
|
|
10
|
+
style: { color: '#797593' },
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
types: ['delimiter', 'important', 'atrule', 'operator', 'keyword'],
|
|
14
|
+
style: { color: '#286983' },
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
types: [
|
|
18
|
+
'tag',
|
|
19
|
+
'doctype',
|
|
20
|
+
'variable',
|
|
21
|
+
'regex',
|
|
22
|
+
'class-name',
|
|
23
|
+
'selector',
|
|
24
|
+
'inserted',
|
|
25
|
+
],
|
|
26
|
+
style: { color: '#56949f' },
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
types: ['boolean', 'entity', 'number', 'symbol', 'function'],
|
|
30
|
+
style: { color: '#d7827e' },
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
types: ['string', 'char', 'property', 'attr-value'],
|
|
34
|
+
style: { color: '#ea9d34' },
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
types: ['parameter', 'url', 'attr-name', 'builtin'],
|
|
38
|
+
style: { color: '#907aa9' },
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
types: ['deleted'],
|
|
42
|
+
style: { color: '#b4637a' },
|
|
43
|
+
},
|
|
44
|
+
],
|
|
45
|
+
};
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import * as SelectPrimitive from '@radix-ui/react-select';
|
|
5
|
+
import { cn } from './ui';
|
|
6
|
+
import {
|
|
7
|
+
CheckIcon,
|
|
8
|
+
ChevronDownIcon,
|
|
9
|
+
ChevronUpIcon,
|
|
10
|
+
} from '@heroicons/react/24/outline';
|
|
11
|
+
import { useShadowRoot, useShadowDarkMode } from './StyleMe';
|
|
12
|
+
|
|
13
|
+
function Select({
|
|
14
|
+
...props
|
|
15
|
+
}: React.ComponentProps<typeof SelectPrimitive.Root>) {
|
|
16
|
+
return <SelectPrimitive.Root data-slot="select" {...props} />;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function SelectGroup({
|
|
20
|
+
...props
|
|
21
|
+
}: React.ComponentProps<typeof SelectPrimitive.Group>) {
|
|
22
|
+
return <SelectPrimitive.Group data-slot="select-group" {...props} />;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function SelectValue({
|
|
26
|
+
...props
|
|
27
|
+
}: React.ComponentProps<typeof SelectPrimitive.Value>) {
|
|
28
|
+
return (
|
|
29
|
+
<SelectPrimitive.Value
|
|
30
|
+
className="content-[hi]"
|
|
31
|
+
data-slot="select-value"
|
|
32
|
+
{...props}
|
|
33
|
+
/>
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function SelectTrigger({
|
|
38
|
+
className,
|
|
39
|
+
size = 'default',
|
|
40
|
+
children,
|
|
41
|
+
...props
|
|
42
|
+
}: React.ComponentProps<typeof SelectPrimitive.Trigger> & {
|
|
43
|
+
size?: 'sm' | 'default';
|
|
44
|
+
}) {
|
|
45
|
+
return (
|
|
46
|
+
<SelectPrimitive.Trigger
|
|
47
|
+
data-slot="select-trigger"
|
|
48
|
+
data-size={size}
|
|
49
|
+
className={cn(
|
|
50
|
+
"data-placeholder:text-muted-foreground [&_svg:not([class*='text-'])]:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 flex w-fit items-center justify-between gap-2 rounded-sm border border-gray-300/80 bg-white px-3 py-2 text-sm whitespace-nowrap shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 data-[size=default]:h-9 data-[size=sm]:h-8 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2 dark:border-neutral-700 dark:bg-neutral-800 dark:hover:bg-neutral-700/50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
51
|
+
className,
|
|
52
|
+
)}
|
|
53
|
+
{...props}
|
|
54
|
+
>
|
|
55
|
+
{children}
|
|
56
|
+
<SelectPrimitive.Icon asChild>
|
|
57
|
+
<ChevronDownIcon width={14} />
|
|
58
|
+
</SelectPrimitive.Icon>
|
|
59
|
+
</SelectPrimitive.Trigger>
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function SelectContent({
|
|
64
|
+
className,
|
|
65
|
+
children,
|
|
66
|
+
position = 'popper',
|
|
67
|
+
...props
|
|
68
|
+
}: React.ComponentProps<typeof SelectPrimitive.Content>) {
|
|
69
|
+
const shadowRoot = useShadowRoot();
|
|
70
|
+
const darkMode = useShadowDarkMode();
|
|
71
|
+
return (
|
|
72
|
+
<SelectPrimitive.Portal container={shadowRoot}>
|
|
73
|
+
<SelectPrimitive.Content
|
|
74
|
+
data-slot="select-content"
|
|
75
|
+
className={cn(
|
|
76
|
+
'data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 relative z-50 max-h-(--radix-select-content-available-height) min-w-32 origin-(--radix-select-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-sm border bg-gray-100 text-gray-900 shadow-md dark:border-neutral-700 dark:bg-neutral-800 dark:text-white',
|
|
77
|
+
position === 'popper' &&
|
|
78
|
+
'data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1',
|
|
79
|
+
darkMode ? 'dark' : '',
|
|
80
|
+
className,
|
|
81
|
+
)}
|
|
82
|
+
position={position}
|
|
83
|
+
{...props}
|
|
84
|
+
>
|
|
85
|
+
<SelectScrollUpButton />
|
|
86
|
+
<SelectPrimitive.Viewport
|
|
87
|
+
className={cn(
|
|
88
|
+
'p-1',
|
|
89
|
+
position === 'popper' &&
|
|
90
|
+
'h-(--radix-select-trigger-height) w-full min-w-(--radix-select-trigger-width) scroll-my-1',
|
|
91
|
+
)}
|
|
92
|
+
>
|
|
93
|
+
{children}
|
|
94
|
+
</SelectPrimitive.Viewport>
|
|
95
|
+
<SelectScrollDownButton />
|
|
96
|
+
</SelectPrimitive.Content>
|
|
97
|
+
</SelectPrimitive.Portal>
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function SelectLabel({
|
|
102
|
+
className,
|
|
103
|
+
...props
|
|
104
|
+
}: React.ComponentProps<typeof SelectPrimitive.Label>) {
|
|
105
|
+
return (
|
|
106
|
+
<SelectPrimitive.Label
|
|
107
|
+
data-slot="select-label"
|
|
108
|
+
className={cn('text-muted-foreground px-2 py-1.5 text-xs', className)}
|
|
109
|
+
{...props}
|
|
110
|
+
/>
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function SelectItem({
|
|
115
|
+
className,
|
|
116
|
+
children,
|
|
117
|
+
...props
|
|
118
|
+
}: React.ComponentProps<typeof SelectPrimitive.Item>) {
|
|
119
|
+
return (
|
|
120
|
+
<SelectPrimitive.Item
|
|
121
|
+
data-slot="select-item"
|
|
122
|
+
className={cn(
|
|
123
|
+
"relative flex w-full cursor-default items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden select-none hover:bg-gray-200/50 data-disabled:pointer-events-none data-disabled:opacity-50 dark:text-white dark:hover:bg-neutral-700 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2",
|
|
124
|
+
className,
|
|
125
|
+
)}
|
|
126
|
+
{...props}
|
|
127
|
+
>
|
|
128
|
+
<span className="absolute right-2 flex size-3.5 items-center justify-center">
|
|
129
|
+
<SelectPrimitive.ItemIndicator>
|
|
130
|
+
<CheckIcon width={12} className="size-4" />
|
|
131
|
+
</SelectPrimitive.ItemIndicator>
|
|
132
|
+
</span>
|
|
133
|
+
<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
|
|
134
|
+
</SelectPrimitive.Item>
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function SelectSeparator({
|
|
139
|
+
className,
|
|
140
|
+
...props
|
|
141
|
+
}: React.ComponentProps<typeof SelectPrimitive.Separator>) {
|
|
142
|
+
return (
|
|
143
|
+
<SelectPrimitive.Separator
|
|
144
|
+
data-slot="select-separator"
|
|
145
|
+
className={cn('bg-border pointer-events-none -mx-1 my-1 h-px', className)}
|
|
146
|
+
{...props}
|
|
147
|
+
/>
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function SelectScrollUpButton({
|
|
152
|
+
className,
|
|
153
|
+
...props
|
|
154
|
+
}: React.ComponentProps<typeof SelectPrimitive.ScrollUpButton>) {
|
|
155
|
+
return (
|
|
156
|
+
<SelectPrimitive.ScrollUpButton
|
|
157
|
+
data-slot="select-scroll-up-button"
|
|
158
|
+
className={cn(
|
|
159
|
+
'flex cursor-default items-center justify-center py-1',
|
|
160
|
+
className,
|
|
161
|
+
)}
|
|
162
|
+
{...props}
|
|
163
|
+
>
|
|
164
|
+
<ChevronUpIcon className="size-4" />
|
|
165
|
+
</SelectPrimitive.ScrollUpButton>
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function SelectScrollDownButton({
|
|
170
|
+
className,
|
|
171
|
+
...props
|
|
172
|
+
}: React.ComponentProps<typeof SelectPrimitive.ScrollDownButton>) {
|
|
173
|
+
return (
|
|
174
|
+
<SelectPrimitive.ScrollDownButton
|
|
175
|
+
data-slot="select-scroll-down-button"
|
|
176
|
+
className={cn(
|
|
177
|
+
'flex cursor-default items-center justify-center py-1',
|
|
178
|
+
className,
|
|
179
|
+
)}
|
|
180
|
+
{...props}
|
|
181
|
+
>
|
|
182
|
+
<ChevronDownIcon className="size-4" />
|
|
183
|
+
</SelectPrimitive.ScrollDownButton>
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
export {
|
|
188
|
+
Select,
|
|
189
|
+
SelectContent,
|
|
190
|
+
SelectGroup,
|
|
191
|
+
SelectItem,
|
|
192
|
+
SelectLabel,
|
|
193
|
+
SelectScrollDownButton,
|
|
194
|
+
SelectScrollUpButton,
|
|
195
|
+
SelectSeparator,
|
|
196
|
+
SelectTrigger,
|
|
197
|
+
SelectValue,
|
|
198
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { toast } from './ui';
|
|
2
|
+
|
|
3
|
+
export function infoToast(text: string) {
|
|
4
|
+
toast(text);
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export function successToast(text: string) {
|
|
8
|
+
toast.success(text, {
|
|
9
|
+
richColors: true,
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function errorToast(text: string, options?: any) {
|
|
14
|
+
toast.error(text, {
|
|
15
|
+
duration: options?.autoClose,
|
|
16
|
+
richColors: true,
|
|
17
|
+
});
|
|
18
|
+
}
|