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>Profile - 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 .profile-container {
16 padding-bottom: 88px;
17 }
18
19 .profile-header {
20 background: linear-gradient(180deg, var(--surface) 0%, var(--bg) 100%);
21 padding: 0 16px 16px;
22 }
23
24 .profile-cover {
25 height: 120px;
26 background: linear-gradient(135deg, var(--accent-primary) 0%, var(--accent-secondary) 100%);
27 margin: 0 -16px 16px;
28 border-radius: 0 0 16px 16px;
29 }
30
31 .profile-info {
32 position: relative;
33 }
34
35 .profile-avatar {
36 position: absolute;
37 top: -50px;
38 left: 0;
39 width: 100px;
40 height: 100px;
41 border-radius: 50%;
42 background-color: var(--surface);
43 border: 4px solid var(--bg);
44 display: flex;
45 align-items: center;
46 justify-content: center;
47 font-size: 36px;
48 font-weight: 700;
49 color: var(--text-primary);
50 box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
51 }
52
53 .profile-actions {
54 display: flex;
55 justify-content: flex-end;
56 gap: 12px;
57 margin-bottom: 16px;
58 padding-top: 8px;
59 }
60
61 .profile-btn {
62 padding: 8px 20px;
63 border-radius: 9999px;
64 font-size: 14px;
65 font-weight: 600;
66 cursor: pointer;
67 transition: all 0.2s ease;
68 border: 1.5px solid var(--border);
69 background-color: var(--surface);
70 color: var(--text-primary);
71 }
72
73 .profile-btn:hover {
74 background-color: var(--surface-variant);
75 }
76
77 .profile-btn-primary {
78 background-color: var(--text-primary);
79 color: var(--bg);
80 border-color: var(--text-primary);
81 }
82
83 .profile-btn-primary:hover {
84 opacity: 0.9;
85 }
86
87 .profile-name {
88 font-size: 22px;
89 font-weight: 700;
90 color: var(--text-primary);
91 margin-top: 56px;
92 margin-bottom: 4px;
93 }
94
95 .profile-handle {
96 color: var(--text-secondary);
97 font-size: 15px;
98 margin-bottom: 12px;
99 }
100
101 .profile-bio {
102 color: var(--text-primary);
103 font-size: 15px;
104 line-height: 1.5;
105 margin-bottom: 16px;
106 }
107
108 .profile-meta {
109 display: flex;
110 flex-wrap: wrap;
111 gap: 16px;
112 margin-bottom: 16px;
113 }
114
115 .profile-meta-item {
116 display: flex;
117 align-items: center;
118 gap: 6px;
119 color: var(--text-secondary);
120 font-size: 14px;
121 }
122
123 .profile-meta-item svg {
124 width: 16px;
125 height: 16px;
126 color: var(--text-muted);
127 }
128
129 .profile-stats {
130 display: flex;
131 gap: 24px;
132 }
133
134 .profile-stat {
135 color: var(--text-secondary);
136 font-size: 14px;
137 }
138
139 .profile-stat strong {
140 color: var(--text-primary);
141 font-weight: 700;
142 }
143
144 .profile-tabs {
145 display: flex;
146 border-bottom: 1px solid var(--border);
147 background-color: var(--bg);
148 }
149
150 .profile-tab {
151 flex: 1;
152 padding: 16px;
153 text-align: center;
154 font-weight: 600;
155 font-size: 15px;
156 color: var(--text-secondary);
157 cursor: pointer;
158 border-bottom: 2px solid transparent;
159 transition: all 0.2s ease;
160 background: none;
161 border-top: none;
162 border-left: none;
163 border-right: none;
164 }
165
166 .profile-tab:hover {
167 background-color: var(--surface);
168 color: var(--text-primary);
169 }
170
171 .profile-tab.active {
172 color: var(--text-primary);
173 border-bottom-color: var(--accent-primary);
174 }
175
176 .posts-empty {
177 padding: 48px 24px;
178 text-align: center;
179 }
180
181 .posts-empty-icon {
182 width: 64px;
183 height: 64px;
184 color: var(--text-muted);
185 margin-bottom: 16px;
186 }
187
188 .posts-empty-title {
189 font-size: 18px;
190 font-weight: 600;
191 color: var(--text-primary);
192 margin-bottom: 8px;
193 }
194
195 .posts-empty-text {
196 color: var(--text-secondary);
197 font-size: 14px;
198 }
199 </style>
200 </head>
201 <body>
202 <div class="mobile-container">
203 <!-- Header -->
204 <header class="header">
205 <button class="header-action">← Back</button>
206 <h1 class="header-title">John Doe</h1>
207 <button class="header-action">⋯</button>
208 </header>
209
210 <div class="profile-container">
211 <!-- Profile Header -->
212 <div class="profile-header">
213 <div class="profile-cover"></div>
214
215 <div class="profile-info">
216 <div class="profile-avatar">JD</div>
217
218 <div class="profile-actions">
219 <button class="profile-btn">Edit Profile</button>
220 </div>
221
222 <h2 class="profile-name">John Doe</h2>
223 <div class="profile-handle">@johndoe.bsky.social</div>
224
225 <p class="profile-bio">
226 Building things on the web 🚀 • Open source enthusiast • Coffee addict ☕ •
227 <a href="#" class="link">johndoe.dev</a>
228 </p>
229
230 <div class="profile-meta">
231 <div class="profile-meta-item">
232 <svg
233 viewBox="0 0 24 24"
234 fill="none"
235 stroke="currentColor"
236 stroke-width="2"
237 stroke-linecap="round"
238 stroke-linejoin="round">
239 <path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z" />
240 <circle cx="12" cy="10" r="3" />
241 </svg>
242 San Francisco, CA
243 </div>
244
245 <div class="profile-meta-item">
246 <svg
247 viewBox="0 0 24 24"
248 fill="none"
249 stroke="currentColor"
250 stroke-width="2"
251 stroke-linecap="round"
252 stroke-linejoin="round">
253 <rect x="3" y="4" width="18" height="18" rx="2" ry="2" />
254 <line x1="16" y1="2" x2="16" y2="6" />
255 <line x1="8" y1="2" x2="8" y2="6" />
256 <line x1="3" y1="10" x2="21" y2="10" />
257 </svg>
258 Joined March 2023
259 </div>
260 </div>
261
262 <div class="profile-stats">
263 <div class="profile-stat"><strong>256</strong> Following</div>
264 <div class="profile-stat"><strong>1.2K</strong> Followers</div>
265 <div class="profile-stat"><strong>482</strong> Posts</div>
266 </div>
267 </div>
268 </div>
269
270 <!-- Profile Tabs -->
271 <div class="profile-tabs">
272 <button class="profile-tab active">Posts</button>
273 <button class="profile-tab">Replies</button>
274 <button class="profile-tab">Media</button>
275 <button class="profile-tab">Likes</button>
276 </div>
277
278 <!-- User Posts -->
279
280 <!-- Post 1 -->
281 <article class="post-card">
282 <div class="post-header">
283 <div class="avatar">JD</div>
284 <div class="post-author">
285 <div class="post-author-name">John Doe</div>
286 <div class="post-author-handle">@johndoe.bsky.social · <span class="post-timestamp">2h</span></div>
287 </div>
288 </div>
289
290 <div class="post-content">
291 Finally shipped the new feature I've been working on! 🎉 Check it out and let me know what you think. Always
292 open to feedback! <a href="#" class="post-facet-hashtag">#buildinpublic</a>
293 <a href="#" class="post-facet-hashtag">#indiehacker</a>
294 </div>
295
296 <div class="post-actions">
297 <button class="post-action">
298 <svg
299 viewBox="0 0 24 24"
300 fill="none"
301 stroke="currentColor"
302 stroke-width="2"
303 stroke-linecap="round"
304 stroke-linejoin="round">
305 <path
306 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" />
307 </svg>
308 8
309 </button>
310 <button class="post-action">
311 <svg
312 viewBox="0 0 24 24"
313 fill="none"
314 stroke="currentColor"
315 stroke-width="2"
316 stroke-linecap="round"
317 stroke-linejoin="round">
318 <polyline points="17 1 21 5 17 9" />
319 <path d="M3 11V9a4 4 0 0 1 4-4h14" />
320 <polyline points="7 23 3 19 7 15" />
321 <path d="M21 13v2a4 4 0 0 1-4 4H3" />
322 </svg>
323 3
324 </button>
325 <button class="post-action">
326 <svg
327 viewBox="0 0 24 24"
328 fill="none"
329 stroke="currentColor"
330 stroke-width="2"
331 stroke-linecap="round"
332 stroke-linejoin="round">
333 <path
334 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" />
335 </svg>
336 42
337 </button>
338 <button class="post-action">
339 <svg
340 viewBox="0 0 24 24"
341 fill="none"
342 stroke="currentColor"
343 stroke-width="2"
344 stroke-linecap="round"
345 stroke-linejoin="round">
346 <path d="M4 12v8a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-8" />
347 <polyline points="16 6 12 2 8 6" />
348 <line x1="12" y1="2" x2="12" y2="15" />
349 </svg>
350 </button>
351 </div>
352 </article>
353
354 <!-- Post 2 -->
355 <article class="post-card">
356 <div class="post-header">
357 <div class="avatar">JD</div>
358 <div class="post-author">
359 <div class="post-author-name">John Doe</div>
360 <div class="post-author-handle">@johndoe.bsky.social · <span class="post-timestamp">1d</span></div>
361 </div>
362 </div>
363
364 <div class="post-content">
365 Really enjoying the <a href="#" class="post-facet-mention">@bluesky</a> community so far. Great
366 conversations happening here! Looking forward to seeing how the platform evolves.
367 <a href="#" class="post-facet-hashtag">#bluesky</a> <a href="#" class="post-facet-hashtag">#socialmedia</a>
368 </div>
369
370 <div class="post-actions">
371 <button class="post-action">
372 <svg
373 viewBox="0 0 24 24"
374 fill="none"
375 stroke="currentColor"
376 stroke-width="2"
377 stroke-linecap="round"
378 stroke-linejoin="round">
379 <path
380 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" />
381 </svg>
382 15
383 </button>
384 <button class="post-action">
385 <svg
386 viewBox="0 0 24 24"
387 fill="none"
388 stroke="currentColor"
389 stroke-width="2"
390 stroke-linecap="round"
391 stroke-linejoin="round">
392 <polyline points="17 1 21 5 17 9" />
393 <path d="M3 11V9a4 4 0 0 1 4-4h14" />
394 <polyline points="7 23 3 19 7 15" />
395 <path d="M21 13v2a4 4 0 0 1-4 4H3" />
396 </svg>
397 7
398 </button>
399 <button class="post-action">
400 <svg
401 viewBox="0 0 24 24"
402 fill="none"
403 stroke="currentColor"
404 stroke-width="2"
405 stroke-linecap="round"
406 stroke-linejoin="round">
407 <path
408 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" />
409 </svg>
410 89
411 </button>
412 <button class="post-action">
413 <svg
414 viewBox="0 0 24 24"
415 fill="none"
416 stroke="currentColor"
417 stroke-width="2"
418 stroke-linecap="round"
419 stroke-linejoin="round">
420 <path d="M4 12v8a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-8" />
421 <polyline points="16 6 12 2 8 6" />
422 <line x1="12" y1="2" x2="12" y2="15" />
423 </svg>
424 </button>
425 </div>
426 </article>
427
428 <!-- Post 3 - With Embedded Link -->
429 <article class="post-card">
430 <div class="post-header">
431 <div class="avatar">JD</div>
432 <div class="post-author">
433 <div class="post-author-name">John Doe</div>
434 <div class="post-author-handle">@johndoe.bsky.social · <span class="post-timestamp">3d</span></div>
435 </div>
436 </div>
437
438 <div class="post-content">
439 Great read on the future of decentralized social networks by
440 <a href="#" class="post-facet-mention">@protocol</a> <a href="#" class="post-facet-hashtag">#atprotocol</a>
441 <a href="#" class="post-facet-hashtag">#web3</a>
442 </div>
443
444 <div class="post-embed">
445 <div class="post-embed-image">[Article Preview Image]</div>
446 <div class="post-embed-content">
447 <div class="post-embed-title">The Future of Decentralized Social Networks</div>
448 <div class="post-embed-url">protocol.com/blog/future-decentralized-social</div>
449 </div>
450 </div>
451
452 <div class="post-actions">
453 <button class="post-action">
454 <svg
455 viewBox="0 0 24 24"
456 fill="none"
457 stroke="currentColor"
458 stroke-width="2"
459 stroke-linecap="round"
460 stroke-linejoin="round">
461 <path
462 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" />
463 </svg>
464 22
465 </button>
466 <button class="post-action">
467 <svg
468 viewBox="0 0 24 24"
469 fill="none"
470 stroke="currentColor"
471 stroke-width="2"
472 stroke-linecap="round"
473 stroke-linejoin="round">
474 <polyline points="17 1 21 5 17 9" />
475 <path d="M3 11V9a4 4 0 0 1 4-4h14" />
476 <polyline points="7 23 3 19 7 15" />
477 <path d="M21 13v2a4 4 0 0 1-4 4H3" />
478 </svg>
479 14
480 </button>
481 <button class="post-action">
482 <svg
483 viewBox="0 0 24 24"
484 fill="none"
485 stroke="currentColor"
486 stroke-width="2"
487 stroke-linecap="round"
488 stroke-linejoin="round">
489 <path
490 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" />
491 </svg>
492 156
493 </button>
494 <button class="post-action">
495 <svg
496 viewBox="0 0 24 24"
497 fill="none"
498 stroke="currentColor"
499 stroke-width="2"
500 stroke-linecap="round"
501 stroke-linejoin="round">
502 <path d="M4 12v8a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-8" />
503 <polyline points="16 6 12 2 8 6" />
504 <line x1="12" y1="2" x2="12" y2="15" />
505 </svg>
506 </button>
507 </div>
508 </article>
509 </div>
510
511 <!-- Bottom Navigation -->
512 <nav class="nav-bar">
513 <a href="home.html" class="nav-item">
514 <svg
515 viewBox="0 0 24 24"
516 fill="none"
517 stroke="currentColor"
518 stroke-width="2"
519 stroke-linecap="round"
520 stroke-linejoin="round">
521 <path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" />
522 <polyline points="9 22 9 12 15 12 15 22" />
523 </svg>
524 <span>Home</span>
525 </a>
526
527 <a href="profile.html" class="nav-item active">
528 <svg
529 viewBox="0 0 24 24"
530 fill="none"
531 stroke="currentColor"
532 stroke-width="2"
533 stroke-linecap="round"
534 stroke-linejoin="round">
535 <path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2" />
536 <circle cx="12" cy="7" r="4" />
537 </svg>
538 <span>Profile</span>
539 </a>
540
541 <a href="settings.html" class="nav-item">
542 <svg
543 viewBox="0 0 24 24"
544 fill="none"
545 stroke="currentColor"
546 stroke-width="2"
547 stroke-linecap="round"
548 stroke-linejoin="round">
549 <circle cx="12" cy="12" r="3" />
550 <path
551 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" />
552 </svg>
553 <span>Settings</span>
554 </a>
555 </nav>
556 </div>
557
558 <script>
559 if (localStorage.getItem("theme") === "dark") {
560 document.documentElement.setAttribute("data-theme", "dark");
561 }
562 </script>
563 </body>
564</html>