commit 7249af10b8bc0b768fd153e1a4798451b949be15 Author: Teascade Date: Mon Apr 16 14:10:05 2018 +0300 Add very basic site generator diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a6f89c2 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target/ \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..85ee2f0 --- /dev/null +++ b/Cargo.lock @@ -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" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..550ba70 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "teascade-generator" +version = "0.1.0" +authors = ["Teascade "] + +[dependencies] +pulldown-cmark = "*" +toml = "*" +structopt = "*" +serde = "*" +serde_derive = "*" +regex = "*" diff --git a/config.toml b/config.toml new file mode 100644 index 0000000..19052d5 --- /dev/null +++ b/config.toml @@ -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 = "" \ No newline at end of file diff --git a/content.md b/content.md new file mode 100644 index 0000000..2e85b51 --- /dev/null +++ b/content.md @@ -0,0 +1,2 @@ +# Test Header! +Some test content! \ No newline at end of file diff --git a/public/css/default.css b/public/css/default.css new file mode 100644 index 0000000..ce5581f --- /dev/null +++ b/public/css/default.css @@ -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); +} \ No newline at end of file diff --git a/public/test.html b/public/test.html new file mode 100644 index 0000000..ee72fff --- /dev/null +++ b/public/test.html @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Test Page + + + + + + +
+

Test Header!

+

Some test content!

+ +
+ + + \ No newline at end of file diff --git a/src/config.rs b/src/config.rs new file mode 100644 index 0000000..864dfc8 --- /dev/null +++ b/src/config.rs @@ -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, + pub page_configs: Vec, +} + +impl Config { + pub fn new() -> Result { + 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 { + 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)) + } + } +} diff --git a/src/config_toml.rs b/src/config_toml.rs new file mode 100644 index 0000000..4544977 --- /dev/null +++ b/src/config_toml.rs @@ -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, + pub use_default_css: bool, + pub javascript: Vec, + pub css: Vec, + pub favicon: Option, + pub twitter_author: Option, + pub google_robots: Option, + pub google_site_verification: Option, +} + +impl GlobalConfigToml { + pub fn get_config() -> Result { + 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 { + 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, + pub javascript: Option>, + pub css: Option>, +} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..d26af7c --- /dev/null +++ b/src/main.rs @@ -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!"); +} diff --git a/src/renderer.rs b/src/renderer.rs new file mode 100644 index 0000000..dedf957 --- /dev/null +++ b/src/renderer.rs @@ -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 { + 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() + )) + } +} diff --git a/src/template.rs b/src/template.rs new file mode 100644 index 0000000..e84ad0f --- /dev/null +++ b/src/template.rs @@ -0,0 +1,105 @@ +use regex::{Captures, Regex}; + +use std::collections::HashMap; + +use config::SinglePageConfigs; + +type Data = HashMap; + +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>(template: T) -> Template { + Template { + template: template.into(), + regex: Regex::new(r"\{\{(?P\w+)\}\}").unwrap(), + if_regex: Regex::new( + r"\{\{if (?P\w+)\}\}(?P(?:.|\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 + } +} diff --git a/src/templates/default-css.css b/src/templates/default-css.css new file mode 100644 index 0000000..ce5581f --- /dev/null +++ b/src/templates/default-css.css @@ -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); +} \ No newline at end of file diff --git a/src/templates/navbar/navbar-image-item-template.html b/src/templates/navbar/navbar-image-item-template.html new file mode 100644 index 0000000..71ed53a --- /dev/null +++ b/src/templates/navbar/navbar-image-item-template.html @@ -0,0 +1,6 @@ +
  • + + {{image-alt}} + + +
  • \ No newline at end of file diff --git a/src/templates/navbar/navbar-item-template.html b/src/templates/navbar/navbar-item-template.html new file mode 100644 index 0000000..ff5b06d --- /dev/null +++ b/src/templates/navbar/navbar-item-template.html @@ -0,0 +1,3 @@ +
  • + {{name}} +
  • \ No newline at end of file diff --git a/src/templates/page-template.html b/src/templates/page-template.html new file mode 100644 index 0000000..408e2f5 --- /dev/null +++ b/src/templates/page-template.html @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + {{if use_default_css}} + {{endif}} {{css_links}}{{javascript_links}} + + + + {{page_title}} + + + + {{if navbar}} + + {{endif}} +
    + {{content}} +
    + + + \ No newline at end of file diff --git a/src/templates/test.png b/src/templates/test.png new file mode 100644 index 0000000..e263d2b Binary files /dev/null and b/src/templates/test.png differ diff --git a/test_page.toml b/test_page.toml new file mode 100644 index 0000000..57960b8 --- /dev/null +++ b/test_page.toml @@ -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"] \ No newline at end of file