1use std::{
10 error::Error,
11 fs::{self},
12 process::Command,
13};
14
15use clap::Args;
16use strum::IntoEnumIterator;
17
18use crate::{config, template::Template};
19
20#[derive(Args, Debug)]
22pub struct InitOptions {
23 #[arg(long, required = false)]
25 presentation_only: bool,
26}
27
28const MD_PACKAGE_JSON: &str = include_str!("../static/md-templates/package.json");
30const MD_VITE_CONFIG_JS: &str = include_str!("../static/md-templates/vite.config.js");
31const MD_INDEX_HTML: &str = include_str!("../static/md-templates/index.html");
32const MD_MAIN_JS: &str = include_str!("../static/md-templates/main.js");
33const MD_SLIDES: &str = include_str!("../static/md-templates/slides.md");
34const MD_CUSTOM_CSS: &str = include_str!("../static/md-templates/custom.css");
35const MD_FERRIS: &[u8] = include_bytes!("../static/md-templates/ferris.png");
36
37
38const HTML_PACKAGE_JSON: &str = include_str!("../static/html-templates/package.json");
39const HTML_VITE_CONFIG_JS: &str = include_str!("../static/html-templates/vite.config.js");
40const HTML_INDEX_HTML: &str = include_str!("../static/html-templates/index.html");
41const HTML_MAIN_JS: &str = include_str!("../static/html-templates/main.js");
42const HTML_SLIDES: &str = include_str!("../static/html-templates/slides.html");
43const HTML_CUSTOM_CSS: &str = include_str!("../static/html-templates/custom.css");
44const HTML_FERRIS: &[u8] = include_bytes!("../static/html-templates/ferris.png");
45
46pub fn init(_opts: InitOptions) -> Result<(), Box<dyn Error>> {
62 let conf = config::create_conf()?;
63
64
65 let template: Template = prompt_template()?;
66
67 std::fs::create_dir_all(&conf.title)?;
68
69 let output = Command::new("npm")
70 .args(["init", "-y", "--prefix", &conf.title])
71 .current_dir(&conf.title)
72 .output()?;
73
74 if !output.status.success() {
76 eprintln!(
77 "npm init failed: {}",
78 String::from_utf8_lossy(&output.stderr)
79 );
80 return Err("npm init failed".into());
81 }
82
83 let npm_commands = vec![
84 format!("install --save-dev vite http-server"),
85 format!("install --save-dev patch-package"),
86 format!("install reveal.js serve vite-plugin-singlefile"),
87 format!("install vite@5"),
88 ];
89
90 for c in npm_commands {
91 let args: Vec<&str> = c.split(' ').collect();
92 let output = Command::new("npm")
93 .args(&args)
94 .current_dir(&conf.title)
95 .output()?;
96
97 if !output.status.success() {
98 eprintln!(
99 "npm {} failed: {}",
100 c,
101 String::from_utf8_lossy(&output.stderr)
102 );
103 return Err(format!("npm {} failed", c).into());
104 }
105 println!("Bootstrapped npm {}", c);
106
107 println!("Saving config file...");
108
109 config::write_config(&conf.title, &conf)?;
110 }
111
112
113 match template {
115 Template::Markdown => {
116 fs::write(format!("{}/package.json", &conf.title), MD_PACKAGE_JSON)?;
117 fs::write(format!("{}/vite.config.js", &conf.title), MD_VITE_CONFIG_JS)?;
118 fs::write(format!("{}/index.html", &conf.title), MD_INDEX_HTML)?;
119
120 std::fs::create_dir_all(format!("{}/src", &conf.title))?;
121 fs::write(format!("{}/src/main.js", &conf.title), MD_MAIN_JS)?;
122
123 std::fs::create_dir_all(format!("{}/slides", &conf.title))?;
124 fs::write(format!("{}/slides/slides.md", &conf.title), MD_SLIDES)?;
125
126 std::fs::create_dir_all(format!("{}/css", &conf.title))?;
127 fs::write(format!("{}/css/custom.css", &conf.title), MD_CUSTOM_CSS)?;
128
129 std::fs::create_dir_all(format!("{}/public", &conf.title))?;
130 fs::write(format!("{}/public/ferris.png", &conf.title), MD_FERRIS)?;
131 }
132 Template::HTML => {
133
134 fs::write(format!("{}/package.json", &conf.title), HTML_PACKAGE_JSON)?;
135 fs::write(format!("{}/vite.config.js", &conf.title), HTML_VITE_CONFIG_JS)?;
136 fs::write(format!("{}/index.html", &conf.title), HTML_INDEX_HTML)?;
137
138 std::fs::create_dir_all(format!("{}/src", &conf.title))?;
139 fs::write(format!("{}/src/main.js", &conf.title), HTML_MAIN_JS)?;
140
141 std::fs::create_dir_all(format!("{}/slides", &conf.title))?;
142 fs::write(format!("{}/slides/slides.html", &conf.title), HTML_SLIDES)?;
143
144 std::fs::create_dir_all(format!("{}/css", &conf.title))?;
145 fs::write(format!("{}/css/custom.css", &conf.title), HTML_CUSTOM_CSS)?;
146
147 std::fs::create_dir_all(format!("{}/public", &conf.title))?;
148 fs::write(format!("{}/public/ferris.png", &conf.title), HTML_FERRIS)?
149 },
150 }
151
152 Ok(())
153}
154
155fn prompt_template() -> Result<Template, Box<dyn Error>> {
156 let template_opts: Vec<Template> = Template::iter().collect();
157
158 let chosen_template = inquire::Select::new("Select a template:", template_opts).prompt()?;
159
160 Ok(chosen_template)
161}