Stijnus commited on
Commit
a286e3b
·
1 Parent(s): 2b585c2
app/components/settings/event-logs/EventLogsTab.tsx CHANGED
@@ -4,6 +4,7 @@ import { Switch } from '~/components/ui/Switch';
4
  import { logStore, type LogEntry } from '~/lib/stores/logs';
5
  import { useStore } from '@nanostores/react';
6
  import { classNames } from '~/utils/classNames';
 
7
 
8
  interface SelectOption {
9
  value: string;
@@ -301,104 +302,104 @@ export function EventLogsTab() {
301
  {/* Filters */}
302
  <div className="flex items-center gap-4 -mt-2">
303
  {/* Level Filter */}
304
- <div ref={levelFilterRef} className="relative">
305
- <button
306
- onClick={() => {
307
- setShowLevelFilter(!showLevelFilter);
308
- setShowCategoryFilter(false);
309
- }}
310
- className="flex items-center gap-2 px-3 py-1.5 rounded-lg hover:bg-purple-500/10 dark:hover:bg-purple-500/20 hover:text-purple-500 dark:hover:text-purple-500 transition-colors"
311
- >
312
- <div
313
- className={classNames('text-sm', selectedLevelOption?.icon || 'i-ph:funnel')}
314
- style={{ color: selectedLevelOption?.color }}
315
- />
316
- <div className="text-sm text-bolt-elements-textSecondary">{selectedLevelOption?.label || 'All Levels'}</div>
317
- <div
318
  className={classNames(
319
- 'i-ph:caret-down text-sm text-bolt-elements-textTertiary transition-transform',
320
- showLevelFilter ? 'rotate-180' : '',
 
 
 
 
 
321
  )}
322
- />
323
- </button>
324
-
325
- {showLevelFilter && (
326
- <div className="absolute left-0 top-full mt-1 z-20">
327
- <div className="p-1 rounded-lg shadow-lg bg-white dark:bg-[#1A1A1A] border border-[#E5E5E5] dark:border-[#333333]">
328
- {logLevelOptions.map((option) => (
329
- <button
330
- key={option.value}
331
- onClick={() => {
332
- setSelectedLevel(option.value);
333
- setShowLevelFilter(false);
334
- }}
335
- className={classNames(
336
- 'flex items-center gap-2 w-full px-3 py-1.5 rounded-md text-sm transition-colors',
337
- option.value === selectedLevel
338
- ? 'bg-purple-500/10 dark:bg-purple-500/20 text-purple-500 dark:text-purple-500'
339
- : 'hover:bg-purple-500/10 dark:hover:bg-purple-500/20 hover:text-purple-500 dark:hover:text-purple-500',
340
- )}
341
- >
342
- <div className={classNames(option.icon, 'text-base')} style={{ color: option.color }} />
343
- <span>{option.label}</span>
344
- </button>
345
- ))}
346
- </div>
347
- </div>
348
- )}
349
- </div>
 
 
 
 
 
 
 
350
 
351
  <div className="w-px h-4 bg-gray-200 dark:bg-gray-700" />
352
 
353
  {/* Category Filter */}
354
- <div ref={categoryFilterRef} className="relative">
355
- <button
356
- onClick={() => {
357
- setShowCategoryFilter(!showCategoryFilter);
358
- setShowLevelFilter(false);
359
- }}
360
- className="flex items-center gap-2 px-3 py-1.5 rounded-lg hover:bg-purple-500/10 dark:hover:bg-purple-500/20 hover:text-purple-500 dark:hover:text-purple-500 transition-colors"
361
- >
362
- <div
363
- className={classNames('text-sm', selectedCategoryOption?.icon || 'i-ph:squares-four')}
364
- style={{ color: selectedCategoryOption?.color }}
365
- />
366
- <div className="text-sm text-bolt-elements-textSecondary">
367
- {selectedCategoryOption?.label || 'All Categories'}
368
- </div>
369
- <div
370
  className={classNames(
371
- 'i-ph:caret-down text-sm text-bolt-elements-textTertiary transition-transform',
372
- showCategoryFilter ? 'rotate-180' : '',
 
 
 
 
 
373
  )}
374
- />
375
- </button>
376
-
377
- {showCategoryFilter && (
378
- <div className="absolute left-0 top-full mt-1 z-20">
379
- <div className="p-1 rounded-lg shadow-lg bg-white dark:bg-[#1A1A1A] border border-[#E5E5E5] dark:border-[#333333]">
380
- {logCategoryOptions.map((option) => (
381
- <button
382
- key={option.value}
383
- onClick={() => {
384
- setSelectedCategory(option.value);
385
- setShowCategoryFilter(false);
386
- }}
387
- className={classNames(
388
- 'flex items-center gap-2 w-full px-3 py-1.5 rounded-md text-sm transition-colors',
389
- option.value === selectedCategory
390
- ? 'bg-purple-500/10 dark:bg-purple-500/20 text-purple-500 dark:text-purple-500'
391
- : 'hover:bg-purple-500/10 dark:hover:bg-purple-500/20 hover:text-purple-500 dark:hover:text-purple-500',
392
- )}
393
- >
394
- <div className={classNames(option.icon, 'text-base')} style={{ color: option.color }} />
395
- <span>{option.label}</span>
396
- </button>
397
- ))}
398
- </div>
399
- </div>
400
- )}
401
- </div>
 
 
 
 
 
 
 
402
  </div>
403
 
404
  {/* Logs Container */}
 
4
  import { logStore, type LogEntry } from '~/lib/stores/logs';
5
  import { useStore } from '@nanostores/react';
6
  import { classNames } from '~/utils/classNames';
7
+ import * as DropdownMenu from '@radix-ui/react-dropdown-menu';
8
 
9
  interface SelectOption {
10
  value: string;
 
302
  {/* Filters */}
303
  <div className="flex items-center gap-4 -mt-2">
304
  {/* Level Filter */}
305
+ <DropdownMenu.Root open={showLevelFilter} onOpenChange={setShowLevelFilter}>
306
+ <DropdownMenu.Trigger asChild>
307
+ <button
 
 
 
 
 
 
 
 
 
 
 
308
  className={classNames(
309
+ 'flex items-center gap-2',
310
+ 'rounded-lg px-3 py-1.5',
311
+ 'text-sm text-gray-900 dark:text-white',
312
+ 'bg-[#FAFAFA] dark:bg-[#0A0A0A]',
313
+ 'border border-[#E5E5E5] dark:border-[#1A1A1A]',
314
+ 'hover:bg-purple-500/10 dark:hover:bg-purple-500/20',
315
+ 'transition-all duration-200',
316
  )}
317
+ >
318
+ <div
319
+ className={classNames('text-lg', selectedLevelOption?.icon || 'i-ph:funnel')}
320
+ style={{ color: selectedLevelOption?.color }}
321
+ />
322
+ <span>{selectedLevelOption?.label || 'All Levels'}</span>
323
+ <span className="i-ph:caret-down text-lg text-gray-500 dark:text-gray-400" />
324
+ </button>
325
+ </DropdownMenu.Trigger>
326
+
327
+ <DropdownMenu.Portal>
328
+ <DropdownMenu.Content
329
+ className="min-w-[200px] bg-white dark:bg-[#0A0A0A] rounded-lg shadow-lg py-1 z-[250] animate-in fade-in-0 zoom-in-95 border border-[#E5E5E5] dark:border-[#1A1A1A]"
330
+ sideOffset={5}
331
+ align="start"
332
+ side="bottom"
333
+ >
334
+ {logLevelOptions.map((option) => (
335
+ <DropdownMenu.Item
336
+ key={option.value}
337
+ className="group flex items-center px-4 py-2.5 text-sm text-gray-700 dark:text-gray-200 hover:bg-purple-500/10 dark:hover:bg-purple-500/20 cursor-pointer transition-colors"
338
+ onClick={() => setSelectedLevel(option.value)}
339
+ >
340
+ <div className="mr-3 flex h-5 w-5 items-center justify-center">
341
+ <div
342
+ className={classNames(option.icon, 'text-lg group-hover:text-purple-500 transition-colors')}
343
+ style={{ color: option.color }}
344
+ />
345
+ </div>
346
+ <span className="group-hover:text-purple-500 transition-colors">{option.label}</span>
347
+ </DropdownMenu.Item>
348
+ ))}
349
+ </DropdownMenu.Content>
350
+ </DropdownMenu.Portal>
351
+ </DropdownMenu.Root>
352
 
353
  <div className="w-px h-4 bg-gray-200 dark:bg-gray-700" />
354
 
355
  {/* Category Filter */}
356
+ <DropdownMenu.Root open={showCategoryFilter} onOpenChange={setShowCategoryFilter}>
357
+ <DropdownMenu.Trigger asChild>
358
+ <button
 
 
 
 
 
 
 
 
 
 
 
 
 
359
  className={classNames(
360
+ 'flex items-center gap-2',
361
+ 'rounded-lg px-3 py-1.5',
362
+ 'text-sm text-gray-900 dark:text-white',
363
+ 'bg-[#FAFAFA] dark:bg-[#0A0A0A]',
364
+ 'border border-[#E5E5E5] dark:border-[#1A1A1A]',
365
+ 'hover:bg-purple-500/10 dark:hover:bg-purple-500/20',
366
+ 'transition-all duration-200',
367
  )}
368
+ >
369
+ <div
370
+ className={classNames('text-lg', selectedCategoryOption?.icon || 'i-ph:squares-four')}
371
+ style={{ color: selectedCategoryOption?.color }}
372
+ />
373
+ <span>{selectedCategoryOption?.label || 'All Categories'}</span>
374
+ <span className="i-ph:caret-down text-lg text-gray-500 dark:text-gray-400" />
375
+ </button>
376
+ </DropdownMenu.Trigger>
377
+
378
+ <DropdownMenu.Portal>
379
+ <DropdownMenu.Content
380
+ className="min-w-[200px] bg-white dark:bg-[#0A0A0A] rounded-lg shadow-lg py-1 z-[250] animate-in fade-in-0 zoom-in-95 border border-[#E5E5E5] dark:border-[#1A1A1A]"
381
+ sideOffset={5}
382
+ align="start"
383
+ side="bottom"
384
+ >
385
+ {logCategoryOptions.map((option) => (
386
+ <DropdownMenu.Item
387
+ key={option.value}
388
+ className="group flex items-center px-4 py-2.5 text-sm text-gray-700 dark:text-gray-200 hover:bg-purple-500/10 dark:hover:bg-purple-500/20 cursor-pointer transition-colors"
389
+ onClick={() => setSelectedCategory(option.value)}
390
+ >
391
+ <div className="mr-3 flex h-5 w-5 items-center justify-center">
392
+ <div
393
+ className={classNames(option.icon, 'text-lg group-hover:text-purple-500 transition-colors')}
394
+ style={{ color: option.color }}
395
+ />
396
+ </div>
397
+ <span className="group-hover:text-purple-500 transition-colors">{option.label}</span>
398
+ </DropdownMenu.Item>
399
+ ))}
400
+ </DropdownMenu.Content>
401
+ </DropdownMenu.Portal>
402
+ </DropdownMenu.Root>
403
  </div>
404
 
405
  {/* Logs Container */}
app/components/settings/notifications/NotificationsTab.tsx CHANGED
@@ -125,15 +125,15 @@ const NotificationsTab = () => {
125
  return details.message ? <p className="text-sm text-gray-600 dark:text-gray-400">{details.message}</p> : null;
126
  };
127
 
128
- const filterOptions: { id: FilterType; label: string; icon: string }[] = [
129
- { id: 'all', label: 'All Notifications', icon: 'i-ph:bell' },
130
- { id: 'system', label: 'System', icon: 'i-ph:gear' },
131
- { id: 'update', label: 'Updates', icon: 'i-ph:arrow-circle-up' },
132
- { id: 'error', label: 'Errors', icon: 'i-ph:warning-circle' },
133
- { id: 'warning', label: 'Warnings', icon: 'i-ph:warning' },
134
- { id: 'info', label: 'Information', icon: 'i-ph:info' },
135
- { id: 'provider', label: 'Providers', icon: 'i-ph:robot' },
136
- { id: 'network', label: 'Network', icon: 'i-ph:wifi-high' },
137
  ];
138
 
139
  return (
@@ -153,10 +153,8 @@ const NotificationsTab = () => {
153
  )}
154
  >
155
  <span
156
- className={classNames(
157
- filterOptions.find((opt) => opt.id === filter)?.icon || 'i-ph:funnel',
158
- 'text-lg text-gray-500 dark:text-gray-400',
159
- )}
160
  />
161
  {filterOptions.find((opt) => opt.id === filter)?.label || 'Filter Notifications'}
162
  <span className="i-ph:caret-down text-lg text-gray-500 dark:text-gray-400" />
@@ -165,7 +163,7 @@ const NotificationsTab = () => {
165
 
166
  <DropdownMenu.Portal>
167
  <DropdownMenu.Content
168
- className="min-w-[200px] bg-white dark:bg-gray-800 rounded-lg shadow-lg py-1 z-[250] animate-in fade-in-0 zoom-in-95"
169
  sideOffset={5}
170
  align="start"
171
  side="bottom"
@@ -178,10 +176,8 @@ const NotificationsTab = () => {
178
  >
179
  <div className="mr-3 flex h-5 w-5 items-center justify-center">
180
  <div
181
- className={classNames(
182
- option.icon,
183
- 'text-gray-500 dark:text-gray-400 group-hover:text-purple-500 transition-colors',
184
- )}
185
  />
186
  </div>
187
  <span className="group-hover:text-purple-500 transition-colors">{option.label}</span>
 
125
  return details.message ? <p className="text-sm text-gray-600 dark:text-gray-400">{details.message}</p> : null;
126
  };
127
 
128
+ const filterOptions: { id: FilterType; label: string; icon: string; color: string }[] = [
129
+ { id: 'all', label: 'All Notifications', icon: 'i-ph:bell', color: '#9333ea' },
130
+ { id: 'system', label: 'System', icon: 'i-ph:gear', color: '#6b7280' },
131
+ { id: 'update', label: 'Updates', icon: 'i-ph:arrow-circle-up', color: '#9333ea' },
132
+ { id: 'error', label: 'Errors', icon: 'i-ph:warning-circle', color: '#ef4444' },
133
+ { id: 'warning', label: 'Warnings', icon: 'i-ph:warning', color: '#f59e0b' },
134
+ { id: 'info', label: 'Information', icon: 'i-ph:info', color: '#3b82f6' },
135
+ { id: 'provider', label: 'Providers', icon: 'i-ph:robot', color: '#10b981' },
136
+ { id: 'network', label: 'Network', icon: 'i-ph:wifi-high', color: '#6366f1' },
137
  ];
138
 
139
  return (
 
153
  )}
154
  >
155
  <span
156
+ className={classNames('text-lg', filterOptions.find((opt) => opt.id === filter)?.icon || 'i-ph:funnel')}
157
+ style={{ color: filterOptions.find((opt) => opt.id === filter)?.color }}
 
 
158
  />
159
  {filterOptions.find((opt) => opt.id === filter)?.label || 'Filter Notifications'}
160
  <span className="i-ph:caret-down text-lg text-gray-500 dark:text-gray-400" />
 
163
 
164
  <DropdownMenu.Portal>
165
  <DropdownMenu.Content
166
+ className="min-w-[200px] bg-white dark:bg-[#0A0A0A] rounded-lg shadow-lg py-1 z-[250] animate-in fade-in-0 zoom-in-95 border border-[#E5E5E5] dark:border-[#1A1A1A]"
167
  sideOffset={5}
168
  align="start"
169
  side="bottom"
 
176
  >
177
  <div className="mr-3 flex h-5 w-5 items-center justify-center">
178
  <div
179
+ className={classNames(option.icon, 'text-lg group-hover:text-purple-500 transition-colors')}
180
+ style={{ color: option.color }}
 
 
181
  />
182
  </div>
183
  <span className="group-hover:text-purple-500 transition-colors">{option.label}</span>