Skip to content

Commit 7a54df7

Browse files
committed
Add build-dist script and document dist regeneration; update README
1 parent e9a80bc commit 7a54df7

File tree

2 files changed

+114
-0
lines changed

2 files changed

+114
-0
lines changed

README.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,35 @@ Examples & docs
4141
- `examples/components/` — standalone example pages used by the in-repo docs viewer.
4242
- `docs/site/index.html` — open this file to browse component docs and try examples locally.
4343

44+
Dist stylesheet (recommended for consumers)
45+
46+
If you want a single stylesheet file that consumers can link to without running any build tools, use the pre-built distribution:
47+
48+
```html
49+
<link rel="stylesheet" href="/path/to/Final-Fantasy-CSS/dist/final-fantasy.css">
50+
```
51+
52+
Regenerating the distribution
53+
54+
We keep a small, zero-dependency Node script that concatenates the project's CSS sources and resolves local `@import` rules into a single `dist/final-fantasy.css`. This avoids reintroducing a required build pipeline while making it easy to recreate the dist when you change source files.
55+
56+
To regenerate the dist file (optional):
57+
58+
1. Ensure Node.js is available on your machine.
59+
2. Run the script from the repository root:
60+
61+
```powershell
62+
node scripts/build-dist.js
63+
```
64+
65+
The script will write `dist/final-fantasy.css` by resolving local `@import` rules. It intentionally does not fetch remote `@import` URLs (for example Google Fonts); those are left in the built file so browsers can fetch them.
66+
67+
Notes for future contributors / agents
68+
69+
- Rationale: The project keeps pre-rendered docs and a built `dist/final-fantasy.css` to minimize friction for consumers who just want a single file to reference.
70+
- If you're an automated agent or contributor returning to this repo later: we intentionally removed a required Node build step to keep the repository portable. If you need to produce a minified version or use PostCSS features, reintroducing a `package.json` and a PostCSS pipeline is acceptable, but document the change and include the built `dist/` files in the commit so consumers continue to get a single-file stylesheet without running builds.
71+
- When making design iterations: edit the source files under `css/` (themes, `components/`, `core.css`, `fonts.css`), then run `node scripts/build-dist.js` and commit `dist/final-fantasy.css` along with your source changes so reviewers can see the combined output quickly.
72+
4473
Notes
4574

4675
- Fonts in `FF6/fonts/` may have licensing restrictions; check `FF6/fonts/readme.txt` before redistribution.

scripts/build-dist.js

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
#!/usr/bin/env node
2+
const fs = require('fs');
3+
const path = require('path');
4+
5+
// Simple dist builder: resolves local @import url(...) statements
6+
// and concatenates referenced files in order. Does not fetch remote URLs.
7+
8+
const repoRoot = path.resolve(__dirname, '..');
9+
const cssRoot = path.join(repoRoot, 'css');
10+
const entry = path.join(cssRoot, 'final-fantasy.css');
11+
const outDir = path.join(repoRoot, 'dist');
12+
const outFile = path.join(outDir, 'final-fantasy.css');
13+
14+
function readFileSafe(p){
15+
if(!fs.existsSync(p)) return null;
16+
return fs.readFileSync(p,'utf8');
17+
}
18+
19+
function resolveImportPath(baseDir, importPath){
20+
// strip surrounding url(...) or quotes
21+
importPath = importPath.trim();
22+
importPath = importPath.replace(/^url\((.*)\)$/,'$1').replace(/^['"]|['"]$/g,'');
23+
// ignore absolute URLs (http/https)
24+
if(/^https?:\/\//.test(importPath)) return null;
25+
// if path is relative, resolve
26+
return path.resolve(baseDir, importPath);
27+
}
28+
29+
function processCss(filePath, seen){
30+
seen = seen || new Set();
31+
if(!filePath || seen.has(filePath)) return '';
32+
seen.add(filePath);
33+
const content = readFileSafe(filePath);
34+
if(content === null) {
35+
console.warn('Missing file:', filePath);
36+
return '';
37+
}
38+
39+
const dir = path.dirname(filePath);
40+
let out = `/* ===== ${path.relative(repoRoot, filePath)} ===== */\n`;
41+
// Process @import url(...) and @import "..." occurrences
42+
const importRegex = /@import\s+(?:url\()?\s*([^)';]+|"[^"]+"|'[^']+')\s*\)?\s*;?/g;
43+
let lastIndex = 0;
44+
let m;
45+
while((m = importRegex.exec(content)) !== null){
46+
const matchStart = m.index;
47+
// append content before this import
48+
out += content.slice(lastIndex, matchStart);
49+
lastIndex = importRegex.lastIndex;
50+
const rawPath = m[1];
51+
const resolved = resolveImportPath(dir, rawPath);
52+
if(resolved){
53+
// If the resolved path is a directory or not a .css, try adding .css
54+
let candidate = resolved;
55+
if(!path.extname(candidate)) candidate = candidate + '.css';
56+
if(!fs.existsSync(candidate) && fs.existsSync(resolved + '.css')) candidate = resolved + '.css';
57+
if(fs.existsSync(candidate)){
58+
out += processCss(candidate, seen);
59+
continue; // skip adding the import line itself
60+
} else {
61+
// not found, skip but keep the import as-is
62+
out += `/* skipped unresolved import: ${rawPath} */\n`;
63+
}
64+
} else {
65+
// remote import (http), keep as-is
66+
out += m[0] + '\n';
67+
}
68+
}
69+
// append remaining content
70+
out += content.slice(lastIndex);
71+
return out + '\n';
72+
}
73+
74+
function ensureDir(d){ if(!fs.existsSync(d)) fs.mkdirSync(d, { recursive: true }); }
75+
76+
function build(){
77+
ensureDir(outDir);
78+
const result = processCss(entry);
79+
// simple header
80+
const header = `/* Final Fantasy CSS - built dist (generated by scripts/build-dist.js) */\n`;
81+
fs.writeFileSync(outFile, header + '\n' + result, 'utf8');
82+
console.log('Wrote', outFile);
83+
}
84+
85+
build();

0 commit comments

Comments
 (0)