From 7de2c2e935e9059ac7e10d22538850b980b0df3c Mon Sep 17 00:00:00 2001 From: trisua Date: Sat, 31 May 2025 13:07:34 -0400 Subject: [PATCH] add: text and icon plugins (bberry) --- Cargo.lock | 4 +-- crates/app/Cargo.toml | 2 +- crates/app/src/assets.rs | 52 ++++++++++++++++++++++++---- crates/app/src/macros.rs | 12 +++---- crates/app/src/public/html/root.lisp | 46 ++++++++++++------------ 5 files changed, 78 insertions(+), 38 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f666c06..24a871b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -339,9 +339,9 @@ dependencies = [ [[package]] name = "bberry" -version = "0.1.2" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d73b8674872fdd2eb09463fc9e3d15c4510a3abd8a1f8ef0a9e918065913aed5" +checksum = "5ee0ee2ee1f1a6094d77ba1bf5402f8a8d66e77f6353aff728e37249b2e77458" [[package]] name = "bit_field" diff --git a/crates/app/Cargo.toml b/crates/app/Cargo.toml index 117a1cb..80eeaa4 100644 --- a/crates/app/Cargo.toml +++ b/crates/app/Cargo.toml @@ -48,4 +48,4 @@ async-stripe = { version = "0.41.0", features = [ ] } emojis = "0.6.4" webp = "0.3.0" -bberry = "0.1.2" +bberry = "0.2.0" diff --git a/crates/app/src/assets.rs b/crates/app/src/assets.rs index 121e3a3..80f74b8 100644 --- a/crates/app/src/assets.rs +++ b/crates/app/src/assets.rs @@ -1,4 +1,7 @@ -use bberry::core::element::Render; +use bberry::{ + core::element::{Element, Render}, + text, read_param, +}; use pathbufd::PathBufD; use regex::Regex; use std::{ @@ -168,7 +171,12 @@ macro_rules! vendor_icon { /// * icons /// * icons (with class specifier) /// * l10n text -pub(crate) async fn replace_in_html(input: &str, config: &Config, lisp: bool) -> String { +pub(crate) async fn replace_in_html( + input: &str, + config: &Config, + lisp: bool, + plugins: Option<&mut HashMap Element>>>, +) -> String { let reader = HTML_FOOTER.read().await; if reader.is_empty() { @@ -190,7 +198,11 @@ pub(crate) async fn replace_in_html(input: &str, config: &Config, lisp: bool) -> let mut input = if !lisp { input.to_string() } else { - bberry::parse(input).0.render() + if let Some(plugins) = plugins { + bberry::parse(input).render(plugins) + } else { + bberry::parse(input).render_safe() + } }; input = input.replace("", ""); @@ -243,21 +255,49 @@ pub(crate) async fn replace_in_html(input: &str, config: &Config, lisp: bool) -> input } +pub(crate) fn lisp_plugins() -> HashMap Element>> { + let mut plugins = HashMap::new(); + + plugins.insert( + "icon".to_string(), + Box::new(|e: Element| text!(format!("{{{{ icon \"{}\" }}}}", read_param!(e, 0)))) as _, + ); + + plugins.insert( + "icon_class".to_string(), + Box::new(|e: Element| { + text!(format!( + "{{{{ icon \"{}\" c({}) }}}}", + read_param!(e, 0), + read_param!(e, 1) + )) + }) as _, + ); + + plugins.insert( + "str".to_string(), + Box::new(|e: Element| text!(format!("{{{{ text \"{}\" }}}}", read_param!(e, 0)))) as _, + ); + + plugins +} + /// Set up public directories. pub(crate) async fn write_assets(config: &Config) -> PathBufD { vendor_icon!("spotify", VENDOR_SPOTIFY_ICON, config.dirs.icons); vendor_icon!("last_fm", VENDOR_LAST_FM_ICON, config.dirs.icons); // ... + let mut plugins = lisp_plugins(); let html_path = PathBufD::current().join(&config.dirs.templates); - write_template!(html_path->"root.html"(crate::assets::ROOT) --config=config --lisp); + write_template!(html_path->"root.html"(crate::assets::ROOT) --config=config --lisp plugins); write_template!(html_path->"macros.html"(crate::assets::MACROS) --config=config); write_template!(html_path->"components.html"(crate::assets::COMPONENTS) --config=config); - write_template!(html_path->"misc/error.html"(crate::assets::MISC_ERROR) -d "misc" --config=config --lisp); + write_template!(html_path->"misc/error.html"(crate::assets::MISC_ERROR) -d "misc" --config=config --lisp plugins); write_template!(html_path->"misc/notifications.html"(crate::assets::MISC_NOTIFICATIONS) --config=config); - write_template!(html_path->"misc/markdown.html"(crate::assets::MISC_MARKDOWN) --config=config --lisp); + write_template!(html_path->"misc/markdown.html"(crate::assets::MISC_MARKDOWN) --config=config --lisp plugins); write_template!(html_path->"misc/requests.html"(crate::assets::MISC_REQUESTS) --config=config); write_template!(html_path->"auth/base.html"(crate::assets::AUTH_BASE) -d "auth" --config=config); diff --git a/crates/app/src/macros.rs b/crates/app/src/macros.rs index 850bd7d..ce50221 100644 --- a/crates/app/src/macros.rs +++ b/crates/app/src/macros.rs @@ -7,15 +7,15 @@ macro_rules! write_template { ($into:ident->$path:literal($as:expr) --config=$config:ident) => { std::fs::write( $into.join($path), - $crate::assets::replace_in_html($as, &$config, false).await, + $crate::assets::replace_in_html($as, &$config, false, None).await, ) .unwrap(); }; - ($into:ident->$path:literal($as:expr) --config=$config:ident --lisp) => { + ($into:ident->$path:literal($as:expr) --config=$config:ident --lisp $plugins:ident) => { std::fs::write( $into.join($path), - $crate::assets::replace_in_html($as, &$config, true).await, + $crate::assets::replace_in_html($as, &$config, true, Some(&mut $plugins)).await, ) .unwrap(); }; @@ -37,12 +37,12 @@ macro_rules! write_template { std::fs::write( $into.join($path), - $crate::assets::replace_in_html($as, &$config, false).await, + $crate::assets::replace_in_html($as, &$config, false, None).await, ) .unwrap(); }; - ($into:ident->$path:literal($as:expr) -d $dir_path:literal --config=$config:ident --lisp) => { + ($into:ident->$path:literal($as:expr) -d $dir_path:literal --config=$config:ident --lisp $plugins:ident) => { let dir = $into.join($dir_path); if !std::fs::exists(&dir).unwrap() { std::fs::create_dir(dir).unwrap(); @@ -50,7 +50,7 @@ macro_rules! write_template { std::fs::write( $into.join($path), - $crate::assets::replace_in_html($as, &$config, true).await, + $crate::assets::replace_in_html($as, &$config, true, Some(&mut $plugins)).await, ) .unwrap(); }; diff --git a/crates/app/src/public/html/root.lisp b/crates/app/src/public/html/root.lisp index d83d92a..d0bb151 100644 --- a/crates/app/src/public/html/root.lisp +++ b/crates/app/src/public/html/root.lisp @@ -67,12 +67,12 @@ ("class" "card-nest") (div ("class" "card small flex items-center gap-2 red") - (text "{{ icon \"frown\" }}") - (span (text "{{ text \"general:label.account_banned\" }}"))) + (icon (text "frown")) + (str (text "general:label.account_banned"))) (div ("class" "card") - (span (text "{{ text \"general:label.account_banned_body\" }}")))))) + (str (text "general:label.account_banned_body")))))) ; if we aren't banned, just show the page body (text "{% else %} {% block body %}{% endblock %} {%- endif %}") @@ -150,15 +150,15 @@ ("rel" "noopener noreferrer") ("target" "_blank") ("onclick", "document.getElementById('link_filter').close()") - (text "{{ icon \"external-link\" }}") - (span (text "{{ text \"dialog:action.continue\" }}"))) + (icon (text "external-link")) + (str (text "dialog:action.continue"))) (button ("class" "secondary") ("type" "button") ("onclick", "document.getElementById('link_filter').close()") - (text "{{ icon \"x\" }}" ) - (span (text "{{ text \"dialog:action.cancel\" }}")))))) + (icon (text "x")) + (str (text "dialog:action.cancel")))))) (dialog ("id" "web_api_prompt") @@ -179,15 +179,15 @@ ("class" "primary bold circle") ("onclick", "globalThis.web_api_prompt_submit(document.getElementById('prompt').value); document.getElementById('prompt').value = ''") ("type" "button") - (text "{{ icon \"check\" }}") - (text "{{ text \"dialog:action.okay\" }}")) + (icon (text "check")) + (str (text "dialog:action.okay"))) (button ("class" "bold red camo") ("onclick", "globalThis.web_api_prompt_submit('')") ("type" "button") - (text "{{ icon \"x\" }}") - (text "{{ text \"dialog:action.cancel\" }}"))))))) + (icon (text "x")) + (str (text "dialog:action.cancel")))))))) (dialog ("id" "web_api_prompt_long") @@ -208,15 +208,15 @@ ("class" "primary bold circle") ("onclick", "globalThis.web_api_prompt_long_submit(document.getElementById('prompt_long').value); document.getElementById('prompt_long').value = ''") ("type" "button") - (text "{{ icon \"check\" }}") - (text "{{ text \"dialog:action.okay\" }}")) + (icon (text "check")) + (str (text "dialog:action.okay"))) (button ("class" "bold red camo") ("onclick", "globalThis.web_api_prompt_long_submit('')") ("type" "button") - (text "{{ icon \"x\" }}") - (text "{{ text \"dialog:action.cancel\" }}"))))))) + (icon (text "x")) + (str (text "dialog:action.cancel")))))))) (dialog ("id" "web_api_confirm") @@ -236,15 +236,15 @@ ("class" "primary bold circle") ("onclick", "globalThis.web_api_confirm_submit(true)") ("type" "button") - (text "{{ icon \"check\" }}") - (text "{{ text \"dialog:action.yes\" }}")) + (icon (text "check")) + (str (text "dialog:action.yes"))) (button ("class" "bold red camo") ("onclick", "globalThis.web_api_confirm_submit(false)") ("type" "button") - (text "{{ icon \"x\" }}") - (text "{{ text \"dialog:action.no\" }}"))))))) + (icon (text "x")) + (str (text "dialog:action.no")))))))) (div ("class" "lightbox hidden") @@ -252,7 +252,7 @@ (button ("class" "lightbox_exit small square quaternary red") ("onclick" "trigger('ui::lightbox_close')") - (text "{{ icon \"x\" }}")) + (icon (text "x"))) (a ("href" "") @@ -274,8 +274,8 @@ ("href" "/auth/login") ("class" "button") ("data-turbo", "false") - (text "{{ icon \"plus\" }}") - (span (text "{{ text \"general:action.add_account\" }}"))) + (icon (text "plus")) + (span (str (text "general:action.add_account")))) (div ("class" "flex justify-between") @@ -287,7 +287,7 @@ ("class" "quaternary") ("onclick" "document.getElementById('tokens_dialog').close()") ("type" "button") - (text "{{ icon \"check \" }}") + (icon (text "check ")) (span "{{ text \"dialog:action.okay\" }}"))))))) ; user scripts