Static site improvements (#467)

* Improve logging messages

* Make local development easier; improve docs

* Combine page-specific CSS files into one

This file is small, and later it will also contain styles that need to
apply to the whole site.

* Add "Edit this page on GitHub" links

* Remove an unneeded element

* Assign table cell classes during parsing

This way it will work with JavaScript disabled too.

* Match font weights with other styles

* Always show hovered links in gray

Before this change, already-visited links would stay red on hover.

* Minor CSS tweaks

* In main table, show company names in bold

* Add mobile styles for companies table

* Remove a couple more empty profile sections
This commit is contained in:
James Nylen 2018-08-12 23:12:18 -05:00 committed by GitHub
parent 38b276606b
commit 58b9cf57b0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 324 additions and 144 deletions

View file

@ -95,11 +95,20 @@ function copyAssetToBuild( filename, content = null ) {
return '/assets/' + destFilename; return '/assets/' + destFilename;
} }
/**
* Return a URL to edit a page on GitHub.
*/
function githubEditUrl( filename ) {
return (
'https://github.com/remoteintech/remote-jobs/edit/master/'
+ filename
);
}
/** /**
* Write a page's contents to an HTML file. * Write a page's contents to an HTML file.
*/ */
function writePage( filename, pageContent ) { function writePage( filename, pageContent ) {
console.log( 'Writing page "%s"', filename );
filename = path.join( siteBuildPath, filename ); filename = path.join( siteBuildPath, filename );
if ( ! fs.existsSync( path.dirname( filename ) ) ) { if ( ! fs.existsSync( path.dirname( filename ) ) ) {
fs.mkdirSync( path.dirname( filename ) ); fs.mkdirSync( path.dirname( filename ) );
@ -183,6 +192,8 @@ async function buildSite() {
url: copyAssetToBuild( 'wpcom-blog-styles.css', wpcomStylesheetContent ), 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', url: '//fonts.googleapis.com/css?family=Source+Sans+Pro:r%7CSource+Sans+Pro:r,i,b,bi&subset=latin,latin-ext,latin,latin-ext',
}, {
url: copyAssetToBuild( 'site.css' ),
} ]; } ];
const scripts = []; const scripts = [];
if ( wpcomEmojiScript ) { if ( wpcomEmojiScript ) {
@ -192,46 +203,51 @@ async function buildSite() {
} }
// Set up styles/scripts for specific pages // Set up styles/scripts for specific pages
const indexStylesheets = [ {
url: copyAssetToBuild( 'companies-table.css' ),
} ];
const indexScripts = [ { const indexScripts = [ {
url: '//cdnjs.cloudflare.com/ajax/libs/list.js/1.5.0/list.min.js', url: '//cdnjs.cloudflare.com/ajax/libs/list.js/1.5.0/list.min.js',
}, { }, {
url: copyAssetToBuild( 'companies-table.js' ), url: copyAssetToBuild( 'companies-table.js' ),
} ]; } ];
const profileStylesheets = [ {
url: copyAssetToBuild( 'company-profile.css' ),
} ];
// Generate the index.html file from the main README // Generate the index.html file from the main README
// TODO: Build this page and its table dynamically; more filters // TODO: Build this page and its table dynamically; more filters
const readmeTemplate = swig.compileFile( const readmeTemplate = swig.compileFile(
path.join( sitePath, 'templates', 'index.html' ) path.join( sitePath, 'templates', 'index.html' )
); );
console.log( 'Writing main page' );
writePage( 'index.html', readmeTemplate( { writePage( 'index.html', readmeTemplate( {
stylesheets: stylesheets.concat( indexStylesheets ), stylesheets,
scripts: scripts.concat( indexScripts ), scripts: scripts.concat( indexScripts ),
pageContent: data.readmeContent, pageContent: data.readmeContent,
editUrl: githubEditUrl( 'README.md' ),
} ) ); } ) );
// Generate the page for each company // Generate the page for each company
const companyTemplate = swig.compileFile( const companyTemplate = swig.compileFile(
path.join( sitePath, 'templates', 'company.html' ) path.join( sitePath, 'templates', 'company.html' )
); );
data.companies.forEach( company => { process.stdout.write( 'Writing company pages..' );
data.companies.forEach( ( company, i ) => {
const dirname = company.linkedFilename.replace( /\.md$/, '' ); const dirname = company.linkedFilename.replace( /\.md$/, '' );
const missingHeadings = Object.keys( headingPropertyNames ) const missingHeadings = Object.keys( headingPropertyNames )
.filter( h => ! company.profileContent[ h ] ); .filter( h => ! company.profileContent[ h ] );
writePage( path.join( dirname, 'index.html' ), companyTemplate( { writePage( path.join( dirname, 'index.html' ), companyTemplate( {
stylesheets: stylesheets.concat( profileStylesheets ), stylesheets,
scripts, scripts,
company, company,
headingPropertyNames, headingPropertyNames,
missingHeadings, missingHeadings,
editUrl: githubEditUrl( 'company-profiles/' + company.linkedFilename ),
} ) ); } ) );
if ( i % 10 === 0 ) {
process.stdout.write( '.' );
}
} ); } );
console.log();
console.log( 'Site files are ready in "site/build/"' );
} }
buildSite(); buildSite();

