feat: force project naming on creation and integrate autosave from start
This commit is contained in:
+19
-1
@@ -43,6 +43,24 @@ export default function Dashboard() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleNewProject = async () => {
|
||||||
|
const name = prompt('Enter a name for the new project:');
|
||||||
|
if (!name || name.trim() === '') return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await api.saveProject({
|
||||||
|
name: name.trim(),
|
||||||
|
scene_data: {}
|
||||||
|
});
|
||||||
|
if (res.id) {
|
||||||
|
navigate(`/editor/${res.id}`);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Failed to create project', err);
|
||||||
|
alert('Failed to create project');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const handleSignOut = async () => {
|
const handleSignOut = async () => {
|
||||||
await signOut();
|
await signOut();
|
||||||
navigate('/');
|
navigate('/');
|
||||||
@@ -90,7 +108,7 @@ export default function Dashboard() {
|
|||||||
<div className="flex items-center justify-between mb-6">
|
<div className="flex items-center justify-between mb-6">
|
||||||
<h2 className="text-2xl font-bold">Your Projects</h2>
|
<h2 className="text-2xl font-bold">Your Projects</h2>
|
||||||
<button
|
<button
|
||||||
onClick={createNewProject}
|
onClick={handleNewProject}
|
||||||
className="flex items-center gap-2 bg-primary hover:bg-primary/90 text-white px-4 py-2 rounded-xl transition-colors font-medium text-sm"
|
className="flex items-center gap-2 bg-primary hover:bg-primary/90 text-white px-4 py-2 rounded-xl transition-colors font-medium text-sm"
|
||||||
>
|
>
|
||||||
<Plus size={16} /> New Project
|
<Plus size={16} /> New Project
|
||||||
|
|||||||
+27
-40
@@ -655,46 +655,33 @@ export default function Editor() {
|
|||||||
const [openMenu, setOpenMenu] = useState<string | null>(null);
|
const [openMenu, setOpenMenu] = useState<string | null>(null);
|
||||||
const sceneInputRef = useRef<HTMLInputElement>(null);
|
const sceneInputRef = useRef<HTMLInputElement>(null);
|
||||||
|
|
||||||
const newScene = () => {
|
const newScene = async () => {
|
||||||
// Reset all scene state to defaults
|
if (!confirm("Are you sure you want to create a new scene? Unsaved changes in the current scene will be lost.")) return;
|
||||||
setSceneObjects([]);
|
|
||||||
setSelectedIds([]);
|
const name = prompt('Enter a name for the new project:');
|
||||||
setLoadedModel(null);
|
if (!name || name.trim() === '') return;
|
||||||
setModelData(null);
|
|
||||||
setModelBounds(null);
|
setSaveStatus('saving');
|
||||||
setHistory([]);
|
try {
|
||||||
setHistoryIndex(-1);
|
const res = await api.saveProject({
|
||||||
setAdditionalLights([]);
|
name: name.trim(),
|
||||||
setBackplateImage(null);
|
scene_data: {
|
||||||
setCustomHdri(null);
|
sceneObjects: [],
|
||||||
setBackgroundColor('#444444');
|
backgroundColor: '#444444',
|
||||||
setBackgroundType('color');
|
backgroundType: 'color',
|
||||||
setEnvPreset('studio');
|
envPreset: 'studio',
|
||||||
setEnvRotation(0);
|
lightProps: { intensity: 1, color: '#ffffff', shadowBias: -0.0005, shadowRadius: 4 },
|
||||||
setGlobalMaterialProps({
|
groundProps: { showShadow: true, shadowIntensity: 0.4, shadowRotation: 0, shadowSoftness: 0.5, shadowLength: 10 }
|
||||||
color: '#ffffff', roughness: 0.2, metalness: 0.1, clearcoat: 0,
|
}
|
||||||
transmission: 0, thickness: 0, ior: 1.5, sheen: 0, opacity: 1,
|
});
|
||||||
specularIntensity: 1, emissive: '#000000', emissiveIntensity: 0,
|
if (res.id) {
|
||||||
map: undefined, normalMap: undefined, specularMap: undefined, alphaMap: undefined,
|
navigate(`/editor/${res.id}`);
|
||||||
uvScale: 1, uvTiling: [1, 1], uvOffset: [0, 0], uvRotation: 0, mappingType: 'uv'
|
}
|
||||||
});
|
} catch (err) {
|
||||||
setLightProps({ intensity: 1, color: '#ffffff', shadowBias: -0.0005, shadowRadius: 4 });
|
console.error('Failed to create project', err);
|
||||||
setGroundProps({ showShadow: true, shadowIntensity: 0.4, shadowRotation: 0, shadowSoftness: 0.5, shadowLength: 10 });
|
alert('Failed to create project');
|
||||||
setCameraProps(prev => ({
|
setSaveStatus('unsaved');
|
||||||
...prev, fov: 35, zoom: 1, autoRotate: false, orthographic: false,
|
}
|
||||||
position: [5, 3, 5], target: [0, 0.5, 0], pivot: [0, 0, 0],
|
|
||||||
spherical: { distance: 7.68, azimuth: 45, inclination: 20, twist: 0 },
|
|
||||||
}));
|
|
||||||
setCameraPresets([{ id: 'default', name: 'Default View', fov: 35, zoom: 1, position: [3, 2, 5], target: [0, 0, 0] }]);
|
|
||||||
blobURLs.forEach(url => URL.revokeObjectURL(url));
|
|
||||||
setBlobURLs([]);
|
|
||||||
setOpenMenu(null);
|
|
||||||
setShowUVEditor(false);
|
|
||||||
setIsRendering(false);
|
|
||||||
setImportStatus(null);
|
|
||||||
setImportError(null);
|
|
||||||
if (fileInputRef.current) fileInputRef.current.value = '';
|
|
||||||
if (sceneInputRef.current) sceneInputRef.current.value = '';
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const saveScene = async (name: string) => {
|
const saveScene = async (name: string) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user