import React, { useCallback, useEffect, useRef, useState } from "react"; import { useNavigate } from "react-router-dom"; import { Search, Coffee, Heart, Globe } from "lucide-react"; import { getTrendingTags, searchActors, type ActorSearchItem, type Tag, } from "../../api/client"; import { Avatar } from "../ui"; function looksLikeUrl(query: string): boolean { const q = query.trim().toLowerCase(); return ( q.startsWith("http://") || q.startsWith("https://") || /\.(com|org|net|io|dev|me|co|app|xyz|edu|gov)\b/.test(q) ); } export default function RightSidebar() { const navigate = useNavigate(); const [tags, setTags] = useState([]); const [browser] = useState<"chrome" | "firefox" | "edge" | "other">(() => { if (typeof navigator === "undefined") return "other"; const ua = navigator.userAgent; if (/Edg\//i.test(ua)) return "edge"; if (/Firefox/i.test(ua)) return "firefox"; if (/Chrome/i.test(ua)) return "chrome"; return "other"; }); const [searchQuery, setSearchQuery] = useState(""); const [suggestions, setSuggestions] = useState([]); const [showSuggestions, setShowSuggestions] = useState(false); const [selectedIndex, setSelectedIndex] = useState(-1); const inputRef = useRef(null); const suggestionsRef = useRef(null); const isSelectionRef = useRef(false); const latestQueryRef = useRef(searchQuery); useEffect(() => { latestQueryRef.current = searchQuery; if (searchQuery.length < 3 || looksLikeUrl(searchQuery)) { return; } if (isSelectionRef.current) { isSelectionRef.current = false; return; } const capturedQuery = searchQuery; const timer = setTimeout(async () => { try { const data = await searchActors(capturedQuery); if (capturedQuery !== latestQueryRef.current) return; setSuggestions(data.actors || []); setShowSuggestions((data.actors || []).length > 0); setSelectedIndex(-1); } catch (e) { console.error("Search failed:", e); } }, 300); return () => clearTimeout(timer); }, [searchQuery]); useEffect(() => { const handleClickOutside = (e: MouseEvent) => { if ( suggestionsRef.current && !suggestionsRef.current.contains(e.target as Node) && inputRef.current && !inputRef.current.contains(e.target as Node) ) { setShowSuggestions(false); } }; document.addEventListener("mousedown", handleClickOutside); return () => document.removeEventListener("mousedown", handleClickOutside); }, []); const selectSuggestion = useCallback( (actor: ActorSearchItem) => { isSelectionRef.current = true; setSearchQuery(""); setSuggestions([]); setShowSuggestions(false); navigate(`/profile/${encodeURIComponent(actor.handle)}`); }, [navigate], ); const handleKeyDown = useCallback( (e: React.KeyboardEvent) => { if (showSuggestions && suggestions.length > 0) { if (e.key === "ArrowDown") { e.preventDefault(); setSelectedIndex((prev) => Math.min(prev + 1, suggestions.length - 1), ); return; } else if (e.key === "ArrowUp") { e.preventDefault(); setSelectedIndex((prev) => Math.max(prev - 1, -1)); return; } else if (e.key === "Enter" && selectedIndex >= 0) { e.preventDefault(); selectSuggestion(suggestions[selectedIndex]); return; } else if (e.key === "Escape") { setShowSuggestions(false); return; } } if (e.key === "Enter" && searchQuery.trim()) { const q = searchQuery.trim(); if (looksLikeUrl(q)) { navigate(`/url/${encodeURIComponent(q)}`); } else if (q.includes(".")) { navigate(`/profile/${encodeURIComponent(q)}`); } else { navigate(`/search?q=${encodeURIComponent(q)}`); } setSearchQuery(""); setSuggestions([]); setShowSuggestions(false); } }, [ showSuggestions, suggestions, selectedIndex, searchQuery, navigate, selectSuggestion, ], ); useEffect(() => { getTrendingTags(10).then(setTags); }, []); const extensionLink = browser === "firefox" ? "https://addons.mozilla.org/en-US/firefox/addon/margin/" : browser === "edge" ? "https://microsoftedge.microsoft.com/addons/detail/margin/nfjnmllpdgcdnhmmggjihjbidmeadddn" : "https://chromewebstore.google.com/detail/margin/cgpmbiiagnehkikhcbnhiagfomajncpa"; return ( ); }