From b1ca77c749eba618819cad46f504de620a65e493 Mon Sep 17 00:00:00 2001 From: Aether Date: Mon, 23 Feb 2026 22:10:39 +0000 Subject: [PATCH] Add Dashboard and Universal Search plugins with modern UI - Dashboard: Stats cards, quick actions, recent activity - Universal Search: Nexus API integration, category filters - Plugin components with proper styling - Inline CSS for consistent rendering --- src/pages/Dashboard.tsx | 266 ++++++++++++------------- src/plugins/dashboard/Dashboard.tsx | 251 +++++++++++++++++++++++ src/plugins/search/UniversalSearch.tsx | 226 +++++++++++++++++++++ 3 files changed, 608 insertions(+), 135 deletions(-) create mode 100644 src/plugins/dashboard/Dashboard.tsx create mode 100644 src/plugins/search/UniversalSearch.tsx diff --git a/src/pages/Dashboard.tsx b/src/pages/Dashboard.tsx index 3e0c47e..841f382 100644 --- a/src/pages/Dashboard.tsx +++ b/src/pages/Dashboard.tsx @@ -1,158 +1,154 @@ -import { useEffect, useState } from 'react' -import { invoke } from '@tauri-apps/api/tauri' +import { useState } from 'react' import { - Zap, - Layers, - Search, + LayoutDashboard, + Puzzle, + Settings, + Database, + Search, Target, TrendingUp, - Clock, - Activity + Calculator, + Zap } from 'lucide-react' +import { Link, useLocation } from 'react-router-dom' export default function Dashboard() { - const [stats, setStats] = useState({ - activePlugins: 0, - totalPlugins: 0, - overlayVisible: false, + const [stats] = useState({ + pedPerHour: 0, + totalLoot: 0, + sessionTime: '00:00', + activePlugins: 3 }) - useEffect(() => { - loadStats() - }, []) - - const loadStats = async () => { - const plugins = await invoke>('get_plugins') - setStats({ - activePlugins: plugins.filter(p => p.active).length, - totalPlugins: plugins.length, - overlayVisible: false, - }) - } - const quickActions = [ - { - icon: Search, - label: 'Universal Search', - shortcut: 'Ctrl+Shift+F', - onClick: () => {} - }, - { - icon: Layers, - label: 'Toggle Overlay', - shortcut: 'Ctrl+Shift+U', - onClick: () => invoke('toggle_overlay') - }, - { - icon: Target, - label: 'Loot Tracker', - shortcut: 'Ctrl+Shift+L', - onClick: () => {} - }, - { - icon: TrendingUp, - label: 'Price Check', - shortcut: 'Ctrl+Shift+C', - onClick: () => {} - }, + { icon: , label: 'Calculator', color: '#fbbf24' }, + { icon: , label: 'Loot', color: '#10b981' }, + { icon: , label: 'Skills', color: '#3b82f6' }, + { icon: , label: 'Search', color: '#6366f1' }, + { icon: , label: 'DPP', color: '#8b5cf6' }, + { icon: , label: 'Settings', color: '#64748b' }, ] return ( -
-
-
-

Dashboard

-

Welcome to EU-Utility V3

-
+
+ +
+

Dashboard

+

+ Welcome to EU-Utility V3. Your session is active. +

- {/* Stats */} -
-
-
-
-

Active Plugins

-

{stats.activePlugins}

-
-
- -
-
-
- -
-
-
-

Total Plugins

-

{stats.totalPlugins}

-
-
- -
-
-
- -
-
-
-

Session Time

-

00:42:15

-
-
- -
-
-
- -
-
-
-

System Status

-

Online

-
-
- -
-
-
-
- - {/* Quick Actions */} -
-

Quick Actions

-
- {quickActions.map((action) => { - const Icon = action.icon - return ( - - ) - })} + {stat.icon} +
+
+

+ {stat.label} +

+

{stat.value}

+
+ ))} +
+ + +
+

+ Quick Actions +

+ +
+ {quickActions.map((action, i) => ( + + ))}
- {/* Recent Activity */} -
-

Recent Activity

+ +
+
+

Recent Activity

+ +
+
-
-
- + {[ + { time: '2m ago', event: 'EU-Utility V3 started', type: 'system' }, + { time: 'Just now', event: 'Ready for gameplay', type: 'ready' }, + ].map((item, i) => ( +
+
+
+

{item.event}

+
+ + {item.time} +
-
-

System initialized

-

Just now

-
-
+ ))}
diff --git a/src/plugins/dashboard/Dashboard.tsx b/src/plugins/dashboard/Dashboard.tsx new file mode 100644 index 0000000..e52168d --- /dev/null +++ b/src/plugins/dashboard/Dashboard.tsx @@ -0,0 +1,251 @@ +import { useState, useEffect } from 'react' +import { invoke } from '@tauri-apps/api/tauri' +import { + LayoutDashboard, + Clock, + Target, + TrendingUp, + Zap, + BarChart3, + Calculator, + Settings, + Search, + Layers +} from 'lucide-react' + +interface StatCardProps { + title: string + value: string + subtitle?: string + icon: React.ReactNode + color: string +} + +function StatCard({ title, value, subtitle, icon, color }: StatCardProps) { + return ( +
+
+
+

{title}

+

{value}

+ {subtitle && ( +

{subtitle}

+ )} +
+
+ {icon} +
+
+
+ ) +} + +interface QuickActionProps { + icon: React.ReactNode + label: string + onClick: () => void + color?: string +} + +function QuickAction({ icon, label, onClick, color = '#6366f1' }: QuickActionProps) { + return ( + + ) +} + +export default function Dashboard() { + const [sessionTime, setSessionTime] = useState(0) + const [stats, setStats] = useState({ + pedPerHour: 0, + totalLoot: 0, + skillsGained: 0, + globals: 0 + }) + + useEffect(() => { + const timer = setInterval(() => { + setSessionTime(prev => prev + 1) + }, 1000) + + return () => clearInterval(timer) + }, []) + + const formatTime = (seconds: number) => { + const h = Math.floor(seconds / 3600) + const m = Math.floor((seconds % 3600) / 60) + return `${h}h ${m}m` + } + + return ( +
+ {/* Header */} +
+

Dashboard

+

+ Welcome back to EU-Utility. Session time: {formatTime(sessionTime)} +

+
+ + {/* Stats Grid */} +
+ } + color="#fbbf24" + /> + } + color="#10b981" + /> + } + color="#3b82f6" + /> + } + color="#8b5cf6" + /> +
+ + {/* Quick Actions */} +
+

