/ src / components / workspace / CreateWorkspaceModal.svelte
CreateWorkspaceModal.svelte
  1  <script lang="ts">
  2    import { Button, Modal, Input } from '../common';
  3    import type { ParentWorkspace } from '../../lib/types';
  4  
  5    interface Props {
  6      open: boolean;
  7      type: 'parent' | 'child' | 'standalone';
  8      parentWorkspaces?: ParentWorkspace[];
  9      selectedParentId?: string;
 10      oncreate?: (data: { name: string; type: string; parentId?: string }) => void;
 11      onclose?: () => void;
 12    }
 13  
 14    let {
 15      open = $bindable(),
 16      type = 'standalone',
 17      parentWorkspaces = [],
 18      selectedParentId,
 19      oncreate,
 20      onclose,
 21    }: Props = $props();
 22  
 23    let name = $state('');
 24    let parentId = $state('');
 25    let error = $state('');
 26    let creating = $state(false);
 27    const selectId = 'parent-workspace-select';
 28  
 29    // Reset form when modal opens
 30    $effect(() => {
 31      if (open) {
 32        name = '';
 33        // Use the prop or first available parent
 34        parentId = selectedParentId || (parentWorkspaces[0]?.id ?? '');
 35        error = '';
 36        creating = false;
 37      }
 38    });
 39  
 40    const title = $derived(
 41      type === 'parent' ? 'Create Parent Workspace' :
 42      type === 'child' ? 'Create Child Workspace' :
 43      'Create Standalone Workspace'
 44    );
 45  
 46    async function handleSubmit() {
 47      if (!name.trim()) {
 48        error = 'Name is required';
 49        return;
 50      }
 51  
 52      if (type === 'child' && !parentId) {
 53        error = 'Please select a parent workspace';
 54        return;
 55      }
 56  
 57      creating = true;
 58      error = '';
 59  
 60      try {
 61        oncreate?.({
 62          name: name.trim(),
 63          type,
 64          parentId: type === 'child' ? parentId : undefined,
 65        });
 66        open = false;
 67      } catch (e) {
 68        error = e instanceof Error ? e.message : 'Failed to create workspace';
 69      } finally {
 70        creating = false;
 71      }
 72    }
 73  
 74    function handleClose() {
 75      open = false;
 76      onclose?.();
 77    }
 78  </script>
 79  
 80  <Modal bind:open {title} onclose={handleClose}>
 81    <form onsubmit={(e) => { e.preventDefault(); handleSubmit(); }} class="space-y-4">
 82      <Input
 83        bind:value={name}
 84        label="Workspace Name"
 85        placeholder="Enter workspace name"
 86        error={error && !name.trim() ? error : undefined}
 87      />
 88  
 89      {#if type === 'child'}
 90        <div>
 91          <label for={selectId} class="block text-sm font-mono text-text-secondary mb-1.5">
 92            Parent Workspace
 93          </label>
 94          <select
 95            id={selectId}
 96            bind:value={parentId}
 97            class="w-full bg-mnemonic-bg-dark border border-phosphor-dark/50 rounded px-3 py-2 text-text-primary font-mono text-sm focus:outline-none focus:border-phosphor focus:ring-1 focus:ring-phosphor"
 98          >
 99            {#each parentWorkspaces as parent (parent.id)}
100              <option value={parent.id}>{parent.name}</option>
101            {/each}
102          </select>
103          {#if parentWorkspaces.length === 0}
104            <p class="mt-1 text-xs text-status-warning">
105              No parent workspaces available. Create a parent first.
106            </p>
107          {/if}
108        </div>
109      {/if}
110  
111      {#if error && name.trim()}
112        <p class="text-sm text-status-error">{error}</p>
113      {/if}
114    </form>
115  
116    {#snippet footer()}
117      <Button variant="ghost" onclick={handleClose}>
118        Cancel
119      </Button>
120      <Button
121        variant="primary"
122        loading={creating}
123        disabled={!name.trim() || (type === 'child' && !parentId)}
124        onclick={handleSubmit}
125      >
126        Create
127      </Button>
128    {/snippet}
129  </Modal>