diff options
| -rw-r--r-- | .gitignore | 2 | ||||
| -rw-r--r-- | README.md | 81 | ||||
| -rw-r--r-- | files/base.html | 15 | ||||
| -rw-r--r-- | files/config.yaml | 16 | ||||
| -rw-r--r-- | files/first.md | 15 | ||||
| -rw-r--r-- | files/index.html | 14 | ||||
| -rw-r--r-- | files/index.xml | 21 | ||||
| -rw-r--r-- | files/post.html | 14 | ||||
| -rw-r--r-- | main.go | 100 |
9 files changed, 252 insertions, 26 deletions
@@ -1,2 +1,4 @@ public/ example/ +junk/ +jbmafp
\ No newline at end of file @@ -9,3 +9,84 @@ This generator is not for people who need something more complicated. Use Hugo instead. But if you need a simple blog page that needs to spit out an RSS feed or two and have the option to define different templates for different posts, well then this might be useful to you. + +The only thing hard about this project is the spelling of its name. + +Some facts (will be more clear when you read the whole readme): + +- You cannot nest your markdown file under `content` folder. All files must be + in the root of `content` folder. +- `public` folder gets automatically created on `jbmafp --build`. +- All files in `static` folder will be moved to the root of `public` folder. +- When you provide `url` in your markdown files, this will create these files in + the root of `public` folder. No nesting allowed. + +## Install + +```sh +git clone git@github.com:mitjafelicijan/jbmafp.git +cd jbmafp +go install . +``` + +## Generate first site + +- Go to your projects folder or wherever you want to place the site. + +```sh +mkdir my-ugly-website +cd my-ugly-website +jbmafp --init +jbmafp --build +``` + +- Check out `public` folder and you will see a website. That is about it. +- You can also do `jbmafp --help` to see all the option. + +## Understanding all this bullshit + +- Posts go into `content` folder. +- You can change them in `templates` folder. +- Each post must have. All of the fields are required. If you have ever used + Hugo, this is the same thing. Below is example `content/first.md`. + +```md +--- +title: "My first post" +url: first.html +date: 2023-06-29T14:51:39+02:00 +type: post +draft: false +--- + +This is my first post. It ain't much but it's an honest post. +``` + +- `type` is used all over the place. It is used to define a template file of the + page that will be generated. If type is `post` then the program will load + `templates/post.html` to handle generation of the page. +- You can use whatever name you want. I use `note`, `post` as types to separate + all the pages into categories. +- `type` is also used inside templates like: + ```html + <ul> + {{ range .Pages }} + {{ if eq .Type "post" }} + <li><a href="/{{ .RelPermalink }}">{{ .Title }}</a></li> + {{ end }} + {{ end }} + </ul> + ``` +- This is also use for generating RSS feed. Check `templates/index.xml` to see + the example. +- This opens door to quite versatile build option. +- You can trigger additional generation of content under `extras` field in + `config.yaml` file. RSS feed gets generated this way. `template` field tells + generator which file in `templates` folder to use and `url` tells generator + what the file should be called when its saved. + +## License + +[jbmafp](https://github.com/mitjafelicijan/jbmafp) was written by [Mitja +Felicijan](https://mitjafelicijan.com) and is released under the BSD two-clause +license, see the LICENSE file for more information. diff --git a/files/base.html b/files/base.html new file mode 100644 index 0000000..d965c25 --- /dev/null +++ b/files/base.html @@ -0,0 +1,15 @@ +<!DOCTYPE html> +<html lang="{{ .Config.Language }}"> + <head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width,initial-scale=1"> + <title>{{ block "title" . }}{{ .Config.Title }}{{ end }}</title> + <meta name="description" content="{{ block "description" . }}{{ .Config.Description }}{{ end }}"> + <link rel="alternate" type="application/rss+xml" href="{{ .Config.BaseURL }}/index.xml"> + </head> + <body> + <main> + {{ block "content" . }}{{ end }} + </main> + </body> +</html> diff --git a/files/config.yaml b/files/config.yaml new file mode 100644 index 0000000..a89795f --- /dev/null +++ b/files/config.yaml @@ -0,0 +1,16 @@ +title: "Title of your website" +baseurl: "https://example.com" +description: "My new shiny website" +language: "en-us" + +# Code highlighting. +# https://swapoff.org/chroma/playground/ +highlighting: "vs" + +# Minifies output HTML (including inline CSS, JS). +minify: true + +# Other generaters, in this case RSS generator. +extras: + - template: index.xml + url: index.xml diff --git a/files/first.md b/files/first.md new file mode 100644 index 0000000..9a4b97f --- /dev/null +++ b/files/first.md @@ -0,0 +1,15 @@ +--- +title: "My first post" +url: first.html +date: 2023-06-29T14:51:39+02:00 +type: post +draft: false +--- + +This is my first post. It ain't much but it's an honest post. + +```lua +for k, v in pairs(arr) do + print(k, v[1], v[2], v[3]) +end +``` diff --git a/files/index.html b/files/index.html new file mode 100644 index 0000000..eeb2641 --- /dev/null +++ b/files/index.html @@ -0,0 +1,14 @@ +{{ template "base.html" . }} + +{{ define "content" }} +<div> + <h2>Posts</h2> + <ul> + {{ range .Pages }} + {{ if eq .Type "post" }} + <li><a href="/{{ .RelPermalink }}">{{ .Title }}</a></li> + {{ end }} + {{ end }} + </ul> +</div> +{{ end }} diff --git a/files/index.xml b/files/index.xml new file mode 100644 index 0000000..830dd90 --- /dev/null +++ b/files/index.xml @@ -0,0 +1,21 @@ +<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"> + <channel> + <title>{{ .Config.Title }}'s posts</title> + <link>{{ .Config.BaseURL }}</link> + <description>{{ .Config.Description }}</description> + <language>{{ .Config.Language }}</language> + + {{ range $idx, $page := .Pages }} + {{ if eq $page.Type "post" }} + <item> + <title>{{ $page.Title }}</title> + <link>{{ $.Config.BaseURL }}/{{ $page.RelPermalink }}</link> + <pubDate>{{ $page.Created.Format "Mon, 02 Jan 2006 15:04:05 -0700" }}</pubDate> + <guid>{{ $.Config.BaseURL }}/{{ $page.RelPermalink }}</guid> + <description>{{ $page.Summary }}</description> + <content:encoded>{{ $page.Raw }}</content:encoded> + </item> + {{ end }} + {{ end }} + </channel> +</rss> diff --git a/files/post.html b/files/post.html new file mode 100644 index 0000000..28ffad2 --- /dev/null +++ b/files/post.html @@ -0,0 +1,14 @@ +{{ template "base.html" . }} + +{{ define "title" }}{{ .Page.Title }}{{ end }} +{{ define "description" }}{{ .Page.Summary }}{{ end }} + +{{ define "content" }} +<div> + <h1>{{ .Page.Title }}</h1> + <p>{{ .Page.Created.Format "Jan 2, 2006" }}</p> + <div> + {{ .Page.HTML }} + </div> +</div> +{{ end }} @@ -32,6 +32,8 @@ import ( highlighting "github.com/yuin/goldmark-highlighting/v2" cp "github.com/otiai10/copy" + + _ "embed" ) type ConfigExtrasItem struct { @@ -64,6 +66,24 @@ type Page struct { Draft bool } +//go:embed "files/config.yaml" +var EmbedConfig string + +//go:embed "files/first.md" +var EmbedPost string + +//go:embed "files/base.html" +var EmbedTemplateBase string + +//go:embed "files/index.html" +var EmbedTemplateIndex string + +//go:embed "files/post.html" +var EmbedTemplatePost string + +//go:embed "files/index.xml" +var EmbedTemplateFeed string + // Function to clean HTML tags using bluemonday. func cleanHTMLTags(htmlString string) string { p := bluemonday.StrictPolicy() @@ -72,38 +92,36 @@ func cleanHTMLTags(htmlString string) string { } func initializeProject(projectRoot string) { - fmt.Println("Initializing new project") -} + log.Println("Initializing new project") -func main() { - projectRoot := os.Getenv("PROJECT_ROOT") - if projectRoot == "" { - projectRoot = "./" + if err := os.Mkdir(path.Join(projectRoot, "templates"), 0755); err != nil && !os.IsExist(err) { + log.Println("Error creating directory:", err) + return } - fmt.Println("Come back later! Still WIP!") - os.Exit(0) - - // Parsing arguments. - var args struct { - Init bool `arg:"-i,--init" help:"initialize new project"` - Build bool `arg:"-b,--build" help:"build the website"` + if err := os.Mkdir(path.Join(projectRoot, "content"), 0755); err != nil && !os.IsExist(err) { + log.Println("Error creating directory:", err) + return } - arg.MustParse(&args) - - if !args.Init && !args.Build { - fmt.Println("No arguments provided. Try using `jbmafp --help`") - os.Exit(0) + if err := os.Mkdir(path.Join(projectRoot, "static"), 0755); err != nil && !os.IsExist(err) { + log.Println("Error creating directory:", err) + return } - if args.Init { - initializeProject(projectRoot) - os.Exit(0) - } + os.WriteFile(path.Join(projectRoot, "templates", ".gitkeep"), []byte{}, 0755) + os.WriteFile(path.Join(projectRoot, "content", ".gitkeep"), []byte{}, 0755) + os.WriteFile(path.Join(projectRoot, "static", ".gitkeep"), []byte{}, 0755) - os.Exit(0) + os.WriteFile(path.Join(projectRoot, "config.yaml"), []byte(EmbedConfig), 0755) + os.WriteFile(path.Join(projectRoot, "content", "first.md"), []byte(EmbedPost), 0755) + os.WriteFile(path.Join(projectRoot, "templates", "base.html"), []byte(EmbedTemplateBase), 0755) + os.WriteFile(path.Join(projectRoot, "templates", "index.html"), []byte(EmbedTemplateIndex), 0755) + os.WriteFile(path.Join(projectRoot, "templates", "post.html"), []byte(EmbedTemplatePost), 0755) + os.WriteFile(path.Join(projectRoot, "templates", "index.xml"), []byte(EmbedTemplateFeed), 0755) +} +func buildProject(projectRoot string) { // Read config file. configFilepath := path.Join(projectRoot, "config.yaml") configFile, err := os.ReadFile(configFilepath) @@ -195,6 +213,12 @@ func main() { return pages[i].Created.After(pages[j].Created) }) + // Creates public folder if it doesn't exist yet. + if err := os.Mkdir(path.Join(projectRoot, "public"), 0755); err != nil && !os.IsExist(err) { + log.Println("Error creating directory:", err) + return + } + // Generate HTML files for all pages. for _, page := range pages { outFilepath := path.Join(projectRoot, "public", page.Meta["url"].(string)) @@ -237,9 +261,7 @@ func main() { log.Println("Wrote", outFilepath) } else { log.Println("Skipped", outFilepath) - } - } // Generates index page. @@ -317,10 +339,36 @@ func main() { outFilepath := path.Join(projectRoot, "public", extra.URL) os.WriteFile(outFilepath, []byte(buf.String()), 0755) - } } // Guess we are done! log.Println("Done & done...") } + +func main() { + projectRoot := os.Getenv("PROJECT_ROOT") + if projectRoot == "" { + projectRoot = "./" + } + + var args struct { + Init bool `arg:"-i,--init" help:"initialize new project"` + Build bool `arg:"-b,--build" help:"build the website"` + } + + arg.MustParse(&args) + + if !args.Init && !args.Build { + fmt.Println("No arguments provided. Try using `jbmafp --help`") + os.Exit(0) + } + + if args.Init { + initializeProject(projectRoot) + } + + if args.Build { + buildProject(projectRoot) + } +} |
