From 5a84e1bde773bdc782c1db5a633ef8765f220253 Mon Sep 17 00:00:00 2001 From: Lars Wirzenius Date: Mon, 30 Oct 2023 18:45:13 +0200 Subject: feat: allow .subplot to list CSS files to embed in HTML output This is in the meta data field "css_embed". Signed-off-by: Lars Wirzenius Sponsored-by: author --- src/doc.rs | 3 +++ src/metadata.rs | 19 +++++++++++++++++++ subplot.md | 45 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 67 insertions(+) diff --git a/src/doc.rs b/src/doc.rs index f3f9641..83b5ec2 100644 --- a/src/doc.rs +++ b/src/doc.rs @@ -155,6 +155,9 @@ impl Document { let mut css = Element::new(ElementTag::Style); css.push_child(Content::Text(CSS.into())); + for css_file in self.meta.css_embed() { + css.push_child(Content::Text(css_file.into())); + } head.push_child(Content::Elt(css)); self.meta.set_date(date.into()); diff --git a/src/metadata.rs b/src/metadata.rs index e3463b3..dc28ac4 100644 --- a/src/metadata.rs +++ b/src/metadata.rs @@ -50,6 +50,7 @@ pub struct YamlMetadata { documentclass: Option, #[serde(default)] impls: BTreeMap>, + css_embed: Option>, } impl YamlMetadata { @@ -167,6 +168,7 @@ pub struct Metadata { impls: HashMap, /// Extra class names which should be considered 'correct' for this document classes: Vec, + css_embed: Vec, } #[derive(Debug)] @@ -208,6 +210,17 @@ impl Metadata { vec![] }; + let mut css_embed = vec![]; + if let Some(filenames) = &yaml.css_embed { + for filename in filenames.iter() { + let css = std::fs::read(filename) + .map_err(|e| SubplotError::ReadFile(filename.into(), e))?; + let css = String::from_utf8(css) + .map_err(|e| SubplotError::FileUtf8(filename.into(), e))?; + css_embed.push(css); + } + } + let meta = Self { basedir: basedir.as_ref().to_path_buf(), title: yaml.title().into(), @@ -218,6 +231,7 @@ impl Metadata { bindings, impls, classes, + css_embed, }; trace!("metadata: {:#?}", meta); @@ -278,6 +292,11 @@ impl Metadata { pub fn classes(&self) -> impl Iterator { self.classes.iter().map(Deref::deref) } + + /// Contents of CSS files to embed into the HTML output. + pub fn css_embed(&self) -> impl Iterator { + self.css_embed.iter().map(Deref::deref) + } } impl DocumentImpl { diff --git a/subplot.md b/subplot.md index 06e9e38..6532614 100644 --- a/subplot.md +++ b/subplot.md @@ -3639,6 +3639,51 @@ markdowns: ~~~ ~~~~~~ +## HTML output + +### Embedded CSS + +_Requirement:_ The user can specify CSS files to embed in the HTML +output. + +Justification: We want to allow production of self-standing output +with user-defined styling. + +~~~scenario +given file embedded-css.subplot +given file embedded-css.md +given file embedded-css.css +given file b.yaml +given an installed subplot +when I run subplot docgen embedded-css.subplot -o foo.html +then file foo.html contains "silly: property;" +~~~ + +~~~{#embedded-css.subplot .file .yaml .numberLines} +title: Embedded CSS +markdowns: + - embedded-css.md +bindings: + - b.yaml +css_embed: + - embedded-css.css +~~~ + +~~~~~~{#embedded-css.md .file .markdown .numberLines} +# This is a title + +~~~scenario +given precondition +~~~ +~~~~~~ + +~~~{#embedded-css.css .file .css .numberLines} +html { + silly: property; +} +~~~ + + ## Running Subplot The scenarios in this section verify that the Subplot tool can be run -- cgit v1.2.1 From ad26e9d84925532ae5522aad8def5d764fe0ffbe Mon Sep 17 00:00:00 2001 From: Lars Wirzenius Date: Mon, 30 Oct 2023 18:55:47 +0200 Subject: feat: allow adding CSS URLs to HTML output This is in the meta data field "css_urls". Signed-off-by: Lars Wirzenius Sponsored-by: author --- src/doc.rs | 8 ++++++++ src/metadata.rs | 14 ++++++++++++++ subplot.md | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 56 insertions(+) diff --git a/src/doc.rs b/src/doc.rs index 83b5ec2..7e80deb 100644 --- a/src/doc.rs +++ b/src/doc.rs @@ -160,6 +160,14 @@ impl Document { } head.push_child(Content::Elt(css)); + for css_url in self.meta.css_urls() { + let mut link = Element::new(ElementTag::Link); + link.push_attribute(Attribute::new("rel", "stylesheet")); + link.push_attribute(Attribute::new("type", "text/css")); + link.push_attribute(Attribute::new("href", css_url)); + head.push_child(Content::Elt(link)); + } + self.meta.set_date(date.into()); let mut body_content = Element::new(crate::html::ElementTag::Div); diff --git a/src/metadata.rs b/src/metadata.rs index dc28ac4..e382840 100644 --- a/src/metadata.rs +++ b/src/metadata.rs @@ -51,6 +51,7 @@ pub struct YamlMetadata { #[serde(default)] impls: BTreeMap>, css_embed: Option>, + css_urls: Option>, } impl YamlMetadata { @@ -169,6 +170,7 @@ pub struct Metadata { /// Extra class names which should be considered 'correct' for this document classes: Vec, css_embed: Vec, + css_urls: Vec, } #[derive(Debug)] @@ -221,6 +223,12 @@ impl Metadata { } } + let css_urls = if let Some(urls) = &yaml.css_urls { + urls.clone() + } else { + vec![] + }; + let meta = Self { basedir: basedir.as_ref().to_path_buf(), title: yaml.title().into(), @@ -232,6 +240,7 @@ impl Metadata { impls, classes, css_embed, + css_urls, }; trace!("metadata: {:#?}", meta); @@ -297,6 +306,11 @@ impl Metadata { pub fn css_embed(&self) -> impl Iterator { self.css_embed.iter().map(Deref::deref) } + + /// List of CSS urls to add to the HTML output. + pub fn css_urls(&self) -> impl Iterator { + self.css_urls.iter().map(Deref::deref) + } } impl DocumentImpl { diff --git a/subplot.md b/subplot.md index 6532614..432b571 100644 --- a/subplot.md +++ b/subplot.md @@ -3683,6 +3683,40 @@ html { } ~~~ +### CSS URLs + +_Requirement:_ The user can specify CSS URLs to add in the HTML +output. + +Justification: We want to allow users to specify non-embedded CSS. + +~~~scenario +given file css-urls.subplot +given file css-urls.md +given file b.yaml +given an installed subplot +when I run subplot docgen css-urls.subplot -o foo.html +then file foo.html contains "https://example.com/flushing.css" +~~~ + +~~~{#css-urls.subplot .file .yaml .numberLines} +title: Embedded CSS +markdowns: + - css-urls.md +bindings: + - b.yaml +css_urls: + - https://example.com/flushing.css +~~~ + +~~~~~~{#css-urls.md .file .markdown .numberLines} +# This is a title + +~~~scenario +given precondition +~~~ +~~~~~~ + ## Running Subplot -- cgit v1.2.1 From 93b2a8382607d35435518ea73308dee72fb6e547 Mon Sep 17 00:00:00 2001 From: Lars Wirzenius Date: Tue, 31 Oct 2023 09:40:52 +0200 Subject: div for page body class Signed-off-by: Lars Wirzenius Sponsored-by: author --- src/doc.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/doc.rs b/src/doc.rs index 7e80deb..29bc8ad 100644 --- a/src/doc.rs +++ b/src/doc.rs @@ -171,6 +171,7 @@ impl Document { self.meta.set_date(date.into()); let mut body_content = Element::new(crate::html::ElementTag::Div); + body_content.push_attribute(Attribute::new("class", "content")); for md in self.markdowns.iter() { body_content.push_child(Content::Elt(md.root_element().clone())); } -- cgit v1.2.1 From a53c5c551a513375bf66d551b9f72e02eb1003ff Mon Sep 17 00:00:00 2001 From: Lars Wirzenius Date: Tue, 31 Oct 2023 09:52:34 +0200 Subject: feat: add some HTML class attributes This is a start. We'll need to add more as we add more support for styling the output. Signed-off-by: Lars Wirzenius Sponsored-by: author --- src/doc.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/doc.rs b/src/doc.rs index 29bc8ad..07831c2 100644 --- a/src/doc.rs +++ b/src/doc.rs @@ -234,13 +234,19 @@ impl Document { assert!(level <= 6); let mut number = Element::new(ElementTag::Span); + number.push_attribute(Attribute::new("class", "heading-number")); number.push_child(Content::Text(numberer.number(level))); + let mut htext = Element::new(ElementTag::Span); + htext.push_attribute(Attribute::new("class", "heading-text")); + htext.push_child(Content::Text(text)); + let mut a = Element::new(ElementTag::A); a.push_attribute(crate::html::Attribute::new("href", &format!("#{}", id))); + a.push_attribute(Attribute::new("class", "toc-link")); a.push_child(Content::Elt(number)); a.push_child(Content::Text(" ".into())); - a.push_child(Content::Text(text)); + a.push_child(Content::Elt(htext)); let mut li = Element::new(ElementTag::Li); li.push_child(Content::Elt(a)); @@ -288,6 +294,7 @@ impl Document { fn typeset_meta(&self) -> Element { let mut div = Element::new(ElementTag::Div); + div.push_attribute(Attribute::new("class", "meta")); div.push_child(Content::Elt(Self::title(self.meta.title()))); @@ -304,12 +311,14 @@ impl Document { fn title(title: &str) -> Element { let mut e = Element::new(ElementTag::H1); + e.push_attribute(Attribute::new("class", "title")); e.push_child(Content::Text(title.into())); e } fn authors(authors: &[String]) -> Element { let mut list = Element::new(ElementTag::P); + list.push_attribute(Attribute::new("class", "authors")); list.push_child(Content::Text("By: ".into())); let mut first = true; for a in authors { @@ -324,6 +333,7 @@ impl Document { fn date(date: &str) -> Element { let mut e = Element::new(ElementTag::P); + e.push_attribute(Attribute::new("class", "date")); e.push_child(Content::Text(date.into())); e } -- cgit v1.2.1