leptos_obfuscate/
lib.rs

1// Copyright 2024 Sebastian Dobe <sebastiandobe@mailbox.org>
2
3#![doc = include_str!("../README.md")]
4
5use core::time::Duration;
6use leptos::prelude::*;
7
8/// The component accepts an optional honeypot email address / link you can use, if you want to have a
9/// sophisticated setup and blacklist any sender that sends an E-Mail to it.
10///
11/// The `delay_seconds` can be set as well. After this timeout, when mounted inside the browser,
12/// the honeypot address will be exchanged with the real one. This means the link will not work with
13/// HTML only, but there is no good way to prevent bots without Javascript / WASM.
14///
15/// # Panics
16/// If the given String does not contain '@'
17#[component]
18pub fn ObfuscateEmail(
19    #[prop(into)] email: MaybeProp<String>,
20    #[prop(default = "mailto:honeypot@example.com")] honeypot: &'static str,
21    #[prop(default = 3)] delay_seconds: u64,
22) -> impl IntoView {
23    let mailto = RwSignal::new(honeypot.to_string());
24
25    Effect::new(move |_| {
26        if let Some(real_email) = email.get() {
27            let mail = format!("mailto:{}", real_email);
28            set_timeout(move || mailto.set(mail), Duration::from_secs(delay_seconds));
29        }
30    });
31
32    let one = move || {
33        email.get().and_then(|plain| plain.split_once('@').map(|(one, _)| one.chars().rev().collect::<String>()))
34            .unwrap_or_default()
35    };
36
37    let two = move || {
38        email.get().and_then(|plain| plain.split_once('@').map(|(_, two)| two.chars().rev().collect::<String>()))
39            .unwrap_or_default()
40    };
41
42    view! {
43        <a href=move || mailto.get()>
44            <span aria-label="E-Mail" class="obfuscate">
45                {two}
46                <i>"%/#"</i>
47                <span></span>
48                {one}
49            </span>
50        </a>
51    }
52}
53