Add very basic site generator

This commit is contained in:
Sofia 2018-04-16 14:10:05 +03:00
commit 7249af10b8
18 changed files with 1087 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/target/

333
Cargo.lock generated Normal file
View File

@ -0,0 +1,333 @@
[[package]]
name = "aho-corasick"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "ansi_term"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "atty"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
"termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "bitflags"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "bitflags"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "clap"
version = "2.31.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"atty 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"textwrap 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"vec_map 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "getopts"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "lazy_static"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "libc"
version = "0.2.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "memchr"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "proc-macro2"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "pulldown-cmark"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"getopts 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "quote"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "redox_syscall"
version = "0.1.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "redox_termios"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "regex"
version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"regex-syntax 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
"thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
"utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "regex-syntax"
version = "0.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "serde"
version = "1.0.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "serde_derive"
version = "1.0.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive_internals 0.23.1 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "serde_derive_internals"
version = "0.23.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "strsim"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "structopt"
version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"clap 2.31.2 (registry+https://github.com/rust-lang/crates.io-index)",
"structopt-derive 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "structopt-derive"
version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "syn"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "teascade-generator"
version = "0.1.0"
dependencies = [
"pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)",
"structopt 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
"toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "termion"
version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "textwrap"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "thread_local"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "toml"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"serde 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "ucd-util"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "unicode-width"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "unicode-xid"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "unreachable"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "utf8-ranges"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "vec_map"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "void"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "winapi"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[metadata]
"checksum aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d6531d44de723825aa81398a6415283229725a00fa30713812ab9323faa82fc4"
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
"checksum atty 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "af80143d6f7608d746df1520709e5d141c96f240b0e62b0aa41bdfb53374d9d4"
"checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5"
"checksum bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf"
"checksum clap 2.31.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f0f16b89cbb9ee36d87483dc939fe9f1e13c05898d56d7b230a0d4dff033a536"
"checksum getopts 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)" = "b900c08c1939860ce8b54dc6a89e26e00c04c380fd0e09796799bd7f12861e05"
"checksum lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c8f31047daa365f19be14b47c29df4f7c3b581832407daabe6ae77397619237d"
"checksum libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)" = "6fd41f331ac7c5b8ac259b8bf82c75c0fb2e469bbf37d2becbba9a6a2221965b"
"checksum memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "796fba70e76612589ed2ce7f45282f5af869e0fdd7cc6199fa1aa1f1d591ba9d"
"checksum proc-macro2 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "49b6a521dc81b643e9a51e0d1cf05df46d5a2f3c0280ea72bcb68276ba64a118"
"checksum pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d6fdf85cda6cadfae5428a54661d431330b312bc767ddbc57adbedc24da66e32"
"checksum quote 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7b0ff51282f28dc1b53fd154298feaa2e77c5ea0dba68e1fd8b03b72fbe13d2a"
"checksum redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "0d92eecebad22b767915e4d529f89f28ee96dbbf5a4810d2b844373f136417fd"
"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76"
"checksum regex 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "aec3f58d903a7d2a9dc2bf0e41a746f4530e0cab6b615494e058f67a3ef947fb"
"checksum regex-syntax 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "bd90079345f4a4c3409214734ae220fd773c6f2e8a543d07370c6c1c369cfbfb"
"checksum serde 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)" = "4c36359ac1a823e00db02a243376ced650f088dc1f6259bbf828e4668e3c7399"
"checksum serde_derive 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)" = "f0477feff739386f5bca8e13fa43d96a4e834904d538f503906c8179f9205f50"
"checksum serde_derive_internals 0.23.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9d30c4596450fd7bbda79ef15559683f9a79ac0193ea819db90000d7e1cae794"
"checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550"
"checksum structopt 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1dbf9b178b64479997d9515aa4a6956ada20a9829fa03fee3bbcff5962e4e405"
"checksum structopt-derive 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "29040b33bfc5dae3a321f79cbcd86813a5f024e3040a31f057188e7f2b6228ba"
"checksum syn 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)" = "91b52877572087400e83d24b9178488541e3d535259e04ff17a63df1e5ceff59"
"checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096"
"checksum textwrap 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c0b59b6b4b44d867f1370ef1bd91bfb262bf07bf0ae65c202ea2fbc16153b693"
"checksum thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "279ef31c19ededf577bfd12dfae728040a21f635b06a24cd670ff510edd38963"
"checksum toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a0263c6c02c4db6c8f7681f9fd35e90de799ebd4cfdeab77a38f4ff6b3d8c0d9"
"checksum ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd2be2d6639d0f8fe6cdda291ad456e23629558d466e2789d2c3e9892bda285d"
"checksum unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bf3a113775714a22dcb774d8ea3655c53a32debae63a063acc00a91cc586245f"
"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
"checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56"
"checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122"
"checksum vec_map 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "887b5b631c2ad01628bbbaa7dd4c869f80d3186688f8d0b6f58774fbe324988c"
"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
"checksum winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "04e3bd221fcbe8a271359c04f21a76db7d0c6028862d1bb5512d85e1e2eb5bb3"
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"

12
Cargo.toml Normal file
View File

@ -0,0 +1,12 @@
[package]
name = "teascade-generator"
version = "0.1.0"
authors = ["Teascade <teascade@gmail.com>"]
[dependencies]
pulldown-cmark = "*"
toml = "*"
structopt = "*"
serde = "*"
serde_derive = "*"
regex = "*"

10
config.toml Normal file
View File

@ -0,0 +1,10 @@
[website]
website_name = "Test Website Name!"
built_pages = ["test_page.toml"]
use_default_css = true
javascript = []
css = []
#favicon = "path.png"
#twitter_author = "@teascade"
#google_robots = "all"
#google_site_verification = ""

2
content.md Normal file
View File

@ -0,0 +1,2 @@
# Test Header!
Some test content!

141
public/css/default.css Normal file
View File

@ -0,0 +1,141 @@
:root {
--color-main-bg: rgb(38, 40, 43);
--color-navbar-bg: rgb(52, 52, 56);
--color-navbar-button: rgb(50, 50, 53);
--color-navbar-button-hover: rgb(43, 43, 46);
--color-navbar-button-focus: rgb(44, 44, 48);
--color-navbar-border-bottom: rgb(41, 41, 44);
--color-content-bg: rgb(44, 44, 48);
--color-content-fg: rgb(164, 161, 172);
--navbar-height: 3.5vw;
--navbar-width: 60%;
--navbar-padding-size: 0.5em;
--navbar-text-size: 24px;
--content-width: 50%;
--content-text-size: 1.2em;
--content-top-padding: 2em;
--content-side-padding: 2em;
--highlight-color: rgb(230, 134, 217);
}
body, html {
width: 100%;
height: 100%;
padding: 0;
margin: 0;
font-family: Roboto, Helvetica, sans-serif;
background-color: var(--color-main-bg);
}
#text {
width: 100%;
margin: 0;
padding: 0;
}
/* Navbar styles */
nav {
width: 100%;
height: var(--navbar-height);
background-color: var(--color-navbar-bg);
border-bottom: solid 4px var(--color-navbar-border-bottom);
}
nav ul {
height: 100%;
font-size: 0;
margin: 0;
padding: 0;
list-style-type: none;
width: var(--navbar-width);
margin-left: auto;
margin-right: auto;
}
nav li {
height: 100%;
font-size: var(--navbar-text-size);
display: inline-block;
margin: 0;
}
nav li a {
display: block;
height: 100%;
background-color: var(--color-navbar-button);
color: var(--highlight-color);
text-decoration: none;
padding-left: var(--navbar-padding-size);
padding-right: var(--navbar-padding-size);
transition: 0.15s;
border-left: solid 3px var(--color-navbar-button-hover);
position: relative;
}
nav li:not(.image) a {
display: flex;
justify-content: center;
flex-direction: column;
}
nav li:first-child a {
border-left: solid 5px var(--color-navbar-button-hover);
}
nav li:last-child a {
border-right: solid 5px var(--color-navbar-button-hover);
}
nav ul a:hover {
background-color: var(--color-navbar-button-hover);
}
nav ul a:focus {
outline: none;
background-color: var(--color-navbar-button-focus);
}
/* Navbar images */
nav img {
height: var(--navbar-height);
vertical-align: top;
border: 50%;
}
nav li.image {
position: relative;
bottom: calc(var(--navbar-height) / 4);
padding: 0;
}
nav li.image a {
height: auto;
}
/* Article styles */
article {
width: var(--content-width);
min-height: calc(100% - var(--navbar-height) - var(--content-top-padding) - 4px);
margin: auto;
padding-top: var(--content-top-padding);
padding-left: var(--content-side-padding);
padding-right: var(--content-side-padding);
background-color: var(--color-content-bg);
color: var(--color-content-fg);
font-size: var(--content-text-size);
}
article > * {
margin: 0;
}
article a {
color: var(--highlight-color);
}

