summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJustin Wernick <j.wernick@eyeo.com>2021-06-23 21:38:16 +0200
committerJustin Wernick <j.wernick@eyeo.com>2021-06-23 21:38:16 +0200
commit567623ffcc25f6f1ac0df045832cd085e970d6b2 (patch)
treec2551ad03e513ecb214b4b663db68ddd05e330e3
parent9b88c4459120f8e152d92f673597d9d126610fee (diff)
Templating Engine dropdown
-rw-r--r--Cargo.lock19
-rw-r--r--Cargo.toml1
-rw-r--r--css/style.css6
-rw-r--r--src/facebook.rs4
-rw-r--r--src/form.rs16
-rw-r--r--src/lib.rs44
-rw-r--r--src/links.rs51
-rw-r--r--src/telegram.rs7
-rw-r--r--src/twitter.rs7
-rw-r--r--src/whatsapp.rs4
10 files changed, 140 insertions, 19 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 66249cd..1e3ab55 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -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",
diff --git a/Cargo.toml b/Cargo.toml
index 9aa195e..4ae1cc1 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -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()
+ }
+}
diff --git a/src/lib.rs b/src/lib.rs
index ba8bff1..adf9b3e 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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,