(READ ONLY) Margin is an open annotation layer for the internet. Powered by the AT Protocol. margin.at
extension web atproto comments
99
fork

Configure Feed

Select the types of activity you want to include in your feed.

at frontend-rewrite 150 lines 6.1 kB view raw
1import React, { useEffect, useState } from "react"; 2import { useNavigate } from "react-router-dom"; 3import { Search } from "lucide-react"; 4import { getTrendingTags, type Tag } from "../../api/client"; 5 6export default function RightSidebar() { 7 const navigate = useNavigate(); 8 const [tags, setTags] = useState<Tag[]>([]); 9 const [browser] = useState<"chrome" | "firefox" | "edge" | "other">(() => { 10 if (typeof navigator === "undefined") return "other"; 11 const ua = navigator.userAgent; 12 if (/Edg\//i.test(ua)) return "edge"; 13 if (/Firefox/i.test(ua)) return "firefox"; 14 if (/Chrome/i.test(ua)) return "chrome"; 15 return "other"; 16 }); 17 const [searchQuery, setSearchQuery] = useState(""); 18 19 const handleSearch = (e: React.KeyboardEvent) => { 20 if (e.key === "Enter" && searchQuery.trim()) { 21 navigate(`/url?q=${encodeURIComponent(searchQuery.trim())}`); 22 } 23 }; 24 25 useEffect(() => { 26 getTrendingTags().then(setTags); 27 }, []); 28 29 const extensionLink = 30 browser === "firefox" 31 ? "https://addons.mozilla.org/en-US/firefox/addon/margin/" 32 : browser === "edge" 33 ? "https://microsoftedge.microsoft.com/addons/detail/margin/nfjnmllpdgcdnhmmggjihjbidmeadddn" 34 : "https://chromewebstore.google.com/detail/margin/cgpmbiiagnehkikhcbnhiagfomajncpa"; 35 36 return ( 37 <aside className="hidden xl:block w-[280px] shrink-0 sticky top-0 h-screen overflow-y-auto px-5 py-6 border-l border-surface-200/60 dark:border-surface-800/60"> 38 <div className="space-y-5"> 39 <div className="relative"> 40 <div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none"> 41 <Search 42 className="text-surface-400 dark:text-surface-500" 43 size={15} 44 /> 45 </div> 46 <input 47 type="text" 48 value={searchQuery} 49 onChange={(e) => setSearchQuery(e.target.value)} 50 onKeyDown={handleSearch} 51 placeholder="Search..." 52 className="w-full bg-surface-100 dark:bg-surface-800/80 rounded-lg pl-9 pr-4 py-2 text-sm text-surface-900 dark:text-white placeholder:text-surface-400 dark:placeholder:text-surface-500 focus:outline-none focus:ring-2 focus:ring-primary-500/20 focus:bg-white dark:focus:bg-surface-800 transition-all border border-surface-200/60 dark:border-surface-700/60" 53 /> 54 </div> 55 56 <div className="rounded-xl p-4 bg-gradient-to-br from-primary-50 to-primary-100/50 dark:from-primary-950/30 dark:to-primary-900/10 border border-primary-200/40 dark:border-primary-800/30"> 57 <h3 className="font-semibold text-sm mb-1 text-surface-900 dark:text-white"> 58 Get the Extension 59 </h3> 60 <p className="text-surface-500 dark:text-surface-400 text-xs mb-3 leading-relaxed"> 61 Highlight, annotate, and bookmark from any page. 62 </p> 63 <a 64 href={extensionLink} 65 target="_blank" 66 rel="noopener noreferrer" 67 className="flex items-center justify-center w-full px-4 py-2 bg-primary-600 hover:bg-primary-700 dark:bg-primary-500 dark:hover:bg-primary-400 text-white dark:text-white rounded-lg transition-colors text-sm font-medium" 68 > 69 Download for{" "} 70 {browser === "firefox" 71 ? "Firefox" 72 : browser === "edge" 73 ? "Edge" 74 : "Chrome"} 75 </a> 76 </div> 77 78 <div> 79 <h3 className="font-semibold text-sm px-1 mb-3 text-surface-900 dark:text-white tracking-tight"> 80 Trending 81 </h3> 82 {tags.length > 0 ? ( 83 <div className="flex flex-col"> 84 {tags.map((t) => ( 85 <a 86 key={t.tag} 87 href={`/search?q=${t.tag}`} 88 className="px-2 py-2.5 hover:bg-surface-100 dark:hover:bg-surface-800/60 rounded-lg transition-colors group" 89 > 90 <div className="font-semibold text-sm text-surface-900 dark:text-white group-hover:text-primary-600 dark:group-hover:text-primary-400 transition-colors"> 91 #{t.tag} 92 </div> 93 <div className="text-xs text-surface-400 dark:text-surface-500 mt-0.5"> 94 {t.count} {t.count === 1 ? "post" : "posts"} 95 </div> 96 </a> 97 ))} 98 </div> 99 ) : ( 100 <div className="px-2"> 101 <p className="text-sm text-surface-400 dark:text-surface-500"> 102 Nothing trending right now. 103 </p> 104 </div> 105 )} 106 </div> 107 108 <div className="px-1 pt-2"> 109 <div className="flex flex-wrap gap-x-3 gap-y-1 text-[12px] text-surface-400 dark:text-surface-500 leading-relaxed"> 110 <a 111 href="/about" 112 className="hover:underline hover:text-surface-600 dark:hover:text-surface-300" 113 > 114 About 115 </a> 116 <a 117 href="/privacy" 118 className="hover:underline hover:text-surface-600 dark:hover:text-surface-300" 119 > 120 Privacy 121 </a> 122 <a 123 href="/terms" 124 className="hover:underline hover:text-surface-600 dark:hover:text-surface-300" 125 > 126 Terms 127 </a> 128 <a 129 href="https://github.com/margin-at/margin" 130 target="_blank" 131 rel="noreferrer" 132 className="hover:underline hover:text-surface-600 dark:hover:text-surface-300" 133 > 134 GitHub 135 </a> 136 <a 137 href="https://tangled.org/margin.at/margin" 138 target="_blank" 139 rel="noreferrer" 140 className="hover:underline hover:text-surface-600 dark:hover:text-surface-300" 141 > 142 Tangled 143 </a> 144 <span>© 2026 Margin</span> 145 </div> 146 </div> 147 </div> 148 </aside> 149 ); 150}