@kenjura/ursa 0.9.0 → 0.32.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/CHANGELOG.md CHANGED
@@ -1,3 +1,166 @@
1
+ # 0.32
2
+ 2025-12-10
3
+
4
+ - Using .ursa folder in source directory for content hash cache
5
+ - Added --clean flag to ignore cache and regenerate all files
6
+ - Set up npm config for public package publishing
7
+
8
+ # 0.31
9
+ 2025-12-09
10
+
11
+ - Added URL property to JSON directory indices
12
+ - Ensured directory indices are recursive
13
+
14
+ # 0.30
15
+ 2025-12-07
16
+
17
+ - Fixed broken link detection to correctly identify broken internal links
18
+
19
+ # 0.29.0
20
+ 2025-12-07
21
+
22
+ - New nav-main style, two-levels only (but supports any depth), looks way better
23
+
24
+ # 0.28.0
25
+ 2025-12-07
26
+
27
+ - Added broken link detection and styles
28
+ - Fixed hole in "serve" logic that didn't regenerate style.css
29
+
30
+ # 0.27.0
31
+ 2025-12-07
32
+
33
+ - Capitalizing nav-main labels
34
+
35
+ # 0.26.0
36
+ 2025-12-06
37
+ - Fixed global nav styles in desktop
38
+ - Updated main nav style to match TOC
39
+
40
+ # 0.25.0
41
+
42
+ 2025-12-06
43
+
44
+ - Enhanced mobile navigation with hamburger toggle that changes to X when menu is open
45
+ - Improved button accessibility with dynamic aria-label updates
46
+
47
+ # 0.24.0
48
+
49
+ 2025-12-06
50
+
51
+ - Added support for index files in folder links
52
+ - Folders with index.md/txt/yml now link to /folder/index.html
53
+ - Folders without index files render as non-clickable text
54
+
55
+ # 0.23.0
56
+
57
+ 2025-12-04
58
+
59
+ - Implemented incremental build support with content hashing
60
+ - Source file changes now only regenerate modified files
61
+ - Meta file changes still trigger full rebuild
62
+ - Added .content-hashes.json cache for tracking file changes
63
+
64
+ # 0.22.0
65
+
66
+ 2025-12-04
67
+
68
+ - New Notion-style nav-main sidebar design
69
+ - Added folder/document icons with custom icon support
70
+ - Collapsible menu items with expand arrows
71
+ - Responsive flexbox layout for nav-global
72
+
73
+ # 0.21.0
74
+
75
+ 2025-12-01
76
+
77
+ - Enhanced error handling for template retrieval
78
+ - Better error messages when templates are not found
79
+
80
+ # 0.20.0
81
+
82
+ 2025-12-01
83
+
84
+ - Added fault tolerance to generate command
85
+ - Individual file errors no longer stop entire build
86
+ - Errors collected and written to _errors.log
87
+
88
+ # 0.19.0
89
+
90
+ 2025-11-21
91
+
92
+ - Fixed YAML parsing issues with horizontal rules being mistaken for front matter
93
+ - Improved regex to require closing --- on its own line
94
+
95
+ # 0.18.0
96
+
97
+ 2025-11-21
98
+
99
+ - Fixed errors with wikitext rendering
100
+ - Better handling of undefined args.db
101
+
102
+ # 0.17.0
103
+
104
+ 2025-10-23
105
+
106
+ - Added Table of Contents (TOC) generation
107
+ - Smooth scrolling to headings with offset adjustment
108
+ - Active heading tracking in TOC
109
+
110
+ # 0.16.0
111
+
112
+ 2025-10-22
113
+
114
+ - AI-implemented search feature with typeahead
115
+ - Search index built from all articles during generation
116
+
117
+ # 0.15.0
118
+
119
+ 2025-10-22
120
+
121
+ - Improved mobile responsiveness
122
+ - Better media query breakpoint (800px)
123
+ - Enhanced h1 styling and article width for mobile
124
+
125
+ # 0.14.0
126
+
127
+ 2025-10-22
128
+
129
+ - Fixed sticky header generation
130
+ - Enhanced sticky header functionality
131
+ - Added responsive navigation styles
132
+
133
+ # 0.13.0
134
+
135
+ 2025-10-07
136
+
137
+ - Added whitelist feature for selective file generation
138
+ - Added sectionify script for content organization
139
+ - Fixed bugs in node-watch for file monitoring
140
+ - Working sticky headers implementation
141
+
142
+ # 0.12.0
143
+
144
+ 2025-10-06
145
+
146
+ - Added debug CLI mode
147
+ - Fixed embedded style issues
148
+ - Added site navigation
149
+ - Total rewrite of base CSS (article and topnav)
150
+ - Added custom CSS support (disabled by default)
151
+
152
+ # 0.11.0
153
+
154
+ 2025-07-28
155
+
156
+ - added CLI commands (e.g. "ursa src" and "ursa serve src")
157
+
158
+ # 0.10.0
159
+
160
+ 2024-03-13
161
+
162
+ - Will no longer write an autoindex when index document already exists
163
+
1
164
  # 0.9.0
