Skip to content

Commit

Permalink
Add ability to download themes.
Browse files Browse the repository at this point in the history
  • Loading branch information
ibz committed Dec 9, 2024
1 parent eef019c commit c7be20d
Show file tree
Hide file tree
Showing 6 changed files with 112 additions and 51 deletions.
15 changes: 8 additions & 7 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,22 @@ edition = "2021"

[dependencies]
async-std = { version = "1", features = ["attributes"] }
base64 = { version = "0.21" }
bitcoin_hashes = { version = "0.12", features = ["serde"] }
base64 = { version = "0.22" }
bitcoin_hashes = { version = "0.15", features = ["serde"] }
bytes = "1.7.2"
chrono = { version = "0", features = ["serde"] }
clap = { version = "4", features = ["derive"] }
femme = "2"
futures-util = "0.3.30"
futures-util = "0.3"
git2 = "0.19"
globset = "0.4"
grass = {version = "0.13", default-features = false, features = ["random"]}
http-types = "2"
lazy_static = "1.4"
mime_guess = "2.0.4"
multer = "3.1.0"
phf = { version = "0.11.2", features = ["macros"] }
pulldown-cmark = "0.11.0"
mime_guess = "2.0"
multer = "3.1"
phf = { version = "0.11", features = ["macros"] }
pulldown-cmark = "0.12"
regex = "1"
secp256k1 = { version = "0.27", features = ["serde", "bitcoin_hashes"] }
serde = "1"
Expand Down
65 changes: 50 additions & 15 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use bytes::Bytes;
use chrono::Utc;
use clap::Parser;
use futures_util::stream::once;
use git2::Repository;
use http_types::{mime, Method};
use multer::Multipart;
use phf::{phf_map, phf_set};
Expand Down Expand Up @@ -39,6 +40,8 @@ use resource::{ContentSource, Resource, ResourceKind};
use site::Site;
use theme::Theme;

const THEMES_REPO: &str = "https://github.com/getzola/themes";

