Tag Enhancement + bugfixes

This commit is contained in:
Stefan Hardegger
2025-08-17 17:16:40 +02:00
parent 6b83783381
commit 1a99d9830d
34 changed files with 2996 additions and 97 deletions

View File

@@ -9,6 +9,7 @@ import { Story, Collection } from '../../../../types/api';
import AppLayout from '../../../../components/layout/AppLayout';
import Button from '../../../../components/ui/Button';
import LoadingSpinner from '../../../../components/ui/LoadingSpinner';
import TagDisplay from '../../../../components/tags/TagDisplay';
import { calculateReadingTime } from '../../../../lib/settings';
export default function StoryDetailPage() {
@@ -371,12 +372,12 @@ export default function StoryDetailPage() {
<h3 className="font-semibold theme-header mb-3">Tags</h3>
<div className="flex flex-wrap gap-2">
{story.tags.map((tag) => (
<span
<TagDisplay
key={tag.id}
className="px-3 py-1 text-sm rounded-full theme-accent-bg text-white"
>
{tag.name}
</span>
tag={tag}
size="md"
clickable={false}
/>
))}
</div>
</div>

View File

@@ -6,6 +6,7 @@ import AppLayout from '../../../../components/layout/AppLayout';
import { Input, Textarea } from '../../../../components/ui/Input';
import Button from '../../../../components/ui/Button';
import TagInput from '../../../../components/stories/TagInput';
import TagSuggestions from '../../../../components/tags/TagSuggestions';
import RichTextEditor from '../../../../components/stories/RichTextEditor';
import ImageUpload from '../../../../components/ui/ImageUpload';
import AuthorSelector from '../../../../components/stories/AuthorSelector';
@@ -94,6 +95,15 @@ export default function EditStoryPage() {
setFormData(prev => ({ ...prev, tags }));
};
const handleAddSuggestedTag = (tagName: string) => {
if (!formData.tags.includes(tagName.toLowerCase())) {
setFormData(prev => ({
...prev,
tags: [...prev.tags, tagName.toLowerCase()]
}));
}
};
const handleAuthorChange = (authorName: string, authorId?: string) => {
setFormData(prev => ({
...prev,
@@ -150,8 +160,8 @@ export default function EditStoryPage() {
summary: formData.summary || undefined,
contentHtml: formData.contentHtml,
sourceUrl: formData.sourceUrl || undefined,
volume: formData.seriesName ? parseInt(formData.volume) : undefined,
seriesName: formData.seriesName || undefined,
volume: formData.seriesName && formData.volume ? parseInt(formData.volume) : undefined,
seriesName: formData.seriesName, // Send empty string to explicitly clear series
// Send authorId if we have it (existing author), otherwise send authorName (new/changed author)
...(formData.authorId ? { authorId: formData.authorId } : { authorName: formData.authorName }),
tagNames: formData.tags,
@@ -301,6 +311,16 @@ export default function EditStoryPage() {
onChange={handleTagsChange}
placeholder="Edit tags to categorize your story..."
/>
{/* Tag Suggestions */}
<TagSuggestions
title={formData.title}
content={formData.contentHtml}
summary={formData.summary}
currentTags={formData.tags}
onAddTag={handleAddSuggestedTag}
disabled={saving}
/>
</div>
{/* Series and Volume */}

View File

@@ -8,6 +8,7 @@ import { Story } from '../../../types/api';
import LoadingSpinner from '../../../components/ui/LoadingSpinner';
import Button from '../../../components/ui/Button';
import StoryRating from '../../../components/stories/StoryRating';
import TagDisplay from '../../../components/tags/TagDisplay';
import { sanitizeHtml, preloadSanitizationConfig } from '../../../lib/sanitization';
export default function StoryReadingPage() {
@@ -314,12 +315,12 @@ export default function StoryReadingPage() {
{story.tags && story.tags.length > 0 && (
<div className="flex flex-wrap justify-center gap-2 mt-4">
{story.tags.map((tag) => (
<span
<TagDisplay
key={tag.id}
className="px-3 py-1 text-sm theme-accent-bg text-white rounded-full"
>
{tag.name}
</span>
tag={tag}
size="md"
clickable={false}
/>
))}
</div>
)}