|
diff --git a/README.md b/README.md
|
| ... |
| 9 |
instead. But if you need a simple blog page that needs to spit out an RSS feed |
9 |
instead. But if you need a simple blog page that needs to spit out an RSS feed |
| 10 |
or two and have the option to define different templates for different posts, |
10 |
or two and have the option to define different templates for different posts, |
| 11 |
well then this might be useful to you. |
11 |
well then this might be useful to you. |
|
|
12 |
|
|
|
13 |
The only thing hard about this project is the spelling of its name. |
|
|
14 |
|
|
|
15 |
Some facts (will be more clear when you read the whole readme): |
|
|
16 |
|
|
|
17 |
- You cannot nest your markdown file under `content` folder. All files must be |
|
|
18 |
in the root of `content` folder. |
|
|
19 |
- `public` folder gets automatically created on `jbmafp --build`. |
|
|
20 |
- All files in `static` folder will be moved to the root of `public` folder. |
|
|
21 |
- When you provide `url` in your markdown files, this will create these files in |
|
|
22 |
the root of `public` folder. No nesting allowed. |
|
|
23 |
|
|
|
24 |
## Install |
|
|
25 |
|
|
|
26 |
```sh |
|
|
27 |
git clone git@github.com:mitjafelicijan/jbmafp.git |
|
|
28 |
cd jbmafp |
|
|
29 |
go install . |
|
|
30 |
``` |
|
|
31 |
|
|
|
32 |
## Generate first site |
|
|
33 |
|
|
|
34 |
- Go to your projects folder or wherever you want to place the site. |
|
|
35 |
|
|
|
36 |
```sh |
|
|
37 |
mkdir my-ugly-website |
|
|
38 |
cd my-ugly-website |
|
|
39 |
jbmafp --init |
|
|
40 |
jbmafp --build |
|
|
41 |
``` |
|
|
42 |
|
|
|
43 |
- Check out `public` folder and you will see a website. That is about it. |
|
|
44 |
- You can also do `jbmafp --help` to see all the option. |
|
|
45 |
|
|
|
46 |
## Understanding all this bullshit |
|
|
47 |
|
|
|
48 |
- Posts go into `content` folder. |
|
|
49 |
- You can change them in `templates` folder. |
|
|
50 |
- Each post must have. All of the fields are required. If you have ever used |
|
|
51 |
Hugo, this is the same thing. Below is example `content/first.md`. |
|
|
52 |
|
|
|
53 |
```md |
|
|
54 |
--- |
|
|
55 |
title: "My first post" |
|
|
56 |
url: first.html |
|
|
57 |
date: 2023-06-29T14:51:39+02:00 |
|
|
58 |
type: post |
|
|
59 |
draft: false |
|
|
60 |
--- |
|
|
61 |
|
|
|
62 |
This is my first post. It ain't much but it's an honest post. |
|
|
63 |
``` |
|
|
64 |
|
|
|
65 |
- `type` is used all over the place. It is used to define a template file of the |
|
|
66 |
page that will be generated. If type is `post` then the program will load |
|
|
67 |
`templates/post.html` to handle generation of the page. |
|
|
68 |
- You can use whatever name you want. I use `note`, `post` as types to separate |
|
|
69 |
all the pages into categories. |
|
|
70 |
- `type` is also used inside templates like: |
|
|
71 |
```html |
|
|
72 |
<ul> |
|
|
73 |
{{ range .Pages }} |
|
|
74 |
{{ if eq .Type "post" }} |
|
|
75 |
<li><a href="/{{ .RelPermalink }}">{{ .Title }}</a></li> |
|
|
76 |
{{ end }} |
|
|
77 |
{{ end }} |
|
|
78 |
</ul> |
|
|
79 |
``` |
|
|
80 |
- This is also use for generating RSS feed. Check `templates/index.xml` to see |
|
|
81 |
the example. |
|
|
82 |
- This opens door to quite versatile build option. |
|
|
83 |
- You can trigger additional generation of content under `extras` field in |
|
|
84 |
`config.yaml` file. RSS feed gets generated this way. `template` field tells |
|
|
85 |
generator which file in `templates` folder to use and `url` tells generator |
|
|
86 |
what the file should be called when its saved. |
|
|
87 |
|
|
|
88 |
## License |
|
|
89 |
|
|
|
90 |
[jbmafp](https://github.com/mitjafelicijan/jbmafp) was written by [Mitja |
|
|
91 |
Felicijan](https://mitjafelicijan.com) and is released under the BSD two-clause |
|
|
92 |
license, see the LICENSE file for more information. |
|
diff --git a/main.go b/main.go
|
| ... |
| 32 |
highlighting "github.com/yuin/goldmark-highlighting/v2" |
32 |
highlighting "github.com/yuin/goldmark-highlighting/v2" |
| 33 |
|
33 |
|
| 34 |
cp "github.com/otiai10/copy" |
34 |
cp "github.com/otiai10/copy" |
|
|
35 |
|
|
|
36 |
_ "embed" |
| 35 |
) |
37 |
) |
| 36 |
|
38 |
|
| 37 |
type ConfigExtrasItem struct { |
39 |
type ConfigExtrasItem struct { |
| ... |
| 64 |
Draft bool |
66 |
Draft bool |
| 65 |
} |
67 |
} |
| 66 |
|
68 |
|
|
|
69 |
//go:embed "files/config.yaml" |
|
|
70 |
var EmbedConfig string |
|
|
71 |
|
|
|
72 |
//go:embed "files/first.md" |
|
|
73 |
var EmbedPost string |
|
|
74 |
|
|
|
75 |
//go:embed "files/base.html" |
|
|
76 |
var EmbedTemplateBase string |
|
|
77 |
|
|
|
78 |
//go:embed "files/index.html" |
|
|
79 |
var EmbedTemplateIndex string |
|
|
80 |
|
|
|
81 |
//go:embed "files/post.html" |
|
|
82 |
var EmbedTemplatePost string |
|
|
83 |
|
|
|
84 |
//go:embed "files/index.xml" |
|
|
85 |
var EmbedTemplateFeed string |
|
|
86 |
|
| 67 |
// Function to clean HTML tags using bluemonday. |
87 |
// Function to clean HTML tags using bluemonday. |
| 68 |
func cleanHTMLTags(htmlString string) string { |
88 |
func cleanHTMLTags(htmlString string) string { |
| 69 |
p := bluemonday.StrictPolicy() |
89 |
p := bluemonday.StrictPolicy() |
| ... |
| 72 |
} |
92 |
} |
| 73 |
|
93 |
|
| 74 |
func initializeProject(projectRoot string) { |
94 |
func initializeProject(projectRoot string) { |
| 75 |
fmt.Println("Initializing new project") |
95 |
log.Println("Initializing new project") |
| 76 |
} |
|
|
| 77 |
|
96 |
|
| 78 |
func main() { |
97 |
if err := os.Mkdir(path.Join(projectRoot, "templates"), 0755); err != nil && !os.IsExist(err) { |
| 79 |
projectRoot := os.Getenv("PROJECT_ROOT") |
98 |
log.Println("Error creating directory:", err) |
| 80 |
if projectRoot == "" { |
99 |
return |
| 81 |
projectRoot = "./" |
|
|
| 82 |
} |
100 |
} |
| 83 |
|
101 |
|
| 84 |
fmt.Println("Come back later! Still WIP!") |
102 |
if err := os.Mkdir(path.Join(projectRoot, "content"), 0755); err != nil && !os.IsExist(err) { |
| 85 |
os.Exit(0) |
103 |
log.Println("Error creating directory:", err) |
| 86 |
|
104 |
return |
| 87 |
// Parsing arguments. |
|
|
| 88 |
var args struct { |
|
|
| 89 |
Init bool `arg:"-i,--init" help:"initialize new project"` |
|
|
| 90 |
Build bool `arg:"-b,--build" help:"build the website"` |
|
|
| 91 |
} |
105 |
} |
| 92 |
|
106 |
|
| 93 |
arg.MustParse(&args) |
107 |
if err := os.Mkdir(path.Join(projectRoot, "static"), 0755); err != nil && !os.IsExist(err) { |
| 94 |
|
108 |
log.Println("Error creating directory:", err) |
| 95 |
if !args.Init && !args.Build { |
109 |
return |
| 96 |
fmt.Println("No arguments provided. Try using `jbmafp --help`") |
|
|
| 97 |
os.Exit(0) |
|
|
| 98 |
} |
110 |
} |
| 99 |
|
111 |
|
| 100 |
if args.Init { |
112 |
os.WriteFile(path.Join(projectRoot, "templates", ".gitkeep"), []byte{}, 0755) |
| 101 |
initializeProject(projectRoot) |
113 |
os.WriteFile(path.Join(projectRoot, "content", ".gitkeep"), []byte{}, 0755) |
| 102 |
os.Exit(0) |
114 |
os.WriteFile(path.Join(projectRoot, "static", ".gitkeep"), []byte{}, 0755) |
| 103 |
} |
|
|
| 104 |
|
115 |
|
| 105 |
os.Exit(0) |
116 |
os.WriteFile(path.Join(projectRoot, "config.yaml"), []byte(EmbedConfig), 0755) |
|
|
117 |
os.WriteFile(path.Join(projectRoot, "content", "first.md"), []byte(EmbedPost), 0755) |
|
|
118 |
os.WriteFile(path.Join(projectRoot, "templates", "base.html"), []byte(EmbedTemplateBase), 0755) |
|
|
119 |
os.WriteFile(path.Join(projectRoot, "templates", "index.html"), []byte(EmbedTemplateIndex), 0755) |
|
|
120 |
os.WriteFile(path.Join(projectRoot, "templates", "post.html"), []byte(EmbedTemplatePost), 0755) |
|
|
121 |
os.WriteFile(path.Join(projectRoot, "templates", "index.xml"), []byte(EmbedTemplateFeed), 0755) |
|
|
122 |
} |
| 106 |
|
123 |
|
|
|
124 |
func buildProject(projectRoot string) { |
| 107 |
// Read config file. |
125 |
// Read config file. |
| 108 |
configFilepath := path.Join(projectRoot, "config.yaml") |
126 |
configFilepath := path.Join(projectRoot, "config.yaml") |
| 109 |
configFile, err := os.ReadFile(configFilepath) |
127 |
configFile, err := os.ReadFile(configFilepath) |
| ... |
| 195 |
return pages[i].Created.After(pages[j].Created) |
213 |
return pages[i].Created.After(pages[j].Created) |
| 196 |
}) |
214 |
}) |
| 197 |
|
215 |
|
|
|
216 |
// Creates public folder if it doesn't exist yet. |
|
|
217 |
if err := os.Mkdir(path.Join(projectRoot, "public"), 0755); err != nil && !os.IsExist(err) { |
|
|
218 |
log.Println("Error creating directory:", err) |
|
|
219 |
return |
|
|
220 |
} |
|
|
221 |
|
| 198 |
// Generate HTML files for all pages. |
222 |
// Generate HTML files for all pages. |
| 199 |
for _, page := range pages { |
223 |
for _, page := range pages { |
| 200 |
outFilepath := path.Join(projectRoot, "public", page.Meta["url"].(string)) |
224 |
outFilepath := path.Join(projectRoot, "public", page.Meta["url"].(string)) |
| ... |
| 237 |
log.Println("Wrote", outFilepath) |
261 |
log.Println("Wrote", outFilepath) |
| 238 |
} else { |
262 |
} else { |
| 239 |
log.Println("Skipped", outFilepath) |
263 |
log.Println("Skipped", outFilepath) |
| 240 |
|
|
|
| 241 |
} |
264 |
} |
| 242 |
|
|
|
| 243 |
} |
265 |
} |
| 244 |
|
266 |
|
| 245 |
// Generates index page. |
267 |
// Generates index page. |
| ... |
| 317 |
|
339 |
|
| 318 |
outFilepath := path.Join(projectRoot, "public", extra.URL) |
340 |
outFilepath := path.Join(projectRoot, "public", extra.URL) |
| 319 |
os.WriteFile(outFilepath, []byte(buf.String()), 0755) |
341 |
os.WriteFile(outFilepath, []byte(buf.String()), 0755) |
| 320 |
|
|
|
| 321 |
} |
342 |
} |
| 322 |
} |
343 |
} |
| 323 |
|
344 |
|
| 324 |
// Guess we are done! |
345 |
// Guess we are done! |
| 325 |
log.Println("Done & done...") |
346 |
log.Println("Done & done...") |
| 326 |
} |
347 |
} |
|
|
348 |
|
|
|
349 |
func main() { |
|
|
350 |
projectRoot := os.Getenv("PROJECT_ROOT") |
|
|
351 |
if projectRoot == "" { |
|
|
352 |
projectRoot = "./" |
|
|
353 |
} |
|
|
354 |
|
|
|
355 |
var args struct { |
|
|
356 |
Init bool `arg:"-i,--init" help:"initialize new project"` |
|
|
357 |
Build bool `arg:"-b,--build" help:"build the website"` |
|
|
358 |
} |
|
|
359 |
|
|
|
360 |
arg.MustParse(&args) |
|
|
361 |
|
|
|
362 |
if !args.Init && !args.Build { |
|
|
363 |
fmt.Println("No arguments provided. Try using `jbmafp --help`") |
|
|
364 |
os.Exit(0) |
|
|
365 |
} |
|
|
366 |
|
|
|
367 |
if args.Init { |
|
|
368 |
initializeProject(projectRoot) |
|
|
369 |
} |
|
|
370 |
|
|
|
371 |
if args.Build { |
|
|
372 |
buildProject(projectRoot) |
|
|
373 |
} |
|
|
374 |
} |