mirror of
https://github.com/stan-smith/FossFLOW.git
synced 2025-12-23 22:48:57 -05:00
feat: replace import toolbar with tooltip guidance
- Remove import button from top toolbar - Add tooltip on left side directing users to menu > Open - Import functionality remains accessible via burger menu Closes #123
This commit is contained in:
@@ -38,10 +38,7 @@ function App() {
|
||||
const [diagramName, setDiagramName] = useState('');
|
||||
const [showSaveDialog, setShowSaveDialog] = useState(false);
|
||||
const [showLoadDialog, setShowLoadDialog] = useState(false);
|
||||
const [showImportDialog, setShowImportDialog] = useState(false);
|
||||
const [showExportDialog, setShowExportDialog] = useState(false);
|
||||
const [importJson, setImportJson] = useState('');
|
||||
const fileInputRef = useRef<HTMLInputElement>(null);
|
||||
const [fossflowKey, setFossflowKey] = useState(0); // Key to force re-render of FossFLOW
|
||||
const [currentModel, setCurrentModel] = useState<DiagramData | null>(null); // Store current model state
|
||||
const [hasUnsavedChanges, setHasUnsavedChanges] = useState(false);
|
||||
@@ -357,59 +354,6 @@ function App() {
|
||||
setHasUnsavedChanges(false); // Mark as saved after export
|
||||
};
|
||||
|
||||
const handleFileSelect = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const file = event.target.files?.[0];
|
||||
if (!file) return;
|
||||
|
||||
const reader = new FileReader();
|
||||
reader.onload = (e) => {
|
||||
try {
|
||||
const content = e.target?.result as string;
|
||||
const parsedData = JSON.parse(content);
|
||||
|
||||
// Merge imported icons with default icon set
|
||||
const importedIcons = (parsedData.icons || []).filter((icon: any) => icon.collection === 'imported');
|
||||
const mergedIcons = [...icons, ...importedIcons];
|
||||
const mergedData: DiagramData = {
|
||||
...parsedData,
|
||||
title: parsedData.title || 'Imported Diagram',
|
||||
icons: mergedIcons, // Merge default and imported icons
|
||||
colors: parsedData.colors?.length ? parsedData.colors : defaultColors,
|
||||
fitToScreen: parsedData.fitToScreen !== false
|
||||
};
|
||||
|
||||
setDiagramData(mergedData);
|
||||
setDiagramName(parsedData.title || 'Imported Diagram');
|
||||
setCurrentModel(mergedData);
|
||||
setFossflowKey(prev => prev + 1); // Force re-render
|
||||
setShowImportDialog(false);
|
||||
setHasUnsavedChanges(true);
|
||||
|
||||
// Clear the file input
|
||||
if (fileInputRef.current) {
|
||||
fileInputRef.current.value = '';
|
||||
}
|
||||
|
||||
// Success message
|
||||
setTimeout(() => {
|
||||
alert(`Diagram "${parsedData.title || 'Untitled'}" imported successfully!`);
|
||||
}, 100);
|
||||
} catch (error) {
|
||||
alert('Invalid JSON file. Please check the file format.');
|
||||
}
|
||||
};
|
||||
|
||||
reader.onerror = () => {
|
||||
alert('Error reading file. Please try again.');
|
||||
};
|
||||
|
||||
reader.readAsText(file);
|
||||
};
|
||||
|
||||
const importDiagram = () => {
|
||||
// Trigger file input click
|
||||
fileInputRef.current?.click();
|
||||
};
|
||||
|
||||
const handleDiagramManagerLoad = (id: string, data: any) => {
|
||||
// Load diagram from server storage
|
||||
@@ -539,12 +483,6 @@ function App() {
|
||||
)}
|
||||
<button onClick={() => setShowSaveDialog(true)}>{t('nav.saveSessionOnly')}</button>
|
||||
<button onClick={() => setShowLoadDialog(true)}>{t('nav.loadSessionOnly')}</button>
|
||||
<button
|
||||
onClick={() => setShowImportDialog(true)}
|
||||
style={{ backgroundColor: '#28a745' }}
|
||||
>
|
||||
📂 {t('nav.importFile')}
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setShowExportDialog(true)}
|
||||
style={{ backgroundColor: '#007bff' }}
|
||||
@@ -658,53 +596,6 @@ function App() {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Hidden file input for import */}
|
||||
<input
|
||||
ref={fileInputRef}
|
||||
type="file"
|
||||
accept=".json"
|
||||
onChange={handleFileSelect}
|
||||
style={{ display: 'none' }}
|
||||
/>
|
||||
|
||||
{/* Import Dialog */}
|
||||
{showImportDialog && (
|
||||
<div className="dialog-overlay">
|
||||
<div className="dialog">
|
||||
<h2>Import Diagram</h2>
|
||||
<div style={{
|
||||
border: '2px dashed #ccc',
|
||||
borderRadius: '8px',
|
||||
padding: '40px',
|
||||
textAlign: 'center',
|
||||
marginBottom: '20px',
|
||||
backgroundColor: '#f8f9fa'
|
||||
}}>
|
||||
<p style={{ fontSize: '18px', marginBottom: '20px' }}>Choose a JSON file to import</p>
|
||||
<button
|
||||
onClick={importDiagram}
|
||||
style={{
|
||||
padding: '12px 24px',
|
||||
fontSize: '16px',
|
||||
backgroundColor: '#007bff',
|
||||
color: 'white',
|
||||
border: 'none',
|
||||
borderRadius: '4px',
|
||||
cursor: 'pointer'
|
||||
}}
|
||||
>
|
||||
Select File
|
||||
</button>
|
||||
<p style={{ marginTop: '20px', color: '#666', fontSize: '14px' }}>
|
||||
Supported format: .json files exported from Isoflow
|
||||
</p>
|
||||
</div>
|
||||
<div className="dialog-buttons">
|
||||
<button onClick={() => setShowImportDialog(false)}>Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Export Dialog */}
|
||||
{showExportDialog && (
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { Box, IconButton, Paper, Typography } from '@mui/material';
|
||||
import { Close as CloseIcon, FolderOpen as FolderOpenIcon } from '@mui/icons-material';
|
||||
|
||||
const STORAGE_KEY = 'fossflow_import_hint_dismissed';
|
||||
|
||||
export const ImportHintTooltip = () => {
|
||||
const [isDismissed, setIsDismissed] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
// Check if the hint has been dismissed before
|
||||
const dismissed = localStorage.getItem(STORAGE_KEY);
|
||||
if (dismissed !== 'true') {
|
||||
setIsDismissed(false);
|
||||
}
|
||||
}, []);
|
||||
|
||||
const handleDismiss = () => {
|
||||
setIsDismissed(true);
|
||||
localStorage.setItem(STORAGE_KEY, 'true');
|
||||
};
|
||||
|
||||
if (isDismissed) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
position: 'fixed',
|
||||
top: 90,
|
||||
left: 16,
|
||||
zIndex: 1300, // Above most UI elements
|
||||
maxWidth: 280
|
||||
}}
|
||||
>
|
||||
<Paper
|
||||
elevation={4}
|
||||
sx={{
|
||||
p: 2,
|
||||
pr: 5,
|
||||
backgroundColor: 'background.paper',
|
||||
borderLeft: '4px solid',
|
||||
borderLeftColor: 'info.main'
|
||||
}}
|
||||
>
|
||||
<IconButton
|
||||
size="small"
|
||||
onClick={handleDismiss}
|
||||
sx={{
|
||||
position: 'absolute',
|
||||
right: 4,
|
||||
top: 4
|
||||
}}
|
||||
>
|
||||
<CloseIcon fontSize="small" />
|
||||
</IconButton>
|
||||
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', mb: 1 }}>
|
||||
<FolderOpenIcon sx={{ mr: 1, color: 'info.main' }} />
|
||||
<Typography variant="subtitle2" sx={{ fontWeight: 600 }}>
|
||||
Import Diagrams
|
||||
</Typography>
|
||||
</Box>
|
||||
|
||||
<Typography variant="body2" color="text.secondary">
|
||||
To import diagrams, click the <strong>menu button</strong> (☰) in the top left corner,
|
||||
then select <strong>"Open"</strong> to load your diagram files.
|
||||
</Typography>
|
||||
</Paper>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
@@ -20,6 +20,7 @@ import { HelpDialog } from '../HelpDialog/HelpDialog';
|
||||
import { SettingsDialog } from '../SettingsDialog/SettingsDialog';
|
||||
import { ConnectorHintTooltip } from '../ConnectorHintTooltip/ConnectorHintTooltip';
|
||||
import { ConnectorEmptySpaceTooltip } from '../ConnectorEmptySpaceTooltip/ConnectorEmptySpaceTooltip';
|
||||
import { ImportHintTooltip } from '../ImportHintTooltip/ImportHintTooltip';
|
||||
|
||||
const ToolsEnum = {
|
||||
MAIN_MENU: 'MAIN_MENU',
|
||||
@@ -247,6 +248,7 @@ export const UiOverlay = () => {
|
||||
{/* Show connector hint tooltip only in editable mode */}
|
||||
{editorMode === EditorModeEnum.EDITABLE && <ConnectorHintTooltip toolMenuRef={toolMenuRef} />}
|
||||
{editorMode === EditorModeEnum.EDITABLE && <ConnectorEmptySpaceTooltip />}
|
||||
{editorMode === EditorModeEnum.EDITABLE && <ImportHintTooltip />}
|
||||
|
||||
<SceneLayer>
|
||||
<Box ref={contextMenuAnchorRef} />
|
||||
|
||||
Reference in New Issue
Block a user