50
public/test.html Normal file
View File

@ -0,0 +1,50 @@
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="">
<meta charset="utf-8">
<meta name="robots" content="">
<meta name="google-site-verification" content="" />
<meta name="title" content="Test Website Name!">
<meta property="og:title" content="Test Page">
<meta property="og:site_name" content="Test Website Name!">
<meta property="og:type" content="website">
<meta property="og:description" content="">
<meta property="og:image" content="">
<meta property="og:image:secure_url" content="">
<meta property="og:image:type" content="image/png">
<meta property="og:image:width" content="512">
<meta property="og:image:height" content="512">
<meta name="twitter:site" content="">
<meta name="twitter:creator" content="">
<meta name="twitter:title" content="Test Page">
<meta name="twitter:description" content="">
<meta name="twitter:image" content="">
<link rel="stylesheet" href="css/default.css">
<link rel="shortcut icon" href=""></link>
<title>Test Page</title>
</head>
<body>
<nav>
<ul>
</ul>
</nav>
<article>
<h1>Test Header!</h1>
<p>Some test content!</p>
</article>
</body>
</html>

51
src/config.rs Normal file
View File

@ -0,0 +1,51 @@
use config_toml::{GlobalConfigToml, PageConfigToml};
use std::io::Error;
use std::path::PathBuf;
#[derive(Clone)]
pub struct SinglePageConfigs {
pub global_config: GlobalConfigToml,
pub page_config: PageConfigToml,
pub page_config_path: PathBuf,
}
#[derive(Debug)]
pub struct Config {
pub global_config: GlobalConfigToml,
pub page_config_paths: Vec<PathBuf>,
pub page_configs: Vec<PageConfigToml>,
}
impl Config {
pub fn new() -> Result<Config, Error> {
let global_config = GlobalConfigToml::get_config()?;
let mut page_configs = Vec::new();
let mut page_config_paths = Vec::new();
for page_config in global_config.clone().website.built_pages {
let path = PathBuf::from(page_config);
let config = PageConfigToml::get_from(&path)?;
page_configs.push(config);
page_config_paths.push(path);
}
Ok(Config {
global_config,
page_config_paths,
page_configs,
})
}
pub fn get_configs_for(&self, idx: u32) -> Result<SinglePageConfigs, String> {
if let (Some(page_config), Some(page_path)) = (
self.page_configs.get(idx as usize),
self.page_config_paths.get(idx as usize),
) {
Ok(SinglePageConfigs {
global_config: self.global_config.clone(),
page_config: page_config.clone(),
page_config_path: page_path.clone(),
})
} else {
Err(format!("Failed to get page config, idx: {}", idx))
}
}
}

