From b4a8ac82c818a2489d096219fad0b7cc1963b6e0 Mon Sep 17 00:00:00 2001 From: Orual Date: Tue, 23 Jun 2026 21:35:30 -0400 Subject: [PATCH] amusing placeholders --- Cargo.lock | 1 + Cargo.toml | 1 + src/browse.rs | 21 +++++++++++++- src/examples.rs | 77 +++++++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 1 + src/shell.rs | 10 +++++-- 6 files changed, 108 insertions(+), 3 deletions(-) create mode 100644 src/examples.rs diff --git a/Cargo.lock b/Cargo.lock index f26a525..6611c2e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6224,6 +6224,7 @@ dependencies = [ "keyring", "libsqlite3-sys", "polymodel-api", + "rand 0.9.4", "reqwest", "rustls", "serde", diff --git a/Cargo.toml b/Cargo.toml index 67921a5..266dc55 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -109,6 +109,7 @@ tracing-subscriber = { version = "0.3", optional = true, default-features = fals http = "1.4" http-body-util = { version = "0.1", optional = true } reqwest = { version = "0.12", default-features = false, features = ["json", "charset"] } +rand = "0.9" # PM-27 OAuth: private cookie-jar signing key and swappable secret sources # (OS keyring preferred; env override). reqwest is shared with the client crate. diff --git a/src/browse.rs b/src/browse.rs index f25b841..a6ee991 100644 --- a/src/browse.rs +++ b/src/browse.rs @@ -5,6 +5,7 @@ use polymodel_api::space_polymodel::library; use crate::Route; use crate::client::PolymodelClient; +use crate::examples::{HERO_SAMPLE_HANDLES, first_hero_sample_handle}; use crate::profile::profile_href; use crate::session::SessionIdentity; use crate::thing_card::ThingCard; @@ -245,6 +246,23 @@ fn HeroBand() -> Element { var b=this.closest('.hero-band'); if(b){{b.style.display='none';}}\">×", cookie = HERO_DISMISS_COOKIE ); + let sample_handles = serde_json::to_string(HERO_SAMPLE_HANDLES) + .expect("hero sample handles should serialize as JSON"); + let rotation_js = format!( + r#" + (() => {{ + const samples = {sample_handles}; + const input = document.currentScript.closest('.hero-band')?.querySelector('.hero-band-input'); + if (!input || samples.length < 2) return; + let index = Math.floor(Math.random() * samples.length); + input.placeholder = samples[index]; + window.setInterval(() => {{ + index = (index + 1) % samples.length; + input.placeholder = samples[index]; + }}, 30000); + }})(); + "#, + ); rsx! { section { class: "hero-band blueprint-panel", aria_label: "About Polymodel", @@ -259,7 +277,7 @@ fn HeroBand() -> Element { class: "hero-band-input", r#type: "text", name: "identifier", - placeholder: "you.bsky.social", + placeholder: "{first_hero_sample_handle()}", aria_label: "Bluesky handle", } button { class: "button button-secondary", r#type: "submit", "Sign in" } @@ -268,6 +286,7 @@ fn HeroBand() -> Element { } } div { class: "hero-band-dismiss", dangerous_inner_html: dismiss_html } + script { dangerous_inner_html: rotation_js } } } } diff --git a/src/examples.rs b/src/examples.rs new file mode 100644 index 0000000..1a82003 --- /dev/null +++ b/src/examples.rs @@ -0,0 +1,77 @@ +pub(crate) const SAMPLE_HANDLES: &[&str] = &[ + "you.bsky.social", + "alice.bsky.social", + "bob.bsky.social", + "carol.bsky.social", + "you.npmx.social", + "you.gander.social", + "you.pckt.cafe", + "you.blacksky.community", + "you.northsky.social", + "you.eurosky.social", + "you.teal.town", + "you.selfhosted.social", + "you.tngl.sh", + "someone.wsocial.eu", + "ari.bsky.social", + "meri.roomy.chat", + "you.roomy.chat", + "foundry.cryptoanarchy.network", +]; + +pub(crate) const HERO_SAMPLE_HANDLES: &[&str] = &[ + "you.bsky.social", + "you.npmx.social", + "alice.bsky.social", + "bob.bsky.social", + "carol.bsky.social", + "you.pckt.cafe", + "you.blacksky.community", + "you.gander.social", + "you.cryptoanarchy.network", + "you.northsky.social", + "you.eurosky.social", + "you.teal.town", + "you.roomy.chat", + "someone.wsocial.eu", + "you.selfhosted.social", + "you.tngl.sh", + "ari.bsky.social", + "meri.roomy.chat", + "mesh.cryptoanarchy.network", +]; + +pub(crate) const SAMPLE_SEARCH_QUERIES: &[&str] = &[ + "parametric enclosure", + "atproto desk toy", + "bluesky badge clip", + "print-in-place hinge", + "calibration tower", + "gridfinity bins", + "pds server rack", + "snap-fit case", + "tiny relay antenna", + "custom feed trophy", + "desk cable comb", + "did:plc nameplate", + "modular planter", + "statuettes of Alf", + "emotional support benchy", +]; + +pub(crate) fn random_sample_handle() -> String { + random_sample(SAMPLE_HANDLES) +} + +pub(crate) fn first_hero_sample_handle() -> &'static str { + HERO_SAMPLE_HANDLES[0] +} + +pub(crate) fn random_sample_search_query() -> String { + random_sample(SAMPLE_SEARCH_QUERIES) +} + +fn random_sample(samples: &[&str]) -> String { + let index = rand::random::() as usize % samples.len(); + samples[index].to_string() +} diff --git a/src/main.rs b/src/main.rs index e22e7b1..4054629 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,6 +8,7 @@ mod about; mod auth; mod browse; mod client; +mod examples; mod fonts; mod foundation; mod mesh; diff --git a/src/shell.rs b/src/shell.rs index 494cac8..1f2692a 100644 --- a/src/shell.rs +++ b/src/shell.rs @@ -2,6 +2,7 @@ use dioxus::prelude::*; use crate::Route; use crate::auth::{ToastState, broadcast_sign_out, logout_url}; +use crate::examples::{random_sample_handle, random_sample_search_query}; use crate::session::SessionIdentity; /// Global product shell. Renders the persistent header (wordmark, primary nav, @@ -66,6 +67,7 @@ fn ShellSearch() -> Element { }; let mut query = use_signal(|| route_query.clone().unwrap_or_default()); let mut synced_route_query = use_signal(|| route_query.clone()); + let search_placeholder = use_server_cached(random_sample_search_query); if *synced_route_query.read() != route_query { synced_route_query.set(route_query.clone()); @@ -80,7 +82,7 @@ fn ShellSearch() -> Element { class: "app-search-input", r#type: "search", name: "q", - placeholder: "'statuettes of Alf'", + placeholder: "{search_placeholder}", aria_label: "Search Polymodel", value: "{query}", oninput: move |event| query.set(event.value()), @@ -119,6 +121,8 @@ pub(crate) fn SessionControl( ) -> Element { let identity = session.read().clone(); let return_to = current_return_to(); + let handle_placeholder = use_server_cached(random_sample_handle); + let mut identifier = use_signal(|| String::new()); match identity { // Session still resolving: render nothing rather than flashing a sign-in @@ -133,8 +137,10 @@ pub(crate) fn SessionControl( input { r#type: "text", name: "identifier", - placeholder: "alice.bsky.social", + placeholder: "{handle_placeholder}", aria_label: "ATProto handle", + value: "{identifier}", + oninput: move |event| identifier.set(event.value()), } button { class: "button button-primary", r#type: "submit", "Sign in" } } -- knotmirror 0.0.1