atproto Thingiverse but good
12

Configure Feed

Select the types of activity you want to include in your feed.

amusing placeholders

Orual (Jun 29, 2026, 7:06 PM EDT) b4a8ac82 d6a6a08d

+108 -3
+1
Cargo.lock
··· 6224 6224 "keyring", 6225 6225 "libsqlite3-sys", 6226 6226 "polymodel-api", 6227 + "rand 0.9.4", 6227 6228 "reqwest", 6228 6229 "rustls", 6229 6230 "serde",
+1
Cargo.toml
··· 109 109 http = "1.4" 110 110 http-body-util = { version = "0.1", optional = true } 111 111 reqwest = { version = "0.12", default-features = false, features = ["json", "charset"] } 112 + rand = "0.9" 112 113 113 114 # PM-27 OAuth: private cookie-jar signing key and swappable secret sources 114 115 # (OS keyring preferred; env override). reqwest is shared with the client crate.
+20 -1
src/browse.rs
··· 5 5 6 6 use crate::Route; 7 7 use crate::client::PolymodelClient; 8 + use crate::examples::{HERO_SAMPLE_HANDLES, first_hero_sample_handle}; 8 9 use crate::profile::profile_href; 9 10 use crate::session::SessionIdentity; 10 11 use crate::thing_card::ThingCard; ··· 245 246 var b=this.closest('.hero-band'); if(b){{b.style.display='none';}}\">&times;</button>", 246 247 cookie = HERO_DISMISS_COOKIE 247 248 ); 249 + let sample_handles = serde_json::to_string(HERO_SAMPLE_HANDLES) 250 + .expect("hero sample handles should serialize as JSON"); 251 + let rotation_js = format!( 252 + r#" 253 + (() => {{ 254 + const samples = {sample_handles}; 255 + const input = document.currentScript.closest('.hero-band')?.querySelector('.hero-band-input'); 256 + if (!input || samples.length < 2) return; 257 + let index = Math.floor(Math.random() * samples.length); 258 + input.placeholder = samples[index]; 259 + window.setInterval(() => {{ 260 + index = (index + 1) % samples.length; 261 + input.placeholder = samples[index]; 262 + }}, 30000); 263 + }})(); 264 + "#, 265 + ); 248 266 249 267 rsx! { 250 268 section { class: "hero-band blueprint-panel", aria_label: "About Polymodel", ··· 259 277 class: "hero-band-input", 260 278 r#type: "text", 261 279 name: "identifier", 262 - placeholder: "you.bsky.social", 280 + placeholder: "{first_hero_sample_handle()}", 263 281 aria_label: "Bluesky handle", 264 282 } 265 283 button { class: "button button-secondary", r#type: "submit", "Sign in" } ··· 268 286 } 269 287 } 270 288 div { class: "hero-band-dismiss", dangerous_inner_html: dismiss_html } 289 + script { dangerous_inner_html: rotation_js } 271 290 } 272 291 } 273 292 }
+77
src/examples.rs
··· 1 + pub(crate) const SAMPLE_HANDLES: &[&str] = &[ 2 + "you.bsky.social", 3 + "alice.bsky.social", 4 + "bob.bsky.social", 5 + "carol.bsky.social", 6 + "you.npmx.social", 7 + "you.gander.social", 8 + "you.pckt.cafe", 9 + "you.blacksky.community", 10 + "you.northsky.social", 11 + "you.eurosky.social", 12 + "you.teal.town", 13 + "you.selfhosted.social", 14 + "you.tngl.sh", 15 + "someone.wsocial.eu", 16 + "ari.bsky.social", 17 + "meri.roomy.chat", 18 + "you.roomy.chat", 19 + "foundry.cryptoanarchy.network", 20 + ]; 21 + 22 + pub(crate) const HERO_SAMPLE_HANDLES: &[&str] = &[ 23 + "you.bsky.social", 24 + "you.npmx.social", 25 + "alice.bsky.social", 26 + "bob.bsky.social", 27 + "carol.bsky.social", 28 + "you.pckt.cafe", 29 + "you.blacksky.community", 30 + "you.gander.social", 31 + "you.cryptoanarchy.network", 32 + "you.northsky.social", 33 + "you.eurosky.social", 34 + "you.teal.town", 35 + "you.roomy.chat", 36 + "someone.wsocial.eu", 37 + "you.selfhosted.social", 38 + "you.tngl.sh", 39 + "ari.bsky.social", 40 + "meri.roomy.chat", 41 + "mesh.cryptoanarchy.network", 42 + ]; 43 + 44 + pub(crate) const SAMPLE_SEARCH_QUERIES: &[&str] = &[ 45 + "parametric enclosure", 46 + "atproto desk toy", 47 + "bluesky badge clip", 48 + "print-in-place hinge", 49 + "calibration tower", 50 + "gridfinity bins", 51 + "pds server rack", 52 + "snap-fit case", 53 + "tiny relay antenna", 54 + "custom feed trophy", 55 + "desk cable comb", 56 + "did:plc nameplate", 57 + "modular planter", 58 + "statuettes of Alf", 59 + "emotional support benchy", 60 + ]; 61 + 62 + pub(crate) fn random_sample_handle() -> String { 63 + random_sample(SAMPLE_HANDLES) 64 + } 65 + 66 + pub(crate) fn first_hero_sample_handle() -> &'static str { 67 + HERO_SAMPLE_HANDLES[0] 68 + } 69 + 70 + pub(crate) fn random_sample_search_query() -> String { 71 + random_sample(SAMPLE_SEARCH_QUERIES) 72 + } 73 + 74 + fn random_sample(samples: &[&str]) -> String { 75 + let index = rand::random::<u64>() as usize % samples.len(); 76 + samples[index].to_string() 77 + }
+1
src/main.rs
··· 8 8 mod auth; 9 9 mod browse; 10 10 mod client; 11 + mod examples; 11 12 mod fonts; 12 13 mod foundation; 13 14 mod mesh;
+8 -2
src/shell.rs
··· 2 2 3 3 use crate::Route; 4 4 use crate::auth::{ToastState, broadcast_sign_out, logout_url}; 5 + use crate::examples::{random_sample_handle, random_sample_search_query}; 5 6 use crate::session::SessionIdentity; 6 7 7 8 /// Global product shell. Renders the persistent header (wordmark, primary nav, ··· 66 67 }; 67 68 let mut query = use_signal(|| route_query.clone().unwrap_or_default()); 68 69 let mut synced_route_query = use_signal(|| route_query.clone()); 70 + let search_placeholder = use_server_cached(random_sample_search_query); 69 71 70 72 if *synced_route_query.read() != route_query { 71 73 synced_route_query.set(route_query.clone()); ··· 80 82 class: "app-search-input", 81 83 r#type: "search", 82 84 name: "q", 83 - placeholder: "'statuettes of Alf'", 85 + placeholder: "{search_placeholder}", 84 86 aria_label: "Search Polymodel", 85 87 value: "{query}", 86 88 oninput: move |event| query.set(event.value()), ··· 119 121 ) -> Element { 120 122 let identity = session.read().clone(); 121 123 let return_to = current_return_to(); 124 + let handle_placeholder = use_server_cached(random_sample_handle); 125 + let mut identifier = use_signal(|| String::new()); 122 126 123 127 match identity { 124 128 // Session still resolving: render nothing rather than flashing a sign-in ··· 133 137 input { 134 138 r#type: "text", 135 139 name: "identifier", 136 - placeholder: "alice.bsky.social", 140 + placeholder: "{handle_placeholder}", 137 141 aria_label: "ATProto handle", 142 + value: "{identifier}", 143 + oninput: move |event| identifier.set(event.value()), 138 144 } 139 145 button { class: "button button-primary", r#type: "submit", "Sign in" } 140 146 }