a tool for shared writing and social publishing

making tags case insensitive

+23 -11
+4 -2
actions/publishToPublication.ts
··· 89 89 entitiesToDelete?: string[]; 90 90 publishedAt?: string; 91 91 }): Promise<PublishResult> { 92 + // Normalize tags to lowercase for consistent storage and querying 93 + const normalizedTags = tags?.map((tag) => tag.toLowerCase()); 92 94 let identity = await getIdentityData(); 93 95 if (!identity || !identity.atp_did) { 94 96 return { ··· 241 243 publishedAt: 242 244 publishedAt || existingRecord.publishedAt || new Date().toISOString(), 243 245 ...(description && { description }), 244 - ...(tags !== undefined && { tags }), 246 + ...(normalizedTags !== undefined && { tags: normalizedTags }), 245 247 ...(coverImageBlob && { coverImage: coverImageBlob }), 246 248 // Include theme for standalone documents (not for publication documents) 247 249 ...(!publication_uri && theme && { theme }), ··· 259 261 ...(theme && { theme }), 260 262 title: title || "Untitled", 261 263 description: description || "", 262 - ...(tags !== undefined && { tags }), 264 + ...(normalizedTags !== undefined && { tags: normalizedTags }), 263 265 ...(coverImageBlob && { coverImage: coverImageBlob }), 264 266 pages: pagesArray, 265 267 publishedAt:
+6 -2
app/(home-pages)/tag/[tag]/getDocumentsByTag.ts
··· 14 14 export async function getDocumentsByTag( 15 15 tag: string, 16 16 ): Promise<{ posts: Post[] }> { 17 - // Query documents that have this tag 17 + // Normalize tag to lowercase for case-insensitive matching 18 + const normalizedTag = tag.toLowerCase(); 19 + 20 + // Query documents that have this tag (case-insensitive) 21 + // Use ilike on the JSONB text cast to match regardless of stored case 18 22 const { data: rawDocuments, error } = await supabaseServerClient 19 23 .from("documents") 20 24 .select( ··· 23 27 document_mentions_in_bsky(count), 24 28 documents_in_publications(publications(*))`, 25 29 ) 26 - .contains("data->tags", `["${tag}"]`) 30 + .filter("data->>tags", "ilike", `%"${normalizedTag}"%`) 27 31 .order("sort_date", { ascending: false }) 28 32 .limit(50); 29 33
+7 -5
components/Tags.tsx
··· 109 109 } 110 110 111 111 function selectTag(tag: string) { 112 - console.log("selected " + tag); 113 - props.setSelectedTags([...props.selectedTags, tag]); 112 + // Normalize tag to lowercase for consistent storage and querying 113 + const normalizedTag = tag.toLowerCase(); 114 + console.log("selected " + normalizedTag); 115 + props.setSelectedTags([...props.selectedTags, normalizedTag]); 114 116 clearTagInput(); 115 117 } 116 118 ··· 150 152 return ( 151 153 <div className="relative"> 152 154 <Input 153 - className="input-with-border grow w-full outline-none!" 155 + className="input-with-border grow w-full outline-none! lowercase" 154 156 id="placeholder-tag-search-input" 155 157 value={tagInputValue} 156 158 placeholder="search tags…" 157 159 onChange={(e) => { 158 - setTagInputValue(e.target.value); 160 + setTagInputValue(e.target.value.toLowerCase()); 159 161 setIsOpen(true); 160 162 setHighlightedIndex(0); 161 163 }} ··· 193 195 placeholder="search tags…" 194 196 value={tagInputValue} 195 197 onChange={(e) => { 196 - setTagInputValue(e.target.value); 198 + setTagInputValue(e.target.value.toLowerCase()); 197 199 setIsOpen(true); 198 200 setHighlightedIndex(0); 199 201 }}
+6 -2
src/replicache/mutations.ts
··· 660 660 cover_image?: string | null; 661 661 localPublishedAt?: string | null; 662 662 }> = async (args, ctx) => { 663 + // Normalize tags to lowercase for consistent storage and querying 664 + const normalizedTags = args.tags?.map((tag) => tag.toLowerCase()); 665 + 663 666 await ctx.runOnServer(async (serverCtx) => { 664 667 console.log("updating"); 665 668 const updates: { ··· 670 673 } = {}; 671 674 if (args.description !== undefined) updates.description = args.description; 672 675 if (args.title !== undefined) updates.title = args.title; 673 - if (args.tags !== undefined) updates.tags = args.tags; 676 + if (normalizedTags !== undefined) updates.tags = normalizedTags; 674 677 if (args.cover_image !== undefined) updates.cover_image = args.cover_image; 675 678 676 679 if (Object.keys(updates).length > 0) { ··· 695 698 if (args.title !== undefined) await tx.set("publication_title", args.title); 696 699 if (args.description !== undefined) 697 700 await tx.set("publication_description", args.description); 698 - if (args.tags !== undefined) await tx.set("publication_tags", args.tags); 701 + if (normalizedTags !== undefined) 702 + await tx.set("publication_tags", normalizedTags); 699 703 if (args.cover_image !== undefined) 700 704 await tx.set("publication_cover_image", args.cover_image); 701 705 if (args.localPublishedAt !== undefined)