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
+ };
+};