(READ ONLY) Margin is an open annotation layer for the internet. Powered by the AT Protocol.
margin.at
extension
web
atproto
comments
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}