94
src/config_toml.rs Normal file
View File

@ -0,0 +1,94 @@
use toml;
use std::path::PathBuf;
use std::fs::File;
use std::io::{Error, ErrorKind, Read};
#[derive(Deserialize, Clone, Debug)]
pub struct GlobalConfigToml {
pub website: WebsiteConfig,
}
#[derive(Deserialize, Clone, Debug)]
pub struct WebsiteConfig {
pub website_name: String,
pub built_pages: Vec<String>,
pub use_default_css: bool,
pub javascript: Vec<String>,
pub css: Vec<String>,
pub favicon: Option<String>,
pub twitter_author: Option<String>,
pub google_robots: Option<String>,
pub google_site_verification: Option<String>,
}
impl GlobalConfigToml {
pub fn get_config() -> Result<GlobalConfigToml, Error> {
let mut file = File::open("config.toml")?;
let mut contents = String::new();
file.read_to_string(&mut contents)?;
match toml::from_str(&contents) {
Ok(config) => Ok(config),
Err(err) => {
if let Some((line, col)) = err.line_col() {
Err(Error::new(
ErrorKind::Other,
format!("Erronous config.toml at {}:{}", line, col),
))
} else {
Err(Error::new(
ErrorKind::Other,
format!("Failed to parse config.toml correctly. Check variable names!"),
))
}
}
}
}
}
#[derive(Deserialize, Clone, Debug)]
pub struct PageConfigToml {
pub page: PageConfig,
}
impl PageConfigToml {
pub fn get_from(path: &PathBuf) -> Result<PageConfigToml, Error> {
let path_str = match path.to_str() {
Some(path_str) => path_str,
None => "",
};
let mut file = File::open(path.as_path())?;
let mut contents = String::new();
file.read_to_string(&mut contents)?;
match toml::from_str(&contents) {
Ok(config) => Ok(config),
Err(err) => {
if let Some((line, col)) = err.line_col() {
Err(Error::new(
ErrorKind::Other,
format!("Erronous toml: {} at {}:{}", path_str, line, col),
))
} else {
Err(Error::new(
ErrorKind::Other,
format!(
"Failed to parse toml correctly: {}. Check variable names!",
path_str
),
))
}
}
}
}
}
#[derive(Deserialize, Clone, Debug)]
pub struct PageConfig {
pub title: String,
pub description: String,
pub content_path: String,
pub favicon: Option<String>,
pub javascript: Option<Vec<String>>,
pub css: Option<Vec<String>>,
}

