@terrymooreii/sia 2.3.2 → 2.3.3

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/docs/README.md CHANGED
@@ -71,17 +71,26 @@ my-site/
71
71
  ├── _config.yml # Site configuration
72
72
  ├── src/
73
73
  │ ├── posts/ # Blog posts (markdown)
74
- │ │ └── 2024-12-17-my-post/
75
- │ │ ├── index.md
76
- │ │ └── (assets can go here)
74
+ │ │ ├── 2024-12-17-my-post/ # Flat structure (default)
75
+ │ │├── index.md
76
+ │ │└── (assets can go here)
77
+ │ │ └── 2024/ # Or date-organized (if path: posts/:year/:month)
78
+ │ │ └── 12/
79
+ │ │ └── 2024-12-17-my-post/
80
+ │ │ ├── index.md
81
+ │ │ └── (assets can go here)
77
82
  │ ├── pages/ # Static pages
78
83
  │ │ └── about/
79
84
  │ │ ├── index.md
80
85
  │ │ └── (assets can go here)
81
86
  │ ├── notes/ # Short notes/tweets
82
- │ │ └── 2024-12-17-note-1234567890/
83
- │ │ ├── index.md
84
- │ │ └── (assets can go here)
87
+ │ │ ├── 2024-12-17-note-1234567890/ # Flat structure (default)
88
+ │ │├── index.md
89
+ │ │└── (assets can go here)
90
+ │ │ └── 2024/ # Or date-organized (if path: notes/:year)
91
+ │ │ └── 2024-12-17-note-1234567890/
92
+ │ │ ├── index.md
93
+ │ │ └── (assets can go here)
85
94
  │ └── images/ # Images
86
95
  ├── assets/ # Static assets (optional)
87
96
  ├── static/ # Static assets (optional)
@@ -97,10 +106,39 @@ my-site/
97
106
 
98
107
  Each post, page, and note is created as a folder containing an `index.md` file. This allows you to organize assets (images, PDFs, etc.) alongside your content in the same folder.
99
108
 
