diff options
author | Justin Wernick <j.wernick@eyeo.com> | 2021-06-23 21:38:16 +0200 |
---|---|---|
committer | Justin Wernick <j.wernick@eyeo.com> | 2021-06-23 21:38:16 +0200 |
commit | 567623ffcc25f6f1ac0df045832cd085e970d6b2 (patch) | |
tree | c2551ad03e513ecb214b4b663db68ddd05e330e3 | |
parent | 9b88c4459120f8e152d92f673597d9d126610fee (diff) |
Templating Engine dropdown
-rw-r--r-- | Cargo.lock | 19 | ||||
-rw-r--r-- | Cargo.toml | 1 | ||||
-rw-r--r-- | css/style.css | 6 | ||||
-rw-r--r-- | src/facebook.rs | 4 | ||||
-rw-r--r-- | src/form.rs | 16 | ||||
-rw-r--r-- | src/lib.rs | 44 | ||||
-rw-r--r-- | src/links.rs | 51 | ||||
-rw-r--r-- | src/telegram.rs | 7 | ||||
-rw-r--r-- | src/twitter.rs | 7 | ||||
-rw-r--r-- | src/whatsapp.rs | 4 |
10 files changed, 140 insertions, 19 deletions
@@ -108,6 +108,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f92cfa0fd5690b3cf8c1ef2cabbd9b7ef22fa53cf5e1f92b05103f6d5d1cf6e7" [[package]] +name = "convert_case" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" + +[[package]] name = "cookie" version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -137,6 +143,18 @@ dependencies = [ ] [[package]] +name = "derive_more" +version = "0.99.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cc7b9cef1e351660e5443924e4f43ab25fbbed3e9a5f052df3677deb4d6b320" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "syn", +] + +[[package]] name = "discard" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -434,6 +452,7 @@ dependencies = [ name = "no-track-social-links" version = "0.1.0" dependencies = [ + "derive_more", "lazy_static", "seed", "structform", @@ -17,6 +17,7 @@ web-sys = { version = "0.3.47", features = ["Range"] } syntect = { version = "4.5", default-features = false, features = ["default-fancy"], optional = true} lazy_static = "1.4.0" structform = "0.1.0" +derive_more = "0.99" [profile.release] lto = true diff --git a/css/style.css b/css/style.css index 2e8eeee..29b62e3 100644 --- a/css/style.css +++ b/css/style.css @@ -29,6 +29,12 @@ p { text-align: justify; } +label { + min-width: 200px; + display: inline-block; + margin-bottom: 5px; +} + pre { padding: 10px; max-width: 100%; diff --git a/src/facebook.rs b/src/facebook.rs index 06bad4e..c4a99db 100644 --- a/src/facebook.rs +++ b/src/facebook.rs @@ -16,10 +16,10 @@ pub fn icon(color: &str) -> Node<Msg> { } // https://developers.facebook.com/docs/plugins/share-button# -pub fn link(url: &str) -> Node<Msg> { +pub fn link(encoded_url: &str) -> Node<Msg> { let facebook_url = format!( "https://www.facebook.com/sharer/sharer.php?u={}", - Url::encode_uri_component(url) + encoded_url ); let facebook_link = a![ attrs! { diff --git a/src/form.rs b/src/form.rs index b1e023c..e424a28 100644 --- a/src/form.rs +++ b/src/form.rs @@ -1,3 +1,4 @@ +use crate::links::TemplatingEngine; use structform::{derive_form_input, impl_text_input_with_stringops, ParseAndFormat, ParseError}; derive_form_input! {FormTextInput} @@ -14,3 +15,18 @@ impl ParseAndFormat<bool> for FormCheckboxInput<bool> { value.to_string() } } + +derive_form_input! {FormSelectInput} + +impl ParseAndFormat<TemplatingEngine> for FormSelectInput<TemplatingEngine> { + fn parse(value: &str) -> Result<TemplatingEngine, ParseError> { + let trimmed = value.trim(); + trimmed + .parse::<TemplatingEngine>() + .map_err(|e| ParseError::FromStrError(e.to_string())) + } + + fn format(value: &TemplatingEngine) -> String { + value.to_string() + } +} @@ -1,6 +1,7 @@ #![allow(clippy::wildcard_imports)] use crate::form::*; +use links::TemplatingEngine; use seed::{prelude::*, *}; use structform::StructForm; @@ -24,6 +25,7 @@ struct Model { #[derive(Default, Debug)] struct ShareLinksOptions { + template_engine: TemplatingEngine, url: String, facebook: bool, twitter: bool, @@ -34,6 +36,7 @@ struct ShareLinksOptions { #[derive(Default, StructForm)] #[structform(model = "ShareLinksOptions")] struct ShareLinksOptionsForm { + template_engine: FormSelectInput<TemplatingEngine>, url: FormTextInput<String>, facebook: FormCheckboxInput<bool>, twitter: FormCheckboxInput<bool>, @@ -56,11 +59,12 @@ fn update(msg: Msg, model: &mut Model, _: &mut impl Orders<Msg>) { model.links = Vec::new(); } Ok(options) => { + let url = options.template_engine.encode_url(&options.url); let option_links = vec![ - options.facebook.then(|| facebook::link(&options.url)), - options.twitter.then(|| twitter::link(&options.url)), - options.whatsapp.then(|| whatsapp::link(&options.url)), - options.telegram.then(|| telegram::link(&options.url)), + options.facebook.then(|| facebook::link(&url)), + options.twitter.then(|| twitter::link(&url)), + options.whatsapp.then(|| whatsapp::link(&url)), + options.telegram.then(|| telegram::link(&url)), ]; model.links = option_links.into_iter().flatten().collect() } @@ -123,6 +127,31 @@ fn view(model: &Model) -> Node<Msg> { div![ label![ attrs! { + At::For => "template_engine" + }, + "Templating Engine" + ], + select![ + attrs! { + At::Name => "template_engine", + At::Value => model.form.template_engine.input + }, + TemplatingEngine::all_str().into_iter().map(|engine| { + option![ + attrs! { + At::Value => &engine, + At::Selected => (model.form.template_engine.input == engine).as_at_value() + }, + &engine + + ] + }), + input_ev(Ev::Input, |val| Msg::Input(ShareLinksOptionsFormField::TemplateEngine, val) ) + ], + ], + div![ + label![ + attrs! { At::For => "url" }, "URL to share" @@ -130,7 +159,12 @@ fn view(model: &Model) -> Node<Msg> { input![ attrs! { At::Name => "url", - At::Value => model.form.url.input + At::Value => model.form.url.input, + At::Placeholder => match model.form.template_engine.value { + Ok(TemplatingEngine::None) => "https://example.com", + Ok(TemplatingEngine::Jekyll) => "page.url | absolute_url", + Err(_) => "" + } }, input_ev(Ev::Input, |val| Msg::Input(ShareLinksOptionsFormField::Url, val) ) ], diff --git a/src/links.rs b/src/links.rs index 16fce3f..ae1547f 100644 --- a/src/links.rs +++ b/src/links.rs @@ -1,2 +1,53 @@ +use derive_more::Display; +use seed::prelude::Url; +use std::str::FromStr; + pub const SMALL_SHARING_FONT: &'static str = "bold 11px Helvetica, Arial, sans-serif"; pub const LINK_REL: &'static str = "nofollow noopener noreferrer"; + +#[derive(Debug, Display, Clone)] +pub enum TemplatingEngine { + None, + Jekyll, +} + +impl Default for TemplatingEngine { + fn default() -> Self { + Self::None + } +} + +#[derive(Debug, Display)] +pub struct StringError(String); +impl std::error::Error for StringError {} + +impl FromStr for TemplatingEngine { + type Err = StringError; + fn from_str(s: &str) -> Result<Self, Self::Err> { + if s.trim().is_empty() { + return Ok(Self::default()); + } + for candidate in Self::all() { + if s == candidate.to_string() { + return Ok(candidate); + } + } + Err(StringError(format!("{} is not a known templating type", s))) + } +} + +impl TemplatingEngine { + pub fn all() -> Vec<TemplatingEngine> { + vec![Self::None, Self::Jekyll] + } + pub fn all_str() -> Vec<String> { + Self::all().iter().map(ToString::to_string).collect() + } + + pub fn encode_url(&self, url: &str) -> String { + match self { + Self::None => Url::encode_uri_component(url), + Self::Jekyll => format!("{{{{ {} | cgi_escape }}}}", url), + } + } +} diff --git a/src/telegram.rs b/src/telegram.rs index 1d08583..b31db3b 100644 --- a/src/telegram.rs +++ b/src/telegram.rs @@ -16,11 +16,8 @@ pub fn icon(color: &str) -> Node<Msg> { } // https://core.telegram.org/widgets/share -pub fn link(url: &str) -> Node<Msg> { - let telegram_url = format!( - "https://t.me/share/url?url={}", - Url::encode_uri_component(url) - ); +pub fn link(encoded_url: &str) -> Node<Msg> { + let telegram_url = format!("https://t.me/share/url?url={}", encoded_url); let telegram_link = a![ attrs! { At::Href => telegram_url, diff --git a/src/twitter.rs b/src/twitter.rs index 8c1c012..5b95fd2 100644 --- a/src/twitter.rs +++ b/src/twitter.rs @@ -16,11 +16,8 @@ pub fn icon(color: &str) -> Node<Msg> { } // https://developer.twitter.com/en/docs/twitter-for-websites/tweet-button/guides/web-intent -pub fn link(url: &str) -> Node<Msg> { - let twitter_url = format!( - "https://twitter.com/intent/tweet?url={}", - Url::encode_uri_component(url) - ); +pub fn link(encoded_url: &str) -> Node<Msg> { + let twitter_url = format!("https://twitter.com/intent/tweet?url={}", encoded_url); let twitter_link = a![ attrs! { At::Href => twitter_url, diff --git a/src/whatsapp.rs b/src/whatsapp.rs index fc63039..7bf14a5 100644 --- a/src/whatsapp.rs +++ b/src/whatsapp.rs @@ -16,8 +16,8 @@ pub fn icon(color: &str) -> Node<Msg> { } // https://faq.whatsapp.com/general/chats/how-to-use-click-to-chat/?lang=en -pub fn link(url: &str) -> Node<Msg> { - let whatsapp_url = format!("https://wa.me?text={}", Url::encode_uri_component(url)); +pub fn link(encoded_url: &str) -> Node<Msg> { + let whatsapp_url = format!("https://wa.me?text={}", encoded_url); let whatsapp_link = a![ attrs! { At::Href => whatsapp_url, |