feat: units system — mm/cm/m switchable, configurable grid, real measurements, formatted display
This commit is contained in:
+74
-2
@@ -26,10 +26,11 @@ import { getCommandRegistry } from './services/commandRegistry';
|
||||
import { importFile, type ImportResult } from './services/importService';
|
||||
import { exportProject, downloadBlob, type ExportFormat } from './services/exportService';
|
||||
import type { ProjectData } from './types/cad.types';
|
||||
import { loadProjectDataTyped, createElementTyped, updateElement, deleteElement as apiDeleteElement, createLayerTyped, updateLayer, deleteLayer as apiDeleteLayer, createBlockTyped, updateBlock, deleteBlock as apiDeleteBlock, aiChat } from './services/api';
|
||||
import { loadProjectDataTyped, createElementTyped, updateElement, deleteElement as apiDeleteElement, createLayerTyped, updateLayer, deleteLayer as apiDeleteLayer, createBlockTyped, updateBlock, deleteBlock as apiDeleteBlock, aiChat, getSetting, setSetting } from './services/api';
|
||||
import { useYjsBinding } from './crdt';
|
||||
import { registerBuiltinPlugins, pluginRegistry } from './plugins';
|
||||
import type { PluginContext } from './plugins';
|
||||
import type { UnitType } from './utils/format';
|
||||
import './styles.css';
|
||||
import './styles/auth.css';
|
||||
import { useAuth } from './contexts/AuthContext';
|
||||
@@ -99,6 +100,11 @@ const CADEditor: React.FC<CADEditorProps> = ({ projectId, token, onNavigateBack
|
||||
const [snapEnabled, setSnapEnabled] = useState(true);
|
||||
const [polarEnabled, setPolarEnabled] = useState(false);
|
||||
|
||||
// Units
|
||||
const [unit, setUnit] = useState<UnitType>('mm');
|
||||
const [gridSize, setGridSize] = useState<number>(20);
|
||||
const [scaleFactor, setScaleFactor] = useState<number>(1);
|
||||
|
||||
// Right sidebar
|
||||
const [activeRightPanel, setActiveRightPanel] = useState<RightPanel>('tool');
|
||||
const [selectedElement, setSelectedElement] = useState<CADElement | null>(null);
|
||||
@@ -328,6 +334,53 @@ const CADEditor: React.FC<CADEditorProps> = ({ projectId, token, onNavigateBack
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [projectId, token]);
|
||||
|
||||
// Load unit settings from backend on mount
|
||||
React.useEffect(() => {
|
||||
if (!token) return;
|
||||
let cancelled = false;
|
||||
(async () => {
|
||||
try {
|
||||
const [unitSetting, gridSetting, scaleSetting] = await Promise.all([
|
||||
getSetting(token, 'cad.unit').catch(() => null),
|
||||
getSetting(token, 'cad.gridSize').catch(() => null),
|
||||
getSetting(token, 'cad.scaleFactor').catch(() => null),
|
||||
]);
|
||||
if (cancelled) return;
|
||||
if (unitSetting && (unitSetting.value === 'mm' || unitSetting.value === 'cm' || unitSetting.value === 'm')) {
|
||||
setUnit(unitSetting.value as UnitType);
|
||||
}
|
||||
if (gridSetting) {
|
||||
const gs = parseFloat(gridSetting.value);
|
||||
if (!isNaN(gs) && gs > 0) setGridSize(gs);
|
||||
}
|
||||
if (scaleSetting) {
|
||||
const sf = parseFloat(scaleSetting.value);
|
||||
if (!isNaN(sf) && sf > 0) setScaleFactor(sf);
|
||||
}
|
||||
} catch {
|
||||
// Settings not yet stored — use defaults
|
||||
}
|
||||
})();
|
||||
return () => { cancelled = true; };
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [token]);
|
||||
|
||||
// Save unit settings to backend when they change
|
||||
const handleUnitChange = useCallback((newUnit: UnitType) => {
|
||||
setUnit(newUnit);
|
||||
if (token) setSetting(token, 'cad.unit', newUnit).catch(() => {});
|
||||
}, [token]);
|
||||
|
||||
const handleGridSizeChange = useCallback((newSize: number) => {
|
||||
setGridSize(newSize);
|
||||
if (token) setSetting(token, 'cad.gridSize', String(newSize)).catch(() => {});
|
||||
}, [token]);
|
||||
|
||||
const handleScaleFactorChange = useCallback((newFactor: number) => {
|
||||
setScaleFactor(newFactor);
|
||||
if (token) setSetting(token, 'cad.scaleFactor', String(newFactor)).catch(() => {});
|
||||
}, [token]);
|
||||
|
||||
// Sync remote → local: when Yjs data changes from other users, update local state
|
||||
React.useEffect(() => {
|
||||
if (collab.status !== 'connected') return;
|
||||
@@ -1471,6 +1524,8 @@ const CADEditor: React.FC<CADEditorProps> = ({ projectId, token, onNavigateBack
|
||||
onOpenSettings={() => setSettingsOpen(true)}
|
||||
onOpenLeftDrawer={() => setMobileLeftOpen(true)}
|
||||
onOpenRightDrawer={() => setMobileRightOpen(true)}
|
||||
unit={unit}
|
||||
onUnitChange={handleUnitChange}
|
||||
/>
|
||||
<RibbonBar
|
||||
activeTab={activeRibbonTab}
|
||||
@@ -1532,6 +1587,9 @@ const CADEditor: React.FC<CADEditorProps> = ({ projectId, token, onNavigateBack
|
||||
bgConfig={bgConfig}
|
||||
remoteCursors={collab.cursors}
|
||||
groups={groups}
|
||||
unit={unit}
|
||||
gridSize={gridSize}
|
||||
scaleFactor={scaleFactor}
|
||||
/>
|
||||
<RightSidebar
|
||||
activePanel={activeRightPanel}
|
||||
@@ -1574,6 +1632,8 @@ const CADEditor: React.FC<CADEditorProps> = ({ projectId, token, onNavigateBack
|
||||
groups={groups}
|
||||
onSelectElement={handleSelectElement}
|
||||
token={token}
|
||||
unit={unit}
|
||||
scaleFactor={scaleFactor}
|
||||
/>
|
||||
</div>
|
||||
<CommandLine
|
||||
@@ -1595,6 +1655,9 @@ const CADEditor: React.FC<CADEditorProps> = ({ projectId, token, onNavigateBack
|
||||
onTogglePolar={handleTogglePolar}
|
||||
onToggleGrid={handleToggleGrid}
|
||||
seatCount={seatCount}
|
||||
unit={unit}
|
||||
scaleFactor={scaleFactor}
|
||||
onUnitChange={handleUnitChange}
|
||||
/>
|
||||
<MobileDrawers
|
||||
leftOpen={mobileLeftOpen}
|
||||
@@ -1604,7 +1667,16 @@ const CADEditor: React.FC<CADEditorProps> = ({ projectId, token, onNavigateBack
|
||||
onCloseRight={() => setMobileRightOpen(false)}
|
||||
onRightTabChange={setActiveDrawerTab}
|
||||
/>
|
||||
<SettingsModal open={settingsOpen} onClose={() => setSettingsOpen(false)} />
|
||||
<SettingsModal
|
||||
open={settingsOpen}
|
||||
onClose={() => setSettingsOpen(false)}
|
||||
unit={unit}
|
||||
gridSize={gridSize}
|
||||
scaleFactor={scaleFactor}
|
||||
onUnitChange={handleUnitChange}
|
||||
onGridSizeChange={handleGridSizeChange}
|
||||
onScaleFactorChange={handleScaleFactorChange}
|
||||
/>
|
||||
<BackgroundImport
|
||||
open={bgImportOpen}
|
||||
onClose={() => setBgImportOpen(false)}
|
||||
|
||||
Reference in New Issue
Block a user