Skip to content

Commit a82508e

Browse files
committed
add benchy sample + fix mobile selector
1 parent efa7825 commit a82508e

3 files changed

Lines changed: 48 additions & 1 deletion

File tree

public/3dbenchy.stl

10.8 MB
Binary file not shown.

src/App.tsx

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
import { computeAssignments } from './lib/materials/assignMaterials';
1111
import { parseMeshFile } from './lib/mesh/parseMesh';
1212
import { normalize } from './lib/mesh/vector';
13+
import { ACCEPTED_UPLOAD_EXTENSIONS, isMobile, isAcceptedUploadFile } from './lib/upload';
1314
import { PreviewViewport } from './components/PreviewViewport';
1415
import { UploadModal } from './components/UploadModal';
1516
import { mixFilamentsCached } from './lib/preview/mixCache';
@@ -259,6 +260,13 @@ export default function App() {
259260
return;
260261
}
261262

263+
if (!isAcceptedUploadFile(file.name)) {
264+
setOriginalMesh(null);
265+
setError('Unsupported file type. Please choose an STL, OBJ, or 3MF file.');
266+
setStatus('Import failed.');
267+
return;
268+
}
269+
262270
setIsProcessing(true);
263271
setError(null);
264272
setStatus(`Parsing ${file.name}...`);
@@ -334,6 +342,21 @@ export default function App() {
334342
// eslint-disable-next-line react-hooks/exhaustive-deps
335343
}, []);
336344

345+
// Load the bundled 3DBenchy sample on demand (Import → "Load 3D Benchy sample").
346+
const loadSample = async () => {
347+
try {
348+
const response = await fetch(`${import.meta.env.BASE_URL}3dbenchy.stl`);
349+
if (!response.ok) {
350+
throw new Error(`Sample request failed (${response.status}).`);
351+
}
352+
const blob = await response.blob();
353+
await loadFile(new File([blob], '3dbenchy.stl', { type: 'model/stl' }));
354+
} catch (caughtError) {
355+
setError(caughtError instanceof Error ? caughtError.message : 'The sample could not be loaded.');
356+
setStatus('Import failed.');
357+
}
358+
};
359+
337360
const handleFileUpload = async (event: ChangeEvent<HTMLInputElement>) => {
338361
const file = event.target.files?.[0];
339362
if (file) {
@@ -493,9 +516,12 @@ export default function App() {
493516
<section className="panel-section">
494517
<h2>Import</h2>
495518
<label className="file-drop">
496-
<input type="file" accept=".stl,.obj,.3mf,model/stl,model/3mf,text/plain" onChange={handleFileUpload} disabled={isProcessing} />
519+
<input type="file" accept={isMobile ? '' : ACCEPTED_UPLOAD_EXTENSIONS.join(',')} onChange={handleFileUpload} disabled={isProcessing} />
497520
<span>Choose STL, OBJ, or 3MF - or drop one on the window</span>
498521
</label>
522+
<button type="button" className="secondary-button" onClick={loadSample} disabled={isProcessing}>
523+
Load 3D Benchy sample
524+
</button>
499525
<p className={error ? 'status status-error' : 'status'}>{error ?? status}</p>
500526
</section>
501527

src/lib/upload.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Accepted 3D model file extensions (lowercase, with leading dot).
2+
export const ACCEPTED_UPLOAD_EXTENSIONS = ['.stl', '.obj', '.3mf'] as const;
3+
4+
// Coarse pointer ⇒ touch device. Used to relax the file-input `accept` filter,
5+
// which otherwise hides STL/OBJ/3MF files in mobile file pickers.
6+
export const isMobile =
7+
typeof window !== 'undefined' &&
8+
'matchMedia' in window &&
9+
window.matchMedia('(pointer: coarse)').matches;
10+
11+
// Split a filename into name + lowercased extension (incl. leading dot).
12+
export function splitext(_filename: string): { name: string; ext: string } {
13+
const filename = _filename || '';
14+
const ext = filename.slice(Math.max(0, filename.lastIndexOf('.')) || Infinity).toLowerCase();
15+
return { name: filename.substring(0, filename.length - ext.length), ext };
16+
}
17+
18+
export function isAcceptedUploadFile(filename: string): boolean {
19+
const { ext } = splitext(filename);
20+
return (ACCEPTED_UPLOAD_EXTENSIONS as readonly string[]).includes(ext);
21+
}

0 commit comments

Comments
 (0)