mirror of
https://github.com/remoteintech/remote-jobs
synced 2024-12-24 11:23:09 +00:00
Make the listing site work on Netlify (#460)
This commit is contained in:
parent
a65dfb4464
commit
4ee26500e3
18 changed files with 1034 additions and 175 deletions
|
@ -2,4 +2,4 @@ language: node_js
|
|||
|
||||
before_script: npm install
|
||||
|
||||
script: node bin/validate.js && node node_modules/.bin/mocha
|
||||
script: npm run validate && npm test
|
||||
|
|
11
README.md
11
README.md
|
@ -1,12 +1,13 @@
|
|||
# Remote-friendly companies
|
||||
|
||||
A list of semi to fully remote-friendly companies in or around tech. This is the list. There is also a [blog / information website](https://remoteintech.company/).
|
||||
A list of semi to fully remote-friendly companies in or around tech.
|
||||
|
||||
Contributions are very welcome! Please read the [contribution guidelines](/CONTRIBUTING.md) and complete a [Pull Request template](/PULL_REQUEST_TEMPLATE.MD/) for all new submissions.
|
||||
Contributions are very welcome! Please
|
||||
[submit a pull request on GitHub](https://github.com/remoteintech/remote-jobs/blob/master/CONTRIBUTING.md).
|
||||
|
||||
You can see the format needed in the [example.md](/company-profiles/example.md) file.
|
||||
|
||||
_Some company names have a ⚠️️️ icon next to them. This icon means we don't have much information about this company yet and we would love a contribution! See each individual company profile for details._
|
||||
_Some company names have a ⚠️️️ icon next to them. This icon means we don't have
|
||||
much information about this company yet and we would love a contribution! See
|
||||
each individual company profile for details._
|
||||
|
||||
## Companies
|
||||
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
---
|
||||
layout: none
|
||||
---
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
|
@ -28,10 +31,10 @@ p {
|
|||
</head>
|
||||
<body>
|
||||
<p>
|
||||
This site (the Netlify site for
|
||||
<a href="https://github.com/remoteintech/remote-jobs">remoteintech/remote-jobs</a>)
|
||||
This site is <strong>deprecated</strong>.
|
||||
<br />
|
||||
is still under construction. Check back later!
|
||||
Go here instead:
|
||||
<a href="https://remoteintech.company/">remoteintech.company</a>
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
layout: default
|
||||
---
|
||||
{{ content }}
|
||||
<script type="text/javascript" src="/remote-jobs/site/assets/companies-table.js"></script>
|
|
@ -2,18 +2,236 @@
|
|||
|
||||
const fs = require( 'fs' );
|
||||
const path = require( 'path' );
|
||||
const util = require( 'util' );
|
||||
|
||||
const siteDir = path.join( __dirname, '..', 'site' );
|
||||
const siteBuildDir = path.join( siteDir, 'build' );
|
||||
const cheerio = require( 'cheerio' );
|
||||
const phin = require( 'phin' );
|
||||
const rimraf = require( 'rimraf' );
|
||||
const swig = require( 'swig-templates' );
|
||||
|
||||
if ( ! fs.existsSync( siteBuildDir ) ) {
|
||||
fs.mkdirSync( siteBuildDir );
|
||||
const { parseFromDirectory, headingPropertyNames } = require( '../lib' );
|
||||
const contentPath = path.join( __dirname, '..' );
|
||||
const sitePath = path.join( __dirname, '..', 'site' );
|
||||
const siteBuildPath = path.join( sitePath, 'build' );
|
||||
|
||||
// If we are inside the site build path, this is going to cause problems since
|
||||
// we blow away this directory before regenerating the site
|
||||
// Error message (in node core): path.js:1086 cwd = process.cwd();
|
||||
// Error: ENOENT: no such file or directory, uv_cwd
|
||||
function checkPath( wd ) {
|
||||
const checkWorkingPath = path.resolve( wd ) + path.sep;
|
||||
const checkBuildPath = siteBuildPath + path.sep;
|
||||
if ( checkWorkingPath.substring( 0, checkBuildPath.length ) === checkBuildPath ) {
|
||||
throw new Error(
|
||||
"Please change out of the 'site/build' directory before running this script"
|
||||
);
|
||||
}
|
||||
}
|
||||
checkPath( process.cwd() );
|
||||
if ( process.env.INIT_CWD ) {
|
||||
// This script was run via npm; check the original working directory
|
||||
// because npm barfs in this situation too
|
||||
checkPath( process.env.INIT_CWD );
|
||||
}
|
||||
|
||||
fs.writeFileSync(
|
||||
path.join( siteBuildDir, 'index.html' ),
|
||||
fs.readFileSync(
|
||||
path.join( siteDir, 'coming-soon.html' ),
|
||||
'utf8'
|
||||
)
|
||||
);
|
||||
// Parse the content from the Markdown files
|
||||
console.log( 'Parsing content' );
|
||||
const data = parseFromDirectory( contentPath );
|
||||
|
||||
// Stop if there were any errors
|
||||
if ( data.errors && data.errors.length > 0 ) {
|
||||
data.errors.forEach( err => {
|
||||
err.message.split( '\n' ).forEach( line => {
|
||||
console.log( '%s: %s', err.filename, line );
|
||||
} );
|
||||
} );
|
||||
process.exit( 1 );
|
||||
}
|
||||
|
||||
// Otherwise, OK to continue building the static site
|
||||
|
||||
const assetCacheBuster = Date.now();
|
||||
|
||||
// https://github.com/nodejs/node/issues/17871 :(
|
||||
process.on( 'unhandledRejection', err => {
|
||||
console.error( 'Unhandled promise rejection:', err );
|
||||
process.exit( 1 );
|
||||
} );
|
||||
|
||||
/**
|
||||
* Perform an HTTP request to a URL and return the request body.
|
||||
*/
|
||||
async function request( url ) {
|
||||
console.log(
|
||||
'Requesting URL "%s"',
|
||||
url.length > 70
|
||||
? url.substring( 0, 67 ) + '...'
|
||||
: url
|
||||
);
|
||||
const res = await phin.promisified( url );
|
||||
if ( res.statusCode !== 200 ) {
|
||||
throw new Error(
|
||||
'HTTP response code ' + res.statusCode
|
||||
+ ' for URL: ' + url
|
||||
);
|
||||
}
|
||||
return res.body.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a file to site/build/assets/ (from memory or from an existing file in
|
||||
* site/assets/) and include a cache buster in the new name. Return the URL to
|
||||
* the asset file.
|
||||
*/
|
||||
function copyAssetToBuild( filename, content = null ) {
|
||||
const destFilename = filename
|
||||
.replace( /(\.[^.]+)$/, '-' + assetCacheBuster + '$1' );
|
||||
const destPath = path.join( siteBuildPath, 'assets', destFilename );
|
||||
if ( ! content ) {
|
||||
const srcPath = path.join( sitePath, 'assets', filename );
|
||||
content = fs.readFileSync( srcPath, 'utf8' );
|
||||
}
|
||||
fs.writeFileSync( destPath, content );
|
||||
return '/assets/' + destFilename;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a page's contents to an HTML file.
|
||||
*/
|
||||
function writePage( filename, pageContent ) {
|
||||
console.log( 'Writing page "%s"', filename );
|
||||
filename = path.join( siteBuildPath, filename );
|
||||
if ( ! fs.existsSync( path.dirname( filename ) ) ) {
|
||||
fs.mkdirSync( path.dirname( filename ) );
|
||||
}
|
||||
fs.writeFileSync( filename, pageContent );
|
||||
}
|
||||
|
||||
/**
|
||||
* The main function that prepares the static site.
|
||||
*/
|
||||
async function buildSite() {
|
||||
// Load the HTML from the WP.com blog site
|
||||
const $ = cheerio.load( await request( 'https://blog.remoteintech.company/' ) );
|
||||
|
||||
// Load stylesheets from the WP.com blog site
|
||||
const wpcomStylesheets = $( 'style, link[rel=stylesheet]' ).map( ( i, el ) => {
|
||||
const $el = $( el );
|
||||
const stylesheet = {
|
||||
id: $el.attr( 'id' ) || null,
|
||||
media: $el.attr( 'media' ) || null,
|
||||
};
|
||||
if ( $el.is( 'style' ) ) {
|
||||
stylesheet.content = $el.html();
|
||||
} else {
|
||||
stylesheet.url = $el.attr( 'href' );
|
||||
}
|
||||
return stylesheet;
|
||||
} ).toArray();
|
||||
|
||||
// Fetch the contents of stylesheets included via <link> tags
|
||||
await Promise.all(
|
||||
wpcomStylesheets.filter( s => !! s.url ).map( stylesheet => {
|
||||
return request( stylesheet.url ).then( content => {
|
||||
stylesheet.content = content;
|
||||
} );
|
||||
} )
|
||||
);
|
||||
// TODO: Most URLs that appear inside these CSS files are broken because
|
||||
// they refer to relative URLs against s[012].wp.com
|
||||
const wpcomStylesheetContent = wpcomStylesheets
|
||||
.filter( stylesheet => !! stylesheet.content.trim() )
|
||||
.map( stylesheet => {
|
||||
const lines = [ '/**' ];
|
||||
const idString = (
|
||||
stylesheet.id ? ' (id="' + stylesheet.id + '")' : ''
|
||||
);
|
||||
if ( stylesheet.url ) {
|
||||
lines.push( ' * WP.com external style' + idString );
|
||||
lines.push( ' * ' + stylesheet.url );
|
||||
} else {
|
||||
lines.push( ' * WP.com inline style' + idString );
|
||||
}
|
||||
lines.push( ' */' );
|
||||
if ( stylesheet.media && stylesheet.media !== 'all' ) {
|
||||
lines.push( '@media ' + stylesheet.media + ' {' );
|
||||
}
|
||||
lines.push( stylesheet.content.trim() );
|
||||
if ( stylesheet.media && stylesheet.media !== 'all' ) {
|
||||
lines.push( '} /* @media ' + stylesheet.media + ' */' );
|
||||
}
|
||||
return lines.join( '\n' );
|
||||
} ).join( '\n\n' ) + '\n';
|
||||
|
||||
// Use the emoji code from WP.com
|
||||
// Most platforms will display emoji natively, but e.g. Linux does not
|
||||
let wpcomEmojiScript = null;
|
||||
$( 'script' ).each( ( i, el ) => {
|
||||
const scriptContents = $( el ).html();
|
||||
if ( /\bwindow\._wpemojiSettings\s*=\s*{/.test( scriptContents ) ) {
|
||||
wpcomEmojiScript = scriptContents;
|
||||
}
|
||||
} );
|
||||
|
||||
// Set up the site build directory (start fresh each time)
|
||||
rimraf.sync( siteBuildPath );
|
||||
fs.mkdirSync( siteBuildPath );
|
||||
fs.mkdirSync( path.join( siteBuildPath, 'assets' ) );
|
||||
|
||||
// Set up styles/scripts to be included on all pages
|
||||
const stylesheets = [ {
|
||||
url: copyAssetToBuild( 'wpcom-blog-styles.css', wpcomStylesheetContent ),
|
||||
}, {
|
||||
url: '//fonts.googleapis.com/css?family=Source+Sans+Pro:r%7CSource+Sans+Pro:r,i,b,bi&subset=latin,latin-ext,latin,latin-ext',
|
||||
} ];
|
||||
const scripts = [];
|
||||
if ( wpcomEmojiScript ) {
|
||||
scripts.push( {
|
||||
url: copyAssetToBuild( 'wpcom-emoji.js', wpcomEmojiScript ),
|
||||
} );
|
||||
}
|
||||
|
||||
// Set up styles/scripts for specific pages
|
||||
const indexStylesheets = [ {
|
||||
url: copyAssetToBuild( 'companies-table.css' ),
|
||||
} ];
|
||||
const indexScripts = [ {
|
||||
url: '//cdnjs.cloudflare.com/ajax/libs/list.js/1.5.0/list.min.js',
|
||||
}, {
|
||||
url: copyAssetToBuild( 'companies-table.js' ),
|
||||
} ];
|
||||
const profileStylesheets = [ {
|
||||
url: copyAssetToBuild( 'company-profile.css' ),
|
||||
} ];
|
||||
|
||||
// Generate the index.html file from the main README
|
||||
// TODO: Build this page and its table dynamically; more filters
|
||||
const readmeTemplate = swig.compileFile(
|
||||
path.join( sitePath, 'templates', 'index.html' )
|
||||
);
|
||||
writePage( 'index.html', readmeTemplate( {
|
||||
stylesheets: stylesheets.concat( indexStylesheets ),
|
||||
scripts: scripts.concat( indexScripts ),
|
||||
pageContent: data.readmeContent,
|
||||
} ) );
|
||||
|
||||
// Generate the page for each company
|
||||
const companyTemplate = swig.compileFile(
|
||||
path.join( sitePath, 'templates', 'company.html' )
|
||||
);
|
||||
data.companies.forEach( company => {
|
||||
const dirname = company.linkedFilename.replace( /\.md$/, '' );
|
||||
const missingHeadings = Object.keys( headingPropertyNames )
|
||||
.filter( h => ! company.profileContent[ h ] );
|
||||
|
||||
writePage( path.join( dirname, 'index.html' ), companyTemplate( {
|
||||
stylesheets: stylesheets.concat( profileStylesheets ),
|
||||
scripts,
|
||||
company,
|
||||
headingPropertyNames,
|
||||
missingHeadings,
|
||||
} ) );
|
||||
} );
|
||||
}
|
||||
|
||||
buildSite();
|
||||
|
|
42
lib/index.js
42
lib/index.js
|
@ -72,6 +72,15 @@ function stripExtraChars( text ) {
|
|||
exports.stripExtraChars = stripExtraChars;
|
||||
|
||||
|
||||
/**
|
||||
* Other exports
|
||||
*/
|
||||
exports.headingPropertyNames = headingsAll.reduce( ( acc, val ) => {
|
||||
acc[ toIdentifierCase( val ) ] = val;
|
||||
return acc;
|
||||
}, {} );
|
||||
|
||||
|
||||
/**
|
||||
* The main exported function
|
||||
*
|
||||
|
@ -111,6 +120,8 @@ exports.parseFromDirectory = contentPath => {
|
|||
|
||||
$( 'tr' ).each( ( i, tr ) => {
|
||||
if ( i === 0 ) {
|
||||
// Assign an ID to the table.
|
||||
$( tr ).closest( 'table' ).attr( 'id', 'companies-table' );
|
||||
// Skip the table header row.
|
||||
return;
|
||||
}
|
||||
|
@ -123,13 +134,20 @@ exports.parseFromDirectory = contentPath => {
|
|||
);
|
||||
}
|
||||
|
||||
const websiteUrl = $td.eq( 1 ).text();
|
||||
const websiteText = websiteUrl
|
||||
.replace( /^https?:\/\//, '' )
|
||||
.replace( /^www\./, '' )
|
||||
.replace( /\/$/, '' );
|
||||
|
||||
const readmeEntry = {
|
||||
// Strip out warning emoji indicating that this profile is incomplete
|
||||
name: $td.eq( 0 ).text().replace( /\u26a0/, '' ).trim(),
|
||||
// Detect warning emoji next to company name
|
||||
isIncomplete: /\u26a0/.test( $td.eq( 0 ).text() ),
|
||||
website: $td.eq( 1 ).text(),
|
||||
shortRegion: $td.eq( 2 ).text(),
|
||||
websiteUrl,
|
||||
websiteText,
|
||||
shortRegion: $td.eq( 2 ).text().trim(),
|
||||
};
|
||||
|
||||
if ( ! readmeEntry.name ) {
|
||||
|
@ -206,9 +224,28 @@ exports.parseFromDirectory = contentPath => {
|
|||
);
|
||||
}
|
||||
|
||||
// Rewrite company profile link to the correct URL for the static site
|
||||
if ( $profileLink.length ) {
|
||||
$profileLink.attr(
|
||||
'href',
|
||||
$profileLink.attr( 'href' )
|
||||
.replace( /^\/company-profiles\//, '/' )
|
||||
.replace( /\.md$/, '/' )
|
||||
);
|
||||
}
|
||||
|
||||
// Rewrite external website link (target="_blank" etc, shorter text)
|
||||
const $websiteLink = $td.eq( 1 ).children().eq( 0 );
|
||||
$websiteLink
|
||||
.attr( 'target', '_blank' )
|
||||
.attr( 'rel', 'noopener noreferrer' )
|
||||
.text( websiteText );
|
||||
|
||||
readmeCompanies.push( readmeEntry );
|
||||
} );
|
||||
|
||||
const readmeContent = $( 'body' ).html();
|
||||
|
||||
// Scan the individual Markdown files containing the company profiles.
|
||||
|
||||
const allProfileHeadings = {};
|
||||
|
@ -444,5 +481,6 @@ exports.parseFromDirectory = contentPath => {
|
|||
profileFilenames,
|
||||
profileHeadingCounts,
|
||||
companies: readmeCompanies,
|
||||
readmeContent,
|
||||
};
|
||||
};
|
||||
|
|
370
package-lock.json
generated
370
package-lock.json
generated
|
@ -5,8 +5,17 @@
|
|||
"@types/node": {
|
||||
"version": "8.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-8.5.1.tgz",
|
||||
"integrity": "sha512-SrmAO+NhnsuG/6TychSl2VdxBZiw/d6V+8j+DFo8O3PwFi+QeYXWHhAw+b170aSc6zYab6/PjEWRZHIDN9mNUw==",
|
||||
"dev": true
|
||||
"integrity": "sha512-SrmAO+NhnsuG/6TychSl2VdxBZiw/d6V+8j+DFo8O3PwFi+QeYXWHhAw+b170aSc6zYab6/PjEWRZHIDN9mNUw=="
|
||||
},
|
||||
"align-text": {
|
||||
"version": "0.1.4",
|
||||
"resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz",
|
||||
"integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=",
|
||||
"requires": {
|
||||
"kind-of": "^3.0.2",
|
||||
"longest": "^1.0.1",
|
||||
"repeat-string": "^1.5.2"
|
||||
}
|
||||
},
|
||||
"assertion-error": {
|
||||
"version": "1.1.0",
|
||||
|
@ -14,23 +23,25 @@
|
|||
"integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==",
|
||||
"dev": true
|
||||
},
|
||||
"async": {
|
||||
"version": "0.2.10",
|
||||
"resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz",
|
||||
"integrity": "sha1-trvgsGdLnXGXCMo43owjfLUmw9E="
|
||||
},
|
||||
"balanced-match": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
|
||||
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
|
||||
"dev": true
|
||||
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
|
||||
},
|
||||
"boolbase": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
|
||||
"integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=",
|
||||
"dev": true
|
||||
"integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24="
|
||||
},
|
||||
"brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"balanced-match": "^1.0.0",
|
||||
"concat-map": "0.0.1"
|
||||
|
@ -42,6 +53,20 @@
|
|||
"integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==",
|
||||
"dev": true
|
||||
},
|
||||
"camelcase": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz",
|
||||
"integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk="
|
||||
},
|
||||
"center-align": {
|
||||
"version": "0.1.3",
|
||||
"resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz",
|
||||
"integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=",
|
||||
"requires": {
|
||||
"align-text": "^0.1.3",
|
||||
"lazy-cache": "^1.0.3"
|
||||
}
|
||||
},
|
||||
"chai": {
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/chai/-/chai-4.1.2.tgz",
|
||||
|
@ -66,7 +91,6 @@
|
|||
"version": "1.0.0-rc.2",
|
||||
"resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.2.tgz",
|
||||
"integrity": "sha1-S59TqBsn5NXawxwP/Qz6A8xoMNs=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"css-select": "~1.2.0",
|
||||
"dom-serializer": "~0.1.0",
|
||||
|
@ -76,6 +100,29 @@
|
|||
"parse5": "^3.0.1"
|
||||
}
|
||||
},
|
||||
"cliui": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz",
|
||||
"integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=",
|
||||
"requires": {
|
||||
"center-align": "^0.1.1",
|
||||
"right-align": "^0.1.1",
|
||||
"wordwrap": "0.0.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"wordwrap": {
|
||||
"version": "0.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz",
|
||||
"integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8="
|
||||
}
|
||||
}
|
||||
},
|
||||
"colors": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz",
|
||||
"integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=",
|
||||
"dev": true
|
||||
},
|
||||
"commander": {
|
||||
"version": "2.15.1",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz",
|
||||
|
@ -85,20 +132,23 @@
|
|||
"concat-map": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
|
||||
"dev": true
|
||||
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
|
||||
},
|
||||
"core-util-is": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
|
||||
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
|
||||
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
|
||||
},
|
||||
"corser": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/corser/-/corser-2.0.1.tgz",
|
||||
"integrity": "sha1-jtolLsqrWEDc2XXOuQ2TcMgZ/4c=",
|
||||
"dev": true
|
||||
},
|
||||
"css-select": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz",
|
||||
"integrity": "sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"boolbase": "~1.0.0",
|
||||
"css-what": "2.1",
|
||||
|
@ -109,8 +159,7 @@
|
|||
"css-what": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.0.tgz",
|
||||
"integrity": "sha1-lGfQMsOM+u+58teVASUwYvh/ob0=",
|
||||
"dev": true
|
||||
"integrity": "sha1-lGfQMsOM+u+58teVASUwYvh/ob0="
|
||||
},
|
||||
"debug": {
|
||||
"version": "3.1.0",
|
||||
|
@ -121,6 +170,11 @@
|
|||
"ms": "2.0.0"
|
||||
}
|
||||
},
|
||||
"decamelize": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
|
||||
"integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA="
|
||||
},
|
||||
"deep-eql": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz",
|
||||
|
@ -140,7 +194,6 @@
|
|||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.0.tgz",
|
||||
"integrity": "sha1-BzxpdUbOB4DOI75KKOKT5AvDDII=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"domelementtype": "~1.1.1",
|
||||
"entities": "~1.1.1"
|
||||
|
@ -149,22 +202,19 @@
|
|||
"domelementtype": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.1.3.tgz",
|
||||
"integrity": "sha1-vSh3PiZCiBrsUVRJJCmcXNgiGFs=",
|
||||
"dev": true
|
||||
"integrity": "sha1-vSh3PiZCiBrsUVRJJCmcXNgiGFs="
|
||||
}
|
||||
}
|
||||
},
|
||||
"domelementtype": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.0.tgz",
|
||||
"integrity": "sha1-sXrtguirWeUt2cGbF1bg/BhyBMI=",
|
||||
"dev": true
|
||||
"integrity": "sha1-sXrtguirWeUt2cGbF1bg/BhyBMI="
|
||||
},
|
||||
"domhandler": {
|
||||
"version": "2.4.1",
|
||||
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.1.tgz",
|
||||
"integrity": "sha1-iS5HAAqZvlW783dP/qBWHYh5wlk=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"domelementtype": "1"
|
||||
}
|
||||
|
@ -173,17 +223,35 @@
|
|||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz",
|
||||
"integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"dom-serializer": "0",
|
||||
"domelementtype": "1"
|
||||
}
|
||||
},
|
||||
"ecstatic": {
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ecstatic/-/ecstatic-3.2.1.tgz",
|
||||
"integrity": "sha512-BAdHx9LOCG1fwxY8MIydUBskl8UUQrYeC3WE14FA1DPlBzqoG1aOgEkypcSpmiiel8RAj8gW1s40RrclfrpGUg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"he": "^1.1.1",
|
||||
"mime": "^1.6.0",
|
||||
"minimist": "^1.1.0",
|
||||
"url-join": "^2.0.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"minimist": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
|
||||
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"entities": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/entities/-/entities-1.1.1.tgz",
|
||||
"integrity": "sha1-blwtClYhtdra7O+AuQ7ftc13cvA=",
|
||||
"dev": true
|
||||
"integrity": "sha1-blwtClYhtdra7O+AuQ7ftc13cvA="
|
||||
},
|
||||
"escape-string-regexp": {
|
||||
"version": "1.0.5",
|
||||
|
@ -191,11 +259,25 @@
|
|||
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
|
||||
"dev": true
|
||||
},
|
||||
"eventemitter3": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.0.tgz",
|
||||
"integrity": "sha512-ivIvhpq/Y0uSjcHDcOIccjmYjGLcP09MFGE7ysAwkAvkXfpZlC985pH2/ui64DKazbTW/4kN3yqozUxlXzI6cA==",
|
||||
"dev": true
|
||||
},
|
||||
"follow-redirects": {
|
||||
"version": "1.5.2",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.2.tgz",
|
||||
"integrity": "sha512-kssLorP/9acIdpQ2udQVTiCS5LQmdEz9mvdIfDcl1gYX2tPKFADHSyFdvJS040XdFsPzemWtgI3q8mFVCxtX8A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"debug": "^3.1.0"
|
||||
}
|
||||
},
|
||||
"fs.realpath": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
||||
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
|
||||
"dev": true
|
||||
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
|
||||
},
|
||||
"get-func-name": {
|
||||
"version": "2.0.0",
|
||||
|
@ -207,7 +289,6 @@
|
|||
"version": "7.1.2",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
|
||||
"integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"fs.realpath": "^1.0.0",
|
||||
"inflight": "^1.0.4",
|
||||
|
@ -239,7 +320,6 @@
|
|||
"version": "3.9.2",
|
||||
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.9.2.tgz",
|
||||
"integrity": "sha1-G9+HrMoPP55T+k/M6w9LTLsAszg=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"domelementtype": "^1.3.0",
|
||||
"domhandler": "^2.3.0",
|
||||
|
@ -249,11 +329,37 @@
|
|||
"readable-stream": "^2.0.2"
|
||||
}
|
||||
},
|
||||
"http-proxy": {
|
||||
"version": "1.17.0",
|
||||
"resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.17.0.tgz",
|
||||
"integrity": "sha512-Taqn+3nNvYRfJ3bGvKfBSRwy1v6eePlm3oc/aWVxZp57DQr5Eq3xhKJi7Z4hZpS8PC3H4qI+Yly5EmFacGuA/g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"eventemitter3": "^3.0.0",
|
||||
"follow-redirects": "^1.0.0",
|
||||
"requires-port": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"http-server": {
|
||||
"version": "0.11.1",
|
||||
"resolved": "https://registry.npmjs.org/http-server/-/http-server-0.11.1.tgz",
|
||||
"integrity": "sha512-6JeGDGoujJLmhjiRGlt8yK8Z9Kl0vnl/dQoQZlc4oeqaUoAKQg94NILLfrY3oWzSyFaQCVNTcKE5PZ3cH8VP9w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"colors": "1.0.3",
|
||||
"corser": "~2.0.0",
|
||||
"ecstatic": "^3.0.0",
|
||||
"http-proxy": "^1.8.1",
|
||||
"opener": "~1.4.0",
|
||||
"optimist": "0.6.x",
|
||||
"portfinder": "^1.0.13",
|
||||
"union": "~0.4.3"
|
||||
}
|
||||
},
|
||||
"inflight": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
|
||||
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"once": "^1.3.0",
|
||||
"wrappy": "1"
|
||||
|
@ -262,32 +368,56 @@
|
|||
"inherits": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
|
||||
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
|
||||
"dev": true
|
||||
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
|
||||
},
|
||||
"is-buffer": {
|
||||
"version": "1.1.6",
|
||||
"resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
|
||||
"integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w=="
|
||||
},
|
||||
"isarray": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
|
||||
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
|
||||
"dev": true
|
||||
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
|
||||
},
|
||||
"kind-of": {
|
||||
"version": "3.2.2",
|
||||
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
|
||||
"integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
|
||||
"requires": {
|
||||
"is-buffer": "^1.1.5"
|
||||
}
|
||||
},
|
||||
"lazy-cache": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz",
|
||||
"integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4="
|
||||
},
|
||||
"lodash": {
|
||||
"version": "4.17.10",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz",
|
||||
"integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==",
|
||||
"dev": true
|
||||
"integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg=="
|
||||
},
|
||||
"longest": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz",
|
||||
"integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc="
|
||||
},
|
||||
"marked": {
|
||||
"version": "0.3.12",
|
||||
"resolved": "https://registry.npmjs.org/marked/-/marked-0.3.12.tgz",
|
||||
"integrity": "sha512-k4NaW+vS7ytQn6MgJn3fYpQt20/mOgYM5Ft9BYMfQJDz2QT6yEeS9XJ8k2Nw8JTeWK/znPPW2n3UJGzyYEiMoA==",
|
||||
"integrity": "sha512-k4NaW+vS7ytQn6MgJn3fYpQt20/mOgYM5Ft9BYMfQJDz2QT6yEeS9XJ8k2Nw8JTeWK/znPPW2n3UJGzyYEiMoA=="
|
||||
},
|
||||
"mime": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
|
||||
"integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
|
||||
"dev": true
|
||||
},
|
||||
"minimatch": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
|
||||
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
}
|
||||
|
@ -295,8 +425,7 @@
|
|||
"minimist": {
|
||||
"version": "0.0.8",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
|
||||
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
|
||||
"dev": true
|
||||
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
|
||||
},
|
||||
"mkdirp": {
|
||||
"version": "0.5.1",
|
||||
|
@ -336,7 +465,6 @@
|
|||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.1.tgz",
|
||||
"integrity": "sha1-mSms32KPwsQQmN6rgqxYDPFJquQ=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"boolbase": "~1.0.0"
|
||||
}
|
||||
|
@ -345,16 +473,29 @@
|
|||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"opener": {
|
||||
"version": "1.4.3",
|
||||
"resolved": "https://registry.npmjs.org/opener/-/opener-1.4.3.tgz",
|
||||
"integrity": "sha1-XG2ixdflgx6P+jlklQ+NZnSskLg=",
|
||||
"dev": true
|
||||
},
|
||||
"optimist": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz",
|
||||
"integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=",
|
||||
"requires": {
|
||||
"minimist": "~0.0.1",
|
||||
"wordwrap": "~0.0.2"
|
||||
}
|
||||
},
|
||||
"parse5": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/parse5/-/parse5-3.0.3.tgz",
|
||||
"integrity": "sha512-rgO9Zg5LLLkfJF9E6CCmXlSE4UVceloys8JrFqCcHloC3usd/kJCyPDwH2SOlzix2j3xaP9sUX3e8+kvkuleAA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
|
@ -362,8 +503,7 @@
|
|||
"path-is-absolute": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
|
||||
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
|
||||
"dev": true
|
||||
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
|
||||
},
|
||||
"pathval": {
|
||||
"version": "1.1.0",
|
||||
|
@ -371,17 +511,54 @@
|
|||
"integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=",
|
||||
"dev": true
|
||||
},
|
||||
"phin": {
|
||||
"version": "2.9.1",
|
||||
"resolved": "https://registry.npmjs.org/phin/-/phin-2.9.1.tgz",
|
||||
"integrity": "sha512-aRmHatimRP+73UipPJEK6AWHWjNcwssW6QmOpUcogYVgO8hbSi2Dv/yDWQKs/DmTjK3gCaf6CNsuYcIBWMnlVw=="
|
||||
},
|
||||
"portfinder": {
|
||||
"version": "1.0.16",
|
||||
"resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.16.tgz",
|
||||
"integrity": "sha512-icBXCFQxzlK2PMepOM0QeEdPPFSLAaXXeuKOv5AClJlMy1oVCBrkDGJ12IZYesI/BF8mpeVco3vRCmgeBb4+hw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"async": "^1.5.2",
|
||||
"debug": "^2.2.0",
|
||||
"mkdirp": "0.5.x"
|
||||
},
|
||||
"dependencies": {
|
||||
"async": {
|
||||
"version": "1.5.2",
|
||||
"resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz",
|
||||
"integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=",
|
||||
"dev": true
|
||||
},
|
||||
"debug": {
|
||||
"version": "2.6.9",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
||||
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ms": "2.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"process-nextick-args": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz",
|
||||
"integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=",
|
||||
"integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M="
|
||||
},
|
||||
"qs": {
|
||||
"version": "2.3.3",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-2.3.3.tgz",
|
||||
"integrity": "sha1-6eha2+ddoLvkyOBHaghikPhjtAQ=",
|
||||
"dev": true
|
||||
},
|
||||
"readable-stream": {
|
||||
"version": "2.3.3",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz",
|
||||
"integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"core-util-is": "~1.0.0",
|
||||
"inherits": "~2.0.3",
|
||||
|
@ -392,17 +569,47 @@
|
|||
"util-deprecate": "~1.0.1"
|
||||
}
|
||||
},
|
||||
"repeat-string": {
|
||||
"version": "1.6.1",
|
||||
"resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz",
|
||||
"integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc="
|
||||
},
|
||||
"requires-port": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
|
||||
"integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=",
|
||||
"dev": true
|
||||
},
|
||||
"right-align": {
|
||||
"version": "0.1.3",
|
||||
"resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz",
|
||||
"integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=",
|
||||
"requires": {
|
||||
"align-text": "^0.1.1"
|
||||
}
|
||||
},
|
||||
"rimraf": {
|
||||
"version": "2.6.2",
|
||||
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz",
|
||||
"integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==",
|
||||
"requires": {
|
||||
"glob": "^7.0.5"
|
||||
}
|
||||
},
|
||||
"safe-buffer": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
|
||||
"integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==",
|
||||
"dev": true
|
||||
"integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg=="
|
||||
},
|
||||
"source-map": {
|
||||
"version": "0.5.7",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
|
||||
"integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
|
||||
},
|
||||
"string_decoder": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz",
|
||||
"integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"safe-buffer": "~5.1.0"
|
||||
}
|
||||
|
@ -416,23 +623,82 @@
|
|||
"has-flag": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"swig-templates": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/swig-templates/-/swig-templates-2.0.2.tgz",
|
||||
"integrity": "sha1-0lAqcwMBk1b06nbqkGXU9Yr2q3U=",
|
||||
"requires": {
|
||||
"optimist": "~0.6",
|
||||
"uglify-js": "2.6.0"
|
||||
}
|
||||
},
|
||||
"type-detect": {
|
||||
"version": "4.0.8",
|
||||
"resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz",
|
||||
"integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==",
|
||||
"dev": true
|
||||
},
|
||||
"uglify-js": {
|
||||
"version": "2.6.0",
|
||||
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.6.0.tgz",
|
||||
"integrity": "sha1-JeqhzDVQ45QQzu+v0c+7a20V8AE=",
|
||||
"requires": {
|
||||
"async": "~0.2.6",
|
||||
"source-map": "~0.5.1",
|
||||
"uglify-to-browserify": "~1.0.0",
|
||||
"yargs": "~3.10.0"
|
||||
}
|
||||
},
|
||||
"uglify-to-browserify": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz",
|
||||
"integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc="
|
||||
},
|
||||
"union": {
|
||||
"version": "0.4.6",
|
||||
"resolved": "https://registry.npmjs.org/union/-/union-0.4.6.tgz",
|
||||
"integrity": "sha1-GY+9rrolTniLDvy2MLwR8kopWeA=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"qs": "~2.3.3"
|
||||
}
|
||||
},
|
||||
"url-join": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/url-join/-/url-join-2.0.5.tgz",
|
||||
"integrity": "sha1-WvIvGMBSoACkjXuCxenC4v7tpyg=",
|
||||
"dev": true
|
||||
},
|
||||
"util-deprecate": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
|
||||
"dev": true
|
||||
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
|
||||
},
|
||||
"window-size": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz",
|
||||
"integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0="
|
||||
},
|
||||
"wordwrap": {
|
||||
"version": "0.0.3",
|
||||
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz",
|
||||
"integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc="
|
||||
},
|
||||
"wrappy": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
|
||||
"dev": true
|
||||
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
|
||||
},
|
||||
"yargs": {
|
||||
"version": "3.10.0",
|
||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz",
|
||||
"integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=",
|
||||
"requires": {
|
||||
"camelcase": "^1.0.2",
|
||||
"cliui": "^2.1.0",
|
||||
"decamelize": "^1.0.0",
|
||||
"window-size": "0.1.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
19
package.json
19
package.json
|
@ -1,11 +1,20 @@
|
|||
{
|
||||
"devDependencies": {
|
||||
"chai": "^4.1.2",
|
||||
"scripts": {
|
||||
"validate": "bin/validate.js",
|
||||
"test": "mocha",
|
||||
"build": "bin/build-site.js",
|
||||
"serve": "http-server site/build/"
|
||||
},
|
||||
"dependencies": {
|
||||
"cheerio": "^1.0.0-rc.2",
|
||||
"marked": "^0.3.12",
|
||||
"mocha": "^5.2.0"
|
||||
"phin": "^2.9.1",
|
||||
"rimraf": "^2.6.2",
|
||||
"swig-templates": "^2.0.2"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "bin/build-site.js"
|
||||
"devDependencies": {
|
||||
"chai": "^4.1.2",
|
||||
"http-server": "^0.11.1",
|
||||
"mocha": "^5.2.0"
|
||||
}
|
||||
}
|
||||
|
|
53
site/README.md
Normal file
53
site/README.md
Normal file
|
@ -0,0 +1,53 @@
|
|||
# Static site generator
|
||||
|
||||
This folder contains the template files needed to generate the static site for
|
||||
this repo ( https://remoteintech.company/ ).
|
||||
|
||||
The code that parses the site's data from the Markdown files in this repository
|
||||
is located in `bin/build-site.js` and `lib/index.js`.
|
||||
|
||||
On each new change to `master` or to a GitHub pull request, if there are no
|
||||
data validation errors, the site is built and deployed to Netlify (the domain
|
||||
mentioned above for the `master` branch, or a temporary subdomain for pull
|
||||
requests).
|
||||
|
||||
The static site uses a layout and CSS copied from
|
||||
https://blog.remoteintech.company/ which is a site hosted on WordPress.com, and
|
||||
the site builder code uses
|
||||
[`swig`](https://github.com/node-swig/swig-templates)
|
||||
as an HTML templating engine.
|
||||
|
||||
To develop against the site locally, you can run this command:
|
||||
|
||||
```sh
|
||||
npm run build && npm run server
|
||||
```
|
||||
|
||||
If you just want the data structure used to build the site, you can do this:
|
||||
|
||||
```js
|
||||
~/code/remote-jobs $ node
|
||||
> const { parseFromDirectory } = require( './lib' );
|
||||
undefined
|
||||
> const data = parseFromDirectory( '.' );
|
||||
undefined
|
||||
> Object.keys( data );
|
||||
[ 'ok',
|
||||
'profileFilenames',
|
||||
'profileHeadingCounts',
|
||||
'companies',
|
||||
'readmeContent' ]
|
||||
> Object.keys( data.companies[ 0 ] )
|
||||
[ 'name',
|
||||
'isIncomplete',
|
||||
'websiteUrl',
|
||||
'websiteText',
|
||||
'shortRegion',
|
||||
'linkedFilename',
|
||||
'profileContent' ]
|
||||
...
|
||||
```
|
||||
|
||||
|
||||
|
||||
The
|
|
@ -1,28 +1,49 @@
|
|||
.markdown-body table {
|
||||
display: table !important;
|
||||
}
|
||||
|
||||
table td.company-name {
|
||||
width: 34%;
|
||||
}
|
||||
table td.company-website {
|
||||
width: 33%;
|
||||
}
|
||||
table td.company-region {
|
||||
width: 33%;
|
||||
}
|
||||
|
||||
#company-filter {
|
||||
margin: 0 16px;
|
||||
padding: 8px;
|
||||
font-family: "Source Sans Pro", sans-serif;
|
||||
font-size: 15px;
|
||||
font-weight: normal;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
#filters-explanation {
|
||||
font-style: italic;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 50em) {
|
||||
#filters-explanation {
|
||||
font-size: 16px;
|
||||
vertical-align: text-top;
|
||||
}
|
||||
}
|
||||
|
||||
table#companies-table.has-filter th {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
table#companies-table button.sort {
|
||||
width: 100%;
|
||||
border-width: 0;
|
||||
border-radius: 0;
|
||||
padding: 7px 3px 4px;
|
||||
text-align: left;
|
||||
font-weight: 700;
|
||||
color: #666;
|
||||
outline: none;
|
||||
}
|
||||
table#companies-table button.sort:hover,
|
||||
table#companies-table button.sort:focus {
|
||||
color: #c61610;
|
||||
}
|
||||
table#companies-table button.sort:hover {
|
||||
background: #f4f4f4;
|
||||
}
|
||||
|
||||
/* Sort indicators adapted from http://listjs.com/examples/table/ */
|
||||
|
||||
.sort.asc:after,
|
||||
.sort.desc:after {
|
||||
table#companies-table .sort.asc:after,
|
||||
table#companies-table .sort.desc:after {
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-left: 6px solid transparent;
|
||||
|
@ -31,13 +52,25 @@ table td.company-region {
|
|||
display: inline-block;
|
||||
position: relative;
|
||||
left: 3px;
|
||||
top: -1px;
|
||||
top: -2px;
|
||||
}
|
||||
|
||||
.sort.asc:after {
|
||||
border-bottom: 6px solid #000;
|
||||
table#companies-table .sort.asc:after {
|
||||
border-bottom: 6px solid;
|
||||
}
|
||||
|
||||
.sort.desc:after {
|
||||
border-top: 6px solid #000;
|
||||
table#companies-table .sort.desc:after {
|
||||
border-top: 6px solid;
|
||||
}
|
||||
|
||||
/* Keep table columns the same width after filtering */
|
||||
|
||||
table#companies-table td.company-name {
|
||||
width: 40%;
|
||||
}
|
||||
table#companies-table td.company-website {
|
||||
width: 35%;
|
||||
}
|
||||
table#companies-table td.company-region {
|
||||
width: 25%;
|
||||
}
|
||||
|
|
|
@ -1,46 +1,5 @@
|
|||
function headAppendChild( node ) {
|
||||
var head = document.head || document.getElementsByTagName( 'head' )[ 0 ];
|
||||
head.appendChild( node );
|
||||
}
|
||||
|
||||
function loadScript( src, callback ) {
|
||||
var script = document.createElement( 'script' );
|
||||
script.src = src;
|
||||
script.async = false;
|
||||
if ( typeof callback === 'function' ) {
|
||||
script.addEventListener( 'load', callback );
|
||||
}
|
||||
|
||||
headAppendChild( script );
|
||||
}
|
||||
|
||||
function loadStylesheet( src ) {
|
||||
var link = document.createElement( 'link' );
|
||||
link.type = 'text/css';
|
||||
link.rel = 'stylesheet';
|
||||
link.href = src;
|
||||
|
||||
headAppendChild( link );
|
||||
}
|
||||
|
||||
function maybeSetupFilters() {
|
||||
// Get the main site URL from the link at the top of each page
|
||||
var rootUrl = document.querySelector( 'body > div.markdown-body > h1 > a' ).href;
|
||||
// If we're not on the main page, no need to do anything
|
||||
if ( rootUrl !== document.location.href ) {
|
||||
return;
|
||||
}
|
||||
|
||||
loadStylesheet( '/remote-jobs/site/assets/companies-table.css' );
|
||||
|
||||
loadScript(
|
||||
'https://cdnjs.cloudflare.com/ajax/libs/list.js/1.5.0/list.min.js',
|
||||
setupFilters
|
||||
);
|
||||
}
|
||||
|
||||
function setupFilters() {
|
||||
var table = document.querySelector( 'h2#companies + table' );
|
||||
var table = document.querySelector( 'table#companies-table' );
|
||||
|
||||
var headerCells = table.querySelectorAll( 'thead tr th' );
|
||||
headerCells[ 0 ].innerHTML =
|
||||
|
@ -60,13 +19,6 @@ function setupFilters() {
|
|||
tds[ 0 ].setAttribute( 'class', 'company-name' );
|
||||
tds[ 1 ].setAttribute( 'class', 'company-website' );
|
||||
tds[ 2 ].setAttribute( 'class', 'company-region' );
|
||||
|
||||
var websiteUrl = tds[ 1 ].innerText.trim();
|
||||
tds[ 1 ].innerHTML =
|
||||
'<a href="' + websiteUrl + '"'
|
||||
+ '_target="blank" rel="noopener noreferrer">'
|
||||
+ websiteUrl
|
||||
+ '</a>';
|
||||
} );
|
||||
|
||||
var filterInput = document.createElement( 'input' );
|
||||
|
@ -75,15 +27,19 @@ function setupFilters() {
|
|||
filterInput.id = 'company-filter';
|
||||
filterInput.setAttribute( 'class', 'company-filter' );
|
||||
|
||||
var companiesAnchorLink = document.querySelector( '#companies .anchorjs-link' );
|
||||
companiesAnchorLink.parentNode.insertBefore( filterInput, companiesAnchorLink );
|
||||
companiesAnchorLink.parentNode.removeChild( companiesAnchorLink );
|
||||
var companiesHeading = document.querySelector( 'h2#companies' );
|
||||
companiesHeading.appendChild( filterInput );
|
||||
|
||||
document.querySelector( 'body > div.markdown-body' )
|
||||
.setAttribute( 'id', 'company-list' );
|
||||
var filtersExplanation = document.createElement( 'p' );
|
||||
filtersExplanation.id = 'filters-explanation';
|
||||
filtersExplanation.innerHTML = (
|
||||
'Use the text box above to filter the list of companies, '
|
||||
+ 'or click a column heading to sort by that column.'
|
||||
);
|
||||
table.parentNode.insertBefore( filtersExplanation, table );
|
||||
|
||||
window.tableFilter = new List(
|
||||
'company-list',
|
||||
'main', // element ID that contains everything
|
||||
{
|
||||
valueNames: [
|
||||
'company-name',
|
||||
|
@ -93,6 +49,10 @@ function setupFilters() {
|
|||
searchClass: 'company-filter',
|
||||
}
|
||||
);
|
||||
|
||||
table.setAttribute( 'class', 'has-filter' );
|
||||
}
|
||||
|
||||
maybeSetupFilters();
|
||||
document.addEventListener( 'DOMContentLoaded', function( event ) {
|
||||
setupFilters();
|
||||
} );
|
||||
|
|
9
site/assets/company-profile.css
Normal file
9
site/assets/company-profile.css
Normal file
|
@ -0,0 +1,9 @@
|
|||
h1.company-name {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.section-atAGlance {
|
||||
font-size: 15px;
|
||||
color: #999;
|
||||
font-size: 85%;
|
||||
}
|
135
site/templates/base.html
Normal file
135
site/templates/base.html
Normal file
|
@ -0,0 +1,135 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en" class="wf-active">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>{% block pageTitle %}{% endblock %} – Remote In Tech</title>
|
||||
{%- for stylesheet in stylesheets %}
|
||||
<link rel="stylesheet" type="text/css" href="{{ stylesheet.url }}" />
|
||||
{%- endfor %}
|
||||
{%- for script in scripts %}
|
||||
<script type="text/javascript" src="{{ script.url }}"></script>
|
||||
{%- endfor %}
|
||||
</head>
|
||||
<body class="page no-sidebar custom-background">
|
||||
<div id="page" class="hfeed site">
|
||||
<a class="skip-link screen-reader-text" href="#content">Skip to content</a>
|
||||
<header id="masthead" class="site-header" role="banner">
|
||||
<div class="site-branding">
|
||||
<p class="site-title">
|
||||
<a href="/">Remote In Tech</a>
|
||||
</p>
|
||||
<p class="site-description">
|
||||
A list of semi to fully remote-friendly companies in tech
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<nav id="site-navigation" class="main-navigation" role="navigation">
|
||||
<div class="menu-primary-container">
|
||||
<ul id="menu-primary" class="menu">
|
||||
<li class="{% block listItemClasses %}menu-item{% endblock %}">
|
||||
<a href="/">The List</a>
|
||||
</li>
|
||||
<li class="menu-item">
|
||||
<a href="https://blog.remoteintech.company/">About</a>
|
||||
</li>
|
||||
<li class="menu-item">
|
||||
<a href="https://blog.remoteintech.company/contact/">Contact</a>
|
||||
</li>
|
||||
<li class="menu-item">
|
||||
<a href="https://blog.remoteintech.company/posts/">Blog</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav><!-- #site-navigation -->
|
||||
</header><!-- #masthead -->
|
||||
|
||||
<div id="content" class="site-content">
|
||||
<div id="primary" class="content-area">
|
||||
<main id="main" class="site-main" role="main">
|
||||
<article class="page hentry">
|
||||
<div class="entry-content">
|
||||
{% block pageContent %}{% endblock %}
|
||||
</div><!-- .entry-content -->
|
||||
<footer class="entry-footer">
|
||||
</footer><!-- .entry-footer -->
|
||||
</article><!-- .page -->
|
||||
</main><!-- #main -->
|
||||
</div><!-- #primary -->
|
||||
</div><!-- #content -->
|
||||
|
||||
<footer id="colophon" class="site-footer" role="contentinfo">
|
||||
<div class="site-info-wrapper clear">
|
||||
<nav
|
||||
class="jetpack-social-navigation jetpack-social-navigation-svg"
|
||||
role="navigation"
|
||||
aria-label="Social Links Menu"
|
||||
>
|
||||
<div class="menu-social-links-container">
|
||||
<ul id="menu-social-links" class="menu">
|
||||
<li class="menu-item">
|
||||
<a href="https://twitter.com/RemoteInTechCo">
|
||||
<span class="screen-reader-text">
|
||||
RemoteInTechCo Twitter
|
||||
</span>
|
||||
<svg
|
||||
class="icon icon-twitter"
|
||||
aria-hidden="true"
|
||||
role="img"
|
||||
>
|
||||
<use
|
||||
href="#icon-twitter"
|
||||
xlink:href="#icon-twitter"
|
||||
></use>
|
||||
</svg>
|
||||
</a>
|
||||
</li>
|
||||
<li class="menu-item">
|
||||
<a href="https://github.com/remoteintech/remote-jobs">
|
||||
<span class="screen-reader-text">
|
||||
GitHub Repo
|
||||
</span>
|
||||
<svg
|
||||
class="icon icon-github"
|
||||
aria-hidden="true"
|
||||
role="img"
|
||||
>
|
||||
<use
|
||||
href="#icon-github"
|
||||
xlink:href="#icon-github"
|
||||
></use>
|
||||
</svg>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div><!-- .menu-social-links-container -->
|
||||
</nav><!-- .jetpack-social-navigation -->
|
||||
<div class="site-info">
|
||||
Powered by
|
||||
<a href="https://github.com/remoteintech/remote-jobs">
|
||||
GitHub
|
||||
</a>
|
||||
and
|
||||
<a href="https://www.netlify.com/">Netlify</a>
|
||||
</div><!-- .site-info -->
|
||||
</div><!-- .site-info-wrapper -->
|
||||
</footer><!-- #colophon -->
|
||||
</div><!-- #page -->
|
||||
<svg
|
||||
style="position: absolute; width: 0; height: 0; overflow: hidden;"
|
||||
version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
>
|
||||
<defs>
|
||||
<symbol id="icon-github" viewBox="0 0 24 24">
|
||||
<path d="M12,2C6.477,2,2,6.477,2,12c0,4.419,2.865,8.166,6.839,9.489c0.5,0.09,0.682-0.218,0.682-0.484 c0-0.236-0.009-0.866-0.014-1.699c-2.782,0.602-3.369-1.34-3.369-1.34c-0.455-1.157-1.11-1.465-1.11-1.465 c-0.909-0.62,0.069-0.608,0.069-0.608c1.004,0.071,1.532,1.03,1.532,1.03c0.891,1.529,2.341,1.089,2.91,0.833
|
||||
c0.091-0.647,0.349-1.086,0.635-1.337c-2.22-0.251-4.555-1.111-4.555-4.943c0-1.091,0.39-1.984,1.03-2.682 C6.546,8.54,6.202,7.524,6.746,6.148c0,0,0.84-0.269,2.75,1.025C10.295,6.95,11.15,6.84,12,6.836 c0.85,0.004,1.705,0.114,2.504,0.336c1.909-1.294,2.748-1.025,2.748-1.025c0.546,1.376,0.202,2.394,0.1,2.646 c0.64,0.699,1.026,1.591,1.026,2.682c0,3.841-2.337,4.687-4.565,4.935c0.359,0.307,0.679,0.917,0.679,1.852 c0,1.335-0.012,2.415-0.012,2.741c0,0.269,0.18,0.579,0.688,0.481C19.138,20.161,22,16.416,22,12C22,6.477,17.523,2,12,2z"/>
|
||||
</symbol>
|
||||
<symbol id="icon-twitter" viewBox="0 0 24 24">
|
||||
<path d="M22.23,5.924c-0.736,0.326-1.527,0.547-2.357,0.646c0.847-0.508,1.498-1.312,1.804-2.27 c-0.793,0.47-1.671,0.812-2.606,0.996C18.324,4.498,17.257,4,16.077,4c-2.266,0-4.103,1.837-4.103,4.103 c0,0.322,0.036,0.635,0.106,0.935C8.67,8.867,5.647,7.234,3.623,4.751C3.27,5.357,3.067,6.062,3.067,6.814 c0,1.424,0.724,2.679,1.825,3.415c-0.673-0.021-1.305-0.206-1.859-0.513c0,0.017,0,0.034,0,0.052c0,1.988,1.414,3.647,3.292,4.023 c-0.344,0.094-0.707,0.144-1.081,0.144c-0.264,0-0.521-0.026-0.772-0.074c0.522,1.63,2.038,2.816,3.833,2.85 c-1.404,1.1-3.174,1.756-5.096,1.756c-0.331,0-0.658-0.019-0.979-0.057c1.816,1.164,3.973,1.843,6.29,1.843 c7.547,0,11.675-6.252,11.675-11.675c0-0.178-0.004-0.355-0.012-0.531C20.985,7.47,21.68,6.747,22.23,5.924z"/>
|
||||
</symbol>
|
||||
</defs>
|
||||
</svg>
|
||||
</body>
|
||||
</html>
|
58
site/templates/company.html
Normal file
58
site/templates/company.html
Normal file
|
@ -0,0 +1,58 @@
|
|||
{% extends 'base.html' %}
|
||||
|
||||
{% block pageTitle %}{{ company.name }}{% endblock %}
|
||||
|
||||
{% block pageContent %}
|
||||
<h1 class="company-name">{{ company.name }}</h1>
|
||||
|
||||
<div class="section section-atAGlance">
|
||||
<a
|
||||
href="{{ company.websiteUrl }}"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>{{ company.websiteText }}</a>
|
||||
{% if company.shortRegion %}
|
||||
• {{ company.shortRegion }}
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% for headingProperty, headingText in headingPropertyNames %}
|
||||
{% if company.profileContent[ headingProperty ] %}
|
||||
<div class="section section-{{ headingProperty }}">
|
||||
<h2>{{ headingText }}</h2>
|
||||
{{ company.profileContent[ headingProperty ]|safe }}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
{# There are different "levels" of incomplete - if company.isIncomplete is
|
||||
# true then this profile is "really" incomplete, with a warning icon and
|
||||
# everything, so there is no point in showing this section.
|
||||
#}
|
||||
{% if missingHeadings.length and ! company.isIncomplete %}
|
||||
<div class="section section-missingInfo">
|
||||
<h2>Missing info</h2>
|
||||
<p>
|
||||
We're missing some information about this company! Here's what
|
||||
else we need:
|
||||
</p>
|
||||
<ul>
|
||||
{% for headingProperty in missingHeadings %}
|
||||
<li>{{ headingPropertyNames[ headingProperty ] }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
<p>
|
||||
<strong>Want to help?</strong>
|
||||
<a
|
||||
href="https://github.com/remoteintech/remote-jobs/edit/master/company-profiles/{{ company.linkedFilename }}"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Send us a pull request on GitHub
|
||||
</a>
|
||||
with your changes to this file!
|
||||
</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
7
site/templates/index.html
Normal file
7
site/templates/index.html
Normal file
|
@ -0,0 +1,7 @@
|
|||
{% extends 'base.html' %}
|
||||
|
||||
{% block pageTitle %}Remote-friendly companies{% endblock %}
|
||||
|
||||
{% block listItemClasses %}menu-item current-menu-item current_page_item{% endblock %}
|
||||
|
||||
{% block pageContent %}{{ pageContent|safe }}{% endblock %}
|
5
test/fixtures/valid-incomplete/README.md
vendored
5
test/fixtures/valid-incomplete/README.md
vendored
|
@ -3,6 +3,9 @@
|
|||
This company table and its linked company profiles contain some companies that
|
||||
have very little information, marked with a ⚠ symbol.
|
||||
|
||||
The website for AngularClass has been changed to test an edge case with company
|
||||
website links.
|
||||
|
||||
## Companies
|
||||
|
||||
Name | Website | Region
|
||||
|
@ -13,4 +16,4 @@ Name | Website | Region
|
|||
[18F](/company-profiles/18f.md) | https://18f.gsa.gov/ | USA
|
||||
[45royale](/company-profiles/45royale.md) ⚠ | http://45royale.com/ |
|
||||
[Aerolab](/company-profiles/aerolab.md) ⚠ | https://aerolab.co/ |
|
||||
[AngularClass](/company-profiles/angularclass.md) ⚠ | https://angularclass.com | PST Timezone
|
||||
[AngularClass](/company-profiles/angularclass.md) ⚠ | http://www.wikihow.com/wikiHow:About-wikiHow | PST Timezone
|
||||
|
|
52
test/fixtures/valid-incomplete/parsed-content/readme.html
vendored
Normal file
52
test/fixtures/valid-incomplete/parsed-content/readme.html
vendored
Normal file
|
@ -0,0 +1,52 @@
|
|||
<h1 id="test-data">Test data</h1>
|
||||
<p>This company table and its linked company profiles contain some companies that
|
||||
have very little information, marked with a ⚠ symbol.</p>
|
||||
<p>The website for AngularClass has been changed to test an edge case with company
|
||||
website links.</p>
|
||||
<h2 id="companies">Companies</h2>
|
||||
<table id="companies-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Website</th>
|
||||
<th>Region</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><a href="/and-yet/">&yet</a></td>
|
||||
<td><a href="https://andyet.com" target="_blank" rel="noopener noreferrer">andyet.com</a></td>
|
||||
<td>Worldwide</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="/10up/">10up</a></td>
|
||||
<td><a href="https://10up.com/" target="_blank" rel="noopener noreferrer">10up.com</a></td>
|
||||
<td>Worldwide</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="/17hats/">17hats</a></td>
|
||||
<td><a href="https://www.17hats.com/" target="_blank" rel="noopener noreferrer">17hats.com</a></td>
|
||||
<td>Worldwide</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="/18f/">18F</a></td>
|
||||
<td><a href="https://18f.gsa.gov/" target="_blank" rel="noopener noreferrer">18f.gsa.gov</a></td>
|
||||
<td>USA</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="/45royale/">45royale</a> ⚠</td>
|
||||
<td><a href="http://45royale.com/" target="_blank" rel="noopener noreferrer">45royale.com</a></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="/aerolab/">Aerolab</a> ⚠</td>
|
||||
<td><a href="https://aerolab.co/" target="_blank" rel="noopener noreferrer">aerolab.co</a></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="/angularclass/">AngularClass</a> ⚠</td>
|
||||
<td><a href="http://www.wikihow.com/wikiHow:About-wikiHow" target="_blank" rel="noopener noreferrer">wikihow.com/wikiHow:About-wikiHow</a></td>
|
||||
<td>PST Timezone</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
|
@ -13,7 +13,7 @@ describe( 'content parsing and metadata', () => {
|
|||
'fixtures',
|
||||
'valid-incomplete',
|
||||
'parsed-content',
|
||||
profile + '.' + section + '.html'
|
||||
profile + ( section ? '.' + section : '' ) + '.html'
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -36,9 +36,13 @@ describe( 'content parsing and metadata', () => {
|
|||
}
|
||||
|
||||
const result = parseFixtures( 'valid-incomplete' );
|
||||
expect( Object.keys( result ) ).to.eql(
|
||||
[ 'ok', 'profileFilenames', 'profileHeadingCounts', 'companies' ]
|
||||
);
|
||||
expect( Object.keys( result ) ).to.eql( [
|
||||
'ok',
|
||||
'profileFilenames',
|
||||
'profileHeadingCounts',
|
||||
'companies',
|
||||
'readmeContent',
|
||||
] );
|
||||
expect( result ).to.deep.include( {
|
||||
ok: true,
|
||||
profileFilenames: [
|
||||
|
@ -71,13 +75,22 @@ describe( 'content parsing and metadata', () => {
|
|||
);
|
||||
} );
|
||||
} );
|
||||
fs.writeFileSync(
|
||||
getContentFilename( 'readme' ),
|
||||
result.readmeContent
|
||||
);
|
||||
}
|
||||
|
||||
expect( result.readmeContent ).to.eql(
|
||||
readContentFile( 'readme' ) + '\n'
|
||||
);
|
||||
|
||||
expect( result.companies ).to.eql( [
|
||||
{
|
||||
name: '&yet',
|
||||
isIncomplete: false,
|
||||
website: 'https://andyet.com',
|
||||
websiteUrl: 'https://andyet.com',
|
||||
websiteText: 'andyet.com',
|
||||
shortRegion: 'Worldwide',
|
||||
linkedFilename: 'and-yet.md',
|
||||
profileContent: getContent( 'and-yet', [
|
||||
|
@ -92,7 +105,8 @@ describe( 'content parsing and metadata', () => {
|
|||
}, {
|
||||
name: '10up',
|
||||
isIncomplete: false,
|
||||
website: 'https://10up.com/',
|
||||
websiteUrl: 'https://10up.com/',
|
||||
websiteText: '10up.com',
|
||||
shortRegion: 'Worldwide',
|
||||
linkedFilename: '10up.md',
|
||||
profileContent: getContent( '10up', [
|
||||
|
@ -106,7 +120,8 @@ describe( 'content parsing and metadata', () => {
|
|||
}, {
|
||||
name: '17hats',
|
||||
isIncomplete: false,
|
||||
website: 'https://www.17hats.com/',
|
||||
websiteUrl: 'https://www.17hats.com/',
|
||||
websiteText: '17hats.com',
|
||||
shortRegion: 'Worldwide',
|
||||
linkedFilename: '17hats.md',
|
||||
profileContent: getContent( '17hats', [
|
||||
|
@ -119,7 +134,8 @@ describe( 'content parsing and metadata', () => {
|
|||
}, {
|
||||
name: '18F',
|
||||
isIncomplete: false,
|
||||
website: 'https://18f.gsa.gov/',
|
||||
websiteUrl: 'https://18f.gsa.gov/',
|
||||
websiteText: '18f.gsa.gov',
|
||||
shortRegion: 'USA',
|
||||
linkedFilename: '18f.md',
|
||||
profileContent: getContent( '18f', [
|
||||
|
@ -132,7 +148,8 @@ describe( 'content parsing and metadata', () => {
|
|||
}, {
|
||||
name: '45royale',
|
||||
isIncomplete: true,
|
||||
website: 'http://45royale.com/',
|
||||
websiteUrl: 'http://45royale.com/',
|
||||
websiteText: '45royale.com',
|
||||
shortRegion: "",
|
||||
linkedFilename: '45royale.md',
|
||||
profileContent: getContent( '45royale', [
|
||||
|
@ -141,7 +158,8 @@ describe( 'content parsing and metadata', () => {
|
|||
}, {
|
||||
name: 'Aerolab',
|
||||
isIncomplete: true,
|
||||
website: 'https://aerolab.co/',
|
||||
websiteUrl: 'https://aerolab.co/',
|
||||
websiteText: 'aerolab.co',
|
||||
shortRegion: "",
|
||||
linkedFilename: 'aerolab.md',
|
||||
profileContent: getContent( 'aerolab', [
|
||||
|
@ -150,7 +168,8 @@ describe( 'content parsing and metadata', () => {
|
|||
}, {
|
||||
name: 'AngularClass',
|
||||
isIncomplete: true,
|
||||
website: 'https://angularclass.com',
|
||||
websiteUrl: 'http://www.wikihow.com/wikiHow:About-wikiHow',
|
||||
websiteText: 'wikihow.com/wikiHow:About-wikiHow',
|
||||
shortRegion: 'PST Timezone',
|
||||
linkedFilename: 'angularclass.md',
|
||||
profileContent: getContent( 'angularclass', [
|
||||
|
|
Loading…
Reference in a new issue