├── .editorconfig ├── .gitattributes ├── .gitignore ├── LICENSE ├── Makefile ├── README.adoc ├── chercan ├── build.wren └── config.wren ├── content ├── asciidoc.wren ├── asciidoc │ ├── asciidoc.adoc │ └── asciidoc.html ├── index.wren ├── index │ └── index.html ├── tags.wren └── tags │ ├── other.wren.html │ └── tags.wren.html ├── docs ├── .nojekyll ├── asciidoc.html ├── index.html ├── normalize.css ├── sakura-vader.css └── tags.html ├── run ├── static ├── .nojekyll ├── normalize.css └── sakura-vader.css └── themes └── default ├── default.wren.html ├── home.wren.html └── partials ├── footer.wren.html ├── header.wren.html └── header2.wren.html /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_size = 2 5 | indent_style = space 6 | insert_final_newline = true 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | 11 | [Makefile] 12 | indent_style = tab 13 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | $ cat .gitattributes 2 | * text=auto 3 | *.wren linguist-language=JavaScript 4 | *.wren linguist-vendored 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | wren 3 | dist/ 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Ninjas.cl 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | WREN_VERSION = 0.3.0 2 | DIST = docs 3 | 4 | .PHONY: build asciidoc build-all serve wren-macos wren-linux 5 | 6 | ba build-all: 7 | @make asciidoc 8 | @make build 9 | 10 | b build: 11 | # Prepare the build dir 12 | @rm -rf dist/ 13 | @mkdir -p dist/ 14 | @cp -a static/ dist/ 15 | # Find all the content files and pass them to the build without extension 16 | # Only supports root level files. Because Wren CLI does not have mkdir yet. 17 | # https://unix.stackexchange.com/a/283915 18 | @find content -maxdepth 1 -name "*.wren" | rev | cut -f 2- -d "." | rev | xargs -I{} ./wren chercan/build.wren {} 19 | 20 | # Github pages 21 | @rm -rf ${DIST} 22 | @mv -f dist ${DIST} 23 | 24 | a asciidoc: 25 | # Compile all asciidoc files first 26 | @find content -maxdepth 2 -name "*.adoc" | xargs asciidoctor 27 | 28 | s serve: 29 | @make build 30 | python3 -m http.server -d ${DIST} 31 | 32 | wm wren-macos: 33 | @wget https://github.com/wren-lang/wren-cli/releases/download/${WREN_VERSION}/wren_cli-mac-${WREN_VERSION}.zip 34 | @unzip -o wren_cli-mac-${WREN_VERSION}.zip 35 | @rm -f wren_cli-mac-${WREN_VERSION}.zip 36 | @rm -f readme.md 37 | @mv wren_cli wren 38 | @ls 39 | 40 | wl wren-linux: 41 | @wget https://github.com/wren-lang/wren-cli/releases/download/${WREN_VERSION}/wren_cli-linux-${WREN_VERSION}.zip 42 | @unzip -o wren_cli-linux-${WREN_VERSION}.zip 43 | @rm -f wren_cli-linux-${WREN_VERSION}.zip 44 | @rm -f wren_cli-linux-${WREN_VERSION}/readme.md 45 | @mv wren_cli-linux-${WREN_VERSION}/wren_cli wren 46 | @rm -rf wren_cli-linux-${WREN_VERSION} 47 | @ls 48 | -------------------------------------------------------------------------------- /README.adoc: -------------------------------------------------------------------------------- 1 | :ext-relative: 2 | :toc: macro 3 | :toclevels: 4 4 | 5 | # https://en.wikipedia.org/wiki/House_wren[Chercan] Static Site Generator 6 | 7 | A simple https://en.wikipedia.org/wiki/Static_web_page[static site generator] using https://wren.io[Wren] programming language. 8 | 9 | image:https://user-images.githubusercontent.com/292738/100270183-730e7980-2f36-11eb-88f6-b2a1929e23b9.png[https://www.avesdechile.cl/074.htm] 10 | 11 | https://ninjas.cl[image:https://img.shields.io/badge/Ninjas-CL-green.svg?style=flat-square[Ninjas.cl]] 12 | 13 | toc::[] 14 | 15 | ## Dependencies 16 | 17 | Just https://github.com/wren-lang/wren-cli[_Wren CLI_] is needed. (Although _Python3_ is used for local server mode.). 18 | 19 | - Installation: 20 | - MacOS: `make wren-macos` 21 | - Linux: `make wren-linux` 22 | 23 | ## 👩‍💻 Structure 24 | 25 | ```sh 26 | . 27 | ├── LICENSE 28 | ├── Makefile 29 | ├── README.adoc 30 | ├── chercan 31 | │   ├── build.wren 32 | │   └── config.wren 33 | ├── content 34 | │   ├── hello 35 | │   │   ├── hello.adoc 36 | │   │   └── hello.html 37 | │   ├── hello.wren 38 | │   └── index.wren 39 | ├── docs 40 | │   ├── hello.html 41 | │   ├── index.html 42 | │   ├── normalize.css 43 | │   └── sakura-vader.css 44 | ├── static 45 | │   ├── normalize.css 46 | │   └── sakura-vader.css 47 | ├── themes 48 | │   └── default 49 | │   ├── default.wren.html 50 | │   ├── home.wren.html 51 | │   └── partials 52 | │   ├── footer.wren.html 53 | │   └── header.wren.html 54 | └── wren 55 | └── run 56 | ``` 57 | 58 | ## 🚀 Usage 59 | 60 | Create your files inside `content`. Only root level `*.wren` files supported for now (_Wren CLI_ limitations). 61 | 62 | - `./run new `: It will create a new _wren_ file inside `content`. 63 | 64 | - `./run new:adoc `: It will create a new filename with its _*.wren_ and _*.adoc_ inside `content`. 65 | 66 | - `./run build`: It will execute `make build`. (Builds _wren_ files). 67 | 68 | - `./run build:adoc`: It would only build _asciidoc_ files. (Requires https://asciidoctor.org/[AsciiDoctor]). 69 | 70 | - `./run build:all`: It will execute `make build-all` (Builds _wren_ and _asciidoc_ files). 71 | 72 | - `./run serve`: It will execute `make serve`. (Requires _Python3_). 73 | 74 | ### Asciidoc 75 | 76 | You could also create a _directory_ with https://asciidoctor.org/[Asciidoc] files and use the html output to append it to the file contents. It must have the same name as the _Wren_ file. 77 | 78 | - Example _Page_: 79 | 80 | ```js 81 | 82 | class Page { 83 | static title {"Hello Chercan"} 84 | static content {Asciidoc.read()} 85 | } 86 | 87 | return Page 88 | 89 | ``` 90 | 91 | ### Themes 92 | 93 | You can create your own _themes_. They are just _Wren_ files 94 | that uses _Wren tags_ ``. You have all the _Wren_ power 95 | in these templates. 96 | 97 | Name them as `.wren.html`. Configure the default _theme_ in `chercan/config.wren`. 98 | 99 | #### Example 100 | ```html 101 | 102 | 103 | 104 | 105 | 106 | 107 |

