feat: dedicated 3D Models bucket in AssetBucketBrowser
Deploy to VPS / deploy (push) Has been cancelled

Add a "3D Models" bucket (path: models, accept: .glb/.gltf/.usdz)
to the cases scope. Previously 3D files were mixed into the Media
bucket at the root. Now they have their own tab with proper file
type hints and purple accent color matching the AR viewer UI.

- cases/media bucket no longer lists .glb/.gltf/.usdz in accept
- New bucketHint for models bucket warns on non-3D file uploads
- Network page 3D tab updated with purple accent + "3D Models"
  button label pointing to the dedicated bucket

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-06 15:15:44 -05:00
parent f6c3b89e08
commit 8ac372125a
2 changed files with 8 additions and 6 deletions
@@ -402,12 +402,12 @@ export default function NetworkManager() {
<div className={activeTab === "3d" ? "block animate-in fade-in" : "hidden"}>
<p className="text-xs text-[#86868B] mb-6">3D models, dimensions, and renders for the AR viewer.</p>
<div className="mb-8">
<label className="block text-[10px] uppercase tracking-widest text-[#86868B] mb-1.5 flex items-center gap-2"><Box size={12}/> 3D Model (AR) public/cases/models</label>
<label className="block text-[10px] uppercase tracking-widest text-[#A855F7] mb-1.5 flex items-center gap-2"><Box size={12}/> 3D Model (AR)</label>
<div className="flex gap-2">
<input name="model3DPath" defaultValue={editingNode.model3DPath || ""} placeholder="e.g., flxd60a.glb" className="flex-1 bg-black/60 border border-white/10 rounded-xl px-4 py-3 text-purple-400 font-mono text-sm focus:border-purple-400 outline-none" />
<button type="button" onClick={() => { setThreeDAssetTarget("model"); setThreeDAssetsOpen(true); }} className="flex items-center gap-1.5 px-4 py-3 text-xs text-emerald-400 bg-emerald-500/10 border border-emerald-500/20 rounded-xl hover:bg-emerald-500/20 font-medium shrink-0"><FolderOpen size={14} /> Browse</button>
<input name="model3DPath" defaultValue={editingNode.model3DPath || ""} placeholder="e.g., flxd60a.glb" className="flex-1 bg-black/60 border border-white/10 rounded-xl px-4 py-3 text-[#A855F7] font-mono text-sm focus:border-[#A855F7] outline-none" />
<button type="button" onClick={() => { setThreeDAssetTarget("model"); setThreeDAssetsOpen(true); }} className="flex items-center gap-1.5 px-4 py-3 text-xs text-[#A855F7] bg-[#A855F7]/10 border border-[#A855F7]/20 rounded-xl hover:bg-[#A855F7]/20 font-medium shrink-0"><FolderOpen size={14} /> 3D Models</button>
</div>
<p className="text-[9px] text-[#86868B] mt-1.5">GLB for Android/desktop. USDZ (iOS) auto-derived.</p>
<p className="text-[9px] text-[#86868B] mt-1.5">GLB for Android/desktop. USDZ (iOS) auto-derived. Files stored in the dedicated 3D Models bucket.</p>
</div>
{/* DIMENSIONS PANEL */}
+4 -2
View File
@@ -57,8 +57,9 @@ export interface BucketDef {
const BUCKETS_BY_SCOPE: Record<Scope, BucketDef[]> = {
cases: [
{ id: "media", path: "", label: "Media", description: "Cover, gallery, 3D models — files at the case root", icon: ImageIcon, accept: "image/*,.glb,.gltf,.usdz", accentColor: "#00F0FF" },
{ id: "media", path: "", label: "Media", description: "Cover and gallery images at the case root", icon: ImageIcon, accept: "image/*", accentColor: "#00F0FF" },
{ id: "videos", path: "videos", label: "Videos", description: "MP4 clips of the installation in operation", icon: Video, accept: "video/*", accentColor: "#4DA6FF" },
{ id: "models", path: "models", label: "3D Models", description: "GLB/USDZ for AR viewer and 3D display", icon: Box, accept: ".glb,.gltf,.usdz", accentColor: "#A855F7" },
{ id: "renders", path: "renders", label: "Renders", description: "3D rendered images of the equipment", icon: Box, accept: "image/*", accentColor: "#FF6B9D" },
],
applications: [
@@ -88,7 +89,8 @@ function bucketHint(bucket: BucketDef, fileName: string): string | null {
const isModel = ["glb", "gltf", "usdz"].includes(ext);
if (bucket.id === "videos" && !isVideo) return "Videos bucket usually holds .mp4 — this file may not display correctly.";
if (bucket.id === "renders" && !isImage) return "Renders bucket expects images (PNG/JPG/WebP).";
if (bucket.id === "media" && !isImage && !isVideo && !isModel) return "Most pages expect images, videos or 3D model files here.";
if (bucket.id === "models" && !isModel) return "Models bucket expects 3D files (.glb, .gltf, .usdz).";
if (bucket.id === "media" && !isImage && !isVideo) return "Media bucket expects images or videos here.";
return null;
}