19
bin/serve-site.js Executable file
View file

@ -0,0 +1,19 @@
#!/usr/bin/env node
const { spawnSync } = require( 'child_process' );
const path = require( 'path' );
// Build the static site
const result = spawnSync( process.execPath, [
path.join( __dirname, 'build-site.js' ),
], { stdio: 'inherit' } );
if ( result.error ) {
throw result.error;
}
if ( result.status > 0 ) {
process.exit( result.status );
}
// Serve the static site locally
process.argv.splice( 2, 0, path.join( __dirname, '..', 'site', 'build' ) );
require( 'http-server/bin/http-server' );

View file

@ -8,10 +8,6 @@ need—tableware or TV or air purifier—we make shopping for it easy by telling
you the best one to get. The site was founded in September 2011 and was you the best one to get. The site was founded in September 2011 and was
acquired by The New York Times Company in October 2016. acquired by The New York Times Company in October 2016.
## Company size
(TODO)
## Remote status ## Remote status
Some employees work full-time from our office in New York City and some work Some employees work full-time from our office in New York City and some work
@ -21,10 +17,6 @@ remotely from other parts of the US.
United States. United States.
## Company technologies
(TODO)
## Office locations ## Office locations
New York City New York City

View file

@ -224,6 +224,11 @@ exports.parseFromDirectory = contentPath => {
); );
} }
// Set classes on table cells
$td.eq( 0 ).attr( 'class', 'company-name' );
$td.eq( 1 ).attr( 'class', 'company-website' );
$td.eq( 2 ).attr( 'class', 'company-region' );
// Rewrite company profile link to the correct URL for the static site // Rewrite company profile link to the correct URL for the static site
if ( $profileLink.length ) { if ( $profileLink.length ) {
$profileLink.attr( $profileLink.attr(

View file

@ -3,7 +3,14 @@
"validate": "bin/validate.js", "validate": "bin/validate.js",
"test": "mocha", "test": "mocha",
"build": "bin/build-site.js", "build": "bin/build-site.js",
"serve": "http-server site/build/" "serve": "http-server site/build/",
"start": "bin/serve-site.js"
},
"nodemonConfig": {
"ext": "js,md,html,css",
"ignore": [
"site/build/"
]
}, },
"dependencies": { "dependencies": {
"cheerio": "^1.0.0-rc.2", "cheerio": "^1.0.0-rc.2",

View file

@ -1,5 +1,7 @@
# Static site generator # Static site generator
## Overview
This folder contains the template files needed to generate the static site for This folder contains the template files needed to generate the static site for
this repo ( https://remoteintech.company/ ). this repo ( https://remoteintech.company/ ).
@ -17,10 +19,26 @@ the site builder code uses
[`swig`](https://github.com/node-swig/swig-templates) [`swig`](https://github.com/node-swig/swig-templates)
as an HTML templating engine. as an HTML templating engine.
To develop against the site locally, you can run this command: ## Development
If you submit any changes as a pull request, GitHub and Netlify will
automatically validate, build, and deploy a preview of the site for you.
For longer-running or more complicated changes, though, it can be useful to run
the site locally. To make this work, you should be using the version of
Node.js specified in the `.nvmrc` file. Other versions may work but have not
been tested.
Run `npm install` to install dependencies.
Then run `npm start` to build and serve the site locally.
You can also use `nodemon` to automatically rebuild and reload the site when
you make changes:
```sh ```sh
npm run build && npm run server npm install -g nodemon
nodemon bin/serve-site.js
``` ```
If you just want the data structure used to build the site, you can do this: If you just want the data structure used to build the site, you can do this:

View file

@ -1,76 +0,0 @@
#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;
}
}
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/ */
table#companies-table .sort.asc:after,
table#companies-table .sort.desc:after {
width: 0;
height: 0;
border-left: 6px solid transparent;
border-right: 6px solid transparent;
content:"";
display: inline-block;
position: relative;
left: 3px;
top: -2px;
}
table#companies-table .sort.asc:after {
border-bottom: 6px solid;
}
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%;
}

View file

@ -12,15 +12,6 @@ function setupFilters() {
var tbody = table.querySelector( 'tbody' ); var tbody = table.querySelector( 'tbody' );
tbody.setAttribute( 'class', 'list' ); tbody.setAttribute( 'class', 'list' );
var bodyRows = Array.prototype.slice.call( tbody.querySelectorAll( 'tr' ) );
bodyRows.forEach( function( tr ) {
var tds = tr.querySelectorAll( 'td' );
tds[ 0 ].setAttribute( 'class', 'company-name' );
tds[ 1 ].setAttribute( 'class', 'company-website' );
tds[ 2 ].setAttribute( 'class', 'company-region' );
} );
var filterInput = document.createElement( 'input' ); var filterInput = document.createElement( 'input' );
filterInput.type = 'text'; filterInput.type = 'text';
filterInput.placeholder = 'Filter Companies'; filterInput.placeholder = 'Filter Companies';
@ -50,7 +41,10 @@ function setupFilters() {
} }
); );
table.setAttribute( 'class', 'has-filter' ); document.body.setAttribute(
'class',
document.body.getAttribute( 'class' ) + ' filters-enabled'
);
} }
document.addEventListener( 'DOMContentLoaded', function( event ) { document.addEventListener( 'DOMContentLoaded', function( event ) {

View file

@ -1,9 +0,0 @@
h1.company-name {
margin-bottom: 8px;
}
.section-atAGlance {
font-size: 15px;
color: #999;
font-size: 85%;
}

216
site/assets/site.css Normal file
View file

@ -0,0 +1,216 @@
/**
* Global styles
*/
footer span[role=separator] {
padding: 0 0.2em;
}
footer span[role=separator]::before {
content: '\2022';
font-weight: 700;
}
@media screen and (max-width: 600px) {
footer span[role=separator]::before {
content: '\A';
white-space: pre;
}
}
.site-info a {
color: #c61610;
}
a:hover,
a:visited:hover {
color: #999;
}
/**
* Styles for company profile pages
*/
h1.company-name {
margin-bottom: 8px;
}
.section-atAGlance {
font-size: 15px;
color: #999;
font-size: 85%;
}
/**
* Styles for the companies table and filters on the main page
*/
#company-filter {
margin: 0 0 0 16px;
padding: 8px;
font-family: "Source Sans Pro", sans-serif;
font-size: 15px;
font-weight: 300;
vertical-align: middle;
}
#filters-explanation {
font-style: italic;
font-size: 15px;
}
@media screen and (min-width: 50em) {
#filters-explanation {
font-size: 16px;
}
}
body.filters-enabled table#companies-table 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/ */
table#companies-table .sort.asc:after,
table#companies-table .sort.desc:after {
width: 0;
height: 0;
border-left: 6px solid transparent;
border-right: 6px solid transparent;
content: '';
display: inline-block;
position: relative;
left: 3px;
top: -2px;
}
table#companies-table .sort.asc:after {
border-bottom: 6px solid;
}
table#companies-table .sort.desc:after {
border-top: 6px solid;
}
/* Column-specific styles */
table#companies-table td.company-name {
font-weight: 700;
width: 40%;
}
table#companies-table td.company-website {
width: 35%;
}
table#companies-table td.company-region {
width: 25%;
}
/* Mobile-friendly display */
@media screen and (max-width: 600px) {
body.filters-enabled h2#companies {
margin-bottom: 18px;
}
#company-filter {
display: block;
width: 100%;
margin: 27px 0 0 0;
}
table#companies-table,
table#companies-table thead,
table#companies-table tbody,
table#companies-table tr {
display: block;
}
table#companies-table tr {
border-bottom: 1px solid #eee;
padding: 0 0 8px 12px;
}
table#companies-table button.sort {
width: auto;
padding-left: 6px;
padding-right: 6px;
}
table#companies-table .sort.asc:after,
table#companies-table .sort.desc:after {
margin-right: 2px;
}
table#companies-table thead tr {
border-bottom-width: 3px;
padding: 0;
}
table#companies-table th,
table#companies-table td {
width: auto !important;
padding-left: 0;
padding-right: 0;
border-bottom-width: 0;
}
table#companies-table th {
display: inline-block;
}
table#companies-table th::after {
padding: 0 3px 0 6px;
content: '/';
}
table#companies-table th:last-child::after {
display: none;
}
table#companies-table td.company-name {
display: flex;
font-size: 16px;
font-weight: 700;
padding-bottom: 0;
margin-left: -12px;
}
table#companies-table td.company-name a {
flex: 100%;
}
table#companies-table td.company-website,
table#companies-table td.company-region {
display: inline;
padding: 0;
}
table#companies-table td.company-region::before {
padding: 0 6px 0 3px;
content: '/';
}
table#companies-table td.company-region:empty::before {
display: none;
}
}

