mobile bluesky app made with flutter
lazurite.stormlightlabs.org/
mobile
bluesky
flutter
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>Home - 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 .feed-container {
16 padding-bottom: 88px;
17 }
18
19 .compose-box {
20 padding: 16px;
21 border-bottom: 1px solid var(--border);
22 background-color: var(--bg);
23 }
24
25 .compose-inner {
26 display: flex;
27 gap: 12px;
28 }
29
30 .compose-input-wrapper {
31 flex: 1;
32 }
33
34 .compose-input {
35 width: 100%;
36 border: none;
37 background: transparent;
38 color: var(--text-primary);
39 font-size: 16px;
40 resize: none;
41 outline: none;
42 font-family: inherit;
43 min-height: 24px;
44 }
45
46 .compose-input::placeholder {
47 color: var(--text-muted);
48 }
49
50 .compose-actions {
51 display: flex;
52 justify-content: space-between;
53 align-items: center;
54 margin-top: 12px;
55 padding-left: 60px;
56 }
57
58 .compose-tools {
59 display: flex;
60 gap: 8px;
61 }
62
63 .compose-tool {
64 width: 36px;
65 height: 36px;
66 border-radius: 50%;
67 border: none;
68 background: transparent;
69 color: var(--accent-primary);
70 cursor: pointer;
71 display: flex;
72 align-items: center;
73 justify-content: center;
74 transition: background-color 0.2s ease;
75 }
76
77 .compose-tool:hover {
78 background-color: rgba(0, 102, 255, 0.1);
79 }
80
81 .compose-tool svg {
82 width: 20px;
83 height: 20px;
84 }
85
86 .compose-submit {
87 padding: 8px 20px;
88 border-radius: 9999px;
89 border: none;
90 background-color: var(--accent-primary);
91 color: white;
92 font-weight: 600;
93 font-size: 14px;
94 cursor: pointer;
95 transition: background-color 0.2s ease;
96 }
97
98 .compose-submit:hover {
99 background-color: var(--accent-primary-hover);
100 }
101
102 .feed-tabs {
103 display: flex;
104 border-bottom: 1px solid var(--border);
105 background-color: var(--bg);
106 }
107
108 .feed-tab {
109 flex: 1;
110 padding: 16px;
111 text-align: center;
112 font-weight: 600;
113 font-size: 15px;
114 color: var(--text-secondary);
115 cursor: pointer;
116 border-bottom: 2px solid transparent;
117 transition: all 0.2s ease;
118 background: none;
119 border-top: none;
120 border-left: none;
121 border-right: none;
122 }
123
124 .feed-tab:hover {
125 background-color: var(--surface);
126 color: var(--text-primary);
127 }
128
129 .feed-tab.active {
130 color: var(--text-primary);
131 border-bottom-color: var(--accent-primary);
132 }
133
134 .post-facet-mention {
135 color: var(--accent-primary);
136 text-decoration: none;
137 font-weight: 500;
138 }
139
140 .post-facet-mention:hover {
141 text-decoration: underline;
142 }
143
144 .post-facet-hashtag {
145 color: var(--accent-secondary);
146 text-decoration: none;
147 font-weight: 500;
148 }
149
150 .post-facet-hashtag:hover {
151 text-decoration: underline;
152 }
153
154 .post-facet-link {
155 color: var(--accent-primary);
156 text-decoration: underline;
157 }
158
159 .post-embed {
160 margin-top: 12px;
161 border: 1px solid var(--border);
162 border-radius: 12px;
163 overflow: hidden;
164 }
165
166 .post-embed-image {
167 width: 100%;
168 height: 200px;
169 background: linear-gradient(135deg, var(--surface) 0%, var(--surface-variant) 100%);
170 display: flex;
171 align-items: center;
172 justify-content: center;
173 color: var(--text-muted);
174 }
175
176 .post-embed-content {
177 padding: 12px;
178 }
179
180 .post-embed-title {
181 font-weight: 600;
182 color: var(--text-primary);
183 font-size: 14px;
184 margin-bottom: 4px;
185 }
186
187 .post-embed-url {
188 color: var(--text-muted);
189 font-size: 12px;
190 }
191 </style>
192 </head>
193 <body>
194 <div class="mobile-container">
195 <!-- Header -->
196 <header class="header">
197 <h1 class="header-title">Home</h1>
198 <button class="header-action">Settings</button>
199 </header>
200
201 <div class="feed-container">
202 <!-- Compose Box -->
203 <div class="compose-box">
204 <div class="compose-inner">
205 <div class="avatar avatar-sm">JD</div>
206 <div class="compose-input-wrapper">
207 <textarea class="compose-input" placeholder="What's on your mind?" rows="2"></textarea>
208 </div>
209 </div>
210 <div class="compose-actions">
211 <div class="compose-tools">
212 <button class="compose-tool" title="Add image">
213 <svg
214 viewBox="0 0 24 24"
215 fill="none"
216 stroke="currentColor"
217 stroke-width="2"
218 stroke-linecap="round"
219 stroke-linejoin="round">
220 <rect x="3" y="3" width="18" height="18" rx="2" ry="2" />
221 <circle cx="8.5" cy="8.5" r="1.5" />
222 <polyline points="21 15 16 10 5 21" />
223 </svg>
224 </button>
225 <button class="compose-tool" title="Add GIF">
226 <svg
227 viewBox="0 0 24 24"
228 fill="none"
229 stroke="currentColor"
230 stroke-width="2"
231 stroke-linecap="round"
232 stroke-linejoin="round">
233 <text x="4" y="16" font-family="inherit" font-size="12" font-weight="bold" fill="currentColor">
234 GIF
235 </text>
236 </svg>
237 </button>
238 <button class="compose-tool" title="Add poll">
239 <svg
240 viewBox="0 0 24 24"
241 fill="none"
242 stroke="currentColor"
243 stroke-width="2"
244 stroke-linecap="round"
245 stroke-linejoin="round">
246 <line x1="18" y1="20" x2="18" y2="10" />
247 <line x1="12" y1="20" x2="12" y2="4" />
248 <line x1="6" y1="20" x2="6" y2="14" />
249 </svg>
250 </button>
251 <button class="compose-tool" title="Emoji">
252 <svg
253 viewBox="0 0 24 24"
254 fill="none"
255 stroke="currentColor"
256 stroke-width="2"
257 stroke-linecap="round"
258 stroke-linejoin="round">
259 <circle cx="12" cy="12" r="10" />
260 <path d="M8 14s1.5 2 4 2 4-2 4-2" />
261 <line x1="9" y1="9" x2="9.01" y2="9" />
262 <line x1="15" y1="9" x2="15.01" y2="9" />
263 </svg>
264 </button>
265 </div>
266 <button class="compose-submit">Post</button>
267 </div>
268 </div>
269
270 <!-- Feed Tabs -->
271 <div class="feed-tabs">
272 <button class="feed-tab active">Following</button>
273 <button class="feed-tab">Discover</button>
274 </div>
275
276 <!-- Post 1 -->
277 <article class="post-card">
278 <div class="post-header">
279 <div class="avatar">AS</div>
280 <div class="post-author">
281 <div class="post-author-name">Alice Smith</div>
282 <div class="post-author-handle">@alice.bsky.social · <span class="post-timestamp">2h</span></div>
283 </div>
284 </div>
285
286 <div class="post-content">
287 Just launched my new project! 🚀 Check out the demo at <a href="#" class="post-facet-link">example.com</a>.
288 Special thanks to <a href="#" class="post-facet-mention">@bob.bsky.social</a> for the help!
289 <a href="#" class="post-facet-hashtag">#buildinpublic</a> <a href="#" class="post-facet-hashtag">#dev</a>
290 </div>
291
292 <div class="post-embed">
293 <div class="post-embed-image">[Project Screenshot]</div>
294 <div class="post-embed-content">
295 <div class="post-embed-title">My Awesome Project</div>
296 <div class="post-embed-url">example.com</div>
297 </div>
298 </div>
299
300 <div class="post-actions">
301 <button class="post-action">
302 <svg
303 viewBox="0 0 24 24"
304 fill="none"
305 stroke="currentColor"
306 stroke-width="2"
307 stroke-linecap="round"
308 stroke-linejoin="round">
309 <path
310 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" />
311 </svg>
312 12
313 </button>
314 <button class="post-action">
315 <svg
316 viewBox="0 0 24 24"
317 fill="none"
318 stroke="currentColor"
319 stroke-width="2"
320 stroke-linecap="round"
321 stroke-linejoin="round">
322 <polyline points="17 1 21 5 17 9" />
323 <path d="M3 11V9a4 4 0 0 1 4-4h14" />
324 <polyline points="7 23 3 19 7 15" />
325 <path d="M21 13v2a4 4 0 0 1-4 4H3" />
326 </svg>
327 5
328 </button>
329 <button class="post-action">
330 <svg
331 viewBox="0 0 24 24"
332 fill="none"
333 stroke="currentColor"
334 stroke-width="2"
335 stroke-linecap="round"
336 stroke-linejoin="round">
337 <path
338 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" />
339 </svg>
340 48
341 </button>
342 <button class="post-action">
343 <svg
344 viewBox="0 0 24 24"
345 fill="none"
346 stroke="currentColor"
347 stroke-width="2"
348 stroke-linecap="round"
349 stroke-linejoin="round">
350 <path d="M4 12v8a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-8" />
351 <polyline points="16 6 12 2 8 6" />
352 <line x1="12" y1="2" x2="12" y2="15" />
353 </svg>
354 </button>
355 </div>
356 </article>
357
358 <!-- Post 2 -->
359 <article class="post-card">
360 <div class="post-header">
361 <div class="avatar">BJ</div>
362 <div class="post-author">
363 <div class="post-author-name">Bob Johnson</div>
364 <div class="post-author-handle">@bob.bsky.social · <span class="post-timestamp">4h</span></div>
365 </div>
366 </div>
367
368 <div class="post-content">
369 Working on some exciting features for the next release! Here's a sneak peek of what's coming: improved
370 search, better notifications, and dark mode support. <a href="#" class="post-facet-hashtag">#bluesky</a>
371 <a href="#" class="post-facet-hashtag">#atproto</a>
372 </div>
373
374 <div class="post-actions">
375 <button class="post-action">
376 <svg
377 viewBox="0 0 24 24"
378 fill="none"
379 stroke="currentColor"
380 stroke-width="2"
381 stroke-linecap="round"
382 stroke-linejoin="round">
383 <path
384 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" />
385 </svg>
386 8
387 </button>
388 <button class="post-action">
389 <svg
390 viewBox="0 0 24 24"
391 fill="none"
392 stroke="currentColor"
393 stroke-width="2"
394 stroke-linecap="round"
395 stroke-linejoin="round">
396 <polyline points="17 1 21 5 17 9" />
397 <path d="M3 11V9a4 4 0 0 1 4-4h14" />
398 <polyline points="7 23 3 19 7 15" />
399 <path d="M21 13v2a4 4 0 0 1-4 4H3" />
400 </svg>
401 24
402 </button>
403 <button class="post-action">
404 <svg
405 viewBox="0 0 24 24"
406 fill="none"
407 stroke="currentColor"
408 stroke-width="2"
409 stroke-linecap="round"
410 stroke-linejoin="round">
411 <path
412 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" />
413 </svg>
414 156
415 </button>
416 <button class="post-action">
417 <svg
418 viewBox="0 0 24 24"
419 fill="none"
420 stroke="currentColor"
421 stroke-width="2"
422 stroke-linecap="round"
423 stroke-linejoin="round">
424 <path d="M4 12v8a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-8" />
425 <polyline points="16 6 12 2 8 6" />
426 <line x1="12" y1="2" x2="12" y2="15" />
427 </svg>
428 </button>
429 </div>
430 </article>
431
432 <!-- Post 3 - Rich Facets -->
433 <article class="post-card">
434 <div class="post-header">
435 <div class="avatar">CW</div>
436 <div class="post-author">
437 <div class="post-author-name">Carol White</div>
438 <div class="post-author-handle">@carol.dev · <span class="post-timestamp">6h</span></div>
439 </div>
440 </div>
441
442 <div class="post-content">
443 The <a href="#" class="post-facet-mention">@atproto</a> team has been doing amazing work! Read their latest
444 blog post about federation: <a href="#" class="post-facet-link">atproto.com/blog/federation</a>
445
446 <br /><br />
447
448 Key highlights: • Self-hosting guides • PDS (Personal Data Server) setup • Relay infrastructure
449
450 <br /><br />
451
452 <a href="#" class="post-facet-hashtag">#atprotocol</a>
453 <a href="#" class="post-facet-hashtag">#decentralized</a>
454 <a href="#" class="post-facet-hashtag">#socialweb</a>
455 </div>
456
457 <div class="post-actions">
458 <button class="post-action">
459 <svg
460 viewBox="0 0 24 24"
461 fill="none"
462 stroke="currentColor"
463 stroke-width="2"
464 stroke-linecap="round"
465 stroke-linejoin="round">
466 <path
467 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" />
468 </svg>
469 34
470 </button>
471 <button class="post-action">
472 <svg
473 viewBox="0 0 24 24"
474 fill="none"
475 stroke="currentColor"
476 stroke-width="2"
477 stroke-linecap="round"
478 stroke-linejoin="round">
479 <polyline points="17 1 21 5 17 9" />
480 <path d="M3 11V9a4 4 0 0 1 4-4h14" />
481 <polyline points="7 23 3 19 7 15" />
482 <path d="M21 13v2a4 4 0 0 1-4 4H3" />
483 </svg>
484 12
485 </button>
486 <button class="post-action">
487 <svg
488 viewBox="0 0 24 24"
489 fill="none"
490 stroke="currentColor"
491 stroke-width="2"
492 stroke-linecap="round"
493 stroke-linejoin="round">
494 <path
495 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" />
496 </svg>
497 289
498 </button>
499 <button class="post-action">
500 <svg
501 viewBox="0 0 24 24"
502 fill="none"
503 stroke="currentColor"
504 stroke-width="2"
505 stroke-linecap="round"
506 stroke-linejoin="round">
507 <path d="M4 12v8a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-8" />
508 <polyline points="16 6 12 2 8 6" />
509 <line x1="12" y1="2" x2="12" y2="15" />
510 </svg>
511 </button>
512 </div>
513 </article>
514
515 <!-- Post 4 -->
516 <article class="post-card">
517 <div class="post-header">
518 <div class="avatar">DM</div>
519 <div class="post-author">
520 <div class="post-author-name">David Miller</div>
521 <div class="post-author-handle">@davidm.bsky.social · <span class="post-timestamp">8h</span></div>
522 </div>
523 </div>
524
525 <div class="post-content">
526 Beautiful sunset from my hike today! 🌅 <a href="#" class="post-facet-hashtag">#nature</a>
527 <a href="#" class="post-facet-hashtag">#photography</a> <a href="#" class="post-facet-hashtag">#hiking</a>
528 </div>
529
530 <div class="post-embed">
531 <div class="post-embed-image">[Sunset Photo]</div>
532 </div>
533
534 <div class="post-actions">
535 <button class="post-action">
536 <svg
537 viewBox="0 0 24 24"
538 fill="none"
539 stroke="currentColor"
540 stroke-width="2"
541 stroke-linecap="round"
542 stroke-linejoin="round">
543 <path
544 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" />
545 </svg>
546 6
547 </button>
548 <button class="post-action">
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 <polyline points="17 1 21 5 17 9" />
557 <path d="M3 11V9a4 4 0 0 1 4-4h14" />
558 <polyline points="7 23 3 19 7 15" />
559 <path d="M21 13v2a4 4 0 0 1-4 4H3" />
560 </svg>
561 18
562 </button>
563 <button class="post-action">
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 <path
572 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" />
573 </svg>
574 423
575 </button>
576 <button class="post-action">
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="M4 12v8a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-8" />
585 <polyline points="16 6 12 2 8 6" />
586 <line x1="12" y1="2" x2="12" y2="15" />
587 </svg>
588 </button>
589 </div>
590 </article>
591 </div>
592
593 <!-- Bottom Navigation -->
594 <nav class="nav-bar">
595 <a href="home.html" class="nav-item active">
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 <path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" />
604 <polyline points="9 22 9 12 15 12 15 22" />
605 </svg>
606 <span>Home</span>
607 </a>
608
609 <a href="profile.html" class="nav-item">
610 <svg
611 viewBox="0 0 24 24"
612 fill="none"
613 stroke="currentColor"
614 stroke-width="2"
615 stroke-linecap="round"
616 stroke-linejoin="round">
617 <path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2" />
618 <circle cx="12" cy="7" r="4" />
619 </svg>
620 <span>Profile</span>
621 </a>
622
623 <a href="settings.html" class="nav-item">
624 <svg
625 viewBox="0 0 24 24"
626 fill="none"
627 stroke="currentColor"
628 stroke-width="2"
629 stroke-linecap="round"
630 stroke-linejoin="round">
631 <circle cx="12" cy="12" r="3" />
632 <path
633 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" />
634 </svg>
635 <span>Settings</span>
636 </a>
637 </nav>
638 </div>
639
640 <script>
641 if (localStorage.getItem("theme") === "dark") {
642 document.documentElement.setAttribute("data-theme", "dark");
643 }
644 </script>
645 </body>
646</html>