54
src/main.rs Normal file
View File

@ -0,0 +1,54 @@
extern crate pulldown_cmark;
extern crate regex;
#[macro_use]
extern crate serde_derive;
extern crate toml;
mod config_toml;
mod config;
mod template;
mod renderer;
use config::Config;
use template::Template;
use std::error::Error;
use std::fs::{create_dir_all, File};
use std::io::prelude::*;
const DEFAULT_CSS: &'static str = include_str!("templates/default-css.css");
const PAGE_TEMPLATE: &'static str = include_str!("templates/page-template.html");
fn main() {
println!("Fetching configs");
let config = match Config::new() {
Ok(config) => config,
Err(err) => panic!(err.description().to_owned()),
};
if config.global_config.website.use_default_css {
println!("Adding public/css/default.css");
create_dir_all("public/css").ok();
let mut file = File::create("public/css/default.css").unwrap();
file.write_all(DEFAULT_CSS.as_bytes()).ok();
}
println!("Generating page template");
let template = Template::new(PAGE_TEMPLATE);
println!("Rendering public/test.html");
let rendered = match config.get_configs_for(0) {
Ok(page_config) => template.render(&Template::page_data_from(
page_config.clone(),
renderer::render_markdown_content(&page_config).unwrap(),
)),
Err(err) => panic!(err),
};
println!("Writing public/test.html");
create_dir_all("public").ok();
let mut file = File::create("public/test.html").unwrap();
file.write_all(rendered.as_bytes()).ok();
println!("Done!");
}

29
src/renderer.rs Normal file
View File

