diff --git a/Cargo.lock b/Cargo.lock index bcf7b32..be463a4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -135,6 +135,12 @@ dependencies = [ "windows-targets", ] +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + [[package]] name = "bitflags" version = "1.3.2" @@ -624,8 +630,7 @@ dependencies = [ [[package]] name = "grass" version = "0.13.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7a68216437ef68f0738e48d6c7bb9e6e6a92237e001b03d838314b068f33c94" +source = "git+https://git.shadowfacts.net/shadowfacts/grass.git?branch=custom-global-variables#e64e648b6174d23b6d4a8ad674eb443dc6fcbdff" dependencies = [ "getrandom", "grass_compiler", @@ -634,14 +639,14 @@ dependencies = [ [[package]] name = "grass_compiler" version = "0.13.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d9e3df7f0222ce5184154973d247c591d9aadc28ce7a73c6cd31100c9facff6" +source = "git+https://git.shadowfacts.net/shadowfacts/grass.git?branch=custom-global-variables#e64e648b6174d23b6d4a8ad674eb443dc6fcbdff" dependencies = [ "codemap", "indexmap", "lasso", "once_cell", "phf", + "rand", ] [[package]] @@ -1891,6 +1896,7 @@ name = "v7" version = "0.1.0" dependencies = [ "anyhow", + "base64", "chrono", "clap", "compute_graph", @@ -1898,6 +1904,7 @@ dependencies = [ "env_logger", "futures", "grass", + "grass_compiler", "html5ever", "log", "markup5ever_rcdom", diff --git a/Cargo.toml b/Cargo.toml index 7680a1a..0874939 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,13 +17,17 @@ serde_json = "1.0" [dependencies] anyhow = "1.0.95" +base64 = "0.22.1" chrono = { version = "0.4.39", features = ["serde"] } clap = { version = "4.5.23", features = ["cargo"] } compute_graph = { path = "crates/compute_graph" } debounced = "0.2.0" env_logger = "0.11.6" futures = "0.3.31" -grass = { version = "0.13.4", default-features = false } +grass = { version = "0.13.4", default-features = false, git = "https://git.shadowfacts.net/shadowfacts/grass.git", branch = "custom-global-variables" } +grass_compiler = { version = "0.13.4", features = [ + "custom-builtin-fns", +], git = "https://git.shadowfacts.net/shadowfacts/grass.git", branch = "custom-global-variables" } html5ever = "0.27.0" log = "0.4.22" markup5ever_rcdom = "0.3.0" diff --git a/site_test/css/main.scss b/site_test/css/main.scss index b6f6b6d..2ec45ad 100644 --- a/site_test/css/main.scss +++ b/site_test/css/main.scss @@ -1,5 +1,35 @@ -.foo { - .bar { - color: red; - } +@font-face { + font-family: "Equity A"; + font-style: normal; + font-weight: normal; + font-stretch: normal; + font-display: auto; + src: url("data:font/woff2;base64," + $equity-a-regular) format("woff2"); +} + +@font-face { + font-family: "Equity A"; + font-style: italic; + font-weight: normal; + font-stretch: normal; + font-display: auto; + src: url("data:font/woff2;base64," + $equity-a-italic) format("woff2"); +} + +@font-face { + font-family: "Equity A"; + font-style: normal; + font-weight: bold; + font-stretch: normal; + font-display: auto; + src: url("data:font/woff2;base64," + $equity-a-bold) format("woff2"); +} + +@font-face { + font-family: "Equity A"; + font-style: italic; + font-weight: bold; + font-stretch: normal; + font-display: auto; + src: url("data:font/woff2;base64," + $equity-a-bold-italic) format("woff2"); } diff --git a/site_test/fonts/equity-a-bold-italic.woff2 b/site_test/fonts/equity-a-bold-italic.woff2 new file mode 100644 index 0000000..339cc03 Binary files /dev/null and b/site_test/fonts/equity-a-bold-italic.woff2 differ diff --git a/site_test/fonts/equity-a-bold.woff2 b/site_test/fonts/equity-a-bold.woff2 new file mode 100644 index 0000000..2977a86 Binary files /dev/null and b/site_test/fonts/equity-a-bold.woff2 differ diff --git a/site_test/fonts/equity-a-italic.woff2 b/site_test/fonts/equity-a-italic.woff2 new file mode 100644 index 0000000..21ed50d Binary files /dev/null and b/site_test/fonts/equity-a-italic.woff2 differ diff --git a/site_test/fonts/equity-a-regular.woff2 b/site_test/fonts/equity-a-regular.woff2 new file mode 100644 index 0000000..a242789 Binary files /dev/null and b/site_test/fonts/equity-a-regular.woff2 differ diff --git a/src/generator/css.rs b/src/generator/css.rs index 94ef7b0..79534d9 100644 --- a/src/generator/css.rs +++ b/src/generator/css.rs @@ -1,5 +1,12 @@ -use std::{cell::RefCell, collections::HashSet, io::Write, path::PathBuf, rc::Rc}; +use std::{ + cell::RefCell, + collections::{HashMap, HashSet}, + io::Write, + path::PathBuf, + rc::Rc, +}; +use base64::{Engine, prelude::BASE64_STANDARD}; use compute_graph::{ InvalidationSignal, builder::GraphBuilder, @@ -7,6 +14,7 @@ use compute_graph::{ synchronicity::Asynchronous, }; use grass::{Fs, Options, OutputStyle}; +use grass_compiler::sass_value::{QuoteKind, Value}; use log::error; use super::{ @@ -18,21 +26,55 @@ pub fn make_graph( builder: &mut GraphBuilder<(), Asynchronous>, watcher: Rc>, ) -> Input<()> { + let mut watcher_ = watcher.borrow_mut(); + let mut fonts = HashMap::<&'static str, Input>::new(); + let filenames: &[&str] = &[ + "equity-a-regular", + "equity-a-bold", + "equity-a-italic", + "equity-a-bold-italic", + ]; + for name in filenames { + fonts.insert(name, read_font(name, builder, &mut *watcher_)); + } + drop(watcher_); + let invalidate_css_box = Rc::new(RefCell::new(None)); let (css, invalidate_css) = builder.add_invalidatable_rule(CompileScss { watcher, watched: HashSet::new(), invalidate: Rc::clone(&invalidate_css_box), + fonts, }); invalidate_css_box.replace(Some(invalidate_css)); css } -#[derive(InputVisitable)] +fn read_font( + name: &'static str, + builder: &mut GraphBuilder<(), Asynchronous>, + watcher: &mut FileWatcher, +) -> Input { + let mut path = content_path("fonts"); + path.push(name); + path.set_extension("woff2"); + let (font, invalidate) = builder.add_invalidatable_rule(ReadFont(path.clone())); + watcher.watch(path, move || invalidate.invalidate()); + font +} + struct CompileScss { watcher: Rc>, watched: HashSet, invalidate: Rc>>, + fonts: HashMap<&'static str, Input>, +} +impl InputVisitable for CompileScss { + fn visit_inputs(&self, visitor: &mut impl compute_graph::rule::InputVisitor) { + for input in self.fonts.values() { + visitor.visit(input); + } + } } impl Rule for CompileScss { type Output = (); @@ -44,8 +86,14 @@ impl Rule for CompileScss { } else { OutputStyle::Compressed }; - let options = Options::default().fs(&fs).style(style); + let mut options = Options::default().fs(&fs).style(style); + for (name, input) in self.fonts.iter() { + let value = Value::String(input.value().to_owned(), QuoteKind::None); + options = options.add_custom_var(*name, value); + } + let result = grass::from_path(content_path("css/main.scss"), &options); + let mut watcher = self.watcher.borrow_mut(); for file in read_files.take() { if !self.watched.contains(&file) { @@ -54,6 +102,7 @@ impl Rule for CompileScss { watcher.watch(file, move || signal.invalidate()); } } + match result { Ok(s) => { output_writer("css/main.css") @@ -88,3 +137,18 @@ impl<'a> Fs for TrackingFs<'a> { std::fs::canonicalize(path) } } + +#[derive(InputVisitable)] +struct ReadFont(PathBuf); +impl Rule for ReadFont { + type Output = String; + fn evaluate(&mut self) -> Self::Output { + match std::fs::read(&self.0) { + Ok(data) => BASE64_STANDARD.encode(data), + Err(e) => { + error!("Error reading font {:?}: {:?}", &self.0, e); + String::new() + } + } + } +}