View file

@ -51,8 +51,6 @@
<div class="entry-content"> <div class="entry-content">
{% block pageContent %}{% endblock %} {% block pageContent %}{% endblock %}
</div><!-- .entry-content --> </div><!-- .entry-content -->
<footer class="entry-footer">
</footer><!-- .entry-footer -->
</article><!-- .page --> </article><!-- .page -->
</main><!-- #main --> </main><!-- #main -->
</div><!-- #primary --> </div><!-- #primary -->
@ -111,6 +109,10 @@
</a> </a>
and and
<a href="https://www.netlify.com/">Netlify</a> <a href="https://www.netlify.com/">Netlify</a>
<span role="separator"></span>
<a href="{{ editUrl }}" target="_blank" rel="noopener noreferrer">
Edit this page on GitHub
</a>
</div><!-- .site-info --> </div><!-- .site-info -->
</div><!-- .site-info-wrapper --> </div><!-- .site-info-wrapper -->
</footer><!-- #colophon --> </footer><!-- #colophon -->

View file

@ -43,11 +43,7 @@
</ul> </ul>
<p> <p>
<strong>Want to help?</strong> <strong>Want to help?</strong>
<a <a href="{{ editUrl }}" target="_blank" rel="noopener noreferrer">
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 Send us a pull request on GitHub
</a> </a>
with your changes to this file! with your changes to this file!

