commit
45d366dee3
|
@ -4,6 +4,8 @@
|
||||||
|
|
||||||
- Add `redirect_to` to section front matter to redirect when landing on section
|
- Add `redirect_to` to section front matter to redirect when landing on section
|
||||||
root page
|
root page
|
||||||
|
- Make `title` in config optional
|
||||||
|
- Improved `gutenberg init` UX and users first experience
|
||||||
|
|
||||||
## 0.1.1 (2017-07-16)
|
## 0.1.1 (2017-07-16)
|
||||||
|
|
||||||
|
|
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -400,6 +400,7 @@ dependencies = [
|
||||||
"staticfile 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"staticfile 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"term-painter 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"term-painter 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"toml 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"toml 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"url 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"utils 0.1.0",
|
"utils 0.1.0",
|
||||||
"ws 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"ws 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
|
@ -22,6 +22,9 @@ chrono = "0.4"
|
||||||
toml = "0.4"
|
toml = "0.4"
|
||||||
term-painter = "0.2"
|
term-painter = "0.2"
|
||||||
|
|
||||||
|
# Used in init to ensure the url given as base_url is a valid one
|
||||||
|
url = "1.5"
|
||||||
|
|
||||||
# Below is for the serve cmd
|
# Below is for the serve cmd
|
||||||
staticfile = "0.4"
|
staticfile = "0.4"
|
||||||
iron = "0.5"
|
iron = "0.5"
|
||||||
|
|
|
@ -18,11 +18,11 @@ use rendering::highlighting::THEME_SET;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
/// Title of the site
|
/// Base URL of the site, the only required config argument
|
||||||
pub title: String,
|
|
||||||
/// Base URL of the site
|
|
||||||
pub base_url: String,
|
pub base_url: String,
|
||||||
|
|
||||||
|
/// Title of the site. Defaults to None
|
||||||
|
pub title: Option<String>,
|
||||||
/// Whether to highlight all code blocks found in markdown files. Defaults to false
|
/// Whether to highlight all code blocks found in markdown files. Defaults to false
|
||||||
pub highlight_code: Option<bool>,
|
pub highlight_code: Option<bool>,
|
||||||
/// Which themes to use for code highlighting. See Readme for supported themes
|
/// Which themes to use for code highlighting. See Readme for supported themes
|
||||||
|
@ -123,7 +123,7 @@ impl Config {
|
||||||
impl Default for Config {
|
impl Default for Config {
|
||||||
fn default() -> Config {
|
fn default() -> Config {
|
||||||
Config {
|
Config {
|
||||||
title: "".to_string(),
|
title: Some("".to_string()),
|
||||||
base_url: "http://a-website.com/".to_string(),
|
base_url: "http://a-website.com/".to_string(),
|
||||||
highlight_code: Some(true),
|
highlight_code: Some(true),
|
||||||
highlight_theme: Some("base16-ocean-dark".to_string()),
|
highlight_theme: Some("base16-ocean-dark".to_string()),
|
||||||
|
@ -167,7 +167,7 @@ base_url = "https://replace-this-with-your-url.com"
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let config = Config::parse(config).unwrap();
|
let config = Config::parse(config).unwrap();
|
||||||
assert_eq!(config.title, "My site".to_string());
|
assert_eq!(config.title.unwrap(), "My site".to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
0
components/templates/src/builtins/index.html
Normal file
0
components/templates/src/builtins/index.html
Normal file
0
components/templates/src/builtins/page.html
Normal file
0
components/templates/src/builtins/page.html
Normal file
0
components/templates/src/builtins/section.html
Normal file
0
components/templates/src/builtins/section.html
Normal file
|
@ -20,6 +20,12 @@ lazy_static! {
|
||||||
pub static ref GUTENBERG_TERA: Tera = {
|
pub static ref GUTENBERG_TERA: Tera = {
|
||||||
let mut tera = Tera::default();
|
let mut tera = Tera::default();
|
||||||
tera.add_raw_templates(vec![
|
tera.add_raw_templates(vec![
|
||||||
|
// adding default built-ins templates for index/page/section so
|
||||||
|
// users don't get an error when they run gutenberg after init
|
||||||
|
("index.html", include_str!("builtins/index.html")),
|
||||||
|
("page.html", include_str!("builtins/page.html")),
|
||||||
|
("section.html", include_str!("builtins/section.html")),
|
||||||
|
|
||||||
("rss.xml", include_str!("builtins/rss.xml")),
|
("rss.xml", include_str!("builtins/rss.xml")),
|
||||||
("sitemap.xml", include_str!("builtins/sitemap.xml")),
|
("sitemap.xml", include_str!("builtins/sitemap.xml")),
|
||||||
("robots.txt", include_str!("builtins/robots.txt")),
|
("robots.txt", include_str!("builtins/robots.txt")),
|
||||||
|
|
|
@ -10,7 +10,7 @@ pub fn build_cli() -> App<'static, 'static> {
|
||||||
(@arg config: -c --config +takes_value "Path to a config file other than config.toml")
|
(@arg config: -c --config +takes_value "Path to a config file other than config.toml")
|
||||||
(@subcommand init =>
|
(@subcommand init =>
|
||||||
(about: "Create a new Gutenberg project")
|
(about: "Create a new Gutenberg project")
|
||||||
(@arg name: +required "Name of the project. Will create a directory with that name in the current directory")
|
(@arg name: +required "Name of the project. Will create a new directory with that name in the current directory")
|
||||||
)
|
)
|
||||||
(@subcommand build =>
|
(@subcommand build =>
|
||||||
(about: "Builds the site")
|
(about: "Builds the site")
|
||||||
|
|
|
@ -1,14 +1,23 @@
|
||||||
use std::fs::create_dir;
|
use std::fs::{create_dir, canonicalize};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
use errors::Result;
|
use errors::Result;
|
||||||
use utils::fs::create_file;
|
use utils::fs::create_file;
|
||||||
|
|
||||||
|
use prompt::{ask_bool, ask_url};
|
||||||
|
use console;
|
||||||
|
|
||||||
|
|
||||||
const CONFIG: &'static str = r#"
|
const CONFIG: &'static str = r#"
|
||||||
title = "My site"
|
# The URL the site will be built for
|
||||||
# replace the url below with yours
|
base_url = "%BASE_URL%"
|
||||||
base_url = "https://example.com"
|
|
||||||
|
# Whether to automatically compile all Sass files in the sass directory
|
||||||
|
compile_sass = %COMPILE_SASS%
|
||||||
|
|
||||||
|
# Whether to do syntax highlighting
|
||||||
|
# Theme can be customised by setting the `highlight_theme` variable to a theme supported by Gutenberg
|
||||||
|
highlight_code = %HIGHLIGHT%
|
||||||
|
|
||||||
[extra]
|
[extra]
|
||||||
# Put all your custom variables here
|
# Put all your custom variables here
|
||||||
|
@ -17,23 +26,38 @@ base_url = "https://example.com"
|
||||||
|
|
||||||
pub fn create_new_project(name: &str) -> Result<()> {
|
pub fn create_new_project(name: &str) -> Result<()> {
|
||||||
let path = Path::new(name);
|
let path = Path::new(name);
|
||||||
|
|
||||||
// Better error message than the rust default
|
// Better error message than the rust default
|
||||||
if path.exists() && path.is_dir() {
|
if path.exists() && path.is_dir() {
|
||||||
bail!("Folder `{}` already exists", path.to_string_lossy().to_string());
|
bail!("Folder `{}` already exists", path.to_string_lossy().to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
// main folder
|
|
||||||
create_dir(path)?;
|
create_dir(path)?;
|
||||||
create_file(&path.join("config.toml"), CONFIG.trim_left())?;
|
console::info("Welcome to Gutenberg!");
|
||||||
|
|
||||||
|
let base_url = ask_url("> What is the URL of your site?", "https://example.com")?;
|
||||||
|
let compile_sass = ask_bool("> Do you want to enable Sass compilation?", true)?;
|
||||||
|
let highlight = ask_bool("> Do you want to enable syntax highlighting?", false)?;
|
||||||
|
|
||||||
|
let config = CONFIG
|
||||||
|
.trim_left()
|
||||||
|
.replace("%BASE_URL%", &base_url)
|
||||||
|
.replace("%COMPILE_SASS%", &format!("{}", compile_sass))
|
||||||
|
.replace("%HIGHLIGHT%", &format!("{}", highlight));
|
||||||
|
|
||||||
|
create_file(&path.join("config.toml"), &config)?;
|
||||||
|
|
||||||
// content folder
|
|
||||||
create_dir(path.join("content"))?;
|
create_dir(path.join("content"))?;
|
||||||
|
|
||||||
// layouts folder
|
|
||||||
create_dir(path.join("templates"))?;
|
create_dir(path.join("templates"))?;
|
||||||
|
|
||||||
create_dir(path.join("static"))?;
|
create_dir(path.join("static"))?;
|
||||||
|
if compile_sass {
|
||||||
|
create_dir(path.join("sass"))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
println!();
|
||||||
|
console::success(&format!("Done! Your site was created in {:?}", canonicalize(path).unwrap()));
|
||||||
|
println!();
|
||||||
|
console::info("Get started by using the built-in server: `gutenberg serve`");
|
||||||
|
println!("There is no built-in theme so you will see a white page.");
|
||||||
|
println!("Visit https://github.com/Keats/gutenberg for the full documentation.");
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ extern crate staticfile;
|
||||||
extern crate iron;
|
extern crate iron;
|
||||||
extern crate mount;
|
extern crate mount;
|
||||||
extern crate notify;
|
extern crate notify;
|
||||||
|
extern crate url;
|
||||||
extern crate ws;
|
extern crate ws;
|
||||||
|
|
||||||
extern crate site;
|
extern crate site;
|
||||||
|
@ -21,6 +22,7 @@ mod cmd;
|
||||||
mod console;
|
mod console;
|
||||||
mod rebuild;
|
mod rebuild;
|
||||||
mod cli;
|
mod cli;
|
||||||
|
mod prompt;
|
||||||
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
@ -31,7 +33,7 @@ fn main() {
|
||||||
match matches.subcommand() {
|
match matches.subcommand() {
|
||||||
("init", Some(matches)) => {
|
("init", Some(matches)) => {
|
||||||
match cmd::create_new_project(matches.value_of("name").unwrap()) {
|
match cmd::create_new_project(matches.value_of("name").unwrap()) {
|
||||||
Ok(()) => console::success("Project created"),
|
Ok(()) => (),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
console::unravel_errors("Failed to create the project", &e);
|
console::unravel_errors("Failed to create the project", &e);
|
||||||
::std::process::exit(1);
|
::std::process::exit(1);
|
||||||
|
|
53
src/prompt.rs
Normal file
53
src/prompt.rs
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
use std::io::{self, Write, BufRead};
|
||||||
|
|
||||||
|
use url::Url;
|
||||||
|
|
||||||
|
use errors::Result;
|
||||||
|
|
||||||
|
/// Wait for user input and return what they typed
|
||||||
|
fn read_line() -> Result<String> {
|
||||||
|
let stdin = io::stdin();
|
||||||
|
let stdin = stdin.lock();
|
||||||
|
let mut lines = stdin.lines();
|
||||||
|
lines
|
||||||
|
.next()
|
||||||
|
.and_then(|l| l.ok())
|
||||||
|
.ok_or("unable to read from stdin for confirmation".into())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Ask a yes/no question to the user
|
||||||
|
pub fn ask_bool(question: &str, default: bool) -> Result<bool> {
|
||||||
|
print!("{} {}: ", question, if default { "[Y/n]" } else { "[y/N]" });
|
||||||
|
let _ = io::stdout().flush();
|
||||||
|
let input = read_line()?;
|
||||||
|
|
||||||
|
match &*input {
|
||||||
|
"y" | "Y" | "yes" | "YES" | "true" => Ok(true),
|
||||||
|
"n" | "N" | "no" | "NO" | "false" => Ok(false),
|
||||||
|
"" => Ok(default),
|
||||||
|
_ => {
|
||||||
|
println!("Invalid choice: '{}'", input);
|
||||||
|
ask_bool(question, default)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Ask a question to the user where they can write a URL
|
||||||
|
pub fn ask_url(question: &str, default: &str) -> Result<String> {
|
||||||
|
print!("{} ({}): ", question, default);
|
||||||
|
let _ = io::stdout().flush();
|
||||||
|
let input = read_line()?;
|
||||||
|
|
||||||
|
match &*input {
|
||||||
|
"" => Ok(default.to_string()),
|
||||||
|
_ => {
|
||||||
|
match Url::parse(&input) {
|
||||||
|
Ok(_) => Ok(input),
|
||||||
|
Err(_) => {
|
||||||
|
println!("Invalid URL: '{}'", input);
|
||||||
|
ask_url(question, default)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue