Trocou demo por blob na nuvem
X-Lovable-Edit-ID: edt-e0f35f63-9afa-4420-93c9-bbbf4e2eb083 Co-authored-by: Reifonas <211114984+Reifonas@users.noreply.github.com>
This commit is contained in:
+38
-16
@@ -1,19 +1,18 @@
|
|||||||
import { useEffect, useRef, useCallback, useState } from 'react';
|
import { useEffect, useRef, useCallback, useState } from 'react';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import { Upload, Glasses, CheckCircle, XCircle, Loader2, Box, Package } from 'lucide-react';
|
import { Upload, Glasses, CheckCircle, XCircle, Loader2, Box, Package, Cloud } from 'lucide-react';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { useModelStore } from '@/stores/useModelStore';
|
import { useModelStore } from '@/stores/useModelStore';
|
||||||
import { toast } from 'sonner';
|
import { toast } from 'sonner';
|
||||||
import { generateDemoBeamGLB } from '@/lib/generateDemoBeam';
|
|
||||||
import { getSupportedExtension, convertToGLB, ACCEPTED_EXTENSIONS } from '@/lib/convertToGLB';
|
import { getSupportedExtension, convertToGLB, ACCEPTED_EXTENSIONS } from '@/lib/convertToGLB';
|
||||||
import { convertIFCtoGLB } from '@/lib/convertIFC';
|
import { convertIFCtoGLB } from '@/lib/convertIFC';
|
||||||
|
|
||||||
const Index = () => {
|
const Index = () => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const fileInputRef = useRef<HTMLInputElement>(null);
|
const fileInputRef = useRef<HTMLInputElement>(null);
|
||||||
const [loadingDemo, setLoadingDemo] = useState(false);
|
|
||||||
const [loadingDemoIFC, setLoadingDemoIFC] = useState(false);
|
const [loadingDemoIFC, setLoadingDemoIFC] = useState(false);
|
||||||
const [loadingDemoCotovelo, setLoadingDemoCotovelo] = useState(false);
|
const [loadingDemoCotovelo, setLoadingDemoCotovelo] = useState(false);
|
||||||
|
const [loadingCloud, setLoadingCloud] = useState(false);
|
||||||
const [converting, setConverting] = useState(false);
|
const [converting, setConverting] = useState(false);
|
||||||
const { model, setModel, xrSupported, setXrSupported } = useModelStore();
|
const { model, setModel, xrSupported, setXrSupported } = useModelStore();
|
||||||
|
|
||||||
@@ -63,18 +62,41 @@ const Index = () => {
|
|||||||
}
|
}
|
||||||
}, [setModel]);
|
}, [setModel]);
|
||||||
|
|
||||||
const handleLoadDemo = useCallback(async () => {
|
const handleLoadCloud = useCallback(async () => {
|
||||||
setLoadingDemo(true);
|
const url = window.prompt('URL do modelo (GLB · OBJ · STL · IFC):', 'https://');
|
||||||
|
if (!url) return;
|
||||||
|
setLoadingCloud(true);
|
||||||
try {
|
try {
|
||||||
const { blob, fileName, fileSize } = await generateDemoBeamGLB();
|
const fileName = url.split('/').pop()?.split('?')[0] || 'modelo-cloud';
|
||||||
const url = URL.createObjectURL(blob);
|
const ext = getSupportedExtension(fileName);
|
||||||
setModel({ fileName, fileSize, url });
|
if (!ext) {
|
||||||
toast.success('Modelo demo "IPE 200 — 1000mm" carregado!');
|
toast.error('URL deve apontar para .GLB, .OBJ, .STL ou .IFC');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const response = await fetch(url, { mode: 'cors' });
|
||||||
|
if (!response.ok) throw new Error(`HTTP ${response.status}`);
|
||||||
|
const buffer = await response.arrayBuffer();
|
||||||
|
|
||||||
|
let blob: Blob;
|
||||||
|
let outName = fileName;
|
||||||
|
let outSize = buffer.byteLength;
|
||||||
|
if (ext === 'glb') {
|
||||||
|
blob = new Blob([buffer], { type: 'model/gltf-binary' });
|
||||||
|
} else if (ext === 'ifc') {
|
||||||
|
const r = await convertIFCtoGLB(buffer, fileName);
|
||||||
|
blob = r.blob; outName = r.fileName; outSize = r.fileSize;
|
||||||
|
} else {
|
||||||
|
const r = await convertToGLB(buffer, ext, fileName);
|
||||||
|
blob = r.blob; outName = r.fileName; outSize = r.fileSize;
|
||||||
|
}
|
||||||
|
const blobUrl = URL.createObjectURL(blob);
|
||||||
|
setModel({ fileName: outName, fileSize: outSize, url: blobUrl });
|
||||||
|
toast.success(`"${outName}" carregado da nuvem (RAM)`);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
toast.error('Falha ao gerar modelo demo');
|
toast.error('Falha ao carregar da nuvem (verifique URL/CORS)');
|
||||||
} finally {
|
} finally {
|
||||||
setLoadingDemo(false);
|
setLoadingCloud(false);
|
||||||
}
|
}
|
||||||
}, [setModel]);
|
}, [setModel]);
|
||||||
|
|
||||||
@@ -163,11 +185,11 @@ const Index = () => {
|
|||||||
<div className="grid grid-cols-3 gap-2">
|
<div className="grid grid-cols-3 gap-2">
|
||||||
<Button
|
<Button
|
||||||
variant="outline"
|
variant="outline"
|
||||||
className="h-12 w-full gap-2 border-muted-foreground/30 text-muted-foreground hover:border-primary hover:text-primary transition-all text-xs"
|
className="h-12 w-full gap-2 border-primary/40 text-primary hover:border-primary hover:bg-primary/10 transition-all text-xs"
|
||||||
onClick={handleLoadDemo}
|
onClick={handleLoadCloud}
|
||||||
disabled={loadingDemo}>
|
disabled={loadingCloud}>
|
||||||
{loadingDemo ? <Loader2 className="h-4 w-4 animate-spin" /> : <Package className="h-4 w-4" />}
|
{loadingCloud ? <Loader2 className="h-4 w-4 animate-spin" /> : <Cloud className="h-4 w-4" />}
|
||||||
{loadingDemo ? 'Gerando…' : 'Demo — Viga IPE 200'}
|
{loadingCloud ? 'Baixando…' : 'Carregar da Nuvem'}
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
Reference in New Issue
Block a user