diff --git a/src/components/SignatureCategories.tsx b/src/components/SignatureCategories.tsx new file mode 100644 index 0000000..eb835a6 --- /dev/null +++ b/src/components/SignatureCategories.tsx @@ -0,0 +1,99 @@ + +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; +import { Badge } from "@/components/ui/badge"; +import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@/components/ui/collapsible"; +import { ChevronDown, ChevronRight, Zap, Shield, Coins, HelpCircle, Pickaxe, Gauge } from "lucide-react"; +import { SignatureListItem } from "@/components/SignatureListItem"; +import { SignatureCategory } from "@/hooks/useSignatureCategories"; + +interface SignatureCategoriesProps { + categories: SignatureCategory[]; + onToggleCategory: (categoryId: string) => void; +} + +const getCategoryIcon = (categoryId: string) => { + switch (categoryId) { + case 'combat': + return ; + case 'data_relic': + return ; + case 'gas': + return ; + case 'ore': + return ; + case 'wormhole': + return ; + default: + return ; + } +}; + +const getCategoryColor = (categoryId: string) => { + switch (categoryId) { + case 'combat': + return 'text-red-400 border-red-600'; + case 'data_relic': + return 'text-blue-400 border-blue-600'; + case 'gas': + return 'text-green-400 border-green-600'; + case 'ore': + return 'text-yellow-400 border-yellow-600'; + case 'wormhole': + return 'text-purple-400 border-purple-600'; + default: + return 'text-slate-400 border-slate-600'; + } +}; + +export const SignatureCategories = ({ categories, onToggleCategory }: SignatureCategoriesProps) => { + if (categories.length === 0) { + return ( + + +
No signatures found
+
+
+ ); + } + + return ( +
+ {categories.map((category) => ( + + onToggleCategory(category.id)}> + + + +
+ {category.isVisible ? ( + + ) : ( + + )} + {getCategoryIcon(category.id)} + {category.name} +
+ + {category.signatures.length} + +
+
+
+ + +
+ {category.signatures.map((signature) => ( + + ))} +
+
+
+
+
+ ))} +
+ ); +}; diff --git a/src/components/SystemTracker.tsx b/src/components/SystemTracker.tsx index c5ad21b..3978590 100644 --- a/src/components/SystemTracker.tsx +++ b/src/components/SystemTracker.tsx @@ -5,7 +5,8 @@ import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { RefreshCw, AlertCircle, Radar } from "lucide-react"; -import { SignatureListItem } from "@/components/SignatureListItem"; +import { SignatureCategories } from "@/components/SignatureCategories"; +import { useSignatureCategories } from "@/hooks/useSignatureCategories"; import { toast } from "@/hooks/use-toast"; import pb from "@/lib/pocketbase"; @@ -59,6 +60,8 @@ export const SystemTracker = ({ system }: SystemTrackerProps) => { return dateB.localeCompare(dateA); }); + const { categories, toggleCategoryVisibility } = useSignatureCategories(sortedSignatures); + return (
{/* System Status Card */} @@ -96,37 +99,6 @@ export const SystemTracker = ({ system }: SystemTrackerProps) => { )} - {/* Signatures Display */} - {system && !signaturesLoading && ( -
- {sortedSignatures.length === 0 ? ( - - -
No signatures found for {system}
-
-
- ) : ( - - - - Signatures - - {sortedSignatures.length} Total - - - - -
- {sortedSignatures.map((signature) => ( - - ))} -
-
-
- )} -
- )} - {/* Loading State */} {signaturesLoading && system && ( @@ -143,6 +115,14 @@ export const SystemTracker = ({ system }: SystemTrackerProps) => { )} + + {/* Signature Categories */} + {system && !signaturesLoading && ( + + )}
); }; diff --git a/src/hooks/useSignatureCategories.ts b/src/hooks/useSignatureCategories.ts new file mode 100644 index 0000000..86093cc --- /dev/null +++ b/src/hooks/useSignatureCategories.ts @@ -0,0 +1,130 @@ + +import { useState, useEffect, useMemo } from 'react'; +import { SigviewRecord as Signature } from "@/lib/pbtypes"; + +export interface SignatureCategory { + id: string; + name: string; + signatures: Signature[]; + isVisible: boolean; +} + +const CATEGORY_PREFERENCES_KEY = 'signature-category-preferences'; + +export const categorizeSignatures = (signatures: Signature[]): Record => { + const categories: Record = { + unknown: [], + combat: [], + data_relic: [], + gas: [], + ore: [], + wormhole: [] + }; + + signatures.forEach(signature => { + const type = signature.type?.toLowerCase() || ''; + const name = signature.signame?.toLowerCase() || ''; + + if (!type || type === '') { + categories.unknown.push(signature); + } else if (type.includes('combat') || type.includes('den') || type.includes('rally')) { + categories.combat.push(signature); + } else if (type.includes('data') || type.includes('relic') || type.includes('exploration')) { + categories.data_relic.push(signature); + } else if (type.includes('gas') || name.includes('gas')) { + categories.gas.push(signature); + } else if (type.includes('ore') || type.includes('mining') || name.includes('ore')) { + categories.ore.push(signature); + } else if (type.includes('wormhole') || name.includes('wormhole') || type.includes('k162')) { + categories.wormhole.push(signature); + } else { + categories.unknown.push(signature); + } + }); + + return categories; +}; + +export const useSignatureCategories = (signatures: Signature[]) => { + const [categoryVisibility, setCategoryVisibility] = useState>({ + unknown: true, + combat: true, + data_relic: true, + gas: true, + ore: true, + wormhole: true + }); + + // Load preferences from localStorage on mount + useEffect(() => { + const saved = localStorage.getItem(CATEGORY_PREFERENCES_KEY); + if (saved) { + try { + const preferences = JSON.parse(saved); + setCategoryVisibility(prev => ({ ...prev, ...preferences })); + } catch (error) { + console.error('Failed to parse category preferences:', error); + } + } + }, []); + + // Save preferences to localStorage when they change + useEffect(() => { + localStorage.setItem(CATEGORY_PREFERENCES_KEY, JSON.stringify(categoryVisibility)); + }, [categoryVisibility]); + + const categories = useMemo(() => { + const categorized = categorizeSignatures(signatures); + + return [ + { + id: 'unknown', + name: 'Unknown Sites', + signatures: categorized.unknown, + isVisible: categoryVisibility.unknown + }, + { + id: 'combat', + name: 'Combat Sites', + signatures: categorized.combat, + isVisible: categoryVisibility.combat + }, + { + id: 'data_relic', + name: 'Data/Relic Sites', + signatures: categorized.data_relic, + isVisible: categoryVisibility.data_relic + }, + { + id: 'gas', + name: 'Gas Sites', + signatures: categorized.gas, + isVisible: categoryVisibility.gas + }, + { + id: 'ore', + name: 'Ore Sites', + signatures: categorized.ore, + isVisible: categoryVisibility.ore + }, + { + id: 'wormhole', + name: 'Wormholes', + signatures: categorized.wormhole, + isVisible: categoryVisibility.wormhole + } + ].filter(category => category.signatures.length > 0); + }, [signatures, categoryVisibility]); + + const toggleCategoryVisibility = (categoryId: string) => { + setCategoryVisibility(prev => ({ + ...prev, + [categoryId]: !prev[categoryId] + })); + }; + + return { + categories, + toggleCategoryVisibility + }; +};