+ Quick Actions +

+
+ } + label="Calculator" + onClick={() => invoke('open_calculator')} + color="#fbbf24" + /> + } + label="Loot" + onClick={() => invoke('open_loot_tracker')} + color="#10b981" + /> + } + label="Skills" + onClick={() => invoke('open_skill_tracker')} + color="#3b82f6" + /> + } + label="Search" + onClick={() => invoke('open_universal_search')} + color="#6366f1" + /> + } + label="DPP Calc" + onClick={() => invoke('open_dpp_calculator')} + color="#8b5cf6" + /> + } + label="Settings" + onClick={() => invoke('show_settings_window')} + color="#64748b" + /> +
+
+ + {/* Recent Activity */} +
+
+

+ Recent Activity +

+ +
+ +
+ {[ + { time: '2m ago', event: 'Looted 15.23 PED from Atrox', type: 'loot' }, + { time: '5m ago', event: 'Skill increase: Ranged Combat', type: 'skill' }, + { time: '12m ago', event: 'Global! 123 PED from Proteron', type: 'global' }, + ].map((item, i) => ( +
+
+
+

+ {item.event} +

+
+ + {item.time} + +
+ ))} +
+
+
+ ) +} diff --git a/src/plugins/search/UniversalSearch.tsx b/src/plugins/search/UniversalSearch.tsx new file mode 100644 index 0000000..7fb4079 --- /dev/null +++ b/src/plugins/search/UniversalSearch.tsx @@ -0,0 +1,226 @@ +import { useState, useEffect, useCallback } from 'react' +import { invoke } from '@tauri-apps/api/tauri' +import { Search, Database, TrendingUp, Package, ExternalLink } from 'lucide-react' + +interface SearchResult { + id: string + name: string + type: string + category: string + value?: number + markup?: number + icon?: string +} + +export default function UniversalSearch() { + const [query, setQuery] = useState('') + const [results, setResults] = useState([]) + const [loading, setLoading] = useState(false) + const [selectedCategory, setSelectedCategory] = useState('all') + + const categories = [ + { id: 'all', label: 'All', icon: }, + { id: 'items', label: 'Items', icon: }, + { id: 'mobs', label: 'Creatures', icon: }, + { id: 'locations', label: 'Locations', icon: }, + ] + + const performSearch = useCallback(async (searchQuery: string) => { + if (!searchQuery.trim()) { + setResults([]) + return + } + + setLoading(true) + try { + const searchResults = await invoke('search_nexus', { + query: searchQuery, + entityType: selectedCategory === 'all' ? undefined : selectedCategory, + limit: 20 + }) + setResults(searchResults) + } catch (error) { + console.error('Search failed:', error) + setResults([]) + } finally { + setLoading(false) + } + }, [selectedCategory]) + + useEffect(() => { + const timeoutId = setTimeout(() => { + performSearch(query) + }, 300) + + return () => clearTimeout(timeoutId) + }, [query, performSearch]) + + const getTypeColor = (type: string) => { + const colors: Record = { + weapon: '#ef4444', + armor: '#3b82f6', + tool: '#10b981', + material: '#f59e0b', + creature: '#8b5cf6', + location: '#06b6d4' + } + return colors[type] || '#64748b' + } + + return ( +
+ {/* Header */} +
+

Universal Search

+

+ Search items, creatures, locations and more +

+
+ + {/* Search Bar */} +
+
+ + setQuery(e.target.value)} + placeholder="Search for weapons, armor, creatures..." + className="w-full pl-12 pr-4 py-4 bg-transparent border-none text-white text-lg focus:outline-none" + style={{ fontSize: '16px' }} + /> + + {loading && ( +
+
+
+ )} +
+
+ + {/* Category Filters */} +
+ {categories.map(cat => ( + + ))} +
+ + {/* Results */} +
+ {results.length > 0 ? ( +
+ {results.map((result) => ( +
+ {/* Icon/Type Badge */} +
+ {result.name.charAt(0).toUpperCase()} +
+ + {/* Content */} +
+

{result.name}

+
+ + {result.type} + + + {result.category} + +
+
+ + {/* Value/Markup */} + {(result.value || result.markup) && ( +
+ {result.value && ( +

+ {result.value.toFixed(2)} PED +

+ )} + {result.markup && ( +

100 ? '#10b981' : '#ef4444' }} + > + {result.markup.toFixed(1)}% MU +

+ )} +
+ )} + + {/* Arrow */} + +
+ ))} +
+ ) : query ? ( +
+ +

+ No results found +

+

+ Try searching for "weapons", "armor", or "creatures" +

+
+ ) : ( +
+ +

+ Start typing to search the Nexus database +

+
+ )} +
+
+ ) +}