fix: explicit tag scanning with delete UI

- Remove auto-parsing on collapse
- Add "Scan for #tags" button that parses from current textarea content
- Always show tags section with delete buttons
- Show help text when no tags exist

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Thomas Richter
2026-02-01 22:41:35 +01:00
parent a19e51b6b9
commit b00d71956e
2 changed files with 24 additions and 12 deletions

View File

@@ -128,11 +128,9 @@
debouncedSave(); debouncedSave();
} }
async function toggleExpand() { function toggleExpand() {
if (expanded) { if (expanded) {
// Collapsing - parse hashtags from content // Collapsing - reset edit state to current entry values
await handleParseTags();
// Reset edit state to current entry values
editTitle = entry.title || ''; editTitle = entry.title || '';
editContent = entry.content; editContent = entry.content;
editType = entry.type; editType = entry.type;
@@ -210,9 +208,10 @@
} }
async function handleParseTags() { async function handleParseTags() {
// Parse hashtags from content // Parse hashtags from current content in textarea
const formData = new FormData(); const formData = new FormData();
formData.append('id', entry.id); formData.append('id', entry.id);
formData.append('content', editContent);
await fetch('?/parseTags', { await fetch('?/parseTags', {
method: 'POST', method: 'POST',
@@ -520,9 +519,18 @@
</div> </div>
<!-- Tags section --> <!-- Tags section -->
{#if entry.tags?.length > 0}
<div> <div>
<label class="block text-sm font-medium text-gray-700 mb-2">Tags</label> <div class="flex items-center justify-between mb-2">
<label class="text-sm font-medium text-gray-700">Tags</label>
<button
type="button"
onclick={handleParseTags}
class="text-sm text-blue-600 hover:text-blue-700"
>
Scan for #tags
</button>
</div>
{#if entry.tags?.length > 0}
<div class="flex flex-wrap gap-2"> <div class="flex flex-wrap gap-2">
{#each entry.tags as tag} {#each entry.tags as tag}
<span class="inline-flex items-center gap-1 px-2 py-1 bg-blue-100 text-blue-700 rounded-full text-sm"> <span class="inline-flex items-center gap-1 px-2 py-1 bg-blue-100 text-blue-700 rounded-full text-sm">
@@ -540,8 +548,10 @@
</span> </span>
{/each} {/each}
</div> </div>
</div> {:else}
<p class="text-sm text-gray-500">No tags. Use #hashtags in content and click "Scan for #tags".</p>
{/if} {/if}
</div>
<div class="flex items-center justify-between"> <div class="flex items-center justify-between">
<div> <div>

View File

@@ -296,6 +296,7 @@ export const actions: Actions = {
parseTags: async ({ request }) => { parseTags: async ({ request }) => {
const formData = await request.formData(); const formData = await request.formData();
const id = formData.get('id')?.toString(); const id = formData.get('id')?.toString();
const content = formData.get('content')?.toString();
if (!id) { if (!id) {
return fail(400, { error: 'Entry ID is required' }); return fail(400, { error: 'Entry ID is required' });
@@ -306,8 +307,9 @@ export const actions: Actions = {
return fail(404, { error: 'Entry not found' }); return fail(404, { error: 'Entry not found' });
} }
// Parse hashtags from current content and merge with existing tags // Parse hashtags from provided content (or fall back to database content)
const newTags = parseHashtags(existing.content); const textToParse = content ?? existing.content;
const newTags = parseHashtags(textToParse);
const existingTags = tagRepository.getByEntryId(id).map((t) => t.name.toLowerCase()); const existingTags = tagRepository.getByEntryId(id).map((t) => t.name.toLowerCase());
const allTags = [...new Set([...existingTags, ...newTags])]; const allTags = [...new Set([...existingTags, ...newTags])];
tagRepository.updateEntryTags(id, allTags); tagRepository.updateEntryTags(id, allTags);