mirror of
https://github.com/GenderDysphoria/GenderDysphoria.fyi.git
synced 2025-01-30 23:06:18 +00:00
Added support for loading posts
This commit is contained in:
parent
56d5f33453
commit
27621e0edd
1
.gitignore
vendored
1
.gitignore
vendored
@ -6,6 +6,7 @@ node_modules
|
||||
/bs-manifest.json
|
||||
/bs-cache
|
||||
/pages.json
|
||||
/posts.json
|
||||
/if-*
|
||||
/twitter-cache.json
|
||||
/twitter-config.json
|
||||
|
@ -28,19 +28,19 @@ module.exports = exports = class File {
|
||||
file.basename = basename = basename.slice(1);
|
||||
}
|
||||
|
||||
// remove the public root and any _images segment from the dir
|
||||
const dir = this._dir(file.dir);
|
||||
|
||||
this.kind = kind(filepath);
|
||||
this.type = type(filepath);
|
||||
this.input = filepath; // public/file.ext
|
||||
this.cwd = file.dir;
|
||||
this.ext = this.preprocessed ? file.ext : normalizedExt(file.ext);
|
||||
this.input = filepath; // public/file.ext
|
||||
this.base = path.join(...dir); // '', 'folder', 'folder/subfolder'
|
||||
this.dir = path.join('/', ...dir); // /, /folder, /folder/subfolder
|
||||
this.name = name; // index, fileA, fileB
|
||||
this.basename = basename; // index.ext, fileA.ext, fileB.ext
|
||||
this.ext = file.ext;
|
||||
|
||||
const dir = this._dir(file.dir);
|
||||
if (dir) {
|
||||
this.base = path.join(...dir); // '', 'folder', 'folder/subfolder'
|
||||
this.dir = path.join('/', ...dir); // /, /folder, /folder/subfolder
|
||||
}
|
||||
|
||||
this._out();
|
||||
|
||||
|
71
build/files.js
Normal file
71
build/files.js
Normal file
@ -0,0 +1,71 @@
|
||||
const path = require('path');
|
||||
const { groupBy, keyBy, filter, find, get, memoize } = require('lodash');
|
||||
const { kind, KIND } = require('./resolve');
|
||||
const File = require('./file');
|
||||
const Asset = require('./asset');
|
||||
const Page = require('./page');
|
||||
|
||||
module.exports = exports = class Files {
|
||||
|
||||
constructor (paths, base = '') {
|
||||
this.KIND_MAP = this._kindMap();
|
||||
|
||||
this.base = base;
|
||||
this.files = paths.map(this._parsePath.bind(this)).filter(Boolean);
|
||||
|
||||
const {
|
||||
[KIND.PAGE]: pages,
|
||||
[KIND.ASSET]: assets,
|
||||
} = groupBy(this.files, 'kind');
|
||||
|
||||
this.pages = pages || [];
|
||||
this.assets = assets || [];
|
||||
|
||||
this._getTitlecard = memoize(() =>
|
||||
get(find(this.files, { name: 'titlecard', dir: this.base }), [ 0, 'url' ]),
|
||||
);
|
||||
|
||||
this._getWebReady = memoize(() => assets && keyBy(assets.map((a) => a.webready()), 'name'));
|
||||
|
||||
this.for = memoize(this.for);
|
||||
}
|
||||
|
||||
get all () {
|
||||
return this.files;
|
||||
}
|
||||
|
||||
get titlecard () {
|
||||
return this._getTitlecard();
|
||||
}
|
||||
|
||||
get webready () {
|
||||
return this._getWebReady();
|
||||
}
|
||||
|
||||
get tasks () {
|
||||
return this.files.map((a) => a.tasks()).flat(1);
|
||||
}
|
||||
|
||||
for (dir) {
|
||||
dir = path.join(this.base, dir);
|
||||
const subset = filter(this.files, { dir });
|
||||
return new this.constructor(subset, dir);
|
||||
}
|
||||
|
||||
_kindMap () {
|
||||
return {
|
||||
[KIND.PAGE]: Page,
|
||||
[KIND.ASSET]: Asset,
|
||||
[KIND.OTHER]: File,
|
||||
};
|
||||
}
|
||||
|
||||
_parsePath (filepath) {
|
||||
if (typeof filepath === 'object') return filepath;
|
||||
const k = kind(filepath);
|
||||
const F = this.KIND_MAP[k];
|
||||
const f = new F(filepath);
|
||||
if (f.kind === KIND.PAGE && f.preprocessed) return false;
|
||||
return f;
|
||||
}
|
||||
};
|
@ -1,5 +1,8 @@
|
||||
|
||||
process.env.BLUEBIRD_DEBUG = true;
|
||||
|
||||
const loadPublicFiles = require('./public');
|
||||
const loadPostFiles = require('./posts');
|
||||
const Cache = require('./cache');
|
||||
const Promise = require('bluebird');
|
||||
const fs = require('fs-extra');
|
||||
@ -16,21 +19,31 @@ const scripts = require('./scripts');
|
||||
|
||||
|
||||
exports.everything = function (prod = false) {
|
||||
const fn = async () => {
|
||||
async function fn () {
|
||||
|
||||
// load a directory scan of the public folder
|
||||
const PublicFiles = await loadPublicFiles();
|
||||
// load a directory scan of the public and post folders
|
||||
const [ PublicFiles, PostFiles ] = await Promise.all([
|
||||
loadPublicFiles(),
|
||||
loadPostFiles(),
|
||||
]);
|
||||
|
||||
// load data for all the files in that folder
|
||||
await Promise.map(PublicFiles.assets, (p) => p.load());
|
||||
await Promise.map(PublicFiles.pages, (p) => p.load(PublicFiles));
|
||||
|
||||
await Promise.map(PostFiles.assets, (p) => p.load());
|
||||
await Promise.map(PostFiles.pages, (p) => p.load(PostFiles));
|
||||
|
||||
|
||||
// prime tweet data for all pages
|
||||
const pages = await primeTweets(PublicFiles.pages);
|
||||
const posts = await primeTweets(PostFiles.pages);
|
||||
|
||||
|
||||
// compile all tasks to be completed
|
||||
const tasks = await Promise.all([
|
||||
PublicFiles.tasks,
|
||||
PostFiles.tasks,
|
||||
scss(prod),
|
||||
scripts(prod),
|
||||
svg(prod),
|
||||
@ -38,6 +51,7 @@ exports.everything = function (prod = false) {
|
||||
]);
|
||||
|
||||
await fs.writeFile(resolve('pages.json'), JSON.stringify(pages.map((p) => p.toJson()), null, 2));
|
||||
await fs.writeFile(resolve('posts.json'), JSON.stringify(posts.map((p) => p.toJson()), null, 2));
|
||||
|
||||
await fs.ensureDir(resolve('dist'));
|
||||
const cache = new Cache({ prod });
|
||||
@ -45,10 +59,9 @@ exports.everything = function (prod = false) {
|
||||
await evaluate(tasks.flat(), cache);
|
||||
await cache.save();
|
||||
|
||||
await pageWriter(pages, prod);
|
||||
};
|
||||
await pageWriter([ ...pages, ...posts ], prod);
|
||||
}
|
||||
|
||||
const ret = () => fn().catch((err) => { console.log(err.trace || err); throw err; });
|
||||
ret.displayName = prod ? 'generateEverythingForProd' : 'generateEverything';
|
||||
return ret;
|
||||
fn.displayName = prod ? 'buildForProd' : 'build';
|
||||
return fn;
|
||||
};
|
||||
|
@ -44,7 +44,7 @@ module.exports = exports = async function writePageContent (pages, prod) {
|
||||
preview: page.engine === 'md' && String(engines.preview(data.source, data)),
|
||||
};
|
||||
|
||||
const output = resolve('dist', page.output);
|
||||
const output = resolve('dist', page.out);
|
||||
await fs.ensureDir(path.dirname(output));
|
||||
await Promise.all([
|
||||
fs.writeFile(output, Buffer.from(html)),
|
||||
|
@ -31,23 +31,27 @@ module.exports = exports = class Page extends File {
|
||||
'flags',
|
||||
);
|
||||
|
||||
this.engine = ENGINE[this.type] || ENGINE.COPY;
|
||||
}
|
||||
|
||||
_out () {
|
||||
var isIndexPage = (this.name === 'index');
|
||||
var isClean = isCleanUrl(this.ext);
|
||||
|
||||
if (isClean && isIndexPage) {
|
||||
this.output = path.join(this.base, 'index.html');
|
||||
this.out = path.join(this.base, 'index.html');
|
||||
this.json = path.join(this.base, 'index.json');
|
||||
this.url = this.dir;
|
||||
} else if (isClean) {
|
||||
this.output = path.join(this.base, this.name, 'index.html');
|
||||
this.out = path.join(this.base, this.name, 'index.html');
|
||||
this.json = path.join(this.base, this.name + '.json');
|
||||
this.url = path.join(this.dir, this.name);
|
||||
} else if (isIndexPage) {
|
||||
this.output = path.join(this.base, 'index.html');
|
||||
this.out = path.join(this.base, 'index.html');
|
||||
this.json = path.join(this.base, this.name + '.json');
|
||||
this.url = this.dir;
|
||||
} else {
|
||||
this.output = path.join(this.base, this.basename);
|
||||
this.out = path.join(this.base, this.basename);
|
||||
this.json = path.join(this.base, this.basename + '.json');
|
||||
this.url = path.join(this.dir, this.basename);
|
||||
}
|
||||
@ -55,8 +59,6 @@ module.exports = exports = class Page extends File {
|
||||
const url = new URL(pkg.siteInfo.siteUrl);
|
||||
url.pathname = this.url;
|
||||
this.fullurl = url.href;
|
||||
|
||||
this.engine = ENGINE[this.type] || ENGINE.COPY;
|
||||
}
|
||||
|
||||
async load (PublicFiles) {
|
||||
@ -65,8 +67,6 @@ module.exports = exports = class Page extends File {
|
||||
fs.stat(this.input).catch(() => ({})),
|
||||
]);
|
||||
|
||||
const { titlecard, assets } = PublicFiles.for(this.dir);
|
||||
|
||||
// empty file
|
||||
if (!raw || !ctime) {
|
||||
log.error('Could not load page: ' + this.filepath);
|
||||
@ -82,20 +82,28 @@ module.exports = exports = class Page extends File {
|
||||
|
||||
this.source = body;
|
||||
this.meta = meta;
|
||||
this.images = assets;
|
||||
this.titlecard = titlecard;
|
||||
this.tweets = (meta.tweets || []).map(parseTweetId);
|
||||
this.dateCreated = meta.date && new Date(meta.date) || ctime;
|
||||
this.dateModified = mtime;
|
||||
|
||||
this.classes = Array.from(new Set(meta.classes || []));
|
||||
this._parse(PublicFiles);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
_parse (PublicFiles) {
|
||||
const { titlecard, webready } = PublicFiles.for(this.dir);
|
||||
|
||||
this.images = webready;
|
||||
this.titlecard = titlecard;
|
||||
this.tweets = (this.meta.tweets || []).map(parseTweetId);
|
||||
|
||||
this.classes = Array.from(new Set(this.meta.classes || []));
|
||||
this.flags = this.classes.reduce((res, item) => {
|
||||
var camelCased = item.replace(/-([a-z])/g, (g) => g[1].toUpperCase());
|
||||
res[camelCased] = true;
|
||||
return res;
|
||||
}, {});
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
tasks () {
|
||||
|
16
build/post-asset.js
Normal file
16
build/post-asset.js
Normal file
@ -0,0 +1,16 @@
|
||||
|
||||
const { without } = require('lodash');
|
||||
const Asset = require('./asset');
|
||||
|
||||
const postmatch = /(\d{4}-\d\d-\d\d)\.\d{4}\.(\w+)/;
|
||||
|
||||
module.exports = exports = class PostAsset extends Asset {
|
||||
|
||||
_dir (dir) {
|
||||
dir = dir.replace(postmatch, '$2').split('/');
|
||||
dir = without(dir, 'posts', '_images');
|
||||
dir.unshift('p');
|
||||
return dir;
|
||||
}
|
||||
|
||||
};
|
54
build/post.js
Normal file
54
build/post.js
Normal file
@ -0,0 +1,54 @@
|
||||
|
||||
const path = require('path');
|
||||
const { without } = require('lodash');
|
||||
const { resolve, isCleanUrl } = require('./resolve');
|
||||
const Page = require('./page');
|
||||
const pkg = require(resolve('package.json'));
|
||||
|
||||
const postmatch = /(\d{4}-\d\d-\d\d)\.\d{4}\.(\w+)/;
|
||||
|
||||
module.exports = exports = class Post extends Page {
|
||||
|
||||
_dir (dir) {
|
||||
// if the file name matches the postmatch pattern, then this needs to be /p/ file
|
||||
const match = this.name.match(postmatch);
|
||||
|
||||
if (match) {
|
||||
return [ 'p', match[2] ];
|
||||
}
|
||||
|
||||
dir = dir.replace(postmatch, '$2').split('/');
|
||||
dir = without(dir, 'posts', '_images');
|
||||
dir.unshift('p');
|
||||
return dir;
|
||||
}
|
||||
|
||||
_out () {
|
||||
var isIndexPage = (this.name === 'index' || this.name.match(postmatch));
|
||||
var isClean = isCleanUrl(this.ext);
|
||||
|
||||
if (isClean && isIndexPage) {
|
||||
this.out = path.join(this.base, 'index.html');
|
||||
this.json = path.join(this.base, 'index.json');
|
||||
this.url = this.dir;
|
||||
} else if (isClean) {
|
||||
this.out = path.join(this.base, this.name, 'index.html');
|
||||
this.json = path.join(this.base, this.name + '.json');
|
||||
this.url = path.join(this.dir, this.name);
|
||||
} else if (isIndexPage) {
|
||||
this.out = path.join(this.base, 'index.html');
|
||||
this.json = path.join(this.base, this.name + '.json');
|
||||
this.url = this.dir;
|
||||
} else {
|
||||
this.out = path.join(this.base, this.basename);
|
||||
this.json = path.join(this.base, this.basename + '.json');
|
||||
this.url = path.join(this.dir, this.basename);
|
||||
}
|
||||
|
||||
const url = new URL(pkg.siteInfo.siteUrl);
|
||||
url.pathname = this.url;
|
||||
this.fullurl = url.href;
|
||||
}
|
||||
|
||||
};
|
||||
|
21
build/posts.js
Normal file
21
build/posts.js
Normal file
@ -0,0 +1,21 @@
|
||||
const glob = require('./lib/glob');
|
||||
const { ROOT, KIND } = require('./resolve');
|
||||
const File = require('./file');
|
||||
const Asset = require('./post-asset');
|
||||
const Post = require('./post');
|
||||
const Files = require('./files');
|
||||
|
||||
class PostFiles extends Files {
|
||||
_kindMap () {
|
||||
return {
|
||||
[KIND.PAGE]: Post,
|
||||
[KIND.ASSET]: Asset,
|
||||
[KIND.OTHER]: File,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = exports = async function loadPublicFiles () {
|
||||
return new PostFiles(await glob('posts/**/*', { cwd: ROOT, nodir: true }));
|
||||
};
|
||||
|
@ -1,64 +1,8 @@
|
||||
const glob = require('./lib/glob');
|
||||
const { groupBy, keyBy, filter, find, get, memoize } = require('lodash');
|
||||
const { ROOT, kind, KIND } = require('./resolve');
|
||||
const File = require('./file');
|
||||
const Asset = require('./asset');
|
||||
const Page = require('./page');
|
||||
const Promise = require('bluebird');
|
||||
const { ROOT } = require('./resolve');
|
||||
|
||||
const KIND_MAP = {
|
||||
[KIND.PAGE]: Page,
|
||||
[KIND.ASSET]: Asset,
|
||||
[KIND.OTHER]: File,
|
||||
};
|
||||
const Files = require('./files');
|
||||
|
||||
module.exports = exports = async function loadPublicFiles () {
|
||||
const files = await Promise.map(glob('public/**/*', { cwd: ROOT, nodir: true }), (filepath) => {
|
||||
const k = kind(filepath);
|
||||
const F = KIND_MAP[k];
|
||||
const f = new F(filepath);
|
||||
if (f.kind === KIND.PAGE && f.preprocessed) return false;
|
||||
return f;
|
||||
}).filter(Boolean);
|
||||
|
||||
const {
|
||||
[KIND.PAGE]: pages,
|
||||
[KIND.ASSET]: assets,
|
||||
} = groupBy(files, 'kind');
|
||||
|
||||
function within (dir) {
|
||||
const subset = filter(files, { dir });
|
||||
|
||||
const getTitlecard = memoize(() =>
|
||||
get(find(files, { name: 'titlecard' }), [ 0, 'url' ]),
|
||||
);
|
||||
|
||||
const {
|
||||
[KIND.PAGE]: subpages,
|
||||
[KIND.ASSET]: subassets,
|
||||
} = groupBy(subset, 'kind');
|
||||
|
||||
const webready = subassets && keyBy(subassets.map((a) => a.webready()), 'name');
|
||||
|
||||
return {
|
||||
all: subset,
|
||||
get titlecard () { return getTitlecard; },
|
||||
get pages () {
|
||||
return subpages;
|
||||
},
|
||||
get assets () {
|
||||
return webready;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
all: files,
|
||||
pages,
|
||||
assets,
|
||||
for: memoize(within),
|
||||
get tasks () {
|
||||
return files.map((a) => a.tasks()).flat(1);
|
||||
},
|
||||
};
|
||||
return new Files(await glob('public/**/*', { cwd: ROOT, nodir: true }));
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user