109
+ **Note:** You can organize posts and notes by date using date variables in the `path` configuration (e.g., `posts/:year/:month`). See [Date Variables in Paths](#date-variables-in-paths) for details.
110
+
100
111
  ## Configuration
101
112
 
102
113
  Edit `_config.yml` to customize your site:
103
114
 
115
+ ### Date Variables in Paths
116
+
117
+ You can organize posts and notes by date using date variables in the `path` property:
118
+
119
+ ```yaml
120
+ collections:
121
+ posts:
122
+ path: posts/:year/:month # Organizes posts by year and month
123
+ # New posts will be created in: posts/2024/01/2024-01-15-slug/
124
+
125
+ notes:
126
+ path: notes/:year # Organizes notes by year only
127
+ # New notes will be created in: notes/2024/2024-01-15-note-1234567890/
128
+ ```
129
+
130
+ **Supported date variables:**
131
+ - `:year` - 4-digit year (e.g., `2024`)
132
+ - `:month` - 2-digit month (e.g., `01`, `12`)
133
+ - `:day` - 2-digit day (e.g., `01`, `31`)
134
+
135
+ **Examples:**
136
+ - `posts/:year/:month` → `posts/2024/01/`
137
+ - `posts/:year` → `posts/2024/`
138
+ - `notes/:year/:month/:day` → `notes/2024/01/15/`
139
+
140
+ When loading collections, Sia automatically searches recursively through all date-organized directories, so existing content will be found regardless of the path structure.
141
+
104
142
  ```yaml
105
143
  site:
106
144
  title: "My Blog"
@@ -117,7 +155,7 @@ output: dist
117
155
 
118
156
  collections:
119
157
  posts:
120
- path: posts
158
+ path: posts # Or use date variables: posts/:year/:month
121
159
  layout: post
122
160
  permalink: /blog/:slug/
123
161
  sortBy: date
@@ -127,7 +165,7 @@ collections:
127
165
  layout: page
128
166
  permalink: /:slug/
129
167
  notes:
130
- path: notes
168
+ path: notes # Or use date variables: notes/:year
131
169
  layout: note
132
170
  permalink: /notes/:slug/
133
171
 
@@ -165,13 +165,32 @@ Blog posts are stored in `src/posts/` (or your configured path).
165
165
  # From _config.yml
166
166
  collections:
167
167
  posts:
168
- path: posts
168
+ path: posts # Or use date variables: posts/:year/:month
169
169
  layout: post
170
170
  permalink: /blog/:slug/
171
171
  sortBy: date
172
172
  sortOrder: desc
173
173
  ```
174
174
 
175
+ **Date Variables in Paths:**
176
+
177
+ You can organize posts by date using date variables in the `path` property:
178
+
179
+ ```yaml
180
+ collections:
181
+ posts:
182
+ path: posts/:year/:month # Creates: posts/2024/01/2024-01-15-slug/
183
+ # Or
184
+ path: posts/:year # Creates: posts/2024/2024-01-15-slug/
185
+ ```
186
+
187
+ **Supported variables:**
188
+ - `:year` - 4-digit year (e.g., `2024`)
189
+ - `:month` - 2-digit month (e.g., `01`, `12`)
190
+ - `:day` - 2-digit day (e.g., `01`, `31`)
191
+
192
+ When you create a new post, it will be automatically placed in the correct date-organized directory based on the current date.
193
+
175
194
  ### Typical Post Front Matter
176
195
 
177
196
  ```yaml
@@ -268,13 +287,32 @@ Notes are short-form content stored in `src/notes/` (or your configured path). T
268
287
  # From _config.yml
269
288
  collections:
270
289
  notes:
271
- path: notes
290
+ path: notes # Or use date variables: notes/:year
272
291
  layout: note
273
292
  permalink: /notes/:slug/
274
293
  sortBy: date
275
294
  sortOrder: desc
276
295
  ```
277
296
 
297
+ **Date Variables in Paths:**
298
+
299
+ You can organize notes by date using date variables in the `path` property:
300
+
301
+ ```yaml
302
+ collections:
303
+ notes:
304
+ path: notes/:year # Creates: notes/2024/2024-01-15-note-1234567890/
305
+ # Or
306
+ path: notes/:year/:month # Creates: notes/2024/01/2024-01-15-note-1234567890/
307
+ ```
308
+
309
+ **Supported variables:**
310
+ - `:year` - 4-digit year (e.g., `2024`)
311
+ - `:month` - 2-digit month (e.g., `01`, `12`)
312
+ - `:day` - 2-digit day (e.g., `01`, `31`)
313
+
314
+ When you create a new note, it will be automatically placed in the correct date-organized directory based on the current date.
315
+
278
316
  ### Typical Note Front Matter
279
317
 
280
318
  Notes often have minimal front matter since they're short-form:
package/lib/content.js CHANGED
@@ -321,6 +321,49 @@ function truncateMarkdownSafely(text, maxLength) {
321
321
  return text.substring(0, truncateAt).trim() + '...';
322
322
  }
323
323
 
324
+ /**
325
+ * Expand date variables in a path template
326
+ * Supports :year, :month, :day variables
327
+ * @param {string} pathTemplate - Path template with date variables (e.g., "posts/:year/:month")
328
+ * @param {Date} date - Date to use for expansion
329
+ * @returns {string} Expanded path
330
+ */
331
+ export function expandDatePath(pathTemplate, date) {
332
+ if (!pathTemplate || typeof pathTemplate !== 'string') {
333
+ return pathTemplate;
334
+ }
335
+
336
+ const year = date.getFullYear();
337
+ const month = String(date.getMonth() + 1).padStart(2, '0');
338
+ const day = String(date.getDate()).padStart(2, '0');
339
+
340
+ return pathTemplate
341
+ .replace(/:year/g, year)
342
+ .replace(/:month/g, month)
343
+ .replace(/:day/g, day);
344
+ }
345
+
346
+ /**
347
+ * Get base path from a path template (removes date variables for recursive searching)
348
+ * @param {string} pathTemplate - Path template with date variables
349
+ * @returns {string} Base path (everything before the first date variable)
350
+ */
351
+ export function getBasePath(pathTemplate) {
352
+ if (!pathTemplate || typeof pathTemplate !== 'string') {
353
+ return pathTemplate;
354
+ }
355
+
356
+ // Find the first occurrence of a date variable (can be at start or after a slash)
357
+ const firstVariable = pathTemplate.match(/:(\w+)/);
358
+ if (!firstVariable) {
359
+ // No date variables, return as-is
360
+ return pathTemplate;
361
+ }
362
+
363
+ // Return everything before the first date variable
364
+ return pathTemplate.substring(0, firstVariable.index);
365
+ }
366
+
324
367
  /**
325
368
  * Generate a URL-friendly slug from a string
326
369
  */
@@ -577,7 +620,11 @@ export async function loadCollection(config, collectionName) {
577
620
  return [];
578
621
  }
579
622
 
580
- const collectionDir = join(config.inputDir, collectionConfig.path);
623
+ // If path contains date variables, use base path for recursive searching
624
+ // Otherwise use the path as-is
625
+ const pathTemplate = collectionConfig.path;
626
+ const basePath = getBasePath(pathTemplate);
627
+ const collectionDir = join(config.inputDir, basePath);
581
628
  const files = getMarkdownFiles(collectionDir);
582
629
 
583
630
  const items = await Promise.all(
@@ -671,6 +718,8 @@ export default {
671
718
  getMarkdownFiles,
672
719
  loadCollection,
673
720
  loadAllCollections,
674
- addMarkedExtension
721
+ addMarkedExtension,
722
+ expandDatePath,
723
+ getBasePath
675
724
  };
676
725
 
package/lib/migrate.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { readdirSync, statSync, existsSync, mkdirSync, renameSync } from 'fs';
2
2
  import { join, dirname, basename, extname } from 'path';
3
3
  import { loadConfig } from './config.js';
4
- import { getMarkdownFiles } from './content.js';
4
+ import { getMarkdownFiles, getBasePath } from './content.js';
5
5
 
6
6
  /**
7
7
  * Check if a file is already in folder-based structure
@@ -102,7 +102,10 @@ export async function migrateContent(options = {}) {
102
102
  continue;
103
103
  }
104
104
 
105
- const collectionDir = join(config.inputDir, collectionConfig.path);
105
+ // If path contains date variables, use base path for recursive searching
106
+ const pathTemplate = collectionConfig.path;
107
+ const basePath = getBasePath(pathTemplate);
108
+ const collectionDir = join(config.inputDir, basePath);
106
109
 
107
110
  if (!existsSync(collectionDir)) {
108
111
  console.log(`⚠️ Collection directory not found: ${collectionDir}`);
package/lib/new.js CHANGED
@@ -2,7 +2,7 @@ import prompts from 'prompts';
2
2
  import { writeFileSync, existsSync, mkdirSync } from 'fs';
3
3
  import { join } from 'path';
4
4
  import { loadConfig } from './config.js';
5
- import { slugify } from './content.js';
5
+ import { slugify, expandDatePath } from './content.js';
6
6
 
7
7
  /**
8
8
  * Get current date in YYYY-MM-DD format
@@ -52,7 +52,10 @@ function createPost(config, options) {
52
52
  const slug = slugify(options.title);
53
53
  const date = getDateString();
54
54
  const folderName = `${date}-${slug}`;
55
- const postsDir = join(config.inputDir, config.collections.posts?.path || 'posts');
55
+ const now = new Date();
56
+ const pathTemplate = config.collections.posts?.path || 'posts';
57
+ const expandedPath = expandDatePath(pathTemplate, now);
58
+ const postsDir = join(config.inputDir, expandedPath);
56
59
  const postFolder = join(postsDir, folderName);
57
60
  const filePath = join(postFolder, 'index.md');
58
61
 
@@ -129,7 +132,10 @@ function createNote(config, options) {
129
132
  const date = getDateString();
130
133
  const timestamp = Date.now();
131
134
  const folderName = `${date}-${slug}-${timestamp}`;
132
- const notesDir = join(config.inputDir, config.collections.notes?.path || 'notes');
135
+ const now = new Date();
136
+ const pathTemplate = config.collections.notes?.path || 'notes';
137
+ const expandedPath = expandDatePath(pathTemplate, now);
138
+ const notesDir = join(config.inputDir, expandedPath);
133
139
  const noteFolder = join(notesDir, folderName);
134
140
  const filePath = join(noteFolder, 'index.md');
135
141
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@terrymooreii/sia",
3
- "version": "2.3.2",
3
+ "version": "2.3.3",
4
4
  "description": "A simple, powerful static site generator with markdown, front matter, and Nunjucks templates",
5
5
  "main": "lib/index.js",
6
6
  "bin": {