├── .gitignore
├── LICENSE
├── Makefile
├── README.md
├── cli
├── build.go
├── cli.go
├── create.go
├── sample
│ ├── posts
│ │ ├── creating-a-blog.md
│ │ ├── creating-posts.md
│ │ ├── generating-html-files-for-a-blog-aka-building-a-blog.md
│ │ ├── getting-help.md
│ │ ├── installation.md
│ │ ├── overview.md
│ │ ├── quick-start.md
│ │ ├── serving-a-blog.md
│ │ └── templates.md
│ └── templates
│ │ ├── css
│ │ ├── font.min.css
│ │ ├── main.min.css
│ │ ├── normalize.min.css
│ │ ├── prism.min.css
│ │ └── skeleton.min.css
│ │ ├── favicon.ico
│ │ ├── images
│ │ ├── email-16.png
│ │ ├── email-24.png
│ │ ├── github-16.png
│ │ ├── github-24.png
│ │ ├── logo.png
│ │ ├── twitter-16.png
│ │ └── twitter-24.png
│ │ ├── index.tmpl
│ │ ├── js
│ │ └── prism.min.js
│ │ ├── layout.tmpl
│ │ ├── post.tmpl
│ │ └── tag.tmpl
├── serve.go
└── usage.go
├── go.mod
├── go.sum
├── lib
├── blog.go
├── html.go
├── markdown.go
└── markdown_test.go
└── main.go
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 | _dist
3 | ROADMAP.md
4 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2024 Miro Varga [mirovarga.com]
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 | LINUX_OS = linux
2 | WIN_OS = windows
3 | DARWIN_OS = darwin
4 | ARCH_AMD = amd64
5 | ARCH_ARM = arm64
6 |
7 | DIST_DIR = _dist
8 | LINUX_DIR = $(DIST_DIR)/$(LINUX_OS)
9 | WIN_DIR = $(DIST_DIR)/$(WIN_OS)
10 | DARWIN_DIR = $(DIST_DIR)/$(DARWIN_OS)
11 |
12 | BIN_FILE = litepub
13 | OTHER_FILES = LICENSE README.md
14 |
15 | VERSION = $(shell git describe --tags --abbrev=0)
16 |
17 | build: clean
18 | @go build
19 |
20 | install: clean
21 | @go install
22 |
23 | dist: clean
24 | @echo "Building Linux distribution"
25 | @mkdir -p $(LINUX_DIR)
26 | @GOOS=$(LINUX_OS) GOARCH=$(ARCH_AMD) go build -o $(LINUX_DIR)/$(BIN_FILE)
27 | @zip -qj9 $(DIST_DIR)/$(BIN_FILE)-$(VERSION)-$(LINUX_OS)-$(ARCH_AMD).zip $(LINUX_DIR)/$(BIN_FILE) $(OTHER_FILES)
28 | @rm -rf $(LINUX_DIR)
29 |
30 | @echo "Building Windows distribution"
31 | @mkdir -p $(WIN_DIR)
32 | @GOOS=$(WIN_OS) GOARCH=$(ARCH_AMD) go build -o $(WIN_DIR)/$(BIN_FILE).exe
33 | @zip -qj9 $(DIST_DIR)/$(BIN_FILE)-$(VERSION)-$(WIN_OS)-$(ARCH_AMD).zip $(WIN_DIR)/$(BIN_FILE).exe $(OTHER_FILES)
34 | @rm -rf $(WIN_DIR)
35 |
36 | @echo "Building Darwin distribution"
37 | @mkdir -p $(DARWIN_DIR)
38 | @GOOS=$(DARWIN_OS) GOARCH=$(ARCH_ARM) go build -o $(DARWIN_DIR)/$(BIN_FILE)
39 | @zip -qj9 $(DIST_DIR)/$(BIN_FILE)-$(VERSION)-$(DARWIN_OS)-$(ARCH_ARM).zip $(DARWIN_DIR)/$(BIN_FILE) $(OTHER_FILES)
40 | @rm -rf $(DARWIN_DIR)
41 |
42 | clean:
43 | @go clean
44 | @rm -rf $(DIST_DIR)
45 |
46 | .PHONY: build install dist clean
47 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # LitePub
2 |
3 | A lightweight static blog generator written in Go.
4 |
5 | > Why another one? I wrote a blog post that briefly describes
6 | [why I created it](http://www.mirovarga.com/a-lightweight-static-blog-generator-in-go.html).
7 |
8 | ## Overview
9 |
10 | LitePub is a static blog generator that tries to be as easy to use as possible.
11 |
12 | It requires no software dependencies, needs no configuration files, uses no
13 | databases. All it needs is one binary, posts written in
14 | [Markdown](https://en.wikipedia.org/wiki/Markdown) and a set of templates to
15 | render the posts to static HTML files.
16 |
17 | Posts don't have to include any special metadata (aka front matter) like title
18 | or date in them - the title, date and optional tags are parsed from the natural
19 | flow of the posts.
20 |
21 | ## Quick Start
22 |
23 | To create a sample blog follow these steps:
24 |
25 | 1. Download a [release](https://github.com/mirovarga/litepub/releases) and
26 | unpack it to a directory.
27 |
28 | 2. `cd` to the directory.
29 |
30 | 3. Create a sample blog:
31 |
32 | ```shell
33 | ./litepub create
34 | ```
35 |
36 | 4. Build the blog:
37 |
38 | ```shell
39 | ./litepub build
40 | Generating: index.html
41 | Generating: tags/reference.html
42 | Generating: tags/tutorial.html
43 | Generating: tags/advanced.html
44 | Generating: tags/docs.html
45 | Generating: tags/basics.html
46 | Generating: overview.html
47 | Generating: quick-start.html
48 | Generating: installation.html
49 | Generating: creating-a-blog.html
50 | Generating: creating-posts.html
51 | Generating: generating-html-files-for-a-blog-aka-building-a-blog.html
52 | Generating: serving-a-blog.html
53 | Generating: templates.html
54 | Generating: getting-help.html
55 | ```
56 |
57 | 5. Run the built-in server:
58 |
59 | ```shell
60 | ./litepub serve
61 | Running on http://localhost:2703
62 | Ctrl+C to quit
63 | ```
64 |
65 | 6. Open [http://localhost:2703](http://localhost:2703) in your browser.
66 |
67 | ## Documentation
68 |
69 | ### Installation
70 |
71 | #### Via the `go install` command
72 |
73 | ```shell
74 | go install github.com/mirovarga/litepub@latest
75 | ```
76 |
77 | #### Manually
78 |
79 | Download a [release](https://github.com/mirovarga/litepub/releases) and unpack
80 | it to a directory.
81 |
82 | > You can optionally add the directory to the `PATH` so you can run `litepub`
83 | from any directory. All examples assume you have `litepub` in your `PATH`.
84 |
85 | ### Creating a Blog
86 |
87 | The following will create a sample blog in the current directory:
88 |
89 | ```shell
90 | litepub create
91 | ```
92 |
93 | If you don't need the sample templates and posts use the `--skeleton` option:
94 |
95 | ```shell
96 | litepub create --skeleton
97 | ```
98 |
99 | > Because the template files are required they will be still created but with
100 | > no content.
101 |
102 | #### Directory Structure
103 |
104 | Each blog is stored in a directory with the following structure:
105 |
106 | ```shell
107 | posts/ # the posts
108 | draft/ # the draft posts (they are ignored when building the blog)
109 | templates/ # the templates and accompanying files (html, css, js, png, etc.)
110 | layout.tmpl
111 | index.tmpl
112 | post.tmpl
113 | tag.tmpl
114 | www/ # the generated HTML files (plus copied accompanying files)
115 | ```
116 |
117 | #### The **create** Command Reference
118 |
119 | ```
120 | Usage:
121 | litepub create [
] [-s, --skeleton] [-q, --quiet]
122 |
123 | Arguments:
124 | The directory to create the blog in or look for; it will be created if
125 | it doesn't exist (only when creating a blog) [default: .]
126 |
127 | Options:
128 | -s, --skeleton Don't create sample posts and templates
129 | -q, --quiet Show only errors
130 | ```
131 |
132 | ### Creating Posts
133 |
134 | To create a post just add a [Markdown](https://en.wikipedia.org/wiki/Markdown)
135 | file in the `posts` directory. The file name and extension aren't important,
136 | only the content of the file.
137 |
138 | > All posts need to be stored directly in the `posts` directory. In other words,
139 | > subdirectories in the `posts` directory are ignored when looking for posts.
140 |
141 | Each post looks like this (it's the start of an
142 | [actual post](http://www.mirovarga.com/how-i-switched-from-java-to-javascript.html)
143 | from my blog):
144 |
145 | ```markdown
146 | 1 # How I Switched from Java to JavaScript
147 | 2
148 | 3 *Jan 25, 2015*
149 | 4
150 | 5 *Java, JavaScript*
151 | 6
152 | 7 I know that there are lots of posts about why JavaScript, or more specifically
153 | 8 Node.js, is better than Java but nevertheless I wanted to contribute, too.
154 | 9 ...
155 | ```
156 |
157 | - Line `1` is the post's title. If it starts with one or more `#`s they are
158 | stripped. So in this case the title becomes *How I Switched from Java to
159 | JavaScript*.
160 | - Line `3` is the post's date. It has to be in the `*MMM d, YYYY*` format.
161 | - Line `5` are comma separated post tags.
162 | - Anything below line `6` is the content of the post.
163 |
164 | > The post's title and date are required. Tags are optional.
165 |
166 | #### Draft Posts
167 |
168 | Any post can be marked as draft by simply moving it to the `draft` subdirectory
169 | of the `posts` directory. To unmark it just move it back to the `posts`
170 | directory.
171 |
172 | > Deleting a post is analogous to drafting: just remove it from the `posts`
173 | directory.
174 |
175 | ### Generating HTML Files for a Blog, aka Building a Blog
176 |
177 | To generate the HTML files for a blog `cd` to the blog's directory and use the
178 | `build` command:
179 |
180 | ```shell
181 | litepub build
182 | Generating: index.html
183 | Generating: tags/reference.html
184 | Generating: tags/tutorial.html
185 | Generating: tags/advanced.html
186 | Generating: tags/docs.html
187 | Generating: tags/basics.html
188 | Generating: overview.html
189 | Generating: quick-start.html
190 | Generating: installation.html
191 | Generating: creating-a-blog.html
192 | Generating: creating-posts.html
193 | Generating: generating-html-files-for-a-blog-aka-building-a-blog.html
194 | Generating: serving-a-blog.html
195 | Generating: templates.html
196 | Generating: getting-help.html
197 | ```
198 |
199 | > The draft posts and posts starting with a dot (`.`) are ignored when building
200 | > a blog.
201 |
202 | LitePub takes the `*.tmpl` files from the `templates` directory, applies them to
203 | posts stored in the `posts` directory and generates the HTML files to the `www`
204 | directory. It also copies all accompanying files (and directories) from
205 | the `templates` directory to the `www` directory.
206 |
207 | > The generated HTML file names are created by slugifying the post title
208 | > (or the tag name when generating tag pages) and adding the `html` extension.
209 | > For example, a post with the *How I Switched from Java to JavaScript* title is
210 | > generated to the `how-i-switched-from-java-to-javascript.html` file.
211 |
212 | #### The **build** Command Reference
213 |
214 | ```
215 | Usage:
216 | litepub build [] [-q, --quiet]
217 |
218 | Arguments:
219 | The directory to create the blog in or look for; it will be created if
220 | it doesn't exist (only when creating a blog) [default: .]
221 |
222 | Options:
223 | -q, --quiet Show only errors
224 | ```
225 |
226 | ### Serving a Blog
227 |
228 | LitePub has a built-in server so you can see how a generated blog looks like in
229 | a browser. `cd` to the blog's directory and start the server:
230 |
231 | ```shell
232 | litepub serve
233 | Running on http://localhost:2703
234 | Ctrl+C to quit
235 | ```
236 |
237 | Now open [http://localhost:2703](http://localhost:2703) in your browser to see
238 | the generated blog.
239 |
240 | #### Serving a Blog on a Different Port
241 |
242 | When starting the server you can specify a port on which to listen with the
243 | `--port` option:
244 |
245 | ```shell
246 | litepub serve --port 3000
247 | Running on http://localhost:3000
248 | Ctrl+C to quit
249 | ```
250 |
251 | #### Serving a Blog and Watching for Changes
252 |
253 | When creating templates or even writing posts it's quite useful to be able to
254 | immediately see the changes after refreshing the page. To tell LitePub that it
255 | should watch for changes to posts and templates use the `--watch` option:
256 |
257 | ```shell
258 | litepub serve --watch
259 | Running on http://localhost:2703
260 | Rebuilding when posts or templates change
261 | Ctrl+C to quit
262 | ```
263 |
264 | > Note that subdirectories in the `posts` and `templates` directories aren't
265 | > watched.
266 |
267 | #### Rebuilding a Blog Before Serving
268 |
269 | Sometimes it can be useful to rebuild a blog before serving it, for example when
270 | you don't remember if you made any changes to posts or templates. To rebuild a
271 | blog before serving use the `--rebuild` option:
272 |
273 | ```shell
274 | litepub serve --rebuild
275 | Generating: index.html
276 | Generating: tags/reference.html
277 | Generating: tags/tutorial.html
278 | Generating: tags/advanced.html
279 | Generating: tags/docs.html
280 | Generating: tags/basics.html
281 | Generating: overview.html
282 | Generating: quick-start.html
283 | Generating: installation.html
284 | Generating: creating-a-blog.html
285 | Generating: creating-posts.html
286 | Generating: generating-html-files-for-a-blog-aka-building-a-blog.html
287 | Generating: serving-a-blog.html
288 | Generating: templates.html
289 | Generating: getting-help.html
290 | Running on http://localhost:2703
291 | Ctrl+C to quit
292 | ```
293 |
294 | #### The **serve** Command Reference
295 |
296 | ```
297 | Usage:
298 | litepub serve [] [-R, --rebuild] [-p, --port ] [-w, --watch] [-q, --quiet]
299 |
300 | Arguments:
301 | The directory to create the blog in or look for; it will be created if
302 | it doesn't exist (only when creating a blog) [default: .]
303 |
304 | Options:
305 | -R, --rebuild Rebuild the blog before serving
306 | -p, --port The port to listen on [default: 2703]
307 | -w, --watch Rebuild the blog when posts or templates change
308 | -q, --quiet Show only errors
309 | ```
310 |
311 | ### Templates
312 |
313 | The `create` command adds sample templates to the `templates` directory. Of
314 | course, you can change them or create your own from scratch.
315 |
316 | LitePub uses the Go [html/template](https://golang.org/pkg/html/template/)
317 | package to define the templates.
318 |
319 | > Design changes require no knowledge of Go templates. However changes that
320 | > affect what data is displayed will require it less or more (depending on
321 | > the change).
322 |
323 | #### Structure
324 |
325 | There are four required files in the `templates` directory:
326 |
327 | ```shell
328 | templates/ # the templates and accompanying files (html, css, js, png, etc.)
329 | layout.tmpl
330 | index.tmpl
331 | post.tmpl
332 | tag.tmpl
333 | ```
334 |
335 | - `layout.tmpl` defines the common layout for the home page (`index.tmpl`), post
336 | pages (`post.tmpl`) and tag pages (`tag.tmpl`)
337 | - `index.tmpl` is used when generating the home page (`index.html`)
338 | - `post.tmpl` is used when generating post pages
339 | - and `tag.tmpl` is used when generating tag pages
340 |
341 | Besides the four files there can be any number of `html`, `css`, `js`, `png`,
342 | etc. files that are used by the `.tmpl` files.
343 |
344 | > If you're not familiar with Go templates, some things in the next sections can
345 | > be unclear.
346 |
347 | #### Data
348 |
349 | Templates have access to data they are meant to display. There are two types of
350 | data: `Post`s and `Tag`s.
351 |
352 | ##### Posts
353 |
354 | A `Post` has the following properties:
355 |
356 | - `Title` - the post title
357 | - `Content` - the content of the post as Markdown text
358 | - `Written` - the post's date
359 | - `Tags` - an array of tags the post is tagged with (can be empty)
360 | - `Draft` - `true` if the post is a draft
361 |
362 | > To get a post's page URL in a template use the `slug` function (described
363 | > below) like this: `A Post`.
364 |
365 | ##### Tags
366 |
367 | A `Tag` has the following properties:
368 |
369 | - `Name` - the tag name
370 | - `Posts` - an array of `Post`s that are tagged with the tag sorted by `Written`
371 | in descending order
372 |
373 | > To get a tag's page URL in a template use the `slug` function (described
374 | > below) like this: `A Tag`.
375 |
376 | The `index.tmpl` template has access to an array of `Post`s sorted by `Written`
377 | in descending order. The `post.tmpl` template has access to the `Post` it
378 | displays. The `tag.tmpl` template has access to the `Tag` it displays.
379 |
380 | #### Functions
381 |
382 | The `index.tmpl`, `post.tmpl` and `tag.tmpl` templates have access to the
383 | following functions:
384 |
385 | ##### html
386 |
387 | Converts a Markdown string to a raw HTML, for example `{{.Content | html}}`.
388 |
389 | ##### summary
390 |
391 | Extracts the first paragraph of a Markdown string that isn't a header (doesn't
392 | start with a `#`), for example `{{.Content | summary | html}}`.
393 |
394 | ##### even
395 |
396 | Returns `true` if an integer is even, for example
397 | `{{if even $i}}{{end}}`.
398 |
399 | ##### inc
400 |
401 | Increments an integer by one, for example
402 | `{{if or (eq (inc $i) $l) (not (even $i))}}{{end}}`.
403 |
404 | ##### slug
405 |
406 | Slugifies a string, for example `A Post`.
407 |
408 | > The available functions represent my needs when converting my handmade blog
409 | > to a generated one.
410 |
411 | ### Getting Help
412 |
413 | To see all available commands and their options use the `--help` option:
414 |
415 | ```shell
416 | litepub --help
417 | LitePub 0.5.7 [github.com/mirovarga/litepub]
418 | Copyright (c) 2024 Miro Varga [mirovarga.com]
419 |
420 | Usage:
421 | litepub create [] [-s, --skeleton] [-q, --quiet]
422 | litepub build [] [-q, --quiet]
423 | litepub serve [] [-R, --rebuild] [-p, --port ] [-w, --watch] [-q, --quiet]
424 |
425 | Arguments:
426 | The directory to create the blog in or look for; it will be created if
427 | it doesn't exist (only when creating a blog) [default: .]
428 |
429 | Options:
430 | -s, --skeleton Don't create sample posts and templates
431 | -R, --rebuild Rebuild the blog before serving
432 | -p, --port The port to listen on [default: 2703]
433 | -w, --watch Rebuild the blog when posts or templates change
434 | -q, --quiet Show only errors
435 | -h, --help Show this screen
436 | -v, --version Show version
437 | ```
438 |
--------------------------------------------------------------------------------
/cli/build.go:
--------------------------------------------------------------------------------
1 | package cli
2 |
3 | import (
4 | "path/filepath"
5 |
6 | "github.com/mirovarga/litepub/lib"
7 | )
8 |
9 | func build(arguments map[string]interface{}) int {
10 | dir := arguments[""].(string)
11 |
12 | blog, err := lib.NewMarkdownBlog(dir).Read()
13 | if err != nil {
14 | log.Errorf("Failed to read blog: %s\n", err)
15 | return 1
16 | }
17 |
18 | gen, err := lib.NewStaticBlogGenerator(blog, filepath.Join(dir, templatesDir),
19 | filepath.Join(dir, outputDir), printProgress)
20 | if err != nil {
21 | log.Errorf("Failed to create generator: %s\n", err)
22 | return 1
23 | }
24 |
25 | err = gen.Generate()
26 | if err != nil {
27 | log.Errorf("Failed to generate blog: %s\n", err)
28 | return 1
29 | }
30 |
31 | return 0
32 | }
33 |
34 | func printProgress(path string) {
35 | log.Infof("Generating: %s\n", path)
36 | }
37 |
--------------------------------------------------------------------------------
/cli/cli.go:
--------------------------------------------------------------------------------
1 | package cli
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/docopt/docopt-go"
7 | )
8 |
9 | const (
10 | postsDir = "posts"
11 | templatesDir = "templates"
12 | outputDir = "www"
13 | )
14 |
15 | var log quietableLog
16 |
17 | // TODO pass args (also check for other ways to decouple things)
18 | func Run() int {
19 | arguments, _ := docopt.ParseArgs(usage, nil, "LitePub 0.5.7")
20 |
21 | log = quietableLog{arguments["--quiet"].(int) == 1}
22 |
23 | if _, ok := arguments[""].(string); !ok {
24 | arguments[""] = "."
25 | }
26 |
27 | if arguments["create"].(bool) {
28 | return create(arguments)
29 | } else if arguments["build"].(bool) {
30 | return build(arguments)
31 | } else if arguments["serve"].(bool) {
32 | return serve(arguments)
33 | }
34 |
35 | return 0
36 | }
37 |
38 | type quietableLog struct {
39 | quiet bool
40 | }
41 |
42 | func (l quietableLog) Infof(format string, v ...interface{}) {
43 | if !l.quiet {
44 | fmt.Printf(format, v...)
45 | }
46 | }
47 |
48 | func (l quietableLog) Errorf(format string, v ...interface{}) {
49 | fmt.Printf("ERROR: "+format, v...)
50 | }
51 |
--------------------------------------------------------------------------------
/cli/create.go:
--------------------------------------------------------------------------------
1 | package cli
2 |
3 | import (
4 | "embed"
5 | "io/fs"
6 | "os"
7 | "path/filepath"
8 | "strings"
9 |
10 | "github.com/mirovarga/litepub/lib"
11 | )
12 |
13 | //go:embed sample
14 | var assets embed.FS
15 |
16 | var templates = []string{"layout.tmpl", "index.tmpl", "post.tmpl", "tag.tmpl"}
17 |
18 | func create(arguments map[string]interface{}) int {
19 | dir := arguments[""].(string)
20 |
21 | lib.NewMarkdownBlog(dir)
22 |
23 | if arguments["--skeleton"].(int) == 1 {
24 | // TODO here we should call something like lib.NewStaticBlogGenerator(dir)
25 | // with this branch's functionality and execute the else branch when
26 | // --skeleton == 0
27 | tmplDir := filepath.Join(dir, templatesDir)
28 | err := os.MkdirAll(tmplDir, 0700)
29 | if err != nil {
30 | log.Errorf("Failed to create blog: %s\n", err)
31 | return 1
32 | }
33 |
34 | for _, template := range templates {
35 | err := os.WriteFile(filepath.Join(tmplDir, template), nil, 0600)
36 | if err != nil {
37 | log.Errorf("Failed to create blog: %s\n", err)
38 | return 1
39 | }
40 | }
41 | } else {
42 | err := fs.WalkDir(assets, "sample", func(path string, d fs.DirEntry, err error) error {
43 | if path == "sample" {
44 | return nil
45 | }
46 |
47 | trimmedPath := strings.TrimPrefix(path, "sample/")
48 | if d.IsDir() {
49 | return os.MkdirAll(filepath.Join(dir, trimmedPath), 0700)
50 | } else {
51 | bytes, err := fs.ReadFile(assets, path)
52 | if err != nil {
53 | return err
54 | }
55 | return os.WriteFile(filepath.Join(dir, trimmedPath), bytes, 0600)
56 | }
57 | })
58 | if err != nil {
59 | log.Errorf("Failed to create blog: %s\n", err)
60 | return 1
61 | }
62 | }
63 |
64 | log.Infof("Created blog: %s\n", dir)
65 | return 0
66 | }
67 |
--------------------------------------------------------------------------------
/cli/sample/posts/creating-a-blog.md:
--------------------------------------------------------------------------------
1 | # Creating a Blog
2 |
3 | *Nov 16, 2015*
4 |
5 | *Docs, Basics*
6 |
7 | The following will create a sample blog in the current directory:
8 |
9 | ```
10 | $ litepub create
11 | ```
12 |
13 | If you don't need the sample templates and posts use the `--skeleton` option:
14 |
15 | ```
16 | $ litepub create --skeleton
17 | ```
18 |
19 | > Because the template files are required they will be still created but with no content.
20 |
21 | ## Directory Structure
22 |
23 | Each blog is stored in a directory with the following structure:
24 |
25 | ```bash
26 | posts/ # the posts
27 | draft/ # the draft posts (they are ignored when building the blog)
28 | templates/ # the templates and accompanying files (html, css, js, png, etc.)
29 | layout.tmpl
30 | index.tmpl
31 | post.tmpl
32 | tag.tmpl
33 | www/ # the generated HTML files (plus copied accompanying files)
34 | ```
35 |
36 | ## The **create** Command Reference
37 |
38 | ```
39 | Usage:
40 | litepub create [] [-s, --skeleton] [-q, --quiet]
41 |
42 | Arguments:
43 | The directory to create the blog in or look for; it will be created if
44 | it doesn't exist (only when creating a blog) [default: .]
45 |
46 | Options:
47 | -s, --skeleton Don't create sample posts and templates
48 | -q, --quiet Show only errors
49 | ```
50 |
51 | **Next**: [Creating Posts](/creating-posts.html)
52 |
--------------------------------------------------------------------------------
/cli/sample/posts/creating-posts.md:
--------------------------------------------------------------------------------
1 | # Creating Posts
2 |
3 | *Nov 15, 2015*
4 |
5 | *Docs, Basics*
6 |
7 | To create a post just add a [Markdown](https://en.wikipedia.org/wiki/Markdown)
8 | file in the `posts` directory. The file name and extension aren't important,
9 | only the content of the file.
10 |
11 | > All posts need to be stored directly in the `posts` directory. In other words, subdirectories in the `posts` directory are ignored when looking for posts.
12 |
13 | Each post looks like this (it's the start of an
14 | [actual post](http://www.mirovarga.com/how-i-switched-from-java-to-javascript.html)
15 | from my blog):
16 |
17 | ```markdown
18 | 1 # How I Switched from Java to JavaScript
19 | 2
20 | 3 *Jan 25, 2015*
21 | 4
22 | 5 *Java, JavaScript*
23 | 6
24 | 7 I know that there are lots of posts about why JavaScript, or more specifically
25 | 8 Node.js, is better than Java but nevertheless I wanted to contribute, too.
26 | 9 ...
27 | ```
28 |
29 | - Line `1` is the post's title. If it starts with one or more `#`s they are
30 | stripped. So in this case the title becomes *How I Switched from Java to
31 | JavaScript*.
32 | - Line `3` is the post's date. It has to be in the `*MMM d, YYYY*` format.
33 | - Line `5` are comma separated post tags.
34 | - Anything below line `6` is the content of the post.
35 |
36 | > The post's title and date are required. Tags are optional.
37 |
38 | ## Draft Posts
39 |
40 | Any post can be marked as draft by simply moving it to the `draft` subdirectory
41 | of the `posts` directory. To unmark it just move it back to the `posts`
42 | directory.
43 |
44 | > Deleting a post is analogous to drafting: just remove it from the `posts`
45 | directory.
46 |
47 | **
48 | Next**: [Generating HTML Files for a Blog, aka Building a Blog](/generating-html-files-for-a-blog-aka-building-a-blog.html)
49 |
--------------------------------------------------------------------------------
/cli/sample/posts/generating-html-files-for-a-blog-aka-building-a-blog.md:
--------------------------------------------------------------------------------
1 | # Generating HTML Files for a Blog, aka Building a Blog
2 |
3 | *Nov 14, 2015*
4 |
5 | *Docs, Basics*
6 |
7 | To generate the HTML files for a blog `cd` to the blog's directory and use the
8 | `build` command:
9 |
10 | ```
11 | $ litepub build
12 | Generating: index.html
13 | Generating: tags/reference.html
14 | Generating: tags/tutorial.html
15 | Generating: tags/advanced.html
16 | Generating: tags/docs.html
17 | Generating: tags/basics.html
18 | Generating: overview.html
19 | Generating: quick-start.html
20 | Generating: installation.html
21 | Generating: creating-a-blog.html
22 | Generating: creating-posts.html
23 | Generating: generating-html-files-for-a-blog-aka-building-a-blog.html
24 | Generating: serving-a-blog.html
25 | Generating: templates.html
26 | Generating: getting-help.html
27 | ```
28 |
29 | > The draft posts are ignored when building a blog.
30 |
31 | LitePub takes the `*.tmpl` files from the `templates` directory, applies them to
32 | posts stored in the `posts` directory and generates the HTML files to the `www`
33 | directory. It also copies all accompanying files (and directories) from
34 | the `templates` directory to the `www` directory.
35 |
36 | > The generated HTML file names are created by slugifying the post title (or the tag name when generating tag pages) and adding the `html` extension. For example, a post with the *How I Switched from Java to JavaScript* title is generated to the `how-i-switched-from-java-to-javascript.html` file.
37 |
38 | ## The **build** Command Reference
39 |
40 | ```
41 | Usage:
42 | litepub build [] [-q, --quiet]
43 |
44 | Arguments:
45 | The directory to create the blog in or look for; it will be created if
46 | it doesn't exist (only when creating a blog) [default: .]
47 |
48 | Options:
49 | -q, --quiet Show only errors
50 | ```
51 |
52 | **Next**: [Serving a Blog](/serving-a-blog.html)
53 |
--------------------------------------------------------------------------------
/cli/sample/posts/getting-help.md:
--------------------------------------------------------------------------------
1 | # Getting Help
2 |
3 | *Nov 11, 2015*
4 |
5 | *Docs, Reference*
6 |
7 | To see all available commands and their options use the `--help` option:
8 |
9 | ```
10 | $ litepub --help
11 | LitePub 0.5.7 [github.com/mirovarga/litepub]
12 | Copyright (c) 2024 Miro Varga [mirovarga.com]
13 |
14 | Usage:
15 | litepub create [] [-s, --skeleton] [-q, --quiet]
16 | litepub build [] [-q, --quiet]
17 | litepub serve [] [-R, --rebuild] [-p, --port ] [-w, --watch] [-q, --quiet]
18 |
19 | Arguments:
20 | The directory to create the blog in or look for; it will be created if
21 | it doesn't exist (only when creating a blog) [default: .]
22 |
23 | Options:
24 | -s, --skeleton Don't create sample posts and templates
25 | -R, --rebuild Rebuild the blog before serving
26 | -p, --port The port to listen on [default: 2703]
27 | -w, --watch Rebuild the blog when posts or templates change
28 | -q, --quiet Show only errors
29 | -h, --help Show this screen
30 | -v, --version Show version
31 | ```
32 |
--------------------------------------------------------------------------------
/cli/sample/posts/installation.md:
--------------------------------------------------------------------------------
1 | # Installation
2 |
3 | *Nov 17, 2015*
4 |
5 | *Docs, Basics*
6 |
7 | Download a [release](https://github.com/mirovarga/litepub/releases) and unpack
8 | it to a directory. That's all.
9 |
10 | > You can optionally add the directory to the `PATH` so you can run `litepub`
11 | from any directory. All examples assume you have `litepub` in your `PATH`.
12 |
13 | **Next**: [Creating a Blog](/creating-a-blog.html)
14 |
--------------------------------------------------------------------------------
/cli/sample/posts/overview.md:
--------------------------------------------------------------------------------
1 | # Overview
2 |
3 | *Nov 19, 2015*
4 |
5 | LitePub is a static blog generator that tries to be as easy to use as possible.
6 |
7 | It requires no software dependencies, needs no configuration files, uses no
8 | databases. All it needs is one binary, posts written in
9 | [Markdown](https://en.wikipedia.org/wiki/Markdown) and a set of templates to
10 | render the posts to static HTML files.
11 |
12 | Posts don't have to include any special metadata (aka front matter) like title
13 | or date in them - the title, date and optional tags are parsed from the natural
14 | flow of the posts.
15 |
16 | **Next**: [Quick Start](/quick-start.html)
17 |
--------------------------------------------------------------------------------
/cli/sample/posts/quick-start.md:
--------------------------------------------------------------------------------
1 | # Quick Start
2 |
3 | *Nov 18, 2015*
4 |
5 | *Docs, Tutorial*
6 |
7 | To create a sample blog follow these steps:
8 |
9 | 1. Download a [release](https://github.com/mirovarga/litepub/releases) and
10 | unpack it to a directory.
11 |
12 | 2. `cd` to the directory.
13 |
14 | 3. Create a sample blog:
15 |
16 | ```
17 | $ ./litepub create
18 | ```
19 |
20 | 4. Build the blog:
21 |
22 | ```
23 | $ ./litepub build
24 |
25 | Generating: index.html Generating: tags/reference.html Generating:
26 | tags/tutorial.html Generating: tags/advanced.html Generating: tags/docs.html
27 | Generating: tags/basics.html Generating: overview.html Generating:
28 | quick-start.html Generating: installation.html Generating: creating-a-blog.html
29 | Generating: creating-posts.html Generating:
30 | generating-html-files-for-a-blog-aka-building-a-blog.html Generating:
31 | serving-a-blog.html Generating: templates.html Generating: getting-help.html
32 |
33 | ```
34 |
35 | 5. Run the built-in server:
36 |
37 | ```
38 |
39 | $ ./litepub serve Running on http://localhost:2703
40 | Ctrl+C to quit
41 |
42 | ```
43 |
44 | 6. Open [http://localhost:2703](http://localhost:2703) in your browser.
45 |
46 | **Next**: [Installation](/installation.html)
47 |
--------------------------------------------------------------------------------
/cli/sample/posts/serving-a-blog.md:
--------------------------------------------------------------------------------
1 | # Serving a Blog
2 |
3 | *Nov 13, 2015*
4 |
5 | *Docs, Basics*
6 |
7 | LitePub has a built-in server so you can see how a generated blog looks like in
8 | a browser. `cd` to the blog's directory and start the server:
9 |
10 | ```
11 | $ litepub serve
12 | Running on http://localhost:2703
13 | Ctrl+C to quit
14 | ```
15 |
16 | Now open [http://localhost:2703](http://localhost:2703) in your browser to see
17 | the generated blog.
18 |
19 | > Note that the server ignores the draft posts.
20 |
21 | ## Serving a Blog on a Different Port
22 |
23 | When starting the server you can specify a port on which to listen with the
24 | `--port` option:
25 |
26 | ```
27 | $ litepub serve --port 3000
28 | Running on http://localhost:3000
29 | Ctrl+C to quit
30 | ```
31 |
32 | ## Serving a Blog and Watching for Changes
33 |
34 | When creating templates or even writing posts it's quite useful to be able to
35 | immediately see the changes after refreshing the page. To tell LitePub that it
36 | should watch for changes to posts and templates use the `--watch` option:
37 |
38 | ```
39 | $ litepub serve --watch
40 | Running on http://localhost:2703
41 | Rebuilding when posts or templates change
42 | Ctrl+C to quit
43 | ```
44 |
45 | > Note that subdirectories in the `posts` and `templates` directories aren't watched.
46 |
47 | ## Rebuilding a Blog Before Serving
48 |
49 | Sometimes it can be useful to rebuild a blog before serving it, for example when
50 | you don't remember if you made any changes to posts or templates. To rebuild a
51 | blog before serving use the `--rebuild` option:
52 |
53 | ```
54 | $ litepub serve --rebuild
55 | Generating: index.html
56 | Generating: tags/reference.html
57 | Generating: tags/tutorial.html
58 | Generating: tags/advanced.html
59 | Generating: tags/docs.html
60 | Generating: tags/basics.html
61 | Generating: overview.html
62 | Generating: quick-start.html
63 | Generating: installation.html
64 | Generating: creating-a-blog.html
65 | Generating: creating-posts.html
66 | Generating: generating-html-files-for-a-blog-aka-building-a-blog.html
67 | Generating: serving-a-blog.html
68 | Generating: templates.html
69 | Generating: getting-help.html
70 | Running on http://localhost:2703
71 | Ctrl+C to quit
72 | ```
73 |
74 | ## The **serve** Command Reference
75 |
76 | ```
77 | Usage:
78 | litepub serve [] [-R, --rebuild] [-p, --port ] [-w, --watch] [-q, --quiet]
79 |
80 | Arguments:
81 | The directory to create the blog in or look for; it will be created if
82 | it doesn't exist (only when creating a blog) [default: .]
83 |
84 | Options:
85 | -R, --rebuild Rebuild the blog before serving
86 | -p, --port The port to listen on [default: 2703]
87 | -w, --watch Rebuild the blog when posts or templates change
88 | -q, --quiet Show only errors
89 | ```
90 |
91 | **Next**: [Templates](/templates.html)
92 |
--------------------------------------------------------------------------------
/cli/sample/posts/templates.md:
--------------------------------------------------------------------------------
1 | # Templates
2 |
3 | *Nov 12, 2015*
4 |
5 | *Docs, Advanced*
6 |
7 | The `create` command adds sample templates to the `templates` directory. Of
8 | course, you can change them or create your own from scratch.
9 |
10 | LitePub uses the Go [html/template](https://golang.org/pkg/html/template/)
11 | package to define the templates.
12 |
13 | > Design changes require no knowledge of Go templates. However changes that affect what data is displayed will require it less or more (depending on the change).
14 |
15 | ## Structure
16 |
17 | There are four required files in the `templates` directory:
18 |
19 | ```bash
20 | templates/ # the templates and accompanying files (html, css, js, png, etc.)
21 | layout.tmpl
22 | index.tmpl
23 | post.tmpl
24 | tag.tmpl
25 | ```
26 |
27 | - `layout.tmpl` defines the common layout for the home page (`index.tmpl`), post
28 | pages (`post.tmpl`) and tag pages (`tag.tmpl`)
29 | - `index.tmpl` is used when generating the home page (`index.html`)
30 | - `post.tmpl` is used when generating post pages
31 | - and `tag.tmpl` is used when generating tag pages
32 |
33 | Besides the four files there can be any number of `html`, `css`, `js`, `png`,
34 | etc. files that are used by the `.tmpl` files.
35 |
36 | > If you're not familiar with Go templates, some things in the next sections can be unclear.
37 |
38 | ## Data
39 |
40 | Templates have access to data they are meant to display. There are two types of
41 | data: `Post`s and `Tag`s.
42 |
43 | ### Posts
44 |
45 | A `Post` has the following properties:
46 |
47 | - `Title` - the post title
48 | - `Content` - the content of the post as Markdown text
49 | - `Written` - the post's date
50 | - `Tags` - an array of tags the post is tagged with (can be empty)
51 | - `Draft` - `true` if the post is a draft
52 |
53 | > To get a post's page URL in a template use the `slug` function (described below) like this: `A Post`.
54 |
55 | ### Tags
56 |
57 | A `Tag` has the following properties:
58 |
59 | - `Name` - the tag name
60 | - `Posts` - an array of `Post`s that are tagged with the tag sorted by `Written`
61 | in descending order
62 |
63 | > To get a tag's page URL in a template use the `slug` function (described below) like this: `A Tag`.
64 |
65 | The `index.tmpl` template has access to an array of `Post`s sorted by `Written`
66 | in descending order. The `post.tmpl` template has access to the `Post` it
67 | displays. The `tag.tmpl` template has access to the `Tag` it displays.
68 |
69 | ## Functions
70 |
71 | The `index.tmpl`, `post.tmpl` and `tag.tmpl` templates have access to the
72 | following functions:
73 |
74 | ### html
75 |
76 | Converts a Markdown string to a raw HTML, for example `{{.Content | html}}`.
77 |
78 | ### summary
79 |
80 | Extracts the first paragraph of a Markdown string that isn't a header (doesn't
81 | start with a `#`), for example `{{.Content | summary | html}}`.
82 |
83 | ### even
84 |
85 | Returns `true` if an integer is even, for example
86 | `{{if even $i}}{{end}}`.
87 |
88 | ### inc
89 |
90 | Increments an integer by one, for example
91 | `{{if or (eq (inc $i) $l) (not (even $i))}}{{end}}`.
92 |
93 | ### slug
94 |
95 | Slugifies a string, for example `A Post`.
96 |
97 | > The available functions represent my needs when converting my handmade blog to a generated one.
98 |
99 | **Next**: [Getting Help](/getting-help.html)
100 |
--------------------------------------------------------------------------------
/cli/sample/templates/css/font.min.css:
--------------------------------------------------------------------------------
1 | @font-face{font-family:Raleway;font-style:normal;font-weight:300;src:local('Raleway Light'),local('Raleway-Light'),url(https://fonts.gstatic.com/s/raleway/v9/-_Ctzj9b56b8RgXW8FArifk_vArhqVIZ0nv9q090hN8.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02C6,U+02DA,U+02DC,U+2000-206F,U+2074,U+20AC,U+2212,U+2215,U+E0FF,U+EFFD,U+F000}@font-face{font-family:Raleway;font-style:normal;font-weight:400;src:local('Raleway'),url(https://fonts.gstatic.com/s/raleway/v9/0dTEPzkLWceF7z0koJaX1A.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02C6,U+02DA,U+02DC,U+2000-206F,U+2074,U+20AC,U+2212,U+2215,U+E0FF,U+EFFD,U+F000}@font-face{font-family:Raleway;font-style:normal;font-weight:600;src:local('Raleway SemiBold'),local('Raleway-SemiBold'),url(https://fonts.gstatic.com/s/raleway/v9/xkvoNo9fC8O2RDydKj12b_k_vArhqVIZ0nv9q090hN8.woff2) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02C6,U+02DA,U+02DC,U+2000-206F,U+2074,U+20AC,U+2212,U+2215,U+E0FF,U+EFFD,U+F000}
2 |
--------------------------------------------------------------------------------
/cli/sample/templates/css/main.min.css:
--------------------------------------------------------------------------------
1 | a,a:active,a:focus,a:hover{color:#888;text-decoration:none}a,footer,header{color:#888}body{font-size:1.8rem}a{border-bottom:1px dotted #888}a:active,a:focus,a:hover{border-bottom:1px solid #888}a.logo{font-size:2rem;font-weight:700}a.logo img{vertical-align:text-top}a.img,a.logo{border-bottom:none}blockquote{font-style:italic;border-left:.2rem solid #bbb;margin:0;padding-left:2rem}pre{font-size:1.6rem;padding:0!important}code{border:none}header{margin-top:2rem;margin-bottom:4rem}footer{margin-top:8rem;margin-bottom:2rem}.what{text-align:center;margin-bottom:6rem}
2 |
--------------------------------------------------------------------------------
/cli/sample/templates/css/normalize.min.css:
--------------------------------------------------------------------------------
1 | /*! normalize.css v3.0.2 | MIT License | git.io/normalize */html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}h1{font-size:2em;margin:.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}
2 |
--------------------------------------------------------------------------------
/cli/sample/templates/css/prism.min.css:
--------------------------------------------------------------------------------
1 | code[class*=language-],pre[class*=language-]{color:#000;text-shadow:0 1px #fff;font-family:Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace;direction:ltr;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none}code[class*=language-] ::-moz-selection,code[class*=language-]::-moz-selection,pre[class*=language-] ::-moz-selection,pre[class*=language-]::-moz-selection{text-shadow:none;background:#b3d4fc}code[class*=language-] ::selection,code[class*=language-]::selection,pre[class*=language-] ::selection,pre[class*=language-]::selection{text-shadow:none;background:#b3d4fc}@media print{code[class*=language-],pre[class*=language-]{text-shadow:none}}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto}:not(pre)>code[class*=language-],pre[class*=language-]{background:#f5f2f0}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#708090}.token.punctuation{color:#999}.namespace{opacity:.7}.token.boolean,.token.constant,.token.deleted,.token.number,.token.property,.token.symbol,.token.tag{color:#905}.token.attr-name,.token.builtin,.token.char,.token.inserted,.token.selector,.token.string{color:#690}.language-css .token.string,.style .token.string,.token.entity,.token.operator,.token.url{color:#a67f59;background:hsla(0,0%,100%,.5)}.token.atrule,.token.attr-value,.token.keyword{color:#07a}.token.function{color:#DD4A68}.token.important,.token.regex,.token.variable{color:#e90}.token.bold,.token.important{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help}
2 |
--------------------------------------------------------------------------------
/cli/sample/templates/css/skeleton.min.css:
--------------------------------------------------------------------------------
1 | .container{position:relative;width:100%;max-width:960px;margin:0 auto;padding:0 20px;box-sizing:border-box}.column,.columns{width:100%;float:left;box-sizing:border-box}@media (min-width:400px){.container{width:85%;padding:0}}@media (min-width:550px){.container{width:80%}.column,.columns{margin-left:4%}.column:first-child,.columns:first-child{margin-left:0}.one.column,.one.columns{width:4.66666666667%}.two.columns{width:13.3333333333%}.three.columns{width:22%}.four.columns{width:30.6666666667%}.five.columns{width:39.3333333333%}.six.columns{width:48%}.seven.columns{width:56.6666666667%}.eight.columns{width:65.3333333333%}.nine.columns{width:74%}.ten.columns{width:82.6666666667%}.eleven.columns{width:91.3333333333%}.twelve.columns{width:100%;margin-left:0}.one-third.column{width:30.6666666667%}.two-thirds.column{width:65.3333333333%}.one-half.column{width:48%}.offset-by-one.column,.offset-by-one.columns{margin-left:8.66666666667%}.offset-by-two.column,.offset-by-two.columns{margin-left:17.3333333333%}.offset-by-three.column,.offset-by-three.columns{margin-left:26%}.offset-by-four.column,.offset-by-four.columns{margin-left:34.6666666667%}.offset-by-five.column,.offset-by-five.columns{margin-left:43.3333333333%}.offset-by-six.column,.offset-by-six.columns{margin-left:52%}.offset-by-seven.column,.offset-by-seven.columns{margin-left:60.6666666667%}.offset-by-eight.column,.offset-by-eight.columns{margin-left:69.3333333333%}.offset-by-nine.column,.offset-by-nine.columns{margin-left:78%}.offset-by-ten.column,.offset-by-ten.columns{margin-left:86.6666666667%}.offset-by-eleven.column,.offset-by-eleven.columns{margin-left:95.3333333333%}.offset-by-one-third.column,.offset-by-one-third.columns{margin-left:34.6666666667%}.offset-by-two-thirds.column,.offset-by-two-thirds.columns{margin-left:69.3333333333%}.offset-by-one-half.column,.offset-by-one-half.columns{margin-left:52%}}html{font-size:62.5%}body{font-size:1.5em;line-height:1.6;font-weight:400;font-family:Raleway,HelveticaNeue,"Helvetica Neue",Helvetica,Arial,sans-serif;color:#222}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:2rem;font-weight:300}h1{font-size:4rem;line-height:1.2;letter-spacing:-.1rem}h2{font-size:3.6rem;line-height:1.25;letter-spacing:-.1rem}h3{font-size:3rem;line-height:1.3;letter-spacing:-.1rem}h4{font-size:2.4rem;line-height:1.35;letter-spacing:-.08rem}h5{font-size:1.8rem;line-height:1.5;letter-spacing:-.05rem}h6{font-size:1.5rem;line-height:1.6;letter-spacing:0}@media (min-width:550px){h1{font-size:5rem}h2{font-size:4.2rem}h3{font-size:3.6rem}h4{font-size:3rem}h5{font-size:2.4rem}h6{font-size:1.5rem}}p{margin-top:0}a{color:#1EAEDB}a:hover{color:#0FA0CE}.button,button,input[type=button],input[type=reset],input[type=submit]{display:inline-block;height:38px;padding:0 30px;color:#555;text-align:center;font-size:11px;font-weight:600;line-height:38px;letter-spacing:.1rem;text-transform:uppercase;text-decoration:none;white-space:nowrap;background-color:transparent;border-radius:4px;border:1px solid #bbb;cursor:pointer;box-sizing:border-box}.button:focus,.button:hover,button:focus,button:hover,input[type=button]:focus,input[type=button]:hover,input[type=reset]:focus,input[type=reset]:hover,input[type=submit]:focus,input[type=submit]:hover{color:#333;border-color:#888;outline:0}.button.button-primary,button.button-primary,input[type=button].button-primary,input[type=reset].button-primary,input[type=submit].button-primary{color:#FFF;background-color:#33C3F0;border-color:#33C3F0}.button.button-primary:focus,.button.button-primary:hover,button.button-primary:focus,button.button-primary:hover,input[type=button].button-primary:focus,input[type=button].button-primary:hover,input[type=reset].button-primary:focus,input[type=reset].button-primary:hover,input[type=submit].button-primary:focus,input[type=submit].button-primary:hover{color:#FFF;background-color:#1EAEDB;border-color:#1EAEDB}input[type=email],input[type=number],input[type=password],input[type=search],input[type=tel],input[type=text],input[type=url],select,textarea{height:38px;padding:6px 10px;background-color:#fff;border:1px solid #D1D1D1;border-radius:4px;box-shadow:none;box-sizing:border-box}input[type=email],input[type=number],input[type=password],input[type=search],input[type=tel],input[type=text],input[type=url],textarea{-webkit-appearance:none;-moz-appearance:none;appearance:none}textarea{min-height:65px;padding-top:6px;padding-bottom:6px}input[type=email]:focus,input[type=number]:focus,input[type=password]:focus,input[type=search]:focus,input[type=tel]:focus,input[type=text]:focus,input[type=url]:focus,select:focus,textarea:focus{border:1px solid #33C3F0;outline:0}label,legend{display:block;margin-bottom:.5rem;font-weight:600}fieldset{padding:0;border-width:0}input[type=checkbox],input[type=radio]{display:inline}label>.label-body{display:inline-block;margin-left:.5rem;font-weight:400}ul{list-style:circle inside}ol{list-style:decimal inside}ol,ul{padding-left:0;margin-top:0}ol ol,ol ul,ul ol,ul ul{margin:1.5rem 0 1.5rem 3rem;font-size:90%}li{margin-bottom:1rem}code{padding:.2rem .5rem;margin:0 .2rem;font-size:90%;white-space:nowrap;background:#F1F1F1;border:1px solid #E1E1E1;border-radius:4px}pre>code{display:block;padding:1rem 1.5rem;white-space:pre}td,th{padding:12px 15px;text-align:left;border-bottom:1px solid #E1E1E1}td:first-child,th:first-child{padding-left:0}td:last-child,th:last-child{padding-right:0}.button,button{margin-bottom:1rem}fieldset,input,select,textarea{margin-bottom:1.5rem}blockquote,dl,figure,form,ol,p,pre,table,ul{margin-bottom:2.5rem}.u-full-width{width:100%;box-sizing:border-box}.u-max-full-width{max-width:100%;box-sizing:border-box}.u-pull-right{float:right}.u-pull-left{float:left}hr{margin-top:3rem;margin-bottom:3.5rem;border-width:0;border-top:1px solid #E1E1E1}.container:after,.row:after,.u-cf{content:"";display:table;clear:both}
2 |
--------------------------------------------------------------------------------
/cli/sample/templates/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mirovarga/litepub/ddfb969bdf6cc8ac5d5496381ed69edde665adfa/cli/sample/templates/favicon.ico
--------------------------------------------------------------------------------
/cli/sample/templates/images/email-16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mirovarga/litepub/ddfb969bdf6cc8ac5d5496381ed69edde665adfa/cli/sample/templates/images/email-16.png
--------------------------------------------------------------------------------
/cli/sample/templates/images/email-24.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mirovarga/litepub/ddfb969bdf6cc8ac5d5496381ed69edde665adfa/cli/sample/templates/images/email-24.png
--------------------------------------------------------------------------------
/cli/sample/templates/images/github-16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mirovarga/litepub/ddfb969bdf6cc8ac5d5496381ed69edde665adfa/cli/sample/templates/images/github-16.png
--------------------------------------------------------------------------------
/cli/sample/templates/images/github-24.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mirovarga/litepub/ddfb969bdf6cc8ac5d5496381ed69edde665adfa/cli/sample/templates/images/github-24.png
--------------------------------------------------------------------------------
/cli/sample/templates/images/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mirovarga/litepub/ddfb969bdf6cc8ac5d5496381ed69edde665adfa/cli/sample/templates/images/logo.png
--------------------------------------------------------------------------------
/cli/sample/templates/images/twitter-16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mirovarga/litepub/ddfb969bdf6cc8ac5d5496381ed69edde665adfa/cli/sample/templates/images/twitter-16.png
--------------------------------------------------------------------------------
/cli/sample/templates/images/twitter-24.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mirovarga/litepub/ddfb969bdf6cc8ac5d5496381ed69edde665adfa/cli/sample/templates/images/twitter-24.png
--------------------------------------------------------------------------------
/cli/sample/templates/index.tmpl:
--------------------------------------------------------------------------------
1 | {{define "title"}}
2 | A lightweight static blog generator
3 | {{end}}
4 |
5 | {{define "content"}}
6 |
7 |
8 |
A Lightweight Static Blog Generator
9 |
10 |
11 |
12 | Single Binary · No Configuration · Posts in Markdown
13 | · No Front Matter · Tags · Drafts ·
14 | Built-in Server
15 |