Full parallel implementation of typesense and opensearch

This commit is contained in:
Stefan Hardegger
2025-09-20 09:40:09 +02:00
parent 54df3c471e
commit f1773873d4
20 changed files with 2869 additions and 290 deletions

View File

@@ -17,17 +17,34 @@ interface StoryCardProps {
onSelect?: () => void;
}
export default function StoryCard({
story,
viewMode,
onUpdate,
showSelection = false,
isSelected = false,
onSelect
export default function StoryCard({
story,
viewMode,
onUpdate,
showSelection = false,
isSelected = false,
onSelect
}: StoryCardProps) {
const [rating, setRating] = useState(story.rating || 0);
const [updating, setUpdating] = useState(false);
// Helper function to get tags from either tags array or tagNames array
const getTags = () => {
if (Array.isArray(story.tags) && story.tags.length > 0) {
return story.tags;
}
if (Array.isArray(story.tagNames) && story.tagNames.length > 0) {
// Convert tagNames to Tag objects for display compatibility
return story.tagNames.map((name, index) => ({
id: `tag-${index}`, // Temporary ID for display
name: name
}));
}
return [];
};
const displayTags = getTags();
const handleRatingClick = async (e: React.MouseEvent, newRating: number) => {
// Prevent default and stop propagation to avoid triggering navigation
e.preventDefault();
@@ -58,7 +75,7 @@ export default function StoryCard({
const calculateReadingPercentage = (story: Story): number => {
if (!story.readingPosition) return 0;
const totalLength = story.contentPlain?.length || story.contentHtml.length;
const totalLength = story.contentPlain?.length || story.contentHtml?.length || 0;
if (totalLength === 0) return 0;
return Math.round((story.readingPosition / totalLength) * 100);
@@ -124,9 +141,9 @@ export default function StoryCard({
</div>
{/* Tags */}
{Array.isArray(story.tags) && story.tags.length > 0 && (
{displayTags.length > 0 && (
<div className="flex flex-wrap gap-1 mt-2">
{story.tags.slice(0, 3).map((tag) => (
{displayTags.slice(0, 3).map((tag) => (
<TagDisplay
key={tag.id}
tag={tag}
@@ -134,9 +151,9 @@ export default function StoryCard({
clickable={false}
/>
))}
{story.tags.length > 3 && (
{displayTags.length > 3 && (
<span className="px-2 py-1 text-xs theme-text">
+{story.tags.length - 3} more
+{displayTags.length - 3} more
</span>
)}
</div>
@@ -260,9 +277,9 @@ export default function StoryCard({
</div>
{/* Tags */}
{Array.isArray(story.tags) && story.tags.length > 0 && (
{displayTags.length > 0 && (
<div className="flex flex-wrap gap-1 mt-2">
{story.tags.slice(0, 2).map((tag) => (
{displayTags.slice(0, 2).map((tag) => (
<TagDisplay
key={tag.id}
tag={tag}
@@ -270,9 +287,9 @@ export default function StoryCard({
clickable={false}
/>
))}
{story.tags.length > 2 && (
{displayTags.length > 2 && (
<span className="px-2 py-1 text-xs theme-text">
+{story.tags.length - 2}
+{displayTags.length - 2}
</span>
)}
</div>