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 704 lines 20 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>Messages - Lazurite</title> 7 <link rel="preconnect" href="https://fonts.googleapis.com" /> 8 <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> 9 <link href="https://fonts.googleapis.com/css2?family=Lora:wght@400;500;600;700&display=swap" rel="stylesheet" /> 10 <link 11 href="https://fonts.googleapis.com/css2?family=DM+Sans:ital,opsz,wght@0,9..40,100..1000;1,9..40,100..1000&display=swap" 12 rel="stylesheet" /> 13 <link rel="stylesheet" href="styles.css" /> 14 <style> 15 .messages-container { 16 padding-bottom: 88px; 17 } 18 19 /* Tabs */ 20 .msg-tabs { 21 display: flex; 22 border-bottom: 1px solid var(--border); 23 background-color: var(--bg); 24 } 25 26 .msg-tab { 27 flex: 1; 28 padding: 14px; 29 text-align: center; 30 font-weight: 600; 31 font-size: 15px; 32 color: var(--text-secondary); 33 cursor: pointer; 34 border-bottom: 2px solid transparent; 35 transition: all 0.2s ease; 36 background: none; 37 border-top: none; 38 border-left: none; 39 border-right: none; 40 } 41 42 .msg-tab:hover { 43 background-color: var(--surface); 44 color: var(--text-primary); 45 } 46 47 .msg-tab.active { 48 color: var(--text-primary); 49 border-bottom-color: var(--accent-primary); 50 } 51 52 .msg-tab-badge { 53 display: inline-flex; 54 align-items: center; 55 justify-content: center; 56 min-width: 18px; 57 height: 18px; 58 padding: 0 5px; 59 border-radius: 9px; 60 background-color: var(--accent-error); 61 color: white; 62 font-size: 10px; 63 font-weight: 700; 64 margin-left: 6px; 65 } 66 67 /* Conversation Item */ 68 .convo-item { 69 display: flex; 70 align-items: center; 71 gap: 12px; 72 padding: 14px 16px; 73 border-bottom: 1px solid var(--border); 74 cursor: pointer; 75 transition: background-color 0.2s ease; 76 position: relative; 77 } 78 79 .convo-item:hover { 80 background-color: var(--surface); 81 } 82 83 .convo-item.unread { 84 background-color: var(--surface); 85 } 86 87 .convo-avatar { 88 position: relative; 89 flex-shrink: 0; 90 } 91 92 .convo-avatar .avatar { 93 width: 48px; 94 height: 48px; 95 } 96 97 .convo-unread-dot { 98 position: absolute; 99 top: 0; 100 right: 0; 101 width: 12px; 102 height: 12px; 103 border-radius: 50%; 104 background-color: var(--accent-primary); 105 border: 2px solid var(--bg); 106 } 107 108 .convo-info { 109 flex: 1; 110 min-width: 0; 111 } 112 113 .convo-header { 114 display: flex; 115 align-items: baseline; 116 justify-content: space-between; 117 gap: 8px; 118 margin-bottom: 2px; 119 } 120 121 .convo-name { 122 font-weight: 600; 123 font-size: 15px; 124 color: var(--text-primary); 125 white-space: nowrap; 126 overflow: hidden; 127 text-overflow: ellipsis; 128 } 129 130 .convo-time { 131 font-size: 12px; 132 color: var(--text-muted); 133 flex-shrink: 0; 134 } 135 136 .convo-last-message { 137 font-size: 14px; 138 color: var(--text-secondary); 139 white-space: nowrap; 140 overflow: hidden; 141 text-overflow: ellipsis; 142 } 143 144 .convo-last-message.unread { 145 color: var(--text-primary); 146 font-weight: 500; 147 } 148 149 .convo-muted-icon { 150 width: 14px; 151 height: 14px; 152 color: var(--text-muted); 153 flex-shrink: 0; 154 } 155 156 /* New Message FAB */ 157 .fab-new-message { 158 position: fixed; 159 bottom: 100px; 160 right: calc(50% - 207px + 16px); 161 width: 56px; 162 height: 56px; 163 border-radius: 50%; 164 background-color: var(--accent-primary); 165 color: white; 166 border: none; 167 cursor: pointer; 168 display: flex; 169 align-items: center; 170 justify-content: center; 171 box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); 172 transition: all 0.2s ease; 173 z-index: 50; 174 } 175 176 .fab-new-message:hover { 177 transform: scale(1.05); 178 box-shadow: 0 6px 16px rgba(0, 0, 0, 0.2); 179 } 180 181 .fab-new-message svg { 182 width: 24px; 183 height: 24px; 184 } 185 186 /* Message Thread View */ 187 .thread-header { 188 display: flex; 189 align-items: center; 190 gap: 12px; 191 padding: 12px 16px; 192 border-bottom: 1px solid var(--border); 193 background-color: var(--bg); 194 position: sticky; 195 top: 0; 196 z-index: 50; 197 } 198 199 .thread-back { 200 background: none; 201 border: none; 202 color: var(--text-secondary); 203 cursor: pointer; 204 display: flex; 205 align-items: center; 206 } 207 208 .thread-back svg { 209 width: 24px; 210 height: 24px; 211 } 212 213 .thread-info { 214 flex: 1; 215 } 216 217 .thread-name { 218 font-weight: 600; 219 font-size: 16px; 220 color: var(--text-primary); 221 } 222 223 .thread-handle { 224 font-size: 13px; 225 color: var(--text-secondary); 226 } 227 228 .thread-overflow { 229 background: none; 230 border: none; 231 color: var(--text-secondary); 232 cursor: pointer; 233 padding: 8px; 234 } 235 236 .thread-overflow svg { 237 width: 20px; 238 height: 20px; 239 } 240 241 /* Chat Bubbles */ 242 .chat-area { 243 padding: 16px; 244 display: flex; 245 flex-direction: column; 246 gap: 8px; 247 padding-bottom: 80px; 248 } 249 250 .chat-bubble-row { 251 display: flex; 252 gap: 8px; 253 max-width: 80%; 254 } 255 256 .chat-bubble-row.sent { 257 align-self: flex-end; 258 flex-direction: row-reverse; 259 } 260 261 .chat-bubble-row.received { 262 align-self: flex-start; 263 } 264 265 .chat-bubble { 266 padding: 10px 14px; 267 border-radius: 18px; 268 font-size: 15px; 269 line-height: 1.4; 270 position: relative; 271 } 272 273 .chat-bubble.sent { 274 background-color: var(--accent-primary); 275 color: white; 276 border-bottom-right-radius: 4px; 277 } 278 279 .chat-bubble.received { 280 background-color: var(--surface); 281 color: var(--text-primary); 282 border: 1px solid var(--border); 283 border-bottom-left-radius: 4px; 284 } 285 286 .chat-time { 287 font-size: 11px; 288 color: var(--text-muted); 289 margin-top: 4px; 290 padding: 0 4px; 291 } 292 293 .chat-time.sent { 294 text-align: right; 295 } 296 297 .chat-date-divider { 298 text-align: center; 299 padding: 12px 0; 300 font-size: 12px; 301 color: var(--text-muted); 302 font-weight: 500; 303 } 304 305 /* Message Input */ 306 .msg-input-bar { 307 position: fixed; 308 bottom: 0; 309 left: 50%; 310 transform: translateX(-50%); 311 width: 100%; 312 max-width: 414px; 313 display: flex; 314 align-items: center; 315 gap: 8px; 316 padding: 12px 16px; 317 background-color: var(--bg); 318 border-top: 1px solid var(--border); 319 z-index: 100; 320 } 321 322 .msg-input { 323 flex: 1; 324 padding: 10px 16px; 325 border: 1px solid var(--border); 326 border-radius: 9999px; 327 background-color: var(--surface); 328 color: var(--text-primary); 329 font-size: 15px; 330 font-family: var(--font-body); 331 outline: none; 332 transition: border-color 0.2s ease; 333 } 334 335 .msg-input:focus { 336 border-color: var(--accent-primary); 337 } 338 339 .msg-input::placeholder { 340 color: var(--text-muted); 341 } 342 343 .msg-send-btn { 344 width: 40px; 345 height: 40px; 346 border-radius: 50%; 347 border: none; 348 background-color: var(--accent-primary); 349 color: white; 350 cursor: pointer; 351 display: flex; 352 align-items: center; 353 justify-content: center; 354 transition: background-color 0.2s ease; 355 flex-shrink: 0; 356 } 357 358 .msg-send-btn:hover { 359 background-color: var(--accent-primary-hover); 360 } 361 362 .msg-send-btn svg { 363 width: 18px; 364 height: 18px; 365 } 366 367 /* Nav badge */ 368 .nav-item { 369 position: relative; 370 } 371 372 .nav-item-badge { 373 position: absolute; 374 top: 2px; 375 right: 8px; 376 min-width: 18px; 377 height: 18px; 378 padding: 0 5px; 379 border-radius: 9px; 380 background-color: var(--accent-error); 381 color: white; 382 font-size: 10px; 383 font-weight: 700; 384 display: flex; 385 align-items: center; 386 justify-content: center; 387 } 388 389 /* View toggle */ 390 .view-toggle { 391 display: none; 392 } 393 .view-toggle.active { 394 display: block; 395 } 396 </style> 397 </head> 398 <body> 399 <div class="mobile-container"> 400 <!-- ==================== --> 401 <!-- CONVERSATION LIST VIEW --> 402 <!-- ==================== --> 403 <div class="view-toggle active" id="list-view"> 404 <!-- Header --> 405 <header class="header"> 406 <h1 class="header-title">Messages</h1> 407 <button class="header-action" onclick="toggleView()">Open Thread</button> 408 </header> 409 410 <!-- Tabs --> 411 <div class="msg-tabs"> 412 <button class="msg-tab active">Primary</button> 413 <button class="msg-tab">Requests <span class="msg-tab-badge">2</span></button> 414 </div> 415 416 <div class="messages-container"> 417 <!-- Unread conversation --> 418 <div class="convo-item unread"> 419 <div class="convo-avatar"> 420 <div class="avatar">AS</div> 421 <div class="convo-unread-dot"></div> 422 </div> 423 <div class="convo-info"> 424 <div class="convo-header"> 425 <span class="convo-name">Alice Smith</span> 426 <span class="convo-time">12m</span> 427 </div> 428 <div class="convo-last-message unread"> 429 Hey! Did you see the new federation update? It's really exciting. 430 </div> 431 </div> 432 </div> 433 434 <!-- Unread conversation --> 435 <div class="convo-item unread"> 436 <div class="convo-avatar"> 437 <div class="avatar">BJ</div> 438 <div class="convo-unread-dot"></div> 439 </div> 440 <div class="convo-info"> 441 <div class="convo-header"> 442 <span class="convo-name">Bob Johnson</span> 443 <span class="convo-time">2h</span> 444 </div> 445 <div class="convo-last-message unread">Would love to collaborate on the AT Protocol project</div> 446 </div> 447 </div> 448 449 <!-- Read conversation --> 450 <div class="convo-item"> 451 <div class="convo-avatar"> 452 <div class="avatar">CW</div> 453 </div> 454 <div class="convo-info"> 455 <div class="convo-header"> 456 <span class="convo-name">Carol White</span> 457 <span class="convo-time">1d</span> 458 </div> 459 <div class="convo-last-message">Thanks for sharing that article! I'll check it out this weekend.</div> 460 </div> 461 </div> 462 463 <!-- Muted conversation --> 464 <div class="convo-item"> 465 <div class="convo-avatar"> 466 <div class="avatar">DM</div> 467 </div> 468 <div class="convo-info"> 469 <div class="convo-header"> 470 <span class="convo-name">David Miller</span> 471 <span class="convo-time">3d</span> 472 </div> 473 <div class="convo-last-message">Sounds good, let's catch up next week then!</div> 474 </div> 475 <svg 476 class="convo-muted-icon" 477 viewBox="0 0 24 24" 478 fill="none" 479 stroke="currentColor" 480 stroke-width="2" 481 stroke-linecap="round" 482 stroke-linejoin="round"> 483 <path d="M11 5L6 9H2v6h4l5 4V5z" /> 484 <line x1="23" y1="9" x2="17" y2="15" /> 485 <line x1="17" y1="9" x2="23" y2="15" /> 486 </svg> 487 </div> 488 489 <!-- Old conversation --> 490 <div class="convo-item"> 491 <div class="convo-avatar"> 492 <div class="avatar">EL</div> 493 </div> 494 <div class="convo-info"> 495 <div class="convo-header"> 496 <span class="convo-name">Eva Lee</span> 497 <span class="convo-time">1w</span> 498 </div> 499 <div class="convo-last-message">Great chatting with you at the meetup!</div> 500 </div> 501 </div> 502 </div> 503 504 <!-- New Message FAB --> 505 <button class="fab-new-message" title="New message"> 506 <svg 507 viewBox="0 0 24 24" 508 fill="none" 509 stroke="currentColor" 510 stroke-width="2" 511 stroke-linecap="round" 512 stroke-linejoin="round"> 513 <line x1="22" y1="2" x2="11" y2="13" /> 514 <polygon points="22 2 15 22 11 13 2 9 22 2" /> 515 </svg> 516 </button> 517 518 <!-- Bottom Navigation --> 519 <nav class="nav-bar"> 520 <a href="home.html" class="nav-item"> 521 <svg 522 viewBox="0 0 24 24" 523 fill="none" 524 stroke="currentColor" 525 stroke-width="2" 526 stroke-linecap="round" 527 stroke-linejoin="round"> 528 <path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" /> 529 <polyline points="9 22 9 12 15 12 15 22" /> 530 </svg> 531 <span>Home</span> 532 </a> 533 534 <a href="search.html" class="nav-item"> 535 <svg 536 viewBox="0 0 24 24" 537 fill="none" 538 stroke="currentColor" 539 stroke-width="2" 540 stroke-linecap="round" 541 stroke-linejoin="round"> 542 <circle cx="11" cy="11" r="8" /> 543 <line x1="21" y1="21" x2="16.65" y2="16.65" /> 544 </svg> 545 <span>Search</span> 546 </a> 547 548 <a href="notifications.html" class="nav-item"> 549 <svg 550 viewBox="0 0 24 24" 551 fill="none" 552 stroke="currentColor" 553 stroke-width="2" 554 stroke-linecap="round" 555 stroke-linejoin="round"> 556 <path d="M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9" /> 557 <path d="M13.73 21a2 2 0 0 1-3.46 0" /> 558 </svg> 559 <span>Alerts</span> 560 </a> 561 562 <a href="messages.html" class="nav-item active"> 563 <svg 564 viewBox="0 0 24 24" 565 fill="none" 566 stroke="currentColor" 567 stroke-width="2" 568 stroke-linecap="round" 569 stroke-linejoin="round"> 570 <path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" /> 571 </svg> 572 <span class="nav-item-badge">2</span> 573 <span>Chat</span> 574 </a> 575 576 <a href="profile.html" class="nav-item"> 577 <svg 578 viewBox="0 0 24 24" 579 fill="none" 580 stroke="currentColor" 581 stroke-width="2" 582 stroke-linecap="round" 583 stroke-linejoin="round"> 584 <path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2" /> 585 <circle cx="12" cy="7" r="4" /> 586 </svg> 587 <span>Profile</span> 588 </a> 589 </nav> 590 </div> 591 592 <!-- ==================== --> 593 <!-- MESSAGE THREAD VIEW --> 594 <!-- ==================== --> 595 <div class="view-toggle" id="thread-view"> 596 <!-- Thread Header --> 597 <div class="thread-header"> 598 <button class="thread-back" onclick="toggleView()"> 599 <svg 600 viewBox="0 0 24 24" 601 fill="none" 602 stroke="currentColor" 603 stroke-width="2" 604 stroke-linecap="round" 605 stroke-linejoin="round"> 606 <polyline points="15 18 9 12 15 6" /> 607 </svg> 608 </button> 609 <div class="thread-info"> 610 <div class="thread-name">Alice Smith</div> 611 <div class="thread-handle">@alice.bsky.social</div> 612 </div> 613 <button class="thread-overflow"> 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 <circle cx="12" cy="12" r="1" /> 622 <circle cx="19" cy="12" r="1" /> 623 <circle cx="5" cy="12" r="1" /> 624 </svg> 625 </button> 626 </div> 627 628 <!-- Chat Area --> 629 <div class="chat-area"> 630 <div class="chat-date-divider">Today</div> 631 632 <div class="chat-bubble-row received"> 633 <div class="chat-bubble received">Hey! Did you see the new federation update? It's really exciting.</div> 634 </div> 635 <div class="chat-time">10:23 AM</div> 636 637 <div class="chat-bubble-row sent"> 638 <div class="chat-bubble sent"> 639 Yes! I was just reading through the announcement. The self-hosting guide looks much improved. 640 </div> 641 </div> 642 <div class="chat-time sent">10:25 AM</div> 643 644 <div class="chat-bubble-row received"> 645 <div class="chat-bubble received"> 646 Right? I'm thinking of setting up my own PDS this weekend. Want to try it together? 647 </div> 648 </div> 649 <div class="chat-time">10:27 AM</div> 650 651 <div class="chat-bubble-row sent"> 652 <div class="chat-bubble sent"> 653 That sounds great! I've been meaning to do that for a while. Let me know when you're free. 654 </div> 655 </div> 656 <div class="chat-time sent">10:30 AM</div> 657 658 <div class="chat-bubble-row received"> 659 <div class="chat-bubble received"> 660 Saturday afternoon works for me. We could do a video call and set them up at the same time. 661 </div> 662 </div> 663 <div class="chat-time">10:32 AM</div> 664 </div> 665 666 <!-- Message Input --> 667 <div class="msg-input-bar"> 668 <input class="msg-input" type="text" placeholder="Type a message..." /> 669 <button class="msg-send-btn"> 670 <svg 671 viewBox="0 0 24 24" 672 fill="none" 673 stroke="currentColor" 674 stroke-width="2" 675 stroke-linecap="round" 676 stroke-linejoin="round"> 677 <line x1="22" y1="2" x2="11" y2="13" /> 678 <polygon points="22 2 15 22 11 13 2 9 22 2" /> 679 </svg> 680 </button> 681 </div> 682 </div> 683 </div> 684 685 <script> 686 if (localStorage.getItem("theme")) { 687 const t = localStorage.getItem("theme"); 688 if (t !== "light") document.documentElement.setAttribute("data-theme", t); 689 } 690 691 function toggleView() { 692 document.getElementById("list-view").classList.toggle("active"); 693 document.getElementById("thread-view").classList.toggle("active"); 694 } 695 696 document.querySelectorAll(".msg-tab").forEach((tab) => { 697 tab.addEventListener("click", () => { 698 document.querySelectorAll(".msg-tab").forEach((t) => t.classList.remove("active")); 699 tab.classList.add("active"); 700 }); 701 }); 702 </script> 703 </body> 704</html>