🚀 Auto-deploy: melhoria no snap e medição AR em 22/05/2026 20:51:44
This commit is contained in:
+64
-8
@@ -11,6 +11,8 @@ import { CloudLoader } from '@/components/CloudLoader';
|
||||
import { SceneModelList } from '@/components/SceneModelList';
|
||||
import { RecentFilesList } from '@/components/RecentFilesList';
|
||||
import { addRecentFile } from '@/lib/recentFiles';
|
||||
import { Switch } from '@/components/ui/switch';
|
||||
import { Label } from '@/components/ui/label';
|
||||
|
||||
const Index = () => {
|
||||
const navigate = useNavigate();
|
||||
@@ -21,6 +23,16 @@ const Index = () => {
|
||||
const [converting, setConverting] = useState(false);
|
||||
const { model, addModel, models, maxModels, xrSupported, setXrSupported } = useModelStore();
|
||||
|
||||
const [ifcConvert, setIfcConvert] = useState(() => {
|
||||
const saved = localStorage.getItem('tsxr_ifc_convert');
|
||||
return saved !== 'false';
|
||||
});
|
||||
|
||||
const handleToggleIfcConvert = (checked: boolean) => {
|
||||
setIfcConvert(checked);
|
||||
localStorage.setItem('tsxr_ifc_convert', checked ? 'true' : 'false');
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (navigator.xr) {
|
||||
navigator.xr.isSessionSupported('immersive-ar').then(setXrSupported).catch(() => setXrSupported(false));
|
||||
@@ -74,8 +86,19 @@ const Index = () => {
|
||||
if (!sigCheck.ok) {
|
||||
toast.error(sigCheck.reason!);
|
||||
if (sigCheck.detail) console.warn('[validateModelFile]', sigCheck.detail);
|
||||
setConverting(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ext === 'ifc' && !ifcConvert) {
|
||||
const url = URL.createObjectURL(file);
|
||||
addModel({ fileName: file.name, fileSize: file.size, url });
|
||||
addRecentFile(file.name, file).catch(() => {});
|
||||
toast.success(`Modelo "${file.name}" carregado de forma nativa!`);
|
||||
setConverting(false);
|
||||
return;
|
||||
}
|
||||
|
||||
let result;
|
||||
if (ext === 'ifc') {
|
||||
result = await convertIFCtoGLB(buffer, file.name);
|
||||
@@ -93,7 +116,7 @@ const Index = () => {
|
||||
} finally {
|
||||
setConverting(false);
|
||||
}
|
||||
}, [addModel]);
|
||||
}, [addModel, ifcConvert]);
|
||||
|
||||
// Carregar da Nuvem agora é encapsulado em <CloudLoader />
|
||||
|
||||
@@ -102,6 +125,14 @@ const Index = () => {
|
||||
try {
|
||||
const response = await fetch('/models/demo250hp.ifc');
|
||||
const buffer = await response.arrayBuffer();
|
||||
if (!ifcConvert) {
|
||||
const blob = new Blob([buffer], { type: 'application/octet-stream' });
|
||||
const url = URL.createObjectURL(blob);
|
||||
addModel({ fileName: 'demo250hp.ifc', fileSize: blob.size, url });
|
||||
addRecentFile('demo250hp.ifc', blob).catch(() => {});
|
||||
toast.success('Modelo demo "250 HP" (IFC nativo) carregado!');
|
||||
return;
|
||||
}
|
||||
const result = await convertIFCtoGLB(buffer, 'demo250hp.ifc');
|
||||
const url = URL.createObjectURL(result.blob);
|
||||
addModel({ fileName: result.fileName, fileSize: result.fileSize, url });
|
||||
@@ -109,17 +140,25 @@ const Index = () => {
|
||||
toast.success('Modelo demo "250 HP" (IFC) carregado!');
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
toast.error('Falha ao converter modelo demo IFC');
|
||||
toast.error('Falha ao processar modelo demo IFC');
|
||||
} finally {
|
||||
setLoadingDemoIFC(false);
|
||||
}
|
||||
}, [addModel]);
|
||||
}, [addModel, ifcConvert]);
|
||||
|
||||
const handleLoadDemoCotovelo = useCallback(async () => {
|
||||
setLoadingDemoCotovelo(true);
|
||||
try {
|
||||
const response = await fetch('/models/B126-COTOVELO.ifc');
|
||||
const buffer = await response.arrayBuffer();
|
||||
if (!ifcConvert) {
|
||||
const blob = new Blob([buffer], { type: 'application/octet-stream' });
|
||||
const url = URL.createObjectURL(blob);
|
||||
addModel({ fileName: 'B126-COTOVELO.ifc', fileSize: blob.size, url });
|
||||
addRecentFile('B126-COTOVELO.ifc', blob).catch(() => {});
|
||||
toast.success('Modelo demo "B126 Cotovelo" (IFC nativo) carregado!');
|
||||
return;
|
||||
}
|
||||
const result = await convertIFCtoGLB(buffer, 'B126-COTOVELO.ifc');
|
||||
const url = URL.createObjectURL(result.blob);
|
||||
addModel({ fileName: result.fileName, fileSize: result.fileSize, url });
|
||||
@@ -127,15 +166,15 @@ const Index = () => {
|
||||
toast.success('Modelo demo "B126 Cotovelo" (IFC) carregado!');
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
toast.error('Falha ao converter modelo demo Cotovelo');
|
||||
toast.error('Falha ao processar modelo demo Cotovelo');
|
||||
} finally {
|
||||
setLoadingDemoCotovelo(false);
|
||||
}
|
||||
}, [addModel]);
|
||||
}, [addModel, ifcConvert]);
|
||||
|
||||
const handleEnterViewer = () => {
|
||||
if (!model) {
|
||||
toast.error('Importe um modelo GLB primeiro');
|
||||
toast.error('Importe um modelo 3D primeiro');
|
||||
return;
|
||||
}
|
||||
navigate('/viewer');
|
||||
@@ -175,11 +214,28 @@ const Index = () => {
|
||||
|
||||
{converting ? <Loader2 className="h-8 w-8 animate-spin" /> : <Upload className="h-8 w-8" />}
|
||||
<div className="text-center">
|
||||
<p className="text-sm font-semibold">{converting ? 'Convertendo modelo…' : 'Importar Modelo 3D'}</p>
|
||||
<p className="text-sm font-semibold">{converting ? 'Carregando modelo…' : 'Importar Modelo 3D'}</p>
|
||||
<p className="text-xs text-muted-foreground">GLB · OBJ · STL · IFC — Escala 1:1</p>
|
||||
</div>
|
||||
</Button>
|
||||
|
||||
{/* Toggle IFC Conversion */}
|
||||
<div className="flex items-center justify-between rounded-lg border border-border bg-card/50 p-3.5">
|
||||
<div className="flex flex-col gap-0.5">
|
||||
<Label htmlFor="ifc-convert-toggle" className="text-xs font-semibold cursor-pointer text-foreground">
|
||||
Conversão IFC ➔ GLB
|
||||
</Label>
|
||||
<p className="text-[10px] text-muted-foreground">
|
||||
{ifcConvert ? 'Otimizado para AR (conversão automática)' : 'Modo nativo (carregamento bruto IFC)'}
|
||||
</p>
|
||||
</div>
|
||||
<Switch
|
||||
id="ifc-convert-toggle"
|
||||
checked={ifcConvert}
|
||||
onCheckedChange={handleToggleIfcConvert}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Demo buttons */}
|
||||
<div className="grid grid-cols-3 gap-2">
|
||||
<CloudLoader />
|
||||
@@ -254,7 +310,7 @@ const Index = () => {
|
||||
|
||||
{/* Footer */}
|
||||
<p className="mt-16 text-center font-mono text-xs text-muted-foreground/50">
|
||||
TrackSteelXR v1.02 — Q.C. Inspection
|
||||
TrackSteelXR v1.03 — Q.C. Inspection
|
||||
</p>
|
||||
</div>);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user