---
phase: 02-core-crud
plan: 03
type: execute
wave: 3
depends_on: [02-02]
files_modified:
  - src/lib/components/EntryCard.svelte
  - src/lib/components/CompletedToggle.svelte
  - src/routes/+page.svelte
  - src/routes/+page.server.ts
autonomous: true

must_haves:
  truths:
    - "Clicking an entry expands it to show edit fields"
    - "Editing title or content auto-saves after typing stops"
    - "User can toggle show/hide completed tasks"
    - "User can change entry type after creation"
  artifacts:
    - path: "src/lib/components/EntryCard.svelte"
      provides: "Expandable entry with inline editing"
      contains: "expanded"
    - path: "src/lib/components/CompletedToggle.svelte"
      provides: "Toggle for showing completed tasks"
      min_lines: 15
    - path: "src/routes/+page.svelte"
      provides: "Main page with completed toggle"
      contains: "CompletedToggle"
  key_links:
    - from: "src/lib/components/EntryCard.svelte"
      to: "src/routes/+page.server.ts"
      via: "form action ?/update"
      pattern: "action=.*\\?/update"
---

<objective>
Implement inline editing with expand/collapse and auto-save, plus completed tasks toggle.

Purpose: Users can click an entry to expand and edit it in place. Changes save automatically as they type (debounced). Completed tasks can be shown/hidden.

Output: Expandable EntryCard with auto-save, CompletedToggle component, updated page with toggle integration.
</objective>

<execution_context>
@/home/tho/.claude/get-shit-done/workflows/execute-plan.md
@/home/tho/.claude/get-shit-done/templates/summary.md
</execution_context>

<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/STATE.md
@.planning/phases/02-core-crud/02-CONTEXT.md
@.planning/phases/02-core-crud/02-RESEARCH.md
@.planning/phases/02-core-crud/02-02-SUMMARY.md
@src/lib/components/EntryCard.svelte
@src/routes/+page.svelte
@src/routes/+page.server.ts
</context>

<tasks>

<task type="auto">
  <name>Task 1: Add expand/collapse and inline editing to EntryCard</name>
  <files>src/lib/components/EntryCard.svelte</files>
  <action>
Update EntryCard to support expand/collapse with inline editing and debounced auto-save.

Key changes:
1. Add `expanded` state variable
2. When collapsed, show title + truncated content (current behavior)
3. When expanded, show editable fields: title input, content textarea, type selector
4. Auto-save changes with 400ms debounce using fetch to ?/update
5. Use Svelte's slide transition for smooth expand/collapse

