ML-based recommendation feed for Bluesky posts
1<!DOCTYPE html>
2<head>
3 <meta charset="UTF-8">
4 <meta name="viewport" content="width=device-width, initial-scale=1.0">
5 <title>Bluesky Recommendations</title>
6 <style>
7 * {
8 margin: 0;
9 padding: 0;
10 box-sizing: border-box;
11 }
12
13 body {
14 font-family: 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
15 background: #f8f5d7;
16 min-height: 100vh;
17 padding: 40px 20px;
18 }
19
20 .container {
21 max-width: 750px;
22 margin: 0 auto;
23 padding-top: 80px;
24 }
25
26 .list-contianer {
27 max-width: 500px;
28 }
29
30 h1 {
31 color: rgb(0, 0, 0);
32 text-align: center;
33 margin-bottom: 40px;
34 font-size: 2.5em;
35 }
36
37 .profiles-grid {
38 display: flex;
39 gap: 24px;
40 padding: 12px;
41 }
42
43 .profile-card {
44 background: rgb(255, 254, 241);
45 border-radius: 10px;
46 padding: 24px;
47 margin: 15px 10px;
48 box-shadow: 0 5px 5px rgba(0,0,0,0.2);
49 transition: transform 0.3s ease, box-shadow 0.3s ease;
50 cursor: pointer;
51 display: flex;
52 align-items: center;
53 }
54
55 .profile-card:hover {
56 transform: scale(1.02);
57 box-shadow: 0 5px 5px rgba(0,0,0,0.3);
58 }
59
60 .profile-image {
61 max-width: 80px;
62 max-height: 80px;
63 aspect-ratio: 1;
64 border-radius: 55px;
65 object-fit: cover;
66 }
67
68 .profile-info {
69 text-align: left;
70 margin-left: 25px;
71 }
72
73 .display-name {
74 font-size: 1.4em;
75 font-weight: 600;
76 color: #2d3748;
77 margin-bottom: 2px;
78 }
79
80 .did {
81 font-size: 0.9em;
82 color: #718096;
83 font-family: 'Courier New', monospace;
84 background: #f7fafc;
85 padding: 6px 12px;
86 margin-bottom: 4px;
87 border-radius: 8px;
88 word-break: break-all;
89 width: fit-content;
90 }
91 .description {
92 font-size: 0.95em;
93 color: #4a5568;
94 line-height: 1.5;
95 margin-bottom: 12px;
96 padding-left: 6px;
97 }
98
99 .search-container {
100 margin: 0 auto 30px;
101 padding: 0 10px;
102 }
103 .search-container form {
104 display: flex;
105 gap: 10px;
106 width: 100%;
107 }
108 .search-input {
109 flex: 1;
110 padding: 12px 16px;
111 font-size: 1em;
112 border: 2px solid #e2e8f0;
113 border-radius: 8px;
114 background: rgb(255, 254, 241);
115 font-family: 'Courier New', monospace;
116 }
117 .search-input:focus {
118 outline: none;
119 border-color: #667eea;
120 }
121 .search-button {
122 padding: 12px 24px;
123 font-size: 1em;
124 font-weight: 600;
125 background: #667eea;
126 color: white;
127 border: none;
128 border-radius: 8px;
129 cursor: pointer;
130 transition: background 0.3s ease;
131 }
132 .search-button:hover {
133 background: #5568d3;
134 }
135
136 .blurb {
137 text-align: center;
138 margin-bottom: 10px;
139 }
140 </style>
141</head>
142<body>
143 <div class="container">
144 <h1>Bluesky Account Recommendations</h1>
145
146 <p class="blurb">Enter your bluesky handle or DID and get a list of recommended accounts!</p>
147
148 <div class="search-container">
149 <form onsubmit="event.preventDefault(); searchProfile();">
150 <input type="text" id="searchInput" placeholder="Enter handle or DID (e.g. johndoe.bsky.social)..." class="search-input" value="{{ query }}">
151 <button type="submit" class="search-button">Go</button>
152 </form>
153 </div>
154
155 <ul class="list-container">
156 {% for profile in profiles %}
157 <div class="profile-card" onclick="window.open('https://bsky.app/profile/{{ profile.handle }}', '_blank')">
158 <img src={{ profile.avatar }} alt="Profile" class="profile-image">
159 <div class="profile-info">
160 <div class="display-name">@{{ profile.handle }}</div>
161 <div class="did">{{ profile.did }}</div>
162 <div class="description">{{ profile.description }}</div>
163 </div>
164 </div>
165 {% endfor %}
166 </ul>
167
168 <script>
169 function searchProfile() {
170 const searchValue = document.getElementById('searchInput').value.trim();
171 if (searchValue) {
172 const url = new URL(window.location.href);
173 url.searchParams.set('query', searchValue);
174 window.location.href = url.toString();
175 }
176 }
177 </script>
178 </div>
179</body>