mirror of
https://github.com/stackblitz-labs/bolt.diy
synced 2025-05-31 10:57:17 +00:00
ui fix
This commit is contained in:
parent
2b585c24fe
commit
a286e3bf34
@ -4,6 +4,7 @@ import { Switch } from '~/components/ui/Switch';
|
||||
import { logStore, type LogEntry } from '~/lib/stores/logs';
|
||||
import { useStore } from '@nanostores/react';
|
||||
import { classNames } from '~/utils/classNames';
|
||||
import * as DropdownMenu from '@radix-ui/react-dropdown-menu';
|
||||
|
||||
interface SelectOption {
|
||||
value: string;
|
||||
@ -301,104 +302,104 @@ export function EventLogsTab() {
|
||||
{/* Filters */}
|
||||
<div className="flex items-center gap-4 -mt-2">
|
||||
{/* Level Filter */}
|
||||
<div ref={levelFilterRef} className="relative">
|
||||
<button
|
||||
onClick={() => {
|
||||
setShowLevelFilter(!showLevelFilter);
|
||||
setShowCategoryFilter(false);
|
||||
}}
|
||||
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"
|
||||
>
|
||||
<div
|
||||
className={classNames('text-sm', selectedLevelOption?.icon || 'i-ph:funnel')}
|
||||
style={{ color: selectedLevelOption?.color }}
|
||||
/>
|
||||
<div className="text-sm text-bolt-elements-textSecondary">{selectedLevelOption?.label || 'All Levels'}</div>
|
||||
<div
|
||||
<DropdownMenu.Root open={showLevelFilter} onOpenChange={setShowLevelFilter}>
|
||||
<DropdownMenu.Trigger asChild>
|
||||
<button
|
||||
className={classNames(
|
||||
'i-ph:caret-down text-sm text-bolt-elements-textTertiary transition-transform',
|
||||
showLevelFilter ? 'rotate-180' : '',
|
||||
'flex items-center gap-2',
|
||||
'rounded-lg px-3 py-1.5',
|
||||
'text-sm text-gray-900 dark:text-white',
|
||||
'bg-[#FAFAFA] dark:bg-[#0A0A0A]',
|
||||
'border border-[#E5E5E5] dark:border-[#1A1A1A]',
|
||||
'hover:bg-purple-500/10 dark:hover:bg-purple-500/20',
|
||||
'transition-all duration-200',
|
||||
)}
|
||||
/>
|
||||
</button>
|
||||
>
|
||||
<div
|
||||
className={classNames('text-lg', selectedLevelOption?.icon || 'i-ph:funnel')}
|
||||
style={{ color: selectedLevelOption?.color }}
|
||||
/>
|
||||
<span>{selectedLevelOption?.label || 'All Levels'}</span>
|
||||
<span className="i-ph:caret-down text-lg text-gray-500 dark:text-gray-400" />
|
||||
</button>
|
||||
</DropdownMenu.Trigger>
|
||||
|
||||
{showLevelFilter && (
|
||||
<div className="absolute left-0 top-full mt-1 z-20">
|
||||
<div className="p-1 rounded-lg shadow-lg bg-white dark:bg-[#1A1A1A] border border-[#E5E5E5] dark:border-[#333333]">
|
||||
{logLevelOptions.map((option) => (
|
||||
<button
|
||||
key={option.value}
|
||||
onClick={() => {
|
||||
setSelectedLevel(option.value);
|
||||
setShowLevelFilter(false);
|
||||
}}
|
||||
className={classNames(
|
||||
'flex items-center gap-2 w-full px-3 py-1.5 rounded-md text-sm transition-colors',
|
||||
option.value === selectedLevel
|
||||
? 'bg-purple-500/10 dark:bg-purple-500/20 text-purple-500 dark:text-purple-500'
|
||||
: 'hover:bg-purple-500/10 dark:hover:bg-purple-500/20 hover:text-purple-500 dark:hover:text-purple-500',
|
||||
)}
|
||||
>
|
||||
<div className={classNames(option.icon, 'text-base')} style={{ color: option.color }} />
|
||||
<span>{option.label}</span>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<DropdownMenu.Portal>
|
||||
<DropdownMenu.Content
|
||||
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]"
|
||||
sideOffset={5}
|
||||
align="start"
|
||||
side="bottom"
|
||||
>
|
||||
{logLevelOptions.map((option) => (
|
||||
<DropdownMenu.Item
|
||||
key={option.value}
|
||||
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"
|
||||
onClick={() => setSelectedLevel(option.value)}
|
||||
>
|
||||
<div className="mr-3 flex h-5 w-5 items-center justify-center">
|
||||
<div
|
||||
className={classNames(option.icon, 'text-lg group-hover:text-purple-500 transition-colors')}
|
||||
style={{ color: option.color }}
|
||||
/>
|
||||
</div>
|
||||
<span className="group-hover:text-purple-500 transition-colors">{option.label}</span>
|
||||
</DropdownMenu.Item>
|
||||
))}
|
||||
</DropdownMenu.Content>
|
||||
</DropdownMenu.Portal>
|
||||
</DropdownMenu.Root>
|
||||
|
||||
<div className="w-px h-4 bg-gray-200 dark:bg-gray-700" />
|
||||
|
||||
{/* Category Filter */}
|
||||
<div ref={categoryFilterRef} className="relative">
|
||||
<button
|
||||
onClick={() => {
|
||||
setShowCategoryFilter(!showCategoryFilter);
|
||||
setShowLevelFilter(false);
|
||||
}}
|
||||
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"
|
||||
>
|
||||
<div
|
||||
className={classNames('text-sm', selectedCategoryOption?.icon || 'i-ph:squares-four')}
|
||||
style={{ color: selectedCategoryOption?.color }}
|
||||
/>
|
||||
<div className="text-sm text-bolt-elements-textSecondary">
|
||||
{selectedCategoryOption?.label || 'All Categories'}
|
||||
</div>
|
||||
<div
|
||||
<DropdownMenu.Root open={showCategoryFilter} onOpenChange={setShowCategoryFilter}>
|
||||
<DropdownMenu.Trigger asChild>
|
||||
<button
|
||||
className={classNames(
|
||||
'i-ph:caret-down text-sm text-bolt-elements-textTertiary transition-transform',
|
||||
showCategoryFilter ? 'rotate-180' : '',
|
||||
'flex items-center gap-2',
|
||||
'rounded-lg px-3 py-1.5',
|
||||
'text-sm text-gray-900 dark:text-white',
|
||||
'bg-[#FAFAFA] dark:bg-[#0A0A0A]',
|
||||
'border border-[#E5E5E5] dark:border-[#1A1A1A]',
|
||||
'hover:bg-purple-500/10 dark:hover:bg-purple-500/20',
|
||||
'transition-all duration-200',
|
||||
)}
|
||||
/>
|
||||
</button>
|
||||
>
|
||||
<div
|
||||
className={classNames('text-lg', selectedCategoryOption?.icon || 'i-ph:squares-four')}
|
||||
style={{ color: selectedCategoryOption?.color }}
|
||||
/>
|
||||
<span>{selectedCategoryOption?.label || 'All Categories'}</span>
|
||||
<span className="i-ph:caret-down text-lg text-gray-500 dark:text-gray-400" />
|
||||
</button>
|
||||
</DropdownMenu.Trigger>
|
||||
|
||||
{showCategoryFilter && (
|
||||
<div className="absolute left-0 top-full mt-1 z-20">
|
||||
<div className="p-1 rounded-lg shadow-lg bg-white dark:bg-[#1A1A1A] border border-[#E5E5E5] dark:border-[#333333]">
|
||||
{logCategoryOptions.map((option) => (
|
||||
<button
|
||||
key={option.value}
|
||||
onClick={() => {
|
||||
setSelectedCategory(option.value);
|
||||
setShowCategoryFilter(false);
|
||||
}}
|
||||
className={classNames(
|
||||
'flex items-center gap-2 w-full px-3 py-1.5 rounded-md text-sm transition-colors',
|
||||
option.value === selectedCategory
|
||||
? 'bg-purple-500/10 dark:bg-purple-500/20 text-purple-500 dark:text-purple-500'
|
||||
: 'hover:bg-purple-500/10 dark:hover:bg-purple-500/20 hover:text-purple-500 dark:hover:text-purple-500',
|
||||
)}
|
||||
>
|
||||
<div className={classNames(option.icon, 'text-base')} style={{ color: option.color }} />
|
||||
<span>{option.label}</span>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<DropdownMenu.Portal>
|
||||
<DropdownMenu.Content
|
||||
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]"
|
||||
sideOffset={5}
|
||||
align="start"
|
||||
side="bottom"
|
||||
>
|
||||
{logCategoryOptions.map((option) => (
|
||||
<DropdownMenu.Item
|
||||
key={option.value}
|
||||
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"
|
||||
onClick={() => setSelectedCategory(option.value)}
|
||||
>
|
||||
<div className="mr-3 flex h-5 w-5 items-center justify-center">
|
||||
<div
|
||||
className={classNames(option.icon, 'text-lg group-hover:text-purple-500 transition-colors')}
|
||||
style={{ color: option.color }}
|
||||
/>
|
||||
</div>
|
||||
<span className="group-hover:text-purple-500 transition-colors">{option.label}</span>
|
||||
</DropdownMenu.Item>
|
||||
))}
|
||||
</DropdownMenu.Content>
|
||||
</DropdownMenu.Portal>
|
||||
</DropdownMenu.Root>
|
||||
</div>
|
||||
|
||||
{/* Logs Container */}
|
||||
|
@ -125,15 +125,15 @@ const NotificationsTab = () => {
|
||||
return details.message ? <p className="text-sm text-gray-600 dark:text-gray-400">{details.message}</p> : null;
|
||||
};
|
||||
|
||||
const filterOptions: { id: FilterType; label: string; icon: string }[] = [
|
||||
{ id: 'all', label: 'All Notifications', icon: 'i-ph:bell' },
|
||||
{ id: 'system', label: 'System', icon: 'i-ph:gear' },
|
||||
{ id: 'update', label: 'Updates', icon: 'i-ph:arrow-circle-up' },
|
||||
{ id: 'error', label: 'Errors', icon: 'i-ph:warning-circle' },
|
||||
{ id: 'warning', label: 'Warnings', icon: 'i-ph:warning' },
|
||||
{ id: 'info', label: 'Information', icon: 'i-ph:info' },
|
||||
{ id: 'provider', label: 'Providers', icon: 'i-ph:robot' },
|
||||
{ id: 'network', label: 'Network', icon: 'i-ph:wifi-high' },
|
||||
const filterOptions: { id: FilterType; label: string; icon: string; color: string }[] = [
|
||||
{ id: 'all', label: 'All Notifications', icon: 'i-ph:bell', color: '#9333ea' },
|
||||
{ id: 'system', label: 'System', icon: 'i-ph:gear', color: '#6b7280' },
|
||||
{ id: 'update', label: 'Updates', icon: 'i-ph:arrow-circle-up', color: '#9333ea' },
|
||||
{ id: 'error', label: 'Errors', icon: 'i-ph:warning-circle', color: '#ef4444' },
|
||||
{ id: 'warning', label: 'Warnings', icon: 'i-ph:warning', color: '#f59e0b' },
|
||||
{ id: 'info', label: 'Information', icon: 'i-ph:info', color: '#3b82f6' },
|
||||
{ id: 'provider', label: 'Providers', icon: 'i-ph:robot', color: '#10b981' },
|
||||
{ id: 'network', label: 'Network', icon: 'i-ph:wifi-high', color: '#6366f1' },
|
||||
];
|
||||
|
||||
return (
|
||||
@ -153,10 +153,8 @@ const NotificationsTab = () => {
|
||||
)}
|
||||
>
|
||||
<span
|
||||
className={classNames(
|
||||
filterOptions.find((opt) => opt.id === filter)?.icon || 'i-ph:funnel',
|
||||
'text-lg text-gray-500 dark:text-gray-400',
|
||||
)}
|
||||
className={classNames('text-lg', filterOptions.find((opt) => opt.id === filter)?.icon || 'i-ph:funnel')}
|
||||
style={{ color: filterOptions.find((opt) => opt.id === filter)?.color }}
|
||||
/>
|
||||
{filterOptions.find((opt) => opt.id === filter)?.label || 'Filter Notifications'}
|
||||
<span className="i-ph:caret-down text-lg text-gray-500 dark:text-gray-400" />
|
||||
@ -165,7 +163,7 @@ const NotificationsTab = () => {
|
||||
|
||||
<DropdownMenu.Portal>
|
||||
<DropdownMenu.Content
|
||||
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"
|
||||
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]"
|
||||
sideOffset={5}
|
||||
align="start"
|
||||
side="bottom"
|
||||
@ -178,10 +176,8 @@ const NotificationsTab = () => {
|
||||
>
|
||||
<div className="mr-3 flex h-5 w-5 items-center justify-center">
|
||||
<div
|
||||
className={classNames(
|
||||
option.icon,
|
||||
'text-gray-500 dark:text-gray-400 group-hover:text-purple-500 transition-colors',
|
||||
)}
|
||||
className={classNames(option.icon, 'text-lg group-hover:text-purple-500 transition-colors')}
|
||||
style={{ color: option.color }}
|
||||
/>
|
||||
</div>
|
||||
<span className="group-hover:text-purple-500 transition-colors">{option.label}</span>
|
||||
|
Loading…
Reference in New Issue
Block a user