Initials avatars
Round avatars with a person's initials as SVG, the colour from the name so each keeps theirs, the text readable on it.
Version 1.0.0 · 3 functions · 0 crates
Functions
What use avatar_initials.qwer gives a program, with the types Quillo sees. To take only some, or under other names: use avatar_initials, avatar_color from avatar_initials (Quillo 0.6).
avatar_initials(name: str) → strThe initials of name, at most two letters in capitals: "Ada Lovelace" is "AL", "grace" is "G", "Jean-Luc Picard" is "JP"; an email gives those of its name part ("ada.l@x" is "AL"). "?" for a name with no letters.
avatar_color(name: str) → strThe background colour for name, one of twelve, always the same for the same name (any case, spaces trimmed).
avatar_svg(name: str, size: int, options: any) → strAn avatar for name as SVG, size pixels square (16 to 1024). options (or null): shape "circle" (the default), "rounded" or "square", background and color as "#rrggbb" to choose them yourself, and title false to leave out the tooltip with the name.
Get it
$ quillo install avatar_initials # avatar_initials.qwer into this folder$ quillo install avatar_initials --example # and its example, avatar_initials.qweOr with curl:
$ curl -O https://quillolang.org/plugins/files/avatar_initials.qwer$ curl -O https://quillolang.org/plugins/files/avatar_initials.qweThen, in your program, all of it or only what you call:
use avatar_initials.qweruse avatar_initials, avatar_color from avatar_initials // Quillo 0.6: only theseIt uses these crates, which cargo fetches the first time the plugin is built:
Example
// A team page with an initials avatar for everyone who has not uploaded a photo.//// quillo run avatar_initials.qwe then open http://localhost:8080/use "avatar_initials.qwer"let team = ["Ada Lovelace", "grace hopper", "Jean-Luc Picard", "alan.turing@example.com", "Edsger"]route GET /avatar/:name = respond(200, avatar_svg(name, 64, null), { "content-type": "image/svg+xml", "cache-control": "max-age=86400" })route GET / = <html><body style="font-family: sans-serif"> {for n in team => <div style="display: flex; gap: 8px; align-items: center; margin: 4px">{raw(avatar_svg(n, 40, { shape: "rounded" }))} {n}</div>}</body></html>route GET /initials = team | map((n) => { name: n, initials: avatar_initials(n), color: avatar_color(n) })$ quillo run avatar_initials.qwe$ curl 'localhost:8080/initials'$ curl 'localhost:8080/avatar/Ada%20Lovelace'Source
//! Round avatars with a person's initials, as SVG: the colour comes from the name, so each person keeps theirs, and the text stays readable on it.//! version: 1.0.0//!//! [dependencies]use serde_json::Value;// Mid-tone colours on which white text reads (4.5:1 or better).const COLOURS: [&str; 12] = ["#1d4ed8", "#b91c1c", "#047857", "#7c3aed", "#be185d", "#0e7490", "#a16207", "#4338ca", "#15803d", "#c2410c", "#6d28d9", "#0f766e"];fn esc(s: &str) -> String { s.replace('&', "&").replace('<', "<").replace('>', ">").replace('"', """)}/// The initials of `name`, at most two letters in capitals: "Ada Lovelace" is "AL", "grace" is "G", "Jean-Luc Picard" is "JP"; an email gives those of its name part ("ada.l@x" is "AL")./// "?" for a name with no letters.pub fn avatar_initials(name: &str) -> String { let base = name.split('@').next().unwrap_or(""); let words: Vec<&str> = base.split(|c: char| c.is_whitespace() || c == '.' || c == '_' || c == '-' || c == '+').filter(|w| w.chars().any(char::is_alphanumeric)).collect(); let first = |w: &str| w.chars().find(|c| c.is_alphanumeric()).map(|c| c.to_uppercase().collect::<String>()).unwrap_or_default(); let s = match words.as_slice() { [] => "?".to_string(), [one] => first(one), [a, .., b] => format!("{}{}", first(a), first(b)), }; if s.is_empty() { "?".into() } else { s }}/// The background colour for `name`, one of twelve, always the same for the same name (any case, spaces trimmed).pub fn avatar_color(name: &str) -> String { let mut h: u32 = 2166136261; for b in name.trim().to_lowercase().bytes() { h ^= b as u32; h = h.wrapping_mul(16777619); } COLOURS[(h % COLOURS.len() as u32) as usize].to_string()}/// An avatar for `name` as SVG, `size` pixels square (16 to 1024). `options` (or null): `shape` "circle" (the default), "rounded" or "square",/// `background` and `color` as "#rrggbb" to choose them yourself, and `title` false to leave out the tooltip with the name.pub fn avatar_svg(name: &str, size: i64, options: serde_json::Value) -> String { let s = size.clamp(16, 1024); let pick = |k: &str| options.get(k).and_then(Value::as_str).filter(|c| c.starts_with('#') && [4, 7].contains(&c.len()) && c[1..].chars().all(|x| x.is_ascii_hexdigit())).map(str::to_string); let bg = pick("background").unwrap_or_else(|| avatar_color(name)); let fg = pick("color").unwrap_or_else(|| "#ffffff".into()); let initials = avatar_initials(name); let shape = match options.get("shape").and_then(Value::as_str).unwrap_or("circle") { "square" => format!(r#"<rect width="{s}" height="{s}" fill="{bg}"/>"#), "rounded" => format!(r#"<rect width="{s}" height="{s}" rx="{}" fill="{bg}"/>"#, s / 5), _ => format!(r#"<circle cx="{h}" cy="{h}" r="{h}" fill="{bg}"/>"#, h = s as f64 / 2.0), }; let font = if initials.chars().count() > 1 { s as f64 * 0.4 } else { s as f64 * 0.48 }; let title = if options.get("title").and_then(Value::as_bool) == Some(false) { String::new() } else { format!("<title>{}</title>", esc(name.trim())) }; format!(r#"<svg xmlns="http://www.w3.org/2000/svg" width="{s}" height="{s}" viewBox="0 0 {s} {s}" role="img">{title}{shape}<text x="50%" y="50%" dominant-baseline="central" text-anchor="middle" font-family="system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif" font-size="{font:.0}" font-weight="600" fill="{fg}">{}</text></svg>"#, esc(&initials))}Related
identicon.qwer · 1.0.0GitHub-style identicons from any text, as SVG or PNG: a symmetric pattern in a colour of its own, the same text always the same picture.7 views · 7 downloadsAudio waveform audio_wave.qwer · 1.0.0A WAV file's waveform for an audio player: the loudness of each slice from 0 to 1, or drawn as an SVG of bars.6 views · 7 downloadsGraphviz graphviz.qwer · 1.0.0Graphs in Graphviz's DOT language laid out and drawn as SVG, with no Graphviz installed: flowcharts, org charts and state machines.7 views · 8 downloadsPlaceholders placeholder.qwer · 1.0.0Placeholder images as SVG: a box of any size with its dimensions or your text in your colours, as markup or a data: URL.8 views · 8 downloadsQR codes qr.qwer · 1.0.0QR codes as SVG for links, tickets, Wi-Fi and two-factor set-up, in any colours, or drawn as text.10 views · 7 downloadsSparklines sparkline.qwer · 1.0.0Tiny inline charts from a list of numbers: SVG line and bar sparklines for table cells and sentences, and the same in text (▁▃▆█).6 views · 8 downloadsThread 0 posts
On Initials avatars: questions, tips, corrections, and code that uses it.
No posts yet. The first one opens the thread.