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>Feeds - 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 href="https://fonts.googleapis.com/css2?family=DM+Sans:ital,opsz,wght@0,9..40,100..1000;1,9..40,100..1000&display=swap" rel="stylesheet" />
11 <link rel="stylesheet" href="styles.css" />
12 <style>
13 .feeds-container {
14 padding-bottom: 88px;
15 }
16
17 .feeds-section-header {
18 display: flex;
19 align-items: center;
20 justify-content: space-between;
21 padding: 12px 16px;
22 background-color: var(--surface);
23 border-bottom: 1px solid var(--border);
24 }
25
26 .feeds-section-title {
27 font-size: 13px;
28 font-weight: 600;
29 color: var(--text-muted);
30 text-transform: uppercase;
31 letter-spacing: 0.5px;
32 }
33
34 .feeds-section-action {
35 background: none;
36 border: none;
37 color: var(--accent-primary);
38 font-size: 13px;
39 font-weight: 600;
40 cursor: pointer;
41 }
42
43 /* Feed Item */
44 .feed-item {
45 display: flex;
46 align-items: center;
47 gap: 12px;
48 padding: 14px 16px;
49 border-bottom: 1px solid var(--border);
50 transition: background-color 0.2s ease;
51 }
52
53 .feed-item-drag {
54 width: 20px;
55 display: flex;
56 flex-direction: column;
57 align-items: center;
58 gap: 2px;
59 cursor: grab;
60 flex-shrink: 0;
61 color: var(--text-muted);
62 }
63
64 .feed-item-drag svg {
65 width: 16px;
66 height: 16px;
67 }
68
69 .feed-item-icon {
70 width: 40px;
71 height: 40px;
72 border-radius: 10px;
73 display: flex;
74 align-items: center;
75 justify-content: center;
76 font-size: 18px;
77 flex-shrink: 0;
78 }
79
80 .feed-item-icon-blue {
81 background: linear-gradient(135deg, #0066ff 0%, #0ea5e9 100%);
82 color: white;
83 }
84
85 .feed-item-icon-purple {
86 background: linear-gradient(135deg, #8b5cf6 0%, #be95ff 100%);
87 color: white;
88 }
89
90 .feed-item-icon-green {
91 background: linear-gradient(135deg, #22c55e 0%, #42be65 100%);
92 color: white;
93 }
94
95 .feed-item-icon-orange {
96 background: linear-gradient(135deg, #f59e0b 0%, #fb923c 100%);
97 color: white;
98 }
99
100 .feed-item-icon-pink {
101 background: linear-gradient(135deg, #ee5396 0%, #ff7eb6 100%);
102 color: white;
103 }
104
105 .feed-item-icon-teal {
106 background: linear-gradient(135deg, #08bdba 0%, #3ddbd9 100%);
107 color: white;
108 }
109
110 .feed-item-info {
111 flex: 1;
112 min-width: 0;
113 }
114
115 .feed-item-name {
116 font-weight: 600;
117 font-size: 15px;
118 color: var(--text-primary);
119 }
120
121 .feed-item-creator {
122 font-size: 13px;
123 color: var(--text-secondary);
124 }
125
126 .feed-item-desc {
127 font-size: 13px;
128 color: var(--text-muted);
129 margin-top: 2px;
130 display: -webkit-box;
131 line-clamp: 1;
132 -webkit-line-clamp: 1;
133 -webkit-box-orient: vertical;
134 overflow: hidden;
135 }
136
137 .feed-item-actions {
138 display: flex;
139 align-items: center;
140 gap: 8px;
141 flex-shrink: 0;
142 }
143
144 .feed-pin-btn {
145 width: 32px;
146 height: 32px;
147 border-radius: 50%;
148 border: 1.5px solid var(--border);
149 background: none;
150 cursor: pointer;
151 display: flex;
152 align-items: center;
153 justify-content: center;
154 transition: all 0.2s ease;
155 }
156
157 .feed-pin-btn svg {
158 width: 16px;
159 height: 16px;
160 color: var(--text-muted);
161 }
162
163 .feed-pin-btn:hover {
164 border-color: var(--accent-primary);
165 }
166
167 .feed-pin-btn:hover svg {
168 color: var(--accent-primary);
169 }
170
171 .feed-pin-btn.pinned {
172 background-color: var(--accent-primary);
173 border-color: var(--accent-primary);
174 }
175
176 .feed-pin-btn.pinned svg {
177 color: white;
178 }
179
180 .feed-remove-btn {
181 width: 32px;
182 height: 32px;
183 border-radius: 50%;
184 border: none;
185 background: none;
186 cursor: pointer;
187 display: flex;
188 align-items: center;
189 justify-content: center;
190 transition: all 0.2s ease;
191 }
192
193 .feed-remove-btn svg {
194 width: 16px;
195 height: 16px;
196 color: var(--text-muted);
197 }
198
199 .feed-remove-btn:hover svg {
200 color: var(--accent-error);
201 }
202
203 /* Discover Feed Card */
204 .discover-grid {
205 padding: 16px;
206 display: flex;
207 flex-direction: column;
208 gap: 12px;
209 }
210
211 .discover-card {
212 display: flex;
213 align-items: center;
214 gap: 12px;
215 padding: 12px;
216 background-color: var(--surface);
217 border-radius: 12px;
218 border: 1px solid var(--border);
219 cursor: pointer;
220 transition: all 0.2s ease;
221 }
222
223 .discover-card:hover {
224 border-color: var(--accent-primary);
225 background-color: var(--surface-variant);
226 }
227
228 .discover-card-info {
229 flex: 1;
230 min-width: 0;
231 }
232
233 .discover-card-name {
234 font-weight: 600;
235 font-size: 15px;
236 color: var(--text-primary);
237 }
238
239 .discover-card-creator {
240 font-size: 12px;
241 color: var(--text-secondary);
242 }
243
244 .discover-card-desc {
245 font-size: 13px;
246 color: var(--text-muted);
247 margin-top: 4px;
248 display: -webkit-box;
249 line-clamp: 2;
250 -webkit-line-clamp: 2;
251 -webkit-box-orient: vertical;
252 overflow: hidden;
253 }
254
255 .discover-card-likes {
256 font-size: 12px;
257 color: var(--text-muted);
258 margin-top: 4px;
259 }
260
261 .add-feed-btn {
262 padding: 6px 14px;
263 border-radius: 9999px;
264 border: 1.5px solid var(--accent-primary);
265 background: none;
266 color: var(--accent-primary);
267 font-size: 13px;
268 font-weight: 600;
269 cursor: pointer;
270 transition: all 0.2s ease;
271 flex-shrink: 0;
272 white-space: nowrap;
273 }
274
275 .add-feed-btn:hover {
276 background-color: var(--accent-primary);
277 color: white;
278 }
279 </style>
280 </head>
281 <body>
282 <div class="mobile-container">
283 <!-- Header -->
284 <header class="header">
285 <button class="header-action">← Back</button>
286 <h1 class="header-title">My Feeds</h1>
287 <button class="header-action">Done</button>
288 </header>
289
290 <div class="feeds-container">
291 <!-- Pinned Feeds -->
292 <div class="feeds-section-header">
293 <span class="feeds-section-title">Pinned Feeds</span>
294 <button class="feeds-section-action">Reorder</button>
295 </div>
296
297 <div class="feed-item">
298 <div class="feed-item-drag">
299 <svg
300 viewBox="0 0 24 24"
301 fill="none"
302 stroke="currentColor"
303 stroke-width="2"
304 stroke-linecap="round"
305 stroke-linejoin="round">
306 <line x1="3" y1="9" x2="21" y2="9" />
307 <line x1="3" y1="15" x2="21" y2="15" />
308 </svg>
309 </div>
310 <div class="feed-item-icon feed-item-icon-blue">
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 width="20"
319 height="20">
320 <path d="M16 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2" />
321 <circle cx="8.5" cy="7" r="4" />
322 <polyline points="17 11 19 13 23 9" />
323 </svg>
324 </div>
325 <div class="feed-item-info">
326 <div class="feed-item-name">Following</div>
327 <div class="feed-item-creator">Timeline</div>
328 </div>
329 <div class="feed-item-actions">
330 <button class="feed-pin-btn pinned" title="Unpin">
331 <svg viewBox="0 0 24 24" fill="currentColor" stroke="none">
332 <path
333 d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z" />
334 </svg>
335 </button>
336 </div>
337 </div>
338
339 <div class="feed-item">
340 <div class="feed-item-drag">
341 <svg
342 viewBox="0 0 24 24"
343 fill="none"
344 stroke="currentColor"
345 stroke-width="2"
346 stroke-linecap="round"
347 stroke-linejoin="round">
348 <line x1="3" y1="9" x2="21" y2="9" />
349 <line x1="3" y1="15" x2="21" y2="15" />
350 </svg>
351 </div>
352 <div class="feed-item-icon feed-item-icon-orange">🔥</div>
353 <div class="feed-item-info">
354 <div class="feed-item-name">What's Hot</div>
355 <div class="feed-item-creator">by Bluesky</div>
356 </div>
357 <div class="feed-item-actions">
358 <button class="feed-pin-btn pinned" title="Unpin">
359 <svg viewBox="0 0 24 24" fill="currentColor" stroke="none">
360 <path
361 d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z" />
362 </svg>
363 </button>
364 </div>
365 </div>
366
367 <div class="feed-item">
368 <div class="feed-item-drag">
369 <svg
370 viewBox="0 0 24 24"
371 fill="none"
372 stroke="currentColor"
373 stroke-width="2"
374 stroke-linecap="round"
375 stroke-linejoin="round">
376 <line x1="3" y1="9" x2="21" y2="9" />
377 <line x1="3" y1="15" x2="21" y2="15" />
378 </svg>
379 </div>
380 <div class="feed-item-icon feed-item-icon-purple">🧪</div>
381 <div class="feed-item-info">
382 <div class="feed-item-name">Science</div>
383 <div class="feed-item-creator">by bossett.social</div>
384 </div>
385 <div class="feed-item-actions">
386 <button class="feed-pin-btn pinned" title="Unpin">
387 <svg viewBox="0 0 24 24" fill="currentColor" stroke="none">
388 <path
389 d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z" />
390 </svg>
391 </button>
392 </div>
393 </div>
394
395 <!-- Saved (Unpinned) Feeds -->
396 <div class="feeds-section-header">
397 <span class="feeds-section-title">Saved Feeds</span>
398 </div>
399
400 <div class="feed-item">
401 <div style="width: 20px"></div>
402 <div class="feed-item-icon feed-item-icon-green">📰</div>
403 <div class="feed-item-info">
404 <div class="feed-item-name">News</div>
405 <div class="feed-item-creator">by skyfeed.xyz</div>
406 </div>
407 <div class="feed-item-actions">
408 <button class="feed-pin-btn" title="Pin">
409 <svg
410 viewBox="0 0 24 24"
411 fill="none"
412 stroke="currentColor"
413 stroke-width="2"
414 stroke-linecap="round"
415 stroke-linejoin="round">
416 <path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z" />
417 <circle cx="12" cy="10" r="3" />
418 </svg>
419 </button>
420 <button class="feed-remove-btn" title="Remove">
421 <svg
422 viewBox="0 0 24 24"
423 fill="none"
424 stroke="currentColor"
425 stroke-width="2"
426 stroke-linecap="round"
427 stroke-linejoin="round">
428 <line x1="18" y1="6" x2="6" y2="18" />
429 <line x1="6" y1="6" x2="18" y2="18" />
430 </svg>
431 </button>
432 </div>
433 </div>
434
435 <div class="feed-item">
436 <div style="width: 20px"></div>
437 <div class="feed-item-icon feed-item-icon-pink">🎨</div>
438 <div class="feed-item-info">
439 <div class="feed-item-name">Art</div>
440 <div class="feed-item-creator">by flicknow.xyz</div>
441 </div>
442 <div class="feed-item-actions">
443 <button class="feed-pin-btn" title="Pin">
444 <svg
445 viewBox="0 0 24 24"
446 fill="none"
447 stroke="currentColor"
448 stroke-width="2"
449 stroke-linecap="round"
450 stroke-linejoin="round">
451 <path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z" />
452 <circle cx="12" cy="10" r="3" />
453 </svg>
454 </button>
455 <button class="feed-remove-btn" title="Remove">
456 <svg
457 viewBox="0 0 24 24"
458 fill="none"
459 stroke="currentColor"
460 stroke-width="2"
461 stroke-linecap="round"
462 stroke-linejoin="round">
463 <line x1="18" y1="6" x2="6" y2="18" />
464 <line x1="6" y1="6" x2="18" y2="18" />
465 </svg>
466 </button>
467 </div>
468 </div>
469
470 <!-- Discover -->
471 <div class="feeds-section-header">
472 <span class="feeds-section-title">Discover Feeds</span>
473 <button class="feeds-section-action">See All</button>
474 </div>
475
476 <div class="discover-grid">
477 <div class="discover-card">
478 <div class="feed-item-icon feed-item-icon-teal">🌐</div>
479 <div class="discover-card-info">
480 <div class="discover-card-name">Popular With Friends</div>
481 <div class="discover-card-creator">by Bluesky</div>
482 <div class="discover-card-desc">Posts liked by people you follow</div>
483 <div class="discover-card-likes">❤️ 15.2K likes</div>
484 </div>
485 <button class="add-feed-btn">+ Add</button>
486 </div>
487
488 <div class="discover-card">
489 <div class="feed-item-icon feed-item-icon-blue">💻</div>
490 <div class="discover-card-info">
491 <div class="discover-card-name">Tech & Dev</div>
492 <div class="discover-card-creator">by devfeed.app</div>
493 <div class="discover-card-desc">A curated mix of tech, programming, and dev culture posts</div>
494 <div class="discover-card-likes">❤️ 8.3K likes</div>
495 </div>
496 <button class="add-feed-btn">+ Add</button>
497 </div>
498
499 <div class="discover-card">
500 <div class="feed-item-icon feed-item-icon-green">📸</div>
501 <div class="discover-card-info">
502 <div class="discover-card-name">Photography</div>
503 <div class="discover-card-creator">by photo.bsky.social</div>
504 <div class="discover-card-desc">Beautiful photos from across the Bluesky network</div>
505 <div class="discover-card-likes">❤️ 6.1K likes</div>
506 </div>
507 <button class="add-feed-btn">+ Add</button>
508 </div>
509 </div>
510 </div>
511
512 <!-- Bottom Navigation -->
513 <nav class="nav-bar">
514 <a href="home.html" class="nav-item">
515 <svg
516 viewBox="0 0 24 24"
517 fill="none"
518 stroke="currentColor"
519 stroke-width="2"
520 stroke-linecap="round"
521 stroke-linejoin="round">
522 <path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" />
523 <polyline points="9 22 9 12 15 12 15 22" />
524 </svg>
525 <span>Home</span>
526 </a>
527
528 <a href="search.html" class="nav-item">
529 <svg
530 viewBox="0 0 24 24"
531 fill="none"
532 stroke="currentColor"
533 stroke-width="2"
534 stroke-linecap="round"
535 stroke-linejoin="round">
536 <circle cx="11" cy="11" r="8" />
537 <line x1="21" y1="21" x2="16.65" y2="16.65" />
538 </svg>
539 <span>Search</span>
540 </a>
541
542 <a href="profile.html" class="nav-item">
543 <svg
544 viewBox="0 0 24 24"
545 fill="none"
546 stroke="currentColor"
547 stroke-width="2"
548 stroke-linecap="round"
549 stroke-linejoin="round">
550 <path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2" />
551 <circle cx="12" cy="7" r="4" />
552 </svg>
553 <span>Profile</span>
554 </a>
555
556 <a href="settings.html" class="nav-item">
557 <svg
558 viewBox="0 0 24 24"
559 fill="none"
560 stroke="currentColor"
561 stroke-width="2"
562 stroke-linecap="round"
563 stroke-linejoin="round">
564 <circle cx="12" cy="12" r="3" />
565 <path
566 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" />
567 </svg>
568 <span>Settings</span>
569 </a>
570 </nav>
571 </div>
572
573 <script>
574 if (localStorage.getItem("theme") === "dark") {
575 document.documentElement.setAttribute("data-theme", "dark");
576 }
577 </script>
578 </body>
579</html>