```svelte
<script lang="ts">
  import type { Entry } from '$lib/server/db/schema';
  import { enhance } from '$app/forms';
  import { slide } from 'svelte/transition';

  interface Props {
    entry: Entry;
  }

  let { entry }: Props = $props();

  // Expand/collapse state
  let expanded = $state(false);

  // Edit state - initialize from entry
  let editTitle = $state(entry.title || '');
  let editContent = $state(entry.content);
  let editType = $state(entry.type);

  // Debounced auto-save
  let saveTimeout: ReturnType<typeof setTimeout>;
  let isSaving = $state(false);

  async function debouncedSave() {
    clearTimeout(saveTimeout);
    saveTimeout = setTimeout(async () => {
      isSaving = true;
      const formData = new FormData();
      formData.append('id', entry.id);
      formData.append('title', editTitle);
      formData.append('content', editContent);
      formData.append('type', editType);

      try {
        await fetch('?/update', {
          method: 'POST',
          body: formData
        });
      } finally {
        isSaving = false;
      }
    }, 400);
  }

  function handleInput() {
    debouncedSave();
  }

  function toggleExpand() {
    if (expanded) {
      // Collapsing - reset edit state to current entry values
      editTitle = entry.title || '';
      editContent = entry.content;
      editType = entry.type;
    }
    expanded = !expanded;
  }
</script>

<article class="p-4 border-b border-gray-100 md:border md:rounded-lg md:shadow-sm md:mb-3 bg-white">
  <!-- Collapsed view - clickable header -->
  <button
    type="button"
    onclick={toggleExpand}
    class="w-full text-left flex items-start gap-3"
  >
    {#if entry.type === 'task'}
      <form method="POST" action="?/toggleComplete" use:enhance onclick={(e) => e.stopPropagation()}>
        <input type="hidden" name="id" value={entry.id} />
        <button
          type="submit"
          class="w-6 h-6 rounded border-2 border-gray-300 flex items-center justify-center touch-target
                 {entry.status === 'done' ? 'bg-green-500 border-green-500' : 'hover:border-gray-400'}"
          aria-label={entry.status === 'done' ? 'Mark as incomplete' : 'Mark as complete'}
        >
          {#if entry.status === 'done'}
            <svg class="w-4 h-4 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
              <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7" />
            </svg>
          {/if}
        </button>
      </form>
    {:else}
      <span class="w-6 h-6 rounded-full bg-purple-100 flex items-center justify-center flex-shrink-0">
        <span class="text-purple-600 text-xs font-medium">T</span>
      </span>
    {/if}

    <div class="flex-1 min-w-0">
      <h3 class="font-medium text-gray-900 text-base md:text-lg {entry.status === 'done' ? 'line-through text-gray-400' : ''}">
        {entry.title || 'Untitled'}
      </h3>
      {#if !expanded}
        <p class="text-gray-600 text-sm md:text-base line-clamp-2 {entry.status === 'done' ? 'text-gray-400' : ''}">
          {entry.content}
        </p>
      {/if}
    </div>

    <div class="flex items-center gap-2">
      {#if isSaving}
        <span class="text-xs text-gray-400">Saving...</span>
      {/if}
      <span class="text-xs px-2 py-1 rounded-full {entry.type === 'task' ? 'bg-blue-100 text-blue-700' : 'bg-purple-100 text-purple-700'}">
        {entry.type}
      </span>
      <svg
        class="w-5 h-5 text-gray-400 transform transition-transform {expanded ? 'rotate-180' : ''}"
        fill="none"
        stroke="currentColor"
        viewBox="0 0 24 24"
      >
        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" />
      </svg>
    </div>
  </button>

  <!-- Expanded view - edit fields -->
  {#if expanded}
    <div transition:slide={{ duration: 200 }} class="mt-4 pl-9 space-y-3">
      <div>
        <label for="edit-title-{entry.id}" class="block text-sm font-medium text-gray-700 mb-1">Title</label>
        <input
          id="edit-title-{entry.id}"
          bind:value={editTitle}
          oninput={handleInput}
          placeholder="Add a title..."
          class="w-full px-3 py-2 border border-gray-200 rounded-lg text-base focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
        />
      </div>

      <div>
        <label for="edit-content-{entry.id}" class="block text-sm font-medium text-gray-700 mb-1">Content</label>
        <textarea
          id="edit-content-{entry.id}"
          bind:value={editContent}
          oninput={handleInput}
          rows="4"
          class="w-full px-3 py-2 border border-gray-200 rounded-lg text-base resize-y focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
        ></textarea>
      </div>

      <div class="flex items-center justify-between">
        <div>
          <label for="edit-type-{entry.id}" class="block text-sm font-medium text-gray-700 mb-1">Type</label>
          <select
            id="edit-type-{entry.id}"
            bind:value={editType}
            onchange={handleInput}
            class="px-3 py-2 border border-gray-200 rounded-lg text-base focus:outline-none focus:ring-2 focus:ring-blue-500"
          >
            <option value="thought">Thought</option>
            <option value="task">Task</option>
          </select>
        </div>

        <form method="POST" action="?/delete" use:enhance>
          <input type="hidden" name="id" value={entry.id} />
          <button
            type="submit"
            class="px-4 py-2 text-red-600 hover:bg-red-50 rounded-lg touch-target"
            onclick={(e) => {
              if (!confirm('Delete this entry?')) {
                e.preventDefault();
              }
            }}
          >
            Delete
          </button>
        </form>
      </div>
    </div>
  {/if}
</article>
```

Features:
- Click anywhere on header to expand/collapse
- Checkbox click doesn't trigger expand (stopPropagation)
- Smooth slide transition
- 400ms debounce on input changes
- "Saving..." indicator during save
- Delete with confirmation dialog
- Type can be changed after creation
  </action>
  <verify>
Start dev server: `npm run dev`
- Click an entry - should expand
- Edit title or content - should see "Saving..." briefly
- Click again - should collapse
- Change type - should save
- Delete - should prompt for confirmation
  </verify>
  <done>EntryCard expands/collapses with inline editing and 400ms debounced auto-save</done>
</task>

<task type="auto">
  <name>Task 2: Create CompletedToggle component and wire up showCompleted</name>
  <files>src/lib/components/CompletedToggle.svelte, src/routes/+page.svelte, src/routes/+page.server.ts</files>
  <action>