#[derive(Parser)]
struct Cli {
#[clap(short('e'), long)]
Expand Down Expand Up @@ -366,7 +369,7 @@ async fn handle_request(request: Request<State>) -> tide::Result<Response> {
}

let themes = request.state().themes.read().unwrap();
let theme = themes.get(&site.config.theme.clone().unwrap()).unwrap();
let theme = themes.get(&site.config.theme).unwrap();

let mut resource_path = format!("/{}", &path);
if site_resources.contains(&resource_path) {
Expand Down Expand Up @@ -553,10 +556,7 @@ async fn handle_get_site_config(request: Request<State>) -> tide::Result<Respons

Ok(Response::builder(StatusCode::Ok)
.content_type(mime::JSON)
.body(
json!({"theme": site.config.theme.unwrap_or("".to_string()), "available_themes": themes})
.to_string(),
)
.body(json!({"theme": site.config.theme, "available_themes": themes}).to_string())
.build())
}

Expand All @@ -578,13 +578,11 @@ async fn handle_put_site_config(mut request: Request<State>) -> tide::Result<Res
// which is already merged with the theme's config!
let config_path = format!("{}/{}/_config.toml", site::SITE_PATH, site.domain);
let mut config = site::load_config(&config_path).unwrap();
config.theme = Some(
request
.body_json::<PutSiteConfigRequestBody>()
.await
.unwrap()
.theme,
);
config.theme = request
.body_json::<PutSiteConfigRequestBody>()
.await
.unwrap()
.theme;
site::save_config(&config_path, config);

let new_site = site::load_site(&site.domain);
Expand Down Expand Up @@ -872,11 +870,48 @@ async fn main() -> Result<(), std::io::Error> {

femme::with_level(log::LevelFilter::Info);

let themes = theme::load_themes();
let mut themes = theme::load_themes();

if themes.len() == 0 {
println!("No themes found. Exiting!");
return Ok(());
log::error!("No themes found!");

let stdin = io::stdin();
let mut response = String::new();
while response != "n" && response != "y" {
print!("Fetch themes from {}? [y/n]? ", THEMES_REPO);
io::stdout().flush().unwrap();
response = stdin.lock().lines().next().unwrap().unwrap().to_lowercase();
}

if response == "y" {
let url = format!("{}.git", THEMES_REPO);
match Repository::clone(&url, "./themes") {
Ok(repo) => {
for mut submodule in repo.submodules().unwrap() {
log::info!(
"Cloning theme: {}...",
submodule.path().as_os_str().to_str().unwrap()
);
if let Err(e) = submodule.update(true, None) {
log::warn!(
"Failed to clone theme {}: {}",
submodule.path().as_os_str().to_str().unwrap(),
e
);
};
}
}
Err(e) => panic!("Failed to clone themes repo: {}", e),
};
} else {
return Ok(());
}

themes = theme::load_themes();

if themes.len() == 0 {
panic!("No themes!");
}
}

let sites;
Expand Down
2 changes: 1 addition & 1 deletion src/nostr.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use bitcoin_hashes::{sha256, Hash};
use bitcoin_hashes::sha256;
use chrono::{DateTime, NaiveDateTime, TimeDelta, TimeZone, Utc};
use lazy_static::lazy_static;
use secp256k1::{schnorr, Secp256k1, VerifyOnly, XOnlyPublicKey};
Expand Down
16 changes: 9 additions & 7 deletions src/sass.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,23 @@ use walkdir::{DirEntry, WalkDir};

// https://github.com/getzola/zola/blob/master/components/site/src/sass.rs

pub fn compile_sass(sass_path: &PathBuf) -> HashMap<String, String> {
pub fn compile_sass(sass_path: &PathBuf) -> Result<HashMap<String, String>, String> {
let mut resources = HashMap::new();

let options = Options::default().style(OutputStyle::Compressed);
let files = get_non_partial_scss(&sass_path);

for file in files {
let css = compile_file(&file, &options).unwrap();

let path = file.strip_prefix(&sass_path).unwrap().with_extension("css");

resources.insert(format!("/{}", path.display().to_string()), css);
match compile_file(&file, &options) {
Ok(css) => {
let path = file.strip_prefix(&sass_path).unwrap().with_extension("css");
resources.insert(format!("/{}", path.display().to_string()), css);
}
_ => return Err(format!("Error compiling file: {}", file.display())),
}
}

resources
Ok(resources)
}

fn is_partial_scss(entry: &DirEntry) -> bool {
Expand Down
17 changes: 9 additions & 8 deletions src/site.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ pub const SITE_PATH: &str = "./sites";
use crate::{
content, nostr,
resource::{ContentSource, Resource, ResourceKind},
template,
template, theme,
theme::ThemeConfig,
utils::merge,
};

Expand Down Expand Up @@ -46,7 +47,7 @@ pub struct SiteConfig {
pub base_url: String,
pub pubkey: Option<String>,

pub theme: Option<String>,
pub theme: String,
pub title: Option<String>,

#[serde(default = "default_feed_filename")]
Expand Down Expand Up @@ -82,7 +83,7 @@ impl SiteConfig {
}
}

pub fn merge(&mut self, other: &SiteConfig) {
pub fn merge(&mut self, other: &ThemeConfig) {
for (key, value) in &other.extra {
if !self.extra.contains_key(key) {
self.extra.insert(key.to_owned(), value.clone());
Expand All @@ -96,7 +97,7 @@ impl SiteConfig {
fn load_templates(site_config: &SiteConfig) -> tera::Tera {
println!("Loading templates...");

let theme_path = format!("./themes/{}", site_config.theme.as_ref().unwrap());
let theme_path = format!("./themes/{}", site_config.theme);

let mut tera = tera::Tera::new(&format!("{}/templates/**/*", theme_path)).unwrap();
tera.autoescape_on(vec![]);
Expand Down Expand Up @@ -470,8 +471,8 @@ pub fn load_site(domain: &str) -> Site {

let mut config = config.unwrap();

let theme_path = format!("./themes/{}", config.theme.as_ref().unwrap());
let theme_config = load_config(&format!("{}/config.toml", theme_path)).unwrap();
let theme_path = format!("./themes/{}", config.theme);
let theme_config = theme::load_config(&format!("{}/config.toml", theme_path)).unwrap();

config.merge(&theme_config);

Expand Down Expand Up @@ -534,8 +535,8 @@ pub fn create_site(domain: &str, admin_pubkey: Option<String>) -> Site {

let mut config = load_config(&format!("{}/_config.toml", path)).unwrap();

let theme_path = format!("./themes/{}", config.theme.as_ref().unwrap());
let theme_config = load_config(&format!("{}/config.toml", theme_path)).unwrap();
let theme_path = format!("./themes/{}", config.theme);
let theme_config = theme::load_config(&format!("{}/config.toml", theme_path)).unwrap();

config.merge(&theme_config);

Expand Down
48 changes: 35 additions & 13 deletions src/theme.rs
Original file line number Diff line number Diff line change
@@ -1,34 +1,50 @@
use serde::{Deserialize, Serialize};
use std::{
collections::HashMap,
fs,
path::PathBuf,
sync::{Arc, RwLock},
};
use tide::log;

use crate::sass;
use crate::site::{load_config, SiteConfig};

#[derive(Clone)]
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct ThemeConfig {
#[serde(flatten)]
pub extra: HashMap<String, toml::Value>,
}

pub fn load_config(config_path: &str) -> Option<ThemeConfig> {
if let Ok(content) = fs::read_to_string(config_path) {
Some(toml::from_str(&content).unwrap())
} else {
None
}
}

pub struct Theme {
pub path: String,
pub config: SiteConfig,
pub config: ThemeConfig,
pub resources: Arc<RwLock<HashMap<String, String>>>,
}

impl Theme {
pub fn load_sass(&self) {
pub fn load_sass(&self) -> Result<(), String> {
let mut sass_path = PathBuf::from(&self.path);
sass_path.push("sass/");
if !sass_path.as_path().exists() {
return;
return Ok(());
}

let mut resources = self.resources.write().unwrap();

for (k, v) in &sass::compile_sass(&sass_path) {
println!("Loaded theme resource: {}", k);
for (k, v) in &sass::compile_sass(&sass_path)? {
log::debug!("Loaded theme resource: {}", k);
resources.insert(k.to_owned(), v.to_string());
}

Ok(())
}
}

Expand All @@ -40,31 +56,37 @@ pub fn load_themes() -> HashMap<String, Theme> {

let mut themes = HashMap::new();
for path in &paths {
println!("Found theme: {}", path.file_name().to_str().unwrap());
log::info!("Found theme: {}", path.file_name().to_str().unwrap());

let theme_path = path.path().display().to_string();

let config = load_config(&format!("{}/config.toml", theme_path));
if config.is_none() {
println!("No config for theme: {}. Skipping!", theme_path);
log::warn!("No config for theme: {}. Skipping!", theme_path);
continue;
}
let config = config.unwrap();

let theme = Theme {
path: theme_path,
path: theme_path.clone(),
config,
resources: Arc::new(RwLock::new(HashMap::new())),
};

theme.load_sass();
if let Err(e) = theme.load_sass() {
log::warn!(
"Failed to load sass for theme: {}. Skipping! Error: {}",
theme_path,
e
)
}

println!("Theme loaded!");
log::debug!("Theme loaded: {}!", path.file_name().to_str().unwrap());

themes.insert(path.file_name().to_str().unwrap().to_string(), theme);
}

println!("{} themes loaded!", themes.len());
log::info!("{} themes loaded!", themes.len());

themes
}

0 comments on commit c7be20d

Please sign in to comment.