Social Annotations in the Atmosphere
15
fork

Configure Feed

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

firefox working

+286 -91
+11 -1
entrypoints/sidepanel/main.ts
··· 93 93 }); 94 94 95 95 // Login handler 96 - loginBtn?.addEventListener('click', async () => { 96 + const handleLogin = async () => { 97 97 let handle = handleInput?.value.trim(); 98 98 if (!handle) { 99 99 alert('Please enter your handle'); ··· 129 129 } catch (error) { 130 130 if (authStatus) authStatus.textContent = 'Login failed'; 131 131 console.error('Login error:', error); 132 + } 133 + }; 134 + 135 + loginBtn?.addEventListener('click', handleLogin); 136 + 137 + // Handle Enter key on handle input 138 + handleInput?.addEventListener('keydown', (e) => { 139 + if (e.key === 'Enter') { 140 + e.preventDefault(); 141 + handleLogin(); 132 142 } 133 143 }); 134 144
+45 -21
public/index.html
··· 3 3 <head> 4 4 <meta charset="UTF-8"> 5 5 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 6 - <title>seams.so - Web Annotations on AT Protocol</title> 6 + <title>seams.so - Wisdom is made Together</title> 7 7 <link rel="stylesheet" href="landing.css"> 8 8 </head> 9 9 <body> 10 - <div class="container"> 11 - <header class="hero"> 12 - <h1>seams.so</h1> 13 - <p class="tagline">Web annotations on AT Protocol</p> 14 - <p class="description"> 15 - Highlight, annotate, and discuss any webpage. Built on the open AT Protocol, 16 - your annotations live in your personal data server. 17 - </p> 18 - </header> 10 + <div class="layout"> 11 + <aside class="sidebar"> 12 + <div class="sidebar-content"> 13 + <header class="hero"> 14 + <div class="logo">Seams</div> 15 + <h1>Wisdom is made Together</h1> 16 + <p class="tagline">Annotations in the Atmosphere</p> 17 + <div class="cta-buttons"> 18 + <a href="#install" class="cta-primary">Install Extension</a> 19 + </div> 20 + </header> 19 21 20 - <main class="feed-section"> 21 - <h2>Recent Annotations</h2> 22 - <div id="annotations-feed" class="annotations-feed"> 23 - <div class="loading">Loading annotations...</div> 22 + <footer class="footer desktop-footer"> 23 + <div class="footer-icons"> 24 + <a href="https://tangled.org/@hyl.st/seams.so" target="_blank" aria-label="Tangled"> 25 + <img src="https://semble.so/_next/static/media/tangled-icon.b95d4d65.svg" alt="Tangled" /> 26 + </a> 27 + <a href="https://bsky.app" target="_blank" aria-label="Bluesky"> 28 + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 360 320"> 29 + <path fill="currentColor" d="M180 142c-16.3-31.7-60.7-90.8-102-120C38.5-5.9 23.4-1 13.5 3.4 2.1 8.6 0 26.2 0 36.5c0 10.4 5.7 84.8 9.4 97.2 12.2 41 55.7 55 95.7 50.5-58.7 8.6-110.8 30-42.4 106.1 75.1 77.9 103-16.7 117.3-64.6 14.3 48 30.8 139 116 64.6 64-64.6 17.6-97.5-41.1-106.1 40 4.4 83.5-9.5 95.7-50.5 3.7-12.4 9.4-86.8 9.4-97.2 0-10.3-2-27.9-13.5-33C336.5-1 321.5-6 282 22c-41.3 29.2-85.7 88.3-102 120Z"/> 30 + </svg> 31 + </a> 32 + </div> 33 + </footer> 24 34 </div> 25 - <div id="load-more" class="load-more" style="display: none;"> 26 - <button id="load-more-btn">Load More</button> 35 + </aside> 36 + 37 + <main class="main-content"> 38 + <div class="feed-section" id="feed"> 39 + <div id="annotations-feed" class="annotations-feed"> 40 + <div class="loading">Tending the garden...</div> 41 + </div> 42 + <div id="load-more" class="load-more" style="display: none;"> 43 + <button id="load-more-btn">Nurture More</button> 44 + </div> 27 45 </div> 28 46 </main> 29 47 30 - <footer class="footer"> 31 - <p> 32 - <a href="https://github.com/Chickensoupwithrice/synthes.is" target="_blank">GitHub</a> 33 - · Built with AT Protocol 34 - </p> 48 + <footer class="footer mobile-footer"> 49 + <div class="footer-icons"> 50 + <a href="https://tangled.org/@hyl.st/seams.so" target="_blank" aria-label="Tangled"> 51 + <img src="https://semble.so/_next/static/media/tangled-icon.b95d4d65.svg" alt="Tangled" /> 52 + </a> 53 + <a href="https://bsky.app" target="_blank" aria-label="Bluesky"> 54 + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 360 320"> 55 + <path fill="currentColor" d="M180 142c-16.3-31.7-60.7-90.8-102-120C38.5-5.9 23.4-1 13.5 3.4 2.1 8.6 0 26.2 0 36.5c0 10.4 5.7 84.8 9.4 97.2 12.2 41 55.7 55 95.7 50.5-58.7 8.6-110.8 30-42.4 106.1 75.1 77.9 103-16.7 117.3-64.6 14.3 48 30.8 139 116 64.6 64-64.6 17.6-97.5-41.1-106.1 40 4.4 83.5-9.5 95.7-50.5 3.7-12.4 9.4-86.8 9.4-97.2 0-10.3-2-27.9-13.5-33C336.5-1 321.5-6 282 22c-41.3 29.2-85.7 88.3-102 120Z"/> 56 + </svg> 57 + </a> 58 + </div> 35 59 </footer> 36 60 </div> 37 61
+219 -64
public/landing.css
··· 4 4 padding: 0; 5 5 } 6 6 7 + :root { 8 + --forest-green: #2d5016; 9 + --forest-green-light: #3d6b1f; 10 + --forest-green-dark: #1f3810; 11 + } 12 + 7 13 body { 8 14 font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; 9 15 background: #fafafa; 10 16 color: #1a1a1a; 11 17 position: relative; 12 18 line-height: 1.6; 19 + margin: 0; 20 + padding: 0; 13 21 } 14 22 15 23 /* Blueprint grid background */ ··· 19 27 inset: 0; 20 28 pointer-events: none; 21 29 background-image: 22 - radial-gradient(circle, rgba(0, 0, 0, 0.08) 1px, transparent 1px); 30 + radial-gradient(circle, rgba(45, 80, 22, 0.06) 1px, transparent 1px); 23 31 background-size: 20px 20px; 24 32 z-index: 0; 25 33 } 26 34 27 - .container { 28 - max-width: 800px; 29 - margin: 0 auto; 30 - padding: 40px 20px; 35 + /* Layout - Sidebar + Main Content */ 36 + .layout { 37 + display: flex; 38 + min-height: 100vh; 31 39 position: relative; 32 40 z-index: 1; 33 41 } 34 42 35 - /* Hero Section */ 43 + /* Sidebar */ 44 + .sidebar { 45 + width: 420px; 46 + background: #fff; 47 + border-right: 2px dashed #d0d0d0; 48 + position: sticky; 49 + top: 0; 50 + height: 100vh; 51 + overflow-y: auto; 52 + flex-shrink: 0; 53 + } 54 + 55 + .sidebar-content { 56 + display: flex; 57 + flex-direction: column; 58 + justify-content: space-between; 59 + min-height: 100vh; 60 + padding: 60px 0; 61 + } 62 + 63 + /* Hero Section in Sidebar */ 36 64 .hero { 65 + flex: 1; 66 + display: flex; 67 + flex-direction: column; 68 + justify-content: center; 69 + align-items: center; 37 70 text-align: center; 38 - padding: 60px 20px; 39 - margin-bottom: 60px; 40 - border: 1px dashed #d0d0d0; 41 - border-radius: 2px; 42 - background: #fff; 71 + padding: 0 48px; 72 + } 73 + 74 + .logo { 75 + font-size: 14px; 76 + font-weight: 600; 77 + letter-spacing: 0.15em; 78 + text-transform: uppercase; 79 + color: #999; 80 + margin-bottom: 24px; 43 81 } 44 82 45 83 .hero h1 { 46 - font-size: 48px; 84 + font-size: clamp(32px, 3.5vw, 48px); 47 85 font-weight: 700; 48 - margin-bottom: 16px; 49 - color: #0085ff; 86 + margin-bottom: 24px; 87 + color: #1a1a1a; 88 + line-height: 1.1; 89 + letter-spacing: -0.02em; 50 90 } 51 91 52 92 .tagline { 53 - font-size: 20px; 93 + font-size: 14px; 54 94 color: #666; 55 - margin-bottom: 24px; 95 + margin-bottom: 32px; 96 + font-weight: 400; 97 + line-height: 1.6; 98 + } 99 + 100 + /* CTA Buttons */ 101 + .cta-buttons { 102 + display: flex; 103 + gap: 12px; 104 + flex-direction: column; 105 + align-items: center; 106 + } 107 + 108 + .cta-primary, 109 + .cta-secondary { 110 + padding: 12px 28px; 111 + border-radius: 2px; 112 + font-size: 14px; 56 113 font-weight: 500; 114 + text-decoration: none; 115 + transition: all 0.2s; 116 + border: 1px dashed; 117 + display: inline-block; 57 118 } 58 119 59 - .description { 60 - font-size: 16px; 61 - color: #555; 62 - max-width: 600px; 63 - margin: 0 auto; 64 - line-height: 1.7; 120 + .cta-primary { 121 + background: var(--forest-green); 122 + color: #fff; 123 + border-color: var(--forest-green-dark); 124 + } 125 + 126 + .cta-primary:hover { 127 + background: var(--forest-green-dark); 128 + transform: translateY(-1px); 129 + } 130 + 131 + .cta-secondary { 132 + background: transparent; 133 + color: var(--forest-green); 134 + border-color: var(--forest-green); 135 + } 136 + 137 + .cta-secondary:hover { 138 + border-color: var(--forest-green-dark); 139 + background: rgba(45, 80, 22, 0.05); 140 + } 141 + 142 + /* Main Content Area */ 143 + .main-content { 144 + flex: 1; 145 + background: #fafafa; 146 + overflow-y: auto; 65 147 } 66 148 67 149 /* Feed Section */ 68 150 .feed-section { 69 - margin-bottom: 60px; 70 - } 71 - 72 - .feed-section h2 { 73 - font-size: 24px; 74 - margin-bottom: 24px; 75 - font-weight: 600; 76 - color: #333; 151 + padding: 60px 48px; 152 + max-width: 900px; 77 153 } 78 154 79 155 .annotations-feed { 80 156 display: flex; 81 157 flex-direction: column; 82 - gap: 20px; 158 + gap: 24px; 83 159 } 84 160 85 161 /* Annotation Card */ 86 162 .annotation-card { 87 - padding: 20px; 163 + padding: 24px; 88 164 border: 1px dashed #d0d0d0; 89 165 border-radius: 2px; 90 166 background: #fff; 91 - transition: border-color 0.2s; 167 + transition: all 0.2s; 168 + position: relative; 92 169 } 93 170 94 171 .annotation-card:hover { 95 - border-color: #0085ff; 172 + border-color: var(--forest-green); 173 + box-shadow: 0 2px 8px rgba(45, 80, 22, 0.08); 96 174 } 97 175 98 176 .annotation-quote { 99 177 margin-bottom: 16px; 100 178 padding: 12px 16px; 101 179 background: #fafafa; 102 - border-left: 3px solid #0085ff; 180 + border-left: 3px solid var(--forest-green); 103 181 font-style: italic; 104 182 color: #555; 105 183 font-size: 15px; 184 + line-height: 1.6; 106 185 } 107 186 108 187 .annotation-body { ··· 124 203 } 125 204 126 205 .annotation-source { 127 - color: #0085ff; 206 + color: #1a1a1a; 128 207 text-decoration: none; 129 208 font-weight: 500; 130 209 display: inline-flex; 131 210 align-items: center; 132 211 gap: 4px; 212 + border-bottom: 1px dashed transparent; 213 + transition: border-color 0.2s; 133 214 } 134 215 135 216 .annotation-source:hover { 136 - text-decoration: underline; 217 + border-bottom-color: #1a1a1a; 137 218 } 138 219 139 220 .annotation-author { ··· 148 229 height: 24px; 149 230 border-radius: 50%; 150 231 object-fit: cover; 232 + border: 1px dashed #d0d0d0; 151 233 } 152 234 153 235 .annotation-author a { 154 - color: #0085ff; 236 + color: #1a1a1a; 155 237 text-decoration: none; 156 238 font-weight: 500; 239 + border-bottom: 1px dashed transparent; 240 + transition: border-color 0.2s; 157 241 } 158 242 159 243 .annotation-author a:hover { 160 - text-decoration: underline; 244 + border-bottom-color: #1a1a1a; 161 245 } 162 246 163 247 .annotation-time { ··· 169 253 .empty, 170 254 .error { 171 255 text-align: center; 172 - padding: 40px 20px; 256 + padding: 60px 20px; 173 257 color: #999; 174 258 font-style: italic; 175 259 } ··· 182 266 /* Load More */ 183 267 .load-more { 184 268 text-align: center; 185 - margin-top: 32px; 269 + margin-top: 40px; 186 270 } 187 271 188 272 #load-more-btn { 189 - background: #0085ff; 273 + background: var(--forest-green); 190 274 color: white; 191 - border: 1px dashed #0070dd; 275 + border: 1px dashed var(--forest-green-dark); 192 276 padding: 12px 32px; 193 277 border-radius: 2px; 194 278 cursor: pointer; 195 279 font-size: 14px; 196 280 font-weight: 500; 197 - transition: background 0.2s; 281 + transition: all 0.2s; 198 282 } 199 283 200 284 #load-more-btn:hover { 201 - background: #0070dd; 285 + background: var(--forest-green-dark); 286 + transform: translateY(-1px); 202 287 } 203 288 204 289 #load-more-btn:disabled { 205 290 background: #ccc; 206 291 border-color: #aaa; 207 292 cursor: not-allowed; 293 + transform: none; 208 294 } 209 295 210 - /* Footer */ 296 + /* Footer in Sidebar */ 211 297 .footer { 298 + padding-top: 40px; 299 + color: #999; 300 + font-size: 13px; 212 301 text-align: center; 213 - padding: 40px 20px; 214 - color: #666; 215 - font-size: 14px; 302 + margin: 0; 303 + border-top: 2px dashed #d0d0d0; 304 + } 305 + 306 + .mobile-footer { 307 + display: none; 308 + } 309 + 310 + .desktop-footer { 311 + display: block; 312 + } 313 + 314 + .footer-icons { 315 + display: flex; 316 + gap: 20px; 317 + justify-content: center; 318 + align-items: center; 216 319 } 217 320 218 - .footer a { 219 - color: #0085ff; 321 + .footer-icons a { 322 + color: #1a1a1a; 220 323 text-decoration: none; 221 - font-weight: 500; 324 + transition: all 0.2s; 325 + display: flex; 326 + align-items: center; 327 + justify-content: center; 328 + } 329 + 330 + .footer-icons a img, 331 + .footer-icons a svg { 332 + width: 32px; 333 + height: 32px; 334 + opacity: 0.6; 335 + transition: opacity 0.2s; 222 336 } 223 337 224 - .footer a:hover { 225 - text-decoration: underline; 338 + .footer-icons a:hover img, 339 + .footer-icons a:hover svg { 340 + opacity: 1; 226 341 } 227 342 228 343 /* Responsive */ 344 + @media (max-width: 1024px) { 345 + .layout { 346 + flex-direction: column; 347 + } 348 + 349 + .sidebar { 350 + width: 100%; 351 + height: auto; 352 + position: relative; 353 + border-right: none; 354 + border-bottom: 2px dashed #d0d0d0; 355 + } 356 + 357 + .sidebar-content { 358 + min-height: auto; 359 + padding: 40px 0; 360 + } 361 + 362 + .hero { 363 + justify-content: flex-start; 364 + padding: 0 32px; 365 + } 366 + 367 + .desktop-footer { 368 + display: none; 369 + } 370 + 371 + .mobile-footer { 372 + display: block; 373 + padding: 40px 32px; 374 + margin: 0; 375 + border-top: 2px dashed #d0d0d0; 376 + background: #fafafa; 377 + } 378 + 379 + .feed-section { 380 + padding: 48px 32px; 381 + } 382 + } 383 + 229 384 @media (max-width: 640px) { 230 - .container { 231 - padding: 20px 16px; 385 + .sidebar-content { 386 + padding: 32px 0; 232 387 } 233 388 234 389 .hero { 235 - padding: 40px 16px; 236 - margin-bottom: 40px; 390 + padding: 0 24px; 237 391 } 238 392 239 393 .hero h1 { 240 - font-size: 36px; 394 + font-size: 32px; 241 395 } 242 396 243 - .tagline { 244 - font-size: 18px; 397 + .mobile-footer { 398 + padding: 32px 24px; 399 + font-size: 12px; 245 400 } 246 401 247 - .description { 248 - font-size: 15px; 402 + .feed-section { 403 + padding: 32px 24px; 249 404 } 250 405 251 406 .annotation-card { 252 - padding: 16px; 407 + padding: 20px; 253 408 } 254 409 }
+2 -1
public/oauth/client-metadata.json
··· 4 4 "redirect_uris": [ 5 5 "https://synthes-is.netlify.app", 6 6 "https://synthes-is.netlify.app/oauth/callback", 7 - "https://synthes-is.netlify.app/oauth/ff/callback" 7 + "https://synthes-is.netlify.app/oauth/ff/callback", 8 + "https://e7a0b7703dc3d21c8ef60539da3ed68d27b48e8c.extensions.allizom.org/" 8 9 ], 9 10 "application_type": "web", 10 11 "client_name": "Synthesis",
+2 -4
public/oauth/ff/callback.html
··· 8 8 <p>Redirecting...</p> 9 9 <script> 10 10 // Relay to Firefox extension callback 11 - // Firefox extensions use browser.identity.getRedirectURL() which returns a moz-extension:// URL 12 - // The actual URL will be captured by launchWebAuthFlow 13 - // For Firefox, we redirect to a web_accessible_resource 14 - const extRedirect = browser.identity.getRedirectURL('extension-callback.html'); 11 + // The extension ID is synthesis@seams.so, which Firefox hashes to this subdomain 12 + const extRedirect = 'https://e7a0b7703dc3d21c8ef60539da3ed68d27b48e8c.extensions.allizom.org/'; 15 13 window.location.href = extRedirect + window.location.search + window.location.hash; 16 14 </script> 17 15 </body>
+7
wxt.config.ts
··· 8 8 ...(env.browser === 'chrome' && { 9 9 key: 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyv6hsV+VmGtQB8kZFQE0x0VYvhH0Lq2GzDhKZHh9BvPZLmFJQjXqzD9K0UzXxMXBj8FqV3WEJ9xFzDqJc+hKRBqJFQp0vXYrG8hVLVsqxW2wYpF1K8ZqMH3J0V2VB9C3KxvqBJk9kQxqHj8BvXJFqVQ3E5VqJzYqK0Hh9vK0E2J1YxLqJ8kV9qBxV0E1J2V3kQxqFz8B1XJFqVQ3E5VqJzYqK0Hh9vK0E2J1YxLqJ8kV9qBxV0E1J2V3kQxqFz8B1XJFqVQ3E5VqJzYqK0Hh9vK0E2J1YxLqJ8kV9qBxV0E1J2V3kQxqFz8B1XJFqVQ3E5VqJzYqK0Hh9vK0E2J1YxLqJ8kV9qBxV0E1J2V3kQxqFQIDAQAB', 10 10 }), 11 + ...(env.browser === 'firefox' && { 12 + browser_specific_settings: { 13 + gecko: { 14 + id: 'synthesis@seams.so', 15 + }, 16 + }, 17 + }), 11 18 permissions: [ 12 19 'storage', 13 20 'tabs',