Sys-Arc-Visl/src/hooks/useVisualOrganizer.ts
SysVis AI 5c4b83203c feat: add mobile-first UX improvements and theme-aware exports
- Mobile hamburger header with slide-in menu
- Mobile bottom action bar for canvas controls
- Full-screen settings modal on mobile
- Mobile empty state with Get Started prompt
- Theme-aware PNG/JPG/SVG exports (respects light/dark mode)
- Added file-saver package for reliable cross-browser downloads
- Updated README with new features and Docker Hub instructions
2025-12-29 09:59:25 +07:00

87 lines
3.4 KiB
TypeScript

import { useCallback, useMemo } from 'react';
import { useDiagramStore } from '../store';
import { useSettingsStore } from '../store/settingsStore';
import { createVisualOrganizer } from '../lib/visualOrganizer';
import { analyzeVisualLayout } from '../lib/aiService';
import type { LayoutSuggestion, VisualIssue, LayoutMetrics } from '../types/visualOrganization';
export const useVisualOrganizer = () => {
const { nodes, edges, setNodes, setEdges } = useDiagramStore();
const { aiMode, onlineProvider, apiKey, ollamaUrl, modelName } = useSettingsStore();
const visualOrganizer = useMemo(() => {
return createVisualOrganizer(nodes, edges);
}, [nodes, edges]);
const analyzeLayout = useCallback(() => {
return visualOrganizer.analyzeLayout();
}, [visualOrganizer]);
const generateSuggestions = useCallback(async () => {
// 1. Get algorithmic suggestions
const algorithmicSuggestions = visualOrganizer.generateSuggestions();
// 2. Get AI suggestions if enabled
let aiSuggestions: LayoutSuggestion[] = [];
try {
const analysisResult = visualOrganizer.analyzeLayout();
const aiResult = await analyzeVisualLayout(
nodes,
edges,
analysisResult.metrics,
ollamaUrl,
modelName,
aiMode,
onlineProvider,
apiKey
);
if (aiResult.success && aiResult.analysis?.suggestions) {
aiSuggestions = aiResult.analysis.suggestions.map((s: any) => ({
id: s.id || `ai-${Math.random().toString(36).substr(2, 9)}`,
title: s.title,
description: s.description,
type: s.type || 'style',
impact: s.impact || 'low',
estimatedImprovement: 0,
beforeState: { metrics: analysisResult.metrics, issues: [] }, // AI doesn't calculate this yet
afterState: { metrics: analysisResult.metrics, estimatedIssues: [] },
implementation: {
nodePositions: {}, // AI suggestions might not have positions yet
description: s.fix_strategy // Store strategy for possible future implementation
}
}));
}
} catch (error) {
console.warn('AI visual analysis failed:', error);
}
return [...algorithmicSuggestions, ...aiSuggestions];
}, [visualOrganizer, nodes, edges, aiMode, onlineProvider, apiKey, ollamaUrl, modelName]);
const applySuggestion = useCallback((suggestion: LayoutSuggestion) => {
const { nodes: newNodes, edges: newEdges } = visualOrganizer.applySuggestion(suggestion);
setNodes(newNodes);
setEdges(newEdges);
}, [visualOrganizer, setNodes, setEdges]);
const getPresets = useCallback(() => {
return visualOrganizer.getPresets();
}, [visualOrganizer]);
return {
analyzeLayout,
generateSuggestions,
applySuggestion,
getPresets,
visualOrganizer
};
};
export type LayoutAnalysis = {
metrics: LayoutMetrics;
issues: VisualIssue[];
strengths: string[];
};
export default useVisualOrganizer;