**CompletedToggle.svelte** - Toggle for showing/hiding completed tasks:

```svelte
<script lang="ts">
  import { preferences } from '$lib/stores/preferences.svelte';

  let showCompleted = $state(false);

  // Initialize from preferences (client-side only)
  $effect(() => {
    if (typeof window !== 'undefined') {
      showCompleted = $preferences.showCompleted;
    }
  });

  function handleChange(e: Event) {
    const target = e.target as HTMLInputElement;
    showCompleted = target.checked;
    $preferences.showCompleted = showCompleted;
  }
</script>

<label class="flex items-center gap-2 text-sm text-gray-600 cursor-pointer">
  <input
    type="checkbox"
    checked={showCompleted}
    onchange={handleChange}
    class="w-4 h-4 rounded border-gray-300 text-blue-600 focus:ring-blue-500"
  />
  Show completed
</label>
```

**Update +page.server.ts** - Accept showCompleted parameter:

Modify the load function to accept a URL search param:

```typescript
export const load: PageServerLoad = async ({ url }) => {
  const showCompleted = url.searchParams.get('showCompleted') === 'true';
  const entries = entryRepository.getOrdered({ showCompleted });
  return { entries, showCompleted };
};
```

**Update +page.svelte** - Add toggle and use invalidateAll for refresh:

```svelte
<script lang="ts">
  import { goto, invalidateAll } from '$app/navigation';
  import { page } from '$app/state';
  import EntryList from '$lib/components/EntryList.svelte';
  import QuickCapture from '$lib/components/QuickCapture.svelte';
  import CompletedToggle from '$lib/components/CompletedToggle.svelte';
  import { preferences } from '$lib/stores/preferences.svelte';

  let { data } = $props();

  // Sync URL with preference on mount
  $effect(() => {
    if (typeof window !== 'undefined') {
      const urlShowCompleted = $page.url.searchParams.get('showCompleted') === 'true';
      const prefShowCompleted = $preferences.showCompleted;

      if (urlShowCompleted !== prefShowCompleted) {
        const url = new URL($page.url);
        if (prefShowCompleted) {
          url.searchParams.set('showCompleted', 'true');
        } else {
          url.searchParams.delete('showCompleted');
        }
        goto(url.toString(), { replaceState: true, invalidateAll: true });
      }
    }
  });
</script>

<svelte:head>
  <title>TaskPlaner</title>
</svelte:head>

<main class="min-h-screen bg-gray-50 pb-40">
  <header class="bg-white border-b border-gray-200 sticky top-0 z-10">
    <div class="max-w-2xl mx-auto px-4 py-4 flex items-center justify-between">
      <h1 class="text-xl font-bold text-gray-900">TaskPlaner</h1>
      <CompletedToggle />
    </div>
  </header>

  <div class="max-w-2xl mx-auto px-4 py-4">
    <EntryList entries={data.entries} />
  </div>

  <QuickCapture />
</main>
```

Note: The preference syncs with URL so the server can filter correctly. When toggle changes, URL updates and data reloads.
  </action>
  <verify>
Start dev server: `npm run dev`
- Create a task, mark it complete
- Should disappear from list
- Check "Show completed" - completed task should appear
- Refresh page - toggle state should persist
  </verify>
  <done>CompletedToggle shows/hides completed tasks, state persists in preferences and URL</done>
</task>

</tasks>

<verification>
After all tasks complete:

1. **TypeScript**: `npm run check` passes
2. **Expand/collapse**: Click entry to expand, click again to collapse
3. **Inline editing**: Title, content, type can be edited in expanded view
4. **Auto-save**: Editing shows "Saving..." then saves (no need to click save)
5. **Delete**: Delete button in expanded view with confirmation
6. **Completed toggle**: Checkbox in header shows/hides completed tasks
7. **Persistence**: Toggle state persists across page refreshes

Requirements satisfied:
- CORE-02: Edit entry ✓
- CORE-03: Delete entry ✓ (with confirmation)
- CORE-06: Add notes (append to content) ✓
</verification>

<success_criteria>
- EntryCard expands on click to show edit fields
- Changes auto-save with 400ms debounce
- Delete button with confirmation dialog
- CompletedToggle shows/hides completed tasks
- Toggle state persists in localStorage
- TypeScript compilation passes
</success_criteria>

<output>
After completion, create `.planning/phases/02-core-crud/02-03-SUMMARY.md`
</output>
