slack status without the slack status.zzstoatzz.io/
quickslice

fix: clippy warning (avoid unnecessary to_string)

Changed files
+226 -1
src
templates
+8
src/api/status.rs
··· 130 130 vec![] 131 131 }); 132 132 133 + let is_admin_flag = is_admin(did.as_str()); 133 134 let html = StatusTemplate { 134 135 title: "your status", 135 136 handle, 136 137 current_status, 137 138 history, 138 139 is_owner: true, // They're viewing their own status 140 + is_admin: is_admin_flag, 139 141 } 140 142 .render() 141 143 .expect("template should be valid"); ··· 192 194 current_status, 193 195 history, 194 196 is_owner: false, // Visitor viewing owner's status 197 + is_admin: false, 195 198 } 196 199 .render() 197 200 .expect("template should be valid"); ··· 275 278 vec![] 276 279 }); 277 280 281 + let is_admin_flag = match session.get::<String>("did").unwrap_or(None) { 282 + Some(d) => is_admin(&d), 283 + None => false, 284 + }; 278 285 let html = StatusTemplate { 279 286 title: &format!("@{} status", handle), 280 287 handle: handle.clone(), 281 288 current_status, 282 289 history, 283 290 is_owner, 291 + is_admin: is_admin_flag, 284 292 } 285 293 .render() 286 294 .expect("template should be valid");
+1
src/templates.rs
··· 36 36 pub current_status: Option<StatusFromDb>, 37 37 pub history: Vec<StatusFromDb>, 38 38 pub is_owner: bool, 39 + pub is_admin: bool, 39 40 } 40 41 41 42 #[derive(Template)]
+109 -1
templates/feed.html
··· 45 45 </button> 46 46 </div> 47 47 </header> 48 + 49 + {% if is_admin %} 50 + <!-- Admin Upload (fixed top-left) --> 51 + <div class="admin-panel" id="admin-panel"> 52 + <button class="admin-toggle" id="admin-toggle" title="admin tools" aria-label="admin tools">⚙️</button> 53 + <div class="admin-content" id="admin-content" style="display:none;"> 54 + <div class="admin-section"> 55 + <div class="admin-title">upload emoji</div> 56 + <form id="emoji-upload-form"> 57 + <input type="text" id="emoji-name" placeholder="name (optional)" maxlength="40" /> 58 + <input type="file" id="emoji-file" accept="image/png,image/gif" required /> 59 + <button type="submit">upload</button> 60 + </form> 61 + <div class="admin-msg" id="admin-msg" aria-live="polite"></div> 62 + </div> 63 + </div> 64 + </div> 65 + {% endif %} 48 66 49 67 <!-- Simple Settings (logged in users only) --> 50 68 {% if let Some(p) = &profile %} ··· 738 756 font-size: 1.5rem; 739 757 } 740 758 } 759 + 760 + /* Admin panel (top-left) */ 761 + .admin-panel { 762 + position: fixed; 763 + top: 12px; 764 + left: 12px; 765 + z-index: 9999; 766 + } 767 + .admin-toggle { 768 + background: var(--bg-tertiary); 769 + border: 1px solid var(--border-color); 770 + border-radius: 10px; 771 + padding: 6px 8px; 772 + cursor: pointer; 773 + color: var(--text-secondary); 774 + } 775 + .admin-content { 776 + margin-top: 8px; 777 + background: var(--bg-tertiary); 778 + border: 1px solid var(--border-color); 779 + border-radius: 12px; 780 + padding: 10px; 781 + width: 240px; 782 + box-shadow: var(--shadow-md); 783 + } 784 + .admin-title { 785 + font-size: 12px; 786 + color: var(--text-secondary); 787 + margin-bottom: 6px; 788 + } 789 + .admin-content input[type="text"], 790 + .admin-content input[type="file"] { 791 + width: 100%; 792 + margin-bottom: 8px; 793 + } 794 + .admin-content button[type="submit"] { 795 + width: 100%; 796 + background: var(--accent); 797 + color: #fff; 798 + border: none; 799 + border-radius: 8px; 800 + padding: 6px 8px; 801 + cursor: pointer; 802 + } 803 + .admin-msg { font-size: 12px; color: var(--text-secondary); margin-top: 6px; } 741 804 </style> 742 805 743 806 <script> ··· 1206 1269 }); 1207 1270 }); 1208 1271 }); 1209 - </script> 1272 + </script> 1273 + <script> 1274 + // Admin upload toggles and submit 1275 + document.addEventListener('DOMContentLoaded', function () { 1276 + const toggle = document.getElementById('admin-toggle'); 1277 + const content = document.getElementById('admin-content'); 1278 + const form = document.getElementById('emoji-upload-form'); 1279 + const file = document.getElementById('emoji-file'); 1280 + const name = document.getElementById('emoji-name'); 1281 + const msg = document.getElementById('admin-msg'); 1282 + if (!toggle || !content || !form) return; 1283 + 1284 + toggle.addEventListener('click', () => { 1285 + content.style.display = content.style.display === 'none' ? 'block' : 'none'; 1286 + }); 1287 + 1288 + form.addEventListener('submit', async (e) => { 1289 + e.preventDefault(); 1290 + msg.textContent = ''; 1291 + if (!file.files || file.files.length === 0) { 1292 + msg.textContent = 'choose a PNG or GIF'; 1293 + return; 1294 + } 1295 + const f = file.files[0]; 1296 + if (!['image/png','image/gif'].includes(f.type)) { 1297 + msg.textContent = 'only PNG or GIF'; 1298 + return; 1299 + } 1300 + const fd = new FormData(); 1301 + fd.append('file', f); 1302 + if (name.value.trim().length) fd.append('name', name.value.trim()); 1303 + try { 1304 + const res = await fetch('/admin/upload-emoji', { method: 'POST', body: fd }); 1305 + const json = await res.json(); 1306 + if (!res.ok || !json.success) { 1307 + msg.textContent = json.error || 'upload failed'; 1308 + return; 1309 + } 1310 + msg.textContent = `uploaded: ${json.filename}`; 1311 + // Optionally refresh emoji list used by picker 1312 + } catch (err) { 1313 + msg.textContent = 'network error'; 1314 + } 1315 + }); 1316 + }); 1317 + </script> 1210 1318 {%endblock content%}
+108
templates/status.html
··· 46 46 {% endif %} 47 47 </div> 48 48 </header> 49 + 50 + {% if is_admin %} 51 + <!-- Admin Upload (fixed top-left) --> 52 + <div class="admin-panel" id="admin-panel"> 53 + <button class="admin-toggle" id="admin-toggle" title="admin tools" aria-label="admin tools">⚙️</button> 54 + <div class="admin-content" id="admin-content" style="display:none;"> 55 + <div class="admin-section"> 56 + <div class="admin-title">upload emoji</div> 57 + <form id="emoji-upload-form"> 58 + <input type="text" id="emoji-name" placeholder="name (optional)" maxlength="40" /> 59 + <input type="file" id="emoji-file" accept="image/png,image/gif" required /> 60 + <button type="submit">upload</button> 61 + </form> 62 + <div class="admin-msg" id="admin-msg" aria-live="polite"></div> 63 + </div> 64 + </div> 65 + </div> 66 + {% endif %} 49 67 50 68 <!-- Simple Settings (owner only) --> 51 69 {% if is_owner %} ··· 350 368 align-items: center; 351 369 margin-bottom: 2rem; 352 370 } 371 + 372 + /* Admin panel (top-left) */ 373 + .admin-panel { 374 + position: fixed; 375 + top: 12px; 376 + left: 12px; 377 + z-index: 9999; 378 + } 379 + .admin-toggle { 380 + background: var(--bg-tertiary); 381 + border: 1px solid var(--border-color); 382 + border-radius: 10px; 383 + padding: 6px 8px; 384 + cursor: pointer; 385 + color: var(--text-secondary); 386 + } 387 + .admin-content { 388 + margin-top: 8px; 389 + background: var(--bg-tertiary); 390 + border: 1px solid var(--border-color); 391 + border-radius: 12px; 392 + padding: 10px; 393 + width: 240px; 394 + box-shadow: var(--shadow-md); 395 + } 396 + .admin-title { 397 + font-size: 12px; 398 + color: var(--text-secondary); 399 + margin-bottom: 6px; 400 + } 401 + .admin-content input[type="text"], 402 + .admin-content input[type="file"] { 403 + width: 100%; 404 + margin-bottom: 8px; 405 + } 406 + .admin-content button[type="submit"] { 407 + width: 100%; 408 + background: var(--accent); 409 + color: #fff; 410 + border: none; 411 + border-radius: 8px; 412 + padding: 6px 8px; 413 + cursor: pointer; 414 + } 415 + .admin-msg { font-size: 12px; color: var(--text-secondary); margin-top: 6px; } 353 416 354 417 .header-actions { 355 418 display: flex; ··· 1963 2026 }); 1964 2027 }); 1965 2028 }); 2029 + </script> 2030 + <script> 2031 + // Admin upload toggles and submit 2032 + document.addEventListener('DOMContentLoaded', function () { 2033 + const toggle = document.getElementById('admin-toggle'); 2034 + const content = document.getElementById('admin-content'); 2035 + const form = document.getElementById('emoji-upload-form'); 2036 + const file = document.getElementById('emoji-file'); 2037 + const name = document.getElementById('emoji-name'); 2038 + const msg = document.getElementById('admin-msg'); 2039 + if (!toggle || !content || !form) return; 2040 + 2041 + toggle.addEventListener('click', () => { 2042 + content.style.display = content.style.display === 'none' ? 'block' : 'none'; 2043 + }); 2044 + 2045 + form.addEventListener('submit', async (e) => { 2046 + e.preventDefault(); 2047 + msg.textContent = ''; 2048 + if (!file.files || file.files.length === 0) { 2049 + msg.textContent = 'choose a PNG or GIF'; 2050 + return; 2051 + } 2052 + const f = file.files[0]; 2053 + if (!['image/png','image/gif'].includes(f.type)) { 2054 + msg.textContent = 'only PNG or GIF'; 2055 + return; 2056 + } 2057 + const fd = new FormData(); 2058 + fd.append('file', f); 2059 + if (name.value.trim().length) fd.append('name', name.value.trim()); 2060 + try { 2061 + const res = await fetch('/admin/upload-emoji', { method: 'POST', body: fd }); 2062 + const json = await res.json(); 2063 + if (!res.ok || !json.success) { 2064 + msg.textContent = json.error || 'upload failed'; 2065 + return; 2066 + } 2067 + msg.textContent = `uploaded: ${json.filename}`; 2068 + // Optionally refresh emoji list used by picker 2069 + } catch (err) { 2070 + msg.textContent = 'network error'; 2071 + } 2072 + }); 2073 + }); 1966 2074 </script> 1967 2075 {%endblock content%}