fix: Remove unused variables in PostWindow and PostComposer

Clean up TypeScript warnings by removing:
- Unused customTitle parameter in PostWindow
- Unused isInline variable in PostComposer

All tests passing, build successful.
This commit is contained in:
Claude
2026-01-17 10:52:21 +00:00
parent 8dc61635cf
commit af6973265f
3 changed files with 158 additions and 194 deletions

View File

@@ -34,7 +34,7 @@ export interface PostWindowProps {
* post -k 30023 # Create a different kind (if supported)
* ```
*/
export function PostWindow({ kind = 1, customTitle }: PostWindowProps) {
export function PostWindow({ kind = 1 }: PostWindowProps) {
const activeAccount = use$(accountManager.active$);
const { searchProfiles } = useProfileSearch();
const { searchEmojis } = useEmojiSearch();
@@ -144,31 +144,20 @@ export function PostWindow({ kind = 1, customTitle }: PostWindowProps) {
return (
<div className="flex h-full flex-col p-4">
{/* Header */}
<div className="mb-4">
<h2 className="text-lg font-semibold">
{customTitle || `Create Kind ${kind} Note`}
</h2>
<p className="text-xs text-muted-foreground mt-1">
Publish to selected relays with mention tagging
</p>
</div>
{/* Composer */}
<div className="flex-1 min-h-0 overflow-auto">
<PostComposer
ref={composerRef}
variant="card"
onSubmit={handleSubmit}
searchProfiles={searchProfiles}
searchEmojis={searchEmojis}
showSubmitButton
submitLabel="Publish"
isLoading={isPublishing}
placeholder="What's on your mind?"
autoFocus
/>
</div>
{/* Composer - full height */}
<PostComposer
ref={composerRef}
variant="card"
onSubmit={handleSubmit}
searchProfiles={searchProfiles}
searchEmojis={searchEmojis}
showSubmitButton
submitLabel="Publish"
isLoading={isPublishing}
placeholder="What's on your mind?"
autoFocus
className="h-full"
/>
</div>
);
}

View File

@@ -6,7 +6,7 @@ import {
useMemo,
useEffect,
} from "react";
import { Loader2, Paperclip, ChevronDown } from "lucide-react";
import { Loader2, Paperclip, Hash, AtSign } from "lucide-react";
import { useGrimoire } from "@/core/state";
import { nip19 } from "nostr-tools";
import {
@@ -20,18 +20,13 @@ import type { EmojiSearchResult } from "@/services/emoji-search";
import type { ChatAction } from "@/types/chat-actions";
import { useBlossomUpload } from "@/hooks/useBlossomUpload";
import { Button } from "../ui/button";
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "../ui/tooltip";
import { Checkbox } from "../ui/checkbox";
import {
Collapsible,
CollapsibleContent,
CollapsibleTrigger,
} from "../ui/collapsible";
DropdownMenu,
DropdownMenuContent,
DropdownMenuCheckboxItem,
DropdownMenuTrigger,
} from "../ui/dropdown-menu";
/**
* Result when submitting a post
@@ -134,17 +129,6 @@ function extractHashtags(content: string): string[] {
* - Blob attachments
* - Relay selection
* - Mention p-tag selection
*
* @example
* ```tsx
* <PostComposer
* variant="card"
* onSubmit={handlePublish}
* searchProfiles={searchProfiles}
* searchEmojis={searchEmojis}
* showSubmitButton
* />
* ```
*/
export const PostComposer = forwardRef<PostComposerHandle, PostComposerProps>(
(
@@ -188,6 +172,9 @@ export const PostComposer = forwardRef<PostComposerHandle, PostComposerProps>(
const [extractedMentions, setExtractedMentions] = useState<string[]>([]);
const [selectedMentions, setSelectedMentions] = useState<string[]>([]);
// Track extracted hashtags
const [extractedHashtags, setExtractedHashtags] = useState<string[]>([]);
// Blossom upload hook
const { open: openUpload, dialog: uploadDialog } = useBlossomUpload({
accept: "image/*,video/*,audio/*",
@@ -211,7 +198,11 @@ export const PostComposer = forwardRef<PostComposerHandle, PostComposerProps>(
const serialized = editorRef.current?.getSerializedContent();
if (serialized) {
const mentions = extractMentions(serialized.text);
const hashtags = extractHashtags(serialized.text);
setExtractedMentions(mentions);
setExtractedHashtags(hashtags);
// Auto-select new mentions
setSelectedMentions((prev) => {
const newMentions = mentions.filter((m) => !prev.includes(m));
@@ -228,20 +219,19 @@ export const PostComposer = forwardRef<PostComposerHandle, PostComposerProps>(
) => {
if (!content.trim()) return;
const hashtags = extractHashtags(content);
await onSubmit({
content,
emojiTags,
blobAttachments,
relays: selectedRelays,
mentionedPubkeys: selectedMentions,
hashtags,
hashtags: extractedHashtags,
});
// Clear selections after successful submit
setExtractedMentions([]);
setSelectedMentions([]);
setExtractedHashtags([]);
};
// Expose methods via ref
@@ -253,110 +243,123 @@ export const PostComposer = forwardRef<PostComposerHandle, PostComposerProps>(
editorRef.current?.clear();
setExtractedMentions([]);
setSelectedMentions([]);
setExtractedHashtags([]);
setSelectedRelays(userRelays);
},
isEmpty: () => editorRef.current?.isEmpty() ?? true,
submit: () => {
editorRef.current?.submit();
},
}),
[],
[userRelays],
);
const isInline = variant === "inline";
const isCard = variant === "card";
// Relays section open state
const [relaysOpen, setRelaysOpen] = useState(false);
const [mentionsOpen, setMentionsOpen] = useState(false);
return (
<div
className={`flex flex-col gap-3 ${isCard ? "p-3 border rounded-lg bg-card" : ""} ${className}`}
>
{/* Editor row */}
<div className="flex gap-1.5 items-center">
{/* Attach button */}
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<Button
type="button"
variant="ghost"
size="icon"
className={`flex-shrink-0 text-muted-foreground hover:text-foreground ${isInline ? "size-7" : "size-9"}`}
onClick={openUpload}
disabled={isLoading}
>
<Paperclip className={isInline ? "size-4" : "size-5"} />
</Button>
</TooltipTrigger>
<TooltipContent side="top">
<p>Attach media</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
{/* Editor */}
<div className={`flex-1 min-w-0 ${isCard ? "editor-card" : ""}`}>
<MentionEditor
ref={editorRef}
placeholder={placeholder}
searchProfiles={searchProfiles}
searchEmojis={searchEmojis}
searchCommands={searchCommands}
onCommandExecute={onCommandExecute}
onSubmit={handleSubmit}
autoFocus={autoFocus}
className="w-full"
onChange={handleContentChange}
/>
</div>
{/* Submit button (optional) */}
{showSubmitButton && (
<Button
type="button"
variant="secondary"
size={isInline ? "sm" : "default"}
className={`flex-shrink-0 ${isInline ? "h-7 px-2 text-xs" : ""}`}
disabled={isLoading}
onClick={() => {
editorRef.current?.submit();
}}
>
{isLoading ? (
<Loader2
className={`animate-spin ${isInline ? "size-3" : "size-4"}`}
/>
) : (
submitLabel
)}
</Button>
)}
<div className={`flex flex-col gap-3 ${className}`}>
{/* Editor - full width, no border, takes up available space */}
<div className={`${isCard ? "editor-card flex-1 min-h-0" : ""}`}>
<MentionEditor
ref={editorRef}
placeholder={placeholder}
searchProfiles={searchProfiles}
searchEmojis={searchEmojis}
searchCommands={searchCommands}
onCommandExecute={onCommandExecute}
onSubmit={handleSubmit}
autoFocus={autoFocus}
className="w-full h-full"
onChange={handleContentChange}
/>
</div>
{/* Relays section (collapsible) */}
{/* Actions row: Upload, Mentions dropdown, Hashtags dropdown */}
{isCard && (
<div className="flex items-center gap-2">
{/* Upload button */}
<Button
type="button"
variant="outline"
size="sm"
onClick={openUpload}
disabled={isLoading}
className="h-8"
>
<Paperclip className="size-4 mr-1.5" />
Upload
</Button>
{/* Mentions dropdown */}
{extractedMentions.length > 0 && (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="outline" size="sm" className="h-8">
<AtSign className="size-4 mr-1.5" />
Mentions ({selectedMentions.length})
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="start" className="w-64">
{extractedMentions.map((pubkey) => (
<DropdownMenuCheckboxItem
key={pubkey}
checked={selectedMentions.includes(pubkey)}
onCheckedChange={(checked) => {
if (checked) {
setSelectedMentions([...selectedMentions, pubkey]);
} else {
setSelectedMentions(
selectedMentions.filter((p) => p !== pubkey),
);
}
}}
>
<span className="font-mono text-xs">
{pubkey.slice(0, 8)}...{pubkey.slice(-8)}
</span>
</DropdownMenuCheckboxItem>
))}
</DropdownMenuContent>
</DropdownMenu>
)}
{/* Hashtags dropdown (read-only, just shows what will be tagged) */}
{extractedHashtags.length > 0 && (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="outline" size="sm" className="h-8">
<Hash className="size-4 mr-1.5" />
Hashtags ({extractedHashtags.length})
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="start" className="w-48">
{extractedHashtags.map((tag) => (
<div
key={tag}
className="px-2 py-1.5 text-sm text-muted-foreground"
>
#{tag}
</div>
))}
</DropdownMenuContent>
</DropdownMenu>
)}
</div>
)}
{/* Relay selector */}
{isCard && userRelays.length > 0 && (
<Collapsible open={relaysOpen} onOpenChange={setRelaysOpen}>
<CollapsibleTrigger asChild>
<Button
variant="ghost"
size="sm"
className="w-full justify-between text-xs h-6"
>
<span className="text-muted-foreground">
Relays ({selectedRelays.length}/{userRelays.length})
</span>
<ChevronDown
className={`size-3 transition-transform ${relaysOpen ? "rotate-180" : ""}`}
/>
</Button>
</CollapsibleTrigger>
<CollapsibleContent className="space-y-1 pt-2">
<div className="flex flex-col gap-1.5">
<div className="text-xs font-medium text-muted-foreground">
Publish to relays:
</div>
<div className="flex flex-col gap-1.5 max-h-32 overflow-y-auto">
{userRelays.map((relay) => (
<div key={relay} className="flex items-center gap-2">
<label
key={relay}
className="flex items-center gap-2 text-sm cursor-pointer hover:bg-muted/50 p-1.5 rounded"
>
<Checkbox
id={`relay-${relay}`}
checked={selectedRelays.includes(relay)}
onCheckedChange={(checked) => {
if (checked) {
@@ -368,62 +371,35 @@ export const PostComposer = forwardRef<PostComposerHandle, PostComposerProps>(
}
}}
/>
<label
htmlFor={`relay-${relay}`}
className="text-xs font-mono cursor-pointer text-foreground"
>
<span className="font-mono text-xs flex-1">
{relay.replace(/^wss?:\/\//, "")}
</label>
</div>
</span>
</label>
))}
</CollapsibleContent>
</Collapsible>
</div>
</div>
)}
{/* Mentions section (collapsible) */}
{isCard && extractedMentions.length > 0 && (
<Collapsible open={mentionsOpen} onOpenChange={setMentionsOpen}>
<CollapsibleTrigger asChild>
<Button
variant="ghost"
size="sm"
className="w-full justify-between text-xs h-6"
>
<span className="text-muted-foreground">
Mentions ({selectedMentions.length}/{extractedMentions.length}
)
</span>
<ChevronDown
className={`size-3 transition-transform ${mentionsOpen ? "rotate-180" : ""}`}
/>
</Button>
</CollapsibleTrigger>
<CollapsibleContent className="space-y-1 pt-2">
{extractedMentions.map((pubkey) => (
<div key={pubkey} className="flex items-center gap-2">
<Checkbox
id={`mention-${pubkey}`}
checked={selectedMentions.includes(pubkey)}
onCheckedChange={(checked) => {
if (checked) {
setSelectedMentions([...selectedMentions, pubkey]);
} else {
setSelectedMentions(
selectedMentions.filter((p) => p !== pubkey),
);
}
}}
/>
<label
htmlFor={`mention-${pubkey}`}
className="text-xs font-mono cursor-pointer text-foreground"
>
{pubkey.slice(0, 8)}...{pubkey.slice(-8)}
</label>
</div>
))}
</CollapsibleContent>
</Collapsible>
{/* Big publish button */}
{showSubmitButton && (
<Button
type="button"
size="lg"
disabled={isLoading || selectedRelays.length === 0}
onClick={() => {
editorRef.current?.submit();
}}
className="w-full h-12 text-base font-semibold"
>
{isLoading ? (
<>
<Loader2 className="size-5 mr-2 animate-spin" />
Publishing...
</>
) : (
submitLabel
)}
</Button>
)}
{uploadDialog}

View File

@@ -381,11 +381,10 @@ body.animating-layout
/* Multi-row editor styles for card variant */
.editor-card .ProseMirror {
min-height: 6rem;
max-height: 24rem;
height: 100%;
overflow-y: auto;
line-height: 1.5rem;
padding: 0.5rem;
padding: 0.75rem;
}
.editor-card .ProseMirror p {