2
165
 
3
166
  2024-02-10
package/README.md CHANGED
@@ -1,32 +1,195 @@
1
- static site generator from MD/wikitext/YML
1
+ # Ursa Static Site Generator
2
2
 
3
- there are many like it, but this one's mine
3
+ A flexible static site generator that converts Markdown, Wikitext, and YAML files into beautiful HTML sites.
4
4
 
5
- # Developing
5
+ There are many like it, but this one's mine.
6
6
 
7
- ```npm run serve```
7
+ ## Installation
8
8
 
9
- Watches source and meta folder; on change, writes HTML to build folder.
9
+ ### As a CLI tool (global installation)
10
+ ```bash
11
+ npm install -g @kenjura/ursa
12
+ ```
13
+
14
+ ### As a library dependency
15
+ ```bash
16
+ npm install @kenjura/ursa
17
+ ```
18
+
19
+ ## CLI Usage
20
+
21
+ After global installation, you can use the `ursa` command:
22
+
23
+ ```bash
24
+ # Generate site once
25
+ ursa <source-directory>
26
+ ursa generate <source-directory>
27
+
28
+ # Development server with live reloading
29
+ ursa serve <source-directory>
30
+
31
+ # With custom meta and output directories
32
+ ursa content --meta=templates --output=dist
33
+ ursa serve content --meta=templates --output=dist --port=3000
34
+
35
+ # Using a whitelist file to filter which files are processed
36
+ ursa content --whitelist=my-whitelist.txt
37
+ ursa serve content --whitelist=my-whitelist.txt
38
+
39
+ # Using default meta and output directories (meta/ and output/)
40
+ ursa content
41
+ ursa serve content
42
+ ```
43
+
44
+ If not installed, you can run:
45
+ ```bash
46
+ node bin/ursa (same args)
47
+ ```
48
+
49
+ ### CLI Commands
50
+
51
+ #### `ursa [generate] <source>`
52
+ Generate a static site once and exit.
53
+
54
+ #### `ursa serve <source>`
55
+ Start a development server that:
56
+ - Generates the site initially
57
+ - Starts an HTTP server to serve the output directory
58
+ - Watches source and meta directories for changes
59
+ - Automatically regenerates the site when files change
60
+
61
+ ### CLI Options
62
+
63
+ - `<source>` - Source directory containing markdown/wikitext files (required)
64
+ - `--meta, -m` - Meta directory containing templates and styles (default: "meta")
65
+ - `--output, -o` - Output directory for generated site (default: "output")
66
+ - `--port, -p` - Port for development server (default: 8080, serve command only)
67
+ - `--whitelist, -w` - Path to whitelist file containing patterns for files to include
68
+
69
+ ### Whitelist File Format
70
+
71
+ The whitelist file is a plain text file where each line specifies a pattern for files to include. Patterns can be:
72
+
73
+ ```text
74
+ # Comments start with # and are ignored
75
+ # Empty lines are also ignored
76
+
77
+ # Full absolute paths
78
+ /full/path/to/file.md
79
+
80
+ # Relative paths from source root
81
+ character/classes/psion.md
82
+ character/classes/
83
+
84
+ # Directory paths (include trailing slash to match directories)
85
+ spells/
86
+ documentation/
10
87
 
11
- Optional environment variables:
12
- - SOURCE: path to the source folder, default `${cwd}/source`
13
- - META: path to the meta folder, default `${cwd}/meta`
14
- - BUILD: path to the build folder, default `${cwd}/build`
88
+ # Just filenames (matches anywhere in the source tree)
89
+ index.md
90
+ README.md
15
91
 
16
- # Running
92
+ # Partial path matches
93
+ important-document
94
+ classes/wizard
95
+ ```
96
+
97
+ ## Library Usage
98
+
99
+ ### ES Modules (recommended)
100
+
101
+ ```javascript
102
+ import generateSite, { generate, serve } from '@kenjura/ursa';
103
+
104
+ // One-time generation using the default export
105
+ await generateSite({
106
+ source: './content',
107
+ meta: './meta',
108
+ output: './dist',
109
+ whitelist: './my-whitelist.txt' // optional
110
+ });
111
+
112
+ // One-time generation using the named export (matches internal API)
113
+ await generate({
114
+ _source: './content',
115
+ _meta: './meta',
116
+ _output: './dist',
117
+ _whitelist: './my-whitelist.txt' // optional
118
+ });
119
+
120
+ // Development server with live reloading
121
+ await serve({
122
+ _source: './content',
123
+ _meta: './meta',
124
+ _output: './dist',
125
+ port: 3000 // optional, defaults to 8080
126
+ });
127
+ ```
128
+
129
+ ### CommonJS
130
+
131
+ ```javascript
132
+ const generateSite = require('@kenjura/ursa').default;
133
+ const { generate, serve } = require('@kenjura/ursa');
134
+
135
+ // Usage is the same as above
136
+ ```
137
+
138
+ ### Library Functions
139
+
140
+ #### `generateSite({ source, meta, output })`
141
+ Default export. Generates the site once with user-friendly parameter names.
142
+
143
+ #### `generate({ _source, _meta, _output })`
144
+ Named export that matches the internal API. Generates the site once.
145
+
146
+ #### `serve({ _source, _meta, _output, port? })`
147
+ Starts a development server with live reloading:
148
+ - Generates the site initially
149
+ - Starts HTTP server on specified port (default: 8080)
150
+ - Watches for file changes in source and meta directories
151
+ - Automatically regenerates when changes are detected
152
+
153
+ ## Project Structure
154
+
155
+ Your project should have the following structure:
156
+
157
+ ```
158
+ your-project/
159
+ ├── source/ # Source files (markdown, wikitext, yaml)
160
+ │ ├── index.md # Required: main page
161
+ │ └── ...
162
+ ├── meta/ # Templates, styles, and configuration
163
+ │ ├── templates/
164
+ │ ├── styles/
165
+ │ └── ...
166
+ └── output/ # Generated site (created automatically)
167
+ ```
168
+
169
+ ## Developing
170
+
171
+ For development on ursa itself:
172
+
173
+ ```bash
174
+ npm run serve
175
+ ```
176
+
177
+ Watches source and meta folder; on change, writes HTML to build folder.
17
178
 
