ideas: add inline edit for own ideas (author + admin)
This commit is contained in:
@@ -24,6 +24,42 @@
|
||||
let submitting = false;
|
||||
let formError = '';
|
||||
|
||||
let editingId: string | null = null;
|
||||
let editTitle = '';
|
||||
let editBody = '';
|
||||
let editSaving = false;
|
||||
|
||||
function startEdit(idea: Idea) {
|
||||
editingId = idea.id;
|
||||
editTitle = idea.title;
|
||||
editBody = idea.body;
|
||||
}
|
||||
|
||||
function cancelEdit() {
|
||||
editingId = null;
|
||||
}
|
||||
|
||||
async function saveEdit(idea: Idea) {
|
||||
if (!editTitle.trim()) return;
|
||||
editSaving = true;
|
||||
try {
|
||||
const r = await fetch(`/api/ideas/${idea.id}`, {
|
||||
method: 'PATCH',
|
||||
credentials: 'include',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ title: editTitle.trim(), body: editBody.trim() }),
|
||||
});
|
||||
if (r.ok) {
|
||||
idea.title = editTitle.trim();
|
||||
idea.body = editBody.trim();
|
||||
ideas = ideas;
|
||||
editingId = null;
|
||||
}
|
||||
} finally {
|
||||
editSaving = false;
|
||||
}
|
||||
}
|
||||
|
||||
function relativeTime(ts: number): string {
|
||||
const diff = Math.floor(Date.now() / 1000) - ts;
|
||||
if (diff < 60) return 'just now';
|
||||
@@ -216,35 +252,68 @@
|
||||
|
||||
<!-- Content -->
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-start justify-between gap-2">
|
||||
<p class="font-medium text-sm" style="color: var(--text-primary)">
|
||||
{#if done}<span class="mr-1.5 text-green-500">✓</span>{/if}{idea.title}
|
||||
</p>
|
||||
<div class="flex items-center gap-1 shrink-0">
|
||||
{#if isAdmin}
|
||||
<button
|
||||
on:click={() => toggleStatus(idea)}
|
||||
class="text-xs px-1.5 py-0.5 rounded transition-colors"
|
||||
style="color: {done ? 'var(--text-5)' : 'var(--accent)'}; border: 1px solid {done ? 'var(--border-sub)' : 'var(--accent)'}"
|
||||
title={done ? 'Mark as open' : 'Mark as done'}
|
||||
>{done ? 'reopen' : 'done'}</button>
|
||||
{/if}
|
||||
{#if isAdmin || idea.author === myHandle}
|
||||
<button
|
||||
on:click={() => deleteIdea(idea)}
|
||||
class="text-xs px-1.5 py-0.5 rounded transition-colors hover:text-red-400"
|
||||
style="color: var(--text-5)"
|
||||
title="Delete"
|
||||
>×</button>
|
||||
{/if}
|
||||
{#if editingId === idea.id}
|
||||
<input
|
||||
bind:value={editTitle}
|
||||
class="w-full rounded-lg px-3 py-1.5 text-sm mb-2"
|
||||
style="background: var(--bg-elevated); border: 1px solid var(--border-sub); color: var(--text-primary)"
|
||||
/>
|
||||
<textarea
|
||||
bind:value={editBody}
|
||||
rows="2"
|
||||
class="w-full rounded-lg px-3 py-1.5 text-sm mb-2 resize-none"
|
||||
style="background: var(--bg-elevated); border: 1px solid var(--border-sub); color: var(--text-primary)"
|
||||
></textarea>
|
||||
<div class="flex gap-2">
|
||||
<button
|
||||
on:click={() => saveEdit(idea)}
|
||||
disabled={editSaving || !editTitle.trim()}
|
||||
class="px-3 py-1 rounded-lg text-xs font-medium text-white transition-opacity hover:opacity-90 disabled:opacity-50"
|
||||
style="background: var(--accent)"
|
||||
>{editSaving ? 'Saving…' : 'Save'}</button>
|
||||
<button
|
||||
on:click={cancelEdit}
|
||||
class="px-3 py-1 rounded-lg text-xs transition-colors"
|
||||
style="color: var(--text-5)"
|
||||
>Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
{#if idea.body}
|
||||
<p class="text-xs mt-1" style="color: var(--text-4)">{idea.body}</p>
|
||||
{:else}
|
||||
<div class="flex items-start justify-between gap-2">
|
||||
<p class="font-medium text-sm" style="color: var(--text-primary)">
|
||||
{#if done}<span class="mr-1.5 text-green-500">✓</span>{/if}{idea.title}
|
||||
</p>
|
||||
<div class="flex items-center gap-1 shrink-0">
|
||||
{#if isAdmin}
|
||||
<button
|
||||
on:click={() => toggleStatus(idea)}
|
||||
class="text-xs px-1.5 py-0.5 rounded transition-colors"
|
||||
style="color: {done ? 'var(--text-5)' : 'var(--accent)'}; border: 1px solid {done ? 'var(--border-sub)' : 'var(--accent)'}"
|
||||
title={done ? 'Mark as open' : 'Mark as done'}
|
||||
>{done ? 'reopen' : 'done'}</button>
|
||||
{/if}
|
||||
{#if isAdmin || idea.author === myHandle}
|
||||
<button
|
||||
on:click={() => startEdit(idea)}
|
||||
class="text-xs px-1.5 py-0.5 rounded transition-colors hover:text-white"
|
||||
style="color: var(--text-5)"
|
||||
title="Edit"
|
||||
>✎</button>
|
||||
<button
|
||||
on:click={() => deleteIdea(idea)}
|
||||
class="text-xs px-1.5 py-0.5 rounded transition-colors hover:text-red-400"
|
||||
style="color: var(--text-5)"
|
||||
title="Delete"
|
||||
>×</button>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
{#if idea.body}
|
||||
<p class="text-xs mt-1" style="color: var(--text-4)">{idea.body}</p>
|
||||
{/if}
|
||||
<p class="text-xs mt-1.5" style="color: var(--text-5)">
|
||||
@{idea.author} · {relativeTime(idea.created_at)}
|
||||
</p>
|
||||
{/if}
|
||||
<p class="text-xs mt-1.5" style="color: var(--text-5)">
|
||||
@{idea.author} · {relativeTime(idea.created_at)}
|
||||
</p>
|
||||
</div>
|
||||
</li>
|
||||
{/each}
|
||||
|
||||
Reference in New Issue
Block a user