docula 0.31.2 → 0.41.0

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 CHANGED
@@ -12,8 +12,13 @@
12
12
  - [Features](#features)
13
13
  - [Open Source Examples](#open-source-examples)
14
14
  - [Getting Started](#getting-started)
15
+ - [TypeScript Configuration](#typescript-configuration)
15
16
  - [Using Your own Template](#using-your-own-template)
16
17
  - [Building Multiple Pages](#building-multiple-pages)
18
+ - [Public Folder](#public-folder)
19
+ - [Announcements](#announcements)
20
+ - [Changelog](#changelog)
21
+ - [Alert, Info, Warn Styling](#alert-info-warn-styling)
17
22
  - [Using a Github Token](#using-a-github-token)
18
23
  - [Helpers](#helpers)
19
24
  - [Working with Markdown using Writr](#working-with-markdown-using-writr)
@@ -21,9 +26,10 @@
21
26
  - [License - MIT](#license)
22
27
 
23
28
  # Features
24
- * No configuration requrired. Just setup the folder structure with a logo, favicon, and css file.
29
+ * No configuration required. Just setup the folder structure with a logo, favicon, and css file.
25
30
  * Builds a static website that can be hosted anywhere.
26
- * For more complex projects easily add a `docula.config.mjs` file to customize the build process. With PRE and POST methods.
31
+ * For more complex projects easily add a `docula.config.ts` (TypeScript) or `docula.config.mjs` (JavaScript) file to customize the build process with lifecycle hooks.
32
+ * Full TypeScript support with typed configuration and IDE autocompletion.
27
33
  * Support for single page with readme or multiple markdown pages in a docs folder.
28
34
  * Will generate a sitemap.xml and robots.txt for your site.
29
35
  * Uses Github release notes to generate a changelog / releases page.
@@ -67,6 +73,73 @@ Simply replace the logo, favicon, and css file with your own. The readme is your
67
73
 
68
74
  This will build your site and place it in the `dist` folder. You can then host it anywhere you like.
69
75
 
76
+ # TypeScript Configuration
77
+
78
+ Docula supports TypeScript configuration files (`docula.config.ts`) in addition to JavaScript (`docula.config.mjs`). TypeScript configs provide type safety and better IDE support.
79
+
80
+ ## Initializing with TypeScript
81
+
82
+ To create a new project with a TypeScript config file:
83
+
84
+ ```bash
85
+ npx docula init --typescript
86
+ ```
87
+
88
+ This creates a `docula.config.ts` file with full type support:
89
+
90
+ ```typescript
91
+ import type { DoculaOptions } from 'docula';
92
+
93
+ export const options: Partial<DoculaOptions> = {
94
+ templatePath: './template',
95
+ outputPath: './dist',
96
+ sitePath: './site',
97
+ githubPath: 'your-username/your-repo',
98
+ siteTitle: 'My Project',
99
+ siteDescription: 'Project description',
100
+ siteUrl: 'https://your-site.com',
101
+ };
102
+ ```
103
+
104
+ ## Using Lifecycle Hooks with TypeScript
105
+
106
+ You can add typed lifecycle hooks to your config:
107
+
108
+ ```typescript
109
+ import type { DoculaOptions } from 'docula';
110
+
111
+ export const options: Partial<DoculaOptions> = {
112
+ siteTitle: 'My Project',
113
+ // ... other options
114
+ };
115
+
116
+ export const onPrepare = async (config: DoculaOptions): Promise<void> => {
117
+ // Runs before the build process
118
+ console.log(`Building ${config.siteTitle}...`);
119
+ };
120
+ ```
121
+
122
+ ## Config File Priority
123
+
124
+ When both config files exist, Docula loads them in this order (first found wins):
125
+ 1. `docula.config.ts` (TypeScript - takes priority)
126
+ 2. `docula.config.mjs` (JavaScript)
127
+
128
+ ## Available Options
129
+
130
+ | Option | Type | Default | Description |
131
+ |--------|------|---------|-------------|
132
+ | `templatePath` | `string` | `'./template'` | Path to custom template directory |
133
+ | `outputPath` | `string` | `'./dist'` | Output directory for built site |
134
+ | `sitePath` | `string` | `'./site'` | Directory containing site content |
135
+ | `githubPath` | `string` | - | GitHub repository path (e.g., `'user/repo'`) |
136
+ | `siteTitle` | `string` | `'docula'` | Website title |
137
+ | `siteDescription` | `string` | - | Website description |
138
+ | `siteUrl` | `string` | - | Website URL |
139
+ | `port` | `number` | `3000` | Port for local development server |
140
+ | `singlePage` | `boolean` | `true` | Single page or multi-page site |
141
+ | `sections` | `DoculaSection[]` | - | Documentation sections |
142
+
70
143
  # Using Your own Template
71
144
 
72
145
  If you want to use your own template you can do so by adding a `docula.config.ts` file to the root of your project. This file will be used to configure the build process.
@@ -99,6 +172,234 @@ title: Getting Started
99
172
  order: 2
100
173
  ```
101
174
 
175
+ # Public Folder
176
+
177
+ If you have static assets like images, fonts, or other files that need to be copied directly to your built site, you can use a `public` folder. Any files placed in the `public` folder within your site directory will be automatically copied to the root of your `dist` output folder during the build process.
178
+
179
+ ## Usage
180
+
181
+ Create a `public` folder inside your site directory:
182
+
183
+ ```
184
+ site
185
+ ├───public
186
+ │ ├───images
187
+ │ │ ├───screenshot.png
188
+ │ │ └───banner.jpg
189
+ │ ├───fonts
190
+ │ │ └───custom-font.woff2
191
+ │ └───downloads
192
+ │ └───example.pdf
193
+ ├───docs
194
+ ├───logo.svg
195
+ ├───favicon.ico
196
+ └───docula.config.mjs
197
+ ```
198
+
199
+ When you run the build command, all contents of the `public` folder will be copied to the `dist` folder:
200
+
201
+ ```
202
+ dist
203
+ ├───images
204
+ │ ├───screenshot.png
205
+ │ └───banner.jpg
206
+ ├───fonts
207
+ │ └───custom-font.woff2
208
+ ├───downloads
209
+ │ └───example.pdf
210
+ ├───index.html
211
+ └───...
212
+ ```
213
+
214
+ The build output will show each file being copied:
215
+
216
+ ```
217
+ Public folder found, copying contents to dist...
218
+ Copied: images/screenshot.png
219
+ Copied: images/banner.jpg
220
+ Copied: fonts/custom-font.woff2
221
+ Copied: downloads/example.pdf
222
+ Build completed in 1234ms
223
+ ```
224
+
225
+ This is useful for:
226
+ - Images referenced in your documentation
227
+ - Downloadable files (PDFs, zip archives, etc.)
228
+ - Custom fonts
229
+ - Any other static assets that need to be served from your site
230
+
231
+ # Announcements
232
+
233
+ You can display an announcement banner on your home page by creating an `announcement.md` file in your site directory. This is useful for highlighting important updates, new releases, or any time-sensitive information.
234
+
235
+ ## Usage
236
+
237
+ Create an `announcement.md` file in your site folder:
238
+
239
+ ```
240
+ site
241
+ ├───announcement.md
242
+ ├───docs
243
+ ├───logo.svg
244
+ ├───favicon.ico
245
+ └───docula.config.mjs
246
+ ```
247
+
248
+ Add your announcement content using markdown:
249
+
250
+ ```md
251
+ **New Release:** Version 2.0 is now available! Check out the [release notes](/releases) for details.
252
+ ```
253
+
254
+ The announcement will automatically appear on the home page above the "Documentation" button, styled as an alert box with a colored left border.
255
+
256
+ ## Styling
257
+
258
+ The announcement uses your theme's CSS variables and displays with:
259
+ - A subtle background using `--sidebar-background`
260
+ - A prominent left border using `--color-secondary`
261
+ - Links styled with `--color-primary`
262
+
263
+ You can customize the appearance by overriding the `.announcement` class in your `variables.css`:
264
+
265
+ ```css
266
+ .announcement {
267
+ background-color: #fff3cd;
268
+ border-left-color: #ffc107;
269
+ }
270
+ ```
271
+
272
+ ## Removing the Announcement
273
+
274
+ Simply delete the `announcement.md` file when you no longer need the announcement. The home page will automatically return to its normal layout.
275
+
276
+ # Changelog
277
+
278
+ Docula can generate a changelog section for your site from markdown files. This is useful for documenting release notes, updates, and changes to your project in a structured, browsable format.
279
+
280
+ ## Setup
281
+
282
+ Create a `changelog` folder inside your site directory and add markdown (`.md` or `.mdx`) files for each entry:
283
+
284
+ ```
285
+ site
286
+ ├───changelog
287
+ │ ├───2025-01-15-initial-release.md
288
+ │ ├───2025-02-01-new-features.md
289
+ │ └───2025-03-10-bug-fixes.md
290
+ ├───logo.svg
291
+ ├───favicon.ico
292
+ └───docula.config.mjs
293
+ ```
294
+
295
+ ## Entry Format
296
+
297
+ Each changelog entry is a markdown file with front matter:
298
+
299
+ ```md
300
+ ---
301
+ title: "Initial Release"
302
+ date: 2025-01-15
303
+ tag: "Release"
304
+ ---
305
+
306
+ We're excited to announce the initial release! Here's what's included:
307
+
308
+ - Feature A
309
+ - Feature B
310
+ - Bug fix C
311
+ ```
312
+
313
+ ### Front Matter Fields
314
+
315
+ | Field | Required | Description |
316
+ |-------|----------|-------------|
317
+ | `title` | No | Display title for the entry. Defaults to the filename if not provided. |
318
+ | `date` | Yes | Date of the entry (`YYYY-MM-DD`). Used for sorting (newest first). |
319
+ | `tag` | No | A label displayed as a badge (e.g., `Release`, `Bug Fix`, `Feature`). Gets a CSS class based on its value for styling. |
320
+
321
+ ## File Naming
322
+
323
+ Files can optionally be prefixed with a date in `YYYY-MM-DD-` format. The date prefix is stripped to create the URL slug:
324
+
325
+ - `2025-01-15-initial-release.md` → `/changelog/initial-release/`
326
+ - `new-features.md` → `/changelog/new-features/`
327
+
328
+ ## Generated Pages
329
+
330
+ When changelog entries are found, Docula generates:
331
+
332
+ - **Changelog listing page** at `/changelog/` — shows all entries sorted by date (newest first) with titles, dates, tags, and content
333
+ - **Individual entry pages** at `/changelog/{slug}/` — a dedicated page for each entry with a back link to the listing
334
+
335
+ Changelog URLs are also automatically added to the generated `sitemap.xml`.
336
+
337
+ ## Styling
338
+
339
+ Tags receive a CSS class based on their value (e.g., a tag of `"Bug Fix"` gets the class `changelog-tag-bug-fix`). You can style tags and other changelog elements by overriding these classes in your `variables.css`:
340
+
341
+ ```css
342
+ .changelog-entry {
343
+ border-bottom: 1px solid var(--border);
344
+ padding: 1.5rem 0;
345
+ }
346
+
347
+ .changelog-tag {
348
+ font-size: 0.75rem;
349
+ padding: 0.2rem 0.5rem;
350
+ border-radius: 4px;
351
+ }
352
+
353
+ .changelog-tag-release {
354
+ background-color: #d4edda;
355
+ color: #155724;
356
+ }
357
+
358
+ .changelog-tag-bug-fix {
359
+ background-color: #f8d7da;
360
+ color: #721c24;
361
+ }
362
+ ```
363
+
364
+ # Alert, Info, Warn Styling
365
+
366
+ Docula uses Writr's GitHub-flavored Markdown plugins, including GitHub-style blockquote alerts. Use the alert syntax directly in Markdown:
367
+
368
+ ```md
369
+ > [!NOTE]
370
+ > Info: Remember to configure your GitHub token for private repos.
371
+
372
+ > [!WARNING]
373
+ > Warn: This action cannot be undone.
374
+
375
+ > [!CAUTION]
376
+ > Alert: Rotate your secrets immediately.
377
+ ```
378
+
379
+ These render with the `remark-github-blockquote-alert` classes (like `.markdown-alert` and `.markdown-alert-note`). If you want GitHub-like styling, copy the plugin's CSS into your `site/variables.css` or template stylesheet (for example, from `remark-github-blockquote-alert/alert.css`), or add your own overrides:
380
+
381
+ ```css
382
+ .markdown-alert {
383
+ border-left: 4px solid var(--border);
384
+ border-radius: 8px;
385
+ margin: 1rem 0;
386
+ padding: 0.75rem 1rem;
387
+ background: var(--background);
388
+ }
389
+
390
+ .markdown-alert-note {
391
+ border-left-color: #4c8ef7;
392
+ }
393
+
394
+ .markdown-alert-warning {
395
+ border-left-color: #f2b90c;
396
+ }
397
+
398
+ .markdown-alert-caution {
399
+ border-left-color: #e5534b;
400
+ }
401
+ ```
402
+
102
403
  # Using a Github Token
103
404
 
104
405
  If you want to use the Github token to access the Github API you can do so by setting the `GITHUB_TOKEN` environment variable. This is useful if you want to access private repositories or if you want to access the Github API without hitting the rate limit. This is optional and you can still use docula without it but could hit rate limits and will not be able to access private repositories.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "docula",
3
- "version": "0.31.2",
3
+ "version": "0.41.0",
4
4
  "description": "Beautiful Website for Your Projects",
5
5
  "type": "module",
6
6
  "main": "./dist/docula.js",
@@ -29,6 +29,8 @@
29
29
  "website:serve": "rimraf ./site/README.md && node bin/docula.mjs serve -s ./site -o ./site/dist",
30
30
  "website:build:mega": "rimraf ./test/fixtures/mega-page-site/dist && node bin/docula.mjs build -s ./test/fixtures/mega-page-site",
31
31
  "website:serve:mega": "rimraf ./test/fixtures/mega-page-site/dist && node bin/docula.mjs serve -s ./test/fixtures/mega-page-site",
32
+ "website:build:changelog": "rimraf ./test/fixtures/changelog-site/dist && node bin/docula.mjs build -s ./test/fixtures/changelog-site",
33
+ "website:serve:changelog": "rimraf ./test/fixtures/changelog-site/dist && node bin/docula.mjs serve -s ./test/fixtures/changelog-site",
32
34
  "prepare": "pnpm build"
33
35
  },
34
36
  "keywords": [
@@ -51,30 +53,30 @@
51
53
  "docula": "./bin/docula.mjs"
52
54
  },
53
55
  "dependencies": {
54
- "@cacheable/net": "^2.0.4",
55
- "cheerio": "^1.1.2",
56
- "ecto": "^4.7.1",
57
- "feed": "^5.1.0",
56
+ "@cacheable/net": "^2.0.5",
57
+ "ecto": "^4.8.2",
58
+ "feed": "^5.2.0",
58
59
  "he": "^1.2.0",
60
+ "jiti": "^2.6.1",
59
61
  "serve-handler": "^6.1.6",
60
62
  "update-notifier": "^7.3.1",
61
- "writr": "^5.0.1"
63
+ "writr": "^5.0.3"
62
64
  },
63
65
  "devDependencies": {
64
- "@biomejs/biome": "^2.3.9",
66
+ "@biomejs/biome": "^2.4.2",
65
67
  "@types/express": "^5.0.6",
66
68
  "@types/he": "^1.2.3",
67
69
  "@types/js-yaml": "^4.0.9",
68
- "@types/node": "^25.0.3",
70
+ "@types/node": "^25.2.3",
69
71
  "@types/serve-handler": "^6.1.4",
70
72
  "@types/update-notifier": "^6.0.8",
71
- "@vitest/coverage-v8": "^4.0.16",
72
- "dotenv": "^17.2.3",
73
- "rimraf": "^6.1.2",
73
+ "@vitest/coverage-v8": "^4.0.18",
74
+ "dotenv": "^17.3.1",
75
+ "rimraf": "^6.1.3",
74
76
  "tsup": "^8.5.1",
75
77
  "tsx": "^4.21.0",
76
78
  "typescript": "^5.9.3",
77
- "vitest": "^4.0.16"
79
+ "vitest": "^4.0.18"
78
80
  },
79
81
  "files": [
80
82
  "dist",
@@ -0,0 +1,28 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+
4
+ <head>
5
+ {{> header }}
6
+ <title>API Documentation - {{ siteTitle }}</title>
7
+ <meta name="description" content="API Documentation for {{ siteTitle }}" />
8
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@docutopia/react/dist/browser/docutopia.css" />
9
+ <style>
10
+ body {
11
+ margin: 0;
12
+ padding: 0;
13
+ }
14
+ </style>
15
+ </head>
16
+
17
+ <body>
18
+ <div id="docs" style="height: 100vh;"></div>
19
+
20
+ <script src="https://cdn.jsdelivr.net/npm/@docutopia/react/dist/browser/docutopia.js"></script>
21
+ <script>
22
+ Docutopia.render('docs', {
23
+ specUrl: '{{ specUrl }}',
24
+ });
25
+ </script>
26
+ </body>
27
+
28
+ </html>
@@ -0,0 +1,79 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+
4
+ <head>
5
+ {{> header }}
6
+ <title>{{siteTitle}} - {{title}}</title>
7
+ </head>
8
+
9
+ <body>
10
+ {{> singlepage/hero }}
11
+ <a href="https://github.com/{{ githubPath }}" class="github-corner" aria-label="View source on GitHub"><svg width="80"
12
+ height="80" viewBox="0 0 250 250" style="color:#fff; position: absolute; top: 0; border: 0; right: 0;"
13
+ aria-hidden="true">
14
+ <path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path>
15
+ <path
16
+ d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2"
17
+ fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path>
18
+ <path
19
+ d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z"
20
+ fill="currentColor" class="octo-body"></path>
21
+ </svg></a>
22
+ <style>
23
+ .github-corner:hover .octo-arm {
24
+ animation: octocat-wave 560ms ease-in-out
25
+ }
26
+
27
+ @keyframes octocat-wave {
28
+
29
+ 0%,
30
+ 100% {
31
+ transform: rotate(0)
32
+ }
33
+
34
+ 20%,
35
+ 60% {
36
+ transform: rotate(-25deg)
37
+ }
38
+
39
+ 40%,
40
+ 80% {
41
+ transform: rotate(10deg)
42
+ }
43
+ }
44
+
45
+ @media (max-width:500px) {
46
+ .github-corner:hover .octo-arm {
47
+ animation: none
48
+ }
49
+
50
+ .github-corner .octo-arm {
51
+ animation: octocat-wave 560ms ease-in-out
52
+ }
53
+ }
54
+ </style>
55
+ <main class="versions-container">
56
+ <div class="versions-content">
57
+ <div class="changelog-entry-nav">
58
+ <a href="/changelog/">&larr; Back to Changelog</a>
59
+ </div>
60
+ <div class="changelog-entry changelog-entry-single">
61
+ <div class="changelog-entry-header">
62
+ <h1 class="changelog-entry-title">{{title}}</h1>
63
+ {{#if tag}}
64
+ <span class="changelog-tag changelog-tag-{{tagClass}}">{{tag}}</span>
65
+ {{/if}}
66
+ </div>
67
+ <span class="changelog-entry-date">{{formattedDate}}</span>
68
+ <div class="changelog-entry-body">
69
+ {{{generatedHtml}}}
70
+ </div>
71
+ </div>
72
+ </div>
73
+ </main>
74
+ {{> footer}}
75
+
76
+ {{> scripts }}
77
+ </body>
78
+
79
+ </html>
@@ -0,0 +1,81 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+
4
+ <head>
5
+ {{> header }}
6
+ <title>{{siteTitle}} Changelog</title>
7
+ </head>
8
+
9
+ <body>
10
+ {{> singlepage/hero }}
11
+ <a href="https://github.com/{{ githubPath }}" class="github-corner" aria-label="View source on GitHub"><svg width="80"
12
+ height="80" viewBox="0 0 250 250" style="color:#fff; position: absolute; top: 0; border: 0; right: 0;"
13
+ aria-hidden="true">
14
+ <path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path>
15
+ <path
16
+ d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2"
17
+ fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path>
18
+ <path
19
+ d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z"
20
+ fill="currentColor" class="octo-body"></path>
21
+ </svg></a>
22
+ <style>
23
+ .github-corner:hover .octo-arm {
24
+ animation: octocat-wave 560ms ease-in-out
25
+ }
26
+
27
+ @keyframes octocat-wave {
28
+
29
+ 0%,
30
+ 100% {
31
+ transform: rotate(0)
32
+ }
33
+
34
+ 20%,
35
+ 60% {
36
+ transform: rotate(-25deg)
37
+ }
38
+
39
+ 40%,
40
+ 80% {
41
+ transform: rotate(10deg)
42
+ }
43
+ }
44
+
45
+ @media (max-width:500px) {
46
+ .github-corner:hover .octo-arm {
47
+ animation: none
48
+ }
49
+
50
+ .github-corner .octo-arm {
51
+ animation: octocat-wave 560ms ease-in-out
52
+ }
53
+ }
54
+ </style>
55
+ <main class="versions-container">
56
+ <div class="versions-content">
57
+ <h2 class="home-title">Changelog</h2>
58
+ {{#if entries}}
59
+ {{#each entries as |entry|}}
60
+ <div class="changelog-entry">
61
+ <div class="changelog-entry-header">
62
+ <a class="changelog-entry-title" href="/changelog/{{entry.slug}}/">{{entry.title}}</a>
63
+ {{#if entry.tag}}
64
+ <span class="changelog-tag changelog-tag-{{entry.tagClass}}">{{entry.tag}}</span>
65
+ {{/if}}
66
+ </div>
67
+ <span class="changelog-entry-date">{{entry.formattedDate}}</span>
68
+ <div class="changelog-entry-body">
69
+ {{{entry.generatedHtml}}}
70
+ </div>
71
+ </div>
72
+ {{/each}}
73
+ {{/if}}
74
+ </div>
75
+ </main>
76
+ {{> footer}}
77
+
78
+ {{> scripts }}
79
+ </body>
80
+
81
+ </html>