18
- ## Run once, converting source folder into static html
179
+ ### Environment Variables
19
180
 
20
- ```npm start```
181
+ - `SOURCE`: path to the source folder, default `${cwd}/source`
182
+ - `META`: path to the meta folder, default `${cwd}/meta`
183
+ - `BUILD`: path to the build folder, default `${cwd}/build`
21
184
 
22
- Defaults:
23
- - source: the "source" directory in cwd
24
- - meta: the "meta" directory in cwd
25
- - output: the "build" directory in cwd
185
+ ## Running Locally
26
186
 
27
- This is not very useful. Will make these configurable.
187
+ ```bash
188
+ npm start
189
+ ```
28
190
 
191
+ Generates the site once using default directories.
29
192
 
30
- # Inputs and Outputs
193
+ ## Requirements
31
194
 
32
- SOURCE folder should have at least an index.md in it
195
+ SOURCE folder should have at least an index.md in it.
package/bin/ursa.js ADDED
@@ -0,0 +1,208 @@
1
+ #!/usr/bin/env node
2
+
3
+ import yargs from 'yargs';
4
+ import { hideBin } from 'yargs/helpers';
5
+ import { generate } from '../src/jobs/generate.js';
6
+ import { resolve, dirname, join } from 'path';
7
+ import { fileURLToPath } from 'url';
8
+
9
+ // Get the directory where ursa is installed
10
+ const __filename = fileURLToPath(import.meta.url);
11
+ const __dirname = dirname(__filename);
12
+ const PACKAGE_META = join(__dirname, '..', 'meta');
13
+
14
+ yargs(hideBin(process.argv))
15
+ .command(
16
+ 'generate <source>',
17
+ 'Generate a static site from source files',
18
+ (yargs) => {
19
+ return yargs
20
+ .positional('source', {
21
+ describe: 'Source directory containing markdown/wikitext files',
22
+ type: 'string',
23
+ demandOption: true
24
+ })
25
+ .option('meta', {
26
+ alias: 'm',
27
+ describe: 'Meta directory containing templates and styles (defaults to ursa package meta)',
28
+ type: 'string'
29
+ })
30
+ .option('output', {
31
+ alias: 'o',
32
+ default: 'output',
33
+ describe: 'Output directory for generated site',
34
+ type: 'string'
35
+ })
36
+ .option('whitelist', {
37
+ alias: 'w',
38
+ describe: 'Path to whitelist file containing patterns for files to include',
39
+ type: 'string'
40
+ })
41
+ .option('clean', {
42
+ alias: 'c',
43
+ describe: 'Ignore cached hashes and regenerate all files',
44
+ type: 'boolean',
45
+ default: false
46
+ });
47
+ },
48
+ async (argv) => {
49
+ const source = resolve(argv.source);
50
+ const meta = argv.meta ? resolve(argv.meta) : PACKAGE_META;
51
+ const output = resolve(argv.output);
52
+ const whitelist = argv.whitelist ? resolve(argv.whitelist) : null;
53
+ const clean = argv.clean;
54
+
55
+ console.log(`Generating site from ${source} to ${output} using meta from ${meta}`);
56
+ if (whitelist) {
57
+ console.log(`Using whitelist: ${whitelist}`);
58
+ }
59
+ if (clean) {
60
+ console.log(`Clean build: ignoring cached hashes`);
61
+ }
62
+
63
+ try {
64
+ await generate({
65
+ _source: source,
66
+ _meta: meta,
67
+ _output: output,
68
+ _whitelist: whitelist,
69
+ _clean: clean
70
+ });
71
+ console.log('Site generation completed successfully!');
72
+ } catch (error) {
73
+ console.error('Error generating site:', error.message);
74
+ process.exit(1);
75
+ }
76
+ }
77
+ )
78
+ .command(
79
+ 'serve <source>',
80
+ 'Generate site and serve with live reloading',
81
+ (yargs) => {
82
+ return yargs
83
+ .positional('source', {
84
+ describe: 'Source directory containing markdown/wikitext files',
85
+ type: 'string',
86
+ demandOption: true
87
+ })
88
+ .option('meta', {
89
+ alias: 'm',
90
+ describe: 'Meta directory containing templates and styles (defaults to ursa package meta)',
91
+ type: 'string'
92
+ })
93
+ .option('output', {
94
+ alias: 'o',
95
+ default: 'output',
96
+ describe: 'Output directory for generated site',
97
+ type: 'string'
98
+ })
99
+ .option('port', {
100
+ alias: 'p',
101
+ default: 8080,
102
+ describe: 'Port to serve on',
103
+ type: 'number'
104
+ })
105
+ .option('whitelist', {
106
+ alias: 'w',
107
+ describe: 'Path to whitelist file containing patterns for files to include',
108
+ type: 'string'
109
+ })
110
+ .option('clean', {
111
+ alias: 'c',
112
+ describe: 'Ignore cached hashes and regenerate all files',
113
+ type: 'boolean',
114
+ default: false
115
+ });
116
+ },
117
+ async (argv) => {
118
+ const source = resolve(argv.source);
119
+ const meta = argv.meta ? resolve(argv.meta) : PACKAGE_META;
120
+ const output = resolve(argv.output);
121
+ const port = argv.port;
122
+ const whitelist = argv.whitelist ? resolve(argv.whitelist) : null;
123
+ const clean = argv.clean;
124
+
125
+ console.log(`Starting development server...`);
126
+ console.log(`Source: ${source}`);
127
+ console.log(`Meta: ${meta}`);
128
+ console.log(`Output: ${output}`);
129
+ console.log(`Port: ${port}`);
130
+ if (whitelist) {
131
+ console.log(`Using whitelist: ${whitelist}`);
132
+ }
133
+
134
+ try {
135
+ const { serve } = await import('../src/serve.js');
136
+ await serve({
137
+ _source: source,
138
+ _meta: meta,
139
+ _output: output,
140
+ port: port,
141
+ _whitelist: whitelist,
142
+ _clean: clean
143
+ });
144
+ } catch (error) {
145
+ console.error('Error starting development server:', error.message);
146
+ console.error(error);
147
+ process.exit(1);
148
+ }
149
+ }
150
+ )
151
+ .command(
152
+ '$0 <source>',
153
+ 'Generate a static site from source files (default command)',
154
+ (yargs) => {
155
+ return yargs
156
+ .positional('source', {
157
+ describe: 'Source directory containing markdown/wikitext files',
158
+ type: 'string',
159
+ demandOption: true
160
+ })
161
+ .option('meta', {
162
+ alias: 'm',
163
+ default: 'meta',
164
+ describe: 'Meta directory containing templates and styles',
165
+ type: 'string'
166
+ })
167
+ .option('output', {
168
+ alias: 'o',
169
+ default: 'output',
170
+ describe: 'Output directory for generated site',
171
+ type: 'string'
172
+ })
173
+ .option('whitelist', {
174
+ alias: 'w',
175
+ describe: 'Path to whitelist file containing patterns for files to include',
176
+ type: 'string'
177
+ });
178
+ },
179
+ async (argv) => {
180
+ const source = resolve(argv.source);
181
+ const meta = resolve(argv.meta);
182
+ const output = resolve(argv.output);
183
+ const whitelist = argv.whitelist ? resolve(argv.whitelist) : null;
184
+
185
+ console.log(`Generating site from ${source} to ${output} using meta from ${meta}`);
186
+ if (whitelist) {
187
+ console.log(`Using whitelist: ${whitelist}`);
188
+ }
189
+
190
+ try {
191
+ await generate({
192
+ _source: source,
193
+ _meta: meta,
194
+ _output: output,
195
+ _whitelist: whitelist
196
+ });
197
+ console.log('Site generation completed successfully!');
198
+ } catch (error) {
199
+ console.error('Error generating site:', error.message);
200
+ process.exit(1);
201
+ }
202
+ }
203
+ )
204
+ .help()
205
+ .alias('help', 'h')
206
+ .version()
207
+ .alias('version', 'v')
208
+ .parse();
package/lib/index.js CHANGED
@@ -1,9 +1,14 @@
1
1
  import { generate } from "../src/jobs/generate.js";
