add: text and icon plugins (bberry)

This commit is contained in:
trisua 2025-05-31 13:07:34 -04:00
parent 350e47f4b7
commit 7de2c2e935
5 changed files with 78 additions and 38 deletions

4
Cargo.lock generated
View file

@ -339,9 +339,9 @@ dependencies = [
[[package]] [[package]]
name = "bberry" name = "bberry"
version = "0.1.2" version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d73b8674872fdd2eb09463fc9e3d15c4510a3abd8a1f8ef0a9e918065913aed5" checksum = "5ee0ee2ee1f1a6094d77ba1bf5402f8a8d66e77f6353aff728e37249b2e77458"
[[package]] [[package]]
name = "bit_field" name = "bit_field"

View file

@ -48,4 +48,4 @@ async-stripe = { version = "0.41.0", features = [
] } ] }
emojis = "0.6.4" emojis = "0.6.4"
webp = "0.3.0" webp = "0.3.0"
bberry = "0.1.2" bberry = "0.2.0"

View file

@ -1,4 +1,7 @@
use bberry::core::element::Render; use bberry::{
core::element::{Element, Render},
text, read_param,
};
use pathbufd::PathBufD; use pathbufd::PathBufD;
use regex::Regex; use regex::Regex;
use std::{ use std::{
@ -168,7 +171,12 @@ macro_rules! vendor_icon {
/// * icons /// * icons
/// * icons (with class specifier) /// * icons (with class specifier)
/// * l10n text /// * 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<String, Box<dyn FnMut(Element) -> Element>>>,
) -> String {
let reader = HTML_FOOTER.read().await; let reader = HTML_FOOTER.read().await;
if reader.is_empty() { 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 { let mut input = if !lisp {
input.to_string() input.to_string()
} else { } 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("<!-- prettier-ignore -->", ""); input = input.replace("<!-- prettier-ignore -->", "");
@ -243,21 +255,49 @@ pub(crate) async fn replace_in_html(input: &str, config: &Config, lisp: bool) ->
input input
} }
pub(crate) fn lisp_plugins() -> HashMap<String, Box<dyn FnMut(Element) -> 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. /// Set up public directories.
pub(crate) async fn write_assets(config: &Config) -> PathBufD { pub(crate) async fn write_assets(config: &Config) -> PathBufD {
vendor_icon!("spotify", VENDOR_SPOTIFY_ICON, config.dirs.icons); vendor_icon!("spotify", VENDOR_SPOTIFY_ICON, config.dirs.icons);
vendor_icon!("last_fm", VENDOR_LAST_FM_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); 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->"macros.html"(crate::assets::MACROS) --config=config);
write_template!(html_path->"components.html"(crate::assets::COMPONENTS) --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/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->"misc/requests.html"(crate::assets::MISC_REQUESTS) --config=config);
write_template!(html_path->"auth/base.html"(crate::assets::AUTH_BASE) -d "auth" --config=config); write_template!(html_path->"auth/base.html"(crate::assets::AUTH_BASE) -d "auth" --config=config);

View file

@ -7,15 +7,15 @@ macro_rules! write_template {
($into:ident->$path:literal($as:expr) --config=$config:ident) => { ($into:ident->$path:literal($as:expr) --config=$config:ident) => {
std::fs::write( std::fs::write(
$into.join($path), $into.join($path),
$crate::assets::replace_in_html($as, &$config, false).await, $crate::assets::replace_in_html($as, &$config, false, None).await,
) )
.unwrap(); .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( std::fs::write(
$into.join($path), $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(); .unwrap();
}; };
@ -37,12 +37,12 @@ macro_rules! write_template {
std::fs::write( std::fs::write(
$into.join($path), $into.join($path),
$crate::assets::replace_in_html($as, &$config, false).await, $crate::assets::replace_in_html($as, &$config, false, None).await,
) )
.unwrap(); .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); let dir = $into.join($dir_path);
if !std::fs::exists(&dir).unwrap() { if !std::fs::exists(&dir).unwrap() {
std::fs::create_dir(dir).unwrap(); std::fs::create_dir(dir).unwrap();
@ -50,7 +50,7 @@ macro_rules! write_template {
std::fs::write( std::fs::write(
$into.join($path), $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(); .unwrap();
}; };

View file

@ -67,12 +67,12 @@
("class" "card-nest") ("class" "card-nest")
(div (div
("class" "card small flex items-center gap-2 red") ("class" "card small flex items-center gap-2 red")
(text "{{ icon \"frown\" }}") (icon (text "frown"))
(span (text "{{ text \"general:label.account_banned\" }}"))) (str (text "general:label.account_banned")))
(div (div
("class" "card") ("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 ; if we aren't banned, just show the page body
(text "{% else %} {% block body %}{% endblock %} {%- endif %}") (text "{% else %} {% block body %}{% endblock %} {%- endif %}")
@ -150,15 +150,15 @@
("rel" "noopener noreferrer") ("rel" "noopener noreferrer")
("target" "_blank") ("target" "_blank")
("onclick", "document.getElementById('link_filter').close()") ("onclick", "document.getElementById('link_filter').close()")
(text "{{ icon \"external-link\" }}") (icon (text "external-link"))
(span (text "{{ text \"dialog:action.continue\" }}"))) (str (text "dialog:action.continue")))
(button (button
("class" "secondary") ("class" "secondary")
("type" "button") ("type" "button")
("onclick", "document.getElementById('link_filter').close()") ("onclick", "document.getElementById('link_filter').close()")
(text "{{ icon \"x\" }}" ) (icon (text "x"))
(span (text "{{ text \"dialog:action.cancel\" }}")))))) (str (text "dialog:action.cancel"))))))
(dialog (dialog
("id" "web_api_prompt") ("id" "web_api_prompt")
@ -179,15 +179,15 @@
("class" "primary bold circle") ("class" "primary bold circle")
("onclick", "globalThis.web_api_prompt_submit(document.getElementById('prompt').value); document.getElementById('prompt').value = ''") ("onclick", "globalThis.web_api_prompt_submit(document.getElementById('prompt').value); document.getElementById('prompt').value = ''")
("type" "button") ("type" "button")
(text "{{ icon \"check\" }}") (icon (text "check"))
(text "{{ text \"dialog:action.okay\" }}")) (str (text "dialog:action.okay")))
(button (button
("class" "bold red camo") ("class" "bold red camo")
("onclick", "globalThis.web_api_prompt_submit('')") ("onclick", "globalThis.web_api_prompt_submit('')")
("type" "button") ("type" "button")
(text "{{ icon \"x\" }}") (icon (text "x"))
(text "{{ text \"dialog:action.cancel\" }}"))))))) (str (text "dialog:action.cancel"))))))))
(dialog (dialog
("id" "web_api_prompt_long") ("id" "web_api_prompt_long")
@ -208,15 +208,15 @@
("class" "primary bold circle") ("class" "primary bold circle")
("onclick", "globalThis.web_api_prompt_long_submit(document.getElementById('prompt_long').value); document.getElementById('prompt_long').value = ''") ("onclick", "globalThis.web_api_prompt_long_submit(document.getElementById('prompt_long').value); document.getElementById('prompt_long').value = ''")
("type" "button") ("type" "button")
(text "{{ icon \"check\" }}") (icon (text "check"))
(text "{{ text \"dialog:action.okay\" }}")) (str (text "dialog:action.okay")))
(button (button
("class" "bold red camo") ("class" "bold red camo")
("onclick", "globalThis.web_api_prompt_long_submit('')") ("onclick", "globalThis.web_api_prompt_long_submit('')")
("type" "button") ("type" "button")
(text "{{ icon \"x\" }}") (icon (text "x"))
(text "{{ text \"dialog:action.cancel\" }}"))))))) (str (text "dialog:action.cancel"))))))))
(dialog (dialog
("id" "web_api_confirm") ("id" "web_api_confirm")
@ -236,15 +236,15 @@
("class" "primary bold circle") ("class" "primary bold circle")
("onclick", "globalThis.web_api_confirm_submit(true)") ("onclick", "globalThis.web_api_confirm_submit(true)")
("type" "button") ("type" "button")
(text "{{ icon \"check\" }}") (icon (text "check"))
(text "{{ text \"dialog:action.yes\" }}")) (str (text "dialog:action.yes")))
(button (button
("class" "bold red camo") ("class" "bold red camo")
("onclick", "globalThis.web_api_confirm_submit(false)") ("onclick", "globalThis.web_api_confirm_submit(false)")
("type" "button") ("type" "button")
(text "{{ icon \"x\" }}") (icon (text "x"))
(text "{{ text \"dialog:action.no\" }}"))))))) (str (text "dialog:action.no"))))))))
(div (div
("class" "lightbox hidden") ("class" "lightbox hidden")
@ -252,7 +252,7 @@
(button (button
("class" "lightbox_exit small square quaternary red") ("class" "lightbox_exit small square quaternary red")
("onclick" "trigger('ui::lightbox_close')") ("onclick" "trigger('ui::lightbox_close')")
(text "{{ icon \"x\" }}")) (icon (text "x")))
(a (a
("href" "") ("href" "")
@ -274,8 +274,8 @@
("href" "/auth/login") ("href" "/auth/login")
("class" "button") ("class" "button")
("data-turbo", "false") ("data-turbo", "false")
(text "{{ icon \"plus\" }}") (icon (text "plus"))
(span (text "{{ text \"general:action.add_account\" }}"))) (span (str (text "general:action.add_account"))))
(div (div
("class" "flex justify-between") ("class" "flex justify-between")
@ -287,7 +287,7 @@
("class" "quaternary") ("class" "quaternary")
("onclick" "document.getElementById('tokens_dialog').close()") ("onclick" "document.getElementById('tokens_dialog').close()")
("type" "button") ("type" "button")
(text "{{ icon \"check \" }}") (icon (text "check "))
(span "{{ text \"dialog:action.okay\" }}"))))))) (span "{{ text \"dialog:action.okay\" }}")))))))
; user scripts ; user scripts