@terrymooreii/sia 1.0.2 → 2.0.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.
Files changed (61) hide show
  1. package/_config.yml +33 -0
  2. package/bin/cli.js +51 -0
  3. package/defaults/includes/footer.njk +14 -0
  4. package/defaults/includes/header.njk +71 -0
  5. package/defaults/includes/pagination.njk +26 -0
  6. package/defaults/includes/tag-list.njk +11 -0
  7. package/defaults/layouts/base.njk +41 -0
  8. package/defaults/layouts/note.njk +25 -0
  9. package/defaults/layouts/page.njk +14 -0
  10. package/defaults/layouts/post.njk +43 -0
  11. package/defaults/pages/blog.njk +36 -0
  12. package/defaults/pages/feed.njk +28 -0
  13. package/defaults/pages/index.njk +60 -0
  14. package/defaults/pages/notes.njk +34 -0
  15. package/defaults/pages/tag.njk +41 -0
  16. package/defaults/pages/tags.njk +39 -0
  17. package/defaults/styles/main.css +1074 -0
  18. package/lib/assets.js +234 -0
  19. package/lib/build.js +260 -19
  20. package/lib/collections.js +191 -0
  21. package/lib/config.js +114 -0
  22. package/lib/content.js +323 -0
  23. package/lib/index.js +53 -18
  24. package/lib/init.js +555 -6
  25. package/lib/new.js +379 -41
  26. package/lib/server.js +257 -0
  27. package/lib/templates.js +249 -0
  28. package/package.json +30 -15
  29. package/readme.md +212 -63
  30. package/src/images/.gitkeep +3 -0
  31. package/src/notes/2024-12-17-first-note.md +6 -0
  32. package/src/pages/about.md +29 -0
  33. package/src/posts/2024-12-16-markdown-features.md +76 -0
  34. package/src/posts/2024-12-17-welcome-to-sia.md +78 -0
  35. package/src/posts/2024-12-17-welcome-to-static-forge.md +78 -0
  36. package/.prettierignore +0 -3
  37. package/.prettierrc +0 -8
  38. package/lib/helpers.js +0 -37
  39. package/lib/markdown.js +0 -33
  40. package/lib/parse.js +0 -100
  41. package/lib/readconfig.js +0 -18
  42. package/lib/rss.js +0 -63
  43. package/templates/siarc-template.js +0 -53
  44. package/templates/src/_partials/_footer.njk +0 -1
  45. package/templates/src/_partials/_head.njk +0 -35
  46. package/templates/src/_partials/_header.njk +0 -1
  47. package/templates/src/_partials/_layout.njk +0 -12
  48. package/templates/src/_partials/_nav.njk +0 -12
  49. package/templates/src/_partials/page.njk +0 -5
  50. package/templates/src/_partials/post.njk +0 -13
  51. package/templates/src/_partials/posts.njk +0 -19
  52. package/templates/src/assets/android-chrome-192x192.png +0 -0
  53. package/templates/src/assets/android-chrome-512x512.png +0 -0
  54. package/templates/src/assets/apple-touch-icon.png +0 -0
  55. package/templates/src/assets/favicon-16x16.png +0 -0
  56. package/templates/src/assets/favicon-32x32.png +0 -0
  57. package/templates/src/assets/favicon.ico +0 -0
  58. package/templates/src/assets/site.webmanifest +0 -19
  59. package/templates/src/content/index.md +0 -7
  60. package/templates/src/css/markdown.css +0 -1210
  61. package/templates/src/css/theme.css +0 -120
