fix: Fix text alignment, hashtag count, and preload contact profiles

Critical UX fixes:
- Force left text alignment in editor with !important (fixes centered text)
- Add flex layout to editor-card wrapper to prevent centering
- Fix placeholder alignment to be left-aligned

Hashtag/mention sync fixes:
- Properly sync selected hashtags/mentions with extracted ones
- Remove items that are no longer in content (prevents count drift)
- Fixes hashtag count showing wrong number

Profile loading:
- Preload contact profiles when PostWindow opens
- Subscribe to all contact profiles to trigger fetching
- Ensures @ autocomplete has profiles available immediately
- Auto-unsubscribe after 1 second to clean up

All issues from screenshot addressed:
 Text alignment now left (was centered)
 Hashtag count accurate (syncs with content)
 @ autocomplete shows contact profiles
 Contact profiles preloaded on mount

Build successful.
This commit is contained in:
Claude
2026-01-17 11:27:10 +00:00
parent 15e09b5f35
commit f173d431fb
3 changed files with 37 additions and 7 deletions

View File

@@ -1,4 +1,4 @@
import { useCallback, useRef, useState, useMemo } from "react";
import { useCallback, useRef, useState, useMemo, useEffect } from "react";
import { use$ } from "applesauce-react/hooks";
import accountManager from "@/services/accounts";
import { toast } from "sonner";
@@ -70,6 +70,22 @@ export function PostWindow({ kind = 1 }: PostWindowProps) {
return new Set(pubkeys);
}, [contactList]);
// Preload contact profiles for @ autocomplete
useEffect(() => {
if (contactPubkeys.size === 0) return;
// Load profiles for all contacts (trigger fetching if not in store)
const pubkeysArray = Array.from(contactPubkeys);
for (const pubkey of pubkeysArray) {
// Subscribe to profile - this triggers loading if not in store
const sub = eventStore.replaceable(0, pubkey).subscribe(() => {
// Profile loaded or updated
});
// Clean up subscription after initial load
setTimeout(() => sub.unsubscribe(), 1000);
}
}, [contactPubkeys]);
// Filter profile search to only contacts
const searchContactProfiles = useCallback(
async (query: string): Promise<ProfileSearchResult[]> => {

View File

@@ -223,16 +223,20 @@ export const PostComposer = forwardRef<PostComposerHandle, PostComposerProps>(
setExtractedMentions(mentions);
setExtractedHashtags(hashtags);
// Auto-select new mentions
// Sync selected mentions with extracted mentions
// Remove mentions that are no longer in content
setSelectedMentions((prev) => {
const stillPresent = prev.filter((m) => mentions.includes(m));
const newMentions = mentions.filter((m) => !prev.includes(m));
return [...prev, ...newMentions];
return [...stillPresent, ...newMentions];
});
// Auto-select new hashtags
// Sync selected hashtags with extracted hashtags
// Remove hashtags that are no longer in content
setSelectedHashtags((prev) => {
const stillPresent = prev.filter((h) => hashtags.includes(h));
const newHashtags = hashtags.filter((h) => !prev.includes(h));
return [...prev, ...newHashtags];
return [...stillPresent, ...newHashtags];
});
}
};

View File

@@ -380,25 +380,35 @@ body.animating-layout
}
/* Multi-row editor styles for card variant */
.editor-card {
display: flex;
flex-direction: column;
align-items: stretch;
}
.editor-card .ProseMirror {
min-height: 6rem; /* 4 rows at 1.5rem line-height */
overflow-y: auto;
line-height: 1.5rem;
padding: 0.75rem;
text-align: left;
text-align: left !important;
vertical-align: top;
}
.editor-card .ProseMirror p {
line-height: 1.5rem;
margin-bottom: 0.5rem;
text-align: left;
text-align: left !important;
}
.editor-card .ProseMirror p:last-child {
margin-bottom: 0;
}
.editor-card .ProseMirror p.is-editor-empty:first-child::before {
text-align: left !important;
}
/* Mention styles */
.ProseMirror .mention {
color: hsl(var(--primary));