mobile bluesky app made with flutter lazurite.stormlightlabs.org/
mobile bluesky flutter
3
fork

Configure Feed

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

at main 690 lines 22 kB view raw
1<!doctype html> 2<html lang="en"> 3 <head> 4 <meta charset="UTF-8" /> 5 <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" /> 6 <title>Search - Lazurite</title> 7 <link rel="preconnect" href="https://fonts.googleapis.com" /> 8 <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> 9 <link 10 href="https://fonts.googleapis.com/css2?family=DM+Sans:ital,opsz,wght@0,9..40,100..1000;1,9..40,100..1000&display=swap" 11 rel="stylesheet" /> 12 <link rel="stylesheet" href="styles.css" /> 13 <style> 14 .search-container { 15 padding-bottom: 88px; 16 } 17 18 .search-bar { 19 padding: 12px 16px; 20 border-bottom: 1px solid var(--border); 21 display: flex; 22 align-items: center; 23 gap: 12px; 24 } 25 26 .search-input-wrapper { 27 flex: 1; 28 position: relative; 29 } 30 31 .search-input-wrapper svg { 32 position: absolute; 33 left: 12px; 34 top: 50%; 35 transform: translateY(-50%); 36 width: 18px; 37 height: 18px; 38 color: var(--text-muted); 39 } 40 41 .search-input { 42 width: 100%; 43 padding: 10px 12px 10px 38px; 44 border: 1px solid var(--border); 45 border-radius: 9999px; 46 background-color: var(--surface); 47 color: var(--text-primary); 48 font-size: 15px; 49 transition: border-color 0.2s ease; 50 } 51 52 .search-input:focus { 53 outline: none; 54 border-color: var(--accent-primary); 55 } 56 57 .search-input::placeholder { 58 color: var(--text-muted); 59 } 60 61 .search-cancel { 62 background: none; 63 border: none; 64 color: var(--accent-primary); 65 font-size: 15px; 66 font-weight: 500; 67 cursor: pointer; 68 white-space: nowrap; 69 } 70 71 /* Tabs */ 72 .search-tabs { 73 display: flex; 74 border-bottom: 1px solid var(--border); 75 background-color: var(--bg); 76 } 77 78 .search-tab { 79 flex: 1; 80 padding: 14px; 81 text-align: center; 82 font-weight: 600; 83 font-size: 15px; 84 color: var(--text-secondary); 85 cursor: pointer; 86 border-bottom: 2px solid transparent; 87 transition: all 0.2s ease; 88 background: none; 89 border-top: none; 90 border-left: none; 91 border-right: none; 92 } 93 94 .search-tab:hover { 95 background-color: var(--surface); 96 color: var(--text-primary); 97 } 98 99 .search-tab.active { 100 color: var(--text-primary); 101 border-bottom-color: var(--accent-primary); 102 } 103 104 /* Sort Toggle */ 105 .search-sort { 106 display: flex; 107 align-items: center; 108 gap: 8px; 109 padding: 10px 16px; 110 border-bottom: 1px solid var(--border); 111 } 112 113 .search-sort-label { 114 font-size: 13px; 115 color: var(--text-secondary); 116 } 117 118 .sort-toggle { 119 display: flex; 120 background-color: var(--surface); 121 border-radius: 8px; 122 border: 1px solid var(--border); 123 overflow: hidden; 124 } 125 126 .sort-option { 127 padding: 6px 14px; 128 font-size: 13px; 129 font-weight: 500; 130 border: none; 131 background: none; 132 color: var(--text-secondary); 133 cursor: pointer; 134 transition: all 0.2s ease; 135 } 136 137 .sort-option.active { 138 background-color: var(--accent-primary); 139 color: white; 140 } 141 142 /* Search History */ 143 .search-history-header { 144 display: flex; 145 align-items: center; 146 justify-content: space-between; 147 padding: 12px 16px; 148 } 149 150 .search-history-title { 151 font-size: 14px; 152 font-weight: 600; 153 color: var(--text-primary); 154 } 155 156 .search-history-clear { 157 background: none; 158 border: none; 159 color: var(--accent-primary); 160 font-size: 13px; 161 font-weight: 500; 162 cursor: pointer; 163 } 164 165 .history-item { 166 display: flex; 167 align-items: center; 168 justify-content: space-between; 169 padding: 12px 16px; 170 cursor: pointer; 171 transition: background-color 0.2s ease; 172 } 173 174 .history-item:hover { 175 background-color: var(--surface); 176 } 177 178 .history-item-left { 179 display: flex; 180 align-items: center; 181 gap: 12px; 182 } 183 184 .history-icon { 185 width: 20px; 186 height: 20px; 187 color: var(--text-muted); 188 } 189 190 .history-query { 191 font-size: 15px; 192 color: var(--text-primary); 193 } 194 195 .history-meta { 196 font-size: 12px; 197 color: var(--text-muted); 198 } 199 200 .history-delete { 201 width: 20px; 202 height: 20px; 203 color: var(--text-muted); 204 background: none; 205 border: none; 206 cursor: pointer; 207 transition: color 0.2s ease; 208 } 209 210 .history-delete:hover { 211 color: var(--accent-error); 212 } 213 214 /* Actor Results */ 215 .actor-result { 216 display: flex; 217 align-items: center; 218 gap: 12px; 219 padding: 12px 16px; 220 border-bottom: 1px solid var(--border); 221 cursor: pointer; 222 transition: background-color 0.2s ease; 223 } 224 225 .actor-result:hover { 226 background-color: var(--surface); 227 } 228 229 .actor-result-info { 230 flex: 1; 231 min-width: 0; 232 } 233 234 .actor-result-name { 235 font-weight: 600; 236 font-size: 15px; 237 color: var(--text-primary); 238 } 239 240 .actor-result-handle { 241 font-size: 14px; 242 color: var(--text-secondary); 243 } 244 245 .actor-result-bio { 246 font-size: 13px; 247 color: var(--text-muted); 248 margin-top: 2px; 249 display: -webkit-box; 250 line-clamp: 1; 251 -webkit-line-clamp: 1; 252 -webkit-box-orient: vertical; 253 overflow: hidden; 254 } 255 256 .follow-btn { 257 padding: 6px 16px; 258 border-radius: 9999px; 259 border: 1.5px solid var(--accent-primary); 260 background: none; 261 color: var(--accent-primary); 262 font-size: 13px; 263 font-weight: 600; 264 cursor: pointer; 265 transition: all 0.2s ease; 266 flex-shrink: 0; 267 } 268 269 .follow-btn:hover { 270 background-color: var(--accent-primary); 271 color: white; 272 } 273 274 /* Typeahead */ 275 .typeahead-section { 276 border-bottom: 1px solid var(--border); 277 } 278 279 .typeahead-label { 280 padding: 8px 16px; 281 font-size: 12px; 282 font-weight: 600; 283 color: var(--text-muted); 284 text-transform: uppercase; 285 letter-spacing: 0.5px; 286 } 287 288 .post-facet-mention { 289 color: var(--accent-primary); 290 text-decoration: none; 291 font-weight: 500; 292 } 293 294 .post-facet-hashtag { 295 color: var(--accent-secondary); 296 text-decoration: none; 297 font-weight: 500; 298 } 299 </style> 300 </head> 301 <body> 302 <div class="mobile-container"> 303 <!-- Search Bar (replaces standard header) --> 304 <div class="search-bar"> 305 <div class="search-input-wrapper"> 306 <svg 307 viewBox="0 0 24 24" 308 fill="none" 309 stroke="currentColor" 310 stroke-width="2" 311 stroke-linecap="round" 312 stroke-linejoin="round"> 313 <circle cx="11" cy="11" r="8" /> 314 <line x1="21" y1="21" x2="16.65" y2="16.65" /> 315 </svg> 316 <input class="search-input" type="text" placeholder="Search posts or people" value="atproto" /> 317 </div> 318 <button class="search-cancel">Cancel</button> 319 </div> 320 321 <!-- Tabs --> 322 <div class="search-tabs"> 323 <button class="search-tab active">Posts</button> 324 <button class="search-tab">People</button> 325 </div> 326 327 <!-- Sort --> 328 <div class="search-sort"> 329 <span class="search-sort-label">Sort by</span> 330 <div class="sort-toggle"> 331 <button class="sort-option active">Top</button> 332 <button class="sort-option">Latest</button> 333 </div> 334 </div> 335 336 <div class="search-container"> 337 <!-- Post Results --> 338 <article class="post-card"> 339 <div class="post-header"> 340 <div class="avatar">PB</div> 341 <div class="post-author"> 342 <div class="post-author-name">Paul Frazee</div> 343 <div class="post-author-handle">@pfrazee.com · <span class="post-timestamp">3h</span></div> 344 </div> 345 </div> 346 <div class="post-content"> 347 We just shipped a major update to the 348 <a href="#" class="post-facet-mention">@atproto</a> federation code. Self-hosting your own PDS is now easier 349 than ever. 350 <a href="#" class="post-facet-hashtag">#atproto</a> 351 <a href="#" class="post-facet-hashtag">#decentralized</a> 352 </div> 353 <div class="post-actions"> 354 <button class="post-action"> 355 <svg 356 viewBox="0 0 24 24" 357 fill="none" 358 stroke="currentColor" 359 stroke-width="2" 360 stroke-linecap="round" 361 stroke-linejoin="round"> 362 <path 363 d="M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z" /> 364 </svg> 365 67 366 </button> 367 <button class="post-action"> 368 <svg 369 viewBox="0 0 24 24" 370 fill="none" 371 stroke="currentColor" 372 stroke-width="2" 373 stroke-linecap="round" 374 stroke-linejoin="round"> 375 <polyline points="17 1 21 5 17 9" /> 376 <path d="M3 11V9a4 4 0 0 1 4-4h14" /> 377 <polyline points="7 23 3 19 7 15" /> 378 <path d="M21 13v2a4 4 0 0 1-4 4H3" /> 379 </svg> 380 34 381 </button> 382 <button class="post-action"> 383 <svg 384 viewBox="0 0 24 24" 385 fill="none" 386 stroke="currentColor" 387 stroke-width="2" 388 stroke-linecap="round" 389 stroke-linejoin="round"> 390 <path 391 d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z" /> 392 </svg> 393 512 394 </button> 395 <button class="post-action"> 396 <svg 397 viewBox="0 0 24 24" 398 fill="none" 399 stroke="currentColor" 400 stroke-width="2" 401 stroke-linecap="round" 402 stroke-linejoin="round"> 403 <path d="M4 12v8a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-8" /> 404 <polyline points="16 6 12 2 8 6" /> 405 <line x1="12" y1="2" x2="12" y2="15" /> 406 </svg> 407 </button> 408 </div> 409 </article> 410 411 <article class="post-card"> 412 <div class="post-header"> 413 <div class="avatar">JK</div> 414 <div class="post-author"> 415 <div class="post-author-name">Jake Gold</div> 416 <div class="post-author-handle">@jake.bsky.social · <span class="post-timestamp">6h</span></div> 417 </div> 418 </div> 419 <div class="post-content"> 420 The <a href="#" class="post-facet-hashtag">#atproto</a> ecosystem is growing fast. More and more third-party 421 apps popping up every week. The open protocol approach is really paying off 🌐 422 </div> 423 <div class="post-actions"> 424 <button class="post-action"> 425 <svg 426 viewBox="0 0 24 24" 427 fill="none" 428 stroke="currentColor" 429 stroke-width="2" 430 stroke-linecap="round" 431 stroke-linejoin="round"> 432 <path 433 d="M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z" /> 434 </svg> 435 23 436 </button> 437 <button class="post-action"> 438 <svg 439 viewBox="0 0 24 24" 440 fill="none" 441 stroke="currentColor" 442 stroke-width="2" 443 stroke-linecap="round" 444 stroke-linejoin="round"> 445 <polyline points="17 1 21 5 17 9" /> 446 <path d="M3 11V9a4 4 0 0 1 4-4h14" /> 447 <polyline points="7 23 3 19 7 15" /> 448 <path d="M21 13v2a4 4 0 0 1-4 4H3" /> 449 </svg> 450 11 451 </button> 452 <button class="post-action"> 453 <svg 454 viewBox="0 0 24 24" 455 fill="none" 456 stroke="currentColor" 457 stroke-width="2" 458 stroke-linecap="round" 459 stroke-linejoin="round"> 460 <path 461 d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z" /> 462 </svg> 463 178 464 </button> 465 <button class="post-action"> 466 <svg 467 viewBox="0 0 24 24" 468 fill="none" 469 stroke="currentColor" 470 stroke-width="2" 471 stroke-linecap="round" 472 stroke-linejoin="round"> 473 <path d="M4 12v8a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-8" /> 474 <polyline points="16 6 12 2 8 6" /> 475 <line x1="12" y1="2" x2="12" y2="15" /> 476 </svg> 477 </button> 478 </div> 479 </article> 480 481 <!-- People Results (shown when People tab is active — rendered inline for preview) --> 482 <div class="typeahead-section" style="display: none"> 483 <div class="typeahead-label">People</div> 484 485 <div class="actor-result"> 486 <div class="avatar">AT</div> 487 <div class="actor-result-info"> 488 <div class="actor-result-name">AT Protocol</div> 489 <div class="actor-result-handle">@atproto.com</div> 490 <div class="actor-result-bio">The AT Protocol – social networking technology created by Bluesky</div> 491 </div> 492 <button class="follow-btn">Follow</button> 493 </div> 494 495 <div class="actor-result"> 496 <div class="avatar">BS</div> 497 <div class="actor-result-info"> 498 <div class="actor-result-name">Bluesky</div> 499 <div class="actor-result-handle">@bsky.app</div> 500 <div class="actor-result-bio">Building a social internet. Join us at bsky.app</div> 501 </div> 502 <button class="follow-btn">Follow</button> 503 </div> 504 </div> 505 506 <!-- Search History (shown when search input is empty) --> 507 <div style="display: none"> 508 <div class="search-history-header"> 509 <span class="search-history-title">Recent Searches</span> 510 <button class="search-history-clear">Clear All</button> 511 </div> 512 513 <div class="history-item"> 514 <div class="history-item-left"> 515 <svg 516 class="history-icon" 517 viewBox="0 0 24 24" 518 fill="none" 519 stroke="currentColor" 520 stroke-width="2" 521 stroke-linecap="round" 522 stroke-linejoin="round"> 523 <polyline points="12 8 12 12 14 14" /> 524 <circle cx="12" cy="12" r="10" /> 525 </svg> 526 <div> 527 <div class="history-query">flutter bloc</div> 528 <div class="history-meta">Posts · 2 hours ago</div> 529 </div> 530 </div> 531 <button class="history-delete"> 532 <svg 533 viewBox="0 0 24 24" 534 fill="none" 535 stroke="currentColor" 536 stroke-width="2" 537 stroke-linecap="round" 538 stroke-linejoin="round"> 539 <line x1="18" y1="6" x2="6" y2="18" /> 540 <line x1="6" y1="6" x2="18" y2="18" /> 541 </svg> 542 </button> 543 </div> 544 545 <div class="history-item"> 546 <div class="history-item-left"> 547 <svg 548 class="history-icon" 549 viewBox="0 0 24 24" 550 fill="none" 551 stroke="currentColor" 552 stroke-width="2" 553 stroke-linecap="round" 554 stroke-linejoin="round"> 555 <polyline points="12 8 12 12 14 14" /> 556 <circle cx="12" cy="12" r="10" /> 557 </svg> 558 <div> 559 <div class="history-query">@pfrazee.com</div> 560 <div class="history-meta">People · Yesterday</div> 561 </div> 562 </div> 563 <button class="history-delete"> 564 <svg 565 viewBox="0 0 24 24" 566 fill="none" 567 stroke="currentColor" 568 stroke-width="2" 569 stroke-linecap="round" 570 stroke-linejoin="round"> 571 <line x1="18" y1="6" x2="6" y2="18" /> 572 <line x1="6" y1="6" x2="18" y2="18" /> 573 </svg> 574 </button> 575 </div> 576 577 <div class="history-item"> 578 <div class="history-item-left"> 579 <svg 580 class="history-icon" 581 viewBox="0 0 24 24" 582 fill="none" 583 stroke="currentColor" 584 stroke-width="2" 585 stroke-linecap="round" 586 stroke-linejoin="round"> 587 <polyline points="12 8 12 12 14 14" /> 588 <circle cx="12" cy="12" r="10" /> 589 </svg> 590 <div> 591 <div class="history-query">#decentralized</div> 592 <div class="history-meta">Posts · 3 days ago</div> 593 </div> 594 </div> 595 <button class="history-delete"> 596 <svg 597 viewBox="0 0 24 24" 598 fill="none" 599 stroke="currentColor" 600 stroke-width="2" 601 stroke-linecap="round" 602 stroke-linejoin="round"> 603 <line x1="18" y1="6" x2="6" y2="18" /> 604 <line x1="6" y1="6" x2="18" y2="18" /> 605 </svg> 606 </button> 607 </div> 608 </div> 609 </div> 610 611 <!-- Bottom Navigation --> 612 <nav class="nav-bar"> 613 <a href="home.html" class="nav-item"> 614 <svg 615 viewBox="0 0 24 24" 616 fill="none" 617 stroke="currentColor" 618 stroke-width="2" 619 stroke-linecap="round" 620 stroke-linejoin="round"> 621 <path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" /> 622 <polyline points="9 22 9 12 15 12 15 22" /> 623 </svg> 624 <span>Home</span> 625 </a> 626 627 <a href="search.html" class="nav-item active"> 628 <svg 629 viewBox="0 0 24 24" 630 fill="none" 631 stroke="currentColor" 632 stroke-width="2" 633 stroke-linecap="round" 634 stroke-linejoin="round"> 635 <circle cx="11" cy="11" r="8" /> 636 <line x1="21" y1="21" x2="16.65" y2="16.65" /> 637 </svg> 638 <span>Search</span> 639 </a> 640 641 <a href="profile.html" class="nav-item"> 642 <svg 643 viewBox="0 0 24 24" 644 fill="none" 645 stroke="currentColor" 646 stroke-width="2" 647 stroke-linecap="round" 648 stroke-linejoin="round"> 649 <path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2" /> 650 <circle cx="12" cy="7" r="4" /> 651 </svg> 652 <span>Profile</span> 653 </a> 654 655 <a href="settings.html" class="nav-item"> 656 <svg 657 viewBox="0 0 24 24" 658 fill="none" 659 stroke="currentColor" 660 stroke-width="2" 661 stroke-linecap="round" 662 stroke-linejoin="round"> 663 <circle cx="12" cy="12" r="3" /> 664 <path 665 d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z" /> 666 </svg> 667 <span>Settings</span> 668 </a> 669 </nav> 670 </div> 671 672 <script> 673 if (localStorage.getItem("theme") === "dark") { 674 document.documentElement.setAttribute("data-theme", "dark"); 675 } 676 677 document.querySelectorAll(".search-tab").forEach((tab) => { 678 tab.addEventListener("click", () => { 679 document.querySelectorAll(".search-tab").forEach((t) => t.classList.remove("active")); 680 tab.classList.add("active"); 681 682 const isPeople = tab.textContent === "People"; 683 document.querySelectorAll(".post-card").forEach((el) => (el.style.display = isPeople ? "none" : "block")); 684 document.querySelector(".search-sort").style.display = isPeople ? "none" : "flex"; 685 document.querySelector(".typeahead-section").style.display = isPeople ? "block" : "none"; 686 }); 687 }); 688 </script> 689 </body> 690</html>