View file

@ -14,39 +14,39 @@ website links.</p>
</thead> </thead>
<tbody> <tbody>
<tr> <tr>
<td><a href="/and-yet/">&amp;yet</a></td> <td class="company-name"><a href="/and-yet/">&amp;yet</a></td>
<td><a href="https://andyet.com" target="_blank" rel="noopener noreferrer">andyet.com</a></td> <td class="company-website"><a href="https://andyet.com" target="_blank" rel="noopener noreferrer">andyet.com</a></td>
<td>Worldwide</td> <td class="company-region">Worldwide</td>
</tr> </tr>
<tr> <tr>
<td><a href="/10up/">10up</a></td> <td class="company-name"><a href="/10up/">10up</a></td>
<td><a href="https://10up.com/" target="_blank" rel="noopener noreferrer">10up.com</a></td> <td class="company-website"><a href="https://10up.com/" target="_blank" rel="noopener noreferrer">10up.com</a></td>
<td>Worldwide</td> <td class="company-region">Worldwide</td>
</tr> </tr>
<tr> <tr>
<td><a href="/17hats/">17hats</a></td> <td class="company-name"><a href="/17hats/">17hats</a></td>
<td><a href="https://www.17hats.com/" target="_blank" rel="noopener noreferrer">17hats.com</a></td> <td class="company-website"><a href="https://www.17hats.com/" target="_blank" rel="noopener noreferrer">17hats.com</a></td>
<td>Worldwide</td> <td class="company-region">Worldwide</td>
</tr> </tr>
<tr> <tr>
<td><a href="/18f/">18F</a></td> <td class="company-name"><a href="/18f/">18F</a></td>
<td><a href="https://18f.gsa.gov/" target="_blank" rel="noopener noreferrer">18f.gsa.gov</a></td> <td class="company-website"><a href="https://18f.gsa.gov/" target="_blank" rel="noopener noreferrer">18f.gsa.gov</a></td>
<td>USA</td> <td class="company-region">USA</td>
</tr> </tr>
<tr> <tr>
<td><a href="/45royale/">45royale</a> &#x26A0;</td> <td class="company-name"><a href="/45royale/">45royale</a> &#x26A0;</td>
<td><a href="http://45royale.com/" target="_blank" rel="noopener noreferrer">45royale.com</a></td> <td class="company-website"><a href="http://45royale.com/" target="_blank" rel="noopener noreferrer">45royale.com</a></td>
<td></td> <td class="company-region"></td>
</tr> </tr>
<tr> <tr>
<td><a href="/aerolab/">Aerolab</a> &#x26A0;</td> <td class="company-name"><a href="/aerolab/">Aerolab</a> &#x26A0;</td>
<td><a href="https://aerolab.co/" target="_blank" rel="noopener noreferrer">aerolab.co</a></td> <td class="company-website"><a href="https://aerolab.co/" target="_blank" rel="noopener noreferrer">aerolab.co</a></td>
<td></td> <td class="company-region"></td>
</tr> </tr>
<tr> <tr>
<td><a href="/angularclass/">AngularClass</a> &#x26A0;</td> <td class="company-name"><a href="/angularclass/">AngularClass</a> &#x26A0;</td>
<td><a href="http://www.wikihow.com/wikiHow:About-wikiHow" target="_blank" rel="noopener noreferrer">wikihow.com/wikiHow:About-wikiHow</a></td> <td class="company-website"><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> <td class="company-region">PST Timezone</td>
</tr> </tr>
</tbody> </tbody>
</table> </table>