597 lines
24 KiB
Rust
597 lines
24 KiB
Rust
use crate::markdown::is_numeric;
|
|
use serde::{Deserialize, Serialize};
|
|
use serde_valid::Validate;
|
|
use std::fmt::Display;
|
|
|
|
#[derive(Serialize, Deserialize)]
|
|
pub struct Entry {
|
|
pub slug: String,
|
|
pub edit_code: String,
|
|
pub salt: String,
|
|
pub created: usize,
|
|
pub edited: usize,
|
|
pub content: String,
|
|
#[serde(default)]
|
|
pub metadata: String,
|
|
/// The IP address of the last editor of the entry.
|
|
#[serde(default)]
|
|
pub last_edit_from: String,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, PartialEq, Eq)]
|
|
pub enum RecommendedTheme {
|
|
#[serde(alias = "none")]
|
|
None,
|
|
#[serde(alias = "light")]
|
|
Light,
|
|
#[serde(alias = "dark")]
|
|
Dark,
|
|
}
|
|
|
|
impl Default for RecommendedTheme {
|
|
fn default() -> Self {
|
|
Self::None
|
|
}
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, PartialEq, Eq)]
|
|
pub enum TextAlignment {
|
|
#[serde(alias = "left")]
|
|
Left,
|
|
#[serde(alias = "center")]
|
|
Center,
|
|
#[serde(alias = "right")]
|
|
Right,
|
|
#[serde(alias = "justify")]
|
|
Justify,
|
|
}
|
|
|
|
impl Default for TextAlignment {
|
|
fn default() -> Self {
|
|
Self::Left
|
|
}
|
|
}
|
|
|
|
impl Display for TextAlignment {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
f.write_str(match self {
|
|
Self::Left => "left",
|
|
Self::Center => "center",
|
|
Self::Right => "right",
|
|
Self::Justify => "justify",
|
|
})
|
|
}
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Validate, Default)]
|
|
pub struct EntryMetadata {
|
|
/// The title of the page.
|
|
#[serde(default, alias = "PAGE_TITLE")]
|
|
#[validate(max_length = 128)]
|
|
pub page_title: String,
|
|
/// The description of the page.
|
|
#[serde(default, alias = "PAGE_DESCRIPTION")]
|
|
#[validate(max_length = 256)]
|
|
pub page_description: String,
|
|
/// The favicon of the page.
|
|
#[serde(default, alias = "PAGE_ICON")]
|
|
#[validate(max_length = 128)]
|
|
pub page_icon: String,
|
|
/// The title of the page shown in external embeds.
|
|
#[serde(default, alias = "SHARE_TITLE")]
|
|
#[validate(max_length = 128)]
|
|
pub share_title: String,
|
|
/// The description of the page shown in external embeds.
|
|
#[serde(default, alias = "SHARE_DESCRIPTION")]
|
|
#[validate(max_length = 256)]
|
|
pub share_description: String,
|
|
/// The image shown in external embeds.
|
|
#[serde(default, alias = "SHARE_IMAGE")]
|
|
#[validate(max_length = 128)]
|
|
pub share_image: String,
|
|
/// If views are counted and shown for this entry.
|
|
#[serde(default, alias = "OPTION_DISABLE_VIEWS")]
|
|
pub option_disable_views: bool,
|
|
/// If this entry shows up in search engines.
|
|
#[serde(default, alias = "OPTION_DISABLE_SEARCH_ENGINE")]
|
|
pub option_disable_search_engine: bool,
|
|
/// The theme that is automatically used when this entry is viewed.
|
|
#[serde(default, alias = "ACCESS_RECOMMENDED_THEME")]
|
|
pub access_recommended_theme: RecommendedTheme,
|
|
/// The slug of the easy-to-read (no metadata) version of this entry.
|
|
///
|
|
/// Should not begin with "/".
|
|
#[serde(default, alias = "ACCESS_EASY_READ")]
|
|
#[validate(max_length = 32)]
|
|
pub access_easy_read: String,
|
|
/// The padding of the container.
|
|
///
|
|
/// Syntax: <https://developer.mozilla.org/en-US/docs/Web/CSS/padding>
|
|
#[serde(default, alias = "CONTAINER_PADDING")]
|
|
#[validate(max_length = 32)]
|
|
pub container_padding: String,
|
|
/// The maximum width of the container.
|
|
///
|
|
/// Syntax: <https://developer.mozilla.org/en-US/docs/Web/CSS/max-width>
|
|
#[serde(default, alias = "CONTAINER_MAX_WIDTH")]
|
|
#[validate(max_length = 16)]
|
|
pub container_max_width: String,
|
|
/// The padding of the container.
|
|
/// The color of the text in the inner container.
|
|
#[serde(default, alias = "CONTAINER_INNER_FOREGROUND_COLOR")]
|
|
#[validate(max_length = 32)]
|
|
pub container_inner_foreground_color: String,
|
|
/// The background of the inner container.
|
|
///
|
|
/// Syntax: <https://developer.mozilla.org/en-US/docs/Web/CSS/background>
|
|
#[serde(default, alias = "CONTAINER_INNER_BACKGROUND")]
|
|
#[validate(max_length = 256)]
|
|
pub container_inner_background: String,
|
|
/// The background of the inner container.
|
|
///
|
|
/// Syntax: <https://developer.mozilla.org/en-US/docs/Web/CSS/background-color>
|
|
#[serde(default, alias = "CONTAINER_INNER_BACKGROUND_COLOR")]
|
|
#[validate(max_length = 32)]
|
|
pub container_inner_background_color: String,
|
|
/// The background of the inner container.
|
|
///
|
|
/// Syntax: <https://developer.mozilla.org/en-US/docs/Web/CSS/background-image>
|
|
#[serde(default, alias = "CONTAINER_INNER_BACKGROUND_IMAGE")]
|
|
#[validate(max_length = 128)]
|
|
pub container_inner_background_image: String,
|
|
/// The background of the inner container.
|
|
///
|
|
/// Syntax: <https://developer.mozilla.org/en-US/docs/Web/CSS/background-repeat>
|
|
#[serde(default, alias = "CONTAINER_INNER_BACKGROUND_IMAGE_REPEAT")]
|
|
#[validate(max_length = 16)]
|
|
pub container_inner_background_image_repeat: String,
|
|
/// The background of the inner container.
|
|
///
|
|
/// Syntax: <https://developer.mozilla.org/en-US/docs/Web/CSS/background-position>
|
|
#[serde(default, alias = "CONTAINER_INNER_BACKGROUND_IMAGE_POSITION")]
|
|
#[validate(max_length = 16)]
|
|
pub container_inner_background_image_position: String,
|
|
/// The background of the inner container.
|
|
///
|
|
/// Syntax: <https://developer.mozilla.org/en-US/docs/Web/CSS/background-size>
|
|
#[serde(default, alias = "CONTAINER_INNER_BACKGROUND_IMAGE_SIZE")]
|
|
#[validate(max_length = 16)]
|
|
pub container_inner_background_image_size: String,
|
|
/// The color of the text in the outer container.
|
|
#[serde(default, alias = "CONTAINER_OUTER_FOREGROUND_COLOR")]
|
|
#[validate(max_length = 32)]
|
|
pub container_outer_foreground_color: String,
|
|
/// The background of the outer container.
|
|
///
|
|
/// Syntax: <https://developer.mozilla.org/en-US/docs/Web/CSS/background>
|
|
#[serde(default, alias = "CONTAINER_OUTER_BACKGROUND")]
|
|
#[validate(max_length = 256)]
|
|
pub container_outer_background: String,
|
|
/// The background of the outer container.
|
|
///
|
|
/// Syntax: <https://developer.mozilla.org/en-US/docs/Web/CSS/background-color>
|
|
#[serde(default, alias = "CONTAINER_OUTER_BACKGROUND_COLOR")]
|
|
#[validate(max_length = 32)]
|
|
pub container_outer_background_color: String,
|
|
/// The background of the outer container.
|
|
///
|
|
/// Syntax: <https://developer.mozilla.org/en-US/docs/Web/CSS/background-image>
|
|
#[serde(default, alias = "CONTAINER_OUTER_BACKGROUND_IMAGE")]
|
|
#[validate(max_length = 128)]
|
|
pub container_outer_background_image: String,
|
|
/// The background of the outer container.
|
|
///
|
|
/// Syntax: <https://developer.mozilla.org/en-US/docs/Web/CSS/background-repeat>
|
|
#[serde(default, alias = "CONTAINER_OUTER_BACKGROUND_IMAGE_REPEAT")]
|
|
#[validate(max_length = 16)]
|
|
pub container_outer_background_image_repeat: String,
|
|
/// The background of the outer container.
|
|
///
|
|
/// Syntax: <https://developer.mozilla.org/en-US/docs/Web/CSS/background-position>
|
|
#[serde(default, alias = "CONTAINER_OUTER_BACKGROUND_IMAGE_POSITION")]
|
|
#[validate(max_length = 16)]
|
|
pub container_outer_background_image_position: String,
|
|
/// The background of the outer container.
|
|
///
|
|
/// Syntax: <https://developer.mozilla.org/en-US/docs/Web/CSS/background-size>
|
|
#[serde(default, alias = "CONTAINER_OUTER_BACKGROUND_IMAGE_SIZE")]
|
|
#[validate(max_length = 16)]
|
|
pub container_outer_background_image_size: String,
|
|
/// The border around the container.
|
|
///
|
|
/// Syntax: <https://developer.mozilla.org/en-US/docs/Web/CSS/border>
|
|
#[serde(default, alias = "CONTAINER_BORDER")]
|
|
#[validate(max_length = 256)]
|
|
pub container_border: String,
|
|
/// The border around the container.
|
|
///
|
|
/// Syntax: <https://developer.mozilla.org/en-US/docs/Web/CSS/border-image>
|
|
#[serde(default, alias = "CONTAINER_BORDER_IMAGE")]
|
|
#[validate(max_length = 128)]
|
|
pub container_border_image: String,
|
|
/// The border around the container.
|
|
///
|
|
/// Syntax: <https://developer.mozilla.org/en-US/docs/Web/CSS/border-image-slice>
|
|
#[serde(default, alias = "CONTAINER_BORDER_IMAGE_SLICE")]
|
|
#[validate(max_length = 16)]
|
|
pub container_border_image_slice: String,
|
|
/// The border around the container.
|
|
///
|
|
/// Syntax: <https://developer.mozilla.org/en-US/docs/Web/CSS/border-image-width>
|
|
#[serde(default, alias = "CONTAINER_BORDER_IMAGE_WIDTH")]
|
|
#[validate(max_length = 16)]
|
|
pub container_border_image_width: String,
|
|
/// The border around the container.
|
|
///
|
|
/// Syntax: <https://developer.mozilla.org/en-US/docs/Web/CSS/border-image-outset>
|
|
#[serde(default, alias = "CONTAINER_BORDER_IMAGE_OUTSET")]
|
|
#[validate(max_length = 32)]
|
|
pub container_border_image_outset: String,
|
|
/// The border around the container.
|
|
///
|
|
/// Syntax: <https://developer.mozilla.org/en-US/docs/Web/CSS/border-image-repeat>
|
|
#[serde(default, alias = "CONTAINER_BORDER_IMAGE_REPEAT")]
|
|
#[validate(max_length = 16)]
|
|
pub container_border_image_repeat: String,
|
|
/// The border around the container.
|
|
///
|
|
/// Syntax: <https://developer.mozilla.org/en-US/docs/Web/CSS/border-color>
|
|
#[serde(default, alias = "CONTAINER_BORDER_COLOR")]
|
|
#[validate(max_length = 32)]
|
|
pub container_border_color: String,
|
|
/// The border around the container.
|
|
///
|
|
/// Syntax: <https://developer.mozilla.org/en-US/docs/Web/CSS/border-width>
|
|
#[serde(default, alias = "CONTAINER_BORDER_WIDTH")]
|
|
#[validate(max_length = 16)]
|
|
pub container_border_width: String,
|
|
/// The border around the container.
|
|
///
|
|
/// Syntax: <https://developer.mozilla.org/en-US/docs/Web/CSS/border-style>
|
|
#[serde(default, alias = "CONTAINER_BORDER_STYLE")]
|
|
#[validate(max_length = 16)]
|
|
pub container_border_style: String,
|
|
/// The border around the container.
|
|
///
|
|
/// Syntax: <https://developer.mozilla.org/en-US/docs/Web/CSS/border-radius>
|
|
#[serde(default, alias = "CONTAINER_BORDER_RADIUS")]
|
|
#[validate(max_length = 16)]
|
|
pub container_border_radius: String,
|
|
/// The shadow around the container.
|
|
///
|
|
/// Syntax: <https://developer.mozilla.org/en-US/docs/Web/CSS/box-shadow>
|
|
#[serde(default, alias = "CONTAINER_SHADOW")]
|
|
#[validate(max_length = 32)]
|
|
pub container_shadow: String,
|
|
/// If the container is a flexbox.
|
|
#[serde(default, alias = "CONTAINER_FLEX")]
|
|
pub container_flex: bool,
|
|
/// The direction of the container's content (if container has flex enabled).
|
|
#[serde(default, alias = "CONTAINER_FLEX_DIRECTION")]
|
|
#[validate(max_length = 16)]
|
|
pub container_flex_direction: String,
|
|
/// The gap of the container's content (if container has flex enabled).
|
|
///
|
|
/// Syntax: <https://developer.mozilla.org/en-US/docs/Web/CSS/gap>
|
|
#[serde(default, alias = "CONTAINER_FLEX_GAP")]
|
|
#[validate(max_length = 16)]
|
|
pub container_flex_gap: String,
|
|
/// If the container's content wraps (if container has flex enabled).
|
|
///
|
|
/// Syntax: <https://developer.mozilla.org/en-US/docs/Web/CSS/flex-wrap>
|
|
#[serde(default, alias = "CONTAINER_FLEX_WRAP")]
|
|
pub container_flex_wrap: bool,
|
|
/// The alignment of the container's content horizontally (if container has flex enabled).
|
|
///
|
|
/// Swapped to vertical when direction is `column*`.
|
|
///
|
|
/// Syntax: <https://developer.mozilla.org/en-US/docs/Web/CSS/justify-content>
|
|
#[serde(default, alias = "CONTAINER_FLEX_ALIGN_HORIZONTAL")]
|
|
#[validate(max_length = 16)]
|
|
pub container_flex_align_horizontal: String,
|
|
/// The alignment of the container's content vertically (if container has flex enabled).
|
|
///
|
|
/// Swapped to horizontal when direction is `column*`.
|
|
///
|
|
/// Syntax: <https://developer.mozilla.org/en-US/docs/Web/CSS/align-items>
|
|
#[serde(default, alias = "CONTAINER_FLEX_ALIGN_VERTICAL")]
|
|
#[validate(max_length = 16)]
|
|
pub container_flex_align_vertical: String,
|
|
/// The shadow under text.
|
|
///
|
|
/// Syntax: <https://developer.mozilla.org/en-US/docs/Web/CSS/text-shadow>
|
|
#[serde(default, alias = "CONTENT_TEXT_SHADOW")]
|
|
#[validate(max_length = 32)]
|
|
pub content_text_shadow: String,
|
|
/// The shadow under text.
|
|
///
|
|
/// Syntax: <https://developer.mozilla.org/en-US/docs/Web/CSS/text-shadow>
|
|
#[serde(default, alias = "CONTENT_TEXT_SHADOW_COLOR")]
|
|
#[validate(max_length = 32)]
|
|
pub content_text_shadow_color: String,
|
|
/// The shadow under text.
|
|
///
|
|
/// Syntax: <https://developer.mozilla.org/en-US/docs/Web/CSS/text-shadow>
|
|
#[serde(default, alias = "CONTENT_TEXT_SHADOW_OFFSET")]
|
|
#[validate(max_length = 32)]
|
|
pub content_text_shadow_offset: String,
|
|
/// The shadow under text.
|
|
///
|
|
/// Syntax: <https://developer.mozilla.org/en-US/docs/Web/CSS/text-shadow>
|
|
#[serde(default, alias = "CONTENT_TEXT_SHADOW_BLUR")]
|
|
#[validate(max_length = 32)]
|
|
pub content_text_shadow_blur: String,
|
|
/// The name of a font from Google Fonts to use.
|
|
#[serde(default, alias = "CONTENT_FONT")]
|
|
#[validate(max_length = 32)]
|
|
pub content_font: String,
|
|
/// The weight to use for the body text.
|
|
#[serde(default, alias = "CONTENT_FONT_WEIGHT")]
|
|
pub content_font_weight: u32,
|
|
/// The text size of elements by element tag.
|
|
///
|
|
/// # Example
|
|
/// ```toml
|
|
/// # ...
|
|
/// content_text_size = [["h1", "16px"]]
|
|
/// ```
|
|
#[serde(default, alias = "CONTENT_TEXT_SIZE")]
|
|
pub content_text_size: Vec<(String, String)>,
|
|
/// The default text alignment.
|
|
#[serde(default, alias = "CONTENT_TEXT_ALIGN")]
|
|
pub content_text_align: TextAlignment,
|
|
/// The color of links.
|
|
#[serde(default, alias = "CONTENT_LINK_COLOR")]
|
|
pub content_link_color: String,
|
|
/// If paragraph elements have a margin below them.
|
|
#[serde(default, alias = "CONTENT_DISABLE_PARAGRAPH_MARGIN")]
|
|
pub content_disable_paragraph_margin: bool,
|
|
}
|
|
|
|
macro_rules! metadata_css {
|
|
($selector:literal, $property:literal, $self:ident.$field:ident->$output:ident) => {
|
|
if !$self.$field.is_empty() {
|
|
$output.push_str(&format!(
|
|
"{} {{ {}: {}; }}\n",
|
|
$selector,
|
|
$property,
|
|
EntryMetadata::css_escape(&$self.$field)
|
|
));
|
|
}
|
|
};
|
|
|
|
($selector:literal, $property:literal !important, $self:ident.$field:ident->$output:ident) => {
|
|
if !$self.$field.is_empty() {
|
|
$output.push_str(&format!(
|
|
"{} {{ {}: {} !important; }}\n",
|
|
$selector,
|
|
$property,
|
|
EntryMetadata::css_escape(&$self.$field)
|
|
));
|
|
}
|
|
};
|
|
|
|
($selector:literal, $property:literal, $format:literal, $self:ident.$field:ident->$output:ident) => {
|
|
if !$self.$field.is_empty() {
|
|
$output.push_str(&format!(
|
|
"{} {{ {}: {}; }}\n",
|
|
$selector,
|
|
$property,
|
|
format!($format, EntryMetadata::css_escape(&$self.$field))
|
|
));
|
|
}
|
|
};
|
|
}
|
|
|
|
impl EntryMetadata {
|
|
pub fn head_tags(&self) -> String {
|
|
let mut output = String::new();
|
|
|
|
if !self.page_title.is_empty() {
|
|
output.push_str(&format!("<title>{}</title>", self.page_title));
|
|
}
|
|
|
|
if !self.page_description.is_empty() {
|
|
output.push_str(&format!(
|
|
"<meta name=\"description\" content=\"{}\" />",
|
|
self.page_description.replace("\"", "\\\"")
|
|
));
|
|
}
|
|
|
|
if !self.page_icon.is_empty() {
|
|
output.push_str(&format!(
|
|
"<link rel=\"icon\" href=\"{}\" />",
|
|
self.page_icon.replace("\"", "\\\"")
|
|
));
|
|
}
|
|
|
|
if !self.share_title.is_empty() {
|
|
output.push_str(&format!(
|
|
"<meta property=\"og:title\" content=\"{}\" /><meta property=\"twitter:title\" content=\"{}\" />",
|
|
self.share_title.replace("\"", "\\\""),
|
|
self.share_title.replace("\"", "\\\"")
|
|
));
|
|
}
|
|
|
|
if !self.share_description.is_empty() {
|
|
output.push_str(&format!(
|
|
"<meta property=\"og:description\" content=\"{}\" /><meta property=\"twitter:description\" content=\"{}\" />",
|
|
self.share_description.replace("\"", "\\\""),
|
|
self.share_description.replace("\"", "\\\"")
|
|
));
|
|
}
|
|
|
|
if !self.share_image.is_empty() {
|
|
output.push_str(&format!(
|
|
"<meta property=\"og:image\" content=\"{}\" /><meta property=\"twitter:image\" content=\"{}\" />",
|
|
self.share_image.replace("\"", "\\\""),
|
|
self.share_image.replace("\"", "\\\"")
|
|
));
|
|
}
|
|
|
|
if !self.content_font.is_empty() {
|
|
output.push_str(&format!(
|
|
"<link rel=\"preconnect\" href=\"https://fonts.googleapis.com\">
|
|
<link rel=\"preconnect\" href=\"https://fonts.gstatic.com\" crossorigin>
|
|
<link href=\"https://fonts.googleapis.com/css2?family={}&display=swap\" rel=\"stylesheet\">",
|
|
self.content_font.replace(" ", "+").replace("_", "+"),
|
|
));
|
|
}
|
|
|
|
output
|
|
}
|
|
|
|
pub fn css_escape(input: &str) -> String {
|
|
input.replace("}", "").replace(";", "").replace("/*", "")
|
|
}
|
|
|
|
pub fn css(&self) -> String {
|
|
let mut output = "<style>".to_string();
|
|
|
|
metadata_css!(".container", "padding", self.container_padding->output);
|
|
metadata_css!(".container", "max-width", self.container_max_width->output);
|
|
metadata_css!(".container", "color", self.container_inner_foreground_color->output);
|
|
metadata_css!(".container", "background", self.container_inner_background->output);
|
|
metadata_css!(".container", "background-color", self.container_inner_background_color->output);
|
|
metadata_css!(".container", "background-image", "url('{}')", self.container_inner_background_image->output);
|
|
metadata_css!(".container", "background-repeat", self.container_inner_background_image_repeat->output);
|
|
metadata_css!(".container", "background-position", self.container_inner_background_image_position->output);
|
|
metadata_css!(".container", "background-size", self.container_inner_background_image_size->output);
|
|
metadata_css!("body", "color", self.container_outer_foreground_color->output);
|
|
metadata_css!("body", "background", self.container_outer_background->output);
|
|
metadata_css!("body", "background-color", self.container_outer_background_color->output);
|
|
metadata_css!("body", "background-image", "url('{}')", self.container_outer_background_image->output);
|
|
metadata_css!("body", "background-repeat", self.container_outer_background_image_repeat->output);
|
|
metadata_css!("body", "background-position", self.container_outer_background_image_position->output);
|
|
metadata_css!("body", "background-size", self.container_outer_background_image_size->output);
|
|
metadata_css!(".container", "border", self.container_border->output);
|
|
metadata_css!(".container", "border-image", "url('{}')", self.container_border_image->output);
|
|
metadata_css!(".container", "border-image-slice", self.container_border_image_slice->output);
|
|
metadata_css!(".container", "border-image-repeat", self.container_border_image_repeat->output);
|
|
metadata_css!(".container", "border-image-outset", self.container_border_image_outset->output);
|
|
metadata_css!(".container", "border-image-width", self.container_border_image_width->output);
|
|
metadata_css!(".container", "border-color", self.container_border_color->output);
|
|
metadata_css!(".container", "border-style", self.container_border_style->output);
|
|
metadata_css!(".container", "border-width", self.container_border_width->output);
|
|
metadata_css!(".container", "border-radius", self.container_border_radius->output);
|
|
metadata_css!(".container", "box-shadow", self.container_shadow->output);
|
|
metadata_css!(".container", "text-shadow", self.content_text_shadow->output);
|
|
metadata_css!("*, html *", "--color-link" !important, self.content_link_color->output);
|
|
|
|
if self.content_text_align != TextAlignment::Left {
|
|
output.push_str(&format!(
|
|
".container {{ text-align: {}; }}\n",
|
|
EntryMetadata::css_escape(&self.content_text_align.to_string())
|
|
));
|
|
}
|
|
|
|
for (element, size) in &self.content_text_size {
|
|
if element == "*" {
|
|
output.push_str(&format!(
|
|
".container, .container * {{ font-size: {}; }}\n",
|
|
EntryMetadata::css_escape(&size)
|
|
));
|
|
|
|
continue;
|
|
}
|
|
|
|
output.push_str(&format!(
|
|
".container {} {{ font-size: {}; }}\n",
|
|
element,
|
|
EntryMetadata::css_escape(&size)
|
|
));
|
|
}
|
|
|
|
if !self.content_font.is_empty() {
|
|
output.push_str(&format!(
|
|
".container {{ font-family: \"{}\", system-ui; }}",
|
|
self.content_font.replace("_", " ")
|
|
));
|
|
}
|
|
|
|
if self.content_font_weight != 0 {
|
|
output.push_str(&format!(
|
|
".container {{ font-weight: {}; }}",
|
|
self.content_font_weight
|
|
));
|
|
}
|
|
|
|
if !self.content_text_shadow_color.is_empty() {
|
|
output.push_str(&format!(
|
|
".container {{ text-shadow: {} {} {}; }}",
|
|
self.content_text_shadow_offset,
|
|
self.content_text_shadow_blur,
|
|
self.content_text_shadow_color
|
|
));
|
|
}
|
|
|
|
if self.container_flex {
|
|
output.push_str(".container { display: flex; }");
|
|
metadata_css!(".container", "gap", self.container_flex_gap->output);
|
|
metadata_css!(".container", "flex-direction", self.container_flex_direction->output);
|
|
metadata_css!(".container", "align-items", self.container_flex_align_vertical->output);
|
|
metadata_css!(".container", "justify-content", self.container_flex_align_horizontal->output);
|
|
|
|
if self.container_flex_wrap {
|
|
output.push_str(".container { flex-wrap: wrap; }");
|
|
}
|
|
}
|
|
|
|
if self.content_disable_paragraph_margin {
|
|
output.push_str(".container p { margin: 0; }");
|
|
}
|
|
|
|
output + "</style>"
|
|
}
|
|
|
|
pub fn ini_to_toml(input: &str) -> String {
|
|
let mut output = String::new();
|
|
|
|
for line in input.split("\n") {
|
|
if !line.contains("=") {
|
|
// no equal sign, skip line (some other toml function)
|
|
continue;
|
|
}
|
|
|
|
let mut key = String::new();
|
|
let mut value = String::new();
|
|
|
|
let mut chars = line.chars();
|
|
let mut in_value = false;
|
|
|
|
while let Some(char) = chars.next() {
|
|
if !in_value {
|
|
key.push(char);
|
|
|
|
if char == '=' {
|
|
in_value = true;
|
|
}
|
|
|
|
continue;
|
|
} else {
|
|
value.push(char);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
value = value.trim().to_string();
|
|
|
|
// determine if we need to stringify
|
|
let is_numeric = is_numeric(&value);
|
|
if !is_numeric
|
|
&& !value.starts_with("[")
|
|
&& !value.starts_with("\"")
|
|
&& value != "true"
|
|
&& value != "false"
|
|
|| value.starts_with("#")
|
|
{
|
|
value = format!("\"{value}\"");
|
|
}
|
|
|
|
// push line
|
|
output.push_str(&format!("{key} {value}\n"));
|
|
}
|
|
|
|
output
|
|
}
|
|
}
|