2
+ import { serve } from "../src/serve.js";
2
3
 
3
- export default function generateSite({ source, meta, output }) {
4
+ export default function generateSite({ source, meta, output, whitelist }) {
4
5
  if (!source) throw new Error("source is required");
5
6
  if (!meta) throw new Error("meta is required");
6
7
  if (!output) throw new Error("output is required");
7
8
 
8
- generate({ source, meta, output });
9
+ return generate({ _source: source, _meta: meta, _output: output, _whitelist: whitelist });
9
10
  }
11
+
12
+ // Also export the generate and serve functions directly for more flexibility
13
+ export { generate } from "../src/jobs/generate.js";
14
+ export { serve } from "../src/serve.js";
@@ -1,6 +1,8 @@
1
1
  <html>
2
2
 
3
3
  <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
4
6
  <link rel="stylesheet" href="/public/default.css" />
5
7
  <link rel="stylesheet" href="/public/cssui.bundle.min.css" />
6
8
  <link rel="stylesheet" href="/public/character-sheet.css" />
@@ -1,22 +1,46 @@
1
1
  <html>
2
2
 
3
3
  <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>${title}</title>
4
7
  <link rel="stylesheet" href="/public/default.css" />
8
+ <style>
9
+ ${embeddedStyle}
10
+ </style>
11
+ <script>
12
+ // Embed search index data
13
+ window.SEARCH_INDEX = ${searchIndex};
14
+ </script>
15
+ <script src="/public/search.js"></script>
16
+
5
17
  </head>
6
18
 
7
19
  <body data-template-id="default">
20
+ <nav id="nav-global">
21
+ <button class="menu-button" aria-label="Menu">☰</button>
22
+
23
+ <input id="global-search" type="text" placeholder="Search..." />
24
+
25
+ <span class="avatar" aria-hidden="true">👤</span>
26
+ </nav>
8
27
  <nav id="nav-main">
9
- <span id="menu-icon" class="material-symbols-outlined">
10
- menu
11
- </span>
12
28
  ${menu}
13
29
  </nav>
14
- <article>
30
+ <nav id="nav-toc">
31
+ <!-- TOC will be generated by JavaScript -->
32
+ </nav>
33
+ <article id="main-content">
15
34
  ${body}
16
35
  </article>
17
36
  <div id="global-nav">
18
- global nav here
19
37
  </div>
38
+
39
+ <script src="/public/toc.js"></script>
40
+ <script src="/public/toc-generator.js"></script>
41
+ <script src="/public/menu.js"></script>
42
+ <script src="/public/sectionify.js"></script>
43
+ <script src="/public/sticky.js"></script>
20
44
  </body>
21
45
 
22
46
  </html>