Skip to content

Commit

Permalink
feat: support basic theming (#71)
Browse files Browse the repository at this point in the history
  • Loading branch information
Myriad-Dreamin authored Jun 14, 2024
1 parent 488f4dd commit 0594aa4
Show file tree
Hide file tree
Showing 5 changed files with 113 additions and 55 deletions.
7 changes: 7 additions & 0 deletions cli/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,13 @@ pub struct CompileArgs {
#[clap(long, default_value = "/")]
pub path_to_root: String,

/// Specify a theme directory to copy recursively.
///
/// The files will be copied to the `theme/` in the output
/// directory.
#[clap(long)]
pub theme: Option<String>,

/// Add additional directories to search for fonts
#[clap(
long = "font-path",
Expand Down
58 changes: 26 additions & 32 deletions cli/src/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ use crate::{
error::prelude::*,
meta::{BookMeta, BookMetaContent, BookMetaElem, BuildMeta},
render::{DataDict, HtmlRenderer, TypstRenderer},
utils::{copy_dir_embedded, create_dirs, release_packages, write_file},
theme::Theme,
utils::{create_dirs, release_packages, write_file},
CompileArgs,
};
use include_dir::include_dir;
Expand Down Expand Up @@ -44,8 +45,10 @@ impl fmt::Display for JsonContent {
}

pub struct Project {
pub theme: Theme,
pub tr: TypstRenderer,
pub hr: HtmlRenderer,

pub book_meta: Option<BookMeta>,
pub build_meta: Option<BuildMeta>,

Expand All @@ -70,13 +73,21 @@ impl Project {
args.workspace.clone_from(&args.dir);
}

let theme = match &args.theme {
Some(theme) => Theme::new(Path::new(theme))?,
None => Theme::default(),
};

let tr = TypstRenderer::new(args);
let hr = HtmlRenderer::new();
let hr = HtmlRenderer::new(&theme);

let mut proj = Self {
dest_dir: tr.dest_dir.clone(),

theme,
tr,
hr,

book_meta: None,
build_meta: None,
path_to_root,
Expand Down Expand Up @@ -212,46 +223,29 @@ impl Project {
pub fn build(&mut self) -> ZResult<()> {
let mut write_index = false;

create_dirs(&self.dest_dir)?;
copy_dir_embedded(
include_dir!("$CARGO_MANIFEST_DIR/../themes/mdbook/css"),
self.dest_dir.join("css"),
)?;
copy_dir_embedded(
include_dir!("$CARGO_MANIFEST_DIR/../themes/mdbook/FontAwesome/css"),
self.dest_dir.join("FontAwesome/css"),
)?;
copy_dir_embedded(
include_dir!("$CARGO_MANIFEST_DIR/../themes/mdbook/FontAwesome/fonts"),
self.dest_dir.join("FontAwesome/fonts"),
)?;
let themes = self.dest_dir.join("theme");

// todo use themes in filesystem
// copy_dir_all("themes/mdbook/css", self.dest_dir.join("css")).unwrap();
// copy_dir_all(
// "themes/mdbook/fontAwesome",
// self.dest_dir.join("fontAwesome"),
// )
// .unwrap();
// Always update the theme if it is static
// Or copy on first build
if self.theme.is_static() || !themes.exists() {
log::info!("copying theme assets to {:?}", themes);
self.theme.copy_assets(&themes)?;
}

// copy files
create_dirs(self.dest_dir.join("renderer"))?;
// copy internal files
create_dirs(self.dest_dir.join("internal"))?;
write_file(
self.dest_dir.join("renderer/typst_ts_renderer_bg.wasm"),
self.dest_dir.join("internal/typst_ts_renderer_bg.wasm"),
include_bytes!("../../assets/artifacts/typst_ts_renderer_bg.wasm"),
)?;
write_file(
self.dest_dir.join("svg_utils.js"),
self.dest_dir.join("internal/svg_utils.js"),
include_bytes!("../../assets/artifacts/svg_utils.cjs"),
)?;
write_file(
self.dest_dir.join("typst-book.js"),
self.dest_dir.join("internal/typst-book.js"),
include_bytes!("../../assets/artifacts/book.mjs"),
)?;
write_file(
self.dest_dir.join("index.js"),
include_bytes!("../../themes/mdbook/index.js"),
)?;

for ch in self.iter_chapters() {
if let Some(path) = ch.get("path") {
Expand Down Expand Up @@ -386,7 +380,7 @@ impl Project {
// inject chapters
data.insert("chapters".to_owned(), json!(self.iter_chapters()));

let renderer_module = format!("{}renderer/typst_ts_renderer_bg.wasm", self.path_to_root);
let renderer_module = format!("{}internal/typst_ts_renderer_bg.wasm", self.path_to_root);
data.insert("renderer_module".to_owned(), json!(renderer_module));

// inject content
Expand Down
10 changes: 1 addition & 9 deletions cli/src/render/html.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,8 @@ pub struct HtmlRenderer {
}

impl HtmlRenderer {
pub fn new() -> Self {
pub fn new(theme: &theme::Theme) -> Self {
let mut handlebars = Handlebars::new();
// todo std::path::Path::new("themes/mdbook")
let theme = theme::Theme::default();

debug!("Register the index handlebars template");
handlebars
Expand Down Expand Up @@ -289,9 +287,3 @@ fn write_li_open_tag(
li.push_str("\">");
out.write(&li)
}

impl Default for HtmlRenderer {
fn default() -> Self {
Self::new()
}
}
73 changes: 69 additions & 4 deletions cli/src/theme.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,21 @@
use std::{fs::File, io::Read, path::Path};

use log::warn;
use typst_ts_core::{error::prelude::*, ImmutPath};

use crate::utils::{self, copy_dir_embedded, write_file};
use include_dir::include_dir;

#[derive(Debug, PartialEq)]
pub enum EmbeddedThemeAsset {
MdBook,
}

#[derive(Debug, PartialEq)]
pub enum ThemeAsset {
Static(EmbeddedThemeAsset),
Dir(ImmutPath),
}

/// The `Theme` struct should be used instead of the static variables because
/// the `new()` method will look if the user has a theme directory in their
Expand All @@ -12,6 +27,8 @@ use log::warn;
pub struct Theme {
pub index: Vec<u8>,
pub typst_load_trampoline: Vec<u8>,

asset: ThemeAsset,
}

impl Default for Theme {
Expand All @@ -20,6 +37,7 @@ impl Default for Theme {
index: include_bytes!("../../themes/mdbook/index.hbs").to_vec(),
typst_load_trampoline: include_bytes!("../../themes/mdbook/typst-load-trampoline.hbs")
.to_vec(),
asset: ThemeAsset::Static(EmbeddedThemeAsset::MdBook),
}
}
}
Expand All @@ -28,12 +46,18 @@ impl Theme {
/// Creates a `Theme` from the given `theme_dir`.
/// If a file is found in the theme dir, it will override the default
/// version.
pub fn new(theme_dir: &Path) -> Self {
let mut theme = Self::default();
pub fn new(theme_dir: &Path) -> ZResult<Self> {
let mut theme = Self {
asset: ThemeAsset::Dir(theme_dir.into()),
..Default::default()
};

// If the theme directory doesn't exist there's no point continuing...
if !theme_dir.exists() || !theme_dir.is_dir() {
panic!("Theme directory doesn't exist: {:?}", theme_dir);
return Err(error_once!(
"Theme directory doesn't exist",
theme_dir: theme_dir.display(),
));
}

// Check for individual files, if they exist copy them across
Expand Down Expand Up @@ -67,7 +91,48 @@ impl Theme {
// let fonts_dir = theme_dir.join("fonts");
// ...

theme
Ok(theme)
}

pub fn is_static(&self) -> bool {
matches!(self.asset, ThemeAsset::Static(_))
}

pub fn copy_assets(&self, dest_dir: &Path) -> ZResult<()> {
if !dest_dir.exists() {
log::debug!(
"{} does not exist, creating the directory",
dest_dir.display()
);
utils::create_dirs(dest_dir)?;
}

match &self.asset {
ThemeAsset::Static(EmbeddedThemeAsset::MdBook) => {
copy_dir_embedded(
include_dir!("$CARGO_MANIFEST_DIR/../themes/mdbook/css"),
dest_dir.join("css"),
)?;
copy_dir_embedded(
include_dir!("$CARGO_MANIFEST_DIR/../themes/mdbook/FontAwesome/css"),
dest_dir.join("FontAwesome/css"),
)?;
copy_dir_embedded(
include_dir!("$CARGO_MANIFEST_DIR/../themes/mdbook/FontAwesome/fonts"),
dest_dir.join("FontAwesome/fonts"),
)?;
write_file(
dest_dir.join("index.js"),
include_bytes!("../../themes/mdbook/index.js"),
)?;
}
ThemeAsset::Dir(theme_dir) => {
utils::copy_dir_all(theme_dir, dest_dir)
.map_err(error_once_map!("copy_theme_directory"))?;
}
}

Ok(())
}
}

Expand Down
20 changes: 10 additions & 10 deletions themes/mdbook/index.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,17 @@
{{#if favicon_png}}
<link rel="shortcut icon" href="{{ path_to_root }}favicon.png">
{{/if}}
<link rel="stylesheet" href="{{ path_to_root }}css/variables.css">
<link rel="stylesheet" href="{{ path_to_root }}css/general.css">
<link rel="stylesheet" href="{{ path_to_root }}css/chrome.css">
<link rel="stylesheet" href="{{ path_to_root }}theme/css/variables.css">
<link rel="stylesheet" href="{{ path_to_root }}theme/css/general.css">
<link rel="stylesheet" href="{{ path_to_root }}theme/css/chrome.css">
{{#if print_enable}}
<link rel="stylesheet" href="{{ path_to_root }}css/print.css" media="print">
<link rel="stylesheet" href="{{ path_to_root }}theme/css/print.css" media="print">
{{/if}}

<!-- Fonts -->
<link rel="stylesheet" href="{{ path_to_root }}FontAwesome/css/font-awesome.css">
<link rel="stylesheet" href="{{ path_to_root }}theme/FontAwesome/css/font-awesome.css">
{{#if copy_fonts}}
<link rel="stylesheet" href="{{ path_to_root }}fonts/fonts.css">
<link rel="stylesheet" href="{{ path_to_root }}theme/fonts/fonts.css">
{{/if}}

<!-- Custom theme stylesheets -->
Expand Down Expand Up @@ -80,7 +80,7 @@
{{!-- window.captureStack = function() { return new Error(); } --}}
</script>

<script id="typst-book-js" type="module" src="{{ path_to_root }}typst-book.js"></script>
<script id="typst-book-js" type="module" src="{{ path_to_root }}internal/typst-book.js"></script>
{{!-- <script id="typst-book-js" type="module" src="/dev/frontend/dist/book.mjs"></script> --}}
<script>
window.typstRerender = () => { };
Expand Down Expand Up @@ -237,7 +237,7 @@

<div class="right-buttons">
{{#if print_enable}}
<a href="{{ path_to_root }}print.html" title="Print this book" aria-label="Print this book">
<a href="{{ path_to_root }}theme/print.html" title="Print this book" aria-label="Print this book">
<i id="print-button" class="fa fa-print"></i>
</a>
{{/if}}
Expand Down Expand Up @@ -322,9 +322,9 @@

</div>

<script src="{{ path_to_root }}svg_utils.js"></script>
<script src="{{ path_to_root }}internal/svg_utils.js"></script>
{{!-- <script src="/dev/frontend/src/svg_utils.cjs"></script> --}}
<script src="{{ path_to_root }}index.js"></script>
<script src="{{ path_to_root }}theme/index.js"></script>

</div>
</body>
Expand Down

0 comments on commit 0594aa4

Please sign in to comment.