fossbook 0.0.6 → 0.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +68 -0
- package/lib/deploy.js +2 -0
- package/lib/init.js +2 -0
- package/lib/mod/config.js +4 -0
- package/lib/mod/page.js +6 -3
- package/lib/posts.js +4 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# Fossbook
|
|
2
2
|
|
|
3
3
|
A lightweight static blog site generator for GitHub Pages, similar to Hugo but built with Node.js.
|
|
4
|
+
It was originally part of the [F/OSS Comics blog](https://fosscomics.com) and is now an independent, installable package that anyone can use.
|
|
4
5
|
|
|
5
6
|
## Features
|
|
6
7
|
|
|
@@ -85,6 +86,18 @@ module.exports = {
|
|
|
85
86
|
image: "https://example.com/default-image.png",
|
|
86
87
|
theme: "archie",
|
|
87
88
|
|
|
89
|
+
// Optional: URL prefix for posts. Defaults to "posts" -> /posts/<slug>/.
|
|
90
|
+
// Set to "" to serve posts at the site root, /<slug>/.
|
|
91
|
+
postsPath: "posts",
|
|
92
|
+
|
|
93
|
+
// Optional comments (see "Comments" below)
|
|
94
|
+
comments: {
|
|
95
|
+
provider: "utterances",
|
|
96
|
+
repo: "you/your-blog",
|
|
97
|
+
issueTerm: "pathname",
|
|
98
|
+
theme: "github-light",
|
|
99
|
+
},
|
|
100
|
+
|
|
88
101
|
// Directory overrides (defaults shown)
|
|
89
102
|
content: "./content",
|
|
90
103
|
postsDir: "./content/posts",
|
|
@@ -119,6 +132,21 @@ content/posts/My Post Title/
|
|
|
119
132
|
└── feature.png
|
|
120
133
|
```
|
|
121
134
|
|
|
135
|
+
### Post URLs
|
|
136
|
+
|
|
137
|
+
By default, posts are served under `/posts/`, e.g. `/posts/my-post-title/`. To
|
|
138
|
+
change the prefix or move posts to the site root, set `postsPath` in
|
|
139
|
+
`fossbook.config.js`:
|
|
140
|
+
|
|
141
|
+
```js
|
|
142
|
+
postsPath: "", // serves the post above at /my-post-title/ (site root)
|
|
143
|
+
// postsPath: "blog", // or use a different prefix: /blog/my-post-title/
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
This affects the generated output directory, the post URL, post links on the
|
|
147
|
+
home/all-posts/tag pages, and image paths. The on-disk source layout under
|
|
148
|
+
`content/posts/` does not change.
|
|
149
|
+
|
|
122
150
|
## CLI Reference
|
|
123
151
|
|
|
124
152
|
```
|
|
@@ -148,6 +176,46 @@ Fossbook ships with the Archie theme by default. To use a custom theme:
|
|
|
148
176
|
|
|
149
177
|
Theme resolution order: user project `themes/` → built-in `themes/`.
|
|
150
178
|
|
|
179
|
+
## Comments
|
|
180
|
+
|
|
181
|
+
Fossbook supports [utterances](https://utteranc.es) — a commenting widget that
|
|
182
|
+
stores comments as GitHub issues. When enabled, a comment box is rendered at the
|
|
183
|
+
bottom of every post page.
|
|
184
|
+
|
|
185
|
+
### Setup
|
|
186
|
+
|
|
187
|
+
1. Make the repository that backs the comments **public**.
|
|
188
|
+
2. Install the [utterances GitHub App](https://github.com/apps/utterances) on
|
|
189
|
+
that repository so the bot can create issues.
|
|
190
|
+
3. Add a `comments` block to `fossbook.config.js`:
|
|
191
|
+
|
|
192
|
+
```js
|
|
193
|
+
comments: {
|
|
194
|
+
provider: "utterances", // currently the only supported provider
|
|
195
|
+
repo: "you/your-blog", // owner/repo that stores the comment issues
|
|
196
|
+
issueTerm: "pathname", // how a post maps to an issue (see below)
|
|
197
|
+
theme: "github-light", // any utterances theme, e.g. "github-dark"
|
|
198
|
+
},
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
Omit the `comments` block (or set it to `null`) to disable comments.
|
|
202
|
+
|
|
203
|
+
### Options
|
|
204
|
+
|
|
205
|
+
| Field | Required | Default | Description |
|
|
206
|
+
| ----------- | -------- | ---------------- | ---------------------------------------------------------------- |
|
|
207
|
+
| `provider` | yes | — | Must be `"utterances"`. |
|
|
208
|
+
| `repo` | yes | — | `owner/repo` whose issues store the comments. |
|
|
209
|
+
| `issueTerm` | no | `"pathname"` | Mapping between a page and its issue: `pathname`, `url`, `title`, `og:title`. |
|
|
210
|
+
| `theme` | no | `"github-light"` | Any [utterances theme](https://utteranc.es/#configuration). |
|
|
211
|
+
|
|
212
|
+
### Mapping notes
|
|
213
|
+
|
|
214
|
+
With `issueTerm: "pathname"`, each post is matched to a GitHub issue whose title
|
|
215
|
+
equals the page's pathname (with the leading slash stripped). If you change a
|
|
216
|
+
post's URL, the existing comment thread no longer matches — rename the issue
|
|
217
|
+
title to the new pathname to keep the old comments.
|
|
218
|
+
|
|
151
219
|
### Required layout files
|
|
152
220
|
|
|
153
221
|
```
|
package/lib/deploy.js
CHANGED
|
@@ -44,6 +44,7 @@ async function deploy(config, options = {}) {
|
|
|
44
44
|
}).trim();
|
|
45
45
|
if (!unpushed) {
|
|
46
46
|
console.log("No changes to commit and no unpushed commits.");
|
|
47
|
+
printSiteUrl(config);
|
|
47
48
|
return;
|
|
48
49
|
}
|
|
49
50
|
console.log("No new changes to commit, but found unpushed commits. Pushing...");
|
|
@@ -156,6 +157,7 @@ async function waitForDeployment(cwd, config) {
|
|
|
156
157
|
if (runs.length === 0) {
|
|
157
158
|
console.log("No workflow runs found. The deployment may not be configured yet.");
|
|
158
159
|
console.log("Enable GitHub Pages: Settings → Pages → Source → GitHub Actions");
|
|
160
|
+
printSiteUrl(config);
|
|
159
161
|
return;
|
|
160
162
|
}
|
|
161
163
|
|
package/lib/init.js
CHANGED
package/lib/mod/config.js
CHANGED
|
@@ -17,6 +17,7 @@ const defaults = {
|
|
|
17
17
|
image: "",
|
|
18
18
|
theme: "archie",
|
|
19
19
|
basePath: "", // auto-detected for GitHub Pages project sites, e.g. "/repo-name/"
|
|
20
|
+
postsPath: "posts", // URL prefix for posts: "posts" serves articles at /posts/<slug>/; set "" for root
|
|
20
21
|
comments: null, // { provider: "utterances", repo: "user/repo", issueTerm: "pathname", theme: "github-light" }
|
|
21
22
|
content: "./content",
|
|
22
23
|
postsDir: "./content/posts",
|
|
@@ -91,6 +92,9 @@ function loadConfig(configPath) {
|
|
|
91
92
|
merged.basePath += "/";
|
|
92
93
|
}
|
|
93
94
|
|
|
95
|
+
// Normalize postsPath into a bare segment without surrounding slashes
|
|
96
|
+
merged.postsPath = (merged.postsPath || "").replace(/^\/+|\/+$/g, "");
|
|
97
|
+
|
|
94
98
|
return merged;
|
|
95
99
|
}
|
|
96
100
|
|
package/lib/mod/page.js
CHANGED
|
@@ -26,6 +26,9 @@ module.exports = class Page extends PageBase {
|
|
|
26
26
|
// If there's no .md extension, just get the last part of the path
|
|
27
27
|
this.path = path.basename(filePath);
|
|
28
28
|
}
|
|
29
|
+
// The source folder name, used to locate the post's images on disk.
|
|
30
|
+
// this.path may later be prefixed (e.g. "posts/<slug>") for output/URLs.
|
|
31
|
+
this.slug = this.path;
|
|
29
32
|
// parsed content by fields and body
|
|
30
33
|
const content = fm(mdContent);
|
|
31
34
|
|
|
@@ -75,7 +78,7 @@ module.exports = class Page extends PageBase {
|
|
|
75
78
|
recursive: true,
|
|
76
79
|
});
|
|
77
80
|
|
|
78
|
-
fs.mkdirSync(outPath);
|
|
81
|
+
fs.mkdirSync(outPath, { recursive: true });
|
|
79
82
|
} else {
|
|
80
83
|
// remove the outputPath file if it exists
|
|
81
84
|
const outPath = path.join(this.config.dev.outdir, this.path);
|
|
@@ -96,7 +99,7 @@ module.exports = class Page extends PageBase {
|
|
|
96
99
|
);
|
|
97
100
|
|
|
98
101
|
// if there is the images folder in the output directory.
|
|
99
|
-
const srcImagesDir = path.join(this.config.dev.postsdir, this.
|
|
102
|
+
const srcImagesDir = path.join(this.config.dev.postsdir, this.slug, "images");
|
|
100
103
|
if (
|
|
101
104
|
fs.existsSync(srcImagesDir) &&
|
|
102
105
|
this.path !== ""
|
|
@@ -104,7 +107,7 @@ module.exports = class Page extends PageBase {
|
|
|
104
107
|
// Copy images folder from postsdir to outdir
|
|
105
108
|
const destImagesDir = path.join(this.config.dev.outdir, this.path, "images");
|
|
106
109
|
if (!fs.existsSync(destImagesDir))
|
|
107
|
-
fs.mkdirSync(destImagesDir);
|
|
110
|
+
fs.mkdirSync(destImagesDir, { recursive: true });
|
|
108
111
|
|
|
109
112
|
fs.readdirSync(srcImagesDir).forEach(
|
|
110
113
|
(image) => {
|
package/lib/posts.js
CHANGED
|
@@ -23,6 +23,10 @@ module.exports = class Posts {
|
|
|
23
23
|
}
|
|
24
24
|
const post = new Page(this.config);
|
|
25
25
|
post.readSource(path.join(this.config.dev.postsdir, postPath));
|
|
26
|
+
// Optionally nest posts under a URL prefix (e.g. "posts" -> /posts/<slug>/).
|
|
27
|
+
// post.slug stays the source folder name so image lookups remain correct.
|
|
28
|
+
const prefix = this.config.postsPath ? `${this.config.postsPath}/` : "";
|
|
29
|
+
post.path = `${prefix}${post.slug}`;
|
|
26
30
|
post.url = `${this.config.blogsite}/${post.path}/`;
|
|
27
31
|
post.imageURL = `${this.config.blogsite}/${post.path}/images/${post.image}`;
|
|
28
32
|
this.posts.push(post);
|