@ -0,0 +1,29 @@
use std::fs::File;
use std::io::Read;
use pulldown_cmark::{html, Parser};
use config::SinglePageConfigs;
pub fn render_markdown_content(config: &SinglePageConfigs) -> Result<String, String> {
if let Some(parent) = config.page_config_path.parent() {
let path = parent.with_file_name(&config.page_config.page.content_path);
match File::open(&path) {
Ok(mut file) => {
let mut content = String::new();
file.read_to_string(&mut content).ok();
let parser = Parser::new(&content);
let mut markdown = String::new();
html::push_html(&mut markdown, parser);
Ok(markdown)
}
Err(_) => Err(format!("Failed to open file: {}", path.to_str().unwrap())),
}
} else {
Err(format!(
"Failed to get page config parent: {}",
config.page_config_path.to_str().unwrap()
))
}
}

105
src/template.rs Normal file
View File

@ -0,0 +1,105 @@
use regex::{Captures, Regex};
use std::collections::HashMap;
use config::SinglePageConfigs;
type Data = HashMap<String, String>;
macro_rules! hashmap {
( $( $x:expr => $y:expr ),* ) => {
{
let mut temp_map = HashMap::new();
$(
temp_map.insert($x, $y);
)*
temp_map
}
};
}
pub struct Template {
template: String,
regex: Regex,
if_regex: Regex,
}
impl Template {
pub fn new<T: Into<String>>(template: T) -> Template {
Template {
template: template.into(),
regex: Regex::new(r"\{\{(?P<to_replace>\w+)\}\}").unwrap(),
if_regex: Regex::new(
r"\{\{if (?P<boolean>\w+)\}\}(?P<rendered>(?:.|\n)*?)\{\{endif\}\}",
).unwrap(),
}
}
pub fn render(&self, data: &Data) -> String {
let template_clone = self.template.clone();
let result = (&*self.if_regex
.replace_all(&template_clone, |caps: &Captures| {
if let Some(value) = data.get(&caps["boolean"]) {
if value == "true" {
caps["rendered"].to_owned()
} else {
String::new()
}
} else {
String::new()
}
})).to_owned();
let result = (&*self.regex.replace_all(&result, |caps: &Captures| {
if let Some(text) = data.get(&caps["to_replace"]) {
format!("{}", text)
} else {
String::new()
}
})).to_owned();
result
}
pub fn page_data_from(config: SinglePageConfigs, content: String) -> Data {
let favicon = config.page_config.page.favicon.unwrap_or(
config
.global_config
.website
.favicon
.unwrap_or(String::new()),
);
let google_robots = config
.global_config
.website
.google_robots
.unwrap_or(String::new());
let google_verification = config
.global_config
.website
.google_site_verification
.unwrap_or(String::new());
let twitter_author = config
.global_config
.website
.twitter_author
.unwrap_or(String::new());
let map = hashmap!(
"website_name".to_owned() => config.global_config.website.website_name,
"page_title".to_owned() => config.page_config.page.title,
"favicon".to_owned() => favicon.to_owned(),
"google_robots".to_owned() => google_robots,
"google_verification".to_owned() => google_verification,
"twitter_author".to_owned() => twitter_author,
"use_default_css".to_owned() => config.global_config.website.use_default_css.to_string(),
"navbar".to_owned() => "true".to_owned(),
"content".to_owned() => content
);
map
}
}

View File

