your personal website on atproto - mirror blento.app
at mobile-editing 103 lines 2.7 kB view raw
1<script lang="ts"> 2 import { Alert, Button, Modal, Subheading } from '@foxui/core'; 3 import type { CreationModalComponentProps } from '../types'; 4 5 let { item = $bindable(), oncreate, oncancel }: CreationModalComponentProps = $props(); 6 7 let errorMessage = $state(''); 8 let fileInput = $state<HTMLInputElement | undefined>(undefined); 9 10 function handleFileSelect(event: Event) { 11 const input = event.target as HTMLInputElement; 12 const file = input.files?.[0]; 13 14 if (!file) return; 15 16 const extension = file.name.toLowerCase().split('.').pop(); 17 if (!['gltf', 'glb', 'stl', 'fbx'].includes(extension || '')) { 18 errorMessage = 'Please select a .gltf, .glb, .stl, or .fbx file'; 19 return; 20 } 21 22 errorMessage = ''; 23 item.cardData.modelFile = { 24 blob: file, 25 objectUrl: URL.createObjectURL(file), 26 name: file.name, 27 type: extension 28 }; 29 } 30 31 function clearFile() { 32 if (item.cardData.modelFile?.objectUrl) { 33 URL.revokeObjectURL(item.cardData.modelFile.objectUrl); 34 } 35 item.cardData.modelFile = undefined; 36 } 37 38 function canCreate() { 39 if (!item.cardData.modelFile) { 40 errorMessage = 'Please upload a file'; 41 return false; 42 } 43 return true; 44 } 45</script> 46 47<Modal open={true} closeButton={false}> 48 <Subheading>Add a 3D Model</Subheading> 49 50 <div> 51 <p class="text-base-600 dark:text-base-400 mb-2 text-sm"> 52 Upload a 3D model file (.glb, .stl, .fbx, or .gltf) 53 </p> 54 {#if item.cardData.modelFile} 55 <div 56 class="bg-base-100 dark:bg-base-800 flex items-center justify-between rounded-lg border p-3" 57 > 58 <span class="text-sm">{item.cardData.modelFile.name}</span> 59 <Button size="sm" variant="ghost" onclick={clearFile}>Remove</Button> 60 </div> 61 {:else} 62 <input 63 bind:this={fileInput} 64 type="file" 65 accept=".gltf,.glb,.stl,.fbx" 66 onchange={handleFileSelect} 67 class="hidden" 68 /> 69 <Button variant="secondary" onclick={() => fileInput?.click()} class="w-full"> 70 <svg 71 xmlns="http://www.w3.org/2000/svg" 72 fill="none" 73 viewBox="0 0 24 24" 74 stroke-width="1.5" 75 stroke="currentColor" 76 class="mr-2 size-5" 77 > 78 <path 79 stroke-linecap="round" 80 stroke-linejoin="round" 81 d="M3 16.5v2.25A2.25 2.25 0 0 0 5.25 21h13.5A2.25 2.25 0 0 0 21 18.75V16.5m-13.5-9L12 3m0 0 4.5 4.5M12 3v13.5" 82 /> 83 </svg> 84 Choose File 85 </Button> 86 {/if} 87 </div> 88 89 {#if errorMessage} 90 <Alert type="error" title="Error"><span>{errorMessage}</span></Alert> 91 {/if} 92 93 <div class="mt-4 flex justify-end gap-2"> 94 <Button onclick={oncancel} variant="ghost">Cancel</Button> 95 <Button 96 onclick={() => { 97 if (canCreate()) oncreate(); 98 }} 99 > 100 Create 101 </Button> 102 </div> 103</Modal>