108 | 109 | 110 |

111 | 112 | 113 | ``` 114 | 115 | ### Static 116 | 117 | The `static` directory would contain any files (images, css, etc). They would be copied to the output directory. 118 | 119 | ## 📘 LICENSE 120 | MIT 121 | 122 | ## 🤩 Credits 123 | 124 | ++++ 125 |

126 | Made with by 127 | 128 | Ninjas.cl 129 | . 130 |

131 | ++++ 132 | -------------------------------------------------------------------------------- /chercan/build.wren: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env wren 2 | 3 | import "os" for Process 4 | import "io" for File 5 | import "meta" for Meta 6 | 7 | import "./config" for Config 8 | 9 | if (!Process.arguments[0]) { 10 | Fiber.abort("Need filepath. None given.") 11 | } 12 | 13 | var Path = Process.arguments[0].toString 14 | var filename = Path + ".wren" 15 | 16 | if (!File.exists(filename)) { 17 | Fiber.abort("File %(filename) does not exists") 18 | } 19 | 20 | // this is the echo function inside templates 21 | // use it to output content to the final preprocessed template 22 | var echoes_ = [] 23 | var echo = Fn.new {|body| 24 | if (body) { 25 | echoes_.add(body.toString) 26 | } 27 | } 28 | 29 | // Preprocessor for Wren tag files 30 | var TagNeedle = "" 33 | var TagExtension = "wren.html" 34 | var handlers = { 35 | TagNeedleEchoWrapper: Fn.new{|content| "echo.call(%(content))"} 36 | } 37 | 38 | var Preprocess = Fn.new {|content, index, needle, needleEnd| 39 | 40 | var start = content.indexOf(needle, index) 41 | index = start 42 | 43 | var end = content.indexOf(needleEnd, start) 44 | var code = content[start + needle.count...end] 45 | 46 | var eval = code 47 | if (handlers[needle]) { 48 | eval = handlers[needle].call(code) 49 | } 50 | 51 | // Execute the code contents 52 | Meta.compile(eval).call() 53 | 54 | // Build the final echo string 55 | var out = echoes_.join("").toString 56 | 57 | // Reset echo item bag 58 | // So the output of each tag is isolated 59 | echoes_ = [] 60 | 61 | return [content.replace(needle + code + needleEnd, out), index] 62 | } 63 | 64 | var ReplaceTags = Fn.new{|content, needle, needleEnd| 65 | // Search for all instances of tags 66 | var tagCount = content.split(needle).count - 1 67 | var processed = 0 68 | var index = 0 69 | var result = null 70 | 71 | // Preprocess each tag until done 72 | while (processed < tagCount) { 73 | result = Preprocess.call(content, index, needle, needleEnd) 74 | content = result[0].trimStart() 75 | index = result[1] 76 | processed = processed + 1 77 | 78 | // Clean echo bag just to be sure 79 | echoes_ = [] 80 | } 81 | return content 82 | } 83 | 84 | var import_ = Fn.new {|path| 85 | var extension_ = "." + TagExtension 86 | var content = File.read(path + extension_) 87 | content = ReplaceTags.call(content, TagNeedle, TagNeedleEnd) 88 | content = ReplaceTags.call(content, TagNeedleEchoWrapper, TagNeedleEnd) 89 | return content 90 | } 91 | 92 | // Include a file inside themes using this function 93 | var include = Fn.new{|path| import_.call("./themes/%(Config.theme)/" + path)} 94 | 95 | // Require a file inside the content/directory path using this function 96 | var require = Fn.new{|name| import_.call(Path + "/" + name)} 97 | 98 | // Content Helpers 99 | class Content { 100 | static read(file) { 101 | var doc = Path + "/" + file 102 | if (!File.exists(doc)) { 103 | Fiber.abort(doc + " does not exists") 104 | } 105 | var content = File.read(doc) 106 | return content 107 | } 108 | 109 | static read() { 110 | var dir = Path.replace("content/", "") 111 | return Content.read(dir + ".html") 112 | } 113 | 114 | static render(file) { 115 | var content = Content.read(file) 116 | content = ReplaceTags.call(content, TagNeedle, TagNeedleEnd) 117 | content = ReplaceTags.call(content, TagNeedleEchoWrapper, TagNeedleEnd) 118 | return content 119 | } 120 | 121 | static render() { 122 | var dir = Path.replace("content/", "") 123 | return Content.render(dir + ".wren.html") 124 | } 125 | 126 | static adoc(file) { 127 | var content = Content.read(file) 128 | var needle = "" 129 | var start = content.indexOf(needle) + needle.count 130 | var end = content.indexOf("") 131 | return content[start...end] 132 | } 133 | 134 | static adoc() { 135 | var dir = Path.replace("content/", "") 136 | return Content.adoc(dir + ".html") 137 | } 138 | } 139 | 140 | class Asciidoc { 141 | static read() { 142 | return Content.adoc() 143 | } 144 | 145 | static read(file) { 146 | return Content.adoc(file) 147 | } 148 | } 149 | 150 | // This will be available inside templates using this object 151 | var page = Meta.compile(File.read(filename)).call() 152 | 153 | var tpl = Config.template.default 154 | Fiber.new { 155 | if (page.template.toString.trim().count > 0) { 156 | tpl = page.template.toString 157 | } 158 | }.try() 159 | 160 | // Output final file 161 | // If *.wren file is on inner dir this would fail 162 | // wren-cli cannot create directories 163 | 164 | var out = include.call(tpl) 165 | var outname = Path.replace("content/", "") + ".html" 166 | var outpath = Config.out + "/" + outname 167 | 168 | var rendered = File.create(outpath) 169 | rendered.writeBytes(out) 170 | -------------------------------------------------------------------------------- /chercan/config.wren: -------------------------------------------------------------------------------- 1 | 2 | class Template { 3 | // Which template to use if none is given 4 | // default.wren.html 5 | static default {"default"} 6 | } 7 | 8 | class Config { 9 | // Sets the default theme 10 | static theme {"default"} 11 | 12 | static template {Template} 13 | 14 | // Sets the build output dir 15 | static out {"dist"} 16 | } 17 | -------------------------------------------------------------------------------- /content/asciidoc.wren: -------------------------------------------------------------------------------- 1 | 2 | class Page { 3 | static title {"Hello Chercán"} 4 | 5 | // Include an Asciidoc render html 6 | static content {Content.adoc()} 7 | 8 | static myprop {"This is a special property available just to themes/default/home.wren.html"} 9 | 10 | // Selecting other value as the base template 11 | static template {"home"} 12 | } 13 | 14 | return Page 15 | -------------------------------------------------------------------------------- /content/asciidoc/asciidoc.adoc: -------------------------------------------------------------------------------- 1 | ## Hello Wren 2 | This is a document created using _asciidoctor_ 3 | -------------------------------------------------------------------------------- /content/asciidoc/asciidoc.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Hello Wren 9 | 10 | 438 | 439 | 440 | 442 |
443 |
444 |

Hello Wren

445 |
446 |
447 |

This is a document created using asciidoctor

448 |
449 |
450 |
451 |
452 | 457 | 458 | -------------------------------------------------------------------------------- /content/index.wren: -------------------------------------------------------------------------------- 1 | 2 | class Page { 3 | static title {"Welcome to Chercan Static Site Generator"} 4 | 5 | // Include a normal html file 6 | static content {Content.read()} 7 | } 8 | 9 | return Page 10 | -------------------------------------------------------------------------------- /content/index/index.html: -------------------------------------------------------------------------------- 1 |

Welcome to Chercan Static Site Generator

2 |

This is an example generated page

3 | 4 |

Wren is a small, fast, class-based concurrent scripting language

5 |
6 |

Think Smalltalk in a Lua-sized package with a dash of Erlang and wrapped up in 7 | a familiar, modern syntax.

8 |
 9 | System.print("Hello, world!")
10 | 
11 | class Wren {
12 |   flyTo(city) {
13 |     System.print("Flying to %(city)")
14 |   }
15 | }
16 | 
17 | var adjectives = Fiber.new {
18 |   ["small", "clean", "fast"].each {|word| Fiber.yield(word) }
19 | }
20 | 
21 | while (!adjectives.isDone) System.print(adjectives.call())
22 | 
23 | 24 | 30 | -------------------------------------------------------------------------------- /content/tags.wren: -------------------------------------------------------------------------------- 1 | 2 | class Page { 3 | static title {"Content with Wren Tags"} 4 | 5 | // Include Wren tags html file 6 | static content {Content.render()} 7 | } 8 | 9 | return Page 10 | -------------------------------------------------------------------------------- /content/tags/other.wren.html: -------------------------------------------------------------------------------- 1 | 2 |

3 | This Content was included using `require.call()` inside an automatic `echo.call()` tag. 4 |

5 | -------------------------------------------------------------------------------- /content/tags/tags.wren.html: -------------------------------------------------------------------------------- 1 |

2 | This is an example using 3 | 4 |

5 |

6 | 7 |

8 | 9 | -------------------------------------------------------------------------------- /docs/.nojekyll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NinjasCL/chercan/501db9c6cb2f7c95764dd0621d43aefb61d5c90a/docs/.nojekyll -------------------------------------------------------------------------------- /docs/asciidoc.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Another Header · Hello Chercán 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 15 |
16 |
17 |

Hello Wren

18 |
19 |
20 |

This is a document created using asciidoctor

21 |
22 |
23 |
24 |
25 | 30 | 31 | 32 | This is a special property available just to themes/default/home.wren.html 33 | 34 |
35 | 36 |

You can use any valid Wren Code

37 | 38 |
    39 |
  • Item Nº 1
  • Item Nº 2
  • Item Nº 3
  • Item Nº 4
  • Item Nº 5
  • 40 |
41 | 42 |
43 | 44 |

45 | <?= footer ?> is the same as writing <?wren echo.call(footer) ?> 46 |

47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Welcome to Chercan Static Site Generator 6 | 7 | 8 | 9 | 10 | 11 | 12 |

Welcome to Chercan Static Site Generator

13 |

This is an example generated page

14 | 15 |

Wren is a small, fast, class-based concurrent scripting language

16 |
17 |

Think Smalltalk in a Lua-sized package with a dash of Erlang and wrapped up in 18 | a familiar, modern syntax.

19 |
20 | System.print("Hello, world!")
21 | 
22 | class Wren {
23 |   flyTo(city) {
24 |     System.print("Flying to %(city)")
25 |   }
26 | }
27 | 
28 | var adjectives = Fiber.new {
29 |   ["small", "clean", "fast"].each {|word| Fiber.yield(word) }
30 | }
31 | 
32 | while (!adjectives.isDone) System.print(adjectives.call())
33 | 
34 | 35 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /docs/normalize.css: -------------------------------------------------------------------------------- 1 | /*! normalize.css v5.0.0 | MIT License | github.com/necolas/normalize.css */ 2 | html { 3 | font-family: sans-serif; 4 | line-height: 1.15; 5 | -ms-text-size-adjust: 100%; 6 | -webkit-text-size-adjust: 100%; 7 | } 8 | body { 9 | margin: 0; 10 | } 11 | article, 12 | aside, 13 | footer, 14 | header, 15 | nav, 16 | section { 17 | display: block; 18 | } 19 | h1 { 20 | font-size: 2em; 21 | margin: 0.67em 0; 22 | } 23 | figcaption, 24 | figure, 25 | main { 26 | display: block; 27 | } 28 | figure { 29 | margin: 1em 40px; 30 | } 31 | hr { 32 | box-sizing: content-box; 33 | height: 0; 34 | overflow: visible; 35 | } 36 | pre { 37 | font-family: monospace, monospace; 38 | font-size: 1em; 39 | } 40 | a { 41 | background-color: transparent; 42 | -webkit-text-decoration-skip: objects; 43 | } 44 | a:active, 45 | a:hover { 46 | outline-width: 0; 47 | } 48 | abbr[title] { 49 | border-bottom: none; 50 | text-decoration: underline; 51 | text-decoration: underline dotted; 52 | } 53 | b, 54 | strong { 55 | font-weight: inherit; 56 | } 57 | b, 58 | strong { 59 | font-weight: bolder; 60 | } 61 | code, 62 | kbd, 63 | samp { 64 | font-family: monospace, monospace; 65 | font-size: 1em; 66 | } 67 | dfn { 68 | font-style: italic; 69 | } 70 | mark { 71 | background-color: #ff0; 72 | color: #000; 73 | } 74 | small { 75 | font-size: 80%; 76 | } 77 | sub, 78 | sup { 79 | font-size: 75%; 80 | line-height: 0; 81 | position: relative; 82 | vertical-align: baseline; 83 | } 84 | sub { 85 | bottom: -0.25em; 86 | } 87 | sup { 88 | top: -0.5em; 89 | } 90 | audio, 91 | video { 92 | display: inline-block; 93 | } 94 | audio:not([controls]) { 95 | display: none; 96 | height: 0; 97 | } 98 | img { 99 | border-style: none; 100 | } 101 | svg:not(:root) { 102 | overflow: hidden; 103 | } 104 | button, 105 | input, 106 | optgroup, 107 | select, 108 | textarea { 109 | font-family: sans-serif; 110 | font-size: 100%; 111 | line-height: 1.15; 112 | margin: 0; 113 | } 114 | button, 115 | input { 116 | overflow: visible; 117 | } 118 | button, 119 | select { 120 | text-transform: none; 121 | } 122 | [type="reset"], 123 | [type="submit"], 124 | button, 125 | html [type="button"] { 126 | -webkit-appearance: button; 127 | } 128 | [type="button"]::-moz-focus-inner, 129 | [type="reset"]::-moz-focus-inner, 130 | [type="submit"]::-moz-focus-inner, 131 | button::-moz-focus-inner { 132 | border-style: none; 133 | padding: 0; 134 | } 135 | [type="button"]:-moz-focusring, 136 | [type="reset"]:-moz-focusring, 137 | [type="submit"]:-moz-focusring, 138 | button:-moz-focusring { 139 | outline: 1px dotted ButtonText; 140 | } 141 | fieldset { 142 | border: 1px solid silver; 143 | margin: 0 2px; 144 | padding: 0.35em 0.625em 0.75em; 145 | } 146 | legend { 147 | box-sizing: border-box; 148 | color: inherit; 149 | display: table; 150 | max-width: 100%; 151 | padding: 0; 152 | white-space: normal; 153 | } 154 | progress { 155 | display: inline-block; 156 | vertical-align: baseline; 157 | } 158 | textarea { 159 | overflow: auto; 160 | } 161 | [type="checkbox"], 162 | [type="radio"] { 163 | box-sizing: border-box; 164 | padding: 0; 165 | } 166 | [type="number"]::-webkit-inner-spin-button, 167 | [type="number"]::-webkit-outer-spin-button { 168 | height: auto; 169 | } 170 | [type="search"] { 171 | -webkit-appearance: textfield; 172 | outline-offset: -2px; 173 | } 174 | [type="search"]::-webkit-search-cancel-button, 175 | [type="search"]::-webkit-search-decoration { 176 | -webkit-appearance: none; 177 | } 178 | ::-webkit-file-upload-button { 179 | -webkit-appearance: button; 180 | font: inherit; 181 | } 182 | details, 183 | menu { 184 | display: block; 185 | } 186 | summary { 187 | display: list-item; 188 | } 189 | canvas { 190 | display: inline-block; 191 | } 192 | template { 193 | display: none; 194 | } 195 | [hidden] { 196 | display: none; 197 | } 198 | -------------------------------------------------------------------------------- /docs/sakura-vader.css: -------------------------------------------------------------------------------- 1 | /* $color-text: #dedce5; */ 2 | /* Sakura.css v1.3.1 3 | * ================ 4 | * Minimal css theme. 5 | * Project: https://github.com/oxalorg/sakura/ 6 | */ 7 | /* Body */ 8 | html { 9 | font-size: 62.5%; 10 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, 11 | "Helvetica Neue", Arial, "Noto Sans", sans-serif; 12 | } 13 | 14 | body { 15 | font-size: 1.8rem; 16 | line-height: 1.618; 17 | max-width: 38em; 18 | margin: auto; 19 | color: #d9d8dc; 20 | background-color: #120c0e; 21 | padding: 13px; 22 | } 23 | 24 | @media (max-width: 684px) { 25 | body { 26 | font-size: 1.53rem; 27 | } 28 | } 29 | 30 | @media (max-width: 382px) { 31 | body { 32 | font-size: 1.35rem; 33 | } 34 | } 35 | 36 | h1, 37 | h2, 38 | h3, 39 | h4, 40 | h5, 41 | h6 { 42 | line-height: 1.1; 43 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, 44 | "Helvetica Neue", Arial, "Noto Sans", sans-serif; 45 | font-weight: 700; 46 | margin-top: 3rem; 47 | margin-bottom: 1.5rem; 48 | overflow-wrap: break-word; 49 | word-wrap: break-word; 50 | -ms-word-break: break-all; 51 | word-break: break-word; 52 | } 53 | 54 | h1 { 55 | font-size: 2.35em; 56 | } 57 | 58 | h2 { 59 | font-size: 2em; 60 | } 61 | 62 | h3 { 63 | font-size: 1.75em; 64 | } 65 | 66 | h4 { 67 | font-size: 1.5em; 68 | } 69 | 70 | h5 { 71 | font-size: 1.25em; 72 | } 73 | 74 | h6 { 75 | font-size: 1em; 76 | } 77 | 78 | p { 79 | margin-top: 0px; 80 | margin-bottom: 2.5rem; 81 | } 82 | 83 | small, 84 | sub, 85 | sup { 86 | font-size: 75%; 87 | } 88 | 89 | hr { 90 | border-color: #eb99a1; 91 | } 92 | 93 | a { 94 | text-decoration: none; 95 | color: #eb99a1; 96 | } 97 | a:hover { 98 | color: #da4453; 99 | border-bottom: 2px solid #d9d8dc; 100 | } 101 | a:visited { 102 | color: #e26f7a; 103 | } 104 | 105 | ul { 106 | padding-left: 1.4em; 107 | margin-top: 0px; 108 | margin-bottom: 2.5rem; 109 | } 110 | 111 | li { 112 | margin-bottom: 0.4em; 113 | } 114 | 115 | blockquote { 116 | margin-left: 0px; 117 | margin-right: 0px; 118 | padding-left: 1em; 119 | padding-top: 0.8em; 120 | padding-bottom: 0.8em; 121 | padding-right: 0.8em; 122 | border-left: 5px solid #eb99a1; 123 | margin-bottom: 2.5rem; 124 | background-color: #40363a; 125 | } 126 | 127 | blockquote p { 128 | margin-bottom: 0; 129 | } 130 | 131 | img, 132 | video { 133 | height: auto; 134 | max-width: 100%; 135 | margin-top: 0px; 136 | margin-bottom: 2.5rem; 137 | } 138 | 139 | /* Pre and Code */ 140 | pre { 141 | background-color: #40363a; 142 | display: block; 143 | padding: 1em; 144 | overflow-x: auto; 145 | margin-top: 0px; 146 | margin-bottom: 2.5rem; 147 | } 148 | 149 | code { 150 | font-size: 0.9em; 151 | padding: 0 0.5em; 152 | background-color: #40363a; 153 | white-space: pre-wrap; 154 | } 155 | 156 | pre > code { 157 | padding: 0; 158 | background-color: transparent; 159 | white-space: pre; 160 | } 161 | 162 | /* Tables */ 163 | table { 164 | text-align: justify; 165 | width: 100%; 166 | border-collapse: collapse; 167 | } 168 | 169 | td, 170 | th { 171 | padding: 0.5em; 172 | border-bottom: 1px solid #40363a; 173 | } 174 | 175 | /* Buttons, forms and input */ 176 | input, 177 | textarea { 178 | border: 1px solid #d9d8dc; 179 | } 180 | input:focus, 181 | textarea:focus { 182 | border: 1px solid #eb99a1; 183 | } 184 | 185 | textarea { 186 | width: 100%; 187 | } 188 | 189 | .button, 190 | button, 191 | input[type="submit"], 192 | input[type="reset"], 193 | input[type="button"] { 194 | display: inline-block; 195 | padding: 5px 10px; 196 | text-align: center; 197 | text-decoration: none; 198 | white-space: nowrap; 199 | background-color: #eb99a1; 200 | color: #120c0e; 201 | border-radius: 1px; 202 | border: 1px solid #eb99a1; 203 | cursor: pointer; 204 | box-sizing: border-box; 205 | } 206 | .button[disabled], 207 | button[disabled], 208 | input[type="submit"][disabled], 209 | input[type="reset"][disabled], 210 | input[type="button"][disabled] { 211 | cursor: default; 212 | opacity: 0.5; 213 | } 214 | .button:focus:enabled, 215 | .button:hover:enabled, 216 | button:focus:enabled, 217 | button:hover:enabled, 218 | input[type="submit"]:focus:enabled, 219 | input[type="submit"]:hover:enabled, 220 | input[type="reset"]:focus:enabled, 221 | input[type="reset"]:hover:enabled, 222 | input[type="button"]:focus:enabled, 223 | input[type="button"]:hover:enabled { 224 | background-color: #da4453; 225 | border-color: #da4453; 226 | color: #120c0e; 227 | outline: 0; 228 | } 229 | 230 | textarea, 231 | select, 232 | input { 233 | color: #d9d8dc; 234 | padding: 6px 10px; 235 | /* The 6px vertically centers text on FF, ignored by Webkit */ 236 | margin-bottom: 10px; 237 | background-color: #40363a; 238 | border: 1px solid #40363a; 239 | border-radius: 4px; 240 | box-shadow: none; 241 | box-sizing: border-box; 242 | } 243 | textarea:focus, 244 | select:focus, 245 | input:focus { 246 | border: 1px solid #eb99a1; 247 | outline: 0; 248 | } 249 | 250 | input[type="checkbox"]:focus { 251 | outline: 1px dotted #eb99a1; 252 | } 253 | 254 | label, 255 | legend, 256 | fieldset { 257 | display: block; 258 | margin-bottom: 0.5rem; 259 | font-weight: 600; 260 | } 261 | -------------------------------------------------------------------------------- /docs/tags.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Content with Wren Tags 6 | 7 | 8 | 9 | 10 | 11 | 12 |

13 | This is an example using 14 | Content with Wren Tags 15 |

16 |

17 | You can also use this quick echo.call() alternative, Neat! 18 |

19 | 20 |

21 | This Content was included using `require.call()` inside an automatic `echo.call()` tag. 22 |

23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /run: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Chercan TaskFile 3 | # See https://github.com/adriancooney/Taskfile 4 | # A Taskfile is a bash (or zsh etc.) script that follows 5 | # a specific format. It's called Taskfile, sits in the root of your project 6 | # (alongside your other project files) and contains the 7 | # tasks to build your project. 8 | 9 | function new { 10 | FILENAME=$1 11 | { 12 | echo "class Page {" 13 | echo " static title {\"Hello Chercán\"}" 14 | echo " static content {\"My Content\"}" 15 | printf " static date {\"%s\"}\n" "`date`" 16 | echo "}" 17 | echo "return Page" 18 | } > "content/${FILENAME}.wren" 19 | } 20 | 21 | function new:adoc { 22 | FILENAME=$1 23 | mkdir -p "content/${FILENAME}" 24 | touch "content/${FILENAME}/${FILENAME}.adoc" 25 | { 26 | echo "class Page {" 27 | echo " static title {\"Hello Chercán\"}" 28 | echo " static content {Asciidoc.read()}" 29 | printf " static date {\"%s\"}\n" "`date`" 30 | echo "}" 31 | echo "return Page" 32 | } > "content/${FILENAME}.wren" 33 | } 34 | 35 | function remove { 36 | FILENAME=$1 37 | rm -rf "content/${FILENAME}.wren" 38 | rm -rf "content/${FILENAME}/" 39 | } 40 | 41 | function build { 42 | make build 43 | } 44 | 45 | function build:adoc { 46 | make a 47 | } 48 | 49 | function build:all { 50 | make ba 51 | } 52 | 53 | function serve { 54 | make serve 55 | } 56 | 57 | function help { 58 | echo "$0 " 59 | echo "Tasks:" 60 | compgen -A function | cat -n 61 | } 62 | 63 | function default { 64 | # Default task to execute 65 | help 66 | } 67 | 68 | 69 | TIMEFORMAT="Task completed in %3lR" 70 | time ${@:-default} 71 | -------------------------------------------------------------------------------- /static/.nojekyll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NinjasCL/chercan/501db9c6cb2f7c95764dd0621d43aefb61d5c90a/static/.nojekyll -------------------------------------------------------------------------------- /static/normalize.css: -------------------------------------------------------------------------------- 1 | /*! normalize.css v5.0.0 | MIT License | github.com/necolas/normalize.css */ 2 | html { 3 | font-family: sans-serif; 4 | line-height: 1.15; 5 | -ms-text-size-adjust: 100%; 6 | -webkit-text-size-adjust: 100%; 7 | } 8 | body { 9 | margin: 0; 10 | } 11 | article, 12 | aside, 13 | footer, 14 | header, 15 | nav, 16 | section { 17 | display: block; 18 | } 19 | h1 { 20 | font-size: 2em; 21 | margin: 0.67em 0; 22 | } 23 | figcaption, 24 | figure, 25 | main { 26 | display: block; 27 | } 28 | figure { 29 | margin: 1em 40px; 30 | } 31 | hr { 32 | box-sizing: content-box; 33 | height: 0; 34 | overflow: visible; 35 | } 36 | pre { 37 | font-family: monospace, monospace; 38 | font-size: 1em; 39 | } 40 | a { 41 | background-color: transparent; 42 | -webkit-text-decoration-skip: objects; 43 | } 44 | a:active, 45 | a:hover { 46 | outline-width: 0; 47 | } 48 | abbr[title] { 49 | border-bottom: none; 50 | text-decoration: underline; 51 | text-decoration: underline dotted; 52 | } 53 | b, 54 | strong { 55 | font-weight: inherit; 56 | } 57 | b, 58 | strong { 59 | font-weight: bolder; 60 | } 61 | code, 62 | kbd, 63 | samp { 64 | font-family: monospace, monospace; 65 | font-size: 1em; 66 | } 67 | dfn { 68 | font-style: italic; 69 | } 70 | mark { 71 | background-color: #ff0; 72 | color: #000; 73 | } 74 | small { 75 | font-size: 80%; 76 | } 77 | sub, 78 | sup { 79 | font-size: 75%; 80 | line-height: 0; 81 | position: relative; 82 | vertical-align: baseline; 83 | } 84 | sub { 85 | bottom: -0.25em; 86 | } 87 | sup { 88 | top: -0.5em; 89 | } 90 | audio, 91 | video { 92 | display: inline-block; 93 | } 94 | audio:not([controls]) { 95 | display: none; 96 | height: 0; 97 | } 98 | img { 99 | border-style: none; 100 | } 101 | svg:not(:root) { 102 | overflow: hidden; 103 | } 104 | button, 105 | input, 106 | optgroup, 107 | select, 108 | textarea { 109 | font-family: sans-serif; 110 | font-size: 100%; 111 | line-height: 1.15; 112 | margin: 0; 113 | } 114 | button, 115 | input { 116 | overflow: visible; 117 | } 118 | button, 119 | select { 120 | text-transform: none; 121 | } 122 | [type="reset"], 123 | [type="submit"], 124 | button, 125 | html [type="button"] { 126 | -webkit-appearance: button; 127 | } 128 | [type="button"]::-moz-focus-inner, 129 | [type="reset"]::-moz-focus-inner, 130 | [type="submit"]::-moz-focus-inner, 131 | button::-moz-focus-inner { 132 | border-style: none; 133 | padding: 0; 134 | } 135 | [type="button"]:-moz-focusring, 136 | [type="reset"]:-moz-focusring, 137 | [type="submit"]:-moz-focusring, 138 | button:-moz-focusring { 139 | outline: 1px dotted ButtonText; 140 | } 141 | fieldset { 142 | border: 1px solid silver; 143 | margin: 0 2px; 144 | padding: 0.35em 0.625em 0.75em; 145 | } 146 | legend { 147 | box-sizing: border-box; 148 | color: inherit; 149 | display: table; 150 | max-width: 100%; 151 | padding: 0; 152 | white-space: normal; 153 | } 154 | progress { 155 | display: inline-block; 156 | vertical-align: baseline; 157 | } 158 | textarea { 159 | overflow: auto; 160 | } 161 | [type="checkbox"], 162 | [type="radio"] { 163 | box-sizing: border-box; 164 | padding: 0; 165 | } 166 | [type="number"]::-webkit-inner-spin-button, 167 | [type="number"]::-webkit-outer-spin-button { 168 | height: auto; 169 | } 170 | [type="search"] { 171 | -webkit-appearance: textfield; 172 | outline-offset: -2px; 173 | } 174 | [type="search"]::-webkit-search-cancel-button, 175 | [type="search"]::-webkit-search-decoration { 176 | -webkit-appearance: none; 177 | } 178 | ::-webkit-file-upload-button { 179 | -webkit-appearance: button; 180 | font: inherit; 181 | } 182 | details, 183 | menu { 184 | display: block; 185 | } 186 | summary { 187 | display: list-item; 188 | } 189 | canvas { 190 | display: inline-block; 191 | } 192 | template { 193 | display: none; 194 | } 195 | [hidden] { 196 | display: none; 197 | } 198 | -------------------------------------------------------------------------------- /static/sakura-vader.css: -------------------------------------------------------------------------------- 1 | /* $color-text: #dedce5; */ 2 | /* Sakura.css v1.3.1 3 | * ================ 4 | * Minimal css theme. 5 | * Project: https://github.com/oxalorg/sakura/ 6 | */ 7 | /* Body */ 8 | html { 9 | font-size: 62.5%; 10 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, 11 | "Helvetica Neue", Arial, "Noto Sans", sans-serif; 12 | } 13 | 14 | body { 15 | font-size: 1.8rem; 16 | line-height: 1.618; 17 | max-width: 38em; 18 | margin: auto; 19 | color: #d9d8dc; 20 | background-color: #120c0e; 21 | padding: 13px; 22 | } 23 | 24 | @media (max-width: 684px) { 25 | body { 26 | font-size: 1.53rem; 27 | } 28 | } 29 | 30 | @media (max-width: 382px) { 31 | body { 32 | font-size: 1.35rem; 33 | } 34 | } 35 | 36 | h1, 37 | h2, 38 | h3, 39 | h4, 40 | h5, 41 | h6 { 42 | line-height: 1.1; 43 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, 44 | "Helvetica Neue", Arial, "Noto Sans", sans-serif; 45 | font-weight: 700; 46 | margin-top: 3rem; 47 | margin-bottom: 1.5rem; 48 | overflow-wrap: break-word; 49 | word-wrap: break-word; 50 | -ms-word-break: break-all; 51 | word-break: break-word; 52 | } 53 | 54 | h1 { 55 | font-size: 2.35em; 56 | } 57 | 58 | h2 { 59 | font-size: 2em; 60 | } 61 | 62 | h3 { 63 | font-size: 1.75em; 64 | } 65 | 66 | h4 { 67 | font-size: 1.5em; 68 | } 69 | 70 | h5 { 71 | font-size: 1.25em; 72 | } 73 | 74 | h6 { 75 | font-size: 1em; 76 | } 77 | 78 | p { 79 | margin-top: 0px; 80 | margin-bottom: 2.5rem; 81 | } 82 | 83 | small, 84 | sub, 85 | sup { 86 | font-size: 75%; 87 | } 88 | 89 | hr { 90 | border-color: #eb99a1; 91 | } 92 | 93 | a { 94 | text-decoration: none; 95 | color: #eb99a1; 96 | } 97 | a:hover { 98 | color: #da4453; 99 | border-bottom: 2px solid #d9d8dc; 100 | } 101 | a:visited { 102 | color: #e26f7a; 103 | } 104 | 105 | ul { 106 | padding-left: 1.4em; 107 | margin-top: 0px; 108 | margin-bottom: 2.5rem; 109 | } 110 | 111 | li { 112 | margin-bottom: 0.4em; 113 | } 114 | 115 | blockquote { 116 | margin-left: 0px; 117 | margin-right: 0px; 118 | padding-left: 1em; 119 | padding-top: 0.8em; 120 | padding-bottom: 0.8em; 121 | padding-right: 0.8em; 122 | border-left: 5px solid #eb99a1; 123 | margin-bottom: 2.5rem; 124 | background-color: #40363a; 125 | } 126 | 127 | blockquote p { 128 | margin-bottom: 0; 129 | } 130 | 131 | img, 132 | video { 133 | height: auto; 134 | max-width: 100%; 135 | margin-top: 0px; 136 | margin-bottom: 2.5rem; 137 | } 138 | 139 | /* Pre and Code */ 140 | pre { 141 | background-color: #40363a; 142 | display: block; 143 | padding: 1em; 144 | overflow-x: auto; 145 | margin-top: 0px; 146 | margin-bottom: 2.5rem; 147 | } 148 | 149 | code { 150 | font-size: 0.9em; 151 | padding: 0 0.5em; 152 | background-color: #40363a; 153 | white-space: pre-wrap; 154 | } 155 | 156 | pre > code { 157 | padding: 0; 158 | background-color: transparent; 159 | white-space: pre; 160 | } 161 | 162 | /* Tables */ 163 | table { 164 | text-align: justify; 165 | width: 100%; 166 | border-collapse: collapse; 167 | } 168 | 169 | td, 170 | th { 171 | padding: 0.5em; 172 | border-bottom: 1px solid #40363a; 173 | } 174 | 175 | /* Buttons, forms and input */ 176 | input, 177 | textarea { 178 | border: 1px solid #d9d8dc; 179 | } 180 | input:focus, 181 | textarea:focus { 182 | border: 1px solid #eb99a1; 183 | } 184 | 185 | textarea { 186 | width: 100%; 187 | } 188 | 189 | .button, 190 | button, 191 | input[type="submit"], 192 | input[type="reset"], 193 | input[type="button"] { 194 | display: inline-block; 195 | padding: 5px 10px; 196 | text-align: center; 197 | text-decoration: none; 198 | white-space: nowrap; 199 | background-color: #eb99a1; 200 | color: #120c0e; 201 | border-radius: 1px; 202 | border: 1px solid #eb99a1; 203 | cursor: pointer; 204 | box-sizing: border-box; 205 | } 206 | .button[disabled], 207 | button[disabled], 208 | input[type="submit"][disabled], 209 | input[type="reset"][disabled], 210 | input[type="button"][disabled] { 211 | cursor: default; 212 | opacity: 0.5; 213 | } 214 | .button:focus:enabled, 215 | .button:hover:enabled, 216 | button:focus:enabled, 217 | button:hover:enabled, 218 | input[type="submit"]:focus:enabled, 219 | input[type="submit"]:hover:enabled, 220 | input[type="reset"]:focus:enabled, 221 | input[type="reset"]:hover:enabled, 222 | input[type="button"]:focus:enabled, 223 | input[type="button"]:hover:enabled { 224 | background-color: #da4453; 225 | border-color: #da4453; 226 | color: #120c0e; 227 | outline: 0; 228 | } 229 | 230 | textarea, 231 | select, 232 | input { 233 | color: #d9d8dc; 234 | padding: 6px 10px; 235 | /* The 6px vertically centers text on FF, ignored by Webkit */ 236 | margin-bottom: 10px; 237 | background-color: #40363a; 238 | border: 1px solid #40363a; 239 | border-radius: 4px; 240 | box-shadow: none; 241 | box-sizing: border-box; 242 | } 243 | textarea:focus, 244 | select:focus, 245 | input:focus { 246 | border: 1px solid #eb99a1; 247 | outline: 0; 248 | } 249 | 250 | input[type="checkbox"]:focus { 251 | outline: 1px dotted #eb99a1; 252 | } 253 | 254 | label, 255 | legend, 256 | fieldset { 257 | display: block; 258 | margin-bottom: 0.5rem; 259 | font-weight: 600; 260 | } 261 | -------------------------------------------------------------------------------- /themes/default/default.wren.html: -------------------------------------------------------------------------------- 1 | 12 | -------------------------------------------------------------------------------- /themes/default/home.wren.html: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | 9 | 13 | 14 |
15 | 16 |

You can use any valid Wren Code

17 | 18 |
    19 | Item Nº %(num)") 22 | } 23 | ?> 24 |
25 | 26 |
27 | 28 |

29 | <?= footer ?> is the same as writing <?wren echo.call(footer) ?> 30 |

31 | 32 | 33 | -------------------------------------------------------------------------------- /themes/default/partials/footer.wren.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /themes/default/partials/header.wren.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | <?wren echo.call(page.title) ?> 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /themes/default/partials/header2.wren.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Another Header · <?wren echo.call(page.title) ?> 6 | 7 | 8 | 9 | 10 | 11 | --------------------------------------------------------------------------------