@ -0,0 +1,141 @@
:root {
--color-main-bg: rgb(38, 40, 43);
--color-navbar-bg: rgb(52, 52, 56);
--color-navbar-button: rgb(50, 50, 53);
--color-navbar-button-hover: rgb(43, 43, 46);
--color-navbar-button-focus: rgb(44, 44, 48);
--color-navbar-border-bottom: rgb(41, 41, 44);
--color-content-bg: rgb(44, 44, 48);
--color-content-fg: rgb(164, 161, 172);
--navbar-height: 3.5vw;
--navbar-width: 60%;
--navbar-padding-size: 0.5em;
--navbar-text-size: 24px;
--content-width: 50%;
--content-text-size: 1.2em;
--content-top-padding: 2em;
--content-side-padding: 2em;
--highlight-color: rgb(230, 134, 217);
}
body, html {
width: 100%;
height: 100%;
padding: 0;
margin: 0;
font-family: Roboto, Helvetica, sans-serif;
background-color: var(--color-main-bg);
}
#text {
width: 100%;
margin: 0;
padding: 0;
}
/* Navbar styles */
nav {
width: 100%;
height: var(--navbar-height);
background-color: var(--color-navbar-bg);
border-bottom: solid 4px var(--color-navbar-border-bottom);
}
nav ul {
height: 100%;
font-size: 0;
margin: 0;
padding: 0;
list-style-type: none;
width: var(--navbar-width);
margin-left: auto;
margin-right: auto;
}
nav li {
height: 100%;
font-size: var(--navbar-text-size);
display: inline-block;
margin: 0;
}
nav li a {
display: block;
height: 100%;
background-color: var(--color-navbar-button);
color: var(--highlight-color);
text-decoration: none;
padding-left: var(--navbar-padding-size);
padding-right: var(--navbar-padding-size);
transition: 0.15s;
border-left: solid 3px var(--color-navbar-button-hover);
position: relative;
}
nav li:not(.image) a {
display: flex;
justify-content: center;
flex-direction: column;
}
nav li:first-child a {
border-left: solid 5px var(--color-navbar-button-hover);
}
nav li:last-child a {
border-right: solid 5px var(--color-navbar-button-hover);
}
nav ul a:hover {
background-color: var(--color-navbar-button-hover);
}
nav ul a:focus {
outline: none;
background-color: var(--color-navbar-button-focus);
}
/* Navbar images */
nav img {
height: var(--navbar-height);
vertical-align: top;
border: 50%;
}
nav li.image {
position: relative;
bottom: calc(var(--navbar-height) / 4);
padding: 0;
}
nav li.image a {
height: auto;
}
/* Article styles */
article {
width: var(--content-width);
min-height: calc(100% - var(--navbar-height) - var(--content-top-padding) - 4px);
margin: auto;
padding-top: var(--content-top-padding);
padding-left: var(--content-side-padding);
padding-right: var(--content-side-padding);
background-color: var(--color-content-bg);
color: var(--color-content-fg);
font-size: var(--content-text-size);
}
article > * {
margin: 0;
}
article a {
color: var(--highlight-color);
}

View File

@ -0,0 +1,6 @@
<li class="image">
<a href="{{link}}">
<img src="{{image}}" alt="{{image-alt}}">
</img>
</a>
</li>

View File

@ -0,0 +1,3 @@
<li>
<a href="{{link}}">{{name}}</a>
</li>

View File

@ -0,0 +1,48 @@
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="{{page_description}}">
<meta charset="utf-8">
<meta name="robots" content="{{google_robots}}">
<meta name="google-site-verification" content="{{google_verification}}" />
<meta name="title" content="{{website_name}}">
<meta property="og:title" content="{{page_title}}">
<meta property="og:site_name" content="{{website_name}}">
<meta property="og:type" content="website">
<meta property="og:description" content="{{page_description}}">
<meta property="og:image" content="{{favicon}}">
<meta property="og:image:secure_url" content="{{favicon}}">
<meta property="og:image:type" content="image/png">
<meta property="og:image:width" content="512">
<meta property="og:image:height" content="512">
<meta name="twitter:site" content="{{twitter_author}}">
<meta name="twitter:creator" content="{{twitter_author}}">
<meta name="twitter:title" content="{{page_title}}">
<meta name="twitter:description" content="{{page_description}}">
<meta name="twitter:image" content="{{favicon}}"> {{if use_default_css}}
<link rel="stylesheet" href="css/default.css"> {{endif}} {{css_links}}{{javascript_links}}
<link rel="shortcut icon" href="{{favicon}}"></link>
<title>{{page_title}}</title>
</head>
<body>
{{if navbar}}
<nav>
<ul>
{{items}}
</ul>
</nav>
{{endif}}
<article>
{{content}}
</article>
</body>
</html>

BIN
src/templates/test.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

7
test_page.toml Normal file
View File

@ -0,0 +1,7 @@
[page]
title = "Test Page"
description = "This is a test page."
content_path = "content.md"
#favicon = "optional_favicon.png"
#javascript = ["Additional JavaScript"]
#css = ["Additional CSS"]