@@ -0,0 +1,76 @@
1
+ ---
2
+ title: "Markdown Features Guide"
3
+ date: 2024-12-16
4
+ tags: [markdown, tutorial]
5
+ ---
6
+
7
+ This post demonstrates the markdown features supported by Static Forge.
8
+
9
+ ## Headers
10
+
11
+ Use `#` for headers. The more `#` symbols, the smaller the header.
12
+
13
+ ## Text Formatting
14
+
15
+ You can make text **bold**, *italic*, or ***both***. You can also use ~~strikethrough~~.
16
+
17
+ ## Links and Images
18
+
19
+ [This is a link](https://example.com) and here's how to add images:
20
+
21
+ ```markdown
22
+ ![Alt text](/images/photo.jpg)
23
+ ```
24
+
25
+ ## Lists
26
+
27
+ ### Unordered Lists
28
+
29
+ - First item
30
+ - Second item
31
+ - Nested item
32
+ - Another nested item
33
+ - Third item
34
+
35
+ ### Ordered Lists
36
+
37
+ 1. First step
38
+ 2. Second step
39
+ 3. Third step
40
+
41
+ ## Blockquotes
42
+
43
+ > "The best way to predict the future is to create it."
44
+ > — Peter Drucker
45
+
46
+ ## Code
47
+
48
+ Inline `code` looks like this.
49
+
50
+ Code blocks with syntax highlighting:
51
+
52
+ ```javascript
53
+ function greet(name) {
54
+ return `Hello, ${name}!`;
55
+ }
56
+
57
+ console.log(greet('World'));
58
+ ```
59
+
60
+ ## Tables
61
+
62
+ | Feature | Supported |
63
+ |---------|-----------|
64
+ | Markdown | ✅ |
65
+ | Front Matter | ✅ |
66
+ | Tags | ✅ |
67
+ | Pagination | ✅ |
68
+
69
+ ## Horizontal Rule
70
+
71
+ Use `---` for a horizontal rule:
72
+
73
+ ---
74
+
75
+ That's it! Enjoy writing in markdown.
76
+
@@ -0,0 +1,78 @@
1
+ ---
2
+ title: "Welcome to Sia"
3
+ date: 2024-12-17
4
+ tags: [getting-started, sia]
5
+ ---
6
+
7
+ Welcome to your new blog powered by **Sia**! This is a sample post to help you get started.
8
+
9
+ ## What is Sia?
10
+
11
+ Sia is a simple, powerful static site generator that supports:
12
+
13
+ - **Markdown** with front matter for easy content creation
14
+ - **Nunjucks templates** for flexible layouts
15
+ - **Tags** for organizing your content
16
+ - **Pagination** for listing pages
17
+ - **Live reload** during development
18
+ - **Clean, light theme** out of the box
19
+
20
+ ## Getting Started
21
+
22
+ ### Creating Content
23
+
24
+ To create a new blog post:
25
+
26
+ ```bash
27
+ npx sia new post "My New Post"
28
+ ```
29
+
30
+ To create a new page:
31
+
32
+ ```bash
33
+ npx sia new page "About Me"
34
+ ```
35
+
36
+ To create a short note (like a tweet):
37
+
38
+ ```bash
39
+ npx sia new note "Just discovered something cool!"
40
+ ```
41
+
42
+ ### Running the Development Server
43
+
44
+ ```bash
45
+ npm run dev
46
+ ```
47
+
48
+ This will start a local server with live reload at `http://localhost:3000`.
49
+
50
+ ### Building for Production
51
+
52
+ ```bash
53
+ npm run build
54
+ ```
55
+
56
+ This will generate your static site in the `dist` folder, ready to deploy!
57
+
58
+ ## Front Matter
59
+
60
+ Each markdown file can have front matter at the top:
61
+
62
+ ```yaml
63
+ ---
64
+ title: "My Post Title"
65
+ date: 2024-12-17
66
+ tags: [tag1, tag2]
67
+ draft: true # Set to true to hide from production
68
+ ---
69
+ ```
70
+
71
+ ## Customization
72
+
73
+ - Edit `_config.yml` to change site settings
74
+ - Add custom layouts in `_layouts/`
75
+ - Add custom includes in `_includes/`
76
+ - Override default styles by adding `styles/main.css`
77
+
78
+ Happy blogging! 🚀
@@ -0,0 +1,78 @@
1
+ ---
2
+ title: "Welcome to Sia"
3
+ date: 2024-12-17
4
+ tags: [getting-started, sia]
5
+ ---
6
+
7
+ Welcome to your new blog powered by **Sia**! This is a sample post to help you get started.
8
+
9
+ ## What is Sia?
10
+
11
+ Sia is a simple, powerful static site generator that supports:
12
+
13
+ - **Markdown** with front matter for easy content creation
14
+ - **Nunjucks templates** for flexible layouts
15
+ - **Tags** for organizing your content
16
+ - **Pagination** for listing pages
17
+ - **Live reload** during development
18
+ - **Clean, light theme** out of the box
19
+
20
+ ## Getting Started
21
+
22
+ ### Creating Content
23
+
24
+ To create a new blog post:
25
+
26
+ ```bash
27
+ npx sia new post "My New Post"
28
+ ```
29
+
30
+ To create a new page:
31
+
32
+ ```bash
33
+ npx sia new page "About Me"
34
+ ```
35
+
36
+ To create a short note (like a tweet):
37
+
38
+ ```bash
39
+ npx sia new note "Just discovered something cool!"
40
+ ```
41
+
42
+ ### Running the Development Server
43
+
44
+ ```bash
45
+ npm run dev
46
+ ```
47
+
48
+ This will start a local server with live reload at `http://localhost:3000`.
49
+
50
+ ### Building for Production
51
+
52
+ ```bash
53
+ npm run build
54
+ ```
55
+
56
+ This will generate your static site in the `dist` folder, ready to deploy!
57
+
58
+ ## Front Matter
59
+
60
+ Each markdown file can have front matter at the top:
61
+
62
+ ```yaml
63
+ ---
64
+ title: "My Post Title"
65
+ date: 2024-12-17
66
+ tags: [tag1, tag2]
67
+ draft: true # Set to true to hide from production
68
+ ---
69
+ ```
70
+
71
+ ## Customization
72
+
73
+ - Edit `_config.yml` to change site settings
74
+ - Add custom layouts in `_layouts/`
75
+ - Add custom includes in `_includes/`
76
+ - Override default styles by adding `styles/main.css`
77
+
78
+ Happy blogging! 🚀
package/.prettierignore DELETED
@@ -1,3 +0,0 @@
1
- # Ignore artifacts:
2
- public
3
- node_modules
package/.prettierrc DELETED
@@ -1,8 +0,0 @@
1
- {
2
- "printWidth": 120,
3
- "tabWidth": 2,
4
- "jsxBracketSameLine": true,
5
- "singleQuote": true,
6
- "semi": false,
7
- "trailingComma": "es5"
8
- }
package/lib/helpers.js DELETED
@@ -1,37 +0,0 @@
1
- import fs from 'fs'
2
-
3
- export const formatDate = (postDate) => {
4
- const d = new Date(postDate)
5
- const date = d.toLocaleDateString('en-us', {
6
- year: 'numeric',
7
- month: 'long',
8
- day: 'numeric',
9
- })
10
- const time = d.toLocaleTimeString()
11
- return {
12
- datetime: `${date} ${time}`,
13
- date,
14
- year: d.getFullYear(),
15
- }
16
- }
17
-
18
- export const mkdir = (path) => {
19
- if (!fs.existsSync(path)) {
20
- fs.mkdirSync(path)
21
- return true
22
- }
23
- return false
24
- }
25
-
26
- export const cpdir = (src, dest) => {
27
- if (fs.existsSync(src)) {
28
- mkdir(dest)
29
- fs.cpSync(src, dest, { recursive: true })
30
- return true
31
- }
32
- return false
33
- }
34
-
35
- export const writefile = (file, content, options = { flags: 'w+' }) => {
36
- fs.writeFileSync(file, content, options)
37
- }
package/lib/markdown.js DELETED
@@ -1,33 +0,0 @@
1
- import config from './readconfig.js'
2
- import markdownit from 'markdown-it'
3
- import hljs from 'highlight.js'
4
-
5
- import javascript from 'highlight.js/lib/languages/javascript'
6
- import bash from 'highlight.js/lib/languages/bash'
7
- hljs.registerLanguage('javascript', javascript)
8
- hljs.registerLanguage('bash', bash)
9
-
10
- const md = markdownit({
11
- html: true,
12
- linkify: true,
13
- typographer: true,
14
- breaks: true,
15
- highlight: function (str, lang) {
16
- if (config?.app?.markdown?.highlightjs && lang && hljs.getLanguage(lang)) {
17
- try {
18
- return hljs.highlight(str, { language: lang }).value
19
- } catch (__) {}
20
- }
21
-
22
- return ''
23
- },
24
- ...config?.app?.markdown?.markdownitOptions,
25
- })
26
-
27
- if (config?.app?.markdown?.plugins) {
28
- config.app.markdown.plugins.forEach((plugin) => {
29
- md.use(plugin)
30
- })
31
- }
32
-
33
- export default md
package/lib/parse.js DELETED
@@ -1,100 +0,0 @@
1
- import config from './readconfig.js'
2
- import matter from 'gray-matter'
3
- import fs from 'fs'
4
- import path from 'path'
5
- import nunjucks from 'nunjucks'
6
- import md from './markdown.js'
7
-
8
- import { formatDate, mkdir, writefile } from './helpers.js'
9
-
10
- const { app, site } = config
11
-
12
- nunjucks.configure(path.join(app.src, app.partials), {
13
- autoescape: false,
14
- })
15
-
16
- const render = (srcFolder, publicFolder, file) => {
17
- const parsed = matter.read(path.join(srcFolder, file))
18
- const { data: page, content } = parsed
19
- const fileName = path.parse(file).name
20
- const fileNameHtml = `${fileName}.html`
21
-
22
- if(page.draft) {
23
- return
24
- }
25
-
26
- if (!page.template) {
27
- throw new Error(`Missing template tag in ${file}`)
28
- }
29
-
30
- page.date = formatDate(page.created_at)
31
-
32
- // technically slug is the permalink or uri
33
- // this removes the public folder path to reveal the slug path
34
- page.slug = path.join(publicFolder).replace(app.public, '')
35
- // index pages will render automatically in folder but if the file
36
- // name is not then make sure it included in the permalink
37
- if (fileNameHtml !== 'index.html') {
38
- page.slug = path.join(page.slug, fileNameHtml)
39
- }
40
-
41
- const html = md.render(content)
42
- const rendered = nunjucks.render(`${page.template}${app.template_ext}`, {
43
- content: html,
44
- page,
45
- site,
46
- })
47
-
48
- writefile(path.join(publicFolder, fileNameHtml), rendered)
49
-
50
- // collect all the page attibutes for blog posts
51
- if (page.template === 'post') {
52
- return { ...page }
53
- }
54
- }
55
-
56
- const getAllFiles = (srcPath, posts) => {
57
- // take the source path and generate the public path equivalent
58
- const publicPath = srcPath.replace(path.join(app.src, app.content), app.public)
59
-
60
- mkdir(publicPath)
61
-
62
- const files = fs.readdirSync(srcPath)
63
-
64
- files.forEach((file) => {
65
- const filePath = path.join(srcPath, file)
66
-
67
- if (fs.statSync(filePath).isDirectory()) {
68
- // recursively look at files
69
- getAllFiles(filePath, posts)
70
- } else {
71
- // Process markdown files and render the nunjucks template
72
- if (path.extname(file) === '.md') {
73
- const post = render(srcPath, publicPath, file)
74
- if (post) {
75
- posts.push(post)
76
- }
77
- } else {
78
- // file is not a markdown file so just copy it to its public folder
79
- fs.copyFileSync(path.join(srcPath, file), path.join(publicPath, file))
80
- }
81
- }
82
- })
83
- return posts
84
- }
85
-
86
- export const parseContent = () => {
87
- return getAllFiles(path.join(app.src, app.content), [], '/').filter((o) => o != null) // make sure there are no undefined items
88
- }
89
-
90
- export const generateBlogListPage = (posts) => {
91
- const rendered = nunjucks.render(app.posts_template, {
92
- posts,
93
- site,
94
- })
95
-
96
- const blogListDirectory = path.join(app.public, app.blog_list)
97
-
98
- mkdir(blogListDirectory)
99
- writefile(path.join(blogListDirectory, 'index.html'), rendered)
100
- }
package/lib/readconfig.js DELETED
@@ -1,18 +0,0 @@
1
- import { findUp } from 'find-up'
2
-
3
- const configFile = '.siarc.js'
4
-
5
- async function getConfig() {
6
- try {
7
- const siarc = await findUp(configFile)
8
- const { default: config } = await import(siarc)
9
- return config
10
- } catch (err) {
11
- throw new Error(`Unable to find and load the ${configFile} file.`)
12
- }
13
- }
14
- const config = await getConfig()
15
- export default config ?? {
16
- app: {},
17
- site: {},
18
- }
package/lib/rss.js DELETED
@@ -1,63 +0,0 @@
1
- import fs from 'fs'
2
- import path from 'path'
3
- import { Feed } from 'feed'
4
- import config from './readconfig.js'
5
- const { app, site } = config
6
-
7
- const feed = new Feed({
8
- title: site.blog_title,
9
- description: site.blog_description,
10
- id: site.blog_url,
11
- link: site.blog_url,
12
- language: 'en', // optional, used only in RSS 2.0, possible values: http://www.w3.org/TR/REC-html40/struct/dirlang.html#langcodes
13
- image: site.blog_image,
14
- favicon: `${site.blog_url}/assets/favicon.ico`,
15
- copyright: `All rights reserved ${new Date().getFullYear()}, ${site.author}`,
16
- feedLinks: {
17
- json: `${site.blog_url}/feed.json`,
18
- atom: `${site.blog_url}/atom.xml`,
19
- },
20
- author: {
21
- name: site.author,
22
- email: site.email_address,
23
- },
24
- })
25
-
26
- const writeFeed = (name, content) => {
27
- fs.writeFileSync(path.join(app.public, name), content, {
28
- flag: 'w+',
29
- })
30
- }
31
-
32
- export const generateRSS = (posts, count = 10) => {
33
- posts.splice(0, count).forEach((post) => {
34
- feed.addItem({
35
- title: post.title,
36
- id: `${site.blog_url}${post.slug}`,
37
- link: `${site.blog_url}${post.slug}`,
38
- description: post.description,
39
- content: post.content,
40
- author: [
41
- {
42
- name: site.author,
43
- email: site.email_address,
44
- link: site.blog_url,
45
- },
46
- ],
47
- date: post.created_at,
48
- image: `${site.blog_url}/${post.image}`,
49
- })
50
- })
51
-
52
- if (app.feed.rss2) {
53
- writeFeed('rss.xml', feed.rss2())
54
- }
55
-
56
- if (app.feed.atom1) {
57
- writeFeed('atom.xml', feed.atom1())
58
- }
59
-
60
- if (app.feed.json1) {
61
- writeFeed('feed.json', feed.json1())
62
- }
63
- }
@@ -1,53 +0,0 @@
1
- import url from 'url'
2
- import path from 'path'
3
-
4
- const __filename = url.fileURLToPath(import.meta.url)
5
- const __dirname = path.dirname(__filename)
6
-
7
- export default {
8
- // User Config
9
- site: {
10
- blog_url: process.env.BLOG_URL || '',
11
- blog_title: '',
12
- blog_description: '',
13
- blog_image: '',
14
- author: '',
15
- email_address: '',
16
- highlightjs_theme: 'atom-one-dark.min',
17
- nav: [
18
- {
19
- title: 'Home',
20
- href: '/',
21
- },
22
- {
23
- title: 'Blog',
24
- href: '/blog',
25
- },
26
- ],
27
- },
28
-
29
- // App config
30
- app: {
31
- public: `${__dirname}/public`,
32
- src: `${__dirname}/src`,
33
- partials: '_partials',
34
- template_ext: '.njk',
35
- content: 'content',
36
- css: 'css',
37
- js: 'js',
38
- assets: 'assets',
39
- images: 'imgs',
40
- posts_template: 'posts.njk',
41
- blog_list: 'blog',
42
- feed: {
43
- count: 10,
44
- rss2: true,
45
- atom1: true,
46
- json1: true,
47
- },
48
- markdown: {
49
- highlightjs: true,
50
- plugins: [],
51
- },
52
- },
53
- }
@@ -1 +0,0 @@
1
- <footer>Made with Sia</footer>
@@ -1,35 +0,0 @@
1
- <head>
2
- <meta charset="UTF-8" />
3
- <meta name="viewport" content="width=device-width, initial-scale=1">
4
- <title>{{ page.title if page.title else site.blog_title }}</title>
5
- <meta name="author" content="{{ site.author }}" />
6
- <meta
7
- name="description"
8
- content="{{ page.description if page.description else site.blog_description }}"
9
- />
10
- {% if page.slug %}
11
- <meta property="og:url" content="{{site.blog_url}}{{ page.slug }}" />
12
- {% else %}
13
- <meta property="og:url" content="{{site.blog_url}}" />
14
- {% endif %}
15
- <meta property="og:title" content="{{ page.title if page.title else site.blog_title }}" />
16
- <meta property="og:description" content="{{ page.description if page.description else site.blog_description }}" />
17
- <meta property="og:image" content="{{ page.post_image }}" />
18
-
19
- <link type="application/rss+xml" rel="alternate" href="{{ site.blog_url }}/rss.xml" title="{{ site.blog_title }} - RSS Feed" />
20
- <link type="application/atom+xml" rel="alternate" href="{{ site.blog_url }}/atom.xml" title="{{ site.blog_title }} - Atom Feed" />
21
- <link type="application/feed+json" rel="alternate" href="{{ site.blog_url }}/feed.json" title="{{ site.blog_title }} - JSON Feed" />
22
-
23
- <link rel="icon" type="image/x-icon" href="{{ site.blog_url }}/assest/favicon.ico">
24
- <link rel="apple-touch-icon" sizes="180x180" href="{{ site.blog_url }}/assets/apple-touch-icon.png">
25
- <link rel="icon" type="image/png" sizes="32x32" href="{{ site.blog_url }}/assets/favicon-32x32.png">
26
- <link rel="icon" type="image/png" sizes="16x16" href="{{ site.blog_url }}/assets/favicon-16x16.png">
27
- <link rel="manifest" href="{{ site.blog_url }}/assets/site.webmanifest">
28
-
29
- <link rel="stylesheet" type="text/css" href="{{ site.blog_url }}/css/theme.css" />
30
- <link rel="stylesheet" type="text/css" href="{{ site.blog_url }}/css/markdown.css" />
31
- <link
32
- rel="stylesheet"
33
- href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/{{ site.highlightjs_theme }}.css"
34
- />
35
- </head>
@@ -1 +0,0 @@
1
- <!-- add content here to add it to the top of each page/post -->
@@ -1,12 +0,0 @@
1
- <!DOCTYPE >
2
- <html lang="en-US">
3
- {% include "_head.njk" %}
4
- <body class="markdown-body" data-theme="dark">
5
- {% include "_nav.njk" %}
6
- <main class="content">
7
- {% include "_header.njk" %}
8
- {% block content %}{% endblock %}
9
- {% include "_footer.njk" %}
10
- </main>
11
- </body>
12
- </html>
@@ -1,12 +0,0 @@
1
- <nav>
2
- <div class="content nav-container">
3
- <h1 class="blog-title"><a href="{{ site.blog_url }}">{{ site.blog_title }}</a></h1>
4
- <ul>
5
- {% for link in site.nav %}
6
- <li>
7
- <a href="{{ site.blog_url }}{{ link.href }}" title="{{ link.title }}">{{ link.title }}</a>
8
- </li>
9
- {% endfor %}
10
- </ul>
11
- </div>
12
- </nav>
@@ -1,5 +0,0 @@
1
- {%extends "_layout.njk" %}
2
-
3
- {% block content %}
4
- {{ content }}
5
- {% endblock %}
@@ -1,13 +0,0 @@
1
- {%extends "_layout.njk" %}
2
-
3
- {% block content %}
4
- <article>
5
- <header>
6
- <h1 class="post-title">{{ page.title }}</h1>
7
- <time datetime="{{page.date.datetime}}" class="date">
8
- {{ page.date.datetime }}
9
- </time>
10
- </header>
11
- <p>{{ content }}</p>
12
- </article>
13
- {% endblock %}
@@ -1,19 +0,0 @@
1
- {%extends "_layout.njk" %}
2
-
3
- {% block content %}
4
- <div class="posts">
5
- {% for year, posts in posts | sort(true, false, 'created_at') | groupby("date.year") %}
6
- <div class="year">{{ year }}</div>
7
- <ul>
8
- {% for post in posts %}
9
- <li>
10
- <span class="date" title="{{ post.datetime}}">
11
- {{ post.date.date }}
12
- </span>
13
- <a href="{{ site.blog_url }}{{ post.slug }}" title="{{ post.title }}"> {{ post.title }} </a>
14
- </li>
15
- {% endfor %}
16
- </ul>
17
- {% endfor %}
18
- </div>
19
- {% endblock %}
Binary file